21
21
#include "hda_jack.h"
22
22
#include "hda_generic.h"
23
23
24
+ enum {
25
+ CX_HEADSET_NOPRESENT = 0 ,
26
+ CX_HEADSET_PARTPRESENT ,
27
+ CX_HEADSET_ALLPRESENT ,
28
+ };
29
+
24
30
struct conexant_spec {
25
31
struct hda_gen_spec gen ;
26
32
@@ -42,7 +48,8 @@ struct conexant_spec {
42
48
unsigned int gpio_led ;
43
49
unsigned int gpio_mute_led_mask ;
44
50
unsigned int gpio_mic_led_mask ;
45
-
51
+ unsigned int headset_present_flag ;
52
+ bool is_cx8070_sn6140 ;
46
53
};
47
54
48
55
@@ -164,6 +171,27 @@ static void cxt_init_gpio_led(struct hda_codec *codec)
164
171
}
165
172
}
166
173
174
+ static void cx_fixup_headset_recog (struct hda_codec * codec )
175
+ {
176
+ unsigned int mic_persent ;
177
+
178
+ /* fix some headset type recognize fail issue, such as EDIFIER headset */
179
+ /* set micbiasd output current comparator threshold from 66% to 55%. */
180
+ snd_hda_codec_write (codec , 0x1c , 0 , 0x320 , 0x010 );
181
+ /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias registor
182
+ * value adjustment trim from 2.2K ohms to 2.0K ohms.
183
+ */
184
+ snd_hda_codec_write (codec , 0x1c , 0 , 0x3b0 , 0xe10 );
185
+ /* fix reboot headset type recognize fail issue */
186
+ mic_persent = snd_hda_codec_read (codec , 0x19 , 0 , AC_VERB_GET_PIN_SENSE , 0x0 );
187
+ if (mic_persent & AC_PINSENSE_PRESENCE )
188
+ /* enable headset mic VREF */
189
+ snd_hda_codec_write (codec , 0x19 , 0 , AC_VERB_SET_PIN_WIDGET_CONTROL , 0x24 );
190
+ else
191
+ /* disable headset mic VREF */
192
+ snd_hda_codec_write (codec , 0x19 , 0 , AC_VERB_SET_PIN_WIDGET_CONTROL , 0x20 );
193
+ }
194
+
167
195
static int cx_auto_init (struct hda_codec * codec )
168
196
{
169
197
struct conexant_spec * spec = codec -> spec ;
@@ -174,6 +202,9 @@ static int cx_auto_init(struct hda_codec *codec)
174
202
cxt_init_gpio_led (codec );
175
203
snd_hda_apply_fixup (codec , HDA_FIXUP_ACT_INIT );
176
204
205
+ if (spec -> is_cx8070_sn6140 )
206
+ cx_fixup_headset_recog (codec );
207
+
177
208
return 0 ;
178
209
}
179
210
@@ -192,6 +223,77 @@ static void cx_auto_free(struct hda_codec *codec)
192
223
snd_hda_gen_free (codec );
193
224
}
194
225
226
+ static void cx_process_headset_plugin (struct hda_codec * codec )
227
+ {
228
+ unsigned int val ;
229
+ unsigned int count = 0 ;
230
+
231
+ /* Wait headset detect done. */
232
+ do {
233
+ val = snd_hda_codec_read (codec , 0x1c , 0 , 0xca0 , 0x0 );
234
+ if (val & 0x080 ) {
235
+ codec_dbg (codec , "headset type detect done!\n" );
236
+ break ;
237
+ }
238
+ msleep (20 );
239
+ count ++ ;
240
+ } while (count < 3 );
241
+ val = snd_hda_codec_read (codec , 0x1c , 0 , 0xcb0 , 0x0 );
242
+ if (val & 0x800 ) {
243
+ codec_dbg (codec , "headset plugin, type is CTIA\n" );
244
+ snd_hda_codec_write (codec , 0x19 , 0 , AC_VERB_SET_PIN_WIDGET_CONTROL , 0x24 );
245
+ } else if (val & 0x400 ) {
246
+ codec_dbg (codec , "headset plugin, type is OMTP\n" );
247
+ snd_hda_codec_write (codec , 0x19 , 0 , AC_VERB_SET_PIN_WIDGET_CONTROL , 0x24 );
248
+ } else {
249
+ codec_dbg (codec , "headphone plugin\n" );
250
+ }
251
+ }
252
+
253
+ static void cx_update_headset_mic_vref (struct hda_codec * codec , unsigned int res )
254
+ {
255
+ unsigned int phone_present , mic_persent , phone_tag , mic_tag ;
256
+ struct conexant_spec * spec = codec -> spec ;
257
+
258
+ /* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled,
259
+ * the node 19 can only be config to microphone or disabled.
260
+ * Check hp&mic tag to process headset pulgin&plugout.
261
+ */
262
+ phone_tag = snd_hda_codec_read (codec , 0x16 , 0 , AC_VERB_GET_UNSOLICITED_RESPONSE , 0x0 );
263
+ mic_tag = snd_hda_codec_read (codec , 0x19 , 0 , AC_VERB_GET_UNSOLICITED_RESPONSE , 0x0 );
264
+ if ((phone_tag & (res >> AC_UNSOL_RES_TAG_SHIFT )) ||
265
+ (mic_tag & (res >> AC_UNSOL_RES_TAG_SHIFT ))) {
266
+ phone_present = snd_hda_codec_read (codec , 0x16 , 0 , AC_VERB_GET_PIN_SENSE , 0x0 );
267
+ if (!(phone_present & AC_PINSENSE_PRESENCE )) {/* headphone plugout */
268
+ spec -> headset_present_flag = CX_HEADSET_NOPRESENT ;
269
+ snd_hda_codec_write (codec , 0x19 , 0 , AC_VERB_SET_PIN_WIDGET_CONTROL , 0x20 );
270
+ return ;
271
+ }
272
+ if (spec -> headset_present_flag == CX_HEADSET_NOPRESENT ) {
273
+ spec -> headset_present_flag = CX_HEADSET_PARTPRESENT ;
274
+ } else if (spec -> headset_present_flag == CX_HEADSET_PARTPRESENT ) {
275
+ mic_persent = snd_hda_codec_read (codec , 0x19 , 0 ,
276
+ AC_VERB_GET_PIN_SENSE , 0x0 );
277
+ /* headset is present */
278
+ if ((phone_present & AC_PINSENSE_PRESENCE ) &&
279
+ (mic_persent & AC_PINSENSE_PRESENCE )) {
280
+ cx_process_headset_plugin (codec );
281
+ spec -> headset_present_flag = CX_HEADSET_ALLPRESENT ;
282
+ }
283
+ }
284
+ }
285
+ }
286
+
287
+ static void cx_jack_unsol_event (struct hda_codec * codec , unsigned int res )
288
+ {
289
+ struct conexant_spec * spec = codec -> spec ;
290
+
291
+ if (spec -> is_cx8070_sn6140 )
292
+ cx_update_headset_mic_vref (codec , res );
293
+
294
+ snd_hda_jack_unsol_event (codec , res );
295
+ }
296
+
195
297
#ifdef CONFIG_PM
196
298
static int cx_auto_suspend (struct hda_codec * codec )
197
299
{
@@ -205,7 +307,7 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
205
307
.build_pcms = snd_hda_gen_build_pcms ,
206
308
.init = cx_auto_init ,
207
309
.free = cx_auto_free ,
208
- .unsol_event = snd_hda_jack_unsol_event ,
310
+ .unsol_event = cx_jack_unsol_event ,
209
311
#ifdef CONFIG_PM
210
312
.suspend = cx_auto_suspend ,
211
313
.check_power_status = snd_hda_gen_check_power_status ,
@@ -1042,6 +1144,15 @@ static int patch_conexant_auto(struct hda_codec *codec)
1042
1144
codec -> spec = spec ;
1043
1145
codec -> patch_ops = cx_auto_patch_ops ;
1044
1146
1147
+ /* init cx8070/sn6140 flag and reset headset_present_flag */
1148
+ switch (codec -> core .vendor_id ) {
1149
+ case 0x14f11f86 :
1150
+ case 0x14f11f87 :
1151
+ spec -> is_cx8070_sn6140 = true;
1152
+ spec -> headset_present_flag = CX_HEADSET_NOPRESENT ;
1153
+ break ;
1154
+ }
1155
+
1045
1156
cx_auto_parse_eapd (codec );
1046
1157
spec -> gen .own_eapd_ctl = 1 ;
1047
1158
0 commit comments