From 21d35e335a51bd0b961a4ec07f827712b781e386 Mon Sep 17 00:00:00 2001 From: Matteo Martelli Date: Wed, 22 May 2024 18:46:55 +0200 Subject: [PATCH 001/349] ASoC: es8311: dt-bindings: add everest es8311 codec Add DT bindings documentation for the Everest-semi ES8311 codec. Everest-semi ES8311 codec is a low-power mono audio codec with I2S audio interface and I2C control. Signed-off-by: Matteo Martelli Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240522164722.954656-2-matteomartelli3@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/everest,es8316.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.yaml b/Documentation/devicetree/bindings/sound/everest,es8316.yaml index b6079b3c440d..214f135b7777 100644 --- a/Documentation/devicetree/bindings/sound/everest,es8316.yaml +++ b/Documentation/devicetree/bindings/sound/everest,es8316.yaml @@ -4,18 +4,21 @@ $id: http://devicetree.org/schemas/sound/everest,es8316.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Everest ES8316 audio CODEC +title: Everest ES8311 and ES8316 audio CODECs maintainers: - Daniel Drake - Katsuhiro Suzuki + - Matteo Martelli allOf: - $ref: dai-common.yaml# properties: compatible: - const: everest,es8316 + enum: + - everest,es8311 + - everest,es8316 reg: maxItems: 1 From baf9899122b0e585a340e2edc685c56c60b9c23e Mon Sep 17 00:00:00 2001 From: Matteo Martelli Date: Wed, 22 May 2024 18:46:56 +0200 Subject: [PATCH 002/349] ASoC: codecs: es8311: add everest es8311 codec support Add support for the Everest-semi ES8311 codec. Everest-semi ES8311 codec is a low-power mono audio codec with I2S audio interface and I2C control. Supported features: * Both master and slave mode. Master clock is optional in slave mode. * Sample rates from 8KHz to 96KHz. * Sample formats: S16_LE, S18_3LE, S20_3LE, S24_3LE, S24_LE and S32_LE. * I2S formats: I2S, LEFT_J, DSP_A, DSP_B. * BCLK and FSYNC clocks inversion. * Component suspend/resume. * ADC, PGA, DAC controls. * ADC DSP controls: volume, fade (ramp rate), ALC, automute, HPF, EQ. * DAC DSP controls: volume, fade (ramp rate), DRC, EQ. * DAPM routes: capture path with input source selection (differential MIC/DMIC) and AIF channel source selection; playback path with DAC channel source selection. Limitations: * Support only for master clocks with a ratio of ADC (or DAC) clock to LRCLK equal to 256. This to keep the default ADC and DAC oversampling and ADC scale settings. Anyway all 8-96KHz sample rates are supported when the ratio of MCLK to sample rate is 32, 64, 128, 256, 384 or 512 (upper limit due to max MCLK freq of 49.2MHz). * Coefficients for ADC HPF and ADC/DAC EQ not supported. * Digital mic supported but not tested. * S18_3LE, S20_3LE and S24_3LE formats supported but not tested. Signed-off-by: Matteo Martelli Link: https://msgid.link/r/20240522164722.954656-3-matteomartelli3@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/es8311.c | 970 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/es8311.h | 162 +++++++ 4 files changed, 1138 insertions(+) create mode 100644 sound/soc/codecs/es8311.c create mode 100644 sound/soc/codecs/es8311.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 4afc43d3f71f..3936fb36d051 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1101,6 +1101,10 @@ config SND_SOC_ES83XX_DSM_COMMON depends on ACPI tristate +config SND_SOC_ES8311 + tristate "Everest Semi ES8311 CODEC" + depends on I2C + config SND_SOC_ES8316 tristate "Everest Semi ES8316 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b4df22186e25..d784b445bb20 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -119,6 +119,7 @@ snd-soc-dmic-y := dmic.o snd-soc-es7134-y := es7134.o snd-soc-es7241-y := es7241.o snd-soc-es83xx-dsm-common-y := es83xx-dsm-common.o +snd-soc-es8311-y := es8311.o snd-soc-es8316-y := es8316.o snd-soc-es8326-y := es8326.o snd-soc-es8328-y := es8328.o @@ -516,6 +517,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON) += snd-soc-es83xx-dsm-common.o +obj-$(CONFIG_SND_SOC_ES8311) += snd-soc-es8311.o obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o diff --git a/sound/soc/codecs/es8311.c b/sound/soc/codecs/es8311.c new file mode 100644 index 000000000000..b2ee2d04b0e4 --- /dev/null +++ b/sound/soc/codecs/es8311.c @@ -0,0 +1,970 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * es8311.c -- es8311 ALSA SoC audio driver + * + * Copyright (C) 2024 Matteo Martelli + * + * Author: Matteo Martelli + */ + +#include "linux/array_size.h" +#include "sound/pcm.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "es8311.h" + +#define ES8311_NUM_RATES 10 +#define ES8311_RATES (SNDRV_PCM_RATE_8000_96000) +#define ES8311_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +struct es8311_priv { + struct regmap *regmap; + struct clk *mclk; + unsigned long mclk_freq; + bool provider; + unsigned int rates[ES8311_NUM_RATES]; + struct snd_pcm_hw_constraint_list constraints; +}; + +static const DECLARE_TLV_DB_SCALE(es8311_adc_vol_tlv, -9550, 50, 0); +static const DECLARE_TLV_DB_SCALE(es8311_pga_gain_tlv, 0, 300, 0); +static const DECLARE_TLV_DB_SCALE(es8311_adc_scale_tlv, 0, 600, 0); + +#define ES8311_DB_LRCK_STEPS \ + "0.25db/4LRCK", \ + "0.25db/8LRCK", \ + "0.25db/16LRCK", \ + "0.25db/32LRCK", \ + "0.25db/64LRCK", \ + "0.25db/128LRCK", \ + "0.25db/256LRCK", \ + "0.25db/512LRCK", \ + "0.25db/1024LRCK", \ + "0.25db/2048LRCK", \ + "0.25db/4096LRCK", \ + "0.25db/8192LRCK", \ + "0.25db/16384LRCK", \ + "0.25db/32768LRCK", \ + "0.25db/65536LRCK", + +static const char *const es8311_level_winsize_txt[] = { + "0.25db/2LRCK", + ES8311_DB_LRCK_STEPS +}; + +static SOC_ENUM_SINGLE_DECL( + es8311_alc_winsize, ES8311_ADC4, + ES8311_ADC4_ALC_WINSIZE_SHIFT, es8311_level_winsize_txt); +static const DECLARE_TLV_DB_RANGE(es8311_level_tlv, + 0, 1, TLV_DB_SCALE_ITEM(-3010, 600, 0), + 2, 3, TLV_DB_SCALE_ITEM(-2060, 250, 0), + 4, 5, TLV_DB_SCALE_ITEM(-1610, 160, 0), + 6, 7, TLV_DB_SCALE_ITEM(-1320, 120, 0), + 8, 9, TLV_DB_SCALE_ITEM(-1100, 90, 0), + 10, 11, TLV_DB_SCALE_ITEM(-930, 80, 0), + 12, 15, TLV_DB_SCALE_ITEM(-780, 60, 0), +); + +static const char *const es8311_ramprate_txt[] = { + "Disabled", + ES8311_DB_LRCK_STEPS +}; +static SOC_ENUM_SINGLE_DECL( + es8311_adc_ramprate, ES8311_ADC1, + ES8311_ADC1_RAMPRATE_SHIFT, es8311_ramprate_txt); + +static const char *const es8311_automute_winsize_txt[] = { + "2048 samples", + "4096 samples", + "6144 samples", + "8192 samples", + "10240 samples", + "12288 samples", + "14336 samples", + "16384 samples", + "18432 samples", + "20480 samples", + "22528 samples", + "24576 samples", + "26624 samples", + "28672 samples", + "30720 samples", + "32768 samples", +}; +static SOC_ENUM_SINGLE_DECL( + es8311_automute_winsize, ES8311_ADC6, + ES8311_ADC6_AUTOMUTE_WS_SHIFT, es8311_automute_winsize_txt); +static const DECLARE_TLV_DB_RANGE(es8311_automute_ng_tlv, + 0, 7, TLV_DB_SCALE_ITEM(-9600, 600, 0), + 8, 15, TLV_DB_SCALE_ITEM(-5100, 300, 0), +); +static const DECLARE_TLV_DB_SCALE(es8311_automute_vol_tlv, -2800, 400, 0); + +static const DECLARE_TLV_DB_SCALE(es8311_dac_vol_tlv, -9550, 50, 0); +static SOC_ENUM_SINGLE_DECL( + es8311_drc_winsize, ES8311_DAC4, + ES8311_DAC4_DRC_WINSIZE_SHIFT, es8311_level_winsize_txt); +static SOC_ENUM_SINGLE_DECL( + es8311_dac_ramprate, ES8311_DAC6, + ES8311_DAC6_RAMPRATE_SHIFT, es8311_ramprate_txt); + +static const char *const es8311_out_mode_txt[] = { + "Lineout", + "Headphones" +}; +static SOC_ENUM_SINGLE_DECL( + es8311_out_mode, ES8311_SYS9, + ES8311_SYS9_HPSW_SHIFT, es8311_out_mode_txt); + +static const struct snd_kcontrol_new es8311_snd_controls[] = { + /* Capture path */ + SOC_SINGLE_TLV("PGA Capture Volume", ES8311_SYS10, + ES8311_SYS10_PGAGAIN_SHIFT, ES8311_SYS10_PGAGAIN_MAX, 0, + es8311_pga_gain_tlv), + SOC_SINGLE("ADC Polarity Invert Capture Switch", ES8311_ADC2, + ES8311_ADC2_INV_SHIFT, 1, 0), + SOC_SINGLE_TLV("ADC Scale Capture Volume", ES8311_ADC2, + ES8311_ADC2_SCALE_SHIFT, ES8311_ADC2_SCALE_MAX, 0, + es8311_adc_scale_tlv), + SOC_SINGLE_TLV("ADC Capture Volume", ES8311_ADC3, + ES8311_ADC3_VOLUME_SHIFT, ES8311_ADC3_VOLUME_MAX, 0, + es8311_adc_vol_tlv), + SOC_ENUM("ADC Capture Ramp Rate", es8311_adc_ramprate), + SOC_SINGLE("ADC Automute Capture Switch", ES8311_ADC4, + ES8311_ADC4_AUTOMUTE_EN_SHIFT, 1, 0), + SOC_ENUM("ADC Automute Capture Winsize", es8311_automute_winsize), + SOC_SINGLE_TLV("ADC Automute Noise Gate Capture Volume", ES8311_ADC6, + ES8311_ADC6_AUTOMUTE_NG_SHIFT, + ES8311_ADC6_AUTOMUTE_NG_MAX, 0, es8311_automute_ng_tlv), + SOC_SINGLE_TLV("ADC Automute Capture Volume", ES8311_ADC7, + ES8311_ADC7_AUTOMUTE_VOL_SHIFT, + ES8311_ADC7_AUTOMUTE_VOL_MAX, 0, + es8311_automute_vol_tlv), + SOC_SINGLE("ADC HPF Capture Switch", ES8311_ADC8, ES8311_ADC8_HPF_SHIFT, + 1, 0), + SOC_SINGLE("ADC EQ Capture Switch", ES8311_ADC8, + ES8311_ADC8_EQBYPASS_SHIFT, 1, 1), + SOC_SINGLE("ALC Capture Switch", ES8311_ADC4, ES8311_ADC4_ALC_EN_SHIFT, + 1, 0), + SOC_SINGLE_TLV("ALC Capture Max Volume", ES8311_ADC5, + ES8311_ADC5_ALC_MAXLEVEL_SHIFT, + ES8311_ADC5_ALC_MAXLEVEL_MAX, 0, es8311_level_tlv), + SOC_SINGLE_TLV("ALC Capture Min Volume", ES8311_ADC5, + ES8311_ADC5_ALC_MINLEVEL_SHIFT, + ES8311_ADC5_ALC_MINLEVEL_MAX, 0, es8311_level_tlv), + SOC_ENUM("ALC Capture Winsize", es8311_alc_winsize), + + /* Playback path */ + SOC_SINGLE_TLV("DAC Playback Volume", ES8311_DAC2, 0, + ES8311_DAC2_VOLUME_MAX, 0, es8311_dac_vol_tlv), + SOC_SINGLE("DRC Playback Switch", ES8311_DAC4, ES8311_DAC4_DRC_EN_SHIFT, + 1, 0), + SOC_SINGLE_TLV("DRC Playback Max Volume", ES8311_DAC5, + ES8311_DAC5_DRC_MAXLEVEL_SHIFT, + ES8311_DAC5_DRC_MAXLEVEL_MAX, 0, es8311_level_tlv), + SOC_SINGLE_TLV("DRC Playback Min Volume", ES8311_DAC5, + ES8311_DAC5_DRC_MINLEVEL_SHIFT, + ES8311_DAC5_DRC_MINLEVEL_MAX, 0, es8311_level_tlv), + SOC_ENUM("DRC Playback Winsize", es8311_drc_winsize), + SOC_ENUM("DAC Playback Ramp Rate", es8311_dac_ramprate), + SOC_SINGLE("DAC EQ Playback Switch", ES8311_DAC6, + ES8311_DAC6_EQBYPASS_SHIFT, 1, 1), + + SOC_ENUM("Output Mode", es8311_out_mode), +}; + +static const char *const es8311_diff_src_txt[] = { + "Disabled", + "MIC1P-MIC1N", +}; +static SOC_ENUM_SINGLE_DECL( + es8311_diff_src_enum, ES8311_SYS10, + ES8311_SYS10_LINESEL_SHIFT, es8311_diff_src_txt); +static const struct snd_kcontrol_new es8311_diff_src_mux = + SOC_DAPM_ENUM("Differential Source", es8311_diff_src_enum); + +static const char *const es8311_dmic_src_txt[] = { + "Disabled", + "DMIC from MIC1P", +}; +static SOC_ENUM_SINGLE_DECL( + es8311_dmic_src_enum, ES8311_SYS10, + ES8311_SYS10_DMIC_ON_SHIFT, es8311_dmic_src_txt); +static const struct snd_kcontrol_new es8311_dmic_src_mux = + SOC_DAPM_ENUM("Digital Mic Source", es8311_dmic_src_enum); + +static const char * const es8311_aif1tx_src_txt[] = { + "ADC + ADC", + "ADC + 0", + "0 + ADC", + "0 + 0", + "DACL + ADC", + "ADC + DACR", + "DACL + DACR", +}; +static SOC_ENUM_SINGLE_DECL( + es8311_aif1tx_src_enum, ES8311_GPIO, + ES8311_GPIO_ADCDAT_SEL_SHIFT, es8311_aif1tx_src_txt); +static const struct snd_kcontrol_new es8311_aif1tx_src_mux = + SOC_DAPM_ENUM("AIF1TX Source", es8311_aif1tx_src_enum); + +static const char * const es8311_dac_src_txt[] = { + "Left", + "Right" +}; +static SOC_ENUM_SINGLE_DECL( + es8311_dac_src_enum, ES8311_SDP_IN, + ES8311_SDP_IN_SEL_SHIFT, es8311_dac_src_txt); +static const struct snd_kcontrol_new es8311_dac_src_mux = + SOC_DAPM_ENUM("Mono DAC Source", es8311_dac_src_enum); + +static const struct snd_soc_dapm_widget es8311_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("Bias", ES8311_SYS3, ES8311_SYS3_PDN_IBIASGEN_SHIFT, + 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Analog power", ES8311_SYS3, + ES8311_SYS3_PDN_ANA_SHIFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Vref", ES8311_SYS3, ES8311_SYS3_PDN_VREF_SHIFT, 1, + NULL, 0), + + /* Capture path */ + SND_SOC_DAPM_INPUT("DMIC"), + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, + &es8311_diff_src_mux), + SND_SOC_DAPM_SUPPLY("ADC Bias Gen", ES8311_SYS3, + ES8311_SYS3_PDN_ADCBIASGEN_SHIFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Vref Gen", ES8311_SYS3, + ES8311_SYS3_PDN_ADCVREFGEN_SHIFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Clock", ES8311_CLKMGR1, + ES8311_CLKMGR1_CLKADC_ON_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Analog Clock", ES8311_CLKMGR1, + ES8311_CLKMGR1_ANACLKADC_ON_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA", ES8311_SYS4, ES8311_SYS4_PDN_PGA_SHIFT, 1, NULL, + 0), + SND_SOC_DAPM_ADC("Mono ADC", NULL, ES8311_SYS4, + ES8311_SYS4_PDN_MOD_SHIFT, 1), + SND_SOC_DAPM_MUX("Digital Mic Mux", SND_SOC_NOPM, 0, 0, + &es8311_dmic_src_mux), + SND_SOC_DAPM_MUX("AIF1TX Source Mux", SND_SOC_NOPM, 0, 0, + &es8311_aif1tx_src_mux), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, ES8311_SDP_OUT, + ES8311_SDP_MUTE_SHIFT, 1), + + /* Playback path */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, ES8311_SDP_IN, + ES8311_SDP_MUTE_SHIFT, 1), + SND_SOC_DAPM_MUX("Mono DAC Source Mux", SND_SOC_NOPM, 0, 0, + &es8311_dac_src_mux), + SND_SOC_DAPM_DAC("Mono DAC", NULL, ES8311_SYS8, + ES8311_SYS8_PDN_DAC_SHIFT, 1), + SND_SOC_DAPM_SUPPLY("DAC Clock", ES8311_CLKMGR1, + ES8311_CLKMGR1_CLKDAC_ON_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Analog Clock", ES8311_CLKMGR1, + ES8311_CLKMGR1_ANACLKDAC_ON_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Vref Gen", ES8311_SYS3, + ES8311_SYS3_PDN_DACVREFGEN_SHIFT, 1, NULL, 0), + SND_SOC_DAPM_OUTPUT("OUT"), +}; + +static const struct snd_soc_dapm_route es8311_dapm_routes[] = { + /* Capture Path */ + { "MIC1", NULL, "Bias" }, + { "MIC1", NULL, "Analog power" }, + { "MIC1", NULL, "Vref" }, + { "Differential Mux", "MIC1P-MIC1N", "MIC1" }, + { "PGA", NULL, "Differential Mux" }, + { "Mono ADC", NULL, "PGA" }, + { "Mono ADC", NULL, "ADC Bias Gen" }, + { "Mono ADC", NULL, "ADC Vref Gen" }, + { "Mono ADC", NULL, "ADC Clock" }, + { "Mono ADC", NULL, "ADC Analog Clock" }, + { "Digital Mic Mux", "Disabled", "Mono ADC" }, + { "Digital Mic Mux", "DMIC from MIC1P", "DMIC" }, + + { "AIF1TX Source Mux", "ADC + ADC", "Digital Mic Mux" }, + { "AIF1TX Source Mux", "ADC + 0", "Digital Mic Mux" }, + { "AIF1TX Source Mux", "0 + ADC", "Digital Mic Mux" }, + { "AIF1TX Source Mux", "DACL + ADC", "Digital Mic Mux" }, + { "AIF1TX Source Mux", "ADC + DACR", "Digital Mic Mux" }, + + { "AIF1TX", NULL, "AIF1TX Source Mux" }, + + /* Playback Path */ + { "Mono DAC Source Mux", "Left", "AIF1RX" }, + { "Mono DAC Source Mux", "Right", "AIF1RX" }, + { "Mono DAC", NULL, "Mono DAC Source Mux" }, + { "Mono DAC", NULL, "DAC Clock" }, + { "Mono DAC", NULL, "DAC Analog Clock" }, + { "OUT", NULL, "Mono DAC" }, + { "OUT", NULL, "Bias" }, + { "OUT", NULL, "Analog power" }, + { "OUT", NULL, "Vref" }, + { "OUT", NULL, "DAC Vref Gen" }, +}; + +/* Bit clock divider values: + * from 1 to 20: the register takes the div value - 1 + * above 20: the register takes the corresponding idx of the div value + * in the following table + 20 + */ +#define ES8311_BCLK_DIV_IDX_OFFSET 20 +static const unsigned int es8311_bclk_divs[] = { + 22, 24, 25, 30, 32, 33, 34, 36, 44, 48, 66, 72 +}; + +struct es8311_mclk_coeff { + unsigned int rate; + unsigned int mclk; + unsigned int div; + unsigned int mult; + unsigned int div_adc_dac; +}; + +#define ES8311_MCLK_MAX_FREQ 49200000 + +/* Coefficients for common master clock frequencies based on clock table from + * documentation. Limited to have a ratio of adc (or dac) clock to lrclk equal + * to 256. This to keep the default adc and dac oversampling and adc scale + * settings. Internal mclk dividers and multipliers are dynamically adjusted to + * support, respectively, multiples (up to x8) and factors (/2,4,8) of listed + * mclks frequencies (see es8311_cmp_adj_mclk_coeff). + * All rates are supported when mclk/rate ratio is 32, 64, 128, 256, 384 or 512 + * (upper limit due to max mclk freq of 49.2MHz). + */ +static const struct es8311_mclk_coeff es8311_mclk_coeffs[] = { + { 8000, 2048000, 1, 1, 1 }, + { 8000, 6144000, 3, 1, 1 }, + { 8000, 18432000, 3, 1, 3 }, + { 11025, 2822400, 1, 1, 1 }, + { 11025, 8467200, 3, 1, 1 }, + { 16000, 4096000, 1, 1, 1 }, + { 16000, 12288000, 3, 1, 1 }, + { 16000, 18432000, 3, 2, 3 }, + { 22050, 5644800, 1, 1, 1 }, + { 22050, 16934400, 3, 1, 1 }, + { 32000, 8192000, 1, 1, 1 }, + { 32000, 12288000, 3, 2, 1 }, + { 32000, 18432000, 3, 4, 3 }, + { 44100, 11289600, 1, 1, 1 }, + { 44100, 33868800, 3, 1, 1 }, + { 48000, 12288000, 1, 1, 1 }, + { 48000, 18432000, 3, 2, 1 }, + { 64000, 8192000, 1, 2, 1 }, + { 64000, 12288000, 3, 4, 1 }, + { 88200, 11289600, 1, 2, 1 }, + { 88200, 33868800, 3, 2, 1 }, + { 96000, 12288000, 1, 2, 1 }, + { 96000, 18432000, 3, 4, 1 }, +}; + +/* Compare coeff with provided mclk_freq and adjust it if needed. + * If frequencies match, return 0 and the unaltered coeff copy into out_coeff. + * If mclk_freq is a valid multiple or factor of coeff mclk freq, return 0 and + * the adjusted coeff copy into out_coeff. + * Return -EINVAL otherwise. + */ +static int es8311_cmp_adj_mclk_coeff(unsigned int mclk_freq, + const struct es8311_mclk_coeff *coeff, + struct es8311_mclk_coeff *out_coeff) +{ + if (WARN_ON_ONCE(!coeff)) + return -EINVAL; + + unsigned int div = coeff->div; + unsigned int mult = coeff->mult; + bool match = false; + + if (coeff->mclk == mclk_freq) { + match = true; + } else if (mclk_freq % coeff->mclk == 0) { + div = mclk_freq / coeff->mclk; + div *= coeff->div; + if (div <= 8) + match = true; + } else if (coeff->mclk % mclk_freq == 0) { + mult = coeff->mclk / mclk_freq; + if (mult == 2 || mult == 4 || mult == 8) { + mult *= coeff->mult; + if (mult <= 8) + match = true; + } + } + if (!match) + return -EINVAL; + if (out_coeff) { + *out_coeff = *coeff; + out_coeff->div = div; + out_coeff->mult = mult; + } + return 0; +} + +static int es8311_get_mclk_coeff(unsigned int mclk_freq, unsigned int rate, + struct es8311_mclk_coeff *out_coeff) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(es8311_mclk_coeffs); i++) { + const struct es8311_mclk_coeff *coeff = &es8311_mclk_coeffs[i]; + + if (coeff->rate != rate) + continue; + + int ret = + es8311_cmp_adj_mclk_coeff(mclk_freq, coeff, out_coeff); + if (ret == 0) + return 0; + } + return -EINVAL; +} + +static void es8311_set_sysclk_constraints(unsigned int mclk_freq, + struct es8311_priv *es8311) +{ + unsigned int count = 0; + + for (unsigned int i = 0; i < ARRAY_SIZE(es8311_mclk_coeffs) && + count < ARRAY_SIZE(es8311->rates); i++) { + const struct es8311_mclk_coeff *coeff = &es8311_mclk_coeffs[i]; + + if (count > 0 && coeff->rate == es8311->rates[count - 1]) + continue; + + int ret = es8311_cmp_adj_mclk_coeff(mclk_freq, coeff, NULL); + if (ret == 0) + es8311->rates[count++] = coeff->rate; + } + if (count) { + es8311->constraints.list = es8311->rates; + es8311->constraints.count = count; + } +} + +static int es8311_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + struct snd_soc_component *component = dai->component; + struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + unsigned int mask = ES8311_DAC1_DAC_DSMMUTE | + ES8311_DAC1_DAC_DEMMUTE; + unsigned int val = mute ? mask : 0; + + regmap_update_bits(es8311->regmap, ES8311_DAC1, mask, val); + } + + return 0; +} + +static int es8311_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + + if (es8311->constraints.list) { + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &es8311->constraints); + } + + return 0; +} + +static int es8311_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 es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + unsigned int wl; + int par_width = params_width(params); + + switch (par_width) { + case 16: + wl = ES8311_SDP_WL_16; + break; + case 18: + wl = ES8311_SDP_WL_18; + break; + case 20: + wl = ES8311_SDP_WL_20; + break; + case 24: + wl = ES8311_SDP_WL_24; + break; + case 32: + wl = ES8311_SDP_WL_32; + break; + default: + return -EINVAL; + } + unsigned int width = (unsigned int)par_width; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + snd_soc_component_update_bits(component, ES8311_SDP_IN, + ES8311_SDP_WL_MASK, + wl << ES8311_SDP_WL_SHIFT); + } else { + snd_soc_component_update_bits(component, ES8311_SDP_OUT, + ES8311_SDP_WL_MASK, + wl << ES8311_SDP_WL_SHIFT); + } + + if (es8311->mclk_freq > ES8311_MCLK_MAX_FREQ) { + dev_err(component->dev, "mclk frequency %lu too high\n", + es8311->mclk_freq); + return -EINVAL; + } + + unsigned int mclk_freq = es8311->mclk_freq; + unsigned int rate = params_rate(params); + unsigned int clkmgr = ES8311_CLKMGR1_MCLK_ON; + + if (!mclk_freq) { + if (es8311->provider) { + dev_err(component->dev, + "mclk not configured, cannot run as master\n"); + return -EINVAL; + } + dev_dbg(component->dev, + "mclk not configured, use bclk as internal mclk\n"); + + clkmgr = ES8311_CLKMGR1_MCLK_SEL; + + mclk_freq = rate * width * 2; + } + + struct es8311_mclk_coeff coeff; + int ret = es8311_get_mclk_coeff(mclk_freq, rate, &coeff); + if (ret) { + dev_err(component->dev, "unable to find mclk coefficient\n"); + return ret; + } + + unsigned int mask = ES8311_CLKMGR1_MCLK_SEL | ES8311_CLKMGR1_MCLK_ON | + ES8311_CLKMGR1_BCLK_ON; + + clkmgr |= ES8311_CLKMGR1_BCLK_ON; + snd_soc_component_update_bits(component, ES8311_CLKMGR1, mask, clkmgr); + + if (WARN_ON_ONCE(coeff.div == 0 || coeff.div > 8 || + coeff.div_adc_dac == 0 || coeff.div_adc_dac > 8)) + return -EINVAL; + + unsigned int mult; + + switch (coeff.mult) { + case 1: + mult = 0; + break; + case 2: + mult = 1; + break; + case 4: + mult = 2; + break; + case 8: + mult = 3; + break; + default: + WARN_ON_ONCE(true); + return -EINVAL; + } + + mask = ES8311_CLKMGR2_DIV_PRE_MASK | ES8311_CLKMGR2_MULT_PRE_MASK; + clkmgr = (coeff.div - 1) << ES8311_CLKMGR2_DIV_PRE_SHIFT | + mult << ES8311_CLKMGR2_MULT_PRE_SHIFT; + snd_soc_component_update_bits(component, ES8311_CLKMGR2, mask, clkmgr); + + mask = ES8311_CLKMGR5_ADC_DIV_MASK | ES8311_CLKMGR5_DAC_DIV_MASK; + clkmgr = (coeff.div_adc_dac - 1) << ES8311_CLKMGR5_ADC_DIV_SHIFT | + (coeff.div_adc_dac - 1) << ES8311_CLKMGR5_DAC_DIV_SHIFT; + snd_soc_component_update_bits(component, ES8311_CLKMGR5, mask, clkmgr); + + if (es8311->provider) { + unsigned int div_lrclk = mclk_freq / rate; + + if (WARN_ON_ONCE(div_lrclk == 0 || + div_lrclk > ES8311_CLKMGR_LRCLK_DIV_MAX + 1)) + return -EINVAL; + + mask = ES8311_CLKMGR7_LRCLK_DIV_H_MASK; + clkmgr = (div_lrclk - 1) >> 8; + snd_soc_component_update_bits(component, ES8311_CLKMGR7, mask, + clkmgr); + clkmgr = (div_lrclk - 1) & 0xFF; + snd_soc_component_write(component, ES8311_CLKMGR8, clkmgr); + + if (div_lrclk % (2 * width) != 0) { + dev_err(component->dev, + "unable to divide mclk %u to generate bclk\n", + mclk_freq); + return -EINVAL; + } + + unsigned int div_bclk = div_lrclk / (2 * width); + + mask = ES8311_CLKMGR6_DIV_BCLK_MASK; + if (div_bclk <= ES8311_BCLK_DIV_IDX_OFFSET) { + clkmgr = div_bclk - 1; + } else { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(es8311_bclk_divs); i++) { + if (es8311_bclk_divs[i] == div_bclk) + break; + } + if (i == ARRAY_SIZE(es8311_bclk_divs)) { + dev_err(component->dev, + "bclk divider %u not supported\n", + div_bclk); + return -EINVAL; + } + + clkmgr = i + ES8311_BCLK_DIV_IDX_OFFSET; + } + snd_soc_component_update_bits(component, ES8311_CLKMGR6, mask, + clkmgr); + } + + return 0; +} + +static int es8311_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + + if (freq > ES8311_MCLK_MAX_FREQ) { + dev_err(component->dev, "invalid frequency %u: too high\n", + freq); + return -EINVAL; + } + + if (es8311->mclk_freq == freq) + return 0; + + es8311->mclk_freq = freq; + es8311->constraints.list = NULL; + es8311->constraints.count = 0; + + if (freq == 0) + return 0; + + int ret = clk_set_rate(es8311->mclk, freq); + if (ret) { + dev_err(component->dev, "unable to set mclk rate\n"); + return ret; + } + + es8311_set_sysclk_constraints(freq, es8311); + + return ret; +} + +static int es8311_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + /* Master mode */ + es8311->provider = true; + + snd_soc_component_update_bits(component, ES8311_RESET, + ES8311_RESET_MSC, + ES8311_RESET_MSC); + break; + case SND_SOC_DAIFMT_CBC_CFC: + /* Slave mode */ + es8311->provider = false; + snd_soc_component_update_bits(component, ES8311_RESET, + ES8311_RESET_MSC, 0); + break; + default: + return -EINVAL; + } + + unsigned int sdp = 0; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + sdp |= ES8311_SDP_FMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + sdp |= ES8311_SDP_FMT_LEFT_J; + break; + case SND_SOC_DAIFMT_RIGHT_J: + dev_err(component->dev, "right justified mode not supported\n"); + return -EINVAL; + case SND_SOC_DAIFMT_DSP_B: + sdp |= ES8311_SDP_LRP; + fallthrough; + case SND_SOC_DAIFMT_DSP_A: + sdp |= ES8311_SDP_FMT_DSP; + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + case SND_SOC_DAIFMT_IB_NF: + break; + default: + dev_err(component->dev, + "inverted fsync not supported in dsp mode\n"); + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + unsigned int clkmgr = 0; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + sdp |= ES8311_SDP_LRP; + break; + case SND_SOC_DAIFMT_IB_NF: + clkmgr |= ES8311_CLKMGR6_BCLK_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + clkmgr |= ES8311_CLKMGR6_BCLK_INV; + sdp |= ES8311_SDP_LRP; + break; + default: + return -EINVAL; + } + + unsigned int mask = ES8311_CLKMGR6_BCLK_INV; + + snd_soc_component_update_bits(component, ES8311_CLKMGR6, mask, clkmgr); + + mask = ES8311_SDP_FMT_MASK | ES8311_SDP_LRP; + snd_soc_component_update_bits(component, ES8311_SDP_IN, mask, sdp); + snd_soc_component_update_bits(component, ES8311_SDP_OUT, mask, sdp); + + return 0; +} + +static int es8311_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { + int ret = clk_prepare_enable(es8311->mclk); + if (ret) { + dev_err(component->dev, + "unable to prepare mclk\n"); + return ret; + } + + snd_soc_component_update_bits( + component, ES8311_SYS3, + ES8311_SYS3_PDN_VMIDSEL_MASK, + ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED); + } + + break; + case SND_SOC_BIAS_OFF: + clk_disable_unprepare(es8311->mclk); + snd_soc_component_update_bits( + component, ES8311_SYS3, ES8311_SYS3_PDN_VMIDSEL_MASK, + ES8311_SYS3_PDN_VMIDSEL_POWER_DOWN); + break; + default: + break; + } + return 0; +} + +static const struct snd_soc_dai_ops es8311_dai_ops = { + .startup = es8311_startup, + .hw_params = es8311_hw_params, + .mute_stream = es8311_mute, + .set_sysclk = es8311_set_sysclk, + .set_fmt = es8311_set_dai_fmt, + .no_capture_mute = 1, +}; + +static struct snd_soc_dai_driver es8311_dai = { + .name = "es8311", + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = ES8311_RATES, + .formats = ES8311_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = ES8311_RATES, + .formats = ES8311_FORMATS, + }, + .ops = &es8311_dai_ops, + .symmetric_rate = 1, +}; + +static void es8311_reset(struct snd_soc_component *component, bool reset) +{ + /* Reset procedure: + * (1) power down state machine and reset codec blocks then, + * (2) after a short delay, power up state machine and leave reset mode. + * Specific delay is not documented, using the same as es8316. + */ + unsigned int mask = ES8311_RESET_CSM_ON | ES8311_RESET_RST_MASK; + + if (reset) { + /* Enter reset mode */ + snd_soc_component_update_bits(component, ES8311_RESET, mask, + ES8311_RESET_RST_MASK); + } else { + /* Leave reset mode */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, ES8311_RESET, mask, + ES8311_RESET_CSM_ON); + } +} + +static int es8311_suspend(struct snd_soc_component *component) +{ + struct es8311_priv *es8311; + + es8311 = snd_soc_component_get_drvdata(component); + + es8311_reset(component, true); + + regcache_cache_only(es8311->regmap, true); + regcache_mark_dirty(es8311->regmap); + + return 0; +} + +static int es8311_resume(struct snd_soc_component *component) +{ + struct es8311_priv *es8311; + + es8311 = snd_soc_component_get_drvdata(component); + + es8311_reset(component, false); + + regcache_cache_only(es8311->regmap, false); + regcache_sync(es8311->regmap); + + return 0; +} + +static int es8311_component_probe(struct snd_soc_component *component) +{ + struct es8311_priv *es8311; + + es8311 = snd_soc_component_get_drvdata(component); + + es8311->mclk = devm_clk_get_optional(component->dev, "mclk"); + if (IS_ERR(es8311->mclk)) { + dev_err(component->dev, "invalid mclk\n"); + return PTR_ERR(es8311->mclk); + } + + es8311->mclk_freq = clk_get_rate(es8311->mclk); + if (es8311->mclk_freq > 0 && es8311->mclk_freq < ES8311_MCLK_MAX_FREQ) + es8311_set_sysclk_constraints(es8311->mclk_freq, es8311); + + es8311_reset(component, true); + es8311_reset(component, false); + + /* Set minimal power up time */ + snd_soc_component_write(component, ES8311_SYS1, 0); + snd_soc_component_write(component, ES8311_SYS2, 0); + + return 0; +} + +static const struct regmap_config es8311_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ES8311_REG_MAX, + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static const struct snd_soc_component_driver es8311_component_driver = { + .probe = es8311_component_probe, + .suspend = es8311_suspend, + .resume = es8311_resume, + .set_bias_level = es8311_set_bias_level, + .controls = es8311_snd_controls, + .num_controls = ARRAY_SIZE(es8311_snd_controls), + .dapm_widgets = es8311_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8311_dapm_widgets), + .dapm_routes = es8311_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8311_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, +}; + +static int es8311_i2c_probe(struct i2c_client *i2c_client) +{ + struct es8311_priv *es8311; + + struct device *dev = &i2c_client->dev; + + es8311 = devm_kzalloc(dev, sizeof(*es8311), GFP_KERNEL); + if (es8311 == NULL) + return -ENOMEM; + + es8311->regmap = + devm_regmap_init_i2c(i2c_client, &es8311_regmap_config); + if (IS_ERR(es8311->regmap)) + return PTR_ERR(es8311->regmap); + + i2c_set_clientdata(i2c_client, es8311); + + return devm_snd_soc_register_component(dev, &es8311_component_driver, + &es8311_dai, 1); +} + +static const struct i2c_device_id es8311_id[] = { { "es8311", 0 }, {} }; +MODULE_DEVICE_TABLE(i2c, es8311_id); + +static const struct of_device_id es8311_of_match[] = { + { + .compatible = "everest,es8311", + }, + {} +}; +MODULE_DEVICE_TABLE(of, es8311_of_match); + +static struct i2c_driver es8311_i2c_driver = { + .driver = { + .name = "es8311", + .of_match_table = es8311_of_match, + }, + .probe = es8311_i2c_probe, + .id_table = es8311_id, +}; + +module_i2c_driver(es8311_i2c_driver); + +MODULE_DESCRIPTION("ASoC ES8311 driver"); +MODULE_AUTHOR("Matteo Martelli "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8311.h b/sound/soc/codecs/es8311.h new file mode 100644 index 000000000000..8a3105bb8443 --- /dev/null +++ b/sound/soc/codecs/es8311.h @@ -0,0 +1,162 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * es8311.c -- es8311 ALSA SoC audio driver + * + * Copyright (C) 2024 Matteo Martelli + * + * Author: Matteo Martelli + */ + +#ifndef _ES8311_H +#define _ES8311_H + +#include + +#define ES8311_RESET 0x00 +#define ES8311_RESET_CSM_ON BIT(7) +#define ES8311_RESET_MSC BIT(6) +#define ES8311_RESET_RST_MASK GENMASK(4, 0) + +/* Clock Manager Registers */ +#define ES8311_CLKMGR1 0x01 +#define ES8311_CLKMGR1_MCLK_SEL BIT(7) +#define ES8311_CLKMGR1_MCLK_ON BIT(5) +#define ES8311_CLKMGR1_BCLK_ON BIT(4) +#define ES8311_CLKMGR1_CLKADC_ON_SHIFT 3 +#define ES8311_CLKMGR1_CLKDAC_ON_SHIFT 2 +#define ES8311_CLKMGR1_ANACLKADC_ON_SHIFT 1 +#define ES8311_CLKMGR1_ANACLKDAC_ON_SHIFT 0 +#define ES8311_CLKMGR2 0x02 +#define ES8311_CLKMGR2_DIV_PRE_MASK GENMASK(7, 5) +#define ES8311_CLKMGR2_DIV_PRE_SHIFT 5 +#define ES8311_CLKMGR2_DIV_PRE_MAX 0x07 +#define ES8311_CLKMGR2_MULT_PRE_MASK GENMASK(4, 3) +#define ES8311_CLKMGR2_MULT_PRE_SHIFT 3 +#define ES8311_CLKMGR3 0x03 +#define ES8311_CLKMGR4 0x04 +#define ES8311_CLKMGR5 0x05 +#define ES8311_CLKMGR5_ADC_DIV_MASK GENMASK(7, 4) +#define ES8311_CLKMGR5_ADC_DIV_SHIFT 4 +#define ES8311_CLKMGR5_DAC_DIV_MASK GENMASK(3, 0) +#define ES8311_CLKMGR5_DAC_DIV_SHIFT 0 +#define ES8311_CLKMGR6 0x06 +#define ES8311_CLKMGR6_BCLK_INV BIT(5) +#define ES8311_CLKMGR6_DIV_BCLK_MASK GENMASK(4, 0) +#define ES8311_CLKMGR7 0x07 +#define ES8311_CLKMGR7_LRCLK_DIV_H_MASK GENMASK(3, 0) +#define ES8311_CLKMGR8 0x08 +#define ES8311_CLKMGR_LRCLK_DIV_MAX 0x0FFF + +/* SDP Mode Registers */ +#define ES8311_SDP_IN 0x09 +#define ES8311_SDP_IN_SEL_SHIFT 7 +#define ES8311_SDP_OUT 0x0A +/* Following values are the same for both SPD_IN and SDP_OUT */ +#define ES8311_SDP_MUTE_SHIFT 6 +#define ES8311_SDP_LRP BIT(5) +#define ES8311_SDP_WL_MASK GENMASK(4, 2) +#define ES8311_SDP_WL_SHIFT 2 +#define ES8311_SDP_WL_24 0x00 +#define ES8311_SDP_WL_20 0x01 +#define ES8311_SDP_WL_18 0x02 +#define ES8311_SDP_WL_16 0x03 +#define ES8311_SDP_WL_32 0x04 +#define ES8311_SDP_FMT_MASK GENMASK(1, 0) +#define ES8311_SDP_FMT_I2S 0x00 +#define ES8311_SDP_FMT_LEFT_J 0x01 +#define ES8311_SDP_FMT_DSP 0x03 + +/* System registers */ +#define ES8311_SYS1 0x0B +#define ES8311_SYS2 0x0C +#define ES8311_SYS3 0x0D +#define ES8311_SYS3_PDN_ANA_SHIFT 7 +#define ES8311_SYS3_PDN_IBIASGEN_SHIFT 6 +#define ES8311_SYS3_PDN_ADCBIASGEN_SHIFT 5 +#define ES8311_SYS3_PDN_ADCVREFGEN_SHIFT 4 +#define ES8311_SYS3_PDN_DACVREFGEN_SHIFT 3 +#define ES8311_SYS3_PDN_VREF_SHIFT 2 +#define ES8311_SYS3_PDN_VMIDSEL_MASK GENMASK(1, 0) +#define ES8311_SYS3_PDN_VMIDSEL_POWER_DOWN 0 +#define ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED 1 +#define ES8311_SYS3_PDN_VMIDSEL_NORMAL_OPERATION 2 +#define ES8311_SYS3_PDN_VMIDSEL_STARTUP_FAST_SPEED 3 +#define ES8311_SYS4 0x0E +#define ES8311_SYS4_PDN_PGA_SHIFT 6 +#define ES8311_SYS4_PDN_MOD_SHIFT 5 +#define ES8311_SYS5 0x0F +#define ES8311_SYS6 0x10 +#define ES8311_SYS7 0x11 +#define ES8311_SYS8 0x12 +#define ES8311_SYS8_PDN_DAC_SHIFT 1 +#define ES8311_SYS9 0x13 +#define ES8311_SYS9_HPSW_SHIFT 4 +#define ES8311_SYS10 0x14 +#define ES8311_SYS10_DMIC_ON_SHIFT 6 +#define ES8311_SYS10_LINESEL_SHIFT 4 +#define ES8311_SYS10_PGAGAIN_SHIFT 0 +#define ES8311_SYS10_PGAGAIN_MAX 0x0A + +/* ADC Registers*/ +#define ES8311_ADC1 0x15 +#define ES8311_ADC1_RAMPRATE_SHIFT 4 +#define ES8311_ADC2 0x16 +#define ES8311_ADC2_INV_SHIFT 4 +#define ES8311_ADC2_SCALE_SHIFT 0 +#define ES8311_ADC2_SCALE_MAX 0x07 +#define ES8311_ADC3 0x17 +#define ES8311_ADC3_VOLUME_SHIFT 0 +#define ES8311_ADC3_VOLUME_MAX 0xFF +#define ES8311_ADC4 0x18 +#define ES8311_ADC4_ALC_EN_SHIFT 7 +#define ES8311_ADC4_AUTOMUTE_EN_SHIFT 6 +#define ES8311_ADC4_ALC_WINSIZE_SHIFT 0 +#define ES8311_ADC5 0x19 +#define ES8311_ADC5_ALC_MAXLEVEL_SHIFT 4 +#define ES8311_ADC5_ALC_MAXLEVEL_MAX 0x0F +#define ES8311_ADC5_ALC_MINLEVEL_SHIFT 0 +#define ES8311_ADC5_ALC_MINLEVEL_MAX 0x0F +#define ES8311_ADC6 0x1A +#define ES8311_ADC6_AUTOMUTE_WS_SHIFT 4 +#define ES8311_ADC6_AUTOMUTE_NG_SHIFT 0 +#define ES8311_ADC6_AUTOMUTE_NG_MAX 0x0F + +#define ES8311_ADC7 0x1B +#define ES8311_ADC7_AUTOMUTE_VOL_SHIFT 5 +#define ES8311_ADC7_AUTOMUTE_VOL_MAX 0x07 +#define ES8311_ADC8 0x1C +#define ES8311_ADC8_EQBYPASS_SHIFT 6 +#define ES8311_ADC8_HPF_SHIFT 5 + +/* DAC Registers */ +#define ES8311_DAC1 0x31 +#define ES8311_DAC1_DAC_DSMMUTE BIT(6) +#define ES8311_DAC1_DAC_DEMMUTE BIT(5) +#define ES8311_DAC2 0x32 +#define ES8311_DAC2_VOLUME_MAX 0xFF +#define ES8311_DAC3 0x33 +#define ES8311_DAC4 0x34 +#define ES8311_DAC4_DRC_EN_SHIFT 7 +#define ES8311_DAC4_DRC_WINSIZE_SHIFT 0 +#define ES8311_DAC5 0x35 +#define ES8311_DAC5_DRC_MAXLEVEL_SHIFT 4 +#define ES8311_DAC5_DRC_MAXLEVEL_MAX 0x0F +#define ES8311_DAC5_DRC_MINLEVEL_SHIFT 0 +#define ES8311_DAC5_DRC_MINLEVEL_MAX 0x0F +#define ES8311_DAC6 0x37 +#define ES8311_DAC6_RAMPRATE_SHIFT 4 +#define ES8311_DAC6_EQBYPASS_SHIFT 3 + +/* GPIO Registers */ +#define ES8311_GPIO 0x44 +#define ES8311_GPIO_ADC2DAC_SEL_SHIFT 7 +#define ES8311_GPIO_ADCDAT_SEL_SHIFT 4 + +/* Chip Info Registers */ +#define ES8311_CHIPID1 0xFD /* 0x83 */ +#define ES8311_CHIPID2 0xFE /* 0x11 */ +#define ES8311_CHIPVER 0xFF + +#define ES8311_REG_MAX 0xFF + +#endif From 965cc040bf0698e81b0c0aef359ae650b42b428e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 20 May 2024 16:19:56 +0200 Subject: [PATCH 003/349] ASoC: Constify channel mapping array arguments in set_channel_map() There is no need for implementations of DAI set_channel_map() to modify contents of passed arrays with actual channel mapping. Additionally, the caller keeps full ownership of the array. Constify these pointer arguments so the code will be safer and easier to read (documenting the caller's ownership). Acked-by: Charles Keepax Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240520-asoc-x1e80100-4-channel-mapping-v4-1-f657159b4aad@linaro.org Signed-off-by: Mark Brown --- include/sound/cs35l41.h | 4 ++-- include/sound/soc-dai.h | 8 ++++---- sound/soc/codecs/adau7118.c | 6 ++++-- sound/soc/codecs/cs35l41-lib.c | 4 ++-- sound/soc/codecs/cs35l41.c | 3 ++- sound/soc/codecs/max98504.c | 6 ++++-- sound/soc/codecs/wcd9335.c | 6 ++++-- sound/soc/codecs/wcd934x.c | 6 ++++-- sound/soc/qcom/qdsp6/q6afe-dai.c | 16 ++++++++++------ sound/soc/qcom/qdsp6/q6apm-lpass-dais.c | 6 ++++-- sound/soc/soc-dai.c | 4 ++-- 11 files changed, 42 insertions(+), 27 deletions(-) diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index bb70782d15d0..43c6a9ef8d9f 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -896,8 +896,8 @@ int cs35l41_test_key_lock(struct device *dev, struct regmap *regmap); int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap); int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsigned int reg_revid); int cs35l41_set_channels(struct device *dev, struct regmap *reg, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot); + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot); int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg); void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_dsp *dsp); int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap, diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index adcd8719d343..15ef268c9845 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -188,8 +188,8 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot); + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot); int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); @@ -305,8 +305,8 @@ struct snd_soc_dai_ops { unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); int (*set_channel_map)(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot); + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot); int (*get_channel_map)(struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c index a663d37e5776..abc4764697a5 100644 --- a/sound/soc/codecs/adau7118.c +++ b/sound/soc/codecs/adau7118.c @@ -121,8 +121,10 @@ static const struct snd_soc_dapm_widget adau7118_widgets[] = { }; static int adau7118_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) + unsigned int tx_num, + const unsigned int *tx_slot, + unsigned int rx_num, + const unsigned int *rx_slot) { struct adau7118_data *st = snd_soc_component_get_drvdata(dai->component); diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index e9993a39f7d0..1702f26049d3 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -936,8 +936,8 @@ int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsign EXPORT_SYMBOL_GPL(cs35l41_register_errata_patch); int cs35l41_set_channels(struct device *dev, struct regmap *reg, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot) { unsigned int val, mask; int i; diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index cb25c33cc9b9..1688c2c688f0 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -673,7 +673,8 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = { }; static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_n, - unsigned int *tx_slot, unsigned int rx_n, unsigned int *rx_slot) + const unsigned int *tx_slot, + unsigned int rx_n, const unsigned int *rx_slot) { struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component); diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c index 93412b966b33..6b6a7ece4cec 100644 --- a/sound/soc/codecs/max98504.c +++ b/sound/soc/codecs/max98504.c @@ -220,8 +220,10 @@ static int max98504_set_tdm_slot(struct snd_soc_dai *dai, return 0; } static int max98504_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) + unsigned int tx_num, + const unsigned int *tx_slot, + unsigned int rx_num, + const unsigned int *rx_slot) { struct max98504_priv *max98504 = snd_soc_dai_get_drvdata(dai); struct regmap *map = max98504->regmap; diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index deb15b95992d..42a99978fe5a 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -1983,8 +1983,10 @@ static int wcd9335_trigger(struct snd_pcm_substream *substream, int cmd, } static int wcd9335_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) + unsigned int tx_num, + const unsigned int *tx_slot, + unsigned int rx_num, + const unsigned int *rx_slot) { struct wcd9335_codec *wcd; int i; diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index de870c7819ca..fcad2c9fba55 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1923,8 +1923,10 @@ static int wcd934x_trigger(struct snd_pcm_substream *substream, int cmd, } static int wcd934x_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) + unsigned int tx_num, + const unsigned int *tx_slot, + unsigned int rx_num, + const unsigned int *rx_slot) { struct wcd934x_codec *wcd; int i; diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index a9c4f896a7df..7d9628cda875 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -172,8 +172,8 @@ static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai, } static int q6tdm_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); @@ -250,8 +250,10 @@ static int q6tdm_hw_params(struct snd_pcm_substream *substream, } static int q6dma_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_ch_mask, - unsigned int rx_num, unsigned int *rx_ch_mask) + unsigned int tx_num, + const unsigned int *tx_ch_mask, + unsigned int rx_num, + const unsigned int *rx_ch_mask) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); @@ -407,8 +409,10 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream, } static int q6slim_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) + unsigned int tx_num, + const unsigned int *tx_slot, + unsigned int rx_num, + const unsigned int *rx_slot) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id]; diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index 68a38f63a2db..6bfbb52345e1 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -25,8 +25,10 @@ struct q6apm_lpass_dai_data { }; static int q6dma_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_ch_mask, - unsigned int rx_num, unsigned int *rx_ch_mask) + unsigned int tx_num, + const unsigned int *tx_ch_mask, + unsigned int rx_num, + const unsigned int *rx_ch_mask) { struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index fefe394dce72..03afd5efb24c 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -304,8 +304,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); * configure the relationship between channel number and TDM slot number. */ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot) { int ret = -ENOTSUPP; From 22ad2e3c21281802cd519454544009da7e7a8ea4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 20 May 2024 16:19:57 +0200 Subject: [PATCH 004/349] ASoC: qcom: q6apm-lpass-dais: Implement proper channel mapping The set_channel_map() implementation in q6apm-lpass-dais driver was copying older pre-Audioreach code from q6afe-dai driver, but not really using it. The code sets active channel mask based on passed channel mapping, but Audioreach code does not use that mask ever. Audioreach module configuration does have on the other hand proper channel mapping field, which should supersed that active channel mask. Drop the unused active channel mask and implement proper mapping of channels in q6apm-lpass-dais driver. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240520-asoc-x1e80100-4-channel-mapping-v4-2-f657159b4aad@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/audioreach.h | 1 - sound/soc/qcom/qdsp6/q6apm-lpass-dais.c | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index 2c82917b7162..eb9306280988 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -755,7 +755,6 @@ struct audioreach_module_config { u16 data_format; u16 num_channels; - u16 active_channels_mask; u16 dp_idx; u32 channel_allocation; u32 sd_line_mask; diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index 6bfbb52345e1..a4ad1d0e6abd 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -33,7 +33,7 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai, struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); struct audioreach_module_config *cfg = &dai_data->module_config[dai->id]; - int ch_mask; + int i; switch (dai->id) { case WSA_CODEC_DMA_TX_0: @@ -58,7 +58,8 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai, tx_num); return -EINVAL; } - ch_mask = *tx_ch_mask; + for (i = 0; i < tx_num; i++) + cfg->channel_map[i] = tx_ch_mask[i]; break; case WSA_CODEC_DMA_RX_0: @@ -81,7 +82,8 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai, rx_num); return -EINVAL; } - ch_mask = *rx_ch_mask; + for (i = 0; i < rx_num; i++) + cfg->channel_map[i] = rx_ch_mask[i]; break; default: @@ -90,8 +92,6 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai, return -EINVAL; } - cfg->active_channels_mask = ch_mask; - return 0; } From 5d5dd9bb227a1bdbef5ec7d167ac65775d1b99dc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 20 May 2024 16:19:58 +0200 Subject: [PATCH 005/349] ASoC: qcom: qdsp6: Set channel mapping instead of fixed defaults When constructing packets to DSP, the Audioreach code uses 'struct audioreach_module_config' to configure parameters like number of channels, bitrate, sample rate etc, but uses defaults for the channel mapping. Rework this code to copy the channel mapping from 'struct audioreach_module_config', instead of using the default. This requires all callers to fill that structure: add missing initialization of channel mapping. Entire patch makes code more logical and easier to follow: 1. q6apm-dai and q6apm-lpass-dais code which allocates 'struct audioreach_module_config' initializes it fully, so fills both the number of channels and the channel mapping. 2. Audioreach code, which uses 'struct audioreach_module_config' when constructing packets, copies entire contents of passed config, not only pieces of it. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240520-asoc-x1e80100-4-channel-mapping-v4-3-f657159b4aad@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/audioreach.c | 30 ++++++------------------- sound/soc/qcom/qdsp6/audioreach.h | 1 + sound/soc/qcom/qdsp6/q6apm-dai.c | 3 +++ sound/soc/qcom/qdsp6/q6apm-lpass-dais.c | 5 ++++- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index 5291deac0a0b..4ebaaf736fb9 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -267,7 +267,7 @@ void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t token } EXPORT_SYMBOL_GPL(audioreach_alloc_apm_cmd_pkt); -static void audioreach_set_channel_mapping(u8 *ch_map, int num_channels) +void audioreach_set_default_channel_mapping(u8 *ch_map, int num_channels) { if (num_channels == 1) { ch_map[0] = PCM_CHANNEL_FL; @@ -281,6 +281,7 @@ static void audioreach_set_channel_mapping(u8 *ch_map, int num_channels) ch_map[3] = PCM_CHANNEL_RS; } } +EXPORT_SYMBOL_GPL(audioreach_set_default_channel_mapping); static void apm_populate_container_config(struct apm_container_obj *cfg, struct audioreach_container *cont) @@ -819,7 +820,7 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, uint32_t num_channels = cfg->num_channels; int payload_size; struct gpr_pkt *pkt; - int rc; + int rc, i; void *p; payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) + @@ -842,18 +843,8 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, media_format->sample_rate = cfg->sample_rate; media_format->bit_width = cfg->bit_width; media_format->num_channels = cfg->num_channels; - - if (num_channels == 1) { - media_format->channel_mapping[0] = PCM_CHANNEL_FL; - } else if (num_channels == 2) { - media_format->channel_mapping[0] = PCM_CHANNEL_FL; - media_format->channel_mapping[1] = PCM_CHANNEL_FR; - } else if (num_channels == 4) { - media_format->channel_mapping[0] = PCM_CHANNEL_FL; - media_format->channel_mapping[1] = PCM_CHANNEL_FR; - media_format->channel_mapping[2] = PCM_CHANNEL_LS; - media_format->channel_mapping[3] = PCM_CHANNEL_RS; - } + for (i = 0; i < num_channels; i++) + media_format->channel_mapping[i] = cfg->channel_map[i]; rc = q6apm_send_cmd_sync(graph->apm, pkt, 0); @@ -883,9 +874,6 @@ static int audioreach_set_compr_media_format(struct media_format *media_fmt_hdr, mp3_cfg->q_factor = mcfg->bit_width - 1; mp3_cfg->endianness = PCM_LITTLE_ENDIAN; mp3_cfg->num_channels = mcfg->num_channels; - - audioreach_set_channel_mapping(mp3_cfg->channel_mapping, - mcfg->num_channels); break; case SND_AUDIOCODEC_AAC: media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED; @@ -1104,9 +1092,7 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, media_cfg->num_channels = mcfg->num_channels; media_cfg->q_factor = mcfg->bit_width - 1; media_cfg->bits_per_sample = mcfg->bit_width; - - audioreach_set_channel_mapping(media_cfg->channel_mapping, - num_channels); + memcpy(media_cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels); rc = q6apm_send_cmd_sync(graph->apm, pkt, 0); @@ -1163,9 +1149,7 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, cfg->q_factor = mcfg->bit_width - 1; cfg->endianness = PCM_LITTLE_ENDIAN; cfg->num_channels = mcfg->num_channels; - - audioreach_set_channel_mapping(cfg->channel_mapping, - num_channels); + memcpy(cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels); } else { rc = audioreach_set_compr_media_format(header, p, mcfg); if (rc) { diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index eb9306280988..61a69df4f50f 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -766,6 +766,7 @@ struct audioreach_module_config { /* Packet Allocation routines */ void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t token); +void audioreach_set_default_channel_mapping(u8 *ch_map, int num_channels); void *audioreach_alloc_cmd_pkt(int payload_size, uint32_t opcode, uint32_t token, uint32_t src_port, uint32_t dest_port); diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c index c7df8343b2dc..c9404b5934c7 100644 --- a/sound/soc/qcom/qdsp6/q6apm-dai.c +++ b/sound/soc/qcom/qdsp6/q6apm-dai.c @@ -239,6 +239,7 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, cfg.num_channels = runtime->channels; cfg.bit_width = prtd->bits_per_sample; cfg.fmt = SND_AUDIOCODEC_PCM; + audioreach_set_default_channel_mapping(cfg.channel_map, runtime->channels); if (prtd->state) { /* clear the previous setup if any */ @@ -665,6 +666,8 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component, cfg.num_channels = 2; cfg.bit_width = prtd->bits_per_sample; cfg.fmt = codec->id; + audioreach_set_default_channel_mapping(cfg.channel_map, + cfg.num_channels); memcpy(&cfg.codec, codec, sizeof(*codec)); ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg); diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index a4ad1d0e6abd..ba28ec9dff86 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -106,6 +106,7 @@ static int q6hdmi_hw_params(struct snd_pcm_substream *substream, cfg->bit_width = params_width(params); cfg->sample_rate = params_rate(params); cfg->num_channels = channels; + audioreach_set_default_channel_mapping(cfg->channel_map, channels); switch (dai->id) { case DISPLAY_PORT_RX_0: @@ -130,10 +131,12 @@ static int q6dma_hw_params(struct snd_pcm_substream *substream, { struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); struct audioreach_module_config *cfg = &dai_data->module_config[dai->id]; + int channels = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max; cfg->bit_width = params_width(params); cfg->sample_rate = params_rate(params); - cfg->num_channels = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max; + cfg->num_channels = channels; + audioreach_set_default_channel_mapping(cfg->channel_map, channels); return 0; } From cf03e271fdca8059090622ef27c20576341f1a75 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 20 May 2024 16:19:59 +0200 Subject: [PATCH 006/349] ASoC: qcom: x1e80100: Correct channel mapping X1E80100 CRD board comes with four speakers arranged as left front+back and then right front+back. Using default channel mapping causes front right speaker to play left back stream. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240520-asoc-x1e80100-4-channel-mapping-v4-4-f657159b4aad@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/x1e80100.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c index 0e0773a85809..d7e0bd03dffd 100644 --- a/sound/soc/qcom/x1e80100.c +++ b/sound/soc/qcom/x1e80100.c @@ -12,6 +12,7 @@ #include "common.h" #include "qdsp6/q6afe.h" +#include "qdsp6/q6dsp-common.h" #include "sdw.h" struct x1e80100_snd_data { @@ -80,6 +81,23 @@ static int x1e80100_snd_prepare(struct snd_pcm_substream *substream) struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + const unsigned int rx_slot[4] = { PCM_CHANNEL_FL, + PCM_CHANNEL_LB, + PCM_CHANNEL_FR, + PCM_CHANNEL_RB }; + int ret; + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + case WSA_CODEC_DMA_RX_1: + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, + ARRAY_SIZE(rx_slot), rx_slot); + if (ret) + return ret; + break; + default: + break; + } return qcom_snd_sdw_prepare(substream, sruntime, &data->stream_prepared[cpu_dai->id]); From bad0a07a7e61a54969cdbb188b143e39040acf43 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 21 May 2024 16:46:25 +0800 Subject: [PATCH 007/349] ASoC: rt1320: Add RT1320 SDCA vendor-specific driver This is the initial amplifier driver for rt1320. -- add class id 1 Signed-off-by: Shuming Fan v2: add Capture DAI for AEC feedback v3: add some comments for blind writes/patch_code/calling sdw_slave_read_prop v4: add comments for different class id Reviewed-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240521084625.453554-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt1320-sdw.c | 2260 +++++++++++++++++++++++++++++++++ sound/soc/codecs/rt1320-sdw.h | 94 ++ 4 files changed, 2363 insertions(+) create mode 100644 sound/soc/codecs/rt1320-sdw.c create mode 100644 sound/soc/codecs/rt1320-sdw.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 4afc43d3f71f..7502581d1631 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -222,6 +222,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT1308_SDW imply SND_SOC_RT1316_SDW imply SND_SOC_RT1318_SDW + imply SND_SOC_RT1320_SDW imply SND_SOC_RT9120 imply SND_SOC_RTQ9128 imply SND_SOC_SDW_MOCKUP @@ -1575,6 +1576,12 @@ config SND_SOC_RT1318_SDW depends on SOUNDWIRE select REGMAP_SOUNDWIRE +config SND_SOC_RT1320_SDW + tristate "Realtek RT1320 Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + select REGMAP_SOUNDWIRE_MBQ + config SND_SOC_RT5514 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b4df22186e25..f9eb7c073a00 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -222,6 +222,7 @@ snd-soc-rt1308-y := rt1308.o snd-soc-rt1308-sdw-y := rt1308-sdw.o snd-soc-rt1316-sdw-y := rt1316-sdw.o snd-soc-rt1318-sdw-y := rt1318-sdw.o +snd-soc-rt1320-sdw-y := rt1320-sdw.o snd-soc-rt274-y := rt274.o snd-soc-rt286-y := rt286.o snd-soc-rt298-y := rt298.o @@ -614,6 +615,7 @@ obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o obj-$(CONFIG_SND_SOC_RT1318_SDW) += snd-soc-rt1318-sdw.o +obj-$(CONFIG_SND_SOC_RT1320_SDW) += snd-soc-rt1320-sdw.o obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c new file mode 100644 index 000000000000..2916fa77b791 --- /dev/null +++ b/sound/soc/codecs/rt1320-sdw.c @@ -0,0 +1,2260 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt1320-sdw.c -- rt1320 SDCA ALSA SoC amplifier audio driver +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rt1320-sdw.h" + +/* + * The 'blind writes' is an SDCA term to deal with platform-specific initialization. + * It might include vendor-specific or SDCA control registers. + */ +static const struct reg_sequence rt1320_blind_write[] = { + { 0xc003, 0xe0 }, + { 0xc01b, 0xfc }, + { 0xc5c3, 0xf2 }, + { 0xc5c2, 0x00 }, + { 0xc5c6, 0x10 }, + { 0xc5c4, 0x12 }, + { 0xc5c8, 0x03 }, + { 0xc5d8, 0x0a }, + { 0xc5f7, 0x22 }, + { 0xc5f6, 0x22 }, + { 0xc5d0, 0x0f }, + { 0xc5d1, 0x89 }, + { 0xc057, 0x51 }, + { 0xc054, 0x35 }, + { 0xc053, 0x55 }, + { 0xc052, 0x55 }, + { 0xc051, 0x13 }, + { 0xc050, 0x15 }, + { 0xc060, 0x77 }, + { 0xc061, 0x55 }, + { 0xc063, 0x55 }, + { 0xc065, 0xa5 }, + { 0xc06b, 0x0a }, + { 0xca05, 0xd6 }, + { 0xca25, 0xd6 }, + { 0xcd00, 0x05 }, + { 0xc604, 0x40 }, + { 0xc609, 0x40 }, + { 0xc046, 0xff }, + { 0xc045, 0xff }, + { 0xc044, 0xff }, + { 0xc043, 0xff }, + { 0xc042, 0xff }, + { 0xc041, 0xff }, + { 0xc040, 0xff }, + { 0xcc10, 0x01 }, + { 0xc700, 0xf0 }, + { 0xc701, 0x13 }, + { 0xc901, 0x04 }, + { 0xc900, 0x73 }, + { 0xde03, 0x05 }, + { 0xdd0b, 0x0d }, + { 0xdd0a, 0xff }, + { 0xdd09, 0x0d }, + { 0xdd08, 0xff }, + { 0xc570, 0x08 }, + { 0xe803, 0xbe }, + { 0xc003, 0xc0 }, + { 0xc081, 0xfe }, + { 0xce31, 0x0d }, + { 0xce30, 0xae }, + { 0xce37, 0x0b }, + { 0xce36, 0xd2 }, + { 0xce39, 0x04 }, + { 0xce38, 0x80 }, + { 0xce3f, 0x00 }, + { 0xce3e, 0x00 }, + { 0xd470, 0x8b }, + { 0xd471, 0x18 }, + { 0xc019, 0x10 }, + { 0xd487, 0x3f }, + { 0xd486, 0xc3 }, +}; + +/* + * The 'patch code' is written to the patch code area. + * The patch code area is used for SDCA register expansion flexibility. + */ +static const struct reg_sequence rt1320_patch_code_write[] = { + { 0x10007000, 0x37 }, + { 0x10007001, 0x77 }, + { 0x10007002, 0x00 }, + { 0x10007003, 0x10 }, + { 0x10007004, 0xb7 }, + { 0x10007005, 0xe7 }, + { 0x10007006, 0x00 }, + { 0x10007007, 0x10 }, + { 0x10007008, 0x13 }, + { 0x10007009, 0x07 }, + { 0x1000700a, 0x07 }, + { 0x1000700b, 0x40 }, + { 0x1000700c, 0x23 }, + { 0x1000700d, 0xae }, + { 0x1000700e, 0xe7 }, + { 0x1000700f, 0xda }, + { 0x10007010, 0x37 }, + { 0x10007011, 0x77 }, + { 0x10007012, 0x00 }, + { 0x10007013, 0x10 }, + { 0x10007014, 0x13 }, + { 0x10007015, 0x07 }, + { 0x10007016, 0x47 }, + { 0x10007017, 0x61 }, + { 0x10007018, 0x23 }, + { 0x10007019, 0xa4 }, + { 0x1000701a, 0xe7 }, + { 0x1000701b, 0xde }, + { 0x1000701c, 0x37 }, + { 0x1000701d, 0x77 }, + { 0x1000701e, 0x00 }, + { 0x1000701f, 0x10 }, + { 0x10007020, 0x13 }, + { 0x10007021, 0x07 }, + { 0x10007022, 0x07 }, + { 0x10007023, 0x52 }, + { 0x10007024, 0x23 }, + { 0x10007025, 0xae }, + { 0x10007026, 0xe7 }, + { 0x10007027, 0xde }, + { 0x10007028, 0x37 }, + { 0x10007029, 0x77 }, + { 0x1000702a, 0x00 }, + { 0x1000702b, 0x10 }, + { 0x1000702c, 0x13 }, + { 0x1000702d, 0x07 }, + { 0x1000702e, 0x47 }, + { 0x1000702f, 0x54 }, + { 0x10007030, 0x23 }, + { 0x10007031, 0xaa }, + { 0x10007032, 0xe7 }, + { 0x10007033, 0xe4 }, + { 0x10007034, 0x37 }, + { 0x10007035, 0x87 }, + { 0x10007036, 0x00 }, + { 0x10007037, 0x10 }, + { 0x10007038, 0x13 }, + { 0x10007039, 0x07 }, + { 0x1000703a, 0x47 }, + { 0x1000703b, 0x81 }, + { 0x1000703c, 0x23 }, + { 0x1000703d, 0xa2 }, + { 0x1000703e, 0xe7 }, + { 0x1000703f, 0xe8 }, + { 0x10007040, 0x23 }, + { 0x10007041, 0xa4 }, + { 0x10007042, 0xe7 }, + { 0x10007043, 0xe8 }, + { 0x10007044, 0x37 }, + { 0x10007045, 0x77 }, + { 0x10007046, 0x00 }, + { 0x10007047, 0x10 }, + { 0x10007048, 0x13 }, + { 0x10007049, 0x07 }, + { 0x1000704a, 0x07 }, + { 0x1000704b, 0x59 }, + { 0x1000704c, 0x23 }, + { 0x1000704d, 0xa8 }, + { 0x1000704e, 0xe7 }, + { 0x1000704f, 0xea }, + { 0x10007050, 0x37 }, + { 0x10007051, 0x77 }, + { 0x10007052, 0x00 }, + { 0x10007053, 0x10 }, + { 0x10007054, 0x13 }, + { 0x10007055, 0x07 }, + { 0x10007056, 0x07 }, + { 0x10007057, 0x78 }, + { 0x10007058, 0x23 }, + { 0x10007059, 0xa6 }, + { 0x1000705a, 0xe7 }, + { 0x1000705b, 0xec }, + { 0x1000705c, 0x67 }, + { 0x1000705d, 0x80 }, + { 0x1000705e, 0x00 }, + { 0x1000705f, 0x00 }, + { 0x10007400, 0x37 }, + { 0x10007401, 0xd7 }, + { 0x10007402, 0x00 }, + { 0x10007403, 0x00 }, + { 0x10007404, 0x83 }, + { 0x10007405, 0x27 }, + { 0x10007406, 0x47 }, + { 0x10007407, 0x56 }, + { 0x10007408, 0xb7 }, + { 0x10007409, 0x06 }, + { 0x1000740a, 0x00 }, + { 0x1000740b, 0x02 }, + { 0x1000740c, 0xb3 }, + { 0x1000740d, 0xf7 }, + { 0x1000740e, 0xd7 }, + { 0x1000740f, 0x00 }, + { 0x10007410, 0x63 }, + { 0x10007411, 0x8a }, + { 0x10007412, 0x07 }, + { 0x10007413, 0x00 }, + { 0x10007414, 0x93 }, + { 0x10007415, 0x06 }, + { 0x10007416, 0x10 }, + { 0x10007417, 0x00 }, + { 0x10007418, 0x23 }, + { 0x10007419, 0x83 }, + { 0x1000741a, 0xd1 }, + { 0x1000741b, 0x44 }, + { 0x1000741c, 0x93 }, + { 0x1000741d, 0x07 }, + { 0x1000741e, 0xf0 }, + { 0x1000741f, 0xff }, + { 0x10007420, 0x23 }, + { 0x10007421, 0x22 }, + { 0x10007422, 0xf7 }, + { 0x10007423, 0x56 }, + { 0x10007424, 0x37 }, + { 0x10007425, 0xd7 }, + { 0x10007426, 0x00 }, + { 0x10007427, 0x00 }, + { 0x10007428, 0x83 }, + { 0x10007429, 0x27 }, + { 0x1000742a, 0x47 }, + { 0x1000742b, 0x58 }, + { 0x1000742c, 0x93 }, + { 0x1000742d, 0xf7 }, + { 0x1000742e, 0x17 }, + { 0x1000742f, 0x00 }, + { 0x10007430, 0x63 }, + { 0x10007431, 0x86 }, + { 0x10007432, 0x07 }, + { 0x10007433, 0x00 }, + { 0x10007434, 0x93 }, + { 0x10007435, 0x07 }, + { 0x10007436, 0x10 }, + { 0x10007437, 0x00 }, + { 0x10007438, 0x23 }, + { 0x10007439, 0x22 }, + { 0x1000743a, 0xf7 }, + { 0x1000743b, 0x58 }, + { 0x1000743c, 0xb7 }, + { 0x1000743d, 0xd7 }, + { 0x1000743e, 0x00 }, + { 0x1000743f, 0x00 }, + { 0x10007440, 0x03 }, + { 0x10007441, 0xa7 }, + { 0x10007442, 0x47 }, + { 0x10007443, 0x58 }, + { 0x10007444, 0xb7 }, + { 0x10007445, 0x07 }, + { 0x10007446, 0x00 }, + { 0x10007447, 0x04 }, + { 0x10007448, 0x33 }, + { 0x10007449, 0x77 }, + { 0x1000744a, 0xf7 }, + { 0x1000744b, 0x00 }, + { 0x1000744c, 0x93 }, + { 0x1000744d, 0x07 }, + { 0x1000744e, 0x00 }, + { 0x1000744f, 0x00 }, + { 0x10007450, 0x63 }, + { 0x10007451, 0x0e }, + { 0x10007452, 0x07 }, + { 0x10007453, 0x04 }, + { 0x10007454, 0x37 }, + { 0x10007455, 0x07 }, + { 0x10007456, 0x00 }, + { 0x10007457, 0x11 }, + { 0x10007458, 0x03 }, + { 0x10007459, 0x47 }, + { 0x1000745a, 0x87 }, + { 0x1000745b, 0x0e }, + { 0x1000745c, 0x93 }, + { 0x1000745d, 0x06 }, + { 0x1000745e, 0x40 }, + { 0x1000745f, 0x00 }, + { 0x10007460, 0x13 }, + { 0x10007461, 0x77 }, + { 0x10007462, 0xf7 }, + { 0x10007463, 0x0f }, + { 0x10007464, 0x63 }, + { 0x10007465, 0x02 }, + { 0x10007466, 0xd7 }, + { 0x10007467, 0x0a }, + { 0x10007468, 0x93 }, + { 0x10007469, 0x06 }, + { 0x1000746a, 0x70 }, + { 0x1000746b, 0x00 }, + { 0x1000746c, 0x63 }, + { 0x1000746d, 0x10 }, + { 0x1000746e, 0xd7 }, + { 0x1000746f, 0x04 }, + { 0x10007470, 0x93 }, + { 0x10007471, 0x07 }, + { 0x10007472, 0x60 }, + { 0x10007473, 0x06 }, + { 0x10007474, 0x37 }, + { 0x10007475, 0xd7 }, + { 0x10007476, 0x00 }, + { 0x10007477, 0x00 }, + { 0x10007478, 0x83 }, + { 0x10007479, 0x46 }, + { 0x1000747a, 0x77 }, + { 0x1000747b, 0xa6 }, + { 0x1000747c, 0x93 }, + { 0x1000747d, 0xe6 }, + { 0x1000747e, 0x06 }, + { 0x1000747f, 0xf8 }, + { 0x10007480, 0x93 }, + { 0x10007481, 0xf6 }, + { 0x10007482, 0xf6 }, + { 0x10007483, 0x0f }, + { 0x10007484, 0xa3 }, + { 0x10007485, 0x03 }, + { 0x10007486, 0xd7 }, + { 0x10007487, 0xa6 }, + { 0x10007488, 0x83 }, + { 0x10007489, 0x46 }, + { 0x1000748a, 0x77 }, + { 0x1000748b, 0xa8 }, + { 0x1000748c, 0x93 }, + { 0x1000748d, 0xe6 }, + { 0x1000748e, 0x06 }, + { 0x1000748f, 0xf8 }, + { 0x10007490, 0x93 }, + { 0x10007491, 0xf6 }, + { 0x10007492, 0xf6 }, + { 0x10007493, 0x0f }, + { 0x10007494, 0xa3 }, + { 0x10007495, 0x03 }, + { 0x10007496, 0xd7 }, + { 0x10007497, 0xa8 }, + { 0x10007498, 0xb7 }, + { 0x10007499, 0xc6 }, + { 0x1000749a, 0x00 }, + { 0x1000749b, 0x00 }, + { 0x1000749c, 0x23 }, + { 0x1000749d, 0x84 }, + { 0x1000749e, 0xf6 }, + { 0x1000749f, 0x06 }, + { 0x100074a0, 0xa3 }, + { 0x100074a1, 0x84 }, + { 0x100074a2, 0xf6 }, + { 0x100074a3, 0x06 }, + { 0x100074a4, 0xb7 }, + { 0x100074a5, 0x06 }, + { 0x100074a6, 0x00 }, + { 0x100074a7, 0x04 }, + { 0x100074a8, 0x23 }, + { 0x100074a9, 0x22 }, + { 0x100074aa, 0xd7 }, + { 0x100074ab, 0x58 }, + { 0x100074ac, 0x37 }, + { 0x100074ad, 0xd7 }, + { 0x100074ae, 0x00 }, + { 0x100074af, 0x00 }, + { 0x100074b0, 0x03 }, + { 0x100074b1, 0x27 }, + { 0x100074b2, 0x47 }, + { 0x100074b3, 0x58 }, + { 0x100074b4, 0xb7 }, + { 0x100074b5, 0x06 }, + { 0x100074b6, 0x00 }, + { 0x100074b7, 0x08 }, + { 0x100074b8, 0x33 }, + { 0x100074b9, 0x77 }, + { 0x100074ba, 0xd7 }, + { 0x100074bb, 0x00 }, + { 0x100074bc, 0x63 }, + { 0x100074bd, 0x04 }, + { 0x100074be, 0x07 }, + { 0x100074bf, 0x04 }, + { 0x100074c0, 0x37 }, + { 0x100074c1, 0x07 }, + { 0x100074c2, 0x00 }, + { 0x100074c3, 0x11 }, + { 0x100074c4, 0x03 }, + { 0x100074c5, 0x47 }, + { 0x100074c6, 0xc7 }, + { 0x100074c7, 0x0e }, + { 0x100074c8, 0x93 }, + { 0x100074c9, 0x06 }, + { 0x100074ca, 0x40 }, + { 0x100074cb, 0x00 }, + { 0x100074cc, 0x13 }, + { 0x100074cd, 0x77 }, + { 0x100074ce, 0xf7 }, + { 0x100074cf, 0x0f }, + { 0x100074d0, 0x63 }, + { 0x100074d1, 0x00 }, + { 0x100074d2, 0xd7 }, + { 0x100074d3, 0x04 }, + { 0x100074d4, 0x93 }, + { 0x100074d5, 0x06 }, + { 0x100074d6, 0x70 }, + { 0x100074d7, 0x00 }, + { 0x100074d8, 0x63 }, + { 0x100074d9, 0x00 }, + { 0x100074da, 0xd7 }, + { 0x100074db, 0x04 }, + { 0x100074dc, 0x63 }, + { 0x100074dd, 0x84 }, + { 0x100074de, 0x07 }, + { 0x100074df, 0x02 }, + { 0x100074e0, 0xb7 }, + { 0x100074e1, 0xd6 }, + { 0x100074e2, 0x00 }, + { 0x100074e3, 0x00 }, + { 0x100074e4, 0x03 }, + { 0x100074e5, 0xc7 }, + { 0x100074e6, 0x56 }, + { 0x100074e7, 0xa4 }, + { 0x100074e8, 0x13 }, + { 0x100074e9, 0x67 }, + { 0x100074ea, 0x07 }, + { 0x100074eb, 0xf8 }, + { 0x100074ec, 0x13 }, + { 0x100074ed, 0x77 }, + { 0x100074ee, 0xf7 }, + { 0x100074ef, 0x0f }, + { 0x100074f0, 0xa3 }, + { 0x100074f1, 0x82 }, + { 0x100074f2, 0xe6 }, + { 0x100074f3, 0xa4 }, + { 0x100074f4, 0x37 }, + { 0x100074f5, 0xc7 }, + { 0x100074f6, 0x00 }, + { 0x100074f7, 0x00 }, + { 0x100074f8, 0x23 }, + { 0x100074f9, 0x02 }, + { 0x100074fa, 0xf7 }, + { 0x100074fb, 0x06 }, + { 0x100074fc, 0xb7 }, + { 0x100074fd, 0x07 }, + { 0x100074fe, 0x00 }, + { 0x100074ff, 0x08 }, + { 0x10007500, 0x23 }, + { 0x10007501, 0xa2 }, + { 0x10007502, 0xf6 }, + { 0x10007503, 0x58 }, + { 0x10007504, 0x67 }, + { 0x10007505, 0x80 }, + { 0x10007506, 0x00 }, + { 0x10007507, 0x00 }, + { 0x10007508, 0x93 }, + { 0x10007509, 0x07 }, + { 0x1000750a, 0x80 }, + { 0x1000750b, 0x08 }, + { 0x1000750c, 0x6f }, + { 0x1000750d, 0xf0 }, + { 0x1000750e, 0x9f }, + { 0x1000750f, 0xf6 }, + { 0x10007510, 0x93 }, + { 0x10007511, 0x07 }, + { 0x10007512, 0x80 }, + { 0x10007513, 0x08 }, + { 0x10007514, 0x6f }, + { 0x10007515, 0xf0 }, + { 0x10007516, 0xdf }, + { 0x10007517, 0xfc }, + { 0x10007518, 0x93 }, + { 0x10007519, 0x07 }, + { 0x1000751a, 0x60 }, + { 0x1000751b, 0x06 }, + { 0x1000751c, 0x6f }, + { 0x1000751d, 0xf0 }, + { 0x1000751e, 0x5f }, + { 0x1000751f, 0xfc }, + { 0x10007520, 0x37 }, + { 0x10007521, 0xd7 }, + { 0x10007522, 0x00 }, + { 0x10007523, 0x00 }, + { 0x10007524, 0x83 }, + { 0x10007525, 0x27 }, + { 0x10007526, 0x07 }, + { 0x10007527, 0x53 }, + { 0x10007528, 0xb7 }, + { 0x10007529, 0x06 }, + { 0x1000752a, 0x02 }, + { 0x1000752b, 0x00 }, + { 0x1000752c, 0xb3 }, + { 0x1000752d, 0xf7 }, + { 0x1000752e, 0xd7 }, + { 0x1000752f, 0x00 }, + { 0x10007530, 0x63 }, + { 0x10007531, 0x88 }, + { 0x10007532, 0x07 }, + { 0x10007533, 0x00 }, + { 0x10007534, 0x13 }, + { 0x10007535, 0x06 }, + { 0x10007536, 0xa0 }, + { 0x10007537, 0x05 }, + { 0x10007538, 0x23 }, + { 0x10007539, 0xa8 }, + { 0x1000753a, 0xc1 }, + { 0x1000753b, 0x56 }, + { 0x1000753c, 0x23 }, + { 0x1000753d, 0x28 }, + { 0x1000753e, 0xd7 }, + { 0x1000753f, 0x52 }, + { 0x10007540, 0x67 }, + { 0x10007541, 0x80 }, + { 0x10007542, 0x00 }, + { 0x10007543, 0x00 }, + { 0x10007544, 0x37 }, + { 0x10007545, 0xd7 }, + { 0x10007546, 0x00 }, + { 0x10007547, 0x10 }, + { 0x10007548, 0x83 }, + { 0x10007549, 0x47 }, + { 0x1000754a, 0x07 }, + { 0x1000754b, 0xd9 }, + { 0x1000754c, 0x93 }, + { 0x1000754d, 0x06 }, + { 0x1000754e, 0x20 }, + { 0x1000754f, 0x00 }, + { 0x10007550, 0x93 }, + { 0x10007551, 0xf7 }, + { 0x10007552, 0xf7 }, + { 0x10007553, 0x0f }, + { 0x10007554, 0x63 }, + { 0x10007555, 0x9c }, + { 0x10007556, 0xd7 }, + { 0x10007557, 0x02 }, + { 0x10007558, 0xb7 }, + { 0x10007559, 0xc6 }, + { 0x1000755a, 0x00 }, + { 0x1000755b, 0x00 }, + { 0x1000755c, 0x83 }, + { 0x1000755d, 0xc7 }, + { 0x1000755e, 0x26 }, + { 0x1000755f, 0x04 }, + { 0x10007560, 0x93 }, + { 0x10007561, 0xf7 }, + { 0x10007562, 0xf7 }, + { 0x10007563, 0x07 }, + { 0x10007564, 0x23 }, + { 0x10007565, 0x81 }, + { 0x10007566, 0xf6 }, + { 0x10007567, 0x04 }, + { 0x10007568, 0xb7 }, + { 0x10007569, 0xd6 }, + { 0x1000756a, 0x00 }, + { 0x1000756b, 0x00 }, + { 0x1000756c, 0x83 }, + { 0x1000756d, 0xc7 }, + { 0x1000756e, 0xa6 }, + { 0x1000756f, 0xe1 }, + { 0x10007570, 0x93 }, + { 0x10007571, 0xf7 }, + { 0x10007572, 0xf7 }, + { 0x10007573, 0x07 }, + { 0x10007574, 0x23 }, + { 0x10007575, 0x8d }, + { 0x10007576, 0xf6 }, + { 0x10007577, 0xe0 }, + { 0x10007578, 0x23 }, + { 0x10007579, 0x08 }, + { 0x1000757a, 0x07 }, + { 0x1000757b, 0xd8 }, + { 0x1000757c, 0x83 }, + { 0x1000757d, 0x47 }, + { 0x1000757e, 0x47 }, + { 0x1000757f, 0xd9 }, + { 0x10007580, 0x93 }, + { 0x10007581, 0x87 }, + { 0x10007582, 0x17 }, + { 0x10007583, 0x00 }, + { 0x10007584, 0x93 }, + { 0x10007585, 0xf7 }, + { 0x10007586, 0xf7 }, + { 0x10007587, 0x0f }, + { 0x10007588, 0x23 }, + { 0x10007589, 0x0a }, + { 0x1000758a, 0xf7 }, + { 0x1000758b, 0xd8 }, + { 0x1000758c, 0x67 }, + { 0x1000758d, 0x80 }, + { 0x1000758e, 0x00 }, + { 0x1000758f, 0x00 }, + { 0x10007590, 0xb7 }, + { 0x10007591, 0xd7 }, + { 0x10007592, 0x00 }, + { 0x10007593, 0x00 }, + { 0x10007594, 0x83 }, + { 0x10007595, 0xc7 }, + { 0x10007596, 0x07 }, + { 0x10007597, 0x47 }, + { 0x10007598, 0x93 }, + { 0x10007599, 0xf7 }, + { 0x1000759a, 0x07 }, + { 0x1000759b, 0x01 }, + { 0x1000759c, 0x63 }, + { 0x1000759d, 0x8a }, + { 0x1000759e, 0x07 }, + { 0x1000759f, 0x06 }, + { 0x100075a0, 0x63 }, + { 0x100075a1, 0x02 }, + { 0x100075a2, 0x05 }, + { 0x100075a3, 0x06 }, + { 0x100075a4, 0x37 }, + { 0x100075a5, 0xc7 }, + { 0x100075a6, 0x00 }, + { 0x100075a7, 0x00 }, + { 0x100075a8, 0x83 }, + { 0x100075a9, 0x27 }, + { 0x100075aa, 0xc7 }, + { 0x100075ab, 0x5f }, + { 0x100075ac, 0x23 }, + { 0x100075ad, 0xae }, + { 0x100075ae, 0xf1 }, + { 0x100075af, 0x40 }, + { 0x100075b0, 0xb7 }, + { 0x100075b1, 0x06 }, + { 0x100075b2, 0x00 }, + { 0x100075b3, 0x10 }, + { 0x100075b4, 0xb3 }, + { 0x100075b5, 0xf7 }, + { 0x100075b6, 0xd7 }, + { 0x100075b7, 0x00 }, + { 0x100075b8, 0x63 }, + { 0x100075b9, 0x8c }, + { 0x100075ba, 0x07 }, + { 0x100075bb, 0x04 }, + { 0x100075bc, 0x83 }, + { 0x100075bd, 0x47 }, + { 0x100075be, 0x07 }, + { 0x100075bf, 0x56 }, + { 0x100075c0, 0x93 }, + { 0x100075c1, 0xf7 }, + { 0x100075c2, 0x87 }, + { 0x100075c3, 0x01 }, + { 0x100075c4, 0x63 }, + { 0x100075c5, 0x86 }, + { 0x100075c6, 0x07 }, + { 0x100075c7, 0x04 }, + { 0x100075c8, 0x83 }, + { 0x100075c9, 0x47 }, + { 0x100075ca, 0x17 }, + { 0x100075cb, 0x08 }, + { 0x100075cc, 0x93 }, + { 0x100075cd, 0xf7 }, + { 0x100075ce, 0x47 }, + { 0x100075cf, 0x00 }, + { 0x100075d0, 0x63 }, + { 0x100075d1, 0x80 }, + { 0x100075d2, 0x07 }, + { 0x100075d3, 0x04 }, + { 0x100075d4, 0xb7 }, + { 0x100075d5, 0xc7 }, + { 0x100075d6, 0xc2 }, + { 0x100075d7, 0x3f }, + { 0x100075d8, 0x93 }, + { 0x100075d9, 0x87 }, + { 0x100075da, 0x07 }, + { 0x100075db, 0xfc }, + { 0x100075dc, 0x83 }, + { 0x100075dd, 0xa7 }, + { 0x100075de, 0x47 }, + { 0x100075df, 0x00 }, + { 0x100075e0, 0x93 }, + { 0x100075e1, 0xd7 }, + { 0x100075e2, 0x17 }, + { 0x100075e3, 0x00 }, + { 0x100075e4, 0x93 }, + { 0x100075e5, 0xf7 }, + { 0x100075e6, 0x17 }, + { 0x100075e7, 0x00 }, + { 0x100075e8, 0x63 }, + { 0x100075e9, 0x84 }, + { 0x100075ea, 0x07 }, + { 0x100075eb, 0x02 }, + { 0x100075ec, 0x23 }, + { 0x100075ed, 0x8a }, + { 0x100075ee, 0xf1 }, + { 0x100075ef, 0x40 }, + { 0x100075f0, 0xb7 }, + { 0x100075f1, 0x07 }, + { 0x100075f2, 0x00 }, + { 0x100075f3, 0xc0 }, + { 0x100075f4, 0x37 }, + { 0x100075f5, 0xf7 }, + { 0x100075f6, 0x00 }, + { 0x100075f7, 0x00 }, + { 0x100075f8, 0x93 }, + { 0x100075f9, 0x87 }, + { 0x100075fa, 0xf7 }, + { 0x100075fb, 0xff }, + { 0x100075fc, 0x23 }, + { 0x100075fd, 0x2c }, + { 0x100075fe, 0xf7 }, + { 0x100075ff, 0x06 }, + { 0x10007600, 0x67 }, + { 0x10007601, 0x80 }, + { 0x10007602, 0x00 }, + { 0x10007603, 0x00 }, + { 0x10007604, 0x23 }, + { 0x10007605, 0x8a }, + { 0x10007606, 0x01 }, + { 0x10007607, 0x40 }, + { 0x10007608, 0xb7 }, + { 0x10007609, 0xf7 }, + { 0x1000760a, 0x00 }, + { 0x1000760b, 0x00 }, + { 0x1000760c, 0x23 }, + { 0x1000760d, 0xac }, + { 0x1000760e, 0x07 }, + { 0x1000760f, 0x06 }, + { 0x10007610, 0x67 }, + { 0x10007611, 0x80 }, + { 0x10007612, 0x00 }, + { 0x10007613, 0x00 }, + { 0x10007614, 0x13 }, + { 0x10007615, 0x01 }, + { 0x10007616, 0x01 }, + { 0x10007617, 0xff }, + { 0x10007618, 0x23 }, + { 0x10007619, 0x26 }, + { 0x1000761a, 0x11 }, + { 0x1000761b, 0x00 }, + { 0x1000761c, 0x23 }, + { 0x1000761d, 0x24 }, + { 0x1000761e, 0x81 }, + { 0x1000761f, 0x00 }, + { 0x10007620, 0x37 }, + { 0x10007621, 0xc7 }, + { 0x10007622, 0x00 }, + { 0x10007623, 0x00 }, + { 0x10007624, 0x83 }, + { 0x10007625, 0x47 }, + { 0x10007626, 0x07 }, + { 0x10007627, 0x56 }, + { 0x10007628, 0x93 }, + { 0x10007629, 0xf7 }, + { 0x1000762a, 0x17 }, + { 0x1000762b, 0x00 }, + { 0x1000762c, 0x63 }, + { 0x1000762d, 0x98 }, + { 0x1000762e, 0x07 }, + { 0x1000762f, 0x00 }, + { 0x10007630, 0x83 }, + { 0x10007631, 0x47 }, + { 0x10007632, 0x07 }, + { 0x10007633, 0x56 }, + { 0x10007634, 0x93 }, + { 0x10007635, 0xf7 }, + { 0x10007636, 0x27 }, + { 0x10007637, 0x00 }, + { 0x10007638, 0x63 }, + { 0x10007639, 0x82 }, + { 0x1000763a, 0x07 }, + { 0x1000763b, 0x08 }, + { 0x1000763c, 0x37 }, + { 0x1000763d, 0xd4 }, + { 0x1000763e, 0x00 }, + { 0x1000763f, 0x00 }, + { 0x10007640, 0x83 }, + { 0x10007641, 0x47 }, + { 0x10007642, 0x14 }, + { 0x10007643, 0x47 }, + { 0x10007644, 0x93 }, + { 0x10007645, 0xf7 }, + { 0x10007646, 0x27 }, + { 0x10007647, 0x00 }, + { 0x10007648, 0x63 }, + { 0x10007649, 0x8a }, + { 0x1000764a, 0x07 }, + { 0x1000764b, 0x06 }, + { 0x1000764c, 0x93 }, + { 0x1000764d, 0x05 }, + { 0x1000764e, 0x10 }, + { 0x1000764f, 0x00 }, + { 0x10007650, 0x13 }, + { 0x10007651, 0x05 }, + { 0x10007652, 0x20 }, + { 0x10007653, 0x10 }, + { 0x10007654, 0xef }, + { 0x10007655, 0xa0 }, + { 0x10007656, 0x8f }, + { 0x10007657, 0x9a }, + { 0x10007658, 0x37 }, + { 0x10007659, 0x05 }, + { 0x1000765a, 0x01 }, + { 0x1000765b, 0x00 }, + { 0x1000765c, 0x93 }, + { 0x1000765d, 0x05 }, + { 0x1000765e, 0x00 }, + { 0x1000765f, 0x01 }, + { 0x10007660, 0x13 }, + { 0x10007661, 0x05 }, + { 0x10007662, 0xb5 }, + { 0x10007663, 0xa0 }, + { 0x10007664, 0xef }, + { 0x10007665, 0xa0 }, + { 0x10007666, 0x8f }, + { 0x10007667, 0x99 }, + { 0x10007668, 0x83 }, + { 0x10007669, 0x47 }, + { 0x1000766a, 0x24 }, + { 0x1000766b, 0xe0 }, + { 0x1000766c, 0x13 }, + { 0x1000766d, 0x05 }, + { 0x1000766e, 0x80 }, + { 0x1000766f, 0x3e }, + { 0x10007670, 0x93 }, + { 0x10007671, 0x05 }, + { 0x10007672, 0x00 }, + { 0x10007673, 0x00 }, + { 0x10007674, 0x93 }, + { 0x10007675, 0xe7 }, + { 0x10007676, 0x07 }, + { 0x10007677, 0xf8 }, + { 0x10007678, 0x93 }, + { 0x10007679, 0xf7 }, + { 0x1000767a, 0xf7 }, + { 0x1000767b, 0x0f }, + { 0x1000767c, 0x23 }, + { 0x1000767d, 0x01 }, + { 0x1000767e, 0xf4 }, + { 0x1000767f, 0xe0 }, + { 0x10007680, 0x83 }, + { 0x10007681, 0x47 }, + { 0x10007682, 0x24 }, + { 0x10007683, 0xe0 }, + { 0x10007684, 0x93 }, + { 0x10007685, 0xf7 }, + { 0x10007686, 0xf7 }, + { 0x10007687, 0x0f }, + { 0x10007688, 0x93 }, + { 0x10007689, 0xe7 }, + { 0x1000768a, 0x07 }, + { 0x1000768b, 0x04 }, + { 0x1000768c, 0x23 }, + { 0x1000768d, 0x01 }, + { 0x1000768e, 0xf4 }, + { 0x1000768f, 0xe0 }, + { 0x10007690, 0xef }, + { 0x10007691, 0xe0 }, + { 0x10007692, 0x8f }, + { 0x10007693, 0xb9 }, + { 0x10007694, 0x83 }, + { 0x10007695, 0x47 }, + { 0x10007696, 0x34 }, + { 0x10007697, 0xe0 }, + { 0x10007698, 0x93 }, + { 0x10007699, 0xf7 }, + { 0x1000769a, 0x07 }, + { 0x1000769b, 0x02 }, + { 0x1000769c, 0xe3 }, + { 0x1000769d, 0x9c }, + { 0x1000769e, 0x07 }, + { 0x1000769f, 0xfe }, + { 0x100076a0, 0x37 }, + { 0x100076a1, 0x05 }, + { 0x100076a2, 0x01 }, + { 0x100076a3, 0x00 }, + { 0x100076a4, 0x93 }, + { 0x100076a5, 0x05 }, + { 0x100076a6, 0x00 }, + { 0x100076a7, 0x00 }, + { 0x100076a8, 0x13 }, + { 0x100076a9, 0x05 }, + { 0x100076aa, 0xb5 }, + { 0x100076ab, 0xa0 }, + { 0x100076ac, 0xef }, + { 0x100076ad, 0xa0 }, + { 0x100076ae, 0x0f }, + { 0x100076af, 0x95 }, + { 0x100076b0, 0x83 }, + { 0x100076b1, 0x47 }, + { 0x100076b2, 0x14 }, + { 0x100076b3, 0x47 }, + { 0x100076b4, 0x93 }, + { 0x100076b5, 0xf7 }, + { 0x100076b6, 0xd7 }, + { 0x100076b7, 0x0f }, + { 0x100076b8, 0xa3 }, + { 0x100076b9, 0x08 }, + { 0x100076ba, 0xf4 }, + { 0x100076bb, 0x46 }, + { 0x100076bc, 0x03 }, + { 0x100076bd, 0xa7 }, + { 0x100076be, 0x01 }, + { 0x100076bf, 0x57 }, + { 0x100076c0, 0x93 }, + { 0x100076c1, 0x07 }, + { 0x100076c2, 0xa0 }, + { 0x100076c3, 0x05 }, + { 0x100076c4, 0x63 }, + { 0x100076c5, 0x14 }, + { 0x100076c6, 0xf7 }, + { 0x100076c7, 0x04 }, + { 0x100076c8, 0x37 }, + { 0x100076c9, 0x07 }, + { 0x100076ca, 0x00 }, + { 0x100076cb, 0x11 }, + { 0x100076cc, 0x83 }, + { 0x100076cd, 0x47 }, + { 0x100076ce, 0x07 }, + { 0x100076cf, 0x01 }, + { 0x100076d0, 0x13 }, + { 0x100076d1, 0x06 }, + { 0x100076d2, 0x30 }, + { 0x100076d3, 0x00 }, + { 0x100076d4, 0x93 }, + { 0x100076d5, 0xf7 }, + { 0x100076d6, 0xf7 }, + { 0x100076d7, 0x0f }, + { 0x100076d8, 0x63 }, + { 0x100076d9, 0x9a }, + { 0x100076da, 0xc7 }, + { 0x100076db, 0x02 }, + { 0x100076dc, 0x03 }, + { 0x100076dd, 0x47 }, + { 0x100076de, 0x87 }, + { 0x100076df, 0x01 }, + { 0x100076e0, 0x13 }, + { 0x100076e1, 0x77 }, + { 0x100076e2, 0xf7 }, + { 0x100076e3, 0x0f }, + { 0x100076e4, 0x63 }, + { 0x100076e5, 0x14 }, + { 0x100076e6, 0xf7 }, + { 0x100076e7, 0x02 }, + { 0x100076e8, 0x37 }, + { 0x100076e9, 0xd7 }, + { 0x100076ea, 0x00 }, + { 0x100076eb, 0x00 }, + { 0x100076ec, 0x83 }, + { 0x100076ed, 0x47 }, + { 0x100076ee, 0x37 }, + { 0x100076ef, 0x54 }, + { 0x100076f0, 0x93 }, + { 0x100076f1, 0xf7 }, + { 0x100076f2, 0xf7 }, + { 0x100076f3, 0x0f }, + { 0x100076f4, 0x93 }, + { 0x100076f5, 0xe7 }, + { 0x100076f6, 0x07 }, + { 0x100076f7, 0x02 }, + { 0x100076f8, 0xa3 }, + { 0x100076f9, 0x01 }, + { 0x100076fa, 0xf7 }, + { 0x100076fb, 0x54 }, + { 0x100076fc, 0x83 }, + { 0x100076fd, 0x47 }, + { 0x100076fe, 0x37 }, + { 0x100076ff, 0x54 }, + { 0x10007700, 0x93 }, + { 0x10007701, 0xf7 }, + { 0x10007702, 0xf7 }, + { 0x10007703, 0x0d }, + { 0x10007704, 0xa3 }, + { 0x10007705, 0x01 }, + { 0x10007706, 0xf7 }, + { 0x10007707, 0x54 }, + { 0x10007708, 0x23 }, + { 0x10007709, 0xa8 }, + { 0x1000770a, 0x01 }, + { 0x1000770b, 0x56 }, + { 0x1000770c, 0xb7 }, + { 0x1000770d, 0xd7 }, + { 0x1000770e, 0x00 }, + { 0x1000770f, 0x10 }, + { 0x10007710, 0x03 }, + { 0x10007711, 0xc7 }, + { 0x10007712, 0x07 }, + { 0x10007713, 0xd9 }, + { 0x10007714, 0x93 }, + { 0x10007715, 0x06 }, + { 0x10007716, 0x10 }, + { 0x10007717, 0x00 }, + { 0x10007718, 0x13 }, + { 0x10007719, 0x77 }, + { 0x1000771a, 0xf7 }, + { 0x1000771b, 0x0f }, + { 0x1000771c, 0x63 }, + { 0x1000771d, 0x1a }, + { 0x1000771e, 0xd7 }, + { 0x1000771f, 0x04 }, + { 0x10007720, 0x03 }, + { 0x10007721, 0xc7 }, + { 0x10007722, 0x27 }, + { 0x10007723, 0xd9 }, + { 0x10007724, 0x13 }, + { 0x10007725, 0x07 }, + { 0x10007726, 0x17 }, + { 0x10007727, 0x00 }, + { 0x10007728, 0x13 }, + { 0x10007729, 0x77 }, + { 0x1000772a, 0xf7 }, + { 0x1000772b, 0x0f }, + { 0x1000772c, 0x23 }, + { 0x1000772d, 0x89 }, + { 0x1000772e, 0xe7 }, + { 0x1000772f, 0xd8 }, + { 0x10007730, 0x83 }, + { 0x10007731, 0xc6 }, + { 0x10007732, 0x27 }, + { 0x10007733, 0xd9 }, + { 0x10007734, 0x03 }, + { 0x10007735, 0xc7 }, + { 0x10007736, 0x17 }, + { 0x10007737, 0xd9 }, + { 0x10007738, 0x93 }, + { 0x10007739, 0xf6 }, + { 0x1000773a, 0xf6 }, + { 0x1000773b, 0x0f }, + { 0x1000773c, 0x13 }, + { 0x1000773d, 0x77 }, + { 0x1000773e, 0xf7 }, + { 0x1000773f, 0x0f }, + { 0x10007740, 0x63 }, + { 0x10007741, 0xe8 }, + { 0x10007742, 0xe6 }, + { 0x10007743, 0x02 }, + { 0x10007744, 0xb7 }, + { 0x10007745, 0xd6 }, + { 0x10007746, 0x00 }, + { 0x10007747, 0x00 }, + { 0x10007748, 0x03 }, + { 0x10007749, 0xc7 }, + { 0x1000774a, 0xa6 }, + { 0x1000774b, 0xe1 }, + { 0x1000774c, 0x13 }, + { 0x1000774d, 0x67 }, + { 0x1000774e, 0x07 }, + { 0x1000774f, 0xf8 }, + { 0x10007750, 0x13 }, + { 0x10007751, 0x77 }, + { 0x10007752, 0xf7 }, + { 0x10007753, 0x0f }, + { 0x10007754, 0x23 }, + { 0x10007755, 0x8d }, + { 0x10007756, 0xe6 }, + { 0x10007757, 0xe0 }, + { 0x10007758, 0x03 }, + { 0x10007759, 0xc7 }, + { 0x1000775a, 0x37 }, + { 0x1000775b, 0xd9 }, + { 0x1000775c, 0x13 }, + { 0x1000775d, 0x07 }, + { 0x1000775e, 0x17 }, + { 0x1000775f, 0x00 }, + { 0x10007760, 0x13 }, + { 0x10007761, 0x77 }, + { 0x10007762, 0xf7 }, + { 0x10007763, 0x0f }, + { 0x10007764, 0xa3 }, + { 0x10007765, 0x89 }, + { 0x10007766, 0xe7 }, + { 0x10007767, 0xd8 }, + { 0x10007768, 0x13 }, + { 0x10007769, 0x07 }, + { 0x1000776a, 0x20 }, + { 0x1000776b, 0x00 }, + { 0x1000776c, 0x23 }, + { 0x1000776d, 0x88 }, + { 0x1000776e, 0xe7 }, + { 0x1000776f, 0xd8 }, + { 0x10007770, 0x83 }, + { 0x10007771, 0x20 }, + { 0x10007772, 0xc1 }, + { 0x10007773, 0x00 }, + { 0x10007774, 0x03 }, + { 0x10007775, 0x24 }, + { 0x10007776, 0x81 }, + { 0x10007777, 0x00 }, + { 0x10007778, 0x13 }, + { 0x10007779, 0x01 }, + { 0x1000777a, 0x01 }, + { 0x1000777b, 0x01 }, + { 0x1000777c, 0x67 }, + { 0x1000777d, 0x80 }, + { 0x1000777e, 0x00 }, + { 0x1000777f, 0x00 }, + { 0x10007780, 0x03 }, + { 0x10007781, 0xc7 }, + { 0x10007782, 0xa1 }, + { 0x10007783, 0x40 }, + { 0x10007784, 0x93 }, + { 0x10007785, 0x06 }, + { 0x10007786, 0x10 }, + { 0x10007787, 0x00 }, + { 0x10007788, 0x63 }, + { 0x10007789, 0x16 }, + { 0x1000778a, 0xd7 }, + { 0x1000778b, 0x00 }, + { 0x1000778c, 0xb7 }, + { 0x1000778d, 0xd6 }, + { 0x1000778e, 0x00 }, + { 0x1000778f, 0x10 }, + { 0x10007790, 0xa3 }, + { 0x10007791, 0x8a }, + { 0x10007792, 0xe6 }, + { 0x10007793, 0xd8 }, + { 0x10007794, 0x83 }, + { 0x10007795, 0xc7 }, + { 0x10007796, 0xa1 }, + { 0x10007797, 0x40 }, + { 0x10007798, 0x63 }, + { 0x10007799, 0x9c }, + { 0x1000779a, 0x07 }, + { 0x1000779b, 0x06 }, + { 0x1000779c, 0x13 }, + { 0x1000779d, 0x01 }, + { 0x1000779e, 0x01 }, + { 0x1000779f, 0xff }, + { 0x100077a0, 0x23 }, + { 0x100077a1, 0x22 }, + { 0x100077a2, 0x91 }, + { 0x100077a3, 0x00 }, + { 0x100077a4, 0x23 }, + { 0x100077a5, 0x26 }, + { 0x100077a6, 0x11 }, + { 0x100077a7, 0x00 }, + { 0x100077a8, 0x23 }, + { 0x100077a9, 0x24 }, + { 0x100077aa, 0x81 }, + { 0x100077ab, 0x00 }, + { 0x100077ac, 0xb7 }, + { 0x100077ad, 0xc4 }, + { 0x100077ae, 0x00 }, + { 0x100077af, 0x00 }, + { 0x100077b0, 0x83 }, + { 0x100077b1, 0xc7 }, + { 0x100077b2, 0x04 }, + { 0x100077b3, 0x56 }, + { 0x100077b4, 0x13 }, + { 0x100077b5, 0x07 }, + { 0x100077b6, 0x80 }, + { 0x100077b7, 0x01 }, + { 0x100077b8, 0x93 }, + { 0x100077b9, 0xf7 }, + { 0x100077ba, 0xf7 }, + { 0x100077bb, 0x0f }, + { 0x100077bc, 0x63 }, + { 0x100077bd, 0x70 }, + { 0x100077be, 0xf7 }, + { 0x100077bf, 0x04 }, + { 0x100077c0, 0x37 }, + { 0x100077c1, 0xd4 }, + { 0x100077c2, 0x00 }, + { 0x100077c3, 0x10 }, + { 0x100077c4, 0x83 }, + { 0x100077c5, 0x47 }, + { 0x100077c6, 0x54 }, + { 0x100077c7, 0xd9 }, + { 0x100077c8, 0x93 }, + { 0x100077c9, 0xf7 }, + { 0x100077ca, 0xf7 }, + { 0x100077cb, 0x0f }, + { 0x100077cc, 0x63 }, + { 0x100077cd, 0x88 }, + { 0x100077ce, 0x07 }, + { 0x100077cf, 0x02 }, + { 0x100077d0, 0x93 }, + { 0x100077d1, 0x07 }, + { 0x100077d2, 0x10 }, + { 0x100077d3, 0x00 }, + { 0x100077d4, 0x23 }, + { 0x100077d5, 0x82 }, + { 0x100077d6, 0xf4 }, + { 0x100077d7, 0x58 }, + { 0x100077d8, 0x03 }, + { 0x100077d9, 0x45 }, + { 0x100077da, 0x64 }, + { 0x100077db, 0xd9 }, + { 0x100077dc, 0xb7 }, + { 0x100077dd, 0x15 }, + { 0x100077de, 0x00 }, + { 0x100077df, 0x00 }, + { 0x100077e0, 0x93 }, + { 0x100077e1, 0x85 }, + { 0x100077e2, 0x85 }, + { 0x100077e3, 0x38 }, + { 0x100077e4, 0x13 }, + { 0x100077e5, 0x75 }, + { 0x100077e6, 0xf5 }, + { 0x100077e7, 0x0f }, + { 0x100077e8, 0xef }, + { 0x100077e9, 0xe0 }, + { 0x100077ea, 0x9f }, + { 0x100077eb, 0xd0 }, + { 0x100077ec, 0x93 }, + { 0x100077ed, 0x55 }, + { 0x100077ee, 0xf5 }, + { 0x100077ef, 0x41 }, + { 0x100077f0, 0xef }, + { 0x100077f1, 0xe0 }, + { 0x100077f2, 0x8f }, + { 0x100077f3, 0xa3 }, + { 0x100077f4, 0x23 }, + { 0x100077f5, 0x82 }, + { 0x100077f6, 0x04 }, + { 0x100077f7, 0x58 }, + { 0x100077f8, 0xa3 }, + { 0x100077f9, 0x0a }, + { 0x100077fa, 0x04 }, + { 0x100077fb, 0xd8 }, + { 0x100077fc, 0x83 }, + { 0x100077fd, 0x20 }, + { 0x100077fe, 0xc1 }, + { 0x100077ff, 0x00 }, + { 0x10007800, 0x03 }, + { 0x10007801, 0x24 }, + { 0x10007802, 0x81 }, + { 0x10007803, 0x00 }, + { 0x10007804, 0x83 }, + { 0x10007805, 0x24 }, + { 0x10007806, 0x41 }, + { 0x10007807, 0x00 }, + { 0x10007808, 0x13 }, + { 0x10007809, 0x01 }, + { 0x1000780a, 0x01 }, + { 0x1000780b, 0x01 }, + { 0x1000780c, 0x67 }, + { 0x1000780d, 0x80 }, + { 0x1000780e, 0x00 }, + { 0x1000780f, 0x00 }, + { 0x10007810, 0x67 }, + { 0x10007811, 0x80 }, + { 0x10007812, 0x00 }, + { 0x10007813, 0x00 }, + { 0x10007814, 0x13 }, + { 0x10007815, 0x01 }, + { 0x10007816, 0x01 }, + { 0x10007817, 0xff }, + { 0x10007818, 0x23 }, + { 0x10007819, 0x26 }, + { 0x1000781a, 0x11 }, + { 0x1000781b, 0x00 }, + { 0x1000781c, 0xef }, + { 0x1000781d, 0xd0 }, + { 0x1000781e, 0x8f }, + { 0x1000781f, 0x86 }, + { 0x10007820, 0x83 }, + { 0x10007821, 0xc7 }, + { 0x10007822, 0x11 }, + { 0x10007823, 0x42 }, + { 0x10007824, 0x63 }, + { 0x10007825, 0x86 }, + { 0x10007826, 0x07 }, + { 0x10007827, 0x00 }, + { 0x10007828, 0x03 }, + { 0x10007829, 0xc7 }, + { 0x1000782a, 0x01 }, + { 0x1000782b, 0x42 }, + { 0x1000782c, 0x63 }, + { 0x1000782d, 0x10 }, + { 0x1000782e, 0x07 }, + { 0x1000782f, 0x02 }, + { 0x10007830, 0x83 }, + { 0x10007831, 0xc6 }, + { 0x10007832, 0x21 }, + { 0x10007833, 0x41 }, + { 0x10007834, 0x13 }, + { 0x10007835, 0x07 }, + { 0x10007836, 0xf0 }, + { 0x10007837, 0x01 }, + { 0x10007838, 0x13 }, + { 0x10007839, 0x05 }, + { 0x1000783a, 0xf0 }, + { 0x1000783b, 0x01 }, + { 0x1000783c, 0x63 }, + { 0x1000783d, 0x98 }, + { 0x1000783e, 0xe6 }, + { 0x1000783f, 0x02 }, + { 0x10007840, 0x63 }, + { 0x10007841, 0x8a }, + { 0x10007842, 0x07 }, + { 0x10007843, 0x02 }, + { 0x10007844, 0x83 }, + { 0x10007845, 0xc7 }, + { 0x10007846, 0x01 }, + { 0x10007847, 0x42 }, + { 0x10007848, 0x63 }, + { 0x10007849, 0x86 }, + { 0x1000784a, 0x07 }, + { 0x1000784b, 0x02 }, + { 0x1000784c, 0x83 }, + { 0x1000784d, 0xc7 }, + { 0x1000784e, 0x31 }, + { 0x1000784f, 0x42 }, + { 0x10007850, 0x63 }, + { 0x10007851, 0x86 }, + { 0x10007852, 0x07 }, + { 0x10007853, 0x00 }, + { 0x10007854, 0x83 }, + { 0x10007855, 0xc7 }, + { 0x10007856, 0x21 }, + { 0x10007857, 0x42 }, + { 0x10007858, 0x63 }, + { 0x10007859, 0x9e }, + { 0x1000785a, 0x07 }, + { 0x1000785b, 0x00 }, + { 0x1000785c, 0x03 }, + { 0x1000785d, 0xc7 }, + { 0x1000785e, 0x21 }, + { 0x1000785f, 0x41 }, + { 0x10007860, 0x93 }, + { 0x10007861, 0x07 }, + { 0x10007862, 0xb0 }, + { 0x10007863, 0x01 }, + { 0x10007864, 0x63 }, + { 0x10007865, 0x08 }, + { 0x10007866, 0xf7 }, + { 0x10007867, 0x00 }, + { 0x10007868, 0x13 }, + { 0x10007869, 0x05 }, + { 0x1000786a, 0xb0 }, + { 0x1000786b, 0x01 }, + { 0x1000786c, 0xef }, + { 0x1000786d, 0xd0 }, + { 0x1000786e, 0x0f }, + { 0x1000786f, 0xcf }, + { 0x10007870, 0xef }, + { 0x10007871, 0xd0 }, + { 0x10007872, 0x8f }, + { 0x10007873, 0xa4 }, + { 0x10007874, 0x93 }, + { 0x10007875, 0x06 }, + { 0x10007876, 0x10 }, + { 0x10007877, 0x00 }, + { 0x10007878, 0xa3 }, + { 0x10007879, 0x89 }, + { 0x1000787a, 0xd1 }, + { 0x1000787b, 0x40 }, + { 0x1000787c, 0x37 }, + { 0x1000787d, 0xd7 }, + { 0x1000787e, 0x00 }, + { 0x1000787f, 0x10 }, + { 0x10007880, 0x83 }, + { 0x10007881, 0x47 }, + { 0x10007882, 0x07 }, + { 0x10007883, 0xd9 }, + { 0x10007884, 0x93 }, + { 0x10007885, 0xf7 }, + { 0x10007886, 0xf7 }, + { 0x10007887, 0x0f }, + { 0x10007888, 0x63 }, + { 0x10007889, 0x90 }, + { 0x1000788a, 0x07 }, + { 0x1000788b, 0x02 }, + { 0x1000788c, 0x37 }, + { 0x1000788d, 0xc6 }, + { 0x1000788e, 0x00 }, + { 0x1000788f, 0x00 }, + { 0x10007890, 0x83 }, + { 0x10007891, 0x47 }, + { 0x10007892, 0x26 }, + { 0x10007893, 0x04 }, + { 0x10007894, 0x93 }, + { 0x10007895, 0xe7 }, + { 0x10007896, 0x07 }, + { 0x10007897, 0xf8 }, + { 0x10007898, 0x93 }, + { 0x10007899, 0xf7 }, + { 0x1000789a, 0xf7 }, + { 0x1000789b, 0x0f }, + { 0x1000789c, 0x23 }, + { 0x1000789d, 0x01 }, + { 0x1000789e, 0xf6 }, + { 0x1000789f, 0x04 }, + { 0x100078a0, 0x23 }, + { 0x100078a1, 0x08 }, + { 0x100078a2, 0xd7 }, + { 0x100078a3, 0xd8 }, + { 0x100078a4, 0x23 }, + { 0x100078a5, 0x09 }, + { 0x100078a6, 0x07 }, + { 0x100078a7, 0xd8 }, + { 0x100078a8, 0x83 }, + { 0x100078a9, 0x20 }, + { 0x100078aa, 0xc1 }, + { 0x100078ab, 0x00 }, + { 0x100078ac, 0x13 }, + { 0x100078ad, 0x01 }, + { 0x100078ae, 0x01 }, + { 0x100078af, 0x01 }, + { 0x100078b0, 0x67 }, + { 0x100078b1, 0x80 }, + { 0x100078b2, 0x00 }, + { 0x100078b3, 0x00 }, + { 0x3fc2bfc7, 0x00 }, + { 0x3fc2bfc6, 0x00 }, + { 0x3fc2bfc5, 0x00 }, + { 0x3fc2bfc4, 0x01 }, + { 0x0000d486, 0x43 }, + { 0x1000db00, 0x02 }, + { 0x1000db01, 0x00 }, + { 0x1000db02, 0x11 }, + { 0x1000db03, 0x00 }, + { 0x1000db04, 0x00 }, + { 0x1000db05, 0x82 }, + { 0x1000db06, 0x04 }, + { 0x1000db07, 0xf1 }, + { 0x1000db08, 0x00 }, + { 0x1000db09, 0x00 }, + { 0x1000db0a, 0x40 }, + { 0x0000d540, 0x01 }, +}; + +static const struct reg_default rt1320_reg_defaults[] = { + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, +}; + +static const struct reg_default rt1320_mbq_defaults[] = { + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, +}; + +static bool rt1320_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0xc000 ... 0xc086: + case 0xc400 ... 0xc409: + case 0xc480 ... 0xc48f: + case 0xc4c0 ... 0xc4c4: + case 0xc4e0 ... 0xc4e7: + case 0xc500: + case 0xc560 ... 0xc56b: + case 0xc570: + case 0xc580 ... 0xc59a: + case 0xc5b0 ... 0xc60f: + case 0xc640 ... 0xc64f: + case 0xc670: + case 0xc680 ... 0xc683: + case 0xc700 ... 0xc76f: + case 0xc800 ... 0xc801: + case 0xc820: + case 0xc900 ... 0xc901: + case 0xc920 ... 0xc921: + case 0xca00 ... 0xca07: + case 0xca20 ... 0xca27: + case 0xca40 ... 0xca4b: + case 0xca60 ... 0xca68: + case 0xca80 ... 0xca88: + case 0xcb00 ... 0xcb0c: + case 0xcc00 ... 0xcc12: + case 0xcc80 ... 0xcc81: + case 0xcd00: + case 0xcd80 ... 0xcd82: + case 0xce00 ... 0xce4d: + case 0xcf00 ... 0xcf25: + case 0xd000 ... 0xd0ff: + case 0xd100 ... 0xd1ff: + case 0xd200 ... 0xd2ff: + case 0xd300 ... 0xd3ff: + case 0xd400 ... 0xd403: + case 0xd410 ... 0xd417: + case 0xd470 ... 0xd497: + case 0xd4dc ... 0xd50f: + case 0xd520 ... 0xd543: + case 0xd560 ... 0xd5ef: + case 0xd600 ... 0xd663: + case 0xda00 ... 0xda6e: + case 0xda80 ... 0xda9e: + case 0xdb00 ... 0xdb7f: + case 0xdc00: + case 0xdc20 ... 0xdc21: + case 0xdd00 ... 0xdd17: + case 0xde00 ... 0xde09: + case 0xdf00 ... 0xdf1b: + case 0xe000 ... 0xe847: + case 0xf717 ... 0xf719: + case 0xf720 ... 0xf723: + case 0x1000f008: + case 0x3fe2e000 ... 0x3fe2e003: + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0): + return true; + default: + return false; + } +} + +static bool rt1320_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0xc402 ... 0xc406: + case 0xc48c ... 0xc48f: + case 0xc560: + case 0xc5b5 ... 0xc5b7: + case 0xc5fc ... 0xc5ff: + case 0xc820: + case 0xc900: + case 0xc920: + case 0xca42: + case 0xca62: + case 0xca82: + case 0xcd00: + case 0xce03: + case 0xce10: + case 0xce14 ... 0xce17: + case 0xce44 ... 0xce49: + case 0xce4c ... 0xce4d: + case 0xcf0c: + case 0xcf10 ... 0xcf25: + case 0xd486 ... 0xd487: + case 0xd4e5 ... 0xd4e6: + case 0xd4e8 ... 0xd4ff: + case 0xd530: + case 0xd540: + case 0xd543: + case 0xdb58 ... 0xdb5f: + case 0xdb60 ... 0xdb63: + case 0xdb68 ... 0xdb69: + case 0xdb6d: + case 0xdb70 ... 0xdb71: + case 0xdb76: + case 0xdb7a: + case 0xdb7c ... 0xdb7f: + case 0xdd0c ... 0xdd13: + case 0xde02: + case 0xdf14 ... 0xdf1b: + case 0xe83c ... 0xe847: + case 0xf717 ... 0xf719: + case 0xf720 ... 0xf723: + case 0x10000000 ... 0x10007fff: + case 0x1000c000 ... 0x1000dfff: + case 0x1000f008: + case 0x3fc2bfc4 ... 0x3fc2bfc7: + case 0x3fe2e000 ... 0x3fe2e003: + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0): + return true; + default: + return false; + } +} + +static bool rt1320_mbq_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02): + return true; + default: + return false; + } +} + +static const struct regmap_config rt1320_sdw_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt1320_readable_register, + .volatile_reg = rt1320_volatile_register, + .max_register = 0x41081488, + .reg_defaults = rt1320_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt1320_reg_defaults), + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static const struct regmap_config rt1320_mbq_regmap = { + .name = "sdw-mbq", + .reg_bits = 32, + .val_bits = 16, + .readable_reg = rt1320_mbq_readable_register, + .max_register = 0x41000192, + .reg_defaults = rt1320_mbq_defaults, + .num_reg_defaults = ARRAY_SIZE(rt1320_mbq_defaults), + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt1320_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; + + /* + * Due to support the multi-lane, we call 'sdw_slave_read_prop' to get the lane mapping + */ + sdw_slave_read_prop(slave); + + 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; + prop->lane_control_support = true; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = BIT(4); + prop->sink_ports = BIT(1); + + 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 rt1320_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev); + unsigned int amp_func_status, val, tmp; + + if (rt1320->hw_init) + return 0; + + regcache_cache_only(rt1320->regmap, false); + regcache_cache_only(rt1320->mbq_regmap, false); + if (rt1320->first_hw_init) { + regcache_cache_bypass(rt1320->regmap, true); + regcache_cache_bypass(rt1320->mbq_regmap, true); + } else { + /* + * PM runtime status is marked as 'active' only when a Slave reports as Attached + */ + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + if (rt1320->version_id < 0) { + regmap_read(rt1320->regmap, RT1320_DEV_VERSION_ID_1, &val); + rt1320->version_id = val; + } + + regmap_read(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0), &_func_status); + dev_dbg(dev, "%s amp func_status=0x%x\n", __func__, amp_func_status); + + /* initialization write */ + if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt1320->first_hw_init)) { + regmap_multi_reg_write(rt1320->regmap, rt1320_blind_write, ARRAY_SIZE(rt1320_blind_write)); + regmap_multi_reg_write(rt1320->regmap, rt1320_patch_code_write, + ARRAY_SIZE(rt1320_patch_code_write)); + + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0), + FUNCTION_NEEDS_INITIALIZATION); + } + if (!rt1320->first_hw_init) { + regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0); + regmap_read(rt1320->regmap, RT1320_HIFI_VER_0, &val); + regmap_read(rt1320->regmap, RT1320_HIFI_VER_1, &tmp); + val = (tmp << 8) | val; + regmap_read(rt1320->regmap, RT1320_HIFI_VER_2, &tmp); + val = (tmp << 16) | val; + regmap_read(rt1320->regmap, RT1320_HIFI_VER_3, &tmp); + val = (tmp << 24) | val; + dev_dbg(dev, "%s ROM version=0x%x\n", __func__, val); + /* + * We call the version b which has the new DSP ROM code against version a. + * Therefore, we read the DSP address to check the ID. + */ + if (val == RT1320_VER_B_ID) + rt1320->version_id = RT1320_VB; + regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 3); + } + dev_dbg(dev, "%s version_id=%d\n", __func__, rt1320->version_id); + + if (rt1320->first_hw_init) { + regcache_cache_bypass(rt1320->regmap, false); + regcache_cache_bypass(rt1320->mbq_regmap, false); + regcache_mark_dirty(rt1320->regmap); + regcache_mark_dirty(rt1320->mbq_regmap); + } + + /* Mark Slave initialization complete */ + rt1320->first_hw_init = true; + rt1320->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + return 0; +} + +static int rt1320_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_UNATTACHED) + rt1320->hw_init = false; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt1320->hw_init || status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt1320_io_init(&slave->dev, slave); +} + +static int rt1320_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 rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + default: + break; + } + + return 0; +} + +static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + unsigned int read_l, read_r, gain_l_val, gain_r_val; + unsigned int lvalue, rvalue; + const unsigned int interval_offset = 0xc0; + + regmap_read(rt1320->mbq_regmap, mc->reg, &lvalue); + regmap_read(rt1320->mbq_regmap, mc->rreg, &rvalue); + + /* L Channel */ + gain_l_val = ucontrol->value.integer.value[0]; + if (gain_l_val > mc->max) + gain_l_val = mc->max; + gain_l_val = 0 - ((mc->max - gain_l_val) * interval_offset); + gain_l_val &= 0xffff; + + /* R Channel */ + gain_r_val = ucontrol->value.integer.value[1]; + if (gain_r_val > mc->max) + gain_r_val = mc->max; + gain_r_val = 0 - ((mc->max - gain_r_val) * interval_offset); + gain_r_val &= 0xffff; + + if (lvalue == gain_l_val && rvalue == gain_r_val) + return 0; + + /* Lch*/ + regmap_write(rt1320->mbq_regmap, mc->reg, gain_l_val); + /* Rch */ + regmap_write(rt1320->mbq_regmap, mc->rreg, gain_r_val); + + regmap_read(rt1320->mbq_regmap, mc->reg, &read_l); + regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r); + if (read_r == gain_r_val && read_l == gain_l_val) + return 1; + + return -EIO; +} + +static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0; + const unsigned int interval_offset = 0xc0; + + regmap_read(rt1320->mbq_regmap, mc->reg, &read_l); + regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r); + + ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset); + + if (read_l != read_r) + ctl_r = mc->max - (((0 - read_r) & 0xffff) / interval_offset); + else + ctl_r = ctl_l; + + ucontrol->value.integer.value[0] = ctl_l; + ucontrol->value.integer.value[1] = ctl_r; + return 0; +} + +static const char * const rt1320_rx_data_ch_select[] = { + "L,R", + "R,L", + "L,L", + "R,R", + "L,L+R", + "R,L+R", + "L+R,L", + "L+R,R", + "L+R,L+R", +}; + +static SOC_ENUM_SINGLE_DECL(rt1320_rx_data_ch_enum, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0, + rt1320_rx_data_ch_select); + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); + +static const struct snd_kcontrol_new rt1320_snd_controls[] = { + SOC_DOUBLE_R_EXT_TLV("FU21 Playback Volume", + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01), + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), + 0, 0x57, 0, rt1320_set_gain_get, rt1320_set_gain_put, out_vol_tlv), + SOC_ENUM("RX Channel Select", rt1320_rx_data_ch_enum), +}; + +static const struct snd_kcontrol_new rt1320_spk_l_dac = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01), + 0, 1, 1); +static const struct snd_kcontrol_new rt1320_spk_r_dac = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02), + 0, 1, 1); + +static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Digital Interface */ + SND_SOC_DAPM_PGA("FU21", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0, + rt1320_pde23_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + /* Output */ + SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt1320_spk_l_dac), + SND_SOC_DAPM_SWITCH("OT23 R", SND_SOC_NOPM, 0, 0, &rt1320_spk_r_dac), + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), + + /* Input */ + SND_SOC_DAPM_PGA("AEC Data", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SIGGEN("AEC Gen"), +}; + +static const struct snd_soc_dapm_route rt1320_dapm_routes[] = { + { "FU21", NULL, "DP1RX" }, + { "FU21", NULL, "PDE 23" }, + { "OT23 L", "Switch", "FU21" }, + { "OT23 R", "Switch", "FU21" }, + { "SPOL", NULL, "OT23 L" }, + { "SPOR", NULL, "OT23 R" }, + + { "AEC Data", NULL, "AEC Gen" }, + { "DP4TX", NULL, "AEC Data" }, +}; + +static int rt1320_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 rt1320_sdw_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_dai_set_dma_data(dai, substream, NULL); +} + +static int rt1320_sdw_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 rt1320_sdw_priv *rt1320 = + snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + struct sdw_stream_runtime *sdw_stream; + int retval; + 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 (!rt1320->sdw_slave) + return -EINVAL; + + /* SoundWire specific configuration */ + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (dai->id == RT1320_AIF1) + port_config.num = 1; + else + return -EINVAL; + } else { + if (dai->id == RT1320_AIF1) + port_config.num = 4; + else + return -EINVAL; + } + + retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, + &port_config, 1, sdw_stream); + if (retval) { + dev_err(dai->dev, "%s: Unable to configure port\n", __func__); + return retval; + } + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 16000: + sampling_rate = RT1320_SDCA_RATE_16000HZ; + break; + case 32000: + sampling_rate = RT1320_SDCA_RATE_32000HZ; + break; + case 44100: + sampling_rate = RT1320_SDCA_RATE_44100HZ; + break; + case 48000: + sampling_rate = RT1320_SDCA_RATE_48000HZ; + break; + case 96000: + sampling_rate = RT1320_SDCA_RATE_96000HZ; + break; + case 192000: + sampling_rate = RT1320_SDCA_RATE_192000HZ; + break; + default: + dev_err(component->dev, "%s: Rate %d is not supported\n", + __func__, params_rate(params)); + return -EINVAL; + } + + /* set sampling frequency */ + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + + return 0; +} + +static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1320_sdw_priv *rt1320 = + snd_soc_component_get_drvdata(component); + struct sdw_stream_runtime *sdw_stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt1320->sdw_slave) + return -EINVAL; + + sdw_stream_remove_slave(rt1320->sdw_slave, sdw_stream); + return 0; +} + +/* + * slave_ops: callbacks for get_clock_stop_mode, clock_stop and + * port_prep are not defined for now + */ +static const struct sdw_slave_ops rt1320_slave_ops = { + .read_prop = rt1320_read_prop, + .update_status = rt1320_update_status, +}; + +static int rt1320_sdw_component_probe(struct snd_soc_component *component) +{ + int ret; + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + + rt1320->component = component; + + if (!rt1320->first_hw_init) + return 0; + + ret = pm_runtime_resume(component->dev); + dev_dbg(&rt1320->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + +static const struct snd_soc_component_driver soc_component_sdw_rt1320 = { + .probe = rt1320_sdw_component_probe, + .controls = rt1320_snd_controls, + .num_controls = ARRAY_SIZE(rt1320_snd_controls), + .dapm_widgets = rt1320_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt1320_dapm_widgets), + .dapm_routes = rt1320_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt1320_dapm_routes), + .endianness = 1, +}; + +static const struct snd_soc_dai_ops rt1320_aif_dai_ops = { + .hw_params = rt1320_sdw_hw_params, + .hw_free = rt1320_sdw_pcm_hw_free, + .set_stream = rt1320_set_sdw_stream, + .shutdown = rt1320_sdw_shutdown, +}; + +#define RT1320_STEREO_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define RT1320_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver rt1320_sdw_dai[] = { + { + .name = "rt1320-aif1", + .id = RT1320_AIF1, + .playback = { + .stream_name = "DP1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT1320_STEREO_RATES, + .formats = RT1320_FORMATS, + }, + .capture = { + .stream_name = "DP4 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT1320_STEREO_RATES, + .formats = RT1320_FORMATS, + }, + .ops = &rt1320_aif_dai_ops, + }, +}; + +static int rt1320_sdw_init(struct device *dev, struct regmap *regmap, + struct regmap *mbq_regmap, struct sdw_slave *slave) +{ + struct rt1320_sdw_priv *rt1320; + int ret; + + rt1320 = devm_kzalloc(dev, sizeof(*rt1320), GFP_KERNEL); + if (!rt1320) + return -ENOMEM; + + dev_set_drvdata(dev, rt1320); + rt1320->sdw_slave = slave; + rt1320->mbq_regmap = mbq_regmap; + rt1320->regmap = regmap; + + regcache_cache_only(rt1320->regmap, true); + regcache_cache_only(rt1320->mbq_regmap, true); + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt1320->hw_init = false; + rt1320->first_hw_init = false; + rt1320->version_id = -1; + + ret = devm_snd_soc_register_component(dev, + &soc_component_sdw_rt1320, + rt1320_sdw_dai, + ARRAY_SIZE(rt1320_sdw_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; +} + +static int rt1320_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap, *mbq_regmap; + + /* Regmap Initialization */ + mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt1320_mbq_regmap); + if (IS_ERR(mbq_regmap)) + return PTR_ERR(mbq_regmap); + + regmap = devm_regmap_init_sdw(slave, &rt1320_sdw_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return rt1320_sdw_init(&slave->dev, regmap, mbq_regmap, slave); +} + +static int rt1320_sdw_remove(struct sdw_slave *slave) +{ + pm_runtime_disable(&slave->dev); + + return 0; +} + +/* + * Version A/B will use the class id 0 + * The newer version than A/B will use the class id 1, so add it in advance + */ +static const struct sdw_device_id rt1320_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x1320, 0x3, 0x0, 0), + SDW_SLAVE_ENTRY_EXT(0x025d, 0x1320, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt1320_id); + +static int __maybe_unused rt1320_dev_suspend(struct device *dev) +{ + struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev); + + if (!rt1320->hw_init) + return 0; + + regcache_cache_only(rt1320->regmap, true); + regcache_cache_only(rt1320->mbq_regmap, true); + return 0; +} + +#define RT1320_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt1320_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt1320->first_hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT1320_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__); + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt1320->regmap, false); + regcache_sync(rt1320->regmap); + regcache_cache_only(rt1320->mbq_regmap, false); + regcache_sync(rt1320->mbq_regmap); + return 0; +} + +static const struct dev_pm_ops rt1320_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume) + SET_RUNTIME_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume, NULL) +}; + +static struct sdw_driver rt1320_sdw_driver = { + .driver = { + .name = "rt1320-sdca", + .pm = &rt1320_pm, + }, + .probe = rt1320_sdw_probe, + .remove = rt1320_sdw_remove, + .ops = &rt1320_slave_ops, + .id_table = rt1320_id, +}; +module_sdw_driver(rt1320_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT1320 driver SDCA SDW"); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h new file mode 100644 index 000000000000..b23228e74568 --- /dev/null +++ b/sound/soc/codecs/rt1320-sdw.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt1320-sdw.h -- RT1320 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2024 Realtek Semiconductor Corp. + */ + +#ifndef __RT1320_SDW_H__ +#define __RT1320_SDW_H__ + +#include +#include +#include +#include +#include + +/* imp-defined registers */ +#define RT1320_DEV_VERSION_ID_1 0xc404 + +#define RT1320_KR0_STATUS_CNT 0x1000f008 +#define RT1320_HIFI_VER_0 0x3fe2e000 +#define RT1320_HIFI_VER_1 0x3fe2e001 +#define RT1320_HIFI_VER_2 0x3fe2e002 +#define RT1320_HIFI_VER_3 0x3fe2e003 + +/* RT1320 SDCA Control - function number */ +#define FUNC_NUM_AMP 0x04 + +/* RT1320 SDCA entity */ +#define RT1320_SDCA_ENT0 0x00 +#define RT1320_SDCA_ENT_PDE11 0x2a +#define RT1320_SDCA_ENT_PDE23 0x33 +#define RT1320_SDCA_ENT_PDE27 0x27 +#define RT1320_SDCA_ENT_FU14 0x32 +#define RT1320_SDCA_ENT_FU21 0x03 +#define RT1320_SDCA_ENT_FU113 0x30 +#define RT1320_SDCA_ENT_CS14 0x13 +#define RT1320_SDCA_ENT_CS21 0x21 +#define RT1320_SDCA_ENT_CS113 0x12 +#define RT1320_SDCA_ENT_SAPU 0x29 +#define RT1320_SDCA_ENT_PPU21 0x04 + +/* RT1320 SDCA control */ +#define RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10 +#define RT1320_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT1320_SDCA_CTL_FU_MUTE 0x01 +#define RT1320_SDCA_CTL_FU_VOLUME 0x02 +#define RT1320_SDCA_CTL_SAPU_PROTECTION_MODE 0x10 +#define RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS 0x11 +#define RT1320_SDCA_CTL_POSTURE_NUMBER 0x10 +#define RT1320_SDCA_CTL_FUNC_STATUS 0x10 + +/* RT1320 SDCA channel */ +#define CH_01 0x01 +#define CH_02 0x02 + +/* Function_Status */ +#define FUNCTION_NEEDS_INITIALIZATION BIT(5) + +/* Sample Frequency Index */ +#define RT1320_SDCA_RATE_16000HZ 0x04 +#define RT1320_SDCA_RATE_32000HZ 0x07 +#define RT1320_SDCA_RATE_44100HZ 0x08 +#define RT1320_SDCA_RATE_48000HZ 0x09 +#define RT1320_SDCA_RATE_96000HZ 0x0b +#define RT1320_SDCA_RATE_192000HZ 0x0d + +enum { + RT1320_AIF1, +}; + +/* + * The version id will be useful to distinguish the capability between the different IC versions. + * Currently, VA and VB have different DSP FW versions. + */ +enum rt1320_version_id { + RT1320_VA, + RT1320_VB, +}; + +#define RT1320_VER_B_ID 0x07392238 + +struct rt1320_sdw_priv { + struct snd_soc_component *component; + struct regmap *regmap; + struct regmap *mbq_regmap; + struct sdw_slave *sdw_slave; + struct sdw_bus_params params; + bool hw_init; + bool first_hw_init; + int version_id; +}; + +#endif /* __RT1320_SDW_H__ */ From ad72a1e7c0534b9d533ac967a880b8f8d0b83bc0 Mon Sep 17 00:00:00 2001 From: Xiaxi Shen Date: Thu, 16 May 2024 22:13:17 -0700 Subject: [PATCH 008/349] ASoC: dt-bindings: ak4104: convert to dt schema Convert ak4104 binding to DT schema Signed-off-by: Xiaxi Shen Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240517051317.466764-1-shenxiaxi26@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ak4104.txt | 25 ---------- .../bindings/sound/asahi-kasei,ak4104.yaml | 49 +++++++++++++++++++ 2 files changed, 49 insertions(+), 25 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/ak4104.txt create mode 100644 Documentation/devicetree/bindings/sound/asahi-kasei,ak4104.yaml diff --git a/Documentation/devicetree/bindings/sound/ak4104.txt b/Documentation/devicetree/bindings/sound/ak4104.txt deleted file mode 100644 index ae5f7f057dc3..000000000000 --- a/Documentation/devicetree/bindings/sound/ak4104.txt +++ /dev/null @@ -1,25 +0,0 @@ -AK4104 S/PDIF transmitter - -This device supports SPI mode only. - -Required properties: - - - compatible : "asahi-kasei,ak4104" - - - reg : The chip select number on the SPI bus - - - vdd-supply : A regulator node, providing 2.7V - 3.6V - -Optional properties: - - - reset-gpios : a GPIO spec for the reset pin. If specified, it will be - deasserted before communication to the device starts. - -Example: - -spdif: ak4104@0 { - compatible = "asahi-kasei,ak4104"; - reg = <0>; - spi-max-frequency = <5000000>; - vdd-supply = <&vdd_3v3_reg>; -}; diff --git a/Documentation/devicetree/bindings/sound/asahi-kasei,ak4104.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4104.yaml new file mode 100644 index 000000000000..86f6061d3c50 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4104.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4104.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AK4104 S/PDIF transmitter + +allOf: + - $ref: dai-common.yaml# + +maintainers: + - Daniel Mack + - Xiaxi Shen + +properties: + compatible: + const: asahi-kasei,ak4104 + + reg: + description: Chip select number on the SPI bus + maxItems: 1 + + vdd-supply: + description: A regulator node providing between 2.7V and 3.6V. + + reset-gpios: + maxItems: 1 + description: Optional GPIO spec for the reset pin, deasserted + before communication starts. + +required: + - compatible + - reg + - vdd-supply + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@0 { + compatible = "asahi-kasei,ak4104"; + reg = <0>; + vdd-supply = <&vdd_3v3_reg>; + }; + }; From f20847d92caa51c31556a64f0849903c55ed38c1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 May 2024 12:42:25 +0200 Subject: [PATCH 009/349] ASoC: codecs: wcd938x: Drop unused duplicated MIC2 bias register defines All MIC1-4 bias registers are the same and the header already defines register fields for them. Drop unused, duplicated defines for MIC2 bias enable register. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240523104228.36263-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h index 74b1498fec38..df07e92d9d97 100644 --- a/sound/soc/codecs/wcd938x.h +++ b/sound/soc/codecs/wcd938x.h @@ -75,9 +75,7 @@ #define WCD938X_MICB_PULL_UP 2 #define WCD938X_MICB_PULL_DOWN 3 #define WCD938X_ANA_MICB2 (0x3023) -#define WCD938X_ANA_MICB2_ENABLE BIT(6) #define WCD938X_ANA_MICB2_ENABLE_MASK GENMASK(7, 6) -#define WCD938X_ANA_MICB2_VOUT_MASK GENMASK(5, 0) #define WCD938X_ANA_MICB2_RAMP (0x3024) #define WCD938X_RAMP_EN_MASK BIT(7) #define WCD938X_RAMP_SHIFT_CTRL_MASK GENMASK(4, 2) From 40b2ffaf594cdf9e4a86d4f28b392e58b9dafafd Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 May 2024 12:42:26 +0200 Subject: [PATCH 010/349] ASoC: codecs: wcd938x: Unify define used for MIC2 bias register There is a define for MIC bias registers enable mask called WCD938X_MICB_EN_MASK, which is already used to handle all four MIC1-4 biases in wcd938x_mbhc_micb_adjust_voltage(). Use the same define also in wcd938x_mbhc_micb_en_status() for MIC2 to have unified, simpler approach. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240523104228.36263-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.c | 2 +- sound/soc/codecs/wcd938x.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 6021aa5a5689..9e2070356b84 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -1982,7 +1982,7 @@ static bool wcd938x_mbhc_micb_en_status(struct snd_soc_component *component, int if (micb_num == MIC_BIAS_2) { val = snd_soc_component_read_field(component, WCD938X_ANA_MICB2, - WCD938X_ANA_MICB2_ENABLE_MASK); + WCD938X_MICB_EN_MASK); if (val == WCD938X_MICB_ENABLE) return true; } diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h index df07e92d9d97..0d332cb555ac 100644 --- a/sound/soc/codecs/wcd938x.h +++ b/sound/soc/codecs/wcd938x.h @@ -75,7 +75,6 @@ #define WCD938X_MICB_PULL_UP 2 #define WCD938X_MICB_PULL_DOWN 3 #define WCD938X_ANA_MICB2 (0x3023) -#define WCD938X_ANA_MICB2_ENABLE_MASK GENMASK(7, 6) #define WCD938X_ANA_MICB2_RAMP (0x3024) #define WCD938X_RAMP_EN_MASK BIT(7) #define WCD938X_RAMP_SHIFT_CTRL_MASK GENMASK(4, 2) From 42cef39b76ee705118b27b23a0117e382d4d4a35 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 May 2024 12:42:27 +0200 Subject: [PATCH 011/349] ASoC: codecs: wcd939x: Unify define used for MIC bias registers All four microphone bias registers have similar layout: enable mask is exactly the same. Use one define, just like older driver wcd938x is doing, to make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240523104228.36263-3-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 36 +++++++++++++++++------------------- sound/soc/codecs/wcd939x.h | 5 +---- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index c49894aad8a5..201592c728c3 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -1268,25 +1268,20 @@ static int wcd939x_micbias_control(struct snd_soc_component *component, { struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); int micb_index = micb_num - 1; - u16 micb_field; u16 micb_reg; switch (micb_num) { case MIC_BIAS_1: micb_reg = WCD939X_ANA_MICB1; - micb_field = WCD939X_MICB1_ENABLE; break; case MIC_BIAS_2: micb_reg = WCD939X_ANA_MICB2; - micb_field = WCD939X_MICB2_ENABLE; break; case MIC_BIAS_3: micb_reg = WCD939X_ANA_MICB3; - micb_field = WCD939X_MICB3_ENABLE; break; case MIC_BIAS_4: micb_reg = WCD939X_ANA_MICB4; - micb_field = WCD939X_MICB4_ENABLE; break; default: dev_err(component->dev, "%s: Invalid micbias number: %d\n", @@ -1300,7 +1295,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component, if (wcd939x->pullup_ref[micb_index] == 1 && wcd939x->micb_ref[micb_index] == 0) snd_soc_component_write_field(component, micb_reg, - micb_field, MICB_BIAS_PULL_UP); + WCD939X_MICB_ENABLE, + MICB_BIAS_PULL_UP); break; case MICB_PULLUP_DISABLE: if (wcd939x->pullup_ref[micb_index] > 0) @@ -1308,7 +1304,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component, if (wcd939x->pullup_ref[micb_index] == 0 && wcd939x->micb_ref[micb_index] == 0) snd_soc_component_write_field(component, micb_reg, - micb_field, MICB_BIAS_DISABLE); + WCD939X_MICB_ENABLE, + MICB_BIAS_DISABLE); break; case MICB_ENABLE: wcd939x->micb_ref[micb_index]++; @@ -1345,7 +1342,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component, snd_soc_component_write_field(component, WCD939X_MICB4_TEST_CTL_2, WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); - snd_soc_component_write_field(component, micb_reg, micb_field, + snd_soc_component_write_field(component, micb_reg, + WCD939X_MICB_ENABLE, MICB_BIAS_ENABLE); if (micb_num == MIC_BIAS_2) wcd_mbhc_event_notify(wcd939x->wcd_mbhc, @@ -1362,7 +1360,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component, if (wcd939x->micb_ref[micb_index] == 0 && wcd939x->pullup_ref[micb_index] > 0) snd_soc_component_write_field(component, micb_reg, - micb_field, MICB_BIAS_PULL_UP); + WCD939X_MICB_ENABLE, + MICB_BIAS_PULL_UP); else if (wcd939x->micb_ref[micb_index] == 0 && wcd939x->pullup_ref[micb_index] == 0) { if (micb_num == MIC_BIAS_2) @@ -1370,7 +1369,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component, WCD_EVENT_PRE_MICBIAS_2_OFF); snd_soc_component_write_field(component, micb_reg, - micb_field, MICB_BIAS_DISABLE); + WCD939X_MICB_ENABLE, + MICB_BIAS_DISABLE); if (micb_num == MIC_BIAS_2) wcd_mbhc_event_notify(wcd939x->wcd_mbhc, WCD_EVENT_POST_MICBIAS_2_OFF); @@ -1873,7 +1873,7 @@ static bool wcd939x_mbhc_micb_en_status(struct snd_soc_component *component, int if (micb_num == MIC_BIAS_2) { u8 val; - val = FIELD_GET(WCD939X_MICB2_ENABLE, + val = FIELD_GET(WCD939X_MICB_ENABLE, snd_soc_component_read(component, WCD939X_ANA_MICB2)); if (val == MICB_BIAS_ENABLE) return true; @@ -1935,7 +1935,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, int req_volt, int micb_num) { struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); - unsigned int micb_en_field, micb_vout_ctl_field; + unsigned int micb_vout_ctl_field; unsigned int micb_reg, cur_vout_ctl, micb_en; int req_vout_ctl; int ret = 0; @@ -1943,22 +1943,18 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, switch (micb_num) { case MIC_BIAS_1: micb_reg = WCD939X_ANA_MICB1; - micb_en_field = WCD939X_MICB1_ENABLE; micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL; break; case MIC_BIAS_2: micb_reg = WCD939X_ANA_MICB2; - micb_en_field = WCD939X_MICB2_ENABLE; micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL; break; case MIC_BIAS_3: micb_reg = WCD939X_ANA_MICB3; - micb_en_field = WCD939X_MICB3_ENABLE; micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL; break; case MIC_BIAS_4: micb_reg = WCD939X_ANA_MICB4; - micb_en_field = WCD939X_MICB4_ENABLE; micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL; break; default: @@ -1975,7 +1971,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, * micbias. */ micb_en = snd_soc_component_read_field(component, micb_reg, - micb_en_field); + WCD939X_MICB_ENABLE); cur_vout_ctl = snd_soc_component_read_field(component, micb_reg, micb_vout_ctl_field); @@ -1996,14 +1992,16 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, if (micb_en == MICB_BIAS_ENABLE) snd_soc_component_write_field(component, micb_reg, - micb_en_field, MICB_BIAS_PULL_DOWN); + WCD939X_MICB_ENABLE, + MICB_BIAS_PULL_DOWN); snd_soc_component_write_field(component, micb_reg, micb_vout_ctl_field, req_vout_ctl); if (micb_en == MICB_BIAS_ENABLE) { snd_soc_component_write_field(component, micb_reg, - micb_en_field, MICB_BIAS_ENABLE); + WCD939X_MICB_ENABLE, + MICB_BIAS_ENABLE); /* * Add 2ms delay as per HW requirement after enabling * micbias diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h index 807cf3113d20..383a79316439 100644 --- a/sound/soc/codecs/wcd939x.h +++ b/sound/soc/codecs/wcd939x.h @@ -91,10 +91,9 @@ #define WCD939X_ANA_MBHC_BTN7 (0x3021) #define WCD939X_MBHC_BTN7_VTH GENMASK(7, 2) #define WCD939X_ANA_MICB1 (0x3022) -#define WCD939X_MICB1_ENABLE GENMASK(7, 6) +#define WCD939X_MICB_ENABLE GENMASK(7, 6) #define WCD939X_MICB1_VOUT_CTL GENMASK(5, 0) #define WCD939X_ANA_MICB2 (0x3023) -#define WCD939X_MICB2_ENABLE GENMASK(7, 6) #define WCD939X_MICB2_VOUT_CTL GENMASK(5, 0) #define WCD939X_ANA_MICB2_RAMP (0x3024) #define WCD939X_MICB2_RAMP_RAMP_ENABLE BIT(7) @@ -103,10 +102,8 @@ #define WCD939X_MICB2_RAMP_SHIFT_CTL GENMASK(4, 2) #define WCD939X_MICB2_RAMP_USB_MGDET_MICB2_RAMP GENMASK(1, 0) #define WCD939X_ANA_MICB3 (0x3025) -#define WCD939X_MICB3_ENABLE GENMASK(7, 6) #define WCD939X_MICB3_VOUT_CTL GENMASK(5, 0) #define WCD939X_ANA_MICB4 (0x3026) -#define WCD939X_MICB4_ENABLE GENMASK(7, 6) #define WCD939X_MICB4_VOUT_CTL GENMASK(5, 0) #define WCD939X_BIAS_CTL (0x3028) #define WCD939X_BIAS_VBG_FINE_ADJ (0x3029) From 6f80324bc1317f50f1c25c6d65a8dbef417aeba4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 May 2024 12:42:28 +0200 Subject: [PATCH 012/349] ASoC: codecs: wcd939x: Minor white-space and define cleanup Correct white-space issues and drop unused WCD939X_MBHC_IS_SECOND_RAMP_REQUIRED() define. No functional impact. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240523104228.36263-4-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 201592c728c3..770bc2f35ba7 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -85,7 +85,6 @@ enum { #define WCD939X_MBHC_GET_X1(x) ((x) & 0x3FFF) /* Z value compared in milliOhm */ -#define WCD939X_MBHC_IS_SECOND_RAMP_REQUIRED(z) false #define WCD939X_ANA_MBHC_ZDET_CONST (1018 * 1024) enum { @@ -525,7 +524,7 @@ static int wcd939x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, WCD939X_DIGITAL_CDC_COMP_CTL_0, WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN, true); - /* 5msec compander delay as per HW requirement */ + /* 5msec compander delay as per HW requirement */ if (!wcd939x->comp2_enable || snd_soc_component_read_field(component, WCD939X_DIGITAL_CDC_COMP_CTL_0, @@ -1869,7 +1868,6 @@ static void wcd939x_mbhc_program_btn_thr(struct snd_soc_component *component, static bool wcd939x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num) { - if (micb_num == MIC_BIAS_2) { u8 val; From d556f807bda0b260b392069b3c8ac9e6491f0025 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 16 May 2024 10:56:11 +0300 Subject: [PATCH 013/349] ASoC: SOF: ipc4-topology: Add support for NHLT with 16-bit only DMIC blob The ACPI NHLT table always had 32-bit DMIC blob even if 16-bit was also present and taken as a 'rule' which obviously got broken and there is at least one device on the market which ships with only 16-bit DMIC configuration blob. This corner case has never been supported and it is going to need topology updates for DMIC copier to support multiple formats. As for the kernel side: if the copier supports multiple formats and the preferred 32-bit DMIC blob is not found then we will try to get a 16-bit DMIC configuration and look for a 16-bit copier config. Fixes: f9209644ae76 ("ASoC: SOF: ipc4-topology: Correct DAI copier config and NHLT blob request") Link: https://github.com/thesofproject/linux/issues/4973 Signed-off-by: Peter Ujfalusi Reviewed-by: Seppo Ingalsuo Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://msgid.link/r/20240516075611.18018-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index beff10989324..521b4dcba601 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1483,6 +1483,8 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai dir, dev_type); if (!cfg) { + bool get_new_blob = false; + if (format_change) { /* * The 32-bit blob was not found in NHLT table, try to @@ -1490,7 +1492,20 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai */ bit_depth = params_width(params); format_change = false; + get_new_blob = true; + } else if (linktype == SOF_DAI_INTEL_DMIC && !single_format) { + /* + * The requested 32-bit blob (no format change for the + * blob request) was not found in NHLT table, try to + * look for 16-bit blob if the copier supports multiple + * formats + */ + bit_depth = 16; + format_change = true; + get_new_blob = true; + } + if (get_new_blob) { cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type, bit_depth, bit_depth, @@ -1513,8 +1528,8 @@ out: if (format_change) { /* - * Update the params to reflect that we have loaded 32-bit blob - * instead of the 16-bit. + * Update the params to reflect that different blob was loaded + * instead of the requested bit depth (16 -> 32 or 32 -> 16). * This information is going to be used by the caller to find * matching copier format on the dai side. */ @@ -1522,7 +1537,11 @@ out: m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); snd_mask_none(m); - snd_mask_set_format(m, SNDRV_PCM_FORMAT_S32_LE); + if (bit_depth == 16) + snd_mask_set_format(m, SNDRV_PCM_FORMAT_S16_LE); + else + snd_mask_set_format(m, SNDRV_PCM_FORMAT_S32_LE); + } return 0; From 734447685ecc7c6328e40cb1bd4aaeeac03c1413 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 13 May 2024 19:37:20 +0200 Subject: [PATCH 014/349] ASoC: topology: Constify an argument of snd_soc_tplg_component_load() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit snd_soc_tplg_component_load() does not modify its "*ops" argument. It only read some values and stores it in "soc_tplg.ops". This argument and the ops field in "struct soc_tplg" can be made const. Signed-off-by: Christophe JAILLET Reviewed-by: Amadeusz Sławiński Link: https://msgid.link/r/f2f983e791d7f941a95556bb147f426a345d84d4.1715526069.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 2 +- sound/soc/soc-topology.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index f055c6917f6c..1eedd203ac29 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -178,7 +178,7 @@ static inline const void *snd_soc_tplg_get_data(struct snd_soc_tplg_hdr *hdr) /* Dynamic Object loading and removal for component drivers */ int snd_soc_tplg_component_load(struct snd_soc_component *comp, - struct snd_soc_tplg_ops *ops, const struct firmware *fw); + const struct snd_soc_tplg_ops *ops, const struct firmware *fw); int snd_soc_tplg_component_remove(struct snd_soc_component *comp); /* Binds event handlers to dynamic widgets */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 90ca37e008b3..b00ec01361c2 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -73,7 +73,7 @@ struct soc_tplg { int bytes_ext_ops_count; /* optional fw loading callbacks to component drivers */ - struct snd_soc_tplg_ops *ops; + const struct snd_soc_tplg_ops *ops; }; /* check we dont overflow the data for this control chunk */ @@ -2334,7 +2334,7 @@ static int soc_tplg_load(struct soc_tplg *tplg) /* load audio component topology from "firmware" file */ int snd_soc_tplg_component_load(struct snd_soc_component *comp, - struct snd_soc_tplg_ops *ops, const struct firmware *fw) + const struct snd_soc_tplg_ops *ops, const struct firmware *fw) { struct soc_tplg tplg; int ret; From e51c001faa59fd751ef16bac6cf373fb7fc91e9c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 13 May 2024 19:37:21 +0200 Subject: [PATCH 015/349] ASoC: Intel: avs: Constify struct snd_soc_tplg_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Constifying "struct snd_soc_tplg_ops" moves some data to a read-only section, so increase overall security. On a x86_64, with allmodconfig: Before: text data bss dec hex filename 28046 794 0 28840 70a8 sound/soc/intel/avs/topology.o After: text data bss dec hex filename 28206 614 0 28820 7094 sound/soc/intel/avs/topology.o Signed-off-by: Christophe JAILLET Reviewed-by: Amadeusz Sławiński Link: https://msgid.link/r/01de0157088de0475970c79738284d6c86d702fe.1715526069.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/intel/avs/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index 02bae207f6ec..35381a835c93 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -1889,7 +1889,7 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_ return 0; } -static struct snd_soc_tplg_ops avs_tplg_ops = { +static const struct snd_soc_tplg_ops avs_tplg_ops = { .io_ops = avs_control_ops, .io_ops_count = ARRAY_SIZE(avs_control_ops), .control_load = avs_control_load, From 4a341101337fc158b993417a9d2085815b0201da Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 13 May 2024 19:37:22 +0200 Subject: [PATCH 016/349] ASoC: qdsp6: audioreach: Constify struct snd_soc_tplg_ops Constifying "struct snd_soc_tplg_ops" moves some data to a read-only section, so increase overall security. On a x86_64, with allmodconfig: Before: text data bss dec hex filename 19942 832 0 20774 5126 sound/soc/qcom/qdsp6/topology.o After: text data bss dec hex filename 20102 652 0 20754 5112 sound/soc/qcom/qdsp6/topology.o Signed-off-by: Christophe JAILLET Link: https://msgid.link/r/a5ae843dd8aaacbc1148aea7a3b1d03f11495872.1715526069.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c index 70572c83e101..c15d1a2b6dbf 100644 --- a/sound/soc/qcom/qdsp6/topology.c +++ b/sound/soc/qcom/qdsp6/topology.c @@ -1240,7 +1240,7 @@ static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = { audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw}, }; -static struct snd_soc_tplg_ops audioreach_tplg_ops = { +static const struct snd_soc_tplg_ops audioreach_tplg_ops = { .io_ops = audioreach_io_ops, .io_ops_count = ARRAY_SIZE(audioreach_io_ops), From 9ff6aaf0f7e99798afeda974c83e410e9e2c3026 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 13 May 2024 19:37:23 +0200 Subject: [PATCH 017/349] ASoC: Intel: Skylake: Constify struct snd_soc_tplg_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Constifying "struct snd_soc_tplg_ops" moves some data to a read-only section, so increase overall security. On a x86_64, with allmodconfig: Before: text data bss dec hex filename 58844 5282 56 64182 fab6 sound/soc/intel/skylake/skl-topology.o After: text data bss dec hex filename 59004 5122 56 64182 fab6 sound/soc/intel/skylake/skl-topology.o Signed-off-by: Christophe JAILLET Reviewed-by: Amadeusz Sławiński Link: https://msgid.link/r/48f096b6dc617ecf3ca53211c2a696a4df33b21a.1715526069.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index e27f0fc3d897..602ef4321122 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3470,7 +3470,7 @@ static int skl_tplg_complete(struct snd_soc_component *component) return 0; } -static struct snd_soc_tplg_ops skl_tplg_ops = { +static const struct snd_soc_tplg_ops skl_tplg_ops = { .widget_load = skl_tplg_widget_load, .control_load = skl_tplg_control_load, .bytes_ext_ops = skl_tlv_ops, From e9c33917932e940348833bf4a1ad3c5ffceb211e Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 13 May 2024 19:37:24 +0200 Subject: [PATCH 018/349] ASoC: SOF: topology: Constify struct snd_soc_tplg_ops Constifying "struct snd_soc_tplg_ops" moves some data to a read-only section, so increase overall security. On a x86_64, with allmodconfig: Before: text data bss dec hex filename 44519 2888 48 47455 b95f sound/soc/sof/topology.o After: text data bss dec hex filename 44839 2552 48 47439 b94f sound/soc/sof/topology.o Signed-off-by: Christophe JAILLET Link: https://msgid.link/r/2d9f5b75e979eb38b6f3baf85dfa1f0fdb3447ef.1715526069.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index da182314aa87..b54382131991 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2278,7 +2278,7 @@ static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops[] = { {SOF_TPLG_KCTL_BYTES_VOLATILE_RO, snd_sof_bytes_ext_volatile_get}, }; -static struct snd_soc_tplg_ops sof_tplg_ops = { +static const struct snd_soc_tplg_ops sof_tplg_ops = { /* external kcontrol init - used for any driver specific init */ .control_load = sof_control_load, .control_unload = sof_control_unload, @@ -2433,7 +2433,7 @@ static int sof_dspless_link_load(struct snd_soc_component *scomp, int index, return 0; } -static struct snd_soc_tplg_ops sof_dspless_tplg_ops = { +static const struct snd_soc_tplg_ops sof_dspless_tplg_ops = { /* external widget init - used for any driver specific init */ .widget_ready = sof_dspless_widget_ready, .widget_unload = sof_dspless_widget_unload, From 8951ae0b2e096387154fa05887259b405cc05383 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 13 May 2024 19:37:25 +0200 Subject: [PATCH 019/349] const_structs.checkpatch: add snd_soc_tplg_ops Now that the soc-topology can handle "const struct snd_soc_tplg_ops" make sure that new usages of the struct already enter the tree as const. Signed-off-by: Christophe JAILLET Link: https://msgid.link/r/6936369a414077265c11115c98364ae21e3cbdda.1715526069.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- scripts/const_structs.checkpatch | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch index 52e5bfb61fd0..e9589c372968 100644 --- a/scripts/const_structs.checkpatch +++ b/scripts/const_structs.checkpatch @@ -79,6 +79,7 @@ snd_rawmidi_ops snd_soc_component_driver snd_soc_dai_ops snd_soc_ops +snd_soc_tplg_ops soc_pcmcia_socket_ops stacktrace_ops sysfs_ops From 560495c04d053b98f1349249a8d0545fb25d84ec Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 7 May 2024 14:37:33 -0300 Subject: [PATCH 020/349] ASoC: fsl: fsl_aud2htx: Switch to RUNTIME_PM_OPS() Replace SET_RUNTIME_PM_OPS() with its modern alternative RUNTIME_PM_OPS(). The combined usage of pm_ptr() and RUNTIME_PM_OPS() allows the compiler to evaluate if the runtime suspend/resume() functions are used at build time or are simply dead code. This allows removing the __maybe_unused notation from the runtime suspend/resume() functions. Signed-off-by: Fabio Estevam Link: https://msgid.link/r/20240507173735.3456334-1-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_aud2htx.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index ee2f6ad1f800..a6cbaa6364c7 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -261,7 +261,7 @@ static void fsl_aud2htx_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev) +static int fsl_aud2htx_runtime_suspend(struct device *dev) { struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev); @@ -271,7 +271,7 @@ static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev) +static int fsl_aud2htx_runtime_resume(struct device *dev) { struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev); int ret; @@ -288,9 +288,8 @@ static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev) } static const struct dev_pm_ops fsl_aud2htx_pm_ops = { - SET_RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend, - fsl_aud2htx_runtime_resume, - NULL) + RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend, fsl_aud2htx_runtime_resume, + NULL) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; @@ -300,7 +299,7 @@ static struct platform_driver fsl_aud2htx_driver = { .remove_new = fsl_aud2htx_remove, .driver = { .name = "fsl-aud2htx", - .pm = &fsl_aud2htx_pm_ops, + .pm = pm_ptr(&fsl_aud2htx_pm_ops), .of_match_table = fsl_aud2htx_dt_ids, }, }; From fa14065d71cb0cfe8eb445b23fd313922693a1fa Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 7 May 2024 14:37:34 -0300 Subject: [PATCH 021/349] ASoC: fsl: fsl_easrc: Switch to RUNTIME_PM_OPS() Replace SET_RUNTIME_PM_OPS() with its modern alternative RUNTIME_PM_OPS(). The combined usage of pm_ptr() and RUNTIME_PM_OPS() allows the compiler to evaluate if the runtime suspend/resume() functions are used at build time or are simply dead code. This allows removing the __maybe_unused notation from the runtime suspend/resume() functions. Signed-off-by: Fabio Estevam Link: https://msgid.link/r/20240507173735.3456334-2-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_easrc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index ec53bda46a46..962f30912091 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1988,7 +1988,7 @@ static void fsl_easrc_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static __maybe_unused int fsl_easrc_runtime_suspend(struct device *dev) +static int fsl_easrc_runtime_suspend(struct device *dev) { struct fsl_asrc *easrc = dev_get_drvdata(dev); struct fsl_easrc_priv *easrc_priv = easrc->private; @@ -2005,7 +2005,7 @@ static __maybe_unused int fsl_easrc_runtime_suspend(struct device *dev) return 0; } -static __maybe_unused int fsl_easrc_runtime_resume(struct device *dev) +static int fsl_easrc_runtime_resume(struct device *dev) { struct fsl_asrc *easrc = dev_get_drvdata(dev); struct fsl_easrc_priv *easrc_priv = easrc->private; @@ -2086,9 +2086,7 @@ disable_mem_clk: } static const struct dev_pm_ops fsl_easrc_pm_ops = { - SET_RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, - fsl_easrc_runtime_resume, - NULL) + RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, fsl_easrc_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; @@ -2098,7 +2096,7 @@ static struct platform_driver fsl_easrc_driver = { .remove_new = fsl_easrc_remove, .driver = { .name = "fsl-easrc", - .pm = &fsl_easrc_pm_ops, + .pm = pm_ptr(&fsl_easrc_pm_ops), .of_match_table = fsl_easrc_dt_ids, }, }; From 5dfd8f78b57641530bb674791b66b4ae8a8417f5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 7 May 2024 14:37:35 -0300 Subject: [PATCH 022/349] ASoC: fsl: fsl_xcvr: Switch to RUNTIME_PM_OPS() Replace SET_RUNTIME_PM_OPS() with its modern alternative RUNTIME_PM_OPS(). The combined usage of pm_ptr() and RUNTIME_PM_OPS() allows the compiler to evaluate if the runtime suspend/resume() functions are used at build time or are simply dead code. This allows removing the __maybe_unused notation from the runtime suspend/resume() functions. Signed-off-by: Fabio Estevam Link: https://msgid.link/r/20240507173735.3456334-3-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_xcvr.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index c46f64557a7f..5472ace23d82 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -1364,7 +1364,7 @@ static void fsl_xcvr_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev) +static int fsl_xcvr_runtime_suspend(struct device *dev) { struct fsl_xcvr *xcvr = dev_get_drvdata(dev); int ret; @@ -1398,7 +1398,7 @@ static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev) return 0; } -static __maybe_unused int fsl_xcvr_runtime_resume(struct device *dev) +static int fsl_xcvr_runtime_resume(struct device *dev) { struct fsl_xcvr *xcvr = dev_get_drvdata(dev); int ret; @@ -1483,9 +1483,7 @@ stop_ipg_clk: } static const struct dev_pm_ops fsl_xcvr_pm_ops = { - SET_RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend, - fsl_xcvr_runtime_resume, - NULL) + RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend, fsl_xcvr_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; @@ -1494,7 +1492,7 @@ static struct platform_driver fsl_xcvr_driver = { .probe = fsl_xcvr_probe, .driver = { .name = "fsl,imx8mp-audio-xcvr", - .pm = &fsl_xcvr_pm_ops, + .pm = pm_ptr(&fsl_xcvr_pm_ops), .of_match_table = fsl_xcvr_dt_ids, }, .remove_new = fsl_xcvr_remove, From ed2581305360725381190bc442918e4e5b2b8545 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 13 May 2024 19:57:16 +0200 Subject: [PATCH 023/349] ASoC: intel: Constify struct snd_soc_ops Constifying "struct snd_soc_ops" moves some data to a read-only section, so increase overall security. This structure is also part of scripts/const_structs.checkpatch. As an example, on a x86_64, with allmodconfig: Before: text data bss dec hex filename 6315 3696 0 10011 271b sound/soc/intel/boards/ehl_rt5660.o After: text data bss dec hex filename 6379 3648 0 10027 272b sound/soc/intel/boards/ehl_rt5660.o Signed-off-by: Christophe JAILLET Link: https://msgid.link/r/2f0613bf4c6018569cdaac876d0589e49cf38a80.1715622793.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw-rt5650.c | 2 +- sound/soc/intel/boards/ehl_rt5660.c | 2 +- sound/soc/intel/boards/kbl_da7219_max98357a.c | 4 ++-- sound/soc/intel/boards/kbl_da7219_max98927.c | 6 +++--- sound/soc/intel/boards/kbl_rt5660.c | 2 +- sound/soc/intel/boards/kbl_rt5663_max98927.c | 8 ++++---- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 6 +++--- sound/soc/intel/boards/sof_es8336.c | 2 +- sound/soc/intel/boards/sof_nau8825.c | 2 +- sound/soc/intel/boards/sof_realtek_common.c | 2 +- sound/soc/intel/boards/sof_rt5682.c | 2 +- sound/soc/intel/boards/sof_sdw_common.h | 2 +- sound/soc/intel/boards/sof_sdw_rt_amp.c | 2 +- sound/soc/intel/boards/sof_wm8804.c | 2 +- 14 files changed, 22 insertions(+), 22 deletions(-) diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index 3ae26f21458f..3c7cee03a02e 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -131,7 +131,7 @@ static int bdw_rt5650_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops bdw_rt5650_ops = { +static const struct snd_soc_ops bdw_rt5650_ops = { .hw_params = bdw_rt5650_hw_params, }; diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c index 686e60321224..26289e8fdd87 100644 --- a/sound/soc/intel/boards/ehl_rt5660.c +++ b/sound/soc/intel/boards/ehl_rt5660.c @@ -132,7 +132,7 @@ static int rt5660_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops rt5660_ops = { +static const struct snd_soc_ops rt5660_ops = { .hw_params = rt5660_hw_params, }; diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index 9dbc15f9d1c9..154f6a74ed15 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -354,7 +354,7 @@ static int kabylake_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops kabylake_dmic_ops = { +static const struct snd_soc_ops kabylake_dmic_ops = { .startup = kabylake_dmic_startup, }; @@ -388,7 +388,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static struct snd_soc_ops skylake_refcap_ops = { +static const struct snd_soc_ops skylake_refcap_ops = { .startup = kabylake_refcap_startup, }; diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index e662da5af83b..02ed77a07e23 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -288,7 +288,7 @@ static int kabylake_ssp0_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -static struct snd_soc_ops kabylake_ssp0_ops = { +static const struct snd_soc_ops kabylake_ssp0_ops = { .hw_params = kabylake_ssp0_hw_params, .trigger = kabylake_ssp0_trigger, }; @@ -535,7 +535,7 @@ static int kabylake_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops kabylake_dmic_ops = { +static const struct snd_soc_ops kabylake_dmic_ops = { .startup = kabylake_dmic_startup, }; @@ -569,7 +569,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream) } -static struct snd_soc_ops skylake_refcap_ops = { +static const struct snd_soc_ops skylake_refcap_ops = { .startup = kabylake_refcap_startup, }; diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c index 894d127c482a..66885cb36f24 100644 --- a/sound/soc/intel/boards/kbl_rt5660.c +++ b/sound/soc/intel/boards/kbl_rt5660.c @@ -277,7 +277,7 @@ static int kabylake_rt5660_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops kabylake_rt5660_ops = { +static const struct snd_soc_ops kabylake_rt5660_ops = { .hw_params = kabylake_rt5660_hw_params, }; diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index e16c42e81eca..9da89436a917 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -489,7 +489,7 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops kabylake_rt5663_ops = { +static const struct snd_soc_ops kabylake_rt5663_ops = { .hw_params = kabylake_rt5663_hw_params, }; @@ -539,7 +539,7 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops kabylake_ssp0_ops = { +static const struct snd_soc_ops kabylake_ssp0_ops = { .hw_params = kabylake_ssp0_hw_params, }; @@ -575,7 +575,7 @@ static int kabylake_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops kabylake_dmic_ops = { +static const struct snd_soc_ops kabylake_dmic_ops = { .startup = kabylake_dmic_startup, }; @@ -609,7 +609,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static struct snd_soc_ops skylake_refcap_ops = { +static const struct snd_soc_ops skylake_refcap_ops = { .startup = kabylake_refcap_startup, }; diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index a9501cd106ff..a32ce8f972f3 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -424,7 +424,7 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops kabylake_rt5663_ops = { +static const struct snd_soc_ops kabylake_rt5663_ops = { .hw_params = kabylake_rt5663_hw_params, }; @@ -469,7 +469,7 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops kabylake_ssp0_ops = { +static const struct snd_soc_ops kabylake_ssp0_ops = { .hw_params = kabylake_ssp0_hw_params, }; @@ -508,7 +508,7 @@ static int kabylake_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops kabylake_dmic_ops = { +static const struct snd_soc_ops kabylake_dmic_ops = { .startup = kabylake_dmic_startup, }; diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index c1fcc156a575..2a88efaa6d26 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -371,7 +371,7 @@ static int sof_es8336_hw_params(struct snd_pcm_substream *substream, } /* machine stream operations */ -static struct snd_soc_ops sof_es8336_ops = { +static const struct snd_soc_ops sof_es8336_ops = { .hw_params = sof_es8336_hw_params, .trigger = sof_8336_trigger, }; diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index c08b4eef0bcb..bfe17acbc161 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -115,7 +115,7 @@ static int sof_nau8825_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops sof_nau8825_ops = { +static const struct snd_soc_ops sof_nau8825_ops = { .hw_params = sof_nau8825_hw_params, }; diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c index dda346e0f737..f52e25083905 100644 --- a/sound/soc/intel/boards/sof_realtek_common.c +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -452,7 +452,7 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops rt1015_ops = { +static const struct snd_soc_ops rt1015_ops = { .hw_params = rt1015_hw_params, }; diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 6fc6eb0c5172..23a40b913290 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -397,7 +397,7 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops sof_rt5682_ops = { +static const struct snd_soc_ops sof_rt5682_ops = { .hw_params = sof_rt5682_hw_params, }; diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 3dfba6f6b95d..7dedac918065 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -169,7 +169,7 @@ int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); /* RT1308 I2S support */ -extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops; +extern const struct snd_soc_ops sof_sdw_rt1308_i2s_ops; /* generic amp support */ int sof_sdw_rt_amp_init(struct snd_soc_card *card, diff --git a/sound/soc/intel/boards/sof_sdw_rt_amp.c b/sound/soc/intel/boards/sof_sdw_rt_amp.c index 797ea9ffa77a..d1c0f91ce589 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_amp.c +++ b/sound/soc/intel/boards/sof_sdw_rt_amp.c @@ -233,7 +233,7 @@ static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, } /* machine stream operations */ -struct snd_soc_ops sof_sdw_rt1308_i2s_ops = { +const struct snd_soc_ops sof_sdw_rt1308_i2s_ops = { .hw_params = rt1308_i2s_hw_params, }; diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c index 4cb0d463bf40..b2d02cc92a6a 100644 --- a/sound/soc/intel/boards/sof_wm8804.c +++ b/sound/soc/intel/boards/sof_wm8804.c @@ -148,7 +148,7 @@ static int sof_wm8804_hw_params(struct snd_pcm_substream *substream, } /* machine stream operations */ -static struct snd_soc_ops sof_wm8804_ops = { +static const struct snd_soc_ops sof_wm8804_ops = { .hw_params = sof_wm8804_hw_params, }; From 8cb3aeebcb86088e30232277c9bee9054837442b Mon Sep 17 00:00:00 2001 From: Mohan Kumar Date: Mon, 27 May 2024 12:56:06 +0000 Subject: [PATCH 024/349] ASoC: simple-card-utils: Split simple_fixup_sample_fmt func Split the simple_fixup_sample_fmt() into two functions by adding one more function named simple_util_get_sample_fmt() to return the sample format value. This is useful for drivers that wish to simply get the sample format without setting the mask. Signed-off-by: Mohan Kumar Signed-off-by: Sameer Pujar Link: https://msgid.link/r/20240527125608.2461300-2-spujar@nvidia.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 ++ sound/soc/generic/simple-card-utils.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index ad67957b7b48..2c2279d082ec 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -174,6 +174,8 @@ void simple_util_parse_convert(struct device_node *np, char *prefix, struct simple_util_data *data); bool simple_util_is_convert_required(const struct simple_util_data *data); +int simple_util_get_sample_fmt(struct simple_util_data *data); + int simple_util_parse_routing(struct snd_soc_card *card, char *prefix); int simple_util_parse_widgets(struct snd_soc_card *card, diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index b4876b4f259d..852989611362 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -13,12 +13,11 @@ #include #include -static void simple_fixup_sample_fmt(struct simple_util_data *data, - struct snd_pcm_hw_params *params) +int simple_util_get_sample_fmt(struct simple_util_data *data) { int i; - struct snd_mask *mask = hw_param_mask(params, - SNDRV_PCM_HW_PARAM_FORMAT); + int val = -EINVAL; + struct { char *fmt; u32 val; @@ -33,11 +32,26 @@ static void simple_fixup_sample_fmt(struct simple_util_data *data, for (i = 0; i < ARRAY_SIZE(of_sample_fmt_table); i++) { if (!strcmp(data->convert_sample_format, of_sample_fmt_table[i].fmt)) { - snd_mask_none(mask); - snd_mask_set(mask, of_sample_fmt_table[i].val); + val = of_sample_fmt_table[i].val; break; } } + return val; +} +EXPORT_SYMBOL_GPL(simple_util_get_sample_fmt); + +static void simple_fixup_sample_fmt(struct simple_util_data *data, + struct snd_pcm_hw_params *params) +{ + int val; + struct snd_mask *mask = hw_param_mask(params, + SNDRV_PCM_HW_PARAM_FORMAT); + + val = simple_util_get_sample_fmt(data); + if (val >= 0) { + snd_mask_none(mask); + snd_mask_set(mask, val); + } } void simple_util_parse_convert(struct device_node *np, From 2502f8dd8c30edbca9253d5999294f58211039b1 Mon Sep 17 00:00:00 2001 From: Mohan Kumar Date: Mon, 27 May 2024 12:56:07 +0000 Subject: [PATCH 025/349] ASoC: tegra: I2S client convert formats handling The AHUB HW modules are interconnected with CIF which are capable of supporting Channel and Sample bit format conversion. Due to this, the I2S Client can have different Channel and Sample bit from the hw_params() and this config is passed from CIF port of I2S DT node which can help to perform this conversion. For e.g. HFP usecase consists of BT SCO with 1ch and 8k audio data which needs to be converted and mixed with external codec playback and capture path which is of 2ch and 48k format. For HFP Playback: The path includes mono to stereo and 8k to 48k conversion _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |1ch | | 1ch | |2ch | SFC | 2ch | | |BT SCO |---->| I2Sx |------>| CIF |----->| 8k->48k |---->| Codec I2Sy| |_ _ _ _| |_ _ __|client |_ _ _|audio |_ _ _ _ _| |_ _ _ _ _ _| For HFP Capture: The path includes stereo to mono and 48k to 8k conversion _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | 2ch | SFC | 2ch | | 1ch | | 1ch | | | codec I2Sy|---->| 48k->8k |----->| CIF |------>| I2Sx |---->| BT SCO| |_ _ _ _ _ _| |_ _ _ _ _| audio|_ _ _|client |_ _ _ _| |_ _ _ _| For above two path, I2S client channel uses existing DT binding to pass channels and format conversion in I2Sx CIF Port. Signed-off-by: Mohan Kumar Signed-off-by: Sameer Pujar Link: https://msgid.link/r/20240527125608.2461300-3-spujar@nvidia.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra210_i2s.c | 71 ++++++++++++++++++++++++++++++++-- sound/soc/tegra/tegra210_i2s.h | 2 + 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index ba7fdd7405ac..fe4fde844d86 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -8,11 +8,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include "tegra210_i2s.h" #include "tegra_cif.h" @@ -603,6 +605,7 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int sample_size, channels, srate, val, reg, path; struct tegra_cif_conf cif_conf; + snd_pcm_format_t sample_format; memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); @@ -615,28 +618,51 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, cif_conf.audio_ch = channels; cif_conf.client_ch = channels; + if (i2s->client_channels) + cif_conf.client_ch = i2s->client_channels; + /* AHUB CIF Audio bits configs */ switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + cif_conf.audio_bits = TEGRA_ACIF_BITS_8; + break; + case SNDRV_PCM_FORMAT_S16_LE: + cif_conf.audio_bits = TEGRA_ACIF_BITS_16; + break; + case SNDRV_PCM_FORMAT_S32_LE: + cif_conf.audio_bits = TEGRA_ACIF_BITS_32; + break; + default: + dev_err(dev, "unsupported params audio bit format!\n"); + return -EOPNOTSUPP; + } + + sample_format = params_format(params); + if (i2s->client_sample_format >= 0) + sample_format = (snd_pcm_format_t)i2s->client_sample_format; + + /* + * Format of the I2S for sending/receiving the audio + * to/from external device. + */ + switch (sample_format) { case SNDRV_PCM_FORMAT_S8: val = I2S_BITS_8; sample_size = 8; - cif_conf.audio_bits = TEGRA_ACIF_BITS_8; cif_conf.client_bits = TEGRA_ACIF_BITS_8; break; case SNDRV_PCM_FORMAT_S16_LE: val = I2S_BITS_16; sample_size = 16; - cif_conf.audio_bits = TEGRA_ACIF_BITS_16; cif_conf.client_bits = TEGRA_ACIF_BITS_16; break; case SNDRV_PCM_FORMAT_S32_LE: val = I2S_BITS_32; sample_size = 32; - cif_conf.audio_bits = TEGRA_ACIF_BITS_32; cif_conf.client_bits = TEGRA_ACIF_BITS_32; break; default: - dev_err(dev, "unsupported format!\n"); + dev_err(dev, "unsupported client bit format!\n"); return -EOPNOTSUPP; } @@ -872,6 +898,40 @@ static const struct regmap_config tegra210_i2s_regmap_config = { .cache_type = REGCACHE_FLAT, }; +/* + * The AHUB HW modules are interconnected with CIF which are capable of + * supporting Channel and Sample bit format conversion. This needs different + * CIF Audio and client configuration. As one of the config comes from + * params_channels() or params_format(), the extra configuration is passed from + * CIF Port of DT I2S node which can help to perform this conversion. + * + * 4ch audio = 4ch client = 2ch 2ch + * -----> ADMAIF -----------> CIF -------------> I2S ----> + */ +static void tegra210_parse_client_convert(struct device *dev) +{ + struct tegra210_i2s *i2s = dev_get_drvdata(dev); + struct device_node *ports, *ep; + struct simple_util_data data = {}; + int cif_port = 0; + + ports = of_get_child_by_name(dev->of_node, "ports"); + if (ports) { + ep = of_graph_get_endpoint_by_regs(ports, cif_port, -1); + if (ep) { + simple_util_parse_convert(ep, NULL, &data); + of_node_put(ep); + } + of_node_put(ports); + } + + if (data.convert_channels) + i2s->client_channels = data.convert_channels; + + if (data.convert_sample_format) + i2s->client_sample_format = simple_util_get_sample_fmt(&data); +} + static int tegra210_i2s_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -887,6 +947,7 @@ static int tegra210_i2s_probe(struct platform_device *pdev) i2s->tx_mask = DEFAULT_I2S_SLOT_MASK; i2s->rx_mask = DEFAULT_I2S_SLOT_MASK; i2s->loopback = false; + i2s->client_sample_format = -EINVAL; dev_set_drvdata(dev, i2s); @@ -916,6 +977,8 @@ static int tegra210_i2s_probe(struct platform_device *pdev) return PTR_ERR(i2s->regmap); } + tegra210_parse_client_convert(dev); + regcache_cache_only(i2s->regmap, true); err = devm_snd_soc_register_component(dev, &tegra210_i2s_cmpnt, diff --git a/sound/soc/tegra/tegra210_i2s.h b/sound/soc/tegra/tegra210_i2s.h index 030d70c45e18..fe478f3d8435 100644 --- a/sound/soc/tegra/tegra210_i2s.h +++ b/sound/soc/tegra/tegra210_i2s.h @@ -112,6 +112,8 @@ struct tegra210_i2s { struct clk *clk_i2s; struct clk *clk_sync_input; struct regmap *regmap; + int client_sample_format; + unsigned int client_channels; unsigned int stereo_to_mono[I2S_PATHS]; unsigned int mono_to_stereo[I2S_PATHS]; unsigned int dai_fmt; From 4c7d2dc698dfdb16db180c142cd681c42e23b419 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 22 May 2024 11:08:24 +0800 Subject: [PATCH 026/349] ASoC: dt-bindings: fsl,mqs: Add i.MX95 platform support There are two MQS instances on the i.MX95 platform. The definition of bit positions in the control register are different. In order to support these MQS modules, define two compatible strings to distinguish them. As one instance is in the always-on domain, another is in the net controller domain, so the compatible strings are "fsl,imx95-aonmix-mqs", "fsl,imx95-netcmix-mqs". Signed-off-by: Shengjiu Wang Reviewed-by: Rob Herring (Arm) Link: https://msgid.link/r/1716347305-18457-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,mqs.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml index 8b33353a80ca..030ccc173130 100644 --- a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml @@ -23,6 +23,8 @@ properties: - fsl,imx8qm-mqs - fsl,imx8qxp-mqs - fsl,imx93-mqs + - fsl,imx95-aonmix-mqs + - fsl,imx95-netcmix-mqs clocks: minItems: 1 From 401a1f021bbc5a81eb63742f62005629c4f8d747 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 22 May 2024 11:08:25 +0800 Subject: [PATCH 027/349] ASoC: fsl_mqs: Add i.MX95 platform support There are two MQS instances on the i.MX95 platform. The definition of bit positions in the control register are different. In order to support these MQS modules, define two compatible strings to distinguish them. Define different soc data according to compatible strings On i.MX95 one instance in nect-mix is supported by this commit, another instance in always-on-mix is not supported, which depends on System Manager function readiness. Signed-off-by: Shengjiu Wang Link: https://msgid.link/r/1716347305-18457-3-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_mqs.c | 46 +++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 60929c36a0e3..c95b84a54dc4 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -28,10 +28,16 @@ #define MQS_CLK_DIV_MASK (0xFF << 0) #define MQS_CLK_DIV_SHIFT (0) +enum reg_type { + TYPE_REG_OWN, /* module own register space */ + TYPE_REG_GPR, /* register in GPR space */ + TYPE_REG_SM, /* System Manager controls the register */ +}; + /** * struct fsl_mqs_soc_data - soc specific data * - * @use_gpr: control register is in General Purpose Register group + * @type: control register space type * @ctrl_off: control register offset * @en_mask: enable bit mask * @en_shift: enable bit shift @@ -43,7 +49,7 @@ * @div_shift: clock divider bit shift */ struct fsl_mqs_soc_data { - bool use_gpr; + enum reg_type type; int ctrl_off; int en_mask; int en_shift; @@ -200,7 +206,7 @@ static int fsl_mqs_probe(struct platform_device *pdev) */ mqs_priv->soc = of_device_get_match_data(&pdev->dev); - if (mqs_priv->soc->use_gpr) { + if (mqs_priv->soc->type == TYPE_REG_GPR) { gpr_np = of_parse_phandle(np, "gpr", 0); if (!gpr_np) { dev_err(&pdev->dev, "failed to get gpr node by phandle\n"); @@ -304,7 +310,7 @@ static const struct dev_pm_ops fsl_mqs_pm_ops = { }; static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = { - .use_gpr = false, + .type = TYPE_REG_OWN, .ctrl_off = REG_MQS_CTRL, .en_mask = MQS_EN_MASK, .en_shift = MQS_EN_SHIFT, @@ -317,7 +323,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = { }; static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = { - .use_gpr = true, + .type = TYPE_REG_GPR, .ctrl_off = IOMUXC_GPR2, .en_mask = IMX6SX_GPR2_MQS_EN_MASK, .en_shift = IMX6SX_GPR2_MQS_EN_SHIFT, @@ -330,7 +336,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = { }; static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = { - .use_gpr = true, + .type = TYPE_REG_GPR, .ctrl_off = 0x20, .en_mask = BIT(1), .en_shift = 1, @@ -342,10 +348,38 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = { .div_shift = 8, }; +static const struct fsl_mqs_soc_data fsl_mqs_imx95_aon_data = { + .type = TYPE_REG_SM, + .ctrl_off = 0x88, + .en_mask = BIT(1), + .en_shift = 1, + .rst_mask = BIT(2), + .rst_shift = 2, + .osr_mask = BIT(3), + .osr_shift = 3, + .div_mask = GENMASK(15, 8), + .div_shift = 8, +}; + +static const struct fsl_mqs_soc_data fsl_mqs_imx95_netc_data = { + .type = TYPE_REG_GPR, + .ctrl_off = 0x0, + .en_mask = BIT(2), + .en_shift = 2, + .rst_mask = BIT(3), + .rst_shift = 3, + .osr_mask = BIT(4), + .osr_shift = 4, + .div_mask = GENMASK(16, 9), + .div_shift = 9, +}; + static const struct of_device_id fsl_mqs_dt_ids[] = { { .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data }, { .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data }, { .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data }, + { .compatible = "fsl,imx95-aonmix-mqs", .data = &fsl_mqs_imx95_aon_data }, + { .compatible = "fsl,imx95-netcmix-mqs", .data = &fsl_mqs_imx95_netc_data }, {} }; MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids); From 10b6ad2b2d8ed07637bd4930f91548c9668ec7df Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 May 2024 14:35:35 -0500 Subject: [PATCH 028/349] ASoC: Intel: sof_sdw_cs42l42: use dai parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dai is passed from the parameter. We don't need to find the dai by name. Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw_cs42l42.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw_cs42l42.c b/sound/soc/intel/boards/sof_sdw_cs42l42.c index fdb75fc71c26..fc18e4aa3dbe 100644 --- a/sound/soc/intel/boards/sof_sdw_cs42l42.c +++ b/sound/soc/intel/boards/sof_sdw_cs42l42.c @@ -36,24 +36,15 @@ static struct snd_soc_jack_pin cs42l42_jack_pins[] = { }, }; -static const char * const jack_codecs[] = { - "cs42l42" -}; - int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai; struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; - codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; + component = dai->component; card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:cs42l42", card->components); From 1bf95876e6e1a3c77637d951cf59fb5c02bd02fa Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 May 2024 14:35:36 -0500 Subject: [PATCH 029/349] ASoC: Intel: sof_sdw_rt711: use dai parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dai is passed from the parameter. We don't need to find the dai by name. Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw_rt711.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c index d49e5aa786c3..60ff4d88e2dc 100644 --- a/sound/soc/intel/boards/sof_sdw_rt711.c +++ b/sound/soc/intel/boards/sof_sdw_rt711.c @@ -59,24 +59,15 @@ static struct snd_soc_jack_pin rt711_jack_pins[] = { }, }; -static const char * const jack_codecs[] = { - "rt711" -}; - int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai; struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; - codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; + component = dai->component; card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:rt711", card->components); From 044413afbcca5da3ac61f2fb829a1fbb0df8ac81 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 May 2024 14:35:37 -0500 Subject: [PATCH 030/349] ASoC: Intel: sof_sdw_rt5682: use dai parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dai is passed from the parameter. We don't need to find the dai by name. Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw_rt5682.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/intel/boards/sof_sdw_rt5682.c index 96f193798540..67737815d016 100644 --- a/sound/soc/intel/boards/sof_sdw_rt5682.c +++ b/sound/soc/intel/boards/sof_sdw_rt5682.c @@ -35,24 +35,15 @@ static struct snd_soc_jack_pin rt5682_jack_pins[] = { }, }; -static const char * const jack_codecs[] = { - "rt5682" -}; - int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai; struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; - codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; + component = dai->component; card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:rt5682", card->components); From b237afe50151e5041d0734c759d5f8dac5c1b694 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 May 2024 14:35:38 -0500 Subject: [PATCH 031/349] ASoC: Intel: sof_sdw_rt700: use dai parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dai is passed from the parameter. We don't need to find the dai by name. Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw_rt700.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/intel/boards/sof_sdw_rt700.c index f9575db9d99c..0db730071be2 100644 --- a/sound/soc/intel/boards/sof_sdw_rt700.c +++ b/sound/soc/intel/boards/sof_sdw_rt700.c @@ -33,24 +33,15 @@ static struct snd_soc_jack_pin rt700_jack_pins[] = { }, }; -static const char * const jack_codecs[] = { - "rt700" -}; - int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai; struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; - codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; + component = dai->component; card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:rt700", card->components); From 06868a46301f4bcb1c9dcd71a291775ff3627a7a Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 May 2024 14:35:39 -0500 Subject: [PATCH 032/349] ASoC: Intel: sof_sdw_rt_dmic: use from dai parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dai is passed from the parameter. We don't need to find the dai by name. Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw_rt_dmic.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw_rt_dmic.c b/sound/soc/intel/boards/sof_sdw_rt_dmic.c index b8b493d5c6ec..ea7c1a4bc566 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_dmic.c +++ b/sound/soc/intel/boards/sof_sdw_rt_dmic.c @@ -12,25 +12,13 @@ #include "sof_board_helpers.h" #include "sof_sdw_common.h" -static const char * const dmics[] = { - "rt715", - "rt715-sdca", - "rt712-sdca-dmic", - "rt722-sdca", -}; - int rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; struct snd_soc_component *component; - struct snd_soc_dai *codec_dai; char *mic_name; - codec_dai = get_codec_dai_by_name(rtd, dmics, ARRAY_SIZE(dmics)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; + component = dai->component; /* * rt715-sdca (aka rt714) is a special case that uses different name in card->components From 3c3e35cec005467f4091907f5ff8c8cbfecc1bf1 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 May 2024 14:35:40 -0500 Subject: [PATCH 033/349] ASoC: Intel: sof_sdw_rt_sdca_jack_common: use dai parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dai is passed from the parameter. We don't need to find the dai by name. Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c index 012195c50519..4254e30ee4c3 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c +++ b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c @@ -74,10 +74,6 @@ static struct snd_soc_jack_pin rt_sdca_jack_pins[] = { }, }; -static const char * const jack_codecs[] = { - "rt711", "rt712", "rt713", "rt722" -}; - /* * The sdca suffix is required for rt711 since there are two generations of the same chip. * RT713 is an SDCA device but the sdca suffix is required for backwards-compatibility with @@ -91,17 +87,12 @@ int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *d { struct snd_soc_card *card = rtd->card; struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai; struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; int i; - codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; + component = dai->component; card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:%s", card->components, component->name_prefix); From a9a7e865b187eadac8f5c253f7f9befca80699f4 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 May 2024 14:35:41 -0500 Subject: [PATCH 034/349] ASoC: Intel: sof_sdw: remove get_codec_dai_by_name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_codec_dai_by_name() is not used anymore. Remove it. Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 18 ------------------ sound/soc/intel/boards/sof_sdw_common.h | 4 ---- 2 files changed, 22 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index e41b0d95e0ff..9dc50a6d5301 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -559,24 +559,6 @@ static const struct snd_kcontrol_new rt700_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), }; -struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd, - const char * const dai_name[], - int num_dais) -{ - struct snd_soc_dai *dai; - int index; - int i; - - for (index = 0; index < num_dais; index++) - for_each_rtd_codec_dais(rtd, i, dai) - if (strstr(dai->name, dai_name[index])) { - dev_dbg(rtd->card->dev, "get dai %s\n", dai->name); - return dai; - } - - return NULL; -} - /* these wrappers are only needed to avoid typecast compilation errors */ int sdw_startup(struct snd_pcm_substream *substream) { diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 3dfba6f6b95d..4e92ff65b537 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -134,10 +134,6 @@ struct mc_private { extern unsigned long sof_sdw_quirk; -struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd, - const char * const dai_name[], - int num_dais); - int sdw_startup(struct snd_pcm_substream *substream); int sdw_prepare(struct snd_pcm_substream *substream); int sdw_trigger(struct snd_pcm_substream *substream, int cmd); From 8a7f876a692c4c7dc7ae845ae400b94df5a6a7c4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 27 May 2024 14:35:42 -0500 Subject: [PATCH 035/349] ASoC: Intel: sof_sdw: Add missing controls for cs42l43/cs35l56 No reason for cs42l43 and cs35l56 not to offer pin switch controls for the headphones and speakers, add these controls. Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 9dc50a6d5301..0516ae660824 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1059,6 +1059,8 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, .init = sof_sdw_cs_amp_init, .rtd_init = cs_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), .widgets = generic_spk_widgets, .num_widgets = ARRAY_SIZE(generic_spk_widgets), }, @@ -1094,6 +1096,8 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_type = SOF_SDW_DAI_TYPE_JACK, .dailink = {SDW_JACK_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, .rtd_init = cs42l43_hs_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), .widgets = generic_jack_widgets, .num_widgets = ARRAY_SIZE(generic_jack_widgets), }, @@ -1119,6 +1123,8 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, .init = sof_sdw_cs42l43_spk_init, .rtd_init = cs42l43_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), .widgets = generic_spk_widgets, .num_widgets = ARRAY_SIZE(generic_spk_widgets), .quirk = SOF_CODEC_SPKR | SOF_SIDECAR_AMPS, From 65ab45b90656e9b7ed51bce27ab7d83618167e76 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 27 May 2024 14:35:43 -0500 Subject: [PATCH 036/349] ASoC: Intel: soc-acpi: Add match entries for some cs42l43 laptops Add some new match table entries on Arrowlake and Raptorlake for some coming cs42l43 laptops. Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-arl-match.c | 50 +++++++++++++++++++ .../intel/common/soc-acpi-intel-rpl-match.c | 50 +++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c index 79d26e0f2c28..cc87c34e5a08 100644 --- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c @@ -15,6 +15,42 @@ static const struct snd_soc_acpi_endpoint single_endpoint = { .group_id = 0, }; +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { + { + .adr = 0x00003001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { .adr = 0x000020025D071100ull, @@ -33,6 +69,14 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { } }; +static const struct snd_soc_acpi_link_adr arl_cs42l43_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, +}; + static const struct snd_soc_acpi_link_adr arl_rvp[] = { { .mask = BIT(0), @@ -58,6 +102,12 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { + { + .link_mask = BIT(0), + .links = arl_cs42l43_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l0.tplg", + }, { .link_mask = 0x1, /* link0 required */ .links = arl_rvp, 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 b0a49e28ab09..bc8817633b81 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -30,6 +30,42 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { + { + .adr = 0x00003001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { .adr = 0x000020025D071100ull, @@ -156,6 +192,14 @@ static const struct snd_soc_acpi_adr_device rt714_3_adr[] = { } }; +static const struct snd_soc_acpi_link_adr rpl_cs42l43_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, +}; + static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = { { .mask = BIT(0), @@ -446,6 +490,12 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = { + { + .link_mask = BIT(0), + .links = rpl_cs42l43_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-rpl-cs42l43-l0.tplg", + }, { .link_mask = 0xF, /* 4 active links required */ .links = rpl_sdca_3_in_1, From 91cdecaba791c74df6da0650e797fe1192cf2700 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 27 May 2024 14:35:44 -0500 Subject: [PATCH 037/349] ASoC: Intel: sof_sdw: Add quirks for some new Dell laptops Add quirks for some new Dell laptops using Cirrus amplifiers in a bridge configuration. Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 0516ae660824..b646b32dd311 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -505,6 +505,22 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(RT711_JD2), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3") + }, + .driver_data = (void *)(SOF_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4") + }, + .driver_data = (void *)(SOF_SIDECAR_AMPS), + }, {} }; From 6073c477d11c1ea4b3f13d9f6e15ca54041af9a3 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 May 2024 14:35:46 -0500 Subject: [PATCH 038/349] ASoC: SOF: sof-audio: rename dai clock setting query function We are going to extend the dai_get_clk() callback function to retrieve other dai-specific settings like tdm slot number, not just mclk/bclk frequencies. Revisit functions and macros related to the callback and replace the string 'clk' with 'param' to reflect the ongoing change. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3-topology.c | 12 ++++++------ sound/soc/sof/ipc4-topology.c | 12 ++++++------ sound/soc/sof/sof-audio.c | 10 +++++----- sound/soc/sof/sof-audio.h | 8 ++++---- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 32c7d1f3b528..b68dea41cd95 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -2500,7 +2500,7 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif return 0; } -static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type) +static int sof_ipc3_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_type) { struct sof_dai_private_data *private = dai->private; @@ -2509,15 +2509,15 @@ static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da switch (private->dai_config->type) { case SOF_DAI_INTEL_SSP: - switch (clk_type) { - case SOF_DAI_CLK_INTEL_SSP_MCLK: + switch (param_type) { + case SOF_DAI_PARAM_INTEL_SSP_MCLK: return private->dai_config->ssp.mclk_rate; - case SOF_DAI_CLK_INTEL_SSP_BCLK: + case SOF_DAI_PARAM_INTEL_SSP_BCLK: return private->dai_config->ssp.bclk_rate; default: + dev_err(sdev->dev, "invalid SSP param %d\n", param_type); break; } - dev_err(sdev->dev, "fail to get SSP clk %d rate\n", clk_type); break; default: /* not yet implemented for platforms other than the above */ @@ -2692,7 +2692,7 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = { .widget_free = sof_ipc3_widget_free, .widget_setup = sof_ipc3_widget_setup, .dai_config = sof_ipc3_dai_config, - .dai_get_clk = sof_ipc3_dai_get_clk, + .dai_get_param = sof_ipc3_dai_get_param, .set_up_all_pipelines = sof_ipc3_set_up_all_pipelines, .tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines, .parse_manifest = sof_ipc3_parse_manifest, diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index beff10989324..67e34fd559f2 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -3130,7 +3130,7 @@ static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, return 0; } -static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type) +static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_type) { struct sof_ipc4_copier *ipc4_copier = dai->private; struct snd_soc_tplg_hw_config *hw_config; @@ -3169,13 +3169,13 @@ static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da switch (ipc4_copier->dai_type) { case SOF_DAI_INTEL_SSP: - switch (clk_type) { - case SOF_DAI_CLK_INTEL_SSP_MCLK: + switch (param_type) { + case SOF_DAI_PARAM_INTEL_SSP_MCLK: return le32_to_cpu(hw_config->mclk_rate); - case SOF_DAI_CLK_INTEL_SSP_BCLK: + case SOF_DAI_PARAM_INTEL_SSP_BCLK: return le32_to_cpu(hw_config->bclk_rate); default: - dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type); + dev_err(sdev->dev, "invalid SSP param %d\n", param_type); break; } break; @@ -3352,7 +3352,7 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = { .route_free = sof_ipc4_route_free, .dai_config = sof_ipc4_dai_config, .parse_manifest = sof_ipc4_parse_manifest, - .dai_get_clk = sof_ipc4_dai_get_clk, + .dai_get_param = sof_ipc4_dai_get_param, .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines, .link_setup = sof_ipc4_link_setup, }; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index b3ac040811e7..2421a115747e 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -978,7 +978,7 @@ struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, return NULL; } -static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type) +static int sof_dai_get_param(struct snd_soc_pcm_runtime *rtd, int param_type) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); @@ -991,8 +991,8 @@ static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type) if (!dai) return 0; - if (tplg_ops && tplg_ops->dai_get_clk) - return tplg_ops->dai_get_clk(sdev, dai, clk_type); + if (tplg_ops && tplg_ops->dai_get_param) + return tplg_ops->dai_get_param(sdev, dai, param_type); return 0; } @@ -1003,7 +1003,7 @@ static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type) */ int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd) { - return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_MCLK); + return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_MCLK); } EXPORT_SYMBOL(sof_dai_get_mclk); @@ -1013,6 +1013,6 @@ EXPORT_SYMBOL(sof_dai_get_mclk); */ int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) { - return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK); + return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_BCLK); } EXPORT_SYMBOL(sof_dai_get_bclk); diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index ec2a3bb644d2..abb2a00c520d 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -44,8 +44,8 @@ #define WIDGET_IS_AIF_OR_DAI(id) (WIDGET_IS_DAI(id) || WIDGET_IS_AIF(id)) #define WIDGET_IS_COPIER(id) (WIDGET_IS_AIF_OR_DAI(id) || (id) == snd_soc_dapm_buffer) -#define SOF_DAI_CLK_INTEL_SSP_MCLK 0 -#define SOF_DAI_CLK_INTEL_SSP_BCLK 1 +#define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 +#define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 enum sof_widget_op { SOF_WIDGET_PREPARE, @@ -208,7 +208,7 @@ struct sof_ipc_tplg_widget_ops { * @widget_setup: Function pointer for setting up setup in the DSP * @widget_free: Function pointer for freeing widget in the DSP * @dai_config: Function pointer for sending DAI config IPC to the DSP - * @dai_get_clk: Function pointer for getting the DAI clock setting + * @dai_get_param: Function pointer for getting the DAI parameter * @set_up_all_pipelines: Function pointer for setting up all topology pipelines * @tear_down_all_pipelines: Function pointer for tearing down all topology pipelines * @parse_manifest: Function pointer for ipc4 specific parsing of topology manifest @@ -229,7 +229,7 @@ struct sof_ipc_tplg_ops { int (*widget_free)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); int (*dai_config)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, unsigned int flags, struct snd_sof_dai_config_data *data); - int (*dai_get_clk)(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type); + int (*dai_get_param)(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_type); int (*set_up_all_pipelines)(struct snd_sof_dev *sdev, bool verify); int (*tear_down_all_pipelines)(struct snd_sof_dev *sdev, bool verify); int (*parse_manifest)(struct snd_soc_component *scomp, int index, From 1deba6e24c221c61c6eab8656a53f8c17035932b Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 May 2024 14:35:47 -0500 Subject: [PATCH 039/349] ASoC: SOF: sof-audio: add sof_dai_get_tdm_slots function An new interface, sof_dai_get_tdm_slots(), is added for machine driver to get tdm slot number from topology. The dai_get_param() callback needs to support new parameter type SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS by returning the tdm slot number of specific SSP port. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof.h | 1 + sound/soc/sof/sof-audio.c | 10 ++++++++++ sound/soc/sof/sof-audio.h | 5 +++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index ec6c30d54592..64fd5504cb2b 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -173,5 +173,6 @@ struct sof_dev_desc { int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd); int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd); +int sof_dai_get_tdm_slots(struct snd_soc_pcm_runtime *rtd); #endif diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 2421a115747e..881eec38c2e2 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -1016,3 +1016,13 @@ int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_BCLK); } EXPORT_SYMBOL(sof_dai_get_bclk); + +/* + * Helper to get SSP TDM slot number from a pcm_runtime. + * Return 0 if not exist. + */ +int sof_dai_get_tdm_slots(struct snd_soc_pcm_runtime *rtd) +{ + return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS); +} +EXPORT_SYMBOL(sof_dai_get_tdm_slots); diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index abb2a00c520d..49be02234fc3 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -44,8 +44,9 @@ #define WIDGET_IS_AIF_OR_DAI(id) (WIDGET_IS_DAI(id) || WIDGET_IS_AIF(id)) #define WIDGET_IS_COPIER(id) (WIDGET_IS_AIF_OR_DAI(id) || (id) == snd_soc_dapm_buffer) -#define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 -#define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 +#define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 +#define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 +#define SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS 2 enum sof_widget_op { SOF_WIDGET_PREPARE, From e495f3ebe967fcc487d84f80ef236e4c0e92c2b6 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 May 2024 14:35:48 -0500 Subject: [PATCH 040/349] ASoC: SOF: ipc3-topology: support tdm slot number query Support the new parameter type SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS in sof_ipc3_dai_get_param() function to get the tdm slot number of specific SSP port. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3-topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index b68dea41cd95..be61e377e59e 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -2514,6 +2514,8 @@ static int sof_ipc3_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai * return private->dai_config->ssp.mclk_rate; case SOF_DAI_PARAM_INTEL_SSP_BCLK: return private->dai_config->ssp.bclk_rate; + case SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS: + return private->dai_config->ssp.tdm_slots; default: dev_err(sdev->dev, "invalid SSP param %d\n", param_type); break; From 97a9e9915cbb43d0feedbe2c9cf117f3dabf1286 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 May 2024 14:35:49 -0500 Subject: [PATCH 041/349] ASoC: SOF: ipc4-topology: support tdm slot number query Support the new parameter type SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS in sof_ipc4_dai_get_param() function to get the tdm slot number of specific SSP port. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 67e34fd559f2..df4344f7d547 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -3174,6 +3174,8 @@ static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai * return le32_to_cpu(hw_config->mclk_rate); case SOF_DAI_PARAM_INTEL_SSP_BCLK: return le32_to_cpu(hw_config->bclk_rate); + case SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS: + return le32_to_cpu(hw_config->tdm_slots); default: dev_err(sdev->dev, "invalid SSP param %d\n", param_type); break; From 459d71f14771211ee19d10a97675f4f08871f58a Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 May 2024 14:35:50 -0500 Subject: [PATCH 042/349] ASoC: Intel: maxim-common: rewrite max_98373_hw_params function Rewrite max_98373_hw_params() function to get tdm slot number from topology in runtime because earlier platforms use 4-slot setting instead of 8. Also check if the interface is configured in TDM mode before calling snd_soc_dai_set_tdm_slot() function. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_maxim_common.c | 84 +++++++++++++++++++---- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 6c40ecc04723..f965b172fa36 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "../common/soc-intel-quirks.h" #include "sof_maxim_common.h" @@ -72,26 +73,85 @@ static struct snd_soc_dai_link_component max_98373_components[] = { }, }; +/* + * According to the definition of 'DAI Sel Mux' mixer in max98373.c, rx mask + * should choose two channels from TDM slots, the LSB of rx mask is left channel + * and the other one is right channel. + * + * For tx mask, each codec requires two channels: one for V-sense and the other + * one for I-sense. Must match the device property "maxim,vmon-slot-no" and + * "maxim,imon-slot-no" in ACPI table. + */ +static const struct { + unsigned int tx; + unsigned int rx; +} max_98373_tdm_mask[] = { + {.tx = 0x03, .rx = 0x3}, + {.tx = 0x0c, .rx = 0x3}, +}; + static int max_98373_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *codec_dai; + int i; + int tdm_slots; int ret = 0; - int j; - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { - /* DEV0 tdm slot configuration */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32); - } else if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { - /* DEV1 tdm slot configuration */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32); + for_each_rtd_codec_dais(rtd, i, codec_dai) { + if (i >= ARRAY_SIZE(max_98373_tdm_mask)) { + dev_err(codec_dai->dev, "only 2 amps are supported\n"); + return -EINVAL; } - if (ret < 0) { - dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", - ret); - return ret; + + switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* get the tplg configured tdm slot number */ + tdm_slots = sof_dai_get_tdm_slots(rtd); + if (tdm_slots <= 0) { + dev_err(rtd->dev, "invalid tdm slots %d\n", + tdm_slots); + return -EINVAL; + } + + /* + * check if tdm slot number is too small for channel + * allocation + */ + if (fls(max_98373_tdm_mask[i].tx) > tdm_slots) { + dev_err(codec_dai->dev, "slot mismatch, tx %d slots %d\n", + fls(max_98373_tdm_mask[i].tx), tdm_slots); + return -EINVAL; + } + + if (fls(max_98373_tdm_mask[i].rx) > tdm_slots) { + dev_err(codec_dai->dev, "slot mismatch, rx %d slots %d\n", + fls(max_98373_tdm_mask[i].rx), tdm_slots); + return -EINVAL; + } + + dev_dbg(codec_dai->dev, "set tdm slot: tx 0x%x rx 0x%x slots %d width %d\n", + max_98373_tdm_mask[i].tx, + max_98373_tdm_mask[i].rx, + tdm_slots, params_width(params)); + + ret = snd_soc_dai_set_tdm_slot(codec_dai, + max_98373_tdm_mask[i].tx, + max_98373_tdm_mask[i].rx, + tdm_slots, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; + } + break; + default: + dev_dbg(codec_dai->dev, "codec is in I2S mode\n"); + break; } } return 0; From 660f029afe9bc4217e600f5616c66b855615b666 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 May 2024 14:35:51 -0500 Subject: [PATCH 043/349] ASoC: Intel: sof_da7219: remove local max98373 ops Since maxim-module could detect tdm slot number in runtime, we could remove local ops and use maxim-module to handle max98373. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-18-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_board_helpers.h | 2 - sound/soc/intel/boards/sof_da7219.c | 44 ---------------------- 2 files changed, 46 deletions(-) diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h index dfcc2c5c25cc..faba847bb7c9 100644 --- a/sound/soc/intel/boards/sof_board_helpers.h +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -86,12 +86,10 @@ enum { /* * sof_da7219_private: private data for da7219 machine driver * - * @is_jsl_board: true for JSL boards * @mclk_en: true for mclk pin is connected * @pll_bypass: true for PLL bypass mode */ struct sof_da7219_private { - bool is_jsl_board; bool mclk_en; bool pll_bypass; }; diff --git a/sound/soc/intel/boards/sof_da7219.c b/sound/soc/intel/boards/sof_da7219.c index 886771e9b9d6..0e3c352a1672 100644 --- a/sound/soc/intel/boards/sof_da7219.c +++ b/sound/soc/intel/boards/sof_da7219.c @@ -178,40 +178,6 @@ static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd) snd_soc_component_set_jack(component, NULL, NULL); } -static int max98373_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream); - int ret, j; - - for (j = 0; j < runtime->dai_link->num_codecs; j++) { - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, j); - - if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { - /* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 3, 4, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { - /* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC, 3, 4, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - } - - return 0; -} - -static const struct snd_soc_ops max98373_ops = { - .hw_params = max98373_hw_params, -}; - static int card_late_probe(struct snd_soc_card *card) { return sof_intel_board_card_late_probe(card); @@ -276,14 +242,6 @@ sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, break; case CODEC_MAX98373: max_98373_dai_link(dev, ctx->amp_link); - - if (ctx->da7219.is_jsl_board) { - ctx->amp_link->ops = &max98373_ops; /* use local ops */ - } else { - /* TBD: implement the amp for later platform */ - dev_err(dev, "max98373 not support yet\n"); - return -EINVAL; - } break; case CODEC_MAX98390: max_98390_dai_link(dev, ctx->amp_link); @@ -388,8 +346,6 @@ static int audio_probe(struct platform_device *pdev) break; } } else if (board_quirk & SOF_DA7219_JSL_BOARD) { - ctx->da7219.is_jsl_board = true; - /* overwrite the DAI link order for JSL boards */ ctx->link_order_overwrite = JSL_LINK_ORDER; From 1085350387056812d19abaf20c59674ce36f0b8c Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 May 2024 14:35:52 -0500 Subject: [PATCH 044/349] ASoC: Intel: sof_da7219: disable max98373 speaker pins in late_probe Commit 94d2d0897474 ("ASoC: Intel: Boards: tgl_max98373: add dai_trigger function") disables speaker pins in late_probe to allow DSP to enter low power state. Add same code to sof_da7219 driver. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-19-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_da7219.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/sof_da7219.c b/sound/soc/intel/boards/sof_da7219.c index 0e3c352a1672..fa1f7d2d8278 100644 --- a/sound/soc/intel/boards/sof_da7219.c +++ b/sound/soc/intel/boards/sof_da7219.c @@ -180,6 +180,19 @@ static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd) static int card_late_probe(struct snd_soc_card *card) { + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_dapm_context *dapm = &card->dapm; + int err; + + if (ctx->amp_type == CODEC_MAX98373) { + /* Disable Left and Right Spk pin after boot */ + snd_soc_dapm_disable_pin(dapm, "Left Spk"); + snd_soc_dapm_disable_pin(dapm, "Right Spk"); + err = snd_soc_dapm_sync(dapm); + if (err < 0) + return err; + } + return sof_intel_board_card_late_probe(card); } From e46e55b8142c2b02972e4a73753fa330a4541315 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 27 May 2024 14:39:36 -0500 Subject: [PATCH 045/349] ASoC: SOF: Intel: hda: print PCI class info only once With the deferred probe mechanism used by the gfx/display subsystem, we see this message repeated for no good reason. Print the information only once. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Link: https://msgid.link/r/20240527193936.165702-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index e6a38de0a0aa..541c6052d4ed 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -783,8 +783,8 @@ int hda_dsp_probe_early(struct snd_sof_dev *sdev) pci->class); return -ENODEV; } - dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n", - pci->class); + dev_info_once(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n", + pci->class); } chip = get_chip_info(sdev->pdata); From 278343bba366d23f8afc99f2d1eb0ab959c32001 Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Sat, 25 May 2024 15:28:05 +0200 Subject: [PATCH 046/349] ASoC: dt-bindings: samsung,midas-audio: Add headset mic bias supply Some devices use a separate mic bias supply (also referred to as "ear mic bias") to enable/disable the headset mic. Add the DT property headset-mic-bias-supply to allow for specifying this supply. Signed-off-by: Artur Weber Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240525-midas-wm1811-gpio-jack-v4-1-f488e03bd8c7@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/samsung,midas-audio.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml index 6ec80f529d84..6ed53dd0bb53 100644 --- a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml @@ -53,6 +53,9 @@ properties: submic-bias-supply: description: Supply for the micbias on the Sub microphone + headset-mic-bias-supply: + description: Supply for the micbias on the Headset microphone + fm-sel-gpios: maxItems: 1 description: GPIO pin for FM selection From 0a590ecc672ae3de56384bbed05a4de532034b8f Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Sat, 25 May 2024 15:28:06 +0200 Subject: [PATCH 047/349] ASoC: dt-bindings: samsung,midas-audio: Add GPIO-based headset jack detection Some Samsung devices that share the midas-audio driver use a GPIO-based approach to headset jack detection, as opposed to using the built-in jack detection provided by the wm8994 driver. This setup uses two GPIOs (one for jack detection and another for key detection) and an ADC channel for determining the jack type or button pressed. Add DT configuration values that allow for describing these setups. Signed-off-by: Artur Weber Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240525-midas-wm1811-gpio-jack-v4-2-f488e03bd8c7@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/samsung,midas-audio.yaml | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml index 6ed53dd0bb53..69ddfd4afdcd 100644 --- a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml @@ -64,6 +64,36 @@ properties: maxItems: 1 description: GPIO pin for line out selection + headset-detect-gpios: + maxItems: 1 + description: GPIO for detection of headset insertion + + headset-key-gpios: + maxItems: 1 + description: GPIO for detection of headset key press + + io-channels: + maxItems: 1 + description: IO channel to read micbias voltage for headset detection + + io-channel-names: + const: headset-detect + + samsung,headset-4pole-threshold-microvolt: + minItems: 2 + maxItems: 2 + description: + Array containing minimum and maximum IO channel value for 4-pole + (with microphone/button) headsets. If the IO channel value is + outside of this range, a 3-pole headset is assumed. + + samsung,headset-button-threshold-microvolt: + minItems: 3 + maxItems: 3 + description: | + Array of minimum (inclusive) IO channel values for headset button + detection, in order: "Media", "Volume Up" and "Volume Down". + required: - compatible - cpu From c6aa3ade499d8ee3374be70c137bd4411fbfdbdd Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Sat, 25 May 2024 15:28:07 +0200 Subject: [PATCH 048/349] ASoC: samsung: midas_wm1811: Use SND_SOC_DAPM_REGULATOR_SUPPLY for bias regulators Instead of using a custom function with the SND_SOC_DAPM_MIC widget, split out the main mic/sub mic bias regulators into a separate widget using SND_SOC_DAPM_REGULATOR_SUPPLY, and connect them via a routing. Signed-off-by: Artur Weber Link: https://msgid.link/r/20240525-midas-wm1811-gpio-jack-v4-3-f488e03bd8c7@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 62 +++++++------------------------- 1 file changed, 13 insertions(+), 49 deletions(-) diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 0841e2e6f8ce..072a4707e9db 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -27,8 +26,6 @@ #define DEFAULT_FLL1_RATE 11289600U struct midas_priv { - struct regulator *reg_mic_bias; - struct regulator *reg_submic_bias; struct gpio_desc *gpio_fm_sel; struct gpio_desc *gpio_lineout_sel; unsigned int fll1_rate; @@ -169,38 +166,6 @@ static int midas_ext_spkmode(struct snd_soc_dapm_widget *w, return ret; } -static int midas_mic_bias(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_card *card = w->dapm->card; - struct midas_priv *priv = snd_soc_card_get_drvdata(card); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - return regulator_enable(priv->reg_mic_bias); - case SND_SOC_DAPM_POST_PMD: - return regulator_disable(priv->reg_mic_bias); - } - - return 0; -} - -static int midas_submic_bias(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_card *card = w->dapm->card; - struct midas_priv *priv = snd_soc_card_get_drvdata(card); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - return regulator_enable(priv->reg_submic_bias); - case SND_SOC_DAPM_POST_PMD: - return regulator_disable(priv->reg_submic_bias); - } - - return 0; -} - static int midas_fm_set(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -272,8 +237,17 @@ static const struct snd_soc_dapm_widget midas_dapm_widgets[] = { 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), + SND_SOC_DAPM_MIC("Main Mic", NULL), + SND_SOC_DAPM_REGULATOR_SUPPLY("mic-bias", 0, 0), + SND_SOC_DAPM_MIC("Sub Mic", NULL), + SND_SOC_DAPM_REGULATOR_SUPPLY("submic-bias", 0, 0), +}; + +/* Default routing; supplemented by audio-routing DT property */ +static const struct snd_soc_dapm_route midas_dapm_routes[] = { + /* Bind microphones with their respective regulator supplies */ + {"Main Mic", NULL, "mic-bias"}, + {"Sub Mic", NULL, "submic-bias"}, }; static int midas_set_bias_level(struct snd_soc_card *card, @@ -421,6 +395,8 @@ static struct snd_soc_card midas_card = { .num_controls = ARRAY_SIZE(midas_controls), .dapm_widgets = midas_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(midas_dapm_widgets), + .dapm_routes = midas_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(midas_dapm_routes), .set_bias_level = midas_set_bias_level, .late_probe = midas_late_probe, @@ -443,18 +419,6 @@ static int midas_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); card->dev = dev; - priv->reg_mic_bias = devm_regulator_get(dev, "mic-bias"); - if (IS_ERR(priv->reg_mic_bias)) { - dev_err(dev, "Failed to get mic bias regulator\n"); - return PTR_ERR(priv->reg_mic_bias); - } - - priv->reg_submic_bias = devm_regulator_get(dev, "submic-bias"); - if (IS_ERR(priv->reg_submic_bias)) { - dev_err(dev, "Failed to get submic bias regulator\n"); - return PTR_ERR(priv->reg_submic_bias); - } - priv->gpio_fm_sel = devm_gpiod_get_optional(dev, "fm-sel", GPIOD_OUT_HIGH); if (IS_ERR(priv->gpio_fm_sel)) { dev_err(dev, "Failed to get FM selection GPIO\n"); From 9da93d4932aa17d5a1342af75872fbba776a3a8d Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Sat, 25 May 2024 15:28:08 +0200 Subject: [PATCH 049/349] ASoC: samsung: midas_wm1811: Add headset mic bias supply support Some devices use a headset mic bias supply (sometimes referred to as "ear mic bias") to enable/disable the headset mic. Add a REGULATOR_SUPPLY widget for this supply which gets the headset- mic-bias supply and is routed to the Headset Mic switch similar to how it's done for the other mic bias regulators. Signed-off-by: Artur Weber Link: https://msgid.link/r/20240525-midas-wm1811-gpio-jack-v4-4-f488e03bd8c7@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 072a4707e9db..4226d9169775 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -237,6 +237,7 @@ static const struct snd_soc_dapm_widget midas_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_REGULATOR_SUPPLY("headset-mic-bias", 0, 0), SND_SOC_DAPM_MIC("Main Mic", NULL), SND_SOC_DAPM_REGULATOR_SUPPLY("mic-bias", 0, 0), SND_SOC_DAPM_MIC("Sub Mic", NULL), @@ -248,6 +249,7 @@ static const struct snd_soc_dapm_route midas_dapm_routes[] = { /* Bind microphones with their respective regulator supplies */ {"Main Mic", NULL, "mic-bias"}, {"Sub Mic", NULL, "submic-bias"}, + {"Headset Mic", NULL, "headset-mic-bias"}, }; static int midas_set_bias_level(struct snd_soc_card *card, From c91d0c2e198d4453e634fe43a72ccbc59811af17 Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Sat, 25 May 2024 15:28:09 +0200 Subject: [PATCH 050/349] ASoC: samsung: midas_wm1811: Add GPIO-based headset jack detection Some Samsung devices that use the midas_wm1811 driver use a GPIO-based method for detecting whether the headset jack is plugged in, as well as detecting which headset buttons are pressed. There are two GPIOs: a "headset detect" GPIO responsible for detecting jack insertion, and a "headset key" GPIO which triggers when a button on the headset is pressed. The plug type and the button pressed are determined based on information from an ADC channel. The headset mic is enabled by a headset mic bias regulator. Add support for the GPIO-based headset jack detection mechanism, and make it configurable from the device tree. This implementation borrows somewhat from the aries_wm8994.c driver, though there are a few changes to make the code cleaner, and to add support for DT-based configuration. Notably, a dependency on IIO is introduced, to accommodate the ADC reading requirement. Signed-off-by: Artur Weber Link: https://msgid.link/r/20240525-midas-wm1811-gpio-jack-v4-5-f488e03bd8c7@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 2 +- sound/soc/samsung/midas_wm1811.c | 274 +++++++++++++++++++++++++++++-- 2 files changed, 264 insertions(+), 12 deletions(-) diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 93c2b1b08d0a..4b1ea7b2c796 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -140,7 +140,7 @@ config SND_SOC_SAMSUNG_ARIES_WM8994 config SND_SOC_SAMSUNG_MIDAS_WM1811 tristate "SoC I2S Audio support for Midas boards" - depends on SND_SOC_SAMSUNG + depends on SND_SOC_SAMSUNG && IIO select SND_SAMSUNG_I2S select SND_SOC_WM8994 help diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 4226d9169775..3a6d3fc8152a 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -7,7 +7,9 @@ #include #include +#include #include +#include #include #include #include @@ -28,6 +30,9 @@ struct midas_priv { struct gpio_desc *gpio_fm_sel; struct gpio_desc *gpio_lineout_sel; + struct gpio_desc *gpio_headset_detect; + struct gpio_desc *gpio_headset_key; + struct iio_channel *adc_headset_detect; unsigned int fll1_rate; struct snd_soc_jack headset_jack; @@ -44,6 +49,117 @@ static struct snd_soc_jack_pin headset_jack_pins[] = { }, }; +/* + * min_mv/max_mv values in this struct are set up based on DT values. + */ +static struct snd_soc_jack_zone headset_jack_zones[] = { + { .jack_type = SND_JACK_HEADPHONE, }, + { .jack_type = SND_JACK_HEADSET, }, + { .jack_type = SND_JACK_HEADPHONE, }, +}; + +/* + * This is used for manual detection in headset_key_check, we reuse the + * structure since it's convenient. + * + * min_mv/max_mv values in this struct are set up based on DT values. + */ +static struct snd_soc_jack_zone headset_key_zones[] = { + { .jack_type = SND_JACK_BTN_0, }, /* Media */ + { .jack_type = SND_JACK_BTN_1, }, /* Volume Up */ + { .jack_type = SND_JACK_BTN_2, }, /* Volume Down */ +}; + +static int headset_jack_check(void *data) +{ + struct snd_soc_component *codec = data; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec); + struct midas_priv *priv = snd_soc_card_get_drvdata(codec->card); + int adc, ret; + int jack_type = 0; + + if (!gpiod_get_value_cansleep(priv->gpio_headset_detect)) + return 0; + + /* Enable headset mic bias regulator so that the ADC reading works */ + ret = snd_soc_dapm_force_enable_pin(dapm, "headset-mic-bias"); + if (ret < 0) { + pr_err("%s: Failed to enable headset mic bias regulator (%d), assuming headphones\n", + __func__, ret); + return SND_JACK_HEADPHONE; + } + snd_soc_dapm_sync(dapm); + + /* Sleep for a small amount of time to get the value to stabilize */ + msleep(20); + + ret = iio_read_channel_processed(priv->adc_headset_detect, &adc); + if (ret) { + pr_err("%s: Failed to read ADC (%d), assuming headphones\n", + __func__, ret); + jack_type = SND_JACK_HEADPHONE; + goto out; + } + pr_debug("%s: ADC value is %d\n", __func__, adc); + + jack_type = snd_soc_jack_get_type(&priv->headset_jack, adc); + +out: + ret = snd_soc_dapm_disable_pin(dapm, "headset-mic-bias"); + if (ret < 0) + pr_err("%s: Failed to disable headset mic bias regulator (%d)\n", + __func__, ret); + snd_soc_dapm_sync(dapm); + + return jack_type; +} + +static int headset_key_check(void *data) +{ + struct snd_soc_component *codec = data; + struct midas_priv *priv = snd_soc_card_get_drvdata(codec->card); + int adc, i, ret; + + if (!gpiod_get_value_cansleep(priv->gpio_headset_key)) + return 0; + + /* Filter out keypresses when 4 pole jack not detected */ + if (!(priv->headset_jack.status & SND_JACK_MICROPHONE)) + return 0; + + ret = iio_read_channel_processed(priv->adc_headset_detect, &adc); + if (ret) { + pr_err("%s: Failed to read ADC (%d), can't detect key type\n", + __func__, ret); + return 0; + } + pr_debug("%s: ADC value is %d\n", __func__, adc); + + for (i = 0; i < ARRAY_SIZE(headset_key_zones); i++) { + if (adc >= headset_key_zones[i].min_mv && + adc <= headset_key_zones[i].max_mv) { + return headset_key_zones[i].jack_type; + } + } + + return 0; +} + +static struct snd_soc_jack_gpio headset_gpio[] = { + { + .name = "Headset Jack", + .report = SND_JACK_HEADSET, + .debounce_time = 150, + .jack_status_check = headset_jack_check, + }, + { + .name = "Headset Key", + .report = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, + .debounce_time = 30, + .jack_status_check = headset_key_check, + }, +}; + static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate) { struct snd_soc_card *card = rtd->card; @@ -291,18 +407,67 @@ static int midas_late_probe(struct snd_soc_card *card) return ret; } - 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; + if (!priv->gpio_headset_detect) { + 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; + + wm8958_mic_detect(aif1_dai->component, &priv->headset_jack, + NULL, NULL, NULL, NULL); + } else { + /* Some devices (n8000, t310) use a GPIO to detect the jack. */ + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2, + &priv->headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); + if (ret) { + dev_err(card->dev, + "Failed to set up headset pins: %d\n", ret); + return ret; + } + + ret = snd_soc_jack_add_zones(&priv->headset_jack, + ARRAY_SIZE(headset_jack_zones), + headset_jack_zones); + if (ret) { + dev_err(card->dev, + "Failed to set up headset zones: %d\n", ret); + return ret; + } + + headset_gpio[0].data = aif1_dai->component; + headset_gpio[0].desc = priv->gpio_headset_detect; + + headset_gpio[1].data = aif1_dai->component; + headset_gpio[1].desc = priv->gpio_headset_key; + + snd_jack_set_key(priv->headset_jack.jack, + SND_JACK_BTN_0, KEY_MEDIA); + snd_jack_set_key(priv->headset_jack.jack, + SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(priv->headset_jack.jack, + SND_JACK_BTN_2, KEY_VOLUMEDOWN); + + ret = snd_soc_jack_add_gpios(&priv->headset_jack, + ARRAY_SIZE(headset_gpio), + headset_gpio); + if (ret) + dev_err(card->dev, + "Failed to set up headset jack GPIOs: %d\n", + ret); + + return ret; + } - wm8958_mic_detect(aif1_dai->component, &priv->headset_jack, - NULL, NULL, NULL, NULL); return 0; } @@ -411,6 +576,9 @@ static int midas_probe(struct platform_device *pdev) struct snd_soc_card *card = &midas_card; struct device *dev = &pdev->dev; static struct snd_soc_dai_link *dai_link; + enum iio_chan_type channel_type; + u32 fourpole_threshold[2]; + u32 button_threshold[3]; struct midas_priv *priv; int ret, i; @@ -434,6 +602,90 @@ static int midas_probe(struct platform_device *pdev) return PTR_ERR(priv->gpio_lineout_sel); } + priv->gpio_headset_detect = devm_gpiod_get_optional(dev, + "headset-detect", GPIOD_IN); + if (IS_ERR(priv->gpio_headset_detect)) + return dev_err_probe(dev, PTR_ERR(priv->gpio_headset_detect), + "Failed to get headset jack detect GPIO\n"); + + if (priv->gpio_headset_detect) { + priv->adc_headset_detect = devm_iio_channel_get(dev, + "headset-detect"); + if (IS_ERR(priv->adc_headset_detect)) + return dev_err_probe(dev, + PTR_ERR(priv->adc_headset_detect), + "Failed to get ADC channel\n"); + + ret = iio_get_channel_type(priv->adc_headset_detect, + &channel_type); + if (ret) { + dev_err(dev, "Failed to get ADC channel type\n"); + return ret; + } + + if (channel_type != IIO_VOLTAGE) { + dev_err(dev, "ADC channel is not voltage\n"); + return ret; + } + + priv->gpio_headset_key = devm_gpiod_get(dev, "headset-key", + GPIOD_IN); + if (IS_ERR(priv->gpio_headset_key)) + return dev_err_probe(dev, + PTR_ERR(priv->gpio_headset_key), + "Failed to get headset key GPIO\n"); + + ret = of_property_read_u32_array(dev->of_node, + "samsung,headset-4pole-threshold-microvolt", + fourpole_threshold, + ARRAY_SIZE(fourpole_threshold)); + if (ret) { + dev_err(dev, "Failed to get 4-pole jack detection threshold\n"); + return ret; + } + + if (fourpole_threshold[0] > fourpole_threshold[1]) { + dev_err(dev, "Invalid 4-pole jack detection threshold value\n"); + return -EINVAL; + } + + headset_jack_zones[0].max_mv = (fourpole_threshold[0]); + headset_jack_zones[1].min_mv = (fourpole_threshold[0] + 1); + + headset_jack_zones[1].max_mv = (fourpole_threshold[1]); + headset_jack_zones[2].min_mv = (fourpole_threshold[1] + 1); + + ret = of_property_read_u32_array(dev->of_node, + "samsung,headset-button-threshold-microvolt", + button_threshold, + ARRAY_SIZE(button_threshold)); + if (ret) { + dev_err(dev, "Failed to get headset button detection threshold\n"); + return ret; + } + + if (button_threshold[0] > button_threshold[1] || + button_threshold[1] > button_threshold[2]) { + dev_err(dev, "Invalid headset button detection threshold value\n"); + return -EINVAL; + } + + for (i = 0; i < 3; i++) { + if (i != 0 && button_threshold[i] <= 0) { + dev_err(dev, "Invalid headset button detection threshold value\n"); + return -EINVAL; + } + + headset_key_zones[i].min_mv = button_threshold[i]; + + if (i == 2) + headset_key_zones[i].max_mv = UINT_MAX; + else + headset_key_zones[i].max_mv = \ + (button_threshold[i+1] - 1); + } + } + ret = snd_soc_of_parse_card_name(card, "model"); if (ret < 0) { dev_err(dev, "Card name is not specified\n"); From 255009d22c185623140de600a5fb54f0fd541bb8 Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Sat, 25 May 2024 15:28:10 +0200 Subject: [PATCH 051/349] ASoC: samsung: midas_wm1811: Use dev_err_probe where appropriate Since we're already using it in the newly-added GPIO requests for jack detection, extend it to the previous checks as well. Signed-off-by: Artur Weber Link: https://msgid.link/r/20240525-midas-wm1811-gpio-jack-v4-6-f488e03bd8c7@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 3a6d3fc8152a..3a269c7de169 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -590,17 +590,15 @@ static int midas_probe(struct platform_device *pdev) card->dev = dev; priv->gpio_fm_sel = devm_gpiod_get_optional(dev, "fm-sel", GPIOD_OUT_HIGH); - if (IS_ERR(priv->gpio_fm_sel)) { - dev_err(dev, "Failed to get FM selection GPIO\n"); - return PTR_ERR(priv->gpio_fm_sel); - } + if (IS_ERR(priv->gpio_fm_sel)) + return dev_err_probe(dev, PTR_ERR(priv->gpio_fm_sel), + "Failed to get FM selection GPIO\n"); priv->gpio_lineout_sel = devm_gpiod_get_optional(dev, "lineout-sel", GPIOD_OUT_HIGH); - if (IS_ERR(priv->gpio_lineout_sel)) { - dev_err(dev, "Failed to get line out selection GPIO\n"); - return PTR_ERR(priv->gpio_lineout_sel); - } + if (IS_ERR(priv->gpio_lineout_sel)) + return dev_err_probe(dev, PTR_ERR(priv->gpio_lineout_sel), + "Failed to get line out selection GPIO\n"); priv->gpio_headset_detect = devm_gpiod_get_optional(dev, "headset-detect", GPIOD_IN); From 34864c05a54d1bc544c8c3939aababbc481d99e3 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 29 May 2024 12:14:50 -0700 Subject: [PATCH 052/349] ASoC: Intel: avs: es8336: Switch to new Intel CPU model defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New CPU #defines encode vendor and family as well as model. Signed-off-by: Tony Luck Reviewed-by: Amadeusz Sławiński Acked-by: Mark Brown Link: https://msgid.link/r/20240529191450.63414-1-tony.luck@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/es8336.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index 3bf37a8fd6e6..c8522e2430f8 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include "../utils.h" #define ES8336_CODEC_DAI "ES8316 HiFi" @@ -153,9 +153,9 @@ static int avs_es8336_hw_params(struct snd_pcm_substream *substream, int clk_freq; int ret; - switch (boot_cpu_data.x86_model) { - case INTEL_FAM6_KABYLAKE_L: - case INTEL_FAM6_KABYLAKE: + switch (boot_cpu_data.x86_vfm) { + case INTEL_KABYLAKE_L: + case INTEL_KABYLAKE: clk_freq = 24000000; break; default: From 44e55f9de9950dba091401898a931fc1a3a99146 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Sat, 1 Jun 2024 23:54:44 +0100 Subject: [PATCH 053/349] ASoC: codecs: lpass-rx-macro: remove unused struct 'rx_macro_reg_mask_val' 'rx_macro_reg_mask_val' is unused since the original commit af3d54b99764 ("ASoC: codecs: lpass-rx-macro: add support for lpass rx macro"). Remove it. Signed-off-by: Dr. David Alan Gilbert Link: https://msgid.link/r/20240601225446.183505-2-linux@treblig.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index f35187d69cac..dfb7e4c69683 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -463,12 +463,6 @@ static const struct comp_coeff_val comp_coeff_table[HPH_MODE_MAX][COMP_MAX_COEFF }, }; -struct rx_macro_reg_mask_val { - u16 reg; - u8 mask; - u8 val; -}; - enum { INTERP_HPHL, INTERP_HPHR, From 62ccbe8cbe2a1b6911ec47bea8b1510dc1f82dd5 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Sat, 1 Jun 2024 23:54:45 +0100 Subject: [PATCH 054/349] ASoC: codecs: wm0010: remove unused struct 'wm0010_spi_msg' 'wm0010_spi_msg' has been unused since the original commit e3523e01869d ("ASoC: wm0010: Add initial wm0010 DSP driver"). Remove it. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Charles Keepax Link: https://msgid.link/r/20240601225446.183505-3-linux@treblig.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm0010.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 8f862729a2ca..edd2cb185c42 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -115,14 +115,6 @@ struct wm0010_priv { struct completion boot_completion; }; -struct wm0010_spi_msg { - struct spi_message m; - struct spi_transfer t; - u8 *tx_buf; - u8 *rx_buf; - size_t len; -}; - static const struct snd_soc_dapm_widget wm0010_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("CLKIN", SND_SOC_NOPM, 0, 0, NULL, 0), }; From 8080dde80a2d3657529c2172471c06cfcd9a228e Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Sat, 1 Jun 2024 23:54:46 +0100 Subject: [PATCH 055/349] ASoC: codecs: cx2072x: remove unused struct 'cx2072x_eq_ctrl' 'cx2072x_eq_ctrl' has been unused since the original commit a497a4363706 ("ASoC: Add support for Conexant CX2072X CODEC"). Remove it. Signed-off-by: Dr. David Alan Gilbert Link: https://msgid.link/r/20240601225446.183505-4-linux@treblig.org Signed-off-by: Mark Brown --- sound/soc/codecs/cx2072x.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index e8e22b1a1963..8cfec8dcf839 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -63,11 +63,6 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7400, 100, 0); static const DECLARE_TLV_DB_SCALE(dac_tlv, -7400, 100, 0); static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 1200, 0); -struct cx2072x_eq_ctrl { - u8 ch; - u8 band; -}; - static const DECLARE_TLV_DB_RANGE(hpf_tlv, 0, 0, TLV_DB_SCALE_ITEM(120, 0, 0), 1, 63, TLV_DB_SCALE_ITEM(30, 30, 0) From 45919c28134519080a85a5fb66d0f65955ef7572 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:14 +0000 Subject: [PATCH 056/349] ASoC: simple-card-utils: remove both playback/capture_only check soc-pcm.c :: soc_get_playback_capture() will indicate error if both playback_only / capture_only were true. Thus, graph_util_parse_link_direction() which setup playback_only / capture_only don't need to check it. And, its return value is not used on existing driver. Let's remove it. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/87a5kah6gm.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 +- sound/soc/generic/simple-card-utils.c | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 2c2279d082ec..0a6435ac5c5f 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -197,7 +197,7 @@ int graph_util_is_ports0(struct device_node *port); int graph_util_parse_dai(struct device *dev, struct device_node *ep, struct snd_soc_dai_link_component *dlc, int *is_single_link); -int graph_util_parse_link_direction(struct device_node *np, +void graph_util_parse_link_direction(struct device_node *np, bool *is_playback_only, bool *is_capture_only); #ifdef DEBUG diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 852989611362..bc4d518c35cb 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -1140,7 +1140,7 @@ parse_dai_end: } EXPORT_SYMBOL_GPL(graph_util_parse_dai); -int graph_util_parse_link_direction(struct device_node *np, +void graph_util_parse_link_direction(struct device_node *np, bool *playback_only, bool *capture_only) { bool is_playback_only = false; @@ -1149,13 +1149,8 @@ int graph_util_parse_link_direction(struct device_node *np, is_playback_only = of_property_read_bool(np, "playback-only"); is_capture_only = of_property_read_bool(np, "capture-only"); - if (is_playback_only && is_capture_only) - return -EINVAL; - *playback_only = is_playback_only; *capture_only = is_capture_only; - - return 0; } EXPORT_SYMBOL_GPL(graph_util_parse_link_direction); From 72999a1b6663f1ff604e79aea54f168f78e2441a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:20 +0000 Subject: [PATCH 057/349] ASoC: audio-graph-card2: add ep_to_port() / port_to_ports() Current audio-graph-card2 is using of_get_parent() to get "port" from "ep", or get "ports" from "port". But it is difficlut to understand, and "ports" might not exist. This patch adds ep_to_port() to get "port" from "ep", and port_to_ports() to get "ports" from "port". "ports" will be NULL if not exist. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/878qzuh6gf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 46 +++++++++++++++++---------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 81e84095107e..58123fbc2904 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -236,6 +236,18 @@ enum graph_type { #define port_to_endpoint(port) of_get_child_by_name(port, "endpoint") +#define ep_to_port(ep) of_get_parent(ep) +static struct device_node *port_to_ports(struct device_node *port) +{ + struct device_node *ports = of_get_parent(port); + + if (!of_node_name_eq(ports, "ports")) { + of_node_put(ports); + return NULL; + } + return ports; +} + static enum graph_type __graph_get_type(struct device_node *lnk) { struct device_node *np, *parent_np; @@ -320,7 +332,7 @@ static int graph_lnk_is_multi(struct device_node *lnk) static struct device_node *graph_get_next_multi_ep(struct device_node **port) { - struct device_node *ports = of_get_parent(*port); + struct device_node *ports = port_to_ports(*port); struct device_node *ep = NULL; struct device_node *rep = NULL; @@ -365,8 +377,8 @@ static const struct snd_soc_ops graph_ops = { static void graph_parse_convert(struct device_node *ep, struct simple_dai_props *props) { - struct device_node *port = of_get_parent(ep); - struct device_node *ports = of_get_parent(port); + struct device_node *port = ep_to_port(ep); + struct device_node *ports = port_to_ports(port); struct simple_util_data *adata = &props->adata; if (of_node_name_eq(ports, "ports")) @@ -381,8 +393,8 @@ static void graph_parse_convert(struct device_node *ep, static void graph_parse_mclk_fs(struct device_node *ep, struct simple_dai_props *props) { - struct device_node *port = of_get_parent(ep); - struct device_node *ports = of_get_parent(port); + struct device_node *port = ep_to_port(ep); + struct device_node *ports = port_to_ports(port); if (of_node_name_eq(ports, "ports")) of_property_read_u32(ports, "mclk-fs", &props->mclk_fs); @@ -481,8 +493,8 @@ static int __graph_parse_node(struct simple_util_priv *priv, if (!is_cpu && gtype == GRAPH_DPCM) { struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, idx); struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, idx); - struct device_node *rport = of_get_parent(ep); - struct device_node *rports = of_get_parent(rport); + struct device_node *rport = ep_to_port(ep); + struct device_node *rports = port_to_ports(rport); if (of_node_name_eq(rports, "ports")) snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix"); @@ -539,11 +551,11 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, */ struct device_node *mcpu_ep = port_to_endpoint(mcpu_port); struct device_node *mcpu_ep_n = mcpu_ep; - struct device_node *mcpu_port_top = of_get_next_child(of_get_parent(mcpu_port), NULL); + struct device_node *mcpu_port_top = of_get_next_child(port_to_ports(mcpu_port), NULL); struct device_node *mcpu_ep_top = port_to_endpoint(mcpu_port_top); struct device_node *mcodec_ep_top = of_graph_get_remote_endpoint(mcpu_ep_top); - struct device_node *mcodec_port_top = of_get_parent(mcodec_ep_top); - struct device_node *mcodec_ports = of_get_parent(mcodec_port_top); + struct device_node *mcodec_port_top = ep_to_port(mcodec_ep_top); + struct device_node *mcodec_ports = port_to_ports(mcodec_port_top); int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); int ret = -EINVAL; @@ -566,9 +578,9 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, } mcodec_ep_n = of_graph_get_remote_endpoint(mcpu_ep_n); - mcodec_port = of_get_parent(mcodec_ep_n); + mcodec_port = ep_to_port(mcodec_ep_n); - if (mcodec_ports != of_get_parent(mcodec_port)) + if (mcodec_ports != port_to_ports(mcodec_port)) goto mcpu_err; codec_idx = 0; @@ -765,12 +777,12 @@ static void graph_link_init(struct simple_util_priv *priv, if (graph_lnk_is_multi(port)) { of_node_get(port); ep = graph_get_next_multi_ep(&port); - port = of_get_parent(ep); + port = ep_to_port(ep); } else { ep = port_to_endpoint(port); } - ports = of_get_parent(port); + ports = port_to_ports(port); /* * ports { @@ -966,7 +978,7 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv, */ of_node_get(lnk); port0 = lnk; - ports = of_get_parent(port0); + ports = port_to_ports(port0); port1 = of_get_next_child(ports, lnk); /* @@ -1098,7 +1110,7 @@ static int graph_counter(struct device_node *lnk) * ignore first lnk part */ if (graph_lnk_is_multi(lnk)) { - struct device_node *ports = of_get_parent(lnk); + struct device_node *ports = port_to_ports(lnk); struct device_node *port = NULL; int cnt = 0; @@ -1195,7 +1207,7 @@ static int graph_count_c2c(struct simple_util_priv *priv, struct device_node *lnk, struct link_info *li) { - struct device_node *ports = of_get_parent(lnk); + struct device_node *ports = port_to_ports(lnk); struct device_node *port0 = lnk; struct device_node *port1 = of_get_next_child(ports, of_node_get(lnk)); struct device_node *ep0 = port_to_endpoint(port0); From 33ae57277ce08b83c65c18a09bf09499de613c01 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:24 +0000 Subject: [PATCH 058/349] ASoC: audio-graph-card2: remove ports node name check Current audio-graph-card2 is checking if the node name was "ports" or not when parsing the property. if (of_node_name_eq(ports, "ports")) of_xxx(ports, ...); Now, it is using new port_to_ports() which will be NULL if the node doesn't have "ports", and each of_xxx functions will do nothing if node was NULL. Now we don't need to check ports node name. Let's remove and cleanup it. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/877cfeh6gb.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 15 +++++++-------- sound/soc/generic/simple-card-utils.c | 3 +++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 58123fbc2904..3029e8ebfa22 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -381,8 +381,7 @@ static void graph_parse_convert(struct device_node *ep, struct device_node *ports = port_to_ports(port); struct simple_util_data *adata = &props->adata; - if (of_node_name_eq(ports, "ports")) - simple_util_parse_convert(ports, NULL, adata); + simple_util_parse_convert(ports, NULL, adata); simple_util_parse_convert(port, NULL, adata); simple_util_parse_convert(ep, NULL, adata); @@ -396,8 +395,7 @@ static void graph_parse_mclk_fs(struct device_node *ep, struct device_node *port = ep_to_port(ep); struct device_node *ports = port_to_ports(port); - if (of_node_name_eq(ports, "ports")) - of_property_read_u32(ports, "mclk-fs", &props->mclk_fs); + of_property_read_u32(ports, "mclk-fs", &props->mclk_fs); of_property_read_u32(port, "mclk-fs", &props->mclk_fs); of_property_read_u32(ep, "mclk-fs", &props->mclk_fs); @@ -496,8 +494,7 @@ static int __graph_parse_node(struct simple_util_priv *priv, struct device_node *rport = ep_to_port(ep); struct device_node *rports = port_to_ports(rport); - if (of_node_name_eq(rports, "ports")) - snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix"); + snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix"); snd_soc_of_parse_node_prefix(rport, cconf, codecs->of_node, "prefix"); of_node_put(rport); @@ -717,6 +714,9 @@ static void graph_parse_daifmt(struct device_node *node, { unsigned int fmt; + if (!node) + return; + /* * see also above "daifmt" explanation * and samples. @@ -798,8 +798,7 @@ static void graph_link_init(struct simple_util_priv *priv, */ graph_parse_daifmt(ep, &daifmt, &bit_frame); /* (C) */ graph_parse_daifmt(port, &daifmt, &bit_frame); /* (B) */ - if (of_node_name_eq(ports, "ports")) - graph_parse_daifmt(ports, &daifmt, &bit_frame); /* (A) */ + graph_parse_daifmt(ports, &daifmt, &bit_frame); /* (A) */ /* * convert bit_frame diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index bc4d518c35cb..a655f20428af 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -60,6 +60,9 @@ void simple_util_parse_convert(struct device_node *np, { char prop[128]; + if (!np) + return; + if (!prefix) prefix = ""; From 844de7eebe97a1c277f8a408457712086c957195 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:28 +0000 Subject: [PATCH 059/349] ASoC: audio-graph-card2: expand dai_link property part Current dai_link related property are parsed and enabled only on CPU port node (A)(b)(c). OTOH, Audio Graph Card2 supports many connections like Multi-CPU, DPCM, Codec2Codec today. For example in Multi-CPU case, it will be checked via (X) -> (B) -> (b) process, but (X) / (B) part property is not parsed. >From dai_link related settings point of view, (B) (C) part and Codec port also enabled is more viscerally understandable, and useful. card2 { (X) links = <&snd-cpu (A) &snd-multi (B) &snd-dpcm (C) ...> multi { ports { (B) snd-multi: port { ... }; ... }; }; dpcm { ports { (C) snd-dpcm: port { ... }; ... }; }; codec2codec { ... }; }; cpu_device { ports { (A) snd-cpu: port { ... }; (b) mcpu: port { ... }; (c) dcpu: port { ... }; } }; One note here is that if it was Multi-CPU/Codec case, 1st port only enabled to have property it. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/875xuyh6g7.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 95 +++++++++++++++++---------- sound/soc/generic/simple-card-utils.c | 13 ++-- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 3029e8ebfa22..bd714a6f74e6 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -763,42 +763,55 @@ static void graph_parse_daifmt(struct device_node *node, } static void graph_link_init(struct simple_util_priv *priv, - struct device_node *port, + struct device_node *lnk, + struct device_node *port_cpu, + struct device_node *port_codec, struct link_info *li, int is_cpu_node) { struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); - struct device_node *ep; - struct device_node *ports; + struct device_node *ep_cpu, *ep_codec; + struct device_node *ports_cpu, *ports_codec; unsigned int daifmt = 0, daiclk = 0; bool playback_only = 0, capture_only = 0; unsigned int bit_frame = 0; - if (graph_lnk_is_multi(port)) { - of_node_get(port); - ep = graph_get_next_multi_ep(&port); - port = ep_to_port(ep); + of_node_get(port_cpu); + if (graph_lnk_is_multi(port_cpu)) { + ep_cpu = graph_get_next_multi_ep(&port_cpu); + of_node_put(port_cpu); + port_cpu = ep_to_port(ep_cpu); } else { - ep = port_to_endpoint(port); + ep_cpu = port_to_endpoint(port_cpu); } + ports_cpu = port_to_ports(port_cpu); - ports = port_to_ports(port); + of_node_get(port_codec); + if (graph_lnk_is_multi(port_codec)) { + ep_codec = graph_get_next_multi_ep(&port_codec); + of_node_put(port_cpu); + port_codec = ep_to_port(ep_codec); + } else { + ep_codec = port_to_endpoint(port_codec); + } + ports_codec = port_to_ports(port_codec); - /* - * ports { - * (A) - * port { - * (B) - * endpoint { - * (C) - * }; - * }; - * }; - * }; - */ - graph_parse_daifmt(ep, &daifmt, &bit_frame); /* (C) */ - graph_parse_daifmt(port, &daifmt, &bit_frame); /* (B) */ - graph_parse_daifmt(ports, &daifmt, &bit_frame); /* (A) */ + + graph_parse_daifmt(ep_cpu, &daifmt, &bit_frame); + graph_parse_daifmt(ep_codec, &daifmt, &bit_frame); + graph_parse_daifmt(port_cpu, &daifmt, &bit_frame); + graph_parse_daifmt(port_codec, &daifmt, &bit_frame); + graph_parse_daifmt(ports_cpu, &daifmt, &bit_frame); + graph_parse_daifmt(ports_codec, &daifmt, &bit_frame); + graph_parse_daifmt(lnk, &daifmt, &bit_frame); + + graph_util_parse_link_direction(lnk, &playback_only, &capture_only); + graph_util_parse_link_direction(ports_cpu, &playback_only, &capture_only); + graph_util_parse_link_direction(ports_codec, &playback_only, &capture_only); + graph_util_parse_link_direction(port_cpu, &playback_only, &capture_only); + graph_util_parse_link_direction(port_codec, &playback_only, &capture_only); + graph_util_parse_link_direction(ep_cpu, &playback_only, &capture_only); + graph_util_parse_link_direction(ep_codec, &playback_only, &capture_only); /* * convert bit_frame @@ -809,16 +822,21 @@ static void graph_link_init(struct simple_util_priv *priv, if (is_cpu_node) daiclk = snd_soc_daifmt_clock_provider_flipped(daiclk); - graph_util_parse_link_direction(port, &playback_only, &capture_only); - - dai_link->playback_only = playback_only; - dai_link->capture_only = capture_only; + dai_link->playback_only = playback_only; + dai_link->capture_only = capture_only; dai_link->dai_fmt = daifmt | daiclk; dai_link->init = simple_util_dai_init; dai_link->ops = &graph_ops; if (priv->ops) dai_link->ops = priv->ops; + + of_node_put(ports_cpu); + of_node_put(ports_codec); + of_node_put(port_cpu); + of_node_put(port_codec); + of_node_put(ep_cpu); + of_node_put(ep_codec); } int audio_graph2_link_normal(struct simple_util_priv *priv, @@ -846,7 +864,7 @@ int audio_graph2_link_normal(struct simple_util_priv *priv, if (ret < 0) goto err; - graph_link_init(priv, cpu_port, li, 1); + graph_link_init(priv, lnk, cpu_port, codec_port, li, 1); err: of_node_put(codec_port); of_node_put(cpu_ep); @@ -861,13 +879,16 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv, { struct device_node *ep = port_to_endpoint(lnk); struct device_node *rep = of_graph_get_remote_endpoint(ep); - struct device_node *rport = of_graph_get_remote_port(ep); + struct device_node *cpu_port = NULL; + struct device_node *codec_port = NULL; struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); int is_cpu = graph_util_is_ports0(lnk); int ret; if (is_cpu) { + cpu_port = of_graph_get_remote_port(ep); /* rport */ + /* * dpcm { * // Front-End @@ -895,10 +916,13 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv, dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; - ret = graph_parse_node(priv, GRAPH_DPCM, rport, li, 1); + ret = graph_parse_node(priv, GRAPH_DPCM, cpu_port, li, 1); if (ret) goto err; + } else { + codec_port = of_graph_get_remote_port(ep); /* rport */ + /* * dpcm { * // Front-End @@ -928,7 +952,7 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = simple_util_be_hw_params_fixup; - ret = graph_parse_node(priv, GRAPH_DPCM, rport, li, 0); + ret = graph_parse_node(priv, GRAPH_DPCM, codec_port, li, 0); if (ret < 0) goto err; } @@ -938,11 +962,12 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv, snd_soc_dai_link_set_capabilities(dai_link); - graph_link_init(priv, rport, li, is_cpu); + graph_link_init(priv, lnk, cpu_port, codec_port, li, is_cpu); err: of_node_put(ep); of_node_put(rep); - of_node_put(rport); + of_node_put(cpu_port); + of_node_put(codec_port); return ret; } @@ -1030,7 +1055,7 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv, if (ret < 0) goto err2; - graph_link_init(priv, codec0_port, li, 1); + graph_link_init(priv, lnk, codec0_port, codec1_port, li, 1); err2: of_node_put(ep0); of_node_put(ep1); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index a655f20428af..dcd0569157ce 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -1146,14 +1146,13 @@ EXPORT_SYMBOL_GPL(graph_util_parse_dai); void graph_util_parse_link_direction(struct device_node *np, bool *playback_only, bool *capture_only) { - bool is_playback_only = false; - bool is_capture_only = false; + bool is_playback_only = of_property_read_bool(np, "playback-only"); + bool is_capture_only = of_property_read_bool(np, "capture-only"); - is_playback_only = of_property_read_bool(np, "playback-only"); - is_capture_only = of_property_read_bool(np, "capture-only"); - - *playback_only = is_playback_only; - *capture_only = is_capture_only; + if (is_playback_only) + *playback_only = is_playback_only; + if (is_capture_only) + *capture_only = is_capture_only; } EXPORT_SYMBOL_GPL(graph_util_parse_link_direction); From f2d7e85962baf410b1bbbb4cf23a1ca59261ef76 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:32 +0000 Subject: [PATCH 060/349] ASoC: audio-graph-card2: merge graph_parse_mclk_fs() into graph_link_init() Now graph_link_init() is parsing dai_link related property. Let's handle mclk_fs on it, too. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/874jaih6g3.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index bd714a6f74e6..8eea81888758 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -389,20 +389,6 @@ static void graph_parse_convert(struct device_node *ep, of_node_put(ports); } -static void graph_parse_mclk_fs(struct device_node *ep, - struct simple_dai_props *props) -{ - struct device_node *port = ep_to_port(ep); - struct device_node *ports = port_to_ports(port); - - of_property_read_u32(ports, "mclk-fs", &props->mclk_fs); - of_property_read_u32(port, "mclk-fs", &props->mclk_fs); - of_property_read_u32(ep, "mclk-fs", &props->mclk_fs); - - of_node_put(port); - of_node_put(ports); -} - static int __graph_parse_node(struct simple_util_priv *priv, enum graph_type gtype, struct device_node *ep, @@ -424,8 +410,6 @@ static int __graph_parse_node(struct simple_util_priv *priv, dai = simple_props_to_dai_codec(dai_props, idx); } - graph_parse_mclk_fs(ep, dai_props); - ret = graph_util_parse_dai(dev, ep, dlc, &is_single_links); if (ret < 0) return ret; @@ -770,6 +754,7 @@ static void graph_link_init(struct simple_util_priv *priv, int is_cpu_node) { struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *ep_cpu, *ep_codec; struct device_node *ports_cpu, *ports_codec; unsigned int daifmt = 0, daiclk = 0; @@ -813,6 +798,14 @@ static void graph_link_init(struct simple_util_priv *priv, graph_util_parse_link_direction(ep_cpu, &playback_only, &capture_only); graph_util_parse_link_direction(ep_codec, &playback_only, &capture_only); + of_property_read_u32(lnk, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(ports_cpu, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(ports_codec, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(port_cpu, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(port_codec, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs); + /* * convert bit_frame * We need to flip clock_provider if it was CPU node, From df23fcd56bb75ab522350bd8cb52bde9067aea45 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:36 +0000 Subject: [PATCH 061/349] ASoC: audio-graph-card: add ep_to_port() / port_to_ports() Current audio-graph-card is using of_get_parent() to get "port" from "ep", or get "ports" from "port". But it is difficlut to understand, and "ports" might not exist. This patch adds ep_to_port() to get "port" from "ep", and port_to_ports() to get "ports" from "port". "ports" will be NULL if not exist. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/8734q2h6fz.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 83e3ba773fbd..552b94908cf7 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -19,6 +19,18 @@ #define DPCM_SELECTABLE 1 +#define ep_to_port(ep) of_get_parent(ep) +static struct device_node *port_to_ports(struct device_node *port) +{ + struct device_node *ports = of_get_parent(port); + + if (!of_node_name_eq(ports, "ports")) { + of_node_put(ports); + return NULL; + } + return ports; +} + static int graph_outdrv_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -68,8 +80,8 @@ static void graph_parse_convert(struct device *dev, struct simple_util_data *adata) { struct device_node *top = dev->of_node; - struct device_node *port = of_get_parent(ep); - struct device_node *ports = of_get_parent(port); + struct device_node *port = ep_to_port(ep); + struct device_node *ports = port_to_ports(port); struct device_node *node = of_graph_get_port_parent(ep); simple_util_parse_convert(top, NULL, adata); @@ -87,8 +99,8 @@ static void graph_parse_mclk_fs(struct device_node *top, struct device_node *ep, struct simple_dai_props *props) { - struct device_node *port = of_get_parent(ep); - struct device_node *ports = of_get_parent(port); + struct device_node *port = ep_to_port(ep); + struct device_node *ports = port_to_ports(port); of_property_read_u32(top, "mclk-fs", &props->mclk_fs); if (of_node_name_eq(ports, "ports")) @@ -231,8 +243,8 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, "be.%pOFP.%s", codecs->of_node, codecs->dai_name); /* check "prefix" from top node */ - port = of_get_parent(ep); - ports = of_get_parent(port); + port = ep_to_port(ep); + ports = port_to_ports(port); snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, "prefix"); if (of_node_name_eq(ports, "ports")) @@ -350,7 +362,7 @@ static int __graph_for_each_link(struct simple_util_priv *priv, /* get codec */ codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_get_parent(codec_ep); + codec_port = ep_to_port(codec_ep); /* get convert-xxx property */ memset(&adata, 0, sizeof(adata)); From 84c9601a92b755f869ac811607402e5b2162c225 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:40 +0000 Subject: [PATCH 062/349] ASoC: audio-graph-card: remove ports node name check Current audio-graph-card is checking if the node name was "ports" or not when parsing the property. if (of_node_name_eq(ports, "ports")) of_xxx(ports, ...); Now, it is using new port_to_ports() which will be NULL if the node doesn't have "ports", and each of_xxx functions will do nothing if node was NULL. Now we don't need to check ports node name. Let's remove and cleanup it. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/871q5mh6fv.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 552b94908cf7..c60f00146859 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -85,8 +85,7 @@ static void graph_parse_convert(struct device *dev, struct device_node *node = of_graph_get_port_parent(ep); simple_util_parse_convert(top, NULL, adata); - if (of_node_name_eq(ports, "ports")) - simple_util_parse_convert(ports, NULL, adata); + simple_util_parse_convert(ports, NULL, adata); simple_util_parse_convert(port, NULL, adata); simple_util_parse_convert(ep, NULL, adata); @@ -103,8 +102,7 @@ static void graph_parse_mclk_fs(struct device_node *top, struct device_node *ports = port_to_ports(port); of_property_read_u32(top, "mclk-fs", &props->mclk_fs); - if (of_node_name_eq(ports, "ports")) - of_property_read_u32(ports, "mclk-fs", &props->mclk_fs); + of_property_read_u32(ports, "mclk-fs", &props->mclk_fs); of_property_read_u32(port, "mclk-fs", &props->mclk_fs); of_property_read_u32(ep, "mclk-fs", &props->mclk_fs); @@ -245,12 +243,9 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, /* check "prefix" from top node */ port = ep_to_port(ep); ports = port_to_ports(port); - snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, - "prefix"); - if (of_node_name_eq(ports, "ports")) - snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix"); - snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, - "prefix"); + snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, "prefix"); + snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix"); + snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, "prefix"); of_node_put(ports); of_node_put(port); From f23bac6e6913eed9eb831b4893255ea862d40ea5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:44 +0000 Subject: [PATCH 063/349] ASoC: audio-graph-card: enable playback/capture_only property Audio Graph Card2 is supporting playback/capture_only property, let's follow Audio Graph Card, too. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/87zfsafrvb.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index c60f00146859..6a19e40d2c4a 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -149,26 +149,44 @@ static int graph_parse_node(struct simple_util_priv *priv, } static int graph_link_init(struct simple_util_priv *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, + struct device_node *ep_cpu, + struct device_node *ep_codec, struct link_info *li, char *name) { struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct device_node *port_cpu = ep_to_port(ep_cpu); + struct device_node *port_codec = ep_to_port(ep_codec); + bool playback_only = 0, capture_only = 0; int ret; - ret = simple_util_parse_daifmt(dev, cpu_ep, codec_ep, + ret = simple_util_parse_daifmt(dev, ep_cpu, ep_codec, NULL, &dai_link->dai_fmt); if (ret < 0) - return ret; + goto init_end; + + graph_util_parse_link_direction(top, &playback_only, &capture_only); + graph_util_parse_link_direction(port_cpu, &playback_only, &capture_only); + graph_util_parse_link_direction(port_codec, &playback_only, &capture_only); + graph_util_parse_link_direction(ep_cpu, &playback_only, &capture_only); + graph_util_parse_link_direction(ep_codec, &playback_only, &capture_only); + + dai_link->playback_only = playback_only; + dai_link->capture_only = capture_only; dai_link->init = simple_util_dai_init; dai_link->ops = &graph_ops; if (priv->ops) dai_link->ops = priv->ops; - return simple_util_set_dailink_name(dev, dai_link, name); + ret = simple_util_set_dailink_name(dev, dai_link, name); +init_end: + of_node_put(port_cpu); + of_node_put(port_codec); + + return ret; } static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, From a0174c88386b48bea7c35bc5a927f7057cb45d38 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:48 +0000 Subject: [PATCH 064/349] ASoC: audio-graph-card: merge graph_parse_mclk_fs() into graph_link_init() Now graph_link_init() is parsing dai_link related property. Let's handle mclk_fs on it, too. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/87y17ufrv8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 32 +++++++++++----------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 6a19e40d2c4a..7b981aa8690a 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -94,29 +94,12 @@ static void graph_parse_convert(struct device *dev, of_node_put(node); } -static void graph_parse_mclk_fs(struct device_node *top, - struct device_node *ep, - struct simple_dai_props *props) -{ - struct device_node *port = ep_to_port(ep); - struct device_node *ports = port_to_ports(port); - - of_property_read_u32(top, "mclk-fs", &props->mclk_fs); - of_property_read_u32(ports, "mclk-fs", &props->mclk_fs); - of_property_read_u32(port, "mclk-fs", &props->mclk_fs); - of_property_read_u32(ep, "mclk-fs", &props->mclk_fs); - - of_node_put(port); - of_node_put(ports); -} - static int graph_parse_node(struct simple_util_priv *priv, struct device_node *ep, struct link_info *li, int *cpu) { struct device *dev = simple_priv_to_dev(priv); - struct device_node *top = dev->of_node; struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct snd_soc_dai_link_component *dlc; @@ -131,8 +114,6 @@ static int graph_parse_node(struct simple_util_priv *priv, dai = simple_props_to_dai_codec(dai_props, 0); } - graph_parse_mclk_fs(top, ep, dai_props); - ret = graph_util_parse_dai(dev, ep, dlc, cpu); if (ret < 0) return ret; @@ -157,8 +138,11 @@ static int graph_link_init(struct simple_util_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *port_cpu = ep_to_port(ep_cpu); struct device_node *port_codec = ep_to_port(ep_codec); + struct device_node *ports_cpu = port_to_ports(port_cpu); + struct device_node *ports_codec = port_to_ports(port_codec); bool playback_only = 0, capture_only = 0; int ret; @@ -173,6 +157,14 @@ static int graph_link_init(struct simple_util_priv *priv, graph_util_parse_link_direction(ep_cpu, &playback_only, &capture_only); graph_util_parse_link_direction(ep_codec, &playback_only, &capture_only); + of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(ports_cpu, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(ports_codec, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(port_cpu, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(port_codec, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs); + dai_link->playback_only = playback_only; dai_link->capture_only = capture_only; @@ -183,6 +175,8 @@ static int graph_link_init(struct simple_util_priv *priv, ret = simple_util_set_dailink_name(dev, dai_link, name); init_end: + of_node_put(ports_cpu); + of_node_put(ports_codec); of_node_put(port_cpu); of_node_put(port_codec); From 42d37e8de8f2d121481a65e6a3e10f6387c0ad4c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:51 +0000 Subject: [PATCH 065/349] ASoC: simple-audio-card: enable playback/capture_only property Audio Graph Card2 is supporting playback/capture_only property, let's follow Simple Audio Card, too. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/87wmnefrv4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 9c79ff6a568f..e436e8fcfa0f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -187,24 +187,39 @@ static int simple_parse_node(struct simple_util_priv *priv, } static int simple_link_init(struct simple_util_priv *priv, - struct device_node *node, + struct device_node *cpu, struct device_node *codec, struct link_info *li, char *prefix, char *name) { struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct device_node *node = of_get_parent(cpu); + bool playback_only = 0, capture_only = 0; int ret; ret = simple_util_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); if (ret < 0) - return 0; + goto init_end; + + graph_util_parse_link_direction(top, &playback_only, &capture_only); + graph_util_parse_link_direction(node, &playback_only, &capture_only); + graph_util_parse_link_direction(cpu, &playback_only, &capture_only); + graph_util_parse_link_direction(codec, &playback_only, &capture_only); + + dai_link->playback_only = playback_only; + dai_link->capture_only = capture_only; dai_link->init = simple_util_dai_init; dai_link->ops = &simple_ops; - return simple_util_set_dailink_name(dev, dai_link, name); + ret = simple_util_set_dailink_name(dev, dai_link, name); +init_end: + of_node_put(node); + + return ret; } static int simple_dai_link_of_dpcm(struct simple_util_priv *priv, @@ -278,7 +293,7 @@ static int simple_dai_link_of_dpcm(struct simple_util_priv *priv, snd_soc_dai_link_set_capabilities(dai_link); - ret = simple_link_init(priv, node, codec, li, prefix, dai_name); + ret = simple_link_init(priv, np, codec, li, prefix, dai_name); out_put_node: li->link++; @@ -336,7 +351,7 @@ static int simple_dai_link_of(struct simple_util_priv *priv, simple_util_canonicalize_cpu(cpus, single_cpu); simple_util_canonicalize_platform(platforms, cpus); - ret = simple_link_init(priv, node, codec, li, prefix, dai_name); + ret = simple_link_init(priv, cpu, codec, li, prefix, dai_name); dai_link_of_err: of_node_put(plat); From c4cfe1136d6edf8970ccdd944b7f86f7aa3edb77 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:55 +0000 Subject: [PATCH 066/349] ASoC: simple-audio-card: merge simple_parse_mclk_fs() into simple_link_init() Now graph_link_init() is parsing dai_link related property. Let's handle mclk_fs on it, too. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/87v82yfrv0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index e436e8fcfa0f..2de5e6efe947 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -129,24 +129,6 @@ static void simple_parse_convert(struct device *dev, of_node_put(node); } -static void simple_parse_mclk_fs(struct device_node *top, - struct device_node *np, - struct simple_dai_props *props, - char *prefix) -{ - struct device_node *node = of_get_parent(np); - char prop[128]; - - snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX); - of_property_read_u32(top, prop, &props->mclk_fs); - - snprintf(prop, sizeof(prop), "%smclk-fs", prefix); - of_property_read_u32(node, prop, &props->mclk_fs); - of_property_read_u32(np, prop, &props->mclk_fs); - - of_node_put(node); -} - static int simple_parse_node(struct simple_util_priv *priv, struct device_node *np, struct link_info *li, @@ -154,7 +136,6 @@ static int simple_parse_node(struct simple_util_priv *priv, int *cpu) { struct device *dev = simple_priv_to_dev(priv); - struct device_node *top = dev->of_node; struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct snd_soc_dai_link_component *dlc; @@ -169,8 +150,6 @@ static int simple_parse_node(struct simple_util_priv *priv, dai = simple_props_to_dai_codec(dai_props, 0); } - simple_parse_mclk_fs(top, np, dai_props, prefix); - ret = simple_parse_dai(dev, np, dlc, cpu); if (ret) return ret; @@ -195,6 +174,7 @@ static int simple_link_init(struct simple_util_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *node = of_get_parent(cpu); bool playback_only = 0, capture_only = 0; int ret; @@ -209,6 +189,15 @@ static int simple_link_init(struct simple_util_priv *priv, graph_util_parse_link_direction(cpu, &playback_only, &capture_only); graph_util_parse_link_direction(codec, &playback_only, &capture_only); + of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(node, PREFIX "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(cpu, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(cpu, PREFIX "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(codec, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(codec, PREFIX "mclk-fs", &dai_props->mclk_fs); + dai_link->playback_only = playback_only; dai_link->capture_only = capture_only; From fe243a546bcbc405abb7cc5cf26852609cf4e2cc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 May 2024 14:50:49 +0200 Subject: [PATCH 067/349] ASoC: codecs: wcd939x: Unify define used for MIC bias VOUT registers All four microphone bias registers have similar layout: VOUT control mask is exactly the same. Use one define, just like older driver wcd938x is doing, to make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240523125049.43713-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 17 ++++++----------- sound/soc/codecs/wcd939x.h | 5 +---- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 770bc2f35ba7..72d8a6a35052 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -1933,7 +1933,6 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, int req_volt, int micb_num) { struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); - unsigned int micb_vout_ctl_field; unsigned int micb_reg, cur_vout_ctl, micb_en; int req_vout_ctl; int ret = 0; @@ -1941,19 +1940,15 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, switch (micb_num) { case MIC_BIAS_1: micb_reg = WCD939X_ANA_MICB1; - micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL; break; case MIC_BIAS_2: micb_reg = WCD939X_ANA_MICB2; - micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL; break; case MIC_BIAS_3: micb_reg = WCD939X_ANA_MICB3; - micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL; break; case MIC_BIAS_4: micb_reg = WCD939X_ANA_MICB4; - micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL; break; default: return -EINVAL; @@ -1971,7 +1966,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, micb_en = snd_soc_component_read_field(component, micb_reg, WCD939X_MICB_ENABLE); cur_vout_ctl = snd_soc_component_read_field(component, micb_reg, - micb_vout_ctl_field); + WCD939X_MICB_VOUT_CTL); req_vout_ctl = wcd939x_get_micb_vout_ctl_val(req_volt); if (req_vout_ctl < 0) { @@ -1994,7 +1989,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, MICB_BIAS_PULL_DOWN); snd_soc_component_write_field(component, micb_reg, - micb_vout_ctl_field, req_vout_ctl); + WCD939X_MICB_VOUT_CTL, req_vout_ctl); if (micb_en == MICB_BIAS_ENABLE) { snd_soc_component_write_field(component, micb_reg, @@ -2912,13 +2907,13 @@ static int wcd939x_set_micbias_data(struct wcd939x_priv *wcd939x) return -EINVAL; regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB1, - WCD939X_MICB1_VOUT_CTL, vout_ctl_1); + WCD939X_MICB_VOUT_CTL, vout_ctl_1); regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB2, - WCD939X_MICB2_VOUT_CTL, vout_ctl_2); + WCD939X_MICB_VOUT_CTL, vout_ctl_2); regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB3, - WCD939X_MICB3_VOUT_CTL, vout_ctl_3); + WCD939X_MICB_VOUT_CTL, vout_ctl_3); regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB4, - WCD939X_MICB4_VOUT_CTL, vout_ctl_4); + WCD939X_MICB_VOUT_CTL, vout_ctl_4); return 0; } diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h index 383a79316439..756f497a337c 100644 --- a/sound/soc/codecs/wcd939x.h +++ b/sound/soc/codecs/wcd939x.h @@ -92,9 +92,8 @@ #define WCD939X_MBHC_BTN7_VTH GENMASK(7, 2) #define WCD939X_ANA_MICB1 (0x3022) #define WCD939X_MICB_ENABLE GENMASK(7, 6) -#define WCD939X_MICB1_VOUT_CTL GENMASK(5, 0) +#define WCD939X_MICB_VOUT_CTL GENMASK(5, 0) #define WCD939X_ANA_MICB2 (0x3023) -#define WCD939X_MICB2_VOUT_CTL GENMASK(5, 0) #define WCD939X_ANA_MICB2_RAMP (0x3024) #define WCD939X_MICB2_RAMP_RAMP_ENABLE BIT(7) #define WCD939X_MICB2_RAMP_MB2_IN2P_SHORT_ENABLE BIT(6) @@ -102,9 +101,7 @@ #define WCD939X_MICB2_RAMP_SHIFT_CTL GENMASK(4, 2) #define WCD939X_MICB2_RAMP_USB_MGDET_MICB2_RAMP GENMASK(1, 0) #define WCD939X_ANA_MICB3 (0x3025) -#define WCD939X_MICB3_VOUT_CTL GENMASK(5, 0) #define WCD939X_ANA_MICB4 (0x3026) -#define WCD939X_MICB4_VOUT_CTL GENMASK(5, 0) #define WCD939X_BIAS_CTL (0x3028) #define WCD939X_BIAS_VBG_FINE_ADJ (0x3029) #define WCD939X_LDOL_VDDCX_ADJUST (0x3040) From d8e5fa784867c4cd400afecc43aec57c51c10dc7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 May 2024 14:48:08 +0200 Subject: [PATCH 068/349] ASoC: codecs: wcd938x: Drop no-op ADC2_BCS Disable Switch The "ADC2_BCS Disable Switch" control does basically nothing: sets field in driver's private data structure which is never read again to configure hardware. Drop the control as it has no effect. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240523124808.42923-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 9e2070356b84..73387152ce02 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -206,7 +206,6 @@ struct wcd938x_priv { bool comp1_enable; bool comp2_enable; bool ldoh; - bool bcs_dis; }; static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); @@ -1650,31 +1649,6 @@ static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol, return 1; } -static int wcd938x_bcs_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); - - ucontrol->value.integer.value[0] = wcd938x->bcs_dis; - - return 0; -} - -static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); - - if (wcd938x->bcs_dis == ucontrol->value.integer.value[0]) - return 0; - - wcd938x->bcs_dis = ucontrol->value.integer.value[0]; - - return 1; -} - static const char * const tx_mode_mux_text_wcd9380[] = { "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", }; @@ -2695,8 +2669,6 @@ static const struct snd_kcontrol_new wcd938x_snd_controls[] = { wcd938x_get_swr_port, wcd938x_set_swr_port), SOC_SINGLE_EXT("LDOH Enable Switch", SND_SOC_NOPM, 0, 1, 0, wcd938x_ldoh_get, wcd938x_ldoh_put), - SOC_SINGLE_EXT("ADC2_BCS Disable Switch", SND_SOC_NOPM, 0, 1, 0, - wcd938x_bcs_get, wcd938x_bcs_put), SOC_SINGLE_TLV("ADC1 Volume", WCD938X_ANA_TX_CH1, 0, 20, 0, analog_gain), SOC_SINGLE_TLV("ADC2 Volume", WCD938X_ANA_TX_CH2, 0, 20, 0, analog_gain), From ccdc13ab26ca248fdc53179a0c7f588ab2e1c8d8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 3 Jun 2024 10:25:44 +0300 Subject: [PATCH 069/349] ASoC: SOF: Intel: pci-tgl: Align ADL-N sof_dev_desc struct name to convention Follow the convention already in use by other platforms on naming the sof_dev_desc struct by dropping the underscore between adl and n Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240603072544.5215-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/pci-tgl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index ebe1a7d16689..01db2e720b44 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -183,7 +183,7 @@ static const struct sof_dev_desc adl_desc = { .ops_free = hda_ops_free, }; -static const struct sof_dev_desc adl_n_desc = { +static const struct sof_dev_desc adln_desc = { .machines = snd_soc_acpi_intel_adl_machines, .alt_machines = snd_soc_acpi_intel_adl_sdw_machines, .use_acpi_target_states = true, @@ -298,7 +298,7 @@ static const struct pci_device_id sof_pci_ids[] = { { 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) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adln_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); From fc1277335ffa0d180c76ddccf5fe27fc75674e67 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 29 May 2024 16:40:01 +0800 Subject: [PATCH 070/349] ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX95 Add compatible string "fsl,imx95-xcvr" for i.MX95 platform. The difference between each platform is in below table. +---------+--------+----------+--------+ | SOC | PHY | eARC/ARC | SPDIF | +---------+--------+----------+--------+ | i.MX8MP | V1 | Yes | Yes | +---------+--------+----------+--------+ | i.MX93 | N/A | N/A | Yes | +---------+--------+----------+--------+ | i.MX95 | V2 | N/A | Yes | +---------+--------+----------+--------+ On i.MX95, there are two PLL clock sources, they are the parent clocks of the XCVR root clock. one is for 8kHz series rates, named as 'pll8k', another one is for 11kHz series rates, named as 'pll11k'. They are optional clocks, if there are such clocks, then the driver can switch between them to support more accurate sample rates. As 'pll8k' and 'pll11k' are optional, then add 'minItems: 4' for clocks and clock-names properties. On i.MX95, the 'interrupts' configuration has the same constraint as i.MX93. Only on i.MX8MP, the 'resets' is required, but for i.MX95 and i.MX93 there is no such hardware setting. Signed-off-by: Shengjiu Wang Reviewed-by: Rob Herring (Arm) Link: https://msgid.link/r/1716972002-2315-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl,xcvr.yaml | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml index 0eb0c1ba8710..197ae8ba9c30 100644 --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml @@ -22,6 +22,7 @@ properties: enum: - fsl,imx8mp-xcvr - fsl,imx93-xcvr + - fsl,imx95-xcvr reg: items: @@ -49,6 +50,9 @@ properties: - description: PHY clock - description: SPBA clock - description: PLL clock + - description: PLL clock source for 8kHz series + - description: PLL clock source for 11kHz series + minItems: 4 clock-names: items: @@ -56,6 +60,9 @@ properties: - const: phy - const: spba - const: pll_ipg + - const: pll8k + - const: pll11k + minItems: 4 dmas: items: @@ -79,15 +86,24 @@ required: - clock-names - dmas - dma-names - - resets allOf: + - if: + properties: + compatible: + contains: + const: fsl,imx8mp-xcvr + then: + required: + - resets + - if: properties: compatible: contains: enum: - fsl,imx93-xcvr + - fsl,imx95-xcvr then: properties: interrupts: @@ -98,6 +114,20 @@ allOf: interrupts: maxItems: 1 + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8mp-xcvr + - fsl,imx93-xcvr + then: + properties: + clocks: + maxItems: 4 + clock-names: + maxItems: 4 + additionalProperties: false examples: From f13b349e3c70320ef5a86edfc888a6feb612abb0 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 29 May 2024 16:40:02 +0800 Subject: [PATCH 071/349] ASoC: fsl_xcvr: Add support for i.MX95 platform On i.MX95, the XCVR uses a new PLL in the PHY, which is General Purpose (GP) PLL. Add GP PLL configuration support in the driver and add the 'pll_ver' flag to distinguish different PLL on different platforms. The XCVR also use PHY but limited for SPDIF only case Add 'use_phy' flag to distinguish these platforms. When there are 'pll8k' and 'pll11k' clock existing, the clock source of 'phy_clk' can be changed for different sample rate requirement. Signed-off-by: Shengjiu Wang Reviewed-by: Chancel Liu Link: https://msgid.link/r/1716972002-2315-3-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/fsl_xcvr.c | 126 ++++++++++++++++++++++++++------------- sound/soc/fsl/fsl_xcvr.h | 91 ++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 42 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 270726c134b3..9a371d4496c2 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -103,6 +103,7 @@ config SND_SOC_FSL_XCVR select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_SOC_FSL_UTILS help Say Y if you want to add Audio Transceiver (XCVR) support for NXP iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC, diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 5472ace23d82..337da46a2f90 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -15,14 +15,22 @@ #include #include "fsl_xcvr.h" +#include "fsl_utils.h" #include "imx-pcm.h" #define FSL_XCVR_CAPDS_SIZE 256 +enum fsl_xcvr_pll_verison { + PLL_MX8MP, + PLL_MX95, +}; + struct fsl_xcvr_soc_data { const char *fw_name; bool spdif_only; bool use_edma; + bool use_phy; + enum fsl_xcvr_pll_verison pll_ver; }; struct fsl_xcvr { @@ -33,6 +41,8 @@ struct fsl_xcvr { struct clk *pll_ipg_clk; struct clk *phy_clk; struct clk *spba_clk; + struct clk *pll8k_clk; + struct clk *pll11k_clk; struct reset_control *reset; u8 streams; u32 mode; @@ -262,10 +272,10 @@ static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy) static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) { struct device *dev = &xcvr->pdev->dev; - u32 i, div = 0, log2; + u32 i, div = 0, log2, val; int ret; - if (xcvr->soc_data->spdif_only) + if (!xcvr->soc_data->use_phy) return 0; for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) { @@ -288,45 +298,62 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) return ret; } - /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET, - FSL_XCVR_PLL_BANDGAP_EN_VBG, 0); + switch (xcvr->soc_data->pll_ver) { + case PLL_MX8MP: + /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET, + FSL_XCVR_PLL_BANDGAP_EN_VBG, 0); - /* PLL: CTRL0: DIV_INTEGER */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0); - /* PLL: NUMERATOR: MFN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0); - /* PLL: DENOMINATOR: MFD */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0); - /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0); - udelay(25); - /* PLL: CTRL0: Clear Hold Ring Off */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR, - FSL_XCVR_PLL_CTRL0_HROFF, 0); - udelay(100); - if (tx) { /* TX is enabled for SPDIF only */ - /* PLL: POSTDIV: PDIV0 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 0), 0); - /* PLL: CTRL_SET: CLKMUX0_EN */ + /* PLL: CTRL0: DIV_INTEGER */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0); + /* PLL: NUMERATOR: MFN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0); + /* PLL: DENOMINATOR: MFD */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0); + /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM0_EN, 0); - } else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */ - /* PLL: POSTDIV: PDIV1 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 1), 0); - /* PLL: CTRL_SET: CLKMUX1_EN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM1_EN, 0); - } else { /* SPDIF / ARC RX */ - /* PLL: POSTDIV: PDIV2 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 2), 0); - /* PLL: CTRL_SET: CLKMUX2_EN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM2_EN, 0); + FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0); + udelay(25); + /* PLL: CTRL0: Clear Hold Ring Off */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR, + FSL_XCVR_PLL_CTRL0_HROFF, 0); + udelay(100); + if (tx) { /* TX is enabled for SPDIF only */ + /* PLL: POSTDIV: PDIV0 */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, + FSL_XCVR_PLL_PDIVx(log2, 0), 0); + /* PLL: CTRL_SET: CLKMUX0_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, + FSL_XCVR_PLL_CTRL0_CM0_EN, 0); + } else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */ + /* PLL: POSTDIV: PDIV1 */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, + FSL_XCVR_PLL_PDIVx(log2, 1), 0); + /* PLL: CTRL_SET: CLKMUX1_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, + FSL_XCVR_PLL_CTRL0_CM1_EN, 0); + } else { /* SPDIF / ARC RX */ + /* PLL: POSTDIV: PDIV2 */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, + FSL_XCVR_PLL_PDIVx(log2, 2), 0); + /* PLL: CTRL_SET: CLKMUX2_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, + FSL_XCVR_PLL_CTRL0_CM2_EN, 0); + } + break; + case PLL_MX95: + val = fsl_xcvr_pll_cfg[i].mfi << FSL_XCVR_GP_PLL_DIV_MFI_SHIFT | div; + fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_DIV, val, 0); + val = fsl_xcvr_pll_cfg[i].mfn << FSL_XCVR_GP_PLL_NUMERATOR_MFN_SHIFT; + fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_NUMERATOR, val, 0); + fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_DENOMINATOR, + fsl_xcvr_pll_cfg[i].mfd, 0); + val = FSL_XCVR_GP_PLL_CTRL_POWERUP | FSL_XCVR_GP_PLL_CTRL_CLKMUX_EN; + fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_CTRL, val, 0); + break; + default: + dev_err(dev, "Error for PLL version %d\n", xcvr->soc_data->pll_ver); + return -EINVAL; } if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */ @@ -362,6 +389,8 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq) freq = xcvr->soc_data->spdif_only ? freq / 5 : freq; clk_disable_unprepare(xcvr->phy_clk); + fsl_asoc_reparent_pll_clocks(dev, xcvr->phy_clk, + xcvr->pll8k_clk, xcvr->pll11k_clk, freq); ret = clk_set_rate(xcvr->phy_clk, freq); if (ret < 0) { dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret); @@ -373,7 +402,7 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq) return ret; } - if (xcvr->soc_data->spdif_only) + if (!xcvr->soc_data->use_phy) return 0; /* Release AI interface from reset */ ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, @@ -1017,7 +1046,7 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg) { struct fsl_xcvr *xcvr = dev_get_drvdata(dev); - if (xcvr->soc_data->spdif_only) + if (!xcvr->soc_data->use_phy) if ((reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA) || reg > FSL_XCVR_TX_DPTH_BCRR) return false; @@ -1090,7 +1119,7 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg) { struct fsl_xcvr *xcvr = dev_get_drvdata(dev); - if (xcvr->soc_data->spdif_only) + if (!xcvr->soc_data->use_phy) if (reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA) return false; switch (reg) { @@ -1234,6 +1263,8 @@ static irqreturn_t irq0_isr(int irq, void *devid) static const struct fsl_xcvr_soc_data fsl_xcvr_imx8mp_data = { .fw_name = "imx/xcvr/xcvr-imx8mp.bin", + .use_phy = true, + .pll_ver = PLL_MX8MP, }; static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = { @@ -1241,9 +1272,17 @@ static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = { .use_edma = true, }; +static const struct fsl_xcvr_soc_data fsl_xcvr_imx95_data = { + .spdif_only = true, + .use_phy = true, + .use_edma = true, + .pll_ver = PLL_MX95, +}; + static const struct of_device_id fsl_xcvr_dt_ids[] = { { .compatible = "fsl,imx8mp-xcvr", .data = &fsl_xcvr_imx8mp_data }, { .compatible = "fsl,imx93-xcvr", .data = &fsl_xcvr_imx93_data}, + { .compatible = "fsl,imx95-xcvr", .data = &fsl_xcvr_imx95_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids); @@ -1287,6 +1326,9 @@ static int fsl_xcvr_probe(struct platform_device *pdev) return PTR_ERR(xcvr->pll_ipg_clk); } + fsl_asoc_get_pll_clocks(dev, &xcvr->pll8k_clk, + &xcvr->pll11k_clk); + xcvr->ram_addr = devm_platform_ioremap_resource_byname(pdev, "ram"); if (IS_ERR(xcvr->ram_addr)) return PTR_ERR(xcvr->ram_addr); diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h index 044058fc6aa2..882428592e1a 100644 --- a/sound/soc/fsl/fsl_xcvr.h +++ b/sound/soc/fsl/fsl_xcvr.h @@ -291,4 +291,95 @@ #define FSL_XCVR_RX_CS_BUFF_1 0xA0 /* Second RX CS buffer */ #define FSL_XCVR_CAP_DATA_STR 0x300 /* Capabilities data structure */ +/* GP PLL Registers */ +#define FSL_XCVR_GP_PLL_CTRL 0x00 +#define FSL_XCVR_GP_PLL_CTRL_SET 0x04 +#define FSL_XCVR_GP_PLL_CTRL_CLR 0x08 +#define FSL_XCVR_GP_PLL_CTRL_TOG 0x0C +#define FSL_XCVR_GP_PLL_ANA_PRG 0x10 +#define FSL_XCVR_GP_PLL_ANA_PRG_SET 0x14 +#define FSL_XCVR_GP_PLL_ANA_PRG_CLR 0x18 +#define FSL_XCVR_GP_PLL_ANA_PRG_TOG 0x1C +#define FSL_XCVR_GP_PLL_TEST 0x20 +#define FSL_XCVR_GP_PLL_TEST_SET 0x24 +#define FSL_XCVR_GP_PLL_TEST_CLR 0x28 +#define FSL_XCVR_GP_PLL_TEST_TOG 0x2C +#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM 0x30 +#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_SET 0x34 +#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_CLR 0x38 +#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_TOG 0x3C +#define FSL_XCVR_GP_PLL_NUMERATOR 0x40 +#define FSL_XCVR_GP_PLL_NUMERATOR_SET 0x44 +#define FSL_XCVR_GP_PLL_NUMERATOR_CLR 0x48 +#define FSL_XCVR_GP_PLL_NUMERATOR_TOG 0x4C +#define FSL_XCVR_GP_PLL_DENOMINATOR 0x50 +#define FSL_XCVR_GP_PLL_DENOMINATOR_SET 0x54 +#define FSL_XCVR_GP_PLL_DENOMINATOR_CLR 0x58 +#define FSL_XCVR_GP_PLL_DENOMINATOR_TOG 0x5C +#define FSL_XCVR_GP_PLL_DIV 0x60 +#define FSL_XCVR_GP_PLL_DIV_SET 0x64 +#define FSL_XCVR_GP_PLL_DIV_CLR 0x68 +#define FSL_XCVR_GP_PLL_DIV_TOG 0x6C +#define FSL_XCVR_GP_PLL_DFS_CTRL0 0x70 +#define FSL_XCVR_GP_PLL_DFS_CTRL0_SET 0x74 +#define FSL_XCVR_GP_PLL_DFS_CTRL0_CLR 0x78 +#define FSL_XCVR_GP_PLL_DFS_CTRL0_TOG 0x7C +#define FSL_XCVR_GP_PLL_DFS_DIV0 0x80 +#define FSL_XCVR_GP_PLL_DFS_DIV0_SET 0x84 +#define FSL_XCVR_GP_PLL_DFS_DIV0_CLR 0x88 +#define FSL_XCVR_GP_PLL_DFS_DIV0_TOG 0x8C +#define FSL_XCVR_GP_PLL_DFS_CTRL1 0x90 +#define FSL_XCVR_GP_PLL_DFS_CTRL1_SET 0x94 +#define FSL_XCVR_GP_PLL_DFS_CTRL1_CLR 0x98 +#define FSL_XCVR_GP_PLL_DFS_CTRL1_TOG 0x9C +#define FSL_XCVR_GP_PLL_DFS_DIV1 0xA0 +#define FSL_XCVR_GP_PLL_DFS_DIV1_SET 0xA4 +#define FSL_XCVR_GP_PLL_DFS_DIV1_CLR 0xA8 +#define FSL_XCVR_GP_PLL_DFS_DIV1_TOG 0xAC +#define FSL_XCVR_GP_PLL_DFS_CTRL2 0xB0 +#define FSL_XCVR_GP_PLL_DFS_CTRL2_SET 0xB4 +#define FSL_XCVR_GP_PLL_DFS_CTRL2_CLR 0xB8 +#define FSL_XCVR_GP_PLL_DFS_CTRL2_TOG 0xBC +#define FSL_XCVR_GP_PLL_DFS_DIV2 0xC0 +#define FSL_XCVR_GP_PLL_DFS_DIV2_SET 0xC4 +#define FSL_XCVR_GP_PLL_DFS_DIV2_CLR 0xC8 +#define FSL_XCVR_GP_PLL_DFS_DIV2_TOG 0xCC +#define FSL_XCVR_GP_PLL_DFS_CTRL3 0xD0 +#define FSL_XCVR_GP_PLL_DFS_CTRL3_SET 0xD4 +#define FSL_XCVR_GP_PLL_DFS_CTRL3_CLR 0xD8 +#define FSL_XCVR_GP_PLL_DFS_CTRL3_TOG 0xDC +#define FSL_XCVR_GP_PLL_DFS_DIV3 0xE0 +#define FSL_XCVR_GP_PLL_DFS_DIV3_SET 0xE4 +#define FSL_XCVR_GP_PLL_DFS_DIV3_CLR 0xE8 +#define FSL_XCVR_GP_PLL_DFS_DIV3_TOG 0xEC +#define FSL_XCVR_GP_PLL_STATUS 0xF0 +#define FSL_XCVR_GP_PLL_STATUS_SET 0xF4 +#define FSL_XCVR_GP_PLL_STATUS_CLR 0xF8 +#define FSL_XCVR_GP_PLL_STATUS_TOG 0xFC + +/* GP PLL Control Register */ +#define FSL_XCVR_GP_PLL_CTRL_LBYPASS BIT(31) +#define FSL_XCVR_GP_PLL_CTRL_HCS BIT(16) +#define FSL_XCVR_GP_PLL_CTRL_MSD BIT(12) +#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN3 BIT(11) +#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN2 BIT(10) +#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN1 BIT(9) +#define FSL_XCVR_GP_PLL_CTRL_SPREADCTL BIT(8) +#define FSL_XCVR_GP_PLL_CTRL_CLKMUX_BYPASS BIT(2) +#define FSL_XCVR_GP_PLL_CTRL_CLKMUX_EN BIT(1) +#define FSL_XCVR_GP_PLL_CTRL_POWERUP BIT(0) + +/* GP PLL Numerator Register */ +#define FSL_XCVR_GP_PLL_NUMERATOR_MFN_SHIFT 2 +#define FSL_XCVR_GP_PLL_NUMERATOR_MFN GENMASK(31, 2) + +/* GP PLL Denominator Register */ +#define FSL_XCVR_GP_PLL_DENOMINATOR_MFD GENMASK(29, 0) + +/* GP PLL Dividers Register */ +#define FSL_XCVR_GP_PLL_DIV_MFI_SHIFT 16 +#define FSL_XCVR_GP_PLL_DIV_MFI GENMASK(24, 16) +#define FSL_XCVR_GP_PLL_DIV_RDIV GENMASK(15, 13) +#define FSL_XCVR_GP_PLL_DIV_ODIV GENMASK(7, 0) + #endif /* __FSL_XCVR_H */ From 39d762edd1f353c4446dbce83a18da4e491cc48e Mon Sep 17 00:00:00 2001 From: Ricard Wanderlof Date: Tue, 28 May 2024 17:40:04 +0200 Subject: [PATCH 072/349] ASoC: dt-bindings: tlv320adc3xxx: Fix incorrect GPIO description Fix the description for the ti,dmdin-gpio1 and ti,dmclk-gpio2 properties to correctly describe that when configured as general purpose outputs (ADC3XXX_GPIO_GPO), the pins are available via the GPIO framework. Signed-off-by: Ricard Wanderlof Reviewed-by: Rob Herring (Arm) Link: https://msgid.link/r/20240528-tlv320adc3xxx-dt-gpio-fix-v1-1-209fb2c2f86f@axis.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ti,tlv320adc3xxx.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml index ede14ca2c07a..8ac741f4cd56 100644 --- a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml @@ -58,8 +58,8 @@ properties: description: | Configuration for DMDIN/GPIO1 pin. - When ADC3XXX_GPIO_GPO is configured, this causes corresponding the - ALSA control "GPIOx Output" to appear, as a switch control. + When ADC3XXX_GPIO_GPO is selected, the pin may be controlled via the + GPIO framework, as pin number 0 on the device. ti,dmclk-gpio2: $ref: /schemas/types.yaml#/definitions/uint32 @@ -76,8 +76,8 @@ properties: description: | Configuration for DMCLK/GPIO2 pin. - When ADC3XXX_GPIO_GPO is configured, this causes corresponding the - ALSA control "GPIOx Output" to appear, as a switch control. + When ADC3XXX_GPIO_GPO is selected, the pin may be controlled via the + GPIO framework, as pin number 1 on the device. Note that there is currently no support for reading the GPIO pins as inputs. From a1708fda9388c83215f0be82ad47df10be6e1975 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 6 Jun 2024 10:06:58 +0200 Subject: [PATCH 073/349] ASoC: dt-bindings: convert amlogic,g12a-tohdmitx to dt-schema Convert text bindings to dt-schema format for the Amlogic TX HDMI control glue. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Link: https://msgid.link/r/20240606-topic-amlogic-upstream-bindings-convert-g12a-tohdmitx-v2-1-70d44fa30790@linaro.org Signed-off-by: Mark Brown --- .../bindings/sound/amlogic,g12a-tohdmitx.txt | 58 ------------------- .../bindings/sound/amlogic,g12a-tohdmitx.yaml | 54 +++++++++++++++++ 2 files changed, 54 insertions(+), 58 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt create mode 100644 Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.yaml diff --git a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt deleted file mode 100644 index 4e8cd7eb7cec..000000000000 --- a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt +++ /dev/null @@ -1,58 +0,0 @@ -* Amlogic HDMI Tx control glue - -Required properties: -- compatible: "amlogic,g12a-tohdmitx" or - "amlogic,sm1-tohdmitx" -- reg: physical base address of the controller and length of memory - mapped region. -- #sound-dai-cells: should be 1. -- resets: phandle to the dedicated reset line of the hdmitx glue. - -Example on the S905X2 SoC: - -tohdmitx: audio-controller@744 { - compatible = "amlogic,g12a-tohdmitx"; - reg = <0x0 0x744 0x0 0x4>; - #sound-dai-cells = <1>; - resets = <&clkc_audio AUD_RESET_TOHDMITX>; -}; - -Example of an 'amlogic,axg-sound-card': - -sound { - compatible = "amlogic,axg-sound-card"; - -[...] - - dai-link-x { - sound-dai = <&tdmif_a>; - dai-format = "i2s"; - dai-tdm-slot-tx-mask-0 = <1 1>; - - codec-0 { - sound-dai = <&tohdmitx TOHDMITX_I2S_IN_A>; - }; - - codec-1 { - sound-dai = <&external_dac>; - }; - }; - - dai-link-y { - sound-dai = <&tdmif_c>; - dai-format = "i2s"; - dai-tdm-slot-tx-mask-0 = <1 1>; - - codec { - sound-dai = <&tohdmitx TOHDMITX_I2S_IN_C>; - }; - }; - - dai-link-z { - sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; - - codec { - sound-dai = <&hdmi_tx>; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.yaml b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.yaml new file mode 100644 index 000000000000..b4b78475c5b8 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/amlogic,g12a-tohdmitx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic G12a HDMI TX Control Glue + +maintainers: + - Jerome Brunet + +allOf: + - $ref: dai-common.yaml# + +properties: + $nodename: + pattern: "^audio-controller@.*" + + compatible: + oneOf: + - items: + - const: amlogic,g12a-tohdmitx + - items: + - enum: + - amlogic,sm1-tohdmitx + - const: amlogic,g12a-tohdmitx + + reg: + maxItems: 1 + + resets: + maxItems: 1 + + "#sound-dai-cells": + const: 1 + +required: + - compatible + - reg + - resets + - "#sound-dai-cells" + +unevaluatedProperties: false + +examples: + - | + #include + + tohdmitx: audio-controller@744 { + compatible = "amlogic,g12a-tohdmitx"; + reg = <0x744 0x4>; + resets = <&clkc_audio AUD_RESET_TOHDMITX>; + #sound-dai-cells = <1>; + }; From 27173bb0b64461acf4e00f1bae3b15d8d2348c14 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 24 May 2024 09:25:29 +0530 Subject: [PATCH 074/349] ASoC: dt-bindings: document wcd937x Audio Codec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the Qualcomm WCD9370/WCD9375 Audio Codec and the Soundwire devices than can be found on Qualcomm QCM6490 based platforms. The Qualcomm WCD9370/WCD9375 Audio Codec communicates with the host SoC over 2 Soundwire links to provide: - 3 TX ADC paths with 4 differential AMIC inputs - 6 DMIC inputs that are shared with AMIC input - 4 Microphone BIAS - RX paths with 4 PAs – HPHL/R, EAR and AUX - Stereo Headphone output - MBHC engine for Headset Detection Signed-off-by: Prasad Kumpatla Co-developed-by: Mohammad Rafi Shaik Signed-off-by: Mohammad Rafi Shaik Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240524035535.3119208-2-quic_mohs@quicinc.com Signed-off-by: Mark Brown --- .../bindings/sound/qcom,wcd937x-sdw.yaml | 91 +++++++++++++++++++ .../bindings/sound/qcom,wcd937x.yaml | 82 +++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd937x-sdw.yaml create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd937x-sdw.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd937x-sdw.yaml new file mode 100644 index 000000000000..d3cf8f59cb23 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,wcd937x-sdw.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,wcd937x-sdw.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SoundWire Slave devices on WCD9370/WCD9375 + +maintainers: + - Srinivas Kandagatla + +description: | + Qualcomm WCD9370/WCD9375 Codec is a standalone Hi-Fi audio codec IC. + It has RX and TX Soundwire slave devices. This bindings is for the + slave devices. + +properties: + compatible: + const: sdw20217010a00 + + reg: + maxItems: 1 + + qcom,tx-port-mapping: + description: | + Specifies static port mapping between device and host tx ports. + In the order of the device port index which are adc1_port, adc23_port, + dmic03_mbhc_port, dmic46_port. + Supports maximum 4 tx soundwire ports. + + WCD9370 TX Port 1 (ADC1) <=> SWR2 Port 2 + WCD9370 TX Port 2 (ADC2, 3) <=> SWR2 Port 2 + WCD9370 TX Port 3 (DMIC0,1,2,3 & MBHC) <=> SWR2 Port 3 + WCD9370 TX Port 4 (DMIC4,5,6,7) <=> SWR2 Port 4 + + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 4 + maxItems: 4 + items: + enum: [1, 2, 3, 4] + + qcom,rx-port-mapping: + description: | + Specifies static port mapping between device and host rx ports. + In the order of device port index which are hph_port, clsh_port, + comp_port, lo_port, dsd port. + Supports maximum 5 rx soundwire ports. + + WCD9370 RX Port 1 (HPH_L/R) <==> SWR1 Port 1 (HPH_L/R) + WCD9370 RX Port 2 (CLSH) <==> SWR1 Port 2 (CLSH) + WCD9370 RX Port 3 (COMP_L/R) <==> SWR1 Port 3 (COMP_L/R) + WCD9370 RX Port 4 (LO) <==> SWR1 Port 4 (LO) + WCD9370 RX Port 5 (DSD_L/R) <==> SWR1 Port 5 (DSD) + + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 5 + maxItems: 5 + items: + enum: [1, 2, 3, 4, 5] + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + soundwire@3210000 { + reg = <0x03210000 0x2000>; + #address-cells = <2>; + #size-cells = <0>; + wcd937x_rx: codec@0,4 { + compatible = "sdw20217010a00"; + reg = <0 4>; + qcom,rx-port-mapping = <1 2 3 4 5>; + }; + }; + + soundwire@3230000 { + reg = <0x03230000 0x2000>; + #address-cells = <2>; + #size-cells = <0>; + wcd937x_tx: codec@0,3 { + compatible = "sdw20217010a00"; + reg = <0 3>; + qcom,tx-port-mapping = <2 2 3 4>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml new file mode 100644 index 000000000000..de397d879acc --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,wcd937x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm WCD9370/WCD9375 Audio Codec + +maintainers: + - Srinivas Kandagatla + +description: + Qualcomm WCD9370/WCD9375 Codec is a standalone Hi-Fi audio codec IC. + It has RX and TX Soundwire slave devices. + +allOf: + - $ref: dai-common.yaml# + - $ref: qcom,wcd93xx-common.yaml# + +properties: + compatible: + oneOf: + - const: qcom,wcd9370-codec + - items: + - const: qcom,wcd9375-codec + - const: qcom,wcd9370-codec + + vdd-px-supply: + description: A reference to the 1.8V I/O supply + +required: + - compatible + - vdd-px-supply + +unevaluatedProperties: false + +examples: + - | + #include + codec { + compatible = "qcom,wcd9370-codec"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&wcd_reset_n>; + pinctrl-1 = <&wcd_reset_n_sleep>; + reset-gpios = <&tlmm 83 GPIO_ACTIVE_HIGH>; + vdd-buck-supply = <&vreg_l17b_1p8>; + vdd-rxtx-supply = <&vreg_l18b_1p8>; + vdd-px-supply = <&vreg_l18b_1p8>; + vdd-mic-bias-supply = <&vreg_bob>; + qcom,micbias1-microvolt = <1800000>; + qcom,micbias2-microvolt = <1800000>; + qcom,micbias3-microvolt = <1800000>; + qcom,micbias4-microvolt = <1800000>; + qcom,rx-device = <&wcd937x_rx>; + qcom,tx-device = <&wcd937x_tx>; + #sound-dai-cells = <1>; + }; + + /* ... */ + + soundwire@3210000 { + reg = <0x03210000 0x2000>; + #address-cells = <2>; + #size-cells = <0>; + wcd937x_rx: codec@0,4 { + compatible = "sdw20217010a00"; + reg = <0 4>; + qcom,rx-port-mapping = <1 2 3 4 5>; + }; + }; + + soundwire@3230000 { + reg = <0x03230000 0x2000>; + #address-cells = <2>; + #size-cells = <0>; + wcd937x_tx: codec@0,3 { + compatible = "sdw20217010a00"; + reg = <0 3>; + qcom,tx-port-mapping = <1 2 3 4>; + }; + }; +... From c99a515ff15380ec5f8827049914145ba908e8da Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 24 May 2024 09:25:30 +0530 Subject: [PATCH 075/349] ASoC: codecs: wcd937x-sdw: add SoundWire driver This patch adds support to SoundWire devices on WCD9370/WCD9375 Codec. The WCD9370/WCD9375 Soundwire devices will be used by the main WCD9370/WCD9375 Audio Codec driver to access registers and configure Soundwire RX and TX ports. Signed-off-by: Prasad Kumpatla Co-developed-by: Mohammad Rafi Shaik Signed-off-by: Mohammad Rafi Shaik Link: https://lore.kernel.org/r/20240524035535.3119208-3-quic_mohs@quicinc.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x-sdw.c | 1139 ++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd937x.h | 653 ++++++++++++++++++ 2 files changed, 1792 insertions(+) create mode 100644 sound/soc/codecs/wcd937x-sdw.c create mode 100644 sound/soc/codecs/wcd937x.h diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c new file mode 100644 index 000000000000..a45025bf96c6 --- /dev/null +++ b/sound/soc/codecs/wcd937x-sdw.c @@ -0,0 +1,1139 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd937x.h" + +static struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = { + WCD_SDW_CH(WCD937X_HPH_L, WCD937X_HPH_PORT, BIT(0)), + WCD_SDW_CH(WCD937X_HPH_R, WCD937X_HPH_PORT, BIT(1)), + WCD_SDW_CH(WCD937X_CLSH, WCD937X_CLSH_PORT, BIT(0)), + WCD_SDW_CH(WCD937X_COMP_L, WCD937X_COMP_PORT, BIT(0)), + WCD_SDW_CH(WCD937X_COMP_R, WCD937X_COMP_PORT, BIT(1)), + WCD_SDW_CH(WCD937X_LO, WCD937X_LO_PORT, BIT(0)), + WCD_SDW_CH(WCD937X_DSD_L, WCD937X_DSD_PORT, BIT(0)), + WCD_SDW_CH(WCD937X_DSD_R, WCD937X_DSD_PORT, BIT(1)), +}; + +static struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = { + WCD_SDW_CH(WCD937X_ADC1, WCD937X_ADC_1_PORT, BIT(0)), + WCD_SDW_CH(WCD937X_ADC2, WCD937X_ADC_2_3_PORT, BIT(0)), + WCD_SDW_CH(WCD937X_ADC3, WCD937X_ADC_2_3_PORT, BIT(0)), + WCD_SDW_CH(WCD937X_DMIC0, WCD937X_DMIC_0_3_MBHC_PORT, BIT(0)), + WCD_SDW_CH(WCD937X_DMIC1, WCD937X_DMIC_0_3_MBHC_PORT, BIT(1)), + WCD_SDW_CH(WCD937X_MBHC, WCD937X_DMIC_0_3_MBHC_PORT, BIT(2)), + WCD_SDW_CH(WCD937X_DMIC2, WCD937X_DMIC_0_3_MBHC_PORT, BIT(2)), + WCD_SDW_CH(WCD937X_DMIC3, WCD937X_DMIC_0_3_MBHC_PORT, BIT(3)), + WCD_SDW_CH(WCD937X_DMIC4, WCD937X_DMIC_4_6_PORT, BIT(0)), + WCD_SDW_CH(WCD937X_DMIC5, WCD937X_DMIC_4_6_PORT, BIT(1)), + WCD_SDW_CH(WCD937X_DMIC6, WCD937X_DMIC_4_6_PORT, BIT(2)), +}; + +static struct sdw_dpn_prop wcd937x_dpn_prop[WCD937X_MAX_SWR_PORTS] = { + { + .num = 1, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 8, + .simple_ch_prep_sm = true, + }, { + .num = 2, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, { + .num = 3, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, { + .num = 4, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, { + .num = 5, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + } +}; + +struct device *wcd937x_sdw_device_get(struct device_node *np) +{ + return bus_find_device_by_of_node(&sdw_bus_type, np); +} +EXPORT_SYMBOL_GPL(wcd937x_sdw_device_get); + +int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS]; + unsigned long ch_mask; + int i, j; + + wcd->sconfig.ch_count = 1; + wcd->active_ports = 0; + for (i = 0; i < WCD937X_MAX_SWR_PORTS; i++) { + ch_mask = wcd->port_config[i].ch_mask; + if (!ch_mask) + continue; + + for_each_set_bit(j, &ch_mask, 4) + wcd->sconfig.ch_count++; + + port_config[wcd->active_ports] = wcd->port_config[i]; + wcd->active_ports++; + } + + wcd->sconfig.bps = 1; + wcd->sconfig.frame_rate = params_rate(params); + wcd->sconfig.direction = wcd->is_tx ? SDW_DATA_DIR_TX : SDW_DATA_DIR_RX; + wcd->sconfig.type = SDW_STREAM_PCM; + + return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig, + &port_config[0], wcd->active_ports, + wcd->sruntime); +} +EXPORT_SYMBOL_GPL(wcd937x_sdw_hw_params); + +static int wcd9370_update_status(struct sdw_slave *slave, enum sdw_slave_status status) +{ + struct wcd937x_sdw_priv *wcd = dev_get_drvdata(&slave->dev); + + if (wcd->regmap && status == SDW_SLAVE_ATTACHED) { + /* Write out any cached changes that happened between probe and attach */ + regcache_cache_only(wcd->regmap, false); + return regcache_sync(wcd->regmap); + } + + return 0; +} + +/* + * Handle Soundwire out-of-band interrupt event by triggering + * the first irq of the slave_irq irq domain, which then will + * be handled by the regmap_irq threaded irq. + * Looping is to ensure no interrupts were missed in the process. + */ +static int wcd9370_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct wcd937x_sdw_priv *wcd = dev_get_drvdata(&slave->dev); + struct irq_domain *slave_irq = wcd->slave_irq; + u32 sts1, sts2, sts3; + + do { + handle_nested_irq(irq_find_mapping(slave_irq, 0)); + regmap_read(wcd->regmap, WCD937X_DIGITAL_INTR_STATUS_0, &sts1); + regmap_read(wcd->regmap, WCD937X_DIGITAL_INTR_STATUS_1, &sts2); + regmap_read(wcd->regmap, WCD937X_DIGITAL_INTR_STATUS_2, &sts3); + + } while (sts1 || sts2 || sts3); + + return IRQ_HANDLED; +} + +static const struct reg_default wcd937x_defaults[] = { + /* Default values except for Read-Only & Volatile registers */ + { WCD937X_ANA_BIAS, 0x00 }, + { WCD937X_ANA_RX_SUPPLIES, 0x00 }, + { WCD937X_ANA_HPH, 0x0c }, + { WCD937X_ANA_EAR, 0x00 }, + { WCD937X_ANA_EAR_COMPANDER_CTL, 0x02 }, + { WCD937X_ANA_TX_CH1, 0x20 }, + { WCD937X_ANA_TX_CH2, 0x00 }, + { WCD937X_ANA_TX_CH3, 0x20 }, + { WCD937X_ANA_TX_CH3_HPF, 0x00 }, + { WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00 }, + { WCD937X_ANA_MICB3_DSP_EN_LOGIC, 0x00 }, + { WCD937X_ANA_MBHC_MECH, 0x39 }, + { WCD937X_ANA_MBHC_ELECT, 0x08 }, + { WCD937X_ANA_MBHC_ZDET, 0x00 }, + { WCD937X_ANA_MBHC_BTN0, 0x00 }, + { WCD937X_ANA_MBHC_BTN1, 0x10 }, + { WCD937X_ANA_MBHC_BTN2, 0x20 }, + { WCD937X_ANA_MBHC_BTN3, 0x30 }, + { WCD937X_ANA_MBHC_BTN4, 0x40 }, + { WCD937X_ANA_MBHC_BTN5, 0x50 }, + { WCD937X_ANA_MBHC_BTN6, 0x60 }, + { WCD937X_ANA_MBHC_BTN7, 0x70 }, + { WCD937X_ANA_MICB1, 0x10 }, + { WCD937X_ANA_MICB2, 0x10 }, + { WCD937X_ANA_MICB2_RAMP, 0x00 }, + { WCD937X_ANA_MICB3, 0x10 }, + { WCD937X_BIAS_CTL, 0x2a }, + { WCD937X_BIAS_VBG_FINE_ADJ, 0x55 }, + { WCD937X_LDOL_VDDCX_ADJUST, 0x01 }, + { WCD937X_LDOL_DISABLE_LDOL, 0x00 }, + { WCD937X_MBHC_CTL_CLK, 0x00 }, + { WCD937X_MBHC_CTL_ANA, 0x00 }, + { WCD937X_MBHC_CTL_SPARE_1, 0x00 }, + { WCD937X_MBHC_CTL_SPARE_2, 0x00 }, + { WCD937X_MBHC_CTL_BCS, 0x00 }, + { WCD937X_MBHC_TEST_CTL, 0x00 }, + { WCD937X_LDOH_MODE, 0x2b }, + { WCD937X_LDOH_BIAS, 0x68 }, + { WCD937X_LDOH_STB_LOADS, 0x00 }, + { WCD937X_LDOH_SLOWRAMP, 0x50 }, + { WCD937X_MICB1_TEST_CTL_1, 0x1a }, + { WCD937X_MICB1_TEST_CTL_2, 0x18 }, + { WCD937X_MICB1_TEST_CTL_3, 0xa4 }, + { WCD937X_MICB2_TEST_CTL_1, 0x1a }, + { WCD937X_MICB2_TEST_CTL_2, 0x18 }, + { WCD937X_MICB2_TEST_CTL_3, 0xa4 }, + { WCD937X_MICB3_TEST_CTL_1, 0x1a }, + { WCD937X_MICB3_TEST_CTL_2, 0x18 }, + { WCD937X_MICB3_TEST_CTL_3, 0xa4 }, + { WCD937X_TX_COM_ADC_VCM, 0x39 }, + { WCD937X_TX_COM_BIAS_ATEST, 0xc0 }, + { WCD937X_TX_COM_ADC_INT1_IB, 0x6f }, + { WCD937X_TX_COM_ADC_INT2_IB, 0x4f }, + { WCD937X_TX_COM_TXFE_DIV_CTL, 0x2e }, + { WCD937X_TX_COM_TXFE_DIV_START, 0x00 }, + { WCD937X_TX_COM_TXFE_DIV_STOP_9P6M, 0xc7 }, + { WCD937X_TX_COM_TXFE_DIV_STOP_12P288M, 0xff }, + { WCD937X_TX_1_2_TEST_EN, 0xcc }, + { WCD937X_TX_1_2_ADC_IB, 0x09 }, + { WCD937X_TX_1_2_ATEST_REFCTL, 0x0a }, + { WCD937X_TX_1_2_TEST_CTL, 0x38 }, + { WCD937X_TX_1_2_TEST_BLK_EN, 0xff }, + { WCD937X_TX_1_2_TXFE_CLKDIV, 0x00 }, + { WCD937X_TX_3_TEST_EN, 0xcc }, + { WCD937X_TX_3_ADC_IB, 0x09 }, + { WCD937X_TX_3_ATEST_REFCTL, 0x0a }, + { WCD937X_TX_3_TEST_CTL, 0x38 }, + { WCD937X_TX_3_TEST_BLK_EN, 0xff }, + { WCD937X_TX_3_TXFE_CLKDIV, 0x00 }, + { WCD937X_TX_3_SPARE_MONO, 0x00 }, + { WCD937X_CLASSH_MODE_1, 0x40 }, + { WCD937X_CLASSH_MODE_2, 0x3a }, + { WCD937X_CLASSH_MODE_3, 0x00 }, + { WCD937X_CLASSH_CTRL_VCL_1, 0x70 }, + { WCD937X_CLASSH_CTRL_VCL_2, 0x82 }, + { WCD937X_CLASSH_CTRL_CCL_1, 0x31 }, + { WCD937X_CLASSH_CTRL_CCL_2, 0x80 }, + { WCD937X_CLASSH_CTRL_CCL_3, 0x80 }, + { WCD937X_CLASSH_CTRL_CCL_4, 0x51 }, + { WCD937X_CLASSH_CTRL_CCL_5, 0x00 }, + { WCD937X_CLASSH_BUCK_TMUX_A_D, 0x00 }, + { WCD937X_CLASSH_BUCK_SW_DRV_CNTL, 0x77 }, + { WCD937X_CLASSH_SPARE, 0x00 }, + { WCD937X_FLYBACK_EN, 0x4e }, + { WCD937X_FLYBACK_VNEG_CTRL_1, 0x0b }, + { WCD937X_FLYBACK_VNEG_CTRL_2, 0x45 }, + { WCD937X_FLYBACK_VNEG_CTRL_3, 0x74 }, + { WCD937X_FLYBACK_VNEG_CTRL_4, 0x7f }, + { WCD937X_FLYBACK_VNEG_CTRL_5, 0x83 }, + { WCD937X_FLYBACK_VNEG_CTRL_6, 0x98 }, + { WCD937X_FLYBACK_VNEG_CTRL_7, 0xa9 }, + { WCD937X_FLYBACK_VNEG_CTRL_8, 0x68 }, + { WCD937X_FLYBACK_VNEG_CTRL_9, 0x64 }, + { WCD937X_FLYBACK_VNEGDAC_CTRL_1, 0xed }, + { WCD937X_FLYBACK_VNEGDAC_CTRL_2, 0xf0 }, + { WCD937X_FLYBACK_VNEGDAC_CTRL_3, 0xa6 }, + { WCD937X_FLYBACK_CTRL_1, 0x65 }, + { WCD937X_FLYBACK_TEST_CTL, 0x00 }, + { WCD937X_RX_AUX_SW_CTL, 0x00 }, + { WCD937X_RX_PA_AUX_IN_CONN, 0x00 }, + { WCD937X_RX_TIMER_DIV, 0x32 }, + { WCD937X_RX_OCP_CTL, 0x1f }, + { WCD937X_RX_OCP_COUNT, 0x77 }, + { WCD937X_RX_BIAS_EAR_DAC, 0xa0 }, + { WCD937X_RX_BIAS_EAR_AMP, 0xaa }, + { WCD937X_RX_BIAS_HPH_LDO, 0xa9 }, + { WCD937X_RX_BIAS_HPH_PA, 0xaa }, + { WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8a }, + { WCD937X_RX_BIAS_HPH_RDAC_LDO, 0x88 }, + { WCD937X_RX_BIAS_HPH_CNP1, 0x82 }, + { WCD937X_RX_BIAS_HPH_LOWPOWER, 0x82 }, + { WCD937X_RX_BIAS_AUX_DAC, 0xa0 }, + { WCD937X_RX_BIAS_AUX_AMP, 0xaa }, + { WCD937X_RX_BIAS_VNEGDAC_BLEEDER, 0x50 }, + { WCD937X_RX_BIAS_MISC, 0x00 }, + { WCD937X_RX_BIAS_BUCK_RST, 0x08 }, + { WCD937X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44 }, + { WCD937X_RX_BIAS_FLYB_ERRAMP, 0x40 }, + { WCD937X_RX_BIAS_FLYB_BUFF, 0xaa }, + { WCD937X_RX_BIAS_FLYB_MID_RST, 0x14 }, + { WCD937X_HPH_CNP_EN, 0x80 }, + { WCD937X_HPH_CNP_WG_CTL, 0x9a }, + { WCD937X_HPH_CNP_WG_TIME, 0x14 }, + { WCD937X_HPH_OCP_CTL, 0x28 }, + { WCD937X_HPH_AUTO_CHOP, 0x16 }, + { WCD937X_HPH_CHOP_CTL, 0x83 }, + { WCD937X_HPH_PA_CTL1, 0x46 }, + { WCD937X_HPH_PA_CTL2, 0x50 }, + { WCD937X_HPH_L_EN, 0x80 }, + { WCD937X_HPH_L_TEST, 0xe0 }, + { WCD937X_HPH_L_ATEST, 0x50 }, + { WCD937X_HPH_R_EN, 0x80 }, + { WCD937X_HPH_R_TEST, 0xe0 }, + { WCD937X_HPH_R_ATEST, 0x54 }, + { WCD937X_HPH_RDAC_CLK_CTL1, 0x99 }, + { WCD937X_HPH_RDAC_CLK_CTL2, 0x9b }, + { WCD937X_HPH_RDAC_LDO_CTL, 0x33 }, + { WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 }, + { WCD937X_HPH_REFBUFF_UHQA_CTL, 0xa8 }, + { WCD937X_HPH_REFBUFF_LP_CTL, 0x0e }, + { WCD937X_HPH_L_DAC_CTL, 0x20 }, + { WCD937X_HPH_R_DAC_CTL, 0x20 }, + { WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55 }, + { WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0x19 }, + { WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1, 0xa0 }, + { WCD937X_EAR_EAR_EN_REG, 0x22 }, + { WCD937X_EAR_EAR_PA_CON, 0x44 }, + { WCD937X_EAR_EAR_SP_CON, 0xdb }, + { WCD937X_EAR_EAR_DAC_CON, 0x80 }, + { WCD937X_EAR_EAR_CNP_FSM_CON, 0xb2 }, + { WCD937X_EAR_TEST_CTL, 0x00 }, + { WCD937X_ANA_NEW_PAGE_REGISTER, 0x00 }, + { WCD937X_HPH_NEW_ANA_HPH2, 0x00 }, + { WCD937X_HPH_NEW_ANA_HPH3, 0x00 }, + { WCD937X_SLEEP_CTL, 0x16 }, + { WCD937X_SLEEP_WATCHDOG_CTL, 0x00 }, + { WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00 }, + { WCD937X_MBHC_NEW_CTL_1, 0x02 }, + { WCD937X_MBHC_NEW_CTL_2, 0x05 }, + { WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0xe9 }, + { WCD937X_MBHC_NEW_ZDET_ANA_CTL, 0x0f }, + { WCD937X_MBHC_NEW_ZDET_RAMP_CTL, 0x00 }, + { WCD937X_TX_NEW_TX_CH2_SEL, 0x00 }, + { WCD937X_AUX_AUXPA, 0x00 }, + { WCD937X_LDORXTX_MODE, 0x0c }, + { WCD937X_LDORXTX_CONFIG, 0x10 }, + { WCD937X_DIE_CRACK_DIE_CRK_DET_EN, 0x00 }, + { WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40 }, + { WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81 }, + { WCD937X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 }, + { WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 }, + { WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81 }, + { WCD937X_HPH_NEW_INT_PA_MISC1, 0x22 }, + { WCD937X_HPH_NEW_INT_PA_MISC2, 0x00 }, + { WCD937X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 }, + { WCD937X_HPH_NEW_INT_HPH_TIMER1, 0xfe }, + { WCD937X_HPH_NEW_INT_HPH_TIMER2, 0x02 }, + { WCD937X_HPH_NEW_INT_HPH_TIMER3, 0x4e }, + { WCD937X_HPH_NEW_INT_HPH_TIMER4, 0x54 }, + { WCD937X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 }, + { WCD937X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 }, + { WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62 }, + { WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01 }, + { WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11 }, + { WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57 }, + { WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01 }, + { WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00 }, + { WCD937X_MBHC_NEW_INT_SPARE_2, 0x00 }, + { WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON, 0xa8 }, + { WCD937X_EAR_INT_NEW_CNP_VCM_CON1, 0x42 }, + { WCD937X_EAR_INT_NEW_CNP_VCM_CON2, 0x22 }, + { WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS, 0x00 }, + { WCD937X_AUX_INT_EN_REG, 0x00 }, + { WCD937X_AUX_INT_PA_CTRL, 0x06 }, + { WCD937X_AUX_INT_SP_CTRL, 0xd2 }, + { WCD937X_AUX_INT_DAC_CTRL, 0x80 }, + { WCD937X_AUX_INT_CLK_CTRL, 0x50 }, + { WCD937X_AUX_INT_TEST_CTRL, 0x00 }, + { WCD937X_AUX_INT_STATUS_REG, 0x00 }, + { WCD937X_AUX_INT_MISC, 0x00 }, + { WCD937X_LDORXTX_INT_BIAS, 0x6e }, + { WCD937X_LDORXTX_INT_STB_LOADS_DTEST, 0x50 }, + { WCD937X_LDORXTX_INT_TEST0, 0x1c }, + { WCD937X_LDORXTX_INT_STARTUP_TIMER, 0xff }, + { WCD937X_LDORXTX_INT_TEST1, 0x1f }, + { WCD937X_LDORXTX_INT_STATUS, 0x00 }, + { WCD937X_SLEEP_INT_WATCHDOG_CTL_1, 0x0a }, + { WCD937X_SLEEP_INT_WATCHDOG_CTL_2, 0x0a }, + { WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02 }, + { WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60 }, + { WCD937X_DIGITAL_PAGE_REGISTER, 0x00 }, + { WCD937X_DIGITAL_CDC_RST_CTL, 0x03 }, + { WCD937X_DIGITAL_TOP_CLK_CFG, 0x00 }, + { WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x00 }, + { WCD937X_DIGITAL_SWR_RST_EN, 0x00 }, + { WCD937X_DIGITAL_CDC_PATH_MODE, 0x55 }, + { WCD937X_DIGITAL_CDC_RX_RST, 0x00 }, + { WCD937X_DIGITAL_CDC_RX0_CTL, 0xfc }, + { WCD937X_DIGITAL_CDC_RX1_CTL, 0xfc }, + { WCD937X_DIGITAL_CDC_RX2_CTL, 0xfc }, + { WCD937X_DIGITAL_DEM_BYPASS_DATA0, 0x55 }, + { WCD937X_DIGITAL_DEM_BYPASS_DATA1, 0x55 }, + { WCD937X_DIGITAL_DEM_BYPASS_DATA2, 0x55 }, + { WCD937X_DIGITAL_DEM_BYPASS_DATA3, 0x01 }, + { WCD937X_DIGITAL_CDC_COMP_CTL_0, 0x00 }, + { WCD937X_DIGITAL_CDC_RX_DELAY_CTL, 0x66 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A3_0, 0xac }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1a }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A5_0, 0xbc }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A6_0, 0xc7 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A7_0, 0xf8 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_C_0, 0x47 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_C_1, 0x43 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_C_2, 0xb1 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_C_3, 0x17 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R1, 0x4b }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R2, 0x26 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R3, 0x32 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R4, 0x57 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R5, 0x63 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R6, 0x7c }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R7, 0x57 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A1_0, 0x00 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A1_1, 0x01 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A2_0, 0x96 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A2_1, 0x09 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A3_0, 0xab }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A3_1, 0x05 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A4_0, 0x1c }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A4_1, 0x02 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A5_0, 0x17 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A5_1, 0x02 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A6_0, 0xaa }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A7_0, 0xe3 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_C_0, 0x69 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_C_1, 0x54 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_C_2, 0x02 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_C_3, 0x15 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R1, 0xa4 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R2, 0xb5 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R3, 0x86 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R4, 0x85 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R5, 0xaa }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R6, 0xe2 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R7, 0x62 }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55 }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xa9 }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3d }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2e }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01 }, + { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0, 0x00 }, + { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1, 0xfc }, + { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2, 0x01 }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_AUX_GAIN_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_SWR_CLH, 0x00 }, + { WCD937X_DIGITAL_SWR_CLH_BYP, 0x00 }, + { WCD937X_DIGITAL_CDC_TX0_CTL, 0x68 }, + { WCD937X_DIGITAL_CDC_TX1_CTL, 0x68 }, + { WCD937X_DIGITAL_CDC_TX2_CTL, 0x68 }, + { WCD937X_DIGITAL_CDC_TX_RST, 0x00 }, + { WCD937X_DIGITAL_CDC_REQ_CTL, 0x01 }, + { WCD937X_DIGITAL_CDC_AMIC_CTL, 0x07 }, + { WCD937X_DIGITAL_CDC_DMIC_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_DMIC1_CTL, 0x01 }, + { WCD937X_DIGITAL_CDC_DMIC2_CTL, 0x01 }, + { WCD937X_DIGITAL_CDC_DMIC3_CTL, 0x01 }, + { WCD937X_DIGITAL_EFUSE_CTL, 0x2b }, + { WCD937X_DIGITAL_EFUSE_PRG_CTL, 0x00 }, + { WCD937X_DIGITAL_EFUSE_TEST_CTL_0, 0x00 }, + { WCD937X_DIGITAL_EFUSE_TEST_CTL_1, 0x00 }, + { WCD937X_DIGITAL_PDM_WD_CTL0, 0x00 }, + { WCD937X_DIGITAL_PDM_WD_CTL1, 0x00 }, + { WCD937X_DIGITAL_PDM_WD_CTL2, 0x00 }, + { WCD937X_DIGITAL_INTR_MODE, 0x00 }, + { WCD937X_DIGITAL_INTR_MASK_0, 0xff }, + { WCD937X_DIGITAL_INTR_MASK_1, 0xff }, + { WCD937X_DIGITAL_INTR_MASK_2, 0x0f }, + { WCD937X_DIGITAL_INTR_CLEAR_0, 0x00 }, + { WCD937X_DIGITAL_INTR_CLEAR_1, 0x00 }, + { WCD937X_DIGITAL_INTR_CLEAR_2, 0x00 }, + { WCD937X_DIGITAL_INTR_LEVEL_0, 0x00 }, + { WCD937X_DIGITAL_INTR_LEVEL_1, 0x00 }, + { WCD937X_DIGITAL_INTR_LEVEL_2, 0x00 }, + { WCD937X_DIGITAL_INTR_SET_0, 0x00 }, + { WCD937X_DIGITAL_INTR_SET_1, 0x00 }, + { WCD937X_DIGITAL_INTR_SET_2, 0x00 }, + { WCD937X_DIGITAL_INTR_TEST_0, 0x00 }, + { WCD937X_DIGITAL_INTR_TEST_1, 0x00 }, + { WCD937X_DIGITAL_INTR_TEST_2, 0x00 }, + { WCD937X_DIGITAL_CDC_CONN_RX0_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_CONN_RX1_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_CONN_RX2_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_CONN_TX_CTL, 0x00 }, + { WCD937X_DIGITAL_LOOP_BACK_MODE, 0x00 }, + { WCD937X_DIGITAL_SWR_DAC_TEST, 0x00 }, + { WCD937X_DIGITAL_SWR_HM_TEST_RX_0, 0x40 }, + { WCD937X_DIGITAL_SWR_HM_TEST_TX_0, 0x40 }, + { WCD937X_DIGITAL_SWR_HM_TEST_RX_1, 0x00 }, + { WCD937X_DIGITAL_SWR_HM_TEST_TX_1, 0x00 }, + { WCD937X_DIGITAL_PAD_CTL_PDM_RX0, 0xf1 }, + { WCD937X_DIGITAL_PAD_CTL_PDM_RX1, 0xf1 }, + { WCD937X_DIGITAL_PAD_CTL_PDM_TX0, 0xf1 }, + { WCD937X_DIGITAL_PAD_CTL_PDM_TX1, 0xf1 }, + { WCD937X_DIGITAL_PAD_INP_DIS_0, 0x00 }, + { WCD937X_DIGITAL_PAD_INP_DIS_1, 0x00 }, + { WCD937X_DIGITAL_DRIVE_STRENGTH_0, 0x00 }, + { WCD937X_DIGITAL_DRIVE_STRENGTH_1, 0x00 }, + { WCD937X_DIGITAL_DRIVE_STRENGTH_2, 0x00 }, + { WCD937X_DIGITAL_RX_DATA_EDGE_CTL, 0x1f }, + { WCD937X_DIGITAL_TX_DATA_EDGE_CTL, 0x10 }, + { WCD937X_DIGITAL_GPIO_MODE, 0x00 }, + { WCD937X_DIGITAL_PIN_CTL_OE, 0x00 }, + { WCD937X_DIGITAL_PIN_CTL_DATA_0, 0x00 }, + { WCD937X_DIGITAL_PIN_CTL_DATA_1, 0x00 }, + { WCD937X_DIGITAL_DIG_DEBUG_CTL, 0x00 }, + { WCD937X_DIGITAL_DIG_DEBUG_EN, 0x00 }, + { WCD937X_DIGITAL_ANA_CSR_DBG_ADD, 0x00 }, + { WCD937X_DIGITAL_ANA_CSR_DBG_CTL, 0x48 }, + { WCD937X_DIGITAL_SSP_DBG, 0x00 }, + { WCD937X_DIGITAL_SPARE_0, 0x00 }, + { WCD937X_DIGITAL_SPARE_1, 0x00 }, + { WCD937X_DIGITAL_SPARE_2, 0x00 }, +}; + +static bool wcd937x_rdwr_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD937X_ANA_BIAS: + case WCD937X_ANA_RX_SUPPLIES: + case WCD937X_ANA_HPH: + case WCD937X_ANA_EAR: + case WCD937X_ANA_EAR_COMPANDER_CTL: + case WCD937X_ANA_TX_CH1: + case WCD937X_ANA_TX_CH2: + case WCD937X_ANA_TX_CH3: + case WCD937X_ANA_TX_CH3_HPF: + case WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC: + case WCD937X_ANA_MICB3_DSP_EN_LOGIC: + case WCD937X_ANA_MBHC_MECH: + case WCD937X_ANA_MBHC_ELECT: + case WCD937X_ANA_MBHC_ZDET: + case WCD937X_ANA_MBHC_BTN0: + case WCD937X_ANA_MBHC_BTN1: + case WCD937X_ANA_MBHC_BTN2: + case WCD937X_ANA_MBHC_BTN3: + case WCD937X_ANA_MBHC_BTN4: + case WCD937X_ANA_MBHC_BTN5: + case WCD937X_ANA_MBHC_BTN6: + case WCD937X_ANA_MBHC_BTN7: + case WCD937X_ANA_MICB1: + case WCD937X_ANA_MICB2: + case WCD937X_ANA_MICB2_RAMP: + case WCD937X_ANA_MICB3: + case WCD937X_BIAS_CTL: + case WCD937X_BIAS_VBG_FINE_ADJ: + case WCD937X_LDOL_VDDCX_ADJUST: + case WCD937X_LDOL_DISABLE_LDOL: + case WCD937X_MBHC_CTL_CLK: + case WCD937X_MBHC_CTL_ANA: + case WCD937X_MBHC_CTL_SPARE_1: + case WCD937X_MBHC_CTL_SPARE_2: + case WCD937X_MBHC_CTL_BCS: + case WCD937X_MBHC_TEST_CTL: + case WCD937X_LDOH_MODE: + case WCD937X_LDOH_BIAS: + case WCD937X_LDOH_STB_LOADS: + case WCD937X_LDOH_SLOWRAMP: + case WCD937X_MICB1_TEST_CTL_1: + case WCD937X_MICB1_TEST_CTL_2: + case WCD937X_MICB1_TEST_CTL_3: + case WCD937X_MICB2_TEST_CTL_1: + case WCD937X_MICB2_TEST_CTL_2: + case WCD937X_MICB2_TEST_CTL_3: + case WCD937X_MICB3_TEST_CTL_1: + case WCD937X_MICB3_TEST_CTL_2: + case WCD937X_MICB3_TEST_CTL_3: + case WCD937X_TX_COM_ADC_VCM: + case WCD937X_TX_COM_BIAS_ATEST: + case WCD937X_TX_COM_ADC_INT1_IB: + case WCD937X_TX_COM_ADC_INT2_IB: + case WCD937X_TX_COM_TXFE_DIV_CTL: + case WCD937X_TX_COM_TXFE_DIV_START: + case WCD937X_TX_COM_TXFE_DIV_STOP_9P6M: + case WCD937X_TX_COM_TXFE_DIV_STOP_12P288M: + case WCD937X_TX_1_2_TEST_EN: + case WCD937X_TX_1_2_ADC_IB: + case WCD937X_TX_1_2_ATEST_REFCTL: + case WCD937X_TX_1_2_TEST_CTL: + case WCD937X_TX_1_2_TEST_BLK_EN: + case WCD937X_TX_1_2_TXFE_CLKDIV: + case WCD937X_TX_3_TEST_EN: + case WCD937X_TX_3_ADC_IB: + case WCD937X_TX_3_ATEST_REFCTL: + case WCD937X_TX_3_TEST_CTL: + case WCD937X_TX_3_TEST_BLK_EN: + case WCD937X_TX_3_TXFE_CLKDIV: + case WCD937X_CLASSH_MODE_1: + case WCD937X_CLASSH_MODE_2: + case WCD937X_CLASSH_MODE_3: + case WCD937X_CLASSH_CTRL_VCL_1: + case WCD937X_CLASSH_CTRL_VCL_2: + case WCD937X_CLASSH_CTRL_CCL_1: + case WCD937X_CLASSH_CTRL_CCL_2: + case WCD937X_CLASSH_CTRL_CCL_3: + case WCD937X_CLASSH_CTRL_CCL_4: + case WCD937X_CLASSH_CTRL_CCL_5: + case WCD937X_CLASSH_BUCK_TMUX_A_D: + case WCD937X_CLASSH_BUCK_SW_DRV_CNTL: + case WCD937X_CLASSH_SPARE: + case WCD937X_FLYBACK_EN: + case WCD937X_FLYBACK_VNEG_CTRL_1: + case WCD937X_FLYBACK_VNEG_CTRL_2: + case WCD937X_FLYBACK_VNEG_CTRL_3: + case WCD937X_FLYBACK_VNEG_CTRL_4: + case WCD937X_FLYBACK_VNEG_CTRL_5: + case WCD937X_FLYBACK_VNEG_CTRL_6: + case WCD937X_FLYBACK_VNEG_CTRL_7: + case WCD937X_FLYBACK_VNEG_CTRL_8: + case WCD937X_FLYBACK_VNEG_CTRL_9: + case WCD937X_FLYBACK_VNEGDAC_CTRL_1: + case WCD937X_FLYBACK_VNEGDAC_CTRL_2: + case WCD937X_FLYBACK_VNEGDAC_CTRL_3: + case WCD937X_FLYBACK_CTRL_1: + case WCD937X_FLYBACK_TEST_CTL: + case WCD937X_RX_AUX_SW_CTL: + case WCD937X_RX_PA_AUX_IN_CONN: + case WCD937X_RX_TIMER_DIV: + case WCD937X_RX_OCP_CTL: + case WCD937X_RX_OCP_COUNT: + case WCD937X_RX_BIAS_EAR_DAC: + case WCD937X_RX_BIAS_EAR_AMP: + case WCD937X_RX_BIAS_HPH_LDO: + case WCD937X_RX_BIAS_HPH_PA: + case WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2: + case WCD937X_RX_BIAS_HPH_RDAC_LDO: + case WCD937X_RX_BIAS_HPH_CNP1: + case WCD937X_RX_BIAS_HPH_LOWPOWER: + case WCD937X_RX_BIAS_AUX_DAC: + case WCD937X_RX_BIAS_AUX_AMP: + case WCD937X_RX_BIAS_VNEGDAC_BLEEDER: + case WCD937X_RX_BIAS_MISC: + case WCD937X_RX_BIAS_BUCK_RST: + case WCD937X_RX_BIAS_BUCK_VREF_ERRAMP: + case WCD937X_RX_BIAS_FLYB_ERRAMP: + case WCD937X_RX_BIAS_FLYB_BUFF: + case WCD937X_RX_BIAS_FLYB_MID_RST: + case WCD937X_HPH_CNP_EN: + case WCD937X_HPH_CNP_WG_CTL: + case WCD937X_HPH_CNP_WG_TIME: + case WCD937X_HPH_OCP_CTL: + case WCD937X_HPH_AUTO_CHOP: + case WCD937X_HPH_CHOP_CTL: + case WCD937X_HPH_PA_CTL1: + case WCD937X_HPH_PA_CTL2: + case WCD937X_HPH_L_EN: + case WCD937X_HPH_L_TEST: + case WCD937X_HPH_L_ATEST: + case WCD937X_HPH_R_EN: + case WCD937X_HPH_R_TEST: + case WCD937X_HPH_R_ATEST: + case WCD937X_HPH_RDAC_CLK_CTL1: + case WCD937X_HPH_RDAC_CLK_CTL2: + case WCD937X_HPH_RDAC_LDO_CTL: + case WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL: + case WCD937X_HPH_REFBUFF_UHQA_CTL: + case WCD937X_HPH_REFBUFF_LP_CTL: + case WCD937X_HPH_L_DAC_CTL: + case WCD937X_HPH_R_DAC_CTL: + case WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL: + case WCD937X_HPH_SURGE_HPHLR_SURGE_EN: + case WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1: + case WCD937X_EAR_EAR_EN_REG: + case WCD937X_EAR_EAR_PA_CON: + case WCD937X_EAR_EAR_SP_CON: + case WCD937X_EAR_EAR_DAC_CON: + case WCD937X_EAR_EAR_CNP_FSM_CON: + case WCD937X_EAR_TEST_CTL: + case WCD937X_HPH_NEW_ANA_HPH2: + case WCD937X_HPH_NEW_ANA_HPH3: + case WCD937X_SLEEP_CTL: + case WCD937X_SLEEP_WATCHDOG_CTL: + case WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL: + case WCD937X_MBHC_NEW_CTL_1: + case WCD937X_MBHC_NEW_CTL_2: + case WCD937X_MBHC_NEW_PLUG_DETECT_CTL: + case WCD937X_MBHC_NEW_ZDET_ANA_CTL: + case WCD937X_MBHC_NEW_ZDET_RAMP_CTL: + case WCD937X_TX_NEW_TX_CH2_SEL: + case WCD937X_AUX_AUXPA: + case WCD937X_LDORXTX_MODE: + case WCD937X_LDORXTX_CONFIG: + case WCD937X_DIE_CRACK_DIE_CRK_DET_EN: + case WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL: + case WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L: + case WCD937X_HPH_NEW_INT_RDAC_VREF_CTL: + case WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL: + case WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R: + case WCD937X_HPH_NEW_INT_PA_MISC1: + case WCD937X_HPH_NEW_INT_PA_MISC2: + case WCD937X_HPH_NEW_INT_PA_RDAC_MISC: + case WCD937X_HPH_NEW_INT_HPH_TIMER1: + case WCD937X_HPH_NEW_INT_HPH_TIMER2: + case WCD937X_HPH_NEW_INT_HPH_TIMER3: + case WCD937X_HPH_NEW_INT_HPH_TIMER4: + case WCD937X_HPH_NEW_INT_PA_RDAC_MISC2: + case WCD937X_HPH_NEW_INT_PA_RDAC_MISC3: + case WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI: + case WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP: + case WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP: + case WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL: + case WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL: + case WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT: + case WCD937X_MBHC_NEW_INT_SPARE_2: + case WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON: + case WCD937X_EAR_INT_NEW_CNP_VCM_CON1: + case WCD937X_EAR_INT_NEW_CNP_VCM_CON2: + case WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS: + case WCD937X_AUX_INT_EN_REG: + case WCD937X_AUX_INT_PA_CTRL: + case WCD937X_AUX_INT_SP_CTRL: + case WCD937X_AUX_INT_DAC_CTRL: + case WCD937X_AUX_INT_CLK_CTRL: + case WCD937X_AUX_INT_TEST_CTRL: + case WCD937X_AUX_INT_MISC: + case WCD937X_LDORXTX_INT_BIAS: + case WCD937X_LDORXTX_INT_STB_LOADS_DTEST: + case WCD937X_LDORXTX_INT_TEST0: + case WCD937X_LDORXTX_INT_STARTUP_TIMER: + case WCD937X_LDORXTX_INT_TEST1: + case WCD937X_SLEEP_INT_WATCHDOG_CTL_1: + case WCD937X_SLEEP_INT_WATCHDOG_CTL_2: + case WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1: + case WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2: + case WCD937X_DIGITAL_CDC_RST_CTL: + case WCD937X_DIGITAL_TOP_CLK_CFG: + case WCD937X_DIGITAL_CDC_ANA_CLK_CTL: + case WCD937X_DIGITAL_CDC_DIG_CLK_CTL: + case WCD937X_DIGITAL_SWR_RST_EN: + case WCD937X_DIGITAL_CDC_PATH_MODE: + case WCD937X_DIGITAL_CDC_RX_RST: + case WCD937X_DIGITAL_CDC_RX0_CTL: + case WCD937X_DIGITAL_CDC_RX1_CTL: + case WCD937X_DIGITAL_CDC_RX2_CTL: + case WCD937X_DIGITAL_DEM_BYPASS_DATA0: + case WCD937X_DIGITAL_DEM_BYPASS_DATA1: + case WCD937X_DIGITAL_DEM_BYPASS_DATA2: + case WCD937X_DIGITAL_DEM_BYPASS_DATA3: + case WCD937X_DIGITAL_CDC_COMP_CTL_0: + case WCD937X_DIGITAL_CDC_RX_DELAY_CTL: + case WCD937X_DIGITAL_CDC_HPH_DSM_A1_0: + case WCD937X_DIGITAL_CDC_HPH_DSM_A1_1: + case WCD937X_DIGITAL_CDC_HPH_DSM_A2_0: + case WCD937X_DIGITAL_CDC_HPH_DSM_A2_1: + case WCD937X_DIGITAL_CDC_HPH_DSM_A3_0: + case WCD937X_DIGITAL_CDC_HPH_DSM_A3_1: + case WCD937X_DIGITAL_CDC_HPH_DSM_A4_0: + case WCD937X_DIGITAL_CDC_HPH_DSM_A4_1: + case WCD937X_DIGITAL_CDC_HPH_DSM_A5_0: + case WCD937X_DIGITAL_CDC_HPH_DSM_A5_1: + case WCD937X_DIGITAL_CDC_HPH_DSM_A6_0: + case WCD937X_DIGITAL_CDC_HPH_DSM_A7_0: + case WCD937X_DIGITAL_CDC_HPH_DSM_C_0: + case WCD937X_DIGITAL_CDC_HPH_DSM_C_1: + case WCD937X_DIGITAL_CDC_HPH_DSM_C_2: + case WCD937X_DIGITAL_CDC_HPH_DSM_C_3: + case WCD937X_DIGITAL_CDC_HPH_DSM_R1: + case WCD937X_DIGITAL_CDC_HPH_DSM_R2: + case WCD937X_DIGITAL_CDC_HPH_DSM_R3: + case WCD937X_DIGITAL_CDC_HPH_DSM_R4: + case WCD937X_DIGITAL_CDC_HPH_DSM_R5: + case WCD937X_DIGITAL_CDC_HPH_DSM_R6: + case WCD937X_DIGITAL_CDC_HPH_DSM_R7: + case WCD937X_DIGITAL_CDC_AUX_DSM_A1_0: + case WCD937X_DIGITAL_CDC_AUX_DSM_A1_1: + case WCD937X_DIGITAL_CDC_AUX_DSM_A2_0: + case WCD937X_DIGITAL_CDC_AUX_DSM_A2_1: + case WCD937X_DIGITAL_CDC_AUX_DSM_A3_0: + case WCD937X_DIGITAL_CDC_AUX_DSM_A3_1: + case WCD937X_DIGITAL_CDC_AUX_DSM_A4_0: + case WCD937X_DIGITAL_CDC_AUX_DSM_A4_1: + case WCD937X_DIGITAL_CDC_AUX_DSM_A5_0: + case WCD937X_DIGITAL_CDC_AUX_DSM_A5_1: + case WCD937X_DIGITAL_CDC_AUX_DSM_A6_0: + case WCD937X_DIGITAL_CDC_AUX_DSM_A7_0: + case WCD937X_DIGITAL_CDC_AUX_DSM_C_0: + case WCD937X_DIGITAL_CDC_AUX_DSM_C_1: + case WCD937X_DIGITAL_CDC_AUX_DSM_C_2: + case WCD937X_DIGITAL_CDC_AUX_DSM_C_3: + case WCD937X_DIGITAL_CDC_AUX_DSM_R1: + case WCD937X_DIGITAL_CDC_AUX_DSM_R2: + case WCD937X_DIGITAL_CDC_AUX_DSM_R3: + case WCD937X_DIGITAL_CDC_AUX_DSM_R4: + case WCD937X_DIGITAL_CDC_AUX_DSM_R5: + case WCD937X_DIGITAL_CDC_AUX_DSM_R6: + case WCD937X_DIGITAL_CDC_AUX_DSM_R7: + case WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0: + case WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1: + case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0: + case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1: + case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2: + case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0: + case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1: + case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2: + case WCD937X_DIGITAL_CDC_HPH_GAIN_CTL: + case WCD937X_DIGITAL_CDC_AUX_GAIN_CTL: + case WCD937X_DIGITAL_CDC_EAR_PATH_CTL: + case WCD937X_DIGITAL_CDC_SWR_CLH: + case WCD937X_DIGITAL_SWR_CLH_BYP: + case WCD937X_DIGITAL_CDC_TX0_CTL: + case WCD937X_DIGITAL_CDC_TX1_CTL: + case WCD937X_DIGITAL_CDC_TX2_CTL: + case WCD937X_DIGITAL_CDC_TX_RST: + case WCD937X_DIGITAL_CDC_REQ_CTL: + case WCD937X_DIGITAL_CDC_AMIC_CTL: + case WCD937X_DIGITAL_CDC_DMIC_CTL: + case WCD937X_DIGITAL_CDC_DMIC1_CTL: + case WCD937X_DIGITAL_CDC_DMIC2_CTL: + case WCD937X_DIGITAL_CDC_DMIC3_CTL: + case WCD937X_DIGITAL_EFUSE_CTL: + case WCD937X_DIGITAL_EFUSE_PRG_CTL: + case WCD937X_DIGITAL_EFUSE_TEST_CTL_0: + case WCD937X_DIGITAL_EFUSE_TEST_CTL_1: + case WCD937X_DIGITAL_PDM_WD_CTL0: + case WCD937X_DIGITAL_PDM_WD_CTL1: + case WCD937X_DIGITAL_PDM_WD_CTL2: + case WCD937X_DIGITAL_INTR_MODE: + case WCD937X_DIGITAL_INTR_MASK_0: + case WCD937X_DIGITAL_INTR_MASK_1: + case WCD937X_DIGITAL_INTR_MASK_2: + case WCD937X_DIGITAL_INTR_CLEAR_0: + case WCD937X_DIGITAL_INTR_CLEAR_1: + case WCD937X_DIGITAL_INTR_CLEAR_2: + case WCD937X_DIGITAL_INTR_LEVEL_0: + case WCD937X_DIGITAL_INTR_LEVEL_1: + case WCD937X_DIGITAL_INTR_LEVEL_2: + case WCD937X_DIGITAL_INTR_SET_0: + case WCD937X_DIGITAL_INTR_SET_1: + case WCD937X_DIGITAL_INTR_SET_2: + case WCD937X_DIGITAL_INTR_TEST_0: + case WCD937X_DIGITAL_INTR_TEST_1: + case WCD937X_DIGITAL_INTR_TEST_2: + case WCD937X_DIGITAL_CDC_CONN_RX0_CTL: + case WCD937X_DIGITAL_CDC_CONN_RX1_CTL: + case WCD937X_DIGITAL_CDC_CONN_RX2_CTL: + case WCD937X_DIGITAL_CDC_CONN_TX_CTL: + case WCD937X_DIGITAL_LOOP_BACK_MODE: + case WCD937X_DIGITAL_SWR_DAC_TEST: + case WCD937X_DIGITAL_SWR_HM_TEST_RX_0: + case WCD937X_DIGITAL_SWR_HM_TEST_TX_0: + case WCD937X_DIGITAL_SWR_HM_TEST_RX_1: + case WCD937X_DIGITAL_SWR_HM_TEST_TX_1: + case WCD937X_DIGITAL_SWR_HM_TEST: + case WCD937X_DIGITAL_PAD_CTL_PDM_RX0: + case WCD937X_DIGITAL_PAD_CTL_PDM_RX1: + case WCD937X_DIGITAL_PAD_CTL_PDM_TX0: + case WCD937X_DIGITAL_PAD_CTL_PDM_TX1: + case WCD937X_DIGITAL_PAD_INP_DIS_0: + case WCD937X_DIGITAL_PAD_INP_DIS_1: + case WCD937X_DIGITAL_DRIVE_STRENGTH_0: + case WCD937X_DIGITAL_DRIVE_STRENGTH_1: + case WCD937X_DIGITAL_DRIVE_STRENGTH_2: + case WCD937X_DIGITAL_RX_DATA_EDGE_CTL: + case WCD937X_DIGITAL_TX_DATA_EDGE_CTL: + case WCD937X_DIGITAL_GPIO_MODE: + case WCD937X_DIGITAL_PIN_CTL_OE: + case WCD937X_DIGITAL_PIN_CTL_DATA_0: + case WCD937X_DIGITAL_PIN_CTL_DATA_1: + case WCD937X_DIGITAL_PIN_STATUS_0: + case WCD937X_DIGITAL_PIN_STATUS_1: + case WCD937X_DIGITAL_DIG_DEBUG_CTL: + case WCD937X_DIGITAL_DIG_DEBUG_EN: + case WCD937X_DIGITAL_ANA_CSR_DBG_ADD: + case WCD937X_DIGITAL_ANA_CSR_DBG_CTL: + case WCD937X_DIGITAL_SSP_DBG: + case WCD937X_DIGITAL_MODE_STATUS_0: + case WCD937X_DIGITAL_MODE_STATUS_1: + case WCD937X_DIGITAL_SPARE_0: + case WCD937X_DIGITAL_SPARE_1: + case WCD937X_DIGITAL_SPARE_2: + return true; + } + + return false; +} + +static bool wcd937x_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD937X_ANA_MBHC_RESULT_1: + case WCD937X_ANA_MBHC_RESULT_2: + case WCD937X_ANA_MBHC_RESULT_3: + case WCD937X_MBHC_MOISTURE_DET_FSM_STATUS: + case WCD937X_TX_1_2_SAR2_ERR: + case WCD937X_TX_1_2_SAR1_ERR: + case WCD937X_TX_3_SPARE_MONO: + case WCD937X_TX_3_SAR1_ERR: + case WCD937X_HPH_L_STATUS: + case WCD937X_HPH_R_STATUS: + case WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS: + case WCD937X_EAR_STATUS_REG_1: + case WCD937X_EAR_STATUS_REG_2: + case WCD937X_MBHC_NEW_FSM_STATUS: + case WCD937X_MBHC_NEW_ADC_RESULT: + case WCD937X_DIE_CRACK_DIE_CRK_DET_OUT: + case WCD937X_AUX_INT_STATUS_REG: + case WCD937X_LDORXTX_INT_STATUS: + case WCD937X_DIGITAL_CHIP_ID0: + case WCD937X_DIGITAL_CHIP_ID1: + case WCD937X_DIGITAL_CHIP_ID2: + case WCD937X_DIGITAL_CHIP_ID3: + case WCD937X_DIGITAL_EFUSE_T_DATA_0: + case WCD937X_DIGITAL_EFUSE_T_DATA_1: + case WCD937X_DIGITAL_INTR_STATUS_0: + case WCD937X_DIGITAL_INTR_STATUS_1: + case WCD937X_DIGITAL_INTR_STATUS_2: + case WCD937X_DIGITAL_EFUSE_REG_0: + case WCD937X_DIGITAL_EFUSE_REG_1: + case WCD937X_DIGITAL_EFUSE_REG_2: + case WCD937X_DIGITAL_EFUSE_REG_3: + case WCD937X_DIGITAL_EFUSE_REG_4: + case WCD937X_DIGITAL_EFUSE_REG_5: + case WCD937X_DIGITAL_EFUSE_REG_6: + case WCD937X_DIGITAL_EFUSE_REG_7: + case WCD937X_DIGITAL_EFUSE_REG_8: + case WCD937X_DIGITAL_EFUSE_REG_9: + case WCD937X_DIGITAL_EFUSE_REG_10: + case WCD937X_DIGITAL_EFUSE_REG_11: + case WCD937X_DIGITAL_EFUSE_REG_12: + case WCD937X_DIGITAL_EFUSE_REG_13: + case WCD937X_DIGITAL_EFUSE_REG_14: + case WCD937X_DIGITAL_EFUSE_REG_15: + case WCD937X_DIGITAL_EFUSE_REG_16: + case WCD937X_DIGITAL_EFUSE_REG_17: + case WCD937X_DIGITAL_EFUSE_REG_18: + case WCD937X_DIGITAL_EFUSE_REG_19: + case WCD937X_DIGITAL_EFUSE_REG_20: + case WCD937X_DIGITAL_EFUSE_REG_21: + case WCD937X_DIGITAL_EFUSE_REG_22: + case WCD937X_DIGITAL_EFUSE_REG_23: + case WCD937X_DIGITAL_EFUSE_REG_24: + case WCD937X_DIGITAL_EFUSE_REG_25: + case WCD937X_DIGITAL_EFUSE_REG_26: + case WCD937X_DIGITAL_EFUSE_REG_27: + case WCD937X_DIGITAL_EFUSE_REG_28: + case WCD937X_DIGITAL_EFUSE_REG_29: + case WCD937X_DIGITAL_EFUSE_REG_30: + case WCD937X_DIGITAL_EFUSE_REG_31: + return true; + } + + return wcd937x_rdwr_register(dev, reg); +} + +static bool wcd937x_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD937X_ANA_MBHC_RESULT_1: + case WCD937X_ANA_MBHC_RESULT_2: + case WCD937X_ANA_MBHC_RESULT_3: + case WCD937X_MBHC_MOISTURE_DET_FSM_STATUS: + case WCD937X_TX_1_2_SAR1_ERR: + case WCD937X_TX_1_2_SAR2_ERR: + case WCD937X_TX_3_SAR1_ERR: + case WCD937X_HPH_L_STATUS: + case WCD937X_HPH_R_STATUS: + case WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS: + case WCD937X_EAR_STATUS_REG_1: + case WCD937X_EAR_STATUS_REG_2: + case WCD937X_MBHC_NEW_FSM_STATUS: + case WCD937X_MBHC_NEW_ADC_RESULT: + case WCD937X_DIE_CRACK_DIE_CRK_DET_OUT: + case WCD937X_DIGITAL_INTR_STATUS_0: + case WCD937X_DIGITAL_INTR_STATUS_1: + case WCD937X_DIGITAL_INTR_STATUS_2: + case WCD937X_DIGITAL_SWR_HM_TEST: + case WCD937X_DIGITAL_PIN_STATUS_0: + case WCD937X_DIGITAL_PIN_STATUS_1: + case WCD937X_DIGITAL_MODE_STATUS_0: + case WCD937X_DIGITAL_MODE_STATUS_1: + return true; + } + return false; +} + +static const struct regmap_config wcd937x_regmap_config = { + .name = "wcd937x_csr", + .reg_bits = 32, + .val_bits = 8, + .cache_type = REGCACHE_MAPLE, + .reg_defaults = wcd937x_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd937x_defaults), + .max_register = WCD937X_MAX_REGISTER, + .readable_reg = wcd937x_readable_register, + .writeable_reg = wcd937x_rdwr_register, + .volatile_reg = wcd937x_volatile_register, +}; + +static const struct sdw_slave_ops wcd9370_slave_ops = { + .update_status = wcd9370_update_status, + .interrupt_callback = wcd9370_interrupt_callback, +}; + +static int wcd937x_sdw_component_bind(struct device *dev, + struct device *master, void *data) +{ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static void wcd937x_sdw_component_unbind(struct device *dev, + struct device *master, void *data) +{ + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_dont_use_autosuspend(dev); +} + +static const struct component_ops wcd937x_sdw_component_ops = { + .bind = wcd937x_sdw_component_bind, + .unbind = wcd937x_sdw_component_unbind, +}; + +static int wcd9370_probe(struct sdw_slave *pdev, + const struct sdw_device_id *id) +{ + struct device *dev = &pdev->dev; + struct wcd937x_sdw_priv *wcd; + int ret; + + wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); + if (!wcd) + return -ENOMEM; + + /* Port map index starts at 0, however the data port for this codec start at index 1 */ + if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) { + wcd->is_tx = true; + ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping", + &pdev->m_port_map[1], + WCD937X_MAX_TX_SWR_PORTS); + } else { + ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping", + &pdev->m_port_map[1], + WCD937X_MAX_SWR_PORTS); + } + if (ret < 0) + dev_info(dev, "Error getting static port mapping for %s (%d)\n", + wcd->is_tx ? "TX" : "RX", ret); + + wcd->sdev = pdev; + dev_set_drvdata(dev, wcd); + + pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | + SDW_SCP_INT1_BUS_CLASH | + SDW_SCP_INT1_PARITY; + pdev->prop.lane_control_support = true; + pdev->prop.simple_clk_stop_capable = true; + if (wcd->is_tx) { + pdev->prop.source_ports = GENMASK(WCD937X_MAX_TX_SWR_PORTS, 0); + pdev->prop.src_dpn_prop = wcd937x_dpn_prop; + wcd->ch_info = &wcd937x_sdw_tx_ch_info[0]; + pdev->prop.wake_capable = true; + + wcd->regmap = devm_regmap_init_sdw(pdev, &wcd937x_regmap_config); + if (IS_ERR(wcd->regmap)) + return dev_err_probe(dev, PTR_ERR(wcd->regmap), + "Regmap init failed\n"); + + /* Start in cache-only until device is enumerated */ + regcache_cache_only(wcd->regmap, true); + } else { + pdev->prop.sink_ports = GENMASK(WCD937X_MAX_SWR_PORTS, 0); + pdev->prop.sink_dpn_prop = wcd937x_dpn_prop; + wcd->ch_info = &wcd937x_sdw_rx_ch_info[0]; + } + + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return component_add(dev, &wcd937x_sdw_component_ops); +} + +static int wcd9370_remove(struct sdw_slave *pdev) +{ + struct device *dev = &pdev->dev; + + component_del(dev, &wcd937x_sdw_component_ops); + + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_dont_use_autosuspend(dev); + + return 0; +} + +static const struct sdw_device_id wcd9370_slave_id[] = { + SDW_SLAVE_ENTRY(0x0217, 0x10a, 0), /* WCD9370 RX/TX Device ID */ + { }, +}; +MODULE_DEVICE_TABLE(sdw, wcd9370_slave_id); + +static int __maybe_unused wcd937x_sdw_runtime_suspend(struct device *dev) +{ + struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev); + + if (wcd->regmap) { + regcache_cache_only(wcd->regmap, true); + regcache_mark_dirty(wcd->regmap); + } + + return 0; +} + +static int __maybe_unused wcd937x_sdw_runtime_resume(struct device *dev) +{ + struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev); + + if (wcd->regmap) { + regcache_cache_only(wcd->regmap, false); + regcache_sync(wcd->regmap); + } + + return 0; +} + +static const struct dev_pm_ops wcd937x_sdw_pm_ops = { + SET_RUNTIME_PM_OPS(wcd937x_sdw_runtime_suspend, wcd937x_sdw_runtime_resume, NULL) +}; + +static struct sdw_driver wcd9370_codec_driver = { + .probe = wcd9370_probe, + .remove = wcd9370_remove, + .ops = &wcd9370_slave_ops, + .id_table = wcd9370_slave_id, + .driver = { + .name = "wcd9370-codec", + .pm = &wcd937x_sdw_pm_ops, + } +}; +module_sdw_driver(wcd9370_codec_driver); + +MODULE_DESCRIPTION("WCD937X SDW codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h new file mode 100644 index 000000000000..e6e1ad5926d5 --- /dev/null +++ b/sound/soc/codecs/wcd937x.h @@ -0,0 +1,653 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _WCD937X_REGISTERS_H +#define _WCD937X_REGISTERS_H + +#include +#include + +#define WCD937X_BASE_ADDRESS 0x3000 +#define WCD937X_ANA_BIAS 0x3001 +#define WCD937X_ANA_RX_SUPPLIES 0x3008 +#define WCD937X_ANA_HPH 0x3009 +#define WCD937X_ANA_EAR 0x300A +#define WCD937X_ANA_EAR_COMPANDER_CTL 0x300B +#define WCD937X_EAR_GAIN_MASK GENMASK(6, 2) +#define WCD937X_ANA_TX_CH1 0x300E +#define WCD937X_ANA_TX_CH2 0x300F +#define WCD937X_ANA_TX_CH3 0x3010 +#define WCD937X_ANA_TX_CH3_HPF 0x3011 +#define WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC 0x3012 +#define WCD937X_ANA_MICB3_DSP_EN_LOGIC 0x3013 +#define WCD937X_ANA_MBHC_MECH 0x3014 +#define WCD937X_MBHC_L_DET_EN_MASK BIT(7) +#define WCD937X_MBHC_L_DET_EN BIT(7) +#define WCD937X_MBHC_GND_DET_EN_MASK BIT(6) +#define WCD937X_MBHC_MECH_DETECT_TYPE_MASK BIT(5) +#define WCD937X_MBHC_MECH_DETECT_TYPE_INS 1 +#define WCD937X_MBHC_HPHL_PLUG_TYPE_MASK BIT(4) +#define WCD937X_MBHC_HPHL_PLUG_TYPE_NO 1 +#define WCD937X_MBHC_GND_PLUG_TYPE_MASK BIT(3) +#define WCD937X_MBHC_GND_PLUG_TYPE_NO 1 +#define WCD937X_MBHC_HSL_PULLUP_COMP_EN BIT(2) +#define WCD937X_MBHC_HSG_PULLUP_COMP_EN BIT(1) +#define WCD937X_MBHC_HPHL_100K_TO_GND_EN BIT(0) +#define WCD937X_ANA_MBHC_ELECT 0x3015 +#define WCD937X_ANA_MBHC_BD_ISRC_CTL_MASK GENMASK(6, 4) +#define WCD937X_ANA_MBHC_BD_ISRC_100UA GENMASK(5, 4) +#define WCD937X_ANA_MBHC_BD_ISRC_OFF 0 +#define WCD937X_ANA_MBHC_BIAS_EN_MASK BIT(0) +#define WCD937X_ANA_MBHC_BIAS_EN BIT(0) +#define WCD937X_ANA_MBHC_ZDET 0x3016 +#define WCD937X_ANA_MBHC_RESULT_1 0x3017 +#define WCD937X_ANA_MBHC_RESULT_2 0x3018 +#define WCD937X_ANA_MBHC_RESULT_3 0x3019 +#define WCD937X_MBHC_BTN_RESULT_MASK GENMASK(2, 0) +#define WCD937X_ANA_MBHC_BTN0 0x301A +#define WCD937X_MBHC_BTN_VTH_MASK GENMASK(7, 2) +#define WCD937X_ANA_MBHC_BTN1 0x301B +#define WCD937X_ANA_MBHC_BTN2 0x301C +#define WCD937X_ANA_MBHC_BTN3 0x301D +#define WCD937X_ANA_MBHC_BTN4 0x301E +#define WCD937X_ANA_MBHC_BTN5 0x301F +#define WCD937X_VTH_MASK GENMASK(7, 2) +#define WCD937X_ANA_MBHC_BTN6 0x3020 +#define WCD937X_ANA_MBHC_BTN7 0x3021 +#define WCD937X_ANA_MICB1 0x3022 +#define WCD937X_MICB_VOUT_MASK GENMASK(5, 0) +#define WCD937X_MICB_EN_MASK GENMASK(7, 6) +#define WCD937X_MICB_DISABLE 0 +#define WCD937X_MICB_ENABLE 1 +#define WCD937X_MICB_PULL_UP 2 +#define WCD937X_MICB_PULL_DOWN 3 +#define WCD937X_ANA_MICB2 0x3023 +#define WCD937X_ANA_MICB2_ENABLE BIT(6) +#define WCD937X_ANA_MICB2_ENABLE_MASK GENMASK(7, 6) +#define WCD937X_ANA_MICB2_VOUT_MASK GENMASK(5, 0) +#define WCD937X_ANA_MICB2_RAMP 0x3024 +#define WCD937X_RAMP_EN_MASK BIT(7) +#define WCD937X_RAMP_SHIFT_CTRL_MASK GENMASK(4, 2) +#define WCD937X_ANA_MICB3 0x3025 +#define WCD937X_ANA_MICB_EN GENMASK(7, 6) +#define WCD937X_MICB_DISABLE 0 +#define WCD937X_MICB_ENABLE 1 +#define WCD937X_MICB_PULL_UP 2 +#define WCD937X_ANA_MICB_VOUT GENMASK(5, 0) +#define WCD937X_BIAS_CTL 0x3028 +#define WCD937X_BIAS_VBG_FINE_ADJ 0x3029 +#define WCD937X_LDOL_VDDCX_ADJUST 0x3040 +#define WCD937X_LDOL_DISABLE_LDOL 0x3041 +#define WCD937X_MBHC_CTL_CLK 0x3056 +#define WCD937X_MBHC_CTL_ANA 0x3057 +#define WCD937X_MBHC_CTL_SPARE_1 0x3058 +#define WCD937X_MBHC_CTL_SPARE_2 0x3059 +#define WCD937X_MBHC_CTL_BCS 0x305A +#define WCD937X_MBHC_MOISTURE_DET_FSM_STATUS 0x305B +#define WCD937X_MBHC_TEST_CTL 0x305C +#define WCD937X_LDOH_MODE 0x3067 +#define WCD937X_LDOH_BIAS 0x3068 +#define WCD937X_LDOH_STB_LOADS 0x3069 +#define WCD937X_LDOH_SLOWRAMP 0x306A +#define WCD937X_MICB1_TEST_CTL_1 0x306B +#define WCD937X_MICB1_TEST_CTL_2 0x306C +#define WCD937X_MICB1_TEST_CTL_3 0x306D +#define WCD937X_MICB2_TEST_CTL_1 0x306E +#define WCD937X_MICB2_TEST_CTL_2 0x306F +#define WCD937X_MICB2_TEST_CTL_3 0x3070 +#define WCD937X_MICB3_TEST_CTL_1 0x3071 +#define WCD937X_MICB3_TEST_CTL_2 0x3072 +#define WCD937X_MICB3_TEST_CTL_3 0x3073 +#define WCD937X_TX_COM_ADC_VCM 0x3077 +#define WCD937X_TX_COM_BIAS_ATEST 0x3078 +#define WCD937X_TX_COM_ADC_INT1_IB 0x3079 +#define WCD937X_TX_COM_ADC_INT2_IB 0x307A +#define WCD937X_TX_COM_TXFE_DIV_CTL 0x307B +#define WCD937X_TX_COM_TXFE_DIV_START 0x307C +#define WCD937X_TX_COM_TXFE_DIV_STOP_9P6M 0x307D +#define WCD937X_TX_COM_TXFE_DIV_STOP_12P288M 0x307E +#define WCD937X_TX_1_2_TEST_EN 0x307F +#define WCD937X_TX_1_2_ADC_IB 0x3080 +#define WCD937X_TX_1_2_ATEST_REFCTL 0x3081 +#define WCD937X_TX_1_2_TEST_CTL 0x3082 +#define WCD937X_TX_1_2_TEST_BLK_EN 0x3083 +#define WCD937X_TX_1_2_TXFE_CLKDIV 0x3084 +#define WCD937X_TX_1_2_SAR2_ERR 0x3085 +#define WCD937X_TX_1_2_SAR1_ERR 0x3086 +#define WCD937X_TX_3_TEST_EN 0x3087 +#define WCD937X_TX_3_ADC_IB 0x3088 +#define WCD937X_TX_3_ATEST_REFCTL 0x3089 +#define WCD937X_TX_3_TEST_CTL 0x308A +#define WCD937X_TX_3_TEST_BLK_EN 0x308B +#define WCD937X_TX_3_TXFE_CLKDIV 0x308C +#define WCD937X_TX_3_SPARE_MONO 0x308D +#define WCD937X_TX_3_SAR1_ERR 0x308E +#define WCD937X_CLASSH_MODE_1 0x3097 +#define WCD937X_CLASSH_MODE_2 0x3098 +#define WCD937X_CLASSH_MODE_3 0x3099 +#define WCD937X_CLASSH_CTRL_VCL_1 0x309A +#define WCD937X_CLASSH_CTRL_VCL_2 0x309B +#define WCD937X_CLASSH_CTRL_CCL_1 0x309C +#define WCD937X_CLASSH_CTRL_CCL_2 0x309D +#define WCD937X_CLASSH_CTRL_CCL_3 0x309E +#define WCD937X_CLASSH_CTRL_CCL_4 0x309F +#define WCD937X_CLASSH_CTRL_CCL_5 0x30A0 +#define WCD937X_CLASSH_BUCK_TMUX_A_D 0x30A1 +#define WCD937X_CLASSH_BUCK_SW_DRV_CNTL 0x30A2 +#define WCD937X_CLASSH_SPARE 0x30A3 +#define WCD937X_FLYBACK_EN 0x30A4 +#define WCD937X_FLYBACK_VNEG_CTRL_1 0x30A5 +#define WCD937X_FLYBACK_VNEG_CTRL_2 0x30A6 +#define WCD937X_FLYBACK_VNEG_CTRL_3 0x30A7 +#define WCD937X_FLYBACK_VNEG_CTRL_4 0x30A8 +#define WCD937X_FLYBACK_VNEG_CTRL_5 0x30A9 +#define WCD937X_FLYBACK_VNEG_CTRL_6 0x30AA +#define WCD937X_FLYBACK_VNEG_CTRL_7 0x30AB +#define WCD937X_FLYBACK_VNEG_CTRL_8 0x30AC +#define WCD937X_FLYBACK_VNEG_CTRL_9 0x30AD +#define WCD937X_FLYBACK_VNEGDAC_CTRL_1 0x30AE +#define WCD937X_FLYBACK_VNEGDAC_CTRL_2 0x30AF +#define WCD937X_FLYBACK_VNEGDAC_CTRL_3 0x30B0 +#define WCD937X_FLYBACK_CTRL_1 0x30B1 +#define WCD937X_FLYBACK_TEST_CTL 0x30B2 +#define WCD937X_RX_AUX_SW_CTL 0x30B3 +#define WCD937X_RX_PA_AUX_IN_CONN 0x30B4 +#define WCD937X_RX_TIMER_DIV 0x30B5 +#define WCD937X_RX_OCP_CTL 0x30B6 +#define WCD937X_RX_OCP_COUNT 0x30B7 +#define WCD937X_RX_BIAS_EAR_DAC 0x30B8 +#define WCD937X_RX_BIAS_EAR_AMP 0x30B9 +#define WCD937X_RX_BIAS_HPH_LDO 0x30BA +#define WCD937X_RX_BIAS_HPH_PA 0x30BB +#define WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2 0x30BC +#define WCD937X_RX_BIAS_HPH_RDAC_LDO 0x30BD +#define WCD937X_RX_BIAS_HPH_CNP1 0x30BE +#define WCD937X_RX_BIAS_HPH_LOWPOWER 0x30BF +#define WCD937X_RX_BIAS_AUX_DAC 0x30C0 +#define WCD937X_RX_BIAS_AUX_AMP 0x30C1 +#define WCD937X_RX_BIAS_VNEGDAC_BLEEDER 0x30C2 +#define WCD937X_RX_BIAS_MISC 0x30C3 +#define WCD937X_RX_BIAS_BUCK_RST 0x30C4 +#define WCD937X_RX_BIAS_BUCK_VREF_ERRAMP 0x30C5 +#define WCD937X_RX_BIAS_FLYB_ERRAMP 0x30C6 +#define WCD937X_RX_BIAS_FLYB_BUFF 0x30C7 +#define WCD937X_RX_BIAS_FLYB_MID_RST 0x30C8 +#define WCD937X_HPH_L_STATUS 0x30C9 +#define WCD937X_HPH_R_STATUS 0x30CA +#define WCD937X_HPH_CNP_EN 0x30CB +#define WCD937X_HPH_CNP_WG_CTL 0x30CC +#define WCD937X_HPH_CNP_WG_TIME 0x30CD +#define WCD937X_HPH_OCP_CTL 0x30CE +#define WCD937X_HPH_AUTO_CHOP 0x30CF +#define WCD937X_HPH_CHOP_CTL 0x30D0 +#define WCD937X_HPH_PA_CTL1 0x30D1 +#define WCD937X_HPH_PA_CTL2 0x30D2 +#define WCD937X_HPHPA_GND_R_MASK BIT(6) +#define WCD937X_HPHPA_GND_L_MASK BIT(4) +#define WCD937X_HPH_L_EN 0x30D3 +#define WCD937X_HPH_L_TEST 0x30D4 +#define WCD937X_HPH_L_ATEST 0x30D5 +#define WCD937X_HPH_R_EN 0x30D6 +#define WCD937X_GAIN_SRC_SEL_MASK BIT(5) +#define WCD937X_GAIN_SRC_SEL_REGISTER 1 +#define WCD937X_HPH_R_TEST 0x30D7 +#define WCD937X_HPH_R_ATEST 0x30D8 +#define WCD937X_HPH_RDAC_CLK_CTL1 0x30D9 +#define WCD937X_HPHPA_GND_OVR_MASK BIT(1) +#define WCD937X_CHOP_CLK_EN_MASK BIT(7) +#define WCD937X_HPH_RDAC_CLK_CTL2 0x30DA +#define WCD937X_HPH_RDAC_LDO_CTL 0x30DB +#define WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL 0x30DC +#define WCD937X_HPH_REFBUFF_UHQA_CTL 0x30DD +#define WCD937X_HPH_REFBUFF_LP_CTL 0x30DE +#define WCD937X_PREREF_FLIT_BYPASS_MASK BIT(0) +#define WCD937X_HPH_L_DAC_CTL 0x30DF +#define WCD937X_HPH_R_DAC_CTL 0x30E0 +#define WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL 0x30E1 +#define WCD937X_HPH_SURGE_HPHLR_SURGE_EN 0x30E2 +#define WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1 0x30E3 +#define WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS 0x30E4 +#define WCD937X_EAR_EAR_EN_REG 0x30E9 +#define WCD937X_EAR_EAR_PA_CON 0x30EA +#define WCD937X_EAR_EAR_SP_CON 0x30EB +#define WCD937X_EAR_EAR_DAC_CON 0x30EC +#define WCD937X_EAR_EAR_CNP_FSM_CON 0x30ED +#define WCD937X_EAR_TEST_CTL 0x30EE +#define WCD937X_EAR_STATUS_REG_1 0x30EF +#define WCD937X_EAR_STATUS_REG_2 0x30F0 +#define WCD937X_ANA_NEW_PAGE_REGISTER 0x3100 +#define WCD937X_HPH_NEW_ANA_HPH2 0x3101 +#define WCD937X_HPH_NEW_ANA_HPH3 0x3102 +#define WCD937X_SLEEP_CTL 0x3103 +#define WCD937X_SLEEP_WATCHDOG_CTL 0x3104 +#define WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL 0x311F +#define WCD937X_MBHC_NEW_CTL_1 0x3120 +#define WCD937X_MBHC_CTL_RCO_EN_MASK BIT(7) +#define WCD937X_MBHC_CTL_RCO_EN BIT(7) +#define WCD937X_MBHC_BTN_DBNC_MASK GENMASK(1, 0) +#define WCD937X_MBHC_BTN_DBNC_T_16_MS 0x2 +#define WCD937X_MBHC_NEW_CTL_2 0x3121 +#define WCD937X_MBHC_NEW_PLUG_DETECT_CTL 0x3122 +#define WCD937X_MBHC_NEW_ZDET_ANA_CTL 0x3123 +#define WCD937X_M_RTH_CTL_MASK GENMASK(3, 2) +#define WCD937X_MBHC_HS_VREF_CTL_MASK GENMASK(1, 0) +#define WCD937X_MBHC_HS_VREF_1P5_V 0x1 +#define WCD937X_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS 0x6 +#define WCD937X_ZDET_RANGE_CTL_MASK GENMASK(3, 0) +#define WCD937X_ZDET_MAXV_CTL_MASK GENMASK(6, 4) +#define WCD937X_MBHC_NEW_ZDET_RAMP_CTL 0x3124 +#define WCD937X_MBHC_NEW_FSM_STATUS 0x3125 +#define WCD937X_MBHC_NEW_ADC_RESULT 0x3126 +#define WCD937X_TX_NEW_TX_CH2_SEL 0x3127 +#define WCD937X_AUX_AUXPA 0x3128 +#define WCD937X_AUXPA_CLK_EN_MASK BIT(4) +#define WCD937X_AUXPA_CLK_EN_MASK BIT(4) +#define WCD937X_LDORXTX_MODE 0x3129 +#define WCD937X_LDORXTX_CONFIG 0x312A +#define WCD937X_DIE_CRACK_DIE_CRK_DET_EN 0x312C +#define WCD937X_DIE_CRACK_DIE_CRK_DET_OUT 0x312D +#define WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL 0x3132 +#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L 0x3133 +#define WCD937X_HPH_NEW_INT_RDAC_VREF_CTL 0x3134 +#define WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL 0x3135 +#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R 0x3136 +#define WCD937X_HPH_NEW_INT_PA_MISC1 0x3137 +#define WCD937X_HPH_NEW_INT_PA_MISC2 0x3138 +#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC 0x3139 +#define WCD937X_HPH_NEW_INT_HPH_TIMER1 0x313A +#define WCD937X_HPH_NEW_INT_HPH_TIMER2 0x313B +#define WCD937X_HPH_NEW_INT_HPH_TIMER3 0x313C +#define WCD937X_HPH_NEW_INT_HPH_TIMER4 0x313D +#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC2 0x313E +#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC3 0x313F +#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI 0x3145 +#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP 0x3146 +#define WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP 0x3147 +#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL 0x31AF +#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL 0x31B0 +#define WCD937X_MOISTURE_EN_POLLING_MASK BIT(2) +#define WCD937X_HSDET_PULLUP_C_MASK GENMASK(4, 0) +#define WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT 0x31B1 +#define WCD937X_MBHC_NEW_INT_SPARE_2 0x31B2 +#define WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON 0x31B7 +#define WCD937X_EAR_INT_NEW_CNP_VCM_CON1 0x31B8 +#define WCD937X_EAR_INT_NEW_CNP_VCM_CON2 0x31B9 +#define WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS 0x31BA +#define WCD937X_AUX_INT_EN_REG 0x31BD +#define WCD937X_AUX_INT_PA_CTRL 0x31BE +#define WCD937X_AUX_INT_SP_CTRL 0x31BF +#define WCD937X_AUX_INT_DAC_CTRL 0x31C0 +#define WCD937X_AUX_INT_CLK_CTRL 0x31C1 +#define WCD937X_AUX_INT_TEST_CTRL 0x31C2 +#define WCD937X_AUX_INT_STATUS_REG 0x31C3 +#define WCD937X_AUX_INT_MISC 0x31C4 +#define WCD937X_LDORXTX_INT_BIAS 0x31C5 +#define WCD937X_LDORXTX_INT_STB_LOADS_DTEST 0x31C6 +#define WCD937X_LDORXTX_INT_TEST0 0x31C7 +#define WCD937X_LDORXTX_INT_STARTUP_TIMER 0x31C8 +#define WCD937X_LDORXTX_INT_TEST1 0x31C9 +#define WCD937X_LDORXTX_INT_STATUS 0x31CA +#define WCD937X_SLEEP_INT_WATCHDOG_CTL_1 0x31D0 +#define WCD937X_SLEEP_INT_WATCHDOG_CTL_2 0x31D1 +#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1 0x31D3 +#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2 0x31D4 +#define WCD937X_DIGITAL_PAGE_REGISTER 0x3400 +#define WCD937X_DIGITAL_CHIP_ID0 0x3401 +#define WCD937X_DIGITAL_CHIP_ID1 0x3402 +#define WCD937X_DIGITAL_CHIP_ID2 0x3403 +#define WCD937X_DIGITAL_CHIP_ID3 0x3404 +#define WCD937X_DIGITAL_CDC_RST_CTL 0x3406 +#define WCD937X_DIGITAL_TOP_CLK_CFG 0x3407 +#define WCD937X_DIGITAL_CDC_ANA_CLK_CTL 0x3408 +#define WCD937X_DIGITAL_CDC_DIG_CLK_CTL 0x3409 +#define WCD937X_DIGITAL_SWR_RST_EN 0x340A +#define WCD937X_DIGITAL_CDC_PATH_MODE 0x340B +#define WCD937X_DIGITAL_CDC_RX_RST 0x340C +#define WCD937X_DIGITAL_CDC_RX0_CTL 0x340D +#define WCD937X_DIGITAL_CDC_RX1_CTL 0x340E +#define WCD937X_DIGITAL_CDC_RX2_CTL 0x340F +#define WCD937X_DIGITAL_DEM_BYPASS_DATA0 0x3410 +#define WCD937X_DIGITAL_DEM_BYPASS_DATA1 0x3411 +#define WCD937X_DIGITAL_DEM_BYPASS_DATA2 0x3412 +#define WCD937X_DIGITAL_DEM_BYPASS_DATA3 0x3413 +#define WCD937X_DIGITAL_CDC_COMP_CTL_0 0x3414 +#define WCD937X_DIGITAL_CDC_RX_DELAY_CTL 0x3417 +#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_0 0x3418 +#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_1 0x3419 +#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_0 0x341A +#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_1 0x341B +#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_0 0x341C +#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_1 0x341D +#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_0 0x341E +#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_1 0x341F +#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_0 0x3420 +#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_1 0x3421 +#define WCD937X_DIGITAL_CDC_HPH_DSM_A6_0 0x3422 +#define WCD937X_DIGITAL_CDC_HPH_DSM_A7_0 0x3423 +#define WCD937X_DIGITAL_CDC_HPH_DSM_C_0 0x3424 +#define WCD937X_DIGITAL_CDC_HPH_DSM_C_1 0x3425 +#define WCD937X_DIGITAL_CDC_HPH_DSM_C_2 0x3426 +#define WCD937X_DIGITAL_CDC_HPH_DSM_C_3 0x3427 +#define WCD937X_DIGITAL_CDC_HPH_DSM_R1 0x3428 +#define WCD937X_DIGITAL_CDC_HPH_DSM_R2 0x3429 +#define WCD937X_DIGITAL_CDC_HPH_DSM_R3 0x342A +#define WCD937X_DIGITAL_CDC_HPH_DSM_R4 0x342B +#define WCD937X_DIGITAL_CDC_HPH_DSM_R5 0x342C +#define WCD937X_DIGITAL_CDC_HPH_DSM_R6 0x342D +#define WCD937X_DIGITAL_CDC_HPH_DSM_R7 0x342E +#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_0 0x342F +#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_1 0x3430 +#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_0 0x3431 +#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_1 0x3432 +#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_0 0x3433 +#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_1 0x3434 +#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_0 0x3435 +#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_1 0x3436 +#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_0 0x3437 +#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_1 0x3438 +#define WCD937X_DIGITAL_CDC_AUX_DSM_A6_0 0x3439 +#define WCD937X_DIGITAL_CDC_AUX_DSM_A7_0 0x343A +#define WCD937X_DIGITAL_CDC_AUX_DSM_C_0 0x343B +#define WCD937X_DIGITAL_CDC_AUX_DSM_C_1 0x343C +#define WCD937X_DIGITAL_CDC_AUX_DSM_C_2 0x343D +#define WCD937X_DIGITAL_CDC_AUX_DSM_C_3 0x343E +#define WCD937X_DIGITAL_CDC_AUX_DSM_R1 0x343F +#define WCD937X_DIGITAL_CDC_AUX_DSM_R2 0x3440 +#define WCD937X_DIGITAL_CDC_AUX_DSM_R3 0x3441 +#define WCD937X_DIGITAL_CDC_AUX_DSM_R4 0x3442 +#define WCD937X_DIGITAL_CDC_AUX_DSM_R5 0x3443 +#define WCD937X_DIGITAL_CDC_AUX_DSM_R6 0x3444 +#define WCD937X_DIGITAL_CDC_AUX_DSM_R7 0x3445 +#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0 0x3446 +#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1 0x3447 +#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0 0x3448 +#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1 0x3449 +#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2 0x344A +#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0 0x344B +#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1 0x344C +#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2 0x344D +#define WCD937X_DIGITAL_CDC_HPH_GAIN_CTL 0x344E +#define WCD937X_DIGITAL_CDC_AUX_GAIN_CTL 0x344F +#define WCD937X_DIGITAL_CDC_EAR_PATH_CTL 0x3450 +#define WCD937X_DIGITAL_CDC_SWR_CLH 0x3451 +#define WCD937X_DIGITAL_SWR_CLH_BYP 0x3452 +#define WCD937X_DIGITAL_CDC_TX0_CTL 0x3453 +#define WCD937X_DIGITAL_CDC_TX1_CTL 0x3454 +#define WCD937X_DIGITAL_CDC_TX2_CTL 0x3455 +#define WCD937X_DIGITAL_CDC_TX_RST 0x3456 +#define WCD937X_DIGITAL_CDC_REQ_CTL 0x3457 +#define WCD937X_DIGITAL_CDC_AMIC_CTL 0x345A +#define WCD937X_DIGITAL_CDC_DMIC_CTL 0x345B +#define WCD937X_DIGITAL_CDC_DMIC1_CTL 0x345C +#define WCD937X_DIGITAL_CDC_DMIC2_CTL 0x345D +#define WCD937X_DIGITAL_CDC_DMIC3_CTL 0x345E +#define WCD937X_DIGITAL_EFUSE_CTL 0x345F +#define WCD937X_DIGITAL_EFUSE_PRG_CTL 0x3460 +#define WCD937X_DIGITAL_EFUSE_TEST_CTL_0 0x3461 +#define WCD937X_DIGITAL_EFUSE_TEST_CTL_1 0x3462 +#define WCD937X_DIGITAL_EFUSE_T_DATA_0 0x3463 +#define WCD937X_DIGITAL_EFUSE_T_DATA_1 0x3464 +#define WCD937X_DIGITAL_PDM_WD_CTL0 0x3465 +#define WCD937X_DIGITAL_PDM_WD_CTL1 0x3466 +#define WCD937X_DIGITAL_PDM_WD_CTL2 0x3467 +#define WCD937X_DIGITAL_INTR_MODE 0x346A +#define WCD937X_DIGITAL_INTR_MASK_0 0x346B +#define WCD937X_DIGITAL_INTR_MASK_1 0x346C +#define WCD937X_DIGITAL_INTR_MASK_2 0x346D +#define WCD937X_DIGITAL_INTR_STATUS_0 0x346E +#define WCD937X_DIGITAL_INTR_STATUS_1 0x346F +#define WCD937X_DIGITAL_INTR_STATUS_2 0x3470 +#define WCD937X_DIGITAL_INTR_CLEAR_0 0x3471 +#define WCD937X_DIGITAL_INTR_CLEAR_1 0x3472 +#define WCD937X_DIGITAL_INTR_CLEAR_2 0x3473 +#define WCD937X_DIGITAL_INTR_LEVEL_0 0x3474 +#define WCD937X_DIGITAL_INTR_LEVEL_1 0x3475 +#define WCD937X_DIGITAL_INTR_LEVEL_2 0x3476 +#define WCD937X_DIGITAL_INTR_SET_0 0x3477 +#define WCD937X_DIGITAL_INTR_SET_1 0x3478 +#define WCD937X_DIGITAL_INTR_SET_2 0x3479 +#define WCD937X_DIGITAL_INTR_TEST_0 0x347A +#define WCD937X_DIGITAL_INTR_TEST_1 0x347B +#define WCD937X_DIGITAL_INTR_TEST_2 0x347C +#define WCD937X_DIGITAL_CDC_CONN_RX0_CTL 0x347F +#define WCD937X_DIGITAL_CDC_CONN_RX1_CTL 0x3480 +#define WCD937X_DIGITAL_CDC_CONN_RX2_CTL 0x3481 +#define WCD937X_DIGITAL_CDC_CONN_TX_CTL 0x3482 +#define WCD937X_DIGITAL_LOOP_BACK_MODE 0x3483 +#define WCD937X_DIGITAL_SWR_DAC_TEST 0x3484 +#define WCD937X_DIGITAL_SWR_HM_TEST_RX_0 0x3485 +#define WCD937X_DIGITAL_SWR_HM_TEST_TX_0 0x3491 +#define WCD937X_DIGITAL_SWR_HM_TEST_RX_1 0x3492 +#define WCD937X_DIGITAL_SWR_HM_TEST_TX_1 0x3493 +#define WCD937X_DIGITAL_SWR_HM_TEST 0x3494 +#define WCD937X_DIGITAL_PAD_CTL_PDM_RX0 0x3495 +#define WCD937X_DIGITAL_PAD_CTL_PDM_RX1 0x3496 +#define WCD937X_DIGITAL_PAD_CTL_PDM_TX0 0x3497 +#define WCD937X_DIGITAL_PAD_CTL_PDM_TX1 0x3498 +#define WCD937X_DIGITAL_PAD_INP_DIS_0 0x3499 +#define WCD937X_DIGITAL_PAD_INP_DIS_1 0x349A +#define WCD937X_DIGITAL_DRIVE_STRENGTH_0 0x349B +#define WCD937X_DIGITAL_DRIVE_STRENGTH_1 0x349C +#define WCD937X_DIGITAL_DRIVE_STRENGTH_2 0x349D +#define WCD937X_DIGITAL_RX_DATA_EDGE_CTL 0x349E +#define WCD937X_DIGITAL_TX_DATA_EDGE_CTL 0x349F +#define WCD937X_DIGITAL_GPIO_MODE 0x34A0 +#define WCD937X_DIGITAL_PIN_CTL_OE 0x34A1 +#define WCD937X_DIGITAL_PIN_CTL_DATA_0 0x34A2 +#define WCD937X_DIGITAL_PIN_CTL_DATA_1 0x34A3 +#define WCD937X_DIGITAL_PIN_STATUS_0 0x34A4 +#define WCD937X_DIGITAL_PIN_STATUS_1 0x34A5 +#define WCD937X_DIGITAL_DIG_DEBUG_CTL 0x34A6 +#define WCD937X_DIGITAL_DIG_DEBUG_EN 0x34A7 +#define WCD937X_DIGITAL_ANA_CSR_DBG_ADD 0x34A8 +#define WCD937X_DIGITAL_ANA_CSR_DBG_CTL 0x34A9 +#define WCD937X_DIGITAL_SSP_DBG 0x34AA +#define WCD937X_DIGITAL_MODE_STATUS_0 0x34AB +#define WCD937X_DIGITAL_MODE_STATUS_1 0x34AC +#define WCD937X_DIGITAL_SPARE_0 0x34AD +#define WCD937X_DIGITAL_SPARE_1 0x34AE +#define WCD937X_DIGITAL_SPARE_2 0x34AF +#define WCD937X_DIGITAL_EFUSE_REG_0 0x34B0 +#define WCD937X_DIGITAL_EFUSE_REG_1 0x34B1 +#define WCD937X_DIGITAL_EFUSE_REG_2 0x34B2 +#define WCD937X_DIGITAL_EFUSE_REG_3 0x34B3 +#define WCD937X_DIGITAL_EFUSE_REG_4 0x34B4 +#define WCD937X_DIGITAL_EFUSE_REG_5 0x34B5 +#define WCD937X_DIGITAL_EFUSE_REG_6 0x34B6 +#define WCD937X_DIGITAL_EFUSE_REG_7 0x34B7 +#define WCD937X_DIGITAL_EFUSE_REG_8 0x34B8 +#define WCD937X_DIGITAL_EFUSE_REG_9 0x34B9 +#define WCD937X_DIGITAL_EFUSE_REG_10 0x34BA +#define WCD937X_DIGITAL_EFUSE_REG_11 0x34BB +#define WCD937X_DIGITAL_EFUSE_REG_12 0x34BC +#define WCD937X_DIGITAL_EFUSE_REG_13 0x34BD +#define WCD937X_DIGITAL_EFUSE_REG_14 0x34BE +#define WCD937X_DIGITAL_EFUSE_REG_15 0x34BF +#define WCD937X_DIGITAL_EFUSE_REG_16 0x34C0 +#define WCD937X_DIGITAL_EFUSE_REG_17 0x34C1 +#define WCD937X_DIGITAL_EFUSE_REG_18 0x34C2 +#define WCD937X_DIGITAL_EFUSE_REG_19 0x34C3 +#define WCD937X_DIGITAL_EFUSE_REG_20 0x34C4 +#define WCD937X_DIGITAL_EFUSE_REG_21 0x34C5 +#define WCD937X_DIGITAL_EFUSE_REG_22 0x34C6 +#define WCD937X_DIGITAL_EFUSE_REG_23 0x34C7 +#define WCD937X_DIGITAL_EFUSE_REG_24 0x34C8 +#define WCD937X_DIGITAL_EFUSE_REG_25 0x34C9 +#define WCD937X_DIGITAL_EFUSE_REG_26 0x34CA +#define WCD937X_DIGITAL_EFUSE_REG_27 0x34CB +#define WCD937X_DIGITAL_EFUSE_REG_28 0x34CC +#define WCD937X_DIGITAL_EFUSE_REG_29 0x34CD +#define WCD937X_DIGITAL_EFUSE_REG_30 0x34CE +#define WCD937X_DIGITAL_EFUSE_REG_31 0x34CF +#define WCD937X_MAX_REGISTER (WCD937X_DIGITAL_EFUSE_REG_31) + +#define WCD937X_MAX_MICBIAS 3 +#define WCD937X_MAX_BULK_SUPPLY 3 +#define WCD937X_MAX_TX_SWR_PORTS 4 +#define WCD937X_MAX_SWR_PORTS 5 +#define WCD937X_MAX_SWR_CH_IDS 15 + +/* Convert from vout ctl to micbias voltage in mV */ +#define WCD_VOUT_CTL_TO_MICB(v) (1000 + (v) * 50) +#define MAX_PORT 8 +#define MAX_CH_PER_PORT 8 +#define MAX_TX_PWR_CH 2 +#define SWR_NUM_PORTS 4 + +#define WCD937X_MAX_SLAVE_PORT_TYPES 10 + +struct codec_port_info { + u32 slave_port_type; + u32 master_port_type; + u32 ch_mask; + u32 num_ch; + u32 ch_rate; +}; + +struct wcd937x_sdw_ch_info { + int port_num; + unsigned int ch_mask; +}; + +#define WCD_SDW_CH(id, pn, cmask) \ + [id] = { \ + .port_num = pn, \ + .ch_mask = cmask, \ + } + +struct wcd937x_priv; +struct wcd937x_sdw_priv { + struct sdw_slave *sdev; + struct sdw_stream_config sconfig; + struct sdw_stream_runtime *sruntime; + struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS]; + struct wcd937x_sdw_ch_info *ch_info; + bool port_enable[WCD937X_MAX_SWR_CH_IDS]; + int active_ports; + int num_ports; + bool is_tx; + struct wcd937x_priv *wcd937x; + struct irq_domain *slave_irq; + struct regmap *regmap; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD937X_SDW) +int wcd937x_sdw_free(struct wcd937x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +int wcd937x_sdw_set_sdw_stream(struct wcd937x_sdw_priv *wcd, + struct snd_soc_dai *dai, + void *stream, int direction); +int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + +struct device *wcd937x_sdw_device_get(struct device_node *np); + +#else +int wcd937x_sdw_free(struct wcd937x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return -EOPNOTSUPP; +} + +int wcd937x_sdw_set_sdw_stream(struct wcd937x_sdw_priv *wcd, + struct snd_soc_dai *dai, + void *stream, int direction) +{ + return -EOPNOTSUPP; +} + +int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return -EOPNOTSUPP; +} +#endif + +enum { + WCD_RX1, + WCD_RX2, + WCD_RX3 +}; + +enum { + /* INTR_CTRL_INT_MASK_0 */ + WCD937X_IRQ_MBHC_BUTTON_PRESS_DET = 0, + WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET, + WCD937X_IRQ_MBHC_ELECT_INS_REM_DET, + WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD937X_IRQ_MBHC_SW_DET, + WCD937X_IRQ_HPHR_OCP_INT, + WCD937X_IRQ_HPHR_CNP_INT, + WCD937X_IRQ_HPHL_OCP_INT, + + /* INTR_CTRL_INT_MASK_1 */ + WCD937X_IRQ_HPHL_CNP_INT, + WCD937X_IRQ_EAR_CNP_INT, + WCD937X_IRQ_EAR_SCD_INT, + WCD937X_IRQ_AUX_CNP_INT, + WCD937X_IRQ_AUX_SCD_INT, + WCD937X_IRQ_HPHL_PDM_WD_INT, + WCD937X_IRQ_HPHR_PDM_WD_INT, + WCD937X_IRQ_AUX_PDM_WD_INT, + + /* INTR_CTRL_INT_MASK_2 */ + WCD937X_IRQ_LDORT_SCD_INT, + WCD937X_IRQ_MBHC_MOISTURE_INT, + WCD937X_IRQ_HPHL_SURGE_DET_INT, + WCD937X_IRQ_HPHR_SURGE_DET_INT, + WCD937X_NUM_IRQS, +}; + +enum wcd937x_tx_sdw_ports { + WCD937X_ADC_1_PORT = 1, + WCD937X_ADC_2_3_PORT, + WCD937X_DMIC_0_3_MBHC_PORT, + WCD937X_DMIC_4_6_PORT, +}; + +enum wcd937x_tx_sdw_channels { + WCD937X_ADC1, + WCD937X_ADC2, + WCD937X_ADC3, + WCD937X_DMIC0, + WCD937X_DMIC1, + WCD937X_MBHC, + WCD937X_DMIC2, + WCD937X_DMIC3, + WCD937X_DMIC4, + WCD937X_DMIC5, + WCD937X_DMIC6, +}; + +enum wcd937x_rx_sdw_ports { + WCD937X_HPH_PORT = 1, + WCD937X_CLSH_PORT, + WCD937X_COMP_PORT, + WCD937X_LO_PORT, + WCD937X_DSD_PORT, +}; + +enum wcd937x_rx_sdw_channels { + WCD937X_HPH_L, + WCD937X_HPH_R, + WCD937X_CLSH, + WCD937X_COMP_L, + WCD937X_COMP_R, + WCD937X_LO, + WCD937X_DSD_R, + WCD937X_DSD_L, +}; + +enum { + WCD937X_SDW_DIR_RX, + WCD937X_SDW_DIR_TX, +}; + +#endif From 9be3ec196da41b20b624ae4ed0303df58548644e Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 24 May 2024 09:25:31 +0530 Subject: [PATCH 076/349] ASoC: codecs: wcd937x: add wcd937x codec driver This patch adds basic SoundWire codec driver to support for WCD9370/WCD9375 TX and RX devices. The WCD9370/WCD9375 has Multi Button Headset Control hardware to support Headset insertion, type detection, 8 headset buttons detection, Over Current detection and Impedence measurements. This patch adds support for this using wcd-mbhc apis. Signed-off-by: Prasad Kumpatla Co-developed-by: Mohammad Rafi Shaik Signed-off-by: Mohammad Rafi Shaik Link: https://lore.kernel.org/r/20240524035535.3119208-4-quic_mohs@quicinc.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 1677 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1677 insertions(+) create mode 100644 sound/soc/codecs/wcd937x.c diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c new file mode 100644 index 000000000000..4470ee0ecae6 --- /dev/null +++ b/sound/soc/codecs/wcd937x.c @@ -0,0 +1,1677 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wcd-clsh-v2.h" +#include "wcd-mbhc-v2.h" +#include "wcd937x.h" + +enum { + CHIPID_WCD9370 = 0, + CHIPID_WCD9375 = 5, +}; + +/* Z value defined in milliohm */ +#define WCD937X_ZDET_VAL_32 (32000) +#define WCD937X_ZDET_VAL_400 (400000) +#define WCD937X_ZDET_VAL_1200 (1200000) +#define WCD937X_ZDET_VAL_100K (100000000) +/* Z floating defined in ohms */ +#define WCD937X_ZDET_FLOATING_IMPEDANCE (0x0FFFFFFE) +#define WCD937X_ZDET_NUM_MEASUREMENTS (900) +#define WCD937X_MBHC_GET_C1(c) (((c) & 0xC000) >> 14) +#define WCD937X_MBHC_GET_X1(x) ((x) & 0x3FFF) +/* Z value compared in milliOhm */ +#define WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z) (((z) > 400000) || ((z) < 32000)) +#define WCD937X_MBHC_ZDET_CONST (86 * 16384) +#define WCD937X_MBHC_MOISTURE_RREF R_24_KOHM +#define WCD_MBHC_HS_V_MAX 1600 +#define EAR_RX_PATH_AUX 1 +#define WCD937X_MBHC_MAX_BUTTONS 8 + +#define WCD937X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) + +/* Fractional Rates */ +#define WCD937X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) + +#define WCD937X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +enum { + ALLOW_BUCK_DISABLE, + HPH_COMP_DELAY, + HPH_PA_DELAY, + AMIC2_BCS_ENABLE, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + NUM_CODEC_DAIS, +}; + +struct wcd937x_priv { + struct sdw_slave *tx_sdw_dev; + struct wcd937x_sdw_priv *sdw_priv[NUM_CODEC_DAIS]; + struct device *txdev; + struct device *rxdev; + struct device_node *rxnode; + struct device_node *txnode; + struct regmap *regmap; + /* micb setup lock */ + struct mutex micb_lock; + /* mbhc module */ + struct wcd_mbhc *wcd_mbhc; + struct wcd_mbhc_config mbhc_cfg; + struct wcd_mbhc_intr intr_ids; + struct wcd_clsh_ctrl *clsh_info; + struct irq_domain *virq; + struct regmap_irq_chip *wcd_regmap_irq_chip; + struct regmap_irq_chip_data *irq_chip; + struct regulator_bulk_data supplies[WCD937X_MAX_BULK_SUPPLY]; + struct regulator *buck_supply; + struct snd_soc_jack *jack; + unsigned long status_mask; + s32 micb_ref[WCD937X_MAX_MICBIAS]; + s32 pullup_ref[WCD937X_MAX_MICBIAS]; + u32 hph_mode; + int ear_rx_path; + u32 chipid; + u32 micb1_mv; + u32 micb2_mv; + u32 micb3_mv; + u32 micb4_mv; /* 9375 only */ + int hphr_pdm_wd_int; + int hphl_pdm_wd_int; + int aux_pdm_wd_int; + bool comp1_enable; + bool comp2_enable; + + struct gpio_desc *us_euro_gpio; + struct gpio_desc *reset_gpio; + + int dmic_0_1_clk_cnt; + int dmic_2_3_clk_cnt; + int dmic_4_5_clk_cnt; + atomic_t rx_clk_cnt; + atomic_t ana_clk_count; +}; + +struct wcd937x_mbhc_zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; + u16 btn5; + u16 btn6; + u16 btn7; +}; + +static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { + WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD937X_ANA_MBHC_MECH, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD937X_ANA_MBHC_MECH, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD937X_ANA_MBHC_MECH, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x30), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD937X_ANA_MBHC_ELECT, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F), + WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD937X_ANA_MBHC_MECH, 0x04), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD937X_ANA_MBHC_MECH, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD937X_ANA_MBHC_MECH, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD937X_ANA_MBHC_MECH, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD937X_ANA_MBHC_ELECT, 0x06), + WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD937X_ANA_MBHC_ELECT, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F), + WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD937X_MBHC_NEW_CTL_1, 0x03), + WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD937X_MBHC_NEW_CTL_2, 0x03), + WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD937X_ANA_MBHC_RESULT_3, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD937X_HPH_OCP_CTL, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x07), + WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD937X_ANA_MBHC_ELECT, 0x70), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0xFF), + WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD937X_ANA_MICB2, 0xC0), + WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD937X_HPH_CNP_WG_TIME, 0xFF), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD937X_ANA_HPH, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD937X_ANA_HPH, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD937X_ANA_HPH, 0xC0), + WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD937X_ANA_MBHC_RESULT_3, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD937X_MBHC_CTL_BCS, 0x02), + WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD937X_MBHC_NEW_FSM_STATUS, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD937X_MBHC_NEW_CTL_2, 0x70), + WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD937X_MBHC_NEW_FSM_STATUS, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD937X_HPH_PA_CTL2, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD937X_HPH_PA_CTL2, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD937X_HPH_L_TEST, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD937X_HPH_R_TEST, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD937X_DIGITAL_INTR_STATUS_0, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD937X_DIGITAL_INTR_STATUS_0, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD937X_MBHC_NEW_CTL_1, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD937X_MBHC_NEW_FSM_STATUS, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD937X_MBHC_NEW_FSM_STATUS, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD937X_MBHC_NEW_ADC_RESULT, 0xFF), + WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD937X_ANA_MICB2, 0x3F), + WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD937X_MBHC_NEW_CTL_1, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD937X_MBHC_NEW_CTL_1, 0x04), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD937X_ANA_MBHC_ZDET, 0x02), +}; + +static const struct regmap_irq wcd937x_irqs[WCD937X_NUM_IRQS] = { + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_PRESS_DET, 0, BIT(0)), + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, BIT(1)), + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_DET, 0, BIT(2)), + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, BIT(3)), + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_SW_DET, 0, BIT(4)), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_OCP_INT, 0, BIT(5)), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_CNP_INT, 0, BIT(6)), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_OCP_INT, 0, BIT(7)), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_CNP_INT, 1, BIT(0)), + REGMAP_IRQ_REG(WCD937X_IRQ_EAR_CNP_INT, 1, BIT(1)), + REGMAP_IRQ_REG(WCD937X_IRQ_EAR_SCD_INT, 1, BIT(2)), + REGMAP_IRQ_REG(WCD937X_IRQ_AUX_CNP_INT, 1, BIT(3)), + REGMAP_IRQ_REG(WCD937X_IRQ_AUX_SCD_INT, 1, BIT(4)), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_PDM_WD_INT, 1, BIT(5)), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_PDM_WD_INT, 1, BIT(6)), + REGMAP_IRQ_REG(WCD937X_IRQ_AUX_PDM_WD_INT, 1, BIT(7)), + REGMAP_IRQ_REG(WCD937X_IRQ_LDORT_SCD_INT, 2, BIT(0)), + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_MOISTURE_INT, 2, BIT(1)), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_SURGE_DET_INT, 2, BIT(2)), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_SURGE_DET_INT, 2, BIT(3)), +}; + +static int wcd937x_handle_post_irq(void *data) +{ + struct wcd937x_priv *wcd937x; + + if (data) + wcd937x = (struct wcd937x_priv *)data; + else + return IRQ_HANDLED; + + regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_0, 0); + regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_1, 0); + regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_2, 0); + + return IRQ_HANDLED; +} + +static const u32 wcd937x_config_regs[] = { + WCD937X_DIGITAL_INTR_LEVEL_0, +}; + +static struct regmap_irq_chip wcd937x_regmap_irq_chip = { + .name = "wcd937x", + .irqs = wcd937x_irqs, + .num_irqs = ARRAY_SIZE(wcd937x_irqs), + .num_regs = 3, + .status_base = WCD937X_DIGITAL_INTR_STATUS_0, + .mask_base = WCD937X_DIGITAL_INTR_MASK_0, + .ack_base = WCD937X_DIGITAL_INTR_CLEAR_0, + .use_ack = 1, + .clear_ack = 1, + .config_base = wcd937x_config_regs, + .num_config_bases = ARRAY_SIZE(wcd937x_config_regs), + .num_config_regs = 1, + .runtime_pm = true, + .handle_post_irq = wcd937x_handle_post_irq, + .irq_drv_data = NULL, +}; + +static void wcd937x_reset(struct wcd937x_priv *wcd937x) +{ + usleep_range(20, 30); + + gpiod_set_value(wcd937x->reset_gpio, 1); + + usleep_range(20, 30); +} + +static void wcd937x_io_init(struct regmap *regmap) +{ + u32 val = 0, temp = 0, temp1 = 0; + + regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_29, &val); + + val = val & 0x0F; + + regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_16, &temp); + regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_17, &temp1); + + if (temp == 0x02 || temp1 > 0x09) + regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x0E, val); + else + regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x0e, 0x0e); + + regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x80, 0x80); + usleep_range(1000, 1010); + + regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x40, 0x40); + usleep_range(1000, 1010); + + regmap_update_bits(regmap, WCD937X_LDORXTX_CONFIG, BIT(4), 0x00); + regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xf0, BIT(7)); + regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(7), BIT(7)); + regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(6), BIT(6)); + usleep_range(10000, 10010); + + regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(6), 0x00); + regmap_update_bits(regmap, WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xff, 0xd9); + regmap_update_bits(regmap, WCD937X_MICB1_TEST_CTL_1, 0xff, 0xfa); + regmap_update_bits(regmap, WCD937X_MICB2_TEST_CTL_1, 0xff, 0xfa); + regmap_update_bits(regmap, WCD937X_MICB3_TEST_CTL_1, 0xff, 0xfa); + + regmap_update_bits(regmap, WCD937X_MICB1_TEST_CTL_2, 0x38, 0x00); + regmap_update_bits(regmap, WCD937X_MICB2_TEST_CTL_2, 0x38, 0x00); + regmap_update_bits(regmap, WCD937X_MICB3_TEST_CTL_2, 0x38, 0x00); + + /* Set Bandgap Fine Adjustment to +5mV for Tanggu SMIC part */ + regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_16, &val); + if (val == 0x01) { + regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0); + } else if (val == 0x02) { + regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x1F, 0x04); + regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x1F, 0x04); + regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0); + regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xF0, 0x50); + } +} + +static int wcd937x_rx_clk_enable(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + if (atomic_read(&wcd937x->rx_clk_cnt)) + return 0; + + snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(3), BIT(3)); + snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(0), BIT(0)); + snd_soc_component_update_bits(component, WCD937X_ANA_RX_SUPPLIES, BIT(0), BIT(0)); + snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX0_CTL, BIT(6), 0x00); + snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX1_CTL, BIT(6), 0x00); + snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX2_CTL, BIT(6), 0x00); + snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(1), BIT(1)); + + atomic_inc(&wcd937x->rx_clk_cnt); + + return 0; +} + +static int wcd937x_rx_clk_disable(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + if (!atomic_read(&wcd937x->rx_clk_cnt)) { + dev_err(component->dev, "clk already disabled\n"); + return 0; + } + + atomic_dec(&wcd937x->rx_clk_cnt); + + snd_soc_component_update_bits(component, WCD937X_ANA_RX_SUPPLIES, BIT(0), 0x00); + snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(1), 0x00); + snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(0), 0x00); + + return 0; +} + +static int wcd937x_get_micb_vout_ctl_val(u32 micb_mv) +{ + if (micb_mv < 1000 || micb_mv > 2850) { + pr_err("Unsupported micbias voltage (%u mV)\n", micb_mv); + return -EINVAL; + } + + return (micb_mv - 1000) / 50; +} + +static int wcd937x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int micb_index = micb_num - 1; + u16 micb_reg; + + if (micb_index < 0 || (micb_index > WCD937X_MAX_MICBIAS - 1)) { + dev_err(component->dev, "Invalid micbias index, micb_ind:%d\n", micb_index); + return -EINVAL; + } + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD937X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD937X_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD937X_ANA_MICB3; + break; + default: + dev_err(component->dev, "Invalid micbias number: %d\n", micb_num); + return -EINVAL; + } + + mutex_lock(&wcd937x->micb_lock); + switch (req) { + case MICB_PULLUP_ENABLE: + wcd937x->pullup_ref[micb_index]++; + if (wcd937x->pullup_ref[micb_index] == 1 && + wcd937x->micb_ref[micb_index] == 0) + snd_soc_component_update_bits(component, micb_reg, + 0xc0, BIT(7)); + break; + case MICB_PULLUP_DISABLE: + if (wcd937x->pullup_ref[micb_index] > 0) + wcd937x->pullup_ref[micb_index]++; + if (wcd937x->pullup_ref[micb_index] == 0 && + wcd937x->micb_ref[micb_index] == 0) + snd_soc_component_update_bits(component, micb_reg, + 0xc0, 0x00); + break; + case MICB_ENABLE: + wcd937x->micb_ref[micb_index]++; + atomic_inc(&wcd937x->ana_clk_count); + if (wcd937x->micb_ref[micb_index] == 1) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + 0xf0, 0xf0); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(4), BIT(4)); + snd_soc_component_update_bits(component, + WCD937X_MICB1_TEST_CTL_2, + BIT(0), BIT(0)); + snd_soc_component_update_bits(component, + WCD937X_MICB2_TEST_CTL_2, + BIT(0), BIT(0)); + snd_soc_component_update_bits(component, + WCD937X_MICB3_TEST_CTL_2, + BIT(0), BIT(0)); + snd_soc_component_update_bits(component, + micb_reg, 0xc0, BIT(6)); + + if (micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd937x->wcd_mbhc, + WCD_EVENT_POST_MICBIAS_2_ON); + + if (micb_num == MIC_BIAS_2 && is_dapm) + wcd_mbhc_event_notify(wcd937x->wcd_mbhc, + WCD_EVENT_POST_DAPM_MICBIAS_2_ON); + } + break; + case MICB_DISABLE: + atomic_dec(&wcd937x->ana_clk_count); + if (wcd937x->micb_ref[micb_index] > 0) + wcd937x->micb_ref[micb_index]--; + if (wcd937x->micb_ref[micb_index] == 0 && + wcd937x->pullup_ref[micb_index] > 0) + snd_soc_component_update_bits(component, micb_reg, + 0xc0, BIT(7)); + else if (wcd937x->micb_ref[micb_index] == 0 && + wcd937x->pullup_ref[micb_index] == 0) { + if (micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd937x->wcd_mbhc, + WCD_EVENT_PRE_MICBIAS_2_OFF); + + snd_soc_component_update_bits(component, micb_reg, + 0xc0, 0x00); + if (micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd937x->wcd_mbhc, + WCD_EVENT_POST_MICBIAS_2_OFF); + } + + if (is_dapm && micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd937x->wcd_mbhc, + WCD_EVENT_POST_DAPM_MICBIAS_2_OFF); + if (atomic_read(&wcd937x->ana_clk_count) <= 0) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(4), 0x00); + atomic_set(&wcd937x->ana_clk_count, 0); + } + break; + } + mutex_unlock(&wcd937x->micb_lock); + + return 0; +} + +static int wcd937x_connect_port(struct wcd937x_sdw_priv *wcd, u8 port_idx, u8 ch_id, bool enable) +{ + struct sdw_port_config *port_config = &wcd->port_config[port_idx - 1]; + struct wcd937x_sdw_ch_info *ch_info = &wcd->ch_info[ch_id]; + u8 port_num = ch_info->port_num; + u8 ch_mask = ch_info->ch_mask; + + port_config->num = port_num; + + if (enable) + port_config->ch_mask |= ch_mask; + else + port_config->ch_mask &= ~ch_mask; + + return 0; +} + +/* MBHC related */ +static void wcd937x_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_1, + WCD937X_MBHC_CTL_RCO_EN_MASK, enable); +} + +static void wcd937x_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, WCD937X_ANA_MBHC_ELECT, + WCD937X_ANA_MBHC_BIAS_EN, enable); +} + +static void wcd937x_mbhc_program_btn_thr(struct snd_soc_component *component, + int *btn_low, int *btn_high, + int num_btn, bool is_micbias) +{ + int i, vth; + + if (num_btn > WCD_MBHC_DEF_BUTTONS) { + dev_err(component->dev, "%s: invalid number of buttons: %d\n", + __func__, num_btn); + return; + } + + for (i = 0; i < num_btn; i++) { + vth = ((btn_high[i] * 2) / 25) & 0x3F; + snd_soc_component_write_field(component, WCD937X_ANA_MBHC_BTN0 + i, + WCD937X_MBHC_BTN_VTH_MASK, vth); + } +} + +static bool wcd937x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num) +{ + u8 val; + + if (micb_num == MIC_BIAS_2) { + val = snd_soc_component_read_field(component, + WCD937X_ANA_MICB2, + WCD937X_ANA_MICB2_ENABLE_MASK); + if (val == WCD937X_MICB_ENABLE) + return true; + } + return false; +} + +static void wcd937x_mbhc_hph_l_pull_up_control(struct snd_soc_component *component, + int pull_up_cur) +{ + /* Default pull up current to 2uA */ + if (pull_up_cur > HS_PULLUP_I_OFF || pull_up_cur < HS_PULLUP_I_3P0_UA) + pull_up_cur = HS_PULLUP_I_2P0_UA; + + snd_soc_component_write_field(component, + WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, + WCD937X_HSDET_PULLUP_C_MASK, pull_up_cur); +} + +static int wcd937x_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + return wcd937x_micbias_control(component, micb_num, req, false); +} + +static void wcd937x_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP, + WCD937X_RAMP_SHIFT_CTRL_MASK, 0x0C); + snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP, + WCD937X_RAMP_EN_MASK, 1); + } else { + snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP, + WCD937X_RAMP_EN_MASK, 0); + snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP, + WCD937X_RAMP_SHIFT_CTRL_MASK, 0); + } +} + +static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, int micb_num) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD937X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD937X_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD937X_ANA_MICB3; + break; + default: + return -EINVAL; + } + mutex_lock(&wcd937x->micb_lock); + /* + * If requested micbias voltage is same as current micbias + * voltage, then just return. Otherwise, adjust voltage as + * per requested value. If micbias is already enabled, then + * to avoid slow micbias ramp-up or down enable pull-up + * momentarily, change the micbias value and then re-enable + * micbias. + */ + micb_en = snd_soc_component_read_field(component, micb_reg, + WCD937X_MICB_EN_MASK); + cur_vout_ctl = snd_soc_component_read_field(component, micb_reg, + WCD937X_MICB_VOUT_MASK); + + req_vout_ctl = wcd937x_get_micb_vout_ctl_val(req_volt); + if (req_vout_ctl < 0) { + ret = -EINVAL; + goto exit; + } + + if (cur_vout_ctl == req_vout_ctl) { + ret = 0; + goto exit; + } + + if (micb_en == WCD937X_MICB_ENABLE) + snd_soc_component_write_field(component, micb_reg, + WCD937X_MICB_EN_MASK, + WCD937X_MICB_PULL_UP); + + snd_soc_component_write_field(component, micb_reg, + WCD937X_MICB_VOUT_MASK, + req_vout_ctl); + + if (micb_en == WCD937X_MICB_ENABLE) { + snd_soc_component_write_field(component, micb_reg, + WCD937X_MICB_EN_MASK, + WCD937X_MICB_ENABLE); + /* + * Add 2ms delay as per HW requirement after enabling + * micbias + */ + usleep_range(2000, 2100); + } +exit: + mutex_unlock(&wcd937x->micb_lock); + return ret; +} + +static int wcd937x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int micb_mv; + + if (micb_num != MIC_BIAS_2) + return -EINVAL; + /* + * If device tree micbias level is already above the minimum + * voltage needed to detect threshold microphone, then do + * not change the micbias, just return. + */ + if (wcd937x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV) + return 0; + + micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd937x->micb2_mv; + + return wcd937x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); +} + +static void wcd937x_mbhc_get_result_params(struct snd_soc_component *component, + s16 *d1_a, u16 noff, + int32_t *zdet) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int i; + int val, val1; + s16 c1; + s32 x1, d1; + s32 denom; + static const int minCode_param[] = { + 3277, 1639, 820, 410, 205, 103, 52, 26 + }; + + regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x20); + for (i = 0; i < WCD937X_ZDET_NUM_MEASUREMENTS; i++) { + regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_2, &val); + if (val & 0x80) + break; + } + val = val << 0x8; + regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_1, &val1); + val |= val1; + regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x00); + x1 = WCD937X_MBHC_GET_X1(val); + c1 = WCD937X_MBHC_GET_C1(val); + /* If ramp is not complete, give additional 5ms */ + if (c1 < 2 && x1) + usleep_range(5000, 5050); + + if (!c1 || !x1) { + dev_err(component->dev, "Impedance detect ramp error, c1=%d, x1=0x%x\n", + c1, x1); + goto ramp_down; + } + d1 = d1_a[c1]; + denom = (x1 * d1) - (1 << (14 - noff)); + if (denom > 0) + *zdet = (WCD937X_MBHC_ZDET_CONST * 1000) / denom; + else if (x1 < minCode_param[noff]) + *zdet = WCD937X_ZDET_FLOATING_IMPEDANCE; + + dev_err(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d (milliohm)\n", + __func__, d1, c1, x1, *zdet); +ramp_down: + i = 0; + while (x1) { + regmap_read(wcd937x->regmap, + WCD937X_ANA_MBHC_RESULT_1, &val); + regmap_read(wcd937x->regmap, + WCD937X_ANA_MBHC_RESULT_2, &val1); + val = val << 0x08; + val |= val1; + x1 = WCD937X_MBHC_GET_X1(val); + i++; + if (i == WCD937X_ZDET_NUM_MEASUREMENTS) + break; + } +} + +static void wcd937x_mbhc_zdet_ramp(struct snd_soc_component *component, + struct wcd937x_mbhc_zdet_param *zdet_param, + s32 *zl, s32 *zr, s16 *d1_a) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + s32 zdet = 0; + + snd_soc_component_write_field(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL, + WCD937X_ZDET_MAXV_CTL_MASK, zdet_param->ldo_ctl); + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN5, + WCD937X_VTH_MASK, zdet_param->btn5); + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN6, + WCD937X_VTH_MASK, zdet_param->btn6); + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN7, + WCD937X_VTH_MASK, zdet_param->btn7); + snd_soc_component_write_field(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL, + WCD937X_ZDET_RANGE_CTL_MASK, zdet_param->noff); + snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_ZDET_RAMP_CTL, + 0x0F, zdet_param->nshift); + + if (!zl) + goto z_right; + /* Start impedance measurement for HPH_L */ + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ZDET, 0x80, 0x80); + wcd937x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ZDET, 0x80, 0x00); + + *zl = zdet; + +z_right: + if (!zr) + return; + /* Start impedance measurement for HPH_R */ + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ZDET, 0x40, 0x40); + wcd937x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ZDET, 0x40, 0x00); + + *zr = zdet; +} + +static void wcd937x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, + s32 *z_val, int flag_l_r) +{ + s16 q1; + int q1_cal; + + if (*z_val < (WCD937X_ZDET_VAL_400 / 1000)) + q1 = snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r)); + else + q1 = snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r)); + if (q1 & 0x80) + q1_cal = (10000 - ((q1 & 0x7F) * 25)); + else + q1_cal = (10000 + (q1 * 25)); + if (q1_cal > 0) + *z_val = ((*z_val) * 10000) / q1_cal; +} + +static void wcd937x_wcd_mbhc_calc_impedance(struct snd_soc_component *component, + u32 *zl, u32 *zr) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + s16 reg0, reg1, reg2, reg3, reg4; + s32 z1l, z1r, z1ls; + int zMono, z_diff1, z_diff2; + bool is_fsm_disable = false; + struct wcd937x_mbhc_zdet_param zdet_param[] = { + {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */ + {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */ + {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */ + {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */ + }; + struct wcd937x_mbhc_zdet_param *zdet_param_ptr = NULL; + s16 d1_a[][4] = { + {0, 30, 90, 30}, + {0, 30, 30, 5}, + {0, 30, 30, 5}, + {0, 30, 30, 5}, + }; + s16 *d1 = NULL; + + reg0 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN5); + reg1 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN6); + reg2 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN7); + reg3 = snd_soc_component_read(component, WCD937X_MBHC_CTL_CLK); + reg4 = snd_soc_component_read(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL); + + if (snd_soc_component_read(component, WCD937X_ANA_MBHC_ELECT) & 0x80) { + is_fsm_disable = true; + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ELECT, 0x80, 0x00); + } + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (wcd937x->mbhc_cfg.hphl_swh) + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_MECH, 0x80, 0x00); + + /* Turn off 100k pull down on HPHL */ + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_MECH, 0x01, 0x00); + + /* Disable surge protection before impedance detection. + * This is done to give correct value for high impedance. + */ + regmap_update_bits(wcd937x->regmap, + WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00); + /* 1ms delay needed after disable surge protection */ + usleep_range(1000, 1010); + + /* First get impedance on Left */ + d1 = d1_a[1]; + zdet_param_ptr = &zdet_param[1]; + wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1l, NULL, d1); + + if (!WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1l)) + goto left_ch_impedance; + + /* Second ramp for left ch */ + if (z1l < WCD937X_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1l > WCD937X_ZDET_VAL_400) && + (z1l <= WCD937X_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1l > WCD937X_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1l, NULL, d1); + +left_ch_impedance: + if (z1l == WCD937X_ZDET_FLOATING_IMPEDANCE || + z1l > WCD937X_ZDET_VAL_100K) { + *zl = WCD937X_ZDET_FLOATING_IMPEDANCE; + zdet_param_ptr = &zdet_param[1]; + d1 = d1_a[1]; + } else { + *zl = z1l / 1000; + wcd937x_wcd_mbhc_qfuse_cal(component, zl, 0); + } + + /* Start of right impedance ramp and calculation */ + wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1r, d1); + if (WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1r)) { + if ((z1r > WCD937X_ZDET_VAL_1200 && + zdet_param_ptr->noff == 0x6) || + ((*zl) != WCD937X_ZDET_FLOATING_IMPEDANCE)) + goto right_ch_impedance; + /* Second ramp for right ch */ + if (z1r < WCD937X_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1r > WCD937X_ZDET_VAL_400) && + (z1r <= WCD937X_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1r > WCD937X_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1r, d1); + } +right_ch_impedance: + if (z1r == WCD937X_ZDET_FLOATING_IMPEDANCE || + z1r > WCD937X_ZDET_VAL_100K) { + *zr = WCD937X_ZDET_FLOATING_IMPEDANCE; + } else { + *zr = z1r / 1000; + wcd937x_wcd_mbhc_qfuse_cal(component, zr, 1); + } + + /* Mono/stereo detection */ + if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) && + (*zr == WCD937X_ZDET_FLOATING_IMPEDANCE)) { + dev_err(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) || + (*zr == WCD937X_ZDET_FLOATING_IMPEDANCE) || + ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) || + ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) { + wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_MONO); + goto zdet_complete; + } + snd_soc_component_write_field(component, WCD937X_HPH_R_ATEST, + WCD937X_HPHPA_GND_OVR_MASK, 1); + snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2, + WCD937X_HPHPA_GND_R_MASK, 1); + if (*zl < (WCD937X_ZDET_VAL_32 / 1000)) + wcd937x_mbhc_zdet_ramp(component, &zdet_param[0], &z1ls, NULL, d1); + else + wcd937x_mbhc_zdet_ramp(component, &zdet_param[1], &z1ls, NULL, d1); + snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2, + WCD937X_HPHPA_GND_R_MASK, 0); + snd_soc_component_write_field(component, WCD937X_HPH_R_ATEST, + WCD937X_HPHPA_GND_OVR_MASK, 0); + z1ls /= 1000; + wcd937x_wcd_mbhc_qfuse_cal(component, &z1ls, 0); + /* Parallel of left Z and 9 ohm pull down resistor */ + zMono = ((*zl) * 9) / ((*zl) + 9); + z_diff1 = (z1ls > zMono) ? (z1ls - zMono) : (zMono - z1ls); + z_diff2 = ((*zl) > z1ls) ? ((*zl) - z1ls) : (z1ls - (*zl)); + if ((z_diff1 * (*zl + z1ls)) > (z_diff2 * (z1ls + zMono))) + wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_STEREO); + else + wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_MONO); + + /* Enable surge protection again after impedance detection */ + regmap_update_bits(wcd937x->regmap, + WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0); +zdet_complete: + snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN5, reg0); + snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN6, reg1); + snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN7, reg2); + /* Turn on 100k pull down on HPHL */ + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_MECH, 0x01, 0x01); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (wcd937x->mbhc_cfg.hphl_swh) + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_MECH, 0x80, 0x80); + + snd_soc_component_write(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL, reg4); + snd_soc_component_write(component, WCD937X_MBHC_CTL_CLK, reg3); + if (is_fsm_disable) + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ELECT, 0x80, 0x80); +} + +static void wcd937x_mbhc_gnd_det_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH, + WCD937X_MBHC_HSG_PULLUP_COMP_EN, 1); + snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH, + WCD937X_MBHC_GND_DET_EN_MASK, 1); + } else { + snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH, + WCD937X_MBHC_GND_DET_EN_MASK, 0); + snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH, + WCD937X_MBHC_HSG_PULLUP_COMP_EN, 0); + } +} + +static void wcd937x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2, + WCD937X_HPHPA_GND_R_MASK, enable); + snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2, + WCD937X_HPHPA_GND_L_MASK, enable); +} + +static void wcd937x_mbhc_moisture_config(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + if (wcd937x->mbhc_cfg.moist_rref == R_OFF) { + snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2, + WCD937X_M_RTH_CTL_MASK, R_OFF); + return; + } + + /* Do not enable moisture detection if jack type is NC */ + if (!wcd937x->mbhc_cfg.hphl_swh) { + dev_err(component->dev, "%s: disable moisture detection for NC\n", + __func__); + snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2, + WCD937X_M_RTH_CTL_MASK, R_OFF); + return; + } + + snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2, + WCD937X_M_RTH_CTL_MASK, wcd937x->mbhc_cfg.moist_rref); +} + +static void wcd937x_mbhc_moisture_detect_en(struct snd_soc_component *component, bool enable) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + if (enable) + snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2, + WCD937X_M_RTH_CTL_MASK, wcd937x->mbhc_cfg.moist_rref); + else + snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2, + WCD937X_M_RTH_CTL_MASK, R_OFF); +} + +static bool wcd937x_mbhc_get_moisture_status(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + bool ret = false; + + if (wcd937x->mbhc_cfg.moist_rref == R_OFF) { + snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2, + WCD937X_M_RTH_CTL_MASK, R_OFF); + goto done; + } + + /* Do not enable moisture detection if jack type is NC */ + if (!wcd937x->mbhc_cfg.hphl_swh) { + dev_err(component->dev, "%s: disable moisture detection for NC\n", + __func__); + snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2, + WCD937X_M_RTH_CTL_MASK, R_OFF); + goto done; + } + + /* + * If moisture_en is already enabled, then skip to plug type + * detection. + */ + if (snd_soc_component_read_field(component, WCD937X_MBHC_NEW_CTL_2, WCD937X_M_RTH_CTL_MASK)) + goto done; + + wcd937x_mbhc_moisture_detect_en(component, true); + /* Read moisture comparator status */ + ret = ((snd_soc_component_read(component, WCD937X_MBHC_NEW_FSM_STATUS) + & 0x20) ? 0 : 1); +done: + return ret; +} + +static void wcd937x_mbhc_moisture_polling_ctrl(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, + WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, + WCD937X_MOISTURE_EN_POLLING_MASK, enable); +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .clk_setup = wcd937x_mbhc_clk_setup, + .mbhc_bias = wcd937x_mbhc_mbhc_bias_control, + .set_btn_thr = wcd937x_mbhc_program_btn_thr, + .micbias_enable_status = wcd937x_mbhc_micb_en_status, + .hph_pull_up_control_v2 = wcd937x_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = wcd937x_mbhc_request_micbias, + .mbhc_micb_ramp_control = wcd937x_mbhc_micb_ramp_control, + .mbhc_micb_ctrl_thr_mic = wcd937x_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = wcd937x_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = wcd937x_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = wcd937x_mbhc_hph_pull_down_ctrl, + .mbhc_moisture_config = wcd937x_mbhc_moisture_config, + .mbhc_get_moisture_status = wcd937x_mbhc_get_moisture_status, + .mbhc_moisture_polling_ctrl = wcd937x_mbhc_moisture_polling_ctrl, + .mbhc_moisture_detect_en = wcd937x_mbhc_moisture_detect_en, +}; + +static int wcd937x_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd937x->wcd_mbhc); + + return 0; +} + +static int wcd937x_hph_impedance_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 zl, zr; + bool hphr; + struct soc_mixer_control *mc; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + mc = (struct soc_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + wcd_mbhc_get_impedance(wcd937x->wcd_mbhc, &zl, &zr); + ucontrol->value.integer.value[0] = hphr ? zr : zl; + + return 0; +} + +static const struct snd_kcontrol_new hph_type_detect_controls[] = { + SOC_SINGLE_EXT("HPH Type", 0, 0, WCD_MBHC_HPH_STEREO, 0, + wcd937x_get_hph_type, NULL), +}; + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, INT_MAX, 0, + wcd937x_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, INT_MAX, 0, + wcd937x_hph_impedance_get, NULL), +}; + +static int wcd937x_mbhc_init(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + struct wcd_mbhc_intr *intr_ids = &wcd937x->intr_ids; + + intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd937x->irq_chip, + WCD937X_IRQ_MBHC_SW_DET); + intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(wcd937x->irq_chip, + WCD937X_IRQ_MBHC_BUTTON_PRESS_DET); + intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(wcd937x->irq_chip, + WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET); + intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(wcd937x->irq_chip, + WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET); + intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(wcd937x->irq_chip, + WCD937X_IRQ_MBHC_ELECT_INS_REM_DET); + intr_ids->hph_left_ocp = regmap_irq_get_virq(wcd937x->irq_chip, + WCD937X_IRQ_HPHL_OCP_INT); + intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd937x->irq_chip, + WCD937X_IRQ_HPHR_OCP_INT); + + wcd937x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true); + if (IS_ERR(wcd937x->wcd_mbhc)) + return PTR_ERR(wcd937x->wcd_mbhc); + + snd_soc_add_component_controls(component, impedance_detect_controls, + ARRAY_SIZE(impedance_detect_controls)); + snd_soc_add_component_controls(component, hph_type_detect_controls, + ARRAY_SIZE(hph_type_detect_controls)); + + return 0; +} + +static void wcd937x_mbhc_deinit(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + wcd_mbhc_deinit(wcd937x->wcd_mbhc); +} + +/* END MBHC */ + +static int wcd937x_set_micbias_data(struct wcd937x_priv *wcd937x) +{ + int vout_ctl[3]; + + /* Set micbias voltage */ + vout_ctl[0] = wcd937x_get_micb_vout_ctl_val(wcd937x->micb1_mv); + vout_ctl[1] = wcd937x_get_micb_vout_ctl_val(wcd937x->micb2_mv); + vout_ctl[2] = wcd937x_get_micb_vout_ctl_val(wcd937x->micb3_mv); + if ((vout_ctl[0] | vout_ctl[1] | vout_ctl[2]) < 0) + return -EINVAL; + + regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB1, WCD937X_ANA_MICB_VOUT, vout_ctl[0]); + regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB2, WCD937X_ANA_MICB_VOUT, vout_ctl[1]); + regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB3, WCD937X_ANA_MICB_VOUT, vout_ctl[2]); + + return 0; +} + +static irqreturn_t wcd937x_wd_handle_irq(int irq, void *data) +{ + return IRQ_HANDLED; +} + +static struct irq_chip wcd_irq_chip = { + .name = "WCD937x", +}; + +static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq); + irq_set_nested_thread(virq, 1); + irq_set_noprobe(virq); + + return 0; +} + +static const struct irq_domain_ops wcd_domain_ops = { + .map = wcd_irq_chip_map, +}; + +static int wcd937x_irq_init(struct wcd937x_priv *wcd, struct device *dev) +{ + wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL); + if (!(wcd->virq)) { + dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); + return -EINVAL; + } + + return devm_regmap_add_irq_chip(dev, wcd->regmap, + irq_create_mapping(wcd->virq, 0), + IRQF_ONESHOT, 0, &wcd937x_regmap_irq_chip, + &wcd->irq_chip); +} + +static int wcd937x_soc_codec_probe(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + struct sdw_slave *tx_sdw_dev = wcd937x->tx_sdw_dev; + struct device *dev = component->dev; + unsigned long time_left; + int i, ret; + + time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete, + msecs_to_jiffies(5000)); + if (!time_left) { + dev_err(dev, "soundwire device init timeout\n"); + return -ETIMEDOUT; + } + + snd_soc_component_init_regmap(component, wcd937x->regmap); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + wcd937x->chipid = (snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_0) & 0x1e) >> 1; + if (wcd937x->chipid != CHIPID_WCD9370 && + wcd937x->chipid != CHIPID_WCD9375) { + dev_err(dev, "Got unknown chip id: 0x%x\n", wcd937x->chipid); + pm_runtime_put(dev); + return -EINVAL; + } + + wcd937x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD937X); + if (IS_ERR(wcd937x->clsh_info)) { + pm_runtime_put(dev); + return PTR_ERR(wcd937x->clsh_info); + } + + wcd937x_io_init(wcd937x->regmap); + /* Set all interrupts as edge triggered */ + for (i = 0; i < wcd937x_regmap_irq_chip.num_regs; i++) + regmap_write(wcd937x->regmap, (WCD937X_DIGITAL_INTR_LEVEL_0 + i), 0); + + pm_runtime_put(dev); + + wcd937x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip, + WCD937X_IRQ_HPHR_PDM_WD_INT); + wcd937x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip, + WCD937X_IRQ_HPHL_PDM_WD_INT); + wcd937x->aux_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip, + WCD937X_IRQ_AUX_PDM_WD_INT); + + /* Request for watchdog interrupt */ + ret = devm_request_threaded_irq(dev, wcd937x->hphr_pdm_wd_int, NULL, wcd937x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "HPHR PDM WDOG INT", wcd937x); + if (ret) + dev_err(dev, "Failed to request HPHR watchdog interrupt (%d)\n", ret); + + ret = devm_request_threaded_irq(dev, wcd937x->hphl_pdm_wd_int, NULL, wcd937x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "HPHL PDM WDOG INT", wcd937x); + if (ret) + dev_err(dev, "Failed to request HPHL watchdog interrupt (%d)\n", ret); + + ret = devm_request_threaded_irq(dev, wcd937x->aux_pdm_wd_int, NULL, wcd937x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "AUX PDM WDOG INT", wcd937x); + if (ret) + dev_err(dev, "Failed to request Aux watchdog interrupt (%d)\n", ret); + + /* Disable watchdog interrupt for HPH and AUX */ + disable_irq_nosync(wcd937x->hphr_pdm_wd_int); + disable_irq_nosync(wcd937x->hphl_pdm_wd_int); + disable_irq_nosync(wcd937x->aux_pdm_wd_int); + + ret = wcd937x_mbhc_init(component); + if (ret) + dev_err(component->dev, "mbhc initialization failed\n"); + + return ret; +} + +static void wcd937x_soc_codec_remove(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + wcd937x_mbhc_deinit(component); + free_irq(wcd937x->aux_pdm_wd_int, wcd937x); + free_irq(wcd937x->hphl_pdm_wd_int, wcd937x); + free_irq(wcd937x->hphr_pdm_wd_int, wcd937x); + + wcd_clsh_ctrl_free(wcd937x->clsh_info); +} + +static int wcd937x_codec_set_jack(struct snd_soc_component *comp, + struct snd_soc_jack *jack, void *data) +{ + struct wcd937x_priv *wcd = dev_get_drvdata(comp->dev); + int ret = 0; + + if (jack) + ret = wcd_mbhc_start(wcd->wcd_mbhc, &wcd->mbhc_cfg, jack); + else + wcd_mbhc_stop(wcd->wcd_mbhc); + + return ret; +} + +static const struct snd_soc_component_driver soc_codec_dev_wcd937x = { + .name = "wcd937x_codec", + .probe = wcd937x_soc_codec_probe, + .remove = wcd937x_soc_codec_remove, + .set_jack = wcd937x_codec_set_jack, + .endianness = 1, +}; + +static void wcd937x_dt_parse_micbias_info(struct device *dev, struct wcd937x_priv *wcd) +{ + struct device_node *np = dev->of_node; + u32 prop_val = 0; + int ret = 0; + + ret = of_property_read_u32(np, "qcom,micbias1-microvolt", &prop_val); + if (!ret) + wcd->micb1_mv = prop_val / 1000; + else + dev_warn(dev, "Micbias1 DT property not found\n"); + + ret = of_property_read_u32(np, "qcom,micbias2-microvolt", &prop_val); + if (!ret) + wcd->micb2_mv = prop_val / 1000; + else + dev_warn(dev, "Micbias2 DT property not found\n"); + + ret = of_property_read_u32(np, "qcom,micbias3-microvolt", &prop_val); + if (!ret) + wcd->micb3_mv = prop_val / 1000; + else + dev_warn(dev, "Micbias3 DT property not found\n"); +} + +static bool wcd937x_swap_gnd_mic(struct snd_soc_component *component, bool active) +{ + int value; + struct wcd937x_priv *wcd937x; + + wcd937x = snd_soc_component_get_drvdata(component); + + value = gpiod_get_value(wcd937x->us_euro_gpio); + gpiod_set_value(wcd937x->us_euro_gpio, !value); + + return true; +} + +static int wcd937x_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev); + struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id]; + + return wcd937x_sdw_hw_params(wcd, substream, params, dai); +} + +static int wcd937x_codec_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev); + struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id]; + + return sdw_stream_remove_slave(wcd->sdev, wcd->sruntime); +} + +static int wcd937x_codec_set_sdw_stream(struct snd_soc_dai *dai, + void *stream, int direction) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev); + struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id]; + + wcd->sruntime = stream; + + return 0; +} + +static const struct snd_soc_dai_ops wcd937x_sdw_dai_ops = { + .hw_params = wcd937x_codec_hw_params, + .hw_free = wcd937x_codec_free, + .set_stream = wcd937x_codec_set_sdw_stream, +}; + +static struct snd_soc_dai_driver wcd937x_dais[] = { + [0] = { + .name = "wcd937x-sdw-rx", + .playback = { + .stream_name = "WCD AIF Playback", + .rates = WCD937X_RATES | WCD937X_FRAC_RATES, + .formats = WCD937X_FORMATS, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd937x_sdw_dai_ops, + }, + [1] = { + .name = "wcd937x-sdw-tx", + .capture = { + .stream_name = "WCD AIF Capture", + .rates = WCD937X_RATES, + .formats = WCD937X_FORMATS, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd937x_sdw_dai_ops, + }, +}; + +static int wcd937x_bind(struct device *dev) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(dev); + int ret; + + /* Give the SDW subdevices some more time to settle */ + usleep_range(5000, 5010); + + ret = component_bind_all(dev, wcd937x); + if (ret) { + dev_err(dev, "Slave bind failed, ret = %d\n", ret); + return ret; + } + + wcd937x->rxdev = wcd937x_sdw_device_get(wcd937x->rxnode); + if (!wcd937x->rxdev) { + dev_err(dev, "could not find slave with matching of node\n"); + return -EINVAL; + } + + wcd937x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd937x->rxdev); + wcd937x->sdw_priv[AIF1_PB]->wcd937x = wcd937x; + + wcd937x->txdev = wcd937x_sdw_device_get(wcd937x->txnode); + if (!wcd937x->txdev) { + dev_err(dev, "could not find txslave with matching of node\n"); + return -EINVAL; + } + + wcd937x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd937x->txdev); + wcd937x->sdw_priv[AIF1_CAP]->wcd937x = wcd937x; + wcd937x->tx_sdw_dev = dev_to_sdw_dev(wcd937x->txdev); + if (!wcd937x->tx_sdw_dev) { + dev_err(dev, "could not get txslave with matching of dev\n"); + return -EINVAL; + } + + /* + * As TX is the main CSR reg interface, which should not be suspended first. + * expicilty add the dependency link + */ + if (!device_link_add(wcd937x->rxdev, wcd937x->txdev, + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "Could not devlink TX and RX\n"); + return -EINVAL; + } + + if (!device_link_add(dev, wcd937x->txdev, + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "Could not devlink WCD and TX\n"); + return -EINVAL; + } + + if (!device_link_add(dev, wcd937x->rxdev, + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "Could not devlink WCD and RX\n"); + return -EINVAL; + } + + wcd937x->regmap = dev_get_regmap(&wcd937x->tx_sdw_dev->dev, NULL); + if (!wcd937x->regmap) { + dev_err(dev, "could not get TX device regmap\n"); + return -EINVAL; + } + + ret = wcd937x_irq_init(wcd937x, dev); + if (ret) { + dev_err(dev, "IRQ init failed: %d\n", ret); + return ret; + } + + wcd937x->sdw_priv[AIF1_PB]->slave_irq = wcd937x->virq; + wcd937x->sdw_priv[AIF1_CAP]->slave_irq = wcd937x->virq; + + ret = wcd937x_set_micbias_data(wcd937x); + if (ret < 0) { + dev_err(dev, "Bad micbias pdata\n"); + return ret; + } + + ret = snd_soc_register_component(dev, &soc_codec_dev_wcd937x, + wcd937x_dais, ARRAY_SIZE(wcd937x_dais)); + if (ret) + dev_err(dev, "Codec registration failed\n"); + + return ret; +} + +static void wcd937x_unbind(struct device *dev) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(dev); + + snd_soc_unregister_component(dev); + device_link_remove(dev, wcd937x->txdev); + device_link_remove(dev, wcd937x->rxdev); + device_link_remove(wcd937x->rxdev, wcd937x->txdev); + component_unbind_all(dev, wcd937x); + mutex_destroy(&wcd937x->micb_lock); +} + +static const struct component_master_ops wcd937x_comp_ops = { + .bind = wcd937x_bind, + .unbind = wcd937x_unbind, +}; + +static int wcd937x_add_slave_components(struct wcd937x_priv *wcd937x, + struct device *dev, + struct component_match **matchptr) +{ + struct device_node *np = dev->of_node; + + wcd937x->rxnode = of_parse_phandle(np, "qcom,rx-device", 0); + if (!wcd937x->rxnode) { + dev_err(dev, "Couldn't parse phandle to qcom,rx-device!\n"); + return -ENODEV; + } + of_node_get(wcd937x->rxnode); + component_match_add_release(dev, matchptr, component_release_of, + component_compare_of, wcd937x->rxnode); + + wcd937x->txnode = of_parse_phandle(np, "qcom,tx-device", 0); + if (!wcd937x->txnode) { + dev_err(dev, "Couldn't parse phandle to qcom,tx-device\n"); + return -ENODEV; + } + of_node_get(wcd937x->txnode); + component_match_add_release(dev, matchptr, component_release_of, + component_compare_of, wcd937x->txnode); + + return 0; +} + +static int wcd937x_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + struct device *dev = &pdev->dev; + struct wcd937x_priv *wcd937x; + struct wcd_mbhc_config *cfg; + int ret; + + wcd937x = devm_kzalloc(dev, sizeof(*wcd937x), GFP_KERNEL); + if (!wcd937x) + return -ENOMEM; + + dev_set_drvdata(dev, wcd937x); + mutex_init(&wcd937x->micb_lock); + + wcd937x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(wcd937x->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(wcd937x->reset_gpio), + "failed to reset wcd gpio\n"); + + wcd937x->us_euro_gpio = devm_gpiod_get_optional(dev, "us-euro", GPIOD_OUT_LOW); + if (IS_ERR(wcd937x->us_euro_gpio)) + return dev_err_probe(dev, PTR_ERR(wcd937x->us_euro_gpio), + "us-euro swap Control GPIO not found\n"); + + cfg = &wcd937x->mbhc_cfg; + cfg->swap_gnd_mic = wcd937x_swap_gnd_mic; + + wcd937x->supplies[0].supply = "vdd-rxtx"; + wcd937x->supplies[1].supply = "vdd-px"; + wcd937x->supplies[2].supply = "vdd-mic-bias"; + + ret = devm_regulator_bulk_get(dev, WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + if (ret) + return dev_err_probe(dev, ret, "Failed to get supplies\n"); + + ret = regulator_bulk_enable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable supplies\n"); + + /* Get the buck separately, as it needs special handling */ + wcd937x->buck_supply = devm_regulator_get(dev, "vdd-buck"); + if (IS_ERR(wcd937x->buck_supply)) + return dev_err_probe(dev, PTR_ERR(wcd937x->buck_supply), + "Failed to get buck supply\n"); + + ret = regulator_enable(wcd937x->buck_supply); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable buck supply\n"); + + wcd937x_dt_parse_micbias_info(dev, wcd937x); + + cfg->mbhc_micbias = MIC_BIAS_2; + cfg->anc_micbias = MIC_BIAS_2; + cfg->v_hs_max = WCD_MBHC_HS_V_MAX; + cfg->num_btn = WCD937X_MBHC_MAX_BUTTONS; + cfg->micb_mv = wcd937x->micb2_mv; + cfg->linein_th = 5000; + cfg->hs_thr = 1700; + cfg->hph_thr = 50; + + wcd_dt_parse_mbhc_data(dev, &wcd937x->mbhc_cfg); + + ret = wcd937x_add_slave_components(wcd937x, dev, &match); + if (ret) + return ret; + + wcd937x_reset(wcd937x); + + ret = component_master_add_with_match(dev, &wcd937x_comp_ops, match); + if (ret) + return ret; + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + return ret; +} + +static void wcd937x_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct wcd937x_priv *wcd937x = dev_get_drvdata(dev); + + component_master_del(&pdev->dev, &wcd937x_comp_ops); + + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_dont_use_autosuspend(dev); + + regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); +} + +#if defined(CONFIG_OF) +static const struct of_device_id wcd937x_of_match[] = { + { .compatible = "qcom,wcd9370-codec" }, + { .compatible = "qcom,wcd9375-codec" }, + { } +}; +MODULE_DEVICE_TABLE(of, wcd937x_of_match); +#endif + +static struct platform_driver wcd937x_codec_driver = { + .probe = wcd937x_probe, + .remove_new = wcd937x_remove, + .driver = { + .name = "wcd937x_codec", + .of_match_table = of_match_ptr(wcd937x_of_match), + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(wcd937x_codec_driver); +MODULE_DESCRIPTION("WCD937X Codec driver"); +MODULE_LICENSE("GPL"); From 82be8c62a38c6a44e64ecb29d7a9b5cb35c6cad4 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 24 May 2024 09:25:32 +0530 Subject: [PATCH 077/349] ASoC: codecs: wcd937x: add basic controls This patch adds basic controls found in WCD9370/WCD9375 codec. Signed-off-by: Prasad Kumpatla Co-developed-by: Mohammad Rafi Shaik Signed-off-by: Mohammad Rafi Shaik Link: https://lore.kernel.org/r/20240524035535.3119208-5-quic_mohs@quicinc.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 201 +++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 4470ee0ecae6..293a84a53918 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -120,6 +120,10 @@ struct wcd937x_priv { atomic_t ana_clk_count; }; +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); + struct wcd937x_mbhc_zdet_param { u16 ldo_ctl; u16 noff; @@ -476,6 +480,157 @@ static int wcd937x_connect_port(struct wcd937x_sdw_priv *wcd, u8 port_idx, u8 ch return 0; } +static int wcd937x_rx_hph_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd937x->hph_mode; + return 0; +} + +static int wcd937x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + u32 mode_val; + + mode_val = ucontrol->value.enumerated.item[0]; + + if (!mode_val) + mode_val = CLS_AB; + + if (mode_val == wcd937x->hph_mode) + return 0; + + switch (mode_val) { + case CLS_H_NORMAL: + case CLS_H_HIFI: + case CLS_H_LP: + case CLS_AB: + case CLS_H_LOHIFI: + case CLS_H_ULP: + case CLS_AB_LP: + case CLS_AB_HIFI: + wcd937x->hph_mode = mode_val; + return 1; + } + + dev_dbg(component->dev, "%s: Invalid HPH Mode\n", __func__); + return -EINVAL; +} + +static int wcd937x_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc; + bool hphr; + + mc = (struct soc_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + + ucontrol->value.integer.value[0] = hphr ? wcd937x->comp2_enable : + wcd937x->comp1_enable; + return 0; +} + +static int wcd937x_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[AIF1_PB]; + int value = ucontrol->value.integer.value[0]; + struct soc_mixer_control *mc; + int portidx; + bool hphr; + + mc = (struct soc_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + + if (hphr) { + if (value == wcd937x->comp2_enable) + return 0; + + wcd937x->comp2_enable = value; + } else { + if (value == wcd937x->comp1_enable) + return 0; + + wcd937x->comp1_enable = value; + } + + portidx = wcd->ch_info[mc->reg].port_num; + + if (value) + wcd937x_connect_port(wcd, portidx, mc->reg, true); + else + wcd937x_connect_port(wcd, portidx, mc->reg, false); + + return 1; +} + +static int wcd937x_get_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(comp); + struct wcd937x_sdw_priv *wcd; + int dai_id = mixer->shift; + int ch_idx = mixer->reg; + int portidx; + + wcd = wcd937x->sdw_priv[dai_id]; + portidx = wcd->ch_info[ch_idx].port_num; + + ucontrol->value.integer.value[0] = wcd->port_enable[portidx]; + + return 0; +} + +static int wcd937x_set_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(comp); + struct wcd937x_sdw_priv *wcd; + int dai_id = mixer->shift; + int ch_idx = mixer->reg; + int portidx; + bool enable; + + wcd = wcd937x->sdw_priv[dai_id]; + + portidx = wcd->ch_info[ch_idx].port_num; + + enable = ucontrol->value.integer.value[0]; + + if (enable == wcd->port_enable[portidx]) { + wcd937x_connect_port(wcd, portidx, ch_idx, enable); + return 0; + } + + wcd->port_enable[portidx] = enable; + wcd937x_connect_port(wcd, portidx, ch_idx, enable); + + return 1; +} + +static const char * const rx_hph_mode_mux_text[] = { + "CLS_H_NORMAL", "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", + "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_AB_LP", "CLS_AB_HIFI", +}; + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), rx_hph_mode_mux_text); + /* MBHC related */ static void wcd937x_mbhc_clk_setup(struct snd_soc_component *component, bool enable) @@ -1150,6 +1305,50 @@ static void wcd937x_mbhc_deinit(struct snd_soc_component *component) /* END MBHC */ +static const struct snd_kcontrol_new wcd937x_snd_controls[] = { + SOC_SINGLE_TLV("EAR_PA Volume", WCD937X_ANA_EAR_COMPANDER_CTL, + 2, 0x10, 0, ear_pa_gain), + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd937x_rx_hph_mode_get, wcd937x_rx_hph_mode_put), + + SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0, + wcd937x_get_compander, wcd937x_set_compander), + SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0, + wcd937x_get_compander, wcd937x_set_compander), + + SOC_SINGLE_TLV("HPHL Volume", WCD937X_HPH_L_EN, 0, 20, 1, line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD937X_HPH_R_EN, 0, 20, 1, line_gain), + SOC_SINGLE_TLV("ADC1 Volume", WCD937X_ANA_TX_CH1, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD937X_ANA_TX_CH2, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD937X_ANA_TX_CH3, 0, 20, 0, analog_gain), + + SOC_SINGLE_EXT("HPHL Switch", WCD937X_HPH_L, 0, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("HPHR Switch", WCD937X_HPH_R, 0, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + + SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("ADC3 Switch", WCD937X_ADC3, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("DMIC0 Switch", WCD937X_DMIC0, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("DMIC1 Switch", WCD937X_DMIC1, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("MBHC Switch", WCD937X_MBHC, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("DMIC2 Switch", WCD937X_DMIC2, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("DMIC3 Switch", WCD937X_DMIC3, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("DMIC4 Switch", WCD937X_DMIC4, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("DMIC5 Switch", WCD937X_DMIC5, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), +}; + static int wcd937x_set_micbias_data(struct wcd937x_priv *wcd937x) { int vout_ctl[3]; @@ -1316,6 +1515,8 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd937x = { .name = "wcd937x_codec", .probe = wcd937x_soc_codec_probe, .remove = wcd937x_soc_codec_remove, + .controls = wcd937x_snd_controls, + .num_controls = ARRAY_SIZE(wcd937x_snd_controls), .set_jack = wcd937x_codec_set_jack, .endianness = 1, }; From 57fe69db7a015e828ec69d819707c5b8eac6d052 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 24 May 2024 09:25:33 +0530 Subject: [PATCH 078/349] ASoC: codecs: wcd937x: add playback dapm widgets This patch adds required dapm widgets for playback. Signed-off-by: Prasad Kumpatla Co-developed-by: Mohammad Rafi Shaik Signed-off-by: Mohammad Rafi Shaik Link: https://lore.kernel.org/r/20240524035535.3119208-6-quic_mohs@quicinc.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 667 +++++++++++++++++++++++++++++++++++++ 1 file changed, 667 insertions(+) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 293a84a53918..3b0e4bd4eb4f 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -342,6 +342,569 @@ static int wcd937x_rx_clk_disable(struct snd_soc_component *component) return 0; } +static int wcd937x_codec_hphl_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(0), BIT(0)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, + BIT(2), BIT(2)); + snd_soc_component_update_bits(component, + WCD937X_HPH_RDAC_CLK_CTL1, + BIT(7), 0x00); + set_bit(HPH_COMP_DELAY, &wcd937x->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0f, BIT(1)); + else if (hph_mode == CLS_H_LOHIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0f, 0x06); + + if (wcd937x->comp1_enable) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + BIT(1), BIT(1)); + snd_soc_component_update_bits(component, + WCD937X_HPH_L_EN, + BIT(5), 0x00); + + if (wcd937x->comp2_enable) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + BIT(0), BIT(0)); + snd_soc_component_update_bits(component, + WCD937X_HPH_R_EN, BIT(5), 0x00); + } + + if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) { + usleep_range(5000, 5110); + clear_bit(HPH_COMP_DELAY, &wcd937x->status_mask); + } + } else { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + BIT(1), 0x00); + snd_soc_component_update_bits(component, + WCD937X_HPH_L_EN, + BIT(5), BIT(5)); + } + + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_HPH_TIMER1, + BIT(1), 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0f, BIT(0)); + break; + } + + return 0; +} + +static int wcd937x_codec_hphr_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(1), BIT(1)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, BIT(3), BIT(3)); + snd_soc_component_update_bits(component, + WCD937X_HPH_RDAC_CLK_CTL1, BIT(7), 0x00); + set_bit(HPH_COMP_DELAY, &wcd937x->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, + 0x0f, BIT(1)); + else if (hph_mode == CLS_H_LOHIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, + 0x0f, 0x06); + if (wcd937x->comp2_enable) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + BIT(0), BIT(0)); + snd_soc_component_update_bits(component, + WCD937X_HPH_R_EN, BIT(5), 0x00); + if (wcd937x->comp1_enable) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + BIT(1), BIT(1)); + snd_soc_component_update_bits(component, + WCD937X_HPH_L_EN, + BIT(5), 0x00); + } + + if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) { + usleep_range(5000, 5110); + clear_bit(HPH_COMP_DELAY, &wcd937x->status_mask); + } + } else { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + BIT(0), 0x00); + snd_soc_component_update_bits(component, + WCD937X_HPH_R_EN, + BIT(5), BIT(5)); + } + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_HPH_TIMER1, + BIT(1), 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, + 0x0f, BIT(0)); + break; + } + + return 0; +} + +static int wcd937x_codec_ear_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, + BIT(2), BIT(2)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(0), BIT(0)); + + if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0f, BIT(1)); + else if (hph_mode == CLS_H_LOHIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0f, 0x06); + if (wcd937x->comp1_enable) + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + BIT(1), BIT(1)); + usleep_range(5000, 5010); + + snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN, BIT(2), 0x00); + wcd_clsh_ctrl_set_state(wcd937x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, + hph_mode); + + break; + case SND_SOC_DAPM_POST_PMD: + if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_HIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0f, BIT(0)); + if (wcd937x->comp1_enable) + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + BIT(1), 0x00); + break; + } + + return 0; +} + +static int wcd937x_codec_aux_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(2), BIT(2)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(2), BIT(2)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_AUX_GAIN_CTL, + BIT(0), BIT(0)); + wcd_clsh_ctrl_set_state(wcd937x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_AUX, + hph_mode); + + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(2), 0x00); + break; + } + + return 0; +} + +static int wcd937x_codec_enable_hphr_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_clsh_ctrl_set_state(wcd937x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + hph_mode); + snd_soc_component_update_bits(component, WCD937X_ANA_HPH, + BIT(4), BIT(4)); + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd937x->status_mask); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL1, + 0x07, 0x03); + break; + case SND_SOC_DAPM_POST_PMU: + if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) { + if (wcd937x->comp2_enable) + usleep_range(7000, 7100); + else + usleep_range(20000, 20100); + clear_bit(HPH_PA_DELAY, &wcd937x->status_mask); + } + + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_HPH_TIMER1, + BIT(1), BIT(1)); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + BIT(1), BIT(1)); + enable_irq(wcd937x->hphr_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd937x->hphr_pdm_wd_int); + set_bit(HPH_PA_DELAY, &wcd937x->status_mask); + wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_PRE_HPHR_PA_OFF); + break; + case SND_SOC_DAPM_POST_PMD: + if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) { + if (wcd937x->comp2_enable) + usleep_range(7000, 7100); + else + usleep_range(20000, 20100); + clear_bit(HPH_PA_DELAY, &wcd937x->status_mask); + } + + wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_POST_HPHR_PA_OFF); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL1, 0x07, 0x00); + snd_soc_component_update_bits(component, WCD937X_ANA_HPH, + BIT(4), 0x00); + wcd_clsh_ctrl_set_state(wcd937x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, + hph_mode); + break; + } + + return 0; +} + +static int wcd937x_codec_enable_hphl_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_clsh_ctrl_set_state(wcd937x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + hph_mode); + snd_soc_component_update_bits(component, WCD937X_ANA_HPH, + BIT(5), BIT(5)); + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd937x->status_mask); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x03); + break; + case SND_SOC_DAPM_POST_PMU: + if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) { + if (!wcd937x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd937x->status_mask); + } + + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_HPH_TIMER1, + BIT(1), BIT(1)); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + BIT(1), BIT(1)); + enable_irq(wcd937x->hphl_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd937x->hphl_pdm_wd_int); + set_bit(HPH_PA_DELAY, &wcd937x->status_mask); + wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_PRE_HPHL_PA_OFF); + break; + case SND_SOC_DAPM_POST_PMD: + if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) { + if (!wcd937x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd937x->status_mask); + } + + wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_POST_HPHL_PA_OFF); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x00); + snd_soc_component_update_bits(component, + WCD937X_ANA_HPH, BIT(5), 0x00); + wcd_clsh_ctrl_set_state(wcd937x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + hph_mode); + break; + } + + return 0; +} + +static int wcd937x_codec_enable_aux_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL2, + BIT(0), BIT(0)); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1010); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + BIT(1), BIT(1)); + enable_irq(wcd937x->aux_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd937x->aux_pdm_wd_int); + break; + case SND_SOC_DAPM_POST_PMD: + usleep_range(2000, 2010); + wcd_clsh_ctrl_set_state(wcd937x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_AUX, + hph_mode); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL2, + BIT(0), 0x00); + break; + } + + return 0; +} + +static int wcd937x_codec_enable_ear_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable watchdog interrupt for HPHL or AUX depending on mux value */ + wcd937x->ear_rx_path = snd_soc_component_read(component, + WCD937X_DIGITAL_CDC_EAR_PATH_CTL); + + if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX) + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL2, + BIT(0), BIT(0)); + else + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL0, + 0x07, 0x03); + if (!wcd937x->comp1_enable) + snd_soc_component_update_bits(component, + WCD937X_ANA_EAR_COMPANDER_CTL, + BIT(7), BIT(7)); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(6000, 6010); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + BIT(1), BIT(1)); + + if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX) + enable_irq(wcd937x->aux_pdm_wd_int); + else + enable_irq(wcd937x->hphl_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX) + disable_irq_nosync(wcd937x->aux_pdm_wd_int); + else + disable_irq_nosync(wcd937x->hphl_pdm_wd_int); + break; + case SND_SOC_DAPM_POST_PMD: + if (!wcd937x->comp1_enable) + snd_soc_component_update_bits(component, + WCD937X_ANA_EAR_COMPANDER_CTL, + BIT(7), 0x00); + usleep_range(7000, 7010); + wcd_clsh_ctrl_set_state(wcd937x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, + hph_mode); + snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN, + BIT(2), BIT(2)); + + if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX) + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL2, + BIT(0), 0x00); + else + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL0, + 0x07, 0x00); + break; + } + + return 0; +} + +static int wcd937x_enable_rx1(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + if (event == SND_SOC_DAPM_POST_PMD) { + wcd937x_rx_clk_disable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(0), 0x00); + } + + return 0; +} + +static int wcd937x_enable_rx2(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + if (event == SND_SOC_DAPM_POST_PMD) { + wcd937x_rx_clk_disable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(1), 0x00); + } + + return 0; +} + +static int wcd937x_enable_rx3(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + if (event == SND_SOC_DAPM_POST_PMD) { + usleep_range(6000, 6010); + wcd937x_rx_clk_disable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(2), 0x00); + } + + return 0; +} + +static int wcd937x_codec_enable_vdd_buck(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (test_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask)) { + dev_err(component->dev, "buck already in enabled state\n"); + clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); + return 0; + } + ret = regulator_enable(wcd937x->buck_supply); + if (ret) { + dev_err(component->dev, "VDD_BUCK is not enabled\n"); + return ret; + } + clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); + usleep_range(200, 250); + break; + case SND_SOC_DAPM_POST_PMD: + set_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); + break; + } + + return 0; +} + static int wcd937x_get_micb_vout_ctl_val(u32 micb_mv) { if (micb_mv < 1000 || micb_mv > 2850) { @@ -1349,6 +1912,108 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = { wcd937x_get_swr_port, wcd937x_set_swr_port), }; +static const struct snd_kcontrol_new ear_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new aux_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new hphl_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new hphr_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const char * const rdac3_mux_text[] = { + "RX1", "RX3" +}; + +static const struct soc_enum rdac3_enum = + SOC_ENUM_SINGLE(WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0, + ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text); + +static const struct snd_kcontrol_new rx_rdac3_mux = SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum); + +static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { + /* Input widgets */ + SND_SOC_DAPM_INPUT("IN1_HPHL"), + SND_SOC_DAPM_INPUT("IN2_HPHR"), + SND_SOC_DAPM_INPUT("IN3_AUX"), + + SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_vdd_buck, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0), + + /* RX widgets */ + SND_SOC_DAPM_PGA_E("EAR PGA", WCD937X_ANA_EAR, 7, 0, NULL, 0, + wcd937x_codec_enable_ear_pa, + 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("AUX PGA", WCD937X_AUX_AUXPA, 7, 0, NULL, 0, + wcd937x_codec_enable_aux_pa, + 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("HPHL PGA", WCD937X_ANA_HPH, 7, 0, NULL, 0, + wcd937x_codec_enable_hphl_pa, + 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("HPHR PGA", WCD937X_ANA_HPH, 6, 0, NULL, 0, + wcd937x_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC4", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_aux_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux), + + SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd937x_enable_rx1, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd937x_enable_rx2, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd937x_enable_rx3, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + /* RX mixer widgets*/ + SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0, + ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)), + SND_SOC_DAPM_MIXER("AUX_RDAC", SND_SOC_NOPM, 0, 0, + aux_rdac_switch, ARRAY_SIZE(aux_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0, + hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0, + hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)), + + /* RX output widgets */ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("AUX"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), +}; + static int wcd937x_set_micbias_data(struct wcd937x_priv *wcd937x) { int vout_ctl[3]; @@ -1517,6 +2182,8 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd937x = { .remove = wcd937x_soc_codec_remove, .controls = wcd937x_snd_controls, .num_controls = ARRAY_SIZE(wcd937x_snd_controls), + .dapm_widgets = wcd937x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd937x_dapm_widgets), .set_jack = wcd937x_codec_set_jack, .endianness = 1, }; From 8ee78493be89c42d016f941a9b00c203ec08daab Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 24 May 2024 09:25:34 +0530 Subject: [PATCH 079/349] ASoC: codecs: wcd937x: add capture dapm widgets This patch adds required dapm widgets for capture path. Signed-off-by: Prasad Kumpatla Co-developed-by: Mohammad Rafi Shaik Signed-off-by: Mohammad Rafi Shaik Link: https://lore.kernel.org/r/20240524035535.3119208-7-quic_mohs@quicinc.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 404 +++++++++++++++++++++++++++++++++++++ 1 file changed, 404 insertions(+) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 3b0e4bd4eb4f..f8b57f47ad55 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -915,6 +915,145 @@ static int wcd937x_get_micb_vout_ctl_val(u32 micb_mv) return (micb_mv - 1000) / 50; } +static int wcd937x_tx_swr_ctrl(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + bool use_amic3 = snd_soc_component_read(component, WCD937X_TX_NEW_TX_CH2_SEL) & BIT(7); + + /* Enable BCS for Headset mic */ + if (event == SND_SOC_DAPM_PRE_PMU && strnstr(w->name, "ADC", sizeof("ADC"))) + if (w->shift == 1 && !use_amic3) + set_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask); + + return 0; +} + +static int wcd937x_codec_enable_adc(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + atomic_inc(&wcd937x->ana_clk_count); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(7), BIT(7)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(3), BIT(3)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(4), BIT(4)); + break; + case SND_SOC_DAPM_POST_PMD: + if (w->shift == 1 && test_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask)) + clear_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask); + + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(3), 0x00); + break; + } + + return 0; +} + +static int wcd937x_enable_req(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_REQ_CTL, BIT(1), BIT(1)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_REQ_CTL, BIT(0), 0x00); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH2, BIT(6), BIT(6)); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH3_HPF, BIT(6), BIT(6)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x70, 0x70); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH1, BIT(7), BIT(7)); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH2, BIT(6), 0x00); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH2, BIT(7), BIT(7)); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH3, BIT(7), BIT(7)); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH1, BIT(7), 0x00); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH2, BIT(7), 0x00); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH3, BIT(7), 0x00); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(4), 0x00); + + atomic_dec(&wcd937x->ana_clk_count); + if (atomic_read(&wcd937x->ana_clk_count) <= 0) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(4), 0x00); + atomic_set(&wcd937x->ana_clk_count, 0); + } + + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(7), 0x00); + break; + } + + return 0; +} + +static int wcd937x_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + u16 dmic_clk_reg; + + switch (w->shift) { + case 0: + case 1: + dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC1_CTL; + break; + case 2: + case 3: + dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC2_CTL; + break; + case 4: + case 5: + dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC3_CTL; + break; + default: + dev_err(component->dev, "Invalid DMIC Selection\n"); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(7), BIT(7)); + snd_soc_component_update_bits(component, + dmic_clk_reg, 0x07, BIT(1)); + snd_soc_component_update_bits(component, + dmic_clk_reg, BIT(3), BIT(3)); + snd_soc_component_update_bits(component, + dmic_clk_reg, 0x70, BIT(5)); + break; + } + + return 0; +} + static int wcd937x_micbias_control(struct snd_soc_component *component, int micb_num, int req, bool is_dapm) { @@ -1026,6 +1165,82 @@ static int wcd937x_micbias_control(struct snd_soc_component *component, return 0; } +static int __wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + int micb_num; + + if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_micbias_control(component, micb_num, + MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd937x_micbias_control(component, micb_num, + MICB_DISABLE, true); + break; + } + + return 0; +} + +static int wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + return __wcd937x_codec_enable_micbias(w, event); +} + +static int __wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + int micb_num; + + if (strnstr(w->name, "VA MIC BIAS1", sizeof("VA MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "VA MIC BIAS2", sizeof("VA MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "VA MIC BIAS3", sizeof("VA MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_micbias_control(component, micb_num, MICB_PULLUP_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd937x_micbias_control(component, micb_num, MICB_PULLUP_DISABLE, true); + break; + } + + return 0; +} + +static int wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + return __wcd937x_codec_enable_micbias_pullup(w, event); +} + static int wcd937x_connect_port(struct wcd937x_sdw_priv *wcd, u8 port_idx, u8 ch_id, bool enable) { struct sdw_port_config *port_config = &wcd->port_config[port_idx - 1]; @@ -1912,6 +2127,42 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = { wcd937x_get_swr_port, wcd937x_set_swr_port), }; +static const struct snd_kcontrol_new adc1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic5_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic6_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + static const struct snd_kcontrol_new ear_rdac_switch[] = { SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) }; @@ -1928,22 +2179,76 @@ static const struct snd_kcontrol_new hphr_rdac_switch[] = { SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) }; +static const char * const adc2_mux_text[] = { + "INP2", "INP3" +}; + static const char * const rdac3_mux_text[] = { "RX1", "RX3" }; +static const struct soc_enum adc2_enum = + SOC_ENUM_SINGLE(WCD937X_TX_NEW_TX_CH2_SEL, 7, + ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + static const struct soc_enum rdac3_enum = SOC_ENUM_SINGLE(WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0, ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text); +static const struct snd_kcontrol_new tx_adc2_mux = SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum); + static const struct snd_kcontrol_new rx_rdac3_mux = SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum); static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { /* Input widgets */ + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), SND_SOC_DAPM_INPUT("IN1_HPHL"), SND_SOC_DAPM_INPUT("IN2_HPHR"), SND_SOC_DAPM_INPUT("IN3_AUX"), + /* TX widgets */ + SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0, + wcd937x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd937x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd937x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux), + + /* TX mixers */ + SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0, + adc1_switch, ARRAY_SIZE(adc1_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 1, 0, + adc2_switch, ARRAY_SIZE(adc2_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + /* MIC_BIAS widgets */ + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, wcd937x_codec_enable_vdd_buck, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -2007,11 +2312,101 @@ static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0, hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)), + /* TX output widgets */ + SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"), + SND_SOC_DAPM_OUTPUT("WCD_TX_OUTPUT"), + /* RX output widgets */ SND_SOC_DAPM_OUTPUT("EAR"), SND_SOC_DAPM_OUTPUT("AUX"), SND_SOC_DAPM_OUTPUT("HPHL"), SND_SOC_DAPM_OUTPUT("HPHR"), + + /* MIC_BIAS pull up widgets */ + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_widget wcd9375_dapm_widgets[] = { + /* Input widgets */ + SND_SOC_DAPM_INPUT("AMIC4"), + + /* TX widgets */ + SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0, + wcd937x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd937x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* TX mixer widgets */ + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0, + 0, dmic1_switch, ARRAY_SIZE(dmic1_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 1, + 0, dmic2_switch, ARRAY_SIZE(dmic2_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 2, + 0, dmic3_switch, ARRAY_SIZE(dmic3_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 3, + 0, dmic4_switch, ARRAY_SIZE(dmic4_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 4, + 0, dmic5_switch, ARRAY_SIZE(dmic5_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 5, + 0, dmic6_switch, ARRAY_SIZE(dmic6_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 2, 0, adc3_switch, + ARRAY_SIZE(adc3_switch), wcd937x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* Output widgets */ + SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"), }; static int wcd937x_set_micbias_data(struct wcd937x_priv *wcd937x) @@ -2143,6 +2538,15 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component) disable_irq_nosync(wcd937x->hphl_pdm_wd_int); disable_irq_nosync(wcd937x->aux_pdm_wd_int); + if (wcd937x->chipid == CHIPID_WCD9375) { + ret = snd_soc_dapm_new_controls(dapm, wcd9375_dapm_widgets, + ARRAY_SIZE(wcd9375_dapm_widgets)); + if (ret < 0) { + dev_err(component->dev, "Failed to add snd_ctls\n"); + return ret; + } + } + ret = wcd937x_mbhc_init(component); if (ret) dev_err(component->dev, "mbhc initialization failed\n"); From 313e978df7fc38b9e949ac5933d0d9d56d5e8a9c Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 24 May 2024 09:25:35 +0530 Subject: [PATCH 080/349] ASoC: codecs: wcd937x: add audio routing and Kconfig This patch adds audio routing for both playback and capture and Makefile and Kconfigs changes for wcd937x. Signed-off-by: Prasad Kumpatla Co-developed-by: Mohammad Rafi Shaik Signed-off-by: Mohammad Rafi Shaik Link: https://lore.kernel.org/r/20240524035535.3119208-8-quic_mohs@quicinc.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 20 ++++++++++ sound/soc/codecs/Makefile | 7 ++++ sound/soc/codecs/wcd937x.c | 80 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3621781d63c4..7b99556f24d3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -279,6 +279,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_UDA1380 imply SND_SOC_WCD9335 imply SND_SOC_WCD934X + imply SND_SOC_WCD937X_SDW imply SND_SOC_WCD938X_SDW imply SND_SOC_WCD939X_SDW imply SND_SOC_LPASS_MACRO_COMMON @@ -2111,6 +2112,25 @@ config SND_SOC_WCD934X The WCD9340/9341 is a audio codec IC Integrated in Qualcomm SoCs like SDM845. +config SND_SOC_WCD937X + depends on SND_SOC_WCD937X_SDW + tristate + depends on SOUNDWIRE || !SOUNDWIRE + select SND_SOC_WCD_CLASSH + +config SND_SOC_WCD937X_SDW + tristate "WCD9370/WCD9375 Codec - SDW" + select SND_SOC_WCD937X + select SND_SOC_WCD_MBHC + select REGMAP_IRQ + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + help + The WCD9370/9375 is an audio codec IC used with SoCs + like SC7280 or QCM6490 chipsets, and it connected + via soundwire. + To compile this codec driver say Y or m. + config SND_SOC_WCD938X depends on SND_SOC_WCD938X_SDW tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d343d23c8f0f..ca69f35cc0f7 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -318,6 +318,8 @@ snd-soc-wcd-classh-y := wcd-clsh-v2.o snd-soc-wcd-mbhc-y := wcd-mbhc-v2.o snd-soc-wcd9335-y := wcd9335.o snd-soc-wcd934x-y := wcd934x.o +snd-soc-wcd937x-objs := wcd937x.o +snd-soc-wcd937x-sdw-objs := wcd937x-sdw.o snd-soc-wcd938x-y := wcd938x.o snd-soc-wcd938x-sdw-y := wcd938x-sdw.o snd-soc-wcd939x-y := wcd939x.o @@ -714,6 +716,11 @@ obj-$(CONFIG_SND_SOC_WCD_CLASSH) += snd-soc-wcd-classh.o obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o obj-$(CONFIG_SND_SOC_WCD934X) += snd-soc-wcd934x.o +obj-$(CONFIG_SND_SOC_WCD937X) += snd-soc-wcd937x.o +ifdef CONFIG_SND_SOC_WCD937X_SDW +# avoid link failure by forcing sdw code built-in when needed +obj-$(CONFIG_SND_SOC_WCD937X) += snd-soc-wcd937x-sdw.o +endif obj-$(CONFIG_SND_SOC_WCD938X) += snd-soc-wcd938x.o ifdef CONFIG_SND_SOC_WCD938X_SDW # avoid link failure by forcing sdw code built-in when needed diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index f8b57f47ad55..ef649ed77fb2 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -2409,6 +2409,77 @@ static const struct snd_soc_dapm_widget wcd9375_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"), }; +static const struct snd_soc_dapm_route wcd937x_audio_map[] = { + { "ADC1_OUTPUT", NULL, "ADC1_MIXER" }, + { "ADC1_MIXER", "Switch", "ADC1 REQ" }, + { "ADC1 REQ", NULL, "ADC1" }, + { "ADC1", NULL, "AMIC1" }, + + { "ADC2_OUTPUT", NULL, "ADC2_MIXER" }, + { "ADC2_MIXER", "Switch", "ADC2 REQ" }, + { "ADC2 REQ", NULL, "ADC2" }, + { "ADC2", NULL, "ADC2 MUX" }, + { "ADC2 MUX", "INP3", "AMIC3" }, + { "ADC2 MUX", "INP2", "AMIC2" }, + + { "IN1_HPHL", NULL, "VDD_BUCK" }, + { "IN1_HPHL", NULL, "CLS_H_PORT" }, + { "RX1", NULL, "IN1_HPHL" }, + { "RDAC1", NULL, "RX1" }, + { "HPHL_RDAC", "Switch", "RDAC1" }, + { "HPHL PGA", NULL, "HPHL_RDAC" }, + { "HPHL", NULL, "HPHL PGA" }, + + { "IN2_HPHR", NULL, "VDD_BUCK" }, + { "IN2_HPHR", NULL, "CLS_H_PORT" }, + { "RX2", NULL, "IN2_HPHR" }, + { "RDAC2", NULL, "RX2" }, + { "HPHR_RDAC", "Switch", "RDAC2" }, + { "HPHR PGA", NULL, "HPHR_RDAC" }, + { "HPHR", NULL, "HPHR PGA" }, + + { "IN3_AUX", NULL, "VDD_BUCK" }, + { "IN3_AUX", NULL, "CLS_H_PORT" }, + { "RX3", NULL, "IN3_AUX" }, + { "RDAC4", NULL, "RX3" }, + { "AUX_RDAC", "Switch", "RDAC4" }, + { "AUX PGA", NULL, "AUX_RDAC" }, + { "AUX", NULL, "AUX PGA" }, + + { "RDAC3_MUX", "RX3", "RX3" }, + { "RDAC3_MUX", "RX1", "RX1" }, + { "RDAC3", NULL, "RDAC3_MUX" }, + { "EAR_RDAC", "Switch", "RDAC3" }, + { "EAR PGA", NULL, "EAR_RDAC" }, + { "EAR", NULL, "EAR PGA" }, +}; + +static const struct snd_soc_dapm_route wcd9375_audio_map[] = { + { "ADC3_OUTPUT", NULL, "ADC3_MIXER" }, + { "ADC3_OUTPUT", NULL, "ADC3_MIXER" }, + { "ADC3_MIXER", "Switch", "ADC3 REQ" }, + { "ADC3 REQ", NULL, "ADC3" }, + { "ADC3", NULL, "AMIC4" }, + + { "DMIC1_OUTPUT", NULL, "DMIC1_MIXER" }, + { "DMIC1_MIXER", "Switch", "DMIC1" }, + + { "DMIC2_OUTPUT", NULL, "DMIC2_MIXER" }, + { "DMIC2_MIXER", "Switch", "DMIC2" }, + + { "DMIC3_OUTPUT", NULL, "DMIC3_MIXER" }, + { "DMIC3_MIXER", "Switch", "DMIC3" }, + + { "DMIC4_OUTPUT", NULL, "DMIC4_MIXER" }, + { "DMIC4_MIXER", "Switch", "DMIC4" }, + + { "DMIC5_OUTPUT", NULL, "DMIC5_MIXER" }, + { "DMIC5_MIXER", "Switch", "DMIC5" }, + + { "DMIC6_OUTPUT", NULL, "DMIC6_MIXER" }, + { "DMIC6_MIXER", "Switch", "DMIC6" }, +}; + static int wcd937x_set_micbias_data(struct wcd937x_priv *wcd937x) { int vout_ctl[3]; @@ -2545,6 +2616,13 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component) dev_err(component->dev, "Failed to add snd_ctls\n"); return ret; } + + ret = snd_soc_dapm_add_routes(dapm, wcd9375_audio_map, + ARRAY_SIZE(wcd9375_audio_map)); + if (ret < 0) { + dev_err(component->dev, "Failed to add routes\n"); + return ret; + } } ret = wcd937x_mbhc_init(component); @@ -2588,6 +2666,8 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd937x = { .num_controls = ARRAY_SIZE(wcd937x_snd_controls), .dapm_widgets = wcd937x_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wcd937x_dapm_widgets), + .dapm_routes = wcd937x_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd937x_audio_map), .set_jack = wcd937x_codec_set_jack, .endianness = 1, }; From 0b7e448119428e1dcb854abb5855f66966fb82dc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 28 May 2024 14:29:33 -0500 Subject: [PATCH 081/349] ACPI: utils: introduce acpi_get_local_u64_address() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ACPI _ADR is a 64-bit value. We changed the definitions in commit ca6f998cf9a2 ("ACPI: bus: change _ADR representation to 64 bits") but some helpers still assume the value is a 32-bit value. This patch adds a new helper to extract the full 64-bits. The existing 32-bit helper is kept for backwards-compatibility and cases where the _ADR is known to fit in a 32-bit value. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Acked-by: Rafael J. Wysocki Reviewed-by: Takashi Iwai Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240528192936.16180-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- drivers/acpi/utils.c | 16 +++++++++++++--- include/linux/acpi.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 202234ba54bd..ae9384282273 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -277,15 +277,25 @@ acpi_evaluate_integer(acpi_handle handle, EXPORT_SYMBOL(acpi_evaluate_integer); -int acpi_get_local_address(acpi_handle handle, u32 *addr) +int acpi_get_local_u64_address(acpi_handle handle, u64 *addr) { - unsigned long long adr; acpi_status status; - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, addr); if (ACPI_FAILURE(status)) return -ENODATA; + return 0; +} +EXPORT_SYMBOL(acpi_get_local_u64_address); +int acpi_get_local_address(acpi_handle handle, u32 *addr) +{ + u64 adr; + int ret; + + ret = acpi_get_local_u64_address(handle, &adr); + if (ret < 0) + return ret; *addr = (u32)adr; return 0; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 28c3fb2bef0d..65e7177bcb02 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -761,6 +761,7 @@ static inline u64 acpi_arch_get_root_pointer(void) } #endif +int acpi_get_local_u64_address(acpi_handle handle, u64 *addr); int acpi_get_local_address(acpi_handle handle, u32 *addr); const char *acpi_get_subsystem_id(acpi_handle handle); From b6212f9bf489daf9716aed0e8c4dc6a807ce839f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 28 May 2024 14:29:34 -0500 Subject: [PATCH 082/349] soundwire: slave: simplify code with acpi_get_local_u64_address() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now we have a helper so there's no need to open-code. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Acked-by: Vinod Koul Reviewed-by: Takashi Iwai Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240528192936.16180-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- drivers/soundwire/slave.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 9963b92eb505..f1a4df6cfebd 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -97,18 +97,13 @@ static bool find_slave(struct sdw_bus *bus, struct acpi_device *adev, struct sdw_slave_id *id) { - u64 addr; unsigned int link_id; - acpi_status status; + u64 addr; + int ret; - status = acpi_evaluate_integer(adev->handle, - METHOD_NAME__ADR, NULL, &addr); - - if (ACPI_FAILURE(status)) { - dev_err(bus->dev, "_ADR resolution failed: %x\n", - status); + ret = acpi_get_local_u64_address(adev->handle, &addr); + if (ret < 0) return false; - } if (bus->ops->override_adr) addr = bus->ops->override_adr(bus, addr); From 9b7dc68eeba04d20f4a1733e791bc71355423612 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 28 May 2024 14:29:35 -0500 Subject: [PATCH 083/349] ALSA: hda: intel-sdw-acpi: use acpi_get_local_u64_address() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now we have a helper so there's no need to open-code. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Takashi Iwai Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240528192936.16180-4-pierre-louis.bossart@linux.intel.com Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/hda/intel-sdw-acpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c index d7417a40392b..f3b2a610df23 100644 --- a/sound/hda/intel-sdw-acpi.c +++ b/sound/hda/intel-sdw-acpi.c @@ -125,11 +125,11 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, void *cdata, void **return_value) { struct sdw_intel_acpi_info *info = cdata; - acpi_status status; u64 adr; + int ret; - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) + ret = acpi_get_local_u64_address(handle, &adr); + if (ret < 0) return AE_OK; /* keep going */ if (!acpi_fetch_acpi_dev(handle)) { From d52378dda71cd9a0a25f863ffb9ccc4280133a4f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 6 Jun 2024 00:27:24 +0300 Subject: [PATCH 084/349] ASoC: codecs: Remove unused of_gpio.h of_gpio.h is deprecated and subject to remove. The drivers in question don't use it, simply remove the unused header. Reviewed-by: Kuninori Morimoto Reviewed-by: Charles Keepax Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240605221446.2624964-2-andriy.shevchenko@linux.intel.com Acked-by: Heiko Stuebner Signed-off-by: Mark Brown --- sound/soc/codecs/ak4118.c | 1 - sound/soc/codecs/ak4458.c | 1 - sound/soc/codecs/aw88399.c | 2 +- sound/soc/codecs/cs53l30.c | 1 - sound/soc/codecs/max98390.c | 1 - sound/soc/codecs/pcm3168a.c | 1 - sound/soc/codecs/rk817_codec.c | 1 - sound/soc/codecs/tas2552.c | 1 - sound/soc/codecs/tas2764.c | 1 - sound/soc/codecs/tas2770.c | 1 - sound/soc/codecs/tas2780.c | 1 - sound/soc/codecs/tlv320adc3xxx.c | 1 - sound/soc/codecs/tlv320adcx140.c | 1 - sound/soc/codecs/tlv320aic31xx.c | 1 - sound/soc/codecs/ts3a227e.c | 1 - sound/soc/codecs/wsa883x.c | 1 - 16 files changed, 1 insertion(+), 16 deletions(-) diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c index 9a43235e6a11..23e868e4e3fb 100644 --- a/sound/soc/codecs/ak4118.c +++ b/sound/soc/codecs/ak4118.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 73cf482f104f..32cb802ad635 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index 9fcb805bf971..df6d52a1cfef 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include "aw88399.h" diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index c0893146423b..2ee13d885fdc 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index 57fa2db1e148..1bae253618fd 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 9d6431338fb7..3c0e0fdbfc5c 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c index d4da98469f8b..5fea600bc3a4 100644 --- a/sound/soc/codecs/rk817_codec.c +++ b/sound/soc/codecs/rk817_codec.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index a7ed59ec49a6..9e68afc09897 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 1dc719d726ab..5eaddf07aadc 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 67bc1c8b0131..5601fba17c96 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c index a18ccf5fb7ad..6902bfef185b 100644 --- a/sound/soc/codecs/tas2780.c +++ b/sound/soc/codecs/tas2780.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index e100cc9f5c19..eb180df9a72a 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 41342b340680..d594bf166c0e 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 4d7c5a80c6ed..2f94cfda0e33 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index dbf448dd8864..b9eb59e3bfa0 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index a2e86ef7d18f..8abce2160d65 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include From f10d0956bc0460744fa4c085cff41ce862619a2c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 6 Jun 2024 00:27:25 +0300 Subject: [PATCH 085/349] ASoC: fsl: Remove unused of_gpio.h of_gpio.h is deprecated and subject to remove. The drivers in question don't use it, simply remove the unused header. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240605221446.2624964-3-andriy.shevchenko@linux.intel.com Reviewed-by: Kuninori Morimoto Reviewed-by: Charles Keepax Acked-by: Heiko Stuebner Signed-off-by: Mark Brown --- sound/soc/fsl/imx-es8328.c | 1 - sound/soc/fsl/imx-rpmsg.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 5b9648f3b087..3ef92f6dfc6b 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index 0f1ad7ad7d27..ce98d2288193 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -5,9 +5,7 @@ #include #include #include -#include #include -#include #include #include #include From 640557f3de900974d35a46f5a7b0f2161fe2ba35 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 6 Jun 2024 00:27:26 +0300 Subject: [PATCH 086/349] ASoC: rockchip: Remove unused of_gpio.h of_gpio.h is deprecated and subject to remove. The drivers in question don't use it, simply remove the unused header. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240605221446.2624964-4-andriy.shevchenko@linux.intel.com Reviewed-by: Kuninori Morimoto Reviewed-by: Charles Keepax Acked-by: Heiko Stuebner Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 1 - sound/soc/rockchip/rockchip_spdif.c | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index b0c3ef030e06..b378f870b3ad 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 1a24b78e9e02..eb9d5dee196e 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include From e9bf7ed59d2e4a1d071f11ff8d04895377970e42 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 6 Jun 2024 00:27:27 +0300 Subject: [PATCH 087/349] ASoC: codecs: Replace of_gpio.h by proper one of_gpio.h is deprecated and subject to remove. The driver doesn't use it directly, replace it with what is really being used. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240605221446.2624964-5-andriy.shevchenko@linux.intel.com Acked-by: Heiko Stuebner Signed-off-by: Mark Brown --- sound/soc/codecs/aw88395/aw88395.c | 2 +- sound/soc/codecs/aw88399.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c index 3c459a67ad0c..be6ebcb51cca 100644 --- a/sound/soc/codecs/aw88395/aw88395.c +++ b/sound/soc/codecs/aw88395/aw88395.c @@ -8,9 +8,9 @@ // Author: Weidong Wang // +#include #include #include -#include #include #include #include "aw88395.h" diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index df6d52a1cfef..5d8481612eab 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -8,9 +8,9 @@ // #include +#include #include #include -#include #include #include #include "aw88399.h" From 7a31da79c13ef6449c84f6007d81d1c082dd3aaf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 6 Jun 2024 00:27:28 +0300 Subject: [PATCH 088/349] ASoC: generic: Replace of_gpio.h by proper one of_gpio.h is deprecated and subject to remove. The driver doesn't use it directly, replace it with what is really being used. Acked-by: Kuninori Morimoto Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240605221446.2624964-6-andriy.shevchenko@linux.intel.com Reviewed-by: Kuninori Morimoto Reviewed-by: Charles Keepax Acked-by: Heiko Stuebner Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2-custom-sample.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.c b/sound/soc/generic/audio-graph-card2-custom-sample.c index 1b6ccd2de964..8e5a51098490 100644 --- a/sound/soc/generic/audio-graph-card2-custom-sample.c +++ b/sound/soc/generic/audio-graph-card2-custom-sample.c @@ -5,8 +5,9 @@ // Copyright (C) 2020 Renesas Electronics Corp. // Copyright (C) 2020 Kuninori Morimoto // +#include +#include #include -#include #include #include From 7f4c7e43453fe0bcd0d40bcab8567e0dac5f50b8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 6 Jun 2024 00:27:29 +0300 Subject: [PATCH 089/349] ASoC: samsung: Replace of_gpio.h by proper one of_gpio.h is deprecated and subject to remove. The driver doesn't use it directly, replace it with what is really being used. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240605221446.2624964-7-andriy.shevchenko@linux.intel.com Reviewed-by: Kuninori Morimoto Reviewed-by: Charles Keepax Acked-by: Heiko Stuebner Signed-off-by: Mark Brown --- sound/soc/samsung/aries_wm8994.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c index a548ac33dd94..01716df0c842 100644 --- a/sound/soc/samsung/aries_wm8994.c +++ b/sound/soc/samsung/aries_wm8994.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0+ #include +#include #include #include #include #include #include -#include #include #include #include From b97e40905580c4585faa491189214e74101ca2ad Mon Sep 17 00:00:00 2001 From: Mithil Bavishi Date: Sat, 8 Jun 2024 15:23:02 +0530 Subject: [PATCH 090/349] ASoC: dt-bindings: omap-mcpdm: Convert to DT schema Convert the OMAP4+ McPDM bindings from txt to yaml (dtschema). Drop ti,hwmods property as it is not needed since the sysc conversion. Add dma, dma-names, reg-names properties to match the DTS so as to not break the already existing ABI. Also update example node to match the existing node in the DTS. Signed-off-by: Mithil Bavishi Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240608095305.2887-1-bavishimithil@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/omap-mcpdm.txt | 30 -------- .../bindings/sound/ti,omap4-mcpdm.yaml | 73 +++++++++++++++++++ 2 files changed, 73 insertions(+), 30 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/omap-mcpdm.txt create mode 100644 Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml diff --git a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt deleted file mode 100644 index ff98a0cb5b3f..000000000000 --- a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt +++ /dev/null @@ -1,30 +0,0 @@ -* Texas Instruments OMAP4+ McPDM - -Required properties: -- compatible: "ti,omap4-mcpdm" -- reg: Register location and size as an array: - , - ; -- interrupts: Interrupt number for McPDM -- ti,hwmods: Name of the hwmod associated to the McPDM -- clocks: phandle for the pdmclk provider, likely <&twl6040> -- clock-names: Must be "pdmclk" - -Example: - -mcpdm: mcpdm@40132000 { - compatible = "ti,omap4-mcpdm"; - reg = <0x40132000 0x7f>, /* MPU private access */ - <0x49032000 0x7f>; /* L3 Interconnect */ - interrupts = <0 112 0x4>; - interrupt-parent = <&gic>; - ti,hwmods = "mcpdm"; -}; - -In board DTS file the pdmclk needs to be added: - -&mcpdm { - clocks = <&twl6040>; - clock-names = "pdmclk"; - status = "okay"; -}; diff --git a/Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml b/Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml new file mode 100644 index 000000000000..cdea0a00826a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,omap4-mcpdm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OMAP McPDM + +maintainers: + - Misael Lopez Cruz + +description: + OMAP ALSA SoC DAI driver using McPDM port used by TWL6040 + +properties: + compatible: + const: ti,omap4-mcpdm + + reg: + items: + - description: MPU access base address + - description: L3 interconnect address + + reg-names: + items: + - const: mpu + - const: dma + + interrupts: + maxItems: 1 + + dmas: + maxItems: 2 + + dma-names: + items: + - const: up_link + - const: dn_link + + clocks: + maxItems: 1 + + clock-names: + items: + - const: pdmclk + +required: + - compatible + - reg + - reg-names + - interrupts + - dmas + - dma-names + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + mcpdm@0 { + compatible = "ti,omap4-mcpdm"; + reg = <0x0 0x7f>, /* MPU private access */ + <0x49032000 0x7f>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; + interrupts = ; + interrupt-parent = <&gic>; + dmas = <&sdma 65>, <&sdma 66>; + dma-names = "up_link", "dn_link"; + clocks = <&twl6040>; + clock-names = "pdmclk"; + }; From 0ac3f1a4c2a345c48d22e8eb5b5aeb9304cb11db Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Fri, 7 Jun 2024 11:27:20 +0530 Subject: [PATCH 091/349] ASoC: dt-bindings: ak4554: Convert to dtschema Convert the AK4554 sound codec bindings to DT schema. Signed-off-by: Animesh Agarwal Cc: Daniel Baluta Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240607055725.38057-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ak4554.txt | 11 -------- .../bindings/sound/asahi-kasei,ak4554.yaml | 27 +++++++++++++++++++ 2 files changed, 27 insertions(+), 11 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/ak4554.txt create mode 100644 Documentation/devicetree/bindings/sound/asahi-kasei,ak4554.yaml diff --git a/Documentation/devicetree/bindings/sound/ak4554.txt b/Documentation/devicetree/bindings/sound/ak4554.txt deleted file mode 100644 index 934fa02754b3..000000000000 --- a/Documentation/devicetree/bindings/sound/ak4554.txt +++ /dev/null @@ -1,11 +0,0 @@ -AK4554 ADC/DAC - -Required properties: - - - compatible : "asahi-kasei,ak4554" - -Example: - -ak4554-adc-dac { - compatible = "asahi-kasei,ak4554"; -}; diff --git a/Documentation/devicetree/bindings/sound/asahi-kasei,ak4554.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4554.yaml new file mode 100644 index 000000000000..c77d85df239e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4554.yaml @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4554.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AK4554 sound codec + +maintainers: + - Kuninori Morimoto + - Liam Girdwood + - Mark Brown + +properties: + compatible: + const: asahi-kasei,ak4554 + +required: + - compatible + +additionalProperties: false + +examples: + - | + codec { + compatible = "asahi-kasei,ak4554"; + }; From c38082bf223fb4a3f2bdf1f79650af53d3499dea Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Tue, 11 Jun 2024 14:25:56 +0100 Subject: [PATCH 092/349] ASoC: cs35l56: Attempt to read from cirrus,speaker-id device property first When cs35l56 is connected via cs42l43 there isn't an ACPI node for the cs35l56 so all properties are under the cs42l43 ACPI node. We're adding a property as a way for the cs42l43 driver to pass this info in via a software node. Signed-off-by: Simon Trimmer Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20240611132556.1557075-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56-shared.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 8af89a263594..e89027cd40d1 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -853,9 +853,16 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED); int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base) { struct gpio_descs *descs; - int speaker_id; + u32 speaker_id; int i, ret; + /* Attempt to read the speaker type from a device property first */ + ret = device_property_read_u32(cs35l56_base->dev, "cirrus,speaker-id", &speaker_id); + if (!ret) { + dev_dbg(cs35l56_base->dev, "Speaker ID = %d\n", speaker_id); + return speaker_id; + } + /* Read the speaker type qualifier from the motherboard GPIOs */ descs = gpiod_get_array_optional(cs35l56_base->dev, "spk-id", GPIOD_IN); if (!descs) { From 5c33876a20e1f42471c2b6fd1804428311d35f1f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 8 Jun 2024 17:24:31 +0300 Subject: [PATCH 093/349] ASoC: samsung: midas_wm1811: Fix error code in probe() This accidentally returns success instead of -EINVAL. Fixes: c91d0c2e198d ("ASoC: samsung: midas_wm1811: Add GPIO-based headset jack detection") Signed-off-by: Dan Carpenter Acked-by: Artur Weber Link: https://lore.kernel.org/r/01590109-cf27-404b-88ff-b42bb73ca1c6@moroto.mountain Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 3a269c7de169..bbfe5fef59af 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -623,7 +623,7 @@ static int midas_probe(struct platform_device *pdev) if (channel_type != IIO_VOLTAGE) { dev_err(dev, "ADC channel is not voltage\n"); - return ret; + return -EINVAL; } priv->gpio_headset_key = devm_gpiod_get(dev, "headset-key", From a694956df4ca75d74bcd422908ddcd8e2ea3042e Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Thu, 6 Jun 2024 09:42:00 +0530 Subject: [PATCH 094/349] ASoC: dt-bindings: linux,spdif: Convert spdif-reciever.txt to dtschema Convert the dummy SPDIF receiver bindings to DT schema. Signed-off-by: Animesh Agarwal Cc: Daniel Baluta Reviewed-by: Rob Herring (Arm) Acked-by: Neil Armstrong Link: https://lore.kernel.org/r/20240606041212.78428-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../sound/{linux,spdif-dit.yaml => linux,spdif.yaml} | 8 +++++--- .../devicetree/bindings/sound/spdif-receiver.txt | 10 ---------- 2 files changed, 5 insertions(+), 13 deletions(-) rename Documentation/devicetree/bindings/sound/{linux,spdif-dit.yaml => linux,spdif.yaml} (75%) delete mode 100644 Documentation/devicetree/bindings/sound/spdif-receiver.txt diff --git a/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml b/Documentation/devicetree/bindings/sound/linux,spdif.yaml similarity index 75% rename from Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml rename to Documentation/devicetree/bindings/sound/linux,spdif.yaml index fe5f0756af2f..0f4893e11ec4 100644 --- a/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml +++ b/Documentation/devicetree/bindings/sound/linux,spdif.yaml @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/linux,spdif-dit.yaml# +$id: http://devicetree.org/schemas/sound/linux,spdif.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Dummy SPDIF Transmitter +title: Dummy SPDIF Transmitter/Receiver maintainers: - Mark Brown @@ -14,7 +14,9 @@ allOf: properties: compatible: - const: linux,spdif-dit + enum: + - linux,spdif-dit + - linux,spdif-dir "#sound-dai-cells": const: 0 diff --git a/Documentation/devicetree/bindings/sound/spdif-receiver.txt b/Documentation/devicetree/bindings/sound/spdif-receiver.txt deleted file mode 100644 index 80f807bf8a1d..000000000000 --- a/Documentation/devicetree/bindings/sound/spdif-receiver.txt +++ /dev/null @@ -1,10 +0,0 @@ -Device-Tree bindings for dummy spdif receiver - -Required properties: - - compatible: should be "linux,spdif-dir". - -Example node: - - codec: spdif-receiver { - compatible = "linux,spdif-dir"; - }; From 01e29260c645bb844fb73ad40a022d6647fb52a0 Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Tue, 11 Jun 2024 18:14:00 +0530 Subject: [PATCH 095/349] ASoC: dt-bindings: wlf,wm8782: Convert to dtschema Convert the WM8782 audio codec bindings to DT schema. Signed-off-by: Animesh Agarwal Cc: Daniel Baluta Reviewed-by: Rob Herring (Arm) Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20240611124405.63427-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/wlf,wm8782.yaml | 47 +++++++++++++++++++ .../devicetree/bindings/sound/wm8782.txt | 24 ---------- 2 files changed, 47 insertions(+), 24 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/wlf,wm8782.yaml delete mode 100644 Documentation/devicetree/bindings/sound/wm8782.txt diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8782.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8782.yaml new file mode 100644 index 000000000000..d0bbdc9f9ced --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wlf,wm8782.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/wlf,wm8782.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Wolfson Microelectromics WM8782 audio CODEC + +maintainers: + - patches@opensource.cirrus.com + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: wlf,wm8782 + + Vdda-supply: + description: Regulator for the analog power supply (2.7V - 5.5V) + + Vdd-supply: + description: Regulator for the digital power supply (2.7V - 3.6V) + + wlf,fsampen: + description: FSAMPEN pin value, 0 for low, 1 for high, 2 for disconnected. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - Vdda-supply + - Vdd-supply + +unevaluatedProperties: false + +examples: + - | + wm8782: codec { + compatible = "wlf,wm8782"; + Vdda-supply = <&vdda_supply>; + Vdd-supply = <&vdd_supply>; + wlf,fsampen = <2>; + }; diff --git a/Documentation/devicetree/bindings/sound/wm8782.txt b/Documentation/devicetree/bindings/sound/wm8782.txt deleted file mode 100644 index 1a28f3280972..000000000000 --- a/Documentation/devicetree/bindings/sound/wm8782.txt +++ /dev/null @@ -1,24 +0,0 @@ -WM8782 stereo ADC - -This device does not have any control interface or reset pins. - -Required properties: - - - compatible : "wlf,wm8782" - - Vdda-supply : phandle to a regulator for the analog power supply (2.7V - 5.5V) - - Vdd-supply : phandle to a regulator for the digital power supply (2.7V - 3.6V) - -Optional properties: - - - wlf,fsampen: - FSAMPEN pin value, 0 for low, 1 for high, 2 for disconnected. - Defaults to 0 if left unspecified. - -Example: - -wm8782: stereo-adc { - compatible = "wlf,wm8782"; - Vdda-supply = <&vdda_supply>; - Vdd-supply = <&vdd_supply>; - wlf,fsampen = <2>; /* 192KHz */ -}; From e8ffc08366f9787a69ac4b4fb3bfa0f837cd846a Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Tue, 11 Jun 2024 17:52:51 +0530 Subject: [PATCH 096/349] ASoC: dt-bindings: wlf,wm8804: Convert to dtschema Convert the WM8804 audio codec bindings to DT schema. Signed-off-by: Animesh Agarwal Cc: Daniel Baluta Reviewed-by: Rob Herring (Arm) Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20240611122258.47406-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/wlf,wm8804.yaml | 58 +++++++++++++++++++ .../devicetree/bindings/sound/wm8804.txt | 25 -------- 2 files changed, 58 insertions(+), 25 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/wlf,wm8804.yaml delete mode 100644 Documentation/devicetree/bindings/sound/wm8804.txt diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8804.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8804.yaml new file mode 100644 index 000000000000..3c060179f06e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wlf,wm8804.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/wlf,wm8804.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: WM8804 audio codec + +description: | + This device supports both I2C and SPI (configured with pin strapping on the + board). + +maintainers: + - patches@opensource.cirrus.com + +properties: + compatible: + const: wlf,wm8804 + + reg: + description: + The I2C address of the device for I2C, the chip select number for SPI. + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + PVDD-supply: + description: PLL core supply + + DVDD-supply: + description: Digital core supply + + wlf,reset-gpio: + description: A GPIO specifier for the GPIO controlling the reset pin. + maxItems: 1 + +required: + - reg + - compatible + - PVDD-supply + - DVDD-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + compatible = "wlf,wm8804"; + reg = <0x1a>; + PVDD-supply = <&pvdd_reg>; + DVDD-supply = <&dvdd_reg>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/wm8804.txt b/Documentation/devicetree/bindings/sound/wm8804.txt deleted file mode 100644 index 2c1641c17a91..000000000000 --- a/Documentation/devicetree/bindings/sound/wm8804.txt +++ /dev/null @@ -1,25 +0,0 @@ -WM8804 audio CODEC - -This device supports both I2C and SPI (configured with pin strapping -on the board). - -Required properties: - - - compatible : "wlf,wm8804" - - - reg : the I2C address of the device for I2C, the chip select - number for SPI. - - - PVDD-supply, DVDD-supply : Power supplies for the device, as covered - in Documentation/devicetree/bindings/regulator/regulator.txt - -Optional properties: - - - wlf,reset-gpio: A GPIO specifier for the GPIO controlling the reset pin - -Example: - -wm8804: codec@1a { - compatible = "wlf,wm8804"; - reg = <0x1a>; -}; From fe833e4397fbdc3ae13a60202dfc7c335b032499 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Wed, 12 Jun 2024 20:26:26 -0700 Subject: [PATCH 097/349] ASoC: amd: add missing MODULE_DESCRIPTION() macros With ARCH=x86, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in sound/soc/amd/renoir/snd-acp3x-rn.o WARNING: modpost: missing MODULE_DESCRIPTION() in sound/soc/amd/yc/snd-soc-acp6x-mach.o WARNING: modpost: missing MODULE_DESCRIPTION() in sound/soc/amd/acp/snd-acp-i2s.o WARNING: modpost: missing MODULE_DESCRIPTION() in sound/soc/amd/acp/snd-acp-pdm.o WARNING: modpost: missing MODULE_DESCRIPTION() in sound/soc/amd/acp/snd-acp-legacy-common.o WARNING: modpost: missing MODULE_DESCRIPTION() in sound/soc/amd/acp/snd-acp-pci.o WARNING: modpost: missing MODULE_DESCRIPTION() in sound/soc/amd/ps/snd-soc-ps-mach.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240612-md-sound-soc-amd-v1-1-ad1de0409c11@quicinc.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-i2s.c | 1 + sound/soc/amd/acp/acp-legacy-common.c | 1 + sound/soc/amd/acp/acp-pci.c | 1 + sound/soc/amd/acp/acp-pdm.c | 1 + sound/soc/amd/ps/ps-mach.c | 1 + sound/soc/amd/renoir/acp3x-rn.c | 1 + sound/soc/amd/yc/acp6x-mach.c | 1 + 7 files changed, 7 insertions(+) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 60cbc881be6e..0bc8617e922a 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -616,5 +616,6 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { }; EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); +MODULE_DESCRIPTION("AMD ACP Audio I2S controller"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS(DRV_NAME); diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index 3be7c6d55a6f..4422cec81e3c 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -475,4 +475,5 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip) } EXPORT_SYMBOL_NS_GPL(check_acp_config, SND_SOC_ACP_COMMON); +MODULE_DESCRIPTION("AMD ACP legacy common features"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index ad320b29e87d..565623afd42e 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -247,6 +247,7 @@ static struct pci_driver snd_amd_acp_pci_driver = { }; module_pci_driver(snd_amd_acp_pci_driver); +MODULE_DESCRIPTION("AMD ACP common PCI support"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); MODULE_ALIAS(DRV_NAME); diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index f754bf79b5e3..bb79269c2fc1 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -178,5 +178,6 @@ const struct snd_soc_dai_ops acp_dmic_dai_ops = { }; EXPORT_SYMBOL_NS_GPL(acp_dmic_dai_ops, SND_SOC_ACP_COMMON); +MODULE_DESCRIPTION("AMD ACP Audio PDM controller"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS(DRV_NAME); diff --git a/sound/soc/amd/ps/ps-mach.c b/sound/soc/amd/ps/ps-mach.c index e675b8f569eb..ff8ad036b077 100644 --- a/sound/soc/amd/ps/ps-mach.c +++ b/sound/soc/amd/ps/ps-mach.c @@ -75,5 +75,6 @@ static struct platform_driver acp63_mach_driver = { module_platform_driver(acp63_mach_driver); MODULE_AUTHOR("Syed.SabaKareem@amd.com"); +MODULE_DESCRIPTION("AMD Pink Sardine support for DMIC"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amd/renoir/acp3x-rn.c b/sound/soc/amd/renoir/acp3x-rn.c index 5d979a7b77fb..3249f74a0197 100644 --- a/sound/soc/amd/renoir/acp3x-rn.c +++ b/sound/soc/amd/renoir/acp3x-rn.c @@ -72,5 +72,6 @@ static struct platform_driver acp_mach_driver = { module_platform_driver(acp_mach_driver); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_DESCRIPTION("AMD Renoir support for DMIC"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index 1760b5d42460..4b32517c1b7c 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -504,5 +504,6 @@ static struct platform_driver acp6x_mach_driver = { module_platform_driver(acp6x_mach_driver); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_DESCRIPTION("AMD Yellow Carp support for DMIC"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); From cc3c2376412098ca5f8c1a50e61e69620e9f09d1 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Sun, 2 Jun 2024 00:26:04 +0100 Subject: [PATCH 098/349] ALSA: xen-front: remove unused struct 'alsa_sndif_hw_param' 'alsa_sndif_hw_param' has been unused since the original commit 1cee559351a7 ("ALSA: xen-front: Implement ALSA virtual sound driver"). Remove it. Signed-off-by: Dr. David Alan Gilbert Link: https://lore.kernel.org/r/20240601232604.198662-1-linux@treblig.org Signed-off-by: Takashi Iwai --- sound/xen/xen_snd_front_alsa.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c index 31b5dc0f34d2..b229eb6f7057 100644 --- a/sound/xen/xen_snd_front_alsa.c +++ b/sound/xen/xen_snd_front_alsa.c @@ -69,11 +69,6 @@ struct alsa_sndif_sample_format { snd_pcm_format_t alsa; }; -struct alsa_sndif_hw_param { - u8 sndif; - snd_pcm_hw_param_t alsa; -}; - static const struct alsa_sndif_sample_format ALSA_SNDIF_FORMATS[] = { { .sndif = XENSND_PCM_FORMAT_U8, From 163f10b2935362f0e8ef8d7fadd0b5aa33e9130f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Jun 2024 08:47:07 +0200 Subject: [PATCH 099/349] PCI: Add INTEL_HDA_PTL to pci_ids.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More PCI ids for Intel audio. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Acked-by: Bjorn Helgaas Link: https://lore.kernel.org/r/20240612064709.51141-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 942a587bb97e..0168c6a60148 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -3112,6 +3112,7 @@ #define PCI_DEVICE_ID_INTEL_HDA_LNL_P 0xa828 #define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 #define PCI_DEVICE_ID_INTEL_HDA_BMG 0xe2f7 +#define PCI_DEVICE_ID_INTEL_HDA_PTL 0xe428 #define PCI_DEVICE_ID_INTEL_HDA_CML_R 0xf0c8 #define PCI_DEVICE_ID_INTEL_HDA_RKL_S 0xf1c8 From 9c7fb8e832b741f6f0c9fd4bb2cce05e38d48335 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Jun 2024 08:47:08 +0200 Subject: [PATCH 100/349] ALSA: hda: hda-intel: add PantherLake support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One more PCI ID. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20240612064709.51141-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3500108f6ba3..b33602e64d17 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2495,6 +2495,8 @@ static const struct pci_device_id azx_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Arrow Lake */ { PCI_DEVICE_DATA(INTEL, HDA_ARL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + /* Panther Lake */ + { PCI_DEVICE_DATA(INTEL, HDA_PTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) }, /* Apollolake (Broxton-P) */ { PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) }, /* Gemini-Lake */ From 19765dbef1cda16027559bff2dd1370da87a2eb7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Jun 2024 08:47:09 +0200 Subject: [PATCH 101/349] ALSA: hda: intel-dsp-config: Add PTL support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same recipes as LNL Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20240612064709.51141-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/intel-dsp-config.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 537863447358..a7419d2e912e 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -543,6 +543,15 @@ static const struct config_entry config_table[] = { .device = PCI_DEVICE_ID_INTEL_HDA_LNL_P, }, #endif + + /* Panther Lake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PANTHERLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_PTL, + }, +#endif + }; static const struct config_entry *snd_intel_dsp_find_config From a9c8ca5d5d8452ca38300c7fb74bf8735d08f43b Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 11 Jun 2024 09:30:04 +0200 Subject: [PATCH 102/349] ASoC: dt-bindings: convert tas571x.txt to dt-schema Convert the text bindings for the Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 stereo power amplifiers to dt-schema. Signed-off-by: Neil Armstrong Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240611-topic-amlogic-upstream-bindings-convert-tas57xx-v2-1-38269edc1d95@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/tas571x.txt | 49 ------- .../devicetree/bindings/sound/ti,tas57xx.yaml | 133 ++++++++++++++++++ 2 files changed, 133 insertions(+), 49 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt create mode 100644 Documentation/devicetree/bindings/sound/ti,tas57xx.yaml diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt deleted file mode 100644 index 1addc75989d5..000000000000 --- a/Documentation/devicetree/bindings/sound/tas571x.txt +++ /dev/null @@ -1,49 +0,0 @@ -Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 stereo power amplifiers - -The codec is controlled through an I2C interface. It also has two other -signals that can be wired up to GPIOs: reset (strongly recommended), and -powerdown (optional). - -Required properties: - -- compatible: should be one of the following: - - "ti,tas5707" - - "ti,tas5711", - - "ti,tas5717", - - "ti,tas5719", - - "ti,tas5721" - - "ti,tas5733" -- reg: The I2C address of the device -- #sound-dai-cells: must be equal to 0 - -Optional properties: - -- reset-gpios: GPIO specifier for the TAS571x's active low reset line -- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line -- clocks: clock phandle for the MCLK input -- clock-names: should be "mclk" -- AVDD-supply: regulator phandle for the AVDD supply (all chips) -- DVDD-supply: regulator phandle for the DVDD supply (all chips) -- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719) -- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719) -- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719) -- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711) -- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711) -- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711) -- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711) -- DRVDD-supply: regulator phandle for the DRVDD supply (5721) -- PVDD-supply: regulator phandle for the PVDD supply (5721) - -Example: - - tas5717: audio-codec@2a { - compatible = "ti,tas5717"; - reg = <0x2a>; - #sound-dai-cells = <0>; - - reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; - pdn-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>; - - clocks = <&clk_core CLK_I2S>; - clock-names = "mclk"; - }; diff --git a/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml b/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml new file mode 100644 index 000000000000..2f917238db95 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,tas57xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 stereo power amplifiers + +maintainers: + - Neil Armstrong + +properties: + compatible: + enum: + - ti,tas5707 + - ti,tas5711 + - ti,tas5717 + - ti,tas5719 + - ti,tas5721 + - ti,tas5733 + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + description: GPIO for the active low reset line + + pdn-gpios: + maxItems: 1 + description: GPIO for the active low powerdown line + + clocks: + maxItems: 1 + + clock-names: + const: mclk + + AVDD-supply: true + DVDD-supply: true + HPVDD-supply: true + PVDD_AB-supply: true + PVDD_CD-supply: true + PVDD_A-supply: true + PVDD_B-supply: true + PVDD_C-supply: true + PVDD_D-supply: true + DRVDD-supply: true + PVDD-supply: true + + '#sound-dai-cells': + const: 0 + + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - '#sound-dai-cells' + +allOf: + - $ref: dai-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - ti,tas5717 + - ti,tas5719 + then: + properties: + PVDD_A-supply: false + PVDD_B-supply: false + PVDD_C-supply: false + PVDD_D-supply: false + DRVDD-supply: false + PVDD-supply: false + + - if: + properties: + compatible: + contains: + enum: + - ti,tas5711 + then: + properties: + HPVDD-supply: false + PVDD_AB-supply: false + PVDD_CD-supply: false + DRVDD-supply: false + PVDD-supply: false + + - if: + properties: + compatible: + contains: + enum: + - ti,tas5721 + then: + properties: + HPVDD-supply: false + PVDD_AB-supply: false + PVDD_CD-supply: false + PVDD_A-supply: false + PVDD_B-supply: false + PVDD_C-supply: false + PVDD_D-supply: false + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@2a { + compatible = "ti,tas5717"; + reg = <0x2a>; + #sound-dai-cells = <0>; + reset-gpios = <&gpio1 15 0>; + pdn-gpios = <&gpio1 15 0>; + AVDD-supply = <&avdd_supply>; + DVDD-supply = <&dvdd_supply>; + HPVDD-supply = <&hpvdd_supply>; + PVDD_AB-supply = <&pvdd_ab_supply>; + PVDD_CD-supply = <&pvdd_cd_supply>; + }; + }; + +... From 7fbc4f5e633cbc23576c32ff9773faa1788afc2d Mon Sep 17 00:00:00 2001 From: Abdulrasaq Lawani Date: Wed, 12 Jun 2024 12:36:50 -0400 Subject: [PATCH 103/349] dt-bindings: sound: Convert max98088 to dtschema Convert the max98088 audio codec txt bindings to DT schema. Signed-off-by: Abdulrasaq Lawani Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240612163730.515819-1-abdulrasaqolawani@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/maxim,max98088.txt | 23 --------- .../bindings/sound/maxim,max98088.yaml | 47 +++++++++++++++++++ 2 files changed, 47 insertions(+), 23 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/maxim,max98088.txt create mode 100644 Documentation/devicetree/bindings/sound/maxim,max98088.yaml diff --git a/Documentation/devicetree/bindings/sound/maxim,max98088.txt b/Documentation/devicetree/bindings/sound/maxim,max98088.txt deleted file mode 100644 index da764d913319..000000000000 --- a/Documentation/devicetree/bindings/sound/maxim,max98088.txt +++ /dev/null @@ -1,23 +0,0 @@ -MAX98088 audio CODEC - -This device supports I2C only. - -Required properties: - -- compatible: "maxim,max98088" or "maxim,max98089". -- reg: The I2C address of the device. - -Optional properties: - -- clocks: the clock provider of MCLK, see ../clock/clock-bindings.txt section - "consumer" for more information. -- clock-names: must be set to "mclk" - -Example: - -max98089: codec@10 { - compatible = "maxim,max98089"; - reg = <0x10>; - clocks = <&clks IMX6QDL_CLK_CKO2>; - clock-names = "mclk"; -}; diff --git a/Documentation/devicetree/bindings/sound/maxim,max98088.yaml b/Documentation/devicetree/bindings/sound/maxim,max98088.yaml new file mode 100644 index 000000000000..e4a2967e1e81 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/maxim,max98088.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/maxim,max98088.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MAX98088 audio CODEC + +maintainers: + - Abdulrasaq Lawani + +properties: + compatible: + enum: + - maxim,max98088 + - maxim,max98089 + + reg: + maxItems: 1 + + clocks: + items: + - description: master clock + + clock-names: + items: + - const: mclk + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + audio-codec@10 { + compatible = "maxim,max98089"; + reg = <0x10>; + clocks = <&clks 0>; + clock-names = "mclk"; + }; + }; From 378918d5918116b95300dd7f03913a1d0841f223 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 13 Jun 2024 11:49:31 +0100 Subject: [PATCH 104/349] ASoC: codecs: lpass-macro: add helpers to get codec version LPASS Digital codec have changes in register layout across multiple versions. Add a proper way read the codec version allowint all the lpass macro drivers (tx, rx, wsa, va) to configure the registers correctly. LPASS VA macro has the required registers to read the codec version. Read the the version and make it available to other lpass codec macros using the common helper functions. Existing method of using LPASS IP version is not accurate as the same the codec versioning is totally independent of LPASS IP block versions. These helper functions should be able to provide a convient way to get the codec version, and will help scale the drivers in right direction. Signed-off-by: Srinivas Kandagatla Tested-by: Krzysztof Kozlowski Tested-by: Neil Armstrong # on SM8650-HDK Link: https://lore.kernel.org/r/20240612-lpass-codec-v25-v4-1-f63d3676dbc4@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-macro-common.c | 23 ++++++++++++++++++ sound/soc/codecs/lpass-macro-common.h | 35 +++++++++++++++++++++++++++ sound/soc/codecs/lpass-va-macro.c | 28 +++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c index da1b422250b8..8b038a99a8f9 100644 --- a/sound/soc/codecs/lpass-macro-common.c +++ b/sound/soc/codecs/lpass-macro-common.c @@ -11,6 +11,9 @@ #include "lpass-macro-common.h" +static DEFINE_MUTEX(lpass_codec_mutex); +static int lpass_codec_version; + struct lpass_macro *lpass_macro_pds_init(struct device *dev) { struct lpass_macro *l_pds; @@ -66,5 +69,25 @@ void lpass_macro_pds_exit(struct lpass_macro *pds) } EXPORT_SYMBOL_GPL(lpass_macro_pds_exit); +void lpass_macro_set_codec_version(int version) +{ + mutex_lock(&lpass_codec_mutex); + lpass_codec_version = version; + mutex_unlock(&lpass_codec_mutex); +} +EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version); + +int lpass_macro_get_codec_version(void) +{ + int ver; + + mutex_lock(&lpass_codec_mutex); + ver = lpass_codec_version; + mutex_unlock(&lpass_codec_mutex); + + return ver; +} +EXPORT_SYMBOL_GPL(lpass_macro_get_codec_version); + MODULE_DESCRIPTION("Common macro driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h index d98718b3dc4b..f6f1bfe8eb77 100644 --- a/sound/soc/codecs/lpass-macro-common.h +++ b/sound/soc/codecs/lpass-macro-common.h @@ -18,6 +18,18 @@ enum lpass_version { LPASS_VER_11_0_0, }; +enum lpass_codec_version { + LPASS_CODEC_VERSION_1_0 = 1, + LPASS_CODEC_VERSION_1_1, + LPASS_CODEC_VERSION_1_2, + LPASS_CODEC_VERSION_2_0, + LPASS_CODEC_VERSION_2_1, + LPASS_CODEC_VERSION_2_5, + LPASS_CODEC_VERSION_2_6, + LPASS_CODEC_VERSION_2_7, + LPASS_CODEC_VERSION_2_8, +}; + struct lpass_macro { struct device *macro_pd; struct device *dcodec_pd; @@ -25,5 +37,28 @@ struct lpass_macro { struct lpass_macro *lpass_macro_pds_init(struct device *dev); void lpass_macro_pds_exit(struct lpass_macro *pds); +void lpass_macro_set_codec_version(int version); +int lpass_macro_get_codec_version(void); + +static inline const char *lpass_macro_get_codec_version_string(int version) +{ + switch (version) { + case LPASS_CODEC_VERSION_2_0: + return "v2.0"; + case LPASS_CODEC_VERSION_2_1: + return "v2.1"; + case LPASS_CODEC_VERSION_2_5: + return "v2.5"; + case LPASS_CODEC_VERSION_2_6: + return "v2.6"; + case LPASS_CODEC_VERSION_2_7: + return "v2.7"; + case LPASS_CODEC_VERSION_2_8: + return "v2.8"; + default: + break; + } + return "NA"; +} #endif /* __LPASS_MACRO_COMMON_H__ */ diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 6eceeff10bf6..a555e1e078eb 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1461,6 +1461,32 @@ undefined_rate: return dmic_sample_rate; } +static void va_macro_set_lpass_codec_version(struct va_macro *va) +{ + int core_id_0 = 0, core_id_1 = 0, core_id_2 = 0, version; + + regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_0, &core_id_0); + regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_1, &core_id_1); + regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_2, &core_id_2); + + if ((core_id_0 == 0x01) && (core_id_1 == 0x0F)) + version = LPASS_CODEC_VERSION_2_0; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0E)) + version = LPASS_CODEC_VERSION_2_1; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x50 || core_id_2 == 0x51)) + version = LPASS_CODEC_VERSION_2_5; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x60 || core_id_2 == 0x61)) + version = LPASS_CODEC_VERSION_2_6; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x70 || core_id_2 == 0x71)) + version = LPASS_CODEC_VERSION_2_7; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x80 || core_id_2 == 0x81)) + version = LPASS_CODEC_VERSION_2_8; + + lpass_macro_set_codec_version(version); + + dev_dbg(va->dev, "LPASS Codec Version %s\n", lpass_macro_get_codec_version_string(version)); +} + static int va_macro_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1554,6 +1580,8 @@ static int va_macro_probe(struct platform_device *pdev) goto err_npl; } + va_macro_set_lpass_codec_version(va); + if (va->has_swr_master) { /* Set default CLK div to 1 */ regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL0, From dbacef05898d65f586fb9b90ba367e6bf898d68d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 13 Jun 2024 11:49:32 +0100 Subject: [PATCH 105/349] ASoC: codec: lpass-rx-macro: prepare driver to accomdate new codec versions LPASS Codec v2.5 has significant changes in the rx block register strides. This is a preparatory patch to do the required changes in the existing driver to be able to accomdate these changes. Signed-off-by: Srinivas Kandagatla Tested-by: Krzysztof Kozlowski Tested-by: Neil Armstrong # on SM8650-HDK Link: https://lore.kernel.org/r/20240612-lpass-codec-v25-v4-2-f63d3676dbc4@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 397 ++++++++++++++++++------------ 1 file changed, 244 insertions(+), 153 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index f35187d69cac..360c9003a890 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -158,7 +158,7 @@ #define CDC_RX_INTR_CTRL_LEVEL0 (0x03C0) #define CDC_RX_INTR_CTRL_BYPASS0 (0x03C8) #define CDC_RX_INTR_CTRL_SET0 (0x03D0) -#define CDC_RX_RXn_RX_PATH_CTL(n) (0x0400 + 0x80 * n) +#define CDC_RX_RXn_RX_PATH_CTL(rx, n) (0x0400 + rx->rxn_reg_stride * n) #define CDC_RX_RX0_RX_PATH_CTL (0x0400) #define CDC_RX_PATH_RESET_EN_MASK BIT(6) #define CDC_RX_PATH_CLK_EN_MASK BIT(5) @@ -166,45 +166,47 @@ #define CDC_RX_PATH_PGA_MUTE_MASK BIT(4) #define CDC_RX_PATH_PGA_MUTE_ENABLE BIT(4) #define CDC_RX_PATH_PCM_RATE_MASK GENMASK(3, 0) -#define CDC_RX_RXn_RX_PATH_CFG0(n) (0x0404 + 0x80 * n) +#define CDC_RX_RXn_RX_PATH_CFG0(rx, n) (0x0404 + rx->rxn_reg_stride * n) #define CDC_RX_RXn_COMP_EN_MASK BIT(1) #define CDC_RX_RX0_RX_PATH_CFG0 (0x0404) #define CDC_RX_RXn_CLSH_EN_MASK BIT(6) #define CDC_RX_DLY_ZN_EN_MASK BIT(3) #define CDC_RX_DLY_ZN_ENABLE BIT(3) #define CDC_RX_RXn_HD2_EN_MASK BIT(2) -#define CDC_RX_RXn_RX_PATH_CFG1(n) (0x0408 + 0x80 * n) +#define CDC_RX_RXn_RX_PATH_CFG1(rx, n) (0x0408 + rx->rxn_reg_stride * n) #define CDC_RX_RXn_SIDETONE_EN_MASK BIT(4) #define CDC_RX_RX0_RX_PATH_CFG1 (0x0408) #define CDC_RX_RX0_HPH_L_EAR_SEL_MASK BIT(1) -#define CDC_RX_RXn_RX_PATH_CFG2(n) (0x040C + 0x80 * n) +#define CDC_RX_RXn_RX_PATH_CFG2(rx, n) (0x040C + rx->rxn_reg_stride * n) #define CDC_RX_RXn_HPF_CUT_FREQ_MASK GENMASK(1, 0) #define CDC_RX_RX0_RX_PATH_CFG2 (0x040C) -#define CDC_RX_RXn_RX_PATH_CFG3(n) (0x0410 + 0x80 * n) +#define CDC_RX_RXn_RX_PATH_CFG3(rx, n) (0x0410 + rx->rxn_reg_stride * n) #define CDC_RX_RX0_RX_PATH_CFG3 (0x0410) #define CDC_RX_DC_COEFF_SEL_MASK GENMASK(1, 0) #define CDC_RX_DC_COEFF_SEL_TWO 0x2 -#define CDC_RX_RXn_RX_VOL_CTL(n) (0x0414 + 0x80 * n) +#define CDC_RX_RXn_RX_VOL_CTL(rx, n) (0x0414 + rx->rxn_reg_stride * n) #define CDC_RX_RX0_RX_VOL_CTL (0x0414) -#define CDC_RX_RXn_RX_PATH_MIX_CTL(n) (0x0418 + 0x80 * n) +#define CDC_RX_RXn_RX_PATH_MIX_CTL(rx, n) (0x0418 + rx->rxn_reg_stride * n) #define CDC_RX_RXn_MIX_PCM_RATE_MASK GENMASK(3, 0) #define CDC_RX_RXn_MIX_RESET_MASK BIT(6) #define CDC_RX_RXn_MIX_RESET BIT(6) #define CDC_RX_RXn_MIX_CLK_EN_MASK BIT(5) #define CDC_RX_RX0_RX_PATH_MIX_CTL (0x0418) #define CDC_RX_RX0_RX_PATH_MIX_CFG (0x041C) -#define CDC_RX_RXn_RX_VOL_MIX_CTL(n) (0x0420 + 0x80 * n) +#define CDC_RX_RXn_RX_VOL_MIX_CTL(rx, n) (0x0420 + rx->rxn_reg_stride * n) #define CDC_RX_RX0_RX_VOL_MIX_CTL (0x0420) #define CDC_RX_RX0_RX_PATH_SEC1 (0x0424) #define CDC_RX_RX0_RX_PATH_SEC2 (0x0428) #define CDC_RX_RX0_RX_PATH_SEC3 (0x042C) +#define CDC_RX_RXn_RX_PATH_SEC3(rx, n) (0x042c + rx->rxn_reg_stride * n) #define CDC_RX_RX0_RX_PATH_SEC4 (0x0430) #define CDC_RX_RX0_RX_PATH_SEC7 (0x0434) +#define CDC_RX_RXn_RX_PATH_SEC7(rx, n) (0x0434 + rx->rxn_reg_stride * n) #define CDC_RX_DSM_OUT_DELAY_SEL_MASK GENMASK(2, 0) #define CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE 0x2 #define CDC_RX_RX0_RX_PATH_MIX_SEC0 (0x0438) #define CDC_RX_RX0_RX_PATH_MIX_SEC1 (0x043C) -#define CDC_RX_RXn_RX_PATH_DSM_CTL(n) (0x0440 + 0x80 * n) +#define CDC_RX_RXn_RX_PATH_DSM_CTL(rx, n) (0x0440 + rx->rxn_reg_stride * n) #define CDC_RX_RXn_DSM_CLK_EN_MASK BIT(0) #define CDC_RX_RX0_RX_PATH_DSM_CTL (0x0440) #define CDC_RX_RX0_RX_PATH_DSM_DATA1 (0x0444) @@ -213,6 +215,7 @@ #define CDC_RX_RX0_RX_PATH_DSM_DATA4 (0x0450) #define CDC_RX_RX0_RX_PATH_DSM_DATA5 (0x0454) #define CDC_RX_RX0_RX_PATH_DSM_DATA6 (0x0458) +/* RX offsets prior to 2.5 codec version */ #define CDC_RX_RX1_RX_PATH_CTL (0x0480) #define CDC_RX_RX1_RX_PATH_CFG0 (0x0484) #define CDC_RX_RX1_RX_PATH_CFG1 (0x0488) @@ -598,6 +601,8 @@ struct rx_macro { int rx_mclk_users; int clsh_users; int rx_mclk_cnt; + int codec_version; + int rxn_reg_stride; bool is_ear_mode_on; bool hph_pwr_mode; bool hph_hd2_mode; @@ -976,49 +981,6 @@ static const struct reg_default rx_defaults[] = { { CDC_RX_RX0_RX_PATH_DSM_DATA4, 0x55 }, { CDC_RX_RX0_RX_PATH_DSM_DATA5, 0x55 }, { CDC_RX_RX0_RX_PATH_DSM_DATA6, 0x55 }, - { CDC_RX_RX1_RX_PATH_CTL, 0x04 }, - { CDC_RX_RX1_RX_PATH_CFG0, 0x00 }, - { CDC_RX_RX1_RX_PATH_CFG1, 0x64 }, - { CDC_RX_RX1_RX_PATH_CFG2, 0x8F }, - { CDC_RX_RX1_RX_PATH_CFG3, 0x00 }, - { CDC_RX_RX1_RX_VOL_CTL, 0x00 }, - { CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04 }, - { CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E }, - { CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00 }, - { CDC_RX_RX1_RX_PATH_SEC1, 0x08 }, - { CDC_RX_RX1_RX_PATH_SEC2, 0x00 }, - { CDC_RX_RX1_RX_PATH_SEC3, 0x00 }, - { CDC_RX_RX1_RX_PATH_SEC4, 0x00 }, - { CDC_RX_RX1_RX_PATH_SEC7, 0x00 }, - { CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08 }, - { CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00 }, - { CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08 }, - { CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00 }, - { CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00 }, - { CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00 }, - { CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55 }, - { CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55 }, - { CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55 }, - { CDC_RX_RX2_RX_PATH_CTL, 0x04 }, - { CDC_RX_RX2_RX_PATH_CFG0, 0x00 }, - { CDC_RX_RX2_RX_PATH_CFG1, 0x64 }, - { CDC_RX_RX2_RX_PATH_CFG2, 0x8F }, - { CDC_RX_RX2_RX_PATH_CFG3, 0x00 }, - { CDC_RX_RX2_RX_VOL_CTL, 0x00 }, - { CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04 }, - { CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E }, - { CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00 }, - { CDC_RX_RX2_RX_PATH_SEC0, 0x04 }, - { CDC_RX_RX2_RX_PATH_SEC1, 0x08 }, - { CDC_RX_RX2_RX_PATH_SEC2, 0x00 }, - { CDC_RX_RX2_RX_PATH_SEC3, 0x00 }, - { CDC_RX_RX2_RX_PATH_SEC4, 0x00 }, - { CDC_RX_RX2_RX_PATH_SEC5, 0x00 }, - { CDC_RX_RX2_RX_PATH_SEC6, 0x00 }, - { CDC_RX_RX2_RX_PATH_SEC7, 0x00 }, - { CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08 }, - { CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00 }, - { CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00 }, { CDC_RX_IDLE_DETECT_PATH_CTL, 0x00 }, { CDC_RX_IDLE_DETECT_CFG0, 0x07 }, { CDC_RX_IDLE_DETECT_CFG1, 0x3C }, @@ -1121,6 +1083,53 @@ static const struct reg_default rx_defaults[] = { { CDC_RX_DSD1_CFG2, 0x96 }, }; +static const struct reg_default rx_pre_2_5_defaults[] = { + { CDC_RX_RX1_RX_PATH_CTL, 0x04 }, + { CDC_RX_RX1_RX_PATH_CFG0, 0x00 }, + { CDC_RX_RX1_RX_PATH_CFG1, 0x64 }, + { CDC_RX_RX1_RX_PATH_CFG2, 0x8F }, + { CDC_RX_RX1_RX_PATH_CFG3, 0x00 }, + { CDC_RX_RX1_RX_VOL_CTL, 0x00 }, + { CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04 }, + { CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E }, + { CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00 }, + { CDC_RX_RX1_RX_PATH_SEC1, 0x08 }, + { CDC_RX_RX1_RX_PATH_SEC2, 0x00 }, + { CDC_RX_RX1_RX_PATH_SEC3, 0x00 }, + { CDC_RX_RX1_RX_PATH_SEC4, 0x00 }, + { CDC_RX_RX1_RX_PATH_SEC7, 0x00 }, + { CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08 }, + { CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00 }, + { CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08 }, + { CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00 }, + { CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00 }, + { CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00 }, + { CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55 }, + { CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55 }, + { CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55 }, + { CDC_RX_RX2_RX_PATH_CTL, 0x04 }, + { CDC_RX_RX2_RX_PATH_CFG0, 0x00 }, + { CDC_RX_RX2_RX_PATH_CFG1, 0x64 }, + { CDC_RX_RX2_RX_PATH_CFG2, 0x8F }, + { CDC_RX_RX2_RX_PATH_CFG3, 0x00 }, + { CDC_RX_RX2_RX_VOL_CTL, 0x00 }, + { CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04 }, + { CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E }, + { CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00 }, + { CDC_RX_RX2_RX_PATH_SEC0, 0x04 }, + { CDC_RX_RX2_RX_PATH_SEC1, 0x08 }, + { CDC_RX_RX2_RX_PATH_SEC2, 0x00 }, + { CDC_RX_RX2_RX_PATH_SEC3, 0x00 }, + { CDC_RX_RX2_RX_PATH_SEC4, 0x00 }, + { CDC_RX_RX2_RX_PATH_SEC5, 0x00 }, + { CDC_RX_RX2_RX_PATH_SEC6, 0x00 }, + { CDC_RX_RX2_RX_PATH_SEC7, 0x00 }, + { CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08 }, + { CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00 }, + { CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00 }, + +}; + static bool rx_is_wronly_register(struct device *dev, unsigned int reg) { @@ -1175,8 +1184,62 @@ static bool rx_is_volatile_register(struct device *dev, unsigned int reg) return false; } +static bool rx_pre_2_5_is_rw_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_RX_RX1_RX_PATH_CTL: + case CDC_RX_RX1_RX_PATH_CFG0: + case CDC_RX_RX1_RX_PATH_CFG1: + case CDC_RX_RX1_RX_PATH_CFG2: + case CDC_RX_RX1_RX_PATH_CFG3: + case CDC_RX_RX1_RX_VOL_CTL: + case CDC_RX_RX1_RX_PATH_MIX_CTL: + case CDC_RX_RX1_RX_PATH_MIX_CFG: + case CDC_RX_RX1_RX_VOL_MIX_CTL: + case CDC_RX_RX1_RX_PATH_SEC1: + case CDC_RX_RX1_RX_PATH_SEC2: + case CDC_RX_RX1_RX_PATH_SEC3: + case CDC_RX_RX1_RX_PATH_SEC4: + case CDC_RX_RX1_RX_PATH_SEC7: + case CDC_RX_RX1_RX_PATH_MIX_SEC0: + case CDC_RX_RX1_RX_PATH_MIX_SEC1: + case CDC_RX_RX1_RX_PATH_DSM_CTL: + case CDC_RX_RX1_RX_PATH_DSM_DATA1: + case CDC_RX_RX1_RX_PATH_DSM_DATA2: + case CDC_RX_RX1_RX_PATH_DSM_DATA3: + case CDC_RX_RX1_RX_PATH_DSM_DATA4: + case CDC_RX_RX1_RX_PATH_DSM_DATA5: + case CDC_RX_RX1_RX_PATH_DSM_DATA6: + case CDC_RX_RX2_RX_PATH_CTL: + case CDC_RX_RX2_RX_PATH_CFG0: + case CDC_RX_RX2_RX_PATH_CFG1: + case CDC_RX_RX2_RX_PATH_CFG2: + case CDC_RX_RX2_RX_PATH_CFG3: + case CDC_RX_RX2_RX_VOL_CTL: + case CDC_RX_RX2_RX_PATH_MIX_CTL: + case CDC_RX_RX2_RX_PATH_MIX_CFG: + case CDC_RX_RX2_RX_VOL_MIX_CTL: + case CDC_RX_RX2_RX_PATH_SEC0: + case CDC_RX_RX2_RX_PATH_SEC1: + case CDC_RX_RX2_RX_PATH_SEC2: + case CDC_RX_RX2_RX_PATH_SEC3: + case CDC_RX_RX2_RX_PATH_SEC4: + case CDC_RX_RX2_RX_PATH_SEC5: + case CDC_RX_RX2_RX_PATH_SEC6: + case CDC_RX_RX2_RX_PATH_SEC7: + case CDC_RX_RX2_RX_PATH_MIX_SEC0: + case CDC_RX_RX2_RX_PATH_MIX_SEC1: + case CDC_RX_RX2_RX_PATH_DSM_CTL: + return true; + } + + return false; +} + static bool rx_is_rw_register(struct device *dev, unsigned int reg) { + struct rx_macro *rx = dev_get_drvdata(dev); + switch (reg) { case CDC_RX_TOP_TOP_CFG0: case CDC_RX_TOP_SWR_CTRL: @@ -1306,49 +1369,6 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg) case CDC_RX_RX0_RX_PATH_DSM_DATA4: case CDC_RX_RX0_RX_PATH_DSM_DATA5: case CDC_RX_RX0_RX_PATH_DSM_DATA6: - case CDC_RX_RX1_RX_PATH_CTL: - case CDC_RX_RX1_RX_PATH_CFG0: - case CDC_RX_RX1_RX_PATH_CFG1: - case CDC_RX_RX1_RX_PATH_CFG2: - case CDC_RX_RX1_RX_PATH_CFG3: - case CDC_RX_RX1_RX_VOL_CTL: - case CDC_RX_RX1_RX_PATH_MIX_CTL: - case CDC_RX_RX1_RX_PATH_MIX_CFG: - case CDC_RX_RX1_RX_VOL_MIX_CTL: - case CDC_RX_RX1_RX_PATH_SEC1: - case CDC_RX_RX1_RX_PATH_SEC2: - case CDC_RX_RX1_RX_PATH_SEC3: - case CDC_RX_RX1_RX_PATH_SEC4: - case CDC_RX_RX1_RX_PATH_SEC7: - case CDC_RX_RX1_RX_PATH_MIX_SEC0: - case CDC_RX_RX1_RX_PATH_MIX_SEC1: - case CDC_RX_RX1_RX_PATH_DSM_CTL: - case CDC_RX_RX1_RX_PATH_DSM_DATA1: - case CDC_RX_RX1_RX_PATH_DSM_DATA2: - case CDC_RX_RX1_RX_PATH_DSM_DATA3: - case CDC_RX_RX1_RX_PATH_DSM_DATA4: - case CDC_RX_RX1_RX_PATH_DSM_DATA5: - case CDC_RX_RX1_RX_PATH_DSM_DATA6: - case CDC_RX_RX2_RX_PATH_CTL: - case CDC_RX_RX2_RX_PATH_CFG0: - case CDC_RX_RX2_RX_PATH_CFG1: - case CDC_RX_RX2_RX_PATH_CFG2: - case CDC_RX_RX2_RX_PATH_CFG3: - case CDC_RX_RX2_RX_VOL_CTL: - case CDC_RX_RX2_RX_PATH_MIX_CTL: - case CDC_RX_RX2_RX_PATH_MIX_CFG: - case CDC_RX_RX2_RX_VOL_MIX_CTL: - case CDC_RX_RX2_RX_PATH_SEC0: - case CDC_RX_RX2_RX_PATH_SEC1: - case CDC_RX_RX2_RX_PATH_SEC2: - case CDC_RX_RX2_RX_PATH_SEC3: - case CDC_RX_RX2_RX_PATH_SEC4: - case CDC_RX_RX2_RX_PATH_SEC5: - case CDC_RX_RX2_RX_PATH_SEC6: - case CDC_RX_RX2_RX_PATH_SEC7: - case CDC_RX_RX2_RX_PATH_MIX_SEC0: - case CDC_RX_RX2_RX_PATH_MIX_SEC1: - case CDC_RX_RX2_RX_PATH_DSM_CTL: case CDC_RX_IDLE_DETECT_PATH_CTL: case CDC_RX_IDLE_DETECT_CFG0: case CDC_RX_IDLE_DETECT_CFG1: @@ -1435,6 +1455,16 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg) return true; } + switch (rx->codec_version) { + case LPASS_CODEC_VERSION_1_0: + case LPASS_CODEC_VERSION_1_1: + case LPASS_CODEC_VERSION_1_2: + case LPASS_CODEC_VERSION_2_0: + return rx_pre_2_5_is_rw_register(dev, reg); + default: + break; + } + return false; } @@ -1485,14 +1515,12 @@ static bool rx_is_readable_register(struct device *dev, unsigned int reg) return rx_is_rw_register(dev, reg); } -static const struct regmap_config rx_regmap_config = { +static struct regmap_config rx_regmap_config = { .name = "rx_macro", .reg_bits = 16, .val_bits = 32, /* 8 but with 32 bit read/write */ .reg_stride = 4, .cache_type = REGCACHE_FLAT, - .reg_defaults = rx_defaults, - .num_reg_defaults = ARRAY_SIZE(rx_defaults), .max_register = RX_MAX_OFFSET, .writeable_reg = rx_is_writeable_register, .volatile_reg = rx_is_volatile_register, @@ -1504,16 +1532,17 @@ static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, { struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol); struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm); + struct rx_macro *rx = snd_soc_component_get_drvdata(component); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short look_ahead_dly_reg; unsigned int val; val = ucontrol->value.enumerated.item[0]; - if (e->reg == CDC_RX_RX0_RX_PATH_CFG1) - look_ahead_dly_reg = CDC_RX_RX0_RX_PATH_CFG0; - else if (e->reg == CDC_RX_RX1_RX_PATH_CFG1) - look_ahead_dly_reg = CDC_RX_RX1_RX_PATH_CFG0; + if (e->reg == CDC_RX_RXn_RX_PATH_CFG1(rx, 0)) + look_ahead_dly_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 0); + else if (e->reg == CDC_RX_RXn_RX_PATH_CFG1(rx, 1)) + look_ahead_dly_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 1); /* Set Look Ahead Delay */ if (val) @@ -1567,7 +1596,7 @@ static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) { - int_fs_reg = CDC_RX_RXn_RX_PATH_CTL(j); + int_fs_reg = CDC_RX_RXn_RX_PATH_CTL(rx, j); /* sample_rate is in Hz */ snd_soc_component_update_bits(component, int_fs_reg, CDC_RX_PATH_PCM_RATE_MASK, @@ -1600,7 +1629,7 @@ static int rx_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai, CDC_RX_INTX_2_SEL_MASK); if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) { - int_fs_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j); + int_fs_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, j); snd_soc_component_update_bits(component, int_fs_reg, CDC_RX_RXn_MIX_PCM_RATE_MASK, rate_reg_val); @@ -1719,6 +1748,7 @@ static int rx_macro_get_channel_map(struct snd_soc_dai *dai, static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_component *component = dai->component; + struct rx_macro *rx = snd_soc_component_get_drvdata(component); uint16_t j, reg, mix_reg, dsm_reg; u16 int_mux_cfg0, int_mux_cfg1; u8 int_mux_cfg0_val, int_mux_cfg1_val; @@ -1729,9 +1759,9 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) case RX_MACRO_AIF3_PB: case RX_MACRO_AIF4_PB: for (j = 0; j < INTERP_MAX; j++) { - reg = CDC_RX_RXn_RX_PATH_CTL(j); - mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j); - dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(j); + reg = CDC_RX_RXn_RX_PATH_CTL(rx, j); + mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, j); + dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, j); if (mute) { snd_soc_component_update_bits(component, reg, @@ -1748,7 +1778,7 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) } if (j == INTERP_AUX) - dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL; + dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, 2); int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8; int_mux_cfg1 = int_mux_cfg0 + 4; @@ -1956,10 +1986,11 @@ static int rx_macro_enable_main_path(struct snd_soc_dapm_widget *w, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rx_macro *rx = snd_soc_component_get_drvdata(component); u16 gain_reg, reg; - reg = CDC_RX_RXn_RX_PATH_CTL(w->shift); - gain_reg = CDC_RX_RXn_RX_VOL_CTL(w->shift); + reg = CDC_RX_RXn_RX_PATH_CTL(rx, w->shift); + gain_reg = CDC_RX_RXn_RX_VOL_CTL(rx, w->shift); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1991,7 +2022,7 @@ static int rx_macro_config_compander(struct snd_soc_component *component, if (comp == INTERP_AUX) return 0; - pcm_rate = snd_soc_component_read(component, CDC_RX_RXn_RX_PATH_CTL(comp)) & 0x0F; + pcm_rate = snd_soc_component_read(component, CDC_RX_RXn_RX_PATH_CTL(rx, comp)) & 0x0F; if (pcm_rate < 0x06) val = 0x03; else if (pcm_rate < 0x08) @@ -2002,11 +2033,11 @@ static int rx_macro_config_compander(struct snd_soc_component *component, val = 0x00; if (SND_SOC_DAPM_EVENT_ON(event)) - snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(comp), + snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, comp), CDC_RX_DC_COEFF_SEL_MASK, val); if (SND_SOC_DAPM_EVENT_OFF(event)) - snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(comp), + snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, comp), CDC_RX_DC_COEFF_SEL_MASK, 0x3); if (!rx->comp_enabled[comp]) return 0; @@ -2019,14 +2050,14 @@ static int rx_macro_config_compander(struct snd_soc_component *component, CDC_RX_COMPANDERn_SOFT_RST_MASK, 0x1); snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp), CDC_RX_COMPANDERn_SOFT_RST_MASK, 0x0); - snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(comp), + snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(rx, comp), CDC_RX_RXn_COMP_EN_MASK, 0x1); } if (SND_SOC_DAPM_EVENT_OFF(event)) { snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp), CDC_RX_COMPANDERn_HALT_MASK, 0x1); - snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(comp), + snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(rx, comp), CDC_RX_RXn_COMP_EN_MASK, 0x0); snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp), CDC_RX_COMPANDERn_CLK_EN_MASK, 0x0); @@ -2125,13 +2156,13 @@ static int rx_macro_config_aux_hpf(struct snd_soc_component *component, /* Update Aux HPF control */ if (!rx->is_aux_hpf_on) snd_soc_component_update_bits(component, - CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x00); + CDC_RX_RXn_RX_PATH_CFG1(rx, 2), 0x04, 0x00); } if (SND_SOC_DAPM_EVENT_OFF(event)) { /* Reset to default (HPF=ON) */ snd_soc_component_update_bits(component, - CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x04); + CDC_RX_RXn_RX_PATH_CFG1(rx, 2), 0x04, 0x04); } return 0; @@ -2183,7 +2214,7 @@ static int rx_macro_config_classh(struct snd_soc_component *component, CDC_RX_CLSH_DECAY_CTRL, CDC_RX_CLSH_DECAY_RATE_MASK, 0x0); snd_soc_component_write_field(component, - CDC_RX_RX0_RX_PATH_CFG0, + CDC_RX_RXn_RX_PATH_CFG0(rx, 0), CDC_RX_RXn_CLSH_EN_MASK, 0x1); break; case INTERP_HPHR: @@ -2199,15 +2230,15 @@ static int rx_macro_config_classh(struct snd_soc_component *component, CDC_RX_CLSH_DECAY_CTRL, CDC_RX_CLSH_DECAY_RATE_MASK, 0x0); snd_soc_component_write_field(component, - CDC_RX_RX1_RX_PATH_CFG0, + CDC_RX_RXn_RX_PATH_CFG0(rx, 1), CDC_RX_RXn_CLSH_EN_MASK, 0x1); break; case INTERP_AUX: snd_soc_component_update_bits(component, - CDC_RX_RX2_RX_PATH_CFG0, + CDC_RX_RXn_RX_PATH_CFG0(rx, 2), CDC_RX_RX2_DLY_Z_EN_MASK, 1); snd_soc_component_write_field(component, - CDC_RX_RX2_RX_PATH_CFG0, + CDC_RX_RXn_RX_PATH_CFG0(rx, 2), CDC_RX_RX2_CLSH_EN_MASK, 1); break; } @@ -2218,16 +2249,17 @@ static int rx_macro_config_classh(struct snd_soc_component *component, static void rx_macro_hd2_control(struct snd_soc_component *component, u16 interp_idx, int event) { + struct rx_macro *rx = snd_soc_component_get_drvdata(component); u16 hd2_scale_reg, hd2_enable_reg; switch (interp_idx) { case INTERP_HPHL: - hd2_scale_reg = CDC_RX_RX0_RX_PATH_SEC3; - hd2_enable_reg = CDC_RX_RX0_RX_PATH_CFG0; + hd2_scale_reg = CDC_RX_RXn_RX_PATH_SEC3(rx, 0); + hd2_enable_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 0); break; case INTERP_HPHR: - hd2_scale_reg = CDC_RX_RX1_RX_PATH_SEC3; - hd2_enable_reg = CDC_RX_RX1_RX_PATH_CFG0; + hd2_scale_reg = CDC_RX_RXn_RX_PATH_SEC3(rx, 1); + hd2_enable_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 1); break; } @@ -2482,7 +2514,7 @@ static int rx_macro_hphdelay_lutbypass(struct snd_soc_component *component, if (interp_idx == INTERP_HPHL) { if (rx->is_ear_mode_on) snd_soc_component_write_field(component, - CDC_RX_RX0_RX_PATH_CFG1, + CDC_RX_RXn_RX_PATH_CFG1(rx, 0), CDC_RX_RX0_HPH_L_EAR_SEL_MASK, 0x1); else snd_soc_component_write_field(component, @@ -2499,7 +2531,7 @@ static int rx_macro_hphdelay_lutbypass(struct snd_soc_component *component, if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) { snd_soc_component_write_field(component, - CDC_RX_RX0_RX_PATH_CFG1, + CDC_RX_RXn_RX_PATH_CFG1(rx, 0), CDC_RX_RX0_HPH_L_EAR_SEL_MASK, 0x0); snd_soc_component_update_bits(component, hph_lut_bypass_reg, CDC_RX_TOP_HPH_LUT_BYPASS_MASK, 0); @@ -2516,11 +2548,12 @@ static int rx_macro_enable_interp_clk(struct snd_soc_component *component, u16 main_reg, dsm_reg, rx_cfg2_reg; struct rx_macro *rx = snd_soc_component_get_drvdata(component); - main_reg = CDC_RX_RXn_RX_PATH_CTL(interp_idx); - dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(interp_idx); + main_reg = CDC_RX_RXn_RX_PATH_CTL(rx, interp_idx); + dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, interp_idx); if (interp_idx == INTERP_AUX) - dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL; - rx_cfg2_reg = CDC_RX_RXn_RX_PATH_CFG2(interp_idx); + dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, 2); + + rx_cfg2_reg = CDC_RX_RXn_RX_PATH_CFG2(rx, interp_idx); if (SND_SOC_DAPM_EVENT_ON(event)) { if (rx->main_clk_users[interp_idx] == 0) { @@ -2587,10 +2620,11 @@ static int rx_macro_enable_mix_path(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 rx_macro *rx = snd_soc_component_get_drvdata(component); u16 gain_reg, mix_reg; - gain_reg = CDC_RX_RXn_RX_VOL_MIX_CTL(w->shift); - mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(w->shift); + gain_reg = CDC_RX_RXn_RX_VOL_MIX_CTL(rx, w->shift); + mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, w->shift); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -2621,17 +2655,18 @@ static int rx_macro_enable_rx_path_clk(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 rx_macro *rx = snd_soc_component_get_drvdata(component); switch (event) { case SND_SOC_DAPM_PRE_PMU: rx_macro_enable_interp_clk(component, event, w->shift); - snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(w->shift), + snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(rx, w->shift), CDC_RX_RXn_SIDETONE_EN_MASK, 1); - snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CTL(w->shift), + snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CTL(rx, w->shift), CDC_RX_PATH_CLK_EN_MASK, 1); break; case SND_SOC_DAPM_POST_PMD: - snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(w->shift), + snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(rx, w->shift), CDC_RX_RXn_SIDETONE_EN_MASK, 0); rx_macro_enable_interp_clk(component, event, w->shift); break; @@ -2801,20 +2836,22 @@ static int rx_macro_iir_filter_info(struct snd_kcontrol *kcontrol, return 0; } -static const struct snd_kcontrol_new rx_macro_snd_controls[] = { - SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", CDC_RX_RX0_RX_VOL_CTL, - -84, 40, digital_gain), +static const struct snd_kcontrol_new rx_macro_def_snd_controls[] = { SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", CDC_RX_RX1_RX_VOL_CTL, -84, 40, digital_gain), SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", CDC_RX_RX2_RX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", CDC_RX_RX0_RX_VOL_MIX_CTL, - -84, 40, digital_gain), SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", CDC_RX_RX1_RX_VOL_MIX_CTL, -84, 40, digital_gain), SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", CDC_RX_RX2_RX_VOL_MIX_CTL, -84, 40, digital_gain), +}; +static const struct snd_kcontrol_new rx_macro_snd_controls[] = { + SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", CDC_RX_RX0_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", CDC_RX_RX0_RX_VOL_MIX_CTL, + -84, 40, digital_gain), SOC_SINGLE_EXT("RX_COMP1 Switch", SND_SOC_NOPM, RX_MACRO_COMP1, 1, 0, rx_macro_get_compander, rx_macro_set_compander), SOC_SINGLE_EXT("RX_COMP2 Switch", SND_SOC_NOPM, RX_MACRO_COMP2, 1, 0, @@ -2931,6 +2968,10 @@ static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w, return 0; } +static const struct snd_soc_dapm_widget rx_macro_def_dapm_widgets[] = { + SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int1_dem_inp_mux), +}; static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("RX AIF1 PB", "RX_MACRO_AIF1 Playback", 0, @@ -3003,8 +3044,6 @@ static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = { SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0, &rx_int0_dem_inp_mux), - SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0, - &rx_int1_dem_inp_mux), SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0, &rx_int0_2_mux, rx_macro_enable_mix_path, @@ -3399,32 +3438,55 @@ static const struct snd_soc_dapm_route rx_audio_map[] = { static int rx_macro_component_probe(struct snd_soc_component *component) { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rx_macro *rx = snd_soc_component_get_drvdata(component); + const struct snd_soc_dapm_widget *widgets; + const struct snd_kcontrol_new *controls; + unsigned int num_controls; + int ret, num_widgets; snd_soc_component_init_regmap(component, rx->regmap); - snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_SEC7, + snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 0), CDC_RX_DSM_OUT_DELAY_SEL_MASK, CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE); - snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_SEC7, + snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 1), CDC_RX_DSM_OUT_DELAY_SEL_MASK, CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE); - snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_SEC7, + snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 2), CDC_RX_DSM_OUT_DELAY_SEL_MASK, CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE); - snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_CFG3, + snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 0), CDC_RX_DC_COEFF_SEL_MASK, CDC_RX_DC_COEFF_SEL_TWO); - snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_CFG3, + snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 1), CDC_RX_DC_COEFF_SEL_MASK, CDC_RX_DC_COEFF_SEL_TWO); - snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_CFG3, + snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 2), CDC_RX_DC_COEFF_SEL_MASK, CDC_RX_DC_COEFF_SEL_TWO); + switch (rx->codec_version) { + case LPASS_CODEC_VERSION_1_0: + case LPASS_CODEC_VERSION_1_1: + case LPASS_CODEC_VERSION_1_2: + case LPASS_CODEC_VERSION_2_0: + controls = rx_macro_def_snd_controls; + num_controls = ARRAY_SIZE(rx_macro_def_snd_controls); + widgets = rx_macro_def_dapm_widgets; + num_widgets = ARRAY_SIZE(rx_macro_def_dapm_widgets); + break; + default: + return -EINVAL; + } + rx->component = component; - return 0; + ret = snd_soc_add_component_controls(component, controls, num_controls); + if (ret) + return ret; + + return snd_soc_dapm_new_controls(dapm, widgets, num_widgets); } static int swclk_gate_enable(struct clk_hw *hw) @@ -3523,11 +3585,12 @@ static const struct snd_soc_component_driver rx_macro_component_drv = { static int rx_macro_probe(struct platform_device *pdev) { + struct reg_default *reg_defaults; struct device *dev = &pdev->dev; kernel_ulong_t flags; struct rx_macro *rx; void __iomem *base; - int ret; + int ret, def_count; flags = (kernel_ulong_t)device_get_match_data(dev); @@ -3566,11 +3629,36 @@ static int rx_macro_probe(struct platform_device *pdev) ret = PTR_ERR(base); goto err; } + rx->codec_version = lpass_macro_get_codec_version(); + switch (rx->codec_version) { + case LPASS_CODEC_VERSION_1_0: + case LPASS_CODEC_VERSION_1_1: + case LPASS_CODEC_VERSION_1_2: + case LPASS_CODEC_VERSION_2_0: + rx->rxn_reg_stride = 0x80; + def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_pre_2_5_defaults); + reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL); + if (!reg_defaults) { + ret = -ENOMEM; + goto err; + } + memcpy(®_defaults[0], rx_defaults, sizeof(rx_defaults)); + memcpy(®_defaults[ARRAY_SIZE(rx_defaults)], + rx_pre_2_5_defaults, sizeof(rx_pre_2_5_defaults)); + break; + default: + dev_err(rx->dev, "Unsupported Codec version (%d)\n", rx->codec_version); + ret = -EINVAL; + goto err; + } + + rx_regmap_config.reg_defaults = reg_defaults; + rx_regmap_config.num_reg_defaults = def_count; rx->regmap = devm_regmap_init_mmio(dev, base, &rx_regmap_config); if (IS_ERR(rx->regmap)) { ret = PTR_ERR(rx->regmap); - goto err; + goto err_ver; } dev_set_drvdata(dev, rx); @@ -3583,7 +3671,7 @@ static int rx_macro_probe(struct platform_device *pdev) ret = clk_prepare_enable(rx->macro); if (ret) - goto err; + goto err_ver; ret = clk_prepare_enable(rx->dcodec); if (ret) @@ -3629,6 +3717,7 @@ static int rx_macro_probe(struct platform_device *pdev) if (ret) goto err_clkout; + kfree(reg_defaults); return 0; err_clkout: @@ -3641,6 +3730,8 @@ err_mclk: clk_disable_unprepare(rx->dcodec); err_dcodec: clk_disable_unprepare(rx->macro); +err_ver: + kfree(reg_defaults); err: lpass_macro_pds_exit(rx->pds); From 432e5074f805d0f976c7430af376a0dd07f1c6d7 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 13 Jun 2024 11:49:33 +0100 Subject: [PATCH 106/349] ASoC: codec: lpass-rx-macro: add support for 2.5 codec version LPASS Codec v2.5 has significant changes in the rx register strides. Due to this headset playback on SM8550, SM8650, x1e80100 and all SoCs after SM8450 have only Left working. This patch adjusts the registers to accomdate 2.5 changes. With this fixed now L and R are functional on Headset playback. Signed-off-by: Srinivas Kandagatla Tested-by: Krzysztof Kozlowski Tested-by: Neil Armstrong # on SM8650-HDK Link: https://lore.kernel.org/r/20240612-lpass-codec-v25-v4-3-f63d3676dbc4@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 198 ++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 360c9003a890..d962a9599694 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -262,6 +262,53 @@ #define CDC_RX_RX2_RX_PATH_MIX_SEC0 (0x0544) #define CDC_RX_RX2_RX_PATH_MIX_SEC1 (0x0548) #define CDC_RX_RX2_RX_PATH_DSM_CTL (0x054C) + +/* LPASS CODEC version 2.5 rx reg offsets */ +#define CDC_2_5_RX_RX1_RX_PATH_CTL (0x04c0) +#define CDC_2_5_RX_RX1_RX_PATH_CFG0 (0x04c4) +#define CDC_2_5_RX_RX1_RX_PATH_CFG1 (0x04c8) +#define CDC_2_5_RX_RX1_RX_PATH_CFG2 (0x04cC) +#define CDC_2_5_RX_RX1_RX_PATH_CFG3 (0x04d0) +#define CDC_2_5_RX_RX1_RX_VOL_CTL (0x04d4) +#define CDC_2_5_RX_RX1_RX_PATH_MIX_CTL (0x04d8) +#define CDC_2_5_RX_RX1_RX_PATH_MIX_CFG (0x04dC) +#define CDC_2_5_RX_RX1_RX_VOL_MIX_CTL (0x04e0) +#define CDC_2_5_RX_RX1_RX_PATH_SEC1 (0x04e4) +#define CDC_2_5_RX_RX1_RX_PATH_SEC2 (0x04e8) +#define CDC_2_5_RX_RX1_RX_PATH_SEC3 (0x04eC) +#define CDC_2_5_RX_RX1_RX_PATH_SEC4 (0x04f0) +#define CDC_2_5_RX_RX1_RX_PATH_SEC7 (0x04f4) +#define CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0 (0x04f8) +#define CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1 (0x04fC) +#define CDC_2_5_RX_RX1_RX_PATH_DSM_CTL (0x0500) +#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1 (0x0504) +#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2 (0x0508) +#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3 (0x050C) +#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4 (0x0510) +#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5 (0x0514) +#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6 (0x0518) + +#define CDC_2_5_RX_RX2_RX_PATH_CTL (0x0580) +#define CDC_2_5_RX_RX2_RX_PATH_CFG0 (0x0584) +#define CDC_2_5_RX_RX2_RX_PATH_CFG1 (0x0588) +#define CDC_2_5_RX_RX2_RX_PATH_CFG2 (0x058C) +#define CDC_2_5_RX_RX2_RX_PATH_CFG3 (0x0590) +#define CDC_2_5_RX_RX2_RX_VOL_CTL (0x0594) +#define CDC_2_5_RX_RX2_RX_PATH_MIX_CTL (0x0598) +#define CDC_2_5_RX_RX2_RX_PATH_MIX_CFG (0x059C) +#define CDC_2_5_RX_RX2_RX_VOL_MIX_CTL (0x05a0) +#define CDC_2_5_RX_RX2_RX_PATH_SEC0 (0x05a4) +#define CDC_2_5_RX_RX2_RX_PATH_SEC1 (0x05a8) +#define CDC_2_5_RX_RX2_RX_PATH_SEC2 (0x05aC) +#define CDC_2_5_RX_RX2_RX_PATH_SEC3 (0x05b0) +#define CDC_2_5_RX_RX2_RX_PATH_SEC4 (0x05b4) +#define CDC_2_5_RX_RX2_RX_PATH_SEC5 (0x05b8) +#define CDC_2_5_RX_RX2_RX_PATH_SEC6 (0x05bC) +#define CDC_2_5_RX_RX2_RX_PATH_SEC7 (0x05c0) +#define CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0 (0x05c4) +#define CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1 (0x05c8) +#define CDC_2_5_RX_RX2_RX_PATH_DSM_CTL (0x05cC) + #define CDC_RX_IDLE_DETECT_PATH_CTL (0x0780) #define CDC_RX_IDLE_DETECT_CFG0 (0x0784) #define CDC_RX_IDLE_DETECT_CFG1 (0x0788) @@ -764,6 +811,8 @@ static SOC_ENUM_SINGLE_DECL(rx_int0_dem_inp_enum, CDC_RX_RX0_RX_PATH_CFG1, 0, rx_int_dem_inp_mux_text); static SOC_ENUM_SINGLE_DECL(rx_int1_dem_inp_enum, CDC_RX_RX1_RX_PATH_CFG1, 0, rx_int_dem_inp_mux_text); +static SOC_ENUM_SINGLE_DECL(rx_2_5_int1_dem_inp_enum, CDC_2_5_RX_RX1_RX_PATH_CFG1, 0, + rx_int_dem_inp_mux_text); static SOC_ENUM_SINGLE_DECL(rx_macro_rx0_enum, SND_SOC_NOPM, 0, rx_macro_mux_text); static SOC_ENUM_SINGLE_DECL(rx_macro_rx1_enum, SND_SOC_NOPM, 0, rx_macro_mux_text); @@ -1083,6 +1132,52 @@ static const struct reg_default rx_defaults[] = { { CDC_RX_DSD1_CFG2, 0x96 }, }; +static const struct reg_default rx_2_5_defaults[] = { + { CDC_2_5_RX_RX1_RX_PATH_CTL, 0x04 }, + { CDC_2_5_RX_RX1_RX_PATH_CFG0, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_CFG1, 0x64 }, + { CDC_2_5_RX_RX1_RX_PATH_CFG2, 0x8F }, + { CDC_2_5_RX_RX1_RX_PATH_CFG3, 0x00 }, + { CDC_2_5_RX_RX1_RX_VOL_CTL, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_MIX_CTL, 0x04 }, + { CDC_2_5_RX_RX1_RX_PATH_MIX_CFG, 0x7E }, + { CDC_2_5_RX_RX1_RX_VOL_MIX_CTL, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_SEC1, 0x08 }, + { CDC_2_5_RX_RX1_RX_PATH_SEC2, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_SEC3, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_SEC4, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_SEC7, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0, 0x08 }, + { CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_DSM_CTL, 0x08 }, + { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3, 0x00 }, + { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4, 0x55 }, + { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5, 0x55 }, + { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6, 0x55 }, + { CDC_2_5_RX_RX2_RX_PATH_CTL, 0x04 }, + { CDC_2_5_RX_RX2_RX_PATH_CFG0, 0x00 }, + { CDC_2_5_RX_RX2_RX_PATH_CFG1, 0x64 }, + { CDC_2_5_RX_RX2_RX_PATH_CFG2, 0x8F }, + { CDC_2_5_RX_RX2_RX_PATH_CFG3, 0x00 }, + { CDC_2_5_RX_RX2_RX_VOL_CTL, 0x00 }, + { CDC_2_5_RX_RX2_RX_PATH_MIX_CTL, 0x04 }, + { CDC_2_5_RX_RX2_RX_PATH_MIX_CFG, 0x7E }, + { CDC_2_5_RX_RX2_RX_VOL_MIX_CTL, 0x00 }, + { CDC_2_5_RX_RX2_RX_PATH_SEC0, 0x04 }, + { CDC_2_5_RX_RX2_RX_PATH_SEC1, 0x08 }, + { CDC_2_5_RX_RX2_RX_PATH_SEC2, 0x00 }, + { CDC_2_5_RX_RX2_RX_PATH_SEC3, 0x00 }, + { CDC_2_5_RX_RX2_RX_PATH_SEC4, 0x00 }, + { CDC_2_5_RX_RX2_RX_PATH_SEC5, 0x00 }, + { CDC_2_5_RX_RX2_RX_PATH_SEC6, 0x00 }, + { CDC_2_5_RX_RX2_RX_PATH_SEC7, 0x00 }, + { CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0, 0x08 }, + { CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1, 0x00 }, + { CDC_2_5_RX_RX2_RX_PATH_DSM_CTL, 0x00 }, +}; + static const struct reg_default rx_pre_2_5_defaults[] = { { CDC_RX_RX1_RX_PATH_CTL, 0x04 }, { CDC_RX_RX1_RX_PATH_CFG0, 0x00 }, @@ -1236,6 +1331,58 @@ static bool rx_pre_2_5_is_rw_register(struct device *dev, unsigned int reg) return false; } +static bool rx_2_5_is_rw_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_2_5_RX_RX1_RX_PATH_CTL: + case CDC_2_5_RX_RX1_RX_PATH_CFG0: + case CDC_2_5_RX_RX1_RX_PATH_CFG1: + case CDC_2_5_RX_RX1_RX_PATH_CFG2: + case CDC_2_5_RX_RX1_RX_PATH_CFG3: + case CDC_2_5_RX_RX1_RX_VOL_CTL: + case CDC_2_5_RX_RX1_RX_PATH_MIX_CTL: + case CDC_2_5_RX_RX1_RX_PATH_MIX_CFG: + case CDC_2_5_RX_RX1_RX_VOL_MIX_CTL: + case CDC_2_5_RX_RX1_RX_PATH_SEC1: + case CDC_2_5_RX_RX1_RX_PATH_SEC2: + case CDC_2_5_RX_RX1_RX_PATH_SEC3: + case CDC_2_5_RX_RX1_RX_PATH_SEC4: + case CDC_2_5_RX_RX1_RX_PATH_SEC7: + case CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0: + case CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1: + case CDC_2_5_RX_RX1_RX_PATH_DSM_CTL: + case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1: + case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2: + case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3: + case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4: + case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5: + case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6: + case CDC_2_5_RX_RX2_RX_PATH_CTL: + case CDC_2_5_RX_RX2_RX_PATH_CFG0: + case CDC_2_5_RX_RX2_RX_PATH_CFG1: + case CDC_2_5_RX_RX2_RX_PATH_CFG2: + case CDC_2_5_RX_RX2_RX_PATH_CFG3: + case CDC_2_5_RX_RX2_RX_VOL_CTL: + case CDC_2_5_RX_RX2_RX_PATH_MIX_CTL: + case CDC_2_5_RX_RX2_RX_PATH_MIX_CFG: + case CDC_2_5_RX_RX2_RX_VOL_MIX_CTL: + case CDC_2_5_RX_RX2_RX_PATH_SEC0: + case CDC_2_5_RX_RX2_RX_PATH_SEC1: + case CDC_2_5_RX_RX2_RX_PATH_SEC2: + case CDC_2_5_RX_RX2_RX_PATH_SEC3: + case CDC_2_5_RX_RX2_RX_PATH_SEC4: + case CDC_2_5_RX_RX2_RX_PATH_SEC5: + case CDC_2_5_RX_RX2_RX_PATH_SEC6: + case CDC_2_5_RX_RX2_RX_PATH_SEC7: + case CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0: + case CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1: + case CDC_2_5_RX_RX2_RX_PATH_DSM_CTL: + return true; + } + + return false; +} + static bool rx_is_rw_register(struct device *dev, unsigned int reg) { struct rx_macro *rx = dev_get_drvdata(dev); @@ -1461,6 +1608,11 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg) case LPASS_CODEC_VERSION_1_2: case LPASS_CODEC_VERSION_2_0: return rx_pre_2_5_is_rw_register(dev, reg); + case LPASS_CODEC_VERSION_2_5: + case LPASS_CODEC_VERSION_2_6: + case LPASS_CODEC_VERSION_2_7: + case LPASS_CODEC_VERSION_2_8: + return rx_2_5_is_rw_register(dev, reg); default: break; } @@ -1563,6 +1715,10 @@ static const struct snd_kcontrol_new rx_int1_dem_inp_mux = SOC_DAPM_ENUM_EXT("rx_int1_dem_inp", rx_int1_dem_inp_enum, snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put); +static const struct snd_kcontrol_new rx_2_5_int1_dem_inp_mux = + SOC_DAPM_ENUM_EXT("rx_int1_dem_inp", rx_2_5_int1_dem_inp_enum, + snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put); + static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, int rate_reg_val, u32 sample_rate) { @@ -2847,6 +3003,18 @@ static const struct snd_kcontrol_new rx_macro_def_snd_controls[] = { -84, 40, digital_gain), }; +static const struct snd_kcontrol_new rx_macro_2_5_snd_controls[] = { + + SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", CDC_2_5_RX_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", CDC_2_5_RX_RX2_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", CDC_2_5_RX_RX1_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", CDC_2_5_RX_RX2_RX_VOL_MIX_CTL, + -84, 40, digital_gain), +}; + static const struct snd_kcontrol_new rx_macro_snd_controls[] = { SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", CDC_RX_RX0_RX_VOL_CTL, -84, 40, digital_gain), @@ -2968,6 +3136,12 @@ static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w, return 0; } + +static const struct snd_soc_dapm_widget rx_macro_2_5_dapm_widgets[] = { + SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_2_5_int1_dem_inp_mux), +}; + static const struct snd_soc_dapm_widget rx_macro_def_dapm_widgets[] = { SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0, &rx_int1_dem_inp_mux), @@ -3476,6 +3650,15 @@ static int rx_macro_component_probe(struct snd_soc_component *component) widgets = rx_macro_def_dapm_widgets; num_widgets = ARRAY_SIZE(rx_macro_def_dapm_widgets); break; + case LPASS_CODEC_VERSION_2_5: + case LPASS_CODEC_VERSION_2_6: + case LPASS_CODEC_VERSION_2_7: + case LPASS_CODEC_VERSION_2_8: + controls = rx_macro_2_5_snd_controls; + num_controls = ARRAY_SIZE(rx_macro_2_5_snd_controls); + widgets = rx_macro_2_5_dapm_widgets; + num_widgets = ARRAY_SIZE(rx_macro_2_5_dapm_widgets); + break; default: return -EINVAL; } @@ -3646,6 +3829,21 @@ static int rx_macro_probe(struct platform_device *pdev) memcpy(®_defaults[ARRAY_SIZE(rx_defaults)], rx_pre_2_5_defaults, sizeof(rx_pre_2_5_defaults)); break; + case LPASS_CODEC_VERSION_2_5: + case LPASS_CODEC_VERSION_2_6: + case LPASS_CODEC_VERSION_2_7: + case LPASS_CODEC_VERSION_2_8: + rx->rxn_reg_stride = 0xc0; + def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_2_5_defaults); + reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL); + if (!reg_defaults) { + ret = -ENOMEM; + goto err; + } + memcpy(®_defaults[0], rx_defaults, sizeof(rx_defaults)); + memcpy(®_defaults[ARRAY_SIZE(rx_defaults)], + rx_2_5_defaults, sizeof(rx_2_5_defaults)); + break; default: dev_err(rx->dev, "Unsupported Codec version (%d)\n", rx->codec_version); ret = -EINVAL; From 39eab0148752055928c4c54db12d6cf89881e6cd Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 16 Jun 2024 20:52:26 -0700 Subject: [PATCH 107/349] ASoC: fsl: imx-pcm-fiq: add missing MODULE_DESCRIPTION() macro With ARCH=arm, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in sound/soc/fsl/imx-pcm-fiq.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://msgid.link/r/20240616-md-arm-sound-soc-fsl-v2-1-228772e81a54@quicinc.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-fiq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 0d124002678e..3391430e4253 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -319,4 +319,5 @@ void imx_pcm_fiq_exit(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit); +MODULE_DESCRIPTION("Freescale i.MX PCM FIQ handler"); MODULE_LICENSE("GPL"); From 20346f5c7bc9f83c74b5efed163ae4e2ea7616a9 Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Sun, 16 Jun 2024 13:19:30 +0530 Subject: [PATCH 108/349] ASoC: dt-bindings: realtek,rt5631: Convert to dtschema Convert the ALC5631/RT5631 audio CODEC bindings to DT Schema. Signed-off-by: Animesh Agarwal Cc: Daniel Baluta Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240616074936.151267-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/realtek,rt5631.yaml | 67 +++++++++++++++++++ .../devicetree/bindings/sound/rt5631.txt | 48 ------------- 2 files changed, 67 insertions(+), 48 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/realtek,rt5631.yaml delete mode 100644 Documentation/devicetree/bindings/sound/rt5631.txt diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5631.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5631.yaml new file mode 100644 index 000000000000..747a731c44c9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,rt5631.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,rt5631.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ALC5631/RT5631 audio CODEC + +maintainers: + - Animesh Agarwal + +description: | + This device supports I2C only. + + Pins on the device (for linking into audio routes): + * SPK_OUT_R_P + * SPK_OUT_R_N + * SPK_OUT_L_P + * SPK_OUT_L_N + * HP_OUT_L + * HP_OUT_R + * AUX_OUT2_LP + * AUX_OUT2_RN + * AUX_OUT1_LP + * AUX_OUT1_RN + * AUX_IN_L_JD + * AUX_IN_R_JD + * MONO_IN_P + * MONO_IN_N + * MIC1_P + * MIC1_N + * MIC2_P + * MIC2_N + * MONO_OUT_P + * MONO_OUT_N + * MICBIAS1 + * MICBIAS2 + +properties: + compatible: + enum: + - realtek,alc5631 + - realtek,rt5631 + + reg: + maxItems: 1 + + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@1a { + compatible = "realtek,alc5631"; + reg = <0x1a>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/rt5631.txt b/Documentation/devicetree/bindings/sound/rt5631.txt deleted file mode 100644 index 56bc85232c49..000000000000 --- a/Documentation/devicetree/bindings/sound/rt5631.txt +++ /dev/null @@ -1,48 +0,0 @@ -ALC5631/RT5631 audio CODEC - -This device supports I2C only. - -Required properties: - - - compatible : "realtek,alc5631" or "realtek,rt5631" - - - reg : the I2C address of the device. - -Pins on the device (for linking into audio routes): - - * SPK_OUT_R_P - * SPK_OUT_R_N - * SPK_OUT_L_P - * SPK_OUT_L_N - * HP_OUT_L - * HP_OUT_R - * AUX_OUT2_LP - * AUX_OUT2_RN - * AUX_OUT1_LP - * AUX_OUT1_RN - * AUX_IN_L_JD - * AUX_IN_R_JD - * MONO_IN_P - * MONO_IN_N - * MIC1_P - * MIC1_N - * MIC2_P - * MIC2_N - * MONO_OUT_P - * MONO_OUT_N - * MICBIAS1 - * MICBIAS2 - -Example: - -alc5631: audio-codec@1a { - compatible = "realtek,alc5631"; - reg = <0x1a>; -}; - -or - -rt5631: audio-codec@1a { - compatible = "realtek,rt5631"; - reg = <0x1a>; -}; From 2618b2ec8d140951588e4b4c8dd745676427d2cb Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Sun, 16 Jun 2024 15:22:19 +0530 Subject: [PATCH 109/349] ASoC: dt-bindings: realtek,rt5514: Convert to dtschema Convert the RT5514 audio CODEC bindings to DT Schema. Make bindings complete by adding 'spi-max-frequency', 'wakeup-source' properties. Signed-off-by: Animesh Agarwal Cc: Daniel Baluta Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240616095223.260786-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/realtek,rt5514.yaml | 70 +++++++++++++++++++ .../devicetree/bindings/sound/rt5514.txt | 37 ---------- 2 files changed, 70 insertions(+), 37 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/realtek,rt5514.yaml delete mode 100644 Documentation/devicetree/bindings/sound/rt5514.txt diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5514.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5514.yaml new file mode 100644 index 000000000000..7fbf7739c371 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,rt5514.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,rt5514.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RT5514 audio CODEC + +maintainers: + - Animesh Agarwal + +description: | + This device supports both I2C and SPI. + + Pins on the device (for linking into audio routes) for I2C: + * DMIC1L + * DMIC1R + * DMIC2L + * DMIC2R + * AMICL + * AMICR + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + - $ref: dai-common.yaml# + +properties: + compatible: + const: realtek,rt5514 + + reg: + maxItems: 1 + + clocks: + items: + - description: Master clock to the CODEC + + clock-names: + items: + - const: mclk + + interrupts: + maxItems: 1 + description: The interrupt number to the cpu. + + realtek,dmic-init-delay-ms: + description: Set the DMIC initial delay (ms) to wait it ready for I2C. + + spi-max-frequency: true + + wakeup-source: + type: boolean + description: Flag to indicate this device can wake system (suspend/resume). + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@57 { + compatible = "realtek,rt5514"; + reg = <0x57>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/rt5514.txt b/Documentation/devicetree/bindings/sound/rt5514.txt deleted file mode 100644 index d2cc171f22f2..000000000000 --- a/Documentation/devicetree/bindings/sound/rt5514.txt +++ /dev/null @@ -1,37 +0,0 @@ -RT5514 audio CODEC - -This device supports both I2C and SPI. - -Required properties: - -- compatible : "realtek,rt5514". - -- reg : the I2C address of the device for I2C, the chip select - number for SPI. - -Optional properties: - -- clocks: The phandle of the master clock to the CODEC -- clock-names: Should be "mclk" - -- interrupts: The interrupt number to the cpu. The interrupt specifier format - depends on the interrupt controller. - -- realtek,dmic-init-delay-ms - Set the DMIC initial delay (ms) to wait it ready for I2C. - -Pins on the device (for linking into audio routes) for I2C: - - * DMIC1L - * DMIC1R - * DMIC2L - * DMIC2R - * AMICL - * AMICR - -Example: - -rt5514: codec@57 { - compatible = "realtek,rt5514"; - reg = <0x57>; -}; From 1c75adb22d49ca9389333ca5e6939052a7203111 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 13 Jun 2024 22:59:09 +0200 Subject: [PATCH 110/349] ASoC: SOF: mediatek: Constify struct mtk_adsp_ipc_ops 'struct mtk_adsp_ipc_ops' is not modified in these drivers. Constifying this structure moves some data to a read-only section, so increase overall security. In order to do it, "struct mtk_adsp_ipc" also needs to be adjusted to this new const qualifier. On a x86_64, with allmodconfig: Before: ====== text data bss dec hex filename 15533 2383 0 17916 45fc sound/soc/sof/mediatek/mt8195/mt8195.o After: ===== text data bss dec hex filename 15557 2367 0 17924 4604 sound/soc/sof/mediatek/mt8195/mt8195.o Signed-off-by: Christophe JAILLET Link: https://msgid.link/r/a45d6b2b5ec040ea0fc78fca662c2dca3f13a49f.1718312321.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- include/linux/firmware/mediatek/mtk-adsp-ipc.h | 2 +- sound/soc/sof/mediatek/mt8186/mt8186.c | 2 +- sound/soc/sof/mediatek/mt8195/mt8195.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/firmware/mediatek/mtk-adsp-ipc.h b/include/linux/firmware/mediatek/mtk-adsp-ipc.h index 5b1d16fa3f56..6e86799a7dc4 100644 --- a/include/linux/firmware/mediatek/mtk-adsp-ipc.h +++ b/include/linux/firmware/mediatek/mtk-adsp-ipc.h @@ -40,7 +40,7 @@ struct mtk_adsp_chan { struct mtk_adsp_ipc { struct mtk_adsp_chan chans[MTK_ADSP_MBOX_NUM]; struct device *dev; - struct mtk_adsp_ipc_ops *ops; + const struct mtk_adsp_ipc_ops *ops; void *private_data; }; diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index bea1b9d9ca28..74522400207e 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -82,7 +82,7 @@ static void mt8186_dsp_handle_request(struct mtk_adsp_ipc *ipc) } } -static struct mtk_adsp_ipc_ops dsp_ops = { +static const struct mtk_adsp_ipc_ops dsp_ops = { .handle_reply = mt8186_dsp_handle_reply, .handle_request = mt8186_dsp_handle_request, }; diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 31dc98d1b1d8..24ae1d4959be 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -82,7 +82,7 @@ static void mt8195_dsp_handle_request(struct mtk_adsp_ipc *ipc) } } -static struct mtk_adsp_ipc_ops dsp_ops = { +static const struct mtk_adsp_ipc_ops dsp_ops = { .handle_reply = mt8195_dsp_handle_reply, .handle_request = mt8195_dsp_handle_request, }; From 195815c2755d70df92f46e6d737cd677db7adeef Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 17 Jun 2024 04:26:38 +0000 Subject: [PATCH 111/349] ASoC: audio-graph-card2: add support for aux devices Add device tree property to define auxiliary devices to be added to Audio Graph Card which is already supported on Simle Card. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/878qz4ry81.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 8eea81888758..be5a4ebfddd4 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -1398,6 +1398,10 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, simple_util_debug_info(priv); + ret = snd_soc_of_parse_aux_devs(card, "aux-devs"); + if (ret < 0) + goto err; + ret = devm_snd_soc_register_card(dev, card); err: devm_kfree(dev, li); From d4a7d067e061c95c6387cf537258082074a4d299 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 14:57:34 +0200 Subject: [PATCH 112/349] ASoC: soc-dai.h: Constify DAI ops auto_selectable_formats The core ASoC code does not modify contents of the 'auto_selectable_formats' array passed in 'struct snd_soc_dai_ops', so make it const for code safety. Reviewed-by: Herve Codina Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617125735.582963-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 15ef268c9845..279223c4ef5e 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -361,7 +361,7 @@ struct snd_soc_dai_ops { * see * snd_soc_dai_get_fmt() */ - u64 *auto_selectable_formats; + const u64 *auto_selectable_formats; int num_auto_selectable_formats; /* probe ordering - for components with runtime dependencies */ From 595265c92668cbdbd9f299c49907734d468c12e9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 14:57:35 +0200 Subject: [PATCH 113/349] ASoC: Constify DAI ops auto_selectable_formats The static arrays passed as 'auto_selectable_formats' are not modified by the drivers nor by the core code, so make it const for code safety. Signed-off-by: Krzysztof Kozlowski Acked-by: Herve Codina Link: https://msgid.link/r/20240617125735.582963-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 2 +- sound/soc/codecs/da7213.c | 2 +- sound/soc/codecs/framer-codec.c | 2 +- sound/soc/codecs/hdmi-codec.c | 2 +- sound/soc/codecs/idt821034.c | 2 +- sound/soc/codecs/pcm3168a.c | 2 +- sound/soc/codecs/peb2466.c | 2 +- sound/soc/generic/test-component.c | 2 +- sound/soc/sh/fsi.c | 2 +- sound/soc/sh/rcar/core.c | 2 +- sound/soc/soc-utils.c | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 73fb35560e51..551738abd1a5 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -753,7 +753,7 @@ static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd, * SND_SOC_DAIFMT_CBC_CFC * SND_SOC_DAIFMT_CBP_CFP */ -static u64 ak4613_dai_formats = +static const u64 ak4613_dai_formats = SND_SOC_POSSIBLE_DAIFMT_I2S | SND_SOC_POSSIBLE_DAIFMT_LEFT_J; diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index a2b328f3b39f..f3ef6fb55304 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1720,7 +1720,7 @@ static int da7213_set_component_pll(struct snd_soc_component *component, * SND_SOC_DAIFMT_CBC_CFC * SND_SOC_DAIFMT_CBP_CFP */ -static u64 da7213_dai_formats = +static const u64 da7213_dai_formats = SND_SOC_POSSIBLE_DAIFMT_I2S | SND_SOC_POSSIBLE_DAIFMT_LEFT_J | SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | diff --git a/sound/soc/codecs/framer-codec.c b/sound/soc/codecs/framer-codec.c index e5fcde9ee308..6f57a3aeecc8 100644 --- a/sound/soc/codecs/framer-codec.c +++ b/sound/soc/codecs/framer-codec.c @@ -238,7 +238,7 @@ static int framer_dai_startup(struct snd_pcm_substream *substream, return 0; } -static u64 framer_dai_formats[] = { +static const u64 framer_dai_formats[] = { SND_SOC_POSSIBLE_DAIFMT_DSP_B, }; diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index d3abb7ce2153..74caae52e127 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -715,7 +715,7 @@ static int hdmi_codec_mute(struct snd_soc_dai *dai, int mute, int direction) * For example, * ${LINUX}/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c */ -static u64 hdmi_codec_formats = +static const u64 hdmi_codec_formats = SND_SOC_POSSIBLE_DAIFMT_NB_NF | SND_SOC_POSSIBLE_DAIFMT_NB_IF | SND_SOC_POSSIBLE_DAIFMT_IB_NF | diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c index 2cc7b9166e69..cb7a68c799f8 100644 --- a/sound/soc/codecs/idt821034.c +++ b/sound/soc/codecs/idt821034.c @@ -860,7 +860,7 @@ static int idt821034_dai_startup(struct snd_pcm_substream *substream, return 0; } -static u64 idt821034_dai_formats[] = { +static const u64 idt821034_dai_formats[] = { SND_SOC_POSSIBLE_DAIFMT_DSP_A | SND_SOC_POSSIBLE_DAIFMT_DSP_B, }; diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 3c0e0fdbfc5c..fac0617ab95b 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -562,7 +562,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return 0; } -static u64 pcm3168a_dai_formats[] = { +static const u64 pcm3168a_dai_formats[] = { /* * Select below from Sound Card, not here * SND_SOC_DAIFMT_CBC_CFC diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c index 5dec69be0acb..76ee7e3f4d9b 100644 --- a/sound/soc/codecs/peb2466.c +++ b/sound/soc/codecs/peb2466.c @@ -814,7 +814,7 @@ static int peb2466_dai_startup(struct snd_pcm_substream *substream, &peb2466_sample_bits_constr); } -static u64 peb2466_dai_formats[] = { +static const u64 peb2466_dai_formats[] = { SND_SOC_POSSIBLE_DAIFMT_DSP_A | SND_SOC_POSSIBLE_DAIFMT_DSP_B, }; diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c index e4967540a2e1..e9e5e235a8a6 100644 --- a/sound/soc/generic/test-component.c +++ b/sound/soc/generic/test-component.c @@ -189,7 +189,7 @@ static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream, return 0; } -static u64 test_dai_formats = +static const u64 test_dai_formats = /* * Select below from Sound Card, not auto * SND_SOC_POSSIBLE_DAIFMT_BP_FP diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 84601ba43b7d..087e379aa3bc 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1713,7 +1713,7 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, * SND_SOC_DAIFMT_CBC_CFC * SND_SOC_DAIFMT_CBP_CFP */ -static u64 fsi_dai_formats = +static const u64 fsi_dai_formats = SND_SOC_POSSIBLE_DAIFMT_I2S | SND_SOC_POSSIBLE_DAIFMT_LEFT_J | SND_SOC_POSSIBLE_DAIFMT_NB_NF | diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 6bc7027ed4db..63b3c8bf0fde 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1061,7 +1061,7 @@ static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream, return rsnd_dai_call(prepare, io, priv); } -static u64 rsnd_soc_dai_formats[] = { +static const u64 rsnd_soc_dai_formats[] = { /* * 1st Priority * diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index d05e712c9518..20135a8359bf 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -163,7 +163,7 @@ static const struct snd_soc_component_driver dummy_codec = { * SND_SOC_POSSIBLE_DAIFMT_CBC_CFP * SND_SOC_POSSIBLE_DAIFMT_CBC_CFC */ -static u64 dummy_dai_formats = +static const u64 dummy_dai_formats = SND_SOC_POSSIBLE_DAIFMT_I2S | SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | SND_SOC_POSSIBLE_DAIFMT_LEFT_J | From 960ccf6eafacaa4fc6b244fb91e736113c3fb715 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Mon, 17 Jun 2024 16:41:02 +0100 Subject: [PATCH 114/349] ALSA: hda: hda_component: Introduce component parent structure In preparation for moving duplicated members from the hda_component structure introduce a parent structure that wraps the array of components. This also allows us to confine the knowledge of the maximum number of entries to the hda_component files and eliminate passing that redundant information around and making direct accesses to the array. Signed-off-by: Simon Trimmer Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/20240617154105.108635-2-simont@opensource.cirrus.com --- sound/pci/hda/hda_component.c | 65 +++++++++++++++++++---------------- sound/pci/hda/hda_component.h | 42 ++++++++++++++-------- sound/pci/hda/patch_realtek.c | 17 +++++---- 3 files changed, 71 insertions(+), 53 deletions(-) diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c index d02589014a3f..b05a0b87d32a 100644 --- a/sound/pci/hda/hda_component.c +++ b/sound/pci/hda/hda_component.c @@ -15,35 +15,39 @@ #include "hda_local.h" #ifdef CONFIG_ACPI -void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps, +void hda_component_acpi_device_notify(struct hda_component_parent *parent, acpi_handle handle, u32 event, void *data) { + struct hda_component *comp; int i; - for (i = 0; i < num_comps; i++) { - if (comps[i].dev && comps[i].acpi_notify) - comps[i].acpi_notify(acpi_device_handle(comps[i].adev), event, - comps[i].dev); + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { + comp = hda_component_from_index(parent, i); + if (comp->dev && comp->acpi_notify) + comp->acpi_notify(acpi_device_handle(comp->adev), event, comp->dev); } } EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, SND_HDA_SCODEC_COMPONENT); int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, int num_comps, + struct hda_component_parent *parent, acpi_notify_handler handler, void *data) { bool support_notifications = false; struct acpi_device *adev; + struct hda_component *comp; int ret; int i; - adev = comps[0].adev; + adev = parent->comps[0].adev; if (!acpi_device_handle(adev)) return 0; - for (i = 0; i < num_comps; i++) + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { + comp = hda_component_from_index(parent, i); support_notifications = support_notifications || - comps[i].acpi_notifications_supported; + comp->acpi_notifications_supported; + } if (support_notifications) { ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, @@ -61,13 +65,13 @@ int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, SND_HDA_SCODEC_COMPONENT); void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, + struct hda_component_parent *parent, acpi_notify_handler handler) { struct acpi_device *adev; int ret; - adev = comps[0].adev; + adev = parent->comps[0].adev; if (!acpi_device_handle(adev)) return; @@ -78,21 +82,25 @@ void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, SND_HDA_SCODEC_COMPONENT); #endif /* ifdef CONFIG_ACPI */ -void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps, int action) +void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action) { + struct hda_component *comp; int i; - for (i = 0; i < num_comps; i++) { - if (comps[i].dev && comps[i].pre_playback_hook) - comps[i].pre_playback_hook(comps[i].dev, action); + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { + comp = hda_component_from_index(parent, i); + if (comp->dev && comp->pre_playback_hook) + comp->pre_playback_hook(comp->dev, action); } - for (i = 0; i < num_comps; i++) { - if (comps[i].dev && comps[i].playback_hook) - comps[i].playback_hook(comps[i].dev, action); + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { + comp = hda_component_from_index(parent, i); + if (comp->dev && comp->playback_hook) + comp->playback_hook(comp->dev, action); } - for (i = 0; i < num_comps; i++) { - if (comps[i].dev && comps[i].post_playback_hook) - comps[i].post_playback_hook(comps[i].dev, action); + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { + comp = hda_component_from_index(parent, i); + if (comp->dev && comp->post_playback_hook) + comp->post_playback_hook(comp->dev, action); } } EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, SND_HDA_SCODEC_COMPONENT); @@ -124,22 +132,21 @@ static int hda_comp_match_dev_name(struct device *dev, void *data) } int hda_component_manager_bind(struct hda_codec *cdc, - struct hda_component *comps, int count) + struct hda_component_parent *parent) { int i; - /* Init shared data */ - for (i = 0; i < count; ++i) { - memset(&comps[i], 0, sizeof(comps[i])); - comps[i].codec = cdc; - } + /* Init shared and component specific data */ + memset(parent, 0, sizeof(*parent)); + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) + parent->comps[i].codec = cdc; - return component_bind_all(hda_codec_dev(cdc), comps); + return component_bind_all(hda_codec_dev(cdc), &parent->comps); } EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, SND_HDA_SCODEC_COMPONENT); int hda_component_manager_init(struct hda_codec *cdc, - struct hda_component *comps, int count, + struct hda_component_parent *parent, int count, const char *bus, const char *hid, const char *match_str, const struct component_master_ops *ops) diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index c70b3de68ab2..a016f1b942a2 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -28,18 +28,21 @@ struct hda_component { void (*post_playback_hook)(struct device *dev, int action); }; +struct hda_component_parent { + struct hda_component comps[HDA_MAX_COMPONENTS]; +}; + #ifdef CONFIG_ACPI -void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps, +void hda_component_acpi_device_notify(struct hda_component_parent *parent, acpi_handle handle, u32 event, void *data); int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, int num_comps, + struct hda_component_parent *parent, acpi_notify_handler handler, void *data); void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, + struct hda_component_parent *parent, acpi_notify_handler handler); #else -static inline void hda_component_acpi_device_notify(struct hda_component *comps, - int num_comps, +static inline void hda_component_acpi_device_notify(struct hda_component_parent *parent, acpi_handle handle, u32 event, void *data) @@ -47,8 +50,7 @@ static inline void hda_component_acpi_device_notify(struct hda_component *comps, } static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, - int num_comps, + struct hda_component_parent *parent, acpi_notify_handler handler, void *data) @@ -57,17 +59,16 @@ static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec } static inline void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, + struct hda_component_parent *parent, acpi_notify_handler handler) { } #endif /* ifdef CONFIG_ACPI */ -void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps, - int action); +void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action); int hda_component_manager_init(struct hda_codec *cdc, - struct hda_component *comps, int count, + struct hda_component_parent *parent, int count, const char *bus, const char *hid, const char *match_str, const struct component_master_ops *ops); @@ -75,13 +76,24 @@ int hda_component_manager_init(struct hda_codec *cdc, void hda_component_manager_free(struct hda_codec *cdc, const struct component_master_ops *ops); -int hda_component_manager_bind(struct hda_codec *cdc, - struct hda_component *comps, int count); +int hda_component_manager_bind(struct hda_codec *cdc, struct hda_component_parent *parent); + +static inline struct hda_component *hda_component_from_index(struct hda_component_parent *parent, + int index) +{ + if (!parent) + return NULL; + + if (index < 0 || index >= ARRAY_SIZE(parent->comps)) + return NULL; + + return &parent->comps[index]; +} static inline void hda_component_manager_unbind(struct hda_codec *cdc, - struct hda_component *comps) + struct hda_component_parent *parent) { - component_unbind_all(hda_codec_dev(cdc), comps); + component_unbind_all(hda_codec_dev(cdc), &parent->comps); } #endif /* ifndef __HDA_COMPONENT_H__ */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e2dbcf8f5bcf..e8f931baae4f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -131,7 +131,7 @@ struct alc_spec { u8 alc_mute_keycode_map[1]; /* component binding */ - struct hda_component comps[HDA_MAX_COMPONENTS]; + struct hda_component_parent comps; }; /* @@ -6793,8 +6793,7 @@ static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data) codec_info(cdc, "ACPI Notification %d\n", event); - hda_component_acpi_device_notify(spec->comps, ARRAY_SIZE(spec->comps), - handle, event, data); + hda_component_acpi_device_notify(&spec->comps, handle, event, data); } static int comp_bind(struct device *dev) @@ -6803,12 +6802,12 @@ static int comp_bind(struct device *dev) struct alc_spec *spec = cdc->spec; int ret; - ret = hda_component_manager_bind(cdc, spec->comps, ARRAY_SIZE(spec->comps)); + ret = hda_component_manager_bind(cdc, &spec->comps); if (ret) return ret; return hda_component_manager_bind_acpi_notifications(cdc, - spec->comps, ARRAY_SIZE(spec->comps), + &spec->comps, comp_acpi_device_notify, cdc); } @@ -6817,8 +6816,8 @@ static void comp_unbind(struct device *dev) struct hda_codec *cdc = dev_to_hda_codec(dev); struct alc_spec *spec = cdc->spec; - hda_component_manager_unbind_acpi_notifications(cdc, spec->comps, comp_acpi_device_notify); - hda_component_manager_unbind(cdc, spec->comps); + hda_component_manager_unbind_acpi_notifications(cdc, &spec->comps, comp_acpi_device_notify); + hda_component_manager_unbind(cdc, &spec->comps); } static const struct component_master_ops comp_master_ops = { @@ -6831,7 +6830,7 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_ { struct alc_spec *spec = cdc->spec; - hda_component_manager_playback_hook(spec->comps, ARRAY_SIZE(spec->comps), action); + hda_component_manager_playback_hook(&spec->comps, action); } static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus, @@ -6842,7 +6841,7 @@ static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bu switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: - ret = hda_component_manager_init(cdc, spec->comps, count, bus, hid, + ret = hda_component_manager_init(cdc, &spec->comps, count, bus, hid, match_str, &comp_master_ops); if (ret) return; From 1adf91011f60e6d992cb1294e77a872845a390ed Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Mon, 17 Jun 2024 16:41:03 +0100 Subject: [PATCH 115/349] ALSA: hda: hda_component: Change codecs to use component parent structure Change the hda_component binding APIs to pass the hds_component_parent as the parameter so the array of components can be abstracted. Signed-off-by: Simon Trimmer Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/20240617154105.108635-3-simont@opensource.cirrus.com --- sound/pci/hda/cs35l41_hda.c | 42 +++++++++++++++++++-------------- sound/pci/hda/cs35l56_hda.c | 25 +++++++++++--------- sound/pci/hda/hda_component.c | 2 +- sound/pci/hda/hda_component.h | 2 +- sound/pci/hda/tas2781_hda_i2c.c | 31 ++++++++++++------------ 5 files changed, 56 insertions(+), 46 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 031703f010be..ceba4f2c85f1 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -1419,27 +1419,28 @@ static void cs35l41_acpi_device_notify(acpi_handle handle, u32 event, struct dev static int cs35l41_hda_bind(struct device *dev, struct device *master, void *master_data) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); - struct hda_component *comps = master_data; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; unsigned int sleep_flags; int ret = 0; - if (!comps || cs35l41->index < 0 || cs35l41->index >= HDA_MAX_COMPONENTS) + comp = hda_component_from_index(parent, cs35l41->index); + if (!comp) return -EINVAL; - comps = &comps[cs35l41->index]; - if (comps->dev) + if (comp->dev) return -EBUSY; pm_runtime_get_sync(dev); mutex_lock(&cs35l41->fw_mutex); - comps->dev = dev; + comp->dev = dev; if (!cs35l41->acpi_subsystem_id) cs35l41->acpi_subsystem_id = kasprintf(GFP_KERNEL, "%.8x", - comps->codec->core.subsystem_id); - cs35l41->codec = comps->codec; - strscpy(comps->name, dev_name(dev), sizeof(comps->name)); + comp->codec->core.subsystem_id); + cs35l41->codec = comp->codec; + strscpy(comp->name, dev_name(dev), sizeof(comp->name)); cs35l41->firmware_type = HDA_CS_DSP_FW_SPK_PROT; @@ -1454,13 +1455,13 @@ 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; - comps->acpi_notify = cs35l41_acpi_device_notify; - comps->adev = cs35l41->dacpi; + comp->playback_hook = cs35l41_hda_playback_hook; + comp->pre_playback_hook = cs35l41_hda_pre_playback_hook; + comp->post_playback_hook = cs35l41_hda_post_playback_hook; + comp->acpi_notify = cs35l41_acpi_device_notify; + comp->adev = cs35l41->dacpi; - comps->acpi_notifications_supported = cs35l41_dsm_supported(acpi_device_handle(comps->adev), + comp->acpi_notifications_supported = cs35l41_dsm_supported(acpi_device_handle(comp->adev), CS35L41_DSM_GET_MUTE); cs35l41->mute_override = cs35l41_get_acpi_mute_state(cs35l41, @@ -1469,7 +1470,7 @@ 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)) + if (!device_link_add(&comp->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS)) dev_warn(dev, "Unable to create device link\n"); unlock_system_sleep(sleep_flags); @@ -1489,14 +1490,19 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *master_data) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); - struct hda_component *comps = master_data; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; unsigned int sleep_flags; - if (comps[cs35l41->index].dev == dev) { - memset(&comps[cs35l41->index], 0, sizeof(*comps)); + comp = hda_component_from_index(parent, cs35l41->index); + if (!comp) + return; + + if (comp->dev == dev) { sleep_flags = lock_system_sleep(); device_link_remove(&cs35l41->codec->core.dev, cs35l41->dev); unlock_system_sleep(sleep_flags); + memset(comp, 0, sizeof(*comp)); } } diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index e134ede6c5aa..df4498c77171 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -685,20 +685,21 @@ err_pm_put: 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; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; int ret; - if (!comps || cs35l56->index < 0 || cs35l56->index >= HDA_MAX_COMPONENTS) + comp = hda_component_from_index(parent, cs35l56->index); + if (!comp) return -EINVAL; - comps = &comps[cs35l56->index]; - if (comps->dev) + if (comp->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; + comp->dev = dev; + cs35l56->codec = comp->codec; + strscpy(comp->name, dev_name(dev), sizeof(comp->name)); + comp->playback_hook = cs35l56_hda_playback_hook; ret = cs35l56_hda_fw_load(cs35l56); if (ret) @@ -720,7 +721,8 @@ static int cs35l56_hda_bind(struct device *dev, struct device *master, void *mas 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; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; cs35l56_hda_remove_controls(cs35l56); @@ -732,8 +734,9 @@ static void cs35l56_hda_unbind(struct device *dev, struct device *master, void * if (cs35l56->base.fw_patched) cs_dsp_power_down(&cs35l56->cs_dsp); - if (comps[cs35l56->index].dev == dev) - memset(&comps[cs35l56->index], 0, sizeof(*comps)); + comp = hda_component_from_index(parent, cs35l56->index); + if (comp && (comp->dev == dev)) + memset(comp, 0, sizeof(*comp)); cs35l56->codec = NULL; diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c index b05a0b87d32a..8c11c8b37799 100644 --- a/sound/pci/hda/hda_component.c +++ b/sound/pci/hda/hda_component.c @@ -141,7 +141,7 @@ int hda_component_manager_bind(struct hda_codec *cdc, for (i = 0; i < ARRAY_SIZE(parent->comps); i++) parent->comps[i].codec = cdc; - return component_bind_all(hda_codec_dev(cdc), &parent->comps); + return component_bind_all(hda_codec_dev(cdc), parent); } EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, SND_HDA_SCODEC_COMPONENT); diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index a016f1b942a2..e547e1f1e674 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -93,7 +93,7 @@ static inline struct hda_component *hda_component_from_index(struct hda_componen static inline void hda_component_manager_unbind(struct hda_codec *cdc, struct hda_component_parent *parent) { - component_unbind_all(hda_codec_dev(cdc), &parent->comps); + component_unbind_all(hda_codec_dev(cdc), parent); } #endif /* ifndef __HDA_COMPONENT_H__ */ diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index fdee6592c502..c6c1e8e81972 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -706,20 +706,20 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, void *master_data) { struct tas2781_hda *tas_hda = dev_get_drvdata(dev); - struct hda_component *comps = master_data; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; struct hda_codec *codec; unsigned int subid; int ret; - if (!comps || tas_hda->priv->index < 0 || - tas_hda->priv->index >= HDA_MAX_COMPONENTS) + comp = hda_component_from_index(parent, tas_hda->priv->index); + if (!comp) return -EINVAL; - comps = &comps[tas_hda->priv->index]; - if (comps->dev) + if (comp->dev) return -EBUSY; - codec = comps->codec; + codec = comp->codec; subid = codec->core.subsystem_id >> 16; switch (subid) { @@ -733,13 +733,13 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, pm_runtime_get_sync(dev); - comps->dev = dev; + comp->dev = dev; - strscpy(comps->name, dev_name(dev), sizeof(comps->name)); + strscpy(comp->name, dev_name(dev), sizeof(comp->name)); ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready); if (!ret) - comps->playback_hook = tas2781_hda_playback_hook; + comp->playback_hook = tas2781_hda_playback_hook; pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); @@ -751,13 +751,14 @@ static void tas2781_hda_unbind(struct device *dev, struct device *master, void *master_data) { struct tas2781_hda *tas_hda = dev_get_drvdata(dev); - struct hda_component *comps = master_data; - comps = &comps[tas_hda->priv->index]; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; - if (comps->dev == dev) { - comps->dev = NULL; - memset(comps->name, 0, sizeof(comps->name)); - comps->playback_hook = NULL; + comp = hda_component_from_index(parent, tas_hda->priv->index); + if (comp && (comp->dev == dev)) { + comp->dev = NULL; + memset(comp->name, 0, sizeof(comp->name)); + comp->playback_hook = NULL; } tas2781_hda_remove_controls(tas_hda); From 3b2a8582876d0b1ff1d8df9ff3cca03a70268fe2 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Mon, 17 Jun 2024 16:41:04 +0100 Subject: [PATCH 116/349] ALSA: hda: hda_component: Move codec field into the parent There is one codec shared across all of the bound HDA components and a copy is usually stashed in the amp driver so it doesn't need to be in every hda_component. Signed-off-by: Simon Trimmer Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/20240617154105.108635-4-simont@opensource.cirrus.com --- sound/pci/hda/cs35l41_hda.c | 7 ++++--- sound/pci/hda/cs35l56_hda.c | 2 +- sound/pci/hda/hda_component.c | 5 +---- sound/pci/hda/hda_component.h | 2 +- sound/pci/hda/tas2781_hda_i2c.c | 2 +- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index ceba4f2c85f1..ee9f83b737de 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -1436,10 +1436,11 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas mutex_lock(&cs35l41->fw_mutex); comp->dev = dev; + cs35l41->codec = parent->codec; if (!cs35l41->acpi_subsystem_id) cs35l41->acpi_subsystem_id = kasprintf(GFP_KERNEL, "%.8x", - comp->codec->core.subsystem_id); - cs35l41->codec = comp->codec; + cs35l41->codec->core.subsystem_id); + strscpy(comp->name, dev_name(dev), sizeof(comp->name)); cs35l41->firmware_type = HDA_CS_DSP_FW_SPK_PROT; @@ -1470,7 +1471,7 @@ 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(&comp->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS)) + if (!device_link_add(&cs35l41->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS)) dev_warn(dev, "Unable to create device link\n"); unlock_system_sleep(sleep_flags); diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index df4498c77171..cc4aa90db1d1 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -697,7 +697,7 @@ static int cs35l56_hda_bind(struct device *dev, struct device *master, void *mas return -EBUSY; comp->dev = dev; - cs35l56->codec = comp->codec; + cs35l56->codec = parent->codec; strscpy(comp->name, dev_name(dev), sizeof(comp->name)); comp->playback_hook = cs35l56_hda_playback_hook; diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c index 8c11c8b37799..1a9950b76866 100644 --- a/sound/pci/hda/hda_component.c +++ b/sound/pci/hda/hda_component.c @@ -134,12 +134,9 @@ static int hda_comp_match_dev_name(struct device *dev, void *data) int hda_component_manager_bind(struct hda_codec *cdc, struct hda_component_parent *parent) { - int i; - /* Init shared and component specific data */ memset(parent, 0, sizeof(*parent)); - for (i = 0; i < ARRAY_SIZE(parent->comps); i++) - parent->comps[i].codec = cdc; + parent->codec = cdc; return component_bind_all(hda_codec_dev(cdc), parent); } diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index e547e1f1e674..dd4dabeae9ee 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -19,7 +19,6 @@ struct hda_component { struct device *dev; char name[HDA_MAX_NAME_SIZE]; - struct hda_codec *codec; struct acpi_device *adev; bool acpi_notifications_supported; void (*acpi_notify)(acpi_handle handle, u32 event, struct device *dev); @@ -29,6 +28,7 @@ struct hda_component { }; struct hda_component_parent { + struct hda_codec *codec; struct hda_component comps[HDA_MAX_COMPONENTS]; }; diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index c6c1e8e81972..d7af4fd10714 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -719,7 +719,7 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, if (comp->dev) return -EBUSY; - codec = comp->codec; + codec = parent->codec; subid = codec->core.subsystem_id >> 16; switch (subid) { From 047b9cbbaa8ee3f1d71ff07d181ea6397be97ffe Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Mon, 17 Jun 2024 16:41:05 +0100 Subject: [PATCH 117/349] ALSA: hda: hda_component: Protect shared data with a mutex The hda_component contains information shared from the amp drivers to the codec that can be altered (for example as the driver unloads). Guard the update and use of these to prevent use of stale data. Signed-off-by: Simon Trimmer Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/20240617154105.108635-5-simont@opensource.cirrus.com --- sound/pci/hda/hda_component.c | 13 ++++++++++++- sound/pci/hda/hda_component.h | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c index 1a9950b76866..7b19cb38b4e0 100644 --- a/sound/pci/hda/hda_component.c +++ b/sound/pci/hda/hda_component.c @@ -21,11 +21,13 @@ void hda_component_acpi_device_notify(struct hda_component_parent *parent, struct hda_component *comp; int i; + mutex_lock(&parent->mutex); for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { comp = hda_component_from_index(parent, i); if (comp->dev && comp->acpi_notify) comp->acpi_notify(acpi_device_handle(comp->adev), event, comp->dev); } + mutex_unlock(&parent->mutex); } EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, SND_HDA_SCODEC_COMPONENT); @@ -87,6 +89,7 @@ void hda_component_manager_playback_hook(struct hda_component_parent *parent, in struct hda_component *comp; int i; + mutex_lock(&parent->mutex); for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { comp = hda_component_from_index(parent, i); if (comp->dev && comp->pre_playback_hook) @@ -102,6 +105,7 @@ void hda_component_manager_playback_hook(struct hda_component_parent *parent, in if (comp->dev && comp->post_playback_hook) comp->post_playback_hook(comp->dev, action); } + mutex_unlock(&parent->mutex); } EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, SND_HDA_SCODEC_COMPONENT); @@ -134,11 +138,18 @@ static int hda_comp_match_dev_name(struct device *dev, void *data) int hda_component_manager_bind(struct hda_codec *cdc, struct hda_component_parent *parent) { + int ret; + /* Init shared and component specific data */ memset(parent, 0, sizeof(*parent)); + mutex_init(&parent->mutex); parent->codec = cdc; - return component_bind_all(hda_codec_dev(cdc), parent); + mutex_lock(&parent->mutex); + ret = component_bind_all(hda_codec_dev(cdc), parent); + mutex_unlock(&parent->mutex); + + return ret; } EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, SND_HDA_SCODEC_COMPONENT); diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index dd4dabeae9ee..9f786608144c 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -11,6 +11,7 @@ #include #include +#include #include #define HDA_MAX_COMPONENTS 4 @@ -28,6 +29,7 @@ struct hda_component { }; struct hda_component_parent { + struct mutex mutex; struct hda_codec *codec; struct hda_component comps[HDA_MAX_COMPONENTS]; }; @@ -93,7 +95,9 @@ static inline struct hda_component *hda_component_from_index(struct hda_componen static inline void hda_component_manager_unbind(struct hda_codec *cdc, struct hda_component_parent *parent) { + mutex_lock(&parent->mutex); component_unbind_all(hda_codec_dev(cdc), parent); + mutex_unlock(&parent->mutex); } #endif /* ifndef __HDA_COMPONENT_H__ */ From eb882afcfa83991c0b72913e8a18f941a9986b8f Mon Sep 17 00:00:00 2001 From: bo liu Date: Tue, 18 Jun 2024 09:01:21 +0800 Subject: [PATCH 118/349] ALSA: hda/senarytech: add senarytech codec support Add initial Senarytech codec support for SN6186. Note that this hda patch relies on the configuration default registers to be set correctly (normally by BIOS/firmware) in order for it to set up pin widgets properly. Signed-off-by: bo liu Link: https://lore.kernel.org/20240618010121.67335-1-bo.liu@senarytech.com Signed-off-by: Takashi Iwai --- MAINTAINERS | 6 + sound/hda/hdac_device.c | 1 + sound/pci/hda/Kconfig | 11 ++ sound/pci/hda/Makefile | 2 + sound/pci/hda/patch_senarytech.c | 244 +++++++++++++++++++++++++++++++ 5 files changed, 264 insertions(+) create mode 100644 sound/pci/hda/patch_senarytech.c diff --git a/MAINTAINERS b/MAINTAINERS index a6a011792167..82ea8c8f74c1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24949,6 +24949,12 @@ F: mm/zpool.c F: mm/zswap.c F: tools/testing/selftests/cgroup/test_zswap.c +SENARYTECH AUDIO CODEC DRIVER +M: bo liu +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git +F: sound/pci/hda/patch_senarytech.c + THE REST M: Linus Torvalds L: linux-kernel@vger.kernel.org diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 068c16e52dff..3fbb9793dcfc 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -665,6 +665,7 @@ static const struct hda_vendor_id hda_vendor_ids[] = { { 0x19e5, "Huawei" }, { 0x1aec, "Wolfson Microelectronics" }, { 0x1af4, "QEMU" }, + { 0x1fa8, "Senarytech" }, { 0x434d, "C-Media" }, { 0x8086, "Intel" }, { 0x8384, "SigmaTel" }, diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 0da625533afc..1252632f0ffa 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -292,6 +292,17 @@ config SND_HDA_CODEC_CONEXANT comment "Set to Y if you want auto-loading the codec driver" depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m +config SND_HDA_CODEC_SENARYTECH + tristate "Build Senarytech HD-audio codec support" + select SND_HDA_GENERIC + select SND_HDA_GENERIC_LEDS + help + Say Y or M here to include Senarytech HD-audio codec support in + snd-hda-intel driver, such as SN6186. + +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_SENARYTECH=m + config SND_HDA_CODEC_CA0110 tristate "Build Creative CA0110-IBG codec support" select SND_HDA_GENERIC diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 058ca0a289e4..80210f845df2 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -24,6 +24,7 @@ snd-hda-codec-cs8409-y := patch_cs8409.o patch_cs8409-tables.o snd-hda-codec-ca0110-y := patch_ca0110.o snd-hda-codec-ca0132-y := patch_ca0132.o snd-hda-codec-conexant-y := patch_conexant.o +snd-hda-codec-senarytech-y :=patch_senarytech.o snd-hda-codec-via-y := patch_via.o snd-hda-codec-hdmi-y := patch_hdmi.o hda_eld.o @@ -55,6 +56,7 @@ obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o +obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o diff --git a/sound/pci/hda/patch_senarytech.c b/sound/pci/hda/patch_senarytech.c new file mode 100644 index 000000000000..0691996fa971 --- /dev/null +++ b/sound/pci/hda/patch_senarytech.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HD audio interface patch for Senary HDA audio codec + * + * Initially based on sound/pci/hda/patch_conexant.c + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "hda_local.h" +#include "hda_auto_parser.h" +#include "hda_beep.h" +#include "hda_jack.h" +#include "hda_generic.h" + +struct senary_spec { + struct hda_gen_spec gen; + + /* extra EAPD pins */ + unsigned int num_eapds; + hda_nid_t eapds[4]; + hda_nid_t mute_led_eapd; + + unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ + + int mute_led_polarity; + unsigned int gpio_led; + unsigned int gpio_mute_led_mask; + unsigned int gpio_mic_led_mask; +}; + +#ifdef CONFIG_SND_HDA_INPUT_BEEP +/* additional beep mixers; private_value will be overwritten */ +static const struct snd_kcontrol_new senary_beep_mixer[] = { + HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), +}; + +static int set_beep_amp(struct senary_spec *spec, hda_nid_t nid, + int idx, int dir) +{ + struct snd_kcontrol_new *knew; + unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); + int i; + + spec->gen.beep_nid = nid; + for (i = 0; i < ARRAY_SIZE(senary_beep_mixer); i++) { + knew = snd_hda_gen_add_kctl(&spec->gen, NULL, + &senary_beep_mixer[i]); + if (!knew) + return -ENOMEM; + knew->private_value = beep_amp; + } + return 0; +} + +static int senary_auto_parse_beep(struct hda_codec *codec) +{ + struct senary_spec *spec = codec->spec; + hda_nid_t nid; + + for_each_hda_codec_node(nid, codec) + if ((get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) && + (get_wcaps(codec, nid) & (AC_WCAP_OUT_AMP | AC_WCAP_AMP_OVRD))) + return set_beep_amp(spec, nid, 0, HDA_OUTPUT); + return 0; +} +#else +#define senary_auto_parse_beep(codec) 0 +#endif + +/* parse EAPDs */ +static void senary_auto_parse_eapd(struct hda_codec *codec) +{ + struct senary_spec *spec = codec->spec; + hda_nid_t nid; + + for_each_hda_codec_node(nid, codec) { + if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) + continue; + if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) + continue; + spec->eapds[spec->num_eapds++] = nid; + if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) + break; + } +} + +static void senary_auto_turn_eapd(struct hda_codec *codec, int num_pins, + const hda_nid_t *pins, bool on) +{ + int i; + + for (i = 0; i < num_pins; i++) { + if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_EAPD_BTLENABLE, + on ? 0x02 : 0); + } +} + +/* turn on/off EAPD according to Master switch */ +static void senary_auto_vmaster_hook(void *private_data, int enabled) +{ + struct hda_codec *codec = private_data; + struct senary_spec *spec = codec->spec; + + senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled); +} + +static void senary_init_gpio_led(struct hda_codec *codec) +{ + struct senary_spec *spec = codec->spec; + unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask; + + if (mask) { + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, + mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, + mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_led); + } +} + +static int senary_auto_init(struct hda_codec *codec) +{ + snd_hda_gen_init(codec); + senary_init_gpio_led(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); + + return 0; +} + +static void senary_auto_shutdown(struct hda_codec *codec) +{ + struct senary_spec *spec = codec->spec; + + /* Turn the problematic codec into D3 to avoid spurious noises + * from the internal speaker during (and after) reboot + */ + senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false); +} + +static void senary_auto_free(struct hda_codec *codec) +{ + senary_auto_shutdown(codec); + snd_hda_gen_free(codec); +} + +static int senary_auto_suspend(struct hda_codec *codec) +{ + senary_auto_shutdown(codec); + return 0; +} + +static const struct hda_codec_ops senary_auto_patch_ops = { + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = senary_auto_init, + .free = senary_auto_free, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = senary_auto_suspend, + .check_power_status = snd_hda_gen_check_power_status, +}; + +static int patch_senary_auto(struct hda_codec *codec) +{ + struct senary_spec *spec; + int err; + + codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + snd_hda_gen_spec_init(&spec->gen); + codec->spec = spec; + codec->patch_ops = senary_auto_patch_ops; + + senary_auto_parse_eapd(codec); + spec->gen.own_eapd_ctl = 1; + + if (!spec->gen.vmaster_mute.hook) + spec->gen.vmaster_mute.hook = senary_auto_vmaster_hook; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, + spec->parse_flags); + if (err < 0) + goto error; + + err = senary_auto_parse_beep(codec); + if (err < 0) + goto error; + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + if (err < 0) + goto error; + + /* Some laptops with Senary chips show stalls in S3 resume, + * which falls into the single-cmd mode. + * Better to make reset, then. + */ + if (!codec->bus->core.sync_write) { + codec_info(codec, + "Enable sync_write for stable communication\n"); + codec->bus->core.sync_write = 1; + codec->bus->allow_bus_reset = 1; + } + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + + return 0; + + error: + senary_auto_free(codec); + return err; +} + +/* + */ + +static const struct hda_device_id snd_hda_id_senary[] = { + HDA_CODEC_ENTRY(0x1fa86186, "SN6186", patch_senary_auto), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_senary); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Senarytech HD-audio codec"); + +static struct hda_codec_driver senary_driver = { + .id = snd_hda_id_senary, +}; + +module_hda_codec_driver(senary_driver); From 10457f5042b4890a667e2f15a2e783490dda44d2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 16 Jun 2024 09:34:42 +0200 Subject: [PATCH 119/349] ALSA: vmaster: Return error for invalid input values So far the vmaster code has been tolerant about the input values and accepts any values by correcting internally. But now our own selftest starts complaining about this behavior, so let's be picky and change the behavior to return -EINVAL for invalid input values instead. Reported-by: Paul Menzel Closes: https://lore.kernel.org/r/1d44be36-9bb9-4d82-8953-5ae2a4f09405@molgen.mpg.de Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/20240616073454.16512-2-tiwai@suse.de --- sound/core/vmaster.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 04a57f7be6ea..c657659b236c 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -198,6 +198,12 @@ static int follower_put(struct snd_kcontrol *kcontrol, err = follower_init(follower); if (err < 0) return err; + for (ch = 0; ch < follower->info.count; ch++) { + if (ucontrol->value.integer.value[ch] < follower->info.min_val || + ucontrol->value.integer.value[ch] > follower->info.max_val) + return -EINVAL; + } + for (ch = 0; ch < follower->info.count; ch++) { if (follower->vals[ch] != ucontrol->value.integer.value[ch]) { changed = 1; @@ -365,6 +371,8 @@ static int master_put(struct snd_kcontrol *kcontrol, new_val = ucontrol->value.integer.value[0]; if (new_val == old_val) return 0; + if (new_val < master->info.min_val || new_val > master->info.max_val) + return -EINVAL; err = sync_followers(master, old_val, new_val); if (err < 0) From 5bae83007bdd71919a38d5c6db020ef43e2299c6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 16 Jun 2024 09:34:43 +0200 Subject: [PATCH 120/349] ALSA: hda: Return -EINVAL for invalid volume/switch inputs So far the HD-audio driver has been tolerant about the input values and accepts any values by correcting the amp volume and switch values internally. But now our own selftest starts complaining about this behavior, so let's be picky and change the behavior to return -EINVAL for invalid input values instead. Reported-by: Paul Menzel Closes: https://lore.kernel.org/r/1d44be36-9bb9-4d82-8953-5ae2a4f09405@molgen.mpg.de Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/20240616073454.16512-3-tiwai@suse.de --- sound/pci/hda/hda_codec.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 325e8f0b99a8..3dd1bda0c5c6 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1496,7 +1496,7 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, /* ofs = 0: raw max value */ maxval = get_amp_max_value(codec, nid, dir, 0); if (val > maxval) - val = maxval; + return -EINVAL; return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, HDA_AMP_VOLMASK, val); } @@ -1547,13 +1547,21 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, unsigned int ofs = get_amp_offset(kcontrol); long *valp = ucontrol->value.integer.value; int change = 0; + int err; if (chs & 1) { - change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); + err = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); + if (err < 0) + return err; + change |= err; valp++; } - if (chs & 2) - change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); + if (chs & 2) { + err = update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); + if (err < 0) + return err; + change |= err; + } return change; } EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); @@ -2149,15 +2157,20 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, int change = 0; if (chs & 1) { + if (*valp < 0 || *valp > 1) + return -EINVAL; change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, HDA_AMP_MUTE, *valp ? 0 : HDA_AMP_MUTE); valp++; } - if (chs & 2) + if (chs & 2) { + if (*valp < 0 || *valp > 1) + return -EINVAL; change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, HDA_AMP_MUTE, *valp ? 0 : HDA_AMP_MUTE); + } hda_call_check_power_status(codec, nid); return change; } From 50ed081284fe2bfd1f25e8b92f4f6a4990e73c0a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 16 Jun 2024 09:34:44 +0200 Subject: [PATCH 121/349] ALSA: control: Apply sanity check of input values for user elements Although we have already a mechanism for sanity checks of input values for control writes, it's not applied unless the kconfig CONFIG_SND_CTL_INPUT_VALIDATION is set due to the performance reason. Nevertheless, it still makes sense to apply the same check for user elements despite of its cost, as that's the only way to filter out the invalid values; the user controls are handled solely in ALSA core code, and there is no corresponding driver, after all. This patch adds the same input value validation for user control elements at its put callback. The kselftest will be happier with this change, as the incorrect values will be bailed out now with errors. For other normal controls, the check is applied still only when CONFIG_SND_CTL_INPUT_VALIDATION is set. Reported-by: Paul Menzel Closes: https://lore.kernel.org/r/1d44be36-9bb9-4d82-8953-5ae2a4f09405@molgen.mpg.de Reviewed-by: Jaroslav Kysela Reviewed-by: Mark Brown Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/20240616073454.16512-4-tiwai@suse.de --- sound/core/control.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/core/control.c b/sound/core/control.c index fb0c60044f7b..1dd2337e2930 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1480,12 +1480,16 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol, static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - int change; + int err, change; struct user_element *ue = kcontrol->private_data; unsigned int size = ue->elem_data_size; char *dst = ue->elem_data + snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size; + err = sanity_check_input_values(ue->card, ucontrol, &ue->info, false); + if (err < 0) + return err; + change = memcmp(&ucontrol->value, dst, size) != 0; if (change) memcpy(dst, &ucontrol->value, size); From 1b1285e4759e4d9df4f8e46d92802ff87ce8709b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 16 Jun 2024 09:34:45 +0200 Subject: [PATCH 122/349] kselftest/alsa: Fix validation of writes to volatile controls When validating writes to controls we check that whatever value we wrote actually appears in the control. For volatile controls we cannot assume that this will be the case, the value may be changed at any time including between our write and read. Handle this by moving the check for volatile controls that we currently do for events to a separate block and just verifying that whatever value we read is valid for the control. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20240614-alsa-selftest-volatile-v1-1-3874f02964b1@kernel.org Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/20240616073454.16512-5-tiwai@suse.de --- tools/testing/selftests/alsa/mixer-test.c | 45 +++++++++++++++-------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/tools/testing/selftests/alsa/mixer-test.c b/tools/testing/selftests/alsa/mixer-test.c index 1c04e5f638a0..dd74f8cc7ece 100644 --- a/tools/testing/selftests/alsa/mixer-test.c +++ b/tools/testing/selftests/alsa/mixer-test.c @@ -625,6 +625,21 @@ static int write_and_verify(struct ctl_data *ctl, return err; } + /* + * We can't verify any specific value for volatile controls + * but we should still check that whatever we read is a valid + * vale for the control. + */ + if (snd_ctl_elem_info_is_volatile(ctl->info)) { + if (!ctl_value_valid(ctl, read_val)) { + ksft_print_msg("Volatile control %s has invalid value\n", + ctl->name); + return -EINVAL; + } + + return 0; + } + /* * Check for an event if the value changed, or confirm that * there was none if it didn't. We rely on the kernel @@ -632,22 +647,20 @@ static int write_and_verify(struct ctl_data *ctl, * write, this is currently true, should that ever change this * will most likely break and need updating. */ - if (!snd_ctl_elem_info_is_volatile(ctl->info)) { - err = wait_for_event(ctl, 0); - if (snd_ctl_elem_value_compare(initial_val, read_val)) { - if (err < 1) { - ksft_print_msg("No event generated for %s\n", - ctl->name); - show_values(ctl, initial_val, read_val); - ctl->event_missing++; - } - } else { - if (err != 0) { - ksft_print_msg("Spurious event generated for %s\n", - ctl->name); - show_values(ctl, initial_val, read_val); - ctl->event_spurious++; - } + err = wait_for_event(ctl, 0); + if (snd_ctl_elem_value_compare(initial_val, read_val)) { + if (err < 1) { + ksft_print_msg("No event generated for %s\n", + ctl->name); + show_values(ctl, initial_val, read_val); + ctl->event_missing++; + } + } else { + if (err != 0) { + ksft_print_msg("Spurious event generated for %s\n", + ctl->name); + show_values(ctl, initial_val, read_val); + ctl->event_spurious++; } } From 210e6a844112bd7e28a04faedac677918e1f3040 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 16 Jun 2024 09:34:46 +0200 Subject: [PATCH 123/349] ALSA: chmap: Mark Channel Map controls as volatile The values returned from Playback Channel Map and Capture Channel Map controls may vary dynamically depending on the corresponding PCM stream. Mark those as volatile to indicate the values are unstable and not suitable for testing. Note that we may change the driver to return -EINVAL, but this would bring other side effects, such as "alsactl restore" would start receiving unexpected errors. So we still keep returning 0 for those invalid inputs. Reported-by: Paul Menzel Closes: https://lore.kernel.org/r/1d44be36-9bb9-4d82-8953-5ae2a4f09405@molgen.mpg.de Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/20240616073454.16512-6-tiwai@suse.de --- sound/core/pcm_lib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 6f73b3c2c205..071c67cbc479 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2556,6 +2556,7 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream, struct snd_kcontrol_new knew = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, .info = pcm_chmap_ctl_info, From 6278056e42d953e207e2afd416be39d09ed2d496 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 16 Jun 2024 09:34:47 +0200 Subject: [PATCH 124/349] ALSA: hda: Add input value sanity checks to HDMI channel map controls Add a simple sanity check to HD-audio HDMI Channel Map controls. Although the value might not be accepted for the actual connection, we can filter out some bogus values beforehand, and that should be enough for making kselftest happier. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/20240616073454.16512-7-tiwai@suse.de --- sound/hda/hdmi_chmap.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c index 5d8e1d944b0a..7b276047f85a 100644 --- a/sound/hda/hdmi_chmap.c +++ b/sound/hda/hdmi_chmap.c @@ -753,6 +753,20 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, return 0; } +/* a simple sanity check for input values to chmap kcontrol */ +static int chmap_value_check(struct hdac_chmap *hchmap, + const struct snd_ctl_elem_value *ucontrol) +{ + int i; + + for (i = 0; i < hchmap->channels_max; i++) { + if (ucontrol->value.integer.value[i] < 0 || + ucontrol->value.integer.value[i] > SNDRV_CHMAP_LAST) + return -EINVAL; + } + return 0; +} + static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -764,6 +778,10 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, unsigned char chmap[8], per_pin_chmap[8]; int i, err, ca, prepared = 0; + err = chmap_value_check(hchmap, ucontrol); + if (err < 0) + return err; + /* No monitor is connected in dyn_pcm_assign. * It's invalid to setup the chmap */ From e946455ce116fd822718d6acd874f3f4cf306520 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 17 Jun 2024 12:05:23 +0200 Subject: [PATCH 125/349] ALSA: control: Allow NULL passed to snd_ctl_remove() There are lots of code checking NULL for kcontrol passed to snd_ctl_remove() in the caller side. Let's make snd_ctl_remove() accepting the NULL kcontrol instead a la free(), so that we can clean up the caller side. Link: https://lore.kernel.org/20240617100529.6667-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/control.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/core/control.c b/sound/core/control.c index 1dd2337e2930..f64a555f404f 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -604,6 +604,7 @@ static inline int snd_ctl_remove_locked(struct snd_card *card, * * Removes the control from the card and then releases the instance. * You don't need to call snd_ctl_free_one(). + * Passing NULL to @kcontrol argument is allowed as noop. * * Return: 0 if successful, or a negative error code on failure. * @@ -611,6 +612,8 @@ static inline int snd_ctl_remove_locked(struct snd_card *card, */ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) { + if (!kcontrol) + return 0; guard(rwsem_write)(&card->controls_rwsem); return snd_ctl_remove_locked(card, kcontrol); } From 4d4500b4396a226d159b2633b091c0b65509b24a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 17 Jun 2024 12:05:24 +0200 Subject: [PATCH 126/349] ALSA: sb: Drop NULL check for snd_ctl_remove() Since snd_ctl_remove() accepts the NULL kcontrol argument now, we can drop the check in the caller side. Link: https://lore.kernel.org/20240617100529.6667-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/isa/sb/emu8000.c | 6 ++---- sound/isa/sb/sb16_csp.c | 12 ++++-------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index a6405772d537..af478c36ce5b 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1039,10 +1039,8 @@ snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu) return 0; __error: - for (i = 0; i < EMU8000_NUM_CONTROLS; i++) { - if (emu->controls[i]) - snd_ctl_remove(card, emu->controls[i]); - } + for (i = 0; i < EMU8000_NUM_CONTROLS; i++) + snd_ctl_remove(card, emu->controls[i]); return err; } diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 8d8357019719..fdb992733bde 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -1080,14 +1080,10 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p) card = p->chip->card; - if (p->qsound_switch) { - snd_ctl_remove(card, p->qsound_switch); - p->qsound_switch = NULL; - } - if (p->qsound_space) { - snd_ctl_remove(card, p->qsound_space); - p->qsound_space = NULL; - } + snd_ctl_remove(card, p->qsound_switch); + p->qsound_switch = NULL; + snd_ctl_remove(card, p->qsound_space); + p->qsound_space = NULL; /* cancel pending transfer of QSound parameters */ spin_lock_irqsave (&p->q_lock, flags); From 9d67a4006f7219577c5c4502d43892feb8773aa6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 17 Jun 2024 12:05:26 +0200 Subject: [PATCH 127/349] ALSA: hda: Drop NULL check for snd_ctl_remove() Since snd_ctl_remove() accepts the NULL kcontrol argument now, we can drop the check in the caller side. Link: https://lore.kernel.org/20240617100529.6667-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_cs_dsp_ctl.c | 2 +- sound/pci/hda/tas2781_hda_i2c.c | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/hda_cs_dsp_ctl.c b/sound/pci/hda/hda_cs_dsp_ctl.c index e6e876998e71..deb74c247082 100644 --- a/sound/pci/hda/hda_cs_dsp_ctl.c +++ b/sound/pci/hda/hda_cs_dsp_ctl.c @@ -207,7 +207,7 @@ void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) struct hda_cs_dsp_coeff_ctl *ctl = cs_ctl->priv; /* ctl and kctl may already have been removed by ALSA private_free */ - if (ctl && ctl->kctl) + if (ctl) snd_ctl_remove(ctl->card, ctl->kctl); } EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_remove, SND_HDA_CS_DSP_CONTROLS); diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index d7af4fd10714..879d4b48e6c7 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -597,18 +597,13 @@ static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda) { struct hda_codec *codec = tas_hda->priv->codec; - if (tas_hda->dsp_prog_ctl) - snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl); - - if (tas_hda->dsp_conf_ctl) - snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl); + snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl); + snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl); for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--) - if (tas_hda->snd_ctls[i]) - snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]); + snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]); - if (tas_hda->prof_ctl) - snd_ctl_remove(codec->card, tas_hda->prof_ctl); + snd_ctl_remove(codec->card, tas_hda->prof_ctl); } static void tasdev_fw_ready(const struct firmware *fmw, void *context) From f900a055f8e279a0f572f54f57b967a99aa7a465 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 17 Jun 2024 12:05:27 +0200 Subject: [PATCH 128/349] ALSA: spi: Drop NULL check for snd_ctl_remove() Since snd_ctl_remove() accepts the NULL kcontrol argument now, we can drop the check in the caller side. Link: https://lore.kernel.org/20240617100529.6667-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/spi/at73c213.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 5648d744aa79..8f6929ced2c8 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -726,12 +726,8 @@ static int snd_at73c213_mixer(struct snd_at73c213 *chip) return 0; cleanup: - for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++) { - struct snd_kcontrol *kctl; - kctl = snd_ctl_find_numid(card, idx); - if (kctl) - snd_ctl_remove(card, kctl); - } + for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++) + snd_ctl_remove(card, snd_ctl_find_numid(card, idx)); return errval; } From 2fbafecb0f05818e25f6c926c6f9ad9ef597429c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 15:03:19 +0200 Subject: [PATCH 129/349] ASoC: Constify of_phandle_args in snd_soc_dai_driver ASoC core code does not modify contents of 'of_phandle_args' in 'struct snd_soc_dai_driver', so the pointer can be made as a pointer to const. This makes code safer, serves as clear annotation of core's intentions and allows putting pointed structures in rodata (if ever applicable). Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617-n-asoc-const-auto-selectable-formats-v1-1-8004f346ee38@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 15ef268c9845..e6c61c79c483 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -413,7 +413,7 @@ struct snd_soc_dai_driver { unsigned int id; unsigned int base; struct snd_soc_dobj dobj; - struct of_phandle_args *dai_args; + const struct of_phandle_args *dai_args; /* ops */ const struct snd_soc_dai_ops *ops; From 020b37d06f97de289940805bc821190d5858eda0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 15:03:20 +0200 Subject: [PATCH 130/349] ASoC: Constify of_phandle_args in snd_soc_dai_link_component ASoC core code does not modify contents of 'of_phandle_args' in 'struct snd_soc_dai_link_component', so the pointer can be made as a pointer to const. This makes code safer, serves as clear annotation of core's intentions and allows putting pointed structures in rodata (if ever applicable). Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617-n-asoc-const-auto-selectable-formats-v1-2-8004f346ee38@linaro.org Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 33671437ee89..f02a51694ab4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -675,7 +675,7 @@ struct snd_soc_dai_link_component { const char *name; struct device_node *of_node; const char *dai_name; - struct of_phandle_args *dai_args; + const struct of_phandle_args *dai_args; }; /* From f3ac3da7e4d0957b3402fb31a4ca480e739e086f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 15:03:21 +0200 Subject: [PATCH 131/349] ASoC: Constify passed data to core function Several ASoC functions receive pointers to data which is not modified, e.g. pointers to 'snd_soc_dai', 'snd_soc_pcm_runtime', 'snd_pcm_hw_params' and 'snd_soc_dai_link'. All these pointers can be made as a pointer to const. This makes code safer, serves as clear annotation of function's intentions (no ownership passed to the function, no modifications) and allows putting pointed structures in rodata (if ever applicable). Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617-n-asoc-const-auto-selectable-formats-v1-3-8004f346ee38@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 18 ++++++++++-------- include/sound/soc.h | 17 +++++++++-------- sound/soc/soc-core.c | 4 ++-- sound/soc/soc-dai.c | 8 ++++---- sound/soc/soc-utils.c | 8 ++++---- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index e6c61c79c483..3c45b418270e 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -180,8 +180,8 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio); /* Digital Audio interface formatting */ -int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd); -u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority); +int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd); +u64 snd_soc_dai_get_fmt(const struct snd_soc_dai *dai, int priority); int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, @@ -202,7 +202,7 @@ int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); -int snd_soc_dai_is_dummy(struct snd_soc_dai *dai); +int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai); int snd_soc_dai_hw_params(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, @@ -218,7 +218,7 @@ void snd_soc_dai_suspend(struct snd_soc_dai *dai); void snd_soc_dai_resume(struct snd_soc_dai *dai); int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd, int num); -bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream); +bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int stream); void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link); void snd_soc_dai_action(struct snd_soc_dai *dai, int stream, int action); @@ -232,7 +232,7 @@ static inline void snd_soc_dai_deactivate(struct snd_soc_dai *dai, { snd_soc_dai_action(dai, stream, -1); } -int snd_soc_dai_active(struct snd_soc_dai *dai); +int snd_soc_dai_active(const struct snd_soc_dai *dai); int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order); int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order); @@ -271,7 +271,7 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai, struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata); -const char *snd_soc_dai_name_get(struct snd_soc_dai *dai); +const char *snd_soc_dai_name_get(const struct snd_soc_dai *dai); struct snd_soc_dai_ops { /* DAI driver callbacks */ @@ -518,7 +518,8 @@ static inline void snd_soc_dai_init_dma_data(struct snd_soc_dai *dai, void *play snd_soc_dai_dma_data_set_capture(dai, capture); } -static inline unsigned int snd_soc_dai_tdm_mask_get(struct snd_soc_dai *dai, int stream) +static inline unsigned int snd_soc_dai_tdm_mask_get(const struct snd_soc_dai *dai, + int stream) { return dai->stream[stream].tdm_mask; } @@ -529,7 +530,8 @@ static inline void snd_soc_dai_tdm_mask_set(struct snd_soc_dai *dai, int stream, dai->stream[stream].tdm_mask = tdm_mask; } -static inline unsigned int snd_soc_dai_stream_active(struct snd_soc_dai *dai, int stream) +static inline unsigned int snd_soc_dai_stream_active(const struct snd_soc_dai *dai, + int stream) { /* see snd_soc_dai_action() for setup */ return dai->stream[stream].active; diff --git a/include/sound/soc.h b/include/sound/soc.h index f02a51694ab4..a8e66bbf932b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -534,10 +534,10 @@ static inline int snd_soc_set_dmi_name(struct snd_soc_card *card, /* Utility functions to get clock rates from various things */ int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); -int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); +int snd_soc_params_to_frame_size(const struct snd_pcm_hw_params *params); int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots); -int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms); -int snd_soc_tdm_params_to_bclk(struct snd_pcm_hw_params *params, +int snd_soc_params_to_bclk(const struct snd_pcm_hw_params *parms); +int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params, int tdm_width, int tdm_slots, int slot_multiple); /* set runtime hw params */ @@ -837,7 +837,8 @@ struct snd_soc_dai_link { #endif }; -static inline int snd_soc_link_num_ch_map(struct snd_soc_dai_link *link) { +static inline int snd_soc_link_num_ch_map(const struct snd_soc_dai_link *link) +{ return max(link->num_cpus, link->num_codecs); } @@ -1299,7 +1300,7 @@ struct soc_enum { #endif }; -static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) +static inline bool snd_soc_volsw_is_stereo(const struct soc_mixer_control *mc) { if (mc->reg == mc->rreg && mc->shift == mc->rshift) return false; @@ -1311,7 +1312,7 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) return true; } -static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e, +static inline unsigned int snd_soc_enum_val_to_item(const struct soc_enum *e, unsigned int val) { unsigned int i; @@ -1326,7 +1327,7 @@ static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e, return 0; } -static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e, +static inline unsigned int snd_soc_enum_item_to_val(const struct soc_enum *e, unsigned int item) { if (!e->values) @@ -1401,7 +1402,7 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np, snd_soc_daifmt_clock_provider_from_bitmap( \ snd_soc_daifmt_parse_clock_provider_as_bitmap(np, prefix)) -int snd_soc_get_stream_cpu(struct snd_soc_dai_link *dai_link, int stream); +int snd_soc_get_stream_cpu(const struct snd_soc_dai_link *dai_link, int stream); int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_component *dlc); int snd_soc_of_get_dlc(struct device_node *of_node, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3ab6626ad680..724fe1f033b5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -297,7 +297,7 @@ static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc, return 0; } -const char *snd_soc_dai_name_get(struct snd_soc_dai *dai) +const char *snd_soc_dai_name_get(const struct snd_soc_dai *dai) { /* see snd_soc_is_matching_dai() */ if (dai->driver->name) @@ -3430,7 +3430,7 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_daifmt_parse_clock_provider_raw); -int snd_soc_get_stream_cpu(struct snd_soc_dai_link *dai_link, int stream) +int snd_soc_get_stream_cpu(const struct snd_soc_dai_link *dai_link, int stream) { /* * [Normal] diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 03afd5efb24c..55d1a5a099df 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -134,7 +134,7 @@ int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) } EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); -int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd) +int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *dai; int i, max = 0; @@ -166,7 +166,7 @@ int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd) * modes. This will mean that sometimes fewer formats * are reported here than are supported by set_fmt(). */ -u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority) +u64 snd_soc_dai_get_fmt(const struct snd_soc_dai *dai, int priority) { const struct snd_soc_dai_ops *ops = dai->driver->ops; u64 fmt = 0; @@ -471,7 +471,7 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai, * * Returns true if the DAI supports the indicated stream type. */ -bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir) +bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir) { struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir); @@ -528,7 +528,7 @@ void snd_soc_dai_action(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(snd_soc_dai_action); -int snd_soc_dai_active(struct snd_soc_dai *dai) +int snd_soc_dai_active(const struct snd_soc_dai *dai) { int stream, active; diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index d05e712c9518..5dea5609baf4 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -21,7 +21,7 @@ int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots) } EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size); -int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params) +int snd_soc_params_to_frame_size(const struct snd_pcm_hw_params *params) { int sample_size; @@ -40,7 +40,7 @@ int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots) } EXPORT_SYMBOL_GPL(snd_soc_calc_bclk); -int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) +int snd_soc_params_to_bclk(const struct snd_pcm_hw_params *params) { int ret; @@ -79,7 +79,7 @@ EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); * Return: bclk frequency in Hz, else a negative error code if params format * is invalid. */ -int snd_soc_tdm_params_to_bclk(struct snd_pcm_hw_params *params, +int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params, int tdm_width, int tdm_slots, int slot_multiple) { if (!tdm_slots) @@ -211,7 +211,7 @@ static struct snd_soc_dai_driver dummy_dai = { .ops = &dummy_dai_ops, }; -int snd_soc_dai_is_dummy(struct snd_soc_dai *dai) +int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai) { if (dai->driver == &dummy_dai) return 1; From 785d64c4941221044940ab199e6625af17296470 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 15:03:22 +0200 Subject: [PATCH 132/349] ASoC: Constify DAI passed to get_channel_map get_channel_map() is supposed to obtain map of channels without modifying the state of the given DAI, so make the pointer to 'struct snd_soc_dai' as pointing to const. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617-n-asoc-const-auto-selectable-formats-v1-4-8004f346ee38@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 4 ++-- sound/soc/codecs/lpass-rx-macro.c | 2 +- sound/soc/codecs/lpass-tx-macro.c | 2 +- sound/soc/codecs/lpass-va-macro.c | 2 +- sound/soc/codecs/lpass-wsa-macro.c | 2 +- sound/soc/codecs/wcd9335.c | 2 +- sound/soc/codecs/wcd934x.c | 2 +- sound/soc/soc-dai.c | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 3c45b418270e..f22969298de1 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -198,7 +198,7 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, int direction); -int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, +int snd_soc_dai_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); @@ -307,7 +307,7 @@ struct snd_soc_dai_ops { int (*set_channel_map)(struct snd_soc_dai *dai, unsigned int tx_num, const unsigned int *tx_slot, unsigned int rx_num, const unsigned int *rx_slot); - int (*get_channel_map)(struct snd_soc_dai *dai, + int (*get_channel_map)(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); int (*set_tristate)(struct snd_soc_dai *dai, int tristate); diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 00ecc470ba8b..83791507ed13 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -1833,7 +1833,7 @@ static int rx_macro_hw_params(struct snd_pcm_substream *substream, return 0; } -static int rx_macro_get_channel_map(struct snd_soc_dai *dai, +static int rx_macro_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index c98b0b747a92..209c12ec16dd 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -1167,7 +1167,7 @@ static int tx_macro_hw_params(struct snd_pcm_substream *substream, return 0; } -static int tx_macro_get_channel_map(struct snd_soc_dai *dai, +static int tx_macro_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index a555e1e078eb..b0006f4ce8a2 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -892,7 +892,7 @@ static int va_macro_hw_params(struct snd_pcm_substream *substream, return 0; } -static int va_macro_get_channel_map(struct snd_soc_dai *dai, +static int va_macro_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 6ce309980cd1..1e19c2b28a4f 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -992,7 +992,7 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream, return 0; } -static int wsa_macro_get_channel_map(struct snd_soc_dai *dai, +static int wsa_macro_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 42a99978fe5a..fc0ab00a253f 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -2014,7 +2014,7 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai, return 0; } -static int wcd9335_get_channel_map(struct snd_soc_dai *dai, +static int wcd9335_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index fcad2c9fba55..b5a929659dc8 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1960,7 +1960,7 @@ static int wcd934x_set_channel_map(struct snd_soc_dai *dai, return 0; } -static int wcd934x_get_channel_map(struct snd_soc_dai *dai, +static int wcd934x_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 55d1a5a099df..0c3a834e504d 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -11,7 +11,7 @@ #include #define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret) -static inline int _soc_dai_ret(struct snd_soc_dai *dai, +static inline int _soc_dai_ret(const struct snd_soc_dai *dai, const char *func, int ret) { /* Positive, Zero values are not errors */ @@ -327,7 +327,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); * @rx_slot: pointer to an array which imply the RX slot number channel * 0~num-1 uses */ -int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, +int snd_soc_dai_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { From de267e7a6ea8e6fa29af2287adfc9fc9d87e6dc9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 15:03:23 +0200 Subject: [PATCH 133/349] ASoC: Constify return of snd_soc_dai_get_pcm_stream() Returned 'struct snd_soc_pcm_stream' by snd_soc_dai_get_pcm_stream() is not modified by the users, so it can be changed as pointer to const. This is a necessary step towards making the 'dai->driver' a pointer to const. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617-n-asoc-const-auto-selectable-formats-v1-5-8004f346ee38@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 +- sound/soc/intel/avs/pcm.c | 4 ++-- sound/soc/soc-dai.c | 2 +- sound/soc/soc-pcm.c | 26 +++++++++++++------------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index f22969298de1..bd249710d716 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -473,7 +473,7 @@ struct snd_soc_dai { unsigned int probed:1; }; -static inline struct snd_soc_pcm_stream * +static inline const struct snd_soc_pcm_stream * snd_soc_dai_get_pcm_stream(const struct snd_soc_dai *dai, int stream) { return (stream == SNDRV_PCM_STREAM_PLAYBACK) ? diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 88e711875004..c76b86254a8b 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -341,7 +341,7 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_stream *stream_info; + const struct snd_soc_pcm_stream *stream_info; struct hdac_ext_stream *link_stream; struct hdac_ext_link *link; struct avs_dma_data *data; @@ -637,7 +637,7 @@ static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_so static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_stream *stream_info; + const struct snd_soc_pcm_stream *stream_info; struct avs_dma_data *data; struct hdac_ext_stream *host_stream; unsigned int format_val; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 0c3a834e504d..9e47053419c1 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -473,7 +473,7 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai, */ bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir) { - struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir); + const struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir); /* If the codec specifies any channels at all, it supports the stream */ return stream->channels_min; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 711b2f49ed88..bad823718ae4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -504,7 +504,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) unsigned int bits = 0, cpu_bits = 0; for_each_rtd_codec_dais(rtd, i, codec_dai) { - struct snd_soc_pcm_stream *pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream); + const struct snd_soc_pcm_stream *pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream); if (pcm_codec->sig_bits == 0) { bits = 0; @@ -514,7 +514,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) } for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - struct snd_soc_pcm_stream *pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream); + const struct snd_soc_pcm_stream *pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream); if (pcm_cpu->sig_bits == 0) { cpu_bits = 0; @@ -538,7 +538,7 @@ static void soc_pcm_hw_init(struct snd_pcm_hardware *hw) } static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw, - struct snd_soc_pcm_stream *p) + const struct snd_soc_pcm_stream *p) { hw->rates = snd_pcm_rate_mask_intersect(hw->rates, p->rates); @@ -551,20 +551,20 @@ static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw, } static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw, - struct snd_soc_pcm_stream *p) + const struct snd_soc_pcm_stream *p) { hw->channels_min = max(hw->channels_min, p->channels_min); hw->channels_max = min(hw->channels_max, p->channels_max); } static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw, - struct snd_soc_pcm_stream *p) + const struct snd_soc_pcm_stream *p) { hw->formats &= p->formats; } static void soc_pcm_hw_update_subformat(struct snd_pcm_hardware *hw, - struct snd_soc_pcm_stream *p) + const struct snd_soc_pcm_stream *p) { hw->subformats &= p->subformats; } @@ -583,8 +583,8 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai; - struct snd_soc_pcm_stream *codec_stream; - struct snd_soc_pcm_stream *cpu_stream; + const struct snd_soc_pcm_stream *codec_stream; + const struct snd_soc_pcm_stream *cpu_stream; unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX; int i; @@ -1712,7 +1712,7 @@ static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream) hw->formats &= formats; for_each_rtd_cpu_dais(fe, i, dai) { - struct snd_soc_pcm_stream *cpu_stream; + const struct snd_soc_pcm_stream *cpu_stream; /* * Skip CPUs which don't support the current stream @@ -1750,7 +1750,7 @@ static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream) for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_soc_pcm_stream *codec_stream; + const struct snd_soc_pcm_stream *codec_stream; int i; for_each_rtd_codec_dais(be, i, dai) { @@ -1787,7 +1787,7 @@ static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream) for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_soc_pcm_stream *cpu_stream; + const struct snd_soc_pcm_stream *cpu_stream; struct snd_soc_dai *dai; int i; @@ -1809,7 +1809,7 @@ static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream) * DAIs connected to a single CPU DAI, use CPU DAI's directly */ if (be->dai_link->num_codecs == 1) { - struct snd_soc_pcm_stream *codec_stream = snd_soc_dai_get_pcm_stream( + const struct snd_soc_pcm_stream *codec_stream = snd_soc_dai_get_pcm_stream( snd_soc_rtd_to_codec(be, 0), stream); soc_pcm_hw_update_chan(hw, codec_stream); @@ -1835,7 +1835,7 @@ static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream) for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_soc_pcm_stream *pcm; + const struct snd_soc_pcm_stream *pcm; struct snd_soc_dai *dai; int i; From 6d620e50bb055e072c8c50cf95cd397fc24378c2 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 6 Jun 2024 11:49:19 +0100 Subject: [PATCH 134/349] ASoC: qcom: q6dsp: parse Display port tokens Signed-off-by: Srinivas Kandagatla Tested-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Tested-by: Dmitry Baryshkov # X13s Link: https://msgid.link/r/20240606104922.114229-2-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/topology.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c index c15d1a2b6dbf..f4d62ea60baa 100644 --- a/sound/soc/qcom/qdsp6/topology.c +++ b/sound/soc/qcom/qdsp6/topology.c @@ -730,6 +730,29 @@ static int audioreach_widget_i2s_module_load(struct audioreach_module *mod, return 0; } +static int audioreach_widget_dp_module_load(struct audioreach_module *mod, + struct snd_soc_tplg_vendor_array *mod_array) +{ + struct snd_soc_tplg_vendor_value_elem *mod_elem; + int tkn_count = 0; + + mod_elem = mod_array->value; + + while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { + switch (le32_to_cpu(mod_elem->token)) { + case AR_TKN_U32_MODULE_FMT_DATA: + mod->data_format = le32_to_cpu(mod_elem->value); + break; + default: + break; + } + tkn_count++; + mod_elem++; + } + + return 0; +} + static int audioreach_widget_load_buffer(struct snd_soc_component *component, int index, struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w) @@ -760,6 +783,9 @@ static int audioreach_widget_load_buffer(struct snd_soc_component *component, case MODULE_ID_I2S_SOURCE: audioreach_widget_i2s_module_load(mod, mod_array); break; + case MODULE_ID_DISPLAY_PORT_SINK: + audioreach_widget_dp_module_load(mod, mod_array); + break; default: return -EINVAL; } From 735db4ea16caaebf8e4884ec0c2e419c96391ac8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 6 Jun 2024 11:49:20 +0100 Subject: [PATCH 135/349] ASoC: qcom: common: add Display port Jack function Add a common function to add Display port jack. Signed-off-by: Srinivas Kandagatla Tested-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Tested-by: Dmitry Baryshkov # X13s Link: https://msgid.link/r/20240606104922.114229-3-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/common.c | 35 +++++++++++++++++++++++++++++++++++ sound/soc/qcom/common.h | 3 +++ 2 files changed, 38 insertions(+) diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 3d02aa3844f2..56b4a3654aec 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -8,9 +8,19 @@ #include #include "common.h" +#define NAME_SIZE 32 + static const struct snd_soc_dapm_widget qcom_jack_snd_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("DP0 Jack", NULL), + SND_SOC_DAPM_SPK("DP1 Jack", NULL), + SND_SOC_DAPM_SPK("DP2 Jack", NULL), + SND_SOC_DAPM_SPK("DP3 Jack", NULL), + SND_SOC_DAPM_SPK("DP4 Jack", NULL), + SND_SOC_DAPM_SPK("DP5 Jack", NULL), + SND_SOC_DAPM_SPK("DP6 Jack", NULL), + SND_SOC_DAPM_SPK("DP7 Jack", NULL), }; int qcom_snd_parse_of(struct snd_soc_card *card) @@ -240,5 +250,30 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup); +int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_jack *dp_jack, int dp_pcm_id) +{ + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + struct snd_soc_card *card = rtd->card; + char jack_name[NAME_SIZE]; + int rval, i; + + snprintf(jack_name, sizeof(jack_name), "DP%d Jack", dp_pcm_id); + rval = snd_soc_card_jack_new(card, jack_name, SND_JACK_AVOUT, dp_jack); + if (rval) + return rval; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + rval = snd_soc_component_set_jack(codec_dai->component, dp_jack, NULL); + if (rval != 0 && rval != -ENOTSUPP) { + dev_warn(card->dev, "Failed to set jack: %d\n", rval); + return rval; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_snd_dp_jack_setup); + MODULE_DESCRIPTION("ASoC Qualcomm helper functions"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h index d7f80ee5ae26..1b8d3f90bffa 100644 --- a/sound/soc/qcom/common.h +++ b/sound/soc/qcom/common.h @@ -9,5 +9,8 @@ int qcom_snd_parse_of(struct snd_soc_card *card); int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_jack *jack, bool *jack_setup); +int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_jack *dp_jack, int id); + #endif From 7e815bb9abd16f99c987987242a9fe13dfa0f052 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 6 Jun 2024 11:49:21 +0100 Subject: [PATCH 136/349] ASoC: qcom: sc8280xp: add Display port Jack Add support for Display Port Jack events. Signed-off-by: Srinivas Kandagatla Tested-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Tested-by: Dmitry Baryshkov # X13s Link: https://msgid.link/r/20240606104922.114229-4-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 06fd47c4178f..922ecada1cd8 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -19,6 +19,7 @@ struct sc8280xp_snd_data { struct snd_soc_card *card; struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; struct snd_soc_jack jack; + struct snd_soc_jack dp_jack[8]; bool jack_setup; }; @@ -27,6 +28,8 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_card *card = rtd->card; + struct snd_soc_jack *dp_jack = NULL; + int dp_pcm_id = 0; switch (cpu_dai->id) { case WSA_CODEC_DMA_RX_0: @@ -41,10 +44,22 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) snd_soc_limit_volume(card, "SpkrLeft PA Volume", 17); snd_soc_limit_volume(card, "SpkrRight PA Volume", 17); break; + case DISPLAY_PORT_RX_0: + /* DISPLAY_PORT dai ids are not contiguous */ + dp_pcm_id = 0; + dp_jack = &data->dp_jack[dp_pcm_id]; + break; + case DISPLAY_PORT_RX_1 ... DISPLAY_PORT_RX_7: + dp_pcm_id = cpu_dai->id - DISPLAY_PORT_RX_1 + 1; + dp_jack = &data->dp_jack[dp_pcm_id]; + break; default: break; } + if (dp_jack) + return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id); + return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); } From 24790a3cd1bdc083f9989f2fdb223f6494ebc99c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Jun 2024 11:49:22 +0100 Subject: [PATCH 137/349] ASoC: qcom: x1e80100: Add USB DisplayPort plug support Add support for handling jack events of USB (DisplayPort). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Srinivas Kandagatla Tested-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Tested-by: Dmitry Baryshkov # X13s Link: https://msgid.link/r/20240606104922.114229-5-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/x1e80100.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c index d7e0bd03dffd..898b5c26bf1e 100644 --- a/sound/soc/qcom/x1e80100.c +++ b/sound/soc/qcom/x1e80100.c @@ -20,12 +20,32 @@ struct x1e80100_snd_data { struct snd_soc_card *card; struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; struct snd_soc_jack jack; + struct snd_soc_jack dp_jack[8]; bool jack_setup; }; static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd) { struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_jack *dp_jack = NULL; + int dp_pcm_id = 0; + + switch (cpu_dai->id) { + case DISPLAY_PORT_RX_0: + dp_pcm_id = 0; + dp_jack = &data->dp_jack[dp_pcm_id]; + break; + case DISPLAY_PORT_RX_1 ... DISPLAY_PORT_RX_7: + dp_pcm_id = cpu_dai->id - DISPLAY_PORT_RX_1 + 1; + dp_jack = &data->dp_jack[dp_pcm_id]; + break; + default: + break; + } + + if (dp_jack) + return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id); return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); } From 4e617f0cb2dd9675a3b2707c10d89f0f5303ad1e Mon Sep 17 00:00:00 2001 From: Ricard Wanderlof Date: Fri, 7 Jun 2024 17:22:04 +0200 Subject: [PATCH 138/349] ASoC: dt-bindings: tlv320adc3xxx: Add MICBIAS-as-GPO properties Add properties for configuring the MICBIAS pins as general purpose outputs, with some limitations: The voltage on the pin when activated may be set using another property to 2.0 V, 2.5 V or AVDD. When deactivated the pin will float. Signed-off-by: Ricard Wanderlof Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240607-tlv320adc3xxx-micbias-gpo-v3-1-59dbec8b98f4@axis.com Signed-off-by: Mark Brown --- .../bindings/sound/ti,tlv320adc3xxx.yaml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml index 8ac741f4cd56..66b76656229f 100644 --- a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml @@ -82,6 +82,26 @@ properties: Note that there is currently no support for reading the GPIO pins as inputs. + ti,micbias1-gpo: + type: boolean + description: | + When set, the MICBIAS1 pin may be controlled via the GPIO framework, + as pin number 3 on the device. + + In this mode, when the pin is activated, it will be set to the voltage + specified by the ti,micbias1-vg property. When deactivated, the pin will + float. + + ti,micbias2-gpo: + type: boolean + description: | + When set, the MICBIAS2 pin may be controlled via the GPIO framework, + as pin number 4 on the device. + + In this mode, when the pin is activated, it will be set to the voltage + specified by the ti,micbias2-vg property. When deactivated, the pin will + float. + ti,micbias1-vg: $ref: /schemas/types.yaml#/definitions/uint32 enum: @@ -104,6 +124,10 @@ properties: description: | Mic bias voltage output on MICBIAS2 pin +dependencies: + ti,micbias1-gpo: ['ti,micbias1-vg'] + ti,micbias2-gpo: ['ti,micbias2-vg'] + required: - compatible - reg From 6c01001414ce477311d872c40e23dfec4866d608 Mon Sep 17 00:00:00 2001 From: Ricard Wanderlof Date: Fri, 7 Jun 2024 17:22:05 +0200 Subject: [PATCH 139/349] ASoC: tlv320adc3xxx: Add support for using MICBIAS pins as GPO Add boolean ti,micbias1-gpo and ti,micbias2-gpo devicetree properties. When set, the respective MICBIAS pins can be used as general purpose outputs controlled via the GPIO framework, in addition to the two configurable GPIO pins. This is useful in applications where the MICBIAS functionality is not required, but it is useful to have a couple of extra GPIO pins. The voltage on the respective MICBIAS pin in the active state is governed by the ti,micbias1-vg and ti,micbias2-vg properties, respectively (same properties as when the pins are used as MICBIAS pins). Signed-off-by: Ricard Wanderlof Link: https://msgid.link/r/20240607-tlv320adc3xxx-micbias-gpo-v3-2-59dbec8b98f4@axis.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320adc3xxx.c | 105 ++++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index eb180df9a72a..7073b9d1cda8 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -39,9 +39,10 @@ */ #define ADC3XXX_MICBIAS_PINS 2 +#define ADC3XXX_GPIO_PINS 2 /* Number of GPIO pins exposed via the gpiolib interface */ -#define ADC3XXX_GPIOS_MAX 2 +#define ADC3XXX_GPIOS_MAX (ADC3XXX_MICBIAS_PINS + ADC3XXX_GPIO_PINS) #define ADC3XXX_RATES SNDRV_PCM_RATE_8000_96000 #define ADC3XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -320,7 +321,8 @@ struct adc3xxx { struct gpio_desc *rst_pin; unsigned int pll_mode; unsigned int sysclk; - unsigned int gpio_cfg[ADC3XXX_GPIOS_MAX]; /* value+1 (0 => not set) */ + unsigned int gpio_cfg[ADC3XXX_GPIO_PINS]; /* value+1 (0 => not set) */ + unsigned int micbias_gpo[ADC3XXX_MICBIAS_PINS]; /* 1 => pin is GPO */ unsigned int micbias_vg[ADC3XXX_MICBIAS_PINS]; int master; u8 page_no; @@ -328,7 +330,7 @@ struct adc3xxx { struct gpio_chip gpio_chip; }; -static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIOS_MAX] = { +static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIO_PINS] = { ADC3XXX_GPIO1_CTRL, ADC3XXX_GPIO2_CTRL }; @@ -959,14 +961,23 @@ static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset) if (offset >= ADC3XXX_GPIOS_MAX) return -EINVAL; - /* GPIO1 is offset 0, GPIO2 is offset 1 */ - /* We check here that the GPIO pins are either not configured in the - * DT, or that they purposely are set as outputs. - * (Input mode not yet implemented). - */ - if (adc3xxx->gpio_cfg[offset] != 0 && - adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1) - return -EINVAL; + if (offset >= 0 && offset < ADC3XXX_GPIO_PINS) { + /* GPIO1 is offset 0, GPIO2 is offset 1 */ + /* We check here that the GPIO pins are either not configured + * in the DT, or that they purposely are set as outputs. + * (Input mode not yet implemented). + */ + if (adc3xxx->gpio_cfg[offset] != 0 && + adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1) + return -EINVAL; + } else if (offset >= ADC3XXX_GPIO_PINS && offset < ADC3XXX_GPIOS_MAX) { + /* MICBIAS1 is offset 2, MICBIAS2 is offset 3 */ + /* We check here if the MICBIAS pins are in fact configured + * as GPOs. + */ + if (!adc3xxx->micbias_gpo[offset - ADC3XXX_GPIO_PINS]) + return -EINVAL; + } return 0; } @@ -976,6 +987,21 @@ static int adc3xxx_gpio_direction_out(struct gpio_chip *chip, { struct adc3xxx *adc3xxx = gpiochip_get_data(chip); + /* For the MICBIAS pins, they are by definition outputs. */ + if (offset >= ADC3XXX_GPIO_PINS) { + unsigned int vg; + unsigned int micbias = offset - ADC3XXX_GPIO_PINS; + + if (value) + vg = adc3xxx->micbias_vg[micbias]; + else + vg = ADC3XXX_MICBIAS_OFF; + return regmap_update_bits(adc3xxx->regmap, + ADC3XXX_MICBIAS_CTRL, + ADC3XXX_MICBIAS_MASK << adc3xxx_micbias_shift[micbias], + vg << adc3xxx_micbias_shift[micbias]); + } + /* Set GPIO output function. */ return regmap_update_bits(adc3xxx->regmap, adc3xxx_gpio_ctrl_reg[offset], @@ -1004,9 +1030,17 @@ static int adc3xxx_gpio_get(struct gpio_chip *chip, unsigned int offset) unsigned int regval; int ret; - /* We only allow output pins, so just read the value set in the output - * pin register field. - */ + /* We only allow output pins, so just read the value prevously set. */ + if (offset >= ADC3XXX_GPIO_PINS) { + /* MICBIAS pins */ + unsigned int micbias = offset - ADC3XXX_GPIO_PINS; + + ret = regmap_read(adc3xxx->regmap, ADC3XXX_MICBIAS_CTRL, ®val); + if (ret) + return ret; + return ((regval >> adc3xxx_micbias_shift[micbias]) & ADC3XXX_MICBIAS_MASK) != + ADC3XXX_MICBIAS_OFF; + } ret = regmap_read(adc3xxx->regmap, adc3xxx_gpio_ctrl_reg[offset], ®val); if (ret) return ret; @@ -1048,7 +1082,7 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx) * This allows us to set up things which are not software * controllable GPIOs, such as PDM microphone I/O, */ - for (gpio = 0; gpio < ADC3XXX_GPIOS_MAX; gpio++) { + for (gpio = 0; gpio < ADC3XXX_GPIO_PINS; gpio++) { unsigned int cfg = adc3xxx->gpio_cfg[gpio]; if (cfg) { @@ -1060,9 +1094,15 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx) } } - /* Set up micbias voltage */ + /* Set up micbias voltage. */ + /* If pin is configured as GPO, set off initially. */ for (micbias = 0; micbias < ADC3XXX_MICBIAS_PINS; micbias++) { - unsigned int vg = adc3xxx->micbias_vg[micbias]; + unsigned int vg; + + if (adc3xxx->micbias_gpo[micbias]) + vg = ADC3XXX_MICBIAS_OFF; + else + vg = adc3xxx->micbias_vg[micbias]; regmap_update_bits(adc3xxx->regmap, ADC3XXX_MICBIAS_CTRL, @@ -1090,8 +1130,19 @@ static int adc3xxx_parse_dt_gpio(struct adc3xxx *adc3xxx, return 0; } -static int adc3xxx_parse_dt_micbias(struct adc3xxx *adc3xxx, - const char *propname, unsigned int *vg) +static int adc3xxx_parse_dt_micbias_gpo(struct adc3xxx *adc3xxx, + const char *propname, + unsigned int *cfg) +{ + struct device *dev = adc3xxx->dev; + struct device_node *np = dev->of_node; + + *cfg = of_property_read_bool(np, propname); + return 0; +} + +static int adc3xxx_parse_dt_micbias_vg(struct adc3xxx *adc3xxx, + const char *propname, unsigned int *vg) { struct device *dev = adc3xxx->dev; struct device_node *np = dev->of_node; @@ -1382,16 +1433,28 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c) dev_dbg(dev, "Enabled MCLK, freq %lu Hz\n", clk_get_rate(adc3xxx->mclk)); } + /* Configure mode for DMDIN/GPIO1 pin */ ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmdin-gpio1", &adc3xxx->gpio_cfg[0]); if (ret < 0) goto err_unprepare_mclk; + /* Configure mode for DMCLK/GPIO2 pin */ ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmclk-gpio2", &adc3xxx->gpio_cfg[1]); if (ret < 0) goto err_unprepare_mclk; - ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]); + /* Configure mode for MICBIAS1: as Mic Bias output or GPO */ + ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias1-gpo", &adc3xxx->micbias_gpo[0]); if (ret < 0) goto err_unprepare_mclk; - ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]); + /* Configure mode for MICBIAS2: as Mic Bias output or GPO */ + ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias2-gpo", &adc3xxx->micbias_gpo[1]); + if (ret < 0) + goto err_unprepare_mclk; + /* Configure voltage for MICBIAS1 pin (ON voltage when used as GPO) */ + ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]); + if (ret < 0) + goto err_unprepare_mclk; + /* Configure voltage for MICBIAS2 pin (ON voltage when used as GPO) */ + ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]); if (ret < 0) goto err_unprepare_mclk; From 634f3b4e7dde3827e3b81306416ec306b323e39b Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Tue, 18 Jun 2024 14:00:11 +0100 Subject: [PATCH 140/349] ALSA: hda: cs35l56: Perform firmware download in the background It is possible that during system boot when there multiple devices attempting simultaneous initialization on a slow control bus the download of firmware and tuning data may take a user perceivable amount of time (a slow I2C bus with 4 amps this work could take over 2 seconds). Adopt a pattern used in the ASoC driver and perform this activity in a background thread so that interactive performance is not impaired. The system_long_wq is a parallel workqueue and driver instances will perform their firmware downloads in parallel to make best use of available bus bandwidth. Signed-off-by: Simon Trimmer Link: https://lore.kernel.org/20240618130011.62860-1-simont@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 90 ++++++++++++++++++++++++++++++------- sound/pci/hda/cs35l56_hda.h | 3 ++ 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index cc4aa90db1d1..96d3f13c5abf 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -50,11 +50,19 @@ static const struct reg_sequence cs35l56_hda_dai_config[] = { }; +static void cs35l56_hda_wait_dsp_ready(struct cs35l56_hda *cs35l56) +{ + /* Wait for patching to complete */ + flush_work(&cs35l56->dsp_work); +} + static void cs35l56_hda_play(struct cs35l56_hda *cs35l56) { unsigned int val; int ret; + cs35l56_hda_wait_dsp_ready(cs35l56); + pm_runtime_get_sync(cs35l56->base.dev); ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY); if (ret == 0) { @@ -180,6 +188,8 @@ static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol, unsigned int reg_val; int i; + cs35l56_hda_wait_dsp_ready(cs35l56); + regmap_read(cs35l56->base.regmap, kcontrol->private_value, ®_val); reg_val &= CS35L56_ASP_TXn_SRC_MASK; @@ -203,6 +213,8 @@ static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol, if (item >= CS35L56_NUM_INPUT_SRC) return -EINVAL; + cs35l56_hda_wait_dsp_ready(cs35l56); + regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value, CS35L56_INPUT_MASK, cs35l56_tx_input_values[item], &changed); @@ -227,6 +239,8 @@ static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol, unsigned int pos; int ret; + cs35l56_hda_wait_dsp_ready(cs35l56); + ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_POSTURE_NUMBER, &pos); if (ret) return ret; @@ -248,6 +262,8 @@ static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol, (pos > CS35L56_MAIN_POSTURE_MAX)) return -EINVAL; + cs35l56_hda_wait_dsp_ready(cs35l56); + ret = regmap_update_bits_check(cs35l56->base.regmap, CS35L56_MAIN_POSTURE_NUMBER, CS35L56_MAIN_POSTURE_MASK, @@ -291,6 +307,8 @@ static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol, int vol; int ret; + cs35l56_hda_wait_dsp_ready(cs35l56); + ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_RENDER_USER_VOLUME, &raw_vol); if (ret) @@ -323,6 +341,8 @@ static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol, raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) << CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT; + cs35l56_hda_wait_dsp_ready(cs35l56); + ret = regmap_update_bits_check(cs35l56->base.regmap, CS35L56_MAIN_RENDER_USER_VOLUME, CS35L56_MAIN_RENDER_USER_VOLUME_MASK, @@ -539,8 +559,9 @@ static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmw kfree(coeff_filename); } -static void cs35l56_hda_add_dsp_controls(struct cs35l56_hda *cs35l56) +static void cs35l56_hda_create_dsp_controls_work(struct work_struct *work) { + struct cs35l56_hda *cs35l56 = container_of(work, struct cs35l56_hda, control_work); struct hda_cs_dsp_ctl_info info; info.device_name = cs35l56->amp_name; @@ -566,7 +587,7 @@ static void cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56) dev_info(cs35l56->base.dev, "Calibration applied\n"); } -static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) +static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) { const struct firmware *coeff_firmware = NULL; const struct firmware *wmfw_firmware = NULL; @@ -574,15 +595,34 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) char *wmfw_filename = NULL; unsigned int preloaded_fw_ver; bool firmware_missing; - int ret = 0; + bool add_dsp_controls_required = false; + int ret; - /* Prepare for a new DSP power-up */ + /* + * control_work must be flushed before proceeding, but we can't do that + * here as it would create a deadlock on controls_rwsem so it must be + * performed before queuing dsp_work. + */ + WARN_ON_ONCE(work_busy(&cs35l56->control_work)); + + /* + * Prepare for a new DSP power-up. If the DSP has had firmware + * downloaded previously then it needs to be powered down so that it + * can be updated and if hadn't been patched before then the controls + * will need to be added once firmware download succeeds. + */ if (cs35l56->base.fw_patched) cs_dsp_power_down(&cs35l56->cs_dsp); + else + add_dsp_controls_required = true; cs35l56->base.fw_patched = false; - pm_runtime_get_sync(cs35l56->base.dev); + ret = pm_runtime_resume_and_get(cs35l56->base.dev); + if (ret < 0) { + dev_err(cs35l56->base.dev, "Failed to resume and get %d\n", ret); + return; + } /* * The firmware can only be upgraded if it is currently running @@ -606,7 +646,6 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) */ if (!coeff_firmware && firmware_missing) { dev_err(cs35l56->base.dev, ".bin file required but not found\n"); - ret = -ENOENT; goto err_fw_release; } @@ -659,6 +698,15 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) CS35L56_FIRMWARE_MISSING); cs35l56->base.fw_patched = true; + /* + * Adding controls is deferred to prevent a lock inversion - ALSA takes + * the controls_rwsem when adding a control, the get() / put() + * functions of a control are called holding controls_rwsem and those + * that depend on running firmware wait for dsp_work() to complete. + */ + if (add_dsp_controls_required) + queue_work(system_long_wq, &cs35l56->control_work); + ret = cs_dsp_run(&cs35l56->cs_dsp); if (ret) dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret); @@ -678,8 +726,13 @@ err_fw_release: coeff_firmware, coeff_filename); err_pm_put: pm_runtime_put(cs35l56->base.dev); +} - return ret; +static void cs35l56_hda_dsp_work(struct work_struct *work) +{ + struct cs35l56_hda *cs35l56 = container_of(work, struct cs35l56_hda, dsp_work); + + cs35l56_hda_fw_load(cs35l56); } static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data) @@ -687,7 +740,6 @@ static int cs35l56_hda_bind(struct device *dev, struct device *master, void *mas struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); struct hda_component_parent *parent = master_data; struct hda_component *comp; - int ret; comp = hda_component_from_index(parent, cs35l56->index); if (!comp) @@ -701,12 +753,10 @@ static int cs35l56_hda_bind(struct device *dev, struct device *master, void *mas strscpy(comp->name, dev_name(dev), sizeof(comp->name)); comp->playback_hook = cs35l56_hda_playback_hook; - ret = cs35l56_hda_fw_load(cs35l56); - if (ret) - return ret; + flush_work(&cs35l56->control_work); + queue_work(system_long_wq, &cs35l56->dsp_work); 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); @@ -724,6 +774,9 @@ static void cs35l56_hda_unbind(struct device *dev, struct device *master, void * struct hda_component_parent *parent = master_data; struct hda_component *comp; + cancel_work_sync(&cs35l56->dsp_work); + cancel_work_sync(&cs35l56->control_work); + cs35l56_hda_remove_controls(cs35l56); #if IS_ENABLED(CONFIG_SND_DEBUG) @@ -752,6 +805,9 @@ static int cs35l56_hda_system_suspend(struct device *dev) { struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + cs35l56_hda_wait_dsp_ready(cs35l56); + flush_work(&cs35l56->control_work); + if (cs35l56->playing) cs35l56_hda_pause(cs35l56); @@ -850,11 +906,8 @@ static int cs35l56_hda_system_resume(struct device *dev) 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 (ret > 0) + queue_work(system_long_wq, &cs35l56->dsp_work); if (cs35l56->playing) cs35l56_hda_play(cs35l56); @@ -972,6 +1025,9 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) mutex_init(&cs35l56->base.irq_lock); dev_set_drvdata(cs35l56->base.dev, cs35l56); + INIT_WORK(&cs35l56->dsp_work, cs35l56_hda_dsp_work); + INIT_WORK(&cs35l56->control_work, cs35l56_hda_create_dsp_controls_work); + ret = cs35l56_hda_read_acpi(cs35l56, hid, id); if (ret) goto err; diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/pci/hda/cs35l56_hda.h index 464e4aa63cd1..c40d159507c2 100644 --- a/sound/pci/hda/cs35l56_hda.h +++ b/sound/pci/hda/cs35l56_hda.h @@ -14,6 +14,7 @@ #include #include #include +#include #include struct dentry; @@ -21,6 +22,8 @@ struct dentry; struct cs35l56_hda { struct cs35l56_base base; struct hda_codec *codec; + struct work_struct dsp_work; + struct work_struct control_work; int index; const char *system_name; From 9292013bd3738bd00ee78bf1705620a9881031b5 Mon Sep 17 00:00:00 2001 From: Andrejs Cainikovs Date: Thu, 13 Jun 2024 10:46:50 +0200 Subject: [PATCH 141/349] ASoC: nau8822: move nau8822_set_dai_sysclk() Next commit in series makes a change which calls nau8822_set_pll() from nau8822_set_dai_sysclk(). Moving latter after the former would avoid a forward declaration, and this is exactly what this change does. Signed-off-by: Andrejs Cainikovs Link: https://msgid.link/r/20240613084652.13113-2-andrejs.cainikovs@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8822.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index e6909e64dfa3..a6741bda6a9e 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -612,20 +612,6 @@ static const struct snd_soc_dapm_route nau8822_dapm_routes[] = { {"Right DAC", NULL, "Digital Loopback"}, }; -static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir) -{ - struct snd_soc_component *component = dai->component; - struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); - - nau8822->div_id = clk_id; - nau8822->sysclk = freq; - dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq, - clk_id == NAU8822_CLK_PLL ? "PLL" : "MCLK"); - - return 0; -} - static int nau8822_calc_pll(unsigned int pll_in, unsigned int fs, struct nau8822_pll *pll_param) { @@ -782,6 +768,20 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, return 0; } +static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + + nau8822->div_id = clk_id; + nau8822->sysclk = freq; + dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq, + clk_id == NAU8822_CLK_PLL ? "PLL" : "MCLK"); + + return 0; +} + static int nau8822_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_component *component = dai->component; From 9c3b21cc8528d52321c66236c3b794300c78d9e6 Mon Sep 17 00:00:00 2001 From: Andrejs Cainikovs Date: Thu, 13 Jun 2024 10:46:51 +0200 Subject: [PATCH 142/349] ASoC: nau8822: set NAU8822_REFIMP_80K only once Following bias state machine logic this bit is set twice before playback. This change makes sure this bit set is set only once. Signed-off-by: Andrejs Cainikovs Suggested-by: Emanuele Ghidoli Link: https://msgid.link/r/20240613084652.13113-3-andrejs.cainikovs@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8822.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index a6741bda6a9e..5f9f0953aa2f 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -942,6 +942,8 @@ static int nau8822_set_bias_level(struct snd_soc_component *component, { switch (level) { case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: snd_soc_component_update_bits(component, NAU8822_REG_POWER_MANAGEMENT_1, From 93f12a75682698ad4d2614b88cc68f52bb8fb917 Mon Sep 17 00:00:00 2001 From: Andrejs Cainikovs Date: Thu, 13 Jun 2024 10:46:52 +0200 Subject: [PATCH 143/349] ASoC: nau8822: add MCLK support This change adds MCLK clock handling directly within driver. When used in combination with simple-audio-card, and mclk-fs is set, simple-audio-card will change MCLK frequency before configuring PLL. In some cases, however, MCLK reference clock should be static (see [1]), which means it needs to be moved away from simple-audio-card. [1]: https://lore.kernel.org/all/ZfBdxrzX3EnPuGOn@ediswmail9.ad.cirrus.com/ Signed-off-by: Andrejs Cainikovs Link: https://msgid.link/r/20240613084652.13113-4-andrejs.cainikovs@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8822.c | 48 ++++++++++++++++++++++++++++++++++---- sound/soc/codecs/nau8822.h | 1 + 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index 5f9f0953aa2f..e1cbaf8a944d 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -773,11 +774,26 @@ static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, { struct snd_soc_component *component = dai->component; struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + unsigned long mclk_freq; nau8822->div_id = clk_id; nau8822->sysclk = freq; + + if (nau8822->mclk) { + mclk_freq = clk_get_rate(nau8822->mclk); + if (mclk_freq != freq) { + int ret = nau8822_set_pll(dai, NAU8822_CLK_MCLK, + NAU8822_CLK_MCLK, mclk_freq, freq); + if (ret) { + dev_err(component->dev, "Failed to set PLL\n"); + return ret; + } + nau8822->div_id = NAU8822_CLK_PLL; + } + } + dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq, - clk_id == NAU8822_CLK_PLL ? "PLL" : "MCLK"); + nau8822->div_id == NAU8822_CLK_PLL ? "PLL" : "MCLK"); return 0; } @@ -848,7 +864,7 @@ static int nau8822_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); - int val_len = 0, val_rate = 0; + int div = 0, val_len = 0, val_rate = 0; unsigned int ctrl_val, bclk_fs, bclk_div; /* make BCLK and LRC divide configuration if the codec as master. */ @@ -915,8 +931,10 @@ static int nau8822_hw_params(struct snd_pcm_substream *substream, /* If the master clock is from MCLK, provide the runtime FS for driver * to get the master clock prescaler configuration. */ - if (nau8822->div_id == NAU8822_CLK_MCLK) - nau8822_config_clkdiv(dai, 0, params_rate(params)); + if (nau8822->div_id != NAU8822_CLK_MCLK) + div = nau8822->pll.mclk_scaler; + + nau8822_config_clkdiv(dai, div, params_rate(params)); return 0; } @@ -940,17 +958,34 @@ static int nau8822_mute(struct snd_soc_dai *dai, int mute, int direction) static int nau8822_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: + if (nau8822->mclk && + snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON) { + int ret = clk_prepare_enable(nau8822->mclk); + + if (ret) { + dev_err(component->dev, + "Failed to enable MCLK: %d\n", ret); + return ret; + } + } + snd_soc_component_update_bits(component, NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_REFIMP_MASK, NAU8822_REFIMP_80K); break; case SND_SOC_BIAS_STANDBY: + if (nau8822->mclk && + snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_OFF) + clk_disable_unprepare(nau8822->mclk); + snd_soc_component_update_bits(component, NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_IOBUF_EN | NAU8822_ABIAS_EN, @@ -1127,6 +1162,11 @@ static int nau8822_i2c_probe(struct i2c_client *i2c) } i2c_set_clientdata(i2c, nau8822); + nau8822->mclk = devm_clk_get_optional(&i2c->dev, "mclk"); + if (IS_ERR(nau8822->mclk)) + return dev_err_probe(&i2c->dev, PTR_ERR(nau8822->mclk), + "Error getting mclk\n"); + nau8822->regmap = devm_regmap_init_i2c(i2c, &nau8822_regmap_config); if (IS_ERR(nau8822->regmap)) { ret = PTR_ERR(nau8822->regmap); diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h index 6ecd46e45923..13fe0a091e9e 100644 --- a/sound/soc/codecs/nau8822.h +++ b/sound/soc/codecs/nau8822.h @@ -215,6 +215,7 @@ struct nau8822_pll { struct nau8822 { struct device *dev; struct regmap *regmap; + struct clk *mclk; struct nau8822_pll pll; int sysclk; int div_id; From 7109f10ca4225c4a7e47dee5eab0d8d72edbf324 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Jun 2024 00:10:15 +0000 Subject: [PATCH 144/349] ASoC: dt-bindings: audio-graph-card2: add support for aux devices Add device tree property to define auxiliary devices to be added to Audio Graph Card which is already supported on Simle Card. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/87jzin3yc8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/audio-graph-card2.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml b/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml index d3ce4de449d5..f943f90d8b15 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml @@ -23,6 +23,11 @@ properties: Each entry is a pair of strings, the first being the connection's sink, the second being the connection's source. $ref: /schemas/types.yaml#/definitions/non-unique-string-array + aux-devs: + description: | + List of phandles pointing to auxiliary devices, such + as amplifiers, to be added to the sound card. + $ref: /schemas/types.yaml#/definitions/phandle-array multi: type: object description: Multi-CPU/Codec node From 9f774c757e3fb2ac32dc4377e8f21f3364a8df81 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 14 Jun 2024 21:36:45 +0800 Subject: [PATCH 145/349] ASoc: tas2781: Enable RCA-based playback without DSP firmware download In only loading RCA (Reconfigurable Architecture) binary case, no DSP program will be working inside tas2563/tas2781, that is dsp-bypass mode, do not support speaker protection, or audio acoustic algorithms in this mode. Fixes: ef3bcde75d06 ("ASoC: tas2781: Add tas2781 driver") Signed-off-by: Shenghao Ding Reviewed-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240614133646.910-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- include/sound/tas2781-dsp.h | 11 +++++++-- sound/soc/codecs/tas2781-fmwlib.c | 18 ++++++++++---- sound/soc/codecs/tas2781-i2c.c | 39 ++++++++++++++++++++----------- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/include/sound/tas2781-dsp.h b/include/sound/tas2781-dsp.h index 7fba7ea26a4b..3cda9da14f6d 100644 --- a/include/sound/tas2781-dsp.h +++ b/include/sound/tas2781-dsp.h @@ -117,10 +117,17 @@ struct tasdevice_fw { struct device *dev; }; -enum tasdevice_dsp_fw_state { - TASDEVICE_DSP_FW_NONE = 0, +enum tasdevice_fw_state { + /* Driver in startup mode, not load any firmware. */ TASDEVICE_DSP_FW_PENDING, + /* DSP firmware in the system, but parsing error. */ TASDEVICE_DSP_FW_FAIL, + /* + * Only RCA (Reconfigurable Architecture) firmware load + * successfully. + */ + TASDEVICE_RCA_FW_OK, + /* Both RCA and DSP firmware load successfully. */ TASDEVICE_DSP_FW_ALL_OK, }; diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index 265a8ca25cbb..838d29fead96 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -2324,14 +2324,21 @@ void tasdevice_tuning_switch(void *context, int state) struct tasdevice_fw *tas_fmw = tas_priv->fmw; int profile_cfg_id = tas_priv->rcabin.profile_cfg_id; - if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) { - dev_err(tas_priv->dev, "DSP bin file not loaded\n"); + /* + * Only RCA-based Playback can still work with no dsp program running + * inside the chip. + */ + switch (tas_priv->fw_state) { + case TASDEVICE_RCA_FW_OK: + case TASDEVICE_DSP_FW_ALL_OK: + break; + default: return; } if (state == 0) { - if (tas_priv->cur_prog < tas_fmw->nr_programs) { - /*dsp mode or tuning mode*/ + if (tas_fmw && tas_priv->cur_prog < tas_fmw->nr_programs) { + /* dsp mode or tuning mode */ profile_cfg_id = tas_priv->rcabin.profile_cfg_id; tasdevice_select_tuningprm_cfg(tas_priv, tas_priv->cur_prog, tas_priv->cur_conf, @@ -2340,9 +2347,10 @@ void tasdevice_tuning_switch(void *context, int state) tasdevice_select_cfg_blk(tas_priv, profile_cfg_id, TASDEVICE_BIN_BLK_PRE_POWER_UP); - } else + } else { tasdevice_select_cfg_blk(tas_priv, profile_cfg_id, TASDEVICE_BIN_BLK_PRE_SHUTDOWN); + } } EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch, SND_SOC_TAS2781_FMWLIB); diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 9350972dfefe..c64d458e524e 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -380,23 +380,37 @@ static void tasdevice_fw_ready(const struct firmware *fmw, mutex_lock(&tas_priv->codec_lock); ret = tasdevice_rca_parser(tas_priv, fmw); - if (ret) + if (ret) { + tasdevice_config_info_remove(tas_priv); goto out; + } tasdevice_create_control(tas_priv); tasdevice_dsp_remove(tas_priv); tasdevice_calbin_remove(tas_priv); - tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; + /* + * The baseline is the RCA-only case, and then the code attempts to + * load DSP firmware but in case of failures just keep going, i.e. + * failing to load DSP firmware is NOT an error. + */ + tas_priv->fw_state = TASDEVICE_RCA_FW_OK; scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin", tas_priv->dev_name); 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; } - tasdevice_dsp_create_ctrls(tas_priv); + + /* + * If no dsp-related kcontrol created, the dsp resource will be freed. + */ + ret = tasdevice_dsp_create_ctrls(tas_priv); + if (ret) { + dev_err(tas_priv->dev, "dsp controls error\n"); + goto out; + } tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; @@ -417,9 +431,8 @@ static void tasdevice_fw_ready(const struct firmware *fmw, tasdevice_prmg_load(tas_priv, 0); tas_priv->cur_prog = 0; 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); + if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) { + /* If DSP FW fail, DSP kcontrol won't be created. */ tasdevice_dsp_remove(tas_priv); } mutex_unlock(&tas_priv->codec_lock); @@ -466,14 +479,14 @@ static int tasdevice_startup(struct snd_pcm_substream *substream, { struct snd_soc_component *codec = dai->component; struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); - int ret = 0; - if (tas_priv->fw_state != TASDEVICE_DSP_FW_ALL_OK) { - dev_err(tas_priv->dev, "DSP bin file not loaded\n"); - ret = -EINVAL; + switch (tas_priv->fw_state) { + case TASDEVICE_RCA_FW_OK: + case TASDEVICE_DSP_FW_ALL_OK: + return 0; + default: + return -EINVAL; } - - return ret; } static int tasdevice_hw_params(struct snd_pcm_substream *substream, From e565ab184946650f19afb9fe74f8be84fcb6d210 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:14 +0200 Subject: [PATCH 146/349] ASoC: codecs: wcd-mbhc: Constify passed MBHC reg fields The wcd-mbhc-v2 helper code/module does not modify passed array of registry fields, thus it can be made const for code safety. It will also allow individual drivers to allocate the array in rodata. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-1-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd-mbhc-v2.c | 4 ++-- sound/soc/codecs/wcd-mbhc-v2.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 0e6218ed0e5e..d589a212b768 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -50,7 +50,7 @@ struct wcd_mbhc { struct wcd_mbhc_config *cfg; const struct wcd_mbhc_cb *mbhc_cb; const struct wcd_mbhc_intr *intr_ids; - struct wcd_mbhc_field *fields; + const struct wcd_mbhc_field *fields; /* Delayed work to report long button press */ struct delayed_work mbhc_btn_dwork; /* Work to handle plug report */ @@ -1505,7 +1505,7 @@ EXPORT_SYMBOL(wcd_dt_parse_mbhc_data); struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, const struct wcd_mbhc_cb *mbhc_cb, const struct wcd_mbhc_intr *intr_ids, - struct wcd_mbhc_field *fields, + const struct wcd_mbhc_field *fields, bool impedance_det_en) { struct device *dev = component->dev; diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h index df68e99c81a3..b977e8f87d7c 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.h +++ b/sound/soc/codecs/wcd-mbhc-v2.h @@ -279,7 +279,7 @@ int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc); struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, const struct wcd_mbhc_cb *mbhc_cb, const struct wcd_mbhc_intr *mbhc_cdc_intr_ids, - struct wcd_mbhc_field *fields, + const struct wcd_mbhc_field *fields, bool impedance_det_en); int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr); @@ -300,7 +300,7 @@ static inline void wcd_mbhc_stop(struct wcd_mbhc *mbhc) static inline struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, const struct wcd_mbhc_cb *mbhc_cb, const struct wcd_mbhc_intr *mbhc_cdc_intr_ids, - struct wcd_mbhc_field *fields, + const struct wcd_mbhc_field *fields, bool impedance_det_en) { return ERR_PTR(-ENOTSUPP); From 60ce48f5311103dd7a09e12d0b75d7ec44e291d9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:15 +0200 Subject: [PATCH 147/349] ASoC: codecs: wcd9335: Drop unused state container fields The driver does not use few 'struct wcd9335_codec' members, so just drop them for smaller code. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-2-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 42a99978fe5a..60e7704e48d2 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -297,7 +297,6 @@ struct wcd9335_codec { struct clk *mclk; struct clk *native_clk; u32 mclk_rate; - u8 version; struct slim_device *slim; struct slim_device *slim_ifc_dev; @@ -347,8 +346,6 @@ struct wcd9335_codec { int dmic_4_5_clk_cnt; int dmic_sample_rate; int mad_dmic_sample_rate; - - int native_clk_users; }; struct wcd9335_irq { @@ -5109,7 +5106,6 @@ static int wcd9335_bring_up(struct wcd9335_codec *wcd) if (byte0 == 0x1) { dev_info(wcd->dev, "WCD9335 CODEC version is v2.0\n"); - wcd->version = WCD9335_VERSION_2_0; regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL, 0x01); regmap_write(rm, WCD9335_SIDO_SIDO_TEST_2, 0x00); regmap_write(rm, WCD9335_SIDO_SIDO_CCL_8, 0x6F); From b2ff7c88bf751fa502f5707f0b7b047afcba87dc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:16 +0200 Subject: [PATCH 148/349] ASoC: codecs: wcd9335: Constify static data Driver does not modify few static data (arrays with sample rates, interrupt description, regmap config), so make them const for code safety. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-3-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 60e7704e48d2..c5ac2d46e556 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -394,13 +394,13 @@ struct interp_sample_rate { int rate_val; }; -static struct interp_sample_rate int_mix_rate_val[] = { +static const struct interp_sample_rate int_mix_rate_val[] = { {48000, 0x4}, /* 48K */ {96000, 0x5}, /* 96K */ {192000, 0x6}, /* 192K */ }; -static struct interp_sample_rate int_prim_rate_val[] = { +static const struct interp_sample_rate int_prim_rate_val[] = { {8000, 0x0}, /* 8K */ {16000, 0x1}, /* 16K */ {24000, -EINVAL},/* 24K */ @@ -4023,7 +4023,7 @@ static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) return ret; } -static struct wcd9335_irq wcd9335_irqs[] = { +static const struct wcd9335_irq wcd9335_irqs[] = { { .irq = WCD9335_IRQ_SLIMBUS, .handler = wcd9335_slimbus_irq, @@ -4960,7 +4960,7 @@ static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg) } } -static struct regmap_config wcd9335_regmap_config = { +static const struct regmap_config wcd9335_regmap_config = { .reg_bits = 16, .val_bits = 8, .cache_type = REGCACHE_MAPLE, @@ -4984,7 +4984,7 @@ static const struct regmap_range_cfg wcd9335_ifc_ranges[] = { }, }; -static struct regmap_config wcd9335_ifc_regmap_config = { +static const struct regmap_config wcd9335_ifc_regmap_config = { .reg_bits = 16, .val_bits = 8, .can_multi_write = true, From 4a03b5dbad466c902d522f3405daa4e5d80578c5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:17 +0200 Subject: [PATCH 149/349] ASoC: codecs: wcd9335: Handle nicer probe deferral and simplify with dev_err_probe() wcd9335_parse_dt() function is called only from probe(), so printing errors on resource acquisition is discouraged, because it can pollute dmesg. Use dev_err_probe() to fix this and also make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-4-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index c5ac2d46e556..334c5241617f 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -5031,22 +5031,16 @@ static int wcd9335_parse_dt(struct wcd9335_codec *wcd) int ret; wcd->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); - if (wcd->reset_gpio < 0) { - dev_err(dev, "Reset GPIO missing from DT\n"); - return wcd->reset_gpio; - } + if (wcd->reset_gpio < 0) + return dev_err_probe(dev, wcd->reset_gpio, "Reset GPIO missing from DT\n"); wcd->mclk = devm_clk_get(dev, "mclk"); - if (IS_ERR(wcd->mclk)) { - dev_err(dev, "mclk not found\n"); - return PTR_ERR(wcd->mclk); - } + if (IS_ERR(wcd->mclk)) + return dev_err_probe(dev, PTR_ERR(wcd->mclk), "mclk not found\n"); wcd->native_clk = devm_clk_get(dev, "slimbus"); - if (IS_ERR(wcd->native_clk)) { - dev_err(dev, "slimbus clock not found\n"); - return PTR_ERR(wcd->native_clk); - } + if (IS_ERR(wcd->native_clk)) + return dev_err_probe(dev, PTR_ERR(wcd->native_clk), "slimbus clock not found\n"); wcd->supplies[0].supply = "vdd-buck"; wcd->supplies[1].supply = "vdd-buck-sido"; @@ -5055,10 +5049,8 @@ static int wcd9335_parse_dt(struct wcd9335_codec *wcd) wcd->supplies[4].supply = "vdd-io"; ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies); - if (ret) { - dev_err(dev, "Failed to get supplies: err = %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to get supplies\n"); return 0; } @@ -5157,10 +5149,8 @@ static int wcd9335_slim_probe(struct slim_device *slim) wcd->dev = dev; ret = wcd9335_parse_dt(wcd); - if (ret) { - dev_err(dev, "Error parsing DT: %d\n", ret); + if (ret) return ret; - } ret = wcd9335_power_on_reset(wcd); if (ret) From 3ed4beba49463997eb9a4afa0d46ece7dc5dbf19 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:18 +0200 Subject: [PATCH 150/349] ASoC: codecs: wcd9335: Drop unneeded error message Error-level should not be used as debugging. The code (function wcd9335_get_dmic_clk_val()) will always be called with same parameters, so this is not really useful debug anyway, so drop it. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-5-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 334c5241617f..6a1376b3b98c 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -2849,10 +2849,6 @@ static u8 wcd9335_get_dmic_clk_val(struct snd_soc_component *component, u32 div_factor; u8 dmic_ctl_val; - dev_err(component->dev, - "%s: mclk_rate = %d, dmic_sample_rate = %d\n", - __func__, mclk_rate, dmic_clk_rate); - /* Default value to return in case of error */ if (mclk_rate == WCD9335_MCLK_CLK_9P6MHZ) dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; From 1d1cda22da5db03a0c794d139e06519e3a94f815 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:19 +0200 Subject: [PATCH 151/349] ASoC: codecs: wcd9335: Drop unused dmic rate handling Driver was prepared to adjust DMIC microphone parameters according to DMIC clock rate which is read from platform data or Devicetree. The latter part never happened, so the code is always called with dmic_clk_rate=0, prints error and uses default/fallback values. All this part can be simplified by dropping dead parts of code. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-6-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 52 +++----------------------------------- 1 file changed, 3 insertions(+), 49 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 6a1376b3b98c..f5fe2583b807 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -344,8 +344,6 @@ struct wcd9335_codec { int dmic_0_1_clk_cnt; int dmic_2_3_clk_cnt; int dmic_4_5_clk_cnt; - int dmic_sample_rate; - int mad_dmic_sample_rate; }; struct wcd9335_irq { @@ -2844,52 +2842,15 @@ out: } static u8 wcd9335_get_dmic_clk_val(struct snd_soc_component *component, - u32 mclk_rate, u32 dmic_clk_rate) + u32 mclk_rate) { - u32 div_factor; u8 dmic_ctl_val; - /* Default value to return in case of error */ if (mclk_rate == WCD9335_MCLK_CLK_9P6MHZ) dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; else dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3; - if (dmic_clk_rate == 0) { - dev_err(component->dev, - "%s: dmic_sample_rate cannot be 0\n", - __func__); - goto done; - } - - div_factor = mclk_rate / dmic_clk_rate; - switch (div_factor) { - case 2: - dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; - break; - case 3: - dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3; - break; - case 4: - dmic_ctl_val = WCD9335_DMIC_CLK_DIV_4; - break; - case 6: - dmic_ctl_val = WCD9335_DMIC_CLK_DIV_6; - break; - case 8: - dmic_ctl_val = WCD9335_DMIC_CLK_DIV_8; - break; - case 16: - dmic_ctl_val = WCD9335_DMIC_CLK_DIV_16; - break; - default: - dev_err(component->dev, - "%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n", - __func__, div_factor, mclk_rate, dmic_clk_rate); - break; - } - -done: return dmic_ctl_val; } @@ -2943,11 +2904,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - dmic_rate_val = - wcd9335_get_dmic_clk_val(comp, - wcd->mclk_rate, - wcd->dmic_sample_rate); - + dmic_rate_val = wcd9335_get_dmic_clk_val(comp, wcd->mclk_rate); (*dmic_clk_cnt)++; if (*dmic_clk_cnt == 1) { snd_soc_component_update_bits(comp, dmic_clk_reg, @@ -2959,10 +2916,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: - dmic_rate_val = - wcd9335_get_dmic_clk_val(comp, - wcd->mclk_rate, - wcd->mad_dmic_sample_rate); + dmic_rate_val = wcd9335_get_dmic_clk_val(comp, wcd->mclk_rate); (*dmic_clk_cnt)--; if (*dmic_clk_cnt == 0) { snd_soc_component_update_bits(comp, dmic_clk_reg, From 1bce5c586ba56dfa6acf8d13f0f608f5f5d717bd Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:20 +0200 Subject: [PATCH 152/349] ASoC: codecs: wcd934x: Drop unused interp path enum The enum with inter path is not used. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-7-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index fcad2c9fba55..cdb68f34e55a 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -475,11 +475,6 @@ enum { INTn_2_INP_SEL_PROXIMITY, }; -enum { - INTERP_MAIN_PATH, - INTERP_MIX_PATH, -}; - struct interp_sample_rate { int sample_rate; int rate_val; From 5ad81bf49a18dc22bd7e1c56f67be9b5eb50267c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:21 +0200 Subject: [PATCH 153/349] ASoC: codecs: wcd934x: Constify static data Driver does not modify few static data (arrays with sample rates, MBHC reg fields, regmap config), so make them const for code safety. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-8-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index cdb68f34e55a..7885aa423886 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -480,7 +480,7 @@ struct interp_sample_rate { int rate_val; }; -static struct interp_sample_rate sr_val_tbl[] = { +static const struct interp_sample_rate sr_val_tbl[] = { {8000, 0x0}, {16000, 0x1}, {32000, 0x3}, @@ -522,7 +522,7 @@ static const struct regmap_range_cfg wcd934x_ifc_ranges[] = { }, }; -static struct regmap_config wcd934x_ifc_regmap_config = { +static const struct regmap_config wcd934x_ifc_regmap_config = { .reg_bits = 16, .val_bits = 8, .max_register = 0xffff, @@ -1212,7 +1212,7 @@ static const struct soc_enum cdc_if_tx13_mux_enum = SOC_ENUM_SINGLE(WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0, ARRAY_SIZE(cdc_if_tx13_mux_text), cdc_if_tx13_mux_text); -static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { +static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD934X_ANA_MBHC_MECH, 0x80), WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD934X_ANA_MBHC_MECH, 0x40), WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD934X_ANA_MBHC_MECH, 0x20), From a252188244aeff72e4331abba2fee6b9093c847b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:22 +0200 Subject: [PATCH 154/349] ASoC: codecs: wcd934x: Drop unused mic bias voltage fields Driver stores the voltage of mic bias in fields in state container structure, but actually never reads them - except for the mic2 bias (micb2_mv field). Drop the fields from the structure so the code will be a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-9-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 7885aa423886..2a5fb4370ba3 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -566,10 +566,7 @@ struct wcd934x_codec { struct mutex micb_lock; u32 micb_ref[WCD934X_MAX_MICBIAS]; u32 pullup_ref[WCD934X_MAX_MICBIAS]; - u32 micb1_mv; u32 micb2_mv; - u32 micb3_mv; - u32 micb4_mv; }; #define to_wcd934x_codec(_hw) container_of(_hw, struct wcd934x_codec, hw) @@ -2203,7 +2200,8 @@ static int wcd934x_get_micbias_val(struct device *dev, const char *micbias, mv = WCD934X_DEF_MICBIAS_MV; } - *micb_mv = mv; + if (micb_mv) + *micb_mv = mv; return (mv - 1000) / 50; } @@ -2215,17 +2213,14 @@ static int wcd934x_init_dmic(struct snd_soc_component *comp) u32 def_dmic_rate, dmic_clk_drv; vout_ctl_1 = wcd934x_get_micbias_val(comp->dev, - "qcom,micbias1-microvolt", - &wcd->micb1_mv); + "qcom,micbias1-microvolt", NULL); vout_ctl_2 = wcd934x_get_micbias_val(comp->dev, "qcom,micbias2-microvolt", &wcd->micb2_mv); vout_ctl_3 = wcd934x_get_micbias_val(comp->dev, - "qcom,micbias3-microvolt", - &wcd->micb3_mv); + "qcom,micbias3-microvolt", NULL); vout_ctl_4 = wcd934x_get_micbias_val(comp->dev, - "qcom,micbias4-microvolt", - &wcd->micb4_mv); + "qcom,micbias4-microvolt", NULL); snd_soc_component_update_bits(comp, WCD934X_ANA_MICB1, WCD934X_MICB_VAL_MASK, vout_ctl_1); From 9ea22713227397b56a2b36a68c8bda13f0b43d70 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:23 +0200 Subject: [PATCH 155/349] ASoC: codecs: wcd934x: Handle nicer probe deferral and simplify with dev_err_probe() wcd934x_codec_parse_data() function is called only from probe(), so printing errors on resource acquisition is discouraged, because it can pollute dmesg in case of probe deferral. The actual deferral is here unlikely, but still the code is a bit simpler with dev_err_probe(). Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-10-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 2a5fb4370ba3..d1bbc963856b 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -5856,17 +5856,13 @@ static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd) struct device_node *ifc_dev_np; ifc_dev_np = of_parse_phandle(dev->of_node, "slim-ifc-dev", 0); - if (!ifc_dev_np) { - dev_err(dev, "No Interface device found\n"); - return -EINVAL; - } + if (!ifc_dev_np) + return dev_err_probe(dev, -EINVAL, "No Interface device found\n"); wcd->sidev = of_slim_get_device(wcd->sdev->ctrl, ifc_dev_np); of_node_put(ifc_dev_np); - if (!wcd->sidev) { - dev_err(dev, "Unable to get SLIM Interface device\n"); - return -EINVAL; - } + if (!wcd->sidev) + return dev_err_probe(dev, -EINVAL, "Unable to get SLIM Interface device\n"); slim_get_logical_addr(wcd->sidev); wcd->if_regmap = regmap_init_slimbus(wcd->sidev, @@ -5912,10 +5908,8 @@ static int wcd934x_codec_probe(struct platform_device *pdev) mutex_init(&wcd->micb_lock); ret = wcd934x_codec_parse_data(wcd); - if (ret) { - dev_err(wcd->dev, "Failed to get SLIM IRQ\n"); + if (ret) return ret; - } /* set default rate 9P6MHz */ regmap_update_bits(wcd->regmap, WCD934X_CODEC_RPM_CLK_MCLK_CFG, From 0ad42c04e9b223d913ad4b1463c0f1cdc00f3cc5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:24 +0200 Subject: [PATCH 156/349] ASoC: codecs: wcd937x: Constify static data Driver does not modify few static data (MBHC reg fields, IRQ chip), so make them const for code safety. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-11-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index ef649ed77fb2..4cf17d62a0bc 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -133,7 +133,7 @@ struct wcd937x_mbhc_zdet_param { u16 btn7; }; -static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { +static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD937X_ANA_MBHC_MECH, 0x80), WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD937X_ANA_MBHC_MECH, 0x40), WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD937X_ANA_MBHC_MECH, 0x20), @@ -227,7 +227,7 @@ static const u32 wcd937x_config_regs[] = { WCD937X_DIGITAL_INTR_LEVEL_0, }; -static struct regmap_irq_chip wcd937x_regmap_irq_chip = { +static const struct regmap_irq_chip wcd937x_regmap_irq_chip = { .name = "wcd937x", .irqs = wcd937x_irqs, .num_irqs = ARRAY_SIZE(wcd937x_irqs), @@ -2503,7 +2503,7 @@ static irqreturn_t wcd937x_wd_handle_irq(int irq, void *data) return IRQ_HANDLED; } -static struct irq_chip wcd_irq_chip = { +static const struct irq_chip wcd_irq_chip = { .name = "WCD937x", }; From c8ed66cbc3b7ccd9e5ae98b06023c1fe3e834ca8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:25 +0200 Subject: [PATCH 157/349] ASoC: codecs: wcd937x: Constify wcd937x_sdw_ch_info Driver does not modify static wcd937x_sdw_ch_info array, so it can be made const for code safety. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-12-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x-sdw.c | 4 ++-- sound/soc/codecs/wcd937x.c | 2 +- sound/soc/codecs/wcd937x.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c index a45025bf96c6..a24d6c620dba 100644 --- a/sound/soc/codecs/wcd937x-sdw.c +++ b/sound/soc/codecs/wcd937x-sdw.c @@ -19,7 +19,7 @@ #include #include "wcd937x.h" -static struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = { +static const struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = { WCD_SDW_CH(WCD937X_HPH_L, WCD937X_HPH_PORT, BIT(0)), WCD_SDW_CH(WCD937X_HPH_R, WCD937X_HPH_PORT, BIT(1)), WCD_SDW_CH(WCD937X_CLSH, WCD937X_CLSH_PORT, BIT(0)), @@ -30,7 +30,7 @@ static struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = { WCD_SDW_CH(WCD937X_DSD_R, WCD937X_DSD_PORT, BIT(1)), }; -static struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = { +static const struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = { WCD_SDW_CH(WCD937X_ADC1, WCD937X_ADC_1_PORT, BIT(0)), WCD_SDW_CH(WCD937X_ADC2, WCD937X_ADC_2_3_PORT, BIT(0)), WCD_SDW_CH(WCD937X_ADC3, WCD937X_ADC_2_3_PORT, BIT(0)), diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 4cf17d62a0bc..8b000ba9a469 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -1244,7 +1244,7 @@ static int wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, static int wcd937x_connect_port(struct wcd937x_sdw_priv *wcd, u8 port_idx, u8 ch_id, bool enable) { struct sdw_port_config *port_config = &wcd->port_config[port_idx - 1]; - struct wcd937x_sdw_ch_info *ch_info = &wcd->ch_info[ch_id]; + const struct wcd937x_sdw_ch_info *ch_info = &wcd->ch_info[ch_id]; u8 port_num = ch_info->port_num; u8 ch_mask = ch_info->ch_mask; diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h index e6e1ad5926d5..6f857ce7d8b7 100644 --- a/sound/soc/codecs/wcd937x.h +++ b/sound/soc/codecs/wcd937x.h @@ -522,7 +522,7 @@ struct wcd937x_sdw_priv { struct sdw_stream_config sconfig; struct sdw_stream_runtime *sruntime; struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS]; - struct wcd937x_sdw_ch_info *ch_info; + const struct wcd937x_sdw_ch_info *ch_info; bool port_enable[WCD937X_MAX_SWR_CH_IDS]; int active_ports; int num_ports; From d8e746719d705427e69c7f0ac2ca20aaf560a03e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:26 +0200 Subject: [PATCH 158/349] ASoC: codecs: wcd937x: Drop unused enums, defines and types Few declarations (defines, struct codec_port_info, enums) are not used and can be safely dropped. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-13-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.h | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h index 6f857ce7d8b7..834a3e7713a3 100644 --- a/sound/soc/codecs/wcd937x.h +++ b/sound/soc/codecs/wcd937x.h @@ -488,23 +488,6 @@ #define WCD937X_MAX_SWR_PORTS 5 #define WCD937X_MAX_SWR_CH_IDS 15 -/* Convert from vout ctl to micbias voltage in mV */ -#define WCD_VOUT_CTL_TO_MICB(v) (1000 + (v) * 50) -#define MAX_PORT 8 -#define MAX_CH_PER_PORT 8 -#define MAX_TX_PWR_CH 2 -#define SWR_NUM_PORTS 4 - -#define WCD937X_MAX_SLAVE_PORT_TYPES 10 - -struct codec_port_info { - u32 slave_port_type; - u32 master_port_type; - u32 ch_mask; - u32 num_ch; - u32 ch_rate; -}; - struct wcd937x_sdw_ch_info { int port_num; unsigned int ch_mask; @@ -570,12 +553,6 @@ int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd, } #endif -enum { - WCD_RX1, - WCD_RX2, - WCD_RX3 -}; - enum { /* INTR_CTRL_INT_MASK_0 */ WCD937X_IRQ_MBHC_BUTTON_PRESS_DET = 0, @@ -645,9 +622,4 @@ enum wcd937x_rx_sdw_channels { WCD937X_DSD_L, }; -enum { - WCD937X_SDW_DIR_RX, - WCD937X_SDW_DIR_TX, -}; - #endif From c2d9fd2e94588eb83f8855e942d77b5f539c5a5f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:27 +0200 Subject: [PATCH 159/349] ASoC: codecs: wcd937x: Drop unused state container fields The driver does not use few 'struct wcd937x_priv' and 'struct wcd937x_sdw_priv' members, so just drop them for smaller code. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-14-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 4 ---- sound/soc/codecs/wcd937x.h | 1 - 2 files changed, 5 deletions(-) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 8b000ba9a469..96e2989f9722 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -103,7 +103,6 @@ struct wcd937x_priv { u32 micb1_mv; u32 micb2_mv; u32 micb3_mv; - u32 micb4_mv; /* 9375 only */ int hphr_pdm_wd_int; int hphl_pdm_wd_int; int aux_pdm_wd_int; @@ -113,9 +112,6 @@ struct wcd937x_priv { struct gpio_desc *us_euro_gpio; struct gpio_desc *reset_gpio; - int dmic_0_1_clk_cnt; - int dmic_2_3_clk_cnt; - int dmic_4_5_clk_cnt; atomic_t rx_clk_cnt; atomic_t ana_clk_count; }; diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h index 834a3e7713a3..f267c66ca959 100644 --- a/sound/soc/codecs/wcd937x.h +++ b/sound/soc/codecs/wcd937x.h @@ -508,7 +508,6 @@ struct wcd937x_sdw_priv { const struct wcd937x_sdw_ch_info *ch_info; bool port_enable[WCD937X_MAX_SWR_CH_IDS]; int active_ports; - int num_ports; bool is_tx; struct wcd937x_priv *wcd937x; struct irq_domain *slave_irq; From 6dc7b8a10419a267cd5eb7ac2bb407f7fc7865e2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:28 +0200 Subject: [PATCH 160/349] ASoC: codecs: wcd937x: Drop unused chipid member The driver stores the read chipid in 'struct wcd937x_priv' but never needs it after. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-15-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 96e2989f9722..4beb70bc4d8c 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -99,7 +99,6 @@ struct wcd937x_priv { s32 pullup_ref[WCD937X_MAX_MICBIAS]; u32 hph_mode; int ear_rx_path; - u32 chipid; u32 micb1_mv; u32 micb2_mv; u32 micb3_mv; @@ -2539,6 +2538,7 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component) struct device *dev = component->dev; unsigned long time_left; int i, ret; + u32 chipid; time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete, msecs_to_jiffies(5000)); @@ -2552,11 +2552,10 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component) if (ret < 0) return ret; - wcd937x->chipid = (snd_soc_component_read(component, - WCD937X_DIGITAL_EFUSE_REG_0) & 0x1e) >> 1; - if (wcd937x->chipid != CHIPID_WCD9370 && - wcd937x->chipid != CHIPID_WCD9375) { - dev_err(dev, "Got unknown chip id: 0x%x\n", wcd937x->chipid); + chipid = (snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_0) & 0x1e) >> 1; + if (chipid != CHIPID_WCD9370 && chipid != CHIPID_WCD9375) { + dev_err(dev, "Got unknown chip id: 0x%x\n", chipid); pm_runtime_put(dev); return -EINVAL; } @@ -2605,7 +2604,7 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component) disable_irq_nosync(wcd937x->hphl_pdm_wd_int); disable_irq_nosync(wcd937x->aux_pdm_wd_int); - if (wcd937x->chipid == CHIPID_WCD9375) { + if (chipid == CHIPID_WCD9375) { ret = snd_soc_dapm_new_controls(dapm, wcd9375_dapm_widgets, ARRAY_SIZE(wcd9375_dapm_widgets)); if (ret < 0) { From 424e6bc4328b39a924cc2acb251868cfd23fe369 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:29 +0200 Subject: [PATCH 161/349] ASoC: codecs: wcd938x: Constify static data Driver does not modify few static data (MBHC reg fields, IRQ chip), so make them const for code safety. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-16-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 73387152ce02..124c18712422 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -221,7 +221,7 @@ struct wcd938x_mbhc_zdet_param { u16 btn7; }; -static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { +static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD938X_ANA_MBHC_MECH, 0x80), WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD938X_ANA_MBHC_MECH, 0x40), WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD938X_ANA_MBHC_MECH, 0x20), @@ -3027,7 +3027,7 @@ static irqreturn_t wcd938x_wd_handle_irq(int irq, void *data) return IRQ_HANDLED; } -static struct irq_chip wcd_irq_chip = { +static const struct irq_chip wcd_irq_chip = { .name = "WCD938x", }; From af57d5e3b58886ee5efc6ba9d0e25c8d1d3c3c37 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:30 +0200 Subject: [PATCH 162/349] ASoC: codecs: wcd938x: Constify wcd938x_sdw_ch_info Driver does not modify static wcd938x_sdw_ch_info array, so it can be made const for code safety. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-17-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x-sdw.c | 4 ++-- sound/soc/codecs/wcd938x.c | 2 +- sound/soc/codecs/wcd938x.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c index a1f04010da95..c995bcc59ead 100644 --- a/sound/soc/codecs/wcd938x-sdw.c +++ b/sound/soc/codecs/wcd938x-sdw.c @@ -21,7 +21,7 @@ #define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m)) -static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = { +static const struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = { WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)), WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)), WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)), @@ -32,7 +32,7 @@ static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = { WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)), }; -static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = { +static const struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = { WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)), WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)), WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)), diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 124c18712422..12b32d5dc580 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -418,7 +418,7 @@ static int wcd938x_io_init(struct wcd938x_priv *wcd938x) } -static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info, +static int wcd938x_sdw_connect_port(const struct wcd938x_sdw_ch_info *ch_info, struct sdw_port_config *port_config, u8 enable) { diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h index 0d332cb555ac..09e39a19fbe4 100644 --- a/sound/soc/codecs/wcd938x.h +++ b/sound/soc/codecs/wcd938x.h @@ -653,7 +653,7 @@ struct wcd938x_sdw_priv { struct sdw_stream_config sconfig; struct sdw_stream_runtime *sruntime; struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS]; - struct wcd938x_sdw_ch_info *ch_info; + const struct wcd938x_sdw_ch_info *ch_info; bool port_enable[WCD938X_MAX_SWR_CH_IDS]; int active_ports; int num_ports; From 43e7400f6bf51ecedf4ddad942cd812fe351ce74 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:31 +0200 Subject: [PATCH 163/349] ASoC: codecs: wcd938x: Drop unused RX/TX direction enum The enum with RX/TX soundwire direction is not used. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-18-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h index 09e39a19fbe4..45b7de242209 100644 --- a/sound/soc/codecs/wcd938x.h +++ b/sound/soc/codecs/wcd938x.h @@ -642,10 +642,6 @@ enum wcd938x_rx_sdw_channels { WCD938X_DSD_R, WCD938X_DSD_L, }; -enum { - WCD938X_SDW_DIR_RX, - WCD938X_SDW_DIR_TX, -}; struct wcd938x_priv; struct wcd938x_sdw_priv { From 3f1deca19e68e48bd89a72c4fe648275d9af574b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:32 +0200 Subject: [PATCH 164/349] ASoC: codecs: wcd938x: Drop unused num_ports field The driver does not use few 'num_ports' in 'struct wcd938x_sdw_priv'. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-19-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h index 45b7de242209..b2ad98026ae2 100644 --- a/sound/soc/codecs/wcd938x.h +++ b/sound/soc/codecs/wcd938x.h @@ -652,7 +652,6 @@ struct wcd938x_sdw_priv { const struct wcd938x_sdw_ch_info *ch_info; bool port_enable[WCD938X_MAX_SWR_CH_IDS]; int active_ports; - int num_ports; bool is_tx; struct wcd938x_priv *wcd938x; struct irq_domain *slave_irq; From 8e5d5b2c96fadecdaebff5afcbb7f51580701122 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:33 +0200 Subject: [PATCH 165/349] ASoC: codecs: wcd939x: Constify static data Driver does not modify few static data (MBHC reg fields, IRQ chip), so make them const for code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-20-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 72d8a6a35052..1f94f49f9829 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -220,7 +220,7 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); -static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { +static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD939X_ANA_MBHC_MECH, 0x80), WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD939X_ANA_MBHC_MECH, 0x40), WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD939X_ANA_MBHC_MECH, 0x20), @@ -291,7 +291,7 @@ static const struct regmap_irq wcd939x_irqs[WCD939X_NUM_IRQS] = { REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), }; -static struct regmap_irq_chip wcd939x_regmap_irq_chip = { +static const struct regmap_irq_chip wcd939x_regmap_irq_chip = { .name = "wcd939x", .irqs = wcd939x_irqs, .num_irqs = ARRAY_SIZE(wcd939x_irqs), @@ -2957,7 +2957,7 @@ static irqreturn_t wcd939x_wd_handle_irq(int irq, void *data) * \- regmap_irq_thread() * \- handle_nested_irq(i) */ -static struct irq_chip wcd_irq_chip = { +static const struct irq_chip wcd_irq_chip = { .name = "WCD939x", }; From f49100faccb5d2ffb4c9e5e4bba6173f5ac43d22 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:34 +0200 Subject: [PATCH 166/349] ASoC: codecs: wcd939x: Constify wcd939x_sdw_ch_info Driver does not modify static wcd939x_sdw_ch_info array, so it can be made const for code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-21-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x-sdw.c | 4 ++-- sound/soc/codecs/wcd939x.c | 2 +- sound/soc/codecs/wcd939x.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c index 8acb5651c5bc..94b1e99a3ca0 100644 --- a/sound/soc/codecs/wcd939x-sdw.c +++ b/sound/soc/codecs/wcd939x-sdw.c @@ -23,7 +23,7 @@ #define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m)) -static struct wcd939x_sdw_ch_info wcd939x_sdw_rx_ch_info[] = { +static const struct wcd939x_sdw_ch_info wcd939x_sdw_rx_ch_info[] = { WCD_SDW_CH(WCD939X_HPH_L, WCD939X_HPH_PORT, BIT(0)), WCD_SDW_CH(WCD939X_HPH_R, WCD939X_HPH_PORT, BIT(1)), WCD_SDW_CH(WCD939X_CLSH, WCD939X_CLSH_PORT, BIT(0)), @@ -36,7 +36,7 @@ static struct wcd939x_sdw_ch_info wcd939x_sdw_rx_ch_info[] = { WCD_SDW_CH(WCD939X_HIFI_PCM_R, WCD939X_HIFI_PCM_PORT, BIT(1)), }; -static struct wcd939x_sdw_ch_info wcd939x_sdw_tx_ch_info[] = { +static const struct wcd939x_sdw_ch_info wcd939x_sdw_tx_ch_info[] = { WCD_SDW_CH(WCD939X_ADC1, WCD939X_ADC_1_4_PORT, BIT(0)), WCD_SDW_CH(WCD939X_ADC2, WCD939X_ADC_1_4_PORT, BIT(1)), WCD_SDW_CH(WCD939X_ADC3, WCD939X_ADC_1_4_PORT, BIT(2)), diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 1f94f49f9829..66af035bd0e5 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -414,7 +414,7 @@ static int wcd939x_io_init(struct snd_soc_component *component) return 0; } -static int wcd939x_sdw_connect_port(struct wcd939x_sdw_ch_info *ch_info, +static int wcd939x_sdw_connect_port(const struct wcd939x_sdw_ch_info *ch_info, struct sdw_port_config *port_config, u8 enable) { diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h index 756f497a337c..a6c9c6cee056 100644 --- a/sound/soc/codecs/wcd939x.h +++ b/sound/soc/codecs/wcd939x.h @@ -914,7 +914,7 @@ struct wcd939x_sdw_priv { struct sdw_stream_config sconfig; struct sdw_stream_runtime *sruntime; struct sdw_port_config port_config[WCD939X_MAX_SWR_PORTS]; - struct wcd939x_sdw_ch_info *ch_info; + const struct wcd939x_sdw_ch_info *ch_info; bool port_enable[WCD939X_MAX_SWR_CH_IDS]; int active_ports; int num_ports; From 2642b6aa9d0f43c52c83461bc7ae4917336e7643 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:35 +0200 Subject: [PATCH 167/349] ASoC: codecs: wcd939x: Drop unused RX/TX direction enum The enum with RX/TX soundwire direction is not used. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-22-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h index a6c9c6cee056..0aa4d9d542c6 100644 --- a/sound/soc/codecs/wcd939x.h +++ b/sound/soc/codecs/wcd939x.h @@ -903,11 +903,6 @@ enum wcd939x_rx_sdw_channels { WCD939X_HIFI_PCM_R, }; -enum { - WCD939X_SDW_DIR_RX, - WCD939X_SDW_DIR_TX, -}; - struct wcd939x_priv; struct wcd939x_sdw_priv { struct sdw_slave *sdev; From 34935cd4721f0492eafbc516dd1fc7f5f687fa76 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jun 2024 18:15:36 +0200 Subject: [PATCH 168/349] ASoC: codecs: wcd939x: Drop unused num_ports field The driver does not use few 'num_ports' in 'struct wcd939x_sdw_priv'. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Link: https://msgid.link/r/20240612-asoc-wcd9xxx-wide-cleanups-v1-23-0d15885b2a06@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h index 0aa4d9d542c6..1571c2120cfc 100644 --- a/sound/soc/codecs/wcd939x.h +++ b/sound/soc/codecs/wcd939x.h @@ -912,7 +912,6 @@ struct wcd939x_sdw_priv { const struct wcd939x_sdw_ch_info *ch_info; bool port_enable[WCD939X_MAX_SWR_CH_IDS]; int active_ports; - int num_ports; bool is_tx; struct wcd939x_priv *wcd939x; struct irq_domain *slave_irq; From 3ec1428d7b7c519d757a013cef908d7e33dee882 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Mon, 17 Jun 2024 14:53:38 +0100 Subject: [PATCH 169/349] ASoC: cs35l56: Accept values greater than 0 as IRQ numbers IRQ lookup functions such as those in ACPI can return error values when an IRQ is not defined. The i2c core driver converts the error codes to a value of 0 and the SPI bus driver passes them unaltered to client device drivers. The cs35l56 driver should only accept positive non-zero values as IRQ numbers. Signed-off-by: Simon Trimmer Fixes: 8a731fd37f8b ("ASoC: cs35l56: Move utility functions to shared file") Link: https://msgid.link/r/20240617135338.82006-1-simont@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56-shared.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index e89027cd40d1..569bab3a2a6e 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -393,7 +393,7 @@ int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) { int ret; - if (!irq) + if (irq < 1) return 0; ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq, From ca73d314363d6682b6c736ea45e3a4ca551923a6 Mon Sep 17 00:00:00 2001 From: Khanh Le Date: Wed, 19 Jun 2024 00:59:36 +0000 Subject: [PATCH 170/349] ASoC: Add ak4619 codec support Add support for the Asahi Kasei AK4619 audio codec. [Kuninori cleanuped and adjusted to upstream code] Signed-off-by: Khanh Le Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/87iky5wxvr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ak4619.c | 912 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 919 insertions(+) create mode 100644 sound/soc/codecs/ak4619.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7b99556f24d3..910303adef70 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -45,6 +45,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AK4535 imply SND_SOC_AK4554 imply SND_SOC_AK4613 + imply SND_SOC_AK4619 imply SND_SOC_AK4641 imply SND_SOC_AK4642 imply SND_SOC_AK4671 @@ -598,6 +599,10 @@ config SND_SOC_AK4613 tristate "AKM AK4613 CODEC" depends on I2C +config SND_SOC_AK4619 + tristate "AKM AK4619 CODEC" + depends on I2C + config SND_SOC_AK4641 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index ca69f35cc0f7..2db7760d2aac 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -39,6 +39,7 @@ snd-soc-ak4458-y := ak4458.o snd-soc-ak4535-y := ak4535.o snd-soc-ak4554-y := ak4554.o snd-soc-ak4613-y := ak4613.o +snd-soc-ak4619-y := ak4619.o snd-soc-ak4641-y := ak4641.o snd-soc-ak4642-y := ak4642.o snd-soc-ak4671-y := ak4671.o @@ -439,6 +440,7 @@ obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o obj-$(CONFIG_SND_SOC_AK4613) += snd-soc-ak4613.o +obj-$(CONFIG_SND_SOC_AK4619) += snd-soc-ak4619.o obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o diff --git a/sound/soc/codecs/ak4619.c b/sound/soc/codecs/ak4619.c new file mode 100644 index 000000000000..cbe27abe1f50 --- /dev/null +++ b/sound/soc/codecs/ak4619.c @@ -0,0 +1,912 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ak4619.c -- Asahi Kasei ALSA SoC Audio driver + * + * Copyright (C) 2023 Renesas Electronics Corporation + * Khanh Le + * + * Based on ak4613.c by Kuninori Morimoto + * Based on da7213.c by Adam Thomson + * Based on ak4641.c by Harald Welte + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Registers + */ + +#define PWR_MGMT 0x00 /* Power Management */ +#define AU_IFF1 0x01 /* Audio I/F Format */ +#define AU_IFF2 0x02 /* Audio I/F Format (Extended) */ +#define SYS_CLK 0x03 /* System Clock Setting */ +#define MIC_AMP1 0x04 /* MIC AMP Gain 1 */ +#define MIC_AMP2 0x05 /* MIC AMP Gain 2 */ +#define LADC1 0x06 /* ADC1 Lch Digital Volume */ +#define RADC1 0x07 /* ADC1 Rch Digital Volume */ +#define LADC2 0x08 /* ADC2 Lch Digital Volume */ +#define RADC2 0x09 /* ADC2 Rch Digital Volume */ +#define ADC_DF 0x0a /* ADC Digital Filter Setting */ +#define ADC_AI 0x0b /* ADC Analog Input Setting */ +#define ADC_MHPF 0x0D /* ADC Mute & HPF Control */ +#define LDAC1 0x0E /* DAC1 Lch Digital Volume */ +#define RDAC1 0x0F /* DAC1 Rch Digital Volume */ +#define LDAC2 0x10 /* DAC2 Lch Digital Volume */ +#define RDAC2 0x11 /* DAC2 Rch Digital Volume */ +#define DAC_IS 0x12 /* DAC Input Select Setting */ +#define DAC_DEMP 0x13 /* DAC De-Emphasis Setting */ +#define DAC_MF 0x14 /* DAC Mute & Filter Setting */ + +/* + * Bit fields + */ + +/* Power Management */ +#define PMAD2 BIT(5) +#define PMAD1 BIT(4) +#define PMDA2 BIT(2) +#define PMDA1 BIT(1) +#define RSTN BIT(0) + +/* Audio_I/F Format */ +#define DCF_STEREO_I2S (0x0 << 4) +#define DCF_STEREO_MSB (0x5 << 4) +#define DCF_PCM_SF (0x6 << 4) +#define DCF_PCM_LF (0x7 << 4) +#define DSL_32 (0x3 << 2) +#define DCF_MASK (0x7 << 4) +#define DSL_MASK (0x3 << 2) +#define BCKP BIT(1) + +/* Audio_I/F Format (Extended) */ +#define DIDL_24 (0x0 << 2) +#define DIDL_20 (0x1 << 2) +#define DIDL_16 (0x2 << 2) +#define DIDL_32 (0x3 << 2) +#define DODL_24 (0x0 << 0) +#define DODL_20 (0x1 << 0) +#define DODL_16 (0x2 << 0) +#define DIDL_MASK (0x3 << 2) +#define DODL_MASK (0x3 << 0) +#define SLOT BIT(4) + +/* System Clock Setting */ +#define FS_MASK 0x7 + +/* MIC AMP Gain */ +#define MGNL_SHIFT 4 +#define MGNR_SHIFT 0 +#define MGN_MAX 0xB + +/* ADC Digital Volume */ +#define VOLAD_SHIFT 0 +#define VOLAD_MAX 0xFF + +/* ADC Digital Filter Setting */ +#define AD1SL_SHIFT 0 +#define AD2SL_SHIFT 4 + +/* Analog Input Select */ +#define AD1LSEL_SHIFT 6 +#define AD1RSEL_SHIFT 4 +#define AD2LSEL_SHIFT 2 +#define AD2RSEL_SHIFT 0 + +/* ADC Mute & HPF Control */ +#define ATSPAD_SHIFT 7 +#define AD1MUTE_SHIFT 5 +#define AD2MUTE_SHIFT 6 +#define AD1MUTE_MAX 1 +#define AD2MUTE_MAX 1 +#define AD1MUTE_EN BIT(5) +#define AD2MUTE_EN BIT(6) +#define AD1HPFN_SHIFT 1 +#define AD1HPFN_MAX 1 +#define AD2HPFN_SHIFT 2 +#define AD2HPFN_MAX 1 + +/* DAC Digital Volume */ +#define VOLDA_SHIFT 0 +#define VOLDA_MAX 0xFF + +/* DAC Input Select Setting */ +#define DAC1SEL_SHIFT 0 +#define DAC2SEL_SHIFT 2 + +/* DAC De-Emphasis Setting */ +#define DEM1_32000 (0x3 << 0) +#define DEM1_44100 (0x0 << 0) +#define DEM1_48000 (0x2 << 0) +#define DEM1_OFF (0x1 << 0) +#define DEM2_32000 (0x3 << 2) +#define DEM2_44100 (0x0 << 2) +#define DEM2_48000 (0x2 << 2) +#define DEM2_OFF (0x1 << 2) +#define DEM1_MASK (0x3 << 0) +#define DEM2_MASK (0x3 << 2) +#define DEM1_SHIFT 0 +#define DEM2_SHIFT 2 + +/* DAC Mute & Filter Setting */ +#define DA1MUTE_SHIFT 4 +#define DA1MUTE_MAX 1 +#define DA2MUTE_SHIFT 5 +#define DA2MUTE_MAX 1 +#define DA1MUTE_EN BIT(4) +#define DA2MUTE_EN BIT(5) +#define ATSPDA_SHIFT 7 +#define DA1SL_SHIFT 0 +#define DA2SL_SHIFT 2 + +/* Codec private data */ +struct ak4619_priv { + struct regmap *regmap; + struct snd_pcm_hw_constraint_list constraint; + int deemph_en; + unsigned int playback_rate; + unsigned int sysclk; +}; + +/* + * DAC Volume + * + * max : 0x00 : +12.0 dB + * ( 0.5 dB step ) + * min : 0xFE : -115.0 dB + * mute: 0xFF + */ +static const DECLARE_TLV_DB_SCALE(dac_tlv, -11550, 50, 1); + +/* + * MIC Volume + * + * max : 0x0B : +27.0 dB + * ( 3 dB step ) + * min: 0x00 : -6.0 dB + */ +static const DECLARE_TLV_DB_SCALE(mic_tlv, -600, 300, 0); + +/* + * ADC Volume + * + * max : 0x00 : +24.0 dB + * ( 0.5 dB step ) + * min : 0xFE : -103.0 dB + * mute: 0xFF + */ +static const DECLARE_TLV_DB_SCALE(adc_tlv, -10350, 50, 1); + +/* ADC & DAC Volume Level Transition Time select */ +static const char * const ak4619_vol_trans_txt[] = { + "4/fs", "16/fs" +}; + +static SOC_ENUM_SINGLE_DECL(ak4619_adc_vol_trans, ADC_MHPF, ATSPAD_SHIFT, ak4619_vol_trans_txt); +static SOC_ENUM_SINGLE_DECL(ak4619_dac_vol_trans, DAC_MF, ATSPDA_SHIFT, ak4619_vol_trans_txt); + +/* ADC Digital Filter select */ +static const char * const ak4619_adc_digi_fil_txt[] = { + "Sharp Roll-Off Filter", + "Slow Roll-Off Filter", + "Short Delay Sharp Roll-Off Filter", + "Short Delay Slow Roll-Off Filter", + "Voice Filter" +}; + +static SOC_ENUM_SINGLE_DECL(ak4619_adc_1_digi_fil, ADC_DF, AD1SL_SHIFT, ak4619_adc_digi_fil_txt); +static SOC_ENUM_SINGLE_DECL(ak4619_adc_2_digi_fil, ADC_DF, AD2SL_SHIFT, ak4619_adc_digi_fil_txt); + +/* DAC De-Emphasis Filter select */ +static const char * const ak4619_dac_de_emp_txt[] = { + "44.1kHz", "OFF", "48kHz", "32kHz" +}; + +static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_de_emp, DAC_DEMP, DEM1_SHIFT, ak4619_dac_de_emp_txt); +static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_de_emp, DAC_DEMP, DEM2_SHIFT, ak4619_dac_de_emp_txt); + +/* DAC Digital Filter select */ +static const char * const ak4619_dac_digi_fil_txt[] = { + "Sharp Roll-Off Filter", + "Slow Roll-Off Filter", + "Short Delay Sharp Roll-Off Filter", + "Short Delay Slow Roll-Off Filter" +}; + +static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_digi_fil, DAC_MF, DA1SL_SHIFT, ak4619_dac_digi_fil_txt); +static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_digi_fil, DAC_MF, DA2SL_SHIFT, ak4619_dac_digi_fil_txt); + +/* + * Control functions + */ + +static void ak4619_set_deemph(struct snd_soc_component *component) +{ + struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component); + u8 dem = 0; + + if (!ak4619->deemph_en) + return; + + switch (ak4619->playback_rate) { + case 32000: + dem |= DEM1_32000 | DEM2_32000; + break; + case 44100: + dem |= DEM1_44100 | DEM2_44100; + break; + case 48000: + dem |= DEM1_48000 | DEM2_48000; + break; + default: + dem |= DEM1_OFF | DEM2_OFF; + break; + } + snd_soc_component_update_bits(component, DAC_DEMP, DEM1_MASK | DEM2_MASK, dem); +} + +static int ak4619_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component); + int deemph_en = ucontrol->value.integer.value[0]; + int ret = 0; + + switch (deemph_en) { + case 0: + case 1: + break; + default: + return -EINVAL; + } + + if (ak4619->deemph_en != deemph_en) + ret = 1; /* The value changed */ + + ak4619->deemph_en = deemph_en; + ak4619_set_deemph(component); + + return ret; +} + +static int ak4619_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = ak4619->deemph_en; + + return 0; +}; + +/* + * KControls + */ +static const struct snd_kcontrol_new ak4619_snd_controls[] = { + + /* Volume controls */ + SOC_DOUBLE_R_TLV("DAC 1 Volume", LDAC1, RDAC1, VOLDA_SHIFT, VOLDA_MAX, 1, dac_tlv), + SOC_DOUBLE_R_TLV("DAC 2 Volume", LDAC2, RDAC2, VOLDA_SHIFT, VOLDA_MAX, 1, dac_tlv), + SOC_DOUBLE_R_TLV("ADC 1 Volume", LADC1, RADC1, VOLAD_SHIFT, VOLAD_MAX, 1, adc_tlv), + SOC_DOUBLE_R_TLV("ADC 2 Volume", LADC2, RADC2, VOLAD_SHIFT, VOLAD_MAX, 1, adc_tlv), + + SOC_DOUBLE_TLV("Mic 1 Volume", MIC_AMP1, MGNL_SHIFT, MGNR_SHIFT, MGN_MAX, 0, mic_tlv), + SOC_DOUBLE_TLV("Mic 2 Volume", MIC_AMP2, MGNL_SHIFT, MGNR_SHIFT, MGN_MAX, 0, mic_tlv), + + /* Volume Level Transition Time controls */ + SOC_ENUM("ADC Volume Level Transition Time", ak4619_adc_vol_trans), + SOC_ENUM("DAC Volume Level Transition Time", ak4619_dac_vol_trans), + + /* Mute controls */ + SOC_SINGLE("DAC 1 Switch", DAC_MF, DA1MUTE_SHIFT, DA1MUTE_MAX, 1), + SOC_SINGLE("DAC 2 Switch", DAC_MF, DA2MUTE_SHIFT, DA2MUTE_MAX, 1), + + SOC_SINGLE("ADC 1 Switch", ADC_MHPF, AD1MUTE_SHIFT, AD1MUTE_MAX, 1), + SOC_SINGLE("ADC 2 Switch", ADC_MHPF, AD2MUTE_SHIFT, AD2MUTE_MAX, 1), + + /* Filter controls */ + SOC_ENUM("ADC 1 Digital Filter", ak4619_adc_1_digi_fil), + SOC_ENUM("ADC 2 Digital Filter", ak4619_adc_2_digi_fil), + + SOC_SINGLE("ADC 1 HPF", ADC_MHPF, AD1HPFN_SHIFT, AD1HPFN_MAX, 1), + SOC_SINGLE("ADC 2 HPF", ADC_MHPF, AD2HPFN_SHIFT, AD2HPFN_MAX, 1), + + SOC_ENUM("DAC 1 De-Emphasis Filter", ak4619_dac_1_de_emp), + SOC_ENUM("DAC 2 De-Emphasis Filter", ak4619_dac_2_de_emp), + + SOC_ENUM("DAC 1 Digital Filter", ak4619_dac_1_digi_fil), + SOC_ENUM("DAC 2 Digital Filter", ak4619_dac_2_digi_fil), + + SOC_SINGLE_BOOL_EXT("Playback De-Emphasis Switch", 0, ak4619_get_deemph, ak4619_put_deemph), +}; + +/* + * DAPM + */ + +/* Analog input mode */ +static const char * const ak4619_analog_in_txt[] = { + "Differential", "Single-Ended1", "Single-Ended2", "Pseudo Differential" +}; + +static SOC_ENUM_SINGLE_DECL(ak4619_ad_1_left_in, ADC_AI, AD1LSEL_SHIFT, ak4619_analog_in_txt); +static SOC_ENUM_SINGLE_DECL(ak4619_ad_1_right_in, ADC_AI, AD1RSEL_SHIFT, ak4619_analog_in_txt); +static SOC_ENUM_SINGLE_DECL(ak4619_ad_2_left_in, ADC_AI, AD2LSEL_SHIFT, ak4619_analog_in_txt); +static SOC_ENUM_SINGLE_DECL(ak4619_ad_2_right_in, ADC_AI, AD2RSEL_SHIFT, ak4619_analog_in_txt); + +static const struct snd_kcontrol_new ak4619_ad_1_left_in_mux = + SOC_DAPM_ENUM("Analog Input 1 Left MUX", ak4619_ad_1_left_in); +static const struct snd_kcontrol_new ak4619_ad_1_right_in_mux = + SOC_DAPM_ENUM("Analog Input 1 Right MUX", ak4619_ad_1_right_in); +static const struct snd_kcontrol_new ak4619_ad_2_left_in_mux = + SOC_DAPM_ENUM("Analog Input 2 Left MUX", ak4619_ad_2_left_in); +static const struct snd_kcontrol_new ak4619_ad_2_right_in_mux = + SOC_DAPM_ENUM("Analog Input 2 Right MUX", ak4619_ad_2_right_in); + +/* DAC source mux */ +static const char * const ak4619_dac_in_txt[] = { + "SDIN1", "SDIN2", "SDOUT1", "SDOUT2" +}; + +static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_in, DAC_IS, DAC1SEL_SHIFT, ak4619_dac_in_txt); +static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_in, DAC_IS, DAC2SEL_SHIFT, ak4619_dac_in_txt); + +static const struct snd_kcontrol_new ak4619_dac_1_in_mux = + SOC_DAPM_ENUM("DAC 1 Source MUX", ak4619_dac_1_in); +static const struct snd_kcontrol_new ak4619_dac_2_in_mux = + SOC_DAPM_ENUM("DAC 2 Source MUX", ak4619_dac_2_in); + +static const struct snd_soc_dapm_widget ak4619_dapm_widgets[] = { + + /* DACs */ + SND_SOC_DAPM_DAC("DAC1", NULL, PWR_MGMT, 1, 0), + SND_SOC_DAPM_DAC("DAC2", NULL, PWR_MGMT, 2, 0), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC1", NULL, PWR_MGMT, 4, 0), + SND_SOC_DAPM_ADC("ADC2", NULL, PWR_MGMT, 5, 0), + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("AOUT1L"), + SND_SOC_DAPM_OUTPUT("AOUT2L"), + + SND_SOC_DAPM_OUTPUT("AOUT1R"), + SND_SOC_DAPM_OUTPUT("AOUT2R"), + + /* Inputs */ + SND_SOC_DAPM_INPUT("AIN1L"), + SND_SOC_DAPM_INPUT("AIN2L"), + SND_SOC_DAPM_INPUT("AIN4L"), + SND_SOC_DAPM_INPUT("AIN5L"), + + SND_SOC_DAPM_INPUT("AIN1R"), + SND_SOC_DAPM_INPUT("AIN2R"), + SND_SOC_DAPM_INPUT("AIN4R"), + SND_SOC_DAPM_INPUT("AIN5R"), + + SND_SOC_DAPM_INPUT("MIC1L"), + SND_SOC_DAPM_INPUT("MIC1R"), + SND_SOC_DAPM_INPUT("MIC2L"), + SND_SOC_DAPM_INPUT("MIC2R"), + + /* DAI */ + SND_SOC_DAPM_AIF_IN("SDIN1", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("SDIN2", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("SDOUT1", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("SDOUT2", "Capture", 0, SND_SOC_NOPM, 0, 0), + + /* MUXs for Mic PGA source selection */ + SND_SOC_DAPM_MUX("Analog Input 1 Left MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_1_left_in_mux), + SND_SOC_DAPM_MUX("Analog Input 1 Right MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_1_right_in_mux), + SND_SOC_DAPM_MUX("Analog Input 2 Left MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_2_left_in_mux), + SND_SOC_DAPM_MUX("Analog Input 2 Right MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_2_right_in_mux), + + /* MUXs for DAC source selection */ + SND_SOC_DAPM_MUX("DAC 1 Source MUX", SND_SOC_NOPM, 0, 0, &ak4619_dac_1_in_mux), + SND_SOC_DAPM_MUX("DAC 2 Source MUX", SND_SOC_NOPM, 0, 0, &ak4619_dac_2_in_mux), +}; + +static const struct snd_soc_dapm_route ak4619_intercon[] = { + /* Dest Connecting Widget Source */ + + /* Output path */ + {"AOUT1L", NULL, "DAC1"}, + {"AOUT2L", NULL, "DAC2"}, + + {"AOUT1R", NULL, "DAC1"}, + {"AOUT2R", NULL, "DAC2"}, + + {"DAC1", NULL, "DAC 1 Source MUX"}, + {"DAC2", NULL, "DAC 2 Source MUX"}, + + {"DAC 1 Source MUX", "SDIN1", "SDIN1"}, + {"DAC 1 Source MUX", "SDIN2", "SDIN2"}, + {"DAC 1 Source MUX", "SDOUT1", "SDOUT1"}, + {"DAC 1 Source MUX", "SDOUT2", "SDOUT2"}, + + {"DAC 2 Source MUX", "SDIN1", "SDIN1"}, + {"DAC 2 Source MUX", "SDIN2", "SDIN2"}, + {"DAC 2 Source MUX", "SDOUT1", "SDOUT1"}, + {"DAC 2 Source MUX", "SDOUT2", "SDOUT2"}, + + /* Input path */ + {"SDOUT1", NULL, "ADC1"}, + {"SDOUT2", NULL, "ADC2"}, + + {"ADC1", NULL, "Analog Input 1 Left MUX"}, + {"ADC1", NULL, "Analog Input 1 Right MUX"}, + + {"ADC2", NULL, "Analog Input 2 Left MUX"}, + {"ADC2", NULL, "Analog Input 2 Right MUX"}, + + {"Analog Input 1 Left MUX", "Differential", "MIC1L"}, + {"Analog Input 1 Left MUX", "Single-Ended1", "MIC1L"}, + {"Analog Input 1 Left MUX", "Single-Ended2", "MIC1L"}, + {"Analog Input 1 Left MUX", "Pseudo Differential", "MIC1L"}, + + {"Analog Input 1 Right MUX", "Differential", "MIC1R"}, + {"Analog Input 1 Right MUX", "Single-Ended1", "MIC1R"}, + {"Analog Input 1 Right MUX", "Single-Ended2", "MIC1R"}, + {"Analog Input 1 Right MUX", "Pseudo Differential", "MIC1R"}, + + {"Analog Input 2 Left MUX", "Differential", "MIC2L"}, + {"Analog Input 2 Left MUX", "Single-Ended1", "MIC2L"}, + {"Analog Input 2 Left MUX", "Single-Ended2", "MIC2L"}, + {"Analog Input 2 Left MUX", "Pseudo Differential", "MIC2L"}, + + {"Analog Input 2 Right MUX", "Differential", "MIC2R"}, + {"Analog Input 2 Right MUX", "Single-Ended1", "MIC2R"}, + {"Analog Input 2 Right MUX", "Single-Ended2", "MIC2R"}, + {"Analog Input 2 Right MUX", "Pseudo Differential", "MIC2R"}, + + {"MIC1L", NULL, "AIN1L"}, + {"MIC1L", NULL, "AIN2L"}, + + {"MIC1R", NULL, "AIN1R"}, + {"MIC1R", NULL, "AIN2R"}, + + {"MIC2L", NULL, "AIN4L"}, + {"MIC2L", NULL, "AIN5L"}, + + {"MIC2R", NULL, "AIN4R"}, + {"MIC2R", NULL, "AIN5R"}, +}; + +static const struct reg_default ak4619_reg_defaults[] = { + { PWR_MGMT, 0x00 }, + { AU_IFF1, 0x0C }, + { AU_IFF2, 0x0C }, + { SYS_CLK, 0x00 }, + { MIC_AMP1, 0x22 }, + { MIC_AMP2, 0x22 }, + { LADC1, 0x30 }, + { RADC1, 0x30 }, + { LADC2, 0x30 }, + { RADC2, 0x30 }, + { ADC_DF, 0x00 }, + { ADC_AI, 0x00 }, + { ADC_MHPF, 0x00 }, + { LDAC1, 0x18 }, + { RDAC1, 0x18 }, + { LDAC2, 0x18 }, + { RDAC2, 0x18 }, + { DAC_IS, 0x04 }, + { DAC_DEMP, 0x05 }, + { DAC_MF, 0x0A }, +}; + +static int ak4619_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + u8 pwr_ctrl = 0; + + switch (level) { + case SND_SOC_BIAS_ON: + pwr_ctrl |= RSTN; + fallthrough; + case SND_SOC_BIAS_PREPARE: + pwr_ctrl |= PMAD1 | PMAD2 | PMDA1 | PMDA2; + fallthrough; + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_OFF: + default: + break; + } + + snd_soc_component_write(component, PWR_MGMT, pwr_ctrl); + + return 0; +} + +static int ak4619_dai_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 ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component); + unsigned int width; + unsigned int rate; + unsigned int fs; + bool is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + u8 dai_ctrl = 0; + u8 clk_mode = 0; + + width = params_width(params); + switch (width) { + case 16: + dai_ctrl |= is_play ? DIDL_16 : DODL_16; + break; + case 20: + dai_ctrl |= is_play ? DIDL_20 : DODL_20; + break; + case 24: + dai_ctrl |= is_play ? DIDL_24 : DODL_24; + break; + case 32: + if (is_play) + dai_ctrl |= DIDL_32; + else + return -EINVAL; + break; + default: + return -EINVAL; + } + + rate = params_rate(params); + if (rate) + fs = ak4619->sysclk / rate; + else + return -EINVAL; + + switch (rate) { + case 8000: + case 11025: + case 12000: + case 16000: + case 22050: + case 24000: + case 32000: + case 44100: + case 48000: + switch (fs) { + case 256: + clk_mode |= (0x0 << 0); + break; + case 384: + clk_mode |= (0x2 << 0); + break; + case 512: + clk_mode |= (0x3 << 0); + break; + default: + return -EINVAL; + } + break; + case 64000: + case 88200: + case 96000: + if (fs == 256) + clk_mode |= (0x1 << 0); + else + return -EINVAL; + break; + case 176400: + case 192000: + if (fs == 128) + clk_mode |= (0x4 << 0); + else + return -EINVAL; + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, SYS_CLK, FS_MASK, clk_mode); + snd_soc_component_update_bits(component, AU_IFF2, + is_play ? DIDL_MASK : DODL_MASK, dai_ctrl); + + if (is_play) { + ak4619->playback_rate = rate; + ak4619_set_deemph(component); + } + + return 0; +} + +static int ak4619_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + u8 dai_fmt1 = 0; + u8 dai_fmt2 = 0; + + /* Set clock normal/inverted */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + dai_fmt1 |= BCKP; + break; + case SND_SOC_DAIFMT_NB_IF: + case SND_SOC_DAIFMT_IB_IF: + default: + return -EINVAL; + } + + /* Only Stereo modes are supported */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + dai_fmt1 |= DCF_STEREO_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + dai_fmt1 |= DCF_STEREO_MSB; + break; + case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */ + dai_fmt1 |= DCF_PCM_SF; + dai_fmt2 |= SLOT; + break; + case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */ + dai_fmt1 |= DCF_PCM_LF; + dai_fmt2 |= SLOT; + break; + default: + return -EINVAL; + } + + /* Only slave mode is support */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + break; + default: + return -EINVAL; + } + + /* By default only 64 BICK per LRCLK is supported */ + dai_fmt1 |= DSL_32; + + snd_soc_component_update_bits(component, AU_IFF1, DCF_MASK | + DSL_MASK | BCKP, dai_fmt1); + snd_soc_component_update_bits(component, AU_IFF2, SLOT, dai_fmt2); + + return 0; +} + +static int ak4619_dai_set_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component); + + ak4619->sysclk = freq; + + return 0; +} + +static int ak4619_dai_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + struct snd_soc_component *component = dai->component; + + snd_soc_component_update_bits(component, DAC_MF, DA1MUTE_EN, mute ? DA1MUTE_EN : 0); + snd_soc_component_update_bits(component, DAC_MF, DA2MUTE_EN, mute ? DA2MUTE_EN : 0); + + return 0; +} + +static void ak4619_hw_constraints(struct ak4619_priv *ak4619, + struct snd_pcm_runtime *runtime) +{ + struct snd_pcm_hw_constraint_list *constraint = &ak4619->constraint; + int ak4619_rate_mask = 0; + unsigned int fs; + int i; + static const unsigned int ak4619_sr[] = { + 8000, + 11025, + 12000, + 16000, + 22050, + 24000, + 32000, + 44100, + 48000, + 64000, + 88200, + 96000, + 176400, + 192000, + }; + + /* + * [8kHz - 48kHz] : 256fs, 384fs or 512fs + * [64kHz - 96kHz] : 256fs + * [176.4kHz, 192kHz] : 128fs + */ + + for (i = 0; i < ARRAY_SIZE(ak4619_sr); i++) { + fs = ak4619->sysclk / ak4619_sr[i]; + + switch (fs) { + case 512: + case 384: + case 256: + ak4619_rate_mask |= (1 << i); + break; + case 128: + switch (i) { + case (ARRAY_SIZE(ak4619_sr) - 1): + case (ARRAY_SIZE(ak4619_sr) - 2): + ak4619_rate_mask |= (1 << i); + break; + default: + break; + } + break; + default: + break; + } + }; + + constraint->list = ak4619_sr; + constraint->mask = ak4619_rate_mask; + constraint->count = ARRAY_SIZE(ak4619_sr); + + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, constraint); +}; + +#define PLAYBACK_MODE 0 +#define CAPTURE_MODE 1 + +static int ak4619_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component); + + ak4619_hw_constraints(ak4619, substream->runtime); + + return 0; +} + +static u64 ak4619_dai_formats[] = { + /* + * Select below from Sound Card, not here + * SND_SOC_DAIFMT_CBC_CFC + * SND_SOC_DAIFMT_CBP_CFP + */ + + /* First Priority */ + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J, + + /* Second Priority */ + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B, +}; + +static const struct snd_soc_dai_ops ak4619_dai_ops = { + .startup = ak4619_dai_startup, + .set_sysclk = ak4619_dai_set_sysclk, + .set_fmt = ak4619_dai_set_fmt, + .hw_params = ak4619_dai_hw_params, + .mute_stream = ak4619_dai_mute, + .auto_selectable_formats = ak4619_dai_formats, + .num_auto_selectable_formats = ARRAY_SIZE(ak4619_dai_formats), +}; + +static const struct snd_soc_component_driver soc_component_dev_ak4619 = { + .set_bias_level = ak4619_set_bias_level, + .controls = ak4619_snd_controls, + .num_controls = ARRAY_SIZE(ak4619_snd_controls), + .dapm_widgets = ak4619_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4619_dapm_widgets), + .dapm_routes = ak4619_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4619_intercon), + .idle_bias_on = 1, + .endianness = 1, +}; + +static const struct regmap_config ak4619_regmap_cfg = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x14, + .reg_defaults = ak4619_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ak4619_reg_defaults), + .cache_type = REGCACHE_MAPLE, +}; + +static const struct of_device_id ak4619_of_match[] = { + { .compatible = "asahi-kasei,ak4619", .data = &ak4619_regmap_cfg }, + {}, +}; +MODULE_DEVICE_TABLE(of, ak4619_of_match); + +static const struct i2c_device_id ak4619_i2c_id[] = { + { "ak4619", (kernel_ulong_t)&ak4619_regmap_cfg }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ak4619_i2c_id); + +#define AK4619_RATES SNDRV_PCM_RATE_8000_192000 + +#define AK4619_DAC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S20_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +#define AK4619_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S20_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver ak4619_dai = { + .name = "ak4619-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AK4619_RATES, + .formats = AK4619_DAC_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AK4619_RATES, + .formats = AK4619_ADC_FORMATS, + }, + .ops = &ak4619_dai_ops, + .symmetric_rate = 1, +}; + +static int ak4619_i2c_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct ak4619_priv *ak4619; + int ret; + + ak4619 = devm_kzalloc(dev, sizeof(*ak4619), GFP_KERNEL); + if (!ak4619) + return -ENOMEM; + + i2c_set_clientdata(i2c, ak4619); + + ak4619->regmap = devm_regmap_init_i2c(i2c, &ak4619_regmap_cfg); + if (IS_ERR(ak4619->regmap)) { + ret = PTR_ERR(ak4619->regmap); + dev_err(dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_component(dev, &soc_component_dev_ak4619, + &ak4619_dai, 1); + if (ret < 0) { + dev_err(dev, "Failed to register ak4619 component: %d\n", + ret); + return ret; + } + + return 0; +} + +static struct i2c_driver ak4619_i2c_driver = { + .driver = { + .name = "ak4619-codec", + .of_match_table = ak4619_of_match, + }, + .probe = ak4619_i2c_probe, + .id_table = ak4619_i2c_id, +}; +module_i2c_driver(ak4619_i2c_driver); + +MODULE_DESCRIPTION("SoC AK4619 driver"); +MODULE_AUTHOR("Khanh Le "); +MODULE_LICENSE("GPL v2"); From 6469267afed4ffb9d16ce8c44a2b518b9b31c215 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 19 Jun 2024 01:00:23 +0000 Subject: [PATCH 171/349] ASoC: dt-bindings: ak4619: Add initial DT binding Add Asahi Kasei ak4619 audio codec bindings. Signed-off-by: Kuninori Morimoto Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/87h6dpwxug.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../bindings/sound/asahi-kasei,ak4619.yaml | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml diff --git a/Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml new file mode 100644 index 000000000000..d412531ef9a2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4619.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AK4619 I2C transmitter + +maintainers: + - Kuninori Morimoto + - Khanh Le + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: asahi-kasei,ak4619 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: mclk + + "#sound-dai-cells": + const: 0 + + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@10 { + compatible = "asahi-kasei,ak4619"; + reg = <0x10>; + + clocks = <&rcar_sound>; + clock-names = "mclk"; + + #sound-dai-cells = <0>; + port { + ak4619_endpoint: endpoint { + remote-endpoint = <&rsnd_endpoint>; + }; + }; + }; + }; From fe1ff61487ace69cd4e680e36169c90667eb9624 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 19 Jun 2024 05:53:42 +0000 Subject: [PATCH 172/349] ASoC: rt1318: Add RT1318 audio amplifier driver This is the initial i2s-based amplifier driver for rt1318. Signed-off-by: Jack Yu Link: https://msgid.link/r/b3055442ce6d4994aa01aa1fad6ba1fe@realtek.com Signed-off-by: Mark Brown --- include/sound/rt1318.h | 16 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt1318.c | 1354 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt1318.h | 342 ++++++++++ 5 files changed, 1719 insertions(+) create mode 100644 include/sound/rt1318.h create mode 100644 sound/soc/codecs/rt1318.c create mode 100644 sound/soc/codecs/rt1318.h diff --git a/include/sound/rt1318.h b/include/sound/rt1318.h new file mode 100644 index 000000000000..fe6bff06036c --- /dev/null +++ b/include/sound/rt1318.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * linux/sound/rt1318.h -- Platform data for RT1318 + * + * Copyright 2024 Realtek Semiconductor Corp. + */ + +#ifndef __LINUX_SND_RT1318_H +#define __LINUX_SND_RT1318_H + +struct rt1318_platform_data { + unsigned int init_r0_l; + unsigned int init_r0_r; +}; + +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7b99556f24d3..a99cb26eb280 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -221,6 +221,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT722_SDCA_SDW imply SND_SOC_RT1308_SDW imply SND_SOC_RT1316_SDW + imply SND_SOC_RT1318 imply SND_SOC_RT1318_SDW imply SND_SOC_RT1320_SDW imply SND_SOC_RT9120 @@ -1576,6 +1577,10 @@ config SND_SOC_RT1316_SDW depends on SOUNDWIRE select REGMAP_SOUNDWIRE +config SND_SOC_RT1318 + tristate + depends on I2C + config SND_SOC_RT1318_SDW tristate "Realtek RT1318 Codec - SDW" depends on SOUNDWIRE diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index ca69f35cc0f7..ad0f77224c74 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -222,6 +222,7 @@ snd-soc-rt1305-y := rt1305.o snd-soc-rt1308-y := rt1308.o snd-soc-rt1308-sdw-y := rt1308-sdw.o snd-soc-rt1316-sdw-y := rt1316-sdw.o +snd-soc-rt1318-y := rt1318.o snd-soc-rt1318-sdw-y := rt1318-sdw.o snd-soc-rt1320-sdw-y := rt1320-sdw.o snd-soc-rt274-y := rt274.o @@ -618,6 +619,7 @@ obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o +obj-$(CONFIG_SND_SOC_RT1318) += snd-soc-rt1318.o obj-$(CONFIG_SND_SOC_RT1318_SDW) += snd-soc-rt1318-sdw.o obj-$(CONFIG_SND_SOC_RT1320_SDW) += snd-soc-rt1320-sdw.o obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c new file mode 100644 index 000000000000..4e47db4fc7fb --- /dev/null +++ b/sound/soc/codecs/rt1318.c @@ -0,0 +1,1354 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt1318.c -- RT1318 ALSA SoC audio amplifier driver +// Author: Jack Yu +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt1318.h" + +static struct reg_sequence init_list[] = { + { 0x0000C000, 0x01}, + { 0x0000F20D, 0x00}, + { 0x0000F212, 0x3E}, + { 0x0000C001, 0x02}, + { 0x0000C003, 0x22}, + { 0x0000C004, 0x44}, + { 0x0000C005, 0x44}, + { 0x0000C007, 0x64}, + { 0x0000C00E, 0xE7}, + { 0x0000F223, 0x7F}, + { 0x0000F224, 0xDB}, + { 0x0000F225, 0xEE}, + { 0x0000F226, 0x3F}, + { 0x0000F227, 0x0F}, + { 0x0000F21A, 0x78}, + { 0x0000F242, 0x3C}, + { 0x0000C120, 0x40}, + { 0x0000C125, 0x03}, + { 0x0000C321, 0x0A}, + { 0x0000C200, 0xD8}, + { 0x0000C201, 0x27}, + { 0x0000C202, 0x0F}, + { 0x0000C400, 0x0E}, + { 0x0000C401, 0x43}, + { 0x0000C402, 0xE0}, + { 0x0000C403, 0x00}, + { 0x0000C404, 0x4C}, + { 0x0000C406, 0x40}, + { 0x0000C407, 0x02}, + { 0x0000C408, 0x3F}, + { 0x0000C300, 0x01}, + { 0x0000C125, 0x03}, + { 0x0000DF00, 0x10}, + { 0x0000F20B, 0x2A}, + { 0x0000DF5F, 0x01}, + { 0x0000DF60, 0xA7}, + { 0x0000C203, 0x84}, + { 0x0000C206, 0x78}, + { 0x0000F10A, 0x09}, + { 0x0000F10B, 0x4C}, + { 0x0000F104, 0xF4}, + { 0x0000F105, 0x03}, + { 0x0000F109, 0xE0}, + { 0x0000F10B, 0x5C}, + { 0x0000F104, 0xF4}, + { 0x0000F105, 0x04}, + { 0x0000F109, 0x65}, + { 0x0000F10B, 0x5C}, + { 0x0000F104, 0xF4}, + { 0x0000F105, 0x02}, + { 0x0000F109, 0x30}, + { 0x0000F10B, 0x5C}, + { 0x0000E706, 0x0F}, + { 0x0000E707, 0x30}, + { 0x0000E806, 0x0F}, + { 0x0000E807, 0x30}, + { 0x0000CE04, 0x03}, + { 0x0000CE05, 0x5F}, + { 0x0000CE06, 0xA2}, + { 0x0000CE07, 0x6B}, + { 0x0000CF04, 0x03}, + { 0x0000CF05, 0x5F}, + { 0x0000CF06, 0xA2}, + { 0x0000CF07, 0x6B}, + { 0x0000CE60, 0xE3}, + { 0x0000C130, 0x51}, + { 0x0000E000, 0xA8}, + { 0x0000F102, 0x00}, + { 0x0000F103, 0x00}, + { 0x0000F104, 0xF5}, + { 0x0000F105, 0x23}, + { 0x0000F109, 0x04}, + { 0x0000F10A, 0x0B}, + { 0x0000F10B, 0x4C}, + { 0x0000F10B, 0x5C}, + { 0x41001888, 0x00}, + { 0x0000C121, 0x0B}, + { 0x0000F102, 0x00}, + { 0x0000F103, 0x00}, + { 0x0000F104, 0xF5}, + { 0x0000F105, 0x23}, + { 0x0000F109, 0x00}, + { 0x0000F10A, 0x0B}, + { 0x0000F10B, 0x4C}, + { 0x0000F10B, 0x5C}, + { 0x0000F800, 0x20}, + { 0x0000CA00, 0x80}, + { 0x0000CA10, 0x00}, + { 0x0000CA02, 0x78}, + { 0x0000CA12, 0x78}, + { 0x0000ED00, 0x90}, + { 0x0000E604, 0x00}, + { 0x0000DB00, 0x0C}, + { 0x0000DD00, 0x0C}, + { 0x0000DC19, 0x00}, + { 0x0000DC1A, 0x6A}, + { 0x0000DC1B, 0xAA}, + { 0x0000DC1C, 0xAB}, + { 0x0000DC1D, 0x00}, + { 0x0000DC1E, 0x16}, + { 0x0000DC1F, 0xDB}, + { 0x0000DC20, 0x6D}, + { 0x0000DE19, 0x00}, + { 0x0000DE1A, 0x6A}, + { 0x0000DE1B, 0xAA}, + { 0x0000DE1C, 0xAB}, + { 0x0000DE1D, 0x00}, + { 0x0000DE1E, 0x16}, + { 0x0000DE1F, 0xDB}, + { 0x0000DE20, 0x6D}, + { 0x0000DB32, 0x00}, + { 0x0000DD32, 0x00}, + { 0x0000DB33, 0x0A}, + { 0x0000DD33, 0x0A}, + { 0x0000DB34, 0x1A}, + { 0x0000DD34, 0x1A}, + { 0x0000DB15, 0xEF}, + { 0x0000DD15, 0xEF}, + { 0x0000DB17, 0xEF}, + { 0x0000DD17, 0xEF}, + { 0x0000DB94, 0x70}, + { 0x0000DD94, 0x70}, + { 0x0000DB19, 0x40}, + { 0x0000DD19, 0x40}, + { 0x0000DB12, 0xC0}, + { 0x0000DD12, 0xC0}, + { 0x0000DB00, 0x4C}, + { 0x0000DB04, 0x05}, + { 0x0000DB05, 0x03}, + { 0x0000DD04, 0x05}, + { 0x0000DD05, 0x03}, + { 0x0000DBBB, 0x09}, + { 0x0000DBBC, 0x30}, + { 0x0000DBBD, 0xF0}, + { 0x0000DBBE, 0xF1}, + { 0x0000DDBB, 0x09}, + { 0x0000DDBC, 0x30}, + { 0x0000DDBD, 0xF0}, + { 0x0000DDBE, 0xF1}, + { 0x0000DB01, 0x79}, + { 0x0000DD01, 0x79}, + { 0x0000DB08, 0x40}, + { 0x0000DD08, 0x40}, + { 0x0000DC52, 0xEF}, + { 0x0000DE52, 0xEF}, + { 0x0000DB00, 0xCC}, + { 0x0000CC2C, 0x00}, + { 0x0000CC2D, 0x2A}, + { 0x0000CC2E, 0x83}, + { 0x0000CC2F, 0xA8}, + { 0x0000CD2C, 0x00}, + { 0x0000CD2D, 0x2A}, + { 0x0000CD2E, 0x83}, + { 0x0000CD2F, 0xA8}, + { 0x0000CC24, 0x00}, + { 0x0000CC25, 0x51}, + { 0x0000CC26, 0xEB}, + { 0x0000CC27, 0x85}, + { 0x0000CD24, 0x00}, + { 0x0000CD25, 0x51}, + { 0x0000CD26, 0xEB}, + { 0x0000CD27, 0x85}, + { 0x0000CC20, 0x00}, + { 0x0000CC21, 0x00}, + { 0x0000CC22, 0x43}, + { 0x0000CD20, 0x00}, + { 0x0000CD21, 0x00}, + { 0x0000CD22, 0x43}, + { 0x0000CC16, 0x0F}, + { 0x0000CC17, 0x00}, + { 0x0000CD16, 0x0F}, + { 0x0000CD17, 0x00}, + { 0x0000CC29, 0x5D}, + { 0x0000CC2A, 0xC0}, + { 0x0000CD29, 0x5D}, + { 0x0000CD2A, 0xC0}, + { 0x0000CC31, 0x20}, + { 0x0000CC32, 0x00}, + { 0x0000CC33, 0x00}, + { 0x0000CC34, 0x00}, + { 0x0000CD31, 0x20}, + { 0x0000CD32, 0x00}, + { 0x0000CD33, 0x00}, + { 0x0000CD34, 0x00}, + { 0x0000CC36, 0x79}, + { 0x0000CC37, 0x99}, + { 0x0000CC38, 0x99}, + { 0x0000CC39, 0x99}, + { 0x0000CD36, 0x79}, + { 0x0000CD37, 0x99}, + { 0x0000CD38, 0x99}, + { 0x0000CD39, 0x99}, + { 0x0000CC09, 0x00}, + { 0x0000CC0A, 0x07}, + { 0x0000CC0B, 0x5F}, + { 0x0000CC0C, 0x6F}, + { 0x0000CD09, 0x00}, + { 0x0000CD0A, 0x07}, + { 0x0000CD0B, 0x5F}, + { 0x0000CD0C, 0x6F}, + { 0x0000CC0E, 0x00}, + { 0x0000CC0F, 0x03}, + { 0x0000CC10, 0xAF}, + { 0x0000CC11, 0xB7}, + { 0x0000CD0E, 0x00}, + { 0x0000CD0F, 0x03}, + { 0x0000CD10, 0xAF}, + { 0x0000CD11, 0xB7}, + { 0x0000CCD6, 0x00}, + { 0x0000CCD7, 0x03}, + { 0x0000CDD6, 0x00}, + { 0x0000CDD7, 0x03}, + { 0x0000CCD8, 0x00}, + { 0x0000CCD9, 0x03}, + { 0x0000CDD8, 0x00}, + { 0x0000CDD9, 0x03}, + { 0x0000CCDA, 0x00}, + { 0x0000CCDB, 0x03}, + { 0x0000CDDA, 0x00}, + { 0x0000CDDB, 0x03}, + { 0x0000C320, 0x20}, + { 0x0000C203, 0x9C}, +}; +#define rt1318_INIT_REG_LEN ARRAY_SIZE(init_list) + +static const struct reg_default rt1318_reg[] = { + { 0xc000, 0x00 }, + { 0xc001, 0x43 }, + { 0xc003, 0x22 }, + { 0xc004, 0x44 }, + { 0xc005, 0x44 }, + { 0xc006, 0x33 }, + { 0xc007, 0x64 }, + { 0xc008, 0x05 }, + { 0xc00a, 0xfc }, + { 0xc00b, 0x0f }, + { 0xc00c, 0x0e }, + { 0xc00d, 0xef }, + { 0xc00e, 0xe5 }, + { 0xc00f, 0xff }, + { 0xc120, 0xc0 }, + { 0xc121, 0x00 }, + { 0xc122, 0x00 }, + { 0xc123, 0x14 }, + { 0xc125, 0x00 }, + { 0xc130, 0x59 }, + { 0xc200, 0x00 }, + { 0xc201, 0x00 }, + { 0xc202, 0x00 }, + { 0xc203, 0x04 }, + { 0xc204, 0x00 }, + { 0xc205, 0x00 }, + { 0xc206, 0x68 }, + { 0xc207, 0x70 }, + { 0xc208, 0x00 }, + { 0xc20a, 0x00 }, + { 0xc20b, 0x01 }, + { 0xc20c, 0x7f }, + { 0xc20d, 0x01 }, + { 0xc20e, 0x7f }, + { 0xc300, 0x00 }, + { 0xc301, 0x00 }, + { 0xc303, 0x80 }, + { 0xc320, 0x00 }, + { 0xc321, 0x09 }, + { 0xc322, 0x02 }, + { 0xc400, 0x00 }, + { 0xc401, 0x00 }, + { 0xc402, 0x00 }, + { 0xc403, 0x00 }, + { 0xc404, 0x00 }, + { 0xc405, 0x00 }, + { 0xc406, 0x00 }, + { 0xc407, 0x00 }, + { 0xc408, 0x00 }, + { 0xc410, 0x04 }, + { 0xc430, 0x00 }, + { 0xc431, 0x00 }, + { 0xca00, 0x10 }, + { 0xca01, 0x00 }, + { 0xca02, 0x0b }, + { 0xca10, 0x10 }, + { 0xca11, 0x00 }, + { 0xca12, 0x0b }, + { 0xce04, 0x08 }, + { 0xce05, 0x00 }, + { 0xce06, 0x00 }, + { 0xce07, 0x00 }, + { 0xce60, 0x63 }, + { 0xcf04, 0x08 }, + { 0xcf05, 0x00 }, + { 0xcf06, 0x00 }, + { 0xcf07, 0x00 }, + { 0xdb00, 0x00 }, + { 0xdb08, 0x40 }, + { 0xdb12, 0x00 }, + { 0xdb35, 0x00 }, + { 0xdbb5, 0x00 }, + { 0xdbb6, 0x40 }, + { 0xdbb7, 0x00 }, + { 0xdbb8, 0x00 }, + { 0xdbc5, 0x00 }, + { 0xdbc6, 0x00 }, + { 0xdbc7, 0x00 }, + { 0xdbc8, 0x00 }, + { 0xdd08, 0x40 }, + { 0xdd12, 0x00 }, + { 0xdd35, 0x00 }, + { 0xddb5, 0x00 }, + { 0xddb6, 0x40 }, + { 0xddb7, 0x00 }, + { 0xddb8, 0x00 }, + { 0xddc5, 0x00 }, + { 0xddc6, 0x00 }, + { 0xddc7, 0x00 }, + { 0xddc8, 0x00 }, + { 0xdd93, 0x00 }, + { 0xdd94, 0x64 }, + { 0xdf00, 0x00 }, + { 0xdf5f, 0x00 }, + { 0xdf60, 0x00 }, + { 0xe000, 0x08 }, + { 0xe300, 0xa0 }, + { 0xe400, 0x22 }, + { 0xe706, 0x2f }, + { 0xe707, 0x2f }, + { 0xe806, 0x2f }, + { 0xe807, 0x2f }, + { 0xea00, 0x43 }, + { 0xed00, 0x80 }, + { 0xed01, 0x0f }, + { 0xed02, 0xff }, + { 0xed03, 0x00 }, + { 0xed04, 0x00 }, + { 0xed05, 0x0f }, + { 0xed06, 0xff }, + { 0xf010, 0x10 }, + { 0xf011, 0xec }, + { 0xf012, 0x68 }, + { 0xf013, 0x21 }, + { 0xf102, 0x00 }, + { 0xf103, 0x00 }, + { 0xf104, 0x00 }, + { 0xf105, 0x00 }, + { 0xf106, 0x00 }, + { 0xf107, 0x00 }, + { 0xf108, 0x00 }, + { 0xf109, 0x00 }, + { 0xf10a, 0x03 }, + { 0xf10b, 0x40 }, + { 0xf20b, 0x28 }, + { 0xf20d, 0x00 }, + { 0xf212, 0x00 }, + { 0xf21a, 0x00 }, + { 0xf223, 0x40 }, + { 0xf224, 0x00 }, + { 0xf225, 0x00 }, + { 0xf226, 0x00 }, + { 0xf227, 0x00 }, + { 0xf242, 0x0c }, + { 0xf800, 0x00 }, + { 0xf801, 0x12 }, + { 0xf802, 0xe0 }, + { 0xf803, 0x2f }, + { 0xf804, 0x00 }, + { 0xf805, 0x00 }, + { 0xf806, 0x07 }, + { 0xf807, 0xff }, +}; + +static bool rt1318_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0xc000: + case 0xc301: + case 0xc410: + case 0xc430 ... 0xc431: + case 0xdb06: + case 0xdb12: + case 0xdb1d ... 0xdb1f: + case 0xdb35: + case 0xdb37: + case 0xdb8a ... 0xdb92: + case 0xdbc5 ... 0xdbc8: + case 0xdc2b ... 0xdc49: + case 0xdd0b: + case 0xdd12: + case 0xdd1d ... 0xdd1f: + case 0xdd35: + case 0xdd8a ... 0xdd92: + case 0xddc5 ... 0xddc8: + case 0xde2b ... 0xde44: + case 0xdf4a ... 0xdf55: + case 0xe224 ... 0xe23b: + case 0xea01: + case 0xebc5: + case 0xebc8: + case 0xebcb ... 0xebcc: + case 0xed03 ... 0xed06: + case 0xf010 ... 0xf014: + return true; + + default: + return false; + } +} + +static bool rt1318_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0xc000 ... 0xc00f: + case 0xc120 ... 0xc130: + case 0xc200 ... 0xc20e: + case 0xc300 ... 0xc303: + case 0xc320 ... 0xc322: + case 0xc400 ... 0xc408: + case 0xc430 ... 0xc431: + case 0xca00 ... 0xca02: + case 0xca10 ... 0xca12: + case 0xcb00 ... 0xcb0b: + case 0xcc00 ... 0xcce5: + case 0xcd00 ... 0xcde5: + case 0xce00 ... 0xce6a: + case 0xcf00 ... 0xcf53: + case 0xd000 ... 0xd0cc: + case 0xd100 ... 0xd1b9: + case 0xdb00 ... 0xdc53: + case 0xdd00 ... 0xde53: + case 0xdf00 ... 0xdf6b: + case 0xe000: + case 0xe300: + case 0xe400: + case 0xe706 ... 0xe707: + case 0xe806 ... 0xe807: + case 0xea00: + case 0xeb00 ... 0xebcc: + case 0xec00 ... 0xecb9: + case 0xed00 ... 0xed06: + case 0xf010 ... 0xf014: + case 0xf102 ... 0xf10b: + case 0xf20b: + case 0xf20d ... 0xf242: + case 0xf800 ... 0xf807: + return true; + default: + return false; + } +} + +static int rt1318_dac_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 rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(rt1318->regmap, RT1318_PWR_STA1, + RT1318_PDB_CTRL_MASK, RT1318_PDB_CTRL_HIGH); + break; + + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(rt1318->regmap, RT1318_PWR_STA1, + RT1318_PDB_CTRL_MASK, RT1318_PDB_CTRL_LOW); + break; + + default: + break; + } + return 0; +} + +static int rt1318_dvol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + rt1318->rt1318_dvol = ucontrol->value.integer.value[0]; + + if (rt1318->rt1318_dvol <= RT1318_DVOL_STEP && rt1318->rt1318_dvol >= 0) { + regmap_write(rt1318->regmap, RT1318_DA_VOL_L_8, + rt1318->rt1318_dvol >> 8); + regmap_write(rt1318->regmap, RT1318_DA_VOL_L_1_7, + rt1318->rt1318_dvol & 0xff); + regmap_write(rt1318->regmap, RT1318_DA_VOL_R_8, + rt1318->rt1318_dvol >> 8); + regmap_write(rt1318->regmap, RT1318_DA_VOL_R_1_7, + rt1318->rt1318_dvol & 0xff); + return 1; + } + + return 0; +} + +static int rt1318_dvol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt1318->rt1318_dvol; + + return 0; +} + +static const struct snd_kcontrol_new rt1318_snd_controls[] = { + SOC_SINGLE_EXT("Amp Playback Volume", SND_SOC_NOPM, 0, 383, 0, + rt1318_dvol_get, rt1318_dvol_put), +}; + +static const struct snd_soc_dapm_widget rt1318_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + /* DACs */ + SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, + rt1318_dac_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("Amp"), +}; + +static const struct snd_soc_dapm_route rt1318_dapm_routes[] = { + {"DAC", NULL, "AIF1RX"}, + {"Amp", NULL, "DAC"}, +}; + +static int rt1318_get_clk_info(int sclk, int rate) +{ + int i, pd[] = {1, 2, 4, 8, 16, 24}; + + if (sclk <= 0 || rate <= 0) + return -EINVAL; + + rate = rate << 8; + for (i = 0; i < ARRAY_SIZE(pd); i++) + if (sclk == rate * pd[i]) + return i; + + return -EINVAL; +} + +static int rt1318_clk_ip_info(struct snd_soc_component *component, int lrclk) +{ + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + switch (lrclk) { + case RT1318_LRCLK_48000: + case RT1318_LRCLK_44100: + case RT1318_LRCLK_16000: + regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON, + RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK, + RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON4); + break; + case RT1318_LRCLK_96000: + regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON, + RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK, + RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON2); + break; + case RT1318_LRCLK_192000: + regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON, + RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK, + RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON1); + break; + default: + dev_err(component->dev, "Unsupported clock rate.\n"); + return -EINVAL; + } + + return 0; +} + +static int rt1318_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 rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + int data_len = 0, ch_len = 0; + int pre_div, ret; + + rt1318->lrck = params_rate(params); + pre_div = rt1318_get_clk_info(rt1318->sysclk, rt1318->lrck); + if (pre_div < 0) { + dev_err(component->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + ret = rt1318_clk_ip_info(component, rt1318->lrck); + if (ret < 0) { + dev_err(component->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + + switch (params_width(params)) { + case 16: + break; + case 20: + data_len = RT1318_I2S_DL_20; + ch_len = RT1318_I2S_DL_20; + break; + case 24: + data_len = RT1318_I2S_DL_24; + ch_len = RT1318_I2S_DL_24; + break; + case 32: + data_len = RT1318_I2S_DL_32; + ch_len = RT1318_I2S_DL_32; + break; + case 8: + data_len = RT1318_I2S_DL_8; + ch_len = RT1318_I2S_DL_8; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rt1318->regmap, RT1318_CLK2, + RT1318_DIV_AP_MASK | RT1318_DIV_DAMOD_MASK, + pre_div << RT1318_DIV_AP_SFT | + pre_div << RT1318_DIV_DAMOD_SFT); + regmap_update_bits(rt1318->regmap, RT1318_CLK3, + RT1318_AD_STO1_MASK | RT1318_AD_STO2_MASK, + pre_div << RT1318_AD_STO1_SFT | + pre_div << RT1318_AD_STO2_SFT); + regmap_update_bits(rt1318->regmap, RT1318_CLK4, + RT1318_AD_ANA_STO1_MASK | RT1318_AD_ANA_STO2_MASK, + pre_div << RT1318_AD_ANA_STO1_SFT | + pre_div << RT1318_AD_ANA_STO2_SFT); + regmap_update_bits(rt1318->regmap, RT1318_CLK5, + RT1318_DIV_FIFO_IN_MASK | RT1318_DIV_FIFO_OUT_MASK, + pre_div << RT1318_DIV_FIFO_IN_SFT | + pre_div << RT1318_DIV_FIFO_OUT_SFT); + regmap_update_bits(rt1318->regmap, RT1318_CLK6, + RT1318_DIV_NLMS_MASK | RT1318_DIV_AD_MONO_MASK | + RT1318_DIV_POST_G_MASK, pre_div << RT1318_DIV_NLMS_SFT | + pre_div << RT1318_DIV_AD_MONO_SFT | + pre_div << RT1318_DIV_POST_G_SFT); + + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL2, + RT1318_I2S_DL_MASK, data_len << RT1318_I2S_DL_SFT); + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL3, + RT1318_I2S_TX_CHL_MASK | RT1318_I2S_RX_CHL_MASK, + ch_len << RT1318_I2S_TX_CHL_SFT | + ch_len << RT1318_I2S_RX_CHL_SFT); + + return 0; +} + +static int rt1318_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + unsigned int reg_val = 0, reg_val2 = 0; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val2 |= RT1318_TDM_BCLK_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT1318_FMT_LEFT_J; + break; + + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT1318_FMT_PCM_A_R; + break; + + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT1318_FMT_PCM_B_R; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL1, + RT1318_I2S_FMT_MASK, reg_val); + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL1, + RT1318_TDM_BCLK_MASK, reg_val2); + + return 0; +} + +static int rt1318_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + int reg_val = 0; + + if (freq == rt1318->sysclk && clk_id == rt1318->sysclk_src) + return 0; + + switch (clk_id) { + case RT1318_SCLK_S_BCLK: + reg_val |= RT1318_SYSCLK_BCLK; + break; + case RT1318_SCLK_S_SDW: + reg_val |= RT1318_SYSCLK_SDW; + break; + case RT1318_SCLK_S_PLL2F: + reg_val |= RT1318_SYSCLK_PLL2F; + break; + case RT1318_SCLK_S_PLL2B: + reg_val |= RT1318_SYSCLK_PLL2B; + break; + case RT1318_SCLK_S_MCLK: + reg_val |= RT1318_SYSCLK_MCLK; + break; + case RT1318_SCLK_S_RC0: + reg_val |= RT1318_SYSCLK_RC1; + break; + case RT1318_SCLK_S_RC1: + reg_val |= RT1318_SYSCLK_RC2; + break; + case RT1318_SCLK_S_RC2: + reg_val |= RT1318_SYSCLK_RC3; + break; + default: + dev_err(component->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + + rt1318->sysclk = freq; + rt1318->sysclk_src = clk_id; + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_SYSCLK_SEL_MASK, reg_val); + + return 0; +} + +static const struct pll_calc_map pll_preset_table[] = { + {512000, 4096000, 22, 190, 0, true, false}, + {1024000, 4096000, 22, 94, 0, true, false}, + {1024000, 16384000, 4, 190, 0, true, false}, + {1411200, 11289600, 6, 62, 0, true, false}, + {1536000, 12288000, 6, 62, 0, true, false}, + {2822400, 11289600, 6, 62, 0, true, false}, + {2822400, 45158400, 0, 62, 0, true, false}, + {2822400, 49152000, 0, 62, 0, true, false}, + {3072000, 12288000, 6, 62, 0, true, false}, + {3072000, 24576000, 2, 62, 0, true, false}, + {3072000, 49152000, 0, 62, 0, true, false}, + {6144000, 24576000, 2, 94, 4, false, false}, + {6144000, 49152000, 0, 30, 0, true, false}, + {6144000, 98304000, 0, 94, 4, false, true}, + {12288000, 49152000, 0, 62, 6, false, false}, +}; + +static int rt1318_pll_calc(const unsigned int freq_in, + const unsigned int freq_out, struct rt1318_pll_code *pll_code) +{ + int max_n = RT1318_PLL_N_MAX, max_m = RT1318_PLL_M_MAX; + int i, k, red, n_t, pll_out, in_t, out_t; + int n = 0, m = 0, m_t = 0; + int red_t = abs(freq_out - freq_in); + bool m_bypass = false, k_bypass = false; + + if (RT1318_PLL_INP_MAX < freq_in || RT1318_PLL_INP_MIN > freq_in) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) { + if (freq_in == pll_preset_table[i].pll_in && + freq_out == pll_preset_table[i].pll_out) { + k = pll_preset_table[i].k; + m = pll_preset_table[i].m; + n = pll_preset_table[i].n; + m_bypass = pll_preset_table[i].m_bp; + k_bypass = pll_preset_table[i].k_bp; + goto code_find; + } + } + + k = 100000000 / freq_out - 2; + if (k > RT1318_PLL_K_MAX) + k = RT1318_PLL_K_MAX; + if (k < 0) { + k = 0; + k_bypass = true; + } + for (n_t = 0; n_t <= max_n; n_t++) { + in_t = freq_in / (k_bypass ? 1 : (k + 2)); + pll_out = freq_out / (n_t + 2); + if (in_t < 0) + continue; + if (in_t == pll_out) { + m_bypass = true; + n = n_t; + goto code_find; + } + red = abs(in_t - pll_out); + if (red < red_t) { + m_bypass = true; + n = n_t; + m = m_t; + if (red == 0) + goto code_find; + red_t = red; + } + for (m_t = 0; m_t <= max_m; m_t++) { + out_t = in_t / (m_t + 2); + red = abs(out_t - pll_out); + if (red < red_t) { + m_bypass = false; + n = n_t; + m = m_t; + if (red == 0) + goto code_find; + red_t = red; + } + } + } + pr_debug("Only get approximation about PLL\n"); + +code_find: + + pll_code->m_bp = m_bypass; + pll_code->k_bp = k_bypass; + pll_code->m_code = m; + pll_code->n_code = n; + pll_code->k_code = k; + return 0; +} + +static int rt1318_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_component *component = dai->component; + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + struct rt1318_pll_code pll_code; + int ret; + + if (!freq_in || !freq_out) { + dev_dbg(component->dev, "PLL disabled\n"); + rt1318->pll_in = 0; + rt1318->pll_out = 0; + return 0; + } + + if (source == rt1318->pll_src && freq_in == rt1318->pll_in && + freq_out == rt1318->pll_out) + return 0; + + switch (source) { + case RT1318_PLL_S_BCLK0: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_BCLK0); + break; + case RT1318_PLL_S_BCLK1: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_BCLK1); + break; + case RT1318_PLL_S_RC: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_RC); + break; + case RT1318_PLL_S_MCLK: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_MCLK); + break; + case RT1318_PLL_S_SDW_IN_PLL: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_SDW1); + break; + case RT1318_PLL_S_SDW_0: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_SDW2); + break; + case RT1318_PLL_S_SDW_1: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_SDW3); + break; + case RT1318_PLL_S_SDW_2: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_SDW4); + break; + default: + dev_err(component->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + + ret = rt1318_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + regmap_update_bits(rt1318->regmap, RT1318_PLL1_K, + RT1318_K_PLL1_MASK, pll_code.k_code); + regmap_update_bits(rt1318->regmap, RT1318_PLL1_M, + RT1318_M_PLL1_MASK, (pll_code.m_bp ? 0 : pll_code.m_code)); + regmap_update_bits(rt1318->regmap, RT1318_PLL1_N_8, + RT1318_N_8_PLL1_MASK, pll_code.n_code >> 8); + regmap_update_bits(rt1318->regmap, RT1318_PLL1_N_7_0, + RT1318_N_7_0_PLL1_MASK, pll_code.n_code); + + rt1318->pll_in = freq_in; + rt1318->pll_out = freq_out; + rt1318->pll_src = source; + + return 0; +} + +static int rt1318_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 rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + unsigned int cn = 0, cl = 0, rx_slotnum; + int ret = 0, first_bit; + + switch (slots) { + case 4: + cn |= RT1318_I2S_CH_TX_4CH; + cn |= RT1318_I2S_CH_RX_4CH; + break; + case 6: + cn |= RT1318_I2S_CH_TX_6CH; + cn |= RT1318_I2S_CH_RX_6CH; + break; + case 8: + cn |= RT1318_I2S_CH_TX_8CH; + cn |= RT1318_I2S_CH_RX_8CH; + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + cl |= RT1318_I2S_TX_CHL_20; + cl |= RT1318_I2S_RX_CHL_20; + break; + case 24: + cl |= RT1318_I2S_TX_CHL_24; + cl |= RT1318_I2S_RX_CHL_24; + break; + case 32: + cl |= RT1318_I2S_TX_CHL_32; + cl |= RT1318_I2S_RX_CHL_32; + break; + case 8: + cl |= RT1318_I2S_TX_CHL_8; + cl |= RT1318_I2S_RX_CHL_8; + break; + case 16: + break; + default: + return -EINVAL; + } + + /* Rx slot configuration */ + rx_slotnum = hweight_long(rx_mask); + if (rx_slotnum != 1) { + ret = -EINVAL; + dev_err(component->dev, "too many rx slots or zero slot\n"); + goto _set_tdm_err_; + } + + first_bit = __ffs(rx_mask); + switch (first_bit) { + case 0: + case 2: + case 4: + case 6: + regmap_update_bits(rt1318->regmap, + RT1318_TDM_CTRL9, + RT1318_TDM_I2S_TX_L_DAC1_1_MASK | + RT1318_TDM_I2S_TX_R_DAC1_1_MASK, + (first_bit << RT1318_TDM_I2S_TX_L_DAC1_1_SFT) | + ((first_bit + 1) << RT1318_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + case 1: + case 3: + case 5: + case 7: + regmap_update_bits(rt1318->regmap, + RT1318_TDM_CTRL9, + RT1318_TDM_I2S_TX_L_DAC1_1_MASK | + RT1318_TDM_I2S_TX_R_DAC1_1_MASK, + ((first_bit - 1) << RT1318_TDM_I2S_TX_L_DAC1_1_SFT) | + (first_bit << RT1318_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL2, + RT1318_I2S_CH_TX_MASK | RT1318_I2S_CH_RX_MASK, cn); + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL3, + RT1318_I2S_TX_CHL_MASK | RT1318_I2S_RX_CHL_MASK, cl); + +_set_tdm_err_: + return ret; +} + +static int rt1318_probe(struct snd_soc_component *component) +{ + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + rt1318->component = component; + + schedule_work(&rt1318->cali_work); + rt1318->rt1318_dvol = RT1318_DVOL_STEP; + + return 0; +} + +static void rt1318_remove(struct snd_soc_component *component) +{ + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + cancel_work_sync(&rt1318->cali_work); +} + +#ifdef CONFIG_PM +static int rt1318_suspend(struct snd_soc_component *component) +{ + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(rt1318->regmap, true); + regcache_mark_dirty(rt1318->regmap); + return 0; +} + +static int rt1318_resume(struct snd_soc_component *component) +{ + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(rt1318->regmap, false); + regcache_sync(rt1318->regmap); + return 0; +} +#else +#define rt1318_suspend NULL +#define rt1318_resume NULL +#endif + +#define RT1318_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt1318_aif_dai_ops = { + .hw_params = rt1318_hw_params, + .set_fmt = rt1318_set_dai_fmt, + .set_sysclk = rt1318_set_dai_sysclk, + .set_pll = rt1318_set_dai_pll, + .set_tdm_slot = rt1318_set_tdm_slot, +}; + +static struct snd_soc_dai_driver rt1318_dai[] = { + { + .name = "rt1318-aif", + .id = 0, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT1318_STEREO_RATES, + .formats = RT1318_FORMATS, + }, + .ops = &rt1318_aif_dai_ops, + } +}; + +static const struct snd_soc_component_driver soc_component_dev_rt1318 = { + .probe = rt1318_probe, + .remove = rt1318_remove, + .suspend = rt1318_suspend, + .resume = rt1318_resume, + .controls = rt1318_snd_controls, + .num_controls = ARRAY_SIZE(rt1318_snd_controls), + .dapm_widgets = rt1318_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt1318_dapm_widgets), + .dapm_routes = rt1318_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt1318_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct regmap_config rt1318_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt1318_readable_register, + .volatile_reg = rt1318_volatile_register, + .max_register = 0x41001888, + .reg_defaults = rt1318_reg, + .num_reg_defaults = ARRAY_SIZE(rt1318_reg), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static const struct i2c_device_id rt1318_i2c_id[] = { + { "rt1318", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt1318_i2c_id); + +static const struct of_device_id rt1318_of_match[] = { + { .compatible = "realtek,rt1318", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt1318_of_match); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id rt1318_acpi_match[] = { + { "10EC1318", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt1318_acpi_match); +#endif + +static int rt1318_parse_dt(struct rt1318_priv *rt1318, struct device *dev) +{ + device_property_read_u32(dev, "realtek,r0_l", + &rt1318->pdata.init_r0_l); + device_property_read_u32(dev, "realtek,r0_r", + &rt1318->pdata.init_r0_r); + + return 0; +} + +static void rt1318_calibration_sequence(struct rt1318_priv *rt1318) +{ + regmap_write(rt1318->regmap, RT1318_CLK1, 0x22); + regmap_write(rt1318->regmap, RT1318_PLL1_N_7_0, 0x06); + regmap_write(rt1318->regmap, RT1318_STP_TEMP_L, 0xCC); + regmap_write(rt1318->regmap, RT1318_STP_SEL_L, 0x40); + regmap_write(rt1318->regmap, RT1318_STP_SEL_R, 0x40); + regmap_write(rt1318->regmap, RT1318_SINE_GEN0, 0x20); + regmap_write(rt1318->regmap, RT1318_SPK_VOL_TH, 0x00); + regmap_write(rt1318->regmap, RT1318_FEEDBACK_PATH, 0x0B); + regmap_write(rt1318->regmap, RT1318_TCON, 0x1C); + regmap_write(rt1318->regmap, RT1318_TCON_RELATE, 0x58); + regmap_write(rt1318->regmap, RT1318_TCON_RELATE, 0x78); + regmap_write(rt1318->regmap, RT1318_STP_R0_EN_L, 0xC2); +} + +static void rt1318_r0_calculate(struct rt1318_priv *rt1318) +{ + unsigned int r0_l, r0_l_byte0, r0_l_byte1, r0_l_byte2, r0_l_byte3; + unsigned int r0_r, r0_r_byte0, r0_r_byte1, r0_r_byte2, r0_r_byte3; + unsigned int r0_l_integer, r0_l_factor, r0_r_integer, r0_r_factor; + unsigned int format = 16777216; /* 2^24 */ + + regmap_read(rt1318->regmap, RT1318_R0_L_24, &r0_l_byte0); + regmap_read(rt1318->regmap, RT1318_R0_L_23_16, &r0_l_byte1); + regmap_read(rt1318->regmap, RT1318_R0_L_15_8, &r0_l_byte2); + regmap_read(rt1318->regmap, RT1318_R0_L_7_0, &r0_l_byte3); + r0_l = r0_l_byte0 << 24 | r0_l_byte1 << 16 | r0_l_byte2 << 8 | r0_l_byte3; + r0_l_integer = format / r0_l; + r0_l_factor = (format * 10) / r0_l - r0_l_integer * 10; + + regmap_read(rt1318->regmap, RT1318_R0_R_24, &r0_r_byte0); + regmap_read(rt1318->regmap, RT1318_R0_R_23_16, &r0_r_byte1); + regmap_read(rt1318->regmap, RT1318_R0_R_15_8, &r0_r_byte2); + regmap_read(rt1318->regmap, RT1318_R0_R_7_0, &r0_r_byte3); + r0_r = r0_r_byte0 << 24 | r0_r_byte1 << 16 | r0_r_byte2 << 8 | r0_r_byte3; + r0_r_integer = format / r0_r; + r0_r_factor = (format * 10) / r0_r - r0_r_integer * 10; + + dev_dbg(rt1318->component->dev, "r0_l_ch:%d.%d ohm\n", r0_l_integer, r0_l_factor); + dev_dbg(rt1318->component->dev, "r0_r_ch:%d.%d ohm\n", r0_r_integer, r0_r_factor); +} + +static void rt1318_r0_restore(struct rt1318_priv *rt1318) +{ + regmap_write(rt1318->regmap, RT1318_PRE_R0_L_24, + (rt1318->pdata.init_r0_l >> 24) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_L_23_16, + (rt1318->pdata.init_r0_l >> 16) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_L_15_8, + (rt1318->pdata.init_r0_l >> 8) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_L_7_0, + (rt1318->pdata.init_r0_l >> 0) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_R_24, + (rt1318->pdata.init_r0_r >> 24) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_R_23_16, + (rt1318->pdata.init_r0_r >> 16) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_R_15_8, + (rt1318->pdata.init_r0_r >> 8) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_R_7_0, + (rt1318->pdata.init_r0_r >> 0) & 0xff); + regmap_write(rt1318->regmap, RT1318_STP_SEL_L, 0x80); + regmap_write(rt1318->regmap, RT1318_STP_SEL_R, 0x80); + regmap_write(rt1318->regmap, RT1318_R0_CMP_L_FLAG, 0xc0); + regmap_write(rt1318->regmap, RT1318_R0_CMP_R_FLAG, 0xc0); + regmap_write(rt1318->regmap, RT1318_STP_R0_EN_L, 0xc0); + regmap_write(rt1318->regmap, RT1318_STP_R0_EN_R, 0xc0); + regmap_write(rt1318->regmap, RT1318_STP_TEMP_L, 0xcc); + regmap_write(rt1318->regmap, RT1318_TCON, 0x9c); +} + +static int rt1318_calibrate(struct rt1318_priv *rt1318) +{ + int chk_cnt = 30, count = 0; + int val, val2; + + regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x1); + usleep_range(0, 10000); + rt1318_calibration_sequence(rt1318); + + while (count < chk_cnt) { + msleep(100); + regmap_read(rt1318->regmap, RT1318_R0_CMP_L_FLAG, &val); + regmap_read(rt1318->regmap, RT1318_R0_CMP_R_FLAG, &val2); + val = (val >> 1) & 0x1; + val2 = (val2 >> 1) & 0x1; + if (val & val2) { + dev_dbg(rt1318->component->dev, "Calibration done.\n"); + break; + } + count++; + if (count == chk_cnt) { + regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x0); + return RT1318_R0_CALIB_NOT_DONE; + } + } + regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x0); + regmap_read(rt1318->regmap, RT1318_R0_CMP_L_FLAG, &val); + regmap_read(rt1318->regmap, RT1318_R0_CMP_R_FLAG, &val2); + if ((val & 0x1) & (val2 & 0x1)) + return RT1318_R0_IN_RANGE; + else + return RT1318_R0_OUT_OF_RANGE; +} + +static void rt1318_calibration_work(struct work_struct *work) +{ + struct rt1318_priv *rt1318 = + container_of(work, struct rt1318_priv, cali_work); + int ret; + + if (rt1318->pdata.init_r0_l && rt1318->pdata.init_r0_r) + rt1318_r0_restore(rt1318); + else { + ret = rt1318_calibrate(rt1318); + if (ret == RT1318_R0_IN_RANGE) + rt1318_r0_calculate(rt1318); + dev_dbg(rt1318->component->dev, "Calibrate R0 result:%d\n", ret); + } +} + +static int rt1318_i2c_probe(struct i2c_client *i2c) +{ + struct rt1318_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt1318_priv *rt1318; + int ret, val, val2, dev_id; + + rt1318 = devm_kzalloc(&i2c->dev, sizeof(struct rt1318_priv), + GFP_KERNEL); + if (!rt1318) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt1318); + + if (pdata) + rt1318->pdata = *pdata; + else + rt1318_parse_dt(rt1318, &i2c->dev); + + rt1318->regmap = devm_regmap_init_i2c(i2c, &rt1318_regmap); + if (IS_ERR(rt1318->regmap)) { + ret = PTR_ERR(rt1318->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt1318->regmap, RT1318_DEV_ID1, &val); + regmap_read(rt1318->regmap, RT1318_DEV_ID2, &val2); + dev_id = (val << 8) | val2; + if (dev_id != 0x6821) { + dev_err(&i2c->dev, + "Device with ID register %#x is not rt1318\n", + dev_id); + return -ENODEV; + } + + ret = regmap_register_patch(rt1318->regmap, init_list, + ARRAY_SIZE(init_list)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + + INIT_WORK(&rt1318->cali_work, rt1318_calibration_work); + + return devm_snd_soc_register_component(&i2c->dev, + &soc_component_dev_rt1318, rt1318_dai, ARRAY_SIZE(rt1318_dai)); +} + +static struct i2c_driver rt1318_i2c_driver = { + .driver = { + .name = "rt1318", + .of_match_table = of_match_ptr(rt1318_of_match), + .acpi_match_table = ACPI_PTR(rt1318_acpi_match), + }, + .probe = rt1318_i2c_probe, + .id_table = rt1318_i2c_id, +}; +module_i2c_driver(rt1318_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT1318 driver"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt1318.h b/sound/soc/codecs/rt1318.h new file mode 100644 index 000000000000..cec40b484216 --- /dev/null +++ b/sound/soc/codecs/rt1318.h @@ -0,0 +1,342 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt1318.h -- Platform data for RT1318 + * + * Copyright 2024 Realtek Semiconductor Corp. + */ +#include + +#ifndef __RT1318_H__ +#define __RT1318_H__ + +struct rt1318_priv { + struct snd_soc_component *component; + struct rt1318_platform_data pdata; + struct work_struct cali_work; + struct regmap *regmap; + + unsigned int r0_l_integer; + unsigned int r0_l_factor; + unsigned int r0_r_integer; + unsigned int r0_r_factor; + int rt1318_init; + int rt1318_dvol; + int sysclk_src; + int sysclk; + int lrck; + int bclk; + int master; + int pll_src; + int pll_in; + int pll_out; +}; + +#define RT1318_PLL_INP_MAX 40000000 +#define RT1318_PLL_INP_MIN 256000 +#define RT1318_PLL_N_MAX 0x1ff +#define RT1318_PLL_K_MAX 0x1f +#define RT1318_PLL_M_MAX 0x1f + +#define RT1318_LRCLK_192000 192000 +#define RT1318_LRCLK_96000 96000 +#define RT1318_LRCLK_48000 48000 +#define RT1318_LRCLK_44100 44100 +#define RT1318_LRCLK_16000 16000 +#define RT1318_DVOL_STEP 383 + +#define RT1318_CLK1 0xc001 +#define RT1318_CLK2 0xc003 +#define RT1318_CLK3 0xc004 +#define RT1318_CLK4 0xc005 +#define RT1318_CLK5 0xc006 +#define RT1318_CLK6 0xc007 +#define RT1318_CLK7 0xc008 +#define RT1318_PWR_STA1 0xc121 +#define RT1318_SPK_VOL_TH 0xc130 +#define RT1318_TCON 0xc203 +#define RT1318_SRC_TCON 0xc204 +#define RT1318_TCON_RELATE 0xc206 +#define RT1318_DA_VOL_L_8 0xc20b +#define RT1318_DA_VOL_L_1_7 0xc20c +#define RT1318_DA_VOL_R_8 0xc20d +#define RT1318_DA_VOL_R_1_7 0xc20e +#define RT1318_FEEDBACK_PATH 0xc321 +#define RT1318_STP_TEMP_L 0xdb00 +#define RT1318_STP_SEL_L 0xdb08 +#define RT1318_STP_R0_EN_L 0xdb12 +#define RT1318_R0_CMP_L_FLAG 0xdb35 +#define RT1318_PRE_R0_L_24 0xdbb5 +#define RT1318_PRE_R0_L_23_16 0xdbb6 +#define RT1318_PRE_R0_L_15_8 0xdbb7 +#define RT1318_PRE_R0_L_7_0 0xdbb8 +#define RT1318_R0_L_24 0xdbc5 +#define RT1318_R0_L_23_16 0xdbc6 +#define RT1318_R0_L_15_8 0xdbc7 +#define RT1318_R0_L_7_0 0xdbc8 +#define RT1318_STP_SEL_R 0xdd08 +#define RT1318_STP_R0_EN_R 0xdd12 +#define RT1318_R0_CMP_R_FLAG 0xdd35 +#define RT1318_PRE_R0_R_24 0xddb5 +#define RT1318_PRE_R0_R_23_16 0xddb6 +#define RT1318_PRE_R0_R_15_8 0xddb7 +#define RT1318_PRE_R0_R_7_0 0xddb8 +#define RT1318_R0_R_24 0xddc5 +#define RT1318_R0_R_23_16 0xddc6 +#define RT1318_R0_R_15_8 0xddc7 +#define RT1318_R0_R_7_0 0xddc8 +#define RT1318_DEV_ID1 0xf012 +#define RT1318_DEV_ID2 0xf013 +#define RT1318_PLL1_K 0xf20d +#define RT1318_PLL1_M 0xf20f +#define RT1318_PLL1_N_8 0xf211 +#define RT1318_PLL1_N_7_0 0xf212 +#define RT1318_SINE_GEN0 0xf800 +#define RT1318_TDM_CTRL1 0xf900 +#define RT1318_TDM_CTRL2 0xf901 +#define RT1318_TDM_CTRL3 0xf902 +#define RT1318_TDM_CTRL9 0xf908 + + +/* Clock-1 (0xC001) */ +#define RT1318_PLLIN_MASK (0x7 << 4) +#define RT1318_PLLIN_BCLK0 (0x0 << 4) +#define RT1318_PLLIN_BCLK1 (0x1 << 4) +#define RT1318_PLLIN_RC (0x2 << 4) +#define RT1318_PLLIN_MCLK (0x3 << 4) +#define RT1318_PLLIN_SDW1 (0x4 << 4) +#define RT1318_PLLIN_SDW2 (0x5 << 4) +#define RT1318_PLLIN_SDW3 (0x6 << 4) +#define RT1318_PLLIN_SDW4 (0x7 << 4) +#define RT1318_SYSCLK_SEL_MASK (0x7 << 0) +#define RT1318_SYSCLK_BCLK (0x0 << 0) +#define RT1318_SYSCLK_SDW (0x1 << 0) +#define RT1318_SYSCLK_PLL2F (0x2 << 0) +#define RT1318_SYSCLK_PLL2B (0x3 << 0) +#define RT1318_SYSCLK_MCLK (0x4 << 0) +#define RT1318_SYSCLK_RC1 (0x5 << 0) +#define RT1318_SYSCLK_RC2 (0x6 << 0) +#define RT1318_SYSCLK_RC3 (0x7 << 0) +/* Clock-2 (0xC003) */ +#define RT1318_DIV_AP_MASK (0x3 << 4) +#define RT1318_DIV_AP_SFT 4 +#define RT1318_DIV_AP_DIV1 (0x0 << 4) +#define RT1318_DIV_AP_DIV2 (0x1 << 4) +#define RT1318_DIV_AP_DIV4 (0x2 << 4) +#define RT1318_DIV_AP_DIV8 (0x3 << 4) +#define RT1318_DIV_DAMOD_MASK (0x3 << 0) +#define RT1318_DIV_DAMOD_SFT 0 +#define RT1318_DIV_DAMOD_DIV1 (0x0 << 0) +#define RT1318_DIV_DAMOD_DIV2 (0x1 << 0) +#define RT1318_DIV_DAMOD_DIV4 (0x2 << 0) +#define RT1318_DIV_DAMOD_DIV8 (0x3 << 0) +/* Clock-3 (0xC004) */ +#define RT1318_AD_STO1_MASK (0x7 << 4) +#define RT1318_AD_STO1_SFT 4 +#define RT1318_AD_STO1_DIV1 (0x0 << 4) +#define RT1318_AD_STO1_DIV2 (0x1 << 4) +#define RT1318_AD_STO1_DIV4 (0x2 << 4) +#define RT1318_AD_STO1_DIV8 (0x3 << 4) +#define RT1318_AD_STO1_DIV16 (0x4 << 4) +#define RT1318_AD_STO2_MASK (0x7 << 0) +#define RT1318_AD_STO2_SFT 0 +#define RT1318_AD_STO2_DIV1 (0x0 << 0) +#define RT1318_AD_STO2_DIV2 (0x1 << 0) +#define RT1318_AD_STO2_DIV4 (0x2 << 0) +#define RT1318_AD_STO2_DIV8 (0x3 << 0) +#define RT1318_AD_STO2_DIV16 (0x4 << 0) +#define RT1318_AD_STO2_SFT 0 +/* Clock-4 (0xC005) */ +#define RT1318_AD_ANA_STO1_MASK (0x7 << 4) +#define RT1318_AD_ANA_STO1_SFT 4 +#define RT1318_AD_ANA_STO1_DIV1 (0x0 << 4) +#define RT1318_AD_ANA_STO1_DIV2 (0x1 << 4) +#define RT1318_AD_ANA_STO1_DIV4 (0x2 << 4) +#define RT1318_AD_ANA_STO1_DIV8 (0x3 << 4) +#define RT1318_AD_ANA_STO1_DIV16 (0x4 << 4) +#define RT1318_AD_ANA_STO2_MASK (0x7 << 0) +#define RT1318_AD_ANA_STO2_DIV1 (0x0 << 0) +#define RT1318_AD_ANA_STO2_DIV2 (0x1 << 0) +#define RT1318_AD_ANA_STO2_DIV4 (0x2 << 0) +#define RT1318_AD_ANA_STO2_DIV8 (0x3 << 0) +#define RT1318_AD_ANA_STO2_DIV16 (0x4 << 0) +#define RT1318_AD_ANA_STO2_SFT 0 +/* Clock-5 (0xC006) */ +#define RT1318_DIV_FIFO_IN_MASK (0x3 << 4) +#define RT1318_DIV_FIFO_IN_SFT 4 +#define RT1318_DIV_FIFO_IN_DIV1 (0x0 << 4) +#define RT1318_DIV_FIFO_IN_DIV2 (0x1 << 4) +#define RT1318_DIV_FIFO_IN_DIV4 (0x2 << 4) +#define RT1318_DIV_FIFO_IN_DIV8 (0x3 << 4) +#define RT1318_DIV_FIFO_OUT_MASK (0x3 << 0) +#define RT1318_DIV_FIFO_OUT_DIV1 (0x0 << 0) +#define RT1318_DIV_FIFO_OUT_DIV2 (0x1 << 0) +#define RT1318_DIV_FIFO_OUT_DIV4 (0x2 << 0) +#define RT1318_DIV_FIFO_OUT_DIV8 (0x3 << 0) +#define RT1318_DIV_FIFO_OUT_SFT 0 +/* Clock-6 (0xC007) */ +#define RT1318_DIV_NLMS_MASK (0x3 << 6) +#define RT1318_DIV_NLMS_SFT 6 +#define RT1318_DIV_NLMS_DIV1 (0x0 << 6) +#define RT1318_DIV_NLMS_DIV2 (0x1 << 6) +#define RT1318_DIV_NLMS_DIV4 (0x2 << 6) +#define RT1318_DIV_NLMS_DIV8 (0x3 << 6) +#define RT1318_DIV_AD_MONO_MASK (0x7 << 3) +#define RT1318_DIV_AD_MONO_SFT 3 +#define RT1318_DIV_AD_MONO_DIV1 (0x0 << 3) +#define RT1318_DIV_AD_MONO_DIV2 (0x1 << 3) +#define RT1318_DIV_AD_MONO_DIV4 (0x2 << 3) +#define RT1318_DIV_AD_MONO_DIV8 (0x3 << 3) +#define RT1318_DIV_AD_MONO_DIV16 (0x4 << 3) +#define RT1318_DIV_POST_G_MASK (0x7 << 0) +#define RT1318_DIV_POST_G_SFT 0 +#define RT1318_DIV_POST_G_DIV1 (0x0 << 0) +#define RT1318_DIV_POST_G_DIV2 (0x1 << 0) +#define RT1318_DIV_POST_G_DIV4 (0x2 << 0) +#define RT1318_DIV_POST_G_DIV8 (0x3 << 0) +#define RT1318_DIV_POST_G_DIV16 (0x4 << 0) +/* Power Status 1 (0xC121) */ +#define RT1318_PDB_CTRL_MASK (0x1) +#define RT1318_PDB_CTRL_LOW (0x0) +#define RT1318_PDB_CTRL_HIGH (0x1) +#define RT1318_PDB_CTRL_SFT 0 +/* SRC Tcon(0xc204) */ +#define RT1318_SRCIN_IN_SEL_MASK (0x3 << 6) +#define RT1318_SRCIN_IN_48K (0x0 << 6) +#define RT1318_SRCIN_IN_44P1 (0x1 << 6) +#define RT1318_SRCIN_IN_32K (0x2 << 6) +#define RT1318_SRCIN_IN_16K (0x3 << 6) +#define RT1318_SRCIN_F12288_MASK (0x3 << 4) +#define RT1318_SRCIN_TCON1 (0x0 << 4) +#define RT1318_SRCIN_TCON2 (0x1 << 4) +#define RT1318_SRCIN_TCON4 (0x2 << 4) +#define RT1318_SRCIN_TCON8 (0x3 << 4) +#define RT1318_SRCIN_DACLK_MASK (0x3 << 2) +#define RT1318_DACLK_TCON1 (0x0 << 2) +#define RT1318_DACLK_TCON2 (0x1 << 2) +#define RT1318_DACLK_TCON4 (0x2 << 2) +#define RT1318_DACLK_TCON8 (0x3 << 2) +/* R0 Compare Flag (0xDB35) */ +#define RT1318_R0_RANGE_MASK (0x1) +#define RT1318_R0_OUTOFRANGE (0x0) +#define RT1318_R0_INRANGE (0x1) +/* PLL internal setting (0xF20D), K value */ +#define RT1318_K_PLL1_MASK (0x1f << 0) +/* PLL internal setting (0xF20F), M value */ +#define RT1318_M_PLL1_MASK (0x1f << 0) +/* PLL internal setting (0xF211), N_8 value */ +#define RT1318_N_8_PLL1_MASK (0x1 << 0) +/* PLL internal setting (0xF212), N_7_0 value */ +#define RT1318_N_7_0_PLL1_MASK (0xff << 0) +/* TDM CTRL 1 (0xf900) */ +#define RT1318_TDM_BCLK_MASK (0x1 << 7) +#define RT1318_TDM_BCLK_NORM (0x0 << 7) +#define RT1318_TDM_BCLK_INV (0x1 << 7) +#define RT1318_I2S_FMT_MASK (0x7 << 0) +#define RT1318_FMT_I2S (0x0 << 0) +#define RT1318_FMT_LEFT_J (0x1 << 0) +#define RT1318_FMT_PCM_A_R (0x2 << 0) +#define RT1318_FMT_PCM_B_R (0x3 << 0) +#define RT1318_FMT_PCM_A_F (0x6 << 0) +#define RT1318_FMT_PCM_B_F (0x7 << 0) +#define RT1318_I2S_FMT_SFT 0 +/* TDM CTRL 2 (0xf901) */ +#define RT1318_I2S_CH_TX_MASK (0x3 << 6) +#define RT1318_I2S_CH_TX_2CH (0x0 << 6) +#define RT1318_I2S_CH_TX_4CH (0x1 << 6) +#define RT1318_I2S_CH_TX_6CH (0x2 << 6) +#define RT1318_I2S_CH_TX_8CH (0x3 << 6) +#define RT1318_I2S_CH_RX_MASK (0x3 << 4) +#define RT1318_I2S_CH_RX_2CH (0x0 << 4) +#define RT1318_I2S_CH_RX_4CH (0x1 << 4) +#define RT1318_I2S_CH_RX_6CH (0x2 << 4) +#define RT1318_I2S_CH_RX_8CH (0x3 << 4) +#define RT1318_I2S_DL_MASK 0x7 +#define RT1318_I2S_DL_SFT 0 +#define RT1318_I2S_DL_16 0x0 +#define RT1318_I2S_DL_20 0x1 +#define RT1318_I2S_DL_24 0x2 +#define RT1318_I2S_DL_32 0x3 +#define RT1318_I2S_DL_8 0x4 +/* TDM CTRL 3 (0xf902) */ +#define RT1318_I2S_TX_CHL_MASK (0x7 << 4) +#define RT1318_I2S_TX_CHL_SFT 4 +#define RT1318_I2S_TX_CHL_16 (0x0 << 4) +#define RT1318_I2S_TX_CHL_20 (0x1 << 4) +#define RT1318_I2S_TX_CHL_24 (0x2 << 4) +#define RT1318_I2S_TX_CHL_32 (0x3 << 4) +#define RT1318_I2S_TX_CHL_8 (0x4 << 4) +#define RT1318_I2S_RX_CHL_MASK (0x7 << 0) +#define RT1318_I2S_RX_CHL_SFT 0 +#define RT1318_I2S_RX_CHL_16 (0x0 << 0) +#define RT1318_I2S_RX_CHL_20 (0x1 << 0) +#define RT1318_I2S_RX_CHL_24 (0x2 << 0) +#define RT1318_I2S_RX_CHL_32 (0x3 << 0) +#define RT1318_I2S_RX_CHL_8 (0x4 << 0) +/* TDM CTRL 9 (0xf908) */ +#define RT1318_TDM_I2S_TX_L_DAC1_1_MASK (0x7 << 4) +#define RT1318_TDM_I2S_TX_R_DAC1_1_MASK 0x7 +#define RT1318_TDM_I2S_TX_L_DAC1_1_SFT 4 +#define RT1318_TDM_I2S_TX_R_DAC1_1_SFT 0 + +#define RT1318_REG_DISP_LEN 23 + +/* System Clock Source */ +enum { + RT1318_SCLK_S_BCLK, + RT1318_SCLK_S_SDW, + RT1318_SCLK_S_PLL2F, + RT1318_SCLK_S_PLL2B, + RT1318_SCLK_S_MCLK, + RT1318_SCLK_S_RC0, + RT1318_SCLK_S_RC1, + RT1318_SCLK_S_RC2, +}; + +/* PLL Source */ +enum { + RT1318_PLL_S_BCLK0, + RT1318_PLL_S_BCLK1, + RT1318_PLL_S_RC, + RT1318_PLL_S_MCLK, + RT1318_PLL_S_SDW_IN_PLL, + RT1318_PLL_S_SDW_0, + RT1318_PLL_S_SDW_1, + RT1318_PLL_S_SDW_2, +}; + +/* TDM channel */ +enum { + RT1318_2CH, + RT1318_4CH, + RT1318_6CH, + RT1318_8CH, +}; + +/* R0 calibration result */ +enum { + RT1318_R0_OUT_OF_RANGE, + RT1318_R0_IN_RANGE, + RT1318_R0_CALIB_NOT_DONE, +}; + +/* PLL pre-defined M/N/K */ + +struct pll_calc_map { + unsigned int pll_in; + unsigned int pll_out; + int k; + int n; + int m; + bool m_bp; + bool k_bp; +}; + +struct rt1318_pll_code { + bool m_bp; /* Indicates bypass m code or not. */ + bool k_bp; /* Indicates bypass k code or not. */ + int m_code; + int n_code; + int k_code; +}; + +#endif /* __RT1318_H__ */ From ae8fc2948b48f001514d4b73167fcef3b398a5fb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Jun 2024 00:32:39 +0000 Subject: [PATCH 173/349] ASoC: dt-bindings: add missing vender prefix on filename Many Sound yaml files doesn't have vender prefix on filename. Add missing vender prefix for these files. Signed-off-by: Kuninori Morimoto Reviewed-by: Daniel Baluta Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/87wmmkpi6w.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../bindings/sound/{ak4375.yaml => asahi-kasei,ak4375.yaml} | 2 +- .../bindings/sound/{ak4613.yaml => asahi-kasei,ak4613.yaml} | 2 +- .../bindings/sound/{ak4642.yaml => asahi-kasei,ak4642.yaml} | 2 +- .../bindings/sound/{sgtl5000.yaml => fsl,sgtl5000.yaml} | 2 +- .../bindings/sound/{zl38060.yaml => mscc,zl38060.yaml} | 2 +- .../bindings/sound/{rt1019.yaml => realtek,rt1019.yaml} | 2 +- .../devicetree/bindings/sound/{tas2562.yaml => ti,tas2562.yaml} | 2 +- .../devicetree/bindings/sound/{tas2770.yaml => ti,tas2770.yaml} | 2 +- .../devicetree/bindings/sound/{tas27xx.yaml => ti,tas27xx.yaml} | 2 +- .../bindings/sound/{tas5805m.yaml => ti,tas5805m.yaml} | 2 +- .../sound/{tlv320adcx140.yaml => ti,tlv320adcx140.yaml} | 2 +- .../devicetree/bindings/sound/{wm8750.yaml => wlf,wm8750.yaml} | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) rename Documentation/devicetree/bindings/sound/{ak4375.yaml => asahi-kasei,ak4375.yaml} (94%) rename Documentation/devicetree/bindings/sound/{ak4613.yaml => asahi-kasei,ak4613.yaml} (94%) rename Documentation/devicetree/bindings/sound/{ak4642.yaml => asahi-kasei,ak4642.yaml} (94%) rename Documentation/devicetree/bindings/sound/{sgtl5000.yaml => fsl,sgtl5000.yaml} (97%) rename Documentation/devicetree/bindings/sound/{zl38060.yaml => mscc,zl38060.yaml} (96%) rename Documentation/devicetree/bindings/sound/{rt1019.yaml => realtek,rt1019.yaml} (90%) rename Documentation/devicetree/bindings/sound/{tas2562.yaml => ti,tas2562.yaml} (97%) rename Documentation/devicetree/bindings/sound/{tas2770.yaml => ti,tas2770.yaml} (97%) rename Documentation/devicetree/bindings/sound/{tas27xx.yaml => ti,tas27xx.yaml} (97%) rename Documentation/devicetree/bindings/sound/{tas5805m.yaml => ti,tas5805m.yaml} (95%) rename Documentation/devicetree/bindings/sound/{tlv320adcx140.yaml => ti,tlv320adcx140.yaml} (99%) rename Documentation/devicetree/bindings/sound/{wm8750.yaml => wlf,wm8750.yaml} (92%) diff --git a/Documentation/devicetree/bindings/sound/ak4375.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4375.yaml similarity index 94% rename from Documentation/devicetree/bindings/sound/ak4375.yaml rename to Documentation/devicetree/bindings/sound/asahi-kasei,ak4375.yaml index 587598e122c6..bc07fcba535b 100644 --- a/Documentation/devicetree/bindings/sound/ak4375.yaml +++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4375.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/ak4375.yaml# +$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4375.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: AK4375 DAC and headphones amplifier diff --git a/Documentation/devicetree/bindings/sound/ak4613.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4613.yaml similarity index 94% rename from Documentation/devicetree/bindings/sound/ak4613.yaml rename to Documentation/devicetree/bindings/sound/asahi-kasei,ak4613.yaml index 75e13414d6eb..b49a6cff9f1f 100644 --- a/Documentation/devicetree/bindings/sound/ak4613.yaml +++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4613.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/ak4613.yaml# +$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4613.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: AK4613 I2C transmitter diff --git a/Documentation/devicetree/bindings/sound/ak4642.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4642.yaml similarity index 94% rename from Documentation/devicetree/bindings/sound/ak4642.yaml rename to Documentation/devicetree/bindings/sound/asahi-kasei,ak4642.yaml index 437fe5d7cae1..fc03f0373a1a 100644 --- a/Documentation/devicetree/bindings/sound/ak4642.yaml +++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4642.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/ak4642.yaml# +$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4642.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: AK4642 I2C transmitter diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.yaml b/Documentation/devicetree/bindings/sound/fsl,sgtl5000.yaml similarity index 97% rename from Documentation/devicetree/bindings/sound/sgtl5000.yaml rename to Documentation/devicetree/bindings/sound/fsl,sgtl5000.yaml index 1353c051488f..c6ab1ca16763 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,sgtl5000.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/sgtl5000.yaml# +$id: http://devicetree.org/schemas/sound/fsl,sgtl5000.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Freescale SGTL5000 Stereo Codec diff --git a/Documentation/devicetree/bindings/sound/zl38060.yaml b/Documentation/devicetree/bindings/sound/mscc,zl38060.yaml similarity index 96% rename from Documentation/devicetree/bindings/sound/zl38060.yaml rename to Documentation/devicetree/bindings/sound/mscc,zl38060.yaml index 8bd201e573aa..994313fd12b2 100644 --- a/Documentation/devicetree/bindings/sound/zl38060.yaml +++ b/Documentation/devicetree/bindings/sound/mscc,zl38060.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/zl38060.yaml# +$id: http://devicetree.org/schemas/sound/mscc,zl38060.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: ZL38060 Connected Home Audio Processor from Microsemi. diff --git a/Documentation/devicetree/bindings/sound/rt1019.yaml b/Documentation/devicetree/bindings/sound/realtek,rt1019.yaml similarity index 90% rename from Documentation/devicetree/bindings/sound/rt1019.yaml rename to Documentation/devicetree/bindings/sound/realtek,rt1019.yaml index 3d5a91a942f4..adf5e38f4dbc 100644 --- a/Documentation/devicetree/bindings/sound/rt1019.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt1019.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/rt1019.yaml# +$id: http://devicetree.org/schemas/sound/realtek,rt1019.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: RT1019 Mono Class-D Audio Amplifier diff --git a/Documentation/devicetree/bindings/sound/tas2562.yaml b/Documentation/devicetree/bindings/sound/ti,tas2562.yaml similarity index 97% rename from Documentation/devicetree/bindings/sound/tas2562.yaml rename to Documentation/devicetree/bindings/sound/ti,tas2562.yaml index d28c102c0ce7..8bc3b0c7531e 100644 --- a/Documentation/devicetree/bindings/sound/tas2562.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas2562.yaml @@ -2,7 +2,7 @@ # Copyright (C) 2019 Texas Instruments Incorporated %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/tas2562.yaml# +$id: http://devicetree.org/schemas/sound/ti,tas2562.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TAS2562 Smart PA diff --git a/Documentation/devicetree/bindings/sound/tas2770.yaml b/Documentation/devicetree/bindings/sound/ti,tas2770.yaml similarity index 97% rename from Documentation/devicetree/bindings/sound/tas2770.yaml rename to Documentation/devicetree/bindings/sound/ti,tas2770.yaml index be2536e8c440..362c2e6154f0 100644 --- a/Documentation/devicetree/bindings/sound/tas2770.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas2770.yaml @@ -2,7 +2,7 @@ # Copyright (C) 2019-20 Texas Instruments Incorporated %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/tas2770.yaml# +$id: http://devicetree.org/schemas/sound/ti,tas2770.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TAS2770 Smart PA diff --git a/Documentation/devicetree/bindings/sound/tas27xx.yaml b/Documentation/devicetree/bindings/sound/ti,tas27xx.yaml similarity index 97% rename from Documentation/devicetree/bindings/sound/tas27xx.yaml rename to Documentation/devicetree/bindings/sound/ti,tas27xx.yaml index f2d878f6f495..530bc3937847 100644 --- a/Documentation/devicetree/bindings/sound/tas27xx.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas27xx.yaml @@ -2,7 +2,7 @@ # Copyright (C) 2020-2022 Texas Instruments Incorporated %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/tas27xx.yaml# +$id: http://devicetree.org/schemas/sound/ti,tas27xx.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TAS2764/TAS2780 Smart PA diff --git a/Documentation/devicetree/bindings/sound/tas5805m.yaml b/Documentation/devicetree/bindings/sound/ti,tas5805m.yaml similarity index 95% rename from Documentation/devicetree/bindings/sound/tas5805m.yaml rename to Documentation/devicetree/bindings/sound/ti,tas5805m.yaml index 12c41974274e..c2c2835a9e1d 100644 --- a/Documentation/devicetree/bindings/sound/tas5805m.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas5805m.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/tas5805m.yaml# +$id: http://devicetree.org/schemas/sound/ti,tas5805m.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: TAS5805M audio amplifier diff --git a/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml similarity index 99% rename from Documentation/devicetree/bindings/sound/tlv320adcx140.yaml rename to Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml index f3274bcc4c05..876fa97bfbcd 100644 --- a/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml @@ -2,7 +2,7 @@ # Copyright (C) 2019 Texas Instruments Incorporated %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/tlv320adcx140.yaml# +$id: http://devicetree.org/schemas/sound/ti,tlv320adcx140.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TLV320ADCX140 Quad Channel Analog-to-Digital Converter diff --git a/Documentation/devicetree/bindings/sound/wm8750.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8750.yaml similarity index 92% rename from Documentation/devicetree/bindings/sound/wm8750.yaml rename to Documentation/devicetree/bindings/sound/wlf,wm8750.yaml index 24246ac7bbdf..96859e38315b 100644 --- a/Documentation/devicetree/bindings/sound/wm8750.yaml +++ b/Documentation/devicetree/bindings/sound/wlf,wm8750.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/wm8750.yaml# +$id: http://devicetree.org/schemas/sound/wlf,wm8750.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: WM8750 and WM8987 audio CODECs From 78df231dae2e1a9bf22f76b5cf03c0bf98738fd7 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 20 Jun 2024 11:39:57 +0200 Subject: [PATCH 174/349] ASoC: dt-bindings: convert everest,es7241.txt to dt-schema Convert the text biddings for the Everest ES7241 2 channels I2S analog to digital converter to dt-schema. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20240620-topic-amlogic-upstream-bindings-convert-everest-v2-1-660985615522@linaro.org Signed-off-by: Mark Brown --- .../bindings/sound/everest,es7241.txt | 28 -------- .../bindings/sound/everest,es7241.yaml | 67 +++++++++++++++++++ 2 files changed, 67 insertions(+), 28 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/everest,es7241.txt create mode 100644 Documentation/devicetree/bindings/sound/everest,es7241.yaml diff --git a/Documentation/devicetree/bindings/sound/everest,es7241.txt b/Documentation/devicetree/bindings/sound/everest,es7241.txt deleted file mode 100644 index 28f82cf4959f..000000000000 --- a/Documentation/devicetree/bindings/sound/everest,es7241.txt +++ /dev/null @@ -1,28 +0,0 @@ -ES7241 i2s AD converter - -Required properties: -- compatible : "everest,es7241" -- VDDP-supply: regulator phandle for the VDDA supply -- VDDA-supply: regulator phandle for the VDDP supply -- VDDD-supply: regulator phandle for the VDDD supply - -Optional properties: -- reset-gpios: gpio connected to the reset pin -- m0-gpios : gpio connected to the m0 pin -- m1-gpios : gpio connected to the m1 pin -- everest,sdout-pull-down: - Format used by the serial interface is controlled by pulling - the sdout. If the sdout is pulled down, leftj format is used. - If this property is not provided, sdout is assumed to pulled - up and i2s format is used - -Example: - -linein: audio-codec@2 { - #sound-dai-cells = <0>; - compatible = "everest,es7241"; - VDDA-supply = <&vcc_3v3>; - VDDP-supply = <&vcc_3v3>; - VDDD-supply = <&vcc_3v3>; - reset-gpios = <&gpio GPIOH_42>; -}; diff --git a/Documentation/devicetree/bindings/sound/everest,es7241.yaml b/Documentation/devicetree/bindings/sound/everest,es7241.yaml new file mode 100644 index 000000000000..f179af758730 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/everest,es7241.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/everest,es7241.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Everest ES7241 2 channels I2S analog to digital converter + +maintainers: + - Neil Armstrong + +properties: + compatible: + enum: + - everest,es7241 + + reset-gpios: + maxItems: 1 + description: GPIO connected to the reset pin + + m0-gpios: + maxItems: 1 + description: GPIO connected to the m0 pin + + m1-gpios: + maxItems: 1 + description: GPIO connected to the m0 pin + + everest,sdout-pull-down: + type: boolean + description: + Format used by the serial interface is controlled by pulling + the sdout. If the sdout is pulled down, leftj format is used. + If this property is not provided, sdout is assumed to pulled + up and i2s format is used + + VDDP-supply: true + VDDA-supply: true + VDDD-supply: true + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - VDDP-supply + - VDDA-supply + - VDDD-supply + +allOf: + - $ref: dai-common.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + codec { + compatible = "everest,es7241"; + #sound-dai-cells = <0>; + reset-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + VDDP-supply = <&vddp_supply>; + VDDA-supply = <&vdda_supply>; + VDDD-supply = <&vddd_supply>; + }; + +... From 534a0e5e737f8117344372d8658a4702ae816281 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 20 Jun 2024 11:39:58 +0200 Subject: [PATCH 175/349] ASoC: dt-bindings: convert everest,es7134.txt to dt-schema Convert the text bindings of the Everest ES7134/7144/7154 2 channels I2S analog to digital converter to dt-schema. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20240620-topic-amlogic-upstream-bindings-convert-everest-v2-2-660985615522@linaro.org Signed-off-by: Mark Brown --- .../bindings/sound/everest,es7134.txt | 15 ----- .../bindings/sound/everest,es71x4.yaml | 62 +++++++++++++++++++ 2 files changed, 62 insertions(+), 15 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/everest,es7134.txt create mode 100644 Documentation/devicetree/bindings/sound/everest,es71x4.yaml diff --git a/Documentation/devicetree/bindings/sound/everest,es7134.txt b/Documentation/devicetree/bindings/sound/everest,es7134.txt deleted file mode 100644 index 091666069bde..000000000000 --- a/Documentation/devicetree/bindings/sound/everest,es7134.txt +++ /dev/null @@ -1,15 +0,0 @@ -ES7134 i2s DA converter - -Required properties: -- compatible : "everest,es7134" or - "everest,es7144" or - "everest,es7154" -- VDD-supply : regulator phandle for the VDD supply -- PVDD-supply: regulator phandle for the PVDD supply for the es7154 - -Example: - -i2s_codec: external-codec { - compatible = "everest,es7134"; - VDD-supply = <&vcc_5v>; -}; diff --git a/Documentation/devicetree/bindings/sound/everest,es71x4.yaml b/Documentation/devicetree/bindings/sound/everest,es71x4.yaml new file mode 100644 index 000000000000..fd1b32812228 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/everest,es71x4.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/everest,es71x4.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Everest ES7134/7144/7154 2 channels I2S analog to digital converter + +maintainers: + - Neil Armstrong + +properties: + compatible: + enum: + - everest,es7134 + - everest,es7144 + - everest,es7154 + + VDD-supply: true + PVDD-supply: true + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - VDD-supply + +allOf: + - $ref: dai-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - everest,es7134 + - everest,es7144 + then: + properties: + PVDD-supply: false + + - if: + properties: + compatible: + contains: + enum: + - everest,es7154 + then: + required: + - PVDD-supply + +unevaluatedProperties: false + +examples: + - | + codec { + compatible = "everest,es7134"; + #sound-dai-cells = <0>; + VDD-supply = <&vdd_supply>; + }; + +... From 75a08ec8c3a6aef914235c409a99046a3d29d1d4 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 17 Jun 2024 12:58:37 +0530 Subject: [PATCH 176/349] ASoC: amd: acp: remove acp_i2s_probe function In acp_i2s_probe(), acp_base null check is verified. As already acp_base null check will be verified in acp platform driver probe sequence, additional NULL check in acp_i2s_probe() is not needed. Remove acp_i2s_probe() function. Signed-off-by: Vijendar Mukunda Link: https://patch.msgid.link/20240617072844.871468-4-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-i2s.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 6815e751a819..54985fd0eede 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -584,21 +584,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d return 0; } -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); - - if (!adata->acp_base) { - dev_err(dev, "I2S base is NULL\n"); - return -EINVAL; - } - - return 0; -} - 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, From 50f1670145392398f4f2ffe9abe4599c86d11ec2 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 17 Jun 2024 12:58:38 +0530 Subject: [PATCH 177/349] ASoC: amd: acp: remove unused variables from acp_resource structure Remove unused variables i2s_pin_cfg_offset and i2s_mode from acp_resource structure entries. Signed-off-by: Vijendar Mukunda Link: https://patch.msgid.link/20240617072844.871468-5-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-rembrandt.c | 2 -- sound/soc/amd/acp/acp-renoir.c | 2 -- sound/soc/amd/acp/acp63.c | 2 -- sound/soc/amd/acp/acp70.c | 2 -- sound/soc/amd/acp/amd.h | 2 -- 5 files changed, 10 deletions(-) diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 158f819f8da4..953a793de9a3 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -39,8 +39,6 @@ static struct acp_resource rsrc = { .irqp_used = 1, .soc_mclk = true, .irq_reg_offset = 0x1a00, - .i2s_pin_cfg_offset = 0x1440, - .i2s_mode = 0x0a, .scratch_reg_offset = 0x12800, .sram_pte_offset = 0x03802800, }; diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index b0e181c9a733..db835ed7c208 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -32,8 +32,6 @@ static struct acp_resource rsrc = { .no_of_ctrls = 1, .irqp_used = 0, .irq_reg_offset = 0x1800, - .i2s_pin_cfg_offset = 0x1400, - .i2s_mode = 0x04, .scratch_reg_offset = 0x12800, .sram_pte_offset = 0x02052800, }; diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c index 4d342441a650..f223311b6740 100644 --- a/sound/soc/amd/acp/acp63.c +++ b/sound/soc/amd/acp/acp63.c @@ -55,8 +55,6 @@ static struct acp_resource rsrc = { .irqp_used = 1, .soc_mclk = true, .irq_reg_offset = 0x1a00, - .i2s_pin_cfg_offset = 0x1440, - .i2s_mode = 0x0a, .scratch_reg_offset = 0x12800, .sram_pte_offset = 0x03802800, }; diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c index 0d7cdd4017e5..a2cbdcca4313 100644 --- a/sound/soc/amd/acp/acp70.c +++ b/sound/soc/amd/acp/acp70.c @@ -31,8 +31,6 @@ static struct acp_resource rsrc = { .irqp_used = 1, .soc_mclk = true, .irq_reg_offset = 0x1a00, - .i2s_pin_cfg_offset = 0x1440, - .i2s_mode = 0x0a, .scratch_reg_offset = 0x12800, .sram_pte_offset = 0x03802800, }; diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index d75b4eb34de8..cbf9ca26f3ee 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -162,8 +162,6 @@ struct acp_resource { int irqp_used; bool soc_mclk; u32 irq_reg_offset; - u32 i2s_pin_cfg_offset; - int i2s_mode; u64 scratch_reg_offset; u64 sram_pte_offset; }; From 5b162f60e7e051624e187e45b0fdc481c3573f17 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 17 Jun 2024 12:58:39 +0530 Subject: [PATCH 178/349] ASoC: amd: acp: modify conditional check for programming i2s mclk ACP provides different IO configurations(ACP PDM, I2S and SoundWire). I2S mclk should be programmed only when I2S configuration is selected and I2S controller is programmed as clock master. Modify the conditional check for programming i2s mclk. Signed-off-by: Vijendar Mukunda Link: https://patch.msgid.link/20240617072844.871468-6-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-rembrandt.c | 5 +++-- sound/soc/amd/acp/acp63.c | 5 +++-- sound/soc/amd/acp/amd.h | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 953a793de9a3..e19981c7d65a 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -229,12 +229,13 @@ static int rembrandt_audio_probe(struct platform_device *pdev) adata->rsrc = &rsrc; adata->platform = REMBRANDT; adata->flag = chip->flag; + adata->is_i2s_config = chip->is_i2s_config; adata->machines = snd_soc_acpi_amd_rmb_acp_machines; acp_machine_select(adata); dev_set_drvdata(dev, adata); - if (chip->flag != FLAG_AMD_LEGACY_ONLY_DMIC) { + if (chip->is_i2s_config && rsrc.soc_mclk) { ret = acp6x_master_clock_generate(dev); if (ret) return ret; @@ -267,7 +268,7 @@ static int __maybe_unused rmb_pcm_resume(struct device *dev) snd_pcm_uframes_t buf_in_frames; u64 buf_size; - if (adata->flag != FLAG_AMD_LEGACY_ONLY_DMIC) + if (adata->is_i2s_config && adata->rsrc->soc_mclk) acp6x_master_clock_generate(dev); spin_lock(&adata->acp_lock); diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c index f223311b6740..f340920b3289 100644 --- a/sound/soc/amd/acp/acp63.c +++ b/sound/soc/amd/acp/acp63.c @@ -239,11 +239,12 @@ static int acp63_audio_probe(struct platform_device *pdev) adata->rsrc = &rsrc; adata->platform = ACP63; adata->flag = chip->flag; + adata->is_i2s_config = chip->is_i2s_config; adata->machines = snd_soc_acpi_amd_acp63_acp_machines; acp_machine_select(adata); dev_set_drvdata(dev, adata); - if (chip->flag != FLAG_AMD_LEGACY_ONLY_DMIC) { + if (chip->is_i2s_config && rsrc.soc_mclk) { ret = acp63_i2s_master_clock_generate(adata); if (ret) return ret; @@ -276,7 +277,7 @@ static int __maybe_unused acp63_pcm_resume(struct device *dev) snd_pcm_uframes_t buf_in_frames; u64 buf_size; - if (adata->flag != FLAG_AMD_LEGACY_ONLY_DMIC) + if (adata->is_i2s_config && adata->rsrc->soc_mclk) acp63_i2s_master_clock_generate(adata); spin_lock(&adata->acp_lock); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index cbf9ca26f3ee..87a4813783f9 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -173,6 +173,7 @@ struct acp_dev_data { unsigned int i2s_irq; bool tdm_mode; + bool is_i2s_config; /* SOC specific dais */ struct snd_soc_dai_driver *dai_driver; int num_dai; From d85695b01cbb2455a2f70528bb9e53f2463a39cf Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 17 Jun 2024 12:58:40 +0530 Subject: [PATCH 179/349] ASoC: amd: acp: move i2s clock generation sequence I2S clock generation registers should be programmed before starting the I2S dma when I2S controller is programmed as clock master. Move i2s clock generation register programming sequence prior to i2s dma start. Signed-off-by: Vijendar Mukunda Link: https://patch.msgid.link/20240617072844.871468-7-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 54985fd0eede..97258b4cf89b 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -369,12 +369,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct } writel(period_bytes, adata->acp_base + water_val); writel(buf_size, adata->acp_base + buf_reg); + if (rsrc->soc_mclk) + acp_set_i2s_clk(adata, dai->driver->id); val = readl(adata->acp_base + reg_val); val = val | BIT(0); writel(val, adata->acp_base + reg_val); writel(1, adata->acp_base + ier_val); - if (rsrc->soc_mclk) - acp_set_i2s_clk(adata, dai->driver->id); return 0; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: From 8978e1f7bc26655e0373c4a6b31e17fcdd497329 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 17 Jun 2024 12:58:41 +0530 Subject: [PATCH 180/349] ASoC: amd: acp: add pcm constraints for buffer size and period size ACP common dma driver has a buffer size and period size restriction which should be 64 byte aligned. Add pcm constraints for the same. Signed-off-by: Vijendar Mukunda Link: https://patch.msgid.link/20240617072844.871468-8-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-platform.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index aaac8aa744cb..4f409cd09c11 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -197,6 +197,20 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs else runtime->hw = acp_pcm_hardware_capture; + ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, DMA_SIZE); + if (ret) { + dev_err(component->dev, "set hw constraint HW_PARAM_PERIOD_BYTES failed\n"); + kfree(stream); + return ret; + } + + ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, DMA_SIZE); + if (ret) { + dev_err(component->dev, "set hw constraint HW_PARAM_BUFFER_BYTES failed\n"); + kfree(stream); + return ret; + } + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) { dev_err(component->dev, "set integer constraint failed\n"); From 3722873d49a1788d5420894d4f6f63e35f5c1f13 Mon Sep 17 00:00:00 2001 From: Hao Ge Date: Mon, 17 Jun 2024 10:09:54 +0800 Subject: [PATCH 181/349] ASoc: PCM6240: Return directly after a failed devm_kzalloc() in pcmdevice_i2c_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value “-ENOMEM” was assigned to the local variable “ret” in one if branch after a devm_kzalloc() call failed at the beginning. This error code will trigger then a pcmdevice_remove() call with a passed null pointer so that an undesirable dereference will be performed. Thus return the appropriate error code directly. Fixes: 1324eafd37aa ("ASoc: PCM6240: Create PCM6240 Family driver code") Signed-off-by: Hao Ge Link: https://patch.msgid.link/20240617020954.17252-1-hao.ge@linux.dev Signed-off-by: Mark Brown --- sound/soc/codecs/pcm6240.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index 86e126783a1d..8f7057e689fb 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -2087,10 +2087,8 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c) #endif pcm_dev = devm_kzalloc(&i2c->dev, sizeof(*pcm_dev), GFP_KERNEL); - if (!pcm_dev) { - ret = -ENOMEM; - goto out; - } + if (!pcm_dev) + return -ENOMEM; pcm_dev->chip_id = (id != NULL) ? id->driver_data : 0; From 0e2407ae89b340c385afdca1e1c61dd651ae6b35 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Fri, 21 Jun 2024 10:17:56 -0500 Subject: [PATCH 182/349] ASoC: dt-bindings: cirrus,cs530x: Add initial DT binding Add the YAML DT bindings for the cs530x high performance audio ADCs. Signed-off-by: Paul Handrigan Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240621151757.1661265-2-paulha@opensource.cirrus.com Signed-off-by: Mark Brown --- .../bindings/sound/cirrus,cs530x.yaml | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml new file mode 100644 index 000000000000..9582eb8eb418 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs530x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic cs530x family of audio ADCs + +maintainers: + - Paul Handrigan + - patches@opensource.cirrus.com + +description: + The CS530X devices are a family of high performance audio ADCs. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - cirrus,cs5302 + - cirrus,cs5304 + - cirrus,cs5308 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 1 + + reset-gpios: + maxItems: 1 + + vdd-a-supply: + description: Analog power supply + + vdd-io-supply: + description: Digital IO power supply + + cirrus,in-hiz-pin12: + description: + Sets input channels one and two to high impedance. + type: boolean + + cirrus,in-hiz-pin34: + description: + Sets input channels three and four to high impedance. + type: boolean + + cirrus,in-hiz-pin56: + description: + Sets input channels five and six to high impedance. + type: boolean + + cirrus,in-hiz-pin78: + description: + Sets input channels seven and eight to high impedance. + type: boolean + +required: + - compatible + - reg + - "#sound-dai-cells" + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + cs5304: adc@48 { + compatible = "cirrus,cs5304"; + reg = <0x48>; + #sound-dai-cells = <1>; + reset-gpios = <&gpio 110 GPIO_ACTIVE_LOW>; + vdd-a-supply = <&vreg>; + vdd-io-supply = <&vreg>; + cirrus,in-hiz-pin34; + }; + }; From 2884c29152c098c32e0041061f8327bcdb4e0697 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Fri, 21 Jun 2024 10:17:57 -0500 Subject: [PATCH 183/349] ASoC: cs530x: Support for cs530x ADCs Add support for the cs530x family of high performance ADCs. Signed-off-by: Paul Handrigan Link: https://patch.msgid.link/20240621151757.1661265-3-paulha@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 14 + sound/soc/codecs/Makefile | 4 + sound/soc/codecs/cs530x-i2c.c | 72 +++ sound/soc/codecs/cs530x.c | 966 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs530x.h | 223 ++++++++ 5 files changed, 1279 insertions(+) create mode 100644 sound/soc/codecs/cs530x-i2c.c create mode 100644 sound/soc/codecs/cs530x.c create mode 100644 sound/soc/codecs/cs530x.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a99cb26eb280..1f539c4b9432 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -99,6 +99,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS47L90 imply SND_SOC_CS47L92 imply SND_SOC_CS53L30 + imply SND_SOC_CS530X_I2C imply SND_SOC_CX20442 imply SND_SOC_CX2072X imply SND_SOC_DA7210 @@ -1000,6 +1001,19 @@ config SND_SOC_CS53L30 tristate "Cirrus Logic CS53L30 CODEC" depends on I2C +config SND_SOC_CS530X + tristate + +config SND_SOC_CS530X_I2C + tristate "Cirrus Logic CS530x ADCs (I2C)" + depends on I2C + select REGMAP + select REGMAP_I2C + select SND_SOC_CS530X + help + Enable support for Cirrus Logic CS530X ADCs + with I2C control. + config SND_SOC_CX20442 tristate depends on TTY diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index ad0f77224c74..c2c0d02b5484 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -107,6 +107,8 @@ snd-soc-cs47l85-y := cs47l85.o snd-soc-cs47l90-y := cs47l90.o snd-soc-cs47l92-y := cs47l92.o snd-soc-cs53l30-y := cs53l30.o +snd-soc-cs530x-y := cs530x.o +snd-soc-cs530x-i2c-y := cs530x-i2c.o snd-soc-cx20442-y := cx20442.o snd-soc-cx2072x-y := cx2072x.o snd-soc-da7210-y := da7210.o @@ -509,6 +511,8 @@ obj-$(CONFIG_SND_SOC_CS47L85) += snd-soc-cs47l85.o obj-$(CONFIG_SND_SOC_CS47L90) += snd-soc-cs47l90.o obj-$(CONFIG_SND_SOC_CS47L92) += snd-soc-cs47l92.o obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o +obj-$(CONFIG_SND_SOC_CS530X) += snd-soc-cs530x.o +obj-$(CONFIG_SND_SOC_CS530X_I2C) += snd-soc-cs530x-i2c.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_CX2072X) += snd-soc-cx2072x.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c new file mode 100644 index 000000000000..56659bf735db --- /dev/null +++ b/sound/soc/codecs/cs530x-i2c.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS530x CODEC driver +// +// Copyright (C) 2024 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include + +#include "cs530x.h" + +static const struct of_device_id cs530x_of_match[] = { + { + .compatible = "cirrus,cs5302", + .data = (void *)CS5302, + }, { + .compatible = "cirrus,cs5304", + .data = (void *)CS5304, + }, { + .compatible = "cirrus,cs5308", + .data = (void *)CS5308, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cs530x_of_match); + +static const struct i2c_device_id cs530x_i2c_id[] = { + { "cs5302", CS5302 }, + { "cs5304", CS5304 }, + { "cs5308", CS5308 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs530x_i2c_id); + +static int cs530x_i2c_probe(struct i2c_client *client) +{ + struct cs530x_priv *cs530x; + + cs530x = devm_kzalloc(&client->dev, sizeof(*cs530x), GFP_KERNEL); + if (!cs530x) + return -ENOMEM; + + i2c_set_clientdata(client, cs530x); + + cs530x->regmap = devm_regmap_init_i2c(client, &cs530x_regmap); + if (IS_ERR(cs530x->regmap)) + return dev_err_probe(&client->dev, PTR_ERR(cs530x->regmap), + "Failed to allocate register map\n"); + + cs530x->devtype = (uintptr_t)i2c_get_match_data(client); + cs530x->dev = &client->dev; + + return cs530x_probe(cs530x); +} + +static struct i2c_driver cs530x_i2c_driver = { + .driver = { + .name = "cs530x", + .of_match_table = cs530x_of_match, + }, + .probe = cs530x_i2c_probe, + .id_table = cs530x_i2c_id, +}; +module_i2c_driver(cs530x_i2c_driver); + +MODULE_DESCRIPTION("I2C CS530X driver"); +MODULE_IMPORT_NS(SND_SOC_CS530X); +MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c new file mode 100644 index 000000000000..036d0f45e3ba --- /dev/null +++ b/sound/soc/codecs/cs530x.c @@ -0,0 +1,966 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS530x CODEC driver +// +// Copyright (C) 2024 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs530x.h" + +#define CS530X_MAX_ADC_CH 8 +#define CS530X_MIN_ADC_CH 2 + +static const char *cs530x_supply_names[CS530X_NUM_SUPPLIES] = { + "vdd-a", + "vdd-io", +}; + +static const struct reg_default cs530x_reg_defaults[] = { + { CS530X_CLK_CFG_0, 0x30 }, + { CS530X_CLK_CFG_1, 0x0001 }, + { CS530X_CHIP_ENABLE, 0 }, + { CS530X_ASP_CFG, 0 }, + { CS530X_SIGNAL_PATH_CFG, 0 }, + { CS530X_IN_ENABLES, 0 }, + { CS530X_IN_RAMP_SUM, 0x0022 }, + { CS530X_IN_FILTER, 0 }, + { CS530X_IN_HIZ, 0 }, + { CS530X_IN_INV, 0 }, + { CS530X_IN_VOL_CTRL1_0, 0x8000 }, + { CS530X_IN_VOL_CTRL1_1, 0x8000 }, + { CS530X_IN_VOL_CTRL2_0, 0x8000 }, + { CS530X_IN_VOL_CTRL2_1, 0x8000 }, + { CS530X_IN_VOL_CTRL3_0, 0x8000 }, + { CS530X_IN_VOL_CTRL3_1, 0x8000 }, + { CS530X_IN_VOL_CTRL4_0, 0x8000 }, + { CS530X_IN_VOL_CTRL4_1, 0x8000 }, + { CS530X_PAD_FN, 0 }, + { CS530X_PAD_LVL, 0 }, +}; + +static bool cs530x_read_and_write_regs(unsigned int reg) +{ + switch (reg) { + case CS530X_CLK_CFG_0: + case CS530X_CLK_CFG_1: + case CS530X_CHIP_ENABLE: + case CS530X_ASP_CFG: + case CS530X_SIGNAL_PATH_CFG: + case CS530X_IN_ENABLES: + case CS530X_IN_RAMP_SUM: + case CS530X_IN_FILTER: + case CS530X_IN_HIZ: + case CS530X_IN_INV: + case CS530X_IN_VOL_CTRL1_0: + case CS530X_IN_VOL_CTRL1_1: + case CS530X_IN_VOL_CTRL2_0: + case CS530X_IN_VOL_CTRL2_1: + case CS530X_IN_VOL_CTRL3_0: + case CS530X_IN_VOL_CTRL3_1: + case CS530X_IN_VOL_CTRL4_0: + case CS530X_IN_VOL_CTRL4_1: + case CS530X_PAD_FN: + case CS530X_PAD_LVL: + return true; + default: + return false; + } +} + +static bool cs530x_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS530X_DEVID: + case CS530X_REVID: + return true; + default: + return cs530x_read_and_write_regs(reg); + } +} + +static bool cs530x_writeable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS530X_SW_RESET: + case CS530X_IN_VOL_CTRL5: + return true; + default: + return cs530x_read_and_write_regs(reg); + } +} + +static int cs530x_put_volsw_vu(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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + int ret; + + snd_soc_dapm_mutex_lock(dapm); + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + if (ret) + goto volsw_err; + + /* Write IN_VU bit for the volume change to take effect */ + regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_IN_VU); + +volsw_err: + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1270, 50, 0); + +static const char * const cs530x_in_hpf_text[] = { + "Min Phase Slow Roll-off", + "Min Phase Fast Roll-off", + "Linear Phase Slow Roll-off", + "Linear Phase Fast Roll-off", +}; + +static SOC_ENUM_SINGLE_DECL(cs530x_in_hpf_enum, CS530X_IN_FILTER, + CS530X_IN_FILTER_SHIFT, + cs530x_in_hpf_text); + +static const char * const cs530x_in_4ch_sum_text[] = { + "None", + "Groups of 2", + "Groups of 4", +}; + +static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch4_enum, CS530X_IN_RAMP_SUM, + CS530X_IN_SUM_MODE_SHIFT, + cs530x_in_4ch_sum_text); + +static const struct snd_kcontrol_new cs530x_in_sum_4ch_controls[] = { +SOC_ENUM("IN Sum Select", cs530x_in_sum_ch4_enum), +}; + +static const char * const cs530x_in_8ch_sum_text[] = { + "None", + "Groups of 2", + "Groups of 4", + "Groups of 8", +}; + +static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch8_enum, CS530X_IN_RAMP_SUM, + CS530X_IN_SUM_MODE_SHIFT, + cs530x_in_8ch_sum_text); + +static const struct snd_kcontrol_new cs530x_in_sum_8ch_controls[] = { +SOC_ENUM("IN Sum Select", cs530x_in_sum_ch8_enum), +}; + + +static const char * const cs530x_vol_ramp_text[] = { + "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", + "15ms/6dB", "30ms/6dB", +}; + +static SOC_ENUM_SINGLE_DECL(cs530x_ramp_inc_enum, CS530X_IN_RAMP_SUM, + CS530X_RAMP_RATE_INC_SHIFT, + cs530x_vol_ramp_text); + +static SOC_ENUM_SINGLE_DECL(cs530x_ramp_dec_enum, CS530X_IN_RAMP_SUM, + CS530X_RAMP_RATE_DEC_SHIFT, + cs530x_vol_ramp_text); + +static const struct snd_kcontrol_new cs530x_in_1_to_2_controls[] = { +SOC_SINGLE_EXT_TLV("IN1 Volume", CS530X_IN_VOL_CTRL1_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("IN2 Volume", CS530X_IN_VOL_CTRL1_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), + +SOC_ENUM("IN HPF Select", cs530x_in_hpf_enum), +SOC_ENUM("Input Ramp Up", cs530x_ramp_inc_enum), +SOC_ENUM("Input Ramp Down", cs530x_ramp_dec_enum), + +SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_IN1_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_IN2_INV_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new cs530x_in_3_to_4_controls[] = { +SOC_SINGLE_EXT_TLV("IN3 Volume", CS530X_IN_VOL_CTRL2_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("IN4 Volume", CS530X_IN_VOL_CTRL2_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), + +SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_IN3_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_IN4_INV_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new cs530x_in_5_to_8_controls[] = { +SOC_SINGLE_EXT_TLV("IN5 Volume", CS530X_IN_VOL_CTRL3_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("IN6 Volume", CS530X_IN_VOL_CTRL3_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("IN7 Volume", CS530X_IN_VOL_CTRL4_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("IN8 Volume", CS530X_IN_VOL_CTRL4_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), + +SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_IN5_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_IN6_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_IN7_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_IN8_INV_SHIFT, 1, 0), +}; + +static int cs530x_adc_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + cs530x->adc_pairs_count++; + break; + case SND_SOC_DAPM_POST_PMU: + regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + + (w->shift * 2), CS530X_IN_MUTE); + regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + + ((w->shift+1) * 2), CS530X_IN_MUTE); + + cs530x->adc_pairs_count--; + if (!cs530x->adc_pairs_count) { + usleep_range(1000, 1100); + return regmap_write(regmap, CS530X_IN_VOL_CTRL5, + CS530X_IN_VU); + } + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + + (w->shift * 2), CS530X_IN_MUTE); + regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + + ((w->shift+1) * 2), CS530X_IN_MUTE); + return regmap_write(regmap, CS530X_IN_VOL_CTRL5, + CS530X_IN_VU); + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_kcontrol_new adc12_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +static const struct snd_kcontrol_new adc34_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +static const struct snd_kcontrol_new adc56_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +static const struct snd_kcontrol_new adc78_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +static const struct snd_kcontrol_new in_hpf_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +/* General DAPM widgets for all devices */ +static const struct snd_soc_dapm_widget cs530x_gen_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("Global Enable", CS530X_CHIP_ENABLE, 0, 0, NULL, 0), +}; + +/* ADC's Channels 1 and 2 plus generic ADC DAPM events */ +static const struct snd_soc_dapm_widget cs530x_adc_ch12_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN1"), +SND_SOC_DAPM_INPUT("IN2"), +SND_SOC_DAPM_ADC_E("ADC1", NULL, CS530X_IN_ENABLES, 0, 0, + cs530x_adc_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_ADC("ADC2", NULL, CS530X_IN_ENABLES, 1, 0), +SND_SOC_DAPM_SWITCH("ADC12 Enable", SND_SOC_NOPM, 0, 0, &adc12_ctrl), +SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_IN_HPF_EN_SHIFT, + 0, &in_hpf_ctrl), +}; + +/* ADC's Channels 3 and 4 */ +static const struct snd_soc_dapm_widget cs530x_adc_ch34_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN3"), +SND_SOC_DAPM_INPUT("IN4"), +SND_SOC_DAPM_ADC_E("ADC3", NULL, CS530X_IN_ENABLES, 2, 0, + cs530x_adc_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_ADC("ADC4", NULL, CS530X_IN_ENABLES, 3, 0), +SND_SOC_DAPM_SWITCH("ADC34 Enable", SND_SOC_NOPM, 0, 0, &adc34_ctrl), +}; + +/* ADC's Channels 5 to 8 */ +static const struct snd_soc_dapm_widget cs530x_adc_ch58_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN5"), +SND_SOC_DAPM_INPUT("IN6"), +SND_SOC_DAPM_INPUT("IN7"), +SND_SOC_DAPM_INPUT("IN8"), +SND_SOC_DAPM_ADC_E("ADC5", NULL, CS530X_IN_ENABLES, 4, 0, + cs530x_adc_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_ADC("ADC6", NULL, CS530X_IN_ENABLES, 5, 0), +SND_SOC_DAPM_SWITCH("ADC56 Enable", SND_SOC_NOPM, 0, 0, &adc56_ctrl), +SND_SOC_DAPM_ADC_E("ADC7", NULL, CS530X_IN_ENABLES, 6, 0, + cs530x_adc_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_ADC("ADC8", NULL, CS530X_IN_ENABLES, 7, 0), +SND_SOC_DAPM_SWITCH("ADC78 Enable", SND_SOC_NOPM, 0, 0, &adc78_ctrl), +}; + +static const struct snd_soc_dapm_route adc_ch1_2_routes[] = { + { "ADC1", NULL, "Global Enable" }, + { "ADC2", NULL, "Global Enable" }, + + { "ADC12 Enable", "Switch", "IN1" }, + { "ADC12 Enable", "Switch", "IN2" }, + { "ADC1", NULL, "ADC12 Enable" }, + { "ADC2", NULL, "ADC12 Enable" }, + { "IN HPF", "Switch", "ADC1" }, + { "IN HPF", "Switch", "ADC2" }, + + { "AIF Capture", NULL, "IN HPF" }, + { "AIF Capture", NULL, "ADC1" }, + { "AIF Capture", NULL, "ADC2" }, +}; + +static const struct snd_soc_dapm_route adc_ch3_4_routes[] = { + { "ADC3", NULL, "Global Enable" }, + { "ADC4", NULL, "Global Enable" }, + + { "ADC34 Enable", "Switch", "IN3" }, + { "ADC34 Enable", "Switch", "IN4" }, + { "ADC3", NULL, "ADC34 Enable" }, + { "ADC4", NULL, "ADC34 Enable" }, + { "IN HPF", "Switch", "ADC3" }, + { "IN HPF", "Switch", "ADC4" }, + + { "AIF Capture", NULL, "ADC3" }, + { "AIF Capture", NULL, "ADC4" }, +}; + +static const struct snd_soc_dapm_route adc_ch5_8_routes[] = { + { "ADC5", NULL, "Global Enable" }, + { "ADC6", NULL, "Global Enable" }, + { "ADC7", NULL, "Global Enable" }, + { "ADC8", NULL, "Global Enable" }, + + { "ADC56 Enable", "Switch", "IN5" }, + { "ADC56 Enable", "Switch", "IN6" }, + { "ADC5", NULL, "ADC56 Enable" }, + { "ADC6", NULL, "ADC56 Enable" }, + { "IN HPF", "Switch", "ADC5" }, + { "IN HPF", "Switch", "ADC6" }, + + { "AIF Capture", NULL, "ADC5" }, + { "AIF Capture", NULL, "ADC6" }, + + { "ADC78 Enable", "Switch", "IN7" }, + { "ADC78 Enable", "Switch", "IN8" }, + { "ADC7", NULL, "ADC78 Enable" }, + { "ADC8", NULL, "ADC78 Enable" }, + { "IN HPF", "Switch", "ADC7" }, + { "IN HPF", "Switch", "ADC8" }, + + { "AIF Capture", NULL, "ADC7" }, + { "AIF Capture", NULL, "ADC8" }, +}; + +static void cs530x_add_12_adc_widgets(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_add_component_controls(component, + cs530x_in_1_to_2_controls, + ARRAY_SIZE(cs530x_in_1_to_2_controls)); + + snd_soc_dapm_new_controls(dapm, cs530x_adc_ch12_dapm_widgets, + ARRAY_SIZE(cs530x_adc_ch12_dapm_widgets)); + + snd_soc_dapm_add_routes(dapm, adc_ch1_2_routes, + ARRAY_SIZE(adc_ch1_2_routes)); +} + +static void cs530x_add_34_adc_widgets(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_add_component_controls(component, + cs530x_in_3_to_4_controls, + ARRAY_SIZE(cs530x_in_3_to_4_controls)); + + snd_soc_dapm_new_controls(dapm, cs530x_adc_ch34_dapm_widgets, + ARRAY_SIZE(cs530x_adc_ch34_dapm_widgets)); + + snd_soc_dapm_add_routes(dapm, adc_ch3_4_routes, + ARRAY_SIZE(adc_ch3_4_routes)); +} + +static int cs530x_set_bclk(struct snd_soc_component *component) +{ + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + unsigned int bclk_val; + + switch (cs530x->bclk) { + case 2822400: + case 3072000: + bclk_val = CS530X_BCLK_2P822_3P072; + break; + case 5644800: + case 6144000: + bclk_val = CS530X_BCLK_5P6448_6P144; + break; + case 11289600: + case 12288000: + bclk_val = CS530X_BCLK_11P2896_12P288; + break; + case 22579200: + case 24576000: + bclk_val = CS530X_BCLK_24P5792_24P576; + break; + default: + dev_err(component->dev, "Invalid BCLK %d\n", cs530x->bclk); + return -EINVAL; + } + + dev_dbg(component->dev, "BCLK is %d\n", cs530x->bclk); + + return regmap_update_bits(regmap, CS530X_ASP_CFG, + CS530X_ASP_BCLK_FREQ_MASK, bclk_val); +} + +static int cs530x_set_pll_refclk(struct snd_soc_component *component, + const unsigned int freq) +{ + struct cs530x_priv *priv = snd_soc_component_get_drvdata(component); + struct regmap *regmap = priv->regmap; + unsigned int refclk; + + switch (freq) { + case 2822400: + case 3072000: + refclk = CS530X_REFCLK_2P822_3P072; + break; + case 5644800: + case 6144000: + refclk = CS530X_REFCLK_5P6448_6P144; + break; + case 11289600: + case 12288000: + refclk = CS530X_REFCLK_11P2896_12P288; + break; + case 22579200: + case 24576000: + refclk = CS530X_REFCLK_24P5792_24P576; + break; + default: + dev_err(component->dev, "Invalid PLL refclk %d\n", freq); + return -EINVAL; + } + + return regmap_update_bits(regmap, CS530X_CLK_CFG_0, + CS530X_PLL_REFCLK_FREQ_MASK, refclk); +} + +static int cs530x_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + int ret = 0, fs = params_rate(params); + unsigned int fs_val; + + + switch (fs) { + case 32000: + fs_val = CS530X_FS_32K; + break; + case 44100: + case 48000: + fs_val = CS530X_FS_48K_44P1K; + break; + case 88200: + case 96000: + fs_val = CS530X_FS_96K_88P2K; + break; + case 176400: + case 192000: + fs_val = CS530X_FS_192K_176P4K; + break; + case 356800: + case 384000: + fs_val = CS530X_FS_384K_356P8K; + break; + case 705600: + case 768000: + fs_val = CS530X_FS_768K_705P6K; + break; + default: + dev_err(component->dev, "Invalid sample rate %d\n", fs); + return -EINVAL; + } + + cs530x->fs = fs; + regmap_update_bits(regmap, CS530X_CLK_CFG_1, + CS530X_SAMPLE_RATE_MASK, fs_val); + + if (cs530x->tdm_slots) { + dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n", + cs530x->tdm_slots, cs530x->tdm_width); + cs530x->bclk = snd_soc_calc_bclk(cs530x->fs, + cs530x->tdm_width, + params_channels(params), + cs530x->tdm_slots); + } else { + cs530x->bclk = snd_soc_params_to_bclk(params); + } + + if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0, + CS530X_PLL_REFCLK_SRC_MASK)) { + ret = cs530x_set_pll_refclk(component, cs530x->bclk); + if (ret) + return ret; + } + + return cs530x_set_bclk(component); +} + +static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct cs530x_priv *priv = snd_soc_component_get_drvdata(component); + struct regmap *regmap = priv->regmap; + unsigned int asp_fmt, asp_cfg = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + case SND_SOC_DAIFMT_CBM_CFM: + asp_cfg = CS530X_ASP_PRIMARY; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + asp_fmt = CS530X_ASP_FMT_DSP_A; + break; + case SND_SOC_DAIFMT_I2S: + asp_fmt = CS530X_ASP_FMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + asp_fmt = CS530X_ASP_FMT_LJ; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + asp_cfg |= CS530X_ASP_BCLK_INV; + break; + default: + return -EINVAL; + } + + regmap_update_bits(regmap, CS530X_ASP_CFG, + CS530X_ASP_PRIMARY | CS530X_ASP_BCLK_INV, + asp_cfg); + + return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG, + CS530X_ASP_FMT_MASK, asp_fmt); +} + +static bool cs530x_check_mclk_freq(struct snd_soc_component *component, + const unsigned int freq) +{ + switch (freq) { + case 24576000: + case 22579200: + case 12288000: + case 11289600: + return true; + default: + dev_err(component->dev, "Invalid MCLK %d\n", freq); + return false; + } +} + +static int cs530x_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + unsigned int val; + + switch (tx_mask) { + case CS530X_0_1_TDM_SLOT_MASK: + case CS530X_0_3_TDM_SLOT_MASK: + case CS530X_0_7_TDM_SLOT_MASK: + val = CS530X_0_7_TDM_SLOT_VAL; + break; + case CS530X_2_3_TDM_SLOT_MASK: + val = CS530X_2_3_TDM_SLOT_VAL; + break; + case CS530X_4_5_TDM_SLOT_MASK: + case CS530X_4_7_TDM_SLOT_MASK: + val = CS530X_4_7_TDM_SLOT_VAL; + break; + case CS530X_6_7_TDM_SLOT_MASK: + val = CS530X_6_7_TDM_SLOT_VAL; + break; + case CS530X_8_9_TDM_SLOT_MASK: + case CS530X_8_11_TDM_SLOT_MASK: + case CS530X_8_15_TDM_SLOT_MASK: + val = CS530X_8_15_TDM_SLOT_VAL; + break; + case CS530X_10_11_TDM_SLOT_MASK: + val = CS530X_10_11_TDM_SLOT_VAL; + break; + case CS530X_12_13_TDM_SLOT_MASK: + case CS530X_12_15_TDM_SLOT_MASK: + val = CS530X_12_15_TDM_SLOT_VAL; + break; + case CS530X_14_15_TDM_SLOT_MASK: + val = CS530X_14_15_TDM_SLOT_VAL; + break; + default: + dev_err(component->dev, "Invalid TX slot(s) 0x%x\n", tx_mask); + return -EINVAL; + } + + return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG, + CS530X_ASP_TDM_SLOT_MASK, + val << CS530X_ASP_TDM_SLOT_SHIFT); +} + +static const struct snd_soc_dai_ops cs530x_dai_ops = { + .set_fmt = cs530x_set_fmt, + .hw_params = cs530x_hw_params, + .set_tdm_slot = cs530x_set_tdm_slot, +}; + +static const struct snd_soc_dai_driver cs530x_dai = { + .name = "cs530x-dai", + .capture = { + .stream_name = "AIF Capture", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &cs530x_dai_ops, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, +}; + +static int cs530x_set_pll(struct snd_soc_component *component, int pll_id, + int source, unsigned int freq_in, + unsigned int freq_out) +{ + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + unsigned int sysclk_src; + int ret; + + regmap_read(regmap, CS530X_CLK_CFG_0, &sysclk_src); + + /* Check if the source is the PLL */ + if ((sysclk_src & CS530X_SYSCLK_SRC_MASK) == 0) + return 0; + + switch (source) { + case CS530X_PLL_SRC_MCLK: + if (!cs530x_check_mclk_freq(component, freq_in)) + return -EINVAL; + + ret = cs530x_set_pll_refclk(component, freq_in); + if (ret) + return ret; + + break; + case CS530X_PLL_SRC_BCLK: + break; + default: + dev_err(component->dev, "Invalid PLL source %d\n", source); + return -EINVAL; + } + + return regmap_update_bits(regmap, CS530X_CLK_CFG_0, + CS530X_PLL_REFCLK_SRC_MASK, source); +} + +static int cs530x_component_probe(struct snd_soc_component *component) +{ + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int num_widgets; + + snd_soc_dapm_new_controls(dapm, cs530x_gen_dapm_widgets, + ARRAY_SIZE(cs530x_gen_dapm_widgets)); + + switch (cs530x->devtype) { + case CS5302: + cs530x_add_12_adc_widgets(component); + break; + case CS5304: + cs530x_add_12_adc_widgets(component); + cs530x_add_34_adc_widgets(component); + + num_widgets = ARRAY_SIZE(cs530x_in_sum_4ch_controls); + snd_soc_add_component_controls(component, + cs530x_in_sum_4ch_controls, + num_widgets); + break; + + case CS5308: + cs530x_add_12_adc_widgets(component); + cs530x_add_34_adc_widgets(component); + + num_widgets = ARRAY_SIZE(cs530x_in_5_to_8_controls); + snd_soc_add_component_controls(component, + cs530x_in_5_to_8_controls, + num_widgets); + + num_widgets = ARRAY_SIZE(cs530x_in_sum_8ch_controls); + snd_soc_add_component_controls(component, + cs530x_in_sum_8ch_controls, + num_widgets); + + num_widgets = ARRAY_SIZE(cs530x_adc_ch58_dapm_widgets); + snd_soc_dapm_new_controls(dapm, cs530x_adc_ch58_dapm_widgets, + num_widgets); + + snd_soc_dapm_add_routes(dapm, adc_ch5_8_routes, + ARRAY_SIZE(adc_ch5_8_routes)); + break; + default: + dev_err(component->dev, "Invalid device type %d\n", + cs530x->devtype); + return -EINVAL; + } + + return 0; +} + +static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id, + int source, unsigned int freq, int dir) +{ + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + + switch (source) { + case CS530X_SYSCLK_SRC_MCLK: + if (freq != 24560000 && freq != 22572000) { + dev_err(component->dev, "Invalid MCLK source rate %d\n", + freq); + return -EINVAL; + } + + cs530x->mclk_rate = freq; + break; + case CS530X_SYSCLK_SRC_PLL: + break; + default: + dev_err(component->dev, "Invalid clock id %d\n", clk_id); + return -EINVAL; + } + + return regmap_update_bits(regmap, CS530X_CLK_CFG_0, + CS530X_SYSCLK_SRC_MASK, + source << CS530X_SYSCLK_SRC_SHIFT); +} + +static const struct snd_soc_component_driver soc_component_dev_cs530x = { + .probe = cs530x_component_probe, + .set_sysclk = cs530x_set_sysclk, + .set_pll = cs530x_set_pll, + .endianness = 1, +}; + +const struct regmap_config cs530x_regmap = { + .reg_bits = 16, + .val_bits = 16, + + .max_register = CS530X_MAX_REGISTER, + .readable_reg = cs530x_readable_register, + .writeable_reg = cs530x_writeable_register, + + .cache_type = REGCACHE_MAPLE, + .reg_defaults = cs530x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults), +}; +EXPORT_SYMBOL_NS_GPL(cs530x_regmap, SND_SOC_CS530X); + +static int cs530x_check_device_id(struct cs530x_priv *cs530x) +{ + struct device *dev = cs530x->dev; + unsigned int dev_id, rev; + int ret; + + ret = regmap_read(cs530x->regmap, CS530X_DEVID, &dev_id); + if (ret) + return dev_err_probe(dev, ret, "Can't read device ID\n"); + + ret = regmap_read(cs530x->regmap, CS530X_REVID, &rev); + if (ret) + return dev_err_probe(dev, ret, "Can't read REV ID\n"); + + dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x\n", dev_id, rev); + + switch (dev_id) { + case CS530X_2CH_ADC_DEV_ID: + cs530x->num_adcs = 2; + break; + case CS530X_4CH_ADC_DEV_ID: + cs530x->num_adcs = 4; + break; + case CS530X_8CH_ADC_DEV_ID: + cs530x->num_adcs = 8; + break; + default: + return dev_err_probe(dev, -EINVAL, "Invalid device ID 0x%x\n", + dev_id); + } + + return 0; +} + +static int cs530x_parse_device_properties(struct cs530x_priv *cs530x) +{ + struct regmap *regmap = cs530x->regmap; + struct device *dev = cs530x->dev; + unsigned int val = 0; + + switch (cs530x->num_adcs) { + case 8: + if (device_property_read_bool(dev, "cirrus,in-hiz-pin78")) + val = CS530X_IN78_HIZ; + + if (device_property_read_bool(dev, "cirrus,in-hiz-pin56")) + val |= CS530X_IN56_HIZ; + + fallthrough; + case 4: + if (device_property_read_bool(dev, "cirrus,in-hiz-pin34")) + val |= CS530X_IN34_HIZ; + + fallthrough; + case 2: + if (device_property_read_bool(dev, "cirrus,in-hiz-pin12")) + val |= CS530X_IN12_HIZ; + + return regmap_set_bits(regmap, CS530X_IN_HIZ, val); + default: + return dev_err_probe(dev, -EINVAL, + "Invalid number of adcs %d\n", + cs530x->num_adcs); + } +} + +int cs530x_probe(struct cs530x_priv *cs530x) +{ + struct device *dev = cs530x->dev; + int ret, i; + + cs530x->dev_dai = devm_kmemdup(dev, &cs530x_dai, + sizeof(*(cs530x->dev_dai)), + GFP_KERNEL); + if (!cs530x->dev_dai) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(cs530x->supplies); i++) + cs530x->supplies[i].supply = cs530x_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs530x->supplies), + cs530x->supplies); + if (ret != 0) + return dev_err_probe(dev, ret, "Failed to request supplies"); + + ret = regulator_bulk_enable(ARRAY_SIZE(cs530x->supplies), + cs530x->supplies); + if (ret != 0) + return dev_err_probe(dev, ret, "Failed to enable supplies"); + + cs530x->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(cs530x->reset_gpio)) { + ret = dev_err_probe(dev, PTR_ERR(cs530x->reset_gpio), + "Reset gpio not available\n"); + goto err_regulator; + } + + if (cs530x->reset_gpio) { + usleep_range(2000, 2100); + gpiod_set_value_cansleep(cs530x->reset_gpio, 0); + } + + usleep_range(5000, 5100); + ret = cs530x_check_device_id(cs530x); + if (ret) + goto err_reset; + + if (!cs530x->reset_gpio) { + ret = regmap_write(cs530x->regmap, CS530X_SW_RESET, + CS530X_SW_RST_VAL); + if (ret) { + dev_err_probe(dev, ret, "Soft Reset Failed\n"); + goto err_reset; + } + } + + ret = cs530x_parse_device_properties(cs530x); + if (ret) + goto err_reset; + + cs530x->dev_dai->capture.channels_max = cs530x->num_adcs; + + ret = devm_snd_soc_register_component(dev, + &soc_component_dev_cs530x, cs530x->dev_dai, 1); + if (ret) { + dev_err_probe(dev, ret, "Can't register cs530x component\n"); + goto err_reset; + } + + return 0; + +err_reset: + gpiod_set_value_cansleep(cs530x->reset_gpio, 1); + +err_regulator: + regulator_bulk_disable(ARRAY_SIZE(cs530x->supplies), + cs530x->supplies); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs530x_probe, SND_SOC_CS530X); + +MODULE_DESCRIPTION("CS530X CODEC Driver"); +MODULE_AUTHOR("Paul Handrigan "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h new file mode 100644 index 000000000000..1c85310a5d03 --- /dev/null +++ b/sound/soc/codecs/cs530x.h @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * CS530x CODEC driver internal data + * + * Copyright (C) 2023-2024 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#ifndef _CS530X_H +#define _CS530X_H + +#include +#include +#include +#include + +/* Devices */ +#define CS530X_2CH_ADC_DEV_ID 0x5302 +#define CS530X_4CH_ADC_DEV_ID 0x5304 +#define CS530X_8CH_ADC_DEV_ID 0x5308 + +/* Registers */ + +#define CS530X_DEVID 0x0000000 +#define CS530X_REVID 0x0000004 +#define CS530X_SW_RESET 0x0000022 + +#define CS530X_CLK_CFG_0 0x0000040 +#define CS530X_CLK_CFG_1 0x0000042 +#define CS530X_CHIP_ENABLE 0x0000044 +#define CS530X_ASP_CFG 0x0000048 +#define CS530X_SIGNAL_PATH_CFG 0x0000050 +#define CS530X_IN_ENABLES 0x0000080 +#define CS530X_IN_RAMP_SUM 0x0000082 +#define CS530X_IN_FILTER 0x0000086 +#define CS530X_IN_HIZ 0x0000088 +#define CS530X_IN_INV 0x000008A +#define CS530X_IN_VOL_CTRL1_0 0x0000090 +#define CS530X_IN_VOL_CTRL1_1 0x0000092 +#define CS530X_IN_VOL_CTRL2_0 0x0000094 +#define CS530X_IN_VOL_CTRL2_1 0x0000096 +#define CS530X_IN_VOL_CTRL3_0 0x0000098 +#define CS530X_IN_VOL_CTRL3_1 0x000009A +#define CS530X_IN_VOL_CTRL4_0 0x000009C +#define CS530X_IN_VOL_CTRL4_1 0x000009E +#define CS530X_IN_VOL_CTRL5 0x00000A0 + +#define CS530X_PAD_FN 0x0003D24 +#define CS530X_PAD_LVL 0x0003D28 + +#define CS530X_MAX_REGISTER CS530X_PAD_LVL + +/* Register Fields */ + +/* REVID */ +#define CS530X_MTLREVID GENMASK(3, 0) +#define CS530X_AREVID GENMASK(7, 4) + +/* SW_RESET */ +#define CS530X_SW_RST_SHIFT 8 +#define CS530X_SW_RST_VAL (0x5A << CS530X_SW_RST_SHIFT) + +/* CLK_CFG_0 */ +#define CS530X_PLL_REFCLK_SRC_MASK BIT(0) +#define CS530X_PLL_REFCLK_FREQ_MASK GENMASK(5, 4) +#define CS530X_SYSCLK_SRC_MASK BIT(12) +#define CS530X_SYSCLK_SRC_SHIFT 12 +#define CS530X_REFCLK_2P822_3P072 0 +#define CS530X_REFCLK_5P6448_6P144 0x10 +#define CS530X_REFCLK_11P2896_12P288 0x20 +#define CS530X_REFCLK_24P5792_24P576 0x30 + +/* CLK_CFG_1 */ +#define CS530X_SAMPLE_RATE_MASK GENMASK(2, 0) +#define CS530X_FS_32K 0 +#define CS530X_FS_48K_44P1K 1 +#define CS530X_FS_96K_88P2K 2 +#define CS530X_FS_192K_176P4K 3 +#define CS530X_FS_384K_356P8K 4 +#define CS530X_FS_768K_705P6K 5 + +/* CHIP_ENABLE */ +#define CS530X_GLOBAL_EN BIT(0) + +/* ASP_CFG */ +#define CS530X_ASP_BCLK_FREQ_MASK GENMASK(1, 0) +#define CS530X_ASP_PRIMARY BIT(5) +#define CS530X_ASP_BCLK_INV BIT(6) +#define CS530X_BCLK_2P822_3P072 0 +#define CS530X_BCLK_5P6448_6P144 1 +#define CS530X_BCLK_11P2896_12P288 2 +#define CS530X_BCLK_24P5792_24P576 3 + +/* SIGNAL_PATH_CFG */ +#define CS530X_ASP_FMT_MASK GENMASK(2, 0) +#define CS530X_ASP_TDM_SLOT_MASK GENMASK(5, 3) +#define CS530X_ASP_TDM_SLOT_SHIFT 3 +#define CS530X_ASP_CH_REVERSE BIT(9) +#define CS530X_ASP_FMT_I2S 0 +#define CS530X_ASP_FMT_LJ 1 +#define CS530X_ASP_FMT_DSP_A 0x6 + +/* TDM Slots */ +#define CS530X_0_1_TDM_SLOT_MASK GENMASK(1, 0) +#define CS530X_0_3_TDM_SLOT_MASK GENMASK(3, 0) +#define CS530X_0_7_TDM_SLOT_MASK GENMASK(7, 0) +#define CS530X_0_7_TDM_SLOT_VAL 0 + +#define CS530X_2_3_TDM_SLOT_MASK GENMASK(3, 2) +#define CS530X_2_3_TDM_SLOT_VAL 1 + +#define CS530X_4_5_TDM_SLOT_MASK GENMASK(5, 4) +#define CS530X_4_7_TDM_SLOT_MASK GENMASK(7, 4) +#define CS530X_4_7_TDM_SLOT_VAL 2 + +#define CS530X_6_7_TDM_SLOT_MASK GENMASK(7, 6) +#define CS530X_6_7_TDM_SLOT_VAL 3 + +#define CS530X_8_9_TDM_SLOT_MASK GENMASK(9, 8) +#define CS530X_8_11_TDM_SLOT_MASK GENMASK(11, 8) +#define CS530X_8_15_TDM_SLOT_MASK GENMASK(15, 8) +#define CS530X_8_15_TDM_SLOT_VAL 4 + +#define CS530X_10_11_TDM_SLOT_MASK GENMASK(11, 10) +#define CS530X_10_11_TDM_SLOT_VAL 5 + +#define CS530X_12_13_TDM_SLOT_MASK GENMASK(13, 12) +#define CS530X_12_15_TDM_SLOT_MASK GENMASK(15, 12) +#define CS530X_12_15_TDM_SLOT_VAL 6 + +#define CS530X_14_15_TDM_SLOT_MASK GENMASK(15, 14) +#define CS530X_14_15_TDM_SLOT_VAL 7 + +/* IN_RAMP_SUM */ +#define CS530X_RAMP_RATE_INC_SHIFT 0 +#define CS530X_RAMP_RATE_DEC_SHIFT 4 +#define CS530X_IN_SUM_MODE_SHIFT 13 + +/* IN_FILTER */ +#define CS530X_IN_FILTER_SHIFT 8 +#define CS530X_IN_HPF_EN_SHIFT 12 + +/* IN_HIZ */ +#define CS530X_IN12_HIZ BIT(0) +#define CS530X_IN34_HIZ BIT(1) +#define CS530X_IN56_HIZ BIT(2) +#define CS530X_IN78_HIZ BIT(3) + +/* IN_INV */ +#define CS530X_IN1_INV_SHIFT 0 +#define CS530X_IN2_INV_SHIFT 1 +#define CS530X_IN3_INV_SHIFT 2 +#define CS530X_IN4_INV_SHIFT 3 +#define CS530X_IN5_INV_SHIFT 4 +#define CS530X_IN6_INV_SHIFT 5 +#define CS530X_IN7_INV_SHIFT 6 +#define CS530X_IN8_INV_SHIFT 7 + +/* IN_VOL_CTLy_z */ +#define CS530X_IN_MUTE BIT(15) + +/* IN_VOL_CTL5 */ +#define CS530X_IN_VU BIT(0) + +/* PAD_FN */ +#define CS530X_DOUT2_FN BIT(0) +#define CS530X_DOUT3_FN BIT(1) +#define CS530X_DOUT4_FN BIT(2) +#define CS530X_SPI_CS_FN BIT(3) +#define CS530X_CONFIG2_FN BIT(6) +#define CS530X_CONFIG3_FN BIT(7) +#define CS530X_CONFIG4_FN BIT(8) +#define CS530X_CONFIG5_FN BIT(9) + +/* PAD_LVL */ +#define CS530X_CONFIG2_LVL BIT(6) +#define CS530X_CONFIG3_LVL BIT(7) +#define CS530X_CONFIG4_LVL BIT(8) +#define CS530X_CONFIG5_LVL BIT(9) + +/* System Clock Source */ +#define CS530X_SYSCLK_SRC_MCLK 0 +#define CS530X_SYSCLK_SRC_PLL 1 + +/* PLL Reference Clock Source */ +#define CS530X_PLL_SRC_BCLK 0 +#define CS530X_PLL_SRC_MCLK 1 + +#define CS530X_NUM_SUPPLIES 2 + +enum cs530x_type { + CS5302, + CS5304, + CS5308, +}; + +/* codec private data */ +struct cs530x_priv { + struct regmap *regmap; + struct device *dev; + struct snd_soc_dai_driver *dev_dai; + + enum cs530x_type devtype; + int num_adcs; + int num_dacs; + + struct regulator_bulk_data supplies[CS530X_NUM_SUPPLIES]; + + unsigned int mclk_rate; + + int tdm_width; + int tdm_slots; + int bclk; + int fs; + int adc_pairs_count; + + struct gpio_desc *reset_gpio; +}; + +extern const struct regmap_config cs530x_regmap; +int cs530x_probe(struct cs530x_priv *cs530x); + +#endif From 9c9b172fdd918c2f852140fc4a3cd827b78fa947 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Sat, 22 Jun 2024 13:12:45 +0000 Subject: [PATCH 184/349] ASoC: Add support for ti,pcm5242 to the pcm512x driver Add a compatible string to enable support for the ti,pcm5242 DAC chip in the pcm512x driver. Signed-off-by: Christian Hewitt Link: https://patch.msgid.link/20240622131245.2607533-3-christianshewitt@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x-i2c.c | 2 ++ sound/soc/codecs/pcm512x-spi.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c index 4be476a280e1..92bcf5179779 100644 --- a/sound/soc/codecs/pcm512x-i2c.c +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -39,6 +39,7 @@ static const struct i2c_device_id pcm512x_i2c_id[] = { { "pcm5122", }, { "pcm5141", }, { "pcm5142", }, + { "pcm5242", }, { "tas5754", }, { "tas5756", }, { } @@ -51,6 +52,7 @@ static const struct of_device_id pcm512x_of_match[] = { { .compatible = "ti,pcm5122", }, { .compatible = "ti,pcm5141", }, { .compatible = "ti,pcm5142", }, + { .compatible = "ti,pcm5242", }, { .compatible = "ti,tas5754", }, { .compatible = "ti,tas5756", }, { } diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c index 4d29e7196380..6629b862f47d 100644 --- a/sound/soc/codecs/pcm512x-spi.c +++ b/sound/soc/codecs/pcm512x-spi.c @@ -36,6 +36,7 @@ static const struct spi_device_id pcm512x_spi_id[] = { { "pcm5122", }, { "pcm5141", }, { "pcm5142", }, + { "pcm5242", }, { }, }; MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); @@ -45,6 +46,7 @@ static const struct of_device_id pcm512x_of_match[] = { { .compatible = "ti,pcm5122", }, { .compatible = "ti,pcm5141", }, { .compatible = "ti,pcm5142", }, + { .compatible = "ti,pcm5242", }, { } }; MODULE_DEVICE_TABLE(of, pcm512x_of_match); From 9427997a5e13320a3c404a0cb67a292ad8e00b62 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Sat, 22 Jun 2024 13:12:44 +0000 Subject: [PATCH 185/349] ASoC: dt-bindings: add ti,pcm5242 to pcm512x Add ti,pcm5242 to the pcm512x driver file Signed-off-by: Christian Hewitt Link: https://patch.msgid.link/20240622131245.2607533-2-christianshewitt@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/pcm512x.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt index 77006a4aec4a..47878a6df608 100644 --- a/Documentation/devicetree/bindings/sound/pcm512x.txt +++ b/Documentation/devicetree/bindings/sound/pcm512x.txt @@ -6,7 +6,7 @@ on the board). The TAS575x devices only support I2C. Required properties: - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141", - "ti,pcm5142", "ti,tas5754" or "ti,tas5756" + "ti,pcm5142", "ti,pcm5242", "ti,tas5754" or "ti,tas5756" - reg : the I2C address of the device for I2C, the chip select number for SPI. From 4eed78198b30c4c5975e454e7b1e6e25a7ac7353 Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Mon, 24 Jun 2024 11:06:04 +0800 Subject: [PATCH 186/349] ASoC: codecs: ES8326: Slove headphone detection issue We modified the headphone detection setting to avoid an error button state after codec resume from suspend state Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20240624030607.4307-2-zhangyi@everest-semi.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 6a4e42e5e35b..0468e6db81ca 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -877,6 +877,8 @@ static void es8326_jack_detect_handler(struct work_struct *work) if (es8326->jack->status & SND_JACK_HEADSET) { /* detect button */ dev_dbg(comp->dev, "button pressed\n"); + regmap_write(es8326->regmap, ES8326_INT_SOURCE, + (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); queue_delayed_work(system_wq, &es8326->button_press_work, 10); goto exit; } @@ -1052,11 +1054,6 @@ static int es8326_resume(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_ADC_MUTE, 0x0f); - es8326->jack_remove_retry = 0; - es8326->hp = 0; - es8326->hpl_vol = 0x03; - es8326->hpr_vol = 0x03; - es8326_irq(es8326->irq, es8326); return 0; } @@ -1211,6 +1208,10 @@ static int es8326_i2c_probe(struct i2c_client *i2c) } es8326->irq = i2c->irq; + es8326->jack_remove_retry = 0; + es8326->hp = 0; + es8326->hpl_vol = 0x03; + es8326->hpr_vol = 0x03; INIT_DELAYED_WORK(&es8326->jack_detect_work, es8326_jack_detect_handler); INIT_DELAYED_WORK(&es8326->button_press_work, From 7e7dbdee96cbc660e7e8d3d9d7a512acaa6ca69d Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Mon, 24 Jun 2024 11:06:06 +0800 Subject: [PATCH 187/349] ASoC: codecs: ES8326: Minimize the pop noise Executing regcache_sync at initialization, we can hear a gentle pop noise. So we created es8326_init for initialization instead of executing es8326_resume Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20240624030607.4307-4-zhangyi@everest-semi.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 0468e6db81ca..55edab04fa4b 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -974,14 +974,10 @@ static int es8326_calibrate(struct snd_soc_component *component) return 0; } -static int es8326_resume(struct snd_soc_component *component) +static void es8326_init(struct snd_soc_component *component) { struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); - 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); regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0); @@ -1037,7 +1033,6 @@ static int es8326_resume(struct snd_soc_component *component) es8326_enable_micbias(es8326->component); usleep_range(50000, 70000); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00); - regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9); regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, @@ -1053,6 +1048,28 @@ static int es8326_resume(struct snd_soc_component *component) ES8326_MUTE); regmap_write(es8326->regmap, ES8326_ADC_MUTE, 0x0f); + regmap_write(es8326->regmap, ES8326_CLK_DIV_LRCK, 0xff); + + msleep(200); + regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9); +} + +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_cache_bypass(es8326->regmap, true); + regmap_read(es8326->regmap, ES8326_CLK_RESAMPLE, ®); + regcache_cache_bypass(es8326->regmap, false); + /* reset internal clock state */ + if (reg == 0x05) + regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON); + else + es8326_init(component); + + regcache_sync(es8326->regmap); es8326_irq(es8326->irq, es8326); return 0; @@ -1112,7 +1129,7 @@ static int es8326_probe(struct snd_soc_component *component) } dev_dbg(component->dev, "interrupt-clk %x", es8326->interrupt_clk); - es8326_resume(component); + es8326_init(component); return 0; } From 34fa846f52f9fbef8aa262d3b39e71188e8dd884 Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Mon, 24 Jun 2024 11:06:07 +0800 Subject: [PATCH 188/349] ASoC: codecs: ES8326: regcache_sync error issue We modified the regmap_config members to fix cach sync error. There are several registers that should be read-only registers. If these registers are written while synchronizing the register values, the codec will enter an error state.So we create es8326_writeable_register, and set these registers to false Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20240624030607.4307-5-zhangyi@everest-semi.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 55edab04fa4b..b246694ebb4f 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -329,11 +329,29 @@ static bool es8326_volatile_register(struct device *dev, unsigned int reg) } } +static bool es8326_writeable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ES8326_BIAS_SW1: + case ES8326_BIAS_SW2: + case ES8326_BIAS_SW3: + case ES8326_BIAS_SW4: + case ES8326_ADC_HPFS1: + case ES8326_ADC_HPFS2: + return false; + default: + return true; + } +} + static const struct regmap_config es8326_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0xff, + .use_single_read = true, + .use_single_write = true, .volatile_reg = es8326_volatile_register, + .writeable_reg = es8326_writeable_register, .cache_type = REGCACHE_RBTREE, }; From 4ae814dabcdae3e434820c64396e15ccb33cc0ce Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Thu, 13 Jun 2024 10:07:25 +0800 Subject: [PATCH 189/349] ASoC: mediatek: mt6358: Add "Dmic Mode Switch" kcontrol for switch DMIC mode. There are two hardware connection methods for DMICs on the MT6358. In cases where more than two DMICs are used, we need to time-multiplex these DMICs. Therefore, we need to dynamically switch the modes of these DMICs based on the actual usage scenarios. ---- DMIC1 AU_VIN0 --- ---- DMIC2 AU_VIN2 --- ----DMIC3 When we want to use DMIC1/2, configure it to one-wire mode. When we want to use DMIC1/3, configure it to two-wire mode. Signed-off-by: Jiaxin Yu Link: https://patch.msgid.link/20240613020725.27874-1-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6358.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 0284e29c11d3..9247b90d1b99 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -96,7 +96,7 @@ struct mt6358_priv { int wov_enabled; - unsigned int dmic_one_wire_mode; + int dmic_one_wire_mode; }; int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, @@ -577,6 +577,39 @@ static int mt6358_put_wov(struct snd_kcontrol *kcontrol, return 0; } +static int mt6358_dmic_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(c); + + ucontrol->value.integer.value[0] = priv->dmic_one_wire_mode; + dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode); + + return 0; +} + +static int mt6358_dmic_mode_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(c); + int enabled = ucontrol->value.integer.value[0]; + + if (enabled < 0 || enabled > 1) + return -EINVAL; + + if (priv->dmic_one_wire_mode != enabled) { + priv->dmic_one_wire_mode = enabled; + dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode); + + return 1; + } + dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode); + + return 0; +} + static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0); static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0); @@ -599,6 +632,9 @@ static const struct snd_kcontrol_new mt6358_snd_controls[] = { SOC_SINGLE_BOOL_EXT("Wake-on-Voice Phase2 Switch", 0, mt6358_get_wov, mt6358_put_wov), + + SOC_SINGLE_BOOL_EXT("Dmic Mode Switch", 0, + mt6358_dmic_mode_get, mt6358_dmic_mode_set), }; /* MUX */ From fe836c78ef1ff16da32912c22348091a0d67bda1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 24 Jun 2024 14:15:18 +0200 Subject: [PATCH 190/349] ASoC: SOF: ipc4-topology: Use correct queue_id for requesting input pin format It is incorrect to request the input pin format of the destination widget using the output pin index of the source module as the indexes are not necessarily matching. moduleA.out_pin1 can be connected to moduleB.in_pin0 for example. Use the dst_queue_id to request the input format of the destination module. This bug remained unnoticed likely because in nocodec topologies we don't have process modules after a module copier, thus the pin/queue index is ignored. For the process module case, the code was likely have been tested in a controlled way where all the pin/queue/format properties were present to work. Update the debug prints to have better information. Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Signed-off-by: Pierre-Louis Bossart Cc: stable@vger.kernel.org # v6.8+ Link: https://patch.msgid.link/20240624121519.91703-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index d123edfa3bae..7755c01735f5 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -2869,7 +2869,7 @@ static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id, static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, struct snd_sof_widget *src_widget, struct snd_sof_widget *sink_widget, - int sink_id) + struct snd_sof_route *sroute) { struct sof_ipc4_copier_config_set_sink_format format; const struct sof_ipc_ops *iops = sdev->ipc->ops; @@ -2878,9 +2878,6 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, struct sof_ipc4_fw_module *fw_module; struct sof_ipc4_msg msg = {{ 0 }}; - dev_dbg(sdev->dev, "%s set copier sink %d format\n", - src_widget->widget->name, sink_id); - if (WIDGET_IS_DAI(src_widget->id)) { struct snd_sof_dai *dai = src_widget->private; @@ -2891,13 +2888,15 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, fw_module = src_widget->module_info; - format.sink_id = sink_id; + format.sink_id = sroute->src_queue_id; memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt)); - pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sink_id); + pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sroute->dst_queue_id); if (!pin_fmt) { - dev_err(sdev->dev, "Unable to get pin %d format for %s", - sink_id, sink_widget->widget->name); + dev_err(sdev->dev, + "Failed to get input audio format of %s:%d for output of %s:%d\n", + sink_widget->widget->name, sroute->dst_queue_id, + src_widget->widget->name, sroute->src_queue_id); return -EINVAL; } @@ -2955,7 +2954,8 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, SOF_PIN_TYPE_OUTPUT); if (sroute->src_queue_id < 0) { - dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n", + dev_err(sdev->dev, + "failed to get src_queue_id ID from source widget %s\n", src_widget->widget->name); return sroute->src_queue_id; } @@ -2963,7 +2963,8 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, SOF_PIN_TYPE_INPUT); if (sroute->dst_queue_id < 0) { - dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n", + dev_err(sdev->dev, + "failed to get dst_queue_id ID from sink widget %s\n", sink_widget->widget->name); sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT); @@ -2972,10 +2973,11 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * /* Pin 0 format is already set during copier module init */ if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) { - ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget, - sroute->src_queue_id); + ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, + sink_widget, sroute); if (ret < 0) { - dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n", + dev_err(sdev->dev, + "failed to set sink format for source %s:%d\n", src_widget->widget->name, sroute->src_queue_id); goto out; } From 00dd4d86ed908e70d912a96ad91d1248ff055b62 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 21 Jun 2024 21:23:07 +0800 Subject: [PATCH 191/349] ASoc: tas2781: Add name_prefix as the prefix name of firmwares and kcontrol to support corresponding TAS2563/TAS2781s Add name_prefix as the prefix name of firmwares and kcontrol to support corresponding TAS2563/TAS2781s. name_prefix is not mandatory. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20240621132309.564-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- include/sound/tas2781.h | 1 + sound/soc/codecs/tas2781-comlib.c | 13 +++++++++---- sound/soc/codecs/tas2781-i2c.c | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index 99ca3e401fd1..cd8ce522b78e 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -108,6 +108,7 @@ struct tasdevice_priv { unsigned char coef_binaryname[64]; unsigned char rca_binaryname[64]; unsigned char dev_name[32]; + const char *name_prefix; unsigned char ndev; unsigned int magic_num; unsigned int chip_id; diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index 3aa81514dad7..6db1a260da82 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 // -// tas2781-lib.c -- TAS2781 Common functions for HDA and ASoC Audio drivers +// TAS2781 Common functions for HDA and ASoC Audio drivers // -// Copyright 2023 Texas Instruments, Inc. +// Copyright 2023 - 2024 Texas Instruments, Inc. // // Author: Shenghao Ding @@ -277,8 +277,13 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, */ mutex_lock(&tas_priv->codec_lock); - scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin", - tas_priv->dev_name, tas_priv->ndev); + if (tas_priv->name_prefix) + scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin", + tas_priv->name_prefix, tas_priv->dev_name, + tas_priv->ndev); + else + scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin", + tas_priv->dev_name, tas_priv->ndev); crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL); tas_priv->codec = codec; ret = request_firmware_nowait(module, FW_ACTION_UEVENT, diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index c64d458e524e..4d1a0d836e77 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -579,6 +579,7 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec) { struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + tas_priv->name_prefix = codec->name_prefix; return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready); } From 65c90df918205bc84f5448550cde76a54dae5f52 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 24 Jun 2024 14:11:16 +0200 Subject: [PATCH 192/349] ASoC: Intel: sof_sdw: fix jack detection on ADL-N variant RVP Experimental tests show that JD2_100K is required, otherwise the jack is detected always even with nothing plugged-in. To avoid matching with other known quirks the SKU information is used. Signed-off-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20240624121119.91552-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index b646b32dd311..89b92a061489 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -277,6 +277,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2_100K), + }, { .callback = sof_sdw_quirk_cb, .matches = { From e364ffceab9252c06388727250d7583d6e0aea87 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 24 Jun 2024 14:11:17 +0200 Subject: [PATCH 193/349] ASoC: Intel: maxim-common: add max_98373_get_tx_mask function Add a helper function max_98373_get_tx_mask() to get tx mask from max98373 ACPI device properties at runtime. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20240624121119.91552-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_maxim_common.c | 56 +++++++++++++++++------ 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index f965b172fa36..fcc3b95e57a4 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -77,19 +77,36 @@ static struct snd_soc_dai_link_component max_98373_components[] = { * According to the definition of 'DAI Sel Mux' mixer in max98373.c, rx mask * should choose two channels from TDM slots, the LSB of rx mask is left channel * and the other one is right channel. - * - * For tx mask, each codec requires two channels: one for V-sense and the other - * one for I-sense. Must match the device property "maxim,vmon-slot-no" and - * "maxim,imon-slot-no" in ACPI table. */ static const struct { - unsigned int tx; unsigned int rx; } max_98373_tdm_mask[] = { - {.tx = 0x03, .rx = 0x3}, - {.tx = 0x0c, .rx = 0x3}, + {.rx = 0x3}, + {.rx = 0x3}, }; +/* + * The tx mask indicates which channel(s) contains output IV-sense data and + * others should set to Hi-Z. Here we get the channel number from codec's ACPI + * device property "maxim,vmon-slot-no" and "maxim,imon-slot-no" to generate the + * mask. Refer to the max98373_slot_config() function in max98373.c codec driver. + */ +static unsigned int max_98373_get_tx_mask(struct device *dev) +{ + int vmon_slot; + int imon_slot; + + if (device_property_read_u32(dev, "maxim,vmon-slot-no", &vmon_slot)) + vmon_slot = 0; + + if (device_property_read_u32(dev, "maxim,imon-slot-no", &imon_slot)) + imon_slot = 1; + + dev_dbg(dev, "vmon_slot %d imon_slot %d\n", vmon_slot, imon_slot); + + return (0x1 << vmon_slot) | (0x1 << imon_slot); +} + static int max_98373_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -98,6 +115,8 @@ static int max_98373_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai; int i; int tdm_slots; + unsigned int tx_mask; + unsigned int tx_mask_used = 0x0; int ret = 0; for_each_rtd_codec_dais(rtd, i, codec_dai) { @@ -117,13 +136,26 @@ static int max_98373_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* get the tx mask from ACPI device properties */ + tx_mask = max_98373_get_tx_mask(codec_dai->dev); + if (!tx_mask) + return -EINVAL; + + if (tx_mask & tx_mask_used) { + dev_err(codec_dai->dev, "invalid tx mask 0x%x, used 0x%x\n", + tx_mask, tx_mask_used); + return -EINVAL; + } + + tx_mask_used |= tx_mask; + /* * check if tdm slot number is too small for channel * allocation */ - if (fls(max_98373_tdm_mask[i].tx) > tdm_slots) { + if (fls(tx_mask) > tdm_slots) { dev_err(codec_dai->dev, "slot mismatch, tx %d slots %d\n", - fls(max_98373_tdm_mask[i].tx), tdm_slots); + fls(tx_mask), tdm_slots); return -EINVAL; } @@ -134,12 +166,10 @@ static int max_98373_hw_params(struct snd_pcm_substream *substream, } dev_dbg(codec_dai->dev, "set tdm slot: tx 0x%x rx 0x%x slots %d width %d\n", - max_98373_tdm_mask[i].tx, - max_98373_tdm_mask[i].rx, + tx_mask, max_98373_tdm_mask[i].rx, tdm_slots, params_width(params)); - ret = snd_soc_dai_set_tdm_slot(codec_dai, - max_98373_tdm_mask[i].tx, + ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask, max_98373_tdm_mask[i].rx, tdm_slots, params_width(params)); From 92d5b5930e7d55ca07b483490d6298eee828bbe4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 24 Jun 2024 14:11:18 +0200 Subject: [PATCH 194/349] ASoC: Intel: sof_sdw: add quirk for Dell SKU 0B8C MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jack detection needs to rely on JD2, as most other Dell AlderLake-based devices. Closes: https://github.com/thesofproject/linux/issues/5021 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Link: https://patch.msgid.link/20240624121119.91552-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 89b92a061489..e94849b84a6b 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -406,6 +406,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { /* No Jack */ .driver_data = (void *)SOF_SDW_TGL_HDMI, }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, { .callback = sof_sdw_quirk_cb, .matches = { From c073f0757663c104271c8749f7e6b19b29c7b8ac Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 24 Jun 2024 14:11:19 +0200 Subject: [PATCH 195/349] ASoC: Intel: sof_sdw: select PINCTRL_CS42L43 and SPI_CS42L43 Cs42l43 bridge mode needs the two configurations. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20240624121119.91552-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 4e0586034de4..f1faa5dd2a4f 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -677,6 +677,8 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_CS42L43_SDW select MFD_CS42L43 select MFD_CS42L43_SDW + select PINCTRL_CS42L43 + select SPI_CS42L43 select SND_SOC_CS35L56_SPI select SND_SOC_CS35L56_SDW select SND_SOC_DMIC From 337b7b0b8b02aa10b52386371433eb6f522dc550 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Jun 2024 13:33:55 +0200 Subject: [PATCH 196/349] ALSA: pcm_dmaengine: Unify two close functions Both snd_dmaengine_pcm_close() and snd_dmaengine_pcm_close_release_chan() are almost identical except for a call of dma_release_channel() in the latter. For code simplification, unify them internally. Just a code refactoring, and no functional changes. Link: https://patch.msgid.link/20240625113356.2123-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_dmaengine.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 7346c993a067..4f18511f1c92 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -349,13 +349,8 @@ int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan); -/** - * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream - * @substream: PCM substream - * - * Return: 0 on success, a negative error code otherwise - */ -int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) +static void __snd_dmaengine_pcm_close(struct snd_pcm_substream *substream, + bool release_channel) { struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); struct dma_tx_state state; @@ -366,8 +361,20 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) dmaengine_terminate_async(prtd->dma_chan); dmaengine_synchronize(prtd->dma_chan); + if (release_channel) + dma_release_channel(prtd->dma_chan); kfree(prtd); +} +/** + * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream + * @substream: PCM substream + * + * Return: 0 on success, a negative error code otherwise + */ +int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) +{ + __snd_dmaengine_pcm_close(substream, false); return 0; } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); @@ -383,18 +390,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); */ int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream) { - struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); - struct dma_tx_state state; - enum dma_status status; - - status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state); - if (status == DMA_PAUSED) - dmaengine_terminate_async(prtd->dma_chan); - - dmaengine_synchronize(prtd->dma_chan); - dma_release_channel(prtd->dma_chan); - kfree(prtd); - + __snd_dmaengine_pcm_close(substream, true); return 0; } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan); From 15c99e7fa9e2bb536e813478250d2a609863dcfb Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Tue, 25 Jun 2024 05:34:19 +0200 Subject: [PATCH 197/349] MAINTAINERS: adjust file entries after adding vendor prefix in sound dtbs Commit ae8fc2948b48 ("ASoC: dt-bindings: add missing vender prefix on filename") renames a few files in Documentation/devicetree/bindings/sound/, but misses to adjust the file entries pointing to those files in MAINTAINERS. Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about broken references. Adjust the file entries in NXP SGTL5000 DRIVER and TEXAS INSTRUMENTS AUDIO (ASoC/HDA) DRIVERS. Signed-off-by: Lukas Bulwahn Acked-by: Kuninori Morimoto Link: https://patch.msgid.link/20240625033419.149775-1-lukas.bulwahn@redhat.com Signed-off-by: Mark Brown --- MAINTAINERS | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c35c03901252..d3b064ce0ba6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16195,7 +16195,7 @@ NXP SGTL5000 DRIVER M: Fabio Estevam L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained -F: Documentation/devicetree/bindings/sound/sgtl5000.yaml +F: Documentation/devicetree/bindings/sound/fsl,sgtl5000.yaml F: sound/soc/codecs/sgtl5000* NXP SJA1105 ETHERNET SWITCH DRIVER @@ -22175,13 +22175,13 @@ M: Baojun Xu L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/sound/tas2552.txt -F: Documentation/devicetree/bindings/sound/tas2562.yaml -F: Documentation/devicetree/bindings/sound/tas2770.yaml -F: Documentation/devicetree/bindings/sound/tas27xx.yaml +F: Documentation/devicetree/bindings/sound/ti,tas2562.yaml +F: Documentation/devicetree/bindings/sound/ti,tas2770.yaml +F: Documentation/devicetree/bindings/sound/ti,tas27xx.yaml F: Documentation/devicetree/bindings/sound/ti,pcm1681.yaml F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml -F: Documentation/devicetree/bindings/sound/tlv320adcx140.yaml +F: Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml F: Documentation/devicetree/bindings/sound/tlv320aic31xx.txt F: Documentation/devicetree/bindings/sound/tpa6130a2.txt F: include/sound/tas2*.h From 6f9faf1410fe151350ece4a93df30b9e06deec92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 24 Jun 2024 15:17:27 +0200 Subject: [PATCH 198/349] ASoC: codecs: Drop explicit initialization of struct i2c_device_id::driver_data to 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These drivers don't use the driver_data member of struct i2c_device_id, so don't explicitly initialize this member. This prepares putting driver_data in an anonymous union which requires either no initialization or named designators. But it's also a nice cleanup on its own. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/20240624131728.1244053-2-u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw87390.c | 2 +- sound/soc/codecs/aw88261.c | 2 +- sound/soc/codecs/aw88395/aw88395.c | 2 +- sound/soc/codecs/aw88399.c | 2 +- sound/soc/codecs/es8311.c | 5 ++++- sound/soc/codecs/rt1318.c | 2 +- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c index 79521ff44001..110009616966 100644 --- a/sound/soc/codecs/aw87390.c +++ b/sound/soc/codecs/aw87390.c @@ -445,7 +445,7 @@ static int aw87390_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id aw87390_i2c_id[] = { - { AW87390_I2C_NAME, 0 }, + { AW87390_I2C_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, aw87390_i2c_id); diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c index a78ceedd0334..fb99871578c5 100644 --- a/sound/soc/codecs/aw88261.c +++ b/sound/soc/codecs/aw88261.c @@ -1266,7 +1266,7 @@ static int aw88261_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id aw88261_i2c_id[] = { - { AW88261_I2C_NAME, 0 }, + { AW88261_I2C_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, aw88261_i2c_id); diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c index be6ebcb51cca..aea44a199b98 100644 --- a/sound/soc/codecs/aw88395/aw88395.c +++ b/sound/soc/codecs/aw88395/aw88395.c @@ -560,7 +560,7 @@ static int aw88395_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id aw88395_i2c_id[] = { - { AW88395_I2C_NAME, 0 }, + { AW88395_I2C_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, aw88395_i2c_id); diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index 5d8481612eab..8dc2b8aa6832 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -1892,7 +1892,7 @@ static int aw88399_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id aw88399_i2c_id[] = { - { AW88399_I2C_NAME, 0 }, + { AW88399_I2C_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, aw88399_i2c_id); diff --git a/sound/soc/codecs/es8311.c b/sound/soc/codecs/es8311.c index b2ee2d04b0e4..f557e33c26ad 100644 --- a/sound/soc/codecs/es8311.c +++ b/sound/soc/codecs/es8311.c @@ -943,7 +943,10 @@ static int es8311_i2c_probe(struct i2c_client *i2c_client) &es8311_dai, 1); } -static const struct i2c_device_id es8311_id[] = { { "es8311", 0 }, {} }; +static const struct i2c_device_id es8311_id[] = { + { "es8311" }, + { } +}; MODULE_DEVICE_TABLE(i2c, es8311_id); static const struct of_device_id es8311_of_match[] = { diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c index 4e47db4fc7fb..83b29b441be9 100644 --- a/sound/soc/codecs/rt1318.c +++ b/sound/soc/codecs/rt1318.c @@ -1141,7 +1141,7 @@ static const struct regmap_config rt1318_regmap = { }; static const struct i2c_device_id rt1318_i2c_id[] = { - { "rt1318", 0 }, + { "rt1318" }, { } }; MODULE_DEVICE_TABLE(i2c, rt1318_i2c_id); From 903e85093670c3e1107980b5e5a718682458f316 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 25 Jun 2024 18:06:14 +0200 Subject: [PATCH 199/349] ASoC: codecs: lpass-rx-macro: add missing handling of v2.1 codec We have also v2.1 version of the codec (see 'enum lpass_codec_version'), so handle it as well in all switch cases. Fixes: dbacef05898d ("ASoC: codec: lpass-rx-macro: prepare driver to accomdate new codec versions") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20240625160614.450506-1-krzysztof.kozlowski@linaro.org Reviewed-by: Dmitry Baryshkov Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 83791507ed13..8af86509a3ff 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -1601,6 +1601,7 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg) case LPASS_CODEC_VERSION_1_1: case LPASS_CODEC_VERSION_1_2: case LPASS_CODEC_VERSION_2_0: + case LPASS_CODEC_VERSION_2_1: return rx_pre_2_5_is_rw_register(dev, reg); case LPASS_CODEC_VERSION_2_5: case LPASS_CODEC_VERSION_2_6: @@ -3639,6 +3640,7 @@ static int rx_macro_component_probe(struct snd_soc_component *component) case LPASS_CODEC_VERSION_1_1: case LPASS_CODEC_VERSION_1_2: case LPASS_CODEC_VERSION_2_0: + case LPASS_CODEC_VERSION_2_1: controls = rx_macro_def_snd_controls; num_controls = ARRAY_SIZE(rx_macro_def_snd_controls); widgets = rx_macro_def_dapm_widgets; @@ -3812,6 +3814,7 @@ static int rx_macro_probe(struct platform_device *pdev) case LPASS_CODEC_VERSION_1_1: case LPASS_CODEC_VERSION_1_2: case LPASS_CODEC_VERSION_2_0: + case LPASS_CODEC_VERSION_2_1: rx->rxn_reg_stride = 0x80; def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_pre_2_5_defaults); reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL); From 50b8affb5665efa028998ad2c116b1106623409e Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 25 Jun 2024 16:43:03 +0800 Subject: [PATCH 200/349] ASoC: rt711-sdca: add GE selected mode control The SDCA spec defines a 'selected_mode' control which can override the 'detected_mode' reported by hardware. This is useful for platform integration as well as in cases where the hardware(e.g. 3.5mm jack cable) is not able to accurately detect the jack type. Signed-off-by: Shuming Fan Tested-by: yung-chuan.liao@linux.intel.com Link: https://patch.msgid.link/20240625084303.2273911-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdca.c | 72 +++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt711-sdca.h | 1 + 2 files changed, 73 insertions(+) diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 1e8dbfc3ecd9..dd6ccf17afd4 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -81,6 +81,24 @@ static void rt711_sdca_reset(struct rt711_sdca_priv *rt711) RT711_HDA_LEGACY_RESET_CTL, 0x1, 0x1); } +static void rt711_sdca_ge_force_jack_type(struct rt711_sdca_priv *rt711, unsigned int det_mode) +{ + switch (det_mode) { + case 0x00: + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x0000); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x10, 0x00); + break; + case 0x03: + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x8000); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x17, 0x13); + break; + case 0x05: + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x8400); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x17, 0x15); + break; + } +} + static int rt711_sdca_calibration(struct rt711_sdca_priv *rt711) { unsigned int val, loop_rc = 0, loop_dc = 0; @@ -248,6 +266,8 @@ static int rt711_sdca_headset_detect(struct rt711_sdca_priv *rt711) unsigned int det_mode; int ret; + rt711_sdca_ge_force_jack_type(rt711, rt711->ge_mode_override); + /* get detected_mode */ ret = regmap_read(rt711->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0), @@ -790,6 +810,56 @@ static int rt711_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol, return changed; } +static int rt711_sdca_ge_select_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned int val, item; + + val = (rt711->ge_mode_override >> e->shift_l) & e->mask; + item = snd_soc_enum_val_to_item(e, val); + ucontrol->value.enumerated.item[0] = item; + return 0; +} + +static int rt711_sdca_ge_select_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned int val, change = 0; + + if (item[0] >= e->items) + return -EINVAL; + + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + if (rt711->ge_mode_override != val) { + rt711->ge_mode_override = val; + change = 1; + } + + return change; +} + +static const char * const rt711_sdca_ge_select[] = { + "Auto", + "Headphone", + "Headset", +}; + +static int rt711_sdca_ge_select_values[] = { + 0, + 3, + 5, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(rt711_sdca_ge_mode_enum, SND_SOC_NOPM, + 0, 0x7, rt711_sdca_ge_select, rt711_sdca_ge_select_values); + static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); @@ -824,6 +894,8 @@ static const struct snd_kcontrol_new rt711_sdca_snd_controls[] = { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 8, 3, 0, rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, mic_vol_tlv), + SOC_ENUM_EXT("GE49 Selected Mode", rt711_sdca_ge_mode_enum, + rt711_sdca_ge_select_get, rt711_sdca_ge_select_put), }; static int rt711_sdca_mux_get(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h index 11d421e8ab2b..15263dcb0314 100644 --- a/sound/soc/codecs/rt711-sdca.h +++ b/sound/soc/codecs/rt711-sdca.h @@ -33,6 +33,7 @@ struct rt711_sdca_priv { int hw_ver; bool fu0f_dapm_mute, fu0f_mixer_l_mute, fu0f_mixer_r_mute; bool fu1e_dapm_mute, fu1e_mixer_l_mute, fu1e_mixer_r_mute; + unsigned int ge_mode_override; }; /* NID */ From 04f4de6f68eec73595682f32952467591f0cc016 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 25 Jun 2024 18:58:45 +0200 Subject: [PATCH 201/349] ASoC: codecs: lpass-wsa-macro: Drop unused define WSA_MACRO_MUX_INP_MASK2 define is not used. Signed-off-by: Krzysztof Kozlowski Acked-by: Dmitry Baryshkov Link: https://patch.msgid.link/20240625-qcom-audio-wsa-second-speaker-v1-1-f65ffdfc368c@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 1e19c2b28a4f..1a36a384cc88 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -235,7 +235,6 @@ #define NUM_INTERPOLATORS 2 #define WSA_NUM_CLKS_MAX 5 #define WSA_MACRO_MCLK_FREQ 19200000 -#define WSA_MACRO_MUX_INP_MASK2 0x38 #define WSA_MACRO_MUX_CFG_OFFSET 0x8 #define WSA_MACRO_MUX_CFG1_OFFSET 0x4 #define WSA_MACRO_RX_COMP_OFFSET 0x40 From 5dcf442bbbcada62631f5a376c44ff794596c2f0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 25 Jun 2024 18:58:46 +0200 Subject: [PATCH 202/349] ASoC: codecs: lpass-wsa-macro: Prepare to accommodate new codec versions The driver for Qualcomm LPASS WSA macro codec was developed and tested on codec v2.1, however v2.5 has significant changes in the registers. The driver correctly works for v2.1 codec, but has issues when running on SoC with v2.5 codec (so starting with SM8450, even though playback works properly on that SoC). Prepare the driver for handling differences in register layouts of newer version. This does not have functional impact on older codec versions, but just: 1. Renames few soc_enums and widgets as v2.1, 2. For registers being different in v2.5, moves the defaults and regmap configuration to new structures, 3. Adds new 'struct wsa_reg_layout' with offsets and masks for few registers, so most of the code can stay unchaged on v2.5, 4. Chooses proper widgets, regmap config and register layout based on version of the codec. Signed-off-by: Krzysztof Kozlowski Acked-by: Dmitry Baryshkov Link: https://patch.msgid.link/20240625-qcom-audio-wsa-second-speaker-v1-2-f65ffdfc368c@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 340 ++++++++++++++++++----------- 1 file changed, 218 insertions(+), 122 deletions(-) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 1a36a384cc88..8cdf8f7f64b1 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -44,11 +44,7 @@ #define CDC_WSA_TOP_I2S_CLK (0x00A4) #define CDC_WSA_TOP_I2S_RESET (0x00A8) #define CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 (0x0100) -#define CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK GENMASK(2, 0) -#define CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK GENMASK(5, 3) #define CDC_WSA_RX_INP_MUX_RX_INT0_CFG1 (0x0104) -#define CDC_WSA_RX_INTX_2_SEL_MASK GENMASK(2, 0) -#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK GENMASK(5, 3) #define CDC_WSA_RX_INP_MUX_RX_INT1_CFG0 (0x0108) #define CDC_WSA_RX_INP_MUX_RX_INT1_CFG1 (0x010C) #define CDC_WSA_RX_INP_MUX_RX_MIX_CFG0 (0x0110) @@ -173,22 +169,7 @@ #define CDC_WSA_COMPANDER0_CTL5 (0x0594) #define CDC_WSA_COMPANDER0_CTL6 (0x0598) #define CDC_WSA_COMPANDER0_CTL7 (0x059C) -#define CDC_WSA_COMPANDER1_CTL0 (0x05C0) -#define CDC_WSA_COMPANDER1_CTL1 (0x05C4) -#define CDC_WSA_COMPANDER1_CTL2 (0x05C8) -#define CDC_WSA_COMPANDER1_CTL3 (0x05CC) -#define CDC_WSA_COMPANDER1_CTL4 (0x05D0) -#define CDC_WSA_COMPANDER1_CTL5 (0x05D4) -#define CDC_WSA_COMPANDER1_CTL6 (0x05D8) -#define CDC_WSA_COMPANDER1_CTL7 (0x05DC) -#define CDC_WSA_SOFTCLIP0_CRC (0x0600) -#define CDC_WSA_SOFTCLIP_CLK_EN_MASK BIT(0) -#define CDC_WSA_SOFTCLIP_CLK_ENABLE BIT(0) -#define CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL (0x0604) -#define CDC_WSA_SOFTCLIP_EN_MASK BIT(0) -#define CDC_WSA_SOFTCLIP_ENABLE BIT(0) -#define CDC_WSA_SOFTCLIP1_CRC (0x0640) -#define CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0644) +/* CDC_WSA_COMPANDER1_CTLx and CDC_WSA_SOFTCLIPx differ per LPASS codec versions */ #define CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL (0x0680) #define CDC_WSA_EC_HQ_EC_CLK_EN_MASK BIT(0) #define CDC_WSA_EC_HQ_EC_CLK_ENABLE BIT(0) @@ -217,6 +198,24 @@ #define CDC_WSA_SPLINE_ASRC1_STATUS_FIFO (0x0760) #define WSA_MAX_OFFSET (0x0760) +/* LPASS codec version <=2.4 register offsets */ +#define CDC_WSA_COMPANDER1_CTL0 (0x05C0) +#define CDC_WSA_COMPANDER1_CTL1 (0x05C4) +#define CDC_WSA_COMPANDER1_CTL2 (0x05C8) +#define CDC_WSA_COMPANDER1_CTL3 (0x05CC) +#define CDC_WSA_COMPANDER1_CTL4 (0x05D0) +#define CDC_WSA_COMPANDER1_CTL5 (0x05D4) +#define CDC_WSA_COMPANDER1_CTL6 (0x05D8) +#define CDC_WSA_COMPANDER1_CTL7 (0x05DC) +#define CDC_WSA_SOFTCLIP0_CRC (0x0600) +#define CDC_WSA_SOFTCLIP_CLK_EN_MASK BIT(0) +#define CDC_WSA_SOFTCLIP_CLK_ENABLE BIT(0) +#define CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL (0x0604) +#define CDC_WSA_SOFTCLIP_EN_MASK BIT(0) +#define CDC_WSA_SOFTCLIP_ENABLE BIT(0) +#define CDC_WSA_SOFTCLIP1_CRC (0x0640) +#define CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0644) + #define WSA_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) @@ -237,8 +236,6 @@ #define WSA_MACRO_MCLK_FREQ 19200000 #define WSA_MACRO_MUX_CFG_OFFSET 0x8 #define WSA_MACRO_MUX_CFG1_OFFSET 0x4 -#define WSA_MACRO_RX_COMP_OFFSET 0x40 -#define WSA_MACRO_RX_SOFTCLIP_OFFSET 0x40 #define WSA_MACRO_RX_PATH_OFFSET 0x80 #define WSA_MACRO_RX_PATH_CFG3_OFFSET 0x10 #define WSA_MACRO_RX_PATH_DSMDEM_OFFSET 0x4C @@ -334,12 +331,34 @@ enum { WSA_MACRO_MAX_DAIS, }; +/** + * struct wsa_reg_layout - Register layout differences + * @rx_intx_1_mix_inp0_sel_mask: register mask for RX_INTX_1_MIX_INP0_SEL_MASK + * @rx_intx_1_mix_inp1_sel_mask: register mask for RX_INTX_1_MIX_INP1_SEL_MASK + * @rx_intx_1_mix_inp2_sel_mask: register mask for RX_INTX_1_MIX_INP2_SEL_MASK + * @rx_intx_2_sel_mask: register mask for RX_INTX_2_SEL_MASK + * @compander1_reg_offset: offset between compander registers (compander1 - compander0) + * @softclip0_reg_base: base address of softclip0 register + * @softclip1_reg_offset: offset between compander registers (softclip1 - softclip0) + */ +struct wsa_reg_layout { + unsigned int rx_intx_1_mix_inp0_sel_mask; + unsigned int rx_intx_1_mix_inp1_sel_mask; + unsigned int rx_intx_1_mix_inp2_sel_mask; + unsigned int rx_intx_2_sel_mask; + unsigned int compander1_reg_offset; + unsigned int softclip0_reg_base; + unsigned int softclip1_reg_offset; +}; + struct wsa_macro { struct device *dev; int comp_enabled[WSA_MACRO_COMP_MAX]; int ec_hq[WSA_MACRO_RX1 + 1]; u16 prim_int_users[WSA_MACRO_RX1 + 1]; u16 wsa_mclk_users; + enum lpass_codec_version codec_version; + const struct wsa_reg_layout *reg_layout; unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[WSA_MACRO_MAX_DAIS]; int rx_port_value[WSA_MACRO_RX_MAX]; @@ -358,13 +377,23 @@ struct wsa_macro { }; #define to_wsa_macro(_hw) container_of(_hw, struct wsa_macro, hw) +static const struct wsa_reg_layout wsa_codec_v2_1 = { + .rx_intx_1_mix_inp0_sel_mask = GENMASK(2, 0), + .rx_intx_1_mix_inp1_sel_mask = GENMASK(5, 3), + .rx_intx_1_mix_inp2_sel_mask = GENMASK(5, 3), + .rx_intx_2_sel_mask = GENMASK(2, 0), + .compander1_reg_offset = 0x40, + .softclip0_reg_base = 0x600, + .softclip1_reg_offset = 0x40, +}; + static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400); -static const char *const rx_text[] = { +static const char *const rx_text_v2_1[] = { "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "DEC0", "DEC1" }; -static const char *const rx_mix_text[] = { +static const char *const rx_mix_text_v2_1[] = { "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1" }; @@ -389,68 +418,68 @@ static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_ear_spkr_pa_gain_enum, wsa_macro_ear_spkr_pa_gain_text); /* RX INT0 */ -static const struct soc_enum rx0_prim_inp0_chain_enum = +static const struct soc_enum rx0_prim_inp0_chain_enum_v2_1 = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, - 0, 7, rx_text); + 0, 7, rx_text_v2_1); -static const struct soc_enum rx0_prim_inp1_chain_enum = +static const struct soc_enum rx0_prim_inp1_chain_enum_v2_1 = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, - 3, 7, rx_text); + 3, 7, rx_text_v2_1); -static const struct soc_enum rx0_prim_inp2_chain_enum = +static const struct soc_enum rx0_prim_inp2_chain_enum_v2_1 = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, - 3, 7, rx_text); + 3, 7, rx_text_v2_1); -static const struct soc_enum rx0_mix_chain_enum = +static const struct soc_enum rx0_mix_chain_enum_v2_1 = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, - 0, 5, rx_mix_text); + 0, 5, rx_mix_text_v2_1); static const struct soc_enum rx0_sidetone_mix_enum = SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text); -static const struct snd_kcontrol_new rx0_prim_inp0_mux = - SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum); +static const struct snd_kcontrol_new rx0_prim_inp0_mux_v2_1 = + SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum_v2_1); -static const struct snd_kcontrol_new rx0_prim_inp1_mux = - SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum); +static const struct snd_kcontrol_new rx0_prim_inp1_mux_v2_1 = + SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum_v2_1); -static const struct snd_kcontrol_new rx0_prim_inp2_mux = - SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum); +static const struct snd_kcontrol_new rx0_prim_inp2_mux_v2_1 = + SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum_v2_1); -static const struct snd_kcontrol_new rx0_mix_mux = - SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum); +static const struct snd_kcontrol_new rx0_mix_mux_v2_1 = + SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2_1); static const struct snd_kcontrol_new rx0_sidetone_mix_mux = SOC_DAPM_ENUM("WSA_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum); /* RX INT1 */ -static const struct soc_enum rx1_prim_inp0_chain_enum = +static const struct soc_enum rx1_prim_inp0_chain_enum_v2_1 = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, - 0, 7, rx_text); + 0, 7, rx_text_v2_1); -static const struct soc_enum rx1_prim_inp1_chain_enum = +static const struct soc_enum rx1_prim_inp1_chain_enum_v2_1 = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, - 3, 7, rx_text); + 3, 7, rx_text_v2_1); -static const struct soc_enum rx1_prim_inp2_chain_enum = +static const struct soc_enum rx1_prim_inp2_chain_enum_v2_1 = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, - 3, 7, rx_text); + 3, 7, rx_text_v2_1); -static const struct soc_enum rx1_mix_chain_enum = +static const struct soc_enum rx1_mix_chain_enum_v2_1 = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, - 0, 5, rx_mix_text); + 0, 5, rx_mix_text_v2_1); -static const struct snd_kcontrol_new rx1_prim_inp0_mux = - SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum); +static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2_1 = + SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2_1); -static const struct snd_kcontrol_new rx1_prim_inp1_mux = - SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum); +static const struct snd_kcontrol_new rx1_prim_inp1_mux_v2_1 = + SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum_v2_1); -static const struct snd_kcontrol_new rx1_prim_inp2_mux = - SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum); +static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2_1 = + SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum_v2_1); -static const struct snd_kcontrol_new rx1_mix_mux = - SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum); +static const struct snd_kcontrol_new rx1_mix_mux_v2_1 = + SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2_1); static const struct soc_enum rx_mix_ec0_enum = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, @@ -489,14 +518,6 @@ static const struct reg_default wsa_defaults[] = { { CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, 0x00}, { CDC_WSA_RX_INP_MUX_RX_EC_CFG0, 0x00}, { CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, 0x00}, - { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02}, - { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00}, - { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02}, - { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00}, - { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02}, - { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00}, - { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02}, - { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00}, { CDC_WSA_INTR_CTRL_CFG, 0x00}, { CDC_WSA_INTR_CTRL_CLR_COMMIT, 0x00}, { CDC_WSA_INTR_CTRL_PIN1_MASK0, 0xFF}, @@ -561,18 +582,6 @@ static const struct reg_default wsa_defaults[] = { { CDC_WSA_COMPANDER0_CTL5, 0x00}, { CDC_WSA_COMPANDER0_CTL6, 0x01}, { CDC_WSA_COMPANDER0_CTL7, 0x28}, - { CDC_WSA_COMPANDER1_CTL0, 0x60}, - { CDC_WSA_COMPANDER1_CTL1, 0xDB}, - { CDC_WSA_COMPANDER1_CTL2, 0xFF}, - { CDC_WSA_COMPANDER1_CTL3, 0x35}, - { CDC_WSA_COMPANDER1_CTL4, 0xFF}, - { CDC_WSA_COMPANDER1_CTL5, 0x00}, - { CDC_WSA_COMPANDER1_CTL6, 0x01}, - { CDC_WSA_COMPANDER1_CTL7, 0x28}, - { CDC_WSA_SOFTCLIP0_CRC, 0x00}, - { CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38}, - { CDC_WSA_SOFTCLIP1_CRC, 0x00}, - { CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38}, { CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL, 0x00}, { CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0, 0x01}, { CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL, 0x00}, @@ -597,6 +606,29 @@ static const struct reg_default wsa_defaults[] = { { CDC_WSA_SPLINE_ASRC1_STATUS_FIFO, 0x00}, }; +static const struct reg_default wsa_defaults_v2_1[] = { + { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02}, + { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00}, + { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02}, + { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00}, + { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02}, + { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00}, + { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02}, + { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00}, + { CDC_WSA_COMPANDER1_CTL0, 0x60}, + { CDC_WSA_COMPANDER1_CTL1, 0xDB}, + { CDC_WSA_COMPANDER1_CTL2, 0xFF}, + { CDC_WSA_COMPANDER1_CTL3, 0x35}, + { CDC_WSA_COMPANDER1_CTL4, 0xFF}, + { CDC_WSA_COMPANDER1_CTL5, 0x00}, + { CDC_WSA_COMPANDER1_CTL6, 0x01}, + { CDC_WSA_COMPANDER1_CTL7, 0x28}, + { CDC_WSA_SOFTCLIP0_CRC, 0x00}, + { CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38}, + { CDC_WSA_SOFTCLIP1_CRC, 0x00}, + { CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38}, +}; + static bool wsa_is_wronly_register(struct device *dev, unsigned int reg) { @@ -610,6 +642,26 @@ static bool wsa_is_wronly_register(struct device *dev, return false; } +static bool wsa_is_rw_register_v2_1(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_WSA_COMPANDER1_CTL0: + case CDC_WSA_COMPANDER1_CTL1: + case CDC_WSA_COMPANDER1_CTL2: + case CDC_WSA_COMPANDER1_CTL3: + case CDC_WSA_COMPANDER1_CTL4: + case CDC_WSA_COMPANDER1_CTL5: + case CDC_WSA_COMPANDER1_CTL7: + case CDC_WSA_SOFTCLIP0_CRC: + case CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL: + case CDC_WSA_SOFTCLIP1_CRC: + case CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL: + return true; + } + + return false; +} + static bool wsa_is_rw_register(struct device *dev, unsigned int reg) { switch (reg) { @@ -701,17 +753,6 @@ static bool wsa_is_rw_register(struct device *dev, unsigned int reg) case CDC_WSA_COMPANDER0_CTL4: case CDC_WSA_COMPANDER0_CTL5: case CDC_WSA_COMPANDER0_CTL7: - case CDC_WSA_COMPANDER1_CTL0: - case CDC_WSA_COMPANDER1_CTL1: - case CDC_WSA_COMPANDER1_CTL2: - case CDC_WSA_COMPANDER1_CTL3: - case CDC_WSA_COMPANDER1_CTL4: - case CDC_WSA_COMPANDER1_CTL5: - case CDC_WSA_COMPANDER1_CTL7: - case CDC_WSA_SOFTCLIP0_CRC: - case CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL: - case CDC_WSA_SOFTCLIP1_CRC: - case CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL: case CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL: case CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0: case CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL: @@ -727,7 +768,7 @@ static bool wsa_is_rw_register(struct device *dev, unsigned int reg) return true; } - return false; + return wsa_is_rw_register_v2_1(dev, reg); } static bool wsa_is_writeable_register(struct device *dev, unsigned int reg) @@ -741,6 +782,16 @@ static bool wsa_is_writeable_register(struct device *dev, unsigned int reg) return ret; } +static bool wsa_is_readable_register_v2_1(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_WSA_COMPANDER1_CTL6: + return true; + } + + return wsa_is_rw_register(dev, reg); +} + static bool wsa_is_readable_register(struct device *dev, unsigned int reg) { switch (reg) { @@ -750,7 +801,6 @@ static bool wsa_is_readable_register(struct device *dev, unsigned int reg) case CDC_WSA_INTR_CTRL_PIN1_STATUS0: case CDC_WSA_INTR_CTRL_PIN2_STATUS0: case CDC_WSA_COMPANDER0_CTL6: - case CDC_WSA_COMPANDER1_CTL6: case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB: case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB: case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB: @@ -764,7 +814,17 @@ static bool wsa_is_readable_register(struct device *dev, unsigned int reg) return true; } - return wsa_is_rw_register(dev, reg); + return wsa_is_readable_register_v2_1(dev, reg); +} + +static bool wsa_is_volatile_register_v2_1(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_WSA_COMPANDER1_CTL6: + return true; + } + + return false; } static bool wsa_is_volatile_register(struct device *dev, unsigned int reg) @@ -774,7 +834,6 @@ static bool wsa_is_volatile_register(struct device *dev, unsigned int reg) case CDC_WSA_INTR_CTRL_PIN1_STATUS0: case CDC_WSA_INTR_CTRL_PIN2_STATUS0: case CDC_WSA_COMPANDER0_CTL6: - case CDC_WSA_COMPANDER1_CTL6: case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB: case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB: case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB: @@ -787,7 +846,8 @@ static bool wsa_is_volatile_register(struct device *dev, unsigned int reg) case CDC_WSA_SPLINE_ASRC1_STATUS_FIFO: return true; } - return false; + + return wsa_is_volatile_register_v2_1(dev, reg); } static const struct regmap_config wsa_regmap_config = { @@ -796,8 +856,7 @@ static const struct regmap_config wsa_regmap_config = { .val_bits = 32, /* 8 but with 32 bit read/write */ .reg_stride = 4, .cache_type = REGCACHE_FLAT, - .reg_defaults = wsa_defaults, - .num_reg_defaults = ARRAY_SIZE(wsa_defaults), + /* .reg_defaults and .num_reg_defaults set in probe() */ .max_register = WSA_MAX_OFFSET, .writeable_reg = wsa_is_writeable_register, .volatile_reg = wsa_is_volatile_register, @@ -871,11 +930,11 @@ static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, for (j = 0; j < NUM_INTERPOLATORS; j++) { int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET; inp0_sel = snd_soc_component_read_field(component, int_mux_cfg0, - CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK); - inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0, - CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK); + wsa->reg_layout->rx_intx_1_mix_inp0_sel_mask); + inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0, + wsa->reg_layout->rx_intx_1_mix_inp1_sel_mask); inp2_sel = snd_soc_component_read_field(component, int_mux_cfg1, - CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK); + wsa->reg_layout->rx_intx_1_mix_inp2_sel_mask); if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || @@ -916,7 +975,7 @@ static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai, int_mux_cfg1 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG1; for (j = 0; j < NUM_INTERPOLATORS; j++) { int_mux_cfg1_val = snd_soc_component_read_field(component, int_mux_cfg1, - CDC_WSA_RX_INTX_2_SEL_MASK); + wsa->reg_layout->rx_intx_2_sel_mask); if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) { int_fs_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL + @@ -1299,7 +1358,7 @@ static int wsa_macro_config_compander(struct snd_soc_component *component, return 0; comp_ctl0_reg = CDC_WSA_COMPANDER0_CTL0 + - (comp * WSA_MACRO_RX_COMP_OFFSET); + (comp * wsa->reg_layout->compander1_reg_offset); rx_path_cfg0_reg = CDC_WSA_RX0_RX_PATH_CFG0 + (comp * WSA_MACRO_RX_PATH_OFFSET); @@ -1345,8 +1404,8 @@ static void wsa_macro_enable_softclip_clk(struct snd_soc_component *component, int path, bool enable) { - u16 softclip_clk_reg = CDC_WSA_SOFTCLIP0_CRC + - (path * WSA_MACRO_RX_SOFTCLIP_OFFSET); + u16 softclip_clk_reg = wsa->reg_layout->softclip0_reg_base + + (path * wsa->reg_layout->softclip1_reg_offset); u8 softclip_mux_mask = (1 << path); u8 softclip_mux_value = (1 << path); @@ -1391,7 +1450,7 @@ static int wsa_macro_config_softclip(struct snd_soc_component *component, return 0; softclip_ctrl_reg = CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL + - (softclip_path * WSA_MACRO_RX_SOFTCLIP_OFFSET); + (softclip_path * wsa->reg_layout->softclip1_reg_offset); if (SND_SOC_DAPM_EVENT_ON(event)) { /* Enable Softclip clock and mux */ @@ -1416,6 +1475,7 @@ static int wsa_macro_config_softclip(struct snd_soc_component *component, static bool wsa_macro_adie_lb(struct snd_soc_component *component, int interp_idx) { + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); u16 int_mux_cfg0, int_mux_cfg1; u8 int_n_inp0, int_n_inp1, int_n_inp2; @@ -1423,19 +1483,19 @@ static bool wsa_macro_adie_lb(struct snd_soc_component *component, int_mux_cfg1 = int_mux_cfg0 + 4; int_n_inp0 = snd_soc_component_read_field(component, int_mux_cfg0, - CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK); + wsa->reg_layout->rx_intx_1_mix_inp0_sel_mask); if (int_n_inp0 == INTn_1_INP_SEL_DEC0 || int_n_inp0 == INTn_1_INP_SEL_DEC1) return true; int_n_inp1 = snd_soc_component_read_field(component, int_mux_cfg0, - CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK); + wsa->reg_layout->rx_intx_1_mix_inp1_sel_mask); if (int_n_inp1 == INTn_1_INP_SEL_DEC0 || int_n_inp1 == INTn_1_INP_SEL_DEC1) return true; int_n_inp2 = snd_soc_component_read_field(component, int_mux_cfg1, - CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK); + wsa->reg_layout->rx_intx_1_mix_inp2_sel_mask); if (int_n_inp2 == INTn_1_INP_SEL_DEC0 || int_n_inp2 == INTn_1_INP_SEL_DEC1) return true; @@ -2073,19 +2133,6 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = { SND_SOC_DAPM_MIXER("WSA RX_MIX0", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("WSA RX_MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux), - SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux), - SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux), - SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0, - 0, &rx0_mix_mux, wsa_macro_enable_mix_path, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux), - SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux), - SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux), - SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1, - 0, &rx1_mix_mux, wsa_macro_enable_mix_path, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0, wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_MIXER_E("WSA_RX INT1 MIX", SND_SOC_NOPM, 1, 0, NULL, 0, @@ -2136,6 +2183,21 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = { SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; +static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets_v2_1[] = { + SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux_v2_1), + SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux_v2_1), + SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux_v2_1), + SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0, + 0, &rx0_mix_mux_v2_1, wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux_v2_1), + SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux_v2_1), + SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux_v2_1), + SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1, + 0, &rx1_mix_mux_v2_1, wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + static const struct snd_soc_dapm_route wsa_audio_map[] = { /* VI Feedback */ {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_1", "VIINPUT_WSA"}, @@ -2281,7 +2343,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) static int wsa_macro_component_probe(struct snd_soc_component *comp) { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(comp); struct wsa_macro *wsa = snd_soc_component_get_drvdata(comp); + const struct snd_soc_dapm_widget *widgets; + unsigned int num_widgets; snd_soc_component_init_regmap(comp, wsa->regmap); @@ -2298,7 +2363,10 @@ static int wsa_macro_component_probe(struct snd_soc_component *comp) wsa_macro_set_spkr_mode(comp, WSA_MACRO_SPKR_MODE_1); - return 0; + widgets = wsa_macro_dapm_widgets_v2_1; + num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_1); + + return snd_soc_dapm_new_controls(dapm, widgets, num_widgets); } static int swclk_gate_enable(struct clk_hw *hw) @@ -2378,10 +2446,12 @@ static const struct snd_soc_component_driver wsa_macro_component_drv = { static int wsa_macro_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct reg_default *reg_defaults; + struct regmap_config *reg_config; struct wsa_macro *wsa; kernel_ulong_t flags; void __iomem *base; - int ret; + int ret, def_count; flags = (kernel_ulong_t)device_get_match_data(dev); @@ -2415,10 +2485,36 @@ static int wsa_macro_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - wsa->regmap = devm_regmap_init_mmio(dev, base, &wsa_regmap_config); + wsa->codec_version = lpass_macro_get_codec_version(); + switch (wsa->codec_version) { + default: + wsa->reg_layout = &wsa_codec_v2_1; + def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_1); + reg_defaults = devm_kmalloc_array(dev, def_count, + sizeof(*reg_defaults), + GFP_KERNEL); + if (!reg_defaults) + return -ENOMEM; + memcpy(®_defaults[0], wsa_defaults, sizeof(wsa_defaults)); + memcpy(®_defaults[ARRAY_SIZE(wsa_defaults)], + wsa_defaults_v2_1, sizeof(wsa_defaults_v2_1)); + break; + } + + reg_config = devm_kmemdup(dev, &wsa_regmap_config, + sizeof(*reg_config), GFP_KERNEL); + if (!reg_config) + return -ENOMEM; + + reg_config->reg_defaults = reg_defaults; + reg_config->num_reg_defaults = def_count; + + wsa->regmap = devm_regmap_init_mmio(dev, base, reg_config); if (IS_ERR(wsa->regmap)) return PTR_ERR(wsa->regmap); + devm_kfree(dev, reg_config); + devm_kfree(dev, reg_defaults); dev_set_drvdata(dev, wsa); wsa->dev = dev; From 727de4fbc5466c7150482b532f2b7f7e514134f3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 25 Jun 2024 18:58:47 +0200 Subject: [PATCH 203/349] ASoC: codecs: lpass-wsa-macro: Correct support for newer v2.5 version Starting with v2.5 of Qualcomm LPASS Codec, few registers in the WSA macro block change. Bring proper support for this v2.5 and newer versions, to fix second speaker playback (speaker was silent). Signed-off-by: Krzysztof Kozlowski Acked-by: Dmitry Baryshkov Link: https://patch.msgid.link/20240625-qcom-audio-wsa-second-speaker-v1-3-f65ffdfc368c@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 309 ++++++++++++++++++++++++++++- 1 file changed, 306 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 8cdf8f7f64b1..8351f0974e6a 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -216,6 +216,47 @@ #define CDC_WSA_SOFTCLIP1_CRC (0x0640) #define CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0644) +/* LPASS codec version >=2.5 register offsets */ +#define CDC_WSA_TOP_FS_UNGATE (0x00AC) +#define CDC_WSA_TOP_GRP_SEL (0x00B0) +#define CDC_WSA_TOP_FS_UNGATE2 (0x00DC) +#define CDC_2_5_WSA_COMPANDER0_CTL8 (0x05A0) +#define CDC_2_5_WSA_COMPANDER0_CTL9 (0x05A4) +#define CDC_2_5_WSA_COMPANDER0_CTL10 (0x05A8) +#define CDC_2_5_WSA_COMPANDER0_CTL11 (0x05AC) +#define CDC_2_5_WSA_COMPANDER0_CTL12 (0x05B0) +#define CDC_2_5_WSA_COMPANDER0_CTL13 (0x05B4) +#define CDC_2_5_WSA_COMPANDER0_CTL14 (0x05B8) +#define CDC_2_5_WSA_COMPANDER0_CTL15 (0x05BC) +#define CDC_2_5_WSA_COMPANDER0_CTL16 (0x05C0) +#define CDC_2_5_WSA_COMPANDER0_CTL17 (0x05C4) +#define CDC_2_5_WSA_COMPANDER0_CTL18 (0x05C8) +#define CDC_2_5_WSA_COMPANDER0_CTL19 (0x05CC) +#define CDC_2_5_WSA_COMPANDER1_CTL0 (0x05E0) +#define CDC_2_5_WSA_COMPANDER1_CTL1 (0x05E4) +#define CDC_2_5_WSA_COMPANDER1_CTL2 (0x05E8) +#define CDC_2_5_WSA_COMPANDER1_CTL3 (0x05EC) +#define CDC_2_5_WSA_COMPANDER1_CTL4 (0x05F0) +#define CDC_2_5_WSA_COMPANDER1_CTL5 (0x05F4) +#define CDC_2_5_WSA_COMPANDER1_CTL6 (0x05F8) +#define CDC_2_5_WSA_COMPANDER1_CTL7 (0x05FC) +#define CDC_2_5_WSA_COMPANDER1_CTL8 (0x0600) +#define CDC_2_5_WSA_COMPANDER1_CTL9 (0x0604) +#define CDC_2_5_WSA_COMPANDER1_CTL10 (0x0608) +#define CDC_2_5_WSA_COMPANDER1_CTL11 (0x060C) +#define CDC_2_5_WSA_COMPANDER1_CTL12 (0x0610) +#define CDC_2_5_WSA_COMPANDER1_CTL13 (0x0614) +#define CDC_2_5_WSA_COMPANDER1_CTL14 (0x0618) +#define CDC_2_5_WSA_COMPANDER1_CTL15 (0x061C) +#define CDC_2_5_WSA_COMPANDER1_CTL16 (0x0620) +#define CDC_2_5_WSA_COMPANDER1_CTL17 (0x0624) +#define CDC_2_5_WSA_COMPANDER1_CTL18 (0x0628) +#define CDC_2_5_WSA_COMPANDER1_CTL19 (0x062C) +#define CDC_2_5_WSA_SOFTCLIP0_CRC (0x0640) +#define CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL (0x0644) +#define CDC_2_5_WSA_SOFTCLIP1_CRC (0x0660) +#define CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0664) + #define WSA_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) @@ -387,16 +428,34 @@ static const struct wsa_reg_layout wsa_codec_v2_1 = { .softclip1_reg_offset = 0x40, }; +static const struct wsa_reg_layout wsa_codec_v2_5 = { + .rx_intx_1_mix_inp0_sel_mask = GENMASK(3, 0), + .rx_intx_1_mix_inp1_sel_mask = GENMASK(7, 4), + .rx_intx_1_mix_inp2_sel_mask = GENMASK(7, 4), + .rx_intx_2_sel_mask = GENMASK(3, 0), + .compander1_reg_offset = 0x60, + .softclip0_reg_base = 0x640, + .softclip1_reg_offset = 0x20, +}; + static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400); static const char *const rx_text_v2_1[] = { "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "DEC0", "DEC1" }; +static const char *const rx_text_v2_5[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8", "DEC0", "DEC1" +}; + static const char *const rx_mix_text_v2_1[] = { "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1" }; +static const char *const rx_mix_text_v2_5[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8" +}; + static const char *const rx_mix_ec_text[] = { "ZERO", "RX_MIX_TX0", "RX_MIX_TX1" }; @@ -434,6 +493,22 @@ static const struct soc_enum rx0_mix_chain_enum_v2_1 = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, 0, 5, rx_mix_text_v2_1); +static const struct soc_enum rx0_prim_inp0_chain_enum_v2_5 = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, + 0, 12, rx_text_v2_5); + +static const struct soc_enum rx0_prim_inp1_chain_enum_v2_5 = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, + 4, 12, rx_text_v2_5); + +static const struct soc_enum rx0_prim_inp2_chain_enum_v2_5 = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, + 4, 12, rx_text_v2_5); + +static const struct soc_enum rx0_mix_chain_enum_v2_5 = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, + 0, 10, rx_mix_text_v2_5); + static const struct soc_enum rx0_sidetone_mix_enum = SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text); @@ -449,6 +524,18 @@ static const struct snd_kcontrol_new rx0_prim_inp2_mux_v2_1 = static const struct snd_kcontrol_new rx0_mix_mux_v2_1 = SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2_1); +static const struct snd_kcontrol_new rx0_prim_inp0_mux_v2_5 = + SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum_v2_5); + +static const struct snd_kcontrol_new rx0_prim_inp1_mux_v2_5 = + SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum_v2_5); + +static const struct snd_kcontrol_new rx0_prim_inp2_mux_v2_5 = + SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum_v2_5); + +static const struct snd_kcontrol_new rx0_mix_mux_v2_5 = + SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2_5); + static const struct snd_kcontrol_new rx0_sidetone_mix_mux = SOC_DAPM_ENUM("WSA_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum); @@ -469,6 +556,22 @@ static const struct soc_enum rx1_mix_chain_enum_v2_1 = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, 0, 5, rx_mix_text_v2_1); +static const struct soc_enum rx1_prim_inp0_chain_enum_v2_5 = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, + 0, 12, rx_text_v2_5); + +static const struct soc_enum rx1_prim_inp1_chain_enum_v2_5 = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, + 4, 12, rx_text_v2_5); + +static const struct soc_enum rx1_prim_inp2_chain_enum_v2_5 = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, + 4, 12, rx_text_v2_5); + +static const struct soc_enum rx1_mix_chain_enum_v2_5 = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, + 0, 10, rx_mix_text_v2_5); + static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2_1 = SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2_1); @@ -481,6 +584,18 @@ static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2_1 = static const struct snd_kcontrol_new rx1_mix_mux_v2_1 = SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2_1); +static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2_5 = + SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2_5); + +static const struct snd_kcontrol_new rx1_prim_inp1_mux_v2_5 = + SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum_v2_5); + +static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2_5 = + SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum_v2_5); + +static const struct snd_kcontrol_new rx1_mix_mux_v2_5 = + SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2_5); + static const struct soc_enum rx_mix_ec0_enum = SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, 0, 3, rx_mix_ec_text); @@ -629,6 +744,56 @@ static const struct reg_default wsa_defaults_v2_1[] = { { CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38}, }; +static const struct reg_default wsa_defaults_v2_5[] = { + { CDC_WSA_TOP_FS_UNGATE, 0xFF}, + { CDC_WSA_TOP_GRP_SEL, 0x08}, + { CDC_WSA_TOP_FS_UNGATE2, 0x1F}, + { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x04}, + { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x02}, + { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x04}, + { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x02}, + { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x04}, + { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x02}, + { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x04}, + { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x02}, + { CDC_2_5_WSA_COMPANDER0_CTL8, 0x00}, + { CDC_2_5_WSA_COMPANDER0_CTL9, 0x00}, + { CDC_2_5_WSA_COMPANDER0_CTL10, 0x06}, + { CDC_2_5_WSA_COMPANDER0_CTL11, 0x12}, + { CDC_2_5_WSA_COMPANDER0_CTL12, 0x1E}, + { CDC_2_5_WSA_COMPANDER0_CTL13, 0x24}, + { CDC_2_5_WSA_COMPANDER0_CTL14, 0x24}, + { CDC_2_5_WSA_COMPANDER0_CTL15, 0x24}, + { CDC_2_5_WSA_COMPANDER0_CTL16, 0x00}, + { CDC_2_5_WSA_COMPANDER0_CTL17, 0x24}, + { CDC_2_5_WSA_COMPANDER0_CTL18, 0x2A}, + { CDC_2_5_WSA_COMPANDER0_CTL19, 0x16}, + { CDC_2_5_WSA_COMPANDER1_CTL0, 0x60}, + { CDC_2_5_WSA_COMPANDER1_CTL1, 0xDB}, + { CDC_2_5_WSA_COMPANDER1_CTL2, 0xFF}, + { CDC_2_5_WSA_COMPANDER1_CTL3, 0x35}, + { CDC_2_5_WSA_COMPANDER1_CTL4, 0xFF}, + { CDC_2_5_WSA_COMPANDER1_CTL5, 0x00}, + { CDC_2_5_WSA_COMPANDER1_CTL6, 0x01}, + { CDC_2_5_WSA_COMPANDER1_CTL7, 0x28}, + { CDC_2_5_WSA_COMPANDER1_CTL8, 0x00}, + { CDC_2_5_WSA_COMPANDER1_CTL9, 0x00}, + { CDC_2_5_WSA_COMPANDER1_CTL10, 0x06}, + { CDC_2_5_WSA_COMPANDER1_CTL11, 0x12}, + { CDC_2_5_WSA_COMPANDER1_CTL12, 0x1E}, + { CDC_2_5_WSA_COMPANDER1_CTL13, 0x24}, + { CDC_2_5_WSA_COMPANDER1_CTL14, 0x24}, + { CDC_2_5_WSA_COMPANDER1_CTL15, 0x24}, + { CDC_2_5_WSA_COMPANDER1_CTL16, 0x00}, + { CDC_2_5_WSA_COMPANDER1_CTL17, 0x24}, + { CDC_2_5_WSA_COMPANDER1_CTL18, 0x2A}, + { CDC_2_5_WSA_COMPANDER1_CTL19, 0x16}, + { CDC_2_5_WSA_SOFTCLIP0_CRC, 0x00}, + { CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38}, + { CDC_2_5_WSA_SOFTCLIP1_CRC, 0x00}, + { CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38}, +}; + static bool wsa_is_wronly_register(struct device *dev, unsigned int reg) { @@ -662,8 +827,57 @@ static bool wsa_is_rw_register_v2_1(struct device *dev, unsigned int reg) return false; } +static bool wsa_is_rw_register_v2_5(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_WSA_TOP_FS_UNGATE: + case CDC_WSA_TOP_GRP_SEL: + case CDC_WSA_TOP_FS_UNGATE2: + case CDC_2_5_WSA_COMPANDER0_CTL8: + case CDC_2_5_WSA_COMPANDER0_CTL9: + case CDC_2_5_WSA_COMPANDER0_CTL10: + case CDC_2_5_WSA_COMPANDER0_CTL11: + case CDC_2_5_WSA_COMPANDER0_CTL12: + case CDC_2_5_WSA_COMPANDER0_CTL13: + case CDC_2_5_WSA_COMPANDER0_CTL14: + case CDC_2_5_WSA_COMPANDER0_CTL15: + case CDC_2_5_WSA_COMPANDER0_CTL16: + case CDC_2_5_WSA_COMPANDER0_CTL17: + case CDC_2_5_WSA_COMPANDER0_CTL18: + case CDC_2_5_WSA_COMPANDER0_CTL19: + case CDC_2_5_WSA_COMPANDER1_CTL0: + case CDC_2_5_WSA_COMPANDER1_CTL1: + case CDC_2_5_WSA_COMPANDER1_CTL2: + case CDC_2_5_WSA_COMPANDER1_CTL3: + case CDC_2_5_WSA_COMPANDER1_CTL4: + case CDC_2_5_WSA_COMPANDER1_CTL5: + case CDC_2_5_WSA_COMPANDER1_CTL7: + case CDC_2_5_WSA_COMPANDER1_CTL8: + case CDC_2_5_WSA_COMPANDER1_CTL9: + case CDC_2_5_WSA_COMPANDER1_CTL10: + case CDC_2_5_WSA_COMPANDER1_CTL11: + case CDC_2_5_WSA_COMPANDER1_CTL12: + case CDC_2_5_WSA_COMPANDER1_CTL13: + case CDC_2_5_WSA_COMPANDER1_CTL14: + case CDC_2_5_WSA_COMPANDER1_CTL15: + case CDC_2_5_WSA_COMPANDER1_CTL16: + case CDC_2_5_WSA_COMPANDER1_CTL17: + case CDC_2_5_WSA_COMPANDER1_CTL18: + case CDC_2_5_WSA_COMPANDER1_CTL19: + case CDC_2_5_WSA_SOFTCLIP0_CRC: + case CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL: + case CDC_2_5_WSA_SOFTCLIP1_CRC: + case CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL: + return true; + } + + return false; +} + static bool wsa_is_rw_register(struct device *dev, unsigned int reg) { + struct wsa_macro *wsa = dev_get_drvdata(dev); + switch (reg) { case CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL: case CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL: @@ -768,6 +982,9 @@ static bool wsa_is_rw_register(struct device *dev, unsigned int reg) return true; } + if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5) + return wsa_is_rw_register_v2_5(dev, reg); + return wsa_is_rw_register_v2_1(dev, reg); } @@ -792,8 +1009,20 @@ static bool wsa_is_readable_register_v2_1(struct device *dev, unsigned int reg) return wsa_is_rw_register(dev, reg); } +static bool wsa_is_readable_register_v2_5(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_2_5_WSA_COMPANDER1_CTL6: + return true; + } + + return wsa_is_rw_register(dev, reg); +} + static bool wsa_is_readable_register(struct device *dev, unsigned int reg) { + struct wsa_macro *wsa = dev_get_drvdata(dev); + switch (reg) { case CDC_WSA_INTR_CTRL_CLR_COMMIT: case CDC_WSA_INTR_CTRL_PIN1_CLEAR0: @@ -814,6 +1043,9 @@ static bool wsa_is_readable_register(struct device *dev, unsigned int reg) return true; } + if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5) + return wsa_is_readable_register_v2_5(dev, reg); + return wsa_is_readable_register_v2_1(dev, reg); } @@ -827,8 +1059,20 @@ static bool wsa_is_volatile_register_v2_1(struct device *dev, unsigned int reg) return false; } +static bool wsa_is_volatile_register_v2_5(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_2_5_WSA_COMPANDER1_CTL6: + return true; + } + + return false; +} + static bool wsa_is_volatile_register(struct device *dev, unsigned int reg) { + struct wsa_macro *wsa = dev_get_drvdata(dev); + /* Update volatile list for rx/tx macros */ switch (reg) { case CDC_WSA_INTR_CTRL_PIN1_STATUS0: @@ -847,6 +1091,9 @@ static bool wsa_is_volatile_register(struct device *dev, unsigned int reg) return true; } + if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5) + return wsa_is_volatile_register_v2_5(dev, reg); + return wsa_is_volatile_register_v2_1(dev, reg); } @@ -2198,6 +2445,21 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets_v2_1[] = { SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; +static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets_v2_5[] = { + SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux_v2_5), + SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux_v2_5), + SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux_v2_5), + SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0, + 0, &rx0_mix_mux_v2_5, wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux_v2_5), + SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux_v2_5), + SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux_v2_5), + SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1, + 0, &rx1_mix_mux_v2_5, wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + static const struct snd_soc_dapm_route wsa_audio_map[] = { /* VI Feedback */ {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_1", "VIINPUT_WSA"}, @@ -2363,8 +2625,25 @@ static int wsa_macro_component_probe(struct snd_soc_component *comp) wsa_macro_set_spkr_mode(comp, WSA_MACRO_SPKR_MODE_1); - widgets = wsa_macro_dapm_widgets_v2_1; - num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_1); + switch (wsa->codec_version) { + case LPASS_CODEC_VERSION_1_0: + case LPASS_CODEC_VERSION_1_1: + case LPASS_CODEC_VERSION_1_2: + case LPASS_CODEC_VERSION_2_0: + case LPASS_CODEC_VERSION_2_1: + widgets = wsa_macro_dapm_widgets_v2_1; + num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_1); + break; + case LPASS_CODEC_VERSION_2_5: + case LPASS_CODEC_VERSION_2_6: + case LPASS_CODEC_VERSION_2_7: + case LPASS_CODEC_VERSION_2_8: + widgets = wsa_macro_dapm_widgets_v2_5; + num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_5); + break; + default: + return -EINVAL; + } return snd_soc_dapm_new_controls(dapm, widgets, num_widgets); } @@ -2487,7 +2766,11 @@ static int wsa_macro_probe(struct platform_device *pdev) wsa->codec_version = lpass_macro_get_codec_version(); switch (wsa->codec_version) { - default: + case LPASS_CODEC_VERSION_1_0: + case LPASS_CODEC_VERSION_1_1: + case LPASS_CODEC_VERSION_1_2: + case LPASS_CODEC_VERSION_2_0: + case LPASS_CODEC_VERSION_2_1: wsa->reg_layout = &wsa_codec_v2_1; def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_1); reg_defaults = devm_kmalloc_array(dev, def_count, @@ -2499,6 +2782,26 @@ static int wsa_macro_probe(struct platform_device *pdev) memcpy(®_defaults[ARRAY_SIZE(wsa_defaults)], wsa_defaults_v2_1, sizeof(wsa_defaults_v2_1)); break; + + case LPASS_CODEC_VERSION_2_5: + case LPASS_CODEC_VERSION_2_6: + case LPASS_CODEC_VERSION_2_7: + case LPASS_CODEC_VERSION_2_8: + wsa->reg_layout = &wsa_codec_v2_5; + def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_5); + reg_defaults = devm_kmalloc_array(dev, def_count, + sizeof(*reg_defaults), + GFP_KERNEL); + if (!reg_defaults) + return -ENOMEM; + memcpy(®_defaults[0], wsa_defaults, sizeof(wsa_defaults)); + memcpy(®_defaults[ARRAY_SIZE(wsa_defaults)], + wsa_defaults_v2_5, sizeof(wsa_defaults_v2_5)); + break; + + default: + dev_err(wsa->dev, "Unsupported Codec version (%d)\n", wsa->codec_version); + return -EINVAL; } reg_config = devm_kmemdup(dev, &wsa_regmap_config, From ebc1a54051b58d1aa3a8855faac8bf16b88b8af7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 25 Jun 2024 18:57:35 +0200 Subject: [PATCH 204/349] ASoC: codecs: lpass-macro: Gracefully handle unknown version Qualcomm LPASS macro codec driver parses registers in order to detect version of the codec. It recognizes codecs v2.0 - v2.8, however we know that there are earlier versions and 'enum lpass_codec_version' has also v1.0, v1.1 and v1.2. If by any chance we run on unrecognized version, driver will use random value from the stack as the codec version. Fix it by mapping such cases to an enum of value 0: LPASS_CODEC_VERSION_UNKNOWN. Fixes: 378918d59181 ("ASoC: codecs: lpass-macro: add helpers to get codec version") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20240625165736.722106-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-macro-common.h | 3 ++- sound/soc/codecs/lpass-va-macro.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h index f6f1bfe8eb77..94697d0ba8c9 100644 --- a/sound/soc/codecs/lpass-macro-common.h +++ b/sound/soc/codecs/lpass-macro-common.h @@ -19,7 +19,8 @@ enum lpass_version { }; enum lpass_codec_version { - LPASS_CODEC_VERSION_1_0 = 1, + LPASS_CODEC_VERSION_UNKNOWN, + LPASS_CODEC_VERSION_1_0, LPASS_CODEC_VERSION_1_1, LPASS_CODEC_VERSION_1_2, LPASS_CODEC_VERSION_2_0, diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index b0006f4ce8a2..b852cc7ffad9 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1463,7 +1463,8 @@ undefined_rate: static void va_macro_set_lpass_codec_version(struct va_macro *va) { - int core_id_0 = 0, core_id_1 = 0, core_id_2 = 0, version; + int core_id_0 = 0, core_id_1 = 0, core_id_2 = 0; + int version = LPASS_CODEC_VERSION_UNKNOWN; regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_0, &core_id_0); regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_1, &core_id_1); From 06462d6f3fb3c445b5abac7b134d9fe9e361113f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 25 Jun 2024 18:57:36 +0200 Subject: [PATCH 205/349] ASoC: codecs: lpass-macro: Use enum for handling codec version Replace 'int' with proper 'enum lpass_codec_version' in every place which handles the parsed codec version (not raw register values!) to be explicit about contents of the variable. This makes code easier to read and compilers could check missing switch cases. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20240625165736.722106-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-macro-common.c | 8 ++++---- sound/soc/codecs/lpass-macro-common.h | 4 ++-- sound/soc/codecs/lpass-rx-macro.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c index 8b038a99a8f9..6e3b8d0897dd 100644 --- a/sound/soc/codecs/lpass-macro-common.c +++ b/sound/soc/codecs/lpass-macro-common.c @@ -12,7 +12,7 @@ #include "lpass-macro-common.h" static DEFINE_MUTEX(lpass_codec_mutex); -static int lpass_codec_version; +static enum lpass_codec_version lpass_codec_version; struct lpass_macro *lpass_macro_pds_init(struct device *dev) { @@ -69,7 +69,7 @@ void lpass_macro_pds_exit(struct lpass_macro *pds) } EXPORT_SYMBOL_GPL(lpass_macro_pds_exit); -void lpass_macro_set_codec_version(int version) +void lpass_macro_set_codec_version(enum lpass_codec_version version) { mutex_lock(&lpass_codec_mutex); lpass_codec_version = version; @@ -77,9 +77,9 @@ void lpass_macro_set_codec_version(int version) } EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version); -int lpass_macro_get_codec_version(void) +enum lpass_codec_version lpass_macro_get_codec_version(void) { - int ver; + enum lpass_codec_version ver; mutex_lock(&lpass_codec_mutex); ver = lpass_codec_version; diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h index 94697d0ba8c9..3aa9737f2737 100644 --- a/sound/soc/codecs/lpass-macro-common.h +++ b/sound/soc/codecs/lpass-macro-common.h @@ -38,8 +38,8 @@ struct lpass_macro { struct lpass_macro *lpass_macro_pds_init(struct device *dev); void lpass_macro_pds_exit(struct lpass_macro *pds); -void lpass_macro_set_codec_version(int version); -int lpass_macro_get_codec_version(void); +void lpass_macro_set_codec_version(enum lpass_codec_version version); +enum lpass_codec_version lpass_macro_get_codec_version(void); static inline const char *lpass_macro_get_codec_version_string(int version) { diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 8af86509a3ff..9c4f0763675d 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -642,7 +642,7 @@ struct rx_macro { int rx_mclk_users; int clsh_users; int rx_mclk_cnt; - int codec_version; + enum lpass_codec_version codec_version; int rxn_reg_stride; bool is_ear_mode_on; bool hph_pwr_mode; From fafc20ded3f4659873c83c2af6d389983d480994 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 12 Jun 2024 06:02:26 +0000 Subject: [PATCH 206/349] ASoC: audio-graph-port: add link-trigger-order Sound Card need to consider/adjust HW control ordering based on the combination of CPU/Codec. The controlling feature is already supported on ASoC, but Simple Audio Card / Audio Graph Card still not support it. Let's support it. Cc: Maxim Kochetkov Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87sexizojx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-port.yaml | 9 +++++++ include/dt-bindings/sound/audio-graph.h | 26 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 include/dt-bindings/sound/audio-graph.h diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index 28b27e7e45de..d1cbfc5edd3a 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -25,6 +25,15 @@ definitions: capture-only: description: port connection used only for capture $ref: /schemas/types.yaml#/definitions/flag + link-trigger-order: + description: trigger order for both start/stop + $ref: /schemas/types.yaml#/definitions/uint32-array + link-trigger-order-start: + description: trigger order for start + $ref: /schemas/types.yaml#/definitions/uint32-array + link-trigger-order-stop: + description: trigger order for stop + $ref: /schemas/types.yaml#/definitions/uint32-array endpoint-base: allOf: diff --git a/include/dt-bindings/sound/audio-graph.h b/include/dt-bindings/sound/audio-graph.h new file mode 100644 index 000000000000..bdb70c6b7332 --- /dev/null +++ b/include/dt-bindings/sound/audio-graph.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * audio-graph.h + * + * Copyright (c) 2024 Kuninori Morimoto + */ +#ifndef __AUDIO_GRAPH_H +#define __AUDIO_GRAPH_H + +/* + * used in + * link-trigger-order + * link-trigger-order-start + * link-trigger-order-stop + * + * default is + * link-trigger-order = ; + */ +#define SND_SOC_TRIGGER_LINK 0 +#define SND_SOC_TRIGGER_COMPONENT 1 +#define SND_SOC_TRIGGER_DAI 2 +#define SND_SOC_TRIGGER_SIZE 3 /* shoud be last */ + +#endif /* __AUDIO_GRAPH_H */ From 5d9cacdccf17bd33dac3ea378324650159c2a863 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 12 Jun 2024 06:02:33 +0000 Subject: [PATCH 207/349] ASoC: simple-card-utils: add link-trigger-order support Some Sound Card might need special trigger ordering which is based on CPU/Codec connection. It is already supported on ASoC, but Simple Audio Card / Audio Graph Card still not support it. Let's support it. Cc: Maxim Kochetkov Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87r0d2zojq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 4 ++ sound/soc/generic/simple-card-utils.c | 71 +++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 0a6435ac5c5f..3360d9eab068 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -199,6 +199,10 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep, void graph_util_parse_link_direction(struct device_node *np, bool *is_playback_only, bool *is_capture_only); +void graph_util_parse_trigger_order(struct simple_util_priv *priv, + struct device_node *np, + enum snd_soc_trigger_order *trigger_start, + enum snd_soc_trigger_order *trigger_stop); #ifdef DEBUG static inline void simple_util_debug_dai(struct simple_util_priv *priv, diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index dcd0569157ce..a18de86b3c88 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -4,6 +4,7 @@ // // Copyright (c) 2016 Kuninori Morimoto +#include #include #include #include @@ -1156,6 +1157,76 @@ void graph_util_parse_link_direction(struct device_node *np, } EXPORT_SYMBOL_GPL(graph_util_parse_link_direction); +static enum snd_soc_trigger_order +__graph_util_parse_trigger_order(struct simple_util_priv *priv, + struct device_node *np, + const char *prop) +{ + u32 val[SND_SOC_TRIGGER_SIZE]; + int ret; + + ret = of_property_read_u32_array(np, prop, val, SND_SOC_TRIGGER_SIZE); + if (ret == 0) { + struct device *dev = simple_priv_to_dev(priv); + u32 order = (val[0] << 8) + + (val[1] << 4) + + (val[2]); + + switch (order) { + case (SND_SOC_TRIGGER_LINK << 8) + + (SND_SOC_TRIGGER_COMPONENT << 4) + + (SND_SOC_TRIGGER_DAI): + return SND_SOC_TRIGGER_ORDER_DEFAULT; + + case (SND_SOC_TRIGGER_LINK << 8) + + (SND_SOC_TRIGGER_DAI << 4) + + (SND_SOC_TRIGGER_COMPONENT): + return SND_SOC_TRIGGER_ORDER_LDC; + + default: + dev_err(dev, "unsupported trigger order [0x%x]\n", order); + } + } + + /* SND_SOC_TRIGGER_ORDER_MAX means error */ + return SND_SOC_TRIGGER_ORDER_MAX; +} + +void graph_util_parse_trigger_order(struct simple_util_priv *priv, + struct device_node *np, + enum snd_soc_trigger_order *trigger_start, + enum snd_soc_trigger_order *trigger_stop) +{ + static enum snd_soc_trigger_order order; + + /* + * We can use it like below + * + * #include + * + * link-trigger-order = ; + */ + + order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order"); + if (order < SND_SOC_TRIGGER_ORDER_MAX) { + *trigger_start = order; + *trigger_stop = order; + } + + order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-start"); + if (order < SND_SOC_TRIGGER_ORDER_MAX) + *trigger_start = order; + + order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-stop"); + if (order < SND_SOC_TRIGGER_ORDER_MAX) + *trigger_stop = order; + + return; +} +EXPORT_SYMBOL_GPL(graph_util_parse_trigger_order); + /* Module information */ MODULE_AUTHOR("Kuninori Morimoto "); MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); From 8696d732f1c804312d44806242d4a91c49a7a154 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 12 Jun 2024 06:02:39 +0000 Subject: [PATCH 208/349] ASoC: simple-audio-card: add link-trigger-order support Some Sound Card might need special trigger ordering which is based on CPU/Codec connection. It is already supported on ASoC, but Simple Audio Card still not yet support it. Let's support it. Cc: Maxim Kochetkov Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87plsmzojk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 2de5e6efe947..edbb6322e9be 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -176,6 +176,8 @@ static int simple_link_init(struct simple_util_priv *priv, struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *node = of_get_parent(cpu); + enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT; + enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT; bool playback_only = 0, capture_only = 0; int ret; @@ -198,9 +200,17 @@ static int simple_link_init(struct simple_util_priv *priv, of_property_read_u32(codec, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(codec, PREFIX "mclk-fs", &dai_props->mclk_fs); + graph_util_parse_trigger_order(priv, top, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, node, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, codec, &trigger_start, &trigger_stop); + dai_link->playback_only = playback_only; dai_link->capture_only = capture_only; + dai_link->trigger_start = trigger_start; + dai_link->trigger_stop = trigger_stop; + dai_link->init = simple_util_dai_init; dai_link->ops = &simple_ops; From 4d4125d8f5e19476c006014d5530b8127ed5703f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 12 Jun 2024 06:02:46 +0000 Subject: [PATCH 209/349] ASoC: audio-graph-card: add link-trigger-order support Some Sound Card might need special trigger ordering which is based on CPU/Codec connection. It is already supported on ASoC, but Audio Graph Card still not yet support it. Let's support it. Cc: Maxim Kochetkov Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87o786zojd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 7b981aa8690a..acf7d92d21e6 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -143,6 +143,8 @@ static int graph_link_init(struct simple_util_priv *priv, struct device_node *port_codec = ep_to_port(ep_codec); struct device_node *ports_cpu = port_to_ports(port_cpu); struct device_node *ports_codec = port_to_ports(port_codec); + enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT; + enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT; bool playback_only = 0, capture_only = 0; int ret; @@ -165,9 +167,20 @@ static int graph_link_init(struct simple_util_priv *priv, of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs); + graph_util_parse_trigger_order(priv, top, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ports_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ports_codec, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ep_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ep_codec, &trigger_start, &trigger_stop); + dai_link->playback_only = playback_only; dai_link->capture_only = capture_only; + dai_link->trigger_start = trigger_start; + dai_link->trigger_stop = trigger_stop; + dai_link->init = simple_util_dai_init; dai_link->ops = &graph_ops; if (priv->ops) From e64343fa57335662b555477d9ddebd8285db2b66 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 12 Jun 2024 06:02:52 +0000 Subject: [PATCH 210/349] ASoC: audio-graph-card2: add link-trigger-order support Some Sound Card might need special trigger ordering which is based on CPU/Codec connection. It is already supported on ASoC, but Audio Graph Card2 still not yet support it. Let's support it. Cc: Maxim Kochetkov Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87msnqzoj8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index be5a4ebfddd4..93d9d045587b 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -759,6 +759,8 @@ static void graph_link_init(struct simple_util_priv *priv, struct device_node *ports_cpu, *ports_codec; unsigned int daifmt = 0, daiclk = 0; bool playback_only = 0, capture_only = 0; + enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT; + enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT; unsigned int bit_frame = 0; of_node_get(port_cpu); @@ -806,6 +808,14 @@ static void graph_link_init(struct simple_util_priv *priv, of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs); + graph_util_parse_trigger_order(priv, lnk, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ports_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ports_codec, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ep_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ep_codec, &trigger_start, &trigger_stop); + /* * convert bit_frame * We need to flip clock_provider if it was CPU node, @@ -818,6 +828,9 @@ static void graph_link_init(struct simple_util_priv *priv, dai_link->playback_only = playback_only; dai_link->capture_only = capture_only; + dai_link->trigger_start = trigger_start; + dai_link->trigger_stop = trigger_stop; + dai_link->dai_fmt = daifmt | daiclk; dai_link->init = simple_util_dai_init; dai_link->ops = &graph_ops; From 15c958390460f964ec707ae6c5d1843638ebfe69 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 12 Jun 2024 14:40:50 +0800 Subject: [PATCH 211/349] ASoC: fsl_sai: Add separate DAI for transmitter and receiver The transmitter and receiver part of the SAI interface need to be configured with different master/slave mode, especially to work with the audiomix module. +-------+ +-----------+ | SAI1 | --TX--> | | | | <--RX-- | | +-------+ | | | AUDIOMIX | +-------+ | | | SAI2 | --TX--> | | +-------+ +-----------+ The SAI1 TX is in master mode, but SAI1 RX is in slave mode. So add another two DAIs for TX and RX separately. but only defined fsl_sai_set_dai_fmt_tx() and fsl_sai_set_dai_fmt_rx() ops function for current case, in the future, the other ops function for TX and RX can be defined if required. Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/1718174452-17596-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 141 +++++++++++++++++++++++++++++----------- sound/soc/fsl/fsl_sai.h | 4 +- 2 files changed, 104 insertions(+), 41 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 0e2c31439670..d03b0172b8ad 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -357,18 +357,18 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_BP_FP: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; val_cr4 |= FSL_SAI_CR4_FSD_MSTR; - sai->is_consumer_mode = false; + sai->is_consumer_mode[tx] = false; break; case SND_SOC_DAIFMT_BC_FC: - sai->is_consumer_mode = true; + sai->is_consumer_mode[tx] = true; break; case SND_SOC_DAIFMT_BP_FC: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; - sai->is_consumer_mode = false; + sai->is_consumer_mode[tx] = false; break; case SND_SOC_DAIFMT_BC_FP: val_cr4 |= FSL_SAI_CR4_FSD_MSTR; - sai->is_consumer_mode = true; + sai->is_consumer_mode[tx] = true; break; default: return -EINVAL; @@ -400,6 +400,16 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) return ret; } +static int fsl_sai_set_dai_fmt_tx(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, true); +} + +static int fsl_sai_set_dai_fmt_rx(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, false); +} + static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); @@ -412,7 +422,7 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) bool support_1_1_ratio = sai->verid.version >= 0x0301; /* Don't apply to consumer mode */ - if (sai->is_consumer_mode) + if (sai->is_consumer_mode[tx]) return 0; /* @@ -575,7 +585,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, } } - if (!sai->is_consumer_mode) { + if (!sai->is_consumer_mode[tx]) { ret = fsl_sai_set_bclk(cpu_dai, tx, bclk); if (ret) return ret; @@ -613,7 +623,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, * RCR5(TCR5) for playback(capture), or there will be sync error. */ - if (!sai->is_consumer_mode && fsl_sai_dir_is_synced(sai, adir)) { + if (!sai->is_consumer_mode[tx] && fsl_sai_dir_is_synced(sai, adir)) { regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | FSL_SAI_CR4_CHMOD_MASK, @@ -683,7 +693,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, * FSD_MSTR bit for this specific case. */ if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && - !sai->is_consumer_mode) + !sai->is_consumer_mode[tx]) regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_FSD_MSTR, 0); @@ -697,7 +707,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, /* Enable FSD_MSTR after configuring word width */ if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && - !sai->is_consumer_mode) + !sai->is_consumer_mode[tx]) regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR); @@ -720,8 +730,8 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), FSL_SAI_CR3_TRCE_MASK, 0); - if (!sai->is_consumer_mode && - sai->mclk_streams & BIT(substream->stream)) { + if (!sai->is_consumer_mode[tx] && + sai->mclk_streams & BIT(substream->stream)) { clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); sai->mclk_streams &= ~BIT(substream->stream); } @@ -759,7 +769,7 @@ static void fsl_sai_config_disable(struct fsl_sai *sai, int dir) * This is a hardware bug, and will be fix in the * next sai version. */ - if (!sai->is_consumer_mode) { + if (!sai->is_consumer_mode[tx]) { /* Software Reset */ regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); /* Clear SR bit to finish the reset */ @@ -914,6 +924,30 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { .startup = fsl_sai_startup, }; +static const struct snd_soc_dai_ops fsl_sai_pcm_dai_tx_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_tx, + .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 const struct snd_soc_dai_ops fsl_sai_pcm_dai_rx_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_rx, + .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); @@ -931,26 +965,55 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component) return 0; } -static struct snd_soc_dai_driver fsl_sai_dai_template = { - .playback = { - .stream_name = "CPU-Playback", - .channels_min = 1, - .channels_max = 32, - .rate_min = 8000, - .rate_max = 2822400, - .rates = SNDRV_PCM_RATE_KNOT, - .formats = FSL_SAI_FORMATS, +static struct snd_soc_dai_driver fsl_sai_dai_template[] = { + { + .name = "sai-tx-rx", + .playback = { + .stream_name = "CPU-Playback", + .channels_min = 1, + .channels_max = 32, + .rate_min = 8000, + .rate_max = 2822400, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = FSL_SAI_FORMATS, + }, + .capture = { + .stream_name = "CPU-Capture", + .channels_min = 1, + .channels_max = 32, + .rate_min = 8000, + .rate_max = 2822400, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = FSL_SAI_FORMATS, + }, + .ops = &fsl_sai_pcm_dai_ops, }, - .capture = { - .stream_name = "CPU-Capture", - .channels_min = 1, - .channels_max = 32, - .rate_min = 8000, - .rate_max = 2822400, - .rates = SNDRV_PCM_RATE_KNOT, - .formats = FSL_SAI_FORMATS, + { + .name = "sai-tx", + .playback = { + .stream_name = "CPU-Playback", + .channels_min = 1, + .channels_max = 32, + .rate_min = 8000, + .rate_max = 2822400, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = FSL_SAI_FORMATS, + }, + .ops = &fsl_sai_pcm_dai_tx_ops, + }, + { + .name = "sai-rx", + .capture = { + .stream_name = "CPU-Capture", + .channels_min = 1, + .channels_max = 32, + .rate_min = 8000, + .rate_max = 2822400, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = FSL_SAI_FORMATS, + }, + .ops = &fsl_sai_pcm_dai_rx_ops, }, - .ops = &fsl_sai_pcm_dai_ops, }; static const struct snd_soc_component_driver fsl_component = { @@ -1399,15 +1462,15 @@ static int fsl_sai_probe(struct platform_device *pdev) return ret; } - memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template, - sizeof(fsl_sai_dai_template)); + memcpy(&sai->cpu_dai_drv, fsl_sai_dai_template, + sizeof(*fsl_sai_dai_template) * ARRAY_SIZE(fsl_sai_dai_template)); /* Sync Tx with Rx as default by following old DT binding */ sai->synchronous[RX] = true; sai->synchronous[TX] = false; - sai->cpu_dai_drv.symmetric_rate = 1; - sai->cpu_dai_drv.symmetric_channels = 1; - sai->cpu_dai_drv.symmetric_sample_bits = 1; + sai->cpu_dai_drv[0].symmetric_rate = 1; + sai->cpu_dai_drv[0].symmetric_channels = 1; + sai->cpu_dai_drv[0].symmetric_sample_bits = 1; if (of_property_read_bool(np, "fsl,sai-synchronous-rx") && of_property_read_bool(np, "fsl,sai-asynchronous")) { @@ -1424,9 +1487,9 @@ static int fsl_sai_probe(struct platform_device *pdev) /* Discard all settings for asynchronous mode */ sai->synchronous[RX] = false; sai->synchronous[TX] = false; - sai->cpu_dai_drv.symmetric_rate = 0; - sai->cpu_dai_drv.symmetric_channels = 0; - sai->cpu_dai_drv.symmetric_sample_bits = 0; + sai->cpu_dai_drv[0].symmetric_rate = 0; + sai->cpu_dai_drv[0].symmetric_channels = 0; + sai->cpu_dai_drv[0].symmetric_sample_bits = 0; } sai->mclk_direction_output = of_property_read_bool(np, "fsl,sai-mclk-direction-output"); @@ -1505,7 +1568,7 @@ static int fsl_sai_probe(struct platform_device *pdev) } ret = devm_snd_soc_register_component(dev, &fsl_component, - &sai->cpu_dai_drv, 1); + sai->cpu_dai_drv, ARRAY_SIZE(fsl_sai_dai_template)); if (ret) goto err_pm_get_sync; diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 550df87b6a06..dadbd16ee394 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -282,7 +282,7 @@ struct fsl_sai { struct clk *pll11k_clk; struct resource *res; - bool is_consumer_mode; + bool is_consumer_mode[2]; bool is_lsb_first; bool is_dsp_mode; bool is_pdm_mode; @@ -299,7 +299,7 @@ struct fsl_sai { unsigned int bclk_ratio; const struct fsl_sai_soc_data *soc_data; - struct snd_soc_dai_driver cpu_dai_drv; + struct snd_soc_dai_driver cpu_dai_drv[3]; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; struct fsl_sai_verid verid; From 6232a7eb1afc842d0daf1c0314e1eda65731783f Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 12 Jun 2024 14:40:51 +0800 Subject: [PATCH 212/349] ASoC: fsl_audmix: Split playback and capture stream to different DAI As audmix requires playback and capture stream in different master/slave mode, so separate playback and capture stream to different DAI. There are three DAIs required, two DAIs for playback one DAI for capture. Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/1718174452-17596-3-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_audmix.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 0ab2c1962117..1671a3037c60 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -326,15 +326,6 @@ static struct snd_soc_dai_driver fsl_audmix_dai[] = { .rates = SNDRV_PCM_RATE_8000_96000, .formats = FSL_AUDMIX_FORMATS, }, - .capture = { - .stream_name = "AUDMIX-Capture-0", - .channels_min = 8, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 96000, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = FSL_AUDMIX_FORMATS, - }, .ops = &fsl_audmix_dai_ops, }, { @@ -349,8 +340,13 @@ static struct snd_soc_dai_driver fsl_audmix_dai[] = { .rates = SNDRV_PCM_RATE_8000_96000, .formats = FSL_AUDMIX_FORMATS, }, + .ops = &fsl_audmix_dai_ops, + }, + { + .id = 2, + .name = "audmix-2", .capture = { - .stream_name = "AUDMIX-Capture-1", + .stream_name = "AUDMIX-Capture-0", .channels_min = 8, .channels_max = 8, .rate_min = 8000, From 05d996e113481fdd9ac40ccf5cadabd1e73f2404 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 12 Jun 2024 14:40:52 +0800 Subject: [PATCH 213/349] ASoC: imx-audmix: Split capture device for audmix There will be three devices for this sound card, hw:x,0 is the playback device for one SAI, hw:x,1 is the playback device for another SAI, hw:x,2 is the capture device for audmix output. then capture device and playback device can be configured with different master/slave mode. Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/1718174452-17596-4-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audmix.c | 79 ++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index 2aeb18397bcb..6fbcf33fd0de 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -140,6 +140,13 @@ static const struct snd_soc_ops imx_audmix_be_ops = { .hw_params = imx_audmix_be_hw_params, }; +static const char *name[][3] = { + {"HiFi-AUDMIX-FE-0", "HiFi-AUDMIX-FE-1", "HiFi-AUDMIX-FE-2"}, + {"sai-tx", "sai-tx", "sai-rx"}, + {"AUDMIX-Playback-0", "AUDMIX-Playback-1", "CPU-Capture"}, + {"CPU-Playback", "CPU-Playback", "AUDMIX-Capture-0"}, +}; + static int imx_audmix_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -150,7 +157,7 @@ static int imx_audmix_probe(struct platform_device *pdev) struct imx_audmix *priv; int i, num_dai, ret; const char *fe_name_pref = "HiFi-AUDMIX-FE-"; - char *be_name, *be_pb, *be_cp, *dai_name, *capture_dai_name; + char *be_name, *dai_name; if (pdev->dev.parent) { audmix_np = pdev->dev.parent->of_node; @@ -183,6 +190,7 @@ static int imx_audmix_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + num_dai += 1; priv->num_dai = 2 * num_dai; priv->dai = devm_kcalloc(&pdev->dev, priv->num_dai, sizeof(struct snd_soc_dai_link), GFP_KERNEL); @@ -196,7 +204,7 @@ static int imx_audmix_probe(struct platform_device *pdev) if (!priv->dai_conf) return -ENOMEM; - priv->num_dapm_routes = 3 * num_dai; + priv->num_dapm_routes = num_dai; priv->dapm_routes = devm_kcalloc(&pdev->dev, priv->num_dapm_routes, sizeof(struct snd_soc_dapm_route), GFP_KERNEL); @@ -211,8 +219,12 @@ static int imx_audmix_probe(struct platform_device *pdev) if (!dlc) return -ENOMEM; - ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i, - &args); + if (i == num_dai - 1) + ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, 0, + &args); + else + ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i, + &args); if (ret < 0) { dev_err(&pdev->dev, "of_parse_phandle_with_args failed\n"); return ret; @@ -226,20 +238,14 @@ static int imx_audmix_probe(struct platform_device *pdev) put_device(&cpu_pdev->dev); dai_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%s", - fe_name_pref, args.np->full_name + 1); + fe_name_pref, args.np->full_name); if (!dai_name) return -ENOMEM; dev_info(pdev->dev.parent, "DAI FE name:%s\n", dai_name); - if (i == 0) { + if (i == num_dai - 1) out_cpu_np = args.np; - capture_dai_name = - devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s", - dai_name, "CPU-Capture"); - if (!capture_dai_name) - return -ENOMEM; - } /* * CPU == Platform @@ -252,27 +258,23 @@ static int imx_audmix_probe(struct platform_device *pdev) priv->dai[i].num_cpus = 1; priv->dai[i].num_codecs = 1; priv->dai[i].num_platforms = 1; - - priv->dai[i].name = dai_name; + priv->dai[i].name = name[0][i]; priv->dai[i].stream_name = "HiFi-AUDMIX-FE"; priv->dai[i].cpus->of_node = args.np; - priv->dai[i].cpus->dai_name = dev_name(&cpu_pdev->dev); + priv->dai[i].cpus->dai_name = name[1][i]; + priv->dai[i].dynamic = 1; priv->dai[i].dpcm_playback = 1; - priv->dai[i].dpcm_capture = (i == 0 ? 1 : 0); + if (i == num_dai - 1) { + priv->dai[i].dpcm_capture = 1; + priv->dai[i].dpcm_playback = 0; + } priv->dai[i].ignore_pmdown_time = 1; priv->dai[i].ops = &imx_audmix_fe_ops; /* Add AUDMIX Backend */ be_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "audmix-%d", i); - be_pb = devm_kasprintf(&pdev->dev, GFP_KERNEL, - "AUDMIX-Playback-%d", i); - be_cp = devm_kasprintf(&pdev->dev, GFP_KERNEL, - "AUDMIX-Capture-%d", i); - if (!be_name || !be_pb || !be_cp) - return -ENOMEM; - priv->dai[num_dai + i].cpus = &dlc[1]; priv->dai[num_dai + i].codecs = &snd_soc_dummy_dlc; @@ -284,24 +286,33 @@ static int imx_audmix_probe(struct platform_device *pdev) priv->dai[num_dai + i].cpus->dai_name = be_name; priv->dai[num_dai + i].no_pcm = 1; priv->dai[num_dai + i].dpcm_playback = 1; - priv->dai[num_dai + i].dpcm_capture = 1; + if (i == num_dai - 1) { + priv->dai[num_dai + i].dpcm_capture = 1; + priv->dai[num_dai + i].dpcm_playback = 0; + } priv->dai[num_dai + i].ignore_pmdown_time = 1; priv->dai[num_dai + i].ops = &imx_audmix_be_ops; priv->dai_conf[i].dlc.of_node = args.np; priv->dai_conf[i].name_prefix = dai_name; - priv->dapm_routes[i].source = - devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s", - dai_name, "CPU-Playback"); - if (!priv->dapm_routes[i].source) - return -ENOMEM; + if (i == num_dai - 1) { + priv->dapm_routes[i].sink = + devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s", + dai_name, name[2][i]); + if (!priv->dapm_routes[i].sink) + return -ENOMEM; - priv->dapm_routes[i].sink = be_pb; - priv->dapm_routes[num_dai + i].source = be_pb; - priv->dapm_routes[num_dai + i].sink = be_cp; - priv->dapm_routes[2 * num_dai + i].source = be_cp; - priv->dapm_routes[2 * num_dai + i].sink = capture_dai_name; + priv->dapm_routes[i].source = name[3][i]; + } else { + priv->dapm_routes[i].source = + devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s", + dai_name, name[3][i]); + if (!priv->dapm_routes[i].source) + return -ENOMEM; + + priv->dapm_routes[i].sink = name[2][i]; + } } cpu_pdev = of_find_device_by_node(out_cpu_np); From f9f7f29f64454bb20896c7d918c3abc3a1aa487b Mon Sep 17 00:00:00 2001 From: Aleksandr Mishin Date: Wed, 5 Jun 2024 13:49:53 +0300 Subject: [PATCH 214/349] ASoC: qcom: Adjust issues in case of DT error in asoc_qcom_lpass_cpu_platform_probe() If IORESOURCE_MEM "lpass-rxtx-cdc-dma-lpm" or "lpass-va-cdc-dma-lpm" resources is not provided in Device Tree due to any error, platform_get_resource_byname() will return NULL which is later dereferenced. According to sound/qcom,lpass-cpu.yaml, these resources are provided, but DT can be broken due to any error. In such cases driver must be able to protect itself, since the DT is external data for the driver. Adjust this issues by adding NULL return check. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: b138706225c9 ("ASoC: qcom: Add regmap config support for codec dma driver") Signed-off-by: Aleksandr Mishin Link: https://patch.msgid.link/20240605104953.12072-1-amishin@t-argos.ru Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index b0f3e02cb043..5a47f661e0c6 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -1166,9 +1166,13 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm"); + if (!res) + return -EINVAL; drvdata->rxtx_cdc_dma_lpm_buf = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm"); + if (!res) + return -EINVAL; drvdata->va_cdc_dma_lpm_buf = res->start; } From 4faed8ca581c0307af4a58e6c0027ce2b2cbd5d3 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 5 Jun 2024 11:40:51 +0200 Subject: [PATCH 215/349] ASoC: dt-bindings: amlogic,gx-sound-card: drop minItems for audio-widgets Like "audio-routing" drop the minItems: 2 from the "audio-widgets", because any limit here - lower or upper- is rather meaningless. This will also fix `dtbs_check` warnings like: sound: audio-widgets: ['Speaker', '7J4-14 LEFT', 'Speaker', '7J4-11 RIGHT'] is too long Signed-off-by: Neil Armstrong Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240605-topic-amlogic-upstream-bindings-fixes-audio-widgets-v1-1-65bd7cc2e09b@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/amlogic,gx-sound-card.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml index d4277d342e69..0ecdaf7190e9 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml @@ -23,7 +23,6 @@ properties: audio-widgets: $ref: /schemas/types.yaml#/definitions/non-unique-string-array - minItems: 2 description: |- A list off component DAPM widget. Each entry is a pair of strings, the first being the widget type, the second being the widget name From f2177731b6cdaedfe1dea5ec7d185be579b14cc5 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 20 Jun 2024 18:32:24 +0800 Subject: [PATCH 216/349] ASoC: rt712-sdca: change the definition name of SDCA channel number This patch doesn't have any change of functionality. Signed-off-by: Shuming Fan Link: https://patch.msgid.link/20240620103224.2124179-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca-sdw.c | 12 +++++----- sound/soc/codecs/rt712-sdca-sdw.h | 28 +++++++++++------------ sound/soc/codecs/rt712-sdca.c | 38 +++++++++++++++---------------- sound/soc/codecs/rt712-sdca.h | 10 ++++---- 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index ce337db86d1a..ecc541c5a583 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -79,12 +79,12 @@ static bool rt712_sdca_mbq_readable_register(struct device *dev, unsigned int re case 0x5d00000 ... 0x5d00009: case 0x5f00000 ... 0x5f00030: case 0x6100000 ... 0x6100068: - case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L): - case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R): - case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L): - case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R): - case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L): - case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02): return true; default: return false; diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h index 4be22ccd8561..f0cb871b9fa2 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.h +++ b/sound/soc/codecs/rt712-sdca-sdw.h @@ -57,16 +57,16 @@ static const struct reg_default rt712_sdca_reg_defaults[] = { { 0x3303, 0x1f }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_PDE23, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, }; @@ -95,14 +95,14 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = { { 0x6100064, 0x8000 }, { 0x6100065, 0x0000 }, { 0x6100067, 0xff12 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_L), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_R), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, }; #endif /* __RT712_SDW_H__ */ diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index b503de9fda80..e69e1a14fb51 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -592,20 +592,20 @@ static int rt712_sdca_set_gain_get(struct snd_kcontrol *kcontrol, static int rt712_sdca_set_fu0f_capture_ctl(struct rt712_sdca_priv *rt712) { int err; - unsigned int ch_l, ch_r; + unsigned int ch_01, ch_02; - ch_l = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_l_mute) ? 0x01 : 0x00; - ch_r = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_r_mute) ? 0x01 : 0x00; + ch_01 = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_l_mute) ? 0x01 : 0x00; + ch_02 = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_r_mute) ? 0x01 : 0x00; err = regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, - RT712_SDCA_CTL_FU_MUTE, CH_L), ch_l); + RT712_SDCA_CTL_FU_MUTE, CH_01), ch_01); if (err < 0) return err; err = regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, - RT712_SDCA_CTL_FU_MUTE, CH_R), ch_r); + RT712_SDCA_CTL_FU_MUTE, CH_02), ch_02); if (err < 0) return err; @@ -649,28 +649,28 @@ static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, 0, 1000, 0); static const struct snd_kcontrol_new rt712_sdca_controls[] = { SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume", - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L), - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0, 0x57, 0, rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, out_vol_tlv), SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0, rt712_sdca_fu0f_capture_get, rt712_sdca_fu0f_capture_put), SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume", - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L), - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0, 0x3f, 0, rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, mic_vol_tlv), SOC_DOUBLE_R_EXT_TLV("FU44 Boost Volume", - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_L), - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_R), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 8, 3, 0, rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, boost_vol_tlv), }; static const struct snd_kcontrol_new rt712_sdca_spk_controls[] = { SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume", - SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L), - SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R), + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01), + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0, 0x57, 0, rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, out_vol_tlv), }; @@ -763,21 +763,21 @@ static int rt712_sdca_fu05_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_L), + RT712_SDCA_CTL_FU_MUTE, CH_01), unmute); regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_R), + RT712_SDCA_CTL_FU_MUTE, CH_02), unmute); break; case SND_SOC_DAPM_PRE_PMD: regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_L), + RT712_SDCA_CTL_FU_MUTE, CH_01), mute); regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_R), + RT712_SDCA_CTL_FU_MUTE, CH_02), mute); break; } @@ -885,8 +885,8 @@ static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w, static const struct snd_kcontrol_new rt712_spk_sto_dac = SOC_DAPM_DOUBLE_R("Switch", - SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_L), - SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_R), + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0, 1, 1); static const struct snd_soc_dapm_widget rt712_sdca_dapm_widgets[] = { diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h index ff79e03118ce..bf462a837c0d 100644 --- a/sound/soc/codecs/rt712-sdca.h +++ b/sound/soc/codecs/rt712-sdca.h @@ -39,6 +39,12 @@ struct rt712_sdca_priv { bool fu0f_mixer_r_mute; }; +/* SDCA (Channel) */ +#define CH_01 0x01 +#define CH_02 0x02 +#define CH_03 0x03 +#define CH_04 0x04 + /* NID */ #define RT712_VENDOR_REG 0x20 #define RT712_VENDOR_CALI 0x58 @@ -176,10 +182,6 @@ struct rt712_sdca_priv { #define RT712_SDCA_CTL_VENDOR_DEF 0x30 #define RT712_SDCA_CTL_FU_CH_GAIN 0x0b -/* RT712 SDCA channel */ -#define CH_L 0x01 -#define CH_R 0x02 - /* sample frequency index */ #define RT712_SDCA_RATE_16000HZ 0x04 #define RT712_SDCA_RATE_32000HZ 0x07 From 936abb09c1c7ce2c9c8b7838fc780e98c0140759 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 20 Jun 2024 18:32:37 +0800 Subject: [PATCH 217/349] ASoC: rt712-sdca: add the function for version B The version B will support the multi-lane function and integrate the DMIC function in one SoundWire interface. Due to some registers having different default values between version A and B, this patch also removes the redundant default registers to avoid confusion. Signed-off-by: Shuming Fan Link: https://patch.msgid.link/20240620103237.2124196-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca-sdw.c | 24 +- sound/soc/codecs/rt712-sdca-sdw.h | 69 +--- sound/soc/codecs/rt712-sdca.c | 627 +++++++++++++++++++++++++++--- sound/soc/codecs/rt712-sdca.h | 40 ++ 4 files changed, 660 insertions(+), 100 deletions(-) diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index ecc541c5a583..90d5aaddbd5b 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -34,6 +34,10 @@ static bool rt712_sdca_readable_register(struct device *dev, unsigned int reg) case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0): case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2: return true; default: @@ -56,6 +60,10 @@ static bool rt712_sdca_volatile_register(struct device *dev, unsigned int reg) case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0): case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2: return true; default: @@ -78,13 +86,21 @@ static bool rt712_sdca_mbq_readable_register(struct device *dev, unsigned int re case 0x5c00000 ... 0x5c0009a: case 0x5d00000 ... 0x5d00009: case 0x5f00000 ... 0x5f00030: - case 0x6100000 ... 0x6100068: + case 0x6100000 ... 0x61000f1: case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01): case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02): case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01): case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04): return true; default: return false; @@ -96,7 +112,9 @@ static bool rt712_sdca_mbq_volatile_register(struct device *dev, unsigned int re switch (reg) { case 0x2000000: case 0x200001a: + case 0x2000020: case 0x2000024: + case 0x2000030: case 0x2000046: case 0x200008a: case 0x5800000: @@ -178,13 +196,15 @@ static int rt712_sdca_read_prop(struct sdw_slave *slave) unsigned long addr; struct sdw_dpn_prop *dpn; + sdw_slave_read_prop(slave); + 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 */ - prop->source_ports = BIT(4); /* BITMAP: 00010000 */ + prop->source_ports = BIT(8) | BIT(4); /* BITMAP: 100010000 */ prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */ nval = hweight32(prop->source_ports); diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h index f0cb871b9fa2..99fd2d67f04d 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.h +++ b/sound/soc/codecs/rt712-sdca-sdw.h @@ -12,49 +12,7 @@ #include static const struct reg_default rt712_sdca_reg_defaults[] = { - { 0x201a, 0x00 }, - { 0x201b, 0x00 }, - { 0x201c, 0x00 }, - { 0x201d, 0x00 }, - { 0x201e, 0x00 }, - { 0x201f, 0x00 }, - { 0x2029, 0x00 }, - { 0x202a, 0x00 }, - { 0x202d, 0x00 }, - { 0x202e, 0x00 }, - { 0x202f, 0x00 }, - { 0x2030, 0x00 }, - { 0x2031, 0x00 }, - { 0x2032, 0x00 }, - { 0x2033, 0x00 }, - { 0x2034, 0x00 }, - { 0x2230, 0x00 }, - { 0x2231, 0x2f }, - { 0x2232, 0x80 }, - { 0x2f01, 0x00 }, - { 0x2f02, 0x09 }, - { 0x2f03, 0x00 }, - { 0x2f04, 0x00 }, - { 0x2f05, 0x0b }, - { 0x2f06, 0x01 }, - { 0x2f08, 0x00 }, - { 0x2f09, 0x00 }, - { 0x2f0a, 0x01 }, - { 0x2f35, 0x01 }, - { 0x2f36, 0xcf }, - { 0x2f50, 0x0f }, - { 0x2f54, 0x01 }, - { 0x2f58, 0x07 }, - { 0x2f59, 0x09 }, - { 0x2f5a, 0x01 }, - { 0x2f5b, 0x07 }, - { 0x2f5c, 0x05 }, - { 0x2f5d, 0x05 }, - { 0x3201, 0x01 }, - { 0x320c, 0x00 }, - { 0x3301, 0x01 }, - { 0x3302, 0x00 }, - { 0x3303, 0x1f }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, @@ -63,17 +21,22 @@ static const struct reg_default rt712_sdca_reg_defaults[] = { { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_PDE23, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_PDE23, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, }; static const struct reg_default rt712_sdca_mbq_defaults[] = { { 0x2000004, 0xaa01 }, { 0x200000e, 0x21e0 }, - { 0x2000024, 0x01ba }, { 0x200004a, 0x8830 }, { 0x2000067, 0xf100 }, { 0x5800000, 0x1893 }, @@ -81,12 +44,8 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = { { 0x5b00005, 0x0000 }, { 0x5b00029, 0x3fff }, { 0x5b0002a, 0xf000 }, - { 0x5f00008, 0x7000 }, + { 0x6100000, 0x04e4 }, { 0x610000e, 0x0007 }, - { 0x6100022, 0x2828 }, - { 0x6100023, 0x2929 }, - { 0x6100026, 0x2c29 }, - { 0x610002c, 0x4150 }, { 0x6100045, 0x0860 }, { 0x6100046, 0x0029 }, { 0x6100053, 0x3fff }, @@ -101,6 +60,14 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = { { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, }; diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index e69e1a14fb51..e210c574bb74 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -82,7 +82,8 @@ static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712) dev = regmap_get_device(regmap); /* Set HP-JD source from JD1 */ - rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a); + if (rt712->version_id == RT712_VA) + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a); /* FSM switch to calibration manual mode */ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_FSM_CTL, 0x4100); @@ -198,11 +199,17 @@ static unsigned int rt712_sdca_button_detect(struct rt712_sdca_priv *rt712) _end_btn_det_: /* Host is owner, so set back to device */ - if (owner == 0) + if (owner == 0) { /* set owner to device */ - regmap_write(rt712->regmap, - SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, - RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01); + if (rt712->version_id == RT712_VA) + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, + RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01); + else + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, + RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01); + } return btn_type; } @@ -415,8 +422,9 @@ static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712) switch (rt712->jd_src) { case RT712_JD1: - /* Set HP-JD source from JD1 */ - rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a); + /* Set HP-JD source from JD1, VB uses JD1 in default */ + if (rt712->version_id == RT712_VA) + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a); break; default: dev_warn(rt712->component->dev, "Wrong JD source\n"); @@ -854,7 +862,7 @@ static int rt712_sdca_pde12_event(struct snd_soc_dapm_widget *w, return 0; } -static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w, +static int rt712_sdca_pde23_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = @@ -883,9 +891,12 @@ static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w, return 0; } -static const struct snd_kcontrol_new rt712_spk_sto_dac = - SOC_DAPM_DOUBLE_R("Switch", +static const struct snd_kcontrol_new rt712_spk_l_dac = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), + 0, 1, 1); +static const struct snd_kcontrol_new rt712_spk_r_dac = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0, 1, 1); @@ -931,20 +942,26 @@ static const struct snd_soc_dapm_widget rt712_sdca_spk_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0), /* Digital Interface */ - SND_SOC_DAPM_SWITCH("FU06", SND_SOC_NOPM, 0, 0, &rt712_spk_sto_dac), + SND_SOC_DAPM_PGA("FU06", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0, + rt712_sdca_pde23_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), /* Output */ - SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0, - rt712_sdca_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt712_spk_l_dac), + SND_SOC_DAPM_SWITCH("OT23 R", SND_SOC_NOPM, 0, 0, &rt712_spk_r_dac), SND_SOC_DAPM_OUTPUT("SPOL"), SND_SOC_DAPM_OUTPUT("SPOR"), }; static const struct snd_soc_dapm_route rt712_sdca_spk_dapm_routes[] = { - { "FU06", "Switch", "DP3RX" }, - { "CLASS D", NULL, "FU06" }, - { "SPOL", NULL, "CLASS D" }, - { "SPOR", NULL, "CLASS D" }, + { "FU06", NULL, "DP3RX" }, + { "FU06", NULL, "PDE 23" }, + { "OT23 L", "Switch", "FU06" }, + { "OT23 R", "Switch", "FU06" }, + { "SPOL", NULL, "OT23 L" }, + { "SPOR", NULL, "OT23 R" }, }; static int rt712_sdca_parse_dt(struct rt712_sdca_priv *rt712, struct device *dev) @@ -983,6 +1000,376 @@ static int rt712_sdca_probe(struct snd_soc_component *component) return 0; } +static int rt712_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + struct rt712_dmic_kctrl_priv *p = + (struct rt712_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int regvalue, ctl, i; + unsigned int adc_vol_flag = 0; + const unsigned int interval_offset = 0xc0; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume")) + adc_vol_flag = 1; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt712->mbq_regmap, p->reg_base + i, ®value); + + if (!adc_vol_flag) /* boost gain */ + ctl = regvalue / 0x0a00; + else { /* ADC gain */ + if (adc_vol_flag) + ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset); + else + ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset); + } + + ucontrol->value.integer.value[i] = ctl; + } + + return 0; +} + +static int rt712_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt712_dmic_kctrl_priv *p = + (struct rt712_dmic_kctrl_priv *)kcontrol->private_value; + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + unsigned int gain_val[4]; + unsigned int i, adc_vol_flag = 0, changed = 0; + unsigned int regvalue[4]; + const unsigned int interval_offset = 0xc0; + int err; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume")) + adc_vol_flag = 1; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt712->mbq_regmap, p->reg_base + i, ®value[i]); + + gain_val[i] = ucontrol->value.integer.value[i]; + if (gain_val[i] > p->max) + gain_val[i] = p->max; + + if (!adc_vol_flag) /* boost gain */ + gain_val[i] = gain_val[i] * 0x0a00; + else { /* ADC gain */ + gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset); + gain_val[i] &= 0xffff; + } + + if (regvalue[i] != gain_val[i]) + changed = 1; + } + + if (!changed) + return 0; + + for (i = 0; i < p->count; i++) { + err = regmap_write(rt712->mbq_regmap, p->reg_base + i, gain_val[i]); + if (err < 0) + dev_err(&rt712->slave->dev, "0x%08x can't be set\n", p->reg_base + i); + } + + return changed; +} + +static int rt712_sdca_set_fu1e_capture_ctl(struct rt712_sdca_priv *rt712) +{ + int err, i; + unsigned int ch_mute; + + for (i = 0; i < ARRAY_SIZE(rt712->fu1e_mixer_mute); i++) { + ch_mute = (rt712->fu1e_dapm_mute || rt712->fu1e_mixer_mute[i]) ? 0x01 : 0x00; + err = regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, + RT712_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute); + if (err < 0) + return err; + } + + return 0; +} + +static int rt712_sdca_dmic_fu1e_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + struct rt712_dmic_kctrl_priv *p = + (struct rt712_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int i; + + for (i = 0; i < p->count; i++) + ucontrol->value.integer.value[i] = !rt712->fu1e_mixer_mute[i]; + + return 0; +} + +static int rt712_sdca_dmic_fu1e_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + struct rt712_dmic_kctrl_priv *p = + (struct rt712_dmic_kctrl_priv *)kcontrol->private_value; + int err, changed = 0, i; + + for (i = 0; i < p->count; i++) { + if (rt712->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i]) + changed = 1; + rt712->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i]; + } + + err = rt712_sdca_set_fu1e_capture_ctl(rt712); + if (err < 0) + return err; + + return changed; +} + +static int rt712_sdca_fu_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct rt712_dmic_kctrl_priv *p = + (struct rt712_dmic_kctrl_priv *)kcontrol->private_value; + + if (p->max == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = p->count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = p->max; + return 0; +} + +#define RT712_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \ + ((unsigned long)&(struct rt712_dmic_kctrl_priv) \ + {.reg_base = xreg_base, .count = xcount, .max = xmax, \ + .invert = xinvert}) + +#define RT712_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = rt712_sdca_fu_info, \ + .get = rt712_sdca_dmic_fu1e_capture_get, \ + .put = rt712_sdca_dmic_fu1e_capture_put, \ + .private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)} + +#define RT712_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\ + xhandler_put, xcount, xmax, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = rt712_sdca_fu_info, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) } + +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(dmic_vol_tlv, 0, 1000, 0); + +static const struct snd_kcontrol_new rt712_sdca_dmic_snd_controls[] = { + RT712_SDCA_FU_CTRL("FU1E Capture Switch", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), + 1, 1, 4), + RT712_SDCA_EXT_TLV("FU1E Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01), + rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 0x3f, in_vol_tlv), + RT712_SDCA_EXT_TLV("FU15 Boost Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), + rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 3, dmic_vol_tlv), +}; + +static int rt712_sdca_dmic_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + unsigned int val = 0, mask_sft; + + if (strstr(ucontrol->id.name, "ADC 0A Mux")) + mask_sft = 0; + else if (strstr(ucontrol->id.name, "ADC 0B Mux")) + mask_sft = 4; + else + return -EINVAL; + + rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL, + RT712_HDA_LEGACY_MUX_CTL0, &val); + + ucontrol->value.enumerated.item[0] = (((val >> mask_sft) & 0xf) == 0x4) ? 0 : 1; + + return 0; +} + +static int rt712_sdca_dmic_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, mask_sft; + + if (item[0] >= e->items) + return -EINVAL; + + if (strstr(ucontrol->id.name, "ADC 0A Mux")) + mask_sft = 0; + else if (strstr(ucontrol->id.name, "ADC 0B Mux")) + mask_sft = 4; + else + return -EINVAL; + + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL, + RT712_HDA_LEGACY_MUX_CTL0, &val2); + val2 = ((0xf << mask_sft) & val2) >> mask_sft; + + if (val == 0) + val = 0x4; + else if (val >= 1) + val = 0xe; + + if (val == val2) + change = 0; + else + change = 1; + + if (change) + rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL, + RT712_HDA_LEGACY_MUX_CTL0, 0xf << mask_sft, + val << mask_sft); + + snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL); + + return change; +} + +static const char * const adc_dmic_mux_text[] = { + "DMIC1", + "DMIC2", +}; + +static SOC_ENUM_SINGLE_DECL( + rt712_adc0a_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL( + rt712_adc0b_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text); + +static const struct snd_kcontrol_new rt712_sdca_dmic_adc0a_mux = + SOC_DAPM_ENUM_EXT("ADC 0A Mux", rt712_adc0a_enum, + rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put); + +static const struct snd_kcontrol_new rt712_sdca_dmic_adc0b_mux = + SOC_DAPM_ENUM_EXT("ADC 0B Mux", rt712_adc0b_enum, + rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put); + +static int rt712_sdca_dmic_fu1e_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 rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt712->fu1e_dapm_mute = false; + rt712_sdca_set_fu1e_capture_ctl(rt712); + break; + case SND_SOC_DAPM_PRE_PMD: + rt712->fu1e_dapm_mute = true; + rt712_sdca_set_fu1e_capture_ctl(rt712); + break; + } + return 0; +} + +static int rt712_sdca_dmic_pde11_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 rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11, + RT712_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11, + RT712_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget rt712_sdca_dmic_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + + SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0, + rt712_sdca_dmic_pde11_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_ADC_E("FU 1E", NULL, SND_SOC_NOPM, 0, 0, + rt712_sdca_dmic_fu1e_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX("ADC 0A Mux", SND_SOC_NOPM, 0, 0, + &rt712_sdca_dmic_adc0a_mux), + SND_SOC_DAPM_MUX("ADC 0B Mux", SND_SOC_NOPM, 0, 0, + &rt712_sdca_dmic_adc0b_mux), + + SND_SOC_DAPM_AIF_OUT("DP8TX", "DP8 Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt712_sdca_dmic_audio_map[] = { + {"DP8TX", NULL, "FU 1E"}, + + {"FU 1E", NULL, "PDE 11"}, + {"FU 1E", NULL, "ADC 0A Mux"}, + {"FU 1E", NULL, "ADC 0B Mux"}, + {"ADC 0A Mux", "DMIC1", "DMIC1"}, + {"ADC 0A Mux", "DMIC2", "DMIC2"}, + {"ADC 0B Mux", "DMIC1", "DMIC1"}, + {"ADC 0B Mux", "DMIC2", "DMIC2"}, +}; + +static int rt712_sdca_dmic_probe(struct snd_soc_component *component) +{ + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + int ret; + + rt712->dmic_component = component; + + if (!rt712->first_hw_init) + return 0; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_sdca_dev_rt712 = { .probe = rt712_sdca_probe, .controls = rt712_sdca_controls, @@ -995,6 +1382,20 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt712 = { .endianness = 1, }; +static const struct snd_soc_component_driver soc_sdca_dev_rt712_dmic = { + .probe = rt712_sdca_dmic_probe, + .controls = rt712_sdca_dmic_snd_controls, + .num_controls = ARRAY_SIZE(rt712_sdca_dmic_snd_controls), + .dapm_widgets = rt712_sdca_dmic_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt712_sdca_dmic_dapm_widgets), + .dapm_routes = rt712_sdca_dmic_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt712_sdca_dmic_audio_map), + .endianness = 1, +#ifdef CONFIG_DEBUG_FS + .debugfs_prefix = "dmic", +#endif +}; + static int rt712_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction) { @@ -1022,7 +1423,7 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, int retval, port, num_channels; unsigned int sampling_rate; - dev_dbg(dai->dev, "%s %s", __func__, dai->name); + dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id); sdw_stream = snd_soc_dai_get_dma_data(dai, substream); if (!sdw_stream) @@ -1031,6 +1432,10 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, if (!rt712->slave) return -EINVAL; + /* VA doesn't support AIF3 */ + if (dai->id == RT712_AIF3 && rt712->version_id == RT712_VA) + return -EINVAL; + /* SoundWire specific configuration */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { direction = SDW_DATA_DIR_RX; @@ -1044,6 +1449,8 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, direction = SDW_DATA_DIR_TX; if (dai->id == RT712_AIF1) port = 4; + else if (dai->id == RT712_AIF3) + port = 8; else return -EINVAL; } @@ -1105,6 +1512,14 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); break; + case RT712_AIF3: + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + break; default: dev_err(component->dev, "%s: Wrong DAI id\n", __func__); return -EINVAL; @@ -1174,6 +1589,21 @@ static struct snd_soc_dai_driver rt712_sdca_dai[] = { } }; +static struct snd_soc_dai_driver rt712_sdca_dmic_dai[] = { + { + .name = "rt712-sdca-aif3", + .id = RT712_AIF3, + .capture = { + .stream_name = "DP8 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = RT712_STEREO_RATES, + .formats = RT712_FORMATS, + }, + .ops = &rt712_sdca_ops, + } +}; + int rt712_sdca_init(struct device *dev, struct regmap *regmap, struct regmap *mbq_regmap, struct sdw_slave *slave) { @@ -1206,6 +1636,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, rt712->first_hw_init = false; rt712->fu0f_dapm_mute = true; rt712->fu0f_mixer_l_mute = rt712->fu0f_mixer_r_mute = true; + rt712->fu1e_dapm_mute = true; + rt712->fu1e_mixer_mute[0] = rt712->fu1e_mixer_mute[1] = + rt712->fu1e_mixer_mute[2] = rt712->fu1e_mixer_mute[3] = true; /* JD source uses JD1 in default */ rt712->jd_src = RT712_JD1; @@ -1239,35 +1672,11 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, return 0; } -int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) +static void rt712_sdca_va_io_init(struct rt712_sdca_priv *rt712) { - struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev); int ret = 0; - unsigned int val, hibernation_flag; - - rt712->disable_irq = false; - - 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_bypass(rt712->regmap, true); - regcache_cache_bypass(rt712->mbq_regmap, true); - } else { - /* - * PM runtime status is marked as 'active' only when a Slave reports as Attached - */ - - /* update count of parent 'active' children */ - pm_runtime_set_active(&slave->dev); - } - - pm_runtime_get_noresume(&slave->dev); - - rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val); - rt712->hw_id = (val & 0xf000) >> 12; + unsigned int hibernation_flag; + struct device *dev = &rt712->slave->dev; rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81); rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0); @@ -1307,6 +1716,131 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04); } +} + +static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712) +{ + int ret = 0; + unsigned int jack_func_status, mic_func_status, amp_func_status; + struct device *dev = &rt712->slave->dev; + + regmap_read(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &jack_func_status); + regmap_read(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &mic_func_status); + regmap_read(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &_func_status); + dev_dbg(dev, "%s jack/mic/amp func_status=0x%x, 0x%x, 0x%x\n", + __func__, jack_func_status, mic_func_status, amp_func_status); + + /* DMIC */ + if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) { + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_IT_FLOAT_CTL, 0x1526); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_CH12_FLOAT_CTL, 0x0304); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL, 0x1f1e); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0B_FU_CH12_FLOAT_CTL, 0x0304); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_HDA_LEGACY_CONFIG_CTL0, 0x8010); + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT11, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01); + rt712_sdca_index_write(rt712, RT712_ULTRA_SOUND_DET, RT712_ULTRA_SOUND_DETECTOR6, 0x3200); + regmap_write(rt712->regmap, RT712_RC_CAL, 0x23); + + /* clear flag */ + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), + FUNCTION_NEEDS_INITIALIZATION); + } + + /* Jack */ + if ((jack_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) { + rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_SEL_VEE2_HP_CTL1, 0x042a); + rt712_sdca_index_write(rt712, RT712_CHARGE_PUMP, RT712_HP_DET_CTL3, 0x1fff); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec67); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0); + rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL1, 0x0000); + rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL2, 0x0000); + regmap_write(rt712->regmap, RT712_RC_CAL, 0x23); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_JD_CTL1, 0x2802); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL6, 0xf215); + + /* calibration */ + ret = rt712_sdca_calibration(rt712); + if (ret < 0) + dev_err(dev, "%s, calibration failed!\n", __func__); + + rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL, RT712_MIXER_CTL1, 0x3000, 0x0000); + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_IT09, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_MISC_CTL_FOR_UAJ, 0x0003); + + /* clear flag */ + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), + FUNCTION_NEEDS_INITIALIZATION); + } + + /* SPK */ + if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) { + if (rt712->hw_id != RT712_DEV_ID_713) { + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec63); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL1, 0xfff5); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_EAPD_CTL, 0x0002); + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04); + } + /* clear flag */ + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), + FUNCTION_NEEDS_INITIALIZATION); + } +} + +int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev); + int ret = 0; + unsigned int val; + struct sdw_slave_prop *prop = &slave->prop; + + rt712->disable_irq = false; + + 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_bypass(rt712->regmap, true); + regcache_cache_bypass(rt712->mbq_regmap, true); + } else { + /* + * PM runtime status is marked as 'active' only when a Slave reports as Attached + */ + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val); + rt712->hw_id = (val & 0xf000) >> 12; + rt712->version_id = (val & 0x0f00) >> 8; + dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id); + + if (rt712->version_id == RT712_VA) + rt712_sdca_va_io_init(rt712); + else { + /* multilanes and DMIC are supported by rt712vb */ + ret = devm_snd_soc_register_component(dev, + &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai)); + if (ret < 0) + return ret; + + prop->lane_control_support = true; + rt712_sdca_vb_io_init(rt712); + } /* * if set_jack callback occurred early than io_init, @@ -1315,8 +1849,7 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt712->hs_jack) rt712_sdca_jack_init(rt712); - if (!hibernation_flag) - rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001); if (rt712->first_hw_init) { regcache_cache_bypass(rt712->regmap, false); diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h index bf462a837c0d..2169f2f726b9 100644 --- a/sound/soc/codecs/rt712-sdca.h +++ b/sound/soc/codecs/rt712-sdca.h @@ -19,6 +19,7 @@ struct rt712_sdca_priv { struct regmap *regmap; struct regmap *mbq_regmap; struct snd_soc_component *component; + struct snd_soc_component *dmic_component; struct sdw_slave *slave; struct sdw_bus_params params; bool hw_init; @@ -34,9 +35,19 @@ struct rt712_sdca_priv { unsigned int scp_sdca_stat1; unsigned int scp_sdca_stat2; unsigned int hw_id; + unsigned int version_id; bool fu0f_dapm_mute; bool fu0f_mixer_l_mute; bool fu0f_mixer_r_mute; + bool fu1e_dapm_mute; + bool fu1e_mixer_mute[4]; +}; + +struct rt712_dmic_kctrl_priv { + unsigned int reg_base; + unsigned int count; + unsigned int max; + unsigned int invert; }; /* SDCA (Channel) */ @@ -47,6 +58,8 @@ struct rt712_sdca_priv { /* NID */ #define RT712_VENDOR_REG 0x20 +#define RT712_EQ_CTRL 0x53 +#define RT712_CHARGE_PUMP 0x57 #define RT712_VENDOR_CALI 0x58 #define RT712_ULTRA_SOUND_DET 0x59 #define RT712_VENDOR_IMS_DRE 0x5b @@ -56,9 +69,13 @@ struct rt712_sdca_priv { /* Index (NID:20h) */ #define RT712_JD_PRODUCT_NUM 0x00 #define RT712_ANALOG_BIAS_CTL3 0x04 +#define RT712_JD_CTL1 0x09 +#define RT712_IO_CTL 0x0c #define RT712_LDO2_3_CTL1 0x0e #define RT712_PARA_VERB_CTL 0x1a #define RT712_CC_DET1 0x24 +#define RT712_CLASSD_AMP_CTL1 0x37 +#define RT712_CLASSD_AMP_CTL6 0x3c #define RT712_COMBO_JACK_AUTO_CTL1 0x45 #define RT712_COMBO_JACK_AUTO_CTL2 0x46 #define RT712_COMBO_JACK_AUTO_CTL3 0x47 @@ -67,6 +84,9 @@ struct rt712_sdca_priv { #define RT712_SW_CONFIG1 0x8a #define RT712_SW_CONFIG2 0x8b +/* Index (NID:57h) */ +#define RT712_HP_DET_CTL3 0x0c + /* Index (NID:58h) */ #define RT712_DAC_DC_CALI_CTL1 0x00 #define RT712_DAC_DC_CALI_CTL2 0x01 @@ -77,6 +97,7 @@ struct rt712_sdca_priv { /* Index (NID:5bh) */ #define RT712_IMS_DIGITAL_CTL1 0x00 #define RT712_IMS_DIGITAL_CTL5 0x05 +#define RT712_SEL_VEE2_HP_CTL1 0x23 #define RT712_HP_DETECT_RLDET_CTL1 0x29 #define RT712_HP_DETECT_RLDET_CTL2 0x2a @@ -115,6 +136,11 @@ struct rt712_sdca_priv { #define RT712_UMP_HID_CTL6 0x66 #define RT712_UMP_HID_CTL7 0x67 #define RT712_UMP_HID_CTL8 0x68 +#define RT712_MISC_CTL_FOR_UAJ 0x72 +#define RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL 0xa2 +#define RT712_DMIC2_FU_IT_FLOAT_CTL 0xa6 +#define RT712_ADC0B_FU_CH12_FLOAT_CTL 0xb0 +#define RT712_DMIC2_FU_CH12_FLOAT_CTL 0xb1 /* Parameter & Verb control 01 (0x1a)(NID:20h) */ #define RT712_HIDDEN_REG_SW_RESET (0x1 << 14) @@ -145,6 +171,7 @@ struct rt712_sdca_priv { #define FUNC_NUM_AMP 0x04 /* RT712 SDCA entity */ +#define RT712_SDCA_ENT0 0x00 #define RT712_SDCA_ENT_HID01 0x01 #define RT712_SDCA_ENT_GE49 0x49 #define RT712_SDCA_ENT_USER_FU05 0x05 @@ -163,6 +190,7 @@ struct rt712_sdca_priv { #define RT712_SDCA_ENT_CS1C 0x1c #define RT712_SDCA_ENT_CS31 0x31 #define RT712_SDCA_ENT_OT23 0x42 +#define RT712_SDCA_ENT_IT11 0x26 #define RT712_SDCA_ENT_IT26 0x26 #define RT712_SDCA_ENT_IT09 0x09 #define RT712_SDCA_ENT_PLATFORM_FU15 0x15 @@ -181,6 +209,12 @@ struct rt712_sdca_priv { #define RT712_SDCA_CTL_REQ_POWER_STATE 0x01 #define RT712_SDCA_CTL_VENDOR_DEF 0x30 #define RT712_SDCA_CTL_FU_CH_GAIN 0x0b +#define RT712_SDCA_CTL_FUNC_STATUS 0x10 + +/* Function_Status */ +#define FUNCTION_NEEDS_INITIALIZATION BIT(5) +#define FUNCTION_HAS_BEEN_RESET BIT(6) +#define FUNCTION_BUSY BIT(7) /* sample frequency index */ #define RT712_SDCA_RATE_16000HZ 0x04 @@ -193,6 +227,7 @@ struct rt712_sdca_priv { enum { RT712_AIF1, RT712_AIF2, + RT712_AIF3, }; enum rt712_sdca_jd_src { @@ -209,6 +244,11 @@ enum rt712_sdca_hw_id { #define RT712_PART_ID_713 0x713 +enum rt712_sdca_version { + RT712_VA, + RT712_VB, +}; + int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave); int rt712_sdca_init(struct device *dev, struct regmap *regmap, struct regmap *mbq_regmap, struct sdw_slave *slave); From 5b707581c072bcef086ef4c122a2ea81470a1027 Mon Sep 17 00:00:00 2001 From: Zhu Jun Date: Wed, 26 Jun 2024 01:48:59 -0700 Subject: [PATCH 218/349] selftests/alsa:Fix printf format string in pcm-test.c Inside of test_pcm_time() arguments are printed via printf but '%d' is used to print @flags (of type unsigned int). Use '%u' instead, just like we do everywhere else. Signed-off-by: Zhu Jun Reviewed-by: Mark Brown Link: https://patch.msgid.link/20240626084859.4350-1-zhujun2@cmss.chinamobile.com Signed-off-by: Takashi Iwai --- tools/testing/selftests/alsa/pcm-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index de664dedb541..914efcdce1ec 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -383,7 +383,7 @@ __format: goto __close; } if (rrate != rate) { - snprintf(msg, sizeof(msg), "rate mismatch %ld != %d", rate, rrate); + snprintf(msg, sizeof(msg), "rate mismatch %ld != %u", rate, rrate); goto __close; } rperiod_size = period_size; From 36ac1e29f49ff4cbf1500465db311b17d8ba9213 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 27 Jun 2024 14:52:03 +0200 Subject: [PATCH 219/349] ASoC: codecs: lpass-wsa-macro: add missing select of common code The Qualcomm LPASS WSA macro codec driver uses now parts of common module, so it has to select SND_SOC_LPASS_MACRO_COMMON. sound/soc/codecs/lpass-wsa-macro.o: in function `wsa_macro_probe': sound/soc/codecs/lpass-wsa-macro.c:2767:(.text+0x1c9c): undefined reference to `lpass_macro_get_codec_version' Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202406272231.th1LtuLk-lkp@intel.com/ Fixes: 5dcf442bbbca ("ASoC: codecs: lpass-wsa-macro: Prepare to accommodate new codec versions") Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240627125203.171048-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 2019da190dcb..97bb69c9848d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2557,6 +2557,7 @@ config SND_SOC_LPASS_MACRO_COMMON config SND_SOC_LPASS_WSA_MACRO depends on COMMON_CLK select REGMAP_MMIO + select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)" config SND_SOC_LPASS_VA_MACRO From 752fea92d9b3e4255a2f75e7efa6fe148562ccbf Mon Sep 17 00:00:00 2001 From: Piotr Wojtaszczyk Date: Thu, 27 Jun 2024 17:00:21 +0200 Subject: [PATCH 220/349] ASoC: dt-bindings: lpc32xx: Add lpc32xx i2s DT binding Add nxp,lpc3220-i2s DT binding documentation. Signed-off-by: Piotr Wojtaszczyk Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240627150046.258795-4-piotr.wojtaszczyk@timesys.com Signed-off-by: Mark Brown --- .../bindings/sound/nxp,lpc3220-i2s.yaml | 73 +++++++++++++++++++ MAINTAINERS | 9 +++ 2 files changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml diff --git a/Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml b/Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml new file mode 100644 index 000000000000..40a0877a8aba --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nxp,lpc3220-i2s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP LPC32XX I2S Controller + +description: + The I2S controller in LPC32XX SoCs, ASoC DAI. + +maintainers: + - J.M.B. Downing + - Piotr Wojtaszczyk + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - nxp,lpc3220-i2s + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: input clock of the peripheral. + + dmas: + items: + - description: RX DMA Channel + - description: TX DMA Channel + + dma-names: + items: + - const: rx + - const: tx + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - reg + - interrupts + - clocks + - dmas + - dma-names + - '#sound-dai-cells' + +additionalProperties: false + +examples: + - | + #include + #include + + i2s@20094000 { + compatible = "nxp,lpc3220-i2s"; + reg = <0x20094000 0x1000>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LPC32XX_CLK_I2S0>; + dmas = <&dma 0 1>, <&dma 13 1>; + dma-names = "rx", "tx"; + #sound-dai-cells = <0>; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index d3b064ce0ba6..5e5701402009 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8909,6 +8909,15 @@ S: Maintained F: sound/soc/fsl/fsl* F: sound/soc/fsl/imx* +FREESCALE SOC LPC32XX SOUND DRIVERS +M: J.M.B. Downing +M: Piotr Wojtaszczyk +R: Vladimir Zapolskiy +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +L: linuxppc-dev@lists.ozlabs.org +S: Maintained +F: Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml + FREESCALE SOC SOUND QMC DRIVER M: Herve Codina L: alsa-devel@alsa-project.org (moderated for non-subscribers) From 0959de657a10cc40b2cc41cff9169ab0e0fd4456 Mon Sep 17 00:00:00 2001 From: Piotr Wojtaszczyk Date: Thu, 27 Jun 2024 17:00:29 +0200 Subject: [PATCH 221/349] ASoC: fsl: Add i2s and pcm drivers for LPC32xx CPUs This driver was ported from an old version in linux 2.6.27 and adjusted for the new ASoC framework and DMA API. Signed-off-by: Piotr Wojtaszczyk Link: https://patch.msgid.link/20240627150046.258795-12-piotr.wojtaszczyk@timesys.com Signed-off-by: Mark Brown --- MAINTAINERS | 1 + sound/soc/fsl/Kconfig | 7 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/lpc3xxx-i2s.c | 375 ++++++++++++++++++++++++++++++++++++ sound/soc/fsl/lpc3xxx-i2s.h | 79 ++++++++ sound/soc/fsl/lpc3xxx-pcm.c | 72 +++++++ 6 files changed, 536 insertions(+) create mode 100644 sound/soc/fsl/lpc3xxx-i2s.c create mode 100644 sound/soc/fsl/lpc3xxx-i2s.h create mode 100644 sound/soc/fsl/lpc3xxx-pcm.c diff --git a/MAINTAINERS b/MAINTAINERS index 5e5701402009..93f8f2ed3cb2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8917,6 +8917,7 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: linuxppc-dev@lists.ozlabs.org S: Maintained F: Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml +F: sound/soc/fsl/lpc3xxx-* FREESCALE SOC SOUND QMC DRIVER M: Herve Codina diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 9a371d4496c2..8b7088623b6a 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -131,6 +131,13 @@ config SND_SOC_FSL_RPMSG This option is only useful for out-of-tree drivers since in-tree drivers select it automatically. +config SND_SOC_FSL_LPC3XXX + tristate "SoC Audio for NXP LPC32XX CPUs" + depends on ARCH_LPC32XX || COMPILE_TEST + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for the LPC3XXX I2S interface. + config SND_SOC_IMX_PCM_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 2fe78eed3a48..2a61e2f96438 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o snd-soc-fsl-audmix-y := fsl_audmix.o snd-soc-fsl-asoc-card-y := fsl-asoc-card.o snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o +snd-soc-fsl-lpc3xxx-y := lpc3xxx-pcm.o lpc3xxx-i2s.o snd-soc-fsl-sai-y := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o @@ -29,6 +30,7 @@ snd-soc-fsl-qmc-audio-y := fsl_qmc_audio.o obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o +obj-$(CONFIG_SND_SOC_FSL_LPC3XXX) += snd-soc-fsl-lpc3xxx.o obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o diff --git a/sound/soc/fsl/lpc3xxx-i2s.c b/sound/soc/fsl/lpc3xxx-i2s.c new file mode 100644 index 000000000000..0e5b4d5202ff --- /dev/null +++ b/sound/soc/fsl/lpc3xxx-i2s.c @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Author: Kevin Wells +// +// Copyright (C) 2008 NXP Semiconductors +// Copyright 2023 Timesys Corporation + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "lpc3xxx-i2s.h" + +#define I2S_PLAYBACK_FLAG 0x1 +#define I2S_CAPTURE_FLAG 0x2 + +#define LPC3XXX_I2S_RATES ( \ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) + +#define LPC3XXX_I2S_FORMATS ( \ + SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static void __lpc3xxx_find_clkdiv(u32 *clkx, u32 *clky, int freq, int xbytes, u32 clkrate) +{ + u32 i2srate; + u32 idxx, idyy; + u32 savedbitclkrate, diff, trate, baseclk; + + /* Adjust rate for sample size (bits) and 2 channels and offset for + * divider in clock output + */ + i2srate = (freq / 100) * 2 * (8 * xbytes); + i2srate = i2srate << 1; + clkrate = clkrate / 100; + baseclk = clkrate; + *clkx = 1; + *clky = 1; + + /* Find the best divider */ + *clkx = *clky = 0; + savedbitclkrate = 0; + diff = ~0; + for (idxx = 1; idxx < 0xFF; idxx++) { + for (idyy = 1; idyy < 0xFF; idyy++) { + trate = (baseclk * idxx) / idyy; + if (abs(trate - i2srate) < diff) { + diff = abs(trate - i2srate); + savedbitclkrate = trate; + *clkx = idxx; + *clky = idyy; + } + } + } +} + +static int lpc3xxx_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + struct device *dev = i2s_info_p->dev; + u32 flag; + int ret = 0; + + guard(mutex)(&i2s_info_p->lock); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + flag = I2S_PLAYBACK_FLAG; + else + flag = I2S_CAPTURE_FLAG; + + if (flag & i2s_info_p->streams_in_use) { + dev_warn(dev, "I2S channel is busy\n"); + ret = -EBUSY; + return ret; + } + + if (i2s_info_p->streams_in_use == 0) { + ret = clk_prepare_enable(i2s_info_p->clk); + if (ret) { + dev_err(dev, "Can't enable clock, err=%d\n", ret); + return ret; + } + } + + i2s_info_p->streams_in_use |= flag; + return 0; +} + +static void lpc3xxx_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regs = i2s_info_p->regs; + const u32 stop_bits = (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP); + u32 flag; + + guard(mutex)(&i2s_info_p->lock); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + flag = I2S_PLAYBACK_FLAG; + regmap_write(regs, LPC3XXX_REG_I2S_TX_RATE, 0); + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, stop_bits, stop_bits); + } else { + flag = I2S_CAPTURE_FLAG; + regmap_write(regs, LPC3XXX_REG_I2S_RX_RATE, 0); + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, stop_bits, stop_bits); + } + i2s_info_p->streams_in_use &= ~flag; + + if (i2s_info_p->streams_in_use == 0) + clk_disable_unprepare(i2s_info_p->clk); +} + +static int lpc3xxx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + + /* Will use in HW params later */ + i2s_info_p->freq = freq; + + return 0; +} + +static int lpc3xxx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + struct device *dev = i2s_info_p->dev; + + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) { + dev_warn(dev, "unsupported bus format %d\n", fmt); + return -EINVAL; + } + + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) { + dev_warn(dev, "unsupported clock provider %d\n", fmt); + return -EINVAL; + } + + return 0; +} + +static int lpc3xxx_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + struct device *dev = i2s_info_p->dev; + struct regmap *regs = i2s_info_p->regs; + int xfersize; + u32 tmp, clkx, clky; + + tmp = LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + tmp |= LPC3XXX_I2S_WW8 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW8_HP); + xfersize = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + tmp |= LPC3XXX_I2S_WW16 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW16_HP); + xfersize = 2; + break; + + case SNDRV_PCM_FORMAT_S32_LE: + tmp |= LPC3XXX_I2S_WW32 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW32_HP); + xfersize = 4; + break; + + default: + dev_warn(dev, "Unsupported audio data format %d\n", params_format(params)); + return -EINVAL; + } + + if (params_channels(params) == 1) + tmp |= LPC3XXX_I2S_MONO; + + __lpc3xxx_find_clkdiv(&clkx, &clky, i2s_info_p->freq, xfersize, i2s_info_p->clkrate); + + dev_dbg(dev, "Stream : %s\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + dev_dbg(dev, "Desired clock rate : %d\n", i2s_info_p->freq); + dev_dbg(dev, "Base clock rate : %d\n", i2s_info_p->clkrate); + dev_dbg(dev, "Transfer size (bytes) : %d\n", xfersize); + dev_dbg(dev, "Clock divider (x) : %d\n", clkx); + dev_dbg(dev, "Clock divider (y) : %d\n", clky); + dev_dbg(dev, "Channels : %d\n", params_channels(params)); + dev_dbg(dev, "Data format : %s\n", "I2S"); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_write(regs, LPC3XXX_REG_I2S_DMA1, + LPC3XXX_I2S_DMA1_TX_EN | LPC3XXX_I2S_DMA0_TX_DEPTH(4)); + regmap_write(regs, LPC3XXX_REG_I2S_TX_RATE, (clkx << 8) | clky); + regmap_write(regs, LPC3XXX_REG_I2S_DAO, tmp); + } else { + regmap_write(regs, LPC3XXX_REG_I2S_DMA0, + LPC3XXX_I2S_DMA0_RX_EN | LPC3XXX_I2S_DMA1_RX_DEPTH(4)); + regmap_write(regs, LPC3XXX_REG_I2S_RX_RATE, (clkx << 8) | clky); + regmap_write(regs, LPC3XXX_REG_I2S_DAI, tmp); + } + + return 0; +} + +static int lpc3xxx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regs = i2s_info_p->regs; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, + LPC3XXX_I2S_STOP, LPC3XXX_I2S_STOP); + else + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, + LPC3XXX_I2S_STOP, LPC3XXX_I2S_STOP); + break; + + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, + (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP), 0); + else + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, + (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP), 0); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int lpc3xxx_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &i2s_info_p->playback_dma_config, + &i2s_info_p->capture_dma_config); + return 0; +} + +const struct snd_soc_dai_ops lpc3xxx_i2s_dai_ops = { + .probe = lpc3xxx_i2s_dai_probe, + .startup = lpc3xxx_i2s_startup, + .shutdown = lpc3xxx_i2s_shutdown, + .trigger = lpc3xxx_i2s_trigger, + .hw_params = lpc3xxx_i2s_hw_params, + .set_sysclk = lpc3xxx_i2s_set_dai_sysclk, + .set_fmt = lpc3xxx_i2s_set_dai_fmt, +}; + +struct snd_soc_dai_driver lpc3xxx_i2s_dai_driver = { + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = LPC3XXX_I2S_RATES, + .formats = LPC3XXX_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = LPC3XXX_I2S_RATES, + .formats = LPC3XXX_I2S_FORMATS, + }, + .ops = &lpc3xxx_i2s_dai_ops, + .symmetric_rate = 1, + .symmetric_channels = 1, + .symmetric_sample_bits = 1, +}; + +static const struct snd_soc_component_driver lpc32xx_i2s_component = { + .name = "lpc32xx-i2s", + .legacy_dai_naming = 1, +}; + +static const struct regmap_config lpc32xx_i2s_regconfig = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = LPC3XXX_REG_I2S_RX_RATE, +}; + +static int lpc32xx_i2s_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct lpc3xxx_i2s_info *i2s_info_p; + struct resource *res; + void __iomem *iomem; + int ret; + + i2s_info_p = devm_kzalloc(dev, sizeof(*i2s_info_p), GFP_KERNEL); + if (!i2s_info_p) + return -ENOMEM; + + platform_set_drvdata(pdev, i2s_info_p); + i2s_info_p->dev = dev; + + iomem = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(iomem)) + return dev_err_probe(dev, PTR_ERR(iomem), "Can't map registers\n"); + + i2s_info_p->regs = devm_regmap_init_mmio(dev, iomem, &lpc32xx_i2s_regconfig); + if (IS_ERR(i2s_info_p->regs)) + return dev_err_probe(dev, PTR_ERR(i2s_info_p->regs), + "failed to init register map: %d\n", ret); + + i2s_info_p->clk = devm_clk_get(dev, NULL); + if (IS_ERR(i2s_info_p->clk)) + return dev_err_probe(dev, PTR_ERR(i2s_info_p->clk), "Can't get clock\n"); + + i2s_info_p->clkrate = clk_get_rate(i2s_info_p->clk); + if (i2s_info_p->clkrate == 0) + return dev_err_probe(dev, -EINVAL, "Invalid returned clock rate\n"); + + mutex_init(&i2s_info_p->lock); + + ret = devm_snd_soc_register_component(dev, &lpc32xx_i2s_component, + &lpc3xxx_i2s_dai_driver, 1); + if (ret) + return dev_err_probe(dev, ret, "Can't register cpu_dai component\n"); + + i2s_info_p->playback_dma_config.addr = (dma_addr_t)(res->start + LPC3XXX_REG_I2S_TX_FIFO); + i2s_info_p->playback_dma_config.maxburst = 4; + + i2s_info_p->capture_dma_config.addr = (dma_addr_t)(res->start + LPC3XXX_REG_I2S_RX_FIFO); + i2s_info_p->capture_dma_config.maxburst = 4; + + ret = lpc3xxx_pcm_register(pdev); + if (ret) + return dev_err_probe(dev, ret, "Can't register pcm component\n"); + + return 0; +} + +static const struct of_device_id lpc32xx_i2s_match[] = { + { .compatible = "nxp,lpc3220-i2s" }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_i2s_match); + +static struct platform_driver lpc32xx_i2s_driver = { + .probe = lpc32xx_i2s_probe, + .driver = { + .name = "lpc3xxx-i2s", + .of_match_table = lpc32xx_i2s_match, + }, +}; + +module_platform_driver(lpc32xx_i2s_driver); + +MODULE_AUTHOR("Kevin Wells "); +MODULE_AUTHOR("Piotr Wojtaszczyk "); +MODULE_DESCRIPTION("ASoC LPC3XXX I2S interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/lpc3xxx-i2s.h b/sound/soc/fsl/lpc3xxx-i2s.h new file mode 100644 index 000000000000..eec755448478 --- /dev/null +++ b/sound/soc/fsl/lpc3xxx-i2s.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * Copyright 2023 Timesys Corporation + */ + +#ifndef __SOUND_SOC_LPC3XXX_I2S_H +#define __SOUND_SOC_LPC3XXX_I2S_H + +#include +#include + +struct lpc3xxx_i2s_info { + struct device *dev; + struct clk *clk; + struct mutex lock; /* To serialize user-space access */ + struct regmap *regs; + u32 streams_in_use; + u32 clkrate; + int freq; + struct snd_dmaengine_dai_dma_data playback_dma_config; + struct snd_dmaengine_dai_dma_data capture_dma_config; +}; + +int lpc3xxx_pcm_register(struct platform_device *pdev); + +/* I2S controller register offsets */ +#define LPC3XXX_REG_I2S_DAO 0x00 +#define LPC3XXX_REG_I2S_DAI 0x04 +#define LPC3XXX_REG_I2S_TX_FIFO 0x08 +#define LPC3XXX_REG_I2S_RX_FIFO 0x0C +#define LPC3XXX_REG_I2S_STAT 0x10 +#define LPC3XXX_REG_I2S_DMA0 0x14 +#define LPC3XXX_REG_I2S_DMA1 0x18 +#define LPC3XXX_REG_I2S_IRQ 0x1C +#define LPC3XXX_REG_I2S_TX_RATE 0x20 +#define LPC3XXX_REG_I2S_RX_RATE 0x24 + +/* i2s_daO i2s_dai register definitions */ +#define LPC3XXX_I2S_WW8 FIELD_PREP(0x3, 0) /* Word width is 8bit */ +#define LPC3XXX_I2S_WW16 FIELD_PREP(0x3, 1) /* Word width is 16bit */ +#define LPC3XXX_I2S_WW32 FIELD_PREP(0x3, 3) /* Word width is 32bit */ +#define LPC3XXX_I2S_MONO BIT(2) /* Mono */ +#define LPC3XXX_I2S_STOP BIT(3) /* Stop, diables the access to FIFO, mutes the channel */ +#define LPC3XXX_I2S_RESET BIT(4) /* Reset the channel */ +#define LPC3XXX_I2S_WS_SEL BIT(5) /* Channel Master(0) or slave(1) mode select */ +#define LPC3XXX_I2S_WS_HP(s) FIELD_PREP(0x7FC0, s) /* Word select half period - 1 */ +#define LPC3XXX_I2S_MUTE BIT(15) /* Mute the channel, Transmit channel only */ + +#define LPC3XXX_I2S_WW32_HP 0x1f /* Word select half period for 32bit word width */ +#define LPC3XXX_I2S_WW16_HP 0x0f /* Word select half period for 16bit word width */ +#define LPC3XXX_I2S_WW8_HP 0x7 /* Word select half period for 8bit word width */ + +/* i2s_stat register definitions */ +#define LPC3XXX_I2S_IRQ_STAT BIT(0) +#define LPC3XXX_I2S_DMA0_REQ BIT(1) +#define LPC3XXX_I2S_DMA1_REQ BIT(2) + +/* i2s_dma0 Configuration register definitions */ +#define LPC3XXX_I2S_DMA0_RX_EN BIT(0) /* Enable RX DMA1 */ +#define LPC3XXX_I2S_DMA0_TX_EN BIT(1) /* Enable TX DMA1 */ +#define LPC3XXX_I2S_DMA0_RX_DEPTH(s) FIELD_PREP(0xF00, s) /* Set the DMA1 RX Request level */ +#define LPC3XXX_I2S_DMA0_TX_DEPTH(s) FIELD_PREP(0xF0000, s) /* Set the DMA1 TX Request level */ + +/* i2s_dma1 Configuration register definitions */ +#define LPC3XXX_I2S_DMA1_RX_EN BIT(0) /* Enable RX DMA1 */ +#define LPC3XXX_I2S_DMA1_TX_EN BIT(1) /* Enable TX DMA1 */ +#define LPC3XXX_I2S_DMA1_RX_DEPTH(s) FIELD_PREP(0x700, s) /* Set the DMA1 RX Request level */ +#define LPC3XXX_I2S_DMA1_TX_DEPTH(s) FIELD_PREP(0x70000, s) /* Set the DMA1 TX Request level */ + +/* i2s_irq register definitions */ +#define LPC3XXX_I2S_RX_IRQ_EN BIT(0) /* Enable RX IRQ */ +#define LPC3XXX_I2S_TX_IRQ_EN BIT(1) /* Enable TX IRQ */ +#define LPC3XXX_I2S_IRQ_RX_DEPTH(s) FIELD_PREP(0xFF00, s) /* valid values ar 0 to 7 */ +#define LPC3XXX_I2S_IRQ_TX_DEPTH(s) FIELD_PREP(0xFF0000, s) /* valid values ar 0 to 7 */ + +#endif diff --git a/sound/soc/fsl/lpc3xxx-pcm.c b/sound/soc/fsl/lpc3xxx-pcm.c new file mode 100644 index 000000000000..c0d499b9b8ba --- /dev/null +++ b/sound/soc/fsl/lpc3xxx-pcm.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Author: Kevin Wells +// +// Copyright (C) 2008 NXP Semiconductors +// Copyright 2023 Timesys Corporation + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "lpc3xxx-i2s.h" + +#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_U8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE | \ + SNDRV_PCM_FMTBIT_U32_LE | \ + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) + +static const struct snd_pcm_hardware lpc3xxx_pcm_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME), + .formats = STUB_FORMATS, + .period_bytes_min = 128, + .period_bytes_max = 2048, + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = 128 * 1024 +}; + +static const struct snd_dmaengine_pcm_config lpc3xxx_dmaengine_pcm_config = { + .pcm_hardware = &lpc3xxx_pcm_hardware, + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + .compat_filter_fn = pl08x_filter_id, + .prealloc_buffer_size = 128 * 1024, +}; + +const struct snd_soc_component_driver lpc3xxx_soc_platform_driver = { + .name = "lpc32xx-pcm", +}; + +int lpc3xxx_pcm_register(struct platform_device *pdev) +{ + int ret; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, &lpc3xxx_dmaengine_pcm_config, 0); + if (ret) { + dev_err(&pdev->dev, "failed to register dmaengine: %d\n", ret); + return ret; + } + + return devm_snd_soc_register_component(&pdev->dev, &lpc3xxx_soc_platform_driver, + NULL, 0); +} +EXPORT_SYMBOL(lpc3xxx_pcm_register); From 4adf454ff62883ee64b0b9818b951f34aa078d5a Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 28 Jun 2024 14:01:29 +0200 Subject: [PATCH 222/349] ASoC: soc-utils: allow sample rate up to 768kHz for the dummy dai The dummy DAI should allow any (reasonable) rates possible. Make the rate continuous for dummy and set range from 5512Hz to 768kHz The change is mostly cosmetic as dummy is skipped when setting the hwparams. Signed-off-by: Jerome Brunet Link: https://patch.msgid.link/20240628120130.2015665-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/soc-utils.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 11ba89c6b83c..303823dc45d7 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -144,7 +144,6 @@ static const struct snd_soc_component_driver dummy_codec = { .endianness = 1, }; -#define STUB_RATES SNDRV_PCM_RATE_8000_384000 #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_U8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ @@ -198,14 +197,18 @@ static struct snd_soc_dai_driver dummy_dai = { .stream_name = "Playback", .channels_min = 1, .channels_max = 384, - .rates = STUB_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = STUB_FORMATS, }, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 384, - .rates = STUB_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = STUB_FORMATS, }, .ops = &dummy_dai_ops, From 061505a1a61169bd25dd908f95ba22f33dffdd69 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 28 Jun 2024 13:24:06 +0800 Subject: [PATCH 223/349] ASoC: Remove unneeded semicolon ./sound/soc/codecs/ak4619.c:757:2-3: Unneeded semicolon Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=9442 Signed-off-by: Yang Li Link: https://patch.msgid.link/20240628052406.36644-1-yang.lee@linux.alibaba.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4619.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ak4619.c b/sound/soc/codecs/ak4619.c index cbe27abe1f50..8f2442482f72 100644 --- a/sound/soc/codecs/ak4619.c +++ b/sound/soc/codecs/ak4619.c @@ -754,7 +754,7 @@ static void ak4619_hw_constraints(struct ak4619_priv *ak4619, default: break; } - }; + } constraint->list = ak4619_sr; constraint->mask = ak4619_rate_mask; From 1a70579723fde3624a72dfea6e79e55be6e36659 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Fri, 28 Jun 2024 16:05:34 +0800 Subject: [PATCH 224/349] ASoC: max98088: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Fixes: 62a7fc32a628 ("ASoC: max98088: Add master clock handling") Signed-off-by: Chen Ni Link: https://patch.msgid.link/20240628080534.843815-1-nichen@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 8b56ee550c09..8b0645c63462 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1318,6 +1318,7 @@ static int max98088_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component); + int ret; switch (level) { case SND_SOC_BIAS_ON: @@ -1333,10 +1334,13 @@ static int max98088_set_bias_level(struct snd_soc_component *component, */ if (!IS_ERR(max98088->mclk)) { if (snd_soc_component_get_bias_level(component) == - SND_SOC_BIAS_ON) + SND_SOC_BIAS_ON) { clk_disable_unprepare(max98088->mclk); - else - clk_prepare_enable(max98088->mclk); + } else { + ret = clk_prepare_enable(max98088->mclk); + if (ret) + return ret; + } } break; From 288921232dd97bb2e35cff2ee38957db5b3e5ef1 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 27 Jun 2024 17:52:59 +0800 Subject: [PATCH 225/349] ASoC: dt-bindings: fsl,xcvr: Adjust the number of interrupts On i.MX8MP, there are 3 interrupts, the third interrupt is SPDIF wakeup interrupt from PHY Add ref: dai-common.yaml for #sound-dai-cells is needed and XCVR is a DAI device. Signed-off-by: Shengjiu Wang Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/1719481981-4069-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,xcvr.yaml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml index 197ae8ba9c30..5e2801014221 100644 --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml @@ -42,6 +42,7 @@ properties: items: - description: WAKEUPMIX Audio XCVR Interrupt 1 - description: WAKEUPMIX Audio XCVR Interrupt 2 + - description: SPDIF wakeup interrupt from PHY minItems: 1 clocks: @@ -88,6 +89,7 @@ required: - dma-names allOf: + - $ref: dai-common.yaml# - if: properties: compatible: @@ -112,7 +114,8 @@ allOf: else: properties: interrupts: - maxItems: 1 + minItems: 3 + maxItems: 3 - if: properties: @@ -128,7 +131,7 @@ allOf: clock-names: maxItems: 4 -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -143,7 +146,9 @@ examples: <0x30cc0c00 0x080>, <0x30cc0e00 0x080>; reg-names = "ram", "regs", "rxfifo", "txfifo"; - interrupts = <0x0 128 IRQ_TYPE_LEVEL_HIGH>; + interrupts = , + , + ; clocks = <&audiomix_clk IMX8MP_CLK_AUDIOMIX_EARC_IPG>, <&audiomix_clk IMX8MP_CLK_AUDIOMIX_EARC_PHY>, <&audiomix_clk IMX8MP_CLK_AUDIOMIX_SPBA2_ROOT>, From 730674b21db12be6ea6b3034c618de5d7a16987d Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 28 Jun 2024 14:32:54 +0200 Subject: [PATCH 226/349] ASoC: meson: tdm: add sample rate support up to 768kHz Add support for 705.6kHz and 768kHz sample rates Signed-off-by: Jerome Brunet Link: https://patch.msgid.link/20240628123256.2019224-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-fifo.c | 2 +- sound/soc/meson/axg-frddr.c | 4 ++-- sound/soc/meson/axg-tdm.h | 2 +- sound/soc/meson/axg-toddr.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index 59abe0b3c59f..7e6090af720b 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -32,7 +32,7 @@ static const struct snd_pcm_hardware axg_fifo_hw = { SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), .formats = AXG_FIFO_FORMATS, .rate_min = 5512, - .rate_max = 384000, + .rate_max = 768000, .channels_min = 1, .channels_max = AXG_FIFO_CH_MAX, .period_bytes_min = AXG_FIFO_BURST, diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index e97d43ae7fd2..e70c8c34c7db 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -112,7 +112,7 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = { .channels_max = AXG_FIFO_CH_MAX, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 5515, - .rate_max = 384000, + .rate_max = 768000, .formats = AXG_FIFO_FORMATS, }, .ops = &axg_frddr_ops, @@ -189,7 +189,7 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = { .channels_max = AXG_FIFO_CH_MAX, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 5515, - .rate_max = 384000, + .rate_max = 768000, .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_frddr_ops, diff --git a/sound/soc/meson/axg-tdm.h b/sound/soc/meson/axg-tdm.h index daaca10fec9e..1a17f546ce6e 100644 --- a/sound/soc/meson/axg-tdm.h +++ b/sound/soc/meson/axg-tdm.h @@ -16,7 +16,7 @@ #define AXG_TDM_NUM_LANES 4 #define AXG_TDM_CHANNEL_MAX 128 #define AXG_TDM_RATES (SNDRV_PCM_RATE_5512 | \ - SNDRV_PCM_RATE_8000_384000) + SNDRV_PCM_RATE_8000_768000) #define AXG_TDM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_LE | \ diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index e03a6e21c1c6..03512da4092b 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -131,7 +131,7 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = { .channels_max = AXG_FIFO_CH_MAX, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 5515, - .rate_max = 384000, + .rate_max = 768000, .formats = AXG_FIFO_FORMATS, }, .ops = &axg_toddr_ops, @@ -228,7 +228,7 @@ static struct snd_soc_dai_driver g12a_toddr_dai_drv = { .channels_max = AXG_FIFO_CH_MAX, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 5515, - .rate_max = 384000, + .rate_max = 768000, .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_toddr_ops, From 5d7e328e20b3d2bd3e1e8bea7a868ab8892aeed1 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 1 Jul 2024 11:44:42 +0100 Subject: [PATCH 227/349] ASoC: cs35l56: Revert support for dual-ownership of ASP registers This patch reverts a series of commits that allowed for the ASP registers to be owned by either the driver or the firmware. Nothing currently depends on the functionality that is being reverted, so it is safe to remove. The commits being reverted are (last 3 are bugfixes to the first 2): commit 72a77d7631c6 ("ASoC: cs35l56: Fix to ensure ASP1 registers match cache") commit 07f7d6e7a124 ("ASoC: cs35l56: Fix for initializing ASP1 mixer registers") commit 4703b014f28b ("ASoC: cs35l56: fix reversed if statement in cs35l56_dspwait_asp1tx_put()") commit c14f09f010cc ("ASoC: cs35l56: Fix deadlock in ASP1 mixer register initialization") commit dfd2ffb37399 ("ASoC: cs35l56: Prevent overwriting firmware ASP config") These reverts have been squashed into a single commit because there would be no reason to revert only some of them (which would just reintroduce bugs). The changes introduced by the commits were well-intentioned but somewhat misguided. ACPI does not provide any information about how audio hardware is linked together, so that information has to be hardcoded into drivers. On Windows the firmware is customized to statically setup appropriate configuration of the audio links, and the intent of the commits was to re-use this information if the Linux host drivers aren't taking control of the ASP. This would avoid having to hardcode the ASP config into the machine driver on some systems. However, this added complexity and race conditions into the driver. It also complicates implementation of new code. The only case where the ASP is used but the host is not taking ownership is when CS35L56 is used in SoundWire mode with the ASP as a reference audio interconnect. But even in that case it's not necessarily required even if the firmware initialized it. Typically it is used to avoid the host SDCA drivers having to be capable of aggregating capture paths from multiple SoundWire peripherals. But the SOF SoundWire support is capable of doing that aggregation. Reverting all these commits significantly simplifies the driver. Let's just use the normal Linux mechanisms of the machine driver and ALSA controls to set things up instead of trying to use the firmware to do use-case setup. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20240701104444.172556-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 9 +- sound/soc/codecs/cs35l56-shared.c | 101 ++++----------- sound/soc/codecs/cs35l56.c | 205 ++---------------------------- sound/soc/codecs/cs35l56.h | 1 - 4 files changed, 43 insertions(+), 273 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 1a3c6f66f620..2e19722989f7 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -267,13 +267,18 @@ struct cs35l56_base { bool fw_patched; bool secured; bool can_hibernate; - bool fw_owns_asp1; bool cal_data_valid; s8 cal_index; struct cirrus_amp_cal_data cal_data; struct gpio_desc *reset_gpio; }; +/* Temporary to avoid a build break with the HDA driver */ +static inline int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base) +{ + return 0; +} + extern struct regmap_config cs35l56_regmap_i2c; extern struct regmap_config cs35l56_regmap_spi; extern struct regmap_config cs35l56_regmap_sdw; @@ -284,8 +289,6 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC]; extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; int cs35l56_set_patch(struct cs35l56_base *cs35l56_base); -int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base); -int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base); int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command); int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base); int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 880228f89baf..035d7c3c4683 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -20,6 +20,18 @@ static const struct reg_sequence cs35l56_patch[] = { * Firmware can change these to non-defaults to satisfy SDCA. * Ensure that they are at known defaults. */ + { CS35L56_ASP1_ENABLES1, 0x00000000 }, + { CS35L56_ASP1_CONTROL1, 0x00000028 }, + { CS35L56_ASP1_CONTROL2, 0x18180200 }, + { CS35L56_ASP1_CONTROL3, 0x00000002 }, + { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 }, + { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 }, + { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 }, + { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 }, + { CS35L56_ASP1TX1_INPUT, 0x00000000 }, + { CS35L56_ASP1TX2_INPUT, 0x00000000 }, + { CS35L56_ASP1TX3_INPUT, 0x00000000 }, + { CS35L56_ASP1TX4_INPUT, 0x00000000 }, { CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 }, { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 }, { CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 }, @@ -41,12 +53,18 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED); static const struct reg_default cs35l56_reg_defaults[] = { /* no defaults for OTP_MEM - first read populates cache */ - /* - * No defaults for ASP1 control or ASP1TX mixer. See - * cs35l56_populate_asp1_register_defaults() and - * cs35l56_sync_asp1_mixer_widgets_with_firmware(). - */ - + { CS35L56_ASP1_ENABLES1, 0x00000000 }, + { CS35L56_ASP1_CONTROL1, 0x00000028 }, + { CS35L56_ASP1_CONTROL2, 0x18180200 }, + { CS35L56_ASP1_CONTROL3, 0x00000002 }, + { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 }, + { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 }, + { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 }, + { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 }, + { CS35L56_ASP1TX1_INPUT, 0x00000000 }, + { CS35L56_ASP1TX2_INPUT, 0x00000000 }, + { CS35L56_ASP1TX3_INPUT, 0x00000000 }, + { CS35L56_ASP1TX4_INPUT, 0x00000000 }, { CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 }, { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 }, { CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 }, @@ -206,77 +224,6 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg) } } -static const struct reg_sequence cs35l56_asp1_defaults[] = { - REG_SEQ0(CS35L56_ASP1_ENABLES1, 0x00000000), - REG_SEQ0(CS35L56_ASP1_CONTROL1, 0x00000028), - REG_SEQ0(CS35L56_ASP1_CONTROL2, 0x18180200), - REG_SEQ0(CS35L56_ASP1_CONTROL3, 0x00000002), - REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL1, 0x03020100), - REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL5, 0x00020100), - REG_SEQ0(CS35L56_ASP1_DATA_CONTROL1, 0x00000018), - REG_SEQ0(CS35L56_ASP1_DATA_CONTROL5, 0x00000018), - REG_SEQ0(CS35L56_ASP1TX1_INPUT, 0x00000000), - REG_SEQ0(CS35L56_ASP1TX2_INPUT, 0x00000000), - REG_SEQ0(CS35L56_ASP1TX3_INPUT, 0x00000000), - REG_SEQ0(CS35L56_ASP1TX4_INPUT, 0x00000000), -}; - -/* - * The firmware can have control of the ASP so we don't provide regmap - * with defaults for these registers, to prevent a regcache_sync() from - * overwriting the firmware settings. But if the machine driver hooks up - * the ASP it means the driver is taking control of the ASP, so then the - * registers are populated with the defaults. - */ -int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base) -{ - if (!cs35l56_base->fw_owns_asp1) - return 0; - - cs35l56_base->fw_owns_asp1 = false; - - return regmap_multi_reg_write(cs35l56_base->regmap, cs35l56_asp1_defaults, - ARRAY_SIZE(cs35l56_asp1_defaults)); -} -EXPORT_SYMBOL_NS_GPL(cs35l56_init_asp1_regs_for_driver_control, SND_SOC_CS35L56_SHARED); - -/* - * The firmware boot sequence can overwrite the ASP1 config registers so that - * they don't match regmap's view of their values. Rewrite the values from the - * regmap cache into the hardware registers. - */ -int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base) -{ - struct reg_sequence asp1_regs[ARRAY_SIZE(cs35l56_asp1_defaults)]; - int i, ret; - - if (cs35l56_base->fw_owns_asp1) - return 0; - - memcpy(asp1_regs, cs35l56_asp1_defaults, sizeof(asp1_regs)); - - /* Read current values from regmap cache into the write sequence */ - for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) { - ret = regmap_read(cs35l56_base->regmap, asp1_regs[i].reg, &asp1_regs[i].def); - if (ret) - goto err; - } - - /* Write the values cache-bypassed so that they will be written to silicon */ - ret = regmap_multi_reg_write_bypassed(cs35l56_base->regmap, asp1_regs, - ARRAY_SIZE(asp1_regs)); - if (ret) - goto err; - - return 0; - -err: - dev_err(cs35l56_base->dev, "Failed to sync ASP1 registers: %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_NS_GPL(cs35l56_force_sync_asp1_registers_from_cache, SND_SOC_CS35L56_SHARED); - int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command) { unsigned int val; diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 758dfdf9d3ea..7cac9812f5b5 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -63,131 +63,6 @@ static int cs35l56_dspwait_put_volsw(struct snd_kcontrol *kcontrol, return snd_soc_put_volsw(kcontrol, ucontrol); } -static const unsigned short cs35l56_asp1_mixer_regs[] = { - CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX2_INPUT, - CS35L56_ASP1TX3_INPUT, CS35L56_ASP1TX4_INPUT, -}; - -static const char * const cs35l56_asp1_mux_control_names[] = { - "ASP1 TX1 Source", "ASP1 TX2 Source", "ASP1 TX3 Source", "ASP1 TX4 Source" -}; - -static int cs35l56_sync_asp1_mixer_widgets_with_firmware(struct cs35l56_private *cs35l56) -{ - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component); - const char *prefix = cs35l56->component->name_prefix; - char full_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - const char *name; - struct snd_kcontrol *kcontrol; - struct soc_enum *e; - unsigned int val[4]; - int i, item, ret; - - if (cs35l56->asp1_mixer_widgets_initialized) - return 0; - - /* - * Resume so we can read the registers from silicon if the regmap - * cache has not yet been populated. - */ - ret = pm_runtime_resume_and_get(cs35l56->base.dev); - if (ret < 0) - return ret; - - /* Wait for firmware download and reboot */ - cs35l56_wait_dsp_ready(cs35l56); - - ret = regmap_bulk_read(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT, - val, ARRAY_SIZE(val)); - - pm_runtime_mark_last_busy(cs35l56->base.dev); - pm_runtime_put_autosuspend(cs35l56->base.dev); - - if (ret) { - dev_err(cs35l56->base.dev, "Failed to read ASP1 mixer regs: %d\n", ret); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(cs35l56_asp1_mux_control_names); ++i) { - name = cs35l56_asp1_mux_control_names[i]; - - if (prefix) { - snprintf(full_name, sizeof(full_name), "%s %s", prefix, name); - name = full_name; - } - - kcontrol = snd_soc_card_get_kcontrol_locked(dapm->card, name); - if (!kcontrol) { - dev_warn(cs35l56->base.dev, "Could not find control %s\n", name); - continue; - } - - e = (struct soc_enum *)kcontrol->private_value; - item = snd_soc_enum_val_to_item(e, val[i] & CS35L56_ASP_TXn_SRC_MASK); - snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL); - } - - cs35l56->asp1_mixer_widgets_initialized = true; - - return 0; -} - -static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); - struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int index = e->shift_l; - unsigned int addr, val; - int ret; - - ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56); - if (ret) - return ret; - - addr = cs35l56_asp1_mixer_regs[index]; - ret = regmap_read(cs35l56->base.regmap, addr, &val); - if (ret) - return ret; - - val &= CS35L56_ASP_TXn_SRC_MASK; - ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); - - return 0; -} - -static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); - struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); - struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int item = ucontrol->value.enumerated.item[0]; - int index = e->shift_l; - unsigned int addr, val; - bool changed; - int ret; - - ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56); - if (ret) - return ret; - - addr = cs35l56_asp1_mixer_regs[index]; - val = snd_soc_enum_item_to_val(e, item); - - ret = regmap_update_bits_check(cs35l56->base.regmap, addr, - CS35L56_ASP_TXn_SRC_MASK, val, &changed); - if (ret) - return ret; - - if (changed) - snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL); - - return changed; -} - static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0); static const struct snd_kcontrol_new cs35l56_controls[] = { @@ -206,44 +81,40 @@ static const struct snd_kcontrol_new cs35l56_controls[] = { }; static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx1_enum, - SND_SOC_NOPM, - 0, 0, + CS35L56_ASP1TX1_INPUT, + 0, CS35L56_ASP_TXn_SRC_MASK, cs35l56_tx_input_texts, cs35l56_tx_input_values); static const struct snd_kcontrol_new asp1_tx1_mux = - SOC_DAPM_ENUM_EXT("ASP1TX1 SRC", cs35l56_asp1tx1_enum, - cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put); + SOC_DAPM_ENUM("ASP1TX1 SRC", cs35l56_asp1tx1_enum); static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx2_enum, - SND_SOC_NOPM, - 1, 0, + CS35L56_ASP1TX2_INPUT, + 0, CS35L56_ASP_TXn_SRC_MASK, cs35l56_tx_input_texts, cs35l56_tx_input_values); static const struct snd_kcontrol_new asp1_tx2_mux = - SOC_DAPM_ENUM_EXT("ASP1TX2 SRC", cs35l56_asp1tx2_enum, - cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put); + SOC_DAPM_ENUM("ASP1TX2 SRC", cs35l56_asp1tx2_enum); static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx3_enum, - SND_SOC_NOPM, - 2, 0, + CS35L56_ASP1TX3_INPUT, + 0, CS35L56_ASP_TXn_SRC_MASK, cs35l56_tx_input_texts, cs35l56_tx_input_values); static const struct snd_kcontrol_new asp1_tx3_mux = - SOC_DAPM_ENUM_EXT("ASP1TX3 SRC", cs35l56_asp1tx3_enum, - cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put); + SOC_DAPM_ENUM("ASP1TX3 SRC", cs35l56_asp1tx3_enum); static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx4_enum, - SND_SOC_NOPM, - 3, 0, + CS35L56_ASP1TX4_INPUT, + 0, CS35L56_ASP_TXn_SRC_MASK, cs35l56_tx_input_texts, cs35l56_tx_input_values); static const struct snd_kcontrol_new asp1_tx4_mux = - SOC_DAPM_ENUM_EXT("ASP1TX4 SRC", cs35l56_asp1tx4_enum, - cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put); + SOC_DAPM_ENUM("ASP1TX4 SRC", cs35l56_asp1tx4_enum); static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx1_enum, CS35L56_SWIRE_DP3_CH1_INPUT, @@ -281,21 +152,6 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx4_enum, static const struct snd_kcontrol_new sdw1_tx4_mux = SOC_DAPM_ENUM("SDW1TX4 SRC", cs35l56_sdw1tx4_enum); -static int cs35l56_asp1_cfg_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 cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /* Override register values set by firmware boot */ - return cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); - default: - return 0; - } -} - static int cs35l56_play_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -332,9 +188,6 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = { SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_B", 0, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_AMP", 0, 0), - SND_SOC_DAPM_SUPPLY("ASP1 CFG", SND_SOC_NOPM, 0, 0, cs35l56_asp1_cfg_event, - SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_SUPPLY("PLAY", SND_SOC_NOPM, 0, 0, cs35l56_play_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), @@ -402,9 +255,6 @@ static const struct snd_soc_dapm_route cs35l56_audio_map[] = { { "AMP", NULL, "VDD_B" }, { "AMP", NULL, "VDD_AMP" }, - { "ASP1 Playback", NULL, "ASP1 CFG" }, - { "ASP1 Capture", NULL, "ASP1 CFG" }, - { "ASP1 Playback", NULL, "PLAY" }, { "SDW1 Playback", NULL, "PLAY" }, @@ -455,14 +305,9 @@ 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; - int ret; dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt); - ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); - if (ret) - return ret; - switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { case SND_SOC_DAIFMT_CBC_CFC: break; @@ -536,11 +381,6 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx unsigned int rx_mask, int slots, int slot_width) { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); - int ret; - - ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); - if (ret) - return ret; if ((slots == 0) || (slot_width == 0)) { dev_dbg(cs35l56->base.dev, "tdm config cleared\n"); @@ -589,11 +429,6 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream, struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); unsigned int rate = params_rate(params); u8 asp_width, asp_wl; - int ret; - - ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); - if (ret) - return ret; asp_wl = params_width(params); if (cs35l56->asp_slot_width) @@ -650,11 +485,7 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); - int freq_id, ret; - - ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); - if (ret) - return ret; + int freq_id; if (freq == 0) { cs35l56->sysclk_set = false; @@ -1035,13 +866,6 @@ static int cs35l56_component_probe(struct snd_soc_component *component) debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate); debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched); - /* - * The widgets for the ASP1TX mixer can't be initialized - * until the firmware has been downloaded and rebooted. - */ - regcache_drop_region(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX4_INPUT); - cs35l56->asp1_mixer_widgets_initialized = false; - queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work); return 0; @@ -1432,9 +1256,6 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) cs35l56->base.cal_index = -1; cs35l56->speaker_id = -ENOENT; - /* Assume that the firmware owns ASP1 until we know different */ - cs35l56->base.fw_owns_asp1 = true; - dev_set_drvdata(cs35l56->base.dev, cs35l56); cs35l56_fill_supply_names(cs35l56->supplies); diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index b000e7365e40..200f695efca3 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -51,7 +51,6 @@ struct cs35l56_private { u8 asp_slot_count; bool tdm_mode; bool sysclk_set; - bool asp1_mixer_widgets_initialized; u8 old_sdw_clock_scale; }; From e2996141d6db0d8b353e1c221a37c8e1be109d4a Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 1 Jul 2024 11:44:43 +0100 Subject: [PATCH 228/349] ASoC: cs35l56: Remove support for A1 silicon No product was ever released with A1 silicon so there is no need for the driver to include support for it. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20240701104444.172556-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 2 - sound/soc/codecs/cs35l56-sdw.c | 74 ------------------------------- sound/soc/codecs/cs35l56-shared.c | 21 +-------- sound/soc/codecs/cs35l56.h | 1 - 4 files changed, 2 insertions(+), 96 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 2e19722989f7..642ef690ebc2 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -80,9 +80,7 @@ #define CS35L56_DSP1_AHBM_WINDOW_DEBUG_1 0x25E2044 #define CS35L56_DSP1_XMEM_UNPACKED24_0 0x2800000 #define CS35L56_DSP1_FW_VER 0x2800010 -#define CS35L56_DSP1_HALO_STATE_A1 0x2801E58 #define CS35L56_DSP1_HALO_STATE 0x28021E0 -#define CS35L56_DSP1_PM_CUR_STATE_A1 0x2804000 #define CS35L56_DSP1_PM_CUR_STATE 0x2804308 #define CS35L56_DSP1_XMEM_UNPACKED24_8191 0x2807FFC #define CS35L56_DSP1_CORE_BASE 0x2B80000 diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 70ff55c1517f..8862107105ae 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -317,79 +317,6 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral, return 0; } -static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56, - struct sdw_slave *peripheral) -{ - unsigned int curr_scale_reg, next_scale_reg; - int curr_scale, next_scale, ret; - - if (!cs35l56->base.init_done) - return 0; - - if (peripheral->bus->params.curr_bank) { - curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1; - next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0; - } else { - curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0; - next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1; - } - - /* - * Current clock scale value must be different to new value. - * Modify current to guarantee this. If next still has the dummy - * value we wrote when it was current, the core code has not set - * a new scale so restore its original good value - */ - curr_scale = sdw_read_no_pm(peripheral, curr_scale_reg); - if (curr_scale < 0) { - 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->base.dev, "Failed to read next clock scale: %d\n", next_scale); - return next_scale; - } - - if (next_scale == CS35L56_SDW_INVALID_BUS_SCALE) { - next_scale = cs35l56->old_sdw_clock_scale; - ret = sdw_write_no_pm(peripheral, next_scale_reg, next_scale); - if (ret < 0) { - dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", - ret); - return ret; - } - } - - 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->base.dev, "Failed to modify current clock scale: %d\n", ret); - return ret; - } - - dev_dbg(cs35l56->base.dev, "Next bus scale: %#x\n", next_scale); - - return 0; -} - -static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral, - struct sdw_bus_params *params) -{ - struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); - int sclk; - - sclk = params->curr_dr_freq / 2; - dev_dbg(cs35l56->base.dev, "%s: sclk=%u c=%u r=%u\n", - __func__, sclk, params->col, params->row); - - if ((cs35l56->base.type == 0x56) && (cs35l56->base.rev < 0xb0)) - return cs35l56_a1_kick_divider(cs35l56, peripheral); - - return 0; -} - static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral, enum sdw_clk_stop_mode mode, enum sdw_clk_stop_type type) @@ -405,7 +332,6 @@ static const struct sdw_slave_ops cs35l56_sdw_ops = { .read_prop = cs35l56_sdw_read_prop, .interrupt_callback = cs35l56_sdw_interrupt, .update_status = cs35l56_sdw_update_status, - .bus_config = cs35l56_sdw_bus_config, #ifdef DEBUG .clk_stop = cs35l56_sdw_clk_stop, #endif diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 035d7c3c4683..e7e8d617da94 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -245,19 +245,13 @@ 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, + ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP1_PM_CUR_STATE, val, (val == CS35L56_HALO_STATE_SHUTDOWN), CS35L56_HALO_STATE_POLL_US, CS35L56_HALO_STATE_TIMEOUT_US); @@ -270,15 +264,9 @@ 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; unsigned int val = 0; int read_ret, poll_ret; - if (cs35l56_base->rev < CS35L56_REVID_B0) - reg = CS35L56_DSP1_HALO_STATE_A1; - else - reg = CS35L56_DSP1_HALO_STATE; - /* * The regmap must remain in cache-only until the chip has * booted, so use a bypassed read of the status register. @@ -288,7 +276,7 @@ int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) CS35L56_HALO_STATE_POLL_US, CS35L56_HALO_STATE_TIMEOUT_US, false, - cs35l56_base->regmap, reg, &val); + cs35l56_base->regmap, CS35L56_DSP1_HALO_STATE, &val); if (poll_ret) { dev_err(cs35l56_base->dev, "Firmware boot timed out(%d): HALO_STATE=%#x\n", @@ -726,11 +714,6 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) else cs35l56_wait_control_port_ready(); - /* - * 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_bypassed(cs35l56_base->regmap, CS35L56_REVID, &revid); if (ret < 0) { dev_err(cs35l56_base->dev, "Get Revision ID failed\n"); diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index 200f695efca3..8a987ec01507 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -51,7 +51,6 @@ struct cs35l56_private { u8 asp_slot_count; bool tdm_mode; bool sysclk_set; - u8 old_sdw_clock_scale; }; extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi; From e5524e3316ac54ca04dde3bfef4565bacf72c594 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 1 Jul 2024 11:44:44 +0100 Subject: [PATCH 229/349] ASoC: cs35l56: Remove redundant clearing of clk_stop_mode1 struct sdw_slave_prop is zero-initialized by the SoundWire core so there is no need to clear clk_stop_mode1 to false. Removing this also avoids having an unnecessary build dependency on a struct member. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20240701104444.172556-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56-sdw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 8862107105ae..fc03bb7ecae1 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -271,7 +271,6 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) prop->source_ports = BIT(CS35L56_SDW1_CAPTURE_PORT); prop->sink_ports = BIT(CS35L56_SDW1_PLAYBACK_PORT); prop->paging_support = true; - prop->clk_stop_mode1 = false; prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | SDW_SCP_INT1_IMPL_DEF; From 8e5c11963c5ca4af90b36147cabb4835e59990aa Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 26 Jun 2024 16:12:01 +0900 Subject: [PATCH 230/349] ASoC: dt-bindings: fsl_rpmsg: Add compatible string for i.MX95 Add compatible string for i.MX95 platform which supports audio function through rpmsg channel between Cortex-A and Cortex-M core. Signed-off-by: Chancel Liu Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240626071202.7149-1-chancel.liu@nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml index 188f38baddec..3d5d435c765b 100644 --- a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml @@ -29,6 +29,7 @@ properties: - fsl,imx8mp-rpmsg-audio - fsl,imx8ulp-rpmsg-audio - fsl,imx93-rpmsg-audio + - fsl,imx95-rpmsg-audio clocks: items: From 19dec6650e3fd02de8752c4e0ab1c4894ce7fcb7 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 26 Jun 2024 16:12:02 +0900 Subject: [PATCH 231/349] ASoC: fsl_rpmsg: Add support for i.MX95 platform Add compatible string and specific soc data to support rpmsg sound card on i.MX95 platform. Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Link: https://patch.msgid.link/20240626071202.7149-2-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_rpmsg.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index bc41a0666856..467d6bc9f956 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -175,6 +175,14 @@ static const struct fsl_rpmsg_soc_data imx93_data = { SNDRV_PCM_FMTBIT_S32_LE, }; +static const struct fsl_rpmsg_soc_data imx95_data = { + .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | 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}, @@ -182,6 +190,7 @@ static const struct of_device_id fsl_rpmsg_ids[] = { { .compatible = "fsl,imx8mp-rpmsg-audio", .data = &imx8mp_data}, { .compatible = "fsl,imx8ulp-rpmsg-audio", .data = &imx7ulp_data}, { .compatible = "fsl,imx93-rpmsg-audio", .data = &imx93_data}, + { .compatible = "fsl,imx95-rpmsg-audio", .data = &imx95_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids); From 878f4c36f9235e8a15fe0c2ecde066d92c50c8ff Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Mon, 24 Jun 2024 18:59:44 +0530 Subject: [PATCH 232/349] ASoC: dt-bindings: realtek,rt5659: Convert to dtschema Convert the RT5659/RT5658 audio CODEC bindings to DT schema. Signed-off-by: Animesh Agarwal Cc: Daniel Baluta Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240624132949.124228-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/realtek,rt5659.yaml | 129 ++++++++++++++++++ .../devicetree/bindings/sound/rt5659.txt | 89 ------------ 2 files changed, 129 insertions(+), 89 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/realtek,rt5659.yaml delete mode 100644 Documentation/devicetree/bindings/sound/rt5659.txt diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5659.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5659.yaml new file mode 100644 index 000000000000..1100ffd9a7c0 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,rt5659.yaml @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,rt5659.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RT5659/RT5658 audio CODEC + +maintainers: + - Animesh Agarwal + +description: | + This device supports I2C only. + + Pins on the device (for linking into audio routes) for RT5659/RT5658: + * DMIC L1 + * DMIC R1 + * DMIC L2 + * DMIC R2 + * IN1P + * IN1N + * IN2P + * IN2N + * IN3P + * IN3N + * IN4P + * IN4N + * HPOL + * HPOR + * SPOL + * SPOR + * LOUTL + * LOUTR + * MONOOUT + * PDML + * PDMR + * SPDIF + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - realtek,rt5659 + - realtek,rt5658 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: mclk + + realtek,dmic1-data-pin: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # dmic1 is not used + - 1 # using IN2N pin as dmic1 data pin + - 2 # using GPIO5 pin as dmic1 data pin + - 3 # using GPIO9 pin as dmic1 data pin + - 4 # using GPIO11 pin as dmic1 data pin + description: Specify which pin to be used as DMIC1 data pin. + default: 0 + + realtek,dmic2-data-pin: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # dmic2 is not used + - 1 # using IN2P pin as dmic2 data pin + - 2 # using GPIO6 pin as dmic2 data pin + - 3 # using GPIO10 pin as dmic2 data pin + - 4 # using GPIO12 pin as dmic2 data pin + description: Specify which pin to be used as DMIC2 data pin. + default: 0 + + realtek,jd-src: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # No JD is used + - 1 # using JD3 as JD source + - 2 # JD source for Intel HDA header + description: Specify which JD source be used. + default: 0 + + realtek,ldo1-en-gpios: + maxItems: 1 + description: CODEC's LDO1_EN pin. + + realtek,reset-gpios: + maxItems: 1 + description: CODEC's RESET pin. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1b { + compatible = "realtek,rt5659"; + reg = <0x1b>; + interrupt-parent = <&gpio>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + realtek,ldo1-en-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt deleted file mode 100644 index 8f3f62c0226a..000000000000 --- a/Documentation/devicetree/bindings/sound/rt5659.txt +++ /dev/null @@ -1,89 +0,0 @@ -RT5659/RT5658 audio CODEC - -This device supports I2C only. - -Required properties: - -- compatible : One of "realtek,rt5659" or "realtek,rt5658". - -- reg : The I2C address of the device. - -- interrupts : The CODEC's interrupt output. - -Optional properties: - -- clocks: The phandle of the master clock to the CODEC -- clock-names: Should be "mclk" - -- realtek,in1-differential -- realtek,in3-differential -- realtek,in4-differential - Boolean. Indicate MIC1/3/4 input are differential, rather than single-ended. - -- realtek,dmic1-data-pin - 0: dmic1 is not used - 1: using IN2N pin as dmic1 data pin - 2: using GPIO5 pin as dmic1 data pin - 3: using GPIO9 pin as dmic1 data pin - 4: using GPIO11 pin as dmic1 data pin - -- realtek,dmic2-data-pin - 0: dmic2 is not used - 1: using IN2P pin as dmic2 data pin - 2: using GPIO6 pin as dmic2 data pin - 3: using GPIO10 pin as dmic2 data pin - 4: using GPIO12 pin as dmic2 data pin - -- realtek,jd-src - 0: No JD is used - 1: using JD3 as JD source - 2: JD source for Intel HDA header - -- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. -- realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin. - -- sound-name-prefix: Please refer to dai-common.yaml - -- ports: A Codec may have a single or multiple I2S interfaces. These - interfaces on Codec side can be described under 'ports' or 'port'. - When the SoC or host device is connected to multiple interfaces of - the Codec, the connectivity can be described using 'ports' property. - If a single interface is used, then 'port' can be used. The usage - depends on the platform or board design. - Please refer to Documentation/devicetree/bindings/graph.txt - -Pins on the device (for linking into audio routes) for RT5659/RT5658: - - * DMIC L1 - * DMIC R1 - * DMIC L2 - * DMIC R2 - * IN1P - * IN1N - * IN2P - * IN2N - * IN3P - * IN3N - * IN4P - * IN4N - * HPOL - * HPOR - * SPOL - * SPOR - * LOUTL - * LOUTR - * MONOOUT - * PDML - * PDMR - * SPDIF - -Example: - -rt5659 { - compatible = "realtek,rt5659"; - reg = <0x1b>; - interrupt-parent = <&gpio>; - interrupts = ; - realtek,ldo1-en-gpios = - <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; -}; From 3913ecb38833e8926467a17f1f1679ccd25a7230 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 1 Jul 2024 00:38:51 +0000 Subject: [PATCH 233/349] ASoC: simple-audio-mux: enable to select MUX names simple-audio-mux is designed to be used generally, thus "Input 1" or "Input 2" are used to selecting MUX input. This numbered inputs would work, but might be not user friendly in some case, for example in case of system hardware design has some clear labels. Adds new "state-labels" property and enable to select MUX by own state names. Original > amixer set "MUX" "Input 1" Use mux-names sound_mux: mux { compatible = "simple-audio-mux"; mux-gpios = <...>; state-labels = "Label_A", "Label_B"; }; > amixer set "MUX" "Label_A" Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87msn27xpg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/simple-mux.c | 55 +++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c index bf67de12d20b..240af0563283 100644 --- a/sound/soc/codecs/simple-mux.c +++ b/sound/soc/codecs/simple-mux.c @@ -9,12 +9,21 @@ #include #include +#define MUX_TEXT_SIZE 2 +#define MUX_WIDGET_SIZE 4 +#define MUX_ROUTE_SIZE 3 struct simple_mux { struct gpio_desc *gpiod_mux; unsigned int mux; + const char *mux_texts[MUX_TEXT_SIZE]; + struct soc_enum mux_enum; + struct snd_kcontrol_new mux_mux; + struct snd_soc_dapm_widget mux_widgets[MUX_WIDGET_SIZE]; + struct snd_soc_dapm_route mux_routes[MUX_ROUTE_SIZE]; + struct snd_soc_component_driver mux_driver; }; -static const char * const simple_mux_texts[] = { +static const char * const simple_mux_texts[MUX_TEXT_SIZE] = { "Input 1", "Input 2" }; @@ -66,30 +75,23 @@ static unsigned int simple_mux_read(struct snd_soc_component *component, static const struct snd_kcontrol_new simple_mux_mux = SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put); -static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[] = { +static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[MUX_WIDGET_SIZE] = { SND_SOC_DAPM_INPUT("IN1"), SND_SOC_DAPM_INPUT("IN2"), - SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux), + SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux), // see simple_mux_probe() SND_SOC_DAPM_OUTPUT("OUT"), }; -static const struct snd_soc_dapm_route simple_mux_dapm_routes[] = { +static const struct snd_soc_dapm_route simple_mux_dapm_routes[MUX_ROUTE_SIZE] = { { "OUT", NULL, "MUX" }, - { "MUX", "Input 1", "IN1" }, - { "MUX", "Input 2", "IN2" }, -}; - -static const struct snd_soc_component_driver simple_mux_component_driver = { - .dapm_widgets = simple_mux_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(simple_mux_dapm_widgets), - .dapm_routes = simple_mux_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(simple_mux_dapm_routes), - .read = simple_mux_read, + { "MUX", "Input 1", "IN1" }, // see simple_mux_probe() + { "MUX", "Input 2", "IN2" }, // see simple_mux_probe() }; static int simple_mux_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct simple_mux *priv; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -103,7 +105,30 @@ static int simple_mux_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(priv->gpiod_mux), "Failed to get 'mux' gpio"); - return devm_snd_soc_register_component(dev, &simple_mux_component_driver, NULL, 0); + /* Copy default settings */ + memcpy(&priv->mux_texts, &simple_mux_texts, sizeof(priv->mux_texts)); + memcpy(&priv->mux_enum, &simple_mux_enum, sizeof(priv->mux_enum)); + memcpy(&priv->mux_mux, &simple_mux_mux, sizeof(priv->mux_mux)); + memcpy(&priv->mux_widgets, &simple_mux_dapm_widgets, sizeof(priv->mux_widgets)); + memcpy(&priv->mux_routes, &simple_mux_dapm_routes, sizeof(priv->mux_routes)); + + priv->mux_driver.dapm_widgets = priv->mux_widgets; + priv->mux_driver.num_dapm_widgets = MUX_WIDGET_SIZE; + priv->mux_driver.dapm_routes = priv->mux_routes; + priv->mux_driver.num_dapm_routes = MUX_ROUTE_SIZE; + priv->mux_driver.read = simple_mux_read; + + /* Overwrite text ("Input 1", "Input 2") if property exists */ + of_property_read_string_array(np, "state-labels", priv->mux_texts, MUX_TEXT_SIZE); + + /* switch to use priv data instead of default */ + priv->mux_enum.texts = priv->mux_texts; + priv->mux_mux.private_value = (unsigned long)&priv->mux_enum; + priv->mux_widgets[2].kcontrol_news = &priv->mux_mux; + priv->mux_routes[1].control = priv->mux_texts[0]; // "Input 1" + priv->mux_routes[2].control = priv->mux_texts[1]; // "Input 2" + + return devm_snd_soc_register_component(dev, &priv->mux_driver, NULL, 0); } #ifdef CONFIG_OF From 9337f15f4fd6ebd35d911225c4a88ec82d27b2a2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 1 Jul 2024 00:38:59 +0000 Subject: [PATCH 234/349] ASoC: dt-bindings: simple-audio-mux: add state-labels property simple-audio-mux is designed to be used generally, thus "Input 1" or "Input 2" are used to selecting MUX input. This numbered inputs would work, but might be not user friendly in some case, for example in case of system hardware design has some clear labels. Adds new "state-labels" property and enable to select MUX by own state names. Signed-off-by: Kuninori Morimoto Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/87le2m7xp8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/simple-audio-mux.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml index 9f319caf3db7..194ac1d4f4f5 100644 --- a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml +++ b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml @@ -24,6 +24,11 @@ properties: description: | GPIOs used to select the input line. + state-labels: + description: State of input line. default is "Input 1", "Input 2" + $ref: /schemas/types.yaml#/definitions/string-array + maxItems: 2 + sound-name-prefix: true required: @@ -37,4 +42,5 @@ examples: mux { compatible = "simple-audio-mux"; mux-gpios = <&gpio 3 0>; + state-labels = "Label_A", "Label_B"; }; From 49beb4d2e85634ec1e1c82d76461d9552676045d Mon Sep 17 00:00:00 2001 From: Manikantan R Date: Thu, 27 Jun 2024 15:44:38 +0100 Subject: [PATCH 235/349] ASoC: dt-bindings: wsa883x: Document port mapping property Document port mapping property for wsa883x. Port mapping is required to be able map correct master ports for VI feedback. All the device ports are not mapped in same order as master ports, so there is a need for having static port mapping for WSA codecs. Signed-off-by: Manikantan R Reviewed-by: Krzysztof Kozlowski Tested-by: Neil Armstrong # on SM8650-HDK Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20240626-port-map-v2-1-6cc1c5608cdd@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml index 8e462cdf0018..14d312f9c345 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml @@ -32,6 +32,14 @@ properties: vdd-supply: description: VDD Supply for the Codec + qcom,port-mapping: + description: | + Specifies static port mapping between slave and master ports. + In the order of slave port index. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 4 + maxItems: 4 + '#thermal-sensor-cells': const: 0 From 1cf3295bd108abbd7f128071ae9775fd18394ca9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 27 Jun 2024 15:44:39 +0100 Subject: [PATCH 236/349] ASoC: codecs: wsa883x: parse port-mapping information Add support to parse static master port map information from device tree. Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Tested-by: Neil Armstrong # on SM8650-HDK Signed-off-by: Srinivas Kandagatla Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20240626-port-map-v2-2-6cc1c5608cdd@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wsa883x.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 8abce2160d65..f5a15f0e891e 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -1398,6 +1398,14 @@ static int wsa883x_probe(struct sdw_slave *pdev, wsa883x->sconfig.direction = SDW_DATA_DIR_RX; wsa883x->sconfig.type = SDW_STREAM_PDM; + /** + * Port map index starts with 0, however the data port for this codec + * are from index 1 + */ + if (of_property_read_u32_array(dev->of_node, "qcom,port-mapping", &pdev->m_port_map[1], + WSA883X_MAX_SWR_PORTS)) + dev_dbg(dev, "Static Port mapping not specified\n"); + pdev->prop.sink_ports = GENMASK(WSA883X_MAX_SWR_PORTS, 0); pdev->prop.simple_clk_stop_capable = true; pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop; From d47abee9fede21b19d5227061c5a8761ec1659fb Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 27 Jun 2024 15:44:40 +0100 Subject: [PATCH 237/349] ASoC: dt-bindings: wsa8840: Document port mapping property Document port mapping property for wsa884x. Port mapping is required to be able map correct master ports. All the device ports are not mapped in same order as master ports, so there is a need for having static port mapping for WSA codecs. Reviewed-by: Krzysztof Kozlowski Tested-by: Neil Armstrong # on SM8650-HDK Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20240626-port-map-v2-3-6cc1c5608cdd@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml index 22798d22d981..83e0360301e1 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml @@ -32,6 +32,14 @@ properties: description: Powerdown/Shutdown line to use (pin SD_N) maxItems: 1 + qcom,port-mapping: + description: | + Specifies static port mapping between slave and master ports. + In the order of slave port index. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 6 + maxItems: 6 + '#sound-dai-cells': const: 0 From e1bc5c324bcca3acdbe817ccbf9aa7992d89479d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 27 Jun 2024 15:44:41 +0100 Subject: [PATCH 238/349] ASoC: codecs: wsa884x: parse port-mapping information Add support to parse static master port map information from device tree. This is required for correct port mapping between soundwire device and master ports. Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Tested-by: Neil Armstrong # on SM8650-HDK Signed-off-by: Srinivas Kandagatla Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20240626-port-map-v2-4-6cc1c5608cdd@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wsa884x.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index a9767ef0e39d..a6034547b4f3 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -1887,6 +1887,14 @@ static int wsa884x_probe(struct sdw_slave *pdev, wsa884x->sconfig.direction = SDW_DATA_DIR_RX; wsa884x->sconfig.type = SDW_STREAM_PDM; + /** + * Port map index starts with 0, however the data port for this codec + * are from index 1 + */ + if (of_property_read_u32_array(dev->of_node, "qcom,port-mapping", &pdev->m_port_map[1], + WSA884X_MAX_SWR_PORTS)) + dev_dbg(dev, "Static Port mapping not specified\n"); + pdev->prop.sink_ports = GENMASK(WSA884X_MAX_SWR_PORTS, 0); pdev->prop.simple_clk_stop_capable = true; pdev->prop.sink_dpn_prop = wsa884x_sink_dpn_prop; From 55f0a1fa6ea4e339c797e9a3292ca0caa4ab3885 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Sat, 29 Jun 2024 18:11:10 +0800 Subject: [PATCH 239/349] ASoc: tas2781: Add name_prefix as the prefix name of DSP firmwares and calibrated data files Add name_prefix as the prefix name of DSP firmwares and calibrated data files which stored speaker calibrated impedance. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20240629101112.628-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2781-i2c.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 4d1a0d836e77..cc765d45c6b5 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -394,8 +394,12 @@ static void tasdevice_fw_ready(const struct firmware *fmw, * failing to load DSP firmware is NOT an error. */ tas_priv->fw_state = TASDEVICE_RCA_FW_OK; - scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin", - tas_priv->dev_name); + if (tas_priv->name_prefix) + scnprintf(tas_priv->rca_binaryname, 64, "%s-%s_coef.bin", + tas_priv->name_prefix, tas_priv->dev_name); + else + scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin", + tas_priv->dev_name); ret = tasdevice_dsp_parser(tas_priv); if (ret) { dev_err(tas_priv->dev, "dspfw load %s error\n", @@ -418,8 +422,15 @@ static void tasdevice_fw_ready(const struct firmware *fmw, * calibrated data inside algo. */ for (i = 0; i < tas_priv->ndev; i++) { - scnprintf(tas_priv->cal_binaryname[i], 64, "%s_cal_0x%02x.bin", - tas_priv->dev_name, tas_priv->tasdevice[i].dev_addr); + if (tas_priv->name_prefix) + scnprintf(tas_priv->cal_binaryname[i], 64, + "%s-%s_cal_0x%02x.bin", tas_priv->name_prefix, + tas_priv->dev_name, + tas_priv->tasdevice[i].dev_addr); + else + scnprintf(tas_priv->cal_binaryname[i], 64, + "%s_cal_0x%02x.bin", tas_priv->dev_name, + tas_priv->tasdevice[i].dev_addr); ret = tas2781_load_calibration(tas_priv, tas_priv->cal_binaryname[i], i); if (ret != 0) From 4381b88b24a2edf9ce130adc9acd53258ba44116 Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Thu, 27 Jun 2024 16:20:26 +0530 Subject: [PATCH 240/349] ASoC: dt-bindings: realtek,rt5677: Convert to dtschema Convert the RT5677 audio CODEC bindings to DT schema. Signed-off-by: Animesh Agarwal Cc: Daniel Baluta Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240627105030.14360-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/realtek,rt5677.yaml | 135 ++++++++++++++++++ .../devicetree/bindings/sound/rt5677.txt | 78 ---------- 2 files changed, 135 insertions(+), 78 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/realtek,rt5677.yaml delete mode 100644 Documentation/devicetree/bindings/sound/rt5677.txt diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5677.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5677.yaml new file mode 100644 index 000000000000..9ce23e58e5ea --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,rt5677.yaml @@ -0,0 +1,135 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,rt5677.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RT5677 audio CODEC + +maintainers: + - Animesh Agarwal + +description: | + This device supports I2C only. + + Pins on the device (for linking into audio routes): + * IN1P + * IN1N + * IN2P + * IN2N + * MICBIAS1 + * DMIC1 + * DMIC2 + * DMIC3 + * DMIC4 + * LOUT1 + * LOUT2 + * LOUT3 + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: realtek,rt5677 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + gpio-controller: true + + '#gpio-cells': + const: 2 + + realtek,pow-ldo2-gpio: + maxItems: 1 + description: CODEC's POW_LDO2 pin. + + realtek,reset-gpio: + maxItems: 1 + description: CODEC's RESET pin. Active low. + + realtek,gpio-config: + description: | + Array of six 8bit elements that configures GPIO. + 0 - floating (reset value) + 1 - pull down + 2 - pull up + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 6 + maxItems: 6 + items: + maximum: 2 + + realtek,jd1-gpio: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # OFF + - 1 # GPIO1 for jd1. + - 2 # GPIO2 for jd1. + - 3 # GPIO3 for jd1. + description: Configures GPIO Mic Jack detection 1. + + realtek,jd2-gpio: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # OFF + - 1 # GPIO4 for jd2. + - 2 # GPIO5 for jd2. + - 3 # GPIO6 for jd2. + description: Configures GPIO Mic Jack detection 2. + + realtek,jd3-gpio: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # OFF + - 1 # GPIO4 for jd3. + - 2 # GPIO5 for jd3. + - 3 # GPIO6 for jd3. + description: Configures GPIO Mic Jack detection 3. + +patternProperties: + '^realtek,in[1-2]-differential$': + type: boolean + description: Indicate MIC1/2 input are differential, rather than + single-ended. + + '^realtek,lout[1-3]-differential$': + type: boolean + description: Indicate LOUT1/2/3 outputs are differential, rather than + single-ended. + +required: + - compatible + - reg + - interrupts + - gpio-controller + - '#gpio-cells' + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@2c { + compatible = "realtek,rt5677"; + reg = <0x2c>; + interrupt-parent = <&gpio>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + realtek,pow-ldo2-gpio = <&gpio 3 GPIO_ACTIVE_HIGH>; + realtek,reset-gpio = <&gpio 3 GPIO_ACTIVE_LOW>; + realtek,in1-differential; + realtek,gpio-config = <0 0 0 0 0 2>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt deleted file mode 100644 index da2430099181..000000000000 --- a/Documentation/devicetree/bindings/sound/rt5677.txt +++ /dev/null @@ -1,78 +0,0 @@ -RT5677 audio CODEC - -This device supports I2C only. - -Required properties: - -- compatible : "realtek,rt5677". - -- reg : The I2C address of the device. - -- interrupts : The CODEC's interrupt output. - -- gpio-controller : Indicates this device is a GPIO controller. - -- #gpio-cells : Should be two. The first cell is the pin number and the - second cell is used to specify optional parameters (currently unused). - -Optional properties: - -- realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin. -- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin. Active low. - -- realtek,in1-differential -- realtek,in2-differential -- realtek,lout1-differential -- realtek,lout2-differential -- realtek,lout3-differential - Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential, - rather than single-ended. - -- realtek,gpio-config - Array of six 8bit elements that configures GPIO. - 0 - floating (reset value) - 1 - pull down - 2 - pull up - -- realtek,jd1-gpio - Configures GPIO Mic Jack detection 1. - Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively. - -- realtek,jd2-gpio -- realtek,jd3-gpio - Configures GPIO Mic Jack detection 2 and 3. - Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively. - -Pins on the device (for linking into audio routes): - - * IN1P - * IN1N - * IN2P - * IN2N - * MICBIAS1 - * DMIC1 - * DMIC2 - * DMIC3 - * DMIC4 - * LOUT1 - * LOUT2 - * LOUT3 - -Example: - -rt5677 { - compatible = "realtek,rt5677"; - reg = <0x2c>; - interrupt-parent = <&gpio>; - interrupts = ; - - gpio-controller; - #gpio-cells = <2>; - - realtek,pow-ldo2-gpio = - <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; - realtek,reset-gpio = <&gpio TEGRA_GPIO(BB, 3) GPIO_ACTIVE_LOW>; - realtek,in1-differential = "true"; - realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */ - realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */ -}; From f4662e6d51ffc0826f975429d3c1b6d1f1a295f1 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 1 Jul 2024 09:24:16 -0700 Subject: [PATCH 241/349] ASoC: fsl: lpc3xxx-i2s: Avoid using ret uninitialized in lpc32xx_i2s_probe() clang points out that ret may be used uninitialized in lpc32xx_i2s_probe() in an error pointer path (which becomes fatal with CONFIG_WERROR): sound/soc/fsl/lpc3xxx-i2s.c:326:47: error: variable 'ret' is uninitialized when used here [-Werror,-Wuninitialized] 326 | "failed to init register map: %d\n", ret); | ^~~ sound/soc/fsl/lpc3xxx-i2s.c:310:9: note: initialize the variable 'ret' to silence this warning 310 | int ret; | ^ | = 0 1 error generated. One solution would be a small refactoring of the second parameter in dev_err_probe(), PTR_ERR(i2s_info_p->regs), to be the value of ret in the if statement. However, a nicer solution for debugging purposes, which is the point of this statement, would be to use the '%pe' specifier to symbolically print the error pointer value. Do so, which eliminates the uninitialized use of ret, clearing up the warning. Fixes: 0959de657a10 ("ASoC: fsl: Add i2s and pcm drivers for LPC32xx CPUs") Signed-off-by: Nathan Chancellor Link: https://patch.msgid.link/20240701-lpc32xx-asoc-fix-uninitialized-ret-v1-1-985d86189739@kernel.org Signed-off-by: Mark Brown --- sound/soc/fsl/lpc3xxx-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/lpc3xxx-i2s.c b/sound/soc/fsl/lpc3xxx-i2s.c index 0e5b4d5202ff..af995ca081a3 100644 --- a/sound/soc/fsl/lpc3xxx-i2s.c +++ b/sound/soc/fsl/lpc3xxx-i2s.c @@ -323,7 +323,7 @@ static int lpc32xx_i2s_probe(struct platform_device *pdev) i2s_info_p->regs = devm_regmap_init_mmio(dev, iomem, &lpc32xx_i2s_regconfig); if (IS_ERR(i2s_info_p->regs)) return dev_err_probe(dev, PTR_ERR(i2s_info_p->regs), - "failed to init register map: %d\n", ret); + "failed to init register map: %pe\n", i2s_info_p->regs); i2s_info_p->clk = devm_clk_get(dev, NULL); if (IS_ERR(i2s_info_p->clk)) From f1afb360b6f1f49e943ac85b26d4224ec67d22d3 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 1 Jul 2024 11:26:38 -0700 Subject: [PATCH 242/349] ASoC: fsl: lpc3xxx-i2s: Include bitfield.h for FIELD_PREP bitfield.h is not explicitly included but it is required for FIELD_PREP to be expanded by the preprocessor. If it is not implicitly included, there will be a compiler error (as seen with ARCH=hexagon allmodconfig): sound/soc/fsl/lpc3xxx-i2s.c:169:10: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 169 | tmp |= LPC3XXX_I2S_WW8 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW8_HP); | ^ sound/soc/fsl/lpc3xxx-i2s.h:42:30: note: expanded from macro 'LPC3XXX_I2S_WW8' 42 | #define LPC3XXX_I2S_WW8 FIELD_PREP(0x3, 0) /* Word width is 8bit */ | ^ sound/soc/fsl/lpc3xxx-i2s.c:205:34: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 205 | LPC3XXX_I2S_DMA1_TX_EN | LPC3XXX_I2S_DMA0_TX_DEPTH(4)); | ^ sound/soc/fsl/lpc3xxx-i2s.h:65:38: note: expanded from macro 'LPC3XXX_I2S_DMA0_TX_DEPTH' 65 | #define LPC3XXX_I2S_DMA0_TX_DEPTH(s) FIELD_PREP(0xF0000, s) /* Set the DMA1 TX Request level */ | ^ sound/soc/fsl/lpc3xxx-i2s.c:210:34: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 210 | LPC3XXX_I2S_DMA0_RX_EN | LPC3XXX_I2S_DMA1_RX_DEPTH(4)); | ^ sound/soc/fsl/lpc3xxx-i2s.h:70:38: note: expanded from macro 'LPC3XXX_I2S_DMA1_RX_DEPTH' 70 | #define LPC3XXX_I2S_DMA1_RX_DEPTH(s) FIELD_PREP(0x700, s) /* Set the DMA1 RX Request level */ | ^ Include bitfield.h explicitly, so that FIELD_PREP is always expanded, clearing up the compiler error. Fixes: 0959de657a10 ("ASoC: fsl: Add i2s and pcm drivers for LPC32xx CPUs") Signed-off-by: Nathan Chancellor Link: https://patch.msgid.link/20240701-lpc32xx-asoc-fix-include-for-field_prep-v1-1-0c5d7f71921b@kernel.org Signed-off-by: Mark Brown --- sound/soc/fsl/lpc3xxx-i2s.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/lpc3xxx-i2s.h b/sound/soc/fsl/lpc3xxx-i2s.h index eec755448478..b6657853017a 100644 --- a/sound/soc/fsl/lpc3xxx-i2s.h +++ b/sound/soc/fsl/lpc3xxx-i2s.h @@ -9,6 +9,7 @@ #ifndef __SOUND_SOC_LPC3XXX_I2S_H #define __SOUND_SOC_LPC3XXX_I2S_H +#include #include #include From 2e068fe01ecbf677d414d4c1b02eea1636dd614c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 28 Jun 2024 11:58:30 +0200 Subject: [PATCH 243/349] ASoC: codecs: lpass-rx-macro: Fix using NULL pointer in probe() dev_err The 'rx->dev' is assigned closer to the end of the probe() function, so the dev_err() must not use it - it is still NULL at this point. Instead there is already a local 'dev' variable. Fixes: dbacef05898d ("ASoC: codec: lpass-rx-macro: prepare driver to accomdate new codec versions") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20240628095831.207942-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 9c4f0763675d..d47c49c90de3 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3842,7 +3842,7 @@ static int rx_macro_probe(struct platform_device *pdev) rx_2_5_defaults, sizeof(rx_2_5_defaults)); break; default: - dev_err(rx->dev, "Unsupported Codec version (%d)\n", rx->codec_version); + dev_err(dev, "Unsupported Codec version (%d)\n", rx->codec_version); ret = -EINVAL; goto err; } From 765d3a2aa195882e231835f5d9ac4d99affc8c07 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 28 Jun 2024 11:58:31 +0200 Subject: [PATCH 244/349] ASoC: codecs: lpass-wsa-macro: Fix using NULL pointer in probe() dev_err The 'wsa->dev' is assigned closer to the end of the probe() function, so the dev_err() must not use it - it is still NULL at this point. Instead there is already a local 'dev' variable. Fixes: 727de4fbc546 ("ASoC: codecs: lpass-wsa-macro: Correct support for newer v2.5 version") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20240628095831.207942-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 8351f0974e6a..b4e7139bac61 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2800,7 +2800,7 @@ static int wsa_macro_probe(struct platform_device *pdev) break; default: - dev_err(wsa->dev, "Unsupported Codec version (%d)\n", wsa->codec_version); + dev_err(dev, "Unsupported Codec version (%d)\n", wsa->codec_version); return -EINVAL; } From f05c1ffc274516ef101d2e0f860bcb9b08c6c622 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 25 Jun 2024 19:25:46 +0200 Subject: [PATCH 245/349] ALSA: pcm: reinvent the stream synchronization ID API Until the commit e11f0f90a626 ("ALSA: pcm: remove SNDRV_PCM_IOCTL1_INFO internal command"), there was a possibility to pass information about the synchronized streams to the user space. The mentioned commit removed blindly the appropriate code with an irrelevant comment. The revert may be appropriate, but since this API was lost for several years without any complains, it's time to improve it. The hardware parameters may change the used stream clock source (e.g. USB hardware) so move this synchronization ID to hw_params as read-only field. It seems that pipewire can benefit from this API (disable adaptive resampling for perfectly synchronized PCM streams) now. Note that the contents of ID is not supposed to be used for direct comparison with a specific byte sequence. The "empty" case is when all bytes are zero (driver does not offer this information) and all other cases must be only used for equal comparison among PCM streams (including different sound cards) if they are using identical hardware clock. Cc: Takashi Sakamoto Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20240625172836.589380-2-perex@perex.cz --- include/sound/pcm.h | 3 ++- include/uapi/sound/asound.h | 9 +++++---- sound/core/pcm_lib.c | 27 +++++++++++++++++++++++---- sound/core/pcm_native.c | 6 ++++++ sound/pci/emu10k1/p16v.c | 7 +++---- 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 3edd7a7346da..dbce137d8806 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -93,6 +93,7 @@ struct snd_pcm_ops { #define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 /* 3 is absent slot. */ #define SNDRV_PCM_IOCTL1_FIFO_SIZE 4 +#define SNDRV_PCM_IOCTL1_SYNC_ID 5 #define SNDRV_PCM_TRIGGER_STOP 0 #define SNDRV_PCM_TRIGGER_START 1 @@ -401,7 +402,7 @@ struct snd_pcm_runtime { snd_pcm_uframes_t silence_start; /* starting pointer to silence area */ snd_pcm_uframes_t silence_filled; /* already filled part of silence area */ - union snd_pcm_sync_id sync; /* hardware synchronization ID */ + unsigned char sync[16]; /* hardware synchronization ID */ /* -- mmap -- */ struct snd_pcm_mmap_status *status; diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 628d46a0da92..8bf7e8a0eb6f 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -142,7 +142,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 17) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 18) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; @@ -334,7 +334,7 @@ union snd_pcm_sync_id { unsigned char id[16]; unsigned short id16[8]; unsigned int id32[4]; -}; +} __attribute__((deprecated)); struct snd_pcm_info { unsigned int device; /* RO/WR (control): device number */ @@ -348,7 +348,7 @@ struct snd_pcm_info { int dev_subclass; /* SNDRV_PCM_SUBCLASS_* */ unsigned int subdevices_count; unsigned int subdevices_avail; - union snd_pcm_sync_id sync; /* hardware synchronization ID */ + unsigned char pad1[16]; /* was: hardware synchronization ID */ unsigned char reserved[64]; /* reserved for future... */ }; @@ -420,7 +420,8 @@ struct snd_pcm_hw_params { unsigned int rate_num; /* R: rate numerator */ unsigned int rate_den; /* R: rate denominator */ snd_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ - unsigned char reserved[64]; /* reserved for future */ + unsigned char sync[16]; /* R: synchronization ID (perfect sync - one clock source) */ + unsigned char reserved[48]; /* reserved for future */ }; enum { diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 071c67cbc479..f64a03f79b01 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -525,10 +525,8 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - runtime->sync.id32[0] = substream->pcm->card->number; - runtime->sync.id32[1] = -1; - runtime->sync.id32[2] = -1; - runtime->sync.id32[3] = -1; + *(__u32 *)runtime->sync = cpu_to_le32(substream->pcm->card->number); + memset(runtime->sync + 4, 0xff, sizeof(runtime->sync) - 4); } EXPORT_SYMBOL(snd_pcm_set_sync); @@ -1810,6 +1808,25 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, return 0; } +/** + * is sync id (clock id) empty? + */ +static inline bool pcm_sync_empty(const unsigned char *sync) +{ + return sync[0] == 0 && sync[1] == 0 && sync[2] == 0 && sync[3] == 0 && + sync[4] == 0 && sync[5] == 0 && sync[6] == 0 && sync[7] == 0; +} + +static int snd_pcm_lib_ioctl_sync_id(struct snd_pcm_substream *substream, + void *arg) +{ + struct snd_pcm_hw_params *params = arg; + + if (pcm_sync_empty(params->sync)) + memcpy(params->sync, substream->runtime->sync, sizeof(params->sync)); + return 0; +} + /** * snd_pcm_lib_ioctl - a generic PCM ioctl callback * @substream: the pcm substream instance @@ -1831,6 +1848,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, return snd_pcm_lib_ioctl_channel_info(substream, arg); case SNDRV_PCM_IOCTL1_FIFO_SIZE: return snd_pcm_lib_ioctl_fifo_size(substream, arg); + case SNDRV_PCM_IOCTL1_SYNC_ID: + return snd_pcm_lib_ioctl_sync_id(substream, arg); } return -ENXIO; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index c152ccf32214..4057f9f10aee 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -533,6 +533,12 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, SNDRV_PCM_INFO_MMAP_VALID); } + err = snd_pcm_ops_ioctl(substream, + SNDRV_PCM_IOCTL1_SYNC_ID, + params); + if (err < 0) + return err; + return 0; } diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index e7f097cae574..773725dbdfbd 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -174,10 +174,9 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea if (err < 0) return err; - runtime->sync.id32[0] = substream->pcm->card->number; - runtime->sync.id32[1] = 'P'; - runtime->sync.id32[2] = 16; - runtime->sync.id32[3] = 'V'; + *(__u32 *)runtime->sync = cpu_to_le32(substream->pcm->card->number); + memset(runtime->sync + 4, 0, sizeof(runtime->sync) - 4); + strncpy(runtime->sync + 4, "P16V", 4); return 0; } From d712c58c55d9a4b4cc88ec2e1f8cd2e3b82359b5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 25 Jun 2024 19:25:47 +0200 Subject: [PATCH 246/349] ALSA: pcm: optimize and clarify stream synchronization ID API Optimize the memory usage in struct snd_pcm_runtime - use boolean value for the standard sync ID scheme. Introduce snd_pcm_set_sync_per_card function to build synchronization IDs. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20240625172836.589380-3-perex@perex.cz --- include/sound/pcm.h | 15 ++++++++++-- sound/core/pcm_lib.c | 51 ++++++++++++++++++++++++---------------- sound/pci/emu10k1/p16v.c | 16 +++++++++---- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index dbce137d8806..ac8f3aef9205 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -402,7 +402,7 @@ struct snd_pcm_runtime { snd_pcm_uframes_t silence_start; /* starting pointer to silence area */ snd_pcm_uframes_t silence_filled; /* already filled part of silence area */ - unsigned char sync[16]; /* hardware synchronization ID */ + bool std_sync_id; /* hardware synchronization - standard per card ID */ /* -- mmap -- */ struct snd_pcm_mmap_status *status; @@ -1156,7 +1156,18 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int void snd_pcm_set_ops(struct snd_pcm * pcm, int direction, const struct snd_pcm_ops *ops); -void snd_pcm_set_sync(struct snd_pcm_substream *substream); +void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, + const unsigned char *id, unsigned int len); +/** + * snd_pcm_set_sync - set the PCM sync id + * @substream: the pcm substream + * + * Use the default PCM sync identifier for the specific card. + */ +static inline void snd_pcm_set_sync(struct snd_pcm_substream *substream) +{ + substream->runtime->std_sync_id = true; +} int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substream); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index f64a03f79b01..e48a84f8e977 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -516,19 +516,37 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, EXPORT_SYMBOL(snd_pcm_set_ops); /** - * snd_pcm_set_sync - set the PCM sync id + * snd_pcm_set_sync_per_card - set the PCM sync id with card number * @substream: the pcm substream + * @params: modified hardware parameters + * @id: identifier (max 12 bytes) + * @len: identifier length (max 12 bytes) * - * Sets the PCM sync identifier for the card. + * Sets the PCM sync identifier for the card with zero padding. + * + * User space or any user should use this 16-byte identifier for a comparison only + * to check if two IDs are similar or different. Special case is the identifier + * containing only zeros. Interpretation for this combination is - empty (not set). + * The contents of the identifier should not be interpreted in any other way. + * + * The synchronization ID must be unique per clock source (usually one sound card, + * but multiple soundcard may use one PCM word clock source which means that they + * are fully synchronized). + * + * This routine composes this ID using card number in first four bytes and + * 12-byte additional ID. When other ID composition is used (e.g. for multiple + * sound cards), make sure that the composition does not clash with this + * composition scheme. */ -void snd_pcm_set_sync(struct snd_pcm_substream *substream) +void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + const unsigned char *id, unsigned int len) { - struct snd_pcm_runtime *runtime = substream->runtime; - - *(__u32 *)runtime->sync = cpu_to_le32(substream->pcm->card->number); - memset(runtime->sync + 4, 0xff, sizeof(runtime->sync) - 4); + *(__u32 *)params->sync = cpu_to_le32(substream->pcm->card->number); + len = max(12, len); + strncpy(params->sync + 4, id, len); + memset(params->sync + 4 + len, 0, 12 - len); } -EXPORT_SYMBOL(snd_pcm_set_sync); /* * Standard ioctl routine @@ -1808,22 +1826,15 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, return 0; } -/** - * is sync id (clock id) empty? - */ -static inline bool pcm_sync_empty(const unsigned char *sync) -{ - return sync[0] == 0 && sync[1] == 0 && sync[2] == 0 && sync[3] == 0 && - sync[4] == 0 && sync[5] == 0 && sync[6] == 0 && sync[7] == 0; -} - static int snd_pcm_lib_ioctl_sync_id(struct snd_pcm_substream *substream, void *arg) { - struct snd_pcm_hw_params *params = arg; + static const unsigned char id[12] = { 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff }; - if (pcm_sync_empty(params->sync)) - memcpy(params->sync, substream->runtime->sync, sizeof(params->sync)); + if (substream->runtime->std_sync_id) + snd_pcm_set_sync_per_card(substream, arg, id, sizeof(id)); return 0; } diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 773725dbdfbd..a9a75891f1da 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -174,10 +174,6 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea if (err < 0) return err; - *(__u32 *)runtime->sync = cpu_to_le32(substream->pcm->card->number); - memset(runtime->sync + 4, 0, sizeof(runtime->sync) - 4); - strncpy(runtime->sync + 4, "P16V", 4); - return 0; } @@ -225,6 +221,17 @@ static int snd_p16v_pcm_open_capture(struct snd_pcm_substream *substream) return snd_p16v_pcm_open_capture_channel(substream, 0); } +static int snd_p16v_pcm_ioctl_playback(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + if (cmd == SNDRV_PCM_IOCTL1_SYNC_ID) { + static const unsigned char id[4] = { 'P', '1', '6', 'V' }; + snd_pcm_set_sync_per_card(substream, arg, id, 4); + return 0; + } + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + /* prepare playback callback */ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) { @@ -530,6 +537,7 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream) static const struct snd_pcm_ops snd_p16v_playback_front_ops = { .open = snd_p16v_pcm_open_playback_front, .close = snd_p16v_pcm_close_playback, + .ioctl = snd_p16v_pcm_ioctl_playback, .prepare = snd_p16v_pcm_prepare_playback, .trigger = snd_p16v_pcm_trigger_playback, .pointer = snd_p16v_pcm_pointer_playback, From fcad7177eb7854ce244ce863c82583d8a6ce5952 Mon Sep 17 00:00:00 2001 From: Maxim Kochetkov Date: Tue, 2 Jul 2024 00:16:21 +0300 Subject: [PATCH 247/349] ASoC: dt-bindings: nau8824: Add master clock handling Use master clock "mclk" if provided through device tree. Signed-off-by: Maxim Kochetkov Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240701211631.92384-2-fido_max@inbox.ru Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nuvoton,nau8824.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml index 3dbf438c3841..232dc16a94a3 100644 --- a/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml @@ -23,6 +23,14 @@ properties: '#sound-dai-cells': const: 0 + clocks: + items: + - description: The phandle of the master clock to the CODEC + + clock-names: + items: + - const: mclk + interrupts: maxItems: 1 From 1d3724c92dc20584f76033347384b8c1536480af Mon Sep 17 00:00:00 2001 From: Maxim Kochetkov Date: Tue, 2 Jul 2024 00:16:22 +0300 Subject: [PATCH 248/349] ASoC: codecs: nau8824: Add master clock handling Use master clock "mclk" if provided through device tree. Signed-off-by: Maxim Kochetkov Link: https://patch.msgid.link/20240701211631.92384-3-fido_max@inbox.ru Signed-off-by: Mark Brown --- sound/soc/codecs/nau8824.c | 21 +++++++++++++++++++-- sound/soc/codecs/nau8824.h | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index f92b95b21cae..12540397fd4d 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -506,6 +506,7 @@ static int system_clock_control(struct snd_soc_dapm_widget *w, struct regmap *regmap = nau8824->regmap; unsigned int value; bool clk_fll, error; + int ret; if (SND_SOC_DAPM_EVENT_OFF(event)) { dev_dbg(nau8824->dev, "system clock control : POWER OFF\n"); @@ -520,8 +521,15 @@ static int system_clock_control(struct snd_soc_dapm_widget *w, } else { nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0); } + + clk_disable_unprepare(nau8824->mclk); } else { dev_dbg(nau8824->dev, "system clock control : POWER ON\n"); + + ret = clk_prepare_enable(nau8824->mclk); + if (ret) + return ret; + /* Check the clock source setting is proper or not * no matter the source is from FLL or MCLK. */ @@ -563,16 +571,21 @@ static int dmic_clock_control(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component); int src; + unsigned int freq; + + freq = clk_get_rate(nau8824->mclk); + if (!freq) + freq = nau8824->fs * 256; /* The DMIC clock is gotten from system clock (256fs) divided by * DMIC_SRC (1, 2, 4, 8, 16, 32). The clock has to be equal or * less than 3.072 MHz. */ for (src = 0; src < 5; src++) { - if ((0x1 << (8 - src)) * nau8824->fs <= DMIC_CLK) + if (freq / (0x1 << src) <= DMIC_CLK) break; } - dev_dbg(nau8824->dev, "dmic src %d for mclk %d\n", src, nau8824->fs * 256); + dev_dbg(nau8824->dev, "dmic src %d for mclk %d\n", src, freq); regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER, NAU8824_CLK_DMIC_SRC_MASK, (src << NAU8824_CLK_DMIC_SRC_SFT)); @@ -1871,6 +1884,10 @@ static int nau8824_read_device_properties(struct device *dev, if (ret) nau8824->jack_eject_debounce = 1; + nau8824->mclk = devm_clk_get_optional(dev, "mclk"); + if (IS_ERR(nau8824->mclk)) + return PTR_ERR(nau8824->mclk); + return 0; } diff --git a/sound/soc/codecs/nau8824.h b/sound/soc/codecs/nau8824.h index 5fcfc43dfc85..d8e19515133c 100644 --- a/sound/soc/codecs/nau8824.h +++ b/sound/soc/codecs/nau8824.h @@ -434,6 +434,7 @@ struct nau8824 { struct snd_soc_jack *jack; struct work_struct jdet_work; struct semaphore jd_sem; + struct clk *mclk; int fs; int irq; int resume_lock; From 62412a9357b16a4e39dc582deb2e2a682b92524c Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 2 Jul 2024 12:08:09 +0100 Subject: [PATCH 249/349] firmware: cs_dsp: Don't allow writes to read-only controls Add a check to cs_dsp_coeff_write_ctrl() to abort if the control is not writeable. The cs_dsp code originated as an ASoC driver (wm_adsp) where all controls were exported as ALSA controls. It relied on ALSA to enforce the read-only permission. Now that the code has been separated from ALSA/ASoC it must perform its own permission check. This isn't currently causing any problems so there shouldn't be any need to backport this. If the client of cs_dsp exposes the control as an ALSA control, it should set permissions on that ALSA control to protect it. The few uses of cs_dsp_coeff_write_ctrl() inside drivers are for writable controls. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20240702110809.16836-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 0d139e4de37c..d2aa0980ed78 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -796,6 +796,9 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, lockdep_assert_held(&ctl->dsp->pwr_lock); + if (ctl->flags && !(ctl->flags & WMFW_CTL_FLAG_WRITEABLE)) + return -EPERM; + if (len + off * sizeof(u32) > ctl->len) return -EINVAL; From 97a05cb4ab12f55e19cf28f6ceca47bb6ed8fea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:38 +0200 Subject: [PATCH 250/349] ASoC: topology: Simplify code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using goto, when there is no controls, just do a loop when there are. Overall the check seems to be a bit redundant as num_kcontrols will only be above 0 if kcontrols are set anyway, but let's keep it, while simplifying code. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-2-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 4b166294602f..dff83d49a8f6 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -394,13 +394,9 @@ static void soc_tplg_remove_widget(struct snd_soc_component *comp, if (dobj->unload) dobj->unload(comp, dobj); - if (!w->kcontrols) - goto free_news; - - for (i = 0; w->kcontrols && i < w->num_kcontrols; i++) - snd_ctl_remove(card, w->kcontrols[i]); - -free_news: + if (w->kcontrols) + for (i = 0; i < w->num_kcontrols; i++) + snd_ctl_remove(card, w->kcontrols[i]); list_del(&dobj->list); From 7aa129706b4d6f7a2c649b359eea0336eb640feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:39 +0200 Subject: [PATCH 251/349] ASoC: topology: Do not do unnecessary dobj management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Widget kcontrols do not need to be managed as topology dynamic objects with an index and a linked list. As they are always associated with a widget which is already a topology dynamic object, thus all addition/removals of a widget will by design manage the kcontrol. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-3-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index dff83d49a8f6..bd29b40acb99 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1134,8 +1134,6 @@ static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_ sm->min = le32_to_cpu(mc->min); sm->invert = le32_to_cpu(mc->invert); sm->platform_max = le32_to_cpu(mc->platform_max); - sm->dobj.index = tplg->index; - INIT_LIST_HEAD(&sm->dobj.list); /* map io handlers */ err = soc_tplg_kcontrol_bind_io(&mc->hdr, kc, tplg); @@ -1198,7 +1196,6 @@ static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_k se->items = le32_to_cpu(ec->items); se->mask = le32_to_cpu(ec->mask); - se->dobj.index = tplg->index; switch (le32_to_cpu(ec->hdr.ops.info)) { case SND_SOC_TPLG_CTL_ENUM_VALUE: @@ -1273,7 +1270,6 @@ static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_ kc->access = le32_to_cpu(be->hdr.access); sbe->max = le32_to_cpu(be->max); - INIT_LIST_HEAD(&sbe->dobj.list); /* map standard io handlers and check for external handlers */ err = soc_tplg_kcontrol_bind_io(&be->hdr, kc, tplg); From 8ec2a2643544ce352f012ad3d248163199d05dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:40 +0200 Subject: [PATCH 252/349] ASoC: topology: Properly initialize soc_enum values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit soc_tplg_denum_create_values() should properly set its values field. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-4-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index bd29b40acb99..15c006c47d80 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -847,6 +847,8 @@ static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum * se->dobj.control.dvalues[i] = le32_to_cpu(ec->values[i]); } + se->items = le32_to_cpu(ec->items); + se->values = (const unsigned int *)se->dobj.control.dvalues; return 0; } From 52f4f7272c92d5be3988839a33be41b180bbc28e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:41 +0200 Subject: [PATCH 253/349] ASoC: topology: Cleanup soc_tplg_dapm_widget_dbytes_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minor cleanups to increase readability. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-5-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 15c006c47d80..73e127975822 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1249,25 +1249,22 @@ static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_ be = (struct snd_soc_tplg_bytes_control *)tplg->pos; /* validate kcontrol */ - if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) return -EINVAL; sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL); if (!sbe) return -ENOMEM; - tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + - le32_to_cpu(be->priv.size)); + tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + le32_to_cpu(be->priv.size)); - dev_dbg(tplg->dev, - "ASoC: adding bytes kcontrol %s with access 0x%x\n", + dev_dbg(tplg->dev, "ASoC: adding bytes kcontrol %s with access 0x%x\n", be->hdr.name, be->hdr.access); - kc->private_value = (long)sbe; kc->name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL); if (!kc->name) return -ENOMEM; + kc->private_value = (long)sbe; kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kc->access = le32_to_cpu(be->hdr.access); @@ -1281,11 +1278,7 @@ static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_ } /* pass control to driver for optional further init */ - err = soc_tplg_control_load(tplg, kc, &be->hdr); - if (err < 0) - return err; - - return 0; + return soc_tplg_control_load(tplg, kc, &be->hdr); } static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, From 40a16442a048c5f2b4336edd4d202f1930fb9df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:42 +0200 Subject: [PATCH 254/349] ASoC: topology: Cleanup soc_tplg_dapm_widget_dmixer_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minor cleanups to increase readability. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-6-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 73e127975822..242d8b9c2f03 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1094,43 +1094,37 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) { - struct soc_mixer_control *sm; struct snd_soc_tplg_mixer_control *mc; + struct soc_mixer_control *sm; int err; mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; /* validate kcontrol */ - if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) return -EINVAL; sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL); if (!sm) return -ENOMEM; - tplg->pos += sizeof(struct snd_soc_tplg_mixer_control) + - le32_to_cpu(mc->priv.size); + tplg->pos += sizeof(struct snd_soc_tplg_mixer_control) + le32_to_cpu(mc->priv.size); - dev_dbg(tplg->dev, " adding DAPM widget mixer control %s\n", - mc->hdr.name); + dev_dbg(tplg->dev, "ASoC: adding mixer kcontrol %s with access 0x%x\n", + mc->hdr.name, mc->hdr.access); - kc->private_value = (long)sm; kc->name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL); if (!kc->name) return -ENOMEM; + kc->private_value = (long)sm; kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kc->access = le32_to_cpu(mc->hdr.access); /* we only support FL/FR channel mapping atm */ - sm->reg = tplg_chan_get_reg(tplg, mc->channel, - SNDRV_CHMAP_FL); - sm->rreg = tplg_chan_get_reg(tplg, mc->channel, - SNDRV_CHMAP_FR); - sm->shift = tplg_chan_get_shift(tplg, mc->channel, - SNDRV_CHMAP_FL); - sm->rshift = tplg_chan_get_shift(tplg, mc->channel, - SNDRV_CHMAP_FR); + sm->reg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FL); + sm->rreg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FR); + sm->shift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FL); + sm->rshift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FR); sm->max = le32_to_cpu(mc->max); sm->min = le32_to_cpu(mc->min); @@ -1147,17 +1141,12 @@ static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_ /* create any TLV data */ err = soc_tplg_create_tlv(tplg, kc, &mc->hdr); if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", - mc->hdr.name); + dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", mc->hdr.name); return err; } /* pass control to driver for optional further init */ - err = soc_tplg_control_load(tplg, kc, &mc->hdr); - if (err < 0) - return err; - - return 0; + return soc_tplg_control_load(tplg, kc, &mc->hdr); } static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) From d1d0262a1f5c7a543271bd5899cdb4b3ddfe054b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:43 +0200 Subject: [PATCH 255/349] ASoC: topology: Cleanup soc_tplg_dapm_widget_denum_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minor cleanups to increase readability. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-7-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 242d8b9c2f03..6a2a8249903d 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1156,36 +1156,31 @@ static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_k int err; ec = (struct snd_soc_tplg_enum_control *)tplg->pos; + /* validate kcontrol */ - if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) return -EINVAL; se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL); if (!se) return -ENOMEM; - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - le32_to_cpu(ec->priv.size)); + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + le32_to_cpu(ec->priv.size)); - dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", - ec->hdr.name); + dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", ec->hdr.name, ec->items); - kc->private_value = (long)se; kc->name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL); if (!kc->name) return -ENOMEM; + kc->private_value = (long)se; kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kc->access = le32_to_cpu(ec->hdr.access); /* we only support FL/FR channel mapping atm */ se->reg = tplg_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); - se->shift_l = tplg_chan_get_shift(tplg, ec->channel, - SNDRV_CHMAP_FL); - se->shift_r = tplg_chan_get_shift(tplg, ec->channel, - SNDRV_CHMAP_FR); + se->shift_l = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL); + se->shift_r = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR); - se->items = le32_to_cpu(ec->items); se->mask = le32_to_cpu(ec->mask); switch (le32_to_cpu(ec->hdr.ops.info)) { @@ -1193,8 +1188,7 @@ static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_k case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: err = soc_tplg_denum_create_values(tplg, se, ec); if (err < 0) { - dev_err(tplg->dev, "ASoC: could not create values for %s\n", - ec->hdr.name); + dev_err(tplg->dev, "ASoC: could not create values for %s\n", ec->hdr.name); return err; } fallthrough; @@ -1203,8 +1197,7 @@ static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_k case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: err = soc_tplg_denum_create_texts(tplg, se, ec); if (err < 0) { - dev_err(tplg->dev, "ASoC: could not create texts for %s\n", - ec->hdr.name); + dev_err(tplg->dev, "ASoC: could not create texts for %s\n", ec->hdr.name); return err; } break; @@ -1222,11 +1215,7 @@ static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_k } /* pass control to driver for optional further init */ - err = soc_tplg_control_load(tplg, kc, &ec->hdr); - if (err < 0) - return err; - - return 0; + return soc_tplg_control_load(tplg, kc, &ec->hdr); } static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) From 963942f73b02b053f97e079ed6dae5f3602cc4b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:44 +0200 Subject: [PATCH 256/349] ASoC: topology: Correctly set shift_r in soc_tplg_denum_create() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This aligns soc_tplg_denum_create() with soc_tplg_dapm_widget_denum_create(), as there is no reason for difference in behavior. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-8-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 6a2a8249903d..e6eb514de569 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -891,7 +891,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size) se->shift_l = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL); se->shift_r = tplg_chan_get_shift(tplg, ec->channel, - SNDRV_CHMAP_FL); + SNDRV_CHMAP_FR); se->mask = le32_to_cpu(ec->mask); se->dobj.index = tplg->index; From f14a33fcadbacc1d9728e9c75253145ae6e09bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:45 +0200 Subject: [PATCH 257/349] ASoC: topology: Align dynamic object initialization for controls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit soc_tplg_dbytes_create() missed se->dobj.index initialization, so add it there. Additionally separate dynamic object initialization into separate logical block code. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-9-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index e6eb514de569..72bd3823a015 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -677,10 +677,12 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size) kc.access = le32_to_cpu(be->hdr.access); sbe->max = le32_to_cpu(be->max); + + INIT_LIST_HEAD(&sbe->dobj.list); sbe->dobj.type = SND_SOC_DOBJ_BYTES; + sbe->dobj.index = tplg->index; if (tplg->ops) sbe->dobj.unload = tplg->ops->control_unload; - INIT_LIST_HEAD(&sbe->dobj.list); /* map io handlers */ ret = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg); @@ -750,11 +752,12 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size) sm->min = le32_to_cpu(mc->min); sm->invert = le32_to_cpu(mc->invert); sm->platform_max = le32_to_cpu(mc->platform_max); - sm->dobj.index = tplg->index; + + INIT_LIST_HEAD(&sm->dobj.list); sm->dobj.type = SND_SOC_DOBJ_MIXER; + sm->dobj.index = tplg->index; if (tplg->ops) sm->dobj.unload = tplg->ops->control_unload; - INIT_LIST_HEAD(&sm->dobj.list); /* map io handlers */ ret = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg); @@ -894,11 +897,12 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size) SNDRV_CHMAP_FR); se->mask = le32_to_cpu(ec->mask); - se->dobj.index = tplg->index; + + INIT_LIST_HEAD(&se->dobj.list); se->dobj.type = SND_SOC_DOBJ_ENUM; + se->dobj.index = tplg->index; if (tplg->ops) se->dobj.unload = tplg->ops->control_unload; - INIT_LIST_HEAD(&se->dobj.list); switch (le32_to_cpu(ec->hdr.ops.info)) { case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: From 76d8aa0f727e327a0ba9bcb904865c40d256c292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:46 +0200 Subject: [PATCH 258/349] ASoC: topology: Rename function creating widget kcontrol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In following patches it will be reused to also create standalone kcontrol, so it makes sense to name it in more generic way. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-10-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 72bd3823a015..f85cf67f74b1 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1096,7 +1096,7 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, return ret; } -static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) +static int soc_tplg_control_dmixer_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) { struct snd_soc_tplg_mixer_control *mc; struct soc_mixer_control *sm; @@ -1153,7 +1153,7 @@ static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_ return soc_tplg_control_load(tplg, kc, &mc->hdr); } -static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) +static int soc_tplg_control_denum_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) { struct snd_soc_tplg_enum_control *ec; struct soc_enum *se; @@ -1222,7 +1222,7 @@ static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_k return soc_tplg_control_load(tplg, kc, &ec->hdr); } -static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) +static int soc_tplg_control_dbytes_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) { struct snd_soc_tplg_bytes_control *be; struct soc_bytes_ext *sbe; @@ -1350,7 +1350,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, kc[i].index = mixer_count; kcontrol_type[i] = SND_SOC_TPLG_TYPE_MIXER; mixer_count++; - ret = soc_tplg_dapm_widget_dmixer_create(tplg, &kc[i]); + ret = soc_tplg_control_dmixer_create(tplg, &kc[i]); if (ret < 0) goto hdr_err; break; @@ -1363,7 +1363,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, kc[i].index = enum_count; kcontrol_type[i] = SND_SOC_TPLG_TYPE_ENUM; enum_count++; - ret = soc_tplg_dapm_widget_denum_create(tplg, &kc[i]); + ret = soc_tplg_control_denum_create(tplg, &kc[i]); if (ret < 0) goto hdr_err; break; @@ -1372,7 +1372,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, kc[i].index = bytes_count; kcontrol_type[i] = SND_SOC_TPLG_TYPE_BYTES; bytes_count++; - ret = soc_tplg_dapm_widget_dbytes_create(tplg, &kc[i]); + ret = soc_tplg_control_dbytes_create(tplg, &kc[i]); if (ret < 0) goto hdr_err; break; From c2dad0db01fcacd44616e9d4c7263b187c4ff530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:47 +0200 Subject: [PATCH 259/349] ASoC: topology: Reshuffle function placement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for following cleanups move functions around. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-11-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 466 +++++++++++++++++++-------------------- 1 file changed, 233 insertions(+), 233 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index f85cf67f74b1..5aab1df7e260 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -640,6 +640,239 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg, return 0; } +static int soc_tplg_control_dmixer_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) +{ + struct snd_soc_tplg_mixer_control *mc; + struct soc_mixer_control *sm; + int err; + + mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; + + /* validate kcontrol */ + if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; + + sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL); + if (!sm) + return -ENOMEM; + + tplg->pos += sizeof(struct snd_soc_tplg_mixer_control) + le32_to_cpu(mc->priv.size); + + dev_dbg(tplg->dev, "ASoC: adding mixer kcontrol %s with access 0x%x\n", + mc->hdr.name, mc->hdr.access); + + kc->name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL); + if (!kc->name) + return -ENOMEM; + kc->private_value = (long)sm; + kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc->access = le32_to_cpu(mc->hdr.access); + + /* we only support FL/FR channel mapping atm */ + sm->reg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FL); + sm->rreg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FR); + sm->shift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FL); + sm->rshift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FR); + + sm->max = le32_to_cpu(mc->max); + sm->min = le32_to_cpu(mc->min); + sm->invert = le32_to_cpu(mc->invert); + sm->platform_max = le32_to_cpu(mc->platform_max); + + /* map io handlers */ + err = soc_tplg_kcontrol_bind_io(&mc->hdr, kc, tplg); + if (err) { + soc_control_err(tplg, &mc->hdr, mc->hdr.name); + return err; + } + + /* create any TLV data */ + err = soc_tplg_create_tlv(tplg, kc, &mc->hdr); + if (err < 0) { + dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", mc->hdr.name); + return err; + } + + /* pass control to driver for optional further init */ + return soc_tplg_control_load(tplg, kc, &mc->hdr); +} + +static int soc_tplg_denum_create_texts(struct soc_tplg *tplg, struct soc_enum *se, + struct snd_soc_tplg_enum_control *ec) +{ + int i, ret; + + if (le32_to_cpu(ec->items) > ARRAY_SIZE(ec->texts)) + return -EINVAL; + + se->dobj.control.dtexts = + devm_kcalloc(tplg->dev, le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL); + if (se->dobj.control.dtexts == NULL) + return -ENOMEM; + + for (i = 0; i < le32_to_cpu(ec->items); i++) { + + if (strnlen(ec->texts[i], SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + goto err; + } + + se->dobj.control.dtexts[i] = devm_kstrdup(tplg->dev, ec->texts[i], GFP_KERNEL); + if (!se->dobj.control.dtexts[i]) { + ret = -ENOMEM; + goto err; + } + } + + se->items = le32_to_cpu(ec->items); + se->texts = (const char * const *)se->dobj.control.dtexts; + return 0; + +err: + return ret; +} + +static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum *se, + struct snd_soc_tplg_enum_control *ec) +{ + int i; + + /* + * Following "if" checks if we have at most SND_SOC_TPLG_NUM_TEXTS + * values instead of using ARRAY_SIZE(ec->values) due to the fact that + * it is oversized for its purpose. Additionally it is done so because + * it is defined in UAPI header where it can't be easily changed. + */ + if (le32_to_cpu(ec->items) > SND_SOC_TPLG_NUM_TEXTS) + return -EINVAL; + + se->dobj.control.dvalues = devm_kcalloc(tplg->dev, le32_to_cpu(ec->items), + sizeof(*se->dobj.control.dvalues), + GFP_KERNEL); + if (!se->dobj.control.dvalues) + return -ENOMEM; + + /* convert from little-endian */ + for (i = 0; i < le32_to_cpu(ec->items); i++) { + se->dobj.control.dvalues[i] = le32_to_cpu(ec->values[i]); + } + + se->items = le32_to_cpu(ec->items); + se->values = (const unsigned int *)se->dobj.control.dvalues; + return 0; +} + +static int soc_tplg_control_denum_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) +{ + struct snd_soc_tplg_enum_control *ec; + struct soc_enum *se; + int err; + + ec = (struct snd_soc_tplg_enum_control *)tplg->pos; + + /* validate kcontrol */ + if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; + + se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL); + if (!se) + return -ENOMEM; + + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + le32_to_cpu(ec->priv.size)); + + dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", ec->hdr.name, ec->items); + + kc->name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL); + if (!kc->name) + return -ENOMEM; + kc->private_value = (long)se; + kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc->access = le32_to_cpu(ec->hdr.access); + + /* we only support FL/FR channel mapping atm */ + se->reg = tplg_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); + se->shift_l = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL); + se->shift_r = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR); + + se->mask = le32_to_cpu(ec->mask); + + switch (le32_to_cpu(ec->hdr.ops.info)) { + case SND_SOC_TPLG_CTL_ENUM_VALUE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + err = soc_tplg_denum_create_values(tplg, se, ec); + if (err < 0) { + dev_err(tplg->dev, "ASoC: could not create values for %s\n", ec->hdr.name); + return err; + } + fallthrough; + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: + err = soc_tplg_denum_create_texts(tplg, se, ec); + if (err < 0) { + dev_err(tplg->dev, "ASoC: could not create texts for %s\n", ec->hdr.name); + return err; + } + break; + default: + dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", + ec->hdr.ops.info, ec->hdr.name); + return -EINVAL; + } + + /* map io handlers */ + err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg); + if (err) { + soc_control_err(tplg, &ec->hdr, ec->hdr.name); + return err; + } + + /* pass control to driver for optional further init */ + return soc_tplg_control_load(tplg, kc, &ec->hdr); +} + +static int soc_tplg_control_dbytes_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) +{ + struct snd_soc_tplg_bytes_control *be; + struct soc_bytes_ext *sbe; + int err; + + be = (struct snd_soc_tplg_bytes_control *)tplg->pos; + + /* validate kcontrol */ + if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; + + sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL); + if (!sbe) + return -ENOMEM; + + tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + le32_to_cpu(be->priv.size)); + + dev_dbg(tplg->dev, "ASoC: adding bytes kcontrol %s with access 0x%x\n", + be->hdr.name, be->hdr.access); + + kc->name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL); + if (!kc->name) + return -ENOMEM; + kc->private_value = (long)sbe; + kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc->access = le32_to_cpu(be->hdr.access); + + sbe->max = le32_to_cpu(be->max); + + /* map standard io handlers and check for external handlers */ + err = soc_tplg_kcontrol_bind_io(&be->hdr, kc, tplg); + if (err) { + soc_control_err(tplg, &be->hdr, be->hdr.name); + return err; + } + + /* pass control to driver for optional further init */ + return soc_tplg_control_load(tplg, kc, &be->hdr); +} + static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size) { struct snd_soc_tplg_bytes_control *be; @@ -789,72 +1022,6 @@ err: return ret; } -static int soc_tplg_denum_create_texts(struct soc_tplg *tplg, struct soc_enum *se, - struct snd_soc_tplg_enum_control *ec) -{ - int i, ret; - - if (le32_to_cpu(ec->items) > ARRAY_SIZE(ec->texts)) - return -EINVAL; - - se->dobj.control.dtexts = - devm_kcalloc(tplg->dev, le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL); - if (se->dobj.control.dtexts == NULL) - return -ENOMEM; - - for (i = 0; i < le32_to_cpu(ec->items); i++) { - - if (strnlen(ec->texts[i], SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { - ret = -EINVAL; - goto err; - } - - se->dobj.control.dtexts[i] = devm_kstrdup(tplg->dev, ec->texts[i], GFP_KERNEL); - if (!se->dobj.control.dtexts[i]) { - ret = -ENOMEM; - goto err; - } - } - - se->items = le32_to_cpu(ec->items); - se->texts = (const char * const *)se->dobj.control.dtexts; - return 0; - -err: - return ret; -} - -static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum *se, - struct snd_soc_tplg_enum_control *ec) -{ - int i; - - /* - * Following "if" checks if we have at most SND_SOC_TPLG_NUM_TEXTS - * values instead of using ARRAY_SIZE(ec->values) due to the fact that - * it is oversized for its purpose. Additionally it is done so because - * it is defined in UAPI header where it can't be easily changed. - */ - if (le32_to_cpu(ec->items) > SND_SOC_TPLG_NUM_TEXTS) - return -EINVAL; - - se->dobj.control.dvalues = devm_kcalloc(tplg->dev, le32_to_cpu(ec->items), - sizeof(*se->dobj.control.dvalues), - GFP_KERNEL); - if (!se->dobj.control.dvalues) - return -ENOMEM; - - /* convert from little-endian */ - for (i = 0; i < le32_to_cpu(ec->items); i++) { - se->dobj.control.dvalues[i] = le32_to_cpu(ec->values[i]); - } - - se->items = le32_to_cpu(ec->items); - se->values = (const unsigned int *)se->dobj.control.dvalues; - return 0; -} - static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size) { struct snd_soc_tplg_enum_control *ec; @@ -1096,173 +1263,6 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, return ret; } -static int soc_tplg_control_dmixer_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) -{ - struct snd_soc_tplg_mixer_control *mc; - struct soc_mixer_control *sm; - int err; - - mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; - - /* validate kcontrol */ - if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; - - sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL); - if (!sm) - return -ENOMEM; - - tplg->pos += sizeof(struct snd_soc_tplg_mixer_control) + le32_to_cpu(mc->priv.size); - - dev_dbg(tplg->dev, "ASoC: adding mixer kcontrol %s with access 0x%x\n", - mc->hdr.name, mc->hdr.access); - - kc->name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL); - if (!kc->name) - return -ENOMEM; - kc->private_value = (long)sm; - kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc->access = le32_to_cpu(mc->hdr.access); - - /* we only support FL/FR channel mapping atm */ - sm->reg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FL); - sm->rreg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FR); - sm->shift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FL); - sm->rshift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FR); - - sm->max = le32_to_cpu(mc->max); - sm->min = le32_to_cpu(mc->min); - sm->invert = le32_to_cpu(mc->invert); - sm->platform_max = le32_to_cpu(mc->platform_max); - - /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&mc->hdr, kc, tplg); - if (err) { - soc_control_err(tplg, &mc->hdr, mc->hdr.name); - return err; - } - - /* create any TLV data */ - err = soc_tplg_create_tlv(tplg, kc, &mc->hdr); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", mc->hdr.name); - return err; - } - - /* pass control to driver for optional further init */ - return soc_tplg_control_load(tplg, kc, &mc->hdr); -} - -static int soc_tplg_control_denum_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) -{ - struct snd_soc_tplg_enum_control *ec; - struct soc_enum *se; - int err; - - ec = (struct snd_soc_tplg_enum_control *)tplg->pos; - - /* validate kcontrol */ - if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; - - se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL); - if (!se) - return -ENOMEM; - - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + le32_to_cpu(ec->priv.size)); - - dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", ec->hdr.name, ec->items); - - kc->name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL); - if (!kc->name) - return -ENOMEM; - kc->private_value = (long)se; - kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc->access = le32_to_cpu(ec->hdr.access); - - /* we only support FL/FR channel mapping atm */ - se->reg = tplg_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); - se->shift_l = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL); - se->shift_r = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR); - - se->mask = le32_to_cpu(ec->mask); - - switch (le32_to_cpu(ec->hdr.ops.info)) { - case SND_SOC_TPLG_CTL_ENUM_VALUE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - err = soc_tplg_denum_create_values(tplg, se, ec); - if (err < 0) { - dev_err(tplg->dev, "ASoC: could not create values for %s\n", ec->hdr.name); - return err; - } - fallthrough; - case SND_SOC_TPLG_CTL_ENUM: - case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - err = soc_tplg_denum_create_texts(tplg, se, ec); - if (err < 0) { - dev_err(tplg->dev, "ASoC: could not create texts for %s\n", ec->hdr.name); - return err; - } - break; - default: - dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", - ec->hdr.ops.info, ec->hdr.name); - return -EINVAL; - } - - /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg); - if (err) { - soc_control_err(tplg, &ec->hdr, ec->hdr.name); - return err; - } - - /* pass control to driver for optional further init */ - return soc_tplg_control_load(tplg, kc, &ec->hdr); -} - -static int soc_tplg_control_dbytes_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) -{ - struct snd_soc_tplg_bytes_control *be; - struct soc_bytes_ext *sbe; - int err; - - be = (struct snd_soc_tplg_bytes_control *)tplg->pos; - - /* validate kcontrol */ - if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; - - sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL); - if (!sbe) - return -ENOMEM; - - tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + le32_to_cpu(be->priv.size)); - - dev_dbg(tplg->dev, "ASoC: adding bytes kcontrol %s with access 0x%x\n", - be->hdr.name, be->hdr.access); - - kc->name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL); - if (!kc->name) - return -ENOMEM; - kc->private_value = (long)sbe; - kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc->access = le32_to_cpu(be->hdr.access); - - sbe->max = le32_to_cpu(be->max); - - /* map standard io handlers and check for external handlers */ - err = soc_tplg_kcontrol_bind_io(&be->hdr, kc, tplg); - if (err) { - soc_control_err(tplg, &be->hdr, be->hdr.name); - return err; - } - - /* pass control to driver for optional further init */ - return soc_tplg_control_load(tplg, kc, &be->hdr); -} - static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, struct snd_soc_tplg_dapm_widget *w) { From 0867278200f787817036419fc87b56fb04a448e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:48 +0200 Subject: [PATCH 260/349] ASoC: topology: Unify code for creating standalone and widget bytes control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code used to create standalone and widget bytes control is same, with exception that in standalone case dynamic object needs to be registered and control created directly. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-12-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 51 +++++++--------------------------------- 1 file changed, 9 insertions(+), 42 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 5aab1df7e260..b10a6be8f75b 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -875,41 +875,21 @@ static int soc_tplg_control_dbytes_create(struct soc_tplg *tplg, struct snd_kcon static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size) { - struct snd_soc_tplg_bytes_control *be; + struct snd_kcontrol_new kc = {0}; struct soc_bytes_ext *sbe; - struct snd_kcontrol_new kc; - int ret = 0; + int ret; if (soc_tplg_check_elem_count(tplg, sizeof(struct snd_soc_tplg_bytes_control), 1, size, "mixer bytes")) return -EINVAL; - be = (struct snd_soc_tplg_bytes_control *)tplg->pos; + ret = soc_tplg_control_dbytes_create(tplg, &kc); + if (ret) + return ret; - /* validate kcontrol */ - if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; - - sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL); - if (sbe == NULL) - return -ENOMEM; - - tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + - le32_to_cpu(be->priv.size)); - - dev_dbg(tplg->dev, - "ASoC: adding bytes kcontrol %s with access 0x%x\n", - be->hdr.name, be->hdr.access); - - memset(&kc, 0, sizeof(kc)); - kc.name = be->hdr.name; - kc.private_value = (long)sbe; - kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc.access = le32_to_cpu(be->hdr.access); - - sbe->max = le32_to_cpu(be->max); + /* register dynamic object */ + sbe = (struct soc_bytes_ext *)&kc.private_value; INIT_LIST_HEAD(&sbe->dobj.list); sbe->dobj.type = SND_SOC_DOBJ_BYTES; @@ -917,26 +897,13 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size) if (tplg->ops) sbe->dobj.unload = tplg->ops->control_unload; - /* map io handlers */ - ret = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg); - if (ret) { - soc_control_err(tplg, &be->hdr, be->hdr.name); - goto err; - } - - /* pass control to driver for optional further init */ - ret = soc_tplg_control_load(tplg, &kc, &be->hdr); - if (ret < 0) - goto err; - - /* register control here */ + /* create control directly */ ret = soc_tplg_add_kcontrol(tplg, &kc, &sbe->dobj.control.kcontrol); if (ret < 0) - goto err; + return ret; list_add(&sbe->dobj.list, &tplg->comp->dobj_list); -err: return ret; } From 4654ca7cc8d6b57c77436dd44b347cc7dd3f5f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:49 +0200 Subject: [PATCH 261/349] ASoC: topology: Unify code for creating standalone and widget mixer control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code used to create standalone and widget mixer control is same, with exception that in standalone case dynamic object needs to be registered and control created directly. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-13-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 66 ++++++---------------------------------- 1 file changed, 9 insertions(+), 57 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b10a6be8f75b..5fde44808246 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -909,49 +909,21 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size) static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size) { - struct snd_soc_tplg_mixer_control *mc; + struct snd_kcontrol_new kc = {0}; struct soc_mixer_control *sm; - struct snd_kcontrol_new kc; - int ret = 0; + int ret; if (soc_tplg_check_elem_count(tplg, sizeof(struct snd_soc_tplg_mixer_control), 1, size, "mixers")) return -EINVAL; - mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; + ret = soc_tplg_control_dmixer_create(tplg, &kc); + if (ret) + return ret; - /* validate kcontrol */ - if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; - - sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL); - if (sm == NULL) - return -ENOMEM; - tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + - le32_to_cpu(mc->priv.size)); - - dev_dbg(tplg->dev, - "ASoC: adding mixer kcontrol %s with access 0x%x\n", - mc->hdr.name, mc->hdr.access); - - memset(&kc, 0, sizeof(kc)); - kc.name = mc->hdr.name; - kc.private_value = (long)sm; - kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc.access = le32_to_cpu(mc->hdr.access); - - /* we only support FL/FR channel mapping atm */ - sm->reg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FL); - sm->rreg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FR); - sm->shift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FL); - sm->rshift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FR); - - sm->max = le32_to_cpu(mc->max); - sm->min = le32_to_cpu(mc->min); - sm->invert = le32_to_cpu(mc->invert); - sm->platform_max = le32_to_cpu(mc->platform_max); + /* register dynamic object */ + sm = (struct soc_mixer_control *)&kc.private_value; INIT_LIST_HEAD(&sm->dobj.list); sm->dobj.type = SND_SOC_DOBJ_MIXER; @@ -959,33 +931,13 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size) if (tplg->ops) sm->dobj.unload = tplg->ops->control_unload; - /* map io handlers */ - ret = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg); - if (ret) { - soc_control_err(tplg, &mc->hdr, mc->hdr.name); - goto err; - } - - /* create any TLV data */ - ret = soc_tplg_create_tlv(tplg, &kc, &mc->hdr); - if (ret < 0) { - dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", mc->hdr.name); - goto err; - } - - /* pass control to driver for optional further init */ - ret = soc_tplg_control_load(tplg, &kc, &mc->hdr); - if (ret < 0) - goto err; - - /* register control here */ + /* create control directly */ ret = soc_tplg_add_kcontrol(tplg, &kc, &sm->dobj.control.kcontrol); if (ret < 0) - goto err; + return ret; list_add(&sm->dobj.list, &tplg->comp->dobj_list); -err: return ret; } From 8f2942b9198c935862bc2400602780844b352667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 27 Jun 2024 12:18:50 +0200 Subject: [PATCH 262/349] ASoC: topology: Unify code for creating standalone and widget enum control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code used to create standalone and widget enum control is same, with exception that in standalone case dynamic object needs to be registered and control created directly. Signed-off-by: Amadeusz Sławiński Link: https://patch.msgid.link/20240627101850.2191513-14-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 86 +++++----------------------------------- 1 file changed, 9 insertions(+), 77 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 5fde44808246..af5d42b57be7 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -943,46 +943,21 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size) static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size) { - struct snd_soc_tplg_enum_control *ec; + struct snd_kcontrol_new kc = {0}; struct soc_enum *se; - struct snd_kcontrol_new kc; - int ret = 0; + int ret; if (soc_tplg_check_elem_count(tplg, sizeof(struct snd_soc_tplg_enum_control), 1, size, "enums")) return -EINVAL; - ec = (struct snd_soc_tplg_enum_control *)tplg->pos; + ret = soc_tplg_control_denum_create(tplg, &kc); + if (ret) + return ret; - /* validate kcontrol */ - if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; - - se = devm_kzalloc(tplg->dev, (sizeof(*se)), GFP_KERNEL); - if (se == NULL) - return -ENOMEM; - - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - le32_to_cpu(ec->priv.size)); - - dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", - ec->hdr.name, ec->items); - - memset(&kc, 0, sizeof(kc)); - kc.name = ec->hdr.name; - kc.private_value = (long)se; - kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc.access = le32_to_cpu(ec->hdr.access); - - se->reg = tplg_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); - se->shift_l = tplg_chan_get_shift(tplg, ec->channel, - SNDRV_CHMAP_FL); - se->shift_r = tplg_chan_get_shift(tplg, ec->channel, - SNDRV_CHMAP_FR); - - se->mask = le32_to_cpu(ec->mask); + /* register dynamic object */ + se = (struct soc_enum *)kc.private_value; INIT_LIST_HEAD(&se->dobj.list); se->dobj.type = SND_SOC_DOBJ_ENUM; @@ -990,56 +965,13 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size) if (tplg->ops) se->dobj.unload = tplg->ops->control_unload; - switch (le32_to_cpu(ec->hdr.ops.info)) { - case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - case SND_SOC_TPLG_CTL_ENUM_VALUE: - ret = soc_tplg_denum_create_values(tplg, se, ec); - if (ret < 0) { - dev_err(tplg->dev, - "ASoC: could not create values for %s\n", - ec->hdr.name); - goto err; - } - fallthrough; - case SND_SOC_TPLG_CTL_ENUM: - case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - ret = soc_tplg_denum_create_texts(tplg, se, ec); - if (ret < 0) { - dev_err(tplg->dev, - "ASoC: could not create texts for %s\n", - ec->hdr.name); - goto err; - } - break; - default: - ret = -EINVAL; - dev_err(tplg->dev, - "ASoC: invalid enum control type %d for %s\n", - ec->hdr.ops.info, ec->hdr.name); - goto err; - } - - /* map io handlers */ - ret = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg); - if (ret) { - soc_control_err(tplg, &ec->hdr, ec->hdr.name); - goto err; - } - - /* pass control to driver for optional further init */ - ret = soc_tplg_control_load(tplg, &kc, &ec->hdr); - if (ret < 0) - goto err; - - /* register control here */ + /* create control directly */ ret = soc_tplg_add_kcontrol(tplg, &kc, &se->dobj.control.kcontrol); if (ret < 0) - goto err; + return ret; list_add(&se->dobj.list, &tplg->comp->dobj_list); -err: return ret; } From 83d43ab0a1cb83b1f3d731885a5d800ad8e84524 Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Tue, 2 Jul 2024 17:30:58 +0530 Subject: [PATCH 263/349] ASoC: dt-bindings: realtek,rt5645: Convert to dtschema Convert the RT5650/RT5645 audio CODEC bindings to DT schema. Reviewed-by: Rob Herring (Arm) Signed-off-by: Animesh Agarwal Cc: Daniel Baluta Link: https://patch.msgid.link/20240702120106.17100-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/realtek,rt5645.yaml | 131 ++++++++++++++++++ .../devicetree/bindings/sound/rt5645.txt | 82 ----------- 2 files changed, 131 insertions(+), 82 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/realtek,rt5645.yaml delete mode 100644 Documentation/devicetree/bindings/sound/rt5645.txt diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5645.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5645.yaml new file mode 100644 index 000000000000..13f09f1bc800 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,rt5645.yaml @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,rt5645.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RT5650/RT5645 audio CODEC + +maintainers: + - Animesh Agarwal + +description: | + This device supports I2C only. + + Pins on the device (for linking into audio routes) for RT5645/RT5650: + * DMIC L1 + * DMIC R1 + * DMIC L2 + * DMIC R2 + * IN1P + * IN1N + * IN2P + * IN2N + * Haptic Generator + * HPOL + * HPOR + * LOUTL + * LOUTR + * PDM1L + * PDM1R + * SPOL + * SPOR + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - realtek,rt5645 + - realtek,rt5650 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + description: The CODEC's interrupt output. + + avdd-supply: + description: Power supply for AVDD, providing 1.8V. + + cpvdd-supply: + description: Power supply for CPVDD, providing 3.5V. + + hp-detect-gpios: + description: + A GPIO spec for the external headphone detect pin. If jd-mode = 0, we + will get the JD status by getting the value of hp-detect-gpios. + maxItems: 1 + + cbj-sleeve-gpios: + description: + A GPIO spec to control the external combo jack circuit to tie the + sleeve/ring2 contacts to the ground or floating. It could avoid some + electric noise from the active speaker jacks. + maxItems: 1 + + realtek,in2-differential: + description: + Indicate MIC2 input are differential, rather than single-ended. + type: boolean + + realtek,dmic1-data-pin: + description: Specify which pin to be used as DMIC1 data pin. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # dmic1 is not used + - 1 # using IN2P pin as dmic1 data pin + - 2 # using GPIO6 pin as dmic1 data pin + - 3 # using GPIO10 pin as dmic1 data pin + - 4 # using GPIO12 pin as dmic1 data pin + + realtek,dmic2-data-pin: + description: Specify which pin to be used as DMIC2 data pin. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # dmic2 is not used + - 1 # using IN2N pin as dmic2 data pin + - 2 # using GPIO5 pin as dmic2 data pin + - 3 # using GPIO11 pin as dmic2 data pin + + realtek,jd-mode: + description: The JD mode of rt5645/rt5650. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # rt5645/rt5650 JD function is not used + - 1 # Mode-0 (VDD=3.3V), two port jack detection + - 2 # Mode-1 (VDD=3.3V), one port jack detection + - 3 # Mode-2 (VDD=1.8V), one port jack detection + +required: + - compatible + - reg + - interrupts + - avdd-supply + - cpvdd-supply + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + compatible = "realtek,rt5650"; + reg = <0x1a>; + hp-detect-gpios = <&gpio 19 0>; + cbj-sleeve-gpios = <&gpio 20 0>; + interrupt-parent = <&gpio>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + avdd-supply = <&avdd_reg>; + cpvdd-supply = <&cpvdd_supply>; + realtek,jd-mode = <3>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/rt5645.txt b/Documentation/devicetree/bindings/sound/rt5645.txt deleted file mode 100644 index c1fa379f5f3e..000000000000 --- a/Documentation/devicetree/bindings/sound/rt5645.txt +++ /dev/null @@ -1,82 +0,0 @@ -RT5650/RT5645 audio CODEC - -This device supports I2C only. - -Required properties: - -- compatible : One of "realtek,rt5645" or "realtek,rt5650". - -- reg : The I2C address of the device. - -- interrupts : The CODEC's interrupt output. - -- avdd-supply: Power supply for AVDD, providing 1.8V. - -- cpvdd-supply: Power supply for CPVDD, providing 3.5V. - -Optional properties: - -- hp-detect-gpios: - a GPIO spec for the external headphone detect pin. If jd-mode = 0, - we will get the JD status by getting the value of hp-detect-gpios. - -- cbj-sleeve-gpios: - a GPIO spec to control the external combo jack circuit to tie the sleeve/ring2 - contacts to the ground or floating. It could avoid some electric noise from the - active speaker jacks. - -- realtek,in2-differential - Boolean. Indicate MIC2 input are differential, rather than single-ended. - -- realtek,dmic1-data-pin - 0: dmic1 is not used - 1: using IN2P pin as dmic1 data pin - 2: using GPIO6 pin as dmic1 data pin - 3: using GPIO10 pin as dmic1 data pin - 4: using GPIO12 pin as dmic1 data pin - -- realtek,dmic2-data-pin - 0: dmic2 is not used - 1: using IN2N pin as dmic2 data pin - 2: using GPIO5 pin as dmic2 data pin - 3: using GPIO11 pin as dmic2 data pin - --- realtek,jd-mode : The JD mode of rt5645/rt5650 - 0 : rt5645/rt5650 JD function is not used - 1 : Mode-0 (VDD=3.3V), two port jack detection - 2 : Mode-1 (VDD=3.3V), one port jack detection - 3 : Mode-2 (VDD=1.8V), one port jack detection - -Pins on the device (for linking into audio routes) for RT5645/RT5650: - - * DMIC L1 - * DMIC R1 - * DMIC L2 - * DMIC R2 - * IN1P - * IN1N - * IN2P - * IN2N - * Haptic Generator - * HPOL - * HPOR - * LOUTL - * LOUTR - * PDM1L - * PDM1R - * SPOL - * SPOR - -Example: - -codec: rt5650@1a { - compatible = "realtek,rt5650"; - reg = <0x1a>; - hp-detect-gpios = <&gpio 19 0>; - cbj-sleeve-gpios = <&gpio 20 0>; - interrupt-parent = <&gpio>; - interrupts = <7 IRQ_TYPE_EDGE_FALLING>; - realtek,dmic-en = "true"; - realtek,en-jd-func = "true"; - realtek,jd-mode = <3>; -}; From 4aad1d9471108a5023e224422b2522323521174c Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 2 Jul 2024 15:53:49 -0600 Subject: [PATCH 264/349] ASoC: PCM6240: Use of_property_read_reg() Replace the open-coded parsing of "reg" with of_property_read_reg(). The #ifdef is also easily replaced with IS_ENABLED(). Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240702215349.839350-1-robh@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/pcm6240.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index 8f7057e689fb..5faf5e97a105 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -2081,10 +2082,6 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c) struct device_node *np; unsigned int dev_addrs[PCMDEVICE_MAX_I2C_DEVICES]; int ret = 0, i = 0, ndev = 0; -#ifdef CONFIG_OF - const __be32 *reg, *reg_end; - int len, sw, aw; -#endif pcm_dev = devm_kzalloc(&i2c->dev, sizeof(*pcm_dev), GFP_KERNEL); if (!pcm_dev) @@ -2118,27 +2115,19 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, pcm_dev); mutex_init(&pcm_dev->codec_lock); np = pcm_dev->dev->of_node; -#ifdef CONFIG_OF - aw = of_n_addr_cells(np); - sw = of_n_size_cells(np); - if (sw == 0) { - reg = (const __be32 *)of_get_property(np, - "reg", &len); - reg_end = reg + len/sizeof(*reg); - ndev = 0; - do { - dev_addrs[ndev] = of_read_number(reg, aw); - reg += aw; - ndev++; - } while (reg < reg_end); + + if (IS_ENABLED(CONFIG_OF)) { + u64 addr; + + for (i = 0; i < PCMDEVICE_MAX_I2C_DEVICES; i++) { + if (of_property_read_reg(np, i, &addr, NULL)) + break; + dev_addrs[ndev++] = addr; + } } else { ndev = 1; dev_addrs[0] = i2c->addr; } -#else - ndev = 1; - dev_addrs[0] = i2c->addr; -#endif pcm_dev->irq_info.gpio = of_irq_get(np, 0); for (i = 0; i < ndev; i++) From 31a45f9190b5b4f5cd8cdec8471babd5215eee04 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 2 Jul 2024 15:54:01 -0600 Subject: [PATCH 265/349] ASoC: tas2781: Use of_property_read_reg() Replace the open-coded parsing of "reg" with of_property_read_reg(). The #ifdef is also easily replaced with IS_ENABLED(). Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240702215402.839673-1-robh@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas2781-i2c.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index cc765d45c6b5..e0e630f66101 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -647,33 +648,20 @@ static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv) tas_priv->irq_info.irq_gpio = acpi_dev_gpio_irq_get(ACPI_COMPANION(&client->dev), 0); - } else { + } else if (IS_ENABLED(CONFIG_OF)) { struct device_node *np = tas_priv->dev->of_node; -#ifdef CONFIG_OF - const __be32 *reg, *reg_end; - int len, sw, aw; + u64 addr; - aw = of_n_addr_cells(np); - sw = of_n_size_cells(np); - if (sw == 0) { - reg = (const __be32 *)of_get_property(np, - "reg", &len); - reg_end = reg + len/sizeof(*reg); - ndev = 0; - do { - dev_addrs[ndev] = of_read_number(reg, aw); - reg += aw; - ndev++; - } while (reg < reg_end); - } else { - ndev = 1; - dev_addrs[0] = client->addr; + for (i = 0; i < TASDEVICE_MAX_CHANNELS; i++) { + if (of_property_read_reg(np, i, &addr, NULL)) + break; + dev_addrs[ndev++] = addr; } -#else + + tas_priv->irq_info.irq_gpio = of_irq_get(np, 0); + } else { ndev = 1; dev_addrs[0] = client->addr; -#endif - tas_priv->irq_info.irq_gpio = of_irq_get(np, 0); } tas_priv->ndev = ndev; for (i = 0; i < ndev; i++) From c66995ae403073212f5ba60d2079003866c6e130 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 3 Jul 2024 10:55:16 +0100 Subject: [PATCH 266/349] ASoC: cs35l56: Use header defines for Speaker Volume control definition The "Speaker Volume" control was being defined using four hardcoded magic numbers. There are #defines in the cs35l56.h header for these numbers, so change the code to use the defined constants. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20240703095517.208077-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 7cac9812f5b5..84c34f5b1a51 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -71,7 +71,11 @@ static const struct snd_kcontrol_new cs35l56_controls[] = { cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw), SOC_SINGLE_S_EXT_TLV("Speaker Volume", CS35L56_MAIN_RENDER_USER_VOLUME, - 6, -400, 400, 9, 0, + CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT, + CS35L56_MAIN_RENDER_USER_VOLUME_MIN, + CS35L56_MAIN_RENDER_USER_VOLUME_MAX, + CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT, + 0, cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw, vol_tlv), From 244389bd42870640c4b5ef672a360da329b579ed Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 3 Jul 2024 10:55:17 +0100 Subject: [PATCH 267/349] ASoC: cs35l56: Limit Speaker Volume to +12dB maximum Change CS35L56_MAIN_RENDER_USER_VOLUME_MAX to 48, to limit the maximum value of the Speaker Volume control to +12dB. The minimum value is unchanged so that the default 0dB has the same integer control value. The original maximum of 400 (+100dB) was the largest value that can be mathematically handled by the DSP. The actual maximum amplification is +12dB. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20240703095517.208077-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 642ef690ebc2..a6aa112e5741 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -207,7 +207,7 @@ /* CS35L56_MAIN_RENDER_USER_VOLUME */ #define CS35L56_MAIN_RENDER_USER_VOLUME_MIN -400 -#define CS35L56_MAIN_RENDER_USER_VOLUME_MAX 400 +#define CS35L56_MAIN_RENDER_USER_VOLUME_MAX 48 #define CS35L56_MAIN_RENDER_USER_VOLUME_MASK 0x0000FFC0 #define CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT 6 #define CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT 9 From c288f0a1c08efa65f9e3bb7954eb3cefb966c97d Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Fri, 28 Jun 2024 18:43:54 +0900 Subject: [PATCH 268/349] ASoC: fsl_xcvr: Improve suspend/resume flow in fsl_xcvr_trigger() In the current flow all interrupts are disabled in runtime suspend phase. However interrupts enablement only exists in fsl_xcvr_prepare(). After resume fsl_xcvr_prepare() may not be called so it will cause all interrupts still disabled even if resume from suspend. Interrupts should be explictily enabled after resume. Also, DPATH reset setting only exists in fsl_xcvr_prepare(). After resume from suspend DPATH should be reset otherwise there'll be channel swap issue. Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Link: https://patch.msgid.link/20240628094354.780720-1-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_xcvr.c | 43 +++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 337da46a2f90..bf9a4e90978e 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -529,16 +529,6 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream, break; } - ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, - FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL); - if (ret < 0) { - dev_err(dai->dev, "Error while setting IER0: %d\n", ret); - return ret; - } - - /* set DPATH RESET */ - m_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); - v_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, m_ctl, v_ctl); if (ret < 0) { dev_err(dai->dev, "Error while setting EXT_CTRL: %d\n", ret); @@ -679,6 +669,15 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + /* set DPATH RESET */ + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_DPTH_RESET(tx), + FSL_XCVR_EXT_CTRL_DPTH_RESET(tx)); + if (ret < 0) { + dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret); + return ret; + } + if (tx) { switch (xcvr->mode) { case FSL_XCVR_MODE_EARC: @@ -711,6 +710,13 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, + FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL); + if (ret < 0) { + dev_err(dai->dev, "Error while setting IER0: %d\n", ret); + return ret; + } + /* clear DPATH RESET */ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, FSL_XCVR_EXT_CTRL_DPTH_RESET(tx), @@ -733,6 +739,13 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, + FSL_XCVR_IRQ_EARC_ALL, 0); + if (ret < 0) { + dev_err(dai->dev, "Failed to clear IER0: %d\n", ret); + return ret; + } + if (tx) { switch (xcvr->mode) { case FSL_XCVR_MODE_SPDIF: @@ -1411,16 +1424,6 @@ static int fsl_xcvr_runtime_suspend(struct device *dev) struct fsl_xcvr *xcvr = dev_get_drvdata(dev); int ret; - /* - * Clear interrupts, when streams starts or resumes after - * suspend, interrupts are enabled in prepare(), so no need - * to enable interrupts in resume(). - */ - ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, - FSL_XCVR_IRQ_EARC_ALL, 0); - if (ret < 0) - dev_err(dev, "Failed to clear IER0: %d\n", ret); - if (!xcvr->soc_data->spdif_only) { /* Assert M0+ reset */ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, From cb148180125ef88a4c1c20ecf25337f1e45657bb Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 3 Jul 2024 18:20:57 +0200 Subject: [PATCH 269/349] ASoC: cs35l34: Constify struct regmap_config `cs35l34_regmap` is not modified and can be declared as const to move its data to a read-only section. Signed-off-by: Javier Carrasco Link: https://patch.msgid.link/20240703-sound-const-regmap_config-v1-1-2e379b0446a7@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l34.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index 4c517231d765..e63a518e3b8e 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -787,7 +787,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l34 = { .endianness = 1, }; -static struct regmap_config cs35l34_regmap = { +static const struct regmap_config cs35l34_regmap = { .reg_bits = 8, .val_bits = 8, From 306e0317bddfbb6bea1ad31c3daeecaec0304295 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 3 Jul 2024 18:20:58 +0200 Subject: [PATCH 270/349] ASoC: cs35l35: Constify struct regmap_config `cs35l35_regmap` is not modified and can be declared as const to move its data to a read-only section. Signed-off-by: Javier Carrasco Link: https://patch.msgid.link/20240703-sound-const-regmap_config-v1-2-2e379b0446a7@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index c39b3cfe9574..7a01b1d9fc9d 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1086,7 +1086,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l35 = { .endianness = 1, }; -static struct regmap_config cs35l35_regmap = { +static const struct regmap_config cs35l35_regmap = { .reg_bits = 8, .val_bits = 8, From 0271df05e6fe92b7000dcce5058a0ed6af127ef6 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 3 Jul 2024 18:20:59 +0200 Subject: [PATCH 271/349] ASoC: cs35l36: Constify struct regmap_config `cs35l36_regmap` is not modified and can be declared as const to move its data to a read-only section. Signed-off-by: Javier Carrasco Link: https://patch.msgid.link/20240703-sound-const-regmap_config-v1-3-2e379b0446a7@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l36.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index bc79990615e8..cbea79bd8980 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -1300,7 +1300,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l36 = { .endianness = 1, }; -static struct regmap_config cs35l36_regmap = { +static const struct regmap_config cs35l36_regmap = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, From 52f0aa5fb9437013f7f35d61426de497a8927891 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 3 Jul 2024 18:21:00 +0200 Subject: [PATCH 272/349] ASoC: cs53l30: Constify struct regmap_config `cs53l30_regmap` is not modified and can be declared as const to move its data to a read-only section. Signed-off-by: Javier Carrasco Link: https://patch.msgid.link/20240703-sound-const-regmap_config-v1-4-2e379b0446a7@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs53l30.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index 2ee13d885fdc..bcbaf28a0b2d 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -900,7 +900,7 @@ static const struct snd_soc_component_driver cs53l30_driver = { .endianness = 1, }; -static struct regmap_config cs53l30_regmap = { +static const struct regmap_config cs53l30_regmap = { .reg_bits = 8, .val_bits = 8, From 8d9c0ede48f29c9fccd095952d657fc5696da9ac Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 3 Jul 2024 18:21:01 +0200 Subject: [PATCH 273/349] ASoC: jz4760: Constify struct regmap_config `jz4760_codec_regmap_config` is not modified and can be declared as const to move its data to a read-only section. Signed-off-by: Javier Carrasco Link: https://patch.msgid.link/20240703-sound-const-regmap_config-v1-5-2e379b0446a7@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/jz4760.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c index 9df58e23d360..6217e611259f 100644 --- a/sound/soc/codecs/jz4760.c +++ b/sound/soc/codecs/jz4760.c @@ -821,7 +821,7 @@ static const u8 jz4760_codec_reg_defaults[] = { 0x1F, 0x00, 0x00, 0x00 }; -static struct regmap_config jz4760_codec_regmap_config = { +static const struct regmap_config jz4760_codec_regmap_config = { .reg_bits = 7, .val_bits = 8, From 7abfa29ba6a43c5e25622de1ba1f1846b9c9b5e8 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 3 Jul 2024 18:21:02 +0200 Subject: [PATCH 274/349] ASoC: jz4770: Constify struct regmap_config `jz4760_codec_regmap_config` is not modified and can be declared as const to move its data to a read-only section. Signed-off-by: Javier Carrasco Link: https://patch.msgid.link/20240703-sound-const-regmap_config-v1-6-2e379b0446a7@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/jz4770.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c index 1d0c467ab57b..acb9eaa7ea1c 100644 --- a/sound/soc/codecs/jz4770.c +++ b/sound/soc/codecs/jz4770.c @@ -872,7 +872,7 @@ static const u8 jz4770_codec_reg_defaults[] = { 0x07, 0x44, 0x1F, 0x00 }; -static struct regmap_config jz4770_codec_regmap_config = { +static const struct regmap_config jz4770_codec_regmap_config = { .reg_bits = 7, .val_bits = 8, From 5ffab1d3f3f3281869b894070fe4438f307759ec Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 3 Jul 2024 18:21:03 +0200 Subject: [PATCH 275/349] ASoC: wsa881x: Constify struct regmap_config `wsa881x_regmap_config` is not modified and can be declared as const to move its data to a read-only section. Signed-off-by: Javier Carrasco Link: https://patch.msgid.link/20240703-sound-const-regmap_config-v1-7-2e379b0446a7@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wsa881x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 1253695bebd8..0478599d0f35 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -634,7 +634,7 @@ static bool wsa881x_volatile_register(struct device *dev, unsigned int reg) } } -static struct regmap_config wsa881x_regmap_config = { +static const struct regmap_config wsa881x_regmap_config = { .reg_bits = 32, .val_bits = 8, .cache_type = REGCACHE_MAPLE, From 22c361dc7ce4d4d6a688febee57d6e4b130b96b3 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 3 Jul 2024 18:21:04 +0200 Subject: [PATCH 276/349] ASoC: wsa883x: Constify struct regmap_config `wsa883x_regmap_config` is not modified and can be declared as const to move its data to a read-only section. Signed-off-by: Javier Carrasco Link: https://patch.msgid.link/20240703-sound-const-regmap_config-v1-8-2e379b0446a7@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wsa883x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index f5a15f0e891e..d0ab4e2290b6 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -934,7 +934,7 @@ static bool wsa883x_volatile_register(struct device *dev, unsigned int reg) return wsa883x_readonly_register(dev, reg); } -static struct regmap_config wsa883x_regmap_config = { +static const struct regmap_config wsa883x_regmap_config = { .reg_bits = 32, .val_bits = 8, .cache_type = REGCACHE_MAPLE, From e15cc906b9c5af5414bb6002b6a036550bca6bd8 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 3 Jul 2024 18:21:05 +0200 Subject: [PATCH 277/349] ASoC: wsa884x: Constify struct regmap_config `wsa884x_regmap_config` is not modified and can be declared as const to move its data to a read-only section. Signed-off-by: Javier Carrasco Link: https://patch.msgid.link/20240703-sound-const-regmap_config-v1-9-2e379b0446a7@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wsa884x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index a6034547b4f3..d17ae17b2938 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -1319,7 +1319,7 @@ static bool wsa884x_volatile_register(struct device *dev, unsigned int reg) return wsa884x_readonly_register(dev, reg); } -static struct regmap_config wsa884x_regmap_config = { +static const struct regmap_config wsa884x_regmap_config = { .reg_bits = 32, .val_bits = 8, .cache_type = REGCACHE_MAPLE, From 3b628e617b21144579bbca806a26737e8485d93a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 1 Jul 2024 09:02:12 +0200 Subject: [PATCH 278/349] ASoC: tas5086: Convert to GPIO descriptors Switch the driver to use GPIO descriptors. Notice that we let the gpiolib handle line inversion for the active low reset line (nreset !reset). There are no upstream device trees using the tas5086 compatible string, if there were, we would need to ascertain that they all set the GPIO_ACTIVE_LOW flag on their GPIO lines. Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20240701-asoc-tas-gpios-v1-1-d69ec5d79939@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas5086.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 6d45df3b9ba4..4bc1fdd232bb 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -24,14 +24,13 @@ #include #include #include -#include +#include #include #include #include #include #include #include -#include #include #include #include @@ -246,7 +245,7 @@ struct tas5086_private { /* Current sample rate for de-emphasis control */ int rate; /* GPIO driving Reset pin, if any */ - int gpio_nreset; + struct gpio_desc *reset; struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; }; @@ -462,11 +461,11 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream) static void tas5086_reset(struct tas5086_private *priv) { - if (gpio_is_valid(priv->gpio_nreset)) { + if (priv->reset) { /* Reset codec - minimum assertion time is 400ns */ - gpio_direction_output(priv->gpio_nreset, 0); + gpiod_direction_output(priv->reset, 1); udelay(1); - gpio_set_value(priv->gpio_nreset, 1); + gpiod_set_value(priv->reset, 0); /* Codec needs ~15ms to wake up */ msleep(15); @@ -867,9 +866,9 @@ static void tas5086_remove(struct snd_soc_component *component) { struct tas5086_private *priv = snd_soc_component_get_drvdata(component); - if (gpio_is_valid(priv->gpio_nreset)) + if (priv->reset) /* Set codec to the reset state */ - gpio_set_value(priv->gpio_nreset, 0); + gpiod_set_value(priv->reset, 1); regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); }; @@ -914,7 +913,6 @@ static int tas5086_i2c_probe(struct i2c_client *i2c) { struct tas5086_private *priv; struct device *dev = &i2c->dev; - int gpio_nreset = -EINVAL; int i, ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -940,12 +938,11 @@ static int tas5086_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, priv); - gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); - if (gpio_is_valid(gpio_nreset)) - if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset")) - gpio_nreset = -EINVAL; - - priv->gpio_nreset = gpio_nreset; + /* Request line asserted */ + priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(priv->reset)) + return PTR_ERR(priv->reset); + gpiod_set_consumer_name(priv->reset, "TAS5086 Reset"); ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); if (ret < 0) { From 891168dc4a6c637ca76c64e7bde6917b96b9cd54 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Jul 2024 09:39:33 +0200 Subject: [PATCH 279/349] ASoC: codecs: lpass-rx-macro: Simplify PDS cleanup with devm Eliminate PDS cleanup by using devm_add_action_or_reset() which results in one less error path and smaller cleanup in remove(). Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240701-b4-qcom-audio-lpass-codec-cleanups-v3-1-6d98d4dd1ef5@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-macro-common.h | 5 +++++ sound/soc/codecs/lpass-rx-macro.c | 30 +++++++++++---------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h index 3aa9737f2737..21cb30ab706d 100644 --- a/sound/soc/codecs/lpass-macro-common.h +++ b/sound/soc/codecs/lpass-macro-common.h @@ -41,6 +41,11 @@ void lpass_macro_pds_exit(struct lpass_macro *pds); void lpass_macro_set_codec_version(enum lpass_codec_version version); enum lpass_codec_version lpass_macro_get_codec_version(void); +static inline void lpass_macro_pds_exit_action(void *pds) +{ + lpass_macro_pds_exit(pds); +} + static inline const char *lpass_macro_get_codec_version_string(int version) { switch (version) { diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index d47c49c90de3..77e734ad1885 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3803,11 +3803,14 @@ static int rx_macro_probe(struct platform_device *pdev) if (IS_ERR(rx->pds)) return PTR_ERR(rx->pds); + ret = devm_add_action_or_reset(dev, lpass_macro_pds_exit_action, rx->pds); + if (ret) + return ret; + base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto err; - } + if (IS_ERR(base)) + return PTR_ERR(base); + rx->codec_version = lpass_macro_get_codec_version(); switch (rx->codec_version) { case LPASS_CODEC_VERSION_1_0: @@ -3818,10 +3821,8 @@ static int rx_macro_probe(struct platform_device *pdev) rx->rxn_reg_stride = 0x80; def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_pre_2_5_defaults); reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL); - if (!reg_defaults) { - ret = -ENOMEM; - goto err; - } + if (!reg_defaults) + return -ENOMEM; memcpy(®_defaults[0], rx_defaults, sizeof(rx_defaults)); memcpy(®_defaults[ARRAY_SIZE(rx_defaults)], rx_pre_2_5_defaults, sizeof(rx_pre_2_5_defaults)); @@ -3833,18 +3834,15 @@ static int rx_macro_probe(struct platform_device *pdev) rx->rxn_reg_stride = 0xc0; def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_2_5_defaults); reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL); - if (!reg_defaults) { - ret = -ENOMEM; - goto err; - } + if (!reg_defaults) + return -ENOMEM; memcpy(®_defaults[0], rx_defaults, sizeof(rx_defaults)); memcpy(®_defaults[ARRAY_SIZE(rx_defaults)], rx_2_5_defaults, sizeof(rx_2_5_defaults)); break; default: dev_err(dev, "Unsupported Codec version (%d)\n", rx->codec_version); - ret = -EINVAL; - goto err; + return -EINVAL; } rx_regmap_config.reg_defaults = reg_defaults; @@ -3927,8 +3925,6 @@ err_dcodec: clk_disable_unprepare(rx->macro); err_ver: kfree(reg_defaults); -err: - lpass_macro_pds_exit(rx->pds); return ret; } @@ -3942,8 +3938,6 @@ static void rx_macro_remove(struct platform_device *pdev) clk_disable_unprepare(rx->fsgen); clk_disable_unprepare(rx->macro); clk_disable_unprepare(rx->dcodec); - - lpass_macro_pds_exit(rx->pds); } static const struct of_device_id rx_macro_dt_match[] = { From ee5e13b2c92324938c2bffc44b36b5a29fc28087 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Jul 2024 09:39:34 +0200 Subject: [PATCH 280/349] ASoC: codecs: lpass-rx-macro: Simplify with cleanup.h Allocate the default register values array with scoped/cleanup.h to reduce number of error paths and make code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240701-b4-qcom-audio-lpass-codec-cleanups-v3-2-6d98d4dd1ef5@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 77e734ad1885..638f3995a364 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. +#include #include #include #include @@ -3764,7 +3765,6 @@ static const struct snd_soc_component_driver rx_macro_component_drv = { static int rx_macro_probe(struct platform_device *pdev) { - struct reg_default *reg_defaults; struct device *dev = &pdev->dev; kernel_ulong_t flags; struct rx_macro *rx; @@ -3812,6 +3812,8 @@ static int rx_macro_probe(struct platform_device *pdev) return PTR_ERR(base); rx->codec_version = lpass_macro_get_codec_version(); + struct reg_default *reg_defaults __free(kfree) = NULL; + switch (rx->codec_version) { case LPASS_CODEC_VERSION_1_0: case LPASS_CODEC_VERSION_1_1: @@ -3849,10 +3851,8 @@ static int rx_macro_probe(struct platform_device *pdev) rx_regmap_config.num_reg_defaults = def_count; rx->regmap = devm_regmap_init_mmio(dev, base, &rx_regmap_config); - if (IS_ERR(rx->regmap)) { - ret = PTR_ERR(rx->regmap); - goto err_ver; - } + if (IS_ERR(rx->regmap)) + return PTR_ERR(rx->regmap); dev_set_drvdata(dev, rx); @@ -3864,7 +3864,7 @@ static int rx_macro_probe(struct platform_device *pdev) ret = clk_prepare_enable(rx->macro); if (ret) - goto err_ver; + return ret; ret = clk_prepare_enable(rx->dcodec); if (ret) @@ -3910,7 +3910,6 @@ static int rx_macro_probe(struct platform_device *pdev) if (ret) goto err_clkout; - kfree(reg_defaults); return 0; err_clkout: @@ -3923,8 +3922,6 @@ err_mclk: clk_disable_unprepare(rx->dcodec); err_dcodec: clk_disable_unprepare(rx->macro); -err_ver: - kfree(reg_defaults); return ret; } From 0c02cacf62fd90bf9f0c6c33e9a4862cfc50aab4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Jul 2024 09:39:35 +0200 Subject: [PATCH 281/349] ASoC: codecs: lpass-rx-macro: Keep static regmap_config as const The driver has static 'struct regmap_config', which is then customized depending on device version. This works fine, because there should not be two devices in a system simultaneously and even less likely that such two devices would have different versions, thus different regmap config. However code is cleaner and more obvious when static data in the driver is also const - it serves as a template. Mark the 'struct regmap_config' as const and duplicate it in the probe() with kmemdup to allow customizing per detected device variant. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240701-b4-qcom-audio-lpass-codec-cleanups-v3-3-6d98d4dd1ef5@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 638f3995a364..d4d7e02db83f 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -1663,7 +1663,7 @@ static bool rx_is_readable_register(struct device *dev, unsigned int reg) return rx_is_rw_register(dev, reg); } -static struct regmap_config rx_regmap_config = { +static const struct regmap_config rx_regmap_config = { .name = "rx_macro", .reg_bits = 16, .val_bits = 32, /* 8 but with 32 bit read/write */ @@ -3847,10 +3847,16 @@ static int rx_macro_probe(struct platform_device *pdev) return -EINVAL; } - rx_regmap_config.reg_defaults = reg_defaults; - rx_regmap_config.num_reg_defaults = def_count; + struct regmap_config *reg_config __free(kfree) = kmemdup(&rx_regmap_config, + sizeof(*reg_config), + GFP_KERNEL); + if (!reg_config) + return -ENOMEM; - rx->regmap = devm_regmap_init_mmio(dev, base, &rx_regmap_config); + reg_config->reg_defaults = reg_defaults; + reg_config->num_reg_defaults = def_count; + + rx->regmap = devm_regmap_init_mmio(dev, base, reg_config); if (IS_ERR(rx->regmap)) return PTR_ERR(rx->regmap); From bf95919fe1917efa8f5da83057ff9fc11130aa55 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Jul 2024 09:39:36 +0200 Subject: [PATCH 282/349] ASoC: dapm: Use unsigned for number of widgets in snd_soc_dapm_new_controls() Number of widgets in array passed to snd_soc_dapm_new_controls() cannot be negative, so make it explicit by using 'unsigned int', just like snd_soc_add_component_controls() is doing. Reviewed-by: Dmitry Baryshkov Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240701-b4-qcom-audio-lpass-codec-cleanups-v3-4-6d98d4dd1ef5@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 2 +- sound/soc/soc-dapm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 667ecd4daa68..12cd7b5a2202 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -457,7 +457,7 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uncontrol); int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget, int num); + const struct snd_soc_dapm_widget *widget, unsigned int num); struct snd_soc_dapm_widget *snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget); struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 16dad4a45443..32cc90d09bc2 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3857,7 +3857,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); */ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget, - int num) + unsigned int num) { int i; int ret = 0; From c72585d79249fb07ca3e3c91022e312d21f20f40 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Jul 2024 09:39:37 +0200 Subject: [PATCH 283/349] ASoC: codecs: lpass-rx-macro: Use unsigned for number of widgets Driver uses ARRAY_SIZE() to get number of widgets later passed to snd_soc_dapm_new_controls(), which is an 'unsigned int'. Reviewed-by: Dmitry Baryshkov Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240701-b4-qcom-audio-lpass-codec-cleanups-v3-5-6d98d4dd1ef5@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index d4d7e02db83f..ce42749660c8 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3612,8 +3612,8 @@ static int rx_macro_component_probe(struct snd_soc_component *component) struct rx_macro *rx = snd_soc_component_get_drvdata(component); const struct snd_soc_dapm_widget *widgets; const struct snd_kcontrol_new *controls; - unsigned int num_controls; - int ret, num_widgets; + unsigned int num_controls, num_widgets; + int ret; snd_soc_component_init_regmap(component, rx->regmap); From 67820eb9f4895791da46df42ff7942dfc1353bb2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Jul 2024 09:39:38 +0200 Subject: [PATCH 284/349] ASoC: codecs: lpass-wsa-macro: Simplify with cleanup.h Driver's probe() has two allocations which are needed only within the probe() itself - for devm_regmap_init_mmio(). Usage of devm interface is a bit misleading here, because these can be freed right after each scope finishes. This makes the code a bit more obvious and self documenting. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240701-b4-qcom-audio-lpass-codec-cleanups-v3-6-6d98d4dd1ef5@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index b4e7139bac61..73a588289408 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. +#include #include #include #include @@ -2725,8 +2726,6 @@ static const struct snd_soc_component_driver wsa_macro_component_drv = { static int wsa_macro_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct reg_default *reg_defaults; - struct regmap_config *reg_config; struct wsa_macro *wsa; kernel_ulong_t flags; void __iomem *base; @@ -2765,6 +2764,8 @@ static int wsa_macro_probe(struct platform_device *pdev) return PTR_ERR(base); wsa->codec_version = lpass_macro_get_codec_version(); + struct reg_default *reg_defaults __free(kfree) = NULL; + switch (wsa->codec_version) { case LPASS_CODEC_VERSION_1_0: case LPASS_CODEC_VERSION_1_1: @@ -2773,9 +2774,8 @@ static int wsa_macro_probe(struct platform_device *pdev) case LPASS_CODEC_VERSION_2_1: wsa->reg_layout = &wsa_codec_v2_1; def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_1); - reg_defaults = devm_kmalloc_array(dev, def_count, - sizeof(*reg_defaults), - GFP_KERNEL); + reg_defaults = kmalloc_array(def_count, sizeof(*reg_defaults), + GFP_KERNEL); if (!reg_defaults) return -ENOMEM; memcpy(®_defaults[0], wsa_defaults, sizeof(wsa_defaults)); @@ -2789,9 +2789,8 @@ static int wsa_macro_probe(struct platform_device *pdev) case LPASS_CODEC_VERSION_2_8: wsa->reg_layout = &wsa_codec_v2_5; def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_5); - reg_defaults = devm_kmalloc_array(dev, def_count, - sizeof(*reg_defaults), - GFP_KERNEL); + reg_defaults = kmalloc_array(def_count, sizeof(*reg_defaults), + GFP_KERNEL); if (!reg_defaults) return -ENOMEM; memcpy(®_defaults[0], wsa_defaults, sizeof(wsa_defaults)); @@ -2804,8 +2803,9 @@ static int wsa_macro_probe(struct platform_device *pdev) return -EINVAL; } - reg_config = devm_kmemdup(dev, &wsa_regmap_config, - sizeof(*reg_config), GFP_KERNEL); + struct regmap_config *reg_config __free(kfree) = kmemdup(&wsa_regmap_config, + sizeof(*reg_config), + GFP_KERNEL); if (!reg_config) return -ENOMEM; @@ -2816,8 +2816,6 @@ static int wsa_macro_probe(struct platform_device *pdev) if (IS_ERR(wsa->regmap)) return PTR_ERR(wsa->regmap); - devm_kfree(dev, reg_config); - devm_kfree(dev, reg_defaults); dev_set_drvdata(dev, wsa); wsa->dev = dev; From e62599902327d27687693f6e5253a5d56583db58 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:28 +0200 Subject: [PATCH 285/349] ASoC: fsl: fsl_qmc_audio: Check devm_kasprintf() returned value devm_kasprintf() can return a NULL pointer on failure but this returned value is not checked. Fix this lack and check the returned value. Fixes: 075c7125b11c ("ASoC: fsl: Add support for QMC audio") Cc: stable@vger.kernel.org Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-2-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_qmc_audio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index bfaaa451735b..dd90ef16fa97 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -604,6 +604,8 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d", np->parent->name, qmc_dai->id); + if (!qmc_dai->name) + return -ENOMEM; qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np, "fsl,qmc-chan"); From 86dd725b57a88869acfe15b0405937450d0aef30 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:29 +0200 Subject: [PATCH 286/349] ASoC: fsl: fsl_qmc_audio: Fix issues detected by checkpatch ./scripts/checkpatch.pl --strict --codespell detected several issues when running on the fsl_qmc_audio.c file: - CHECK: spaces preferred around that '*' (ctx:VxV) - CHECK: Alignment should match open parenthesis - CHECK: Comparison to NULL could be written "!prtd" - CHECK: spaces preferred around that '/' (ctx:VxV) - CHECK: Lines should not end with a '(' - CHECK: Please don't use multiple blank lines Some of them are present several times. Fix all of these issues without any functional changes. Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-3-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_qmc_audio.c | 65 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index dd90ef16fa97..917a32389f3d 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -54,7 +54,7 @@ static int qmc_audio_pcm_construct(struct snd_soc_component *component, return ret; snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev, - 64*1024, 64*1024); + 64 * 1024, 64 * 1024); return 0; } @@ -89,8 +89,8 @@ static void qmc_audio_pcm_write_complete(void *context) prtd->period_ptr_submitted = prtd->dma_buffer_start; ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, - qmc_audio_pcm_write_complete, prtd); + prtd->period_ptr_submitted, prtd->period_size, + qmc_audio_pcm_write_complete, prtd); if (ret) { dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n", ret); @@ -118,8 +118,8 @@ static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned i prtd->period_ptr_submitted = prtd->dma_buffer_start; ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, - qmc_audio_pcm_read_complete, prtd); + prtd->period_ptr_submitted, prtd->period_size, + qmc_audio_pcm_read_complete, prtd); if (ret) { dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n", ret); @@ -144,8 +144,8 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* Submit first chunk ... */ ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, - qmc_audio_pcm_write_complete, prtd); + prtd->period_ptr_submitted, prtd->period_size, + qmc_audio_pcm_write_complete, prtd); if (ret) { dev_err(component->dev, "write_submit failed %d\n", ret); @@ -159,8 +159,8 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, /* ... and send it */ ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, - qmc_audio_pcm_write_complete, prtd); + prtd->period_ptr_submitted, prtd->period_size, + qmc_audio_pcm_write_complete, prtd); if (ret) { dev_err(component->dev, "write_submit failed %d\n", ret); @@ -169,8 +169,8 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, } else { /* Submit first chunk ... */ ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, - qmc_audio_pcm_read_complete, prtd); + prtd->period_ptr_submitted, prtd->period_size, + qmc_audio_pcm_read_complete, prtd); if (ret) { dev_err(component->dev, "read_submit failed %d\n", ret); @@ -184,8 +184,8 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, /* ... and send it */ ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, - qmc_audio_pcm_read_complete, prtd); + prtd->period_ptr_submitted, prtd->period_size, + qmc_audio_pcm_read_complete, prtd); if (ret) { dev_err(component->dev, "write_submit failed %d\n", ret); @@ -220,8 +220,8 @@ static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *compone } static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component, - const struct of_phandle_args *args, - const char **dai_name) + const struct of_phandle_args *args, + const char **dai_name) { struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev); struct snd_soc_dai_driver *dai_driver; @@ -245,10 +245,10 @@ static const struct snd_pcm_hardware qmc_audio_pcm_hardware = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE, .period_bytes_min = 32, - .period_bytes_max = 64*1024, + .period_bytes_max = 64 * 1024, .periods_min = 2, - .periods_max = 2*1024, - .buffer_bytes_max = 64*1024, + .periods_max = 2 * 1024, + .buffer_bytes_max = 64 * 1024, }; static int qmc_audio_pcm_open(struct snd_soc_component *component, @@ -266,7 +266,7 @@ static int qmc_audio_pcm_open(struct snd_soc_component *component, return ret; prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); - if (prtd == NULL) + if (!prtd) return -ENOMEM; runtime->private_data = prtd; @@ -329,13 +329,13 @@ static int qmc_dai_hw_rule_channels_by_format(struct qmc_dai *qmc_dai, ch.max = nb_ts; break; case 16: - ch.max = nb_ts/2; + ch.max = nb_ts / 2; break; case 32: - ch.max = nb_ts/4; + ch.max = nb_ts / 4; break; case 64: - ch.max = nb_ts/8; + ch.max = nb_ts / 8; break; default: dev_err(qmc_dai->dev, "format physical width %u not supported\n", @@ -356,9 +356,8 @@ static int qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts); } -static int qmc_dai_hw_rule_capture_channels_by_format( - struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) +static int qmc_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { struct qmc_dai *qmc_dai = rule->private; @@ -394,18 +393,16 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai, return snd_mask_refine(f_old, &f_new); } -static int qmc_dai_hw_rule_playback_format_by_channels( - struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) +static int qmc_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { struct qmc_dai *qmc_dai = rule->private; return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts); } -static int qmc_dai_hw_rule_capture_format_by_channels( - struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) +static int qmc_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { struct qmc_dai *qmc_dai = rule->private; @@ -413,7 +410,7 @@ static int qmc_dai_hw_rule_capture_format_by_channels( } static int qmc_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct qmc_dai_prtd *prtd = substream->runtime->private_data; snd_pcm_hw_rule_func_t hw_rule_channels_by_format; @@ -587,7 +584,8 @@ static u64 qmc_audio_formats(u8 nb_ts) } static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np, - struct qmc_dai *qmc_dai, struct snd_soc_dai_driver *qmc_soc_dai_driver) + struct qmc_dai *qmc_dai, + struct snd_soc_dai_driver *qmc_soc_dai_driver) { struct qmc_chan_info info; u32 val; @@ -704,7 +702,6 @@ static int qmc_audio_probe(struct platform_device *pdev) i++; } - platform_set_drvdata(pdev, qmc_audio); ret = devm_snd_soc_register_component(qmc_audio->dev, From 42212b2ce8b1182d536452eee2880d2de7cce059 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:30 +0200 Subject: [PATCH 287/349] ASoC: fsl: fsl_qmc_audio: Split channel buffer and PCM pointer handling The driver mixes some internal values for channel DMA buffer handling and PCM pointer handling. In the currently supported interleaved mode, this mix does not lead to any issues but in order to prepare the support for the non-interleaved mode, having them clearly separated will ease the support and avoid additional computation to convert values used in channel DMA buffer management in values usable for PCM pointer. Use a specific set of variable for PCM pointer handling and an other set for channel DMA buffer. Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-4-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_qmc_audio.c | 84 +++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index 917a32389f3d..e8281e548746 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -35,11 +35,16 @@ struct qmc_audio { struct qmc_dai_prtd { struct qmc_dai *qmc_dai; - dma_addr_t dma_buffer_start; - dma_addr_t period_ptr_submitted; - dma_addr_t period_ptr_ended; - dma_addr_t dma_buffer_end; - size_t period_size; + + snd_pcm_uframes_t buffer_ended; + snd_pcm_uframes_t buffer_size; + snd_pcm_uframes_t period_size; + + dma_addr_t ch_dma_addr_start; + dma_addr_t ch_dma_addr_current; + dma_addr_t ch_dma_addr_end; + size_t ch_dma_size; + struct snd_pcm_substream *substream; }; @@ -65,13 +70,17 @@ static int qmc_audio_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_runtime *runtime = substream->runtime; struct qmc_dai_prtd *prtd = substream->runtime->private_data; - prtd->dma_buffer_start = runtime->dma_addr; - prtd->dma_buffer_end = runtime->dma_addr + params_buffer_bytes(params); - prtd->period_size = params_period_bytes(params); - prtd->period_ptr_submitted = prtd->dma_buffer_start; - prtd->period_ptr_ended = prtd->dma_buffer_start; prtd->substream = substream; + prtd->buffer_ended = 0; + prtd->buffer_size = params_buffer_size(params); + prtd->period_size = params_period_size(params); + + prtd->ch_dma_addr_start = runtime->dma_addr; + prtd->ch_dma_addr_end = runtime->dma_addr + params_buffer_bytes(params); + prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; + prtd->ch_dma_size = params_period_bytes(params); + return 0; } @@ -80,16 +89,16 @@ static void qmc_audio_pcm_write_complete(void *context) struct qmc_dai_prtd *prtd = context; int ret; - prtd->period_ptr_ended += prtd->period_size; - if (prtd->period_ptr_ended >= prtd->dma_buffer_end) - prtd->period_ptr_ended = prtd->dma_buffer_start; + prtd->buffer_ended += prtd->period_size; + if (prtd->buffer_ended >= prtd->buffer_size) + prtd->buffer_ended = 0; - prtd->period_ptr_submitted += prtd->period_size; - if (prtd->period_ptr_submitted >= prtd->dma_buffer_end) - prtd->period_ptr_submitted = prtd->dma_buffer_start; + prtd->ch_dma_addr_current += prtd->ch_dma_size; + if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) + prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, + prtd->ch_dma_addr_current, prtd->ch_dma_size, qmc_audio_pcm_write_complete, prtd); if (ret) { dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n", @@ -104,21 +113,21 @@ static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned i struct qmc_dai_prtd *prtd = context; int ret; - if (length != prtd->period_size) { + if (length != prtd->ch_dma_size) { dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n", - length, prtd->period_size); + length, prtd->ch_dma_size); } - prtd->period_ptr_ended += prtd->period_size; - if (prtd->period_ptr_ended >= prtd->dma_buffer_end) - prtd->period_ptr_ended = prtd->dma_buffer_start; + prtd->buffer_ended += prtd->period_size; + if (prtd->buffer_ended >= prtd->buffer_size) + prtd->buffer_ended = 0; - prtd->period_ptr_submitted += prtd->period_size; - if (prtd->period_ptr_submitted >= prtd->dma_buffer_end) - prtd->period_ptr_submitted = prtd->dma_buffer_start; + prtd->ch_dma_addr_current += prtd->ch_dma_size; + if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) + prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, + prtd->ch_dma_addr_current, prtd->ch_dma_size, qmc_audio_pcm_read_complete, prtd); if (ret) { dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n", @@ -144,7 +153,7 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* Submit first chunk ... */ ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, + prtd->ch_dma_addr_current, prtd->ch_dma_size, qmc_audio_pcm_write_complete, prtd); if (ret) { dev_err(component->dev, "write_submit failed %d\n", @@ -153,13 +162,13 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, } /* ... prepare next one ... */ - prtd->period_ptr_submitted += prtd->period_size; - if (prtd->period_ptr_submitted >= prtd->dma_buffer_end) - prtd->period_ptr_submitted = prtd->dma_buffer_start; + prtd->ch_dma_addr_current += prtd->ch_dma_size; + if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) + prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; /* ... and send it */ ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, + prtd->ch_dma_addr_current, prtd->ch_dma_size, qmc_audio_pcm_write_complete, prtd); if (ret) { dev_err(component->dev, "write_submit failed %d\n", @@ -169,7 +178,7 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, } else { /* Submit first chunk ... */ ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, + prtd->ch_dma_addr_current, prtd->ch_dma_size, qmc_audio_pcm_read_complete, prtd); if (ret) { dev_err(component->dev, "read_submit failed %d\n", @@ -178,13 +187,13 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, } /* ... prepare next one ... */ - prtd->period_ptr_submitted += prtd->period_size; - if (prtd->period_ptr_submitted >= prtd->dma_buffer_end) - prtd->period_ptr_submitted = prtd->dma_buffer_start; + prtd->ch_dma_addr_current += prtd->ch_dma_size; + if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) + prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; /* ... and send it */ ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, - prtd->period_ptr_submitted, prtd->period_size, + prtd->ch_dma_addr_current, prtd->ch_dma_size, qmc_audio_pcm_read_complete, prtd); if (ret) { dev_err(component->dev, "write_submit failed %d\n", @@ -215,8 +224,7 @@ static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *compone { struct qmc_dai_prtd *prtd = substream->runtime->private_data; - return bytes_to_frames(substream->runtime, - prtd->period_ptr_ended - prtd->dma_buffer_start); + return prtd->buffer_ended; } static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component, From 5e51a1f9dfd90de6e44cfb5340d48263f9e8f8d8 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:31 +0200 Subject: [PATCH 288/349] ASoC: fsl: fsl_qmc_audio: Identify the QMC channel involved in completion routines The current QMC audio driver uses only one QMC channel per DAI. The context used by QMC channel transfer (read and write) completion routines does not contains any QMC channel and the only one available per DAI is used to schedule the next transfer. This works pretty well with only one QMC channel per DAI. The future support for non-inlerleave mode will use several QMC channel per DAI. In that case, QMC channel transfer completion routines need to identify the QMC channel related to the completion. In order to fill this lack, even if identifying the current QMC channel among several QMC channels is not needed for the current code, add one indirection level and introduce the qmc_dai_chan data structrure. This structure contains the QMC channel involved in the completion and refererences to the runtime context (capture and playback) used by the DAI. Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-5-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_qmc_audio.c | 72 +++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index e8281e548746..b07770257bad 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -17,13 +17,19 @@ #include #include +struct qmc_dai_chan { + struct qmc_dai_prtd *prtd_tx; + struct qmc_dai_prtd *prtd_rx; + struct qmc_chan *qmc_chan; +}; + struct qmc_dai { char *name; int id; struct device *dev; - struct qmc_chan *qmc_chan; unsigned int nb_tx_ts; unsigned int nb_rx_ts; + struct qmc_dai_chan chan; }; struct qmc_audio { @@ -86,9 +92,12 @@ static int qmc_audio_pcm_hw_params(struct snd_soc_component *component, static void qmc_audio_pcm_write_complete(void *context) { - struct qmc_dai_prtd *prtd = context; + struct qmc_dai_chan *chan = context; + struct qmc_dai_prtd *prtd; int ret; + prtd = chan->prtd_tx; + prtd->buffer_ended += prtd->period_size; if (prtd->buffer_ended >= prtd->buffer_size) prtd->buffer_ended = 0; @@ -97,9 +106,10 @@ static void qmc_audio_pcm_write_complete(void *context) if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; - ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_write_complete, prtd); + qmc_audio_pcm_write_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n", ret); @@ -110,9 +120,12 @@ static void qmc_audio_pcm_write_complete(void *context) static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags) { - struct qmc_dai_prtd *prtd = context; + struct qmc_dai_chan *chan = context; + struct qmc_dai_prtd *prtd; int ret; + prtd = chan->prtd_rx; + if (length != prtd->ch_dma_size) { dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n", length, prtd->ch_dma_size); @@ -126,9 +139,10 @@ static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned i if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; - ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_read_complete, prtd); + qmc_audio_pcm_read_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n", ret); @@ -151,10 +165,13 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + prtd->qmc_dai->chan.prtd_tx = prtd; + /* Submit first chunk ... */ - ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_write_complete, prtd); + qmc_audio_pcm_write_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(component->dev, "write_submit failed %d\n", ret); @@ -167,19 +184,23 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; /* ... and send it */ - ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_write_complete, prtd); + qmc_audio_pcm_write_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(component->dev, "write_submit failed %d\n", ret); return ret; } } else { + prtd->qmc_dai->chan.prtd_rx = prtd; + /* Submit first chunk ... */ - ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_read_complete, prtd); + qmc_audio_pcm_read_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(component->dev, "read_submit failed %d\n", ret); @@ -192,9 +213,10 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; /* ... and send it */ - ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_read_complete, prtd); + qmc_audio_pcm_read_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(component->dev, "write_submit failed %d\n", ret); @@ -489,7 +511,7 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { chan_param.mode = QMC_TRANSPARENT; chan_param.transp.max_rx_buf_size = params_period_bytes(params); - ret = qmc_chan_set_param(qmc_dai->qmc_chan, &chan_param); + ret = qmc_chan_set_param(qmc_dai->chan.qmc_chan, &chan_param); if (ret) { dev_err(dai->dev, "set param failed %d\n", ret); @@ -520,23 +542,23 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = qmc_chan_start(qmc_dai->qmc_chan, direction); + ret = qmc_chan_start(qmc_dai->chan.qmc_chan, direction); if (ret) return ret; break; case SNDRV_PCM_TRIGGER_STOP: - ret = qmc_chan_stop(qmc_dai->qmc_chan, direction); + ret = qmc_chan_stop(qmc_dai->chan.qmc_chan, direction); if (ret) return ret; - ret = qmc_chan_reset(qmc_dai->qmc_chan, direction); + ret = qmc_chan_reset(qmc_dai->chan.qmc_chan, direction); if (ret) return ret; break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = qmc_chan_stop(qmc_dai->qmc_chan, direction); + ret = qmc_chan_stop(qmc_dai->chan.qmc_chan, direction); if (ret) return ret; break; @@ -613,10 +635,10 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * if (!qmc_dai->name) return -ENOMEM; - qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np, - "fsl,qmc-chan"); - if (IS_ERR(qmc_dai->qmc_chan)) { - ret = PTR_ERR(qmc_dai->qmc_chan); + qmc_dai->chan.qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np, + "fsl,qmc-chan"); + if (IS_ERR(qmc_dai->chan.qmc_chan)) { + ret = PTR_ERR(qmc_dai->chan.qmc_chan); return dev_err_probe(qmc_audio->dev, ret, "dai %d get QMC channel failed\n", qmc_dai->id); } @@ -624,7 +646,7 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * qmc_soc_dai_driver->id = qmc_dai->id; qmc_soc_dai_driver->name = qmc_dai->name; - ret = qmc_chan_get_info(qmc_dai->qmc_chan, &info); + ret = qmc_chan_get_info(qmc_dai->chan.qmc_chan, &info); if (ret) { dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n", qmc_dai->id, ret); From 33a6969fbc653f25d5204b17fb67d5a21e6295e6 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:32 +0200 Subject: [PATCH 289/349] ASoC: fsl: fsl_qmc_audio: Introduce qmc_audio_pcm_{read,write}_submit() Submitting data to QMC channels is done in several places: transfer completions and DAI start. The operation done is simple and consist in one function call. With the future introduction of support for non-interleaved mode, submitting data will be more complex. To avoid copy/paste of code in several places, introduce qmc_audio_pcm_{read,write}_submit() whose goal is to handle this data submission. Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-6-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_qmc_audio.c | 93 +++++++++++++++++------------------ 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index b07770257bad..36145f1ddbf1 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -90,11 +90,29 @@ static int qmc_audio_pcm_hw_params(struct snd_soc_component *component, return 0; } +static void qmc_audio_pcm_write_complete(void *context); + +static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd) +{ + int ret; + + ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, + prtd->ch_dma_addr_current, prtd->ch_dma_size, + qmc_audio_pcm_write_complete, + &prtd->qmc_dai->chan); + if (ret) { + dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n", + ret); + return ret; + } + + return 0; +} + static void qmc_audio_pcm_write_complete(void *context) { struct qmc_dai_chan *chan = context; struct qmc_dai_prtd *prtd; - int ret; prtd = chan->prtd_tx; @@ -106,23 +124,33 @@ static void qmc_audio_pcm_write_complete(void *context) if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; - ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, - prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_write_complete, - &prtd->qmc_dai->chan); + qmc_audio_pcm_write_submit(prtd); + + snd_pcm_period_elapsed(prtd->substream); +} + +static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags); + +static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd) +{ + int ret; + + ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, + prtd->ch_dma_addr_current, prtd->ch_dma_size, + qmc_audio_pcm_read_complete, + &prtd->qmc_dai->chan); if (ret) { - dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n", + dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n", ret); } - snd_pcm_period_elapsed(prtd->substream); + return 0; } static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags) { struct qmc_dai_chan *chan = context; struct qmc_dai_prtd *prtd; - int ret; prtd = chan->prtd_rx; @@ -139,14 +167,7 @@ static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned i if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; - ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, - prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_read_complete, - &prtd->qmc_dai->chan); - if (ret) { - dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n", - ret); - } + qmc_audio_pcm_read_submit(prtd); snd_pcm_period_elapsed(prtd->substream); } @@ -168,15 +189,9 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, prtd->qmc_dai->chan.prtd_tx = prtd; /* Submit first chunk ... */ - ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, - prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_write_complete, - &prtd->qmc_dai->chan); - if (ret) { - dev_err(component->dev, "write_submit failed %d\n", - ret); + ret = qmc_audio_pcm_write_submit(prtd); + if (ret) return ret; - } /* ... prepare next one ... */ prtd->ch_dma_addr_current += prtd->ch_dma_size; @@ -184,28 +199,16 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; /* ... and send it */ - ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, - prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_write_complete, - &prtd->qmc_dai->chan); - if (ret) { - dev_err(component->dev, "write_submit failed %d\n", - ret); + ret = qmc_audio_pcm_write_submit(prtd); + if (ret) return ret; - } } else { prtd->qmc_dai->chan.prtd_rx = prtd; /* Submit first chunk ... */ - ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, - prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_read_complete, - &prtd->qmc_dai->chan); - if (ret) { - dev_err(component->dev, "read_submit failed %d\n", - ret); + ret = qmc_audio_pcm_read_submit(prtd); + if (ret) return ret; - } /* ... prepare next one ... */ prtd->ch_dma_addr_current += prtd->ch_dma_size; @@ -213,15 +216,9 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; /* ... and send it */ - ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, - prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_read_complete, - &prtd->qmc_dai->chan); - if (ret) { - dev_err(component->dev, "write_submit failed %d\n", - ret); + ret = qmc_audio_pcm_read_submit(prtd); + if (ret) return ret; - } } break; From b81cfa66435bdab896b4c24e11d24ec33bdb0601 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:33 +0200 Subject: [PATCH 290/349] ASoC: fsl: fsl_qmc_audio: Introduce qmc_dai_constraints_interleaved() Constraints are set by qmc_dai_startup(). These constraints are specific to the interleaved mode. With the future introduction of support for non-interleaved mode, a new set of constraints will be set. To make the code clear and keep qmc_dai_startup() simple, extract the current interleaved mode constraints settings to a specific function. Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-7-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_qmc_audio.c | 37 +++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index 36145f1ddbf1..f70c6c8eec4a 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -436,24 +436,14 @@ static int qmc_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params * return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts); } -static int qmc_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream, + struct qmc_dai *qmc_dai) { - struct qmc_dai_prtd *prtd = substream->runtime->private_data; snd_pcm_hw_rule_func_t hw_rule_channels_by_format; snd_pcm_hw_rule_func_t hw_rule_format_by_channels; - struct qmc_dai *qmc_dai; unsigned int frame_bits; int ret; - qmc_dai = qmc_dai_get_data(dai); - if (!qmc_dai) { - dev_err(dai->dev, "Invalid dai\n"); - return -EINVAL; - } - - prtd->qmc_dai = qmc_dai; - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format; hw_rule_format_by_channels = qmc_dai_hw_rule_capture_format_by_channels; @@ -468,7 +458,7 @@ static int qmc_dai_startup(struct snd_pcm_substream *substream, hw_rule_channels_by_format, qmc_dai, SNDRV_PCM_HW_PARAM_FORMAT, -1); if (ret) { - dev_err(dai->dev, "Failed to add channels rule (%d)\n", ret); + dev_err(qmc_dai->dev, "Failed to add channels rule (%d)\n", ret); return ret; } @@ -476,7 +466,7 @@ static int qmc_dai_startup(struct snd_pcm_substream *substream, hw_rule_format_by_channels, qmc_dai, SNDRV_PCM_HW_PARAM_CHANNELS, -1); if (ret) { - dev_err(dai->dev, "Failed to add format rule (%d)\n", ret); + dev_err(qmc_dai->dev, "Failed to add format rule (%d)\n", ret); return ret; } @@ -484,13 +474,30 @@ static int qmc_dai_startup(struct snd_pcm_substream *substream, SNDRV_PCM_HW_PARAM_FRAME_BITS, frame_bits); if (ret < 0) { - dev_err(dai->dev, "Failed to add frame_bits constraint (%d)\n", ret); + dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret); return ret; } return 0; } +static int qmc_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct qmc_dai_prtd *prtd = substream->runtime->private_data; + struct qmc_dai *qmc_dai; + + qmc_dai = qmc_dai_get_data(dai); + if (!qmc_dai) { + dev_err(dai->dev, "Invalid dai\n"); + return -EINVAL; + } + + prtd->qmc_dai = qmc_dai; + + return qmc_dai_constraints_interleaved(substream, qmc_dai); +} + static int qmc_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) From 37797c605da33445adc112561695f70bfaa11133 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:34 +0200 Subject: [PATCH 291/349] soc: fsl: cpm1: qmc: Introduce functions to get a channel from a phandle list qmc_chan_get_byphandle() and the resource managed version retrieve a channel from a simple phandle. Extend the API and introduce qmc_chan_get_byphandles_index() and the resource managed version in order to retrieve a channel from a phandle list using the provided index to identify the phandle in the list. Also update qmc_chan_get_byphandle() and the resource managed version to use qmc_chan_get_byphandles_index() and so avoid code duplication. Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-8-herve.codina@bootlin.com Signed-off-by: Mark Brown --- drivers/soc/fsl/qe/qmc.c | 19 +++++++++++-------- include/soc/fsl/qe/qmc.h | 25 ++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index f498db9abe35..e23d60018400 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1777,13 +1777,15 @@ static struct qmc_chan *qmc_chan_get_from_qmc(struct device_node *qmc_np, unsign return qmc_chan; } -struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name) +struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np, + const char *phandles_name, + int index) { struct of_phandle_args out_args; struct qmc_chan *qmc_chan; int ret; - ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, + ret = of_parse_phandle_with_fixed_args(np, phandles_name, 1, index, &out_args); if (ret < 0) return ERR_PTR(ret); @@ -1797,7 +1799,7 @@ struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phan of_node_put(out_args.np); return qmc_chan; } -EXPORT_SYMBOL(qmc_chan_get_byphandle); +EXPORT_SYMBOL(qmc_chan_get_byphandles_index); struct qmc_chan *qmc_chan_get_bychild(struct device_node *np) { @@ -1827,9 +1829,10 @@ static void devm_qmc_chan_release(struct device *dev, void *res) qmc_chan_put(*qmc_chan); } -struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, - struct device_node *np, - const char *phandle_name) +struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev, + struct device_node *np, + const char *phandles_name, + int index) { struct qmc_chan *qmc_chan; struct qmc_chan **dr; @@ -1838,7 +1841,7 @@ struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, if (!dr) return ERR_PTR(-ENOMEM); - qmc_chan = qmc_chan_get_byphandle(np, phandle_name); + qmc_chan = qmc_chan_get_byphandles_index(np, phandles_name, index); if (!IS_ERR(qmc_chan)) { *dr = qmc_chan; devres_add(dev, dr); @@ -1848,7 +1851,7 @@ struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, return qmc_chan; } -EXPORT_SYMBOL(devm_qmc_chan_get_byphandle); +EXPORT_SYMBOL(devm_qmc_chan_get_byphandles_index); struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, struct device_node *np) diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h index 2a333fc1ea81..0fa7205145ce 100644 --- a/include/soc/fsl/qe/qmc.h +++ b/include/soc/fsl/qe/qmc.h @@ -16,11 +16,30 @@ struct device_node; struct device; struct qmc_chan; -struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name); +struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np, + const char *phandles_name, + int index); +struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev, + struct device_node *np, + const char *phandles_name, + int index); + +static inline struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, + const char *phandle_name) +{ + return qmc_chan_get_byphandles_index(np, phandle_name, 0); +} + +static inline struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, + struct device_node *np, + const char *phandle_name) +{ + return devm_qmc_chan_get_byphandles_index(dev, np, phandle_name, 0); +} + struct qmc_chan *qmc_chan_get_bychild(struct device_node *np); void qmc_chan_put(struct qmc_chan *chan); -struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, struct device_node *np, - const char *phandle_name); + struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, struct device_node *np); enum qmc_mode { From af8432b2e41abc0a20bdc01a3b144ea7b2f1ee09 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:35 +0200 Subject: [PATCH 292/349] soc: fsl: cpm1: qmc: Introduce qmc_chan_count_phandles() No function in the QMC API is available to get the number of phandles present in a phandle list. Fill this lack introducing qmc_chan_count_phandles(). Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-9-herve.codina@bootlin.com Signed-off-by: Mark Brown --- drivers/soc/fsl/qe/qmc.c | 13 +++++++++++++ include/soc/fsl/qe/qmc.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index e23d60018400..76bb496305a0 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1777,6 +1777,19 @@ static struct qmc_chan *qmc_chan_get_from_qmc(struct device_node *qmc_np, unsign return qmc_chan; } +int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name) +{ + int count; + + /* phandles are fixed args phandles with one arg */ + count = of_count_phandle_with_args(np, phandles_name, NULL); + if (count < 0) + return count; + + return count / 2; +} +EXPORT_SYMBOL(qmc_chan_count_phandles); + struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np, const char *phandles_name, int index) diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h index 0fa7205145ce..294e42ea8d4c 100644 --- a/include/soc/fsl/qe/qmc.h +++ b/include/soc/fsl/qe/qmc.h @@ -16,6 +16,8 @@ struct device_node; struct device; struct qmc_chan; +int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name); + struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np, const char *phandles_name, int index); From fb6013168fa94d5863ed6085b24eaeb89102ad74 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:36 +0200 Subject: [PATCH 293/349] dt-bindings: sound: fsl,qmc-audio: Add support for multiple QMC channels per DAI The QMC audio uses one QMC channel per DAI and uses this QMC channel to transmit interleaved audio channel samples. In order to work in non-interleave mode, a QMC audio DAI needs to use multiple QMC channels. In that case, the DAI maps each QMC channel to exactly one audio channel. Allow QMC audio DAIs with multiple QMC channels attached. Signed-off-by: Herve Codina Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240701113038.55144-10-herve.codina@bootlin.com Signed-off-by: Mark Brown --- .../bindings/sound/fsl,qmc-audio.yaml | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml b/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml index b522ed7dcc51..a23e49198c37 100644 --- a/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml @@ -12,7 +12,9 @@ maintainers: description: | The QMC audio is an ASoC component which uses QMC (QUICC Multichannel Controller) channels to transfer the audio data. - It provides as many DAI as the number of QMC channel used. + It provides several DAIs. For each DAI, the DAI is working in interleaved mode + if only one QMC channel is used by the DAI or it is working in non-interleaved + mode if several QMC channels are used by the DAI. allOf: - $ref: dai-common.yaml# @@ -45,12 +47,19 @@ patternProperties: fsl,qmc-chan: $ref: /schemas/types.yaml#/definitions/phandle-array items: - - items: - - description: phandle to QMC node - - description: Channel number + items: + - description: phandle to QMC node + - description: Channel number + minItems: 1 description: - Should be a phandle/number pair. The phandle to QMC node and the QMC - channel to use for this DAI. + Should be a phandle/number pair list. The list of phandle to QMC node + and the QMC channel pair to use for this DAI. + If only one phandle/number pair is provided, this DAI works in + interleaved mode, i.e. audio channels for this DAI are interleaved in + the QMC channel. If more than one pair is provided, this DAI works + in non-interleave mode. In that case the first audio channel uses the + the first QMC channel, the second audio channel uses the second QMC + channel, etc... required: - reg @@ -79,6 +88,11 @@ examples: reg = <17>; fsl,qmc-chan = <&qmc 17>; }; + dai@18 { + reg = <18>; + /* Non-interleaved mode */ + fsl,qmc-chan = <&qmc 18>, <&qmc 19>; + }; }; sound { @@ -115,4 +129,19 @@ examples: dai-tdm-slot-rx-mask = <0 0 1 0 1 0 1 0 1>; }; }; + simple-audio-card,dai-link@2 { + reg = <2>; + format = "dsp_b"; + cpu { + sound-dai = <&audio_controller 18>; + }; + codec { + sound-dai = <&codec3>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <8>; + /* TS 9, 10 */ + dai-tdm-slot-tx-mask = <0 0 0 0 0 0 0 0 0 1 1>; + dai-tdm-slot-rx-mask = <0 0 0 0 0 0 0 0 0 1 1>; + }; + }; }; From 188d9cae54388171d28bd632a2561863db4b9f8b Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:37 +0200 Subject: [PATCH 294/349] ASoC: fsl: fsl_qmc_audio: Add support for non-interleaved mode. The current fsl_qmc_audio works in interleaved mode. The audio samples are interleaved and all data are sent to (received from) one QMC channel. Using several QMC channels, non interleaved mode can be easily supported. In that case, data related to ch0 are sent to (received from) the first QMC channel, data related to ch1 use the next QMC channel and so on up to the last channel. In terms of constraints and settings, the two modes are slightly different: - Interleaved mode: - The sample size should fit in the number of time-slots available for the QMC channel. - The number of audio channels should fit in the number of time-slots (taking into account the sample size) available for the QMC channel. - Non-interleaved mode: - The number of audio channels is the number of available QMC channels. - Each QMC channel should have the same number of time-slots. - The sample size equals the number of time-slots of one QMC channel. Add support for the non-interleaved mode allowing multiple QMC channel per DAI. The DAI switches in non-interleaved mode when more that one QMC channel is available. Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-11-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_qmc_audio.c | 370 +++++++++++++++++++++++++++------- 1 file changed, 296 insertions(+), 74 deletions(-) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index f70c6c8eec4a..8668abd35208 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -29,7 +29,11 @@ struct qmc_dai { struct device *dev; unsigned int nb_tx_ts; unsigned int nb_rx_ts; - struct qmc_dai_chan chan; + + unsigned int nb_chans_avail; + unsigned int nb_chans_used_tx; + unsigned int nb_chans_used_rx; + struct qmc_dai_chan *chans; }; struct qmc_audio { @@ -50,7 +54,10 @@ struct qmc_dai_prtd { dma_addr_t ch_dma_addr_current; dma_addr_t ch_dma_addr_end; size_t ch_dma_size; + size_t ch_dma_offset; + unsigned int channels; + DECLARE_BITMAP(chans_pending, 64); struct snd_pcm_substream *substream; }; @@ -69,6 +76,18 @@ static int qmc_audio_pcm_construct(struct snd_soc_component *component, return 0; } +static bool qmc_audio_access_is_interleaved(snd_pcm_access_t access) +{ + switch (access) { + case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED: + case SNDRV_PCM_ACCESS_RW_INTERLEAVED: + return true; + default: + break; + } + return false; +} + static int qmc_audio_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -76,6 +95,14 @@ static int qmc_audio_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_runtime *runtime = substream->runtime; struct qmc_dai_prtd *prtd = substream->runtime->private_data; + /* + * In interleaved mode, the driver uses one QMC channel for all audio + * channels whereas in non-interleaved mode, it uses one QMC channel per + * audio channel. + */ + prtd->channels = qmc_audio_access_is_interleaved(params_access(params)) ? + 1 : params_channels(params); + prtd->substream = substream; prtd->buffer_ended = 0; @@ -83,9 +110,10 @@ static int qmc_audio_pcm_hw_params(struct snd_soc_component *component, prtd->period_size = params_period_size(params); prtd->ch_dma_addr_start = runtime->dma_addr; - prtd->ch_dma_addr_end = runtime->dma_addr + params_buffer_bytes(params); + prtd->ch_dma_offset = params_buffer_bytes(params) / prtd->channels; + prtd->ch_dma_addr_end = runtime->dma_addr + prtd->ch_dma_offset; prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; - prtd->ch_dma_size = params_period_bytes(params); + prtd->ch_dma_size = params_period_bytes(params) / prtd->channels; return 0; } @@ -94,16 +122,23 @@ static void qmc_audio_pcm_write_complete(void *context); static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd) { + unsigned int i; int ret; - ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, - prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_write_complete, - &prtd->qmc_dai->chan); - if (ret) { - dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n", - ret); - return ret; + for (i = 0; i < prtd->channels; i++) { + bitmap_set(prtd->chans_pending, i, 1); + + ret = qmc_chan_write_submit(prtd->qmc_dai->chans[i].qmc_chan, + prtd->ch_dma_addr_current + i * prtd->ch_dma_offset, + prtd->ch_dma_size, + qmc_audio_pcm_write_complete, + &prtd->qmc_dai->chans[i]); + if (ret) { + dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n", + i, ret); + bitmap_clear(prtd->chans_pending, i, 1); + return ret; + } } return 0; @@ -116,6 +151,16 @@ static void qmc_audio_pcm_write_complete(void *context) prtd = chan->prtd_tx; + /* Mark the current channel as completed */ + bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1); + + /* + * All QMC channels involved must have completed their transfer before + * submitting a new one. + */ + if (!bitmap_empty(prtd->chans_pending, 64)) + return; + prtd->buffer_ended += prtd->period_size; if (prtd->buffer_ended >= prtd->buffer_size) prtd->buffer_ended = 0; @@ -133,15 +178,23 @@ static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned i static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd) { + unsigned int i; int ret; - ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, - prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_read_complete, - &prtd->qmc_dai->chan); - if (ret) { - dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n", - ret); + for (i = 0; i < prtd->channels; i++) { + bitmap_set(prtd->chans_pending, i, 1); + + ret = qmc_chan_read_submit(prtd->qmc_dai->chans[i].qmc_chan, + prtd->ch_dma_addr_current + i * prtd->ch_dma_offset, + prtd->ch_dma_size, + qmc_audio_pcm_read_complete, + &prtd->qmc_dai->chans[i]); + if (ret) { + dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n", + i, ret); + bitmap_clear(prtd->chans_pending, i, 1); + return ret; + } } return 0; @@ -154,11 +207,21 @@ static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned i prtd = chan->prtd_rx; + /* Mark the current channel as completed */ + bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1); + if (length != prtd->ch_dma_size) { dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n", length, prtd->ch_dma_size); } + /* + * All QMC channels involved must have completed their transfer before + * submitting a new one. + */ + if (!bitmap_empty(prtd->chans_pending, 64)) + return; + prtd->buffer_ended += prtd->period_size; if (prtd->buffer_ended >= prtd->buffer_size) prtd->buffer_ended = 0; @@ -176,6 +239,7 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd) { struct qmc_dai_prtd *prtd = substream->runtime->private_data; + unsigned int i; int ret; if (!prtd->qmc_dai) { @@ -185,8 +249,10 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, switch (cmd) { case SNDRV_PCM_TRIGGER_START: + bitmap_zero(prtd->chans_pending, 64); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - prtd->qmc_dai->chan.prtd_tx = prtd; + for (i = 0; i < prtd->channels; i++) + prtd->qmc_dai->chans[i].prtd_tx = prtd; /* Submit first chunk ... */ ret = qmc_audio_pcm_write_submit(prtd); @@ -203,7 +269,8 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, if (ret) return ret; } else { - prtd->qmc_dai->chan.prtd_rx = prtd; + for (i = 0; i < prtd->channels; i++) + prtd->qmc_dai->chans[i].prtd_rx = prtd; /* Submit first chunk ... */ ret = qmc_audio_pcm_read_submit(prtd); @@ -270,6 +337,7 @@ static const struct snd_pcm_hardware qmc_audio_pcm_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_NONINTERLEAVED | SNDRV_PCM_INFO_PAUSE, .period_bytes_min = 32, .period_bytes_max = 64 * 1024, @@ -442,6 +510,7 @@ static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream, snd_pcm_hw_rule_func_t hw_rule_channels_by_format; snd_pcm_hw_rule_func_t hw_rule_format_by_channels; unsigned int frame_bits; + u64 access; int ret; if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { @@ -478,6 +547,44 @@ static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream, return ret; } + access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED | + 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED; + ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS, + access); + if (ret) { + dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret); + return ret; + } + + return 0; +} + +static int qmc_dai_constraints_noninterleaved(struct snd_pcm_substream *substream, + struct qmc_dai *qmc_dai) +{ + unsigned int frame_bits; + u64 access; + int ret; + + frame_bits = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ? + qmc_dai->nb_rx_ts * 8 : qmc_dai->nb_tx_ts * 8; + ret = snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_FRAME_BITS, + frame_bits); + if (ret < 0) { + dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret); + return ret; + } + + access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED | + 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED; + ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS, + access); + if (ret) { + dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret); + return ret; + } + return 0; } @@ -495,7 +602,9 @@ static int qmc_dai_startup(struct snd_pcm_substream *substream, prtd->qmc_dai = qmc_dai; - return qmc_dai_constraints_interleaved(substream, qmc_dai); + return qmc_dai->nb_chans_avail > 1 ? + qmc_dai_constraints_noninterleaved(substream, qmc_dai) : + qmc_dai_constraints_interleaved(substream, qmc_dai); } static int qmc_dai_hw_params(struct snd_pcm_substream *substream, @@ -503,7 +612,9 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct qmc_chan_param chan_param = {0}; + unsigned int nb_chans_used; struct qmc_dai *qmc_dai; + unsigned int i; int ret; qmc_dai = qmc_dai_get_data(dai); @@ -512,15 +623,34 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* + * In interleaved mode, the driver uses one QMC channel for all audio + * channels whereas in non-interleaved mode, it uses one QMC channel per + * audio channel. + */ + nb_chans_used = qmc_audio_access_is_interleaved(params_access(params)) ? + 1 : params_channels(params); + + if (nb_chans_used > qmc_dai->nb_chans_avail) { + dev_err(dai->dev, "Not enough qmc_chans. Need %u, avail %u\n", + nb_chans_used, qmc_dai->nb_chans_avail); + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { chan_param.mode = QMC_TRANSPARENT; - chan_param.transp.max_rx_buf_size = params_period_bytes(params); - ret = qmc_chan_set_param(qmc_dai->chan.qmc_chan, &chan_param); - if (ret) { - dev_err(dai->dev, "set param failed %d\n", - ret); - return ret; + chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used; + for (i = 0; i < nb_chans_used; i++) { + ret = qmc_chan_set_param(qmc_dai->chans[i].qmc_chan, &chan_param); + if (ret) { + dev_err(dai->dev, "chans[%u], set param failed %d\n", + i, ret); + return ret; + } } + qmc_dai->nb_chans_used_rx = nb_chans_used; + } else { + qmc_dai->nb_chans_used_tx = nb_chans_used; } return 0; @@ -529,9 +659,12 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream, static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { + unsigned int nb_chans_used; struct qmc_dai *qmc_dai; + unsigned int i; int direction; - int ret; + int ret = 0; + int ret_tmp; qmc_dai = qmc_dai_get_data(dai); if (!qmc_dai) { @@ -539,30 +672,50 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd, return -EINVAL; } - direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - QMC_CHAN_WRITE : QMC_CHAN_READ; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = QMC_CHAN_WRITE; + nb_chans_used = qmc_dai->nb_chans_used_tx; + } else { + direction = QMC_CHAN_READ; + nb_chans_used = qmc_dai->nb_chans_used_rx; + } switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = qmc_chan_start(qmc_dai->chan.qmc_chan, direction); - if (ret) - return ret; + for (i = 0; i < nb_chans_used; i++) { + ret = qmc_chan_start(qmc_dai->chans[i].qmc_chan, direction); + if (ret) + goto err_stop; + } break; case SNDRV_PCM_TRIGGER_STOP: - ret = qmc_chan_stop(qmc_dai->chan.qmc_chan, direction); - if (ret) - return ret; - ret = qmc_chan_reset(qmc_dai->chan.qmc_chan, direction); + /* Stop and reset all QMC channels and return the first error encountered */ + for (i = 0; i < nb_chans_used; i++) { + ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction); + if (!ret) + ret = ret_tmp; + if (ret_tmp) + continue; + + ret_tmp = qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction); + if (!ret) + ret = ret_tmp; + } if (ret) return ret; break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = qmc_chan_stop(qmc_dai->chan.qmc_chan, direction); + /* Stop all QMC channels and return the first error encountered */ + for (i = 0; i < nb_chans_used; i++) { + ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction); + if (!ret) + ret = ret_tmp; + } if (ret) return ret; break; @@ -572,6 +725,13 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd, } return 0; + +err_stop: + while (i--) { + qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction); + qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction); + } + return ret; } static const struct snd_soc_dai_ops qmc_dai_ops = { @@ -580,7 +740,7 @@ static const struct snd_soc_dai_ops qmc_dai_ops = { .hw_params = qmc_dai_hw_params, }; -static u64 qmc_audio_formats(u8 nb_ts) +static u64 qmc_audio_formats(u8 nb_ts, bool is_noninterleaved) { unsigned int format_width; unsigned int chan_width; @@ -612,6 +772,13 @@ static u64 qmc_audio_formats(u8 nb_ts) if (format_width > chan_width || chan_width % format_width) continue; + /* + * In non interleaved mode, we can only support formats that + * can fit only 1 time in the channel + */ + if (is_noninterleaved && format_width != chan_width) + continue; + formats_mask |= pcm_format_to_bits(format); } return formats_mask; @@ -622,6 +789,12 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * struct snd_soc_dai_driver *qmc_soc_dai_driver) { struct qmc_chan_info info; + unsigned long rx_fs_rate; + unsigned long tx_fs_rate; + unsigned int nb_tx_ts; + unsigned int nb_rx_ts; + unsigned int i; + int count; u32 val; int ret; @@ -639,56 +812,105 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * if (!qmc_dai->name) return -ENOMEM; - qmc_dai->chan.qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np, - "fsl,qmc-chan"); - if (IS_ERR(qmc_dai->chan.qmc_chan)) { - ret = PTR_ERR(qmc_dai->chan.qmc_chan); - return dev_err_probe(qmc_audio->dev, ret, - "dai %d get QMC channel failed\n", qmc_dai->id); + count = qmc_chan_count_phandles(np, "fsl,qmc-chan"); + if (count < 0) + return dev_err_probe(qmc_audio->dev, count, + "dai %d get number of QMC channel failed\n", qmc_dai->id); + if (!count) + return dev_err_probe(qmc_audio->dev, -EINVAL, + "dai %d no QMC channel defined\n", qmc_dai->id); + + qmc_dai->chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->chans), GFP_KERNEL); + if (!qmc_dai->chans) + return -ENOMEM; + + for (i = 0; i < count; i++) { + qmc_dai->chans[i].qmc_chan = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np, + "fsl,qmc-chan", i); + if (IS_ERR(qmc_dai->chans[i].qmc_chan)) { + return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->chans[i].qmc_chan), + "dai %d get QMC channel %d failed\n", qmc_dai->id, i); + } + + ret = qmc_chan_get_info(qmc_dai->chans[i].qmc_chan, &info); + if (ret) { + dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n", + qmc_dai->id, i, ret); + return ret; + } + dev_info(qmc_audio->dev, "dai %d QMC channel %d mode %d, nb_tx_ts %u, nb_rx_ts %u\n", + qmc_dai->id, i, info.mode, info.nb_tx_ts, info.nb_rx_ts); + + if (info.mode != QMC_TRANSPARENT) { + dev_err(qmc_audio->dev, "dai %d QMC chan %d mode %d is not QMC_TRANSPARENT\n", + qmc_dai->id, i, info.mode); + return -EINVAL; + } + + /* + * All channels must have the same number of Tx slots and the + * same numbers of Rx slots. + */ + if (i == 0) { + nb_tx_ts = info.nb_tx_ts; + nb_rx_ts = info.nb_rx_ts; + tx_fs_rate = info.tx_fs_rate; + rx_fs_rate = info.rx_fs_rate; + } else { + if (nb_tx_ts != info.nb_tx_ts) { + dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Tx timeslots (%u instead of %u)\n", + qmc_dai->id, i, info.nb_tx_ts, nb_tx_ts); + return -EINVAL; + } + if (nb_rx_ts != info.nb_rx_ts) { + dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Rx timeslots (%u instead of %u)\n", + qmc_dai->id, i, info.nb_rx_ts, nb_rx_ts); + return -EINVAL; + } + if (tx_fs_rate != info.tx_fs_rate) { + dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Tx frame sample rate (%lu instead of %lu)\n", + qmc_dai->id, i, info.tx_fs_rate, tx_fs_rate); + return -EINVAL; + } + if (rx_fs_rate != info.rx_fs_rate) { + dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Rx frame sample rate (%lu instead of %lu)\n", + qmc_dai->id, i, info.rx_fs_rate, rx_fs_rate); + return -EINVAL; + } + } } + qmc_dai->nb_chans_avail = count; + qmc_dai->nb_tx_ts = nb_tx_ts * count; + qmc_dai->nb_rx_ts = nb_rx_ts * count; + qmc_soc_dai_driver->id = qmc_dai->id; qmc_soc_dai_driver->name = qmc_dai->name; - ret = qmc_chan_get_info(qmc_dai->chan.qmc_chan, &info); - if (ret) { - dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n", - qmc_dai->id, ret); - return ret; - } - dev_info(qmc_audio->dev, "dai %d QMC channel mode %d, nb_tx_ts %u, nb_rx_ts %u\n", - qmc_dai->id, info.mode, info.nb_tx_ts, info.nb_rx_ts); - - if (info.mode != QMC_TRANSPARENT) { - dev_err(qmc_audio->dev, "dai %d QMC chan mode %d is not QMC_TRANSPARENT\n", - qmc_dai->id, info.mode); - return -EINVAL; - } - qmc_dai->nb_tx_ts = info.nb_tx_ts; - qmc_dai->nb_rx_ts = info.nb_rx_ts; - qmc_soc_dai_driver->playback.channels_min = 0; qmc_soc_dai_driver->playback.channels_max = 0; - if (qmc_dai->nb_tx_ts) { + if (nb_tx_ts) { qmc_soc_dai_driver->playback.channels_min = 1; - qmc_soc_dai_driver->playback.channels_max = qmc_dai->nb_tx_ts; + qmc_soc_dai_driver->playback.channels_max = count > 1 ? count : nb_tx_ts; } - qmc_soc_dai_driver->playback.formats = qmc_audio_formats(qmc_dai->nb_tx_ts); + qmc_soc_dai_driver->playback.formats = qmc_audio_formats(nb_tx_ts, + count > 1 ? true : false); qmc_soc_dai_driver->capture.channels_min = 0; qmc_soc_dai_driver->capture.channels_max = 0; - if (qmc_dai->nb_rx_ts) { + if (nb_rx_ts) { qmc_soc_dai_driver->capture.channels_min = 1; - qmc_soc_dai_driver->capture.channels_max = qmc_dai->nb_rx_ts; + qmc_soc_dai_driver->capture.channels_max = count > 1 ? count : nb_rx_ts; } - qmc_soc_dai_driver->capture.formats = qmc_audio_formats(qmc_dai->nb_rx_ts); + qmc_soc_dai_driver->capture.formats = qmc_audio_formats(nb_rx_ts, + count > 1 ? true : false); - qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(info.tx_fs_rate); - qmc_soc_dai_driver->playback.rate_min = info.tx_fs_rate; - qmc_soc_dai_driver->playback.rate_max = info.tx_fs_rate; - qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(info.rx_fs_rate); - qmc_soc_dai_driver->capture.rate_min = info.rx_fs_rate; - qmc_soc_dai_driver->capture.rate_max = info.rx_fs_rate; + qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(tx_fs_rate); + qmc_soc_dai_driver->playback.rate_min = tx_fs_rate; + qmc_soc_dai_driver->playback.rate_max = tx_fs_rate; + qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(rx_fs_rate); + qmc_soc_dai_driver->capture.rate_min = rx_fs_rate; + qmc_soc_dai_driver->capture.rate_max = rx_fs_rate; qmc_soc_dai_driver->ops = &qmc_dai_ops; From 6558e8737af2067763e115ce3759372cd068b897 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 4 Jul 2024 10:59:44 +0200 Subject: [PATCH 295/349] ASoC: SOF: ipc4-topology: Use single token list for the copiers There is no need to keep separate token list for dai and 'common' copier token list when the 'common' list is actually the aif list, the SOF_COPIER_DEEP_BUFFER_TOKENS are not applicable for buffers. We could have separate lists for all types but it is probably simpler to just use a single list for all types of copiers. Function specific tokens will be only parsed by function specific code anyways. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi Signed-off-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20240704085944.371450-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 7755c01735f5..90f6856ee80c 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -3307,14 +3307,17 @@ static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link return 0; } -static enum sof_tokens common_copier_token_list[] = { +/* Tokens needed for different copier variants (aif, dai and buffer) */ +static enum sof_tokens copier_token_list[] = { SOF_COMP_TOKENS, + SOF_COPIER_TOKENS, SOF_AUDIO_FMT_NUM_TOKENS, SOF_IN_AUDIO_FORMAT_TOKENS, SOF_OUT_AUDIO_FORMAT_TOKENS, - SOF_COPIER_DEEP_BUFFER_TOKENS, - SOF_COPIER_TOKENS, SOF_COMP_EXT_TOKENS, + + SOF_COPIER_DEEP_BUFFER_TOKENS, /* for AIF copier */ + SOF_DAI_TOKENS, /* for DAI copier */ }; static enum sof_tokens pipeline_token_list[] = { @@ -3322,16 +3325,6 @@ static enum sof_tokens pipeline_token_list[] = { SOF_PIPELINE_TOKENS, }; -static enum sof_tokens dai_token_list[] = { - SOF_COMP_TOKENS, - SOF_AUDIO_FMT_NUM_TOKENS, - SOF_IN_AUDIO_FORMAT_TOKENS, - SOF_OUT_AUDIO_FORMAT_TOKENS, - SOF_COPIER_TOKENS, - SOF_DAI_TOKENS, - SOF_COMP_EXT_TOKENS, -}; - static enum sof_tokens pga_token_list[] = { SOF_COMP_TOKENS, SOF_GAIN_TOKENS, @@ -3368,23 +3361,23 @@ static enum sof_tokens process_token_list[] = { static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, - common_copier_token_list, ARRAY_SIZE(common_copier_token_list), + copier_token_list, ARRAY_SIZE(copier_token_list), NULL, sof_ipc4_prepare_copier_module, sof_ipc4_unprepare_copier_module}, [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, - common_copier_token_list, ARRAY_SIZE(common_copier_token_list), + copier_token_list, ARRAY_SIZE(copier_token_list), NULL, sof_ipc4_prepare_copier_module, sof_ipc4_unprepare_copier_module}, [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, - dai_token_list, ARRAY_SIZE(dai_token_list), NULL, + copier_token_list, ARRAY_SIZE(copier_token_list), NULL, sof_ipc4_prepare_copier_module, sof_ipc4_unprepare_copier_module}, [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, - dai_token_list, ARRAY_SIZE(dai_token_list), NULL, + copier_token_list, ARRAY_SIZE(copier_token_list), NULL, sof_ipc4_prepare_copier_module, sof_ipc4_unprepare_copier_module}, [snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, - common_copier_token_list, ARRAY_SIZE(common_copier_token_list), + copier_token_list, ARRAY_SIZE(copier_token_list), NULL, sof_ipc4_prepare_copier_module, sof_ipc4_unprepare_copier_module}, [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, From 1e0dff741b0a8af35645e5c3ffc4050893002a9c Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 3 Jul 2024 20:26:15 +0800 Subject: [PATCH 296/349] ASoC: ak4458: remove "reset-gpios" property handler commit c721f189e89c0 ("reset: Instantiate reset GPIO controller for shared reset-gpios") check if there is no "resets" property will fallback to "reset-gpios". So don't need to handle "reset-gpios" separately in the driver, the "reset-gpios" handler is duplicated with "resets" control handler, remove it. Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/1720009575-11677-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4458.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 32cb802ad635..d472d9952628 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -45,7 +45,6 @@ struct ak4458_priv { const struct ak4458_drvdata *drvdata; struct device *dev; struct regmap *regmap; - struct gpio_desc *reset_gpiod; struct reset_control *reset; struct gpio_desc *mute_gpiod; int digfil; /* SSLOW, SD, SLOW bits */ @@ -631,10 +630,7 @@ static struct snd_soc_dai_driver ak4497_dai = { static void ak4458_reset(struct ak4458_priv *ak4458, bool active) { - if (ak4458->reset_gpiod) { - gpiod_set_value_cansleep(ak4458->reset_gpiod, active); - usleep_range(1000, 2000); - } else if (!IS_ERR_OR_NULL(ak4458->reset)) { + if (!IS_ERR_OR_NULL(ak4458->reset)) { if (active) reset_control_assert(ak4458->reset); else @@ -758,11 +754,6 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) if (IS_ERR(ak4458->reset)) return PTR_ERR(ak4458->reset); - ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset", - GPIOD_OUT_LOW); - if (IS_ERR(ak4458->reset_gpiod)) - return PTR_ERR(ak4458->reset_gpiod); - ak4458->mute_gpiod = devm_gpiod_get_optional(ak4458->dev, "mute", GPIOD_OUT_LOW); if (IS_ERR(ak4458->mute_gpiod)) From 9f3ae72c5dbca9ba558c752f1ef969ed6908be01 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Jul 2024 14:26:16 +0200 Subject: [PATCH 297/349] ASoC: codecs: wcd939x: Fix typec mux and switch leak during device removal Driver does not unregister typec structures (typec_mux_dev and typec_switch_desc) during removal leading to leaks. Fix this by moving typec registering parts to separate function and using devm interface to release them. This also makes code a bit simpler: - Smaller probe() function with less error paths and no #ifdefs, - No need to store typec_mux_dev and typec_switch_desc in driver state container structure. Cc: stable@vger.kernel.org Fixes: 10f514bd172a ("ASoC: codecs: Add WCD939x Codec driver") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20240701122616.414158-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 113 ++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 47 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 66af035bd0e5..68fc591670dc 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -181,8 +181,6 @@ struct wcd939x_priv { /* typec handling */ bool typec_analog_mux; #if IS_ENABLED(CONFIG_TYPEC) - struct typec_mux_dev *typec_mux; - struct typec_switch_dev *typec_sw; enum typec_orientation typec_orientation; unsigned long typec_mode; struct typec_switch *typec_switch; @@ -3519,6 +3517,68 @@ static const struct component_master_ops wcd939x_comp_ops = { .unbind = wcd939x_unbind, }; +static void __maybe_unused wcd939x_typec_mux_unregister(void *data) +{ + struct typec_mux_dev *typec_mux = data; + + typec_mux_unregister(typec_mux); +} + +static void __maybe_unused wcd939x_typec_switch_unregister(void *data) +{ + struct typec_switch_dev *typec_sw = data; + + typec_switch_unregister(typec_sw); +} + +static int wcd939x_add_typec(struct wcd939x_priv *wcd939x, struct device *dev) +{ +#if IS_ENABLED(CONFIG_TYPEC) + int ret; + struct typec_mux_dev *typec_mux; + struct typec_switch_dev *typec_sw; + struct typec_mux_desc mux_desc = { + .drvdata = wcd939x, + .fwnode = dev_fwnode(dev), + .set = wcd939x_typec_mux_set, + }; + struct typec_switch_desc sw_desc = { + .drvdata = wcd939x, + .fwnode = dev_fwnode(dev), + .set = wcd939x_typec_switch_set, + }; + + /* + * Is USBSS is used to mux analog lines, + * register a typec mux/switch to get typec events + */ + if (!wcd939x->typec_analog_mux) + return 0; + + typec_mux = typec_mux_register(dev, &mux_desc); + if (IS_ERR(typec_mux)) + return dev_err_probe(dev, PTR_ERR(typec_mux), + "failed to register typec mux\n"); + + ret = devm_add_action_or_reset(dev, wcd939x_typec_mux_unregister, + typec_mux); + if (ret) + return ret; + + typec_sw = typec_switch_register(dev, &sw_desc); + if (IS_ERR(typec_sw)) + return dev_err_probe(dev, PTR_ERR(typec_sw), + "failed to register typec switch\n"); + + ret = devm_add_action_or_reset(dev, wcd939x_typec_switch_unregister, + typec_sw); + if (ret) + return ret; +#endif + + return 0; +} + static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x, struct device *dev, struct component_match **matchptr) @@ -3567,42 +3627,13 @@ static int wcd939x_probe(struct platform_device *pdev) return -EINVAL; } -#if IS_ENABLED(CONFIG_TYPEC) - /* - * Is USBSS is used to mux analog lines, - * register a typec mux/switch to get typec events - */ - if (wcd939x->typec_analog_mux) { - struct typec_mux_desc mux_desc = { - .drvdata = wcd939x, - .fwnode = dev_fwnode(dev), - .set = wcd939x_typec_mux_set, - }; - struct typec_switch_desc sw_desc = { - .drvdata = wcd939x, - .fwnode = dev_fwnode(dev), - .set = wcd939x_typec_switch_set, - }; - - wcd939x->typec_mux = typec_mux_register(dev, &mux_desc); - if (IS_ERR(wcd939x->typec_mux)) { - ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_mux), - "failed to register typec mux\n"); - goto err_disable_regulators; - } - - wcd939x->typec_sw = typec_switch_register(dev, &sw_desc); - if (IS_ERR(wcd939x->typec_sw)) { - ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_sw), - "failed to register typec switch\n"); - goto err_unregister_typec_mux; - } - } -#endif /* CONFIG_TYPEC */ + ret = wcd939x_add_typec(wcd939x, dev); + if (ret) + goto err_disable_regulators; ret = wcd939x_add_slave_components(wcd939x, dev, &match); if (ret) - goto err_unregister_typec_switch; + goto err_disable_regulators; wcd939x_reset(wcd939x); @@ -3619,18 +3650,6 @@ static int wcd939x_probe(struct platform_device *pdev) return 0; -#if IS_ENABLED(CONFIG_TYPEC) -err_unregister_typec_mux: - if (wcd939x->typec_analog_mux) - typec_mux_unregister(wcd939x->typec_mux); -#endif /* CONFIG_TYPEC */ - -err_unregister_typec_switch: -#if IS_ENABLED(CONFIG_TYPEC) - if (wcd939x->typec_analog_mux) - typec_switch_unregister(wcd939x->typec_sw); -#endif /* CONFIG_TYPEC */ - err_disable_regulators: regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); From 5080808c3339de2220c602ab7c7fa23dc6c1a5a3 Mon Sep 17 00:00:00 2001 From: Aleksandr Mishin Date: Wed, 3 Jul 2024 22:10:07 +0300 Subject: [PATCH 298/349] ASoC: amd: Adjust error handling in case of absent codec device acpi_get_first_physical_node() can return NULL in several cases (no such device, ACPI table error, reference count drop to 0, etc). Existing check just emit error message, but doesn't perform return. Then this NULL pointer is passed to devm_acpi_dev_add_driver_gpios() where it is dereferenced. Adjust this error handling by adding error code return. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 02527c3f2300 ("ASoC: amd: add Machine driver for Jadeite platform") Signed-off-by: Aleksandr Mishin Link: https://patch.msgid.link/20240703191007.8524-1-amishin@t-argos.ru Signed-off-by: Mark Brown --- sound/soc/amd/acp-es8336.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/acp-es8336.c b/sound/soc/amd/acp-es8336.c index e079b3218c6f..3756b8bef17b 100644 --- a/sound/soc/amd/acp-es8336.c +++ b/sound/soc/amd/acp-es8336.c @@ -203,8 +203,10 @@ static int st_es8336_late_probe(struct snd_soc_card *card) codec_dev = acpi_get_first_physical_node(adev); acpi_dev_put(adev); - if (!codec_dev) + if (!codec_dev) { dev_err(card->dev, "can not find codec dev\n"); + return -ENODEV; + } ret = devm_acpi_dev_add_driver_gpios(codec_dev, acpi_es8336_gpios); if (ret) From 5f9f982dd71b418aeba7a0b37f87312545c06df4 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Wed, 3 Jul 2024 15:07:28 +0100 Subject: [PATCH 299/349] ALSA: hda: cs35l41: Fix missing Speaker ID GPIO description in _DSD Laptop 10431A63 contains valid _DSD, but missing Speaker ID description. Add this discription, but keep the rest of the _DSD to ensure the correct firmware and tuning is loaded for this laptop. Signed-off-by: Stefan Binding Link: https://patch.msgid.link/20240703140802.27688-1-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 86 ++++++++++++++++------------ sound/pci/hda/cs35l41_hda.h | 1 + sound/pci/hda/cs35l41_hda_property.c | 15 +++++ 3 files changed, 65 insertions(+), 37 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index ee9f83b737de..4b411ed8c3fe 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -1753,38 +1753,14 @@ int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int return speaker_id; } -static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id) +int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id) { struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; u32 values[HDA_MAX_COMPONENTS]; - struct acpi_device *adev; - struct device *physdev; - struct spi_device *spi; - const char *sub; char *property; size_t nval; int i, ret; - adev = acpi_dev_get_first_match_dev(hid, NULL, -1); - if (!adev) { - dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid); - return -ENODEV; - } - - cs35l41->dacpi = adev; - physdev = get_device(acpi_get_first_physical_node(adev)); - - sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); - if (IS_ERR(sub)) - 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 out; - } - property = "cirrus,dev-index"; ret = device_property_count_u32(physdev, property); if (ret <= 0) @@ -1816,8 +1792,9 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i /* To use the same release code for all laptop variants we can't use devm_ version of * gpiod_get here, as CLSA010* don't have a fully functional bios with an _DSD node */ - cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(adev), "reset", cs35l41->index, - GPIOD_OUT_LOW, "cs35l41-reset"); + cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset", + cs35l41->index, GPIOD_OUT_LOW, + "cs35l41-reset"); property = "cirrus,speaker-position"; ret = device_property_read_u32_array(physdev, property, values, nval); @@ -1873,6 +1850,51 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i hw_cfg->bst_type = CS35L41_EXT_BOOST; hw_cfg->valid = true; + + return 0; +err: + dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret); + hw_cfg->valid = false; + hw_cfg->gpio1.valid = false; + hw_cfg->gpio2.valid = false; + acpi_dev_put(cs35l41->dacpi); + + return ret; +} + +static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id) +{ + struct acpi_device *adev; + struct device *physdev; + struct spi_device *spi; + const char *sub; + int ret; + + adev = acpi_dev_get_first_match_dev(hid, NULL, -1); + if (!adev) { + dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid); + return -ENODEV; + } + + cs35l41->dacpi = adev; + physdev = get_device(acpi_get_first_physical_node(adev)); + + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); + if (IS_ERR(sub)) + 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 out; + } + + ret = cs35l41_hda_parse_acpi(cs35l41, physdev, id); + if (ret) { + put_device(physdev); + return ret; + } out: put_device(physdev); @@ -1888,16 +1910,6 @@ out: } return 0; - -err: - dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret); - hw_cfg->valid = false; - hw_cfg->gpio1.valid = false; - hw_cfg->gpio2.valid = false; - acpi_dev_put(cs35l41->dacpi); - put_device(physdev); - - return ret; } int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq, diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h index b0bebb778462..c730b3351589 100644 --- a/sound/pci/hda/cs35l41_hda.h +++ b/sound/pci/hda/cs35l41_hda.h @@ -104,5 +104,6 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i struct regmap *regmap, enum control_bus control_bus); 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); +int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id); #endif /*__CS35L41_HDA_H__*/ diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index 51998d1c72ff..5860379a0412 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -428,6 +428,20 @@ static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *phy return 0; } +static int missing_speaker_id_gpio2(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid) +{ + int ret; + + ret = cs35l41_add_gpios(cs35l41, physdev, -1, 2, -1, 2); + if (ret) { + dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret); + return ret; + } + + return cs35l41_hda_parse_acpi(cs35l41, physdev, id); +} + struct cs35l41_prop_model { const char *hid; const char *ssid; @@ -501,6 +515,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CSC3551", "104317F3", generic_dsd_config }, { "CSC3551", "10431863", generic_dsd_config }, { "CSC3551", "104318D3", generic_dsd_config }, + { "CSC3551", "10431A63", missing_speaker_id_gpio2 }, { "CSC3551", "10431A83", generic_dsd_config }, { "CSC3551", "10431B93", generic_dsd_config }, { "CSC3551", "10431C9F", generic_dsd_config }, From cabf0b0cff07bc8d6e80ab6a8f8a127a2708147b Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Thu, 4 Jul 2024 17:49:37 +0800 Subject: [PATCH 300/349] ASoc: tas2781: Set "Speaker Force Firmware Load" as the common kcontrol for both tas27871 and tas2563 Set "Speaker Force Firmware Load" as the common kcontrol for both tas27871 and tas2563 and move it into newly-created tasdevice_snd_controls, and keep the digital gain and analog gain in tas2781_snd_controls. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20240704094939.1824-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2781-i2c.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index e0e630f66101..b412f8f2e5d5 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -104,7 +104,7 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, return tasdevice_amp_putvol(tas_priv, ucontrol, mc); } -static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, +static int tasdev_force_fwload_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = @@ -119,7 +119,7 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, return 0; } -static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, +static int tasdev_force_fwload_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = @@ -140,6 +140,11 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, return change; } +static const struct snd_kcontrol_new tasdevice_snd_controls[] = { + SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, + tasdev_force_fwload_get, tasdev_force_fwload_put), +}; + static const struct snd_kcontrol_new tas2781_snd_controls[] = { SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL, 1, 0, 20, 0, tas2781_amp_getvol, @@ -147,8 +152,6 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = { SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL, 0, 0, 200, 1, tas2781_digital_getvol, tas2781_digital_putvol, dvc_tlv), - SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, - tas2781_force_fwload_get, tas2781_force_fwload_put), }; static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, @@ -590,6 +593,18 @@ static struct snd_soc_dai_driver tasdevice_dai_driver[] = { static int tasdevice_codec_probe(struct snd_soc_component *codec) { struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + int rc; + + if (tas_priv->chip_id == TAS2781) { + rc = snd_soc_add_component_controls(codec, + tas2781_snd_controls, + ARRAY_SIZE(tas2781_snd_controls)); + if (rc < 0) { + dev_err(tas_priv->dev, "%s: Add control err rc = %d", + __func__, rc); + return rc; + } + } tas_priv->name_prefix = codec->name_prefix; return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready); @@ -617,8 +632,8 @@ static const struct snd_soc_component_driver soc_codec_driver_tasdevice = { .probe = tasdevice_codec_probe, .remove = tasdevice_codec_remove, - .controls = tas2781_snd_controls, - .num_controls = ARRAY_SIZE(tas2781_snd_controls), + .controls = tasdevice_snd_controls, + .num_controls = ARRAY_SIZE(tasdevice_snd_controls), .dapm_widgets = tasdevice_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(tasdevice_dapm_widgets), .dapm_routes = tasdevice_audio_map, @@ -759,7 +774,7 @@ MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match); static struct i2c_driver tasdevice_i2c_driver = { .driver = { - .name = "tas2781-codec", + .name = "tasdev-codec", .of_match_table = of_match_ptr(tasdevice_of_match), #ifdef CONFIG_ACPI .acpi_match_table = ACPI_PTR(tasdevice_acpi_match), From bc7540b794df29f6ec0b24996381d6e68779d02f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 5 Jul 2024 08:35:53 +0200 Subject: [PATCH 301/349] ALSA: pcm: Fix missing export of snd_pcm_set_sync_per-card() The recent change for the PCM sync API forgot to export a new API function that is currently used in emu10k1 driver. This patch adds the missing export. Fixes: d712c58c55d9 ("ALSA: pcm: optimize and clarify stream synchronization ID API") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202407051343.1Sz8AKFt-lkp@intel.com/ Reviewed-by: Jaroslav Kysela Link: https://patch.msgid.link/20240705063555.17220-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e48a84f8e977..66683656fb13 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -547,6 +547,7 @@ void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream, strncpy(params->sync + 4, id, len); memset(params->sync + 4 + len, 0, 12 - len); } +EXPORT_SYMBOL_GPL(snd_pcm_set_sync_per_card); /* * Standard ioctl routine From a892b700e63bcb3679ebed1a0c3160e7b9225138 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 5 Jul 2024 09:58:28 +0200 Subject: [PATCH 302/349] ALSA: pcm: Fix id copying in snd_pcm_set_sync_per_card() Avoid to use strncpy and do proper length limiting (12 bytes) to avoid out of array access. Fixes: d712c58c55d9 ("ALSA: pcm: optimize and clarify stream synchronization ID API") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202407050501.o5Z3bibi-lkp@intel.com/ Signed-off-by: Jaroslav Kysela Link: https://patch.msgid.link/20240705075828.19746-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 66683656fb13..6e7905749c4a 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -543,8 +543,8 @@ void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream, const unsigned char *id, unsigned int len) { *(__u32 *)params->sync = cpu_to_le32(substream->pcm->card->number); - len = max(12, len); - strncpy(params->sync + 4, id, len); + len = min(12, len); + memcpy(params->sync + 4, id, len); memset(params->sync + 4 + len, 0, 12 - len); } EXPORT_SYMBOL_GPL(snd_pcm_set_sync_per_card); From ccb367c5ab5814bb731eb517544a2ba6b7c3b689 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 5 Jul 2024 14:48:46 +0800 Subject: [PATCH 303/349] ASoc: pcm6240: Remove unnecessary name-prefix for all the controls Adding name-prefix for each audio controls is a redundant, because name-prefix will be automatically added behind the control name when creating a new control. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20240705064846.1723-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm6240.c | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index 5faf5e97a105..6641e7c1ddf4 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -58,12 +58,6 @@ static const char *const pcmdev_ctrl_name[] = { "%s i2c%d Dev%d Ch%d Fine Volume", }; -static const char *const pcmdev_ctrl_name_with_prefix[] = { - "%s Dev%d Ch%d Ana Volume", - "%s Dev%d Ch%d Digi Volume", - "%s Dev%d Ch%d Fine Volume", -}; - static const struct pcmdevice_mixer_control adc5120_analog_gain_ctl[] = { { .shift = 1, @@ -1366,10 +1360,7 @@ static int pcmdev_gain_ctrl_add(struct pcmdevice_priv *pcm_dev, name_id = pcmdev_gain_ctl_info[id][ctl_id].pcmdev_ctrl_name_id; - if (comp->name_prefix) - ctrl_name = pcmdev_ctrl_name_with_prefix[name_id]; - else - ctrl_name = pcmdev_ctrl_name[name_id]; + ctrl_name = pcmdev_ctrl_name[name_id]; for (chn = 1; chn <= nr_chn; chn++) { name = devm_kzalloc(pcm_dev->dev, @@ -1378,13 +1369,9 @@ static int pcmdev_gain_ctrl_add(struct pcmdevice_priv *pcm_dev, ret = -ENOMEM; goto out; } - if (comp->name_prefix) - scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, - ctrl_name, comp->name_prefix, dev_no, chn); - else - scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, - ctrl_name, pcm_dev->upper_dev_name, adap->nr, - dev_no, chn); + scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, + ctrl_name, pcm_dev->upper_dev_name, adap->nr, + dev_no, chn); pcmdev_controls[mix_index].tlv.p = pcmdev_gain_ctl_info[id][ctl_id].gain; pcmdev_ctrl = devm_kmemdup(pcm_dev->dev, @@ -1438,13 +1425,8 @@ static int pcmdev_profile_ctrl_add(struct pcmdevice_priv *pcm_dev) if (!name) return -ENOMEM; - if (comp->name_prefix) - scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, - "%s Profile id", comp->name_prefix); - else - scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, - "%s i2c%d Profile id", pcm_dev->upper_dev_name, - adap->nr); + scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, + "%s i2c%d Profile id", pcm_dev->upper_dev_name, adap->nr); pcmdev_ctrl->name = name; pcmdev_ctrl->iface = SNDRV_CTL_ELEM_IFACE_MIXER; pcmdev_ctrl->info = pcmdevice_info_profile; From fefbbdfb59d3a20fd98734363e6dd9fa7cc65c70 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 5 Jul 2024 18:03:42 +0200 Subject: [PATCH 304/349] ALSA: seq: Add tempo base unit for MIDI2 Set Tempo messages MIDI2 Set Tempo message defines the tempo in 10ns unit for finer accuracy, while MIDI1 was defined in 1us unit. For adapting this different unit, introduce "tempo_base" field to snd_seq_queue_tempo struct so that user-space can pass the proper tempo base unit. The accepted value is limited, it must be either 0, 10 or 1000. The protocol version is bumped to 1.0.4 along with this. The access with the older protocol version ignores the tempo-base value in ioctls and always treats as 1000. Reviewed-by: Jaroslav Kysela Link: https://patch.msgid.link/20240705160344.6481-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 7 ++++--- sound/core/seq/seq_clientmgr.c | 4 ++++ sound/core/seq/seq_queue.c | 6 ++++-- sound/core/seq/seq_timer.c | 21 +++++++++++++++------ sound/core/seq/seq_timer.h | 4 +++- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index c85fdd8895d8..39b37edcf813 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -10,7 +10,7 @@ #include /** version of the sequencer */ -#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 3) +#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 4) /** * definition of sequencer event types @@ -523,11 +523,12 @@ struct snd_seq_queue_status { /* queue tempo */ struct snd_seq_queue_tempo { int queue; /* sequencer queue */ - unsigned int tempo; /* current tempo, us/tick */ + unsigned int tempo; /* current tempo, us/tick (or different time-base below) */ int ppq; /* time resolution, ticks/quarter */ unsigned int skew_value; /* queue skew */ unsigned int skew_base; /* queue skew base */ - char reserved[24]; /* for the future */ + unsigned short tempo_base; /* tempo base in nsec unit; either 10 or 1000 */ + char reserved[22]; /* for the future */ }; diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 42a705141050..8c4ee5066afe 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1718,6 +1718,8 @@ static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client, tempo->ppq = tmr->ppq; tempo->skew_value = tmr->skew; tempo->skew_base = tmr->skew_base; + if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 4)) + tempo->tempo_base = tmr->tempo_base; queuefree(queue); return 0; @@ -1739,6 +1741,8 @@ static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client, struct snd_seq_queue_tempo *tempo = arg; int result; + if (client->user_pversion < SNDRV_PROTOCOL_VERSION(1, 0, 4)) + tempo->tempo_base = 0; result = snd_seq_set_queue_tempo(client->number, tempo); return result < 0 ? result : 0; } diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 500ee6b19c71..5df26788dda4 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -460,7 +460,8 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client, return -EPERM; } - result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq); + result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq, + info->tempo_base); if (result >= 0 && info->skew_base > 0) result = snd_seq_timer_set_skew(q->timer, info->skew_value, info->skew_base); @@ -724,7 +725,7 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, tmr = q->timer; if (tmr->tempo) - bpm = 60000000 / tmr->tempo; + bpm = (60000 * tmr->tempo_base) / tmr->tempo; else bpm = 0; @@ -741,6 +742,7 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, snd_iprintf(buffer, "timer state : %s\n", tmr->running ? "Running" : "Stopped"); snd_iprintf(buffer, "timer PPQ : %d\n", tmr->ppq); snd_iprintf(buffer, "current tempo : %d\n", tmr->tempo); + snd_iprintf(buffer, "tempo base : %d ns\n", tmr->tempo_base); snd_iprintf(buffer, "current BPM : %d\n", bpm); snd_iprintf(buffer, "current time : %d.%09d s\n", tmr->cur_time.tv_sec, tmr->cur_time.tv_nsec); snd_iprintf(buffer, "current tick : %d\n", tmr->tick.cur_tick); diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index ad2b97e2762d..c9f0392ac7f1 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -20,14 +20,17 @@ static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr) { - if (tmr->tempo < 1000000) - tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq; + unsigned int threshold = + tmr->tempo_base == 1000 ? 1000000 : 10000; + + if (tmr->tempo < threshold) + tmr->tick.resolution = (tmr->tempo * tmr->tempo_base) / tmr->ppq; else { /* might overflow.. */ unsigned int s; s = tmr->tempo % tmr->ppq; - s = (s * 1000) / tmr->ppq; - tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000; + s = (s * tmr->tempo_base) / tmr->ppq; + tmr->tick.resolution = (tmr->tempo / tmr->ppq) * tmr->tempo_base; tmr->tick.resolution += s; } if (tmr->tick.resolution <= 0) @@ -79,6 +82,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) /* setup defaults */ tmr->ppq = 96; /* 96 PPQ */ tmr->tempo = 500000; /* 120 BPM */ + tmr->tempo_base = 1000; /* 1us */ snd_seq_timer_set_tick_resolution(tmr); tmr->running = 0; @@ -164,8 +168,9 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) return 0; } -/* set current tempo and ppq in a shot */ -int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) +/* set current tempo, ppq and base in a shot */ +int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq, + unsigned int tempo_base) { int changed; @@ -173,6 +178,9 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) return -EINVAL; if (tempo <= 0 || ppq <= 0) return -EINVAL; + /* allow only 10ns or 1us tempo base for now */ + if (tempo_base && tempo_base != 10 && tempo_base != 1000) + return -EINVAL; guard(spinlock_irqsave)(&tmr->lock); if (tmr->running && (ppq != tmr->ppq)) { /* refuse to change ppq on running timers */ @@ -183,6 +191,7 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) changed = (tempo != tmr->tempo) || (ppq != tmr->ppq); tmr->tempo = tempo; tmr->ppq = ppq; + tmr->tempo_base = tempo_base ? tempo_base : 1000; if (changed) snd_seq_timer_set_tick_resolution(tmr); return 0; diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index 4bec57df8158..3b906064bde1 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h @@ -36,6 +36,7 @@ struct snd_seq_timer { unsigned int skew; unsigned int skew_base; + unsigned int tempo_base; struct timespec64 last_update; /* time of last clock update, used for interpolation */ @@ -116,7 +117,8 @@ int snd_seq_timer_stop(struct snd_seq_timer *tmr); int snd_seq_timer_start(struct snd_seq_timer *tmr); int snd_seq_timer_continue(struct snd_seq_timer *tmr); int snd_seq_timer_set_tempo(struct snd_seq_timer *tmr, int tempo); -int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq); +int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq, + unsigned int tempo_base); int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position); int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position); int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base); From 408e49381750ca22fc584a37636f5035d2cd4c25 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:10:55 +0200 Subject: [PATCH 305/349] ASoC: codecs: audio-iio-aux: Simplify audio_iio_aux_add_dapms() with cleanup.h Allocate the memory with scoped/cleanup.h in audio_iio_aux_add_dapms() to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-1-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/audio-iio-aux.c | 36 ++++++++++---------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c index 1e8e1effc2af..3969ee45f41e 100644 --- a/sound/soc/codecs/audio-iio-aux.c +++ b/sound/soc/codecs/audio-iio-aux.c @@ -6,6 +6,7 @@ // // Author: Herve Codina +#include #include #include #include @@ -131,33 +132,27 @@ 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); + /* Allocated names are not needed afterwards (duplicated in ASoC internals) */ + char *input_name __free(kfree) = 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; - } + char *output_name __free(kfree) = kasprintf(GFP_KERNEL, "%s OUT", chan->name); + if (!output_name) + return -ENOMEM; - pga_name = kasprintf(GFP_KERNEL, "%s PGA", chan->name); - if (!pga_name) { - ret = -ENOMEM; - goto out_free_output_name; - } + char *pga_name __free(kfree) = kasprintf(GFP_KERNEL, "%s PGA", chan->name); + if (!pga_name) + return -ENOMEM; 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; + return ret; routes[0].sink = pga_name; routes[0].control = NULL; @@ -165,17 +160,8 @@ static int audio_iio_aux_add_dapms(struct snd_soc_component *component, 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; + return snd_soc_dapm_add_routes(dapm, routes, 2); } static int audio_iio_aux_component_probe(struct snd_soc_component *component) From f9cbfb66127bfc2a47dece3dfcdab2b79ab06c50 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:10:56 +0200 Subject: [PATCH 306/349] ASoC: codecs: audio-iio-aux: Simplify audio_iio_aux_probe() with cleanup.h Allocate the memory with scoped/cleanup.h in audio_iio_aux_probe() to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-2-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/audio-iio-aux.c | 47 ++++++++++++-------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c index 3969ee45f41e..588e48044c13 100644 --- a/sound/soc/codecs/audio-iio-aux.c +++ b/sound/soc/codecs/audio-iio-aux.c @@ -230,8 +230,6 @@ 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; @@ -248,22 +246,22 @@ static int audio_iio_aux_probe(struct platform_device *pdev) iio_aux->num_chans = count; - names = kcalloc(iio_aux->num_chans, sizeof(*names), GFP_KERNEL); + const char **names __free(kfree) = 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; - } + u32 *invert_ranges __free(kfree) = kcalloc(iio_aux->num_chans, + sizeof(*invert_ranges), + GFP_KERNEL); + if (!invert_ranges) + return -ENOMEM; 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; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read io-channel-names\n"); /* * snd-control-invert-range is optional and can contain fewer items @@ -274,10 +272,8 @@ static int audio_iio_aux_probe(struct platform_device *pdev) 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; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read snd-control-invert-range\n"); } for (i = 0; i < iio_aux->num_chans; i++) { @@ -286,23 +282,16 @@ static int audio_iio_aux_probe(struct platform_device *pdev) 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; - } + if (IS_ERR(iio_aux_chan->iio_chan)) + return dev_err_probe(dev, PTR_ERR(iio_aux_chan->iio_chan), + "get IIO channel '%s' failed\n", + iio_aux_chan->name); } 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; + return devm_snd_soc_register_component(dev, &audio_iio_aux_component_driver, + NULL, 0); } static const struct of_device_id audio_iio_aux_ids[] = { From 6344ab5d0826640799e0c054ed4c0846b3f87ccb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:10:57 +0200 Subject: [PATCH 307/349] ASoC: codecs: wcd9335: Simplify with cleanup.h Allocate the memory with scoped/cleanup.h to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-3-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 1a20131e2a60..373a31ddccb2 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -2714,25 +2715,23 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w, struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); unsigned int decimator; char *dec_adc_mux_name = NULL; - char *widget_name = NULL; - char *wname; + char *widget_name; int ret = 0, amic_n; u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg; u16 tx_gain_ctl_reg; char *dec; u8 hpf_coff_freq; - widget_name = kmemdup_nul(w->name, 15, GFP_KERNEL); - if (!widget_name) + char *wname __free(kfree) = kmemdup_nul(w->name, 15, GFP_KERNEL); + if (!wname) return -ENOMEM; - wname = widget_name; + widget_name = wname; dec_adc_mux_name = strsep(&widget_name, " "); if (!dec_adc_mux_name) { dev_err(comp->dev, "%s: Invalid decimator = %s\n", __func__, w->name); - ret = -EINVAL; - goto out; + return -EINVAL; } dec_adc_mux_name = widget_name; @@ -2740,16 +2739,14 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w, if (!dec) { dev_err(comp->dev, "%s: decimator index not found\n", __func__); - ret = -EINVAL; - goto out; + return -EINVAL; } ret = kstrtouint(dec, 10, &decimator); if (ret < 0) { dev_err(comp->dev, "%s: Invalid decimator = %s\n", __func__, wname); - ret = -EINVAL; - goto out; + return -EINVAL; } tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + 16 * decimator; @@ -2836,8 +2833,7 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w, snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00); break; } -out: - kfree(wname); + return ret; } From 56d426f5525d1ad919e20663ad01a58238652df7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:10:58 +0200 Subject: [PATCH 308/349] ASoC: codecs: wcd934x: Simplify with cleanup.h Allocate the memory with scoped/cleanup.h to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-4-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 6c65b46e2dc9..291d0c80a6fc 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019, Linaro Limited +#include #include #include #include @@ -4973,25 +4974,23 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w, struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); unsigned int decimator; char *dec_adc_mux_name = NULL; - char *widget_name = NULL; - char *wname; + char *widget_name; int ret = 0, amic_n; u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg; u16 tx_gain_ctl_reg; char *dec; u8 hpf_coff_freq; - widget_name = kstrndup(w->name, 15, GFP_KERNEL); - if (!widget_name) + char *wname __free(kfree) = kstrndup(w->name, 15, GFP_KERNEL); + if (!wname) return -ENOMEM; - wname = widget_name; + widget_name = wname; dec_adc_mux_name = strsep(&widget_name, " "); if (!dec_adc_mux_name) { dev_err(comp->dev, "%s: Invalid decimator = %s\n", __func__, w->name); - ret = -EINVAL; - goto out; + return -EINVAL; } dec_adc_mux_name = widget_name; @@ -4999,16 +4998,14 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w, if (!dec) { dev_err(comp->dev, "%s: decimator index not found\n", __func__); - ret = -EINVAL; - goto out; + return -EINVAL; } ret = kstrtouint(dec, 10, &decimator); if (ret < 0) { dev_err(comp->dev, "%s: Invalid decimator = %s\n", __func__, wname); - ret = -EINVAL; - goto out; + return -EINVAL; } tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL + 16 * decimator; @@ -5101,8 +5098,7 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w, WCD934X_DEC_PWR_LVL_DF); break; } -out: - kfree(wname); + return ret; } From 6440e7b2a058c50a05ebcc58f35693c50522fc1a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:10:59 +0200 Subject: [PATCH 309/349] ASoC: simple-card-utils: Simplify with cleanup.h Allocate the memory with scoped/cleanup.h to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Acked-by: Kuninori Morimoto Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-5-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index a18de86b3c88..fedae7f6f70c 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -5,6 +5,7 @@ // Copyright (c) 2016 Kuninori Morimoto #include +#include #include #include #include @@ -135,8 +136,8 @@ EXPORT_SYMBOL_GPL(simple_util_parse_daifmt); int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np, struct simple_util_dai *dai) { - u32 *array_values, *p; int n, i, ret; + u32 *p; if (!of_property_read_bool(np, "dai-tdm-slot-width-map")) return 0; @@ -151,14 +152,15 @@ int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np, if (!dai->tdm_width_map) return -ENOMEM; - array_values = kcalloc(n, sizeof(*array_values), GFP_KERNEL); + u32 *array_values __free(kfree) = kcalloc(n, sizeof(*array_values), + GFP_KERNEL); if (!array_values) return -ENOMEM; ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n); if (ret < 0) { dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret); - goto out; + return ret; } p = array_values; @@ -169,11 +171,8 @@ int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np, } dai->n_tdm_widths = i; - ret = 0; -out: - kfree(array_values); - return ret; + return 0; } EXPORT_SYMBOL_GPL(simple_util_parse_tdm_width_map); From 5725c16af2678d334de0bcb85b42cfa50b32e04c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:11:00 +0200 Subject: [PATCH 310/349] ASoC: audio-graph-card: Use cleanup.h instead of devm_kfree() Allocate the memory with scoped/cleanup.h, instead of devm interface, to make the code more obvious that memory is not used outside this scope. Signed-off-by: Krzysztof Kozlowski Acked-by: Kuninori Morimoto Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-6-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index acf7d92d21e6..3425fbbcbd7e 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -7,6 +7,7 @@ // // based on ${LINUX}/sound/soc/generic/simple-card.c +#include #include #include #include @@ -573,10 +574,9 @@ static int graph_get_dais_count(struct simple_util_priv *priv, int audio_graph_parse_of(struct simple_util_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); + struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL); if (!li) return -ENOMEM; @@ -628,7 +628,6 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) if (ret < 0) goto err; - devm_kfree(dev, li); return 0; err: From b39f7713ece62b2b0a3cfad7a75a0eb0ab71aa4e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:11:01 +0200 Subject: [PATCH 311/349] ASoC: audio-graph-card2: Use cleanup.h instead of devm_kfree() Allocate the memory with scoped/cleanup.h, instead of devm interface, to make the code more obvious that memory is not used outside this scope. Signed-off-by: Krzysztof Kozlowski Acked-by: Kuninori Morimoto Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-7-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 93d9d045587b..56f7f946882e 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -1350,10 +1350,9 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, struct graph2_custom_hooks *hooks) { struct snd_soc_card *card = simple_priv_to_card(priv); - struct link_info *li; int ret; - li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); + struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL); if (!li) return -ENOMEM; @@ -1417,8 +1416,6 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, ret = devm_snd_soc_register_card(dev, card); err: - devm_kfree(dev, li); - if (ret < 0) dev_err_probe(dev, ret, "parse error\n"); From 7d996c8a5fea700e816379e57f4983e2611519a0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:11:02 +0200 Subject: [PATCH 312/349] ASoC: simple-card: Use cleanup.h instead of devm_kfree() Allocate the memory with scoped/cleanup.h, instead of devm interface, to make the code more obvious that memory is not used outside this scope. Signed-off-by: Krzysztof Kozlowski Acked-by: Kuninori Morimoto Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-8-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index edbb6322e9be..d2588f1ea54e 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -5,6 +5,7 @@ // Copyright (C) 2012 Renesas Solutions Corp. // Kuninori Morimoto +#include #include #include #include @@ -727,7 +728,6 @@ static int simple_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct snd_soc_card *card; - struct link_info *li; int ret; /* Allocate the private data and the DAI link array */ @@ -741,7 +741,7 @@ static int simple_probe(struct platform_device *pdev) card->probe = simple_soc_probe; card->driver_name = "simple-card"; - li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); + struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL); if (!li) return -ENOMEM; @@ -818,7 +818,6 @@ static int simple_probe(struct platform_device *pdev) if (ret < 0) goto err; - devm_kfree(dev, li); return 0; err: simple_util_clean_reference(card); From 1a7b846818210cbdf8994bfee1340c09342a5b3b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:11:03 +0200 Subject: [PATCH 313/349] ASoC: ops: Simplify with cleanup.h Allocate the memory with scoped/cleanup.h to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-9-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/soc-ops.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index b27e89ff6a16..19928f098d8d 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -11,6 +11,7 @@ // with code, comments and ideas from :- // Richard Purdie +#include #include #include #include @@ -727,14 +728,14 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, struct soc_bytes *params = (void *)kcontrol->private_value; int ret, len; unsigned int val, mask; - void *data; if (!component->regmap || !params->num_regs) return -EINVAL; len = params->num_regs * component->val_bytes; - data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); + void *data __free(kfree) = kmemdup(ucontrol->value.bytes.data, len, + GFP_KERNEL | GFP_DMA); if (!data) return -ENOMEM; @@ -746,7 +747,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, if (params->mask) { ret = regmap_read(component->regmap, params->base, &val); if (ret != 0) - goto out; + return ret; val &= params->mask; @@ -760,14 +761,14 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, ret = regmap_parse_val(component->regmap, &mask, &mask); if (ret != 0) - goto out; + return ret; ((u16 *)data)[0] &= mask; ret = regmap_parse_val(component->regmap, &val, &val); if (ret != 0) - goto out; + return ret; ((u16 *)data)[0] |= val; break; @@ -776,30 +777,23 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, ret = regmap_parse_val(component->regmap, &mask, &mask); if (ret != 0) - goto out; + return ret; ((u32 *)data)[0] &= mask; ret = regmap_parse_val(component->regmap, &val, &val); if (ret != 0) - goto out; + return ret; ((u32 *)data)[0] |= val; break; default: - ret = -EINVAL; - goto out; + return -EINVAL; } } - ret = regmap_raw_write(component->regmap, params->base, - data, len); - -out: - kfree(data); - - return ret; + return regmap_raw_write(component->regmap, params->base, data, len); } EXPORT_SYMBOL_GPL(snd_soc_bytes_put); From 5b3cc85673bcc7bb961a3a6fa229cbc4fe0441ac Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:11:04 +0200 Subject: [PATCH 314/349] ASoC: dapm: Simplify dapm_cnew_widget() with cleanup.h Allocate the memory with scoped/cleanup.h in dapm_cnew_widget() to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-10-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 32cc90d09bc2..4b322bb634b6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -323,9 +324,9 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( const struct snd_soc_dapm_widget *_widget, const char *prefix) { - struct snd_soc_dapm_widget *w; - - w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + struct snd_soc_dapm_widget *w __free(kfree) = kmemdup(_widget, + sizeof(*_widget), + GFP_KERNEL); if (!w) return NULL; @@ -333,20 +334,18 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, _widget->name); else w->name = kstrdup_const(_widget->name, GFP_KERNEL); - if (!w->name) { - kfree(w); + if (!w->name) return NULL; - } if (_widget->sname) { w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); if (!w->sname) { kfree_const(w->name); - kfree(w); return NULL; } } - return w; + + return_ptr(w); } struct dapm_kcontrol_data { From 522133d4401010d936b0588a5a975c2c965cb88e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 14:11:05 +0200 Subject: [PATCH 315/349] ASoC: dapm: Simplify snd_soc_dai_link_event_pre_pmu() with cleanup.h Allocate the memory with scoped/cleanup.h in snd_soc_dai_link_event_pre_pmu() to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240703-asoc-cleanup-h-v1-11-71219dfd0aef@linaro.org Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 4b322bb634b6..37dccd9c1ba0 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3882,11 +3882,10 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_path *path; struct snd_soc_dai *source, *sink; struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_pcm_hw_params *params = NULL; const struct snd_soc_pcm_stream *config = NULL; struct snd_pcm_runtime *runtime = NULL; unsigned int fmt; - int ret = 0; + int ret; /* * NOTE @@ -3897,15 +3896,14 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, * stuff that increases stack usage. * So, we use kzalloc()/kfree() for params in this function. */ - params = kzalloc(sizeof(*params), GFP_KERNEL); + struct snd_pcm_hw_params *params __free(kfree) = kzalloc(sizeof(*params), + GFP_KERNEL); if (!params) return -ENOMEM; runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); - if (!runtime) { - ret = -ENOMEM; - goto out; - } + if (!runtime) + return -ENOMEM; substream->runtime = runtime; @@ -3915,7 +3913,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, ret = snd_soc_dai_startup(source, substream); if (ret < 0) - goto out; + return ret; snd_soc_dai_activate(source, substream->stream); } @@ -3926,7 +3924,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, ret = snd_soc_dai_startup(sink, substream); if (ret < 0) - goto out; + return ret; snd_soc_dai_activate(sink, substream->stream); } @@ -3941,16 +3939,14 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, config = rtd->dai_link->c2c_params + rtd->c2c_params_select; if (!config) { dev_err(w->dapm->dev, "ASoC: link config missing\n"); - ret = -EINVAL; - goto out; + return -EINVAL; } /* Be a little careful as we don't want to overflow the mask array */ if (!config->formats) { dev_warn(w->dapm->dev, "ASoC: Invalid format was specified\n"); - ret = -EINVAL; - goto out; + return -EINVAL; } fmt = ffs(config->formats) - 1; @@ -3971,7 +3967,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, ret = snd_soc_dai_hw_params(source, substream, params); if (ret < 0) - goto out; + return ret; dapm_update_dai_unlocked(substream, params, source); } @@ -3982,7 +3978,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, ret = snd_soc_dai_hw_params(sink, substream, params); if (ret < 0) - goto out; + return ret; dapm_update_dai_unlocked(substream, params, sink); } @@ -3992,11 +3988,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, runtime->channels = params_channels(params); runtime->rate = params_rate(params); -out: - /* see above NOTE */ - kfree(params); - - return ret; + return 0; } static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, From 1cc509edbe23b61e8c245611bd15d88edb635a38 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Sun, 7 Jul 2024 16:30:07 +0800 Subject: [PATCH 316/349] ASoc: TAS2781: replace beXX_to_cpup with get_unaligned_beXX for potentially broken alignment Use get_unaligned_be16 instead of be16_to_cpup and get_unaligned_be32 instead of be32_to_cpup for potentially broken alignment. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20240707083011.98-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2781-fmwlib.c | 71 +++++++++++++++---------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index 838d29fead96..63626b982d04 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -21,7 +21,7 @@ #include #include #include - +#include #define ERROR_PRAM_CRCCHK 0x0000000 #define ERROR_YRAM_CRCCHK 0x0000001 @@ -187,8 +187,7 @@ static struct tasdevice_config_info *tasdevice_add_config( /* convert data[offset], data[offset + 1], data[offset + 2] and * data[offset + 3] into host */ - cfg_info->nblocks = - be32_to_cpup((__be32 *)&config_data[config_offset]); + cfg_info->nblocks = get_unaligned_be32(&config_data[config_offset]); config_offset += 4; /* Several kinds of dsp/algorithm firmwares can run on tas2781, @@ -232,14 +231,14 @@ static struct tasdevice_config_info *tasdevice_add_config( } bk_da[i]->yram_checksum = - be16_to_cpup((__be16 *)&config_data[config_offset]); + get_unaligned_be16(&config_data[config_offset]); config_offset += 2; bk_da[i]->block_size = - be32_to_cpup((__be32 *)&config_data[config_offset]); + get_unaligned_be32(&config_data[config_offset]); config_offset += 4; bk_da[i]->n_subblks = - be32_to_cpup((__be32 *)&config_data[config_offset]); + get_unaligned_be32(&config_data[config_offset]); config_offset += 4; @@ -289,7 +288,7 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw) } buf = (unsigned char *)fmw->data; - fw_hdr->img_sz = be32_to_cpup((__be32 *)&buf[offset]); + fw_hdr->img_sz = get_unaligned_be32(&buf[offset]); offset += 4; if (fw_hdr->img_sz != fmw->size) { dev_err(tas_priv->dev, @@ -300,9 +299,9 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw) goto out; } - fw_hdr->checksum = be32_to_cpup((__be32 *)&buf[offset]); + fw_hdr->checksum = get_unaligned_be32(&buf[offset]); offset += 4; - fw_hdr->binary_version_num = be32_to_cpup((__be32 *)&buf[offset]); + fw_hdr->binary_version_num = get_unaligned_be32(&buf[offset]); if (fw_hdr->binary_version_num < 0x103) { dev_err(tas_priv->dev, "File version 0x%04x is too low", fw_hdr->binary_version_num); @@ -311,7 +310,7 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw) goto out; } offset += 4; - fw_hdr->drv_fw_version = be32_to_cpup((__be32 *)&buf[offset]); + fw_hdr->drv_fw_version = get_unaligned_be32(&buf[offset]); offset += 8; fw_hdr->plat_type = buf[offset]; offset += 1; @@ -339,11 +338,11 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw) for (i = 0; i < TASDEVICE_DEVICE_SUM; i++, offset++) fw_hdr->devs[i] = buf[offset]; - fw_hdr->nconfig = be32_to_cpup((__be32 *)&buf[offset]); + fw_hdr->nconfig = get_unaligned_be32(&buf[offset]); offset += 4; for (i = 0; i < TASDEVICE_CONFIG_SUM; i++) { - fw_hdr->config_size[i] = be32_to_cpup((__be32 *)&buf[offset]); + fw_hdr->config_size[i] = get_unaligned_be32(&buf[offset]); offset += 4; total_config_sz += fw_hdr->config_size[i]; } @@ -423,7 +422,7 @@ static int fw_parse_block_data_kernel(struct tasdevice_fw *tas_fmw, /* convert data[offset], data[offset + 1], data[offset + 2] and * data[offset + 3] into host */ - block->type = be32_to_cpup((__be32 *)&data[offset]); + block->type = get_unaligned_be32(&data[offset]); offset += 4; block->is_pchksum_present = data[offset]; @@ -438,10 +437,10 @@ static int fw_parse_block_data_kernel(struct tasdevice_fw *tas_fmw, block->ychksum = data[offset]; offset++; - block->blk_size = be32_to_cpup((__be32 *)&data[offset]); + block->blk_size = get_unaligned_be32(&data[offset]); offset += 4; - block->nr_subblocks = be32_to_cpup((__be32 *)&data[offset]); + block->nr_subblocks = get_unaligned_be32(&data[offset]); offset += 4; /* fixed m68k compiling issue: @@ -482,7 +481,7 @@ static int fw_parse_data_kernel(struct tasdevice_fw *tas_fmw, offset = -EINVAL; goto out; } - img_data->nr_blk = be32_to_cpup((__be32 *)&data[offset]); + img_data->nr_blk = get_unaligned_be32(&data[offset]); offset += 4; img_data->dev_blks = kcalloc(img_data->nr_blk, @@ -578,14 +577,14 @@ static int fw_parse_variable_header_kernel( offset = -EINVAL; goto out; } - fw_hdr->device_family = be16_to_cpup((__be16 *)&buf[offset]); + fw_hdr->device_family = get_unaligned_be16(&buf[offset]); if (fw_hdr->device_family != 0) { dev_err(tas_priv->dev, "%s:not TAS device\n", __func__); offset = -EINVAL; goto out; } offset += 2; - fw_hdr->device = be16_to_cpup((__be16 *)&buf[offset]); + fw_hdr->device = get_unaligned_be16(&buf[offset]); if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE || fw_hdr->device == 6) { dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device); @@ -603,7 +602,7 @@ static int fw_parse_variable_header_kernel( goto out; } - tas_fmw->nr_programs = be32_to_cpup((__be32 *)&buf[offset]); + tas_fmw->nr_programs = get_unaligned_be32(&buf[offset]); offset += 4; if (tas_fmw->nr_programs == 0 || tas_fmw->nr_programs > @@ -622,14 +621,14 @@ static int fw_parse_variable_header_kernel( for (i = 0; i < tas_fmw->nr_programs; i++) { program = &(tas_fmw->programs[i]); - program->prog_size = be32_to_cpup((__be32 *)&buf[offset]); + program->prog_size = get_unaligned_be32(&buf[offset]); offset += 4; } /* Skip the unused prog_size */ offset += 4 * (TASDEVICE_MAXPROGRAM_NUM_KERNEL - tas_fmw->nr_programs); - tas_fmw->nr_configurations = be32_to_cpup((__be32 *)&buf[offset]); + tas_fmw->nr_configurations = get_unaligned_be32(&buf[offset]); offset += 4; /* The max number of config in firmware greater than 4 pieces of @@ -661,7 +660,7 @@ static int fw_parse_variable_header_kernel( for (i = 0; i < tas_fmw->nr_programs; i++) { config = &(tas_fmw->configs[i]); - config->cfg_size = be32_to_cpup((__be32 *)&buf[offset]); + config->cfg_size = get_unaligned_be32(&buf[offset]); offset += 4; } @@ -699,7 +698,7 @@ static int tasdevice_process_block(void *context, unsigned char *data, switch (subblk_typ) { case TASDEVICE_CMD_SING_W: { int i; - unsigned short len = be16_to_cpup((__be16 *)&data[2]); + unsigned short len = get_unaligned_be16(&data[2]); subblk_offset += 2; if (subblk_offset + 4 * len > sublocksize) { @@ -725,7 +724,7 @@ static int tasdevice_process_block(void *context, unsigned char *data, } break; case TASDEVICE_CMD_BURST: { - unsigned short len = be16_to_cpup((__be16 *)&data[2]); + unsigned short len = get_unaligned_be16(&data[2]); subblk_offset += 2; if (subblk_offset + 4 + len > sublocksize) { @@ -766,7 +765,7 @@ static int tasdevice_process_block(void *context, unsigned char *data, is_err = true; break; } - sleep_time = be16_to_cpup((__be16 *)&data[2]) * 1000; + sleep_time = get_unaligned_be16(&data[2]) * 1000; usleep_range(sleep_time, sleep_time + 50); subblk_offset += 2; } @@ -910,7 +909,7 @@ static int fw_parse_variable_hdr(struct tasdevice_priv offset += len; - fw_hdr->device_family = be32_to_cpup((__be32 *)&buf[offset]); + fw_hdr->device_family = get_unaligned_be32(&buf[offset]); if (fw_hdr->device_family != 0) { dev_err(tas_priv->dev, "%s: not TAS device\n", __func__); offset = -EINVAL; @@ -918,7 +917,7 @@ static int fw_parse_variable_hdr(struct tasdevice_priv } offset += 4; - fw_hdr->device = be32_to_cpup((__be32 *)&buf[offset]); + fw_hdr->device = get_unaligned_be32(&buf[offset]); if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE || fw_hdr->device == 6) { dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device); @@ -963,7 +962,7 @@ static int fw_parse_block_data(struct tasdevice_fw *tas_fmw, offset = -EINVAL; goto out; } - block->type = be32_to_cpup((__be32 *)&data[offset]); + block->type = get_unaligned_be32(&data[offset]); offset += 4; if (tas_fmw->fw_hdr.fixed_hdr.drv_ver >= PPC_DRIVER_CRCCHK) { @@ -988,7 +987,7 @@ static int fw_parse_block_data(struct tasdevice_fw *tas_fmw, block->is_ychksum_present = 0; } - block->nr_cmds = be32_to_cpup((__be32 *)&data[offset]); + block->nr_cmds = get_unaligned_be32(&data[offset]); offset += 4; n = block->nr_cmds * 4; @@ -1039,7 +1038,7 @@ static int fw_parse_data(struct tasdevice_fw *tas_fmw, goto out; } offset += n; - img_data->nr_blk = be16_to_cpup((__be16 *)&data[offset]); + img_data->nr_blk = get_unaligned_be16(&data[offset]); offset += 2; img_data->dev_blks = kcalloc(img_data->nr_blk, @@ -1076,7 +1075,7 @@ static int fw_parse_program_data(struct tasdevice_priv *tas_priv, offset = -EINVAL; goto out; } - tas_fmw->nr_programs = be16_to_cpup((__be16 *)&buf[offset]); + tas_fmw->nr_programs = get_unaligned_be16(&buf[offset]); offset += 2; if (tas_fmw->nr_programs == 0) { @@ -1143,7 +1142,7 @@ static int fw_parse_configuration_data( offset = -EINVAL; goto out; } - tas_fmw->nr_configurations = be16_to_cpup((__be16 *)&data[offset]); + tas_fmw->nr_configurations = get_unaligned_be16(&data[offset]); offset += 2; if (tas_fmw->nr_configurations == 0) { @@ -1775,7 +1774,7 @@ static int fw_parse_header(struct tasdevice_priv *tas_priv, /* Convert data[offset], data[offset + 1], data[offset + 2] and * data[offset + 3] into host */ - fw_fixed_hdr->fwsize = be32_to_cpup((__be32 *)&buf[offset]); + fw_fixed_hdr->fwsize = get_unaligned_be32(&buf[offset]); offset += 4; if (fw_fixed_hdr->fwsize != fmw->size) { dev_err(tas_priv->dev, "File size not match, %lu %u", @@ -1784,9 +1783,9 @@ static int fw_parse_header(struct tasdevice_priv *tas_priv, goto out; } offset += 4; - fw_fixed_hdr->ppcver = be32_to_cpup((__be32 *)&buf[offset]); + fw_fixed_hdr->ppcver = get_unaligned_be32(&buf[offset]); offset += 8; - fw_fixed_hdr->drv_ver = be32_to_cpup((__be32 *)&buf[offset]); + fw_fixed_hdr->drv_ver = get_unaligned_be32(&buf[offset]); offset += 72; out: @@ -1828,7 +1827,7 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv, offset = -EINVAL; goto out; } - tas_fmw->nr_calibrations = be16_to_cpup((__be16 *)&data[offset]); + tas_fmw->nr_calibrations = get_unaligned_be16(&data[offset]); offset += 2; if (tas_fmw->nr_calibrations != 1) { From a613b63db233b6e7d46ec72f009c1cbb7db8be66 Mon Sep 17 00:00:00 2001 From: Elinor Montmasson Date: Thu, 27 Jun 2024 10:30:58 +0200 Subject: [PATCH 317/349] ASoC: fsl-asoc-card: add support for dai links with multiple codecs Add support for dai links using multiple codecs for multi-codec use cases. Co-developed-by: Philip-Dylan Gleonec Signed-off-by: Philip-Dylan Gleonec Signed-off-by: Elinor Montmasson Link: https://patch.msgid.link/20240627083104.123357-2-elinor.montmasson@savoirfairelinux.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index eb67689dcd6e..e8003fbc8092 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -542,6 +542,7 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card) static int fsl_asoc_card_probe(struct platform_device *pdev) { struct device_node *cpu_np, *codec_np, *asrc_np; + struct snd_soc_dai_link_component *codec_comp; struct device_node *np = pdev->dev.of_node; struct platform_device *asrc_pdev = NULL; struct device_node *bitclkprovider = NULL; @@ -552,6 +553,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) const char *codec_dai_name; const char *codec_dev_name; u32 asrc_fmt = 0; + int codec_idx; u32 width; int ret; @@ -816,10 +818,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) /* Normal DAI Link */ priv->dai_link[0].cpus->of_node = cpu_np; - priv->dai_link[0].codecs->dai_name = codec_dai_name; + priv->dai_link[0].codecs[0].dai_name = codec_dai_name; if (!fsl_asoc_card_is_ac97(priv)) - priv->dai_link[0].codecs->of_node = codec_np; + priv->dai_link[0].codecs[0].of_node = codec_np; else { u32 idx; @@ -830,11 +832,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) goto asrc_fail; } - priv->dai_link[0].codecs->name = + priv->dai_link[0].codecs[0].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ac97-codec.%u", (unsigned int)idx); - if (!priv->dai_link[0].codecs->name) { + if (!priv->dai_link[0].codecs[0].name) { ret = -ENOMEM; goto asrc_fail; } @@ -848,10 +850,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) /* DPCM DAI Links only if ASRC exists */ priv->dai_link[1].cpus->of_node = asrc_np; priv->dai_link[1].platforms->of_node = asrc_np; - priv->dai_link[2].codecs->dai_name = codec_dai_name; - priv->dai_link[2].codecs->of_node = codec_np; - priv->dai_link[2].codecs->name = - priv->dai_link[0].codecs->name; + for_each_link_codecs((&(priv->dai_link[2])), codec_idx, codec_comp) { + codec_comp->dai_name = priv->dai_link[0].codecs[codec_idx].dai_name; + codec_comp->of_node = priv->dai_link[0].codecs[codec_idx].of_node; + codec_comp->name = priv->dai_link[0].codecs[codec_idx].name; + } priv->dai_link[2].cpus->of_node = cpu_np; priv->dai_link[2].dai_fmt = priv->dai_fmt; priv->card.num_links = 3; From c68fa0d9b0f8cc7c3ae7d29c02adbc97622a73f5 Mon Sep 17 00:00:00 2001 From: Elinor Montmasson Date: Thu, 27 Jun 2024 10:30:59 +0200 Subject: [PATCH 318/349] ASoC: fsl-asoc-card: add second dai link component for codecs Add a second dai link component for codecs that will be used for use cases with 2 codecs. It is needed for future integration of the SPDIF support, which will use spdif_receiver and spdif_transmitter drivers. To prevent deferring in use cases using only one codec, also set by default the number of codecs to 1 for the relevant dai links. Co-developed-by: Philip-Dylan Gleonec Signed-off-by: Philip-Dylan Gleonec Signed-off-by: Elinor Montmasson Link: https://patch.msgid.link/20240627083104.123357-3-elinor.montmasson@savoirfairelinux.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index e8003fbc8092..805e2030bde4 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -296,7 +296,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, SND_SOC_DAILINK_DEFS(hifi, DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_EMPTY(), COMP_EMPTY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(hifi_fe, @@ -306,7 +306,7 @@ SND_SOC_DAILINK_DEFS(hifi_fe, SND_SOC_DAILINK_DEFS(hifi_be, DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_EMPTY())); + DAILINK_COMP_ARRAY(COMP_EMPTY(), COMP_EMPTY())); static const struct snd_soc_dai_link fsl_asoc_card_dai[] = { /* Default ASoC DAI Link*/ @@ -622,6 +622,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) memcpy(priv->dai_link, fsl_asoc_card_dai, sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link)); + priv->dai_link[0].num_codecs = 1; + priv->dai_link[2].num_codecs = 1; priv->card.dapm_routes = audio_map; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map); From fcc6ace84f1f6ce2211af25c3c8fb30a0fb2bb2c Mon Sep 17 00:00:00 2001 From: Elinor Montmasson Date: Thu, 27 Jun 2024 10:31:00 +0200 Subject: [PATCH 319/349] ASoC: fsl-asoc-card: add compatibility to use 2 codecs in dai-links Adapt the driver to work with configurations using two codecs or more. Modify fsl_asoc_card_probe() to handle use cases where 2 codecs are given in the device tree. This will be needed to add support for the SPDIF. Use cases using one codec will ignore any given codecs other than the first. Co-developed-by: Philip-Dylan Gleonec Signed-off-by: Philip-Dylan Gleonec Signed-off-by: Elinor Montmasson Link: https://patch.msgid.link/20240627083104.123357-4-elinor.montmasson@savoirfairelinux.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 279 ++++++++++++++++++++-------------- 1 file changed, 161 insertions(+), 118 deletions(-) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 805e2030bde4..87329731e02d 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -99,7 +99,7 @@ struct fsl_asoc_card_priv { struct simple_util_jack hp_jack; struct simple_util_jack mic_jack; struct platform_device *pdev; - struct codec_priv codec_priv; + struct codec_priv codec_priv[2]; struct cpu_priv cpu_priv; struct snd_soc_card card; u8 streams; @@ -172,10 +172,12 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - struct codec_priv *codec_priv = &priv->codec_priv; + struct codec_priv *codec_priv; + struct snd_soc_dai *codec_dai; struct cpu_priv *cpu_priv = &priv->cpu_priv; struct device *dev = rtd->card->dev; unsigned int pll_out; + int codec_idx; int ret; priv->sample_rate = params_rate(params); @@ -208,28 +210,32 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, } /* Specific configuration for PLL */ - if (codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) { - if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE) - pll_out = priv->sample_rate * 384; - else - pll_out = priv->sample_rate * 256; + for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) { + codec_priv = &priv->codec_priv[codec_idx]; - ret = snd_soc_dai_set_pll(snd_soc_rtd_to_codec(rtd, 0), - codec_priv->pll_id, - codec_priv->mclk_id, - codec_priv->mclk_freq, pll_out); - if (ret) { - dev_err(dev, "failed to start FLL: %d\n", ret); - goto fail; - } + if (codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) { + if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE) + pll_out = priv->sample_rate * 384; + else + pll_out = priv->sample_rate * 256; - ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), - codec_priv->fll_id, - pll_out, SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_pll(codec_dai, + codec_priv->pll_id, + codec_priv->mclk_id, + codec_priv->mclk_freq, pll_out); + if (ret) { + dev_err(dev, "failed to start FLL: %d\n", ret); + goto fail; + } - if (ret && ret != -ENOTSUPP) { - dev_err(dev, "failed to set SYSCLK: %d\n", ret); - goto fail; + ret = snd_soc_dai_set_sysclk(codec_dai, + codec_priv->fll_id, + pll_out, SND_SOC_CLOCK_IN); + + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set SYSCLK: %d\n", ret); + goto fail; + } } } @@ -244,28 +250,34 @@ static int fsl_asoc_card_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct codec_priv *codec_priv = &priv->codec_priv; + struct codec_priv *codec_priv; + struct snd_soc_dai *codec_dai; struct device *dev = rtd->card->dev; + int codec_idx; int ret; priv->streams &= ~BIT(substream->stream); - if (!priv->streams && codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) { - /* Force freq to be free_freq to avoid error message in codec */ - ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), - codec_priv->mclk_id, - codec_priv->free_freq, - SND_SOC_CLOCK_IN); - if (ret) { - dev_err(dev, "failed to switch away from FLL: %d\n", ret); - return ret; - } + for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) { + codec_priv = &priv->codec_priv[codec_idx]; - ret = snd_soc_dai_set_pll(snd_soc_rtd_to_codec(rtd, 0), - codec_priv->pll_id, 0, 0, 0); - if (ret && ret != -ENOTSUPP) { - dev_err(dev, "failed to stop FLL: %d\n", ret); - return ret; + if (!priv->streams && codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) { + /* Force freq to be free_freq to avoid error message in codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, + codec_priv->mclk_id, + codec_priv->free_freq, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "failed to switch away from FLL: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, + codec_priv->pll_id, 0, 0, 0); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to stop FLL: %d\n", ret); + return ret; + } } } @@ -504,9 +516,10 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card) struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); struct snd_soc_pcm_runtime *rtd = list_first_entry( &card->rtd_list, struct snd_soc_pcm_runtime, list); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct codec_priv *codec_priv = &priv->codec_priv; + struct snd_soc_dai *codec_dai; + struct codec_priv *codec_priv; struct device *dev = card->dev; + int codec_idx; int ret; if (fsl_asoc_card_is_ac97(priv)) { @@ -526,32 +539,37 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card) return 0; } - ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, - codec_priv->mclk_freq, SND_SOC_CLOCK_IN); - if (ret && ret != -ENOTSUPP) { - dev_err(dev, "failed to set sysclk in %s\n", __func__); - return ret; - } + for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) { + codec_priv = &priv->codec_priv[codec_idx]; - if (!IS_ERR_OR_NULL(codec_priv->mclk)) - clk_prepare_enable(codec_priv->mclk); + ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, + codec_priv->mclk_freq, SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set sysclk in %s\n", __func__); + return ret; + } + + if (!IS_ERR_OR_NULL(codec_priv->mclk)) + clk_prepare_enable(codec_priv->mclk); + } return 0; } static int fsl_asoc_card_probe(struct platform_device *pdev) { - struct device_node *cpu_np, *codec_np, *asrc_np; + struct device_node *cpu_np, *asrc_np; struct snd_soc_dai_link_component *codec_comp; + struct device_node *codec_np[2]; struct device_node *np = pdev->dev.of_node; struct platform_device *asrc_pdev = NULL; struct device_node *bitclkprovider = NULL; struct device_node *frameprovider = NULL; struct platform_device *cpu_pdev; struct fsl_asoc_card_priv *priv; - struct device *codec_dev = NULL; - const char *codec_dai_name; - const char *codec_dev_name; + struct device *codec_dev[2] = { NULL, NULL }; + const char *codec_dai_name[2]; + const char *codec_dev_name[2]; u32 asrc_fmt = 0; int codec_idx; u32 width; @@ -580,21 +598,25 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) goto fail; } - codec_np = of_parse_phandle(np, "audio-codec", 0); - if (codec_np) { - struct platform_device *codec_pdev; - struct i2c_client *codec_i2c; + codec_np[0] = of_parse_phandle(np, "audio-codec", 0); + codec_np[1] = of_parse_phandle(np, "audio-codec", 1); - codec_i2c = of_find_i2c_device_by_node(codec_np); - if (codec_i2c) { - codec_dev = &codec_i2c->dev; - codec_dev_name = codec_i2c->name; - } - if (!codec_dev) { - codec_pdev = of_find_device_by_node(codec_np); - if (codec_pdev) { - codec_dev = &codec_pdev->dev; - codec_dev_name = codec_pdev->name; + for (codec_idx = 0; codec_idx < 2; codec_idx++) { + if (codec_np[codec_idx]) { + struct platform_device *codec_pdev; + struct i2c_client *codec_i2c; + + codec_i2c = of_find_i2c_device_by_node(codec_np[codec_idx]); + if (codec_i2c) { + codec_dev[codec_idx] = &codec_i2c->dev; + codec_dev_name[codec_idx] = codec_i2c->name; + } + if (!codec_dev[codec_idx]) { + codec_pdev = of_find_device_by_node(codec_np[codec_idx]); + if (codec_pdev) { + codec_dev[codec_idx] = &codec_pdev->dev; + codec_dev_name[codec_idx] = codec_pdev->name; + } } } } @@ -604,12 +626,14 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) asrc_pdev = of_find_device_by_node(asrc_np); /* Get the MCLK rate only, and leave it controlled by CODEC drivers */ - if (codec_dev) { - struct clk *codec_clk = clk_get(codec_dev, NULL); + for (codec_idx = 0; codec_idx < 2; codec_idx++) { + if (codec_dev[codec_idx]) { + struct clk *codec_clk = clk_get(codec_dev[codec_idx], NULL); - if (!IS_ERR(codec_clk)) { - priv->codec_priv.mclk_freq = clk_get_rate(codec_clk); - clk_put(codec_clk); + if (!IS_ERR(codec_clk)) { + priv->codec_priv[codec_idx].mclk_freq = clk_get_rate(codec_clk); + clk_put(codec_clk); + } } } @@ -629,31 +653,33 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->card.num_dapm_routes = ARRAY_SIZE(audio_map); priv->card.driver_name = DRIVER_NAME; - priv->codec_priv.fll_id = -1; - priv->codec_priv.pll_id = -1; + for (codec_idx = 0; codec_idx < 2; codec_idx++) { + priv->codec_priv[codec_idx].fll_id = -1; + priv->codec_priv[codec_idx].pll_id = -1; + } /* Diversify the card configurations */ if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) { - codec_dai_name = "cs42888"; - priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq; - priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq; + codec_dai_name[0] = "cs42888"; + priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv[0].mclk_freq; + priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv[0].mclk_freq; priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; priv->cpu_priv.slot_width = 32; priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; } else if (of_device_is_compatible(np, "fsl,imx-audio-cs427x")) { - codec_dai_name = "cs4271-hifi"; - priv->codec_priv.mclk_id = CS427x_SYSCLK_MCLK; + codec_dai_name[0] = "cs4271-hifi"; + priv->codec_priv[0].mclk_id = CS427x_SYSCLK_MCLK; priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { - codec_dai_name = "sgtl5000"; - priv->codec_priv.mclk_id = SGTL5000_SYSCLK; + codec_dai_name[0] = "sgtl5000"; + priv->codec_priv[0].mclk_id = SGTL5000_SYSCLK; priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) { - codec_dai_name = "tlv320aic32x4-hifi"; + codec_dai_name[0] = "tlv320aic32x4-hifi"; priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) { - codec_dai_name = "tlv320dac31xx-hifi"; + codec_dai_name[0] = "tlv320dac31xx-hifi"; priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; priv->dai_link[1].dpcm_capture = 0; priv->dai_link[2].dpcm_capture = 0; @@ -662,23 +688,23 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) { - codec_dai_name = "wm8962"; - priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK; - priv->codec_priv.fll_id = WM8962_SYSCLK_FLL; - priv->codec_priv.pll_id = WM8962_FLL; + codec_dai_name[0] = "wm8962"; + priv->codec_priv[0].mclk_id = WM8962_SYSCLK_MCLK; + priv->codec_priv[0].fll_id = WM8962_SYSCLK_FLL; + priv->codec_priv[0].pll_id = WM8962_FLL; priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) { - codec_dai_name = "wm8960-hifi"; - priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO; - priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO; + codec_dai_name[0] = "wm8960-hifi"; + priv->codec_priv[0].fll_id = WM8960_SYSCLK_AUTO; + priv->codec_priv[0].pll_id = WM8960_SYSCLK_AUTO; priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) { - codec_dai_name = "ac97-hifi"; + codec_dai_name[0] = "ac97-hifi"; priv->dai_fmt = SND_SOC_DAIFMT_AC97; priv->card.dapm_routes = audio_map_ac97; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_ac97); } else if (of_device_is_compatible(np, "fsl,imx-audio-mqs")) { - codec_dai_name = "fsl-mqs-dai"; + codec_dai_name[0] = "fsl-mqs-dai"; priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_NB_NF; @@ -687,7 +713,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8524")) { - codec_dai_name = "wm8524-hifi"; + codec_dai_name[0] = "wm8524-hifi"; priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; priv->dai_link[1].dpcm_capture = 0; priv->dai_link[2].dpcm_capture = 0; @@ -695,32 +721,32 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); } else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) { - codec_dai_name = "si476x-codec"; + codec_dai_name[0] = "si476x-codec"; priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; priv->card.dapm_routes = audio_map_rx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx); } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8958")) { - codec_dai_name = "wm8994-aif1"; + codec_dai_name[0] = "wm8994-aif1"; priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; - priv->codec_priv.mclk_id = WM8994_FLL_SRC_MCLK1; - priv->codec_priv.fll_id = WM8994_SYSCLK_FLL1; - priv->codec_priv.pll_id = WM8994_FLL1; - priv->codec_priv.free_freq = priv->codec_priv.mclk_freq; + priv->codec_priv[0].mclk_id = WM8994_FLL_SRC_MCLK1; + priv->codec_priv[0].fll_id = WM8994_SYSCLK_FLL1; + priv->codec_priv[0].pll_id = WM8994_FLL1; + priv->codec_priv[0].free_freq = priv->codec_priv[0].mclk_freq; priv->card.dapm_routes = NULL; priv->card.num_dapm_routes = 0; } else if (of_device_is_compatible(np, "fsl,imx-audio-nau8822")) { - codec_dai_name = "nau8822-hifi"; - priv->codec_priv.mclk_id = NAU8822_CLK_MCLK; - priv->codec_priv.fll_id = NAU8822_CLK_PLL; - priv->codec_priv.pll_id = NAU8822_CLK_PLL; + codec_dai_name[0] = "nau8822-hifi"; + priv->codec_priv[0].mclk_id = NAU8822_CLK_MCLK; + priv->codec_priv[0].fll_id = NAU8822_CLK_PLL; + priv->codec_priv[0].pll_id = NAU8822_CLK_PLL; priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; - if (codec_dev) - priv->codec_priv.mclk = devm_clk_get(codec_dev, NULL); + if (codec_dev[0]) + priv->codec_priv[0].mclk = devm_clk_get(codec_dev[0], NULL); } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8904")) { - codec_dai_name = "wm8904-hifi"; - priv->codec_priv.mclk_id = WM8904_FLL_MCLK; - priv->codec_priv.fll_id = WM8904_CLK_FLL; - priv->codec_priv.pll_id = WM8904_FLL_MCLK; + codec_dai_name[0] = "wm8904-hifi"; + priv->codec_priv[0].mclk_id = WM8904_FLL_MCLK; + priv->codec_priv[0].fll_id = WM8904_CLK_FLL; + priv->codec_priv[0].pll_id = WM8904_FLL_MCLK; priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else { dev_err(&pdev->dev, "unknown Device Tree compatible\n"); @@ -732,18 +758,30 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) * Allow setting mclk-id from the device-tree node. Otherwise, the * default value for each card configuration is used. */ - of_property_read_u32(np, "mclk-id", &priv->codec_priv.mclk_id); + for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) { + of_property_read_u32_index(np, "mclk-id", codec_idx, + &priv->codec_priv[codec_idx].mclk_id); + } /* Format info from DT is optional. */ snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL, &bitclkprovider, &frameprovider); if (bitclkprovider || frameprovider) { unsigned int daifmt = snd_soc_daifmt_parse_format(np, NULL); + bool codec_bitclkprovider = false; + bool codec_frameprovider = false; - if (codec_np == bitclkprovider) - daifmt |= (codec_np == frameprovider) ? + for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) { + if (bitclkprovider && codec_np[codec_idx] == bitclkprovider) + codec_bitclkprovider = true; + if (frameprovider && codec_np[codec_idx] == frameprovider) + codec_frameprovider = true; + } + + if (codec_bitclkprovider) + daifmt |= (codec_frameprovider) ? SND_SOC_DAIFMT_CBP_CFP : SND_SOC_DAIFMT_CBP_CFC; else - daifmt |= (codec_np == frameprovider) ? + daifmt |= (codec_frameprovider) ? SND_SOC_DAIFMT_CBC_CFP : SND_SOC_DAIFMT_CBC_CFC; /* Override dai_fmt with value from DT */ @@ -759,7 +797,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) of_node_put(bitclkprovider); of_node_put(frameprovider); - if (!fsl_asoc_card_is_ac97(priv) && !codec_dev) { + if (!fsl_asoc_card_is_ac97(priv) && !codec_dev[0]) { dev_dbg(&pdev->dev, "failed to find codec device\n"); ret = -EPROBE_DEFER; goto asrc_fail; @@ -798,7 +836,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) ret = snd_soc_of_parse_card_name(&priv->card, "model"); if (ret) { snprintf(priv->name, sizeof(priv->name), "%s-audio", - fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name); + fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name[0]); priv->card.name = priv->name; } priv->card.dai_link = priv->dai_link; @@ -820,11 +858,15 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) /* Normal DAI Link */ priv->dai_link[0].cpus->of_node = cpu_np; - priv->dai_link[0].codecs[0].dai_name = codec_dai_name; + for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) { + codec_comp->dai_name = codec_dai_name[codec_idx]; + } - if (!fsl_asoc_card_is_ac97(priv)) - priv->dai_link[0].codecs[0].of_node = codec_np; - else { + if (!fsl_asoc_card_is_ac97(priv)) { + for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) { + codec_comp->of_node = codec_np[codec_idx]; + } + } else { u32 idx; ret = of_property_read_u32(cpu_np, "cell-index", &idx); @@ -926,7 +968,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) asrc_fail: of_node_put(asrc_np); - of_node_put(codec_np); + of_node_put(codec_np[0]); + of_node_put(codec_np[1]); put_device(&cpu_pdev->dev); fail: of_node_put(cpu_np); From 6d174cc4f22461ad3fe383570527e86bf1948a2e Mon Sep 17 00:00:00 2001 From: Elinor Montmasson Date: Thu, 27 Jun 2024 10:31:01 +0200 Subject: [PATCH 320/349] ASoC: fsl-asoc-card: merge spdif support from imx-spdif.c The imx-spdif machine driver creates audio card to directly use an S/PDIF device. However, it doesn't support interacting with an ASRC. fsl-asoc-card already has the support to create audio card which can use the ASRC. Merge the S/PDIF support from imx-spdif into driver fsl-asoc-card to extend the support of S/PDIF audio card with the use of ASRC devices. fsl-asoc-card uses slightly different DT properties than imx-spdif: * the "spdif-controller" property from imx-spdif is named "audio-cpu" in fsl-asoc-card. * fsl-asoc-card uses codecs explicitly declared in DT with "audio-codec". With an SPDIF, codec drivers spdif_transmitter and spdif_receiver should be used. Driver imx-spdif used instead the dummy codec and a pair of boolean properties, "spdif-in" and "spdif-out". To keep backward compatibility, support for "spdif-controller", "spdif-in" and "spdif-out" is also added to fsl-asoc-card. However, it is recommended to use the new properties if possible. It is better to declare transmitter and/or receiver in DT than using the dummy codec. DTs using compatible "fsl,imx-audio-spdif" are still compatible, and fsl-asoc-card will behave the same as imx-spdif for these DTs. Signed-off-by: Elinor Montmasson Link: https://patch.msgid.link/20240627083104.123357-5-elinor.montmasson@savoirfairelinux.com Signed-off-by: Mark Brown --- arch/arm/configs/imx_v6_v7_defconfig | 1 - arch/arm64/configs/defconfig | 1 - sound/soc/fsl/Kconfig | 10 +-- sound/soc/fsl/Makefile | 2 - sound/soc/fsl/fsl-asoc-card.c | 85 +++++++++++++++++++++- sound/soc/fsl/imx-spdif.c | 103 --------------------------- 6 files changed, 84 insertions(+), 118 deletions(-) delete mode 100644 sound/soc/fsl/imx-spdif.c diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index cf2480dce285..ac5ae621b2af 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -311,7 +311,6 @@ CONFIG_SND_IMX_SOC=y CONFIG_SND_SOC_EUKREA_TLV320=y CONFIG_SND_SOC_IMX_ES8328=y CONFIG_SND_SOC_IMX_SGTL5000=y -CONFIG_SND_SOC_IMX_SPDIF=y CONFIG_SND_SOC_FSL_ASOC_CARD=y CONFIG_SND_SOC_AC97_CODEC=y CONFIG_SND_SOC_CS42XX8_I2C=y diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 57a9abe78ee4..a6c9688fee0e 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -940,7 +940,6 @@ CONFIG_SND_SOC_FSL_MICFIL=m CONFIG_SND_SOC_FSL_EASRC=m CONFIG_SND_IMX_SOC=m CONFIG_SND_SOC_IMX_SGTL5000=m -CONFIG_SND_SOC_IMX_SPDIF=m CONFIG_SND_SOC_FSL_ASOC_CARD=m CONFIG_SND_SOC_IMX_AUDMIX=m CONFIG_SND_SOC_MT8183=m diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 8b7088623b6a..e283751abfef 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -303,15 +303,6 @@ config SND_SOC_IMX_SGTL5000 SND_SOC_FSL_ASOC_CARD and SND_SOC_SGTL5000 to use the newer driver. -config SND_SOC_IMX_SPDIF - tristate "SoC Audio support for i.MX boards with S/PDIF" - select SND_SOC_IMX_PCM_DMA - select SND_SOC_FSL_SPDIF - help - SoC Audio support for i.MX boards with S/PDIF - Say Y if you want to add support for SoC audio on an i.MX board with - a S/DPDIF. - config SND_SOC_FSL_ASOC_CARD tristate "Generic ASoC Sound Card with ASRC support" depends on OF && I2C @@ -323,6 +314,7 @@ config SND_SOC_FSL_ASOC_CARD select SND_SOC_FSL_ESAI select SND_SOC_FSL_SAI select SND_SOC_FSL_SSI + select SND_SOC_FSL_SPDIF select SND_SOC_TLV320AIC31XX select SND_SOC_WM8994 select MFD_WM8994 diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 2a61e2f96438..ad97244b5cc3 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -67,7 +67,6 @@ obj-$(CONFIG_SND_SOC_IMX_PCM_RPMSG) += imx-pcm-rpmsg.o snd-soc-eukrea-tlv320-y := eukrea-tlv320.o snd-soc-imx-es8328-y := imx-es8328.o snd-soc-imx-sgtl5000-y := imx-sgtl5000.o -snd-soc-imx-spdif-y := imx-spdif.o snd-soc-imx-audmix-y := imx-audmix.o snd-soc-imx-hdmi-y := imx-hdmi.o snd-soc-imx-rpmsg-y := imx-rpmsg.o @@ -76,7 +75,6 @@ snd-soc-imx-card-y := imx-card.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o -obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o obj-$(CONFIG_SND_SOC_IMX_RPMSG) += snd-soc-imx-rpmsg.o diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 87329731e02d..82df887b3af5 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -477,6 +477,75 @@ static int fsl_asoc_card_audmux_init(struct device_node *np, return 0; } +static int fsl_asoc_card_spdif_init(struct device_node *codec_np[], + struct device_node *cpu_np, + const char *codec_dai_name[], + struct fsl_asoc_card_priv *priv) +{ + struct device *dev = &priv->pdev->dev; + struct device_node *np = dev->of_node; + + if (!of_node_name_eq(cpu_np, "spdif")) { + dev_err(dev, "CPU phandle invalid, should be an SPDIF device\n"); + return -EINVAL; + } + + priv->dai_link[0].playback_only = true; + priv->dai_link[0].capture_only = true; + + for (int i = 0; i < 2; i++) { + if (!codec_np[i]) + break; + + if (of_device_is_compatible(codec_np[i], "linux,spdif-dit")) { + priv->dai_link[0].capture_only = false; + codec_dai_name[i] = "dit-hifi"; + } else if (of_device_is_compatible(codec_np[i], "linux,spdif-dir")) { + priv->dai_link[0].playback_only = false; + codec_dai_name[i] = "dir-hifi"; + } + } + + // Old SPDIF DT binding + if (!codec_np[0]) { + codec_dai_name[0] = snd_soc_dummy_dlc.dai_name; + if (of_property_read_bool(np, "spdif-out")) + priv->dai_link[0].capture_only = false; + if (of_property_read_bool(np, "spdif-in")) + priv->dai_link[0].playback_only = false; + } + + if (priv->dai_link[0].playback_only && priv->dai_link[0].capture_only) { + dev_err(dev, "no enabled S/PDIF DAI link\n"); + return -EINVAL; + } + + if (priv->dai_link[0].playback_only) { + priv->dai_link[1].dpcm_capture = false; + priv->dai_link[2].dpcm_capture = false; + priv->card.dapm_routes = audio_map_tx; + priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); + } else if (priv->dai_link[0].capture_only) { + priv->dai_link[1].dpcm_playback = false; + priv->dai_link[2].dpcm_playback = false; + priv->card.dapm_routes = audio_map_rx; + priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx); + } + + // No DAPM routes with old bindings and dummy codec + if (!codec_np[0]) { + priv->card.dapm_routes = NULL; + priv->card.num_dapm_routes = 0; + } + + if (codec_np[0] && codec_np[1]) { + priv->dai_link[0].num_codecs = 2; + priv->dai_link[2].num_codecs = 2; + } + + return 0; +} + static int hp_jack_event(struct notifier_block *nb, unsigned long event, void *data) { @@ -582,9 +651,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->pdev = pdev; cpu_np = of_parse_phandle(np, "audio-cpu", 0); - /* Give a chance to old DT binding */ + /* Give a chance to old DT bindings */ if (!cpu_np) cpu_np = of_parse_phandle(np, "ssi-controller", 0); + if (!cpu_np) + cpu_np = of_parse_phandle(np, "spdif-controller", 0); if (!cpu_np) { dev_err(&pdev->dev, "CPU phandle missing or invalid\n"); ret = -EINVAL; @@ -748,6 +819,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->codec_priv[0].fll_id = WM8904_CLK_FLL; priv->codec_priv[0].pll_id = WM8904_FLL_MCLK; priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; + } else if (of_device_is_compatible(np, "fsl,imx-audio-spdif")) { + ret = fsl_asoc_card_spdif_init(codec_np, cpu_np, codec_dai_name, priv); + if (ret) + goto asrc_fail; } else { dev_err(&pdev->dev, "unknown Device Tree compatible\n"); ret = -EINVAL; @@ -797,7 +872,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) of_node_put(bitclkprovider); of_node_put(frameprovider); - if (!fsl_asoc_card_is_ac97(priv) && !codec_dev[0]) { + if (!fsl_asoc_card_is_ac97(priv) && !codec_dev[0] + && codec_dai_name[0] != snd_soc_dummy_dlc.dai_name) { dev_dbg(&pdev->dev, "failed to find codec device\n"); ret = -EPROBE_DEFER; goto asrc_fail; @@ -862,6 +938,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) codec_comp->dai_name = codec_dai_name[codec_idx]; } + // Old SPDIF DT binding support + if (codec_dai_name[0] == snd_soc_dummy_dlc.dai_name) + priv->dai_link[0].codecs[0].name = snd_soc_dummy_dlc.name; + if (!fsl_asoc_card_is_ac97(priv)) { for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) { codec_comp->of_node = codec_np[codec_idx]; @@ -992,6 +1072,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = { { .compatible = "fsl,imx-audio-wm8958", }, { .compatible = "fsl,imx-audio-nau8822", }, { .compatible = "fsl,imx-audio-wm8904", }, + { .compatible = "fsl,imx-audio-spdif", }, {} }; MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids); diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c deleted file mode 100644 index 1e57939a7e29..000000000000 --- a/sound/soc/fsl/imx-spdif.c +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// Copyright (C) 2013 Freescale Semiconductor, Inc. - -#include -#include -#include - -struct imx_spdif_data { - struct snd_soc_dai_link dai; - struct snd_soc_card card; -}; - -static int imx_spdif_audio_probe(struct platform_device *pdev) -{ - struct device_node *spdif_np, *np = pdev->dev.of_node; - struct imx_spdif_data *data; - struct snd_soc_dai_link_component *comp; - int ret = 0; - - spdif_np = of_parse_phandle(np, "spdif-controller", 0); - if (!spdif_np) { - dev_err(&pdev->dev, "failed to find spdif-controller\n"); - ret = -EINVAL; - goto end; - } - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - comp = devm_kzalloc(&pdev->dev, sizeof(*comp), GFP_KERNEL); - if (!data || !comp) { - ret = -ENOMEM; - goto end; - } - - /* - * CPU == Platform - * platform is using soc-generic-dmaengine-pcm - */ - data->dai.cpus = - data->dai.platforms = comp; - data->dai.codecs = &snd_soc_dummy_dlc; - - data->dai.num_cpus = 1; - data->dai.num_codecs = 1; - data->dai.num_platforms = 1; - - data->dai.name = "S/PDIF PCM"; - data->dai.stream_name = "S/PDIF PCM"; - data->dai.cpus->of_node = spdif_np; - data->dai.playback_only = true; - data->dai.capture_only = true; - - if (of_property_read_bool(np, "spdif-out")) - data->dai.capture_only = false; - - if (of_property_read_bool(np, "spdif-in")) - data->dai.playback_only = false; - - if (data->dai.playback_only && data->dai.capture_only) { - dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n"); - goto end; - } - - data->card.dev = &pdev->dev; - data->card.dai_link = &data->dai; - data->card.num_links = 1; - data->card.owner = THIS_MODULE; - - ret = snd_soc_of_parse_card_name(&data->card, "model"); - if (ret) - goto end; - - ret = devm_snd_soc_register_card(&pdev->dev, &data->card); - if (ret) - dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); - -end: - of_node_put(spdif_np); - - return ret; -} - -static const struct of_device_id imx_spdif_dt_ids[] = { - { .compatible = "fsl,imx-audio-spdif", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids); - -static struct platform_driver imx_spdif_driver = { - .driver = { - .name = "imx-spdif", - .pm = &snd_soc_pm_ops, - .of_match_table = imx_spdif_dt_ids, - }, - .probe = imx_spdif_audio_probe, -}; - -module_platform_driver(imx_spdif_driver); - -MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:imx-spdif"); From 4359caadd17fbde64d656c10bd6f2dc91b675a11 Mon Sep 17 00:00:00 2001 From: Elinor Montmasson Date: Thu, 27 Jun 2024 10:31:02 +0200 Subject: [PATCH 321/349] ASoC: dt-bindings: update fsl-asoc-card bindings after imx-spdif merge The S/PDIF audio card support with compatible "fsl,imx-audio-spdif" was merged from imx-spdif into the fsl-asoc-card driver. It makes possible to use an S/PDIF with an ASRC. This merge introduces new DT bindings to use with compatible "fsl,imx-audio-spdif" to follow the way fsl-asoc-card works: * the "spdif-controller" property from imx-spdif is named "audio-cpu" in fsl-asoc-card. * fsl-asoc-card uses codecs explicitly declared in DT with "audio-codec". With an SPDIF, codec drivers spdif_transmitter and spdif_receiver should be used. Driver imx-spdif used instead the dummy codec and a pair of boolean properties, "spdif-in" and "spdif-out". In an upcoming commit, in-tree DTs will be modified to follow these new properties: * Property "spdif-controller" will be renamed "audio-cpu". * spdif_transmitter and spdif_receiver nodes will be declared and linked to the fsl-asoc-card node with the property "audio-codec". To keep backward compatibility with other DTs, support for "spdif-controller", "spdif-in" and "spdif-out" properties is kept. However, it is recommended to use the new properties if possible. It is better to declare transmitter and/or receiver in DT than using the dummy codec. DTs using compatible "fsl,imx-audio-spdif" are still supported, and fsl-asoc-card will behave the same as imx-spdif for these DTs. Signed-off-by: Elinor Montmasson Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240627083104.123357-6-elinor.montmasson@savoirfairelinux.com Signed-off-by: Mark Brown --- .../bindings/sound/fsl,imx-audio-spdif.yaml | 66 ------------------- .../bindings/sound/fsl-asoc-card.yaml | 53 +++++++++++++-- 2 files changed, 49 insertions(+), 70 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml diff --git a/Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml b/Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml deleted file mode 100644 index 5fc543d02ecb..000000000000 --- a/Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml +++ /dev/null @@ -1,66 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/sound/fsl,imx-audio-spdif.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Freescale i.MX audio complex with S/PDIF transceiver - -maintainers: - - Shengjiu Wang - -properties: - compatible: - oneOf: - - items: - - enum: - - fsl,imx-sabreauto-spdif - - fsl,imx6sx-sdb-spdif - - const: fsl,imx-audio-spdif - - enum: - - fsl,imx-audio-spdif - - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - - spdif-controller: - $ref: /schemas/types.yaml#/definitions/phandle - description: The phandle of the i.MX S/PDIF controller - - spdif-out: - type: boolean - description: - If present, the transmitting function of S/PDIF will be enabled, - indicating there's a physical S/PDIF out connector or jack on the - board or it's connecting to some other IP block, such as an HDMI - encoder or display-controller. - - spdif-in: - type: boolean - description: - If present, the receiving function of S/PDIF will be enabled, - indicating there is a physical S/PDIF in connector/jack on the board. - -required: - - compatible - - model - - spdif-controller - -anyOf: - - required: - - spdif-in - - required: - - spdif-out - -additionalProperties: false - -examples: - - | - sound-spdif { - compatible = "fsl,imx-audio-spdif"; - model = "imx-spdif"; - spdif-controller = <&spdif>; - spdif-out; - spdif-in; - }; diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml b/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml index 9922664d5ccc..92aa47ec72c7 100644 --- a/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml +++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml @@ -65,6 +65,11 @@ properties: - fsl,imx-audio-sgtl5000 - fsl,imx-audio-wm8960 - fsl,imx-audio-wm8962 + - items: + - enum: + - fsl,imx-sabreauto-spdif + - fsl,imx6sx-sdb-spdif + - const: fsl,imx-audio-spdif - items: - enum: - fsl,imx-audio-ac97 @@ -81,6 +86,7 @@ properties: - fsl,imx-audio-wm8960 - fsl,imx-audio-wm8962 - fsl,imx-audio-wm8958 + - fsl,imx-audio-spdif model: $ref: /schemas/types.yaml#/definitions/string @@ -93,8 +99,15 @@ properties: need to add ASRC support via DPCM. audio-codec: - $ref: /schemas/types.yaml#/definitions/phandle - description: The phandle of an audio codec + $ref: /schemas/types.yaml#/definitions/phandle-array + description: | + The phandle of an audio codec. + With "fsl,imx-audio-spdif", either SPDIF audio codec spdif_transmitter, + spdif_receiver or both. + minItems: 1 + maxItems: 2 + items: + maxItems: 1 audio-cpu: $ref: /schemas/types.yaml#/definitions/phandle @@ -150,8 +163,10 @@ properties: description: dai-link uses bit clock inversion. mclk-id: - $ref: /schemas/types.yaml#/definitions/uint32 - description: main clock id, specific for each card configuration. + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Main clock id for each codec, specific for each card configuration. + minItems: 1 + maxItems: 2 mux-int-port: $ref: /schemas/types.yaml#/definitions/uint32 @@ -167,6 +182,27 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: The phandle of an CPU DAI controller + spdif-controller: + $ref: /schemas/types.yaml#/definitions/phandle + deprecated: true + description: The phandle of an S/PDIF CPU DAI controller. + + spdif-out: + type: boolean + deprecated: true + description: | + If present, the transmitting function of S/PDIF will be enabled, + indicating there's a physical S/PDIF out connector or jack on the + board or it's connecting to some other IP block, such as an HDMI + encoder or display-controller. + + spdif-in: + type: boolean + deprecated: true + description: | + If present, the receiving function of S/PDIF will be enabled, + indicating there is a physical S/PDIF in connector/jack on the board. + required: - compatible - model @@ -195,3 +231,12 @@ examples: "AIN2L", "Line In Jack", "AIN2R", "Line In Jack"; }; + + - | + sound-spdif-asrc { + compatible = "fsl,imx-audio-spdif"; + model = "spdif-asrc-audio"; + audio-cpu = <&spdif>; + audio-asrc = <&easrc>; + audio-codec = <&spdifdit>, <&spdifdir>; + }; From d2eb433c8546363134cabca7a85c73086700aeec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 8 Jul 2024 15:02:53 +0200 Subject: [PATCH 322/349] ALSA: ppc: keywest: Drop explicit initialization of struct i2c_device_id::driver_data to 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver doesn't use the driver_data member of struct i2c_device_id, so don't explicitly initialize this member. This prepares putting driver_data in an anonymous union which requires either no initialization or named designators. But it's also a nice cleanup on its own. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/20240708130254.9631-2-u.kleine-koenig@baylibre.com Signed-off-by: Takashi Iwai --- sound/ppc/keywest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index dfc1fc9b701d..2894d041b2f5 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c @@ -80,8 +80,8 @@ static void keywest_remove(struct i2c_client *client) static const struct i2c_device_id keywest_i2c_id[] = { - { "MAC,tas3004", 0 }, /* instantiated by i2c-powermac */ - { "keywest", 0 }, /* instantiated by us if needed */ + { "MAC,tas3004" }, /* instantiated by i2c-powermac */ + { "keywest" }, /* instantiated by us if needed */ { } }; MODULE_DEVICE_TABLE(i2c, keywest_i2c_id); From be5db7581f59621ed9cb9cbf6bebccda38263eb5 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Tue, 9 Jul 2024 12:33:40 +0800 Subject: [PATCH 323/349] ASoc: TAS2781: rename the tas2781_reset as tasdevice_reset Rename the tas2781_reset as tasdevice_reset in case of misunderstanding. RESET register for both tas2563 and tas2781 is same and the use of reset pin is also same. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20240709043342.946-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- include/sound/tas2781.h | 8 ++++---- sound/pci/hda/tas2781_hda_i2c.c | 4 ++-- sound/soc/codecs/tas2781-comlib.c | 8 ++++---- sound/soc/codecs/tas2781-i2c.c | 2 ++ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index cd8ce522b78e..a43ad6dcb7c7 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -2,7 +2,7 @@ // // ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier // -// Copyright (C) 2022 - 2023 Texas Instruments Incorporated +// Copyright (C) 2022 - 2024 Texas Instruments Incorporated // https://www.ti.com // // The TAS2563/TAS2781 driver implements a flexible and configurable @@ -43,8 +43,8 @@ (page * 128)) + reg) /*Software Reset */ -#define TAS2781_REG_SWRESET TASDEVICE_REG(0x0, 0X0, 0x01) -#define TAS2781_REG_SWRESET_RESET BIT(0) +#define TASDEVICE_REG_SWRESET TASDEVICE_REG(0x0, 0X0, 0x01) +#define TASDEVICE_REG_SWRESET_RESET BIT(0) /*I2C Checksum */ #define TASDEVICE_I2CChecksum TASDEVICE_REG(0x0, 0x0, 0x7E) @@ -140,7 +140,7 @@ struct tasdevice_priv { void (*apply_calibration)(struct tasdevice_priv *tas_priv); }; -void tas2781_reset(struct tasdevice_priv *tas_dev); +void tasdevice_reset(struct tasdevice_priv *tas_dev); int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, struct module *module, void (*cont)(const struct firmware *fw, void *context)); diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 75f7674c66ee..10420360b214 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -834,7 +834,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) pm_runtime_set_active(tas_hda->dev); pm_runtime_enable(tas_hda->dev); - tas2781_reset(tas_hda->priv); + tasdevice_reset(tas_hda->priv); ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops); if (ret) { @@ -929,7 +929,7 @@ static int tas2781_system_resume(struct device *dev) tas_hda->priv->tasdevice[i].cur_prog = -1; tas_hda->priv->tasdevice[i].cur_conf = -1; } - tas2781_reset(tas_hda->priv); + tasdevice_reset(tas_hda->priv); tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); /* If calibrated data occurs error, dsp will still work with default diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index 6db1a260da82..1fbf4560f5cc 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -243,7 +243,7 @@ struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c) } EXPORT_SYMBOL_GPL(tasdevice_kzalloc); -void tas2781_reset(struct tasdevice_priv *tas_dev) +void tasdevice_reset(struct tasdevice_priv *tas_dev) { int ret, i; @@ -254,8 +254,8 @@ void tas2781_reset(struct tasdevice_priv *tas_dev) } else { for (i = 0; i < tas_dev->ndev; i++) { ret = tasdevice_dev_write(tas_dev, i, - TAS2781_REG_SWRESET, - TAS2781_REG_SWRESET_RESET); + TASDEVICE_REG_SWRESET, + TASDEVICE_REG_SWRESET_RESET); if (ret < 0) dev_err(tas_dev->dev, "dev %d swreset fail, %d\n", @@ -264,7 +264,7 @@ void tas2781_reset(struct tasdevice_priv *tas_dev) } usleep_range(1000, 1050); } -EXPORT_SYMBOL_GPL(tas2781_reset); +EXPORT_SYMBOL_GPL(tasdevice_reset); int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, struct module *module, diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index b412f8f2e5d5..d5d95ae57c73 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -742,6 +742,8 @@ static int tasdevice_i2c_probe(struct i2c_client *i2c) if (ret) goto err; + tasdevice_reset(tas_priv); + ret = devm_snd_soc_register_component(tas_priv->dev, &soc_codec_driver_tasdevice, tasdevice_dai_driver, ARRAY_SIZE(tasdevice_dai_driver)); From e52a73e694522c7c94369a7741717a9f50baca0b Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 9 Jul 2024 11:09:21 +0800 Subject: [PATCH 324/349] ASoC: Intel: sof_sdw: Convert comma to semicolon Replace a comma between expression statements by a semicolon. Signed-off-by: Chen Ni Link: https://patch.msgid.link/20240709030921.585740-1-nichen@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index e94849b84a6b..e5feaef669d1 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -2136,9 +2136,9 @@ static int mc_probe(struct platform_device *pdev) card = &ctx->card; card->dev = &pdev->dev; - card->name = "soundwire", - card->owner = THIS_MODULE, - card->late_probe = sof_sdw_card_late_probe, + card->name = "soundwire"; + card->owner = THIS_MODULE; + card->late_probe = sof_sdw_card_late_probe; snd_soc_card_set_drvdata(card, ctx); From d0f4ce8a28dd992579949b8ea2df810c4b5fe9b5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Jul 2024 19:19:16 +0200 Subject: [PATCH 325/349] ASoC: codecs: aw88395: Simplify with cleanup.h Allocate memory, which is being freed at end of the scope, with scoped/cleanup.h to reduce number of error paths and make code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240701171917.596173-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/aw88395/aw88395_lib.c | 51 +++++++++----------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c index f25f6e0d4428..769ca32a5c8e 100644 --- a/sound/soc/codecs/aw88395/aw88395_lib.c +++ b/sound/soc/codecs/aw88395/aw88395_lib.c @@ -7,6 +7,7 @@ // Author: Bruce zhao // +#include #include #include #include "aw88395_lib.h" @@ -361,11 +362,11 @@ static int aw_dev_parse_raw_dsp_fw(unsigned char *data, unsigned int data_len, static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *data, unsigned int data_len, struct aw_prof_desc *prof_desc) { - struct aw_bin *aw_bin; int ret; int i; - aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(struct aw_bin), GFP_KERNEL); + struct aw_bin *aw_bin __free(kfree) = kzalloc(data_len + sizeof(struct aw_bin), + GFP_KERNEL); if (!aw_bin) return -ENOMEM; @@ -375,7 +376,7 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char * ret = aw_parsing_bin_file(aw_dev, aw_bin); if (ret < 0) { dev_err(aw_dev->dev, "parse bin failed"); - goto parse_bin_failed; + return ret; } for (i = 0; i < aw_bin->all_bin_parse_num; i++) { @@ -387,10 +388,8 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char * data + aw_bin->header_info[i].valid_data_addr; break; case DATA_TYPE_DSP_REG: - if (aw_bin->header_info[i].valid_data_len & 0x01) { - ret = -EINVAL; - goto parse_bin_failed; - } + if (aw_bin->header_info[i].valid_data_len & 0x01) + return -EINVAL; swab16_array((u16 *)(data + aw_bin->header_info[i].valid_data_addr), aw_bin->header_info[i].valid_data_len >> 1); @@ -402,10 +401,8 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char * break; case DATA_TYPE_DSP_FW: case DATA_TYPE_SOC_APP: - if (aw_bin->header_info[i].valid_data_len & 0x01) { - ret = -EINVAL; - goto parse_bin_failed; - } + if (aw_bin->header_info[i].valid_data_len & 0x01) + return -EINVAL; swab16_array((u16 *)(data + aw_bin->header_info[i].valid_data_addr), aw_bin->header_info[i].valid_data_len >> 1); @@ -422,20 +419,17 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char * } } prof_desc->prof_st = AW88395_PROFILE_OK; - ret = 0; -parse_bin_failed: - devm_kfree(aw_dev->dev, aw_bin); - return ret; + return 0; } 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); + struct aw_bin *aw_bin __free(kfree) = kzalloc(data_len + sizeof(*aw_bin), + GFP_KERNEL); if (!aw_bin) return -ENOMEM; @@ -445,14 +439,13 @@ static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev, ret = aw_parsing_bin_file(aw_dev, aw_bin); if (ret < 0) { dev_err(aw_dev->dev, "parse bin failed"); - goto parse_bin_failed; + return ret; } 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"); - ret = -EINVAL; - goto parse_bin_failed; + return -EINVAL; } prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data = @@ -461,15 +454,7 @@ static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev, 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, @@ -678,21 +663,21 @@ static int aw_dev_cfg_get_multiple_valid_prof(struct aw_device *aw_dev, static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev, struct aw_cfg_hdr *prof_hdr) { - struct aw_all_prof_info *all_prof_info; int ret; - all_prof_info = devm_kzalloc(aw_dev->dev, sizeof(struct aw_all_prof_info), GFP_KERNEL); + struct aw_all_prof_info *all_prof_info __free(kfree) = kzalloc(sizeof(*all_prof_info), + GFP_KERNEL); if (!all_prof_info) return -ENOMEM; ret = aw_dev_parse_dev_type(aw_dev, prof_hdr, all_prof_info); if (ret < 0) { - goto exit; + return ret; } else if (ret == AW88395_DEV_TYPE_NONE) { dev_dbg(aw_dev->dev, "get dev type num is 0, parse default dev"); ret = aw_dev_parse_dev_default_type(aw_dev, prof_hdr, all_prof_info); if (ret < 0) - goto exit; + return ret; } switch (aw_dev->prof_data_type) { @@ -710,8 +695,6 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev, if (!ret) aw_dev->prof_info.prof_name_list = profile_name; -exit: - devm_kfree(aw_dev->dev, all_prof_info); return ret; } From a8915e2fe86c29304a3038f269f4667b371b87d2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Jul 2024 19:19:17 +0200 Subject: [PATCH 326/349] ASoC: qcom: topology: Simplify with cleanup.h Allocate memory, which is being freed at end of the scope, with scoped/cleanup.h to reduce number of error paths and make code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240701171917.596173-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/topology.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c index f4d62ea60baa..83319a928f29 100644 --- a/sound/soc/qcom/qdsp6/topology.c +++ b/sound/soc/qcom/qdsp6/topology.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2020, Linaro Limited +#include #include #include #include @@ -1288,18 +1289,19 @@ int audioreach_tplg_init(struct snd_soc_component *component) struct snd_soc_card *card = component->card; struct device *dev = component->dev; const struct firmware *fw; - char *tplg_fw_name; int ret; /* Inline with Qualcomm UCM configs and linux-firmware path */ - tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name); + char *tplg_fw_name __free(kfree) = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", + card->driver_name, + card->name); if (!tplg_fw_name) return -ENOMEM; ret = request_firmware(&fw, tplg_fw_name, dev); if (ret < 0) { dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret); - goto err; + return ret; } ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw); @@ -1309,8 +1311,6 @@ int audioreach_tplg_init(struct snd_soc_component *component) } release_firmware(fw); -err: - kfree(tplg_fw_name); return ret; } From 054ac9c97c7d9eb55f471fc6f019b654d17332a7 Mon Sep 17 00:00:00 2001 From: Rayyan Ansari Date: Wed, 10 Jul 2024 12:36:06 +0100 Subject: [PATCH 327/349] ASoC: dt-bindings: qcom,msm8916-wcd-digital-codec: convert to dtschema Convert the Qualcomm MSM8916 WCD Digital Audio Codec bindings from text to yaml dt schema format. Make bindings complete by adding #sound-dai-cells. Signed-off-by: Rayyan Ansari Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240710113833.39859-2-rayyan.ansari@linaro.org Signed-off-by: Mark Brown --- .../sound/qcom,msm8916-wcd-digital-codec.yaml | 55 +++++++++++++++++++ .../sound/qcom,msm8916-wcd-digital.txt | 20 ------- 2 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml delete mode 100644 Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml new file mode 100644 index 000000000000..a899c4e7c1c9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,msm8916-wcd-digital-codec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm MSM8916 WCD Digital Audio Codec + +maintainers: + - Srinivas Kandagatla + +description: + The digital WCD audio codec found on Qualcomm MSM8916 LPASS. + +properties: + compatible: + const: qcom,msm8916-wcd-digital-codec + + reg: + maxItems: 1 + + clocks: + maxItems: 2 + + clock-names: + items: + - const: ahbix-clk + - const: mclk + + '#sound-dai-cells': + const: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - '#sound-dai-cells' + +allOf: + - $ref: dai-common.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + audio-codec@771c000 { + compatible = "qcom,msm8916-wcd-digital-codec"; + reg = <0x0771c000 0x400>; + clocks = <&gcc GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK>, + <&gcc GCC_CODEC_DIGCODEC_CLK>; + clock-names = "ahbix-clk", "mclk"; + #sound-dai-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt deleted file mode 100644 index 1c8e4cb25176..000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt +++ /dev/null @@ -1,20 +0,0 @@ -msm8916 digital audio CODEC - -## Bindings for codec core in lpass: - -Required properties - - compatible = "qcom,msm8916-wcd-digital-codec"; - - reg: address space for lpass codec. - - clocks: Handle to mclk and ahbclk - - clock-names: should be "mclk", "ahbix-clk". - -Example: - -audio-codec@771c000{ - compatible = "qcom,msm8916-wcd-digital-codec"; - reg = <0x0771c000 0x400>; - clocks = <&gcc GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK>, - <&gcc GCC_CODEC_DIGCODEC_CLK>; - clock-names = "ahbix-clk", "mclk"; - #sound-dai-cells = <1>; -}; From 3cbda25e2db28b4352c73d4167f0dab10049ea54 Mon Sep 17 00:00:00 2001 From: Rayyan Ansari Date: Wed, 10 Jul 2024 12:36:08 +0100 Subject: [PATCH 328/349] ASoC: dt-bindings: qcom,apq8096-sndcard: use dtschema Remove old txt bindings and add apq8096 soundcard entry to existing dt schema. Signed-off-by: Rayyan Ansari Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240710113833.39859-4-rayyan.ansari@linaro.org Signed-off-by: Mark Brown --- .../bindings/sound/qcom,apq8096.txt | 128 ------------------ .../bindings/sound/qcom,sm8250.yaml | 1 + 2 files changed, 1 insertion(+), 128 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/qcom,apq8096.txt diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8096.txt b/Documentation/devicetree/bindings/sound/qcom,apq8096.txt deleted file mode 100644 index e1b9fa8a5bf8..000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,apq8096.txt +++ /dev/null @@ -1,128 +0,0 @@ -* Qualcomm Technologies APQ8096 ASoC sound card driver - -This binding describes the APQ8096 sound card, which uses qdsp for audio. - -- compatible: - Usage: required - Value type: - Definition: must be "qcom,apq8096-sndcard" - -- audio-routing: - Usage: Optional - Value type: - Definition: A list of the connections between audio components. - Each entry is a pair of strings, the first being the - connection's sink, the second being the connection's - source. Valid names could be power supplies, MicBias - of codec and the jacks on the board: - Valid names include: - - Board Connectors: - "Headphone Left" - "Headphone Right" - "Earphone" - "Line Out1" - "Line Out2" - "Line Out3" - "Line Out4" - "Analog Mic1" - "Analog Mic2" - "Analog Mic3" - "Analog Mic4" - "Analog Mic5" - "Analog Mic6" - "Digital Mic2" - "Digital Mic3" - - Audio pins and MicBias on WCD9335 Codec: - "MIC_BIAS1" - "MIC_BIAS2" - "MIC_BIAS3" - "MIC_BIAS4" - "AMIC1" - "AMIC2" - "AMIC3" - "AMIC4" - "AMIC5" - "AMIC6" - "AMIC6" - "DMIC1" - "DMIC2" - "DMIC3" - -- model: - Usage: required - Value type: - Definition: The user-visible name of this sound card. - -- aux-devs - Usage: optional - Value type: - Definition: A list of phandles for auxiliary devices (e.g. analog - amplifiers) that do not appear directly within the DAI - links. Should be connected to another audio component - using "audio-routing". - -= dailinks -Each subnode of sndcard represents either a dailink, and subnodes of each -dailinks would be cpu/codec/platform dais. - -- link-name: - Usage: required - Value type: - Definition: User friendly name for dai link - -= CPU, PLATFORM, CODEC dais subnodes -- cpu: - Usage: required - Value type: - Definition: cpu dai sub-node - -- codec: - Usage: Optional - Value type: - Definition: codec dai sub-node - -- platform: - Usage: Optional - Value type: - Definition: platform dai sub-node - -- sound-dai: - Usage: required - Value type: - Definition: dai phandle/s and port of CPU/CODEC/PLATFORM node. - -Obsolete: - qcom,model: String for soundcard name (Use model instead) - qcom,audio-routing: A list of the connections between audio components. - (Use audio-routing instead) - -Example: - -audio { - compatible = "qcom,apq8096-sndcard"; - model = "DB820c"; - - mm1-dai-link { - link-name = "MultiMedia1"; - cpu { - sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; - }; - }; - - hdmi-dai-link { - link-name = "HDMI Playback"; - cpu { - sound-dai = <&q6afe HDMI_RX>; - }; - - platform { - sound-dai = <&q6adm>; - }; - - codec { - sound-dai = <&hdmi 0>; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index b2e15ebbd1bc..c9076dcd44c1 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -28,6 +28,7 @@ properties: - const: qcom,sm8450-sndcard - enum: - qcom,apq8016-sbc-sndcard + - qcom,apq8096-sndcard - qcom,msm8916-qdsp6-sndcard - qcom,qcm6490-idp-sndcard - qcom,qcs6490-rb3gen2-sndcard From bff92858dfb9897e4c06c11aab0322e1aab822f7 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 10 Jul 2024 11:36:37 +0100 Subject: [PATCH 329/349] firmware: cs_dsp: Don't allocate temporary buffer for info text Don't allocate a temporary buffer to hold a NUL-terminated copy of the NAME/INFO string from the wmfw/bin. It can be printed directly to the log. Also limit the maximum number of characters that will be logged from this string. The NAME/INFO blocks in the firmware files are an array of characters with a length, not a NUL-terminated C string. The original code allocated a temporary buffer to make a NUL-terminated copy of the string and then passed that to dev_info(). There's no need for this: printf formatting can use "%.*s" to print a character array of a given length. Signed-off-by: Richard Fitzgerald Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20240710103640.78197-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 35 +++++++------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 8a347b938406..9bd3f78396ea 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1470,7 +1471,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, const struct wmfw_region *region; const struct cs_dsp_region *mem; const char *region_name; - char *text = NULL; struct cs_dsp_buf *buf; unsigned int reg; int regions = 0; @@ -1542,15 +1542,15 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, region_name = "Unknown"; reg = 0; - text = NULL; offset = le32_to_cpu(region->offset) & 0xffffff; type = be32_to_cpu(region->type) & 0xff; switch (type) { + case WMFW_INFO_TEXT: case WMFW_NAME_TEXT: - region_name = "Firmware name"; - text = kzalloc(le32_to_cpu(region->len) + 1, - GFP_KERNEL); + region_name = "Info/Name"; + cs_dsp_info(dsp, "%s: %.*s\n", file, + min(le32_to_cpu(region->len), 100), region->data); break; case WMFW_ALGORITHM_DATA: region_name = "Algorithm"; @@ -1558,11 +1558,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, if (ret != 0) goto out_fw; break; - case WMFW_INFO_TEXT: - region_name = "Information"; - text = kzalloc(le32_to_cpu(region->len) + 1, - GFP_KERNEL); - break; case WMFW_ABSOLUTE: region_name = "Absolute"; reg = offset; @@ -1596,13 +1591,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, regions, le32_to_cpu(region->len), offset, region_name); - if (text) { - memcpy(text, region->data, le32_to_cpu(region->len)); - cs_dsp_info(dsp, "%s: %s\n", file, text); - kfree(text); - text = NULL; - } - if (reg) { buf = cs_dsp_buf_alloc(region->data, le32_to_cpu(region->len), @@ -1644,7 +1632,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, out_fw: regmap_async_complete(regmap); cs_dsp_buf_free(&buf_list); - kfree(text); if (ret == -EOVERFLOW) cs_dsp_err(dsp, "%s: file content overflows file data\n", file); @@ -2177,7 +2164,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware struct cs_dsp_alg_region *alg_region; const char *region_name; int ret, pos, blocks, type, offset, reg, version; - char *text = NULL; struct cs_dsp_buf *buf; if (!firmware) @@ -2246,7 +2232,8 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware region_name = "Unknown"; switch (type) { case (WMFW_NAME_TEXT << 8): - text = kzalloc(le32_to_cpu(blk->len) + 1, GFP_KERNEL); + cs_dsp_info(dsp, "%s: %.*s\n", dsp->fw_name, + min(le32_to_cpu(blk->len), 100), blk->data); break; case (WMFW_INFO_TEXT << 8): case (WMFW_METADATA << 8): @@ -2318,13 +2305,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware break; } - if (text) { - memcpy(text, blk->data, le32_to_cpu(blk->len)); - cs_dsp_info(dsp, "%s: %s\n", dsp->fw_name, text); - kfree(text); - text = NULL; - } - if (reg) { buf = cs_dsp_buf_alloc(blk->data, le32_to_cpu(blk->len), @@ -2364,7 +2344,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware out_fw: regmap_async_complete(regmap); cs_dsp_buf_free(&buf_list); - kfree(text); if (ret == -EOVERFLOW) cs_dsp_err(dsp, "%s: file content overflows file data\n", file); From 584e86e14c59d36688633002613792923620d8c0 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 10 Jul 2024 11:36:38 +0100 Subject: [PATCH 330/349] firmware: cs_dsp: Make wmfw and bin filename arguments const char * The wmfw_filename and bin_filename strings passed into cs_dsp_power_up() and cs_dsp_adsp1_power_up() should be const char *. Signed-off-by: Richard Fitzgerald Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20240710103640.78197-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 8 ++++---- include/linux/firmware/cirrus/cs_dsp.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 9bd3f78396ea..fda6faa8c835 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -2410,8 +2410,8 @@ EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_init, FW_CS_DSP); * Return: Zero for success, a negative number on error. */ int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, - const struct firmware *wmfw_firmware, char *wmfw_filename, - const struct firmware *coeff_firmware, char *coeff_filename, + const struct firmware *wmfw_firmware, const char *wmfw_filename, + const struct firmware *coeff_firmware, const char *coeff_filename, const char *fw_name) { unsigned int val; @@ -2704,8 +2704,8 @@ static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp) * Return: Zero for success, a negative number on error. */ int cs_dsp_power_up(struct cs_dsp *dsp, - const struct firmware *wmfw_firmware, char *wmfw_filename, - const struct firmware *coeff_firmware, char *coeff_filename, + const struct firmware *wmfw_firmware, const char *wmfw_filename, + const struct firmware *coeff_firmware, const char *coeff_filename, const char *fw_name) { int ret; diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index 82687e07a7c2..8078dc377948 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -213,13 +213,13 @@ int cs_dsp_adsp2_init(struct cs_dsp *dsp); int cs_dsp_halo_init(struct cs_dsp *dsp); int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, - const struct firmware *wmfw_firmware, char *wmfw_filename, - const struct firmware *coeff_firmware, char *coeff_filename, + const struct firmware *wmfw_firmware, const char *wmfw_filename, + const struct firmware *coeff_firmware, const char *coeff_filename, const char *fw_name); void cs_dsp_adsp1_power_down(struct cs_dsp *dsp); int cs_dsp_power_up(struct cs_dsp *dsp, - const struct firmware *wmfw_firmware, char *wmfw_filename, - const struct firmware *coeff_firmware, char *coeff_filename, + const struct firmware *wmfw_firmware, const char *wmfw_filename, + const struct firmware *coeff_firmware, const char *coeff_filename, const char *fw_name); void cs_dsp_power_down(struct cs_dsp *dsp); int cs_dsp_run(struct cs_dsp *dsp); From a4939119055d5c97aff2cea040f1af8c4606bfa1 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 10 Jul 2024 11:36:39 +0100 Subject: [PATCH 331/349] firmware: cs_dsp: Clarify wmfw format version log message Change the log message of the wmfw format version to include the file name, and change the message to say "format" instead of "Firmware version". Merge this with the message that logs the timestamp. The wmfw format version is information that is useful to have logged because the behaviour of firmware controls depends on the wmfw format. So "unexpected" behaviour could be caused by having expectations based on one format of wmfw when a different format has been loaded. But the original message was confusing. It reported the file format version but didn't actually log the name of the file it referred to. It also called it "Firmware version", which is confusing when a later message also logs a firmware version that is the version of the actual firmware within the wmfw. The logging of the firmware timestamp has been merged into this. That was originally a dbg-only message, but as we are already logging a line of info, we might as well add a few extra characters to log the timestamp. The timestamp is now logged in hexadecimal - it's not particularly useful as a decimal value. Signed-off-by: Richard Fitzgerald Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20240710103640.78197-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index fda6faa8c835..865db8defc56 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -1499,7 +1499,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, goto out_fw; } - cs_dsp_info(dsp, "Firmware version: %d\n", header->ver); dsp->fw_ver = header->ver; if (header->core != dsp->type) { @@ -1523,8 +1522,8 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, goto out_fw; } - cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file, - le64_to_cpu(footer->timestamp)); + cs_dsp_info(dsp, "%s: format %d timestamp %#llx\n", file, header->ver, + le64_to_cpu(footer->timestamp)); while (pos < firmware->size) { /* Is there enough data for a complete block header? */ From dc0e5ca8856dc6a97e3b117879dfb2b52bda06b6 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 10 Jul 2024 11:36:40 +0100 Subject: [PATCH 332/349] firmware: cs_dsp: Rename fw_ver to wmfw_ver Rename the confusingly named struct member fw_ver to wmfw_ver. It contains the wmfw format version of the loaded wmfw file. This commit also contains an update to wm_adsp for the new name. Signed-off-by: Richard Fitzgerald Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20240710103640.78197-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 20 ++++++++++---------- include/linux/firmware/cirrus/cs_dsp.h | 2 +- sound/soc/codecs/wm_adsp.c | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 865db8defc56..66c2f09b0be7 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -1048,7 +1048,7 @@ static int cs_dsp_create_control(struct cs_dsp *dsp, ctl->fw_name = dsp->fw_name; ctl->alg_region = *alg_region; - if (subname && dsp->fw_ver >= 2) { + if (subname && dsp->wmfw_ver >= 2) { ctl->subname_len = subname_len; ctl->subname = kasprintf(GFP_KERNEL, "%.*s", subname_len, subname); if (!ctl->subname) { @@ -1175,7 +1175,7 @@ static int cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, raw = (const struct wmfw_adsp_alg_data *)region->data; - switch (dsp->fw_ver) { + switch (dsp->wmfw_ver) { case 0: case 1: if (sizeof(*raw) > data_len) @@ -1252,7 +1252,7 @@ static int cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, blk->offset = le16_to_cpu(raw->hdr.offset); blk->mem_type = le16_to_cpu(raw->hdr.type); - switch (dsp->fw_ver) { + switch (dsp->wmfw_ver) { case 0: case 1: if (sizeof(*raw) > (data_len - pos)) @@ -1499,7 +1499,7 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, goto out_fw; } - dsp->fw_ver = header->ver; + dsp->wmfw_ver = header->ver; if (header->core != dsp->type) { cs_dsp_err(dsp, "%s: invalid core %d != %d\n", @@ -1779,7 +1779,7 @@ static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, list_add_tail(&alg_region->list, &dsp->alg_regions); - if (dsp->fw_ver > 0) + if (dsp->wmfw_ver > 0) cs_dsp_ctl_fixup_base(dsp, alg_region); return alg_region; @@ -1902,7 +1902,7 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) ret = PTR_ERR(alg_region); goto out; } - if (dsp->fw_ver == 0) { + if (dsp->wmfw_ver == 0) { if (i + 1 < n_algs) { len = be32_to_cpu(adsp1_alg[i + 1].dm); len -= be32_to_cpu(adsp1_alg[i].dm); @@ -1924,7 +1924,7 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) ret = PTR_ERR(alg_region); goto out; } - if (dsp->fw_ver == 0) { + if (dsp->wmfw_ver == 0) { if (i + 1 < n_algs) { len = be32_to_cpu(adsp1_alg[i + 1].zm); len -= be32_to_cpu(adsp1_alg[i].zm); @@ -2015,7 +2015,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) ret = PTR_ERR(alg_region); goto out; } - if (dsp->fw_ver == 0) { + if (dsp->wmfw_ver == 0) { if (i + 1 < n_algs) { len = be32_to_cpu(adsp2_alg[i + 1].xm); len -= be32_to_cpu(adsp2_alg[i].xm); @@ -2037,7 +2037,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) ret = PTR_ERR(alg_region); goto out; } - if (dsp->fw_ver == 0) { + if (dsp->wmfw_ver == 0) { if (i + 1 < n_algs) { len = be32_to_cpu(adsp2_alg[i + 1].ym); len -= be32_to_cpu(adsp2_alg[i].ym); @@ -2059,7 +2059,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) ret = PTR_ERR(alg_region); goto out; } - if (dsp->fw_ver == 0) { + if (dsp->wmfw_ver == 0) { if (i + 1 < n_algs) { len = be32_to_cpu(adsp2_alg[i + 1].zm); len -= be32_to_cpu(adsp2_alg[i].zm); diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index 8078dc377948..2e649810169f 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -167,7 +167,7 @@ struct cs_dsp { const struct cs_dsp_region *mem; int num_mems; - int fw_ver; + int wmfw_ver; bool booted; bool running; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 68d2d6444533..9f8549b34e30 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -601,7 +601,7 @@ static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl) return -EINVAL; } - switch (cs_dsp->fw_ver) { + switch (cs_dsp->wmfw_ver) { case 0: case 1: ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, From e021e0eecba99d7ec68f6e7972a72175f54ff6e3 Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Wed, 10 Jul 2024 00:12:25 +0530 Subject: [PATCH 333/349] ASoC: dt-bindings: cirrus,cs4270: Convert to dtschema Convert the Cirrus Logic CS4270 audio CODEC bindings to DT schema. Add missing va-supply, vd-supply and vlc-supply properties, because they are already being used in the DTS and the driver for this device. Cc: Daniel Baluta Signed-off-by: Animesh Agarwal Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240709184231.125207-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/cirrus,cs4270.yaml | 59 +++++++++++++++++++ .../devicetree/bindings/sound/cs4270.txt | 21 ------- 2 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml delete mode 100644 Documentation/devicetree/bindings/sound/cs4270.txt diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml new file mode 100644 index 000000000000..336e11773694 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs4270.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CS4270 audio CODEC + +maintainers: + - patches@opensource.cirrus.com + +description: + The CS4270 is a stereo audio codec. The driver for this device currently only + supports I2C. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: cirrus,cs4270 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + reset-gpios: + description: + This pin will be deasserted before communication to the codec starts. + maxItems: 1 + + va-supply: + description: Analog power supply. + + vd-supply: + description: Digital power supply. + + vlc-supply: + description: Serial Control Port power supply. + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@48 { + compatible = "cirrus,cs4270"; + reg = <0x48>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt deleted file mode 100644 index c33770ec4c3c..000000000000 --- a/Documentation/devicetree/bindings/sound/cs4270.txt +++ /dev/null @@ -1,21 +0,0 @@ -CS4270 audio CODEC - -The driver for this device currently only supports I2C. - -Required properties: - - - compatible : "cirrus,cs4270" - - - reg : the I2C address of the device for I2C - -Optional properties: - - - reset-gpios : a GPIO spec for the reset pin. If specified, it will be - deasserted before communication to the codec starts. - -Example: - -codec: cs4270@48 { - compatible = "cirrus,cs4270"; - reg = <0x48>; -}; From c62bec0fe36873ab6c87c9ae84a6b661d09244c4 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Wed, 10 Jul 2024 11:04:15 -0500 Subject: [PATCH 334/349] ASoC: cs530x: Calculate proper bclk rate using TDM Calculate the proper bclk rate using the number of tdm slots and the width of the tdm data. Fixes: 2884c29152c0 ("ASoC: cs530x: Support for cs530x ADCs") Signed-off-by: Paul Handrigan Link: https://lore.kernel.org/r/20240710160416.2617173-1-paulha@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x.c | 15 ++++++++++----- sound/soc/codecs/cs530x.h | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index 036d0f45e3ba..195739657f4e 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -526,13 +526,15 @@ static int cs530x_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(regmap, CS530X_CLK_CFG_1, CS530X_SAMPLE_RATE_MASK, fs_val); - if (cs530x->tdm_slots) { + + if (regmap_test_bits(regmap, CS530X_SIGNAL_PATH_CFG, + CS530X_TDM_EN_MASK)) { dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n", cs530x->tdm_slots, cs530x->tdm_width); - cs530x->bclk = snd_soc_calc_bclk(cs530x->fs, - cs530x->tdm_width, - params_channels(params), - cs530x->tdm_slots); + cs530x->bclk = snd_soc_tdm_params_to_bclk(params, + cs530x->tdm_width, + cs530x->tdm_slots, + 1); } else { cs530x->bclk = snd_soc_params_to_bclk(params); } @@ -655,6 +657,9 @@ static int cs530x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, return -EINVAL; } + cs530x->tdm_width = slot_width; + cs530x->tdm_slots = slots; + return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG, CS530X_ASP_TDM_SLOT_MASK, val << CS530X_ASP_TDM_SLOT_SHIFT); diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index 1c85310a5d03..1915a0efe829 100644 --- a/sound/soc/codecs/cs530x.h +++ b/sound/soc/codecs/cs530x.h @@ -96,6 +96,7 @@ #define CS530X_ASP_TDM_SLOT_MASK GENMASK(5, 3) #define CS530X_ASP_TDM_SLOT_SHIFT 3 #define CS530X_ASP_CH_REVERSE BIT(9) +#define CS530X_TDM_EN_MASK BIT(2) #define CS530X_ASP_FMT_I2S 0 #define CS530X_ASP_FMT_LJ 1 #define CS530X_ASP_FMT_DSP_A 0x6 From 0d1ebba74fad7b6b3eb0e2bc08d649d20c7aa7c9 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Wed, 10 Jul 2024 11:04:16 -0500 Subject: [PATCH 335/349] ASoC: cs530x: Remove bclk from private structure Remove the bclk int from the private structure and pass it into the set_bclk function. Signed-off-by: Paul Handrigan Link: https://lore.kernel.org/r/20240710160416.2617173-2-paulha@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x.c | 24 ++++++++++++------------ sound/soc/codecs/cs530x.h | 1 - 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index 195739657f4e..25a86a32e936 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -415,13 +415,13 @@ static void cs530x_add_34_adc_widgets(struct snd_soc_component *component) ARRAY_SIZE(adc_ch3_4_routes)); } -static int cs530x_set_bclk(struct snd_soc_component *component) +static int cs530x_set_bclk(struct snd_soc_component *component, const int freq) { struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); struct regmap *regmap = cs530x->regmap; unsigned int bclk_val; - switch (cs530x->bclk) { + switch (freq) { case 2822400: case 3072000: bclk_val = CS530X_BCLK_2P822_3P072; @@ -439,11 +439,11 @@ static int cs530x_set_bclk(struct snd_soc_component *component) bclk_val = CS530X_BCLK_24P5792_24P576; break; default: - dev_err(component->dev, "Invalid BCLK %d\n", cs530x->bclk); + dev_err(component->dev, "Invalid BCLK frequency %d\n", freq); return -EINVAL; } - dev_dbg(component->dev, "BCLK is %d\n", cs530x->bclk); + dev_dbg(component->dev, "BCLK frequency is %d\n", freq); return regmap_update_bits(regmap, CS530X_ASP_CFG, CS530X_ASP_BCLK_FREQ_MASK, bclk_val); @@ -489,7 +489,7 @@ static int cs530x_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); struct regmap *regmap = cs530x->regmap; - int ret = 0, fs = params_rate(params); + int ret = 0, fs = params_rate(params), bclk; unsigned int fs_val; @@ -531,22 +531,22 @@ static int cs530x_hw_params(struct snd_pcm_substream *substream, CS530X_TDM_EN_MASK)) { dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n", cs530x->tdm_slots, cs530x->tdm_width); - cs530x->bclk = snd_soc_tdm_params_to_bclk(params, - cs530x->tdm_width, - cs530x->tdm_slots, - 1); + bclk = snd_soc_tdm_params_to_bclk(params, + cs530x->tdm_width, + cs530x->tdm_slots, + 1); } else { - cs530x->bclk = snd_soc_params_to_bclk(params); + bclk = snd_soc_params_to_bclk(params); } if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0, CS530X_PLL_REFCLK_SRC_MASK)) { - ret = cs530x_set_pll_refclk(component, cs530x->bclk); + ret = cs530x_set_pll_refclk(component, bclk); if (ret) return ret; } - return cs530x_set_bclk(component); + return cs530x_set_bclk(component, bclk); } static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index 1915a0efe829..f473e33eb835 100644 --- a/sound/soc/codecs/cs530x.h +++ b/sound/soc/codecs/cs530x.h @@ -211,7 +211,6 @@ struct cs530x_priv { int tdm_width; int tdm_slots; - int bclk; int fs; int adc_pairs_count; From e3fff693da9fa0337d98dab496db3a04c5227aae Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Wed, 10 Jul 2024 12:57:52 +0530 Subject: [PATCH 336/349] ASoC: dt-bindings: cirrus,cs42xx8: Convert to dtschema Convert the Cirrus Logic CS42448/CS42888 audio CODEC bindings to DT schema format. Set power supply properties to required only for CS42888. Cc: Daniel Baluta Signed-off-by: Animesh Agarwal Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240710072756.99765-1-animeshagarwal28@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/cirrus,cs42xx8.yaml | 81 +++++++++++++++++++ .../devicetree/bindings/sound/cs42xx8.txt | 34 -------- 2 files changed, 81 insertions(+), 34 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml delete mode 100644 Documentation/devicetree/bindings/sound/cs42xx8.txt diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml new file mode 100644 index 000000000000..725b47e82062 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs42xx8.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CS42448/CS42888 audio CODEC + +maintainers: + - patches@opensource.cirrus.com + +properties: + compatible: + enum: + - cirrus,cs42448 + - cirrus,cs42888 + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + const: mclk + + VA-supply: + description: Analog power supply. + + VD-supply: + description: Digital power supply. + + VLC-supply: + description: Control port power supply + + VLS-supply: + description: Serial port interface power supply. + + reset-gpios: + description: This pin is connected to the chip's RESET pin. + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + +if: + properties: + compatible: + contains: + const: cirrus,cs42888 +then: + required: + - VA-supply + - VD-supply + - VLC-supply + - VLS-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@48 { + compatible = "cirrus,cs42888"; + reg = <0x48>; + clocks = <&codec_mclk 0>; + clock-names = "mclk"; + VA-supply = <®_audio>; + VD-supply = <®_audio>; + VLS-supply = <®_audio>; + VLC-supply = <®_audio>; + reset-gpios = <&gpio 1>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/cs42xx8.txt b/Documentation/devicetree/bindings/sound/cs42xx8.txt deleted file mode 100644 index bbfe39347c20..000000000000 --- a/Documentation/devicetree/bindings/sound/cs42xx8.txt +++ /dev/null @@ -1,34 +0,0 @@ -CS42448/CS42888 audio CODEC - -Required properties: - - - compatible : must contain one of "cirrus,cs42448" and "cirrus,cs42888" - - - reg : the I2C address of the device for I2C - - - clocks : a list of phandles + clock-specifiers, one for each entry in - clock-names - - - clock-names : must contain "mclk" - - - VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device, - as covered in Documentation/devicetree/bindings/regulator/regulator.txt - -Optional properties: - - - reset-gpios : a GPIO spec to define which pin is connected to the chip's - !RESET pin - -Example: - -cs42888: codec@48 { - compatible = "cirrus,cs42888"; - reg = <0x48>; - clocks = <&codec_mclk 0>; - clock-names = "mclk"; - VA-supply = <®_audio>; - VD-supply = <®_audio>; - VLS-supply = <®_audio>; - VLC-supply = <®_audio>; - reset-gpios = <&pca9557_b 1 GPIO_ACTIVE_LOW>; -}; From 0ffc5a40ad21996c1c4b1d8a636c9051ea41a76e Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Thu, 4 Jul 2024 13:47:21 +0530 Subject: [PATCH 337/349] ASoC: codecs: wcd937x-sdw: Fix Unbalanced pm_runtime_enable Fix the unbalanced pm_runtime_enable! in wcd937x-sdw soundwire slave. Fixes: c99a515ff153 ("ASoC: codecs: wcd937x-sdw: add SoundWire driver") Signed-off-by: Mohammad Rafi Shaik Link: https://patch.msgid.link/20240704081723.3394153-2-quic_mohs@quicinc.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x-sdw.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c index a24d6c620dba..3abc8041406a 100644 --- a/sound/soc/codecs/wcd937x-sdw.c +++ b/sound/soc/codecs/wcd937x-sdw.c @@ -1067,13 +1067,15 @@ static int wcd9370_probe(struct sdw_slave *pdev, wcd->ch_info = &wcd937x_sdw_rx_ch_info[0]; } - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - return component_add(dev, &wcd937x_sdw_component_ops); + ret = component_add(dev, &wcd937x_sdw_component_ops); + if (ret) + return ret; + + /* Set suspended until aggregate device is bind */ + pm_runtime_set_suspended(dev); + + return 0; } static int wcd9370_remove(struct sdw_slave *pdev) @@ -1082,10 +1084,6 @@ static int wcd9370_remove(struct sdw_slave *pdev) component_del(dev, &wcd937x_sdw_component_ops); - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - pm_runtime_dont_use_autosuspend(dev); - return 0; } From a5f727f423101efd60a27bccd7680df429cef38a Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Thu, 4 Jul 2024 13:47:22 +0530 Subject: [PATCH 338/349] ASoC: codecs: wcd937x: Remove the string compare in MIC BIAS widget settings Remove the string compare with widget name in MIC BIAS settings, instead of string compare use the MIC BIAS id's. Reported-by: Srinivas Kandagatla Closes: https://lore.kernel.org/linux-sound/ba911ebd-aef5-46af-ace1-84d13bee6876@linaro.org/ Signed-off-by: Mohammad Rafi Shaik Link: https://patch.msgid.link/20240704081723.3394153-3-quic_mohs@quicinc.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 4beb70bc4d8c..94282499fa33 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -1164,16 +1164,7 @@ static int __wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - int micb_num; - - if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) - micb_num = MIC_BIAS_1; - else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) - micb_num = MIC_BIAS_2; - else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) - micb_num = MIC_BIAS_3; - else - return -EINVAL; + int micb_num = w->shift; switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1203,16 +1194,7 @@ static int __wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - int micb_num; - - if (strnstr(w->name, "VA MIC BIAS1", sizeof("VA MIC BIAS1"))) - micb_num = MIC_BIAS_1; - else if (strnstr(w->name, "VA MIC BIAS2", sizeof("VA MIC BIAS2"))) - micb_num = MIC_BIAS_2; - else if (strnstr(w->name, "VA MIC BIAS3", sizeof("VA MIC BIAS3"))) - micb_num = MIC_BIAS_3; - else - return -EINVAL; + int micb_num = w->shift; switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -2231,15 +2213,15 @@ static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { SND_SOC_DAPM_POST_PMD), /* MIC_BIAS widgets */ - SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, wcd937x_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, wcd937x_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, wcd937x_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), @@ -2320,15 +2302,15 @@ static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("HPHR"), /* MIC_BIAS pull up widgets */ - SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, wcd937x_codec_enable_micbias_pullup, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, wcd937x_codec_enable_micbias_pullup, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, wcd937x_codec_enable_micbias_pullup, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), From 216d04139a6d0ecaea9432178225b29d367da886 Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Thu, 4 Jul 2024 13:47:23 +0530 Subject: [PATCH 339/349] ASoC: codecs: wcd937x: Remove separate handling for vdd-buck supply Remove separate handling for vdd-buck regulator supply which is not required. The vdd-buck regulator supply enabled using bulk enable. Add the error handling in wcd937x_probe() and disable the regulators in error case. Reported-by: Christophe JAILLET Closes: https://lore.kernel.org/linux-sound/834d31cc-f4bc-4db7-a25b-f9869e550eb6@wanadoo.fr/ Signed-off-by: Mohammad Rafi Shaik Link: https://patch.msgid.link/20240704081723.3394153-4-quic_mohs@quicinc.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 61 ++++++++------------------------------ sound/soc/codecs/wcd937x.h | 2 +- 2 files changed, 14 insertions(+), 49 deletions(-) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 94282499fa33..13926f4b0d9f 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -869,37 +869,6 @@ static int wcd937x_enable_rx3(struct snd_soc_dapm_widget *w, return 0; } -static int wcd937x_codec_enable_vdd_buck(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); - int ret = 0; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - if (test_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask)) { - dev_err(component->dev, "buck already in enabled state\n"); - clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); - return 0; - } - ret = regulator_enable(wcd937x->buck_supply); - if (ret) { - dev_err(component->dev, "VDD_BUCK is not enabled\n"); - return ret; - } - clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); - usleep_range(200, 250); - break; - case SND_SOC_DAPM_POST_PMD: - set_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); - break; - } - - return 0; -} - static int wcd937x_get_micb_vout_ctl_val(u32 micb_mv) { if (micb_mv < 1000 || micb_mv > 2850) { @@ -2226,10 +2195,7 @@ static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, - wcd937x_codec_enable_vdd_buck, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - + SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0), /* RX widgets */ @@ -2915,24 +2881,17 @@ static int wcd937x_probe(struct platform_device *pdev) wcd937x->supplies[0].supply = "vdd-rxtx"; wcd937x->supplies[1].supply = "vdd-px"; wcd937x->supplies[2].supply = "vdd-mic-bias"; + wcd937x->supplies[3].supply = "vdd-buck"; ret = devm_regulator_bulk_get(dev, WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); if (ret) return dev_err_probe(dev, ret, "Failed to get supplies\n"); ret = regulator_bulk_enable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - if (ret) + if (ret) { + regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); return dev_err_probe(dev, ret, "Failed to enable supplies\n"); - - /* Get the buck separately, as it needs special handling */ - wcd937x->buck_supply = devm_regulator_get(dev, "vdd-buck"); - if (IS_ERR(wcd937x->buck_supply)) - return dev_err_probe(dev, PTR_ERR(wcd937x->buck_supply), - "Failed to get buck supply\n"); - - ret = regulator_enable(wcd937x->buck_supply); - if (ret) - return dev_err_probe(dev, ret, "Failed to enable buck supply\n"); + } wcd937x_dt_parse_micbias_info(dev, wcd937x); @@ -2949,13 +2908,13 @@ static int wcd937x_probe(struct platform_device *pdev) ret = wcd937x_add_slave_components(wcd937x, dev, &match); if (ret) - return ret; + goto err_disable_regulators; wcd937x_reset(wcd937x); ret = component_master_add_with_match(dev, &wcd937x_comp_ops, match); if (ret) - return ret; + goto err_disable_regulators; pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); @@ -2964,6 +2923,12 @@ static int wcd937x_probe(struct platform_device *pdev) pm_runtime_enable(dev); pm_runtime_idle(dev); + return 0; + +err_disable_regulators: + regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + return ret; } diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h index f267c66ca959..37bff16e88dd 100644 --- a/sound/soc/codecs/wcd937x.h +++ b/sound/soc/codecs/wcd937x.h @@ -483,7 +483,7 @@ #define WCD937X_MAX_REGISTER (WCD937X_DIGITAL_EFUSE_REG_31) #define WCD937X_MAX_MICBIAS 3 -#define WCD937X_MAX_BULK_SUPPLY 3 +#define WCD937X_MAX_BULK_SUPPLY 4 #define WCD937X_MAX_TX_SWR_PORTS 4 #define WCD937X_MAX_SWR_PORTS 5 #define WCD937X_MAX_SWR_CH_IDS 15 From 75ed63a5ab5d1d2872c735bc7edf8fef0e2fa2ea Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Wed, 10 Jul 2024 14:42:37 +0800 Subject: [PATCH 340/349] ASoC: tas2781: Add new Kontrol to set tas2563 digital Volume Requriment from customer to add new kcontrol to set tas2563 digital Volume Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20240710064238.1480-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- include/sound/tas2781-tlv.h | 262 ++++++++++++++++++++++++++++++++- include/sound/tas2781.h | 1 + sound/soc/codecs/tas2781-i2c.c | 129 ++++++++++++++-- 3 files changed, 382 insertions(+), 10 deletions(-) diff --git a/include/sound/tas2781-tlv.h b/include/sound/tas2781-tlv.h index 1dc59005d241..99c41bfc7827 100644 --- a/include/sound/tas2781-tlv.h +++ b/include/sound/tas2781-tlv.h @@ -2,7 +2,7 @@ // // ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier // -// Copyright (C) 2022 - 2023 Texas Instruments Incorporated +// Copyright (C) 2022 - 2024 Texas Instruments Incorporated // https://www.ti.com // // The TAS2781 driver implements a flexible and configurable @@ -17,5 +17,265 @@ static const __maybe_unused DECLARE_TLV_DB_SCALE(dvc_tlv, -10000, 100, 0); static const DECLARE_TLV_DB_SCALE(amp_vol_tlv, 1100, 50, 0); +static const DECLARE_TLV_DB_SCALE(tas2563_dvc_tlv, -12150, 50, 1); +/* pow(10, db/20) * pow(2,30) */ +static const unsigned char tas2563_dvc_table[][4] = { + { 0X00, 0X00, 0X00, 0X00 }, /* -121.5db */ + { 0X00, 0X00, 0X03, 0XBC }, /* -121.0db */ + { 0X00, 0X00, 0X03, 0XF5 }, /* -120.5db */ + { 0X00, 0X00, 0X04, 0X31 }, /* -120.0db */ + { 0X00, 0X00, 0X04, 0X71 }, /* -119.5db */ + { 0X00, 0X00, 0X04, 0XB4 }, /* -119.0db */ + { 0X00, 0X00, 0X04, 0XFC }, /* -118.5db */ + { 0X00, 0X00, 0X05, 0X47 }, /* -118.0db */ + { 0X00, 0X00, 0X05, 0X97 }, /* -117.5db */ + { 0X00, 0X00, 0X05, 0XEC }, /* -117.0db */ + { 0X00, 0X00, 0X06, 0X46 }, /* -116.5db */ + { 0X00, 0X00, 0X06, 0XA5 }, /* -116.0db */ + { 0X00, 0X00, 0X07, 0X0A }, /* -115.5db */ + { 0X00, 0X00, 0X07, 0X75 }, /* -115.0db */ + { 0X00, 0X00, 0X07, 0XE6 }, /* -114.5db */ + { 0X00, 0X00, 0X08, 0X5E }, /* -114.0db */ + { 0X00, 0X00, 0X08, 0XDD }, /* -113.5db */ + { 0X00, 0X00, 0X09, 0X63 }, /* -113.0db */ + { 0X00, 0X00, 0X09, 0XF2 }, /* -112.5db */ + { 0X00, 0X00, 0X0A, 0X89 }, /* -112.0db */ + { 0X00, 0X00, 0X0B, 0X28 }, /* -111.5db */ + { 0X00, 0X00, 0X0B, 0XD2 }, /* -111.0db */ + { 0X00, 0X00, 0X0C, 0X85 }, /* -110.5db */ + { 0X00, 0X00, 0X0D, 0X43 }, /* -110.0db */ + { 0X00, 0X00, 0X0E, 0X0C }, /* -109.5db */ + { 0X00, 0X00, 0X0E, 0XE1 }, /* -109.0db */ + { 0X00, 0X00, 0X0F, 0XC3 }, /* -108.5db */ + { 0X00, 0X00, 0X10, 0XB2 }, /* -108.0db */ + { 0X00, 0X00, 0X11, 0XAF }, /* -107.5db */ + { 0X00, 0X00, 0X12, 0XBC }, /* -107.0db */ + { 0X00, 0X00, 0X13, 0XD8 }, /* -106.5db */ + { 0X00, 0X00, 0X15, 0X05 }, /* -106.0db */ + { 0X00, 0X00, 0X16, 0X44 }, /* -105.5db */ + { 0X00, 0X00, 0X17, 0X96 }, /* -105.0db */ + { 0X00, 0X00, 0X18, 0XFB }, /* -104.5db */ + { 0X00, 0X00, 0X1A, 0X76 }, /* -104.0db */ + { 0X00, 0X00, 0X1C, 0X08 }, /* -103.5db */ + { 0X00, 0X00, 0X1D, 0XB1 }, /* -103.0db */ + { 0X00, 0X00, 0X1F, 0X73 }, /* -102.5db */ + { 0X00, 0X00, 0X21, 0X51 }, /* -102.0db */ + { 0X00, 0X00, 0X23, 0X4A }, /* -101.5db */ + { 0X00, 0X00, 0X25, 0X61 }, /* -101.0db */ + { 0X00, 0X00, 0X27, 0X98 }, /* -100.5db */ + { 0X00, 0X00, 0X29, 0XF1 }, /* -100.0db */ + { 0X00, 0X00, 0X2C, 0X6D }, /* -99.5db */ + { 0X00, 0X00, 0X2F, 0X0F }, /* -99.0db */ + { 0X00, 0X00, 0X31, 0XD9 }, /* -98.5db */ + { 0X00, 0X00, 0X34, 0XCD }, /* -98.0db */ + { 0X00, 0X00, 0X37, 0XEE }, /* -97.5db */ + { 0X00, 0X00, 0X3B, 0X3F }, /* -97.0db */ + { 0X00, 0X00, 0X3E, 0XC1 }, /* -96.5db */ + { 0X00, 0X00, 0X42, 0X79 }, /* -96.0db */ + { 0X00, 0X00, 0X46, 0X6A }, /* -95.5db */ + { 0X00, 0X00, 0X4A, 0X96 }, /* -95.0db */ + { 0X00, 0X00, 0X4F, 0X01 }, /* -94.5db */ + { 0X00, 0X00, 0X53, 0XAF }, /* -94.0db */ + { 0X00, 0X00, 0X58, 0XA5 }, /* -93.5db */ + { 0X00, 0X00, 0X5D, 0XE6 }, /* -93.0db */ + { 0X00, 0X00, 0X63, 0X76 }, /* -92.5db */ + { 0X00, 0X00, 0X69, 0X5B }, /* -92.0db */ + { 0X00, 0X00, 0X6F, 0X99 }, /* -91.5db */ + { 0X00, 0X00, 0X76, 0X36 }, /* -91.0db */ + { 0X00, 0X00, 0X7D, 0X37 }, /* -90.5db */ + { 0X00, 0X00, 0X84, 0XA2 }, /* -90.0db */ + { 0X00, 0X00, 0X8C, 0X7E }, /* -89.5db */ + { 0X00, 0X00, 0X94, 0XD1 }, /* -89.0db */ + { 0X00, 0X00, 0X9D, 0XA3 }, /* -88.5db */ + { 0X00, 0X00, 0XA6, 0XFA }, /* -88.0db */ + { 0X00, 0X00, 0XB0, 0XDF }, /* -87.5db */ + { 0X00, 0X00, 0XBB, 0X5A }, /* -87.0db */ + { 0X00, 0X00, 0XC6, 0X74 }, /* -86.5db */ + { 0X00, 0X00, 0XD2, 0X36 }, /* -86.0db */ + { 0X00, 0X00, 0XDE, 0XAB }, /* -85.5db */ + { 0X00, 0X00, 0XEB, 0XDC }, /* -85.0db */ + { 0X00, 0X00, 0XF9, 0XD6 }, /* -84.5db */ + { 0X00, 0X01, 0X08, 0XA4 }, /* -84.0db */ + { 0X00, 0X01, 0X18, 0X52 }, /* -83.5db */ + { 0X00, 0X01, 0X28, 0XEF }, /* -83.0db */ + { 0X00, 0X01, 0X3A, 0X87 }, /* -82.5db */ + { 0X00, 0X01, 0X4D, 0X2A }, /* -82.0db */ + { 0X00, 0X01, 0X60, 0XE8 }, /* -81.5db */ + { 0X00, 0X01, 0X75, 0XD1 }, /* -81.0db */ + { 0X00, 0X01, 0X8B, 0XF7 }, /* -80.5db */ + { 0X00, 0X01, 0XA3, 0X6E }, /* -80.0db */ + { 0X00, 0X01, 0XBC, 0X48 }, /* -79.5db */ + { 0X00, 0X01, 0XD6, 0X9B }, /* -79.0db */ + { 0X00, 0X01, 0XF2, 0X7E }, /* -78.5db */ + { 0X00, 0X02, 0X10, 0X08 }, /* -78.0db */ + { 0X00, 0X02, 0X2F, 0X51 }, /* -77.5db */ + { 0X00, 0X02, 0X50, 0X76 }, /* -77.0db */ + { 0X00, 0X02, 0X73, 0X91 }, /* -76.5db */ + { 0X00, 0X02, 0X98, 0XC0 }, /* -76.0db */ + { 0X00, 0X02, 0XC0, 0X24 }, /* -75.5db */ + { 0X00, 0X02, 0XE9, 0XDD }, /* -75.0db */ + { 0X00, 0X03, 0X16, 0X0F }, /* -74.5db */ + { 0X00, 0X03, 0X44, 0XDF }, /* -74.0db */ + { 0X00, 0X03, 0X76, 0X76 }, /* -73.5db */ + { 0X00, 0X03, 0XAA, 0XFC }, /* -73.0db */ + { 0X00, 0X03, 0XE2, 0XA0 }, /* -72.5db */ + { 0X00, 0X04, 0X1D, 0X8F }, /* -72.0db */ + { 0X00, 0X04, 0X5B, 0XFD }, /* -71.5db */ + { 0X00, 0X04, 0X9E, 0X1D }, /* -71.0db */ + { 0X00, 0X04, 0XE4, 0X29 }, /* -70.5db */ + { 0X00, 0X05, 0X2E, 0X5A }, /* -70.0db */ + { 0X00, 0X05, 0X7C, 0XF2 }, /* -69.5db */ + { 0X00, 0X05, 0XD0, 0X31 }, /* -69.0db */ + { 0X00, 0X06, 0X28, 0X60 }, /* -68.5db */ + { 0X00, 0X06, 0X85, 0XC8 }, /* -68.0db */ + { 0X00, 0X06, 0XE8, 0XB9 }, /* -67.5db */ + { 0X00, 0X07, 0X51, 0X86 }, /* -67.0db */ + { 0X00, 0X07, 0XC0, 0X8A }, /* -66.5db */ + { 0X00, 0X08, 0X36, 0X21 }, /* -66.0db */ + { 0X00, 0X08, 0XB2, 0XB0 }, /* -65.5db */ + { 0X00, 0X09, 0X36, 0XA1 }, /* -65.0db */ + { 0X00, 0X09, 0XC2, 0X63 }, /* -64.5db */ + { 0X00, 0X0A, 0X56, 0X6D }, /* -64.0db */ + { 0X00, 0X0A, 0XF3, 0X3C }, /* -63.5db */ + { 0X00, 0X0B, 0X99, 0X56 }, /* -63.0db */ + { 0X00, 0X0C, 0X49, 0X48 }, /* -62.5db */ + { 0X00, 0X0D, 0X03, 0XA7 }, /* -62.0db */ + { 0X00, 0X0D, 0XC9, 0X11 }, /* -61.5db */ + { 0X00, 0X0E, 0X9A, 0X2D }, /* -61.0db */ + { 0X00, 0X0F, 0X77, 0XAD }, /* -60.5db */ + { 0X00, 0X10, 0X62, 0X4D }, /* -60.0db */ + { 0X00, 0X11, 0X5A, 0XD5 }, /* -59.5db */ + { 0X00, 0X12, 0X62, 0X16 }, /* -59.0db */ + { 0X00, 0X13, 0X78, 0XF0 }, /* -58.5db */ + { 0X00, 0X14, 0XA0, 0X50 }, /* -58.0db */ + { 0X00, 0X15, 0XD9, 0X31 }, /* -57.5db */ + { 0X00, 0X17, 0X24, 0X9C }, /* -57.0db */ + { 0X00, 0X18, 0X83, 0XAA }, /* -56.5db */ + { 0X00, 0X19, 0XF7, 0X86 }, /* -56.0db */ + { 0X00, 0X1B, 0X81, 0X6A }, /* -55.5db */ + { 0X00, 0X1D, 0X22, 0XA4 }, /* -55.0db */ + { 0X00, 0X1E, 0XDC, 0X98 }, /* -54.5db */ + { 0X00, 0X20, 0XB0, 0XBC }, /* -54.0db */ + { 0X00, 0X22, 0XA0, 0X9D }, /* -53.5db */ + { 0X00, 0X24, 0XAD, 0XE0 }, /* -53.0db */ + { 0X00, 0X26, 0XDA, 0X43 }, /* -52.5db */ + { 0X00, 0X29, 0X27, 0X9D }, /* -52.0db */ + { 0X00, 0X2B, 0X97, 0XE3 }, /* -51.5db */ + { 0X00, 0X2E, 0X2D, 0X27 }, /* -51.0db */ + { 0X00, 0X30, 0XE9, 0X9A }, /* -50.5db */ + { 0X00, 0X33, 0XCF, 0X8D }, /* -50.0db */ + { 0X00, 0X36, 0XE1, 0X78 }, /* -49.5db */ + { 0X00, 0X3A, 0X21, 0XF3 }, /* -49.0db */ + { 0X00, 0X3D, 0X93, 0XC3 }, /* -48.5db */ + { 0X00, 0X41, 0X39, 0XD3 }, /* -48.0db */ + { 0X00, 0X45, 0X17, 0X3B }, /* -47.5db */ + { 0X00, 0X49, 0X2F, 0X44 }, /* -47.0db */ + { 0X00, 0X4D, 0X85, 0X66 }, /* -46.5db */ + { 0X00, 0X52, 0X1D, 0X50 }, /* -46.0db */ + { 0X00, 0X56, 0XFA, 0XE8 }, /* -45.5db */ + { 0X00, 0X5C, 0X22, 0X4E }, /* -45.0db */ + { 0X00, 0X61, 0X97, 0XE1 }, /* -44.5db */ + { 0X00, 0X67, 0X60, 0X44 }, /* -44.0db */ + { 0X00, 0X6D, 0X80, 0X60 }, /* -43.5db */ + { 0X00, 0X73, 0XFD, 0X65 }, /* -43.0db */ + { 0X00, 0X7A, 0XDC, 0XD7 }, /* -42.5db */ + { 0X00, 0X82, 0X24, 0X8A }, /* -42.0db */ + { 0X00, 0X89, 0XDA, 0XAB }, /* -41.5db */ + { 0X00, 0X92, 0X05, 0XC6 }, /* -41.0db */ + { 0X00, 0X9A, 0XAC, 0XC8 }, /* -40.5db */ + { 0X00, 0XA3, 0XD7, 0X0A }, /* -40.0db */ + { 0X00, 0XAD, 0X8C, 0X52 }, /* -39.5db */ + { 0X00, 0XB7, 0XD4, 0XDD }, /* -39.0db */ + { 0X00, 0XC2, 0XB9, 0X65 }, /* -38.5db */ + { 0X00, 0XCE, 0X43, 0X28 }, /* -38.0db */ + { 0X00, 0XDA, 0X7B, 0XF1 }, /* -37.5db */ + { 0X00, 0XE7, 0X6E, 0X1E }, /* -37.0db */ + { 0X00, 0XF5, 0X24, 0XAC }, /* -36.5db */ + { 0X01, 0X03, 0XAB, 0X3D }, /* -36.0db */ + { 0X01, 0X13, 0X0E, 0X24 }, /* -35.5db */ + { 0X01, 0X23, 0X5A, 0X71 }, /* -35.0db */ + { 0X01, 0X34, 0X9D, 0XF8 }, /* -34.5db */ + { 0X01, 0X46, 0XE7, 0X5D }, /* -34.0db */ + { 0X01, 0X5A, 0X46, 0X27 }, /* -33.5db */ + { 0X01, 0X6E, 0XCA, 0XC5 }, /* -33.0db */ + { 0X01, 0X84, 0X86, 0X9F }, /* -32.5db */ + { 0X01, 0X9B, 0X8C, 0X27 }, /* -32.0db */ + { 0X01, 0XB3, 0XEE, 0XE5 }, /* -31.5db */ + { 0X01, 0XCD, 0XC3, 0X8C }, /* -31.0db */ + { 0X01, 0XE9, 0X20, 0X05 }, /* -30.5db */ + { 0X02, 0X06, 0X1B, 0X89 }, /* -30.0db */ + { 0X02, 0X24, 0XCE, 0XB0 }, /* -29.5db */ + { 0X02, 0X45, 0X53, 0X85 }, /* -29.0db */ + { 0X02, 0X67, 0XC5, 0XA2 }, /* -28.5db */ + { 0X02, 0X8C, 0X42, 0X3F }, /* -28.0db */ + { 0X02, 0XB2, 0XE8, 0X55 }, /* -27.5db */ + { 0X02, 0XDB, 0XD8, 0XAD }, /* -27.0db */ + { 0X03, 0X07, 0X36, 0X05 }, /* -26.5db */ + { 0X03, 0X35, 0X25, 0X29 }, /* -26.0db */ + { 0X03, 0X65, 0XCD, 0X13 }, /* -25.5db */ + { 0X03, 0X99, 0X57, 0X0C }, /* -25.0db */ + { 0X03, 0XCF, 0XEE, 0XCF }, /* -24.5db */ + { 0X04, 0X09, 0XC2, 0XB0 }, /* -24.0db */ + { 0X04, 0X47, 0X03, 0XC1 }, /* -23.5db */ + { 0X04, 0X87, 0XE5, 0XFB }, /* -23.0db */ + { 0X04, 0XCC, 0XA0, 0X6D }, /* -22.5db */ + { 0X05, 0X15, 0X6D, 0X68 }, /* -22.0db */ + { 0X05, 0X62, 0X8A, 0XB3 }, /* -21.5db */ + { 0X05, 0XB4, 0X39, 0XBC }, /* -21.0db */ + { 0X06, 0X0A, 0XBF, 0XD4 }, /* -20.5db */ + { 0X06, 0X66, 0X66, 0X66 }, /* -20.0db */ + { 0X06, 0XC7, 0X7B, 0X36 }, /* -19.5db */ + { 0X07, 0X2E, 0X50, 0XA6 }, /* -19.0db */ + { 0X07, 0X9B, 0X3D, 0XF6 }, /* -18.5db */ + { 0X08, 0X0E, 0X9F, 0X96 }, /* -18.0db */ + { 0X08, 0X88, 0XD7, 0X6D }, /* -17.5db */ + { 0X09, 0X0A, 0X4D, 0X2F }, /* -17.0db */ + { 0X09, 0X93, 0X6E, 0XB8 }, /* -16.5db */ + { 0X0A, 0X24, 0XB0, 0X62 }, /* -16.0db */ + { 0X0A, 0XBE, 0X8D, 0X70 }, /* -15.5db */ + { 0X0B, 0X61, 0X88, 0X71 }, /* -15.0db */ + { 0X0C, 0X0E, 0X2B, 0XB0 }, /* -14.5db */ + { 0X0C, 0XC5, 0X09, 0XAB }, /* -14.0db */ + { 0X0D, 0X86, 0XBD, 0X8D }, /* -13.5db */ + { 0X0E, 0X53, 0XEB, 0XB3 }, /* -13.0db */ + { 0X0F, 0X2D, 0X42, 0X38 }, /* -12.5db */ + { 0X10, 0X13, 0X79, 0X87 }, /* -12.0db */ + { 0X11, 0X07, 0X54, 0XF9 }, /* -11.5db */ + { 0X12, 0X09, 0XA3, 0X7A }, /* -11.0db */ + { 0X13, 0X1B, 0X40, 0X39 }, /* -10.5db */ + { 0X14, 0X3D, 0X13, 0X62 }, /* -10.0db */ + { 0X15, 0X70, 0X12, 0XE1 }, /* -9.5db */ + { 0X16, 0XB5, 0X43, 0X37 }, /* -9.0db */ + { 0X18, 0X0D, 0XB8, 0X54 }, /* -8.5db */ + { 0X19, 0X7A, 0X96, 0X7F }, /* -8.0db */ + { 0X1A, 0XFD, 0X13, 0X54 }, /* -7.5db */ + { 0X1C, 0X96, 0X76, 0XC6 }, /* -7.0db */ + { 0X1E, 0X48, 0X1C, 0X37 }, /* -6.5db */ + { 0X20, 0X13, 0X73, 0X9E }, /* -6.0db */ + { 0X21, 0XFA, 0X02, 0XBF }, /* -5.5db */ + { 0X23, 0XFD, 0X66, 0X78 }, /* -5.0db */ + { 0X26, 0X1F, 0X54, 0X1C }, /* -4.5db */ + { 0X28, 0X61, 0X9A, 0XE9 }, /* -4.0db */ + { 0X2A, 0XC6, 0X25, 0X91 }, /* -3.5db */ + { 0X2D, 0X4E, 0XFB, 0XD5 }, /* -3.0db */ + { 0X2F, 0XFE, 0X44, 0X48 }, /* -2.5db */ + { 0X32, 0XD6, 0X46, 0X17 }, /* -2.0db */ + { 0X35, 0XD9, 0X6B, 0X02 }, /* -1.5db */ + { 0X39, 0X0A, 0X41, 0X5F }, /* -1.0db */ + { 0X3C, 0X6B, 0X7E, 0X4F }, /* -0.5db */ + { 0X40, 0X00, 0X00, 0X00 }, /* 0.0db */ + { 0X43, 0XCA, 0XD0, 0X22 }, /* 0.5db */ + { 0X47, 0XCF, 0X26, 0X7D }, /* 1.0db */ + { 0X4C, 0X10, 0X6B, 0XA5 }, /* 1.5db */ + { 0X50, 0X92, 0X3B, 0XE3 }, /* 2.0db */ + { 0X55, 0X58, 0X6A, 0X46 }, /* 2.5db */ + { 0X5A, 0X67, 0X03, 0XDF }, /* 3.0db */ + { 0X5F, 0XC2, 0X53, 0X32 }, /* 3.5db */ + { 0X65, 0X6E, 0XE3, 0XDB }, /* 4.0db */ + { 0X6B, 0X71, 0X86, 0X68 }, /* 4.5db */ + { 0X71, 0XCF, 0X54, 0X71 }, /* 5.0db */ + { 0X78, 0X8D, 0XB4, 0XE9 }, /* 5.5db */ + { 0XFF, 0XFF, 0XFF, 0XFF }, /* 6.0db */ +}; #endif diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index a43ad6dcb7c7..18161d02a96f 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -50,6 +50,7 @@ #define TASDEVICE_I2CChecksum TASDEVICE_REG(0x0, 0x0, 0x7E) /* Volume control */ +#define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0C) #define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1A) #define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03) #define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1) diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index d5d95ae57c73..e79d613745b4 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -31,6 +31,7 @@ #include #include #include +#include static const struct i2c_device_id tasdevice_id[] = { { "tas2563", TAS2563 }, @@ -140,6 +141,101 @@ static int tasdev_force_fwload_put(struct snd_kcontrol *kcontrol, return change; } +static int tas2563_digital_gain_get( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec); + unsigned int l = 0, r = mc->max; + unsigned int target, ar_mid, mid, ar_l, ar_r; + unsigned int reg = mc->reg; + unsigned char data[4]; + int ret; + + mutex_lock(&tas_dev->codec_lock); + /* Read the primary device */ + ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); + if (ret) { + dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); + goto out; + } + + target = get_unaligned_be32(&data[0]); + + while (r > 1 + l) { + mid = (l + r) / 2; + ar_mid = get_unaligned_be32(tas2563_dvc_table[mid]); + if (target < ar_mid) + r = mid; + else + l = mid; + } + + ar_l = get_unaligned_be32(tas2563_dvc_table[l]); + ar_r = get_unaligned_be32(tas2563_dvc_table[r]); + + /* find out the member same as or closer to the current volume */ + ucontrol->value.integer.value[0] = + abs(target - ar_l) <= abs(target - ar_r) ? l : r; +out: + mutex_unlock(&tas_dev->codec_lock); + return 0; +} + +static int tas2563_digital_gain_put( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec); + int vol = ucontrol->value.integer.value[0]; + int status = 0, max = mc->max, rc = 1; + int i, ret; + unsigned int reg = mc->reg; + unsigned int volrd, volwr; + unsigned char data[4]; + + vol = clamp(vol, 0, max); + mutex_lock(&tas_dev->codec_lock); + /* Read the primary device */ + ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); + if (ret) { + dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); + rc = -1; + goto out; + } + + volrd = get_unaligned_be32(&data[0]); + volwr = get_unaligned_be32(tas2563_dvc_table[vol]); + + if (volrd == volwr) { + rc = 0; + goto out; + } + + for (i = 0; i < tas_dev->ndev; i++) { + ret = tasdevice_dev_bulk_write(tas_dev, i, reg, + (unsigned char *)tas2563_dvc_table[vol], 4); + if (ret) { + dev_err(tas_dev->dev, + "%s, set digital vol error in dev %d\n", + __func__, i); + status |= BIT(i); + } + } + + if (status) + rc = -1; +out: + mutex_unlock(&tas_dev->codec_lock); + return rc; +} + static const struct snd_kcontrol_new tasdevice_snd_controls[] = { SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, tasdev_force_fwload_get, tasdev_force_fwload_put), @@ -154,6 +250,13 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = { tas2781_digital_putvol, dvc_tlv), }; +static const struct snd_kcontrol_new tas2563_snd_controls[] = { + SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2563_DVC_LVL, 0, + 0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0, + tas2563_digital_gain_get, tas2563_digital_gain_put, + tas2563_dvc_tlv), +}; + static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -593,17 +696,25 @@ static struct snd_soc_dai_driver tasdevice_dai_driver[] = { static int tasdevice_codec_probe(struct snd_soc_component *codec) { struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + struct snd_kcontrol_new *p; + unsigned int size; int rc; - if (tas_priv->chip_id == TAS2781) { - rc = snd_soc_add_component_controls(codec, - tas2781_snd_controls, - ARRAY_SIZE(tas2781_snd_controls)); - if (rc < 0) { - dev_err(tas_priv->dev, "%s: Add control err rc = %d", - __func__, rc); - return rc; - } + switch (tas_priv->chip_id) { + case TAS2781: + p = (struct snd_kcontrol_new *)tas2781_snd_controls; + size = ARRAY_SIZE(tas2781_snd_controls); + break; + default: + p = (struct snd_kcontrol_new *)tas2563_snd_controls; + size = ARRAY_SIZE(tas2563_snd_controls); + } + + rc = snd_soc_add_component_controls(codec, p, size); + if (rc < 0) { + dev_err(tas_priv->dev, "%s: Add control err rc = %d", + __func__, rc); + return rc; } tas_priv->name_prefix = codec->name_prefix; From 8fc1e8b230771442133d5cf5fa4313277aa2bb8b Mon Sep 17 00:00:00 2001 From: Edson Juliano Drosdeck Date: Fri, 12 Jul 2024 15:06:42 -0300 Subject: [PATCH 341/349] ALSA: hda/realtek: Enable headset mic on Positivo SU C1400 Positivo SU C1400 is equipped with ALC256, and it needs ALC269_FIXUP_ASPIRE_HEADSET_MIC quirk to make its headset mic work. Signed-off-by: Edson Juliano Drosdeck Cc: Link: https://patch.msgid.link/20240712180642.22564-1-edson.drosdeck@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 766f0b1d3e9d..34cb731b40bc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10384,6 +10384,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE), SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), + SND_PCI_QUIRK(0x10ec, 0x119e, "Positivo SU C1400", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x10ec, 0x11bc, "VAIO VJFE-IL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x124c, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), From 2f38cf730caedaeacdefb7ff35b0a3c1168117f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Jul 2024 14:35:54 +0200 Subject: [PATCH 342/349] ALSA: usb: Fix UBSAN warning in parse_audio_unit() A malformed USB descriptor may pass the lengthy mixer description with a lot of channels, and this may overflow the 32bit integer shift size, as caught by syzbot UBSAN test. Although this won't cause any real trouble, it's better to address. This patch introduces a sanity check of the number of channels to bail out the parsing when too many channels are found. Reported-by: syzbot+78d5b129a762182225aa@syzkaller.appspotmail.com Closes: https://lore.kernel.org/0000000000000adac5061d3c7355@google.com Link: https://patch.msgid.link/20240715123619.26612-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 409fc1164694..fd6b94b3b638 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2014,6 +2014,13 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, bmaControls = ftr->bmaControls; } + if (channels > 32) { + usb_audio_info(state->chip, + "usbmixer: too many channels (%d) in unit %d\n", + channels, unitid); + return -EINVAL; + } + /* parse the source unit */ err = parse_audio_unit(state, hdr->bSourceID); if (err < 0) From e54dc34318f62bdeea7edefed386d47fae155618 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Jul 2024 14:36:45 +0200 Subject: [PATCH 343/349] ALSA: usb: Use BIT() for bit values Instead of the explicit "1 << x", use BIT() macro for one bit values. This will improve the readability and also avoids the possible bad value for 31bit shift. Link: https://patch.msgid.link/20240715123646.26679-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/format.c | 17 +++++++---------- sound/usb/mixer.c | 38 +++++++++++++++++++------------------- sound/usb/mixer_quirks.c | 20 ++++++++++---------- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/sound/usb/format.c b/sound/usb/format.c index 3b45d0ee7693..1bb6a455a1b4 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -82,13 +82,13 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, fp->fmt_bits = sample_width; if ((pcm_formats == 0) && - (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED))) { + (format == 0 || format == BIT(UAC_FORMAT_TYPE_I_UNDEFINED))) { /* some devices don't define this correctly... */ usb_audio_info(chip, "%u:%d : format type 0 is detected, processed as PCM\n", fp->iface, fp->altsetting); - format = 1 << UAC_FORMAT_TYPE_I_PCM; + format = BIT(UAC_FORMAT_TYPE_I_PCM); } - if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) { + if (format & BIT(UAC_FORMAT_TYPE_I_PCM)) { if (((chip->usb_id == USB_ID(0x0582, 0x0016)) || /* Edirol SD-90 */ (chip->usb_id == USB_ID(0x0582, 0x000c))) && @@ -128,7 +128,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, break; } } - if (format & (1 << UAC_FORMAT_TYPE_I_PCM8)) { + if (format & BIT(UAC_FORMAT_TYPE_I_PCM8)) { /* Dallas DS4201 workaround: it advertises U8 format, but really supports S8. */ if (chip->usb_id == USB_ID(0x04fa, 0x4201)) @@ -136,15 +136,12 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, else pcm_formats |= SNDRV_PCM_FMTBIT_U8; } - if (format & (1 << UAC_FORMAT_TYPE_I_IEEE_FLOAT)) { + if (format & BIT(UAC_FORMAT_TYPE_I_IEEE_FLOAT)) pcm_formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; - } - if (format & (1 << UAC_FORMAT_TYPE_I_ALAW)) { + if (format & BIT(UAC_FORMAT_TYPE_I_ALAW)) pcm_formats |= SNDRV_PCM_FMTBIT_A_LAW; - } - if (format & (1 << UAC_FORMAT_TYPE_I_MULAW)) { + if (format & BIT(UAC_FORMAT_TYPE_I_MULAW)) pcm_formats |= SNDRV_PCM_FMTBIT_MU_LAW; - } if (format & ~0x3f) { usb_audio_info(chip, "%u:%d : unsupported format bits %#llx\n", diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index fd6b94b3b638..c00009b545c0 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -433,7 +433,7 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval, { int err; - if (cval->cached & (1 << channel)) { + if (cval->cached & BIT(channel)) { *value = cval->cache_val[index]; return 0; } @@ -445,7 +445,7 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval, cval->control, channel, err); return err; } - cval->cached |= 1 << channel; + cval->cached |= BIT(channel); cval->cache_val[index] = *value; return 0; } @@ -522,7 +522,7 @@ int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int err; unsigned int read_only = (channel == 0) ? cval->master_readonly : - cval->ch_readonly & (1 << (channel - 1)); + cval->ch_readonly & BIT(channel - 1); if (read_only) { usb_audio_dbg(cval->head.mixer->chip, @@ -536,7 +536,7 @@ int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, value); if (err < 0) return err; - cval->cached |= 1 << channel; + cval->cached |= BIT(channel); cval->cache_val[index] = value; return 0; } @@ -1253,7 +1253,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, int minchn = 0; if (cval->cmask) { for (i = 0; i < MAX_CHANNELS; i++) - if (cval->cmask & (1 << i)) { + if (cval->cmask & BIT(i)) { minchn = i + 1; break; } @@ -1358,7 +1358,7 @@ no_res_check: } else { idx = 0; for (i = 0; i < MAX_CHANNELS; i++) { - if (cval->cmask & (1 << i)) { + if (cval->cmask & BIT(i)) { init_cur_mix_raw(cval, i + 1, idx); idx++; } @@ -1416,7 +1416,7 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, if (cval->cmask) { cnt = 0; for (c = 0; c < MAX_CHANNELS; c++) { - if (!(cval->cmask & (1 << c))) + if (!(cval->cmask & BIT(c))) continue; err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &val); if (err < 0) @@ -1448,7 +1448,7 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, if (cval->cmask) { cnt = 0; for (c = 0; c < MAX_CHANNELS; c++) { - if (!(cval->cmask & (1 << c))) + if (!(cval->cmask & BIT(c))) continue; err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &oval); if (err < 0) @@ -1700,7 +1700,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, } else { int i, c = 0; for (i = 0; i < 16; i++) - if (ctl_mask & (1 << i)) + if (ctl_mask & BIT(i)) c++; cval->channels = c; cval->ch_readonly = readonly_mask; @@ -2060,8 +2060,8 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); - if (mask & (1 << i)) - ch_bits |= (1 << j); + if (mask & BIT(i)) + ch_bits |= BIT(j); } /* audio class v1 controls are never read-only */ @@ -2072,7 +2072,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, if (ch_bits & 1) build_feature_ctl(state, _ftr, ch_bits, control, &iterm, unitid, 0); - if (master_bits & (1 << i)) + if (master_bits & BIT(i)) build_feature_ctl(state, _ftr, 0, control, &iterm, unitid, 0); } @@ -2088,9 +2088,9 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); if (uac_v2v3_control_is_readable(mask, control)) { - ch_bits |= (1 << j); + ch_bits |= BIT(j); if (!uac_v2v3_control_is_writeable(mask, control)) - ch_read_only |= (1 << j); + ch_read_only |= BIT(j); } } @@ -2181,7 +2181,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, __u8 *c = uac_mixer_unit_bmControls(desc, state->mixer->protocol); if (check_matrix_bitmap(c, in_ch, i, num_outs)) { - cval->cmask |= (1 << i); + cval->cmask |= BIT(i); cval->channels++; } } @@ -2504,7 +2504,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, if (state->mixer->protocol == UAC_VERSION_1) { if (!(controls[valinfo->control / 8] & - (1 << ((valinfo->control % 8) - 1)))) + BIT((valinfo->control % 8) - 1))) continue; } else { /* UAC_VERSION_2/3 */ if (!uac_v2v3_control_is_readable(controls[valinfo->control / 8], @@ -3448,7 +3448,7 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, case UAC2_CS_CUR: /* invalidate cache, so the value is read from the device */ if (channel) - info->cached &= ~(1 << channel); + info->cached &= ~BIT(channel); else /* master channel */ info->cached = 0; @@ -3684,9 +3684,9 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list) if (cval->cmask) { idx = 0; for (c = 0; c < MAX_CHANNELS; c++) { - if (!(cval->cmask & (1 << c))) + if (!(cval->cmask & BIT(c))) continue; - if (cval->cached & (1 << (c + 1))) { + if (cval->cached & BIT(c + 1)) { err = snd_usb_set_cur_mix_value(cval, c + 1, idx, cval->cache_val[idx]); if (err < 0) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 212b5e6443d8..2bc344cf54a8 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -1139,7 +1139,7 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) for (out = 0; out < 8; out++) { control = out + 1; for (in = 0; in < 8; in++) { - cmask = 1 << in; + cmask = BIT(in); snprintf(name, sizeof(name), "AIn%d - Out%d Capture Volume", in + 1, out + 1); @@ -1150,7 +1150,7 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) return err; } for (in = 8; in < 16; in++) { - cmask = 1 << in; + cmask = BIT(in); snprintf(name, sizeof(name), "DIn%d - Out%d Playback Volume", in - 7, out + 1); @@ -1215,7 +1215,7 @@ static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) const unsigned int control = 7; for (ch = 0; ch < 4; ++ch) { - cmask = 1 << ch; + cmask = BIT(ch); snprintf(name, sizeof(name), "Effect Return %d Volume", ch + 1); err = snd_create_std_mono_ctl(mixer, id, control, @@ -1239,7 +1239,7 @@ static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) const unsigned int control = 9; for (ch = 0; ch < 8; ++ch) { - cmask = 1 << ch; + cmask = BIT(ch); snprintf(name, sizeof(name), "Effect Send AIn%d Volume", ch + 1); err = snd_create_std_mono_ctl(mixer, id, control, cmask, @@ -1249,7 +1249,7 @@ static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) return err; } for (ch = 8; ch < 16; ++ch) { - cmask = 1 << ch; + cmask = BIT(ch); snprintf(name, sizeof(name), "Effect Send DIn%d Volume", ch - 7); err = snd_create_std_mono_ctl(mixer, id, control, cmask, @@ -1352,7 +1352,7 @@ static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer) chan - num_outs + 1, out + 1); } - cmask = (out == 0) ? 0 : 1 << (out - 1); + cmask = (out == 0) ? 0 : BIT(out - 1); offset = chan * num_outs; err = snd_create_std_mono_ctl_offset(mixer, id, control, cmask, val_type, offset, name, @@ -1438,7 +1438,7 @@ static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer) chan - num_outs + 1); } - cmask = (chan == 0) ? 0 : 1 << (chan - 1); + cmask = (chan == 0) ? 0 : BIT(chan - 1); err = snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, name, &snd_usb_mixer_vol_tlv); @@ -1480,7 +1480,7 @@ static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer chan + 1); cmask = (chan == 0) ? 0 : - 1 << (chan + (chan % 2) * num_outs - 1); + BIT(chan + (chan % 2) * num_outs - 1); err = snd_create_std_mono_ctl_offset(mixer, id, control, cmask, val_type, offset, name, &snd_usb_mixer_vol_tlv); @@ -2568,12 +2568,12 @@ static int snd_bbfpro_ctl_update(struct usb_mixer_interface *mixer, u8 reg, usb_idx = 3; usb_val = value ? 3 : 0; } else { - usb_idx = 1 << index; + usb_idx = BIT(index); usb_val = value ? usb_idx : 0; } } else { usb_req = SND_BBFPRO_USBREQ_CTL_REG2; - usb_idx = 1 << index; + usb_idx = BIT(index); usb_val = value ? usb_idx : 0; } From 88e98af9f4b5b0d60c1fe7f7f2701b5467691e75 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 17 Jul 2024 14:44:53 +0800 Subject: [PATCH 344/349] ALSA: pcm_dmaengine: Don't synchronize DMA channel when DMA is paused When suspended, the DMA channel may enter PAUSE state if dmaengine_pause() is supported by DMA. At this state, dmaengine_synchronize() should not be called, otherwise the DMA channel can't be resumed successfully. Fixes: e8343410ddf0 ("ALSA: dmaengine: Synchronize dma channel after drop()") Signed-off-by: Shengjiu Wang Cc: Link: https://patch.msgid.link/1721198693-27636-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Takashi Iwai --- sound/core/pcm_dmaengine.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index b54336d4bffc..b134a51b3fd5 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -352,8 +352,12 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan); int snd_dmaengine_pcm_sync_stop(struct snd_pcm_substream *substream) { struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + struct dma_tx_state state; + enum dma_status status; - dmaengine_synchronize(prtd->dma_chan); + status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state); + if (status != DMA_PAUSED) + dmaengine_synchronize(prtd->dma_chan); return 0; } From 3bfd7c0ba184de99e9f5083b29e5308f30767265 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 17 Jul 2024 10:33:01 +0200 Subject: [PATCH 345/349] ALSA: seq: ump: Skip useless ports for static blocks When the UMP Endpoint is configured with static blocks, the block configuration will never change, hence the unused ports will be unchanged as well. Creating sequencer ports for those unused ports is simply useless, and it might be rather confusing for users. The idea behind the inactive ports was for allowing connections from/to ports that can become usable later, but this will never happen for inactive groups in static blocks. Let's change the sequencer UMP binding to skip those unused ports when the UMP EP is with static blocks. Fixes: 81fd444aa371 ("ALSA: seq: Bind UMP device") Cc: Link: https://patch.msgid.link/20240717083322.25892-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/seq/seq_ump_client.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c index c627d72f7fe2..9cdfbeae3ed5 100644 --- a/sound/core/seq/seq_ump_client.c +++ b/sound/core/seq/seq_ump_client.c @@ -28,6 +28,7 @@ struct seq_ump_group { int group; /* group index (0-based) */ unsigned int dir_bits; /* directions */ bool active; /* activeness */ + bool valid; /* valid group (referred by blocks) */ char name[64]; /* seq port name */ }; @@ -210,6 +211,13 @@ static void fill_port_info(struct snd_seq_port_info *port, sprintf(port->name, "Group %d", group->group + 1); } +/* skip non-existing group for static blocks */ +static bool skip_group(struct seq_ump_client *client, struct seq_ump_group *group) +{ + return !group->valid && + (client->ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS); +} + /* create a new sequencer port per UMP group */ static int seq_ump_group_init(struct seq_ump_client *client, int group_index) { @@ -217,6 +225,9 @@ static int seq_ump_group_init(struct seq_ump_client *client, int group_index) struct snd_seq_port_info *port __free(kfree) = NULL; struct snd_seq_port_callback pcallbacks; + if (skip_group(client, group)) + return 0; + port = kzalloc(sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM; @@ -250,6 +261,9 @@ static void update_port_infos(struct seq_ump_client *client) return; for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) { + if (skip_group(client, &client->groups[i])) + continue; + old->addr.client = client->seq_client; old->addr.port = i; err = snd_seq_kernel_client_ctl(client->seq_client, @@ -284,6 +298,7 @@ static void update_group_attrs(struct seq_ump_client *client) group->dir_bits = 0; group->active = 0; group->group = i; + group->valid = false; } list_for_each_entry(fb, &client->ump->block_list, list) { @@ -291,6 +306,7 @@ static void update_group_attrs(struct seq_ump_client *client) break; group = &client->groups[fb->info.first_group]; for (i = 0; i < fb->info.num_groups; i++, group++) { + group->valid = true; if (fb->info.active) group->active = 1; switch (fb->info.direction) { From 1e5597e5ff18d452cf9afa847e904f301d1ac690 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Wed, 17 Jul 2024 19:53:04 +0800 Subject: [PATCH 346/349] ALSA: hda/tas2781: Add new quirk for Lenovo Hera2 Laptop Add new vendor_id and subsystem_id in quirk for Lenovo Hera2 Laptop. Signed-off-by: Shenghao Ding Cc: Link: https://patch.msgid.link/20240717115305.723-1-shenghao-ding@ti.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 75f9faaad313..d6b6a97600fc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10539,6 +10539,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x231a, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x231e, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318), SND_PCI_QUIRK(0x17aa, 0x231f, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318), + SND_PCI_QUIRK(0x17aa, 0x2326, "Hera2", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), From d7063c08738573fc2f3296da6d31a22fa8aa843a Mon Sep 17 00:00:00 2001 From: Seunghun Han Date: Thu, 18 Jul 2024 17:09:08 +0900 Subject: [PATCH 347/349] ALSA: hda/realtek: Fix the speaker output on Samsung Galaxy Book Pro 360 Samsung Galaxy Book Pro 360 (13" 2022 NT935QDB-KC71S) with codec SSID 144d:c1a4 requires the same workaround to enable the speaker amp as other Samsung models with the ALC298 codec. Signed-off-by: Seunghun Han Cc: Link: https://patch.msgid.link/20240718080908.8677-1-kkamagui@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d6b6a97600fc..c3a86a99f8c6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10398,6 +10398,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc1a3, "Samsung Galaxy Book Pro (NP935XDB-KC1SE)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc1a4, "Samsung Galaxy Book Pro 360 (NT935QBD)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc1a6, "Samsung Galaxy Book Pro 360 (NP930QBD)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP), From b1a7b97aa534b031f929ba4bf70d2e869b117c9d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Jul 2024 15:47:59 +0100 Subject: [PATCH 348/349] kselftest/alsa: Use card name rather than number in test names Currently for the PCM and mixer tests we report test names which identify the card being tested with the card number. This ensures we have unique names but since card numbers are dynamically assigned at runtime the names we end up with will often not be stable on systems with multiple cards especially where those cards are provided by separate modules loeaded at runtime. This makes it difficult for automated systems and UIs to relate test results between runs on affected platforms. Address this by replacing our use of card numbers with card names which are more likely to be stable across runs. We use the card ID since it is guaranteed to be unique by default, unlike the long name. There is still some vulnerability to ordering issues if multiple cards with the same base ID are present in the system but have separate dependencies but not all drivers put distinguishing information in their long names. Signed-off-by: Mark Brown Link: https://patch.msgid.link/20240716-alsa-kselftest-board-name-v2-1-60f1acdde096@kernel.org Signed-off-by: Takashi Iwai --- tools/testing/selftests/alsa/mixer-test.c | 98 ++++++++++++++--------- tools/testing/selftests/alsa/pcm-test.c | 64 ++++++++++----- 2 files changed, 104 insertions(+), 58 deletions(-) diff --git a/tools/testing/selftests/alsa/mixer-test.c b/tools/testing/selftests/alsa/mixer-test.c index dd74f8cc7ece..2a4b2662035e 100644 --- a/tools/testing/selftests/alsa/mixer-test.c +++ b/tools/testing/selftests/alsa/mixer-test.c @@ -33,6 +33,8 @@ struct card_data { snd_ctl_t *handle; int card; + snd_ctl_card_info_t *info; + const char *card_name; struct pollfd pollfd; int num_ctls; snd_ctl_elem_list_t *ctls; @@ -91,8 +93,26 @@ static void find_controls(void) err = snd_card_get_longname(card, &card_longname); if (err != 0) card_longname = "Unknown"; - ksft_print_msg("Card %d - %s (%s)\n", card, - card_name, card_longname); + + err = snd_ctl_card_info_malloc(&card_data->info); + if (err != 0) + ksft_exit_fail_msg("Failed to allocate card info: %d\n", + err); + + err = snd_ctl_card_info(card_data->handle, card_data->info); + if (err == 0) { + card_data->card_name = snd_ctl_card_info_get_id(card_data->info); + if (!card_data->card_name) + ksft_print_msg("Failed to get card ID\n"); + } else { + ksft_print_msg("Failed to get card info: %d\n", err); + } + + if (!card_data->card_name) + card_data->card_name = "Unknown"; + + ksft_print_msg("Card %d/%s - %s (%s)\n", card, + card_data->card_name, card_name, card_longname); /* Count controls */ snd_ctl_elem_list_malloc(&card_data->ctls); @@ -389,16 +409,16 @@ static void test_ctl_get_value(struct ctl_data *ctl) /* If the control is turned off let's be polite */ if (snd_ctl_elem_info_is_inactive(ctl->info)) { ksft_print_msg("%s is inactive\n", ctl->name); - ksft_test_result_skip("get_value.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("get_value.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } /* Can't test reading on an unreadable control */ if (!snd_ctl_elem_info_is_readable(ctl->info)) { ksft_print_msg("%s is not readable\n", ctl->name); - ksft_test_result_skip("get_value.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("get_value.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } @@ -413,8 +433,8 @@ static void test_ctl_get_value(struct ctl_data *ctl) err = -EINVAL; out: - ksft_test_result(err >= 0, "get_value.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result(err >= 0, "get_value.%s.%d\n", + ctl->card->card_name, ctl->elem); } static bool strend(const char *haystack, const char *needle) @@ -431,7 +451,7 @@ static void test_ctl_name(struct ctl_data *ctl) { bool name_ok = true; - ksft_print_msg("%d.%d %s\n", ctl->card->card, ctl->elem, + ksft_print_msg("%s.%d %s\n", ctl->card->card_name, ctl->elem, ctl->name); /* Only boolean controls should end in Switch */ @@ -453,8 +473,8 @@ static void test_ctl_name(struct ctl_data *ctl) } } - ksft_test_result(name_ok, "name.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result(name_ok, "name.%s.%d\n", + ctl->card->card_name, ctl->elem); } static void show_values(struct ctl_data *ctl, snd_ctl_elem_value_t *orig_val, @@ -695,30 +715,30 @@ static void test_ctl_write_default(struct ctl_data *ctl) /* If the control is turned off let's be polite */ if (snd_ctl_elem_info_is_inactive(ctl->info)) { ksft_print_msg("%s is inactive\n", ctl->name); - ksft_test_result_skip("write_default.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("write_default.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } if (!snd_ctl_elem_info_is_writable(ctl->info)) { ksft_print_msg("%s is not writeable\n", ctl->name); - ksft_test_result_skip("write_default.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("write_default.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } /* No idea what the default was for unreadable controls */ if (!snd_ctl_elem_info_is_readable(ctl->info)) { ksft_print_msg("%s couldn't read default\n", ctl->name); - ksft_test_result_skip("write_default.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("write_default.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } err = write_and_verify(ctl, ctl->def_val, NULL); - ksft_test_result(err >= 0, "write_default.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result(err >= 0, "write_default.%s.%d\n", + ctl->card->card_name, ctl->elem); } static bool test_ctl_write_valid_boolean(struct ctl_data *ctl) @@ -828,15 +848,15 @@ static void test_ctl_write_valid(struct ctl_data *ctl) /* If the control is turned off let's be polite */ if (snd_ctl_elem_info_is_inactive(ctl->info)) { ksft_print_msg("%s is inactive\n", ctl->name); - ksft_test_result_skip("write_valid.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("write_valid.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } if (!snd_ctl_elem_info_is_writable(ctl->info)) { ksft_print_msg("%s is not writeable\n", ctl->name); - ksft_test_result_skip("write_valid.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("write_valid.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } @@ -859,16 +879,16 @@ static void test_ctl_write_valid(struct ctl_data *ctl) default: /* No tests for this yet */ - ksft_test_result_skip("write_valid.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("write_valid.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } /* Restore the default value to minimise disruption */ write_and_verify(ctl, ctl->def_val, NULL); - ksft_test_result(pass, "write_valid.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result(pass, "write_valid.%s.%d\n", + ctl->card->card_name, ctl->elem); } static bool test_ctl_write_invalid_value(struct ctl_data *ctl, @@ -1040,15 +1060,15 @@ static void test_ctl_write_invalid(struct ctl_data *ctl) /* If the control is turned off let's be polite */ if (snd_ctl_elem_info_is_inactive(ctl->info)) { ksft_print_msg("%s is inactive\n", ctl->name); - ksft_test_result_skip("write_invalid.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("write_invalid.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } if (!snd_ctl_elem_info_is_writable(ctl->info)) { ksft_print_msg("%s is not writeable\n", ctl->name); - ksft_test_result_skip("write_invalid.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("write_invalid.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } @@ -1071,28 +1091,28 @@ static void test_ctl_write_invalid(struct ctl_data *ctl) default: /* No tests for this yet */ - ksft_test_result_skip("write_invalid.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result_skip("write_invalid.%s.%d\n", + ctl->card->card_name, ctl->elem); return; } /* Restore the default value to minimise disruption */ write_and_verify(ctl, ctl->def_val, NULL); - ksft_test_result(pass, "write_invalid.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result(pass, "write_invalid.%s.%d\n", + ctl->card->card_name, ctl->elem); } static void test_ctl_event_missing(struct ctl_data *ctl) { - ksft_test_result(!ctl->event_missing, "event_missing.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result(!ctl->event_missing, "event_missing.%s.%d\n", + ctl->card->card_name, ctl->elem); } static void test_ctl_event_spurious(struct ctl_data *ctl) { - ksft_test_result(!ctl->event_spurious, "event_spurious.%d.%d\n", - ctl->card->card, ctl->elem); + ksft_test_result(!ctl->event_spurious, "event_spurious.%s.%d\n", + ctl->card->card_name, ctl->elem); } int main(void) diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index 914efcdce1ec..a8f189ffdd8e 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -24,6 +24,8 @@ typedef struct timespec timestamp_t; struct card_data { int card; + snd_ctl_card_info_t *info; + const char *name; pthread_t thread; struct card_data *next; }; @@ -35,6 +37,7 @@ struct pcm_data { int card; int device; int subdevice; + const char *card_name; snd_pcm_stream_t stream; snd_config_t *pcm_config; struct pcm_data *next; @@ -167,6 +170,10 @@ static void find_pcms(void) config = get_alsalib_config(); while (card >= 0) { + card_data = calloc(1, sizeof(*card_data)); + if (!card_data) + ksft_exit_fail_msg("Out of memory\n"); + sprintf(name, "hw:%d", card); err = snd_ctl_open_lconf(&handle, name, 0, config); @@ -182,14 +189,29 @@ static void find_pcms(void) err = snd_card_get_longname(card, &card_longname); if (err != 0) card_longname = "Unknown"; - ksft_print_msg("Card %d - %s (%s)\n", card, - card_name, card_longname); + + err = snd_ctl_card_info_malloc(&card_data->info); + if (err != 0) + ksft_exit_fail_msg("Failed to allocate card info: %d\n", + err); + + err = snd_ctl_card_info(handle, card_data->info); + if (err == 0) { + card_data->name = snd_ctl_card_info_get_id(card_data->info); + if (!card_data->name) + ksft_print_msg("Failed to get card ID\n"); + } else { + ksft_print_msg("Failed to get card info: %d\n", err); + } + + if (!card_data->name) + card_data->name = "Unknown"; + + ksft_print_msg("Card %d/%s - %s (%s)\n", card, + card_data->name, card_name, card_longname); card_config = conf_by_card(card); - card_data = calloc(1, sizeof(*card_data)); - if (!card_data) - ksft_exit_fail_msg("Out of memory\n"); card_data->card = card; card_data->next = card_list; card_list = card_data; @@ -232,6 +254,7 @@ static void find_pcms(void) pcm_data->card = card; pcm_data->device = dev; pcm_data->subdevice = subdev; + pcm_data->card_name = card_data->name; pcm_data->stream = stream; pcm_data->pcm_config = conf_get_subtree(card_config, key, NULL); pcm_data->next = pcm_list; @@ -294,9 +317,9 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class, desc = conf_get_string(pcm_cfg, "description", NULL, NULL); if (desc) - ksft_print_msg("%s.%s.%d.%d.%d.%s - %s\n", + ksft_print_msg("%s.%s.%s.%d.%d.%s - %s\n", test_class_name, test_name, - data->card, data->device, data->subdevice, + data->card_name, data->device, data->subdevice, snd_pcm_stream_name(data->stream), desc); @@ -352,9 +375,9 @@ __format: old_format = format; format = snd_pcm_format_value(alt_formats[i]); if (format != SND_PCM_FORMAT_UNKNOWN) { - ksft_print_msg("%s.%d.%d.%d.%s.%s format %s -> %s\n", + ksft_print_msg("%s.%s.%d.%d.%s.%s format %s -> %s\n", test_name, - data->card, data->device, data->subdevice, + data->card_name, data->device, data->subdevice, snd_pcm_stream_name(data->stream), snd_pcm_access_name(access), snd_pcm_format_name(old_format), @@ -430,9 +453,9 @@ __format: goto __close; } - ksft_print_msg("%s.%s.%d.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n", + ksft_print_msg("%s.%s.%s.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n", test_class_name, test_name, - data->card, data->device, data->subdevice, + data->card_name, data->device, data->subdevice, snd_pcm_stream_name(data->stream), snd_pcm_access_name(access), snd_pcm_format_name(format), @@ -491,9 +514,10 @@ __close: * Anything specified as specific to this system * should always be supported. */ - ksft_test_result(!skip, "%s.%s.%d.%d.%d.%s.params\n", + ksft_test_result(!skip, "%s.%s.%s.%d.%d.%s.params\n", test_class_name, test_name, - data->card, data->device, data->subdevice, + data->card_name, data->device, + data->subdevice, snd_pcm_stream_name(data->stream)); break; default: @@ -501,14 +525,16 @@ __close: } if (!skip) - ksft_test_result(pass, "%s.%s.%d.%d.%d.%s\n", + ksft_test_result(pass, "%s.%s.%s.%d.%d.%s\n", test_class_name, test_name, - data->card, data->device, data->subdevice, + data->card_name, data->device, + data->subdevice, snd_pcm_stream_name(data->stream)); else - ksft_test_result_skip("%s.%s.%d.%d.%d.%s\n", + ksft_test_result_skip("%s.%s.%s.%d.%d.%s\n", test_class_name, test_name, - data->card, data->device, data->subdevice, + data->card_name, data->device, + data->subdevice, snd_pcm_stream_name(data->stream)); if (msg[0]) @@ -609,8 +635,8 @@ int main(void) conf->filename, conf->config_id); for (pcm = pcm_missing; pcm != NULL; pcm = pcm->next) { - ksft_test_result(false, "test.missing.%d.%d.%d.%s\n", - pcm->card, pcm->device, pcm->subdevice, + ksft_test_result(false, "test.missing.%s.%d.%d.%s\n", + pcm->card_name, pcm->device, pcm->subdevice, snd_pcm_stream_name(pcm->stream)); } From 4594d26fca91fab0e1621d2ab196f3f9bab96bc8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Jul 2024 15:48:00 +0100 Subject: [PATCH 349/349] kselftest/alsa: Log the PCM ID in pcm-test Drivers report a string with a name for each PCM, log it during startup of pcm-test as a diagnostic aid. Signed-off-by: Mark Brown Link: https://patch.msgid.link/20240716-alsa-kselftest-board-name-v2-2-60f1acdde096@kernel.org Signed-off-by: Takashi Iwai --- tools/testing/selftests/alsa/pcm-test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index a8f189ffdd8e..dbd7c222ce93 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -240,6 +240,10 @@ static void find_pcms(void) if (err < 0) ksft_exit_fail_msg("snd_ctl_pcm_info: %d:%d:%d\n", dev, 0, stream); + + ksft_print_msg("%s.0 - %s\n", card_data->name, + snd_pcm_info_get_id(pcm_info)); + count = snd_pcm_info_get_subdevices_count(pcm_info); for (subdev = 0; subdev < count; subdev++) { sprintf(key, "pcm.%d.%d.%s", dev, subdev, snd_pcm_stream_name(stream));