diff options
author | Jean-Francois Moine <moinejf@free.fr> | 2014-11-29 02:57:15 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-12-01 05:49:28 -0500 |
commit | 6833d26ef823b20acbf9d4afcfd7077e623b302c (patch) | |
tree | 748928ded0c600bed45b5567437444f23c255fde /drivers/gpu/drm/i2c | |
parent | ed9a84262a83ab0260325c2f5eae39e441003d55 (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.c | 22 |
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 { | |||
33 | struct i2c_client *cec; | 33 | struct i2c_client *cec; |
34 | struct i2c_client *hdmi; | 34 | struct i2c_client *hdmi; |
35 | struct mutex mutex; | 35 | struct mutex mutex; |
36 | struct delayed_work dwork; | ||
36 | uint16_t rev; | 37 | uint16_t rev; |
37 | uint8_t current_page; | 38 | uint8_t current_page; |
38 | int dpms; | 39 | int dpms; |
@@ -549,6 +550,17 @@ tda998x_reset(struct tda998x_priv *priv) | |||
549 | reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); | 550 | reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); |
550 | } | 551 | } |
551 | 552 | ||
553 | /* handle HDMI connect/disconnect */ | ||
554 | static void tda998x_hpd(struct work_struct *work) | ||
555 | { | ||
556 | struct delayed_work *dwork = to_delayed_work(work); | ||
557 | struct tda998x_priv *priv = | ||
558 | container_of(dwork, struct tda998x_priv, dwork); | ||
559 | |||
560 | if (priv->encoder && priv->encoder->dev) | ||
561 | drm_kms_helper_hotplug_event(priv->encoder->dev); | ||
562 | } | ||
563 | |||
552 | /* | 564 | /* |
553 | * only 2 interrupts may occur: screen plug/unplug and EDID read | 565 | * only 2 interrupts may occur: screen plug/unplug and EDID read |
554 | */ | 566 | */ |
@@ -572,8 +584,7 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data) | |||
572 | priv->wq_edid_wait = 0; | 584 | priv->wq_edid_wait = 0; |
573 | wake_up(&priv->wq_edid); | 585 | wake_up(&priv->wq_edid); |
574 | } else if (cec != 0) { /* HPD change */ | 586 | } else if (cec != 0) { /* HPD change */ |
575 | if (priv->encoder && priv->encoder->dev) | 587 | schedule_delayed_work(&priv->dwork, HZ/10); |
576 | drm_helper_hpd_irq_event(priv->encoder->dev); | ||
577 | } | 588 | } |
578 | return IRQ_HANDLED; | 589 | return IRQ_HANDLED; |
579 | } | 590 | } |
@@ -1183,8 +1194,10 @@ static void tda998x_destroy(struct tda998x_priv *priv) | |||
1183 | /* disable all IRQs and free the IRQ handler */ | 1194 | /* disable all IRQs and free the IRQ handler */ |
1184 | cec_write(priv, REG_CEC_RXSHPDINTENA, 0); | 1195 | cec_write(priv, REG_CEC_RXSHPDINTENA, 0); |
1185 | reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); | 1196 | reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); |
1186 | if (priv->hdmi->irq) | 1197 | if (priv->hdmi->irq) { |
1187 | free_irq(priv->hdmi->irq, priv); | 1198 | free_irq(priv->hdmi->irq, priv); |
1199 | cancel_delayed_work_sync(&priv->dwork); | ||
1200 | } | ||
1188 | 1201 | ||
1189 | i2c_unregister_device(priv->cec); | 1202 | i2c_unregister_device(priv->cec); |
1190 | } | 1203 | } |
@@ -1338,8 +1351,9 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) | |||
1338 | if (client->irq) { | 1351 | if (client->irq) { |
1339 | int irqf_trigger; | 1352 | int irqf_trigger; |
1340 | 1353 | ||
1341 | /* init read EDID waitqueue */ | 1354 | /* init read EDID waitqueue and HDP work */ |
1342 | init_waitqueue_head(&priv->wq_edid); | 1355 | init_waitqueue_head(&priv->wq_edid); |
1356 | INIT_DELAYED_WORK(&priv->dwork, tda998x_hpd); | ||
1343 | 1357 | ||
1344 | /* clear pending interrupts */ | 1358 | /* clear pending interrupts */ |
1345 | reg_read(priv, REG_INT_FLAGS_0); | 1359 | reg_read(priv, REG_INT_FLAGS_0); |