#define TWL6040_RATES   (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 #define TWL6040_FORMATS         (SNDRV_PCM_FMTBIT_S32_LE)
 
+struct twl6040_jack_data {
+       struct snd_soc_jack *jack;
+       int report;
+};
+
 /* codec private data */
 struct twl6040_data {
        int audpwron;
        unsigned int sysclk;
        struct snd_pcm_hw_constraint_list *sysclk_constraints;
        struct completion ready;
+       struct twl6040_jack_data hs_jack;
+       struct snd_soc_codec *codec;
+       struct workqueue_struct *workqueue;
+       struct delayed_work delayed_work;
+       struct mutex mutex;
 };
 
 /*
        return 0;
 }
 
+void twl6040_hs_jack_report(struct snd_soc_codec *codec,
+                               struct snd_soc_jack *jack, int report)
+{
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       int status;
+
+       mutex_lock(&priv->mutex);
+
+       /* Sync status */
+       status = twl6040_read_reg_volatile(codec, TWL6040_REG_STATUS);
+       if (status & TWL6040_PLUGCOMP)
+               snd_soc_jack_report(jack, report, report);
+       else
+               snd_soc_jack_report(jack, 0, report);
+
+       mutex_unlock(&priv->mutex);
+}
+
+void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
+                               struct snd_soc_jack *jack, int report)
+{
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       struct twl6040_jack_data *hs_jack = &priv->hs_jack;
+
+       hs_jack->jack = jack;
+       hs_jack->report = report;
+
+       twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
+}
+EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect);
+
+static void twl6040_accessory_work(struct work_struct *work)
+{
+       struct twl6040_data *priv = container_of(work,
+                                       struct twl6040_data, delayed_work.work);
+       struct snd_soc_codec *codec = priv->codec;
+       struct twl6040_jack_data *hs_jack = &priv->hs_jack;
+
+       twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
+}
+
 /* audio interrupt handler */
 static irqreturn_t twl6040_naudint_handler(int irq, void *data)
 {
                break;
        case TWL6040_PLUGINT:
        case TWL6040_UNPLUGINT:
+               queue_delayed_work(priv->workqueue, &priv->delayed_work,
+                                                       msecs_to_jiffies(200));
+               break;
        case TWL6040_HOOKINT:
                break;
        case TWL6040_HFINT:
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, priv);
 
+       priv->codec = codec;
+
        if (twl_codec) {
                audpwron = twl_codec->audpwron_gpio;
                naudint = twl_codec->naudint_irq;
 
        priv->audpwron = audpwron;
        priv->naudint = naudint;
+       priv->workqueue = create_singlethread_workqueue("twl6040-codec");
+
+       if (!priv->workqueue)
+               goto work_err;
+
+       INIT_DELAYED_WORK(&priv->delayed_work, twl6040_accessory_work);
+
+       mutex_init(&priv->mutex);
 
        init_completion(&priv->ready);
 
        if (gpio_is_valid(audpwron))
                gpio_free(audpwron);
 gpio1_err:
+       destroy_workqueue(priv->workqueue);
+work_err:
        kfree(priv);
        return ret;
 }
        if (naudint)
                free_irq(naudint, codec);
 
+       destroy_workqueue(priv->workqueue);
        kfree(priv);
 
        return 0;