1343 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1343 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* drivers/input/touchscreen/atmel.c - ATMEL Touch driver
 | |
|  *
 | |
|  * Copyright (C) 2009 HTC Corporation.
 | |
|  *
 | |
|  * This software is licensed under the terms of the GNU General Public
 | |
|  * License version 2, as published by the Free Software Foundation, and
 | |
|  * may be copied, distributed, and modified under those terms.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <linux/module.h>
 | |
| #include <linux/input.h>
 | |
| #include <linux/interrupt.h>
 | |
| #include <linux/earlysuspend.h>
 | |
| #include <linux/platform_device.h>
 | |
| #include <linux/i2c.h>
 | |
| #include <linux/delay.h>
 | |
| #include <asm/io.h>
 | |
| #include <asm/gpio.h>
 | |
| #include <mach/board.h>
 | |
| #include <asm/mach-types.h>
 | |
| #include <linux/atmel_qt602240.h>
 | |
| #include <linux/jiffies.h>
 | |
| #include <mach/msm_hsusb.h>
 | |
| 
 | |
| #define ATMEL_EN_SYSFS
 | |
| #define ATMEL_I2C_RETRY_TIMES 10
 | |
| 
 | |
| struct atmel_ts_data {
 | |
| 	struct i2c_client *client;
 | |
| 	struct input_dev *input_dev;
 | |
| 	struct workqueue_struct *atmel_wq;
 | |
| 	struct work_struct work;
 | |
| 	int (*power) (int on);
 | |
| 	struct early_suspend early_suspend;
 | |
| 	struct info_id_t *id;
 | |
| 	struct object_t *object_table;
 | |
| 	uint8_t finger_count;
 | |
| 	uint16_t abs_x_min;
 | |
| 	uint16_t abs_x_max;
 | |
| 	uint16_t abs_y_min;
 | |
| 	uint16_t abs_y_max;
 | |
| 	uint8_t abs_pressure_min;
 | |
| 	uint8_t abs_pressure_max;
 | |
| 	uint8_t abs_width_min;
 | |
| 	uint8_t abs_width_max;
 | |
| 	uint8_t first_pressed;
 | |
| 	uint8_t debug_log_level;
 | |
| 	struct atmel_finger_data finger_data[10];
 | |
| 	uint8_t finger_type;
 | |
| 	uint8_t finger_support;
 | |
| 	uint16_t finger_pressed;
 | |
| 	uint8_t face_suppression;
 | |
| 	uint8_t grip_suppression;
 | |
| 	uint8_t noise_status[2];
 | |
| 	uint16_t *filter_level;
 | |
| 	uint8_t calibration_confirm;
 | |
| 	uint64_t timestamp;
 | |
| 	struct atmel_config_data config_setting[2];
 | |
| 	uint8_t status;
 | |
| 	uint8_t GCAF_sample;
 | |
| 	uint8_t *GCAF_level;
 | |
| 	uint8_t noisethr;
 | |
| #ifdef ATMEL_EN_SYSFS
 | |
| 	struct device dev;
 | |
| #endif
 | |
| 
 | |
| };
 | |
| 
 | |
| static struct atmel_ts_data *private_ts;
 | |
| 
 | |
| #ifdef CONFIG_HAS_EARLYSUSPEND
 | |
| static void atmel_ts_early_suspend(struct early_suspend *h);
 | |
| static void atmel_ts_late_resume(struct early_suspend *h);
 | |
| #endif
 | |
| 
 | |
| int i2c_atmel_read(struct i2c_client *client, uint16_t address, uint8_t *data, uint8_t length)
 | |
| {
 | |
| 	int retry;
 | |
| 	uint8_t addr[2];
 | |
| 
 | |
| 	struct i2c_msg msg[] = {
 | |
| 		{
 | |
| 			.addr = client->addr,
 | |
| 			.flags = 0,
 | |
| 			.len = 2,
 | |
| 			.buf = addr,
 | |
| 		},
 | |
| 		{
 | |
| 			.addr = client->addr,
 | |
| 			.flags = I2C_M_RD,
 | |
| 			.len = length,
 | |
| 			.buf = data,
 | |
| 		}
 | |
| 	};
 | |
| 	addr[0] = address & 0xFF;
 | |
| 	addr[1] = (address >> 8) & 0xFF;
 | |
| 
 | |
| 	for (retry = 0; retry < ATMEL_I2C_RETRY_TIMES; retry++) {
 | |
| 		if (i2c_transfer(client->adapter, msg, 2) == 2)
 | |
| 			break;
 | |
| 		mdelay(10);
 | |
| 	}
 | |
| 	if (retry == ATMEL_I2C_RETRY_TIMES) {
 | |
| 		printk(KERN_ERR "i2c_read_block retry over %d\n",
 | |
| 			ATMEL_I2C_RETRY_TIMES);
 | |
| 		return -EIO;
 | |
| 	}
 | |
| 	return 0;
 | |
| 
 | |
| }
 | |
| 
 | |
| int i2c_atmel_write(struct i2c_client *client, uint16_t address, uint8_t *data, uint8_t length)
 | |
| {
 | |
| 	int retry, loop_i;
 | |
| 	uint8_t buf[length + 2];
 | |
| 
 | |
| 	struct i2c_msg msg[] = {
 | |
| 		{
 | |
| 			.addr = client->addr,
 | |
| 			.flags = 0,
 | |
| 			.len = length + 2,
 | |
| 			.buf = buf,
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	buf[0] = address & 0xFF;
 | |
| 	buf[1] = (address >> 8) & 0xFF;
 | |
| 
 | |
| 	for (loop_i = 0; loop_i < length; loop_i++)
 | |
| 		buf[loop_i + 2] = data[loop_i];
 | |
| 
 | |
| 	for (retry = 0; retry < ATMEL_I2C_RETRY_TIMES; retry++) {
 | |
| 		if (i2c_transfer(client->adapter, msg, 1) == 1)
 | |
| 			break;
 | |
| 		mdelay(10);
 | |
| 	}
 | |
| 
 | |
| 	if (retry == ATMEL_I2C_RETRY_TIMES) {
 | |
| 		printk(KERN_ERR "i2c_write_block retry over %d\n",
 | |
| 			ATMEL_I2C_RETRY_TIMES);
 | |
| 		return -EIO;
 | |
| 	}
 | |
| 	return 0;
 | |
| 
 | |
| }
 | |
| 
 | |
| int i2c_atmel_write_byte_data(struct i2c_client *client, uint16_t address, uint8_t value)
 | |
| {
 | |
| 	i2c_atmel_write(client, address, &value, 1);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| uint16_t get_object_address(struct atmel_ts_data *ts, uint8_t object_type)
 | |
| {
 | |
| 	uint8_t loop_i;
 | |
| 	for (loop_i = 0; loop_i < ts->id->num_declared_objects; loop_i++) {
 | |
| 		if (ts->object_table[loop_i].object_type == object_type)
 | |
| 			return ts->object_table[loop_i].i2c_address;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| uint8_t get_object_size(struct atmel_ts_data *ts, uint8_t object_type)
 | |
| {
 | |
| 	uint8_t loop_i;
 | |
| 	for (loop_i = 0; loop_i < ts->id->num_declared_objects; loop_i++) {
 | |
| 		if (ts->object_table[loop_i].object_type == object_type)
 | |
| 			return ts->object_table[loop_i].size;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| uint8_t get_report_ids_size(struct atmel_ts_data *ts, uint8_t object_type)
 | |
| {
 | |
| 	uint8_t loop_i;
 | |
| 	for (loop_i = 0; loop_i < ts->id->num_declared_objects; loop_i++) {
 | |
| 		if (ts->object_table[loop_i].object_type == object_type)
 | |
| 			return ts->object_table[loop_i].report_ids;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #ifdef ATMEL_EN_SYSFS
 | |
| static ssize_t atmel_gpio_show(struct device *dev,
 | |
| 		struct device_attribute *attr, char *buf)
 | |
| {
 | |
| 	int ret = 0;
 | |
| 	struct atmel_ts_data *ts_data;
 | |
| 	struct atmel_i2c_platform_data *pdata;
 | |
| 
 | |
| 	ts_data = private_ts;
 | |
| 	pdata = ts_data->client->dev.platform_data;
 | |
| 
 | |
| 	ret = gpio_get_value(pdata->gpio_irq);
 | |
| 	printk(KERN_DEBUG "GPIO_TP_INT_N=%d\n", pdata->gpio_irq);
 | |
| 	sprintf(buf, "GPIO_TP_INT_N=%d\n", ret);
 | |
| 	ret = strlen(buf) + 1;
 | |
| 	return ret;
 | |
| }
 | |
| static DEVICE_ATTR(gpio, 0444, atmel_gpio_show, NULL);
 | |
| static ssize_t atmel_vendor_show(struct device *dev,
 | |
| 		struct device_attribute *attr, char *buf)
 | |
| {
 | |
| 	int ret = 0;
 | |
| 	struct atmel_ts_data *ts_data;
 | |
| 	ts_data = private_ts;
 | |
| 	sprintf(buf, "%s_x%4.4X_x%4.4X\n", "ATMEL",
 | |
| 		ts_data->id->family_id, ts_data->id->version);
 | |
| 	ret = strlen(buf) + 1;
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static DEVICE_ATTR(vendor, 0444, atmel_vendor_show, NULL);
 | |
| 
 | |
| static uint16_t atmel_reg_addr;
 | |
| 
 | |
| static ssize_t atmel_register_show(struct device *dev,
 | |
| 		struct device_attribute *attr, char *buf)
 | |
| {
 | |
| 	int ret = 0;
 | |
| 	uint8_t ptr[1];
 | |
| 	struct atmel_ts_data *ts_data;
 | |
| 	ts_data = private_ts;
 | |
| 	if (i2c_atmel_read(ts_data->client, atmel_reg_addr, ptr, 1) < 0) {
 | |
| 		printk(KERN_WARNING "%s: read fail\n", __func__);
 | |
| 		return ret;
 | |
| 	}
 | |
| 	ret += sprintf(buf, "addr: %d, data: %d\n", atmel_reg_addr, ptr[0]);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static ssize_t atmel_register_store(struct device *dev,
 | |
| 		struct device_attribute *attr, const char *buf, size_t count)
 | |
| {
 | |
| 	int ret = 0;
 | |
| 	struct atmel_ts_data *ts_data;
 | |
| 	char buf_tmp[4], buf_zero[200];
 | |
| 	uint8_t write_da;
 | |
| 
 | |
| 	ts_data = private_ts;
 | |
| 	memset(buf_tmp, 0x0, sizeof(buf_tmp));
 | |
| 	if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':' &&
 | |
| 		(buf[5] == ':' || buf[5] == '\n')) {
 | |
| 		memcpy(buf_tmp, buf + 2, 3);
 | |
| 		atmel_reg_addr = simple_strtol(buf_tmp, NULL, 10);
 | |
| 		printk(KERN_DEBUG "read addr: 0x%X\n", atmel_reg_addr);
 | |
| 		if (!atmel_reg_addr) {
 | |
| 			printk(KERN_WARNING "%s: string to number fail\n",
 | |
| 								__func__);
 | |
| 			return count;
 | |
| 		}
 | |
| 		printk(KERN_DEBUG "%s: set atmel_reg_addr is: %d\n",
 | |
| 						__func__, atmel_reg_addr);
 | |
| 		if (buf[0] == 'w' && buf[5] == ':' && buf[9] == '\n') {
 | |
| 			memcpy(buf_tmp, buf + 6, 3);
 | |
| 			write_da = simple_strtol(buf_tmp, NULL, 10);
 | |
| 			printk(KERN_DEBUG "write addr: 0x%X, data: 0x%X\n",
 | |
| 						atmel_reg_addr, write_da);
 | |
| 			ret = i2c_atmel_write_byte_data(ts_data->client,
 | |
| 						atmel_reg_addr, write_da);
 | |
| 			if (ret < 0) {
 | |
| 				printk(KERN_ERR "%s: write fail(%d)\n",
 | |
| 								__func__, ret);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	if ((buf[0] == '0') && (buf[1] == ':') && (buf[5] == ':')) {
 | |
| 		memcpy(buf_tmp, buf + 2, 3);
 | |
| 		atmel_reg_addr = simple_strtol(buf_tmp, NULL, 10);
 | |
| 		memcpy(buf_tmp, buf + 6, 3);
 | |
| 		memset(buf_zero, 0x0, sizeof(buf_zero));
 | |
| 		ret = i2c_atmel_write(ts_data->client, atmel_reg_addr,
 | |
| 			buf_zero, simple_strtol(buf_tmp, NULL, 10) - atmel_reg_addr + 1);
 | |
| 		if (buf[9] == 'r') {
 | |
| 			i2c_atmel_write_byte_data(ts_data->client,
 | |
| 				get_object_address(ts_data, GEN_COMMANDPROCESSOR_T6) + 1, 0x55);
 | |
| 			i2c_atmel_write_byte_data(ts_data->client,
 | |
| 				get_object_address(ts_data, GEN_COMMANDPROCESSOR_T6), 0x11);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return count;
 | |
| }
 | |
| 
 | |
| static DEVICE_ATTR(register, 0644, atmel_register_show, atmel_register_store);
 | |
| 
 | |
| static ssize_t atmel_regdump_show(struct device *dev,
 | |
| 		struct device_attribute *attr, char *buf)
 | |
| {
 | |
| 	int count = 0, ret_t = 0;
 | |
| 	struct atmel_ts_data *ts_data;
 | |
| 	uint16_t loop_i;
 | |
| 	uint8_t ptr[1];
 | |
| 	ts_data = private_ts;
 | |
| 	if (ts_data->id->version >= 0x14) {
 | |
| 		for (loop_i = 230; loop_i <= 425; loop_i++) {
 | |
| 			ret_t = i2c_atmel_read(ts_data->client, loop_i, ptr, 1);
 | |
| 			if (ret_t < 0) {
 | |
| 				printk(KERN_WARNING "dump fail, addr: %d\n",
 | |
| 								loop_i);
 | |
| 			}
 | |
| 			count += sprintf(buf + count, "addr[%3d]: %3d, ",
 | |
| 								loop_i , *ptr);
 | |
| 			if (((loop_i - 230) % 4) == 3)
 | |
| 				count += sprintf(buf + count, "\n");
 | |
| 		}
 | |
| 		count += sprintf(buf + count, "\n");
 | |
| 	}
 | |
| 	return count;
 | |
| }
 | |
| 
 | |
| static ssize_t atmel_regdump_dump(struct device *dev,
 | |
| 		struct device_attribute *attr, const char *buf, size_t count)
 | |
| {
 | |
| 	struct atmel_ts_data *ts_data;
 | |
| 	ts_data = private_ts;
 | |
| 	if (buf[0] >= '0' && buf[0] <= '9' && buf[1] == '\n')
 | |
| 		ts_data->debug_log_level = buf[0] - 0x30;
 | |
| 
 | |
| 	return count;
 | |
| 
 | |
| }
 | |
| 
 | |
| static DEVICE_ATTR(regdump, 0644, atmel_regdump_show, atmel_regdump_dump);
 | |
| 
 | |
| static ssize_t atmel_debug_level_show(struct device *dev,
 | |
| 		struct device_attribute *attr, char *buf)
 | |
| {
 | |
| 	struct atmel_ts_data *ts_data;
 | |
| 	size_t count = 0;
 | |
| 	ts_data = private_ts;
 | |
| 
 | |
| 	count += sprintf(buf, "%d\n", ts_data->debug_log_level);
 | |
| 
 | |
| 	return count;
 | |
| }
 | |
| 
 | |
| static ssize_t atmel_debug_level_dump(struct device *dev,
 | |
| 		struct device_attribute *attr, const char *buf, size_t count)
 | |
| {
 | |
| 	struct atmel_ts_data *ts_data;
 | |
| 	ts_data = private_ts;
 | |
| 	if (buf[0] >= '0' && buf[0] <= '9' && buf[1] == '\n')
 | |
| 		ts_data->debug_log_level = buf[0] - 0x30;
 | |
| 
 | |
| 	return count;
 | |
| }
 | |
| 
 | |
| static DEVICE_ATTR(debug_level, 0644, atmel_debug_level_show, atmel_debug_level_dump);
 | |
| 
 | |
| static struct kobject *android_touch_kobj;
 | |
| 
 | |
| static int atmel_touch_sysfs_init(void)
 | |
| {
 | |
| 	int ret;
 | |
| 	android_touch_kobj = kobject_create_and_add("android_touch", NULL);
 | |
| 	if (android_touch_kobj == NULL) {
 | |
| 		printk(KERN_ERR "%s: subsystem_register failed\n", __func__);
 | |
| 		ret = -ENOMEM;
 | |
| 		return ret;
 | |
| 	}
 | |
| 	ret = sysfs_create_file(android_touch_kobj, &dev_attr_gpio.attr);
 | |
| 	if (ret) {
 | |
| 		printk(KERN_ERR "%s: sysfs_create_file failed\n", __func__);
 | |
| 		return ret;
 | |
| 	}
 | |
| 	ret = sysfs_create_file(android_touch_kobj, &dev_attr_vendor.attr);
 | |
| 	if (ret) {
 | |
| 		printk(KERN_ERR "%s: sysfs_create_file failed\n", __func__);
 | |
| 		return ret;
 | |
| 	}
 | |
| 	atmel_reg_addr = 0;
 | |
| 	ret = sysfs_create_file(android_touch_kobj, &dev_attr_register.attr);
 | |
| 	if (ret) {
 | |
| 		printk(KERN_ERR "%s: sysfs_create_file failed\n", __func__);
 | |
| 		return ret;
 | |
| 	}
 | |
| 	ret = sysfs_create_file(android_touch_kobj, &dev_attr_regdump.attr);
 | |
| 	if (ret) {
 | |
| 		printk(KERN_ERR "%s: sysfs_create_file failed\n", __func__);
 | |
| 		return ret;
 | |
| 	}
 | |
| 	ret = sysfs_create_file(android_touch_kobj, &dev_attr_debug_level.attr);
 | |
| 	if (ret) {
 | |
| 		printk(KERN_ERR "%s: sysfs_create_file failed\n", __func__);
 | |
| 		return ret;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void atmel_touch_sysfs_deinit(void)
 | |
| {
 | |
| 	sysfs_remove_file(android_touch_kobj, &dev_attr_regdump.attr);
 | |
| 	sysfs_remove_file(android_touch_kobj, &dev_attr_register.attr);
 | |
| 	sysfs_remove_file(android_touch_kobj, &dev_attr_vendor.attr);
 | |
| 	sysfs_remove_file(android_touch_kobj, &dev_attr_gpio.attr);
 | |
| 	kobject_del(android_touch_kobj);
 | |
| }
 | |
| 
 | |
| #endif
 | |
| static int check_delta(struct atmel_ts_data*ts)
 | |
| {
 | |
| 	int8_t data[128];
 | |
| 	uint8_t loop_i;
 | |
| 	int16_t rawdata, count = 0;
 | |
| 
 | |
| 	memset(data, 0xFF, sizeof(data));
 | |
| 	i2c_atmel_write_byte_data(ts->client,
 | |
| 		get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + 5, 0x10);
 | |
| 
 | |
| 	for (loop_i = 0; !(data[0] == 0x10 && data[1] == 0x00) && loop_i < 10; loop_i++) {
 | |
| 		msleep(5);
 | |
| 		i2c_atmel_read(ts->client, get_object_address(ts, DIAGNOSTIC_T37), data, 2);
 | |
| 	}
 | |
| 	if (loop_i == 10)
 | |
| 		printk(KERN_ERR "%s: Diag data not ready\n", __func__);
 | |
| 
 | |
| 	i2c_atmel_read(ts->client, get_object_address(ts, DIAGNOSTIC_T37), data, 128);
 | |
| 	if (data[0] == 0x10 && data[1] == 0x00) {
 | |
| 		for (loop_i = 2; loop_i < 127; loop_i += 2) {
 | |
| 			rawdata = data[loop_i+1] << 8 | data[loop_i];
 | |
| 			if (abs(rawdata) > 50)
 | |
| 				count++;
 | |
| 		}
 | |
| 		if (count > 32)
 | |
| 			return 1;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void check_calibration(struct atmel_ts_data*ts)
 | |
| {
 | |
| 	uint8_t data[82];
 | |
| 	uint8_t loop_i, loop_j, x_limit = 0, check_mask, tch_ch = 0, atch_ch = 0;
 | |
| 
 | |
| 	memset(data, 0xFF, sizeof(data));
 | |
| 	i2c_atmel_write_byte_data(ts->client,
 | |
| 		get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + 5, 0xF3);
 | |
| 
 | |
| 	for (loop_i = 0; !(data[0] == 0xF3 && data[1] == 0x00) && loop_i < 10; loop_i++) {
 | |
| 		msleep(5);
 | |
| 		i2c_atmel_read(ts->client, get_object_address(ts, DIAGNOSTIC_T37), data, 2);
 | |
| 	}
 | |
| 
 | |
| 	if (loop_i == 10)
 | |
| 		printk(KERN_ERR "%s: Diag data not ready\n", __func__);
 | |
| 
 | |
| 	i2c_atmel_read(ts->client, get_object_address(ts, DIAGNOSTIC_T37), data, 82);
 | |
| 	if (data[0] == 0xF3 && data[1] == 0x00) {
 | |
| 		x_limit = 16 + ts->config_setting[0].config_T28[2];
 | |
| 		x_limit = x_limit << 1;
 | |
| 
 | |
| 		for (loop_i = 0; loop_i < x_limit; loop_i += 2) {
 | |
| 			for (loop_j = 0; loop_j < 8; loop_j++) {
 | |
| 				check_mask = 1 << loop_j;
 | |
| 				if (data[2 + loop_i] & check_mask)
 | |
| 					tch_ch++;
 | |
| 				if (data[3 + loop_i] & check_mask)
 | |
| 					tch_ch++;
 | |
| 				if (data[42 + loop_i] & check_mask)
 | |
| 					atch_ch++;
 | |
| 				if (data[43 + loop_i] & check_mask)
 | |
| 					atch_ch++;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	i2c_atmel_write_byte_data(ts->client,
 | |
| 		get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + 5, 0x01);
 | |
| 
 | |
| 	if (tch_ch && (atch_ch == 0)) {
 | |
| 		if (jiffies > (ts->timestamp + HZ/2) && (ts->calibration_confirm == 1)) {
 | |
| 			ts->calibration_confirm = 2;
 | |
| 			printk(KERN_INFO "%s: calibration confirm\n", __func__);
 | |
| 			i2c_atmel_write_byte_data(ts->client,
 | |
| 			get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + 6,
 | |
| 				ts->config_setting[ts->status].config_T8[6]);
 | |
| 			i2c_atmel_write_byte_data(ts->client,
 | |
| 				get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + 7,
 | |
| 				ts->config_setting[ts->status].config_T8[7]);
 | |
| 		}
 | |
| 		if (ts->calibration_confirm < 2)
 | |
| 			ts->calibration_confirm = 1;
 | |
| 		ts->timestamp = jiffies;
 | |
| 	} else if ((tch_ch - 25) <= atch_ch && (tch_ch || atch_ch)) {
 | |
| 		ts->calibration_confirm = 0;
 | |
| 		i2c_atmel_write_byte_data(ts->client,
 | |
| 			get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + 2, 0x55);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void atmel_ts_work_func(struct work_struct *work)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct atmel_ts_data *ts = container_of(work, struct atmel_ts_data, work);
 | |
| 	uint8_t data[ts->finger_support * 9];
 | |
| 
 | |
| 	uint8_t loop_i, loop_j, report_type, msg_num, msg_byte_num = 8, finger_report;
 | |
| 	msg_num = (ts->finger_count && ts->id->version >= 0x15)
 | |
| 		? ts->finger_count : 1;
 | |
| 
 | |
| 	ret = i2c_atmel_read(ts->client, get_object_address(ts,
 | |
| 		GEN_MESSAGEPROCESSOR_T5), data, msg_num * 9 - 2);
 | |
| 
 | |
| 	if (ts->debug_log_level & 0x1) {
 | |
| 		for (loop_i = 0; loop_i < msg_num * 9 - 2; loop_i++)
 | |
| 			printk("0x%2.2X ", data[loop_i]);
 | |
| 		printk("\n");
 | |
| 	}
 | |
| 
 | |
| 	if (ts->id->version >= 0x15) {
 | |
| 	for (loop_i = 0; loop_i < msg_num; loop_i++) {
 | |
| 		report_type = data[loop_i * 9] - ts->finger_type;
 | |
| 		if (report_type >= 0 && report_type < ts->finger_support) {
 | |
| 			if (ts->calibration_confirm < 2 && ts->id->version >= 0x16)
 | |
| 				check_calibration(ts);
 | |
| 			ts->finger_data[report_type].x = data[loop_i * 9 + 2] << 2 | data[loop_i * 9 + 4] >> 6;
 | |
| 			ts->finger_data[report_type].y = data[loop_i * 9 + 3] << 2 | (data[loop_i * 9 + 4] & 0x0C) >> 2;
 | |
| 			ts->finger_data[report_type].w = data[loop_i * 9 + 5];
 | |
| 			ts->finger_data[report_type].z = data[loop_i * 9 + 6];
 | |
| 			if (data[loop_i * 9 + 1] & 0x20) {
 | |
| 				if ((ts->grip_suppression >> report_type) & 1)
 | |
| 					ts->grip_suppression &= ~(1 << report_type);
 | |
| 				if (((ts->finger_pressed >> report_type) & 1) == 1) {
 | |
| 					ts->finger_count--;
 | |
| 					ts->finger_pressed &= ~(1 << report_type);
 | |
| 					if (!ts->first_pressed) {
 | |
| 						if (!ts->finger_count)
 | |
| 							ts->first_pressed = 1;
 | |
| 						printk(KERN_INFO "E%d@%d,%d\n", report_type + 1,
 | |
| 								ts->finger_data[report_type].x, ts->finger_data[report_type].y);
 | |
| 					}
 | |
| 				}
 | |
| 			} else if ((data[loop_i * 9 + 1] & 0xC0) && (((ts->finger_pressed >> report_type) & 1) == 0)) {
 | |
| 				if (ts->filter_level[0]) {
 | |
| 					if (ts->finger_data[report_type].x < ts->filter_level[0] || ts->finger_data[report_type].x > ts->filter_level[3])
 | |
| 						ts->grip_suppression |= 1 << report_type;
 | |
| 					else if ((ts->finger_data[report_type].x < ts->filter_level[1] || ts->finger_data[report_type].x > ts->filter_level[2])
 | |
| 						&& ((ts->grip_suppression >> report_type) & 1))
 | |
| 						ts->grip_suppression |= 1 << report_type;
 | |
| 					else if (ts->finger_data[report_type].x > ts->filter_level[1] && ts->finger_data[report_type].x < ts->filter_level[2])
 | |
| 						ts->grip_suppression &= ~(1 << report_type);
 | |
| 				}
 | |
| 				if (((ts->grip_suppression >> report_type) & 1) == 0) {
 | |
| 					if (!ts->first_pressed)
 | |
| 						printk(KERN_INFO "S%d@%d,%d\n", report_type + 1,
 | |
| 							ts->finger_data[report_type].x, ts->finger_data[report_type].y);
 | |
| 					ts->finger_count++;
 | |
| 					ts->finger_pressed |= 1 << report_type;
 | |
| 				}
 | |
| 			}
 | |
| 		} else {
 | |
| 			if (data[loop_i * 9] == get_report_ids_size(ts, GEN_COMMANDPROCESSOR_T6)) {
 | |
| 				printk(KERN_INFO "Touch Status: ");
 | |
| 				msg_byte_num = 5;
 | |
| 			} else if (data[loop_i * 9] == get_report_ids_size(ts, PROCI_GRIPFACESUPPRESSION_T20)) {
 | |
| 				if (ts->calibration_confirm < 2 && ts->id->version >= 0x16)
 | |
| 					check_calibration(ts);
 | |
| 				ts->face_suppression = data[loop_i * 9 + 1];
 | |
| 				printk(KERN_INFO "Touch Face suppression %s: ",
 | |
| 					ts->face_suppression ? "Active" : "Inactive");
 | |
| 				msg_byte_num = 2;
 | |
| 			} else if (data[loop_i * 9] == get_report_ids_size(ts, PROCG_NOISESUPPRESSION_T22)) {
 | |
| 				if (data[loop_i * 9 + 1] == 0x10) /* reduce message print */
 | |
| 					msg_byte_num = 0;
 | |
| 				else {
 | |
| 					printk(KERN_INFO "Touch Noise suppression: ");
 | |
| 					msg_byte_num = 4;
 | |
| 					if (ts->status && data[loop_i * 9 + 2] >= ts->GCAF_sample) {
 | |
| 						i2c_atmel_write_byte_data(ts->client,
 | |
| 							get_object_address(ts, GEN_POWERCONFIG_T7), 0x08);
 | |
| 						i2c_atmel_write_byte_data(ts->client,
 | |
| 							get_object_address(ts, GEN_POWERCONFIG_T7) + 1, 0x08);
 | |
| 						for (loop_j = 0; loop_j < 5; loop_j++) {
 | |
| 							if (ts->GCAF_sample < ts->GCAF_level[loop_j]) {
 | |
| 								ts->GCAF_sample = ts->GCAF_level[loop_j];
 | |
| 								break;
 | |
| 							}
 | |
| 						}
 | |
| 						if (loop_j == 5)
 | |
| 							ts->GCAF_sample += 24;
 | |
| 						if (ts->GCAF_sample >= 63) {
 | |
| 							ts->GCAF_sample = 63;
 | |
| 							i2c_atmel_write_byte_data(ts->client,
 | |
| 								get_object_address(ts, PROCG_NOISESUPPRESSION_T22) + 8,
 | |
| 								ts->config_setting[1].config[1]);
 | |
| 							i2c_atmel_write_byte_data(ts->client,
 | |
| 								get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + 7, 0x1);
 | |
| 						}
 | |
| 						i2c_atmel_write_byte_data(ts->client,
 | |
| 							get_object_address(ts, SPT_CTECONFIG_T28) + 4, ts->GCAF_sample);
 | |
| 					}
 | |
| 					if (data[loop_i * 9 + 1] & 0x0C && ts->GCAF_sample == 63) {
 | |
| 						ts->noisethr += 30;
 | |
| 						if (ts->noisethr > 255)
 | |
| 							ts->noisethr = 255;
 | |
| 						i2c_atmel_write_byte_data(ts->client,
 | |
| 							get_object_address(ts, PROCG_NOISESUPPRESSION_T22) + 8,
 | |
| 							ts->noisethr);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			if (data[loop_i * 9] != 0xFF) {
 | |
| 				for (loop_j = 0; loop_j < msg_byte_num; loop_j++)
 | |
| 					printk("0x%2.2X ", data[loop_i * 9 + loop_j]);
 | |
| 				if (msg_byte_num)
 | |
| 					printk("\n");
 | |
| 			}
 | |
| 		}
 | |
| 		if (loop_i == msg_num - 1) {
 | |
| 			if (!ts->finger_count || ts->face_suppression) {
 | |
| 				ts->finger_pressed = 0;
 | |
| 				ts->finger_count = 0;
 | |
| #ifdef CONFIG_TOUCHSCREEN_COMPATIBLE_REPORT
 | |
| 				input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
 | |
| #else
 | |
| 				input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
 | |
| 				input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
 | |
| #endif
 | |
| 				if (ts->debug_log_level & 0x2)
 | |
| 					printk(KERN_INFO "Finger leave\n");
 | |
| 			} else {
 | |
| 				for (loop_i = 0, finger_report = 0; loop_i < ts->finger_support; loop_i++) {
 | |
| 					if (((ts->finger_pressed >> loop_i) & 1) == 1) {
 | |
| 						finger_report++;
 | |
| #ifdef CONFIG_TOUCHSCREEN_COMPATIBLE_REPORT
 | |
| 						input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
 | |
| 							ts->finger_data[loop_i].z);
 | |
| 						input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
 | |
| 							ts->finger_data[loop_i].w);
 | |
| 						input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
 | |
| 							ts->finger_data[loop_i].x);
 | |
| 						input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
 | |
| 							ts->finger_data[loop_i].y);
 | |
| 						input_mt_sync(ts->input_dev);
 | |
| #else
 | |
| 						input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE,
 | |
| 							ts->finger_data[loop_i].z << 16 | ts->finger_data[loop_i].w);
 | |
| 						input_report_abs(ts->input_dev, ABS_MT_POSITION,
 | |
| 							(ts->finger_count == finger_report) << 31 |
 | |
| 							ts->finger_data[loop_i].x << 16 | ts->finger_data[loop_i].y);
 | |
| #endif
 | |
| 						if (ts->debug_log_level & 0x2)
 | |
| 							printk(KERN_INFO "Finger %d=> X:%d, Y:%d w:%d, z:%d, F:%d\n",
 | |
| 								loop_i + 1, ts->finger_data[loop_i].x,
 | |
| 								ts->finger_data[loop_i].y, ts->finger_data[loop_i].w,
 | |
| 								ts->finger_data[loop_i].z, ts->finger_count);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| #ifdef CONFIG_TOUCHSCREEN_COMPATIBLE_REPORT
 | |
| 			input_sync(ts->input_dev);
 | |
| #endif
 | |
| 		}
 | |
| 	}
 | |
| 	}	else { /*read one message one time */
 | |
| 	report_type = data[0] - ts->finger_type;
 | |
| 	if (report_type >= 0 && report_type < ts->finger_support) {
 | |
| 		/* for issue debug only */
 | |
| 		if ((data[1] & 0x60) == 0x60)
 | |
| 			printk(KERN_INFO"x60 ISSUE happened: %x, %x, %x, %x, %x, %x, %x, %x\n",
 | |
| 				data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
 | |
| 		if ((data[1] & 0x20) && (((ts->finger_pressed >> report_type) & 1) == 1)) {
 | |
| 			ts->finger_count--;
 | |
| 			ts->finger_pressed &= ~(1 << report_type);
 | |
| 		} else if ((data[1] & 0xC0) && (((ts->finger_pressed >> report_type) & 1) == 0)) {
 | |
| 			ts->finger_count++;
 | |
| 			ts->finger_pressed |= 1 << report_type;
 | |
| 		}
 | |
| 		ts->finger_data[report_type].x = data[2] << 2 | data[4] >> 6;
 | |
| 		ts->finger_data[report_type].y = data[3] << 2 | (data[4] & 0x0C) >> 2;
 | |
| 		ts->finger_data[report_type].w = data[5];
 | |
| 		ts->finger_data[report_type].z = data[6];
 | |
| 		if (!ts->finger_count) {
 | |
| 			ts->finger_pressed = 0;
 | |
| 			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
 | |
| 			if (ts->debug_log_level & 0x2)
 | |
| 				printk(KERN_INFO "Finger leave\n");
 | |
| 		} else {
 | |
| 			for (loop_i = 0; loop_i < ts->finger_support; loop_i++) {
 | |
| 				if (((ts->finger_pressed >> loop_i) & 1) == 1) {
 | |
| 					input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
 | |
| 						ts->finger_data[loop_i].z);
 | |
| 					input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
 | |
| 						ts->finger_data[loop_i].w);
 | |
| 					input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
 | |
| 						ts->finger_data[loop_i].x);
 | |
| 					input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
 | |
| 						ts->finger_data[loop_i].y);
 | |
| 					input_mt_sync(ts->input_dev);
 | |
| 					if (ts->debug_log_level & 0x2)
 | |
| 						printk(KERN_INFO "Finger %d=> X:%d, Y:%d w:%d, z:%d, F:%d\n",
 | |
| 							loop_i + 1, ts->finger_data[loop_i].x,
 | |
| 							ts->finger_data[loop_i].y, ts->finger_data[loop_i].w,
 | |
| 							ts->finger_data[loop_i].z, ts->finger_count);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		input_sync(ts->input_dev);
 | |
| 	} else
 | |
| 		printk(KERN_INFO"RAW data: %x, %x, %x, %x, %x, %x, %x, %x\n",
 | |
| 			data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
 | |
| 	}
 | |
| 	enable_irq(ts->client->irq);
 | |
| }
 | |
| 
 | |
| static irqreturn_t atmel_ts_irq_handler(int irq, void *dev_id)
 | |
| {
 | |
| 	struct atmel_ts_data *ts = dev_id;
 | |
| 
 | |
| 	disable_irq_nosync(ts->client->irq);
 | |
| 	queue_work(ts->atmel_wq, &ts->work);
 | |
| 	return IRQ_HANDLED;
 | |
| }
 | |
| 
 | |
| static void cable_tp_status_handler_func(int connected)
 | |
| {
 | |
| 	struct atmel_ts_data *ts;
 | |
| 	ts = private_ts;
 | |
| 	printk(KERN_INFO "Touch: cable change to %d\n", connected);
 | |
| 	if (connected != ts->status) {
 | |
| 		if (connected)
 | |
| 			ts->status = 1;
 | |
| 		else
 | |
| 			ts->status = 0;
 | |
| 
 | |
| 		if (ts->config_setting[1].config[0]) {
 | |
| 			if (ts->status) {
 | |
| 				ts->calibration_confirm = 2;
 | |
| 				i2c_atmel_write_byte_data(ts->client,
 | |
| 					get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + 6,
 | |
| 					ts->config_setting[ts->status].config_T8[6]);
 | |
| 				i2c_atmel_write_byte_data(ts->client,
 | |
| 					get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + 7,
 | |
| 					ts->config_setting[ts->status].config_T8[7]);
 | |
| 			}
 | |
| 			i2c_atmel_write_byte_data(ts->client,
 | |
| 				get_object_address(ts, TOUCH_MULTITOUCHSCREEN_T9) + 7,
 | |
| 				ts->config_setting[ts->status].config[0]);
 | |
| 			if (!ts->status)
 | |
| 				i2c_atmel_write_byte_data(ts->client,
 | |
| 					get_object_address(ts, PROCG_NOISESUPPRESSION_T22) + 8,
 | |
| 					ts->config_setting[ts->status].config[1]);
 | |
| 			i2c_atmel_write_byte_data(ts->client,
 | |
| 				get_object_address(ts, SPT_CTECONFIG_T28) + 3,
 | |
| 				ts->config_setting[ts->status].config[2]);
 | |
| 			i2c_atmel_write_byte_data(ts->client,
 | |
| 				get_object_address(ts, SPT_CTECONFIG_T28) + 4,
 | |
| 				ts->config_setting[ts->status].config[3]);
 | |
| 			ts->GCAF_sample = ts->config_setting[1].config[3];
 | |
| 		} else {
 | |
| 			if (ts->config_setting[1].config_T7 != NULL)
 | |
| 				i2c_atmel_write(ts->client,
 | |
| 					get_object_address(ts, GEN_POWERCONFIG_T7),
 | |
| 					ts->config_setting[ts->status].config_T7,
 | |
| 					get_object_size(ts, GEN_POWERCONFIG_T7));
 | |
| 			if (ts->config_setting[1].config_T8 != NULL)
 | |
| 				i2c_atmel_write(ts->client,
 | |
| 					get_object_address(ts, GEN_ACQUISITIONCONFIG_T8),
 | |
| 					ts->config_setting[1].config_T8,
 | |
| 					get_object_size(ts, GEN_ACQUISITIONCONFIG_T8));
 | |
| 			if (ts->config_setting[ts->status].config_T9 != NULL)
 | |
| 				i2c_atmel_write(ts->client,
 | |
| 					get_object_address(ts, TOUCH_MULTITOUCHSCREEN_T9),
 | |
| 					ts->config_setting[ts->status].config_T9,
 | |
| 					get_object_size(ts, TOUCH_MULTITOUCHSCREEN_T9));
 | |
| 			if (ts->config_setting[ts->status].config_T22 != NULL)
 | |
| 				i2c_atmel_write(ts->client,
 | |
| 					get_object_address(ts, PROCG_NOISESUPPRESSION_T22),
 | |
| 					ts->config_setting[ts->status].config_T22,
 | |
| 					get_object_size(ts, PROCG_NOISESUPPRESSION_T22));
 | |
| 			if (ts->config_setting[ts->status].config_T28 != NULL) {
 | |
| 				i2c_atmel_write(ts->client,
 | |
| 					get_object_address(ts, SPT_CTECONFIG_T28),
 | |
| 					ts->config_setting[ts->status].config_T28,
 | |
| 					get_object_size(ts, SPT_CTECONFIG_T28));
 | |
| 				ts->GCAF_sample = ts->config_setting[ts->status].config_T28[4];
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static struct t_usb_status_notifier cable_status_handler = {
 | |
| 	.name = "usb_tp_connected",
 | |
| 	.func = cable_tp_status_handler_func,
 | |
| };
 | |
| 
 | |
| static int atmel_ts_probe(struct i2c_client *client,
 | |
| 			 const struct i2c_device_id *id)
 | |
| {
 | |
| 	struct atmel_ts_data *ts;
 | |
| 	struct atmel_i2c_platform_data *pdata;
 | |
| 	int ret = 0, i = 0, intr = 0;
 | |
| 	uint8_t loop_i;
 | |
| 	struct i2c_msg msg[2];
 | |
| 	uint8_t data[16];
 | |
| 	uint8_t type_count = 0, CRC_check = 0;
 | |
| 
 | |
| 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 | |
| 		printk(KERN_ERR"%s: need I2C_FUNC_I2C\n", __func__);
 | |
| 		ret = -ENODEV;
 | |
| 		goto err_check_functionality_failed;
 | |
| 	}
 | |
| 
 | |
| 	ts = kzalloc(sizeof(struct atmel_ts_data), GFP_KERNEL);
 | |
| 	if (ts == NULL) {
 | |
| 		printk(KERN_ERR"%s: allocate atmel_ts_data failed\n", __func__);
 | |
| 		ret = -ENOMEM;
 | |
| 		goto err_alloc_data_failed;
 | |
| 	}
 | |
| 
 | |
| 	ts->atmel_wq = create_singlethread_workqueue("atmel_wq");
 | |
| 	if (!ts->atmel_wq) {
 | |
| 		printk(KERN_ERR"%s: create workqueue failed\n", __func__);
 | |
| 		ret = -ENOMEM;
 | |
| 		goto err_cread_wq_failed;
 | |
| 	}
 | |
| 
 | |
| 	INIT_WORK(&ts->work, atmel_ts_work_func);
 | |
| 	ts->client = client;
 | |
| 	i2c_set_clientdata(client, ts);
 | |
| 	pdata = client->dev.platform_data;
 | |
| 
 | |
| 	if (pdata) {
 | |
| 		ts->power = pdata->power;
 | |
| 		intr = pdata->gpio_irq;
 | |
| 	}
 | |
| 	if (ts->power) {
 | |
| 		ret = ts->power(1);
 | |
| 		msleep(2);
 | |
| 		if (ret < 0) {
 | |
| 			printk(KERN_ERR "%s:power on failed\n", __func__);
 | |
| 			goto err_power_failed;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for (loop_i = 0; loop_i < 10; loop_i++) {
 | |
| 		if (!gpio_get_value(intr))
 | |
| 			break;
 | |
| 		msleep(10);
 | |
| 	}
 | |
| 
 | |
| 	if (loop_i == 10)
 | |
| 		printk(KERN_ERR "No Messages\n");
 | |
| 
 | |
| 	/* read message*/
 | |
| 	msg[0].addr = ts->client->addr;
 | |
| 	msg[0].flags = I2C_M_RD;
 | |
| 	msg[0].len = 7;
 | |
| 	msg[0].buf = data;
 | |
| 	ret = i2c_transfer(client->adapter, msg, 1);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		printk(KERN_INFO "No Atmel chip inside\n");
 | |
| 		goto err_detect_failed;
 | |
| 	}
 | |
| 	printk(KERN_INFO "Touch: 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X\n",
 | |
| 		data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
 | |
| 
 | |
| 	if (data[1] & 0x24) {
 | |
| 		printk(KERN_INFO "atmel_ts_probe(): init err: %x\n", data[1]);
 | |
| 		goto err_detect_failed;
 | |
| 	} else {
 | |
| 		for (loop_i = 0; loop_i < 10; loop_i++) {
 | |
| 			if (gpio_get_value(intr)) {
 | |
| 				printk(KERN_INFO "Touch: No more message\n");
 | |
| 				break;
 | |
| 			}
 | |
| 			ret = i2c_transfer(client->adapter, msg, 1);
 | |
| 			printk(KERN_INFO "Touch: 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X\n",
 | |
| 				data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
 | |
| 			msleep(10);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Read the info block data. */
 | |
| 	ts->id = kzalloc(sizeof(struct info_id_t), GFP_KERNEL);
 | |
| 	if (ts->id == NULL) {
 | |
| 		printk(KERN_ERR"%s: allocate info_id_t failed\n", __func__);
 | |
| 		goto err_alloc_failed;
 | |
| 	}
 | |
| 	ret = i2c_atmel_read(client, 0x00, data, 7);
 | |
| 
 | |
| 	ts->id->family_id = data[0];
 | |
| 	ts->id->variant_id = data[1];
 | |
| 	if (ts->id->family_id == 0x80 && ts->id->variant_id == 0x10)
 | |
| 		ts->id->version = data[2] + 6;
 | |
| 	else
 | |
| 		ts->id->version = data[2];
 | |
| 	ts->id->build = data[3];
 | |
| 	ts->id->matrix_x_size = data[4];
 | |
| 	ts->id->matrix_y_size = data[5];
 | |
| 	ts->id->num_declared_objects = data[6];
 | |
| 
 | |
| 	printk(KERN_INFO "info block: 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X\n",
 | |
| 		ts->id->family_id, ts->id->variant_id,
 | |
| 		ts->id->version, ts->id->build,
 | |
| 		ts->id->matrix_x_size, ts->id->matrix_y_size,
 | |
| 		ts->id->num_declared_objects);
 | |
| 
 | |
| 	/* Read object table. */
 | |
| 	ts->object_table = kzalloc(sizeof(struct object_t)*ts->id->num_declared_objects, GFP_KERNEL);
 | |
| 	if (ts->object_table == NULL) {
 | |
| 		printk(KERN_ERR"%s: allocate object_table failed\n", __func__);
 | |
| 		goto err_alloc_failed;
 | |
| 	}
 | |
| 	for (i = 0; i < ts->id->num_declared_objects; i++) {
 | |
| 		ret = i2c_atmel_read(client, i * 6 + 0x07, data, 6);
 | |
| 		ts->object_table[i].object_type = data[0];
 | |
| 		ts->object_table[i].i2c_address = data[1] | data[2] << 8;
 | |
| 		ts->object_table[i].size = data[3] + 1;
 | |
| 		ts->object_table[i].instances = data[4];
 | |
| 		ts->object_table[i].num_report_ids = data[5];
 | |
| 		if (data[5]) {
 | |
| 			ts->object_table[i].report_ids = type_count + 1;
 | |
| 			type_count += data[5];
 | |
| 		}
 | |
| 		if (data[0] == 9)
 | |
| 			ts->finger_type = ts->object_table[i].report_ids;
 | |
| 		printk(KERN_INFO "Type: %2.2X, Start: %4.4X, Size: %2X, Instance: %2X, RD#: %2X, %2X\n",
 | |
| 			ts->object_table[i].object_type , ts->object_table[i].i2c_address,
 | |
| 			ts->object_table[i].size, ts->object_table[i].instances,
 | |
| 			ts->object_table[i].num_report_ids, ts->object_table[i].report_ids);
 | |
| 	}
 | |
| 
 | |
| 	if (pdata) {
 | |
| 		while (pdata->version > ts->id->version)
 | |
| 			pdata++;
 | |
| 		if (pdata->source) {
 | |
| 			i2c_atmel_write_byte_data(client,
 | |
| 				get_object_address(ts, SPT_GPIOPWM_T19), 0x7);
 | |
| 			for (loop_i = 0; loop_i < 10; loop_i++) {
 | |
| 				if (!gpio_get_value(intr))
 | |
| 					break;
 | |
| 				msleep(10);
 | |
| 			}
 | |
| 			if (loop_i == 10)
 | |
| 				printk(KERN_ERR "No Messages when check source\n");
 | |
| 			for (loop_i = 0; loop_i < 10; loop_i++) {
 | |
| 				i2c_atmel_read(ts->client, get_object_address(ts,
 | |
| 					GEN_MESSAGEPROCESSOR_T5), data, 2);
 | |
| 				if (data[0] == get_report_ids_size(ts, SPT_GPIOPWM_T19)) {
 | |
| 					while ((data[1] >> 3) != pdata->source)
 | |
| 						pdata++;
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		ts->finger_support = pdata->config_T9[14];
 | |
| 		printk(KERN_INFO"finger_type: %d, max finger: %d\n", ts->finger_type, ts->finger_support);
 | |
| 
 | |
| 		/* infoamtion block CRC check */
 | |
| 		if (pdata->object_crc[0]) {
 | |
| 			ret = i2c_atmel_write_byte_data(client,
 | |
| 				get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + 2, 0x55);
 | |
| 			for (loop_i = 0; loop_i < 10; loop_i++) {
 | |
| 				if (!gpio_get_value(intr)) {
 | |
| 					ret = i2c_atmel_read(ts->client, get_object_address(ts,
 | |
| 						GEN_MESSAGEPROCESSOR_T5), data, 5);
 | |
| 					if (data[0] == get_report_ids_size(ts, GEN_COMMANDPROCESSOR_T6))
 | |
| 						break;
 | |
| 				}
 | |
| 				msleep(10);
 | |
| 			}
 | |
| 			if (loop_i == 10)
 | |
| 				printk(KERN_INFO "Touch: No checksum read\n");
 | |
| 			else {
 | |
| 				for (loop_i = 0; loop_i < 3; loop_i++) {
 | |
| 					if (pdata->object_crc[loop_i] != data[loop_i + 2]) {
 | |
| 						printk(KERN_ERR"CRC Error: %x, %x\n", pdata->object_crc[loop_i], data[loop_i + 2]);
 | |
| 						break;
 | |
| 					}
 | |
| 				}
 | |
| 				if (loop_i == 3) {
 | |
| 					printk(KERN_INFO "CRC passed: ");
 | |
| 					for (loop_i = 0; loop_i < 3; loop_i++)
 | |
| 						printk("0x%2.2X ", pdata->object_crc[loop_i]);
 | |
| 					printk("\n");
 | |
| 					CRC_check = 1;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		ts->abs_x_min = pdata->abs_x_min;
 | |
| 		ts->abs_x_max = pdata->abs_x_max;
 | |
| 		ts->abs_y_min = pdata->abs_y_min;
 | |
| 		ts->abs_y_max = pdata->abs_y_max;
 | |
| 		ts->abs_pressure_min = pdata->abs_pressure_min;
 | |
| 		ts->abs_pressure_max = pdata->abs_pressure_max;
 | |
| 		ts->abs_width_min = pdata->abs_width_min;
 | |
| 		ts->abs_width_max = pdata->abs_width_max;
 | |
| 		ts->GCAF_level = pdata->GCAF_level;
 | |
| 		printk(KERN_INFO "GCAF_level: %d, %d, %d, %d, %d\n",
 | |
| 			ts->GCAF_level[0], ts->GCAF_level[1], ts->GCAF_level[2],
 | |
| 			ts->GCAF_level[3], ts->GCAF_level[4]);
 | |
| 		ts->filter_level = pdata->filter_level;
 | |
| 		printk(KERN_INFO "filter_level: %d, %d, %d, %d\n",
 | |
| 			ts->filter_level[0], ts->filter_level[1], ts->filter_level[2], ts->filter_level[3]);
 | |
| 
 | |
| 		ts->config_setting[0].config_T7
 | |
| 			= ts->config_setting[1].config_T7
 | |
| 			= pdata->config_T7;
 | |
| 		ts->config_setting[0].config_T8
 | |
| 			= ts->config_setting[1].config_T8
 | |
| 			= pdata->config_T8;
 | |
| 		ts->config_setting[0].config_T9 = pdata->config_T9;
 | |
| 		ts->config_setting[0].config_T22 = pdata->config_T22;
 | |
| 		ts->config_setting[0].config_T28 = pdata->config_T28;
 | |
| 
 | |
| 		if (pdata->cable_config[0]) {
 | |
| 			ts->config_setting[0].config[0] = pdata->config_T9[7];
 | |
| 			ts->config_setting[0].config[1] = pdata->config_T22[8];
 | |
| 			ts->config_setting[0].config[2] = pdata->config_T28[3];
 | |
| 			ts->config_setting[0].config[3] = pdata->config_T28[4];
 | |
| 			for (loop_i = 0; loop_i < 4; loop_i++)
 | |
| 				ts->config_setting[1].config[loop_i] = pdata->cable_config[loop_i];
 | |
| 			ts->GCAF_sample = ts->config_setting[1].config[3];
 | |
| 			ts->noisethr = pdata->cable_config[1];
 | |
| 		} else {
 | |
| 			if (pdata->cable_config_T7[0])
 | |
| 				ts->config_setting[1].config_T7 = pdata->cable_config_T7;
 | |
| 			if (pdata->cable_config_T8[0])
 | |
| 				ts->config_setting[1].config_T8 = pdata->cable_config_T8;
 | |
| 			if (pdata->cable_config_T9[0]) {
 | |
| 				ts->config_setting[1].config_T9 = pdata->cable_config_T9;
 | |
| 				ts->config_setting[1].config_T22 = pdata->cable_config_T22;
 | |
| 				ts->config_setting[1].config_T28 = pdata->cable_config_T28;
 | |
| 				ts->GCAF_sample = ts->config_setting[ts->status].config_T28[4];
 | |
| 			}
 | |
| 		}
 | |
| 		if (usb_get_connect_type())
 | |
| 			ts->status = 1;
 | |
| 
 | |
| 		if (!CRC_check) {
 | |
| 			printk(KERN_INFO "Touch: Config reload\n");
 | |
| 
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, SPT_CTECONFIG_T28),
 | |
| 				pdata->config_T28, get_object_size(ts, SPT_CTECONFIG_T28));
 | |
| 
 | |
| 			ret = i2c_atmel_write_byte_data(client, get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + 1, 0x55);
 | |
| 			msleep(10);
 | |
| 
 | |
| 			ret = i2c_atmel_write_byte_data(client, get_object_address(ts, GEN_COMMANDPROCESSOR_T6), 0x11);
 | |
| 			msleep(64);
 | |
| 
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, GEN_COMMANDPROCESSOR_T6),
 | |
| 				pdata->config_T6, get_object_size(ts, GEN_COMMANDPROCESSOR_T6));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, GEN_POWERCONFIG_T7),
 | |
| 				pdata->config_T7, get_object_size(ts, GEN_POWERCONFIG_T7));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, GEN_ACQUISITIONCONFIG_T8),
 | |
| 				pdata->config_T8, get_object_size(ts, GEN_ACQUISITIONCONFIG_T8));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, TOUCH_MULTITOUCHSCREEN_T9),
 | |
| 				pdata->config_T9, get_object_size(ts, TOUCH_MULTITOUCHSCREEN_T9));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, TOUCH_KEYARRAY_T15),
 | |
| 				pdata->config_T15, get_object_size(ts, TOUCH_KEYARRAY_T15));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, SPT_GPIOPWM_T19),
 | |
| 				pdata->config_T19, get_object_size(ts, SPT_GPIOPWM_T19));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, PROCI_GRIPFACESUPPRESSION_T20),
 | |
| 				pdata->config_T20, get_object_size(ts, PROCI_GRIPFACESUPPRESSION_T20));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, PROCG_NOISESUPPRESSION_T22),
 | |
| 				pdata->config_T22, get_object_size(ts, PROCG_NOISESUPPRESSION_T22));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, TOUCH_PROXIMITY_T23),
 | |
| 				pdata->config_T23, get_object_size(ts, TOUCH_PROXIMITY_T23));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, PROCI_ONETOUCHGESTUREPROCESSOR_T24),
 | |
| 				pdata->config_T24, get_object_size(ts, PROCI_ONETOUCHGESTUREPROCESSOR_T24));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, SPT_SELFTEST_T25),
 | |
| 				pdata->config_T25, get_object_size(ts, SPT_SELFTEST_T25));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, PROCI_TWOTOUCHGESTUREPROCESSOR_T27),
 | |
| 				pdata->config_T27, get_object_size(ts, PROCI_TWOTOUCHGESTUREPROCESSOR_T27));
 | |
| 			i2c_atmel_write(ts->client, get_object_address(ts, SPT_CTECONFIG_T28),
 | |
| 				pdata->config_T28, get_object_size(ts, SPT_CTECONFIG_T28));
 | |
| 
 | |
| 			ret = i2c_atmel_write_byte_data(client, get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + 1, 0x55);
 | |
| 
 | |
| 			for (loop_i = 0; loop_i < 10; loop_i++) {
 | |
| 				if (!gpio_get_value(intr))
 | |
| 					break;
 | |
| 				printk(KERN_INFO "Touch: wait for Message(%d)\n", loop_i + 1);
 | |
| 				msleep(10);
 | |
| 			}
 | |
| 
 | |
| 			i2c_atmel_read(client, get_object_address(ts, GEN_MESSAGEPROCESSOR_T5), data, 7);
 | |
| 			printk(KERN_INFO "Touch: 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X\n",
 | |
| 				data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
 | |
| 
 | |
| 			ret = i2c_atmel_write_byte_data(client, get_object_address(ts, GEN_COMMANDPROCESSOR_T6), 0x11);
 | |
| 			msleep(64);
 | |
| 
 | |
| 			i2c_atmel_read(client, get_object_address(ts, GEN_MESSAGEPROCESSOR_T5), data, 7);
 | |
| 			printk(KERN_INFO "Touch: 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X\n",
 | |
| 				data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
 | |
| 			/* For Ace */
 | |
| 		}
 | |
| 
 | |
| 		if (ts->status) {
 | |
| 			printk(KERN_INFO "Touch: set cable config\n");
 | |
| 			if (ts->config_setting[1].config[0]) {
 | |
| 				i2c_atmel_write_byte_data(ts->client,
 | |
| 					get_object_address(ts, TOUCH_MULTITOUCHSCREEN_T9) + 7,
 | |
| 					ts->config_setting[1].config[0]);
 | |
| 				i2c_atmel_write_byte_data(ts->client,
 | |
| 					get_object_address(ts, SPT_CTECONFIG_T28) + 3,
 | |
| 					ts->config_setting[1].config[2]);
 | |
| 				i2c_atmel_write_byte_data(ts->client,
 | |
| 					get_object_address(ts, SPT_CTECONFIG_T28) + 4,
 | |
| 					ts->config_setting[1].config[3]);
 | |
| 			} else {
 | |
| 				if (ts->config_setting[1].config_T7 != NULL)
 | |
| 					i2c_atmel_write(ts->client,
 | |
| 						get_object_address(ts, GEN_POWERCONFIG_T7),
 | |
| 						ts->config_setting[1].config_T7,
 | |
| 						get_object_size(ts, GEN_POWERCONFIG_T7));
 | |
| 				if (ts->config_setting[1].config_T8 != NULL)
 | |
| 					i2c_atmel_write(ts->client,
 | |
| 						get_object_address(ts, GEN_ACQUISITIONCONFIG_T8),
 | |
| 						ts->config_setting[1].config_T8,
 | |
| 						get_object_size(ts, GEN_ACQUISITIONCONFIG_T8));
 | |
| 				if (ts->config_setting[1].config_T9 != NULL)
 | |
| 					i2c_atmel_write(ts->client,
 | |
| 						get_object_address(ts, TOUCH_MULTITOUCHSCREEN_T9),
 | |
| 						ts->config_setting[1].config_T9,
 | |
| 						get_object_size(ts, TOUCH_MULTITOUCHSCREEN_T9));
 | |
| 				if (ts->config_setting[1].config_T22 != NULL)
 | |
| 					i2c_atmel_write(ts->client,
 | |
| 						get_object_address(ts, PROCG_NOISESUPPRESSION_T22),
 | |
| 						ts->config_setting[1].config_T22,
 | |
| 						get_object_size(ts, PROCG_NOISESUPPRESSION_T22));
 | |
| 				if (ts->config_setting[1].config_T28 != NULL) {
 | |
| 					i2c_atmel_write(ts->client,
 | |
| 						get_object_address(ts, SPT_CTECONFIG_T28),
 | |
| 						ts->config_setting[1].config_T28,
 | |
| 						get_object_size(ts, SPT_CTECONFIG_T28));
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	ts->input_dev = input_allocate_device();
 | |
| 	if (ts->input_dev == NULL) {
 | |
| 		ret = -ENOMEM;
 | |
| 		dev_err(&client->dev, "Failed to allocate input device\n");
 | |
| 		goto err_input_dev_alloc_failed;
 | |
| 	}
 | |
| 	ts->input_dev->name = "atmel-touchscreen";
 | |
| 	set_bit(EV_SYN, ts->input_dev->evbit);
 | |
| 	set_bit(EV_KEY, ts->input_dev->evbit);
 | |
| 	set_bit(BTN_TOUCH, ts->input_dev->keybit);
 | |
| 	set_bit(BTN_2, ts->input_dev->keybit);
 | |
| 	set_bit(EV_ABS, ts->input_dev->evbit);
 | |
| 
 | |
| 	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
 | |
| 				ts->abs_x_min, ts->abs_x_max, 0, 0);
 | |
| 	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
 | |
| 				ts->abs_y_min, ts->abs_y_max, 0, 0);
 | |
| 	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
 | |
| 				ts->abs_pressure_min, ts->abs_pressure_max,
 | |
| 				0, 0);
 | |
| 	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,
 | |
| 				ts->abs_width_min, ts->abs_width_max, 0, 0);
 | |
| #ifndef CONFIG_TOUCHSCREEN_COMPATIBLE_REPORT
 | |
| 	input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE,
 | |
| 		0, ((ts->abs_pressure_max << 16) | ts->abs_width_max), 0, 0);
 | |
| 	input_set_abs_params(ts->input_dev, ABS_MT_POSITION,
 | |
| 		0, ((1 << 31) | (ts->abs_x_max << 16) | ts->abs_y_max), 0, 0);
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 	ret = input_register_device(ts->input_dev);
 | |
| 	if (ret) {
 | |
| 		dev_err(&client->dev,
 | |
| 			"atmel_ts_probe: Unable to register %s input device\n",
 | |
| 			ts->input_dev->name);
 | |
| 		goto err_input_register_device_failed;
 | |
| 	}
 | |
| 
 | |
| 	ret = request_irq(client->irq, atmel_ts_irq_handler, IRQF_TRIGGER_LOW,
 | |
| 			client->name, ts);
 | |
| 	if (ret)
 | |
| 		dev_err(&client->dev, "request_irq failed\n");
 | |
| 
 | |
| #ifdef CONFIG_HAS_EARLYSUSPEND
 | |
| 	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING - 1;
 | |
| 	ts->early_suspend.suspend = atmel_ts_early_suspend;
 | |
| 	ts->early_suspend.resume = atmel_ts_late_resume;
 | |
| 	register_early_suspend(&ts->early_suspend);
 | |
| #endif
 | |
| 
 | |
| 	private_ts = ts;
 | |
| #ifdef ATMEL_EN_SYSFS
 | |
| 	atmel_touch_sysfs_init();
 | |
| #endif
 | |
| 
 | |
| 	dev_info(&client->dev, "Start touchscreen %s in interrupt mode\n",
 | |
| 			ts->input_dev->name);
 | |
| 
 | |
| 	usb_register_notifier(&cable_status_handler);
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| err_input_register_device_failed:
 | |
| 	input_free_device(ts->input_dev);
 | |
| 
 | |
| err_input_dev_alloc_failed:
 | |
| err_alloc_failed:
 | |
| err_detect_failed:
 | |
| err_power_failed:
 | |
| 	destroy_workqueue(ts->atmel_wq);
 | |
| 
 | |
| err_cread_wq_failed:
 | |
| 	kfree(ts);
 | |
| 
 | |
| err_alloc_data_failed:
 | |
| err_check_functionality_failed:
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static int atmel_ts_remove(struct i2c_client *client)
 | |
| {
 | |
| 	struct atmel_ts_data *ts = i2c_get_clientdata(client);
 | |
| 
 | |
| #ifdef ATMEL_EN_SYSFS
 | |
| 	atmel_touch_sysfs_deinit();
 | |
| #endif
 | |
| 
 | |
| 	unregister_early_suspend(&ts->early_suspend);
 | |
| 	free_irq(client->irq, ts);
 | |
| 
 | |
| 	destroy_workqueue(ts->atmel_wq);
 | |
| 	input_unregister_device(ts->input_dev);
 | |
| 	kfree(ts);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int atmel_ts_suspend(struct i2c_client *client, pm_message_t mesg)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct atmel_ts_data *ts = i2c_get_clientdata(client);
 | |
| 
 | |
| 	printk(KERN_INFO "%s: enter\n", __func__);
 | |
| 
 | |
| 	disable_irq(client->irq);
 | |
| 
 | |
| 	ret = cancel_work_sync(&ts->work);
 | |
| 	if (ret)
 | |
| 		enable_irq(client->irq);
 | |
| 
 | |
| 	ts->finger_pressed = 0;
 | |
| 	ts->finger_count = 0;
 | |
| 	ts->first_pressed = 0;
 | |
| 
 | |
| 	i2c_atmel_write_byte_data(client,
 | |
| 		get_object_address(ts, GEN_POWERCONFIG_T7), 0x0);
 | |
| 	i2c_atmel_write_byte_data(client,
 | |
| 		get_object_address(ts, GEN_POWERCONFIG_T7) + 1, 0x0);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int atmel_ts_resume(struct i2c_client *client)
 | |
| {
 | |
| 	struct atmel_ts_data *ts = i2c_get_clientdata(client);
 | |
| 
 | |
| 	i2c_atmel_write(ts->client, get_object_address(ts, GEN_POWERCONFIG_T7),
 | |
| 		ts->config_setting[ts->status].config_T7, get_object_size(ts, GEN_POWERCONFIG_T7));
 | |
| 	if (ts->config_setting[1].config[0] && ts->status && !check_delta(ts)) {
 | |
| 		ts->calibration_confirm = 2;
 | |
| 		i2c_atmel_write_byte_data(ts->client,
 | |
| 			get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + 6,
 | |
| 			ts->config_setting[ts->status].config_T8[6]);
 | |
| 		i2c_atmel_write_byte_data(ts->client,
 | |
| 			get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + 7,
 | |
| 			ts->config_setting[ts->status].config_T8[7]);
 | |
| 	} else {
 | |
| 		ts->calibration_confirm = 0;
 | |
| 		i2c_atmel_write_byte_data(client,
 | |
| 			get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + 2, 0x55);
 | |
| 		i2c_atmel_write_byte_data(client,
 | |
| 			get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + 6, 0x0);
 | |
| 		i2c_atmel_write_byte_data(client,
 | |
| 			get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + 7, 0x0);
 | |
| 	}
 | |
| 	enable_irq(client->irq);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_HAS_EARLYSUSPEND
 | |
| static void atmel_ts_early_suspend(struct early_suspend *h)
 | |
| {
 | |
| 	struct atmel_ts_data *ts;
 | |
| 	ts = container_of(h, struct atmel_ts_data, early_suspend);
 | |
| 	atmel_ts_suspend(ts->client, PMSG_SUSPEND);
 | |
| }
 | |
| 
 | |
| static void atmel_ts_late_resume(struct early_suspend *h)
 | |
| {
 | |
| 	struct atmel_ts_data *ts;
 | |
| 	ts = container_of(h, struct atmel_ts_data, early_suspend);
 | |
| 	atmel_ts_resume(ts->client);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static const struct i2c_device_id atml_ts_i2c_id[] = {
 | |
| 	{ ATMEL_QT602240_NAME, 0 },
 | |
| 	{ }
 | |
| };
 | |
| 
 | |
| static struct i2c_driver atmel_ts_driver = {
 | |
| 	.id_table = atml_ts_i2c_id,
 | |
| 	.probe = atmel_ts_probe,
 | |
| 	.remove = atmel_ts_remove,
 | |
| #ifndef CONFIG_HAS_EARLYSUSPEND
 | |
| 	.suspend = atmel_ts_suspend,
 | |
| 	.resume = atmel_ts_resume,
 | |
| #endif
 | |
| 	.driver = {
 | |
| 			.name = ATMEL_QT602240_NAME,
 | |
| 	},
 | |
| };
 | |
| 
 | |
| static int __devinit atmel_ts_init(void)
 | |
| {
 | |
| 	printk(KERN_INFO "atmel_ts_init():\n");
 | |
| 	return i2c_add_driver(&atmel_ts_driver);
 | |
| }
 | |
| 
 | |
| static void __exit atmel_ts_exit(void)
 | |
| {
 | |
| 	i2c_del_driver(&atmel_ts_driver);
 | |
| }
 | |
| 
 | |
| module_init(atmel_ts_init);
 | |
| module_exit(atmel_ts_exit);
 | |
| 
 | |
| MODULE_DESCRIPTION("ATMEL Touch driver");
 | |
| MODULE_LICENSE("GPL");
 | |
| 
 |