#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/wakelock.h>
#include <linux/ioctl.h>
#include <linux/ctype.h>
#include <linux/timer.h>
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#endif
#define DRV_NAME "adxl345"
#define DRIVER_VERSION "1.0"
#define IRQ 57
#define I2C_ADDR 0x53
#define DEVID 0x00
#define THRESH_TAP 0x1D
#define OFSX 0x1E
#define OFSY 0x1F
#define OFSZ 0x20
#define DUR 0x21
#define LATENT 0x22
#define Window 0x23
#define THRESH_ACT 0x24
#define THRESH_INACT 0x25
#define TIME_INACT 0x26
#define ACT_INACT_CTL 0x27
#define THRESH_FF 0x28
#define TIME_FF 0x29
#define TAP_AXES 0x2A
#define ACT_TAP_STATUS 0x2B
#define BW_RATE 0x2C
#define POWER_CTL 0x2D
#define INT_ENABLE 0x2E
#define INT_MAP 0x2F
#define INT_SOURCE 0x30
#define DATA_FORMAT 0x31
#define DATAX0 0x32
#define DATAX1 0x33
#define DATAY0 0x34
#define DATAY1 0x35
#define DATAZ0 0x36
#define DATAZ1 0x37
#define FIFO_CTL 0x38
#define FIFO_STATUS 0x39
#define THRESH_TAP_VAL 0x50
#define DUR_VAL 0x40
#define LATENT_VAL 0x20
#define Window_VAL 0xF0
#define THRESH_ACT_VAL 1
#define THRESH_INACT_VAL 4
#define TIME_INACT_VAL 1
#define ACT_INACT_CTL_VAL 0xF0
#define THRESH_FF_VAL 8
#define TIME_FF_VAL 0x20
#define TAP_AXES_VAL 0x00
#define BW_RATE_VAL 0x09 // 0x0A
#define POWER_CTL_VAL 0x0B
#define INT_ENABLE_VAL 0x80
#define INT_MAP_VAL 0x00
#define DATA_FORMAT_VAL 0x0B
#define FIFO_CTL_VAL 0x00
#define DELAY 3*HZ
static struct wake_lock gsensor_wake_lock;
struct adxl345_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct mutex lock;
struct mutex wlock;
int enable;
int running;
int wakelock;
struct work_struct work;
struct work_struct watch_work;
#if defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif
u32 irq; /* IRQ number */
s16 x;
s16 y;
s16 z;
};
static struct i2c_adapter *this_adapter;
static struct i2c_client *this_client;
static struct adxl345_data * this_data;
static struct timer_list watch_timer;
static int live = 0;
static int adxl345_i2c_write(struct i2c_client *client,
u8 reg, u8 val)
{
struct adxl345_data *data = i2c_get_clientdata(client);
int ret = 0;
mutex_lock(&data->lock);
ret = i2c_smbus_write_byte_data(client, reg, val);
mutex_unlock(&data->lock);
return ret;
}
static int adxl345_i2c_read_block(struct i2c_client *client,
u8 addr, u8 *buf, int len)
{
struct i2c_msg msgs[2];
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = &addr;
msgs[1].addr = client->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = len;
msgs[1].buf = buf;
if (i2c_transfer(client->adapter, msgs, 2) < 0) {
pr_err("%s:i2c_transfer failed!\n", __func__);
return -EIO;
}
return 0;
}
static irqreturn_t gs_irq(int irq, void *dev_id)
{
struct adxl345_data *data = (struct adxl345_data *)dev_id;
if (data == NULL){
pr_err("%s:get data failed!!!!!", __func__);
}
live = 1;
schedule_work(&data->work);
return IRQ_HANDLED;
}
static void work_func(struct work_struct *work)
{
struct adxl345_data *data = container_of(work, struct adxl345_data, work);
u8 buf[6];
u8 source;
source = i2c_smbus_read_byte_data(data->client, INT_SOURCE);
adxl345_i2c_read_block(data->client, DATAX0, buf, 6);
data->x = (buf[1] << 8) | buf[0];
data->y = (buf[3] << 8) | buf[2];
data->z = (buf[5] << 8) | buf[4];
input_report_abs(data->input_dev, ABS_X, -(data->x));
input_report_abs(data->input_dev, ABS_Y, data->y);
input_report_abs(data->input_dev, ABS_Z, data->z);
input_sync(data->input_dev);
}
static int adxl345_init_reg(struct i2c_client *client)
{
int ret = 0;
ret = adxl345_i2c_write(client, BW_RATE, BW_RATE_VAL);
ret = adxl345_i2c_write(client, DATA_FORMAT, DATA_FORMAT_VAL);
ret = adxl345_i2c_write(client, FIFO_CTL, FIFO_CTL_VAL);
ret = adxl345_i2c_write(client, INT_ENABLE, INT_ENABLE_VAL);
ret = adxl345_i2c_write(client, POWER_CTL, POWER_CTL_VAL);
return ret;
}
static void watch_work_func(struct work_struct *work)
{
adxl345_i2c_write(this_data->client, POWER_CTL, 0x07);
msleep(10);
adxl345_init_reg(this_data->client);
printk("gsensor %s\n",__func__);
}
static int adxl345_open(struct input_dev *dev)
{
/*
struct adxl345_data * data=input_get_drvdata(dev);
u8 buf[6], int_s;
adxl345_init_reg(data->client);
int_s = i2c_smbus_read_byte_data(data->client, INT_SOURCE);
adxl345_i2c_read_block(data->client, DATAX0, &buf, 6);
enable_irq(data->irq);
*/
return 0;
}
static void adxl345_close(struct input_dev *dev)
{
/*
struct adxl345_data * data=input_get_drvdata(dev);
disable_irq_nosync(data->irq);
adxl345_i2c_write( data->client, POWER_CTL, 0x07);
*/
return ;
}
#ifdef CONFIG_PM
static int adxl345_suspend(struct i2c_client *client, pm_message_t state)
{
del_timer_sync(&watch_timer);
/*
printk("hujl@debug:%s enter suspend!\n", __func__);
struct adxl345_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev =data->input_dev;
mutex_lock(&input_dev->mutex);
if(input_dev->users)
{
disable_irq_nosync(data->irq);
adxl345_i2c_write(client, POWER_CTL, 0x07);
}
mutex_unlock(&input_dev->mutex);
*/
return 0;
}
static int adxl345_resume(struct i2c_client *client)
{
/*
printk("hujl@debug:%s enter resume!\n", __func__);
u8 buf[6], int_s;
struct adxl345_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev =data->input_dev;
mutex_lock(&input_dev->mutex);
if(input_dev->users)
{
adxl345_init_reg(data->client);
int_s = i2c_smbus_read_byte_data(data->client, INT_SOURCE);
adxl345_i2c_read_block(client, DATAX0, &buf, 6);
enable_irq(data->irq);
}
mutex_unlock(&input_dev->mutex);
*/
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void adxl345_early_suspend(struct early_suspend *h)
{
struct adxl345_data *data = container_of(h, struct adxl345_data, early_suspend);
adxl345_suspend(data->client, PMSG_SUSPEND);
}
static void adxl345_late_resume(struct early_suspend *h)
{
struct adxl345_data *data = container_of(h, struct adxl345_data, early_suspend);
adxl345_resume(data->client);
}
#endif
#else
#define adxl345_suspend NULL
#define adxl345_resume NULL
#endif
static ssize_t gsensor_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
ssize_t ret = -EINVAL;
char *after;
int int_s;
unsigned long state = simple_strtoul(buf, &after, 10);
size_t count = after - buf;
u8 tbuf[6];
printk("%s %s\n",__func__,buf);
if (*after && isspace(*after))
count++;
if (count == size) {
ret=count;
if(state>0)
{
mutex_lock(&this_data->wlock);
// this_data->enable++;
if(this_data->enable==0)
{
this_data->enable=1;
adxl345_init_reg(this_data->client);
int_s = i2c_smbus_read_byte_data(this_data->client, INT_SOURCE);
adxl345_i2c_read_block(this_data->client, DATAX0, tbuf, 6);
enable_irq(this_data->irq);
watch_timer.expires=jiffies + DELAY;
watch_timer.data = 1;
add_timer(&watch_timer);
}
mutex_unlock(&this_data->wlock);
}
else
if(state==0)
{
mutex_lock(&this_data->wlock);
if(this_data->enable>0)
{
// this_data->enable--;
this_data->enable=0;
{
disable_irq_nosync(this_data->irq);
adxl345_i2c_write(this_data->client, POWER_CTL, 0x07);
}
watch_timer.data = 0;
del_timer_sync(&watch_timer);
}
mutex_unlock(&this_data->wlock);
}
}
return ret;
}
static ssize_t gsensor_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", this_data->enable);
}
static ssize_t gsensor_wakelock_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
ssize_t ret = -EINVAL;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
size_t count = after - buf;
printk("%s %s\n",__func__,buf);
if (*after && isspace(*after))
count++;
if (count == size) {
ret = count;
if(state>0)
{
mutex_lock(&this_data->wlock);
if(this_data->wakelock==0)
{
this_data->wakelock=1;
wake_lock(&gsensor_wake_lock);
}
mutex_unlock(&this_data->wlock);
}
else
if(state==0)
{
mutex_lock(&this_data->wlock);
if(this_data->wakelock==1)
{
this_data->wakelock=0;
wake_unlock(&gsensor_wake_lock);
}
mutex_unlock(&this_data->wlock);
}
}
return ret;
}
static ssize_t gsensor_wakelock_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n",this_data->wakelock);
}
static DEVICE_ATTR(wakelock, 0666, gsensor_wakelock_show, gsensor_wakelock_store);
static DEVICE_ATTR(enable, 0666, gsensor_enable_show, gsensor_enable_store);
void watch_timer_function(unsigned long arg)
{
int add = arg;
if((this_data->enable == 1) && (live == 0))
schedule_work(&this_data->watch_work);
live = 0;
if(add == 1)
{
watch_timer.expires = jiffies + DELAY;
add_timer(&watch_timer);
}
// printk("%s:\n", __func__);
return;
}
void watch_timer_init(void)
{
init_timer(&watch_timer);
watch_timer.function = watch_timer_function;
watch_timer.expires = jiffies + DELAY;
watch_timer.data = 0;
}
static int adxl345_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err = 0;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct adxl345_data *data;
int status;
printk("%s:\n", __func__);
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
return -EIO;
data = kzalloc(sizeof(struct adxl345_data), GFP_KERNEL);
if (!data) {
pr_err("%s:get memory failed!\n", __func__);
return -ENOMEM;
}
data->client = client;
i2c_set_clientdata(client, data);
mutex_init(&data->lock);
mutex_init(&data->wlock);
data->input_dev = input_allocate_device();
if (!data->input_dev) {
pr_err("%s:input device allocate failed!\n", __func__);
goto err_free;
}
data->input_dev->name = "g-sensor";
data->input_dev->id.bustype = BUS_I2C;
data->input_dev->close=adxl345_close;
data->input_dev->open =adxl345_open;
input_set_drvdata(data->input_dev, data);
data->input_dev->evbit[0] = BIT_MASK(EV_ABS);
data->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) |
BIT(ABS_Z);
input_set_abs_params(data->input_dev, ABS_X, -32767, 32767, 0, 0);
input_set_abs_params(data->input_dev, ABS_Y, -32767, 32767, 0, 0);
input_set_abs_params(data->input_dev, ABS_Z, -32767, 32767, 0, 0);
err = input_register_device(data->input_dev);
if (err){
pr_err("%s: Cannot register input (%d)\n", __func__, err);
goto err_free_inputdev;
}
INIT_WORK(&data->work, work_func);
INIT_WORK(&data->watch_work, watch_work_func);
this_data = data;
err = gpio_request(IRQ, "adxl345_irq");
if (err) {
pr_err("request_gpio failed! err = %d\n", err);
goto err_unregister_input_dev;
}
gpio_tlmm_config(GPIO_CFG(IRQ, 0, GPIO_INPUT,
GPIO_PULL_DOWN, GPIO_8MA), GPIO_ENABLE);
data->irq = MSM_GPIO_TO_INT(IRQ);
err = request_irq(data->irq, gs_irq, IRQF_TRIGGER_RISING, "adxl345", data);
if (err){
pr_err("request irq failed! err = %d\n", err);
goto err_free_gpio;
}
disable_irq_nosync(data->irq);
/*
err = adxl345_init_reg(client);
if (err) {
pr_err("init registers failed! err = %d\n", err);
goto err_free_irq;
}
*/
#ifdef CONFIG_HAS_EARLYSUSPEND
data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
data->early_suspend.suspend = adxl345_early_suspend;
data->early_suspend.resume = adxl345_late_resume;
register_early_suspend(&data->early_suspend);
#endif
dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION);
status=device_create_file(&data->input_dev->dev ,&dev_attr_enable);
if(status)
{
goto err_free_irq;
}
status=device_create_file(&data->input_dev->dev ,&dev_attr_wakelock);
if(status)
{
device_remove_file(&data->input_dev->dev ,&dev_attr_enable);
goto err_free_irq;
}
wake_lock_init(&gsensor_wake_lock, WAKE_LOCK_SUSPEND, "gsensor");
watch_timer_init();
return 0;
err_free_irq:
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&data->early_suspend);
#endif
free_irq(data->irq, data);
err_free_gpio:
gpio_free(IRQ);
err_unregister_input_dev:
input_unregister_device(data->input_dev);
err_free_inputdev:
input_free_device(data->input_dev);
err_free:
kfree(data);
return err;
}
static int __devexit adxl345_remove(struct i2c_client *client)
{
struct adxl345_data *data = i2c_get_clientdata(client);
wake_lock_destroy(&gsensor_wake_lock);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&data->early_suspend);
#endif
free_irq(data->irq, data);
gpio_free(IRQ);
cancel_work_sync(&data->work);
input_unregister_device(data->input_dev);
this_data=NULL;
kfree(data);
return 0;
}
static const struct i2c_device_id adxl345_id[] = {
{"adxl345", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, adxl345_id);
static struct i2c_driver adxl345_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
.probe = adxl345_probe,
.remove = adxl345_remove,
.id_table = adxl345_id,
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = adxl345_suspend,
.resume = adxl345_resume,
#endif
};
static int __init adxl345_init(void)
{
struct i2c_board_info info[]= {
{ I2C_BOARD_INFO("adxl345", I2C_ADDR), },
};
printk("%s:\n", __func__);
this_adapter = i2c_get_adapter(0);
if (!this_adapter) {
printk("%s: i2c_get_adapter failed\n", __func__);
return PTR_ERR(this_adapter);
}
this_client = i2c_new_device(this_adapter, info);
if (!this_client) {
printk("%s: i2c_new_device failed\n", __func__);
return PTR_ERR(this_client);
} else {
this_client->adapter = this_adapter;
printk("%s: this_client = 0x%p \n", __func__, this_client);
}
return i2c_add_driver(&adxl345_driver);
}
static void __exit adxl345_exit(void)
{
i2c_del_driver(&adxl345_driver);
i2c_unregister_device(this_client);
}
MODULE_AUTHOR("Gening.Hu ");
MODULE_DESCRIPTION("adxl345");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRIVER_VERSION);
module_init(adxl345_init);
module_exit(adxl345_exit);
|