2121#include "hda_jack.h"
2222#include "hda_generic.h"
2323
24+ enum {
25+ CX_HEADSET_NOPRESENT = 0 ,
26+ CX_HEADSET_PARTPRESENT ,
27+ CX_HEADSET_ALLPRESENT ,
28+ };
29+
2430struct conexant_spec {
2531 struct hda_gen_spec gen ;
2632
@@ -42,7 +48,8 @@ struct conexant_spec {
4248 unsigned int gpio_led ;
4349 unsigned int gpio_mute_led_mask ;
4450 unsigned int gpio_mic_led_mask ;
45-
51+ unsigned int headset_present_flag ;
52+ bool is_cx8070_sn6140 ;
4653};
4754
4855
@@ -164,6 +171,27 @@ static void cxt_init_gpio_led(struct hda_codec *codec)
164171 }
165172}
166173
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+
167195static int cx_auto_init (struct hda_codec * codec )
168196{
169197 struct conexant_spec * spec = codec -> spec ;
@@ -174,6 +202,9 @@ static int cx_auto_init(struct hda_codec *codec)
174202 cxt_init_gpio_led (codec );
175203 snd_hda_apply_fixup (codec , HDA_FIXUP_ACT_INIT );
176204
205+ if (spec -> is_cx8070_sn6140 )
206+ cx_fixup_headset_recog (codec );
207+
177208 return 0 ;
178209}
179210
@@ -192,6 +223,77 @@ static void cx_auto_free(struct hda_codec *codec)
192223 snd_hda_gen_free (codec );
193224}
194225
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+
195297#ifdef CONFIG_PM
196298static int cx_auto_suspend (struct hda_codec * codec )
197299{
@@ -205,7 +307,7 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
205307 .build_pcms = snd_hda_gen_build_pcms ,
206308 .init = cx_auto_init ,
207309 .free = cx_auto_free ,
208- .unsol_event = snd_hda_jack_unsol_event ,
310+ .unsol_event = cx_jack_unsol_event ,
209311#ifdef CONFIG_PM
210312 .suspend = cx_auto_suspend ,
211313 .check_power_status = snd_hda_gen_check_power_status ,
@@ -1042,6 +1144,15 @@ static int patch_conexant_auto(struct hda_codec *codec)
10421144 codec -> spec = spec ;
10431145 codec -> patch_ops = cx_auto_patch_ops ;
10441146
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+
10451156 cx_auto_parse_eapd (codec );
10461157 spec -> gen .own_eapd_ctl = 1 ;
10471158
0 commit comments