OMAP: DSS2: Taal: Add proper external TE support
authorJani Nikula <ext-jani.1.nikula@nokia.com>
Tue, 13 Apr 2010 07:57:52 +0000 (10:57 +0300)
committerTomi Valkeinen <tomi.valkeinen@nokia.com>
Tue, 3 Aug 2010 12:18:48 +0000 (15:18 +0300)
Add gpio irq based external TE support with timeout.

Signed-off-by: Jani Nikula <ext-jani.1.nikula@nokia.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
drivers/video/omap2/displays/panel-taal.c

index 2f89678..e52631e 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/fb.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
-#include <linux/completion.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
@@ -65,6 +64,8 @@
 /* #define TAAL_USE_ESD_CHECK */
 #define TAAL_ESD_CHECK_PERIOD  msecs_to_jiffies(5000)
 
+static irqreturn_t taal_te_isr(int irq, void *data);
+static void taal_te_timeout_work_callback(struct work_struct *work);
 static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
 
 struct taal_data {
@@ -85,7 +86,15 @@ struct taal_data {
 
        bool te_enabled;
        bool use_ext_te;
-       struct completion te_completion;
+
+       atomic_t do_update;
+       struct {
+               u16 x;
+               u16 y;
+               u16 w;
+               u16 h;
+       } update_region;
+       struct delayed_work te_timeout_work;
 
        bool use_dsi_bl;
 
@@ -346,16 +355,6 @@ static void taal_get_resolution(struct omap_dss_device *dssdev,
        }
 }
 
-static irqreturn_t taal_te_isr(int irq, void *data)
-{
-       struct omap_dss_device *dssdev = data;
-       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-
-       complete_all(&td->te_completion);
-
-       return IRQ_HANDLED;
-}
-
 static ssize_t taal_num_errors_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -545,6 +544,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
 
        mutex_init(&td->lock);
 
+       atomic_set(&td->do_update, 0);
+
        td->esd_wq = create_singlethread_workqueue("taal_esd");
        if (td->esd_wq == NULL) {
                dev_err(&dssdev->dev, "can't create ESD workqueue\n");
@@ -606,9 +607,12 @@ static int taal_probe(struct omap_dss_device *dssdev)
                        goto err_irq;
                }
 
-               init_completion(&td->te_completion);
+               INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work,
+                                       taal_te_timeout_work_callback);
 
                td->use_ext_te = true;
+
+               dev_dbg(&dssdev->dev, "Using GPIO TE\n");
        }
 
        r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
@@ -909,6 +913,47 @@ static void taal_framedone_cb(int err, void *data)
        dsi_bus_unlock();
 }
 
+static irqreturn_t taal_te_isr(int irq, void *data)
+{
+       struct omap_dss_device *dssdev = data;
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       int old;
+       int r;
+
+       old = atomic_cmpxchg(&td->do_update, 1, 0);
+
+       if (old) {
+               cancel_delayed_work(&td->te_timeout_work);
+
+               r = omap_dsi_update(dssdev, TCH,
+                               td->update_region.x,
+                               td->update_region.y,
+                               td->update_region.w,
+                               td->update_region.h,
+                               taal_framedone_cb, dssdev);
+               if (r)
+                       goto err;
+       }
+
+       return IRQ_HANDLED;
+err:
+       dev_err(&dssdev->dev, "start update failed\n");
+       dsi_bus_unlock();
+       return IRQ_HANDLED;
+}
+
+static void taal_te_timeout_work_callback(struct work_struct *work)
+{
+       struct taal_data *td = container_of(work, struct taal_data,
+                                       te_timeout_work.work);
+       struct omap_dss_device *dssdev = td->dssdev;
+
+       dev_err(&dssdev->dev, "TE not received for 250ms!\n");
+
+       atomic_set(&td->do_update, 0);
+       dsi_bus_unlock();
+}
+
 static int taal_update(struct omap_dss_device *dssdev,
                                    u16 x, u16 y, u16 w, u16 h)
 {
@@ -933,10 +978,21 @@ static int taal_update(struct omap_dss_device *dssdev,
        if (r)
                goto err;
 
-       r = omap_dsi_update(dssdev, TCH, x, y, w, h,
-                       taal_framedone_cb, dssdev);
-       if (r)
-               goto err;
+       if (td->te_enabled && td->use_ext_te) {
+               td->update_region.x = x;
+               td->update_region.y = y;
+               td->update_region.w = w;
+               td->update_region.h = h;
+               barrier();
+               schedule_delayed_work(&td->te_timeout_work,
+                               msecs_to_jiffies(250));
+               atomic_set(&td->do_update, 1);
+       } else {
+               r = omap_dsi_update(dssdev, TCH, x, y, w, h,
+                               taal_framedone_cb, dssdev);
+               if (r)
+                       goto err;
+       }
 
        /* note: no bus_unlock here. unlock is in framedone_cb */
        mutex_unlock(&td->lock);
@@ -972,7 +1028,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
        else
                r = taal_dcs_write_0(DCS_TEAR_OFF);
 
-       omapdss_dsi_enable_te(dssdev, enable);
+       if (!td->use_ext_te)
+               omapdss_dsi_enable_te(dssdev, enable);
 
        /* XXX for some reason, DSI TE breaks if we don't wait here.
         * Panel bug? Needs more studying */