Skip to content

Commit b831b4d

Browse files
mstrozekbroonie
authored andcommitted
ASoC: intel: sof_sdw: Add support for cs42l43-cs35l56 sidecar amps
The cs42l43 has both a SPI master and an I2S interface, these can be used to populate 2 cs35l56 amplifiers as sidecar devices along side the cs42l43. Giving a system that looks like: +-----+ +---------+ <- SPI -> +---------+ | CPU | <- SDW -> | CS42L43 | | CS35L56 | +-----+ +---------+ <- I2S -> +---------+ Add a quirk to specify this feature is present and use it to add codec to codec DAI link to connect the amplifiers into the sound card, add appropriate widgets, and setup clocking on the amplifiers. Reviewed-by: Bard Liao <[email protected]> Signed-off-by: Maciej Strozek <[email protected]> Signed-off-by: Charles Keepax <[email protected]> Signed-off-by: Pierre-Louis Bossart <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent da52441 commit b831b4d

File tree

6 files changed

+173
-6
lines changed

6 files changed

+173
-6
lines changed

sound/soc/intel/boards/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
690690
select SND_SOC_CS42L43_SDW
691691
select MFD_CS42L43
692692
select MFD_CS42L43_SDW
693+
select SND_SOC_CS35L56_SPI
693694
select SND_SOC_CS35L56_SDW
694695
select SND_SOC_DMIC
695696
select SND_SOC_INTEL_HDA_DSP_COMMON

sound/soc/intel/boards/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ snd-soc-ehl-rt5660-objs := ehl_rt5660.o
3737
snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o
3838
snd-soc-sof-sdw-objs += sof_sdw.o \
3939
sof_sdw_maxim.o sof_sdw_rt_amp.o \
40+
bridge_cs35l56.o \
4041
sof_sdw_rt5682.o sof_sdw_rt700.o \
4142
sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \
4243
sof_sdw_rt712_sdca.o sof_sdw_rt722_sdca.o \
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
//
3+
// Intel SOF Machine Driver with Cirrus Logic CS35L56 Smart Amp
4+
5+
#include <linux/module.h>
6+
#include <linux/platform_device.h>
7+
#include <sound/core.h>
8+
#include <sound/pcm.h>
9+
#include <sound/pcm_params.h>
10+
#include <sound/soc.h>
11+
#include <sound/soc-acpi.h>
12+
#include "sof_sdw_common.h"
13+
14+
static const struct snd_soc_dapm_widget bridge_widgets[] = {
15+
SND_SOC_DAPM_SPK("Bridge Speaker", NULL),
16+
};
17+
18+
static const struct snd_soc_dapm_route bridge_map[] = {
19+
{"Bridge Speaker", NULL, "AMPL SPK"},
20+
{"Bridge Speaker", NULL, "AMPR SPK"},
21+
};
22+
23+
static const char * const bridge_cs35l56_name_prefixes[] = {
24+
"AMPL",
25+
"AMPR",
26+
};
27+
28+
static int bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd)
29+
{
30+
struct snd_soc_card *card = rtd->card;
31+
int i, ret;
32+
unsigned int rx_mask = 3; // ASP RX1, RX2
33+
unsigned int tx_mask = 3; // ASP TX1, TX2
34+
struct snd_soc_dai *codec_dai;
35+
struct snd_soc_dai *cpu_dai;
36+
37+
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
38+
"%s spk:cs35l56-bridge",
39+
card->components);
40+
if (!card->components)
41+
return -ENOMEM;
42+
43+
ret = snd_soc_dapm_new_controls(&card->dapm, bridge_widgets,
44+
ARRAY_SIZE(bridge_widgets));
45+
if (ret) {
46+
dev_err(card->dev, "widgets addition failed: %d\n", ret);
47+
return ret;
48+
}
49+
50+
ret = snd_soc_dapm_add_routes(&card->dapm, bridge_map, ARRAY_SIZE(bridge_map));
51+
if (ret) {
52+
dev_err(card->dev, "map addition failed: %d\n", ret);
53+
return ret;
54+
}
55+
56+
/* 4 x 16-bit sample slots and FSYNC=48000, BCLK=3.072 MHz */
57+
for_each_rtd_codec_dais(rtd, i, codec_dai) {
58+
ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask, rx_mask, 4, 16);
59+
if (ret < 0)
60+
return ret;
61+
62+
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 3072000, SND_SOC_CLOCK_IN);
63+
if (ret < 0)
64+
return ret;
65+
}
66+
67+
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
68+
ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, rx_mask, 4, 16);
69+
if (ret < 0)
70+
return ret;
71+
}
72+
73+
return 0;
74+
}
75+
76+
static const struct snd_soc_pcm_stream bridge_params = {
77+
.formats = SNDRV_PCM_FMTBIT_S16_LE,
78+
.rate_min = 48000,
79+
.rate_max = 48000,
80+
.channels_min = 2,
81+
.channels_max = 2,
82+
};
83+
84+
SND_SOC_DAILINK_DEFS(bridge_dai,
85+
DAILINK_COMP_ARRAY(COMP_CODEC("cs42l43-codec", "cs42l43-asp")),
86+
DAILINK_COMP_ARRAY(COMP_CODEC("spi-cs35l56-left", "cs35l56-asp1"),
87+
COMP_CODEC("spi-cs35l56-right", "cs35l56-asp1")),
88+
DAILINK_COMP_ARRAY(COMP_PLATFORM("cs42l43-codec")));
89+
90+
static const struct snd_soc_dai_link bridge_dai_template = {
91+
.name = "cs42l43-cs35l56",
92+
.init = bridge_cs35l56_asp_init,
93+
.c2c_params = &bridge_params,
94+
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBC_CFC,
95+
SND_SOC_DAILINK_REG(bridge_dai),
96+
};
97+
98+
int bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
99+
int *num_dais, int *num_devs)
100+
{
101+
if (sof_sdw_quirk & SOF_SIDECAR_AMPS) {
102+
(*num_dais)++;
103+
(*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
104+
}
105+
106+
return 0;
107+
}
108+
109+
int bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
110+
struct snd_soc_dai_link **dai_links,
111+
struct snd_soc_codec_conf **codec_conf)
112+
{
113+
if (sof_sdw_quirk & SOF_SIDECAR_AMPS) {
114+
**dai_links = bridge_dai_template;
115+
116+
for (int i = 0; i < ARRAY_SIZE(bridge_cs35l56_name_prefixes); i++) {
117+
(*codec_conf)->dlc.name = (*dai_links)->codecs[i].name;
118+
(*codec_conf)->name_prefix = bridge_cs35l56_name_prefixes[i];
119+
(*codec_conf)++;
120+
}
121+
122+
(*dai_links)++;
123+
}
124+
125+
return 0;
126+
}
127+
128+
int bridge_cs35l56_spk_init(struct snd_soc_card *card,
129+
struct snd_soc_dai_link *dai_links,
130+
struct sof_sdw_codec_info *info,
131+
bool playback)
132+
{
133+
if (sof_sdw_quirk & SOF_SIDECAR_AMPS)
134+
info->amp_num += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
135+
136+
return 0;
137+
}

sound/soc/intel/boards/sof_sdw.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ static void log_quirks(struct device *dev)
3939
dev_err(dev, "quirk SOF_SDW_NO_AGGREGATION enabled but no longer supported\n");
4040
if (sof_sdw_quirk & SOF_CODEC_SPKR)
4141
dev_dbg(dev, "quirk SOF_CODEC_SPKR enabled\n");
42+
if (sof_sdw_quirk & SOF_SIDECAR_AMPS)
43+
dev_dbg(dev, "quirk SOF_SIDECAR_AMPS enabled\n");
4244
}
4345

4446
static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
@@ -995,6 +997,8 @@ static struct sof_sdw_codec_info codec_info_list[] = {
995997
{
996998
.part_id = 0x4243,
997999
.codec_name = "cs42l43-codec",
1000+
.count_sidecar = bridge_cs35l56_count_sidecar,
1001+
.add_sidecar = bridge_cs35l56_add_sidecar,
9981002
.dais = {
9991003
{
10001004
.direction = {true, false},
@@ -1023,7 +1027,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
10231027
.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
10241028
.init = sof_sdw_cs42l43_spk_init,
10251029
.rtd_init = cs42l43_spk_rtd_init,
1026-
.quirk = SOF_CODEC_SPKR,
1030+
.quirk = SOF_CODEC_SPKR | SOF_SIDECAR_AMPS,
10271031
},
10281032
},
10291033
.dai_num = 4,

sound/soc/intel/boards/sof_sdw_common.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ enum {
5555
#define SOF_SDW_NO_AGGREGATION BIT(14)
5656
/* If a CODEC has an optional speaker output, this quirk will enable it */
5757
#define SOF_CODEC_SPKR BIT(15)
58+
/*
59+
* If the CODEC has additional devices attached directly to it.
60+
*
61+
* For the cs42l43:
62+
* - 0 - No speaker output
63+
* - SOF_CODEC_SPKR - CODEC internal speaker
64+
* - SOF_SIDECAR_AMPS - 2x Sidecar amplifiers + CODEC internal speaker
65+
* - SOF_CODEC_SPKR | SOF_SIDECAR_AMPS - Not currently supported
66+
*/
67+
#define SOF_SIDECAR_AMPS BIT(16)
5868

5969
/* BT audio offload: reserve 3 bits for future */
6070
#define SOF_BT_OFFLOAD_SSP_SHIFT 15
@@ -177,6 +187,16 @@ int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card,
177187
bool playback);
178188

179189
/* CS AMP support */
190+
int bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
191+
int *num_dais, int *num_devs);
192+
int bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
193+
struct snd_soc_dai_link **dai_links,
194+
struct snd_soc_codec_conf **codec_conf);
195+
int bridge_cs35l56_spk_init(struct snd_soc_card *card,
196+
struct snd_soc_dai_link *dai_links,
197+
struct sof_sdw_codec_info *info,
198+
bool playback);
199+
180200
int sof_sdw_cs_amp_init(struct snd_soc_card *card,
181201
struct snd_soc_dai_link *dai_links,
182202
struct sof_sdw_codec_info *info,

sound/soc/intel/boards/sof_sdw_cs42l43.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,14 @@ int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd)
124124
struct snd_soc_card *card = rtd->card;
125125
int ret;
126126

127-
card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:cs42l43-spk",
128-
card->components);
129-
if (!card->components)
130-
return -ENOMEM;
127+
if (!(sof_sdw_quirk & SOF_SIDECAR_AMPS)) {
128+
/* Will be set by the bridge code in this case */
129+
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
130+
"%s spk:cs42l43-spk",
131+
card->components);
132+
if (!card->components)
133+
return -ENOMEM;
134+
}
131135

132136
ret = snd_soc_dapm_new_controls(&card->dapm, cs42l43_spk_widgets,
133137
ARRAY_SIZE(cs42l43_spk_widgets));
@@ -155,7 +159,7 @@ int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card,
155159

156160
info->amp_num++;
157161

158-
return 0;
162+
return bridge_cs35l56_spk_init(card, dai_links, info, playback);
159163
}
160164

161165
int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd)

0 commit comments

Comments
 (0)