1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * CM9825 HD-audio codec
4 */
5
6 #include <linux/init.h>
7 #include <linux/slab.h>
8 #include <linux/module.h>
9 #include <sound/core.h>
10 #include <sound/hda_codec.h>
11 #include "hda_local.h"
12 #include "hda_auto_parser.h"
13 #include "hda_jack.h"
14 #include "generic.h"
15
16 enum {
17 QUIRK_CM_STD = 0x0,
18 QUIRK_GENE_TWL7_SSID = 0x160dc000
19 };
20
21 /* CM9825 Offset Definitions */
22
23 #define CM9825_VERB_SET_HPF_1 0x781
24 #define CM9825_VERB_SET_HPF_2 0x785
25 #define CM9825_VERB_SET_PLL 0x7a0
26 #define CM9825_VERB_SET_NEG 0x7a1
27 #define CM9825_VERB_SET_ADCL 0x7a2
28 #define CM9825_VERB_SET_DACL 0x7a3
29 #define CM9825_VERB_SET_MBIAS 0x7a4
30 #define CM9825_VERB_SET_VNEG 0x7a8
31 #define CM9825_VERB_SET_D2S 0x7a9
32 #define CM9825_VERB_SET_DACTRL 0x7aa
33 #define CM9825_VERB_SET_P3BCP 0x7ab
34 #define CM9825_VERB_SET_PDNEG 0x7ac
35 #define CM9825_VERB_SET_VDO 0x7ad
36 #define CM9825_VERB_SET_CDALR 0x7b0
37 #define CM9825_VERB_SET_MTCBA 0x7b1
38 #define CM9825_VERB_SET_OTP 0x7b2
39 #define CM9825_VERB_SET_OCP 0x7b3
40 #define CM9825_VERB_SET_GAD 0x7b4
41 #define CM9825_VERB_SET_TMOD 0x7b5
42 #define CM9825_VERB_SET_SNR 0x7b6
43
44 struct cmi_spec {
45 struct hda_gen_spec gen;
46 const struct hda_verb *chip_d0_verbs;
47 const struct hda_verb *chip_d3_verbs;
48 const struct hda_verb *chip_hp_present_verbs;
49 const struct hda_verb *chip_hp_remove_verbs;
50 struct hda_codec *codec;
51 struct delayed_work unsol_inputs_work;
52 struct delayed_work unsol_lineout_work;
53 struct delayed_work unsol_hp_work;
54 hda_nid_t jd_cap_hp;
55 hda_nid_t jd_cap_lineout;
56 hda_nid_t jd_cap_inputs[AUTO_CFG_MAX_INS];
57 int quirk;
58 };
59
60 static const struct hda_verb cm9825_std_d3_verbs[] = {
61 /* chip sleep verbs */
62 {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */
63 {0x43, CM9825_VERB_SET_PLL, 0x01}, /* PLL set */
64 {0x43, CM9825_VERB_SET_NEG, 0xc2}, /* NEG set */
65 {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */
66 {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */
67 {0x43, CM9825_VERB_SET_VNEG, 0x50}, /* VOL NEG */
68 {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */
69 {0x43, CM9825_VERB_SET_PDNEG, 0x04}, /* SEL OSC */
70 {0x43, CM9825_VERB_SET_CDALR, 0xf6}, /* Class D */
71 {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */
72 {}
73 };
74
75 static const struct hda_verb cm9825_std_d0_verbs[] = {
76 /* chip init verbs */
77 {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, /* EAPD set */
78 {0x43, CM9825_VERB_SET_SNR, 0x30}, /* SNR set */
79 {0x43, CM9825_VERB_SET_PLL, 0x00}, /* PLL set */
80 {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */
81 {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */
82 {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */
83 {0x43, CM9825_VERB_SET_VNEG, 0x56}, /* VOL NEG */
84 {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */
85 {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */
86 {0x43, CM9825_VERB_SET_PDNEG, 0x0c}, /* SEL OSC */
87 {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */
88 {0x43, CM9825_VERB_SET_CDALR, 0xf4}, /* Class D */
89 {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */
90 {0x43, CM9825_VERB_SET_MTCBA, 0x61}, /* SR set */
91 {0x43, CM9825_VERB_SET_OCP, 0x33}, /* OTP set */
92 {0x43, CM9825_VERB_SET_GAD, 0x07}, /* ADC -3db */
93 {0x43, CM9825_VERB_SET_TMOD, 0x26}, /* Class D clk */
94 {0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
95 AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d}, /* Gain set */
96 {0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
97 AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d}, /* Gain set */
98 {0x43, CM9825_VERB_SET_HPF_1, 0x40}, /* HPF set */
99 {0x43, CM9825_VERB_SET_HPF_2, 0x40}, /* HPF set */
100 {}
101 };
102
103 static const struct hda_verb cm9825_hp_present_verbs[] = {
104 {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, /* PIN off */
105 {0x43, CM9825_VERB_SET_ADCL, 0x88}, /* ADC */
106 {0x43, CM9825_VERB_SET_DACL, 0xaa}, /* DACL */
107 {0x43, CM9825_VERB_SET_MBIAS, 0x10}, /* MBIAS */
108 {0x43, CM9825_VERB_SET_D2S, 0xf2}, /* depop */
109 {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */
110 {0x43, CM9825_VERB_SET_VDO, 0xc4}, /* VDO set */
111 {}
112 };
113
114 static const struct hda_verb cm9825_hp_remove_verbs[] = {
115 {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */
116 {0x43, CM9825_VERB_SET_DACL, 0x56}, /* DACL */
117 {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */
118 {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */
119 {0x43, CM9825_VERB_SET_DACTRL, 0xe0}, /* DACTRL set */
120 {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */
121 {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* PIN on */
122 {}
123 };
124
125 /*
126 * To save power, AD/CLK is turned off.
127 */
128 static const struct hda_verb cm9825_gene_twl7_d3_verbs[] = {
129 {0x43, CM9825_VERB_SET_D2S, 0x62},
130 {0x43, CM9825_VERB_SET_PLL, 0x01},
131 {0x43, CM9825_VERB_SET_NEG, 0xc2},
132 {0x43, CM9825_VERB_SET_ADCL, 0x00},
133 {0x43, CM9825_VERB_SET_DACL, 0x02},
134 {0x43, CM9825_VERB_SET_MBIAS, 0x00},
135 {0x43, CM9825_VERB_SET_VNEG, 0x50},
136 {0x43, CM9825_VERB_SET_PDNEG, 0x04},
137 {0x43, CM9825_VERB_SET_CDALR, 0xf6},
138 {0x43, CM9825_VERB_SET_OTP, 0xcd},
139 {}
140 };
141
142 /*
143 * These settings are required to properly enable the PLL, clock, ADC and
144 * DAC paths, and to select the correct analog input routing. Without
145 * these explicit configurations, the ADC does not start correctly and
146 * recording does not work reliably on this hardware.
147 *
148 * D0 configuration: enable PLL/CLK/ADC/DAC and optimize performance
149 */
150 static const struct hda_verb cm9825_gene_twl7_d0_verbs[] = {
151 {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
152 {0x43, CM9825_VERB_SET_SNR, 0x38},
153 {0x43, CM9825_VERB_SET_PLL, 0x00},
154 {0x43, CM9825_VERB_SET_ADCL, 0xcf},
155 {0x43, CM9825_VERB_SET_DACL, 0xaa},
156 {0x43, CM9825_VERB_SET_MBIAS, 0x1c},
157 {0x43, CM9825_VERB_SET_VNEG, 0x56},
158 {0x43, CM9825_VERB_SET_D2S, 0x62},
159 {0x43, CM9825_VERB_SET_DACTRL, 0x00},
160 {0x43, CM9825_VERB_SET_PDNEG, 0x0c},
161 {0x43, CM9825_VERB_SET_CDALR, 0xf4},
162 {0x43, CM9825_VERB_SET_OTP, 0xcd},
163 {0x43, CM9825_VERB_SET_MTCBA, 0x61},
164 {0x43, CM9825_VERB_SET_OCP, 0x33},
165 {0x43, CM9825_VERB_SET_GAD, 0x07},
166 {0x43, CM9825_VERB_SET_TMOD, 0x26},
167 {0x43, CM9825_VERB_SET_HPF_1, 0x40},
168 {0x43, CM9825_VERB_SET_HPF_2, 0x40},
169 {0x40, AC_VERB_SET_CONNECT_SEL, 0x00},
170 {0x3d, AC_VERB_SET_CONNECT_SEL, 0x01},
171 {0x46, CM9825_VERB_SET_P3BCP, 0x20},
172 {}
173 };
174
175 /*
176 * Enable DAC to start playback.
177 */
178 static const struct hda_verb cm9825_gene_twl7_playback_start_verbs[] = {
179 {0x43, CM9825_VERB_SET_D2S, 0xf2},
180 {0x43, CM9825_VERB_SET_VDO, 0xd4},
181 {0x43, CM9825_VERB_SET_SNR, 0x30},
182 {}
183 };
184
185 /*
186 * Disable DAC and enable de-pop noise mechanism.
187 */
188 static const struct hda_verb cm9825_gene_twl7_playback_stop_verbs[] = {
189 {0x43, CM9825_VERB_SET_VDO, 0xc0},
190 {0x43, CM9825_VERB_SET_D2S, 0x62},
191 {0x43, CM9825_VERB_SET_VDO, 0xd0},
192 {0x43, CM9825_VERB_SET_SNR, 0x38},
193 {}
194 };
195
cm9825_update_jk_plug_status(struct hda_codec * codec,hda_nid_t nid)196 static void cm9825_update_jk_plug_status(struct hda_codec *codec, hda_nid_t nid)
197 {
198 struct cmi_spec *spec = codec->spec;
199 bool jack_plugin;
200 struct hda_jack_tbl *jack;
201
202 jack_plugin = snd_hda_jack_detect(spec->codec, nid);
203 jack = snd_hda_jack_tbl_get(spec->codec, nid);
204 if (jack) {
205 jack->block_report = 0;
206 snd_hda_jack_report_sync(spec->codec);
207 }
208
209 codec_dbg(spec->codec,
210 "%s, jack_plugin %d, nid 0x%X, line%d\n",
211 __func__, (int)jack_plugin, nid, __LINE__);
212 }
213
cm9825_unsol_inputs_delayed(struct work_struct * work)214 static void cm9825_unsol_inputs_delayed(struct work_struct *work)
215 {
216 struct cmi_spec *spec =
217 container_of(to_delayed_work(work), struct cmi_spec,
218 unsol_inputs_work);
219 int i;
220
221 for (i = 0; i < spec->gen.autocfg.num_inputs; i++) {
222 if (!spec->jd_cap_inputs[i])
223 continue;
224
225 cm9825_update_jk_plug_status(spec->codec,
226 spec->gen.autocfg.inputs[i].pin);
227 }
228 }
229
cm9825_unsol_lineout_delayed(struct work_struct * work)230 static void cm9825_unsol_lineout_delayed(struct work_struct *work)
231 {
232 struct cmi_spec *spec =
233 container_of(to_delayed_work(work), struct cmi_spec,
234 unsol_lineout_work);
235
236 cm9825_update_jk_plug_status(spec->codec,
237 spec->gen.autocfg.line_out_pins[0]);
238 }
239
cm9825_unsol_hp_delayed(struct work_struct * work)240 static void cm9825_unsol_hp_delayed(struct work_struct *work)
241 {
242 struct cmi_spec *spec =
243 container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work);
244 struct hda_jack_tbl *jack;
245 hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
246 bool hp_jack_plugin = false;
247 int err = 0;
248
249 hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
250
251 codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
252 (int)hp_jack_plugin, hp_pin);
253
254 if (!hp_jack_plugin) {
255 err =
256 snd_hda_codec_write(spec->codec, 0x42, 0,
257 AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
258 if (err)
259 codec_dbg(spec->codec, "codec_write err %d\n", err);
260
261 snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs);
262 } else {
263 snd_hda_sequence_write(spec->codec,
264 spec->chip_hp_present_verbs);
265 }
266
267 jack = snd_hda_jack_tbl_get(spec->codec, hp_pin);
268 if (jack) {
269 jack->block_report = 0;
270 snd_hda_jack_report_sync(spec->codec);
271 }
272 }
273
hp_callback(struct hda_codec * codec,struct hda_jack_callback * cb)274 static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
275 {
276 struct cmi_spec *spec = codec->spec;
277 struct hda_jack_tbl *tbl;
278
279 /* Delay enabling the HP amp, to let the mic-detection
280 * state machine run.
281 */
282
283 codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid);
284
285 tbl = snd_hda_jack_tbl_get(codec, cb->nid);
286 if (tbl)
287 tbl->block_report = 1;
288
289 if (cb->nid == spec->jd_cap_hp)
290 schedule_delayed_work(&spec->unsol_hp_work,
291 msecs_to_jiffies(200));
292 else if (cb->nid == spec->jd_cap_lineout)
293 schedule_delayed_work(&spec->unsol_lineout_work,
294 msecs_to_jiffies(200));
295
296 for (int i = 0; i < spec->gen.autocfg.num_inputs; i++) {
297 if (cb->nid == spec->jd_cap_inputs[i])
298 schedule_delayed_work(&spec->unsol_inputs_work,
299 msecs_to_jiffies(200));
300 }
301 }
302
cm9825_setup_unsol(struct hda_codec * codec)303 static void cm9825_setup_unsol(struct hda_codec *codec)
304 {
305 struct cmi_spec *spec = codec->spec;
306 int i;
307
308 hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
309
310 hda_nid_t lineout_pin = spec->gen.autocfg.line_out_pins[0];
311
312 if (hp_pin != 0) {
313 if (is_jack_detectable(codec, hp_pin)) {
314 spec->jd_cap_hp = hp_pin;
315 snd_hda_jack_detect_enable_callback(codec, hp_pin,
316 hp_callback);
317 } else
318 spec->jd_cap_hp = 0;
319 } else
320 spec->jd_cap_hp = 0;
321
322 if (lineout_pin != 0) {
323 if (is_jack_detectable(codec, lineout_pin)) {
324 spec->jd_cap_lineout = lineout_pin;
325 snd_hda_jack_detect_enable_callback(codec, lineout_pin,
326 hp_callback);
327 } else
328 spec->jd_cap_lineout = 0;
329 } else
330 spec->jd_cap_lineout = 0;
331
332 codec_dbg(codec,
333 "%s, jd_cap_hp 0x%02X, jd_cap_lineout 0x%02X, line%d\n",
334 __func__, spec->jd_cap_hp, spec->jd_cap_lineout, __LINE__);
335
336 for (i = 0; i < spec->gen.autocfg.num_inputs; i++) {
337 if (spec->gen.autocfg.inputs[i].pin != 0) {
338 if (is_jack_detectable
339 (codec, spec->gen.autocfg.inputs[i].pin)) {
340 spec->jd_cap_inputs[i] =
341 spec->gen.autocfg.inputs[i].pin;
342 snd_hda_jack_detect_enable_callback(codec,
343 spec->gen.autocfg.inputs[i].pin,
344 hp_callback);
345 } else
346 spec->jd_cap_inputs[i] = 0;
347 } else
348 spec->jd_cap_inputs[i] = 0;
349
350 codec_dbg(codec,
351 "%s, input jd_cap_inputs[%d] 0x%02X, line%d\n",
352 __func__, i, spec->jd_cap_inputs[i], __LINE__);
353 }
354 }
355
cm9825_playback_pcm_hook(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream,int action)356 static void cm9825_playback_pcm_hook(struct hda_pcm_stream *hinfo,
357 struct hda_codec *codec,
358 struct snd_pcm_substream *substream,
359 int action)
360 {
361 struct cmi_spec *spec = codec->spec;
362
363 switch (action) {
364 case HDA_GEN_PCM_ACT_PREPARE:
365 snd_hda_sequence_write(spec->codec,
366 cm9825_gene_twl7_playback_start_verbs);
367 break;
368 case HDA_GEN_PCM_ACT_CLEANUP:
369 snd_hda_sequence_write(spec->codec,
370 cm9825_gene_twl7_playback_stop_verbs);
371 break;
372 default:
373 return;
374 }
375 }
376
cm9825_init(struct hda_codec * codec)377 static int cm9825_init(struct hda_codec *codec)
378 {
379 snd_hda_gen_init(codec);
380 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
381
382 return 0;
383 }
384
cm9825_remove(struct hda_codec * codec)385 static void cm9825_remove(struct hda_codec *codec)
386 {
387 struct cmi_spec *spec = codec->spec;
388 int i;
389
390 if (spec->jd_cap_hp)
391 cancel_delayed_work_sync(&spec->unsol_hp_work);
392
393 if (spec->jd_cap_lineout)
394 cancel_delayed_work_sync(&spec->unsol_lineout_work);
395
396 for (i = 0; i < spec->gen.autocfg.num_inputs; i++) {
397 if (spec->jd_cap_inputs[i]) {
398 cancel_delayed_work_sync(&spec->unsol_inputs_work);
399 break;
400 }
401 }
402
403 snd_hda_gen_remove(codec);
404 }
405
cm9825_suspend(struct hda_codec * codec)406 static int cm9825_suspend(struct hda_codec *codec)
407 {
408 struct cmi_spec *spec = codec->spec;
409 int i;
410
411 if (spec->jd_cap_hp)
412 cancel_delayed_work_sync(&spec->unsol_hp_work);
413
414 if (spec->jd_cap_lineout)
415 cancel_delayed_work_sync(&spec->unsol_lineout_work);
416
417 for (i = 0; i < spec->gen.autocfg.num_inputs; i++) {
418 if (spec->jd_cap_inputs[i]) {
419 cancel_delayed_work_sync(&spec->unsol_inputs_work);
420 break;
421 }
422 }
423
424 snd_hda_sequence_write(codec, spec->chip_d3_verbs);
425
426 return 0;
427 }
428
cm9825_cm_std_resume(struct hda_codec * codec)429 static int cm9825_cm_std_resume(struct hda_codec *codec)
430 {
431 struct cmi_spec *spec = codec->spec;
432 hda_nid_t hp_pin = 0;
433 bool hp_jack_plugin = false;
434 int err;
435
436 err =
437 snd_hda_codec_write(spec->codec, 0x42, 0,
438 AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
439 if (err)
440 codec_dbg(codec, "codec_write err %d\n", err);
441
442 msleep(150); /* for depop noise */
443
444 snd_hda_codec_init(codec);
445
446 snd_hda_sequence_write(codec, spec->chip_d0_verbs);
447
448 hp_pin = spec->gen.autocfg.hp_pins[0];
449 hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
450
451 codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
452 (int)hp_jack_plugin, hp_pin);
453
454 if (!hp_jack_plugin) {
455 err =
456 snd_hda_codec_write(spec->codec, 0x42, 0,
457 AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
458
459 if (err)
460 codec_dbg(codec, "codec_write err %d\n", err);
461
462 snd_hda_sequence_write(codec, cm9825_hp_remove_verbs);
463 }
464
465 return 0;
466 }
467
cm9825_resume(struct hda_codec * codec)468 static int cm9825_resume(struct hda_codec *codec)
469 {
470 struct cmi_spec *spec = codec->spec;
471
472 if (codec->core.subsystem_id == QUIRK_CM_STD)
473 cm9825_cm_std_resume(codec);
474 else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) {
475 snd_hda_codec_init(codec);
476 snd_hda_sequence_write(codec, spec->chip_d0_verbs);
477 }
478
479 snd_hda_regmap_sync(codec);
480 hda_call_check_power_status(codec, 0x01);
481
482 return 0;
483 }
484
cm9825_probe(struct hda_codec * codec,const struct hda_device_id * id)485 static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
486 {
487 struct cmi_spec *spec;
488 struct auto_pin_cfg *cfg;
489 int err = 0;
490
491 spec = kzalloc_obj(*spec);
492 if (spec == NULL)
493 return -ENOMEM;
494
495 codec_dbg(codec, "chip_name: %s, ssid: 0x%X\n",
496 codec->core.chip_name, codec->core.subsystem_id);
497
498 codec->spec = spec;
499 spec->codec = codec;
500 cfg = &spec->gen.autocfg;
501 snd_hda_gen_spec_init(&spec->gen);
502 spec->chip_d0_verbs = cm9825_std_d0_verbs;
503 spec->chip_d3_verbs = cm9825_std_d3_verbs;
504 spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
505 spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
506
507 INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed);
508 INIT_DELAYED_WORK(&spec->unsol_inputs_work,
509 cm9825_unsol_inputs_delayed);
510 INIT_DELAYED_WORK(&spec->unsol_lineout_work,
511 cm9825_unsol_lineout_delayed);
512
513 switch (codec->core.subsystem_id) {
514 case QUIRK_CM_STD:
515 snd_hda_codec_set_name(codec, "CM9825 STD");
516 spec->chip_d0_verbs = cm9825_std_d0_verbs;
517 spec->chip_d3_verbs = cm9825_std_d3_verbs;
518 spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
519 spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
520 break;
521 case QUIRK_GENE_TWL7_SSID:
522 snd_hda_codec_set_name(codec, "CM9825 GENE_TWL7");
523 spec->chip_d0_verbs = cm9825_gene_twl7_d0_verbs;
524 spec->chip_d3_verbs = cm9825_gene_twl7_d3_verbs;
525 spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
526 /* Internal fixed device, Rear, Mic-in, 3.5mm */
527 snd_hda_codec_set_pincfg(codec, 0x37, 0x24A70100);
528 break;
529 default:
530 err = -ENXIO;
531 break;
532 }
533
534 if (err < 0)
535 goto error;
536
537 snd_hda_sequence_write(codec, spec->chip_d0_verbs);
538
539 err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
540 if (err < 0)
541 goto error;
542 err = snd_hda_gen_parse_auto_config(codec, cfg);
543 if (err < 0)
544 goto error;
545
546 cm9825_setup_unsol(codec);
547
548 return 0;
549
550 error:
551 cm9825_remove(codec);
552
553 codec_info(codec, "Enter err %d\n", err);
554
555 return err;
556 }
557
558 static const struct hda_codec_ops cm9825_codec_ops = {
559 .probe = cm9825_probe,
560 .remove = cm9825_remove,
561 .build_controls = snd_hda_gen_build_controls,
562 .build_pcms = snd_hda_gen_build_pcms,
563 .init = cm9825_init,
564 .unsol_event = snd_hda_jack_unsol_event,
565 .suspend = cm9825_suspend,
566 .resume = cm9825_resume,
567 .check_power_status = snd_hda_gen_check_power_status,
568 .stream_pm = snd_hda_gen_stream_pm,
569 };
570
571 /*
572 * driver entries
573 */
574 static const struct hda_device_id snd_hda_id_cm9825[] = {
575 HDA_CODEC_ID(0x13f69825, "CM9825"),
576 {} /* terminator */
577 };
578 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cm9825);
579
580 MODULE_LICENSE("GPL");
581 MODULE_DESCRIPTION("CM9825 HD-audio codec");
582
583 static struct hda_codec_driver cm9825_driver = {
584 .id = snd_hda_id_cm9825,
585 .ops = &cm9825_codec_ops,
586 };
587
588 module_hda_codec_driver(cm9825_driver);
589