diff options
Diffstat (limited to 'recipes/linux/linux-omap-2.6.31/dss2/0017-OMAP-DSS2-Taal-DSI-command-mode-panel-driver.patch')
-rw-r--r-- | recipes/linux/linux-omap-2.6.31/dss2/0017-OMAP-DSS2-Taal-DSI-command-mode-panel-driver.patch | 947 |
1 files changed, 947 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-2.6.31/dss2/0017-OMAP-DSS2-Taal-DSI-command-mode-panel-driver.patch b/recipes/linux/linux-omap-2.6.31/dss2/0017-OMAP-DSS2-Taal-DSI-command-mode-panel-driver.patch new file mode 100644 index 0000000000..c58ce9d36b --- /dev/null +++ b/recipes/linux/linux-omap-2.6.31/dss2/0017-OMAP-DSS2-Taal-DSI-command-mode-panel-driver.patch @@ -0,0 +1,947 @@ +From fc8cd50c04b519f3839e9dc505532e725c7af080 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen <tomi.valkeinen@nokia.com> +Date: Fri, 7 Aug 2009 14:45:05 +0300 +Subject: [PATCH 17/18] OMAP: DSS2: Taal DSI command mode panel driver + +Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com> +--- + drivers/video/omap2/displays/Kconfig | 6 + + drivers/video/omap2/displays/Makefile | 2 + + drivers/video/omap2/displays/panel-taal.c | 900 +++++++++++++++++++++++++++++ + 3 files changed, 908 insertions(+), 0 deletions(-) + create mode 100644 drivers/video/omap2/displays/panel-taal.c + +diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig +index 396905d..79d2861 100644 +--- a/drivers/video/omap2/displays/Kconfig ++++ b/drivers/video/omap2/displays/Kconfig +@@ -19,4 +19,10 @@ config PANEL_SHARP_LS037V7DW01 + help + LCD Panel used in TI's SDP3430 and EVM boards + ++config PANEL_TAAL ++ tristate "Taal DSI Panel" ++ depends on OMAP2_DSS_DSI ++ help ++ Taal DSI command mode panel from TPO. ++ + endmenu +diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile +index a26bbd2..d44e765 100644 +--- a/drivers/video/omap2/displays/Makefile ++++ b/drivers/video/omap2/displays/Makefile +@@ -1,3 +1,5 @@ + obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o + obj-$(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C) += panel-samsung-lte430wq-f0c.o + obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o ++ ++obj-$(CONFIG_PANEL_TAAL) += panel-taal.o +diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c +new file mode 100644 +index 0000000..84f0d47 +--- /dev/null ++++ b/drivers/video/omap2/displays/panel-taal.c +@@ -0,0 +1,900 @@ ++/* ++ * Taal DSI command mode panel ++ * ++ * Copyright (C) 2009 Nokia Corporation ++ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++/*#define DEBUG*/ ++ ++#include <linux/module.h> ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/jiffies.h> ++#include <linux/sched.h> ++#include <linux/backlight.h> ++#include <linux/fb.h> ++#include <linux/interrupt.h> ++#include <linux/gpio.h> ++#include <linux/completion.h> ++ ++#include <mach/display.h> ++ ++/* DSI Virtual channel. Hardcoded for now. */ ++#define TCH 0 ++ ++#define DCS_READ_NUM_ERRORS 0x05 ++#define DCS_READ_POWER_MODE 0x0a ++#define DCS_READ_MADCTL 0x0b ++#define DCS_READ_PIXEL_FORMAT 0x0c ++#define DCS_SLEEP_IN 0x10 ++#define DCS_SLEEP_OUT 0x11 ++#define DCS_DISPLAY_OFF 0x28 ++#define DCS_DISPLAY_ON 0x29 ++#define DCS_COLUMN_ADDR 0x2a ++#define DCS_PAGE_ADDR 0x2b ++#define DCS_MEMORY_WRITE 0x2c ++#define DCS_TEAR_OFF 0x34 ++#define DCS_TEAR_ON 0x35 ++#define DCS_MEM_ACC_CTRL 0x36 ++#define DCS_PIXEL_FORMAT 0x3a ++#define DCS_BRIGHTNESS 0x51 ++#define DCS_CTRL_DISPLAY 0x53 ++#define DCS_WRITE_CABC 0x55 ++#define DCS_READ_CABC 0x56 ++#define DCS_GET_ID1 0xda ++#define DCS_GET_ID2 0xdb ++#define DCS_GET_ID3 0xdc ++ ++struct taal_data { ++ struct backlight_device *bldev; ++ ++ unsigned long hw_guard_end; /* next value of jiffies when we can ++ * issue the next sleep in/out command ++ */ ++ unsigned long hw_guard_wait; /* max guard time in jiffies */ ++ ++ struct omap_dss_device *dssdev; ++ ++ bool enabled; ++ u8 rotate; ++ bool mirror; ++ ++ bool te_enabled; ++ bool use_ext_te; ++ struct completion te_completion; ++ ++ bool use_dsi_bl; ++ ++ bool cabc_broken; ++ unsigned cabc_mode; ++ ++ bool intro_printed; ++}; ++ ++static void hw_guard_start(struct taal_data *td, int guard_msec) ++{ ++ td->hw_guard_wait = msecs_to_jiffies(guard_msec); ++ td->hw_guard_end = jiffies + td->hw_guard_wait; ++} ++ ++static void hw_guard_wait(struct taal_data *td) ++{ ++ unsigned long wait = td->hw_guard_end - jiffies; ++ ++ if ((long)wait > 0 && wait <= td->hw_guard_wait) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(wait); ++ } ++} ++ ++static int taal_dcs_read_1(u8 dcs_cmd, u8 *data) ++{ ++ int r; ++ u8 buf[1]; ++ ++ r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1); ++ ++ if (r < 0) ++ return r; ++ ++ *data = buf[0]; ++ ++ return 0; ++} ++ ++static int taal_dcs_write_0(u8 dcs_cmd) ++{ ++ return dsi_vc_dcs_write(TCH, &dcs_cmd, 1); ++} ++ ++static int taal_dcs_write_1(u8 dcs_cmd, u8 param) ++{ ++ u8 buf[2]; ++ buf[0] = dcs_cmd; ++ buf[1] = param; ++ return dsi_vc_dcs_write(TCH, buf, 2); ++} ++ ++static int taal_sleep_in(struct taal_data *td) ++ ++{ ++ u8 cmd; ++ int r; ++ ++ hw_guard_wait(td); ++ ++ cmd = DCS_SLEEP_IN; ++ r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1); ++ if (r) ++ return r; ++ ++ hw_guard_start(td, 120); ++ ++ msleep(5); ++ ++ return 0; ++} ++ ++static int taal_sleep_out(struct taal_data *td) ++{ ++ int r; ++ ++ hw_guard_wait(td); ++ ++ r = taal_dcs_write_0(DCS_SLEEP_OUT); ++ if (r) ++ return r; ++ ++ hw_guard_start(td, 120); ++ ++ msleep(5); ++ ++ return 0; ++} ++ ++static int taal_get_id(u8 *id1, u8 *id2, u8 *id3) ++{ ++ int r; ++ ++ r = taal_dcs_read_1(DCS_GET_ID1, id1); ++ if (r) ++ return r; ++ r = taal_dcs_read_1(DCS_GET_ID2, id2); ++ if (r) ++ return r; ++ r = taal_dcs_read_1(DCS_GET_ID3, id3); ++ if (r) ++ return r; ++ ++ return 0; ++} ++ ++static int taal_set_addr_mode(u8 rotate, bool mirror) ++{ ++ int r; ++ u8 mode; ++ int b5, b6, b7; ++ ++ r = taal_dcs_read_1(DCS_READ_MADCTL, &mode); ++ if (r) ++ return r; ++ ++ switch (rotate) { ++ default: ++ case 0: ++ b7 = 0; ++ b6 = 0; ++ b5 = 0; ++ break; ++ case 1: ++ b7 = 0; ++ b6 = 1; ++ b5 = 1; ++ break; ++ case 2: ++ b7 = 1; ++ b6 = 1; ++ b5 = 0; ++ break; ++ case 3: ++ b7 = 1; ++ b6 = 0; ++ b5 = 1; ++ break; ++ } ++ ++ if (mirror) ++ b6 = !b6; ++ ++ mode &= ~((1<<7) | (1<<6) | (1<<5)); ++ mode |= (b7 << 7) | (b6 << 6) | (b5 << 5); ++ ++ return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode); ++} ++ ++static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h) ++{ ++ int r; ++ u16 x1 = x; ++ u16 x2 = x + w - 1; ++ u16 y1 = y; ++ u16 y2 = y + h - 1; ++ ++ u8 buf[5]; ++ buf[0] = DCS_COLUMN_ADDR; ++ buf[1] = (x1 >> 8) & 0xff; ++ buf[2] = (x1 >> 0) & 0xff; ++ buf[3] = (x2 >> 8) & 0xff; ++ buf[4] = (x2 >> 0) & 0xff; ++ ++ r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf)); ++ if (r) ++ return r; ++ ++ buf[0] = DCS_PAGE_ADDR; ++ buf[1] = (y1 >> 8) & 0xff; ++ buf[2] = (y1 >> 0) & 0xff; ++ buf[3] = (y2 >> 8) & 0xff; ++ buf[4] = (y2 >> 0) & 0xff; ++ ++ r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf)); ++ if (r) ++ return r; ++ ++ dsi_vc_send_bta_sync(TCH); ++ ++ return r; ++} ++ ++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); ++ int r; ++ int level; ++ ++ if (dev->props.fb_blank == FB_BLANK_UNBLANK && ++ dev->props.power == FB_BLANK_UNBLANK) ++ level = dev->props.brightness; ++ else ++ level = 0; ++ ++ dev_dbg(&dssdev->dev, "update brightness to %d\n", level); ++ ++ 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 { ++ if (!dssdev->set_backlight) ++ return -EINVAL; ++ ++ r = dssdev->set_backlight(dssdev, level); ++ if (r) ++ return r; ++ } ++ ++ return 0; ++} ++ ++static int taal_bl_get_intensity(struct backlight_device *dev) ++{ ++ if (dev->props.fb_blank == FB_BLANK_UNBLANK && ++ dev->props.power == FB_BLANK_UNBLANK) ++ return dev->props.brightness; ++ ++ return 0; ++} ++ ++static struct backlight_ops taal_bl_ops = { ++ .get_brightness = taal_bl_get_intensity, ++ .update_status = taal_bl_update_status, ++}; ++ ++static void taal_get_timings(struct omap_dss_device *dssdev, ++ struct omap_video_timings *timings) ++{ ++ *timings = dssdev->panel.timings; ++} ++ ++static void taal_get_resolution(struct omap_dss_device *dssdev, ++ u16 *xres, u16 *yres) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ ++ if (td->rotate == 0 || td->rotate == 2) { ++ *xres = dssdev->panel.timings.x_res; ++ *yres = dssdev->panel.timings.y_res; ++ } else { ++ *yres = dssdev->panel.timings.x_res; ++ *xres = dssdev->panel.timings.y_res; ++ } ++} ++ ++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) ++{ ++ struct omap_dss_device *dssdev = to_dss_device(dev); ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ u8 errors; ++ int r; ++ ++ if (td->enabled) { ++ dsi_bus_lock(); ++ r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors); ++ dsi_bus_unlock(); ++ } else { ++ r = -ENODEV; ++ } ++ ++ if (r) ++ return r; ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", errors); ++} ++ ++static ssize_t taal_hw_revision_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct omap_dss_device *dssdev = to_dss_device(dev); ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ u8 id1, id2, id3; ++ int r; ++ ++ if (td->enabled) { ++ dsi_bus_lock(); ++ r = taal_get_id(&id1, &id2, &id3); ++ dsi_bus_unlock(); ++ } else { ++ r = -ENODEV; ++ } ++ ++ if (r) ++ return r; ++ ++ return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3); ++} ++ ++static const char *cabc_modes[] = { ++ "off", /* used also always when CABC is not supported */ ++ "ui", ++ "still-image", ++ "moving-image", ++}; ++ ++static ssize_t show_cabc_mode(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct omap_dss_device *dssdev = to_dss_device(dev); ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ const char *mode_str; ++ int mode; ++ int len; ++ ++ mode = td->cabc_mode; ++ ++ mode_str = "unknown"; ++ if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes)) ++ mode_str = cabc_modes[mode]; ++ len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str); ++ ++ return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1; ++} ++ ++static ssize_t store_cabc_mode(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct omap_dss_device *dssdev = to_dss_device(dev); ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) { ++ if (sysfs_streq(cabc_modes[i], buf)) ++ break; ++ } ++ ++ if (i == ARRAY_SIZE(cabc_modes)) ++ return -EINVAL; ++ ++ if (td->enabled) { ++ dsi_bus_lock(); ++ if (!td->cabc_broken) ++ taal_dcs_write_1(DCS_WRITE_CABC, i); ++ dsi_bus_unlock(); ++ } ++ ++ td->cabc_mode = i; ++ ++ return count; ++} ++ ++static ssize_t show_cabc_available_modes(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ int len; ++ int i; ++ ++ for (i = 0, len = 0; ++ len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++) ++ len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s", ++ i ? " " : "", cabc_modes[i], ++ i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : ""); ++ ++ return len < PAGE_SIZE ? len : PAGE_SIZE - 1; ++} ++ ++static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL); ++static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL); ++static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR, ++ show_cabc_mode, store_cabc_mode); ++static DEVICE_ATTR(cabc_available_modes, S_IRUGO, ++ show_cabc_available_modes, NULL); ++ ++static struct attribute *taal_attrs[] = { ++ &dev_attr_num_dsi_errors.attr, ++ &dev_attr_hw_revision.attr, ++ &dev_attr_cabc_mode.attr, ++ &dev_attr_cabc_available_modes.attr, ++ NULL, ++}; ++ ++static struct attribute_group taal_attr_group = { ++ .attrs = taal_attrs, ++}; ++ ++static int taal_probe(struct omap_dss_device *dssdev) ++{ ++ struct taal_data *td; ++ struct backlight_device *bldev; ++ int r; ++ ++ const struct omap_video_timings taal_panel_timings = { ++ .x_res = 864, ++ .y_res = 480, ++ }; ++ ++ dev_dbg(&dssdev->dev, "probe\n"); ++ ++ dssdev->panel.config = OMAP_DSS_LCD_TFT; ++ dssdev->panel.timings = taal_panel_timings; ++ dssdev->ctrl.pixel_size = 24; ++ ++ td = kzalloc(sizeof(*td), GFP_KERNEL); ++ if (!td) { ++ r = -ENOMEM; ++ goto err0; ++ } ++ ++ dev_set_drvdata(&dssdev->dev, td); ++ ++ dssdev->get_timings = taal_get_timings; ++ dssdev->get_resolution = taal_get_resolution; ++ ++ /* if no platform set_backlight() defined, presume DSI backlight ++ * control */ ++ if (!dssdev->set_backlight) ++ td->use_dsi_bl = true; ++ ++ bldev = backlight_device_register("taal", &dssdev->dev, dssdev, ++ &taal_bl_ops); ++ if (IS_ERR(bldev)) { ++ r = PTR_ERR(bldev); ++ goto err1; ++ } ++ ++ td->bldev = bldev; ++ ++ bldev->props.fb_blank = FB_BLANK_UNBLANK; ++ bldev->props.power = FB_BLANK_UNBLANK; ++ if (td->use_dsi_bl) { ++ bldev->props.max_brightness = 255; ++ bldev->props.brightness = 255; ++ } else { ++ bldev->props.max_brightness = 127; ++ bldev->props.brightness = 127; ++ } ++ ++ taal_bl_update_status(bldev); ++ ++ if (dssdev->phy.dsi.ext_te) { ++ int gpio = dssdev->phy.dsi.ext_te_gpio; ++ ++ r = gpio_request(gpio, "taal irq"); ++ if (r) { ++ dev_err(&dssdev->dev, "GPIO request failed\n"); ++ goto err2; ++ } ++ ++ gpio_direction_input(gpio); ++ ++ r = request_irq(gpio_to_irq(gpio), taal_te_isr, ++ IRQF_DISABLED | IRQF_TRIGGER_RISING, ++ "taal vsync", dssdev); ++ ++ if (r) { ++ dev_err(&dssdev->dev, "IRQ request failed\n"); ++ gpio_free(gpio); ++ goto err2; ++ } ++ ++ init_completion(&td->te_completion); ++ ++ td->use_ext_te = true; ++ } ++ ++ r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); ++ if (r) { ++ dev_err(&dssdev->dev, "failed to create sysfs files\n"); ++ goto err3; ++ } ++ ++ return 0; ++err3: ++ if (td->use_ext_te) { ++ int gpio = dssdev->phy.dsi.ext_te_gpio; ++ free_irq(gpio_to_irq(gpio), dssdev); ++ gpio_free(gpio); ++ } ++err2: ++ backlight_device_unregister(bldev); ++err1: ++ kfree(td); ++err0: ++ return r; ++} ++ ++static void taal_remove(struct omap_dss_device *dssdev) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ 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; ++ free_irq(gpio_to_irq(gpio), dssdev); ++ gpio_free(gpio); ++ } ++ ++ bldev = td->bldev; ++ bldev->props.power = FB_BLANK_POWERDOWN; ++ taal_bl_update_status(bldev); ++ backlight_device_unregister(bldev); ++ ++ kfree(td); ++} ++ ++static int taal_enable(struct omap_dss_device *dssdev) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ u8 id1, id2, id3; ++ int r; ++ ++ dev_dbg(&dssdev->dev, "enable\n"); ++ ++ 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); ++ ++ r = taal_sleep_out(td); ++ if (r) ++ return r; ++ ++ r = taal_get_id(&id1, &id2, &id3); ++ if (r) ++ return r; ++ ++ /* on early revisions CABC is broken */ ++ if (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 */ ++ ++ taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ ++ ++ taal_set_addr_mode(td->rotate, td->mirror); ++ if (!td->cabc_broken) ++ taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode); ++ ++ taal_dcs_write_0(DCS_DISPLAY_ON); ++ ++ td->enabled = 1; ++ ++ if (!td->intro_printed) { ++ dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n", ++ id1, id2, id3); ++ if (td->cabc_broken) ++ dev_info(&dssdev->dev, ++ "old Taal version, CABC disabled\n"); ++ td->intro_printed = true; ++ } ++ ++ return 0; ++} ++ ++static void taal_disable(struct omap_dss_device *dssdev) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ ++ dev_dbg(&dssdev->dev, "disable\n"); ++ ++ taal_dcs_write_0(DCS_DISPLAY_OFF); ++ taal_sleep_in(td); ++ ++ /* wait a bit so that the message goes through */ ++ msleep(10); ++ ++ if (dssdev->platform_disable) ++ dssdev->platform_disable(dssdev); ++ ++ td->enabled = 0; ++} ++ ++static int taal_suspend(struct omap_dss_device *dssdev) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ struct backlight_device *bldev = td->bldev; ++ ++ bldev->props.power = FB_BLANK_POWERDOWN; ++ taal_bl_update_status(bldev); ++ ++ return 0; ++} ++ ++static int taal_resume(struct omap_dss_device *dssdev) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ struct backlight_device *bldev = td->bldev; ++ ++ bldev->props.power = FB_BLANK_UNBLANK; ++ taal_bl_update_status(bldev); ++ ++ return 0; ++} ++ ++static void taal_setup_update(struct omap_dss_device *dssdev, ++ u16 x, u16 y, u16 w, u16 h) ++{ ++ taal_set_update_window(x, y, w, h); ++} ++ ++static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ 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); ++ ++ return r; ++} ++ ++static int taal_wait_te(struct omap_dss_device *dssdev) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ long wait = msecs_to_jiffies(500); ++ ++ if (!td->use_ext_te || !td->te_enabled) ++ return 0; ++ ++ INIT_COMPLETION(td->te_completion); ++ wait = wait_for_completion_timeout(&td->te_completion, wait); ++ if (wait == 0) { ++ dev_err(&dssdev->dev, "timeout waiting TE\n"); ++ return -ETIME; ++ } ++ ++ return 0; ++} ++ ++static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ int r; ++ ++ dev_dbg(&dssdev->dev, "rotate %d\n", rotate); ++ ++ if (td->enabled) { ++ r = taal_set_addr_mode(rotate, td->mirror); ++ ++ if (r) ++ return r; ++ } ++ ++ td->rotate = rotate; ++ ++ return 0; ++} ++ ++static u8 taal_get_rotate(struct omap_dss_device *dssdev) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ return td->rotate; ++} ++ ++static int taal_mirror(struct omap_dss_device *dssdev, bool enable) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ int r; ++ ++ dev_dbg(&dssdev->dev, "mirror %d\n", enable); ++ ++ if (td->enabled) { ++ r = taal_set_addr_mode(td->rotate, enable); ++ ++ if (r) ++ return r; ++ } ++ ++ td->mirror = enable; ++ ++ return 0; ++} ++ ++static bool taal_get_mirror(struct omap_dss_device *dssdev) ++{ ++ struct taal_data *td = dev_get_drvdata(&dssdev->dev); ++ return td->mirror; ++} ++ ++static int taal_run_test(struct omap_dss_device *dssdev, int test_num) ++{ ++ u8 id1, id2, id3; ++ int r; ++ ++ r = taal_dcs_read_1(DCS_GET_ID1, &id1); ++ if (r) ++ return r; ++ r = taal_dcs_read_1(DCS_GET_ID2, &id2); ++ if (r) ++ return r; ++ r = taal_dcs_read_1(DCS_GET_ID3, &id3); ++ if (r) ++ return r; ++ ++ return 0; ++} ++ ++static int taal_memory_read(struct omap_dss_device *dssdev, ++ void *buf, size_t size, ++ u16 x, u16 y, u16 w, u16 h) ++{ ++ int r; ++ int first = 1; ++ int plen; ++ unsigned buf_used = 0; ++ ++ if (size < w * h * 3) ++ return -ENOMEM; ++ ++ size = min(w * h * 3, ++ dssdev->panel.timings.x_res * ++ dssdev->panel.timings.y_res * 3); ++ ++ /* plen 1 or 2 goes into short packet. until checksum error is fixed, ++ * use short packets. plen 32 works, but bigger packets seem to cause ++ * an error. */ ++ if (size % 2) ++ plen = 1; ++ else ++ plen = 2; ++ ++ taal_setup_update(dssdev, x, y, w, h); ++ ++ r = dsi_vc_set_max_rx_packet_size(TCH, plen); ++ if (r) ++ return r; ++ ++ while (buf_used < size) { ++ u8 dcs_cmd = first ? 0x2e : 0x3e; ++ first = 0; ++ ++ r = dsi_vc_dcs_read(TCH, dcs_cmd, ++ buf + buf_used, size - buf_used); ++ ++ if (r < 0) { ++ dev_err(&dssdev->dev, "read error\n"); ++ goto err; ++ } ++ ++ buf_used += r; ++ ++ if (r < plen) { ++ dev_err(&dssdev->dev, "short read\n"); ++ break; ++ } ++ } ++ ++ r = buf_used; ++ ++err: ++ dsi_vc_set_max_rx_packet_size(TCH, 1); ++ ++ return r; ++} ++ ++static struct omap_dss_driver taal_driver = { ++ .probe = taal_probe, ++ .remove = taal_remove, ++ ++ .enable = taal_enable, ++ .disable = taal_disable, ++ .suspend = taal_suspend, ++ .resume = taal_resume, ++ ++ .setup_update = taal_setup_update, ++ .enable_te = taal_enable_te, ++ .wait_for_te = taal_wait_te, ++ .set_rotate = taal_rotate, ++ .get_rotate = taal_get_rotate, ++ .set_mirror = taal_mirror, ++ .get_mirror = taal_get_mirror, ++ .run_test = taal_run_test, ++ .memory_read = taal_memory_read, ++ ++ .driver = { ++ .name = "taal", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init taal_init(void) ++{ ++ omap_dss_register_driver(&taal_driver); ++ ++ return 0; ++} ++ ++static void __exit taal_exit(void) ++{ ++ omap_dss_unregister_driver(&taal_driver); ++} ++ ++module_init(taal_init); ++module_exit(taal_exit); ++ ++MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); ++MODULE_DESCRIPTION("Taal Driver"); ++MODULE_LICENSE("GPL"); +-- +1.6.2.4 + |