Blob Blame History Raw
From edd6dffdc6670836909972b32a324dbf6c150757 Mon Sep 17 00:00:00 2001
From: Stefan Binding <sbinding@opensource.cirrus.com>
Date: Mon, 27 Sep 2021 12:14:37 +0100
Subject: [PATCH] ASoC: cs42l42: Use two thresholds and increased wait time for manual type detection
Git-commit: edd6dffdc6670836909972b32a324dbf6c150757
Patch-mainline: v5.16-rc1
References: bsc#1203699

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>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 sound/soc/codecs/cs42l42.c | 84 +++++++++++++++++++++++++++-----------
 sound/soc/codecs/cs42l42.h |  5 +++
 2 files changed, 66 insertions(+), 23 deletions(-)

diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index d5e1e5228b5f..d484ec09eb2e 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -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 */
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
index 2aeabba73e05..0704c902475f 100644
--- a/sound/soc/codecs/cs42l42.h
+++ b/sound/soc/codecs/cs42l42.h
@@ -188,6 +188,11 @@
 #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)
-- 
2.35.3