]> git.ipfire.org Git - thirdparty/linux.git/blobdiff - sound/soc/codecs/rt5651.c
ASoC: rt5651: Add support for jack detect using an external GPIO
[thirdparty/linux.git] / sound / soc / codecs / rt5651.c
index 9a007c16263161c88dab912c1e0fc2ba3c4274cb..75994297c8964a749ea5db14c75b86e6b272b96b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/platform_device.h>
@@ -1621,6 +1622,12 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component)
        struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
        int val;
 
+       if (rt5651->gpiod_hp_det) {
+               val = gpiod_get_value_cansleep(rt5651->gpiod_hp_det);
+               dev_dbg(component->dev, "jack-detect gpio %d\n", val);
+               return val;
+       }
+
        val = snd_soc_component_read32(component, RT5651_INT_IRQ_ST);
        dev_dbg(component->dev, "irq status %#04x\n", val);
 
@@ -1761,6 +1768,13 @@ static int rt5651_detect_headset(struct snd_soc_component *component)
        return SND_JACK_HEADPHONE;
 }
 
+static bool rt5651_support_button_press(struct rt5651_priv *rt5651)
+{
+       /* Button press support only works with internal jack-detection */
+       return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) &&
+               rt5651->gpiod_hp_det == NULL;
+}
+
 static void rt5651_jack_detect_work(struct work_struct *work)
 {
        struct rt5651_priv *rt5651 =
@@ -1785,15 +1799,15 @@ static void rt5651_jack_detect_work(struct work_struct *work)
                WARN_ON(rt5651->ovcd_irq_enabled);
                rt5651_enable_micbias1_for_ovcd(component);
                report = rt5651_detect_headset(component);
-               if (report == SND_JACK_HEADSET) {
+               dev_dbg(component->dev, "detect report %#02x\n", report);
+               snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
+               if (rt5651_support_button_press(rt5651)) {
                        /* Enable ovcd IRQ for button press detect. */
                        rt5651_enable_micbias1_ovcd_irq(component);
                } else {
                        /* No more need for overcurrent detect. */
                        rt5651_disable_micbias1_for_ovcd(component);
                }
-               dev_dbg(component->dev, "detect report %#02x\n", report);
-               snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
        } else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) {
                dev_dbg(component->dev, "OVCD IRQ\n");
 
@@ -1837,16 +1851,20 @@ static void rt5651_cancel_work(void *data)
 }
 
 static void rt5651_enable_jack_detect(struct snd_soc_component *component,
-                                     struct snd_soc_jack *hp_jack)
+                                     struct snd_soc_jack *hp_jack,
+                                     struct gpio_desc *gpiod_hp_det)
 {
        struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
-
-       /* IRQ output on GPIO1 */
-       snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1,
-               RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ);
+       bool using_internal_jack_detect = true;
 
        /* Select jack detect source */
        switch (rt5651->jd_src) {
+       case RT5651_JD_NULL:
+               rt5651->gpiod_hp_det = gpiod_hp_det;
+               if (!rt5651->gpiod_hp_det)
+                       return; /* No jack detect */
+               using_internal_jack_detect = false;
+               break;
        case RT5651_JD1_1:
                snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
                        RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1);
@@ -1865,16 +1883,20 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component,
                snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1,
                        RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN);
                break;
-       case RT5651_JD_NULL:
-               return;
        default:
                dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
                return;
        }
 
-       /* Enable jack detect power */
-       snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
-               RT5651_PWR_JD_M, RT5651_PWR_JD_M);
+       if (using_internal_jack_detect) {
+               /* IRQ output on GPIO1 */
+               snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1,
+                       RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ);
+
+               /* Enable jack detect power */
+               snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+                       RT5651_PWR_JD_M, RT5651_PWR_JD_M);
+       }
 
        /* Set OVCD threshold current and scale-factor */
        snd_soc_component_write(component, RT5651_PR_BASE + RT5651_BIAS_CUR4,
@@ -1903,7 +1925,7 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component,
                RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN);
 
        rt5651->hp_jack = hp_jack;
-       if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+       if (rt5651_support_button_press(rt5651)) {
                rt5651_enable_micbias1_for_ovcd(component);
                rt5651_enable_micbias1_ovcd_irq(component);
        }
@@ -1920,7 +1942,7 @@ static void rt5651_disable_jack_detect(struct snd_soc_component *component)
        disable_irq(rt5651->irq);
        rt5651_cancel_work(rt5651);
 
-       if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+       if (rt5651_support_button_press(rt5651)) {
                rt5651_disable_micbias1_ovcd_irq(component);
                rt5651_disable_micbias1_for_ovcd(component);
                snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
@@ -1933,7 +1955,7 @@ static int rt5651_set_jack(struct snd_soc_component *component,
                           struct snd_soc_jack *jack, void *data)
 {
        if (jack)
-               rt5651_enable_jack_detect(component, jack);
+               rt5651_enable_jack_detect(component, jack, data);
        else
                rt5651_disable_jack_detect(component);