add new driver for all sensors

This commit is contained in:
lw 2012-06-13 14:50:24 +08:00
commit 20f9121ccf
32 changed files with 5045 additions and 27 deletions

View file

@ -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;

View file

@ -194,6 +194,7 @@ source "drivers/input/jogball/Kconfig"
source "drivers/input/lightsensor/Kconfig"
source "drivers/input/sensors/Kconfig"
endif

View file

@ -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

19
drivers/input/sensors/Kconfig Executable file
View file

@ -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

10
drivers/input/sensors/Makefile Executable file
View file

@ -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

View file

@ -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

View file

@ -0,0 +1,3 @@
obj-$(CONFIG_GS_KXTIK) += kxtik.o
obj-$(CONFIG_GS_MMA8452) += mma8452.o

View file

@ -0,0 +1,270 @@
/* drivers/input/sensors/access/kxtik.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/kxtik.h>
#include <linux/sensor-dev.h>
#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);

View file

@ -0,0 +1,308 @@
/* drivers/input/sensors/access/mma8452.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/mma8452.h>
#include <linux/sensor-dev.h>
#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);

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,753 @@
/* drivers/input/sensors/access/akm8975.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/akm8975.h>
#include <linux/sensor-dev.h>
#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; i<sensor->ops->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);

View file

@ -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

View file

@ -0,0 +1,4 @@
# gyroscope drivers
obj-$(CONFIG_GYRO_SENSOR_K3G) += k3g.o
obj-$(CONFIG_GYRO_L3G4200D) += l3g4200d.o

View file

@ -0,0 +1,267 @@
/* drivers/input/sensors/access/kxtik.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/l3g4200d.h>
#include <linux/sensor-dev.h>
#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);

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,238 @@
/* drivers/input/sensors/access/kxtik.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/sensor-dev.h>
#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);

View file

@ -0,0 +1,299 @@
/* drivers/input/sensors/access/kxtik.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/sensor-dev.h>
#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);

View file

@ -0,0 +1,301 @@
/* drivers/input/sensors/access/kxtik.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/sensor-dev.h>
#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);

View file

@ -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

View file

@ -0,0 +1,4 @@
# gsensor drivers
obj-$(CONFIG_PS_AL3006) += ps_al3006.o
obj-$(CONFIG_PS_STK3171) += ps_stk3171.o

View file

@ -0,0 +1,260 @@
/* drivers/input/sensors/access/kxtik.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/sensor-dev.h>
#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);

View file

@ -0,0 +1,265 @@
/* drivers/input/sensors/access/kxtik.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/sensor-dev.h>
#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);

1327
drivers/input/sensors/sensor-dev.c Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,234 @@
/* drivers/input/sensors/sensor-i2c.c - sensor i2c handle
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/sensor-dev.h>
#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 = &reg;
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; i<length; i++)
DBG("0x%x,",rxData[i]);
DBG("\n");
#endif
return ret;
}
EXPORT_SYMBOL(sensor_rx_data);
int sensor_tx_data(struct i2c_client *client, char *txData, 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;
#ifdef SENSOR_DEBUG_TYPE
DBG("addr=0x%x,len=%d,txdata:",txData[0],length);
for(i=1; i<length; i++)
DBG("0x%x,",txData[i]);
DBG("\n");
#endif
ret = sensor_i2c_write(client->adapter, 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);

View file

View file

48
include/linux/akm8975.h Normal file → Executable file
View file

@ -6,17 +6,21 @@
#include <linux/ioctl.h>
#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

77
include/linux/kxtik.h Executable file
View file

@ -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

View file

@ -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

194
include/linux/sensor-dev.h Executable file
View file

@ -0,0 +1,194 @@
/* include/linux/sensor-dev.h - sensor header file
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/miscdevice.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#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);