1717#include "hda_jack.h"
1818#include "hda_generic.h"
1919
20+ /* CM9825 Offset Definitions */
21+
22+ #define CM9825_VERB_SET_HPF_1 0x781
23+ #define CM9825_VERB_SET_HPF_2 0x785
24+ #define CM9825_VERB_SET_PLL 0x7a0
25+ #define CM9825_VERB_SET_NEG 0x7a1
26+ #define CM9825_VERB_SET_ADCL 0x7a2
27+ #define CM9825_VERB_SET_DACL 0x7a3
28+ #define CM9825_VERB_SET_MBIAS 0x7a4
29+ #define CM9825_VERB_SET_VNEG 0x7a8
30+ #define CM9825_VERB_SET_D2S 0x7a9
31+ #define CM9825_VERB_SET_DACTRL 0x7aa
32+ #define CM9825_VERB_SET_PDNEG 0x7ac
33+ #define CM9825_VERB_SET_VDO 0x7ad
34+ #define CM9825_VERB_SET_CDALR 0x7b0
35+ #define CM9825_VERB_SET_MTCBA 0x7b1
36+ #define CM9825_VERB_SET_OTP 0x7b2
37+ #define CM9825_VERB_SET_OCP 0x7b3
38+ #define CM9825_VERB_SET_GAD 0x7b4
39+ #define CM9825_VERB_SET_TMOD 0x7b5
40+ #define CM9825_VERB_SET_SNR 0x7b6
41+
2042struct cmi_spec {
2143 struct hda_gen_spec gen ;
44+ const struct hda_verb * chip_d0_verbs ;
45+ const struct hda_verb * chip_d3_verbs ;
46+ const struct hda_verb * chip_hp_present_verbs ;
47+ const struct hda_verb * chip_hp_remove_verbs ;
48+ struct hda_codec * codec ;
49+ struct delayed_work unsol_hp_work ;
50+ int quirk ;
51+ };
52+
53+ static const struct hda_verb cm9825_std_d3_verbs [] = {
54+ /* chip sleep verbs */
55+ {0x43 , CM9825_VERB_SET_D2S , 0x62 }, /* depop */
56+ {0x43 , CM9825_VERB_SET_PLL , 0x01 }, /* PLL set */
57+ {0x43 , CM9825_VERB_SET_NEG , 0xc2 }, /* NEG set */
58+ {0x43 , CM9825_VERB_SET_ADCL , 0x00 }, /* ADC */
59+ {0x43 , CM9825_VERB_SET_DACL , 0x02 }, /* DACL */
60+ {0x43 , CM9825_VERB_SET_VNEG , 0x50 }, /* VOL NEG */
61+ {0x43 , CM9825_VERB_SET_MBIAS , 0x00 }, /* MBIAS */
62+ {0x43 , CM9825_VERB_SET_PDNEG , 0x04 }, /* SEL OSC */
63+ {0x43 , CM9825_VERB_SET_CDALR , 0xf6 }, /* Class D */
64+ {0x43 , CM9825_VERB_SET_OTP , 0xcd }, /* OTP set */
65+ {}
66+ };
67+
68+ static const struct hda_verb cm9825_std_d0_verbs [] = {
69+ /* chip init verbs */
70+ {0x34 , AC_VERB_SET_EAPD_BTLENABLE , 0x02 }, /* EAPD set */
71+ {0x43 , CM9825_VERB_SET_SNR , 0x30 }, /* SNR set */
72+ {0x43 , CM9825_VERB_SET_PLL , 0x00 }, /* PLL set */
73+ {0x43 , CM9825_VERB_SET_ADCL , 0x00 }, /* ADC */
74+ {0x43 , CM9825_VERB_SET_DACL , 0x02 }, /* DACL */
75+ {0x43 , CM9825_VERB_SET_MBIAS , 0x00 }, /* MBIAS */
76+ {0x43 , CM9825_VERB_SET_VNEG , 0x56 }, /* VOL NEG */
77+ {0x43 , CM9825_VERB_SET_D2S , 0x62 }, /* depop */
78+ {0x43 , CM9825_VERB_SET_DACTRL , 0x00 }, /* DACTRL set */
79+ {0x43 , CM9825_VERB_SET_PDNEG , 0x0c }, /* SEL OSC */
80+ {0x43 , CM9825_VERB_SET_VDO , 0x80 }, /* VDO set */
81+ {0x43 , CM9825_VERB_SET_CDALR , 0xf4 }, /* Class D */
82+ {0x43 , CM9825_VERB_SET_OTP , 0xcd }, /* OTP set */
83+ {0x43 , CM9825_VERB_SET_MTCBA , 0x61 }, /* SR set */
84+ {0x43 , CM9825_VERB_SET_OCP , 0x33 }, /* OTP set */
85+ {0x43 , CM9825_VERB_SET_GAD , 0x07 }, /* ADC -3db */
86+ {0x43 , CM9825_VERB_SET_TMOD , 0x26 }, /* Class D clk */
87+ {0x3C , AC_VERB_SET_AMP_GAIN_MUTE |
88+ AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT , 0x2d }, /* Gain set */
89+ {0x3C , AC_VERB_SET_AMP_GAIN_MUTE |
90+ AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT , 0x2d }, /* Gain set */
91+ {0x43 , CM9825_VERB_SET_HPF_1 , 0x40 }, /* HPF set */
92+ {0x43 , CM9825_VERB_SET_HPF_2 , 0x40 }, /* HPF set */
93+ {}
2294};
2395
96+ static const struct hda_verb cm9825_hp_present_verbs [] = {
97+ {0x42 , AC_VERB_SET_PIN_WIDGET_CONTROL , 0x00 }, /* PIN off */
98+ {0x43 , CM9825_VERB_SET_ADCL , 0x88 }, /* ADC */
99+ {0x43 , CM9825_VERB_SET_DACL , 0xaa }, /* DACL */
100+ {0x43 , CM9825_VERB_SET_MBIAS , 0x10 }, /* MBIAS */
101+ {0x43 , CM9825_VERB_SET_D2S , 0xf2 }, /* depop */
102+ {0x43 , CM9825_VERB_SET_DACTRL , 0x00 }, /* DACTRL set */
103+ {0x43 , CM9825_VERB_SET_VDO , 0xc4 }, /* VDO set */
104+ {}
105+ };
106+
107+ static const struct hda_verb cm9825_hp_remove_verbs [] = {
108+ {0x43 , CM9825_VERB_SET_ADCL , 0x00 }, /* ADC */
109+ {0x43 , CM9825_VERB_SET_DACL , 0x56 }, /* DACL */
110+ {0x43 , CM9825_VERB_SET_MBIAS , 0x00 }, /* MBIAS */
111+ {0x43 , CM9825_VERB_SET_D2S , 0x62 }, /* depop */
112+ {0x43 , CM9825_VERB_SET_DACTRL , 0xe0 }, /* DACTRL set */
113+ {0x43 , CM9825_VERB_SET_VDO , 0x80 }, /* VDO set */
114+ {0x42 , AC_VERB_SET_PIN_WIDGET_CONTROL , 0x40 }, /* PIN on */
115+ {}
116+ };
117+
118+ static void cm9825_unsol_hp_delayed (struct work_struct * work )
119+ {
120+ struct cmi_spec * spec =
121+ container_of (to_delayed_work (work ), struct cmi_spec , unsol_hp_work );
122+ struct hda_jack_tbl * jack ;
123+ hda_nid_t hp_pin = spec -> gen .autocfg .hp_pins [0 ];
124+ bool hp_jack_plugin = false;
125+ int err = 0 ;
126+
127+ hp_jack_plugin = snd_hda_jack_detect (spec -> codec , hp_pin );
128+
129+ codec_dbg (spec -> codec , "hp_jack_plugin %d, hp_pin 0x%X\n" ,
130+ (int )hp_jack_plugin , hp_pin );
131+
132+ if (!hp_jack_plugin ) {
133+ err =
134+ snd_hda_codec_write (spec -> codec , 0x42 , 0 ,
135+ AC_VERB_SET_PIN_WIDGET_CONTROL , 0x40 );
136+ if (err )
137+ codec_dbg (spec -> codec , "codec_write err %d\n" , err );
138+
139+ snd_hda_sequence_write (spec -> codec , spec -> chip_hp_remove_verbs );
140+ } else {
141+ snd_hda_sequence_write (spec -> codec ,
142+ spec -> chip_hp_present_verbs );
143+ }
144+
145+ jack = snd_hda_jack_tbl_get (spec -> codec , hp_pin );
146+ if (jack ) {
147+ jack -> block_report = 0 ;
148+ snd_hda_jack_report_sync (spec -> codec );
149+ }
150+ }
151+
152+ static void hp_callback (struct hda_codec * codec , struct hda_jack_callback * cb )
153+ {
154+ struct cmi_spec * spec = codec -> spec ;
155+ struct hda_jack_tbl * tbl ;
156+
157+ /* Delay enabling the HP amp, to let the mic-detection
158+ * state machine run.
159+ */
160+
161+ codec_dbg (spec -> codec , "cb->nid 0x%X\n" , cb -> nid );
162+
163+ tbl = snd_hda_jack_tbl_get (codec , cb -> nid );
164+ if (tbl )
165+ tbl -> block_report = 1 ;
166+ schedule_delayed_work (& spec -> unsol_hp_work , msecs_to_jiffies (200 ));
167+ }
168+
169+ static void cm9825_setup_unsol (struct hda_codec * codec )
170+ {
171+ struct cmi_spec * spec = codec -> spec ;
172+
173+ hda_nid_t hp_pin = spec -> gen .autocfg .hp_pins [0 ];
174+
175+ snd_hda_jack_detect_enable_callback (codec , hp_pin , hp_callback );
176+ }
177+
178+ static int cm9825_init (struct hda_codec * codec )
179+ {
180+ snd_hda_gen_init (codec );
181+ snd_hda_apply_fixup (codec , HDA_FIXUP_ACT_INIT );
182+
183+ return 0 ;
184+ }
185+
186+ static void cm9825_free (struct hda_codec * codec )
187+ {
188+ struct cmi_spec * spec = codec -> spec ;
189+
190+ cancel_delayed_work_sync (& spec -> unsol_hp_work );
191+ snd_hda_gen_free (codec );
192+ }
193+
194+ static int cm9825_suspend (struct hda_codec * codec )
195+ {
196+ struct cmi_spec * spec = codec -> spec ;
197+
198+ cancel_delayed_work_sync (& spec -> unsol_hp_work );
199+
200+ snd_hda_sequence_write (codec , spec -> chip_d3_verbs );
201+
202+ return 0 ;
203+ }
204+
205+ static int cm9825_resume (struct hda_codec * codec )
206+ {
207+ struct cmi_spec * spec = codec -> spec ;
208+ hda_nid_t hp_pin = 0 ;
209+ bool hp_jack_plugin = false;
210+ int err ;
211+
212+ err =
213+ snd_hda_codec_write (spec -> codec , 0x42 , 0 ,
214+ AC_VERB_SET_PIN_WIDGET_CONTROL , 0x00 );
215+ if (err )
216+ codec_dbg (codec , "codec_write err %d\n" , err );
217+
218+ msleep (150 ); /* for depop noise */
219+
220+ codec -> patch_ops .init (codec );
221+
222+ hp_pin = spec -> gen .autocfg .hp_pins [0 ];
223+ hp_jack_plugin = snd_hda_jack_detect (spec -> codec , hp_pin );
224+
225+ codec_dbg (spec -> codec , "hp_jack_plugin %d, hp_pin 0x%X\n" ,
226+ (int )hp_jack_plugin , hp_pin );
227+
228+ if (!hp_jack_plugin ) {
229+ err =
230+ snd_hda_codec_write (spec -> codec , 0x42 , 0 ,
231+ AC_VERB_SET_PIN_WIDGET_CONTROL , 0x40 );
232+
233+ if (err )
234+ codec_dbg (codec , "codec_write err %d\n" , err );
235+
236+ snd_hda_sequence_write (codec , cm9825_hp_remove_verbs );
237+ }
238+
239+ snd_hda_regmap_sync (codec );
240+ hda_call_check_power_status (codec , 0x01 );
241+
242+ return 0 ;
243+ }
244+
24245/*
25246 * stuff for auto-parser
26247 */
@@ -32,6 +253,53 @@ static const struct hda_codec_ops cmi_auto_patch_ops = {
32253 .unsol_event = snd_hda_jack_unsol_event ,
33254};
34255
256+ static int patch_cm9825 (struct hda_codec * codec )
257+ {
258+ struct cmi_spec * spec ;
259+ struct auto_pin_cfg * cfg ;
260+ int err ;
261+
262+ spec = kzalloc (sizeof (* spec ), GFP_KERNEL );
263+ if (spec == NULL )
264+ return - ENOMEM ;
265+
266+ INIT_DELAYED_WORK (& spec -> unsol_hp_work , cm9825_unsol_hp_delayed );
267+ codec -> spec = spec ;
268+ spec -> codec = codec ;
269+ codec -> patch_ops = cmi_auto_patch_ops ;
270+ codec -> patch_ops .init = cm9825_init ;
271+ codec -> patch_ops .suspend = cm9825_suspend ;
272+ codec -> patch_ops .resume = cm9825_resume ;
273+ codec -> patch_ops .free = cm9825_free ;
274+ codec -> patch_ops .check_power_status = snd_hda_gen_check_power_status ;
275+ cfg = & spec -> gen .autocfg ;
276+ snd_hda_gen_spec_init (& spec -> gen );
277+ spec -> chip_d0_verbs = cm9825_std_d0_verbs ;
278+ spec -> chip_d3_verbs = cm9825_std_d3_verbs ;
279+ spec -> chip_hp_present_verbs = cm9825_hp_present_verbs ;
280+ spec -> chip_hp_remove_verbs = cm9825_hp_remove_verbs ;
281+
282+ snd_hda_sequence_write (codec , spec -> chip_d0_verbs );
283+
284+ err = snd_hda_parse_pin_defcfg (codec , cfg , NULL , 0 );
285+ if (err < 0 )
286+ goto error ;
287+ err = snd_hda_gen_parse_auto_config (codec , cfg );
288+ if (err < 0 )
289+ goto error ;
290+
291+ cm9825_setup_unsol (codec );
292+
293+ return 0 ;
294+
295+ error :
296+ cm9825_free (codec );
297+
298+ codec_info (codec , "Enter err %d\n" , err );
299+
300+ return err ;
301+ }
302+
35303static int patch_cmi9880 (struct hda_codec * codec )
36304{
37305 struct cmi_spec * spec ;
@@ -113,6 +381,7 @@ static const struct hda_device_id snd_hda_id_cmedia[] = {
113381 HDA_CODEC_ENTRY (0x13f68888 , "CMI8888" , patch_cmi8888 ),
114382 HDA_CODEC_ENTRY (0x13f69880 , "CMI9880" , patch_cmi9880 ),
115383 HDA_CODEC_ENTRY (0x434d4980 , "CMI9880" , patch_cmi9880 ),
384+ HDA_CODEC_ENTRY (0x13f69825 , "CM9825" , patch_cm9825 ),
116385 {} /* terminator */
117386};
118387MODULE_DEVICE_TABLE (hdaudio , snd_hda_id_cmedia );
0 commit comments