OSDN Git Service

ASoC: cs42l42: Implement Manual Type detection as fallback
authorStefan Binding <sbinding@opensource.cirrus.com>
Thu, 16 Sep 2021 10:27:50 +0000 (11:27 +0100)
committerMark Brown <broonie@kernel.org>
Thu, 16 Sep 2021 13:05:23 +0000 (14:05 +0100)
Some headsets are not detected correctly by Automatic Type Detection
on cs42l42. Instead, Manual Type Detection can be used to give a
more accurate value.

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

index fb1e4c3..c586ebf 100644 (file)
@@ -1046,37 +1046,117 @@ static struct snd_soc_dai_driver cs42l42_dai = {
                .ops = &cs42l42_ops,
 };
 
-static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42)
+static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42)
 {
        unsigned int hs_det_status;
-       unsigned int int_status;
+       unsigned int hs_det_comp;
+       unsigned int hs_det_sw;
 
-       /* Mask the auto detect interrupt */
+       /* Set hs detect to manual, active mode */
        regmap_update_bits(cs42l42->regmap,
-               CS42L42_CODEC_INT_MASK,
-               CS42L42_PDN_DONE_MASK |
-               CS42L42_HSDET_AUTO_DONE_MASK,
-               (1 << CS42L42_PDN_DONE_SHIFT) |
-               (1 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+               CS42L42_HSDET_CTL2,
+               CS42L42_HSDET_CTRL_MASK |
+               CS42L42_HSDET_SET_MASK |
+               CS42L42_HSBIAS_REF_MASK |
+               CS42L42_HSDET_AUTO_TIME_MASK,
+               (1 << CS42L42_HSDET_CTRL_SHIFT) |
+               (0 << CS42L42_HSDET_SET_SHIFT) |
+               (0 << CS42L42_HSBIAS_REF_SHIFT) |
+               (0 << CS42L42_HSDET_AUTO_TIME_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);
+
+       regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status);
+
+       hs_det_comp = (hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >>
+                       CS42L42_HSDET_COMP1_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);
+
+       regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status);
+
+       hs_det_comp |= ((hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >>
+                       CS42L42_HSDET_COMP2_OUT_SHIFT) << 1;
+
+       switch (hs_det_comp) {
+       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 hs detect to automatic, disabled mode */
+       /* Set Switches */
+       regmap_write(cs42l42->regmap, CS42L42_HS_SWITCH_CTL, hs_det_sw);
+
+       /* Set HSDET mode to Manual—Disabled */
        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_HSDET_CTRL_SHIFT) |
+               (0 << CS42L42_HSDET_SET_SHIFT) |
                (0 << CS42L42_HSBIAS_REF_SHIFT) |
-               (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+               (0 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+}
+
+static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+       unsigned int hs_det_status;
+       unsigned int int_status;
 
        /* Read and save the hs detection result */
        regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status);
 
+       /* Mask the auto detect interrupt */
+       regmap_update_bits(cs42l42->regmap,
+               CS42L42_CODEC_INT_MASK,
+               CS42L42_PDN_DONE_MASK |
+               CS42L42_HSDET_AUTO_DONE_MASK,
+               (1 << CS42L42_PDN_DONE_SHIFT) |
+               (1 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+
+
        cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >>
                                CS42L42_HSDET_TYPE_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.
+        */
+       if (cs42l42->hs_type == CS42L42_PLUG_INVALID ||
+               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 */
        if ((cs42l42->hs_type == CS42L42_PLUG_CTIA) ||
              (cs42l42->hs_type == CS42L42_PLUG_OMTP)) {
index 8734f68..2aeabba 100644 (file)
 #define CS42L42_PLUG_HEADPHONE         2
 #define CS42L42_PLUG_INVALID           3
 
+#define CS42L42_HSDET_SW_COMP1         ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_HS4_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_HS3_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \
+                                        (0 << CS42L42_SW_REF_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_REF_HS3_SHIFT))
+#define CS42L42_HSDET_SW_COMP2         ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \
+                                        (0 << CS42L42_SW_GNDHS_HS3_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_HS3_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \
+                                        (1 << CS42L42_SW_REF_HS4_SHIFT) | \
+                                        (0 << CS42L42_SW_REF_HS3_SHIFT))
+#define CS42L42_HSDET_SW_TYPE1         ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_HS4_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_HS3_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \
+                                        (0 << CS42L42_SW_REF_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_REF_HS3_SHIFT))
+#define CS42L42_HSDET_SW_TYPE2         ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \
+                                        (0 << CS42L42_SW_GNDHS_HS3_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_HS3_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \
+                                        (1 << CS42L42_SW_REF_HS4_SHIFT) | \
+                                        (0 << CS42L42_SW_REF_HS3_SHIFT))
+#define CS42L42_HSDET_SW_TYPE3         ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_HS4_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_HS3_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \
+                                        (1 << CS42L42_SW_REF_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_REF_HS3_SHIFT))
+#define CS42L42_HSDET_SW_TYPE4         ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_HS4_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_HS3_SHIFT) | \
+                                        (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \
+                                        (0 << CS42L42_SW_REF_HS4_SHIFT) | \
+                                        (1 << CS42L42_SW_REF_HS3_SHIFT))
+
+#define CS42L42_HSDET_COMP_TYPE1       1
+#define CS42L42_HSDET_COMP_TYPE2       2
+#define CS42L42_HSDET_COMP_TYPE3       0
+#define CS42L42_HSDET_COMP_TYPE4       3
+
 #define CS42L42_HS_CLAMP_DISABLE       (CS42L42_PAGE_11 + 0x29)
 #define CS42L42_HS_CLAMP_DISABLE_SHIFT 0
 #define CS42L42_HS_CLAMP_DISABLE_MASK  (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT)