static int __init stmvl6180_init(void)
{
	struct stmvl6180_data *vl6180_data = NULL;
	int ret = 0;

	vl6180_dbgmsg("Enter\n");

	vl6180_data = kzalloc(sizeof(struct stmvl6180_data), GFP_KERNEL);
	if (!vl6180_data) {
		vl6180_errmsg("%d failed no memory\n", __LINE__);
		return -ENOMEM;
	}
	/* assign to global variable */
	gp_vl6180_data = vl6180_data;
	vl6180_data->tof_start = stmvl6180_start;
	vl6180_data->tof_stop = stmvl6180_stop;
	/* assign function table */
	vl6180_data->pmodule_func_tbl = &stmvl6180_module_func_tbl;
	/* client specific init function */
	ret = vl6180_data->pmodule_func_tbl->init();
	if (!ret)
		ret = stmvl6180_setup(vl6180_data);
	if (ret) {
		kfree(vl6180_data);
		gp_vl6180_data = NULL;
		vl6180_errmsg("%d failed with %d\n", __LINE__, ret);
	}
	vl6180_dbgmsg("End\n");

	return ret;
}
static int32_t stmvl6180_vreg_control(struct cci_data *data, int config)
{
	int rc = 0, i, cnt;
	struct msm_tof_vreg *vreg_cfg;

	vl6180_dbgmsg("Enter\n");

	vreg_cfg = &data->vreg_cfg;
	cnt = vreg_cfg->num_vreg;
	vl6180_dbgmsg("num_vreg: %d\n", cnt);
	if (!cnt) {
		vl6180_errmsg("failed %d\n", __LINE__);
		return 0;
	}

	if (cnt >= MSM_TOF_MAX_VREGS) {
		vl6180_errmsg("failed %d cnt %d\n", __LINE__, cnt);
		return -EINVAL;
	}

	for (i = 0; i < cnt; i++) {
		rc = msm_camera_config_single_vreg(&(data->pdev->dev), &vreg_cfg->cam_vreg[i], (struct regulator **)&vreg_cfg->data[i], config);
	}

	vl6180_dbgmsg("EXIT rc =%d\n", rc);
	return rc;
}
static ssize_t stmvl6180_store_enable_ps_sensor(struct device *dev,
				struct device_attribute *attr, const char *buf, size_t count)
{
	struct stmvl6180_data *data = gp_vl6180_data;
	unsigned long val = simple_strtoul(buf, NULL, 10);

	if ((val != 0) && (val != 1)) {
		vl6180_errmsg("store unvalid value=%ld\n", val);
		return count;
	}
	vl6180_dbgmsg("Enter, enable ps senosr ( %ld)\n", val);
	mutex_lock(&data->work_mutex);
	vl6180_dbgmsg("enable_ps_sensor old flag:%d\n", data->enable_ps_sensor);
	if (val == 1) {
		/* turn on tof sensor */
		if (data->enable_ps_sensor == 0)
			stmvl6180_start(data, 3, NORMAL_MODE);
	} else {
		/* turn off tof sensor */
		if (data->enable_ps_sensor == 1) {
			data->enable_ps_sensor = 0;
			/* to stop */
			stmvl6180_stop(data);
		}
	}

	mutex_unlock(&data->work_mutex);
	vl6180_dbgmsg("End\n");

	return count;
}
int stmvl6180_power_up_cci(void *cci_object, unsigned int *preset_flag)
{
	int ret = 0;
	struct cci_data *data = (struct cci_data *)cci_object;

	vl6180_dbgmsg("Enter");

	/* need to init cci first */
	ret = stmvl6180_cci_init(data);
	if (ret) {
		vl6180_errmsg("stmvl6180_stmvl6180_cci_init failed %d\n", __LINE__);
		return ret;
	}
	/* actual power up */
	if (data && data->device_type == MSM_CAMERA_PLATFORM_DEVICE) {
		ret = stmvl6180_vreg_control(data, 1);
		if (ret < 0) {
			vl6180_errmsg("stmvl6180_vreg_control failed %d\n", __LINE__);
			return ret;
		}
		gpio_set_value(data->en_gpio,STMVL6180_GPIO_ENABLE);
	}
	msleep(3);
	data->power_up = 1;
	*preset_flag = 1;
	vl6180_dbgmsg("End\n");

	return ret;
}
int stmvl6180_power_down_cci(void *cci_object)
{
	int ret = 0;
	struct cci_data *data = (struct cci_data *)cci_object;

	vl6180_dbgmsg("Enter\n");
	if (data->power_up) {
		/* need to release cci first */
		ret = data->client->i2c_func_tbl->i2c_util(data->client, MSM_CCI_RELEASE);
		if (ret < 0) {
			vl6180_errmsg("CCI Release failed rc %d\n", ret);
		}
		/* actual power down */
		if (data->device_type == MSM_CAMERA_PLATFORM_DEVICE) {
			gpio_set_value(data->en_gpio,STMVL6180_GPIO_DISABLE);
			ret = stmvl6180_vreg_control(data, 0);
			if (ret < 0) {
				vl6180_errmsg("stmvl6180_vreg_control failed %d\n", __LINE__);
				return ret;
			}
		}
	}
	data->power_up = 0;
	vl6180_dbgmsg("End\n");
	return ret;
}
int stmvl6180_power_down_i2c(void *i2c_object)
{
	int ret = 0;
#ifndef STM_TEST
	struct i2c_data *data = (struct i2c_data *)i2c_object;
#endif

	vl6180_dbgmsg("Enter\n");
#ifndef STM_TEST
	msleep(3);
	if (data != NULL) {
		ret = regulator_disable(data->vdd);
		if (ret < 0) {
			pr_err("%s: failed to disable st vdd\n", __func__);
			return ret;
		}
		ret = regulator_disable(data->vcc);
		if (ret < 0) {
			pr_err("%s: failed to disable st vcc\n", __func__);
			return ret;
		}
		gpio_set_value(data->cs_gpio_num, 0);
		data->power_up = 0;
	}
#endif

	vl6180_dbgmsg("End\n");
	return ret;
}
int stmvl6180_power_up_i2c(void *i2c_object, unsigned int *preset_flag)
{
	int ret = 0;
#ifndef STM_TEST
	struct i2c_data *data = (struct i2c_data *)i2c_object;
#endif
	vl6180_dbgmsg("Enter\n");

	/* actual power on */
#ifndef STM_TEST
	if (data != NULL) {
		ret = regulator_set_optimum_mode(data->vdd, 100000);
		pr_info("%s: stmvl6180 set L18 to mode %d\n", __func__,  ret);
		ret = regulator_enable(data->vdd);
		if (ret < 0) {
			pr_err("%s: failed to enable st vdd\n", __func__);
			return ret;
		}
		ret = regulator_enable(data->vcc);
		if ( ret < 0) {
			pr_err("%s: failed to enable st vcc\n", __func__);
			return ret;
		}
		gpio_set_value(data->cs_gpio_num, 1);

		/* Delay 3 ms to wait for chip power up */
		msleep(3);
		data->power_up = 1;
	}
	*preset_flag = 1;
#endif

	vl6180_dbgmsg("End\n");
	return ret;
}
static int stmvl6180_probe(struct i2c_client *client,
				   const struct i2c_device_id *id)
{
	int rc = 0;
	struct stmvl6180_data *vl6180_data = NULL;
	struct i2c_data *data = NULL;

	vl6180_dbgmsg("Enter\n");

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
		rc = -EIO;
		return rc;
	}

	vl6180_data = stmvl6180_getobject();
	if (vl6180_data)
		data = &(vl6180_data->client_object);
	data->client = client;

	/* setup regulator */
	stmvl6180_parse_vdd(&data->client->dev, data);

	/* setup client data */
	i2c_set_clientdata(client, vl6180_data);

	/* setup platform i2c client */
	i2c_setclient((void *)client);

	vl6180_dbgmsg("End\n");
	return rc;
}
/*
 * Initialization function
 */
static int stmvl6180_init_client(struct stmvl6180_data *data)
{
	uint8_t id = 0, module_major = 0, module_minor = 0;
	uint8_t model_major = 0, model_minor = 0;
	uint8_t i = 0, val;

	vl6180_dbgmsg("Enter\n");

	/* Read Model ID */
	VL6180x_RdByte(vl6180x_dev, VL6180_MODEL_ID_REG, &id);
	vl6180_errmsg("read MODLE_ID: 0x%x\n", id);
	if (id == 0xb4) {
		vl6180_errmsg("STM VL6180 Found\n");
	} else if (id == 0) {
		vl6180_errmsg("Not found STM VL6180\n");
	}

	/* Read Model Version */
	VL6180x_RdByte(vl6180x_dev, VL6180_MODEL_REV_MAJOR_REG, &model_major);
	model_major &= 0x07;
	VL6180x_RdByte(vl6180x_dev, VL6180_MODEL_REV_MINOR_REG, &model_minor);
	model_minor &= 0x07;
	vl6180_errmsg("STM VL6180 Model Version : %d.%d\n", model_major, model_minor);

	/* Read Module Version */
	VL6180x_RdByte(vl6180x_dev, VL6180_MODULE_REV_MAJOR_REG, &module_major);
	VL6180x_RdByte(vl6180x_dev, VL6180_MODULE_REV_MINOR_REG, &module_minor);
	vl6180_errmsg("STM VL6180 Module Version : %d.%d\n", module_major, module_minor);

	/* Read Identification */
	printk("STM VL6180 Serial Numbe: ");
	for (i = 0; i <= (VL6180_FIRMWARE_REVISION_ID_REG - VL6180_REVISION_ID_REG); i++) {
		VL6180x_RdByte(vl6180x_dev, (VL6180_REVISION_ID_REG + i), &val);
		printk("0x%x-", val);
	}
	printk("\n");


	/* intialization */
	if (data->reset) {
		/* no need
		vl6180_dbgmsg("WaitDeviceBoot");
		VL6180x_WaitDeviceBooted(vl6180x_dev);
		*/

		/* only called if device being reset, otherwise data being overwrite */
		vl6180_dbgmsg("Init data!");
		VL6180x_InitData(vl6180x_dev); /* only called if device being reset */
		data->reset = 0;
	}
	/* set user calibration data - need to be called after VL6180x_InitData */
#ifdef CALIBRATION_FILE
	stmvl6180_read_calibration_file();
#endif

	vl6180_dbgmsg("End\n");

	return 0;
}
static int32_t stmvl6180_platform_probe(struct platform_device *pdev)
{
	struct stmvl6180_data *vl6180_data = NULL;
	struct cci_data *data = NULL;
	int32_t rc = 0;

	vl6180_dbgmsg("Enter\n");

	if (!pdev->dev.of_node) {
		vl6180_errmsg("of_node NULL\n");
		return -EINVAL;
	}

	vl6180_data = stmvl6180_getobject();
	if (NULL == vl6180_data) {
		vl6180_errmsg("Object not found!\n");
		return -EINVAL;
	}

	data = &(vl6180_data->client_object);
	if (!data) {
		vl6180_errmsg("data NULL\n");
		return -EINVAL;
	}

	data->client = (struct msm_camera_i2c_client *)&data->g_client;

	/* setup platform i2c client */
	i2c_setclient((void *)data->client);

	/* Set platform device handle */
	data->subdev_ops = &msm_tof_subdev_ops;
	data->pdev = pdev;
	rc = stmvl6180_get_dt_data(&pdev->dev, data);
	if (rc < 0) {
		vl6180_errmsg("%d, failed rc %d\n", __LINE__, rc);
		return rc;
	}
	data->subdev_id = pdev->id;

	rc = gpio_request_one(data->en_gpio,GPIOF_OUT_INIT_LOW,
						"stmvl6180_ldaf_en_gpio");
	if(rc) {
		vl6180_errmsg("failed gpio request %u\n",data->en_gpio);
		return -EINVAL;
	}
	/* ldaf_int not used */
	data->int_gpio = -1;

	/* Set device type as platform device */
	data->device_type = MSM_CAMERA_PLATFORM_DEVICE;
	data->subdev_initialized = FALSE;

	vl6180_dbgmsg("End\n");

	return rc;

}
void stmvl6180_exit_cci(void *cci_object)
{
	struct cci_data *data = (struct cci_data *)cci_object;
	vl6180_dbgmsg("Enter\n");

	if (data && data->client->cci_client)
		kfree(data->client->cci_client);

	vl6180_dbgmsg("End\n");
}
static int stmvl6180_remove(struct i2c_client *client)
{
	struct stmvl6180_data *data = stmvl6180_getobject();
	vl6180_dbgmsg("Enter\n");

	/* Power down the device */
	stmvl6180_power_down_i2c((void *)&data->client_object);

	vl6180_dbgmsg("End\n");
	return 0;
}
int stmvl6180_init_cci(void)
{
	int ret = 0;
	vl6180_dbgmsg("Enter\n");

	/* register as a platform device */
	ret = platform_driver_register(&stmvl6180_platform_driver);
	if (ret)
		vl6180_errmsg("%d, error ret:%d\n", __LINE__, ret);

	vl6180_dbgmsg("End\n");

	return ret;
}
static int stmvl6180_start(struct stmvl6180_data *data, uint8_t scaling, init_mode_e mode)
{
	int rc = 0;
	vl6180_dbgmsg("Enter\n");

	/* Power up */
	rc = data->pmodule_func_tbl->power_up(&data->client_object, &data->reset);
	if (rc) {
		vl6180_errmsg("%d,error rc %d\n", __LINE__, rc);
		return rc;
	}
	/* init */
	rc = stmvl6180_init_client(data);
	if (rc) {
		vl6180_errmsg("%d, error rc %d\n", __LINE__, rc);
		data->pmodule_func_tbl->power_down(&data->client_object);
		return -EINVAL;
	}
	/* prepare */
	VL6180x_Prepare(vl6180x_dev);
	VL6180x_UpscaleSetScaling(vl6180x_dev, scaling);

	/* check mode */
	if (mode != NORMAL_MODE) {
#if VL6180x_WRAP_AROUND_FILTER_SUPPORT
		/* turn off wrap around filter */
		VL6180x_FilterSetState(vl6180x_dev, 0);
#endif
		VL6180x_SetXTalkCompensationRate(vl6180x_dev, 0);
		VL6180x_UpdateByte(vl6180x_dev, SYSRANGE_RANGE_CHECK_ENABLES,
						~RANGE_CHECK_RANGE_ENABLE_MASK, 0);

	}
	if (mode == OFFSETCALIB_MODE)
		VL6180x_SetOffsetCalibrationData(vl6180x_dev, 0);


	/* start - single shot mode */
	VL6180x_RangeSetSystemMode(vl6180x_dev, MODE_START_STOP|MODE_SINGLESHOT);
	data->ps_is_singleshot = 1;
	data->enable_ps_sensor = 1;

	/* enable work handler */
	stmvl6180_schedule_handler(data);

	vl6180_dbgmsg("End\n");

	return rc;
}
static void __exit stmvl6180_exit(void)
{
	vl6180_dbgmsg("Enter\n");
	if (gp_vl6180_data) {
		input_unregister_device(gp_vl6180_data->input_dev_ps);
		input_free_device(gp_vl6180_data->input_dev_ps);
#ifdef USE_INT
		free_irq(data->irq, gp_vl6180_data);
#endif
		sysfs_remove_group(gp_vl6180_data->range_kobj, &stmvl6180_attr_group);
		gp_vl6180_data->pmodule_func_tbl->deinit(&gp_vl6180_data->client_object);
		kfree(gp_vl6180_data);
		gp_vl6180_data = NULL;
	}
	vl6180_dbgmsg("End\n");
}
int stmvl6180_init_i2c(void)
{
	int ret = 0;

#ifdef STM_TEST
	struct i2c_client *client = NULL;
	struct i2c_adapter *adapter;
	struct i2c_board_info info = {
		.type = "stmvl6180",
		.addr = VL6180_I2C_ADDRESS,
	};
#endif

	vl6180_dbgmsg("Enter\n");

	/* register as a i2c client device */
	ret = i2c_add_driver(&stmvl6180_driver);
	if (ret)
		vl6180_errmsg("%d erro ret:%d\n", __LINE__, ret);

#ifdef STM_TEST
	if (!ret) {
		adapter = i2c_get_adapter(4);
		if (!adapter)
			ret = -EINVAL;
		else
			client = i2c_new_device(adapter, &info);
		if (!client)
			ret = -EINVAL;
	}
#endif

	vl6180_dbgmsg("End with rc:%d\n", ret);

	return ret;
}

void stmvl6180_exit_i2c(void *i2c_object)
{
	vl6180_dbgmsg("Enter\n");
	i2c_del_driver(&stmvl6180_driver);

	vl6180_dbgmsg("End\n");
}
static int stmvl6180_stop(struct stmvl6180_data *data)
{
	int rc = 0;
	vl6180_dbgmsg("Enter\n");

	/* stop - if continuous mode */
	if (data->ps_is_singleshot == 0)
		VL6180x_RangeSetSystemMode(vl6180x_dev, MODE_START_STOP);
	/* clean interrupt */
	VL6180x_RangeClearInterrupt(vl6180x_dev);
	/* cancel work handler */
	stmvl6180_cancel_handler(data);
	/* power down */
	rc = data->pmodule_func_tbl->power_down(&data->client_object);
	if (rc) {
		vl6180_errmsg("%d, error rc %d\n", __LINE__, rc);
		return rc;
	}
	vl6180_dbgmsg("End\n");

	return rc;
}
static int stmvl6180_cci_init(struct cci_data *data)
{
	int rc = 0;
	struct msm_camera_cci_client *cci_client = data->client->cci_client;

	if (FALSE == data->subdev_initialized) {
		data->client->i2c_func_tbl = &msm_sensor_cci_func_tbl;
		data->client->cci_client = kzalloc(sizeof(struct msm_camera_cci_client),  GFP_KERNEL);
		if (!data->client->cci_client) {
			vl6180_errmsg("%d, failed no memory\n", __LINE__);
			return -ENOMEM;
		}
		cci_client = data->client->cci_client;
		cci_client->cci_subdev = msm_cci_get_subdev();
		cci_client->cci_i2c_master = data->cci_master;
		v4l2_subdev_init(&data->msm_sd.sd, data->subdev_ops);
		v4l2_set_subdevdata(&data->msm_sd.sd, data);
		data->msm_sd.sd.internal_ops = &msm_tof_internal_ops;
		data->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
		snprintf(data->msm_sd.sd.name, ARRAY_SIZE(data->msm_sd.sd.name), "msm_tof");
		media_entity_init(&data->msm_sd.sd.entity, 0, NULL, 0);
		data->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
		data->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_TOF;
		data->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
		msm_sd_register(&data->msm_sd);
		msm_tof_v4l2_subdev_fops = v4l2_subdev_fops;
		/*
		#ifdef CONFIG_COMPAT
				msm_tof_v4l2_subdev_fops.compat_ioctl32 = msm_tof_subdev_fops_ioctl;
		#endif
		*/
		data->msm_sd.sd.devnode->fops = &msm_tof_v4l2_subdev_fops;
		data->subdev_initialized = TRUE;
	}

	cci_client->sid = data->slave_addr;
	cci_client->i2c_freq_mode = data->i2c_freq_mode;
	cci_client->retries = 3;
	cci_client->id_map = 0;
	cci_client->cci_i2c_master = data->cci_master;
	rc = data->client->i2c_func_tbl->i2c_util(data->client, MSM_CCI_INIT);
	if (rc < 0) {
		vl6180_errmsg("%d: CCI Init failed\n", __LINE__);
		return rc;
	}
	vl6180_dbgmsg("CCI Init Succeeded\n");

	data->client->addr_type = MSM_CAMERA_I2C_WORD_ADDR;

    return 0;
}
static int32_t msm_tof_power(struct v4l2_subdev *sd, int on)
{
	struct stmvl6180_data *stmdata = stmvl6180_getobject();

	if(stmdata) {
		mutex_lock(&stmdata->work_mutex);
		if(on) {
			if(stmdata->tof_start && stmdata->enable_ps_sensor == 0)
				stmdata->tof_start(stmdata, 3, NORMAL_MODE);
		} else {
			if(stmdata->tof_stop && stmdata->enable_ps_sensor == 1) {
				stmdata->enable_ps_sensor = 0;
				stmdata->tof_stop(stmdata);
			}
		}
		mutex_unlock(&stmdata->work_mutex);
	}
	vl6180_dbgmsg("TOF power called %d\n", on);
	return 0;
}
static void stmvl6180_write_offset_calibration_file(void)
{
	struct file *f;
	char buf[8];
	mm_segment_t fs;

	f = filp_open("/persist/calibration/offset", O_RDWR|O_CREAT, 0644);
	if (IS_ERR(f)) {
		vl6180_errmsg("%ld\n", PTR_ERR(f));
		return;
	}

	fs = get_fs();
	set_fs(get_ds());
	sprintf(buf, "%d", offset_calib);
	vl6180_dbgmsg("write offset as:%s, buf[0]:%c\n", buf, buf[0]);
	f->f_op->write(f, buf, 8, &f->f_pos);
	set_fs(fs);
	filp_close(f, NULL);
	return;
}
/*
 * QCOM specific functions
 */
static int stmvl6180_parse_vdd(struct device *dev, struct i2c_data *data)
{
	int err = 0;
	vl6180_dbgmsg("Enter\n");

	err = of_property_read_string(dev->of_node, "st,vdd", &power_pin_vdd);
	if (err) {
		pr_err("%s: OF error rc=%d at line %d for st,vdd\n",
		       __func__, err, __LINE__);
		goto exit;
	}

	err = of_property_read_string(dev->of_node, "st,vcc", &power_pin_vcc);
	if (err) {
		pr_err("%s: OF error rc=%d at line %d for st,vdd\n",
		       __func__, err, __LINE__);
		goto exit;
	}
	data->cs_gpio_num = of_get_named_gpio(dev->of_node, "st,cs_gpio", 0);
	if (!gpio_is_valid(data->cs_gpio_num)) {
		pr_err("%s: OF error rc=%d at line %d for cy,cs_gpio\n",
		       __func__, err, __LINE__);
		goto exit;
	}

	/* VDD power on */
	data->vdd = regulator_get(dev, power_pin_vdd);

	if (IS_ERR(data->vdd)) {
		pr_err("%s: failed to get st vdd\n", __func__);
		goto exit;
	}

	err = regulator_set_voltage(data->vdd, 2850000, 2850000);
	if (err < 0) {
		pr_err("%s: failed to set st vdd\n", __func__);
		goto exit_vdd_regulator_put;
	}

	/* VCC power on */
	data->vcc = regulator_get(dev, power_pin_vcc);

	if (IS_ERR(data->vcc)) {
		pr_err("%s: failed to get st vcc\n", __func__);
		goto exit_vdd_regulator_put;
	}

	err = regulator_set_voltage(data->vcc, 0, 0);
	if (err < 0) {
		pr_err("%s: failed to set st vcc\n", __func__);
		goto exit_vcc_regulator_put;
	}

	err = gpio_request(data->cs_gpio_num, "tmvl6180");
	if (err < 0) {
		pr_err("%s: failed to get cs gpio\n", __func__);
		goto exit_vcc_regulator_put;
	}

	err = gpio_direction_output(data->cs_gpio_num, 1);
	if (err < 0) {
		pr_err("%s: failed to get cs gpio\n", __func__);
		goto exit_vcc_regulator_put;
	}


	vl6180_dbgmsg("End\n");

	return err;

exit_vcc_regulator_put:
	regulator_put(data->vcc);
exit_vdd_regulator_put:
	regulator_put(data->vdd);
exit:
	return err;
}
static void stmvl6180_read_calibration_file(void)
{
	struct file *f;
	char buf[8];
	mm_segment_t fs;
	int i, is_sign = 0;

	if(gp_vl6180_data->offset_buf.file_opened == true) {
		vl6180_dbgmsg("offset_calib as %d\n",
				gp_vl6180_data->offset_buf.value);
		VL6180x_SetOffsetCalibrationData(vl6180x_dev,
				gp_vl6180_data->offset_buf.value);
	} else {
		f = filp_open("/persist/calibration/offset", O_RDONLY, 0);
		if (f != NULL && !IS_ERR(f) && f->f_dentry != NULL) {
			fs = get_fs();
			set_fs(get_ds());
			/* init the buffer with 0 */
			for (i = 0; i < 8; i++)
				buf[i] = 0;
			f->f_op->read(f, buf, 8, &f->f_pos);
			set_fs(fs);
			vl6180_dbgmsg("offset as:%s, buf[0]:%c\n", buf, buf[0]);
			offset_calib = 0;
			for (i = 0; i < 8; i++) {
				if (i == 0 && buf[0] == '-')
					is_sign = 1;
				else if (buf[i] >= '0' && buf[i] <= '9')
					offset_calib = offset_calib * 10 + (buf[i] - '0');
				else
					break;
			}
			if (is_sign == 1)
				offset_calib = -1 * offset_calib;
			vl6180_dbgmsg("file open offset_calib as %d\n", offset_calib);
			gp_vl6180_data->offset_buf.file_opened = true;
			gp_vl6180_data->offset_buf.value = offset_calib;
			VL6180x_SetOffsetCalibrationData(vl6180x_dev, offset_calib);
			filp_close(f, NULL);
		} else {
			gp_vl6180_data->offset_buf.file_opened = true;
			gp_vl6180_data->offset_buf.value = 0;
			vl6180_errmsg("no offset calibration file exist!\n");
		}
	}
	is_sign = 0;
	if(gp_vl6180_data->xtalk_buf.file_opened == true) {
		vl6180_dbgmsg("xtalk_calib as %d\n",
				gp_vl6180_data->xtalk_buf.value);
		/* set up threshold ignore */
		if ((gp_vl6180_data->xtalk_buf.value+13) < 64 )
			VL6180x_WrWord(vl6180x_dev, SYSRANGE_RANGE_IGNORE_THRESHOLD, 64); /* 0.5Mcps */
		else
			VL6180x_WrWord(vl6180x_dev, SYSRANGE_RANGE_IGNORE_THRESHOLD, (gp_vl6180_data->xtalk_buf.value+13)); /* +0.1Mcps */
		VL6180x_WrByte(vl6180x_dev, SYSRANGE_RANGE_IGNORE_VALID_HEIGHT, 100);
		VL6180x_UpdateByte(vl6180x_dev, SYSRANGE_RANGE_CHECK_ENABLES,
						~RANGE_CHECK_RANGE_ENABLE_MASK, RANGE_CHECK_RANGE_ENABLE_MASK);
		/* setup xtalk compensation rate */
		VL6180x_SetXTalkCompensationRate(vl6180x_dev, gp_vl6180_data->xtalk_buf.value);
	} else {
		f = filp_open("/persist/calibration/xtalk", O_RDONLY, 0);
		if (f != NULL && !IS_ERR(f) && f->f_dentry != NULL) {
			fs = get_fs();
			set_fs(get_ds());
			/* init the buffer with 0 */
			for (i = 0; i < 8; i++)
				buf[i] = 0;
			f->f_op->read(f, buf, 8, &f->f_pos);
			set_fs(fs);
			vl6180_dbgmsg("xtalk as:%s, buf[0]:%c\n", buf, buf[0]);
			xtalk_calib = 0;
			for (i = 0; i < 8; i++) {
				if (i == 0 && buf[0] == '-')
					is_sign = 1;
				else if (buf[i] >= '0' && buf[i] <= '9')
					xtalk_calib = xtalk_calib * 10 + (buf[i] - '0');
				else
					break;
			}
			if (is_sign == 1)
				xtalk_calib = -1 * xtalk_calib;
			vl6180_dbgmsg("file open xtalk_calib as %d\n", xtalk_calib);
			gp_vl6180_data->xtalk_buf.file_opened = true;
			gp_vl6180_data->xtalk_buf.value = xtalk_calib;
			/* set up threshold ignore */
			if ((xtalk_calib+13) < 64 )
				VL6180x_WrWord(vl6180x_dev, SYSRANGE_RANGE_IGNORE_THRESHOLD, 64); /* 0.5Mcps */
			else
				VL6180x_WrWord(vl6180x_dev, SYSRANGE_RANGE_IGNORE_THRESHOLD, (xtalk_calib+13)); /* +0.1Mcps */
			VL6180x_WrByte(vl6180x_dev, SYSRANGE_RANGE_IGNORE_VALID_HEIGHT, 100);
			VL6180x_UpdateByte(vl6180x_dev, SYSRANGE_RANGE_CHECK_ENABLES,
							~RANGE_CHECK_RANGE_ENABLE_MASK, RANGE_CHECK_RANGE_ENABLE_MASK);
			/* setup xtalk compensation rate */
			VL6180x_SetXTalkCompensationRate(vl6180x_dev, xtalk_calib);
			filp_close(f, NULL);
		} else {
			gp_vl6180_data->xtalk_buf.file_opened = true;
			gp_vl6180_data->xtalk_buf.value = XTALK_CALIBRATION_DEFAULT;
			vl6180_errmsg("no xtalk calibration file exist!\n");
		}
	}
	return;
}
static long msm_tof_subdev_ioctl(struct v4l2_subdev *sd,
			unsigned int cmd, void *arg)
{
	vl6180_dbgmsg("Subdev_ioctl not handled cmd: %u arg: %p\n",cmd,arg);
	return 0;
}
/*
 * misc device file operation functions
 */
static int stmvl6180_ioctl_handler(struct file *file,
				unsigned int cmd, unsigned long arg, void __user *p)
{
	int rc = 0;
	unsigned int xtalkint = 0;
	int8_t offsetint = 0;
	struct stmvl6180_data *data = gp_vl6180_data;
	struct stmvl6180_register reg;

	if (!data)
		return -EINVAL;

	vl6180_dbgmsg("Enter enable_ps_sensor:%d\n", data->enable_ps_sensor);
	switch (cmd) {
	/* enable */
	case VL6180_IOCTL_INIT:
		pr_err("%s: VL6180_IOCTL_INIT\n", __func__);
		/* turn on tof sensor only if it's not enabled by other client */
		if (data->enable_ps_sensor == 0) {
			/* to start */
			stmvl6180_start(data, 3, NORMAL_MODE);
		} else
			rc = -EINVAL;
		break;
	/* crosstalk calibration */
	case VL6180_IOCTL_XTALKCALB:
		vl6180_dbgmsg("VL6180_IOCTL_XTALKCALB\n");
		/* turn on tof sensor only if it's not enabled by other client */
		if (data->enable_ps_sensor == 0) {
			/* to start */
			stmvl6180_start(data, 3, XTALKCALIB_MODE);
		} else
			rc = -EINVAL;
		break;
	/* set up Xtalk value */
	case VL6180_IOCTL_SETXTALK:
		vl6180_dbgmsg("VL6180_IOCTL_SETXTALK\n");
		if (copy_from_user(&xtalkint, (unsigned int *)p, sizeof(unsigned int))) {
			vl6180_errmsg("%d, fail\n", __LINE__);
			return -EFAULT;
		}
		vl6180_dbgmsg("SETXTALK as 0x%x\n", xtalkint);
#ifdef CALIBRATION_FILE
		xtalk_calib = xtalkint;
		stmvl6180_write_xtalk_calibration_file();
#endif
		VL6180x_SetXTalkCompensationRate(vl6180x_dev, xtalkint);
		break;
	/* offset calibration */
	case VL6180_IOCTL_OFFCALB:
		vl6180_dbgmsg("VL6180_IOCTL_OFFCALB\n");
		if (data->enable_ps_sensor == 0) {
			/* to start */
			stmvl6180_start(data, 3, OFFSETCALIB_MODE);
		} else
			rc = -EINVAL;
		break;
	/* set up offset value */
	case VL6180_IOCTL_SETOFFSET:
		vl6180_dbgmsg("VL6180_IOCTL_SETOFFSET\n");
		if (copy_from_user(&offsetint, (int8_t *)p, sizeof(int8_t))) {
			vl6180_errmsg("%d, fail\n", __LINE__);
			return -EFAULT;
		}
		vl6180_dbgmsg("SETOFFSET as %d\n", offsetint);
#ifdef CALIBRATION_FILE
		offset_calib = offsetint;
		stmvl6180_write_offset_calibration_file();
#endif
		VL6180x_SetOffsetCalibrationData(vl6180x_dev, offsetint);
		break;
	/* disable */
	case VL6180_IOCTL_STOP:
		vl6180_errmsg("VL6180_IOCTL_STOP\n");
		/* turn off tof sensor only if it's enabled by other client */
		if (data->enable_ps_sensor == 1) {
			data->enable_ps_sensor = 0;
			/* to stop */
			stmvl6180_stop(data);
		}
		break;
	/* Get all range data */
	case VL6180_IOCTL_GETDATAS:
		vl6180_dbgmsg("VL6180_IOCTL_GETDATAS\n");
		if (copy_to_user((VL6180x_RangeData_t *)p, &(data->rangeData), sizeof(VL6180x_RangeData_t))) {
			vl6180_errmsg("%d, fail\n", __LINE__);
			return -EFAULT;
		}
		break;
	case VL6180_IOCTL_REGISTER:
		vl6180_dbgmsg("VL6180_IOCTL_REGISTER\n");
		if (copy_from_user(&reg, (struct stmvl6180_register *)p,
							sizeof(struct stmvl6180_register))) {
			vl6180_errmsg("%d, fail\n", __LINE__);
			return -EFAULT;
		}
		reg.status = 0;
		switch (reg.reg_bytes) {
		case(4):
			if (reg.is_read)
				reg.status = VL6180x_RdDWord(vl6180x_dev, (uint16_t)reg.reg_index,
											&reg.reg_data);
			else
				reg.status = VL6180x_WrDWord(vl6180x_dev, (uint16_t)reg.reg_index,
											reg.reg_data);
			break;
		case(2):
			if (reg.is_read)
				reg.status = VL6180x_RdWord(vl6180x_dev, (uint16_t)reg.reg_index,
											(uint16_t *)&reg.reg_data);
			else
				reg.status = VL6180x_WrWord(vl6180x_dev, (uint16_t)reg.reg_index,
											(uint16_t)reg.reg_data);			
			break;
		case(1):
			if (reg.is_read)
				reg.status = VL6180x_RdByte(vl6180x_dev, (uint16_t)reg.reg_index,
											(uint8_t *)&reg.reg_data);
			else
				reg.status = VL6180x_WrByte(vl6180x_dev, (uint16_t)reg.reg_index,
											(uint8_t)reg.reg_data);						
			break;
		default:
			reg.status = -1;

		}
		if (copy_to_user((struct stmvl6180_register *)p, &reg,
							sizeof(struct stmvl6180_register))) {
			vl6180_errmsg("%d, fail\n", __LINE__);
			return -EFAULT;
		}
		break;
	default:
		rc = -EINVAL;
		break;
	}
	return rc;
}
/*
 * QCOM specific functions
 */
static int stmvl6180_get_dt_data(struct device *dev, struct cci_data *data)
{
	int rc = 0;
	vl6180_dbgmsg("Enter\n");

	if (dev->of_node) {
		struct device_node *of_node = dev->of_node;
		struct msm_tof_vreg *vreg_cfg;

		if (!of_node) {
			vl6180_errmsg("failed %d\n", __LINE__);
			return -EINVAL;
		}

		rc = of_property_read_u32(of_node, "cell-index", &data->pdev->id);
		if (rc < 0) {
			vl6180_errmsg("failed %d\n", __LINE__);
			return rc;
		}
		vl6180_dbgmsg("cell-index: %d\n", data->pdev->id);
		rc = of_property_read_u32(of_node, "qcom,cci-master", &data->cci_master);
		if (rc < 0) {
			vl6180_errmsg("failed %d\n", __LINE__);
			/* Set default master 0 */
			data->cci_master = MASTER_0;
			rc = 0;
		}
		vl6180_dbgmsg("cci_master: %d\n", data->cci_master);
		rc = of_property_read_u32(of_node, "qcom,slave-addr",&data->slave_addr);
		if (rc < 0) {
			vl6180_errmsg("failed %d\n", __LINE__);
			data->slave_addr = 0x29;
			rc = 0;
		}
		vl6180_dbgmsg("slave addr: %d\n", data->slave_addr);
		if (of_find_property(of_node, "qcom,cam-vreg-name", NULL)) {
			vreg_cfg = &data->vreg_cfg;
			rc = msm_camera_get_dt_vreg_data(of_node,
				&vreg_cfg->cam_vreg, &vreg_cfg->num_vreg);
			if (rc < 0) {
				vl6180_errmsg("failed %d\n", __LINE__);
				return rc;
			}
		}
		vl6180_dbgmsg("vreg-name: %s min_volt: %d max_volt: %d",
					vreg_cfg->cam_vreg->reg_name,
					vreg_cfg->cam_vreg->min_voltage,
					vreg_cfg->cam_vreg->max_voltage);

		data->en_gpio = of_get_named_gpio(of_node,
						"stmvl6180,ldaf-en-gpio",0);
		if (data->en_gpio < 0 || !gpio_is_valid(data->en_gpio)) {
			vl6180_errmsg("en_gpio is unavailable or invalid\n");
			return data->en_gpio;
	        }
		data->int_gpio = of_get_named_gpio(of_node,
						"stmvl6180,ldaf-int-gpio",0);
		if (data->int_gpio < 0 || !gpio_is_valid(data->int_gpio)) {
			vl6180_errmsg("en_gpio is unvailable or invalid\n");
			return data->int_gpio;
		}
		vl6180_dbgmsg("ldaf_int: %u,ldaf_en: %u\n",
						data->int_gpio,data->en_gpio);

		rc = of_property_read_u32(of_node, "qcom,i2c-freq-mode",
							&data->i2c_freq_mode);
		if (rc < 0 || data->i2c_freq_mode >= I2C_MAX_MODES) {
			data->i2c_freq_mode = 0;
			vl6180_errmsg("invalid i2c frequency mode\n");
		}
		vl6180_dbgmsg("i2c_freq_mode: %u\n",data->i2c_freq_mode);

	}
	vl6180_dbgmsg("End rc =%d\n", rc);

	return rc;
}
static int stmvl6180_setup(struct stmvl6180_data *data)
{
	int rc = 0;
#ifdef USE_INT
	int irq = 0;
#endif

	vl6180_dbgmsg("Enter\n");

	/* init mutex */
	mutex_init(&data->update_lock);
	mutex_init(&data->work_mutex);

#ifdef USE_INT
	/* init interrupt */
	gpio_request(IRQ_NUM, "vl6180_gpio_int");
	gpio_direction_input(IRQ_NUM);
	irq = gpio_to_irq(IRQ_NUM);
	if (irq < 0) {
		vl6180_errmsg("filed to map GPIO: %d to interrupt:%d\n", IRQ_NUM, irq);
	} else {
		int result;
		vl6180_dbgmsg("register_irq:%d\n", irq);
		/* IRQF_TRIGGER_FALLING- poliarity:0 IRQF_TRIGGER_RISNG - poliarty:1 */
		rc = request_threaded_irq(irq, NULL, stmvl6180_interrupt_handler, IRQF_TRIGGER_RISING, "vl6180_lb_gpio_int", (void *)data);
		if (rc) {
			vl6180_errmsg("%d, Could not allocate STMVL6180_INT ! result:%d\n",  __LINE__, result);
			return rc;
		}
	}
	data->irq = irq;
	vl6180_dbgmsg("interrupt is hooked\n");
#endif

	/* init work handler */
	INIT_DELAYED_WORK(&data->dwork, stmvl6180_work_handler);

	/* Register to Input Device */
	data->input_dev_ps = input_allocate_device();
	if (!data->input_dev_ps) {
		rc = -ENOMEM;
		vl6180_errmsg("%d error:%d\n", __LINE__, rc);
#ifdef USE_INT
		free_irq(irq, data);
#endif
		return rc;
	}
	set_bit(EV_ABS, data->input_dev_ps->evbit);
	/* range in cm*/
	input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 76, 0, 0);
	/* tv_sec */
	input_set_abs_params(data->input_dev_ps, ABS_HAT0X, 0, 0xffffffff, 0, 0);
	/* tv_usec */
	input_set_abs_params(data->input_dev_ps, ABS_HAT0Y, 0, 0xffffffff, 0, 0);
	/* range in_mm */
	input_set_abs_params(data->input_dev_ps, ABS_HAT1X, 0, 765, 0, 0);
	/* error code change maximum to 0xff for more flexibility */
	input_set_abs_params(data->input_dev_ps, ABS_HAT1Y, 0, 0xff, 0, 0);
	/* rtnRate */
	input_set_abs_params(data->input_dev_ps, ABS_HAT2X, 0, 0xffffffff, 0, 0);
	/* rtn_amb_rate */
	input_set_abs_params(data->input_dev_ps, ABS_HAT2Y, 0, 0xffffffff, 0, 0);
	/* rtn_conv_time */
	input_set_abs_params(data->input_dev_ps, ABS_HAT3X, 0, 0xffffffff, 0, 0);
	/* dmax */
	input_set_abs_params(data->input_dev_ps, ABS_HAT3Y, 0, 0xffffffff, 0, 0);
	data->input_dev_ps->name = "STM VL6180 proximity sensor";

	/* setup the open/close callbacks for the input_device */
	data->input_dev_ps->open = stmvl6180_data_dev_open;
	data->input_dev_ps->close = stmvl6180_data_dev_close;

	rc = input_register_device(data->input_dev_ps);
	if (rc) {
		rc = -ENOMEM;
		vl6180_errmsg("%d error:%d\n", __LINE__, rc);
#ifdef USE_INT
		free_irq(irq, data);
#endif
		input_free_device(data->input_dev_ps);
		return rc;
	}

	/* Register sysfs hooks */
	data->range_kobj = kobject_create_and_add("range", kernel_kobj);
	if (!data->range_kobj) {
		rc = -ENOMEM;
		vl6180_errmsg("%d error:%d\n", __LINE__, rc);
#ifdef USE_INT
		free_irq(irq, data);
#endif
		input_unregister_device(data->input_dev_ps);
		input_free_device(data->input_dev_ps);
		return rc;
	}
	rc = sysfs_create_group(data->range_kobj, &stmvl6180_attr_group);
	if (rc) {
		rc = -ENOMEM;
		vl6180_errmsg("%d error:%d\n", __LINE__, rc);
#ifdef USE_INT
		free_irq(irq, data);
#endif
		kobject_put(data->range_kobj);
		input_unregister_device(data->input_dev_ps);
		input_free_device(data->input_dev_ps);
		return rc;
	}

	/* to register as a misc device */
	if (misc_register(&stmvl6180_ranging_dev) != 0)
		vl6180_errmsg("Could not register misc. dev for stmvl6180 ranging\n");

	/* init default value */
	data->enable_ps_sensor = 0;
	data->reset = 1;
	data->delay_ms = 30;	/* delay time to 30ms */
	data->enableDebug = 0;
	data->client_object.power_up = 0; /* for those one-the-fly power on/off flag */

	vl6180_dbgmsg("support ver. %s enabled\n", DRIVER_VERSION);
	vl6180_dbgmsg("End");

	return rc;
}