Linux Sound subsystem development
 help / color / mirror / Atom feed
* [PATCH] [PATCH v1] ALSA: hda/cm9825: Add IBP support for DFI
@ 2026-07-08  3:55 Leo Tsai
  2026-07-08 10:54 ` Takashi Iwai
  0 siblings, 1 reply; 2+ messages in thread
From: Leo Tsai @ 2026-07-08  3:55 UTC (permalink / raw)
  To: perex, tiwai, rf; +Cc: leo.tsai, linux-sound, linux-kernel, Leo Tsai

The IBP project is an DFI platform with a fixed audio
configuration consisting of headset(headphone and mic-in).
The audio routing and pin assignments are defined according to
the board-level hardware design and are not intended to be
dynamically changed.

Signed-off-by: Leo Tsai <antivirus621@gmail.com>
---
 sound/hda/codecs/cm9825.c | 148 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 142 insertions(+), 6 deletions(-)

diff --git a/sound/hda/codecs/cm9825.c b/sound/hda/codecs/cm9825.c
index eeb9ca38d2d8..8a74862d8a81 100644
--- a/sound/hda/codecs/cm9825.c
+++ b/sound/hda/codecs/cm9825.c
@@ -15,7 +15,8 @@
 
 enum {
 	QUIRK_CM_STD = 0x0,
-	QUIRK_GENE_TWL7_SSID = 0x160dc000
+	QUIRK_GENE_TWL7_SSID = 0x160dc000,
+	QUIRK_IBP_SSID = 0x15bd3275
 };
 
 /* CM9825 Offset Definitions */
@@ -40,13 +41,19 @@ enum {
 #define CM9825_VERB_SET_GAD 0x7b4
 #define CM9825_VERB_SET_TMOD 0x7b5
 #define CM9825_VERB_SET_SNR 0x7b6
+#define CM9825_VERB_SET_OMTP 0x7ef
+#define CM9825_VERB_READ_OMTP 0xfec
 
 struct cmi_spec {
 	struct hda_gen_spec gen;
 	const struct hda_verb *chip_d0_verbs;
 	const struct hda_verb *chip_d3_verbs;
+	const struct hda_verb *chip_playback_start_verbs;
+	const struct hda_verb *chip_playback_stop_verbs;
 	const struct hda_verb *chip_hp_present_verbs;
 	const struct hda_verb *chip_hp_remove_verbs;
+	const struct hda_verb *chip_lineout_present_verbs;
+	const struct hda_verb *chip_lineout_remove_verbs;
 	struct hda_codec *codec;
 	struct delayed_work unsol_inputs_work;
 	struct delayed_work unsol_lineout_work;
@@ -193,6 +200,94 @@ static const struct hda_verb cm9825_gene_twl7_playback_stop_verbs[] = {
 	{}
 };
 
+/*
+ * To save power, AD/CLK is turned off.
+ */
+static const struct hda_verb cm9825_ibp_d3_verbs[] = {
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_PLL, 0x01},
+	{0x43, CM9825_VERB_SET_NEG, 0xc2},
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},
+	{0x43, CM9825_VERB_SET_DACL, 0x02},
+	{0x43, CM9825_VERB_SET_VNEG, 0x50},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},
+	{0x43, CM9825_VERB_SET_PDNEG, 0x04},
+	{0x43, CM9825_VERB_SET_CDALR, 0xf6},
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},
+	{}
+};
+
+/*
+ * D0 configuration: enable PLL/CLK/ADC/DAC and optimize performance
+ */
+static const struct hda_verb cm9825_ibp_d0_verbs[] = {
+	{0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+	{0x43, CM9825_VERB_SET_SNR, 0x38},
+	{0x43, CM9825_VERB_SET_PLL, 0x00},
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},
+	{0x43, CM9825_VERB_SET_DACL, 0x02},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},
+	{0x43, CM9825_VERB_SET_VNEG, 0x56},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},
+	{0x43, CM9825_VERB_SET_PDNEG, 0x0c},
+	{0x43, CM9825_VERB_SET_CDALR, 0xf4},
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},
+	{0x43, CM9825_VERB_SET_MTCBA, 0x61},
+	{0x43, CM9825_VERB_SET_OCP, 0x33},
+	{0x43, CM9825_VERB_SET_GAD, 0x07},
+	{0x43, CM9825_VERB_SET_TMOD, 0x26},
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0xa0, 0x2d},
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x90, 0x2d},
+	{0x43, CM9825_VERB_SET_HPF_1, 0x40},
+	{0x43, CM9825_VERB_SET_HPF_2, 0x40},
+	{}
+};
+
+/*
+ * Enable mbias, ADC.
+ */
+static const struct hda_verb cm9825_ibp_lineout_present_verbs[] = {
+	{0x43, CM9825_VERB_SET_ADCL, 0x8c},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x10},
+	{}
+};
+
+/*
+ * Disable mbias, ADC.
+ */
+static const struct hda_verb cm9825_ibp_lineout_remove_verbs[] = {
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},
+	{}
+};
+
+/*
+ * Turn on the DAC (widget NID 0x43) in the playback path by writing
+ * a sequence of vendor-specific verbs.
+ */
+static const struct hda_verb cm9825_ibp_playback_start_verbs[] = {
+	{0x43, CM9825_VERB_SET_DACL, 0xaa},
+	{0x43, CM9825_VERB_SET_D2S, 0xf2},
+	{0x43, CM9825_VERB_SET_VDO, 0xc4},
+	{0x43, CM9825_VERB_SET_SNR, 0x30},
+	{}
+};
+
+/*
+ * Shut down the playback path. The order differs slightly from the
+ * enable sequence, likely to avoid audible pop noise when powering
+ * down the output stage.
+ */
+static const struct hda_verb cm9825_ibp_playback_stop_verbs[] = {
+	{0x43, CM9825_VERB_SET_VDO, 0xc0},
+	{0x43, CM9825_VERB_SET_DACL, 0x02},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_VDO, 0x80},
+	{0x43, CM9825_VERB_SET_SNR, 0x38},
+	{}
+};
+
 static void cm9825_update_jk_plug_status(struct hda_codec *codec, hda_nid_t nid)
 {
 	struct cmi_spec *spec = codec->spec;
@@ -232,6 +327,23 @@ static void cm9825_unsol_lineout_delayed(struct work_struct *work)
 	struct cmi_spec *spec =
 	    container_of(to_delayed_work(work), struct cmi_spec,
 			 unsol_lineout_work);
+	hda_nid_t line_out_pin = spec->gen.autocfg.line_out_pins[0];
+	bool line_out_jack_plugin = false;
+
+	line_out_jack_plugin = snd_hda_jack_detect(spec->codec, line_out_pin);
+
+	codec_dbg(spec->codec, "lineout_jack_plugin %d, lineout_pin 0x%X\n",
+		  (int)line_out_jack_plugin, line_out_pin);
+
+	if (!line_out_jack_plugin) {
+		/* Jack plugout */
+		snd_hda_sequence_write(spec->codec,
+				       spec->chip_lineout_remove_verbs);
+	} else {
+		/* Jack plugin */
+		snd_hda_sequence_write(spec->codec,
+				       spec->chip_lineout_present_verbs);
+	}
 
 	cm9825_update_jk_plug_status(spec->codec,
 				     spec->gen.autocfg.line_out_pins[0]);
@@ -362,12 +474,10 @@ static void cm9825_playback_pcm_hook(struct hda_pcm_stream *hinfo,
 
 	switch (action) {
 	case HDA_GEN_PCM_ACT_PREPARE:
-		snd_hda_sequence_write(spec->codec,
-				       cm9825_gene_twl7_playback_start_verbs);
+		snd_hda_sequence_write(codec, spec->chip_playback_start_verbs);
 		break;
 	case HDA_GEN_PCM_ACT_CLEANUP:
-		snd_hda_sequence_write(spec->codec,
-				       cm9825_gene_twl7_playback_stop_verbs);
+		snd_hda_sequence_write(codec, spec->chip_playback_stop_verbs);
 		break;
 	default:
 		return;
@@ -471,7 +581,8 @@ static int cm9825_resume(struct hda_codec *codec)
 
 	if (codec->core.subsystem_id == QUIRK_CM_STD)
 		cm9825_cm_std_resume(codec);
-	else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) {
+	else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID ||
+		 codec->core.subsystem_id == QUIRK_IBP_SSID) {
 		snd_hda_codec_init(codec);
 		snd_hda_sequence_write(codec, spec->chip_d0_verbs);
 	}
@@ -487,6 +598,7 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
 	struct cmi_spec *spec;
 	struct auto_pin_cfg *cfg;
 	int err = 0;
+	unsigned int val;
 
 	spec = kzalloc_obj(*spec);
 	if (spec == NULL)
@@ -523,9 +635,33 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
 		spec->chip_d0_verbs = cm9825_gene_twl7_d0_verbs;
 		spec->chip_d3_verbs = cm9825_gene_twl7_d3_verbs;
 		spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+		spec->chip_playback_start_verbs =
+		    cm9825_gene_twl7_playback_start_verbs;
+		spec->chip_playback_stop_verbs =
+		    cm9825_gene_twl7_playback_stop_verbs;
 		/* Internal fixed device, Rear, Mic-in, 3.5mm */
 		snd_hda_codec_set_pincfg(codec, 0x37, 0x24A70100);
 		break;
+	case QUIRK_IBP_SSID:
+		snd_hda_codec_set_name(codec, "CM9825 IBP");
+		spec->chip_d0_verbs = cm9825_ibp_d0_verbs;
+		spec->chip_d3_verbs = cm9825_ibp_d3_verbs;
+		spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+		spec->chip_lineout_present_verbs =
+		    cm9825_ibp_lineout_present_verbs;
+		spec->chip_lineout_remove_verbs =
+		    cm9825_ibp_lineout_remove_verbs;
+		spec->chip_playback_start_verbs =
+		    cm9825_ibp_playback_start_verbs;
+		spec->chip_playback_stop_verbs = cm9825_ibp_playback_stop_verbs;
+
+		/* OMTP */
+		val =
+		    snd_hda_codec_read(codec, 0x46, 0, CM9825_VERB_READ_OMTP,
+				       0x0);
+		snd_hda_codec_write(codec, 0x46, 0, CM9825_VERB_SET_OMTP,
+				    (val >> 24) & 0x7f);
+		break;
 	default:
 		err = -ENXIO;
 		break;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] [PATCH v1] ALSA: hda/cm9825: Add IBP support for DFI
  2026-07-08  3:55 [PATCH] [PATCH v1] ALSA: hda/cm9825: Add IBP support for DFI Leo Tsai
@ 2026-07-08 10:54 ` Takashi Iwai
  0 siblings, 0 replies; 2+ messages in thread
From: Takashi Iwai @ 2026-07-08 10:54 UTC (permalink / raw)
  To: Leo Tsai; +Cc: perex, tiwai, rf, leo.tsai, linux-sound, linux-kernel

On Wed, 08 Jul 2026 05:55:52 +0200,
Leo Tsai wrote:
> 
> The IBP project is an DFI platform with a fixed audio
> configuration consisting of headset(headphone and mic-in).
> The audio routing and pin assignments are defined according to
> the board-level hardware design and are not intended to be
> dynamically changed.
> 
> Signed-off-by: Leo Tsai <antivirus621@gmail.com>

Applied to for-next branch now.  Thanks.


Takashi

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-08 10:54 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-08  3:55 [PATCH] [PATCH v1] ALSA: hda/cm9825: Add IBP support for DFI Leo Tsai
2026-07-08 10:54 ` Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox