ASoC: cs42l42: Use two thresholds and increased wait time for manual type detection
authorStefan Binding <sbinding@opensource.cirrus.com>
Mon, 27 Sep 2021 11:14:37 +0000 (12:14 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 27 Sep 2021 12:01:02 +0000 (13:01 +0100)
Some headsets require very different comparator thresholds for type detection,
as well as longer settling times. In order to detect a larger number of headsets,
use 2 thresholds to give maximum coverage (1.25V and 1.75V), as well as a longer
settling time of 100ms. This will not affect default audotodetect mode
and applies to manual mode type detection only.

Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20210927111437.18113-1-vitalyr@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/cs42l42.c
sound/soc/codecs/cs42l42.h

index d5e1e52..d484ec0 100644 (file)
@@ -1049,7 +1049,8 @@ static struct snd_soc_dai_driver cs42l42_dai = {
 static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42)
 {
        unsigned int hs_det_status;
-       unsigned int hs_det_comp;
+       unsigned int hs_det_comp1;
+       unsigned int hs_det_comp2;
        unsigned int hs_det_sw;
 
        /* Set hs detect to manual, active mode */
@@ -1064,23 +1065,40 @@ static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42)
                (0 << CS42L42_HSBIAS_REF_SHIFT) |
                (0 << CS42L42_HSDET_AUTO_TIME_SHIFT));
 
+       /* Configure HS DET comparator reference levels. */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_HSDET_CTL1,
+                               CS42L42_HSDET_COMP1_LVL_MASK |
+                               CS42L42_HSDET_COMP2_LVL_MASK,
+                               (CS42L42_HSDET_COMP1_LVL_VAL << CS42L42_HSDET_COMP1_LVL_SHIFT) |
+                               (CS42L42_HSDET_COMP2_LVL_VAL << CS42L42_HSDET_COMP2_LVL_SHIFT));
+
        /* Open the SW_HSB_HS3 switch and close SW_HSB_HS4 for a Type 1 headset. */
        regmap_write(cs42l42->regmap, CS42L42_HS_SWITCH_CTL, CS42L42_HSDET_SW_COMP1);
 
+       msleep(100);
+
        regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status);
 
-       hs_det_comp = (hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >>
+       hs_det_comp1 = (hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >>
                        CS42L42_HSDET_COMP1_OUT_SHIFT;
+       hs_det_comp2 = (hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >>
+                       CS42L42_HSDET_COMP2_OUT_SHIFT;
 
        /* Close the SW_HSB_HS3 switch for a Type 2 headset. */
        regmap_write(cs42l42->regmap, CS42L42_HS_SWITCH_CTL, CS42L42_HSDET_SW_COMP2);
 
+       msleep(100);
+
        regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status);
 
-       hs_det_comp |= ((hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >>
+       hs_det_comp1 |= ((hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >>
+                       CS42L42_HSDET_COMP1_OUT_SHIFT) << 1;
+       hs_det_comp2 |= ((hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >>
                        CS42L42_HSDET_COMP2_OUT_SHIFT) << 1;
 
-       switch (hs_det_comp) {
+       /* Use Comparator 1 with 1.25V Threshold. */
+       switch (hs_det_comp1) {
        case CS42L42_HSDET_COMP_TYPE1:
                cs42l42->hs_type = CS42L42_PLUG_CTIA;
                hs_det_sw = CS42L42_HSDET_SW_TYPE1;
@@ -1089,14 +1107,26 @@ static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42)
                cs42l42->hs_type = CS42L42_PLUG_OMTP;
                hs_det_sw = CS42L42_HSDET_SW_TYPE2;
                break;
-       case CS42L42_HSDET_COMP_TYPE3:
-               cs42l42->hs_type = CS42L42_PLUG_HEADPHONE;
-               hs_det_sw = CS42L42_HSDET_SW_TYPE3;
-               break;
        default:
-               cs42l42->hs_type = CS42L42_PLUG_INVALID;
-               hs_det_sw = CS42L42_HSDET_SW_TYPE4;
-               break;
+               /* Fallback to Comparator 2 with 1.75V Threshold. */
+               switch (hs_det_comp2) {
+               case CS42L42_HSDET_COMP_TYPE1:
+                       cs42l42->hs_type = CS42L42_PLUG_CTIA;
+                       hs_det_sw = CS42L42_HSDET_SW_TYPE1;
+                       break;
+               case CS42L42_HSDET_COMP_TYPE2:
+                       cs42l42->hs_type = CS42L42_PLUG_OMTP;
+                       hs_det_sw = CS42L42_HSDET_SW_TYPE2;
+                       break;
+               case CS42L42_HSDET_COMP_TYPE3:
+                       cs42l42->hs_type = CS42L42_PLUG_HEADPHONE;
+                       hs_det_sw = CS42L42_HSDET_SW_TYPE3;
+                       break;
+               default:
+                       cs42l42->hs_type = CS42L42_PLUG_INVALID;
+                       hs_det_sw = CS42L42_HSDET_SW_TYPE4;
+                       break;
+               }
        }
 
        /* Set Switches */
@@ -1113,6 +1143,14 @@ static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42)
                (0 << CS42L42_HSDET_SET_SHIFT) |
                (0 << CS42L42_HSBIAS_REF_SHIFT) |
                (0 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+
+       /* Configure HS DET comparator reference levels. */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_HSDET_CTL1,
+                               CS42L42_HSDET_COMP1_LVL_MASK |
+                               CS42L42_HSDET_COMP2_LVL_MASK,
+                               (CS42L42_HSDET_COMP1_LVL_DEFAULT << CS42L42_HSDET_COMP1_LVL_SHIFT) |
+                               (CS42L42_HSDET_COMP2_LVL_DEFAULT << CS42L42_HSDET_COMP2_LVL_SHIFT));
 }
 
 static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42)
@@ -1135,6 +1173,18 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42)
        cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >>
                                CS42L42_HSDET_TYPE_SHIFT;
 
+       /* Set hs detect to automatic, disabled mode */
+       regmap_update_bits(cs42l42->regmap,
+               CS42L42_HSDET_CTL2,
+               CS42L42_HSDET_CTRL_MASK |
+               CS42L42_HSDET_SET_MASK |
+               CS42L42_HSBIAS_REF_MASK |
+               CS42L42_HSDET_AUTO_TIME_MASK,
+               (2 << CS42L42_HSDET_CTRL_SHIFT) |
+               (2 << CS42L42_HSDET_SET_SHIFT) |
+               (0 << CS42L42_HSBIAS_REF_SHIFT) |
+               (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+
        /* Run Manual detection if auto detect has not found a headset.
         * We Re-Run with Manual Detection if the original detection was invalid or headphones,
         * to ensure that a headset mic is detected in all cases.
@@ -1143,18 +1193,6 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42)
                cs42l42->hs_type == CS42L42_PLUG_HEADPHONE) {
                dev_dbg(cs42l42->component->dev, "Running Manual Detection Fallback\n");
                cs42l42_manual_hs_type_detect(cs42l42);
-       } else {
-               /* Set hs detect to automatic, disabled mode */
-               regmap_update_bits(cs42l42->regmap,
-                       CS42L42_HSDET_CTL2,
-                       CS42L42_HSDET_CTRL_MASK |
-                       CS42L42_HSDET_SET_MASK |
-                       CS42L42_HSBIAS_REF_MASK |
-                       CS42L42_HSDET_AUTO_TIME_MASK,
-                       (2 << CS42L42_HSDET_CTRL_SHIFT) |
-                       (2 << CS42L42_HSDET_SET_SHIFT) |
-                       (0 << CS42L42_HSBIAS_REF_SHIFT) |
-                       (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
        }
 
        /* Set up button detection */
index 2aeabba..0704c90 100644 (file)
 #define CS42L42_HSDET_COMP2_LVL_SHIFT  4
 #define CS42L42_HSDET_COMP2_LVL_MASK   (15 << CS42L42_HSDET_COMP2_LVL_SHIFT)
 
+#define CS42L42_HSDET_COMP1_LVL_VAL    12 /* 1.25V Comparator */
+#define CS42L42_HSDET_COMP2_LVL_VAL    2  /* 1.75V Comparator */
+#define CS42L42_HSDET_COMP1_LVL_DEFAULT        7  /* 1V Comparator */
+#define CS42L42_HSDET_COMP2_LVL_DEFAULT        7  /* 2V Comparator */
+
 #define CS42L42_HSDET_CTL2             (CS42L42_PAGE_11 + 0x20)
 #define CS42L42_HSDET_AUTO_TIME_SHIFT  0
 #define CS42L42_HSDET_AUTO_TIME_MASK   (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)