#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>
/* #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 {
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;
}
}
-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)
{
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");
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);
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)
{
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);
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 */