struct gpio_desc *reset_gpio;
        struct snd_soc_jack *jack;
        struct mutex irq_lock;
-       u8 plug_state;
+       u8 tip_state;
+       u8 ring_state;
        int pll_config;
        int bclk;
        u8 pll_mclk_f;
                FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2));
 }
 
+static void cs42l84_set_interrupt_masks(struct cs42l84_private *cs42l84,
+                                       unsigned int val)
+{
+       regmap_update_bits(cs42l84->regmap, CS42L84_TSRS_PLUG_INT_MASK,
+                       CS42L84_RS_PLUG | CS42L84_RS_UNPLUG |
+                       CS42L84_TS_PLUG | CS42L84_TS_UNPLUG,
+                       val);
+}
+
 static irqreturn_t cs42l84_irq_thread(int irq, void *data)
 {
        struct cs42l84_private *cs42l84 = (struct cs42l84_private *)data;
        unsigned int stickies[1];
        unsigned int masks[1];
        unsigned int reg;
-       u8 current_plug_status;
+       u8 current_tip_state;
+       u8 current_ring_state;
        int i;
 
        mutex_lock(&cs42l84->irq_lock);
                                irq_params_table[i].mask;
        }
 
+       /* When handling plug sene IRQs, we only care about EITHER tip OR ring.
+        * Ring is useless on remove, and is only useful on insert for
+        * detecting if the plug state has changed AFTER we have handled the
+        * tip sense IRQ, e.g. if the plug was not fully seated within the tip
+        * sense debounce time.
+        */
+
        if ((~masks[0]) & irq_params_table[0].mask) {
                regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®);
-               current_plug_status = (((char) reg) &
+
+               current_tip_state = (((char) reg) &
                      (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
                      CS42L84_TS_PLUG_SHIFT;
 
-               switch (current_plug_status) {
-               case CS42L84_PLUG:
-                       if (cs42l84->plug_state != CS42L84_PLUG) {
-                               cs42l84->plug_state = CS42L84_PLUG;
+               if (current_tip_state != cs42l84->tip_state) {
+                       cs42l84->tip_state = current_tip_state;
+                       switch (current_tip_state) {
+                       case CS42L84_PLUG:
                                dev_dbg(cs42l84->dev, "Plug event\n");
 
                                cs42l84_detect_hs(cs42l84);
                                 * was disconnected at any point during the detection procedure.
                                 */
                                regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®);
-                               current_plug_status = (((char) reg) &
+                               current_tip_state = (((char) reg) &
                                      (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
                                      CS42L84_TS_PLUG_SHIFT;
-                               if (current_plug_status != CS42L84_PLUG) {
+                               if (current_tip_state != CS42L84_PLUG) {
                                        dev_dbg(cs42l84->dev, "Wobbly connection, detection invalidated\n");
-                                       cs42l84->plug_state = CS42L84_UNPLUG;
+                                       cs42l84->tip_state = CS42L84_UNPLUG;
                                        cs42l84_revert_hs(cs42l84);
                                }
-                       }
-                       break;
 
-               case CS42L84_UNPLUG:
-                       if (cs42l84->plug_state != CS42L84_UNPLUG) {
-                               cs42l84->plug_state = CS42L84_UNPLUG;
+                               /* Unmask ring sense interrupts */
+                               cs42l84_set_interrupt_masks(cs42l84, 0);
+                               break;
+                       case CS42L84_UNPLUG:
+                               cs42l84->ring_state = CS42L84_UNPLUG;
                                dev_dbg(cs42l84->dev, "Unplug event\n");
 
                                cs42l84_revert_hs(cs42l84);
                                cs42l84->hs_type = 0;
                                snd_soc_jack_report(cs42l84->jack, 0,
                                                    SND_JACK_HEADSET);
+
+                               /* Mask ring sense interrupts */
+                               cs42l84_set_interrupt_masks(cs42l84,
+                                                           CS42L84_RS_PLUG | CS42L84_RS_UNPLUG);
+                               break;
+                       default:
+                               cs42l84->ring_state = CS42L84_TRANS;
+                               break;
                        }
-                       break;
 
-               default:
-                       if (cs42l84->plug_state != CS42L84_TRANS)
-                               cs42l84->plug_state = CS42L84_TRANS;
+                       mutex_unlock(&cs42l84->irq_lock);
+
+                       return IRQ_HANDLED;
+               }
+
+               /* Tip state didn't change, we must've got a ring sense IRQ */
+               current_ring_state = (((char) reg) &
+                     (CS42L84_RS_PLUG | CS42L84_RS_UNPLUG)) >>
+                     CS42L84_RS_PLUG_SHIFT;
+
+               if (current_ring_state != cs42l84->ring_state) {
+                       cs42l84->ring_state = current_ring_state;
+                       if (current_ring_state == CS42L84_PLUG)
+                               cs42l84_detect_hs(cs42l84);
                }
        }
+
        mutex_unlock(&cs42l84->irq_lock);
 
        return IRQ_HANDLED;
 }
 
-static void cs42l84_set_interrupt_masks(struct cs42l84_private *cs42l84)
-{
-       regmap_update_bits(cs42l84->regmap, CS42L84_TSRS_PLUG_INT_MASK,
-                       CS42L84_RS_PLUG | CS42L84_RS_UNPLUG |
-                       CS42L84_TS_PLUG | CS42L84_TS_UNPLUG,
-                       CS42L84_RS_PLUG | CS42L84_RS_UNPLUG);
-}
-
 static void cs42l84_setup_plug_detect(struct cs42l84_private *cs42l84)
 {
        unsigned int reg;
 
        /* Save the initial status of the tip sense */
        regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®);
-       cs42l84->plug_state = (((char) reg) &
+       cs42l84->tip_state = (((char) reg) &
                      (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
                      CS42L84_TS_PLUG_SHIFT;
 
        /* Setup plug detection */
        cs42l84_setup_plug_detect(cs42l84);
 
-       /* Mask/Unmask Interrupts */
-       cs42l84_set_interrupt_masks(cs42l84);
+       /* Mask ring sense interrupts */
+       cs42l84_set_interrupt_masks(cs42l84, CS42L84_RS_PLUG | CS42L84_RS_UNPLUG);
 
        /* Register codec for machine driver */
        ret = devm_snd_soc_register_component(&i2c_client->dev,