aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sensor
diff options
context:
space:
mode:
authorDaniel Hillenbrand <codeworkx@cyanogenmod.org>2013-06-18 17:55:27 +0200
committerDaniel Hillenbrand <codeworkx@cyanogenmod.org>2013-06-18 17:55:27 +0200
commit855d6a6c1f7c54ef073caac3f6c5f9b1ed72eb4d (patch)
tree89b8db35d4eb326263a0f9827c5186467d6d289e /drivers/sensor
parenta8c0a4a5b062a56e5494894aa86b89a21a86ea3e (diff)
downloadkernel_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.c22
-rw-r--r--drivers/sensor/gp2a_light.c9
-rw-r--r--drivers/sensor/gp2a_proximity.c324
-rw-r--r--drivers/sensor/k3dh.c4
-rw-r--r--drivers/sensor/sensors_core.c45
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], &reg);
+ THR_REG_MSB(thrd, reg);
+ opt_i2c_write(cal_image[4][0], &reg);
+
+ 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], &reg);
+ THR_REG_MSB(thrd, reg);
+ opt_i2c_write(cal_image[6][0], &reg);
+
+ /* 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], &reg);
+ THR_REG_MSB(thrd, reg);
+ opt_i2c_write(manual_image[4][0], &reg);
+
+ thrd = manual_image[5][1]+(data->offset_value);
+ THR_REG_LSB(thrd, reg);
+ opt_i2c_write(manual_image[5][0], &reg);
+ THR_REG_MSB(thrd, reg);
+ opt_i2c_write(manual_image[6][0], &reg);
+
+ /* 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");