input: sensors: add sensors calibrate interface of sensors class

The sensors calibrate interface is a generic interface for sensor
calibrate. Add the interface for user space applications to calibrate
sensors. The interface can send the calibration data to userspace and
also get the calibration data form userspace to driver.

Change-Id: I156e1878f813e8ab0adfb3f2253cdd7fad65e55d
Signed-off-by: Daqing Chen <chendaqing@codeaurora.org>
This commit is contained in:
Daqing Chen 2014-07-30 14:12:01 +08:00
parent 179fd82ce5
commit 4736122663
2 changed files with 172 additions and 0 deletions

View File

@ -20,6 +20,72 @@
#include <linux/ctype.h>
#include <linux/rwsem.h>
#include <linux/sensors.h>
#include <linux/string.h>
#define APPLY_MASK 0x00000001
#define CMD_W_L_MASK 0x00
#define CMD_W_H_MASK 0x10
#define CMD_W_H_L 0x10
#define CMD_MASK 0xF
#define DATA_MASK 0xFFFF0000
#define DATA_AXIS_SHIFT 17
#define DATA_APPLY_SHIFT 16
/*
* CMD_GET_PARAMS(BIT, PARA, DATA) combine high 16 bit and low 16 bit
* as one params
*/
#define CMD_GET_PARAMS(BIT, PARA, DATA) \
((BIT) ? \
((DATA) & DATA_MASK) \
: ((PARA) \
| (((DATA) & DATA_MASK) >> 16)))
/*
* CMD_DO_CAL sensor do calibrate command, when do sensor calibrate must use
* this.
* AXIS_X,AXIS_Y,AXIS_Z write axis params to driver like accelerometer
* magnetometer,gyroscope etc.
* CMD_W_THRESHOLD_H,CMD_W_THRESHOLD_L,CMD_W_BIAS write theshold and bias
* params to proximity driver.
* CMD_W_FACTOR,CMD_W_OFFSET write factor and offset params to light
* sensor driver.
* CMD_COMPLETE when one sensor receive calibrate parameters complete, it
* must use this command to end receive the parameters and send the
* parameters to sensor.
*/
enum {
CMD_DO_CAL = 0x0,
CMD_W_OFFSET_X,
CMD_W_OFFSET_Y,
CMD_W_OFFSET_Z,
CMD_W_THRESHOLD_H,
CMD_W_THRESHOLD_L,
CMD_W_BIAS,
CMD_W_OFFSET,
CMD_W_FACTOR,
CMD_W_RANGE,
CMD_COMPLETE,
CMD_COUNT
};
int cal_map[] = {
0,
offsetof(struct cal_result_t, offset_x),
offsetof(struct cal_result_t, offset_y),
offsetof(struct cal_result_t, offset_z),
offsetof(struct cal_result_t, threshold_h),
offsetof(struct cal_result_t, threshold_l),
offsetof(struct cal_result_t, bias),
offsetof(struct cal_result_t, offset[0]),
offsetof(struct cal_result_t, offset[1]),
offsetof(struct cal_result_t, offset[2]),
offsetof(struct cal_result_t, factor),
offsetof(struct cal_result_t, range),
};
static struct class *sensors_class;
@ -283,6 +349,65 @@ static ssize_t sensors_flush_show(struct device *dev,
? "not exist" : "exist");
}
static ssize_t sensors_calibrate_show(struct device *dev,
struct device_attribute *atte, char *buf)
{
struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
if (sensors_cdev->params == NULL) {
dev_err(dev, "Invalid sensor params\n");
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE, "%s\n", sensors_cdev->params);
}
static ssize_t sensors_calibrate_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
ssize_t ret = -EINVAL;
long data;
int axis, apply_now;
int cmd, bit_h;
ret = kstrtol(buf, 0, &data);
if (ret)
return ret;
dev_dbg(dev, "data = %lx\n", data);
cmd = data & CMD_MASK;
if (cmd == CMD_DO_CAL) {
if (sensors_cdev->sensors_calibrate == NULL) {
dev_err(dev, "Invalid calibrate handle\n");
return -EINVAL;
}
/* parse the data to get the axis and apply_now value*/
apply_now = (int)(data >> DATA_APPLY_SHIFT) & APPLY_MASK;
axis = (int)data >> DATA_AXIS_SHIFT;
dev_dbg(dev, "apply_now = %d, axis = %d\n", apply_now, axis);
ret = sensors_cdev->sensors_calibrate(sensors_cdev,
axis, apply_now);
if (ret)
return ret;
} else {
if (sensors_cdev->sensors_write_cal_params == NULL) {
dev_err(dev,
"Invalid write_cal_params handle\n");
return -EINVAL;
}
bit_h = (data & CMD_W_H_L) >> 4;
if (cmd > CMD_DO_CAL && cmd < CMD_COMPLETE) {
char *p = (char *)(&sensors_cdev->cal_result)
+ cal_map[cmd];
*(int *)p = CMD_GET_PARAMS(bit_h, *(int *)p, data);
} else if (cmd == CMD_COMPLETE) {
ret = sensors_cdev->sensors_write_cal_params
(sensors_cdev, &sensors_cdev->cal_result);
} else {
dev_err(dev, "Invalid command\n");
return -EINVAL;
}
}
return size;
}
static struct device_attribute sensors_class_attrs[] = {
__ATTR(name, 0444, sensors_name_show, NULL),
@ -301,6 +426,8 @@ static struct device_attribute sensors_class_attrs[] = {
__ATTR(self_test, 0440, sensors_test_show, NULL),
__ATTR(batch, 0660, sensors_batch_show, sensors_batch_store),
__ATTR(flush, 0660, sensors_flush_show, sensors_flush_store),
__ATTR(calibrate, 0664, sensors_calibrate_show,
sensors_calibrate_store),
__ATTR_NULL,
};

View File

@ -47,6 +47,43 @@
#define SENSOR_TYPE_STEP_COUNTER 19
#define SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR 20
enum LIS3DH_AXIS {
AXIS_X = 0,
AXIS_Y,
AXIS_Z,
AXIS_XYZ,
};
enum LIS3DH_THRES {
AXIS_THRESHOLD_H = 0,
AXIS_THRESHOLD_L,
AXIS_BIAS,
};
#define AXIS_FACTOR 0
#define AXIS_OFFSET 1
struct cal_result_t {
union {
struct {
int offset_x; /*axis offset of x axis*/
int offset_y; /*axis offset of x axis*/
int offset_z; /*axis offset of x axis*/
};
struct {
int threshold_h; /*proximity threshold_h*/
int threshold_l; /*proximity threshold_l*/
int bias; /*proximity measure data noise*/
};
int offset[3];
};
int factor; /*light sensor factor for real ligt strength*/
int range;
struct cal_result_t *node;
};
/**
* struct sensors_classdev - hold the sensor general parameters and APIs
* @dev: The device to register.
@ -74,6 +111,8 @@
* millisecond.
* @sensors_enable: The handle for enable and disable sensor.
* @sensors_poll_delay: The handle for set the sensor polling delay time.
* @params The sensor calibrate string format params up to userspace.
* @cal_result The sensor calibrate parameters, cal_result is a struct for sensor.
*/
struct sensors_classdev {
struct device *dev;
@ -94,6 +133,8 @@ struct sensors_classdev {
unsigned int batch_mode;
unsigned int delay_msec;
unsigned int batch_timeout_ms;
char *params;
struct cal_result_t cal_result;
/* enable and disable the sensor handle*/
int (*sensors_enable)(struct sensors_classdev *sensors_cdev,
unsigned int enabled);
@ -106,6 +147,10 @@ struct sensors_classdev {
unsigned int period_ms,
unsigned int timeout_ms);
int (*sensors_flush)(struct sensors_classdev *sensors_cdev);
int (*sensors_calibrate)(struct sensors_classdev *sensor_cdev,
int axis, int apply_now);
int (*sensors_write_cal_params)(struct sensors_classdev
*sensor_cdev, struct cal_result_t *cal_result);
};
extern int sensors_classdev_register(struct device *parent,