diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 0f93903d44093..0fb3662e28b60 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -1072,6 +1072,12 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 	if (IS_ERR(hdmi.ip_data.base_wp))
 		return PTR_ERR(hdmi.ip_data.base_wp);
 
+	hdmi.ip_data.irq = platform_get_irq(pdev, 0);
+	if (hdmi.ip_data.irq < 0) {
+		DSSERR("platform_get_irq failed\n");
+		return -ENODEV;
+	}
+
 	r = hdmi_get_clocks(pdev);
 	if (r) {
 		DSSERR("can't get clocks\n");
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h
index 216aa704f9d72..2f7fbc8945789 100644
--- a/drivers/video/omap2/dss/ti_hdmi.h
+++ b/drivers/video/omap2/dss/ti_hdmi.h
@@ -155,6 +155,7 @@ struct hdmi_ip_data {
 	unsigned long	core_av_offset;
 	unsigned long	pll_offset;
 	unsigned long	phy_offset;
+	int		irq;
 	const struct ti_hdmi_ip_ops *ops;
 	struct hdmi_config cfg;
 	struct hdmi_pll_info pll_data;
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
index e18b222ed7390..052f2db35d625 100644
--- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
+++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
@@ -38,6 +38,9 @@
 #include "dss.h"
 #include "dss_features.h"
 
+#define HDMI_IRQ_LINK_CONNECT		(1 << 25)
+#define HDMI_IRQ_LINK_DISCONNECT	(1 << 26)
+
 static inline void hdmi_write_reg(void __iomem *base_addr,
 				const u16 idx, u32 val)
 {
@@ -233,37 +236,39 @@ void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data)
 	hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF);
 }
 
-static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data)
+static irqreturn_t hdmi_irq_handler(int irq, void *data)
 {
-	bool hpd;
-	int r;
-
-	mutex_lock(&ip_data->lock);
-
-	hpd = gpio_get_value(ip_data->hpd_gpio);
+	struct hdmi_ip_data *ip_data = data;
+	void __iomem *wp_base = hdmi_wp_base(ip_data);
+	u32 irqstatus;
+
+	irqstatus = hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS);
+	hdmi_write_reg(wp_base, HDMI_WP_IRQSTATUS, irqstatus);
+	/* flush posted write */
+	hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS);
+
+	if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
+			irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
+		/*
+		 * If we get both connect and disconnect interrupts at the same
+		 * time, turn off the PHY, clear interrupts, and restart, which
+		 * raises connect interrupt if a cable is connected, or nothing
+		 * if cable is not connected.
+		 */
+		hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
 
-	if (hpd)
-		r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON);
-	else
-		r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON);
+		hdmi_write_reg(wp_base, HDMI_WP_IRQSTATUS,
+			HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
+		/* flush posted write */
+		hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS);
 
-	if (r) {
-		DSSERR("Failed to %s PHY TX power\n",
-				hpd ? "enable" : "disable");
-		goto err;
+		hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON);
+	} else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
+		hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON);
+	} else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
+		hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON);
 	}
 
-err:
-	mutex_unlock(&ip_data->lock);
-	return r;
-}
-
-static irqreturn_t hpd_irq_handler(int irq, void *data)
-{
-	struct hdmi_ip_data *ip_data = data;
-
-	hdmi_check_hpd_state(ip_data);
-
 	return IRQ_HANDLED;
 }
 
@@ -272,6 +277,12 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
 	u16 r = 0;
 	void __iomem *phy_base = hdmi_phy_base(ip_data);
 
+	hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQENABLE_CLR,
+			0xffffffff);
+
+	hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQSTATUS,
+			HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
+
 	r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON);
 	if (r)
 		return r;
@@ -297,29 +308,23 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
 	/* Write to phy address 3 to change the polarity control */
 	REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
 
-	r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio),
-				 NULL, hpd_irq_handler,
-				 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
-				 IRQF_ONESHOT, "hpd", ip_data);
+	r = request_threaded_irq(ip_data->irq, NULL, hdmi_irq_handler,
+				 IRQF_ONESHOT, "OMAP HDMI", ip_data);
 	if (r) {
-		DSSERR("HPD IRQ request failed\n");
+		DSSERR("HDMI IRQ request failed\n");
 		hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
 		return r;
 	}
 
-	r = hdmi_check_hpd_state(ip_data);
-	if (r) {
-		free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data);
-		hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
-		return r;
-	}
+	hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQENABLE_SET,
+			HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
 
 	return 0;
 }
 
 void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data)
 {
-	free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data);
+	free_irq(ip_data->irq, ip_data);
 
 	hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
 }
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
index 8366ae19e82ee..6ef2f929a76d7 100644
--- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
+++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
@@ -33,6 +33,7 @@
 #define HDMI_WP_IRQSTATUS			0x28
 #define HDMI_WP_PWR_CTRL			0x40
 #define HDMI_WP_IRQENABLE_SET			0x2C
+#define HDMI_WP_IRQENABLE_CLR			0x30
 #define HDMI_WP_VIDEO_CFG			0x50
 #define HDMI_WP_VIDEO_SIZE			0x60
 #define HDMI_WP_VIDEO_TIMING_H			0x68