/* open command for l3g4200d device file */ static int l3g4200d_open(struct inode *inode, struct file *file) { if (gyro->client == NULL) { GYRO_DBG( "I2C driver not install\n"); return -1; } device_init(); hrtimer_start(&gyro->timer, ktime_set(0, NORMAL_TM), HRTIMER_MODE_REL); gyro->flags = 1; GYRO_DBG("l3g4200d has been opened\n"); return nonseekable_open(inode, file); }
/* read command for l3g4200d device file */ static ssize_t l3g4200d_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { struct l3g4200d_t data; if (gyro->client == NULL) return -1; l3g4200d_read_gyro_values(&data); GYRO_DBG("X axis: %d\n", data.x); GYRO_DBG("Y axis: %d\n", data.y); GYRO_DBG("Z axis: %d\n", data.z); return 0; }
static void gy_late_resume(struct early_suspend *h) { struct l3g4200d_data *gy; gy = container_of(h, struct l3g4200d_data, early_suspend); l3g4200d_resume(gy->client); GYRO_DBG("L3G4200D driver l3g4200d_resume\n"); }
static void gy_early_suspend(struct early_suspend *h) { struct l3g4200d_data *gy; gy = container_of(h, struct l3g4200d_data, early_suspend); l3g4200d_suspend(gy->client, PMSG_SUSPEND); GYRO_DBG("L3G4200D driver gy_early_suspend\n"); }
/* release command for l3g4200d device file */ static int l3g4200d_close(struct inode *inode, struct file *file) { int ret = -1; if (gyro == NULL || gyro->client == NULL) { GYRO_DBG( "I2C driver not install\n"); return -1; } hrtimer_cancel(&gyro->timer); ret = l3g4200d_set_mode(PM_OFF); if(ret < 0) { printk(KERN_ERR "close device i2c set mode PM_OFF err!\n"); } gyro->flags = -1; GYRO_DBG("L3G4200D has been closed\n"); return 0; }
/* write command for l3g4200d device file */ static ssize_t l3g4200d_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) { if (gyro->client == NULL) return -1; GYRO_DBG("l3g4200d should be accessed with ioctl command\n"); return 0; }
static void gy_work_func(struct work_struct *work) { int sesc = 0; struct l3g4200d_data *gy = container_of(work, struct l3g4200d_data, work); memset(&sensor_data, 0, sizeof(sensor_data)); if (gy->client == NULL) { printk(KERN_ERR "gy client is null"); return; } sesc = 0; l3g4200d_read_gyro_values(&sensor_data); GYRO_DBG( "X axis: %d Y axis: %d Z axis: %d\n", sensor_data.x,sensor_data.y,sensor_data.z); if (atomic_read(&a_flag)) { GYRO_DBG("report fusion event to input dev!"); input_report_abs(gy->input_dev, ABS_RX, fusiondata[0]); input_report_abs(gy->input_dev, ABS_RY, fusiondata[1]); input_report_abs(gy->input_dev, ABS_RZ, fusiondata[2]); input_report_abs(gy->input_dev, ABS_THROTTLE, fusiondata[3]); input_report_abs(gy->input_dev, ABS_RUDDER, fusiondata[4]); input_report_abs(gy->input_dev, ABS_WHEEL, fusiondata[5]); input_report_abs(gy->input_dev, ABS_GAS, fusiondata[6]); input_report_abs(gy->input_dev, ABS_BRAKE, fusiondata[7]); input_report_abs(gy->input_dev, ABS_HAT0X, fusiondata[8]); input_report_abs(gy->input_dev, ABS_HAT0Y, fusiondata[9]); atomic_set(&a_flag, 0); } input_report_abs(gy->input_dev, ABS_X, sensor_data.x);//cross x,y adapter hal sensors_akm8973.c input_report_abs(gy->input_dev, ABS_Y, sensor_data.y); input_report_abs(gy->input_dev, ABS_Z, sensor_data.z); input_sync(gy->input_dev); /*initalize timer os gyro*/ if(gyro->flags > 0) { hrtimer_start(&gy->timer, ktime_set(sesc, NORMAL_TM), HRTIMER_MODE_REL); } else { hrtimer_start(&gy->timer, ktime_set(SUSPEND_VAL, 0), HRTIMER_MODE_REL); } }
static int l3g4200d_remove(struct i2c_client *client) { struct l3g4200d_data *lis = i2c_get_clientdata(client); unregister_early_suspend(&lis->early_suspend); hrtimer_cancel(&lis->timer); misc_deregister(&gysensor_device); input_unregister_device(lis->input_dev); kfree(lis); GYRO_DBG("L3G4200D driver removing\n"); return 0; }
/* i2c write routine for l3g4200d digital gyroscope */ static char l3g4200d_i2c_write(unsigned char reg_addr, unsigned char *data, unsigned char len) { int dummy; int i; if (gyro->client == NULL) /* No global client pointer? */ return -1; for (i = 0; i < len; i++) { dummy = i2c_smbus_write_byte_data(gyro->client, reg_addr++, data[i]); if (dummy) { GYRO_DBG("i2c write error\n"); return dummy; } } return 0; }
/* i2c read routine for l3g4200d digital gyroscope */ static char l3g4200d_i2c_read(unsigned char reg_addr, unsigned char *data, unsigned char len) { int dummy = 0; int i = 0; if (gyro->client == NULL) /* No global client pointer? */ return -1; while (i < len) { dummy = i2c_smbus_read_word_data(gyro->client, reg_addr++); if (dummy >= 0) { data[i] = dummy & 0x00ff; //printk(KERN_ERR" i2c read %d %d %x\n ",i, data[i], reg_addr-1); i++; } else { GYRO_DBG(" i2c read error\n "); return dummy; } dummy = len; //usleep_range(3000, 6000); } return dummy; }
static int l3g4200d_probe(struct i2c_client *client, const struct i2c_device_id *devid) { struct l3g4200d_data *data; struct gyro_platform_data *platform_data = NULL; int ret = -1; int tempvalue; GYRO_DBG("l3g4200d_probe start!\n"); if (client->dev.platform_data == NULL) { dev_err(&client->dev, "platform data is NULL. exiting.\n"); ret = -ENODEV; goto exit; } platform_data = client->dev.platform_data; if(platform_data->gyro_power) { ret = platform_data->gyro_power(IC_PM_ON); if( ret < 0) { dev_err(&client->dev, "gyro power on error!\n"); goto exit; } } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ret = -ENODEV; goto exit_pm_off; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)){ ret = -ENODEV; goto exit_pm_off; } /* * OK. For now, we presume we have a valid client. We now create the * client structure, even though we cannot fill it completely yet. */ data = kzalloc(sizeof(struct l3g4200d_data), GFP_KERNEL); if (NULL == data) { dev_err(&client->dev, "failed to allocate memory for module data\n"); ret = -ENOMEM; goto exit_pm_off; } mutex_init(&data->mlock); INIT_WORK(&data->work, gy_work_func); i2c_set_clientdata(client, data); data->client = client; data->pdata = platform_data; ret = l3g4200d_validate_pdata(data); if (ret < 0) { dev_err(&client->dev, "failed to validate platform data\n"); goto exit_kfree; } ret = i2c_smbus_read_byte(client); if ( ret < 0) { GYRO_DBG("i2c_smbus_read_byte error!!\n"); goto err_detect_failed; } else { GYRO_DBG("L3G4200D Device detected!\n"); } /* read chip id */ tempvalue = i2c_smbus_read_word_data(client, WHO_AM_I); if ((tempvalue & 0x00FF) == 0x00D3) { GYRO_DBG("I2C driver registered!\n"); } else { data->client = NULL; ret = -ENODEV; goto err_detect_failed; } if (sensor_dev == NULL) { data->input_dev = input_allocate_device(); if (data->input_dev == NULL) { ret = -ENOMEM; printk(KERN_ERR "gs_probe: Failed to allocate input device\n"); goto err_input_dev_alloc_failed; } data->input_dev->name = "gy_sensors"; sensor_dev = data->input_dev; }else{ data->input_dev = sensor_dev; } data->input_dev->id.vendor = VENDOR; #if 0 set_bit(EV_REL,data->input_dev->evbit); set_bit(REL_RX, data->input_dev->absbit); set_bit(REL_RY, data->input_dev->absbit); set_bit(REL_RZ, data->input_dev->absbit); #endif set_bit(EV_ABS,data->input_dev->evbit); /* modify the func of init */ input_set_abs_params(data->input_dev, ABS_RX, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_RY, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_RZ, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_X, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_Y, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_Z, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_THROTTLE, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_RUDDER, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_WHEEL, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_GAS, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_HAT0X, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_HAT0Y, MIN_VALUE, MAX_VALUE, 0, 0); input_set_abs_params(data->input_dev, ABS_BRAKE, MIN_VALUE, MAX_VALUE, 0, 0); set_bit(EV_SYN,data->input_dev->evbit); data->input_dev->id.bustype = BUS_I2C; input_set_drvdata(data->input_dev, data); ret = input_register_device(data->input_dev); if (ret) { printk(KERN_ERR "gy_probe: Unable to register %s input device\n", data->input_dev->name); /* create l3g-dev device class */ goto err_input_register_device_failed; } ret = misc_register(&gysensor_device); if (ret) { printk(KERN_ERR "gy_probe: gysensor_device register failed\n"); goto err_misc_device_register_failed; } hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); data->timer.function = gy_timer_func; atomic_set(&a_flag, 0); data->flags = -1; #ifdef CONFIG_HAS_EARLYSUSPEND data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; data->early_suspend.suspend = gy_early_suspend; data->early_suspend.resume = gy_late_resume; register_early_suspend(&data->early_suspend); #endif GYRO_DBG("L3G4200D device created successfully\n"); gy_wq = create_singlethread_workqueue("gy_wq"); if (!gy_wq) return -ENOMEM; gyro = data; // hrtimer_start(&this_gs_data->timer, ktime_set(0, 500000000), HRTIMER_MODE_REL); #ifdef CONFIG_HUAWEI_HW_DEV_DCT /* detect current device successful, set the flag as present */ set_hw_dev_flag(DEV_I2C_GYROSCOPE); #endif printk(KERN_DEBUG "l3g4200d_probe successful"); return 0; err_misc_device_register_failed: misc_deregister(&gysensor_device); err_input_register_device_failed: input_free_device(gyro->input_dev); err_input_dev_alloc_failed: err_detect_failed: exit_kfree: kfree(gyro); exit_pm_off: if(platform_data->gyro_power) { platform_data->gyro_power(IC_PM_OFF); } exit: return ret; }
/* modify iotcl interface */ static long l3g4200d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; unsigned char data[6]; short flag = 1; int val = 0; void __user *argp = (void __user *)arg; /* check l3g4200d_client */ if (gyro->client == NULL) { GYRO_DBG( "I2C driver not install\n"); return -EFAULT; } /* cmd mapping */ switch (cmd) { case L3G4200D_SET_RANGE: if (copy_from_user(data, argp, 1) != 0) { GYRO_DBG( "copy_from_user error\n"); return -EFAULT; } err = l3g4200d_set_range(*data); return err; case L3G4200D_SET_MODE: if (copy_from_user(data, argp, 1) != 0) { GYRO_DBG( "copy_to_user error\n"); return -EFAULT; } /*enable or disable timer*/ if( PM_NORMAL == *data ) { gyro->flags = GYRO_ENABLE; hrtimer_start(&gyro->timer, ktime_set(0, NORMAL_TM), HRTIMER_MODE_REL); } else { err = 0; gyro->flags = GYRO_DISABLE; } GYRO_DBG("L3G4200D_SET_MODE %d\n", *data); err = l3g4200d_set_mode(*data); return err; case L3G4200D_SET_BANDWIDTH: if (copy_from_user(data, argp, 1) != 0) { GYRO_DBG("copy_from_user error\n"); return -EFAULT; } err = l3g4200d_set_bandwidth(*data); return err; case L3G4200D_READ_GYRO_VALUES: err = l3g4200d_read_gyro_values( (struct l3g4200d_t *)data); if (copy_to_user((struct l3g4200d_t *)arg, (struct l3g4200d_t *)data, 6) != 0) { GYRO_DBG("copy_to error\n"); return -EFAULT; } return err; case L3G4200D_SET_FUSION_DATA: if(copy_from_user((void*)fusiondata, argp, sizeof(fusiondata)) != 0){ return -EFAULT; } atomic_set(&a_flag, 1); GYRO_DBG("L3G4200D_SET_FUSION_DATA copy_from error\n"); return err; case L3G4200D_GET_GYRO_DATA: if(copy_to_user(argp, &userdata[0], sizeof(userdata))!= 0) { return -EFAULT; } GYRO_DBG("L3G4200D_GET_GYRO_DATA copy_to error\n"); return 0; case ECS_IOCTL_APP_GET_GYRO_DATA: hrtimer_cancel(&gyro->timer); memset(&sensor_data, 0, sizeof(sensor_data)); err = l3g4200d_read_gyro_values(&sensor_data); if(err < 0) { GYRO_DBG("L3G4200D ECS_IOCTL_APP_GET_GYRO_DATA TEST error!\n"); return err; } GYRO_DBG(" before X axis: %d Y axis: %d Z axis: %d\n", sensor_data.x,sensor_data.y,sensor_data.z); if(copy_to_user(argp, &sensor_data, sizeof(sensor_data))!= 0) { GYRO_DBG("ECS_IOCTL_APP_GET_GYRO_DATA copy to user error\n"); return -EFAULT; } return 0; case ECS_IOCTL_APP_GET_GYRO_CAL: GYRO_DBG("L3G4200D mmi get ret!\n"); /* self-test flowchart update*/ hrtimer_cancel(&gyro->timer); memset(&sensor_data, 0, sizeof(sensor_data)); err = l3g4200d_read_gyro_values(&sensor_data); printk(KERN_ERR " before X axis: %d Y axis: %d Z axis: %d\n", sensor_data.x,sensor_data.y,sensor_data.z); l3g4200d_set_selftest(L3G4200D_SELFTEST_EN); msleep(800); err = l3g4200d_read_gyro_values(&sensor_data); printk(KERN_ERR "after X axis: %d Y axis: %d Z axis: %d\n", sensor_data.x,sensor_data.y,sensor_data.z); if(err < 0) { GYRO_DBG("L3G4200D SELF-TEST read error!\n"); return err; } /*put data to user*/ if (copy_to_user(argp, &sensor_data, sizeof(sensor_data))) { return -EFAULT; } l3g4200d_disable_selftest(); return 0; case ECS_IOCTL_APP_GET_CAL: GYRO_DBG("L3G4200D mmi get ret!\n"); /* self-test flowchart update*/ hrtimer_cancel(&gyro->timer); memset(&sensor_data, 0, sizeof(sensor_data)); err = l3g4200d_read_gyro_values(&sensor_data); printk(KERN_ERR " before X axis: %d Y axis: %d Z axis: %d\n", sensor_data.x,sensor_data.y,sensor_data.z); l3g4200d_set_selftest(L3G4200D_SELFTEST_EN); msleep(800); err = l3g4200d_read_gyro_values(&sensor_data); printk(KERN_ERR "after X axis: %d Y axis: %d Z axis: %d\n", sensor_data.x,sensor_data.y,sensor_data.z); if(err < 0) { GYRO_DBG("L3G4200D SELF-TEST read error!\n"); return err; } val = abs(sensor_data.x); if( (val > MAX_VAL) || (val < MIN_VAL) ) { flag = -1; GYRO_DBG("L3G4200D SELF-TEST x %d error!\n", val); } val = abs(sensor_data.y); if( (val > MAX_VAL) || (val < MIN_VAL) ) { flag = -1; GYRO_DBG("L3G4200D SELF-TEST y %d error!\n", val); } val = abs(sensor_data.z); if( (val > MAX_VAL) || (val < MIN_VAL) ) { flag = -1; GYRO_DBG("L3G4200D SELF-TEST z %d error!\n", val); } if (copy_to_user(argp, &flag, sizeof(flag))) { return -EFAULT; } l3g4200d_disable_selftest(); return 0; default: return 0; } return err; }