From: lw Date: Wed, 13 Jun 2012 06:50:24 +0000 (+0800) Subject: add new driver for all sensors X-Git-Tag: firefly_0821_release~9101 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=20f9121ccfcd8c43afedbef01632213fee33fd58;p=firefly-linux-kernel-4.4.55.git add new driver for all sensors --- diff --git a/arch/arm/plat-rk/include/plat/board.h b/arch/arm/plat-rk/include/plat/board.h index 98fee642d804..331f65ff395e 100755 --- a/arch/arm/plat-rk/include/plat/board.h +++ b/arch/arm/plat-rk/include/plat/board.h @@ -90,12 +90,34 @@ struct gsensor_platform_data { void (*exit_platform_hw)(void); }; + struct akm8975_platform_data { short m_layout[4][3][3]; char project_name[64]; int gpio_DRDY; }; +struct sensor_platform_data { + int type; + int irq; + int power_pin; + int reset_pin; + int irq_enable; //if irq_enable=1 then use irq else use polling + int poll_delay_ms; //polling + int x_min; //filter + int y_min; + int z_min; + unsigned char address; + signed char orientation[9]; + short m_layout[4][3][3]; + char project_name[64]; + int (*init_platform_hw)(void); + void (*exit_platform_hw)(void); + int (*power_on)(void); + int (*power_off)(void); +}; + + struct goodix_platform_data { int model ; int rest_pin; diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index d52a16a23a4a..972b67ffaffd 100755 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -194,6 +194,7 @@ source "drivers/input/jogball/Kconfig" source "drivers/input/lightsensor/Kconfig" +source "drivers/input/sensors/Kconfig" endif diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 7b058fb4b7f4..d9f2e938540e 100755 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -28,5 +28,7 @@ obj-$(CONFIG_INPUT_JOGBALL) += jogball/ obj-$(CONFIG_LIGHT_SENSOR_DEVICE) += lightsensor/ obj-$(CONFIG_MAG_SENSORS) += magnetometer/ +obj-$(CONFIG_SENSOR_DEVICE) += sensors/ + obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o diff --git a/drivers/input/sensors/Kconfig b/drivers/input/sensors/Kconfig new file mode 100755 index 000000000000..25fea663108c --- /dev/null +++ b/drivers/input/sensors/Kconfig @@ -0,0 +1,19 @@ +# +# all sensors drivers configuration +# + +comment "handle all sensors" + +menuconfig SENSOR_DEVICE + tristate "handle gsensor,compass,gyroscope,lsensor psensor etc" + +if SENSOR_DEVICE + +source "drivers/input/sensors/accel/Kconfig" +source "drivers/input/sensors/compass/Kconfig" +source "drivers/input/sensors/gyro/Kconfig" +source "drivers/input/sensors/lsensor/Kconfig" +source "drivers/input/sensors/psensor/Kconfig" +source "drivers/input/sensors/temperature/Kconfig" + +endif diff --git a/drivers/input/sensors/Makefile b/drivers/input/sensors/Makefile new file mode 100755 index 000000000000..65d9b20b1a44 --- /dev/null +++ b/drivers/input/sensors/Makefile @@ -0,0 +1,10 @@ +# sensor drivers +obj-$(CONFIG_GSENSOR_DEVICE) += accel/ +obj-$(CONFIG_COMPASS_DEVICE) += compass/ +obj-$(CONFIG_GYROSCOPE_DEVICE) += gyro/ +obj-$(CONFIG_LIGHT_DEVICE) += lsensor/ +obj-$(CONFIG_PROXIMITY_DEVICE) += psensor/ + + +obj-$(CONFIG_SENSOR_DEVICE) += sensor-i2c.o +obj-$(CONFIG_SENSOR_DEVICE) += sensor-dev.o diff --git a/drivers/input/sensors/accel/Kconfig b/drivers/input/sensors/accel/Kconfig new file mode 100755 index 000000000000..701e6ec008e1 --- /dev/null +++ b/drivers/input/sensors/accel/Kconfig @@ -0,0 +1,36 @@ +# +# gsensor drivers configuration +# + +menuconfig GSENSOR_DEVICE + bool "g_sensor device support" + help + Enable this to be able to choose the drivers for controlling the + g_sensor on some platforms, for example on PDAs. + +if GSENSOR_DEVICE +config GS_MMA8452 + bool "gsensor mma8452" + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. + +config GS_KXTIK + bool "gsensor kxtik" + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. + +config GS_LIS3DH + bool "gsensor lis3dh" + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. + +config GS_BMA023 + bool "gsensor bma023" + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. +endif + diff --git a/drivers/input/sensors/accel/Makefile b/drivers/input/sensors/accel/Makefile new file mode 100755 index 000000000000..bb116f0b682b --- /dev/null +++ b/drivers/input/sensors/accel/Makefile @@ -0,0 +1,3 @@ + +obj-$(CONFIG_GS_KXTIK) += kxtik.o +obj-$(CONFIG_GS_MMA8452) += mma8452.o \ No newline at end of file diff --git a/drivers/input/sensors/accel/kxtik.c b/drivers/input/sensors/accel/kxtik.c new file mode 100755 index 000000000000..1b517d5caaca --- /dev/null +++ b/drivers/input/sensors/accel/kxtik.c @@ -0,0 +1,270 @@ +/* drivers/input/sensors/access/kxtik.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + + + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + status = KXTIK_ENABLE; //kxtik + sensor->ops->ctrl_data |= status; + } + else + { + status = ~KXTIK_ENABLE; //kxtik + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + result = sensor_write_reg(client, KXTIK_DATA_CTRL_REG, KXTIK_ODR400F); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + if(sensor->pdata->irq_enable) //open interrupt + { + result = sensor_write_reg(client, KXTIK_INT_CTRL_REG1, 0x34);//enable int,active high,need read INT_REL + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + } + + sensor->ops->ctrl_data = (KXTIK_RES_12BIT | KXTIK_G_2G); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + return result; +} + +static int sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte) +{ + s64 result; + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + //int precision = sensor->ops->precision; + switch (sensor->devid) { + case KXTIK_DEVID: + result = (((int)high_byte << 8) | ((int)low_byte ))>>4; + if (result < KXTIK_BOUNDARY) + result = result* KXTIK_GRAVITY_STEP; + else + result = ~( ((~result & (0x7fff>>(16-KXTIK_PRECISION)) ) + 1) + * KXTIK_GRAVITY_STEP) + 1; + break; + + default: + printk(KERN_ERR "%s: devid wasn't set correctly\n",__func__); + return -EFAULT; + } + + return (int)result; +} + +static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + /* Report acceleration sensor information */ + input_report_abs(sensor->input_dev, ABS_X, axis->x); + input_report_abs(sensor->input_dev, ABS_Y, axis->y); + input_report_abs(sensor->input_dev, ABS_Z, axis->z); + input_sync(sensor->input_dev); + DBG("Gsensor x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); + + return 0; +} + +#define GSENSOR_MIN 10 +static int sensor_report_value(struct i2c_client *client, unsigned char *buffer, int length) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata = sensor->pdata; + int ret = 0; + int x,y,z; + struct sensor_axis axis; + char buffer[6] = {0}; + + if(sensor->ops->read_len < 6) //sensor->ops->read_len = 6 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 6); + + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + do { + *buffer = sensor->ops->read_reg; + ret = sensor_rx_data(client, buffer, sensor->ops->read_len); + if (ret < 0) + return ret; + } while (0); + + //this gsensor need 6 bytes buffer + x = sensor_convert_data(sensor->client, buffer[1], buffer[0]); //buffer[1]:high bit + y = sensor_convert_data(sensor->client, buffer[3], buffer[2]); + z = sensor_convert_data(sensor->client, buffer[5], buffer[4]); + + axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; + axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; + axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; + + DBG( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); + + //Report event only while value is changed to save some power + if((abs(sensor->axis.x - axis.x) > GSENSOR_MIN) || (abs(sensor->axis.y - axis.y) > GSENSOR_MIN) || (abs(sensor->axis.z - axis.z) > GSENSOR_MIN)) + { + gsensor_report_value(client, &axis); + + /* »¥³âµØ»º´æÊý¾Ý. */ + mutex_lock(&(sensor->data_mutex) ); + sensor->axis = axis; + mutex_unlock(&(sensor->data_mutex) ); + } + + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + ret= sensor_read_reg(client, sensor->ops->int_status_reg); + if(ret) + { + printk("%s:fail to clear sensor int status,ret=0x%x\n",__func__,ret); + } + } + + return ret; +} + +struct sensor_operate gsensor_ops = { + .name = "kxtik", + .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct + .id_i2c = ACCEL_ID_KXTIK, //i2c id number + .read_reg = KXTIK_XOUT_L, //read data + .read_len = 6, //data length + .id_reg = KXTIK_WHO_AM_I, //read device id from this register + .id_data = KXTIK_DEVID, //device id + .precision = KXTIK_PRECISION, //12 bits + .ctrl_reg = KXTIK_CTRL_REG1, //enable or disable + .int_status_reg = KXTIK_INT_REL, //intterupt status register + .range = {-KXTIK_RANGE,KXTIK_RANGE}, //range + .trig = IRQF_TRIGGER_LOW|IRQF_ONESHOT, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *gsensor_get_ops(void) +{ + return &gsensor_ops; +} + +EXPORT_SYMBOL(gsensor_get_ops); + +static int __init gsensor_init(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit gsensor_exit(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); +} + + +module_init(gsensor_init); +module_exit(gsensor_exit); + + diff --git a/drivers/input/sensors/accel/mma8452.c b/drivers/input/sensors/accel/mma8452.c new file mode 100755 index 000000000000..c4001619cf4d --- /dev/null +++ b/drivers/input/sensors/accel/mma8452.c @@ -0,0 +1,308 @@ +/* drivers/input/sensors/access/mma8452.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + + +#define MMA8451_DEVID 0x1a +#define MMA8452_DEVID 0x2a +#define MMA8453_DEVID 0x3a + +#define MMA8452_ENABLE 1 + + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + status = MMA8452_ENABLE; //mma8452 + sensor->ops->ctrl_data |= status; + } + else + { + status = ~MMA8452_ENABLE; //mma8452 + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + +static int sensor_init(struct i2c_client *client) +{ + int tmp; + int ret = 0; + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + ret = sensor->ops->active(client,0,0); + if(ret) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return ret; + } + + sensor->status_cur = SENSOR_OFF; + + /* disable FIFO FMODE = 0*/ + ret = sensor_write_reg(client,MMA8452_REG_F_SETUP,0); + DBG("%s: MMA8452_REG_F_SETUP:%x\n",__func__, sensor_read_reg(client,MMA8452_REG_F_SETUP)); + + /* set full scale range to 2g */ + ret = sensor_write_reg(client,MMA8452_REG_XYZ_DATA_CFG,0); + DBG("%s: MMA8452_REG_XYZ_DATA_CFG:%x\n",__func__, sensor_read_reg(client,MMA8452_REG_XYZ_DATA_CFG)); + + /* set bus 8bit/14bit(FREAD = 1,FMODE = 0) ,data rate*/ + tmp = (MMA8452_RATE_12P5<< MMA8452_RATE_SHIFT) | FREAD_MASK; + ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG1,tmp); + + sensor->ops->ctrl_data = tmp; + + DBG("mma8452 MMA8452_REG_CTRL_REG1:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG1)); + + DBG("mma8452 MMA8452_REG_SYSMOD:%x\n",sensor_read_reg(client,MMA8452_REG_SYSMOD)); + + ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG3,5); + DBG("mma8452 MMA8452_REG_CTRL_REG3:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG3)); + + ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG4,1); + DBG("mma8452 MMA8452_REG_CTRL_REG4:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG4)); + + ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG5,1); + DBG("mma8452 MMA8452_REG_CTRL_REG5:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG5)); + + DBG("mma8452 MMA8452_REG_SYSMOD:%x\n",sensor_read_reg(client,MMA8452_REG_SYSMOD)); + + return ret; +} + +static int sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte) +{ + s64 result; + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + //int precision = sensor->ops->precision; + switch (sensor->devid) { + case MMA8451_DEVID: + swap(high_byte,low_byte); + result = ((int)high_byte << (MMA8451_PRECISION-8)) + | ((int)low_byte >> (16-MMA8451_PRECISION)); + if (result < MMA8451_BOUNDARY) + result = result* MMA8451_GRAVITY_STEP; + else + result = ~( ((~result & (0x7fff>>(16-MMA8451_PRECISION)) ) + 1) + * MMA8451_GRAVITY_STEP) + 1; + break; + + case MMA8452_DEVID: + swap(high_byte,low_byte); + result = ((int)high_byte << (MMA8452_PRECISION-8)) + | ((int)low_byte >> (16-MMA8452_PRECISION)); + if (result < MMA8452_BOUNDARY) + result = result* MMA8452_GRAVITY_STEP; + else + result = ~( ((~result & (0x7fff>>(16-MMA8452_PRECISION)) ) + 1) + * MMA8452_GRAVITY_STEP) + 1; + break; + + case MMA8453_DEVID: + swap(high_byte,low_byte); + result = ((int)high_byte << (MMA8453_PRECISION-8)) + | ((int)low_byte >> (16-MMA8453_PRECISION)); + if (result < MMA8453_BOUNDARY) + result = result* MMA8453_GRAVITY_STEP; + else + result = ~( ((~result & (0x7fff>>(16-MMA8453_PRECISION)) ) + 1) + * MMA8453_GRAVITY_STEP) + 1; + break; + + default: + printk(KERN_ERR "%s: devid wasn't set correctly\n",__func__); + return -EFAULT; + } + + return (int)result; +} + +static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + /* Report acceleration sensor information */ + input_report_abs(sensor->input_dev, ABS_X, axis->x); + input_report_abs(sensor->input_dev, ABS_Y, axis->y); + input_report_abs(sensor->input_dev, ABS_Z, axis->z); + input_sync(sensor->input_dev); + DBG("Gsensor x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); + + return 0; +} + +#define GSENSOR_MIN 10 +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata = sensor->pdata; + int ret = 0; + int x,y,z; + struct sensor_axis axis; + char buffer[6] = {0}; + + if(sensor->ops->read_len < 6) //sensor->ops->read_len = 6 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 6); + + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + do { + *buffer = sensor->ops->read_reg; + ret = sensor_rx_data(client, buffer, sensor->ops->read_len); + if (ret < 0) + return ret; + } while (0); + + + //this gsensor need 6 bytes buffer + x = sensor_convert_data(sensor->client, buffer[1], buffer[0]); //buffer[1]:high bit + y = sensor_convert_data(sensor->client, buffer[3], buffer[2]); + z = sensor_convert_data(sensor->client, buffer[5], buffer[4]); + + axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; + axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; + axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; + + DBG( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); + + //Report event only while value is changed to save some power + if((abs(sensor->axis.x - axis.x) > GSENSOR_MIN) || (abs(sensor->axis.y - axis.y) > GSENSOR_MIN) || (abs(sensor->axis.z - axis.z) > GSENSOR_MIN)) + { + gsensor_report_value(client, &axis); + + /* »¥³âµØ»º´æÊý¾Ý. */ + mutex_lock(&(sensor->data_mutex) ); + sensor->axis = axis; + mutex_unlock(&(sensor->data_mutex) ); + } + + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + ret= sensor_read_reg(client, sensor->ops->int_status_reg); + if(ret) + { + printk("%s:fail to clear sensor int status,ret=0x%x\n",__func__,ret); + } + } + + return ret; +} + + +struct sensor_operate gsensor_ops = { + .name = "mma8452", + .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct + .id_i2c = ACCEL_ID_MMA845X, //i2c id number + .read_reg = MMA8452_REG_X_OUT_MSB, //read data + .read_len = 6, //data length + .id_reg = MMA8452_REG_WHO_AM_I, //read device id from this register + .id_data = MMA8452_DEVID, //device id + .precision = MMA8452_PRECISION, //12 bit + .ctrl_reg = MMA8452_REG_CTRL_REG1, //enable or disable + .int_status_reg = MMA8452_REG_INTSRC, //intterupt status register + .range = {-MMA845X_RANGE,MMA845X_RANGE}, //range + .trig = IRQF_TRIGGER_LOW|IRQF_ONESHOT, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *gsensor_get_ops(void) +{ + return &gsensor_ops; +} + +EXPORT_SYMBOL(gsensor_get_ops); + +static int __init gsensor_init(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit gsensor_exit(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); +} + + +module_init(gsensor_init); +module_exit(gsensor_exit); + + + diff --git a/drivers/input/sensors/compass/Kconfig b/drivers/input/sensors/compass/Kconfig new file mode 100755 index 000000000000..72ab06c0c34f --- /dev/null +++ b/drivers/input/sensors/compass/Kconfig @@ -0,0 +1,37 @@ +# +# Magnetometer drivers configuration +# + +menuconfig COMPASS_DEVICE + bool "Magnetometer sensors" + help + Say Y here, and a list of Magnetometer sensors drivers will be displayed. + Everything that didn't fit into the other categories is here. This option + doesn't affect the kernel. + + If unsure, say Y. + +if COMPASS_DEVICE + +config COMPASS_AK8975 + tristate "Asahi Kasei AK8975 3-Axis Magnetometer" + depends on I2C + help + Say yes here to build support for Asahi Kasei AK8975 3-Axis + Magnetometer. + + To compile this driver as a module, choose M here: the module + will be called ak8975. + +config COMPASS_MMC328X + tristate "Mmc328x 3-Axis Magnetometer" + depends on I2C + help + Say yes here to build support for mmc3280 3-Axis + Magnetometer. + + To compile this driver as a module, choose M here: the module + will be called mmc3280. + +endif + diff --git a/drivers/input/sensors/compass/Makefile b/drivers/input/sensors/compass/Makefile new file mode 100755 index 000000000000..dfd09bfa3ea5 --- /dev/null +++ b/drivers/input/sensors/compass/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for industrial I/O Magnetometer sensors +# +obj-$(CONFIG_COMPASS_AK8975) := ak8975.o +obj-$(CONFIG_COMPASS_AK8973) := ak8973.o +obj-$(CONFIG_COMPASS_MMC328X) := mmc328x.o \ No newline at end of file diff --git a/drivers/input/sensors/compass/ak8975.c b/drivers/input/sensors/compass/ak8975.c new file mode 100755 index 000000000000..18af82768930 --- /dev/null +++ b/drivers/input/sensors/compass/ak8975.c @@ -0,0 +1,753 @@ +/* drivers/input/sensors/access/akm8975.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include + +#define SENSOR_DATA_SIZE 8 + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_COMPASS +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + + + +#define AK8975_DEVICE_ID 0x48 +static struct i2c_client *this_client; + +static atomic_t m_flag; +static atomic_t a_flag; +static atomic_t mv_flag; +static atomic_t open_flag; +static short akmd_delay = 100; +static DECLARE_WAIT_QUEUE_HEAD(open_wq); + + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + status = AK8975_MODE_SNG_MEASURE; + sensor->ops->ctrl_data |= status; + } + else + { + status = ~AK8975_MODE_SNG_MEASURE; + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + this_client = client; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + sensor->ops->ctrl_data = 0; + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + DBG("%s:status_cur=%d\n",__func__, sensor->status_cur); + return result; +} + +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + char buffer[8] = {0}; + unsigned char *stat; + unsigned char *stat2; + int ret = 0; +#ifdef SENSOR_DEBUG_TYPE + int i; +#endif + if(sensor->ops->read_len < 8) //sensor->ops->read_len = 8 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 8); + + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + do { + *buffer = sensor->ops->read_reg; + ret = sensor_rx_data(client, buffer, sensor->ops->read_len); + if (ret < 0) + return ret; + } while (0); + + stat = &buffer[0]; + stat2 = &buffer[7]; + + /* + * ST : data ready - + * Measurement has been completed and data is ready to be read. + */ + if ((*stat & 0x01) != 0x01) { + DBG(KERN_ERR "%s:ST is not set\n",__func__); + return -1; + } + + /* + * ST2 : data error - + * occurs when data read is started outside of a readable period; + * data read would not be correct. + * Valid in continuous measurement mode only. + * In single measurement mode this error should not occour but we + * stil account for it and return an error, since the data would be + * corrupted. + * DERR bit is self-clearing when ST2 register is read. + */ + if (*stat2 & 0x04) + { + DBG(KERN_ERR "%s:compass data error\n",__func__); + return -2; + } + + /* + * ST2 : overflow - + * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT. + * This is likely to happen in presence of an external magnetic + * disturbance; it indicates, the sensor data is incorrect and should + * be ignored. + * An error is returned. + * HOFL bit clears when a new measurement starts. + */ + if (*stat2 & 0x08) + { + DBG(KERN_ERR "%s:compass data overflow\n",__func__); + return -3; + } + + /* »¥³âµØ»º´æÊý¾Ý. */ + mutex_lock(&sensor->data_mutex); + memcpy(sensor->sensor_data, buffer, sensor->ops->read_len); + mutex_unlock(&sensor->data_mutex); +#ifdef SENSOR_DEBUG_TYPE + DBG("%s:",__func__); + for(i=0; iops->read_len; i++) + DBG("%d,",buffer[i]); + DBG("\n"); +#endif + + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + ret= sensor_read_reg(client, sensor->ops->int_status_reg); + if(ret) + { + printk("%s:fail to clear sensor int status,ret=0x%x\n",__func__,ret); + } + } + + return ret; +} + +static void compass_set_YPR(short *rbuf) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(this_client); + + /* Report magnetic sensor information */ + if (atomic_read(&m_flag)) { + input_report_abs(sensor->input_dev, ABS_RX, rbuf[0]); + input_report_abs(sensor->input_dev, ABS_RY, rbuf[1]); + input_report_abs(sensor->input_dev, ABS_RZ, rbuf[2]); + input_report_abs(sensor->input_dev, ABS_RUDDER, rbuf[4]); + DBG("%s:m_flag:x=%d,y=%d,z=%d,RUDDER=%d\n",__func__,rbuf[0], rbuf[1], rbuf[2], rbuf[4]); + } + + /* Report acceleration sensor information */ + if (atomic_read(&a_flag)) { + input_report_abs(sensor->input_dev, ABS_X, rbuf[6]); + input_report_abs(sensor->input_dev, ABS_Y, rbuf[7]); + input_report_abs(sensor->input_dev, ABS_Z, rbuf[8]); + input_report_abs(sensor->input_dev, ABS_WHEEL, rbuf[5]); + + DBG("%s:a_flag:x=%d,y=%d,z=%d,WHEEL=%d\n",__func__,rbuf[6], rbuf[7], rbuf[8], rbuf[5]); + } + + /* Report magnetic vector information */ + if (atomic_read(&mv_flag)) { + input_report_abs(sensor->input_dev, ABS_HAT0X, rbuf[9]); + input_report_abs(sensor->input_dev, ABS_HAT0Y, rbuf[10]); + input_report_abs(sensor->input_dev, ABS_BRAKE, rbuf[11]); + + DBG("%s:mv_flag:x=%d,y=%d,BRAKE=%d\n",__func__,rbuf[9], rbuf[10], rbuf[11]); + } + + input_sync(sensor->input_dev); +} + + + +static int compass_aot_open(struct inode *inode, struct file *file) +{ +#ifdef SENSOR_DEBUG_TYPE + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(this_client); +#endif + int result = 0; + int flag = 0; + flag = atomic_read(&open_flag); + if(!flag) + { + atomic_set(&open_flag, 1); + wake_up(&open_wq); + } + + DBG("%s\n", __func__); + return result; +} + + +static int compass_aot_release(struct inode *inode, struct file *file) +{ +#ifdef SENSOR_DEBUG_TYPE + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(this_client); +#endif + //struct i2c_client *client = this_client; + int result = 0; + int flag = 0; + flag = atomic_read(&open_flag); + if(flag) + { + atomic_set(&open_flag, 0); + wake_up(&open_wq); + } + + DBG("%s\n", __func__); + return result; +} + + +/* ioctl - I/O control */ +static long compass_aot_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ +#ifdef SENSOR_DEBUG_TYPE + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(this_client); +#endif + void __user *argp = (void __user *)arg; + int result = 0; + short flag; + + switch (cmd) { + case ECS_IOCTL_APP_SET_MFLAG: + case ECS_IOCTL_APP_SET_AFLAG: + case ECS_IOCTL_APP_SET_MVFLAG: + if (copy_from_user(&flag, argp, sizeof(flag))) { + return -EFAULT; + } + if (flag < 0 || flag > 1) { + return -EINVAL; + } + break; + case ECS_IOCTL_APP_SET_DELAY: + if (copy_from_user(&flag, argp, sizeof(flag))) { + return -EFAULT; + } + break; + default: + break; + } + + switch (cmd) { + case ECS_IOCTL_APP_SET_MFLAG: + atomic_set(&m_flag, flag); + DBG("%s:ECS_IOCTL_APP_SET_MFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_GET_MFLAG: + flag = atomic_read(&m_flag); + DBG("%s:ECS_IOCTL_APP_GET_MFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_SET_AFLAG: + atomic_set(&a_flag, flag); + DBG("%s:ECS_IOCTL_APP_SET_AFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_GET_AFLAG: + flag = atomic_read(&a_flag); + DBG("%s:ECS_IOCTL_APP_GET_AFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_SET_MVFLAG: + atomic_set(&mv_flag, flag); + DBG("%s:ECS_IOCTL_APP_SET_MVFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_GET_MVFLAG: + flag = atomic_read(&mv_flag); + DBG("%s:ECS_IOCTL_APP_GET_MVFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_SET_DELAY: + akmd_delay = flag; + break; + case ECS_IOCTL_APP_GET_DELAY: + flag = akmd_delay; + break; + default: + return -ENOTTY; + } + + switch (cmd) { + case ECS_IOCTL_APP_GET_MFLAG: + case ECS_IOCTL_APP_GET_AFLAG: + case ECS_IOCTL_APP_GET_MVFLAG: + case ECS_IOCTL_APP_GET_DELAY: + if (copy_to_user(argp, &flag, sizeof(flag))) { + return -EFAULT; + } + break; + default: + break; + } + + return result; +} + +static int compass_dev_open(struct inode *inode, struct file *file) +{ +#ifdef SENSOR_DEBUG_TYPE + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(this_client); +#endif + int result = 0; + DBG("%s\n",__func__); + + return result; +} + + +static int compass_dev_release(struct inode *inode, struct file *file) +{ +#ifdef SENSOR_DEBUG_TYPE + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(this_client); +#endif + int result = 0; + DBG("%s\n",__func__); + + return result; +} + +static int compass_akm_set_mode(struct i2c_client *client, char mode) +{ + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); + int result = 0; + + switch(mode) + { + case AK8975_MODE_SNG_MEASURE: + case AK8975_MODE_SELF_TEST: + case AK8975_MODE_FUSE_ACCESS: + if(sensor->status_cur == SENSOR_OFF) + { + if(sensor->pdata->irq_enable) + { + //DBG("%s:enable irq=%d\n",__func__,client->irq); + //enable_irq(client->irq); + } + else + { + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } + + sensor->status_cur = SENSOR_ON; + } + + break; + + case AK8975_MODE_POWERDOWN: + if(sensor->status_cur == SENSOR_ON) + { + if(sensor->pdata->irq_enable) + { + //DBG("%s:disable irq=%d\n",__func__,client->irq); + //disable_irq_nosync(client->irq);//disable irq + } + else + cancel_delayed_work_sync(&sensor->delaywork); + + sensor->status_cur = SENSOR_OFF; + } + break; + + } + + switch(mode) + { + case AK8975_MODE_SNG_MEASURE: + result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK8975_MODE_SNG_MEASURE); + if(result) + printk("%s:i2c error,mode=%d\n",__func__,mode); + break; + case AK8975_MODE_SELF_TEST: + result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK8975_MODE_SELF_TEST); + if(result) + printk("%s:i2c error,mode=%d\n",__func__,mode); + break; + case AK8975_MODE_FUSE_ACCESS: + result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK8975_MODE_FUSE_ACCESS); + if(result) + printk("%s:i2c error,mode=%d\n",__func__,mode); + break; + case AK8975_MODE_POWERDOWN: + /* Set powerdown mode */ + result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK8975_MODE_POWERDOWN); + if(result) + printk("%s:i2c error,mode=%d\n",__func__,mode); + udelay(100); + break; + default: + printk("%s: Unknown mode(%d)", __func__, mode); + result = -EINVAL; + break; + } + DBG("%s:mode=%d\n",__func__,mode); + return result; + +} + + +static int compass_akm_get_openstatus(void) +{ + wait_event_interruptible(open_wq, (atomic_read(&open_flag) != 0)); + return atomic_read(&open_flag); +} + +static int compass_akm_get_closestatus(void) +{ + wait_event_interruptible(open_wq, (atomic_read(&open_flag) <= 0)); + return atomic_read(&open_flag); +} + + +/* ioctl - I/O control */ +static long compass_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); + struct i2c_client *client = this_client; + void __user *argp = (void __user *)arg; + int result = 0; + struct akm8975_platform_data compass; + + /* NOTE: In this function the size of "char" should be 1-byte. */ + char compass_data[SENSOR_DATA_SIZE];/* for GETDATA */ + char rwbuf[RWBUF_SIZE]; /* for READ/WRITE */ + char mode; /* for SET_MODE*/ + short value[12]; /* for SET_YPR */ + short delay; /* for GET_DELAY */ + int status; /* for OPEN/CLOSE_STATUS */ + int ret = -1; /* Return value. */ + + switch (cmd) { + case ECS_IOCTL_WRITE: + case ECS_IOCTL_READ: + if (argp == NULL) { + return -EINVAL; + } + if (copy_from_user(&rwbuf, argp, sizeof(rwbuf))) { + return -EFAULT; + } + break; + case ECS_IOCTL_SET_MODE: + if (argp == NULL) { + return -EINVAL; + } + if (copy_from_user(&mode, argp, sizeof(mode))) { + return -EFAULT; + } + break; + case ECS_IOCTL_SET_YPR: + if (argp == NULL) { + return -EINVAL; + } + if (copy_from_user(&value, argp, sizeof(value))) { + return -EFAULT; + } + break; + default: + break; + } + + switch (cmd) { + case ECS_IOCTL_WRITE: + DBG("%s:ECS_IOCTL_WRITE start\n",__func__); + mutex_lock(&sensor->operation_mutex); + if ((rwbuf[0] < 2) || (rwbuf[0] > (RWBUF_SIZE-1))) { + mutex_unlock(&sensor->operation_mutex); + return -EINVAL; + } + ret = sensor_tx_data(client, &rwbuf[1], rwbuf[0]); + if (ret < 0) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:fait to tx data\n",__func__); + return ret; + } + mutex_unlock(&sensor->operation_mutex); + break; + case ECS_IOCTL_READ: + DBG("%s:ECS_IOCTL_READ start\n",__func__); + mutex_lock(&sensor->operation_mutex); + if ((rwbuf[0] < 1) || (rwbuf[0] > (RWBUF_SIZE-1))) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:data is error\n",__func__); + return -EINVAL; + } + ret = sensor_rx_data(client, &rwbuf[1], rwbuf[0]); + if (ret < 0) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:fait to rx data\n",__func__); + return ret; + } + mutex_unlock(&sensor->operation_mutex); + break; + case ECS_IOCTL_SET_MODE: + DBG("%s:ECS_IOCTL_SET_MODE start\n",__func__); + mutex_lock(&sensor->operation_mutex); + ret = compass_akm_set_mode(client, mode); + if (ret < 0) { + printk("%s:fait to set mode\n",__func__); + mutex_unlock(&sensor->operation_mutex); + return ret; + } + mutex_unlock(&sensor->operation_mutex); + break; + case ECS_IOCTL_GETDATA: + DBG("%s:ECS_IOCTL_GETDATA start\n",__func__); + mutex_lock(&sensor->data_mutex); + memcpy(compass_data, sensor->sensor_data, SENSOR_DATA_SIZE); //get data from buffer + mutex_unlock(&sensor->data_mutex); + break; + case ECS_IOCTL_SET_YPR: + DBG("%s:ECS_IOCTL_SET_YPR start\n",__func__); + mutex_lock(&sensor->data_mutex); + compass_set_YPR(value); + mutex_unlock(&sensor->data_mutex); + break; + case ECS_IOCTL_GET_OPEN_STATUS: + status = compass_akm_get_openstatus(); + DBG("%s:openstatus=%d\n",__func__,status); + break; + case ECS_IOCTL_GET_CLOSE_STATUS: + status = compass_akm_get_closestatus(); + DBG("%s:closestatus=%d\n",__func__,status); + break; + case ECS_IOCTL_GET_DELAY: + delay = akmd_delay; + break; + case ECS_IOCTL_GET_PLATFORM_DATA: + DBG("%s:ECS_IOCTL_GET_PLATFORM_DATA start\n",__func__); + memcpy(compass.m_layout, sensor->pdata->m_layout, sizeof(sensor->pdata->m_layout)); + memcpy(compass.project_name, sensor->pdata->project_name, sizeof(sensor->pdata->project_name)); + ret = copy_to_user(argp, &compass, sizeof(compass)); + if(ret < 0) + { + printk("%s:error,ret=%d\n",__FUNCTION__, ret); + return ret; + } + break; + + default: + return -ENOTTY; + } + + switch (cmd) { + case ECS_IOCTL_READ: + if (copy_to_user(argp, &rwbuf, rwbuf[0]+1)) { + return -EFAULT; + } + break; + case ECS_IOCTL_GETDATA: + if (copy_to_user(argp, &compass_data, sizeof(compass_data))) { + return -EFAULT; + } + break; + case ECS_IOCTL_GET_OPEN_STATUS: + case ECS_IOCTL_GET_CLOSE_STATUS: + if (copy_to_user(argp, &status, sizeof(status))) { + return -EFAULT; + } + break; + case ECS_IOCTL_GET_DELAY: + if (copy_to_user(argp, &delay, sizeof(delay))) { + return -EFAULT; + } + break; + default: + break; + } + + return result; +} + + +static struct file_operations compass_aot_fops = +{ + .owner = THIS_MODULE, + .unlocked_ioctl = compass_aot_ioctl, + .open = compass_aot_open, + .release = compass_aot_release, +}; + + + +static struct miscdevice compass_aot_device = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = "akm8975_aot", + .fops = &compass_aot_fops, +}; + + +static struct file_operations compass_dev_fops = +{ + .owner = THIS_MODULE, + .open = compass_dev_open, + .release = compass_dev_release, + .unlocked_ioctl = compass_dev_ioctl, +}; + + +static struct miscdevice compass_dev_device = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = "akm8975_dev", + .fops = &compass_dev_fops, +}; + +struct sensor_operate akm8975_ops = { + .name = "akm8975", + .type = SENSOR_TYPE_COMPASS, //it is important + .id_i2c = COMPASS_ID_AK8975, + .read_reg = AK8975_REG_ST1, //read data + .read_len = SENSOR_DATA_SIZE, //data length + .id_reg = AK8975_REG_WIA, //read id + .id_data = AK8975_DEVICE_ID, + .precision = 8, //12 bits + .ctrl_reg = AK8975_REG_CNTL, //enable or disable + .int_status_reg = SENSOR_UNKNOW_DATA, //not exist + .range = {-0xffff,0xffff}, + .trig = IRQF_TRIGGER_RISING, //if LEVEL interrupt then IRQF_ONESHOT + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, + .misc_dev = &compass_dev_device, //private misc support +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *compass_get_ops(void) +{ + return &akm8975_ops; +} + +EXPORT_SYMBOL(compass_get_ops); + + +static int __init compass_init(void) +{ + struct sensor_operate *ops = compass_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, compass_get_ops); + + result = misc_register(&compass_aot_device); + if (result < 0) { + printk("%s:fail to register misc device %s\n", __func__, compass_aot_device.name); + goto error; + } + + /* As default, report all information */ + atomic_set(&m_flag, 1); + atomic_set(&a_flag, 1); + atomic_set(&mv_flag, 1); + atomic_set(&open_flag, 0); + init_waitqueue_head(&open_wq); + + printk("%s\n",__func__); +error: + return result; +} + +static void __exit compass_exit(void) +{ + struct sensor_operate *ops = compass_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, compass_get_ops); +} + + +module_init(compass_init); +module_exit(compass_exit); + + diff --git a/drivers/input/sensors/gyro/Kconfig b/drivers/input/sensors/gyro/Kconfig new file mode 100755 index 000000000000..ab5233fc112a --- /dev/null +++ b/drivers/input/sensors/gyro/Kconfig @@ -0,0 +1,19 @@ +# +# gyroscope drivers configuration +# + +menuconfig GYROSCOPE_DEVICE + bool "gyroscope device support" + default n + +if GYROSCOPE_DEVICE + +config GYRO_L3G4200D + bool "gyroscope l3g4200d" + default n + +config GYRO_K3G + bool "gyroscope k3g" + default n + +endif diff --git a/drivers/input/sensors/gyro/Makefile b/drivers/input/sensors/gyro/Makefile new file mode 100755 index 000000000000..c531f6202c74 --- /dev/null +++ b/drivers/input/sensors/gyro/Makefile @@ -0,0 +1,4 @@ +# gyroscope drivers + +obj-$(CONFIG_GYRO_SENSOR_K3G) += k3g.o +obj-$(CONFIG_GYRO_L3G4200D) += l3g4200d.o \ No newline at end of file diff --git a/drivers/input/sensors/gyro/l3g4200d.c b/drivers/input/sensors/gyro/l3g4200d.c new file mode 100755 index 000000000000..761ccd26e3d0 --- /dev/null +++ b/drivers/input/sensors/gyro/l3g4200d.c @@ -0,0 +1,267 @@ +/* drivers/input/sensors/access/kxtik.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_GYROSCOPE +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +#define L3G4200D_ENABLE 0x08 + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + status = L3G4200D_ENABLE; //l3g4200d + sensor->ops->ctrl_data |= status; + } + else + { + status = ~L3G4200D_ENABLE; //l3g4200d + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + unsigned char buf[5]; + unsigned char data = 0; + int i = 0; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + buf[0] = 0x07; //27 + buf[1] = 0x00; + buf[2] = 0x00; + buf[3] = 0x20; //0x00 + buf[4] = 0x00; + for(i=0; i<5; i++) + { + result = sensor_write_reg(client, sensor->ops->ctrl_reg+i, buf[i]); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + } + + result = sensor_read_reg(client, sensor->ops->ctrl_reg); + if (result >= 0) + data = result & 0x000F; + + sensor->ops->ctrl_data = data + ODR100_BW12_5; + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + return result; +} + + +static int gyro_report_value(struct i2c_client *client, struct sensor_axis *axis) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + /* Report GYRO information */ + input_report_rel(sensor->input_dev, ABS_RX, axis->x); + input_report_rel(sensor->input_dev, ABS_RY, axis->y); + input_report_rel(sensor->input_dev, ABS_RZ, axis->z); + input_sync(sensor->input_dev); + DBG("gyro x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); + + return 0; +} + +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata = sensor->pdata; + int ret = 0; + int x = 0, y = 0, z = 0; + struct sensor_axis axis; + char buffer[6] = {0}; + int i = 0; + + if(sensor->ops->read_len < 6) //sensor->ops->read_len = 6 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 6); +#if 0 + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + do { + buffer[0] = sensor->ops->read_reg; + ret = sensor_rx_data(client, buffer, sensor->ops->read_len); + if (ret < 0) + return ret; + } while (0); +#else + + for(i=0; i<6; i++) + { + //buffer[i] = sensor->ops->read_reg + i; + buffer[i] = sensor_read_reg(client, sensor->ops->read_reg + i); + } +#endif + x = (short) (((buffer[1]) << 8) | buffer[0]); + y = (short) (((buffer[3]) << 8) | buffer[2]); + z = (short) (((buffer[5]) << 8) | buffer[4]); + + DBG("%s: x=%d y=%d z=%d \n",__func__, x,y,z); + if(pdata && pdata->orientation) + { + axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; + axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; + axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; + } + else + { + axis.x = x; + axis.y = y; + axis.z = z; + } + + //filter gyro data + if((abs(axis.x) > pdata->x_min)||(abs(axis.y) > pdata->y_min)||(abs(axis.z) > pdata->z_min)) + { + gyro_report_value(client, &axis); + + /* »¥³âµØ»º´æÊý¾Ý. */ + mutex_lock(&(sensor->data_mutex) ); + sensor->axis = axis; + mutex_unlock(&(sensor->data_mutex) ); + } + + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + ret= sensor_read_reg(client, sensor->ops->int_status_reg); + if(ret) + { + printk("%s:fail to clear sensor int status,ret=0x%x\n",__func__,ret); + } + } + + return ret; +} + + +struct sensor_operate gyro_ops = { + .name = "l3g4200d", + .type = SENSOR_TYPE_GYROSCOPE,//sensor type and it should be correct + .id_i2c = GYRO_ID_L3G4200D, //i2c id number + .read_reg = GYRO_DATA_REG, //read data + .read_len = 6, //data length + .id_reg = GYRO_WHO_AM_I, //read device id from this register + .id_data = GYRO_DEVID_L3G4200D, //device id + .precision = 8, //8 bits + .ctrl_reg = GYRO_CTRL_REG1, //enable or disable + .int_status_reg = GYRO_INT_SRC, //intterupt status register,if no exist then -1 + .range = {-32768,32768}, //range + .trig = IRQF_TRIGGER_LOW|IRQF_ONESHOT, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *gyro_get_ops(void) +{ + return &gyro_ops; +} + +EXPORT_SYMBOL(gyro_get_ops); + +static int __init gyro_init(void) +{ + struct sensor_operate *ops = gyro_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, gyro_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit gyro_exit(void) +{ + struct sensor_operate *ops = gyro_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, gyro_get_ops); +} + + +module_init(gyro_init); +module_exit(gyro_exit); + + diff --git a/drivers/input/sensors/lsensor/Kconfig b/drivers/input/sensors/lsensor/Kconfig new file mode 100755 index 000000000000..5cd38076dc3d --- /dev/null +++ b/drivers/input/sensors/lsensor/Kconfig @@ -0,0 +1,22 @@ +# +# light and position sensor drivers configuration +# + +menuconfig LIGHT_DEVICE + bool "light sensor device support" + default n + +if LIGHT_DEVICE +config LS_CM3217 + bool "light sensor cm3217" + default n + +config LS_AL3006 + bool "light sensor al3006" + default n + +config LS_STK3171 + bool "light sensor stk3171" + default n +endif + diff --git a/drivers/input/sensors/lsensor/Makefile b/drivers/input/sensors/lsensor/Makefile new file mode 100755 index 000000000000..98836f434c06 --- /dev/null +++ b/drivers/input/sensors/lsensor/Makefile @@ -0,0 +1,5 @@ +# gsensor drivers + +obj-$(CONFIG_LS_CM3217) += cm3217.o +obj-$(CONFIG_LS_AL3006) += ls_al3006.o +obj-$(CONFIG_LS_STK3171) += ls_stk3171.o \ No newline at end of file diff --git a/drivers/input/sensors/lsensor/cm3217.c b/drivers/input/sensors/lsensor/cm3217.c new file mode 100755 index 000000000000..b51f27154ebe --- /dev/null +++ b/drivers/input/sensors/lsensor/cm3217.c @@ -0,0 +1,238 @@ +/* drivers/input/sensors/access/kxtik.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_LIGHT +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +#define CM3217_ADDR_COM1 0x10 +#define CM3217_ADDR_COM2 0x11 +#define CM3217_ADDR_DATA_MSB 0x10 +#define CM3217_ADDR_DATA_LSB 0x11 + +#define CM3217_COM1_VALUE 0xA7 // (GAIN1:GAIN0)=10, (IT_T1:IT_TO)=01,WMD=1,SD=1, +#define CM3217_COM2_VALUE 0xA0 //100ms + +#define CM3217_CLOSE 0x01 + + + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->client->addr = sensor->ops->ctrl_reg; + sensor->ops->ctrl_data = sensor_read_reg_normal(client); + + //register setting according to chip datasheet + if(!enable) + { + status = CM3217_CLOSE; //cm3217 + sensor->ops->ctrl_data |= status; + } + else + { + status = ~CM3217_CLOSE; //cm3217 + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg_normal(client, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + sensor->client->addr = sensor->ops->ctrl_reg; + sensor->ops->ctrl_data = CM3217_COM1_VALUE; + result = sensor_write_reg_normal(client, sensor->ops->ctrl_data); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->client->addr = CM3217_ADDR_COM2; + result = sensor_write_reg_normal(client, CM3217_COM2_VALUE); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + return result; +} + + +static void light_report_value(struct input_dev *input, int data) +{ + unsigned char index = 0; + if(data <= 10){ + index = 0;goto report; + } + else if(data <= 160){ + index = 1;goto report; + } + else if(data <= 225){ + index = 2;goto report; + } + else if(data <= 320){ + index = 3;goto report; + } + else if(data <= 640){ + index = 4;goto report; + } + else if(data <= 1280){ + index = 5;goto report; + } + else if(data <= 2600){ + index = 6;goto report; + } + else{ + index = 7;goto report; + } + +report: + DBG("cm3217 report data=%d,index = %d\n",data,index); + input_report_abs(input, ABS_MISC, index); + input_sync(input); +} + + +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + char msb = 0, lsb = 0; + + sensor->client->addr = CM3217_ADDR_DATA_LSB; + sensor_rx_data_normal(sensor->client, &lsb, 1); + sensor->client->addr = CM3217_ADDR_DATA_MSB; + sensor_rx_data_normal(sensor->client, &msb, 1); + result = ((msb << 8) | lsb) & 0xffff; + + DBG("%s:result=%d\n",__func__,result); + light_report_value(sensor->input_dev, result); + + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + result= sensor_read_reg(client, sensor->ops->int_status_reg); + if(result) + { + printk("%s:fail to clear sensor int status,ret=0x%x\n",__func__,result); + } + } + + return result; +} + + +struct sensor_operate light_ops = { + .name = "cm3217", + .type = SENSOR_TYPE_LIGHT, //sensor type and it should be correct + .id_i2c = LIGHT_ID_CM3217, //i2c id number + .read_reg = CM3217_ADDR_DATA_LSB, //read data + .read_len = 2, //data length + .id_reg = SENSOR_UNKNOW_DATA, //read device id from this register + .id_data = SENSOR_UNKNOW_DATA, //device id + .precision = 8, //8 bits + .ctrl_reg = CM3217_ADDR_COM1, //enable or disable + .int_status_reg = SENSOR_UNKNOW_DATA, //intterupt status register + .range = {0,10}, //range + .trig = SENSOR_UNKNOW_DATA, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *light_get_ops(void) +{ + return &light_ops; +} + +EXPORT_SYMBOL(light_get_ops); + +static int __init light_init(void) +{ + struct sensor_operate *ops = light_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, light_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit light_exit(void) +{ + struct sensor_operate *ops = light_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, light_get_ops); +} + + +module_init(light_init); +module_exit(light_exit); + + diff --git a/drivers/input/sensors/lsensor/ls_al3006.c b/drivers/input/sensors/lsensor/ls_al3006.c new file mode 100755 index 000000000000..0700ff303d14 --- /dev/null +++ b/drivers/input/sensors/lsensor/ls_al3006.c @@ -0,0 +1,299 @@ +/* drivers/input/sensors/access/kxtik.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_LIGHT +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +#define CONFIG_REG (0x00) +#define TIM_CTL_REG (0x01) +#define ALS_CTL_REG (0x02) +#define INT_STATUS_REG (0x03) +#define PS_CTL_REG (0x04) +#define PS_ALS_DATA_REG (0x05) +#define ALS_WINDOWS_REG (0x08) + +//enable bit[ 0-1], in register CONFIG_REG +#define ONLY_ALS_EN (0x00) +#define ONLY_PROX_EN (0x01) +#define ALL_PROX_ALS_EN (0x02) +#define ALL_IDLE (0x03) + +#define POWER_MODE_MASK (0x0C) +#define POWER_UP_MODE (0x00) +#define POWER_DOWN_MODE (0x08) +#define POWER_RESET_MODE (0x0C) + +static int sensor_power_updown(struct i2c_client *client, int on) +{ + int result = 0; + char value = 0; + int i = 0; + for(i=0; i<3; i++) + { + if(!on) + { + result = sensor_write_reg(client, CONFIG_REG, POWER_DOWN_MODE); + if(result) + return result; + } + else + { + value = sensor_read_reg(client, CONFIG_REG); + value &= ~POWER_MODE_MASK; + value |= POWER_UP_MODE; + result = sensor_write_reg(client, CONFIG_REG, value); + if(result) + return result; + } + + if(!result) + break; + } + + if(i>1) + printk("%s:set %d times",__func__,i); + + return result; +} + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + char value = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + if( (sensor->ops->ctrl_data & 0x03) == ONLY_PROX_EN ) + { + value &= ~0x03; + value |= ALL_PROX_ALS_EN; + } + else if((value & 0x03) == ALL_IDLE ) + { + value &= ~0x03; + value |= ONLY_ALS_EN; + } + + sensor_power_updown(client, 1); + } + else + { + if( (sensor->ops->ctrl_data & 0x03) == ONLY_ALS_EN ) + { + value &= ~0x03; + value |= ALL_IDLE; + } + else if((sensor->ops->ctrl_data & 0x03) == ALL_PROX_ALS_EN ) + { + value &= ~0x03; + value |= ONLY_PROX_EN; + } + + } + + sensor->ops->ctrl_data = value; + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + char value = 0; + + + sensor_power_updown(client, 0); + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + value = 0x41;//The ADC effective resolution = 9; Low lux threshold level = 1; + //value = 0x69; //The ADC effective resolution = 17; Low lux threshold level = 9; + result = sensor_write_reg(client, ALS_CTL_REG, value); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + //value = 0x04;//0x01-0x0f; 17%->93.5% if value = 0x04,then Compensate Loss 52% + value = 0x02;//0x01-0x0f; 17%->93.5% if value = 0x02,then Compensate Loss 31% + result = sensor_write_reg(client, ALS_WINDOWS_REG, value); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + return result; +} + + +static int light_report_value(struct input_dev *input, int data) +{ + unsigned char index = 0; + if(data <= 0){ + index = 0;goto report; + } + else if(data <= 2){ + index = 1;goto report; + } + else if(data <= 4){ + index = 2;goto report; + } + else if(data <= 8){ + index = 3;goto report; + } + else if(data <= 14){ + index = 4;goto report; + } + else if(data <= 20){ + index = 5;goto report; + } + else if(data <= 26){ + index = 6;goto report; + } + else{ + index = 7;goto report; + } + +report: + input_report_abs(input, ABS_MISC, index); + input_sync(input); + + return index; +} + + +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + char value = 0; + char index = 0; + + if(sensor->pdata->irq_enable) + { + if(sensor->ops->int_status_reg) + { + value = sensor_read_reg(client, sensor->ops->int_status_reg); + } + + } + + value = sensor_read_reg(client, sensor->ops->read_reg); + index = light_report_value(sensor->input_dev, value&0x3f); // bit0-5 is ls data; + + DBG("%s:%s result=0x%x,index=%d\n",__func__,sensor->ops->name, value,index); + + return result; +} + +struct sensor_operate light_ops = { + .name = "ls_al3006", + .type = SENSOR_TYPE_LIGHT, //sensor type and it should be correct + .id_i2c = LIGHT_ID_AL3006, //i2c id number + .read_reg = PS_ALS_DATA_REG, //read data + .read_len = 1, //data length + .id_reg = SENSOR_UNKNOW_DATA, //read device id from this register + .id_data = SENSOR_UNKNOW_DATA, //device id + .precision = 8, //8 bits + .ctrl_reg = CONFIG_REG, //enable or disable + .int_status_reg = INT_STATUS_REG, //intterupt status register + .range = {0,10}, //range + .trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *light_get_ops(void) +{ + return &light_ops; +} + +EXPORT_SYMBOL(light_get_ops); + +static int __init light_init(void) +{ + struct sensor_operate *ops = light_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, light_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit light_exit(void) +{ + struct sensor_operate *ops = light_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, light_get_ops); +} + + +module_init(light_init); +module_exit(light_exit); + + diff --git a/drivers/input/sensors/lsensor/ls_stk3171.c b/drivers/input/sensors/lsensor/ls_stk3171.c new file mode 100755 index 000000000000..307e148291f5 --- /dev/null +++ b/drivers/input/sensors/lsensor/ls_stk3171.c @@ -0,0 +1,301 @@ +/* drivers/input/sensors/access/kxtik.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_LIGHT +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +#define ALS_CMD 0x01 +#define ALS_DT1 0x02 +#define ALS_DT2 0X03 +#define ALS_THDH1 0X04 +#define ALS_THDH2 0X05 +#define ALS_THDL1 0X06 +#define ALS_THDL2 0X07 +#define STA_TUS 0X08 +#define PS_CMD 0X09 +#define PS_DT 0X0A +#define PS_THDH 0X0B +#define PS_THDL 0X0C +#define SW_RESET 0X80 + +//ALS_CMD +#define ALS_SD_ENABLE (0<<0) +#define ALS_SD_DISABLE (1<<0) +#define ALS_INT_DISABLE (0<<1) +#define ALS_INT_ENABLE (1<<1) +#define ALS_1T_100MS (0<<2) +#define ALS_2T_200MS (1<<2) +#define ALS_4T_400MS (2<<2) +#define ALS_8T_800MS (3<<2) +#define ALS_RANGE_57671 (0<<5) +#define ALS_RANGE_28836 (1<<5) + +//PS_CMD +#define PS_SD_ENABLE (0<<0) +#define PS_SD_DISABLE (1<<0) +#define PS_INT_DISABLE (0<<1) +#define PS_INT_ENABLE (1<<1) +#define PS_10T_2MS (0<<2) +#define PS_15T_3MS (1<<2) +#define PS_20T_4MS (2<<2) +#define PS_25T_5MS (3<<2) +#define PS_CUR_100MA (0<<3) +#define PS_CUR_200MA (1<<3) +#define PS_SLP_10MS (0<<4) +#define PS_SLP_30MS (1<<4) +#define PS_SLP_90MS (2<<4) +#define PS_SLP_270MS (3<<4) +#define TRIG_PS_OR_LS (0<<5) +#define TRIG_PS_AND_LS (1<<5) + +//STA_TUS +#define STA_PS_INT (1<<4) +#define STA_ALS_INT (1<<3) + + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(!enable) + { + status = ALS_SD_DISABLE; + sensor->ops->ctrl_data |= status; + } + else + { + status = ~ALS_SD_DISABLE; + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + result = sensor_write_reg(client, SW_RESET, 0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + + sensor->ops->ctrl_data |= (ALS_1T_100MS | ALS_RANGE_28836); + + if(sensor->pdata->irq_enable) + sensor->ops->ctrl_data |= ALS_INT_ENABLE; + else + sensor->ops->ctrl_data &= ~ALS_INT_ENABLE; + + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + return result; +} + + +static int light_report_value(struct input_dev *input, int data) +{ + unsigned char index = 0; + if(data <= 10){ + index = 0;goto report; + } + else if(data <= 1600){ + index = 1;goto report; + } + else if(data <= 2250){ + index = 2;goto report; + } + else if(data <= 3200){ + index = 3;goto report; + } + else if(data <= 6400){ + index = 4;goto report; + } + else if(data <= 12800){ + index = 5;goto report; + } + else if(data <= 26000){ + index = 6;goto report; + } + else{ + index = 7;goto report; + } + +report: + input_report_abs(input, ABS_MISC, index); + input_sync(input); + + return index; +} + + +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int value = 0; + char buffer[2] = {0}; + char index = 0; + + if(sensor->ops->read_len < 2) //sensor->ops->read_len = 2 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 2); + + result = sensor_rx_data(client, buffer, sensor->ops->read_len); + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + value = (short) (((buffer[1]) << 8) | buffer[0]); + + index = light_report_value(sensor->input_dev, value); + + if(sensor->pdata->irq_enable) + { + if(sensor->ops->int_status_reg) + { + value = sensor_read_reg(client, sensor->ops->int_status_reg); + } + + if(value & STA_ALS_INT) + { + value &= ~STA_ALS_INT; + result = sensor_write_reg(client, sensor->ops->int_status_reg,value); //clear int + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + } + } + + DBG("%s:%s result=0x%x,index=%d\n",__func__,sensor->ops->name, value,index); + + return result; +} + +struct sensor_operate light_ops = { + .name = "ls_stk3171", + .type = SENSOR_TYPE_LIGHT, //sensor type and it should be correct + .id_i2c = LIGHT_ID_STK3171, //i2c id number + .read_reg = ALS_DT1, //read data + .read_len = 2, //data length + .id_reg = SENSOR_UNKNOW_DATA, //read device id from this register + .id_data = SENSOR_UNKNOW_DATA, //device id + .precision = 16, //8 bits + .ctrl_reg = ALS_CMD, //enable or disable + .int_status_reg = STA_TUS, //intterupt status register + .range = {0,10}, //range + .trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *light_get_ops(void) +{ + return &light_ops; +} + +EXPORT_SYMBOL(light_get_ops); + +static int __init light_init(void) +{ + struct sensor_operate *ops = light_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, light_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit light_exit(void) +{ + struct sensor_operate *ops = light_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, light_get_ops); +} + + +module_init(light_init); +module_exit(light_exit); + + diff --git a/drivers/input/sensors/psensor/Kconfig b/drivers/input/sensors/psensor/Kconfig new file mode 100755 index 000000000000..289280da6020 --- /dev/null +++ b/drivers/input/sensors/psensor/Kconfig @@ -0,0 +1,20 @@ +# +# light and position sensor drivers configuration +# + +menuconfig PROXIMITY_DEVICE + bool "proximity sensor device support" + default n + +if PROXIMITY_DEVICE + +config PS_AL3006 + bool "psensor al3006" + default n + +config PS_STK3171 + bool "psensor stk3171" + default n + +endif + diff --git a/drivers/input/sensors/psensor/Makefile b/drivers/input/sensors/psensor/Makefile new file mode 100755 index 000000000000..1da405f6f88e --- /dev/null +++ b/drivers/input/sensors/psensor/Makefile @@ -0,0 +1,4 @@ +# gsensor drivers + +obj-$(CONFIG_PS_AL3006) += ps_al3006.o +obj-$(CONFIG_PS_STK3171) += ps_stk3171.o \ No newline at end of file diff --git a/drivers/input/sensors/psensor/ps_al3006.c b/drivers/input/sensors/psensor/ps_al3006.c new file mode 100755 index 000000000000..3e8f59e55b9b --- /dev/null +++ b/drivers/input/sensors/psensor/ps_al3006.c @@ -0,0 +1,260 @@ +/* drivers/input/sensors/access/kxtik.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_PROXIMITY +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +#define CONFIG_REG (0x00) +#define TIM_CTL_REG (0x01) +#define ALS_CTL_REG (0x02) +#define INT_STATUS_REG (0x03) +#define PS_CTL_REG (0x04) +#define PS_ALS_DATA_REG (0x05) +#define ALS_WINDOWS_REG (0x08) + +//enable bit[ 0-1], in register CONFIG_REG +#define ONLY_ALS_EN (0x00) +#define ONLY_PROX_EN (0x01) +#define ALL_PROX_ALS_EN (0x02) +#define ALL_IDLE (0x03) + +#define POWER_MODE_MASK (0x0C) +#define POWER_UP_MODE (0x00) +#define POWER_DOWN_MODE (0x08) +#define POWER_RESET_MODE (0x0C) + +static int sensor_power_updown(struct i2c_client *client, int on) +{ + int result = 0; + char value = 0; + int i = 0; + for(i=0; i<3; i++) + { + if(!on) + { + result = sensor_write_reg(client, CONFIG_REG, POWER_DOWN_MODE); + if(result) + return result; + } + else + { + value = sensor_read_reg(client, CONFIG_REG); + value &= ~POWER_MODE_MASK; + value |= POWER_UP_MODE; + result = sensor_write_reg(client, CONFIG_REG, value); + if(result) + return result; + } + + if(!result) + break; + } + + if(i>1) + printk("%s:set %d times",__func__,i); + + return result; +} + + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + char value = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + if( (sensor->ops->ctrl_data & 0x03) == ONLY_ALS_EN ) + { + value &= ~0x03; + value |= ALL_PROX_ALS_EN; + } + else if((value & 0x03) == ALL_IDLE ) + { + value &= ~0x03; + value |= ONLY_PROX_EN; + } + + sensor_power_updown(client, 1); + } + else + { + if( (sensor->ops->ctrl_data & 0x03) == ONLY_PROX_EN ) + { + value &= ~0x03; + value |= ALL_IDLE; + } + else if((sensor->ops->ctrl_data & 0x03) == ALL_PROX_ALS_EN ) + { + value &= ~0x03; + value |= ONLY_ALS_EN; + } + } + + sensor->ops->ctrl_data = value; + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + char value = 0; + + sensor_power_updown(client, 0); + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + value = 0x41;//The ADC effective resolution = 9; Low lux threshold level = 1; + //value = 0x69; //The ADC effective resolution = 17; Low lux threshold level = 9; + result = sensor_write_reg(client, ALS_CTL_REG, value); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + //value = 0x04;//0x01-0x0f; 17%->93.5% if value = 0x04,then Compensate Loss 52% + value = 0x02;//0x01-0x0f; 17%->93.5% if value = 0x02,then Compensate Loss 31% + result = sensor_write_reg(client, ALS_WINDOWS_REG, value); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + return result; +} + +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + char value = 0; + + if(sensor->pdata->irq_enable) + { + if(sensor->ops->int_status_reg) + { + value = sensor_read_reg(client, sensor->ops->int_status_reg); + } + + } + + value = sensor_read_reg(client, sensor->ops->read_reg); + input_report_abs(sensor->input_dev, ABS_DISTANCE, (value>>7)?0:1); + input_sync(sensor->input_dev); + DBG("%s:%s result=0x%x,index=%d\n",__func__,sensor->ops->name, value,(value>>7)?0:1); + + return result; +} + +struct sensor_operate proximity_ops = { + .name = "ps_al3006", + .type = SENSOR_TYPE_PROXIMITY,//sensor type and it should be correct + .id_i2c = PROXIMITY_ID_AL3006, //i2c id number + .read_reg = PS_ALS_DATA_REG, //read data + .read_len = 1, //data length + .id_reg = SENSOR_UNKNOW_DATA, //read device id from this register + .id_data = SENSOR_UNKNOW_DATA, //device id + .precision = 8, //8 bits + .ctrl_reg = CONFIG_REG, //enable or disable + .int_status_reg = INT_STATUS_REG, //intterupt status register + .range = {0,10}, //range + .trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *proximity_get_ops(void) +{ + return &proximity_ops; +} + +EXPORT_SYMBOL(proximity_get_ops); + +static int __init proximity_init(void) +{ + struct sensor_operate *ops = proximity_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, proximity_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit proximity_exit(void) +{ + struct sensor_operate *ops = proximity_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, proximity_get_ops); +} + + +module_init(proximity_init); +module_exit(proximity_exit); + + diff --git a/drivers/input/sensors/psensor/ps_stk3171.c b/drivers/input/sensors/psensor/ps_stk3171.c new file mode 100755 index 000000000000..e5b39eedc97e --- /dev/null +++ b/drivers/input/sensors/psensor/ps_stk3171.c @@ -0,0 +1,265 @@ +/* drivers/input/sensors/access/kxtik.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_PROXIMITY +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +#define ALS_CMD 0x01 +#define ALS_DT1 0x02 +#define ALS_DT2 0X03 +#define ALS_THDH1 0X04 +#define ALS_THDH2 0X05 +#define ALS_THDL1 0X06 +#define ALS_THDL2 0X07 +#define STA_TUS 0X08 +#define PS_CMD 0X09 +#define PS_DT 0X0A +#define PS_THDH 0X0B +#define PS_THDL 0X0C +#define SW_RESET 0X80 + +//ALS_CMD +#define ALS_SD_ENABLE (0<<0) +#define ALS_SD_DISABLE (1<<0) +#define ALS_INT_DISABLE (0<<1) +#define ALS_INT_ENABLE (1<<1) +#define ALS_1T_100MS (0<<2) +#define ALS_2T_200MS (1<<2) +#define ALS_4T_400MS (2<<2) +#define ALS_8T_800MS (3<<2) +#define ALS_RANGE_57671 (0<<5) +#define ALS_RANGE_28836 (1<<5) + +//PS_CMD +#define PS_SD_ENABLE (0<<0) +#define PS_SD_DISABLE (1<<0) +#define PS_INT_DISABLE (0<<1) +#define PS_INT_ENABLE (1<<1) +#define PS_10T_2MS (0<<2) +#define PS_15T_3MS (1<<2) +#define PS_20T_4MS (2<<2) +#define PS_25T_5MS (3<<2) +#define PS_CUR_100MA (0<<3) +#define PS_CUR_200MA (1<<3) +#define PS_SLP_10MS (0<<4) +#define PS_SLP_30MS (1<<4) +#define PS_SLP_90MS (2<<4) +#define PS_SLP_270MS (3<<4) +#define TRIG_PS_OR_LS (0<<5) +#define TRIG_PS_AND_LS (1<<5) + +//STA_TUS +#define STA_PS_INT (1<<4) +#define STA_ALS_INT (1<<3) + + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(!enable) + { + status = PS_SD_DISABLE; + sensor->ops->ctrl_data |= status; + } + else + { + status = ~PS_SD_DISABLE; + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + result = sensor_write_reg(client, SW_RESET, 0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + + sensor->ops->ctrl_data |= (PS_15T_3MS| PS_SLP_90MS | TRIG_PS_OR_LS); + + if(sensor->pdata->irq_enable) + sensor->ops->ctrl_data |= PS_INT_ENABLE; + else + sensor->ops->ctrl_data &= ~PS_INT_ENABLE; + + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + return result; +} + + + +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int value = 0; + char buffer[1] = {0}; + + if(sensor->ops->read_len < 1) //sensor->ops->read_len = 1 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 1); + + result = sensor_rx_data(client, buffer, sensor->ops->read_len); + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + value = buffer[0]; + + input_report_abs(sensor->input_dev, ABS_DISTANCE, value?0:1); + input_sync(sensor->input_dev); + DBG("%s:%s result=0x%x,index=%d\n",__func__,sensor->ops->name, value,value?0:1); + + if(sensor->pdata->irq_enable) + { + if(sensor->ops->int_status_reg) + { + value = sensor_read_reg(client, sensor->ops->int_status_reg); + } + + if(value & STA_PS_INT) + { + value &= ~STA_PS_INT; + result = sensor_write_reg(client, sensor->ops->int_status_reg,value); //clear int + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + } + } + + return result; +} + +struct sensor_operate proximity_ops = { + .name = "ps_stk3171", + .type = SENSOR_TYPE_PROXIMITY, //sensor type and it should be correct + .id_i2c = PROXIMITY_ID_STK3171, //i2c id number + .read_reg = PS_DT, //read data + .read_len = 1, //data length + .id_reg = SENSOR_UNKNOW_DATA, //read device id from this register + .id_data = SENSOR_UNKNOW_DATA, //device id + .precision = 8, //8 bits + .ctrl_reg = PS_CMD, //enable or disable + .int_status_reg = STA_TUS, //intterupt status register + .range = {0,1}, //range + .trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *proximity_get_ops(void) +{ + return &proximity_ops; +} + +EXPORT_SYMBOL(proximity_get_ops); + +static int __init proximity_init(void) +{ + struct sensor_operate *ops = proximity_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, proximity_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit proximity_exit(void) +{ + struct sensor_operate *ops = proximity_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, proximity_get_ops); +} + + +module_init(proximity_init); +module_exit(proximity_exit); + + diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c new file mode 100755 index 000000000000..e20270c6471f --- /dev/null +++ b/drivers/input/sensors/sensor-dev.c @@ -0,0 +1,1327 @@ +/* drivers/input/sensors/sensor-dev.c - handle all gsensor in this file + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include + +#define SENSOR_ON 1 +#define SENSOR_OFF 0 + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +struct sensor_private_data *g_sensor[SENSOR_NUM_TYPES]; +static struct sensor_operate *sensor_ops[SENSOR_NUM_TYPES]; + +static int sensor_get_id(struct i2c_client *client, int *value) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + char temp = sensor->ops->id_reg; + int i = 0; + + if(sensor->ops->id_reg >= 0) + { + for(i=0; i<3; i++) + { + result = sensor_rx_data(client, &temp, 1); + *value = temp; + if(!result) + break; + } + + if(result) + return result; + + if(*value != sensor->ops->id_data) + { + printk("%s:id=0x%x is not 0x%x\n",__func__,*value, sensor->ops->id_data); + result = -1; + } + + DBG("%s:devid=0x%x\n",__func__,*value); + } + + return result; +} + +static int sensor_initial(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + //register setting according to chip datasheet + result = sensor->ops->init(client); + if(result < 0) + { + printk("%s:fail to init sensor\n",__func__); + return result; + } + + + DBG("%s:ctrl_data=0x%x\n",__func__,sensor->ops->ctrl_data); + + return result; + +} + +static int sensor_chip_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_operate *ops = sensor_ops[sensor->type]; + int result = 0; + + if(ops) + { + sensor->ops = ops; + } + else + { + printk("%s:ops is null,sensor name is %s\n",__func__,sensor->i2c_id->name); + result = -1; + goto error; + } + + if(sensor->type != ops->type) + { + printk("%s:type is different:%d,%d\n",__func__,sensor->type, sensor->type); + result = -1; + goto error; + } + + if(!ops->init || !ops->active || !ops->report) + { + printk("%s:error:some function is needed\n",__func__); + result = -1; + goto error; + } + + result = sensor_get_id(sensor->client, &sensor->devid);//get id + if(result < 0) + { + printk("%s:fail to read devid:0x%x\n",__func__,sensor->devid); + goto error; + } + + printk("%s:sensor->devid=0x%x,ops=0x%p\n",__func__,sensor->devid,sensor->ops); + + result = sensor_initial(sensor->client); //init sensor + if(result < 0) + { + printk("%s:fail to init sensor\n",__func__); + goto error; + } + + return 0; + +error: + + return result; +} + +static int sensor_reset_rate(struct i2c_client *client, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + result = sensor->ops->active(client,SENSOR_OFF,rate); + sensor->ops->init(client); + result = sensor->ops->active(client,SENSOR_ON,rate); + + return result; +} + +static int sensor_get_data(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + result = sensor->ops->report(client); + if(result) + goto error; + + /* set data_ready */ + atomic_set(&sensor->data_ready, 1); + /*wake up data_ready work queue*/ + wake_up(&sensor->data_ready_wq); + +error: + return result; +} + +#if 0 +int sensor_get_cached_data(struct i2c_client* client, char *buffer, int length, struct sensor_axis *axis) +{ + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(client); + wait_event_interruptible_timeout(sensor->data_ready_wq, + atomic_read(&(sensor->data_ready) ), + msecs_to_jiffies(1000) ); + if ( 0 == atomic_read(&(sensor->data_ready) ) ) { + printk("waiting 'data_ready_wq' timed out."); + goto error; + } + + + mutex_lock(&sensor->data_mutex); + + switch(sensor->type) + { + case SENSOR_TYPE_ACCEL: + *axis = sensor->axis; + break; + + case SENSOR_TYPE_COMPASS: + memcpy(buffer, sensor->sensor_data, length); + break; + } + + mutex_unlock(&sensor->data_mutex); + + return 0; + +error: + return -1; +} +#endif + +static void sensor_delaywork_func(struct work_struct *work) +{ + struct delayed_work *delaywork = container_of(work, struct delayed_work, work); + struct sensor_private_data *sensor = container_of(delaywork, struct sensor_private_data, delaywork); + struct i2c_client *client = sensor->client; + + mutex_lock(&sensor->sensor_mutex); + if (sensor_get_data(client) < 0) + DBG(KERN_ERR "%s: Get data failed\n",__func__); + + if(!sensor->pdata->irq_enable)//restart work while polling + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + //else + //{ + //if((sensor->ops->trig == IRQF_TRIGGER_LOW) || (sensor->ops->trig == IRQF_TRIGGER_HIGH)) + //enable_irq(sensor->client->irq); + //} + mutex_unlock(&sensor->sensor_mutex); + + DBG("%s:%s\n",__func__,sensor->i2c_id->name); +} + +/* + * This is a threaded IRQ handler so can access I2C/SPI. Since all + * interrupts are clear on read the IRQ line will be reasserted and + * the physical IRQ will be handled again if another interrupt is + * asserted while we run - in the normal course of events this is a + * rare occurrence so we save I2C/SPI reads. We're also assuming that + * it's rare to get lots of interrupts firing simultaneously so try to + * minimise I/O. + */ +static irqreturn_t sensor_interrupt(int irq, void *dev_id) +{ + struct sensor_private_data *sensor = (struct sensor_private_data *)dev_id; + + //use threaded IRQ + if (sensor_get_data(sensor->client) < 0) + DBG(KERN_ERR "%s: Get data failed\n",__func__); + msleep(sensor->pdata->poll_delay_ms); + + + //if((sensor->ops->trig == IRQF_TRIGGER_LOW) || (sensor->ops->trig == IRQF_TRIGGER_HIGH)) + //disable_irq_nosync(irq); + //schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + DBG("%s:irq=%d\n",__func__,irq); + return IRQ_HANDLED; +} + + +static int sensor_irq_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int irq; + if((sensor->pdata->irq_enable)&&(sensor->ops->trig != SENSOR_UNKNOW_DATA)) + { + //INIT_DELAYED_WORK(&sensor->delaywork, sensor_delaywork_func); + if(sensor->pdata->poll_delay_ms < 0) + sensor->pdata->poll_delay_ms = 30; + + result = gpio_request(client->irq, sensor->i2c_id->name); + if (result) + { + printk("%s:fail to request gpio :%d\n",__func__,client->irq); + } + + gpio_pull_updown(client->irq, PullEnable); + irq = gpio_to_irq(client->irq); + //result = request_irq(irq, sensor_interrupt, sensor->ops->trig, client->dev.driver->name, sensor); + result = request_threaded_irq(irq, NULL, sensor_interrupt, sensor->ops->trig, client->dev.driver->name, sensor); + if (result) { + printk(KERN_ERR "%s:fail to request irq = %d, ret = 0x%x\n",__func__, irq, result); + goto error; + } + client->irq = irq; + if((sensor->pdata->type == SENSOR_TYPE_GYROSCOPE)) + disable_irq_nosync(client->irq);//disable irq + printk("%s:use irq=%d\n",__func__,irq); + } + else if(!sensor->pdata->irq_enable) + { + INIT_DELAYED_WORK(&sensor->delaywork, sensor_delaywork_func); + if(sensor->pdata->poll_delay_ms < 0) + sensor->pdata->poll_delay_ms = 30; + + printk("%s:use polling,delay=%d ms\n",__func__,sensor->pdata->poll_delay_ms); + } + +error: + return result; +} + + +static void sensor_suspend(struct early_suspend *h) +{ + struct sensor_private_data *sensor = + container_of(h, struct sensor_private_data, early_suspend); + + if(sensor->ops->suspend) + sensor->ops->suspend(sensor->client); + +} + +static void sensor_resume(struct early_suspend *h) +{ + struct sensor_private_data *sensor = + container_of(h, struct sensor_private_data, early_suspend); + + if(sensor->ops->resume) + sensor->ops->resume(sensor->client); +} + +static int gsensor_dev_open(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_ACCEL]; + //struct i2c_client *client = sensor->client; + + int result = 0; + + + return result; +} + + +static int gsensor_dev_release(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_ACCEL]; + //struct i2c_client *client = sensor->client; + + int result = 0; + + + return result; +} + +/* ioctl - I/O control */ +static long gsensor_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_ACCEL]; + struct i2c_client *client = sensor->client; + void __user *argp = (void __user *)arg; + struct sensor_axis axis = {0}; + char rate; + int result = 0; + + switch (cmd) { + case GSENSOR_IOCTL_APP_SET_RATE: + if (copy_from_user(&rate, argp, sizeof(rate))) + { + result = -EFAULT; + goto error; + } + break; + default: + break; + } + + switch (cmd) { + case GSENSOR_IOCTL_START: + DBG("%s:GSENSOR_IOCTL_START start,status=%d\n", __func__,sensor->status_cur); + mutex_lock(&sensor->operation_mutex); + if(++sensor->start_count == 1) + { + if(sensor->status_cur == SENSOR_OFF) + { + atomic_set(&(sensor->data_ready), 0); + if ( (result = sensor->ops->active(client, 1, 0) ) < 0 ) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:fail to active sensor,ret=%d\n",__func__,result); + goto error; + } + if(sensor->pdata->irq_enable) + { + //printk("%s:enable irq,irq=%d\n",__func__,client->irq); + //enable_irq(client->irq); //enable irq + } + else + { + PREPARE_DELAYED_WORK(&sensor->delaywork, sensor_delaywork_func); + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } + sensor->status_cur = SENSOR_ON; + } + } + mutex_unlock(&sensor->operation_mutex); + DBG("%s:GSENSOR_IOCTL_START OK\n", __func__); + break; + + case GSENSOR_IOCTL_CLOSE: + DBG("%s:GSENSOR_IOCTL_CLOSE start,status=%d\n", __func__,sensor->status_cur); + mutex_lock(&sensor->operation_mutex); + if(--sensor->start_count == 0) + { + if(sensor->status_cur == SENSOR_ON) + { + atomic_set(&(sensor->data_ready), 0); + if ( (result = sensor->ops->active(client, 0, 0) ) < 0 ) { + mutex_unlock(&sensor->operation_mutex); + goto error; + } + + if(sensor->pdata->irq_enable) + { + //printk("%s:disable irq,irq=%d\n",__func__,client->irq); + //disable_irq_nosync(client->irq);//disable irq + } + else + cancel_delayed_work_sync(&sensor->delaywork); + sensor->status_cur = SENSOR_OFF; + } + + DBG("%s:GSENSOR_IOCTL_CLOSE OK\n", __func__); + } + + mutex_unlock(&sensor->operation_mutex); + break; + + case GSENSOR_IOCTL_APP_SET_RATE: + DBG("%s:GSENSOR_IOCTL_APP_SET_RATE start\n", __func__); + mutex_lock(&sensor->operation_mutex); + result = sensor_reset_rate(client, rate); + if (result < 0) + goto error; + if(sensor->status_cur == SENSOR_OFF) + { + if(sensor->pdata->irq_enable) + { + //printk("%s:enable irq,irq=%d\n",__func__,client->irq); + //enable_irq(client->irq); //enable irq + } + else + { + PREPARE_DELAYED_WORK(&sensor->delaywork, sensor_delaywork_func); + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } + sensor->status_cur = SENSOR_ON; + } + mutex_unlock(&sensor->operation_mutex); + DBG("%s:GSENSOR_IOCTL_APP_SET_RATE OK\n", __func__); + break; + + case GSENSOR_IOCTL_GETDATA: + mutex_lock(&sensor->data_mutex); + memcpy(&axis, &sensor->axis, sizeof(sensor->axis)); //get data from buffer + mutex_unlock(&sensor->data_mutex); + break; + default: + result = -ENOTTY; + goto error; + } + + switch (cmd) { + case GSENSOR_IOCTL_GETDATA: + if ( copy_to_user(argp, &axis, sizeof(axis) ) ) { + printk("failed to copy sense data to user space."); + result = -EFAULT; + goto error; + } + DBG("%s:GSENSOR_IOCTL_GETDATA OK\n", __func__); + break; + default: + break; + } + +error: + return result; +} + + +static int compass_dev_open(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; + //struct i2c_client *client = sensor->client; + int result = 0; + + //to do + return result; +} + + +static int compass_dev_release(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; + //struct i2c_client *client = sensor->client; + int result = 0; + + //to do + return result; +} + + +/* ioctl - I/O control */ +static long compass_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; + //struct i2c_client *client = sensor->client; + //void __user *argp = (void __user *)arg; + int result = 0; + + //to do + return result; +} + +static int gyro_dev_open(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_GYROSCOPE]; + //struct i2c_client *client = sensor->client; + + int result = 0; + + + return result; +} + + +static int gyro_dev_release(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_GYROSCOPE]; + //struct i2c_client *client = sensor->client; + + int result = 0; + + + return result; +} + + +/* ioctl - I/O control */ +static long gyro_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_GYROSCOPE]; + struct i2c_client *client = sensor->client; + void __user *argp = (void __user *)arg; + int result = 0; + char rate; + switch (cmd) { + case L3G4200D_IOCTL_GET_ENABLE: + result = !sensor->status_cur; + if (copy_to_user(argp, &result, sizeof(result))) + { + printk("%s:failed to copy status to user space.\n",__FUNCTION__); + return -EFAULT; + } + + DBG("%s :L3G4200D_IOCTL_GET_ENABLE,status=%d\n",__FUNCTION__,result); + break; + case L3G4200D_IOCTL_SET_ENABLE: + DBG("%s :L3G4200D_IOCTL_SET_ENABLE,flag=%d\n",__FUNCTION__,*(unsigned int *)argp); + mutex_lock(&sensor->operation_mutex); + if(*(unsigned int *)argp) + { + if(sensor->status_cur == SENSOR_OFF) + { + if ( (result = sensor->ops->active(client, 1, ODR100_BW12_5) ) < 0 ) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:fail to active sensor,ret=%d\n",__func__,result); + goto error; + } + if(sensor->pdata->irq_enable) + { + DBG("%s:enable irq,irq=%d\n",__func__,client->irq); + enable_irq(client->irq); //enable irq + } + else + { + PREPARE_DELAYED_WORK(&sensor->delaywork, sensor_delaywork_func); + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } + sensor->status_cur = SENSOR_ON; + } + } + else + { + if(sensor->status_cur == SENSOR_ON) + { + if ( (result = sensor->ops->active(client, 0, 0) ) < 0 ) { + mutex_unlock(&sensor->operation_mutex); + goto error; + } + + if(sensor->pdata->irq_enable) + { + DBG("%s:disable irq,irq=%d\n",__func__,client->irq); + disable_irq_nosync(client->irq);//disable irq + } + else + cancel_delayed_work_sync(&sensor->delaywork); + sensor->status_cur = SENSOR_OFF; + } + } + + result = sensor->status_cur; + if (copy_to_user(argp, &result, sizeof(result))) + { + printk("%s:failed to copy sense data to user space.\n",__FUNCTION__); + return -EFAULT; + } + + mutex_unlock(&sensor->operation_mutex); + DBG("%s:L3G4200D_IOCTL_SET_ENABLE OK\n", __func__); + break; + case L3G4200D_IOCTL_SET_DELAY: + mutex_lock(&sensor->operation_mutex); + if (copy_from_user(&rate, argp, sizeof(rate))) + return -EFAULT; + if(sensor->status_cur == SENSOR_OFF) + { + if ( (result = sensor->ops->active(client, 1, rate) ) < 0 ) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:fail to active sensor,ret=%d\n",__func__,result); + goto error; + } + + if(sensor->pdata->irq_enable) + { + DBG("%s:enable irq,irq=%d\n",__func__,client->irq); + enable_irq(client->irq); //enable irq + } + else + { + PREPARE_DELAYED_WORK(&sensor->delaywork, sensor_delaywork_func); + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } + sensor->status_cur = SENSOR_ON; + } + + mutex_unlock(&sensor->operation_mutex); + DBG("%s :L3G4200D_IOCTL_SET_DELAY,rate=%d\n",__FUNCTION__,rate); + break; + + default: + printk("%s:error,cmd=0x%x\n",__func__,cmd); + return -ENOTTY; + } + + DBG("%s:line=%d,cmd=0x%x\n",__func__,__LINE__,cmd); + +error: + return result; +} + +static int light_dev_open(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_LIGHT]; + //struct i2c_client *client = sensor->client; + int result = 0; + + + return result; +} + + + + +static int light_dev_release(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_LIGHT]; + //struct i2c_client *client = sensor->client; + int result = 0; + + + return result; +} + + +/* ioctl - I/O control */ +static long light_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_LIGHT]; + struct i2c_client *client = sensor->client; + unsigned int *argp = (unsigned int *)arg; + int result = 0; + + switch(cmd) + { + case LIGHTSENSOR_IOCTL_GET_ENABLED: + *argp = sensor->status_cur; + break; + case LIGHTSENSOR_IOCTL_ENABLE: + DBG("%s:LIGHTSENSOR_IOCTL_ENABLE start\n", __func__); + mutex_lock(&sensor->operation_mutex); + if(*(unsigned int *)argp) + { + if(sensor->status_cur == SENSOR_OFF) + { + if ( (result = sensor->ops->active(client, SENSOR_ON, 0) ) < 0 ) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:fail to active sensor,ret=%d\n",__func__,result); + goto error; + } + + if(!sensor->pdata->irq_enable) + { + PREPARE_DELAYED_WORK(&sensor->delaywork, sensor_delaywork_func); + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } + sensor->status_cur = SENSOR_ON; + } + } + else + { + if(sensor->status_cur == SENSOR_ON) + { + if ( (result = sensor->ops->active(client, SENSOR_OFF, 0) ) < 0 ) { + mutex_unlock(&sensor->operation_mutex); + goto error; + } + + if(!sensor->pdata->irq_enable) + cancel_delayed_work_sync(&sensor->delaywork); + sensor->status_cur = SENSOR_OFF; + } + } + mutex_unlock(&sensor->operation_mutex); + DBG("%s:LIGHTSENSOR_IOCTL_ENABLE OK\n", __func__); + break; + + default: + break; + } + +error: + return result; +} + + +static int proximity_dev_open(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_PROXIMITY]; + //struct i2c_client *client = sensor->client; + int result = 0; + + + return result; +} + + +static int proximity_dev_release(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_PROXIMITY]; + //struct i2c_client *client = sensor->client; + int result = 0; + + + return result; +} + + +/* ioctl - I/O control */ +static long proximity_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_PROXIMITY]; + struct i2c_client *client = sensor->client; + unsigned int *argp = (unsigned int *)arg; + int result = 0; + switch(cmd) + { + case PSENSOR_IOCTL_GET_ENABLED: + *argp = sensor->status_cur; + break; + case PSENSOR_IOCTL_ENABLE: + DBG("%s:PSENSOR_IOCTL_ENABLE start\n", __func__); + mutex_lock(&sensor->operation_mutex); + if(*(unsigned int *)argp) + { + if(sensor->status_cur == SENSOR_OFF) + { + if ( (result = sensor->ops->active(client, SENSOR_ON, 0) ) < 0 ) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:fail to active sensor,ret=%d\n",__func__,result); + goto error; + } + + if(!sensor->pdata->irq_enable) + { + PREPARE_DELAYED_WORK(&sensor->delaywork, sensor_delaywork_func); + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } + sensor->status_cur = SENSOR_ON; + } + } + else + { + if(sensor->status_cur == SENSOR_ON) + { + if ( (result = sensor->ops->active(client, SENSOR_OFF, 0) ) < 0 ) { + mutex_unlock(&sensor->operation_mutex); + goto error; + } + if(!sensor->pdata->irq_enable) + cancel_delayed_work_sync(&sensor->delaywork); + sensor->status_cur = SENSOR_OFF; + } + } + mutex_unlock(&sensor->operation_mutex); + DBG("%s:PSENSOR_IOCTL_ENABLE OK\n", __func__); + break; + + default: + break; + } + +error: + return result; +} + +static int temperature_dev_open(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_TEMPERATURE]; + //struct i2c_client *client = sensor->client; + + int result = 0; + + + return result; +} + + +static int temperature_dev_release(struct inode *inode, struct file *file) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_TEMPERATURE]; + //struct i2c_client *client = sensor->client; + + int result = 0; + + + return result; +} + + +/* ioctl - I/O control */ +static long temperature_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_TEMPERATURE]; + //struct i2c_client *client = sensor->client; + //void __user *argp = (void __user *)arg; + int result = 0; + + + return result; +} + + +static int sensor_misc_device_register(struct sensor_private_data *sensor, int type) +{ + int result = 0; + + switch(type) + { + case SENSOR_TYPE_ACCEL: + if(!sensor->ops->misc_dev) + { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = gsensor_dev_ioctl; + sensor->fops.open = gsensor_dev_open; + sensor->fops.release = gsensor_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "mma8452_daemon"; + sensor->miscdev.fops = &sensor->fops; + } + else + { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + + } + + break; + + case SENSOR_TYPE_COMPASS: + if(!sensor->ops->misc_dev) + { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = compass_dev_ioctl; + sensor->fops.open = compass_dev_open; + sensor->fops.release = compass_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "compass"; + sensor->miscdev.fops = &sensor->fops; + } + else + { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + + } + + break; + + case SENSOR_TYPE_GYROSCOPE: + if(!sensor->ops->misc_dev) + { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = gyro_dev_ioctl; + sensor->fops.open = gyro_dev_open; + sensor->fops.release = gyro_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "gyrosensor"; + sensor->miscdev.fops = &sensor->fops; + } + else + { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + + } + + break; + + case SENSOR_TYPE_LIGHT: + if(!sensor->ops->misc_dev) + { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = light_dev_ioctl; + sensor->fops.open = light_dev_open; + sensor->fops.release = light_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "lightsensor"; + sensor->miscdev.fops = &sensor->fops; + } + else + { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + + } + break; + + case SENSOR_TYPE_PROXIMITY: + if(!sensor->ops->misc_dev) + { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = proximity_dev_ioctl; + sensor->fops.open = proximity_dev_open; + sensor->fops.release = proximity_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "psensor"; + sensor->miscdev.fops = &sensor->fops; + } + else + { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + + } + break; + + case SENSOR_TYPE_TEMPERATURE: + if(!sensor->ops->misc_dev) + { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = temperature_dev_ioctl; + sensor->fops.open = temperature_dev_open; + sensor->fops.release = temperature_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "temperature"; + sensor->miscdev.fops = &sensor->fops; + } + else + { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + + } + + break; + + default: + printk("%s:unknow sensor type=%d\n",__func__,type); + result = -1; + goto error; + } + + sensor->miscdev.parent = &sensor->client->dev; + result = misc_register(&sensor->miscdev); + if (result < 0) { + dev_err(&sensor->client->dev, + "fail to register misc device %s\n", sensor->miscdev.name); + goto error; + } + + printk("%s:miscdevice: %s\n",__func__,sensor->miscdev.name); + +error: + + return result; + +} + +int sensor_register_slave(int type,struct i2c_client *client, + struct sensor_platform_data *slave_pdata, + struct sensor_operate *(*get_sensor_ops)(void)) +{ + int result = 0; + sensor_ops[type] = get_sensor_ops(); + printk("%s:%s\n",__func__,sensor_ops[type]->name); + return result; +} + + +int sensor_unregister_slave(int type,struct i2c_client *client, + struct sensor_platform_data *slave_pdata, + struct sensor_operate *(*get_sensor_ops)(void)) +{ + int result = 0; + printk("%s:%s\n",__func__,sensor_ops[type]->name); + sensor_ops[type] = NULL; + return result; +} + + +int sensor_probe(struct i2c_client *client, const struct i2c_device_id *devid) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata; + int result = 0; + int type = 0; + dev_info(&client->adapter->dev, "%s: %s,0x%x\n", __func__, devid->name,(unsigned int)client); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); + if (!sensor) { + result = -ENOMEM; + goto out_no_free; + } + + type= pdata->type; + + if((type >= SENSOR_NUM_TYPES) || (type <= SENSOR_TYPE_NULL)) + { + dev_err(&client->adapter->dev, "sensor type is error %d\n", pdata->type); + result = -EFAULT; + goto out_no_free; + } + + i2c_set_clientdata(client, sensor); + sensor->client = client; + sensor->pdata = pdata; + sensor->type = type; + sensor->i2c_id = (struct i2c_device_id *)devid; + + if (pdata->init_platform_hw) { + result = pdata->init_platform_hw(); + if (result < 0) + goto out_free_memory; + } + + memset(&(sensor->axis), 0, sizeof(struct sensor_axis) ); + atomic_set(&(sensor->data_ready), 0); + init_waitqueue_head(&(sensor->data_ready_wq)); + mutex_init(&sensor->data_mutex); + mutex_init(&sensor->operation_mutex); + mutex_init(&sensor->sensor_mutex); + mutex_init(&sensor->i2c_mutex); + + sensor->status_cur = SENSOR_OFF; + sensor->axis.x = 0; + sensor->axis.y = 0; + sensor->axis.z = 0; + + result = sensor_chip_init(sensor->client); + if(result < 0) + goto out_free_memory; + + sensor->input_dev = input_allocate_device(); + if (!sensor->input_dev) { + result = -ENOMEM; + dev_err(&client->dev, + "Failed to allocate input device %s\n", sensor->input_dev->name); + goto out_free_memory; + } + + switch(type) + { + case SENSOR_TYPE_ACCEL: + sensor->input_dev->name = "gsensor"; + set_bit(EV_ABS, sensor->input_dev->evbit); + /* x-axis acceleration */ + input_set_abs_params(sensor->input_dev, ABS_X, sensor->ops->range[0], sensor->ops->range[1], 0, 0); //2g full scale range + /* y-axis acceleration */ + input_set_abs_params(sensor->input_dev, ABS_Y, sensor->ops->range[0], sensor->ops->range[1], 0, 0); //2g full scale range + /* z-axis acceleration */ + input_set_abs_params(sensor->input_dev, ABS_Z, sensor->ops->range[0], sensor->ops->range[1], 0, 0); //2g full scale range + break; + case SENSOR_TYPE_COMPASS: + sensor->input_dev->name = "compass"; + /* Setup input device */ + set_bit(EV_ABS, sensor->input_dev->evbit); + /* yaw (0, 360) */ + input_set_abs_params(sensor->input_dev, ABS_RX, 0, 23040, 0, 0); + /* pitch (-180, 180) */ + input_set_abs_params(sensor->input_dev, ABS_RY, -11520, 11520, 0, 0); + /* roll (-90, 90) */ + input_set_abs_params(sensor->input_dev, ABS_RZ, -5760, 5760, 0, 0); + /* x-axis acceleration (720 x 8G) */ + input_set_abs_params(sensor->input_dev, ABS_X, -5760, 5760, 0, 0); + /* y-axis acceleration (720 x 8G) */ + input_set_abs_params(sensor->input_dev, ABS_Y, -5760, 5760, 0, 0); + /* z-axis acceleration (720 x 8G) */ + input_set_abs_params(sensor->input_dev, ABS_Z, -5760, 5760, 0, 0); + /* status of magnetic sensor */ + input_set_abs_params(sensor->input_dev, ABS_RUDDER, -32768, 3, 0, 0); + /* status of acceleration sensor */ + input_set_abs_params(sensor->input_dev, ABS_WHEEL, -32768, 3, 0, 0); + /* x-axis of raw magnetic vector (-4096, 4095) */ + input_set_abs_params(sensor->input_dev, ABS_HAT0X, -20480, 20479, 0, 0); + /* y-axis of raw magnetic vector (-4096, 4095) */ + input_set_abs_params(sensor->input_dev, ABS_HAT0Y, -20480, 20479, 0, 0); + /* z-axis of raw magnetic vector (-4096, 4095) */ + input_set_abs_params(sensor->input_dev, ABS_BRAKE, -20480, 20479, 0, 0); + break; + case SENSOR_TYPE_GYROSCOPE: + sensor->input_dev->name = "gyro"; + /* x-axis acceleration */ + input_set_capability(sensor->input_dev, EV_REL, REL_RX); + input_set_abs_params(sensor->input_dev, ABS_RX, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + /* y-axis acceleration */ + input_set_capability(sensor->input_dev, EV_REL, REL_RY); + input_set_abs_params(sensor->input_dev, ABS_RY, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + /* z-axis acceleration */ + input_set_capability(sensor->input_dev, EV_REL, REL_RZ); + input_set_abs_params(sensor->input_dev, ABS_RZ, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + break; + case SENSOR_TYPE_LIGHT: + sensor->input_dev->name = "lightsensor-level"; + set_bit(EV_ABS, sensor->input_dev->evbit); + input_set_abs_params(sensor->input_dev, ABS_MISC, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + break; + case SENSOR_TYPE_PROXIMITY: + sensor->input_dev->name = "proximity"; + set_bit(EV_ABS, sensor->input_dev->evbit); + input_set_abs_params(sensor->input_dev, ABS_DISTANCE, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + break; + case SENSOR_TYPE_TEMPERATURE: + sensor->input_dev->name = "temperature"; + set_bit(EV_ABS, sensor->input_dev->evbit); + input_set_abs_params(sensor->input_dev, ABS_THROTTLE, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + break; + default: + printk("%s:unknow sensor type=%d\n",__func__,type); + break; + + } + sensor->input_dev->dev.parent = &client->dev; + + result = input_register_device(sensor->input_dev); + if (result) { + dev_err(&client->dev, + "Unable to register input device %s\n", sensor->input_dev->name); + goto out_input_register_device_failed; + } + + result = sensor_irq_init(sensor->client); + if (result) { + dev_err(&client->dev, + "fail to init sensor irq,ret=%d\n",result); + goto out_input_register_device_failed; + } + + + sensor->miscdev.parent = &client->dev; + result = sensor_misc_device_register(sensor, type); + if (result) { + dev_err(&client->dev, + "fail to register misc device %s\n", sensor->miscdev.name); + goto out_misc_device_register_device_failed; + } + + g_sensor[type] = sensor; + +#ifdef CONFIG_HAS_EARLYSUSPEND + if((sensor->ops->suspend) && (sensor->ops->resume)) + { + sensor->early_suspend.suspend = sensor_suspend; + sensor->early_suspend.resume = sensor_resume; + sensor->early_suspend.level = 0x02; + register_early_suspend(&sensor->early_suspend); + } +#endif + + printk("%s:initialized ok,sensor name:%s,type:%d\n",__func__,sensor->ops->name,type); + + return result; + +out_misc_device_register_device_failed: + input_unregister_device(sensor->input_dev); +out_input_register_device_failed: + input_free_device(sensor->input_dev); +out_free_memory: + kfree(sensor); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static void sensor_shut_down(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + if((sensor->ops->suspend) && (sensor->ops->resume)) + unregister_early_suspend(&sensor->early_suspend); + DBG("%s:%s\n",__func__,sensor->i2c_id->name); +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + cancel_delayed_work_sync(&sensor->delaywork); + misc_deregister(&sensor->miscdev); + input_unregister_device(sensor->input_dev); + input_free_device(sensor->input_dev); + kfree(sensor); +#ifdef CONFIG_HAS_EARLYSUSPEND + if((sensor->ops->suspend) && (sensor->ops->resume)) + unregister_early_suspend(&sensor->early_suspend); +#endif + return result; +} + +static const struct i2c_device_id sensor_id[] = { + /*gsensor*/ + {"gsensor", ACCEL_ID_ALL}, + {"gs_mma8452", ACCEL_ID_MMA845X}, + {"gs_kxtik", ACCEL_ID_KXTIK}, + /*compass*/ + {"compass", COMPASS_ID_ALL}, + {"ak8975", COMPASS_ID_AK8975}, + {"mmc314x", COMPASS_ID_MMC314X}, + /*gyroscope*/ + {"gyro", GYRO_ID_ALL}, + {"l3g4200d_gryo", GYRO_ID_L3G4200D}, + {"k3g", GYRO_ID_K3G}, + /*light sensor*/ + {"lightsensor", LIGHT_ID_ALL}, + {"light_al3006", LIGHT_ID_AL3006}, + /*proximity sensor*/ + {"psensor", PROXIMITY_ID_ALL}, + {"proximity_al3006", PROXIMITY_ID_AL3006}, + /*temperature*/ + {"temperature", TEMPERATURE_ID_ALL}, + {}, +}; + + +static struct i2c_driver sensor_driver = { + .probe = sensor_probe, + .remove = sensor_remove, + .shutdown = sensor_shut_down, + .id_table = sensor_id, + .driver = { + .owner = THIS_MODULE, + .name = "sensors", + }, +}; + +static int __init sensor_init(void) +{ + int res = i2c_add_driver(&sensor_driver); + pr_info("%s: Probe name %s\n", __func__, sensor_driver.driver.name); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit sensor_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&sensor_driver); +} + +late_initcall(sensor_init); +module_exit(sensor_exit); + +MODULE_AUTHOR("ROCKCHIP Corporation:lw@rock-chips.com"); +MODULE_DESCRIPTION("User space character device interface for sensors"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/input/sensors/sensor-i2c.c b/drivers/input/sensors/sensor-i2c.c new file mode 100755 index 000000000000..29545cbd916e --- /dev/null +++ b/drivers/input/sensors/sensor-i2c.c @@ -0,0 +1,234 @@ +/* drivers/input/sensors/sensor-i2c.c - sensor i2c handle + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#define SENSOR_I2C_RATE 200*1000 + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_COMPASS +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +static int sensor_i2c_write(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned int len, unsigned char const *data) +{ + struct i2c_msg msgs[1]; + int res; + + if (!data || !i2c_adap) { + printk("%s:line=%d,error\n",__func__,__LINE__); + return -EINVAL; + } + + msgs[0].addr = address; + msgs[0].flags = 0; /* write */ + msgs[0].buf = (unsigned char *)data; + msgs[0].len = len; + msgs[0].scl_rate = SENSOR_I2C_RATE; + + res = i2c_transfer(i2c_adap, msgs, 1); + if (res == 1) + return 0; + else if(res == 0) + return -EBUSY; + else + return res; + +} + +static int senosr_i2c_read(struct i2c_adapter *i2c_adap, + unsigned char address, unsigned char reg, + unsigned int len, unsigned char *data) +{ + struct i2c_msg msgs[2]; + int res; + + if (!data || !i2c_adap) { + printk("%s:line=%d,error\n",__func__,__LINE__); + return -EINVAL; + } + + msgs[0].addr = address; + msgs[0].flags = 0; /* write */ + msgs[0].buf = ® + msgs[0].len = 1; + msgs[0].scl_rate = SENSOR_I2C_RATE; + + msgs[1].addr = address; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = data; + msgs[1].len = len; + msgs[1].scl_rate = SENSOR_I2C_RATE; + + res = i2c_transfer(i2c_adap, msgs, 2); + if (res == 2) + return 0; + else if(res == 0) + return -EBUSY; + else + return res; + +} + + +int sensor_rx_data(struct i2c_client *client, char *rxData, int length) +{ +#ifdef SENSOR_DEBUG_TYPE + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(client); + int i = 0; +#endif + int ret = 0; + char reg = rxData[0]; + ret = senosr_i2c_read(client->adapter, client->addr, reg, length, rxData); + +#ifdef SENSOR_DEBUG_TYPE + DBG("addr=0x%x,len=%d,rxdata:",reg,length); + for(i=0; iadapter, client->addr, length, txData); + return ret; + +} +EXPORT_SYMBOL(sensor_tx_data); + +int sensor_write_reg(struct i2c_client *client, int addr, int value) +{ + char buffer[2]; + int ret = 0; + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(client); + + mutex_lock(&sensor->i2c_mutex); + buffer[0] = addr; + buffer[1] = value; + ret = sensor_tx_data(client, &buffer[0], 2); + mutex_unlock(&sensor->i2c_mutex); + return ret; +} +EXPORT_SYMBOL(sensor_write_reg); + +int sensor_read_reg(struct i2c_client *client, int addr) +{ + char tmp[1] = {0}; + int ret = 0; + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(client); + + mutex_lock(&sensor->i2c_mutex); + tmp[0] = addr; + ret = sensor_rx_data(client, tmp, 1); + mutex_unlock(&sensor->i2c_mutex); + + return tmp[0]; +} + +EXPORT_SYMBOL(sensor_read_reg); + + +int sensor_tx_data_normal(struct i2c_client *client, char *buf, int num) +{ + int ret = 0; + ret = i2c_master_normal_send(client, buf, num, SENSOR_I2C_RATE); + + return (ret == num) ? 0 : ret; +} +EXPORT_SYMBOL(sensor_tx_data_normal); + + +int sensor_rx_data_normal(struct i2c_client *client, char *buf, int num) +{ + int ret = 0; + ret = i2c_master_normal_recv(client, buf, num, SENSOR_I2C_RATE); + + return (ret == num) ? 0 : ret; +} + +EXPORT_SYMBOL(sensor_rx_data_normal); + + +int sensor_write_reg_normal(struct i2c_client *client, char value) +{ + char buffer[2]; + int ret = 0; + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(client); + + mutex_lock(&sensor->i2c_mutex); + buffer[0] = value; + ret = sensor_tx_data_normal(client, &buffer[0], 1); + mutex_unlock(&sensor->i2c_mutex); + return ret; +} +EXPORT_SYMBOL(sensor_write_reg_normal); + +int sensor_read_reg_normal(struct i2c_client *client) +{ + char tmp[0]; + int ret = 0; + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(client); + + mutex_lock(&sensor->i2c_mutex); + ret = sensor_rx_data_normal(client, tmp, 1); + mutex_unlock(&sensor->i2c_mutex); + + return tmp[0]; +} + +EXPORT_SYMBOL(sensor_read_reg_normal); + + diff --git a/drivers/input/sensors/temperature/Kconfig b/drivers/input/sensors/temperature/Kconfig new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/drivers/input/sensors/temperature/Makefile b/drivers/input/sensors/temperature/Makefile new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/include/linux/akm8975.h b/include/linux/akm8975.h old mode 100644 new mode 100755 index 6a7c43260018..e14fe064901b --- a/include/linux/akm8975.h +++ b/include/linux/akm8975.h @@ -6,17 +6,21 @@ #include +#define AKM8975_I2C_NAME "ak8975" + /*! \name AK8975 operation mode \anchor AK8975_Mode Defines an operation mode of the AK8975.*/ /*! @{*/ -#define AK8975_MODE_SNG_MEASURE 0x01 -#define AK8975_MODE_SELF_TEST 0x08 -#define AK8975_MODE_FUSE_ACCESS 0x0F -#define AK8975_MODE_POWER_DOWN 0x00 +#define AK8975_MODE_SNG_MEASURE 0x01 +#define AK8975_MODE_SELF_TEST 0x08 +#define AK8975_MODE_FUSE_ACCESS 0x0F +#define AK8975_MODE_POWERDOWN 0x00 /*! @}*/ -#define RBUFF_SIZE 8 /* Rx buffer size */ +#define SENSOR_DATA_SIZE 8 /* Rx buffer size, i.e from ST1 to ST2 */ +#define RWBUF_SIZE 16 /* Read/Write buffer size.*/ + /*! \name AK8975 register address \anchor AK8975_REG @@ -52,36 +56,34 @@ Defines a read-only address of the fuse ROM of the AK8975.*/ #define AKMIO 0xA1 /* IOCTLs for AKM library */ -#define ECS_IOCTL_WRITE _IOW(AKMIO, 0x02, char[5]) -#define ECS_IOCTL_READ _IOWR(AKMIO, 0x03, char[5]) -#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x08, char[RBUFF_SIZE]) -#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x0C, short[12]) -#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x0D, int) -#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x0E, int) +#define ECS_IOCTL_WRITE _IOW(AKMIO, 0x01, char*) +#define ECS_IOCTL_READ _IOWR(AKMIO, 0x02, char*) +#define ECS_IOCTL_RESET _IO(AKMIO, 0x03) /* NOT used in AK8975 */ +#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x04, short) +#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x05, char[SENSOR_DATA_SIZE]) +#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x06, short[12]) +#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x07, int) +#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x08, int) #define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x30, short) +#define ECS_IOCTL_GET_PROJECT_NAME _IOR(AKMIO, 0x0D, char[64]) +#define ECS_IOCTL_GET_MATRIX _IOR(AKMIO, 0x0E, short [4][3][3]) +#define ECS_IOCTL_GET_PLATFORM_DATA _IOR(AKMIO, 0x0E, struct akm8975_platform_data) + /* IOCTLs for APPs */ +#define ECS_IOCTL_APP_SET_MODE _IOW(AKMIO, 0x10, short) #define ECS_IOCTL_APP_SET_MFLAG _IOW(AKMIO, 0x11, short) #define ECS_IOCTL_APP_GET_MFLAG _IOW(AKMIO, 0x12, short) #define ECS_IOCTL_APP_SET_AFLAG _IOW(AKMIO, 0x13, short) #define ECS_IOCTL_APP_GET_AFLAG _IOR(AKMIO, 0x14, short) +#define ECS_IOCTL_APP_SET_TFLAG _IOR(AKMIO, 0x15, short)/* NOT use */ +#define ECS_IOCTL_APP_GET_TFLAG _IOR(AKMIO, 0x16, short)/* NOT use */ +#define ECS_IOCTL_APP_RESET_PEDOMETER _IO(AKMIO, 0x17) /* NOT use */ #define ECS_IOCTL_APP_SET_DELAY _IOW(AKMIO, 0x18, short) #define ECS_IOCTL_APP_GET_DELAY ECS_IOCTL_GET_DELAY -/* Set raw magnetic vector flag */ #define ECS_IOCTL_APP_SET_MVFLAG _IOW(AKMIO, 0x19, short) -/* Get raw magnetic vector flag */ #define ECS_IOCTL_APP_GET_MVFLAG _IOR(AKMIO, 0x1A, short) -#define ECS_IOCTL_APP_SET_TFLAG _IOR(AKMIO, 0x15, short) - - -struct akm8975_platform_data { - int intr; - int (*init)(void); - void (*exit)(void); - int (*power_on)(void); - int (*power_off)(void); -}; #endif diff --git a/include/linux/kxtik.h b/include/linux/kxtik.h new file mode 100755 index 000000000000..28ef3c732968 --- /dev/null +++ b/include/linux/kxtik.h @@ -0,0 +1,77 @@ +#define KXTIK_DEVID 0x05 //chip id +#define KXTIK_RANGE 2000000 + +#define KXTIK_XOUT_HPF_L (0x00) /* 0000 0000 */ +#define KXTIK_XOUT_HPF_H (0x01) /* 0000 0001 */ +#define KXTIK_YOUT_HPF_L (0x02) /* 0000 0010 */ +#define KXTIK_YOUT_HPF_H (0x03) /* 0000 0011 */ +#define KXTIK_ZOUT_HPF_L (0x04) /* 0001 0100 */ +#define KXTIK_ZOUT_HPF_H (0x05) /* 0001 0101 */ +#define KXTIK_XOUT_L (0x06) /* 0000 0110 */ +#define KXTIK_XOUT_H (0x07) /* 0000 0111 */ +#define KXTIK_YOUT_L (0x08) /* 0000 1000 */ +#define KXTIK_YOUT_H (0x09) /* 0000 1001 */ +#define KXTIK_ZOUT_L (0x0A) /* 0001 1010 */ +#define KXTIK_ZOUT_H (0x0B) /* 0001 1011 */ +#define KXTIK_ST_RESP (0x0C) /* 0000 1100 */ +#define KXTIK_WHO_AM_I (0x0F) /* 0000 1111 */ +#define KXTIK_TILT_POS_CUR (0x10) /* 0001 0000 */ +#define KXTIK_TILT_POS_PRE (0x11) /* 0001 0001 */ +#define KXTIK_INT_SRC_REG1 (0x15) /* 0001 0101 */ +#define KXTIK_INT_SRC_REG2 (0x16) /* 0001 0110 */ +#define KXTIK_STATUS_REG (0x18) /* 0001 1000 */ +#define KXTIK_INT_REL (0x1A) /* 0001 1010 */ +#define KXTIK_CTRL_REG1 (0x1B) /* 0001 1011 */ +#define KXTIK_CTRL_REG2 (0x1C) /* 0001 1100 */ +#define KXTIK_CTRL_REG3 (0x1D) /* 0001 1101 */ +#define KXTIK_INT_CTRL_REG1 (0x1E) /* 0001 1110 */ +#define KXTIK_INT_CTRL_REG2 (0x1F) /* 0001 1111 */ +#define KXTIK_INT_CTRL_REG3 (0x20) /* 0010 0000 */ +#define KXTIK_DATA_CTRL_REG (0x21) /* 0010 0001 */ +#define KXTIK_TILT_TIMER (0x28) /* 0010 1000 */ +#define KXTIK_WUF_TIMER (0x29) /* 0010 1001 */ +#define KXTIK_TDT_TIMER (0x2B) /* 0010 1011 */ +#define KXTIK_TDT_H_THRESH (0x2C) /* 0010 1100 */ +#define KXTIK_TDT_L_THRESH (0x2D) /* 0010 1101 */ +#define KXTIK_TDT_TAP_TIMER (0x2E) /* 0010 1110 */ +#define KXTIK_TDT_TOTAL_TIMER (0x2F) /* 0010 1111 */ +#define KXTIK_TDT_LATENCY_TIMER (0x30) /* 0011 0000 */ +#define KXTIK_TDT_WINDOW_TIMER (0x31) /* 0011 0001 */ +#define KXTIK_WUF_THRESH (0x5A) /* 0101 1010 */ +#define KXTIK_TILT_ANGLE (0x5C) /* 0101 1100 */ +#define KXTIK_HYST_SET (0x5F) /* 0101 1111 */ + +/* CONTROL REGISTER 1 BITS */ +#define KXTIK_DISABLE 0x7F +#define KXTIK_ENABLE (1 << 7) +/* INPUT_ABS CONSTANTS */ +#define FUZZ 3 +#define FLAT 3 +/* RESUME STATE INDICES */ +#define RES_DATA_CTRL 0 +#define RES_CTRL_REG1 1 +#define RES_INT_CTRL1 2 +#define RESUME_ENTRIES 3 + +/* CTRL_REG1: set resolution, g-range, data ready enable */ +/* Output resolution: 8-bit valid or 12-bit valid */ +#define KXTIK_RES_8BIT 0 +#define KXTIK_RES_12BIT (1 << 6) +/* Output g-range: +/-2g, 4g, or 8g */ +#define KXTIK_G_2G 0 +#define KXTIK_G_4G (1 << 3) +#define KXTIK_G_8G (1 << 4) + +/* DATA_CTRL_REG: controls the output data rate of the part */ +#define KXTIK_ODR12_5F 0 +#define KXTIK_ODR25F 1 +#define KXTIK_ODR50F 2 +#define KXTIK_ODR100F 3 +#define KXTIK_ODR200F 4 +#define KXTIK_ODR400F 5 +#define KXTIK_ODR800F 6 + +/* kxtik */ +#define KXTIK_PRECISION 12 +#define KXTIK_BOUNDARY (0x1 << (KXTIK_PRECISION - 1)) +#define KXTIK_GRAVITY_STEP KXTIK_RANGE / KXTIK_BOUNDARY diff --git a/include/linux/l3g4200d.h b/include/linux/l3g4200d.h index 03a5ff018665..c040b5121fe4 100755 --- a/include/linux/l3g4200d.h +++ b/include/linux/l3g4200d.h @@ -54,12 +54,25 @@ #define L3G4200D_FS_500DPS 0x10 #define L3G4200D_FS_2000DPS 0x30 -#define PM_OFF 0x00 -#define PM_NORMAL 0x08 -#define ENABLE_ALL_AXES 0x07 +#define PM_OFF 0x00 +#define PM_NORMAL 0x08 +#define ENABLE_ALL_AXES 0x07 + +/* l3g4200d gyroscope registers */ +#define GYRO_WHO_AM_I 0x0F +#define GYRO_CTRL_REG1 0x20 /* power control reg */ +#define GYRO_CTRL_REG2 0x21 /* power control reg */ +#define GYRO_CTRL_REG3 0x22 /* power control reg */ +#define GYRO_CTRL_REG4 0x23 /* interrupt control reg */ +#define GYRO_CTRL_REG5 0x24 /* interrupt control reg */ +#define GYRO_DATA_REG 0x28 +#define GYRO_INT_SRC 0x31 + + + /*status*/ -#define L3G4200D_SUSPEND 2 +#define L3G4200D_SUSPEND 2 #define L3G4200D_OPEN 1 #define L3G4200D_CLOSE 0 diff --git a/include/linux/sensor-dev.h b/include/linux/sensor-dev.h new file mode 100755 index 000000000000..c087b1bcf8b1 --- /dev/null +++ b/include/linux/sensor-dev.h @@ -0,0 +1,194 @@ +/* include/linux/sensor-dev.h - sensor header file + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + + +#define SENSOR_ON 1 +#define SENSOR_OFF 0 +#define SENSOR_UNKNOW_DATA -1 + +enum sensor_type { + SENSOR_TYPE_NULL, + SENSOR_TYPE_ACCEL, + SENSOR_TYPE_COMPASS, + SENSOR_TYPE_GYROSCOPE, + SENSOR_TYPE_LIGHT, + SENSOR_TYPE_PROXIMITY, + SENSOR_TYPE_TEMPERATURE, + //SENSOR_TYPE_PRESSURE, + SENSOR_NUM_TYPES +}; + +enum sensor_id { + ID_INVALID = 0, + + ACCEL_ID_ALL, + ACCEL_ID_LIS331, + ACCEL_ID_LSM303DLX, + ACCEL_ID_LIS3DH, + ACCEL_ID_KXSD9, + ACCEL_ID_KXTF9, + ACCEL_ID_KXTIK, + ACCEL_ID_BMA150, + ACCEL_ID_BMA222, + ACCEL_ID_BMA250, + ACCEL_ID_ADXL34X, + ACCEL_ID_MMA8450, + ACCEL_ID_MMA845X, + ACCEL_ID_MPU6050, + + COMPASS_ID_ALL, + COMPASS_ID_AK8975, + COMPASS_ID_AK8972, + COMPASS_ID_AMI30X, + COMPASS_ID_AMI306, + COMPASS_ID_YAS529, + COMPASS_ID_YAS530, + COMPASS_ID_HMC5883, + COMPASS_ID_LSM303DLH, + COMPASS_ID_LSM303DLM, + COMPASS_ID_MMC314X, + COMPASS_ID_HSCDTD002B, + COMPASS_ID_HSCDTD004A, + + GYRO_ID_ALL, + GYRO_ID_L3G4200D, + GYRO_ID_K3G, + + LIGHT_ID_ALL, + LIGHT_ID_CM3217, + LIGHT_ID_AL3006, + LIGHT_ID_STK3171, + + PROXIMITY_ID_ALL, + PROXIMITY_ID_AL3006, + PROXIMITY_ID_STK3171, + TEMPERATURE_ID_ALL, + + PRESSURE_ID_ALL, + PRESSURE_ID_BMA085, +}; + + +struct sensor_axis { + int x; + int y; + int z; +}; + +struct sensor_operate { + char *name; + int type; + int id_i2c; + int range[2]; + int read_reg; + int read_len; + int id_reg; + int id_data; + int precision; + int ctrl_reg; + int ctrl_data; + int int_ctrl_reg; + int int_status_reg; + int trig; //intterupt trigger + int (*active)(struct i2c_client *client, int enable, int rate); + int (*init)(struct i2c_client *client); + int (*report)(struct i2c_client *client); + int (*suspend)(struct i2c_client *client); + int (*resume)(struct i2c_client *client); + struct miscdevice *misc_dev; + +}; + + +/* Platform data for the sensor */ +struct sensor_private_data { + int type; + struct i2c_client *client; + struct input_dev *input_dev; + struct work_struct work; + struct delayed_work delaywork; /*report second event*/ + struct sensor_axis axis; + char sensor_data[40]; //max support40 bytes data + atomic_t data_ready; + wait_queue_head_t data_ready_wq; + struct mutex data_mutex; + struct mutex operation_mutex; + struct mutex sensor_mutex; + struct mutex i2c_mutex; + int status_cur; + int start_count; + int devid; + struct i2c_device_id *i2c_id; + struct sensor_platform_data *pdata; + struct sensor_operate *ops; + struct file_operations fops; + struct miscdevice miscdev; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif +}; + + +extern int sensor_register_slave(int type,struct i2c_client *client, + struct sensor_platform_data *slave_pdata, + struct sensor_operate *(*get_sensor_ops)(void)); + + +extern int sensor_unregister_slave(int type,struct i2c_client *client, + struct sensor_platform_data *slave_pdata, + struct sensor_operate *(*get_sensor_ops)(void)); + + +#define GSENSOR_IO 0xA1 +#define GBUFF_SIZE 12 /* Rx buffer size */ + +/* IOCTLs for MMA8452 library */ +#define GSENSOR_IOCTL_INIT _IO(GSENSOR_IO, 0x01) +#define GSENSOR_IOCTL_RESET _IO(GSENSOR_IO, 0x04) +#define GSENSOR_IOCTL_CLOSE _IO(GSENSOR_IO, 0x02) +#define GSENSOR_IOCTL_START _IO(GSENSOR_IO, 0x03) +#define GSENSOR_IOCTL_GETDATA _IOR(GSENSOR_IO, 0x08, char[GBUFF_SIZE+1]) +/* IOCTLs for APPs */ +#define GSENSOR_IOCTL_APP_SET_RATE _IOW(GSENSOR_IO, 0x10, char) + + +#define LIGHTSENSOR_IOCTL_MAGIC 'l' +#define LIGHTSENSOR_IOCTL_GET_ENABLED _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *) +#define LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *) +#define LIGHTSENSOR_IOCTL_DISABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 3, int *) + +#define PSENSOR_IOCTL_MAGIC 'c' +#define PSENSOR_IOCTL_GET_ENABLED _IOR(PSENSOR_IOCTL_MAGIC, 1, int *) +#define PSENSOR_IOCTL_ENABLE _IOW(PSENSOR_IOCTL_MAGIC, 2, int *) +#define PSENSOR_IOCTL_DISABLE _IOW(PSENSOR_IOCTL_MAGIC, 3, int *) + + + + +extern int sensor_rx_data(struct i2c_client *client, char *rxData, int length); +extern int sensor_tx_data(struct i2c_client *client, char *txData, int length); +extern int sensor_write_reg(struct i2c_client *client, int addr, int value); +extern int sensor_read_reg(struct i2c_client *client, int addr); +extern int sensor_tx_data_normal(struct i2c_client *client, char *buf, int num); +extern int sensor_rx_data_normal(struct i2c_client *client, char *buf, int num); +extern int sensor_write_reg_normal(struct i2c_client *client, char value); +extern int sensor_read_reg_normal(struct i2c_client *client); +