Qualcomm MSM8937 ICN6211 MIPI-2-RGB 芯片驱动

( ICN6211 ILI9806E + 模拟SPI+模拟I2C )

/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only 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.
 *
 * 
 * version:1.0
 * data:2017.9.9
 * function description : mipi-2-rgb (icn6211) device driver which tranfer msg via i2c
 *
 */
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/mdss_io_util.h>
#include <linux/slab.h>

struct icn6211 {
	int en_gp;
	int lcd_rst_gp;
	unsigned char slave_addr;
	int iic_scl_gp;
	int iic_sda_gp;
	int spi_sdi_gp;
	int spi_sdo_gp;
	int spi_csx_gp;
	int spi_sck_gp;
	int rgb_or_lvds; /* 1:rgb, 0, lvds */
	struct mutex icn6211_mutex;
};

struct init_cmd {
	char reg_add;
	char reg_val;
};

static const struct init_cmd icn6211_cmd_table[] = {
#if 0
	{0x20, 0x20},
	{0x21, 0xE0},
	{0x22, 0x13},
	{0x23, 0xA0},
	{0x24, 0x30},
	{0x25, 0x28},
	{0x26, 0x00},
	{0x27, 0x0D},
	{0x28, 0x03},
	{0x29, 0x1D},
	{0x34, 0x80},
	{0x36, 0xA0},
	{0x86, 0x29},
	{0xB5, 0xA0},
	{0x5C, 0xFF},
	{0x2A, 0x01},
	{0x56, 0x90},
	{0x6B, 0x71},
	{0x69, 0x2B},
	{0x10, 0x45},
	{0x11, 0x88},
	{0xB6, 0x20},
	{0x51, 0x20},
	{0x14, 0x43},
	{0x2a, 0x49},
	{0x09, 0x10}
#endif
	{0x20, 0xE0},
	{0x21, 0x20},
	{0x22, 0x31},
	{0x23, 0x2E},
	{0x24, 0x04},
	{0x25, 0x2C},
	{0x26, 0x00},
	{0x27, 0x0F},
	{0x28, 0x01},
	{0x29, 0x10},
	{0x34, 0x80},
	{0x36, 0x2E},
	{0x86, 0x29},
	{0xB5, 0xA0},
	{0x5C, 0xFF},
	{0x2A, 0x01},
	{0x56, 0x90},
	{0x6B, 0x71},
	{0x69, 0x24},
	{0x10, 0xC0},
	{0x11, 0x88},
	{0xB6, 0x20},
	{0x51, 0x20},
	{0x14, 0x43},
	{0x2a, 0x49},
	{0x09, 0x10}
};

#define ICN6211_CMD_CNT (sizeof(icn6211_cmd_table)/sizeof(icn6211_cmd_table[0]))

static struct icn6211 *icn6211_pdata = NULL;

/*simulated i2c ----begin*/
#define OUTP 1
#define INP 0
#define SDA (icn6211_pdata->iic_sda_gp)
#define SCL (icn6211_pdata->iic_scl_gp)

#define  gpio_set_direction(fuck1,fuck2) {if(fuck2==1)gpio_direction_output(fuck1,0);else gpio_direction_input(fuck1);}
#define  gpio_set_val(fuck1,fuck2)       gpio_direction_output(fuck1,fuck2)
#define  gpio_status(fuck1)				 gpio_get_value(fuck1)

static int i2c_start(void)
{

	gpio_set_direction(SDA, OUTP);
	gpio_set_direction (SCL, OUTP);
	gpio_set_val(SCL, 1);
	udelay(50);
	gpio_set_val(SDA, 1);
	udelay(50);

	gpio_set_val(SDA, 0);
	udelay(50);
	gpio_set_val(SCL, 0);
	udelay(50);
	return 0 ;
}

static void i2c_stop(void)
{
	gpio_set_val(SCL, 0);
	udelay(50);
	gpio_set_direction(SDA, OUTP);
	gpio_set_val(SDA, 0);
	udelay(50);
	gpio_set_val(SCL, 1);
	udelay(50);
	gpio_set_val(SDA, 1);
	udelay(50);
}

static unsigned char i2c_read_ack(void)
{
	unsigned char r;
	gpio_set_direction(SDA, INP);
	gpio_set_val(SCL,1);
	udelay(50);
	r = gpio_status(SDA);
	udelay(50);
	gpio_set_val(SCL,0);
	udelay(50);
	return r;
}

#if 0
static int i2c_send_ack(void)
{
	gpio_set_direction(SDA, OUTP);
	gpio_set_val(SDA, 0);
	udelay(50);
	gpio_set_val(SCL,1);
	udelay(50);
	gpio_set_val(SCL,0);
	udelay(50);
	return 0 ;
}
#endif

static int i2c_send_noack(void)
{
	gpio_set_direction(SDA, OUTP);
	gpio_set_val(SDA, 1);
	udelay(50);
	gpio_set_val(SCL,1);
	udelay(50);
	gpio_set_val(SCL,0);
	udelay(50);
	return 0 ;
}
/* I2C write */
static void i2c_write_byte(unsigned char b)
{
	int i;
	gpio_set_direction(SDA, OUTP);
	for (i=7; i>=0; i--) {
		udelay(50);
		gpio_set_val(SDA, !!(b & (1<<i)));
		udelay(50);
		gpio_set_val(SCL, 1);
		udelay(50);
		gpio_set_val(SCL, 0);
	}
	udelay(50);
}
/* I2C read */
unsigned char i2c_read_byte(void)
{
	int i;
	unsigned char r = 0;
	gpio_set_direction(SDA, INP);
	for (i=7; i>=0; i--) {
		gpio_set_val(SCL, 1);
		udelay(50);
		r = (r <<1) | gpio_status(SDA);
		gpio_set_val(SCL, 0);
		udelay(50);
	}
	//i2c_send_ack();
	return r;
}

static int icn6211_i2c_write_byte(struct icn6211 *pdata, char addr, char val)
{
	/*i2c_smbus_write_byte_data()*/
	unsigned char t;
	unsigned char slave_addr = pdata->slave_addr;
	i2c_start();
	t = (slave_addr << 1) | 0;
	i2c_write_byte(t);
	i2c_read_ack();
	i2c_write_byte(addr);
	i2c_read_ack();

	i2c_write_byte(val);
	i2c_read_ack();

	i2c_stop();
	return 0;
}

static int icn6211_i2c_read_byte(struct icn6211 *pdata, char addr)
{
	/*i2c_smbus_read_byte_data()*/
	unsigned char t,val;
    unsigned char slave_addr = pdata->slave_addr;
	i2c_start();
	t = (slave_addr << 1) | 0;
	i2c_write_byte(t);
	i2c_read_ack();
	i2c_write_byte(addr);
	i2c_read_ack();
	i2c_start();
	t = (slave_addr << 1) | 1;
	i2c_write_byte(t);
	i2c_read_ack();
	val = i2c_read_byte();
	i2c_send_noack();
	i2c_stop();
	return val ;
}

static int icn6211_init(struct icn6211 *pdata)
{
	int rc = 0;
	int i = 0;
	const struct init_cmd *cmd_list = icn6211_cmd_table;

	mutex_lock(&pdata->icn6211_mutex);
	if (pdata) {
		for (i = 0; i < ICN6211_CMD_CNT; i++)
		{
			pr_info("ICN6211 write: reg_add=0x%X, reg_val=0x%X\n",
					(cmd_list+i)->reg_add, (cmd_list+i)->reg_val);

			rc = icn6211_i2c_write_byte(pdata, (cmd_list+i)->reg_add, (cmd_list+i)->reg_val);
			if (rc < 0) {
				mutex_unlock(&pdata->icn6211_mutex);
				return rc;
			}
		}
	}

	mutex_unlock(&pdata->icn6211_mutex);
	return rc;
}

static int icn6211_dump(struct icn6211 *pdata)
{
	int rc = 0;
	int i = 0;
	const struct init_cmd *cmd_list = icn6211_cmd_table;

	mutex_lock(&pdata->icn6211_mutex);
	if (pdata) {
		for (i = 0; i < ICN6211_CMD_CNT; i++)
		{
			rc = icn6211_i2c_read_byte(pdata, (cmd_list+i)->reg_add);
			if (rc < 0) {
				mutex_unlock(&pdata->icn6211_mutex);
				return rc;
			}
			pr_info("ICN6211 read : reg_add=0x%X, reg_val=0x%X\n",
					(cmd_list+i)->reg_add, rc);
		}
		rc = icn6211_i2c_read_byte(pdata, 0x00);
		pr_info("ICN6211 read : reg_add=0x00, reg_val=0x%X\n", rc);
	}

	mutex_unlock(&pdata->icn6211_mutex);
	return rc;
}
/*simulated i2c ----end*/

/*simulated spi ----begin*/
#define SPI_SDI(x)	gpio_direction_output(icn6211_pdata->spi_sdi_gp, x)
#define SPI_SDO		gpio_get_value(icn6211_pdata->spi_sdo_gp)
#define SPI_SCK(x)  gpio_direction_output(icn6211_pdata->spi_sck_gp, x)
#define SPI_SCS(x)  gpio_direction_output(icn6211_pdata->spi_csx_gp, x)
#define DelayNs(x)	ndelay(x)

static int spi_write_byte(unsigned char input)
{
	int i = 0;
	SPI_SCS(0);
	DelayNs(50);
	SPI_SDI(1);
	SPI_SCK(0);
	DelayNs(50);
	SPI_SCK(1);
	DelayNs(50);
	for(i = 0; i < 8; i++) {
		SPI_SCK(0);

		if (input & 0x80) {
			SPI_SDI(1);
		} else {
			SPI_SDI(0);
		}

		DelayNs(50);
		SPI_SCK(1);

		input <<= 1;
	}
	return 0;
}

static int spi_read_byte(void)
{
	int i = 0;
	int data = 0;

	SPI_SCS(0);
	DelayNs(150);

	for (i = 0; i < 8; i++) {
		data <<= 1;
		SPI_SCK(0);
		DelayNs(150);
		SPI_SCK(1);
		data |= SPI_SDO;
		DelayNs(50);
	}

	return data;
}

static int SPI_WriteCmd(unsigned char cmd)
{
	return spi_write_byte(cmd);
}

static int SPI_WriteDat(unsigned char dat)
{
	return spi_write_byte(dat);
}

static int lcd_read_dat(void)
{
	return spi_read_byte();
}
/*simulated spi ----end*/

/*lcd init cmd ---- begin*/
#define RESET_LCD(x)	gpio_direction_output(icn6211_pdata->lcd_rst_gp, x)
#define DelayMs(x)		mdelay(x)

static void lcd_init(void)
{
	pr_info("icn6211 lcd_init\n");

	RESET_LCD(1);
	DelayMs(10);
	RESET_LCD(0);
	DelayMs(10);
	RESET_LCD(1);
	DelayMs(120);

	/***************page one command**************/
	SPI_WriteCmd(0xff);
	SPI_WriteDat(0xff);
	SPI_WriteDat(0x98);
	SPI_WriteDat(0x06);
	SPI_WriteDat(0x04);
	SPI_WriteDat(0x01);

	/***************interface mode**************/
	SPI_WriteCmd(0x08);
	SPI_WriteDat(0x10);

	/***************source output direction**************/
	SPI_WriteCmd(0x22);
	SPI_WriteDat(0x00);

	/***************resolution control**************/
	SPI_WriteCmd(0x30);
	SPI_WriteDat(0x02);

	/***************Display Inversion Control**************/
	SPI_WriteCmd(0x31);
	SPI_WriteDat(0x02);

	/***************Power Control**************/
	SPI_WriteCmd(0x40);
	SPI_WriteDat(0x15);

	SPI_WriteCmd(0x41);
	SPI_WriteDat(0x33);

	SPI_WriteCmd(0x42);
	SPI_WriteDat(0x02);

	SPI_WriteCmd(0x43);
	SPI_WriteDat(0x09);

	SPI_WriteCmd(0x44);
	SPI_WriteDat(0x06);

	SPI_WriteCmd(0x45);
	SPI_WriteDat(0xD6);

	SPI_WriteCmd(0x50);
	SPI_WriteDat(0x70);

	SPI_WriteCmd(0x51);
	SPI_WriteDat(0x70);

	/***************Vcom Setting**************/
	SPI_WriteCmd(0x52);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x53);
	SPI_WriteDat(0x2B);

	SPI_WriteCmd(0x54);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x55);
	SPI_WriteDat(0x39);

	/***************Timing**************/
	SPI_WriteCmd(0x60);
	SPI_WriteDat(0x07);

	SPI_WriteCmd(0x61);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x62);
	SPI_WriteDat(0x09);

	SPI_WriteCmd(0x63);
	SPI_WriteDat(0x00);

	/***************Power Gamma Settipng**************/
	SPI_WriteCmd(0xa0);
	SPI_WriteDat(0x08);

	SPI_WriteCmd(0xa1);
	SPI_WriteDat(0x14);

	SPI_WriteCmd(0xa2);
	SPI_WriteDat(0x1C) ;

	SPI_WriteCmd(0xa3);
	SPI_WriteDat(0x0D);

	SPI_WriteCmd(0xa4);
	SPI_WriteDat(0x06) ;

	SPI_WriteCmd(0xa5);
	SPI_WriteDat(0x0E);

	SPI_WriteCmd(0xa6);
	SPI_WriteDat(0x08);

	SPI_WriteCmd(0xa7);
	SPI_WriteDat(0x07);

	SPI_WriteCmd(0xa8);
	SPI_WriteDat(0x06);

	SPI_WriteCmd(0xa9);
	SPI_WriteDat(0x1A);

	SPI_WriteCmd(0xaa);
	SPI_WriteDat(0x0B);

	SPI_WriteCmd(0xab);
	SPI_WriteDat(0x04);

	SPI_WriteCmd(0xac);
	SPI_WriteDat(0x0a);

	SPI_WriteCmd(0xad);
	SPI_WriteDat(0x14);

	SPI_WriteCmd(0xae);
	SPI_WriteDat(0x10);

	SPI_WriteCmd(0xaf);
	SPI_WriteDat(0x08);

	/***************Negitive Gamma setting**************/
	SPI_WriteCmd(0xc0);
	SPI_WriteDat(0x08);

	SPI_WriteCmd(0xc1);
	SPI_WriteDat(0x15);

	SPI_WriteCmd(0xc2);
	SPI_WriteDat(0x1d);

	SPI_WriteCmd(0xc3);
	SPI_WriteDat(0x0d);

	SPI_WriteCmd(0xc4);
	SPI_WriteDat(0x06);

	SPI_WriteCmd(0xc5);
	SPI_WriteDat(0x0F);

	SPI_WriteCmd(0xc6);
	SPI_WriteDat(0x08);

	SPI_WriteCmd(0xc7);
	SPI_WriteDat(0x07);

	SPI_WriteCmd(0xc8);
	SPI_WriteDat(0x06);

	SPI_WriteCmd(0xc9);
	SPI_WriteDat(0x1a);

	SPI_WriteCmd(0xca);
	SPI_WriteDat(0x0b);

	SPI_WriteCmd(0xcb);
	SPI_WriteDat(0x04);

	SPI_WriteCmd(0xcc);
	SPI_WriteDat(0x0a);

	SPI_WriteCmd(0xcd);
	SPI_WriteDat(0x14);

	SPI_WriteCmd(0xce);
	SPI_WriteDat(0x10);

	SPI_WriteCmd(0xcf);
	SPI_WriteDat(0x08);
	DelayMs(10);

	/***************Page 6 Command**************/
	SPI_WriteCmd(0xff);
	SPI_WriteDat(0xff);
	SPI_WriteDat(0x98);
	SPI_WriteDat(0x06);
	SPI_WriteDat(0x04);
	SPI_WriteDat(0x06);

	/***************GIP Setting**************/
	SPI_WriteCmd(0x00);
	SPI_WriteDat(0x21);

	SPI_WriteCmd(0x01);
	SPI_WriteDat(0x0A);

	SPI_WriteCmd(0x02);
	SPI_WriteDat(0x60);

	SPI_WriteCmd(0x03);
	SPI_WriteDat(0x0F);

	SPI_WriteCmd(0x04);
	SPI_WriteDat(0x01);

	SPI_WriteCmd(0x05);
	SPI_WriteDat(0x01);

	SPI_WriteCmd(0x06);
	SPI_WriteDat(0x80);

	SPI_WriteCmd(0x07);
	SPI_WriteDat(0x06);

	SPI_WriteCmd(0x08);
	SPI_WriteDat(0x01);

	SPI_WriteCmd(0x09);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x0A);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x0B);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x0C);
	SPI_WriteDat(0x01);

	SPI_WriteCmd(0x0D);
	SPI_WriteDat(0x01);

	SPI_WriteCmd(0x0E);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x0F);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x10);
	SPI_WriteDat(0xF7);

	SPI_WriteCmd(0x11);
	SPI_WriteDat(0xF0);

	SPI_WriteCmd(0x12);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x13);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x14);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x15);
	SPI_WriteDat(0xC0);

	SPI_WriteCmd(0x16);
	SPI_WriteDat(0x08);

	SPI_WriteCmd(0x17);
	SPI_WriteDat(0x01);

	SPI_WriteCmd(0x18);
	SPI_WriteDat(0x01);

	SPI_WriteCmd(0x19);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x1A);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x1B);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x1C);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x1D);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x20);
	SPI_WriteDat(0x01);

	SPI_WriteCmd(0x21);
	SPI_WriteDat(0x23);

	SPI_WriteCmd(0x22);
	SPI_WriteDat(0x45);

	SPI_WriteCmd(0x23);
	SPI_WriteDat(0x67);

	SPI_WriteCmd(0x24);
	SPI_WriteDat(0x01);

	SPI_WriteCmd(0x25);
	SPI_WriteDat(0x23);

	SPI_WriteCmd(0x26);
	SPI_WriteDat(0x45);

	SPI_WriteCmd(0x27);
	SPI_WriteDat(0x67);

	SPI_WriteCmd(0x30);
	SPI_WriteDat(0x01);

	SPI_WriteCmd(0x31);
	SPI_WriteDat(0xDA);

	SPI_WriteCmd(0x32);
	SPI_WriteDat(0xCB);

	SPI_WriteCmd(0x33);
	SPI_WriteDat(0x22);

	SPI_WriteCmd(0x34);
	SPI_WriteDat(0x22);

	SPI_WriteCmd(0x35);
	SPI_WriteDat(0x11);

	SPI_WriteCmd(0x36);
	SPI_WriteDat(0x00);

	SPI_WriteCmd(0x37);
	SPI_WriteDat(0xAD);

	SPI_WriteCmd(0x38);
	SPI_WriteDat(0xBC);

	SPI_WriteCmd(0x39);
	SPI_WriteDat(0x76);

	SPI_WriteCmd(0x3A);
	SPI_WriteDat(0x67);

	SPI_WriteCmd(0x3B);
	SPI_WriteDat(0x88);

	SPI_WriteCmd(0x3C);
	SPI_WriteDat(0x22);

	SPI_WriteCmd(0x3D);
	SPI_WriteDat(0x22);

	SPI_WriteCmd(0x3E);
	SPI_WriteDat(0x22);

	SPI_WriteCmd(0x3F);
	SPI_WriteDat(0x22);

	SPI_WriteCmd(0x40);
	SPI_WriteDat(0x22);


	/***************page 7 Command**************/
	SPI_WriteCmd(0xff);
	SPI_WriteDat(0xff);
	SPI_WriteDat(0x98);
	SPI_WriteDat(0x06);
	SPI_WriteDat(0x04);
	SPI_WriteDat(0x07);

	/***************VrEG1/2 Out Enable**************/
	SPI_WriteCmd(0x18);
	SPI_WriteDat(0x1D);

	/***************VGL_REG EN**************/
	SPI_WriteCmd(0x17);
	SPI_WriteDat(0x32);

	/***************Power Bais Control**************/
	SPI_WriteCmd(0x02);
	SPI_WriteDat(0x77);

	SPI_WriteCmd(0xE1);
	SPI_WriteDat(0x79);

	SPI_WriteCmd(0x26);
	SPI_WriteDat(0xB2);

	/***************Page 0 Command**************/
	SPI_WriteCmd(0xff);
	SPI_WriteDat(0xff);
	SPI_WriteDat(0x98);
	SPI_WriteDat(0x06);
	SPI_WriteDat(0x04);
	SPI_WriteDat(0x00);

	/***************Interface Pixel Format**************/
	SPI_WriteCmd(0x3A);
	SPI_WriteDat(0x70);

	/***************Display Access Control**************/
	/***************如果出现红蓝反色,请下0x0b,反扫下0x08**************/
	SPI_WriteCmd(0x36);
	SPI_WriteDat(0x03);

	/***************sleep out**************/
	SPI_WriteCmd(0x11);
	SPI_WriteDat(0x00);
	DelayMs(120);
	/***************diplay on**************/
	SPI_WriteCmd(0x29);
	SPI_WriteDat(0x00);
	DelayMs(20);
	lcd_read_dat();
}
/*lcd init cmd ---- end*/

static int icn6211_gpio_init(struct icn6211 *pdata)
{
	int ret = 0;

	/*enable gpio*/
	if (!gpio_is_valid(pdata->en_gp)) {
		pr_err("%s,enable gpio [%d] is invalid!\n",
				__func__, pdata->en_gp);
		return -1;
	}

	ret = gpio_request(pdata->en_gp, "icn6211-en-gpio");
	if (ret) {
		pr_err("%s, Unable to request icn6211 en-gpio\n",__func__);
	}

	ret = gpio_direction_output(pdata->en_gp, 1);
	if (ret) {
		pr_err("%s, Unable to pull up icn6211 en-gpio\n",__func__);
	}
	mdelay(5);
	ret = gpio_direction_output(pdata->en_gp, 0);
	if (ret) {
		pr_err("%s, Unable to pull up icn6211 en-gpio\n",__func__);
	}
	mdelay(15);
	ret = gpio_direction_output(pdata->en_gp, 1);
	if (ret) {
		pr_err("%s, Unable to pull up icn6211 en-gpio\n",__func__);
	}

	/*rgb-lcd-rest gpio*/
	if (gpio_is_valid(pdata->lcd_rst_gp)) {
		ret = gpio_request(pdata->lcd_rst_gp, "icn6211-rgb-lcd-rest");
		if (ret < 0) {
			pr_err("Failed to request GPIO:%d, ERRNO:%d",
					pdata->lcd_rst_gp, ret);
			return -ENODEV;
		} else {
			ret = gpio_direction_output(pdata->lcd_rst_gp, 1);
			if (ret)
				pr_err("Failed to set icn6211-rgb-lcd-rest\n");
			mdelay(5);
		}
	} else {
		pr_err("%s, no rgb lcd rest gpio !!!!!\n",__func__);
		return -1;
	}

	/*i2c-scl*/
	if (gpio_is_valid(pdata->iic_scl_gp)) {
		ret = gpio_request(pdata->iic_scl_gp, "icn6211-i2c-scl");
		if (ret < 0) {
			pr_err("Failed to request GPIO:%d, ERRNO:%d",
					pdata->iic_scl_gp, ret);
			return -ENODEV;
		} else {
			ret = gpio_direction_output(pdata->iic_scl_gp, 1);
			if (ret)
				pr_err("Failed to set icn6211-i2c-scl-gpio\n");
			mdelay(5);
		}
	} else {
		pr_err("%s, no scl gpio !!!!!\n",__func__);
		return -1;
	}
	/*i2c-sda*/
	if (gpio_is_valid(pdata->iic_sda_gp)) {
		ret = gpio_request(pdata->iic_sda_gp, "icn6211-i2c-sda");
		if (ret < 0) {
			pr_err("Failed to request GPIO:%d, ERRNO:%d",
					pdata->iic_sda_gp, ret);
			return -ENODEV;
		} else {
			ret = gpio_direction_output(pdata->iic_sda_gp, 1);
			if (ret)
				pr_err("Failed to set icn6211-i2c-sda-gpio\n");
			mdelay(5);
		}
	} else {
		pr_err("%s, no sda gpio !!!!!\n",__func__);
		return -1;
	}

	/*spi*/
	/*spi-sdi*/
	if (gpio_is_valid(pdata->spi_sdi_gp)) {
		ret = gpio_request(pdata->spi_sdi_gp, "icn6211-spi-sdi");
		if (ret < 0) {
			pr_err("Failed to request GPIO:%d, ERRNO:%d",
					pdata->spi_sdi_gp, ret);
			return -ENODEV;
		} else {
			ret = gpio_direction_output(pdata->spi_sdi_gp, 1);
			if (ret)
				pr_err("Failed to set icn6211-spi-sdi-gpio\n");
			mdelay(5);
		}
	} else {
		pr_err("%s, no spi-sdi gpio !!!!!\n",__func__);
		return -1;
	}

	/*spi-sdo*/
	if (gpio_is_valid(pdata->spi_sdo_gp)) {
		ret = gpio_request(pdata->spi_sdo_gp, "icn6211-spi-sdo");
		if (ret < 0) {
			pr_err("Failed to request GPIO:%d, ERRNO:%d",
					pdata->spi_sdo_gp, ret);
			return -ENODEV;
		} else {
			ret = gpio_direction_input(pdata->spi_sdo_gp);
			if (ret)
				pr_err("Failed to set icn6211-spi-sdo-gpio\n");
			mdelay(5);
		}
	} else {
		pr_err("%s, no spi-sdo gpio !!!!!\n",__func__);
		return -1;
	}

	/*spi-cs*/
	if (gpio_is_valid(pdata->spi_csx_gp)) {
		ret = gpio_request(pdata->spi_csx_gp, "icn6211-spi-cs");
		if (ret < 0) {
			pr_err("Failed to request GPIO:%d, ERRNO:%d",
					pdata->spi_csx_gp, ret);
			return -ENODEV;
		} else {
			ret = gpio_direction_output(pdata->spi_csx_gp, 1);
			if (ret)
				pr_err("Failed to set icn6211-spi-cs-gpio\n");
			mdelay(5);
		}
	} else {
		pr_err("%s, nospi-cs gpio !!!!!\n",__func__);
		return -1;
	}

	/*spi-sc*/
	if (gpio_is_valid(pdata->spi_sck_gp)) {
		ret = gpio_request(pdata->spi_sck_gp, "icn6211-spi-sc");
		if (ret < 0) {
			pr_err("Failed to request GPIO:%d, ERRNO:%d",
					pdata->spi_sck_gp, ret);
			return -ENODEV;
		} else {
			ret = gpio_direction_output(pdata->spi_sck_gp, 1);
			if (ret)
				pr_err("Failed to set icn6211-spi-sc-gpio\n");
			mdelay(5);
		}
	} else {
		pr_err("%s, no spi-sc gpio !!!!!\n",__func__);
		return -1;
	}

	return ret;
}

static int icn6211_parse_dt(struct device *dev, struct icn6211 *pdata)
{
	int rc = 0;
	struct device_node *np = dev->of_node;

	pdata->en_gp = of_get_named_gpio(np, "icn6211,en-gp", 0);
	pdata->lcd_rst_gp = of_get_named_gpio(np, "icn6211,lcd-rst-gp", 0);
	pdata->iic_scl_gp = of_get_named_gpio(np, "icn6211,iic-scl-gp", 0);
	pdata->iic_sda_gp = of_get_named_gpio(np, "icn6211,iic_sda_gp", 0);
	pdata->spi_sdi_gp = of_get_named_gpio(np, "icn6211,spi_sdi_gp", 0);
	pdata->spi_sdo_gp = of_get_named_gpio(np, "icn6211,spi_sdo_gp", 0);
	pdata->spi_csx_gp = of_get_named_gpio(np, "icn6211,spi_csx_gp", 0);
	pdata->spi_sck_gp = of_get_named_gpio(np, "icn6211,spi_sck_gp", 0);
	//pdata->rgb_or_lvds = of_get_property(np, "icn6211,use-rgb", 0);
	pdata->rgb_or_lvds = 1;
	//of_property_read_u32(np, "icn6211,slave_addr", &pdata->slave_addr);
	pdata->slave_addr = 0x2C;

	pr_info("iic scl=%d,sda=%d\n",pdata->iic_scl_gp, pdata->iic_sda_gp);
	pr_info("spi sdi=%d,sdo=%d,cs=%d,sc=%d\n",
			pdata->spi_sdi_gp,pdata->spi_sdo_gp,pdata->spi_csx_gp,pdata->spi_sck_gp);
	pr_info("icn6211 slave add=0x%X, enable-gpio=%d, lcd-rst=%d\n",
	       pdata->slave_addr,pdata->en_gp,pdata->lcd_rst_gp);

	return rc;
}

static int icn6211_probe(struct platform_device *pdev)
{
	struct icn6211 *pdata;
	int ret = 0;

	pr_info("ICN6211:%s\n",__func__);

	pdata = kzalloc(sizeof(struct icn6211), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;
	if (pdev->dev.of_node) {
		icn6211_parse_dt(&pdev->dev, pdata);
	} else {
		pr_err("ICN6211: no device node,exit...\n");
		ret = -1;
		goto err_exit;
	}
	ret = icn6211_gpio_init(pdata);
	if (ret) {
		pr_err("%s: Failed to configure GPIOs\n", __func__);
		goto err_exit;
	}

	mutex_init(&pdata->icn6211_mutex);
	dev_set_drvdata(&pdev->dev, pdata);

	icn6211_pdata = pdata;
	lcd_init();
	mdelay(5);
	icn6211_init(pdata);
	mdelay(5);
	icn6211_dump(pdata);

	return 0;

err_exit:
	kfree(pdata);
	icn6211_pdata = NULL;
	return ret;
}


static const struct of_device_id icn6211_of_match[] = {
	{ .compatible = "qcom,icn6211",},
	{},
};

static int icn6211_resume(struct device *pdev)
{
/* 	Reset_chip();
	mdss_mipi_i2c_init(); */
	return 0;
}

static int icn6211_remove(struct platform_device *pdev) {

	return 0;
}

static int icn6211_suspend(struct device *tdev) {
	/* gpio_direction_output(lt8912b_pdata->rst_gpio, 0); */
	return 0;
}

static const struct dev_pm_ops icn6211_pm_ops =
{
	.suspend = icn6211_suspend,
	.resume = icn6211_resume,
};


static struct platform_driver icn6211_driver = {
	.driver = {
		.name = "qcom,icn6211",
		.owner    = THIS_MODULE,
		.of_match_table = icn6211_of_match,
		.pm = &icn6211_pm_ops,
	},
	.probe    = icn6211_probe,
	.remove   = icn6211_remove,
};

static int __init icn6211_rgb_lvds_init(void)
{
	int ret;

	ret = platform_driver_register(&icn6211_driver);
	if (ret)
		printk(KERN_ERR "icn6211_driver: probe failed: %d\n", ret);

	return ret;
}

static void __exit icn6211_rgb_lvds_exit(void)
{
	platform_driver_unregister(&icn6211_driver);
}

subsys_initcall(icn6211_rgb_lvds_init);
//module_init(mipi_gpio_i2c_init);
//late_initcall(mipi_gpio_i2c_init);
module_exit(icn6211_rgb_lvds_exit);
MODULE_LICENSE("GPL");

另外一个版本,i2c 使用的是硬件的,非模拟i2c。前面一个版本是 i2c和SPI都模拟了

/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only 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.
 *
 * 
 * version:1.0
 * data:2017.9.9
 * function description : mipi-2-rgb (icn6211) device driver which tranfer msg via i2c
 *
 */
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
//#include "msm_dba_internal.h"
#include <linux/mdss_io_util.h>
#include <linux/slab.h>

/********************************** simulated spi & initialize rgb lcd via spi  begein ***********************************************/
/* GPIO126 / GPIO60 / GPIO38 / GPIO31 / GPIO32 */
#define DISP_CSX	(126) /* cs */
#define DISP_WRX	(38)  /* scl */
#define DISP_SDO	(31)  /* sdo */
#define DISP_SDI	(32)  /* sdi */
#define DISP_RST	(60)  /* rst */


#define LCD_W  800
#define LCD_H  480

/**************************************************************
	otm8019 lcd  -->zzd
	
***************************************************************/
#define SET_SPI_CS_HIGH()	gpio_direction_output(DISP_CSX, 1)//CS
#define SET_SPI_CS_LOW()	gpio_direction_output(DISP_CSX, 0)//CS
	
#define SET_SPI_CLK_HIGH()	gpio_direction_output(DISP_WRX, 1)//CLK
#define SET_SPI_CLK_LOW()	gpio_direction_output(DISP_WRX, 0)//CLK
	
#define SET_SPI_MOSI_HIGH() gpio_direction_output(DISP_SDI, 1)//MOSI
#define SET_SPI_MOSI_LOW()	gpio_direction_output(DISP_SDI, 0)//MOSI

#define SET_SPI_MISO()		gpio_direction_input(DISP_SDO)//MISO

#define RESET_SCREEN()		{ gpio_direction_output(DISP_RST, 1);gpio_direction_output(DISP_RST, 0);udelay(100);gpio_direction_output(DISP_RST, 1);udelay(100);}

#define OTM8018B_WCMDH 	0x20
#define OTM8018B_WCMDL 	0x00
#define OTM8018B_WDATA 	0x40
#define LCD_DELAY_1MS    15000          // Sufficient under 1Ghz
#define SPI_DELAY        200
#define ICN6211_SLAVE_ADD	0x2C


void lcd_gpio_init(void)
{
	int ret = 0;

	pr_info("[spilcd] %s, begin...\n",__func__);

	ret = gpio_request(DISP_RST, "display-spi-rst");
	if (ret) {
		pr_err("DISP_RST gpio request failed111\n");
		return;
	}
	gpio_direction_output(DISP_RST, 1);

	ret = gpio_request(DISP_WRX, "display-spi-clk");
	if (ret) {
		pr_err("DISP_WRX gpio request failed111\n");
		return;
	}
	SET_SPI_CLK_HIGH();

	ret = gpio_request(DISP_SDO, "display-spi-sdo");
	if (ret) {
		pr_err("DISP_SDO gpio request failed111\n");
		return;
	}
	SET_SPI_MOSI_HIGH();

	ret = gpio_request(DISP_CSX, "display-spi-cs");
	if (ret) { 
		pr_err("DISP_CSX gpio request failed111\n");
		return;
	}
	SET_SPI_CS_HIGH();

	ret = gpio_request(DISP_SDI, "display-spi-sdi");
	if (ret) {
		pr_err("DISP_SDI gpio request failed111\n");
		return;
	}
	SET_SPI_MISO();
	pr_info("[spilcd] %s, end...\n",__func__);

	return ;
}

static void delay_loop(int delay)
{
    volatile int j,i;
    for(j = 0; j < delay; j++)
		i++;
}

void Spi_Write_Byte( unsigned char ddat )
{
    unsigned char i;

    for (i = 0; i< 8; i++){
 	//SCL0=0;//IM3=0
	//delay(10);
       SET_SPI_CLK_LOW();
       if (ddat&0x80) {
           SET_SPI_MOSI_HIGH();
       } else {
           SET_SPI_MOSI_LOW();
       }

       //SET_SPI_CLK_LOW();
       delay_loop(SPI_DELAY);
       SET_SPI_CLK_HIGH();
       delay_loop(SPI_DELAY);
       //SCL0=0;//IM3=0
       //SCL0=1;
	  //delay(10);
       //ddat=(ddat<<=1);
	   ddat <<= 1;
    }
	return ;
}

void SPI_Write_CMD_OTM8018B(unsigned short SPI_data)//word
{
          
    SET_SPI_CS_LOW();
    Spi_Write_Byte(OTM8018B_WCMDH);
    Spi_Write_Byte((SPI_data&0xFF00) >> 8);
 //CSB=1;//
    SET_SPI_CS_LOW();
    Spi_Write_Byte(OTM8018B_WCMDL);
    Spi_Write_Byte(SPI_data & 0x00FF);
    SET_SPI_CS_HIGH();
}

void SPI_Write_DATA_OTM8018B(unsigned char  SPI_data)
{
    SET_SPI_CS_LOW();
    Spi_Write_Byte(OTM8018B_WDATA);
    Spi_Write_Byte(SPI_data);
    SET_SPI_CS_HIGH();
}


void otm8019_ldi_init(void)
{	
	SET_SPI_CLK_LOW();
 
	SPI_Write_CMD_OTM8018B(0xFF00); SPI_Write_DATA_OTM8018B(0x80); 
	SPI_Write_CMD_OTM8018B(0xFF01); SPI_Write_DATA_OTM8018B(0x19); 
	SPI_Write_CMD_OTM8018B(0xFF02); SPI_Write_DATA_OTM8018B(0x01); 

	SPI_Write_CMD_OTM8018B(0xFF80); SPI_Write_DATA_OTM8018B(0x80); 
	SPI_Write_CMD_OTM8018B(0xFF81); SPI_Write_DATA_OTM8018B(0x19); 

	SPI_Write_CMD_OTM8018B(0xC48A); SPI_Write_DATA_OTM8018B(0x40); 

	SPI_Write_CMD_OTM8018B(0xB3A6); SPI_Write_DATA_OTM8018B(0x20);		//
	SPI_Write_CMD_OTM8018B(0xB3A7); SPI_Write_DATA_OTM8018B(0x01); 

	SPI_Write_CMD_OTM8018B(0xC090); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xC091); SPI_Write_DATA_OTM8018B(0x15); 
	SPI_Write_CMD_OTM8018B(0xC092); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xC093); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xC094); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xC095); SPI_Write_DATA_OTM8018B(0x03); 

	SPI_Write_CMD_OTM8018B(0xC0B4); SPI_Write_DATA_OTM8018B(0x70); 

	SPI_Write_CMD_OTM8018B(0xC181); SPI_Write_DATA_OTM8018B(0x33); 

	SPI_Write_CMD_OTM8018B(0xC481); SPI_Write_DATA_OTM8018B(0x81); 

	SPI_Write_CMD_OTM8018B(0xC487); SPI_Write_DATA_OTM8018B(0x00); 

	SPI_Write_CMD_OTM8018B(0xC489); SPI_Write_DATA_OTM8018B(0x00); 

	SPI_Write_CMD_OTM8018B(0xC582); SPI_Write_DATA_OTM8018B(0xB0); 

	SPI_Write_CMD_OTM8018B(0xC590); SPI_Write_DATA_OTM8018B(0x4E); 
	SPI_Write_CMD_OTM8018B(0xC591); SPI_Write_DATA_OTM8018B(0x34); 
	SPI_Write_CMD_OTM8018B(0xC592); SPI_Write_DATA_OTM8018B(0x06); 
	SPI_Write_CMD_OTM8018B(0xC593); SPI_Write_DATA_OTM8018B(0x91); 
	SPI_Write_CMD_OTM8018B(0xC594); SPI_Write_DATA_OTM8018B(0x33); 
	SPI_Write_CMD_OTM8018B(0xC595); SPI_Write_DATA_OTM8018B(0x34); 
	SPI_Write_CMD_OTM8018B(0xC596); SPI_Write_DATA_OTM8018B(0x23); 

	SPI_Write_CMD_OTM8018B(0xC5B1); SPI_Write_DATA_OTM8018B(0xA8); 

	SPI_Write_CMD_OTM8018B(0xD800); SPI_Write_DATA_OTM8018B(0x6F); 
	SPI_Write_CMD_OTM8018B(0xD801); SPI_Write_DATA_OTM8018B(0x6F); 

	SPI_Write_CMD_OTM8018B(0xD900); SPI_Write_DATA_OTM8018B(0x23);
	SPI_Write_CMD_OTM8018B(0xCE80); SPI_Write_DATA_OTM8018B(0x86); 
	SPI_Write_CMD_OTM8018B(0xCE81); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCE82); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCE83); SPI_Write_DATA_OTM8018B(0x85); 
	SPI_Write_CMD_OTM8018B(0xCE84); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCE85); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCE86); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCE87); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCE88); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCE89); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCE8A); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCE8B); SPI_Write_DATA_OTM8018B(0x00); 

	SPI_Write_CMD_OTM8018B(0xCEA0); SPI_Write_DATA_OTM8018B(0x18); 
	SPI_Write_CMD_OTM8018B(0xCEA1); SPI_Write_DATA_OTM8018B(0x05); 
	SPI_Write_CMD_OTM8018B(0xCEA2); SPI_Write_DATA_OTM8018B(0x83); 
	SPI_Write_CMD_OTM8018B(0xCEA3); SPI_Write_DATA_OTM8018B(0x39); 
	SPI_Write_CMD_OTM8018B(0xCEA4); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCEA5); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCEA6); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCEA7); SPI_Write_DATA_OTM8018B(0x18); 
	SPI_Write_CMD_OTM8018B(0xCEA8); SPI_Write_DATA_OTM8018B(0x04); 
	SPI_Write_CMD_OTM8018B(0xCEA9); SPI_Write_DATA_OTM8018B(0x83); 
	SPI_Write_CMD_OTM8018B(0xCEAA); SPI_Write_DATA_OTM8018B(0x3A); 
	SPI_Write_CMD_OTM8018B(0xCEAB); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCEAC); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCEAD); SPI_Write_DATA_OTM8018B(0x00); 

	SPI_Write_CMD_OTM8018B(0xCEB0); SPI_Write_DATA_OTM8018B(0x18); 
	SPI_Write_CMD_OTM8018B(0xCEB1); SPI_Write_DATA_OTM8018B(0x03); 
	SPI_Write_CMD_OTM8018B(0xCEB2); SPI_Write_DATA_OTM8018B(0x83); 
	SPI_Write_CMD_OTM8018B(0xCEB3); SPI_Write_DATA_OTM8018B(0x3B); 
	SPI_Write_CMD_OTM8018B(0xCEB4); SPI_Write_DATA_OTM8018B(0x86); 
	SPI_Write_CMD_OTM8018B(0xCEB5); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCEB6); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCEB7); SPI_Write_DATA_OTM8018B(0x18); 
	SPI_Write_CMD_OTM8018B(0xCEB8); SPI_Write_DATA_OTM8018B(0x02); 
	SPI_Write_CMD_OTM8018B(0xCEB9); SPI_Write_DATA_OTM8018B(0x83); 
	SPI_Write_CMD_OTM8018B(0xCEBA); SPI_Write_DATA_OTM8018B(0x3C); 
	SPI_Write_CMD_OTM8018B(0xCEBB); SPI_Write_DATA_OTM8018B(0x88); 
	SPI_Write_CMD_OTM8018B(0xCEBC); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCEBD); SPI_Write_DATA_OTM8018B(0x00); 

	SPI_Write_CMD_OTM8018B(0xCFC0); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCFC1); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCFC2); SPI_Write_DATA_OTM8018B(0x20); 
	SPI_Write_CMD_OTM8018B(0xCFC3); SPI_Write_DATA_OTM8018B(0x20); 
	SPI_Write_CMD_OTM8018B(0xCFC4); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCFC5); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCFC6); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCFC7); SPI_Write_DATA_OTM8018B(0x02); 
	SPI_Write_CMD_OTM8018B(0xCFC8); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCFC9); SPI_Write_DATA_OTM8018B(0x00); 

	SPI_Write_CMD_OTM8018B(0xCFD0); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCBC0); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBC1); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCBC2); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCBC3); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCBC4); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCBC5); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCBC6); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBC7); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBC8); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBC9); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBCA); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBCB); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBCC); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBCD); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBCE); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCBD0); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCBD5); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBD6); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBD7); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBD8); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBD9); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBDA); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBDB); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBDC); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBDD); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCBDE); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCBE0); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCBE1); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCBE2); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCBE3); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCBE4); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCBE5); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCC80); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC81); SPI_Write_DATA_OTM8018B(0x26); 
	SPI_Write_CMD_OTM8018B(0xCC82); SPI_Write_DATA_OTM8018B(0x09); 
	SPI_Write_CMD_OTM8018B(0xCC83); SPI_Write_DATA_OTM8018B(0x0B); 
	SPI_Write_CMD_OTM8018B(0xCC84); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCC85); SPI_Write_DATA_OTM8018B(0x25); 
	SPI_Write_CMD_OTM8018B(0xCC86); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC87); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC88); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC89); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCC90); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC91); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC92); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC93); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC94); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC95); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCC9A); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC9B); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC9C); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC9D); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCC9E); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCCA0); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCA1); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCA2); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCA3); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCA4); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCA5); SPI_Write_DATA_OTM8018B(0x25); 
	SPI_Write_CMD_OTM8018B(0xCCA6); SPI_Write_DATA_OTM8018B(0x02); 
	SPI_Write_CMD_OTM8018B(0xCCA7); SPI_Write_DATA_OTM8018B(0x0C); 
	SPI_Write_CMD_OTM8018B(0xCCA8); SPI_Write_DATA_OTM8018B(0x0A); 
	SPI_Write_CMD_OTM8018B(0xCCA9); SPI_Write_DATA_OTM8018B(0x26); 
	SPI_Write_CMD_OTM8018B(0xCCAA); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCCB0); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCB1); SPI_Write_DATA_OTM8018B(0x25); 
	SPI_Write_CMD_OTM8018B(0xCCB2); SPI_Write_DATA_OTM8018B(0x0C); 
	SPI_Write_CMD_OTM8018B(0xCCB3); SPI_Write_DATA_OTM8018B(0x0A); 
	SPI_Write_CMD_OTM8018B(0xCCB4); SPI_Write_DATA_OTM8018B(0x02); 
	SPI_Write_CMD_OTM8018B(0xCCB5); SPI_Write_DATA_OTM8018B(0x26); 
	SPI_Write_CMD_OTM8018B(0xCCB6); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCB7); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCB8); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCB9); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCCC0); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCC1); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCC2); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCC3); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCC4); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCC5); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCCCA); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCCB); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCCC); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCCD); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCCE); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xCCD0); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCD1); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCD2); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCD3); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCD4); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xCCD5); SPI_Write_DATA_OTM8018B(0x26); 
	SPI_Write_CMD_OTM8018B(0xCCD6); SPI_Write_DATA_OTM8018B(0x01); 
	SPI_Write_CMD_OTM8018B(0xCCD7); SPI_Write_DATA_OTM8018B(0x09); 
	SPI_Write_CMD_OTM8018B(0xCCD8); SPI_Write_DATA_OTM8018B(0x0B); 
	SPI_Write_CMD_OTM8018B(0xCCD9); SPI_Write_DATA_OTM8018B(0x25); 
	SPI_Write_CMD_OTM8018B(0xCCDA); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xE100); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xE101); SPI_Write_DATA_OTM8018B(0x07); 
	SPI_Write_CMD_OTM8018B(0xE102); SPI_Write_DATA_OTM8018B(0x10); 
	SPI_Write_CMD_OTM8018B(0xE103); SPI_Write_DATA_OTM8018B(0x22); 
	SPI_Write_CMD_OTM8018B(0xE104); SPI_Write_DATA_OTM8018B(0x40); 
	SPI_Write_CMD_OTM8018B(0xE105); SPI_Write_DATA_OTM8018B(0x56); 
	SPI_Write_CMD_OTM8018B(0xE106); SPI_Write_DATA_OTM8018B(0x66); 
	SPI_Write_CMD_OTM8018B(0xE107); SPI_Write_DATA_OTM8018B(0x99); 
	SPI_Write_CMD_OTM8018B(0xE108); SPI_Write_DATA_OTM8018B(0x88); 
	SPI_Write_CMD_OTM8018B(0xE109); SPI_Write_DATA_OTM8018B(0x9F); 
	SPI_Write_CMD_OTM8018B(0xE10A); SPI_Write_DATA_OTM8018B(0x6A); 
	SPI_Write_CMD_OTM8018B(0xE10B); SPI_Write_DATA_OTM8018B(0x5A); 
	SPI_Write_CMD_OTM8018B(0xE10C); SPI_Write_DATA_OTM8018B(0x74); 
	SPI_Write_CMD_OTM8018B(0xE10D); SPI_Write_DATA_OTM8018B(0x61); 
	SPI_Write_CMD_OTM8018B(0xE10E); SPI_Write_DATA_OTM8018B(0x68); 
	SPI_Write_CMD_OTM8018B(0xE10F); SPI_Write_DATA_OTM8018B(0x61); 
	SPI_Write_CMD_OTM8018B(0xE110); SPI_Write_DATA_OTM8018B(0x5B); 
	SPI_Write_CMD_OTM8018B(0xE111); SPI_Write_DATA_OTM8018B(0x4E); 
	SPI_Write_CMD_OTM8018B(0xE112); SPI_Write_DATA_OTM8018B(0x44); 
	SPI_Write_CMD_OTM8018B(0xE113); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xE200); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xE201); SPI_Write_DATA_OTM8018B(0x07); 
	SPI_Write_CMD_OTM8018B(0xE202); SPI_Write_DATA_OTM8018B(0x10); 
	SPI_Write_CMD_OTM8018B(0xE203); SPI_Write_DATA_OTM8018B(0x22); 
	SPI_Write_CMD_OTM8018B(0xE204); SPI_Write_DATA_OTM8018B(0x40); 
	SPI_Write_CMD_OTM8018B(0xE205); SPI_Write_DATA_OTM8018B(0x56); 
	SPI_Write_CMD_OTM8018B(0xE206); SPI_Write_DATA_OTM8018B(0x66); 
	SPI_Write_CMD_OTM8018B(0xE207); SPI_Write_DATA_OTM8018B(0x99); 
	SPI_Write_CMD_OTM8018B(0xE208); SPI_Write_DATA_OTM8018B(0x88); 
	SPI_Write_CMD_OTM8018B(0xE209); SPI_Write_DATA_OTM8018B(0x9F); 
	SPI_Write_CMD_OTM8018B(0xE20A); SPI_Write_DATA_OTM8018B(0x6A); 
	SPI_Write_CMD_OTM8018B(0xE20B); SPI_Write_DATA_OTM8018B(0x5A); 
	SPI_Write_CMD_OTM8018B(0xE20C); SPI_Write_DATA_OTM8018B(0x74); 
	SPI_Write_CMD_OTM8018B(0xE20D); SPI_Write_DATA_OTM8018B(0x61); 
	SPI_Write_CMD_OTM8018B(0xE20E); SPI_Write_DATA_OTM8018B(0x68); 
	SPI_Write_CMD_OTM8018B(0xE20F); SPI_Write_DATA_OTM8018B(0x61); 
	SPI_Write_CMD_OTM8018B(0xE210); SPI_Write_DATA_OTM8018B(0x5B); 
	SPI_Write_CMD_OTM8018B(0xE211); SPI_Write_DATA_OTM8018B(0x4E); 
	SPI_Write_CMD_OTM8018B(0xE212); SPI_Write_DATA_OTM8018B(0x44); 
	SPI_Write_CMD_OTM8018B(0xE213); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xC480); SPI_Write_DATA_OTM8018B(0x30); 

	SPI_Write_CMD_OTM8018B(0xC098); SPI_Write_DATA_OTM8018B(0x00); 

	SPI_Write_CMD_OTM8018B(0xC0A9); SPI_Write_DATA_OTM8018B(0x0A); 

	SPI_Write_CMD_OTM8018B(0xC1B0); SPI_Write_DATA_OTM8018B(0x20); 
	SPI_Write_CMD_OTM8018B(0xC1B1); SPI_Write_DATA_OTM8018B(0x00); 
	SPI_Write_CMD_OTM8018B(0xC1B2); SPI_Write_DATA_OTM8018B(0x00); 
	
	SPI_Write_CMD_OTM8018B(0xC0E1); SPI_Write_DATA_OTM8018B(0x40); 
	SPI_Write_CMD_OTM8018B(0xC0E2); SPI_Write_DATA_OTM8018B(0x30); 

	SPI_Write_CMD_OTM8018B(0xC180); SPI_Write_DATA_OTM8018B(0x03); 
	SPI_Write_CMD_OTM8018B(0xC181); SPI_Write_DATA_OTM8018B(0x33); 

	SPI_Write_CMD_OTM8018B(0xC1A0); SPI_Write_DATA_OTM8018B(0xE8); 

	SPI_Write_CMD_OTM8018B(0xB690); SPI_Write_DATA_OTM8018B(0xB4); 
	//delay_loop_1ms(10); 
	mdelay(10);

	SPI_Write_CMD_OTM8018B(0xFB00); SPI_Write_DATA_OTM8018B(0x01); 

	SPI_Write_CMD_OTM8018B(0xFF00); SPI_Write_DATA_OTM8018B(0xFF); 
	SPI_Write_CMD_OTM8018B(0xFF01); SPI_Write_DATA_OTM8018B(0xFF); 
	SPI_Write_CMD_OTM8018B(0xFF02); SPI_Write_DATA_OTM8018B(0xFF); 

	SPI_Write_CMD_OTM8018B(0x3600); SPI_Write_DATA_OTM8018B(0xc0); 
	SPI_Write_CMD_OTM8018B(0x3A00); SPI_Write_DATA_OTM8018B(0x70); 

	SPI_Write_CMD_OTM8018B(0x1100); SPI_Write_DATA_OTM8018B(0x00); 
	//delay_loop_1ms(120); 
	mdelay(120);
	SPI_Write_CMD_OTM8018B(0x2900); SPI_Write_DATA_OTM8018B(0x00); 
}

void lcd_otm8019_init(void)
{
	pr_info("[spilcd] %s,starting...\n",__func__);
	lcd_gpio_init();

	/* LCD reset*/
	RESET_SCREEN();

	/*LCD driver init*/
	otm8019_ldi_init();
	pr_info("[spilcd] %s,end...\n",__func__);
}
/********************************** simulated spi & initialize rgb lcd via spi  end ***********************************************/


struct icn6211 {
	int enable_gpio;
	struct i2c_client *client;
	struct regulator *vdd1;
	struct regulator *vdd2;
	struct regulator *vdd3;
	struct regulator *vcc_i2c;
	struct mutex icn6211_mutex;
};

struct icn6211_cmd {
	char reg_add;
	char reg_val;
};

static const struct icn6211_cmd cmd_table[] = {
#if 0
	{0x20, 0xE0},
	{0x21, 0x20},
	{0x22, 0x31},
	{0x23, 0xA0},
	{0x24, 0x30},
	{0x25, 0x28},
	{0x26, 0x00},
	{0x27, 0x0D},
	{0x28, 0x03},
	{0x29, 0x1D},
	{0x34, 0x80},
	{0x36, 0xA0},
	{0xB5, 0xA0},
	{0x5C, 0xFF},
	{0x2A, 0x01},
	{0x56, 0x90},
	{0x6B, 0x71},
	{0x69, 0x2E},
	{0x10, 0x40},
	{0x11, 0x88},
	{0xB6, 0x20},
	{0x51, 0x20},
	//{0x14, 0x43},
	//{0x2a, 0x49},
	{0x09, 0x10}
#endif
	{0x20, 0xE0},
	{0x21, 0x20},
	{0x22, 0x31},
	{0x23, 0x30},
	{0x24, 0x04},
	{0x25, 0x2C},
	{0x26, 0x00},
	{0x27, 0x0F},
	{0x28, 0x01},
	{0x29, 0x10},
	{0x34, 0x80},
	{0x36, 0x30},
	{0xB5, 0xA0},
	{0x5C, 0xFF},
	{0x2A, 0x01},
	{0x56, 0x90},
	{0x6B, 0x71},
	{0x69, 0x21},
	{0x10, 0x45},
	{0x11, 0x88},
	{0xB6, 0x20},
	{0x51, 0x20},
	/*register 0x14 & 0x2a are test mode register*/
	//{0x14, 0x43},
	//{0x2a, 0x49},
	{0x09, 0x10}
};

#define ICN6211_CMD_CNT (sizeof(cmd_table)/sizeof(cmd_table[0]))

static int icn6211_i2c_write(struct icn6211 *pdata)
{
	int rc = 0;
	int i = 0;
	const struct icn6211_cmd *cmd_list = cmd_table;

	mutex_lock(&pdata->icn6211_mutex);
	if (pdata->client) {
		for (i = 0; i < ICN6211_CMD_CNT; i++)
		{
			pr_info("ICN6211 write: reg_add=0x%X, reg_val=0x%X\n", 
					(cmd_list+i)->reg_add, (cmd_list+i)->reg_val);

			rc = i2c_smbus_write_byte_data(pdata->client, (cmd_list+i)->reg_add, (cmd_list+i)->reg_val);
			if (rc < 0) {
				mutex_unlock(&pdata->icn6211_mutex);
				return rc;
			}
		}
	}

	mutex_unlock(&pdata->icn6211_mutex);
	return rc;
}

static int icn6211_i2c_read(struct icn6211 *pdata)
{
	int rc = 0;
	int i = 0;
	const struct icn6211_cmd *cmd_list = cmd_table;

	mutex_lock(&pdata->icn6211_mutex);
	if (pdata->client) {
		for (i = 0; i < ICN6211_CMD_CNT; i++)
		{
			rc = i2c_smbus_read_byte_data(pdata->client, (cmd_list+i)->reg_add);
			if (rc < 0) {
				mutex_unlock(&pdata->icn6211_mutex);
				return rc;
			}
			pr_info("ICN6211 read : reg_add=0x%X, reg_val=0x%X\n", 
					(cmd_list+i)->reg_add, rc);
		}
		rc = i2c_smbus_read_byte_data(pdata->client, 0x00);
		pr_info("ICN6211 read : reg_add=0x00, reg_val=0x%X\n", rc);
	}

	mutex_unlock(&pdata->icn6211_mutex);
	return rc;
}

static void icn6211_mipi_test(struct icn6211 *pdata)
{
	int rc = 0;
	mutex_lock(&pdata->icn6211_mutex);
	rc = i2c_smbus_write_byte_data(pdata->client, 0x88, 0x80);
	if (rc < 0) {
		pr_err("%s, i2c_smbus_write_byte_data error!\n",__func__);
		mutex_unlock(&pdata->icn6211_mutex);
		return ;
	}

	pr_info("%s, rc=%d\n", __func__,rc);
	rc = 5;

	rc = i2c_smbus_read_byte_data(pdata->client, 0x80);
	pr_info("ICN6211 read : reg_add=0x80, reg_val=0x%X\n", rc);
	rc = i2c_smbus_read_byte_data(pdata->client, 0x81);
	pr_info("ICN6211 read : reg_add=0x81, reg_val=0x%X\n", rc);
	mutex_unlock(&pdata->icn6211_mutex);
	return ;

}

static int icn6211_power_on(struct icn6211 *pdata, int on)
{
	int ret = 0;

	if (on) {
		if (!IS_ERR(pdata->vdd1)) {
			ret = regulator_enable(pdata->vdd1);
			if (ret) {
				dev_err(&pdata->client->dev,
						"Regulator vdd1 enable failed ret=%d\n", ret);
				goto err_enable_vdd1;
			}
		}

		if (!IS_ERR(pdata->vdd2)) {
			ret = regulator_enable(pdata->vdd2);
			if (ret) {
				dev_err(&pdata->client->dev,
						"Regulator vdd2 enable failed ret=%d\n", ret);
				goto err_enable_vdd2;
			}
		}

		if (!IS_ERR(pdata->vdd3)) {
			ret = regulator_enable(pdata->vdd3);
			if (ret) {
				dev_err(&pdata->client->dev,
						"Regulator vdd3 enable failed ret=%d\n", ret);
				goto err_enable_vdd3;
			}
		}
	} else {
		if (!IS_ERR(pdata->vdd1))
			ret = regulator_disable(pdata->vdd1);
		if (!IS_ERR(pdata->vdd2))
			ret = regulator_disable(pdata->vdd2);
		if (!IS_ERR(pdata->vdd3))
			ret = regulator_disable(pdata->vdd3);
	}

	return ret;

err_enable_vdd3:
	if (!IS_ERR(pdata->vdd2))
		regulator_disable(pdata->vdd2);
err_enable_vdd2:
	if (!IS_ERR(pdata->vdd1))
		regulator_disable(pdata->vdd1);
err_enable_vdd1:

	return ret;

}

static int icn6211_power_init(struct icn6211 *pdata)
{
	int ret = 0;

	pdata->vdd1 = regulator_get(&pdata->client->dev, "vdd1");
	if (IS_ERR(pdata->vdd1)) {
		ret = PTR_ERR(pdata->vdd1);
		dev_info(&pdata->client->dev,
				"Regulator get failed avdd ret=%d\n", ret);
	}

	pdata->vdd2 = regulator_get(&pdata->client->dev, "vdd2");
	if (IS_ERR(pdata->vdd2)) {
		ret = PTR_ERR(pdata->vdd2);
		dev_info(&pdata->client->dev,
				"Regulator get failed avdd ret=%d\n", ret);
	}

	pdata->vdd3 = regulator_get(&pdata->client->dev, "vdd3");
	if (IS_ERR(pdata->vdd3)) {
		ret = PTR_ERR(pdata->vdd3);
		dev_info(&pdata->client->dev,
				"Regulator get failed avdd ret=%d\n", ret);
	}

	return ret;
}

static int icn6211_gpio_init(struct icn6211 *pdata)
{
	int ret = 0;

	pr_info("%s, icn6211-engpio is %d\n",
			__func__,pdata->enable_gpio);

	if (!gpio_is_valid(pdata->enable_gpio)) {
		pr_err("%s,enable gpio [%d] is invalid!\n",
				__func__, pdata->enable_gpio);
		return -1;
	}

	ret = gpio_request(pdata->enable_gpio, "icn6211-en-gpio");
	if (ret) {
		pr_err("%s, Unable to request icn6211 en-gpio\n",__func__);
	}

	ret = gpio_direction_output(pdata->enable_gpio, 1);
	if (ret) {
		pr_err("%s, Unable to pull up icn6211 en-gpio\n",__func__);
	}
	mdelay(5);
	ret = gpio_direction_output(pdata->enable_gpio, 0);
	if (ret) {
		pr_err("%s, Unable to pull up icn6211 en-gpio\n",__func__);
	}
	mdelay(15);
	ret = gpio_direction_output(pdata->enable_gpio, 1);
	if (ret) {
		pr_err("%s, Unable to pull up icn6211 en-gpio\n",__func__);
	}

	return ret;
}

static int icn6211_parse_dt(struct device *dev, struct icn6211 *pdata)
{
	int rc = 0;
	struct device_node *np = dev->of_node;

	pdata->enable_gpio = of_get_named_gpio(np, "icn6211-en-gp", 0);

	return rc;
}

static int icn6211_probe(struct i2c_client *client,
	 const struct i2c_device_id *id)
{
	struct icn6211 *pdata;
	int ret = 0;

	pr_err("ICN6211:%s\n",__func__);
	if (!client || !client->dev.of_node) {
		dev_err(&client->dev, "%s: invalid input\n\n",__func__);
		return -EINVAL;
	}

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		dev_err(&client->dev, "icn6211  I2C not supported\n");
		return -ENODEV;
	}

	pdata = devm_kzalloc(&client->dev,
		sizeof(struct icn6211), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;

	ret = icn6211_parse_dt(&client->dev, pdata);
	if (ret) {
		pr_err("%s: Failed to parse DT\n", __func__);
		goto err_dt_parse;
	}

	pdata->client = client;

	ret = icn6211_gpio_init(pdata);
	if (ret) {
		pr_err("%s: Failed to configure GPIOs\n", __func__);
		goto err_gpio_cfg;
	}

	if (0)
		ret = icn6211_power_init(pdata);

	if (0) {
		ret = icn6211_power_on(pdata, 1);
		if (ret) {
			pr_err("%s, power on faild !\n",__func__);
			goto err_power_on;
		}
	}

	mutex_init(&pdata->icn6211_mutex);
	dev_set_drvdata(&client->dev, pdata);
	
	mutex_lock(&pdata->icn6211_mutex);
	lcd_otm8019_init();
	mutex_unlock(&pdata->icn6211_mutex);
	mdelay(5);
	
	icn6211_i2c_write(pdata);
	mdelay(5);
	icn6211_i2c_read(pdata);
	msleep(2000);
	icn6211_mipi_test(pdata);

	return 0;
err_power_on:
err_gpio_cfg:
err_dt_parse:
	devm_kfree(&client->dev, pdata);
	return ret;
}


static int icn6211_resume(struct device *tdev) 
{
	    return 0;
}

static int icn6211_suspend(struct device *tdev) 
{
	    return 0;
}
static int icn6211_remove(struct i2c_client *client) 
{
	    return 0;
}

static const struct of_device_id icn6211_mipi_rgb_of_match[] = {
	    { .compatible = "qcom,icn6211_mipi_rgb",},
		    {},
};

static const struct i2c_device_id icn6211_id[] = {
	    {"icn6211_mipi_rgb", 0},
		    {},
};

static const struct dev_pm_ops icn6211_pm_ops = { 
	.suspend = icn6211_suspend,
	.resume = icn6211_resume, 
};

static struct i2c_driver icn6211_driver = {
	.driver = {
		.name = "qcom,icn6211_mipi_rgb",
		.owner    = THIS_MODULE,
		.of_match_table = icn6211_mipi_rgb_of_match,
		.pm = &icn6211_pm_ops,
	},
	.probe    = icn6211_probe,
	.remove   = icn6211_remove,
	.id_table = icn6211_id,
};

module_i2c_driver(icn6211_driver);
MODULE_DESCRIPTION("ICN6211 MIPI-RGB driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i2c:icn6211_mipi_rgb");
发布了28 篇原创文章 · 获赞 23 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/q1075355798/article/details/104313561