xr-smrtvwr-misc: XR SMRTVWR Misc drivers

Following drivers are added to support xr smartviewer reference device.
These drivers are needed to support different chips that are used
in the xr smartviewer reference device. These chips are enabled
and used in smartviewer reference device.
1. qcom-xr-smrtvwr-misc.c - Supports enabling regulator, gpios.
2. tusb1064.c - i2c driver for USB redriver from TI TUSB1064 chip.
3. vxr7200.c - i2c driver for DP2DSI bridge driver from Synaptics
   VXR7200 chip.

Change-Id: I411ceac66882cec840ae63ca2e5a19920bbdeef2
Signed-off-by: Rajesh Bharathwaj <rajeshbharathwaj@codeaurora.org>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index cf5764e..c0b5390 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -282,6 +282,36 @@
 	  to maintain PMIC register and RTC state in the absence of
 	  external power.
 
+config QCOM_XR_SMRTVWR_MISC
+	tristate "QTI XR SmartVwr Misc driver support"
+	default n
+	help
+	  This driver supports the misc chips power up such as
+	  USB bridge chip, Display Port bridgechip, MIPI switches etc.
+	  This driver initializes gpios, turns on and off gpios, and
+          enables/disables LDOs that are part of XR  Smart Viewer
+	  reference device.
+
+config TUSB1064_XR_MISC
+	tristate "I2C driver for TI TUSB1064 chip for XR"
+	default n
+	help
+	  This i2c driver allows applications to communicate with TI
+	  TUSB1064 USB redriver chip. This redriver chip could be configured
+	  to USB3.1 mode, Display Port 4lane and USB2.0 Mode, and Display Port
+	  2-lane and USB 3.1 modes. This driver allows the XR smart viewer to
+	  put in any one of the above three modes.
+
+config VXR200_XR_MISC
+	tristate "I2C driver for Synaptics VXR7200 chip for XR"
+	default n
+	help
+	  This i2c driver allows applications to communicate with Synaptics
+	  VXR7200 DP2DSI bridge chip. This driver enables the display data
+	  from Display Port and move the data to DSI data path. Thus enabling
+	  the display data from DP to be shown on the display of the XR smart
+	  viewer reference device.
+
 config SGI_GRU
 	tristate "SGI GRU driver"
 	depends on X86_UV && SMP
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 6494a66..0331572 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -62,6 +62,10 @@
 
 obj-$(CONFIG_UID_SYS_STATS)	+= uid_sys_stats.o
 obj-$(CONFIG_MEMORY_STATE_TIME)	+= memory_state_time.o
+obj-$(CONFIG_QCOM_XR_SMRTVWR_MISC) += qcom-xr-smrtvwr-misc.o
+obj-$(CONFIG_TUSB1064_XR_MISC) += tusb1064.o
+obj-$(CONFIG_VXR200_XR_MISC) += vxr7200.o
+
 
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_bugs.o
diff --git a/drivers/misc/qcom-xr-smrtvwr-misc.c b/drivers/misc/qcom-xr-smrtvwr-misc.c
new file mode 100644
index 0000000..fc8796f
--- /dev/null
+++ b/drivers/misc/qcom-xr-smrtvwr-misc.c
@@ -0,0 +1,159 @@
+/* Copyright (c) 2020, 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+struct qcom_xr_smrtvwr {
+	struct device	*dev;
+};
+
+
+static int qcom_xr_smrtvwr_probe(struct platform_device *pdev)
+{
+	int rc;
+	struct regulator *reg1, *reg2, *reg3;
+	int dp3p3_en_gpio = 142;
+	int wcd_en_gpio = 93;
+	int switch_gpio = 112;
+	int rgb_tck_oe_en_gpio = 108;
+
+	reg1 = devm_regulator_get(&pdev->dev, "pm660l_l6");
+	if (!IS_ERR(reg1)) {
+		regulator_set_load(reg1, 600000);
+		rc = regulator_enable(reg1);
+		if (rc < 0) {
+			pr_err("%s pm660l_l6 failed\n", __func__);
+			goto reg1_fail;
+		}
+	}
+
+	reg2 = devm_regulator_get(&pdev->dev, "pm660_l6");
+	if (!IS_ERR(reg2)) {
+		regulator_set_load(reg2, 600000);
+		rc = regulator_enable(reg2);
+		if (rc < 0) {
+			pr_err("%s pm660_l6 failed\n", __func__);
+			goto reg2_fail;
+		}
+	}
+
+	reg3 = devm_regulator_get(&pdev->dev, "pm660_l7");
+	if (!IS_ERR(reg3)) {
+		regulator_set_load(reg3, 600000);
+		rc = regulator_enable(reg3);
+		if (rc < 0) {
+			pr_err("%s pm660_l7 failed\n", __func__);
+			goto reg3_fail;
+		}
+	}
+
+	rc = gpio_request(dp3p3_en_gpio, "ti-dp-3v3-en-gpio");
+	if (rc) {
+		pr_err("%s dp3p3_en gpio request failed\n", __func__);
+		goto gpio3p3_fail;
+	}
+	rc = gpio_direction_output(dp3p3_en_gpio, 0);
+	if (rc) {
+		pr_err("%s dp3p3_en_gpio direction failed\n", __func__);
+		goto gpio3p3_fail;
+	}
+	gpio_set_value(dp3p3_en_gpio, 1);
+	msleep(20);
+
+	rc = gpio_request(wcd_en_gpio, "wcd9340_en_gpio");
+	if (rc) {
+		pr_err("%s wcd9340_en_gpio request failed\n", __func__);
+		goto gpiowcd_fail;
+	}
+	rc = gpio_direction_output(wcd_en_gpio, 0);
+	if (rc) {
+		pr_err("%s wcd9340_en_gpio direction failed\n", __func__);
+		goto gpiowcd_fail;
+	}
+	gpio_set_value(wcd_en_gpio, 1);
+	msleep(20);
+
+	rc = gpio_request(switch_gpio, "1p8_en_gpio");
+	if (rc) {
+		pr_err("%s 1p8_switch_gpio request failed\n", __func__);
+		goto gpio_switch_fail;
+	}
+	rc = gpio_direction_output(switch_gpio, 0);
+	if (rc) {
+		pr_err("%s 1p8_switch_gpio direction failed\n", __func__);
+		goto gpio_switch_fail;
+	}
+	gpio_set_value(switch_gpio, 1);
+	msleep(20);
+
+	rc = gpio_request(rgb_tck_oe_en_gpio, "rgb_tck_oe_en_gpio");
+	if (rc) {
+		pr_err("%s rgb_tck_oe_en_gpio request failed\n", __func__);
+		goto gpio_oe_en_fail;
+	}
+	rc = gpio_direction_output(rgb_tck_oe_en_gpio, 0);
+	if (rc) {
+		pr_err("%s rgb_tck_oe_en_gpio direction failed\n", __func__);
+		goto gpio_oe_en_fail;
+	}
+	gpio_set_value(rgb_tck_oe_en_gpio, 0);
+	msleep(20);
+
+	pr_debug("%s success\n", __func__);
+	return 0;
+
+gpio_oe_en_fail:
+	gpio_free(rgb_tck_oe_en_gpio);
+gpio_switch_fail:
+	gpio_free(switch_gpio);
+gpiowcd_fail:
+	gpio_free(wcd_en_gpio);
+gpio3p3_fail:
+	gpio_free(dp3p3_en_gpio);
+reg3_fail:
+	devm_regulator_put(reg3);
+reg2_fail:
+	devm_regulator_put(reg2);
+reg1_fail:
+	devm_regulator_put(reg1);
+
+	return rc;
+}
+
+static const struct of_device_id qcom_xr_smrtvwr_match_table[] = {
+	{ .compatible = "qcom,xr-smrtvwr-misc", },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, qcom_xr_smrtvwr_match_table);
+
+static struct platform_driver qcom_xr_smrtvwr_driver = {
+	.driver	= {
+		.name		= "qcom-xr-smrtvwr-misc",
+		.of_match_table	= qcom_xr_smrtvwr_match_table,
+	},
+	.probe		= qcom_xr_smrtvwr_probe,
+};
+
+module_platform_driver(qcom_xr_smrtvwr_driver);
+
+MODULE_DESCRIPTION("QTI XR SMRTVWR MISC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/tusb1064.c b/drivers/misc/tusb1064.c
new file mode 100644
index 0000000..509961e
--- /dev/null
+++ b/drivers/misc/tusb1064.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2020, 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.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+struct tusb1064 {
+	struct device *dev;
+	struct device_node *host_node;
+	u8 i2c_addr;
+	u32 dp_3v3_en;
+	struct i2c_client *i2c_client;
+	bool power_on;
+};
+
+static struct tusb1064 *pdata;
+
+static int tusb1064_read(struct i2c_client *client, u8 reg, char *buf, u32 size)
+{
+	struct i2c_msg msg[2] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = size,
+			.buf = buf,
+		}
+	};
+
+	if (i2c_transfer(client->adapter, msg, 2) != 2) {
+		pr_err("%s i2c read failed\n", __func__);
+		return -EIO;
+	}
+	pr_debug("%s, reg:%x buf[0]:%x\n", __func__, reg, buf[0]);
+
+	return 0;
+}
+
+static int tusb1064_write(struct i2c_client *client, u8 reg, u8 val)
+{
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = {
+		.addr = client->addr,
+		.flags = 0,
+		.len = 2,
+		.buf = buf,
+	};
+
+	pr_debug("%s, reg:%x, val:%x\n", __func__, reg, val);
+	if (i2c_transfer(client->adapter, &msg, 1) < 1) {
+		pr_err("i2c write failed\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+void tusb1064_flip(bool flip)
+{
+	if (pdata) {
+		if (flip) {
+			pr_debug("%s flipping the switch\n", __func__);
+			/*AUXn->SBU2, AUXp->SBU1*/
+			tusb1064_write(pdata->i2c_client, 0x13, 0x2F);
+		} else {
+			pr_debug("%s not flipping the switch\n", __func__);
+			/*AUXn->SBU2, AUXp->SBU1*/
+			tusb1064_write(pdata->i2c_client, 0x13, 0x1F);
+		}
+	}
+}
+EXPORT_SYMBOL(tusb1064_flip);
+
+static int tusb1064_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	char buf[2];
+
+	if (!client || !client->dev.of_node) {
+		pr_err("%s invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s device doesn't support I2C\n", __func__);
+		return -ENODEV;
+	}
+
+	pdata = devm_kzalloc(&client->dev,
+		sizeof(struct tusb1064), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdata->dev = &client->dev;
+	pdata->i2c_client = client;
+	pr_debug("%s I2C address is %x\n", __func__, client->addr);
+
+	i2c_set_clientdata(client, pdata);
+	dev_set_drvdata(&client->dev, pdata);
+
+	tusb1064_read(pdata->i2c_client, 0x0A, buf, 2);
+	tusb1064_read(pdata->i2c_client, 0x13, buf, 2);
+	/*Enable 4-lane DP with FLip and enable EQ_OVERRIDe*/
+	/*tusb1064_write(pdata, 0x0A, 0x13); */
+	/*written usb sideEnable 4-lane DP with FLip and enable EQ_OVERRIDe */
+	/*tusb1064_write(pdata, 0x0A, 0x12); */
+
+	/*Enable 4-lane DP with FLip and enable EQ_OVERRIDe */
+	if (tusb1064_write(pdata->i2c_client, 0x0A, 0x02) < 0)
+		goto fail;
+
+	pr_debug("%s setting SBU1 to AUXN and SBU2 to AUXP\n", __func__);
+	/*AUXn->SBU2, AUXp->SBU1 */
+	if (tusb1064_write(pdata->i2c_client, 0x13, 0x1F) < 0)
+		goto fail;
+	//tusb1064_write(pdata, 0x13, 0x01);//AUXn->SBU1, AUXp->SBU2
+
+	/*Enable 4-lane DP */
+	if (tusb1064_write(pdata->i2c_client, 0x10, 0x55) < 0)
+		goto fail;
+	/*Enable 4-lane DP */
+	if (tusb1064_write(pdata->i2c_client, 0x11, 0x55) < 0)
+		goto fail;
+	//pr_err("setting SBU1 to AUXp and SBU2 to AUXN\n");
+	//tusb1064_write(pdata, 0x13, 0x8F);//Enable 4-lane DP
+
+	tusb1064_read(pdata->i2c_client, 0x0A, buf, 2);
+	tusb1064_read(pdata->i2c_client, 0x13, buf, 2);
+	tusb1064_read(pdata->i2c_client, 0x10, buf, 2);
+	tusb1064_read(pdata->i2c_client, 0x11, buf, 2);
+
+	pr_debug("%s probe successfully\n", __func__);
+	return 0;
+fail:
+	devm_kfree(&client->dev, pdata);
+	return -EINVAL;
+}
+
+static int tusb1064_remove(struct i2c_client *client)
+{
+	struct tusb1064 *pdata = i2c_get_clientdata(client);
+
+	if (pdata)
+		devm_kfree(&client->dev, pdata);
+	return 0;
+}
+
+static void tusb1064_shutdown(struct i2c_client *client)
+{
+	dev_info(&(client->dev), "shutdown");
+}
+
+static int tusb1064_suspend(struct device *dev, pm_message_t state)
+{
+	dev_info(dev, "suspend");
+	return 0;
+}
+
+static int tusb1064_resume(struct device *dev)
+{
+	dev_info(dev, "resume");
+	return 0;
+}
+
+static const struct i2c_device_id tusb1064_id_table[] = {
+	{"tusb1064", 0},
+	{}
+};
+
+static struct i2c_driver tusb1064_i2c_driver = {
+	.probe = tusb1064_probe,
+	.remove = tusb1064_remove,
+	.shutdown = tusb1064_shutdown,
+	.driver = {
+		.name = "tusb1064",
+		.owner = THIS_MODULE,
+		.suspend = tusb1064_suspend,
+		.resume = tusb1064_resume,
+	},
+	.id_table = tusb1064_id_table,
+};
+module_i2c_driver(tusb1064_i2c_driver);
+MODULE_DEVICE_TABLE(i2c, tusb1064_id_table);
+MODULE_DESCRIPTION("TUSB1064 USB Bridge");
diff --git a/drivers/misc/vxr7200.c b/drivers/misc/vxr7200.c
new file mode 100644
index 0000000..2833df9
--- /dev/null
+++ b/drivers/misc/vxr7200.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2020, 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.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/kernel.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/rwlock.h>
+#include <linux/leds.h>
+
+struct vxr7200 {
+	struct device *dev;
+	struct device_node *host_node;
+
+	u8 i2c_addr;
+	int irq;
+	u32 vxr_3v3_en;
+	u32 led_5v_en;
+	u32 led_drive_en1;
+	u32 led_drive_en2;
+	u32 display_1v8_en;
+	u32 mipi_sw_1v8_en;
+	u32 display_res1;
+	u32 selab_gpio;
+	u32 oenab_gpio;
+	bool gpioInit;
+
+	struct i2c_client *i2c_client;
+
+	struct regulator *vddio;
+	struct regulator *lab;
+	struct regulator *ibb;
+
+	bool power_on;
+};
+
+static int vxr7200_read(struct vxr7200 *pdata, u8 *reg, u8 *buf, u32 size)
+{
+	struct i2c_client *client = pdata->i2c_client;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 4,
+			.buf = reg,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = size,
+			.buf = buf,
+		}
+	};
+
+	if (i2c_transfer(client->adapter, msg, 2) != 2) {
+		pr_err("i2c read failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int turnGpio(struct vxr7200 *pdata, int gpio, char *name, bool on)
+{
+	int ret = -1;
+
+	pr_info("%s vxr7200 gpio:%d, name:%s, on:%d\n", __func__, gpio,
+						name, on);
+	if (!pdata->gpioInit) {
+		ret = gpio_request(gpio, name);
+		if (ret) {
+			pr_err("vxr7200 %s gpio request failed\n", name);
+			goto error;
+		}
+	}
+	if (on) {
+		ret = gpio_direction_output(gpio, 0);
+		if (ret) {
+			pr_err("vxr7200 gpio direction failed\n");
+			goto error;
+		}
+		gpio_set_value(gpio, 1);
+		pr_debug("%s vxr7200 gpio:%d set to high\n", __func__, gpio);
+	} else {
+		ret = gpio_direction_output(gpio, 1);
+		if (ret) {
+			pr_err("vxr7200 gpio direction failed\n");
+			goto error;
+		}
+		gpio_set_value(gpio, 0);
+		pr_debug("%s vxr7200 gpio:%d set to low\n", __func__, gpio);
+	}
+	return 0;
+error:
+	return -EINVAL;
+}
+
+static void vxr7200_set_gpios(struct vxr7200 *pdata, bool turnOn)
+{
+	int rc;
+
+	pr_debug("%s, turnOn:%d\n", __func__, turnOn);
+	if (pdata) {
+		rc = turnGpio(pdata, pdata->vxr_3v3_en, "vxr_3v3_en", turnOn);
+		if (rc)
+			goto gpio1Fail;
+		rc = turnGpio(pdata, pdata->led_5v_en, "led_5v_en", turnOn);
+		if (rc)
+			goto gpio2Fail;
+		rc = turnGpio(pdata, pdata->led_drive_en1,
+					"led_drive_en1", turnOn);
+		if (rc)
+			goto gpio3Fail;
+		rc = turnGpio(pdata, pdata->led_drive_en2,
+					 "led_drive_en2", turnOn);
+		if (rc)
+			goto gpio4Fail;
+		rc = turnGpio(pdata, pdata->display_1v8_en,
+					 "disp_1v8_en", turnOn);
+		if (rc)
+			goto gpio5Fail;
+		pdata->mipi_sw_1v8_en += 1100;
+		rc = turnGpio(pdata, pdata->mipi_sw_1v8_en,
+						 "mipi_sw1v8_en", turnOn);
+		if (rc)
+			goto gpio6Fail;
+		rc = turnGpio(pdata, pdata->display_res1,
+						 "display_res1", turnOn);
+		if (rc)
+			goto gpio7Fail;
+	}
+
+gpio7Fail:
+	gpio_free(pdata->display_res1);
+gpio6Fail:
+	gpio_free(pdata->mipi_sw_1v8_en);
+gpio5Fail:
+	gpio_free(pdata->display_1v8_en);
+gpio4Fail:
+	gpio_free(pdata->led_drive_en2);
+gpio3Fail:
+	gpio_free(pdata->led_drive_en1);
+gpio2Fail:
+	gpio_free(pdata->led_5v_en);
+gpio1Fail:
+	gpio_free(pdata->vxr_3v3_en);
+}
+
+static void vxr7200_free_gpios(struct vxr7200 *pdata)
+{
+	if (pdata) {
+		gpio_free(pdata->vxr_3v3_en);
+		gpio_free(pdata->led_5v_en);
+		gpio_free(pdata->led_drive_en1);
+		gpio_free(pdata->led_drive_en2);
+		gpio_free(pdata->display_1v8_en);
+		gpio_free(pdata->mipi_sw_1v8_en);
+		gpio_free(pdata->display_res1);
+	}
+}
+
+
+static int vxr7200_parse_dt(struct device *dev,
+				struct vxr7200 *pdata)
+{
+	struct device_node *np = dev->of_node;
+	int rc = 0;
+
+	pdata->vxr_3v3_en =
+		of_get_named_gpio(np, "qcom,vxr_3v3_en", 0);
+	if (!gpio_is_valid(pdata->vxr_3v3_en)) {
+		pr_err("vxr_3v3_en gpio not specified\n");
+		rc = -EINVAL;
+	}
+
+	pdata->led_5v_en =
+		of_get_named_gpio(np, "qcom,led-5v-en-gpio", 0);
+	if (!gpio_is_valid(pdata->led_5v_en)) {
+		pr_err("led_5v_en gpio not specified\n");
+		rc = -EINVAL;
+	}
+
+	pdata->led_drive_en1 =
+		of_get_named_gpio(np, "qcom,led-driver-en1-gpio", 0);
+	if (!gpio_is_valid(pdata->led_drive_en1)) {
+		pr_err("led_drive_en1 gpio not specified\n");
+		rc = -EINVAL;
+	}
+
+	pdata->led_drive_en2 =
+		of_get_named_gpio(np, "qcom,led-driver-en2-gpio", 0);
+	if (!gpio_is_valid(pdata->led_drive_en2)) {
+		pr_err("led_drive_en2 gpio not specified\n");
+		rc = -EINVAL;
+	}
+
+	pdata->display_1v8_en =
+		of_get_named_gpio(np, "qcom,1p8-en-gpio", 0);
+	if (!gpio_is_valid(pdata->display_1v8_en)) {
+		pr_err("display_1v8_en gpio not specified\n");
+		rc = -EINVAL;
+	}
+
+	pdata->mipi_sw_1v8_en =
+		of_get_named_gpio(np, "qcom,switch-power-gpio", 0);
+	if (!gpio_is_valid(pdata->mipi_sw_1v8_en)) {
+		pr_err("mipi_sw_1v8_en gpio not specified\n");
+		rc = -EINVAL;
+	}
+
+	pdata->display_res1 =
+		of_get_named_gpio(np, "qcom,platform-reset-gpio", 0);
+	if (!gpio_is_valid(pdata->display_res1)) {
+		pr_err("display_res1 gpio not specified\n");
+		rc = -EINVAL;
+	}
+
+	if (!rc)
+		vxr7200_set_gpios(pdata, true);
+
+	pdata->selab_gpio = of_get_named_gpio(np, "qcom,selab-gpio", 0);
+	if (!gpio_is_valid(pdata->selab_gpio)) {
+		pr_err("selab_gpio gpio not specified\n");
+		rc = -EINVAL;
+		goto gpio_selab_fail;
+	} else
+		turnGpio(pdata, pdata->selab_gpio, "selab_gpio", 0);
+
+	pdata->oenab_gpio = of_get_named_gpio(np, "qcom,oenab-gpio", 0);
+	if (!gpio_is_valid(pdata->oenab_gpio)) {
+		pr_err("oenab_gpio gpio not specified\n");
+		rc = -EINVAL;
+		goto gpio_oenab_fail;
+	} else
+		turnGpio(pdata, pdata->oenab_gpio, "oenab_gpio", 0);
+
+	if (!pdata->gpioInit)
+		pdata->gpioInit = true;
+
+	return rc;
+
+gpio_oenab_fail:
+	gpio_free(pdata->oenab_gpio);
+gpio_selab_fail:
+	gpio_free(pdata->selab_gpio);
+	vxr7200_free_gpios(pdata);
+	return rc;
+}
+
+static void vxr7200_display_pwr_enable_vregs(struct vxr7200 *pdata)
+{
+	int rc = 0;
+
+	pdata->vddio = devm_regulator_get(pdata->dev, "pm660_l11");
+	rc = PTR_RET(pdata->vddio);
+	if (rc) {
+		pr_err("Failed to get pm660_l11 regulator %s\n", __func__);
+		goto vddio_fail;
+	}
+	rc = regulator_set_load(pdata->vddio, 62000);
+	if (rc < 0) {
+		pr_err("Load setting failed for vddio %s\n", __func__);
+		goto vddio_fail;
+	}
+	rc = regulator_set_voltage(pdata->vddio, 1800000, 1800000);
+	if (rc) {
+		pr_err("Set voltage(vddio) fail, rc=%d %s\n", rc, __func__);
+		goto vddio_fail;
+	}
+	rc = regulator_enable(pdata->vddio);
+	if (rc) {
+		pr_err("enable failed for vddio, rc=%d %s\n", rc, __func__);
+		goto vddio_fail;
+	}
+
+	pdata->lab = devm_regulator_get(pdata->dev, "lcdb_ldo");
+	rc = PTR_RET(pdata->lab);
+	if (rc) {
+		pr_err("Failed to get lcdb_ldo_vreg regulator %s\n", __func__);
+		goto lab_fail;
+	}
+	rc = regulator_set_load(pdata->lab, 100000);
+	if (rc < 0) {
+		pr_err("Load Setting failed for lab %s\n", __func__);
+		goto lab_fail;
+	}
+	rc = regulator_set_voltage(pdata->lab, 4600000, 6000000);
+	if (rc) {
+		pr_err("Set voltage(lab) fail, rc=%d %s\n", rc, __func__);
+		goto lab_fail;
+	}
+	rc = regulator_enable(pdata->lab);
+	if (rc) {
+		pr_err("enable failed for lab, rc=%d %s\n", rc, __func__);
+		goto lab_fail;
+	}
+
+	pdata->ibb = devm_regulator_get(pdata->dev, "lcdb_ncp");
+	rc = PTR_RET(pdata->ibb);
+	if (rc) {
+		pr_err("Failed to get lcdb_ncp_vreg regulator %s\n", __func__);
+		goto ibb_fail;
+	}
+	rc = regulator_set_load(pdata->ibb, 100000);
+	if (rc < 0) {
+		pr_err("Load Setting failed for ibb %s\n", __func__);
+		goto ibb_fail;
+	}
+	rc = regulator_set_voltage(pdata->ibb, 4600000, 6000000);
+	if (rc) {
+		pr_err("Set voltage(ibb) fail, rc=%d %s\n", rc, __func__);
+		goto ibb_fail;
+	}
+	rc = regulator_enable(pdata->ibb);
+	if (rc) {
+		pr_err("enable failed for ibb, rc=%d %s\n", rc, __func__);
+		goto ibb_fail;
+	}
+
+	return;
+
+ibb_fail:
+	devm_regulator_put(pdata->ibb);
+	(void)regulator_set_load(pdata->ibb, 100);
+	(void)regulator_set_voltage(pdata->ibb, 0, 6000000);
+
+lab_fail:
+	(void)regulator_set_voltage(pdata->lab, 0, 6000000);
+	(void)regulator_set_load(pdata->lab, 100);
+	devm_regulator_put(pdata->lab);
+
+vddio_fail:
+	(void)regulator_set_load(pdata->vddio, 100);
+	(void)regulator_set_voltage(pdata->vddio, 0, 1800000);
+	devm_regulator_put(pdata->vddio);
+}
+
+static __init int vxr7200_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc;
+	struct vxr7200 *pdata;
+	char *cmdline;
+	u8 reg[4] = {0x00, 0x20, 0x01, 0x60};
+	u8 buf[4] = {0x00, 0x0, 0x0, 0x0};
+
+	if (!client || !client->dev.of_node) {
+		pr_err("%s invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s device doesn't support I2C\n", __func__);
+		return -ENODEV;
+	}
+
+	pdata = devm_kzalloc(&client->dev,
+		sizeof(struct vxr7200), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdata->gpioInit = false;
+
+	cmdline = strnstr(boot_command_line, "msm_drm.dsi_display0=",
+					 strlen(boot_command_line));
+	if (cmdline) {
+		cmdline = strnstr(boot_command_line,
+			 "msm_drm.dsi_display0=dsi_sim_vid_display",
+						strlen(boot_command_line));
+		if (cmdline) {
+			pr_debug("%s DSI SIM, going to dp init cmdline:%s\n",
+					__func__, cmdline);
+			goto dp_init;
+		}
+	}
+	pr_debug("%s DSI way, cmdline:%s\n", __func__, cmdline);
+	goto dsi_display;
+
+dp_init:
+	rc = vxr7200_parse_dt(&client->dev, pdata);
+	if (rc) {
+		pr_err("%s failed to parse device tree\n", __func__);
+		goto err_dt_parse;
+	}
+	pdata->dev = &client->dev;
+	pdata->i2c_client = client;
+
+	vxr7200_display_pwr_enable_vregs(pdata);
+
+	i2c_set_clientdata(client, pdata);
+	dev_set_drvdata(&client->dev, pdata);
+
+	//vxr7200_write(pdata, 0x0A, 0x02);//Enable 4-lane DP
+	vxr7200_read(pdata, reg, buf, 4);//Enable 4-lane DP
+
+dsi_display:
+	return rc;
+
+err_dt_parse:
+	devm_kfree(&client->dev, pdata);
+
+	return rc;
+}
+
+static int vxr7200_remove(struct i2c_client *client)
+{
+	struct vxr7200 *pdata = i2c_get_clientdata(client);
+
+	if (pdata)
+		devm_kfree(&client->dev, pdata);
+	return 0;
+}
+
+
+static void vxr7200_shutdown(struct i2c_client *client)
+{
+	dev_info(&(client->dev), "shutdown");
+}
+
+static int vxr7200_pm_freeze(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct vxr7200 *pdata = i2c_get_clientdata(client);
+
+	dev_info(dev, "freeze");
+	vxr7200_set_gpios(pdata, false);
+	return 0;
+}
+static int vxr7200_pm_restore(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct vxr7200 *pdata = i2c_get_clientdata(client);
+
+	dev_info(dev, "restore");
+	vxr7200_set_gpios(pdata, true);
+	return 0;
+}
+static int vxr7200_pm_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct vxr7200 *pdata = i2c_get_clientdata(client);
+
+	dev_info(dev, "suspend");
+	vxr7200_set_gpios(pdata, false);
+	return 0;
+}
+
+static int vxr7200_pm_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct vxr7200 *pdata = i2c_get_clientdata(client);
+
+	dev_info(dev, "resume");
+	vxr7200_set_gpios(pdata, true);
+	return 0;
+}
+
+static const struct dev_pm_ops vxr7200_dev_pm_ops = {
+	.suspend	= vxr7200_pm_suspend,
+	.resume	 = vxr7200_pm_resume,
+	.freeze	 = vxr7200_pm_freeze,
+	.restore	= vxr7200_pm_restore,
+	.thaw	   = vxr7200_pm_restore,
+	.poweroff       = vxr7200_pm_suspend,
+};
+
+static const struct i2c_device_id vxr7200_id_table[] = {
+	{"vxr7200", 0},
+	{}
+};
+
+static struct i2c_driver vxr7200_i2c_driver = {
+	.probe = vxr7200_probe,
+	.remove = vxr7200_remove,
+	.shutdown = vxr7200_shutdown,
+	.driver = {
+		.name = "vxr7200",
+		.owner = THIS_MODULE,
+		.pm    = &vxr7200_dev_pm_ops,
+	},
+	.id_table = vxr7200_id_table,
+};
+module_i2c_driver(vxr7200_i2c_driver);
+MODULE_DEVICE_TABLE(i2c, vxr7200_id_table);
+MODULE_DESCRIPTION("VXR7200 DP2DSI Bridge");