
#ifndef BUILD_LK
#include <linux/string.h>
#endif
#include "lcm_drv.h"



// ---------------------------------------------------------------------------
//  Local Constants
// ---------------------------------------------------------------------------
// huayu + boe + ips(quan shi jiao)
#define FRAME_WIDTH  										(480)
#define FRAME_HEIGHT 										(960)

#define REGFLAG_DELAY             							0xFEE
#define REGFLAG_END_OF_TABLE      							0xFFF   // END OF REGISTERS MARKER

#define LCM_DSI_CMD_MODE									0

#ifndef TRUE
    #define TRUE 1
#endif

#ifndef FALSE
    #define FALSE 0
#endif

#ifdef BUILD_LK
#define LCD_DEBUG(fmt)  dprintf(CRITICAL,fmt)
#else
#define LCD_DEBUG(fmt)  printk(fmt)
#endif

#define LCM_ID_JD9161  0x9161

// ---------------------------------------------------------------------------
//  Local Variables
// ---------------------------------------------------------------------------

static LCM_UTIL_FUNCS lcm_util = {0};

#define SET_RESET_PIN(v)    								(lcm_util.set_reset_pin((v)))

#define UDELAY(n) 											(lcm_util.udelay(n))
#define MDELAY(n) 											(lcm_util.mdelay(n))

// ---------------------------------------------------------------------------
//  Local Functions
// ---------------------------------------------------------------------------
#define dsi_set_cmdq_V3(para_tbl,size,force_update)        lcm_util.dsi_set_cmdq_V3(para_tbl,size,force_update)
#define dsi_set_cmdq_V2(cmd, count, ppara, force_update)	        lcm_util.dsi_set_cmdq_V2(cmd, count, ppara, force_update)
#define dsi_set_cmdq(pdata, queue_size, force_update)		lcm_util.dsi_set_cmdq(pdata, queue_size, force_update)
#define wrtie_cmd(cmd)										lcm_util.dsi_write_cmd(cmd)
#define write_regs(addr, pdata, byte_nums)					lcm_util.dsi_write_regs(addr, pdata, byte_nums)
#define read_reg											lcm_util.dsi_read_reg()
#define read_reg_v2(cmd, buffer, buffer_size)   				lcm_util.dsi_dcs_read_lcm_reg_v2(cmd, buffer, buffer_size)    

#define   LCM_DSI_CMD_MODE							0
struct LCM_setting_table {
    unsigned cmd;
    unsigned char count;
    unsigned char para_list[64];
};

//static  unsigned char temp53 = 0x15;

static struct LCM_setting_table lcm_initialization_setting[] = {

{0xBF, 3, {0x91,0x61,0xF2}},
{0xB3, 2, {0x00,0x6D}},
{0xB4, 2, {0x00,0x64}},
{0xB8, 6, {0x00,0xA0,0x01,0x00,0xA0,0x01}},
{0xBA, 3, {0x34,0x23,0x00}},

{0xC3, 1, {0x04}},
{0xC4, 2, {0x00,0x78}},
{0xC7, 9, {0x00,0x02,0x32,0x07,0x65,0x2B,0x19,0xA5,0xA5}},

{0xC8, 38, {0x6C,0x60,0x55,0x4C,0x4B,0x3D,0x42,0x2A,0x40,0x3C,0x39,0x55,0x42,0x44,0x33,0x30,0x22,0x11,0x06,0x6C,0x60,0x55,0x4C,0x4B,0x3D,0x42,0x2A,0x40,0x3C,0x39,0x55,0x42,0x44,0x33,0x30,0x22,0x11,0x06}},

{0xD4, 16, {0x1F,0x1F,0x00,0x02,0x1F,0x1E,0x1E,0x08,0x0A,0x04,0x06,0x1F,0x1F,0x1F,0x1F,0x1F}},

{0xD5, 16, {0x1F,0x1F,0x01,0x03,0x1F,0x1E,0x1E,0x09,0x0B,0x05,0x07,0x1F,0x1F,0x1F,0x1F,0x1F}},

{0xD6, 16, {0x1F,0x1E,0x03,0x01,0x1F,0x1F,0x1E,0x07,0x05,0x0B,0x09,0x1F,0x1F,0x1F,0x1F,0x1F}},

{0xD7, 16, {0x1F,0x1E,0x02,0x00,0x1F,0x1F,0x1E,0x06,0x04,0x0A,0x08,0x1F,0x1F,0x1F,0x1F,0x1F}},

{0xD8, 20, {0x20,0x00,0x00,0x30,0x04,0x30,0x01,0x02,0x30,0x01,0x02,0x06,0x7C,0x73,0xC8,0x73,0x06,0x06,0x7c,0x08}},

{0xD9, 19, {0x00,0x0a,0x0a,0x88,0x00,0x00,0x06,0x7B,0x00,0x80,0x00,0x3B,0x33,0x1F,0x00,0x00,0x00,0x06,0x70}},

{0xBE, 1, {0x01}},
{0xC1, 1, {0x10}},
{0xC5, 1, {0x05}},

{0xCC, 10, {0x34,0x20,0x38,0x60,0x11,0x91,0x00,0x40,0x00,0x00}},

{0xBE, 1, {0x00}},
{0x35, 1, {0x00}},
{0x36, 1, {0xC0}},
{0xCF, 2, {0x02,0x05}},

{0x11, 0, {0x00}},
{REGFLAG_DELAY,120,{}},

{0x29, 0, {0x00}},
{REGFLAG_DELAY,10,{}},

{REGFLAG_END_OF_TABLE, 0x00, {}}

};

#if 0
static struct LCM_setting_table lcm_compare_id_setting[] = {
    {0x11, 1, {0x00}},
    {REGFLAG_DELAY, 120, {}},

    // Display ON
    {0x29, 1, {0x00}},
    {REGFLAG_DELAY, 20, {}},
    {REGFLAG_END_OF_TABLE, 0x00, {}}
};


static struct LCM_setting_table lcm_deep_sleep_mode_in_setting[] = {
	// Display off sequence
    	{REGFLAG_DELAY, 1, {}},
	    {0x28, 1, {0x00}},
	{REGFLAG_DELAY, 10, {}},
     // Sleep Mode Ondiv1_real*div2_real
     {0x10, 1, {0x00}},
	{REGFLAG_DELAY, 120, {}},
     {REGFLAG_END_OF_TABLE, 0x00, {}}
};
#endif
static void push_table(struct LCM_setting_table *table, unsigned int count, unsigned char force_update)
{
	unsigned int i;

    for(i = 0; i < count; i++) {
		
        unsigned cmd;
        cmd = table[i].cmd;
		
        switch (cmd) {
			
            case REGFLAG_DELAY :
                MDELAY(table[i].count);
                break;
				
            case REGFLAG_END_OF_TABLE :
                break;
				
            default:
				dsi_set_cmdq_V2(cmd, table[i].count, table[i].para_list, force_update);
				//UDELAY(5);//soso add or it will fail to send register
       	}
    }
	
}


// ---------------------------------------------------------------------------
//  LCM Driver Implementations
// ---------------------------------------------------------------------------

static void lcm_set_util_funcs(const LCM_UTIL_FUNCS *util)
{
		memcpy(&lcm_util, util, sizeof(LCM_UTIL_FUNCS));
}


static void lcm_get_params(LCM_PARAMS *params)
{

		memset(params, 0, sizeof(LCM_PARAMS));

		params->type   = LCM_TYPE_DSI;

		params->width  = FRAME_WIDTH;
		params->height = FRAME_HEIGHT;


#if (LCM_DSI_CMD_MODE)
		params->dsi.mode   = CMD_MODE;
#else
		params->dsi.mode   = SYNC_PULSE_VDO_MODE; //SYNC_PULSE_VDO_MODE;//BURST_VDO_MODE; SYNC_EVENT_VDO_MODE
#endif 

		// DSI
		// Command mode setting 
		params->dsi.LANE_NUM				= LCM_TWO_LANE;
		//The following defined the fomat for data coming from LCD engine.
		params->dsi.data_format.format      = LCM_DSI_FORMAT_RGB888;

		// Video mode setting		
		params->dsi.PS=LCM_PACKED_PS_24BIT_RGB888;

	params->dsi.vertical_sync_active =              4;
	params->dsi.vertical_backporch =                9;
	params->dsi.vertical_frontporch =              9;
	params->dsi.vertical_active_line = FRAME_HEIGHT;

	params->dsi.horizontal_sync_active =           20; 
	params->dsi.horizontal_backporch =             40; 
	params->dsi.horizontal_frontporch =            30; 
		params->dsi.horizontal_active_pixel				= FRAME_WIDTH;
		
		//params->physical_width = 62;
		//params->physical_height = 110;
		
    //MIPI CLK MHZ
    params->dsi.PLL_CLOCK=202;
	params->dsi.ssc_disable = 1;

    //ESD CHECK
     	params->dsi.clk_lp_per_line_enable	= 0;
	params->dsi.noncont_clock		= 0; 
	params->dsi.noncont_clock_period	= 1; //Unit : frames
        params->dsi.esd_check_enable = 1;
		params->dsi.customization_esd_check_enable = 1;
		params->dsi.lcm_esd_check_table[0].cmd			= 0x0a;
		params->dsi.lcm_esd_check_table[0].count		= 1;
		params->dsi.lcm_esd_check_table[0].para_list[0] = 0x9c;

#ifdef CONFIG_MTK_ROUND_CORNER_SUPPORT
params->corner_pattern_width = 20;//圆角的宽度
params->corner_pattern_height = 20;//圆角的高度
#endif

}

static unsigned int lcm_compare_id(void);

static void lcm_init(void)
{
	SET_RESET_PIN(1);
	MDELAY(10);
	SET_RESET_PIN(0);
	MDELAY(10);
	SET_RESET_PIN(1);
	MDELAY(120);
	push_table(lcm_initialization_setting, sizeof(lcm_initialization_setting) / sizeof(struct LCM_setting_table), 1);
}

static void lcm_suspend(void)
{
	SET_RESET_PIN(0);
	MDELAY(120);
//	push_table(lcm_deep_sleep_mode_in_setting,sizeof(lcm_deep_sleep_mode_in_setting) / sizeof(struct LCM_setting_table), 1);


}


static void lcm_resume(void)
{
	lcm_init();
}

static unsigned int lcm_compare_id(void)
{
	unsigned int id = 0;
	unsigned char buffer[5];
	unsigned int array[16];
    	SET_RESET_PIN(1);
	MDELAY(10);
	SET_RESET_PIN(0); 	
	MDELAY(5);
	SET_RESET_PIN(1);
	MDELAY(120);
	//push_table(lcm_compare_id_setting,sizeof(lcm_compare_id_setting) /sizeof(struct LCM_setting_table), 1);

	array[0] = 0x00043902;
	array[1] = 0xF26191BF;
	dsi_set_cmdq(array, 2, 1);

	array[0] = 0x00BE1500;
	dsi_set_cmdq(array, 1, 1);
	MDELAY(50);
	array[0] = 0x00033700;
	dsi_set_cmdq(array, 1, 1);
	MDELAY(50);
	read_reg_v2(0x04, buffer, 2);

	id = (buffer[0] << 8 | buffer[1]);	//we only need ID

	return (LCM_ID_JD9161 == id) ? 1 : 0;
}

static unsigned int lcm_ata_check(unsigned char *buf)
{
        unsigned int id = 0;
        unsigned char buffer[5];
        unsigned int array[16];
        SET_RESET_PIN(1);
        MDELAY(10);
        SET_RESET_PIN(0);
        MDELAY(5);
        SET_RESET_PIN(1);
        MDELAY(120);
        //push_table(lcm_compare_id_setting,sizeof(lcm_compare_id_setting) /sizeof(struct LCM_setting_table), 1);

        array[0] = 0x00043902;
        array[1] = 0xF26191BF;
        dsi_set_cmdq(array, 2, 1);

        array[0] = 0x00BE1500;
        dsi_set_cmdq(array, 1, 1);
        MDELAY(50);
        array[0] = 0x00033700;
        dsi_set_cmdq(array, 1, 1);
        MDELAY(50);
        read_reg_v2(0x04, buffer, 2);

        id = (buffer[0] << 8 | buffer[1]);      //we only need ID

        return (LCM_ID_JD9161 == id) ? 1 : 0;
}

LCM_DRIVER esky_jd9161ba_vdo_fwvga_59_boe_haifei = 
{
    .name			= "esky_jd9161ba_vdo_fwvga_59_boe_haifei",
	.set_util_funcs = lcm_set_util_funcs,
	.get_params     = lcm_get_params,
	.init           = lcm_init,
	.suspend        = lcm_suspend,
	.resume         = lcm_resume,
	.compare_id    	= lcm_compare_id,	
	.ata_check	= lcm_ata_check,
};
