From bdb64beb2b3182ded6b4df3c700b2fae2c5650ef Mon Sep 17 00:00:00 2001 From: Truong Ta Xuan Date: Sun, 19 Jan 2014 08:15:49 +0700 Subject: Fix proximity sensor for GT-N5100 Change-Id: Ic5542259e9ff91ba20216844cf8a65f4a252c111 --- drivers/sensor/gp2a_proximity.c | 763 ++++++++++++++++++++++------------------ 1 file changed, 418 insertions(+), 345 deletions(-) (limited to 'drivers') diff --git a/drivers/sensor/gp2a_proximity.c b/drivers/sensor/gp2a_proximity.c index 7efbf3e..c1624e6 100644 --- a/drivers/sensor/gp2a_proximity.c +++ b/drivers/sensor/gp2a_proximity.c @@ -47,8 +47,6 @@ #define VENDOR "SHARP" #define CHIP_ID "GP2AP" -#define OFFSET_FILE_PATH "/efs/prox_cal" - #if 1 #define gprintk(fmt, x...) printk(KERN_INFO "%s(%d): "\ fmt, __func__ , __LINE__, ## x) @@ -56,17 +54,31 @@ fmt, __func__ , __LINE__, ## x) #define gprintk(x...) do { } while (0) #endif /**************************************************/ -#if defined(CONFIG_MACH_BAFFIN) -#define PROX_READ_NUM 20 +/* Calibration*/ +#define GP2A_CALIBRATION +#ifdef GP2A_CALIBRATION +#ifdef CONFIG_SLP +#define CALIBRATION_FILE_PATH "/csa/sensor/prox_cal_data" #else -#define PROX_READ_NUM 40 +#define CALIBRATION_FILE_PATH "/efs/prox_cal" +#endif +#endif +#if defined(CONFIG_MACH_KONA_SENSOR) +#define DEFAULT_THRESHOLD_DIFF 2 +#else +#define DEFAULT_THRESHOLD_DIFF 1 #endif +#define PROX_READ_NUM 40 #define PS_LOW_THD_L 0x08 #define PS_LOW_THD_H 0x09 #define PS_HIGH_THD_L 0x0A #define PS_HIGH_THD_H 0x0B +#if defined(CONFIG_MACH_KONA_SENSOR) +#define XTALK 8 +#define THDL 10 +#endif /* global var */ static struct i2c_driver opt_i2c_driver; static struct i2c_client *opt_i2c_client; @@ -85,17 +97,17 @@ struct gp2a_data { struct hrtimer prox_timer; struct workqueue_struct *prox_wq; struct work_struct work_prox; - int enabled; int proximity_data; int irq; int average[3]; /*for proximity adc average */ ktime_t prox_poll_delay; - - /* Auto Calibration */ - int offset_value; - int cal_result; - uint16_t threshold_high; - bool offset_cal_high; + u8 enabled; + u8 thresh_diff; + u8 power_state; +#ifdef GP2A_CALIBRATION + u8 default_threshold; + u8 cal_data; +#endif }; /* initial value for sensor register */ @@ -113,13 +125,17 @@ static u8 gp2a_original_image_030a[COL][2] = { /* {0x05 , 0x00}, */ /* {0x06 , 0xFF}, */ /* {0x07 , 0xFF}, */ -#if defined(CONFIG_MACH_BAFFIN) - {0x08, 0x08}, +#if defined(CONFIG_MACH_KONA_SENSOR) + {0x08, 0x08}, /*PS mode LTH(Loff): (??mm) */ #else - {0x08, 0x09}, /*PS mode LTH(Loff): (??mm) */ + {0x08, 0x09}, /*PS mode LTH(Loff): (??mm) */ #endif {0x09, 0x00}, /*PS mode LTH(Loff) : */ - {0x0A, 0x0A}, /*PS mode HTH(Lon) : (??mm) */ +#if defined(CONFIG_MACH_KONA_SENSOR) + {0x0A, 0x0A}, /*PS mode HTH(Lon) : (??mm) */ +#else + {0x0A, 0x0A}, /*PS mode HTH(Lon) : (??mm) */ +#endif {0x0B, 0x00}, /* PS mode HTH(Lon) : */ /* {0x13 , 0x08}, by sharp for internal calculation (type:0) */ /*alternating mode (PS+ALS), TYPE=1 @@ -150,27 +166,22 @@ static u8 gp2a_original_image[COL][2] = { {0x00, 0xC0} }; -#define THR_REG_LSB(data, reg) \ - { \ - reg = (u8)data & 0xff; \ - } -#define THR_REG_MSB(data, reg) \ - { \ - reg = (u8)data >> 8; \ - } - static int proximity_onoff(u8 onoff); +#ifdef GP2A_CALIBRATION +static int proximity_open_calibration(struct gp2a_data *data); +#endif int is_gp2a030a(void) { -#if defined(CONFIG_MACH_C1) || \ - defined(CONFIG_MACH_M0) || \ - defined(CONFIG_MACH_GRANDE) || \ +#if defined(CONFIG_MACH_GRANDE) || \ defined(CONFIG_MACH_IRON) return (system_rev != 0 && system_rev != 3); #endif -#if defined(CONFIG_MACH_M3) || \ - defined(CONFIG_MACH_BAFFIN) +#if defined(CONFIG_MACH_M3_USA_TMO) || \ + defined(CONFIG_MACH_BAFFIN) || \ + defined(CONFIG_MACH_KONA_SENSOR) ||\ + defined(CONFIG_MACH_TAB3) ||\ + defined(CONFIG_MACH_GC2PD) return 1; #endif #if defined(CONFIG_MACH_REDWOOD) @@ -180,17 +191,23 @@ int is_gp2a030a(void) return 0; } -static int gp2a_update_threshold(u8 (*selected_image)[2], - unsigned long new_threshold, bool update_reg) +static int gp2a_update_threshold(struct gp2a_data *data, + u8 (*selected_image)[2], u8 new_threshold, bool update_reg) { int i, err = 0; u8 set_value; + pr_info("%s, new = 0x%x, thresh_diff = %d\n", __func__, + new_threshold, data->thresh_diff); for (i = 0; i < COL; i++) { switch (selected_image[i][0]) { case PS_LOW_THD_L: /*PS mode LTH(Loff) for low 8bit*/ +#if defined(CONFIG_MACH_KONA_SENSOR) + set_value = (new_threshold-data->thresh_diff) & 0x00FF; +#else set_value = new_threshold & 0x00FF; +#endif break; case PS_LOW_THD_H: @@ -200,12 +217,17 @@ static int gp2a_update_threshold(u8 (*selected_image)[2], case PS_HIGH_THD_L: /*PS mode HTH(Lon) for low 8bit*/ - set_value = (new_threshold+1) & 0x00FF; +#if defined(CONFIG_MACH_KONA_SENSOR) + set_value = (new_threshold) & 0x00FF; +#else + set_value = (new_threshold+data->thresh_diff) & 0x00FF; +#endif break; case PS_HIGH_THD_H: /* PS mode HTH(Lon) for high 8bit*/ - set_value = ((new_threshold+1) & 0xFF00) >> 8; + set_value = ((new_threshold + +data->thresh_diff) & 0xFF00) >> 8; break; default: @@ -219,238 +241,14 @@ static int gp2a_update_threshold(u8 (*selected_image)[2], pr_err("%s : setting error i = %d, err=%d\n", __func__, i, err); return err; - } else - selected_image[i][1] = set_value; - } - - return err; -} - -static int proximity_adc_read(struct gp2a_data *data) -{ - int sum[OFFSET_ARRAY_LENGTH]; - int i = OFFSET_ARRAY_LENGTH-1; - int avg; - int min; - int max; - int total; - int D2_data; - unsigned char get_D2_data[2]; - - mutex_lock(&data->data_mutex); - do { - msleep(50); - opt_i2c_read(DATA2_LSB, get_D2_data, sizeof(get_D2_data)); - D2_data = (get_D2_data[1] << 8) | get_D2_data[0]; - sum[i] = D2_data; - if (i == 0) { - min = sum[i]; - max = sum[i]; } else { - if (sum[i] < min) - min = sum[i]; - else if (sum[i] > max) - max = sum[i]; + selected_image[i][1] = set_value; } - total += sum[i]; - } while (i--); - mutex_unlock(&data->data_mutex); - - total -= (min + max); - avg = (int)(total / (OFFSET_ARRAY_LENGTH - 2)); - pr_info("%s: offset = %d\n", __func__, avg); - - return avg; -} - - -static int proximity_open_calibration(struct gp2a_data *data) -{ - struct file *cal_filp = NULL; - int err = 0; - mm_segment_t old_fs; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cal_filp = filp_open(OFFSET_FILE_PATH, - O_RDONLY, S_IRUGO | S_IWUSR | S_IWGRP); - - if (IS_ERR(cal_filp)) { - pr_err("%s: Can't open calibration file\n", __func__); - set_fs(old_fs); - err = PTR_ERR(cal_filp); - goto done; } - err = cal_filp->f_op->read(cal_filp, - (char *)&data->offset_value, - sizeof(int), &cal_filp->f_pos); - if (err != sizeof(int)) { - pr_err("%s: Can't read the cal data from file\n", __func__); - err = -EIO; - } - - pr_info("%s: (%d)\n", __func__, - data->offset_value); - - filp_close(cal_filp, current->files); -done: - set_fs(old_fs); return err; } -static int proximity_do_calibrate(struct gp2a_data *data, - bool do_calib, bool thresh_set) -{ - struct file *cal_filp; - int err; - int xtalk_avg = 0; - int offset_change = 0; - uint16_t thrd = 0; - u8 reg; - mm_segment_t old_fs; - - u8 (*cal_image)[2] = (is_gp2a030a() ? - gp2a_original_image_030a : gp2a_original_image); - - if (do_calib) { - if (thresh_set) { - /* for proximity_thresh_store */ - data->offset_value = - data->threshold_high - - (cal_image[6][1] << 8 | cal_image[5][1]); - } else { - /* tap offset button */ - /* get offset value */ - xtalk_avg = proximity_adc_read(data); - offset_change = - (cal_image[6][1] << 8 | cal_image[5][1]) - - DEFAULT_HI_THR; - if (xtalk_avg < offset_change) { - /* do not need calibration */ - data->cal_result = 0; - err = 0; - goto no_cal; - } - data->offset_value = xtalk_avg - offset_change; - } - /* update threshold */ - thrd = (cal_image[4][1] << 8 | cal_image[3][1]) - + (data->offset_value); - THR_REG_LSB(thrd, reg); - opt_i2c_write(cal_image[3][0], ®); - THR_REG_MSB(thrd, reg); - opt_i2c_write(cal_image[4][0], ®); - - thrd = (cal_image[4][1] << 8 | cal_image[5][1]) - +(data->offset_value); - THR_REG_LSB(thrd, reg); - opt_i2c_write(cal_image[5][0], ®); - THR_REG_MSB(thrd, reg); - opt_i2c_write(cal_image[6][0], ®); - - /* calibration result */ - if (!thresh_set) - data->cal_result = 1; - } else { - /* tap reset button */ - data->offset_value = 0; - /* update threshold */ - opt_i2c_write(cal_image[3][0], &cal_image[3][1]); - opt_i2c_write(cal_image[4][0], &cal_image[4][1]); - opt_i2c_write(cal_image[5][0], &cal_image[5][1]); - opt_i2c_write(cal_image[6][0], &cal_image[6][1]); - /* calibration result */ - data->cal_result = 2; - } - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cal_filp = filp_open(OFFSET_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, - S_IRUGO | S_IWUSR | S_IWGRP); - - if (IS_ERR(cal_filp)) { - pr_err("%s: Can't open calibration file\n", __func__); - set_fs(old_fs); - err = PTR_ERR(cal_filp); - goto done; - } - - err = cal_filp->f_op->write(cal_filp, - (char *)&data->offset_value, sizeof(int), - &cal_filp->f_pos); - if (err != sizeof(int)) { - pr_err("%s: Can't write the cal data to file\n", __func__); - err = -EIO; - } - - filp_close(cal_filp, current->files); -done: - set_fs(old_fs); -no_cal: - return err; -} - -static int proximity_manual_offset(struct gp2a_data *data, u8 change_on) -{ - struct file *cal_filp; - int err; - int16_t thrd; - u8 reg; - mm_segment_t old_fs; - - u8 (*manual_image)[2] = (is_gp2a030a() ? - gp2a_original_image_030a : gp2a_original_image); - - data->offset_value = change_on; - /* update threshold */ - thrd = manual_image[3][1]+(data->offset_value); - THR_REG_LSB(thrd, reg); - opt_i2c_write(manual_image[3][0], ®); - THR_REG_MSB(thrd, reg); - opt_i2c_write(manual_image[4][0], ®); - - thrd = manual_image[5][1]+(data->offset_value); - THR_REG_LSB(thrd, reg); - opt_i2c_write(manual_image[5][0], ®); - THR_REG_MSB(thrd, reg); - opt_i2c_write(manual_image[6][0], ®); - - /* calibration result */ - data->cal_result = 1; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cal_filp = filp_open(OFFSET_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, - S_IRUGO | S_IWUSR | S_IWGRP); - - if (IS_ERR(cal_filp)) { - pr_err("%s: Can't open calibration file\n", __func__); - set_fs(old_fs); - err = PTR_ERR(cal_filp); - goto done; - } - - err = cal_filp->f_op->write(cal_filp, - (char *)&data->offset_value, sizeof(int), - &cal_filp->f_pos); - if (err != sizeof(int)) { - pr_err("%s: Can't write the cal data to file\n", __func__); - err = -EIO; - } - - filp_close(cal_filp, current->files); -done: - set_fs(old_fs); - return err; -} - - /* Proximity Sysfs interface */ static ssize_t proximity_enable_show(struct device *dev, @@ -477,28 +275,63 @@ proximity_enable_store(struct device *dev, err = kstrtoint(buf, 10, &value); if (err) - printk(KERN_ERR "%s, kstrtoint failed.", __func__); + pr_err("%s, kstrtoint failed.", __func__); if (value != 0 && value != 1) return count; gprintk("value = %d\n", value); - if (data->enabled && !value) { /* Proximity power off */ + if (data->enabled && !value) { /* proximity disable */ disable_irq(data->irq); - proximity_enable = value; + data->enabled = 0; proximity_onoff(0); disable_irq_wake(data->irq); - data->pdata->gp2a_led_on(false); - } else if (!data->enabled && value) { /* proximity power on */ - data->pdata->gp2a_led_on(true); - /*msleep(1); */ - proximity_enable = value; + /* proximity power off */ + if (data->pdata->gp2a_led_on + && data->power_state) { + data->pdata->gp2a_led_on(false); + data->power_state = 0; + } + +#ifdef CONFIG_SENSORS_GP2A_VDD_CONTROL + /* gp2a vdd power off */ + if (data->pdata->gp2a_vdd_on + && !(data->enabled & LIGHT_ENABLED)) { + data->pdata->gp2a_vdd_on(false); + data->power_state &= ~LIGHT_ENABLED; + } +#endif + } else if (!(data->enabled) && value) { /* proximity enable */ + /* proximity power on */ + if (data->pdata->gp2a_led_on + && !(data->power_state)) { + data->pdata->gp2a_led_on(true); + data->power_state = 1; + } + +#ifdef CONFIG_SENSORS_GP2A_VDD_CONTROL + /* gp2a vdd power on */ + if (data->pdata->gp2a_vdd_on + && !(data->power_state & LIGHT_ENABLED)) { + data->pdata->gp2a_vdd_on(true); + data->power_state |= LIGHT_ENABLED; + } +#endif + + /*msleep(1); */ +#ifdef GP2A_CALIBRATION + /* open cancelation data */ + err = proximity_open_calibration(data); + if (err < 0 && err != -ENOENT) + pr_err("%s: proximity_open_calibration() failed\n", + __func__); +#endif + data->enabled = 1; proximity_onoff(1); enable_irq_wake(data->irq); - msleep(160); input = gpio_get_value(data->pdata->p_out); input_report_abs(data->input_dev, ABS_DISTANCE, input); @@ -506,7 +339,6 @@ proximity_enable_store(struct device *dev, enable_irq(data->irq); } - data->enabled = value; return count; } @@ -515,8 +347,6 @@ static ssize_t proximity_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct gp2a_data *data = dev_get_drvdata(dev); - static int count; /*count for proximity average */ - int D2_data = 0; unsigned char get_D2_data[2] = { 0, }; @@ -525,12 +355,7 @@ static ssize_t proximity_state_show(struct device *dev, mutex_unlock(&data->data_mutex); D2_data = (get_D2_data[1] << 8) | get_D2_data[0]; - data->average[count] = D2_data; - count++; - if (count == PROX_READ_NUM) - count = 0; - pr_debug("%s: D2_data = %d\n", __func__, D2_data); - return snprintf(buf, PAGE_SIZE, "%d\n", D2_data); + return sprintf(buf, "%d\n", D2_data); } static ssize_t proximity_avg_show(struct device *dev, @@ -559,7 +384,7 @@ static ssize_t proximity_avg_store(struct device *dev, } if (new_value && !proximity_avg_on) { - if (!(proximity_enable)) { + if (!(data->enabled)) { /*data->pdata->gp2a_led_on(true);*/ proximity_onoff(1); } @@ -573,7 +398,7 @@ static ssize_t proximity_avg_store(struct device *dev, hrtimer_cancel(&data->prox_timer); proximity_avg_on = 0; - if (!(proximity_enable)) { + if (!(data->enabled)) { proximity_onoff(0); /*data->pdata->gp2a_led_on(false);*/ } @@ -589,7 +414,7 @@ static ssize_t proximity_thresh_show(struct device *dev, struct device_attribute *attr, char *buf) { int i; - int threshold = 0; + u8 threshold = 0; u8 (*selected_image)[2] = (is_gp2a030a() ? gp2a_original_image_030a : gp2a_original_image); @@ -609,10 +434,11 @@ static ssize_t proximity_thresh_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - unsigned long threshold; + struct gp2a_data *data = dev_get_drvdata(dev); + u8 threshold = 0; int err = 0; - err = strict_strtoul(buf, 10, &threshold); + err = kstrtou8(buf, 10, &threshold); if (err) { pr_err("%s, conversion %s to number.\n", @@ -620,7 +446,7 @@ static ssize_t proximity_thresh_store(struct device *dev, return err; } - err = gp2a_update_threshold(is_gp2a030a() ? + err = gp2a_update_threshold(data, is_gp2a030a() ? gp2a_original_image_030a : gp2a_original_image, threshold, true); @@ -632,53 +458,262 @@ static ssize_t proximity_thresh_store(struct device *dev, return size; } +#ifdef GP2A_CALIBRATION +static u8 proximity_adc_read(struct gp2a_data *gp2a) +{ + int adc_arr[OFFSET_ARRAY_LENGTH]; + int total = 0, min = 0, max = 0; + u8 avg = 0; + int D2_data = 0; + unsigned char get_D2_data[2] = {0,}; + int i; + + for (i = 0; i < OFFSET_ARRAY_LENGTH; i++) { + mdelay(50); + mutex_lock(&gp2a->data_mutex); + opt_i2c_read(0x10, get_D2_data, sizeof(get_D2_data)); + mutex_unlock(&gp2a->data_mutex); + D2_data = (get_D2_data[1] << 8) | get_D2_data[0]; + adc_arr[i] = D2_data; + if (i == 0) { + min = adc_arr[i]; + max = adc_arr[i]; + } else { + if (adc_arr[i] < min) + min = adc_arr[i]; + else if (adc_arr[i] > max) + max = adc_arr[i]; + } + total += adc_arr[i]; + } + + total -= (min + max); + avg = (u8)(total / (OFFSET_ARRAY_LENGTH - 2)); + pr_info("%s: offset = %d\n", __func__, avg); + + return avg; +} + +static int proximity_open_calibration(struct gp2a_data *data) +{ + struct file *cancel_filp = NULL; + int err = 0; + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cancel_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cancel_filp)) { + err = PTR_ERR(cancel_filp); + if (err != -ENOENT) + pr_err("%s: Can't open cancelation file\n", __func__); + set_fs(old_fs); + return err; + } + + err = cancel_filp->f_op->read(cancel_filp, + (char *)&data->cal_data, sizeof(u8), &cancel_filp->f_pos); + if (err != sizeof(u8)) { + pr_err("%s: Can't read the cancel data from file\n", __func__); + err = -EIO; + } + + if (data->cal_data != 0) {/*If there is an offset cal data. */ +#if defined(CONFIG_MACH_KONA_SENSOR) + if (is_gp2a030a()) { + gp2a_original_image_030a[5][1] = + data->default_threshold + data->cal_data; + gp2a_original_image_030a[3][1] = + data->default_threshold + + data->cal_data - DEFAULT_THRESHOLD_DIFF; + } +#else + if (is_gp2a030a()) + gp2a_original_image_030a[3][1] = + data->default_threshold + data->cal_data; + +#endif + else + gp2a_original_image[3][1] = + data->default_threshold + data->cal_data; + + pr_info("%s: prox_cal = %d, prox_thresh = 0x%x\n", + __func__, data->cal_data, (is_gp2a030a() ? + gp2a_original_image_030a[3][1] : + gp2a_original_image[3][1])); + } + + filp_close(cancel_filp, current->files); + set_fs(old_fs); + + return err; +} + +static int proximity_store_calibration(struct device *dev, bool do_calib) +{ + struct gp2a_data *gp2a = dev_get_drvdata(dev); + struct file *cancel_filp = NULL; + mm_segment_t old_fs; + int err = 0; + u8 thresh_x; + + if (do_calib) { + gp2a->cal_data = proximity_adc_read(gp2a); + if (is_gp2a030a()) { +#if defined(CONFIG_MACH_KONA_SENSOR) + gp2a_original_image_030a[3][1] = gp2a->cal_data+XTALK; + gp2a->cal_data = gp2a_original_image_030a[3][1]-THDL; +#else + /* if x-talk + 8 > threshold, threhold = x-talk + 8 */ + /* LTH = threshold - thresh_diff */ + thresh_x = gp2a->cal_data + 8 - gp2a->thresh_diff; + + if (thresh_x > gp2a_original_image_030a[3][1]) + gp2a_original_image_030a[3][1]= thresh_x; +#endif + } + else + gp2a_original_image[3][1] += gp2a->cal_data; + } else { /* reset */ + gp2a->cal_data = 0; + if (is_gp2a030a()) + gp2a_original_image_030a[3][1] = + gp2a->default_threshold; + else + gp2a_original_image[3][1] = gp2a->default_threshold; + } + + /* Update cal data. */ + gp2a_update_threshold(gp2a, is_gp2a030a() ? + gp2a_original_image_030a : gp2a_original_image, + (is_gp2a030a() ? + gp2a_original_image_030a[3][1] : + gp2a_original_image[3][1]), true); + + pr_info("%s: prox_cal = %d, prox_thresh = 0x%x\n", + __func__, gp2a->cal_data, (is_gp2a030a() ? + gp2a_original_image_030a[3][1] : + gp2a_original_image[3][1])); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cancel_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); + if (IS_ERR(cancel_filp)) { + pr_err("%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 *)&gp2a->cal_data, sizeof(u8), &cancel_filp->f_pos); + if (err != sizeof(u8)) { + 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); + + return err; +} + static ssize_t proximity_cal_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct gp2a_data *data = dev_get_drvdata(dev); - int thresh_hi; - unsigned char get_D2_data[2]; - - msleep(20); - opt_i2c_read(PS_HT_LSB, get_D2_data, sizeof(get_D2_data)); - thresh_hi = (get_D2_data[1] << 8) | get_D2_data[0]; - data->threshold_high = thresh_hi; - return sprintf(buf, "%d,%d\n", - data->offset_value, data->threshold_high); +#if defined(CONFIG_MACH_KONA_SENSOR) + return sprintf(buf, "%d,%d\n", data->cal_data, + gp2a_original_image_030a[5][1]); +#else + return sprintf(buf, "%d,%d\n", data->cal_data, (is_gp2a030a() ? + gp2a_original_image_030a[5][1] : + gp2a_original_image[5][1])); +#endif } static ssize_t proximity_cal_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) + struct device_attribute *attr, + const char *buf, size_t size) { - struct gp2a_data *data = dev_get_drvdata(dev); bool do_calib; int err; - if (sysfs_streq(buf, "1")) { /* calibrate cancelation value */ + if (sysfs_streq(buf, "1")) /* calibrate cancelation value */ do_calib = true; - } else if (sysfs_streq(buf, "0")) { /* reset cancelation value */ + else if (sysfs_streq(buf, "0")) /* reset cancelation value */ do_calib = false; - } else { + else { pr_err("%s: invalid value %d\n", __func__, *buf); - err = -EINVAL; - goto done; + return -EINVAL; } - err = proximity_do_calibrate(data, do_calib, false); + + err = proximity_store_calibration(dev, do_calib); if (err < 0) { - pr_err("%s: proximity_store_offset() failed\n", __func__); - goto done; + pr_err("%s: proximity_store_calibration() failed\n", __func__); + return err; } -done: - return err; + + return size; } +static ssize_t proximity_thresh_diff_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gp2a_data *gp2a = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", gp2a->thresh_diff); +} + +static ssize_t proximity_thresh_diff_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct gp2a_data *gp2a = dev_get_drvdata(dev); + struct gp2a_platform_data *pdata = gp2a->pdata; + u8 threshold_diff = 0; + int err; + + err = kstrtou8(buf, 10, &threshold_diff); + if (err) { + pr_err("%s, conversion %s to number.\n", + __func__, buf); + return err; + } + + if ((threshold_diff > 0) && (threshold_diff < 5)) { /* update diff */ + gp2a->thresh_diff = threshold_diff; + } else if (threshold_diff == 0) { /* reset to default */ + pdata->gp2a_get_threshold(&gp2a->thresh_diff); + } else { + pr_err("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + gp2a_update_threshold(gp2a, is_gp2a030a() ? + gp2a_original_image_030a : gp2a_original_image, + (is_gp2a030a() ? + gp2a_original_image_030a[3][1] : + gp2a_original_image[3][1]), true); + + return size; +} +#endif + static DEVICE_ATTR(enable, 0664, proximity_enable_show, proximity_enable_store); static DEVICE_ATTR(prox_avg, 0664, proximity_avg_show, proximity_avg_store); static DEVICE_ATTR(state, 0664, proximity_state_show, NULL); -static DEVICE_ATTR(prox_thresh, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(prox_thresh, 0664, proximity_thresh_show, proximity_thresh_store); -static DEVICE_ATTR(prox_cal, 0664, proximity_cal_show, proximity_cal_store); +#ifdef GP2A_CALIBRATION +static DEVICE_ATTR(prox_cal, 0664, + proximity_cal_show, proximity_cal_store); +static DEVICE_ATTR(prox_diff, 0664, + proximity_thresh_diff_show, proximity_thresh_diff_store); +#endif static struct attribute *proximity_attributes[] = { &dev_attr_enable.attr, @@ -715,7 +750,6 @@ static ssize_t proximity_raw_data_show(struct device *dev, unsigned char get_D2_data[2] = { 0, }; struct gp2a_data *data = dev_get_drvdata(dev); - msleep(20); mutex_lock(&data->data_mutex); opt_i2c_read(0x10, get_D2_data, sizeof(get_D2_data)); mutex_unlock(&data->data_mutex); @@ -735,11 +769,10 @@ static void proxsensor_get_avgvalue(struct gp2a_data *data) u8 proximity_value = 0; unsigned char get_D2_data[2] = { 0, }; - mutex_lock(&data->data_mutex); - for (i = 0; i < PROX_READ_NUM; i++) { - msleep(20); + mutex_lock(&data->data_mutex); opt_i2c_read(0x10, get_D2_data, sizeof(get_D2_data)); + mutex_unlock(&data->data_mutex); proximity_value = (get_D2_data[1] << 8) | get_D2_data[0]; avg += proximity_value; @@ -751,7 +784,6 @@ static void proxsensor_get_avgvalue(struct gp2a_data *data) if (proximity_value > max) max = proximity_value; } - mutex_unlock(&data->data_mutex); avg /= PROX_READ_NUM; data->average[0] = min; @@ -901,7 +933,7 @@ static void gp2a_work_func_prox(struct work_struct *work) static int opt_i2c_init(void) { if (i2c_add_driver(&opt_i2c_driver)) { - printk(KERN_ERR "i2c_add_driver failed\n"); + pr_info("i2c_add_driver failed\n"); return -ENODEV; } return 0; @@ -911,16 +943,13 @@ int opt_i2c_read(u8 reg, unsigned char *rbuf, int len) { int ret = -1; struct i2c_msg msg; - /*int i;*/ if ((opt_i2c_client == NULL) || (!opt_i2c_client->adapter)) { - printk(KERN_ERR "%s %d (opt_i2c_client == NULL)\n", + pr_err("%s %d (opt_i2c_client == NULL)\n", __func__, __LINE__); return -ENODEV; } - /*gprintk("register num : 0x%x\n", reg); */ - msg.addr = opt_i2c_client->addr; msg.flags = I2C_M_WR; msg.len = 1; @@ -936,12 +965,9 @@ int opt_i2c_read(u8 reg, unsigned char *rbuf, int len) } if (ret < 0) - printk(KERN_ERR "%s, i2c transfer error ret=%d\n"\ + pr_err("%s, i2c transfer error ret=%d\n"\ , __func__, ret); - /* for (i=0;i= 0) return 0; } - printk(KERN_ERR "%s, i2c transfer error(%d)\n", __func__, err); + pr_err("%s, i2c transfer error(%d)\n", __func__, err); return err; } @@ -982,7 +1008,7 @@ static int proximity_input_init(struct gp2a_data *data) data->input_dev = input_allocate_device(); if (!data->input_dev) { - printk(KERN_ERR "%s, error\n", __func__); + pr_err("%s, error\n", __func__); return -ENOMEM; } @@ -1021,14 +1047,9 @@ static int gp2a_opt_probe(struct platform_device *pdev) return err; } /* gp2a power on */ +#if !defined(CONFIG_MACH_TAB3) || !defined(CONFIG_MACH_GC2PD) pdata->gp2a_led_on(true); - - if (pdata->gp2a_get_threshold) { - gp2a_update_threshold(is_gp2a030a() ? - gp2a_original_image_030a : gp2a_original_image, - pdata->gp2a_get_threshold(), false); - } - +#endif /* allocate driver_data */ gp2a = kzalloc(sizeof(struct gp2a_data), GFP_KERNEL); if (!gp2a) { @@ -1036,10 +1057,35 @@ static int gp2a_opt_probe(struct platform_device *pdev) return -ENOMEM; } - proximity_enable = 0; +#ifdef CONFIG_SLP + gp2a->thresh_diff = DEFAULT_THRESHOLD_DIFF; +#endif +#if defined(CONFIG_MACH_KONA_SENSOR) + gp2a->thresh_diff = DEFAULT_THRESHOLD_DIFF; +#else + if (pdata->gp2a_get_threshold) + gp2a_update_threshold(gp2a, is_gp2a030a() ? + gp2a_original_image_030a : gp2a_original_image, + pdata->gp2a_get_threshold(&gp2a->thresh_diff), false); + else + gp2a->thresh_diff = DEFAULT_THRESHOLD_DIFF; +#endif +#ifdef GP2A_CALIBRATION +#if defined(CONFIG_MACH_KONA_SENSOR) + gp2a->default_threshold = (is_gp2a030a() ? + gp2a_original_image_030a[5][1] : + gp2a_original_image[5][1]); +#else + gp2a->default_threshold = (is_gp2a030a() ? + gp2a_original_image_030a[3][1] : + gp2a_original_image[3][1]); +#endif +#endif + + gp2a->enabled = 0; + proximity_sensor_detection = 0; proximity_avg_on = 0; - gp2a->enabled = 0; gp2a->pdata = pdata; /* prox_timer settings. we poll for prox_avg values using a timer. */ @@ -1082,9 +1128,19 @@ static int gp2a_opt_probe(struct platform_device *pdev) pr_err("opt_probe failed : i2c_client is NULL\n"); goto err_no_device; } else - printk(KERN_INFO "opt_i2c_client : (0x%p), address = %x\n", + pr_info("opt_i2c_client : (0x%p), address = %x\n", opt_i2c_client, opt_i2c_client->addr); +#ifdef CONFIG_SENSORS_GP2A_VDD_CONTROL + /* gp2a power on */ + if (pdata->gp2a_vdd_on) { + pdata->gp2a_vdd_on(true); + pr_info("%s, power : %d\n", __func__, gp2a-->power_state); + } + gp2a->power_state |= LIGHT_ENABLED; + msleep(20); +#endif + /* GP2A Regs INIT SETTINGS and Check I2C communication */ value = 0x00; /* shutdown mode op[3]=0 */ @@ -1148,12 +1204,20 @@ static int gp2a_opt_probe(struct platform_device *pdev) goto err_proximity_device_create_file6; } +#ifdef GP2A_CALIBRATION if (device_create_file(gp2a->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_file7; } + if (device_create_file(gp2a->proximity_dev, &dev_attr_prox_diff) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_prox_diff.attr.name); + goto err_proximity_device_create_file8; + } +#endif + #ifdef CONFIG_SLP device_init_wakeup(gp2a->proximity_dev, true); #endif @@ -1165,14 +1229,18 @@ static int gp2a_opt_probe(struct platform_device *pdev) return 0; -err_proximity_device_create_file7: +#ifdef GP2A_CALIBRATION +err_proximity_device_create_file8: device_remove_file(gp2a->proximity_dev, &dev_attr_prox_cal); -err_proximity_device_create_file6: +err_proximity_device_create_file7: device_remove_file(gp2a->proximity_dev, &dev_attr_raw_data); -err_proximity_device_create_file5: +#endif +err_proximity_device_create_file6: device_remove_file(gp2a->proximity_dev, &dev_attr_name); -err_proximity_device_create_file4: +err_proximity_device_create_file5: device_remove_file(gp2a->proximity_dev, &dev_attr_vendor); +err_proximity_device_create_file4: + device_remove_file(gp2a->proximity_dev, &dev_attr_prox_thresh); err_proximity_device_create_file3: device_remove_file(gp2a->proximity_dev, &dev_attr_prox_avg); err_proximity_device_create_file2: @@ -1201,19 +1269,20 @@ static int gp2a_opt_remove(struct platform_device *pdev) struct gp2a_data *gp2a = platform_get_drvdata(pdev); if (gp2a == NULL) { - printk(KERN_ERR "%s, gp2a_data is NULL!!!!!\n", __func__); + pr_err("%s, gp2a_data is NULL!!!!!\n", __func__); return -1; } if (gp2a->enabled) { disable_irq(gp2a->irq); - proximity_enable = 0; + gp2a->enabled = 0; + proximity_onoff(0); disable_irq_wake(gp2a->irq); -#ifndef CONFIG_MACH_MIDAS_02_BD +#if !defined(CONFIG_MACH_MIDAS_02_BD) gp2a->pdata->gp2a_led_on(false); + gp2a->power_state = 0; #endif - gp2a->enabled = 0; } hrtimer_cancel(&gp2a->prox_timer); @@ -1228,6 +1297,10 @@ static int gp2a_opt_remove(struct platform_device *pdev) device_remove_file(gp2a->proximity_dev, &dev_attr_vendor); device_remove_file(gp2a->proximity_dev, &dev_attr_name); device_remove_file(gp2a->proximity_dev, &dev_attr_raw_data); +#ifdef GP2A_CALIBRATION + device_remove_file(gp2a->proximity_dev, &dev_attr_prox_cal); + device_remove_file(gp2a->proximity_dev, &dev_attr_prox_diff); +#endif sensors_classdev_unregister(gp2a->proximity_dev); if (gp2a->input_dev != NULL) { @@ -1274,6 +1347,7 @@ static int gp2a_opt_resume(struct platform_device *pdev) gprintk("\n"); if (gp2a->enabled) { + if (device_may_wakeup(&pdev->dev)) enable_irq_wake(gp2a->irq); } @@ -1308,8 +1382,7 @@ static int proximity_onoff(u8 onoff) opt_i2c_write(gp2a_original_image[i][0], &gp2a_original_image[i][1]); if (err < 0) - printk(KERN_ERR - "%s : turnning on error i = %d, err=%d\n", + pr_err("%s : turnning on error i = %d, err=%d\n", __func__, i, err); lightsensor_mode = 0; } @@ -1342,7 +1415,7 @@ static int opt_i2c_probe(struct i2c_client *client, gprintk("start!!!\n"); if (client == NULL) - printk(KERN_ERR "GP2A i2c client is NULL !!!\n"); + pr_err("GP2A i2c client is NULL !!!\n"); opt_i2c_client = client; gprintk("end!!!\n"); -- cgit v1.1