From ca4d49f8a21c37be7e5aed80100ca6b13ac3cf9d Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Thu, 23 Oct 2025 10:03:09 +0100 Subject: [PATCH 01/12] ASoC: cs530x: Update the copyright headers Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-2-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x-i2c.c | 4 ++-- sound/soc/codecs/cs530x.c | 4 ++-- sound/soc/codecs/cs530x.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c index 22b1a4d6b61c..be80dcad3647 100644 --- a/sound/soc/codecs/cs530x-i2c.c +++ b/sound/soc/codecs/cs530x-i2c.c @@ -2,8 +2,8 @@ // // CS530x CODEC driver // -// Copyright (C) 2024 Cirrus Logic, Inc. and -// Cirrus Logic International Semiconductor Ltd. +// Copyright (C) 2024-2025 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. #include #include diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index b9eff240b929..c8959a9525c1 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -2,8 +2,8 @@ // // CS530x CODEC driver // -// Copyright (C) 2024 Cirrus Logic, Inc. and -// Cirrus Logic International Semiconductor Ltd. +// Copyright (C) 2024-2025 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. #include #include diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index f473e33eb835..b325847036e9 100644 --- a/sound/soc/codecs/cs530x.h +++ b/sound/soc/codecs/cs530x.h @@ -2,7 +2,7 @@ /* * CS530x CODEC driver internal data * - * Copyright (C) 2023-2024 Cirrus Logic, Inc. and + * Copyright (C) 2023-2025 Cirrus Logic, Inc. and * Cirrus Logic International Semiconductor Ltd. */ From 1e0722a77b4e263854a812c9c106ddef8fd56720 Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Thu, 23 Oct 2025 10:03:10 +0100 Subject: [PATCH 02/12] ASoC: cs530x: Sort #include directives and tydy up whitespaces Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-3-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x-i2c.c | 2 +- sound/soc/codecs/cs530x.c | 49 ++++++++++++++++------------------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c index be80dcad3647..d6b7883ba7b9 100644 --- a/sound/soc/codecs/cs530x-i2c.c +++ b/sound/soc/codecs/cs530x-i2c.c @@ -48,7 +48,7 @@ static int cs530x_i2c_probe(struct i2c_client *client) 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"); + "Failed to allocate register map\n"); cs530x->devtype = (uintptr_t)i2c_get_match_data(client); cs530x->dev = &client->dev; diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index c8959a9525c1..498005674a3f 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -5,17 +5,17 @@ // Copyright (C) 2024-2025 Cirrus Logic, Inc. and // Cirrus Logic International Semiconductor Ltd. -#include #include #include #include -#include #include -#include -#include #include #include #include +#include +#include +#include +#include #include #include @@ -104,7 +104,7 @@ static bool cs530x_writeable_register(struct device *dev, unsigned int reg) } static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + 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); @@ -224,7 +224,7 @@ 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_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); @@ -236,9 +236,9 @@ static int cs530x_adc_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMU: regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + - (w->shift * 2), CS530X_IN_MUTE); + (w->shift * 2), CS530X_IN_MUTE); regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + - ((w->shift+1) * 2), CS530X_IN_MUTE); + ((w->shift + 1) * 2), CS530X_IN_MUTE); cs530x->adc_pairs_count--; if (!cs530x->adc_pairs_count) { @@ -249,9 +249,9 @@ static int cs530x_adc_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_PRE_PMD: regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + - (w->shift * 2), CS530X_IN_MUTE); + (w->shift * 2), CS530X_IN_MUTE); regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + - ((w->shift+1) * 2), CS530X_IN_MUTE); + ((w->shift + 1) * 2), CS530X_IN_MUTE); return regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_IN_VU); default: @@ -263,16 +263,12 @@ static int cs530x_adc_event(struct snd_soc_dapm_widget *w, 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); @@ -450,7 +446,7 @@ static int cs530x_set_bclk(struct snd_soc_component *component, const int freq) } static int cs530x_set_pll_refclk(struct snd_soc_component *component, - const unsigned int freq) + const unsigned int freq) { struct cs530x_priv *priv = snd_soc_component_get_drvdata(component); struct regmap *regmap = priv->regmap; @@ -492,7 +488,6 @@ static int cs530x_hw_params(struct snd_pcm_substream *substream, int ret = 0, fs = params_rate(params), bclk; unsigned int fs_val; - switch (fs) { case 32000: fs_val = CS530X_FS_32K; @@ -540,7 +535,7 @@ static int cs530x_hw_params(struct snd_pcm_substream *substream, } if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0, - CS530X_PLL_REFCLK_SRC_MASK)) { + CS530X_PLL_REFCLK_SRC_MASK)) { ret = cs530x_set_pll_refclk(component, bclk); if (ret) return ret; @@ -614,7 +609,7 @@ static bool cs530x_check_mclk_freq(struct snd_soc_component *component, } static int cs530x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, - unsigned int rx_mask, int slots, int slot_width) + 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); @@ -686,8 +681,8 @@ static const struct snd_soc_dai_driver cs530x_dai = { }; static int cs530x_set_pll(struct snd_soc_component *component, int pll_id, - int source, unsigned int freq_in, - unsigned int freq_out) + 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; @@ -743,7 +738,6 @@ static int cs530x_component_probe(struct snd_soc_component *component) cs530x_in_sum_4ch_controls, num_widgets); break; - case CS5308: cs530x_add_12_adc_widgets(component); cs530x_add_34_adc_widgets(component); @@ -775,7 +769,7 @@ static int cs530x_component_probe(struct snd_soc_component *component) } static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id, - int source, unsigned int freq, int dir) + int source, unsigned int freq, int dir) { struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); struct regmap *regmap = cs530x->regmap; @@ -895,8 +889,8 @@ int cs530x_probe(struct cs530x_priv *cs530x) int ret, i; cs530x->dev_dai = devm_kmemdup(dev, &cs530x_dai, - sizeof(*(cs530x->dev_dai)), - GFP_KERNEL); + sizeof(*(cs530x->dev_dai)), + GFP_KERNEL); if (!cs530x->dev_dai) return -ENOMEM; @@ -914,10 +908,10 @@ int cs530x_probe(struct cs530x_priv *cs530x) return dev_err_probe(dev, ret, "Failed to enable supplies"); cs530x->reset_gpio = devm_gpiod_get_optional(dev, "reset", - GPIOD_OUT_HIGH); + GPIOD_OUT_HIGH); if (IS_ERR(cs530x->reset_gpio)) { ret = dev_err_probe(dev, PTR_ERR(cs530x->reset_gpio), - "Reset gpio not available\n"); + "Reset gpio not available\n"); goto err_regulator; } @@ -947,7 +941,8 @@ int cs530x_probe(struct cs530x_priv *cs530x) cs530x->dev_dai->capture.channels_max = cs530x->num_adcs; ret = devm_snd_soc_register_component(dev, - &soc_component_dev_cs530x, cs530x->dev_dai, 1); + &soc_component_dev_cs530x, + cs530x->dev_dai, 1); if (ret) { dev_err_probe(dev, ret, "Can't register cs530x component\n"); goto err_reset; From f97ebfda8da28a77a0218a448829451ba7e30d5d Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Thu, 23 Oct 2025 10:03:11 +0100 Subject: [PATCH 03/12] ASoC: cs530x: Remove unused struct members and constants Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-4-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x.c | 6 ------ sound/soc/codecs/cs530x.h | 5 +---- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index 498005674a3f..a4c9127495c5 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -21,9 +21,6 @@ #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", @@ -517,7 +514,6 @@ static int cs530x_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - cs530x->fs = fs; regmap_update_bits(regmap, CS530X_CLK_CFG_1, CS530X_SAMPLE_RATE_MASK, fs_val); @@ -781,8 +777,6 @@ static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id, freq); return -EINVAL; } - - cs530x->mclk_rate = freq; break; case CS530X_SYSCLK_SRC_PLL: break; diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index b325847036e9..5b47c1ae2a09 100644 --- a/sound/soc/codecs/cs530x.h +++ b/sound/soc/codecs/cs530x.h @@ -99,7 +99,7 @@ #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 +#define CS530X_ASP_FMT_DSP_A 6 /* TDM Slots */ #define CS530X_0_1_TDM_SLOT_MASK GENMASK(1, 0) @@ -207,11 +207,8 @@ struct cs530x_priv { struct regulator_bulk_data supplies[CS530X_NUM_SUPPLIES]; - unsigned int mclk_rate; - int tdm_width; int tdm_slots; - int fs; int adc_pairs_count; struct gpio_desc *reset_gpio; From ddbcd2f396116581ad035fb76a99fc2ed865a85f Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Thu, 23 Oct 2025 10:03:12 +0100 Subject: [PATCH 04/12] ASoC: cs530x: Correct constant naming Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-5-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x.c | 10 +++++----- sound/soc/codecs/cs530x.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index a4c9127495c5..6fa62fb6c681 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -491,23 +491,23 @@ static int cs530x_hw_params(struct snd_pcm_substream *substream, break; case 44100: case 48000: - fs_val = CS530X_FS_48K_44P1K; + fs_val = CS530X_FS_44P1K_48K; break; case 88200: case 96000: - fs_val = CS530X_FS_96K_88P2K; + fs_val = CS530X_FS_88P2K_96K; break; case 176400: case 192000: - fs_val = CS530X_FS_192K_176P4K; + fs_val = CS530X_FS_176P4K_192K; break; case 356800: case 384000: - fs_val = CS530X_FS_384K_356P8K; + fs_val = CS530X_FS_356P8K_384K; break; case 705600: case 768000: - fs_val = CS530X_FS_768K_705P6K; + fs_val = CS530X_FS_705P6K_768K; break; default: dev_err(component->dev, "Invalid sample rate %d\n", fs); diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index 5b47c1ae2a09..f7640161c77f 100644 --- a/sound/soc/codecs/cs530x.h +++ b/sound/soc/codecs/cs530x.h @@ -73,11 +73,11 @@ /* 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 +#define CS530X_FS_44P1K_48K 1 +#define CS530X_FS_88P2K_96K 2 +#define CS530X_FS_176P4K_192K 3 +#define CS530X_FS_356P8K_384K 4 +#define CS530X_FS_705P6K_768K 5 /* CHIP_ENABLE */ #define CS530X_GLOBAL_EN BIT(0) From 9957614d2b79578b6f9a2512bfbb2bc7bbdc43ce Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Thu, 23 Oct 2025 10:03:13 +0100 Subject: [PATCH 05/12] ASoC: dt-bindings: sound: cirrus: cs530x: Add cs530x This patch adds additional cs530x family variants. cirrus,cs4282 - high-performance, 32-bit resolution, stereo CODEC cirrus,cs4302 - high performance stereo DAC, 2 channels cirrus,cs4304 - high performance stereo DAC, 4 channels cirrus,cs4308 - high performance stereo DAC, 8 channels Signed-off-by: Vitaly Rodionov Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251023090327.58275-6-vitalyr@opensource.cirrus.com Reviewed-by: Rob Herring (Arm) Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml index 9582eb8eb418..04ed197f91eb 100644 --- a/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml +++ b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml @@ -19,6 +19,10 @@ allOf: properties: compatible: enum: + - cirrus,cs4282 + - cirrus,cs4302 + - cirrus,cs4304 + - cirrus,cs4308 - cirrus,cs5302 - cirrus,cs5304 - cirrus,cs5308 From c63b2315b9cc6b705205c73dcf4591cfeb9a25ae Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Thu, 23 Oct 2025 10:03:14 +0100 Subject: [PATCH 06/12] ASoC: cs530x: Add CODEC and DAC support - Added DAC register address constants - Add the new registers to the regmap config - Renamed constants that are shared between the DACs and ADCs - Add the device IDs and device names of the CODEC and DACs along with their different capabilities - Add DAPM widgets, ALSA controls and event handling for the DAC functionality - Add Playback DAI support Signed-off-by: Simon Trimmer Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-7-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x-i2c.c | 16 ++ sound/soc/codecs/cs530x.c | 411 +++++++++++++++++++++++++++++++--- sound/soc/codecs/cs530x.h | 58 +++-- 3 files changed, 440 insertions(+), 45 deletions(-) diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c index d6b7883ba7b9..ab410826f777 100644 --- a/sound/soc/codecs/cs530x-i2c.c +++ b/sound/soc/codecs/cs530x-i2c.c @@ -14,6 +14,18 @@ static const struct of_device_id cs530x_of_match[] = { { + .compatible = "cirrus,cs4282", + .data = (void *)CS4282, + }, { + .compatible = "cirrus,cs4302", + .data = (void *)CS4302, + }, { + .compatible = "cirrus,cs4304", + .data = (void *)CS4304, + }, { + .compatible = "cirrus,cs4308", + .data = (void *)CS4308, + }, { .compatible = "cirrus,cs5302", .data = (void *)CS5302, }, { @@ -28,6 +40,10 @@ static const struct of_device_id cs530x_of_match[] = { MODULE_DEVICE_TABLE(of, cs530x_of_match); static const struct i2c_device_id cs530x_i2c_id[] = { + { "cs4282", CS4282 }, + { "cs4302", CS4302 }, + { "cs4304", CS4304 }, + { "cs4308", CS4308 }, { "cs5302", CS5302 }, { "cs5304", CS5304 }, { "cs5308", CS5308 }, diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index 6fa62fb6c681..380405d3e3a8 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -45,6 +45,18 @@ static const struct reg_default cs530x_reg_defaults[] = { { CS530X_IN_VOL_CTRL3_1, 0x8000 }, { CS530X_IN_VOL_CTRL4_0, 0x8000 }, { CS530X_IN_VOL_CTRL4_1, 0x8000 }, + { CS530X_OUT_ENABLES, 0 }, + { CS530X_OUT_RAMP_SUM, 0x0022 }, + { CS530X_OUT_FILTER, 0 }, + { CS530X_OUT_INV, 0 }, + { CS530X_OUT_VOL_CTRL1_0, 0x8000 }, + { CS530X_OUT_VOL_CTRL1_1, 0x8000 }, + { CS530X_OUT_VOL_CTRL2_0, 0x8000 }, + { CS530X_OUT_VOL_CTRL2_1, 0x8000 }, + { CS530X_OUT_VOL_CTRL3_0, 0x8000 }, + { CS530X_OUT_VOL_CTRL3_1, 0x8000 }, + { CS530X_OUT_VOL_CTRL4_0, 0x8000 }, + { CS530X_OUT_VOL_CTRL4_1, 0x8000 }, { CS530X_PAD_FN, 0 }, { CS530X_PAD_LVL, 0 }, }; @@ -70,6 +82,19 @@ static bool cs530x_read_and_write_regs(unsigned int reg) case CS530X_IN_VOL_CTRL3_1: case CS530X_IN_VOL_CTRL4_0: case CS530X_IN_VOL_CTRL4_1: + case CS530X_OUT_ENABLES: + case CS530X_OUT_RAMP_SUM: + case CS530X_OUT_DEEMPH: + case CS530X_OUT_FILTER: + case CS530X_OUT_INV: + case CS530X_OUT_VOL_CTRL1_0: + case CS530X_OUT_VOL_CTRL1_1: + case CS530X_OUT_VOL_CTRL2_0: + case CS530X_OUT_VOL_CTRL2_1: + case CS530X_OUT_VOL_CTRL3_0: + case CS530X_OUT_VOL_CTRL3_1: + case CS530X_OUT_VOL_CTRL4_0: + case CS530X_OUT_VOL_CTRL4_1: case CS530X_PAD_FN: case CS530X_PAD_LVL: return true; @@ -94,6 +119,7 @@ static bool cs530x_writeable_register(struct device *dev, unsigned int reg) switch (reg) { case CS530X_SW_RESET: case CS530X_IN_VOL_CTRL5: + case CS530X_OUT_VOL_CTRL5: return true; default: return cs530x_read_and_write_regs(reg); @@ -126,7 +152,7 @@ static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1270, 50, 0); -static const char * const cs530x_in_filter_text[] = { +static const char * const cs530x_inout_filter_text[] = { "Min Phase Slow Roll-off", "Min Phase Fast Roll-off", "Linear Phase Slow Roll-off", @@ -134,24 +160,36 @@ static const char * const cs530x_in_filter_text[] = { }; static SOC_ENUM_SINGLE_DECL(cs530x_in_filter_enum, CS530X_IN_FILTER, - CS530X_IN_FILTER_SHIFT, - cs530x_in_filter_text); + CS530X_INOUT_FILTER_SHIFT, + cs530x_inout_filter_text); -static const char * const cs530x_in_4ch_sum_text[] = { +static SOC_ENUM_SINGLE_DECL(cs530x_out_filter_enum, CS530X_OUT_FILTER, + CS530X_INOUT_FILTER_SHIFT, + cs530x_inout_filter_text); + +static const char * const cs530x_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); + CS530X_INOUT_SUM_MODE_SHIFT, + cs530x_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[] = { +static SOC_ENUM_SINGLE_DECL(cs530x_out_sum_ch4_enum, CS530X_OUT_RAMP_SUM, + CS530X_INOUT_SUM_MODE_SHIFT, + cs530x_4ch_sum_text); + +static const struct snd_kcontrol_new cs530x_out_sum_4ch_controls[] = { +SOC_ENUM("OUT Sum Select", cs530x_out_sum_ch4_enum), +}; + +static const char * const cs530x_8ch_sum_text[] = { "None", "Groups of 2", "Groups of 4", @@ -159,13 +197,20 @@ static const char * const cs530x_in_8ch_sum_text[] = { }; static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch8_enum, CS530X_IN_RAMP_SUM, - CS530X_IN_SUM_MODE_SHIFT, - cs530x_in_8ch_sum_text); + CS530X_INOUT_SUM_MODE_SHIFT, + cs530x_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 SOC_ENUM_SINGLE_DECL(cs530x_out_sum_ch8_enum, CS530X_OUT_RAMP_SUM, + CS530X_INOUT_SUM_MODE_SHIFT, + cs530x_8ch_sum_text); + +static const struct snd_kcontrol_new cs530x_out_sum_8ch_controls[] = { +SOC_ENUM("OUT Sum Select", cs530x_out_sum_ch8_enum), +}; static const char * const cs530x_vol_ramp_text[] = { "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", @@ -190,8 +235,8 @@ SOC_ENUM("IN DEC Filter Select", cs530x_in_filter_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), +SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_INOUT1_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_INOUT2_INV_SHIFT, 1, 0), }; static const struct snd_kcontrol_new cs530x_in_3_to_4_controls[] = { @@ -200,8 +245,8 @@ SOC_SINGLE_EXT_TLV("IN3 Volume", CS530X_IN_VOL_CTRL2_0, 0, 255, 1, 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), +SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_INOUT3_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_INOUT4_INV_SHIFT, 1, 0), }; static const struct snd_kcontrol_new cs530x_in_5_to_8_controls[] = { @@ -214,10 +259,10 @@ SOC_SINGLE_EXT_TLV("IN7 Volume", CS530X_IN_VOL_CTRL4_0, 0, 255, 1, 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), +SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_INOUT5_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_INOUT6_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_INOUT7_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_INOUT8_INV_SHIFT, 1, 0), }; static int cs530x_adc_event(struct snd_soc_dapm_widget *w, @@ -233,24 +278,110 @@ static int cs530x_adc_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMU: regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + - (w->shift * 2), CS530X_IN_MUTE); + (w->shift * 2), CS530X_INOUT_MUTE); regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + - ((w->shift + 1) * 2), CS530X_IN_MUTE); + ((w->shift + 1) * 2), CS530X_INOUT_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); + CS530X_INOUT_VU); } break; case SND_SOC_DAPM_PRE_PMD: regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + - (w->shift * 2), CS530X_IN_MUTE); + (w->shift * 2), CS530X_INOUT_MUTE); regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + - ((w->shift + 1) * 2), CS530X_IN_MUTE); + ((w->shift + 1) * 2), CS530X_INOUT_MUTE); return regmap_write(regmap, CS530X_IN_VOL_CTRL5, - CS530X_IN_VU); + CS530X_INOUT_VU); + default: + return -EINVAL; + } + + return 0; +} + +static SOC_ENUM_SINGLE_DECL(cs530x_ramp_out_inc_enum, CS530X_OUT_RAMP_SUM, + CS530X_RAMP_RATE_INC_SHIFT, + cs530x_vol_ramp_text); + +static SOC_ENUM_SINGLE_DECL(cs530x_ramp_out_dec_enum, CS530X_OUT_RAMP_SUM, + CS530X_RAMP_RATE_DEC_SHIFT, + cs530x_vol_ramp_text); + +static const struct snd_kcontrol_new cs530x_out_1_to_2_controls[] = { +SOC_SINGLE_EXT_TLV("OUT1 Volume", CS530X_OUT_VOL_CTRL1_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("OUT2 Volume", CS530X_OUT_VOL_CTRL1_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), + +SOC_ENUM("OUT DEC Filter Select", cs530x_out_filter_enum), +SOC_ENUM("Output Ramp Up", cs530x_ramp_out_inc_enum), +SOC_ENUM("Output Ramp Down", cs530x_ramp_out_dec_enum), + +SOC_SINGLE("DAC1 Invert Switch", CS530X_OUT_INV, CS530X_INOUT1_INV_SHIFT, 1, 0), +SOC_SINGLE("DAC2 Invert Switch", CS530X_OUT_INV, CS530X_INOUT2_INV_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new cs530x_out_3_to_4_controls[] = { +SOC_SINGLE_EXT_TLV("OUT3 Volume", CS530X_OUT_VOL_CTRL2_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("OUT4 Volume", CS530X_OUT_VOL_CTRL2_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), + +SOC_SINGLE("DAC3 Invert Switch", CS530X_OUT_INV, CS530X_INOUT3_INV_SHIFT, 1, 0), +SOC_SINGLE("DAC4 Invert Switch", CS530X_OUT_INV, CS530X_INOUT4_INV_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new cs530x_out_5_to_8_controls[] = { +SOC_SINGLE_EXT_TLV("OUT5 Volume", CS530X_OUT_VOL_CTRL3_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("OUT6 Volume", CS530X_OUT_VOL_CTRL3_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("OUT7 Volume", CS530X_OUT_VOL_CTRL4_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("OUT8 Volume", CS530X_OUT_VOL_CTRL4_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), + +SOC_SINGLE("DAC5 Invert Switch", CS530X_OUT_INV, CS530X_INOUT5_INV_SHIFT, 1, 0), +SOC_SINGLE("DAC6 Invert Switch", CS530X_OUT_INV, CS530X_INOUT6_INV_SHIFT, 1, 0), +SOC_SINGLE("DAC7 Invert Switch", CS530X_OUT_INV, CS530X_INOUT7_INV_SHIFT, 1, 0), +SOC_SINGLE("DAC8 Invert Switch", CS530X_OUT_INV, CS530X_INOUT8_INV_SHIFT, 1, 0), +}; + +static int cs530x_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + cs530x->dac_pairs_count++; + break; + case SND_SOC_DAPM_POST_PMU: + regmap_clear_bits(regmap, CS530X_OUT_VOL_CTRL1_0 + + (w->shift * 2), CS530X_INOUT_MUTE); + regmap_clear_bits(regmap, CS530X_OUT_VOL_CTRL1_0 + + ((w->shift + 1) * 2), CS530X_INOUT_MUTE); + + cs530x->dac_pairs_count--; + if (!cs530x->dac_pairs_count) { + usleep_range(1000, 1100); + return regmap_write(regmap, CS530X_OUT_VOL_CTRL5, + CS530X_INOUT_VU); + } + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_set_bits(regmap, CS530X_OUT_VOL_CTRL1_0 + + (w->shift * 2), CS530X_INOUT_MUTE); + regmap_set_bits(regmap, CS530X_OUT_VOL_CTRL1_0 + + ((w->shift + 1) * 2), CS530X_INOUT_MUTE); + return regmap_write(regmap, CS530X_OUT_VOL_CTRL5, + CS530X_INOUT_VU); default: return -EINVAL; } @@ -266,8 +397,18 @@ 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 dac12_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); +static const struct snd_kcontrol_new dac34_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); +static const struct snd_kcontrol_new dac56_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); +static const struct snd_kcontrol_new dac78_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); static const struct snd_kcontrol_new in_hpf_ctrl = SOC_DAPM_SINGLE_VIRT("Switch", 1); +static const struct snd_kcontrol_new out_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[] = { @@ -284,7 +425,7 @@ SND_SOC_DAPM_ADC_E("ADC1", NULL, CS530X_IN_ENABLES, 0, 0, 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, +SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_INOUT_HPF_EN_SHIFT, 0, &in_hpf_ctrl), }; @@ -408,6 +549,153 @@ static void cs530x_add_34_adc_widgets(struct snd_soc_component *component) ARRAY_SIZE(adc_ch3_4_routes)); } +/* DAC's Channels 1 and 2 plus generic DAC DAPM events */ +static const struct snd_soc_dapm_widget cs530x_dac_ch12_dapm_widgets[] = { +SND_SOC_DAPM_OUTPUT("OUT1"), +SND_SOC_DAPM_OUTPUT("OUT2"), +SND_SOC_DAPM_DAC_E("DAC1", NULL, CS530X_OUT_ENABLES, 0, 0, + cs530x_dac_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_DAC("DAC2", NULL, CS530X_OUT_ENABLES, 1, 0), +SND_SOC_DAPM_SWITCH("DAC12 Enable", SND_SOC_NOPM, 0, 0, &dac12_ctrl), +SND_SOC_DAPM_SWITCH("OUT HPF", CS530X_OUT_FILTER, CS530X_INOUT_HPF_EN_SHIFT, + 0, &out_hpf_ctrl), +}; + +/* DAC's Channels 3 and 4 */ +static const struct snd_soc_dapm_widget cs530x_dac_ch34_dapm_widgets[] = { +SND_SOC_DAPM_OUTPUT("OUT3"), +SND_SOC_DAPM_OUTPUT("OUT4"), +SND_SOC_DAPM_DAC_E("DAC3", NULL, CS530X_OUT_ENABLES, 2, 0, + cs530x_dac_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_DAC("DAC4", NULL, CS530X_OUT_ENABLES, 3, 0), +SND_SOC_DAPM_SWITCH("DAC34 Enable", SND_SOC_NOPM, 0, 0, &dac34_ctrl), +}; + +/* DAC's Channels 5 to 8 */ +static const struct snd_soc_dapm_widget cs530x_dac_ch58_dapm_widgets[] = { +SND_SOC_DAPM_OUTPUT("OUT5"), +SND_SOC_DAPM_OUTPUT("OUT6"), +SND_SOC_DAPM_OUTPUT("OUT7"), +SND_SOC_DAPM_OUTPUT("OUT8"), +SND_SOC_DAPM_DAC_E("DAC5", NULL, CS530X_OUT_ENABLES, 4, 0, + cs530x_dac_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_DAC("DAC6", NULL, CS530X_OUT_ENABLES, 5, 0), +SND_SOC_DAPM_SWITCH("DAC56 Enable", SND_SOC_NOPM, 0, 0, &dac56_ctrl), +SND_SOC_DAPM_DAC_E("DAC7", NULL, CS530X_OUT_ENABLES, 6, 0, + cs530x_dac_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_DAC("DAC8", NULL, CS530X_OUT_ENABLES, 7, 0), +SND_SOC_DAPM_SWITCH("DAC78 Enable", SND_SOC_NOPM, 0, 0, &dac78_ctrl), +}; + +static const struct snd_soc_dapm_route dac_ch1_2_routes[] = { + { "DAC1", NULL, "Global Enable" }, + { "DAC2", NULL, "Global Enable" }, + + { "DAC12 Enable", "Switch", "OUT1" }, + { "DAC12 Enable", "Switch", "OUT2" }, + { "DAC1", NULL, "DAC12 Enable" }, + { "DAC2", NULL, "DAC12 Enable" }, + { "OUT HPF", "Switch", "DAC1" }, + { "OUT HPF", "Switch", "DAC2" }, + + { "OUT HPF", NULL, "AIF Playback" }, + { "DAC1", NULL, "AIF Playback" }, + { "DAC2", NULL, "AIF Playback" }, + + { "OUT1", NULL, "DAC1" }, + { "OUT2", NULL, "DAC2" }, +}; + +static const struct snd_soc_dapm_route dac_ch3_4_routes[] = { + { "DAC3", NULL, "Global Enable" }, + { "DAC4", NULL, "Global Enable" }, + + { "DAC34 Enable", "Switch", "OUT3" }, + { "DAC34 Enable", "Switch", "OUT4" }, + { "DAC3", NULL, "DAC34 Enable" }, + { "DAC4", NULL, "DAC34 Enable" }, + { "OUT HPF", "Switch", "DAC3" }, + { "OUT HPF", "Switch", "DAC4" }, + + { "DAC3", NULL, "AIF Playback" }, + { "DAC4", NULL, "AIF Playback" }, + + { "OUT3", NULL, "DAC3" }, + { "OUT4", NULL, "DAC4" }, +}; + +static const struct snd_soc_dapm_route dac_ch5_8_routes[] = { + { "DAC5", NULL, "Global Enable" }, + { "DAC6", NULL, "Global Enable" }, + + { "DAC56 Enable", "Switch", "OUT5" }, + { "DAC56 Enable", "Switch", "OUT6" }, + { "DAC5", NULL, "DAC56 Enable" }, + { "DAC6", NULL, "DAC56 Enable" }, + { "OUT HPF", "Switch", "DAC5" }, + { "OUT HPF", "Switch", "DAC6" }, + + { "DAC5", NULL, "AIF Playback" }, + { "DAC6", NULL, "AIF Playback" }, + + { "OUT5", NULL, "DAC5" }, + { "OUT6", NULL, "DAC6" }, + + { "DAC7", NULL, "Global Enable" }, + { "DAC8", NULL, "Global Enable" }, + + { "DAC78 Enable", "Switch", "OUT7" }, + { "DAC78 Enable", "Switch", "OUT8" }, + { "DAC7", NULL, "DAC78 Enable" }, + { "DAC8", NULL, "DAC78 Enable" }, + { "OUT HPF", "Switch", "DAC7" }, + { "OUT HPF", "Switch", "DAC8" }, + + { "DAC7", NULL, "AIF Playback" }, + { "DAC8", NULL, "AIF Playback" }, + + { "OUT7", NULL, "DAC7" }, + { "OUT8", NULL, "DAC8" }, +}; + +static void cs530x_add_12_dac_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_out_1_to_2_controls, + ARRAY_SIZE(cs530x_out_1_to_2_controls)); + + snd_soc_dapm_new_controls(dapm, cs530x_dac_ch12_dapm_widgets, + ARRAY_SIZE(cs530x_dac_ch12_dapm_widgets)); + + snd_soc_dapm_add_routes(dapm, dac_ch1_2_routes, + ARRAY_SIZE(dac_ch1_2_routes)); +} + +static void cs530x_add_34_dac_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_out_3_to_4_controls, + ARRAY_SIZE(cs530x_out_3_to_4_controls)); + + snd_soc_dapm_new_controls(dapm, cs530x_dac_ch34_dapm_widgets, + ARRAY_SIZE(cs530x_dac_ch34_dapm_widgets)); + + snd_soc_dapm_add_routes(dapm, dac_ch3_4_routes, + ARRAY_SIZE(dac_ch3_4_routes)); +} + static int cs530x_set_bclk(struct snd_soc_component *component, const int freq) { struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); @@ -666,8 +954,11 @@ 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, + }, + .playback = { + .stream_name = "AIF Playback", .rates = SNDRV_PCM_RATE_KNOT, .formats = SNDRV_PCM_FMTBIT_S32_LE, }, @@ -722,6 +1013,43 @@ static int cs530x_component_probe(struct snd_soc_component *component) ARRAY_SIZE(cs530x_gen_dapm_widgets)); switch (cs530x->devtype) { + case CS4282: + cs530x_add_12_adc_widgets(component); + cs530x_add_12_dac_widgets(component); + break; + case CS4302: + cs530x_add_12_dac_widgets(component); + break; + case CS4304: + cs530x_add_12_dac_widgets(component); + cs530x_add_34_dac_widgets(component); + + num_widgets = ARRAY_SIZE(cs530x_out_sum_4ch_controls); + snd_soc_add_component_controls(component, + cs530x_out_sum_4ch_controls, + num_widgets); + break; + case CS4308: + cs530x_add_12_dac_widgets(component); + cs530x_add_34_dac_widgets(component); + + num_widgets = ARRAY_SIZE(cs530x_out_5_to_8_controls); + snd_soc_add_component_controls(component, + cs530x_out_5_to_8_controls, + num_widgets); + + num_widgets = ARRAY_SIZE(cs530x_out_sum_8ch_controls); + snd_soc_add_component_controls(component, + cs530x_out_sum_8ch_controls, + num_widgets); + + num_widgets = ARRAY_SIZE(cs530x_dac_ch58_dapm_widgets); + snd_soc_dapm_new_controls(dapm, cs530x_dac_ch58_dapm_widgets, + num_widgets); + + snd_soc_dapm_add_routes(dapm, dac_ch5_8_routes, + ARRAY_SIZE(dac_ch5_8_routes)); + break; case CS5302: cs530x_add_12_adc_widgets(component); break; @@ -825,9 +1153,20 @@ static int cs530x_check_device_id(struct cs530x_priv *cs530x) 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_CODEC_DEV_ID: + cs530x->num_dacs = 2; + cs530x->num_adcs = 2; + break; + case CS530X_2CH_DAC_DEV_ID: + cs530x->num_dacs = 2; + break; + case CS530X_4CH_DAC_DEV_ID: + cs530x->num_dacs = 4; + break; + case CS530X_8CH_DAC_DEV_ID: + cs530x->num_dacs = 8; + break; case CS530X_2CH_ADC_DEV_ID: cs530x->num_adcs = 2; break; @@ -842,6 +1181,9 @@ static int cs530x_check_device_id(struct cs530x_priv *cs530x) dev_id); } + dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x (%d in %d out)\n", dev_id, rev, + cs530x->num_adcs, cs530x->num_dacs); + return 0; } @@ -870,6 +1212,9 @@ static int cs530x_parse_device_properties(struct cs530x_priv *cs530x) val |= CS530X_IN12_HIZ; return regmap_set_bits(regmap, CS530X_IN_HIZ, val); + case 0: + /* No ADCs */ + return 0; default: return dev_err_probe(dev, -EINVAL, "Invalid number of adcs %d\n", @@ -932,7 +1277,15 @@ int cs530x_probe(struct cs530x_priv *cs530x) if (ret) goto err_reset; - cs530x->dev_dai->capture.channels_max = cs530x->num_adcs; + if (cs530x->num_adcs) { + cs530x->dev_dai->capture.channels_min = 2; + cs530x->dev_dai->capture.channels_max = cs530x->num_adcs; + } + + if (cs530x->num_dacs) { + cs530x->dev_dai->playback.channels_min = 2; + cs530x->dev_dai->playback.channels_max = cs530x->num_dacs; + } ret = devm_snd_soc_register_component(dev, &soc_component_dev_cs530x, diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index f7640161c77f..52fb148df36a 100644 --- a/sound/soc/codecs/cs530x.h +++ b/sound/soc/codecs/cs530x.h @@ -15,6 +15,10 @@ #include /* Devices */ +#define CS530X_2CH_CODEC_DEV_ID 0x4282 +#define CS530X_2CH_DAC_DEV_ID 0x4302 +#define CS530X_4CH_DAC_DEV_ID 0x4304 +#define CS530X_8CH_DAC_DEV_ID 0x4308 #define CS530X_2CH_ADC_DEV_ID 0x5302 #define CS530X_4CH_ADC_DEV_ID 0x5304 #define CS530X_8CH_ADC_DEV_ID 0x5308 @@ -45,6 +49,21 @@ #define CS530X_IN_VOL_CTRL4_1 0x000009E #define CS530X_IN_VOL_CTRL5 0x00000A0 +#define CS530X_OUT_ENABLES 0x00000C0 +#define CS530X_OUT_RAMP_SUM 0x00000C2 +#define CS530X_OUT_DEEMPH 0x00000C4 +#define CS530X_OUT_FILTER 0x00000C6 +#define CS530X_OUT_INV 0x00000CA +#define CS530X_OUT_VOL_CTRL1_0 0x00000D0 +#define CS530X_OUT_VOL_CTRL1_1 0x00000D2 +#define CS530X_OUT_VOL_CTRL2_0 0x00000D4 +#define CS530X_OUT_VOL_CTRL2_1 0x00000D6 +#define CS530X_OUT_VOL_CTRL3_0 0x00000D8 +#define CS530X_OUT_VOL_CTRL3_1 0x00000DA +#define CS530X_OUT_VOL_CTRL4_0 0x00000DC +#define CS530X_OUT_VOL_CTRL4_1 0x00000DE +#define CS530X_OUT_VOL_CTRL5 0x00000E0 + #define CS530X_PAD_FN 0x0003D24 #define CS530X_PAD_LVL 0x0003D28 @@ -132,14 +151,14 @@ #define CS530X_14_15_TDM_SLOT_MASK GENMASK(15, 14) #define CS530X_14_15_TDM_SLOT_VAL 7 -/* IN_RAMP_SUM */ +/* IN_RAMP_SUM and OUT_RAMP_SUM */ #define CS530X_RAMP_RATE_INC_SHIFT 0 #define CS530X_RAMP_RATE_DEC_SHIFT 4 -#define CS530X_IN_SUM_MODE_SHIFT 13 +#define CS530X_INOUT_SUM_MODE_SHIFT 13 -/* IN_FILTER */ -#define CS530X_IN_FILTER_SHIFT 8 -#define CS530X_IN_HPF_EN_SHIFT 12 +/* IN_FILTER and OUT_FILTER */ +#define CS530X_INOUT_FILTER_SHIFT 8 +#define CS530X_INOUT_HPF_EN_SHIFT 12 /* IN_HIZ */ #define CS530X_IN12_HIZ BIT(0) @@ -147,18 +166,18 @@ #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_INV and OUT_INV */ +#define CS530X_INOUT1_INV_SHIFT 0 +#define CS530X_INOUT2_INV_SHIFT 1 +#define CS530X_INOUT3_INV_SHIFT 2 +#define CS530X_INOUT4_INV_SHIFT 3 +#define CS530X_INOUT5_INV_SHIFT 4 +#define CS530X_INOUT6_INV_SHIFT 5 +#define CS530X_INOUT7_INV_SHIFT 6 +#define CS530X_INOUT8_INV_SHIFT 7 -/* IN_VOL_CTLy_z */ -#define CS530X_IN_MUTE BIT(15) +/* IN_VOL_CTLy_z and OUT_VOL_CTLy_z */ +#define CS530X_INOUT_MUTE BIT(15) /* IN_VOL_CTL5 */ #define CS530X_IN_VU BIT(0) @@ -178,6 +197,8 @@ #define CS530X_CONFIG3_LVL BIT(7) #define CS530X_CONFIG4_LVL BIT(8) #define CS530X_CONFIG5_LVL BIT(9) +/* IN_VOL_CTL5 and OUT_VOL_CTL5 */ +#define CS530X_INOUT_VU BIT(0) /* System Clock Source */ #define CS530X_SYSCLK_SRC_MCLK 0 @@ -190,6 +211,10 @@ #define CS530X_NUM_SUPPLIES 2 enum cs530x_type { + CS4282, + CS4302, + CS4304, + CS4308, CS5302, CS5304, CS5308, @@ -210,6 +235,7 @@ struct cs530x_priv { int tdm_width; int tdm_slots; int adc_pairs_count; + int dac_pairs_count; struct gpio_desc *reset_gpio; }; From 3941abb26ff327e53e1e8b873cab3ed3d5103eab Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Thu, 23 Oct 2025 10:03:15 +0100 Subject: [PATCH 07/12] ASoC: cs530x: Rename bitfield to reflect common use for ADC and DAC Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-8-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index 380405d3e3a8..abe3fe365425 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -141,8 +141,8 @@ static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol, 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); + /* Write INOUT_VU bit for the volume change to take effect */ + regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_INOUT_VU); volsw_err: snd_soc_dapm_mutex_unlock(dapm); From c37c3e5e390dcd52cbe6178ac53f5a6131ef6f8c Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Thu, 23 Oct 2025 10:03:16 +0100 Subject: [PATCH 08/12] ASoC: cs530x: Check the DEVID matches the devtype If the read device ID is not the expected devtype derived from the compatible device match then fail the probe as other configuration details may be incorrect. Signed-off-by: Simon Trimmer Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-9-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x.c | 6 ++++++ sound/soc/codecs/cs530x.h | 14 +++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index abe3fe365425..6552bef0577b 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -1181,6 +1181,12 @@ static int cs530x_check_device_id(struct cs530x_priv *cs530x) dev_id); } + if (cs530x->devtype != dev_id) { + dev_err(dev, "Read device ID 0x%x is not the expected devtype 0x%x\n", + dev_id, cs530x->devtype); + return -EINVAL; + } + dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x (%d in %d out)\n", dev_id, rev, cs530x->num_adcs, cs530x->num_dacs); diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index 52fb148df36a..d11711715ba8 100644 --- a/sound/soc/codecs/cs530x.h +++ b/sound/soc/codecs/cs530x.h @@ -211,13 +211,13 @@ #define CS530X_NUM_SUPPLIES 2 enum cs530x_type { - CS4282, - CS4302, - CS4304, - CS4308, - CS5302, - CS5304, - CS5308, + CS4282 = CS530X_2CH_CODEC_DEV_ID, + CS4302 = CS530X_2CH_DAC_DEV_ID, + CS4304 = CS530X_4CH_DAC_DEV_ID, + CS4308 = CS530X_8CH_DAC_DEV_ID, + CS5302 = CS530X_2CH_ADC_DEV_ID, + CS5304 = CS530X_4CH_ADC_DEV_ID, + CS5308 = CS530X_8CH_ADC_DEV_ID, }; /* codec private data */ From e7ab858390f24a23ba0827066382ba0e6a8e4379 Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Thu, 23 Oct 2025 10:03:17 +0100 Subject: [PATCH 09/12] ASoC: cs530x: Correct MCLK reference frequency values The MCLK frequency must be 49.152 MHz (for 48 kHz-related sample rates) or 45.1584 MHz (for 44.1 kHz-related sample rates). Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-10-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x.c | 9 ++++++--- sound/soc/codecs/cs530x.h | 6 ++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index 6552bef0577b..e74e6ffa7332 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -1100,9 +1100,12 @@ static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id, switch (source) { case CS530X_SYSCLK_SRC_MCLK: - if (freq != 24560000 && freq != 22572000) { - dev_err(component->dev, "Invalid MCLK source rate %d\n", - freq); + switch (freq) { + case CS530X_SYSCLK_REF_45_1MHZ: + case CS530X_SYSCLK_REF_49_1MHZ: + break; + default: + dev_err(component->dev, "Invalid MCLK source rate %d\n", freq); return -EINVAL; } break; diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index d11711715ba8..2c773c4b6b92 100644 --- a/sound/soc/codecs/cs530x.h +++ b/sound/soc/codecs/cs530x.h @@ -200,6 +200,12 @@ /* IN_VOL_CTL5 and OUT_VOL_CTL5 */ #define CS530X_INOUT_VU BIT(0) +/* MCLK Reference Source Frequency */ +/* 41KHz related */ +#define CS530X_SYSCLK_REF_45_1MHZ 45158400 +/* 48KHz related */ +#define CS530X_SYSCLK_REF_49_1MHZ 49152000 + /* System Clock Source */ #define CS530X_SYSCLK_SRC_MCLK 0 #define CS530X_SYSCLK_SRC_PLL 1 From 38ff69586bbb3a823dd501972e17075374b685a1 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Thu, 23 Oct 2025 10:03:18 +0100 Subject: [PATCH 10/12] ASoC: cs530x: Rename i2c related structures In preparation for SPI support these structures should be renamed to reflect that they are for i2c. Signed-off-by: Simon Trimmer Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-11-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs530x-i2c.c | 2 +- sound/soc/codecs/cs530x.c | 4 ++-- sound/soc/codecs/cs530x.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c index ab410826f777..52b02ceaa7e3 100644 --- a/sound/soc/codecs/cs530x-i2c.c +++ b/sound/soc/codecs/cs530x-i2c.c @@ -61,7 +61,7 @@ static int cs530x_i2c_probe(struct i2c_client *client) i2c_set_clientdata(client, cs530x); - cs530x->regmap = devm_regmap_init_i2c(client, &cs530x_regmap); + cs530x->regmap = devm_regmap_init_i2c(client, &cs530x_regmap_i2c); if (IS_ERR(cs530x->regmap)) return dev_err_probe(&client->dev, PTR_ERR(cs530x->regmap), "Failed to allocate register map\n"); diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index e74e6ffa7332..79f615d5b121 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -1128,7 +1128,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs530x = { .endianness = 1, }; -const struct regmap_config cs530x_regmap = { +const struct regmap_config cs530x_regmap_i2c = { .reg_bits = 16, .val_bits = 16, @@ -1140,7 +1140,7 @@ const struct regmap_config cs530x_regmap = { .reg_defaults = cs530x_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults), }; -EXPORT_SYMBOL_NS_GPL(cs530x_regmap, "SND_SOC_CS530X"); +EXPORT_SYMBOL_NS_GPL(cs530x_regmap_i2c, "SND_SOC_CS530X"); static int cs530x_check_device_id(struct cs530x_priv *cs530x) { diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index 2c773c4b6b92..2a7b7d01ecfb 100644 --- a/sound/soc/codecs/cs530x.h +++ b/sound/soc/codecs/cs530x.h @@ -246,7 +246,7 @@ struct cs530x_priv { struct gpio_desc *reset_gpio; }; -extern const struct regmap_config cs530x_regmap; +extern const struct regmap_config cs530x_regmap_i2c; int cs530x_probe(struct cs530x_priv *cs530x); #endif From bb65cb96f64e9b4ea2bbd41e4591f3da91414fdb Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Thu, 23 Oct 2025 10:03:19 +0100 Subject: [PATCH 11/12] ASoC: dt-bindings: sound: cirrus: cs530x: Add SPI bus support The CS530x device family supports multiple control interfaces. At present, only the I2C interface is implemented. Adding support for the SPI control interface, operating at up to 24 MHz. Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-12-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml index 04ed197f91eb..7600fff0e3b7 100644 --- a/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml +++ b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml @@ -15,6 +15,7 @@ description: allOf: - $ref: dai-common.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# properties: compatible: @@ -30,6 +31,9 @@ properties: reg: maxItems: 1 + spi-max-frequency: + maximum: 24000000 + '#sound-dai-cells': const: 1 From e7434adf0c53a84d548226304cdb41c8818da1cb Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Thu, 23 Oct 2025 10:03:20 +0100 Subject: [PATCH 12/12] ASoC: cs530x: Add SPI bus support for cs530x parts Cirrus Logic cs530x device family has 2 control buses I2C and SPI. This patch adds SPI support. Signed-off-by: Vitaly Rodionov Link: https://patch.msgid.link/20251023090327.58275-13-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 10 ++++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs530x-spi.c | 92 +++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs530x.c | 21 ++++++++ sound/soc/codecs/cs530x.h | 1 + 5 files changed, 126 insertions(+) create mode 100644 sound/soc/codecs/cs530x-spi.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 160c07699a8b..ef49f71e8b34 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -106,6 +106,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS48L32 imply SND_SOC_CS53L30 imply SND_SOC_CS530X_I2C + imply SND_SOC_CS530X_SPI imply SND_SOC_CX20442 imply SND_SOC_CX2072X imply SND_SOC_DA7210 @@ -1082,6 +1083,15 @@ config SND_SOC_CS530X_I2C Enable support for Cirrus Logic CS530X ADCs with I2C control. +config SND_SOC_CS530X_SPI + tristate "Cirrus Logic CS530x ADCs (SPI)" + depends on SPI_MASTER + select REGMAP_SPI + select SND_SOC_CS530X + help + Enable support for Cirrus Logic CS530X ADCs + with SPI control. + config SND_SOC_CX20442 tristate depends on TTY diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index bd95a7c911d5..39138d96a720 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -115,6 +115,7 @@ snd-soc-cs48l32-y := cs48l32.o cs48l32-tables.o snd-soc-cs53l30-y := cs53l30.o snd-soc-cs530x-y := cs530x.o snd-soc-cs530x-i2c-y := cs530x-i2c.o +snd-soc-cs530x-spi-y := cs530x-spi.o snd-soc-cx20442-y := cx20442.o snd-soc-cx2072x-y := cx2072x.o snd-soc-da7210-y := da7210.o @@ -546,6 +547,7 @@ obj-$(CONFIG_SND_SOC_CS48L32) += snd-soc-cs48l32.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_CS530X_SPI) += snd-soc-cs530x-spi.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-spi.c b/sound/soc/codecs/cs530x-spi.c new file mode 100644 index 000000000000..dbf1e7bbec19 --- /dev/null +++ b/sound/soc/codecs/cs530x-spi.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS530x CODEC driver +// +// Copyright (C) 2025 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include + +#include "cs530x.h" + +static const struct of_device_id cs530x_of_match[] = { + { + .compatible = "cirrus,cs4282", + .data = (void *)CS4282, + }, { + .compatible = "cirrus,cs4302", + .data = (void *)CS4302, + }, { + .compatible = "cirrus,cs4304", + .data = (void *)CS4304, + }, { + .compatible = "cirrus,cs4308", + .data = (void *)CS4308, + }, { + .compatible = "cirrus,cs5302", + .data = (void *)CS5302, + }, { + .compatible = "cirrus,cs5304", + .data = (void *)CS5304, + }, { + .compatible = "cirrus,cs5304", + .data = (void *)CS5308, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cs530x_of_match); + +static const struct spi_device_id cs530x_spi_id[] = { + { "cs4282", CS4282 }, + { "cs4302", CS4302 }, + { "cs4304", CS4304 }, + { "cs4308", CS4308 }, + { "cs5302", CS5302 }, + { "cs5304", CS5304 }, + { "cs5308", CS5308 }, + { } +}; +MODULE_DEVICE_TABLE(spi, cs530x_spi_id); + +static int cs530x_spi_probe(struct spi_device *spi) +{ + struct cs530x_priv *cs530x; + struct device *dev = &spi->dev; + int ret; + + cs530x = devm_kzalloc(dev, sizeof(struct cs530x_priv), GFP_KERNEL); + if (cs530x == NULL) + return -ENOMEM; + + spi_set_drvdata(spi, cs530x); + + cs530x->regmap = devm_regmap_init_spi(spi, &cs530x_regmap_spi); + if (IS_ERR(cs530x->regmap)) { + ret = PTR_ERR(cs530x->regmap); + dev_err(dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + + cs530x->devtype = (unsigned long)spi_get_device_match_data(spi); + cs530x->dev = &spi->dev; + + return cs530x_probe(cs530x); +} + +static struct spi_driver cs530x_spi_driver = { + .driver = { + .name = "cs530x", + .of_match_table = cs530x_of_match, + }, + .id_table = cs530x_spi_id, + .probe = cs530x_spi_probe, +}; + +module_spi_driver(cs530x_spi_driver); + +MODULE_DESCRIPTION("SPI CS530X driver"); +MODULE_IMPORT_NS("SND_SOC_CS530X"); +MODULE_AUTHOR("Vitaly Rodionov "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index 79f615d5b121..d052fd324143 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1142,6 +1143,26 @@ const struct regmap_config cs530x_regmap_i2c = { }; EXPORT_SYMBOL_NS_GPL(cs530x_regmap_i2c, "SND_SOC_CS530X"); +const struct regmap_config cs530x_regmap_spi = { + .reg_bits = 16, + .pad_bits = 16, + .val_bits = 16, + + .reg_stride = 2, + + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = CS530X_MAX_REGISTER, + .writeable_reg = cs530x_writeable_register, + .readable_reg = cs530x_readable_register, + + .cache_type = REGCACHE_MAPLE, + .reg_defaults = cs530x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults), +}; +EXPORT_SYMBOL_NS_GPL(cs530x_regmap_spi, "SND_SOC_CS530X"); + static int cs530x_check_device_id(struct cs530x_priv *cs530x) { struct device *dev = cs530x->dev; diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index 2a7b7d01ecfb..1e2f6a7a589c 100644 --- a/sound/soc/codecs/cs530x.h +++ b/sound/soc/codecs/cs530x.h @@ -247,6 +247,7 @@ struct cs530x_priv { }; extern const struct regmap_config cs530x_regmap_i2c; +extern const struct regmap_config cs530x_regmap_spi; int cs530x_probe(struct cs530x_priv *cs530x); #endif