mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 11:03:43 +02:00
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:
parent
9957614d2b
commit
c63b2315b9
|
|
@ -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,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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user