Skip to content

Commit dfce24f

Browse files
Stefan Bindingtiwai
authored andcommitted
ALSA: hda: cs35l41: Add support for center channel in CS35L41 HDA
Currently only left and right channels are supported for each amp. Support is needed for a center channel, using both left and right channel audio. Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> Link: https://patch.msgid.link/20250612160029.848104-2-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 30f85ed commit dfce24f

3 files changed

Lines changed: 78 additions & 38 deletions

File tree

include/sound/cs35l41.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,18 @@
609609
#define CS35L41_DSP_NG_DELAY_MASK 0x0F00
610610
#define CS35L41_DSP_NG_DELAY_SHIFT 8
611611

612+
#define CS35L41_ASP_RX1_EN_MASK 0x00010000
613+
#define CS35L41_ASP_RX1_EN_SHIFT 16
614+
#define CS35L41_ASP_RX2_EN_MASK 0x00020000
615+
#define CS35L41_ASP_RX2_EN_SHIFT 17
616+
#define CS35L41_ASP_TX1_EN_MASK 0x00000001
617+
#define CS35L41_ASP_TX1_EN_SHIFT 0
618+
#define CS35L41_ASP_TX2_EN_MASK 0x00000002
619+
#define CS35L41_ASP_TX2_EN_SHIFT 1
620+
#define CS35L41_ASP_TX3_EN_MASK 0x00000004
621+
#define CS35L41_ASP_TX3_EN_SHIFT 2
622+
#define CS35L41_ASP_TX4_EN_MASK 0x00000008
623+
#define CS35L41_ASP_TX4_EN_SHIFT 3
612624
#define CS35L41_ASP_FMT_MASK 0x0700
613625
#define CS35L41_ASP_FMT_SHIFT 8
614626
#define CS35L41_ASP_DOUT_HIZ_MASK 0x03

sound/pci/hda/cs35l41_hda.c

Lines changed: 65 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -93,47 +93,36 @@ module_param(firmware_autostart, bool, 0444);
9393
MODULE_PARM_DESC(firmware_autostart, "Allow automatic firmware download on boot"
9494
"(0=Disable, 1=Enable) (default=1); ");
9595

96+
static const char channel_name[3] = { 'L', 'R', 'C' };
97+
9698
static const struct reg_sequence cs35l41_hda_config[] = {
9799
{ CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
98100
{ CS35L41_DSP_CLK_CTRL, 0x00000003 }, // DSP CLK EN
99101
{ CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, // GLOBAL_FS = 48 kHz
100-
{ CS35L41_SP_ENABLES, 0x00010000 }, // ASP_RX1_EN = 1
101102
{ CS35L41_SP_RATE_CTRL, 0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
102103
{ CS35L41_SP_FORMAT, 0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
103-
{ CS35L41_SP_HIZ_CTRL, 0x00000002 }, // Hi-Z unused
104104
{ CS35L41_SP_TX_WL, 0x00000018 }, // 24 cycles/slot
105105
{ CS35L41_SP_RX_WL, 0x00000018 }, // 24 cycles/slot
106-
{ CS35L41_DAC_PCM1_SRC, 0x00000008 }, // DACPCM1_SRC = ASPRX1
107106
{ CS35L41_ASP_TX1_SRC, 0x00000018 }, // ASPTX1 SRC = VMON
108107
{ CS35L41_ASP_TX2_SRC, 0x00000019 }, // ASPTX2 SRC = IMON
109-
{ CS35L41_ASP_TX3_SRC, 0x00000032 }, // ASPTX3 SRC = ERRVOL
110-
{ CS35L41_ASP_TX4_SRC, 0x00000033 }, // ASPTX4 SRC = CLASSH_TGT
111-
{ CS35L41_DSP1_RX1_SRC, 0x00000008 }, // DSP1RX1 SRC = ASPRX1
112-
{ CS35L41_DSP1_RX2_SRC, 0x00000009 }, // DSP1RX2 SRC = ASPRX2
113108
{ CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON
114109
{ CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON
110+
};
111+
112+
static const struct reg_sequence cs35l41_hda_config_no_dsp[] = {
113+
{ CS35L41_SP_HIZ_CTRL, 0x00000002 }, // Hi-Z unused
114+
{ CS35L41_DAC_PCM1_SRC, 0x00000008 }, // DACPCM1_SRC = ASPRX1
115+
{ CS35L41_ASP_TX3_SRC, 0x00000000 }, // ASPTX3 SRC = ZERO FILL
116+
{ CS35L41_ASP_TX4_SRC, 0x00000000 }, // ASPTX4 SRC = ZERO FILL
115117
{ CS35L41_DSP1_RX5_SRC, 0x00000020 }, // DSP1RX5 SRC = ERRVOL
118+
{ CS35L41_DSP1_RX6_SRC, 0x00000021 }, // DSP1RX6 SRC = CLASSH_TGT
116119
};
117120

118121
static const struct reg_sequence cs35l41_hda_config_dsp[] = {
119-
{ CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
120-
{ CS35L41_DSP_CLK_CTRL, 0x00000003 }, // DSP CLK EN
121-
{ CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, // GLOBAL_FS = 48 kHz
122-
{ CS35L41_SP_ENABLES, 0x00010001 }, // ASP_RX1_EN = 1, ASP_TX1_EN = 1
123-
{ CS35L41_SP_RATE_CTRL, 0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
124-
{ CS35L41_SP_FORMAT, 0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
125122
{ CS35L41_SP_HIZ_CTRL, 0x00000003 }, // Hi-Z unused/disabled
126-
{ CS35L41_SP_TX_WL, 0x00000018 }, // 24 cycles/slot
127-
{ CS35L41_SP_RX_WL, 0x00000018 }, // 24 cycles/slot
128123
{ CS35L41_DAC_PCM1_SRC, 0x00000032 }, // DACPCM1_SRC = DSP1TX1
129-
{ CS35L41_ASP_TX1_SRC, 0x00000018 }, // ASPTX1 SRC = VMON
130-
{ CS35L41_ASP_TX2_SRC, 0x00000019 }, // ASPTX2 SRC = IMON
131124
{ CS35L41_ASP_TX3_SRC, 0x00000028 }, // ASPTX3 SRC = VPMON
132125
{ CS35L41_ASP_TX4_SRC, 0x00000029 }, // ASPTX4 SRC = VBSTMON
133-
{ CS35L41_DSP1_RX1_SRC, 0x00000008 }, // DSP1RX1 SRC = ASPRX1
134-
{ CS35L41_DSP1_RX2_SRC, 0x00000008 }, // DSP1RX2 SRC = ASPRX1
135-
{ CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON
136-
{ CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON
137126
{ CS35L41_DSP1_RX6_SRC, 0x00000029 }, // DSP1RX6 SRC = VBSTMON
138127
};
139128

@@ -657,6 +646,41 @@ static void cs35l41_irq_release(struct cs35l41_hda *cs35l41)
657646
cs35l41->irq_errors = 0;
658647
}
659648

649+
static void cs35l41_update_mixer(struct cs35l41_hda *cs35l41)
650+
{
651+
struct regmap *reg = cs35l41->regmap;
652+
unsigned int asp_en = 0;
653+
unsigned int dsp1rx2_src = 0;
654+
655+
regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config));
656+
657+
if (cs35l41->cs_dsp.running) {
658+
asp_en |= CS35L41_ASP_TX1_EN_MASK; // ASP_TX1_EN = 1
659+
regmap_multi_reg_write(reg, cs35l41_hda_config_dsp,
660+
ARRAY_SIZE(cs35l41_hda_config_dsp));
661+
if (cs35l41->hw_cfg.bst_type == CS35L41_INT_BOOST)
662+
regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VPMON);
663+
else
664+
regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VBSTMON);
665+
} else {
666+
regmap_multi_reg_write(reg, cs35l41_hda_config_no_dsp,
667+
ARRAY_SIZE(cs35l41_hda_config_no_dsp));
668+
}
669+
670+
if (cs35l41->hw_cfg.spk_pos == CS35L41_CENTER) {
671+
asp_en |= CS35L41_ASP_RX2_EN_MASK; // ASP_RX2_EN = 1
672+
dsp1rx2_src = 0x00000009; // DSP1RX2 SRC = ASPRX2
673+
} else {
674+
dsp1rx2_src = 0x00000008; // DSP1RX2 SRC = ASPRX1
675+
}
676+
677+
asp_en |= CS35L41_ASP_RX1_EN_MASK; // ASP_RX1_EN = 1
678+
679+
regmap_write(reg, CS35L41_SP_ENABLES, asp_en);
680+
regmap_write(reg, CS35L41_DSP1_RX1_SRC, 0x00000008); // DSP1RX1 SRC = ASPRX1
681+
regmap_write(reg, CS35L41_DSP1_RX2_SRC, dsp1rx2_src);
682+
}
683+
660684
static void cs35l41_hda_play_start(struct device *dev)
661685
{
662686
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
@@ -671,19 +695,13 @@ static void cs35l41_hda_play_start(struct device *dev)
671695

672696
cs35l41->playback_started = true;
673697

698+
cs35l41_update_mixer(cs35l41);
699+
674700
if (cs35l41->cs_dsp.running) {
675-
regmap_multi_reg_write(reg, cs35l41_hda_config_dsp,
676-
ARRAY_SIZE(cs35l41_hda_config_dsp));
677-
if (cs35l41->hw_cfg.bst_type == CS35L41_INT_BOOST)
678-
regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VPMON);
679-
else
680-
regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VBSTMON);
681701
regmap_update_bits(reg, CS35L41_PWR_CTRL2,
682702
CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
683703
1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT);
684704
cs35l41_set_cspl_mbox_cmd(cs35l41->dev, reg, CSPL_MBOX_CMD_RESUME);
685-
} else {
686-
regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config));
687705
}
688706
regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
689707
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
@@ -841,22 +859,31 @@ static void cs35l41_hda_post_playback_hook(struct device *dev, int action)
841859
}
842860
}
843861

844-
static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsigned int *tx_slot,
845-
unsigned int rx_num, unsigned int *rx_slot)
862+
static int cs35l41_hda_channel_map(struct cs35l41_hda *cs35l41)
846863
{
847-
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
848-
static const char * const channel_name[] = { "L", "R" };
864+
unsigned int tx_num = 0;
865+
unsigned int *tx_slot = NULL;
866+
unsigned int rx_num;
867+
unsigned int *rx_slot;
868+
unsigned int mono = 0;
849869

850870
if (!cs35l41->amp_name) {
851-
if (*rx_slot >= ARRAY_SIZE(channel_name))
871+
if (cs35l41->hw_cfg.spk_pos >= ARRAY_SIZE(channel_name))
852872
return -EINVAL;
853873

854-
cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%s%d",
855-
channel_name[*rx_slot], cs35l41->channel_index);
874+
cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%c%d",
875+
channel_name[cs35l41->hw_cfg.spk_pos],
876+
cs35l41->channel_index);
856877
if (!cs35l41->amp_name)
857878
return -ENOMEM;
858879
}
859880

881+
rx_num = 1;
882+
if (cs35l41->hw_cfg.spk_pos == CS35L41_CENTER)
883+
rx_slot = &mono;
884+
else
885+
rx_slot = &cs35l41->hw_cfg.spk_pos;
886+
860887
return cs35l41_set_channels(cs35l41->dev, cs35l41->regmap, tx_num, tx_slot, rx_num,
861888
rx_slot);
862889
}
@@ -1495,7 +1522,7 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
14951522
"CS35L41 Bound - SSID: %s, BST: %d, VSPK: %d, CH: %c, FW EN: %d, SPKID: %d\n",
14961523
cs35l41->acpi_subsystem_id, cs35l41->hw_cfg.bst_type,
14971524
cs35l41->hw_cfg.gpio1.func == CS35l41_VSPK_SWITCH,
1498-
cs35l41->hw_cfg.spk_pos ? 'R' : 'L',
1525+
channel_name[cs35l41->hw_cfg.spk_pos],
14991526
cs35l41->cs_dsp.running, cs35l41->speaker_id);
15001527

15011528
return ret;
@@ -1709,7 +1736,7 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
17091736
if (using_irq)
17101737
cs35l41_configure_interrupt(cs35l41, irq_pol);
17111738

1712-
return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos);
1739+
return cs35l41_hda_channel_map(cs35l41);
17131740
}
17141741

17151742
int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id)

sound/pci/hda/cs35l41_hda.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct cs35l41_amp_efi_data {
4242
enum cs35l41_hda_spk_pos {
4343
CS35L41_LEFT,
4444
CS35L41_RIGHT,
45+
CS35L41_CENTER,
4546
};
4647

4748
enum cs35l41_hda_gpio_function {

0 commit comments

Comments
 (0)