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(®, (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_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_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_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, ®, 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; }