716 lines
19 KiB
C
716 lines
19 KiB
C
/*
|
|
* mma7660.c - Linux kernel modules for 3-Axis Orientation/Motion
|
|
* Detection Sensor
|
|
*
|
|
* Copyright (C) 2009-2010 Freescale Semiconductor Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#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/interrupt.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/hwmon-sysfs.h>
|
|
#include <linux/err.h>
|
|
#include <linux/hwmon.h>
|
|
#include <linux/input-polldev.h>
|
|
#include <linux/device.h>
|
|
#include "../init-input.h"
|
|
|
|
//#include <mach/system.h>
|
|
//#include <mach/hardware.h>
|
|
|
|
//#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
//#include <linux/earlysuspend.h>
|
|
//#endif
|
|
|
|
#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_PM)
|
|
#include <linux/pm.h>
|
|
#endif
|
|
|
|
/*
|
|
* Defines
|
|
*/
|
|
#define assert(expr)\
|
|
if (!(expr)) {\
|
|
printk(KERN_ERR "Assertion failed! %s,%d,%s,%s\n",\
|
|
__FILE__, __LINE__, __func__, #expr);\
|
|
}
|
|
|
|
#define MMA7660_DRV_NAME "mma7660"
|
|
#define SENSOR_NAME MMA7660_DRV_NAME
|
|
#define MMA7660_XOUT 0x00
|
|
#define MMA7660_YOUT 0x01
|
|
#define MMA7660_ZOUT 0x02
|
|
#define MMA7660_TILT 0x03
|
|
#define MMA7660_SRST 0x04
|
|
#define MMA7660_SPCNT 0x05
|
|
#define MMA7660_INTSU 0x06
|
|
#define MMA7660_MODE 0x07
|
|
#define MMA7660_SR 0x08
|
|
#define MMA7660_PDET 0x09
|
|
#define MMA7660_PD 0x0A
|
|
#define MMA7660ADDRESS 0x4c
|
|
|
|
#define POLL_INTERVAL_MAX 500
|
|
#define POLL_INTERVAL 50
|
|
#define INPUT_FUZZ 2
|
|
#define INPUT_FLAT 2
|
|
|
|
#define MK_MMA7660_SR(FILT, AWSR, AMSR)\
|
|
(FILT<<5 | AWSR<<3 | AMSR)
|
|
|
|
#define MK_MMA7660_MODE(IAH, IPP, SCPS, ASE, AWE, TON, MODE)\
|
|
(IAH<<7 | IPP<<6 | SCPS<<5 | ASE<<4 | AWE<<3 | TON<<2 | MODE)
|
|
|
|
#define MK_MMA7660_INTSU(SHINTX, SHINTY, SHINTZ, GINT, ASINT, PDINT, PLINT, FBINT)\
|
|
(SHINTX<<7 | SHINTY<<6 | SHINTZ<<5 | GINT<<4 | ASINT<<3 | PDINT<<2 | PLINT<<1 | FBINT)
|
|
|
|
#define MODE_CHANGE_DELAY_MS 100
|
|
|
|
static struct device *hwmon_dev;
|
|
static struct i2c_client *mma7660_i2c_client;
|
|
|
|
static struct mma7660_data_s {
|
|
struct i2c_client *client;
|
|
struct input_polled_dev *pollDev;
|
|
struct mutex interval_mutex;
|
|
struct mutex init_mutex;
|
|
|
|
|
|
#if defined(CONFIG_PM) || defined(CONFIG_HAS_EARLYSUSPEND)
|
|
volatile int suspend_indator;
|
|
#endif
|
|
} mma7660_data;
|
|
|
|
static struct input_polled_dev *mma7660_idev;
|
|
|
|
/* Addresses to scan */
|
|
static const unsigned short normal_i2c[2] = {MMA7660ADDRESS, I2C_CLIENT_END};
|
|
static __u32 twi_id = 0;
|
|
static struct sensor_config_info gsensor_info = {
|
|
.input_type = GSENSOR_TYPE,
|
|
};
|
|
|
|
enum {
|
|
DEBUG_INIT = 1U << 0,
|
|
DEBUG_CONTROL_INFO = 1U << 1,
|
|
DEBUG_DATA_INFO = 1U << 2,
|
|
DEBUG_SUSPEND = 1U << 3,
|
|
};
|
|
static u32 debug_mask = 0;
|
|
#define dprintk(level_mask, fmt, arg...) if (unlikely(debug_mask & level_mask)) \
|
|
printk(KERN_DEBUG fmt , ## arg)
|
|
|
|
module_param_named(debug_mask, debug_mask, int, 0644);
|
|
|
|
static void mma7660_resume_events(struct work_struct *work);
|
|
static void mma7660_init_events(struct work_struct *work);
|
|
static struct workqueue_struct *mma7660_resume_wq;
|
|
static struct workqueue_struct *mma7660_init_wq;
|
|
static DECLARE_WORK(mma7660_resume_work, mma7660_resume_events);
|
|
static DECLARE_WORK(mma7660_init_work, mma7660_init_events);
|
|
|
|
|
|
|
|
//Function as i2c_master_send, and return 1 if operation is successful.
|
|
static int i2c_write_bytes(struct i2c_client *client, uint8_t *data, uint16_t len)
|
|
{
|
|
struct i2c_msg msg;
|
|
int ret=-1;
|
|
|
|
msg.flags = !I2C_M_RD;
|
|
msg.addr = client->addr;
|
|
msg.len = len;
|
|
msg.buf = data;
|
|
|
|
ret=i2c_transfer(client->adapter, &msg,1);
|
|
return ret;
|
|
}
|
|
static bool gsensor_i2c_test(struct i2c_client * client)
|
|
{
|
|
int ret, retry;
|
|
uint8_t test_data[1] = { 0 }; //only write a data address.
|
|
|
|
for(retry=0; retry < 2; retry++)
|
|
{
|
|
ret =i2c_write_bytes(client, test_data, 1); //Test i2c.
|
|
if (ret == 1)
|
|
break;
|
|
msleep(5);
|
|
}
|
|
|
|
return ret==1 ? true : false;
|
|
}
|
|
|
|
/**
|
|
* gsensor_detect - Device detection callback for automatic device creation
|
|
* return value:
|
|
* = 0; success;
|
|
* < 0; err
|
|
*/
|
|
static int gsensor_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|
{
|
|
struct i2c_adapter *adapter = client->adapter;
|
|
int ret;
|
|
|
|
dprintk(DEBUG_INIT, "%s enter \n", __func__);
|
|
|
|
ret = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA);
|
|
if (!ret)
|
|
return -ENODEV;
|
|
|
|
if(twi_id == adapter->nr){
|
|
pr_info("%s: addr= %x\n",__func__,client->addr);
|
|
|
|
ret = gsensor_i2c_test(client);
|
|
if(!ret){
|
|
pr_info("%s:I2C connection might be something wrong or maybe the other gsensor equipment! \n",__func__);
|
|
return -ENODEV;
|
|
}else{
|
|
pr_info("I2C connection sucess!\n");
|
|
strlcpy(info->type, SENSOR_NAME, I2C_NAME_SIZE);
|
|
return 0;
|
|
}
|
|
|
|
}else{
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
static int mma7660_read_xyz(int idx, s8 *pf)
|
|
{
|
|
s32 result;
|
|
|
|
assert(mma7660_i2c_client);
|
|
result=i2c_smbus_read_byte_data(mma7660_i2c_client, idx+MMA7660_XOUT);
|
|
assert(result>=0);
|
|
if (result&(1<<6)) {
|
|
dprintk(DEBUG_DATA_INFO, "mma7660 read new data\n");
|
|
return -1;
|
|
}
|
|
|
|
*pf = (result&(1<<5)) ? (result|(~0x0000003f)) : (result&0x0000003f);
|
|
|
|
return 0;
|
|
}
|
|
#if 0
|
|
static ssize_t mma7660_delay_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct i2c_client *client = mma7660_i2c_client;
|
|
struct mma7660_data_s *mma7660 = NULL;
|
|
|
|
mma7660 = i2c_get_clientdata(client);
|
|
|
|
|
|
return sprintf(buf, "%d\n", mma7660->pollDev->poll_interval);
|
|
|
|
}
|
|
#endif
|
|
|
|
static ssize_t mma7660_delay_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
|
|
{
|
|
unsigned long data;
|
|
int error;
|
|
struct i2c_client *client = mma7660_i2c_client;
|
|
struct mma7660_data_s *mma7660 = NULL;
|
|
|
|
|
|
mma7660 = i2c_get_clientdata(client);
|
|
|
|
|
|
error = strict_strtoul(buf, 10, &data);
|
|
if (error)
|
|
return error;
|
|
if (data > POLL_INTERVAL_MAX)
|
|
data = POLL_INTERVAL_MAX;
|
|
|
|
mutex_lock(&mma7660->interval_mutex);
|
|
mma7660->pollDev->poll_interval = data;
|
|
mutex_unlock(&mma7660->interval_mutex);
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
static ssize_t mma7660_value_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int i;
|
|
int result = 0;
|
|
s8 xyz[3];
|
|
s16 x, y, z;
|
|
|
|
for (i=0; i<3; i++) {
|
|
result = mma7660_read_xyz(i, &xyz[i]);
|
|
if (result < 0) {
|
|
dprintk(DEBUG_DATA_INFO, "mma7660 read data failed\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* convert signed 8bits to signed 16bits */
|
|
x = (((short)xyz[0]) << 8) >> 8;
|
|
y = (((short)xyz[1]) << 8) >> 8;
|
|
z = (((short)xyz[2]) << 8) >> 8;
|
|
|
|
return sprintf(buf, "x= %d y= %d z= %d\n", x, y, z);
|
|
|
|
}
|
|
|
|
static ssize_t mma7660_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) {
|
|
pr_err("%s strict_strtoul error\n", __FUNCTION__);
|
|
goto exit;
|
|
}
|
|
|
|
if (data) {
|
|
mutex_lock(&mma7660_data.init_mutex);
|
|
error = i2c_smbus_write_byte_data(mma7660_i2c_client, MMA7660_MODE,
|
|
MK_MMA7660_MODE(0, 1, 0, 0, 0, 0, 1));
|
|
mutex_unlock(&mma7660_data.init_mutex);
|
|
assert(error==0);
|
|
#if defined(CONFIG_PM) || defined(CONFIG_HAS_EARLYSUSPEND)
|
|
if (mma7660_data.suspend_indator == 0)
|
|
#endif
|
|
mma7660_idev->input->open(mma7660_idev->input);
|
|
|
|
dprintk(DEBUG_CONTROL_INFO, "mma7660 enable setting active \n");
|
|
} else {
|
|
mma7660_idev->input->close(mma7660_idev->input);
|
|
|
|
mutex_lock(&mma7660_data.init_mutex);
|
|
error = i2c_smbus_write_byte_data(mma7660_i2c_client, MMA7660_MODE,
|
|
MK_MMA7660_MODE(0, 0, 0, 0, 0, 0, 0));
|
|
mutex_unlock(&mma7660_data.init_mutex);
|
|
assert(error==0);
|
|
dprintk(DEBUG_CONTROL_INFO, "mma7660 enable setting inactive \n");
|
|
}
|
|
|
|
return count;
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP,
|
|
NULL, mma7660_enable_store);
|
|
|
|
static DEVICE_ATTR(value, S_IRUGO|S_IWUSR|S_IWGRP,
|
|
mma7660_value_show, NULL);
|
|
|
|
static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP,
|
|
NULL, mma7660_delay_store);
|
|
|
|
static struct attribute *mma7660_attributes[] = {
|
|
&dev_attr_value.attr,
|
|
&dev_attr_enable.attr,
|
|
&dev_attr_delay.attr,
|
|
NULL
|
|
};
|
|
|
|
static struct attribute_group mma7660_attribute_group = {
|
|
.attrs = mma7660_attributes
|
|
};
|
|
|
|
|
|
/*
|
|
* Initialization function
|
|
*/
|
|
static int mma7660_init_client(struct i2c_client *client)
|
|
{
|
|
int result;
|
|
|
|
mma7660_i2c_client = client;
|
|
|
|
mutex_lock(&mma7660_data.init_mutex);
|
|
if(0)
|
|
{
|
|
/*
|
|
* Probe the device. We try to set the device to Test Mode and then to
|
|
* write & verify XYZ registers
|
|
*/
|
|
result = i2c_smbus_write_byte_data(client, MMA7660_MODE,MK_MMA7660_MODE(0, 0, 0, 0, 0, 1, 0));
|
|
assert(result==0);
|
|
mdelay(MODE_CHANGE_DELAY_MS);
|
|
|
|
result = i2c_smbus_write_byte_data(client, MMA7660_XOUT, 0x2a);
|
|
assert(result==0);
|
|
|
|
result = i2c_smbus_write_byte_data(client, MMA7660_YOUT, 0x15);
|
|
assert(result==0);
|
|
|
|
result = i2c_smbus_write_byte_data(client, MMA7660_ZOUT, 0x3f);
|
|
assert(result==0);
|
|
|
|
result = i2c_smbus_read_byte_data(client, MMA7660_XOUT);
|
|
|
|
result= i2c_smbus_read_byte_data(client, MMA7660_YOUT);
|
|
|
|
result= i2c_smbus_read_byte_data(client, MMA7660_ZOUT);
|
|
assert(result=0x3f);
|
|
}
|
|
// Enable Orientation Detection Logic
|
|
result = i2c_smbus_write_byte_data(client,
|
|
MMA7660_MODE, MK_MMA7660_MODE(0, 0, 0, 0, 0, 0, 0)); //enter standby
|
|
assert(result==0);
|
|
|
|
result = i2c_smbus_write_byte_data(client,
|
|
MMA7660_SR, MK_MMA7660_SR(2, 2, 1));
|
|
assert(result==0);
|
|
|
|
result = i2c_smbus_write_byte_data(client,
|
|
MMA7660_INTSU, MK_MMA7660_INTSU(0, 0, 0, 0, 1, 0, 1, 1));
|
|
assert(result==0);
|
|
|
|
result = i2c_smbus_write_byte_data(client,
|
|
MMA7660_SPCNT, 0xA0);
|
|
assert(result==0);
|
|
|
|
result = i2c_smbus_write_byte_data(client,
|
|
MMA7660_MODE, MK_MMA7660_MODE(0, 1, 0, 0, 0, 0, 1));
|
|
assert(result==0);
|
|
mutex_unlock(&mma7660_data.init_mutex);
|
|
|
|
mdelay(MODE_CHANGE_DELAY_MS);
|
|
|
|
mma7660_idev->input->open(mma7660_idev->input);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
static void report_abs(void)
|
|
{
|
|
int i;
|
|
int result = 0;
|
|
s8 xyz[3];
|
|
s16 x, y, z;
|
|
|
|
for (i=0; i<3; i++) {
|
|
result = mma7660_read_xyz(i, &xyz[i]);
|
|
if (result < 0) {
|
|
dprintk(DEBUG_DATA_INFO, "mma7660 read data failed\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* convert signed 8bits to signed 16bits */
|
|
x = (((short)xyz[0]) << 8) >> 8;
|
|
y = (((short)xyz[1]) << 8) >> 8;
|
|
z = (((short)xyz[2]) << 8) >> 8;
|
|
//pr_info("xyz[0] = 0x%hx, xyz[1] = 0x%hx, xyz[2] = 0x%hx. \n", xyz[0], xyz[1], xyz[2]);
|
|
//pr_info("x[0] = 0x%hx, y[1] = 0x%hx, z[2] = 0x%hx. \n", x, y, z);
|
|
|
|
input_report_abs(mma7660_idev->input, ABS_X, x);
|
|
input_report_abs(mma7660_idev->input, ABS_Y, y);
|
|
input_report_abs(mma7660_idev->input, ABS_Z, z);
|
|
|
|
input_sync(mma7660_idev->input);
|
|
|
|
dprintk(DEBUG_DATA_INFO, "x= 0x%hx, y = 0x%hx, z = 0x%hx\n", x, y, z);
|
|
}
|
|
|
|
static void mma7660_dev_poll(struct input_polled_dev *dev)
|
|
{
|
|
report_abs();
|
|
}
|
|
|
|
static void mma7660_init_events (struct work_struct *work)
|
|
{
|
|
int result = 0;
|
|
|
|
result = mma7660_init_client(mma7660_i2c_client);
|
|
assert(result==0);
|
|
if(result != 0)
|
|
{
|
|
printk("<%s> init err !", __func__);
|
|
return;
|
|
}
|
|
dprintk(DEBUG_INIT, "mma7660 init events end\n");
|
|
}
|
|
|
|
/*
|
|
* I2C init/probing/exit functions
|
|
*/
|
|
|
|
static int mma7660_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
int result;
|
|
struct input_dev *idev;
|
|
struct i2c_adapter *adapter;
|
|
struct mma7660_data_s* data = &mma7660_data;
|
|
printk("%s enter\n",__FUNCTION__);
|
|
dprintk(DEBUG_INIT, "mma7660 probe\n");
|
|
mma7660_i2c_client = client;
|
|
adapter = to_i2c_adapter(client->dev.parent);
|
|
result = i2c_check_functionality(adapter,
|
|
I2C_FUNC_SMBUS_BYTE |
|
|
I2C_FUNC_SMBUS_BYTE_DATA);
|
|
assert(result);
|
|
|
|
//result = 1; // debug by lchen
|
|
dprintk(DEBUG_INIT, "<%s> mma7660_init_client result %d\n", __func__, result);
|
|
|
|
hwmon_dev = hwmon_device_register(&client->dev);
|
|
assert(!(IS_ERR(hwmon_dev)));
|
|
|
|
dev_info(&client->dev, "build time %s %s\n", __DATE__, __TIME__);
|
|
|
|
/*input poll device register */
|
|
mma7660_idev = input_allocate_polled_device();
|
|
if (!mma7660_idev) {
|
|
dev_err(&client->dev, "alloc poll device failed!\n");
|
|
result = -ENOMEM;
|
|
return result;
|
|
}
|
|
mma7660_idev->poll = mma7660_dev_poll;
|
|
mma7660_idev->poll_interval = POLL_INTERVAL;
|
|
mma7660_idev->poll_interval_max = POLL_INTERVAL_MAX;
|
|
idev = mma7660_idev->input;
|
|
idev->name = MMA7660_DRV_NAME;
|
|
idev->id.bustype = BUS_I2C;
|
|
idev->evbit[0] = BIT_MASK(EV_ABS);
|
|
mutex_init(&data->interval_mutex);
|
|
mutex_init(&data->init_mutex);
|
|
|
|
input_set_abs_params(idev, ABS_X, -512, 512, INPUT_FUZZ, INPUT_FLAT);
|
|
input_set_abs_params(idev, ABS_Y, -512, 512, INPUT_FUZZ, INPUT_FLAT);
|
|
input_set_abs_params(idev, ABS_Z, -512, 512, INPUT_FUZZ, INPUT_FLAT);
|
|
|
|
result = input_register_polled_device(mma7660_idev);
|
|
if (result) {
|
|
dev_err(&client->dev, "register poll device failed!\n");
|
|
return result;
|
|
}
|
|
mma7660_idev->input->close(mma7660_idev->input);
|
|
|
|
result = sysfs_create_group(&mma7660_idev->input->dev.kobj, &mma7660_attribute_group);
|
|
//result = device_create_file(&mma7660_idev->input->dev, &dev_attr_enable);
|
|
//result = device_create_file(&mma7660_idev->input->dev, &dev_attr_value);
|
|
|
|
if(result) {
|
|
dev_err(&client->dev, "create sys failed\n");
|
|
}
|
|
|
|
data->client = client;
|
|
data->pollDev = mma7660_idev;
|
|
i2c_set_clientdata(client, data);
|
|
|
|
mma7660_init_wq = create_singlethread_workqueue("mma7660_init");
|
|
if (mma7660_init_wq == NULL) {
|
|
printk("create mma7660_init_wq fail!\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Initialize the MMA7660 chip */
|
|
queue_work(mma7660_init_wq, &mma7660_init_work);
|
|
|
|
mma7660_resume_wq = create_singlethread_workqueue("mma7660_resume");
|
|
if (mma7660_resume_wq == NULL) {
|
|
printk("create mma7660_resume_wq fail!\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
mma7660_data.early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
|
|
mma7660_data.early_suspend.suspend = mma7660_early_suspend;
|
|
mma7660_data.early_suspend.resume = mma7660_late_resume;
|
|
register_early_suspend(&mma7660_data.early_suspend);
|
|
mma7660_data.suspend_indator = 0;
|
|
#endif
|
|
dprintk(DEBUG_INIT, "mma7660 probe end\n");
|
|
return result;
|
|
}
|
|
|
|
static int mma7660_remove(struct i2c_client *client)
|
|
{
|
|
int result;
|
|
|
|
mutex_lock(&mma7660_data.init_mutex);
|
|
result = i2c_smbus_write_byte_data(client,MMA7660_MODE, MK_MMA7660_MODE(0, 0, 0, 0, 0, 0, 0));
|
|
assert(result==0);
|
|
mutex_unlock(&mma7660_data.init_mutex);
|
|
|
|
#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
unregister_early_suspend(&mma7660_data.early_suspend);
|
|
#endif
|
|
cancel_work_sync(&mma7660_resume_work);
|
|
destroy_workqueue(mma7660_resume_wq);
|
|
sysfs_remove_group(&mma7660_idev->input->dev.kobj, &mma7660_attribute_group);
|
|
mma7660_idev->input->close(mma7660_idev->input);
|
|
input_unregister_polled_device(mma7660_idev);
|
|
input_free_polled_device(mma7660_idev);
|
|
hwmon_device_unregister(hwmon_dev);
|
|
cancel_work_sync(&mma7660_init_work);
|
|
destroy_workqueue(mma7660_init_wq);
|
|
i2c_set_clientdata(client, NULL);
|
|
|
|
return result;
|
|
}
|
|
static void mma7660_resume_events (struct work_struct *work)
|
|
{
|
|
#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_PM)
|
|
int result = 0;
|
|
dprintk(DEBUG_INIT, "mma7660 device init\n");
|
|
result = mma7660_init_client(mma7660_i2c_client);
|
|
assert(result==0);
|
|
|
|
mutex_lock(&mma7660_data.init_mutex);
|
|
mma7660_data.suspend_indator = 0;
|
|
result = i2c_smbus_write_byte_data(mma7660_i2c_client,
|
|
MMA7660_MODE, MK_MMA7660_MODE(0, 1, 0, 0, 0, 0, 1));
|
|
mutex_unlock(&mma7660_data.init_mutex);
|
|
assert(result==0);
|
|
|
|
mma7660_idev->input->open(mma7660_idev->input);
|
|
|
|
dprintk(DEBUG_INIT, "mma7660 device init end\n");
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
static int mma7660_resume(struct i2c_client *client)
|
|
{
|
|
int result = 0;
|
|
dprintk(DEBUG_SUSPEND, "mma7660 resume\n");
|
|
|
|
if (SUPER_STANDBY == standby_type) {
|
|
queue_work(mma7660_resume_wq, &mma7660_resume_work);
|
|
}
|
|
if (SUPER_STANDBY == standby_type) {
|
|
mutex_lock(&mma7660_data.init_mutex);
|
|
mma7660_data.suspend_indator = 0;
|
|
result = i2c_smbus_write_byte_data(mma7660_i2c_client,
|
|
MMA7660_MODE, MK_MMA7660_MODE(0, 1, 0, 0, 0, 0, 1));
|
|
mutex_unlock(&mma7660_data.init_mutex);
|
|
assert(result==0);
|
|
mma7660_idev->input->open(mma7660_idev->input);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static int mma7660_suspend(struct i2c_client *client, pm_message_t mesg)
|
|
{
|
|
int result;
|
|
dprintk(DEBUG_SUSPEND, "mma7660 suspend\n");
|
|
|
|
flush_workqueue(mma7660_resume_wq);
|
|
|
|
mma7660_idev->input->close(mma7660_idev->input);
|
|
|
|
mutex_lock(&mma7660_data.init_mutex);
|
|
mma7660_data.suspend_indator = 1;
|
|
result = i2c_smbus_write_byte_data(mma7660_i2c_client,
|
|
MMA7660_MODE, MK_MMA7660_MODE(0, 0, 0, 0, 0, 0, 0));
|
|
mutex_unlock(&mma7660_data.init_mutex);
|
|
assert(result==0);
|
|
return result;
|
|
}
|
|
#endif
|
|
/* CONFIG_HAS_EARLYSUSPEND */
|
|
|
|
static const struct i2c_device_id mma7660_id[] = {
|
|
{ MMA7660_DRV_NAME, 1 },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(i2c, mma7660_id);
|
|
|
|
static struct i2c_driver mma7660_driver = {
|
|
.class = I2C_CLASS_HWMON,
|
|
.driver = {
|
|
.name = MMA7660_DRV_NAME,
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = "allwinner,sun50i-gsensor-para",
|
|
},
|
|
.probe = mma7660_probe,
|
|
.remove = mma7660_remove,
|
|
#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
#else
|
|
#ifdef CONFIG_PM
|
|
.suspend = mma7660_suspend,
|
|
.resume = mma7660_resume,
|
|
#endif
|
|
#endif
|
|
.id_table = mma7660_id,
|
|
.detect = gsensor_detect,
|
|
.address_list = normal_i2c,
|
|
};
|
|
|
|
static int __init mma7660_init(void)
|
|
{
|
|
int ret = -1;
|
|
printk("======%s=========. \n", __func__);
|
|
|
|
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__);
|
|
}
|
|
}
|
|
twi_id = gsensor_info.twi_id;
|
|
|
|
dprintk(DEBUG_INIT, "%s i2c twi is %d \n", __func__, twi_id);
|
|
|
|
input_set_power_enable(&(gsensor_info.input_type),1);
|
|
|
|
ret = i2c_add_driver(&mma7660_driver);
|
|
if (ret < 0) {
|
|
printk(KERN_INFO "add mma7660 i2c driver failed\n");
|
|
return -ENODEV;
|
|
}
|
|
dprintk(DEBUG_INIT, "add mma7660 i2c driver\n");
|
|
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void __exit mma7660_exit(void)
|
|
{
|
|
printk(KERN_INFO "remove mma7660 i2c driver.\n");
|
|
i2c_del_driver(&mma7660_driver);
|
|
input_set_power_enable(&(gsensor_info.input_type),0);
|
|
}
|
|
|
|
MODULE_AUTHOR("Chen Gang <gang.chen@freescale.com>");
|
|
MODULE_DESCRIPTION("MMA7660 3-Axis Orientation/Motion Detection Sensor driver");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_VERSION("1.1");
|
|
|
|
module_init(mma7660_init);
|
|
module_exit(mma7660_exit);
|
|
|