Skip to content

Commit 0924c6b

Browse files
simontrimmertiwai
authored andcommitted
ALSA: hda/cs8409: Add quirk for CDB35L56-FOUR-HD
Adds quirkiness for the Cirrus Logic CDB35L56-FOUR-HD board. The quirk must be forced by model name "CDB35L56-FOUR-HD" because there isn't a unique SSID that can be used. For example in /etc/modprobe.d: options snd-hda-intel model="CDB35L56-FOUR-HD" The CDB35L56-FOUR-HD is not a complete PC. It is an add-on audio board that requires a host system and replaces the normal HDA codec on the host. Because of this there isn't an SSID that uniquely identifies this configuration. Also, the usual host board is an Aaeon UpXtreme, which doesn't have a unique SSID. Because of this, the quirk must be forced by a module param. This is acceptable because it is a development board, not an end-user system, so there is no need for it to be detected automatically. Signed-off-by: Simon Trimmer <simont@opensource.cirrus.com> Co-developed-by: Richard Fitzgerald <rf@opensource.cirrus.com> Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> Link: https://patch.msgid.link/20260112142850.243054-1-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 8bf65ec commit 0924c6b

4 files changed

Lines changed: 261 additions & 1 deletion

File tree

sound/hda/codecs/cirrus/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ comment "Set to Y if you want auto-loading the codec driver"
3434
config SND_HDA_CODEC_CS8409
3535
tristate "Build Cirrus Logic HDA bridge support"
3636
select SND_HDA_GENERIC
37+
select SND_HDA_SCODEC_COMPONENT
3738
help
3839
Say Y or M here to include Cirrus Logic HDA bridge support
3940
such as CS8409.

sound/hda/codecs/cirrus/cs8409-tables.c

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,70 @@ struct sub_codec dolphin_cs42l42_1 = {
468468
.no_type_dect = 1,
469469
};
470470

471+
/******************************************************************************
472+
* CDB35L56-FOUR-HD Specific Arrays
473+
******************************************************************************/
474+
const struct hda_verb cs8409_cdb35l56_four_init_verbs[] = {
475+
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_STATE, 0x0001 }, /* Enable VPW processing */
476+
{} /* terminator */
477+
};
478+
479+
static const struct hda_pintbl cs8409_cdb35l56_four_pincfgs[] = {
480+
/* 0xPPLLLLLLDDDDTTTTCCCCMMMMAAAASSSS
481+
* P = PCON: AC_JACK_PORT_*
482+
* L = LOC: AC_JACK_LOC_*
483+
* D = DD: device type AC_JACK_*
484+
* T = CTYP: AC_JACK_CONN_*
485+
* C = COL: AC_JACK_COLOR_*
486+
* M = MISC: ?
487+
* A = DA: AC_DEFCFG_DEF_ASSOC
488+
* S = SEQ: Sequence number in DA group
489+
*/
490+
{ CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 }, /* ASP-2-TX */
491+
/* "Mic" */
492+
{ CS8409_PIN_ASP2_RECEIVER_A, 0x04a12050 }, /* ASP-2-RX */
493+
{} /* terminator */
494+
};
495+
496+
const struct cs8409_cir_param cs8409_cdb35l56_four_hw_cfg[] = {
497+
/* +PLL1/2_EN, +I2C_EN */
498+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0xb008 },
499+
/* ASP1/2_EN=0, ASP1_STP=1 */
500+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0002 },
501+
/* ASP1/2_BUS_IDLE=10, +GPIO_I2C */
502+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG3, 0x0a80 },
503+
/* ASP2.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
504+
{ CS8409_PIN_VENDOR_WIDGET, ASP2_A_TX_CTRL1, 0x0800 },
505+
/* ASP2.A: TX.RAP=1, TX.RSZ=24 bits, TX.RCS=0 */
506+
{ CS8409_PIN_VENDOR_WIDGET, ASP2_A_TX_CTRL2, 0x2800 },
507+
/* ASP2.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */
508+
{ CS8409_PIN_VENDOR_WIDGET, ASP2_A_RX_CTRL1, 0x0800 },
509+
/* ASP2.A: RX.RAP=1, RX.RSZ=24 bits, RX.RCS=0 */
510+
{ CS8409_PIN_VENDOR_WIDGET, ASP2_A_RX_CTRL2, 0x2800 },
511+
/* ASP1: LCHI = 00h */
512+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL1, 0x8000 },
513+
/* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */
514+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL2, 0x28ff },
515+
/* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */
516+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL3, 0x0062 },
517+
/* ASP2: LCHI=1Fh */
518+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL1, 0x801f },
519+
/* ASP2: MC/SC_SRCSEL=PLL1, LCPR=3Fh */
520+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL2, 0x283f },
521+
/* ASP2: 5050=1, MCEN=0, FSD=010, SCPOL_IN/OUT=1, SCDIV=1:16 */
522+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL3, 0x805c },
523+
/* ASP1/2_BEEP=0 */
524+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_BEEP_CFG, 0x0000 },
525+
/* ASP1/2_EN=1, ASP1_STP=1 */
526+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0062 },
527+
/* -PLL2_EN */
528+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0x9008 }, /* TX2.A: pre-scale att.=0 dB */
529+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PRE_SCALE_ATTN2, 0x0000 },
530+
/* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=1 */
531+
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PAD_CFG_SLW_RATE_CTRL, 0xfc03 },
532+
{} /* Terminator */
533+
};
534+
471535
/******************************************************************************
472536
* CS8409 Patch Driver Structs
473537
* Arrays Used for all projects using CS8409
@@ -557,7 +621,6 @@ const struct hda_quirk cs8409_fixup_tbl[] = {
557621
{} /* terminator */
558622
};
559623

560-
/* Dell Inspiron models with cs8409/cs42l42 */
561624
const struct hda_model_fixup cs8409_models[] = {
562625
{ .id = CS8409_BULLSEYE, .name = "bullseye" },
563626
{ .id = CS8409_WARLOCK, .name = "warlock" },
@@ -566,6 +629,7 @@ const struct hda_model_fixup cs8409_models[] = {
566629
{ .id = CS8409_CYBORG, .name = "cyborg" },
567630
{ .id = CS8409_DOLPHIN, .name = "dolphin" },
568631
{ .id = CS8409_ODIN, .name = "odin" },
632+
{ .id = CS8409_CDB35L56_FOUR_HD, .name = "CDB35L56-FOUR-HD" },
569633
{}
570634
};
571635

@@ -620,4 +684,14 @@ const struct hda_fixup cs8409_fixups[] = {
620684
.chained = true,
621685
.chain_id = CS8409_FIXUPS,
622686
},
687+
[CS8409_CDB35L56_FOUR_HD] = {
688+
.type = HDA_FIXUP_PINS,
689+
.v.pins = cs8409_cdb35l56_four_pincfgs,
690+
.chained = true,
691+
.chain_id = CS8409_CDB35L56_FOUR_HD_FIXUP,
692+
},
693+
[CS8409_CDB35L56_FOUR_HD_FIXUP] = {
694+
.type = HDA_FIXUP_FUNC,
695+
.v.func = cs8409_cdb35l56_four_autodet_fixup,
696+
},
623697
};

sound/hda/codecs/cirrus/cs8409.c

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@
66
* Cirrus Logic International Semiconductor Ltd.
77
*/
88

9+
#include <linux/acpi.h>
10+
#include <linux/cleanup.h>
11+
#include <linux/i2c.h>
912
#include <linux/init.h>
1013
#include <linux/slab.h>
1114
#include <linux/module.h>
15+
#include <linux/spi/spi.h>
1216
#include <sound/core.h>
1317
#include <linux/mutex.h>
1418
#include <linux/iopoll.h>
1519

1620
#include "cs8409.h"
21+
#include "../side-codecs/hda_component.h"
1722

1823
/******************************************************************************
1924
* CS8409 Specific Functions
@@ -1216,6 +1221,172 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
12161221
}
12171222
}
12181223

1224+
static int cs8409_comp_bind(struct device *dev)
1225+
{
1226+
struct hda_codec *codec = dev_to_hda_codec(dev);
1227+
struct cs8409_spec *spec = codec->spec;
1228+
1229+
return hda_component_manager_bind(codec, &spec->comps);
1230+
}
1231+
1232+
static void cs8409_comp_unbind(struct device *dev)
1233+
{
1234+
struct hda_codec *codec = dev_to_hda_codec(dev);
1235+
struct cs8409_spec *spec = codec->spec;
1236+
1237+
hda_component_manager_unbind(codec, &spec->comps);
1238+
}
1239+
1240+
static const struct component_master_ops cs8409_comp_master_ops = {
1241+
.bind = cs8409_comp_bind,
1242+
.unbind = cs8409_comp_unbind,
1243+
};
1244+
1245+
static void cs8409_comp_playback_hook(struct hda_pcm_stream *hinfo, struct hda_codec *codec,
1246+
struct snd_pcm_substream *sub, int action)
1247+
{
1248+
struct cs8409_spec *spec = codec->spec;
1249+
1250+
hda_component_manager_playback_hook(&spec->comps, action);
1251+
}
1252+
1253+
static void cs8409_cdb35l56_four_hw_init(struct hda_codec *codec)
1254+
{
1255+
const struct cs8409_cir_param *seq = cs8409_cdb35l56_four_hw_cfg;
1256+
1257+
for (; seq->nid; seq++)
1258+
cs8409_vendor_coef_set(codec, seq->cir, seq->coeff);
1259+
}
1260+
1261+
static int cs8409_spk_sw_get(struct snd_kcontrol *kcontrol,
1262+
struct snd_ctl_elem_value *ucontrol)
1263+
{
1264+
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1265+
struct cs8409_spec *spec = codec->spec;
1266+
1267+
ucontrol->value.integer.value[0] = !spec->speaker_muted;
1268+
1269+
return 0;
1270+
}
1271+
1272+
static int cs8409_spk_sw_put(struct snd_kcontrol *kcontrol,
1273+
struct snd_ctl_elem_value *ucontrol)
1274+
{
1275+
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1276+
struct cs8409_spec *spec = codec->spec;
1277+
bool muted = !ucontrol->value.integer.value[0];
1278+
1279+
if (muted == spec->speaker_muted)
1280+
return 0;
1281+
1282+
spec->speaker_muted = muted;
1283+
1284+
return 1;
1285+
}
1286+
1287+
static const struct snd_kcontrol_new cs8409_spk_sw_component_ctrl = {
1288+
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1289+
.info = snd_ctl_boolean_mono_info,
1290+
.get = cs8409_spk_sw_get,
1291+
.put = cs8409_spk_sw_put,
1292+
};
1293+
1294+
void cs8409_cdb35l56_four_autodet_fixup(struct hda_codec *codec,
1295+
const struct hda_fixup *fix,
1296+
int action)
1297+
{
1298+
struct device *dev = hda_codec_dev(codec);
1299+
struct cs8409_spec *spec = codec->spec;
1300+
struct acpi_device *adev;
1301+
const char *bus = NULL;
1302+
static const struct {
1303+
const char *hid;
1304+
const char *name;
1305+
} acpi_ids[] = {{ "CSC3554", "cs35l54-hda" },
1306+
{ "CSC3556", "cs35l56-hda" },
1307+
{ "CSC3557", "cs35l57-hda" }};
1308+
char *match;
1309+
int i, count = 0, count_devindex = 0;
1310+
int ret;
1311+
1312+
switch (action) {
1313+
case HDA_FIXUP_ACT_PRE_PROBE: {
1314+
for (i = 0; i < ARRAY_SIZE(acpi_ids); ++i) {
1315+
adev = acpi_dev_get_first_match_dev(acpi_ids[i].hid, NULL, -1);
1316+
if (adev)
1317+
break;
1318+
}
1319+
if (!adev) {
1320+
dev_err(dev, "Failed to find ACPI entry for a Cirrus Amp\n");
1321+
return;
1322+
}
1323+
1324+
count = i2c_acpi_client_count(adev);
1325+
if (count > 0) {
1326+
bus = "i2c";
1327+
} else {
1328+
count = acpi_spi_count_resources(adev);
1329+
if (count > 0)
1330+
bus = "spi";
1331+
}
1332+
1333+
struct fwnode_handle *fwnode __free(fwnode_handle) =
1334+
fwnode_handle_get(acpi_fwnode_handle(adev));
1335+
acpi_dev_put(adev);
1336+
1337+
if (!bus) {
1338+
dev_err(dev, "Did not find any buses for %s\n", acpi_ids[i].hid);
1339+
return;
1340+
}
1341+
1342+
if (!fwnode) {
1343+
dev_err(dev, "Could not get fwnode for %s\n", acpi_ids[i].hid);
1344+
return;
1345+
}
1346+
1347+
/*
1348+
* When available the cirrus,dev-index property is an accurate
1349+
* count of the amps in a system and is used in preference to
1350+
* the count of bus devices that can contain additional address
1351+
* alias entries.
1352+
*/
1353+
count_devindex = fwnode_property_count_u32(fwnode, "cirrus,dev-index");
1354+
if (count_devindex > 0)
1355+
count = count_devindex;
1356+
1357+
match = devm_kasprintf(dev, GFP_KERNEL, "-%%s:00-%s.%%d", acpi_ids[i].name);
1358+
if (!match)
1359+
return;
1360+
dev_info(dev, "Found %d %s on %s (%s)\n", count, acpi_ids[i].hid, bus, match);
1361+
1362+
ret = hda_component_manager_init(codec, &spec->comps, count, bus,
1363+
acpi_ids[i].hid, match,
1364+
&cs8409_comp_master_ops);
1365+
if (ret)
1366+
return;
1367+
1368+
spec->gen.pcm_playback_hook = cs8409_comp_playback_hook;
1369+
1370+
snd_hda_add_verbs(codec, cs8409_cdb35l56_four_init_verbs);
1371+
snd_hda_sequence_write(codec, cs8409_cdb35l56_four_init_verbs);
1372+
break;
1373+
}
1374+
case HDA_FIXUP_ACT_PROBE:
1375+
spec->speaker_muted = 0; /* speakers begin enabled */
1376+
snd_hda_gen_add_kctl(&spec->gen, "Speaker Playback Switch",
1377+
&cs8409_spk_sw_component_ctrl);
1378+
spec->gen.stream_analog_playback = &cs42l42_48k_pcm_analog_playback;
1379+
snd_hda_codec_set_name(codec, "CS8409/CS35L56");
1380+
break;
1381+
case HDA_FIXUP_ACT_INIT:
1382+
cs8409_cdb35l56_four_hw_init(codec);
1383+
break;
1384+
case HDA_FIXUP_ACT_FREE:
1385+
hda_component_manager_free(&spec->comps, &cs8409_comp_master_ops);
1386+
break;
1387+
}
1388+
}
1389+
12191390
/******************************************************************************
12201391
* Dolphin Specific Functions
12211392
* CS8409/ 2 X CS42L42
@@ -1473,3 +1644,4 @@ module_hda_codec_driver(cs8409_driver);
14731644

14741645
MODULE_LICENSE("GPL");
14751646
MODULE_DESCRIPTION("Cirrus Logic HDA bridge");
1647+
MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT");

sound/hda/codecs/cirrus/cs8409.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "hda_auto_parser.h"
1919
#include "hda_jack.h"
2020
#include "../generic.h"
21+
#include "../side-codecs/hda_component.h"
2122

2223
/* CS8409 Specific Definitions */
2324

@@ -271,6 +272,8 @@ enum {
271272
CS8409_DOLPHIN,
272273
CS8409_DOLPHIN_FIXUPS,
273274
CS8409_ODIN,
275+
CS8409_CDB35L56_FOUR_HD,
276+
CS8409_CDB35L56_FOUR_HD_FIXUP,
274277
};
275278

276279
enum {
@@ -341,12 +344,17 @@ struct cs8409_spec {
341344
unsigned int capture_started:1;
342345
unsigned int init_done:1;
343346
unsigned int build_ctrl_done:1;
347+
unsigned int speaker_muted:1;
344348

345349
/* verb exec op override */
346350
int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
347351
unsigned int *res);
348352
/* unsol_event op override */
349353
void (*unsol_event)(struct hda_codec *codec, unsigned int res);
354+
355+
/* component binding */
356+
struct component_match *match;
357+
struct hda_component_parent comps;
350358
};
351359

352360
extern const struct snd_kcontrol_new cs42l42_dac_volume_mixer;
@@ -374,4 +382,9 @@ extern struct sub_codec dolphin_cs42l42_1;
374382
void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action);
375383
void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action);
376384

385+
extern const struct cs8409_cir_param cs8409_cdb35l56_four_hw_cfg[];
386+
extern const struct hda_verb cs8409_cdb35l56_four_init_verbs[];
387+
void cs8409_cdb35l56_four_autodet_fixup(struct hda_codec *codec, const struct hda_fixup *fix,
388+
int action);
389+
377390
#endif

0 commit comments

Comments
 (0)