OMAP: DSS2: Taal: Add proper external TE support

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>
This commit is contained in:
Jani Nikula 2010-04-13 10:57:52 +03:00 коммит произвёл Tomi Valkeinen
Родитель d2b6578738
Коммит 7ae2fb1192
1 изменённых файлов: 75 добавлений и 18 удалений

Просмотреть файл

@ -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 */