1279 lines
35 KiB
C
1279 lines
35 KiB
C
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/input.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/uaccess.h>
|
|
#include "../init-input.h"
|
|
|
|
#define ALLWINNER_PLATFORM
|
|
//#define ACTIONS_PLATFORM
|
|
#ifdef ALLWINNER_PLATFORM
|
|
#include <linux/sys_config.h>
|
|
#endif
|
|
|
|
// device info
|
|
#define SENSOR_NAME "sc7a30"
|
|
#define SENSOR_I2C_ADDR 0x1D
|
|
#define ABSMIN -512
|
|
#define ABSMAX 512
|
|
#define FUZZ 2
|
|
#define LSG 64
|
|
#define MAX_DELAY 200
|
|
|
|
// constant define
|
|
#define SC7A30_CHIP_ID 0x2A
|
|
#define SC7A30_DATA_READY 0x07
|
|
|
|
#define SC7A30_RANGE_2G 0x00
|
|
#define SC7A30_RANGE_8G 0x01
|
|
|
|
#define SC7A30_MODE_STANDBY 0x07
|
|
#define SC7A30_MODE_ACTIVE 0x47
|
|
|
|
#define SC7A30_RATE_400HZ 0x00
|
|
#define SC7A30_RATE_100HZ 0x01
|
|
|
|
// register define
|
|
#define SC7A30_XOUT 0x29
|
|
#define SC7A30_YOUT 0x2B
|
|
#define SC7A30_ZOUT 0x2D
|
|
#define SC7A30_MODE_REG 0x20
|
|
#define SC7A30_MODE1 0x21
|
|
#define SC7A30_MODE2 0x22
|
|
#define SC7A30_STATUS 0x27
|
|
#define SC7A30_WU_CFG 0X30
|
|
#define SC7A30_WU_SRC 0X31
|
|
#define SC7A30_WU_THS 0X32
|
|
#define SC7A30_WU_DUTATION 0X33
|
|
|
|
#define POLL_INTERVAL_MAX 500
|
|
#define POLL_INTERVAL 50
|
|
#define INPUT_FUZZ 2
|
|
#define INPUT_FLAT 2
|
|
#define SENSORS_INONE 0
|
|
|
|
|
|
#define MODE_CHANGE_DELAY_MS 100
|
|
|
|
// register bits define
|
|
#define SC7A30_RANGE_BIT__POS 7
|
|
#define SC7A30_RANGE_BIT__LEN 1
|
|
#define SC7A30_RANGE_BIT__MSK 0x20
|
|
#define SC7A30_RANGE_BIT__REG SC7A30_MODE_REG
|
|
|
|
#define SC7A30_MODE_BIT__POS 0
|
|
#define SC7A30_MODE_BIT__LEN 7
|
|
#define SC7A30_MODE_BIT__MSK 0x47
|
|
#define SC7A30_MODE_BIT__REG SC7A30_MODE_REG
|
|
|
|
#define SC7A30_RATE_BIT__POS 5
|
|
#define SC7A30_RATE_BIT__LEN 1
|
|
#define SC7A30_RATE_BIT__MSK 0x80
|
|
#define SC7A30_RATE_BIT__REG SC7A30_MODE_REG
|
|
|
|
|
|
#define SC7A30_GET_BITSLICE(regvar, bitname)\
|
|
((regvar & bitname##__MSK) >> bitname##__POS)
|
|
|
|
#define SC7A30_SET_BITSLICE(regvar, bitname, val)\
|
|
((regvar & ~bitname##__MSK) | ((val<<bitname##__POS)&bitname##__MSK))
|
|
|
|
static struct sensor_config_info gsensor_info = {
|
|
.input_type = GSENSOR_TYPE,
|
|
};
|
|
|
|
struct SC7A30_acc{
|
|
s16 x;
|
|
s16 y;
|
|
s16 z;
|
|
} ;
|
|
|
|
struct SC7A30_data {
|
|
struct i2c_client *SC7A30_client;
|
|
struct input_dev *input;
|
|
atomic_t delay;
|
|
atomic_t enable;
|
|
struct mutex enable_mutex;
|
|
struct delayed_work work;
|
|
#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
struct early_suspend early_suspend;
|
|
#endif
|
|
atomic_t position;
|
|
atomic_t calibrated;
|
|
atomic_t fuzz;
|
|
int offset[3];
|
|
};
|
|
|
|
// cfg data : 1-- used
|
|
#define CFG_GSENSOR_USE_CONFIG 1
|
|
|
|
// calibration file path
|
|
#define CFG_GSENSOR_CALIBFILE "/data/data/com.actions.sensor.calib/files/gsensor_calib.txt"
|
|
|
|
/*******************************************
|
|
* for xml cfg
|
|
*******************************************/
|
|
#ifdef ACTIONS_PLATFORM
|
|
#define CFG_GSENSOR_ADAP_ID "gsensor.i2c_adap_id"
|
|
#define CFG_GSENSOR_POSITION "gsensor.position"
|
|
#define CFG_GSENSOR_CALIBRATION "gsensor.calibration"
|
|
#define CFG_GSENSOR_MOD_POSITION "gsensor_"SENSOR_NAME".position"
|
|
extern int get_config(const char *key, char *buff, int len);
|
|
#endif
|
|
|
|
#ifdef ALLWINNER_PLATFORM
|
|
//static union{
|
|
// unsigned short dirty_addr_buf[2];
|
|
// const unsigned short normal_i2c[2];
|
|
//}u_i2c_addr = {{0x00},{SENSOR_I2C_ADDR, I2C_CLIENT_END}};
|
|
static __u32 twi_id = 0;
|
|
static int sc7a30_pin_hd;
|
|
#endif
|
|
/*******************************************
|
|
* end for xml cfg
|
|
*******************************************/
|
|
|
|
//#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
//static void SC7A30_early_suspend(struct early_suspend *h);
|
|
//static void SC7A30_early_resume(struct early_suspend *h);
|
|
//#endif
|
|
|
|
#ifdef ALLWINNER_PLATFORM
|
|
/**
|
|
* gsensor_fetch_sysconfig_para - get config info from sysconfig.fex file.
|
|
* return value:
|
|
* = 0; success;
|
|
* < 0; err
|
|
*/
|
|
/*static int gsensor_fetch_sysconfig_para(void)
|
|
{
|
|
|
|
int ret = -1;
|
|
int device_used = -1;
|
|
__u32 twi_addr = 0;
|
|
char name[I2C_NAME_SIZE];
|
|
script_parser_value_type_t type = SCIRPT_PARSER_VALUE_TYPE_STRING;
|
|
|
|
printk("========%s===================\n", __func__);
|
|
|
|
#if(SENSORS_INONE)
|
|
if(SCRIPT_PARSER_OK != (ret = script_parser_fetch("gsensor_para1", "gsensor_used", &device_used, 1))){
|
|
pr_err("%s: script_parser_fetch err.ret = %d. \n", __func__, ret);
|
|
goto script_parser_fetch_err;
|
|
}
|
|
#else
|
|
if(SCRIPT_PARSER_OK != (ret = script_parser_fetch("gsensor_para", "gsensor_used", &device_used, 1))){
|
|
pr_err("%s: script_parser_fetch err.ret = %d. \n", __func__, ret);
|
|
goto script_parser_fetch_err;
|
|
}
|
|
#endif
|
|
if(1 == device_used){
|
|
#if(SENSORS_INONE)
|
|
if(SCRIPT_PARSER_OK != script_parser_fetch_ex("gsensor_para1", "gsensor_name", (int *)(&name), &type, sizeof(name)/sizeof(int))){
|
|
pr_err("%s: line: %d script_parser_fetch err. \n", __func__, __LINE__);
|
|
goto script_parser_fetch_err;
|
|
}
|
|
#else
|
|
if(SCRIPT_PARSER_OK != script_parser_fetch_ex("gsensor_para", "gsensor_name", (int *)(&name), &type, sizeof(name)/sizeof(int))){
|
|
pr_err("%s: line: %d script_parser_fetch err. \n", __func__, __LINE__);
|
|
goto script_parser_fetch_err;
|
|
}
|
|
#endif
|
|
if(strcmp(SENSOR_NAME, name)){
|
|
pr_err("%s: name %s does not match SENSOR_NAME. \n", __func__, name);
|
|
pr_err(SENSOR_NAME);
|
|
//ret = 1;
|
|
return ret;
|
|
}
|
|
#if(SENSORS_INONE)
|
|
if(SCRIPT_PARSER_OK != script_parser_fetch("gsensor_para1", "gsensor_twi_addr", &twi_addr, sizeof(twi_addr)/sizeof(__u32))){
|
|
pr_err("%s: line: %d: script_parser_fetch err. \n", name, __LINE__);
|
|
goto script_parser_fetch_err;
|
|
}
|
|
#else
|
|
if(SCRIPT_PARSER_OK != script_parser_fetch("gsensor_para", "gsensor_twi_addr", &twi_addr, sizeof(twi_addr)/sizeof(__u32))){
|
|
pr_err("%s: line: %d: script_parser_fetch err. \n", name, __LINE__);
|
|
goto script_parser_fetch_err;
|
|
}
|
|
#endif
|
|
u_i2c_addr.dirty_addr_buf[0] = twi_addr;
|
|
u_i2c_addr.dirty_addr_buf[1] = I2C_CLIENT_END;
|
|
printk("%s: after: gsensor_twi_addr is 0x%x, dirty_addr_buf: 0x%hx. dirty_addr_buf[1]: 0x%hx \n", \
|
|
__func__, twi_addr, u_i2c_addr.dirty_addr_buf[0], u_i2c_addr.dirty_addr_buf[1]);
|
|
#if(SENSORS_INONE)
|
|
if(SCRIPT_PARSER_OK != script_parser_fetch("gsensor_para1", "gsensor_twi_id", &twi_id, 1)){
|
|
pr_err("%s: script_parser_fetch err. \n", name);
|
|
goto script_parser_fetch_err;
|
|
}
|
|
#else
|
|
if(SCRIPT_PARSER_OK != script_parser_fetch("gsensor_para", "gsensor_twi_id", &twi_id, 1)){
|
|
pr_err("%s: script_parser_fetch err. \n", name);
|
|
goto script_parser_fetch_err;
|
|
}
|
|
#endif
|
|
printk("%s: twi_id is %d. \n", __func__, twi_id);
|
|
#if(SENSORS_INONE)
|
|
sc7a30_pin_hd = gpio_request_ex("gsensor_para1",NULL);
|
|
#else
|
|
sc7a30_pin_hd = gpio_request_ex("gsensor_para",NULL);
|
|
#endif
|
|
if (sc7a30_pin_hd==-1) {
|
|
printk("sc7a30 pin request error!\n");
|
|
}
|
|
ret = 0;
|
|
|
|
}else{
|
|
pr_err("%s: gsensor_unused. \n", __func__);
|
|
ret = -1;
|
|
}
|
|
|
|
return ret;
|
|
|
|
script_parser_fetch_err:
|
|
pr_notice("=========script_parser_fetch_err============\n");
|
|
return ret;
|
|
}*/
|
|
/**
|
|
* gsensor_detect - Device detection callback for automatic device creation
|
|
* return value:
|
|
* = 0; success;
|
|
* < 0; err
|
|
*/
|
|
int gsensor_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|
{
|
|
struct i2c_adapter *adapter = client->adapter;
|
|
|
|
if(twi_id == adapter->nr){
|
|
pr_info("%s: Detected chip %s at adapter %d, address 0x%02x\n",
|
|
__func__, SENSOR_NAME, i2c_adapter_id(adapter), client->addr);
|
|
|
|
strlcpy(info->type, SENSOR_NAME, I2C_NAME_SIZE);
|
|
return 0;
|
|
}else{
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int SC7A30_axis_remap(struct i2c_client *client, struct SC7A30_acc *acc);
|
|
|
|
static int SC7A30_smbus_read_byte(struct i2c_client *client,
|
|
unsigned char reg_addr, unsigned char *data)
|
|
{
|
|
s32 dummy;
|
|
dummy = i2c_smbus_read_byte_data(client, reg_addr);
|
|
if (dummy < 0)
|
|
return -1;
|
|
*data = dummy & 0x000000ff;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int SC7A30_smbus_write_byte(struct i2c_client *client,
|
|
unsigned char reg_addr, unsigned char *data)
|
|
{
|
|
s32 dummy;
|
|
dummy = i2c_smbus_write_byte_data(client, reg_addr, *data);
|
|
if (dummy < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int SC7A30_smbus_read_byte_block(struct i2c_client *client,
|
|
unsigned char reg_addr, unsigned char *data, unsigned char len)
|
|
{
|
|
s32 dummy;
|
|
dummy = i2c_smbus_read_i2c_block_data(client, reg_addr, len, data);
|
|
if (dummy < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int SC7A30_smbus_write_byte_block(struct i2c_client *client,
|
|
unsigned char reg_addr, unsigned char *data, unsigned char len)
|
|
{
|
|
s32 dummy;
|
|
dummy = i2c_smbus_write_i2c_block_data(client, reg_addr, len, data);
|
|
if (dummy < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int SC7A30_set_mode(struct i2c_client *client, unsigned char mode)
|
|
{
|
|
int comres = 0;
|
|
unsigned char data = 0;
|
|
|
|
comres = SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
data = SC7A30_SET_BITSLICE(data, SC7A30_MODE_BIT, mode);
|
|
comres += SC7A30_smbus_write_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
|
|
return comres;
|
|
}
|
|
|
|
static int SC7A30_get_mode(struct i2c_client *client, unsigned char *mode)
|
|
{
|
|
int comres = 0;
|
|
unsigned char data = 0;
|
|
|
|
comres = SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
*mode = SC7A30_GET_BITSLICE(data, SC7A30_MODE_BIT);
|
|
|
|
return comres;
|
|
}
|
|
|
|
static int SC7A30_set_range(struct i2c_client *client, unsigned char range)
|
|
{
|
|
int comres = 0;
|
|
unsigned char data = 0;
|
|
unsigned char mode;
|
|
|
|
// save mode
|
|
comres += SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
mode = SC7A30_GET_BITSLICE(data, SC7A30_MODE_BIT);
|
|
if (mode == SC7A30_MODE_ACTIVE) {
|
|
data = SC7A30_SET_BITSLICE(data, SC7A30_MODE_BIT, SC7A30_MODE_STANDBY);
|
|
comres += SC7A30_smbus_write_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
}
|
|
|
|
comres += SC7A30_smbus_read_byte(client, SC7A30_RANGE_BIT__REG, &data);
|
|
data = SC7A30_SET_BITSLICE(data, SC7A30_RANGE_BIT, range);
|
|
comres += SC7A30_smbus_write_byte(client, SC7A30_RANGE_BIT__REG, &data);
|
|
|
|
// restore mode
|
|
if (mode == SC7A30_MODE_ACTIVE) {
|
|
comres += SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
data = SC7A30_SET_BITSLICE(data, SC7A30_MODE_BIT, SC7A30_MODE_ACTIVE);
|
|
comres += SC7A30_smbus_write_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
}
|
|
|
|
return comres;
|
|
}
|
|
|
|
static int SC7A30_get_range(struct i2c_client *client, unsigned char *range)
|
|
{
|
|
int comres = 0;
|
|
unsigned char data = 0;
|
|
|
|
comres = SC7A30_smbus_read_byte(client, SC7A30_RANGE_BIT__REG, &data);
|
|
*range = SC7A30_GET_BITSLICE(data, SC7A30_RANGE_BIT);
|
|
|
|
return comres;
|
|
}
|
|
|
|
static int SC7A30_set_rate(struct i2c_client *client, unsigned char rate)
|
|
{
|
|
int comres = 0;
|
|
unsigned char data = 0;
|
|
unsigned char mode;
|
|
|
|
// save mode
|
|
comres += SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
mode = SC7A30_GET_BITSLICE(data, SC7A30_MODE_BIT);
|
|
if (mode == SC7A30_MODE_ACTIVE) {
|
|
data = SC7A30_SET_BITSLICE(data, SC7A30_MODE_BIT, SC7A30_MODE_STANDBY);
|
|
comres += SC7A30_smbus_write_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
}
|
|
|
|
comres += SC7A30_smbus_read_byte(client, SC7A30_RATE_BIT__REG, &data);
|
|
data = SC7A30_SET_BITSLICE(data, SC7A30_RATE_BIT, rate);
|
|
comres += SC7A30_smbus_write_byte(client, SC7A30_RATE_BIT__REG, &data);
|
|
|
|
// restore mode
|
|
if (mode == SC7A30_MODE_ACTIVE) {
|
|
comres += SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
data = SC7A30_SET_BITSLICE(data, SC7A30_MODE_BIT, SC7A30_MODE_ACTIVE);
|
|
comres += SC7A30_smbus_write_byte(client, SC7A30_MODE_BIT__REG, &data);
|
|
}
|
|
|
|
return comres;
|
|
}
|
|
|
|
static int SC7A30_get_rate(struct i2c_client *client, unsigned char *rate)
|
|
{
|
|
int comres = 0;
|
|
unsigned char data = 0;
|
|
|
|
comres = SC7A30_smbus_read_byte(client, SC7A30_RATE_BIT__REG, &data);
|
|
*rate = SC7A30_GET_BITSLICE(data, SC7A30_RATE_BIT);
|
|
|
|
return comres;
|
|
}
|
|
|
|
|
|
static int SC7A30_hw_init(struct i2c_client *client)
|
|
{
|
|
int comres = 0;
|
|
// sample rate: 100Hz
|
|
comres += SC7A30_set_rate(client, SC7A30_RATE_100HZ);
|
|
|
|
// range: -2G~+2G
|
|
comres += SC7A30_set_range(client, SC7A30_RANGE_2G);
|
|
|
|
return comres;
|
|
}
|
|
|
|
static int SC7A30_read_data(struct i2c_client *client, struct SC7A30_acc *acc)
|
|
{
|
|
s8 px,py,pz;
|
|
s32 result;
|
|
result=i2c_smbus_read_byte_data(client, SC7A30_XOUT);
|
|
px=result&0xff;
|
|
result=i2c_smbus_read_byte_data(client, SC7A30_YOUT);
|
|
py=result&0xff;
|
|
result=i2c_smbus_read_byte_data(client, SC7A30_ZOUT);
|
|
pz=result&0xff;
|
|
acc->x = (((short)px) << 8) >> 8;
|
|
acc->y = (((short)py) << 8) >> 8;
|
|
acc->z = (((short)pz) << 8) >> 8;
|
|
//printk("pga_debug\n");
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t SC7A30_register_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int address, value;
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
sscanf(buf, "[0x%x]=0x%x", &address, &value);
|
|
if (SC7A30_smbus_write_byte(SC7A30->SC7A30_client, (unsigned char)address,
|
|
(unsigned char *)&value) < 0)
|
|
return -EINVAL;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t SC7A30_register_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
size_t count = 0;
|
|
u8 reg[0x32];
|
|
int i;
|
|
|
|
for (i = 0 ; i < 0x32; i++) {
|
|
SC7A30_smbus_read_byte(SC7A30->SC7A30_client, i, reg+i);
|
|
count += sprintf(&buf[count], "0x%x: 0x%x\n", i, reg[i]);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t SC7A30_mode_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
unsigned char data;
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
if (SC7A30_get_mode(SC7A30->SC7A30_client, &data) < 0)
|
|
return sprintf(buf, "Read error\n");
|
|
|
|
return sprintf(buf, "%d\n", data);
|
|
}
|
|
|
|
static ssize_t SC7A30_mode_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned long data;
|
|
int error;
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
error = strict_strtoul(buf, 10, &data);
|
|
if (error)
|
|
return error;
|
|
if (SC7A30_set_mode(SC7A30->SC7A30_client, (unsigned char) data) < 0)
|
|
return -EINVAL;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t SC7A30_rate_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
unsigned char data;
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
if (SC7A30_get_rate(SC7A30->SC7A30_client, &data) < 0)
|
|
return sprintf(buf, "Read error\n");
|
|
|
|
return sprintf(buf, "%d\n", data);
|
|
}
|
|
|
|
static ssize_t SC7A30_rate_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned long data;
|
|
int error;
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
error = strict_strtoul(buf, 10, &data);
|
|
if (error)
|
|
return error;
|
|
if (SC7A30_set_rate(SC7A30->SC7A30_client, (unsigned char) data) < 0)
|
|
return -EINVAL;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t SC7A30_value_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct input_dev *input = to_input_dev(dev);
|
|
struct SC7A30_data *SC7A30 = input_get_drvdata(input);
|
|
struct SC7A30_acc acc;
|
|
int result;
|
|
int retry = 10;
|
|
|
|
while (retry > 0) {
|
|
result = SC7A30_read_data(SC7A30->SC7A30_client, &acc);
|
|
if (result == 0) {
|
|
break;
|
|
}
|
|
retry = retry - 1;
|
|
msleep(20);
|
|
}
|
|
|
|
if (result == 0) {
|
|
SC7A30_axis_remap(SC7A30->SC7A30_client, &acc);
|
|
return sprintf(buf, "%d %d %d\n", acc.x, acc.y, acc.z);
|
|
} else {
|
|
return sprintf(buf, "SC7A30_read_data failed!\n");
|
|
}
|
|
}
|
|
|
|
static ssize_t SC7A30_delay_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
return sprintf(buf, "%d\n", atomic_read(&SC7A30->delay));
|
|
|
|
}
|
|
|
|
static ssize_t SC7A30_delay_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned long data;
|
|
unsigned char rate;
|
|
int error;
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
error = strict_strtoul(buf, 10, &data);
|
|
if (error)
|
|
return error;
|
|
|
|
if (data > MAX_DELAY) {
|
|
data = MAX_DELAY;
|
|
}
|
|
|
|
atomic_set(&SC7A30->delay, (unsigned int) data);
|
|
|
|
// change sample rate
|
|
data = 1000 / data;
|
|
if (data > 200) {
|
|
rate = SC7A30_RATE_400HZ;
|
|
} else if (data > 50) {
|
|
rate = SC7A30_RATE_100HZ;
|
|
}else {
|
|
rate = SC7A30_RATE_100HZ;
|
|
}
|
|
SC7A30_set_rate(SC7A30->SC7A30_client, rate);
|
|
return count;
|
|
}
|
|
|
|
|
|
static ssize_t SC7A30_enable_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
return sprintf(buf, "%d\n", atomic_read(&SC7A30->enable));
|
|
|
|
}
|
|
|
|
static void SC7A30_do_enable(struct device *dev, int enable)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
if (enable) {
|
|
SC7A30_set_mode(SC7A30->SC7A30_client, SC7A30_MODE_ACTIVE);
|
|
schedule_delayed_work(&SC7A30->work,
|
|
msecs_to_jiffies(atomic_read(&SC7A30->delay)));
|
|
} else {
|
|
SC7A30_set_mode(SC7A30->SC7A30_client, SC7A30_MODE_STANDBY);
|
|
cancel_delayed_work_sync(&SC7A30->work);
|
|
}
|
|
}
|
|
|
|
static void SC7A30_set_enable(struct device *dev, int enable)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
int pre_enable = atomic_read(&SC7A30->enable);
|
|
|
|
mutex_lock(&SC7A30->enable_mutex);
|
|
if (enable != pre_enable) {
|
|
SC7A30_do_enable(dev, enable);
|
|
atomic_set(&SC7A30->enable, enable);
|
|
}
|
|
mutex_unlock(&SC7A30->enable_mutex);
|
|
}
|
|
|
|
static ssize_t SC7A30_enable_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned long data;
|
|
int error;
|
|
|
|
error = strict_strtoul(buf, 10, &data);
|
|
if (error)
|
|
return error;
|
|
if ((data == 0) || (data == 1))
|
|
SC7A30_set_enable(dev, data);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t SC7A30_fuzz_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
return sprintf(buf, "%d\n", atomic_read(&SC7A30->fuzz));
|
|
|
|
}
|
|
|
|
static ssize_t SC7A30_fuzz_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned long data;
|
|
int error;
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
error = strict_strtoul(buf, 10, &data);
|
|
if (error)
|
|
return error;
|
|
|
|
atomic_set(&(SC7A30->fuzz), (int) data);
|
|
|
|
if(SC7A30->input != NULL) {
|
|
SC7A30->input->absinfo[ABS_X].fuzz = data;
|
|
SC7A30->input->absinfo[ABS_Y].fuzz = data;
|
|
SC7A30->input->absinfo[ABS_Z].fuzz = data;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t SC7A30_board_position_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int data;
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
data = atomic_read(&(SC7A30->position));
|
|
|
|
return sprintf(buf, "%d\n", data);
|
|
}
|
|
|
|
static ssize_t SC7A30_board_position_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned long data;
|
|
int error;
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
error = strict_strtol(buf, 10, &data);
|
|
if (error)
|
|
return error;
|
|
|
|
atomic_set(&(SC7A30->position), (int) data);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t SC7A30_calibration_run_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
struct SC7A30_acc acc;
|
|
long xyz[3]={0};
|
|
int result,i;
|
|
int retry = 16;
|
|
for(i=0;i<retry;i++)
|
|
{
|
|
result = SC7A30_read_data(SC7A30->SC7A30_client, &acc);
|
|
xyz[0]+=acc.x;
|
|
xyz[1]+=acc.y;
|
|
xyz[2]+=acc.z;
|
|
}
|
|
acc.x=xyz[0]/retry;
|
|
acc.y=xyz[1]/retry;
|
|
acc.z=xyz[2]/retry;
|
|
if (acc.z > 0) {
|
|
acc.z -= LSG;
|
|
}
|
|
else {
|
|
acc.z += LSG;
|
|
}
|
|
/*
|
|
while (retry > 0) {
|
|
result = SC7A30_read_data(SC7A30->SC7A30_client, &acc);
|
|
if (result == 0) {
|
|
break;
|
|
}
|
|
retry = retry - 1;
|
|
msleep(20);
|
|
}
|
|
|
|
if (result == 0) {
|
|
printk(KERN_INFO "data: %d %d %d\n", acc.x, acc.y, acc.z);
|
|
} else {
|
|
printk(KERN_INFO "run calibration failed!\n");
|
|
return count;
|
|
}
|
|
|
|
acc.x = (0 - acc.x) / 2;
|
|
acc.y = (0 - acc.y) / 2;
|
|
if (atomic_read(&SC7A30->position) > 0) {
|
|
acc.z = (LSG - acc.z) / 2;
|
|
} else {
|
|
acc.z = ((-LSG) - acc.z) / 2;
|
|
}
|
|
*/
|
|
printk(KERN_INFO "calibration: %d %d %d\n", acc.x, acc.y, acc.z);
|
|
|
|
SC7A30->offset[0] = acc.x;
|
|
SC7A30->offset[1] = acc.y;
|
|
SC7A30->offset[2] = acc.z;
|
|
printk(KERN_INFO "run calibration finished\n");
|
|
return count;
|
|
}
|
|
|
|
static ssize_t SC7A30_calibration_reset_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
memset(&(SC7A30->offset), 0, sizeof(SC7A30->offset));
|
|
printk(KERN_INFO "reset calibration finished\n");
|
|
return count;
|
|
}
|
|
|
|
static ssize_t SC7A30_calibration_value_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
return sprintf(buf, "%d %d %d\n", SC7A30->offset[0],
|
|
SC7A30->offset[1], SC7A30->offset[2]);
|
|
}
|
|
|
|
static ssize_t SC7A30_calibration_value_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int data[3];
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
|
|
sscanf(buf, "%d %d %d", &data[0], &data[1], &data[2]);
|
|
SC7A30->offset[0] = data[0];
|
|
SC7A30->offset[1] = data[1];
|
|
SC7A30->offset[2] = data[2];
|
|
printk(KERN_INFO "set calibration finished\n");
|
|
return count;
|
|
}
|
|
|
|
static DEVICE_ATTR(reg, 0666,//S_IRUGO|S_IWUSR|S_IWGRP,
|
|
SC7A30_register_show, SC7A30_register_store);
|
|
static DEVICE_ATTR(mode, 0666,//S_IRUGO|S_IWUSR|S_IWGRP,
|
|
SC7A30_mode_show, SC7A30_mode_store);
|
|
static DEVICE_ATTR(rate, 0666,//S_IRUGO|S_IWUSR|S_IWGRP,
|
|
SC7A30_rate_show, SC7A30_rate_store);
|
|
static DEVICE_ATTR(value, 0666,//S_IRUGO,
|
|
SC7A30_value_show, NULL);
|
|
static DEVICE_ATTR(delay, 0666,//S_IRUGO|S_IWUSR|S_IWGRP,
|
|
SC7A30_delay_show, SC7A30_delay_store);
|
|
static DEVICE_ATTR(enable, 0666,//S_IRUGO|S_IWUSR|S_IWGRP,
|
|
SC7A30_enable_show, SC7A30_enable_store);
|
|
static DEVICE_ATTR(fuzz, 0666,//S_IRUGO|S_IWUSR|S_IWGRP,
|
|
SC7A30_fuzz_show, SC7A30_fuzz_store);
|
|
static DEVICE_ATTR(board_position, 0666,//S_IRUGO|S_IWUSR|S_IWGRP,
|
|
SC7A30_board_position_show, SC7A30_board_position_store);
|
|
static DEVICE_ATTR(calibration_run, 0666,//S_IWUSR|S_IWGRP, //calibration_run
|
|
NULL, SC7A30_calibration_run_store);
|
|
static DEVICE_ATTR(calibration_reset, 0666,//S_IWUSR|S_IWGRP,
|
|
NULL, SC7A30_calibration_reset_store);
|
|
static DEVICE_ATTR(calibration_value,0666,//S_IRUGO|S_IWUSR|S_IWGRP,
|
|
SC7A30_calibration_value_show,
|
|
SC7A30_calibration_value_store);
|
|
|
|
static struct attribute *SC7A30_attributes[] = {
|
|
&dev_attr_reg.attr,
|
|
&dev_attr_mode.attr,
|
|
&dev_attr_rate.attr,
|
|
&dev_attr_value.attr,
|
|
&dev_attr_delay.attr,
|
|
&dev_attr_enable.attr,
|
|
&dev_attr_fuzz.attr,
|
|
&dev_attr_board_position.attr,
|
|
&dev_attr_calibration_run.attr,
|
|
&dev_attr_calibration_reset.attr,
|
|
&dev_attr_calibration_value.attr,
|
|
NULL
|
|
};
|
|
|
|
static struct attribute_group SC7A30_attribute_group = {
|
|
.attrs = SC7A30_attributes
|
|
};
|
|
|
|
static int SC7A30_read_file(char *path, char *buf, int size)
|
|
{
|
|
struct file *filp;
|
|
loff_t len, offset;
|
|
int ret=0;
|
|
mm_segment_t fs;
|
|
|
|
filp = filp_open(path, O_RDWR, 0777);
|
|
if (IS_ERR(filp)) {
|
|
ret = PTR_ERR(filp);
|
|
goto out;
|
|
}
|
|
|
|
len = vfs_llseek(filp, 0, SEEK_END);
|
|
if (len > size) {
|
|
len = size;
|
|
}
|
|
|
|
offset = vfs_llseek(filp, 0, SEEK_SET);
|
|
|
|
fs=get_fs();
|
|
set_fs(KERNEL_DS);
|
|
|
|
ret = vfs_read(filp, (char __user *)buf, (size_t)len, &(filp->f_pos));
|
|
|
|
set_fs(fs);
|
|
|
|
filp_close(filp, NULL);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static int SC7A30_load_user_calibration(struct i2c_client *client)
|
|
{
|
|
char buffer[16];
|
|
int ret = 0;
|
|
int data[3];
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
int calibrated = atomic_read(&SC7A30->calibrated);
|
|
|
|
// only calibrate once
|
|
if (calibrated) {
|
|
goto usr_calib_end;
|
|
} else {
|
|
atomic_set(&SC7A30->calibrated, 1);
|
|
}
|
|
|
|
ret = SC7A30_read_file(CFG_GSENSOR_CALIBFILE, buffer, sizeof(buffer));
|
|
if (ret <= 0) {
|
|
printk(KERN_ERR "gsensor calibration file not exist!\n");
|
|
goto usr_calib_end;
|
|
}
|
|
|
|
sscanf(buffer, "%d %d %d", &data[0], &data[1], &data[2]);
|
|
SC7A30->offset[0] = data[0];
|
|
SC7A30->offset[1] = data[1];
|
|
SC7A30->offset[2] = data[2];
|
|
printk(KERN_INFO "user cfg_calibration: %d %d %d\n", data[0], data[1], data[2]);
|
|
|
|
usr_calib_end:
|
|
return ret;
|
|
}
|
|
|
|
static int SC7A30_axis_remap(struct i2c_client *client, struct SC7A30_acc *acc)
|
|
{
|
|
s16 swap;
|
|
struct SC7A30_data *SC7A30 = i2c_get_clientdata(client);
|
|
int position = atomic_read(&SC7A30->position);
|
|
|
|
switch (abs(position)) {
|
|
case 1:
|
|
swap = acc->x;
|
|
acc->x = acc->y;
|
|
acc->y = -swap;
|
|
break;
|
|
case 2:
|
|
acc->x = -(acc->x);
|
|
acc->y = -(acc->y);
|
|
break;
|
|
case 3:
|
|
swap = acc->x;
|
|
acc->x = -acc->y;
|
|
acc->y = swap;
|
|
break;
|
|
case 4:
|
|
break;
|
|
}
|
|
|
|
if (position < 0) {
|
|
acc->z = -(acc->z);
|
|
acc->x = -(acc->x);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void SC7A30_work_func(struct work_struct *work)
|
|
{
|
|
struct SC7A30_data *SC7A30 = container_of((struct delayed_work *)work,
|
|
struct SC7A30_data, work);
|
|
static struct SC7A30_acc acc;
|
|
int result;
|
|
unsigned long delay = msecs_to_jiffies(atomic_read(&SC7A30->delay));
|
|
|
|
SC7A30_load_user_calibration(SC7A30->SC7A30_client);
|
|
|
|
result = SC7A30_read_data(SC7A30->SC7A30_client, &acc);
|
|
acc.x-=SC7A30->offset[0];
|
|
acc.y-=SC7A30->offset[1];
|
|
acc.z-=SC7A30->offset[2];
|
|
if (result == 0) {
|
|
SC7A30_axis_remap(SC7A30->SC7A30_client, &acc);
|
|
|
|
input_report_abs(SC7A30->input, ABS_X, acc.x);
|
|
input_report_abs(SC7A30->input, ABS_Y, -acc.y);
|
|
input_report_abs(SC7A30->input, ABS_Z, acc.z);
|
|
input_sync(SC7A30->input);
|
|
}
|
|
|
|
schedule_delayed_work(&SC7A30->work, delay);
|
|
}
|
|
|
|
static int SC7A30_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
int err = 0;
|
|
struct SC7A30_data *data;
|
|
struct input_dev *dev;
|
|
int cfg_position;
|
|
int cfg_calibration[3];
|
|
|
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
|
printk(KERN_INFO "i2c_check_functionality error\n");
|
|
goto exit;
|
|
}
|
|
data = kzalloc(sizeof(struct SC7A30_data), GFP_KERNEL);
|
|
if (!data) {
|
|
err = -ENOMEM;
|
|
goto exit;
|
|
}
|
|
i2c_set_clientdata(client, data);
|
|
data->SC7A30_client = client;
|
|
mutex_init(&data->enable_mutex);
|
|
|
|
dev = input_allocate_device();
|
|
if (!dev)
|
|
return -ENOMEM;
|
|
dev->name = SENSOR_NAME;
|
|
dev->id.bustype = BUS_I2C;
|
|
|
|
input_set_capability(dev, EV_ABS, ABS_MISC);
|
|
input_set_abs_params(dev, ABS_X, ABSMIN, ABSMAX, FUZZ, 0);
|
|
input_set_abs_params(dev, ABS_Y, ABSMIN, ABSMAX, FUZZ, 0);
|
|
input_set_abs_params(dev, ABS_Z, ABSMIN, ABSMAX, FUZZ, 0);
|
|
input_set_drvdata(dev, data);
|
|
|
|
err = input_register_device(dev);
|
|
if (err < 0) {
|
|
input_free_device(dev);
|
|
goto kfree_exit;
|
|
}
|
|
|
|
data->input = dev;
|
|
|
|
INIT_DELAYED_WORK(&data->work, SC7A30_work_func);
|
|
atomic_set(&data->delay, MAX_DELAY);
|
|
#ifdef ALLWINNER_PLATFORM
|
|
SC7A30_set_enable(&client->dev, 1);
|
|
#endif
|
|
#ifdef ACTIONS_PLATFORM
|
|
atomic_set(&data->enable, 0);
|
|
#endif
|
|
|
|
#ifdef ACTIONS_PLATFORM
|
|
#if CFG_GSENSOR_USE_CONFIG > 0
|
|
/*get xml cfg*/
|
|
err = get_config(CFG_GSENSOR_MOD_POSITION, (char *)(&cfg_position), sizeof(int));
|
|
if (err != 0) {
|
|
err = get_config(CFG_GSENSOR_POSITION, (char *)(&cfg_position), sizeof(int));
|
|
if (err != 0) {
|
|
printk(KERN_ERR"get position %d fail\n", cfg_position);
|
|
goto kfree_exit;
|
|
}
|
|
}
|
|
#else
|
|
cfg_position = -3;
|
|
#endif
|
|
#else
|
|
cfg_position = -3;
|
|
#endif
|
|
atomic_set(&data->position, cfg_position);
|
|
atomic_set(&data->calibrated, 0);
|
|
atomic_set(&data->fuzz, FUZZ);
|
|
|
|
//power on init regs
|
|
err = SC7A30_hw_init(client);
|
|
if (err < 0) {
|
|
printk(KERN_ERR"SC7A30 probe fail! err:%d\n", err);
|
|
goto kfree_exit;
|
|
}
|
|
|
|
err = sysfs_create_group(&data->input->dev.kobj,
|
|
&SC7A30_attribute_group);
|
|
if (err < 0)
|
|
goto error_sysfs;
|
|
|
|
//#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
// data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
|
|
// data->early_suspend.suspend = SC7A30_early_suspend;
|
|
// data->early_suspend.resume = SC7A30_early_resume;
|
|
// register_early_suspend(&data->early_suspend);
|
|
//#endif
|
|
|
|
#ifdef ACTIONS_PLATFORM
|
|
#if CFG_GSENSOR_USE_CONFIG > 0
|
|
/*get xml cfg*/
|
|
err = get_config(CFG_GSENSOR_CALIBRATION, (char *)cfg_calibration, sizeof(cfg_calibration));
|
|
if (err != 0) {
|
|
printk(KERN_ERR"get calibration fail\n");
|
|
goto error_sysfs;
|
|
}
|
|
#else
|
|
memset(cfg_calibration, 0, sizeof(cfg_calibration));
|
|
#endif
|
|
#else
|
|
memset(cfg_calibration, 0, sizeof(cfg_calibration));
|
|
#endif
|
|
|
|
// calibrate offset
|
|
data->offset[0] = (int)cfg_calibration[0];
|
|
data->offset[1] = (int)cfg_calibration[1];
|
|
data->offset[2] = (int)cfg_calibration[2];
|
|
return 0;
|
|
|
|
error_sysfs:
|
|
input_unregister_device(data->input);
|
|
|
|
kfree_exit:
|
|
kfree(data);
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
/*#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
static void SC7A30_early_suspend(struct early_suspend *h)
|
|
{
|
|
// sensor hal will disable when early suspend
|
|
}
|
|
|
|
|
|
static void SC7A30_early_resume(struct early_suspend *h)
|
|
{
|
|
// sensor hal will enable when early resume
|
|
}
|
|
#endif
|
|
*/
|
|
static int SC7A30_remove(struct i2c_client *client)
|
|
{
|
|
struct SC7A30_data *data = i2c_get_clientdata(client);
|
|
|
|
SC7A30_set_enable(&client->dev, 0);
|
|
//#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
// unregister_early_suspend(&data->early_suspend);
|
|
//#endif
|
|
sysfs_remove_group(&data->input->dev.kobj, &SC7A30_attribute_group);
|
|
input_unregister_device(data->input);
|
|
kfree(data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_PM
|
|
|
|
static int SC7A30_suspend(struct device *dev)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *data = i2c_get_clientdata(client);
|
|
|
|
SC7A30_do_enable(dev, 0);
|
|
input_set_power_enable(&(gsensor_info.input_type),0);
|
|
return 0;
|
|
}
|
|
|
|
static int SC7A30_resume(struct device *dev)
|
|
{
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct SC7A30_data *data = i2c_get_clientdata(client);
|
|
|
|
//power on init regs
|
|
SC7A30_hw_init(data->SC7A30_client);
|
|
SC7A30_do_enable(dev, atomic_read(&data->enable));
|
|
input_set_power_enable(&(gsensor_info.input_type),1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
#define SC7A30_suspend NULL
|
|
#define SC7A30_resume NULL
|
|
|
|
#endif*/ /* CONFIG_PM */
|
|
|
|
|
|
static SIMPLE_DEV_PM_OPS(SC7A30_pm_ops, SC7A30_suspend, SC7A30_resume);
|
|
|
|
static const unsigned short SC7A30_addresses[] = {
|
|
SENSOR_I2C_ADDR,
|
|
I2C_CLIENT_END,
|
|
};
|
|
|
|
static const struct i2c_device_id SC7A30_id[] = {
|
|
{ SENSOR_NAME, 0 },
|
|
{ }
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(i2c, SC7A30_id);
|
|
|
|
static const struct of_device_id sc7a30_of_id[] = {
|
|
{ .compatible = "sc7a30",},
|
|
{},
|
|
};
|
|
|
|
|
|
static struct i2c_driver SC7A30_driver = {
|
|
.driver = {
|
|
.owner = THIS_MODULE,
|
|
.name = SENSOR_NAME,
|
|
.pm = &SC7A30_pm_ops,
|
|
.of_match_table = "allwinner,sun50i-gsensor-para",
|
|
},
|
|
.class = I2C_CLASS_HWMON,
|
|
.address_list = SC7A30_addresses,
|
|
.id_table = SC7A30_id,
|
|
.probe = SC7A30_probe,
|
|
.remove = SC7A30_remove,
|
|
|
|
// #ifdef ALLWINNER_PLATFORM
|
|
// .address_list = u_i2c_addr.normal_i2c,
|
|
// #endif
|
|
};
|
|
|
|
static struct i2c_board_info SC7A30_board_info={
|
|
.type = SENSOR_NAME,
|
|
.addr = SENSOR_I2C_ADDR,
|
|
};
|
|
|
|
static struct i2c_client *SC7A30_client;
|
|
|
|
static int __init SC7A30_init(void)
|
|
{
|
|
struct i2c_adapter *i2c_adap;
|
|
unsigned int cfg_i2c_adap_id;
|
|
#ifdef ACTIONS_PLATFORM
|
|
#if CFG_GSENSOR_USE_CONFIG > 0
|
|
int ret;
|
|
|
|
/*get xml cfg*/
|
|
ret = get_config(CFG_GSENSOR_ADAP_ID, (char *)(&cfg_i2c_adap_id), sizeof(unsigned int));
|
|
if (ret != 0) {
|
|
printk(KERN_ERR"get i2c_adap_id %d fail\n", cfg_i2c_adap_id);
|
|
return ret;
|
|
}
|
|
#else
|
|
cfg_i2c_adap_id = 1;
|
|
#endif
|
|
#else
|
|
cfg_i2c_adap_id = 1;
|
|
|
|
#endif
|
|
#ifdef ACTIONS_PLATFORM
|
|
i2c_adap = i2c_get_adapter(cfg_i2c_adap_id);
|
|
SC7A30_client = i2c_new_device(i2c_adap, &SC7A30_board_info);
|
|
i2c_put_adapter(i2c_adap);
|
|
#endif
|
|
#ifdef ALLWINNER_PLATFORM
|
|
int ret ;
|
|
if (input_fetch_sysconfig_para(&(gsensor_info.input_type))){
|
|
printk("%s: err.\n", __func__);
|
|
return -1;
|
|
}else{
|
|
ret = input_init_platform_resource(&(gsensor_info.input_type));
|
|
if (0 != ret){
|
|
printk("%s:ctp_ops.init_platform_resource err. \n", __func__);
|
|
}
|
|
}
|
|
input_set_power_enable(&(gsensor_info.input_type),1);
|
|
twi_id = gsensor_info.twi_id;
|
|
printk("%s i2c twi is %d \n", __func__, twi_id);
|
|
SC7A30_driver.detect = gsensor_detect;
|
|
|
|
#endif
|
|
|
|
return i2c_add_driver(&SC7A30_driver);
|
|
}
|
|
|
|
static void __exit SC7A30_exit(void)
|
|
{
|
|
#ifdef ACTIONS_PLATFORM
|
|
i2c_unregister_device(SC7A30_client);
|
|
#endif
|
|
i2c_del_driver(&SC7A30_driver);
|
|
input_free_platform_resource(&(gsensor_info.input_type));
|
|
}
|
|
|
|
MODULE_AUTHOR("zhiyi quan <quanzhiyi@silan.com.cn>");
|
|
MODULE_DESCRIPTION("SC7A30 3-Axis Orientation/Motion Detection Sensor driver");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
module_init(SC7A30_init);
|
|
module_exit(SC7A30_exit);
|
|
|