Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 939c5671 authored by Mark Brown's avatar Mark Brown
Browse files

extcon: arizona: Time out if MICDET fails to report



In pathological cases the microphone detection may fail to report, for
example due to a failure to get a stable measurement. Provide a timeout
to cover such cases.

Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent 9c2ba270
Loading
Loading
Loading
Loading
+35 −3
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
#define ARIZONA_HPDET_MAX 10000

#define HPDET_DEBOUNCE 500
#define MICD_TIMEOUT 2000

struct arizona_extcon_info {
	struct device *dev;
@@ -63,6 +64,7 @@ struct arizona_extcon_info {
	bool micd_clamp;

	struct delayed_work hpdet_work;
	struct delayed_work micd_timeout_work;

	bool hpdet_active;
	bool hpdet_done;
@@ -730,6 +732,24 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
	info->hpdet_active = false;
}

static void arizona_micd_timeout_work(struct work_struct *work)
{
	struct arizona_extcon_info *info = container_of(work,
							struct arizona_extcon_info,
							micd_timeout_work.work);

	mutex_lock(&info->lock);

	dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
	arizona_identify_headphone(info);

	info->detecting = false;

	arizona_stop_mic(info);

	mutex_unlock(&info->lock);
}

static irqreturn_t arizona_micdet(int irq, void *data)
{
	struct arizona_extcon_info *info = data;
@@ -737,6 +757,8 @@ static irqreturn_t arizona_micdet(int irq, void *data)
	unsigned int val = 0, lvl;
	int ret, i, key;

	cancel_delayed_work_sync(&info->micd_timeout_work);

	mutex_lock(&info->lock);

	for (i = 0; i < 10 && !(val & 0x7fc); i++) {
@@ -858,6 +880,10 @@ static irqreturn_t arizona_micdet(int irq, void *data)
	}

handled:
	if (info->detecting)
		schedule_delayed_work(&info->micd_timeout_work,
				      msecs_to_jiffies(MICD_TIMEOUT));

	pm_runtime_mark_last_busy(info->dev);
	mutex_unlock(&info->lock);

@@ -880,10 +906,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
	struct arizona_extcon_info *info = data;
	struct arizona *arizona = info->arizona;
	unsigned int val, present, mask;
	bool cancelled;
	bool cancelled_hp, cancelled_mic;
	int ret, i;

	cancelled = cancel_delayed_work_sync(&info->hpdet_work);
	cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
	cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);

	pm_runtime_get_sync(info->dev);

@@ -909,10 +936,14 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
	val &= mask;
	if (val == info->last_jackdet) {
		dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
		if (cancelled)
		if (cancelled_hp)
			schedule_delayed_work(&info->hpdet_work,
					      msecs_to_jiffies(HPDET_DEBOUNCE));

		if (cancelled_mic)
			schedule_delayed_work(&info->micd_timeout_work,
					      msecs_to_jiffies(MICD_TIMEOUT));

		goto out;
	}
	info->last_jackdet = val;
@@ -1037,6 +1068,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
	info->dev = &pdev->dev;
	info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
	INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
	INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
	platform_set_drvdata(pdev, info);

	switch (arizona->type) {