From patchwork Sun Feb 25 10:47:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 10240761 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 742B660211 for ; Sun, 25 Feb 2018 10:50:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 68F5329C07 for ; Sun, 25 Feb 2018 10:50:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5C6DA29CCE; Sun, 25 Feb 2018 10:50:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 78B0329C07 for ; Sun, 25 Feb 2018 10:50:57 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 468DB267991; Sun, 25 Feb 2018 11:48:10 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 9FD2C2674D6; Sun, 25 Feb 2018 11:47:50 +0100 (CET) Received: from mx1.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by alsa0.perex.cz (Postfix) with ESMTP id BF8EE267441 for ; Sun, 25 Feb 2018 11:47:47 +0100 (CET) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 34B768182D3A; Sun, 25 Feb 2018 10:47:47 +0000 (UTC) Received: from shalem.localdomain.com (ovpn-116-99.ams2.redhat.com [10.36.116.99]) by smtp.corp.redhat.com (Postfix) with ESMTP id 173D210B0F25; Sun, 25 Feb 2018 10:47:45 +0000 (UTC) From: Hans de Goede To: Mark Brown , Bard Liao , Oder Chiou , Pierre-Louis Bossart Date: Sun, 25 Feb 2018 11:47:02 +0100 Message-Id: <20180225104713.4745-22-hdegoede@redhat.com> In-Reply-To: <20180225104713.4745-1-hdegoede@redhat.com> References: <20180225104713.4745-1-hdegoede@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Sun, 25 Feb 2018 10:47:47 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Sun, 25 Feb 2018 10:47:47 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'hdegoede@redhat.com' RCPT:'' Cc: Hans de Goede , alsa-devel@alsa-project.org, Carlo Caione , Takashi Iwai Subject: [alsa-devel] [PATCH v2 21/32] ASoC: rt5651: Rewrite jack-type detection X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP We get the insertion event before the jack is fully inserted at which point the second ring on a TRRS connector may short the 2nd ring and sleeve contacts. Testing has shown that this short-circuit may happen as late as 500ms after the insertion event, but it never lasts longer then 300ms. This commit changes the detection algorithm to require 5 identical OVCD values in a row at 100 ms intervals to fix the jack-type sometimes getting mis-detected. Tested-by: Carlo Caione Signed-off-by: Hans de Goede --- sound/soc/codecs/rt5651.c | 110 +++++++++++++++++++++++++++++----------------- sound/soc/codecs/rt5651.h | 2 +- 2 files changed, 70 insertions(+), 42 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index b88585d652ea..ee6f951fdbb9 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1622,12 +1622,76 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component) return val == 0; } +/* Jack detect timings */ +#define JACK_SETTLE_TIME 100 /* milli seconds */ +#define JACK_DETECT_COUNT 5 +#define JACK_DETECT_MAXCOUNT 20 /* Aprox. 2 seconds worth of tries */ + +static int rt5651_detect_headset(struct snd_soc_component *component) +{ + int i, headset_count = 0, headphone_count = 0; + + /* + * We get the insertion event before the jack is fully inserted at which + * point the second ring on a TRRS connector may short the 2nd ring and + * sleeve contacts, also the overcurrent detection is not entirely + * reliable. So we try several times with a wait in between until we + * detect the same type JACK_DETECT_COUNT times in a row. + */ + for (i = 0; i < JACK_DETECT_MAXCOUNT; i++) { + /* Clear any previous over-current status flag */ + rt5651_clear_micbias1_ovcd(component); + + msleep(JACK_SETTLE_TIME); + + /* Check the jack is still connected before checking ovcd */ + if (!rt5651_jack_inserted(component)) + return 0; + + if (rt5651_micbias1_ovcd(component)) { + /* + * Over current detected, there is a short between the + * 2nd ring contact and the ground, so a TRS connector + * without a mic contact and thus plain headphones. + */ + dev_dbg(component->dev, "mic-gnd shorted\n"); + headset_count = 0; + headphone_count++; + if (headphone_count == JACK_DETECT_COUNT) + return SND_JACK_HEADPHONE; + } else { + dev_dbg(component->dev, "mic-gnd open\n"); + headphone_count = 0; + headset_count++; + if (headset_count == JACK_DETECT_COUNT) + return SND_JACK_HEADSET; + } + } + + dev_err(component->dev, "Error detecting headset vs headphones, bad contact?, assuming headphones\n"); + return SND_JACK_HEADPHONE; +} + +static void rt5651_jack_detect_work(struct work_struct *work) +{ + struct rt5651_priv *rt5651 = + container_of(work, struct rt5651_priv, jack_detect_work); + int report = 0; + + if (rt5651_jack_inserted(rt5651->component)) { + rt5651_enable_micbias1_for_ovcd(rt5651->component); + report = rt5651_detect_headset(rt5651->component); + rt5651_disable_micbias1_for_ovcd(rt5651->component); + } + + snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); +} + static irqreturn_t rt5651_irq(int irq, void *data) { struct rt5651_priv *rt5651 = data; - queue_delayed_work(system_power_efficient_wq, - &rt5651->jack_detect_work, msecs_to_jiffies(250)); + queue_work(system_power_efficient_wq, &rt5651->jack_detect_work); return IRQ_HANDLED; } @@ -1756,8 +1820,7 @@ static int rt5651_set_jack(struct snd_soc_component *component, } /* sync initial jack state */ - queue_delayed_work(system_power_efficient_wq, - &rt5651->jack_detect_work, 0); + queue_work(system_power_efficient_wq, &rt5651->jack_detect_work); return 0; } @@ -1922,41 +1985,6 @@ static const struct i2c_device_id rt5651_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id); -static int rt5651_jack_detect(struct snd_soc_component *component, int jack_insert) -{ - int jack_type; - - if (jack_insert) { - rt5651_enable_micbias1_for_ovcd(component); - rt5651_clear_micbias1_ovcd(component); - msleep(100); - if (rt5651_micbias1_ovcd(component)) - jack_type = SND_JACK_HEADPHONE; - else - jack_type = SND_JACK_HEADSET; - rt5651_disable_micbias1_for_ovcd(component); - } else { /* jack out */ - jack_type = 0; - } - - return jack_type; -} - -static void rt5651_jack_detect_work(struct work_struct *work) -{ - struct rt5651_priv *rt5651 = - container_of(work, struct rt5651_priv, jack_detect_work.work); - int report, jack_inserted; - - if (!rt5651->component) - return; - - jack_inserted = rt5651_jack_inserted(rt5651->component); - report = rt5651_jack_detect(rt5651->component, jack_inserted); - - snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); -} - static int rt5651_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1995,7 +2023,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, rt5651->irq = i2c->irq; rt5651->hp_mute = 1; - INIT_DELAYED_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work); + INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work); ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5651, @@ -2008,7 +2036,7 @@ static int rt5651_i2c_remove(struct i2c_client *i2c) { struct rt5651_priv *rt5651 = i2c_get_clientdata(i2c); - cancel_delayed_work_sync(&rt5651->jack_detect_work); + cancel_work_sync(&rt5651->jack_detect_work); return 0; } diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h index 5fb25f7e2a8c..6f0e4a8e1378 100644 --- a/sound/soc/codecs/rt5651.h +++ b/sound/soc/codecs/rt5651.h @@ -2072,7 +2072,7 @@ struct rt5651_priv { struct snd_soc_component *component; struct regmap *regmap; struct snd_soc_jack *hp_jack; - struct delayed_work jack_detect_work; + struct work_struct jack_detect_work; enum rt5651_jd_src jd_src; int irq;