aboutsummaryrefslogtreecommitdiff
path: root/drivers/video/omap2/displays/panel-taal.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/displays/panel-taal.c')
-rw-r--r--drivers/video/omap2/displays/panel-taal.c567
1 files changed, 447 insertions, 120 deletions
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index aaf5d308a04..e1c765d1141 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -28,12 +28,13 @@
#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/regulator/consumer.h>
#include <linux/mutex.h>
#include <plat/display.h>
+#include <plat/nokia-dsi-panel.h>
/* DSI Virtual channel. Hardcoded for now. */
#define TCH 0
@@ -62,11 +63,136 @@
#define DCS_GET_ID2 0xdb
#define DCS_GET_ID3 0xdc
-/* #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 panel_regulator {
+ struct regulator *regulator;
+ const char *name;
+ int min_uV;
+ int max_uV;
+};
+
+static void free_regulators(struct panel_regulator *regulators, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ /* disable/put in reverse order */
+ regulator_disable(regulators[n - i - 1].regulator);
+ regulator_put(regulators[n - i - 1].regulator);
+ }
+}
+
+static int init_regulators(struct omap_dss_device *dssdev,
+ struct panel_regulator *regulators, int n)
+{
+ int r, i, v;
+
+ for (i = 0; i < n; i++) {
+ struct regulator *reg;
+
+ reg = regulator_get(&dssdev->dev, regulators[i].name);
+ if (IS_ERR(reg)) {
+ dev_err(&dssdev->dev, "failed to get regulator %s\n",
+ regulators[i].name);
+ r = PTR_ERR(reg);
+ goto err;
+ }
+
+ /* FIXME: better handling of fixed vs. variable regulators */
+ v = regulator_get_voltage(reg);
+ if (v < regulators[i].min_uV || v > regulators[i].max_uV) {
+ r = regulator_set_voltage(reg, regulators[i].min_uV,
+ regulators[i].max_uV);
+ if (r) {
+ dev_err(&dssdev->dev,
+ "failed to set regulator %s voltage\n",
+ regulators[i].name);
+ regulator_put(reg);
+ goto err;
+ }
+ }
+
+ r = regulator_enable(reg);
+ if (r) {
+ dev_err(&dssdev->dev, "failed to enable regulator %s\n",
+ regulators[i].name);
+ regulator_put(reg);
+ goto err;
+ }
+
+ regulators[i].regulator = reg;
+ }
+
+ return 0;
+
+err:
+ free_regulators(regulators, i);
+
+ return r;
+}
+
+/**
+ * struct panel_config - panel configuration
+ * @name: panel name
+ * @type: panel type
+ * @timings: panel resolution
+ * @sleep: various panel specific delays, passed to msleep() if non-zero
+ * @reset_sequence: reset sequence timings, passed to udelay() if non-zero
+ * @regulators: array of panel regulators
+ * @num_regulators: number of regulators in the array
+ */
+struct panel_config {
+ const char *name;
+ int type;
+
+ struct omap_video_timings timings;
+
+ struct {
+ unsigned int sleep_in;
+ unsigned int sleep_out;
+ unsigned int hw_reset;
+ unsigned int enable_te;
+ } sleep;
+
+ struct {
+ unsigned int high;
+ unsigned int low;
+ } reset_sequence;
+
+ struct panel_regulator *regulators;
+ int num_regulators;
+};
+
+enum {
+ PANEL_TAAL,
+};
+
+static struct panel_config panel_configs[] = {
+ {
+ .name = "taal",
+ .type = PANEL_TAAL,
+ .timings = {
+ .x_res = 864,
+ .y_res = 480,
+ },
+ .sleep = {
+ .sleep_in = 5,
+ .sleep_out = 5,
+ .hw_reset = 5,
+ .enable_te = 100, /* possible panel bug */
+ },
+ .reset_sequence = {
+ .high = 10,
+ .low = 10,
+ },
+ },
+};
+
struct taal_data {
struct mutex lock;
@@ -84,8 +210,15 @@ struct taal_data {
bool mirror;
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;
@@ -96,8 +229,16 @@ struct taal_data {
struct workqueue_struct *esd_wq;
struct delayed_work esd_work;
+
+ struct panel_config *panel_config;
};
+static inline struct nokia_dsi_panel_data
+*get_panel_data(const struct omap_dss_device *dssdev)
+{
+ return (struct nokia_dsi_panel_data *) dssdev->data;
+}
+
static void taal_esd_work(struct work_struct *work);
static void hw_guard_start(struct taal_data *td, int guard_msec)
@@ -159,7 +300,8 @@ static int taal_sleep_in(struct taal_data *td)
hw_guard_start(td, 120);
- msleep(5);
+ if (td->panel_config->sleep.sleep_in)
+ msleep(td->panel_config->sleep.sleep_in);
return 0;
}
@@ -176,7 +318,8 @@ static int taal_sleep_out(struct taal_data *td)
hw_guard_start(td, 120);
- msleep(5);
+ if (td->panel_config->sleep.sleep_out)
+ msleep(td->panel_config->sleep.sleep_out);
return 0;
}
@@ -279,6 +422,7 @@ static int taal_bl_update_status(struct backlight_device *dev)
{
struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
int level;
@@ -290,24 +434,26 @@ static int taal_bl_update_status(struct backlight_device *dev)
dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
+ mutex_lock(&td->lock);
+
if (td->use_dsi_bl) {
if (td->enabled) {
dsi_bus_lock();
r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
dsi_bus_unlock();
- if (r)
- return r;
+ } else {
+ r = 0;
}
} else {
- if (!dssdev->set_backlight)
- return -EINVAL;
-
- r = dssdev->set_backlight(dssdev, level);
- if (r)
- return r;
+ if (!panel_data->set_backlight)
+ r = -EINVAL;
+ else
+ r = panel_data->set_backlight(dssdev, level);
}
- return 0;
+ mutex_unlock(&td->lock);
+
+ return r;
}
static int taal_bl_get_intensity(struct backlight_device *dev)
@@ -344,16 +490,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)
{
@@ -362,6 +498,8 @@ static ssize_t taal_num_errors_show(struct device *dev,
u8 errors;
int r;
+ mutex_lock(&td->lock);
+
if (td->enabled) {
dsi_bus_lock();
r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
@@ -370,6 +508,8 @@ static ssize_t taal_num_errors_show(struct device *dev,
r = -ENODEV;
}
+ mutex_unlock(&td->lock);
+
if (r)
return r;
@@ -384,6 +524,8 @@ static ssize_t taal_hw_revision_show(struct device *dev,
u8 id1, id2, id3;
int r;
+ mutex_lock(&td->lock);
+
if (td->enabled) {
dsi_bus_lock();
r = taal_get_id(&id1, &id2, &id3);
@@ -392,6 +534,8 @@ static ssize_t taal_hw_revision_show(struct device *dev,
r = -ENODEV;
}
+ mutex_unlock(&td->lock);
+
if (r)
return r;
@@ -441,6 +585,8 @@ static ssize_t store_cabc_mode(struct device *dev,
if (i == ARRAY_SIZE(cabc_modes))
return -EINVAL;
+ mutex_lock(&td->lock);
+
if (td->enabled) {
dsi_bus_lock();
if (!td->cabc_broken)
@@ -450,6 +596,8 @@ static ssize_t store_cabc_mode(struct device *dev,
td->cabc_mode = i;
+ mutex_unlock(&td->lock);
+
return count;
}
@@ -488,47 +636,93 @@ static struct attribute_group taal_attr_group = {
.attrs = taal_attrs,
};
+static void taal_hw_reset(struct omap_dss_device *dssdev)
+{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+
+ if (panel_data->reset_gpio == -1)
+ return;
+
+ gpio_set_value(panel_data->reset_gpio, 1);
+ if (td->panel_config->reset_sequence.high)
+ udelay(td->panel_config->reset_sequence.high);
+ /* reset the panel */
+ gpio_set_value(panel_data->reset_gpio, 0);
+ /* assert reset */
+ if (td->panel_config->reset_sequence.low)
+ udelay(td->panel_config->reset_sequence.low);
+ gpio_set_value(panel_data->reset_gpio, 1);
+ /* wait after releasing reset */
+ if (td->panel_config->sleep.hw_reset)
+ msleep(td->panel_config->sleep.hw_reset);
+}
+
static int taal_probe(struct omap_dss_device *dssdev)
{
struct backlight_properties props;
struct taal_data *td;
struct backlight_device *bldev;
- int r;
-
- const struct omap_video_timings taal_panel_timings = {
- .x_res = 864,
- .y_res = 480,
- };
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+ struct panel_config *panel_config = NULL;
+ int r, i;
dev_dbg(&dssdev->dev, "probe\n");
+ if (!panel_data || !panel_data->name) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(panel_configs); i++) {
+ if (strcmp(panel_data->name, panel_configs[i].name) == 0) {
+ panel_config = &panel_configs[i];
+ break;
+ }
+ }
+
+ if (!panel_config) {
+ r = -EINVAL;
+ goto err;
+ }
+
dssdev->panel.config = OMAP_DSS_LCD_TFT;
- dssdev->panel.timings = taal_panel_timings;
+ dssdev->panel.timings = panel_config->timings;
dssdev->ctrl.pixel_size = 24;
td = kzalloc(sizeof(*td), GFP_KERNEL);
if (!td) {
r = -ENOMEM;
- goto err0;
+ goto err;
}
td->dssdev = dssdev;
+ td->panel_config = panel_config;
mutex_init(&td->lock);
+ atomic_set(&td->do_update, 0);
+
+ r = init_regulators(dssdev, panel_config->regulators,
+ panel_config->num_regulators);
+ if (r)
+ goto err_reg;
+
td->esd_wq = create_singlethread_workqueue("taal_esd");
if (td->esd_wq == NULL) {
dev_err(&dssdev->dev, "can't create ESD workqueue\n");
r = -ENOMEM;
- goto err1;
+ goto err_wq;
}
INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
dev_set_drvdata(&dssdev->dev, td);
+ taal_hw_reset(dssdev);
+
/* if no platform set_backlight() defined, presume DSI backlight
* control */
memset(&props, 0, sizeof(struct backlight_properties));
- if (!dssdev->set_backlight)
+ if (!panel_data->set_backlight)
td->use_dsi_bl = true;
if (td->use_dsi_bl)
@@ -539,7 +733,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
&taal_bl_ops, &props);
if (IS_ERR(bldev)) {
r = PTR_ERR(bldev);
- goto err2;
+ goto err_bl;
}
td->bldev = bldev;
@@ -553,13 +747,13 @@ static int taal_probe(struct omap_dss_device *dssdev)
taal_bl_update_status(bldev);
- if (dssdev->phy.dsi.ext_te) {
- int gpio = dssdev->phy.dsi.ext_te_gpio;
+ if (panel_data->use_ext_te) {
+ int gpio = panel_data->ext_te_gpio;
r = gpio_request(gpio, "taal irq");
if (r) {
dev_err(&dssdev->dev, "GPIO request failed\n");
- goto err3;
+ goto err_gpio;
}
gpio_direction_input(gpio);
@@ -571,49 +765,52 @@ static int taal_probe(struct omap_dss_device *dssdev)
if (r) {
dev_err(&dssdev->dev, "IRQ request failed\n");
gpio_free(gpio);
- goto err3;
+ 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);
if (r) {
dev_err(&dssdev->dev, "failed to create sysfs files\n");
- goto err4;
+ goto err_sysfs;
}
return 0;
-err4:
- if (td->use_ext_te) {
- int gpio = dssdev->phy.dsi.ext_te_gpio;
- free_irq(gpio_to_irq(gpio), dssdev);
- gpio_free(gpio);
- }
-err3:
+err_sysfs:
+ if (panel_data->use_ext_te)
+ free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev);
+err_irq:
+ if (panel_data->use_ext_te)
+ gpio_free(panel_data->ext_te_gpio);
+err_gpio:
backlight_device_unregister(bldev);
-err2:
- cancel_delayed_work_sync(&td->esd_work);
+err_bl:
destroy_workqueue(td->esd_wq);
-err1:
+err_wq:
+ free_regulators(panel_config->regulators, panel_config->num_regulators);
+err_reg:
kfree(td);
-err0:
+err:
return r;
}
static void taal_remove(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
struct backlight_device *bldev;
dev_dbg(&dssdev->dev, "remove\n");
sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
- if (td->use_ext_te) {
- int gpio = dssdev->phy.dsi.ext_te_gpio;
+ if (panel_data->use_ext_te) {
+ int gpio = panel_data->ext_te_gpio;
free_irq(gpio_to_irq(gpio), dssdev);
gpio_free(gpio);
}
@@ -623,9 +820,15 @@ static void taal_remove(struct omap_dss_device *dssdev)
taal_bl_update_status(bldev);
backlight_device_unregister(bldev);
- cancel_delayed_work_sync(&td->esd_work);
+ cancel_delayed_work(&td->esd_work);
destroy_workqueue(td->esd_wq);
+ /* reset, to be sure that the panel is in a valid state */
+ taal_hw_reset(dssdev);
+
+ free_regulators(td->panel_config->regulators,
+ td->panel_config->num_regulators);
+
kfree(td);
}
@@ -635,23 +838,14 @@ static int taal_power_on(struct omap_dss_device *dssdev)
u8 id1, id2, id3;
int r;
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- return r;
- }
-
- /* it seems we have to wait a bit until taal is ready */
- msleep(5);
-
- dsi_bus_lock();
-
r = omapdss_dsi_display_enable(dssdev);
if (r) {
dev_err(&dssdev->dev, "failed to enable DSI\n");
goto err0;
}
+ taal_hw_reset(dssdev);
+
omapdss_dsi_vc_enable_hs(TCH, false);
r = taal_sleep_out(td);
@@ -662,34 +856,47 @@ static int taal_power_on(struct omap_dss_device *dssdev)
if (r)
goto err;
- /* on early revisions CABC is broken */
- if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
+ /* on early Taal revisions CABC is broken */
+ if (td->panel_config->type == PANEL_TAAL &&
+ (id2 == 0x00 || id2 == 0xff || id2 == 0x81))
td->cabc_broken = true;
- taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
- taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */
+ r = taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
+ if (r)
+ goto err;
+
+ r = taal_dcs_write_1(DCS_CTRL_DISPLAY,
+ (1<<2) | (1<<5)); /* BL | BCTRL */
+ if (r)
+ goto err;
+
+ r = taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
+ if (r)
+ goto err;
- taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
+ r = taal_set_addr_mode(td->rotate, td->mirror);
+ if (r)
+ goto err;
- taal_set_addr_mode(td->rotate, td->mirror);
- if (!td->cabc_broken)
- taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
+ if (!td->cabc_broken) {
+ r = taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
+ if (r)
+ goto err;
+ }
- taal_dcs_write_0(DCS_DISPLAY_ON);
+ r = taal_dcs_write_0(DCS_DISPLAY_ON);
+ if (r)
+ goto err;
r = _taal_enable_te(dssdev, td->te_enabled);
if (r)
goto err;
-#ifdef TAAL_USE_ESD_CHECK
- queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
-#endif
-
td->enabled = 1;
if (!td->intro_printed) {
- dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n",
- id1, id2, id3);
+ dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n",
+ td->panel_config->name, id1, id2, id3);
if (td->cabc_broken)
dev_info(&dssdev->dev,
"old Taal version, CABC disabled\n");
@@ -698,46 +905,44 @@ static int taal_power_on(struct omap_dss_device *dssdev)
omapdss_dsi_vc_enable_hs(TCH, true);
- dsi_bus_unlock();
-
return 0;
err:
+ dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n");
+
+ taal_hw_reset(dssdev);
+
omapdss_dsi_display_disable(dssdev);
err0:
- dsi_bus_unlock();
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
return r;
}
static void taal_power_off(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ int r;
- dsi_bus_lock();
-
- cancel_delayed_work(&td->esd_work);
-
- taal_dcs_write_0(DCS_DISPLAY_OFF);
- taal_sleep_in(td);
+ r = taal_dcs_write_0(DCS_DISPLAY_OFF);
+ if (!r) {
+ r = taal_sleep_in(td);
+ /* HACK: wait a bit so that the message goes through */
+ msleep(10);
+ }
- /* wait a bit so that the message goes through */
- msleep(10);
+ if (r) {
+ dev_err(&dssdev->dev,
+ "error disabling panel, issuing HW reset\n");
+ taal_hw_reset(dssdev);
+ }
omapdss_dsi_display_disable(dssdev);
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
td->enabled = 0;
-
- dsi_bus_unlock();
}
static int taal_enable(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
dev_dbg(&dssdev->dev, "enable\n");
@@ -749,10 +954,19 @@ static int taal_enable(struct omap_dss_device *dssdev)
goto err;
}
+ dsi_bus_lock();
+
r = taal_power_on(dssdev);
+
+ dsi_bus_unlock();
+
if (r)
goto err;
+ if (panel_data->use_esd_check)
+ queue_delayed_work(td->esd_wq, &td->esd_work,
+ TAAL_ESD_CHECK_PERIOD);
+
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
mutex_unlock(&td->lock);
@@ -772,9 +986,15 @@ static void taal_disable(struct omap_dss_device *dssdev)
mutex_lock(&td->lock);
+ cancel_delayed_work(&td->esd_work);
+
+ dsi_bus_lock();
+
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
taal_power_off(dssdev);
+ dsi_bus_unlock();
+
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
mutex_unlock(&td->lock);
@@ -794,7 +1014,14 @@ static int taal_suspend(struct omap_dss_device *dssdev)
goto err;
}
+ cancel_delayed_work(&td->esd_work);
+
+ dsi_bus_lock();
+
taal_power_off(dssdev);
+
+ dsi_bus_unlock();
+
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
mutex_unlock(&td->lock);
@@ -808,6 +1035,7 @@ err:
static int taal_resume(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
dev_dbg(&dssdev->dev, "resume\n");
@@ -819,8 +1047,20 @@ static int taal_resume(struct omap_dss_device *dssdev)
goto err;
}
+ dsi_bus_lock();
+
r = taal_power_on(dssdev);
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ dsi_bus_unlock();
+
+ if (r) {
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+ } else {
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ if (panel_data->use_esd_check)
+ queue_delayed_work(td->esd_wq, &td->esd_work,
+ TAAL_ESD_CHECK_PERIOD);
+ }
mutex_unlock(&td->lock);
@@ -837,10 +1077,52 @@ 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)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
@@ -853,7 +1135,7 @@ static int taal_update(struct omap_dss_device *dssdev,
goto err;
}
- r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h);
+ r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true);
if (r)
goto err;
@@ -861,10 +1143,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 && panel_data->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);
@@ -894,20 +1187,19 @@ static int taal_sync(struct omap_dss_device *dssdev)
static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
- td->te_enabled = enable;
-
if (enable)
r = taal_dcs_write_1(DCS_TEAR_ON, 0);
else
r = taal_dcs_write_0(DCS_TEAR_OFF);
- omapdss_dsi_enable_te(dssdev, enable);
+ if (!panel_data->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 */
- msleep(100);
+ if (td->panel_config->sleep.enable_te)
+ msleep(td->panel_config->sleep.enable_te);
return r;
}
@@ -918,10 +1210,26 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
int r;
mutex_lock(&td->lock);
+
+ if (td->te_enabled == enable)
+ goto end;
+
dsi_bus_lock();
- r = _taal_enable_te(dssdev, enable);
+ if (td->enabled) {
+ r = _taal_enable_te(dssdev, enable);
+ if (r)
+ goto err;
+ }
+
+ td->te_enabled = enable;
+
+ dsi_bus_unlock();
+end:
+ mutex_unlock(&td->lock);
+ return 0;
+err:
dsi_bus_unlock();
mutex_unlock(&td->lock);
@@ -948,6 +1256,10 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
mutex_lock(&td->lock);
+
+ if (td->rotate == rotate)
+ goto end;
+
dsi_bus_lock();
if (td->enabled) {
@@ -959,6 +1271,7 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
td->rotate = rotate;
dsi_bus_unlock();
+end:
mutex_unlock(&td->lock);
return 0;
err:
@@ -987,6 +1300,10 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
dev_dbg(&dssdev->dev, "mirror %d\n", enable);
mutex_lock(&td->lock);
+
+ if (td->mirror == enable)
+ goto end;
+
dsi_bus_lock();
if (td->enabled) {
r = taal_set_addr_mode(td->rotate, enable);
@@ -997,6 +1314,7 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
td->mirror = enable;
dsi_bus_unlock();
+end:
mutex_unlock(&td->lock);
return 0;
err:
@@ -1024,23 +1342,30 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
int r;
mutex_lock(&td->lock);
+
+ if (!td->enabled) {
+ r = -ENODEV;
+ goto err1;
+ }
+
dsi_bus_lock();
r = taal_dcs_read_1(DCS_GET_ID1, &id1);
if (r)
- goto err;
+ goto err2;
r = taal_dcs_read_1(DCS_GET_ID2, &id2);
if (r)
- goto err;
+ goto err2;
r = taal_dcs_read_1(DCS_GET_ID3, &id3);
if (r)
- goto err;
+ goto err2;
dsi_bus_unlock();
mutex_unlock(&td->lock);
return 0;
-err:
+err2:
dsi_bus_unlock();
+err1:
mutex_unlock(&td->lock);
return r;
}
@@ -1128,6 +1453,7 @@ static void taal_esd_work(struct work_struct *work)
struct taal_data *td = container_of(work, struct taal_data,
esd_work.work);
struct omap_dss_device *dssdev = td->dssdev;
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
u8 state1, state2;
int r;
@@ -1168,7 +1494,7 @@ static void taal_esd_work(struct work_struct *work)
}
/* Self-diagnostics result is also shown on TE GPIO line. We need
* to re-enable TE after self diagnostics */
- if (td->use_ext_te && td->te_enabled) {
+ if (td->te_enabled && panel_data->use_ext_te) {
r = taal_dcs_write_1(DCS_TEAR_ON, 0);
if (r)
goto err;
@@ -1184,6 +1510,7 @@ err:
dev_err(&dssdev->dev, "performing LCD reset\n");
taal_power_off(dssdev);
+ taal_hw_reset(dssdev);
taal_power_on(dssdev);
dsi_bus_unlock();