@@ -634,38 +634,128 @@ static void cs42l42_run_jack_detect(struct sub_codec *cs42l42)
634634 cs8409_i2c_write (cs42l42 , CS42L42_HSDET_CTL2 , 0xc0 );
635635}
636636
637- static int cs42l42_handle_tip_sense (struct sub_codec * cs42l42 , unsigned int reg_ts_status )
637+ static int cs42l42_manual_hs_det (struct sub_codec * cs42l42 )
638638{
639- int status_changed = cs42l42 -> force_status_change ;
639+ unsigned int hs_det_status ;
640+ unsigned int hs_det_comp1 ;
641+ unsigned int hs_det_comp2 ;
642+ unsigned int hs_det_sw ;
643+ unsigned int hs_type ;
644+
645+ /* Set hs detect to manual, active mode */
646+ cs8409_i2c_write (cs42l42 , CS42L42_HSDET_CTL2 ,
647+ (1 << CS42L42_HSDET_CTRL_SHIFT ) |
648+ (0 << CS42L42_HSDET_SET_SHIFT ) |
649+ (0 << CS42L42_HSBIAS_REF_SHIFT ) |
650+ (0 << CS42L42_HSDET_AUTO_TIME_SHIFT ));
651+
652+ /* Configure HS DET comparator reference levels. */
653+ cs8409_i2c_write (cs42l42 , CS42L42_HSDET_CTL1 ,
654+ (CS42L42_HSDET_COMP1_LVL_VAL << CS42L42_HSDET_COMP1_LVL_SHIFT ) |
655+ (CS42L42_HSDET_COMP2_LVL_VAL << CS42L42_HSDET_COMP2_LVL_SHIFT ));
656+
657+ /* Open the SW_HSB_HS3 switch and close SW_HSB_HS4 for a Type 1 headset. */
658+ cs8409_i2c_write (cs42l42 , CS42L42_HS_SWITCH_CTL , CS42L42_HSDET_SW_COMP1 );
659+
660+ msleep (100 );
661+
662+ hs_det_status = cs8409_i2c_read (cs42l42 , CS42L42_HS_DET_STATUS );
663+
664+ hs_det_comp1 = (hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK ) >>
665+ CS42L42_HSDET_COMP1_OUT_SHIFT ;
666+ hs_det_comp2 = (hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK ) >>
667+ CS42L42_HSDET_COMP2_OUT_SHIFT ;
668+
669+ /* Close the SW_HSB_HS3 switch for a Type 2 headset. */
670+ cs8409_i2c_write (cs42l42 , CS42L42_HS_SWITCH_CTL , CS42L42_HSDET_SW_COMP2 );
640671
641- cs42l42 -> force_status_change = 0 ;
672+ msleep (100 );
673+
674+ hs_det_status = cs8409_i2c_read (cs42l42 , CS42L42_HS_DET_STATUS );
675+
676+ hs_det_comp1 |= ((hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK ) >>
677+ CS42L42_HSDET_COMP1_OUT_SHIFT ) << 1 ;
678+ hs_det_comp2 |= ((hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK ) >>
679+ CS42L42_HSDET_COMP2_OUT_SHIFT ) << 1 ;
680+
681+ /* Use Comparator 1 with 1.25V Threshold. */
682+ switch (hs_det_comp1 ) {
683+ case CS42L42_HSDET_COMP_TYPE1 :
684+ hs_type = CS42L42_PLUG_CTIA ;
685+ hs_det_sw = CS42L42_HSDET_SW_TYPE1 ;
686+ break ;
687+ case CS42L42_HSDET_COMP_TYPE2 :
688+ hs_type = CS42L42_PLUG_OMTP ;
689+ hs_det_sw = CS42L42_HSDET_SW_TYPE2 ;
690+ break ;
691+ default :
692+ /* Fallback to Comparator 2 with 1.75V Threshold. */
693+ switch (hs_det_comp2 ) {
694+ case CS42L42_HSDET_COMP_TYPE1 :
695+ hs_type = CS42L42_PLUG_CTIA ;
696+ hs_det_sw = CS42L42_HSDET_SW_TYPE1 ;
697+ break ;
698+ case CS42L42_HSDET_COMP_TYPE2 :
699+ hs_type = CS42L42_PLUG_OMTP ;
700+ hs_det_sw = CS42L42_HSDET_SW_TYPE2 ;
701+ break ;
702+ case CS42L42_HSDET_COMP_TYPE3 :
703+ hs_type = CS42L42_PLUG_HEADPHONE ;
704+ hs_det_sw = CS42L42_HSDET_SW_TYPE3 ;
705+ break ;
706+ default :
707+ hs_type = CS42L42_PLUG_INVALID ;
708+ hs_det_sw = CS42L42_HSDET_SW_TYPE4 ;
709+ break ;
710+ }
711+ }
712+
713+ /* Set Switches */
714+ cs8409_i2c_write (cs42l42 , CS42L42_HS_SWITCH_CTL , hs_det_sw );
715+
716+ /* Set HSDET mode to Manual—Disabled */
717+ cs8409_i2c_write (cs42l42 , CS42L42_HSDET_CTL2 ,
718+ (0 << CS42L42_HSDET_CTRL_SHIFT ) |
719+ (0 << CS42L42_HSDET_SET_SHIFT ) |
720+ (0 << CS42L42_HSBIAS_REF_SHIFT ) |
721+ (0 << CS42L42_HSDET_AUTO_TIME_SHIFT ));
722+
723+ /* Configure HS DET comparator reference levels. */
724+ cs8409_i2c_write (cs42l42 , CS42L42_HSDET_CTL1 ,
725+ (CS42L42_HSDET_COMP1_LVL_DEFAULT << CS42L42_HSDET_COMP1_LVL_SHIFT ) |
726+ (CS42L42_HSDET_COMP2_LVL_DEFAULT << CS42L42_HSDET_COMP2_LVL_SHIFT ));
727+
728+ return hs_type ;
729+ }
730+
731+ static int cs42l42_handle_tip_sense (struct sub_codec * cs42l42 , unsigned int reg_ts_status )
732+ {
733+ int status_changed = 0 ;
642734
643735 /* TIP_SENSE INSERT/REMOVE */
644736 switch (reg_ts_status ) {
645737 case CS42L42_TS_PLUG :
646- if (!cs42l42 -> hp_jack_in ) {
647- if (cs42l42 -> no_type_dect ) {
648- status_changed = 1 ;
649- cs42l42 -> hp_jack_in = 1 ;
650- cs42l42 -> mic_jack_in = 0 ;
651- } else {
652- cs42l42_run_jack_detect (cs42l42 );
653- }
738+ if (cs42l42 -> no_type_dect ) {
739+ status_changed = 1 ;
740+ cs42l42 -> hp_jack_in = 1 ;
741+ cs42l42 -> mic_jack_in = 0 ;
742+ } else {
743+ cs42l42_run_jack_detect (cs42l42 );
654744 }
655745 break ;
656746
657747 case CS42L42_TS_UNPLUG :
658- if (cs42l42 -> hp_jack_in || cs42l42 -> mic_jack_in ) {
659- status_changed = 1 ;
660- cs42l42 -> hp_jack_in = 0 ;
661- cs42l42 -> mic_jack_in = 0 ;
662- }
748+ status_changed = 1 ;
749+ cs42l42 -> hp_jack_in = 0 ;
750+ cs42l42 -> mic_jack_in = 0 ;
663751 break ;
664752 default :
665753 /* jack in transition */
666754 break ;
667755 }
668756
757+ codec_dbg (cs42l42 -> codec , "Tip Sense Detection: (%d)\n" , reg_ts_status );
758+
669759 return status_changed ;
670760}
671761
@@ -698,24 +788,40 @@ static int cs42l42_jack_unsol_event(struct sub_codec *cs42l42)
698788
699789 type = (reg_hs_status & CS42L42_HSDET_TYPE_MASK ) >> CS42L42_HSDET_TYPE_SHIFT ;
700790
791+ /* Configure the HSDET mode. */
792+ cs8409_i2c_write (cs42l42 , CS42L42_HSDET_CTL2 , 0x80 );
793+
701794 if (cs42l42 -> no_type_dect ) {
702795 status_changed = cs42l42_handle_tip_sense (cs42l42 , current_plug_status );
703- } else if (type == CS42L42_PLUG_INVALID ) {
704- /* Type CS42L42_PLUG_INVALID not supported */
705- status_changed = cs42l42_handle_tip_sense (cs42l42 , CS42L42_TS_UNPLUG );
706796 } else {
707- if (!cs42l42 -> hp_jack_in ) {
708- status_changed = 1 ;
709- cs42l42 -> hp_jack_in = 1 ;
797+ if (type == CS42L42_PLUG_INVALID || type == CS42L42_PLUG_HEADPHONE ) {
798+ codec_dbg (cs42l42 -> codec ,
799+ "Auto detect value not valid (%d), running manual det\n" ,
800+ type );
801+ type = cs42l42_manual_hs_det (cs42l42 );
710802 }
711- /* type = CS42L42_PLUG_HEADPHONE has no mic */
712- if ((!cs42l42 -> mic_jack_in ) && (type != CS42L42_PLUG_HEADPHONE )) {
803+
804+ switch (type ) {
805+ case CS42L42_PLUG_CTIA :
806+ case CS42L42_PLUG_OMTP :
713807 status_changed = 1 ;
808+ cs42l42 -> hp_jack_in = 1 ;
714809 cs42l42 -> mic_jack_in = 1 ;
810+ break ;
811+ case CS42L42_PLUG_HEADPHONE :
812+ status_changed = 1 ;
813+ cs42l42 -> hp_jack_in = 1 ;
814+ cs42l42 -> mic_jack_in = 0 ;
815+ break ;
816+ default :
817+ status_changed = 1 ;
818+ cs42l42 -> hp_jack_in = 0 ;
819+ cs42l42 -> mic_jack_in = 0 ;
820+ break ;
715821 }
822+ codec_dbg (cs42l42 -> codec , "Detection done (%d)\n" , type );
716823 }
717- /* Configure the HSDET mode. */
718- cs8409_i2c_write (cs42l42 , CS42L42_HSDET_CTL2 , 0x80 );
824+
719825 /* Enable the HPOUT ground clamp and configure the HP pull-down */
720826 cs8409_i2c_write (cs42l42 , CS42L42_DAC_CTL2 , 0x02 );
721827 /* Re-Enable Tip Sense Interrupt */
@@ -803,7 +909,6 @@ static void cs42l42_suspend(struct sub_codec *cs42l42)
803909 cs42l42 -> last_page = 0 ;
804910 cs42l42 -> hp_jack_in = 0 ;
805911 cs42l42 -> mic_jack_in = 0 ;
806- cs42l42 -> force_status_change = 1 ;
807912
808913 /* Put CS42L42 into Reset */
809914 gpio_data = snd_hda_codec_read (codec , CS8409_PIN_AFG , 0 , AC_VERB_GET_GPIO_DATA , 0 );
0 commit comments