如何v3s linux系统中注册一个轮询设备去上报键值

下面是纯liux系统中,注册一个轮询设备,轮询上报键值的例子;

同样的,再MTK平台搜input_register_polled_device,也可以在input子系统下面找到相关的例子;

/*
 *  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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

//#include
#include

#ifdef CONFIG_HAS_EARLYSUSPEND
#include
#endif

#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_PM)
#include
#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           0x68//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;
    
#ifdef CONFIG_HAS_EARLYSUSPEND
    struct early_suspend early_suspend;
#endif
#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);

#ifdef CONFIG_HAS_EARLYSUSPEND
static void mma7660_early_suspend(struct early_suspend *h);
static void mma7660_late_resume(struct early_suspend *h);
#endif

//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;
}


static int tsm12_i2c_read(u8 reg)
{
    
    unsigned char val[1] = {0};
    int ret = 0;

    val[0] = reg;

    //printk(" fm  --- tsm12_i2c_read::i2c_master_send START!!! val[0]=%d!\n", val[0]);
    ret = i2c_master_send(mma7660_i2c_client, val, 1);
    printk(" fm  --- tsm12_i2c_read::i2c_master_send ret=%d, val[0]=%d!\n", ret, val[0]);
    if (ret < 0) 
    {
        printk(" fm  --- tsm12_i2c_read I2C i/o error ret = %d\n", ret);
        return ret;
    }
    printk(" fm  --- i2c_master_send I2C i/o is sucessed add by ccy ret = %d\n", ret);
    

    mdelay(10);

    //printk(" fm  --- tsm12_i2c_read::i2c_master_recv START!!! val[0]=%d!\n", val[0]);
    ret = i2c_master_recv(mma7660_i2c_client, val, 1);
    printk(" fm  --- tsm12_i2c_read::i2c_master_recv ret=%d, val[0]=%d!\n", ret, val[0]);

    if (ret < 0) 
    {
        printk(" fm  --- tsm12_i2c_read I2C read error ret = %d\n", ret);
        return ret;
    }
    printk(" fm  --- i2c_master_recv I2C read successd add by ccy ret = %d, val = %x\n", ret,val[0]);
    

    return val[0];
}
 
 static int tsm12_i2c_write(u8 reg, u8 writedata)
{
    //struct i2c_adapter *adapter = client->adapter;
    u8 databuf[2] = {0};
    int ret = 0;
    databuf[0] = reg;
    databuf[1] = writedata;
    
    ret = i2c_master_send(mma7660_i2c_client, databuf, 2);
    printk(" fm  --- tsm12_i2c_write ret=%d, databuf[0]=%X, databuf[1]=%X\n", ret, databuf[0], databuf[1]);
    
    if(ret < 0)
    {
        printk(" fm  --- tsm12_i2c_write send data failed !\n");
        return -1;
    }

    return ret;
}
/*
 int tsm12_Initial1(void)
 {
 
    msleep(50);
       tsm12_i2c_write(0x09, 0x0B);
    msleep(50);
    tsm12_i2c_write(0x08, 0x33);
    tsm12_i2c_write(0x0A, 0x00);
    tsm12_i2c_write(0x0B, 0x00);
    tsm12_i2c_write(0x0C, 0x00);
    tsm12_i2c_write(0x0D, 0x00);
    tsm12_i2c_write(0x09, 0x07);
 }*/
 

  int tsm12_Initial1(void)
 {
     /*
    msleep(50);
    //gpio_direction_output(config_info.wakeup_gpio.gpio, 0);
   // msleep(50);
    tsm12_i2c_write(0x09, 0x0F);
    msleep(50);
    tsm12_i2c_write(0x09, 0x0B);//鲁玫脢录禄炉 脭脢脨铆脠铆录镁赂麓脦禄 脭脢脨铆脠铆录镁脨脻脙脽    
    msleep(1);
    tsm12_i2c_write(0x02, 0xBB);  //0xBB   //脜盲脰脙 脥篓碌脌1 脥篓碌脌2 脕茅脙么露脠
    tsm12_i2c_write(0x03, 0xBB);  //0xBB   //脜盲脰脙 脥篓碌脌3 脥篓碌脌4 脕茅脙么露脠
    tsm12_i2c_write(0x04, 0xBB);  //0xBB   //脜盲脰脙 脥篓碌脌5 脥篓碌脌6 脕茅脙么露脠
    tsm12_i2c_write(0x05, 0xBB);  //0xBB   //脜盲脰脙 脥篓碌脌7 脥篓碌脌8 脕茅脙么露脠
    tsm12_i2c_write(0x06, 0xBB);  //0xBB   //脜盲脰脙 脥篓碌脌9 脥篓碌脌10 脕茅脙么露脠
    tsm12_i2c_write(0x07, 0xBB);  //0xBB   //脜盲脰脙 脥篓碌脌11 脥篓碌脌12 脕茅脙么露脠//    
    tsm12_i2c_write(0x08,0x6B);//脫脙脫脷陆碌碌脥脕茅脙么露脠
    tsm12_i2c_write(0x0A, 0x00);//脜盲脰脙
    tsm12_i2c_write(0x0B, 0x00);//脜盲脰脙 
    tsm12_i2c_write(0x0C, 0x00);//脜盲脰脙 
    tsm12_i2c_write(0x0D, 0x00);//脜盲脰脙
    // S/W Reset OFF
    tsm12_i2c_write(0x09, 0x03);// 赂麓脦禄潞脥脨脻脙脽驴陋鹿脴录脛麓忙脝梅碌脴脰路   脜盲脰脙 赂麓脦禄潞脥脨脻脙脽 驴脴脰脝驴陋鹿脴  1麓貌驴陋 0鹿脴卤脮
    
    //
//    msleep(50);
//    tsm12_i2c_read(0x09);
//    tsm12_i2c_read(0x08);
//    gpio_direction_output(config_info.wakeup_gpio.gpio, 1);
*/

    tsm12_i2c_write(0x09, 0x0F);
    msleep(50);
    tsm12_i2c_write(0x09, 0x0B);//初始化 允许软件复位 允许软件休眠    
    msleep(1);  
    tsm12_i2c_write(0x02, 0xBB);  //0xBB   //配置 通道1 通道2 灵敏度,灵敏度低四位全为0是最高全为1最低
    tsm12_i2c_write(0x03, 0xBB);  //0xBB   //配置 通道3 通道4 灵敏度
    tsm12_i2c_write(0x04, 0xBB);  //0xBB   //配置 通道5 通道6 灵敏度
    tsm12_i2c_write(0x05, 0xBB);  //0xBB   //配置 通道7 通道8 灵敏度
    tsm12_i2c_write(0x06, 0xBB);  //0xBB   //配置 通道9 通道10 灵敏度
    tsm12_i2c_write(0x07, 0xBB);  //0xBB   //配置 通道11 通道12 灵敏度//*/
    tsm12_i2c_write(0x08,0x2A);//用于提高灵敏度(最后三位用于控制响应时间),RTC全为0是响应最快
    //通道开关允许
    tsm12_i2c_write(0x0A, 0x00);//配置
    tsm12_i2c_write(0x0B, 0x00);//配置 
    tsm12_i2c_write(0x0C, 0x00);//配置 
    tsm12_i2c_write(0x0D, 0x00);//配置
    // S/W Reset OFF
    tsm12_i2c_write(0x09, 0x03);// 复位和休眠开关寄存器地址   配置 复位和休眠 控制开关  1打开 0关闭

 }


/**
 * 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;
    
    printk("xuelin###################%s enter \n", __func__);
    
    ret = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA);
    if (!ret)
            return -ENODEV;
    
    if(twi_id == adapter->nr){
            printk("xuelin################%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)) {
        printk("xuelin########################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)
    {
    
        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 ret;
    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;
        }
    }

    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);
/*    printk("xuelin#################00000000000000000000\n");
    tsm12_i2c_read(0x12);
    printk("xuelin#################tsm12_i2c_read(0x12)\n");
    msleep(1000);
    ret=tsm12_i2c_read(0x11);
    if(ret=0x03)
        
    printk("xuelin#################tsm12_i2c_read(0x11)\n");
    msleep(1000);
    tsm12_i2c_read(0x10);
    printk("xuelin#################tsm12_i2c_read(0x10)\n");
    msleep(1000);
    printk("xuelin#################1111111111111111111\n");*/
    //printk("xuelin#################report_abs end\n");
}

static void mma7660_dev_poll(struct input_polled_dev *dev)
{
    printk("xuelin#################mma7660_dev_poll\n");
    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;
    }
    printk("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;
 
    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
    printk("<%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);
    tsm12_Initial1();
    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_HAS_EARLYSUSPEND
static void mma7660_early_suspend(struct early_suspend *h)
{
    int result;
    dprintk(DEBUG_SUSPEND, "mma7660 early 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;
}

static void mma7660_late_resume(struct early_suspend *h)
{
    int result;
    dprintk(DEBUG_SUSPEND, "mma7660 late resume\n");
    
    if (SUPER_STANDBY == standby_type)
        queue_work(mma7660_resume_wq, &mma7660_resume_work);

    if (NORMAL_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));
        assert(result==0);
        mutex_unlock(&mma7660_data.init_mutex);
        mma7660_idev->input->open(mma7660_idev->input);
    }
    return;
}
#else
#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
#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,
    },
    .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
        twi_id = gsensor_info.twi_id;

    printk("xuelin###############%s i2c twi is %d \n", __func__, twi_id);

    ret = i2c_add_driver(&mma7660_driver);
    if (ret < 0) {
        printk(KERN_INFO "add mma7660 i2c driver failed\n");
        return -ENODEV;
    }
    printk("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);
}

MODULE_AUTHOR("Chen Gang ");
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);

你可能感兴趣的:(驱动管理)