/*
 *
 * Copyright 2012 Texas Instruments, Inc.
 * Author: David Anders <danders.dev@gmail.com>
 *
 * Copyright 2011 Texas Instruments, Inc.
 * Author: Archit Taneja <archit@ti.com>
 *
 * based on d2l panel driver by Jerry Alexander <x0135174@ti.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
#include <drm/drm_edid.h>

#include <video/omapdss.h>
#include <video/mipi_display.h>
#include <video/omap-panel-dsi86.h>

#include "panel-dsi86.h"

#define DSI86DEBUG 1
#define V1920X1080_60HZ 1
#define DSI86SSCEN 1
#define DSI86DSICFGEN 1

static struct i2c_board_info dsi86_i2c_board_info = {
	I2C_BOARD_INFO("dsi86_i2c_driver", 0x2d),
};

struct dsi86_i2c_data {
	struct mutex xfer_lock;
};

static struct i2c_device_id dsi86_i2c_id[] = {
	{ "dsi86_i2c_driver", 0 },
};

static inline struct panel_dsi86_platform_data
*get_pdata(const struct omap_dss_device *dssdev)
{
	return dssdev->data;
}


struct dsi86_eDP_timings {
    u16 hfp;
    u16 hsw;
    u16 hbp;
    u16 vfp;
    u16 vsw;
    u16 vbp;
    u16 hpol;
    u16 vpol;
};


#if V1920X1080_60HZ
static struct dsi86_eDP_timings eDP_timings = {
	.hfp = 48,
	.hsw = 32,
	.hbp = 80,
	.vfp =  3,
	.vsw =  5,
	.vbp =  23, 
	.hpol = 0x80,
	.vpol = 0x80,   
};

static struct omap_video_timings dsi86_default_timings = {
	.x_res = 1920,
	.y_res = 1080,
	.pixel_clock = 137.7,

	.hfp = 15,
	.hsw = 1,
	.hbp = 144,

	.vfp = 1,
	.vsw = 1,
	.vbp = 29,
};

static const struct omap_dss_dsi_videomode_data vm_data_default = {
	/* DSI video mode blanking data */
	/* Unit: byte clock cycles */
	.hsa = 1,
	.hfp = 35,   // Set to 4/3 of the DISPC porch value.
	.hbp = 82,   // Set to 4/3 of the DISPC porch value.

	/* Unit: line clocks */
	.vsa = 5,
	.vfp = 3,
	.vbp = 23,

	.blanking_mode = 1,
	.hsa_blanking_mode = 1,
	.hbp_blanking_mode = 1,
	.hfp_blanking_mode = 1,

	.vp_de_pol = true,
	.vp_vsync_pol = false,
	.vp_hsync_pol = false,
	.vp_hsync_end = false,
	.vp_vsync_end = false,

	.window_sync = 4,
	.ddr_clk_always_on = true,
//    .ddr_clk_always_on = false,
};

#else

static struct dsi86_eDP_timings eDP_timings = {
	.hfp = 48,
	.hsw = 32,
	.hbp = 252,
	.vfp =  2,
	.vsw =  5,
	.vbp =  23, 
	.hpol = 0x00,
	.vpol = 0x80,   
};

static struct omap_video_timings dsi86_default_timings = {
	.x_res = 1600,
	.y_res = 900,
	.pixel_clock = 107.8,

	.hfp = 20,
	.hsw = 1,
	.hbp = 311,

	.vfp = 1,
	.vsw = 1,
	.vbp = 28,
};

static const struct omap_dss_dsi_videomode_data vm_data_default = {
	/* DSI video mode blanking data */
	/* Unit: byte clock cycles */
	.hsa = 1,
	.hfp = 35,   // Set to 4/3 of the DISPC porch value.
	.hbp = 211,   // Set to 4/3 of the DISPC porch value.

	/* Unit: line clocks */
	.vsa = 5,
	.vfp = 2,
	.vbp = 23,

	.blanking_mode = 1,    
	.hsa_blanking_mode = 1,
	.hbp_blanking_mode = 1,
	.hfp_blanking_mode = 1,

	.vp_de_pol = true,
	.vp_vsync_pol = false,
	.vp_hsync_pol = false,
	.vp_hsync_end = false,
	.vp_vsync_end = false,

	.window_sync = 4,
	.ddr_clk_always_on = true,
//    .ddr_clk_always_on = false,
};

#endif


struct dsi86_data {
	struct mutex lock;

	struct omap_dss_device *dssdev;
	struct dentry *debug_dir;
	bool enabled;
	bool dsi96;
	bool apical_enable;
	u8 rotate;
	int pixel_channel;
	int panel_numlanes;
	int panel_datarate;
	long unsigned int lux;
	long unsigned int bl_min;
	long unsigned int bl_max;
	long unsigned int al_min;
	long unsigned int cal_a;
	long unsigned int cal_b;
	long unsigned int cal_c;
	long unsigned int cal_d;
	long unsigned int apical_mode;
	long unsigned int backlight;
	long unsigned int strength_limit;
	long unsigned int strength_out;
	long unsigned int strength_manual;
	long unsigned int drc_in;
	long unsigned int drc_out;
	long unsigned int filter_a;
	long unsigned int filter_b;
	long unsigned int gamma_en;
	long unsigned int iridix;
	long unsigned int t_filter_control;
	u8 rxdata[16];
	u8 txdata[16];

	struct omap_video_timings *timings;
	struct i2c_client *dsi86_i2c_client;
};


struct dsi86_reg {
	/* Address and register value */
	u8 data[10];
	int len;
};

static int dsi86_i2c_probe(struct i2c_client *client,
		const struct i2c_device_id *id)
{
	struct dsi86_i2c_data *dsi86_i2c_data;

#ifdef DSI86DEBUG
	printk(KERN_INFO "DSI86: DSI86_I2C_PROBE\n");
#endif

	dsi86_i2c_data = kzalloc(sizeof(struct dsi86_i2c_data), GFP_KERNEL);

	if (!dsi86_i2c_data) {
		printk(KERN_ERR "DSI86-I2C: memory allocation failed!\n");
		return -ENOMEM;
	}

	mutex_init(&dsi86_i2c_data->xfer_lock);
	i2c_set_clientdata(client, dsi86_i2c_data);

	return 0;
}

static int dsi86_i2c_remove(struct i2c_client *client)
{
	struct dsi86_i2c_data *dsi86_i2c_data = i2c_get_clientdata(client);
#ifdef DSI86DEBUG
	printk(KERN_INFO "DSI86: DSI86_I2C_REMOVE \n");
#endif
	kfree(dsi86_i2c_data);
	return 0;
}

static struct i2c_driver dsi86_i2c_driver = {
	.driver = {
		.name	= "dsi86_i2c_driver",
	},
	.probe		= dsi86_i2c_probe,
	.remove		= dsi86_i2c_remove,
	.id_table	= dsi86_i2c_id,
};

#if 0
static void dsi86_generic_lwrite(struct omap_dss_device *dssdev, u8 saddr_ls, u8 sdata)
{
	u8 buf[3];
	int tmp = 1;

	buf[0] = saddr_ls;
	buf[1] = 0;
	buf[2] = sdata;

	while(tmp != 0)
	{       	
		tmp = dsi_vc_generic_write(dssdev, 0, buf, 3);
	}
	
}
#endif

static void dsi86_generic_swrite(struct omap_dss_device *dssdev, u8 saddr, u8 sdata)
{
    struct panel_dsi86_platform_data *pdata = get_pdata(dssdev);
	int tmp = 1;
	printk(KERN_INFO "DSI86: Generic Short Write.  Addr 0x%x   Data 0x%x\n", saddr, sdata);
	
#if DSI86DSICFGEN      	
		tmp = dsi_vc_generic_write_2(dssdev, 0, saddr, sdata);
		if (tmp == -EIO)
		{
		      gpio_set_value(pdata->reset_gpio, 0);
		      msleep(2000);
		      gpio_set_value(pdata->reset_gpio, 1);		      
		}
		
#else

	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, saddr, sdata);
	
#endif
	
}


static int dsi86_generic_read(struct omap_dss_device *dssdev, u8 Parm1)
{
	struct panel_dsi86_platform_data *pdata = get_pdata(dssdev);
	u8 GenRdvalue = 0;
	u8 * GenRdptr = &GenRdvalue;
	int tmp = 1;

#if DSI86DSICFGEN

		tmp = dsi_vc_generic_read_2(dssdev, 0, Parm1, 0, GenRdptr, 1);
		if (tmp == -EIO)
		{
		      gpio_set_value(pdata->reset_gpio, 0);
		      msleep(2000);
		      gpio_set_value(pdata->reset_gpio, 1);		      
		}
#else
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	
	GenRdvalue = i2c_smbus_read_byte_data(dsi86_i2c_client, Parm1);
	
#endif

	return GenRdvalue;
}

static int dsi86_ind_edid(struct omap_dss_device *dssdev)
{
	int r = 0;
	int i = 0;

	dsi86_generic_swrite(dssdev, DSI86_AUXADDR_HI, 0x00);
	dsi86_generic_swrite(dssdev, DSI86_AUXADDR_MID, 0x00);
	dsi86_generic_swrite(dssdev, DSI86_AUXADDR_LO, 0x50);
	dsi86_generic_swrite(dssdev, DSI86_AUXLEN, 0x01);
	dsi86_generic_swrite(dssdev, DSI86_AUX_CMD_SEND, 0x41);

	do {
		r = dsi86_generic_read(dssdev, DSI86_AUX_STATUS);
	} while (r == 0);

	dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, r);
	
	if (r != 0x1) {
		goto ind_edid_err;
	}

	for (i = 0; i < 8; i++) {
		dsi86_generic_swrite(dssdev, DSI86_AUXLEN, 0x10);
		dsi86_generic_swrite(dssdev, DSI86_AUX_CMD_SEND, 0x51);

		r = 0;
	        do {
			r = dsi86_generic_read(dssdev, DSI86_AUX_STATUS);
		} while (r == 0);

		dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, r);
		if (r != 0x1) {
		    goto ind_edid_err;
		}
	}

	dsi86_generic_swrite(dssdev, DSI86_AUXLEN, 0x00);
	dsi86_generic_swrite(dssdev, DSI86_AUX_CMD_SEND, 0x11);

	r = 0;
	do {
		r = dsi86_generic_read(dssdev, DSI86_AUX_STATUS);
	} while (r == 0);

	dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, r);

	if (r != 0x1) {
		goto ind_edid_err;
	}

	return 0;

ind_edid_err:
	return 1;
}

static void dsi86_get_timings(struct omap_dss_device *dssdev,
			    struct omap_video_timings *timings)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

#ifdef DSI86DEBUG
	printk(KERN_INFO "DSI86: DSI86_GET_TIMINGS \n");
	printk(KERN_INFO "DSI86: X_res 0x%x\n", dssdev->panel.timings.x_res);
	printk(KERN_INFO "DSI86: Y_res 0x%x\n", dssdev->panel.timings.y_res);
	printk(KERN_INFO "DSI86: Pixel_clock 0x%x\n", dssdev->panel.timings.pixel_clock);
#endif

	mutex_lock(&ddata->lock);
	*timings = dssdev->panel.timings;
	mutex_unlock(&ddata->lock);

}

static void dsi86_set_timings(struct omap_dss_device *dssdev,
			    struct omap_video_timings *timings)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

	mutex_lock(&ddata->lock);
	dssdev->panel.timings.x_res = timings->x_res;
	dssdev->panel.timings.y_res = timings->y_res;
	dssdev->panel.timings.pixel_clock = timings->pixel_clock;
	dssdev->panel.timings.hsw = timings->hsw;
	dssdev->panel.timings.hfp = timings->hfp;
	dssdev->panel.timings.hbp = timings->hbp;
	dssdev->panel.timings.vsw = timings->vsw;
	dssdev->panel.timings.vfp = timings->vfp;
	dssdev->panel.timings.vbp = timings->vbp;
	mutex_unlock(&ddata->lock);

#ifdef DSI86DEBUG
	printk(KERN_INFO "DSI86: DSI86_SET_TIMINGS \n");
	printk(KERN_INFO "DSI86: X_res 0x%x\n", timings->x_res);
	printk(KERN_INFO "DSI86: Y_res 0x%x\n", timings->y_res);
	printk(KERN_INFO "DSI86: Pixel_clock 0x%x\n", timings->pixel_clock);
	printk(KERN_INFO "DSI86: HSW 0x%x\n", timings->hsw);
	printk(KERN_INFO "DSI86: HFP 0x%x\n", timings->hfp);
	printk(KERN_INFO "DSI86: HBP 0x%x\n", timings->hbp); 
	printk(KERN_INFO "DSI86: VSW 0x%x\n", timings->vsw);
	printk(KERN_INFO "DSI86: VFP 0x%x\n", timings->vfp);
	printk(KERN_INFO "DSI86: VBP 0x%x\n", timings->vbp);
#endif

}

static int dsi86_check_timings(struct omap_dss_device *dssdev,
			     struct omap_video_timings *timings)
{

#ifdef DSI86DEBUG
	printk(KERN_INFO "DSI86: DSI86_CHECK_TIMINGS \n");
#endif

	return 0;
}

static void dsi86_get_resolution(struct omap_dss_device *dssdev,
			       u16 *xres, u16 *yres)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

#ifdef DSI86DEBUG
	printk(KERN_INFO "DSI86: DSI86_GET_RESOLUTION \n");
#endif

	if (ddata->rotate == 0 || ddata->rotate == 2) {
		*xres = dssdev->panel.timings.x_res;
		*yres = dssdev->panel.timings.y_res;
	} else {
		*yres = dssdev->panel.timings.x_res;
		*xres = dssdev->panel.timings.y_res;
	}
}


/* Function returns following:  */
/* 0x0 = NO HPD CHANGE          */
/* 0x1 = HPD IRQ                */
/* 0x2 = HPD_INSERTION          */
/* 0x4 = HPD_REMOVAL            */
/* 0x8 = HPD_REPLUG             */
static int dsi86_chkhpd(struct omap_dss_device *dssdev)
{
	int hpd_irq_status, hpd_pin_status,ret;

	hpd_irq_status = (dsi86_generic_read(dssdev, DSI86_HPD_STATUS) & 0xF);
	hpd_pin_status = (dsi86_generic_read(dssdev, DSI86_HPD) & 0x10);

	if (hpd_pin_status) {
		if (hpd_irq_status & HPD_INSERT) {
			/*  HPD insertion event*/
			ret = HPD_INSERT;
		}
		else if (hpd_irq_status & HPD_IRQ) {
			/* HPD IRQ event */
			ret = HPD_IRQ;
		}
		else if (hpd_irq_status & HPD_REPLUG) {
			/* HPD replug event */
			ret = HPD_REPLUG;
		}
		else {
			/* HPD no change */
			ret = HPD_NOCHANGE;
		}
	}
	else {
		if (hpd_irq_status & HPD_REMOVE) {
			/* HPD removal event */
			ret = HPD_REMOVE;
		}
		else {
			/* HPD no change */
			ret = HPD_NOCHANGE;
		}
	}

	if (ret) {
		dsi86_generic_swrite(dssdev, DSI86_HPD_STATUS,
			hpd_irq_status);
	}

	return ret;
}

static void dsi86_clr_dsistatus(struct omap_dss_device *dssdev)
{

	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_CHA_STATUS1, 0xFF);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_CHA_STATUS2, 0xFF);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_CHB_STATUS1, 0xFF);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_CHB_STATUS2, 0xFF);

}

static int apical_write(struct i2c_client *dsi86_i2c_client, int reg, long val)
{

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);

	i2c_smbus_write_byte_data(dsi86_i2c_client, reg++, (val & 0xff));
	i2c_smbus_write_byte_data(dsi86_i2c_client, reg, ((val & 0xff00) >> 8));

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return 0;

}

static int apical_calc(struct i2c_client *dsi86_i2c_client)
{

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_CALC_INTERVAL, 0x01);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_START_CALC, 0x00);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_START_CALC, 0x01);

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);


	return 0;
}

static ssize_t dsi86_apical_mode_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
    ddata->apical_mode = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_OPTION_SELECT);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
    
	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->apical_mode);
}

static ssize_t dsi86_apical_mode_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->apical_mode=val;

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_OPTION_SELECT, val);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);


	return count;
}

static ssize_t dsi86_drc_in_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int low,high;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	low = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_DRC_IN_LOW);
	high = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_DRC_IN_HIGH);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ((high<<8) | low));
}

static ssize_t dsi86_drc_in_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->drc_in=val;

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_DRC_IN_LOW, (val & 0xff));
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_DRC_IN_HIGH, ((val & 0xff00) >> 8));

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);


	return count;
}

static ssize_t dsi86_gamma_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	ddata->gamma_en = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_GAMMA);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->gamma_en);
}

static ssize_t dsi86_gamma_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->gamma_en=val;

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_GAMMA, val);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return count;
}

static ssize_t dsi86_drc_out_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int low,high;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	low = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_DRC_OUT_LOW);
	high = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_DRC_OUT_HIGH);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ((high<<8) | low));
}

static ssize_t dsi86_drc_out_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;
    int low,high;
    
	ret = kstrtol(buf, 0, &val);
	ddata->drc_out=val;

    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	low = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_DRC_OUT_LOW);
	high = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_DRC_OUT_HIGH);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
    ddata->drc_out = ((high<<8) | low);

	return count;
}

static ssize_t dsi86_apical_enable_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
    ddata->apical_enable = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_ADEN);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->apical_enable);
}

static ssize_t dsi86_apical_enable_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret,low,high;

	ret = kstrtol(buf, 0, &val);
	ddata->apical_enable=val;

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	low = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_OUT_LOW);
	high = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_OUT_HIGH);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	printk("got low: 0x%x\n",low);
	printk("got high: 0x%x\n",high);

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_LOW, low);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_HIGH, high);

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_ADEN, val);

	return count;
}

static ssize_t dsi86_backlight_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int low,high;

	if (ddata->dsi96 && !(ddata->apical_mode)) {
		i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
		low = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_OUT_LOW);
		high = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_OUT_HIGH);
		i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
		return snprintf(buf, PAGE_SIZE, "%d\n", ((high<<8) | low));
	}
	else
		return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->backlight);
}

static ssize_t dsi86_backlight_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->backlight=val;

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_LOW, (val & 0xff));
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_HIGH, ((val & 0xff00) >> 8));

	return count;
}

static ssize_t dsi86_iridix_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int low;
	
		i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
		low = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_IRIDIX);
		i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
		
	return snprintf(buf, PAGE_SIZE, "%d\n", low);

}

static ssize_t dsi86_iridix_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->iridix=val;

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_IRIDIX, val);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return count;
}



static ssize_t dsi86_filter_a_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int low,high;


		i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
		low = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_FILTER_A_LOW);
		high = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_FILTER_A_HIGH);
		i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
		return snprintf(buf, PAGE_SIZE, "%d\n", ((high<<8) | low));
}

static ssize_t dsi86_filter_a_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->filter_a=val;

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_FILTER_A_LOW, (val & 0xff));
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_FILTER_A_HIGH, ((val & 0xff00) >> 8));
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
    
	return count;
}

static ssize_t dsi86_filter_b_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	ddata->filter_b = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_FILTER_B);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
	return snprintf(buf, PAGE_SIZE, "%d\n", ddata->filter_b);
}

static ssize_t dsi86_filter_b_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->filter_b=val;

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_FILTER_B, val);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
    
	return count;
}


static ssize_t dsi86_strength_limit_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
    ddata->strength_limit = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_STRENGTH_LIMIT);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->strength_limit);
}

static ssize_t dsi86_strength_limit_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->strength_limit=val;

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_STRENGTH_LIMIT, val);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return count;
}

static ssize_t dsi86_strength_out_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	ddata->strength_out = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_STRENGTH_OUT);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->strength_out);
}

static ssize_t dsi86_strength_out_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->strength_out=val;
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	ddata->strength_out = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_STRENGTH_OUT);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return count;
}

static ssize_t dsi86_strength_manual_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	ddata->strength_manual = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_STRENGTH_MANUAL);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->strength_manual);
}

static ssize_t dsi86_strength_manual_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->strength_manual=val;
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_STRENGTH_MANUAL, val);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return count;
}

static ssize_t dsi86_t_filter_control_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	ddata->t_filter_control = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_T_FILTER_CONTROL);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->t_filter_control);
}

static ssize_t dsi86_t_filter_control_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->t_filter_control=val;
	
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_T_FILTER_CONTROL, val);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return count;
}



static ssize_t dsi86_lux_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->lux);
}

static ssize_t dsi86_lux_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	unsigned long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->lux=val;

	/* Program a Default ambient Light level  */
	apical_write(dsi86_i2c_client, DSI86_AMBIENT_LGT_LOW,val);
	apical_calc(dsi86_i2c_client);

	if (!(ddata->dsi96)) {
		if (val * 90 > 0xFFFF)
			ddata->backlight=0xffff;
		else if (val < 112)
			ddata->backlight=0x1FFF;
		else
			ddata->backlight=val*90;

		val=ddata->backlight;
		i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);
			i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_LOW, (val & 0xff));
		i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_HIGH, ((val & 0xff00) >> 8));
	}

	return count;
}

static ssize_t dsi86_al_min_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int low, high;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
    low = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_AMBIENT_LGT_MIN_LOW);
    high = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_AMBIENT_LGT_MIN_HIGH);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ((high<<8) | low));
}

static ssize_t dsi86_al_min_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->al_min=val;

	apical_write(dsi86_i2c_client, DSI86_AMBIENT_LGT_MIN_LOW,val);

	return count;
}

static ssize_t dsi86_bl_min_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int low, high;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
    low = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_MIN_LOW);
    high = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_MIN_HIGH);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ((high<<8) | low));
}

static ssize_t dsi86_bl_min_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->bl_min=val;

	apical_write(dsi86_i2c_client, DSI86_BACKLIGHT_MIN_LOW,val);

	return count;
}

static ssize_t dsi86_bl_max_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int low, high;
	
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x01);
    low = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_MAX_LOW);
    high = i2c_smbus_read_byte_data(dsi86_i2c_client, DSI86_BACKLIGHT_MAX_HIGH);
    i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_PAGESELECT, 0x00);


	return snprintf(buf, PAGE_SIZE, "%ld\n", ((high<<8) | low));
}

static ssize_t dsi86_bl_max_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->bl_max=val;

	apical_write(dsi86_i2c_client, DSI86_BACKLIGHT_MAX_LOW,val);

	return count;
}

static ssize_t dsi86_cal_a_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->cal_a);
}

static ssize_t dsi86_cal_a_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->cal_a=val;

	apical_write(dsi86_i2c_client, DSI86_CAL_A_LOW,val);

	return count;
}

static ssize_t dsi86_cal_b_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->cal_b);
}

static ssize_t dsi86_cal_b_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->cal_b=val;

	apical_write(dsi86_i2c_client, DSI86_CAL_B_LOW,val);

	return count;
}
static ssize_t dsi86_cal_c_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->cal_c);
}

static ssize_t dsi86_cal_c_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	printk("storing: %ld\n",val);
	ddata->cal_c=val;

	apical_write(dsi86_i2c_client, DSI86_CAL_C_LOW,val);

	return count;
}
static ssize_t dsi86_cal_d_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

	return snprintf(buf, PAGE_SIZE, "%ld\n", ddata->cal_d);
}

static ssize_t dsi86_cal_d_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct omap_dss_device *dssdev = to_dss_device(dev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	long val;
	int ret;

	ret = kstrtol(buf, 0, &val);
	ddata->cal_d=val;

	apical_write(dsi86_i2c_client, DSI86_CAL_D_LOW,val);

	return count;
}

static DEVICE_ATTR(cal_a, S_IRUGO | S_IWUSR,
		dsi86_cal_a_show, dsi86_cal_a_store);
static DEVICE_ATTR(cal_b, S_IRUGO | S_IWUSR,
		dsi86_cal_b_show, dsi86_cal_b_store);
static DEVICE_ATTR(cal_c, S_IRUGO | S_IWUSR,
		dsi86_cal_c_show, dsi86_cal_c_store);
static DEVICE_ATTR(cal_d, S_IRUGO | S_IWUSR,
		dsi86_cal_d_show, dsi86_cal_d_store);

static DEVICE_ATTR(backlight, S_IRUGO | S_IWUSR,
		dsi86_backlight_show, dsi86_backlight_store);

static DEVICE_ATTR(strength_limit, S_IRUGO | S_IWUSR,
		dsi86_strength_limit_show, dsi86_strength_limit_store);
		
static DEVICE_ATTR(strength_manual, S_IRUGO | S_IWUSR,
		dsi86_strength_manual_show, dsi86_strength_manual_store);
		
static DEVICE_ATTR(strength_out, S_IRUGO | S_IWUSR,
		dsi86_strength_out_show, dsi86_strength_out_store);
		
static DEVICE_ATTR(t_filter_control, S_IRUGO | S_IWUSR,
		dsi86_t_filter_control_show, dsi86_t_filter_control_store);

static DEVICE_ATTR(apical_enable, S_IRUGO | S_IWUSR,
		dsi86_apical_enable_show, dsi86_apical_enable_store);

static DEVICE_ATTR(apical_mode, S_IRUGO | S_IWUSR,
		dsi86_apical_mode_show, dsi86_apical_mode_store);

static DEVICE_ATTR(lux, S_IRUGO | S_IWUSR,
		dsi86_lux_show, dsi86_lux_store);
		
static DEVICE_ATTR(iridix, S_IRUGO | S_IWUSR,
		dsi86_iridix_show, dsi86_iridix_store);

static DEVICE_ATTR(bl_min, S_IRUGO | S_IWUSR,
		dsi86_bl_min_show, dsi86_bl_min_store);
		
static DEVICE_ATTR(bl_max, S_IRUGO | S_IWUSR,
		dsi86_bl_max_show, dsi86_bl_max_store);

static DEVICE_ATTR(al_min, S_IRUGO | S_IWUSR,
		dsi86_al_min_show, dsi86_al_min_store);
		
static DEVICE_ATTR(drc_in, S_IRUGO | S_IWUSR,
		dsi86_drc_in_show, dsi86_drc_in_store);
		
static DEVICE_ATTR(drc_out, S_IRUGO | S_IWUSR,
		dsi86_drc_out_show, dsi86_drc_out_store);
		
static DEVICE_ATTR(filter_a, S_IRUGO | S_IWUSR,
		dsi86_filter_a_show, dsi86_filter_a_store);
		
static DEVICE_ATTR(filter_b, S_IRUGO | S_IWUSR,
		dsi86_filter_b_show, dsi86_filter_b_store);
		
static DEVICE_ATTR(gamma_en, S_IRUGO | S_IWUSR,
		dsi86_gamma_show, dsi86_gamma_store);

static struct attribute *dsi86_attrs[] = {
	&dev_attr_strength_limit.attr,
	&dev_attr_strength_manual.attr,
	&dev_attr_strength_out.attr,
	&dev_attr_t_filter_control.attr,
	&dev_attr_backlight.attr,
	&dev_attr_apical_mode.attr,
	&dev_attr_apical_enable.attr,
	&dev_attr_lux.attr,
	&dev_attr_iridix.attr,
	&dev_attr_bl_min.attr,
	&dev_attr_bl_max.attr,
	&dev_attr_al_min.attr,
	&dev_attr_cal_a.attr,
	&dev_attr_cal_b.attr,
	&dev_attr_cal_c.attr,
	&dev_attr_cal_d.attr,
	&dev_attr_drc_in.attr,
	&dev_attr_drc_out.attr,
	&dev_attr_filter_a.attr,
	&dev_attr_filter_b.attr,
	&dev_attr_gamma_en.attr,
	NULL,
};

static struct attribute_group dsi86_attr_group = {
	.attrs = dsi86_attrs,
};

static int dsi86_probe(struct omap_dss_device *dssdev)
{
	struct i2c_adapter *adapter;
	struct i2c_client *dsi86_i2c_client;
	int ret = 0,tmp;
	struct dsi86_data *ddata = NULL;
	struct panel_dsi86_platform_data *pdata = get_pdata(dssdev);

	printk(KERN_INFO "DSI86: DSI86_PROBE \n");

	dev_dbg(&dssdev->dev, "dsi86_probe\n");

	if (dssdev->data == NULL) {
		dev_err(&dssdev->dev, "no platform data!\n");
		return -EINVAL;
	}

	printk("DSI85 device name reported as:%s\n",dev_name(&dssdev->dev));

	if (dssdev->data == NULL) {
		dev_err(&dssdev->dev, "no platform data!\n");
		return -EINVAL;
	}

	dssdev->panel.timings = dsi86_default_timings;

	dssdev->panel.config = OMAP_DSS_LCD_TFT;
	dssdev->panel.dsi_vm_data = vm_data_default;

	dssdev->ctrl.pixel_size = 24;

	dssdev->panel.acbi = 0;
	dssdev->panel.acb = 40;

	ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
	if (!ddata)
		return -ENOMEM;

	ddata->dssdev = dssdev;
	pdata = dssdev->data;


	if (!pdata) {
		dev_err(&dssdev->dev, "Invalid platform data\n");
		ret = -EINVAL;
		goto err;
	}

	mutex_init(&ddata->lock);

	dev_set_drvdata(&dssdev->dev, ddata);

	ddata->debug_dir = debugfs_create_dir("dsi86", NULL);
	if (!ddata->debug_dir) {
		dev_err(&dssdev->dev, "failed to create debug dir\n");
		goto err_debugfs;
	}

	ret = omap_dsi_request_vc(dssdev, &ddata->pixel_channel);
	if (ret) {
		dev_err(&dssdev->dev, "failed to request pixel update "
		    "channel\n");
		goto err_debugfs;
	} else
		printk(KERN_INFO "pixel channel setup for %d\n", \
			ddata->pixel_channel);

	printk(KERN_INFO "pixel channel %d\n", ddata->pixel_channel);
	ret = omap_dsi_set_vc_id(dssdev, ddata->pixel_channel, 0);
	if (ret) {
		dev_err(&dssdev->dev, "failed to set VC_ID for pixel data"
			" virtual channel\n");
		goto err_pixel_vc;
	}
		
	adapter = i2c_get_adapter(pdata->i2c_bus_num);
	if (!adapter) {
		printk(KERN_INFO "DSI86-I2C: can't get i2c adapter 2\n");
//		ret = -ENODEV;
//		goto err_pixel_vc;
	}

	dsi86_i2c_client = i2c_new_device(adapter, &dsi86_i2c_board_info);
	if (!dsi86_i2c_client) {
		printk(KERN_INFO "DSI86-I2C: can't add i2c device\n");
//		ret = -ENODEV;
//		goto err_pixel_vc;
	}

	ddata->dsi86_i2c_client = dsi86_i2c_client;

	ret = i2c_smbus_read_byte_data(dsi86_i2c_client, 0x00);
//	ret = dsi86_generic_read(dssdev, 0x00);
	printk(KERN_INFO "DSI86-I2C: reading 0x00 returned - 0x%x\n", ret);

	dev_dbg(&dssdev->dev, "dsi86_probe\n");

	/* Enable EDID I2C address */
	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_I2C_ADDR_CLAIM1, 0xA1);

	tmp = (ODD_EVEN_PIXELS | SINGLE_CHANNEL_DSI);

	/* Set the number of DSI lanes */
	switch (pdata->dsilanes) {
	case 1:
		tmp |= DSI_A_LANES_1;
		break;
	case 2:
		tmp |= DSI_A_LANES_2;
		break;
	case 3:
		tmp |= DSI_A_LANES_3;
		break;
	case 4:
		tmp |= DSI_A_LANES_4;
		break;
	}

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_DSI_CFG, tmp);

	i2c_smbus_write_byte_data(dsi86_i2c_client, DSI86_DSI_EQ, 0x00);
	

	dsi86_clr_dsistatus(dssdev);

	ret = sysfs_create_group(&dssdev->dev.kobj, &dsi86_attr_group);
	if (ret)
		dev_warn(&dssdev->dev, "failed to create sysfs files\n");
        
//   while(r == 0)
//   {
//	   r = dsi86_chkhpd(dssdev);
//	}

	return 0;

err_pixel_vc:
	omap_dsi_release_vc(dssdev, ddata->pixel_channel);
err_debugfs:
	mutex_destroy(&ddata->lock);
	gpio_free(pdata->reset_gpio);
err:
	kfree(ddata);

	return ret;
}

static void __exit dsi86_remove(struct omap_dss_device *dssdev)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

#ifdef DSI86DEBUG
	printk(KERN_INFO "DSI86: DSI86_REMOVE \n");
#endif

	mutex_lock(&ddata->lock);

	dev_set_drvdata(&dssdev->dev, NULL);

	mutex_unlock(&ddata->lock);

	kfree(ddata);
}

#ifdef DSI86_TESTS
static int dsi86_generic_shorttest(struct omap_dss_device *dssdev)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int i = 0;
	int j = 0;
	int max = 1000;
	int tmp = 0;
	int serr = 0;

	dsi86_clr_dsistatus(dssdev);

	for (i = 0; i < max; i++)
	{
		for (j = 0; j < 200; j++) {
			dsi86_generic_swrite(dssdev, 0x73, j);
			tmp = dsi86_generic_read(dssdev, 0x73);
			if (tmp != j) {
				serr = 1;
#ifdef DSI86DEBUG
				printk(KERN_INFO "DSI86: Generic Read/Write ");
				printK(KERN_INFO "Mismatch Address 73h: Rd: ");
				printk(KERN_INFO "0x%x Wr: 0x%x  Itr: 0x%x\n", /
					tmp, j, i);
				tmp=i2c_smbus_read_byte_data(dsi86_i2c_client, /
					0x73);
				printk(KERN_INFO "DSI86-I2C:  Address 73h :");
				printk(KERN_INFO "RD 0x%02x  Wr: 0x%02x\n", /
					tmp, j);
#endif
			}
		}
	}
	return serr;
}

static int dsi86_generic_longtest(struct omap_dss_device *dssdev)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int i = 0;
	int j = 0;
	int max = 1000;
	int tmp = 0;
	int serr = 0;

	dsi86_clr_dsistatus(dssdev);
	
	for (i = 0; i < max; i++)
	{
		for (j = 0; j < 100; j++)
	    {
		   dsi86_generic_lwrite(dssdev, 0x73, j);
		   tmp = dsi86_generic_read(dssdev, 0x73);
                if (tmp != j)
		        {
				 serr = 1;
	             printk(KERN_INFO "DSI86: Generic Long Read/Write Mismatch: Rd: 0x%x Wr: 0x%x\n", tmp, j);
	             printk(KERN_INFO "DSI86-I2C: read 0x%02x  - 0x%02x\n", 0x73, \
		         i2c_smbus_read_byte_data(dsi86_i2c_client, 0x73));
		       }
		       
		}
	}
	return serr;
}
#endif

#ifdef DSI86DEBUG
static void dsi86_dumpconfig(struct omap_dss_device *dssdev)
{

	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x0A, \
		dsi86_generic_read(dssdev, 0x0A));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x0B, \
		dsi86_generic_read(dssdev, 0x0B));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x0D, \
		dsi86_generic_read(dssdev, 0x0D));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x0E, \
		dsi86_generic_read(dssdev, 0x0E));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x0F, \
		dsi86_generic_read(dssdev, 0x0F));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x10, \
		dsi86_generic_read(dssdev, 0x10));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x12, \
		dsi86_generic_read(dssdev, 0x12));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x13, \
		dsi86_generic_read(dssdev, 0x13));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x20, \
		dsi86_generic_read(dssdev, 0x20));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x21, \
		dsi86_generic_read(dssdev, 0x21));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x22, \
		dsi86_generic_read(dssdev, 0x22));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x23, \
		dsi86_generic_read(dssdev, 0x23));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x24, \
		dsi86_generic_read(dssdev, 0x24));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x25, \
		dsi86_generic_read(dssdev, 0x25));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x28, \
		dsi86_generic_read(dssdev, 0x28));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x29, \
		dsi86_generic_read(dssdev, 0x29));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x2C, \
		dsi86_generic_read(dssdev, 0x2C));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x2D, \
		dsi86_generic_read(dssdev, 0x2D));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x30, \
		dsi86_generic_read(dssdev, 0x30));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x31, \
		dsi86_generic_read(dssdev, 0x31));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x34, \
		dsi86_generic_read(dssdev, 0x34));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x36, \
		dsi86_generic_read(dssdev, 0x36));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x38, \
		dsi86_generic_read(dssdev, 0x38));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x3A, \
		dsi86_generic_read(dssdev, 0x3A));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x93, \
		dsi86_generic_read(dssdev, 0x93));
	printk(KERN_INFO "DSI86-Generic: read 0x%02x  - 0x%02x\n", 0x94, \
		dsi86_generic_read(dssdev, 0x94));


}

#endif

// This function will read from the DPCD register of sink.
// auxaddr: 20bit DPCD address.
// Returns:  byte from sink.
static int dsi86_dpcd_read(struct omap_dss_device *dssdev, int auxaddr, int len)
{
	int r = 0;
	int rty = 0;
	int tmp = 0;
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

dpcd_rd_err:
	if (len < 1) len = 1;
	if (len > 16) len = 16;
	/* Clear Status Registers */
//	dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, 0xFF);

	/* Send AUX READ REQUEST */
	dsi86_generic_swrite(dssdev, DSI86_AUXADDR_HI, (auxaddr & 0xF0000) >> 16);
	dsi86_generic_swrite(dssdev, DSI86_AUXADDR_MID, (auxaddr & 0xFF00) >> 8);
	dsi86_generic_swrite(dssdev, DSI86_AUXADDR_LO, auxaddr & 0xFF);
	dsi86_generic_swrite(dssdev, DSI86_AUXLEN, len);
	dsi86_generic_swrite(dssdev, DSI86_AUX_CMD_SEND, 0x91);

	/* POLL SEND_INT */
	do {
		r = dsi86_generic_read(dssdev, DSI86_AUX_STATUS);
	} while (r == 0);

	if ((r & 0x59) != 0x01)
	{
		rty++;
		if (rty <=7)
		{
			printk(KERN_INFO "DSI86: AUX DPCD READ FAILURE.:0x%x  TRY AGAIN\n", r);
			dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, r);
			goto dpcd_rd_err;
		}
		else
		{
			dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, r);
		}
	}
	else
	{
		dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, r);
	}

	
	do {
	   r = dsi86_generic_read(dssdev, DSI86_AUX_RDATA0 + tmp);
	   ddata->rxdata[tmp] = r;
	   tmp++;
    } while (tmp < len);
    
	return ddata->rxdata[0];

}

// This function will write to the DPCD register of sink.
// auxaddr: 20bit DPCD address.
// writedata:  byte to be written.
static int dsi86_dpcd_write(struct omap_dss_device *dssdev, int auxaddr, int writedata)
{
	int r = 0;
	int rty = 0;

dpcd_wr_err:
	/* Clear Status Registers */
	dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, 0xFF);

	/* Send AUX WRITE REQUEST */
	dsi86_generic_swrite(dssdev, DSI86_AUX_WDATA0, writedata);
	dsi86_generic_swrite(dssdev, DSI86_AUXADDR_HI, (auxaddr & 0xF0000) >> 16);
	dsi86_generic_swrite(dssdev, DSI86_AUXADDR_MID, (auxaddr & 0xFF00) >> 8);
	dsi86_generic_swrite(dssdev, DSI86_AUXADDR_LO, auxaddr & 0xFF);
	dsi86_generic_swrite(dssdev, DSI86_AUXLEN, 1);
	dsi86_generic_swrite(dssdev, DSI86_AUX_CMD_SEND, 0x81);

	/* POLL SEND_INT */
	do {         
		r = dsi86_generic_read(dssdev, DSI86_AUX_STATUS);
	} while (r == 0);
	
	if ((r & 0x59) != 0x01)
	{
		rty++;
		if (rty <=7)
		{
			printk(KERN_INFO "DSI86: AUX DPCD WRITE FAILURE. 0x%x  TRY AGAIN\n", r);
			dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, r);
			goto dpcd_wr_err;
		}
		else
		{
			dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, r);
		}
	}
	else
	{
		dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, r);
	}

	return r;

}

static int dsi86_set_dp_lanes(struct omap_dss_device *dssdev, int sinklanes)
{
    struct panel_dsi86_platform_data *pdata = get_pdata(dssdev);
	int r = 0;
	int lanesused = 1;

	if (sinklanes == 0x4)
	{
	    sinklanes = 0x3;
	}

        /* Set Number of DP lanes */
	if (pdata->dpnumlanes == sinklanes)
	{
		lanesused = sinklanes;	
	}
	else if (pdata->dpnumlanes > sinklanes)
	{
		lanesused = sinklanes;
	}
	else
	{
		lanesused = pdata->dpnumlanes;
	}

	r = ((dsi86_generic_read(dssdev, DSI86_DP_NUM_LANES) & 0xCF) | (lanesused << 4));
	dsi86_generic_swrite(dssdev, DSI86_DP_NUM_LANES, r);

	return (r & 0x30) >> 4;

}

static int dsi86_set_datarate(struct omap_dss_device *dssdev, int sinkdatarate)
{
	struct panel_dsi86_platform_data *pdata = get_pdata(dssdev);
	int r = 0;
	int datarateused = 0x1;

	if (sinkdatarate == 0x6)
	{  /*  RBR */
		sinkdatarate = 0x1;
	}
	else if (sinkdatarate == 0xA)
	{   /* HBR */
		sinkdatarate = 0x4;
	}
	else
	{   /* HBR2 */
		sinkdatarate = 0x7;
	}

	if (pdata->dpdatarate == sinkdatarate)
	{
		datarateused = sinkdatarate;
	}
	else if (pdata->dpdatarate > sinkdatarate)
	{
		datarateused = sinkdatarate;
	}
	else
	{
		datarateused = pdata->dpdatarate;
	}

	/* Set DP data rate */
	r = ((dsi86_generic_read(dssdev, DSI86_DP_DATARATE) & 0x1F) | (datarateused << 5));
	dsi86_generic_swrite(dssdev, DSI86_DP_DATARATE, r);

	return (r & 0xE0) >> 5;

}



static void dsi86_semiautotrain(struct omap_dss_device *dssdev)
{
	int r = 0;
	int rty = 0;
	int hpdchg = 0;

//	printk(KERN_INFO "DSI86: Semi-Auto Link Training Start. \n");

	/* Set DP TX Swing to L0 */
	r = ((dsi86_generic_read(dssdev, DSI86_DP_DATARATE) & 0xFC));
	dsi86_generic_swrite(dssdev, DSI86_DP_DATARATE, r);

	/* Set DP Preemphasis to L0 */
	r = ((dsi86_generic_read(dssdev, DSI86_DP_NUM_LANES) & 0x3F));
	dsi86_generic_swrite(dssdev, DSI86_DP_NUM_LANES, r);

semi_auto_err:

	/* Clear Interrupt Status bits if set */
	dsi86_generic_swrite(dssdev, DSI86_AUX_STATUS, 0xFF);
	dsi86_generic_swrite(dssdev, DSI86_HPD_STATUS, 0x0E);	
	dsi86_generic_swrite(dssdev, DSI86_LT_STATUS, 0xFF);

	/* Enable Semi-Auto Link Training */
	dsi86_generic_swrite(dssdev, DSI86_ML_TX_MODE, 0xA);
	r = 0;

	do {
		msleep(10);
	        r = ((dsi86_generic_read(dssdev, DSI86_LT_STATUS) & 0x2F));
	        hpdchg = (dsi86_generic_read(dssdev, DSI86_HPD_STATUS) & 0xFF);
	        printk(KERN_INFO "DSI86: HPD Status 0x%x\n", hpdchg);	        
	} while (r == 0);

	if (r == 0x1)
	{
		r = dsi86_generic_read(dssdev, DSI86_LT_STATUS);
	printk(KERN_INFO "DSI86: DP Semi-Auto Completed Successfully. 0x%x\n", r);

	/* Clear Interrupt Status bits if set */
	dsi86_generic_swrite(dssdev, DSI86_LT_STATUS, r);

	r = dsi86_generic_read(dssdev, DSI86_DP_DATARATE );
	printk(KERN_INFO "DSI86: Datarate 0x%x\n", r);

	r = dsi86_generic_read(dssdev, DSI86_DP_NUM_LANES );
	printk(KERN_INFO "DSI86: NUM of LANES 0x%x\n", r);

	}
	else {
		r = dsi86_generic_read(dssdev, DSI86_LT_STATUS);
		printk(KERN_INFO "DSI86: DP Semi-Auto FAILED!!: LT_STATUS - 0x%x\n", r);
		dsi86_generic_swrite(dssdev, DSI86_LT_STATUS, r);
		r = dsi86_generic_read(dssdev, DSI86_AUX_STATUS);
	    printk(KERN_INFO "DSI86: DP Semi-Auto FAILED!!: AUX_STATUS - 0x%x\n", r);

		if ((r & 0x58) != 0x0)
		{
			rty++;
			if (rty <= 1)
			{
				goto semi_auto_err;
			}
		}
		
		r = dsi86_generic_read(dssdev, DSI86_HPD_STATUS);
		printk(KERN_INFO "DSI86: DP Semi-Auto FAILED!!: HPD_STATUS - 0x%x\n", r);
		dsi86_generic_swrite(dssdev, DSI86_HPD_STATUS, r);
		
		r = dsi86_generic_read(dssdev, DSI86_DP_DATARATE );
		printk(KERN_INFO "DSI86: Datarate 0x%x\n", r);
		r = dsi86_generic_read(dssdev, DSI86_DP_NUM_LANES );
		printk(KERN_INFO "DSI86: NUM of LANES 0x%x\n", r);
	}
}



/*
 * dsi86_config - Configure dsi86
 *
 * Initial configuration for dsi86 configuration registers
*/
static void dsi86_config(struct omap_dss_device *dssdev)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

	printk(KERN_INFO "DSI86: DSI86_CONFIG \n");

	/* Enable EDID I2C address */
	dsi86_generic_swrite(dssdev, DSI86_I2C_ADDR_CLAIM1, 0xA1);


	/* Soft reset and disable PLL */
	dsi86_generic_swrite(dssdev, DSI86_SOFT_RESET, 0x01);

	/* x resolution high/low for channel A */
	dsi86_generic_swrite(dssdev, DSI86_CHA_LINE_LEN_LO, \
		((dssdev->panel.timings.x_res) & 0x00FF));
	dsi86_generic_swrite(dssdev, DSI86_CHA_LINE_LEN_HI, \
		((dssdev->panel.timings.x_res) & 0xFF00)>>8);

	/* y resolution high/low for channel A */
	dsi86_generic_swrite(dssdev, DSI86_CHA_VERT_LINES_LO, \
		(dssdev->panel.timings.y_res & 0x00FF));
	dsi86_generic_swrite(dssdev, DSI86_CHA_VERT_LINES_HI, \
		(dssdev->panel.timings.y_res & 0xFF00)>>8);


	/* HSYNC width high/low for channel A */
	dsi86_generic_swrite(dssdev, DSI86_CHA_HSYNC_WIDTH_LO, \
		(eDP_timings.hsw & 0x00FF));
	dsi86_generic_swrite(dssdev, DSI86_CHA_HSYNC_WIDTH_HI, \
		((eDP_timings.hsw & 0xFF00)>>8) | eDP_timings.hpol);


	/* VSYNC width high/low for channel A */
	dsi86_generic_swrite(dssdev, DSI86_CHA_VSYNC_WIDTH_LO, \
		(eDP_timings.vsw & 0x00FF));
	dsi86_generic_swrite(dssdev, DSI86_CHA_VSYNC_WIDTH_HI, \
		((eDP_timings.vsw & 0xFF00)>>8) | eDP_timings.vpol);


	/* Horizontal BackPorch for channel A */
	dsi86_generic_swrite(dssdev, DSI86_CHA_HORZ_BACKPORCH, \
		(eDP_timings.hbp & 0x00FF));


	/* Vertical BackPorch for channel A */
	dsi86_generic_swrite(dssdev, DSI86_CHA_VERT_BACKPORCH, \
		(eDP_timings.vbp & 0x00FF)); 

	/* Horizontal FrontPorch for channel A */
	dsi86_generic_swrite(dssdev, DSI86_CHA_HORZ_FRONTPORCH, \
		(eDP_timings.hfp & 0x00FF));


	/* Vertical FrontPorch for channel A */
	dsi86_generic_swrite(dssdev, DSI86_CHA_VERT_FRONTPORCH, \
		(eDP_timings.vfp & 0x00FF));

    /*  Enable PWM  */
	dsi86_generic_swrite(dssdev, DSI86_BACKLIGHT_SCALE_LOW, 0xFF);
	dsi86_generic_swrite(dssdev, DSI86_BACKLIGHT_SCALE_HIGH, 0xFF);
	dsi86_generic_swrite(dssdev, DSI86_PWM_PRE_DIV, 0x01);
	dsi86_generic_swrite(dssdev, DSI86_GPIO_CTRL, 0x80);
	dsi86_generic_swrite(dssdev, DSI86_PWM, 0x02);
	
    if (dsi86_generic_read(dssdev, 0x1)  == 0x39)
    { /* DSI96  */
		printk(KERN_INFO "DSI86: DSI96 DETECTED! \n");
		ddata->dsi96 = 1;

		dsi86_generic_swrite(dssdev, DSI86_BACKLIGHT_LOW, 0xff);
		dsi86_generic_swrite(dssdev, DSI86_BACKLIGHT_HIGH, 0x1f);
		ddata->backlight=0x1fff;

		/* Enable Adaptive Display  */
		dsi86_generic_swrite(dssdev, DSI86_ADEN, 0x01);
		ddata->apical_enable=0x01;
		msleep(100);
		printk(KERN_INFO "DSI86: HPD STATUS - 0x%x\n", dsi86_generic_read(dssdev, DSI86_HPD_STATUS));
		/* Change Page to Adaptive Display Registers*/
		dsi86_generic_swrite(dssdev, DSI86_PAGESELECT, 0x01);
		printk(KERN_INFO "DSI86: PAGESELECT - 0x%x\n", dsi86_generic_read(dssdev, DSI86_PAGESELECT));

		/* Program Option_select  */
#if 0
		dsi86_generic_swrite(dssdev, DSI86_OPTION_SELECT, 0x01);
		ddata->apical_mode=0x01;
#else
		dsi86_generic_swrite(dssdev, DSI86_OPTION_SELECT, 0x00);
		ddata->apical_mode=0x00;
#endif

		dsi86_generic_swrite(dssdev, DSI86_BACKLIGHT_MIN_LOW, 0x00);
		dsi86_generic_swrite(dssdev, DSI86_BACKLIGHT_MIN_HIGH, 0x00);
		ddata->bl_min=0x0000;

		dsi86_generic_swrite(dssdev, DSI86_BACKLIGHT_MAX_LOW, 0xFF);
		dsi86_generic_swrite(dssdev, DSI86_BACKLIGHT_MAX_HIGH, 0xFF);
		
		/*  Program Bright and Dark Limits  */
		dsi86_generic_swrite(dssdev, DSI86_LIMIT_AMPL, 0xF0);

		/* Program a Calibration A  */
		dsi86_generic_swrite(dssdev, DSI86_CAL_A_LOW, 0x0D);
		dsi86_generic_swrite(dssdev, DSI86_CAL_A_HIGH, 0x00);
		ddata->cal_a=0x000d;

		/* Program a Calibration B  */
		dsi86_generic_swrite(dssdev, DSI86_CAL_B_LOW, 0x5F);
		dsi86_generic_swrite(dssdev, DSI86_CAL_B_HIGH, 0x00);
		ddata->cal_b=0x005F;

		/* Program a Calibration C  */
		dsi86_generic_swrite(dssdev, DSI86_CAL_C_LOW, 0x13);
		dsi86_generic_swrite(dssdev, DSI86_CAL_C_HIGH, 0x00);
		ddata->cal_c=0x0013;

		/* Program a Calibration D  */
		dsi86_generic_swrite(dssdev, DSI86_CAL_D_LOW, 0x00);
		dsi86_generic_swrite(dssdev, DSI86_CAL_D_HIGH, 0x00);
		ddata->cal_d=0x0000;

		/* Program a Default Ambient Light MIN level  */
		dsi86_generic_swrite(dssdev, DSI86_AMBIENT_LGT_MIN_LOW, 0xFF);
		dsi86_generic_swrite(dssdev, DSI86_AMBIENT_LGT_MIN_HIGH, 0xFF);
		ddata->al_min=0xffff;

		/* Program a Default Ambient Light level  */
		dsi86_generic_swrite(dssdev, DSI86_AMBIENT_LGT_LOW, 0x14);
		dsi86_generic_swrite(dssdev, DSI86_AMBIENT_LGT_HIGH, 0x00);
		ddata->lux=0x0014;

		printk(KERN_INFO "DSI86: AMBIENT_LGT_LOW - 0x%x\n", dsi86_generic_read(dssdev, DSI86_AMBIENT_LGT_LOW));

		dsi86_generic_swrite(dssdev, DSI86_CALC_INTERVAL, 0x01);
		printk(KERN_INFO "DSI86: CALC_INTERVAL - 0x%x\n", dsi86_generic_read(dssdev, DSI86_CALC_INTERVAL));
		/* Set Start Calc  */
		dsi86_generic_swrite(dssdev, DSI86_START_CALC, 0x00);
		dsi86_generic_swrite(dssdev, DSI86_START_CALC, 0x01);

		/* x resolution high/low for channel A */
		dsi86_generic_swrite(dssdev, DSI86_FRAME_WIDTH_LO, \
			((dssdev->panel.timings.x_res) & 0x00FF));
		dsi86_generic_swrite(dssdev, DSI86_FRAME_WIDTH_HI, \
			((dssdev->panel.timings.x_res) & 0xFF00)>>8);

		/* y resolution high/low for channel A */
		dsi86_generic_swrite(dssdev, DSI86_FRAME_HEIGHT_LO, \
			(dssdev->panel.timings.y_res & 0x00FF));
		dsi86_generic_swrite(dssdev, DSI86_FRAME_HEIGHT_HI, \
			(dssdev->panel.timings.y_res & 0xFF00)>>8);

		/* enable dithering with 2-bit */
		dsi86_generic_swrite(dssdev, DSI86_DITHER, 0x03);

		/* Change Page to Standard CFR */
		dsi86_generic_swrite(dssdev, DSI86_PAGESELECT, 0x00);

	}
	else { /* DSI86  */
		printk(KERN_INFO "DSI86: DSI86 DETECTED! \n");
		ddata->dsi96 = 0;
		dsi86_generic_swrite(dssdev, DSI86_BACKLIGHT_LOW, 0xFF);
		dsi86_generic_swrite(dssdev, DSI86_BACKLIGHT_HIGH, 0x1F);
	}

	/* 18BPP Enable */
	dsi86_generic_swrite(dssdev, DSI86_DP_COLOR_BPP, 0x01);

#if 0
	/* COLOR BAR */
	dsi86_generic_swrite(dssdev, DSI86_COLOR_BAR, 0x10);
#endif

	msleep(100);

	/* VStream Enable and Enhanced Frame Enable */
	dsi86_generic_swrite(dssdev, DSI86_ML_POLR,  0xC | ((dsi86_generic_read(dssdev, DSI86_ML_POLR) & 0xF3)));

	return;
}

static void dsi86_testautomation(struct omap_dss_device *dssdev)
{
	int testreq = 0;
	int tmp = 0;
	int tmp1 = 0;
	int dpnls = 0;
	int dpdr = 0;
	int ln01_status = 0;
	int ln23_status = 0;
	int align_done = 0;
	int j = 0;
	int request_vod = 0x0;
    int request_pre = 0x0;
    int postcursor2 = 0x0;

    msleep(10);
	testreq = dsi86_dpcd_read(dssdev, 0x218, 1);
    printk(KERN_INFO "DSI86: DP Test Automation. 0x%x\n", testreq );
   

	if (((testreq & 0x1) == 0x1) || testreq == 0x0)
	{       /*Test Link Training */
	    printk(KERN_INFO "DSI86: Test Link Training. \n");
		tmp = dsi86_dpcd_read(dssdev, 0x219, 1);
		tmp1 = dsi86_dpcd_read(dssdev, 0x220, 1);
		dpdr = dsi86_set_datarate(dssdev, tmp);
		dsi86_generic_swrite(dssdev, DSI86_PLL_EN, 0x01);
		msleep(1);
		dpnls = dsi86_set_dp_lanes(dssdev, tmp1); 
		dsi86_dpcd_write(dssdev, 0x260, 0x01);
		msleep(20);
		ln01_status = dsi86_dpcd_read(dssdev, 0x202, 1);
		ln23_status = dsi86_dpcd_read(dssdev, 0x203, 1);
		align_done = dsi86_dpcd_read(dssdev, 0x204, 1);
		dsi86_dpcd_read(dssdev, 0x205, 1);
        if ((dpnls == 0x1) && ((ln01_status & 0x7) != 0x7))
        {
	         dsi86_semiautotrain(dssdev);
	    }
	    else if ((dpnls >= 0x2) && (ln01_status != 0x77))
	    {
	         dsi86_semiautotrain(dssdev);
        }
	    else if ((dpnls == 0x3) && (ln23_status != 0x77))
	    {
	         dsi86_semiautotrain(dssdev);
		}
		else if ((align_done & 0x1) != 0x1)
		{
		      dsi86_semiautotrain(dssdev);
		}
		else
		{
		   /* NOTHING  */
		}
		dsi86_dpcd_write(dssdev, 0x260, 0x01);
		dsi86_dpcd_write(dssdev, 0x201, 0x02);

	}
	else if ((testreq & 0x4) == 0x4)
	{
		/*Test TEST_EDID_READ */
		printk(KERN_INFO "DSI86: Test EDID. \n");
		dsi86_dpcd_write(dssdev, 0x260, 0x01);

		if (dsi86_ind_edid(dssdev))
		{
    		printk(KERN_INFO "DSI86: INDIRECT EDID. ERROR READING EDID \n");
    	}

	}
	else if ((testreq & 0x8) == 0x8)
	{
		/*PHY_TEST_PATTERN*/
		printk(KERN_INFO "DSI86: PHY_TEST_PATTERN \n");
		
	    tmp = dsi86_dpcd_read(dssdev, 0x219, 1);
	    tmp1 = dsi86_dpcd_read(dssdev, 0x220, 1);
		dsi86_set_datarate(dssdev, tmp);
		printk(KERN_INFO "DSI86: Datarate: 0x%x NumOfLanes: 0x%x\n", tmp, tmp1);
		msleep(2);
				
		tmp = dsi86_dpcd_read(dssdev, 0x248, 1);
		printk(KERN_INFO "DSI86: PHY_TEST_PATTERN (248h): 0x%x \n", tmp);
		if (tmp == 0x1)
		{
		    /* TPS1 */
		    printk(KERN_INFO "DSI86: PHY_TEST_PATTERN: TPS1 \n");
		    dsi86_generic_swrite(dssdev, DSI86_ML_TX_MODE, 0x2);
	    }
		else if (tmp == 0x2)
		{
			/* Symbol Error Measurement Count */
			printk(KERN_INFO "DSI86: PHY_TEST_PATTERN: Symbol Error Measurement Count \n");
			dsi86_generic_swrite(dssdev, DSI86_ML_TX_MODE, 0x7);
		}
		else if (tmp == 0x3)
		{
			/* PRBS7 */
			printk(KERN_INFO "DSI86: PHY_TEST_PATTERN: PRBS7  \n");
			dsi86_generic_swrite(dssdev, DSI86_ML_TX_MODE, 0x5);
		}
		else if (tmp == 0x4)
		{
			/* 80-bit Custom Pattern */
			printk(KERN_INFO "DSI86: PHY_TEST_PATTERN: 80-bit Custom Pattern  \n");
			
			for (j = 0; j < 10; j++)
	        {
				tmp = dsi86_dpcd_read(dssdev, 0x250 + j, 1);
				dsi86_generic_swrite(dssdev, 0x89 + j, tmp);
		    }

			dsi86_generic_swrite(dssdev, DSI86_ML_TX_MODE, 0x8);
		}
		else if (tmp == 0x5)
		{
			/* HBR2 Compliance Eye */
			printk(KERN_INFO "DSI86: PHY_TEST_PATTERN: HBR2 Compliance Eye  \n");
			for (j = 0; j < 2; j++)
	        {
				tmp = dsi86_dpcd_read(dssdev, 0x24A + j, 1);
				dsi86_generic_swrite(dssdev, 0x97 + j, tmp);
		    }
		    dsi86_generic_swrite(dssdev, 0x97, 0x04);
		    dsi86_generic_swrite(dssdev, 0x98, 0x01);


			dsi86_generic_swrite(dssdev, DSI86_ML_TX_MODE, 0x6);
		}
		else
		{
		   /* NOTHING to TEST */	
		}

		/* SET PreEmp Level and VOD level */
		tmp = dsi86_dpcd_read(dssdev, 0x206, 1);
        request_vod = tmp & 0x3;
        request_pre = (tmp & 0xC) >> 2;
        printk(KERN_INFO "DSI86: VOD: 0x%x PreEmp: 0x%x\n", request_vod, request_pre);
        dsi86_dpcd_read(dssdev, 0x207, 1);
        tmp = ((dsi86_generic_read(dssdev, DSI86_DP_NUM_LANES) & 0x3F) | (request_pre << 6));
        dsi86_generic_swrite(dssdev, DSI86_DP_NUM_LANES, tmp);
        
        tmp1 = 0x3 & dsi86_dpcd_read(dssdev, 0x20C, 1);
        if (tmp1 == 0x01)
        {
			postcursor2 = 0x2;
		}
		else if (tmp1 == 0x02)
		{
			postcursor2 = 0x4;
		}
		else if (tmp1 == 0x03)
		{
			postcursor2 = 0x6;
		}
		else
		{
		  	postcursor2 = 0x0;
		}
        tmp = ((dsi86_generic_read(dssdev, DSI86_POST_CURSOR2) & 0xF1) | (postcursor2 << 1));
        dsi86_generic_swrite(dssdev, DSI86_POST_CURSOR2, tmp); 
       
        tmp = ((dsi86_generic_read(dssdev, DSI86_DP_DATARATE) & 0xFC) | (request_vod));
        dsi86_generic_swrite(dssdev, DSI86_DP_DATARATE, tmp);
		msleep(1);
		dsi86_dpcd_write(dssdev, 0x260, 0x01);
		dsi86_dpcd_write(dssdev, 0x201, 0x02);
		
	}
	else if ((testreq & 0x2) == 0x2)
	{
		/*Test Pattern */
	    dsi86_dpcd_write(dssdev, 0x260, 0x01);
	    dsi86_dpcd_write(dssdev, 0x201, 0x02);

	}	
	else
	{
		/* NOTHING TO TEST */
		dsi86_dpcd_write(dssdev, 0x201, 0x02);
	}
}



static void dsi86_power_off(struct omap_dss_device *dssdev)
{
	struct panel_dsi86_platform_data *pdata = get_pdata(dssdev);

    printk(KERN_INFO "DSI86: DSI86_POWER_OFF \n");

	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
		return;

	if (pdata->platform_disable)
		pdata->platform_disable(dssdev);

	omapdss_dsi_display_disable(dssdev, 0, 0);
}



static void dsi86_disable(struct omap_dss_device *dssdev)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

	printk(KERN_INFO "DSI86: DSI86_DISABLE \n");
	mutex_lock(&ddata->lock);
	dsi_bus_lock(dssdev);
	dsi86_power_off(dssdev);
	dsi_bus_unlock(dssdev);
	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
	mutex_unlock(&ddata->lock);

}




static int dsi86_sync(struct omap_dss_device *dssdev)
{
	printk(KERN_INFO "DSI86: DSI86_SYNC \n");
	return 0;
}



static int dsi86_suspend(struct omap_dss_device *dssdev)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);

	printk(KERN_INFO "DSI86: DSI86_SUSPEND \n");

	mutex_lock(&ddata->lock);

	dsi_bus_lock(dssdev);

	dsi86_power_off(dssdev);

	dsi_bus_unlock(dssdev);

	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;

	mutex_unlock(&ddata->lock);

	return 0;
}


static int panel_dsi86_ddc_read(struct i2c_adapter *adapter,
		unsigned char *buf, u16 count, u8 offset)
{
	int r, retries;

	for (retries = 3; retries > 0; retries--) {
		struct i2c_msg msgs[] = {
			{
				.addr   = DDC_ADDR,
				.flags  = 0,
				.len    = 1,
				.buf    = &offset,
			}, {
				.addr   = DDC_ADDR,
				.flags  = I2C_M_RD,
				.len    = count,
				.buf    = buf,
			}
		};

		r = i2c_transfer(adapter, msgs, 2);
		if (r == 2)
			return 0;

		if (r != -EAGAIN)
			break;
	}

	return r < 0 ? r : -EIO;
}

#ifdef DSI86_READ_EDID
static int dsi86_read_edid(struct omap_dss_device *dssdev,
		u8 *edid, int len)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
    struct panel_dsi86_platform_data *pdata = get_pdata(dssdev);
	struct i2c_adapter *adapter;
	int r, l, bytes_read;

	mutex_lock(&ddata->lock);
 

	if (pdata->i2c_bus_num == 0) {
		r = -ENODEV;
		goto err;
	}

	adapter = i2c_get_adapter(pdata->i2c_bus_num);
	if (!adapter) {
		dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
				pdata->i2c_bus_num);
		r = -EINVAL;
		goto err;
	}
    printk(KERN_INFO "DSI86: EDID len 0x%x\n", len);
	l = min(EDID_LENGTH, len);
	r = panel_dsi86_ddc_read(adapter, edid, l, 0);
	if (r)
		goto err;

	bytes_read = l;

	/* if there are extensions, read second block */
	if (len > EDID_LENGTH && edid[0x7e] > 0) {
		l = min(EDID_LENGTH, len - EDID_LENGTH);

		r = panel_dsi86_ddc_read(adapter, edid + EDID_LENGTH,
				l, EDID_LENGTH);
		if (r)
			goto err;

		bytes_read += l;
	}

	mutex_unlock(&ddata->lock);


        printk(KERN_INFO "DSI86: EDID NUM OF BYTES READ 0x%x\n", bytes_read);
	return bytes_read;

err:
	mutex_unlock(&ddata->lock);
	return r;
}
#endif

static int dsi86_power_on(struct omap_dss_device *dssdev)
{
	struct panel_dsi86_platform_data *pdata = get_pdata(dssdev);
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
//	struct i2c_client *dsi86_i2c_client = ddata->dsi86_i2c_client;
	int r = 0;
	int tmp = 0;
	int dpnls = 0;
	int dpdr = 0;
	int ln01_status = 0;
	int ln23_status = 0;
	int align_done = 0;

    printk(KERN_INFO "DSI86: DSI86_POWER_ON \n");

	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
		return 0;

	dssdev->panel.timings = dsi86_default_timings;
	r = omapdss_dsi_display_enable(dssdev);

	if (r)
		goto err0;

	if (pdata->platform_enable) {
		r = pdata->platform_enable(dssdev);
		if (r)
			goto err1;
	}
#ifdef DSI86_TESTS
	printk(KERN_INFO "DSI86: Generic Short LPDT Test \n");
	if (dsi86_generic_shorttest(dssdev)) {
		printk(KERN_INFO "DSI86: Generic Short LPDT tests Failed!!! \n");
	}
	else {
		printk(KERN_INFO "DSI86: Generic Short LPDT tests Passed!!! \n");
	}
#endif

	dsi86_generic_swrite(dssdev, DSI86_PAGESELECT, 0x01);
	printk(KERN_INFO "DSI86: PAGESELECT - 0x%x\n", dsi86_generic_read(dssdev, DSI86_PAGESELECT));

	dsi86_generic_swrite(dssdev, DSI86_PAGESELECT, 0x00);
	printk(KERN_INFO "DSI86: PAGESELECT - 0x%x\n", dsi86_generic_read(dssdev, DSI86_PAGESELECT));

	omapdss_dsi_vc_enable_hs(dssdev, ddata->pixel_channel, true);
	dsi_videomode_panel_preinit(dssdev, ddata->pixel_channel);
	
	r = 0x0;		
	msleep(200);
	
	dsi86_generic_swrite(dssdev, 0x00, 0x00);
#ifdef DSI86_TESTS
	printk(KERN_INFO "DSI86: PAGESELECT - 0x%x\n", dsi86_generic_read(dssdev, DSI86_PAGESELECT));

	printk(KERN_INFO "DSI86: Generic Short HSDT Test \n");
	if (dsi86_generic_shorttest(dssdev)) {
		printk(KERN_INFO "DSI86: Generic Short HSDT tests Failed!!! \n");
	}
	else {
		printk(KERN_INFO "DSI86: Generic Short HSDT tests Passed!!! \n");
	}
#endif

#ifdef DSI86SSCEN
	dsi86_generic_swrite(dssdev, DSI86_DP_NUM_LANES,  0x1 | ((dsi86_generic_read(dssdev, DSI86_DP_NUM_LANES) & 0xFE)));
#endif

//	while(1) 
	while(r == 0) 
    {
		r = dsi86_chkhpd(dssdev);
		if (r == 0x1) { /* HPD IRQ */
			printk(KERN_INFO "DSI86: HPD_IRQ asserted \n");
			dsi86_dpcd_read(dssdev, 0x200, 1);
			if ((dsi86_dpcd_read(dssdev, 0x201, 1) & 0x2) == 0x2) {
				dsi86_testautomation(dssdev);
			}
			else {
				ln01_status = dsi86_dpcd_read(dssdev, 0x202, 1);
				ln23_status = dsi86_dpcd_read(dssdev, 0x203, 1);
				align_done = dsi86_dpcd_read(dssdev, 0x204, 1);
				dsi86_dpcd_read(dssdev, 0x205, 1);
				if ((dpnls == 0x1) && ((ln01_status & 0x7) != 0x7)) {
					dsi86_semiautotrain(dssdev);
				}
				else if ((dpnls >= 0x2) && (ln01_status != 0x77)) {
					dsi86_semiautotrain(dssdev);
				}
				else if ((dpnls == 0x3) && (ln23_status != 0x77))
				{
					dsi86_semiautotrain(dssdev);
				}
				else if ((align_done & 0x1) != 0x1)
				{
					dsi86_semiautotrain(dssdev);
				}
				else
				{
					r = 0;
				}
			}
		}
		else if (r == 0x2)  /* HPD INSERTION */
		{

			printk(KERN_INFO "DSI86: HPD INSERTION OCCURRED \n");

//			if (dsi86_ind_edid(dssdev)) {
//			    printk(KERN_INFO "DSI86: INDIRECT EDID. ERROR READING EDID \n");
//			}

			dsi86_dpcd_read(dssdev, 0x0, 3);
			dpdr = dsi86_set_datarate(dssdev, ddata->rxdata[1]);
			dpnls = dsi86_set_dp_lanes(dssdev, ddata->rxdata[2] & 0x1F); 

//			dpdr = dsi86_set_datarate(dssdev, dsi86_dpcd_read(dssdev, 0x1, 1));
//			dpnls = dsi86_set_dp_lanes(dssdev, dsi86_dpcd_read(dssdev, 0x2, 1) & 0x1F); 
			dsi86_generic_swrite(dssdev, DSI86_PLL_EN, 0x01);
			dsi86_dpcd_read(dssdev, 0x3, 10);

			tmp = dsi86_dpcd_read(dssdev, 0xD, 1);

			if ((tmp & 0x3) != 0x0)
			{
				printk(KERN_INFO "DSI86: EDP Panel present \n");
				if ((tmp & 0x1) == 0x1)
				{  /* ASSR  */
					printk(KERN_INFO "DSI86: EDP Panel ASSR \n");
					dsi86_generic_swrite(dssdev, DSI86_ML_POLR,  0x1 | ((dsi86_generic_read(dssdev, DSI86_ML_POLR) & 0xFC)));
					dsi86_dpcd_write(dssdev, 0x10A, 0x01);
				}
				else if ((tmp & 0x2) == 0x2)
				{  /* Alternate Framing */
					printk(KERN_INFO "DSI86: EDP Panel Alternate Framing \n");
					dsi86_generic_swrite(dssdev, DSI86_ML_POLR,  0x2 | ((dsi86_generic_read(dssdev, DSI86_ML_POLR) & 0xFC)));
					dsi86_dpcd_write(dssdev, 0x10A, 0x02);
				}
				else
				{
					/* Nothing */
					dsi86_generic_swrite(dssdev, DSI86_ML_POLR,  0x0 | ((dsi86_generic_read(dssdev, DSI86_ML_POLR) & 0xFC)));
				}
			}
			else
			{
				dsi86_generic_swrite(dssdev, DSI86_ML_POLR,  0x0 | ((dsi86_generic_read(dssdev, DSI86_ML_POLR) & 0xFC)));
//				dsi86_dpcd_write(dssdev, 0x10A, 0x02);
			}

			msleep(10);
			dsi86_semiautotrain(dssdev);
			dsi86_dpcd_read(dssdev, 0x200, 1);
			if ((dsi86_dpcd_read(dssdev, 0x201, 1) & 0x2) == 0x2)
			{
				dsi86_testautomation(dssdev);
			}
		}
		else if (r == 0x4) /* HPD REMOVAL */
		{
			printk(KERN_INFO "DSI86: HPD REMOVAL OCCURRED \n");
			printk(KERN_INFO "DSI86:  ML_TX_MODE - 0x%x\n", dsi86_generic_read(dssdev, DSI86_ML_TX_MODE));
			dsi86_generic_swrite(dssdev, DSI86_PLL_EN, 0x00);
		}
		else if (r == 0x8) /* HPD REPLUG */
		{
			printk(KERN_INFO "DSI86: HPD REPLUG OCCURRED \n");
			msleep(10);
			dsi86_dpcd_read(dssdev, 0x200, 1);
			if ((dsi86_dpcd_read(dssdev, 0x201, 1) & 0x2) == 0x2)
			{
				dsi86_testautomation(dssdev);
			}
			else
			{
				dpdr  = dsi86_set_datarate(dssdev, dsi86_dpcd_read(dssdev, 0x1, 1));
				dpnls = dsi86_set_dp_lanes(dssdev, dsi86_dpcd_read(dssdev, 0x2, 1) & 0x1F);
				dsi86_generic_swrite(dssdev, DSI86_PLL_EN, 0x01); 
				dsi86_dpcd_read(dssdev, 0x0, 1);
				ln01_status = dsi86_dpcd_read(dssdev, 0x202, 1);
				ln23_status = dsi86_dpcd_read(dssdev, 0x203, 1);
				align_done = dsi86_dpcd_read(dssdev, 0x204, 1);
				dsi86_dpcd_read(dssdev, 0x205, 1);
				if ((dpnls == 0x1) && ((ln01_status & 0x7) != 0x7))
				{
					dsi86_semiautotrain(dssdev);
				}
				else if ((dpnls >= 0x2) && (ln01_status != 0x77))
				{
					dsi86_semiautotrain(dssdev);
				}
				else if ((dpnls == 0x3) && (ln23_status != 0x77))
				{
					dsi86_semiautotrain(dssdev);
				}
				else if ((align_done & 0x1) != 0x1)
				{
				dsi86_semiautotrain(dssdev);
				}
				else
				{
					r = 0;
				}
			}
		}
		else /* NO CHANGE IN HPD */
		{
			r = 0;
		}
	}

	dsi86_config(dssdev);

//	printk(KERN_INFO "DSI86: Generic Short HS DSI  Test \n");
//	if (dsi86_generic_shorttest(dssdev))
//	{
//        	printk(KERN_INFO "DSI86: Generic Short HS DSI tests Failed!!! \n");
//    }
//    else
//    {
//        	printk(KERN_INFO "DSI86: Generic Short HS DSI tests Passed!!! \n");
//	}

#ifdef DSI86DEBUG
	dsi86_dumpconfig(dssdev);
#endif

	dsi_video_mode_enable(dssdev, ddata->pixel_channel);

	ddata->enabled = 1;

//	dsi86_generic_swrite(dssdev, DSI86_CALC_INTERVAL, 0x06);

	return 0;
err1:
	omapdss_dsi_display_disable(dssdev, 0, 0);
err0:
	return r;
}

static int dsi86_resume(struct omap_dss_device *dssdev)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	int r;

	printk(KERN_INFO "DSI86: DSI86_RESUME \n");
	mutex_lock(&ddata->lock);
	dsi_bus_lock(dssdev);
	r = dsi86_power_on(dssdev);
	dsi_bus_unlock(dssdev);
	if (r == 0)
		dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
	mutex_unlock(&ddata->lock);

	return r;
}


static int dsi86_enable(struct omap_dss_device *dssdev)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	int r;

	printk(KERN_INFO "DSI86: DSI86_ENABLE \n");
	mutex_lock(&ddata->lock);
	dsi_bus_lock(dssdev);
	r = dsi86_power_on(dssdev);
	dsi_bus_unlock(dssdev);
	if (r == 0)
		dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
	mutex_unlock(&ddata->lock);

	return r;
}


static bool panel_dsi86_detect(struct omap_dss_device *dssdev)
{
	struct dsi86_data *ddata = dev_get_drvdata(&dssdev->dev);
	struct panel_dsi86_platform_data *pdata = get_pdata(dssdev);
	struct i2c_adapter *adapter;
	unsigned char out;
	int r;

	printk(KERN_INFO "DSI86: DSI86_DETECT entering \n");
	mutex_lock(&ddata->lock);

	if (pdata->i2c_bus_num == 0)
		goto out;

	adapter = i2c_get_adapter(pdata->i2c_bus_num);
	if (!adapter)
		goto out;


	r = panel_dsi86_ddc_read(adapter, &out, 1, 0);
	mutex_unlock(&ddata->lock);
	printk(KERN_INFO "DSI86: DSI86_DETECT leaving \n");

	return r == 0;

out:
	mutex_unlock(&ddata->lock);
	return true;
}


static struct omap_dss_driver dsi86_driver = {
	.probe = dsi86_probe,
//	.remove = dsi86_remove,
	.remove		= __exit_p(dsi86_remove),

	.enable = dsi86_enable,
	.disable = dsi86_disable,
	.suspend = dsi86_suspend,
	.resume = dsi86_resume,

	.sync = dsi86_sync,

	.get_resolution = dsi86_get_resolution,
	.get_recommended_bpp = omapdss_default_get_recommended_bpp,

	.set_timings = dsi86_set_timings,
	.get_timings = dsi86_get_timings,
	.check_timings = dsi86_check_timings,
#ifdef DSI86_READ_EDID
	.read_edid     = dsi86_read_edid, 
#endif
	.detect	       = panel_dsi86_detect,

	.driver = {
		.name = "dsi86",
		.owner = THIS_MODULE,
	},
};



static int __init dsi86_init(void)
{
	int r = 0;

	r = i2c_add_driver(&dsi86_i2c_driver);
	if (r) {
		printk(KERN_WARNING "dsi86_i2c_driver" \
			" registration failed\n");
		return r;
	} else
		printk("DSI86-I2C: registered!\n");

	r = omap_dss_register_driver(&dsi86_driver);
	if (r)
		i2c_del_driver(&dsi86_i2c_driver);

	return 0;
}

static void __exit dsi86_exit(void)
{
	i2c_del_driver(&dsi86_i2c_driver);
	omap_dss_unregister_driver(&dsi86_driver);
}

module_init(dsi86_init);
module_exit(dsi86_exit);
