Skip to content

Commit

Permalink
extcon: arizona: Factor out microphone impedance into a function
Browse files Browse the repository at this point in the history
The microphone detection handler is very long, start breaking it up
by factoring out the actual reading of the impedance value into a
separate functions. Additionally, this also fixes a minor bug and
ensures that the microphone timeout will be rescheduled in all error
cases.

Signed-off-by: Charles Keepax <[email protected]>
Signed-off-by: Chanwoo Choi <[email protected]>
  • Loading branch information
charleskeepax authored and chanwoochoi committed Dec 9, 2019
1 parent 3dfa743 commit 7e14fc4
Showing 1 changed file with 73 additions and 52 deletions.
125 changes: 73 additions & 52 deletions drivers/extcon/extcon-arizona.c
Original file line number Diff line number Diff line change
Expand Up @@ -804,88 +804,109 @@ static void arizona_micd_timeout_work(struct work_struct *work)
mutex_unlock(&info->lock);
}

static void arizona_micd_detect(struct work_struct *work)
static int arizona_micd_adc_read(struct arizona_extcon_info *info)
{
struct arizona_extcon_info *info = container_of(work,
struct arizona_extcon_info,
micd_detect_work.work);
struct arizona *arizona = info->arizona;
unsigned int val = 0, lvl;
int ret, i, key;

cancel_delayed_work_sync(&info->micd_timeout_work);
unsigned int val;
int ret;

mutex_lock(&info->lock);
/* Must disable MICD before we read the ADCVAL */
regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
ARIZONA_MICD_ENA, 0);

/* If the cable was removed while measuring ignore the result */
ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
if (ret < 0) {
dev_err(arizona->dev, "Failed to check cable state: %d\n",
ret);
mutex_unlock(&info->lock);
return;
} else if (!ret) {
dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
mutex_unlock(&info->lock);
return;
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
if (ret != 0) {
dev_err(arizona->dev,
"Failed to read MICDET_ADCVAL: %d\n", ret);
return ret;
}

if (info->detecting && arizona->pdata.micd_software_compare) {
/* Must disable MICD before we read the ADCVAL */
regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
ARIZONA_MICD_ENA, 0);
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
if (ret != 0) {
dev_err(arizona->dev,
"Failed to read MICDET_ADCVAL: %d\n",
ret);
mutex_unlock(&info->lock);
return;
}
dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);

dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
val &= ARIZONA_MICDET_ADCVAL_MASK;
if (val < ARRAY_SIZE(arizona_micd_levels))
val = arizona_micd_levels[val];
else
val = INT_MAX;

if (val <= QUICK_HEADPHONE_MAX_OHM)
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
else if (val <= MICROPHONE_MIN_OHM)
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
else if (val <= MICROPHONE_MAX_OHM)
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
else
val = ARIZONA_MICD_LVL_8;

val &= ARIZONA_MICDET_ADCVAL_MASK;
if (val < ARRAY_SIZE(arizona_micd_levels))
val = arizona_micd_levels[val];
else
val = INT_MAX;

if (val <= QUICK_HEADPHONE_MAX_OHM)
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
else if (val <= MICROPHONE_MIN_OHM)
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
else if (val <= MICROPHONE_MAX_OHM)
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
else
val = ARIZONA_MICD_LVL_8;
}
return val;
}

static int arizona_micd_read(struct arizona_extcon_info *info)
{
struct arizona *arizona = info->arizona;
unsigned int val = 0;
int ret, i;

for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
if (ret != 0) {
dev_err(arizona->dev,
"Failed to read MICDET: %d\n", ret);
mutex_unlock(&info->lock);
return;
return ret;
}

dev_dbg(arizona->dev, "MICDET: %x\n", val);

if (!(val & ARIZONA_MICD_VALID)) {
dev_warn(arizona->dev,
"Microphone detection state invalid\n");
mutex_unlock(&info->lock);
return;
return -EINVAL;
}
}

if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
dev_err(arizona->dev, "Failed to get valid MICDET value\n");
return -EINVAL;
}

return val;
}

static void arizona_micd_detect(struct work_struct *work)
{
struct arizona_extcon_info *info = container_of(work,
struct arizona_extcon_info,
micd_detect_work.work);
struct arizona *arizona = info->arizona;
unsigned int val = 0, lvl;
int ret, i, key;

cancel_delayed_work_sync(&info->micd_timeout_work);

mutex_lock(&info->lock);

/* If the cable was removed while measuring ignore the result */
ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
if (ret < 0) {
dev_err(arizona->dev, "Failed to check cable state: %d\n",
ret);
mutex_unlock(&info->lock);
return;
} else if (!ret) {
dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
mutex_unlock(&info->lock);
return;
}

if (info->detecting && arizona->pdata.micd_software_compare)
ret = arizona_micd_adc_read(info);
else
ret = arizona_micd_read(info);
if (ret < 0)
goto handled;

val = ret;

/* Due to jack detect this should never happen */
if (!(val & ARIZONA_MICD_STS)) {
dev_warn(arizona->dev, "Detected open circuit\n");
Expand Down

0 comments on commit 7e14fc4

Please sign in to comment.