linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] OMAP: DSS: add TPO TD043MTEA1 panel
@ 2009-12-11 19:30 Grazvydas Ignotas
  2010-01-13  8:49 ` Tomi Valkeinen
  0 siblings, 1 reply; 4+ messages in thread
From: Grazvydas Ignotas @ 2009-12-11 19:30 UTC (permalink / raw)
  To: linux-fbdev; +Cc: Tomi Valkeinen, linux-omap, Grazvydas Ignotas

Add support of TPO TD043MTEA1 TFT LCD panel to DSS2 driver.
This panel is used by OMAP3 Pandora device.

Signed-off-by: Grazvydas Ignotas <notasas@gmail.com>
---
 drivers/video/omap2/displays/Kconfig               |    6 +
 drivers/video/omap2/displays/Makefile              |    1 +
 .../video/omap2/displays/panel-tpo-td043mtea1.c    |  489 ++++++++++++++++++++
 3 files changed, 496 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/omap2/displays/panel-tpo-td043mtea1.c

diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index b12a59c..a1d0ce4 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -19,4 +19,10 @@ config PANEL_TAAL
         help
           Taal DSI command mode panel from TPO.
 
+config PANEL_TPO_TD043MTEA1
+        tristate "TPO TD043MTEA1 LCD Panel"
+        depends on OMAP2_DSS && I2C
+        help
+          LCD Panel used in OMAP3 Pandora
+
 endmenu
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index 9556464..143a717 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
 obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
 
 obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
+obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
new file mode 100644
index 0000000..f297a46
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -0,0 +1,489 @@
+/*
+ * LCD panel driver for TPO TD043MTEA1
+ *
+ * Author: Gražvydas Ignotas <notasas@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+
+#include <plat/display.h>
+
+#define TPO_R02_MODE(x)		((x) & 7)
+#define TPO_R02_MODE_800x480	7
+#define TPO_R02_NCLK_RISING	BIT(3)
+#define TPO_R02_HSYNC_HIGH	BIT(4)
+#define TPO_R02_VSYNC_HIGH	BIT(5)
+
+#define TPO_R03_NSTANDBY	BIT(0)
+#define TPO_R03_EN_CP_CLK	BIT(1)
+#define TPO_R03_EN_VGL_PUMP	BIT(2)
+#define TPO_R03_EN_PWM		BIT(3)
+#define TPO_R03_DRIVING_CAP_100	BIT(4)
+#define TPO_R03_EN_PRE_CHARGE	BIT(6)
+#define TPO_R03_SOFTWARE_CTL	BIT(7)
+
+#define TPO_R04_NFLIP_H		BIT(0)
+#define TPO_R04_NFLIP_V		BIT(1)
+#define TPO_R04_CP_CLK_FREQ_1H	BIT(2)
+#define TPO_R04_VGL_FREQ_1H	BIT(4)
+
+#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \
+			TPO_R03_EN_VGL_PUMP |  TPO_R03_EN_PWM | \
+			TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
+			TPO_R03_SOFTWARE_CTL)
+
+#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \
+			TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL)
+
+static const u16 tpo_td043_def_gamma[12] = {
+	106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020
+};
+
+struct tpo_td043_device {
+	struct spi_device *spi;
+	struct regulator *vcc_reg;
+	u16 gamma[12];
+	u32 mode;
+	u32 hmirror:1;
+	u32 vmirror:1;
+};
+
+static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
+{
+	struct spi_message	m;
+	struct spi_transfer	xfer;
+	u16			w;
+	int			r;
+
+	spi_message_init(&m);
+
+	memset(&xfer, 0, sizeof(xfer));
+
+	w = ((u16)addr << 10) | (1 << 8) | data;
+	xfer.tx_buf = &w;
+	xfer.bits_per_word = 16;
+	xfer.len = 2;
+	spi_message_add_tail(&xfer, &m);
+
+	r = spi_sync(spi, &m);
+	if (r < 0)
+		dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r);
+	return r;
+}
+
+static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12])
+{
+	u8 i, val;
+
+	/* gamma bits [9:8] */
+	for (val = i = 0; i < 4; i++)
+		val |= (gamma[i] & 0x300) >> ((i + 1) * 2);
+	tpo_td043_write(spi, 0x11, val);
+
+	for (val = i = 0; i < 4; i++)
+		val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2);
+	tpo_td043_write(spi, 0x12, val);
+
+	for (val = i = 0; i < 4; i++)
+		val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2);
+	tpo_td043_write(spi, 0x13, val);
+
+	/* gamma bits [7:0] */
+	for (val = i = 0; i < 12; i++)
+		tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff);
+}
+
+static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
+{
+	u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | \
+		TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;
+	if (h)
+		reg4 &= ~TPO_R04_NFLIP_H;
+	if (v)
+		reg4 &= ~TPO_R04_NFLIP_V;
+
+	return tpo_td043_write(spi, 4, reg4);
+}
+
+static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+
+	tpo_td043->hmirror = enable;
+	return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
+			tpo_td043->vmirror);
+}
+
+static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+
+	return tpo_td043->hmirror;
+}
+
+static ssize_t tpo_td043_vmirror_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->vmirror);
+}
+
+static ssize_t tpo_td043_vmirror_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+	long val;
+	int ret;
+
+	ret = strict_strtol(buf, 0, &val);
+	if (ret < 0)
+		return ret;
+
+	ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val);
+	if (ret < 0)
+		return ret;
+
+	tpo_td043->vmirror = val;
+
+	return count;
+}
+
+static ssize_t tpo_td043_mode_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->mode);
+}
+
+static ssize_t tpo_td043_mode_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+	long val;
+	int ret;
+
+	ret = strict_strtol(buf, 0, &val);
+	if (ret != 0 || val & ~7)
+		return -EINVAL;
+
+	tpo_td043->mode = val;
+
+	val |= TPO_R02_NCLK_RISING;
+	tpo_td043_write(tpo_td043->spi, 2, val);
+
+	return count;
+}
+
+static ssize_t tpo_td043_gamma_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+	ssize_t len = 0;
+	int ret;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tpo_td043->gamma); i++) {
+		ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
+				tpo_td043->gamma[i]);
+		if (ret < 0)
+			return ret;
+		len += ret;
+	}
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+static ssize_t tpo_td043_gamma_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+	unsigned int g[12];
+	int ret;
+	int i;
+
+	ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",
+			&g[0], &g[1], &g[2], &g[3], &g[4], &g[5],
+			&g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
+
+	if (ret != 12)
+		return -EINVAL;
+
+	for (i = 0; i < 12; i++)
+		tpo_td043->gamma[i] = g[i];
+
+	tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
+
+	return count;
+}
+
+static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR,
+		tpo_td043_vmirror_show, tpo_td043_vmirror_store);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+		tpo_td043_mode_show, tpo_td043_mode_store);
+static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR,
+		tpo_td043_gamma_show, tpo_td043_gamma_store);
+
+static struct attribute *tpo_td043_attrs[] = {
+	&dev_attr_vmirror.attr,
+	&dev_attr_mode.attr,
+	&dev_attr_gamma.attr,
+	NULL,
+};
+
+static struct attribute_group tpo_td043_attr_group = {
+	.attrs = tpo_td043_attrs,
+};
+
+static const struct omap_video_timings tpo_td043_timings = {
+	.x_res		= 800,
+	.y_res		= 480,
+
+	.pixel_clock	= 36000,
+
+	.hsw		= 1,
+	.hfp		= 68,
+	.hbp		= 214,
+
+	.vsw		= 1,
+	.vfp		= 39,
+	.vbp		= 34,
+};
+
+static int tpo_td043_enable(struct omap_dss_device *dssdev)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+	int nreset_gpio = dssdev->reset_gpio;
+	int ret;
+
+	dev_dbg(&dssdev->dev, "enable\n");
+
+	if (dssdev->platform_enable) {
+		ret = dssdev->platform_enable(dssdev);
+		if (ret)
+			return ret;
+	}
+
+	regulator_enable(tpo_td043->vcc_reg);
+
+	/* wait for power up */
+	msleep(160);
+
+	if (gpio_is_valid(nreset_gpio))
+		gpio_set_value(nreset_gpio, 1);
+
+	tpo_td043_write(tpo_td043->spi, 2,
+			TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING);
+	tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_NORMAL);
+	tpo_td043_write(tpo_td043->spi, 0x20, 0xf0);
+	tpo_td043_write(tpo_td043->spi, 0x21, 0xf0);
+	tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
+			tpo_td043->vmirror);
+	tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
+
+	return 0;
+}
+
+static void tpo_td043_disable(struct omap_dss_device *dssdev)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+	int nreset_gpio = dssdev->reset_gpio;
+
+	dev_dbg(&dssdev->dev, "disable\n");
+
+	tpo_td043_write(tpo_td043->spi, 3,
+			TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
+
+	if (gpio_is_valid(nreset_gpio))
+		gpio_set_value(nreset_gpio, 0);
+
+	/* wait for at least 2 vsyncs before cutting off power */
+	msleep(50);
+
+	tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_STANDBY);
+
+	regulator_disable(tpo_td043->vcc_reg);
+
+	if (dssdev->platform_disable)
+		dssdev->platform_disable(dssdev);
+}
+
+static int tpo_td043_suspend(struct omap_dss_device *dssdev)
+{
+	tpo_td043_disable(dssdev);
+	return 0;
+}
+
+static int tpo_td043_resume(struct omap_dss_device *dssdev)
+{
+	return tpo_td043_enable(dssdev);
+}
+
+static int tpo_td043_probe(struct omap_dss_device *dssdev)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+	int nreset_gpio = dssdev->reset_gpio;
+	int ret = 0;
+
+	dev_dbg(&dssdev->dev, "probe\n");
+
+	if (tpo_td043 = NULL) {
+		dev_err(&dssdev->dev, "missing tpo_td043_device\n");
+		return -ENODEV;
+	}
+
+	dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IHS |
+				OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IPC;
+	dssdev->panel.timings = tpo_td043_timings;
+	dssdev->ctrl.pixel_size = 24;
+
+	tpo_td043->mode = TPO_R02_MODE_800x480;
+	memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma));
+
+	tpo_td043->vcc_reg = regulator_get(&dssdev->dev, "vcc");
+	if (IS_ERR(tpo_td043->vcc_reg)) {
+		dev_err(&dssdev->dev, "failed to get LCD VCC regulator\n");
+		ret = PTR_ERR(tpo_td043->vcc_reg);
+		goto fail_regulator;
+	}
+
+	if (gpio_is_valid(nreset_gpio)) {
+		ret = gpio_request(nreset_gpio, "lcd reset");
+		if (ret < 0) {
+			dev_err(&dssdev->dev, "couldn't request reset GPIO\n");
+			goto fail_gpio_req;
+		}
+
+		ret = gpio_direction_output(nreset_gpio, 0);
+		if (ret < 0) {
+			dev_err(&dssdev->dev, "couldn't set GPIO direction\n");
+			goto fail_gpio_direction;
+		}
+	}
+
+	ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
+	if (ret)
+		dev_warn(&dssdev->dev, "failed to create sysfs files\n");
+
+	return 0;
+
+fail_gpio_direction:
+	gpio_free(nreset_gpio);
+fail_gpio_req:
+	regulator_put(tpo_td043->vcc_reg);
+fail_regulator:
+	kfree(tpo_td043);
+	return ret;
+}
+
+static void tpo_td043_remove(struct omap_dss_device *dssdev)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+	int nreset_gpio = dssdev->reset_gpio;
+
+	dev_dbg(&dssdev->dev, "remove\n");
+
+	sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
+	regulator_put(tpo_td043->vcc_reg);
+	if (gpio_is_valid(nreset_gpio))
+		gpio_free(nreset_gpio);
+}
+
+static struct omap_dss_driver tpo_td043_driver = {
+	.probe		= tpo_td043_probe,
+	.remove		= tpo_td043_remove,
+
+	.enable		= tpo_td043_enable,
+	.disable	= tpo_td043_disable,
+	.suspend	= tpo_td043_suspend,
+	.resume		= tpo_td043_resume,
+	.set_mirror	= tpo_td043_set_hmirror,
+	.get_mirror	= tpo_td043_get_hmirror,
+
+	.driver         = {
+		.name	= "tpo_td043mtea1_panel",
+		.owner  = THIS_MODULE,
+	},
+};
+
+static int tpo_td043_spi_probe(struct spi_device *spi)
+{
+	struct omap_dss_device *dssdev = spi->dev.platform_data;
+	struct tpo_td043_device *tpo_td043;
+	int ret;
+
+	if (dssdev = NULL) {
+		dev_err(&spi->dev, "missing dssdev\n");
+		return -ENODEV;
+	}
+
+	spi->bits_per_word = 16;
+	spi->mode = SPI_MODE_0;
+
+	ret = spi_setup(spi);
+	if (ret < 0) {
+		dev_err(&spi->dev, "spi_setup failed: %d\n", ret);
+		return ret;
+	}
+
+	tpo_td043 = kzalloc(sizeof(*tpo_td043), GFP_KERNEL);
+	if (tpo_td043 = NULL)
+		return -ENOMEM;
+
+	tpo_td043->spi = spi;
+	dev_set_drvdata(&spi->dev, tpo_td043);
+	dev_set_drvdata(&dssdev->dev, tpo_td043);
+
+	omap_dss_register_driver(&tpo_td043_driver);
+
+	return 0;
+}
+
+static int __devexit tpo_td043_spi_remove(struct spi_device *spi)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev);
+
+	omap_dss_unregister_driver(&tpo_td043_driver);
+	kfree(tpo_td043);
+
+	return 0;
+}
+
+static struct spi_driver tpo_td043_spi_driver = {
+	.driver = {
+		.name	= "tpo_td043mtea1_panel_spi",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe	= tpo_td043_spi_probe,
+	.remove	= __devexit_p(tpo_td043_spi_remove),
+};
+
+static int __init tpo_td043_init(void)
+{
+	return spi_register_driver(&tpo_td043_spi_driver);
+}
+
+static void __exit tpo_td043_exit(void)
+{
+	spi_unregister_driver(&tpo_td043_spi_driver);
+}
+
+module_init(tpo_td043_init);
+module_exit(tpo_td043_exit);
+
+MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
+MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
+MODULE_LICENSE("GPL");
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] OMAP: DSS: add TPO TD043MTEA1 panel
  2009-12-11 19:30 [PATCH] OMAP: DSS: add TPO TD043MTEA1 panel Grazvydas Ignotas
@ 2010-01-13  8:49 ` Tomi Valkeinen
  2010-01-13 11:06   ` Grazvydas Ignotas
  0 siblings, 1 reply; 4+ messages in thread
From: Tomi Valkeinen @ 2010-01-13  8:49 UTC (permalink / raw)
  To: ext Grazvydas Ignotas
  Cc: linux-fbdev@vger.kernel.org, linux-omap@vger.kernel.org

Hi,

Sorry for the long time it took me to check this out. Checkpatch
complains about indentation, I think the whole file is indented with
spaces, not tabs.

 Tomi


On Fri, 2009-12-11 at 20:30 +0100, ext Grazvydas Ignotas wrote:
> Add support of TPO TD043MTEA1 TFT LCD panel to DSS2 driver.
> This panel is used by OMAP3 Pandora device.
> 
> Signed-off-by: Grazvydas Ignotas <notasas@gmail.com>
> ---
>  drivers/video/omap2/displays/Kconfig               |    6 +
>  drivers/video/omap2/displays/Makefile              |    1 +
>  .../video/omap2/displays/panel-tpo-td043mtea1.c    |  489 ++++++++++++++++++++
>  3 files changed, 496 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/video/omap2/displays/panel-tpo-td043mtea1.c
> 
> diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
> index b12a59c..a1d0ce4 100644
> --- a/drivers/video/omap2/displays/Kconfig
> +++ b/drivers/video/omap2/displays/Kconfig
> @@ -19,4 +19,10 @@ config PANEL_TAAL
>          help
>            Taal DSI command mode panel from TPO.
> 
> +config PANEL_TPO_TD043MTEA1
> +        tristate "TPO TD043MTEA1 LCD Panel"
> +        depends on OMAP2_DSS && I2C
> +        help
> +          LCD Panel used in OMAP3 Pandora
> +
>  endmenu
> diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
> index 9556464..143a717 100644
> --- a/drivers/video/omap2/displays/Makefile
> +++ b/drivers/video/omap2/displays/Makefile
> @@ -2,3 +2,4 @@ obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
>  obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
> 
>  obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
> +obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
> diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
> new file mode 100644
> index 0000000..f297a46
> --- /dev/null
> +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
> @@ -0,0 +1,489 @@
> +/*
> + * LCD panel driver for TPO TD043MTEA1
> + *
> + * Author: Gražvydas Ignotas <notasas@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/spi/spi.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/gpio.h>
> +#include <linux/err.h>
> +
> +#include <plat/display.h>
> +
> +#define TPO_R02_MODE(x)                ((x) & 7)
> +#define TPO_R02_MODE_800x480   7
> +#define TPO_R02_NCLK_RISING    BIT(3)
> +#define TPO_R02_HSYNC_HIGH     BIT(4)
> +#define TPO_R02_VSYNC_HIGH     BIT(5)
> +
> +#define TPO_R03_NSTANDBY       BIT(0)
> +#define TPO_R03_EN_CP_CLK      BIT(1)
> +#define TPO_R03_EN_VGL_PUMP    BIT(2)
> +#define TPO_R03_EN_PWM         BIT(3)
> +#define TPO_R03_DRIVING_CAP_100        BIT(4)
> +#define TPO_R03_EN_PRE_CHARGE  BIT(6)
> +#define TPO_R03_SOFTWARE_CTL   BIT(7)
> +
> +#define TPO_R04_NFLIP_H                BIT(0)
> +#define TPO_R04_NFLIP_V                BIT(1)
> +#define TPO_R04_CP_CLK_FREQ_1H BIT(2)
> +#define TPO_R04_VGL_FREQ_1H    BIT(4)
> +
> +#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \
> +                       TPO_R03_EN_VGL_PUMP |  TPO_R03_EN_PWM | \
> +                       TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
> +                       TPO_R03_SOFTWARE_CTL)
> +
> +#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \
> +                       TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL)
> +
> +static const u16 tpo_td043_def_gamma[12] = {
> +       106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020
> +};
> +
> +struct tpo_td043_device {
> +       struct spi_device *spi;
> +       struct regulator *vcc_reg;
> +       u16 gamma[12];
> +       u32 mode;
> +       u32 hmirror:1;
> +       u32 vmirror:1;
> +};
> +
> +static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
> +{
> +       struct spi_message      m;
> +       struct spi_transfer     xfer;
> +       u16                     w;
> +       int                     r;
> +
> +       spi_message_init(&m);
> +
> +       memset(&xfer, 0, sizeof(xfer));
> +
> +       w = ((u16)addr << 10) | (1 << 8) | data;
> +       xfer.tx_buf = &w;
> +       xfer.bits_per_word = 16;
> +       xfer.len = 2;
> +       spi_message_add_tail(&xfer, &m);
> +
> +       r = spi_sync(spi, &m);
> +       if (r < 0)
> +               dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r);
> +       return r;
> +}
> +
> +static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12])
> +{
> +       u8 i, val;
> +
> +       /* gamma bits [9:8] */
> +       for (val = i = 0; i < 4; i++)
> +               val |= (gamma[i] & 0x300) >> ((i + 1) * 2);
> +       tpo_td043_write(spi, 0x11, val);
> +
> +       for (val = i = 0; i < 4; i++)
> +               val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2);
> +       tpo_td043_write(spi, 0x12, val);
> +
> +       for (val = i = 0; i < 4; i++)
> +               val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2);
> +       tpo_td043_write(spi, 0x13, val);
> +
> +       /* gamma bits [7:0] */
> +       for (val = i = 0; i < 12; i++)
> +               tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff);
> +}
> +
> +static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
> +{
> +       u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | \
> +               TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;
> +       if (h)
> +               reg4 &= ~TPO_R04_NFLIP_H;
> +       if (v)
> +               reg4 &= ~TPO_R04_NFLIP_V;
> +
> +       return tpo_td043_write(spi, 4, reg4);
> +}
> +
> +static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
> +
> +       tpo_td043->hmirror = enable;
> +       return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
> +                       tpo_td043->vmirror);
> +}
> +
> +static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
> +
> +       return tpo_td043->hmirror;
> +}
> +
> +static ssize_t tpo_td043_vmirror_show(struct device *dev,
> +       struct device_attribute *attr, char *buf)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
> +
> +       return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->vmirror);
> +}
> +
> +static ssize_t tpo_td043_vmirror_store(struct device *dev,
> +       struct device_attribute *attr, const char *buf, size_t count)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
> +       long val;
> +       int ret;
> +
> +       ret = strict_strtol(buf, 0, &val);
> +       if (ret < 0)
> +               return ret;
> +
> +       ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val);
> +       if (ret < 0)
> +               return ret;
> +
> +       tpo_td043->vmirror = val;
> +
> +       return count;
> +}
> +
> +static ssize_t tpo_td043_mode_show(struct device *dev,
> +       struct device_attribute *attr, char *buf)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
> +
> +       return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->mode);
> +}
> +
> +static ssize_t tpo_td043_mode_store(struct device *dev,
> +       struct device_attribute *attr, const char *buf, size_t count)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
> +       long val;
> +       int ret;
> +
> +       ret = strict_strtol(buf, 0, &val);
> +       if (ret != 0 || val & ~7)
> +               return -EINVAL;
> +
> +       tpo_td043->mode = val;
> +
> +       val |= TPO_R02_NCLK_RISING;
> +       tpo_td043_write(tpo_td043->spi, 2, val);
> +
> +       return count;
> +}
> +
> +static ssize_t tpo_td043_gamma_show(struct device *dev,
> +       struct device_attribute *attr, char *buf)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
> +       ssize_t len = 0;
> +       int ret;
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(tpo_td043->gamma); i++) {
> +               ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
> +                               tpo_td043->gamma[i]);
> +               if (ret < 0)
> +                       return ret;
> +               len += ret;
> +       }
> +       buf[len - 1] = '\n';
> +
> +       return len;
> +}
> +
> +static ssize_t tpo_td043_gamma_store(struct device *dev,
> +       struct device_attribute *attr, const char *buf, size_t count)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
> +       unsigned int g[12];
> +       int ret;
> +       int i;
> +
> +       ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",
> +                       &g[0], &g[1], &g[2], &g[3], &g[4], &g[5],
> +                       &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
> +
> +       if (ret != 12)
> +               return -EINVAL;
> +
> +       for (i = 0; i < 12; i++)
> +               tpo_td043->gamma[i] = g[i];
> +
> +       tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
> +
> +       return count;
> +}
> +
> +static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR,
> +               tpo_td043_vmirror_show, tpo_td043_vmirror_store);
> +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
> +               tpo_td043_mode_show, tpo_td043_mode_store);
> +static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR,
> +               tpo_td043_gamma_show, tpo_td043_gamma_store);
> +
> +static struct attribute *tpo_td043_attrs[] = {
> +       &dev_attr_vmirror.attr,
> +       &dev_attr_mode.attr,
> +       &dev_attr_gamma.attr,
> +       NULL,
> +};
> +
> +static struct attribute_group tpo_td043_attr_group = {
> +       .attrs = tpo_td043_attrs,
> +};
> +
> +static const struct omap_video_timings tpo_td043_timings = {
> +       .x_res          = 800,
> +       .y_res          = 480,
> +
> +       .pixel_clock    = 36000,
> +
> +       .hsw            = 1,
> +       .hfp            = 68,
> +       .hbp            = 214,
> +
> +       .vsw            = 1,
> +       .vfp            = 39,
> +       .vbp            = 34,
> +};
> +
> +static int tpo_td043_enable(struct omap_dss_device *dssdev)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
> +       int nreset_gpio = dssdev->reset_gpio;
> +       int ret;
> +
> +       dev_dbg(&dssdev->dev, "enable\n");
> +
> +       if (dssdev->platform_enable) {
> +               ret = dssdev->platform_enable(dssdev);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       regulator_enable(tpo_td043->vcc_reg);
> +
> +       /* wait for power up */
> +       msleep(160);
> +
> +       if (gpio_is_valid(nreset_gpio))
> +               gpio_set_value(nreset_gpio, 1);
> +
> +       tpo_td043_write(tpo_td043->spi, 2,
> +                       TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING);
> +       tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_NORMAL);
> +       tpo_td043_write(tpo_td043->spi, 0x20, 0xf0);
> +       tpo_td043_write(tpo_td043->spi, 0x21, 0xf0);
> +       tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
> +                       tpo_td043->vmirror);
> +       tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
> +
> +       return 0;
> +}
> +
> +static void tpo_td043_disable(struct omap_dss_device *dssdev)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
> +       int nreset_gpio = dssdev->reset_gpio;
> +
> +       dev_dbg(&dssdev->dev, "disable\n");
> +
> +       tpo_td043_write(tpo_td043->spi, 3,
> +                       TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
> +
> +       if (gpio_is_valid(nreset_gpio))
> +               gpio_set_value(nreset_gpio, 0);
> +
> +       /* wait for at least 2 vsyncs before cutting off power */
> +       msleep(50);
> +
> +       tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_STANDBY);
> +
> +       regulator_disable(tpo_td043->vcc_reg);
> +
> +       if (dssdev->platform_disable)
> +               dssdev->platform_disable(dssdev);
> +}
> +
> +static int tpo_td043_suspend(struct omap_dss_device *dssdev)
> +{
> +       tpo_td043_disable(dssdev);
> +       return 0;
> +}
> +
> +static int tpo_td043_resume(struct omap_dss_device *dssdev)
> +{
> +       return tpo_td043_enable(dssdev);
> +}
> +
> +static int tpo_td043_probe(struct omap_dss_device *dssdev)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
> +       int nreset_gpio = dssdev->reset_gpio;
> +       int ret = 0;
> +
> +       dev_dbg(&dssdev->dev, "probe\n");
> +
> +       if (tpo_td043 = NULL) {
> +               dev_err(&dssdev->dev, "missing tpo_td043_device\n");
> +               return -ENODEV;
> +       }
> +
> +       dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IHS |
> +                               OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IPC;
> +       dssdev->panel.timings = tpo_td043_timings;
> +       dssdev->ctrl.pixel_size = 24;
> +
> +       tpo_td043->mode = TPO_R02_MODE_800x480;
> +       memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma));
> +
> +       tpo_td043->vcc_reg = regulator_get(&dssdev->dev, "vcc");
> +       if (IS_ERR(tpo_td043->vcc_reg)) {
> +               dev_err(&dssdev->dev, "failed to get LCD VCC regulator\n");
> +               ret = PTR_ERR(tpo_td043->vcc_reg);
> +               goto fail_regulator;
> +       }
> +
> +       if (gpio_is_valid(nreset_gpio)) {
> +               ret = gpio_request(nreset_gpio, "lcd reset");
> +               if (ret < 0) {
> +                       dev_err(&dssdev->dev, "couldn't request reset GPIO\n");
> +                       goto fail_gpio_req;
> +               }
> +
> +               ret = gpio_direction_output(nreset_gpio, 0);
> +               if (ret < 0) {
> +                       dev_err(&dssdev->dev, "couldn't set GPIO direction\n");
> +                       goto fail_gpio_direction;
> +               }
> +       }
> +
> +       ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
> +       if (ret)
> +               dev_warn(&dssdev->dev, "failed to create sysfs files\n");
> +
> +       return 0;
> +
> +fail_gpio_direction:
> +       gpio_free(nreset_gpio);
> +fail_gpio_req:
> +       regulator_put(tpo_td043->vcc_reg);
> +fail_regulator:
> +       kfree(tpo_td043);
> +       return ret;
> +}
> +
> +static void tpo_td043_remove(struct omap_dss_device *dssdev)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
> +       int nreset_gpio = dssdev->reset_gpio;
> +
> +       dev_dbg(&dssdev->dev, "remove\n");
> +
> +       sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
> +       regulator_put(tpo_td043->vcc_reg);
> +       if (gpio_is_valid(nreset_gpio))
> +               gpio_free(nreset_gpio);
> +}
> +
> +static struct omap_dss_driver tpo_td043_driver = {
> +       .probe          = tpo_td043_probe,
> +       .remove         = tpo_td043_remove,
> +
> +       .enable         = tpo_td043_enable,
> +       .disable        = tpo_td043_disable,
> +       .suspend        = tpo_td043_suspend,
> +       .resume         = tpo_td043_resume,
> +       .set_mirror     = tpo_td043_set_hmirror,
> +       .get_mirror     = tpo_td043_get_hmirror,
> +
> +       .driver         = {
> +               .name   = "tpo_td043mtea1_panel",
> +               .owner  = THIS_MODULE,
> +       },
> +};
> +
> +static int tpo_td043_spi_probe(struct spi_device *spi)
> +{
> +       struct omap_dss_device *dssdev = spi->dev.platform_data;
> +       struct tpo_td043_device *tpo_td043;
> +       int ret;
> +
> +       if (dssdev = NULL) {
> +               dev_err(&spi->dev, "missing dssdev\n");
> +               return -ENODEV;
> +       }
> +
> +       spi->bits_per_word = 16;
> +       spi->mode = SPI_MODE_0;
> +
> +       ret = spi_setup(spi);
> +       if (ret < 0) {
> +               dev_err(&spi->dev, "spi_setup failed: %d\n", ret);
> +               return ret;
> +       }
> +
> +       tpo_td043 = kzalloc(sizeof(*tpo_td043), GFP_KERNEL);
> +       if (tpo_td043 = NULL)
> +               return -ENOMEM;
> +
> +       tpo_td043->spi = spi;
> +       dev_set_drvdata(&spi->dev, tpo_td043);
> +       dev_set_drvdata(&dssdev->dev, tpo_td043);
> +
> +       omap_dss_register_driver(&tpo_td043_driver);
> +
> +       return 0;
> +}
> +
> +static int __devexit tpo_td043_spi_remove(struct spi_device *spi)
> +{
> +       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev);
> +
> +       omap_dss_unregister_driver(&tpo_td043_driver);
> +       kfree(tpo_td043);
> +
> +       return 0;
> +}
> +
> +static struct spi_driver tpo_td043_spi_driver = {
> +       .driver = {
> +               .name   = "tpo_td043mtea1_panel_spi",
> +               .bus    = &spi_bus_type,
> +               .owner  = THIS_MODULE,
> +       },
> +       .probe  = tpo_td043_spi_probe,
> +       .remove = __devexit_p(tpo_td043_spi_remove),
> +};
> +
> +static int __init tpo_td043_init(void)
> +{
> +       return spi_register_driver(&tpo_td043_spi_driver);
> +}
> +
> +static void __exit tpo_td043_exit(void)
> +{
> +       spi_unregister_driver(&tpo_td043_spi_driver);
> +}
> +
> +module_init(tpo_td043_init);
> +module_exit(tpo_td043_exit);
> +
> +MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
> +MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
> +MODULE_LICENSE("GPL");
> --
> 1.6.3.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] OMAP: DSS: add TPO TD043MTEA1 panel
  2010-01-13  8:49 ` Tomi Valkeinen
@ 2010-01-13 11:06   ` Grazvydas Ignotas
  2010-01-13 11:33     ` Tomi Valkeinen
  0 siblings, 1 reply; 4+ messages in thread
From: Grazvydas Ignotas @ 2010-01-13 11:06 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: linux-fbdev@vger.kernel.org, linux-omap@vger.kernel.org

On Wed, Jan 13, 2010 at 10:49 AM, Tomi Valkeinen
<tomi.valkeinen@nokia.com> wrote:
> Hi,
>
> Sorry for the long time it took me to check this out. Checkpatch
> complains about indentation, I think the whole file is indented with
> spaces, not tabs.

No it isn't , maybe it's your mail client?
(latest mainline):
./scripts/checkpatch.pl --strict
/tmp/0001-OMAP-DSS-add-TPO-TD043MTEA1-panel.patch
total: 0 errors, 0 warnings, 0 checks, 503 lines checked

Here is the same patch as file (still applies cleanly on mainline):
http://notaz.gp2x.de/misc/pnd/0001-OMAP-DSS-add-TPO-TD043MTEA1-panel.patch


Gražvydas

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] OMAP: DSS: add TPO TD043MTEA1 panel
  2010-01-13 11:06   ` Grazvydas Ignotas
@ 2010-01-13 11:33     ` Tomi Valkeinen
  0 siblings, 0 replies; 4+ messages in thread
From: Tomi Valkeinen @ 2010-01-13 11:33 UTC (permalink / raw)
  To: ext Grazvydas Ignotas
  Cc: linux-fbdev@vger.kernel.org, linux-omap@vger.kernel.org

On Wed, 2010-01-13 at 12:06 +0100, ext Grazvydas Ignotas wrote:
> On Wed, Jan 13, 2010 at 10:49 AM, Tomi Valkeinen
> <tomi.valkeinen@nokia.com> wrote:
> > Hi,
> >
> > Sorry for the long time it took me to check this out. Checkpatch
> > complains about indentation, I think the whole file is indented with
> > spaces, not tabs.
> 
> No it isn't , maybe it's your mail client?
> (latest mainline):
> ./scripts/checkpatch.pl --strict
> /tmp/0001-OMAP-DSS-add-TPO-TD043MTEA1-panel.patch
> total: 0 errors, 0 warnings, 0 checks, 503 lines checked
> 
> Here is the same patch as file (still applies cleanly on mainline):
> http://notaz.gp2x.de/misc/pnd/0001-OMAP-DSS-add-TPO-TD043MTEA1-panel.patch

Strange. Maybe it's my mail client, although every other patch,
including your other patch, was fine. Well... That patch file works
fine. Thanks =).

 Tomi



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2010-01-13 11:33 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-11 19:30 [PATCH] OMAP: DSS: add TPO TD043MTEA1 panel Grazvydas Ignotas
2010-01-13  8:49 ` Tomi Valkeinen
2010-01-13 11:06   ` Grazvydas Ignotas
2010-01-13 11:33     ` Tomi Valkeinen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).