[PATCH] ALSA: hda/cm9825: Add new project GENE_TWL7 for AAEON

Leo Tsai posted 1 patch 6 hours ago
sound/hda/codecs/cm9825.c | 292 +++++++++++++++++++++++++++++++++++++-
1 file changed, 285 insertions(+), 7 deletions(-)
[PATCH] ALSA: hda/cm9825: Add new project GENE_TWL7 for AAEON
Posted by Leo Tsai 6 hours ago
The GENE_TWL7 project is an AAEON platform with a fixed audio
configuration consisting of line-out, line-in, 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 | 292 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 285 insertions(+), 7 deletions(-)

diff --git a/sound/hda/codecs/cm9825.c b/sound/hda/codecs/cm9825.c
index 5c474ce44348..5532dde89ebe 100644
--- a/sound/hda/codecs/cm9825.c
+++ b/sound/hda/codecs/cm9825.c
@@ -13,6 +13,11 @@
 #include "hda_jack.h"
 #include "generic.h"
 
+enum {
+	QUIRK_CM_STD = 0x0,
+	QUIRK_GENE_TWL7_SSID = 0x160dc000
+};
+
 /* CM9825 Offset Definitions */
 
 #define CM9825_VERB_SET_HPF_1 0x781
@@ -25,6 +30,7 @@
 #define CM9825_VERB_SET_VNEG 0x7a8
 #define CM9825_VERB_SET_D2S 0x7a9
 #define CM9825_VERB_SET_DACTRL 0x7aa
+#define CM9825_VERB_SET_P3BCP 0x7ab
 #define CM9825_VERB_SET_PDNEG 0x7ac
 #define CM9825_VERB_SET_VDO 0x7ad
 #define CM9825_VERB_SET_CDALR 0x7b0
@@ -42,6 +48,8 @@ struct cmi_spec {
 	const struct hda_verb *chip_hp_present_verbs;
 	const struct hda_verb *chip_hp_remove_verbs;
 	struct hda_codec *codec;
+	struct delayed_work unsol_linein_work;
+	struct delayed_work unsol_lineout_work;
 	struct delayed_work unsol_hp_work;
 	int quirk;
 };
@@ -111,6 +119,72 @@ static const struct hda_verb cm9825_hp_remove_verbs[] = {
 	{}
 };
 
+/*
+ * To save power, AD/CLK is turned off.
+ */
+static const struct hda_verb cm9825_gene_twl7_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_MBIAS, 0x00},
+	{0x43, CM9825_VERB_SET_VNEG, 0x50},
+	{0x43, CM9825_VERB_SET_PDNEG, 0x04},
+	{0x43, CM9825_VERB_SET_CDALR, 0xf6},
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},
+	{}
+};
+
+/*
+ * Enable CLK/ADC to start recording.
+ */
+static const struct hda_verb cm9825_gene_twl7_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, 0xcf},
+	{0x43, CM9825_VERB_SET_DACL, 0xaa},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x1c},
+	{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},
+	{0x43, CM9825_VERB_SET_HPF_1, 0x40},
+	{0x43, CM9825_VERB_SET_HPF_2, 0x40},
+	{0x40, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x3d, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x46, CM9825_VERB_SET_P3BCP, 0x20},
+	{}
+};
+
+/*
+ * Enable DAC to start playback.
+ */
+static const struct hda_verb cm9825_gene_twl7_playback_start_verbs[] = {
+	{0x43, CM9825_VERB_SET_D2S, 0xf2},
+	{0x43, CM9825_VERB_SET_VDO, 0xd4},
+	{0x43, CM9825_VERB_SET_SNR, 0x30},
+	{}
+};
+
+/*
+ * Disable DAC and enable de-pop noise mechanism.
+ */
+static const struct hda_verb cm9825_gene_twl7_playback_stop_verbs[] = {
+	{0x43, CM9825_VERB_SET_VDO, 0xc0},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_VDO, 0xd0},
+	{0x43, CM9825_VERB_SET_SNR, 0x38},
+	{}
+};
+
 static void cm9825_unsol_hp_delayed(struct work_struct *work)
 {
 	struct cmi_spec *spec =
@@ -162,13 +236,138 @@ static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
 	schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200));
 }
 
+static void cm9825_unsol_linein_delayed(struct work_struct *work)
+{
+	struct cmi_spec *spec =
+	    container_of(to_delayed_work(work), struct cmi_spec,
+			 unsol_linein_work);
+	struct hda_jack_tbl *jack;
+
+	hda_nid_t linein_pin = spec->gen.autocfg.inputs[1].pin;
+
+	bool linein_jack_plugin = false;
+
+	linein_jack_plugin = snd_hda_jack_detect(spec->codec, linein_pin);
+
+	codec_dbg(spec->codec,
+		    "%s, lineout_jack_plugin %d, linein_pin 0x%X, line%d\n",
+		    __func__, (int)linein_jack_plugin, linein_pin, __LINE__);
+
+	jack = snd_hda_jack_tbl_get(spec->codec, linein_pin);
+
+	if (jack) {
+		jack->block_report = 0;
+		snd_hda_jack_report_sync(spec->codec);
+	}
+}
+
+static void linein_callback(struct hda_codec *codec,
+			    struct hda_jack_callback *cb)
+{
+	struct cmi_spec *spec = codec->spec;
+	struct hda_jack_tbl *tbl;
+
+	/* Delay enabling the line, to let the linein-detection
+	 * state machine run.
+	 */
+
+	codec_dbg(codec, "%s, cb->nid 0x%X, line%d\n", __func__,
+		    (int)cb->nid, __LINE__);
+
+	tbl = snd_hda_jack_tbl_get(codec, cb->nid);
+	if (tbl)
+		tbl->block_report = 1;
+	schedule_delayed_work(&spec->unsol_linein_work, msecs_to_jiffies(200));
+}
+
+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);
+	struct hda_jack_tbl *jack;
+
+	hda_nid_t lineout_pin = spec->gen.autocfg.line_out_pins[0];
+
+	bool lineout_jack_plugin = false;
+
+	lineout_jack_plugin = snd_hda_jack_detect(spec->codec, lineout_pin);
+
+	codec_dbg(spec->codec,
+		  "%s, lineout_jack_plugin %d, lineout_pin 0x%X, line%d\n",
+		  __func__, (int)lineout_jack_plugin, lineout_pin, __LINE__);
+
+	jack = snd_hda_jack_tbl_get(spec->codec, lineout_pin);
+
+	if (jack) {
+		jack->block_report = 0;
+		snd_hda_jack_report_sync(spec->codec);
+	}
+}
+
+static void lineout_callback(struct hda_codec *codec,
+			     struct hda_jack_callback *cb)
+{
+	struct cmi_spec *spec = codec->spec;
+	struct hda_jack_tbl *tbl;
+
+	/* Delay enabling the line, to let the linein-detection
+	 * state machine run.
+	 */
+
+	codec_dbg(codec, "%s, cb->nid 0x%X, line%d\n", __func__,
+		  (int)cb->nid, __LINE__);
+
+	tbl = snd_hda_jack_tbl_get(codec, cb->nid);
+	if (tbl)
+		tbl->block_report = 1;
+	schedule_delayed_work(&spec->unsol_lineout_work, msecs_to_jiffies(200));
+}
+
 static void cm9825_setup_unsol(struct hda_codec *codec)
 {
 	struct cmi_spec *spec = codec->spec;
 
 	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
 
-	snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback);
+	hda_nid_t lineout_pin = spec->gen.autocfg.line_out_pins[0];
+
+	hda_nid_t linein_pin = spec->gen.autocfg.inputs[1].pin;
+
+	if (hp_pin != 0)
+		snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback);
+
+	if (lineout_pin != 0)
+		snd_hda_jack_detect_enable_callback(codec, lineout_pin, lineout_callback);
+
+	if (linein_pin != 0)
+		snd_hda_jack_detect_enable_callback(codec, linein_pin, linein_callback);
+
+
+	codec_dbg(codec, "%s, hp_pin 0x%X, lineout_pin 0x%X, linein_pin 0x%X, line%d\n", __func__,
+		  (int)hp_pin, lineout_pin, linein_pin, __LINE__);
+
+}
+
+static void cm9825_playback_pcm_hook(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     struct snd_pcm_substream *substream,
+				     int action)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	switch (action) {
+	case HDA_GEN_PCM_ACT_PREPARE:
+		snd_hda_sequence_write(spec->codec,
+				       cm9825_gene_twl7_playback_start_verbs);
+		break;
+	case HDA_GEN_PCM_ACT_CLEANUP:
+		snd_hda_sequence_write(spec->codec,
+				       cm9825_gene_twl7_playback_stop_verbs);
+		break;
+	default:
+		return;
+	}
 }
 
 static int cm9825_init(struct hda_codec *codec)
@@ -179,26 +378,61 @@ static int cm9825_init(struct hda_codec *codec)
 	return 0;
 }
 
-static void cm9825_remove(struct hda_codec *codec)
+static void cm9825_cm_std_remove(struct hda_codec *codec)
 {
 	struct cmi_spec *spec = codec->spec;
 
 	cancel_delayed_work_sync(&spec->unsol_hp_work);
+}
+
+static void cm9825_gene_twl7_remove(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	cancel_delayed_work_sync(&spec->unsol_linein_work);
+	cancel_delayed_work_sync(&spec->unsol_lineout_work);
+}
+
+static void cm9825_remove(struct hda_codec *codec)
+{
+	if (codec->core.subsystem_id == QUIRK_CM_STD)
+		cm9825_cm_std_remove(codec);
+	else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID)
+		cm9825_gene_twl7_remove(codec);
+
 	snd_hda_gen_remove(codec);
 }
 
-static int cm9825_suspend(struct hda_codec *codec)
+static void cm9825_cm_std_suspend(struct hda_codec *codec)
 {
 	struct cmi_spec *spec = codec->spec;
 
 	cancel_delayed_work_sync(&spec->unsol_hp_work);
+}
+
+static void cm9825_gene_twl7_suspend(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	cancel_delayed_work_sync(&spec->unsol_linein_work);
+	cancel_delayed_work_sync(&spec->unsol_lineout_work);
+}
+
+static int cm9825_suspend(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	if (codec->core.subsystem_id == QUIRK_CM_STD)
+		cm9825_cm_std_suspend(codec);
+	else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID)
+		cm9825_gene_twl7_suspend(codec);
 
 	snd_hda_sequence_write(codec, spec->chip_d3_verbs);
 
 	return 0;
 }
 
-static int cm9825_resume(struct hda_codec *codec)
+static int cm9825_cm_std_resume(struct hda_codec *codec)
 {
 	struct cmi_spec *spec = codec->spec;
 	hda_nid_t hp_pin = 0;
@@ -213,7 +447,7 @@ static int cm9825_resume(struct hda_codec *codec)
 
 	msleep(150);		/* for depop noise */
 
-	snd_hda_codec_init(codec);
+	snd_hda_sequence_write(codec, spec->chip_d0_verbs);
 
 	hp_pin = spec->gen.autocfg.hp_pins[0];
 	hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
@@ -232,6 +466,18 @@ static int cm9825_resume(struct hda_codec *codec)
 		snd_hda_sequence_write(codec, cm9825_hp_remove_verbs);
 	}
 
+	return 0;
+}
+
+static int cm9825_resume(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	if (codec->core.subsystem_id == QUIRK_CM_STD)
+		cm9825_cm_std_resume(codec);
+	else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID)
+		snd_hda_sequence_write(codec, spec->chip_d0_verbs);
+
 	snd_hda_regmap_sync(codec);
 	hda_call_check_power_status(codec, 0x01);
 
@@ -242,13 +488,15 @@ 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;
+	int err = 0;
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed);
+	codec_dbg(codec, "chip_name: %s, ssid: 0x%X\n",
+		  codec->core.chip_name, codec->core.subsystem_id);
+
 	codec->spec = spec;
 	spec->codec = codec;
 	cfg = &spec->gen.autocfg;
@@ -258,6 +506,36 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
 	spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
 	spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
 
+	switch (codec->core.subsystem_id) {
+	case QUIRK_CM_STD:
+		snd_hda_codec_set_name(codec, "CM9825 STD");
+		INIT_DELAYED_WORK(&spec->unsol_hp_work,
+				  cm9825_unsol_hp_delayed);
+		spec->chip_d0_verbs = cm9825_std_d0_verbs;
+		spec->chip_d3_verbs = cm9825_std_d3_verbs;
+		spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
+		spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
+		cm9825_setup_unsol(codec);
+		break;
+	case QUIRK_GENE_TWL7_SSID:
+		snd_hda_codec_set_name(codec, "CM9825 GENE_TWL7");
+		INIT_DELAYED_WORK(&spec->unsol_linein_work,
+				  cm9825_unsol_linein_delayed);
+		INIT_DELAYED_WORK(&spec->unsol_lineout_work,
+				  cm9825_unsol_lineout_delayed);
+		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;
+		snd_hda_codec_set_pincfg(codec, 0x37, 0x24A70100);
+		break;
+	default:
+		err = -ENXIO;
+		break;
+	}
+
+	if (err < 0)
+		goto error;
+
 	snd_hda_sequence_write(codec, spec->chip_d0_verbs);
 
 	err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
-- 
2.43.0
Re: [PATCH] ALSA: hda/cm9825: Add new project GENE_TWL7 for AAEON
Posted by Takashi Iwai 6 hours ago
On Mon, 15 Dec 2025 12:22:46 +0100,
Leo Tsai wrote:
> 
> The GENE_TWL7 project is an AAEON platform with a fixed audio
> configuration consisting of line-out, line-in, 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>

It's good that you react quickly, and the patch looks much better
now.  But don't rush; we have time.

Before resubmission, re-read your patch again and again.  At each
change, you might have broken something else, too.
And, verify whether the patch really works as expected, as well as
verify it doesn't break other models.

Last but not least, please re-read what the previous reviews told.
You forgot the version prefix in the subject again, for example.
(And if there are fixes of the existing models, rather split it as
another fix patch as a preliminary.)


About the code changes:

> +/*
> + * Enable CLK/ADC to start recording.
> + */
> +static const struct hda_verb cm9825_gene_twl7_d0_verbs[] = {
> +	{0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},

In general, we set EAPD at init phase.  It's OK to do it dynamically
here, though.

> +	{0x43, CM9825_VERB_SET_SNR, 0x38},
> +	{0x43, CM9825_VERB_SET_PLL, 0x00},
> +	{0x43, CM9825_VERB_SET_ADCL, 0xcf},
> +	{0x43, CM9825_VERB_SET_DACL, 0xaa},
> +	{0x43, CM9825_VERB_SET_MBIAS, 0x1c},
> +	{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},
> +	{0x43, CM9825_VERB_SET_HPF_1, 0x40},
> +	{0x43, CM9825_VERB_SET_HPF_2, 0x40},
> +	{0x40, AC_VERB_SET_CONNECT_SEL, 0x00},
> +	{0x3d, AC_VERB_SET_CONNECT_SEL, 0x01},

What's the reason to tweak the node connections here?
Isn't it wired properly beforehand?

> +static void cm9825_unsol_linein_delayed(struct work_struct *work)
> +{
> +	struct cmi_spec *spec =
> +	    container_of(to_delayed_work(work), struct cmi_spec,
> +			 unsol_linein_work);
> +	struct hda_jack_tbl *jack;
> +
> +	hda_nid_t linein_pin = spec->gen.autocfg.inputs[1].pin;

This blindly assumes that this second input is the line-in.
It means that the primary input is mic-in, and mic-in doesn't need the
delayed jack detection...?

> +static void linein_callback(struct hda_codec *codec,
> +			    struct hda_jack_callback *cb)
> +{
> +	struct cmi_spec *spec = codec->spec;
> +	struct hda_jack_tbl *tbl;
> +
> +	/* Delay enabling the line, to let the linein-detection
> +	 * state machine run.
> +	 */
> +
> +	codec_dbg(codec, "%s, cb->nid 0x%X, line%d\n", __func__,
> +		    (int)cb->nid, __LINE__);
> +
> +	tbl = snd_hda_jack_tbl_get(codec, cb->nid);
> +	if (tbl)
> +		tbl->block_report = 1;
> +	schedule_delayed_work(&spec->unsol_linein_work, msecs_to_jiffies(200));
> +}

Basically for all three (hp, line-out, line-in), the code itself is
identical except for the pin ID.  They can be unified somehow better.

>  static void cm9825_setup_unsol(struct hda_codec *codec)
>  {
>  	struct cmi_spec *spec = codec->spec;
>  
>  	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
>  
> -	snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback);
> +	hda_nid_t lineout_pin = spec->gen.autocfg.line_out_pins[0];
> +
> +	hda_nid_t linein_pin = spec->gen.autocfg.inputs[1].pin;

Again, taking inputs[1] is flaky.

>  static int cm9825_init(struct hda_codec *codec)
> @@ -179,26 +378,61 @@ static int cm9825_init(struct hda_codec *codec)
>  	return 0;
>  }
>  
> -static void cm9825_remove(struct hda_codec *codec)
> +static void cm9825_cm_std_remove(struct hda_codec *codec)
>  {
>  	struct cmi_spec *spec = codec->spec;
>  
>  	cancel_delayed_work_sync(&spec->unsol_hp_work);
> +}
> +
> +static void cm9825_gene_twl7_remove(struct hda_codec *codec)
> +{
> +	struct cmi_spec *spec = codec->spec;
> +
> +	cancel_delayed_work_sync(&spec->unsol_linein_work);
> +	cancel_delayed_work_sync(&spec->unsol_lineout_work);

The initializations of those work rather depend on the pin
configuration, and strictly speaking, they aren't tied with the
models.  e.g. user/BIOS may override the pin configurations.

That said, the cancel calls should be conditional for each work
instatiation.  You can introduce some flags, for example.

> -static int cm9825_resume(struct hda_codec *codec)
> +static int cm9825_cm_std_resume(struct hda_codec *codec)
>  {
>  	struct cmi_spec *spec = codec->spec;
>  	hda_nid_t hp_pin = 0;
> @@ -213,7 +447,7 @@ static int cm9825_resume(struct hda_codec *codec)
>  
>  	msleep(150);		/* for depop noise */
>  
> -	snd_hda_codec_init(codec);
> +	snd_hda_sequence_write(codec, spec->chip_d0_verbs);

This really changes the behavior.  Are you sure that you don't miss
anything?  e.g. snd_hda_codec_init() calls snd_hda_gen_init(), which
will be lost by your patch.

> @@ -258,6 +506,36 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
>  	spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
>  	spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
>  
> +	switch (codec->core.subsystem_id) {
> +	case QUIRK_CM_STD:
> +		snd_hda_codec_set_name(codec, "CM9825 STD");
> +		INIT_DELAYED_WORK(&spec->unsol_hp_work,
> +				  cm9825_unsol_hp_delayed);
> +		spec->chip_d0_verbs = cm9825_std_d0_verbs;
> +		spec->chip_d3_verbs = cm9825_std_d3_verbs;
> +		spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
> +		spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
> +		cm9825_setup_unsol(codec);

Why it's called here; cm9825_setup_unsol() is called later, no?

> +		break;
> +	case QUIRK_GENE_TWL7_SSID:
> +		snd_hda_codec_set_name(codec, "CM9825 GENE_TWL7");
> +		INIT_DELAYED_WORK(&spec->unsol_linein_work,
> +				  cm9825_unsol_linein_delayed);
> +		INIT_DELAYED_WORK(&spec->unsol_lineout_work,
> +				  cm9825_unsol_lineout_delayed);
> +		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;
> +		snd_hda_codec_set_pincfg(codec, 0x37, 0x24A70100);

Don't put a magic number.  I guess it's a mic pin?  Define it properly
with a comment.


thanks,

Takashi