diff options
author | Zhangfei Gao <zhangfei.gao@linaro.org> | 2013-08-08 14:18:43 +0800 |
---|---|---|
committer | Andrey Konovalov <andrey.konovalov@linaro.org> | 2015-06-19 13:12:35 +0300 |
commit | 9c84d2b89e9227db7d4319712815dc9facd68d74 (patch) | |
tree | 2e72f3739e07659e3f273fb8ea3a5e1974ccf988 | |
parent | 4c389d3bbe29721d7b4336ca77fcd0948944f862 (diff) |
Input: enable touch atmel_mXT224E
touchscreen:
Device Drivers --->
Input device support --->
[*] Touchscreens --->
[*] Atmel mXT224E based touchscreens
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 11 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/atmel_mXT224E.c | 1473 |
3 files changed, 1485 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 80f6386709b..128358f47a3 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1027,4 +1027,15 @@ config TOUCHSCREEN_ZFORCE To compile this driver as a module, choose M here: the module will be called zforce_ts. +config TOUCHSCREEN_MXT224E + tristate "Atmel mXT224E based touchscreens" + depends on I2C + help + Say Y here if you have a TPS6507x based touchscreen + controller. + + If unsure, say N. + + module will be called atmel_mXT224E. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 44deea743d0..3a1ace3587c 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -84,3 +84,4 @@ obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o +obj-$(CONFIG_TOUCHSCREEN_MXT224E) += atmel_mXT224E.o diff --git a/drivers/input/touchscreen/atmel_mXT224E.c b/drivers/input/touchscreen/atmel_mXT224E.c new file mode 100644 index 00000000000..99bcfde16e7 --- /dev/null +++ b/drivers/input/touchscreen/atmel_mXT224E.c @@ -0,0 +1,1473 @@ +/* drivers/input/touchscreen/atmel_mXT224E.c - ATMEL Touch driver + * + * Copyright (C) 2008 ATMEL + * Copyright (C) 2011 Huawei Corporation. + * + * Based on touchscreen code from Atmel 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/platform_device.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/jiffies.h> +#include <linux/stat.h> +#include <linux/slab.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/bitops.h> +#include <linux/of_gpio.h> +#include <linux/pinctrl/consumer.h> + +#include <linux/kthread.h> + +#ifdef TS_ATMEL_DEBUG +#define TS_DEBUG_ATMEL(fmt, args...) pr_info(fmt, ##args) +#else +#define TS_DEBUG_ATMEL(fmt, args...) +#endif + +#define ATMEL_MXT224E_NAME "atmel_mxt224e" + +#define INFO_BLK_FID 0 +#define INFO_BLK_VID 1 +#define INFO_BLK_VER 2 +#define INFO_BLK_BUILD 3 +#define INFO_BLK_XSIZE 4 +#define INFO_BLK_YSIZE 5 +#define INFO_BLK_OBJS 6 + +#define OBJ_TABLE_TYPE 0 +#define OBJ_TABLE_LSB 1 +#define OBJ_TABLE_MSB 2 +#define OBJ_TABLE_SIZE 3 +#define OBJ_TABLE_INSTANCES 4 +#define OBJ_TABLE_RIDS 5 + +#define RESERVED_T0 0u +#define RESERVED_T1 1u +#define DEBUG_DELTAS_T2 2u +#define DEBUG_REFERENCES_T3 3u +#define DEBUG_SIGNALS_T4 4u +#define GEN_MESSAGEPROCESSOR_T5 5u +#define GEN_COMMANDPROCESSOR_T6 6u +#define GEN_POWERCONFIG_T7 7u +#define GEN_ACQUISITIONCONFIG_T8 8u +#define TOUCH_MULTITOUCHSCREEN_T9 9u +#define TOUCH_SINGLETOUCHSCREEN_T10 10u +#define TOUCH_XSLIDER_T11 11u +#define TOUCH_YSLIDER_T12 12u +#define TOUCH_XWHEEL_T13 13u +#define TOUCH_YWHEEL_T14 14u +#define TOUCH_KEYARRAY_T15 15u +#define PROCG_SIGNALFILTER_T16 16u +#define PROCI_LINEARIZATIONTABLE_T17 17u +#define SPT_COMCONFIG_T18 18u +#define SPT_GPIOPWM_T19 19u +#define PROCI_GRIPFACESUPPRESSION_T20 20u +#define RESERVED_T21 21u +#define PROCG_NOISESUPPRESSION_T22 22u +#define TOUCH_PROXIMITY_T23 23u +#define PROCI_ONETOUCHGESTUREPROCESSOR_T24 24u +#define SPT_SELFTEST_T25 25u +#define DEBUG_CTERANGE_T26 26u +#define PROCI_TWOTOUCHGESTUREPROCESSOR_T27 27u +#define SPT_CTECONFIG_T28 28u +#define SPT_GPI_T29 29u +#define SPT_GATE_T30 30u +#define TOUCH_KEYSET_T31 31u +#define TOUCH_XSLIDERSET_T32 32u +#define DIAGNOSTIC_T37 37u +#define PROCI_GRIPSUPPRESSION_T40 40u +#define PROCI_TOUCHSUPPRESSION_T42 42u +#define SPT_CTECONFIG_T46 46u +#define PROCI_STYLUS_T47 47u +#define PROCG_NOISESUPPRESSION_T48 48u + +#define T37_PAGE_SIZE 128 + +#define T37_TCH_FLAG_SIZE 80 +#define T37_TCH_FLAG_IDX 0 +#define T37_ATCH_FLAG_IDX 40 + +#define T37_MODE 0 +#define T37_PAGE 1 +#define T37_DATA 2 /* n bytes */ + +#define T37_PAGE_NUM0 0 +#define T37_PAGE_NUM1 1 +#define T37_PAGE_NUM2 2 +#define T37_PAGE_NUM3 3 + +#define MSG_RID 0 + +#define T6_CFG_RESET 0 +#define T6_CFG_BACKUPNV 1 +#define T6_CFG_CALIBRATE 2 +#define T6_CFG_REPORTALL 3 +/* Reserved */ +#define T6_CFG_DIAG 5 + +#define T6_CFG_DIAG_CMD_PAGEUP 0x01 +#define T6_CFG_DIAG_CMD_PAGEDOWN 0x02 +#define T6_CFG_DIAG_CMD_DELTAS 0x10 +#define T6_CFG_DIAG_CMD_REF 0x11 +#define T6_CFG_DIAG_CMD_CTE 0x31 +#define T6_CFG_DIAG_CMD_TCH 0xF3 + +#define T6_MSG_STATUS 1 +#define T6_MSG_CHECKSUM 2 /* three bytes */ + +#define T6_MSG_STATUS_COMSERR BIT(2) +#define T6_MSG_STATUS_CFGERR BIT(3) +#define T6_MSG_STATUS_CAL BIT(4) +#define T6_MSG_STATUS_SIGERR BIT(5) +#define T6_MSG_STATUS_OFL BIT(6) +#define T6_MSG_STATUS_RESET BIT(7) + +#define T7_CFG_IDLEACQINT 0 +#define T7_CFG_ACTVACQINT 1 +#define T7_CFG_ACTV2IDLETO 2 + +#define T8_CFG_CHRGTIME 0 +/* Reserved */ +#define T8_CFG_TCHDRIFT 2 +#define T8_CFG_DRIFTST 3 +#define T8_CFG_TCHAUTOCAL 4 +#define T8_CFG_SYNC 5 +#define T8_CFG_ATCHCALST 6 +#define T8_CFG_ATCHCALSTHR 7 +#define T8_CFG_ATCHFRCCALTHR 8 /* FW v2.x */ +#define T8_CFG_ATCHFRCCALRATIO 9 /* FW v2.x */ + +#define T9_CFG_CTRL 0 +#define T9_CFG_XORIGIN 1 +#define T9_CFG_YORIGIN 2 +#define T9_CFG_XSIZE 3 +#define T9_CFG_YSIZE 4 +#define T9_CFG_AKSCFG 5 +#define T9_CFG_BLEN 6 +#define T9_CFG_TCHTHR 7 +#define T9_CFG_TCHDI 8 +#define T9_CFG_ORIENT 9 +#define T9_CFG_MRGTIMEOUT 10 +#define T9_CFG_MOVHYSTI 11 +#define T9_CFG_MOVHYSTN 12 +#define T9_CFG_MOVFILTER 13 +#define T9_CFG_NUMTOUCH 14 +#define T9_CFG_MRGHYST 15 +#define T9_CFG_MRGTHR 16 +#define T9_CFG_AMPHYST 17 +#define T9_CFG_XRANGE 18 /* two bytes */ +#define T9_CFG_YRANGE 20 /* two bytes */ +#define T9_CFG_XLOCLIP 22 +#define T9_CFG_XHICLIP 23 +#define T9_CFG_YLOCLIP 24 +#define T9_CFG_YHICLIP 25 +#define T9_CFG_XEDGECTRL 26 +#define T9_CFG_XEDGEDIST 27 +#define T9_CFG_YEDGECTRL 28 +#define T9_CFG_YEDGEDIST 29 +#define T9_CFG_JUMPLIMIT 30 +#define T9_CFG_TCHHYST 31 /* FW v2.x */ + +#define T9_MSG_STATUS 1 +#define T9_MSG_XPOSMSB 2 +#define T9_MSG_YPOSMSB 3 +#define T9_MSG_XYPOSLSB 4 +#define T9_MSG_TCHAREA 5 +#define T9_MSG_TCHAMPLITUDE 6 +#define T9_MSG_TCHVECTOR 7 + +#define T9_MSG_STATUS_UNGRIP BIT(0) /* FW v2.x */ +#define T9_MSG_STATUS_SUPPRESS BIT(1) +#define T9_MSG_STATUS_AMP BIT(2) +#define T9_MSG_STATUS_VECTOR BIT(3) +#define T9_MSG_STATUS_MOVE BIT(4) +#define T9_MSG_STATUS_RELEASE BIT(5) +#define T9_MSG_STATUS_PRESS BIT(6) +#define T9_MSG_STATUS_DETECT BIT(7) + +#define T20_CFG_CTRL 0 +#define T20_CFG_XLOGRIP 1 +#define T20_CFG_XHIGRIP 2 +#define T20_CFG_YLOGRIP 3 +#define T20_CFG_YHIGRIP 4 +#define T20_CFG_MAXTCHS 5 +/* Reserved */ +#define T20_CFG_SZTHR1 7 +#define T20_CFG_SZTHR2 8 +#define T20_CFG_SHPTHR1 9 +#define T20_CFG_SHPTHR2 10 +#define T20_CFG_SHPEXTTO 11 + +#define T20_MSG_STATUS 1 + +#define T20_MSG_STATUS_FACESUP BIT(0) + +#define T22_CFG_CTRL 0 +/* Reserved */ +#define T22_CFG_GCAFUL 3 /* two bytes */ +#define T22_CFG_GCAFLL 5 /* two bytes */ +#define T22_CFG_ACTVGCAFVALID 7 +#define T22_CFG_NOISETHR 8 +/* Reserved */ +#define T22_CFG_FREQHOPSCALE 10 +#define T22_CFG_FREQ 11 /* five bytes */ +#define T22_CFG_IDLEGCAFVAILD 16 + +#define T22_MSG_STATUS 1 +#define T22_MSG_GCAFDEPTH 2 +#define T22_MSG_FREQINDEX 3 + +#define T22_MSG_STATUS_FHCHG BIT(0) +#define T22_MSG_STATUS_GCAFERR BIT(2) +#define T22_MSG_STATUS_FHERR BIT(3) +#define T22_MSG_STATUS_GCAFCHG BIT(4) + +#define T19_CFG_CTRL 0 +#define T19_CFG_REPORTMASK 1 +#define T19_CFG_DIR 2 +#define T19_CFG_INTPULLUP 3 +#define T19_CFG_OUT 4 +#define T19_CFG_WAKE 5 +#define T19_CFG_PWM 6 +#define T19_CFG_PERIOD 7 +#define T19_CFG_DUTY0 8 +#define T19_CFG_DUTY1 9 +#define T19_CFG_DUTY2 10 +#define T19_CFG_DUTY3 11 +#define T19_CFG_TRIGGER0 12 +#define T19_CFG_TRIGGER1 13 +#define T19_CFG_TRIGGER2 14 +#define T19_CFG_TRIGGER3 15 + +#define T19_CFG_CTRL_ENABLE BIT(0) +#define T19_CFG_CTRL_RPTEN BIT(1) +#define T19_CFG_CTRL_FORCERPT BIT(2) + +#define T19_MSG_STATUS 1 + +#define T25_CFG_CTRL 0 +#define T25_CFG_CMD 1 + +#define T25_MSG_STATUS 1 +#define T25_MSG_INFO 2 /* five bytes */ + +#define T28_CFG_CTRL 0 +#define T28_CFG_CMD 1 +#define T28_CFG_MODE 2 +#define T28_CFG_IDLEGCAFDEPTH 3 +#define T28_CFG_ACTVGCAFDEPTH 4 +#define T28_CFG_VOLTAGE 5 + +#define T28_CFG_MODE0_X 16 +#define T28_CFG_MODE0_Y 14 + +#define T28_MSG_STATUS 1 + +#define T48_NOISESUPPRESSION_CFG 1 + +/* cable_config[] of atmel_i2c_platform_data */ +/* config[] of atmel_config_data */ +#define CB_TCHTHR 0 +#define CB_NOISETHR 1 +#define CB_IDLEGCAFDEPTH 2 +#define CB_ACTVGCAFDEPTH 3 + +#define NC_TCHTHR 0 +#define NC_TCHDI 1 +#define NC_NOISETHR 2 + +/* filter_level */ +#define FL_XLOGRIPMIN 0 +#define FL_XLOGRIPMAX 1 +#define FL_XHIGRIPMIN 2 +#define FL_XHIGRIPMAX 3 + +struct info_id_t { + uint8_t family_id; + uint8_t variant_id; + uint8_t version; + uint8_t build; + uint8_t matrix_x_size; + uint8_t matrix_y_size; + uint8_t num_declared_objects; +}; + +struct object_t { + uint8_t object_type; + uint16_t i2c_address; + uint8_t size; + uint8_t instances; + uint8_t num_report_ids; + uint8_t report_ids; +}; + +struct atmel_virtual_key { + int keycode; + int range_min; + int range_max; +}; + +struct atmel_finger_data { + int x; + int y; + int w; + int z; +}; + +struct atmel_i2c_platform_data { + uint16_t version; + uint16_t source; + 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 abs_area_min; + uint8_t abs_area_max; + int gpio_irq; + int gpio_reset; + int (*power)(int on); + u8 config_T6[6]; + u8 config_T7[3]; + u8 config_T8[10]; + u8 config_T9[35]; + u8 config_T15[11]; + u8 config_T19[16]; + u8 config_T20[12]; + u8 config_T22[17]; + u8 config_T23[15]; + u8 config_T24[19]; + u8 config_T25[14]; + u8 config_T27[7]; + u8 config_T28[6]; + u8 config_T40[5]; + u8 config_T42[8]; + u8 config_T46[9]; + u8 config_T47[10]; + u8 config_T48[54]; + u8 object_crc[3]; + u8 cable_config[4]; + u8 cable_config_T7[3]; + u8 cable_config_T8[10]; + u8 cable_config_T9[35]; + u8 cable_config_T22[17]; + u8 cable_config_T28[6]; + u8 cable_config_T46[9]; + u8 cable_config_T48[54]; + u8 noise_config[3]; + u16 filter_level[4]; + u8 GCAF_level[5]; + u8 ATCH_NOR[6]; + u8 ATCH_NOR_20S[6]; +}; + +struct atmel_config_data { + int8_t config[4]; + int8_t *config_T7; + int8_t *config_T8; + int8_t *config_T9; + int8_t *config_T22; + int8_t *config_T28; + int8_t *config_T46; + int8_t *config_T48; +}; + +#define ATMEL_I2C_RETRY_TIMES 10 + +/* config_setting */ +#define NONE 0 +#define CONNECTED 1 +struct atmel_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; + struct atmel_i2c_platform_data *pdata; + struct workqueue_struct *atmel_wq; + struct work_struct work; + int (*power) (int on); + struct info_id_t *id; + struct object_t *object_table; + struct iomux_block *gpio_block; + struct block_config *gpio_block_config; + 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_area_min; + uint8_t abs_area_max; + uint8_t abs_width_min; + uint8_t abs_width_max; + uint8_t abs_pressure_min; + uint8_t abs_pressure_max; + uint8_t first_pressed; + 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]; + int8_t noise_config[3]; + uint8_t status; + uint8_t GCAF_sample; + uint8_t *GCAF_level; + uint8_t noisethr; + uint8_t noisethr_config; + uint8_t diag_command; + uint8_t *ATCH_EXT; + int8_t *ATCH_NOR; + int8_t *ATCH_NOR_20S; + int pre_data[11]; + /*unlock flag used to indicate calibration after unlock system*/ + int unlock_flag; + + /*For usb detect*/ + struct work_struct usb_work; + struct notifier_block nb; + unsigned long usb_event; + struct mutex lock; +}; + +static struct atmel_ts_data *private_ts; + +#define LDO_POWR_VOLTAGE 2700000 /*2.7v*/ +static struct regulator *LDO; + +static int i2c_atmel_read(struct i2c_client *client, uint16_t address, uint8_t *data, uint8_t length) +{ + int retry, ret; + 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++) { + ret = i2c_transfer(client->adapter, msg, 2); + if ((ret == 2) || (ret == -ERESTARTSYS)) + break; + mdelay(10); + } + if (retry == ATMEL_I2C_RETRY_TIMES) { + dev_err(&client->dev, "k3ts, %s: i2c_read_block retry over %d\n", __func__, + ATMEL_I2C_RETRY_TIMES); + return -EIO; + } + return 0; +} + +static int i2c_atmel_write(struct i2c_client *client, uint16_t address, uint8_t *data, uint8_t length) +{ + int retry, loop_i, ret; + 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++) { + ret = i2c_transfer(client->adapter, msg, 1); + if ((ret == 1) || (ret == -ERESTARTSYS)) + break; + mdelay(10); + } + + if (retry == ATMEL_I2C_RETRY_TIMES) { + dev_err(&client->dev, "k3ts, %s: i2c_write_block retry over %d\n", __func__, + ATMEL_I2C_RETRY_TIMES); + return -EIO; + } + return 0; + +} + +static 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; +} + +static 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; +} +static 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; +} + +static uint8_t get_object_size_from_address(struct atmel_ts_data *ts, int address) +{ + uint8_t loop_i; + for (loop_i = 0; loop_i < ts->id->num_declared_objects; loop_i++) { + if (ts->object_table[loop_i].i2c_address == address) + return ts->object_table[loop_i].size; + } + return 0; +} + +uint8_t get_rid(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; +} + +static void check_calibration(struct atmel_ts_data *ts) +{ + uint8_t data[T37_DATA + T37_TCH_FLAG_SIZE]; + 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) + + T6_CFG_DIAG, T6_CFG_DIAG_CMD_TCH); + + for (loop_i = 0; + !(data[T37_MODE] == T6_CFG_DIAG_CMD_TCH && data[T37_PAGE] == T37_PAGE_NUM0) && loop_i < 10; loop_i++) { + msleep(5); + i2c_atmel_read(ts->client, + get_object_address(ts, DIAGNOSTIC_T37), data, 2); + } + + if (loop_i == 10) + dev_err(&ts->client->dev, "k3ts, %s: Diag data not ready\n", __func__); + + i2c_atmel_read(ts->client, get_object_address(ts, DIAGNOSTIC_T37), data, + T37_DATA + T37_TCH_FLAG_SIZE); + if (data[T37_MODE] == T6_CFG_DIAG_CMD_TCH && + data[T37_PAGE] == T37_PAGE_NUM0) { + x_limit = T28_CFG_MODE0_X + ts->config_setting[NONE].config_T28[T28_CFG_MODE]; + x_limit = x_limit << 1; + if (x_limit <= 40) { + for (loop_i = 0; loop_i < x_limit; loop_i += 2) { + for (loop_j = 0; loop_j < BITS_PER_BYTE; loop_j++) { + check_mask = BIT_MASK(loop_j); + if (data[T37_DATA + T37_TCH_FLAG_IDX + loop_i] & + check_mask) + tch_ch++; + if (data[T37_DATA + T37_TCH_FLAG_IDX + loop_i + 1] & + check_mask) + tch_ch++; + if (data[T37_DATA + T37_ATCH_FLAG_IDX + loop_i] & + check_mask) + atch_ch++; + if (data[T37_DATA + T37_ATCH_FLAG_IDX + loop_i + 1] & + check_mask) + atch_ch++; + } + } + } + } + i2c_atmel_write_byte_data(ts->client, + get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + + T6_CFG_DIAG, T6_CFG_DIAG_CMD_PAGEUP); + + if (tch_ch && (atch_ch == 0)) { + if (jiffies > (ts->timestamp + HZ/2) && (ts->calibration_confirm == 1)) { + ts->calibration_confirm = 2; + } + if (ts->calibration_confirm < 2) + ts->calibration_confirm = 1; + ts->timestamp = jiffies; + } else if (atch_ch > 1 || tch_ch > 8) { + ts->calibration_confirm = 0; + i2c_atmel_write_byte_data(ts->client, + get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + + T6_CFG_CALIBRATE, 0x55); + } +} + +static void confirm_calibration(struct atmel_ts_data *ts) +{ + i2c_atmel_write(ts->client, + get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + + T8_CFG_TCHAUTOCAL, ts->ATCH_NOR_20S, 6); + ts->pre_data[0] = 2; +} + +static void msg_process_finger_data_x10y10bit(struct atmel_finger_data *fdata, uint8_t *data) +{ + fdata->x = data[T9_MSG_XPOSMSB] << 2 | data[T9_MSG_XYPOSLSB] >> 6; + fdata->y = data[T9_MSG_YPOSMSB] << 2 | (data[T9_MSG_XYPOSLSB] & 0x0C) >>2; + fdata->w = data[T9_MSG_TCHAREA]; + fdata->z = data[T9_MSG_TCHAMPLITUDE]; +} +static void msg_process_finger_data_x10y12bit(struct atmel_finger_data *fdata, uint8_t *data) +{ + fdata->x = data[T9_MSG_XPOSMSB] << 2 | data[T9_MSG_XYPOSLSB] >> 6; + fdata->y = data[T9_MSG_YPOSMSB] << 4 | (data[T9_MSG_XYPOSLSB] & 0x0F) ; + fdata->w = data[T9_MSG_TCHAREA]; + fdata->z = data[T9_MSG_TCHAMPLITUDE]; +} + +static void msg_process_multitouch(struct atmel_ts_data *ts, uint8_t *data, uint8_t idx) +{ + if (ts->calibration_confirm < 2 && ts->id->version == 0x10) + check_calibration(ts); + if(ts->abs_y_max >= 1024) { + msg_process_finger_data_x10y12bit(&ts->finger_data[idx], data); + } else { + msg_process_finger_data_x10y10bit(&ts->finger_data[idx], data); + } + if (data[T9_MSG_STATUS] & T9_MSG_STATUS_RELEASE) { + if (ts->grip_suppression & BIT(idx)) + ts->grip_suppression &= ~BIT(idx); + if (ts->finger_pressed & BIT(idx)) { + ts->finger_count--; + ts->finger_pressed &= ~BIT(idx); + if (!ts->first_pressed) { + if (!ts->finger_count) + ts->first_pressed = 1; + } + if (ts->pre_data[0] < 2 && ts->unlock_flag != 1) { + + if (ts->finger_count) { + i2c_atmel_write_byte_data(ts->client, + get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + + T6_CFG_CALIBRATE, 0x55); + } else if (!ts->finger_count && ts->pre_data[0] == 1) + ts->pre_data[0] = 0; + } + } + } else if ((data[T9_MSG_STATUS] & (T9_MSG_STATUS_DETECT | T9_MSG_STATUS_PRESS)) + && !(ts->finger_pressed & BIT(idx))) { + if (ts->id->version >= 0x10 && ts->pre_data[0] < 2) { + if (jiffies > (ts->timestamp + 20 * HZ)) { + confirm_calibration(ts); + } + } + if (!(ts->grip_suppression & BIT(idx))) { + ts->finger_count++; + ts->finger_pressed |= BIT(idx); + if (ts->id->version >= 0x10 && ts->pre_data[0] < 2) { + ts->pre_data[idx + 1] = ts->finger_data[idx].x; + ts->pre_data[idx + 2] = ts->finger_data[idx].y; + if (ts->finger_count == ts->finger_support) { + i2c_atmel_write_byte_data(ts->client, + get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + + T6_CFG_CALIBRATE, 0x55); + } else if (!ts->pre_data[0] && ts->finger_count == 1) + ts->pre_data[0] = 1; + } + } + } else if ((data[T9_MSG_STATUS] & (T9_MSG_STATUS_DETECT|T9_MSG_STATUS_PRESS)) + && ts->pre_data[0] < 2 && ts->unlock_flag != 1) { + if (ts->finger_count == 1 && ts->pre_data[0] && + (idx == 0 && ((abs(ts->finger_data[idx].y - ts->pre_data[idx + 2]) > 50) + || (abs(ts->finger_data[idx].x - ts->pre_data[idx + 1]) > 50)))) + { + ts->unlock_flag = 1; + ts->calibration_confirm = 2; + } + } + +} + +static void compatible_input_report(struct input_dev *idev, + struct atmel_finger_data *fdata, uint8_t press, uint8_t last) +{ + if (!press) { + input_mt_sync(idev); + /*input_report_key(idev, BTN_TOUCH, 0);*/ + input_report_key(idev, BTN_TOUCH, 1); + + } else { + TS_DEBUG_ATMEL("k3ts, %s: Touch report_key x = %d, y = %d, z = %d, w = %d\n ", __func__, + fdata->x, fdata->y, fdata->z, fdata->w); + input_report_abs(idev, ABS_MT_TOUCH_MAJOR, fdata->z); + input_report_abs(idev, ABS_MT_WIDTH_MAJOR, fdata->w); + input_report_abs(idev, ABS_MT_POSITION_X, fdata->x); + input_report_abs(idev, ABS_MT_POSITION_Y, fdata->y); + input_mt_sync(idev); + } +} + + + +static void multi_input_report(struct atmel_ts_data *ts) +{ + uint8_t loop_i, finger_report = 0; + + for (loop_i = 0; loop_i < ts->finger_support; loop_i++) { + if (ts->finger_pressed & BIT(loop_i)) { + compatible_input_report(ts->input_dev, &ts->finger_data[loop_i], + 1, (ts->finger_count == ++finger_report)); + } + } +} +static irqreturn_t atmel_interrupt_fun(int irq, void *dev_id) +{ + int ret; + struct atmel_ts_data *ts = dev_id; + uint8_t data[7]; + int8_t report_type; + uint8_t msg_byte_num = 7; + + memset(data, 0x0, sizeof(data)); + + mutex_lock(&ts->lock); + ret = i2c_atmel_read(ts->client, get_object_address(ts, + GEN_MESSAGEPROCESSOR_T5), data, 7); + + report_type = data[MSG_RID] - ts->finger_type; + if (report_type >= 0 && report_type < ts->finger_support) { + msg_process_multitouch(ts, data, report_type); + } else { + if (data[MSG_RID] == get_rid(ts, GEN_COMMANDPROCESSOR_T6)) { + if (data[1] & 0x10) { + ts->timestamp = jiffies; + } + if (data[1] & 0x80) { + msleep(100); + + i2c_atmel_write_byte_data(ts->client, + get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + + T6_CFG_CALIBRATE, 0x55); + } + msg_byte_num = 5; + } + if (data[MSG_RID] == get_rid(ts, PROCI_TOUCHSUPPRESSION_T42)) { + if (ts->calibration_confirm < 2 && ts->id->version == 0x10) { + i2c_atmel_write_byte_data(ts->client, + get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + + T6_CFG_CALIBRATE, 0x55); + } + ts->face_suppression = data[T20_MSG_STATUS]; + printk(KERN_INFO "Touch Face suppression %s: ", + ts->face_suppression ? "Active" : "Inactive"); + msg_byte_num = 2; + } + } + if (!ts->finger_count || ts->face_suppression) { + ts->finger_pressed = 0; + ts->finger_count = 0; + compatible_input_report(ts->input_dev, NULL, 0, 1); + } else { + multi_input_report(ts); + } + input_sync(ts->input_dev); + mutex_unlock(&ts->lock); + + return IRQ_HANDLED; +} + +static int read_object_table(struct atmel_ts_data *ts) +{ + uint8_t i, type_count = 0; + uint8_t data[6]; + memset(data, 0x0, sizeof(data)); + + ts->object_table = kzalloc(sizeof(struct object_t)*ts->id->num_declared_objects, GFP_KERNEL); + if (ts->object_table == NULL) { + dev_err(&ts->client->dev, "k3ts, %s: allocate object_table failed\n", __func__); + return -ENOMEM; + } + + for (i = 0; i < ts->id->num_declared_objects; i++) { + i2c_atmel_read(ts->client, i * 6 + 0x07, data, 6); + ts->object_table[i].object_type = data[OBJ_TABLE_TYPE]; + ts->object_table[i].i2c_address = + data[OBJ_TABLE_LSB] | data[OBJ_TABLE_MSB] << 8; + ts->object_table[i].size = data[OBJ_TABLE_SIZE] + 1; + ts->object_table[i].instances = data[OBJ_TABLE_INSTANCES]; + ts->object_table[i].num_report_ids = data[OBJ_TABLE_RIDS]; + if (data[OBJ_TABLE_RIDS]) { + ts->object_table[i].report_ids = type_count + 1; + type_count += data[OBJ_TABLE_RIDS]; + } + if (data[OBJ_TABLE_TYPE] == TOUCH_MULTITOUCHSCREEN_T9) + ts->finger_type = ts->object_table[i].report_ids; + } + + return 0; +} + +static struct atmel_i2c_platform_data *atmel_ts_get_pdata(struct i2c_client *client) +{ + struct device_node *node = client->dev.of_node; + struct atmel_i2c_platform_data *pdata = client->dev.platform_data; + u32 data[8]; + + if (pdata) + return pdata; + + if (!node) + return NULL; + + pdata = devm_kzalloc(&client->dev, sizeof(struct atmel_i2c_platform_data), + GFP_KERNEL); + pdata->gpio_irq = of_get_named_gpio(node, "atmel-ts,gpio-irq", 0); + pdata->gpio_reset = of_get_named_gpio(node, "atmel-ts,gpio-reset", 0); + + of_property_read_u32_array(node, "atmel-ts,abs", &data[0], 8); + pdata->abs_x_min = data[0]; + pdata->abs_x_max = data[1]; + pdata->abs_y_min = data[2]; + pdata->abs_y_max = data[3]; + pdata->abs_pressure_min = data[4]; + pdata->abs_pressure_max = data[5]; + pdata->abs_width_min = data[6]; + pdata->abs_width_max = data[7]; + + of_property_read_u8_array(node, "atmel-ts,cfg_t6", &pdata->config_T6[0], 6); + of_property_read_u8_array(node, "atmel-ts,cfg_t7", &pdata->config_T7[0], 3); + of_property_read_u8_array(node, "atmel-ts,cfg_t8", &pdata->config_T8[0], 10); + of_property_read_u8_array(node, "atmel-ts,cfg_t9", &pdata->config_T9[0], 35); + of_property_read_u8_array(node, "atmel-ts,cfg_t15", &pdata->config_T15[0], 11); + of_property_read_u8_array(node, "atmel-ts,cfg_t19", &pdata->config_T19[0], 16); + of_property_read_u8_array(node, "atmel-ts,cfg_t23", &pdata->config_T23[0], 15); + of_property_read_u8_array(node, "atmel-ts,cfg_t25", &pdata->config_T25[0], 14); + of_property_read_u8_array(node, "atmel-ts,cfg_t40", &pdata->config_T40[0], 5); + of_property_read_u8_array(node, "atmel-ts,cfg_t42", &pdata->config_T42[0], 8); + of_property_read_u8_array(node, "atmel-ts,cfg_t46", &pdata->config_T46[0], 9); + of_property_read_u8_array(node, "atmel-ts,cfg_t47", &pdata->config_T47[0], 10); + of_property_read_u8_array(node, "atmel-ts,cfg_t48", &pdata->config_T48[0], 54); + of_property_read_u8_array(node, "atmel-ts,object_crc", &pdata->object_crc[0], 3); + of_property_read_u8_array(node, "atmel-ts,cable_config", &pdata->cable_config[0], 4); + of_property_read_u8_array(node, "atmel-ts,cable_config_t7", &pdata->cable_config_T7[0], 3); + of_property_read_u8_array(node, "atmel-ts,cable_config_t8", &pdata->cable_config_T8[0], 10); + of_property_read_u8_array(node, "atmel-ts,cable_config_t46", &pdata->cable_config_T46[0], 9); + of_property_read_u8_array(node, "atmel-ts,cable_config_t48", &pdata->cable_config_T48[0], 54); + of_property_read_u8_array(node, "atmel-ts,noise_config", &pdata->noise_config[0], 3); + of_property_read_u16_array(node, "atmel-ts,filter_level", &pdata->filter_level[0], 4); + of_property_read_u8_array(node, "atmel-ts,gcaf_level", &pdata->GCAF_level[0], 5); + of_property_read_u8_array(node, "atmel-ts,atch_nor", &pdata->ATCH_NOR[0], 6); + of_property_read_u8_array(node, "atmel-ts,atch_nor_20s", &pdata->ATCH_NOR_20S[0], 6); + + return pdata; +} + +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, intr = 0; + uint8_t loop_i; + struct i2c_msg msg[2]; + uint8_t data[16]; + uint8_t CRC_check = 0; + + client->dev.init_name = "atmel-ts"; + LDO = regulator_get(&client->dev, "ldo"); + if (IS_ERR(LDO)) { + dev_err(&client->dev, "no regulator found\n"); + LDO = NULL; + } else { + ret = regulator_enable(LDO); + if (!ret) + ret = regulator_set_voltage(LDO, LDO_POWR_VOLTAGE, LDO_POWR_VOLTAGE); + if (ret) + dev_err(&client->dev, "k3ts, %s: failed to set LDO\n", __func__); + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "k3ts, %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) { + ret = -ENOMEM; + goto err_alloc_data_failed; + } + + ts->unlock_flag = 0; + mutex_init(&ts->lock); + + ts->atmel_wq = create_singlethread_workqueue("atmel_wq"); + if (!ts->atmel_wq) { + dev_err(&client->dev, "k3ts, %s: create workqueue failed\n", __func__); + ret = -ENOMEM; + goto err_cread_wq_failed; + } + + ts->client = client; + i2c_set_clientdata(client, ts); + + pdata = atmel_ts_get_pdata(client); + ts->pdata = pdata; + + if (pdata) { + ts->power = pdata->power; + intr = pdata->gpio_irq; + client->irq = gpio_to_irq(intr); + } + if (ts->power) + ret = ts->power(1); + ret = gpio_request(intr, "gpio_tp_intr"); + if (ret) { + dev_err(&client->dev, "gpio_request %d failed\n", intr); + goto err_request_gpio_failed; + } + ret = gpio_direction_input(intr); + if (ret) { + dev_err(&client->dev, "k3ts, %s: gpio_direction_input failed %d\n", __func__, intr); + goto err_gpio_direction_failed; + } + + ret = gpio_request(ts->pdata->gpio_reset, "gpio_tp_reset"); + if (ret) { + dev_err(&client->dev, "k3ts, %s: gpio_request failed %d, ret = %d\n", + __func__, ts->pdata->gpio_reset, ret); + goto err_request_gpio_reset_failed; + } + + gpio_direction_output(ts->pdata->gpio_reset, 1); + mdelay(5); + gpio_direction_output(ts->pdata->gpio_reset, 0); + mdelay(10); + gpio_direction_output(ts->pdata->gpio_reset, 1); + mdelay(50); + + for (loop_i = 0; loop_i < 10; loop_i++) { + if (!gpio_get_value(intr)) + break; + msleep(10); + } + + if (loop_i == 10) + dev_err(&client->dev, "k3ts, %s: No Messages\n", __func__); + + /* 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) { + dev_err(&client->dev, "k3ts, %s: No Atmel chip inside\n", __func__); + goto err_detect_failed; + } + if (ts->power) + ret = ts->power(2); + + if (data[MSG_RID] == 0x01 && + (data[T6_MSG_STATUS] & (T6_MSG_STATUS_SIGERR|T6_MSG_STATUS_COMSERR))) { + dev_err(&client->dev, "k3ts, %s: init err: %x\n", __func__, data[1]); + goto err_detect_failed; + } else { + for (loop_i = 0; loop_i < 10; loop_i++) { + if (gpio_get_value(intr)) { + dev_err(&client->dev, "k3ts, %s: No more message\n", __func__); + break; + } + ret = i2c_transfer(client->adapter, msg, 1); + msleep(10); + } + } + + /* Read the info block data. */ + ts->id = kzalloc(sizeof(struct info_id_t), GFP_KERNEL); + if (ts->id == NULL) { + dev_err(&client->dev, "k3ts, %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[INFO_BLK_FID]; + ts->id->variant_id = data[INFO_BLK_VID]; + if (ts->id->family_id == 0x80 && ts->id->variant_id == 0x10) + ts->id->version = data[INFO_BLK_VER] + 6; + else + ts->id->version = data[INFO_BLK_VER]; + + ts->id->build = data[INFO_BLK_BUILD]; + ts->id->matrix_x_size = data[INFO_BLK_XSIZE]; + ts->id->matrix_y_size = data[INFO_BLK_YSIZE]; + ts->id->num_declared_objects = data[INFO_BLK_OBJS]; + + /* Read object table. */ + ret = read_object_table(ts); + if (ret < 0) + goto err_read_table_failed; + + + if (pdata) { + ts->finger_support = pdata->config_T9[T9_CFG_NUMTOUCH]; + + /* OBJECT CONFIG CRC check */ + if (pdata->object_crc[0]) { + ret = i2c_atmel_write_byte_data(client, + get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + + T6_CFG_CALIBRATE, 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[MSG_RID] == get_rid(ts, GEN_COMMANDPROCESSOR_T6)) + break; + } + msleep(10); + } + if (loop_i == 10) + dev_err(&client->dev, "k3ts, %s: No checksum read\n", __func__); + else { + dev_info(&client->dev, "k3ts, %s: CRC print : %x, %x, %x\n", __func__, + data[T6_MSG_CHECKSUM + 0], data[T6_MSG_CHECKSUM + 1], data[T6_MSG_CHECKSUM + 2]); + for (loop_i = 0; loop_i < 3; loop_i++) { + if (pdata->object_crc[loop_i] != data[T6_MSG_CHECKSUM + loop_i]) { + dev_err(&client->dev, + "k3ts, %s: CRC Error: %x, %x\n", __func__, + pdata->object_crc[loop_i], + data[T6_MSG_CHECKSUM + loop_i]); + break; + } + } + if (loop_i == 3) { + dev_info(&client->dev, "k3ts, %s: CRC passed: ", __func__); + for (loop_i = 0; loop_i < 3; loop_i++) + pr_info("0x%2.2X ", pdata->object_crc[loop_i]); + pr_info("\n"); + CRC_check = 1;/*means CRC check OK*/ + } + } + } + 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; + if (ts->id->version >= 0x10) { + ts->ATCH_EXT = &pdata->config_T8[6]; + ts->timestamp = jiffies + 60 * HZ; + } + ts->ATCH_NOR = pdata->ATCH_NOR; + ts->ATCH_NOR_20S = pdata->ATCH_NOR_20S; + ts->filter_level = pdata->filter_level; + + ts->config_setting[NONE].config_T7 + = ts->config_setting[CONNECTED].config_T7 + = pdata->config_T7; + ts->config_setting[NONE].config_T8 = pdata->config_T8; + ts->config_setting[CONNECTED].config_T8 = pdata->cable_config_T8; + ts->config_setting[NONE].config_T9 = pdata->config_T9; + ts->config_setting[NONE].config_T22 = pdata->config_T22; + ts->config_setting[NONE].config_T28 = pdata->config_T28; + ts->config_setting[NONE].config_T46 = pdata->config_T46; + ts->config_setting[NONE].config_T48 = pdata->config_T48; + ts->config_setting[CONNECTED].config_T46 = pdata->cable_config_T46; + ts->config_setting[CONNECTED].config_T48 = pdata->cable_config_T48; + + if (pdata->noise_config[0]) + for (loop_i = 0; loop_i < 3; loop_i++) + ts->noise_config[loop_i] = pdata->noise_config[loop_i]; + + if (pdata->cable_config[0]) { + ts->config_setting[NONE].config[CB_TCHTHR] = + pdata->config_T9[T9_CFG_TCHTHR]; + ts->config_setting[NONE].config[CB_NOISETHR] = + pdata->config_T22[T22_CFG_NOISETHR]; + ts->config_setting[NONE].config[CB_IDLEGCAFDEPTH] = + pdata->config_T28[T28_CFG_IDLEGCAFDEPTH]; + ts->config_setting[NONE].config[CB_ACTVGCAFDEPTH] = + pdata->config_T28[T28_CFG_ACTVGCAFDEPTH]; + for (loop_i = 0; loop_i < 4; loop_i++) + ts->config_setting[CONNECTED].config[loop_i] = + pdata->cable_config[loop_i]; + ts->GCAF_sample = + ts->config_setting[CONNECTED].config[CB_ACTVGCAFDEPTH]; + if (ts->id->version >= 0x20) + ts->noisethr = pdata->cable_config[CB_TCHTHR] - + pdata->config_T9[T9_CFG_TCHHYST]; + else + ts->noisethr = pdata->cable_config[CB_TCHTHR]; + ts->noisethr_config = + ts->config_setting[CONNECTED].config[CB_NOISETHR]; + } else { + if (pdata->cable_config_T7[0]) + ts->config_setting[CONNECTED].config_T7 = + pdata->cable_config_T7; + if (pdata->cable_config_T8[0]) + ts->config_setting[CONNECTED].config_T8 = + pdata->cable_config_T8; + if (pdata->cable_config_T9[0]) { + ts->config_setting[CONNECTED].config_T9 = + pdata->cable_config_T9; + ts->config_setting[CONNECTED].config_T22 = + pdata->cable_config_T22; + ts->config_setting[CONNECTED].config_T28 = + pdata->cable_config_T28; + ts->GCAF_sample = + ts->config_setting[CONNECTED].config_T28[T28_CFG_ACTVGCAFDEPTH]; + } + if (ts->status == CONNECTED) + ts->noisethr = (ts->id->version >= 0x20) ? + pdata->cable_config_T9[T9_CFG_TCHTHR] - pdata->cable_config_T9[T9_CFG_TCHHYST] : + pdata->cable_config_T9[T9_CFG_TCHTHR]; + else + ts->noisethr = (ts->id->version >= 0x20) ? + pdata->config_T9[T9_CFG_TCHTHR] - pdata->config_T9[T9_CFG_TCHHYST] : + pdata->config_T9[T9_CFG_TCHTHR]; + ts->noisethr_config = pdata->cable_config_T22[T22_CFG_NOISETHR]; + + } + + 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_GRIPSUPPRESSION_T40), + pdata->config_T40, + get_object_size(ts, PROCI_GRIPSUPPRESSION_T40)); + + i2c_atmel_write(ts->client, + get_object_address(ts, PROCI_TOUCHSUPPRESSION_T42), + pdata->config_T42, + get_object_size(ts, PROCI_TOUCHSUPPRESSION_T42)); + i2c_atmel_write(ts->client, + get_object_address(ts, PROCG_NOISESUPPRESSION_T48), + pdata->config_T48, + get_object_size(ts, PROCG_NOISESUPPRESSION_T48)); + 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, SPT_SELFTEST_T25), + pdata->config_T25, + get_object_size(ts, SPT_SELFTEST_T25)); + i2c_atmel_write(ts->client, + get_object_address(ts, SPT_CTECONFIG_T46), + pdata->config_T46, + get_object_size(ts, SPT_CTECONFIG_T46)); + i2c_atmel_write(ts->client, + get_object_address(ts, PROCI_STYLUS_T47), + pdata->config_T47, + get_object_size(ts, PROCI_STYLUS_T47)); + + ret = i2c_atmel_write_byte_data(client, + get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + + T6_CFG_BACKUPNV, 0x55); + + for (loop_i = 0; loop_i < 10; loop_i++) { + if (!gpio_get_value(intr)) + break; + dev_err(&client->dev, "k3ts, %s: wait for Message(%d)\n", __func__, loop_i + 1); + msleep(10); + } + + i2c_atmel_read(client, + get_object_address(ts, GEN_MESSAGEPROCESSOR_T5), data, 7); + + ret = i2c_atmel_write_byte_data(client, + get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + + T6_CFG_RESET, 0x11);/*reset*/ + msleep(100); + + if (ts->status == CONNECTED) { + if (ts->config_setting[CONNECTED].config_T8 != NULL) + i2c_atmel_write(ts->client, + get_object_address(ts, GEN_ACQUISITIONCONFIG_T8), + ts->config_setting[CONNECTED].config_T8, + get_object_size(ts, GEN_ACQUISITIONCONFIG_T8)); + if (ts->config_setting[CONNECTED].config_T46 != NULL) + i2c_atmel_write(ts->client, + get_object_address(ts, SPT_CTECONFIG_T46), + ts->config_setting[CONNECTED].config_T46, + get_object_size(ts, SPT_CTECONFIG_T46)); + if (ts->config_setting[CONNECTED].config_T48 != NULL) { + i2c_atmel_write(ts->client, + get_object_address(ts, PROCG_NOISESUPPRESSION_T48), + ts->config_setting[CONNECTED].config_T48, + get_object_size(ts, PROCG_NOISESUPPRESSION_T48)); + } + } + } + ts->calibration_confirm = 0; + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + ret = -ENOMEM; + dev_err(&client->dev, "k3ts, %s: Failed to allocate input device\n", __func__); + goto err_input_dev_alloc_failed; + } + /*Modified by z181527 for Debug Only*/ + ts->input_dev->name = "synaptics"/*"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); + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + 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); + + ret = input_register_device(ts->input_dev); + if (ret) { + dev_err(&client->dev, + "k3ts, %s: atmel_ts_probe: Unable to register %s input device\n", __func__, + ts->input_dev->name); + goto err_input_register_device_failed; + } + + ret = request_threaded_irq(client->irq, NULL, atmel_interrupt_fun, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + client->name, ts); + if (ret) + dev_err(&client->dev, "k3ts, %s: request_irq failed\n", __func__); + + private_ts = ts; + + dev_info(&client->dev, "k3ts, %s: probe %s successfully\n", __func__, + ts->input_dev->name); + + return 0; + +err_input_register_device_failed: + input_free_device(ts->input_dev); +err_input_dev_alloc_failed: +err_read_table_failed: + kfree(ts->id); +err_alloc_failed: +err_detect_failed: +err_gpio_direction_failed: +err_request_gpio_reset_failed: + gpio_free(ts->pdata->gpio_reset); + gpio_free(intr); +err_request_gpio_failed: + destroy_workqueue(ts->atmel_wq); +err_cread_wq_failed: + kfree(ts); +err_alloc_data_failed: +err_check_functionality_failed: + if (LDO != NULL) { + regulator_disable(LDO); + regulator_put(LDO); + } + return ret; +} + +static int atmel_ts_remove(struct i2c_client *client) +{ + struct atmel_ts_data *ts = i2c_get_clientdata(client); + + free_irq(client->irq, ts); + + destroy_workqueue(ts->atmel_wq); + input_unregister_device(ts->input_dev); + kfree(ts); + + regulator_disable(LDO); + regulator_put(LDO); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int atmel_ts_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct atmel_ts_data *ts = i2c_get_clientdata(client); + struct atmel_i2c_platform_data *pdata = ts->pdata; + uint8_t data[7]; + int ret = 0; + + mutex_lock(&ts->lock); + ts->finger_pressed = 0; + ts->finger_count = 0; + ts->first_pressed = 0; + + if (ts->id->version >= 0x10) { + ts->pre_data[0] = 0; + ret = i2c_atmel_write(ts->client, + get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + T8_CFG_ATCHCALST, + ts->ATCH_EXT, 4); + if (ret < 0) + pr_err("k3ts, %s: failed to write config T8\n", __func__); + } + + ret = i2c_atmel_write_byte_data(client, + get_object_address(ts, GEN_POWERCONFIG_T7) + T7_CFG_IDLEACQINT, 0x0); + if (ret < 0) + pr_err("k3ts, %s: failed to write config T7\n", __func__); + + ret = i2c_atmel_write_byte_data(client, + get_object_address(ts, GEN_POWERCONFIG_T7) + T7_CFG_ACTVACQINT, 0x0); + if (ret < 0) + pr_err("k3ts, %s: failed to write config T7\n", __func__); + + /* Read T5 until gpio_irq is HIGH level */ + if (!gpio_get_value(pdata->gpio_irq)) { + ret = i2c_atmel_read(ts->client, get_object_address(ts, + GEN_MESSAGEPROCESSOR_T5), data, 7); + if (ret < 0) { + pr_err("k3ts, %s: failed to read T5\n", __func__); + } + } + + mutex_unlock(&ts->lock); + + pr_info("[%s]: -\n", __func__); + return 0; +} + +static int atmel_ts_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct atmel_ts_data *ts = i2c_get_clientdata(client); + int ret = 0; + + pr_info("[%s]: +\n", __func__); + + mutex_lock(&ts->lock); + if (ts->id->version >= 0x10) + ts->timestamp = jiffies; + + ts->unlock_flag = 0; + + ret = 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 (ret < 0) + pr_err("k3ts, %s: failed to write config T7\n", __func__); + + ts->calibration_confirm = 0; + msleep(1); + + ret = i2c_atmel_write(ts->client, + get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + + T8_CFG_TCHAUTOCAL, ts->ATCH_NOR, 6); + if (ret < 0) + pr_err("k3ts, %s: failed to write config T8\n", __func__); + + ret = i2c_atmel_write_byte_data(client, + get_object_address(ts, GEN_COMMANDPROCESSOR_T6) + + T6_CFG_CALIBRATE, 0x55); + if (ret < 0) + pr_err("k3ts, %s: failed to write config T6\n", __func__); + + mutex_unlock(&ts->lock); + + pr_info("[%s]: -\n", __func__); + + return 0; +} +#endif +static SIMPLE_DEV_PM_OPS(atmel_ts_pm_ops, atmel_ts_suspend, atmel_ts_resume); + +static const struct i2c_device_id atml_ts_i2c_id[] = { + { ATMEL_MXT224E_NAME, 0 }, + { } +}; + +#ifdef CONFIG_OF +static const struct of_device_id atmel_ts_dt_ids[] = { + { .compatible = "atmel,ts-mxt224e", }, + { } +}; +MODULE_DEVICE_TABLE(of, atmel_ts_dt_ids); +#endif + +static struct i2c_driver atmel_ts_driver = { + .id_table = atml_ts_i2c_id, + .probe = atmel_ts_probe, + .remove = atmel_ts_remove, + .driver = { + .of_match_table = of_match_ptr(atmel_ts_dt_ids), + .name = ATMEL_MXT224E_NAME, + .pm = &atmel_ts_pm_ops, + }, +}; +module_i2c_driver(atmel_ts_driver); + +MODULE_DESCRIPTION("ATMEL Touch driver"); +MODULE_LICENSE("GPL"); |