Skip to content

Commit 9788587

Browse files
Stefan Bindingbroonie
authored andcommitted
ASoC: cs35l56: Add initial support for CS35L63 for I2C and SoundWire
CS35L63 uses a similar control interface to CS35L56 so support for it can be added into the CS35L56 driver. New regmap configs have been added to support CS35L63. CS35L63 only has SoundWire and I2C control interfaces. Signed-off-by: Stefan Binding <[email protected]> Reviewed-by: Richard Fitzgerald <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent a3ec669 commit 9788587

File tree

6 files changed

+237
-2
lines changed

6 files changed

+237
-2
lines changed

include/sound/cs35l56.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@
104104
#define CS35L56_DSP1_PMEM_0 0x3800000
105105
#define CS35L56_DSP1_PMEM_5114 0x3804FE8
106106

107+
#define CS35L63_DSP1_FW_VER CS35L56_DSP1_FW_VER
108+
#define CS35L63_DSP1_HALO_STATE 0x280396C
109+
#define CS35L63_DSP1_PM_CUR_STATE 0x28042C8
110+
#define CS35L63_PROTECTION_STATUS 0x340009C
111+
#define CS35L63_TRANSDUCER_ACTUAL_PS 0x34000F4
112+
#define CS35L63_MAIN_RENDER_USER_MUTE 0x3400020
113+
#define CS35L63_MAIN_RENDER_USER_VOLUME 0x3400028
114+
#define CS35L63_MAIN_POSTURE_NUMBER 0x3400068
115+
107116
/* DEVID */
108117
#define CS35L56_DEVID_MASK 0x00FFFFFF
109118

@@ -322,8 +331,11 @@ static inline bool cs35l56_is_spi(struct cs35l56_base *cs35l56)
322331
extern const struct regmap_config cs35l56_regmap_i2c;
323332
extern const struct regmap_config cs35l56_regmap_spi;
324333
extern const struct regmap_config cs35l56_regmap_sdw;
334+
extern const struct regmap_config cs35l63_regmap_i2c;
335+
extern const struct regmap_config cs35l63_regmap_sdw;
325336

326337
extern const struct cs35l56_fw_reg cs35l56_fw_reg;
338+
extern const struct cs35l56_fw_reg cs35l63_fw_reg;
327339

328340
extern const struct cirrus_amp_cal_controls cs35l56_calibration_controls;
329341

sound/soc/codecs/cs35l56-i2c.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ static int cs35l56_i2c_probe(struct i2c_client *client)
3737
regmap_config = &cs35l56_regmap_i2c;
3838
cs35l56->base.fw_reg = &cs35l56_fw_reg;
3939
break;
40+
case 0x3563:
41+
regmap_config = &cs35l63_regmap_i2c;
42+
cs35l56->base.fw_reg = &cs35l63_fw_reg;
43+
break;
4044
default:
4145
return -ENODEV;
4246
}
@@ -69,13 +73,15 @@ static void cs35l56_i2c_remove(struct i2c_client *client)
6973

7074
static const struct i2c_device_id cs35l56_id_i2c[] = {
7175
{ "cs35l56", 0x3556 },
76+
{ "cs35l63", 0x3563 },
7277
{}
7378
};
7479
MODULE_DEVICE_TABLE(i2c, cs35l56_id_i2c);
7580

7681
#ifdef CONFIG_ACPI
7782
static const struct acpi_device_id cs35l56_asoc_acpi_match[] = {
7883
{ "CSC355C", 0x3556 },
84+
{ "CSC356C", 0x3563 },
7985
{},
8086
};
8187
MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match);

sound/soc/codecs/cs35l56-sdw.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,74 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral,
393393
return 0;
394394
}
395395

396+
static int cs35l63_sdw_kick_divider(struct cs35l56_private *cs35l56,
397+
struct sdw_slave *peripheral)
398+
{
399+
unsigned int curr_scale_reg, next_scale_reg;
400+
int curr_scale, next_scale, ret;
401+
402+
if (!cs35l56->base.init_done)
403+
return 0;
404+
405+
if (peripheral->bus->params.curr_bank) {
406+
curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1;
407+
next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0;
408+
} else {
409+
curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0;
410+
next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1;
411+
}
412+
413+
/*
414+
* Current clock scale value must be different to new value.
415+
* Modify current to guarantee this. If next still has the dummy
416+
* value we wrote when it was current, the core code has not set
417+
* a new scale so restore its original good value
418+
*/
419+
curr_scale = sdw_read_no_pm(peripheral, curr_scale_reg);
420+
if (curr_scale < 0) {
421+
dev_err(cs35l56->base.dev, "Failed to read current clock scale: %d\n", curr_scale);
422+
return curr_scale;
423+
}
424+
425+
next_scale = sdw_read_no_pm(peripheral, next_scale_reg);
426+
if (next_scale < 0) {
427+
dev_err(cs35l56->base.dev, "Failed to read next clock scale: %d\n", next_scale);
428+
return next_scale;
429+
}
430+
431+
if (next_scale == CS35L56_SDW_INVALID_BUS_SCALE) {
432+
next_scale = cs35l56->old_sdw_clock_scale;
433+
ret = sdw_write_no_pm(peripheral, next_scale_reg, next_scale);
434+
if (ret < 0) {
435+
dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n",
436+
ret);
437+
return ret;
438+
}
439+
}
440+
441+
cs35l56->old_sdw_clock_scale = curr_scale;
442+
ret = sdw_write_no_pm(peripheral, curr_scale_reg, CS35L56_SDW_INVALID_BUS_SCALE);
443+
if (ret < 0) {
444+
dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", ret);
445+
return ret;
446+
}
447+
448+
dev_dbg(cs35l56->base.dev, "Next bus scale: %#x\n", next_scale);
449+
450+
return 0;
451+
}
452+
453+
static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral,
454+
struct sdw_bus_params *params)
455+
{
456+
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
457+
458+
if ((cs35l56->base.type == 0x63) && (cs35l56->base.rev < 0xa1))
459+
return cs35l63_sdw_kick_divider(cs35l56, peripheral);
460+
461+
return 0;
462+
}
463+
396464
static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral,
397465
enum sdw_clk_stop_mode mode,
398466
enum sdw_clk_stop_type type)
@@ -408,6 +476,7 @@ static const struct sdw_slave_ops cs35l56_sdw_ops = {
408476
.read_prop = cs35l56_sdw_read_prop,
409477
.interrupt_callback = cs35l56_sdw_interrupt,
410478
.update_status = cs35l56_sdw_update_status,
479+
.bus_config = cs35l56_sdw_bus_config,
411480
#ifdef DEBUG
412481
.clk_stop = cs35l56_sdw_clk_stop,
413482
#endif
@@ -528,6 +597,10 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi
528597
regmap_config = &cs35l56_regmap_sdw;
529598
cs35l56->base.fw_reg = &cs35l56_fw_reg;
530599
break;
600+
case 0x3563:
601+
regmap_config = &cs35l63_regmap_sdw;
602+
cs35l56->base.fw_reg = &cs35l63_fw_reg;
603+
break;
531604
default:
532605
return -ENODEV;
533606
}
@@ -575,6 +648,7 @@ static const struct dev_pm_ops cs35l56_sdw_pm = {
575648
static const struct sdw_device_id cs35l56_sdw_id[] = {
576649
SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0x3556),
577650
SDW_SLAVE_ENTRY(0x01FA, 0x3557, 0x3557),
651+
SDW_SLAVE_ENTRY(0x01FA, 0x3563, 0x3563),
578652
{},
579653
};
580654
MODULE_DEVICE_TABLE(sdw, cs35l56_sdw_id);

sound/soc/codecs/cs35l56-shared.c

Lines changed: 121 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ static const struct reg_sequence cs35l56_patch_fw[] = {
4747
{ CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 },
4848
};
4949

50+
static const struct reg_sequence cs35l63_patch_fw[] = {
51+
/* These are not reset by a soft-reset, so patch to defaults. */
52+
{ CS35L63_MAIN_RENDER_USER_MUTE, 0x00000000 },
53+
{ CS35L63_MAIN_RENDER_USER_VOLUME, 0x00000000 },
54+
{ CS35L63_MAIN_POSTURE_NUMBER, 0x00000000 },
55+
};
56+
5057
int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
5158
{
5259
int ret;
@@ -64,6 +71,10 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
6471
ret = regmap_register_patch(cs35l56_base->regmap, cs35l56_patch_fw,
6572
ARRAY_SIZE(cs35l56_patch_fw));
6673
break;
74+
case 0x63:
75+
ret = regmap_register_patch(cs35l56_base->regmap, cs35l63_patch_fw,
76+
ARRAY_SIZE(cs35l63_patch_fw));
77+
break;
6778
default:
6879
break;
6980
}
@@ -102,6 +113,36 @@ static const struct reg_default cs35l56_reg_defaults[] = {
102113
{ CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 },
103114
};
104115

116+
static const struct reg_default cs35l63_reg_defaults[] = {
117+
/* no defaults for OTP_MEM - first read populates cache */
118+
119+
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
120+
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
121+
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
122+
{ CS35L56_ASP1_CONTROL3, 0x00000002 },
123+
{ CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
124+
{ CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
125+
{ CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
126+
{ CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
127+
{ CS35L56_ASP1TX1_INPUT, 0x00000000 },
128+
{ CS35L56_ASP1TX2_INPUT, 0x00000000 },
129+
{ CS35L56_ASP1TX3_INPUT, 0x00000000 },
130+
{ CS35L56_ASP1TX4_INPUT, 0x00000000 },
131+
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
132+
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
133+
{ CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
134+
{ CS35L56_SWIRE_DP3_CH4_INPUT, 0x00000028 },
135+
{ CS35L56_IRQ1_MASK_1, 0x8003ffff },
136+
{ CS35L56_IRQ1_MASK_2, 0xffff7fff },
137+
{ CS35L56_IRQ1_MASK_4, 0xe0ffffff },
138+
{ CS35L56_IRQ1_MASK_8, 0x8c000fff },
139+
{ CS35L56_IRQ1_MASK_18, 0x0760f000 },
140+
{ CS35L56_IRQ1_MASK_20, 0x15c00000 },
141+
{ CS35L63_MAIN_RENDER_USER_MUTE, 0x00000000 },
142+
{ CS35L63_MAIN_RENDER_USER_VOLUME, 0x00000000 },
143+
{ CS35L63_MAIN_POSTURE_NUMBER, 0x00000000 },
144+
};
145+
105146
static bool cs35l56_is_dsp_memory(unsigned int reg)
106147
{
107148
switch (reg) {
@@ -199,7 +240,7 @@ static bool cs35l56_precious_reg(struct device *dev, unsigned int reg)
199240
}
200241
}
201242

202-
static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
243+
static bool cs35l56_common_volatile_reg(unsigned int reg)
203244
{
204245
switch (reg) {
205246
case CS35L56_DEVID:
@@ -237,12 +278,32 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
237278
case CS35L56_DSP1_SCRATCH3:
238279
case CS35L56_DSP1_SCRATCH4:
239280
return true;
281+
default:
282+
return cs35l56_is_dsp_memory(reg);
283+
}
284+
}
285+
286+
static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
287+
{
288+
switch (reg) {
240289
case CS35L56_MAIN_RENDER_USER_MUTE:
241290
case CS35L56_MAIN_RENDER_USER_VOLUME:
242291
case CS35L56_MAIN_POSTURE_NUMBER:
243292
return false;
244293
default:
245-
return cs35l56_is_dsp_memory(reg);
294+
return cs35l56_common_volatile_reg(reg);
295+
}
296+
}
297+
298+
static bool cs35l63_volatile_reg(struct device *dev, unsigned int reg)
299+
{
300+
switch (reg) {
301+
case CS35L63_MAIN_RENDER_USER_MUTE:
302+
case CS35L63_MAIN_RENDER_USER_VOLUME:
303+
case CS35L63_MAIN_POSTURE_NUMBER:
304+
return false;
305+
default:
306+
return cs35l56_common_volatile_reg(reg);
246307
}
247308
}
248309

@@ -405,6 +466,11 @@ static const struct reg_sequence cs35l56_system_reset_seq[] = {
405466
REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
406467
};
407468

469+
static const struct reg_sequence cs35l63_system_reset_seq[] = {
470+
REG_SEQ0(CS35L63_DSP1_HALO_STATE, 0),
471+
REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
472+
};
473+
408474
void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
409475
{
410476
/*
@@ -426,6 +492,11 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
426492
cs35l56_system_reset_seq,
427493
ARRAY_SIZE(cs35l56_system_reset_seq));
428494
break;
495+
case 0x63:
496+
regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
497+
cs35l63_system_reset_seq,
498+
ARRAY_SIZE(cs35l63_system_reset_seq));
499+
break;
429500
default:
430501
break;
431502
}
@@ -844,6 +915,9 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
844915
case 0x35A56:
845916
case 0x35A57:
846917
break;
918+
case 0x35A630:
919+
devid = devid >> 4;
920+
break;
847921
default:
848922
dev_err(cs35l56_base->dev, "Unknown device %x\n", devid);
849923
return ret;
@@ -1080,6 +1154,39 @@ const struct regmap_config cs35l56_regmap_sdw = {
10801154
};
10811155
EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, "SND_SOC_CS35L56_SHARED");
10821156

1157+
const struct regmap_config cs35l63_regmap_i2c = {
1158+
.reg_bits = 32,
1159+
.val_bits = 32,
1160+
.reg_stride = 4,
1161+
.reg_base = 0x8000,
1162+
.reg_format_endian = REGMAP_ENDIAN_BIG,
1163+
.val_format_endian = REGMAP_ENDIAN_BIG,
1164+
.max_register = CS35L56_DSP1_PMEM_5114,
1165+
.reg_defaults = cs35l63_reg_defaults,
1166+
.num_reg_defaults = ARRAY_SIZE(cs35l63_reg_defaults),
1167+
.volatile_reg = cs35l63_volatile_reg,
1168+
.readable_reg = cs35l56_readable_reg,
1169+
.precious_reg = cs35l56_precious_reg,
1170+
.cache_type = REGCACHE_MAPLE,
1171+
};
1172+
EXPORT_SYMBOL_NS_GPL(cs35l63_regmap_i2c, "SND_SOC_CS35L56_SHARED");
1173+
1174+
const struct regmap_config cs35l63_regmap_sdw = {
1175+
.reg_bits = 32,
1176+
.val_bits = 32,
1177+
.reg_stride = 4,
1178+
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
1179+
.val_format_endian = REGMAP_ENDIAN_BIG,
1180+
.max_register = CS35L56_DSP1_PMEM_5114,
1181+
.reg_defaults = cs35l63_reg_defaults,
1182+
.num_reg_defaults = ARRAY_SIZE(cs35l63_reg_defaults),
1183+
.volatile_reg = cs35l63_volatile_reg,
1184+
.readable_reg = cs35l56_readable_reg,
1185+
.precious_reg = cs35l56_precious_reg,
1186+
.cache_type = REGCACHE_MAPLE,
1187+
};
1188+
EXPORT_SYMBOL_NS_GPL(cs35l63_regmap_sdw, "SND_SOC_CS35L56_SHARED");
1189+
10831190
const struct cs35l56_fw_reg cs35l56_fw_reg = {
10841191
.fw_ver = CS35L56_DSP1_FW_VER,
10851192
.halo_state = CS35L56_DSP1_HALO_STATE,
@@ -1092,6 +1199,18 @@ const struct cs35l56_fw_reg cs35l56_fw_reg = {
10921199
};
10931200
EXPORT_SYMBOL_NS_GPL(cs35l56_fw_reg, "SND_SOC_CS35L56_SHARED");
10941201

1202+
const struct cs35l56_fw_reg cs35l63_fw_reg = {
1203+
.fw_ver = CS35L63_DSP1_FW_VER,
1204+
.halo_state = CS35L63_DSP1_HALO_STATE,
1205+
.pm_cur_stat = CS35L63_DSP1_PM_CUR_STATE,
1206+
.prot_sts = CS35L63_PROTECTION_STATUS,
1207+
.transducer_actual_ps = CS35L63_TRANSDUCER_ACTUAL_PS,
1208+
.user_mute = CS35L63_MAIN_RENDER_USER_MUTE,
1209+
.user_volume = CS35L63_MAIN_RENDER_USER_VOLUME,
1210+
.posture_number = CS35L63_MAIN_POSTURE_NUMBER,
1211+
};
1212+
EXPORT_SYMBOL_NS_GPL(cs35l63_fw_reg, "SND_SOC_CS35L56_SHARED");
1213+
10951214
MODULE_DESCRIPTION("ASoC CS35L56 Shared");
10961215
MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");
10971216
MODULE_AUTHOR("Simon Trimmer <[email protected]>");

sound/soc/codecs/cs35l56.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,25 @@ static const struct snd_kcontrol_new cs35l56_controls[] = {
8484
cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
8585
};
8686

87+
static const struct snd_kcontrol_new cs35l63_controls[] = {
88+
SOC_SINGLE_EXT("Speaker Switch",
89+
CS35L63_MAIN_RENDER_USER_MUTE, 0, 1, 1,
90+
cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
91+
SOC_SINGLE_S_EXT_TLV("Speaker Volume",
92+
CS35L63_MAIN_RENDER_USER_VOLUME,
93+
CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT,
94+
CS35L56_MAIN_RENDER_USER_VOLUME_MIN,
95+
CS35L56_MAIN_RENDER_USER_VOLUME_MAX,
96+
CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT,
97+
0,
98+
cs35l56_dspwait_get_volsw,
99+
cs35l56_dspwait_put_volsw,
100+
vol_tlv),
101+
SOC_SINGLE_EXT("Posture Number", CS35L63_MAIN_POSTURE_NUMBER,
102+
0, 255, 0,
103+
cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
104+
};
105+
87106
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx1_enum,
88107
CS35L56_ASP1TX1_INPUT,
89108
0, CS35L56_ASP_TXn_SRC_MASK,
@@ -886,6 +905,10 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
886905
ret = snd_soc_add_component_controls(component, cs35l56_controls,
887906
ARRAY_SIZE(cs35l56_controls));
888907
break;
908+
case 0x63:
909+
ret = snd_soc_add_component_controls(component, cs35l63_controls,
910+
ARRAY_SIZE(cs35l63_controls));
911+
break;
889912
default:
890913
ret = -ENODEV;
891914
break;

sound/soc/codecs/cs35l56.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct cs35l56_private {
5151
u8 asp_slot_count;
5252
bool tdm_mode;
5353
bool sysclk_set;
54+
u8 old_sdw_clock_scale;
5455
};
5556

5657
extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi;

0 commit comments

Comments
 (0)