From: Stefan Binding sbinding@opensource.cirrus.com
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 --- 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 78f8c89410b6..3f202acd4a8e 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1048,7 +1048,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 */ @@ -1063,23 +1064,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; @@ -1088,14 +1106,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 */ @@ -1112,6 +1142,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) @@ -1134,6 +1172,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. @@ -1142,18 +1192,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)