diff options
author | Daniel Hillenbrand <codeworkx@cyanogenmod.org> | 2013-06-18 17:55:27 +0200 |
---|---|---|
committer | Daniel Hillenbrand <codeworkx@cyanogenmod.org> | 2013-06-18 17:55:27 +0200 |
commit | 855d6a6c1f7c54ef073caac3f6c5f9b1ed72eb4d (patch) | |
tree | 89b8db35d4eb326263a0f9827c5186467d6d289e /drivers/sensor | |
parent | a8c0a4a5b062a56e5494894aa86b89a21a86ea3e (diff) | |
download | kernel_samsung_smdk4412-855d6a6c1f7c54ef073caac3f6c5f9b1ed72eb4d.zip kernel_samsung_smdk4412-855d6a6c1f7c54ef073caac3f6c5f9b1ed72eb4d.tar.gz kernel_samsung_smdk4412-855d6a6c1f7c54ef073caac3f6c5f9b1ed72eb4d.tar.bz2 |
u1: port sensors and modem interface from smdk4210 kernel
Change-Id: Ifa0a332a0413f4ceb3c70e96573786ae576a2ae0
Diffstat (limited to 'drivers/sensor')
-rw-r--r-- | drivers/sensor/ak8963.c | 22 | ||||
-rw-r--r-- | drivers/sensor/gp2a_light.c | 9 | ||||
-rw-r--r-- | drivers/sensor/gp2a_proximity.c | 324 | ||||
-rw-r--r-- | drivers/sensor/k3dh.c | 4 | ||||
-rw-r--r-- | drivers/sensor/sensors_core.c | 45 |
5 files changed, 396 insertions, 8 deletions
diff --git a/drivers/sensor/ak8963.c b/drivers/sensor/ak8963.c index 674deee..8b4e2a5 100644 --- a/drivers/sensor/ak8963.c +++ b/drivers/sensor/ak8963.c @@ -27,7 +27,8 @@ #include "ak8963-reg.h" #include <linux/sensor/sensors_core.h> -#if defined(CONFIG_SLP) || defined(CONFIG_MACH_GC1) +#if defined(CONFIG_SLP) || defined(CONFIG_MACH_GC1)\ + || defined(CONFIG_MACH_M3_USA_TMO) #define FACTORY_TEST #else #undef FACTORY_TEST @@ -369,7 +370,9 @@ static int ak8963c_selftest(struct akm8963_data *ak_data, int *sf) { u8 buf[6]; s16 x, y, z; + int retry_count = 0; +retry: /* read device info */ i2c_smbus_read_i2c_block_data(ak_data->this_client, AK8963_REG_WIA, 2, buf); @@ -437,10 +440,21 @@ static int ak8963c_selftest(struct akm8963_data *ak_data, int *sf) if (((x >= -200) && (x <= 200)) && ((y >= -200) && (y <= 200)) && - ((z >= -3200) && (z <= -800))) + ((z >= -3200) && (z <= -800))) { + pr_info("%s, Selftest is successful.\n", __func__); return 1; - else - return 0; + } else { + if (retry_count < 5) { + retry_count++; + pr_warn("############################################"); + pr_warn("%s, retry_count=%d\n", __func__, retry_count); + pr_warn("############################################"); + goto retry; + } else { + pr_err("%s, Selftest is failed.\n", __func__); + return 0; + } + } } static ssize_t ak8963c_get_asa(struct device *dev, diff --git a/drivers/sensor/gp2a_light.c b/drivers/sensor/gp2a_light.c index e8828eb..406b522 100644 --- a/drivers/sensor/gp2a_light.c +++ b/drivers/sensor/gp2a_light.c @@ -49,6 +49,7 @@ #define SENSOR_NAME "light_sensor" #define SENSOR_MAX_DELAY (2000) /* 2000 ms */ + #define LIGHT_BUFFER_NUM 5 struct sensor_data { @@ -121,8 +122,11 @@ light_delay_store(struct device *dev, struct device_attribute *attr, if (delay < 0) return count; - delay = delay / 1000000; /* ns to msec */ +#ifdef CONFIG_MACH_BAFFIN + delay = delay / 100; +#endif + gprintk("new_delay = %d, old_delay = %d", delay, data->delay); @@ -587,7 +591,8 @@ static void gp2a_work_func_light(struct work_struct *work) if (data->light_buffer == i) { if (data->light_count++ == LIGHT_BUFFER_NUM) { - input_report_rel(data->input_dev, REL_MISC, adc); + input_report_rel(data->input_dev, REL_MISC, + (adc ? adc : 1)); input_sync(data->input_dev); data->light_count = 0; } diff --git a/drivers/sensor/gp2a_proximity.c b/drivers/sensor/gp2a_proximity.c index 012d8b8..7efbf3e 100644 --- a/drivers/sensor/gp2a_proximity.c +++ b/drivers/sensor/gp2a_proximity.c @@ -47,6 +47,8 @@ #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) @@ -54,7 +56,11 @@ fmt, __func__ , __LINE__, ## x) #define gprintk(x...) do { } while (0) #endif /**************************************************/ +#if defined(CONFIG_MACH_BAFFIN) +#define PROX_READ_NUM 20 +#else #define PROX_READ_NUM 40 +#endif #define PS_LOW_THD_L 0x08 #define PS_LOW_THD_H 0x09 @@ -72,6 +78,7 @@ static char proximity_avg_on; struct gp2a_data { struct input_dev *input_dev; struct work_struct work; /* for proximity sensor */ + struct mutex data_mutex; struct device *proximity_dev; struct gp2a_platform_data *pdata; struct wake_lock prx_wake_lock; @@ -83,6 +90,12 @@ struct gp2a_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; }; /* initial value for sensor register */ @@ -100,7 +113,11 @@ static u8 gp2a_original_image_030a[COL][2] = { /* {0x05 , 0x00}, */ /* {0x06 , 0xFF}, */ /* {0x07 , 0xFF}, */ +#if defined(CONFIG_MACH_BAFFIN) + {0x08, 0x08}, +#else {0x08, 0x09}, /*PS mode LTH(Loff): (??mm) */ +#endif {0x09, 0x00}, /*PS mode LTH(Loff) : */ {0x0A, 0x0A}, /*PS mode HTH(Lon) : (??mm) */ {0x0B, 0x00}, /* PS mode HTH(Lon) : */ @@ -133,6 +150,15 @@ 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); int is_gp2a030a(void) @@ -200,6 +226,231 @@ static int gp2a_update_threshold(u8 (*selected_image)[2], 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]; + } + 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, @@ -263,14 +514,23 @@ proximity_enable_store(struct device *dev, 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, }; - msleep(20); + mutex_lock(&data->data_mutex); opt_i2c_read(0x10, get_D2_data, sizeof(get_D2_data)); + mutex_unlock(&data->data_mutex); D2_data = (get_D2_data[1] << 8) | get_D2_data[0]; - return sprintf(buf, "%d\n", D2_data); + 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); } static ssize_t proximity_avg_show(struct device *dev, @@ -372,11 +632,53 @@ static ssize_t proximity_thresh_store(struct device *dev, return size; } +static ssize_t proximity_cal_show(struct device *dev, + 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); +} + +static ssize_t proximity_cal_store(struct device *dev, + 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 */ + do_calib = true; + } else if (sysfs_streq(buf, "0")) { /* reset cancelation value */ + do_calib = false; + } else { + pr_err("%s: invalid value %d\n", __func__, *buf); + err = -EINVAL; + goto done; + } + err = proximity_do_calibrate(data, do_calib, false); + if (err < 0) { + pr_err("%s: proximity_store_offset() failed\n", __func__); + goto done; + } +done: + return err; +} + 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, proximity_thresh_show, proximity_thresh_store); +static DEVICE_ATTR(prox_cal, 0664, proximity_cal_show, proximity_cal_store); static struct attribute *proximity_attributes[] = { &dev_attr_enable.attr, @@ -411,9 +713,12 @@ static ssize_t proximity_raw_data_show(struct device *dev, { int D2_data = 0; 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); D2_data = (get_D2_data[1] << 8) | get_D2_data[0]; return sprintf(buf, "%d\n", D2_data); @@ -430,6 +735,8 @@ 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); opt_i2c_read(0x10, get_D2_data, sizeof(get_D2_data)); @@ -444,6 +751,7 @@ 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; @@ -761,6 +1069,8 @@ static int gp2a_opt_probe(struct platform_device *pdev) /* set platdata */ platform_set_drvdata(pdev, gp2a); + mutex_init(&gp2a->data_mutex); + /* wake lock init */ wake_lock_init(&gp2a->prx_wake_lock, WAKE_LOCK_SUSPEND, "prx_wake_lock"); @@ -838,6 +1148,12 @@ static int gp2a_opt_probe(struct platform_device *pdev) goto err_proximity_device_create_file6; } + 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; + } + #ifdef CONFIG_SLP device_init_wakeup(gp2a->proximity_dev, true); #endif @@ -849,6 +1165,8 @@ static int gp2a_opt_probe(struct platform_device *pdev) return 0; +err_proximity_device_create_file7: + device_remove_file(gp2a->proximity_dev, &dev_attr_prox_cal); err_proximity_device_create_file6: device_remove_file(gp2a->proximity_dev, &dev_attr_raw_data); err_proximity_device_create_file5: @@ -868,6 +1186,7 @@ err_no_device: sysfs_remove_group(&gp2a->input_dev->dev.kobj, &proximity_attribute_group); wake_lock_destroy(&gp2a->prx_wake_lock); + mutex_destroy(&gp2a->data_mutex); err_sysfs_create_group_proximity: input_unregister_device(gp2a->input_dev); error_setup_reg: @@ -923,6 +1242,7 @@ static int gp2a_opt_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); free_irq(gp2a->irq, gp2a); gpio_free(gp2a->pdata->p_out); + mutex_destroy(&gp2a->data_mutex); kfree(gp2a); return 0; diff --git a/drivers/sensor/k3dh.c b/drivers/sensor/k3dh.c index 9010e0b..a44c30d 100644 --- a/drivers/sensor/k3dh.c +++ b/drivers/sensor/k3dh.c @@ -101,7 +101,11 @@ static int k3dh_read_accel_raw_xyz(struct k3dh_data *data, acc->y = (acc_data[3] << 8) | acc_data[2]; acc->z = (acc_data[5] << 8) | acc_data[4]; +#if defined(CONFIG_MACH_U1_NA_SPR) + acc->x = -acc->x >> 4; +#else acc->x = acc->x >> 4; +#endif acc->y = acc->y >> 4; #if defined(CONFIG_MACH_U1_NA_SPR_REV05) \ || defined(CONFIG_MACH_U1_NA_SPR_EPIC2_REV00) \ diff --git a/drivers/sensor/sensors_core.c b/drivers/sensor/sensors_core.c index a414492..e003652 100644 --- a/drivers/sensor/sensors_core.c +++ b/drivers/sensor/sensors_core.c @@ -26,6 +26,20 @@ struct class *sensors_class; * sensors_classdev_register - create new sensor device in sensors_class. * @dev: The device to register. */ + +static void set_sensor_attr(struct device *dev, + struct device_attribute *attributes[]) +{ + int i; + + for (i = 0; attributes[i] != NULL; i++) { + if ((device_create_file(dev, attributes[i])) < 0) { + printk(KERN_ERR"[SENSOR CORE] create_file attributes %d\n", + i); + } + } +} + struct device *sensors_classdev_register(char *sensors_name) { struct device *dev; @@ -51,6 +65,37 @@ void sensors_classdev_unregister(struct device *dev) } EXPORT_SYMBOL_GPL(sensors_classdev_unregister); +int sensors_register(struct device *dev, void *drvdata, + struct device_attribute *attributes[], char *name) +{ + int ret = 0; + if (!sensors_class) { + sensors_class = class_create(THIS_MODULE, "sensors"); + if (IS_ERR(sensors_class)) + return PTR_ERR(sensors_class); + } + + dev = device_create(sensors_class, NULL, 0, drvdata, "%s", name); + + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + printk(KERN_ERR "[SENSORS CORE] device_create failed! [%d]\n", + ret); + return ret; + } + + set_sensor_attr(dev, attributes); + + return 0; +} +EXPORT_SYMBOL_GPL(sensors_register); + +void sensors_unregister(struct device *dev) +{ + device_unregister(dev); +} +EXPORT_SYMBOL_GPL(sensors_unregister); + static int __init sensors_class_init(void) { sensors_class = class_create(THIS_MODULE, "sensors"); |