Commit 12451814 authored by Stefan Binding's avatar Stefan Binding Committed by Mark Brown

ASoC: cs42l42: Implement Manual Type detection as fallback

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: default avatarStefan Binding <sbinding@opensource.cirrus.com>
Signed-off-by: default avatarVitaly Rodionov <vitalyr@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20210916102750.9212-2-vitalyr@opensource.cirrus.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent bde4f08c
......@@ -1046,11 +1046,83 @@ static struct snd_soc_dai_driver cs42l42_dai = {
.ops = &cs42l42_ops,
};
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_sw;
/* Set hs detect to manual, active 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,
(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 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,
(0 << CS42L42_HSDET_CTRL_SHIFT) |
(0 << CS42L42_HSDET_SET_SHIFT) |
(0 << CS42L42_HSBIAS_REF_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,
......@@ -1059,6 +1131,19 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42)
(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,
......@@ -1070,12 +1155,7 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42)
(2 << CS42L42_HSDET_SET_SHIFT) |
(0 << CS42L42_HSBIAS_REF_SHIFT) |
(3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
/* Read and save the hs detection result */
regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status);
cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >>
CS42L42_HSDET_TYPE_SHIFT;
}
/* Set up button detection */
if ((cs42l42->hs_type == CS42L42_PLUG_CTIA) ||
......
......@@ -228,6 +228,60 @@
#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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment