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
- linux 3.18 -- iic,input,misc,三轴加速度设备驱动(三)
- linux 3.18 -- iic,input,misc,三轴加速度设备驱动(一)
- linux 3.18 -- iic,input,misc,三轴加速度设备驱动(二)
- LINUX下的IIC驱动(三)
- linux设备驱动(三)--应用input子系统实现按键驱动
- arduino中用IIC读取MMA8452三轴加速度模块数据
- linux驱动开发之路(三)——嵌入式 Linux 的蜂鸣器控制实验(misc设备)
- Linux misc 设备驱动
- Atmega16驱动三轴加速度传感器MMA7455
- 三轴加速度传感器bma150驱动解析
- Linux设备驱动(三)块设备
- LINUX的IIC驱动从这开始(三)
- LINUX的IIC驱动从这开始(三)
- linux input子系统驱动(三)
- Linux设备驱动 IIC驱动
- linux 块设备驱动 (三)块设备驱动开发
- Linux设备驱动核心理论(三)
- LINUX 设备驱动(完善 版(三))
- MySQL
- RNA的.fasta数据转换为数字数据
- 对象类型转换
- 关于 redis、memcache、mongoDB 的对比
- 基于mysql数据库的Hibernate3的环境搭建
- linux 3.18 -- iic,input,misc,三轴加速度设备驱动(三)
- Python之创建tuple
- HTTPweb服务器——HTTP基本知识
- 【转】使用SYSTEMINFO类获取UNITY3D运行设备的各类信息(CPU类型,显卡类型等)
- Codeforces-798C-Mike and gcd problem(贪心+数论)
- Java中的异常
- org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool问题解决方案
- 通过监听手势滑动解决DrawerLayout只能边缘打开抽屉问题
- 快速排序的递归实现