#include #include #include #include #include #include #include #include #include #include #include #include #include "../init-input.h" #define ALLWINNER_PLATFORM //#define ACTIONS_PLATFORM #ifdef ALLWINNER_PLATFORM #include #endif // device info #define SENSOR_NAME "sc7a30" #define SENSOR_I2C_ADDR 0x1D #define ABSMIN -512 #define ABSMAX 512 #define FUZZ 2 #define LSG 64 #define MAX_DELAY 200 // constant define #define SC7A30_CHIP_ID 0x2A #define SC7A30_DATA_READY 0x07 #define SC7A30_RANGE_2G 0x00 #define SC7A30_RANGE_8G 0x01 #define SC7A30_MODE_STANDBY 0x07 #define SC7A30_MODE_ACTIVE 0x47 #define SC7A30_RATE_400HZ 0x00 #define SC7A30_RATE_100HZ 0x01 // register define #define SC7A30_XOUT 0x29 #define SC7A30_YOUT 0x2B #define SC7A30_ZOUT 0x2D #define SC7A30_MODE_REG 0x20 #define SC7A30_MODE1 0x21 #define SC7A30_MODE2 0x22 #define SC7A30_STATUS 0x27 #define SC7A30_WU_CFG 0X30 #define SC7A30_WU_SRC 0X31 #define SC7A30_WU_THS 0X32 #define SC7A30_WU_DUTATION 0X33 #define POLL_INTERVAL_MAX 500 #define POLL_INTERVAL 50 #define INPUT_FUZZ 2 #define INPUT_FLAT 2 #define SENSORS_INONE 0 #define MODE_CHANGE_DELAY_MS 100 // register bits define #define SC7A30_RANGE_BIT__POS 7 #define SC7A30_RANGE_BIT__LEN 1 #define SC7A30_RANGE_BIT__MSK 0x20 #define SC7A30_RANGE_BIT__REG SC7A30_MODE_REG #define SC7A30_MODE_BIT__POS 0 #define SC7A30_MODE_BIT__LEN 7 #define SC7A30_MODE_BIT__MSK 0x47 #define SC7A30_MODE_BIT__REG SC7A30_MODE_REG #define SC7A30_RATE_BIT__POS 5 #define SC7A30_RATE_BIT__LEN 1 #define SC7A30_RATE_BIT__MSK 0x80 #define SC7A30_RATE_BIT__REG SC7A30_MODE_REG #define SC7A30_GET_BITSLICE(regvar, bitname)\ ((regvar & bitname##__MSK) >> bitname##__POS) #define SC7A30_SET_BITSLICE(regvar, bitname, val)\ ((regvar & ~bitname##__MSK) | ((val<adapter; if(twi_id == adapter->nr){ pr_info("%s: Detected chip %s at adapter %d, address 0x%02x\n", __func__, SENSOR_NAME, i2c_adapter_id(adapter), client->addr); strlcpy(info->type, SENSOR_NAME, I2C_NAME_SIZE); return 0; }else{ return -ENODEV; } } #endif static int SC7A30_axis_remap(struct i2c_client *client, struct SC7A30_acc *acc); static int SC7A30_smbus_read_byte(struct i2c_client *client, unsigned char reg_addr, unsigned char *data) { s32 dummy; dummy = i2c_smbus_read_byte_data(client, reg_addr); if (dummy < 0) return -1; *data = dummy & 0x000000ff; return 0; } static int SC7A30_smbus_write_byte(struct i2c_client *client, unsigned char reg_addr, unsigned char *data) { s32 dummy; dummy = i2c_smbus_write_byte_data(client, reg_addr, *data); if (dummy < 0) return -1; return 0; } static int SC7A30_smbus_read_byte_block(struct i2c_client *client, unsigned char reg_addr, unsigned char *data, unsigned char len) { s32 dummy; dummy = i2c_smbus_read_i2c_block_data(client, reg_addr, len, data); if (dummy < 0) return -1; return 0; } static int SC7A30_smbus_write_byte_block(struct i2c_client *client, unsigned char reg_addr, unsigned char *data, unsigned char len) { s32 dummy; dummy = i2c_smbus_write_i2c_block_data(client, reg_addr, len, data); if (dummy < 0) return -1; return 0; } static int SC7A30_set_mode(struct i2c_client *client, unsigned char mode) { int comres = 0; unsigned char data = 0; comres = SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data); data = SC7A30_SET_BITSLICE(data, SC7A30_MODE_BIT, mode); comres += SC7A30_smbus_write_byte(client, SC7A30_MODE_BIT__REG, &data); return comres; } static int SC7A30_get_mode(struct i2c_client *client, unsigned char *mode) { int comres = 0; unsigned char data = 0; comres = SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data); *mode = SC7A30_GET_BITSLICE(data, SC7A30_MODE_BIT); return comres; } static int SC7A30_set_range(struct i2c_client *client, unsigned char range) { int comres = 0; unsigned char data = 0; unsigned char mode; // save mode comres += SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data); mode = SC7A30_GET_BITSLICE(data, SC7A30_MODE_BIT); if (mode == SC7A30_MODE_ACTIVE) { data = SC7A30_SET_BITSLICE(data, SC7A30_MODE_BIT, SC7A30_MODE_STANDBY); comres += SC7A30_smbus_write_byte(client, SC7A30_MODE_BIT__REG, &data); } comres += SC7A30_smbus_read_byte(client, SC7A30_RANGE_BIT__REG, &data); data = SC7A30_SET_BITSLICE(data, SC7A30_RANGE_BIT, range); comres += SC7A30_smbus_write_byte(client, SC7A30_RANGE_BIT__REG, &data); // restore mode if (mode == SC7A30_MODE_ACTIVE) { comres += SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data); data = SC7A30_SET_BITSLICE(data, SC7A30_MODE_BIT, SC7A30_MODE_ACTIVE); comres += SC7A30_smbus_write_byte(client, SC7A30_MODE_BIT__REG, &data); } return comres; } static int SC7A30_get_range(struct i2c_client *client, unsigned char *range) { int comres = 0; unsigned char data = 0; comres = SC7A30_smbus_read_byte(client, SC7A30_RANGE_BIT__REG, &data); *range = SC7A30_GET_BITSLICE(data, SC7A30_RANGE_BIT); return comres; } static int SC7A30_set_rate(struct i2c_client *client, unsigned char rate) { int comres = 0; unsigned char data = 0; unsigned char mode; // save mode comres += SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data); mode = SC7A30_GET_BITSLICE(data, SC7A30_MODE_BIT); if (mode == SC7A30_MODE_ACTIVE) { data = SC7A30_SET_BITSLICE(data, SC7A30_MODE_BIT, SC7A30_MODE_STANDBY); comres += SC7A30_smbus_write_byte(client, SC7A30_MODE_BIT__REG, &data); } comres += SC7A30_smbus_read_byte(client, SC7A30_RATE_BIT__REG, &data); data = SC7A30_SET_BITSLICE(data, SC7A30_RATE_BIT, rate); comres += SC7A30_smbus_write_byte(client, SC7A30_RATE_BIT__REG, &data); // restore mode if (mode == SC7A30_MODE_ACTIVE) { comres += SC7A30_smbus_read_byte(client, SC7A30_MODE_BIT__REG, &data); data = SC7A30_SET_BITSLICE(data, SC7A30_MODE_BIT, SC7A30_MODE_ACTIVE); comres += SC7A30_smbus_write_byte(client, SC7A30_MODE_BIT__REG, &data); } return comres; } static int SC7A30_get_rate(struct i2c_client *client, unsigned char *rate) { int comres = 0; unsigned char data = 0; comres = SC7A30_smbus_read_byte(client, SC7A30_RATE_BIT__REG, &data); *rate = SC7A30_GET_BITSLICE(data, SC7A30_RATE_BIT); return comres; } static int SC7A30_hw_init(struct i2c_client *client) { int comres = 0; // sample rate: 100Hz comres += SC7A30_set_rate(client, SC7A30_RATE_100HZ); // range: -2G~+2G comres += SC7A30_set_range(client, SC7A30_RANGE_2G); return comres; } static int SC7A30_read_data(struct i2c_client *client, struct SC7A30_acc *acc) { s8 px,py,pz; s32 result; result=i2c_smbus_read_byte_data(client, SC7A30_XOUT); px=result&0xff; result=i2c_smbus_read_byte_data(client, SC7A30_YOUT); py=result&0xff; result=i2c_smbus_read_byte_data(client, SC7A30_ZOUT); pz=result&0xff; acc->x = (((short)px) << 8) >> 8; acc->y = (((short)py) << 8) >> 8; acc->z = (((short)pz) << 8) >> 8; //printk("pga_debug\n"); return 0; } static ssize_t SC7A30_register_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int address, value; struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); sscanf(buf, "[0x%x]=0x%x", &address, &value); if (SC7A30_smbus_write_byte(SC7A30->SC7A30_client, (unsigned char)address, (unsigned char *)&value) < 0) return -EINVAL; return count; } static ssize_t SC7A30_register_show(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); size_t count = 0; u8 reg[0x32]; int i; for (i = 0 ; i < 0x32; i++) { SC7A30_smbus_read_byte(SC7A30->SC7A30_client, i, reg+i); count += sprintf(&buf[count], "0x%x: 0x%x\n", i, reg[i]); } return count; } static ssize_t SC7A30_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned char data; struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); if (SC7A30_get_mode(SC7A30->SC7A30_client, &data) < 0) return sprintf(buf, "Read error\n"); return sprintf(buf, "%d\n", data); } static ssize_t SC7A30_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long data; int error; struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); error = strict_strtoul(buf, 10, &data); if (error) return error; if (SC7A30_set_mode(SC7A30->SC7A30_client, (unsigned char) data) < 0) return -EINVAL; return count; } static ssize_t SC7A30_rate_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned char data; struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); if (SC7A30_get_rate(SC7A30->SC7A30_client, &data) < 0) return sprintf(buf, "Read error\n"); return sprintf(buf, "%d\n", data); } static ssize_t SC7A30_rate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long data; int error; struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); error = strict_strtoul(buf, 10, &data); if (error) return error; if (SC7A30_set_rate(SC7A30->SC7A30_client, (unsigned char) data) < 0) return -EINVAL; return count; } static ssize_t SC7A30_value_show(struct device *dev, struct device_attribute *attr, char *buf) { struct input_dev *input = to_input_dev(dev); struct SC7A30_data *SC7A30 = input_get_drvdata(input); struct SC7A30_acc acc; int result; int retry = 10; while (retry > 0) { result = SC7A30_read_data(SC7A30->SC7A30_client, &acc); if (result == 0) { break; } retry = retry - 1; msleep(20); } if (result == 0) { SC7A30_axis_remap(SC7A30->SC7A30_client, &acc); return sprintf(buf, "%d %d %d\n", acc.x, acc.y, acc.z); } else { return sprintf(buf, "SC7A30_read_data failed!\n"); } } static ssize_t SC7A30_delay_show(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); return sprintf(buf, "%d\n", atomic_read(&SC7A30->delay)); } static ssize_t SC7A30_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long data; unsigned char rate; int error; struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); error = strict_strtoul(buf, 10, &data); if (error) return error; if (data > MAX_DELAY) { data = MAX_DELAY; } atomic_set(&SC7A30->delay, (unsigned int) data); // change sample rate data = 1000 / data; if (data > 200) { rate = SC7A30_RATE_400HZ; } else if (data > 50) { rate = SC7A30_RATE_100HZ; }else { rate = SC7A30_RATE_100HZ; } SC7A30_set_rate(SC7A30->SC7A30_client, rate); return count; } static ssize_t SC7A30_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); return sprintf(buf, "%d\n", atomic_read(&SC7A30->enable)); } static void SC7A30_do_enable(struct device *dev, int enable) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); if (enable) { SC7A30_set_mode(SC7A30->SC7A30_client, SC7A30_MODE_ACTIVE); schedule_delayed_work(&SC7A30->work, msecs_to_jiffies(atomic_read(&SC7A30->delay))); } else { SC7A30_set_mode(SC7A30->SC7A30_client, SC7A30_MODE_STANDBY); cancel_delayed_work_sync(&SC7A30->work); } } static void SC7A30_set_enable(struct device *dev, int enable) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); int pre_enable = atomic_read(&SC7A30->enable); mutex_lock(&SC7A30->enable_mutex); if (enable != pre_enable) { SC7A30_do_enable(dev, enable); atomic_set(&SC7A30->enable, enable); } mutex_unlock(&SC7A30->enable_mutex); } static ssize_t SC7A30_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) return error; if ((data == 0) || (data == 1)) SC7A30_set_enable(dev, data); return count; } static ssize_t SC7A30_fuzz_show(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); return sprintf(buf, "%d\n", atomic_read(&SC7A30->fuzz)); } static ssize_t SC7A30_fuzz_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long data; int error; struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); error = strict_strtoul(buf, 10, &data); if (error) return error; atomic_set(&(SC7A30->fuzz), (int) data); if(SC7A30->input != NULL) { SC7A30->input->absinfo[ABS_X].fuzz = data; SC7A30->input->absinfo[ABS_Y].fuzz = data; SC7A30->input->absinfo[ABS_Z].fuzz = data; } return count; } static ssize_t SC7A30_board_position_show(struct device *dev, struct device_attribute *attr, char *buf) { int data; struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); data = atomic_read(&(SC7A30->position)); return sprintf(buf, "%d\n", data); } static ssize_t SC7A30_board_position_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long data; int error; struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); error = strict_strtol(buf, 10, &data); if (error) return error; atomic_set(&(SC7A30->position), (int) data); return count; } static ssize_t SC7A30_calibration_run_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); struct SC7A30_acc acc; long xyz[3]={0}; int result,i; int retry = 16; for(i=0;iSC7A30_client, &acc); xyz[0]+=acc.x; xyz[1]+=acc.y; xyz[2]+=acc.z; } acc.x=xyz[0]/retry; acc.y=xyz[1]/retry; acc.z=xyz[2]/retry; if (acc.z > 0) { acc.z -= LSG; } else { acc.z += LSG; } /* while (retry > 0) { result = SC7A30_read_data(SC7A30->SC7A30_client, &acc); if (result == 0) { break; } retry = retry - 1; msleep(20); } if (result == 0) { printk(KERN_INFO "data: %d %d %d\n", acc.x, acc.y, acc.z); } else { printk(KERN_INFO "run calibration failed!\n"); return count; } acc.x = (0 - acc.x) / 2; acc.y = (0 - acc.y) / 2; if (atomic_read(&SC7A30->position) > 0) { acc.z = (LSG - acc.z) / 2; } else { acc.z = ((-LSG) - acc.z) / 2; } */ printk(KERN_INFO "calibration: %d %d %d\n", acc.x, acc.y, acc.z); SC7A30->offset[0] = acc.x; SC7A30->offset[1] = acc.y; SC7A30->offset[2] = acc.z; printk(KERN_INFO "run calibration finished\n"); return count; } static ssize_t SC7A30_calibration_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); memset(&(SC7A30->offset), 0, sizeof(SC7A30->offset)); printk(KERN_INFO "reset calibration finished\n"); return count; } static ssize_t SC7A30_calibration_value_show(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); return sprintf(buf, "%d %d %d\n", SC7A30->offset[0], SC7A30->offset[1], SC7A30->offset[2]); } static ssize_t SC7A30_calibration_value_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int data[3]; struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); sscanf(buf, "%d %d %d", &data[0], &data[1], &data[2]); SC7A30->offset[0] = data[0]; SC7A30->offset[1] = data[1]; SC7A30->offset[2] = data[2]; printk(KERN_INFO "set calibration finished\n"); return count; } static DEVICE_ATTR(reg, 0666,//S_IRUGO|S_IWUSR|S_IWGRP, SC7A30_register_show, SC7A30_register_store); static DEVICE_ATTR(mode, 0666,//S_IRUGO|S_IWUSR|S_IWGRP, SC7A30_mode_show, SC7A30_mode_store); static DEVICE_ATTR(rate, 0666,//S_IRUGO|S_IWUSR|S_IWGRP, SC7A30_rate_show, SC7A30_rate_store); static DEVICE_ATTR(value, 0666,//S_IRUGO, SC7A30_value_show, NULL); static DEVICE_ATTR(delay, 0666,//S_IRUGO|S_IWUSR|S_IWGRP, SC7A30_delay_show, SC7A30_delay_store); static DEVICE_ATTR(enable, 0666,//S_IRUGO|S_IWUSR|S_IWGRP, SC7A30_enable_show, SC7A30_enable_store); static DEVICE_ATTR(fuzz, 0666,//S_IRUGO|S_IWUSR|S_IWGRP, SC7A30_fuzz_show, SC7A30_fuzz_store); static DEVICE_ATTR(board_position, 0666,//S_IRUGO|S_IWUSR|S_IWGRP, SC7A30_board_position_show, SC7A30_board_position_store); static DEVICE_ATTR(calibration_run, 0666,//S_IWUSR|S_IWGRP, //calibration_run NULL, SC7A30_calibration_run_store); static DEVICE_ATTR(calibration_reset, 0666,//S_IWUSR|S_IWGRP, NULL, SC7A30_calibration_reset_store); static DEVICE_ATTR(calibration_value,0666,//S_IRUGO|S_IWUSR|S_IWGRP, SC7A30_calibration_value_show, SC7A30_calibration_value_store); static struct attribute *SC7A30_attributes[] = { &dev_attr_reg.attr, &dev_attr_mode.attr, &dev_attr_rate.attr, &dev_attr_value.attr, &dev_attr_delay.attr, &dev_attr_enable.attr, &dev_attr_fuzz.attr, &dev_attr_board_position.attr, &dev_attr_calibration_run.attr, &dev_attr_calibration_reset.attr, &dev_attr_calibration_value.attr, NULL }; static struct attribute_group SC7A30_attribute_group = { .attrs = SC7A30_attributes }; static int SC7A30_read_file(char *path, char *buf, int size) { struct file *filp; loff_t len, offset; int ret=0; mm_segment_t fs; filp = filp_open(path, O_RDWR, 0777); if (IS_ERR(filp)) { ret = PTR_ERR(filp); goto out; } len = vfs_llseek(filp, 0, SEEK_END); if (len > size) { len = size; } offset = vfs_llseek(filp, 0, SEEK_SET); fs=get_fs(); set_fs(KERNEL_DS); ret = vfs_read(filp, (char __user *)buf, (size_t)len, &(filp->f_pos)); set_fs(fs); filp_close(filp, NULL); out: return ret; } static int SC7A30_load_user_calibration(struct i2c_client *client) { char buffer[16]; int ret = 0; int data[3]; struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); int calibrated = atomic_read(&SC7A30->calibrated); // only calibrate once if (calibrated) { goto usr_calib_end; } else { atomic_set(&SC7A30->calibrated, 1); } ret = SC7A30_read_file(CFG_GSENSOR_CALIBFILE, buffer, sizeof(buffer)); if (ret <= 0) { printk(KERN_ERR "gsensor calibration file not exist!\n"); goto usr_calib_end; } sscanf(buffer, "%d %d %d", &data[0], &data[1], &data[2]); SC7A30->offset[0] = data[0]; SC7A30->offset[1] = data[1]; SC7A30->offset[2] = data[2]; printk(KERN_INFO "user cfg_calibration: %d %d %d\n", data[0], data[1], data[2]); usr_calib_end: return ret; } static int SC7A30_axis_remap(struct i2c_client *client, struct SC7A30_acc *acc) { s16 swap; struct SC7A30_data *SC7A30 = i2c_get_clientdata(client); int position = atomic_read(&SC7A30->position); switch (abs(position)) { case 1: swap = acc->x; acc->x = acc->y; acc->y = -swap; break; case 2: acc->x = -(acc->x); acc->y = -(acc->y); break; case 3: swap = acc->x; acc->x = -acc->y; acc->y = swap; break; case 4: break; } if (position < 0) { acc->z = -(acc->z); acc->x = -(acc->x); } return 0; } static void SC7A30_work_func(struct work_struct *work) { struct SC7A30_data *SC7A30 = container_of((struct delayed_work *)work, struct SC7A30_data, work); static struct SC7A30_acc acc; int result; unsigned long delay = msecs_to_jiffies(atomic_read(&SC7A30->delay)); SC7A30_load_user_calibration(SC7A30->SC7A30_client); result = SC7A30_read_data(SC7A30->SC7A30_client, &acc); acc.x-=SC7A30->offset[0]; acc.y-=SC7A30->offset[1]; acc.z-=SC7A30->offset[2]; if (result == 0) { SC7A30_axis_remap(SC7A30->SC7A30_client, &acc); input_report_abs(SC7A30->input, ABS_X, acc.x); input_report_abs(SC7A30->input, ABS_Y, -acc.y); input_report_abs(SC7A30->input, ABS_Z, acc.z); input_sync(SC7A30->input); } schedule_delayed_work(&SC7A30->work, delay); } static int SC7A30_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err = 0; struct SC7A30_data *data; struct input_dev *dev; int cfg_position; int cfg_calibration[3]; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { printk(KERN_INFO "i2c_check_functionality error\n"); goto exit; } data = kzalloc(sizeof(struct SC7A30_data), GFP_KERNEL); if (!data) { err = -ENOMEM; goto exit; } i2c_set_clientdata(client, data); data->SC7A30_client = client; mutex_init(&data->enable_mutex); dev = input_allocate_device(); if (!dev) return -ENOMEM; dev->name = SENSOR_NAME; dev->id.bustype = BUS_I2C; input_set_capability(dev, EV_ABS, ABS_MISC); input_set_abs_params(dev, ABS_X, ABSMIN, ABSMAX, FUZZ, 0); input_set_abs_params(dev, ABS_Y, ABSMIN, ABSMAX, FUZZ, 0); input_set_abs_params(dev, ABS_Z, ABSMIN, ABSMAX, FUZZ, 0); input_set_drvdata(dev, data); err = input_register_device(dev); if (err < 0) { input_free_device(dev); goto kfree_exit; } data->input = dev; INIT_DELAYED_WORK(&data->work, SC7A30_work_func); atomic_set(&data->delay, MAX_DELAY); #ifdef ALLWINNER_PLATFORM SC7A30_set_enable(&client->dev, 1); #endif #ifdef ACTIONS_PLATFORM atomic_set(&data->enable, 0); #endif #ifdef ACTIONS_PLATFORM #if CFG_GSENSOR_USE_CONFIG > 0 /*get xml cfg*/ err = get_config(CFG_GSENSOR_MOD_POSITION, (char *)(&cfg_position), sizeof(int)); if (err != 0) { err = get_config(CFG_GSENSOR_POSITION, (char *)(&cfg_position), sizeof(int)); if (err != 0) { printk(KERN_ERR"get position %d fail\n", cfg_position); goto kfree_exit; } } #else cfg_position = -3; #endif #else cfg_position = -3; #endif atomic_set(&data->position, cfg_position); atomic_set(&data->calibrated, 0); atomic_set(&data->fuzz, FUZZ); //power on init regs err = SC7A30_hw_init(client); if (err < 0) { printk(KERN_ERR"SC7A30 probe fail! err:%d\n", err); goto kfree_exit; } err = sysfs_create_group(&data->input->dev.kobj, &SC7A30_attribute_group); if (err < 0) goto error_sysfs; //#ifdef CONFIG_HAS_EARLYSUSPEND // data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; // data->early_suspend.suspend = SC7A30_early_suspend; // data->early_suspend.resume = SC7A30_early_resume; // register_early_suspend(&data->early_suspend); //#endif #ifdef ACTIONS_PLATFORM #if CFG_GSENSOR_USE_CONFIG > 0 /*get xml cfg*/ err = get_config(CFG_GSENSOR_CALIBRATION, (char *)cfg_calibration, sizeof(cfg_calibration)); if (err != 0) { printk(KERN_ERR"get calibration fail\n"); goto error_sysfs; } #else memset(cfg_calibration, 0, sizeof(cfg_calibration)); #endif #else memset(cfg_calibration, 0, sizeof(cfg_calibration)); #endif // calibrate offset data->offset[0] = (int)cfg_calibration[0]; data->offset[1] = (int)cfg_calibration[1]; data->offset[2] = (int)cfg_calibration[2]; return 0; error_sysfs: input_unregister_device(data->input); kfree_exit: kfree(data); exit: return err; } /*#ifdef CONFIG_HAS_EARLYSUSPEND static void SC7A30_early_suspend(struct early_suspend *h) { // sensor hal will disable when early suspend } static void SC7A30_early_resume(struct early_suspend *h) { // sensor hal will enable when early resume } #endif */ static int SC7A30_remove(struct i2c_client *client) { struct SC7A30_data *data = i2c_get_clientdata(client); SC7A30_set_enable(&client->dev, 0); //#ifdef CONFIG_HAS_EARLYSUSPEND // unregister_early_suspend(&data->early_suspend); //#endif sysfs_remove_group(&data->input->dev.kobj, &SC7A30_attribute_group); input_unregister_device(data->input); kfree(data); return 0; } #ifdef CONFIG_PM static int SC7A30_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *data = i2c_get_clientdata(client); SC7A30_do_enable(dev, 0); input_set_power_enable(&(gsensor_info.input_type),0); return 0; } static int SC7A30_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct SC7A30_data *data = i2c_get_clientdata(client); //power on init regs SC7A30_hw_init(data->SC7A30_client); SC7A30_do_enable(dev, atomic_read(&data->enable)); input_set_power_enable(&(gsensor_info.input_type),1); return 0; } #else #define SC7A30_suspend NULL #define SC7A30_resume NULL #endif*/ /* CONFIG_PM */ static SIMPLE_DEV_PM_OPS(SC7A30_pm_ops, SC7A30_suspend, SC7A30_resume); static const unsigned short SC7A30_addresses[] = { SENSOR_I2C_ADDR, I2C_CLIENT_END, }; static const struct i2c_device_id SC7A30_id[] = { { SENSOR_NAME, 0 }, { } }; MODULE_DEVICE_TABLE(i2c, SC7A30_id); static const struct of_device_id sc7a30_of_id[] = { { .compatible = "sc7a30",}, {}, }; static struct i2c_driver SC7A30_driver = { .driver = { .owner = THIS_MODULE, .name = SENSOR_NAME, .pm = &SC7A30_pm_ops, .of_match_table = "allwinner,sun50i-gsensor-para", }, .class = I2C_CLASS_HWMON, .address_list = SC7A30_addresses, .id_table = SC7A30_id, .probe = SC7A30_probe, .remove = SC7A30_remove, // #ifdef ALLWINNER_PLATFORM // .address_list = u_i2c_addr.normal_i2c, // #endif }; static struct i2c_board_info SC7A30_board_info={ .type = SENSOR_NAME, .addr = SENSOR_I2C_ADDR, }; static struct i2c_client *SC7A30_client; static int __init SC7A30_init(void) { struct i2c_adapter *i2c_adap; unsigned int cfg_i2c_adap_id; #ifdef ACTIONS_PLATFORM #if CFG_GSENSOR_USE_CONFIG > 0 int ret; /*get xml cfg*/ ret = get_config(CFG_GSENSOR_ADAP_ID, (char *)(&cfg_i2c_adap_id), sizeof(unsigned int)); if (ret != 0) { printk(KERN_ERR"get i2c_adap_id %d fail\n", cfg_i2c_adap_id); return ret; } #else cfg_i2c_adap_id = 1; #endif #else cfg_i2c_adap_id = 1; #endif #ifdef ACTIONS_PLATFORM i2c_adap = i2c_get_adapter(cfg_i2c_adap_id); SC7A30_client = i2c_new_device(i2c_adap, &SC7A30_board_info); i2c_put_adapter(i2c_adap); #endif #ifdef ALLWINNER_PLATFORM int ret ; if (input_fetch_sysconfig_para(&(gsensor_info.input_type))){ printk("%s: err.\n", __func__); return -1; }else{ ret = input_init_platform_resource(&(gsensor_info.input_type)); if (0 != ret){ printk("%s:ctp_ops.init_platform_resource err. \n", __func__); } } input_set_power_enable(&(gsensor_info.input_type),1); twi_id = gsensor_info.twi_id; printk("%s i2c twi is %d \n", __func__, twi_id); SC7A30_driver.detect = gsensor_detect; #endif return i2c_add_driver(&SC7A30_driver); } static void __exit SC7A30_exit(void) { #ifdef ACTIONS_PLATFORM i2c_unregister_device(SC7A30_client); #endif i2c_del_driver(&SC7A30_driver); input_free_platform_resource(&(gsensor_info.input_type)); } MODULE_AUTHOR("zhiyi quan "); MODULE_DESCRIPTION("SC7A30 3-Axis Orientation/Motion Detection Sensor driver"); MODULE_LICENSE("GPL"); module_init(SC7A30_init); module_exit(SC7A30_exit);