Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: rt5651: Rewrite jack-type detection

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 <carlo@endlessm.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Hans de Goede and committed by
Mark Brown
ee680968 0fe94745

+70 -42
+69 -41
sound/soc/codecs/rt5651.c
··· 1622 1622 return val == 0; 1623 1623 } 1624 1624 1625 + /* Jack detect timings */ 1626 + #define JACK_SETTLE_TIME 100 /* milli seconds */ 1627 + #define JACK_DETECT_COUNT 5 1628 + #define JACK_DETECT_MAXCOUNT 20 /* Aprox. 2 seconds worth of tries */ 1629 + 1630 + static int rt5651_detect_headset(struct snd_soc_component *component) 1631 + { 1632 + int i, headset_count = 0, headphone_count = 0; 1633 + 1634 + /* 1635 + * We get the insertion event before the jack is fully inserted at which 1636 + * point the second ring on a TRRS connector may short the 2nd ring and 1637 + * sleeve contacts, also the overcurrent detection is not entirely 1638 + * reliable. So we try several times with a wait in between until we 1639 + * detect the same type JACK_DETECT_COUNT times in a row. 1640 + */ 1641 + for (i = 0; i < JACK_DETECT_MAXCOUNT; i++) { 1642 + /* Clear any previous over-current status flag */ 1643 + rt5651_clear_micbias1_ovcd(component); 1644 + 1645 + msleep(JACK_SETTLE_TIME); 1646 + 1647 + /* Check the jack is still connected before checking ovcd */ 1648 + if (!rt5651_jack_inserted(component)) 1649 + return 0; 1650 + 1651 + if (rt5651_micbias1_ovcd(component)) { 1652 + /* 1653 + * Over current detected, there is a short between the 1654 + * 2nd ring contact and the ground, so a TRS connector 1655 + * without a mic contact and thus plain headphones. 1656 + */ 1657 + dev_dbg(component->dev, "mic-gnd shorted\n"); 1658 + headset_count = 0; 1659 + headphone_count++; 1660 + if (headphone_count == JACK_DETECT_COUNT) 1661 + return SND_JACK_HEADPHONE; 1662 + } else { 1663 + dev_dbg(component->dev, "mic-gnd open\n"); 1664 + headphone_count = 0; 1665 + headset_count++; 1666 + if (headset_count == JACK_DETECT_COUNT) 1667 + return SND_JACK_HEADSET; 1668 + } 1669 + } 1670 + 1671 + dev_err(component->dev, "Error detecting headset vs headphones, bad contact?, assuming headphones\n"); 1672 + return SND_JACK_HEADPHONE; 1673 + } 1674 + 1675 + static void rt5651_jack_detect_work(struct work_struct *work) 1676 + { 1677 + struct rt5651_priv *rt5651 = 1678 + container_of(work, struct rt5651_priv, jack_detect_work); 1679 + int report = 0; 1680 + 1681 + if (rt5651_jack_inserted(rt5651->component)) { 1682 + rt5651_enable_micbias1_for_ovcd(rt5651->component); 1683 + report = rt5651_detect_headset(rt5651->component); 1684 + rt5651_disable_micbias1_for_ovcd(rt5651->component); 1685 + } 1686 + 1687 + snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); 1688 + } 1689 + 1625 1690 static irqreturn_t rt5651_irq(int irq, void *data) 1626 1691 { 1627 1692 struct rt5651_priv *rt5651 = data; 1628 1693 1629 - queue_delayed_work(system_power_efficient_wq, 1630 - &rt5651->jack_detect_work, msecs_to_jiffies(250)); 1694 + queue_work(system_power_efficient_wq, &rt5651->jack_detect_work); 1631 1695 1632 1696 return IRQ_HANDLED; 1633 1697 } ··· 1779 1715 } 1780 1716 1781 1717 /* sync initial jack state */ 1782 - queue_delayed_work(system_power_efficient_wq, 1783 - &rt5651->jack_detect_work, 0); 1718 + queue_work(system_power_efficient_wq, &rt5651->jack_detect_work); 1784 1719 1785 1720 return 0; 1786 1721 } ··· 1991 1928 }; 1992 1929 MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id); 1993 1930 1994 - static int rt5651_jack_detect(struct snd_soc_component *component, int jack_insert) 1995 - { 1996 - int jack_type; 1997 - 1998 - if (jack_insert) { 1999 - rt5651_enable_micbias1_for_ovcd(component); 2000 - rt5651_clear_micbias1_ovcd(component); 2001 - msleep(100); 2002 - if (rt5651_micbias1_ovcd(component)) 2003 - jack_type = SND_JACK_HEADPHONE; 2004 - else 2005 - jack_type = SND_JACK_HEADSET; 2006 - rt5651_disable_micbias1_for_ovcd(component); 2007 - } else { /* jack out */ 2008 - jack_type = 0; 2009 - } 2010 - 2011 - return jack_type; 2012 - } 2013 - 2014 - static void rt5651_jack_detect_work(struct work_struct *work) 2015 - { 2016 - struct rt5651_priv *rt5651 = 2017 - container_of(work, struct rt5651_priv, jack_detect_work.work); 2018 - int report, jack_inserted; 2019 - 2020 - if (!rt5651->component) 2021 - return; 2022 - 2023 - jack_inserted = rt5651_jack_inserted(rt5651->component); 2024 - report = rt5651_jack_detect(rt5651->component, jack_inserted); 2025 - 2026 - snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); 2027 - } 2028 - 2029 1931 /* 2030 1932 * Note this function MUST not look at device-properties, see the comment 2031 1933 * above rt5651_apply_properties(). ··· 2033 2005 rt5651->irq = i2c->irq; 2034 2006 rt5651->hp_mute = 1; 2035 2007 2036 - INIT_DELAYED_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work); 2008 + INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work); 2037 2009 2038 2010 ret = devm_snd_soc_register_component(&i2c->dev, 2039 2011 &soc_component_dev_rt5651, ··· 2046 2018 { 2047 2019 struct rt5651_priv *rt5651 = i2c_get_clientdata(i2c); 2048 2020 2049 - cancel_delayed_work_sync(&rt5651->jack_detect_work); 2021 + cancel_work_sync(&rt5651->jack_detect_work); 2050 2022 2051 2023 return 0; 2052 2024 }
+1 -1
sound/soc/codecs/rt5651.h
··· 2072 2072 struct snd_soc_component *component; 2073 2073 struct regmap *regmap; 2074 2074 struct snd_soc_jack *hp_jack; 2075 - struct delayed_work jack_detect_work; 2075 + struct work_struct jack_detect_work; 2076 2076 enum rt5651_jd_src jd_src; 2077 2077 unsigned int ovcd_th; 2078 2078 unsigned int ovcd_sf;