static int cm3663_setup_reg(struct cm3663_data *cm3663) { int err = 0; u8 tmp; /* initializing the proximity and light sensor registers */ mutex_lock(&cm3663->power_lock); cm3663->pdata->proximity_power(1); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_write(cm3663, REGS_INIT, reg_defaults[3]); cm3663_i2c_write(cm3663, REGS_PS_THD, reg_defaults[7]); cm3663_i2c_write(cm3663, REGS_PS_CMD, reg_defaults[5]); mutex_unlock(&cm3663->power_lock); /* printing the inital proximity value with no contact */ msleep(50); err = cm3663_i2c_read(cm3663, REGS_PS_DATA, &tmp); if (err < 0) { pr_err("%s: read ps_data failed\n", __func__); err = -EIO; } pr_err("%s: initial proximity value = %d\n", __func__, tmp); mutex_lock(&cm3663->power_lock); cm3663_i2c_write(cm3663, REGS_PS_CMD, 0x01); cm3663->pdata->proximity_power(0); mutex_unlock(&cm3663->power_lock); return err; }
static void cm3663_light_enable(struct cm3663_data *cm3663) { u8 tmp; cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_write(cm3663, REGS_INIT, reg_defaults[3]); cm3663_i2c_write(cm3663, REGS_ALS_CMD, reg_defaults[1]); hrtimer_start(&cm3663->light_timer, cm3663->light_poll_delay, HRTIMER_MODE_REL); }
static int lightsensor_get_alsvalue(struct cm3663_data *cm3663) { int value = 0; u8 als_high, als_low; /* get ALS */ cm3663_i2c_read(cm3663, REGS_ALS_LSB, &als_low); cm3663_i2c_read(cm3663, REGS_ALS_MSB, &als_high); value = ((als_high << 8) | als_low) * 5; return value; }
static int lightsensor_get_alsvalue(struct cm3663_data *cm3663) { int als_result = 0; u8 als_high, als_low; /* get ALS */ cm3663_i2c_read(cm3663, REGS_ALS_LSB, &als_low); cm3663_i2c_read(cm3663, REGS_ALS_MSB, &als_high); als_result = ((als_high << 8) | als_low); als_raw = als_result; return als_result * 5; }
static void cm3663_light_enable(struct cm3663_data *cm3663) { u8 tmp; #if defined(CONFIG_MACH_S2PLUS) printk(KERN_INFO "[%s]\n", __func__); #endif cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_write(cm3663, REGS_INIT, reg_defaults[3]); cm3663_i2c_write(cm3663, REGS_ALS_CMD, reg_defaults[1]); hrtimer_start(&cm3663->light_timer, cm3663->light_poll_delay, HRTIMER_MODE_REL); }
static ssize_t proximity_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct cm3663_data *cm3663 = dev_get_drvdata(dev); u8 proximity_value = 0; if (!(cm3663->power_state & PROXIMITY_ENABLED)) { mutex_lock(&cm3663->power_lock); cm3663->pdata->proximity_power(1); cm3663_i2c_write(cm3663, REGS_PS_CMD, reg_defaults[5]); mutex_unlock(&cm3663->power_lock); } msleep(20); cm3663_i2c_read(cm3663, REGS_PS_DATA, &proximity_value); if (!(cm3663->power_state & PROXIMITY_ENABLED)) { mutex_lock(&cm3663->power_lock); cm3663_i2c_write(cm3663, REGS_PS_CMD, 0x01); cm3663->pdata->proximity_power(0); mutex_unlock(&cm3663->power_lock); } return sprintf(buf, "%d", proximity_value); }
static void proxsensor_get_avgvalue(struct cm3663_data *cm3663) { int min = 0, max = 0, avg = 0; int i; u8 proximity_value = 0; for (i = 0; i < PROX_READ_NUM; i++) { msleep(40); cm3663_i2c_read(cm3663, REGS_PS_DATA, &proximity_value); avg += proximity_value; if (!i) min = proximity_value; else if (proximity_value < min) min = proximity_value; if (proximity_value > max) max = proximity_value; } avg /= PROX_READ_NUM; cm3663->avg[0] = min; cm3663->avg[1] = avg; cm3663->avg[2] = max; }
/* interrupt happened due to transition/change of near/far proximity state */ irqreturn_t cm3663_irq_thread_fn(int irq, void *data) { struct cm3663_data *ip = data; u8 val = 1; u8 tmp; printk(KERN_INFO "[CM3663] cm3663_irq_thread_fn called\n"); val = gpio_get_value(ip->i2c_client->irq); if (val < 0) { pr_err("%s: gpio_get_value error %d\n", __func__, val); return IRQ_HANDLED; } /* for debugging : going to be removed */ cm3663_i2c_read(ip, REGS_PS_DATA, &tmp); /* 0 is close, 1 is far */ input_report_abs(ip->proximity_input_dev, ABS_DISTANCE, val); input_sync(ip->proximity_input_dev); printk(KERN_INFO "[CM3663] proximity value = %d \n",val); wake_lock_timeout(&ip->prx_wake_lock, 3*HZ); return IRQ_HANDLED; }
static ssize_t proximity_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct cm3663_data *cm3663 = dev_get_drvdata(dev); bool new_value; u8 tmp; 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; } printk(KERN_INFO "[CM3663] proximity_enable_store : new_value=%d\n", new_value); mutex_lock(&cm3663->power_lock); if (new_value && !(cm3663->power_state & PROXIMITY_ENABLED)) { cm3663->pdata->proximity_power(1); cm3663->power_state |= PROXIMITY_ENABLED; input_report_abs(cm3663->proximity_input_dev, ABS_DISTANCE, 1); input_sync(cm3663->proximity_input_dev); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_write(cm3663, REGS_INIT, reg_defaults[3]); cm3663_i2c_write(cm3663, REGS_PS_THD, reg_defaults[7]); cm3663_i2c_write(cm3663, REGS_PS_CMD, reg_defaults[5]); enable_irq(cm3663->irq); } else if (!new_value && (cm3663->power_state & PROXIMITY_ENABLED)) { cm3663->power_state &= ~PROXIMITY_ENABLED; disable_irq(cm3663->irq); cm3663_i2c_write(cm3663, REGS_PS_CMD, 0x01); cm3663->pdata->proximity_power(0); } mutex_unlock(&cm3663->power_lock); return size; }
/* * sysfs interface * Turn on or off the proximity */ static ssize_t cm3663_proximity_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct cm3663_data *cm3663 = dev_get_drvdata(dev); int enable; if (strict_strtoul(buf, 10, &enable)) return -EINVAL; int enabled = (cm3663->power_state & PROXIMITY_ENABLED) >> 1; u8 tmp = 0; pr_info("[PROXIMITY] %s : new state(%d), old state(%d)\n", __func__, enable, enabled); if (enable == enabled) return size; mutex_lock(&cm3663->power_lock); if (enable) { if (!(cm3663->power_state)) { pr_info("\n proximity_power true\n"); cm3663->pdata->proximity_power(true); } cm3663->power_state |= PROXIMITY_ENABLED; cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_write(cm3663, REGS_INIT, reg_defaults[3]); cm3663_i2c_write(cm3663, REGS_PS_THD, reg_defaults[7]); cm3663_i2c_write(cm3663, REGS_PS_CMD, reg_defaults[5]); enable_irq(cm3663->irq); } else { disable_irq(cm3663->irq); cm3663_i2c_write(cm3663, REGS_PS_CMD, 0x01); cm3663->power_state &= ~PROXIMITY_ENABLED; if (!(cm3663->power_state)) pr_info("\n proximity_power false\n"); } mutex_unlock(&cm3663->power_lock); return size; }
static int cm3663_setup_reg(struct cm3663_data *cm3663) { int err = 0; u8 tmp; #ifdef CONFIG_TARGET_LOCALE_KOR if (system_rev <= 0x05) reg_defaults[PS_THD] = PS_THD_COMP1; /* PS_THD: 07 */ else reg_defaults[PS_THD] = PS_THD_COMP2; /* PS_THD: 10 */ #endif /* initializing the proximity and light sensor registers */ mutex_lock(&cm3663->power_lock); cm3663->pdata->proximity_power(1); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_write(cm3663, REGS_INIT, reg_defaults[3]); cm3663_i2c_write(cm3663, REGS_PS_THD, reg_defaults[7]); cm3663_i2c_write(cm3663, REGS_PS_CMD, reg_defaults[5]); mutex_unlock(&cm3663->power_lock); /* printing the inital proximity value with no contact */ msleep(50); err = cm3663_i2c_read(cm3663, REGS_PS_DATA, &tmp); if (err < 0) { pr_err("%s: read ps_data failed\n", __func__); err = -EIO; } pr_err("%s: initial proximity value = %d\n", __func__, tmp); mutex_lock(&cm3663->power_lock); cm3663_i2c_write(cm3663, REGS_PS_CMD, 0x01); cm3663->pdata->proximity_power(0); mutex_unlock(&cm3663->power_lock); return err; }
static int lightsensor_get_alsvalue(struct cm3663_data *cm3663) { int value = 0; u8 als_high, als_low; #ifdef CONFIG_TARGET_LOCALE_KOR /* Verify power state of light sensor */ if (!(cm3663->power_state & LIGHT_ENABLED)) { pr_err("%s: Light Sensor was disabled by logic, " "cm3663->power_state = 0x%x\n", __func__, cm3663->power_state); cm3663_light_enable(cm3663); cm3663->power_state |= LIGHT_ENABLED; } #endif /* get ALS */ cm3663_i2c_read(cm3663, REGS_ALS_LSB, &als_low); cm3663_i2c_read(cm3663, REGS_ALS_MSB, &als_high); value = ((als_high << 8) | als_low) * 5; return value; }
/* * probe function */ static int cm3663_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = -ENODEV; struct input_dev *input_dev; struct cm3663_data *cm3663; u8 tmp; int cnt = 3; int i = 0; int adc = sizeof(adc_step_table)/sizeof(int); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { pr_err("%s: i2c functionality check failed!\n", __func__); return ret; } cm3663 = kzalloc(sizeof(struct cm3663_data), GFP_KERNEL); if (!cm3663) { pr_err("%s: failed to alloc memory for module data\n", __func__); return -ENOMEM; } cm3663->pdata = client->dev.platform_data; cm3663->i2c_client = client; i2c_set_clientdata(client, cm3663); cm3663_gdata = cm3663; /* wake lock init */ wake_lock_init(&cm3663->prx_wake_lock, WAKE_LOCK_SUSPEND, "prx_wake_lock"); mutex_init(&cm3663->power_lock); ret = cm3663_setup_irq(cm3663); if (ret) { pr_err("%s: could not setup irq\n", __func__); goto err_setup_irq; } /* allocate proximity input_device */ input_dev = input_allocate_device(); if (!input_dev) { pr_err("%s: could not allocate input device\n", __func__); goto err_input_allocate_device_proximity; } cm3663->proximity_input_dev = input_dev; input_set_drvdata(input_dev, cm3663); input_dev->name = "proximity_sensor"; input_set_capability(input_dev, EV_ABS, ABS_DISTANCE); input_set_abs_params(input_dev, ABS_DISTANCE, 0, 1, 0, 0); ret = input_register_device(input_dev); if (ret < 0) { pr_err("%s: could not register input device\n", __func__); input_free_device(input_dev); goto err_input_register_device_proximity; } ret = sysfs_create_group(&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; } /* hrtimer settings. we poll for light values using a timer. */ hrtimer_init(&cm3663->light_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cm3663->light_poll_delay = ns_to_ktime(200 * NSEC_PER_MSEC); cm3663->light_timer.function = cm3663_light_timer_func; /* prox_timer settings. we poll for light values using a timer. */ hrtimer_init(&cm3663->prox_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cm3663->prox_poll_delay = ns_to_ktime(2000 * NSEC_PER_MSEC); cm3663->prox_timer.function = cm3663_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). */ cm3663->light_wq = create_singlethread_workqueue("cm3663_light_wq"); if (!cm3663->light_wq) { ret = -ENOMEM; pr_err("%s: could not create light workqueue\n", __func__); goto err_create_light_workqueue; } cm3663->prox_wq = create_singlethread_workqueue("cm3663_prox_wq"); if (!cm3663->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(&cm3663->work_light, cm3663_work_func_light); INIT_WORK(&cm3663->work_prox, cm3663_work_func_prox); /* allocate lightsensor-level input_device */ input_dev = input_allocate_device(); if (!input_dev) { pr_err("%s: could not allocate input device\n", __func__); ret = -ENOMEM; goto err_input_allocate_device_light; } input_set_drvdata(input_dev, cm3663); input_dev->name = "light_sensor"; input_set_capability(input_dev, EV_ABS, ABS_MISC); input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0); ret = input_register_device(input_dev); if (ret < 0) { pr_err("%s: could not register input device\n", __func__); input_free_device(input_dev); goto err_input_register_device_light; } cm3663->light_input_dev = input_dev; ret = sysfs_create_group(&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; } ret = sensors_register(cm3663->light_sensor_device, cm3663, additional_light_attrs, "light_sensor"); if (ret) { pr_err("%s: cound not register sensor device\n", __func__); goto err_sysfs_create_group_light; } ret = sensors_register(cm3663->proximity_sensor_device, cm3663, additional_proximity_attrs, "proximity_sensor"); if (ret) { pr_err("%s: cound not register sensor device\n", __func__); goto err_sysfs_create_group_light; } /* print inital proximity value with no contact */ mutex_lock(&cm3663->power_lock); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); do { ret = cm3663_i2c_write(cm3663, REGS_INIT, reg_defaults[3]); cnt--; if ((!cnt) && (ret < 0)) goto err_i2c_failed; } while (ret < 0); ret = 0; cm3663_i2c_write(cm3663, REGS_PS_THD, reg_defaults[7]); cm3663_i2c_write(cm3663, REGS_PS_CMD, reg_defaults[5]); msleep(100); cm3663_i2c_read(cm3663, REGS_PS_DATA, &tmp); pr_info("%s: initial proximity value = %d\n", __func__, tmp); cm3663_i2c_write(cm3663, REGS_PS_CMD, 0x01); mutex_unlock(&cm3663->power_lock); /* set initial proximity value as 1 */ input_report_abs(cm3663->proximity_input_dev, ABS_DISTANCE, 1); input_sync(cm3663->proximity_input_dev); pr_info("CM3663 probe ok!!!\n"); goto done; /* error, unwind it all */ err_i2c_failed: sysfs_remove_group(&cm3663->light_input_dev->dev.kobj, &light_attribute_group); err_sysfs_create_group_light: input_unregister_device(cm3663->light_input_dev); err_input_register_device_light: err_input_allocate_device_light: destroy_workqueue(cm3663->prox_wq); err_create_prox_workqueue: destroy_workqueue(cm3663->light_wq); err_create_light_workqueue: sysfs_remove_group(&cm3663->proximity_input_dev->dev.kobj, &proximity_attribute_group); err_sysfs_create_group_proximity: input_unregister_device(cm3663->proximity_input_dev); err_input_register_device_proximity: err_input_allocate_device_proximity: err_setup_irq: mutex_destroy(&cm3663->power_lock); wake_lock_destroy(&cm3663->prx_wake_lock); kfree(cm3663); pr_info("CM3663 probe fail!!!\n"); done: return ret; }
static ssize_t proximity_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct cm3663_data *cm3663 = dev_get_drvdata(dev); bool new_value; u8 tmp; #if defined(CONFIG_MACH_S2PLUS) u8 val = 1; #endif 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; } mutex_lock(&cm3663->power_lock); if (new_value && !(cm3663->power_state & PROXIMITY_ENABLED)) { cm3663->pdata->proximity_power(1); cm3663->power_state |= PROXIMITY_ENABLED; cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_write(cm3663, REGS_INIT, reg_defaults[3]); cm3663_i2c_write(cm3663, REGS_PS_THD, reg_defaults[7]); cm3663_i2c_write(cm3663, REGS_PS_CMD, reg_defaults[5]); #if defined(CONFIG_MACH_S2PLUS) /* report the first value */ val = gpio_get_value(cm3663->i2c_client->irq); if (val < 0) { pr_err("%s: gpio_get_value error %d\n", __func__, val); return IRQ_HANDLED; } cm3663_i2c_read(cm3663, REGS_PS_DATA, &tmp); printk(KERN_INFO "%s: proximity value = %d, val = %d\n", __func__, tmp, val); /* 0 is close, 1 is far */ input_report_abs(cm3663->proximity_input_dev, ABS_DISTANCE, val); input_sync(cm3663->proximity_input_dev); wake_lock_timeout(&cm3663->prx_wake_lock, 3*HZ); #endif enable_irq(cm3663->irq); enable_irq_wake(cm3663->irq); } else if (!new_value && (cm3663->power_state & PROXIMITY_ENABLED)) { cm3663->power_state &= ~PROXIMITY_ENABLED; disable_irq_wake(cm3663->irq); disable_irq(cm3663->irq); cm3663_i2c_write(cm3663, REGS_PS_CMD, 0x01); cm3663->pdata->proximity_power(0); } mutex_unlock(&cm3663->power_lock); return size; }