ASoC: rt5663: Check the JD status in the button pushing
authoroder_chiou@realtek.com <oder_chiou@realtek.com>
Fri, 10 Nov 2017 05:16:44 +0000 (13:16 +0800)
committerMark Brown <broonie@kernel.org>
Fri, 10 Nov 2017 12:34:52 +0000 (12:34 +0000)
Check the JD status in the button pushing to prevent the IRQ that is locked
by button pushing event while the jack unpluging.

Signed-off-by: Oder Chiou <oder_chiou@realtek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/rt5663.c

index eb3065a..d7b163a 100644 (file)
@@ -52,7 +52,7 @@ struct rt5663_priv {
        struct snd_soc_codec *codec;
        struct rt5663_platform_data pdata;
        struct regmap *regmap;
-       struct delayed_work jack_detect_work;
+       struct delayed_work jack_detect_work, jd_unplug_work;
        struct snd_soc_jack *hs_jack;
        struct timer_list btn_check_timer;
        struct impedance_mapping_table *imp_table;
@@ -1940,8 +1940,15 @@ static void rt5663_jack_detect_work(struct work_struct *work)
                                break;
                        }
                        /* button release or spurious interrput*/
-                       if (btn_type == 0)
+                       if (btn_type == 0) {
                                report =  rt5663->jack_type;
+                               cancel_delayed_work_sync(
+                                       &rt5663->jd_unplug_work);
+                       } else {
+                               queue_delayed_work(system_wq,
+                                       &rt5663->jd_unplug_work,
+                                       msecs_to_jiffies(500));
+                       }
                }
        } else {
                /* jack out */
@@ -1962,6 +1969,37 @@ static void rt5663_jack_detect_work(struct work_struct *work)
                            SND_JACK_BTN_2 | SND_JACK_BTN_3);
 }
 
+static void rt5663_jd_unplug_work(struct work_struct *work)
+{
+       struct rt5663_priv *rt5663 =
+               container_of(work, struct rt5663_priv, jd_unplug_work.work);
+       struct snd_soc_codec *codec = rt5663->codec;
+
+       if (!codec)
+               return;
+
+       if (!rt5663_check_jd_status(codec)) {
+               /* jack out */
+               switch (rt5663->codec_ver) {
+               case CODEC_VER_1:
+                       rt5663_v2_jack_detect(rt5663->codec, 0);
+                       break;
+               case CODEC_VER_0:
+                       rt5663_jack_detect(rt5663->codec, 0);
+                       break;
+               default:
+                       dev_err(codec->dev, "Unknown CODEC Version\n");
+               }
+
+               snd_soc_jack_report(rt5663->hs_jack, 0, SND_JACK_HEADSET |
+                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                   SND_JACK_BTN_2 | SND_JACK_BTN_3);
+       } else {
+               queue_delayed_work(system_wq, &rt5663->jd_unplug_work,
+                       msecs_to_jiffies(500));
+       }
+}
+
 static const struct snd_kcontrol_new rt5663_snd_controls[] = {
        /* DAC Digital Volume */
        SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL,
@@ -3556,6 +3594,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
        }
 
        INIT_DELAYED_WORK(&rt5663->jack_detect_work, rt5663_jack_detect_work);
+       INIT_DELAYED_WORK(&rt5663->jd_unplug_work, rt5663_jd_unplug_work);
 
        if (i2c->irq) {
                ret = request_irq(i2c->irq, rt5663_irq,