aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i2c
diff options
context:
space:
mode:
authorJean-Francois Moine <moinejf@free.fr>2014-11-29 08:57:15 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-12-01 10:49:28 +0000
commit6833d26ef823b20acbf9d4afcfd7077e623b302c (patch)
tree748928ded0c600bed45b5567437444f23c255fde /drivers/gpu/drm/i2c
parented9a84262a83ab0260325c2f5eae39e441003d55 (diff)
drm: tda998x: Fix EDID read timeout on HDMI connect
When the HDMI cable is disconnected and reconnected, EDID reading is called too early raising a EDID read timeout. This patch uses the system work queue to delay the notification of the HDMI connect/disconnect event. Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/gpu/drm/i2c')
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 6795f094f737..98f3c4dd7375 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -33,6 +33,7 @@ struct tda998x_priv {
struct i2c_client *cec;
struct i2c_client *hdmi;
struct mutex mutex;
+ struct delayed_work dwork;
uint16_t rev;
uint8_t current_page;
int dpms;
@@ -549,6 +550,17 @@ tda998x_reset(struct tda998x_priv *priv)
reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24);
}
+/* handle HDMI connect/disconnect */
+static void tda998x_hpd(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct tda998x_priv *priv =
+ container_of(dwork, struct tda998x_priv, dwork);
+
+ if (priv->encoder && priv->encoder->dev)
+ drm_kms_helper_hotplug_event(priv->encoder->dev);
+}
+
/*
* only 2 interrupts may occur: screen plug/unplug and EDID read
*/
@@ -572,8 +584,7 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data)
priv->wq_edid_wait = 0;
wake_up(&priv->wq_edid);
} else if (cec != 0) { /* HPD change */
- if (priv->encoder && priv->encoder->dev)
- drm_helper_hpd_irq_event(priv->encoder->dev);
+ schedule_delayed_work(&priv->dwork, HZ/10);
}
return IRQ_HANDLED;
}
@@ -1183,8 +1194,10 @@ static void tda998x_destroy(struct tda998x_priv *priv)
/* disable all IRQs and free the IRQ handler */
cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
- if (priv->hdmi->irq)
+ if (priv->hdmi->irq) {
free_irq(priv->hdmi->irq, priv);
+ cancel_delayed_work_sync(&priv->dwork);
+ }
i2c_unregister_device(priv->cec);
}
@@ -1338,8 +1351,9 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
if (client->irq) {
int irqf_trigger;
- /* init read EDID waitqueue */
+ /* init read EDID waitqueue and HDP work */
init_waitqueue_head(&priv->wq_edid);
+ INIT_DELAYED_WORK(&priv->dwork, tda998x_hpd);
/* clear pending interrupts */
reg_read(priv, REG_INT_FLAGS_0);