Add support for Cirrus Logic CS530x DAC and CODEC

Merge series from Vitaly Rodionov <vitalyr@opensource.cirrus.com>:

This patch series introduces DAC, CODEC, and SPI control bus support
for Cirrus Logic CS530x variants, along with general code cleanup
and resolution of checkpatch.pl warnings.
This commit is contained in:
Mark Brown
2025-10-28 14:27:55 +00:00
7 changed files with 636 additions and 106 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <linux/device.h>
#include <linux/module.h>
@@ -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;

View File

@@ -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 <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#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 <vitalyr@opensource.cirrus.com>");
MODULE_LICENSE("GPL");

View File

@@ -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 <sound/core.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <sound/initval.h>
#include <linux/module.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <linux/pm.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#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 @@ volsw_err:
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;

View File

@@ -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 <linux/regulator/consumer.h>
/* 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