diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml index 9582eb8eb418..7600fff0e3b7 100644 --- a/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml +++ b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml @@ -15,10 +15,15 @@ description: allOf: - $ref: dai-common.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# properties: compatible: enum: + - cirrus,cs4282 + - cirrus,cs4302 + - cirrus,cs4304 + - cirrus,cs4308 - cirrus,cs5302 - cirrus,cs5304 - cirrus,cs5308 @@ -26,6 +31,9 @@ properties: reg: maxItems: 1 + spi-max-frequency: + maximum: 24000000 + '#sound-dai-cells': const: 1 diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 1e649da53ed9..a0dfef57200c 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 @@ -1100,6 +1101,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-i2c.c b/sound/soc/codecs/cs530x-i2c.c index 22b1a4d6b61c..52b02ceaa7e3 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 @@ -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 }, @@ -45,10 +61,10 @@ 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"); + "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-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 0dbc5fb92290..f8f409d0b035 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -2,28 +2,26 @@ // // 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 #include #include -#include #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", @@ -48,6 +46,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 }, }; @@ -73,6 +83,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; @@ -97,6 +120,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); @@ -104,7 +128,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_kcontrol_chip(kcontrol); struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); @@ -118,8 +142,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); @@ -129,7 +153,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", @@ -137,24 +161,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", @@ -162,13 +198,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", @@ -193,8 +236,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[] = { @@ -203,8 +246,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[] = { @@ -217,14 +260,14 @@ 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, - 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,24 +279,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; } @@ -263,18 +392,24 @@ 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 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[] = { @@ -291,7 +426,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), }; @@ -415,6 +550,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); @@ -450,7 +732,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,37 +774,35 @@ 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; 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); return -EINVAL; } - cs530x->fs = fs; regmap_update_bits(regmap, CS530X_CLK_CFG_1, CS530X_SAMPLE_RATE_MASK, fs_val); @@ -540,7 +820,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 +894,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); @@ -675,8 +955,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, }, @@ -686,8 +969,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; @@ -731,6 +1014,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; @@ -743,7 +1063,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,20 +1094,21 @@ 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; 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; } - - cs530x->mclk_rate = freq; break; case CS530X_SYSCLK_SRC_PLL: break; @@ -809,7 +1129,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, @@ -821,7 +1141,27 @@ 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"); + +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) { @@ -837,9 +1177,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; @@ -854,6 +1205,15 @@ 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); + return 0; } @@ -882,6 +1242,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", @@ -895,8 +1258,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 +1277,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; } @@ -944,10 +1307,19 @@ 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, 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; diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h index f473e33eb835..1e2f6a7a589c 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. */ @@ -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 @@ -73,11 +92,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) @@ -99,7 +118,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) @@ -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,14 @@ #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) + +/* 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 @@ -190,9 +217,13 @@ #define CS530X_NUM_SUPPLIES 2 enum cs530x_type { - 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 */ @@ -207,17 +238,16 @@ 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; + int dac_pairs_count; struct gpio_desc *reset_gpio; }; -extern const struct regmap_config cs530x_regmap; +extern const struct regmap_config cs530x_regmap_i2c; +extern const struct regmap_config cs530x_regmap_spi; int cs530x_probe(struct cs530x_priv *cs530x); #endif