linux 3.18 -- iic,input,misc,三轴加速度设备驱动(三)

来源:互联网 发布:数据大魔王 编辑:程序博客网 时间:2024/06/15 05:41

input子系统和misc设备驱动

/* *  bma250.c - Linux kernel modules for 3-Axis Accel sensor */#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/pm.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/miscdevice.h>#include <linux/poll.h>#include <linux/gpio.h>#include "bma250.h"//ioctl命令构建#define SENSOR_IOCTL_BASE           'S'#define SENSOR_GET_MODEL_NAME       _IOR(SENSOR_IOCTL_BASE, 0, char *)#define SENSOR_GET_POWER_STATUS     _IOR(SENSOR_IOCTL_BASE, 2, int)#define SENSOR_SET_POWER_STATUS     _IOR(SENSOR_IOCTL_BASE, 3, int)#define SENSOR_GET_DELAY_TIME       _IOR(SENSOR_IOCTL_BASE, 4, int)#define SENSOR_SET_DELAY_TIME       _IOR(SENSOR_IOCTL_BASE, 5, int)#define SENSOR_SET_HIGH_TH          _IOR(SENSOR_IOCTL_BASE, 6, int)#define SENSOR_GET_HIGH_TH          _IOR(SENSOR_IOCTL_BASE, 7, int)#define SENSOR_SET_TAP_TH           _IOR(SENSOR_IOCTL_BASE, 8, int)#define SENSOR_GET_TAP_TH           _IOR(SENSOR_IOCTL_BASE, 9, int)#define SENSOR_SET_TAP_QUIET        _IOR(SENSOR_IOCTL_BASE, 10, int)#define SENSOR_GET_TAP_QUIET        _IOR(SENSOR_IOCTL_BASE, 11, int)#define SENSOR_SET_TAP_SHOCK        _IOR(SENSOR_IOCTL_BASE, 12, int)#define SENSOR_GET_TAP_SHOCK        _IOR(SENSOR_IOCTL_BASE, 13, int)#define SENSOR_GET_RAW_DATA         _IOR(SENSOR_IOCTL_BASE, 14, short[3])#define BMA250_POSITION_DEFAULT     2#define BMA250_DELAY_DEFAULT        200#define BMA250_TAP_TH_DEFAULT       0x18#define BMA250_STATUS_ZYXDR         0x08#define BMA250_BUF_SIZE             6struct bma250_data bma250_dev;#if 0static int bma250_position_setting[8][3][3] = {    {{0, -1, 0}, {1, 0, 0}, {0, 0, 1} },    {{-1, 0, 0}, {0, -1, 0}, {0, 0, 1} },    {{0, 1, 0}, {-1, 0, 0}, {0, 0, 1} },    {{1, 0, 0}, {0, 1, 0}, {0, 0, 1} },    {{0, -1, 0}, {-1, 0, 0}, {0, 0, -1} },    {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1} },    {{0, 1, 0}, {1, 0, 0}, {0, 0, -1} },    {{1, 0, 0}, {0, -1, 0}, {0, 0, -1} },};#endif#define DEBUG_SWITCH        1#ifdef    DEBUG_SWITCH#define my_debug(fmt,args...) printk(fmt, ##args)#else#define my_debug(fmt,args...) /*do nothing */#endifstatic int bma250_bus_write(struct bma250_data *pdata, u8 reg, u8 val){    if (pdata && pdata->write)        //间接调用bma250_i2c_write()        return pdata->write(pdata, reg, val);       return -EIO;}static int bma250_bus_read(struct bma250_data *pdata, u8 reg){    if (pdata && pdata->read)        //间接调用bma250_i2c_read()        return pdata->read(pdata, reg);    return -EIO;}static int bma250_bus_read_block(struct bma250_data *pdata, u8 reg, u8 len,                   u8 *val){    if (pdata && pdata->read_block)        //间接调用bma250_i2c_read_block        return pdata->read_block(pdata, reg, len, val);    return -EIO;}static int bma250_data_convert(struct bma250_data *pdata, struct bma250_data_axis *axis_data){    /*short rawdata[3], data[3];    int i, j;    int position = atomic_read(&pdata->position);    if (position < 0 || position > 7)        position = 0;    rawdata[0] = axis_data->x;    rawdata[1] = axis_data->y;    rawdata[2] = axis_data->z;    for (i = 0; i < 3; i++) {        data[i] = 0;        for (j = 0; j < 3; j++)            data[i] +=                rawdata[j] *                bma250_position_setting[position][i][j];    }    axis_data->x = data[0];    axis_data->y = data[1];    axis_data->z = data[2];*/    return 0;}/*************************bma250功能函数**************/static int bma250_device_init(struct bma250_data *pdata){    int result;    //Selection of the main power modes and the low power sleep period    result = bma250_bus_write(pdata, BMA250_PMU_LPW, 0);                    //set the normal mode    if (result < 0)        goto out;    //The register allows the selection of the accelerometer g-range.    result = bma250_bus_write(pdata, BMA250_PMU_RANGE, MODE_2G);            //selection the MODE_2G    if (result < 0)        goto out;    if (pdata->irq) {        //Contains the interrupt reset bit and the interrupt mode selection.        result = bma250_bus_write(pdata, BMA250_INT_RST_LATCH, 0x8f);       // clear any latched interrupts, and latch intr        if (result < 0)            goto out;        //Contains the behavioural configuration (electrical behaviour) of the interrupt pins.#if 0        result = bma250_bus_write(pdata, BMA250_INT_OUT_CTRL, 0x01);        //intr 1:push-pull,active high; intr 2:push-pull,active low        if (result < 0)            goto out;#endif              /*配置为高有效,即有上升沿*/        result = bma250_bus_write(pdata, BMA250_INT_OUT_CTRL, 0x05);        //intr 1:push-pull,active high; intr 2:push-pull,active high        if (result < 0)            goto out;//      result = bma250_bus_write(pdata, BMA250_INT_MAP_1, 0x1);            //      result = bma250_bus_write(pdata, BMA250_INT_MAP_1, 0xff);   //      if (result < 0)//          goto out;        //Controls which interrupt signals are mapped to the INT1 pin.        result = bma250_bus_write(pdata, BMA250_INT_MAP_0, 0x22);           // map the single tap and hight g to int1        if (result < 0)            goto out;        /*映射中断源到int2*/        result = bma250_bus_write(pdata, BMA250_INT_MAP_2, 0x22);           // map the single tap and hight g to int2        if (result < 0)            goto out;//      result = bma250_bus_write(pdata, BMA250_INT_EN_1, 0x10);            //      result = bma250_bus_write(pdata, BMA250_INT_EN_0, 0x30);//      if (result < 0)//          goto out;//      result = bma250_bus_write(pdata, BMA250_INT_EN_1, 0);//      if (result < 0)//          goto out;//      printk("BMA250 77\n");        //Controls which interrupt engines in group 0 are enabled        result = bma250_bus_write(pdata, BMA250_INT_EN_0, 0x20);            //enable single tap interrupt        if (result < 0)            goto out;        //Controls which interrupt engines in group 1 are enabled        result = bma250_bus_write(pdata, BMA250_INT_EN_1, 0x07);            //enable high-g interrupt:x-axis, y-axis, z-axis        if (result < 0)            goto out;    }    my_debug ("%s: irq = 0x%x\n", __FUNCTION__, pdata->irq);    atomic_set(&pdata->active, ACTIVED);    return 0;out:    printk("BMA250 device init error\n");    return result;}//Selection of the main power modes and the low power sleep period 之修改睡眠时间static int bma250_set_delay(struct bma250_data *pdata, int delay){    u8 val;    if (delay < 0)        return 0;    val = bma250_bus_read(pdata, BMA250_PMU_LPW);    /* set sensor  *///  bma250_bus_write(pdata, BMA250_CTRL_REG1, (val & ~0xd0));    val &= ~0x1e;    if (delay < 1)        val |= 0x00 << 1;    else if (delay < 2)        val |= 0x06 << 1;    else if (delay < 4)        val |= 0x07 << 1;    else if (delay < 6)        val |= 0x08 << 1;    else if (delay < 10)        val |= 0x09 << 1;    else if (delay < 25)        val |= 0x0a << 1;    else if (delay < 50)        val |= 0x0b << 1;    else if (delay < 100)        val |= 0x0c << 1;    else if (delay < 500)        val |= 0x0d << 1;    else if (delay < 1000)        val |= 0x0e << 1;    else         val |= 0x0f << 1;    bma250_bus_write(pdata, BMA250_PMU_LPW, val);    atomic_set(&pdata->active, ACTIVED);    my_debug ("%s: val = 0x%x, delay=0x%x\n", __FUNCTION__, val, delay);    return 0;}//Selection of the main power modes and the low power sleep period 之修改工作模式static int bma250_change_mode(struct bma250_data *pdata, int mode){    u8 val;    int ret;    val = bma250_bus_read(pdata, BMA250_PMU_LPW); //pm 5:7    val &= ~0xe0;    if (mode == ACTIVED) {        /*if ((mode & 0xd0) == 0)            val |= 0x20;*/        //val &= ~0xe0;        //return bma250_set_delay(pdata, atomic_read(&pdata->delay));    } else if (mode == SUSPEND)        val |= (SUSPEND << 5);    else if (mode == LOW_POWER) {        val |= (LOW_POWER << 5);        bma250_bus_write(pdata, BMA250_PMU_LPW, val);        bma250_set_delay(pdata, atomic_read(&pdata->delay));        return 0;    }    my_debug ("%s: val = 0x%x\n", __FUNCTION__, val);    ret = bma250_bus_write(pdata, BMA250_PMU_LPW, val);    return ret;}//Contains the threshold definition for the high-g interrupt 修改high_g加速度上限阈值 static int bma250_change_high_th(struct bma250_data *pdata, int high_th){    int ret;    //Contains the threshold definition for the high-g interrupt    ret = bma250_bus_write(pdata, BMA250_INT_4, high_th);    my_debug ("%s: val = 0x%x\n", __FUNCTION__, high_th);    return ret;}//Contains the timing definitions for the single tap and double tap interrupts tap quiet设置static int bma250_change_tap_quiet(struct bma250_data *pdata, int tap_quiet){    int ret,val;    if(tap_quiet)        tap_quiet = 0x80;    val = bma250_bus_read(pdata, BMA250_INT_8);    val &= 0x7f;    val |= tap_quiet;    ret = bma250_bus_write(pdata, BMA250_INT_8, val);    my_debug ("%s: val = 0x%x\n", __FUNCTION__, val);    return ret;}//Contains the timing definitions for the single tap and double tap interrupts tap shock设置static int bma250_change_tap_shock(struct bma250_data *pdata, int tap_shock){    int ret,val;    if(tap_shock)        tap_shock = 0x40;    val = bma250_bus_read(pdata, BMA250_INT_8);    val &= 0x7f;    val |= tap_shock;    ret = bma250_bus_write(pdata, BMA250_INT_8, val);    my_debug ("%s: val = 0x%x\n", __FUNCTION__, val);    return ret;}//defines the threshold definition for the single and double tap interrupts tap中断阈值设置static int bma250_change_tap_th(struct bma250_data *pdata, int tap_th){    int ret;    tap_th &= 0x1f;    ret = bma250_bus_write(pdata, BMA250_INT_9, tap_th);    my_debug ("%s: val = 0x%x\n", __FUNCTION__, tap_th);    return ret;}//The register allows the selection of the accelerometer g-rangestatic int bma250_change_range(struct bma250_data *pdata, int range){    int ret;    /*u8 val;    val = bma250_bus_read(pdata, BMA250_PMU_RANGE);    val &= ~0x0f;    val |= ((range&0x3) << 4);*/    range &= 0x0f;    ret = bma250_bus_write(pdata, BMA250_PMU_RANGE, range);    my_debug ("%s: val = 0x%x\n", __FUNCTION__, range);    return ret;}//读取加速度值static int bma250_read_data(struct bma250_data *pdata, struct bma250_data_axis *data){    u8 tmp_data[BMA250_BUF_SIZE];    int ret;    //一次读6个字节 x,y,z    ret = bma250_bus_read_block(pdata, BMA250_ACCD_X_LSB, BMA250_BUF_SIZE, tmp_data);    if (ret < BMA250_BUF_SIZE) {        printk(KERN_ERR "BMA250 read sensor block data error\n");        return -EIO;    }    //注意左移右移是按机器位宽进行    data->x = ((tmp_data[1]&0xff) << 2) | ((tmp_data[0]&0xc0)>>6);    data->y = ((tmp_data[3]&0xff) << 2) | ((tmp_data[2]&0xc0)>>6);    data->z = ((tmp_data[5]&0xff) << 2) | ((tmp_data[4]&0xc0)>>6);//  my_debug ("%s: x = 0x%x, y=0x%x, z=0x%x, data[0]=0x%x,data[1]=0x%x,data[2]=0x%x,data[3]=0x%x,data[4]=0x%x,data[5]=0x%x\n", __FUNCTION__, //      data->x, data->y, data->z, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3], tmp_data[4], tmp_data[5]);    return 0;}/*****************************misc设备*********************/static int bma250_open(struct inode *inode, struct file *file){    //指向bma250设备私有数据。还可以通过动态申请的方式    file->private_data = &bma250_dev;     return nonseekable_open(inode, file);}static int bma250_release(struct inode *inode, struct file *file){    /*note: releasing the wdt in NOWAYOUT-mode does not stop it */    return 0;}static long bma250_ioctl(struct file *file, unsigned int reg, unsigned long arg){    struct bma250_data *pdata = file->private_data;    void __user *argp = (void __user *)arg; //通过arg参数,返回给用户空间数据    long ret = 0;    short sdata[3];    int power_status, high_th, tap_th, tap_quiet, tap_shock;    int delay;    struct bma250_data_axis data;    if (!pdata) {        printk(KERN_ERR "BMA250 struct datt point is NULL.");        return -EFAULT;    }    switch (reg) {    case SENSOR_GET_MODEL_NAME:        if (copy_to_user(argp, "bma250", strlen("bma250") + 1)) {            printk(KERN_ERR "SENSOR_GET_MODEL_NAME copy_to_user failed.");            ret = -EFAULT;        }        break;    case SENSOR_GET_POWER_STATUS:        power_status = atomic_read(&pdata->active);        if (copy_to_user(argp, &power_status, sizeof(int))) {            printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed.");            ret = -EFAULT;        }        break;    case SENSOR_SET_POWER_STATUS:        if (copy_from_user(&power_status, argp, sizeof(int))) {            printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed.");            ret = -EFAULT;        }        if (pdata) {            ret = bma250_change_mode(pdata, power_status);            if (!ret)                atomic_set(&pdata->active, power_status);        }        break;    case SENSOR_GET_DELAY_TIME:        delay = atomic_read(&pdata->delay);        if (copy_to_user(argp, &delay, sizeof(delay))) {            printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed.");            return -EFAULT;        }        break;    case SENSOR_SET_DELAY_TIME:        if (copy_from_user(&delay, argp, sizeof(int))) {            printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed.");            ret = -EFAULT;        }        if (pdata && delay > 0 && delay <= 500) {            ret = bma250_set_delay(pdata, delay);            if (!ret)                atomic_set(&pdata->delay, delay);        }        break;    case SENSOR_GET_HIGH_TH:        high_th = atomic_read(&pdata->high_th);        if (copy_to_user(argp, &high_th, sizeof(int))) {            printk(KERN_ERR "SENSOR_GET_HIGH_TH copy_to_user failed.");            ret = -EFAULT;        }        break;    case SENSOR_SET_HIGH_TH:        if (copy_from_user(&high_th, argp, sizeof(int))) {            printk(KERN_ERR "SENSOR_SET_HIGH_TH copy_to_user failed.");            ret = -EFAULT;        }        if (pdata) {            ret = bma250_change_high_th(pdata,   high_th);            if (!ret)                atomic_set(&pdata->high_th, high_th);        }        break;    case SENSOR_GET_TAP_TH:        tap_th = atomic_read(&pdata->tap_th);        if (copy_to_user(argp, &tap_th, sizeof(int))) {            printk(KERN_ERR "SENSOR_GET_HIGH_TH copy_to_user failed.");            ret = -EFAULT;        }        break;    case SENSOR_SET_TAP_TH:        if (copy_from_user(&tap_th, argp, sizeof(int))) {            printk(KERN_ERR "SENSOR_SET_HIGH_TH copy_to_user failed.");            ret = -EFAULT;        }        if (pdata) {            ret = bma250_change_tap_th(pdata,    tap_th);            if (!ret)                atomic_set(&pdata->tap_th, tap_th);        }        break;    case SENSOR_GET_TAP_QUIET:        tap_th = atomic_read(&pdata->tap_quiet);        if (copy_to_user(argp, &tap_quiet, sizeof(int))) {            printk(KERN_ERR "SENSOR_GET_HIGH_TH copy_to_user failed.");            ret = -EFAULT;        }        break;    case SENSOR_SET_TAP_QUIET:        if (copy_from_user(&tap_quiet, argp, sizeof(int))) {            printk(KERN_ERR "SENSOR_SET_HIGH_TH copy_to_user failed.");            ret = -EFAULT;        }        if (pdata) {            ret = bma250_change_tap_quiet(pdata,     tap_quiet);            if (!ret)                atomic_set(&pdata->tap_quiet, tap_quiet);        }        break;    case SENSOR_GET_TAP_SHOCK:        tap_th = atomic_read(&pdata->tap_shock);        if (copy_to_user(argp, &tap_shock, sizeof(int))) {            printk(KERN_ERR "SENSOR_GET_HIGH_TH copy_to_user failed.");            ret = -EFAULT;        }        break;    case SENSOR_SET_TAP_SHOCK:        if (copy_from_user(&tap_shock, argp, sizeof(int))) {            printk(KERN_ERR "SENSOR_SET_HIGH_TH copy_to_user failed.");            ret = -EFAULT;        }        if (pdata) {            ret = bma250_change_tap_shock(pdata,     tap_shock);            if (!ret)                atomic_set(&pdata->tap_shock, tap_shock);        }        break;    case SENSOR_GET_RAW_DATA:        ret = bma250_read_data(pdata, &data);        if (!ret) {            bma250_data_convert(pdata, &data);            sdata[0] = data.x;            sdata[1] = data.y;            sdata[2] = data.z;            if (copy_to_user(argp, sdata, sizeof(sdata))) {                printk(KERN_ERR "SENSOR_GET_RAW_DATA copy_to_user failed.");                ret = -EFAULT;            }        }        break;    default:        ret = -1;    }    return ret;}static const struct file_operations bma250_fops = {    .owner = THIS_MODULE,    .open = bma250_open,    .release = bma250_release,    .unlocked_ioctl = bma250_ioctl,};static struct miscdevice bma250_device = {    .minor = MISC_DYNAMIC_MINOR,    .name = "bma_gsensor",    .fops = &bma250_fops,};/********************用于测试,在misc下创建相关测试文件**************/static ssize_t bma250_enable_show(struct device *dev, struct device_attribute *attr, char *buf){    struct bma250_data *pdata = &bma250_dev;    int enable = 0;    enable = atomic_read(&pdata->active);    return sprintf(buf, "%d\n", enable);}static ssize_t bma250_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){    struct bma250_data *pdata = &bma250_dev;    int ret;    unsigned long enable;    if(kstrtoul(buf, 10, &enable) < 0) //将buf对于的字符串转换为10进制数字,存入enable变量中。        return -EINVAL;    //enable = (enable > 0) ? 1 : 0;    ret = bma250_change_mode(pdata, enable);    if (!ret) {        atomic_set(&pdata->active, enable);        //if (enable)            printk(KERN_INFO "power status =0x%x\n", (int)enable);        //else        //  printk(KERN_INFO "mma enable setting standby\n");    }    return count;}static ssize_t bma250_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf){    struct bma250_data *pdata = &bma250_dev;    int delay = 0;    delay = atomic_read(&pdata->delay);    return sprintf(buf, "%d\n", delay);}static ssize_t bma250_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){    struct bma250_data *pdata = &bma250_dev;    int ret;    unsigned long delay;    if(kstrtoul(buf, 10, &delay) < 0)        return -EINVAL;    ret = bma250_set_delay(pdata, delay);    if (!ret)        atomic_set(&pdata->delay, delay);    return count;}static ssize_t bma250_position_show(struct device *dev, struct device_attribute *attr, char *buf){    struct bma250_data *pdata = &bma250_dev;    int position = 0;    position = atomic_read(&pdata->position);    return sprintf(buf, "%d\n", position);}static ssize_t bma250_position_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){    struct bma250_data *pdata = &bma250_dev;    unsigned long position;    if(kstrtoul(buf, 10, &position) < 0)        return -EINVAL;    atomic_set(&pdata->position, position);    return count;}static ssize_t bma250_data_show(struct device *dev, struct device_attribute *attr, char *buf){    struct bma250_data *pdata = &bma250_dev;    int ret = 0;    struct bma250_data_axis data;    ret = bma250_read_data(pdata, &data);    if  (!ret)        bma250_data_convert(pdata, &data);    return sprintf(buf, "%d,%d,%d\n", data.x, data.y, data.z);}static ssize_t bma250_range_show(struct device *dev, struct device_attribute *attr, char *buf){    struct bma250_data *pdata = &bma250_dev;    int range = 0;    range = atomic_read(&pdata->range);    return sprintf(buf, "%d\n", range);}static ssize_t bma250_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){    struct bma250_data *pdata = &bma250_dev;    int ret;    unsigned long range;    if (kstrtoul(buf, 10, &range) < 0)        return -EINVAL;    if (range == atomic_read(&pdata->range))        return count;    if (atomic_read(&pdata->active))        printk(KERN_INFO "Pls set the sensor standby and then actived\n");    ret = bma250_change_range(pdata, range);    if (!ret)        atomic_set(&pdata->range, range);    return count;}//使用DEVICE_ATTR,可以在sys fs中添加“文件”,通过修改该文件内容,可以实现在运行过程中动态控制device的目的。//DEVICE_ATTR对应的文件在/sys/devices/目录中对应的device下面/*    DEVICE_ATTR(_name, _mode, _show, _store)    _name:名称,也就是将在sys fs中生成的文件名称。    _mode:上述文件的访问权限,与普通文件相同,UGO的格式。    _show:显示函数,cat该文件时,此函数被调用。    _store:写函数,echo内容到该文件时,此函数被调用。*/static DEVICE_ATTR(enable, 0666, bma250_enable_show, bma250_enable_store);static DEVICE_ATTR(poll_delay, 0666, bma250_poll_delay_show, bma250_poll_delay_store);static DEVICE_ATTR(position, 0666, bma250_position_show, bma250_position_store);static DEVICE_ATTR(data, 0666, bma250_data_show, NULL);static DEVICE_ATTR(range, 0666, bma250_range_show, bma250_range_store);static struct attribute *bma250_attributes[] = {    &dev_attr_enable.attr,    &dev_attr_poll_delay.attr,    &dev_attr_position.attr,    &dev_attr_data.attr,    &dev_attr_range.attr,    NULL};static const struct attribute_group bma250_attr_group = {    .attrs = bma250_attributes,};/******************中断发生时的事件报告**************/static irqreturn_t bma250_irq_handler(int irq, void *dev){    int ret;    u8 int_src;    struct bma250_data *pdata = (struct bma250_data *)dev;    struct bma250_data_axis data;    u8 status_data[BMA250_BUF_SIZE];    bma250_bus_write(pdata, BMA250_INT_RST_LATCH, 0x8f);        //clear latch, and latch intr 手工清除中断标志位    bma250_bus_read_block(pdata, BMA250_INT_STATUS_0, 4, status_data);//  int_src = bma250_bus_read(pdata, BMA250_INT_STATUS_1);    /* data ready interrupt *///  if (int_src & 0x80) {        ret = bma250_read_data(pdata, &data);        if (!ret) {            bma250_data_convert(pdata, &data);            input_report_abs(pdata->idev, ABS_X, data.x);            input_report_abs(pdata->idev, ABS_Y, data.y);            input_report_abs(pdata->idev, ABS_Z, data.z);            input_sync(pdata->idev);  //告诉input_core此次汇报已结束        }//  }    my_debug ("%s: x = 0x%x, y=0x%x, z=0x%x, intr_status0=0x%x, intr_status1=0x%x, intr_status2=0x%x,intr_status3=0x%x\n",        __FUNCTION__, data.x, data.y, data.z,status_data[0], status_data[1], status_data[2], status_data[3]);    return IRQ_HANDLED;}/*******************iic设备驱动注册调用****************/int bma250_driver_init(struct bma250_data *pdata){    int result, chip_id;    // 读取IIC chip id    chip_id = bma250_bus_read(pdata, BMA250_BGW_CHIPID);#if 1    printk("gsensor id = 0x%x\n", chip_id);    if (chip_id != BMA250_ID) {        printk(KERN_ERR "read sensor who am i (0x%x)error !\n",               chip_id);        result = -EINVAL;        goto err_out;    }#endif    /* Initialize the BMA250 chip */    pdata->chip_id = chip_id;    atomic_set(&pdata->delay, BMA250_DELAY_DEFAULT);    atomic_set(&pdata->position, BMA250_POSITION_DEFAULT);    //注册misc设备    result = misc_register(&bma250_device);    if (result != 0) {        printk(KERN_ERR "register acc miscdevice error");        goto err_regsiter_misc;    }    //创建调试文件    result = sysfs_create_group(&bma250_device.this_device->kobj, &bma250_attr_group);    if (result) {        printk(KERN_ERR "create device file failed!\n");        result = -EINVAL;        goto err_create_sysfs;    }    //分配input设备    pdata->idev = input_allocate_device();      if (!pdata->idev) {        result = -ENOMEM;        printk(KERN_ERR "alloc bma250 input device failed!\n");        goto err_alloc_input_device;    }    pdata->idev->name = "bma250Accel";     pdata->idev->id.bustype = BUS_I2C;    pdata->idev->evbit[0] = BIT_MASK(EV_ABS);  //用于记录支持的事件类型的位图    input_set_abs_params(pdata->idev, ABS_X, -0x7fff, 0x7fff, 0, 0);    input_set_abs_params(pdata->idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);    input_set_abs_params(pdata->idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);    //注册input设备    result = input_register_device(pdata->idev);    if (result) {        printk(KERN_ERR "register bma250 input device failed!\n");        goto err_register_input_device;    }    //中断处理    if (pdata->irq) {        //申请input的中断,只定义了中断底半部。        //IRQF_ONESHOT:内核会自动在中断上下文中屏蔽对应中断号;内核调度底半部执行后,重新使能该中断号。        result = request_threaded_irq(  pdata->irq, NULL, bma250_irq_handler,                                        IRQF_TRIGGER_HIGH | IRQF_ONESHOT,                                         pdata->idev->name, pdata);        if (result < 0) {            printk(KERN_ERR "failed to register bma250 irq %d!\n",                   pdata->irq);            goto err_register_irq;        }        //使一个irq具有唤醒系统的功能        result = enable_irq_wake(pdata->irq);        if(result) {            printk(KERN_ERR "failed to set bma250 gpio irq %d wake up!\n",                   pdata->irq);            goto err_register_irq;        }    }    //设置Register 0x2B ,即设置tap中断灵敏度    bma250_change_tap_th(pdata, BMA250_TAP_TH_DEFAULT);    bma250_device_init(pdata);    printk("bma250 device driver probe successfully\n");    return 0;err_register_irq:    input_unregister_device(pdata->idev);err_register_input_device:    input_free_device(pdata->idev);err_alloc_input_device:    sysfs_remove_group(&bma250_device.this_device->kobj, &bma250_attr_group);err_create_sysfs:    misc_deregister(&bma250_device);err_regsiter_misc:    //kfree(pdata);err_out:    return result;}EXPORT_SYMBOL_GPL(bma250_driver_init);int bma250_driver_remove(struct bma250_data *pdata){    bma250_change_mode(pdata, SUSPEND);    if (pdata->irq) {        free_irq(pdata->irq, pdata);        disable_irq_wake(pdata->irq);    }    //注销input设备    input_unregister_device(pdata->idev);       //释放input设备    input_free_device(pdata->idev);    sysfs_remove_group(&bma250_device.this_device->kobj,               &bma250_attr_group);    //注销misc设备    misc_deregister(&bma250_device);//  if (pdata != NULL)//      kfree(pdata);    return 0;}EXPORT_SYMBOL_GPL(bma250_driver_remove);/*****************做电源管理时用到*************/#ifdef CONFIG_PM_SLEEPint bma250_driver_suspend(struct bma250_data *pdata){//  if (SUSPEND != atomic_read(&pdata->active))//      bma250_change_mode(pdata, SUSPEND);    return 0;}EXPORT_SYMBOL_GPL(bma250_driver_suspend);int bma250_driver_resume(struct bma250_data *pdata){//  if (SUSPEND != atomic_read(&pdata->active))//      bma250_change_mode(pdata, atomic_read(&pdata->active));    return 0;}EXPORT_SYMBOL_GPL(bma250_driver_resume);#endif
/* *  bma250.h - Linux kernel modules for 3-Axis Accel sensor * */#ifndef _BMA250_H#define _BMA250_H#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/input.h>#define BMA250_ID  0xf9/* register enum for bma250 registers */enum {  BMA250_BGW_CHIPID = 0,        BMA250_ACCD_X_LSB = 0x02,        BMA250_ACCD_X_MSB,         BMA250_ACCD_Y_LSB,        BMA250_ACCD_Y_MSB,         BMA250_ACCD_Z_LSB,        BMA250_ACCD_Z_MSB,        BMA250_ACCD_TEMP,        BMA250_INT_STATUS_0,        BMA250_INT_STATUS_1,        BMA250_INT_STATUS_2,        BMA250_INT_STATUS_3,        BMA250_FIFO_STATUS = 0x0E,        BMA250_PMU_RANGE,        BMA250_PMU_BW,        BMA250_PMU_LPW,        BMA250_PMU_LOW_NOISE,        BMA250_ACCD_HBW,        BMA250_BGW_SOFTRESET,        BMA250_INT_EN_0 = 0x16,        BMA250_INT_EN_1,         BMA250_INT_EN_2,        BMA250_INT_MAP_0,        BMA250_INT_MAP_1,        BMA250_INT_MAP_2,        BMA250_INT_SRC = 0x1E,        BMA250_INT_OUT_CTRL = 0x20,        BMA250_INT_RST_LATCH,        BMA250_INT_0,         BMA250_INT_1,        BMA250_INT_2,        BMA250_INT_3,         BMA250_INT_4,        BMA250_INT_5,        BMA250_INT_6,         BMA250_INT_7,        BMA250_INT_8,        BMA250_INT_9,        BMA250_REG_END,};enum {  ACTIVED   = 0x01,         LOW_POWER = 0x02,         SUSPEND   = 0x04 };enum {  MODE_2G  =  0x03,         MODE_4G  =  0x05,         MODE_8G  =  0x08,        MODE_16G =  0x0C};enum {  TAP_QUIET_30MS,          TAP_QUIET_20MS };enum {  TAP_SHOCK_50MS,          TAP_SHOCK_75MS };struct bma250_data_axis {        short x;        short y;        short z;};struct bma250_data {     void *bus_priv; //为i2c_client结构    u16 bus_type;    int irq;    s32 (*write)(struct bma250_data *pdata, u8 reg, u8 val);    s32 (*read)(struct bma250_data *pdata, u8 reg);    s32 (*read_block)(struct bma250_data *pdata, u8 reg, u8 len, u8 *val);    struct input_dev *idev;    atomic_t active;    atomic_t high_th;    atomic_t tap_th;    atomic_t tap_quiet;    atomic_t tap_shock;    atomic_t delay;    atomic_t position;    atomic_t range;    u8 chip_id;};extern struct bma250_data bma250_dev;int bma250_driver_init(struct bma250_data *pdata);int bma250_driver_remove(struct bma250_data *pdata);int bma250_driver_suspend(struct bma250_data *pdata);int bma250_driver_resume(struct bma250_data *pdata);#endif /*  */

makefile

bma250_gsensor-objs := bma250.o bma250_i2c.oobj-m := bma250_gsensor.o PWD  := $(shell pwd)KDIR := /home/vec/nfs/tbox-4g/kernel/dirall:    $(MAKE) -C $(KDIR) M=$(PWD) clean:    rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers
0 0
原创粉丝点击