static ssize_t proximity_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct cm36686_data *cm36686 = dev_get_drvdata(dev); u16 ps_data; mutex_lock(&cm36686->power_lock); if (!(cm36686->power_state & PROXIMITY_ENABLED)) { #if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO) cm36686_leden_gpio_onoff(cm36686, 1); #else prox_led_onoff(cm36686, 1); #endif cm36686_i2c_write_word(cm36686, REG_PS_CONF1, ps_reg_init_setting[PS_CONF1][CMD]); } mutex_lock(&cm36686->read_lock); cm36686_i2c_read_word(cm36686, REG_PS_DATA, &ps_data); mutex_unlock(&cm36686->read_lock); if (!(cm36686->power_state & PROXIMITY_ENABLED)) { cm36686_i2c_write_word(cm36686, REG_PS_CONF1, 0x0001); #if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO) cm36686_leden_gpio_onoff(cm36686, 0); #else prox_led_onoff(cm36686, 0); #endif } mutex_unlock(&cm36686->power_lock); return sprintf(buf, "%u\n", ps_data); }
static ssize_t proximity_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct cm36686_data *cm36686 = dev_get_drvdata(dev); u16 ps_data; mutex_lock(&cm36686->power_lock); if (!(cm36686->power_state & PROXIMITY_ENABLED)) { if (cm36686->pdata->cm36686_led_on) { cm36686->pdata->cm36686_led_on(true); msleep(20); } cm36686_i2c_write_word(cm36686, REG_PS_CONF1, ps_reg_init_setting[PS_CONF1][CMD]); } mutex_lock(&cm36686->read_lock); cm36686_i2c_read_word(cm36686, REG_PS_DATA, &ps_data); mutex_unlock(&cm36686->read_lock); if (!(cm36686->power_state & PROXIMITY_ENABLED)) { cm36686_i2c_write_word(cm36686, REG_PS_CONF1, 0x0001); if (cm36686->pdata->cm36686_led_on) cm36686->pdata->cm36686_led_on(false); } mutex_unlock(&cm36686->power_lock); return sprintf(buf, "%u\n", ps_data); }
static int cm36686_setup_reg(struct cm36686_data *cm36686) { int err = 0, i = 0; u16 tmp = 0; /* ALS initialization */ err = cm36686_i2c_write_word(cm36686, als_reg_setting[0][0], als_reg_setting[0][1]); if (err < 0) { pr_err("%s: cm36686_als_reg is failed. %d\n", __func__, err); return err; } /* PS initialization */ if (cm36686->pdata != NULL) { ps_reg_init_setting[PS_THD_LOW][CMD] = cm36686->pdata->default_low_thd; ps_reg_init_setting[PS_THD_HIGH][CMD] = cm36686->pdata->default_hi_thd; pr_info("%s - THD_LOW = %u, THD_HIGH = %u\n", __func__, ps_reg_init_setting[PS_THD_LOW][CMD], ps_reg_init_setting[PS_THD_HIGH][CMD]); } for (i = 0; i < PS_REG_NUM; i++) { err = cm36686_i2c_write_word(cm36686, ps_reg_init_setting[i][REG_ADDR], ps_reg_init_setting[i][CMD]); if (err < 0) { pr_err("%s: cm36686_ps_reg is failed. %d\n", __func__, err); return err; } } /* printing the inital proximity value with no contact */ msleep(50); mutex_lock(&cm36686->read_lock); err = cm36686_i2c_read_word(cm36686, REG_PS_DATA, &tmp); mutex_unlock(&cm36686->read_lock); if (err < 0) { pr_err("%s: read ps_data failed\n", __func__); err = -EIO; } pr_err("%s: initial proximity value = %d\n", __func__, tmp); /* turn off */ cm36686_i2c_write_word(cm36686, REG_CS_CONF1, 0x0001); cm36686_i2c_write_word(cm36686, REG_PS_CONF1, 0x0001); cm36686_i2c_write_word(cm36686, REG_PS_CONF3, 0x0000); pr_info("%s is success.", __func__); return err; }
static ssize_t proximity_avg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct cm36686_data *cm36686 = dev_get_drvdata(dev); bool new_value = false; if (sysfs_streq(buf, "1")) new_value = true; else if (sysfs_streq(buf, "0")) new_value = false; else { pr_err("%s, invalid value %d\n", __func__, *buf); return -EINVAL; } pr_info("%s, average enable = %d\n", __func__, new_value); mutex_lock(&cm36686->power_lock); if (new_value) { if (!(cm36686->power_state & PROXIMITY_ENABLED)) { if (cm36686->cm36686_proxi_vddpower) cm36686->cm36686_proxi_vddpower(true); if (cm36686->pdata->cm36686_led_on) { cm36686->pdata->cm36686_led_on(true); msleep(20); } cm36686_i2c_write_word(cm36686, REG_PS_CONF1, ps_reg_init_setting[PS_CONF1][CMD]); } hrtimer_start(&cm36686->prox_timer, cm36686->prox_poll_delay, HRTIMER_MODE_REL); } else if (!new_value) { hrtimer_cancel(&cm36686->prox_timer); cancel_work_sync(&cm36686->work_prox); if (!(cm36686->power_state & PROXIMITY_ENABLED)) { cm36686_i2c_write_word(cm36686, REG_PS_CONF1, 0x0001); if (cm36686->pdata->cm36686_led_on) cm36686->pdata->cm36686_led_on(false); if (cm36686->cm36686_proxi_vddpower) cm36686->cm36686_proxi_vddpower(false); } } mutex_unlock(&cm36686->power_lock); return size; }
static ssize_t proximity_thresh_low_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct cm36686_data *cm36686 = dev_get_drvdata(dev); u16 thresh_value = ps_reg_init_setting[PS_THD_LOW][CMD]; int err; err = kstrtou16(buf, 10, &thresh_value); if (err < 0) pr_err("%s, kstrtoint failed.", __func__); if (thresh_value > 2) { ps_reg_init_setting[PS_THD_LOW][CMD] = thresh_value; err = cm36686_i2c_write_word(cm36686, REG_PS_THD_LOW, ps_reg_init_setting[PS_THD_LOW][CMD]); if (err < 0) pr_err("%s: cm36686_ps_low_reg is failed. %d\n", __func__, err); pr_info("%s, new low threshold = 0x%x\n", __func__, thresh_value); msleep(150); } else pr_err("%s, wrong low threshold value(0x%x)!!\n", __func__, thresh_value); return size; }
static void cm36686_light_disable(struct cm36686_data *cm36686) { /* disable setting */ cm36686_i2c_write_word(cm36686, REG_CS_CONF1, als_reg_setting[1][1]); hrtimer_cancel(&cm36686->light_timer); cancel_work_sync(&cm36686->work_light); }
static void cm36686_light_enable(struct cm36686_data *cm36686) { /* enable setting */ cm36686_i2c_write_word(cm36686, REG_CS_CONF1, als_reg_setting[0][1]); hrtimer_start(&cm36686->light_timer, ns_to_ktime(200 * NSEC_PER_MSEC), HRTIMER_MODE_REL); }
static int cm36686_i2c_remove(struct i2c_client *client) { struct cm36686_data *cm36686 = i2c_get_clientdata(client); /* free irq */ if (cm36686->power_state & PROXIMITY_ENABLED) { disable_irq_wake(cm36686->irq); disable_irq(cm36686->irq); } free_irq(cm36686->irq, cm36686); gpio_free(cm36686->pdata->irq); /* device off */ if (cm36686->power_state & LIGHT_ENABLED) cm36686_light_disable(cm36686); if (cm36686->power_state & PROXIMITY_ENABLED) { cm36686_i2c_write_word(cm36686, REG_PS_CONF1, 0x0001); } /* destroy workqueue */ destroy_workqueue(cm36686->light_wq); destroy_workqueue(cm36686->prox_wq); /* sysfs destroy */ sensors_unregister(cm36686->light_dev, light_sensor_attrs); sensors_unregister(cm36686->proximity_dev, prox_sensor_attrs); sensors_remove_symlink(&cm36686->light_input_dev->dev.kobj, cm36686->light_input_dev->name); sensors_remove_symlink(&cm36686->proximity_input_dev->dev.kobj, cm36686->proximity_input_dev->name); /* input device destroy */ sysfs_remove_group(&cm36686->light_input_dev->dev.kobj, &light_attribute_group); input_unregister_device(cm36686->light_input_dev); sysfs_remove_group(&cm36686->proximity_input_dev->dev.kobj, &proximity_attribute_group); input_unregister_device(cm36686->proximity_input_dev); #if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO) cm36686_leden_gpio_onoff(cm36686, 0); gpio_free(cm36686->pdata->leden_gpio); #else prox_led_onoff(cm36686, 0); #endif /* lock destroy */ mutex_destroy(&cm36686->read_lock); mutex_destroy(&cm36686->power_lock); wake_lock_destroy(&cm36686->prx_wake_lock); kfree(cm36686); return 0; }
static ssize_t proximity_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct cm36686_data *cm36686 = dev_get_drvdata(dev); bool new_value; if (sysfs_streq(buf, "1")) new_value = true; else if (sysfs_streq(buf, "0")) new_value = false; else { pr_err("[SENSOR] %s: invalid value %d\n", __func__, *buf); return -EINVAL; } mutex_lock(&cm36686->power_lock); pr_info("%s, new_value = %d\n", __func__, new_value); if (new_value && !(cm36686->power_state & PROXIMITY_ENABLED)) { u8 val = 1; int i; #ifdef CM36686_CANCELATION int err = 0; #endif cm36686->power_state |= PROXIMITY_ENABLED; #if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO) cm36686_leden_gpio_onoff(cm36686, 1); #else prox_led_onoff(cm36686, 1); #endif #ifdef CM36686_CANCELATION /* open cancelation data */ err = proximity_open_cancelation(cm36686); if (err < 0 && err != -ENOENT) pr_err("[SENSOR] %s: proximity_open_cancelation() failed\n", __func__); #endif /* enable settings */ for (i = 0; i < PS_REG_NUM; i++) { cm36686_i2c_write_word(cm36686, ps_reg_init_setting[i][REG_ADDR], ps_reg_init_setting[i][CMD]); } val = gpio_get_value(cm36686->pdata->irq); /* 0 is close, 1 is far */ input_report_abs(cm36686->proximity_input_dev, ABS_DISTANCE, val); input_sync(cm36686->proximity_input_dev); enable_irq(cm36686->irq); enable_irq_wake(cm36686->irq); } else if (!new_value && (cm36686->power_state & PROXIMITY_ENABLED)) { cm36686->power_state &= ~PROXIMITY_ENABLED; disable_irq_wake(cm36686->irq); disable_irq(cm36686->irq); /* disable settings */ cm36686_i2c_write_word(cm36686, REG_PS_CONF1, 0x0001); #if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO) cm36686_leden_gpio_onoff(cm36686, 0); #else prox_led_onoff(cm36686, 0); #endif } mutex_unlock(&cm36686->power_lock); return size; }
static int proximity_store_cancelation(struct device *dev, bool do_calib) { struct cm36686_data *cm36686 = dev_get_drvdata(dev); struct file *cancel_filp = NULL; mm_segment_t old_fs; int err = 0; u16 ps_data = 0; if (do_calib) { mutex_lock(&cm36686->read_lock); cm36686_i2c_read_word(cm36686, REG_PS_DATA, &ps_data); ps_reg_init_setting[PS_CANCEL][CMD] = ps_data; mutex_unlock(&cm36686->read_lock); err = get_proximity_threshold(cm36686); if(err != ERROR) { if (cm36686->pdata->cancel_hi_thd) { ps_reg_init_setting[PS_THD_HIGH][CMD] = cm36686->pdata->cancel_hi_thd; } else ps_reg_init_setting[PS_THD_HIGH][CMD] = CANCEL_HI_THD; if (cm36686->pdata->cancel_low_thd) { ps_reg_init_setting[PS_THD_LOW][CMD] = cm36686->pdata->cancel_low_thd; } else ps_reg_init_setting[PS_THD_LOW][CMD] = DEFUALT_LOW_THD; } else { set_default_proximity_threshold(cm36686); } } else { /* reset */ ps_reg_init_setting[PS_CANCEL][CMD] = 0; set_default_proximity_threshold(cm36686); } err = cm36686_i2c_write_word(cm36686, REG_PS_CANC, ps_reg_init_setting[PS_CANCEL][CMD]); if (err < 0) pr_err("%s: cm36686_ps_canc_reg is failed. %d\n", __func__, err); err = cm36686_i2c_write_word(cm36686, REG_PS_THD_HIGH, ps_reg_init_setting[PS_THD_HIGH][CMD]); if (err < 0) pr_err("%s: cm36686_ps_high_reg is failed. %d\n", __func__, err); err = cm36686_i2c_write_word(cm36686, REG_PS_THD_LOW, ps_reg_init_setting[PS_THD_LOW][CMD]); if (err < 0) pr_err("%s: cm36686_ps_low_reg is failed. %d\n", __func__, err); pr_info("%s: prox_cal = 0x%x, ps_high_thresh = 0x%x, ps_low_thresh = 0x%x\n", __func__, ps_reg_init_setting[PS_CANCEL][CMD], ps_reg_init_setting[PS_THD_HIGH][CMD], ps_reg_init_setting[PS_THD_LOW][CMD]); old_fs = get_fs(); set_fs(KERNEL_DS); cancel_filp = filp_open(CANCELATION_FILE_PATH, O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); if (IS_ERR(cancel_filp)) { pr_err("[SENSOR] %s: Can't open cancelation file\n", __func__); set_fs(old_fs); err = PTR_ERR(cancel_filp); return err; } err = cancel_filp->f_op->write(cancel_filp, (char *)&ps_reg_init_setting[PS_CANCEL][CMD], sizeof(u16), &cancel_filp->f_pos); if (err != sizeof(u16)) { pr_err("%s: Can't write the cancel data to file\n", __func__); err = -EIO; } filp_close(cancel_filp, current->files); set_fs(old_fs); if (!do_calib) /* delay for clearing */ msleep(150); return err; }
static int cm36686_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = -ENODEV; struct cm36686_data *cm36686 = NULL; struct cm36686_platform_data *pdata = NULL; int err; pr_info("[SENSOR] %s: Probe Start!\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { pr_err("[SENSOR] %s: i2c functionality check failed!\n", __func__); return ret; } cm36686 = kzalloc(sizeof(struct cm36686_data), GFP_KERNEL); if (!cm36686) { pr_err ("[SENSOR] %s: failed to alloc memory for RGB sensor module data\n", __func__); return -ENOMEM; } if(client->dev.of_node) { pdata = devm_kzalloc (&client->dev , sizeof(struct cm36686_platform_data ), GFP_KERNEL); if(!pdata) { dev_err(&client->dev, "Failed to allocate memory\n"); if(cm36686) kfree(cm36686); return -ENOMEM; } err = cm36686_parse_dt(&client->dev, pdata); if(err) goto err_devicetree; } else pdata = client->dev.platform_data; if (!pdata) { pr_err("%s: missing pdata!\n", __func__); if(cm36686) kfree(cm36686); return ret; } prox_regulator_onoff(&client->dev,1); cm36686->pdata = pdata; cm36686->i2c_client = client; i2c_set_clientdata(client, cm36686); mutex_init(&cm36686->power_lock); mutex_init(&cm36686->read_lock); /* wake lock init for proximity sensor */ wake_lock_init(&cm36686->prx_wake_lock, WAKE_LOCK_SUSPEND, "prx_wake_lock"); #if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO) /* setup leden_gpio */ ret = cm36686_setup_leden_gpio(cm36686); if (ret) { pr_err("%s: could not setup leden_gpio\n", __func__); goto err_setup_leden_gpio; } cm36686_leden_gpio_onoff(cm36686, 1); #else prox_led_onoff(cm36686, 1); #endif /* Check if the device is there or not. */ ret = cm36686_i2c_write_word(cm36686, REG_CS_CONF1, 0x0001); if (ret < 0) { pr_err("[SENSOR] %s: cm36686 is not connected.(%d)\n", __func__, ret); goto err_setup_reg; } /* setup initial registers */ ret = cm36686_setup_reg(cm36686); if (ret < 0) { pr_err("[SENSOR] %s: could not setup regs\n", __func__); goto err_setup_reg; } #if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO) cm36686_leden_gpio_onoff(cm36686, 0); #else prox_led_onoff(cm36686, 0); #endif /* allocate proximity input_device */ cm36686->proximity_input_dev = input_allocate_device(); if (!cm36686->proximity_input_dev) { pr_err("%s: could not allocate proximity input device\n", __func__); goto err_input_allocate_device_proximity; } input_set_drvdata(cm36686->proximity_input_dev, cm36686); cm36686->proximity_input_dev->name = "proximity_sensor"; input_set_capability(cm36686->proximity_input_dev, EV_ABS, ABS_DISTANCE); input_set_abs_params(cm36686->proximity_input_dev, ABS_DISTANCE, 0, 1, 0, 0); ret = input_register_device(cm36686->proximity_input_dev); if (ret < 0) { input_free_device(cm36686->proximity_input_dev); pr_err("[SENSOR] %s: could not register input device\n", __func__); goto err_input_register_device_proximity; } ret = sensors_create_symlink(&cm36686->proximity_input_dev->dev.kobj, cm36686->proximity_input_dev->name); if (ret < 0) { pr_err("[SENSOR] %s: create_symlink error\n", __func__); goto err_sensors_create_symlink_prox; } ret = sysfs_create_group(&cm36686->proximity_input_dev->dev.kobj, &proximity_attribute_group); if (ret) { pr_err("[SENSOR] %s: could not create sysfs group\n", __func__); goto err_sysfs_create_group_proximity; } /* setup irq */ ret = cm36686_setup_irq(cm36686); if (ret) { pr_err("%s: could not setup irq\n", __func__); goto err_setup_irq; } /* For factory test mode, we use timer to get average proximity data. */ /* prox_timer settings. we poll for light values using a timer. */ hrtimer_init(&cm36686->prox_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cm36686->prox_poll_delay = ns_to_ktime(2000 * NSEC_PER_MSEC);/*2 sec*/ cm36686->prox_timer.function = cm36686_prox_timer_func; /* the timer just fires off a work queue request. we need a thread to read the i2c (can be slow and blocking). */ cm36686->prox_wq = create_singlethread_workqueue("cm36686_prox_wq"); if (!cm36686->prox_wq) { ret = -ENOMEM; pr_err("[SENSOR] %s: could not create prox workqueue\n", __func__); goto err_create_prox_workqueue; } /* this is the thread function we run on the work queue */ INIT_WORK(&cm36686->work_prox, cm36686_work_func_prox); /* allocate lightsensor input_device */ cm36686->light_input_dev = input_allocate_device(); if (!cm36686->light_input_dev) { pr_err("%s: could not allocate light input device\n", __func__); goto err_input_allocate_device_light; } input_set_drvdata(cm36686->light_input_dev, cm36686); cm36686->light_input_dev->name = "light_sensor"; input_set_capability(cm36686->light_input_dev, EV_REL, REL_MISC); input_set_capability(cm36686->light_input_dev, EV_REL, REL_DIAL); input_set_capability(cm36686->light_input_dev, EV_REL, REL_WHEEL); ret = input_register_device(cm36686->light_input_dev); if (ret < 0) { input_free_device(cm36686->light_input_dev); pr_err("%s: could not register input device\n", __func__); goto err_input_register_device_light; } ret = sensors_create_symlink(&cm36686->light_input_dev->dev.kobj, cm36686->light_input_dev->name); if (ret < 0) { pr_err("[SENSOR] %s: create_symlink error\n", __func__); goto err_sensors_create_symlink_light; } ret = sysfs_create_group(&cm36686->light_input_dev->dev.kobj, &light_attribute_group); if (ret) { pr_err("[SENSOR] %s: could not create sysfs group\n", __func__); goto err_sysfs_create_group_light; } /* light_timer settings. we poll for light values using a timer. */ hrtimer_init(&cm36686->light_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cm36686->light_poll_delay = ns_to_ktime(200 * NSEC_PER_MSEC); cm36686->light_timer.function = cm36686_light_timer_func; /* the timer just fires off a work queue request. we need a thread to read the i2c (can be slow and blocking). */ cm36686->light_wq = create_singlethread_workqueue("cm36686_light_wq"); if (!cm36686->light_wq) { ret = -ENOMEM; pr_err("[SENSOR] %s: could not create light workqueue\n", __func__); goto err_create_light_workqueue; } /* this is the thread function we run on the work queue */ INIT_WORK(&cm36686->work_light, cm36686_work_func_light); /* set sysfs for proximity sensor */ ret = sensors_register(cm36686->proximity_dev, cm36686, prox_sensor_attrs, "proximity_sensor"); if (ret) { pr_err("[SENSOR] %s: cound not register\ proximity sensor device(%d).\n", __func__, ret); goto prox_sensor_register_failed; } /* set sysfs for light sensor */ ret = sensors_register(cm36686->light_dev, cm36686, light_sensor_attrs, "light_sensor"); if (ret) { pr_err("[SENSOR] %s: cound not register\ light sensor device(%d).\n", __func__, ret); goto light_sensor_register_failed; } pr_info("[SENSOR] %s is success.\n", __func__); goto done; err_devicetree: printk("\n error in device tree"); /* error, unwind it all */ light_sensor_register_failed: sensors_unregister(cm36686->proximity_dev, prox_sensor_attrs); prox_sensor_register_failed: destroy_workqueue(cm36686->light_wq); err_create_light_workqueue: sysfs_remove_group(&cm36686->light_input_dev->dev.kobj, &light_attribute_group); err_sysfs_create_group_light: sensors_remove_symlink(&cm36686->light_input_dev->dev.kobj, cm36686->light_input_dev->name); err_sensors_create_symlink_light: input_unregister_device(cm36686->light_input_dev); err_input_register_device_light: err_input_allocate_device_light: destroy_workqueue(cm36686->prox_wq); err_create_prox_workqueue: free_irq(cm36686->irq, cm36686); gpio_free(cm36686->pdata->irq); err_setup_irq: sysfs_remove_group(&cm36686->proximity_input_dev->dev.kobj, &proximity_attribute_group); err_sysfs_create_group_proximity: sensors_remove_symlink(&cm36686->proximity_input_dev->dev.kobj, cm36686->proximity_input_dev->name); err_sensors_create_symlink_prox: input_unregister_device(cm36686->proximity_input_dev); err_input_register_device_proximity: err_input_allocate_device_proximity: err_setup_reg: #if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO) cm36686_leden_gpio_onoff(cm36686, 0); gpio_free(cm36686->pdata->leden_gpio); err_setup_leden_gpio: #else prox_led_onoff(cm36686, 0); #endif wake_lock_destroy(&cm36686->prx_wake_lock); mutex_destroy(&cm36686->read_lock); mutex_destroy(&cm36686->power_lock); kfree(cm36686); prox_regulator_onoff(&client->dev,0); done: return ret; }
static int cm36686_i2c_remove(struct i2c_client *client) { struct cm36686_data *cm36686 = i2c_get_clientdata(client); /* free irq */ if (cm36686->power_state & PROXIMITY_ENABLED) { disable_irq_wake(cm36686->irq); disable_irq(cm36686->irq); } free_irq(cm36686->irq, cm36686); gpio_free(cm36686->pdata->irq); /* device off */ if (cm36686->power_state & LIGHT_ENABLED) cm36686_light_disable(cm36686); if (cm36686->power_state & PROXIMITY_ENABLED) { cm36686_i2c_write_word(cm36686, REG_PS_CONF1, 0x0001); if (cm36686->pdata->cm36686_led_on) cm36686->pdata->cm36686_led_on(false); if (cm36686->cm36686_light_vddpower) cm36686->cm36686_light_vddpower(false); if (cm36686->cm36686_proxi_vddpower) cm36686->cm36686_proxi_vddpower(false); } /* destroy workqueue */ destroy_workqueue(cm36686->light_wq); destroy_workqueue(cm36686->prox_wq); /* sysfs destroy */ device_remove_file(cm36686->light_dev, &dev_attr_name); device_remove_file(cm36686->light_dev, &dev_attr_vendor); device_remove_file(cm36686->light_dev, &dev_attr_raw_data); device_remove_file(cm36686->light_dev, &dev_attr_lux); sensors_classdev_unregister(cm36686->light_dev); device_remove_file(cm36686->proximity_dev, &dev_attr_name); device_remove_file(cm36686->proximity_dev, &dev_attr_vendor); device_remove_file(cm36686->proximity_dev, &dev_attr_thresh_high); device_remove_file(cm36686->proximity_dev, &dev_attr_thresh_low); device_remove_file(cm36686->proximity_dev, &dev_attr_prox_avg); #ifdef CM36686_CANCELATION device_remove_file(cm36686->proximity_dev, &dev_attr_prox_cal); device_remove_file(cm36686->proximity_dev, &dev_attr_prox_offset_pass); #endif device_remove_file(cm36686->proximity_dev, &attr_prox_raw); device_remove_file(cm36686->proximity_dev, &dev_attr_state); sensors_classdev_unregister(cm36686->proximity_dev); /* input device destroy */ sysfs_remove_group(&cm36686->light_input_dev->dev.kobj, &light_attribute_group); input_unregister_device(cm36686->light_input_dev); sysfs_remove_group(&cm36686->proximity_input_dev->dev.kobj, &proximity_attribute_group); input_unregister_device(cm36686->proximity_input_dev); /* lock destroy */ mutex_destroy(&cm36686->read_lock); mutex_destroy(&cm36686->power_lock); wake_lock_destroy(&cm36686->prx_wake_lock); kfree(cm36686); return 0; }
static int cm36686_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = -ENODEV; struct cm36686_data *cm36686 = NULL; pr_info("%s is called.\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { pr_err("%s: i2c functionality check failed!\n", __func__); return ret; } cm36686 = kzalloc(sizeof(struct cm36686_data), GFP_KERNEL); if (!cm36686) { pr_err("%s: failed to alloc memory for cm36686 module data\n", __func__); return -ENOMEM; } cm36686->pdata = client->dev.platform_data; cm36686->i2c_client = client; i2c_set_clientdata(client, cm36686); mutex_init(&cm36686->power_lock); mutex_init(&cm36686->read_lock); if(cm36686->pdata->cm36686_light_power != NULL) { cm36686->cm36686_light_vddpower = cm36686->pdata->cm36686_light_power; if (cm36686->cm36686_light_vddpower) cm36686->cm36686_light_vddpower(true); } if(cm36686->pdata->cm36686_proxi_power != NULL) { cm36686->cm36686_proxi_vddpower = cm36686->pdata->cm36686_proxi_power; if (cm36686->cm36686_proxi_vddpower) cm36686->cm36686_proxi_vddpower(true); } /* wake lock init for proximity sensor */ wake_lock_init(&cm36686->prx_wake_lock, WAKE_LOCK_SUSPEND, "prx_wake_lock"); if (cm36686->pdata->cm36686_led_on) { cm36686->pdata->cm36686_led_on(true); msleep(20); } /* Check if the device is there or not. */ ret = cm36686_i2c_write_word(cm36686, REG_CS_CONF1, 0x0001); if (ret < 0) { pr_err("%s: cm36686 is not connected.(%d)\n", __func__, ret); goto err_setup_reg; } /* setup initial registers */ ret = cm36686_setup_reg(cm36686); if (ret < 0) { pr_err("%s: could not setup regs\n", __func__); goto err_setup_reg; } if (cm36686->pdata->cm36686_led_on) cm36686->pdata->cm36686_led_on(false); if (cm36686->cm36686_light_vddpower) cm36686->cm36686_light_vddpower(false); if (cm36686->cm36686_proxi_vddpower) cm36686->cm36686_proxi_vddpower(false); /* allocate proximity input_device */ cm36686->proximity_input_dev = input_allocate_device(); if (!cm36686->proximity_input_dev) { pr_err("%s: could not allocate proximity input device\n", __func__); goto err_input_allocate_device_proximity; } input_set_drvdata(cm36686->proximity_input_dev, cm36686); cm36686->proximity_input_dev->name = "proximity_sensor"; input_set_capability(cm36686->proximity_input_dev, EV_ABS, ABS_DISTANCE); input_set_abs_params(cm36686->proximity_input_dev, ABS_DISTANCE, 0, 1, 0, 0); ret = input_register_device(cm36686->proximity_input_dev); if (ret < 0) { input_free_device(cm36686->proximity_input_dev); pr_err("%s: could not register input device\n", __func__); goto err_input_register_device_proximity; } ret = sysfs_create_group(&cm36686->proximity_input_dev->dev.kobj, &proximity_attribute_group); if (ret) { pr_err("%s: could not create sysfs group\n", __func__); goto err_sysfs_create_group_proximity; } #if defined(CONFIG_SENSOR_USE_SYMLINK) ret = sensors_initialize_symlink(cm36686->proximity_input_dev); if (ret < 0) { pr_err("%s - proximity_sensors_initialize_symlink error(%d).\n", __func__, ret); goto err_setup_irq; } #endif /* setup irq */ ret = cm36686_setup_irq(cm36686); if (ret) { pr_err("%s: could not setup irq\n", __func__); goto err_setup_irq; } /* For factory test mode, we use timer to get average proximity data. */ /* prox_timer settings. we poll for light values using a timer. */ hrtimer_init(&cm36686->prox_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cm36686->prox_poll_delay = ns_to_ktime(2000 * NSEC_PER_MSEC);/*2 sec*/ cm36686->prox_timer.function = cm36686_prox_timer_func; /* the timer just fires off a work queue request. we need a thread to read the i2c (can be slow and blocking). */ cm36686->prox_wq = create_singlethread_workqueue("cm36686_prox_wq"); if (!cm36686->prox_wq) { ret = -ENOMEM; pr_err("%s: could not create prox workqueue\n", __func__); goto err_create_prox_workqueue; } /* this is the thread function we run on the work queue */ INIT_WORK(&cm36686->work_prox, cm36686_work_func_prox); /* allocate lightsensor input_device */ cm36686->light_input_dev = input_allocate_device(); if (!cm36686->light_input_dev) { pr_err("%s: could not allocate light input device\n", __func__); goto err_input_allocate_device_light; } input_set_drvdata(cm36686->light_input_dev, cm36686); cm36686->light_input_dev->name = "light_sensor"; input_set_capability(cm36686->light_input_dev, EV_REL, REL_MISC); input_set_capability(cm36686->light_input_dev, EV_REL, REL_DIAL); input_set_capability(cm36686->light_input_dev, EV_REL, REL_WHEEL); ret = input_register_device(cm36686->light_input_dev); if (ret < 0) { input_free_device(cm36686->light_input_dev); pr_err("%s: could not register input device\n", __func__); goto err_input_register_device_light; } ret = sysfs_create_group(&cm36686->light_input_dev->dev.kobj, &light_attribute_group); if (ret) { pr_err("%s: could not create sysfs group\n", __func__); goto err_sysfs_create_group_light; } #if defined(CONFIG_SENSOR_USE_SYMLINK) ret = sensors_initialize_symlink(cm36686->light_input_dev); if (ret < 0) { pr_err("%s - light_sensors_initialize_symlink error(%d).\n", __func__, ret); goto err_create_light_workqueue; } #endif /* light_timer settings. we poll for light values using a timer. */ hrtimer_init(&cm36686->light_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cm36686->light_poll_delay = ns_to_ktime(200 * NSEC_PER_MSEC); cm36686->light_timer.function = cm36686_light_timer_func; /* the timer just fires off a work queue request. we need a thread to read the i2c (can be slow and blocking). */ cm36686->light_wq = create_singlethread_workqueue("cm36686_light_wq"); if (!cm36686->light_wq) { ret = -ENOMEM; pr_err("%s: could not create light workqueue\n", __func__); goto err_create_light_workqueue; } /* this is the thread function we run on the work queue */ INIT_WORK(&cm36686->work_light, cm36686_work_func_light); /* set sysfs for proximity sensor */ cm36686->proximity_dev = sensors_classdev_register("proximity_sensor"); if (IS_ERR(cm36686->proximity_dev)) { pr_err("%s: could not create proximity_dev\n", __func__); goto err_proximity_device_create; } if (device_create_file(cm36686->proximity_dev, &dev_attr_state) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_state.attr.name); goto err_proximity_device_create_file1; } if (device_create_file(cm36686->proximity_dev, &attr_prox_raw) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, attr_prox_raw.attr.name); goto err_proximity_device_create_file2; } #ifdef CM36686_CANCELATION if (device_create_file(cm36686->proximity_dev, &dev_attr_prox_cal) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_prox_cal.attr.name); goto err_proximity_device_create_file3; } if (device_create_file(cm36686->proximity_dev, &dev_attr_prox_offset_pass) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_prox_offset_pass.attr.name); goto err_proximity_device_create_file4; } #endif if (device_create_file(cm36686->proximity_dev, &dev_attr_prox_avg) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_prox_avg.attr.name); goto err_proximity_device_create_file5; } if (device_create_file(cm36686->proximity_dev, &dev_attr_thresh_high) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_thresh_high.attr.name); goto err_proximity_device_create_file6; } if (device_create_file(cm36686->proximity_dev, &dev_attr_vendor) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_vendor.attr.name); goto err_proximity_device_create_file7; } if (device_create_file(cm36686->proximity_dev, &dev_attr_name) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_name.attr.name); goto err_proximity_device_create_file8; } if (device_create_file(cm36686->proximity_dev, &dev_attr_thresh_low) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_thresh_low.attr.name); goto err_proximity_device_create_file9; } dev_set_drvdata(cm36686->proximity_dev, cm36686); /* set sysfs for light sensor */ cm36686->light_dev = sensors_classdev_register("light_sensor"); if (IS_ERR(cm36686->light_dev)) { pr_err("%s: could not create light_dev\n", __func__); goto err_light_device_create; } if (device_create_file(cm36686->light_dev, &dev_attr_lux) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_lux.attr.name); goto err_light_device_create_file1; } if (device_create_file(cm36686->light_dev, &dev_attr_raw_data) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_raw_data.attr.name); goto err_light_device_create_file2; } if (device_create_file(cm36686->light_dev, &dev_attr_vendor) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_vendor.attr.name); goto err_light_device_create_file3; } if (device_create_file(cm36686->light_dev, &dev_attr_name) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_name.attr.name); goto err_light_device_create_file4; } dev_set_drvdata(cm36686->light_dev, cm36686); pr_info("%s is success.\n", __func__); goto done; /* error, unwind it all */ err_light_device_create_file4: device_remove_file(cm36686->light_dev, &dev_attr_vendor); err_light_device_create_file3: device_remove_file(cm36686->light_dev, &dev_attr_raw_data); err_light_device_create_file2: device_remove_file(cm36686->light_dev, &dev_attr_lux); err_light_device_create_file1: sensors_classdev_unregister(cm36686->light_dev); err_light_device_create: device_remove_file(cm36686->proximity_dev, &dev_attr_thresh_low); err_proximity_device_create_file9: device_remove_file(cm36686->proximity_dev, &dev_attr_name); err_proximity_device_create_file8: device_remove_file(cm36686->proximity_dev, &dev_attr_vendor); err_proximity_device_create_file7: device_remove_file(cm36686->proximity_dev, &dev_attr_thresh_high); err_proximity_device_create_file6: device_remove_file(cm36686->proximity_dev, &dev_attr_prox_avg); err_proximity_device_create_file5: #ifdef CM36686_CANCELATION device_remove_file(cm36686->proximity_dev, &dev_attr_prox_offset_pass); err_proximity_device_create_file4: device_remove_file(cm36686->proximity_dev, &dev_attr_prox_cal); err_proximity_device_create_file3: #endif device_remove_file(cm36686->proximity_dev, &attr_prox_raw); err_proximity_device_create_file2: device_remove_file(cm36686->proximity_dev, &dev_attr_state); err_proximity_device_create_file1: sensors_classdev_unregister(cm36686->proximity_dev); err_proximity_device_create: destroy_workqueue(cm36686->light_wq); err_create_light_workqueue: sysfs_remove_group(&cm36686->light_input_dev->dev.kobj, &light_attribute_group); err_sysfs_create_group_light: input_unregister_device(cm36686->light_input_dev); err_input_register_device_light: err_input_allocate_device_light: destroy_workqueue(cm36686->prox_wq); err_create_prox_workqueue: free_irq(cm36686->irq, cm36686); gpio_free(cm36686->pdata->irq); err_setup_irq: sysfs_remove_group(&cm36686->proximity_input_dev->dev.kobj, &proximity_attribute_group); err_sysfs_create_group_proximity: input_unregister_device(cm36686->proximity_input_dev); err_input_register_device_proximity: err_input_allocate_device_proximity: err_setup_reg: if (cm36686->pdata->cm36686_led_on) cm36686->pdata->cm36686_led_on(false); if (cm36686->cm36686_light_vddpower) cm36686->cm36686_light_vddpower(false); if (cm36686->cm36686_proxi_vddpower) cm36686->cm36686_proxi_vddpower(false); wake_lock_destroy(&cm36686->prx_wake_lock); mutex_destroy(&cm36686->read_lock); mutex_destroy(&cm36686->power_lock); kfree(cm36686); done: return ret; }