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 <simont@opensource.cirrus.com>
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
Link: https://patch.msgid.link/20251023090327.58275-7-vitalyr@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Simon Trimmer 2025-10-23 10:03:14 +01:00 committed by Mark Brown
parent 9957614d2b
commit c63b2315b9
3 changed files with 440 additions and 45 deletions

View File

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

View File

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

View File

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