lkml.org 
[lkml]   [2009]   [Aug]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 17/18] OMAP: DSS2: Taal DSI command mode panel driver
    Date
    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.4


    \
     
     \ /
      Last update: 2009-08-28 14:29    [from the cache]
    ©2003-2014 Jasper Spaans. hosted at Digital Ocean