Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eee689c2 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "xr-smrtvwr-misc: XR SMRTVWR Misc drivers"

parents eb79f08a dcc7af8b
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -282,6 +282,36 @@ config QCOM_COINCELL
	  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
+4 −0
Original line number Diff line number Diff line
@@ -62,6 +62,10 @@ obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o

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
+159 −0
Original line number Diff line number Diff line
/* 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");
+208 −0
Original line number Diff line number Diff line
/*
 * 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");

drivers/misc/vxr7200.c

0 → 100644
+507 −0
Original line number Diff line number Diff line
/*
 * 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");