462 lines
12 KiB
C
462 lines
12 KiB
C
/* drivers/input/sensors/gyro/Ewtsa.c
|
|
*
|
|
* Copyright (C) 2012-2015 Rockchip Electronics Co., Ltd.
|
|
* Author: zhangaihui <zah@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 <linux/uaccess.h>
|
|
#include <asm/atomic.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/input.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/freezer.h>
|
|
#include <linux/of_gpio.h>
|
|
#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
#include <linux/earlysuspend.h>
|
|
#endif
|
|
#include <linux/sensor-dev.h>
|
|
|
|
/** This define controls compilation of the master device interface */
|
|
/*#define EWTSA_MASTER_DEVICE*/
|
|
/* configurable */
|
|
#define GYRO_MOUNT_SWAP_XY 0 /* swap X, Y */
|
|
#define GYRO_MOUNT_REVERSE_X 0 /* reverse X */
|
|
#define GYRO_MOUNT_REVERSE_Y 0 /* reverse Y */
|
|
#define GYRO_MOUNT_REVERSE_Z 0 /* reverse Z */
|
|
|
|
/* macro defines */
|
|
/*#define CHIP_ID 0x68*/
|
|
#define DEVICE_NAME "ewtsa"
|
|
#define EWTSA_ON 1
|
|
#define EWTSA_OFF 0
|
|
#define SLEEP_PIN 14
|
|
#define DRDY_PIN 12
|
|
#define DIAG_PIN 11
|
|
#define MAX_VALUE 32768
|
|
|
|
/* ewtsa_delay parameter */
|
|
#define DELAY_THRES_MIN 1
|
|
#define DELAY_THRES_1 4
|
|
#define DELAY_THRES_2 9 /* msec x 90% */
|
|
#define DELAY_THRES_3 18
|
|
#define DELAY_THRES_4 45
|
|
#define DELAY_THRES_5 90
|
|
#define DELAY_THRES_6 128
|
|
#define DELAY_THRES_MAX 255
|
|
#define DELAY_DLPF_2 2
|
|
#define DELAY_DLPF_3 3
|
|
#define DELAY_DLPF_4 4
|
|
#define DELAY_DLPF_5 5
|
|
#define DELAY_DLPF_6 6
|
|
#define DELAY_INTMIN_THRES 9
|
|
|
|
#define DATA_RATE_1 0x01
|
|
|
|
/* ewtsa_sleep parameter */
|
|
#define SLEEP_OFF 0
|
|
#define SLEEP_ON 1
|
|
|
|
/* event mode */
|
|
#define EWTSA_POLLING_MODE 0
|
|
#define EWTSA_INTERUPT_MODE 1
|
|
|
|
/* ewtsa register address */
|
|
#define REG_SMPL 0x15
|
|
#define REG_FS_DLPF 0x16
|
|
#define REG_INT_CFG 0x17
|
|
#define REG_INT_STATUS 0x1A
|
|
#define REG_SELF_O_C 0x29
|
|
#define REG_PWR_MGM 0x3E
|
|
#define REG_MBURST_ALL 0xFF
|
|
#define GYRO_DATA_REG 0x1D
|
|
|
|
/* ewtsa register param */
|
|
#define SELF_O_C_ENABLE 0x00
|
|
#define SELF_O_C_DISABLE 0x01
|
|
#define SLEEP_CTRL_ACTIVATE 0x40
|
|
#define SLEEP_CTRL_SLEEP 0x00
|
|
#define INT_CFG_INT_ENABLE 0x01
|
|
#define INT_CFG_INT_DISABLE 0x00
|
|
|
|
/* ewtsa interrupt control */
|
|
#define EWSTA_INT_CLEAR 0x00
|
|
#define EWSTA_INT_SKIP 0x01
|
|
|
|
/* wait time(ms)*/
|
|
#define EWTSA_BOOST_TIME_0 500
|
|
|
|
/* sleep setting range */
|
|
#define EWTSA_SLP_MIN 0
|
|
#define EWTSA_SLP_MAX 1
|
|
|
|
/* delay setting range */
|
|
#define EWTSA_DLY_MIN 1
|
|
#define EWTSA_DLY_MAX 255
|
|
|
|
/* range setting range */
|
|
#define EWTSA_RNG_MIN 0
|
|
#define EWTSA_RNG_MAX 3
|
|
|
|
/* soc setting range */
|
|
#define EWTSA_SOC_MIN 0
|
|
#define EWTSA_SOC_MAX 1
|
|
|
|
/* event setting range */
|
|
#define EWTSA_EVE_MIN 0
|
|
#define EWTSA_EVE_MAX 1
|
|
|
|
/* init param */
|
|
#define SLEEP_INIT_VAL (SLEEP_ON)
|
|
#define DELAY_INIT_VAL 10
|
|
#define RANGE_INIT_VAL 2 /*range 1000*/
|
|
#define DLPF_INIT_VAL (DELAY_DLPF_2)
|
|
#define CALIB_FUNC_INIT_VAL (EWTSA_ON)
|
|
|
|
/*config store counter num*/
|
|
#define CONFIG_COUNTER_MIN (6+9)
|
|
#define CONFIG_COUNTER_MAX (32+9)
|
|
|
|
/*command name */
|
|
#define COMMAND_NAME_SOC 0
|
|
#define COMMAND_NAME_DLY 1
|
|
#define COMMAND_NAME_RNG 2
|
|
#define COMMAND_NAME_EVE 3
|
|
#define COMMAND_NAME_SLP 4
|
|
#define COMMAND_NAME_NUM 5
|
|
|
|
#define EWTSA_delay DELAY_INIT_VAL
|
|
#define EWTSA_range RANGE_INIT_VAL
|
|
#define EWTSA_calib EWTSA_ON
|
|
|
|
/****************operate according to sensor chip:start************/
|
|
static int i2c_read_byte(struct i2c_client *thisClient, unsigned char regAddr, char *pReadData)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = i2c_master_send( thisClient, (char*)®Addr, 1);
|
|
if(ret < 0)
|
|
{
|
|
printk("EWTSA send cAddress=0x%x error!\n", regAddr);
|
|
return ret;
|
|
}
|
|
ret = i2c_master_recv( thisClient, (char*)pReadData, 1);
|
|
if(ret < 0)
|
|
{
|
|
printk("EWTSAread *pReadData=0x%x error!\n", *pReadData);
|
|
return ret;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
static int i2c_write_byte(struct i2c_client *thisClient, unsigned char regAddr, unsigned char writeData)
|
|
{
|
|
char write_data[2] = {0};
|
|
int ret=0;
|
|
|
|
write_data[0] = regAddr;
|
|
write_data[1] = writeData;
|
|
|
|
ret = i2c_master_send(thisClient, write_data, 2);
|
|
if (ret < 0)
|
|
{
|
|
ret = i2c_master_send(thisClient, write_data, 2);
|
|
if (ret < 0)
|
|
{
|
|
printk("EWTSA send regAddr=0x%x error!\n", regAddr);
|
|
return ret;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int ewtsa_system_restart(struct i2c_client *client)
|
|
{
|
|
int err;
|
|
char reg;
|
|
char smpl , dlpf;
|
|
|
|
err = i2c_write_byte(client, ( unsigned char)REG_SELF_O_C, ( unsigned char)SELF_O_C_DISABLE);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
|
|
///Set SMPL register
|
|
if (EWTSA_delay <= ( unsigned char)DELAY_THRES_2) {
|
|
smpl = ( unsigned char)DELAY_INTMIN_THRES;
|
|
}else{
|
|
smpl = ( unsigned char)(EWTSA_delay - ( unsigned char)1);
|
|
}
|
|
err = i2c_write_byte(client, ( unsigned char)REG_SMPL, ( unsigned char)smpl);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
|
|
///Set DLPF register
|
|
if (EWTSA_delay >= ( unsigned char)DELAY_THRES_6){
|
|
dlpf = ( unsigned char)DELAY_DLPF_6;
|
|
}else if (EWTSA_delay >= ( unsigned char)DELAY_THRES_5) {
|
|
dlpf = ( unsigned char)DELAY_DLPF_5;
|
|
}else if (EWTSA_delay >= ( unsigned char)DELAY_THRES_4){
|
|
dlpf = ( unsigned char)DELAY_DLPF_4;
|
|
}else if (EWTSA_delay >= ( unsigned char)DELAY_THRES_3) {
|
|
dlpf = ( unsigned char)DELAY_DLPF_3;
|
|
}else{
|
|
dlpf = ( unsigned char)DELAY_DLPF_2;
|
|
}
|
|
|
|
reg = ( unsigned char)(( unsigned char)(EWTSA_range << 3) | dlpf | ( unsigned char)0x80 ) ;
|
|
|
|
err = i2c_write_byte(client, REG_FS_DLPF, reg);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
|
|
if (EWTSA_calib== EWTSA_ON) {
|
|
printk("EWTSA_set_calibration() start \n");
|
|
err = i2c_write_byte(client,( unsigned char)REG_SELF_O_C, ( unsigned char)SELF_O_C_ENABLE);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
mdelay(500);
|
|
printk("EWTSA_set_calibration() end \n");
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ewtsa_disable(struct i2c_client *client)
|
|
{
|
|
struct sensor_private_data *sensor =
|
|
(struct sensor_private_data *) i2c_get_clientdata(client);
|
|
|
|
gpio_direction_output(sensor->pdata->standby_pin, GPIO_HIGH);
|
|
|
|
DBG("%s: end \n",__func__);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ewtsa_enable(struct i2c_client *client)
|
|
{
|
|
int err;
|
|
struct sensor_private_data *sensor =
|
|
(struct sensor_private_data *) i2c_get_clientdata(client);
|
|
|
|
gpio_direction_output(sensor->pdata->standby_pin, GPIO_LOW);
|
|
err = i2c_write_byte(client, ( unsigned char)REG_PWR_MGM, ( unsigned char)SLEEP_CTRL_ACTIVATE);////0x44
|
|
if (err < 0){
|
|
//return err;
|
|
err = ewtsa_system_restart(client);///restart; only when i2c error
|
|
if (err < 0){
|
|
return err;
|
|
}
|
|
}
|
|
|
|
err = i2c_write_byte(client, ( unsigned char) REG_INT_CFG, ( unsigned char)INT_CFG_INT_ENABLE);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
DBG("%s: end \n",__func__);
|
|
return 0;
|
|
}
|
|
|
|
void gyro_dev_reset(struct i2c_client *client)
|
|
{
|
|
struct sensor_private_data *sensor =
|
|
(struct sensor_private_data *) i2c_get_clientdata(client);
|
|
|
|
|
|
DBG("%s\n",__func__);
|
|
gpio_direction_output(sensor->pdata->standby_pin, GPIO_HIGH);
|
|
msleep(100);
|
|
gpio_direction_output(sensor->pdata->standby_pin, GPIO_LOW);
|
|
msleep(100);
|
|
}
|
|
|
|
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 status = 0;
|
|
*/
|
|
int result = 0;
|
|
if(enable)
|
|
{
|
|
result=ewtsa_enable(client);
|
|
}
|
|
else
|
|
{
|
|
result=ewtsa_disable(client);
|
|
}
|
|
|
|
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;
|
|
char pReadData=0;
|
|
*/
|
|
sensor->status_cur = SENSOR_OFF;
|
|
gyro_dev_reset(client);
|
|
ewtsa_system_restart(client);
|
|
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);
|
|
|
|
if (sensor->status_cur == SENSOR_ON) {
|
|
/* 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);
|
|
}
|
|
|
|
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;
|
|
/* int value = 0; */
|
|
|
|
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++)
|
|
{
|
|
i2c_read_byte(client, sensor->ops->read_reg + i,&buffer[i]);
|
|
}
|
|
#endif
|
|
|
|
x = (short) (((buffer[0]) << 8) | buffer[1]);
|
|
y = (short) (((buffer[2]) << 8) | buffer[3]);
|
|
z = (short) (((buffer[4]) << 8) | buffer[5]);
|
|
|
|
//printk("%s: x=%d y=%d z=%d \n",__func__, x,y,z);
|
|
if (pdata)
|
|
{
|
|
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;
|
|
}
|
|
|
|
gyro_report_value(client, &axis);
|
|
|
|
mutex_lock(&sensor->data_mutex);
|
|
sensor->axis = axis;
|
|
mutex_unlock(&sensor->data_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static struct sensor_operate gyro_ewtsa_ops = {
|
|
.name = "ewtsa",
|
|
.type = SENSOR_TYPE_GYROSCOPE,
|
|
.id_i2c = GYRO_ID_EWTSA,
|
|
.read_reg = GYRO_DATA_REG,
|
|
.read_len = 6,
|
|
.id_reg = -1,
|
|
.id_data = -1,
|
|
.precision = 16,
|
|
.ctrl_reg = REG_PWR_MGM,
|
|
.int_status_reg = REG_INT_STATUS,
|
|
.range = {-32768, 32768},
|
|
.trig = IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
|
.active = sensor_active,
|
|
.init = sensor_init,
|
|
.report = sensor_report_value,
|
|
};
|
|
|
|
/****************operate according to sensor chip:end************/
|
|
static int gyro_ewtsa_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *devid)
|
|
{
|
|
return sensor_register_device(client, NULL, devid, &gyro_ewtsa_ops);
|
|
}
|
|
|
|
static void gyro_ewtsa_remove(struct i2c_client *client)
|
|
{
|
|
sensor_unregister_device(client, NULL, &gyro_ewtsa_ops);
|
|
}
|
|
|
|
static const struct i2c_device_id gyro_ewtsa_id[] = {
|
|
{"ewtsa_gyro", GYRO_ID_EWTSA},
|
|
{}
|
|
};
|
|
|
|
static struct i2c_driver gyro_ewtsa_driver = {
|
|
.probe = gyro_ewtsa_probe,
|
|
.remove = (void *)gyro_ewtsa_remove,
|
|
.shutdown = sensor_shutdown,
|
|
.id_table = gyro_ewtsa_id,
|
|
.driver = {
|
|
.name = "gyro_ewtsa",
|
|
#ifdef CONFIG_PM
|
|
.pm = &sensor_pm_ops,
|
|
#endif
|
|
},
|
|
};
|
|
|
|
module_i2c_driver(gyro_ewtsa_driver);
|
|
|
|
MODULE_AUTHOR("zhangaihui <zah@rock-chips.com>");
|
|
MODULE_DESCRIPTION("ewtsa 3-Axis Gyroscope driver");
|
|
MODULE_LICENSE("GPL");
|