xref: /linux/sound/hda/codecs/cm9825.c (revision 177bf8620cf4ed290ee170a6c5966adc0924b336)
1*0f1e8306STakashi Iwai // SPDX-License-Identifier: GPL-2.0-or-later
2*0f1e8306STakashi Iwai /*
3*0f1e8306STakashi Iwai  * CM9825 HD-audio codec
4*0f1e8306STakashi Iwai  */
5*0f1e8306STakashi Iwai 
6*0f1e8306STakashi Iwai #include <linux/init.h>
7*0f1e8306STakashi Iwai #include <linux/slab.h>
8*0f1e8306STakashi Iwai #include <linux/module.h>
9*0f1e8306STakashi Iwai #include <sound/core.h>
10*0f1e8306STakashi Iwai #include <sound/hda_codec.h>
11*0f1e8306STakashi Iwai #include "hda_local.h"
12*0f1e8306STakashi Iwai #include "hda_auto_parser.h"
13*0f1e8306STakashi Iwai #include "hda_jack.h"
14*0f1e8306STakashi Iwai #include "generic.h"
15*0f1e8306STakashi Iwai 
16*0f1e8306STakashi Iwai /* CM9825 Offset Definitions */
17*0f1e8306STakashi Iwai 
18*0f1e8306STakashi Iwai #define CM9825_VERB_SET_HPF_1 0x781
19*0f1e8306STakashi Iwai #define CM9825_VERB_SET_HPF_2 0x785
20*0f1e8306STakashi Iwai #define CM9825_VERB_SET_PLL 0x7a0
21*0f1e8306STakashi Iwai #define CM9825_VERB_SET_NEG 0x7a1
22*0f1e8306STakashi Iwai #define CM9825_VERB_SET_ADCL 0x7a2
23*0f1e8306STakashi Iwai #define CM9825_VERB_SET_DACL 0x7a3
24*0f1e8306STakashi Iwai #define CM9825_VERB_SET_MBIAS 0x7a4
25*0f1e8306STakashi Iwai #define CM9825_VERB_SET_VNEG 0x7a8
26*0f1e8306STakashi Iwai #define CM9825_VERB_SET_D2S 0x7a9
27*0f1e8306STakashi Iwai #define CM9825_VERB_SET_DACTRL 0x7aa
28*0f1e8306STakashi Iwai #define CM9825_VERB_SET_PDNEG 0x7ac
29*0f1e8306STakashi Iwai #define CM9825_VERB_SET_VDO 0x7ad
30*0f1e8306STakashi Iwai #define CM9825_VERB_SET_CDALR 0x7b0
31*0f1e8306STakashi Iwai #define CM9825_VERB_SET_MTCBA 0x7b1
32*0f1e8306STakashi Iwai #define CM9825_VERB_SET_OTP 0x7b2
33*0f1e8306STakashi Iwai #define CM9825_VERB_SET_OCP 0x7b3
34*0f1e8306STakashi Iwai #define CM9825_VERB_SET_GAD 0x7b4
35*0f1e8306STakashi Iwai #define CM9825_VERB_SET_TMOD 0x7b5
36*0f1e8306STakashi Iwai #define CM9825_VERB_SET_SNR 0x7b6
37*0f1e8306STakashi Iwai 
38*0f1e8306STakashi Iwai struct cmi_spec {
39*0f1e8306STakashi Iwai 	struct hda_gen_spec gen;
40*0f1e8306STakashi Iwai 	const struct hda_verb *chip_d0_verbs;
41*0f1e8306STakashi Iwai 	const struct hda_verb *chip_d3_verbs;
42*0f1e8306STakashi Iwai 	const struct hda_verb *chip_hp_present_verbs;
43*0f1e8306STakashi Iwai 	const struct hda_verb *chip_hp_remove_verbs;
44*0f1e8306STakashi Iwai 	struct hda_codec *codec;
45*0f1e8306STakashi Iwai 	struct delayed_work unsol_hp_work;
46*0f1e8306STakashi Iwai 	int quirk;
47*0f1e8306STakashi Iwai };
48*0f1e8306STakashi Iwai 
49*0f1e8306STakashi Iwai static const struct hda_verb cm9825_std_d3_verbs[] = {
50*0f1e8306STakashi Iwai 	/* chip sleep verbs */
51*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_D2S, 0x62},	/* depop */
52*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_PLL, 0x01},	/* PLL set */
53*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_NEG, 0xc2},	/* NEG set */
54*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_ADCL, 0x00},	/* ADC */
55*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_DACL, 0x02},	/* DACL */
56*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_VNEG, 0x50},	/* VOL NEG */
57*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_MBIAS, 0x00},	/* MBIAS */
58*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_PDNEG, 0x04},	/* SEL OSC */
59*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_CDALR, 0xf6},	/* Class D */
60*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_OTP, 0xcd},	/* OTP set */
61*0f1e8306STakashi Iwai 	{}
62*0f1e8306STakashi Iwai };
63*0f1e8306STakashi Iwai 
64*0f1e8306STakashi Iwai static const struct hda_verb cm9825_std_d0_verbs[] = {
65*0f1e8306STakashi Iwai 	/* chip init verbs */
66*0f1e8306STakashi Iwai 	{0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},	/* EAPD set */
67*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_SNR, 0x30},	/* SNR set */
68*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_PLL, 0x00},	/* PLL set */
69*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_ADCL, 0x00},	/* ADC */
70*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_DACL, 0x02},	/* DACL */
71*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_MBIAS, 0x00},	/* MBIAS */
72*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_VNEG, 0x56},	/* VOL NEG */
73*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_D2S, 0x62},	/* depop */
74*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_DACTRL, 0x00},	/* DACTRL set */
75*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_PDNEG, 0x0c},	/* SEL OSC */
76*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_VDO, 0x80},	/* VDO set */
77*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_CDALR, 0xf4},	/* Class D */
78*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_OTP, 0xcd},	/* OTP set */
79*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_MTCBA, 0x61},	/* SR set */
80*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_OCP, 0x33},	/* OTP set */
81*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_GAD, 0x07},	/* ADC -3db */
82*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_TMOD, 0x26},	/* Class D clk */
83*0f1e8306STakashi Iwai 	{0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
84*0f1e8306STakashi Iwai 		AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d},	/* Gain set */
85*0f1e8306STakashi Iwai 	{0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
86*0f1e8306STakashi Iwai 		AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d},	/* Gain set */
87*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_HPF_1, 0x40},	/* HPF set */
88*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_HPF_2, 0x40},	/* HPF set */
89*0f1e8306STakashi Iwai 	{}
90*0f1e8306STakashi Iwai };
91*0f1e8306STakashi Iwai 
92*0f1e8306STakashi Iwai static const struct hda_verb cm9825_hp_present_verbs[] = {
93*0f1e8306STakashi Iwai 	{0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00},	/* PIN off */
94*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_ADCL, 0x88},	/* ADC */
95*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_DACL, 0xaa},	/* DACL */
96*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_MBIAS, 0x10},	/* MBIAS */
97*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_D2S, 0xf2},	/* depop */
98*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_DACTRL, 0x00},	/* DACTRL set */
99*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_VDO, 0xc4},	/* VDO set */
100*0f1e8306STakashi Iwai 	{}
101*0f1e8306STakashi Iwai };
102*0f1e8306STakashi Iwai 
103*0f1e8306STakashi Iwai static const struct hda_verb cm9825_hp_remove_verbs[] = {
104*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_ADCL, 0x00},	/* ADC */
105*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_DACL, 0x56},	/* DACL */
106*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_MBIAS, 0x00},	/* MBIAS */
107*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_D2S, 0x62},	/* depop */
108*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_DACTRL, 0xe0},	/* DACTRL set */
109*0f1e8306STakashi Iwai 	{0x43, CM9825_VERB_SET_VDO, 0x80},	/* VDO set */
110*0f1e8306STakashi Iwai 	{0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},	/* PIN on */
111*0f1e8306STakashi Iwai 	{}
112*0f1e8306STakashi Iwai };
113*0f1e8306STakashi Iwai 
cm9825_unsol_hp_delayed(struct work_struct * work)114*0f1e8306STakashi Iwai static void cm9825_unsol_hp_delayed(struct work_struct *work)
115*0f1e8306STakashi Iwai {
116*0f1e8306STakashi Iwai 	struct cmi_spec *spec =
117*0f1e8306STakashi Iwai 	    container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work);
118*0f1e8306STakashi Iwai 	struct hda_jack_tbl *jack;
119*0f1e8306STakashi Iwai 	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
120*0f1e8306STakashi Iwai 	bool hp_jack_plugin = false;
121*0f1e8306STakashi Iwai 	int err = 0;
122*0f1e8306STakashi Iwai 
123*0f1e8306STakashi Iwai 	hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
124*0f1e8306STakashi Iwai 
125*0f1e8306STakashi Iwai 	codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
126*0f1e8306STakashi Iwai 		  (int)hp_jack_plugin, hp_pin);
127*0f1e8306STakashi Iwai 
128*0f1e8306STakashi Iwai 	if (!hp_jack_plugin) {
129*0f1e8306STakashi Iwai 		err =
130*0f1e8306STakashi Iwai 		    snd_hda_codec_write(spec->codec, 0x42, 0,
131*0f1e8306STakashi Iwai 					AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
132*0f1e8306STakashi Iwai 		if (err)
133*0f1e8306STakashi Iwai 			codec_dbg(spec->codec, "codec_write err %d\n", err);
134*0f1e8306STakashi Iwai 
135*0f1e8306STakashi Iwai 		snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs);
136*0f1e8306STakashi Iwai 	} else {
137*0f1e8306STakashi Iwai 		snd_hda_sequence_write(spec->codec,
138*0f1e8306STakashi Iwai 				       spec->chip_hp_present_verbs);
139*0f1e8306STakashi Iwai 	}
140*0f1e8306STakashi Iwai 
141*0f1e8306STakashi Iwai 	jack = snd_hda_jack_tbl_get(spec->codec, hp_pin);
142*0f1e8306STakashi Iwai 	if (jack) {
143*0f1e8306STakashi Iwai 		jack->block_report = 0;
144*0f1e8306STakashi Iwai 		snd_hda_jack_report_sync(spec->codec);
145*0f1e8306STakashi Iwai 	}
146*0f1e8306STakashi Iwai }
147*0f1e8306STakashi Iwai 
hp_callback(struct hda_codec * codec,struct hda_jack_callback * cb)148*0f1e8306STakashi Iwai static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
149*0f1e8306STakashi Iwai {
150*0f1e8306STakashi Iwai 	struct cmi_spec *spec = codec->spec;
151*0f1e8306STakashi Iwai 	struct hda_jack_tbl *tbl;
152*0f1e8306STakashi Iwai 
153*0f1e8306STakashi Iwai 	/* Delay enabling the HP amp, to let the mic-detection
154*0f1e8306STakashi Iwai 	 * state machine run.
155*0f1e8306STakashi Iwai 	 */
156*0f1e8306STakashi Iwai 
157*0f1e8306STakashi Iwai 	codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid);
158*0f1e8306STakashi Iwai 
159*0f1e8306STakashi Iwai 	tbl = snd_hda_jack_tbl_get(codec, cb->nid);
160*0f1e8306STakashi Iwai 	if (tbl)
161*0f1e8306STakashi Iwai 		tbl->block_report = 1;
162*0f1e8306STakashi Iwai 	schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200));
163*0f1e8306STakashi Iwai }
164*0f1e8306STakashi Iwai 
cm9825_setup_unsol(struct hda_codec * codec)165*0f1e8306STakashi Iwai static void cm9825_setup_unsol(struct hda_codec *codec)
166*0f1e8306STakashi Iwai {
167*0f1e8306STakashi Iwai 	struct cmi_spec *spec = codec->spec;
168*0f1e8306STakashi Iwai 
169*0f1e8306STakashi Iwai 	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
170*0f1e8306STakashi Iwai 
171*0f1e8306STakashi Iwai 	snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback);
172*0f1e8306STakashi Iwai }
173*0f1e8306STakashi Iwai 
cm9825_init(struct hda_codec * codec)174*0f1e8306STakashi Iwai static int cm9825_init(struct hda_codec *codec)
175*0f1e8306STakashi Iwai {
176*0f1e8306STakashi Iwai 	snd_hda_gen_init(codec);
177*0f1e8306STakashi Iwai 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
178*0f1e8306STakashi Iwai 
179*0f1e8306STakashi Iwai 	return 0;
180*0f1e8306STakashi Iwai }
181*0f1e8306STakashi Iwai 
cm9825_remove(struct hda_codec * codec)182*0f1e8306STakashi Iwai static void cm9825_remove(struct hda_codec *codec)
183*0f1e8306STakashi Iwai {
184*0f1e8306STakashi Iwai 	struct cmi_spec *spec = codec->spec;
185*0f1e8306STakashi Iwai 
186*0f1e8306STakashi Iwai 	cancel_delayed_work_sync(&spec->unsol_hp_work);
187*0f1e8306STakashi Iwai 	snd_hda_gen_remove(codec);
188*0f1e8306STakashi Iwai }
189*0f1e8306STakashi Iwai 
cm9825_suspend(struct hda_codec * codec)190*0f1e8306STakashi Iwai static int cm9825_suspend(struct hda_codec *codec)
191*0f1e8306STakashi Iwai {
192*0f1e8306STakashi Iwai 	struct cmi_spec *spec = codec->spec;
193*0f1e8306STakashi Iwai 
194*0f1e8306STakashi Iwai 	cancel_delayed_work_sync(&spec->unsol_hp_work);
195*0f1e8306STakashi Iwai 
196*0f1e8306STakashi Iwai 	snd_hda_sequence_write(codec, spec->chip_d3_verbs);
197*0f1e8306STakashi Iwai 
198*0f1e8306STakashi Iwai 	return 0;
199*0f1e8306STakashi Iwai }
200*0f1e8306STakashi Iwai 
cm9825_resume(struct hda_codec * codec)201*0f1e8306STakashi Iwai static int cm9825_resume(struct hda_codec *codec)
202*0f1e8306STakashi Iwai {
203*0f1e8306STakashi Iwai 	struct cmi_spec *spec = codec->spec;
204*0f1e8306STakashi Iwai 	hda_nid_t hp_pin = 0;
205*0f1e8306STakashi Iwai 	bool hp_jack_plugin = false;
206*0f1e8306STakashi Iwai 	int err;
207*0f1e8306STakashi Iwai 
208*0f1e8306STakashi Iwai 	err =
209*0f1e8306STakashi Iwai 	    snd_hda_codec_write(spec->codec, 0x42, 0,
210*0f1e8306STakashi Iwai 				AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
211*0f1e8306STakashi Iwai 	if (err)
212*0f1e8306STakashi Iwai 		codec_dbg(codec, "codec_write err %d\n", err);
213*0f1e8306STakashi Iwai 
214*0f1e8306STakashi Iwai 	msleep(150);		/* for depop noise */
215*0f1e8306STakashi Iwai 
216*0f1e8306STakashi Iwai 	snd_hda_codec_init(codec);
217*0f1e8306STakashi Iwai 
218*0f1e8306STakashi Iwai 	hp_pin = spec->gen.autocfg.hp_pins[0];
219*0f1e8306STakashi Iwai 	hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
220*0f1e8306STakashi Iwai 
221*0f1e8306STakashi Iwai 	codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
222*0f1e8306STakashi Iwai 		  (int)hp_jack_plugin, hp_pin);
223*0f1e8306STakashi Iwai 
224*0f1e8306STakashi Iwai 	if (!hp_jack_plugin) {
225*0f1e8306STakashi Iwai 		err =
226*0f1e8306STakashi Iwai 		    snd_hda_codec_write(spec->codec, 0x42, 0,
227*0f1e8306STakashi Iwai 					AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
228*0f1e8306STakashi Iwai 
229*0f1e8306STakashi Iwai 		if (err)
230*0f1e8306STakashi Iwai 			codec_dbg(codec, "codec_write err %d\n", err);
231*0f1e8306STakashi Iwai 
232*0f1e8306STakashi Iwai 		snd_hda_sequence_write(codec, cm9825_hp_remove_verbs);
233*0f1e8306STakashi Iwai 	}
234*0f1e8306STakashi Iwai 
235*0f1e8306STakashi Iwai 	snd_hda_regmap_sync(codec);
236*0f1e8306STakashi Iwai 	hda_call_check_power_status(codec, 0x01);
237*0f1e8306STakashi Iwai 
238*0f1e8306STakashi Iwai 	return 0;
239*0f1e8306STakashi Iwai }
240*0f1e8306STakashi Iwai 
cm9825_probe(struct hda_codec * codec,const struct hda_device_id * id)241*0f1e8306STakashi Iwai static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
242*0f1e8306STakashi Iwai {
243*0f1e8306STakashi Iwai 	struct cmi_spec *spec;
244*0f1e8306STakashi Iwai 	struct auto_pin_cfg *cfg;
245*0f1e8306STakashi Iwai 	int err;
246*0f1e8306STakashi Iwai 
247*0f1e8306STakashi Iwai 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
248*0f1e8306STakashi Iwai 	if (spec == NULL)
249*0f1e8306STakashi Iwai 		return -ENOMEM;
250*0f1e8306STakashi Iwai 
251*0f1e8306STakashi Iwai 	INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed);
252*0f1e8306STakashi Iwai 	codec->spec = spec;
253*0f1e8306STakashi Iwai 	spec->codec = codec;
254*0f1e8306STakashi Iwai 	cfg = &spec->gen.autocfg;
255*0f1e8306STakashi Iwai 	snd_hda_gen_spec_init(&spec->gen);
256*0f1e8306STakashi Iwai 	spec->chip_d0_verbs = cm9825_std_d0_verbs;
257*0f1e8306STakashi Iwai 	spec->chip_d3_verbs = cm9825_std_d3_verbs;
258*0f1e8306STakashi Iwai 	spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
259*0f1e8306STakashi Iwai 	spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
260*0f1e8306STakashi Iwai 
261*0f1e8306STakashi Iwai 	snd_hda_sequence_write(codec, spec->chip_d0_verbs);
262*0f1e8306STakashi Iwai 
263*0f1e8306STakashi Iwai 	err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
264*0f1e8306STakashi Iwai 	if (err < 0)
265*0f1e8306STakashi Iwai 		goto error;
266*0f1e8306STakashi Iwai 	err = snd_hda_gen_parse_auto_config(codec, cfg);
267*0f1e8306STakashi Iwai 	if (err < 0)
268*0f1e8306STakashi Iwai 		goto error;
269*0f1e8306STakashi Iwai 
270*0f1e8306STakashi Iwai 	cm9825_setup_unsol(codec);
271*0f1e8306STakashi Iwai 
272*0f1e8306STakashi Iwai 	return 0;
273*0f1e8306STakashi Iwai 
274*0f1e8306STakashi Iwai  error:
275*0f1e8306STakashi Iwai 	cm9825_remove(codec);
276*0f1e8306STakashi Iwai 
277*0f1e8306STakashi Iwai 	codec_info(codec, "Enter err %d\n", err);
278*0f1e8306STakashi Iwai 
279*0f1e8306STakashi Iwai 	return err;
280*0f1e8306STakashi Iwai }
281*0f1e8306STakashi Iwai 
282*0f1e8306STakashi Iwai static const struct hda_codec_ops cm9825_codec_ops = {
283*0f1e8306STakashi Iwai 	.probe = cm9825_probe,
284*0f1e8306STakashi Iwai 	.remove = cm9825_remove,
285*0f1e8306STakashi Iwai 	.build_controls = snd_hda_gen_build_controls,
286*0f1e8306STakashi Iwai 	.build_pcms = snd_hda_gen_build_pcms,
287*0f1e8306STakashi Iwai 	.init = cm9825_init,
288*0f1e8306STakashi Iwai 	.unsol_event = snd_hda_jack_unsol_event,
289*0f1e8306STakashi Iwai 	.suspend = cm9825_suspend,
290*0f1e8306STakashi Iwai 	.resume = cm9825_resume,
291*0f1e8306STakashi Iwai 	.check_power_status = snd_hda_gen_check_power_status,
292*0f1e8306STakashi Iwai 	.stream_pm = snd_hda_gen_stream_pm,
293*0f1e8306STakashi Iwai };
294*0f1e8306STakashi Iwai 
295*0f1e8306STakashi Iwai /*
296*0f1e8306STakashi Iwai  * driver entries
297*0f1e8306STakashi Iwai  */
298*0f1e8306STakashi Iwai static const struct hda_device_id snd_hda_id_cm9825[] = {
299*0f1e8306STakashi Iwai 	HDA_CODEC_ID(0x13f69825, "CM9825"),
300*0f1e8306STakashi Iwai 	{} /* terminator */
301*0f1e8306STakashi Iwai };
302*0f1e8306STakashi Iwai MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cm9825);
303*0f1e8306STakashi Iwai 
304*0f1e8306STakashi Iwai MODULE_LICENSE("GPL");
305*0f1e8306STakashi Iwai MODULE_DESCRIPTION("CM9825 HD-audio codec");
306*0f1e8306STakashi Iwai 
307*0f1e8306STakashi Iwai static struct hda_codec_driver cm9825_driver = {
308*0f1e8306STakashi Iwai 	.id = snd_hda_id_cm9825,
309*0f1e8306STakashi Iwai 	.ops = &cm9825_codec_ops,
310*0f1e8306STakashi Iwai };
311*0f1e8306STakashi Iwai 
312*0f1e8306STakashi Iwai module_hda_codec_driver(cm9825_driver);
313