1. 程式人生 > >linux 3.18 -- iic,input,misc,三軸加速度裝置驅動(三)

linux 3.18 -- iic,input,misc,三軸加速度裝置驅動(三)

{{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 */ #endif static 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-range static 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