|
@@ -14,6 +14,7 @@
|
|
|
#include <linux/init.h>
|
|
|
#include <linux/device.h>
|
|
|
#include <linux/spi/spi.h>
|
|
|
+#include <linux/spi/tdo24m.h>
|
|
|
#include <linux/fb.h>
|
|
|
#include <linux/lcd.h>
|
|
|
|
|
@@ -31,6 +32,9 @@ struct tdo24m {
|
|
|
struct spi_transfer xfer;
|
|
|
uint8_t *buf;
|
|
|
|
|
|
+ int (*adj_mode)(struct tdo24m *lcd, int mode);
|
|
|
+ int color_invert;
|
|
|
+
|
|
|
int power;
|
|
|
int mode;
|
|
|
};
|
|
@@ -66,7 +70,7 @@ static uint32_t lcd_panel_off[] = {
|
|
|
CMD_NULL,
|
|
|
};
|
|
|
|
|
|
-static uint32_t lcd_vga_pass_through[] = {
|
|
|
+static uint32_t lcd_vga_pass_through_tdo24m[] = {
|
|
|
CMD1(0xB0, 0x16),
|
|
|
CMD1(0xBC, 0x80),
|
|
|
CMD1(0xE1, 0x00),
|
|
@@ -75,7 +79,7 @@ static uint32_t lcd_vga_pass_through[] = {
|
|
|
CMD_NULL,
|
|
|
};
|
|
|
|
|
|
-static uint32_t lcd_qvga_pass_through[] = {
|
|
|
+static uint32_t lcd_qvga_pass_through_tdo24m[] = {
|
|
|
CMD1(0xB0, 0x16),
|
|
|
CMD1(0xBC, 0x81),
|
|
|
CMD1(0xE1, 0x00),
|
|
@@ -84,7 +88,7 @@ static uint32_t lcd_qvga_pass_through[] = {
|
|
|
CMD_NULL,
|
|
|
};
|
|
|
|
|
|
-static uint32_t lcd_vga_transfer[] = {
|
|
|
+static uint32_t lcd_vga_transfer_tdo24m[] = {
|
|
|
CMD1(0xcf, 0x02), /* Blanking period control (1) */
|
|
|
CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */
|
|
|
CMD1(0xd1, 0x01), /* CKV timing control on/off */
|
|
@@ -110,6 +114,35 @@ static uint32_t lcd_qvga_transfer[] = {
|
|
|
CMD_NULL,
|
|
|
};
|
|
|
|
|
|
+static uint32_t lcd_vga_pass_through_tdo35s[] = {
|
|
|
+ CMD1(0xB0, 0x16),
|
|
|
+ CMD1(0xBC, 0x80),
|
|
|
+ CMD1(0xE1, 0x00),
|
|
|
+ CMD1(0x3B, 0x00),
|
|
|
+ CMD_NULL,
|
|
|
+};
|
|
|
+
|
|
|
+static uint32_t lcd_qvga_pass_through_tdo35s[] = {
|
|
|
+ CMD1(0xB0, 0x16),
|
|
|
+ CMD1(0xBC, 0x81),
|
|
|
+ CMD1(0xE1, 0x00),
|
|
|
+ CMD1(0x3B, 0x22),
|
|
|
+ CMD_NULL,
|
|
|
+};
|
|
|
+
|
|
|
+static uint32_t lcd_vga_transfer_tdo35s[] = {
|
|
|
+ CMD1(0xcf, 0x02), /* Blanking period control (1) */
|
|
|
+ CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */
|
|
|
+ CMD1(0xd1, 0x01), /* CKV timing control on/off */
|
|
|
+ CMD2(0xd2, 0x00, 0x1e), /* CKV 1,2 timing control */
|
|
|
+ CMD2(0xd3, 0x14, 0x28), /* OEV timing control */
|
|
|
+ CMD2(0xd4, 0x28, 0x64), /* ASW timing control (1) */
|
|
|
+ CMD1(0xd5, 0x28), /* ASW timing control (2) */
|
|
|
+ CMD0(0x21), /* Invert for normally black display */
|
|
|
+ CMD0(0x29), /* Display on */
|
|
|
+ CMD_NULL,
|
|
|
+};
|
|
|
+
|
|
|
static uint32_t lcd_panel_config[] = {
|
|
|
CMD2(0xb8, 0xff, 0xf9), /* Output control */
|
|
|
CMD0(0x11), /* sleep out */
|
|
@@ -148,6 +181,8 @@ static int tdo24m_writes(struct tdo24m *lcd, uint32_t *array)
|
|
|
int nparams, err = 0;
|
|
|
|
|
|
for (; *p != CMD_NULL; p++) {
|
|
|
+ if (!lcd->color_invert && *p == CMD0(0x21))
|
|
|
+ continue;
|
|
|
|
|
|
nparams = (*p >> 30) & 0x3;
|
|
|
|
|
@@ -184,12 +219,33 @@ static int tdo24m_adj_mode(struct tdo24m *lcd, int mode)
|
|
|
{
|
|
|
switch (mode) {
|
|
|
case MODE_VGA:
|
|
|
- tdo24m_writes(lcd, lcd_vga_pass_through);
|
|
|
+ tdo24m_writes(lcd, lcd_vga_pass_through_tdo24m);
|
|
|
tdo24m_writes(lcd, lcd_panel_config);
|
|
|
- tdo24m_writes(lcd, lcd_vga_transfer);
|
|
|
+ tdo24m_writes(lcd, lcd_vga_transfer_tdo24m);
|
|
|
break;
|
|
|
case MODE_QVGA:
|
|
|
- tdo24m_writes(lcd, lcd_qvga_pass_through);
|
|
|
+ tdo24m_writes(lcd, lcd_qvga_pass_through_tdo24m);
|
|
|
+ tdo24m_writes(lcd, lcd_panel_config);
|
|
|
+ tdo24m_writes(lcd, lcd_qvga_transfer);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ lcd->mode = mode;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int tdo35s_adj_mode(struct tdo24m *lcd, int mode)
|
|
|
+{
|
|
|
+ switch (mode) {
|
|
|
+ case MODE_VGA:
|
|
|
+ tdo24m_writes(lcd, lcd_vga_pass_through_tdo35s);
|
|
|
+ tdo24m_writes(lcd, lcd_panel_config);
|
|
|
+ tdo24m_writes(lcd, lcd_vga_transfer_tdo35s);
|
|
|
+ break;
|
|
|
+ case MODE_QVGA:
|
|
|
+ tdo24m_writes(lcd, lcd_qvga_pass_through_tdo35s);
|
|
|
tdo24m_writes(lcd, lcd_panel_config);
|
|
|
tdo24m_writes(lcd, lcd_qvga_transfer);
|
|
|
break;
|
|
@@ -213,7 +269,7 @@ static int tdo24m_power_on(struct tdo24m *lcd)
|
|
|
if (err)
|
|
|
goto out;
|
|
|
|
|
|
- err = tdo24m_adj_mode(lcd, lcd->mode);
|
|
|
+ err = lcd->adj_mode(lcd, lcd->mode);
|
|
|
out:
|
|
|
return err;
|
|
|
}
|
|
@@ -262,7 +318,7 @@ static int tdo24m_set_mode(struct lcd_device *ld, struct fb_videomode *m)
|
|
|
if (lcd->mode == mode)
|
|
|
return 0;
|
|
|
|
|
|
- return tdo24m_adj_mode(lcd, mode);
|
|
|
+ return lcd->adj_mode(lcd, mode);
|
|
|
}
|
|
|
|
|
|
static struct lcd_ops tdo24m_ops = {
|
|
@@ -276,8 +332,16 @@ static int __devinit tdo24m_probe(struct spi_device *spi)
|
|
|
struct tdo24m *lcd;
|
|
|
struct spi_message *m;
|
|
|
struct spi_transfer *x;
|
|
|
+ struct tdo24m_platform_data *pdata;
|
|
|
+ enum tdo24m_model model;
|
|
|
int err;
|
|
|
|
|
|
+ pdata = spi->dev.platform_data;
|
|
|
+ if (pdata)
|
|
|
+ model = pdata->model;
|
|
|
+ else
|
|
|
+ model = TDO24M;
|
|
|
+
|
|
|
spi->bits_per_word = 8;
|
|
|
spi->mode = SPI_MODE_3;
|
|
|
err = spi_setup(spi);
|
|
@@ -306,6 +370,20 @@ static int __devinit tdo24m_probe(struct spi_device *spi)
|
|
|
x->tx_buf = &lcd->buf[0];
|
|
|
spi_message_add_tail(x, m);
|
|
|
|
|
|
+ switch (model) {
|
|
|
+ case TDO24M:
|
|
|
+ lcd->color_invert = 1;
|
|
|
+ lcd->adj_mode = tdo24m_adj_mode;
|
|
|
+ break;
|
|
|
+ case TDO35S:
|
|
|
+ lcd->adj_mode = tdo35s_adj_mode;
|
|
|
+ lcd->color_invert = 0;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ dev_err(&spi->dev, "Unsupported model");
|
|
|
+ goto out_free;
|
|
|
+ }
|
|
|
+
|
|
|
lcd->lcd_dev = lcd_device_register("tdo24m", &spi->dev,
|
|
|
lcd, &tdo24m_ops);
|
|
|
if (IS_ERR(lcd->lcd_dev)) {
|