config LCD_I30_800X480
bool "lcd I30"
+config LCD_TL5001_MIPI
+ bool "TL5001 720X1280"
+
endchoice
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
--- /dev/null
+/*
+ * 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__);
+
+}
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"
# Makefile for the jetta tv control.
#
obj-$(CONFIG_RK610_LVDS) += rk610_lcd.o
+obj-$(CONFIG_TC358768_RGB2MIPI) += tc358768.o
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+
+#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_ */