diff options
| author | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
| commit | 8e4bff4cab0ddac6060645b0715210484d02ff40 (patch) | |
| tree | 3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/input/touchscreen/zinitix_touch_bt404.c | |
Diffstat (limited to 'drivers/input/touchscreen/zinitix_touch_bt404.c')
| -rw-r--r-- | drivers/input/touchscreen/zinitix_touch_bt404.c | 3525 |
1 files changed, 3525 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/zinitix_touch_bt404.c b/drivers/input/touchscreen/zinitix_touch_bt404.c new file mode 100644 index 00000000..c58816d3 --- /dev/null +++ b/drivers/input/touchscreen/zinitix_touch_bt404.c @@ -0,0 +1,3525 @@ +/* + * + * Zinitix touch driver + * + * Copyright (C) 2009 Zinitix, Inc. + * + * 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. + * + */ +/* +Version 2.0.0 : using reg data file (2010/11/05) +Version 2.0.1 : syntxt bug fix (2010/11/09) +Version 2.0.2 : Save status cmd delay bug (2010/11/10) +Version 2.0.3 : modify delay 10ms -> 50ms for clear hw calibration bit + : modify ZINITIX_TOTAL_NUMBER_OF_Y register (read only -> read/write ) + : modify SUPPORTED FINGER NUM register (read only -> read/write ) +Version 2.0.4 : [20101116] + Modify Firmware Upgrade routine. +Version 2.0.5 : [20101118] + add esd timer function & some bug fix. + you can select request_threaded_irq or + request_irq, setting USE_THREADED_IRQ. +Version 2.0.6 : [20101123] + add ABS_MT_WIDTH_MAJOR Report +Version 2.0.7 : [20101201] + Modify zinitix_early_suspend() / zinitix_late_resume() routine. +Version 2.0.8 : [20101216] + add using spin_lock option +Version 2.0.9 : [20101216] + Test Version +Version 2.0.10 : [20101217] + add USE_THREAD_METHOD option. + if USE_THREAD_METHOD = 0, you use workqueue +Version 2.0.11 : [20101229] + add USE_UPDATE_SYSFS option for update firmware. + && TOUCH_MODE == 1 mode. +Version 2.0.13 : [20110125] + modify esd timer routine +Version 2.0.14 : [20110217] + esd timer bug fix. (kernel panic) + sysfs bug fix. +Version 2.0.15 : [20110315] + add power off delay ,250ms +Version 2.0.16 : [20110316] + add upgrade method using isp +Version 2.0.17 : [20110406] + change naming rule : sain -> zinitix + (add) pending interrupt skip + add isp upgrade mode + remove warning message when complile +Version 3.0.2 : [20110711] + support bt4x3 series +Version 3.0.3 : [20110720] + add raw data monitoring func. + add the h/w calibration skip option. +Version 3.0.4 : [20110728] + fix using semaphore bug. +Version 3.0.5 : [20110801] + fix some bugs. +Version 3.0.6 : [20110802] + fix Bt4x3 isp upgrade bug. + add USE_TS_MISC_DEVICE option for showing info & upgrade + remove USE_UPDATE_SYSFS option +Version 3.0.7 : [201108016] + merge USE_TS_MISC_DEVICE option and USE_TEST_RAW_TH_DATA_MODE + fix work proceedure bug. +Version 3.0.8 / Version 3.0.9 : [201108017] + add ioctl func. +Version 3.0.10 : [201108030] + support REAL_SUPPORTED_FINGER_NUM +Version 3.0.11 : [201109014] + support zinitix apps. +Version 3.0.12 : [201109015] + add disable touch event func. +Version 3.0.13 : [201109015] + add USING_CHIP_SETTING option : interrupt mask/button num/finger num +Version 3.0.14 : [201109020] + support apps. above kernel version 2.6.35 +Version 3.0.15 : [201101004] + modify timing in firmware upgrade retry when failt to upgrade firmware +Version 3.0.16 : [20111024] + remove thread method. + add resume/suspend function + check code using checkpatch.pl +Version 3.0.19 : [20111124] + modify isp timing : 2ms -> 1ms +Version 3.0.20 : [20120201] + support icecream sandwich + remove bt4x2 option +Version 3.0.21~22 : [20120501] + test +Version 3.0.23 : [20120517] + support mulit touch protocol type B for ics +*/ + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/i2c.h> +#include <linux/miscdevice.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/hrtimer.h> +#include <linux/ioctl.h> +#include <linux/earlysuspend.h> +#include <linux/string.h> +#include <linux/semaphore.h> +#include <linux/kthread.h> +#include <linux/timer.h> +#include <linux/workqueue.h> +#include <linux/firmware.h> +#include <linux/slab.h> +#include <linux/version.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <mach/gpio.h> +#include <linux/uaccess.h> + +#include "zinitix_touch_bt404.h" +#include "zinitix_touch_bt4x4_firmware.h" + + +#define ZINITIX_DEBUG 0 + +static int m_ts_debug_mode = ZINITIX_DEBUG; + +#define SYSTEM_MAX_X_RESOLUTION 480 +#define SYSTEM_MAX_Y_RESOLUTION 870 + + +/* interrupt pin number*/ +#define GPIO_TOUCH_PIN_NUM 141 +/* interrupt pin IRQ number */ +#define GPIO_TOUCH_IRQ 0 + +#if !USE_THREADED_IRQ +static struct workqueue_struct *zinitix_workqueue; +#endif + +static struct workqueue_struct *zinitix_tmr_workqueue; + +#define zinitix_debug_msg(fmt, args...) \ + if (m_ts_debug_mode) \ + printk(KERN_INFO "zinitix : [%-18s:%5d]" fmt, \ + __func__, __LINE__, ## args); + +#define zinitix_printk(fmt, args...) \ + printk(KERN_INFO "zinitix : [%-18s:%5d]" fmt, \ + __func__, __LINE__, ## args); + +struct _ts_zinitix_coord { + u16 x; + u16 y; + u8 width; + u8 sub_status; +}; + +struct _ts_zinitix_point_info { + u16 status; +#if (TOUCH_MODE == 1) + u16 event_flag; +#else + u8 finger_cnt; + u8 time_stamp; +#endif + struct _ts_zinitix_coord coord[MAX_SUPPORTED_FINGER_NUM]; +}; + +#define TOUCH_V_FLIP 0x01 +#define TOUCH_H_FLIP 0x02 +#define TOUCH_XY_SWAP 0x04 + +struct _ts_capa_info { + u16 chip_revision; + u16 chip_firmware_version; + u16 chip_reg_data_version; + u16 x_resolution; + u16 y_resolution; + u32 chip_fw_size; + u32 MaxX; + u32 MaxY; + u32 MinX; + u32 MinY; + u32 Orientation; + u8 gesture_support; + u16 multi_fingers; + u16 button_num; + u16 chip_int_mask; + + u16 x_node_num; + u16 y_node_num; + u16 total_node_num; + u16 max_y_node; + u16 total_cal_n; + +}; + +enum _ts_work_proceedure { + TS_NO_WORK = 0, + TS_NORMAL_WORK, + TS_ESD_TIMER_WORK, + TS_IN_EALRY_SUSPEND, + TS_IN_SUSPEND, + TS_IN_RESUME, + TS_IN_LATE_RESUME, + TS_IN_UPGRADE, + TS_REMOVE_WORK, + TS_SET_MODE, + TS_HW_CALIBRAION, +}; + +struct zinitix_touch_dev { + struct input_dev *input_dev; + struct task_struct *task; + wait_queue_head_t wait; +#if !USE_THREADED_IRQ + struct work_struct work; +#endif + struct work_struct tmr_work; + struct i2c_client *client; + struct semaphore update_lock; + u32 i2c_dev_addr; + struct _ts_capa_info cap_info; + char phys[32]; + + bool is_valid_event; + struct _ts_zinitix_point_info touch_info; + struct _ts_zinitix_point_info reported_touch_info; + u16 icon_event_reg; + u16 event_type; + u32 int_gpio_num; + u32 irq; + u8 button[MAX_SUPPORTED_BUTTON_NUM]; + u8 work_proceedure; + struct semaphore work_proceedure_lock; + u8 use_esd_timer; + + bool in_esd_timer; + struct timer_list esd_timeout_tmr; + struct timer_list *p_esd_timeout_tmr; + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + + + struct semaphore raw_data_lock; + u16 raw_mode_flag; + s16 ref_data[MAX_TEST_RAW_DATA]; + s16 cur_data[MAX_RAW_DATA]; + u8 update; + +}; + + +#define ZINITIX_DRIVER_NAME "Zinitix_tsp" +#define ZINITIX_ISP_NAME "zinitix_isp" +static struct i2c_client *m_isp_client; + +static struct i2c_device_id zinitix_idtable[] = { + {ZINITIX_ISP_NAME, 0}, + {ZINITIX_DRIVER_NAME, 0}, + { } +}; + +#if SEC_TOUCH_INFO_REPORT +extern struct class *sec_class; +struct device *sec_touchscreen_dev; +struct device *sec_touchkey_dev; +#endif + + +/*<= you must set key button mapping*/ +u32 BUTTON_MAPPING_KEY[MAX_SUPPORTED_BUTTON_NUM] = { + KEY_SEARCH, KEY_BACK, KEY_HOME, KEY_MENU,}; + +#define TOUCH_VIRTUAL_KEYS +#ifdef TOUCH_VIRTUAL_KEYS + +static ssize_t virtual_keys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, + __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":30:859:100:55" + ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":430:859:100:55" + "\n"); +} + +static struct kobj_attribute virtual_keys_attr = { + .attr = { + .name = "virtualkeys.Zinitix_tsp", + .mode = S_IRUGO, + }, + .show = &virtual_keys_show, +}; + +static struct attribute *properties_attrs[] = { + &virtual_keys_attr.attr, + NULL +}; + +static struct attribute_group properties_attr_group = { + .attrs = properties_attrs, +}; + + +/* zinitix_ts_virtual_keys_init -- register virutal keys to system + * @return: none + */ +static void zinitix_ts_virtual_keys_init(void) +{ + int ret; + struct kobject *properties_kobj; + + //PIXCIR_DBG("%s",__func__); + + properties_kobj = kobject_create_and_add("board_properties", NULL); + if (properties_kobj) + ret = sysfs_create_group(properties_kobj, + &properties_attr_group); + if (!properties_kobj || ret) + pr_err("failed to create board_properties\n"); +} + + +#endif + + +/* define i2c sub functions*/ +static inline s32 ts_read_data(struct i2c_client *client, + u16 reg, u8 *values, u16 length) +{ + s32 ret; + /* select register*/ + ret = i2c_master_send(client , (u8 *)® , 2); + if (ret < 0) + return ret; + /* for setup tx transaction. */ + udelay(DELAY_FOR_TRANSCATION); + ret = i2c_master_recv(client , values , length); + if (ret < 0) + return ret; + udelay(DELAY_FOR_POST_TRANSCATION); + return length; +} + +static inline s32 ts_write_data(struct i2c_client *client, + u16 reg, u8 *values, u16 length) +{ + s32 ret; + u8 pkt[4]; + pkt[0] = (reg)&0xff; + pkt[1] = (reg >> 8)&0xff; + pkt[2] = values[0]; + pkt[3] = values[1]; + ret = i2c_master_send(client , pkt , length+2); + if (ret < 0) + return ret; + udelay(DELAY_FOR_POST_TRANSCATION); + return length; +} + +static inline s32 ts_write_reg(struct i2c_client *client, u16 reg, u16 value) +{ + if (ts_write_data(client, reg, (u8 *)&value, 2) < 0) + return I2C_FAIL; + return I2C_SUCCESS; +} + +static inline s32 ts_write_cmd(struct i2c_client *client, u16 reg) +{ + s32 ret; + ret = i2c_master_send(client , (u8 *)® , 2); + if (ret < 0) + return I2C_FAIL; + udelay(DELAY_FOR_POST_TRANSCATION); + return I2C_SUCCESS; +} + +static inline s32 ts_read_raw_data(struct i2c_client *client, + u16 reg, u8 *values, u16 length) +{ + s32 ret; + /* select register */ + ret = i2c_master_send(client , (u8 *)® , 2); + if (ret < 0) + return ret; + /* for setup tx transaction. */ + udelay(200); + ret = i2c_master_recv(client , values , length); + if (ret < 0) + return ret; + udelay(DELAY_FOR_POST_TRANSCATION); + return length; +} + + + +static inline s32 ts_read_firmware_data(struct i2c_client *client, + char *addr, u8 *values, u16 length) +{ + s32 ret; + if (addr != NULL) { + /* select register*/ + ret = i2c_master_send(client , addr , 2); + if (ret < 0) + return ret; + /* for setup tx transaction. */ + mdelay(1); + } + ret = i2c_master_recv(client , values , length); + if (ret < 0) + return ret; + udelay(DELAY_FOR_POST_TRANSCATION); + return length; +} + +static inline s32 ts_write_firmware_data(struct i2c_client *client, + u8 *values, u16 length) +{ + s32 ret; + ret = i2c_master_send(client , values , length); + if (ret < 0) + return ret; + udelay(DELAY_FOR_POST_TRANSCATION); + return length; +} + +static int zinitix_touch_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id); +static int zinitix_touch_remove(struct i2c_client *client); +static bool ts_init_touch(struct zinitix_touch_dev *touch_dev); +static void zinitix_clear_report_data(struct zinitix_touch_dev *touch_dev); +static void zinitix_parsing_data(struct zinitix_touch_dev *touch_dev); + +#ifdef CONFIG_PM_SLEEP +static int zinitix_resume(struct device *dev); +static int zinitix_suspend(struct device *dev); +#endif + + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void zinitix_early_suspend(struct early_suspend *h); +static void zinitix_late_resume(struct early_suspend *h); +#endif + + +static void ts_esd_timer_start(u16 sec, struct zinitix_touch_dev *touch_dev); +static void ts_esd_timer_stop(struct zinitix_touch_dev *touch_dev); +static void ts_esd_timer_init(struct zinitix_touch_dev *touch_dev); +static void ts_esd_timeout_handler(unsigned long data); + + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) +static int ts_misc_fops_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +#else +static long ts_misc_fops_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg); +#endif +static int ts_misc_fops_open(struct inode *inode, struct file *filp); +static int ts_misc_fops_close(struct inode *inode, struct file *filp); + +static const struct file_operations ts_misc_fops = { + .owner = THIS_MODULE, + .open = ts_misc_fops_open, + .release = ts_misc_fops_close, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + .ioctl = ts_misc_fops_ioctl, +#else + .unlocked_ioctl = ts_misc_fops_ioctl, +#endif +}; + +static struct miscdevice touch_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "zinitix_touch_misc", + .fops = &ts_misc_fops, +}; + +#define TOUCH_IOCTL_BASE 0xbc +#define TOUCH_IOCTL_GET_DEBUGMSG_STATE _IOW(TOUCH_IOCTL_BASE, 0, int) +#define TOUCH_IOCTL_SET_DEBUGMSG_STATE _IOW(TOUCH_IOCTL_BASE, 1, int) +#define TOUCH_IOCTL_GET_CHIP_REVISION _IOW(TOUCH_IOCTL_BASE, 2, int) +#define TOUCH_IOCTL_GET_FW_VERSION _IOW(TOUCH_IOCTL_BASE, 3, int) +#define TOUCH_IOCTL_GET_REG_DATA_VERSION _IOW(TOUCH_IOCTL_BASE, 4, int) +#define TOUCH_IOCTL_VARIFY_UPGRADE_SIZE _IOW(TOUCH_IOCTL_BASE, 5, int) +#define TOUCH_IOCTL_VARIFY_UPGRADE_DATA _IOW(TOUCH_IOCTL_BASE, 6, int) +#define TOUCH_IOCTL_START_UPGRADE _IOW(TOUCH_IOCTL_BASE, 7, int) +#define TOUCH_IOCTL_GET_X_NODE_NUM _IOW(TOUCH_IOCTL_BASE, 8, int) +#define TOUCH_IOCTL_GET_Y_NODE_NUM _IOW(TOUCH_IOCTL_BASE, 9, int) +#define TOUCH_IOCTL_GET_TOTAL_NODE_NUM _IOW(TOUCH_IOCTL_BASE, 10, int) +#define TOUCH_IOCTL_SET_RAW_DATA_MODE _IOW(TOUCH_IOCTL_BASE, 11, int) +#define TOUCH_IOCTL_GET_RAW_DATA _IOW(TOUCH_IOCTL_BASE, 12, int) +#define TOUCH_IOCTL_GET_X_RESOLUTION _IOW(TOUCH_IOCTL_BASE, 13, int) +#define TOUCH_IOCTL_GET_Y_RESOLUTION _IOW(TOUCH_IOCTL_BASE, 14, int) +#define TOUCH_IOCTL_HW_CALIBRAION _IOW(TOUCH_IOCTL_BASE, 15, int) +#define TOUCH_IOCTL_GET_REG _IOW(TOUCH_IOCTL_BASE, 16, int) +#define TOUCH_IOCTL_SET_REG _IOW(TOUCH_IOCTL_BASE, 17, int) +#define TOUCH_IOCTL_SEND_SAVE_STATUS _IOW(TOUCH_IOCTL_BASE, 18, int) +#define TOUCH_IOCTL_DONOT_TOUCH_EVENT _IOW(TOUCH_IOCTL_BASE, 19, int) + + +struct zinitix_touch_dev *misc_touch_dev; + + + + + +//for Debugging Tol +static bool ts_get_raw_data(struct zinitix_touch_dev *touch_dev) +{ + u32 total_node = touch_dev->cap_info.total_node_num; + u32 sz; + u16 udata; + down(&touch_dev->raw_data_lock); + if (touch_dev->raw_mode_flag == TOUCH_TEST_RAW_MODE) { + sz = (total_node*2 + MAX_TEST_POINT_INFO*2); + + + if (ts_read_raw_data(touch_dev->client, + ZINITIX_RAWDATA_REG, + (char *)touch_dev->cur_data, sz) < 0) { + zinitix_printk("error : read zinitix tc raw data\n"); + up(&touch_dev->raw_data_lock); + return false; + } + + /* no point, so update ref_data*/ + udata = touch_dev->cur_data[total_node]; + + if (!zinitix_bit_test(udata, BIT_ICON_EVENT) + && !zinitix_bit_test(udata, BIT_PT_EXIST)) + memcpy((u8 *)touch_dev->ref_data, + (u8 *)touch_dev->cur_data, total_node*2); + + touch_dev->update = 1; + memcpy((u8 *)(&touch_dev->touch_info), + (u8 *)&touch_dev->cur_data[total_node], + sizeof(struct _ts_zinitix_point_info)); + up(&touch_dev->raw_data_lock); + return true; + } else if (touch_dev->raw_mode_flag != TOUCH_NORMAL_MODE) { + zinitix_debug_msg("read raw data\r\n"); + sz = total_node*2 + sizeof(struct _ts_zinitix_point_info); + + + if (touch_dev->raw_mode_flag == TOUCH_ZINITIX_CAL_N_MODE) { + int total_cal_n = touch_dev->cap_info.total_cal_n; + if (total_cal_n == 0) + total_cal_n = 160; + + sz = + (total_cal_n*2 + sizeof(struct _ts_zinitix_point_info)); + + if (ts_read_raw_data(touch_dev->client, + ZINITIX_RAWDATA_REG, + (char *)touch_dev->cur_data, sz) < 0) { + zinitix_printk("error : read zinitix tc raw data\n"); + up(&touch_dev->raw_data_lock); + return false; + } + misc_touch_dev->update = 1; + memcpy((u8 *)(&touch_dev->touch_info), + (u8 *)&touch_dev->cur_data[total_cal_n], + sizeof(struct _ts_zinitix_point_info)); + up(&touch_dev->raw_data_lock); + return true; + } + + if (ts_read_raw_data(touch_dev->client, + ZINITIX_RAWDATA_REG, + (char *)touch_dev->cur_data, sz) < 0) { + zinitix_printk("error : read zinitix tc raw data\n"); + up(&touch_dev->raw_data_lock); + return false; + } + + udata = touch_dev->cur_data[total_node]; + if (!zinitix_bit_test(udata, BIT_ICON_EVENT) + && !zinitix_bit_test(udata, BIT_PT_EXIST)) + memcpy((u8 *)touch_dev->ref_data, + (u8 *)touch_dev->cur_data, total_node*2); + touch_dev->update = 1; + memcpy((u8 *)(&touch_dev->touch_info), + (u8 *)&touch_dev->cur_data[total_node], + sizeof(struct _ts_zinitix_point_info)); + } + up(&touch_dev->raw_data_lock); + return true; +} + + + +static bool ts_read_coord(struct zinitix_touch_dev *touch_dev) +{ +#if (TOUCH_MODE == 1) + int i; +#endif + + zinitix_debug_msg("ts_read_coord+\r\n"); + + if (gpio_get_value(touch_dev->int_gpio_num)) { + /*interrupt pin is high, not valid data.*/ + touch_dev->touch_info.status = 0; + zinitix_debug_msg("woops... inturrpt pin is high\r\n"); + return true; + } + + //for Debugging Tool + + if (touch_dev->raw_mode_flag != TOUCH_NORMAL_MODE) { + if (ts_get_raw_data(touch_dev) == false) + return false; + goto continue_check_point_data; + } + + + +#if (TOUCH_MODE == 1) + memset(&touch_dev->touch_info, + 0x0, sizeof(struct _ts_zinitix_point_info)); + + if (ts_read_data(touch_dev->client, + ZINITIX_POINT_STATUS_REG, + (u8 *)(&touch_dev->touch_info), 4) < 0) { + zinitix_debug_msg("error read point info using i2c.-\r\n"); + return false; + } + zinitix_debug_msg("status reg = 0x%x , event_flag = 0x%04x\r\n", + touch_dev->touch_info.status, touch_dev->touch_info.event_flag); + + if (touch_dev->touch_info.status == 0x0) { + zinitix_debug_msg("periodical esd repeated int occured\r\n"); + ts_write_cmd(touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(DELAY_FOR_SIGNAL_DELAY); + return true; + } + + if (zinitix_bit_test(touch_dev->touch_info.status, BIT_ICON_EVENT)) { + udelay(20); + if (ts_read_data(touch_dev->client, + ZINITIX_ICON_STATUS_REG, + (u8 *)(&touch_dev->icon_event_reg), 2) < 0) { + printk(KERN_INFO "error read icon info using i2c.\n"); + return false; + } + ts_write_cmd(touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(DELAY_FOR_SIGNAL_DELAY); + return true; + } + + + + if(touch_dev->touch_info.event_flag == 0) { + zinitix_printk( "error : event flag == 0?\n"); + ts_write_cmd(touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(DELAY_FOR_SIGNAL_DELAY); + return true; + } + + for (i = 0; i < touch_dev->cap_info.multi_fingers; i++) { + if (zinitix_bit_test(touch_dev->touch_info.event_flag, i)) { + udelay(20); + if (ts_read_data(touch_dev->client, + ZINITIX_POINT_STATUS_REG+2+(i*3), + (u8 *)(&touch_dev->touch_info.coord[i]), + sizeof(struct _ts_zinitix_coord)) < 0) { + zinitix_debug_msg("error read point info\n"); + return false; + } + } + } + + ts_write_cmd(touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(DELAY_FOR_SIGNAL_DELAY); + return true; +#else + if (ts_read_data(touch_dev->client, + ZINITIX_POINT_STATUS_REG, + (u8 *)(&touch_dev->touch_info), + sizeof(struct _ts_zinitix_point_info)) < 0) { + zinitix_debug_msg("error read point info using i2c.-\n"); + return false; + } + +continue_check_point_data: + zinitix_debug_msg("status = 0x%x , pt cnt = %d, t stamp = %d\n", + touch_dev->touch_info.status, + touch_dev->touch_info.finger_cnt, + touch_dev->touch_info.time_stamp); + + if (touch_dev->touch_info.status == 0x0) { + zinitix_debug_msg("periodical esd repeated int occured\r\n"); + ts_write_cmd(touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(DELAY_FOR_SIGNAL_DELAY); + return true; + } + + if (zinitix_bit_test(touch_dev->touch_info.status, BIT_ICON_EVENT)) { + udelay(20); + if (ts_read_data(touch_dev->client, + ZINITIX_ICON_STATUS_REG, + (u8 *)(&touch_dev->icon_event_reg), 2) < 0) { + zinitix_printk("error read icon info using i2c.\n"); + return false; + } + } + + ts_write_cmd(touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(DELAY_FOR_SIGNAL_DELAY); + zinitix_debug_msg("ts_read_coord-\r\n"); + return true; +#endif +} + + +static irqreturn_t ts_int_handler(int irq, void *dev) +{ + + struct zinitix_touch_dev *touch_dev = (struct zinitix_touch_dev *)dev; + /* zinitix_debug_msg("interrupt occured +\r\n"); */ + if(touch_dev == NULL) return IRQ_HANDLED; + /* remove pending interrupt */ + if (gpio_get_value(touch_dev->int_gpio_num)) { + zinitix_debug_msg("invalid interrupt occured +\r\n"); + return IRQ_HANDLED; + } +#if USE_THREADED_IRQ + return IRQ_WAKE_THREAD; +#else + disable_irq_nosync(irq); + queue_work(zinitix_workqueue, &touch_dev->work); + return IRQ_HANDLED; +#endif +} + + + +static void ts_power_control(u8 ctl) +{ + if (ctl == POWER_OFF) + ; + else if (ctl == POWER_ON) + ; + +} + +static bool ts_mini_init_touch(struct zinitix_touch_dev *touch_dev) +{ + u16 reg_val; + int i; +#if USE_CHECKSUM + u16 chip_eeprom_info; + u16 chip_check_reg[4]; +#endif + + if (touch_dev == NULL) { + zinitix_printk("error (touch_dev == NULL?)\r\n"); + return false; + } + + zinitix_debug_msg("check checksum\r\n"); + +#if USE_CHECKSUM + if (ts_read_data(touch_dev->client, + ZINITIX_EEPROM_INFO_REG, + (u8 *)&chip_eeprom_info, 2) < 0) { + zinitix_printk("fail to read eeprom info(%d)\r\n", i); + goto fail_mini_init; + } + + if (zinitix_bit_test(chip_eeprom_info, 0)) // not calibration + goto fail_mini_init_not_cal; + + if (ts_read_data(touch_dev->client, + ZINITIX_CHECK_REG0, (u8 *)chip_check_reg, 8) < 0) + goto fail_mini_init; + if( (chip_check_reg[0]!=chip_check_reg[2]) || (chip_check_reg[1]!=chip_check_reg[3]) ) { + zinitix_printk("firmware checksum error\r\n"); + goto fail_mini_init; + } +#endif + + if (ts_write_cmd(touch_dev->client, + ZINITIX_SWRESET_CMD) != I2C_SUCCESS) { + zinitix_printk("fail to write reset command\r\n"); + goto fail_mini_init; + } + + + /* initialize */ + if (ts_write_reg(touch_dev->client, + ZINITIX_X_RESOLUTION, + (u16)(touch_dev->cap_info.x_resolution)) != I2C_SUCCESS) + goto fail_mini_init; + + if (ts_write_reg(touch_dev->client, + ZINITIX_Y_RESOLUTION, + (u16)( touch_dev->cap_info.y_resolution)) != I2C_SUCCESS) + goto fail_mini_init; + + zinitix_debug_msg("touch max x = %d\r\n", touch_dev->cap_info.x_resolution); + zinitix_debug_msg("touch max y = %d\r\n", touch_dev->cap_info.y_resolution); + + if (ts_write_reg(touch_dev->client, + ZINITIX_BUTTON_SUPPORTED_NUM, + (u16)touch_dev->cap_info.button_num) != I2C_SUCCESS) + goto fail_mini_init; + + if (ts_write_reg(touch_dev->client, + ZINITIX_SUPPORTED_FINGER_NUM, + (u16)MAX_SUPPORTED_FINGER_NUM) != I2C_SUCCESS) + goto fail_mini_init; + + + if (touch_dev->raw_mode_flag != TOUCH_NORMAL_MODE) { /* Test Mode */ + if (ts_write_reg(touch_dev->client, + ZINITIX_TOUCH_MODE, + touch_dev->raw_mode_flag) != I2C_SUCCESS) + goto fail_mini_init; + } else + + { + reg_val = TOUCH_MODE; + if (ts_write_reg(touch_dev->client, + ZINITIX_TOUCH_MODE, + reg_val) != I2C_SUCCESS) + goto fail_mini_init; + } + /* soft calibration */ + if (ts_write_cmd(touch_dev->client, + ZINITIX_CALIBRATE_CMD) != I2C_SUCCESS) + goto fail_mini_init; + if (ts_write_reg(touch_dev->client, + ZINITIX_INT_ENABLE_FLAG, + touch_dev->cap_info.chip_int_mask) != I2C_SUCCESS) + goto fail_mini_init; + + /* read garbage data */ + for (i = 0; i < 10; i++) { + ts_write_cmd(touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(10); + } + + + if (touch_dev->raw_mode_flag != TOUCH_NORMAL_MODE) { /* Test Mode */ + if (ts_write_reg(touch_dev->client, + ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, + ZINITIX_SCAN_RATE_HZ + *ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL) != I2C_SUCCESS) + zinitix_printk("[zinitix_touch] Fail to set ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL.\r\n"); + } else + { + if (ts_write_reg(touch_dev->client, + ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, + ZINITIX_SCAN_RATE_HZ + *ZINITIX_ESD_TIMER_INTERVAL) != I2C_SUCCESS) + goto fail_mini_init; + + } + if (touch_dev->use_esd_timer) { + ts_esd_timer_start(ZINITIX_CHECK_ESD_TIMER, touch_dev); + zinitix_debug_msg("esd timer start\r\n"); + } + + zinitix_debug_msg("successfully mini initialized\r\n"); + return true; + +fail_mini_init: + + zinitix_printk("early mini init fail\n"); + ts_power_control(POWER_OFF); + mdelay(CHIP_POWER_OFF_DELAY); + ts_power_control(POWER_ON); + mdelay(CHIP_ON_DELAY); +fail_mini_init_not_cal: + if(ts_init_touch(touch_dev) == false) { + zinitix_debug_msg("fail initialized\r\n"); + return false; + } + + if (touch_dev->use_esd_timer) { + ts_esd_timer_start(ZINITIX_CHECK_ESD_TIMER, touch_dev); + zinitix_debug_msg("esd timer start\r\n"); + } + return true; +} + + +static void zinitix_touch_tmr_work(struct work_struct *work) +{ + struct zinitix_touch_dev *touch_dev = + container_of(work, struct zinitix_touch_dev, tmr_work); + + zinitix_printk("tmr queue work ++\r\n"); + if (touch_dev == NULL) { + zinitix_printk("touch dev == NULL ?\r\n"); + goto fail_time_out_init; + } + down(&touch_dev->work_proceedure_lock); + if (touch_dev->work_proceedure != TS_NO_WORK) { + zinitix_printk("other process occupied (%d)\r\n", + touch_dev->work_proceedure); + up(&touch_dev->work_proceedure_lock); + return; + } + touch_dev->work_proceedure = TS_ESD_TIMER_WORK; + + disable_irq(touch_dev->irq); + zinitix_printk("error. timeout occured. maybe ts device dead. so reset & reinit.\r\n"); + ts_power_control(POWER_OFF); + mdelay(CHIP_POWER_OFF_DELAY); + ts_power_control(POWER_ON); + mdelay(CHIP_ON_DELAY); + + zinitix_debug_msg("clear all reported points\r\n"); + zinitix_clear_report_data(touch_dev); + if (ts_mini_init_touch(touch_dev) == false) + goto fail_time_out_init; + + touch_dev->work_proceedure = TS_NO_WORK; + enable_irq(touch_dev->irq); + up(&touch_dev->work_proceedure_lock); + zinitix_printk("tmr queue work ----\r\n"); + return; +fail_time_out_init: + zinitix_printk("tmr work : restart error\r\n"); + ts_esd_timer_start(ZINITIX_CHECK_ESD_TIMER, touch_dev); + touch_dev->work_proceedure = TS_NO_WORK; + enable_irq(touch_dev->irq); + up(&touch_dev->work_proceedure_lock); +} + +static void ts_esd_timer_start(u16 sec, struct zinitix_touch_dev *touch_dev) +{ + if(touch_dev == NULL) return; + if (touch_dev->p_esd_timeout_tmr != NULL) + del_timer(touch_dev->p_esd_timeout_tmr); + touch_dev->p_esd_timeout_tmr = NULL; + + init_timer(&(touch_dev->esd_timeout_tmr)); + touch_dev->esd_timeout_tmr.data = (unsigned long)(touch_dev); + touch_dev->esd_timeout_tmr.function = ts_esd_timeout_handler; + touch_dev->esd_timeout_tmr.expires = jiffies + HZ*sec; + touch_dev->p_esd_timeout_tmr = &touch_dev->esd_timeout_tmr; + add_timer(&touch_dev->esd_timeout_tmr); +} + +static void ts_esd_timer_stop(struct zinitix_touch_dev *touch_dev) +{ + if(touch_dev == NULL) return; + if (touch_dev->p_esd_timeout_tmr) + del_timer(touch_dev->p_esd_timeout_tmr); + touch_dev->p_esd_timeout_tmr = NULL; +} + +static void ts_esd_timer_init(struct zinitix_touch_dev *touch_dev) +{ + if(touch_dev == NULL) return; + init_timer(&(touch_dev->esd_timeout_tmr)); + touch_dev->esd_timeout_tmr.data = (unsigned long)(touch_dev); + touch_dev->esd_timeout_tmr.function = ts_esd_timeout_handler; + touch_dev->p_esd_timeout_tmr = NULL; +} + +static void ts_esd_timeout_handler(unsigned long data) +{ + struct zinitix_touch_dev *touch_dev = (struct zinitix_touch_dev *)data; + if(touch_dev == NULL) return; + touch_dev->p_esd_timeout_tmr = NULL; + queue_work(zinitix_tmr_workqueue, &touch_dev->tmr_work); +} + +#if TOUCH_ONESHOT_UPGRADE +static bool ts_check_need_upgrade(u16 curVersion, u16 curRegVersion) +{ + u16 newVersion; + u16 newRegVersion; + newVersion = (u16) (m_firmware_data[0] | (m_firmware_data[1]<<8)); + + zinitix_printk("cur version = 0x%x, new version = 0x%x\n", + curVersion, newVersion); + + if (curVersion < newVersion) + return true; + else if (curVersion > newVersion) + return false; + + if (m_firmware_data[FIRMWARE_VERSION_POS+2] == 0xff + && m_firmware_data[FIRMWARE_VERSION_POS+3] == 0xff) + return false; + newRegVersion = (u16) (m_firmware_data[FIRMWARE_VERSION_POS+2] + | (m_firmware_data[FIRMWARE_VERSION_POS+3]<<8)); + + + if (curRegVersion < newRegVersion) + return true; + + return false; +} +#endif + +#define TC_PAGE_SZ 64 +#define TC_SECTOR_SZ 8 + +static u8 ts_upgrade_firmware(struct zinitix_touch_dev *touch_dev, + const u8 *firmware_data, u32 size) +{ + u16 flash_addr; + u8 *verify_data; + int retry_cnt = 0; + u8 i2c_buffer[TC_PAGE_SZ+2]; + + if (m_isp_client == NULL) { + zinitix_printk("i2c client for isp is not register \r\n"); + return false; + } + + verify_data = kzalloc(size, GFP_KERNEL); + if (verify_data == NULL) { + zinitix_printk("cannot alloc verify buffer\n"); + return false; + } + +retry_isp_firmware_upgrade: + ts_power_control(POWER_OFF); + mdelay(CHIP_POWER_OFF_AF_FZ_DELAY); + ts_power_control(POWER_ON); + mdelay(1); /* under 4ms*/ + + zinitix_printk("write firmware data\n"); + + for (flash_addr = 0; flash_addr < size; flash_addr += TC_PAGE_SZ) { + + printk(KERN_INFO "."); + zinitix_debug_msg("firmware write : addr = %04x, len = %d\n", + flash_addr, TC_PAGE_SZ); + + i2c_buffer[0] = (flash_addr>>8)&0xff; /*addr_h*/ + i2c_buffer[1] = (flash_addr)&0xff; /*addr_l*/ + memcpy(&i2c_buffer[2], &firmware_data[flash_addr], TC_PAGE_SZ); + + if (ts_write_firmware_data(m_isp_client, + i2c_buffer, TC_PAGE_SZ+2) < 0) { + zinitix_printk("error : write zinitix tc firmare\n"); + goto fail_upgrade; + } + mdelay(20); + } + mdelay(CHIP_POWER_OFF_AF_FZ_DELAY); + + zinitix_printk("\r\nread firmware data\n"); + + + flash_addr = 0; + i2c_buffer[0] = (flash_addr>>8)&0xff; /*addr_h*/ + i2c_buffer[1] = (flash_addr)&0xff; /*addr_l*/ + + if (ts_read_firmware_data(m_isp_client, + i2c_buffer, &verify_data[flash_addr], size) < 0) { + zinitix_printk("error : read zinitix tc firmare: addr = %04x, len = %d\n", + flash_addr, size); + goto fail_upgrade; + } + if (memcmp((u8 *)&firmware_data[flash_addr], + (u8 *)&verify_data[flash_addr], size) != 0) { + zinitix_printk("error : verify error : addr = %04x, len = %d\n", + flash_addr, size); + goto fail_upgrade; + } + + mdelay(CHIP_POWER_OFF_AF_FZ_DELAY); + ts_power_control(POWER_OFF); + mdelay(CHIP_POWER_OFF_AF_FZ_DELAY); + ts_power_control(POWER_ON); + mdelay(CHIP_ON_AF_FZ_DELAY); + zinitix_printk("upgrade finished\n"); + kfree(verify_data); + return true; + +fail_upgrade: + + mdelay(CHIP_POWER_OFF_AF_FZ_DELAY); + ts_power_control(POWER_OFF); + mdelay(CHIP_POWER_OFF_AF_FZ_DELAY); + ts_power_control(POWER_ON); + mdelay(CHIP_ON_AF_FZ_DELAY); + + zinitix_printk("upgrade fail : so retry... (%d)\n", ++retry_cnt); + if (retry_cnt <= ZINITIX_INIT_RETRY_CNT) + goto retry_isp_firmware_upgrade; + + if (verify_data != NULL) + kfree(verify_data); + + zinitix_printk("upgrade fail..\n"); + return false; + +} + +static bool ts_hw_calibration(struct zinitix_touch_dev *touch_dev) +{ + u16 chip_eeprom_info; + /* h/w calibration */ + if (ts_write_reg(touch_dev->client, + ZINITIX_TOUCH_MODE, 0x07) != I2C_SUCCESS) + return false; + mdelay(250); + if (ts_write_cmd(touch_dev->client, + ZINITIX_CALIBRATE_CMD) != I2C_SUCCESS) + return false; + if (ts_write_cmd(touch_dev->client, + ZINITIX_SWRESET_CMD) != I2C_SUCCESS) + return false; + mdelay(10); + ts_write_cmd(touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + + /* wait for h/w calibration*/ + do { + mdelay(1000); + ts_write_cmd(touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + if (ts_read_data(touch_dev->client, + ZINITIX_EEPROM_INFO_REG, + (u8 *)&chip_eeprom_info, 2) < 0) + return false; + zinitix_debug_msg("touch eeprom info = 0x%04X\r\n", + chip_eeprom_info); + if (!zinitix_bit_test(chip_eeprom_info, 0)) + break; + } while (1); + + if (ts_write_reg(touch_dev->client, + ZINITIX_TOUCH_MODE, TOUCH_MODE) != I2C_SUCCESS) + return false; + + if (touch_dev->cap_info.chip_int_mask != 0) + if (ts_write_reg(touch_dev->client, + ZINITIX_INT_ENABLE_FLAG, + touch_dev->cap_info.chip_int_mask) + != I2C_SUCCESS) + return false; + if (ts_write_cmd(touch_dev->client, + ZINITIX_SAVE_CALIBRATION_CMD) != I2C_SUCCESS) + return false; + mdelay(1000); + return true; + +} + +static bool ts_init_touch(struct zinitix_touch_dev *touch_dev) +{ + u16 reg_val; + int i; + u16 SetMaxX = SYSTEM_MAX_X_RESOLUTION; + u16 SetMaxY = SYSTEM_MAX_Y_RESOLUTION; + u16 chip_revision; + u16 chip_firmware_version; + u16 chip_reg_data_version; + u16 chip_eeprom_info; +#if USE_CHECKSUM + u16 chip_check_reg[4]; + u8 checksum_err; +#endif +#if TOUCH_ONESHOT_UPGRADE + s16 stmp; +#endif + int retry_cnt = 0; + + if (touch_dev == NULL) { + zinitix_printk("error touch_dev == null?\r\n"); + return false; + } + +retry_init: + +#if USE_CHECKSUM + for(i = 0; i < ZINITIX_INIT_RETRY_CNT; i++) { + if (ts_read_data(touch_dev->client, + ZINITIX_EEPROM_INFO_REG, + (u8 *)&chip_eeprom_info, 2) < 0) { + zinitix_printk("fail to read eeprom info(%d)\r\n", i); + mdelay(10); + continue; + } else + break; + } + if (i == ZINITIX_INIT_RETRY_CNT) { + goto fail_init; + } + + if (!zinitix_bit_test(chip_eeprom_info, 0)) { // no exist checksum data + + zinitix_debug_msg("check checksum\r\n"); + + checksum_err = 0; + + for (i = 0; i < ZINITIX_INIT_RETRY_CNT; i++) { + if (ts_read_data(touch_dev->client, + ZINITIX_CHECK_REG0, (u8 *)chip_check_reg, 8) < 0) { + mdelay(10); + continue; + } + + zinitix_debug_msg("0x%02X, 0x%02X, 0x%02X, 0x%02X\r\n", + chip_check_reg[0], chip_check_reg[1], chip_check_reg[2], chip_check_reg[3]); + + if( (chip_check_reg[0]!=chip_check_reg[2]) && + (chip_check_reg[1]==chip_check_reg[3]) ) + break; + else { + checksum_err = 1; + break; + } + } + + if (i == ZINITIX_INIT_RETRY_CNT || checksum_err) { + zinitix_printk("fail to check firmware data\r\n"); + if(checksum_err == 1 && retry_cnt < ZINITIX_INIT_RETRY_CNT) + retry_cnt = ZINITIX_INIT_RETRY_CNT; + goto fail_init; + } + } else + zinitix_printk("not calibration, so skip checksum.\r\n"); +#endif + + if (ts_write_cmd(touch_dev->client, + ZINITIX_SWRESET_CMD) != I2C_SUCCESS) { + zinitix_printk("fail to write reset command\r\n"); + goto fail_init; + } + + touch_dev->cap_info.button_num = SUPPORTED_BUTTON_NUM; + + reg_val = 0; + zinitix_bit_set(reg_val, BIT_PT_CNT_CHANGE); + zinitix_bit_set(reg_val, BIT_DOWN); + zinitix_bit_set(reg_val, BIT_MOVE); + zinitix_bit_set(reg_val, BIT_UP); + if (touch_dev->cap_info.button_num > 0) + zinitix_bit_set(reg_val, BIT_ICON_EVENT); + touch_dev->cap_info.chip_int_mask = reg_val; + + + if (ts_write_reg(touch_dev->client, + ZINITIX_INT_ENABLE_FLAG, 0x0) != I2C_SUCCESS) + goto fail_init; + + zinitix_debug_msg("send reset command\r\n"); + if (ts_write_cmd(touch_dev->client, + ZINITIX_SWRESET_CMD) != I2C_SUCCESS) + goto fail_init; + + /* get chip revision id */ + if (ts_read_data(touch_dev->client, + ZINITIX_CHIP_REVISION, + (u8 *)&chip_revision, 2) < 0) { + zinitix_printk("fail to read chip revision\r\n"); + goto fail_init; + } + zinitix_printk("touch chip revision id = %x\r\n", + chip_revision); + + touch_dev->cap_info.chip_fw_size = 32*1024; + + //for Debugging Tool + + if (ts_read_data(touch_dev->client, + ZINITIX_TOTAL_NUMBER_OF_X, + (u8 *)&touch_dev->cap_info.x_node_num, 2) < 0) + goto fail_init; + zinitix_printk("touch chip x node num = %d\r\n", + touch_dev->cap_info.x_node_num); + if (ts_read_data(touch_dev->client, + ZINITIX_TOTAL_NUMBER_OF_Y, + (u8 *)&touch_dev->cap_info.y_node_num, 2) < 0) + goto fail_init; + zinitix_printk("touch chip y node num = %d\r\n", + touch_dev->cap_info.y_node_num); + + touch_dev->cap_info.total_node_num = + touch_dev->cap_info.x_node_num*touch_dev->cap_info.y_node_num; + zinitix_printk("touch chip total node num = %d\r\n", + touch_dev->cap_info.total_node_num); + + if (ts_read_data(touch_dev->client, + ZINITIX_MAX_Y_NUM, + (u8 *)&touch_dev->cap_info.max_y_node, 2) < 0) + goto fail_init; + + zinitix_printk("touch chip max y node num = %d\r\n", + touch_dev->cap_info.max_y_node); + + if (ts_read_data(touch_dev->client, + ZINITIX_CAL_N_TOTAL_NUM, + (u8 *)&touch_dev->cap_info.total_cal_n, 2) < 0) + goto fail_init; + zinitix_printk("touch chip total cal n data num = %d\r\n", + touch_dev->cap_info.total_cal_n); + //---- + + + /* get chip firmware version */ + if (ts_read_data(touch_dev->client, + ZINITIX_FIRMWARE_VERSION, + (u8 *)&chip_firmware_version, 2) < 0) + goto fail_init; + zinitix_printk("touch chip firmware version = %x\r\n", + chip_firmware_version); + +#if TOUCH_ONESHOT_UPGRADE + chip_reg_data_version = 0xffff; + + if (ts_read_data(touch_dev->client, + ZINITIX_DATA_VERSION_REG, + (u8 *)&chip_reg_data_version, 2) < 0) + goto fail_init; + zinitix_debug_msg("touch reg data version = %d\r\n", + chip_reg_data_version); + + if (ts_check_need_upgrade(chip_firmware_version, + chip_reg_data_version) == true) { + zinitix_printk("start upgrade firmware\n"); + + if(ts_upgrade_firmware(touch_dev, &m_firmware_data[2], + touch_dev->cap_info.chip_fw_size) == false) + goto fail_init; + + if(ts_hw_calibration(touch_dev) == false) + goto fail_init; + + /* disable chip interrupt */ + if (ts_write_reg(touch_dev->client, + ZINITIX_INT_ENABLE_FLAG, 0) != I2C_SUCCESS) + goto fail_init; + goto retry_init; + } +#endif + + if (ts_read_data(touch_dev->client, + ZINITIX_DATA_VERSION_REG, + (u8 *)&chip_reg_data_version, 2) < 0) + goto fail_init; + zinitix_debug_msg("touch reg data version = %d\r\n", + chip_reg_data_version); + + if (ts_read_data(touch_dev->client, + ZINITIX_EEPROM_INFO_REG, + (u8 *)&chip_eeprom_info, 2) < 0) + goto fail_init; + zinitix_debug_msg("touch eeprom info = 0x%04X\r\n", chip_eeprom_info); + + + if (zinitix_bit_test(chip_eeprom_info, 0)) { /* hw calibration bit*/ + + /* h/w calibration */ + if(ts_hw_calibration(touch_dev) == false) + goto fail_init; + + /* disable chip interrupt */ + if (ts_write_reg(touch_dev->client, + ZINITIX_INT_ENABLE_FLAG, 0) != I2C_SUCCESS) + goto fail_init; + + } + + + touch_dev->cap_info.chip_revision = (u16)chip_revision; + touch_dev->cap_info.chip_firmware_version = (u16)chip_firmware_version; + touch_dev->cap_info.chip_reg_data_version = (u16)chip_reg_data_version; + + + /* initialize */ + if (ts_write_reg(touch_dev->client, + ZINITIX_X_RESOLUTION, (u16)(SetMaxX)) != I2C_SUCCESS) + goto fail_init; + + if (ts_write_reg(touch_dev->client, + ZINITIX_Y_RESOLUTION, (u16)(SetMaxY)) != I2C_SUCCESS) + goto fail_init; + + touch_dev->cap_info.x_resolution = SetMaxX; + touch_dev->cap_info.y_resolution = SetMaxY; + + zinitix_debug_msg("touch max x = %d\r\n", + touch_dev->cap_info.x_resolution); + zinitix_debug_msg("touch max y = %d\r\n", + touch_dev->cap_info.y_resolution); + + touch_dev->cap_info.MinX = (u32)0; + touch_dev->cap_info.MinY = (u32)0; + touch_dev->cap_info.MaxX = (u32)touch_dev->cap_info.x_resolution; + touch_dev->cap_info.MaxY = (u32)touch_dev->cap_info.y_resolution; + + if (ts_write_reg(touch_dev->client, + ZINITIX_BUTTON_SUPPORTED_NUM, + (u16)touch_dev->cap_info.button_num) != I2C_SUCCESS) + goto fail_init; + + if (ts_write_reg(touch_dev->client, + ZINITIX_SUPPORTED_FINGER_NUM, + (u16)MAX_SUPPORTED_FINGER_NUM) != I2C_SUCCESS) + goto fail_init; + touch_dev->cap_info.multi_fingers = MAX_SUPPORTED_FINGER_NUM; + + zinitix_debug_msg("max supported finger num = %d\r\n", + touch_dev->cap_info.multi_fingers); + touch_dev->cap_info.gesture_support = 0; + zinitix_debug_msg("set other configuration\r\n"); + + + if (touch_dev->raw_mode_flag != TOUCH_NORMAL_MODE) { /* Test Mode */ + if (ts_write_reg(touch_dev->client, + ZINITIX_TOUCH_MODE, + touch_dev->raw_mode_flag) != I2C_SUCCESS) + goto fail_init; + } else + { + reg_val = TOUCH_MODE; + if (ts_write_reg(touch_dev->client, + ZINITIX_TOUCH_MODE, reg_val) != I2C_SUCCESS) + goto fail_init; + } + /* soft calibration */ + if (ts_write_cmd(touch_dev->client, + ZINITIX_CALIBRATE_CMD) != I2C_SUCCESS) + goto fail_init; + if (ts_write_reg(touch_dev->client, + ZINITIX_INT_ENABLE_FLAG, + touch_dev->cap_info.chip_int_mask) != I2C_SUCCESS) + goto fail_init; + + /* read garbage data */ + for (i = 0; i < 10; i++) { + ts_write_cmd(touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(10); + } + + if (touch_dev->raw_mode_flag != TOUCH_NORMAL_MODE) { /* Test Mode */ + if (ts_write_reg(touch_dev->client, + ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, + ZINITIX_SCAN_RATE_HZ + *ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL) != I2C_SUCCESS) + zinitix_printk("fail to set ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL.\r\n"); + } else + { + if (ts_write_reg(touch_dev->client, + ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, + ZINITIX_SCAN_RATE_HZ + *ZINITIX_ESD_TIMER_INTERVAL) != I2C_SUCCESS) + goto fail_init; + zinitix_debug_msg("esd timer register = %d\r\n", reg_val); + } + + zinitix_debug_msg("successfully initialized\r\n"); + return true; + +fail_init: + + if (++retry_cnt <= ZINITIX_INIT_RETRY_CNT) { + ts_power_control(POWER_OFF); + mdelay(CHIP_POWER_OFF_DELAY); + ts_power_control(POWER_ON); + mdelay(CHIP_ON_DELAY); + zinitix_debug_msg("retry to initiallize(retry cnt = %d)\r\n", + retry_cnt); + goto retry_init; + } else if(retry_cnt == ZINITIX_INIT_RETRY_CNT+1) { + touch_dev->cap_info.chip_fw_size = 32*1024; + + zinitix_debug_msg("retry to initiallize(retry cnt = %d)\r\n", retry_cnt); +#if TOUCH_FORCE_UPGRADE + if( ts_upgrade_firmware(touch_dev, &m_firmware_data[2], + touch_dev->cap_info.chip_fw_size) == false) { + zinitix_printk("upgrade fail\n"); + return false; + } + mdelay(100); + // hw calibration and make checksum + if(ts_hw_calibration(touch_dev) == false) + goto fail_hwcal_init; + goto retry_init; +#endif + } +fail_hwcal_init: + zinitix_printk("failed to initiallize\r\n"); + return false; +} + +static void zinitix_clear_report_data(struct zinitix_touch_dev *touch_dev) +{ + int i; + u8 reported = 0; + u8 sub_status; + + + for (i = 0; i < touch_dev->cap_info.button_num; i++) { + if (touch_dev->button[i] == ICON_BUTTON_DOWN) { + touch_dev->button[i] = ICON_BUTTON_UP; + input_report_key(touch_dev->input_dev, + BUTTON_MAPPING_KEY[i], 0); + reported = true; + zinitix_debug_msg("button up = %d \r\n", i); + } + } + + + for (i = 0; i < touch_dev->cap_info.multi_fingers; i++) { + sub_status = touch_dev->reported_touch_info.coord[i].sub_status; + if (zinitix_bit_test(sub_status, SUB_BIT_EXIST)) { +#if MULTI_PROTOCOL_TYPE_B + input_mt_slot(touch_dev->input_dev, i); + input_mt_report_slot_state(touch_dev->input_dev, + MT_TOOL_FINGER, 0); + + input_report_abs(touch_dev->input_dev, + ABS_MT_TRACKING_ID, -1); +#else + input_report_abs(touch_dev->input_dev, + ABS_MT_TRACKING_ID, i); + input_report_abs(touch_dev->input_dev, + ABS_MT_TOUCH_MAJOR, 0); + input_report_abs(touch_dev->input_dev, + ABS_MT_WIDTH_MAJOR, 0); + input_report_abs(touch_dev->input_dev, + ABS_MT_POSITION_X, + touch_dev->reported_touch_info.coord[i].x); + input_report_abs(touch_dev->input_dev, + ABS_MT_POSITION_Y, + touch_dev->reported_touch_info.coord[i].y); + input_mt_sync(touch_dev->input_dev); +#endif + + reported = true; + if (!m_ts_debug_mode) + printk(KERN_INFO "[TSP] R %02d\r\n", i); + } + touch_dev->reported_touch_info.coord[i].sub_status = 0; + } + if (reported) { +#if !MULTI_PROTOCOL_TYPE_B + input_report_key(touch_dev->input_dev, BTN_TOUCH, 0); +#endif + input_sync(touch_dev->input_dev); + } + +} + + +static void zinitix_parsing_data(struct zinitix_touch_dev *touch_dev) +{ + + int i; + u8 reported = false; + u8 sub_status; + u8 prev_sub_status; + u32 x, y; + u32 w; + u32 tmp; + + if(touch_dev == NULL) { + printk(KERN_INFO "zinitix_parsing_data : touch_dev == NULL?\n"); + return; + } + + if (touch_dev->use_esd_timer) { + ts_esd_timer_stop(touch_dev); + zinitix_debug_msg("esd timer stop\r\n"); + } + +#if !USE_THREADED_IRQ + down(&touch_dev->work_proceedure_lock); +#endif + if (touch_dev->work_proceedure != TS_NO_WORK) { + zinitix_debug_msg("zinitix_touch_thread : \ + [warning] other process occupied..\r\n"); + udelay(DELAY_FOR_SIGNAL_DELAY); + if (!gpio_get_value(touch_dev->int_gpio_num)) { + ts_write_cmd(touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(DELAY_FOR_SIGNAL_DELAY); + } + + goto continue_parsing_data; + } + touch_dev->work_proceedure = TS_NORMAL_WORK; + if (ts_read_coord(touch_dev) == false || touch_dev->touch_info.status == 0xffff) { + zinitix_debug_msg("couldn't read touch_dev coord. maybe chip is dead\r\n"); + ts_power_control(POWER_OFF); + mdelay(CHIP_POWER_OFF_DELAY); + ts_power_control(POWER_ON); + mdelay(CHIP_ON_DELAY); + + zinitix_debug_msg("clear all reported points\r\n"); + zinitix_clear_report_data(touch_dev); + ts_mini_init_touch(touch_dev); + goto continue_parsing_data; + } + + + if (touch_dev->raw_mode_flag == TOUCH_TEST_RAW_MODE) + goto continue_parsing_data; + + /* invalid : maybe periodical repeated int. */ + if (touch_dev->touch_info.status == 0x0) + goto continue_parsing_data; + + reported = false; + + if (zinitix_bit_test(touch_dev->touch_info.status, BIT_ICON_EVENT)) { + for (i = 0; i < touch_dev->cap_info.button_num; i++) { + if (zinitix_bit_test(touch_dev->icon_event_reg, + (BIT_O_ICON0_DOWN+i))) { + touch_dev->button[i] = ICON_BUTTON_DOWN; + input_report_key(touch_dev->input_dev, + BUTTON_MAPPING_KEY[i], 1); + reported = true; + zinitix_debug_msg("button down = %d\r\n", i); + if (!m_ts_debug_mode) + printk(KERN_INFO "[TSP] button down = %d\r\n", i); + } + } + + for (i = 0; i < touch_dev->cap_info.button_num; i++) { + if (zinitix_bit_test(touch_dev->icon_event_reg, + (BIT_O_ICON0_UP+i))) { + touch_dev->button[i] = ICON_BUTTON_UP; + input_report_key(touch_dev->input_dev, + BUTTON_MAPPING_KEY[i], 0); + reported = true; + + zinitix_debug_msg("button up = %d\r\n", i); + if (!m_ts_debug_mode) + printk(KERN_INFO "[TSP] button down = %d\r\n", i); + } + } + } + + /* if button press or up event occured... */ + if (reported == true || !zinitix_bit_test(touch_dev->touch_info.status, BIT_PT_EXIST)) { + for (i = 0; i < touch_dev->cap_info.multi_fingers; i++) { + prev_sub_status = + touch_dev->reported_touch_info.coord[i].sub_status; + if (zinitix_bit_test(prev_sub_status, SUB_BIT_EXIST)) { + zinitix_debug_msg("finger [%02d] up\r\n", i); + +#if MULTI_PROTOCOL_TYPE_B + input_mt_slot(touch_dev->input_dev, i); + input_mt_report_slot_state(touch_dev->input_dev, + MT_TOOL_FINGER, 0); + + input_report_abs(touch_dev->input_dev, + ABS_MT_TRACKING_ID, -1); +#else + input_report_abs(touch_dev->input_dev, + ABS_MT_TRACKING_ID, i); + input_report_abs(touch_dev->input_dev, + ABS_MT_TOUCH_MAJOR, 0); + input_report_abs(touch_dev->input_dev, + ABS_MT_WIDTH_MAJOR, 0); + input_report_abs(touch_dev->input_dev, + ABS_MT_POSITION_X, + touch_dev->reported_touch_info.coord[i].x); + input_report_abs(touch_dev->input_dev, + ABS_MT_POSITION_Y, + touch_dev->reported_touch_info.coord[i].y); + input_mt_sync(touch_dev->input_dev); +#endif + if (!m_ts_debug_mode) + printk(KERN_INFO "[TSP] R %02d\r\n", i); + } + } + memset(&touch_dev->reported_touch_info, + 0x0, sizeof(struct _ts_zinitix_point_info)); +#if !MULTI_PROTOCOL_TYPE_B + input_report_key(touch_dev->input_dev, BTN_TOUCH, 0); +#endif + input_sync(touch_dev->input_dev); + if(reported == true) // for button event + udelay(100); + goto continue_parsing_data; + } + if (touch_dev->touch_info.finger_cnt > MAX_SUPPORTED_FINGER_NUM) + touch_dev->touch_info.finger_cnt = MAX_SUPPORTED_FINGER_NUM; + + for (i = 0; i < touch_dev->cap_info.multi_fingers; i++) { + sub_status = touch_dev->touch_info.coord[i].sub_status; + + if (zinitix_bit_test(sub_status, SUB_BIT_DOWN) + || zinitix_bit_test(sub_status, SUB_BIT_MOVE) + || zinitix_bit_test(sub_status, SUB_BIT_EXIST)) { + + x = touch_dev->touch_info.coord[i].x; + y = touch_dev->touch_info.coord[i].y; + w = touch_dev->touch_info.coord[i].width; + + /* transformation from touch to screen orientation */ + if (touch_dev->cap_info.Orientation & TOUCH_V_FLIP) + y = touch_dev->cap_info.MaxY + + touch_dev->cap_info.MinY - y; + if (touch_dev->cap_info.Orientation & TOUCH_H_FLIP) + x = touch_dev->cap_info.MaxX + + touch_dev->cap_info.MinX - x; + if (touch_dev->cap_info.Orientation & TOUCH_XY_SWAP) + zinitix_swap_v(x, y, tmp); + touch_dev->touch_info.coord[i].x = x; + touch_dev->touch_info.coord[i].y = y; + zinitix_debug_msg("finger [%02d] x = %d, y = %d\r\n", + i, x, y); + + if (w == 0) + w = 1; + + prev_sub_status = + touch_dev->reported_touch_info.coord[i].sub_status; + + if (!m_ts_debug_mode && !zinitix_bit_test(prev_sub_status, SUB_BIT_EXIST)) + printk(KERN_INFO "[TSP] P %02d\r\n", i); + +#if MULTI_PROTOCOL_TYPE_B + input_mt_slot(touch_dev->input_dev, i); + input_mt_report_slot_state(touch_dev->input_dev, + MT_TOOL_FINGER, 1); + if (!zinitix_bit_test(prev_sub_status, SUB_BIT_EXIST)) +#endif + input_report_abs(touch_dev->input_dev, + ABS_MT_TRACKING_ID, i); + + + input_report_abs(touch_dev->input_dev, + ABS_MT_TOUCH_MAJOR, (u32)w); + input_report_abs(touch_dev->input_dev, + ABS_MT_WIDTH_MAJOR, (u32)w); + input_report_abs(touch_dev->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(touch_dev->input_dev, + ABS_MT_POSITION_Y, y); +#if !MULTI_PROTOCOL_TYPE_B + input_mt_sync(touch_dev->input_dev); +#endif + }else if (zinitix_bit_test(sub_status, SUB_BIT_UP)) { + zinitix_debug_msg("finger [%02d] up \r\n", i); + + memset(&touch_dev->touch_info.coord[i], + 0x0, sizeof(struct _ts_zinitix_coord)); +#if MULTI_PROTOCOL_TYPE_B + input_mt_slot(touch_dev->input_dev, i); + input_mt_report_slot_state(touch_dev->input_dev, + MT_TOOL_FINGER, 0); + + input_report_abs(touch_dev->input_dev, + ABS_MT_TRACKING_ID, -1); +#else + input_report_abs(touch_dev->input_dev, + ABS_MT_TRACKING_ID, i); + input_report_abs(touch_dev->input_dev, + ABS_MT_TOUCH_MAJOR, 0); + input_report_abs(touch_dev->input_dev, + ABS_MT_WIDTH_MAJOR, 0); + input_report_abs(touch_dev->input_dev, + ABS_MT_POSITION_X, + touch_dev->reported_touch_info.coord[i].x); + input_report_abs(touch_dev->input_dev, + ABS_MT_POSITION_Y, + touch_dev->reported_touch_info.coord[i].y); + input_mt_sync(touch_dev->input_dev); +#endif + + if (!m_ts_debug_mode) + printk(KERN_INFO "[TSP] R %02d\r\n", i); + + } else + memset(&touch_dev->touch_info.coord[i], + 0x0, sizeof(struct _ts_zinitix_coord)); + + } + memcpy((char *)&touch_dev->reported_touch_info, + (char *)&touch_dev->touch_info, + sizeof(struct _ts_zinitix_point_info)); +#if !MULTI_PROTOCOL_TYPE_B + input_report_key(touch_dev->input_dev, BTN_TOUCH, 1); +#endif + input_sync(touch_dev->input_dev); + +continue_parsing_data: + + /* check_interrupt_pin, if high, enable int & wait signal */ + if (touch_dev->work_proceedure == TS_NORMAL_WORK) { + if (touch_dev->use_esd_timer) { + ts_esd_timer_start(ZINITIX_CHECK_ESD_TIMER, touch_dev); + zinitix_debug_msg("esd tmr start\n"); + } + touch_dev->work_proceedure = TS_NO_WORK; + } +#if !USE_THREADED_IRQ + up(&touch_dev->work_proceedure_lock); +#endif +} + + +#if USE_THREADED_IRQ +static irqreturn_t zinitix_touch_work(int irq, void *data) +{ + struct zinitix_touch_dev* touch_dev = (struct zinitix_touch_dev*)data; + zinitix_debug_msg("threaded irq signalled\r\n"); + zinitix_parsing_data(touch_dev); + return IRQ_HANDLED; +} +#else +static void zinitix_touch_work(struct work_struct *work) +{ + + struct zinitix_touch_dev *touch_dev = + container_of(work, struct zinitix_touch_dev, work); + + zinitix_debug_msg("signalled\r\n"); + zinitix_parsing_data(touch_dev); + enable_irq(touch_dev->irq); +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void zinitix_late_resume(struct early_suspend *h) +{ + + struct zinitix_touch_dev *touch_dev; + touch_dev = container_of(h, struct zinitix_touch_dev, early_suspend); + + if (touch_dev == NULL) + return; + zinitix_printk("late resume++\r\n"); + + down(&touch_dev->work_proceedure_lock); + if (touch_dev->work_proceedure != TS_IN_RESUME + && touch_dev->work_proceedure != TS_IN_EALRY_SUSPEND) { + zinitix_printk("invalid work proceedure (%d)\r\n", + touch_dev->work_proceedure); + up(&touch_dev->work_proceedure_lock); + return; + } +#ifdef CONFIG_PM_SLEEP + ts_write_cmd(touch_dev->client, ZINITIX_WAKEUP_CMD); + mdelay(10); +#else + ts_power_control(POWER_ON); + mdelay(CHIP_ON_DELAY); +#endif + if (ts_mini_init_touch(touch_dev) == false) + goto fail_late_resume; + enable_irq(touch_dev->irq); + touch_dev->work_proceedure = TS_NO_WORK; + up(&touch_dev->work_proceedure_lock); + zinitix_printk("resume--\n"); + return; +fail_late_resume: + zinitix_printk("failed to resume\n"); + enable_irq(touch_dev->irq); + touch_dev->work_proceedure = TS_NO_WORK; + up(&touch_dev->work_proceedure_lock); + return; +} + + +static void zinitix_early_suspend(struct early_suspend *h) +{ + struct zinitix_touch_dev *touch_dev = + container_of(h, struct zinitix_touch_dev, early_suspend); + + if (touch_dev == NULL) + return; + + zinitix_printk("early suspend++\n"); + + disable_irq(touch_dev->irq); + if (touch_dev->use_esd_timer) + flush_work(&touch_dev->tmr_work); +#if !USE_THREADED_IRQ + flush_work(&touch_dev->work); +#endif + + down(&touch_dev->work_proceedure_lock); + if (touch_dev->work_proceedure != TS_NO_WORK) { + zinitix_printk("invalid work proceedure (%d)\r\n", + touch_dev->work_proceedure); + up(&touch_dev->work_proceedure_lock); + enable_irq(touch_dev->irq); + return; + } + touch_dev->work_proceedure = TS_IN_EALRY_SUSPEND; + + zinitix_debug_msg("clear all reported points\r\n"); + zinitix_clear_report_data(touch_dev); + + if (touch_dev->use_esd_timer) { + ts_write_reg(touch_dev->client, + ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, 0); + ts_esd_timer_stop(touch_dev); + zinitix_printk("ts_esd_timer_stop\n"); + } + +#ifdef CONFIG_PM_SLEEP + ts_write_reg(touch_dev->client, ZINITIX_INT_ENABLE_FLAG, 0x0); + + udelay(100); + if (ts_write_cmd(touch_dev->client, ZINITIX_SLEEP_CMD) != I2C_SUCCESS) { + zinitix_printk("failed to enter into sleep mode\n"); + up(&touch_dev->work_proceedure_lock); + return; + } +#else + ts_power_control(POWER_OFF); + mdelay(CHIP_POWER_OFF_DELAY); +#endif + zinitix_printk("early suspend--\n"); + up(&touch_dev->work_proceedure_lock); + return; +} + +#endif /* CONFIG_HAS_EARLYSUSPEND */ + + + +#ifdef CONFIG_PM_SLEEP + +static int zinitix_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct zinitix_touch_dev *touch_dev = i2c_get_clientdata(client); + if (touch_dev == NULL) + return 0; + + zinitix_debug_msg("resume++\n"); + down(&touch_dev->work_proceedure_lock); + if (touch_dev->work_proceedure != TS_IN_SUSPEND) { + zinitix_printk("invalid work proceedure (%d)\r\n", + touch_dev->work_proceedure); + up(&touch_dev->work_proceedure_lock); + return 0; + } + + ts_power_control(POWER_ON); + msleep(CHIP_ON_DELAY); + +#ifdef CONFIG_HAS_EARLYSUSPEND + touch_dev->work_proceedure = TS_IN_RESUME; +#else + touch_dev->work_proceedure = TS_NO_WORK; + if (ts_mini_init_touch(touch_dev) == false) + zinitix_printk("failed to resume\n"); + enable_irq(touch_dev->irq); +#endif + + + zinitix_debug_msg("resume--\n"); + up(&touch_dev->work_proceedure_lock); + return 0; +} + +static int zinitix_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct zinitix_touch_dev *touch_dev = i2c_get_clientdata(client); + if (touch_dev == NULL) + return 0; + + zinitix_debug_msg("suspend++\n"); + +#ifndef CONFIG_HAS_EARLYSUSPEND + disable_irq(touch_dev->irq); +#endif + if (touch_dev->use_esd_timer) + flush_work(&touch_dev->tmr_work); +#if !USE_THREADED_IRQ + flush_work(&touch_dev->work); +#endif + down(&touch_dev->work_proceedure_lock); + if (touch_dev->work_proceedure != TS_NO_WORK + && touch_dev->work_proceedure != TS_IN_EALRY_SUSPEND) { + zinitix_printk("zinitix_suspend : invalid work proceedure (%d)\r\n", + touch_dev->work_proceedure); + up(&touch_dev->work_proceedure_lock); +#ifndef CONFIG_HAS_EARLYSUSPEND + enable_irq(touch_dev->irq); +#endif + return 0; + } + +#ifndef CONFIG_HAS_EARLYSUSPEND + zinitix_clear_report_data(touch_dev); + + if (touch_dev->use_esd_timer) { + ts_esd_timer_stop(touch_dev); + zinitix_printk("ts_esd_timer_stop\n"); + } + + ts_write_cmd(touch_dev->client, ZINITIX_SLEEP_CMD); + udelay(100); +#endif + + ts_power_control(POWER_OFF); + mdelay(CHIP_POWER_OFF_DELAY); + + touch_dev->work_proceedure = TS_IN_SUSPEND; + + zinitix_debug_msg("suspend--\n"); + up(&touch_dev->work_proceedure_lock); + return 0; +} + +#endif + +static SIMPLE_DEV_PM_OPS(zinitix_dev_pm_ops, + zinitix_suspend, zinitix_resume); + + + +#if SEC_TOUCH_INFO_REPORT + +#define MAX_X_NODE_CNT 20 +#define MAX_Y_NODE_CNT 16 +#define ZINITIX_MENU_KEY 158 +#define ZINITIX_BACK_KEY 151 +#define CAL_MIN_NUM 1400 +#define CAL_MAX_NUM 2030 +#define INT_WAIT_TIME 50 + +#define CHIP_INFO "ZINITIX" + +static ssize_t zinitix_get_test_raw_data(struct device *dev, struct device_attribute *attr, char *buf) +{ + int i,j; + int k = 0; + + int written_bytes = 0 ; /* & error check */ + + int16_t raw_data[MAX_X_NODE_CNT][MAX_Y_NODE_CNT]={{0,},}; + int16_t diff_data[MAX_X_NODE_CNT][MAX_Y_NODE_CNT]={{0,},}; + + if(misc_touch_dev == NULL) { + zinitix_debug_msg("device NULL : NULL\n"); + return 0; + } + + down(&misc_touch_dev->raw_data_lock); + + for(j = 0 ; j < misc_touch_dev->cap_info.y_node_num; j++) + { + k = j; + for(i = 0 ; i < misc_touch_dev->cap_info.x_node_num ; i++) + { + raw_data[i][j] =(int)(misc_touch_dev->ref_data[k]&0xffff); + diff_data[i][j] =(int)(((s16)(misc_touch_dev->cur_data[k]-misc_touch_dev->ref_data[k]))&0xffff); + k+=misc_touch_dev->cap_info.y_node_num; + } + } + + up(&misc_touch_dev->raw_data_lock); + + if(m_ts_debug_mode) { + for(i = 0 ; i < misc_touch_dev->cap_info.x_node_num ; i++) { + printk("[TSP]"); + for(j = 0 ; j < misc_touch_dev->cap_info.y_node_num ; j++ ) + printk(" %5d", raw_data[i][j]); + printk("\n"); + } + + for(i = 0 ; i < misc_touch_dev->cap_info.x_node_num ; i++) { + printk("[TSP]"); + for(j = 0 ; j < misc_touch_dev->cap_info.y_node_num ; j++ ) + printk(" %5d", diff_data[i][j]); + printk("\n"); + } + } + + for(j = 0 ; j < misc_touch_dev->cap_info.y_node_num ; j++) + { + for (i = 0; i < misc_touch_dev->cap_info.x_node_num ; i++) + written_bytes += sprintf(buf+written_bytes, "%d %d\n", raw_data[i][j], diff_data[i][j]); + } + + if (written_bytes > 0) + return written_bytes; + + return sprintf(buf, "-1"); +} + + +ssize_t zinitix_set_testmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned char value = 0; + int i; + + printk(KERN_INFO "[zinitix_touch] zinitix_set_testmode, buf = %d\r\n", *buf); + + if(misc_touch_dev == NULL) { + zinitix_debug_msg("device NULL : NULL\n"); + return 0; + } + + sscanf(buf, "%c", &value); + + if(value != TOUCH_TEST_RAW_MODE && value != TOUCH_NORMAL_MODE) + { + printk(KERN_WARNING "[zinitix ts] test mode setting value error. you must set %d[=normal] or %d[=raw mode]\r\n", TOUCH_NORMAL_MODE, TOUCH_TEST_RAW_MODE); + return 1; + } + + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + misc_touch_dev->work_proceedure = TS_SET_MODE; + + misc_touch_dev->raw_mode_flag = value; + + printk(KERN_INFO "[zinitix_touch] zinitix_set_testmode, touchkey_testmode = %d\r\n", misc_touch_dev->raw_mode_flag); + + if(misc_touch_dev->raw_mode_flag == TOUCH_NORMAL_MODE) { + printk(KERN_INFO "[zinitix_touch] TEST Mode Exit\r\n"); + + if (ts_write_reg(misc_touch_dev->client, ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, ZINITIX_SCAN_RATE_HZ*ZINITIX_ESD_TIMER_INTERVAL)!=I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] Fail to set ZINITIX_PERIODICAL_INTERRUPT_INTERVAL.\r\n"); + + if (ts_write_reg(misc_touch_dev->client, ZINITIX_TOUCH_MODE, TOUCH_MODE)!=I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] Fail to set ZINITX_TOUCH_MODE %d.\r\n", TOUCH_MODE); + + } else { + printk(KERN_INFO "[zinitix_touch] TEST Mode Enter\r\n"); + + if (ts_write_reg(misc_touch_dev->client, ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, ZINITIX_SCAN_RATE_HZ*ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL)!=I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] Fail to set ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL.\r\n"); + + if (ts_write_reg(misc_touch_dev->client, ZINITIX_TOUCH_MODE, TOUCH_TEST_RAW_MODE)!=I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] TEST Mode : Fail to set ZINITX_TOUCH_MODE %d.\r\n", TOUCH_TEST_RAW_MODE); + + memset(&misc_touch_dev->reported_touch_info, 0x0, sizeof(struct _ts_zinitix_point_info)); + memset(&misc_touch_dev->touch_info, 0x0, sizeof(struct _ts_zinitix_point_info)); + } + // clear garbage data + for(i=0; i<=20; i++) { + mdelay(20); + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + } + + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + return 1; + +} + +static ssize_t zinitix_tkey_reference(struct device *dev, struct device_attribute *attr, char *buf) +{ + + printk(KERN_INFO "[zinitix_touch] %s\r\n", __FUNCTION__); + + if(misc_touch_dev == NULL) { + zinitix_debug_msg("device NULL : NULL\n"); + return 0; + } + + printk(KERN_INFO "[zinitix_touch] %s : menu(%d), back(%d)\r\n", __FUNCTION__, misc_touch_dev->ref_data[ZINITIX_MENU_KEY], misc_touch_dev->ref_data[ZINITIX_BACK_KEY]); + + return sprintf(buf, "%d %d", misc_touch_dev->ref_data[ZINITIX_MENU_KEY], misc_touch_dev->ref_data[ZINITIX_BACK_KEY]); +} + +static ssize_t zinitix_tkey_data(struct device *dev, struct device_attribute *attr, char *buf) +{ + printk(KERN_INFO "[zinitix_touch] %s\r\n", __FUNCTION__); + + if(misc_touch_dev == NULL) { + zinitix_debug_msg("device NULL : NULL\n"); + return 0; + } + + printk(KERN_INFO "[zinitix_touch] %s : menu(%d)(%d), back(%d)(%d)\r\n", __FUNCTION__, + misc_touch_dev->ref_data[ZINITIX_MENU_KEY], misc_touch_dev->cur_data[ZINITIX_MENU_KEY], + misc_touch_dev->ref_data[ZINITIX_BACK_KEY], misc_touch_dev->cur_data[ZINITIX_BACK_KEY]); + + return sprintf(buf, "%d\n%d\n%d\n%d\n", misc_touch_dev->ref_data[ZINITIX_MENU_KEY], misc_touch_dev->cur_data[ZINITIX_MENU_KEY], + misc_touch_dev->ref_data[ZINITIX_BACK_KEY], misc_touch_dev->cur_data[ZINITIX_BACK_KEY]); +} +static int16_t zinitix_cal_ndata[MAX_X_NODE_CNT][MAX_Y_NODE_CNT] = {{0,},}; +static ssize_t zinitix_touch_cal_ndata(struct device *dev, struct device_attribute *attr, char *buf) +{ + int time_out = 0; + int i, j; + int interrup_detecting; + int node_num; + int written_bytes = 0; /* error check */ + + int16_t raw_data[MAX_X_NODE_CNT][MAX_Y_NODE_CNT] = {{0,},}; + + printk(KERN_INFO "[zinitix_touch] zinitix_read_raw_data( )\r\n"); + + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + + misc_touch_dev->work_proceedure = TS_SET_MODE; + + disable_irq(misc_touch_dev->client->irq); + + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_TOUCH_MODE, 7) != I2C_SUCCESS) { + printk(KERN_INFO "[zinitix_touch] ZINITIX_TOUCH_MODE fail\r\n"); + goto fail_read_raw; + } + udelay(10); + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + + //garbage data + for(i=0; i<20; i++) { + mdelay(20); + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + } + + + for (i = 0; i < INT_WAIT_TIME; i++) { + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + time_out = 0; + interrup_detecting = 1; + + while (gpio_get_value(misc_touch_dev->int_gpio_num)) { + mdelay(1); + + if (time_out++ > 20) { + printk(KERN_INFO "[zinitix_touch] interrupt disable timed out\r\n"); + interrup_detecting = 0; + break; + } + } + if (i == INT_WAIT_TIME) { + printk(KERN_INFO "[zinitix_touch] interrupt disable timed out\r\n"); + goto fail_read_raw; + } + + if ((interrup_detecting == 1) && (time_out < 20)) { + if (ts_read_raw_data(misc_touch_dev->client, + ZINITIX_RAWDATA_REG, (char *)raw_data, + MAX_TEST_RAW_DATA*2) < 0) { + printk(KERN_INFO "[zinitix_touch] ZINITIX_RAWDATA_REG fail\r\n"); + goto fail_read_raw; + } + memcpy(zinitix_cal_ndata, raw_data, MAX_TEST_RAW_DATA*2); + break; + } + } + + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_TOUCH_MODE, TOUCH_MODE) != I2C_SUCCESS) { + printk(KERN_INFO "[zinitix_touch] ZINITIX_TOUCH_MODE fail\r\n"); + goto fail_read_raw; + } + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(20); + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + mdelay(20); + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + enable_irq(misc_touch_dev->client->irq); + + if(m_ts_debug_mode) { + for (i = 0; i < misc_touch_dev->cap_info.x_node_num; i++) { + printk(KERN_CONT "[TSP]"); + for (j = 0; j < misc_touch_dev->cap_info.y_node_num; j++) + printk(KERN_CONT " %5d", raw_data[i][j]); + printk(KERN_CONT "\n"); + } + } + + // check cal ndata range + for (i = 0; i < misc_touch_dev->cap_info.x_node_num-1; i++) { + for (j = 0; j < misc_touch_dev->cap_info.y_node_num; j++) { + if (raw_data[i][j] < CAL_MIN_NUM) + return snprintf(buf, 2, "0"); + + if (raw_data[i][j] > CAL_MAX_NUM) + return snprintf(buf, 2, "0"); + } + } + + // check cal touch key ndata range + for (j = 0; j < misc_touch_dev->cap_info.y_node_num; j++) { + node_num = ((misc_touch_dev->cap_info.x_node_num-1)*misc_touch_dev->cap_info.y_node_num) + j; + if(node_num == ZINITIX_MENU_KEY || node_num == ZINITIX_BACK_KEY) { + if (raw_data[misc_touch_dev->cap_info.x_node_num-1][j] + < CAL_MIN_NUM) + return snprintf(buf, 2, "0"); + + if (raw_data[misc_touch_dev->cap_info.x_node_num-1][j] + > CAL_MAX_NUM) + return snprintf(buf, 2, "0"); + } + } + + for (i = 0; i < misc_touch_dev->cap_info.x_node_num; i++) { + for (j = 0; j < misc_touch_dev->cap_info.y_node_num; j++) { + written_bytes += sprintf(buf+written_bytes, "%d,",raw_data[i][j]); + } + } + if(written_bytes > 0) + return written_bytes; +fail_read_raw: + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_TOUCH_MODE, TOUCH_MODE) != I2C_SUCCESS) { + printk(KERN_INFO "[zinitix_touch] ZINITIX_TOUCH_MODE fail\r\n"); + goto fail_read_raw; + } + udelay(20); + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + mdelay(20); + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + enable_irq(misc_touch_dev->client->irq); + + return snprintf(buf, 2, "-1"); +} + +static ssize_t zinitix_touch_ndata_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int i,j,written_bytes=0; + printk("[TSP] %s\n",__func__); + + for (i = 0; i < misc_touch_dev->cap_info.x_node_num-1; i++) { + for (j = 0; j < misc_touch_dev->cap_info.y_node_num; j++) { + written_bytes += sprintf(buf+written_bytes, "%d,",zinitix_cal_ndata[i][j]); + } + } + if(written_bytes > 0) + return written_bytes; +} +static ssize_t zinitix_delta(struct device *dev, struct device_attribute *attr, char *buf) +{ + int written_bytes = 0, i; + + printk(KERN_INFO "[zinitix_touch] %s\r\n", __FUNCTION__); + + if(misc_touch_dev == NULL) { + zinitix_debug_msg("device NULL : NULL\n"); + return 0; + } + + for(i = 0 ; i < misc_touch_dev->cap_info.total_node_num; i++) { + written_bytes += sprintf(buf+written_bytes, "%d,", misc_touch_dev->cur_data[i] - misc_touch_dev->ref_data[i]) ; + } + + if(written_bytes > 0) + return written_bytes; +} + +static ssize_t zinitix_cal_ncount(struct device *dev, struct device_attribute *attr, char *buf) +{ + int i, j; + int written_bytes = 0; /* error check */ + + u8 raw_data[MAX_X_NODE_CNT][MAX_Y_NODE_CNT] = {{0,},}; + + printk(KERN_INFO "[zinitix_touch] zinitix_cal_ncount( )\r\n"); + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + + misc_touch_dev->work_proceedure = TS_SET_MODE; + + disable_irq(misc_touch_dev->client->irq); + + + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_TOUCH_MODE, 8) != I2C_SUCCESS) { + printk(KERN_INFO "[zinitix_touch] ZINITIX_TOUCH_MODE fail\r\n"); + goto fail_read_raw; + } + //clear garbage data + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + for(i=0; i<20; i++) { + mdelay(20); + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + } + + + if (ts_read_raw_data(misc_touch_dev->client, + ZINITIX_RAWDATA_REG, (char *)raw_data, MAX_X_NODE_CNT*MAX_Y_NODE_CNT) < 0) { + printk(KERN_INFO "[TSP] error : read zinitix tc Cal N count data\n"); + goto fail_read_raw; + } + + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_TOUCH_MODE, TOUCH_MODE) != I2C_SUCCESS) { + printk(KERN_INFO "[zinitix_touch] ZINITIX_TOUCH_MODE fail\r\n"); + goto fail_read_raw; + } + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + mdelay(20); + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + mdelay(20); + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + enable_irq(misc_touch_dev->client->irq); + + + if(m_ts_debug_mode) { + for (i = 0; i < misc_touch_dev->cap_info.x_node_num; i++) { + printk("[TSP]"); + for (j = 0; j < misc_touch_dev->cap_info.y_node_num; j++) { + printk(" %d", raw_data[i][j]); + } + printk("\n"); + } + } + + + for (i = 0; i < misc_touch_dev->cap_info.x_node_num; i++) { + for (j = 0; j < misc_touch_dev->cap_info.y_node_num; j++) { + written_bytes +=sprintf(buf+written_bytes, "%d,",raw_data[i][j]); + + } + } + + if(written_bytes > 0) + return written_bytes; + + return snprintf(buf, 2, "-1"); + +fail_read_raw: + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_TOUCH_MODE, TOUCH_MODE) != I2C_SUCCESS) { + printk(KERN_INFO "[zinitix_touch] ZINITIX_TOUCH_MODE fail\r\n"); + goto fail_read_raw; + } + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + udelay(10); + + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + enable_irq(misc_touch_dev->client->irq); + + return snprintf(buf, 2, "-1"); +} + +static ssize_t zinitix_enter_testmode(struct device *dev, struct device_attribute *attr, char *buf) +{ + int i; + + + if(misc_touch_dev == NULL) { + zinitix_debug_msg("device NULL : NULL\n"); + return 0; + } + //printk(KERN_INFO "[zinitix_touch] %s name : %s\r\n", __FUNCTION__, misc_touch_dev->client->name); + + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + + misc_touch_dev->work_proceedure = TS_SET_MODE; + misc_touch_dev->raw_mode_flag = TOUCH_TEST_RAW_MODE; + + if (ts_write_reg(misc_touch_dev->client, ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, ZINITIX_SCAN_RATE_HZ*ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL)!=I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] Fail to set ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL.\r\n"); + + if (ts_write_reg(misc_touch_dev->client, ZINITIX_TOUCH_MODE, TOUCH_TEST_RAW_MODE)!=I2C_SUCCESS) + { + printk(KERN_INFO "[zinitix_touch] TEST Mode : Fail to set ZINITX_TOUCH_MODE %d.\r\n", TOUCH_TEST_RAW_MODE); + } + + ts_write_cmd(misc_touch_dev->client, ZINITIX_CLEAR_INT_STATUS_CMD); + //clear garbage data + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + for(i=0; i<20; i++) { + mdelay(20); + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + } + zinitix_clear_report_data(misc_touch_dev); + memset(&misc_touch_dev->reported_touch_info, 0x0, sizeof(struct _ts_zinitix_point_info)); + memset(&misc_touch_dev->touch_info, 0x0, sizeof(struct _ts_zinitix_point_info)); + + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + enable_irq(misc_touch_dev->client->irq); + return 1; +} + +static ssize_t zinitix_enter_ncountmode(struct device *dev, struct device_attribute *attr, char *buf) +{ + int i; + printk(KERN_INFO "[zinitix_touch] %s 111 name : %s\r\n", __FUNCTION__, misc_touch_dev->client->name); + + if(misc_touch_dev == NULL) { + zinitix_debug_msg("device NULL : NULL\n"); + return 0; + } + + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + misc_touch_dev->work_proceedure = TS_SET_MODE; + misc_touch_dev->raw_mode_flag = TOUCH_ZINITIX_CAL_N_MODE; + + if (ts_write_reg(misc_touch_dev->client, ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, ZINITIX_SCAN_RATE_HZ*ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL)!=I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] Fail to set ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL.\r\n"); + + if (ts_write_reg(misc_touch_dev->client, ZINITIX_TOUCH_MODE, TOUCH_ZINITIX_CAL_N_MODE)!=I2C_SUCCESS) + { + printk(KERN_INFO "[zinitix_touch] TEST Mode : Fail to set ZINITX_TOUCH_MODE %d.\r\n", TOUCH_ZINITIX_CAL_N_MODE); + } + + //clear garbage data + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + for(i=0; i<20; i++) { + mdelay(20); + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + } + zinitix_clear_report_data(misc_touch_dev); + memset(&misc_touch_dev->reported_touch_info, 0x0, sizeof(struct _ts_zinitix_point_info)); + memset(&misc_touch_dev->touch_info, 0x0, sizeof(struct _ts_zinitix_point_info)); + + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + enable_irq(misc_touch_dev->client->irq); + return 1; +} + +static ssize_t zinitix_enter_normalmode(struct device *dev, struct device_attribute *attr, char *buf) +{ + int i; + + printk(KERN_INFO "[zinitix_touch] %s\r\n", __FUNCTION__); + + if(misc_touch_dev == NULL) { + zinitix_debug_msg("device NULL : NULL\n"); + return 0; + } + + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + misc_touch_dev->work_proceedure = TS_SET_MODE; + misc_touch_dev->raw_mode_flag = TOUCH_NORMAL_MODE; + + printk(KERN_INFO "[zinitix_touch] TEST Mode Exit\r\n"); + + if (ts_write_reg(misc_touch_dev->client, ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, ZINITIX_SCAN_RATE_HZ*ZINITIX_ESD_TIMER_INTERVAL)!=I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] Fail to set ZINITIX_PERIODICAL_INTERRUPT_INTERVAL.\r\n"); + + if (ts_write_reg(misc_touch_dev->client, ZINITIX_TOUCH_MODE, TOUCH_MODE)!=I2C_SUCCESS) + { + printk(KERN_INFO "[zinitix_touch] Fail to set ZINITX_TOUCH_MODE %d.\r\n", TOUCH_MODE); + } + //clear garbage data + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + for(i=0; i<20; i++) { + mdelay(20); + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + } + + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + enable_irq(misc_touch_dev->client->irq); + return 1; +} +static ssize_t zinitix_count_node(struct device *dev, struct device_attribute *attr, char *buf) +{ + printk("[TSP] %s\n",__func__); + return sprintf(buf, "%d,%d\n", misc_touch_dev->cap_info.x_node_num,misc_touch_dev->cap_info.y_node_num); +} +static ssize_t zinitix_chip_info(struct device *dev, struct device_attribute *attr, char *buf) +{ + printk("[TSP] %s\n",__func__); + return sprintf(buf, "%s, BT%03X\n", CHIP_INFO, (misc_touch_dev->cap_info.chip_revision>>4)); +} +static ssize_t zinitix_menu_sensitivity_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret = 0; + u16 menu_sensitivity; + + ret = ts_read_data(misc_touch_dev->client, 0x00A8, (u8*)&menu_sensitivity, 2); + + if (ret<0) + return sprintf(buf, "%s\n", "fail to read menu_sensitivity."); + else + return sprintf(buf, "%d\n", menu_sensitivity); +} + +static ssize_t zinitix_back_sensitivity_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret = 0; + u16 back_sensitivity; + + ret = ts_read_data(misc_touch_dev->client, 0x00A9, (u8*)&back_sensitivity, 2); + + if (ret<0) + return sprintf(buf, "%s\n", "fail to read back_sensitivity."); + else + return sprintf(buf, "%d\n", back_sensitivity); +} +static DEVICE_ATTR(get_touch_raw_data, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_get_test_raw_data, zinitix_set_testmode); +static DEVICE_ATTR(tkey_reference, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_tkey_reference, NULL); +static DEVICE_ATTR(touch_cal_ndata, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_touch_cal_ndata, NULL); +static DEVICE_ATTR(delta, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_delta, NULL); +static DEVICE_ATTR(cal_ncount, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_cal_ncount, NULL); +static DEVICE_ATTR(enter_testmode, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_enter_testmode, NULL); +static DEVICE_ATTR(enter_normalmode, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_enter_normalmode, NULL); +static DEVICE_ATTR(count_node, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_count_node, NULL); +static DEVICE_ATTR(chip_info, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_chip_info, NULL); +static DEVICE_ATTR(menu_sensitivity, S_IRUGO | S_IWUSR | S_IWGRP, zinitix_menu_sensitivity_show, NULL); +static DEVICE_ATTR(back_sensitivity, S_IRUGO | S_IWUSR | S_IWGRP, zinitix_back_sensitivity_show, NULL); +static DEVICE_ATTR(touch_ndata, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_touch_ndata_show, NULL); +static DEVICE_ATTR(tkey_data, S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, zinitix_tkey_data, NULL); + +#endif + +static int ts_misc_fops_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int ts_misc_fops_close(struct inode *inode, struct file *filp) +{ + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) +static int ts_misc_fops_ioctl(struct inode *inode, + struct file *filp, unsigned int cmd, + unsigned long arg) +#else +static long ts_misc_fops_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +#endif +{ + void __user *argp = (void __user *)arg; + struct _raw_ioctl raw_ioctl; + u8 *u8Data; + int i, j; + int ret = 0; + size_t sz = 0; + u16 version; + u8 div_node; + int total_cal_n; + + u16 mode; + + struct _reg_ioctl reg_ioctl; + u16 val; + int nval = 0; + + if (misc_touch_dev == NULL) + return -1; + + /* zinitix_debug_msg("cmd = %d, argp = 0x%x\n", cmd, (int)argp); */ + + switch (cmd) { + + case TOUCH_IOCTL_GET_DEBUGMSG_STATE: + ret = m_ts_debug_mode; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_SET_DEBUGMSG_STATE: + if (copy_from_user(&nval, argp, 4)) { + printk(KERN_INFO "[zinitix_touch] error : copy_from_user\n"); + return -1; + } + if (nval) + printk(KERN_INFO "[zinitix_touch] on debug mode (%d)\n", + nval); + else + printk(KERN_INFO "[zinitix_touch] off debug mode (%d)\n", + nval); + m_ts_debug_mode = nval; + break; + + case TOUCH_IOCTL_GET_CHIP_REVISION: + ret = misc_touch_dev->cap_info.chip_revision; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_GET_FW_VERSION: + ret = misc_touch_dev->cap_info.chip_firmware_version; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_GET_REG_DATA_VERSION: + ret = misc_touch_dev->cap_info.chip_reg_data_version; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_VARIFY_UPGRADE_SIZE: + if (copy_from_user(&sz, argp, sizeof(size_t))) + return -1; + + printk(KERN_INFO "firmware size = %d\r\n", sz); + if (misc_touch_dev->cap_info.chip_fw_size != sz) { + printk(KERN_INFO "firmware size error\r\n"); + return -1; + } + break; + + case TOUCH_IOCTL_VARIFY_UPGRADE_DATA: + if (copy_from_user(&m_firmware_data[2], + argp, misc_touch_dev->cap_info.chip_fw_size)) + return -1; + + version = + (u16)(((u16)m_firmware_data[FIRMWARE_VERSION_POS+1]<<8) + |(u16)m_firmware_data[FIRMWARE_VERSION_POS]); + + printk(KERN_INFO "firmware version = %x\r\n", version); + + if (copy_to_user(argp, &version, sizeof(version))) + return -1; + break; + + case TOUCH_IOCTL_START_UPGRADE: + disable_irq(misc_touch_dev->irq); + down(&misc_touch_dev->work_proceedure_lock); + misc_touch_dev->work_proceedure = TS_IN_UPGRADE; + + if (misc_touch_dev->use_esd_timer) + ts_esd_timer_stop(misc_touch_dev); + zinitix_debug_msg("clear all reported points\r\n"); + zinitix_clear_report_data(misc_touch_dev); + + printk(KERN_INFO "start upgrade firmware\n"); + if (ts_upgrade_firmware(misc_touch_dev, + &m_firmware_data[2], + misc_touch_dev->cap_info.chip_fw_size) == false) { + enable_irq(misc_touch_dev->irq); + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + + if (ts_init_touch(misc_touch_dev) == false) { + enable_irq(misc_touch_dev->irq); + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + + + if (misc_touch_dev->use_esd_timer) { + ts_esd_timer_start(ZINITIX_CHECK_ESD_TIMER, + misc_touch_dev); + zinitix_debug_msg("esd timer start\r\n"); + } + + enable_irq(misc_touch_dev->irq); + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + break; + + case TOUCH_IOCTL_GET_X_RESOLUTION: + ret = misc_touch_dev->cap_info.x_resolution; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_GET_Y_RESOLUTION: + ret = misc_touch_dev->cap_info.y_resolution; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_GET_X_NODE_NUM: + ret = misc_touch_dev->cap_info.x_node_num; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_GET_Y_NODE_NUM: + ret = misc_touch_dev->cap_info.y_node_num; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_GET_TOTAL_NODE_NUM: + ret = misc_touch_dev->cap_info.total_node_num; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_HW_CALIBRAION: + ret = -1; + disable_irq(misc_touch_dev->irq); + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO"other process occupied.. (%d)\r\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + misc_touch_dev->work_proceedure = TS_HW_CALIBRAION; + mdelay(100); + + /* h/w calibration */ + if(ts_hw_calibration(misc_touch_dev) == false) + goto fail_hw_cal; + + ret = 0; +fail_hw_cal: + if (misc_touch_dev->raw_mode_flag == TOUCH_NORMAL_MODE) + mode = TOUCH_MODE; + else + mode = misc_touch_dev->raw_mode_flag; + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_TOUCH_MODE, mode) != I2C_SUCCESS) { + printk(KERN_INFO "fail to set touch mode %d.\n", + mode); + goto fail_hw_cal2; + } + + if (ts_write_cmd(misc_touch_dev->client, + ZINITIX_SWRESET_CMD) != I2C_SUCCESS) + goto fail_hw_cal2; + + enable_irq(misc_touch_dev->irq); + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + return ret; +fail_hw_cal2: + enable_irq(misc_touch_dev->irq); + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + return -1; + + case TOUCH_IOCTL_SET_RAW_DATA_MODE: + if (misc_touch_dev == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO"other process occupied.. (%d)\r\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + misc_touch_dev->work_proceedure = TS_SET_MODE; + + if (copy_from_user(&nval, argp, 4)) { + printk(KERN_INFO "[zinitix_touch] error : copy_from_user\r\n"); + misc_touch_dev->work_proceedure = TS_NO_WORK; + return -1; + } + + zinitix_debug_msg("[zinitix_touch] touchkey_testmode = %d\r\n", + misc_touch_dev->raw_mode_flag); + + if (nval == TOUCH_NORMAL_MODE && + misc_touch_dev->raw_mode_flag != TOUCH_NORMAL_MODE) { + /* enter into normal mode */ + misc_touch_dev->raw_mode_flag = nval; + printk(KERN_INFO "[zinitix_touch] raw data mode exit\r\n"); + + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, + ZINITIX_SCAN_RATE_HZ*ZINITIX_ESD_TIMER_INTERVAL) + != I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] Fail to set ZINITIX_PERIODICAL_INTERRUPT_INTERVAL.\n"); + + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_TOUCH_MODE, TOUCH_MODE) != I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] fail to set TOUCH_MODE.\r\n"); + + } else if (nval != TOUCH_NORMAL_MODE) { + /* enter into test mode*/ + misc_touch_dev->raw_mode_flag = nval; + printk(KERN_INFO "[zinitix_touch] raw data mode enter\r\n"); + + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, + ZINITIX_SCAN_RATE_HZ + *ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL) + != I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] Fail to set ZINITIX_RAW_DATA_ESD_TIMER_INTERVAL.\n"); + + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_TOUCH_MODE, + misc_touch_dev->raw_mode_flag) != I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] raw data mode : Fail to set TOUCH_MODE %d.\n", + misc_touch_dev->raw_mode_flag); + } + /* clear garbage data */ + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + mdelay(100); + ts_write_cmd(misc_touch_dev->client, + ZINITIX_CLEAR_INT_STATUS_CMD); + + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + return 0; + + case TOUCH_IOCTL_GET_REG: + if (misc_touch_dev == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + + misc_touch_dev->work_proceedure = TS_SET_MODE; + + if (copy_from_user(®_ioctl, + argp, sizeof(struct _reg_ioctl))) { + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + printk(KERN_INFO "[zinitix_touch] error : copy_from_user\n"); + return -1; + } + + if (ts_read_data(misc_touch_dev->client, + reg_ioctl.addr, (u8 *)&val, 2) < 0) + ret = -1; + + nval = (int)val; + + if (copy_to_user(reg_ioctl.val, (u8 *)&nval, 4)) { + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + printk(KERN_INFO "[zinitix_touch] error : copy_to_user\n"); + return -1; + } + + zinitix_debug_msg("read : reg addr = 0x%x, val = 0x%x\n", + reg_ioctl.addr, nval); + + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + return ret; + + case TOUCH_IOCTL_SET_REG: + + if (misc_touch_dev == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + + misc_touch_dev->work_proceedure = TS_SET_MODE; + if (copy_from_user(®_ioctl, + argp, sizeof(struct _reg_ioctl))) { + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + printk(KERN_INFO "[zinitix_touch] error : copy_from_user\n"); + return -1; + } + + if (copy_from_user(&val, reg_ioctl.val, 4)) { + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + printk(KERN_INFO "[zinitix_touch] error : copy_from_user\n"); + return -1; + } + + if (ts_write_reg(misc_touch_dev->client, + reg_ioctl.addr, val) != I2C_SUCCESS) + ret = -1; + + zinitix_debug_msg("write : reg addr = 0x%x, val = 0x%x\r\n", + reg_ioctl.addr, val); + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + return ret; + + case TOUCH_IOCTL_DONOT_TOUCH_EVENT: + + if (misc_touch_dev == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO"other process occupied.. (%d)\r\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + + misc_touch_dev->work_proceedure = TS_SET_MODE; + if (ts_write_reg(misc_touch_dev->client, + ZINITIX_INT_ENABLE_FLAG, 0) != I2C_SUCCESS) + ret = -1; + zinitix_debug_msg("write : reg addr = 0x%x, val = 0x0\r\n", + ZINITIX_INT_ENABLE_FLAG); + + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + return ret; + + case TOUCH_IOCTL_SEND_SAVE_STATUS: + if (misc_touch_dev == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + down(&misc_touch_dev->work_proceedure_lock); + if (misc_touch_dev->work_proceedure != TS_NO_WORK) { + printk(KERN_INFO"other process occupied.. (%d)\r\n", + misc_touch_dev->work_proceedure); + up(&misc_touch_dev->work_proceedure_lock); + return -1; + } + misc_touch_dev->work_proceedure = TS_SET_MODE; + ret = 0; + if (ts_write_cmd(misc_touch_dev->client, + ZINITIX_SAVE_STATUS_CMD) != I2C_SUCCESS) + ret = -1; + mdelay(1000); /* for fusing eeprom */ + + misc_touch_dev->work_proceedure = TS_NO_WORK; + up(&misc_touch_dev->work_proceedure_lock); + return ret; + + case TOUCH_IOCTL_GET_RAW_DATA: + if (misc_touch_dev == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + + if (misc_touch_dev->raw_mode_flag == TOUCH_NORMAL_MODE) + return -1; + + down(&misc_touch_dev->raw_data_lock); + if (misc_touch_dev->update == 0) { + up(&misc_touch_dev->raw_data_lock); + return -2; + } + + if (copy_from_user(&raw_ioctl, + argp, sizeof(raw_ioctl))) { + up(&misc_touch_dev->raw_data_lock); + printk(KERN_INFO "[zinitix_touch] error : copy_from_user\r\n"); + return -1; + } + + misc_touch_dev->update = 0; + + u8Data = (u8 *)&misc_touch_dev->cur_data[0]; + if (misc_touch_dev->raw_mode_flag == TOUCH_ZINITIX_CAL_N_MODE) { + + + j = 0; + total_cal_n = + misc_touch_dev->cap_info.total_cal_n; + if (total_cal_n == 0) + total_cal_n = 160; + div_node = + (u8)misc_touch_dev->cap_info.max_y_node; + if (div_node == 0) + div_node = 16; + u8Data = (u8 *)&misc_touch_dev->cur_data[0]; + for (i = 0; i < total_cal_n*2; i++) { + if (i%div_node < + misc_touch_dev->cap_info.y_node_num) { + misc_touch_dev->ref_data[j] = + (u16)u8Data[i]; + j++; + } + } + + u8Data = (u8 *)&misc_touch_dev->ref_data[0]; + } + + if (copy_to_user(raw_ioctl.buf, (u8 *)u8Data, + raw_ioctl.sz)) { + up(&misc_touch_dev->raw_data_lock); + return -1; + } + + up(&misc_touch_dev->raw_data_lock); + return 0; + + default: + break; + } + return 0; +} + + + +static int zinitix_touch_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + int ret = 0; + struct zinitix_touch_dev *touch_dev; + int i; + + zinitix_debug_msg("zinitix_touch_probe+\r\n"); + + + zinitix_debug_msg("Above BT4x3 Driver\r\n"); + + printk(KERN_INFO "[zinitix touch] driver version = %s\r\n", + TS_DRVIER_VERSION); + + + if (strcmp(client->name, ZINITIX_ISP_NAME) == 0) { + printk(KERN_INFO "isp client probe \r\n"); + m_isp_client = client; + return 0; + } + + zinitix_debug_msg("i2c check function \r\n"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + printk(KERN_ERR "error : not compatible i2c function \r\n"); + goto err_check_functionality; + } + + zinitix_debug_msg("touch data alloc \r\n"); + touch_dev = kzalloc(sizeof(struct zinitix_touch_dev), GFP_KERNEL); + if (!touch_dev) { + printk(KERN_ERR "unabled to allocate touch data \r\n"); + goto err_alloc_dev_data; + } + touch_dev->client = client; + i2c_set_clientdata(client, touch_dev); + +#if !USE_THREADED_IRQ + INIT_WORK(&touch_dev->work, zinitix_touch_work); + zinitix_debug_msg("touch workqueue create \r\n"); + zinitix_workqueue = create_singlethread_workqueue("zinitix_workqueue"); + if (!zinitix_workqueue) { + printk(KERN_ERR "unabled to create touch thread \r\n"); + goto err_kthread_create_failed; + } +#endif + + zinitix_debug_msg("allocate input device \r\n"); + touch_dev->input_dev = input_allocate_device(); + if (touch_dev->input_dev == 0) { + printk(KERN_ERR "unabled to allocate input device \r\n"); + goto err_input_allocate_device; + } + + /* initialize zinitix touch ic */ + touch_dev->int_gpio_num = GPIO_TOUCH_PIN_NUM; /* for upgrade */ + + memset(&touch_dev->reported_touch_info, + 0x0, sizeof(struct _ts_zinitix_point_info)); + + + /* not test mode */ + touch_dev->raw_mode_flag = TOUCH_NORMAL_MODE; + + if(ts_init_touch(touch_dev) == false) { + goto err_input_register_device; + } + + for (i = 0; i < MAX_SUPPORTED_BUTTON_NUM; i++) + touch_dev->button[i] = ICON_BUTTON_UNCHANGE; + + touch_dev->use_esd_timer = 0; + + INIT_WORK(&touch_dev->tmr_work, zinitix_touch_tmr_work); + zinitix_tmr_workqueue = + create_singlethread_workqueue("zinitix_tmr_workqueue"); + if (!zinitix_tmr_workqueue) { + printk(KERN_ERR "unabled to create touch tmr work queue \r\n"); + goto err_kthread_create_failed; + } + + if (ZINITIX_ESD_TIMER_INTERVAL) { + touch_dev->use_esd_timer = 1; + ts_esd_timer_init(touch_dev); + ts_esd_timer_start(ZINITIX_CHECK_ESD_TIMER, touch_dev); + printk(KERN_INFO " ts_esd_timer_start\n"); + } + + + sprintf(touch_dev->phys, "input(ts)"); + touch_dev->input_dev->name = ZINITIX_DRIVER_NAME; + touch_dev->input_dev->id.bustype = BUS_I2C; + touch_dev->input_dev->id.vendor = 0x0001; + touch_dev->input_dev->phys = touch_dev->phys; + touch_dev->input_dev->id.product = 0x0002; + touch_dev->input_dev->id.version = 0x0100; + + set_bit(EV_SYN, touch_dev->input_dev->evbit); + set_bit(EV_KEY, touch_dev->input_dev->evbit); + set_bit(EV_ABS, touch_dev->input_dev->evbit); + + + for (i = 0; i < MAX_SUPPORTED_BUTTON_NUM; i++) + set_bit(BUTTON_MAPPING_KEY[i], touch_dev->input_dev->keybit); + + if (touch_dev->cap_info.Orientation & TOUCH_XY_SWAP) { + input_set_abs_params(touch_dev->input_dev, ABS_MT_POSITION_Y, + touch_dev->cap_info.MinX, + 480 + ABS_PT_OFFSET, + 0, 0); + input_set_abs_params(touch_dev->input_dev, ABS_MT_POSITION_X, + touch_dev->cap_info.MinY, + 800 + ABS_PT_OFFSET, + 0, 0); + } else { + input_set_abs_params(touch_dev->input_dev, ABS_MT_POSITION_X, + touch_dev->cap_info.MinX, + 480 + ABS_PT_OFFSET, + 0, 0); + input_set_abs_params(touch_dev->input_dev, ABS_MT_POSITION_Y, + touch_dev->cap_info.MinY, + 800 + ABS_PT_OFFSET, + 0, 0); + } + + input_set_abs_params(touch_dev->input_dev, ABS_TOOL_WIDTH, + 0, 255, 0, 0); + input_set_abs_params(touch_dev->input_dev, ABS_MT_TOUCH_MAJOR, + 0, 255, 0, 0); + input_set_abs_params(touch_dev->input_dev, ABS_MT_WIDTH_MAJOR, + 0, 255, 0, 0); + +#if MULTI_PROTOCOL_TYPE_B + set_bit(MT_TOOL_FINGER, touch_dev->input_dev->keybit); + input_mt_init_slots(touch_dev->input_dev, touch_dev->cap_info.multi_fingers); +#else + set_bit(BTN_TOUCH, touch_dev->input_dev->keybit); +#endif + + + input_set_abs_params(touch_dev->input_dev, ABS_MT_TRACKING_ID, + 0, touch_dev->cap_info.multi_fingers, 0, 0); + + + zinitix_debug_msg("register %s input device \r\n", + touch_dev->input_dev->name); + ret = input_register_device(touch_dev->input_dev); + if (ret) { + printk(KERN_ERR "unable to register %s input device\r\n", + touch_dev->input_dev->name); + goto err_input_register_device; + } + +#ifdef TOUCH_VIRTUAL_KEYS + zinitix_ts_virtual_keys_init(); +#endif + /* configure touchscreen interrupt gpio */ + ret = gpio_request(GPIO_TOUCH_PIN_NUM, "zinitix_irq_gpio"); + if (ret) { + printk(KERN_ERR "unable to request gpio.(%s)\r\n", + touch_dev->input_dev->name); + goto err_request_irq; + } + + ret = gpio_direction_input(GPIO_TOUCH_PIN_NUM); + + touch_dev->int_gpio_num = GPIO_TOUCH_PIN_NUM; + + + touch_dev->irq = gpio_to_irq(touch_dev->int_gpio_num); + if (touch_dev->irq < 0) + printk(KERN_INFO "error. gpio_to_irq(..) function is not \ + supported? you should define GPIO_TOUCH_IRQ.\r\n"); + + zinitix_debug_msg("request irq (irq = %d, pin = %d) \r\n", + touch_dev->irq, touch_dev->int_gpio_num); + + touch_dev->work_proceedure = TS_NO_WORK; + sema_init(&touch_dev->work_proceedure_lock, 1); + +#if USE_THREADED_IRQ + ret = request_threaded_irq(touch_dev->irq, ts_int_handler, zinitix_touch_work, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT , ZINITIX_DRIVER_NAME, touch_dev); +#else + ret = request_irq(touch_dev->irq, ts_int_handler, + IRQF_TRIGGER_LOW, ZINITIX_DRIVER_NAME, touch_dev); +#endif + if (ret) { + printk(KERN_ERR "unable to register irq.(%s)\r\n", + touch_dev->input_dev->name); + goto err_request_irq; + } + dev_info(&client->dev, "zinitix touch probe.\r\n"); + +#ifdef CONFIG_HAS_EARLYSUSPEND + touch_dev->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + touch_dev->early_suspend.suspend = zinitix_early_suspend; + touch_dev->early_suspend.resume = zinitix_late_resume; + register_early_suspend(&touch_dev->early_suspend); +#endif + + + sema_init(&touch_dev->raw_data_lock, 1); + + misc_touch_dev = touch_dev; + + ret = misc_register(&touch_misc_device); + if (ret) + zinitix_debug_msg("Fail to register touch misc device.\n"); + +#if SEC_TOUCH_INFO_REPORT + //sys/class/misc/touch_misc_fops/.... + sec_touchscreen_dev = device_create(sec_class, NULL, 0, NULL, "sec_touchscreen"); + + if (IS_ERR(sec_touchscreen_dev)) + pr_err("Failed to create device(sec_touchscreen)!\n"); + + if (device_create_file(sec_touchscreen_dev, + &dev_attr_get_touch_raw_data) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_get_touch_raw_data.attr.name); + + if (device_create_file(sec_touchscreen_dev, + &dev_attr_touch_cal_ndata) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_touch_cal_ndata.attr.name); + + if (device_create_file(sec_touchscreen_dev, + &dev_attr_delta) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_delta.attr.name); + + if (device_create_file(sec_touchscreen_dev, + &dev_attr_cal_ncount) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_cal_ncount.attr.name); + + if (device_create_file(sec_touchscreen_dev, + &dev_attr_enter_testmode) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_enter_testmode.attr.name); + + if (device_create_file(sec_touchscreen_dev, + &dev_attr_enter_normalmode) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_enter_normalmode.attr.name); + + if (device_create_file(sec_touchscreen_dev, &dev_attr_count_node) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_count_node.attr.name); + + if (device_create_file(sec_touchscreen_dev, + &dev_attr_chip_info) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_chip_info.attr.name); + + if (device_create_file(sec_touchscreen_dev, + &dev_attr_touch_ndata) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_touch_ndata.attr.name); + + sec_touchkey_dev = device_create(sec_class, NULL, 0, NULL, "sec_touchkey"); + if (IS_ERR(sec_touchkey_dev)) + pr_err("Failed to create device(sec_touchkey)!\n"); + + if (device_create_file(sec_touchkey_dev, &dev_attr_tkey_data) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_tkey_data.attr.name); + + if (device_create_file(sec_touchkey_dev, &dev_attr_menu_sensitivity) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_menu_sensitivity.attr.name); + if (device_create_file(sec_touchkey_dev, &dev_attr_back_sensitivity) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_back_sensitivity.attr.name); +#endif + + + return 0; + +err_request_irq: + input_unregister_device(touch_dev->input_dev); +err_input_register_device: + input_free_device(touch_dev->input_dev); +err_kthread_create_failed: +err_input_allocate_device: + kfree(touch_dev); +err_alloc_dev_data: +err_check_functionality: + touch_dev = NULL; + + misc_touch_dev = NULL; + + i2c_set_clientdata(client, touch_dev); + ts_power_control(POWER_OFF); + return -ENODEV; +} + + +static int zinitix_touch_remove(struct i2c_client *client) +{ + struct zinitix_touch_dev *touch_dev = i2c_get_clientdata(client); + if(touch_dev == NULL) return 0; + + zinitix_debug_msg("zinitix_touch_remove+ \r\n"); + down(&touch_dev->work_proceedure_lock); +#if !USE_THREADED_IRQ + if (touch_dev->work_proceedure != TS_NO_WORK) + flush_work(&touch_dev->work); +#endif + touch_dev->work_proceedure = TS_REMOVE_WORK; + + if (touch_dev->use_esd_timer != 0) { + flush_work(&touch_dev->tmr_work); + ts_write_reg(touch_dev->client, + ZINITIX_PERIODICAL_INTERRUPT_INTERVAL, 0); + ts_esd_timer_stop(touch_dev); + zinitix_debug_msg(KERN_INFO " ts_esd_timer_stop\n"); + destroy_workqueue(zinitix_tmr_workqueue); + } + + if (touch_dev->irq) + free_irq(touch_dev->irq, touch_dev); + +#if SEC_TOUCH_INFO_REPORT + //device_remove_file(touch_misc_device.this_device, &dev_attr_get_touch_raw_data); --> remove attr + //..... +#endif + misc_deregister(&touch_misc_device); + + + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&touch_dev->early_suspend); +#endif + +#if !USE_THREADED_IRQ + destroy_workqueue(zinitix_workqueue); +#endif + if (gpio_is_valid(touch_dev->int_gpio_num) != 0) + gpio_free(touch_dev->int_gpio_num); + + input_unregister_device(touch_dev->input_dev); + input_free_device(touch_dev->input_dev); + up(&touch_dev->work_proceedure_lock); + kfree(touch_dev); + + return 0; +} + + +static struct i2c_driver zinitix_touch_driver = { + .probe = zinitix_touch_probe, + .remove = zinitix_touch_remove, + .id_table = zinitix_idtable, + .driver = { + .owner = THIS_MODULE, + .name = ZINITIX_DRIVER_NAME, + .pm = &zinitix_dev_pm_ops, + }, +}; + + +static int __devinit zinitix_touch_init(void) +{ + + m_isp_client = NULL; + return i2c_add_driver(&zinitix_touch_driver); +} + +static void __exit zinitix_touch_exit(void) +{ + i2c_del_driver(&zinitix_touch_driver); +} + +module_init(zinitix_touch_init); +module_exit(zinitix_touch_exit); + +MODULE_DESCRIPTION("zinitix touch-screen device driver using i2c interface"); +MODULE_AUTHOR("sohnet <seonwoong.jang@zinitix.com>"); +MODULE_LICENSE("GPL"); + + |
