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_bt541_ts.c | |
Diffstat (limited to 'drivers/input/touchscreen/zinitix_bt541_ts.c')
| -rw-r--r-- | drivers/input/touchscreen/zinitix_bt541_ts.c | 6284 |
1 files changed, 6284 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/zinitix_bt541_ts.c b/drivers/input/touchscreen/zinitix_bt541_ts.c new file mode 100644 index 00000000..eba65108 --- /dev/null +++ b/drivers/input/touchscreen/zinitix_bt541_ts.c @@ -0,0 +1,6284 @@ +/* + * + * Zinitix bt541 touchscreen driver + * + * Copyright (C) 2013 Samsung Electronics Co.Ltd + * + * 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. + * + */ + + +#define TSP_VERBOSE_DEBUG +#define SEC_FACTORY_TEST +#define SUPPORTED_TOUCH_KEY + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/miscdevice.h> +#include <linux/interrupt.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#if defined(CONFIG_PM_RUNTIME) +#include <linux/pm_runtime.h> +#endif +#include <linux/semaphore.h> +#include <linux/timer.h> +#include <linux/workqueue.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/uaccess.h> +#include <linux/regulator/consumer.h> + +#include <linux/input/zinitix_bt541_ts.h> +#include <linux/input/mt.h> +#include <linux/of_gpio.h> +#include <soc/sprd/i2c-sprd.h> +#include <linux/power_supply.h> + +/* added header file */ +/* #define SUPPORTED_USE_DUAL_FW */ +#ifdef SUPPORTED_USE_DUAL_FW +#include "zinitix_bt541_firmware_00.h" +#include "zinitix_bt541_firmware_01.h" +u8 *m_firmware_data; +#else +#include "zinitix_bt541_firmware.h" +#endif + +extern void (*tsp_charger_status_cb)(int); + +#ifdef SUPPORTED_USE_DUAL_FW +#define TSP_TYPE_COUNT 2 +u8 *m_pFirmware[TSP_TYPE_COUNT] = {(u8 *)m_firmware_data_00, (u8 *)m_firmware_data_01,}; +u8 m_FirmwareIdx = 0; +#define CHECK_HWID 1 +static void bt541_firmware_check(void); +#else +#define CHECK_HWID 0 +#endif + +static bool ta_connected =0; +#define ZINITIX_DEBUG 1 +#define ZINITIX_I2C_CHECKSUM 1 +#define TOUCH_BOOSTER 0 +#define NOT_SUPPORTED_TOUCH_DUMMY_KEY +#if TOUCH_BOOSTER +#include <linux/cpufreq.h> +#include <linux/cpufreq_limit.h> +extern int _store_cpu_num_min_limit(unsigned int input); +struct cpufreq_limit_handle *min_handle = NULL; +static const unsigned long touch_cpufreq_lock = 1200000; +#endif + +#ifdef SUPPORTED_PALM_TOUCH +#define TOUCH_POINT_MODE 2 +#else +#define TOUCH_POINT_MODE 0 +#endif + +#define MAX_SUPPORTED_FINGER_NUM 2 /* max 10 */ + +#ifdef SUPPORTED_TOUCH_KEY +#ifdef NOT_SUPPORTED_TOUCH_DUMMY_KEY +#define MAX_SUPPORTED_BUTTON_NUM 2 /* max 8 */ +#define SUPPORTED_BUTTON_NUM 2 +#else +#define MAX_SUPPORTED_BUTTON_NUM 2 /* max 8 */ +#define SUPPORTED_BUTTON_NUM 2 +#endif +#endif + +/* Upgrade Method*/ +#define TOUCH_ONESHOT_UPGRADE 1 +/* if you use isp mode, you must add i2c device : + name = "zinitix_isp" , addr 0x50*/ + +/* resolution offset */ +#define ABS_PT_OFFSET (0) + +#define TOUCH_FORCE_UPGRADE 1 +#define USE_CHECKSUM 1 + +#define CHIP_OFF_DELAY 50 /*ms*/ +#define CHIP_ON_DELAY 20 /*15*/ /*ms*/ +#define FIRMWARE_ON_DELAY 60 /*40*/ /*ms*/ + +#define DELAY_FOR_SIGNAL_DELAY 30 /*us*/ +#define DELAY_FOR_TRANSCATION 50 +#define DELAY_FOR_POST_TRANSCATION 10 + +/* PMIC Regulator based supply to TSP */ +#define TSP_REGULATOR_SUPPLY 1 +/* gpio controlled LDO based supply to TSP */ +#define TSP_LDO_SUPPLY 0 + +enum power_control { + POWER_OFF, + POWER_ON, + POWER_ON_SEQUENCE, +}; + +/* Key Enum */ +enum key_event { + ICON_BUTTON_UNCHANGE, + ICON_BUTTON_DOWN, + ICON_BUTTON_UP, +}; + +/* ESD Protection */ +/*second : if 0, no use. if you have to use, 3 is recommended*/ +#define ESD_TIMER_INTERVAL 1 +#define SCAN_RATE_HZ 100 +#define CHECK_ESD_TIMER 3 + +/*Test Mode (Monitoring Raw Data) */ +#define MAX_RAW_DATA_SZ 576 /* 32x18 */ +#define MAX_TRAW_DATA_SZ \ + (MAX_RAW_DATA_SZ + 4*MAX_SUPPORTED_FINGER_NUM + 2) +/* preriod raw data interval */ + +#define RAWDATA_DELAY_FOR_HOST 100 + +struct raw_ioctl { + u32 sz; + u32 buf; +}; + +struct reg_ioctl { + u32 addr; + u32 val; +}; + +#define TOUCH_SEC_MODE 48 +#define TOUCH_REF_MODE 10 +#define TOUCH_NORMAL_MODE 5 +#define TOUCH_DELTA_MODE 3 +#define TOUCH_SDND_MODE 6 +#define TOUCH_DND_MODE 11 + +/* Other Things */ +#define INIT_RETRY_CNT 1 +#define I2C_SUCCESS 0 +#define I2C_FAIL 1 + +/*---------------------------------------------------------------------*/ + +/* Register Map*/ +#define BT541_SWRESET_CMD 0x0000 +#define BT541_WAKEUP_CMD 0x0001 + +#define BT541_IDLE_CMD 0x0004 +#define BT541_SLEEP_CMD 0x0005 + +#define BT541_CLEAR_INT_STATUS_CMD 0x0003 +#define BT541_CALIBRATE_CMD 0x0006 +#define BT541_SAVE_STATUS_CMD 0x0007 +#define BT541_SAVE_CALIBRATION_CMD 0x0008 +#define BT541_RECALL_FACTORY_CMD 0x000f + +#define BT541_THRESHOLD 0x0020 + +#define BT541_DEBUG_REG 0x0115 /* 0~7 */ + +#define BT541_TOUCH_MODE 0x0010 +#define BT541_CHIP_REVISION 0x0011 +#define BT541_FIRMWARE_VERSION 0x0012 + +#define BT541_MINOR_FW_VERSION 0x0121 + +#define BT541_VENDOR_ID 0x001C +#define BT541_MODULE_ID 0x001E +#define BT541_HW_ID 0x0014 + +#define BT541_DATA_VERSION_REG 0x0013 +#define BT541_SUPPORTED_FINGER_NUM 0x0015 +#define BT541_EEPROM_INFO 0x0018 +#define BT541_INITIAL_TOUCH_MODE 0x0019 + +#define BT541_TOTAL_NUMBER_OF_X 0x0060 +#define BT541_TOTAL_NUMBER_OF_Y 0x0061 + +#define BT541_DELAY_RAW_FOR_HOST 0x007f + +#define BT541_BUTTON_SUPPORTED_NUM 0x00B0 +#define BT541_BUTTON_SENSITIVITY 0x00B2 +#define BT541_DUMMY_BUTTON_SENSITIVITY 0X00C8 +#define BT541_BTN_WIDTH 0x016d + + +#define BT541_X_RESOLUTION 0x00C0 +#define BT541_Y_RESOLUTION 0x00C1 + +#define BT541_POINT_STATUS_REG 0x0080 +#define BT541_ICON_STATUS_REG 0x00AA + +#define BT541_AFE_FREQUENCY 0x0100 +#define BT541_DND_N_COUNT 0x0122 +#define BT541_DND_U_COUNT 0x0135 +#define BT541_SHIFT_VALUE 0x012B + +#define BT541_RAWDATA_REG 0x0200 + +#define BT541_EEPROM_INFO_REG 0x0018 + +#define BT541_INT_ENABLE_FLAG 0x00f0 +#define BT541_PERIODICAL_INTERRUPT_INTERVAL 0x00f1 + +#define BT541_CHECKSUM_RESULT 0x012c + +#define BT541_INIT_FLASH 0x01d0 +#define BT541_WRITE_FLASH 0x01d1 +#define BT541_READ_FLASH 0x01d2 + +#define ZINITIX_INTERNAL_FLAG_02 0x011e + +#define BT541_OPTIONAL_SETTING 0x0116 + +/* Interrupt & status register flag bit + ------------------------------------------------- + */ +#define BIT_PT_CNT_CHANGE 0 +#define BIT_DOWN 1 +#define BIT_MOVE 2 +#define BIT_UP 3 +#define BIT_PALM 4 +#define BIT_PALM_REJECT 5 +#define RESERVED_0 6 +#define RESERVED_1 7 +#define BIT_WEIGHT_CHANGE 8 +#define BIT_PT_NO_CHANGE 9 +#define BIT_REJECT 10 +#define BIT_PT_EXIST 11 +#define RESERVED_2 12 +#define BIT_MUST_ZERO 13 +#define BIT_DEBUG 14 +#define BIT_ICON_EVENT 15 + +/* button */ +#define BIT_O_ICON0_DOWN 0 +#define BIT_O_ICON1_DOWN 1 +#define BIT_O_ICON2_DOWN 2 +#define BIT_O_ICON3_DOWN 3 +#define BIT_O_ICON4_DOWN 4 +#define BIT_O_ICON5_DOWN 5 +#define BIT_O_ICON6_DOWN 6 +#define BIT_O_ICON7_DOWN 7 + +#define BIT_O_ICON0_UP 8 +#define BIT_O_ICON1_UP 9 +#define BIT_O_ICON2_UP 10 +#define BIT_O_ICON3_UP 11 +#define BIT_O_ICON4_UP 12 +#define BIT_O_ICON5_UP 13 +#define BIT_O_ICON6_UP 14 +#define BIT_O_ICON7_UP 15 + + +#define SUB_BIT_EXIST 0 +#define SUB_BIT_DOWN 1 +#define SUB_BIT_MOVE 2 +#define SUB_BIT_UP 3 +#define SUB_BIT_UPDATE 4 +#define SUB_BIT_WAIT 5 + + +#define zinitix_bit_set(val, n) ((val) &= ~(1<<(n)), (val) |= (1<<(n))) +#define zinitix_bit_clr(val, n) ((val) &= ~(1<<(n))) +#define zinitix_bit_test(val, n) ((val) & (1<<(n))) +#define zinitix_swap_v(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define zinitix_swap_16(s) (((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))) + +/* end header file */ + +#ifdef SEC_FACTORY_TEST +/* Touch Screen */ +#define TSP_CMD_STR_LEN 32 +#define TSP_CMD_RESULT_STR_LEN 512 +#define TSP_CMD_PARAM_NUM 8 +#define TSP_CMD_Y_NUM 18 +#define TSP_CMD_X_NUM 30 +#define TSP_CMD_NODE_NUM (TSP_CMD_Y_NUM * TSP_CMD_X_NUM) + +struct tsp_factory_info { + struct list_head cmd_list_head; + char cmd[TSP_CMD_STR_LEN]; + char cmd_param[TSP_CMD_PARAM_NUM]; + char cmd_result[TSP_CMD_RESULT_STR_LEN]; + char cmd_buff[TSP_CMD_RESULT_STR_LEN]; + struct mutex cmd_lock; + bool cmd_is_running; + u8 cmd_state; +}; + +struct tsp_raw_data { + u16 ref_data[TSP_CMD_NODE_NUM]; + u16 pref_data[TSP_CMD_NODE_NUM]; + /*s16 scantime_data[TSP_CMD_NODE_NUM]; */ + s16 delta_data[TSP_CMD_NODE_NUM]; +}; + +enum { + WAITING = 0, + RUNNING, + OK, + FAIL, + NOT_APPLICABLE, +}; + +struct tsp_cmd { + struct list_head list; + const char *cmd_name; + void (*cmd_func)(void *device_data); +}; + +static void fw_update(void *device_data); +static void get_fw_ver_bin(void *device_data); +static void get_fw_ver_ic(void *device_data); +static void module_off_master(void *device_data); +static void module_on_master(void *device_data); +static void module_off_slave(void *device_data); +static void module_on_slave(void *device_data); +static void get_chip_vendor(void *device_data); +static void get_chip_name(void *device_data); +static void get_threshold(void *device_data); +static void get_x_num(void *device_data); +static void get_y_num(void *device_data); +static void not_support_cmd(void *device_data); + +/* Vendor dependant command */ +#ifdef SUPPORTED_USE_DUAL_FW +static void get_module_vendor(void *device_data); +#endif + +static void get_reference_DND(void *device_data); +/*static void get_reference_RxDND(void *device_data);*/ +static void get_reference_HFDND(void *device_data); +/*static void get_reference_RxHFDND(void *device_data);*/ +/*static void get_tkey_delta(void *device_data);*/ +static void get_reference_V_Diff(void *device_data); +/*static void get_reference_max_V_Diff(void *device_data);*/ +static void get_reference_H_Diff(void * device_data); +/*static void get_reference_max_H_Diff(void * device_data);*/ +/*static void get_max_dnd(void *device_data);*/ +/*static void get_min_dnd(void *device_data);*/ +/*static void get_max_hfdnd(void *device_data);*/ +/*static void get_min_hfdnd(void *device_data);*/ +/*static void get_max_hdiff(void *device_data);*/ +/*static void get_min_hdiff(void *device_data);*/ +/*static void get_max_vdiff(void *device_data);*/ +/*static void get_min_vdiff(void *device_data);*/ +/*static void get_reference(void *device_data);*/ +/*static void get_preference(void *device_data);*/ +/*static void run_preference_read(void *device_data);*/ +static void run_reference_DND(void *device_data); +static void run_reference_HFDND(void *device_data); +static void run_reference_V_Diff(void *device_data); +static void run_reference_H_Diff(void *device_data); +/*static void run_reference_read(void *device_data);*/ +static void hfdnd_spec_adjust(void *device_data); +static void clear_reference_data(void *device_data); +static void run_ref_calibration(void *device_data); + +#define TSP_CMD(name, func) .cmd_name = name, .cmd_func = func +static struct tsp_cmd tsp_cmds[] = { + {TSP_CMD("fw_update", fw_update),}, + {TSP_CMD("get_fw_ver_bin", get_fw_ver_bin),}, + {TSP_CMD("get_fw_ver_ic", get_fw_ver_ic),}, + {TSP_CMD("get_threshold", get_threshold),}, + {TSP_CMD("module_off_master", module_off_master),}, + {TSP_CMD("module_on_master", module_on_master),}, + {TSP_CMD("module_off_slave", module_off_slave),}, + {TSP_CMD("module_on_slave", module_on_slave),}, + {TSP_CMD("get_chip_vendor", get_chip_vendor),}, + {TSP_CMD("get_chip_name", get_chip_name),}, + {TSP_CMD("get_x_num", get_x_num),}, + {TSP_CMD("get_y_num", get_y_num),}, + {TSP_CMD("not_support_cmd", not_support_cmd),}, + + /* vendor dependant command */ +#ifdef SUPPORTED_USE_DUAL_FW + {TSP_CMD("get_module_vendor", get_module_vendor),}, +#endif + {TSP_CMD("run_reference_read", run_reference_DND),}, + {TSP_CMD("get_reference", get_reference_DND),}, + {TSP_CMD("run_vdiff_read", run_reference_V_Diff),}, + {TSP_CMD("get_vdiff", get_reference_V_Diff),}, + {TSP_CMD("run_hdiff_read", run_reference_H_Diff),}, + {TSP_CMD("get_hdiff", get_reference_H_Diff),}, + {TSP_CMD("run_highfreq_read", run_reference_HFDND),}, + {TSP_CMD("get_highfreq", get_reference_HFDND),}, + {TSP_CMD("hfdnd_spec_adjust", hfdnd_spec_adjust),}, + {TSP_CMD("clear_reference_data", clear_reference_data),}, + {TSP_CMD("run_ref_calibration", run_ref_calibration),}, + /* + {TSP_CMD("get_reference_DND", get_reference_DND),}, + {TSP_CMD("get_reference_RxDND", get_reference_RxDND),}, + {TSP_CMD("get_reference_HFDND", get_reference_HFDND),}, + {TSP_CMD("get_reference_RxHFDND", get_reference_RxHFDND),}, + {TSP_CMD("get_reference_V_DIFF", get_reference_V_Diff),}, + {TSP_CMD("get_reference_max_V_DIFF", get_reference_max_V_Diff),}, + {TSP_CMD("get_reference_H_DIFF", get_reference_H_Diff),}, + {TSP_CMD("get_reference_max_H_DIFF", get_reference_max_H_Diff),}, + {TSP_CMD("run_reference_HFDND", run_reference_HFDND),}, + {TSP_CMD("run_reference_DND", run_reference_DND),}, + {TSP_CMD("run_reference_diff", run_reference_PDiff),}, + {TSP_CMD("get_max_dnd", get_max_dnd),}, + {TSP_CMD("get_min_dnd", get_min_dnd),}, + {TSP_CMD("get_max_hfdnd", get_max_hfdnd),}, + {TSP_CMD("get_min_hfdnd", get_min_hfdnd),}, + {TSP_CMD("get_max_hdiff", get_max_hdiff),}, + {TSP_CMD("get_min_hdiff", get_min_hdiff),}, + {TSP_CMD("get_max_vdiff", get_max_vdiff),}, + {TSP_CMD("get_min_vdiff", get_min_vdiff),}, + {TSP_CMD("get_tkey_delta", get_tkey_delta),}, + {TSP_CMD("run_reference_read", run_reference_read),}, + {TSP_CMD("get_reference", get_reference),}, + {TSP_CMD("run_dnd_read", run_preference_read),}, + {TSP_CMD("get_dnd", get_preference),}, + */ +}; +#if 0 +#ifdef SUPPORTED_TOUCH_KEY +/* Touch Key */ +static ssize_t touchkey_threshold(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t touch_sensitivity(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t touchkey_back(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t touchkey_recent(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t autocal_stat(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t touchkey_raw_back(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t touchkey_raw_menu(struct device *dev, + struct device_attribute *attr, char *buf); +/*static ssize_t touchkey_idac_back(struct device *dev, + struct device_attribute *attr, char *buf); + static ssize_t touchkey_idac_menu(struct device *dev, + struct device_attribute *attr, char *buf); + */ +#endif +#endif +#endif + +#define TSP_NORMAL_EVENT_MSG 1 +static int m_ts_debug_mode = ZINITIX_DEBUG; + +#if ESD_TIMER_INTERVAL +static struct workqueue_struct *esd_tmr_workqueue; +#endif + +struct coord { + u16 x; + u16 y; + u8 width; + u8 sub_status; +#if (TOUCH_POINT_MODE == 2) + u8 minor_width; + u8 angle; +#endif +}; + +struct point_info { + u16 status; +#if (TOUCH_POINT_MODE == 1) + u16 event_flag; +#else + u8 finger_cnt; + u8 time_stamp; +#endif + struct coord coord[MAX_SUPPORTED_FINGER_NUM]; +}; + +#define TOUCH_V_FLIP 0x01 +#define TOUCH_H_FLIP 0x02 +#define TOUCH_XY_SWAP 0x04 + +/*Test Mode (Monitoring Raw Data) */ +/*---------------------------------------------------------------------*/ +/* GF1 */ +/*---------------------------------------------------------------------*/ +#define PDIFF_DEBUG 1 + +#define TSP_INIT_TEST_RATIO 100 + +#define SEC_DND_N_COUNT 16 +#define SEC_DND_U_COUNT 20 +#define SEC_DND_FREQUENCY 138 /*300khz*/ + +#define SEC_HFDND_N_COUNT 16 +#define SEC_HFDND_U_COUNT 20 +#define SEC_HFDND_FREQUENCY 27 /*300khz*/ +/*---------------------------------------------------------------------*/ +struct capa_info { + u16 vendor_id; + u16 ic_revision; + u16 fw_version; + u16 fw_minor_version; + u16 reg_data_version; + u16 threshold; + u16 key_threshold; + u16 dummy_threshold; + u32 ic_fw_size; + u32 MaxX; + u32 MaxY; + u32 MinX; + u32 MinY; + u8 gesture_support; + u16 multi_fingers; + u16 button_num; + u16 ic_int_mask; + u16 x_node_num; + u16 y_node_num; + u16 total_node_num; + u16 hw_id; + u16 module_id; + u16 afe_frequency; + u16 shift_value; + u16 N_cnt; + u16 U_cnt; + u16 i2s_checksum; +}; + +enum work_state { + NOTHING = 0, + NORMAL, + ESD_TIMER, + EALRY_SUSPEND, + SUSPEND, + RESUME, + LATE_RESUME, + UPGRADE, + REMOVE, + SET_MODE, + HW_CALIBRAION, + RAW_DATA, + PROBE, +}; + +enum { + BUILT_IN = 0, + UMS, + REQ_FW, +}; + +struct bt541_ts_info; + +struct bt541_ts_platform_data { + u32 gpio_int; + u32 gpio_ldo_en; + int (*tsp_power)(struct bt541_ts_info *info, int on); + u32 x_resolution; + u32 y_resolution; + u32 page_size; + u32 orientation; + u32 tsp_supply_type; +}; + +struct bt541_ts_info { + struct i2c_client *client; + struct input_dev *input_dev; + struct bt541_ts_platform_data *pdata; + char phys[32]; + /*struct task_struct *task;*/ + /*wait_queue_head_t wait;*/ + /*struct semaphore update_lock;*/ + /*u32 i2c_dev_addr;*/ + struct capa_info cap_info; + struct point_info touch_info; + struct point_info reported_touch_info; + u16 icon_event_reg; + u16 prev_icon_event; + /*u16 event_type;*/ + int irq; + u8 button[MAX_SUPPORTED_BUTTON_NUM]; + u8 work_state; + struct semaphore work_lock; + /*u16 debug_reg[8];*/ /* for debug */ +#if ESD_TIMER_INTERVAL + struct work_struct tmr_work; + struct timer_list esd_timeout_tmr; + struct timer_list *p_esd_timeout_tmr; + spinlock_t lock; +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct semaphore raw_data_lock; + u16 touch_mode; + s16 cur_data[MAX_TRAW_DATA_SZ]; + u8 update; +#ifdef SEC_FACTORY_TEST + struct tsp_factory_info *factory_info; + struct tsp_raw_data *raw_data; + + s16 ref_data[MAX_RAW_DATA_SZ]; + s16 normal_data[MAX_RAW_DATA_SZ]; + s16 delta_data[MAX_RAW_DATA_SZ]; + u16 pdnd_data[MAX_RAW_DATA_SZ]; + u16 hfdnd_data[MAX_RAW_DATA_SZ]; + u16 PDND2_N_cnt; + u16 PDND2_u_cnt; + u16 PDND2_freq; + + s16 ref_btn_option; + + s16 dnd_max_x; + s16 dnd_max_y; + s16 dnd_max_val; + s16 dnd_real_max_x; + s16 dnd_real_max_y; + s16 dnd_real_max_val; + s16 dnd_min_x; + s16 dnd_min_y; + s16 dnd_min_val; + s16 dnd_real_min_x; + s16 dnd_real_min_y; + s16 dnd_real_min_val; + s16 dnd_node_num; + + s16 hfdnd_max_x; + s16 hfdnd_max_y; + s16 hfdnd_max_val; + s16 hfdnd_real_max_x; + s16 hfdnd_real_max_y; + s16 hfdnd_real_max_val; + s16 hfdnd_min_x; + s16 hfdnd_min_y; + s16 hfdnd_min_val; + s16 hfdnd_real_min_x; + s16 hfdnd_real_min_y; + s16 hfdnd_real_min_val; + s16 hfdnd_node_num; + + s16 hdiff_max_x; + s16 hdiff_max_y; + s16 hdiff_max_val; + s16 hdiff_min_x; + s16 hdiff_min_y; + s16 hdiff_min_val; + s16 hdiff_diff_val; + s16 hdiff_node_num; + + s16 vdiff_max_x; + s16 vdiff_max_y; + s16 vdiff_max_val; + s16 vdiff_min_x; + s16 vdiff_min_y; + s16 vdiff_min_val; + s16 vdiff_diff_val; + s16 vdiff_node_num; + + bool dnd_done; + bool hfdnd_done; + +#endif +#if TOUCH_BOOSTER + u8 finger_cnt; +#endif +}; +/* Dummy touchkey code */ +#define KEY_DUMMY_HOME1 249 +#define KEY_DUMMY_HOME2 250 +#define KEY_DUMMY_MENU 251 +#define KEY_DUMMY_HOME 252 +#define KEY_DUMMY_BACK 253 +/*<= you must set key button mapping*/ +#ifdef NOT_SUPPORTED_TOUCH_DUMMY_KEY +u32 BUTTON_MAPPING_KEY[MAX_SUPPORTED_BUTTON_NUM] = { + KEY_APPSELECT, KEY_BACK}; +#else +u32 BUTTON_MAPPING_KEY[MAX_SUPPORTED_BUTTON_NUM] = { + KEY_DUMMY_MENU, KEY_RECENT,// KEY_DUMMY_HOME1, + /*KEY_DUMMY_HOME2,*/ KEY_BACK, KEY_DUMMY_BACK}; +#endif + + +static int cal_mode; +static int get_boot_mode(char *str) +{ + + get_option(&str, &cal_mode); + printk("get_boot_mode, uart_mode : %d\n", cal_mode); + return 1; +} +__setup("calmode=",get_boot_mode); +/* define i2c sub functions*/ +static inline s32 read_data(struct i2c_client *client, + u16 reg, u8 *values, u16 length) +{ + s32 ret; + int count = 0; +retry: + /* select register*/ + ret = i2c_master_send(client , (u8 *)® , 2); + if (ret < 0) { + mdelay(1); + + if (++count < 8) + goto retry; + + 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 write_data(struct i2c_client *client, + u16 reg, u8 *values, u16 length) +{ + s32 ret; + int count = 0; + u8 pkt[10]; /* max packet */ + pkt[0] = (reg) & 0xff; /* reg addr */ + pkt[1] = (reg >> 8)&0xff; + memcpy((u8 *)&pkt[2], values, length); + +retry: + ret = i2c_master_send(client , pkt , length + 2); + if (ret < 0) { + mdelay(1); + + if (++count < 8) + goto retry; + printk(KERN_INFO "%s, count = %d\n", __func__, count); + + return ret; + } + + udelay(DELAY_FOR_POST_TRANSCATION); + return length; +} + +static inline s32 write_reg(struct i2c_client *client, u16 reg, u16 value) +{ + if (write_data(client, reg, (u8 *)&value, 2) < 0) + return I2C_FAIL; + + return I2C_SUCCESS; +} + +static inline s32 write_cmd(struct i2c_client *client, u16 reg) +{ + s32 ret; + int count = 0; + +retry: + ret = i2c_master_send(client , (u8 *)® , 2); + if (ret < 0) { + mdelay(1); + + if (++count < 8) + goto retry; + + return ret; + } + + udelay(DELAY_FOR_POST_TRANSCATION); + return I2C_SUCCESS; +} + +static inline s32 read_raw_data(struct i2c_client *client, + u16 reg, u8 *values, u16 length) +{ + s32 ret; + int count = 0; + +retry: + /* select register */ + ret = i2c_master_send(client , (u8 *)® , 2); + if (ret < 0) { + mdelay(1); + + if (++count < 8) + goto retry; + + 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 read_firmware_data(struct i2c_client *client, + u16 addr, u8 *values, u16 length) +{ + s32 ret; + /* select register*/ + + ret = i2c_master_send(client , (u8 *)&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; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void bt541_ts_early_suspend(struct early_suspend *h); +static void bt541_ts_late_resume(struct early_suspend *h); +#endif + +static bool bt541_power_control(struct bt541_ts_info *info, u8 ctl); +static int bt541_power(struct bt541_ts_info *info, int on); + +static bool init_touch(struct bt541_ts_info *info, bool fw_oneshot_upgrade); +static bool mini_init_touch(struct bt541_ts_info *info); +static void clear_report_data(struct bt541_ts_info *info); +#if ESD_TIMER_INTERVAL +static void esd_timer_start(u16 sec, struct bt541_ts_info *info); +static void esd_timer_stop(struct bt541_ts_info *info); +static void esd_timer_init(struct bt541_ts_info *info); +static void esd_timeout_handler(unsigned long data); +#endif + +static long ts_misc_fops_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); +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, + .unlocked_ioctl = ts_misc_fops_ioctl, + .compat_ioctl = ts_misc_fops_ioctl, +}; + +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 bt541_ts_info *misc_info; + +#ifdef SUPPORTED_USE_DUAL_FW +static void bt541_firmware_check(void) +{ + int i; + u16 newHWID; + + for (i = 0; i < TSP_TYPE_COUNT; i++) { + newHWID = (u16) (m_pFirmware[i][0x57d2] | (m_pFirmware[i][0x57d3]<<8)); + if (misc_info->cap_info.hw_id == newHWID) { + m_FirmwareIdx = i; + break; + } + } + if (i == TSP_TYPE_COUNT) + m_FirmwareIdx = 0; + + m_firmware_data = m_pFirmware[m_FirmwareIdx]; +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&misc_info->client->dev, "touch tsp type = %d, hw_id = %d\n", m_FirmwareIdx, misc_info->cap_info.hw_id); +#endif +} +#endif + +static u16 m_optional_mode = 0; +static u16 m_prev_optional_mode = 0; +static void bt541_set_optional_mode(struct bt541_ts_info *info, bool force) +{ + if (m_prev_optional_mode == m_optional_mode && !force) + return; + + if (write_reg(info->client, BT541_OPTIONAL_SETTING, m_optional_mode) == I2C_SUCCESS) { + m_prev_optional_mode = m_optional_mode; + dev_info(&misc_info->client->dev, "TA setting changed to %d\n", + m_optional_mode&0x1); + } +} +static void bt541_set_ta_status(struct bt541_ts_info *info) +{ + if (ta_connected) + zinitix_bit_set(m_optional_mode, 0); + else + zinitix_bit_clr(m_optional_mode, 0); +} + +void tsp_charger_enable(int status) +{ + if (status == POWER_SUPPLY_TYPE_BATTERY || + status == POWER_SUPPLY_TYPE_UNKNOWN) + status = 0; + else + status = 1; + + if (status) + ta_connected = true; + else + ta_connected = false; + + bt541_set_ta_status(misc_info); + + dev_info(&misc_info->client->dev, "TA %s\n", + status ? "connected" : "disconnected"); +} +EXPORT_SYMBOL(tsp_charger_enable); + +static bool get_raw_data(struct bt541_ts_info *info, u8 *buff, int skip_cnt) +{ + struct i2c_client *client = info->client; + struct bt541_ts_platform_data *pdata = info->pdata; + u32 total_node = info->cap_info.total_node_num; + u32 sz; + int i; + + disable_irq(info->irq); + + down(&info->work_lock); + if (info->work_state != NOTHING) { + printk(KERN_INFO "other process occupied.. (%d)\n", info->work_state); + enable_irq(info->irq); + up(&info->work_lock); + return false; + } + + info->work_state = RAW_DATA; + + for (i = 0; i < skip_cnt; i++) { + while (gpio_get_value(pdata->gpio_int)) + msleep(1); + + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + msleep(1); + } + + zinitix_debug_msg("read raw data\r\n"); + sz = total_node * 2; + + while (gpio_get_value(pdata->gpio_int)) + msleep(1); + + if (read_raw_data(client, BT541_RAWDATA_REG, (char *)buff, sz) < 0) { + zinitix_printk("error : read zinitix tc raw data\n"); + info->work_state = NOTHING; + enable_irq(info->irq); + up(&info->work_lock); + return false; + } + + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + info->work_state = NOTHING; + enable_irq(info->irq); + up(&info->work_lock); + + return true; +} + +static bool ts_get_raw_data(struct bt541_ts_info *info) +{ + struct i2c_client *client = info->client; + u32 total_node = info->cap_info.total_node_num; + u32 sz; + + if (down_trylock(&info->raw_data_lock)) { + dev_err(&client->dev, "Failed to occupy sema\n"); + info->touch_info.status = 0; + return true; + } + + sz = total_node * 2 + sizeof(struct point_info); + + if (read_raw_data(info->client, BT541_RAWDATA_REG, + (char *)info->cur_data, sz) < 0) { + dev_err(&client->dev, "Failed to read raw data\n"); + up(&info->raw_data_lock); + return false; + } + + info->update = 1; + memcpy((u8 *)(&info->touch_info), + (u8 *)&info->cur_data[total_node], + sizeof(struct point_info)); + up(&info->raw_data_lock); + + return true; +} + +#if ZINITIX_I2C_CHECKSUM +#define ZINITIX_I2C_CHECKSUM_WCNT 0x016a +#define ZINITIX_I2C_CHECKSUM_RESULT 0x016c +static bool i2c_checksum(struct bt541_ts_info *info, s16 *pChecksum, u16 wlength) +{ + s16 checksum_result; + s16 checksum_cur; + int i; + + checksum_cur = 0; + for (i = 0; i < wlength; i++) { + checksum_cur += (s16)pChecksum[i]; + } + if (read_data(info->client, + ZINITIX_I2C_CHECKSUM_RESULT, + (u8 *)(&checksum_result), 2) < 0) { + printk(KERN_INFO "error read i2c checksum rsult.-\n"); + return false; + } + if (checksum_cur != checksum_result) { + printk(KERN_INFO "checksum error : %d, %d\n", checksum_cur, checksum_result); + return false; + } + return true; +} + +#endif + +static bool ts_read_coord(struct bt541_ts_info *info) +{ + struct i2c_client *client = info->client; +#if (TOUCH_POINT_MODE == 1) + int i; +#endif + + /* zinitix_debug_msg("ts_read_coord+\r\n"); */ + + /* for Debugging Tool */ + + if (info->touch_mode != TOUCH_POINT_MODE) { + if (info->update == 0) { + if (ts_get_raw_data(info) == false) + return false; + } else { + info->touch_info.status = 0; + } + + dev_err(&client->dev, "status = 0x%04X\n", info->touch_info.status); + + goto out; + } + +#if (TOUCH_POINT_MODE == 1) + memset(&info->touch_info, + 0x0, sizeof(struct point_info)); + +#if ZINITIX_I2C_CHECKSUM + if (info->cap_info.i2s_checksum) + if ((write_reg(info->client, ZINITIX_I2C_CHECKSUM_WCNT, 2)) != I2C_SUCCESS) + return false; + +#endif + if (read_data(info->client, BT541_POINT_STATUS_REG, (u8 *)(&info->touch_info), 4) < 0) { + dev_err(&client->dev, "%s: Failed to read point info\n", __func__); + + return false; + } + +#if ZINITIX_I2C_CHECKSUM + if (info->cap_info.i2s_checksum) + if (i2c_checksum(info, (s16 *)(&info->touch_info), 2) == false) + return false; +#endif + dev_info(&client->dev, "status reg = 0x%x , event_flag = 0x%04x\n", + info->touch_info.status, info->touch_info.event_flag); + + bt541_set_optional_mode(info, false); + if (info->touch_info.event_flag == 0) + goto out; + +#if ZINITIX_I2C_CHECKSUM + if (info->cap_info.i2s_checksum) + if ((write_reg(info->client, ZINITIX_I2C_CHECKSUM_WCNT, sizeof(struct point_info)/2)) != I2C_SUCCESS) + return false; +#endif + for (i = 0; i < info->cap_info.multi_fingers; i++) { + if (zinitix_bit_test(info->touch_info.event_flag, i)) { + udelay(20); + + if (read_data(info->client, BT541_POINT_STATUS_REG + 2 + ( i * 4), + (u8 *)(&info->touch_info.coord[i]), + sizeof(struct coord)) < 0) { + dev_err(&client->dev, "Failed to read point info\n"); + + return false; + } +#if ZINITIX_I2C_CHECKSUM + if (info->cap_info.i2s_checksum) + if (i2c_checksum(info, (s16 *)(&info->touch_info.coord[i]), sizeof(struct point_info)/2) == false) + return false; +#endif + } + } + +#else +#if ZINITIX_I2C_CHECKSUM + if (info->cap_info.i2s_checksum) + if (write_reg(info->client, + ZINITIX_I2C_CHECKSUM_WCNT, + (sizeof(struct point_info)/2)) != I2C_SUCCESS) { + dev_err(&client->dev, "error write checksum wcnt.-\n"); + return false; + } +#endif + if (read_data(info->client, BT541_POINT_STATUS_REG, + (u8 *)(&info->touch_info), sizeof(struct point_info)) < 0) { + dev_err(&client->dev, "Failed to read point info\n"); + + return false; + } +#if ZINITIX_I2C_CHECKSUM + if (info->cap_info.i2s_checksum) + if (i2c_checksum(info, (s16 *)(&info->touch_info), sizeof(struct point_info)/2) == false) + return false; +#endif + + bt541_set_optional_mode(info, false); + +#endif + +out: + /* error */ + if (zinitix_bit_test(info->touch_info.status, BIT_MUST_ZERO)) { + dev_err(&client->dev, "Invalid must zero bit(%04x)\n", + info->touch_info.status); + + return false; + } + + write_cmd(info->client, BT541_CLEAR_INT_STATUS_CMD); + + return true; +} + +#if ESD_TIMER_INTERVAL +static void esd_timeout_handler(unsigned long data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)data; + + info->p_esd_timeout_tmr = NULL; + queue_work(esd_tmr_workqueue, &info->tmr_work); +} + +static void esd_timer_start(u16 sec, struct bt541_ts_info *info) +{ + unsigned long flags; + spin_lock_irqsave(&info->lock,flags); + if (info->p_esd_timeout_tmr != NULL) +#ifdef CONFIG_SMP + del_singleshot_timer_sync(info->p_esd_timeout_tmr); +#else + del_timer(info->p_esd_timeout_tmr); +#endif + info->p_esd_timeout_tmr = NULL; + init_timer(&(info->esd_timeout_tmr)); + info->esd_timeout_tmr.data = (unsigned long)(info); + info->esd_timeout_tmr.function = esd_timeout_handler; + info->esd_timeout_tmr.expires = jiffies + (HZ * sec); + info->p_esd_timeout_tmr = &info->esd_timeout_tmr; + add_timer(&info->esd_timeout_tmr); + spin_unlock_irqrestore(&info->lock, flags); +} + +static void esd_timer_stop(struct bt541_ts_info *info) +{ + unsigned long flags; + spin_lock_irqsave(&info->lock,flags); + if (info->p_esd_timeout_tmr) +#ifdef CONFIG_SMP + del_singleshot_timer_sync(info->p_esd_timeout_tmr); +#else + del_timer(info->p_esd_timeout_tmr); +#endif + + info->p_esd_timeout_tmr = NULL; + spin_unlock_irqrestore(&info->lock, flags); +} + +static void esd_timer_init(struct bt541_ts_info *info) +{ + unsigned long flags; + spin_lock_irqsave(&info->lock,flags); + init_timer(&(info->esd_timeout_tmr)); + info->esd_timeout_tmr.data = (unsigned long)(info); + info->esd_timeout_tmr.function = esd_timeout_handler; + info->p_esd_timeout_tmr = NULL; + spin_unlock_irqrestore(&info->lock, flags); +} + +static void ts_tmr_work(struct work_struct *work) +{ + struct bt541_ts_info *info = + container_of(work, struct bt541_ts_info, tmr_work); + struct i2c_client *client = info->client; + +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "tmr queue work ++\n"); +#endif + + if (down_trylock(&info->work_lock)) { + dev_err(&client->dev, "%s: Failed to occupy work lock\n", __func__); + esd_timer_start(CHECK_ESD_TIMER, info); + + return; + } + + if (info->work_state != NOTHING) { + dev_info(&client->dev, "%s: Other process occupied (%d)\n", + __func__, info->work_state); + up(&info->work_lock); + + return; + } + info->work_state = ESD_TIMER; + + disable_irq(info->irq); + bt541_power_control(info, POWER_OFF); + bt541_power_control(info, POWER_ON_SEQUENCE); + + clear_report_data(info); + if (mini_init_touch(info) == false) + goto fail_time_out_init; + + info->work_state = NOTHING; + enable_irq(info->irq); + up(&info->work_lock); +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "tmr queue work--\n"); +#endif + + return; +fail_time_out_init: + dev_err(&client->dev, "%s: Failed to restart\n", __func__); + esd_timer_start(CHECK_ESD_TIMER, info); + info->work_state = NOTHING; + enable_irq(info->irq); + up(&info->work_lock); + + return; +} +#endif + +static bool bt541_power_sequence(struct bt541_ts_info *info) +{ + struct i2c_client *client = info->client; + int retry = 0; + u16 chip_code; + +retry_power_sequence: + if (write_reg(client, 0xc000, 0x0001) != I2C_SUCCESS) { + dev_err(&client->dev, "Failed to send power sequence(vendor cmd enable)\n"); + goto fail_power_sequence; + } + udelay(10); + + if (read_data(client, 0xcc00, (u8 *)&chip_code, 2) < 0) { + dev_err(&client->dev, "Failed to read chip code\n"); + goto fail_power_sequence; + } + + dev_info(&client->dev, "%s: chip code = 0x%x\n", __func__, chip_code); + udelay(10); + + if (write_cmd(client, 0xc004) != I2C_SUCCESS) { + dev_err(&client->dev, "Failed to send power sequence(intn clear)\n"); + goto fail_power_sequence; + } + udelay(10); + + if (write_reg(client, 0xc002, 0x0001) != I2C_SUCCESS) { + dev_err(&client->dev, "Failed to send power sequence(nvm init)\n"); + goto fail_power_sequence; + } + mdelay(2); + + if (write_reg(client, 0xc001, 0x0001) != I2C_SUCCESS) { + dev_err(&client->dev, "Failed to send power sequence(program start)\n"); + goto fail_power_sequence; + } + msleep(FIRMWARE_ON_DELAY); /* wait for checksum cal */ + + return true; + +fail_power_sequence: + if (retry++ < 3) { + msleep(CHIP_ON_DELAY); + dev_info(&client->dev, "retry = %d\n", retry); + goto retry_power_sequence; + } + + dev_err(&client->dev, "Failed to send power sequence\n"); + return false; +} + +static struct regulator *touch_regulator; +static int bt541_power(struct bt541_ts_info *info, int on) +{ + int ret = 0; + static u8 is_power_on; + if (touch_regulator == NULL) { + touch_regulator = regulator_get(&info->client->dev, "vddsim2"); + if (IS_ERR(touch_regulator)) { + touch_regulator = NULL; + pr_info("[TSP]: %s: get touch_regulator error\n", + __func__); + return -EIO; + } + } + if (on == 0) { + if (is_power_on) { + is_power_on = 0; + ret = regulator_disable(touch_regulator); + if (ret) { + is_power_on = 1; + pr_err("[TSP]: %s: touch_regulator disable " \ + "failed (%d)\n", __func__, ret); + return -EIO; + } + mdelay(CHIP_OFF_DELAY); + } + } else { + if (!is_power_on) { + is_power_on = 1; + regulator_set_voltage(touch_regulator, 3000000, 3000000); + ret = regulator_enable(touch_regulator); + if (ret) { + is_power_on = 0; + pr_err("[TSP]: %s: touch_regulator enable "\ + "failed (%d)\n", __func__, ret); + return -EIO; + } + } + } + pr_info("[TSP]: %s, expected power[%d], actural power[%d]\n", + __func__, on, is_power_on); + return 0; +} +static bool bt541_power_control(struct bt541_ts_info *info, u8 ctl) +{ + int ret=0; + pr_info("[TSP] %s, %d\n", __func__, ctl); + + if (info->pdata->tsp_supply_type == TSP_REGULATOR_SUPPLY) { + ret = info->pdata->tsp_power(info, ctl); + if (ret) + return false; + + if (ctl == POWER_ON_SEQUENCE) { + msleep(CHIP_ON_DELAY); + return bt541_power_sequence(info); + } + } + else + { + if (ctl == POWER_OFF) { + gpio_direction_output(info->pdata->gpio_ldo_en, 0); + msleep(CHIP_OFF_DELAY); + } else { + gpio_direction_output(info->pdata->gpio_ldo_en, 1); + + /* zxt power on sequence */ + if (ctl == POWER_ON_SEQUENCE) { + msleep(CHIP_ON_DELAY); + return bt541_power_sequence(info); + } + } + } + return true; +} + +#if TOUCH_ONESHOT_UPGRADE +static bool ts_check_need_upgrade(struct bt541_ts_info *info, + u16 cur_version, u16 cur_minor_version, u16 cur_reg_version, u16 cur_hw_id) +{ + u16 new_version; + u16 new_minor_version; + u16 new_reg_version; + /* u16 new_chip_code;*/ +#if CHECK_HWID + u16 new_hw_id; +#endif + new_version = (u16) (m_firmware_data[52] | (m_firmware_data[53]<<8)); + new_minor_version = (u16) (m_firmware_data[56] | (m_firmware_data[57]<<8)); + new_reg_version = (u16) (m_firmware_data[60] | (m_firmware_data[61]<<8)); + /* new_chip_code = (u16) (m_firmware_data[64] | (m_firmware_data[65]<<8));*/ + +#if CHECK_HWID + new_hw_id = (u16)(m_firmware_data[0x7528] | (m_firmware_data[0x7529]<<8)); + dev_info(&info->client->dev, "cur HW_ID = 0x%x, new HW_ID = 0x%x\n", + cur_hw_id, new_hw_id); +#endif + + dev_info(&info->client->dev, "cur version = 0x%x, new version = 0x%x\n", + cur_version, new_version); + + dev_info(&info->client->dev, "cur minor version = 0x%x, new minor version = 0x%x\n", + cur_minor_version, new_minor_version); + dev_info(&info->client->dev, "cur reg data version = 0x%x, new reg data version = 0x%x\n", + cur_reg_version, new_reg_version); + + if (cal_mode) { + dev_info(&info->client->dev, "didn't update TSP F/W!! in CAL MODE\n"); + return false; + } + + if (cur_version > 0xFF) + return true; + if (cur_version < new_version) + return true; + else if (cur_version > new_version) + return false; +#if CHECK_HWID + if (cur_hw_id != new_hw_id) + return true; +#endif + if (cur_minor_version < new_minor_version) + return true; + else if (cur_minor_version > new_minor_version) + return false; + if (cur_reg_version < new_reg_version) + return true; + + return false; +} +#endif + +#define TC_SECTOR_SZ 8 + +#ifdef SUPPORTED_USE_DUAL_FW +static void ts_check_hwid_in_fatal_state(struct bt541_ts_info *info) +{ + /*u16 flash_addr;*/ + u8 check_data[80]; + int i; + u16 hw_id0, hw_id1_1, hw_id1_2; + int retry = 0; +retry_fatal: + bt541_power_control(info, POWER_OFF); + bt541_power_control(info, POWER_ON); + mdelay(10); + if (write_reg(info->client, 0xc000, 0x0001) != I2C_SUCCESS) { + dev_err(&info->client->dev, "power sequence error (vendor cmd enable)\n"); + goto fail_check_hwid; + } + udelay(10); + if (write_cmd(info->client, 0xc004) != I2C_SUCCESS) { + dev_err(&info->client->dev, "power sequence error (intn clear)\n"); + goto fail_check_hwid; + } + udelay(10); + if (write_reg(info->client, 0xc002, 0x0001) != I2C_SUCCESS) { + dev_err(&info->client->dev, "power sequence error (nvm init)\n"); + goto fail_check_hwid; + } + /*dev_err(&info->client->dev, "init flash\n");*/ + mdelay(5); + if (write_reg(info->client, 0xc003, 0x0000) != I2C_SUCCESS) { + dev_err(&info->client->dev, "fail to write nvm vpp on\n"); + goto fail_check_hwid; + } + if (write_reg(info->client, 0xc104, 0x0000) != I2C_SUCCESS) { + dev_err(&info->client->dev, "fail to write nvm wp disable\n"); + goto fail_check_hwid; + } + /*dev_err(&info->client->dev, "init flash\n");*/ + if (write_cmd(info->client, BT541_INIT_FLASH) != I2C_SUCCESS) { + dev_err(&info->client->dev, "failed to init flash\n"); + goto fail_check_hwid; + } + /*dev_err(&info->client->dev, "read firmware data\n");*/ + for (i = 0; i < 80; i += TC_SECTOR_SZ) { + if (read_firmware_data(info->client, + BT541_READ_FLASH, + (u8 *)&check_data[i], TC_SECTOR_SZ) < 0) { + dev_err(&info->client->dev, "error : read zinitix tc firmare\n"); + goto fail_check_hwid; + } + } + hw_id0 = check_data[48] + check_data[49]*256; + hw_id1_1 = check_data[70]; + hw_id1_2 = check_data[71]; + + /*dev_err(&info->client->dev, "eeprom hw id = %d, %d, %d\n", hw_id0, hw_id1_1, hw_id1_2);*/ + + if (hw_id1_1 == hw_id1_2 && hw_id0 != hw_id1_1) + info->cap_info.hw_id = hw_id1_1; + else + info->cap_info.hw_id = hw_id0; + + dev_err(&info->client->dev, "hw id = %d\n", info->cap_info.hw_id); + mdelay(5); + return; + +fail_check_hwid: + if (retry++ < 3) + goto retry_fatal; + dev_err(&info->client->dev, "fail to check hw id\n"); + mdelay(5); +} +#endif + +static u8 ts_upgrade_firmware(struct bt541_ts_info *info, + const u8 *firmware_data, u32 size) +{ + struct i2c_client *client = info->client; + u16 flash_addr; + u16 reg_val; + u8 *verify_data; + int retry_cnt = 0; + int i; + int page_sz = 0; + u16 chip_code; + + verify_data = kzalloc(size, GFP_KERNEL); + if (verify_data == NULL) { + zinitix_printk(KERN_ERR "cannot alloc verify buffer\n"); + return false; + } +#ifdef SUPPORTED_USE_DUAL_FW + if (read_data(client, BT541_MODULE_ID, (u8 *)&cap->module_id, 2) < 0) + dev_err(&client->dev, "Failed to read Modul ID\n"); +#endif +retry_upgrade: + bt541_power_control(info, POWER_OFF); + bt541_power_control(info, POWER_ON); + mdelay(10); + + if (write_reg(client, 0xc000, 0x0001) != I2C_SUCCESS) { + zinitix_printk("power sequence error (vendor cmd enable)\n"); + goto fail_upgrade; + } + + udelay(10); + + if (read_data(client, 0xcc00, (u8 *)&chip_code, 2) < 0) { + zinitix_printk("failed to read chip code\n"); + goto fail_upgrade; + } + + zinitix_printk("chip code = 0x%x\n", chip_code); + page_sz = 128; + udelay(10); + + if (write_cmd(client, 0xc004) != I2C_SUCCESS) { + zinitix_printk("power sequence error (intn clear)\n"); + goto fail_upgrade; + } + + udelay(10); + + if (write_reg(client, 0xc002, 0x0001) != I2C_SUCCESS) { + zinitix_printk("power sequence error (nvm init)\n"); + goto fail_upgrade; + } + + mdelay(5); + + zinitix_printk(KERN_INFO "init flash\n"); + + if (write_reg(client, 0xc003, 0x0001) != I2C_SUCCESS) { + zinitix_printk("failed to write nvm vpp on\n"); + goto fail_upgrade; + } + + if (write_reg(client, 0xc104, 0x0001) != I2C_SUCCESS) { + zinitix_printk("failed to write nvm wp disable\n"); + goto fail_upgrade; + } + + if (write_cmd(client, BT541_INIT_FLASH) != I2C_SUCCESS) { + zinitix_printk(KERN_INFO "failed to init flash\n"); + goto fail_upgrade; + } + + zinitix_printk(KERN_INFO "writing firmware data\n"); + for (flash_addr = 0; flash_addr < size; ) { + for (i = 0; i < page_sz / TC_SECTOR_SZ; i++) { + /*zinitix_debug_msg("write :addr=%04x, len=%d\n", flash_addr, TC_SECTOR_SZ);*/ + /*zinitix_printk(KERN_INFO "writing :addr = %04x, len=%d \n", flash_addr, TC_SECTOR_SZ);*/ + if (write_data(client, + BT541_WRITE_FLASH, + (u8 *)&firmware_data[flash_addr], TC_SECTOR_SZ) < 0) { + zinitix_printk(KERN_INFO"error : write zinitix tc firmare\n"); + goto fail_upgrade; + } + flash_addr += TC_SECTOR_SZ; + udelay(100); + } + + mdelay(30); /*for fuzing delay*/ + } + + if (write_reg(client, 0xc003, 0x0000) != I2C_SUCCESS) { + zinitix_printk("nvm write vpp off\n"); + goto fail_upgrade; + } + + if (write_reg(client, 0xc104, 0x0000) != I2C_SUCCESS) { + zinitix_printk("nvm wp enable\n"); + goto fail_upgrade; + } + + zinitix_printk(KERN_INFO "init flash\n"); + + if (write_cmd(client, BT541_INIT_FLASH) != I2C_SUCCESS) { + zinitix_printk(KERN_INFO "failed to init flash\n"); + goto fail_upgrade; + } + + zinitix_printk(KERN_INFO "read firmware data\n"); + + for (flash_addr = 0; flash_addr < size; ) { + for (i = 0; i < page_sz / TC_SECTOR_SZ; i++) { + /*zinitix_debug_msg("read :addr=%04x, len=%d\n",flash_addr, TC_SECTOR_SZ);*/ + if (read_firmware_data(client, + BT541_READ_FLASH, + (u8 *)&verify_data[flash_addr], TC_SECTOR_SZ) < 0) { + dev_err(&client->dev, "Failed to read firmare\n"); + + goto fail_upgrade; + } + + flash_addr += TC_SECTOR_SZ; + } + } + /* verify */ + dev_info(&client->dev, "verify firmware data\n"); + if (memcmp((u8 *)&firmware_data[0], (u8 *)&verify_data[0], size) == 0) { + dev_info(&client->dev, "upgrade finished\n"); + kfree(verify_data); + bt541_power_control(info, POWER_OFF); + bt541_power_control(info, POWER_ON_SEQUENCE); + + for (i = 0; i < 5; i++) { + if (read_data(client, BT541_CHECKSUM_RESULT, + (u8 *)®_val, 2) < 0) { + mdelay(10); + continue; + } + } + + if (reg_val != 0x55aa) { + dev_err(&client->dev, "upgrade done, but firmware checksum fail. reg_val = %x\n", reg_val); + goto fail_upgrade; + } +#ifdef SUPPORTED_USE_DUAL_FW + if (read_data(client, BT541_MODULE_ID, (u8 *)®_val, 2) < 0) + dev_err(&client->dev, "Failed to read Modul ID\n"); + else { + if (cap->module_id != reg_val) { + write_reg(client, BT541_MODULE_ID, cap->module_id); + write_reg(client, 0xc003, 0x0001); + write_reg(client, 0xc104, 0x0001); + udelay(100); + if (write_cmd(client, BT541_SAVE_STATUS_CMD) != I2C_SUCCESS) + goto fail_upgrade; + + mdelay(1000); + write_reg(client, 0xc003, 0x0000); + write_reg(client, 0xc104, 0x0000); + } + } +#endif + return true; + } + +fail_upgrade: + bt541_power_control(info, POWER_OFF); + + if (retry_cnt++ < INIT_RETRY_CNT) { + dev_err(&client->dev, "upgrade failed : so retry... (%d)\n", retry_cnt); + goto retry_upgrade; + } + + if (verify_data != NULL) + kfree(verify_data); + + dev_info(&client->dev, "Failed to upgrade\n"); + + return false; +} + +static bool ts_hw_calibration(struct bt541_ts_info *info) +{ + struct i2c_client *client = info->client; + u16 chip_eeprom_info; + int time_out = 0; + + if (write_reg(client, + BT541_TOUCH_MODE, 0x07) != I2C_SUCCESS) + return false; + mdelay(10); + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + mdelay(10); + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + mdelay(50); + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + mdelay(10); + + if (write_cmd(client, + BT541_CALIBRATE_CMD) != I2C_SUCCESS) + return false; + + if (write_cmd(client, + BT541_CLEAR_INT_STATUS_CMD) != I2C_SUCCESS) + return false; + + mdelay(10); + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + + /* wait for h/w calibration*/ + do { + mdelay(500); + write_cmd(client, + BT541_CLEAR_INT_STATUS_CMD); + + if (read_data(client, + BT541_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; + + if (time_out++ == 4) { + write_cmd(client, BT541_CALIBRATE_CMD); + mdelay(10); + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + dev_err(&client->dev, "h/w calibration retry timeout.\n"); + } + + if (time_out++ > 10) { + dev_err(&client->dev, "h/w calibration timeout.\n"); + break; + } + + } while (1); + + if (write_reg(client, + BT541_TOUCH_MODE, TOUCH_POINT_MODE) != I2C_SUCCESS) + return false; + + if (info->cap_info.ic_int_mask != 0) { + if (write_reg(client, + BT541_INT_ENABLE_FLAG, + info->cap_info.ic_int_mask) + != I2C_SUCCESS) + return false; + } + + write_reg(client, 0xc003, 0x0001); + write_reg(client, 0xc104, 0x0001); + udelay(100); + if (write_cmd(client, + BT541_SAVE_CALIBRATION_CMD) != I2C_SUCCESS) + return false; + + mdelay(1000); + write_reg(client, 0xc003, 0x0000); + write_reg(client, 0xc104, 0x0000); + return true; +} + +static bool init_touch(struct bt541_ts_info *info, bool fw_oneshot_upgrade) +{ + struct bt541_ts_platform_data *pdata = info->pdata; + struct i2c_client *client = info->client; + struct capa_info *cap = &(info->cap_info); + u16 reg_val; + int i; + u16 chip_eeprom_info; +#if USE_CHECKSUM + u16 chip_check_sum; + u8 checksum_err; +#endif + int retry_cnt = 0; + +retry_init: + for (i = 0; i < INIT_RETRY_CNT; i++) { + if (read_data(client, BT541_EEPROM_INFO_REG, + (u8 *)&chip_eeprom_info, 2) < 0) { + dev_err(&client->dev, "Failed to read eeprom info(%d)\n", i); + mdelay(10); + continue; + } else + break; + } + + if (i == INIT_RETRY_CNT) + goto fail_init; + +#if USE_CHECKSUM + dev_info(&client->dev, "%s: Check checksum\n", __func__); + + checksum_err = 0; + + for (i = 0; i < INIT_RETRY_CNT; i++) { + if (read_data(client, BT541_CHECKSUM_RESULT, + (u8 *)&chip_check_sum, 2) < 0) { + mdelay(10); + continue; + } + +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "0x%04X\n", chip_check_sum); +#endif + + if (chip_check_sum == 0x55aa) + break; + else { + checksum_err = 1; + break; + } + } + + if (i == INIT_RETRY_CNT || checksum_err) { + dev_err(&client->dev, "Failed to check firmware data\n"); + if (checksum_err == 1 && retry_cnt < INIT_RETRY_CNT) + retry_cnt = INIT_RETRY_CNT; + + goto fail_init; + } +#endif + + if (write_cmd(client, BT541_SWRESET_CMD) != I2C_SUCCESS) { + dev_err(&client->dev, "Failed to write reset command\n"); + goto fail_init; + } + + cap->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_POINT_MODE == 2) + zinitix_bit_set(reg_val, BIT_PALM); + zinitix_bit_set(reg_val, BIT_PALM_REJECT); +#endif + + if (cap->button_num > 0) + zinitix_bit_set(reg_val, BIT_ICON_EVENT); + + cap->ic_int_mask = reg_val; + + if (write_reg(client, BT541_INT_ENABLE_FLAG, 0x0) != I2C_SUCCESS) + goto fail_init; + + dev_info(&client->dev, "%s: Send reset command\n", __func__); + if (write_cmd(client, BT541_SWRESET_CMD) != I2C_SUCCESS) + goto fail_init; + + /* get chip information */ + if (read_data(client, BT541_VENDOR_ID, + (u8 *)&cap->vendor_id, 2) < 0) { + zinitix_printk("failed to read chip revision\n"); + goto fail_init; + } + + + if (read_data(client, BT541_CHIP_REVISION, + (u8 *)&cap->ic_revision, 2) < 0) { + zinitix_printk("failed to read chip revision\n"); + goto fail_init; + } + + cap->ic_fw_size = 32*1024; + + if (read_data(client, BT541_HW_ID, (u8 *)&cap->hw_id, 2) < 0) { + dev_err(&client->dev, "Failed to read hw id\n"); + goto fail_init; + } +#ifdef SUPPORTED_USE_DUAL_FW + bt541_firmware_check(); +#endif + if (read_data(client, BT541_THRESHOLD, (u8 *)&cap->threshold, 2) < 0) + goto fail_init; + + if (read_data(client, BT541_BUTTON_SENSITIVITY, + (u8 *)&cap->key_threshold, 2) < 0) + goto fail_init; + + /* if (read_data(client, BT541_DUMMY_BUTTON_SENSITIVITY, + (u8 *)&cap->dummy_threshold, 2) < 0) + goto fail_init;*/ + + if (read_data(client, BT541_TOTAL_NUMBER_OF_X, + (u8 *)&cap->x_node_num, 2) < 0) + goto fail_init; + + if (read_data(client, BT541_TOTAL_NUMBER_OF_Y, + (u8 *)&cap->y_node_num, 2) < 0) + goto fail_init; + + cap->total_node_num = cap->x_node_num * cap->y_node_num; + + + if (read_data(client, BT541_SHIFT_VALUE, + (u8 *)&cap->shift_value, 2) < 0) + goto fail_init; + zinitix_debug_msg("Shift value = %d\n", cap->shift_value); + + + if (read_data(client, BT541_DND_N_COUNT, + (u8 *)&cap->N_cnt, 2) < 0) + goto fail_init; + zinitix_debug_msg("N count = %d\n", cap->N_cnt); + + if (read_data(client, BT541_DND_U_COUNT, + (u8 *)&cap->U_cnt, 2) < 0) + goto fail_init; + zinitix_debug_msg("u count = %d\n", cap->U_cnt); + + if (read_data(client, BT541_AFE_FREQUENCY, + (u8 *)&cap->afe_frequency, 2) < 0) + goto fail_init; + zinitix_debug_msg("afe frequency = %d\n", cap->afe_frequency); + + /* get chip firmware version */ + if (read_data(client, BT541_FIRMWARE_VERSION, + (u8 *)&cap->fw_version, 2) < 0) + goto fail_init; + + if (read_data(client, BT541_MINOR_FW_VERSION, + (u8 *)&cap->fw_minor_version, 2) < 0) + goto fail_init; + + if (read_data(client, BT541_DATA_VERSION_REG, + (u8 *)&cap->reg_data_version, 2) < 0) + goto fail_init; + +#if TOUCH_ONESHOT_UPGRADE + if (fw_oneshot_upgrade && (ts_check_need_upgrade(info, cap->fw_version, + cap->fw_minor_version, cap->reg_data_version, + cap->hw_id) == true)) { + zinitix_printk("start upgrade firmware\n"); + + if (ts_upgrade_firmware(info, m_firmware_data, + cap->ic_fw_size) == false) + goto fail_init; + + if (ts_hw_calibration(info) == false) + goto fail_init; + + /* disable chip interrupt */ + if (write_reg(client, BT541_INT_ENABLE_FLAG, 0) != I2C_SUCCESS) + goto fail_init; + + /* get chip firmware version */ + if (read_data(client, BT541_FIRMWARE_VERSION, + (u8 *)&cap->fw_version, 2) < 0) + goto fail_init; + + if (read_data(client, BT541_MINOR_FW_VERSION, + (u8 *)&cap->fw_minor_version, 2) < 0) + goto fail_init; + + if (read_data(client, BT541_DATA_VERSION_REG, + (u8 *)&cap->reg_data_version, 2) < 0) + goto fail_init; +#ifdef SUPPORTED_USE_DUAL_FW + if (read_data(client, BT541_HW_ID, + (u8 *)&cap->hw_id, 2) < 0) + goto fail_init; + bt541_firmware_check(); + if (read_data(client, BT541_VENDOR_ID, + (u8 *)&cap->vendor_id, 2) < 0) + goto fail_init; +#endif + } +#endif + + if (read_data(client, BT541_EEPROM_INFO_REG, + (u8 *)&chip_eeprom_info, 2) < 0) + goto fail_init; + + if (zinitix_bit_test(chip_eeprom_info, 0)) { /* hw calibration bit*/ + if (ts_hw_calibration(info) == false) + goto fail_init; + + /* disable chip interrupt */ + if (write_reg(client, BT541_INT_ENABLE_FLAG, 0) != I2C_SUCCESS) + goto fail_init; + } + + /* initialize */ + if (write_reg(client, BT541_X_RESOLUTION, + (u16)pdata->x_resolution) != I2C_SUCCESS) + goto fail_init; + + if (write_reg(client, BT541_Y_RESOLUTION, + (u16)pdata->y_resolution) != I2C_SUCCESS) + goto fail_init; + + cap->MinX = (u32)0; + cap->MinY = (u32)0; + cap->MaxX = (u32)pdata->x_resolution; + cap->MaxY = (u32)pdata->y_resolution; + + if (write_reg(client, BT541_BUTTON_SUPPORTED_NUM, + (u16)cap->button_num) != I2C_SUCCESS) + goto fail_init; + + if (write_reg(client, BT541_SUPPORTED_FINGER_NUM, + (u16)MAX_SUPPORTED_FINGER_NUM) != I2C_SUCCESS) + goto fail_init; + + cap->multi_fingers = MAX_SUPPORTED_FINGER_NUM; + zinitix_debug_msg("max supported finger num = %d\r\n", + cap->multi_fingers); + + cap->gesture_support = 0; + zinitix_debug_msg("set other configuration\r\n"); + + if (write_reg(client, BT541_INITIAL_TOUCH_MODE, + TOUCH_POINT_MODE) != I2C_SUCCESS) + goto fail_init; + + if (write_reg(client, BT541_TOUCH_MODE, info->touch_mode) != I2C_SUCCESS) + goto fail_init; + +#if ZINITIX_I2C_CHECKSUM + if (read_data(client, ZINITIX_INTERNAL_FLAG_02, + (u8 *)®_val, 2) < 0) + goto fail_init; + cap->i2s_checksum = !(!zinitix_bit_test(reg_val, 15)); + printk("use i2s checksum = %d\r\n", + cap->i2s_checksum); +#endif + + bt541_set_ta_status(info); + bt541_set_optional_mode(info, true); + /* soft calibration */ + /* if (write_cmd(client, BT541_CALIBRATE_CMD) != I2C_SUCCESS) + goto fail_init;*/ + + if (write_reg(client, BT541_INT_ENABLE_FLAG, + cap->ic_int_mask) != I2C_SUCCESS) + goto fail_init; + + /* read garbage data */ + for (i = 0; i < 10; i++) { + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + udelay(10); + } + + if (info->touch_mode != TOUCH_POINT_MODE) { /* Test Mode */ + if (write_reg(client, BT541_DELAY_RAW_FOR_HOST, + RAWDATA_DELAY_FOR_HOST) != I2C_SUCCESS) { + dev_err(&client->dev, "%s: Failed to set DELAY_RAW_FOR_HOST\n", + __func__); + + goto fail_init; + } + } +#if ESD_TIMER_INTERVAL + if (write_reg(client, BT541_PERIODICAL_INTERRUPT_INTERVAL, + SCAN_RATE_HZ * ESD_TIMER_INTERVAL) != I2C_SUCCESS) + goto fail_init; + + read_data(client, BT541_PERIODICAL_INTERRUPT_INTERVAL, (u8 *)®_val, 2); +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "Esd timer register = %d\n", reg_val); +#endif +#endif + tsp_charger_status_cb = tsp_charger_enable; + zinitix_debug_msg("successfully initialized\r\n"); + return true; + +fail_init: + if (cal_mode) { + dev_err(&client->dev,"didn't update TSP F/W!! in CAL MODE\n"); + return false; + } + if (++retry_cnt <= INIT_RETRY_CNT) { + bt541_power_control(info, POWER_OFF); + bt541_power_control(info, POWER_ON_SEQUENCE); + + zinitix_debug_msg("retry to initiallize(retry cnt = %d)\r\n", + retry_cnt); + goto retry_init; + + } else if (retry_cnt == INIT_RETRY_CNT+1) { + cap->ic_fw_size = 32*1024; + + zinitix_debug_msg("retry to initiallize(retry cnt = %d)\r\n", retry_cnt); +#if TOUCH_FORCE_UPGRADE +#ifdef SUPPORTED_USE_DUAL_FW + ts_check_hwid_in_fatal_state(info); + bt541_firmware_check(); +#endif + if (ts_upgrade_firmware(info, m_firmware_data, + cap->ic_fw_size) == false) { + zinitix_printk("upgrade failed\n"); + return false; + } + + mdelay(100); + + /* hw calibration and make checksum */ + if (ts_hw_calibration(info) == false) { + zinitix_printk("failed to initiallize\r\n"); + return false; + } + goto retry_init; +#endif + } + + dev_err(&client->dev, "Failed to initiallize\n"); + + return false; +} + +static bool mini_init_touch(struct bt541_ts_info *info) +{ + struct bt541_ts_platform_data *pdata = info->pdata; + struct i2c_client *client = info->client; + int i; +#if USE_CHECKSUM + u16 chip_check_sum; + + /*dev_info(&client->dev, "check checksum\n");*/ + + if (read_data(client, BT541_CHECKSUM_RESULT, + (u8 *)&chip_check_sum, 2) < 0) + goto fail_mini_init; + + if (chip_check_sum != 0x55aa) { + dev_err(&client->dev, "Failed to check firmware" + " checksum(0x%04x)\n", chip_check_sum); + + goto fail_mini_init; + } +#endif + + if (write_cmd(client, BT541_SWRESET_CMD) != I2C_SUCCESS) { + dev_info(&client->dev, "Failed to write reset command\n"); + + goto fail_mini_init; + } + + /* initialize */ + if (write_reg(client, BT541_X_RESOLUTION, + (u16)(pdata->x_resolution)) != I2C_SUCCESS) + goto fail_mini_init; + + if (write_reg(client,BT541_Y_RESOLUTION, + (u16)(pdata->y_resolution)) != I2C_SUCCESS) + goto fail_mini_init; + + /*dev_info(&client->dev, "touch max x = %d\r\n", pdata->x_resolution); + dev_info(&client->dev, "touch max y = %d\r\n", pdata->y_resolution);*/ + + if (write_reg(client, BT541_BUTTON_SUPPORTED_NUM, + (u16)info->cap_info.button_num) != I2C_SUCCESS) + goto fail_mini_init; + + if (write_reg(client, BT541_SUPPORTED_FINGER_NUM, + (u16)MAX_SUPPORTED_FINGER_NUM) != I2C_SUCCESS) + goto fail_mini_init; + + if (write_reg(client, BT541_INITIAL_TOUCH_MODE, + TOUCH_POINT_MODE) != I2C_SUCCESS) + goto fail_mini_init; + + if (write_reg(client, BT541_TOUCH_MODE, + info->touch_mode) != I2C_SUCCESS) + goto fail_mini_init; + + bt541_set_ta_status(info); + bt541_set_optional_mode(info, true); + /* soft calibration */ + if (write_cmd(client, BT541_CALIBRATE_CMD) != I2C_SUCCESS) + goto fail_mini_init; + + if (write_reg(client, BT541_INT_ENABLE_FLAG, + info->cap_info.ic_int_mask) != I2C_SUCCESS) + goto fail_mini_init; + + /* read garbage data */ + for (i = 0; i < 10; i++) { + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + udelay(10); + } + + if (info->touch_mode != TOUCH_POINT_MODE) { + if (write_reg(client, BT541_DELAY_RAW_FOR_HOST, + RAWDATA_DELAY_FOR_HOST) != I2C_SUCCESS) { + dev_err(&client->dev, "Failed to set BT541_DELAY_RAW_FOR_HOST\n"); + + goto fail_mini_init; + } + } + +#if ESD_TIMER_INTERVAL + if (write_reg(client, BT541_PERIODICAL_INTERRUPT_INTERVAL, + SCAN_RATE_HZ * ESD_TIMER_INTERVAL) != I2C_SUCCESS) + goto fail_mini_init; + + esd_timer_start(CHECK_ESD_TIMER, info); +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "Started esd timer\n"); +#endif +#endif + + dev_info(&client->dev, "Successfully mini initialized\r\n"); + return true; + +fail_mini_init: + dev_err(&client->dev, "Failed to initialize mini init\n"); + bt541_power_control(info, POWER_OFF); + bt541_power_control(info, POWER_ON_SEQUENCE); + + if (init_touch(info, true) == false) { + dev_err(&client->dev, "Failed to initialize\n"); + + return false; + } + +#if ESD_TIMER_INTERVAL + esd_timer_start(CHECK_ESD_TIMER, info); +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "Started esd timer\n"); +#endif +#endif + return true; +} + +static void clear_report_data(struct bt541_ts_info *info) +{ + int i; + u8 reported = 0; + u8 sub_status; + + for (i = 0; i < info->cap_info.button_num; i++) { + if (info->button[i] == ICON_BUTTON_DOWN) { + info->button[i] = ICON_BUTTON_UP; + input_report_key(info->input_dev, BUTTON_MAPPING_KEY[i], 0); + reported = true; +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + printk(KERN_INFO "Button up = %d\n", i); +#else + printk(KERN_INFO "Button up\n"); +#endif + } + } + + for (i = 0; i < info->cap_info.multi_fingers; i++) { + sub_status = info->reported_touch_info.coord[i].sub_status; + if (zinitix_bit_test(sub_status, SUB_BIT_EXIST)) { + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0); + reported = true; + if (!m_ts_debug_mode && TSP_NORMAL_EVENT_MSG) + printk(KERN_INFO "[TSP] R %02d\r\n", i); + } + info->reported_touch_info.coord[i].sub_status = 0; + } + + if (reported) + input_sync(info->input_dev); + +} + +#define PALM_REPORT_WIDTH 200 +#define PALM_REJECT_WIDTH 255 + +static irqreturn_t bt541_touch_work(int irq, void *data) +{ + struct bt541_ts_info* info = (struct bt541_ts_info*)data; + struct bt541_ts_platform_data *pdata = info->pdata; + struct i2c_client *client = info->client; + int i; + u8 sub_status; + u8 prev_sub_status; + u32 x, y, maxX, maxY; + u32 w; + u32 tmp; + u8 palm = 0; + + if (gpio_get_value(info->pdata->gpio_int)) { + dev_err(&client->dev, "Invalid interrupt\n"); + + return IRQ_HANDLED; + } + + if (down_trylock(&info->work_lock)) { + dev_err(&client->dev, "%s: Failed to occupy work lock\n", __func__); + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + + return IRQ_HANDLED; + } +#if ESD_TIMER_INTERVAL + esd_timer_stop(info); +#endif + + if (info->work_state != NOTHING) { + dev_err(&client->dev, "%s: Other process occupied\n", __func__); + udelay(DELAY_FOR_SIGNAL_DELAY); + + if (!gpio_get_value(info->pdata->gpio_int)) { + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + udelay(DELAY_FOR_SIGNAL_DELAY); + } + + goto out; + } + + info->work_state = NORMAL; + +#if ZINITIX_I2C_CHECKSUM + i = 0; + if (ts_read_coord(info) == false || info->touch_info.status == 0xffff + || info->touch_info.status == 0x1) { + /* more retry*/ + for (i = 1; i < 50; i++) { /* about 10ms*/ + if (!(ts_read_coord(info) == false || info->touch_info.status == 0xffff + || info->touch_info.status == 0x1)) + break; + } + + } + + if (i == 50) { + dev_err(&client->dev, "Failed to read info coord\n"); + bt541_power_control(info, POWER_OFF); + bt541_power_control(info, POWER_ON_SEQUENCE); + + clear_report_data(info); + mini_init_touch(info); + + goto out; + } +#else + if (ts_read_coord(info) == false || info->touch_info.status == 0xffff + || info->touch_info.status == 0x1) { /* maybe desirable reset */ + dev_err(&client->dev, "Failed to read info coord\n"); + bt541_power_control(info, POWER_OFF); + bt541_power_control(info, POWER_ON_SEQUENCE); + + clear_report_data(info); + mini_init_touch(info); + + goto out; + } +#endif + /* invalid : maybe periodical repeated int. */ + if (info->touch_info.status == 0x0) + goto out; + + if (zinitix_bit_test(info->touch_info.status, BIT_ICON_EVENT)) { + if (read_data(info->client, BT541_ICON_STATUS_REG, + (u8 *)(&info->icon_event_reg), 2) < 0) { + dev_err(&client->dev, "Failed to read button info\n"); + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + + goto out; + } + + for (i = 0; i < info->cap_info.button_num; i++) { + if (zinitix_bit_test(info->icon_event_reg, + (BIT_O_ICON0_DOWN + i))) { + info->button[i] = ICON_BUTTON_DOWN; + input_report_key(info->input_dev, BUTTON_MAPPING_KEY[i], 1); +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + dev_info(&client->dev, "Button down = %d\n", i); +#else + dev_info(&client->dev, "Button down\n"); +#endif + } + } + + for (i = 0; i < info->cap_info.button_num; i++) { + if (zinitix_bit_test(info->icon_event_reg, + (BIT_O_ICON0_UP + i))) { + info->button[i] = ICON_BUTTON_UP; + input_report_key(info->input_dev, BUTTON_MAPPING_KEY[i], 0); +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + dev_info(&client->dev, "Button up = %d\n", i); +#else + dev_info(&client->dev, "Button up\n"); +#endif + } + } + } + +#ifdef SUPPORTED_PALM_TOUCH + if (zinitix_bit_test(info->touch_info.status, BIT_PALM)) { +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + dev_info(&client->dev, "Palm report\n"); +#endif + palm = 1; + } + + if (zinitix_bit_test(info->touch_info.status, BIT_PALM_REJECT)) { +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + dev_info(&client->dev, "Palm reject\n"); +#endif + palm = 2; + } +#endif + for (i = 0; i < info->cap_info.multi_fingers; i++) { + sub_status = info->touch_info.coord[i].sub_status; + prev_sub_status = info->reported_touch_info.coord[i].sub_status; + + if (zinitix_bit_test(sub_status, SUB_BIT_EXIST)) { + x = info->touch_info.coord[i].x; + y = info->touch_info.coord[i].y; + w = info->touch_info.coord[i].width; + + /* transformation from touch to screen orientation */ + if (pdata->orientation & TOUCH_V_FLIP) + y = info->cap_info.MaxY + + info->cap_info.MinY - y; + + if (pdata->orientation & TOUCH_H_FLIP) + x = info->cap_info.MaxX + + info->cap_info.MinX - x; + + maxX = info->cap_info.MaxX; + maxY = info->cap_info.MaxY; + + if (pdata->orientation & TOUCH_XY_SWAP) { + zinitix_swap_v(x, y, tmp); + zinitix_swap_v(maxX, maxY, tmp); + } + + if (x > maxX || y > maxY) { +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + dev_err(&client->dev, + "Invalid coord %d : x=%d, y=%d\n", i, x, y); +#endif + continue; + } + + info->touch_info.coord[i].x = x; + info->touch_info.coord[i].y = y; + if (zinitix_bit_test(sub_status, SUB_BIT_DOWN)) + { +#if TOUCH_BOOSTER + if (!min_handle) + { + min_handle = cpufreq_limit_min_freq(touch_cpufreq_lock, "TSP"); + if (IS_ERR(min_handle)) { + printk(KERN_ERR "[TSP] cannot get cpufreq_min lock %lu(%ld)\n", + touch_cpufreq_lock, PTR_ERR(min_handle)); + min_handle = NULL; + } + _store_cpu_num_min_limit(2); + dev_info(&client->dev, "cpu freq on\n"); + } + info->finger_cnt++; +#endif +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + dev_info(&client->dev, "Finger [%02d] x = %d, y = %d," + " w = %d\n", i, x, y, w); +#else + dev_info(&client->dev, "Finger down\n"); +#endif + } + if (w == 0) + w = 1; + + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 1); + +#if (TOUCH_POINT_MODE == 2) + if (palm == 0) { + if (w >= PALM_REPORT_WIDTH) + w = PALM_REPORT_WIDTH - 10; + } else if (palm == 1) { /*palm report*/ + w = PALM_REPORT_WIDTH; + /* info->touch_info.coord[i].minor_width = PALM_REPORT_WIDTH;*/ + } else if (palm == 2) { /* palm reject*/ + /* x = y = 0;*/ + w = PALM_REJECT_WIDTH; + /* info->touch_info.coord[i].minor_width = PALM_REJECT_WIDTH;*/ + } +#endif + + input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, (u32)w); + input_report_abs(info->input_dev, ABS_MT_PRESSURE, (u32)w); + input_report_abs(info->input_dev, ABS_MT_WIDTH_MAJOR, + (u32)((palm == 1) ? w-40 : w)); +#if (TOUCH_POINT_MODE == 2) + input_report_abs(info->input_dev, + ABS_MT_TOUCH_MINOR, (u32)info->touch_info.coord[i].minor_width); + /* input_report_abs(info->input_dev, + ABS_MT_WIDTH_MINOR, (u32)info->touch_info.coord[i].minor_width);*/ +#ifdef SUPPORTED_PALM_TOUCH + /*input_report_abs(info->input_dev, ABS_MT_ANGLE, + (palm > 1)?70:info->touch_info.coord[i].angle - 90);*/ + /*dev_info(&client->dev, "finger [%02d] angle = %03d\n", i, + info->touch_info.coord[i].angle);*/ + input_report_abs(info->input_dev, ABS_MT_PALM, (palm > 0)?1:0); +#endif + /* input_report_abs(info->input_dev, ABS_MT_PALM, 1);*/ +#endif + + input_report_abs(info->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y); + } else if (zinitix_bit_test(sub_status, SUB_BIT_UP)|| + zinitix_bit_test(prev_sub_status, SUB_BIT_EXIST)) { +#if TOUCH_BOOSTER + info->finger_cnt--; + if (!info->finger_cnt) + { + cpufreq_limit_put(min_handle); + min_handle = NULL; + _store_cpu_num_min_limit(1); + dev_info(&client->dev, "cpu freq off\n"); + } +#endif +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + dev_info(&client->dev, "Finger [%02d] up\n", i); +#else + dev_info(&client->dev, "Finger up\n"); +#endif + memset(&info->touch_info.coord[i], 0x0, sizeof(struct coord)); + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0); + + } else { + memset(&info->touch_info.coord[i], 0x0, sizeof(struct coord)); + } + } + memcpy((char *)&info->reported_touch_info, (char *)&info->touch_info, + sizeof(struct point_info)); + input_sync(info->input_dev); + +out: + if (info->work_state == NORMAL) { +#if ESD_TIMER_INTERVAL + esd_timer_start(CHECK_ESD_TIMER, info); +#endif + info->work_state = NOTHING; + } + + up(&info->work_lock); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void bt541_ts_late_resume(struct early_suspend *h) +{ + struct bt541_ts_info *info = misc_info; + //info = container_of(h, struct bt541_ts_info, early_suspend); + struct capa_info *cap = &(info->cap_info); + + if (info == NULL) + return; + zinitix_printk("late resume++\r\n"); + + down(&info->work_lock); + if (info->work_state != RESUME + && info->work_state != EALRY_SUSPEND) { + zinitix_printk("invalid work proceedure (%d)\r\n", + info->work_state); + up(&info->work_lock); + return; + } +#if 0 + write_cmd(info->client, BT541_WAKEUP_CMD); + mdelay(1); +#else + bt541_power_control(info, POWER_ON_SEQUENCE); +#endif + info->work_state = RESUME; + if (mini_init_touch(info) == false) + goto fail_late_resume; + + if (read_data(info->client, BT541_FIRMWARE_VERSION, (u8 *)&cap->fw_version, 2)) + ; + if (read_data(info->client, BT541_MINOR_FW_VERSION, (u8 *)&cap->fw_minor_version, 2)) + ; + if (read_data(info->client, BT541_DATA_VERSION_REG, (u8 *)&cap->reg_data_version, 2)) + ; + if (read_data(info->client, BT541_HW_ID, (u8 *)&cap->hw_id, 2)) + ; + if (read_data(info->client, BT541_VENDOR_ID, (u8 *)&cap->vendor_id, 2)) + ; +#ifdef SUPPORTED_USE_DUAL_FW + bt541_firmware_check(); +#endif + enable_irq(info->irq); + info->work_state = NOTHING; + up(&info->work_lock); + zinitix_printk("late resume--\n"); + return; +fail_late_resume: + zinitix_printk("failed to late resume\n"); + enable_irq(info->irq); + info->work_state = NOTHING; + up(&info->work_lock); + return; +} + +static void bt541_ts_early_suspend(struct early_suspend *h) +{ + struct bt541_ts_info *info = misc_info; + /*info = container_of(h, struct bt541_ts_info, early_suspend);*/ + + if (info == NULL) + return; + + zinitix_printk("early suspend++\n"); + + disable_irq(info->irq); +#if ESD_TIMER_INTERVAL + flush_work(&info->tmr_work); +#endif + + down(&info->work_lock); + if (info->work_state != NOTHING) { + zinitix_printk("invalid work proceedure (%d)\r\n", + info->work_state); + up(&info->work_lock); + enable_irq(info->irq); + return; + } + info->work_state = EALRY_SUSPEND; + + zinitix_debug_msg("clear all reported points\r\n"); + clear_report_data(info); + +#if ESD_TIMER_INTERVAL + /*write_reg(info->client, BT541_PERIODICAL_INTERRUPT_INTERVAL, 0);*/ + esd_timer_stop(info); +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&info->client->dev, "Stopped esd timer\n"); +#endif +#endif + +#if 0 + write_reg(info->client, BT541_INT_ENABLE_FLAG, 0x0); + + udelay(100); + if (write_cmd(info->client, BT541_SLEEP_CMD) != I2C_SUCCESS) { + zinitix_printk("failed to enter into sleep mode\n"); + up(&info->work_lock); + return; + } +#else + bt541_power_control(info, POWER_OFF); +#endif +#if TOUCH_BOOSTER + if (min_handle) + { + dev_err(&info->client->dev,"[TSP] %s %d:: OOPs, Cpu was not in Normal Freq..\n", __func__, __LINE__); + + if (cpufreq_limit_put(min_handle) < 0) { + dev_err(&info->client->dev, "[TSP] Error in scaling down cpu frequency\n"); + } + + min_handle = NULL; + info->finger_cnt = 0; + dev_info(&info->client->dev, "cpu freq off\n"); + } +#endif + zinitix_printk("early suspend--\n"); + up(&info->work_lock); + return; +} +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int bt541_ts_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bt541_ts_info *info = i2c_get_clientdata(client); + struct capa_info *cap = &(info->cap_info); + +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "resume++\n"); +#endif + down(&info->work_lock); + if (info->work_state != SUSPEND) { + dev_err(&client->dev, "%s: Invalid work proceedure (%d)\n", + __func__, info->work_state); + up(&info->work_lock); + + return 0; + } + bt541_power_control(info, POWER_ON_SEQUENCE); + +#ifdef CONFIG_HAS_EARLYSUSPEND + info->work_state = RESUME; +#else + info->work_state = NOTHING; + if (mini_init_touch(info) == false) + dev_err(&client->dev, "Failed to resume\n"); + + if (read_data(client, BT541_FIRMWARE_VERSION, (u8 *)&cap->fw_version, 2)) + ; + if (read_data(client, BT541_MINOR_FW_VERSION, (u8 *)&cap->fw_minor_version, 2)) + ; + if (read_data(client, BT541_DATA_VERSION_REG, (u8 *)&cap->reg_data_version, 2)) + ; + if (read_data(client, BT541_HW_ID, (u8 *)&cap->hw_id, 2)) + ; + if (read_data(client, BT541_VENDOR_ID, (u8 *)&cap->vendor_id, 2)) + ; +#ifdef SUPPORTED_USE_DUAL_FW + bt541_firmware_check(); +#endif + if (!gpio_get_value(info->pdata->gpio_int)) + { + write_cmd(info->client, BT541_CLEAR_INT_STATUS_CMD); + udelay(50); + write_cmd(info->client, BT541_CLEAR_INT_STATUS_CMD); + udelay(50); + write_cmd(info->client, BT541_CLEAR_INT_STATUS_CMD); + } + info->work_state = NOTHING; +#endif + +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "resume--\n"); +#endif + up(&info->work_lock); + enable_irq(info->irq); + return 0; +} + +static int bt541_ts_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bt541_ts_info *info = i2c_get_clientdata(client); + +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "suspend++\n"); +#endif + +#ifndef CONFIG_HAS_EARLYSUSPEND + disable_irq(info->irq); +#endif +#if ESD_TIMER_INTERVAL + flush_work(&info->tmr_work); +#endif + + down(&info->work_lock); + if (info->work_state != NOTHING + && info->work_state != SUSPEND) { + dev_err(&client->dev,"%s: Invalid work proceedure (%d)\n", + __func__, info->work_state); + up(&info->work_lock); +#ifndef CONFIG_HAS_EARLYSUSPEND + enable_irq(info->irq); +#endif + return 0; + } + +#ifndef CONFIG_HAS_EARLYSUSPEND + clear_report_data(info); + +#if ESD_TIMER_INTERVAL + esd_timer_stop(info); +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "Stopped esd timer\n"); +#endif +#endif +#endif + write_cmd(info->client, BT541_SLEEP_CMD); + bt541_power_control(info, POWER_OFF); + info->work_state = SUSPEND; + +#if defined(TSP_VERBOSE_DEBUG) + zinitix_printk("suspend--\n"); +#endif + up(&info->work_lock); + + return 0; +} +#endif + +static bool ts_set_touchmode(u16 value) +{ + int i; + + disable_irq(misc_info->irq); + + down(&misc_info->work_lock); + if (misc_info->work_state != NOTHING) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_info->work_state); + enable_irq(misc_info->irq); + up(&misc_info->work_lock); + return -1; + } + + misc_info->work_state = SET_MODE; + + if (value == TOUCH_DND_MODE) { + if (write_reg(misc_info->client, BT541_DND_N_COUNT, + SEC_DND_N_COUNT) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set DND_N_COUNT\n"); + + if (write_reg(misc_info->client, BT541_DND_U_COUNT, + SEC_DND_U_COUNT) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set DND_U_COUNT\n"); + + if (write_reg(misc_info->client, BT541_AFE_FREQUENCY, + SEC_DND_FREQUENCY) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set AFE_FREQUENCY\n"); + + } else if (misc_info->touch_mode == TOUCH_DND_MODE) { + if (write_reg(misc_info->client, BT541_AFE_FREQUENCY, + misc_info->cap_info.afe_frequency) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set AFE_FREQUENCY\n"); + + if (write_reg(misc_info->client, BT541_DND_U_COUNT, + misc_info->cap_info.U_cnt) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set U_COUNT\n"); + + if (write_reg(misc_info->client, BT541_SHIFT_VALUE, + misc_info->cap_info.shift_value) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set Shift\n"); + } + + if (value == TOUCH_SEC_MODE) + misc_info->touch_mode = TOUCH_POINT_MODE; + else + misc_info->touch_mode = value; + + printk(KERN_INFO "[zinitix_touch] tsp_set_testmode, " + "touchkey_testmode = %d\r\n", misc_info->touch_mode); + + if (misc_info->touch_mode != TOUCH_POINT_MODE) { + if (write_reg(misc_info->client, BT541_DELAY_RAW_FOR_HOST, + RAWDATA_DELAY_FOR_HOST) != I2C_SUCCESS) + zinitix_printk("Fail to set BT541_DELAY_RAW_FOR_HOST.\r\n"); + } + + if (write_reg(misc_info->client, BT541_TOUCH_MODE, + misc_info->touch_mode) != I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] TEST Mode : " + "Fail to set ZINITX_TOUCH_MODE %d.\r\n", misc_info->touch_mode); + + /* clear garbage data */ + for (i = 0; i < 10; i++) { + mdelay(20); + write_cmd(misc_info->client, BT541_CLEAR_INT_STATUS_CMD); + } + + misc_info->work_state = NOTHING; + enable_irq(misc_info->irq); + up(&misc_info->work_lock); + return 1; +} + +static bool ts_set_touchmode2(u16 value) +{ + int i; + + disable_irq(misc_info->irq); + + down(&misc_info->work_lock); + if (misc_info->work_state != NOTHING) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_info->work_state); + enable_irq(misc_info->irq); + up(&misc_info->work_lock); + return -1; + } + + misc_info->work_state = SET_MODE; + + if (value == TOUCH_DND_MODE) { + if (write_reg(misc_info->client, BT541_DND_N_COUNT, + SEC_HFDND_N_COUNT) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set DND_N_COUNT\n"); + + if (write_reg(misc_info->client, BT541_DND_U_COUNT, + SEC_HFDND_U_COUNT) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set DND_U_COUNT\n"); + + if (write_reg(misc_info->client, BT541_AFE_FREQUENCY, + SEC_HFDND_FREQUENCY) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set AFE_FREQUENCY\n"); + + + } else { + if (write_reg(misc_info->client, BT541_AFE_FREQUENCY, + misc_info->cap_info.afe_frequency) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set AFE_FREQUENCY\n"); + + if (write_reg(misc_info->client, BT541_DND_U_COUNT, + misc_info->cap_info.U_cnt) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set U_COUNT\n"); + + if (write_reg(misc_info->client, BT541_SHIFT_VALUE, + misc_info->cap_info.shift_value) != I2C_SUCCESS) + dev_err(&misc_info->client->dev, "Failed to set Shift\n"); + } + + if (value == TOUCH_SEC_MODE) + misc_info->touch_mode = TOUCH_POINT_MODE; + else + misc_info->touch_mode = value; + + printk(KERN_INFO "[zinitix_touch] tsp_set_testmode, " + "touchkey_testmode = %d\r\n", misc_info->touch_mode); + + if (misc_info->touch_mode != TOUCH_POINT_MODE) { + if (write_reg(misc_info->client, BT541_DELAY_RAW_FOR_HOST, + RAWDATA_DELAY_FOR_HOST) != I2C_SUCCESS) + zinitix_printk("Fail to set BT541_DELAY_RAW_FOR_HOST.\r\n"); + } + + if (write_reg(misc_info->client, BT541_TOUCH_MODE, + misc_info->touch_mode) != I2C_SUCCESS) + printk(KERN_INFO "[zinitix_touch] TEST Mode : " + "Fail to set ZINITX_TOUCH_MODE %d.\r\n", misc_info->touch_mode); + + /* clear garbage data */ + for (i = 0; i < 10; i++) { + mdelay(20); + write_cmd(misc_info->client, BT541_CLEAR_INT_STATUS_CMD); + } + + misc_info->work_state = NOTHING; + enable_irq(misc_info->irq); + up(&misc_info->work_lock); + return 1; +} + +static int ts_upgrade_sequence(const u8 *firmware_data) +{ + disable_irq(misc_info->irq); + down(&misc_info->work_lock); + misc_info->work_state = UPGRADE; + +#if ESD_TIMER_INTERVAL + esd_timer_stop(misc_info); +#endif + zinitix_debug_msg("clear all reported points\r\n"); + clear_report_data(misc_info); + + printk(KERN_INFO "start upgrade firmware\n"); + if (ts_upgrade_firmware(misc_info, + firmware_data, + misc_info->cap_info.ic_fw_size) == false) { + enable_irq(misc_info->irq); + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + return -1; + } + + if (init_touch(misc_info, false) == false) { + enable_irq(misc_info->irq); + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + return -1; + } + +#if ESD_TIMER_INTERVAL + esd_timer_start(CHECK_ESD_TIMER, misc_info); +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&misc_info->client->dev, "Started esd timer\n"); +#endif +#endif + + enable_irq(misc_info->irq); + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + return 0; +} + +#ifdef SEC_FACTORY_TEST +static inline void set_cmd_result(struct bt541_ts_info *info, char *buff, int len) +{ + strncat(info->factory_info->cmd_result, buff, len); +} + +static inline void set_default_result(struct bt541_ts_info *info) +{ + char delim = ':'; + memset(info->factory_info->cmd_result, 0x00, ARRAY_SIZE(info->factory_info->cmd_result)); + memcpy(info->factory_info->cmd_result, info->factory_info->cmd, strlen(info->factory_info->cmd)); + strncat(info->factory_info->cmd_result, &delim, 1); +} + +#define MAX_FW_PATH 255 +#define TSP_FW_FILENAME "zinitix_fw.bin" + +static void fw_update(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + int ret = 0; + const u8 *buff = 0; + mm_segment_t old_fs = {0}; + struct file *fp = NULL; + long fsize = 0, nread = 0; + char fw_path[MAX_FW_PATH+1]; + char result[16] = {0}; + + set_default_result(info); + + switch (info->factory_info->cmd_param[0]) { + case BUILT_IN: + ret = ts_upgrade_sequence((u8 *)m_firmware_data); + if (ret < 0) { + info->factory_info->cmd_state = 3; + return; + } + break; + + case UMS: + old_fs = get_fs(); + set_fs(get_ds()); + + snprintf(fw_path, MAX_FW_PATH, "/sdcard/%s", TSP_FW_FILENAME); + fp = filp_open(fw_path, O_RDONLY, 0); + if (IS_ERR(fp)) { + dev_err(&client->dev, + "file %s open error:%lu\n", fw_path, (unsigned long)fp); + info->factory_info->cmd_state = 3; + goto err_open; + } + + fsize = fp->f_path.dentry->d_inode->i_size; + + if (fsize != info->cap_info.ic_fw_size) { + dev_err(&client->dev, "invalid fw size!!\n"); + info->factory_info->cmd_state = 3; + goto err_open; + } + + buff = kzalloc((size_t)fsize, GFP_KERNEL); + if (!buff) { + dev_err(&client->dev, "failed to alloc buffer for fw\n"); + info->factory_info->cmd_state = 3; + goto err_alloc; + } + + nread = vfs_read(fp, (char __user *)buff, fsize, &fp->f_pos); + if (nread != fsize) { + info->factory_info->cmd_state = 3; + goto err_fw_size; + } + + filp_close(fp, current->files); + set_fs(old_fs); + dev_info(&client->dev, "ums fw is loaded!!\n"); + + ret = ts_upgrade_sequence((u8 *)buff); + if (ret < 0) { + kfree(buff); + info->factory_info->cmd_state = 3; + goto update_fail; + } + break; + + default: + dev_err(&client->dev, "invalid fw file type!!\n"); + goto update_fail; + } + + info->factory_info->cmd_state = 2; + snprintf(result, sizeof(result) , "%s", "OK"); + set_cmd_result(info, result, + strnlen(result, sizeof(result))); + kfree(buff); + + return; + + + if (fp != NULL) { +err_fw_size: + kfree(buff); +err_alloc: + filp_close(fp, NULL); +err_open: + set_fs(old_fs); + } +update_fail: + snprintf(result, sizeof(result) , "%s", "NG"); + set_cmd_result(info, result, strnlen(result, sizeof(result))); +} + +static void get_fw_ver_bin(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + u16 fw_version, fw_minor_version, reg_version, hw_id, vendor_id; + u32 version, length; + + set_default_result(info); + + /* To Do */ + /* modify m_firmware_data */ + fw_version = (u16)(m_firmware_data[52] | (m_firmware_data[53] << 8)); + fw_minor_version = (u16)(m_firmware_data[56] | (m_firmware_data[57] << 8)); + reg_version = (u16)(m_firmware_data[60] | (m_firmware_data[61] << 8)); + hw_id = (u16)(m_firmware_data[0x7528] | (m_firmware_data[0x7529]<<8)); + /* vendor_id = ntohs(*(u16 *)&m_firmware_data[0x57e2]);*/ + version = (u32)((u32)(hw_id & 0xff) << 16) | ((fw_version & 0xf ) << 12) + | ((fw_minor_version & 0xf) << 8) | (reg_version & 0xff); + + /* length = sizeof(vendor_id); + snprintf(finfo->cmd_buff, length + 1, "%s", (u8 *)&vendor_id); + snprintf(finfo->cmd_buff + length, sizeof(finfo->cmd_buff) - length, + "%06X", version);*/ + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; +} + +static void get_fw_ver_ic(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + u16 fw_version, fw_minor_version, reg_version, hw_id, vendor_id; + u32 version, length; + + set_default_result(info); + + fw_version = info->cap_info.fw_version; + fw_minor_version = info->cap_info.fw_minor_version; + reg_version = info->cap_info.reg_data_version; + hw_id = info->cap_info.hw_id; + /* vendor_id = ntohs(info->cap_info.vendor_id);*/ + version = (u32)((u32)(hw_id & 0xff) << 16) | ((fw_version & 0xf) << 12) + | ((fw_minor_version & 0xf) << 8) | (reg_version & 0xff); + + /* length = sizeof(vendor_id); + snprintf(finfo->cmd_buff, length + 1, "%s", (u8 *)&vendor_id); + snprintf(finfo->cmd_buff + length, sizeof(finfo->cmd_buff) - length, + "%06X", version);*/ + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; +} + +static void get_threshold(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + + set_default_result(info); + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), + "%d", info->cap_info.threshold); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; +} + +/* + static void get_key_threshold(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + int ret = 0; + u16 threshold; + + set_default_result(info); + + ret = read_data(misc_info->client, BT541_BUTTON_SENSITIVITY, (u8 *)&threshold, 2); + if (ret < 0) { + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", "fail"); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = FAIL; + return; + } + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%u", threshold); + + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + } + */ + + +static void module_off_master(void *device_data) +{ + return; +} + +static void module_on_master(void *device_data) +{ + return; +} + +static void module_off_slave(void *device_data) +{ + return; +} + +static void module_on_slave(void *device_data) +{ + return; +} + +#define BT541_VENDOR_NAME "ZINITIX" + +static void get_chip_vendor(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + + set_default_result(info); + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), + "%s", BT541_VENDOR_NAME); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; +} + +#define BT541_CHIP_NAME "BT541" + +static void get_chip_name(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + + set_default_result(info); + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", BT541_CHIP_NAME); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; +} + +#ifdef SUPPORTED_USE_DUAL_FW +static void get_module_vendor(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + int module_vendor =0; + + set_default_result(info); + + switch (info->cap_info.hw_id) { + case 0: + module_vendor = 0; + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s,%d", "OK", module_vendor); + break; + case 1: + module_vendor = 1; + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s,%d", "OK", module_vendor); + break; + default: + break; + } + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; +} +#endif + +static void get_x_num(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + + set_default_result(info); + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), + "%u", info->cap_info.x_node_num); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; +} + +static void get_y_num(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + + set_default_result(info); + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), + "%u", info->cap_info.y_node_num); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; +} + +static void not_support_cmd(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + + set_default_result(info); + + sprintf(finfo->cmd_buff, "%s", "NA"); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + info->factory_info->cmd_state = NOT_APPLICABLE; + + dev_info(&client->dev, "%s: \"%s(%d)\"\n", __func__, finfo->cmd_buff, + (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; +} + +#if 0 +static void run_reference_read(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + struct tsp_raw_data *raw_data = info->raw_data; + u16 min, max; + s32 i,j; + +#if ESD_TIMER_INTERVAL + esd_timer_stop(misc_info); +#endif + set_default_result(info); + + ts_set_touchmode(TOUCH_DND_MODE); + get_raw_data(info, (u8 *)raw_data->ref_data, 10); + ts_set_touchmode(TOUCH_POINT_MODE); + + min = 0xFFFF; + max = 0x0000; + + for (i = 0; i < info->cap_info.x_node_num; i++) + { + for (j = 0; j < info->cap_info.y_node_num; j++) + { + /*pr_info("ref_data : %d ", + raw_data->ref_data[i * info->cap_info.y_node_num + j]);*/ + + if (raw_data->ref_data[i * info->cap_info.y_node_num + j] < min && + raw_data->ref_data[i * info->cap_info.y_node_num + j] != 0) + min = raw_data->ref_data[i * info->cap_info.y_node_num + j]; + + if (raw_data->ref_data[i * info->cap_info.y_node_num + j] > max) + max = raw_data->ref_data[i * info->cap_info.y_node_num + j]; + + } + /*pr_info("\n");*/ + } + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%d,%d\n", min, max); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: \"%s\"(%d)\n", __func__, finfo->cmd_buff, + (int)strlen(finfo->cmd_buff)); + +#if ESD_TIMER_INTERVAL + esd_timer_start(CHECK_ESD_TIMER, misc_info); +#endif + return; +} +#endif +static bool run_reference_DND_read(void *device_data, int button0, int button1) //DND +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + int i, j, nButton; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + int buttons[2] = {button0,button1}; + bool result = true, item_result= true; + +#if ESD_TIMER_INTERVAL + esd_timer_stop(misc_info); +#endif + + set_default_result(info); + ts_set_touchmode(TOUCH_DND_MODE); + get_raw_data(info, (u8 *)info->pdnd_data, 5); + ts_set_touchmode(TOUCH_POINT_MODE); + + printk("DND_data =\n"); + for (i = 0; i < x_num; i++) { + for (j = 0; j < y_num; j++) { + printk("%d ", info->pdnd_data[j+i*y_num]); + } + printk("\n"); + } + + info->dnd_max_x = info->dnd_max_y = info->dnd_min_x = info->dnd_min_y = 0; + info->dnd_max_val = -32768; + info->dnd_min_val = 32767; + info->dnd_real_max_val = -32768; + info->dnd_real_min_val = 32767; + info->dnd_node_num = -1; + + for (i = 0; i < x_num-1; i++) { + for (j = 0; j < y_num; j++) { + if (info->dnd_real_min_val > info->pdnd_data[j+i*y_num]) { + info->dnd_real_min_x = i; + info->dnd_real_min_y = j; + info->dnd_real_min_val = info->pdnd_data[j+i*y_num]; + } + if (info->dnd_real_max_val < info->pdnd_data[j+i*y_num]) { + info->dnd_real_max_x = i; + info->dnd_real_max_y = j; + info->dnd_real_max_val = info->pdnd_data[j+i*y_num]; + } + + if ((info->pdnd_data[j+i*y_num] < pdnd_min[i][j]) && (info->pdnd_data[j+i*y_num] != 0)) { + printk(" DND View Min fail : NODE = %u, Raw data = %d, SPEC = %u\n", j+i*y_num, info->pdnd_data[j+i*y_num], pdnd_min[i][j]); + item_result = false; + result = false; + + if (info->dnd_node_num == -1) + info->dnd_node_num = j + (i * y_num); + } + if (info->dnd_min_val > info->pdnd_data[j+i*y_num] - pdnd_min[i][j]) { + info->dnd_min_x = i; + info->dnd_min_y = j; + info->dnd_min_val = info->pdnd_data[j+i*y_num] - pdnd_min[i][j]; + } + if (info->pdnd_data[j+i*y_num] > pdnd_max[i][j]) { + printk(" DND View Max fail : NODE = %u, Raw data = %d, SPEC = %u\n", j+i*y_num, info->pdnd_data[j+i*y_num], pdnd_max[i][j]); + item_result = false; + result = false; + + if (info->dnd_node_num == -1) + info->dnd_node_num = j + (i * y_num); + } + if (info->dnd_max_val < info->pdnd_data[j+i*y_num] - pdnd_max[i][j]) { + info->dnd_max_x = i; + info->dnd_max_y = j; + info->dnd_max_val = info->pdnd_data[j+i*y_num] - pdnd_max[i][j]; + } + } + } + + if (item_result) + printk("DND View pass\n"); + else + printk("DND View fail\n"); + + /*button*/ + item_result = true; + if (info->cap_info.button_num) { + for (i = 0; i < 2; i++) { + nButton = buttons[i]; + + if (nButton < 0) + continue; + + if (info->dnd_real_min_val > info->pdnd_data[(x_num-1)*y_num+nButton]) { + info->dnd_real_min_x = x_num-1; + info->dnd_real_min_y = nButton; + info->dnd_real_min_val = info->pdnd_data[(x_num-1)*y_num+nButton]; + } + + if (info->dnd_real_max_val < info->pdnd_data[(x_num-1)*y_num+nButton]) { + info->dnd_real_max_x = x_num-1; + info->dnd_real_max_y = nButton; + info->dnd_real_max_val = info->pdnd_data[(x_num-1)*y_num+nButton]; + } + + if (info->pdnd_data[(x_num-1)*y_num+nButton] < pdnd_min[x_num-1][nButton]) { + printk(" DND Button Min fail : NODE = %u, Raw data = %d, SPEC = %u\n", nButton, info->pdnd_data[(x_num-1)*y_num+nButton], pdnd_min[x_num-1][nButton]); + item_result = false; + result = false; + + if (info->dnd_node_num == -1) + info->dnd_node_num = ((x_num - 1) * y_num) + nButton; + } + + if (info->dnd_min_val > info->pdnd_data[(x_num-1)*y_num+nButton] - pdnd_min[x_num-1][nButton]) { + info->dnd_min_x = x_num-1; + info->dnd_min_y = nButton; + info->dnd_min_val = info->pdnd_data[(x_num-1)*y_num+nButton] - pdnd_min[x_num-1][nButton]; + } + + if (info->pdnd_data[(x_num-1)*y_num+nButton] > pdnd_max[x_num-1][nButton]) { + printk(" DND Button Max fail : NODE = %u, Raw data = %d, SPEC = %u\n", nButton, info->pdnd_data[(x_num-1)*y_num+nButton], pdnd_max[x_num-1][nButton]); + item_result = false; + result = false; + + if (info->dnd_node_num == -1) + info->dnd_node_num = ((x_num - 1) * y_num) + nButton; + } + + if (info->dnd_max_val < info->pdnd_data[(x_num-1)*y_num+nButton] - pdnd_max[x_num-1][nButton]) { + info->dnd_max_x = x_num-1; + info->dnd_max_y = nButton; + info->dnd_max_val = info->pdnd_data[(x_num-1)*y_num+nButton] - pdnd_max[x_num-1][nButton]; + } + } + } + + if (item_result) { + info->dnd_done = true; + printk("DND Button pass\n"); + } else { + info->dnd_done = false; + printk("DND Butoon fail\n"); + } + +#if ESD_TIMER_INTERVAL + esd_timer_start(CHECK_ESD_TIMER, misc_info); +#endif + + return result; +} + +static void run_reference_DND(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + bool temp; + + set_default_result(info); + + temp = run_reference_DND_read(device_data, 4, 7); + + if (temp) { + pr_info("DND pass\n"); + sprintf(finfo->cmd_buff, "OK\n"); + } else { + int x, y, node_num; + + node_num = info->dnd_node_num; + x = node_num / info->cap_info.y_node_num; + y = node_num % info->cap_info.y_node_num; + + pr_info("DND Fail\n"); + sprintf(finfo->cmd_buff, "%d,%d,%d,%d\n", + node_num, + pdnd_min[x][y], + pdnd_max[x][y], + info->pdnd_data[node_num]); + } + + finfo->cmd_state = OK; + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +} + +static bool run_reference_HFDND_read(void *device_data, int button0, int button1) //DND +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + int i, j, nButton; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + int buttons[2] = {button0,button1}; + bool result = true, item_result= true; + +#if ESD_TIMER_INTERVAL + esd_timer_stop(misc_info); +#endif + + set_default_result(info); + ts_set_touchmode2(TOUCH_DND_MODE); + get_raw_data(info, (u8 *)info->hfdnd_data, 5); + ts_set_touchmode(TOUCH_POINT_MODE); + + printk("HFDND_data =\n"); + for (i = 0; i < x_num; i++) { + for (j = 0; j < y_num; j++) { + printk("%d ", info->hfdnd_data[j+i*y_num]); + } + printk("\n"); + } + + info->hfdnd_max_x = info->hfdnd_max_y = info->hfdnd_min_x = info->hfdnd_min_y = 0; + info->hfdnd_max_val = -32768; + info->hfdnd_min_val = 32767; + info->hfdnd_real_max_val = -32768; + info->hfdnd_real_min_val = 32767; + info->hfdnd_node_num = -1; + + //MAX + for (i = 0; i < x_num-1; i++) { + for (j = 0; j < y_num; j++) { + if (info->hfdnd_real_min_val > info->hfdnd_data[j+i*y_num]) { + info->hfdnd_real_min_x = i; + info->hfdnd_real_min_y = j; + info->hfdnd_real_min_val = info->hfdnd_data[j+i*y_num]; + } + + if (info->hfdnd_real_max_val < info->hfdnd_data[j+i*y_num]) { + info->hfdnd_real_max_x = i; + info->hfdnd_real_max_y = j; + info->hfdnd_real_max_val = info->hfdnd_data[j+i*y_num]; + } + + if ((info->hfdnd_data[j+i*y_num] < hfdnd_min[i][j]) && (info->hfdnd_data[j+i*y_num] != 0)) { + printk(" HFDND View Min fail : NODE = %u,Raw data = %d, SPEC = %u\n", j+i*y_num, info->hfdnd_data[j+i*y_num], hfdnd_min[i][j]); + item_result = false; + result = false; + + if (info->hfdnd_node_num == -1) + info->hfdnd_node_num = j + (i * y_num); + } + + if (info->hfdnd_min_val > info->hfdnd_data[j+i*y_num] - hfdnd_min[i][j]) { + info->hfdnd_min_x = i; + info->hfdnd_min_y = j; + info->hfdnd_min_val = info->hfdnd_data[j+i*y_num] - hfdnd_min[i][j]; + } + + if (info->hfdnd_data[j+i*y_num] > hfdnd_max[i][j]) { + printk(" HFDND View Max fail : NODE = %u, Raw data = %d, SPEC = %u\n", j+i*y_num, info->hfdnd_data[j+i*y_num], hfdnd_max[i][j]); + item_result = false; + result = false; + + if (info->hfdnd_node_num == -1) + info->hfdnd_node_num = j + (i * y_num); + } + + if (info->hfdnd_max_val < info->hfdnd_data[j+i*y_num] - hfdnd_max[i][j]) { + info->hfdnd_max_x = i; + info->hfdnd_max_y = j; + info->hfdnd_max_val = info->hfdnd_data[j+i*y_num] - hfdnd_max[i][j]; + } + } + } + + if (item_result) + printk("HFDND View pass\n"); + else + printk("HFDND View Fail\n"); + + //button + item_result = true; + if (info->cap_info.button_num) { + for (i = 0; i < 2; i++) { + nButton = buttons[i]; + if (nButton < 0) + continue; + + if (info->hfdnd_real_min_val > info->hfdnd_data[(x_num-1)*y_num+nButton]) { + info->hfdnd_real_min_x = x_num-1; + info->hfdnd_real_min_y = nButton; + info->hfdnd_real_min_val = info->hfdnd_data[(x_num-1)*y_num+nButton]; + } + + if (info->hfdnd_real_max_val < info->hfdnd_data[(x_num-1)*y_num+nButton]) { + info->hfdnd_real_max_x = x_num-1; + info->hfdnd_real_max_y = nButton; + info->hfdnd_real_max_val = info->hfdnd_data[(x_num-1)*y_num+nButton]; + } + + if (info->hfdnd_data[(x_num-1)*y_num+nButton] < hfdnd_min[x_num-1][nButton]) { + printk(" HFDND Button Min fail : NODE = %u, Raw data = %d, SPEC = %u\n", nButton, info->hfdnd_data[(x_num-1)*y_num+nButton], hfdnd_min[x_num-1][nButton]); + item_result = false; + result = false; + + if (info->hfdnd_node_num == -1) + info->hfdnd_node_num = ((x_num - 1) * y_num) + nButton; + } + if (info->hfdnd_min_val > info->hfdnd_data[(x_num-1)*y_num+nButton] - hfdnd_min[x_num-1][nButton]) { + info->hfdnd_min_x = x_num-1; + info->hfdnd_min_y = nButton; + info->hfdnd_min_val = info->hfdnd_data[(x_num-1)*y_num+nButton] - hfdnd_min[x_num-1][nButton]; + } + if (info->hfdnd_data[(x_num-1)*y_num+nButton] > hfdnd_max[x_num-1][nButton]) { + printk(" HFDND Button Max fail : NODE = %u, Raw data = %d, SPEC = %u\n", nButton, info->hfdnd_data[(x_num-1)*y_num+nButton], hfdnd_min[x_num-1][nButton]); + item_result = false; + result = false; + + if (info->hfdnd_node_num == -1) + info->hfdnd_node_num = ((x_num - 1) * y_num) + nButton; + } + if (info->hfdnd_max_val < info->hfdnd_data[(x_num-1)*y_num+nButton] - hfdnd_min[x_num-1][nButton]) { + info->hfdnd_max_x = x_num-1; + info->hfdnd_max_y = nButton; + info->hfdnd_max_val = info->hfdnd_data[(x_num-1)*y_num+nButton] - hfdnd_min[x_num-1][nButton]; + } + } + } + + if (item_result) { + info->hfdnd_done = true; + printk("HFDND Button pass\n"); + } else { + info->hfdnd_done = false; + printk("HFDND Button fail\n"); + } + +#if ESD_TIMER_INTERVAL + esd_timer_start(CHECK_ESD_TIMER, misc_info); +#endif + + return result; +} + +static void run_reference_HFDND(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + bool temp; + + set_default_result(info); + + temp = run_reference_HFDND_read(device_data, 4, 7); + + if (temp) { + pr_info("HF DND pass\n"); + sprintf(finfo->cmd_buff, "OK\n"); + } else { + int x, y, node_num; + + node_num = info->hfdnd_node_num; + x = node_num / info->cap_info.y_node_num; + y = node_num % info->cap_info.y_node_num; + + pr_info("HF DND Fail\n"); + sprintf(finfo->cmd_buff, "%d,%d,%d,%d\n", + node_num, + hfdnd_min[x][y], + hfdnd_max[x][y], + info->hfdnd_data[node_num]); + } + + finfo->cmd_state = OK; + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +} + +static bool run_reference_V_Diff_read(void *device_data, int button0, int button1) //DND +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + + int print_diff[19*10]={0,}; + int buttons[2] = {button0,button1}; + int i, j, diff_val, pre_val, next_val, nButton; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + bool result = true, item_result = true; + + printk("TSP Diff test scale factor = %d\n",TSP_INIT_TEST_RATIO); + printk("V Diff start\n"); + + info->vdiff_max_x = info->vdiff_max_y = info->vdiff_min_x = info->vdiff_min_y = 0; + info->vdiff_max_val = -32768; + info->vdiff_min_val = 32767; + info->vdiff_node_num = -1; + + item_result = true; + for (i = 0; i < x_num-2; i++) { + for (j = 0; j < y_num; j++) { + //printk("%d ", info->pdnd_data[i*y_num+j]); + next_val = info->pdnd_data[(i*y_num)+j]; + pre_val = info->pdnd_data[(i*y_num)+j+y_num]; + diff_val = (next_val > pre_val)?(next_val - pre_val):(pre_val - next_val); + + printk(" %d ", diff_val); + + pre_val = (TSP_INIT_TEST_RATIO == 100)?((s16)dnd_v_diff[i][j]):((s16)(((s32)dnd_v_diff[i][j] * TSP_INIT_TEST_RATIO) /100)); + if (diff_val > pre_val) { + result = false; + item_result = false; + + if (info->vdiff_node_num == -1) { + info->vdiff_node_num = j + (i * y_num); + info->vdiff_diff_val = diff_val; + } + } +#if PDIFF_DEBUG + print_diff[i*y_num+j] = diff_val; +#endif + if (info->vdiff_max_val < diff_val) { + info->vdiff_max_val = diff_val; + info->vdiff_max_x = i; + info->vdiff_max_y= j; + } + if (info->vdiff_min_val > diff_val) { + info->vdiff_min_val = diff_val; + info->vdiff_min_x = i; + info->vdiff_min_y= j; + } + } + printk("\n"); + } + + if (item_result) + printk("V Diff view pass\n"); + else + printk("V Diff view fail\n"); + + item_result = true; + if ( info->cap_info.button_num) { + printk("TSP Button scale = %d\n", TSP_INIT_TEST_RATIO); + printk("TSP Button Diff Spec. = %d %d\n", + dnd_v_diff[x_num-2][buttons[0]], dnd_v_diff[x_num-2][buttons[1]]); + + for (i = 0; i < 2; i++) { + nButton = buttons[i]; + if (nButton < 0) + continue; + next_val = info->pdnd_data[(x_num-1)*y_num+nButton]; + pre_val = info->pdnd_data[(x_num-2)*y_num+nButton]; + diff_val = (next_val > pre_val)?(next_val - pre_val):(pre_val - next_val); + + pre_val = (TSP_INIT_TEST_RATIO == 100)?( (s16)dnd_v_diff[x_num-2][nButton]+info->ref_btn_option): \ + ((s16)(((s32)dnd_v_diff[x_num-2][nButton]*TSP_INIT_TEST_RATIO)/100)+info->ref_btn_option); + + if (diff_val > pre_val) { + item_result = false; + result = false; + + if (info->vdiff_node_num == -1) { + info->vdiff_node_num = ((x_num - 2) * y_num) + nButton; + info->vdiff_diff_val = diff_val; + } + } + if (info->vdiff_max_val < diff_val) { + info->vdiff_max_val = diff_val; + info->vdiff_max_x = x_num - 1; + info->vdiff_max_y= nButton; + } + if (info->vdiff_min_val >diff_val) { + info->vdiff_min_val = diff_val; + info->vdiff_min_x = x_num - 1; + info->vdiff_min_y= nButton; + } +#if PDIFF_DEBUG + printk("buttons[%d]'s diff_val is %d\n", i, diff_val); +#endif + } + } + + if (item_result) + printk("Button V Diff pass\n"); + else + printk("Button V Diff fail\n"); + + return result; +} + +static void run_reference_V_Diff(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + bool temp; + + set_default_result(info); + + temp = run_reference_V_Diff_read(device_data, 4, 7); + + if (temp) { + pr_info("V Diff pass\n"); + sprintf(finfo->cmd_buff, "OK\n"); + } else { + int x, y, node_num; + + node_num = info->dnd_node_num; + x = node_num / info->cap_info.y_node_num; + y = node_num % info->cap_info.y_node_num; + + pr_info("V Diff Fail\n"); + sprintf(finfo->cmd_buff, "%d,%d,%d,%d\n", + node_num, + 0, + dnd_v_diff[x][y], + info->vdiff_diff_val); + } + + finfo->cmd_state = OK; + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +} + +static bool run_reference_H_Diff_read(void *device_data, int button0, int button1) //DND +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + + int print_diff[19*10]={0,}; + int buttons[2] = {button0,button1}; + int i, j, diff_val, pre_val, next_val; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + bool result = true, item_result = true; + + printk("TSP Diff test scale factor = %d\n",TSP_INIT_TEST_RATIO); + printk("Diff start\n"); + //H DIff + info->hdiff_max_x = info->hdiff_max_y = info->hdiff_min_x = info->hdiff_min_y = 0; + info->hdiff_max_val = -32768; + info->hdiff_min_val = 32767; + info->hdiff_node_num = -1; + + for (i = 0; i < x_num - 1; i++) { + for (j = 0; j < y_num-1; j++) { + //printk("%d ", info->dnd_data[i*y_num+j]); + next_val = info->pdnd_data[(i*y_num)+(j+1)]; + pre_val = info->pdnd_data[(i*y_num)+j]; + diff_val = (next_val > pre_val)?(next_val - pre_val):(pre_val - next_val); + + printk("%d ", diff_val); + + pre_val = (TSP_INIT_TEST_RATIO== 100)?((s16)dnd_h_diff[i][j]):((s16)(((s32)dnd_h_diff[i][j] * TSP_INIT_TEST_RATIO) /100)); + if (diff_val > pre_val) { + result = false; + item_result = false; + + if (info->hdiff_node_num == -1) { + info->hdiff_node_num = j + (i * y_num); + info->hdiff_diff_val = diff_val; + } + } +#if PDIFF_DEBUG + print_diff[i*y_num+j] = diff_val; +#endif + if (info->hdiff_max_val < diff_val) { + info->hdiff_max_val = diff_val; + info->hdiff_max_x = i; + info->hdiff_max_y= j; + } + if (info->hdiff_min_val > diff_val) { + info->hdiff_min_val = diff_val; + info->hdiff_min_x = i; + info->hdiff_min_y= j; + } + } + printk("\n"); + } + + if (item_result) + printk("H Diff pass\n"); + else + printk("H Diff fail\n"); + + item_result = true; + if (info->cap_info.button_num) { + printk("TSP Button scale = %d\n", TSP_INIT_TEST_RATIO); + printk("TSP Button Diff Spec. = %d %d\n", + dnd_v_diff[x_num-2][buttons[0]], dnd_v_diff[x_num-2][buttons[1]]); + + pre_val = info->pdnd_data[(x_num-1)*y_num+button0]; + next_val = info->pdnd_data[(x_num-1)*y_num+button1]; + diff_val = (next_val > pre_val)?(next_val - pre_val):(pre_val - next_val); + + pre_val = (TSP_INIT_TEST_RATIO == 100)?( (s16)dnd_h_diff[x_num-1][button1]+info->ref_btn_option): \ + ((s16)(((s32)dnd_h_diff[x_num-1][button1]*TSP_INIT_TEST_RATIO)/100)+info->ref_btn_option); + + if (diff_val > pre_val) { + item_result = false; + result = false; + + if (info->hdiff_node_num == -1) { + info->hdiff_node_num = ((x_num - 1) * y_num) + button1; + info->hdiff_diff_val = diff_val; + } + } + if (info->hdiff_max_val < diff_val) { + info->hdiff_max_val = diff_val; + info->hdiff_max_x = x_num - 1; + info->hdiff_max_y= button1; + } + if (info->hdiff_min_val >diff_val) { + info->hdiff_min_val = diff_val; + info->hdiff_min_x = x_num - 1; + info->hdiff_min_y= button1; + } + } + + if (item_result) + printk("Button H Diff pass\n"); + else + printk("Button H Diff fail\n"); + + return result; +} + +static void run_reference_H_Diff(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + bool temp; + u8 *ret_string; + + set_default_result(info); + + temp = run_reference_H_Diff_read(device_data, 4, 7); + + if (temp) + ret_string = "H Diff pass"; + else + ret_string = "H Diff Fail"; + + if (temp) { + pr_info("H Diff pass\n"); + sprintf(finfo->cmd_buff, "OK\n"); + } else { + int x, y, node_num; + + node_num = info->hfdnd_node_num; + x = node_num / info->cap_info.y_node_num; + y = node_num % info->cap_info.y_node_num; + + pr_info("H Diff Fail\n"); + sprintf(finfo->cmd_buff, "%d,%d,%d,%d\n", + node_num, + 0, + dnd_h_diff[x][y], + info->hdiff_diff_val); + } + + finfo->cmd_state = OK; + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +} + +static void get_reference_DND(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + char buff[19*7] = {0}; + // char tmp[16] = {0}; + int x_node, y_node; + int node_num; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + + set_default_result(info); + + if (!info->dnd_done) + run_reference_DND_read(device_data, 4, 7); + + x_node = finfo->cmd_param[0]; + y_node = finfo->cmd_param[1]; + + if (x_node < 0 || x_node >= x_num || y_node < 0 || y_node >= y_num) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + finfo->cmd_state = FAIL; + return; + } + /* + for (i = 0; i < x_num-1; i++) { + node_num = i*y_num + y_node; + sprintf(tmp, "%d", info->pdnd_data[node_num]); + strcat(buff, tmp); + if (i < x_num-2) + strcat(buff, " "); + } + */ + node_num = (x_node * y_num) + y_node; + + sprintf(finfo->cmd_buff, "%d", info->pdnd_data[node_num]); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, (int)strnlen(buff, sizeof(buff))); + + return; +} + +/* + static void get_reference_max_H_Diff(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + int H_diff[19*9] = {0}; + int i, j, diff_val, pre_val, next_val; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + int max_hdiff = 0; + + set_default_result(info); + + if (!info->dnd_done) + run_reference_DND_read(device_data, 4, 7); + + printk("H Diff start\n"); +//H DIff +for (i = 0; i < x_num - 1; i++) { +for (j = 0; j <y_num-1; j++) { +next_val = info->pdnd_data[(i*y_num)+(j+1)]; +pre_val = info->pdnd_data[(i*y_num)+j]; +diff_val = (next_val > pre_val)?(next_val - pre_val):(pre_val - next_val); + +printk("%4d ", diff_val); +H_diff[i*(y_num-1)+j] = diff_val; +if ((i == 0) && (j == 0)) +max_hdiff = diff_val; +else { +if (max_hdiff < diff_val) +max_hdiff = diff_val; +} +} +printk("\n"); +} + + +sprintf(finfo->cmd_buff, "%d", max_hdiff); +set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +finfo->cmd_state = OK; + +dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, +finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +} + */ + +static void get_reference_H_Diff(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + int H_diff[19*9] = {0}; + //char tmp[10] = {0}; + int x_node, y_node; + int node_num; + int i, j, diff_val, pre_val, next_val; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + + set_default_result(info); + + if (!info->dnd_done) + run_reference_DND_read(device_data, 4, 7); + + printk("H Diff start\n"); + //H DIff + for (i = 0; i < x_num - 1; i++) { + for (j = 0; j < y_num-1; j++) { + next_val = info->pdnd_data[(i*y_num)+(j+1)]; + pre_val = info->pdnd_data[(i*y_num)+j]; + diff_val = (next_val > pre_val)?(next_val - pre_val):(pre_val - next_val); + + printk("%4d ", diff_val); + H_diff[i*(y_num-1)+j] = diff_val; + } + printk("\n"); + } + + x_node = finfo->cmd_param[0]; + y_node = finfo->cmd_param[1]; + + if (x_node < 0 || x_node >= x_num || y_node < 0 || y_node >= y_num) { + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", "NG"); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = FAIL; + return; + } + /* + for (i = 0; i < x_num-1; i++) { + node_num = i*(y_num-1) + y_node; + sprintf(tmp, "%d", H_diff[node_num]); + strcat(finfo->cmd_buff, tmp); + if (i < x_num-2) + strcat(finfo->cmd_buff, " "); + } + */ + node_num = (x_node * y_num) + y_node; + + sprintf(finfo->cmd_buff, "%d", H_diff[node_num]); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +} + +/* + static void get_reference_max_V_Diff(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + int V_Diff[19*10] = {0}; + int buttons[2] = {4,7}; + int i, j, pre_val, next_val, nButton; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + int diff_val = 0, max_vdiff = 0; + + set_default_result(info); + + if (!info->dnd_done) + run_reference_DND_read(device_data, 4, 7); + + for (i = 0; i < x_num-2; i++) { + for (j=0; j < y_num; j++) { + next_val = info->pdnd_data[(i*y_num)+j]; + pre_val = info->pdnd_data[(i*y_num)+j+y_num]; + diff_val = (next_val > pre_val)?(next_val - pre_val):(pre_val - next_val); + + printk(" %4d ", diff_val); + V_Diff[i*y_num+j] = diff_val; + if ((i == 0) && (j == 0)) + max_vdiff = diff_val; + else { + if (max_vdiff < diff_val) + max_vdiff = diff_val; + } + } + printk("\n"); + } + +//V DIff button +if ( info->cap_info.button_num) { +for (i = 0; i < 2; i++) { +nButton = buttons[i]; +if (nButton < 0) +continue; +next_val = info->pdnd_data[(x_num-1)*y_num+nButton]; +pre_val = info->pdnd_data[(x_num-2)*y_num+nButton]; +diff_val = (next_val > pre_val)?(next_val - pre_val):(pre_val - next_val); +V_Diff[(x_num-1)*y_num + nButton] = diff_val; +if (max_vdiff < diff_val) +max_vdiff = diff_val; +} +} + +sprintf(finfo->cmd_buff, "%d", diff_val); +set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +finfo->cmd_state = OK; + +dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, +finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +} + */ + +static void get_reference_V_Diff(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + /*char tmp[10] = {0};*/ + int V_Diff[19*10] = {0}; + int x_node, y_node; + int node_num; + int buttons[2] = {4,7}; + int i, j, diff_val, pre_val, next_val, nButton; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + + set_default_result(info); + + if (!info->dnd_done) + run_reference_DND_read(device_data, 4, 7); + + for (i = 0; i < x_num-2; i++) { + for (j = 0; j < y_num; j++) { + next_val = info->pdnd_data[(i*y_num)+j]; + pre_val = info->pdnd_data[(i*y_num)+j+y_num]; + diff_val = (next_val > pre_val)?(next_val - pre_val):(pre_val - next_val); + + printk(" %d ", diff_val); + V_Diff[i*y_num+j] = diff_val; + } + printk("\n"); + } + + //V DIff button + if ( info->cap_info.button_num) { + for (i = 0; i < 2; i++) { + nButton = buttons[i]; + if (nButton < 0) + continue; + next_val = info->pdnd_data[(x_num-1)*y_num+nButton]; + pre_val = info->pdnd_data[(x_num-2)*y_num+nButton]; + diff_val = (next_val > pre_val)?(next_val - pre_val):(pre_val - next_val); + V_Diff[(x_num-1)*y_num + nButton] = diff_val; + } + } + + x_node = finfo->cmd_param[0]; + y_node = finfo->cmd_param[1]; + + if (x_node < 0 || x_node >= x_num || y_node < 0 || y_node >= y_num) { + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", "NG"); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = FAIL; + return; + } + /* + for (i = 0; i < x_num-2; i++) { + node_num = i*y_num + y_node; + sprintf(tmp, "%d", V_Diff[node_num]); + strcat(finfo->cmd_buff, tmp); + if (i < x_num-3) + strcat(finfo->cmd_buff, " "); + } + */ + node_num = (x_node * y_num) + y_node; + + sprintf(finfo->cmd_buff, "%d", V_Diff[node_num]); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +} + +static void get_reference_HFDND(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + char buff[512] = {0}; + // char tmp[16] = {0}; + int x_node, y_node; + int node_num; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + + set_default_result(info); + + if (!info->hfdnd_done) + run_reference_HFDND_read(device_data, 4, 7); + + x_node = finfo->cmd_param[0]; + y_node = finfo->cmd_param[1]; + + if (x_node < 0 || x_node >= x_num || y_node < 0 || y_node >= y_num) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + finfo->cmd_state = FAIL; + return; + } + /* + for (i = 0; i < x_num-1; i++) { + node_num = i*y_num + y_node; + sprintf(tmp, "%d", info->hfdnd_data[node_num]); + strcat(buff, tmp); + if (i < x_num-2) + strcat(buff, " "); + } + */ + node_num = (x_node * y_num) + y_node; + + sprintf(finfo->cmd_buff, "%d", info->hfdnd_data[node_num]); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, (int)strnlen(buff, sizeof(buff))); + + return; +} + +/* + static void get_max_dnd(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + set_default_result(info); + + if (!info->dnd_done) + run_reference_DND_read(device_data, 4, 7); + + sprintf(finfo->cmd_buff, "%d", info->dnd_real_max_val); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + } + */ + +/* + static void get_min_dnd(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + set_default_result(info); + + if (!info->dnd_done) + run_reference_DND_read(device_data, 4, 7); + + sprintf(finfo->cmd_buff, "%d", info->dnd_real_min_val); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + } + */ + +/* + static void get_max_hfdnd(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + s16 val[3] = {0}; + + set_default_result(info); + + val[0] = info->hfdnd_max_x; + val[1] = info->hfdnd_max_y; + val[2] = info->hfdnd_max_val; + + memcpy(finfo->cmd_buff, (char*)val, sizeof(finfo->cmd_buff)); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + } + */ + +/* + static void get_min_hfdnd(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + s16 val[3] = {0}; + + set_default_result(info); + + val[0] = info->hfdnd_min_x; + val[1] = info->hfdnd_min_y; + val[2] = info->hfdnd_min_val; + + memcpy(finfo->cmd_buff, (char*)val, sizeof(finfo->cmd_buff)); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + } + */ + +/* + static void get_max_hdiff(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + s16 val[3] = {0}; + + set_default_result(info); + + val[0] = info->hdiff_max_x; + val[1] = info->hdiff_max_y; + val[2] = info->hdiff_max_val; + + sprintf(finfo->cmd_buff, "%d", info->hdiff_max_val); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + } + */ + +/* + static void get_min_hdiff(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + s16 val[3] = {0}; + + set_default_result(info); + + val[0] = info->hdiff_min_x; + val[1] = info->hdiff_min_y; + val[2] = info->hdiff_min_val; + + sprintf(finfo->cmd_buff, "%d", info->hdiff_min_val); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + } + */ + +/* + static void get_max_vdiff(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + s16 val[3] = {0}; + + set_default_result(info); + + val[0] = info->vdiff_max_x; + val[1] = info->vdiff_max_y; + val[2] = info->vdiff_max_val; + + memcpy(finfo->cmd_buff, (char*)val, sizeof(finfo->cmd_buff)); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + } + */ + +/* + static void get_min_vdiff(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + s16 val[3] = {0}; + + set_default_result(info); + + val[0] = info->vdiff_min_x; + val[1] = info->vdiff_min_y; + val[2] = info->vdiff_min_val; + + memcpy(finfo->cmd_buff, (char*)val, sizeof(finfo->cmd_buff)); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + } + */ + +/* + static void get_reference(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + struct tsp_raw_data *raw_data = info->raw_data; + unsigned int val; + int x_node, y_node; + int node_num; + + set_default_result(info); + + x_node = finfo->cmd_param[0]; + y_node = finfo->cmd_param[1]; + + if (x_node < 0 || x_node >= info->cap_info.x_node_num || + y_node < 0 || y_node >= info->cap_info.y_node_num) { + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", "abnormal"); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = FAIL; + return; + } + + node_num = x_node * info->cap_info.y_node_num + y_node; + + val = raw_data->ref_data[node_num]; + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%u", val); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; + } + */ + +#if 0 +static void run_preference_read(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + struct tsp_raw_data *raw_data = info->raw_data; + u16 min, max; + s32 i,j; + + set_default_result(info); + + ts_set_touchmode(TOUCH_PDND_MODE); + get_raw_data(info, (u8 *)raw_data->pref_data, 10); + ts_set_touchmode(TOUCH_POINT_MODE); + + min = 0xFFFF; + max = 0x0000; + + for (i = 0; i < info->cap_info.x_node_num; i++) + { + for (j = 0; j < info->cap_info.y_node_num; j++) + { + /*pr_info("pref_data : %d ", + raw_data->pref_data[i * info->cap_info.y_node_num + j]);*/ + + if (raw_data->pref_data[i * info->cap_info.y_node_num + j] < min && + raw_data->pref_data[i * info->cap_info.y_node_num + j] != 0) + min = raw_data->pref_data[i * info->cap_info.y_node_num + j]; + + if (raw_data->pref_data[i * info->cap_info.y_node_num + j] > max) + max = raw_data->pref_data[i * info->cap_info.y_node_num + j]; + + } + /*pr_info("\n");*/ + } + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%d,%d\n", min, max); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: \"%s\"(%d)\n", __func__, finfo->cmd_buff, + strlen(finfo->cmd_buff)); + + return; +} + +static void get_preference(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + struct tsp_raw_data *raw_data = info->raw_data; + unsigned int val; + int x_node, y_node; + int node_num; + + set_default_result(info); + + x_node = finfo->cmd_param[0]; + y_node = finfo->cmd_param[1]; + + if (x_node < 0 || x_node >= info->cap_info.x_node_num || + y_node < 0 || y_node >= info->cap_info.y_node_num) { + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", "abnormal"); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + info->factory_info->cmd_state = FAIL; + + return; + } + + node_num = x_node * info->cap_info.y_node_num + y_node; + + val = raw_data->pref_data[node_num]; + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%u", val); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; +} +/* + static void run_scantime_read(void *device_data) + { + return; + } + + static void get_scantime(void *device_data) + { + return; + } + */ + +static void run_normal_read(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + set_default_result(info); + ts_set_touchmode(TOUCH_NORMAL_MODE); + get_raw_data(info, (u8 *)info->normal_data, 5); + ts_set_touchmode(TOUCH_POINT_MODE); + finfo->cmd_state = OK; +} +#endif + +#if 0 +static void run_delta_read(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + struct tsp_raw_data *raw_data = info->raw_data; + s16 min, max; + s32 i,j; + + set_default_result(info); + + ts_set_touchmode(TOUCH_DELTA_MODE); + get_raw_data(info, (u8 *)(u8 *)raw_data->delta_data, 5); + ts_set_touchmode(TOUCH_POINT_MODE); + finfo->cmd_state = OK; + + min = (s16)0x7FFF; + max = (s16)0x8000; + + for (i = 0; i < info->cap_info.x_node_num; i++) + { + for (j = 0; j < info->cap_info.y_node_num; j++) + { + /*printk("delta_data : %d\n", raw_data->delta_data[j+i]);*/ + + if (raw_data->delta_data[i * info->cap_info.y_node_num + j] < min && + raw_data->delta_data[i * info->cap_info.y_node_num + j] != 0) + min = raw_data->delta_data[i * info->cap_info.y_node_num + j]; + + if (raw_data->delta_data[i * info->cap_info.y_node_num + j] > max) + max = raw_data->delta_data[i * info->cap_info.y_node_num + j]; + + } + /*printk("\n");*/ + } + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%d,%d\n", min, max); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: \"%s\"(%d)\n", __func__, finfo->cmd_buff, + (int)strlen(finfo->cmd_buff)); + + return; +} +#endif + +/* + static void get_reference_RxDND(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + int y_node, i; + int node_num; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + s16 val[20] = {0}; + char buff[40] = {0}; + + set_default_result(info); + + y_node = finfo->cmd_param[0]; + + if (y_node < 0 || y_node > y_num) { + snprintf(buff, sizeof(buff), "%s", "abnormal"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + finfo->cmd_state = FAIL; + return; + } + + for (i = 0; i < x_num; i++) { + node_num = i*y_num + y_node; + val[i] = info->pdnd_data[node_num]; + } + + memcpy(buff, (char*)val, sizeof(buff)); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + finfo->cmd_state = OK; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, (int)strnlen(buff, sizeof(buff))); + } + */ + +/* + static void get_reference_RxHFDND(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + char buff[40] = {0}; + s16 val[20] = {0}; + int y_node, i; + int node_num; + int x_num = info->cap_info.x_node_num, y_num = info->cap_info.y_node_num; + + set_default_result(info); + + y_node = finfo->cmd_param[0]; + + if (y_node < 0 || y_node > y_num) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + finfo->cmd_state = FAIL; + return; + } + + for (i = 0; i < x_num; i++) { + node_num = i*y_num + y_node; + val[i] = info->hfdnd_data[node_num]; + } + + memcpy(buff, (char*)val, sizeof(buff)); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + finfo->cmd_state = OK; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, (int)strnlen(buff, sizeof(buff))); + } + */ + +/* + static void get_delta(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + struct tsp_raw_data *raw_data = info->raw_data; + unsigned int val; + int x_node, y_node; + int node_num; + + set_default_result(info); + + x_node = finfo->cmd_param[0]; + y_node = finfo->cmd_param[1]; + + if (x_node < 0 || x_node >= info->cap_info.x_node_num || + y_node < 0 || y_node >= info->cap_info.y_node_num) { + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", "abnormal"); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = FAIL; + + return; + } + + node_num = x_node * info->cap_info.y_node_num + y_node; + + val = raw_data->delta_data[node_num]; + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%u", val); + set_cmd_result(info, finfo->cmd_buff, + strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, finfo->cmd_buff, + (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + + return; + } + */ + +/* + static void get_tkey_delta(void *device_data) + { + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct tsp_factory_info *finfo = info->factory_info; + + u16 val; + int btn_node; + int ret; + + set_default_result(info); + + btn_node = finfo->cmd_param[0]; + + if (btn_node < 0 || btn_node > MAX_SUPPORTED_BUTTON_NUM) + goto err_out; + + disable_irq(misc_info->irq); + down(&misc_info->work_lock); + if (misc_info->work_state != NOTHING) { + printk(KERN_INFO "other process occupied.. (%d)\n", + misc_info->work_state); + enable_irq(misc_info->irq); + up(&misc_info->work_lock); + goto err_out; + } + misc_info->work_state = SET_MODE; + + ret = read_data(misc_info->client, BT541_BTN_WIDTH + btn_node, (u8 *)&val, 2); + + if (ret < 0) { + printk(KERN_INFO "read error..\n"); + enable_irq(misc_info->irq); + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + goto err_out; + } + misc_info->work_state = NOTHING; + enable_irq(misc_info->irq); + up(&misc_info->work_lock); + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%u", val); + set_cmd_result(info, finfo->cmd_buff, strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + return; + +err_out: +snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", "NG"); +set_cmd_result(info, finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); +finfo->cmd_state = FAIL; +} + */ + +static void hfdnd_spec_adjust(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + int test; + + set_default_result(info); + + test = finfo->cmd_param[0]; + + if (test) { + dnd_v_diff = assy_dnd_v_diff; + dnd_h_diff = assy_dnd_h_diff; + pdnd_max = assy_pdnd_max; + pdnd_min = assy_pdnd_min; + hfdnd_max = assy_hfdnd_max; + hfdnd_min = assy_hfdnd_min; + } else { + dnd_v_diff = tsp_dnd_v_diff; + dnd_h_diff = tsp_dnd_h_diff; + pdnd_max = tsp_pdnd_max; + pdnd_min = tsp_pdnd_min; + hfdnd_max = tsp_hfdnd_max; + hfdnd_min = tsp_hfdnd_min; + } + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", "OK"); + set_cmd_result(info, finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, + finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + return; +} + +static void clear_reference_data(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + + set_default_result(info); + +#if ESD_TIMER_INTERVAL + esd_timer_stop(info); + write_reg(client, BT541_PERIODICAL_INTERRUPT_INTERVAL, 0); +#endif + + write_reg(client, BT541_EEPROM_INFO_REG, 0xffff); + + write_reg(client, 0xc003, 0x0001); + write_reg(client, 0xc104, 0x0001); + udelay(100); + if (write_cmd(client, BT541_SAVE_STATUS_CMD) != I2C_SUCCESS) + return; + + mdelay(500); + write_reg(client, 0xc003, 0x0000); + write_reg(client, 0xc104, 0x0000); + udelay(100); + +#if ESD_TIMER_INTERVAL + write_reg(client, BT541_PERIODICAL_INTERRUPT_INTERVAL, + SCAN_RATE_HZ * ESD_TIMER_INTERVAL); + esd_timer_start(CHECK_ESD_TIMER, info); +#endif + dev_info(&client->dev, "%s: TSP clear calibration bit\n", __func__); + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", "OK"); + set_cmd_result(info, finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, + finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + return; +} + +static void run_ref_calibration(void *device_data) +{ + struct bt541_ts_info *info = (struct bt541_ts_info *)device_data; + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + int i; + + set_default_result(info); + +#if ESD_TIMER_INTERVAL + esd_timer_stop(info); + write_reg(client, BT541_PERIODICAL_INTERRUPT_INTERVAL, 0); +#endif + + write_reg(client, 0x01CA, 1300); + if (ts_hw_calibration(info) == true) + dev_info(&client->dev, "%s: TSP calibration Pass\n", __func__); + else + dev_info(&client->dev, "%s: TSP calibration Fail\n", __func__); + + write_reg(client, 0x01CA, 0); + write_reg(client, 0x0149, 0); + + for (i = 0; i < 5; i++) { + write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + udelay(10); + } + +#if ESD_TIMER_INTERVAL + write_reg(client, BT541_PERIODICAL_INTERRUPT_INTERVAL, + SCAN_RATE_HZ * ESD_TIMER_INTERVAL); + esd_timer_start(CHECK_ESD_TIMER, info); +#endif + + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "%s", "OK"); + set_cmd_result(info, finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + finfo->cmd_state = OK; + + dev_info(&client->dev, "%s: %s(%d)\n", __func__, + finfo->cmd_buff, (int)strnlen(finfo->cmd_buff, sizeof(finfo->cmd_buff))); + return; +} + +static ssize_t store_cmd(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct bt541_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + char *cur, *start, *end; + char buff[TSP_CMD_STR_LEN] = {0}; + int len, i; + struct tsp_cmd *tsp_cmd_ptr = NULL; + char delim = ','; + bool cmd_found = false; + int param_cnt = 0; + + if (finfo->cmd_is_running == true) { + dev_err(&client->dev, "%s: other cmd is running\n", __func__); + goto err_out; + } + + /* check lock */ + mutex_lock(&finfo->cmd_lock); + finfo->cmd_is_running = true; + mutex_unlock(&finfo->cmd_lock); + + finfo->cmd_state = RUNNING; + + for (i = 0; i < ARRAY_SIZE(finfo->cmd_param); i++) + finfo->cmd_param[i] = 0; + + len = (int)count; + if (*(buf + len - 1) == '\n') + len--; + + memset(finfo->cmd, 0x00, ARRAY_SIZE(finfo->cmd)); + memcpy(finfo->cmd, buf, len); + + cur = strchr(buf, (int)delim); + if (cur) + memcpy(buff, buf, cur - buf); + else + memcpy(buff, buf, len); + + /* find command */ + list_for_each_entry(tsp_cmd_ptr, &finfo->cmd_list_head, list) { + if (!strcmp(buff, tsp_cmd_ptr->cmd_name)) { + cmd_found = true; + break; + } + } + + /* set not_support_cmd */ + if (!cmd_found) { + list_for_each_entry(tsp_cmd_ptr, &finfo->cmd_list_head, list) { + if (!strcmp("not_support_cmd", tsp_cmd_ptr->cmd_name)) + break; + } + } + + /* parsing parameters */ + if (cur && cmd_found) { + cur++; + start = cur; + memset(buff, 0x00, ARRAY_SIZE(buff)); + do { + if (*cur == delim || cur - buf == len) { + end = cur; + memcpy(buff, start, end - start); + *(buff + strlen(buff)) = '\0'; + finfo->cmd_param[param_cnt] = + (int)simple_strtol(buff, NULL, 10); + start = cur + 1; + memset(buff, 0x00, ARRAY_SIZE(buff)); + param_cnt++; + } + cur++; + } while (cur - buf <= len); + } + + dev_info(&client->dev, "cmd = %s\n", tsp_cmd_ptr->cmd_name); + /* for (i = 0; i < param_cnt; i++) + dev_info(&client->dev, "cmd param %d= %d\n", i, finfo->cmd_param[i]);*/ + + tsp_cmd_ptr->cmd_func(info); + + mutex_lock(&finfo->cmd_lock); + finfo->cmd_is_running = false; + mutex_unlock(&finfo->cmd_lock); + +err_out: + return count; +} + +static ssize_t show_cmd_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct bt541_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + + dev_info(&client->dev, "tsp cmd: status:%d\n", finfo->cmd_state); + + if (finfo->cmd_state == WAITING) + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "WAITING"); + + else if (finfo->cmd_state == RUNNING) + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "RUNNING"); + + else if (finfo->cmd_state == OK) + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "OK"); + + else if (finfo->cmd_state == FAIL) + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "FAIL"); + + else if (finfo->cmd_state == NOT_APPLICABLE) + snprintf(finfo->cmd_buff, sizeof(finfo->cmd_buff), "NOT_APPLICABLE"); + + return snprintf(buf, sizeof(finfo->cmd_buff), + "%s\n", finfo->cmd_buff); +} + +static ssize_t show_cmd_result(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct bt541_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + struct tsp_factory_info *finfo = info->factory_info; + + dev_info(&client->dev, "tsp cmd: result: %s\n", finfo->cmd_result); + + finfo->cmd_state = WAITING; + + return snprintf(buf, sizeof(finfo->cmd_result), + "%s\n", finfo->cmd_result); +} + +static DEVICE_ATTR(cmd, S_IWUSR | S_IWGRP, NULL, store_cmd); +static DEVICE_ATTR(cmd_status, S_IRUGO, show_cmd_status, NULL); +static DEVICE_ATTR(cmd_result, S_IRUGO, show_cmd_result, NULL); + +static struct attribute *touchscreen_attributes[] = { + &dev_attr_cmd.attr, + &dev_attr_cmd_status.attr, + &dev_attr_cmd_result.attr, + NULL, +}; + +static struct attribute_group touchscreen_attr_group = { + .attrs = touchscreen_attributes, +}; + +#ifdef SUPPORTED_TOUCH_KEY +static ssize_t show_touchkey_threshold(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bt541_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + struct capa_info *cap = &(info->cap_info); + +#ifdef NOT_SUPPORTED_TOUCH_DUMMY_KEY + dev_info(&client->dev, "%s: key threshold = %d\n", __func__, + cap->key_threshold); + + return snprintf(buf, 41, "%d", cap->key_threshold); +#else + dev_info(&client->dev, "%s: key threshold = %d %d %d %d\n", __func__, + cap->dummy_threshold, cap->key_threshold, cap->key_threshold, cap->dummy_threshold); + + return snprintf(buf, 41, "%d %d %d %d", cap->dummy_threshold, + cap->key_threshold, cap->key_threshold, + cap->dummy_threshold); +#endif +} +#if 0 +static ssize_t enable_dummy_key(struct device *dev, + struct device_attribute *attr, char *buf, size_t count) +{ + static char enable = '0'; + struct bt541_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + + if (!strcmp(buf, "")) + count = sprintf(buf, "%c", enable); + else { + if ((buf[0] - '0' <= 1) && count == 2) + enable = *buf; + else { + dev_err(&client->dev, "%s: Invalid parameter\n", __func__); + + goto err_out; + } + } + + dev_info(&client->dev, "%s: Extra button event %c\n", __func__, enable); + + return count; + +err_out: + return sprintf(buf, "NG"); + + return 0; +} +#endif + +static ssize_t show_touchkey_sensitivity(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bt541_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + u16 val = 0; + int ret; + int i; + +#ifdef NOT_SUPPORTED_TOUCH_DUMMY_KEY + if (!strcmp(attr->attr.name, "touchkey_recent")) + i = 0; + else if (!strcmp(attr->attr.name, "touchkey_back")) + i = 1; + else { + dev_err(&client->dev, "%s: Invalid attribute\n", __func__); + + goto err_out; + } + +#else + if (!strcmp(attr->attr.name, "touchkey_dummy_btn1")) + i = 0; + else if (!strcmp(attr->attr.name, "touchkey_recent")) + i = 1; + else if (!strcmp(attr->attr.name, "touchkey_back")) + i = 2; + else if (!strcmp(attr->attr.name, "touchkey_dummy_btn4")) + i = 3; + else if (!strcmp(attr->attr.name, "touchkey_dummy_btn5")) + i = 4; + else if (!strcmp(attr->attr.name, "touchkey_dummy_btn6")) + i = 5; + else { + dev_err(&client->dev, "%s: Invalid attribute\n", __func__); + + goto err_out; + } +#endif + ret = read_data(client, BT541_BTN_WIDTH + i, (u8 *)&val, 2); + if (ret < 0) { + dev_err(&client->dev, "%s: Failed to read %d's key sensitivity\n", + __func__, i); + + goto err_out; + } + + dev_info(&client->dev, "%s: %d's key sensitivity = %d\n", + __func__, i, val); + + return snprintf(buf, 6, "%d", val); + +err_out: + return sprintf(buf, "NG"); +} + +static ssize_t show_back_key_raw_data(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t show_menu_key_raw_data(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} +/* + static ssize_t show_back_key_idac_data(struct device *dev, + struct device_attribute *attr, char *buf) + { + return 0; + } + + static ssize_t show_menu_key_idac_data(struct device *dev, + struct device_attribute *attr, char *buf) + { + return 0; + } + */ + +static DEVICE_ATTR(touchkey_threshold, S_IRUGO, show_touchkey_threshold, NULL); +/*static DEVICE_ATTR(touch_sensitivity, S_IRUGO, back_key_state_show, NULL);*/ +//static DEVICE_ATTR(extra_button_event, S_IWUSR | S_IWGRP | S_IRUGO, NULL, enable_dummy_key); +static DEVICE_ATTR(touchkey_recent, S_IRUGO, show_touchkey_sensitivity, NULL); +static DEVICE_ATTR(touchkey_back, S_IRUGO, show_touchkey_sensitivity, NULL); +#ifndef NOT_SUPPORTED_TOUCH_DUMMY_KEY +static DEVICE_ATTR(touchkey_dummy_btn1, S_IRUGO, + show_touchkey_sensitivity, NULL); +static DEVICE_ATTR(touchkey_dummy_btn3, S_IRUGO, + show_touchkey_sensitivity, NULL); +static DEVICE_ATTR(touchkey_dummy_btn4, S_IRUGO, + show_touchkey_sensitivity, NULL); +static DEVICE_ATTR(touchkey_dummy_btn6, S_IRUGO, + show_touchkey_sensitivity, NULL); +#endif +/*static DEVICE_ATTR(autocal_stat, S_IRUGO, show_autocal_status, NULL);*/ +static DEVICE_ATTR(touchkey_raw_back, S_IRUGO, show_back_key_raw_data, NULL); +static DEVICE_ATTR(touchkey_raw_menu, S_IRUGO, show_menu_key_raw_data, NULL); +/*static DEVICE_ATTR(touchkey_idac_back, S_IRUGO, show_back_key_idac_data, NULL); + static DEVICE_ATTR(touchkey_idac_menu, S_IRUGO, show_menu_key_idac_data, NULL);*/ + +static struct attribute *touchkey_attributes[] = { + &dev_attr_touchkey_threshold.attr, + /*&dev_attr_touch_sensitivity.attr,*/ + &dev_attr_touchkey_back.attr, + &dev_attr_touchkey_recent.attr, + //&dev_attr_autocal_stat.attr, + //&dev_attr_extra_button_event.attr, + &dev_attr_touchkey_raw_menu.attr, + &dev_attr_touchkey_raw_back.attr, +#ifndef NOT_SUPPORTED_TOUCH_DUMMY_KEY + &dev_attr_touchkey_dummy_btn1.attr, + &dev_attr_touchkey_dummy_btn3.attr, + &dev_attr_touchkey_dummy_btn4.attr, + &dev_attr_touchkey_dummy_btn6.attr, +#endif + //&dev_attr_touchkey_idac_back.attr, + //&dev_attr_touchkey_idac_menu.attr, + NULL, +}; +static struct attribute_group touchkey_attr_group = { + .attrs = touchkey_attributes, +}; +#endif + +static int init_sec_factory(struct bt541_ts_info *info) +{ + struct device *factory_ts_dev; +#ifdef SUPPORTED_TOUCH_KEY + struct device *factory_tk_dev; +#endif + struct tsp_factory_info *factory_info; + struct tsp_raw_data *raw_data; + int ret; + int i; + + factory_info = kzalloc(sizeof(struct tsp_factory_info), GFP_KERNEL); + if (unlikely(!factory_info)) { + dev_err(&info->client->dev, "%s: Failed to allocate memory\n", + __func__); + ret = -ENOMEM; + + goto err_alloc1; + } + raw_data = kzalloc(sizeof(struct tsp_raw_data), GFP_KERNEL); + if (unlikely(!raw_data)) { + dev_err(&info->client->dev, "%s: Failed to allocate memory\n", + __func__); + ret = -ENOMEM; + + goto err_alloc2; + } + + INIT_LIST_HEAD(&factory_info->cmd_list_head); + for (i = 0; i < ARRAY_SIZE(tsp_cmds); i++) + list_add_tail(&tsp_cmds[i].list, &factory_info->cmd_list_head); + + factory_ts_dev = device_create(sec_class, NULL, 0, info, "tsp"); + if (unlikely(!factory_ts_dev)) { + dev_err(&info->client->dev, "Failed to create factory dev\n"); + ret = -ENODEV; + goto err_create_device; + } + +#ifdef SUPPORTED_TOUCH_KEY + factory_tk_dev = device_create(sec_class, NULL, 0, info, "sec_touchkey"); + if (IS_ERR(factory_tk_dev)) { + dev_err(&info->client->dev, "Failed to create factory dev\n"); + ret = -ENODEV; + goto err_create_device; + } +#endif + + ret = sysfs_create_group(&factory_ts_dev->kobj, &touchscreen_attr_group); + if (unlikely(ret)) { + dev_err(&info->client->dev, "Failed to create touchscreen sysfs group\n"); + goto err_create_sysfs; + } + +#ifdef SUPPORTED_TOUCH_KEY + ret = sysfs_create_group(&factory_tk_dev->kobj, &touchkey_attr_group); + if (unlikely(ret)) { + dev_err(&info->client->dev, "Failed to create touchkey sysfs group\n"); + goto err_create_sysfs; + } +#endif + + mutex_init(&factory_info->cmd_lock); + factory_info->cmd_is_running = false; + + info->factory_info = factory_info; + info->raw_data = raw_data; + + dnd_v_diff = assy_dnd_v_diff; + dnd_h_diff = assy_dnd_h_diff; + pdnd_max = assy_pdnd_max; + pdnd_min = assy_pdnd_min; + hfdnd_max = assy_hfdnd_max; + hfdnd_min = assy_hfdnd_min; + + return ret; + +err_create_sysfs: +err_create_device: + kfree(raw_data); +err_alloc2: + kfree(factory_info); +err_alloc1: + + return ret; +} +#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; +} + +static long ts_misc_fops_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct raw_ioctl raw_ioctl; + u8 *u8Data; + int ret = 0; + size_t sz = 0; + u16 version; + u16 mode; + + struct reg_ioctl reg_ioctl; + u16 val; + int nval = 0; + + if (misc_info == NULL) + { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + + 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)) { + pr_info("[zinitix_touch] error : copy_from_user\n"); + return -1; + } + if (nval) + pr_info("[zinitix_touch] on debug mode (%d)\n", + nval); + else + pr_info("[zinitix_touch] off debug mode (%d)\n", + nval); + m_ts_debug_mode = nval; + break; + + case TOUCH_IOCTL_GET_CHIP_REVISION: + ret = misc_info->cap_info.ic_revision; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_GET_FW_VERSION: + ret = misc_info->cap_info.fw_version; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_GET_REG_DATA_VERSION: + ret = misc_info->cap_info.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 "[zinitix_touch]: firmware size = %d\r\n", (int)sz); + if (misc_info->cap_info.ic_fw_size != sz) { + pr_info("[zinitix_touch]: firmware size error\r\n"); + return -1; + } + break; + + case TOUCH_IOCTL_VARIFY_UPGRADE_DATA: + if (copy_from_user(m_firmware_data, + argp, misc_info->cap_info.ic_fw_size)) + return -1; + + version = (u16) (m_firmware_data[52] | (m_firmware_data[53]<<8)); + + pr_info("[zinitix_touch]: firmware version = %x\r\n", version); + + if (copy_to_user(argp, &version, sizeof(version))) + return -1; + break; + + case TOUCH_IOCTL_START_UPGRADE: + return ts_upgrade_sequence((u8 *)m_firmware_data); + + case TOUCH_IOCTL_GET_X_RESOLUTION: + ret = misc_info->pdata->x_resolution; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_GET_Y_RESOLUTION: + ret = misc_info->pdata->y_resolution; + if (copy_to_user(argp, &ret, sizeof(ret))) + return -1; + break; + + case TOUCH_IOCTL_GET_X_NODE_NUM: + ret = misc_info->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_info->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_info->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_info->irq); + down(&misc_info->work_lock); + if (misc_info->work_state != NOTHING) { + pr_info("[zinitix_touch]: other process occupied.. (%d)\r\n", + misc_info->work_state); + up(&misc_info->work_lock); + return -1; + } + misc_info->work_state = HW_CALIBRAION; + mdelay(100); + + /* h/w calibration */ + if (ts_hw_calibration(misc_info) == true) + ret = 0; + + mode = misc_info->touch_mode; + if (write_reg(misc_info->client, + BT541_TOUCH_MODE, mode) != I2C_SUCCESS) { + pr_err("[zinitix_touch]: failed to set touch mode %d.\n", + mode); + goto fail_hw_cal; + } + + if (write_cmd(misc_info->client, + BT541_SWRESET_CMD) != I2C_SUCCESS) + goto fail_hw_cal; + + enable_irq(misc_info->irq); + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + return ret; +fail_hw_cal: + enable_irq(misc_info->irq); + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + return -1; + + case TOUCH_IOCTL_SET_RAW_DATA_MODE: + if (misc_info == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + if (copy_from_user(&nval, argp, 4)) { + pr_info("[zinitix_touch] error : copy_from_user\r\n"); + misc_info->work_state = NOTHING; + return -1; + } + ts_set_touchmode((u16)nval); + + return 0; + + case TOUCH_IOCTL_GET_REG: + if (misc_info == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + down(&misc_info->work_lock); + if (misc_info->work_state != NOTHING) { + pr_info("[zinitix_touch]:other process occupied.. (%d)\n", + misc_info->work_state); + up(&misc_info->work_lock); + return -1; + } + + misc_info->work_state = SET_MODE; + + if (copy_from_user(®_ioctl, + argp, sizeof(struct reg_ioctl))) { + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + pr_info("[zinitix_touch] error : copy_from_user\n"); + return -1; + } + + if (read_data(misc_info->client, + (u16)reg_ioctl.addr, (u8 *)&val, 2) < 0) + ret = -1; + + nval = (int)val; + + if (copy_to_user((void *)(unsigned long)reg_ioctl.val, (u8 *)&nval, 4)) { + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + pr_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_info->work_state = NOTHING; + up(&misc_info->work_lock); + return ret; + + case TOUCH_IOCTL_SET_REG: + + down(&misc_info->work_lock); + if (misc_info->work_state != NOTHING) { + pr_info("[zinitix_touch]: other process occupied.. (%d)\n", + misc_info->work_state); + up(&misc_info->work_lock); + return -1; + } + + misc_info->work_state = SET_MODE; + if (copy_from_user(®_ioctl, + argp, sizeof(struct reg_ioctl))) { + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + pr_info("[zinitix_touch] error : copy_from_user(1)\n"); + return -1; + } + + if (copy_from_user(&val, (void *)(unsigned long)reg_ioctl.val, 4)) { + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + pr_info("[zinitix_touch] error : copy_from_user(2)\n"); + return -1; + } + + if (write_reg(misc_info->client, + (u16)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_info->work_state = NOTHING; + up(&misc_info->work_lock); + return ret; + + case TOUCH_IOCTL_DONOT_TOUCH_EVENT: + + if (misc_info == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + down(&misc_info->work_lock); + if (misc_info->work_state != NOTHING) { + pr_info("[zinitix_touch]: other process occupied.. (%d)\r\n", + misc_info->work_state); + up(&misc_info->work_lock); + return -1; + } + + misc_info->work_state = SET_MODE; + if (write_reg(misc_info->client, + BT541_INT_ENABLE_FLAG, 0) != I2C_SUCCESS) + ret = -1; + zinitix_debug_msg("write : reg addr = 0x%x, val = 0x0\r\n", + BT541_INT_ENABLE_FLAG); + + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + return ret; + + case TOUCH_IOCTL_SEND_SAVE_STATUS: + if (misc_info == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + down(&misc_info->work_lock); + if (misc_info->work_state != NOTHING) { + pr_info("[zinitix_touch]: other process occupied.." \ + "(%d)\r\n", misc_info->work_state); + up(&misc_info->work_lock); + return -1; + } + misc_info->work_state = SET_MODE; + ret = 0; + write_reg(misc_info->client, 0xc003, 0x0001); + write_reg(misc_info->client, 0xc104, 0x0001); + if (write_cmd(misc_info->client, + BT541_SAVE_STATUS_CMD) != I2C_SUCCESS) + ret = -1; + + mdelay(1000); /* for fusing eeprom */ + write_reg(misc_info->client, 0xc003, 0x0000); + write_reg(misc_info->client, 0xc104, 0x0000); + + misc_info->work_state = NOTHING; + up(&misc_info->work_lock); + return ret; + + case TOUCH_IOCTL_GET_RAW_DATA: + if (misc_info == NULL) { + zinitix_debug_msg("misc device NULL?\n"); + return -1; + } + + if (misc_info->touch_mode == TOUCH_POINT_MODE) + return -1; + + down(&misc_info->raw_data_lock); + if (misc_info->update == 0) { + up(&misc_info->raw_data_lock); + return -2; + } + + if (copy_from_user(&raw_ioctl, + argp, sizeof(struct raw_ioctl))) { + up(&misc_info->raw_data_lock); + pr_info("[zinitix_touch] error : copy_from_user\r\n"); + return -1; + } + + misc_info->update = 0; + + u8Data = (u8 *)&misc_info->cur_data[0]; + if (raw_ioctl.sz > MAX_TRAW_DATA_SZ*2) + raw_ioctl.sz = MAX_TRAW_DATA_SZ*2; + if (copy_to_user((void *)(unsigned long)raw_ioctl.buf, (u8 *)u8Data, + raw_ioctl.sz)) { + up(&misc_info->raw_data_lock); + return -1; + } + + up(&misc_info->raw_data_lock); + return 0; + + default: + break; + } + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id tsp_dt_ids[] = { + { .compatible = "Zinitix,bt541_ts", }, + {}, +}; +MODULE_DEVICE_TABLE(of, tsp_dt_ids); +#endif +static int bt541_ts_probe_dt(struct device_node *np, + struct device *dev, + struct bt541_ts_platform_data *pdata) +{ + int ret; + + if (!np) + return -EINVAL; + + pdata->gpio_int = of_get_named_gpio(np,"gpios", 0); + if (pdata->gpio_int < 0) { + pr_err("%s: of_get_named_gpio failed: %d\n", __func__, + pdata->gpio_int); + return -EINVAL; + } + ret = of_property_read_u32(np, "bt541,x_resolution", + &pdata->x_resolution); + if (ret < 0) + return ret; + ret = of_property_read_u32(np, "bt541,y_resolution", + &pdata->y_resolution); + if (ret < 0) + return ret; + ret = of_property_read_u32(np, "bt541,orientation", + &pdata->orientation); + if (ret < 0) + return ret; + + ret = of_property_read_u32(np, "bt541,page_size", &pdata->page_size); + if (ret < 0) + return ret; + + ret = of_property_read_u32(np, "tsp_vdd_supply_type", + &pdata->tsp_supply_type); + if (ret < 0) { + pr_err("%s: failed to read property tsp_vdd_supply_type\n", + __func__); + return ret; + } + + if (pdata->tsp_supply_type == TSP_LDO_SUPPLY) { + pdata->gpio_ldo_en = of_get_named_gpio(np, "gpio_ldo_en", 0); + if (pdata->gpio_ldo_en < 0) { + pr_err("%s: of_get_named_gpio failed: %d\n", __func__, + pdata->gpio_ldo_en); + return -EINVAL; + } + } + pdata->tsp_power = bt541_power; + return 0; + +} + +static int bt541_ts_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct bt541_ts_platform_data *pdata = client->dev.platform_data; + struct bt541_ts_info *info; + struct input_dev *input_dev; + int ret = 0; + int i; + + struct device_node *np = client->dev.of_node; + + if (IS_ENABLED(CONFIG_OF)) { + if (!pdata) { + pdata = devm_kzalloc(&client->dev, + sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + } + ret = bt541_ts_probe_dt(np, &client->dev, pdata); + if (ret) + goto err_no_platform_data; + + } else if (!pdata) { + dev_err(&client->dev, "Not exist platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "Not compatible i2c function\n"); + ret = -EIO; + goto err_no_platform_data; + } + + info = kzalloc(sizeof(struct bt541_ts_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, "Failed to allocate memory\n"); + ret = -ENOMEM; + goto err_no_platform_data; + } + ret = gpio_request(pdata->gpio_int, "bt541_int"); + if (ret < 0) { + pr_err("%s: Request GPIO failed, gpio %d (%d)\n", BT541_TS_DEVICE, + pdata->gpio_int, ret); + goto err_gpio_alloc; + } + gpio_direction_input(pdata->gpio_int); + i2c_set_clientdata(client, info); + info->client = client; + info->pdata = pdata; + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&client->dev, "Failed to allocate input device\n"); + ret = -EPERM; + goto err_alloc; + } + + info->input_dev = input_dev; + info->work_state = PROBE; + + /* power on */ + if (bt541_power_control(info, POWER_ON_SEQUENCE) == false) { + ret = -EPERM; + goto err_power_sequence; + } + + /* To Do */ + /* FW version read from tsp */ + + memset(&info->reported_touch_info, + 0x0, sizeof(struct point_info)); + + /* init touch mode */ + info->touch_mode = TOUCH_POINT_MODE; + misc_info = info; + + if (init_touch(info, true) == false) { + ret = -EPERM; + goto err_input_unregister_device; + } + + for (i = 0; i < MAX_SUPPORTED_BUTTON_NUM; i++) + info->button[i] = ICON_BUTTON_UNCHANGE; + + snprintf(info->phys, sizeof(info->phys), + "%s/input0", dev_name(&client->dev)); + input_dev->name = "sec_touchscreen"; + input_dev->id.bustype = BUS_I2C; + /* input_dev->id.vendor = 0x0001; */ + input_dev->phys = info->phys; + /* input_dev->id.product = 0x0002; */ + /* input_dev->id.version = 0x0100; */ + input_dev->dev.parent = &client->dev; + + set_bit(EV_SYN, info->input_dev->evbit); + set_bit(EV_KEY, info->input_dev->evbit); + set_bit(EV_ABS, info->input_dev->evbit); + set_bit(INPUT_PROP_DIRECT, info->input_dev->propbit); + + for (i = 0; i < MAX_SUPPORTED_BUTTON_NUM; i++) + set_bit(BUTTON_MAPPING_KEY[i], info->input_dev->keybit); + + if (pdata->orientation & TOUCH_XY_SWAP) { + input_set_abs_params(info->input_dev, ABS_MT_POSITION_Y, + info->cap_info.MinX, + info->cap_info.MaxX + ABS_PT_OFFSET, + 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_POSITION_X, + info->cap_info.MinY, + info->cap_info.MaxY + ABS_PT_OFFSET, + 0, 0); + } else { + input_set_abs_params(info->input_dev, ABS_MT_POSITION_X, + info->cap_info.MinX, + info->cap_info.MaxX + ABS_PT_OFFSET, + 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_POSITION_Y, + info->cap_info.MinY, + info->cap_info.MaxY + ABS_PT_OFFSET, + 0, 0); + } + + input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MAJOR, + 0, 255, 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_WIDTH_MAJOR, + 0, 255, 0, 0); + +#if (TOUCH_POINT_MODE == 2) + input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MINOR, + 0, 255, 0, 0); + /* input_set_abs_params(info->input_dev, ABS_MT_WIDTH_MINOR, + 0, 255, 0, 0); */ + /* input_set_abs_params(info->input_dev, ABS_MT_ORIENTATION, + -128, 127, 0, 0); */ + /* input_set_abs_params(info->input_dev, ABS_MT_ANGLE, + -90, 90, 0, 0);*/ + input_set_abs_params(info->input_dev, ABS_MT_PALM, + 0, 1, 0, 0); +#endif + + set_bit(MT_TOOL_FINGER, info->input_dev->keybit); + input_mt_init_slots(info->input_dev, info->cap_info.multi_fingers,0); + + zinitix_debug_msg("register %s input device \r\n", + info->input_dev->name); + input_set_drvdata(info->input_dev, info); + ret = input_register_device(info->input_dev); + if (ret) { + printk(KERN_ERR "unable to register %s input device\r\n", + info->input_dev->name); + goto err_input_register_device; + } + + /* configure irq */ + info->irq = gpio_to_irq(pdata->gpio_int); + if (info->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", + info->irq, pdata->gpio_int); + + info->work_state = NOTHING; +#if TOUCH_BOOSTER + info->finger_cnt = 0; +#endif + sema_init(&info->work_lock, 1); + +#if ESD_TIMER_INTERVAL + spin_lock_init(&info->lock); + INIT_WORK(&info->tmr_work, ts_tmr_work); + esd_tmr_workqueue = + create_singlethread_workqueue("esd_tmr_workqueue"); + + if (!esd_tmr_workqueue) { + dev_err(&client->dev, "Failed to create esd tmr work queue\n"); + ret = -EPERM; + + goto err_esd_input_unregister_device; + } + + esd_timer_init(info); + esd_timer_start(CHECK_ESD_TIMER, info); +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "Started esd timer\n"); +#endif +#endif + ret = request_threaded_irq(info->irq, NULL, bt541_touch_work, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT , BT541_TS_DEVICE, info); + + if (ret) { + printk(KERN_ERR "unable to register irq.(%s)\r\n", + info->input_dev->name); + goto err_request_irq; + } + dev_info(&client->dev, "zinitix touch probe.\r\n"); + sprd_i2c_ctl_chg_clk(1, 400000); // up h/w i2c 1 400k +#ifdef CONFIG_HAS_EARLYSUSPEND + info->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + info->early_suspend.suspend = bt541_ts_early_suspend; + info->early_suspend.resume = bt541_ts_late_resume; + register_early_suspend(&info->early_suspend); +#endif + +#if defined(CONFIG_PM_RUNTIME) && !defined(CONFIG_HAS_EARLYSUSPEND) + pm_runtime_enable(&client->dev); +#endif + + sema_init(&info->raw_data_lock, 1); + + ret = misc_register(&touch_misc_device); + if (ret) { + dev_err(&client->dev, "Failed to register touch misc device\n"); + goto err_misc_register; + } + +#ifdef SEC_FACTORY_TEST + ret = init_sec_factory(info); + if (ret) { + dev_err(&client->dev, "Failed to init sec factory device\n"); + + goto err_kthread_create_failed; + } +#endif + + return 0; + +#ifdef SEC_FACTORY_TEST +err_kthread_create_failed: + kfree(info->factory_info); + kfree(info->raw_data); +#endif +err_misc_register: + free_irq(info->irq, info); +err_request_irq: +#if ESD_TIMER_INTERVAL +err_esd_input_unregister_device: +#endif +err_input_unregister_device: + input_unregister_device(info->input_dev); +err_input_register_device: + tsp_charger_status_cb = NULL; +err_power_sequence: + input_free_device(info->input_dev); +err_alloc: + kfree(info); +err_gpio_alloc: + gpio_free(pdata->gpio_int); +err_no_platform_data: + if (IS_ENABLED(CONFIG_OF)) + devm_kfree(&client->dev, (void *)pdata); + + dev_info(&client->dev, "Failed to probe\n"); + return ret; +} + +static int bt541_ts_remove(struct i2c_client *client) +{ + struct bt541_ts_info *info = i2c_get_clientdata(client); + struct bt541_ts_platform_data *pdata = info->pdata; + + disable_irq(info->irq); + down(&info->work_lock); + + info->work_state = REMOVE; + +#ifdef SEC_FACTORY_TEST + kfree(info->factory_info); + kfree(info->raw_data); +#endif +#if ESD_TIMER_INTERVAL + flush_work(&info->tmr_work); + write_reg(info->client, BT541_PERIODICAL_INTERRUPT_INTERVAL, 0); + esd_timer_stop(info); +#if defined(TSP_VERBOSE_DEBUG) + dev_info(&client->dev, "Stopped esd timer\n"); +#endif + destroy_workqueue(esd_tmr_workqueue); +#endif + + if (info->irq) + free_irq(info->irq, info); + + misc_deregister(&touch_misc_device); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&info->early_suspend); +#endif + + if (gpio_is_valid(pdata->gpio_int) != 0) + gpio_free(pdata->gpio_int); + + tsp_charger_status_cb = NULL; + + input_unregister_device(info->input_dev); + input_free_device(info->input_dev); + up(&info->work_lock); + kfree(info); + + return 0; +} + +void bt541_ts_shutdown(struct i2c_client *client) +{ + struct bt541_ts_info *info = i2c_get_clientdata(client); + + dev_info(&client->dev, "%s++\n",__func__); + disable_irq(info->irq); + down(&info->work_lock); +#if ESD_TIMER_INTERVAL + flush_work(&info->tmr_work); + esd_timer_stop(info); +#endif + up(&info->work_lock); + bt541_power_control(info, POWER_OFF); + dev_info(&client->dev, "%s--\n",__func__); +} + + +static struct i2c_device_id bt541_idtable[] = { + {BT541_TS_DEVICE, 0}, + { } +}; + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static const struct dev_pm_ops bt541_ts_pm_ops ={ +#if defined(CONFIG_PM_RUNTIME) + SET_RUNTIME_PM_OPS(bt541_ts_suspend, bt541_ts_resume,NULL) +#else + SET_SYSTEM_SLEEP_PM_OPS(bt541_ts_suspend, bt541_ts_resume) +#endif +}; +#endif + +static struct i2c_driver bt541_ts_driver = { + .probe = bt541_ts_probe, + .remove = bt541_ts_remove, + .shutdown = bt541_ts_shutdown, + .id_table = bt541_idtable, + .driver = { + .owner = THIS_MODULE, + .name = BT541_TS_DEVICE, + .of_match_table = tsp_dt_ids, +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) + .pm = &bt541_ts_pm_ops, +#endif + }, +}; + +extern unsigned int lpcharge; + +static int __init bt541_ts_init(void) +{ + pr_info("[TSP]: %s\n", __func__); + + if (!lpcharge) + return i2c_add_driver(&bt541_ts_driver); + else + return 0; +} + +static void __exit bt541_ts_exit(void) +{ + i2c_del_driver(&bt541_ts_driver); +} + +module_init(bt541_ts_init); +module_exit(bt541_ts_exit); + +MODULE_DESCRIPTION("touch-screen device driver using i2c interface"); +MODULE_AUTHOR("<mika.kim@samsung.com>"); +MODULE_LICENSE("GPL"); + |
