aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2014-09-19 12:58:57 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2015-02-04 05:32:04 -0500
commita87a6d6b09de3118e5679c2057b99b7791b7673b (patch)
tree669887b685004b13504cde0e768be5f8844330fd /drivers/video
parentfa0c52ab232656d5a730eba73b5e37c70acb78db (diff)
OMAPDSS: encoder-tpd12s015: Fix race issue with LS_OE
A race issue has been observed with the encoder-tpd12s015 driver, which leads to errors when trying to read EDID. This has only now been observed, as OMAP4 and OMAP5 boards used SoC's GPIOs for LS_OE GPIO. On dra7-evm boards, the LS_OE is behind a i2c controlled GPIO expander, which increases the time to set the LS_OE. This patch simplifies the handling of the LS_OE gpio in the driver by removing the interrupt handling totally. The only time we actually need to enable LS_OE is when we are reading the EDID, and thus we can just set and clear the LS_OE gpio inside the read_edid() function. This also has the additional benefit of very slightly decreasing the power consumption. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c57
1 files changed, 10 insertions, 47 deletions
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
index 7f3e11b16c86..990af6baeb0f 100644
--- a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
+++ b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
@@ -29,33 +29,10 @@ struct panel_drv_data {
29 int hpd_gpio; 29 int hpd_gpio;
30 30
31 struct omap_video_timings timings; 31 struct omap_video_timings timings;
32
33 struct completion hpd_completion;
34}; 32};
35 33
36#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) 34#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
37 35
38static irqreturn_t tpd_hpd_irq_handler(int irq, void *data)
39{
40 struct panel_drv_data *ddata = data;
41 bool hpd;
42
43 hpd = gpio_get_value_cansleep(ddata->hpd_gpio);
44
45 dev_dbg(ddata->dssdev.dev, "hpd %d\n", hpd);
46
47 if (gpio_is_valid(ddata->ls_oe_gpio)) {
48 if (hpd)
49 gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
50 else
51 gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
52 }
53
54 complete_all(&ddata->hpd_completion);
55
56 return IRQ_HANDLED;
57}
58
59static int tpd_connect(struct omap_dss_device *dssdev, 36static int tpd_connect(struct omap_dss_device *dssdev,
60 struct omap_dss_device *dst) 37 struct omap_dss_device *dst)
61{ 38{
@@ -70,23 +47,10 @@ static int tpd_connect(struct omap_dss_device *dssdev,
70 dst->src = dssdev; 47 dst->src = dssdev;
71 dssdev->dst = dst; 48 dssdev->dst = dst;
72 49
73 reinit_completion(&ddata->hpd_completion);
74
75 gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1); 50 gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
76 /* DC-DC converter needs at max 300us to get to 90% of 5V */ 51 /* DC-DC converter needs at max 300us to get to 90% of 5V */
77 udelay(300); 52 udelay(300);
78 53
79 /*
80 * If there's a cable connected, wait for the hpd irq to trigger,
81 * which turns on the level shifters.
82 */
83 if (gpio_get_value_cansleep(ddata->hpd_gpio)) {
84 unsigned long to;
85 to = wait_for_completion_timeout(&ddata->hpd_completion,
86 msecs_to_jiffies(250));
87 WARN_ON_ONCE(to == 0);
88 }
89
90 return 0; 54 return 0;
91} 55}
92 56
@@ -179,11 +143,20 @@ static int tpd_read_edid(struct omap_dss_device *dssdev,
179{ 143{
180 struct panel_drv_data *ddata = to_panel_data(dssdev); 144 struct panel_drv_data *ddata = to_panel_data(dssdev);
181 struct omap_dss_device *in = ddata->in; 145 struct omap_dss_device *in = ddata->in;
146 int r;
182 147
183 if (!gpio_get_value_cansleep(ddata->hpd_gpio)) 148 if (!gpio_get_value_cansleep(ddata->hpd_gpio))
184 return -ENODEV; 149 return -ENODEV;
185 150
186 return in->ops.hdmi->read_edid(in, edid, len); 151 if (gpio_is_valid(ddata->ls_oe_gpio))
152 gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
153
154 r = in->ops.hdmi->read_edid(in, edid, len);
155
156 if (gpio_is_valid(ddata->ls_oe_gpio))
157 gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
158
159 return r;
187} 160}
188 161
189static bool tpd_detect(struct omap_dss_device *dssdev) 162static bool tpd_detect(struct omap_dss_device *dssdev)
@@ -309,8 +282,6 @@ static int tpd_probe(struct platform_device *pdev)
309 282
310 platform_set_drvdata(pdev, ddata); 283 platform_set_drvdata(pdev, ddata);
311 284
312 init_completion(&ddata->hpd_completion);
313
314 if (dev_get_platdata(&pdev->dev)) { 285 if (dev_get_platdata(&pdev->dev)) {
315 r = tpd_probe_pdata(pdev); 286 r = tpd_probe_pdata(pdev);
316 if (r) 287 if (r)
@@ -340,13 +311,6 @@ static int tpd_probe(struct platform_device *pdev)
340 if (r) 311 if (r)
341 goto err_gpio; 312 goto err_gpio;
342 313
343 r = devm_request_threaded_irq(&pdev->dev, gpio_to_irq(ddata->hpd_gpio),
344 NULL, tpd_hpd_irq_handler,
345 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
346 IRQF_ONESHOT, "hpd", ddata);
347 if (r)
348 goto err_irq;
349
350 dssdev = &ddata->dssdev; 314 dssdev = &ddata->dssdev;
351 dssdev->ops.hdmi = &tpd_hdmi_ops; 315 dssdev->ops.hdmi = &tpd_hdmi_ops;
352 dssdev->dev = &pdev->dev; 316 dssdev->dev = &pdev->dev;
@@ -365,7 +329,6 @@ static int tpd_probe(struct platform_device *pdev)
365 329
366 return 0; 330 return 0;
367err_reg: 331err_reg:
368err_irq:
369err_gpio: 332err_gpio:
370 omap_dss_put_device(ddata->in); 333 omap_dss_put_device(ddata->in);
371 return r; 334 return r;