add RGB to MIPI tc358768 driver and reference lcd driver
authorhhb <hhb@rock-chips.com>
Tue, 20 Nov 2012 10:01:01 +0000 (18:01 +0800)
committerhhb <hhb@rock-chips.com>
Tue, 20 Nov 2012 10:01:01 +0000 (18:01 +0800)
drivers/video/display/screen/Kconfig
drivers/video/display/screen/Makefile
drivers/video/display/screen/lcd_tl5001_mipi.c [new file with mode: 0644]
drivers/video/display/transmitter/Kconfig
drivers/video/display/transmitter/Makefile
drivers/video/display/transmitter/tc358768.c [new file with mode: 0644]
drivers/video/display/transmitter/tc358768.h [new file with mode: 0644]

index 0e3b0b6f856641e4a038210f475e30bfc35f3856..b31bd70ff39b8f500d04d61cf8c3e76ca6505248 100755 (executable)
@@ -114,6 +114,9 @@ config LCD_HSD07PFW1
 
 config LCD_I30_800X480
         bool "lcd I30"
+config LCD_TL5001_MIPI
+       bool "TL5001 720X1280"
+
 endchoice
 
 
index 5c938df3c816b4b9b1417663da37b93334422b7e..bf64b2c23fd0c5212a7043cc214c3d3086362572 100755 (executable)
@@ -50,3 +50,4 @@ obj-$(CONFIG_LCD_HJ080NA)    += lcd_hj080na.o
 obj-$(CONFIG_LCD_HJ101NA)   += lcd_hj101na.o
 obj-$(CONFIG_LCD_AUTO)   += lcd_auto.o
 obj-$(CONFIG_LCD_I30_800X480)   += lcd_I30_800x480.o
+obj-$(CONFIG_LCD_TL5001_MIPI)    += lcd_tl5001_mipi.o
diff --git a/drivers/video/display/screen/lcd_tl5001_mipi.c b/drivers/video/display/screen/lcd_tl5001_mipi.c
new file mode 100644 (file)
index 0000000..b9b4135
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2012 ROCKCHIP, Inc.
+ *
+ * author: hhb@rock-chips.com
+ * creat date: 2012-04-19
+ * route:drivers/video/display/screen/lcd_hj050na_06a.c
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/rk_fb.h>
+#include <mach/gpio.h>
+#include <mach/iomux.h>
+#include <mach/board.h>
+#include <linux/rk_screen.h>
+#include <linux/ktime.h>
+#include "../transmitter/tc358768.h"
+
+/* Base */
+#define OUT_TYPE           SCREEN_RGB
+#define OUT_FACE           OUT_P888
+#define BYTE_PP                3    //bytes per pixel
+
+
+#define OUT_CLK                 65000000  //  in fact it is 61384615
+#define LCDC_ACLK        300000000
+
+/* Timing */
+#define H_PW                   10
+#define H_BP                   20
+#define H_VD                   720
+#define H_FP                   82
+
+#define V_PW                   8
+#define V_BP                   6
+#define V_VD                   1280
+#define V_FP                   4
+
+
+#define LCD_WIDTH       62    //uint mm the lenth of lcd active area
+#define LCD_HEIGHT      111
+/* Other */
+#define VSYNC_POL              0
+#define HSYNC_POL              VSYNC_POL
+#define DCLK_POL               1
+#define DEN_POL         0 //positive
+#define SWAP_RB                        0
+
+
+#define LCD_TEST 0
+#define CONFIG_DEEP_STANDBY_MODE 0
+#define CONFIG_TC358768_INIT_MODE     0   //1:ARRAY  0:FUNCTION
+
+#define dsi_init(data)                                 mipi_dsi.dsi_init(data, ARRAY_SIZE(data))
+#define dsi_send_dcs_packet(data)      mipi_dsi.dsi_send_dcs_packet(data, ARRAY_SIZE(data))
+#define dsi_hs_start(data)                     mipi_dsi.dsi_hs_start(data, ARRAY_SIZE(data))
+
+#define lap_define ktime_t k0,k1;
+#define lap_start  k0 = ktime_get();
+#define lap_end  { k1 = ktime_get(); k1 = ktime_sub(k1, k0); }
+
+static struct rk29lcd_info *gLcd_info = NULL;
+struct mipi_dsi_t mipi_dsi;
+struct tc358768_t *lcd_tc358768 = NULL;
+
+int lcd_init(void);
+int lcd_standby(u8 enable);
+
+
+#if CONFIG_TC358768_INIT_MODE
+struct spi_cmd_data32 {
+     unsigned int delay;
+     unsigned int value;
+};
+
+struct spi_cmd_data32 TC358768XBG_INIT[] = {
+
+     {0xffffffff,    0xffffffff}
+};
+
+#else
+
+//high speed mode
+static unsigned int re_initialize[] = {
+
+
+};
+
+static unsigned int initialize[] = {
+// **************************************************
+// Initizlize  -> Display On after power-on
+// **************************************************
+// **************************************************
+// Power on TC358768XBG according to recommended power-on sequence
+// Relase reset (RESX="H")
+// Start input REFCK and PCLK
+// **************************************************
+// **************************************************
+// TC358768XBG Software Reset
+// **************************************************
+    0x00020001, //SYSctl, S/W Reset
+    10, 
+    0x00020000, //SYSctl, S/W Reset release
+
+// **************************************************
+// TC358768XBG PLL,Clock Setting
+// **************************************************
+    0x00161063, //PLL Control Register 0 (PLL_PRD,PLL_FBD)
+    0x00180603, //PLL_FRS,PLL_LBWS, PLL oscillation enable
+    1000, 
+    0x00180613, //PLL_FRS,PLL_LBWS, PLL clock out enable
+
+// **************************************************
+// TC358768XBG DPI Input Control
+// **************************************************
+    0x00060032, //FIFO Control Register
+
+// **************************************************
+// TC358768XBG D-PHY Setting
+// **************************************************
+    0x01400000, //D-PHY Clock lane enable
+    0x01420000, //
+    0x01440000, //D-PHY Data lane0 enable
+    0x01460000, //
+    0x01480000, //D-PHY Data lane1 enable
+    0x014A0000, //
+    0x014C0000, //D-PHY Data lane2 enable
+    0x014E0000, //
+    0x01500000, //D-PHY Data lane3 enable
+    0x01520000, //
+
+// **************************************************
+// TC358768XBG DSI-TX PPI Control
+// **************************************************
+    0x021009C4, //LINEINITCNT
+    0x02120000, //
+    0x02140002, //LPTXTIMECNT
+    0x02160000, //
+    0x02200002, //THS_HEADERCNT
+    0x02220000, //
+    0x02244268, //TWAKEUPCNT
+    0x02260000, //
+    0x022C0001, //THS_TRAILCNT
+    0x022E0000, //
+    0x02300005, //HSTXVREGCNT
+    0x02320000, //
+    0x0234001F, //HSTXVREGEN enable
+    0x02360000, //
+    0x02380001, //DSI clock Enable/Disable during LP
+    0x023A0000, //
+    0x023C0001, //BTACNTRL1
+    0x023E0002, //
+    0x02040001, //STARTCNTRL
+    0x02060000, //
+
+// **************************************************
+// TC358768XBG DSI-TX Timing Control
+// **************************************************
+    0x06200001, //Sync Pulse/Sync Event mode setting
+    0x0622000E, //V Control Register1
+    0x06240006, //V Control Register2
+    0x06260500, //V Control Register3
+    0x0628005E, //H Control Register1
+    0x062A003F, //H Control Register2
+    0x062C0870, //H Control Register3
+
+    0x05180001, //DSI Start
+    0x051A0000, //
+
+};
+
+
+
+static unsigned int start_dsi_hs_mode[] = {
+
+// **************************************************
+// Set to HS mode
+// **************************************************
+    0x05000087, //DSI lane setting, DSI mode=HS
+    0x0502A300, //bit set
+    0x05008000, //Switch to DSI mode
+    0x0502C300, //
+
+// **************************************************
+// Host: RGB(DPI) input start
+// **************************************************
+
+    0x00080037, //DSI-TX Format setting
+    0x0050003E, //DSI-TX Pixel stream packet Data Type setting
+    0x00040044 //Configuration Control Register
+
+
+};
+
+#endif
+
+static unsigned char boe_set_extension_command[] = {0xB9, 0xFF, 0x83, 0x94};
+static unsigned char boe_set_MIPI_ctrl[] = {0xBA, 0x13};
+static unsigned char boe_set_power[] = {0xB1, 0x7C, 0x00, 0x34, 0x09, 0x01, 0x11, 0x11, 0x36, 0x3E, 0x26, 0x26, 0x57, 0x12, 0x01, 0xE6};
+static unsigned char boe_setcyc[] = {0xB4, 0x00, 0x00, 0x00, 0x05, 0x06, 0x41, 0x42, 0x02, 0x41, 0x42, 0x43, 0x47, 0x19, 0x58, 
+                                       0x60, 0x08, 0x85, 0x10};
+static unsigned char boe_config05[] = {0xC7, 0x00,     0x20};
+static unsigned char boe_set_gip[] = {0xD5,0x4C,0x01,0x00,0x01,0xCD,0x23,0xEF,0x45,0x67,0x89,0xAB,0x11,0x00,0xDC,0x10,0xFE,0x32,
+                                       0xBA,0x98,0x76,0x54,0x00,0x11,0x40};   
+                                       
+//static unsigned char boe_set_panel[] = {0xCC, 0x01};
+//static unsigned char boe_set_vcom[] = {0xB6, 0x2a};
+static unsigned char boe_set_panel[] = {0xCC, 0x05};
+static unsigned char boe_set_vcom[] = {0xB6, 0x31};
+
+static unsigned char boe_set_gamma[] = {0xE0,0x24,0x33,0x36,0x3F,0x3f,0x3f,0x3c,0x56,0x05,0x0C,0x0e,0x11,0x13,0x12,0x14,0x12,0x1e,
+                                       0x24,0x33,0x36,0x3F,0x3f,0x3F,0x3c,0x56,0x05,0x0c, 0x0e,0x11,0x13,0x12,0x14,0x12, 0x1e};        //
+static unsigned char boe_set_addr_mode[] = {0x36, 0x00};
+static unsigned char boe_set_pixel[] = {0x3a, 0x60};
+
+static unsigned char boe_enter_sleep_mode[] = {0x10};
+static unsigned char boe_exit_sleep_mode[] = {0x11};
+static unsigned char boe_set_diaplay_on[] = {0x29};
+static unsigned char boe_set_diaplay_off[] = {0x28};
+static unsigned char boe_enter_invert_mode[] = {0x21};
+static unsigned char boe_all_pixel_on[] = {0x23};
+static unsigned char boe_set_id[] = {0xc3, 0xaa, 0x55, 0xee};
+
+
+void lcd_power_on(void) {
+
+
+}
+
+void lcd_power_off(void) {
+
+
+}
+#if LCD_TEST
+void lcd_test(void) {
+       u8 buf[8];
+       printk("**mipi lcd test\n");
+    buf[0] = 0x0c;
+       mipi_dsi.dsi_read_dcs_packet(buf, 1);
+       printk("**Get_pixel_format 0x0c:%02x\n", buf[0]);
+       buf[0] = 0x0a;
+       mipi_dsi.dsi_read_dcs_packet(buf, 1);
+       printk("**Get_power_mode 0x0a:%02x\n", buf[0]);
+       buf[0] = 0x0f;
+       mipi_dsi.dsi_read_dcs_packet(buf, 1);
+       printk("**Get_diagnostic_result 0x0f:%02x\n", buf[0]);
+    buf[0] = 0x09;
+       mipi_dsi.dsi_read_dcs_packet(buf, 4);
+       printk("**Read Display Status 0x09:%02x,%02x,%02x,%02x\n", buf[0],buf[1],buf[2],buf[3]);
+}
+#endif
+
+
+
+static unsigned char boe_set_wrdisbv[] = {0x51, 0xff};
+static unsigned char boe_set_wrctrld[] = {0x53, 0x24};
+static unsigned char boe_set_wrcabc[] = {0x55, 0x02};
+static unsigned char boe_set_wrcabcmb[] = {0x5e, 0x0};
+static unsigned char boe_set_cabc[] = {0xc9, 0x0d, 0x01, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0};
+static unsigned char boe_set_cabc_gain[] = {0xca, 0x32, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20};
+
+
+void lcd_cabc(u8 brightness) {
+       
+}
+
+
+
+int lcd_init(void)
+{
+   
+    int i = 0;
+    lap_define
+    //power on
+    lcd_tc358768->power_up(NULL);
+    
+       if(gLcd_info)
+        gLcd_info->io_init();
+
+    i = 0;
+    lap_start
+       //Re-Initialize
+#if CONFIG_TC358768_INIT_MODE
+    i = 0;
+    while (1) {
+       if(TC358768XBG_INIT[i].delay == 0xffffffff)
+               break;
+       tc358768_wr_reg_32bits_delay(TC358768XBG_INIT[i].delay, TC358768XBG_INIT[i].value);
+       i++;
+    }
+#else
+       dsi_init(initialize);
+   
+       
+    //lcd init
+    dsi_send_dcs_packet(boe_exit_sleep_mode);
+    msleep(150);
+    dsi_send_dcs_packet(boe_set_extension_command);
+    msleep(1);
+    dsi_send_dcs_packet(boe_set_MIPI_ctrl);
+    msleep(1);
+    dsi_send_dcs_packet(boe_set_power);
+    msleep(1);
+    dsi_send_dcs_packet(boe_setcyc);
+    msleep(1);
+    dsi_send_dcs_packet(boe_set_vcom);
+    msleep(1);
+    dsi_send_dcs_packet(boe_set_panel);
+    msleep(1);
+    dsi_send_dcs_packet(boe_set_gip);
+    msleep(1);
+    dsi_send_dcs_packet(boe_set_gamma);
+    msleep(1);
+    dsi_send_dcs_packet(boe_set_addr_mode);
+    msleep(1);
+    dsi_send_dcs_packet(boe_set_diaplay_on);
+#if LCD_TEST    
+    lcd_test();
+#endif    
+    dsi_hs_start(start_dsi_hs_mode);
+    
+       msleep(10);
+#endif
+    lap_end
+    printk(">>time:%lld\n", k1.tv64);
+    return 0;
+
+}
+
+int lcd_standby(u8 enable)
+{
+       //int ret = 0;
+       if(enable) {
+
+           printk("suspend lcd\n");
+               //power down
+           if(gLcd_info)
+               gLcd_info->io_deinit();
+               
+           lcd_tc358768->power_down(NULL);    
+               
+       } else {
+               lcd_init();
+       }
+
+    return 0;
+}
+
+void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info )
+{
+    /* screen type & face */
+    screen->type = OUT_TYPE;
+    screen->face = OUT_FACE;
+
+    /* Screen size */
+    screen->x_res = H_VD;
+    screen->y_res = V_VD;
+
+    screen->width = LCD_WIDTH;
+    screen->height = LCD_HEIGHT;
+
+    /* Timing */
+    screen->lcdc_aclk = LCDC_ACLK;
+    screen->pixclock = OUT_CLK;
+       screen->left_margin = H_BP;
+       screen->right_margin = H_FP;
+       screen->hsync_len = H_PW;
+       screen->upper_margin = V_BP;
+       screen->lower_margin = V_FP;
+       screen->vsync_len = V_PW;
+
+       /* Pin polarity */
+       screen->pin_hsync = HSYNC_POL;
+       screen->pin_vsync = VSYNC_POL;
+       screen->pin_den = DEN_POL;
+       screen->pin_dclk = DCLK_POL;
+
+       /* Swap rule */
+    screen->swap_rb = SWAP_RB;
+    screen->swap_rg = 0;
+    screen->swap_gb = 0;
+    screen->swap_delta = 0;
+    screen->swap_dumy = 0;
+
+    /* Operation function*/
+    screen->init = lcd_init;
+    screen->standby = lcd_standby;
+
+    if(lcd_info)
+        gLcd_info = lcd_info;
+    
+    if(tc358768_init(&mipi_dsi) == 0)
+       lcd_tc358768 = (struct tc358768_t *)mipi_dsi.chip;
+    else
+       printk("%s: %s:%d",__FILE__, __func__, __LINE__);       
+
+}
index 5565f72d0cf8f63869efde0c4d17c7532192f7af..bd4421f2ef76c6b6a718a8f0f024d6ac6fa7f5ad 100644 (file)
@@ -4,3 +4,8 @@ config RK610_LVDS
        default y if MFD_RK610
        help
                Support Jetta(RK610) to output LCD1 and LVDS.
+               
+config TC358768_RGB2MIPI
+       bool "toshiba RGB to MIPI DSI"
+       help
+               "a chip that change RGB interface parallel signal into DSI serial signal"
index 75adab5b4151f1e057df23eb28317353422d63bb..65454d87f7ee5eccf3a575bcaee8d0fed34ad839 100644 (file)
@@ -2,3 +2,4 @@
 # Makefile for the jetta tv control.
 #
 obj-$(CONFIG_RK610_LVDS)                       += rk610_lcd.o
+obj-$(CONFIG_TC358768_RGB2MIPI)   += tc358768.o
diff --git a/drivers/video/display/transmitter/tc358768.c b/drivers/video/display/transmitter/tc358768.c
new file mode 100644 (file)
index 0000000..7beb9e4
--- /dev/null
@@ -0,0 +1,689 @@
+/*
+ * Copyright (C) 2012 ROCKCHIP, Inc.
+ *
+ * author: hhb@rock-chips.com
+ * create date: 2012-10-26
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#include "tc358768.h"
+
+#if 0
+#define dsi_debug   printk
+#else
+#define dsi_debug(fmt...)   do { } while (0)
+#endif
+
+#ifdef CONFIG_TC358768_I2C
+struct tc358768_t *tc358768 = NULL;
+struct i2c_client *tc358768_client = NULL;
+struct mipi_dsi_t *dsi;
+
+
+u32 i2c_write_32bits(u32 value) 
+{
+       struct i2c_msg msgs;
+       int ret = -1;
+       char buf[4];
+       buf[0] = value>>24;
+       buf[1] = value>>16;
+       buf[2] = value>>8;
+       buf[3] = value;
+       
+       msgs.addr = tc358768_client->addr;
+       msgs.flags = tc358768_client->flags;
+       msgs.len = 4;
+       msgs.buf = buf;
+       msgs.scl_rate = CONFIG_TC358768_I2C_CLK;
+       msgs.udelay = tc358768_client->udelay;
+
+       ret = i2c_transfer(tc358768_client->adapter, &msgs, 1);
+       if(ret < 0)
+               printk("%s:i2c_transfer fail =%d\n",__func__, ret);
+       return ret;
+}
+
+u32 i2c_read_32bits(u32 value) 
+{
+       struct i2c_msg msgs[2];
+       int ret = -1;
+       char buf[4];
+       buf[0] = value>>8;
+       buf[1] = value;
+       
+       msgs[0].addr = tc358768_client->addr;
+       msgs[0].flags = tc358768_client->flags;
+       msgs[0].len = 2;
+       msgs[0].buf = buf;
+       msgs[0].scl_rate = CONFIG_TC358768_I2C_CLK;
+       msgs[0].udelay = tc358768_client->udelay;
+
+       msgs[1].addr = tc358768_client->addr;
+       msgs[1].flags = tc358768_client->flags | I2C_M_RD;
+       msgs[1].len = 2;
+       msgs[1].buf = buf;
+       msgs[1].scl_rate = CONFIG_TC358768_I2C_CLK;
+       msgs[1].udelay = tc358768_client->udelay;
+
+       ret = i2c_transfer(tc358768_client->adapter, msgs, 2);
+       if(ret < 0)
+               printk("%s:i2c_transfer fail =%d\n",__func__, ret);
+       else
+               ret = (buf[0]<<8) | buf[1];     
+       
+       return ret;
+}
+
+
+int tc358768_gpio_init(void *data) {
+       int ret = 0;
+       struct reset_t *reset = &tc358768->reset;
+       struct power_t *vdd = &tc358768->vddc;
+       if(reset->reset_pin > INVALID_GPIO) {
+               ret = gpio_request(reset->reset_pin, "tc358768_reset");
+               if (ret != 0) {
+                       gpio_free(reset->reset_pin);
+                       printk("%s: request TC358768_RST_PIN error\n", __func__);
+               } else {
+                       if(reset->mux_name)
+                               rk30_mux_api_set(reset->mux_name, reset->mux_mode);
+                       gpio_direction_output(reset->reset_pin, reset->effect_value);
+               }
+       }
+       
+       if(vdd->enable_pin > INVALID_GPIO) {
+               ret = gpio_request(vdd->enable_pin, "tc358768_vddc");
+               if (ret != 0) {
+                       gpio_free(vdd->enable_pin);
+                       printk("%s: request TC358768_vddc_PIN error\n", __func__);
+               } else {
+                       if(vdd->mux_name)
+                               rk30_mux_api_set(vdd->mux_name, vdd->mux_mode); 
+                       gpio_direction_output(vdd->enable_pin, !vdd->effect_value);
+               }
+       }
+       
+       vdd = &tc358768->vddio;
+       if(vdd->enable_pin > INVALID_GPIO) {
+               ret = gpio_request(vdd->enable_pin, "tc358768_vddio");
+               if (ret != 0) {
+                       gpio_free(vdd->enable_pin);
+                       printk("%s: request TC358768_vddio_PIN error\n", __func__);
+               } else {
+                       if(vdd->mux_name)
+                               rk30_mux_api_set(vdd->mux_name, vdd->mux_mode); 
+                       gpio_direction_output(vdd->enable_pin, !vdd->effect_value);     
+               }
+       }
+       
+       vdd = &tc358768->vdd_mipi;
+       if(vdd->enable_pin > INVALID_GPIO) {
+               ret = gpio_request(vdd->enable_pin, "tc358768_vdd_mipi");
+               if (ret != 0) {
+                       gpio_free(vdd->enable_pin);
+                       printk("%s: request TC358768_vdd_mipi_PIN error\n", __func__);
+               } else {
+                       if(vdd->mux_name)
+                               rk30_mux_api_set(vdd->mux_name, vdd->mux_mode); 
+                       gpio_direction_output(vdd->enable_pin, !vdd->effect_value);     
+               }
+       }
+       return 0;
+
+}
+
+int tc358768_gpio_deinit(void *data) {
+       struct reset_t *reset = &tc358768->reset;
+       struct power_t *vdd = &tc358768->vddc;
+       gpio_free(reset->reset_pin);
+       
+       vdd = &tc358768->vddio;
+       gpio_free(vdd->enable_pin);
+       
+       vdd = &tc358768->vdd_mipi;
+       gpio_free(vdd->enable_pin);
+       return 0;
+}
+
+int tc358768_reset(void *data) {
+       int ret = 0;
+       struct reset_t *reset = &tc358768->reset;
+       if(reset->reset_pin <= INVALID_GPIO)
+               return -1;
+       gpio_set_value(reset->reset_pin, reset->effect_value);
+       if(reset->time_before_reset <= 0)
+               msleep(1);
+       else
+               msleep(reset->time_before_reset);
+       
+       gpio_set_value(reset->reset_pin, !reset->effect_value);
+       if(reset->time_after_reset <= 0)
+               msleep(5);
+       else
+               msleep(reset->time_after_reset);
+       return ret;     
+}
+
+int tc358768_vdd_enable(void *data) {
+       int ret = 0;
+       struct power_t *vdd = (struct power_t *)data;
+       if(vdd->enable_pin > INVALID_GPIO) {
+               gpio_set_value(vdd->enable_pin, vdd->effect_value);
+       } else {
+               //for other control
+       }
+       return ret;
+}
+
+int tc358768_vdd_disable(void *data) {
+       int ret = 0;
+       struct power_t *vdd = (struct power_t *)data;
+       
+       if(vdd->enable_pin > INVALID_GPIO) {
+               gpio_set_value(vdd->enable_pin, !vdd->effect_value);
+       } else {
+               //for other control
+       }
+       return ret;
+}
+
+
+int tc358768_power_up(void *data) {
+       int ret = 0;
+       struct tc358768_t *tc = (struct tc358768_t *)tc358768;
+       
+       tc->vddc.enable(&tc->vddc);
+       tc->vdd_mipi.enable(&tc->vdd_mipi);
+       tc->vddio.enable(&tc->vddio);
+       tc->reset.do_reset(&tc->reset);
+       
+       return ret;
+}
+
+int tc358768_power_down(void *data) {
+       int ret = 0;
+       struct tc358768_t *tc = (struct tc358768_t *)tc358768;
+       
+       tc->vddio.disable(&tc->vddio);
+       tc->vdd_mipi.disable(&tc->vdd_mipi);
+       tc->vddc.disable(&tc->vddc);
+       
+       return ret;
+}
+
+static int tc358768_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did) 
+{
+    struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+    
+    int ret = 0;
+
+    if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+        dev_warn(&adapter->dev,
+                "I2C-Adapter doesn't support I2C_FUNC_I2C\n");
+        return -EIO;
+    }
+    tc358768 = (struct tc358768_t *)client->dev.platform_data;
+    if(!tc358768) {
+       ret = -1;
+       printk("%s:%d tc358768 is null\n", __func__, __LINE__);
+       return ret;
+    }  
+    
+    tc358768_client = client;
+    if(!tc358768_client) {
+       ret = -1;
+       printk("%s:%d tc358768_client is null\n", __func__, __LINE__);
+       return ret;
+    }
+    
+    if(!tc358768->gpio_init)
+       tc358768->gpio_init = tc358768_gpio_init;
+       
+    if(!tc358768->gpio_deinit)
+       tc358768->gpio_deinit = tc358768_gpio_deinit;    
+    
+    if(!tc358768->power_up)
+       tc358768->power_up = tc358768_power_up;  
+    if(!tc358768->power_down)
+       tc358768->power_down = tc358768_power_down;     
+    
+    if(!tc358768->reset.do_reset)
+       tc358768->reset.do_reset = tc358768_reset;
+    
+    if(!tc358768->vddc.enable)
+       tc358768->vddc.enable = tc358768_vdd_enable;    
+    if(!tc358768->vddc.disable)
+       tc358768->vddc.disable = tc358768_vdd_disable;
+    
+    if(!tc358768->vddio.enable)
+       tc358768->vddio.enable = tc358768_vdd_enable;    
+    if(!tc358768->vddio.disable)
+       tc358768->vddio.disable = tc358768_vdd_disable;
+    
+    if(!tc358768->vdd_mipi.enable)
+       tc358768->vdd_mipi.enable = tc358768_vdd_enable;    
+    if(!tc358768->vdd_mipi.disable)
+       tc358768->vdd_mipi.disable = tc358768_vdd_disable;
+       
+    dsi->chip = tc358768;      
+       
+    return ret;
+}
+static int tc358768_remove(struct i2c_client *client)
+{
+    tc358768_client = NULL;
+    tc358768 = NULL;
+    return 0;
+}
+
+static const struct i2c_device_id tc358768_id[] = {
+       {"tc358768", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tc358768_id);
+
+static struct i2c_driver tc358768_driver = {
+       .probe          = tc358768_probe,
+       .remove         = tc358768_remove,
+       .id_table       = tc358768_id,
+       .driver = {
+               .name   = "tc358768",
+       },
+};
+#else
+
+u32 spi_read_32bits(u32 addr)
+{
+       unsigned int i = 32;
+       //a frame starts
+       CS_CLR();
+       CLK_SET();
+
+       addr <<= 16;
+       addr &= 0xfffe0000;
+       addr |= 0x00010000;
+
+       udelay(2);
+       while(i--) {
+               CLK_CLR();
+               if(addr & 0x80000000)
+                       TXD_SET();
+        else
+                       TXD_CLR();
+               addr <<= 1;
+               udelay(2);
+               CLK_SET();
+               udelay(2);
+       }
+       //a frame ends
+    CS_SET();
+
+
+    udelay(2);
+    CS_CLR();
+    addr = 0xfffe0000;
+    i = 16;
+       while(i--) {
+               CLK_CLR();
+               if(addr & 0x80000000)
+                       TXD_SET();
+        else
+                       TXD_CLR();
+               addr <<= 1;
+               udelay(2);
+               CLK_SET();
+               udelay(2);
+       }
+
+       TXD_SET();
+
+       addr = 0;
+    i = 16;
+       while(i--) {
+               CLK_CLR();
+               udelay(1);
+               CLK_SET();
+               udelay(1);
+               if (gpio_get_value(gLcd_info->rxd_pin) == 1)
+                       addr |= 1 << i;
+               udelay(1);
+       }
+    CS_SET();
+
+    return addr;
+}
+
+
+//32 bits per frame
+u32 spi_write_32bits(u32 value)
+{
+       int i = 32;
+
+    //a frame starts
+       CS_CLR();
+       CLK_SET();
+
+       while(i--) {
+               CLK_CLR();
+               if(value & 0x80000000)
+                       TXD_SET();
+        else
+                       TXD_CLR();
+               value <<= 1;
+               CLK_SET();
+       }
+       //a frame ends
+    CS_SET();
+
+    return 0;
+}
+
+#endif
+
+u32 tc358768_wr_reg_32bits(u32 data) {
+#ifdef CONFIG_TC358768_I2C
+       i2c_write_32bits(data);
+#else
+       spi_write_32bits(data);
+#endif
+       return 0;
+}
+
+
+u32 tc358768_wr_reg_32bits_delay(u32 delay, u32 data) {
+       //wait a minute  according to the source format
+    if(delay < 20000)
+       udelay(delay);
+    else {
+       mdelay(delay/1000);
+    }
+
+#ifdef CONFIG_TC358768_I2C
+       i2c_write_32bits(data);
+#else
+       spi_write_32bits(data);
+#endif
+       return 0;
+}
+
+
+
+u32 tc358768_rd_reg_32bits(u32 addr) {
+#ifdef CONFIG_TC358768_I2C
+       return i2c_read_32bits(addr);
+#else
+       return spi_read_32bits(addr);
+#endif
+}
+
+
+
+void tc_print(u32 addr) {
+       dsi_debug("+++++++++++addr->%04x: %04x\n", addr, tc358768_rd_reg_32bits(addr));
+}
+
+#define tc358768_wr_regs_32bits(reg_array)  _tc358768_wr_regs_32bits(reg_array, ARRAY_SIZE(reg_array))
+int _tc358768_wr_regs_32bits(unsigned int reg_array[], int n) {
+
+       int i = 0;
+       dsi_debug("%s:%d\n", __func__, n);
+       for(i = 0; i < n; i++) {
+               if(reg_array[i] < 0x00020000) {
+                   if(reg_array[i] < 20000)
+                       udelay(reg_array[i]);
+                   else {
+                       mdelay(reg_array[i]/1000);
+                   }
+               } else {
+                       tc358768_wr_reg_32bits(reg_array[i]);
+               }
+       }
+       return 0;
+}
+
+int tc358768_command_tx_less8bytes(unsigned char type, unsigned char *regs, int n) {
+       int i = 0;
+       unsigned int command[] = {
+                       0x06020000,
+                       0x06040000,
+                       0x06100000,
+                       0x06120000,
+                       0x06140000,
+                       0x06160000,
+       };
+
+       if(n <= 2)
+               command[0] |= 0x1000;   //short packet
+       else {
+               command[0] |= 0x4000;   //long packet
+               command[1] |= n;                //word count byte
+       }
+       command[0] |= type;         //data type
+
+       //dsi_debug("*cmd:\n");
+       //dsi_debug("0x%08x\n", command[0]);
+       //dsi_debug("0x%08x\n", command[1]);
+
+       for(i = 0; i < (n + 1)/2; i++) {
+               command[i+2] |= regs[i*2];
+               if((i*2 + 1) < n)
+                       command[i+2] |= regs[i*2 + 1] << 8;
+               dsi_debug("0x%08x\n", command[i+2]);
+       }
+
+       _tc358768_wr_regs_32bits(command, (n + 1)/2 + 2);
+       tc358768_wr_reg_32bits(0x06000001);   //Packet Transfer
+       //wait until packet is out
+       i = 100;
+       while(tc358768_rd_reg_32bits(0x0600) & 0x01) {
+               if(i-- == 0)
+                       break;
+               tc_print(0x0600);
+       }
+       //udelay(50);
+       return 0;
+}
+
+int tc358768_command_tx_more8bytes_hs(unsigned char type, unsigned char regs[], int n) {
+
+       int i = 0;
+       unsigned int dbg_data = 0x00E80000, temp = 0;
+       unsigned int command[] = {
+                       0x05000080,    //HS data 4 lane, EOT is added
+                       0x0502A300,
+                       0x00080001,
+                       0x00500000,    //Data ID setting
+                       0x00220000,    //Transmission byte count= byte
+                       0x00E08000,        //Enable I2C/SPI write to VB
+                       0x00E20048,    //Total word count = 0x48 (max 0xFFF). This value should be adjusted considering trade off between transmission time and transmission start/stop time delay
+                       0x00E4007F,    //Vertical blank line = 0x7F
+       };
+
+
+       command[3] |= type;        //data type
+       command[4] |= n & 0xffff;           //Transmission byte count
+
+       tc358768_wr_regs_32bits(command);
+
+       for(i = 0; i < (n + 1)/2; i++) {
+               temp = dbg_data | regs[i*2];
+               if((i*2 + 1) < n)
+                       temp |= (regs[i*2 + 1] << 8);
+               //dsi_debug("0x%08x\n", temp);
+               tc358768_wr_reg_32bits(temp);
+       }
+       if((n % 4 == 1) ||  (n % 4 == 2))     //4 bytes align
+               tc358768_wr_reg_32bits(dbg_data);
+
+       tc358768_wr_reg_32bits(0x00E0C000);     //Start command transmisison
+       tc358768_wr_reg_32bits(0x00E00000);      //Stop command transmission. This setting should be done just after above setting to prevent multiple output
+       udelay(200);
+       //Re-Initialize
+       //tc358768_wr_regs_32bits(re_initialize);
+       return 0;
+}
+
+//low power mode only for tc358768a
+int tc358768_command_tx_more8bytes_lp(unsigned char type, unsigned char regs[], int n) {
+
+       int i = 0;
+       unsigned int dbg_data = 0x00E80000, temp = 0;
+       unsigned int command[] = {
+                       0x00080001,
+                       0x00500000,    //Data ID setting
+                       0x00220000,    //Transmission byte count= byte
+                       0x00E08000,        //Enable I2C/SPI write to VB
+       };
+
+       command[1] |= type;        //data type
+       command[2] |= n & 0xffff;           //Transmission byte count
+
+       tc358768_wr_regs_32bits(command);
+
+       for(i = 0; i < (n + 1)/2; i++) {
+               temp = dbg_data | regs[i*2];
+               if((i*2 + 1) < n)
+                       temp |= (regs[i*2 + 1] << 8);
+               //dsi_debug("0x%08x\n", temp);
+               tc358768_wr_reg_32bits(temp);
+
+       }
+       if((n % 4 == 1) ||  (n % 4 == 2))     //4 bytes align
+               tc358768_wr_reg_32bits(dbg_data);
+
+       tc358768_wr_reg_32bits(0x00E0E000);     //Start command transmisison
+       udelay(1000);
+       tc358768_wr_reg_32bits(0x00E02000);      //Keep Mask High to prevent short packets send out
+       tc358768_wr_reg_32bits(0x00E00000);      //Stop command transmission. This setting should be done just after above setting to prevent multiple output
+       udelay(10);
+       return 0;
+}
+
+int _tc358768_send_packet(unsigned char type, unsigned char regs[], int n) {
+
+       if(n <= 8) {
+               tc358768_command_tx_less8bytes(type, regs, n);
+       } else {
+               //tc358768_command_tx_more8bytes_hs(type, regs, n);
+               tc358768_command_tx_more8bytes_lp(type, regs, n);
+       }
+       return 0;
+}
+
+int tc358768_send_packet(unsigned char type, unsigned char regs[], int n) {
+       return _tc358768_send_packet(type, regs, n);
+}
+
+
+/*
+The DCS is separated into two functional areas: the User Command Set and the Manufacturer Command
+Set. Each command is an eight-bit code with 00h to AFh assigned to the User Command Set and all other
+codes assigned to the Manufacturer Command Set.
+*/
+int _mipi_dsi_send_dcs_packet(unsigned char regs[], int n) {
+
+       unsigned char type = 0;
+       if(n == 1) {
+               type = DTYPE_DCS_SWRITE_0P;
+       } else if (n == 2) {
+               type = DTYPE_DCS_SWRITE_1P;
+       } else if (n > 2) {
+               type = DTYPE_DCS_LWRITE;
+       } 
+       _tc358768_send_packet(type, regs, n);
+       return 0;
+}
+
+int mipi_dsi_send_dcs_packet(unsigned char regs[], int n) {
+       return _mipi_dsi_send_dcs_packet(regs, n);
+}
+
+
+int _tc358768_rd_lcd_regs(unsigned char type, char comd, int size, unsigned char* buf) {
+
+       unsigned char regs[8];
+       u32 count = 0, data30, data32;
+       regs[0] = size;
+       regs[1] = 0;
+       tc358768_command_tx_less8bytes(0x37, regs, 2);
+       tc358768_wr_reg_32bits(0x05040010);
+       tc358768_wr_reg_32bits(0x05060000);
+       regs[0] = comd;
+       tc358768_command_tx_less8bytes(type, regs, 1);
+
+       while (!(tc358768_rd_reg_32bits(0x0410) & 0x20)){
+               printk("error 0x0410:%04x\n", tc358768_rd_reg_32bits(0x0410));
+               msleep(1);
+               if(count++ > 10) {
+                       break;
+               }
+       }
+       
+       data30 = tc358768_rd_reg_32bits(0x0430);          //data id , word count[0:7]
+       //printk("0x0430:%04x\n", data30);
+       data32 = tc358768_rd_reg_32bits(0x0432);          //word count[8:15]  ECC
+       //printk("0x0432:%04x\n", data32);
+       
+       while(size > 0) {
+               data30 = tc358768_rd_reg_32bits(0x0430);          
+               //printk("0x0430:%04x\n", data30);
+               data32 = tc358768_rd_reg_32bits(0x0432);          
+               //printk("0x0432:%04x\n", data32);
+       
+               if(size-- > 0)
+                       *buf++ = (u8)data30;
+               else
+                       break;
+               if(size-- > 0)
+                       *buf++ = (u8)(data30 >> 8);
+               else
+                       break;
+               if(size-- > 0) {
+                       *buf++ = (u8)data32;
+                       if(size-- > 0)
+                               *buf++ = (u8)(data32 >> 8);
+               }
+       }       
+       
+       data30 = tc358768_rd_reg_32bits(0x0430);          
+       //printk("0x0430:%04x\n", data30);
+       data32 = tc358768_rd_reg_32bits(0x0432);          
+       //printk("0x0432:%04x\n", data32);
+       return 0;
+}
+
+int mipi_dsi_read_dcs_packet(unsigned char *data, int n) {
+       //DCS READ 
+       _tc358768_rd_lcd_regs(0x06, *data, n, data);
+       return 0;
+}
+
+
+int tc358768_init(struct mipi_dsi_t *pram) {
+       int ret = 0;
+       dsi = pram;
+       if(!dsi)
+               return -1;
+       dsi->id = 0x4401;
+       dsi->dsi_init = _tc358768_wr_regs_32bits;
+       dsi->dsi_hs_start = _tc358768_wr_regs_32bits;
+       dsi->dsi_send_dcs_packet = mipi_dsi_send_dcs_packet;
+       dsi->dsi_read_dcs_packet = mipi_dsi_read_dcs_packet;
+#ifdef CONFIG_TC358768_I2C    
+    i2c_add_driver(&tc358768_driver);
+#endif    
+       tc358768_gpio_init(NULL);
+       return 0;
+exit_init:
+       //tc358768_power_down(NULL);
+       tc358768_gpio_deinit(NULL);
+       return -1;
+}
diff --git a/drivers/video/display/transmitter/tc358768.h b/drivers/video/display/transmitter/tc358768.h
new file mode 100644 (file)
index 0000000..ca3744c
--- /dev/null
@@ -0,0 +1,99 @@
+
+#ifndef TC358768_H_
+#define TC358768_H_
+
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/rk_fb.h>
+#include <mach/gpio.h>
+#include <mach/iomux.h>
+#include <mach/board.h>
+#include <linux/rk_screen.h>
+#include <linux/ktime.h>
+
+
+//DSI DATA TYPE
+#define DTYPE_DCS_SWRITE_0P            0X05 
+#define DTYPE_DCS_SWRITE_1P            0X15 
+#define DTYPE_DCS_LWRITE               0X39 
+#define DTYPE_GEN_LWRITE               0X29 
+#define DTYPE_GEN_SWRITE_2P            0X23 
+#define DTYPE_GEN_SWRITE_1P            0X13
+#define DTYPE_GEN_SWRITE_0P            0X03
+
+#define CONFIG_TC358768_I2C     1
+#define CONFIG_TC358768_I2C_CLK     400*1000
+
+#if !CONFIG_TC358768_I2C 
+/* define spi write command and data interface function */
+#define TXD_PORT        gLcd_info->txd_pin
+#define CLK_PORT        gLcd_info->clk_pin
+#define CS_PORT         gLcd_info->cs_pin
+#define LCD_RST_PORT    gLcd_info->reset_pin
+
+#define CS_OUT()        gpio_direction_output(CS_PORT, 0)
+#define CS_SET()        gpio_set_value(CS_PORT, GPIO_HIGH)
+#define CS_CLR()        gpio_set_value(CS_PORT, GPIO_LOW)
+#define CLK_OUT()       gpio_direction_output(CLK_PORT, 0)
+#define CLK_SET()       gpio_set_value(CLK_PORT, GPIO_HIGH)
+#define CLK_CLR()       gpio_set_value(CLK_PORT, GPIO_LOW)
+#define TXD_OUT()       gpio_direction_output(TXD_PORT, 0)
+#define TXD_SET()       gpio_set_value(TXD_PORT, GPIO_HIGH)
+#define TXD_CLR()       gpio_set_value(TXD_PORT, GPIO_LOW)
+#define LCD_RST_OUT(i)   gpio_direction_output(LCD_RST_PORT, i)
+#define LCD_RST(i)      gpio_set_value(LCD_RST_PORT, i)
+#endif
+
+
+struct mipi_dsi_t {
+       u32 id;
+       int (*dsi_init)(void *, int n);
+       int (*dsi_hs_start)(void *, int n);
+       int (*dsi_send_dcs_packet)(unsigned char *, int n);
+       int (*dsi_read_dcs_packet)(unsigned char *, int n);
+       int (*dsi_send_packet)(void *, int n);
+
+       void *chip;     
+};
+
+struct power_t {
+       int     enable_pin;    //gpio that control power
+       char* mux_name;
+       u32 mux_mode;
+       u32 effect_value;
+       
+       u32 min_voltage;
+       u32 max_voltage;
+       int (*enable)(void *);
+       int (*disable)(void *);
+};
+
+struct reset_t {
+       int     reset_pin;    //gpio that control reset
+       char* mux_name;
+       u32 mux_mode;
+       u32 effect_value;
+       
+       u32 time_before_reset;    //ms
+       u32 time_after_reset;
+       
+       int (*do_reset)(void *);
+};
+
+struct tc358768_t {
+       struct reset_t reset;
+       struct power_t vddc;
+       struct power_t vddio;
+       struct power_t vdd_mipi;
+       struct i2c_client *client;
+       int (*gpio_init)(void *);
+       int (*gpio_deinit)(void *);
+       int (*power_up)(void *);
+       int (*power_down)(void *);
+};
+
+
+int tc358768_init(struct mipi_dsi_t *pram);
+u32 tc358768_wr_reg_32bits_delay(u32 delay, u32 data);
+
+#endif /* end of TC358768_H_ */