From 8e4bff4cab0ddac6060645b0715210484d02ff40 Mon Sep 17 00:00:00 2001 From: Yuval Adam <_@yuv.al> Date: Wed, 30 Aug 2017 08:25:59 +0000 Subject: Initial file dump from open source release --- drivers/input/touchscreen/mms136_ts.c | 4039 +++++++++++++++++++++++++++++++++ 1 file changed, 4039 insertions(+) create mode 100644 drivers/input/touchscreen/mms136_ts.c (limited to 'drivers/input/touchscreen/mms136_ts.c') diff --git a/drivers/input/touchscreen/mms136_ts.c b/drivers/input/touchscreen/mms136_ts.c new file mode 100644 index 00000000..158fe60c --- /dev/null +++ b/drivers/input/touchscreen/mms136_ts.c @@ -0,0 +1,4039 @@ +/* + * mms_ts.c - Touchscreen driver for Melfas MMS-series touch controllers + * + * Copyright (C) 2011 Google Inc. + * Author: Dima Zavin + * Simon Wilson + * + * ISP reflashing code based on original code from Melfas. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#define DEBUG +/* #define VERBOSE_DEBUG */ +#define SEC_TSP_DEBUG +#define SEC_TSP_VERBOSE_DEBUG + +/* #define FORCE_FW_FLASH */ +/* #define FORCE_FW_PASS */ +/* #define ESD_DEBUG */ + +#define SEC_TSP_FACTORY_TEST +#define SEC_TKEY_FACTORY_TEST +#define SEC_TSP_FW_UPDATE +#define TSP_BUF_SIZE 1024 +#define FAIL -1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "mms_ts_fw.h" + +#ifdef CONFIG_LEDS_CLASS +#include +#define TOUCHKEY_BACKLIGHT "button-backlight" +#endif + +#define MAX_FINGERS 10 +#define MAX_WIDTH 30 +#define MAX_PRESSURE 255 +#define MAX_ANGLE 90 +#define MIN_ANGLE -90 + +/* Registers */ +#define MMS_MODE_CONTROL 0x01 +#define MMS_XYRES_HI 0x02 +#define MMS_XRES_LO 0x03 +#define MMS_YRES_LO 0x04 + +#define MMS_INPUT_EVENT_PKT_SZ 0x0F +#define MMS_INPUT_EVENT0 0x10 +#ifdef CONFIG_TOUCHSCREEN_MMS144 +#define FINGER_EVENT_SZ 8 +#elif defined(CONFIG_TOUCHSCREEN_MMS136) +#define FINGER_EVENT_SZ 6 +#endif +#define MMS_CORE_VERSION 0xE1 +#define MMS_TSP_REVISION 0xF0 +#define MMS_HW_REVISION 0xF1 +#define MMS_COMPAT_GROUP 0xF2 +#define MMS_FW_VERSION 0xE3 /*core 5.3: F3->E3*/ + +enum { + ISP_MODE_FLASH_ERASE = 0x59F3, + ISP_MODE_FLASH_WRITE = 0x62CD, + ISP_MODE_FLASH_READ = 0x6AC9, +}; + +/* each address addresses 4-byte words */ +#define ISP_MAX_FW_SIZE (0x1F00 * 4) +#define ISP_IC_INFO_ADDR 0x1F00 +#define ISP_CAL_DATA_SIZE 256 + +#ifdef CONFIG_SEC_DVFS +#define TOUCH_BOOSTER 1 +#define TOUCH_BOOSTER_OFF_TIME 100 +#if TOUCH_BOOSTER +#include +#endif +#endif + +#ifdef SEC_TSP_FW_UPDATE + +#define WORD_SIZE 4 + +#define ISC_PKT_SIZE 1029 +#define ISC_PKT_DATA_SIZE 1024 +#define ISC_PKT_HEADER_SIZE 3 +#define ISC_PKT_NUM 31 + +#define ISC_ENTER_ISC_CMD 0x5F +#define ISC_ENTER_ISC_DATA 0x01 +#define ISC_CMD 0xAE +#define ISC_ENTER_UPDATE_DATA 0x55 +#define ISC_ENTER_UPDATE_DATA_LEN 9 +#define ISC_DATA_WRITE_SUB_CMD 0xF1 +#define ISC_EXIT_ISC_SUB_CMD 0x0F +#define ISC_EXIT_ISC_SUB_CMD2 0xF0 +#define ISC_CHECK_STATUS_CMD 0xAF +#define ISC_CONFIRM_CRC 0x03 +#define ISC_DEFAULT_CRC 0xFFFF + +#endif + +#ifdef SEC_TSP_FACTORY_TEST +#ifdef CONFIG_TOUCHSCREEN_MMS144 +#define TX_NUM 25 +#define RX_NUM 14 +#define NODE_NUM 350 /* 26x14 */ +#elif defined(CONFIG_TOUCHSCREEN_MMS136) +#define TX_NUM 20 +#define RX_NUM 12 +#define NODE_NUM 240 /* 20x12 */ +#endif + +/* self diagnostic */ +#define ADDR_CH_NUM 0x0B +#define ADDR_UNIV_CMD 0xA0 +#define CMD_ENTER_TEST 0x40 +#define CMD_EXIT_TEST 0x4F +#define CMD_CM_DELTA 0x41 +#define CMD_GET_DELTA 0x42 +#define CMD_CM_ABS 0X43 +#define CMD_GET_ABS 0X44 +#define CMD_CM_JITTER 0X45 +#define CMD_GET_JITTER 0X46 +#define CMD_GET_KEY_DELTA 0x4A +#define CMD_GET_KEY_ABS 0x4B +#define CMD_CM_KEY_JITTER 0x4C + +#define CMD_GET_INTEN 0x70 +#define CMD_GET_INTEN_KEY 0x71 +#define CMD_GET_REFER 0x72 +#define CMD_GET_REFER_KEY 0x73 +#define CMD_RESULT_SZ 0XAE +#define CMD_RESULT 0XAF + +/* VSC(Vender Specific Command) */ +#define MMS_VSC_CMD 0xB0 /* vendor specific command */ +#define MMS_VSC_MODE 0x1A /* mode of vendor */ + +#define MMS_VSC_CMD_ENTER 0X01 +#define MMS_VSC_CMD_CM_DELTA 0X02 +#define MMS_VSC_CMD_CM_ABS 0X03 +#define MMS_VSC_CMD_EXIT 0X05 +#define MMS_VSC_CMD_INTENSITY 0X04 +#define MMS_VSC_CMD_RAW 0X06 +#define MMS_VSC_CMD_REFER 0X07 + +#ifdef SEC_TKEY_FACTORY_TEST +#define VSC_INTENSITY_TK 0x14 +#define VSC_RAW_TK 0x16 +#define VSC_THRESHOLD_TK 0x18 +#endif + +#define TSP_CMD_STR_LEN 32 +#define TSP_CMD_RESULT_STR_LEN 512 +#define TSP_CMD_PARAM_NUM 8 +#endif /* SEC_TSP_FACTORY_TEST */ + +#define ISC_DL_MODE 0 + +#if ISC_DL_MODE /* ISC_DL_MODE start */ + +/* + * Default configuration of ISC mode + */ +#define DEFAULT_SLAVE_ADDR 0x48 + +#define SECTION_NUM 3 +#define SECTION_NAME_LEN 5 + +#define PAGE_HEADER 3 +#define PAGE_DATA 1024 +#define PAGE_TAIL 2 +#define PACKET_SIZE (PAGE_HEADER + PAGE_DATA + PAGE_TAIL) +#define TS_WRITE_REGS_LEN 1030 + +#define TIMEOUT_CNT 10 +#define STRING_BUF_LEN 100 + + +/* State Registers */ +#define MIP_ADDR_INPUT_INFORMATION 0x01 + +#define ISC_ADDR_VERSION 0xE1 +#define ISC_ADDR_SECTION_PAGE_INFO 0xE5 + +/* Config Update Commands */ +#define ISC_CMD_ENTER_ISC 0x5F +#define ISC_CMD_ENTER_ISC_PARA1 0x01 +#define ISC_CMD_UPDATE_MODE 0xAE +#define ISC_SUBCMD_ENTER_UPDATE 0x55 +#define ISC_SUBCMD_DATA_WRITE 0XF1 +#define ISC_SUBCMD_LEAVE_UPDATE_PARA1 0x0F +#define ISC_SUBCMD_LEAVE_UPDATE_PARA2 0xF0 +#define ISC_CMD_CONFIRM_STATUS 0xAF + +#define ISC_STATUS_UPDATE_MODE 0x01 +#define ISC_STATUS_CRC_CHECK_SUCCESS 0x03 + +#define ISC_CHAR_2_BCD(num) (((num/10)<<4) + (num%10)) +#define ISC_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +static const char section_name[SECTION_NUM][SECTION_NAME_LEN] = { + "BOOT", "CORE", "CONF" +}; + +static const unsigned char crc0_buf[31] = { + 0x1D, 0x2C, 0x05, 0x34, 0x95, 0xA4, 0x8D, 0xBC, + 0x59, 0x68, 0x41, 0x70, 0xD1, 0xE0, 0xC9, 0xF8, + 0x3F, 0x0E, 0x27, 0x16, 0xB7, 0x86, 0xAF, 0x9E, + 0x7B, 0x4A, 0x63, 0x52, 0xF3, 0xC2, 0xEB +}; + +static const unsigned char crc1_buf[31] = { + 0x1E, 0x9C, 0xDF, 0x5D, 0x76, 0xF4, 0xB7, 0x35, + 0x2A, 0xA8, 0xEB, 0x69, 0x42, 0xC0, 0x83, 0x01, + 0x04, 0x86, 0xC5, 0x47, 0x6C, 0xEE, 0xAD, 0x2F, + 0x30, 0xB2, 0xF1, 0x73, 0x58, 0xDA, 0x99 +}; + +enum { + ISC_NONE = -1, + ISC_SUCCESS = 0, + ISC_FILE_OPEN_ERROR, + ISC_FILE_CLOSE_ERROR, + ISC_FILE_FORMAT_ERROR, + ISC_WRITE_BUFFER_ERROR, + ISC_I2C_ERROR, + ISC_UPDATE_MODE_ENTER_ERROR, + ISC_CRC_ERROR, + ISC_VALIDATION_ERROR, + ISC_COMPATIVILITY_ERROR, + ISC_UPDATE_SECTION_ERROR, + ISC_SLAVE_ERASE_ERROR, + ISC_SLAVE_DOWNLOAD_ERROR, + ISC_DOWNLOAD_WHEN_SLAVE_IS_UPDATED_ERROR, + ISC_INITIAL_PACKET_ERROR, + ISC_NO_NEED_UPDATE_ERROR, + ISC_LIMIT +}; + +enum { + EC_NONE = -1, + EC_DEPRECATED = 0, + EC_BOOTLOADER_RUNNING = 1, + EC_BOOT_ON_SUCCEEDED = 2, + EC_ERASE_END_MARKER_ON_SLAVE_FINISHED = 3, + EC_SLAVE_DOWNLOAD_STARTS = 4, + EC_SLAVE_DOWNLOAD_FINISHED = 5, + EC_2CHIP_HANDSHAKE_FAILED = 0x0E, + EC_ESD_PATTERN_CHECKED = 0x0F, + EC_LIMIT +}; + +struct tISCFWInfo_t { + unsigned char version; + unsigned char compatible_version; + unsigned char start_addr; + unsigned char end_addr; +}; + +static struct tISCFWInfo_t mbin_info[SECTION_NUM]; +static struct tISCFWInfo_t ts_info[SECTION_NUM]; +static bool section_update_flag[SECTION_NUM]; + +const struct firmware *fw_mbin[SECTION_NUM]; + +static unsigned char g_wr_buf[1024 + 3 + 2]; +#endif + +enum { + SEC_NONE = -1, + SEC_BOOTLOADER = 0, + SEC_CORE, + SEC_CONFIG, + SEC_LIMIT +}; + +int touch_is_pressed; +EXPORT_SYMBOL(touch_is_pressed); + +#define NUM_OF_KEY 4 + +enum fw_flash_mode { + ISP_FLASH, + ISC_FLASH, +}; + +enum { + BUILT_IN = 0, + UMS, +}; + +struct mms_ts_info { + struct i2c_client *client; + struct input_dev *input_dev; + char phys[32]; + + int max_x; + int max_y; + + bool invert_x; + bool invert_y; + int irq; + + struct mms_ts_platform_data *pdata; + + char *fw_name; + struct early_suspend early_suspend; +#ifdef CONFIG_SEC_DVFS +#if TOUCH_BOOSTER + struct delayed_work work_dvfs_off; + bool dvfs_lock_status; + struct mutex dvfs_lock; +#endif +#endif + + /* protects the enabled flag */ + struct mutex lock; + bool enabled; + +#ifdef SEC_TKEY_FACTORY_TEST + struct device *dev_tk; + bool *key_pressed; +#endif + enum fw_flash_mode fw_flash_mode; + + void (*register_cb)(struct tsp_callbacks *); + struct tsp_callbacks callbacks; + + bool ta_status; + bool noise_mode; + bool use_surface_touch; + bool use_touchkey; + unsigned char keycode[NUM_OF_KEY]; + +#if defined(SEC_TSP_DEBUG) || defined(SEC_TSP_VERBOSE_DEBUG) + unsigned char finger_state[MAX_FINGERS]; +#endif + +#if defined(SEC_TSP_FW_UPDATE) + u8 fw_update_state; +#endif + u8 fw_boot_ver; + u8 fw_core_ver; + u8 fw_ic_ver; + u8 palm_status; +#if defined(SEC_TSP_FACTORY_TEST) + struct list_head cmd_list_head; + u8 cmd_state; + char cmd[TSP_CMD_STR_LEN]; + int cmd_param[TSP_CMD_PARAM_NUM]; + char cmd_result[TSP_CMD_RESULT_STR_LEN]; + struct mutex cmd_lock; + bool cmd_is_running; + + unsigned int reference[NODE_NUM]; + unsigned int raw[NODE_NUM]; /* CM_ABS */ + unsigned int inspection[NODE_NUM];/* CM_DELTA */ + unsigned int intensity[NODE_NUM]; + bool ft_flag; +#endif /* SEC_TSP_FACTORY_TEST */ +#ifdef CONFIG_LEDS_CLASS + struct led_classdev leds; + bool tkey_led_reserved; +#endif +}; + +struct mms_fw_image { + __le32 hdr_len; + __le32 data_len; + __le32 fw_ver; + __le32 hdr_ver; + u8 data[0]; +} __packed; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mms_ts_early_suspend(struct early_suspend *h); +static void mms_ts_late_resume(struct early_suspend *h); +#endif + +#if defined(SEC_TSP_FACTORY_TEST) +#define TSP_CMD(name, func) .cmd_name = name, .cmd_func = func + +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 get_config_ver(void *device_data); +static void get_threshold(void *device_data); +static void module_off_master(void *device_data); +static void module_on_master(void *device_data); +static void get_chip_vendor(void *device_data); +static void get_chip_name(void *device_data); +static void get_reference(void *device_data); +static void get_cm_abs(void *device_data); +static void get_cm_delta(void *device_data); +static void get_intensity(void *device_data); +static void get_x_num(void *device_data); +static void get_y_num(void *device_data); +static void run_reference_read(void *device_data); +static void run_cm_abs_read(void *device_data); +static void run_cm_delta_read(void *device_data); +static void run_intensity_read(void *device_data); +static void not_support_cmd(void *device_data); + +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_config_ver", get_config_ver),}, + {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", not_support_cmd),}, + {TSP_CMD("module_on_slave", not_support_cmd),}, + {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("get_reference", get_reference),}, + {TSP_CMD("get_cm_abs", get_cm_abs),}, + {TSP_CMD("get_cm_delta", get_cm_delta),}, + {TSP_CMD("get_intensity", get_intensity),}, + {TSP_CMD("run_reference_read", run_reference_read),}, + {TSP_CMD("run_cm_abs_read", run_cm_abs_read),}, + {TSP_CMD("run_cm_delta_read", run_cm_delta_read),}, + {TSP_CMD("run_intensity_read", run_intensity_read),}, + {TSP_CMD("not_support_cmd", not_support_cmd),}, +}; +#endif + +#ifdef CONFIG_LEDS_CLASS +static void msm_tkey_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + bool tkey_led_on; + + struct mms_ts_info *info = + container_of(led_cdev, struct mms_ts_info, leds); + + if (value) + tkey_led_on = true; + else + tkey_led_on = false; + + if (info->enabled) { + info->tkey_led_reserved = false; + info->pdata->tkey_led_vdd_on(tkey_led_on); + } else { + if (value != LED_OFF) + info->tkey_led_reserved = true; + } +} +#endif + +#ifdef CONFIG_SEC_DVFS +#if TOUCH_BOOSTER +static void set_dvfs_off(struct work_struct *work) +{ + struct mms_ts_info *info = container_of(work, + struct mms_ts_info, work_dvfs_off.work); + mutex_lock(&info->dvfs_lock); + set_freq_limit(DVFS_TOUCH_ID, -1); + info->dvfs_lock_status = false; + mutex_unlock(&info->dvfs_lock); +} + +static void set_dvfs_lock(struct mms_ts_info *info, uint32_t on) +{ + int ret = 0; + + mutex_lock(&info->dvfs_lock); + + if (on == 0) { + if (info->dvfs_lock_status) { + schedule_delayed_work(&info->work_dvfs_off, + msecs_to_jiffies(TOUCH_BOOSTER_OFF_TIME)); + } + } else if (on == 1) { + cancel_delayed_work(&info->work_dvfs_off); + if (!info->dvfs_lock_status) { + ret = set_freq_limit(DVFS_TOUCH_ID, MIN_TOUCH_LIMIT); + if (ret < 0) + dev_err(&info->client->dev, "%s: cpu lock failed(%d)\n", + __func__, ret); + info->dvfs_lock_status = true; + } + } else if (on == 2) { + cancel_delayed_work(&info->work_dvfs_off); + schedule_work(&info->work_dvfs_off.work); + } + + mutex_unlock(&info->dvfs_lock); +} +#endif +#endif + +static inline void mms_pwr_on_reset(struct mms_ts_info *info) +{ + struct i2c_adapter *adapter = to_i2c_adapter(info->client->dev.parent); + + if (!info->pdata->mux_fw_flash) { + dev_err(&info->client->dev, "missing platform data, can't do power-on-reset\n"); + return; + } + + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, 1); + gpio_direction_output(info->pdata->gpio_scl, 1); + gpio_direction_output(info->pdata->gpio_resetb, 1); + msleep(50); + info->pdata->vdd_on(1); + msleep(50); + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + /* TODO: Seems long enough for the firmware to boot. + * Find the right value */ + msleep(250); +} +static void release_all_fingers(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + + int i; + + dev_dbg(&info->client->dev, "%s\n", __func__); + + for (i = 0; i < MAX_FINGERS; i++) { +#if defined(SEC_TSP_DEBUG) || defined(SEC_TSP_VERBOSE_DEBUG) + if (info->finger_state[i] == 1) + dev_notice(&client->dev, "finger %d up(force)\n", i); +#endif + info->finger_state[i] = 0; + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, + false); + } + input_sync(info->input_dev); +#ifdef CONFIG_SEC_DVFS +#if TOUCH_BOOSTER + set_dvfs_lock(info, 2); + dev_info(&client->dev, "dvfs_lock free.\n"); +#endif +#endif +} + +static void mms_set_noise_mode(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + + if (!(info->noise_mode && info->enabled)) + return; + dev_notice(&client->dev, "%s\n", __func__); + + if (info->ta_status) { + dev_notice(&client->dev, "noise_mode & TA connect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x30, 0x1); + } else { + dev_notice(&client->dev, "noise_mode & TA disconnect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x30, 0x2); + info->noise_mode = 0; + } +} + +static void reset_mms_ts(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + + if (info->enabled == false) + return; + + dev_notice(&client->dev, "%s++\n", __func__); + disable_irq_nosync(info->irq); + info->enabled = false; + touch_is_pressed = 0; + + release_all_fingers(info); + + mms_pwr_on_reset(info); + enable_irq(info->irq); + info->enabled = true; + + if (info->ta_status) { + dev_notice(&client->dev, "TA connect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x1); + } else { + dev_notice(&client->dev, "TA disconnect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x2); + mms_set_noise_mode(info); + } + + dev_notice(&client->dev, "%s--\n", __func__); +} + +static void melfas_ta_cb(struct tsp_callbacks *cb, bool ta_status) +{ + struct mms_ts_info *info = + container_of(cb, struct mms_ts_info, callbacks); + struct i2c_client *client = info->client; + + dev_notice(&client->dev, "%s\n", __func__); + + info->ta_status = ta_status; + + if (info->enabled) { + if (info->ta_status) { + dev_notice(&client->dev, "TA connect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x1); + } else { + dev_notice(&client->dev, "TA disconnect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x2); + mms_set_noise_mode(info); + } + } +} + +static irqreturn_t mms_ts_interrupt(int irq, void *dev_id) +{ + struct mms_ts_info *info = dev_id; + struct i2c_client *client = info->client; + u8 buf[MAX_FINGERS*FINGER_EVENT_SZ] = { 0 }; + int ret; + int i; + int sz; + u8 reg = MMS_INPUT_EVENT0; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .buf = ®, + .len = 1, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = buf, + }, + }; + + sz = i2c_smbus_read_byte_data(client, MMS_INPUT_EVENT_PKT_SZ); + if (sz < 0) { + pr_err("%s bytes=%d\n", __func__, sz); + for (i = 0; i < 50; i++) { + sz = i2c_smbus_read_byte_data(client, + MMS_INPUT_EVENT_PKT_SZ); + if (sz > 0) + break; + } + + if (i == 50) { + pr_err("i2c failed... reset!!\n"); + reset_mms_ts(info); + goto out; + } + } + /* BUG_ON(sz > MAX_FINGERS*FINGER_EVENT_SZ); */ + if (sz == 0) + goto out; + + if (sz > MAX_FINGERS*FINGER_EVENT_SZ) { + pr_err("abnormal data inputed.\n"); + goto out; + } + + msg[1].len = sz; + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + pr_err("failed to read %d bytes of touch data (%d)\n", + sz, ret); + goto out; + } + +#if defined(VERBOSE_DEBUG) + print_hex_dump(KERN_DEBUG, "mms_ts raw: ", + DUMP_PREFIX_OFFSET, 32, 1, buf, sz, false); + +#endif + if (buf[0] == 0x0F) { /* ESD */ + pr_debug("ESD DETECT.... reset!!\n"); + reset_mms_ts(info); + goto out; + } + + if (buf[0] == 0x0E) { /* NOISE MODE */ + pr_debug("noise mode enter!!\n"); + info->noise_mode = 1 ; + mms_set_noise_mode(info); + goto out; + } + + for (i = 0; i < sz; i += FINGER_EVENT_SZ) { + u8 *tmp = &buf[i]; + int id = (tmp[0] & 0xf) - 1; + int x = tmp[2] | ((tmp[1] & 0xf) << 8); + int y = tmp[3] | (((tmp[1] >> 4) & 0xf) << 8); + int angle = (tmp[5] >= 127) ? (-(256 - tmp[5])) : tmp[5]; + int palm = (buf[0] & 0x10) >> 4; + int type = (tmp[0] & 0x60) >> 5; + int action = (tmp[0] & 0x80) >> 7; + + if (info->use_surface_touch) { + if (palm) { + if (info->palm_status == 3) { + info->palm_status = 1; + } else { + info->palm_status = 3; + palm = 3; + } + } else { + if (info->palm_status == 2) { + info->palm_status = 0; + } else { + info->palm_status = 2; + palm = 2; + } + } + } + + if (info->use_touchkey && type == 0x02) { + input_report_key(info->input_dev, + info->keycode[id], action); +#ifdef SEC_TSP_DEBUG + pr_info("touchkey : keycode=%d action=%d\n", + info->keycode[id], action); +#else + pr_info("touchkey action=%d\n", action); +#endif +#ifdef SEC_TKEY_FACTORY_TEST + info->key_pressed[id] = action; +#endif + } else { + + if (info->invert_x) { + x = info->max_x - x; + if (x < 0) + x = 0; + } + if (info->invert_y) { + y = info->max_y - y; + if (y < 0) + y = 0; + } + if (id >= MAX_FINGERS) { + pr_err("finger id error [%d]\n", id); + reset_mms_ts(info); + goto out; + } + + if ((tmp[0] & 0x80) == 0) { +#if defined(SEC_TSP_DEBUG) + pr_info("fid[%d]: x=%d y=%d p=%d w=%d ", + id, x, y, tmp[5], tmp[4]); + if (info->use_surface_touch) + pr_cont("major=%d minor=%d angle=%d palm=%d\n", + tmp[6], tmp[7], angle, palm); + else + pr_cont("\n"); +#else + pr_info("finger [%d] up\n", id); +#endif + input_mt_slot(info->input_dev, id); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, false); + +#if defined(SEC_TSP_DEBUG) || defined(SEC_TSP_VERBOSE_DEBUG) + info->finger_state[id] = 0; +#endif + continue; + } + + //input_report_key(info->input_dev, BTN_TOUCH, 1); + + input_mt_slot(info->input_dev, id); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, true); + #if 1 + input_report_abs(info->input_dev, + ABS_MT_WIDTH_MAJOR, tmp[4]); + #endif + input_report_abs(info->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(info->input_dev, + ABS_MT_POSITION_Y, y); + #if 1 + + if (info->use_surface_touch) { + input_report_abs(info->input_dev, + ABS_MT_TOUCH_MAJOR, tmp[6]); + input_report_abs(info->input_dev, + ABS_MT_TOUCH_MINOR, tmp[7]); + +#if 0 /* SPRD's test code */ + input_report_abs(info->input_dev, + ABS_MT_ANGLE, angle); + input_report_abs(info->input_dev, + ABS_MT_PALM, palm); +#endif + } + #endif + //input_mt_sync(info->input_dev); + +#if defined(SEC_TSP_DEBUG) + if (info->finger_state[id] == 0) { + info->finger_state[id] = 1; + pr_info("finger id[%d]: x=%d y=%d p=%d w=%d ", + id, x, y, tmp[5], tmp[4]); + + if (info->use_surface_touch) + pr_cont("major=%d minor=%d angle=%d palm=%d\n", + tmp[6], tmp[7], angle, palm); + else + pr_cont("\n"); + } +#else + if (info->finger_state[id] == 0) { + info->finger_state[id] = 1; + pr_info("finger [%d] down\n", id); + } +#endif + } + } + + input_sync(info->input_dev); + touch_is_pressed = 0; + + for (i = 0; i < MAX_FINGERS; i++) { + if (info->finger_state[i] == 1) + touch_is_pressed++; + } + +#ifdef CONFIG_SEC_DVFS +#if TOUCH_BOOSTER + set_dvfs_lock(info, !!touch_is_pressed); +#endif +#endif + +out: + return IRQ_HANDLED; +} + +#if ISC_DL_MODE +static int mms100_i2c_read(struct i2c_client *client, + u16 addr, u16 length, u8 *value) +{ + struct i2c_adapter *adapter = client->adapter; + struct i2c_msg msg; + int ret = -1; + + msg.addr = client->addr; + msg.flags = 0x00; + msg.len = 1; + msg.buf = (u8 *) &addr; + + ret = i2c_transfer(adapter, &msg, 1); + + if (ret >= 0) { + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = length; + msg.buf = (u8 *) value; + + ret = i2c_transfer(adapter, &msg, 1); + } + + if (ret < 0) + dev_err(&client->dev, "I2C read error : [%d]\n", ret); + + return ret; +} + + +static int mms100_reset(struct mms_ts_info *info) +{ + info->pdata->vdd_on(0); + msleep(30); + info->pdata->vdd_on(1); + msleep(300); + + return ISC_SUCCESS; +} +/* +static int mms100_check_operating_mode(struct i2c_client *_client, + const int _error_code) +{ + int ret; + unsigned char rd_buf = 0x00; + unsigned char count = 0; + + if(_client == NULL) + pr_err("[TSP ISC] _client is null\n"); + + ret = mms100_i2c_read(_client, ISC_ADDR_VERSION, 1, &rd_buf); + + if (ret<0) { + pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return _error_code; + } + + return ISC_SUCCESS; +} +*/ +static int mms100_get_version_info(struct i2c_client *_client) +{ + int i, ret; + unsigned char rd_buf[8]; + + /* config version brust read (core, private, public) */ + ret = mms100_i2c_read(_client, ISC_ADDR_VERSION, 3, rd_buf); + if (ret < 0) { + dev_err(&_client->dev, "[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + for (i = 0; i < SECTION_NUM; i++) + ts_info[i].version = rd_buf[i]; + + ts_info[SEC_CORE].compatible_version = + ts_info[SEC_BOOTLOADER].version; + ts_info[SEC_CONFIG].compatible_version = + ts_info[SEC_CORE].version; + + ret = mms100_i2c_read(_client, ISC_ADDR_SECTION_PAGE_INFO, 8, rd_buf); + if (ret < 0) { + dev_err(&_client->dev, "[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + for (i = 0; i < SECTION_NUM; i++) { + ts_info[i].start_addr = rd_buf[i]; + ts_info[i].end_addr = rd_buf[i + SECTION_NUM + 1]; + } + + for (i = 0; i < SECTION_NUM; i++) { + dev_info(&_client->dev, "TS : Section(%d) version: 0x%02X\n", + i, ts_info[i].version); + dev_info(&_client->dev, "TS : Section(%d) Start Address: 0x%02X\n", + i, ts_info[i].start_addr); + dev_info(&_client->dev, "TS : Section(%d) End Address: 0x%02X\n", + i, ts_info[i].end_addr); + dev_info(&_client->dev, "TS : Section(%d) Compatibility: 0x%02X\n", + i, ts_info[i].compatible_version); + } + + return ISC_SUCCESS; +} + +static int mms100_seek_section_info(struct i2c_client *_client) +{ + int i; + char str_buf[STRING_BUF_LEN]; + char name_buf[SECTION_NAME_LEN]; + int version; + int page_num; + + const unsigned char *buf; + int next_ptr; + + for (i = 0; i < SECTION_NUM; i++) { + if (fw_mbin[i] == NULL) { + buf = NULL; + dev_err(&_client->dev, + "[TSP ISC] fw_mbin[%d]->data is NULL\n", i); + } else { + buf = fw_mbin[i]->data; + } + + if (buf == NULL) { + mbin_info[i].version = ts_info[i].version; + mbin_info[i].compatible_version = + ts_info[i].compatible_version; + mbin_info[i].start_addr = ts_info[i].start_addr; + mbin_info[i].end_addr = ts_info[i].end_addr; + } else { + next_ptr = 0; + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "SECTION_NAME")); + + sscanf(buf + next_ptr, "%s%s", str_buf, name_buf); + + if (strncmp(section_name[i], name_buf, + SECTION_NAME_LEN)) + return ISC_FILE_FORMAT_ERROR; + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "SECTION_VERSION")); + + sscanf(buf + next_ptr, "%s%d", str_buf, &version); + mbin_info[i].version = ISC_CHAR_2_BCD(version); + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "START_PAGE_ADDR")); + + sscanf(buf + next_ptr, "%s%d", str_buf, &page_num); + mbin_info[i].start_addr = page_num; + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "END_PAGE_ADDR")); + + sscanf(buf + next_ptr, "%s%d", str_buf, &page_num); + mbin_info[i].end_addr = page_num; + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "COMPATIBLE_VERSION")); + + sscanf(buf + next_ptr, "%s%d", str_buf, &version); + mbin_info[i].compatible_version = + ISC_CHAR_2_BCD(version); + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "[Binary]")); + + if (mbin_info[i].version == 0xFF) + return ISC_FILE_FORMAT_ERROR; + } + } + + for (i = 0; i < SECTION_NUM; i++) { + dev_info(&_client->dev, "[TSP ISC] MBin : Section(%d) Version: 0x%02X\n", + i, mbin_info[i].version); + dev_info(&_client->dev, "[TSP ISC] MBin : Section(%d) Start Address: 0x%02X\n", + i, mbin_info[i].start_addr); + dev_info(&_client->dev, "[TSP ISC] MBin : Section(%d) End Address: 0x%02X\n", + i, mbin_info[i].end_addr); + dev_info(&_client->dev, "[TSP ISC] MBin : Section(%d) Compatibility: 0x%02X\n", + i, mbin_info[i].compatible_version); + } + + return ISC_SUCCESS; +} + +static int mms100_compare_version_info(struct i2c_client *_client) +{ + int i, ret; + unsigned char expected_compatibility[SECTION_NUM]; + + if (mms100_get_version_info(_client) != ISC_SUCCESS) + return ISC_I2C_ERROR; + + ret = mms100_seek_section_info(_client); + + /* Check update areas , 0 : bootloader 1: core 2: private 3: public */ + for (i = 0; i < SECTION_NUM; i++) { + if ((mbin_info[i].version == 0) || + (mbin_info[i].version != ts_info[i].version)) { + section_update_flag[i] = true; + dev_info(&_client->dev, + "[TSP ISC] [%d] section will be updated!\n", i); + } + } + section_update_flag[0] = false; + section_update_flag[1] = false; + dev_info(&_client->dev, "[TSP ISC] [%d] [%d] [%d]", + section_update_flag[0], section_update_flag[1], + section_update_flag[2]); + + if (section_update_flag[SEC_BOOTLOADER]) { + expected_compatibility[SEC_CORE] = + mbin_info[SEC_BOOTLOADER].version; + } else { + expected_compatibility[SEC_CORE] = + ts_info[SEC_BOOTLOADER].version; + } + + if (section_update_flag[SEC_CORE]) { + expected_compatibility[SEC_CONFIG] = + mbin_info[SEC_CORE].version; + } else { + expected_compatibility[SEC_CONFIG] = + ts_info[SEC_CORE].version; + } + + for (i = SEC_CORE; i < SEC_CONFIG; i++) { + if (section_update_flag[i]) { + dev_info(&_client->dev, "[TSP ISC] section_update_flag(%d), 0x%02x, 0x%02x\n", + i, expected_compatibility[i], + mbin_info[i].compatible_version); + + if (expected_compatibility[i] != + mbin_info[i].compatible_version) + return ISC_COMPATIVILITY_ERROR; + } else { + dev_info(&_client->dev, "[TSP ISC] !section_update_flag(%d), 0x%02x, 0x%02x\n", + i, expected_compatibility[i], + ts_info[i].compatible_version); + if (expected_compatibility[i] != + ts_info[i].compatible_version) + return ISC_COMPATIVILITY_ERROR; + } + } + return ISC_SUCCESS; +} + +static int mms100_enter_ISC_mode(struct i2c_client *_client) +{ + int ret; + unsigned char wr_buf[2]; + + dev_info(&_client->dev, "[TSP ISC] %s\n", __func__); + + wr_buf[0] = ISC_CMD_ENTER_ISC; + wr_buf[1] = ISC_CMD_ENTER_ISC_PARA1; + + ret = i2c_master_send(_client, wr_buf, 2); + + if (ret < 0) { + dev_err(&_client->dev, "[TSP ISC] %s,%d: i2c write fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + msleep(50); + + return ISC_SUCCESS; +} + +static int mms100_enter_config_update(struct i2c_client *_client) +{ + int ret; + unsigned char wr_buf[10] = {0,}; + unsigned char rd_buf; + + wr_buf[0] = ISC_CMD_UPDATE_MODE; + wr_buf[1] = ISC_SUBCMD_ENTER_UPDATE; + + ret = i2c_master_send(_client, wr_buf, 10); + + if (ret < 0) { + dev_err(&_client->dev, "[TSP ISC] %s,%d: i2c write fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + ret = mms100_i2c_read(_client, ISC_CMD_CONFIRM_STATUS, 1, &rd_buf); + if (ret < 0) { + dev_err(&_client->dev, "[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + if (rd_buf != ISC_STATUS_UPDATE_MODE) + return ISC_UPDATE_MODE_ENTER_ERROR; + + dev_info(&_client->dev, "[TSP ISC] End mms100_enter_config_update()\n"); + + return ISC_SUCCESS; +} + +static int mms100_ISC_clear_page(struct i2c_client *_client, + unsigned char _page_addr) +{ + int ret; + unsigned char rd_buf; + + memset(&g_wr_buf[3], 0xFF, PAGE_DATA); + + g_wr_buf[0] = ISC_CMD_UPDATE_MODE; /* command */ + g_wr_buf[1] = ISC_SUBCMD_DATA_WRITE; /* sub_command */ + g_wr_buf[2] = _page_addr; + + g_wr_buf[PAGE_HEADER + PAGE_DATA] = crc0_buf[_page_addr]; + g_wr_buf[PAGE_HEADER + PAGE_DATA + 1] = crc1_buf[_page_addr]; + + ret = i2c_master_send(_client, g_wr_buf, PACKET_SIZE); + + if (ret < 0) { + dev_err(&_client->dev, "[TSP ISC] %s,%d: i2c write fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + ret = mms100_i2c_read(_client, ISC_CMD_CONFIRM_STATUS, 1, &rd_buf); + + if (ret < 0) { + dev_err(&_client->dev, "[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + if (rd_buf != ISC_STATUS_CRC_CHECK_SUCCESS) + return ISC_UPDATE_MODE_ENTER_ERROR; + + dev_info(&_client->dev, "[TSP ISC] End mms100_ISC_clear_page()\n"); + return ISC_SUCCESS; + +} + +static int mms100_ISC_clear_validate_markers(struct i2c_client *_client) +{ + int ret_msg; + int i, j; + bool is_matched_address; + + for (i = SEC_CORE; i <= SEC_CONFIG; i++) { + if (section_update_flag[i]) { + if (ts_info[i].end_addr <= 30 && + ts_info[i].end_addr > 0) { + ret_msg = mms100_ISC_clear_page(_client, + ts_info[i].end_addr); + + if (ret_msg != ISC_SUCCESS) + return ret_msg; + } + } + } + + for (i = SEC_CORE; i <= SEC_CONFIG; i++) { + if (section_update_flag[i]) { + is_matched_address = false; + for (j = SEC_CORE; j <= SEC_CONFIG; j++) { + if (mbin_info[i].end_addr == + ts_info[i].end_addr) { + is_matched_address = true; + break; + } + } + + if (!is_matched_address) { + if (mbin_info[i].end_addr <= 30 && + mbin_info[i].end_addr > 0) { + ret_msg = mms100_ISC_clear_page(_client, + mbin_info[i].end_addr); + + if (ret_msg != ISC_SUCCESS) + return ret_msg; + } + } + } + } + + return ISC_SUCCESS; +} + +static void mms100_calc_crc(unsigned char *crc, + int page_addr, unsigned char *ptr_fw) +{ + int i, j; + + unsigned char ucData; + + unsigned short SeedValue; + unsigned short CRC_check_buf; + unsigned short CRC_send_buf; + unsigned short IN_data; + unsigned short XOR_bit_1; + unsigned short XOR_bit_2; + unsigned short XOR_bit_3; + + CRC_check_buf = 0xFFFF; + SeedValue = (unsigned short)page_addr; + + for (i = 7; i >= 0; i--) { + IN_data = (SeedValue >> i) & 0x01; + XOR_bit_1 = (CRC_check_buf & 0x0001) ^ IN_data; + XOR_bit_2 = XOR_bit_1^(CRC_check_buf >> 11 & 0x01); + XOR_bit_3 = XOR_bit_1^(CRC_check_buf >> 4 & 0x01); + CRC_send_buf = (XOR_bit_1 << 4) | (CRC_check_buf >> 12 & 0x0F); + CRC_send_buf = + (CRC_send_buf << 7) | (XOR_bit_2 << 6) | + (CRC_check_buf >> 5 & 0x3F); + CRC_send_buf = + (CRC_send_buf << 4) | (XOR_bit_3 << 3) | + (CRC_check_buf >> 1 & 0x0007); + CRC_check_buf = CRC_send_buf; + } + + for (j = 0; j < 1024; j++) { + ucData = ptr_fw[j]; + + for (i = 7; i >= 0; i--) { + IN_data = (ucData >> i) & 0x0001; + XOR_bit_1 = (CRC_check_buf & 0x0001) ^ IN_data; + XOR_bit_2 = XOR_bit_1^(CRC_check_buf >> 11 & 0x01); + XOR_bit_3 = XOR_bit_1^(CRC_check_buf >> 4 & 0x01); + CRC_send_buf = + (XOR_bit_1 << 4) | (CRC_check_buf >> 12 & 0x0F); + CRC_send_buf = + (CRC_send_buf << 7) | (XOR_bit_2 << 6) | + (CRC_check_buf >> 5 & 0x3F); + CRC_send_buf = + (CRC_send_buf << 4) | (XOR_bit_3 << 3) | + (CRC_check_buf >> 1 & 0x0007); + CRC_check_buf = CRC_send_buf; + } + } + + crc[0] = (unsigned char)((CRC_check_buf >> 8) & 0xFF); + crc[1] = (unsigned char)((CRC_check_buf >> 0) & 0xFF); +} + +static int mms100_update_section_data(struct i2c_client *_client) +{ + int i, j, ret; + unsigned char rd_buf; + unsigned char crc[2]; + const unsigned char *ptr_fw; + char str_buf[STRING_BUF_LEN]; + int page_addr; + + for (i = 0; i < SECTION_NUM; i++) { + if (section_update_flag[i]) { + dev_info(&_client->dev, + "[TSP ISC] section data i2c flash : [%d]\n", i); + + ptr_fw = fw_mbin[i]->data; + + do { + sscanf(ptr_fw, "%s", str_buf); + ptr_fw += strlen(str_buf) + 1; +/* + pr_info("[TSP ISC] Section[%d] %s", i, str_buf ); +*/ + } while (!strstr(str_buf, "[Binary]")); + ptr_fw += 1; + + for (page_addr = mbin_info[i].start_addr; + page_addr <= mbin_info[i].end_addr; + page_addr++) { + if (page_addr - mbin_info[i].start_addr > 0) + ptr_fw += 1024; + + g_wr_buf[0] = ISC_CMD_UPDATE_MODE; + g_wr_buf[1] = ISC_SUBCMD_DATA_WRITE; + g_wr_buf[2] = (unsigned char)page_addr; + + for (j = 0; j < 1024; j += 4) { + g_wr_buf[3+j] = ptr_fw[j+3]; + g_wr_buf[3+j+1] = ptr_fw[j+2]; + g_wr_buf[3+j+2] = ptr_fw[j+1]; + g_wr_buf[3+j+3] = ptr_fw[j+0]; + } + + mms100_calc_crc(crc, page_addr, &g_wr_buf[3]); + + g_wr_buf[1027] = crc[0]; + g_wr_buf[1028] = crc[1]; +/* + pr_info("[TSP ISC] [%d] DATA %02X %02X %02X %02X CRC %02X %02X ", + page_addr, g_wr_buf[3], g_wr_buf[4], + g_wr_buf[5], g_wr_buf[6] , crc[0] , crc[1] ); +*/ + ret = i2c_master_send(_client, + g_wr_buf, PACKET_SIZE); + if (ret < 0) { + dev_err(&_client->dev, "[TSP ISC] %s,%d: i2c write fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + ret = mms100_i2c_read(_client, + ISC_CMD_CONFIRM_STATUS, 1, &rd_buf); + if (ret < 0) { + dev_err(&_client->dev, "[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + if (rd_buf != ISC_STATUS_CRC_CHECK_SUCCESS) + return ISC_CRC_ERROR; + + section_update_flag[i] = false; + } + } + } + + return ISC_SUCCESS; +} + +static int mms100_open_mbinary(struct mms_ts_info *info) +{ + struct i2c_client *_client = info->client; + int ret = 0; + + /*to do fw update */ + { + ret += request_firmware(&(fw_mbin[0]),\ + "tsp_melfas/BOOT_H.fw", &_client->dev); + ret += request_firmware(&(fw_mbin[1]),\ + "tsp_melfas/CORE_H.fw", &_client->dev); + ret += request_firmware(&(fw_mbin[2]),\ + "tsp_melfas/CONF_H.fw", &_client->dev); + } + + if (!ret) + return ISC_SUCCESS; + else { + dev_err(&_client->dev, "[TSP ISC] request_firmware fail\n"); + return ret; + } +} + +static int mms100_close_mbinary(void) +{ + int i; + + for (i = 0; i < SECTION_NUM; i++) { + if (fw_mbin[i] != NULL) + release_firmware(fw_mbin[i]); + } + return ISC_SUCCESS; +} + +int mms100_ISC_download_mbinary(struct mms_ts_info *info) +{ + struct i2c_client *_client = info->client; + int ret_msg = ISC_NONE; + + dev_info(&_client->dev, "[TSP ISC] %s\n", __func__); + + mms100_reset(info); + +/* ret_msg = mms100_check_operating_mode(_client, EC_BOOT_ON_SUCCEEDED); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; +*/ + ret_msg = mms100_open_mbinary(info); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + /* Config version Check */ + ret_msg = mms100_compare_version_info(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + ret_msg = mms100_enter_ISC_mode(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + ret_msg = mms100_enter_config_update(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + ret_msg = mms100_ISC_clear_validate_markers(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + dev_info(&_client->dev, "[TSP ISC] mms100_update_section_data start\n"); + + ret_msg = mms100_update_section_data(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + dev_info(&_client->dev, "[TSP ISC] mms100_update_section_data end\n"); + +/* mms100_reset(info); */ + + dev_info(&_client->dev, "[TSP ISC] FIRMWARE_UPDATE_FINISHED!!!\n"); + + ret_msg = ISC_SUCCESS; + +ISC_ERROR_HANDLE: + if (ret_msg != ISC_SUCCESS) + dev_err(&_client->dev, + "[TSP ISC] ISC_ERROR_CODE: %d\n", ret_msg); + + mms100_reset(info); + mms100_close_mbinary(); + + return ret_msg; +} +#endif /* ISC_DL_MODE end */ + +static void hw_reboot(struct mms_ts_info *info, bool bootloader) +{ + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, bootloader ? 0 : 1); + gpio_direction_output(info->pdata->gpio_scl, bootloader ? 0 : 1); + gpio_direction_output(info->pdata->gpio_resetb, 0); + msleep(30); + info->pdata->vdd_on(1); + msleep(30); + + if (bootloader) { + gpio_set_value(info->pdata->gpio_scl, 0); + gpio_set_value(info->pdata->gpio_sda, 1); + } else { + gpio_set_value(info->pdata->gpio_resetb, 1); + gpio_direction_input(info->pdata->gpio_resetb); + gpio_direction_input(info->pdata->gpio_scl); + gpio_direction_input(info->pdata->gpio_sda); + } + msleep(40); +} + +static inline void hw_reboot_bootloader(struct mms_ts_info *info) +{ + hw_reboot(info, true); +} + +static inline void hw_reboot_normal(struct mms_ts_info *info) +{ + hw_reboot(info, false); +} + +static void isp_toggle_clk(struct mms_ts_info *info, int start_lvl, int end_lvl, + int hold_us) +{ + gpio_set_value(info->pdata->gpio_scl, start_lvl); + udelay(hold_us); + gpio_set_value(info->pdata->gpio_scl, end_lvl); + udelay(hold_us); +} + +/* 1 <= cnt <= 32 bits to write */ +static void isp_send_bits(struct mms_ts_info *info, u32 data, int cnt) +{ + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 0); + + /* clock out the bits, msb first */ + while (cnt--) { + gpio_set_value(info->pdata->gpio_sda, (data >> cnt) & 1); + udelay(3); + isp_toggle_clk(info, 1, 0, 3); + } +} + +/* 1 <= cnt <= 32 bits to read */ +static u32 isp_recv_bits(struct mms_ts_info *info, int cnt) +{ + u32 data = 0; + + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_set_value(info->pdata->gpio_sda, 0); + gpio_direction_input(info->pdata->gpio_sda); + + /* clock in the bits, msb first */ + while (cnt--) { + isp_toggle_clk(info, 0, 1, 1); + data = (data << 1) | (!!gpio_get_value(info->pdata->gpio_sda)); + } + + gpio_direction_output(info->pdata->gpio_sda, 0); + return data; +} + +static void isp_enter_mode(struct mms_ts_info *info, u32 mode) +{ + int cnt; + unsigned long flags; + + local_irq_save(flags); + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 1); + + mode &= 0xffff; + for (cnt = 15; cnt >= 0; cnt--) { + gpio_set_value(info->pdata->gpio_resetb, (mode >> cnt) & 1); + udelay(3); + isp_toggle_clk(info, 1, 0, 3); + } + + gpio_set_value(info->pdata->gpio_resetb, 0); + local_irq_restore(flags); +} + +static void isp_exit_mode(struct mms_ts_info *info) +{ + int i; + unsigned long flags; + + local_irq_save(flags); + gpio_direction_output(info->pdata->gpio_resetb, 0); + udelay(3); + + for (i = 0; i < 10; i++) + isp_toggle_clk(info, 1, 0, 3); + local_irq_restore(flags); +} + +static void isp_flash_set_address(struct mms_ts_info *info, u16 addr) +{ + /* Only 13 bits of addr are valid. + * The addr is in bits 13:1 of cmd */ + isp_send_bits(info, (u32)(addr & 0x1fff) << 1, 18); +} + +static void isp_flash_erase(struct mms_ts_info *info) +{ + isp_enter_mode(info, ISP_MODE_FLASH_ERASE); + + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 1); + + /* 4 clock cycles with different timings for the erase to + * get processed, clk is already 0 from above */ + udelay(7); + isp_toggle_clk(info, 1, 0, 3); + udelay(7); + isp_toggle_clk(info, 1, 0, 3); + usleep_range(25000, 35000); + isp_toggle_clk(info, 1, 0, 3); + usleep_range(150, 200); + isp_toggle_clk(info, 1, 0, 3); + + gpio_set_value(info->pdata->gpio_sda, 0); + + isp_exit_mode(info); +} + +static u32 isp_flash_readl(struct mms_ts_info *info, u16 addr) +{ + int i; + u32 val; + unsigned long flags; + + local_irq_save(flags); + isp_enter_mode(info, ISP_MODE_FLASH_READ); + isp_flash_set_address(info, addr); + + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 0); + udelay(40); + + /* data load cycle */ + for (i = 0; i < 6; i++) + isp_toggle_clk(info, 1, 0, 10); + + val = isp_recv_bits(info, 32); + isp_exit_mode(info); + local_irq_restore(flags); + + return val; +} + +static void isp_flash_writel(struct mms_ts_info *info, u16 addr, u32 val) +{ + unsigned long flags; + + local_irq_save(flags); + isp_enter_mode(info, ISP_MODE_FLASH_WRITE); + isp_flash_set_address(info, addr); + isp_send_bits(info, val, 32); + + gpio_direction_output(info->pdata->gpio_sda, 1); + /* 6 clock cycles with different timings for the data to get written + * into flash */ + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 6); + isp_toggle_clk(info, 0, 1, 12); + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 3); + + isp_toggle_clk(info, 1, 0, 1); + + gpio_direction_output(info->pdata->gpio_sda, 0); + isp_exit_mode(info); + local_irq_restore(flags); + usleep_range(300, 400); +} + +static bool isp_flash_is_erased(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + u32 val; + u16 addr; + + for (addr = 0; addr < (ISP_MAX_FW_SIZE / 4); addr++) { + udelay(40); + val = isp_flash_readl(info, addr); + + if (val != 0xffffffff) { + dev_dbg(&client->dev, + "addr 0x%x not erased: 0x%08x != 0xffffffff\n", + addr, val); + return false; + } + } + return true; +} + +static int isp_fw_write_image(struct mms_ts_info *info, const u8 *data, size_t len) +{ + struct i2c_client *client = info->client; + u16 addr = 0; + + for (addr = 0; addr < (len / 4); addr++, data += 4) { + u32 val = get_unaligned_le32(data); + u32 verify_val; + int retries = 3; + + while (retries--) { + isp_flash_writel(info, addr, val); + verify_val = isp_flash_readl(info, addr); + if (val == verify_val) + break; + dev_err(&client->dev, + "mismatch @ addr 0x%x: 0x%x != 0x%x\n", + addr, verify_val, val); + continue; + } + if (retries < 0) + return -ENXIO; + } + + return 0; +} + +static int isp_fw_download(struct mms_ts_info *info, const u8 *data, size_t len) +{ + struct i2c_client *client = info->client; + u32 val; + int ret = 0; + int i; + u32 *buf = kzalloc(ISP_CAL_DATA_SIZE * 4, GFP_KERNEL); + if (!buf) { + dev_err(&info->client->dev, "%s: failed to allocate memory\n", + __func__); + return -ENOMEM; + } + + if (len % 4) { + dev_err(&client->dev, + "fw image size (%d) must be a multiple of 4 bytes\n", + len); + kfree(buf); + return -EINVAL; + } else if (len > ISP_MAX_FW_SIZE) { + dev_err(&client->dev, + "fw image is too big, %d > %d\n", len, ISP_MAX_FW_SIZE); + kfree(buf); + return -EINVAL; + } + + dev_info(&client->dev, "fw download start\n"); + + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_resetb, 0); + + hw_reboot_bootloader(info); + + dev_info(&client->dev, "calibration data backup\n"); + for (i = 0; i < ISP_CAL_DATA_SIZE; i++) + buf[i] = isp_flash_readl(info, ISP_IC_INFO_ADDR); + + val = isp_flash_readl(info, ISP_IC_INFO_ADDR); + dev_info(&client->dev, "IC info: 0x%02x (%x)\n", val & 0xff, val); + + dev_info(&client->dev, "fw erase...\n"); + isp_flash_erase(info); + if (!isp_flash_is_erased(info)) { + ret = -ENXIO; + goto err; + } + + dev_info(&client->dev, "fw write...\n"); + /* XXX: what does this do?! */ + isp_flash_writel(info, ISP_IC_INFO_ADDR, 0xffffff00 | (val & 0xff)); + usleep_range(1000, 1500); + ret = isp_fw_write_image(info, data, len); + if (ret) + goto err; + usleep_range(1000, 1500); + + dev_info(&client->dev, "restoring data\n"); + for (i = 0; i < ISP_CAL_DATA_SIZE; i++) + isp_flash_writel(info, ISP_IC_INFO_ADDR, buf[i]); + kfree(buf); + + dev_info(&client->dev, "fw download done...\n"); + hw_reboot_normal(info); + msleep(200); + return 0; + +err: + dev_err(&client->dev, "fw download failed...\n"); + kfree(buf); + hw_reboot_normal(info); + return ret; +} + +static int get_fw_version(struct mms_ts_info *info, u8 area) +{ + struct i2c_client *client = info->client; + struct i2c_adapter *adapter = client->adapter; + struct i2c_msg msg; + u8 reg = MMS_CORE_VERSION; + int ret; + unsigned char buf[4]; + + msg.addr = client->addr; + msg.flags = 0x00; + msg.len = 1; + msg.buf = ® + + disable_irq(info->irq); + ret = i2c_transfer(adapter, &msg, 1); + + if (ret >= 0) { + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = 4; + msg.buf = buf; + + ret = i2c_transfer(adapter, &msg, 1); + } + enable_irq(info->irq); + if (ret < 0) { + dev_err(&client->dev, "I2C read error : [%d]\n", ret); + return ret; + } + + if (area == SEC_BOOTLOADER) + return buf[0]; + else if (area == SEC_CORE) + return buf[1]; + else if (area == SEC_CONFIG) + return buf[2]; + else + return 0; +} + +static int get_hw_version(struct mms_ts_info *info) +{ + int ret; + int retries = 3; + + /* this seems to fail sometimes after a reset.. retry a few times */ + disable_irq(info->irq); + do { + ret = i2c_smbus_read_byte_data(info->client, MMS_HW_REVISION); + } while (ret < 0 && retries-- > 0); + enable_irq(info->irq); + + return ret; +} + +static int mms_ts_finish_config(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + int ret; + + ret = request_threaded_irq(client->irq, NULL, mms_ts_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "mms_ts", info); + if (ret < 0) { + ret = 1; + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_req_irq; + } + + info->irq = client->irq; + barrier(); + + dev_info(&client->dev, "Melfas MMS-series touch controller initialized\n"); + + return 0; + +err_req_irq: + return ret; +} + +static int isp_fw_update(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret = 0; + int retries = 3; + int ver; + + ver = get_fw_version(info, SEC_CONFIG); + info->fw_ic_ver = ver; + dev_err(&client->dev, "fw version 0x%02x !!!!\n", ver); + + if (!info->pdata || !info->pdata->mux_fw_flash) { + ret = 1; + dev_err(&client->dev, "fw cannot be updated, missing platform data\n"); + return ret; + } + + disable_irq(info->irq); + while (retries--) { + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + ret = isp_fw_download(info, MELFAS_binary, + MELFAS_binary_nLength); + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + if (ret < 0) { + dev_err(&client->dev, "retrying flashing\n"); + continue; + } + + ver = get_fw_version(info, SEC_CONFIG); + info->fw_ic_ver = ver; + + if (ver == FW_VERSION) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + enable_irq(info->irq); + goto done; + } else { + dev_err(&client->dev, + "ERROR: fw update succeeded, but fw version is still wrong (0x%x != 0x%x)\n", + ver, FW_VERSION); + enable_irq(info->irq); + } + dev_err(&client->dev, "retrying flashing\n"); + } + + return ret; +done: + return ret; +} + +#if ISC_DL_MODE +static int isc_fw_update(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + int ret = 0; + int ver; + int bin_ver; + int retries = 3; + + ver = get_fw_version(info, SEC_CONFIG); + info->fw_ic_ver = ver; + dev_info(&client->dev, "fw version 0x%02x !!!!\n", ver); + + if (!info->pdata || !info->pdata->mux_fw_flash) { + ret = 1; + dev_err(&client->dev, "fw cannot be updated, missing platform data\n"); + goto out; + } + + bin_ver = FW_VERSION; + + while (retries--) { + ret = mms100_ISC_download_mbinary(info); + + ver = get_fw_version(info, SEC_CONFIG); + info->fw_ic_ver = ver; + + if (ret == 0) { + dev_info(&client->dev, "mms100_ISC_download_mbinary success\n"); + goto done; + } else { + dev_err(&client->dev, "mms100_ISC_download_mbinary fail [%d]\n", + ret); + ret = 1; + } + + dev_err(&client->dev, "retrying flashing\n"); + } +out: +done: + return ret; +} +#endif + +#ifdef SEC_TSP_FACTORY_TEST +/* SPRD remove this function */ +#if 0 +static inline int msm_irq_to_gpio(unsigned irq) +{ + /* TODO : Need to verify chip->base=0 */ + return irq - MSM_GPIO_TO_INT(0); +} +#endif +static void set_default_result(struct mms_ts_info *info) +{ + char delim = ':'; + + memset(info->cmd_result, 0x00, ARRAY_SIZE(info->cmd_result)); + memcpy(info->cmd_result, info->cmd, strlen(info->cmd)); + strncat(info->cmd_result, &delim, 1); +} + +static void set_cmd_result(struct mms_ts_info *info, char *buff, int len) +{ + strncat(info->cmd_result, buff, len); +} + +static int get_data(struct mms_ts_info *info, u8 addr, u8 size, u8 *array) +{ + struct i2c_client *client = info->client; + struct i2c_adapter *adapter = client->adapter; + struct i2c_msg msg; + u8 reg = addr; + unsigned char buf[size]; + int ret; + + msg.addr = client->addr; + msg.flags = 0x00; + msg.len = 1; + msg.buf = ® + + ret = i2c_transfer(adapter, &msg, 1); + + if (ret >= 0) { + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = size; + msg.buf = buf; + + ret = i2c_transfer(adapter, &msg, 1); + } + if (ret < 0) { + dev_err(&client->dev, "I2C read error : [%d]\n", ret); + return ret; + } + + memcpy(array, &buf, size); + return size; +} + +static void get_intensity_data(struct mms_ts_info *info) +{ + u8 w_buf[4]; + u8 r_buf; + u8 read_buffer[60] = {0}; + int i, j; + int ret; + u16 max_value = 0, min_value = 0; + u16 raw_data; + char buff[TSP_CMD_STR_LEN] = {0}; + + disable_irq(info->irq); + + w_buf[0] = ADDR_UNIV_CMD; + w_buf[1] = CMD_GET_INTEN; + w_buf[2] = 0xFF; + for (i = 0; i < RX_NUM; i++) { + w_buf[3] = i; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 3, &w_buf[1]); + if (ret < 0) + goto err_i2c; + usleep_range(1, 5); + + ret = i2c_smbus_read_i2c_block_data(info->client, + CMD_RESULT_SZ, 1, &r_buf); + if (ret < 0) + goto err_i2c; + + ret = get_data(info, CMD_RESULT, r_buf, read_buffer); + if (ret < 0) + goto err_i2c; + + for (j = 0; j < r_buf / 2; j++) { + raw_data = + read_buffer[2 * j] | (read_buffer[2 * j + 1] << 8); + if (raw_data > 32767) + raw_data = 0; + if (i == 0 && j == 0) { + max_value = min_value = raw_data; + } else { + max_value = max(max_value, raw_data); + min_value = min(min_value, raw_data); + } + info->intensity[i * TX_NUM + j] = raw_data; + dev_dbg(&info->client->dev, + "intensity[%d][%d] = %d\n", j, i, + info->intensity[i * TX_NUM + j]); + } + } + + snprintf(buff, sizeof(buff), "%d,%d", min_value, max_value); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + enable_irq(info->irq); + + return; + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, MMS_VSC_CMD_INTENSITY); +} + +static void get_raw_data(struct mms_ts_info *info, u8 cmd) +{ + u8 w_buf[4]; + u8 r_buf = 0; + u8 read_buffer[60] = {0}; + int ret; + int i, j; + int max_value = 0, min_value = 0; + int raw_data; + int retry; + char buff[TSP_CMD_STR_LEN] = {0}; + int gpio = info->pdata->gpio_int;/* msm_irq_to_gpio(info->irq); */ + + disable_irq(info->irq); + + ret = i2c_smbus_write_byte_data(info->client, + ADDR_UNIV_CMD, CMD_ENTER_TEST); + if (ret < 0) + goto err_i2c; + + /* event type check */ + retry = 1; + while (retry) { + while (gpio_get_value(gpio)) + udelay(100); + + ret = i2c_smbus_read_i2c_block_data(info->client, + 0x0F, 1, &r_buf); + if (ret < 0) + goto err_i2c; + + ret = i2c_smbus_read_i2c_block_data(info->client, + 0x10, 1, &r_buf); + if (ret < 0) + goto err_i2c; + + dev_info(&info->client->dev, "event type = 0x%x\n", r_buf); + if (r_buf == 0x0C) + retry = 0; + } + + w_buf[0] = ADDR_UNIV_CMD; + if (cmd == MMS_VSC_CMD_CM_DELTA) + w_buf[1] = CMD_CM_DELTA; + else + w_buf[1] = CMD_CM_ABS; + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 1, &w_buf[1]); + if (ret < 0) + goto err_i2c; + while (gpio_get_value(gpio)) + udelay(100); + + ret = i2c_smbus_read_i2c_block_data(info->client, + CMD_RESULT_SZ, 1, &r_buf); + if (ret < 0) + goto err_i2c; + ret = i2c_smbus_read_i2c_block_data(info->client, + CMD_RESULT, 1, &r_buf); + if (ret < 0) + goto err_i2c; + + if (r_buf == 1) + dev_info(&info->client->dev, "PASS\n"); + else + dev_info(&info->client->dev, "FAIL\n"); + + if (cmd == MMS_VSC_CMD_CM_DELTA) + w_buf[1] = CMD_GET_DELTA; + else + w_buf[1] = CMD_GET_ABS; + w_buf[2] = 0xFF; + + for (i = 0; i < RX_NUM; i++) { + w_buf[3] = i; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 3, &w_buf[1]); + if (ret < 0) + goto err_i2c; + + while (gpio_get_value(gpio)) + udelay(100); + + ret = i2c_smbus_read_i2c_block_data(info->client, + CMD_RESULT_SZ, 1, &r_buf); + if (ret < 0) + goto err_i2c; + + ret = get_data(info, CMD_RESULT, r_buf, read_buffer); + if (ret < 0) + goto err_i2c; + + for (j = 0; j < TX_NUM; j++) { + raw_data = + read_buffer[2 * j] | (read_buffer[2 * j + 1] << 8); + if (i == 0 && j == 0) { + max_value = min_value = raw_data; + } else { + max_value = max(max_value, raw_data); + min_value = min(min_value, raw_data); + } + + if (cmd == MMS_VSC_CMD_CM_DELTA) { + info->inspection[i * TX_NUM + j] = + raw_data; + dev_dbg(&info->client->dev, + "delta[%d][%d] = %d\n", j, i, + info->inspection[i * TX_NUM + j]); + } else if (cmd == MMS_VSC_CMD_CM_ABS) { + info->raw[i * TX_NUM + j] = + raw_data; + dev_dbg(&info->client->dev, + "raw[%d][%d] = %d\n", j, i, + info->raw[i * TX_NUM + j]); + } else if (cmd == MMS_VSC_CMD_REFER) { + info->reference[i * TX_NUM + j] = + raw_data; + dev_dbg(&info->client->dev, + "reference[%d][%d] = %d\n", j, i, + info->reference[i * TX_NUM + j]); + } + } + } + + ret = i2c_smbus_write_byte_data(info->client, + ADDR_UNIV_CMD, CMD_EXIT_TEST); + + snprintf(buff, sizeof(buff), "%d,%d", min_value, max_value); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + touch_is_pressed = 0; + release_all_fingers(info); + + info->pdata->vdd_on(0); + msleep(30); + info->pdata->vdd_on(1); + msleep(250); + + if (info->ta_status) { + dev_notice(&info->client->dev, "TA connect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x1); + } else { + dev_notice(&info->client->dev, "TA disconnect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x2); + } + mms_set_noise_mode(info); + + enable_irq(info->irq); + + return; + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, cmd); +} + +static void get_raw_data_all(struct mms_ts_info *info, u8 cmd) +{ + u8 w_buf[6]; + u8 read_buffer[2]; /* 52 */ + char buff[TSP_CMD_STR_LEN] = {0}; + int gpio; + int ret; + int i, j; + u32 max_value, min_value; + u32 raw_data; + + gpio = info->pdata->gpio_int;/*msm_irq_to_gpio(info->irq);*/ + disable_irq(info->irq); + + w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */ + w_buf[1] = MMS_VSC_MODE; /* mode of vendor */ + w_buf[2] = 0; /* tx line */ + w_buf[3] = 0; /* rx line */ + w_buf[4] = 0; /* reserved */ + w_buf[5] = 0; /* sub command */ + + if (cmd == MMS_VSC_CMD_EXIT) { + w_buf[5] = MMS_VSC_CMD_EXIT; /* exit test mode */ + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + touch_is_pressed = 0; + release_all_fingers(info); +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) + set_esd_disable(); +#endif + info->pdata->vdd_on(0); + msleep(30); + info->pdata->vdd_on(1); + msleep(120); + enable_irq(info->irq); +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) + set_esd_enable(); +#endif + return ; + } + + /* MMS_VSC_CMD_CM_DELTA or MMS_VSC_CMD_CM_ABS + * this two mode need to enter the test mode + * exit command must be followed by testing. + */ + if (cmd == MMS_VSC_CMD_CM_DELTA || cmd == MMS_VSC_CMD_CM_ABS) { + /* enter the debug mode */ + w_buf[2] = 0x0; /* tx */ + w_buf[3] = 0x0; /* rx */ + w_buf[5] = MMS_VSC_CMD_ENTER; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + + /* wating for the interrupt */ + while (gpio_get_value(gpio)) + udelay(100); + } + + max_value = 0; + min_value = 0; + + for (i = 0; i < RX_NUM; i++) { + for (j = 0; j < TX_NUM; j++) { + + w_buf[2] = j; /* tx */ + w_buf[3] = i; /* rx */ + w_buf[5] = cmd; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + + usleep_range(1, 5); + + ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, + 2, read_buffer); + if (ret < 0) + goto err_i2c; + + raw_data = ((u16)read_buffer[1] << 8) | read_buffer[0]; + + if (i == 0 && j == 0) { + max_value = min_value = raw_data; + } else { + max_value = max(max_value, raw_data); + min_value = min(min_value, raw_data); + } + + if (cmd == MMS_VSC_CMD_INTENSITY) { + info->intensity[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "intensity[%d][%d] = %d\n", + i, j, info->intensity[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_CM_DELTA) { + info->inspection[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "delta[%d][%d] = %d\n", + i, j, info->inspection[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_CM_ABS) { + info->raw[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "raw[%d][%d] = %d\n", + i, j, info->raw[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_REFER) { + info->reference[j * RX_NUM + i] = + raw_data >> 3; + dev_dbg(&info->client->dev, "reference[%d][%d] = %d\n", + i, j, info->reference[j * RX_NUM + i]); + } + } + } + + snprintf(buff, sizeof(buff), "%d,%d", min_value, max_value); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + enable_irq(info->irq); + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, cmd); +} + +#if defined(ESD_DEBUG) +static u32 get_raw_data_one(struct mms_ts_info *info, u16 rx_idx, u16 tx_idx, + u8 cmd) +{ + u8 w_buf[6]; + u8 read_buffer[2]; + int ret; + u32 raw_data; + + w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */ + w_buf[1] = MMS_VSC_MODE; /* mode of vendor */ + w_buf[2] = 0; /* tx line */ + w_buf[3] = 0; /* rx line */ + w_buf[4] = 0; /* reserved */ + w_buf[5] = 0; /* sub command */ + + if (cmd != MMS_VSC_CMD_INTENSITY && cmd != MMS_VSC_CMD_RAW && + cmd != MMS_VSC_CMD_REFER && cmd != VSC_INTENSITY_TK && + cmd != VSC_RAW_TK) { + dev_err(&info->client->dev, "%s: not profer command(cmd=%d)\n", + __func__, cmd); + return FAIL; + } + + w_buf[2] = tx_idx; /* tx */ + w_buf[3] = rx_idx; /* rx */ + w_buf[5] = cmd; /* sub command */ + + ret = i2c_smbus_write_i2c_block_data(info->client, w_buf[0], 5, + &w_buf[1]); + if (ret < 0) + goto err_i2c; + + ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, 2, + read_buffer); + if (ret < 0) + goto err_i2c; + + raw_data = ((u16)read_buffer[1] << 8) | read_buffer[0]; + if (cmd == MMS_VSC_CMD_REFER) + raw_data = raw_data >> 4; + + return raw_data; + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, cmd); + return FAIL; +} +#endif + +#if defined(SEC_TKEY_FACTORY_TEST) +static u32 get_raw_data_tkey(struct mms_ts_info *info, u16 key_idx, u8 cmd) +{ + u8 w_buf[4]; + u8 r_buf = 0; + u8 read_buffer[60] = {0}; + int ret, raw_data; + int gpio = info->pdata->gpio_int;/*msm_irq_to_gpio(info->irq);*/ + + disable_irq(info->irq); + + w_buf[0] = ADDR_UNIV_CMD; /* Universal CMD ID */ + w_buf[1] = CMD_ENTER_TEST; /* mode of vendor */ + w_buf[2] = 0xFF; /* Exciting CH*/ + w_buf[3] = 0; /* Sensing CH */ + + if (cmd != VSC_INTENSITY_TK && cmd != VSC_RAW_TK) { + dev_err(&info->client->dev, "%s: not profer command(cmd=%d)\n", + __func__, cmd); + return FAIL; + } + + if (cmd == VSC_INTENSITY_TK) + w_buf[1] = CMD_GET_INTEN_KEY; + else + w_buf[1] = CMD_GET_REFER_KEY; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 3, &w_buf[1]); + + if (ret < 0) + goto err_i2c; + while (gpio_get_value(gpio)) + udelay(100); + + ret = i2c_smbus_read_i2c_block_data(info->client, + CMD_RESULT_SZ, 1, &r_buf); + if (ret < 0) + goto err_i2c; + ret = get_data(info, CMD_RESULT, r_buf, read_buffer); + if (ret < 0) + goto err_i2c; + + raw_data = read_buffer[2*key_idx] | (read_buffer[2*key_idx+1] << 8); + + /* if raw_data < 0, return 0*/ + if (read_buffer[2*key_idx+1] & (1 << 7)) + raw_data = 0; + + touch_is_pressed = 0; + info->enabled = true; + + enable_irq(info->irq); + return raw_data; + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, cmd); + return FAIL; +} +#endif + +static ssize_t show_close_tsp_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + info->ft_flag = 0; + + return snprintf(buf, TSP_BUF_SIZE, "%u\n", 0); +} + +static int check_rx_tx_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[TSP_CMD_STR_LEN] = {0}; + int node; + + if (info->cmd_param[0] < 0 || + info->cmd_param[0] >= TX_NUM || + info->cmd_param[1] < 0 || + info->cmd_param[1] >= RX_NUM) { + snprintf(buff, sizeof(buff) , "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_err(&info->client->dev, "%s: parameter error: %u,%u\n", + __func__, info->cmd_param[0], info->cmd_param[1]); + node = -1; + return node; + } + node = info->cmd_param[1] * RX_NUM + info->cmd_param[0]; + dev_info(&info->client->dev, "%s: node = %d\n", __func__, + node); + return node; + +} + +static void not_support_cmd(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + char buff[16] = {0}; + + set_default_result(info); + sprintf(buff, "%s", "NA"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 4; + dev_info(&info->client->dev, "%s: \"%s(%d)\"\n", __func__, + buff, strnlen(buff, sizeof(buff))); + return; +} + +static void fw_update(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + struct i2c_client *client = info->client; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret = 0; + int fw_ver = 0, ver = 0, hw_rev = 0, fw_bin_ver = 0; + int retries = 5; + const u8 *buff = 0; + mm_segment_t old_fs = {0}; + struct file *fp = NULL; + long fsize = 0, nread = 0; + + #define MMS_TS "/sdcard/melfas_fw.bin" + + set_default_result(info); + + hw_rev = get_hw_version(info); + fw_bin_ver = FW_VERSION; + fw_ver = get_fw_version(info, SEC_CONFIG); + dev_info(&client->dev, "fw_ic_ver = 0x%02x, fw_bin_ver = 0x%02x\n", + fw_ver, fw_bin_ver); + + if (info->cmd_param[0] == 0 + && fw_ver >= fw_bin_ver) { + dev_info(&client->dev, "fw version update does not need\n"); + goto do_not_need_update; + } + + switch (info->cmd_param[0]) { + case BUILT_IN: + buff = MELFAS_binary; + fsize = MELFAS_binary_nLength; + dev_info(&client->dev, "built in fw(0x%02x) is loaded!!\n", + fw_bin_ver); +#if ISC_DL_MODE + ret = isc_fw_update(info); +#else + ret = isp_fw_update(info); +#endif + + if (ret) { + dev_err(&client->dev, + "failed to initialize (%d)\n", ret); + } + + ver = get_fw_version(info, SEC_CONFIG); + info->fw_ic_ver = ver; + + if (info->cmd_param[0] == 1) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + info->cmd_state = 2; + enable_irq(info->irq); + return; + } else if (ver == fw_bin_ver) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + info->cmd_state = 2; + enable_irq(info->irq); + return; + } else { + dev_err(&client->dev, "ERROR : fw version is still wrong (0x%x != 0x%x)\n", + ver, FW_VERSION); + } + + break; + + case UMS: + old_fs = get_fs(); + set_fs(get_ds()); + + fp = filp_open(MMS_TS, O_RDONLY, 0); + if (IS_ERR(fp)) { + dev_err(&client->dev, + "file %s open error:%d\n", MMS_TS, (s32)fp); + info->cmd_state = 3; + goto err_open; + } + + fsize = fp->f_path.dentry->d_inode->i_size; + + buff = kzalloc((size_t)fsize, GFP_KERNEL); + if (!buff) { + dev_err(&client->dev, "fail to alloc buffer for fw\n"); + info->cmd_state = 3; + goto err_alloc; + } + + nread = vfs_read(fp, (char __user *)buff, fsize, &fp->f_pos); + if (nread != fsize) { + dev_err(&client->dev, "fail to read file %s (nread = %ld)\n", + MMS_TS, nread); + 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"); + break; + + default: + dev_err(&client->dev, "invalid fw file type!!\n"); + goto not_support; + } + + disable_irq(info->irq); + while (retries--) { + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + ret = isp_fw_download(info, (const u8 *)buff, + (const size_t)fsize); + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + if (ret < 0) { + dev_err(&client->dev, "retrying flashing\n"); + continue; + } + + ver = get_fw_version(info, SEC_CONFIG); + info->fw_ic_ver = ver; + + if (info->cmd_param[0] == 1) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + info->cmd_state = 2; + enable_irq(info->irq); + return; + } else if (ver == fw_bin_ver) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + info->cmd_state = 2; + enable_irq(info->irq); + return; + } else { + dev_err(&client->dev, "ERROR : fw version is still wrong (0x%x != 0x%x)\n", + ver, FW_VERSION); + } + dev_err(&client->dev, "retrying flashing\n"); + } + +err_fw_size: + kfree(buff); +err_alloc: + filp_close(fp, NULL); +err_open: + set_fs(old_fs); +not_support: +do_not_need_update: + info->cmd_state = 2; + return; +} + +static void get_fw_ver_bin(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int hw_rev; + + set_default_result(info); + hw_rev = get_hw_version(info); + + snprintf(buff, sizeof(buff), "ME0453%02x", FW_VERSION); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_fw_ver_ic(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + + if (info->enabled) { + info->fw_boot_ver = get_fw_version(info, SEC_BOOTLOADER); + info->fw_core_ver = get_fw_version(info, SEC_CORE); + info->fw_ic_ver = get_fw_version(info, SEC_CONFIG); + } + snprintf(buff, sizeof(buff), "ME%02x%02x%02x", + info->fw_boot_ver, info->fw_core_ver, info->fw_ic_ver); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_config_ver(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[20] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "0x%X", info->fw_ic_ver); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_threshold(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int threshold; + + set_default_result(info); + + disable_irq(info->irq); + threshold = i2c_smbus_read_byte_data(info->client, 0x05); + enable_irq(info->irq); + if (threshold < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + return; + } + snprintf(buff, sizeof(buff), "%d", threshold); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void module_off_master(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[3] = {0}; + + mutex_lock(&info->lock); + if (info->enabled) { + disable_irq(info->irq); + info->enabled = false; + touch_is_pressed = 0; + } + mutex_unlock(&info->lock); + + info->pdata->vdd_on(0); + + if (info->pdata->is_vdd_on() == 0) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "NG"); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + if (strncmp(buff, "OK", 2) == 0) + info->cmd_state = 2; + else + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: %s\n", __func__, buff); +} + +static void module_on_master(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[3] = {0}; + + mms_pwr_on_reset(info); + + mutex_lock(&info->lock); + if (!info->enabled) { + enable_irq(info->irq); + info->enabled = true; + } + mutex_unlock(&info->lock); + + if (info->pdata->is_vdd_on() == 1) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "NG"); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + if (strncmp(buff, "OK", 2) == 0) + info->cmd_state = 2; + else + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: %s\n", __func__, buff); + +} + +static void get_chip_vendor(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", "MELFAS"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_chip_name(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", info->pdata->tsp_ic_name); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_reference(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->reference[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); + +} + +static void get_cm_abs(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->raw[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_cm_delta(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->inspection[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_intensity(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->intensity[node]; + + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_x_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int val; + + set_default_result(info); + disable_irq(info->irq); + val = i2c_smbus_read_byte_data(info->client, 0x0B); + enable_irq(info->irq); + if (val < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_err(&info->client->dev, + "%s: fail to read num of x (%d).\n", __func__, val); + + return ; + } + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_y_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int val; + + set_default_result(info); + disable_irq(info->irq); + val = i2c_smbus_read_byte_data(info->client, 0x0C); + enable_irq(info->irq); + if (val < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_err(&info->client->dev, + "%s: fail to read num of y (%d).\n", __func__, val); + + return ; + } + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void run_reference_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + /* CORE 4.5 + get_raw_data_all(info, MMS_VSC_CMD_REFER); + */ + get_raw_data(info, MMS_VSC_CMD_REFER); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s\n", __func__); +} + +static void run_cm_abs_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + /* CORE 4.5 + get_raw_data_all(info, MMS_VSC_CMD_CM_ABS); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + */ + get_raw_data(info, MMS_VSC_CMD_CM_ABS); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s\n", __func__); +} + +static void run_cm_delta_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + /* CORE 4.5 + get_raw_data_all(info, MMS_VSC_CMD_CM_DELTA); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + */ + get_raw_data(info, MMS_VSC_CMD_CM_DELTA); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s\n", __func__); +} + +static void run_intensity_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + /* CORE 4.5 + get_raw_data_all(info, MMS_VSC_CMD_INTENSITY); + */ + get_intensity_data(info); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s\n", __func__); +} + +static ssize_t store_cmd(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + + 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 (info->cmd_is_running == true) { + dev_err(&info->client->dev, "tsp_cmd: other cmd is running.\n"); + goto err_out; + } + + + /* check lock */ + mutex_lock(&info->cmd_lock); + info->cmd_is_running = true; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = 1; + + for (i = 0; i < ARRAY_SIZE(info->cmd_param); i++) + info->cmd_param[i] = 0; + + len = (int)count; + if (*(buf + len - 1) == '\n') + len--; + memset(info->cmd, 0x00, ARRAY_SIZE(info->cmd)); + memcpy(info->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, &info->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, &info->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'; + if (kstrtoint(buff, 10, + info->cmd_param + param_cnt) < 0) + goto err_out; + 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, + info->cmd_param[i]); + + tsp_cmd_ptr->cmd_func(info); + + +err_out: + return count; +} + +static ssize_t show_cmd_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + char buff[16] = {0}; + + dev_info(&info->client->dev, "tsp cmd: status:%d\n", info->cmd_state); + + if (info->cmd_state == 0) + snprintf(buff, sizeof(buff), "WAITING"); + + else if (info->cmd_state == 1) + snprintf(buff, sizeof(buff), "RUNNING"); + + else if (info->cmd_state == 2) + snprintf(buff, sizeof(buff), "OK"); + + else if (info->cmd_state == 3) + snprintf(buff, sizeof(buff), "FAIL"); + + else if (info->cmd_state == 4) + snprintf(buff, sizeof(buff), "NOT_APPLICABLE"); + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", buff); +} + +static ssize_t show_cmd_result(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + + dev_info(&info->client->dev, "tsp cmd: result: %s\n", info->cmd_result); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = 0; + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", info->cmd_result); +} + +#ifdef ESD_DEBUG + +static bool intensity_log_flag; + +static ssize_t show_intensity_logging_on(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + struct file *fp; + char log_data[160] = {0,}; + char buff[16] = {0,}; + mm_segment_t old_fs; + long nwrite; + u32 val; + int i, y, c; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + +#define MELFAS_DEBUG_LOG_PATH "/sdcard/melfas_log" + + dev_info(&client->dev, "%s: start.\n", __func__); + fp = filp_open(MELFAS_DEBUG_LOG_PATH, O_RDWR|O_CREAT, + S_IRWXU|S_IRWXG|S_IRWXO); + if (IS_ERR(fp)) { + dev_err(&client->dev, "%s: fail to open log file\n", __func__); + goto open_err; + } + + intensity_log_flag = 1; + do { + for (y = 0; y < 3; y++) { + /* for tx chanel 0~2 */ + memset(log_data, 0x00, 160); + + snprintf(buff, 16, "%1u: ", y); + strncat(log_data, buff, strnlen(buff, 16)); + + for (i = 0; i < RX_NUM; i++) { + val = get_raw_data_one(info, i, y, + MMS_VSC_CMD_INTENSITY); + snprintf(buff, 16, "%5u, ", val); + strncat(log_data, buff, strnlen(buff, 16)); + } + memset(buff, '\n', 2); + c = (y == 2) ? 2 : 1; + strncat(log_data, buff, c); + nwrite = vfs_write(fp, (const char __user *)log_data, + strnlen(log_data, 160), &fp->f_pos); + } + usleep_range(5000); + } while (intensity_log_flag); + + filp_close(fp, current->files); + set_fs(old_fs); + + return 0; + + open_err: + set_fs(old_fs); + return FAIL; +} + +static ssize_t show_intensity_logging_off(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + intensity_log_flag = 0; + usleep_range(10000); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + return 0; +} + +#endif + +#ifdef SEC_TKEY_FACTORY_TEST +static ssize_t tkey_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int tkey_threshold; + + disable_irq(info->irq); + tkey_threshold = i2c_smbus_read_byte_data(info->client, 0x20); + dev_info(&client->dev, "touch key threshold: %d\n", tkey_threshold); + enable_irq(info->irq); + return snprintf(buf, sizeof(int), "%d\n", tkey_threshold); +} + +static ssize_t back_key_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int i, ret, val; + + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) { + if (info->keycode[i] == KEY_BACK) + break; + } + dev_info(&client->dev, "back key state: %d\n", info->key_pressed[i]); + + /* back key*/ + ret = get_raw_data_tkey(info, 1, VSC_INTENSITY_TK); + + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t home_key_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int i, ret, val; + + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) { + if (info->keycode[i] == KEY_HOMEPAGE) + break; + } + dev_info(&client->dev, "home key state: %d\n", info->key_pressed[i]); + + /* home key*/ + ret = get_raw_data_tkey(info, 1, VSC_INTENSITY_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t recent_key_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int i, ret, val; + + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) { + if (info->keycode[i] == KEY_F3) + break; + } + dev_info(&client->dev, "recent key state: %d\n", info->key_pressed[i]); + + /* recent key*/ + ret = get_raw_data_tkey(info, 2, VSC_INTENSITY_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t menu_key_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int i, ret, val; + + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) { + if (info->keycode[i] == KEY_MENU) + break; + } + dev_info(&client->dev, "menu key state: %d\n", info->key_pressed[i]); + + /* menu key*/ + ret = get_raw_data_tkey(info, 0, VSC_INTENSITY_TK); + + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t tkey_rawcounter_show0(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + u32 ret; + u16 val; + + /* back key*/ + ret = get_raw_data_tkey(info, 0, VSC_RAW_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t tkey_rawcounter_show1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int ret; + u16 val; + + /* home key*/ + ret = get_raw_data_tkey(info, 1, VSC_RAW_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t tkey_rawcounter_show2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int ret; + u16 val; + + /* recent key*/ + ret = get_raw_data_tkey(info, 2, VSC_RAW_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t tkey_rawcounter_show3(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int ret; + u16 val; + + /* menu key*/ + ret = get_raw_data_tkey(info, 3, VSC_RAW_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} +#endif + + + +#ifdef SEC_TKEY_FACTORY_TEST +static DEVICE_ATTR(touchkey_threshold, S_IRUGO, tkey_threshold_show, NULL); +static DEVICE_ATTR(touchkey_back, S_IRUGO, back_key_state_show, NULL); +static DEVICE_ATTR(touchkey_home, S_IRUGO, home_key_state_show, NULL); +static DEVICE_ATTR(touchkey_recent, S_IRUGO, recent_key_state_show, NULL); +static DEVICE_ATTR(touchkey_menu, S_IRUGO, menu_key_state_show, NULL); +static DEVICE_ATTR(touchkey_raw_data0, S_IRUGO, tkey_rawcounter_show0, NULL) ; +static DEVICE_ATTR(touchkey_raw_data1, S_IRUGO, tkey_rawcounter_show1, NULL) ; +static DEVICE_ATTR(touchkey_raw_data2, S_IRUGO, tkey_rawcounter_show2, NULL) ; +static DEVICE_ATTR(touchkey_raw_data3, S_IRUGO, tkey_rawcounter_show3, NULL) ; + +static struct attribute *touchkey_attributes[] = { + &dev_attr_touchkey_threshold.attr, + &dev_attr_touchkey_back.attr, + &dev_attr_touchkey_home.attr, + &dev_attr_touchkey_recent.attr, + &dev_attr_touchkey_menu.attr, + &dev_attr_touchkey_raw_data0.attr, + &dev_attr_touchkey_raw_data1.attr, + &dev_attr_touchkey_raw_data2.attr, + &dev_attr_touchkey_raw_data3.attr, + NULL, +}; +static struct attribute_group touchkey_attr_group = { + .attrs = touchkey_attributes, +}; + +static int factory_init_tk(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + int ret; + + info->dev_tk = device_create(sec_class, NULL, (dev_t)NULL, info, + "sec_touchkey"); + if (IS_ERR(info->dev_tk)) { + dev_err(&client->dev, "Failed to create fac touchkey dev\n"); + ret = -ENODEV; + info->dev_tk = NULL; + goto err_create_dev_tk; + } + + ret = sysfs_create_group(&info->dev_tk->kobj, &touchkey_attr_group); + if (ret) { + dev_err(&client->dev, "Failed to create sysfs (touchkey_attr_group).\n"); + ret = (ret > 0) ? -ret : ret; + goto err_create_tk_sysfs; + } + + info->key_pressed = kzalloc(sizeof(bool) * ARRAY_SIZE(info->keycode), + GFP_KERNEL); + if (!info->key_pressed) { + dev_err(&client->dev, "Failed to allocate memory\n"); + ret = -ENOMEM; + goto err_alloc; + } + + return 0; + +err_alloc: + sysfs_remove_group(&info->dev_tk->kobj, &touchkey_attr_group); +err_create_tk_sysfs: +err_create_dev_tk: + return ret; +} +#endif + + +static DEVICE_ATTR(close_tsp_test, S_IRUGO, show_close_tsp_test, NULL); +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); +#ifdef ESD_DEBUG +static DEVICE_ATTR(intensity_logging_on, S_IRUGO, show_intensity_logging_on, + NULL); +static DEVICE_ATTR(intensity_logging_off, S_IRUGO, show_intensity_logging_off, + NULL); +#endif + +static struct attribute *sec_touch_facotry_attributes[] = { + &dev_attr_close_tsp_test.attr, + &dev_attr_cmd.attr, + &dev_attr_cmd_status.attr, + &dev_attr_cmd_result.attr, +#ifdef ESD_DEBUG + &dev_attr_intensity_logging_on.attr, + &dev_attr_intensity_logging_off.attr, +#endif + NULL, +}; + +static struct attribute_group sec_touch_factory_attr_group = { + .attrs = sec_touch_facotry_attributes, +}; +#endif /* SEC_TSP_FACTORY_TEST */ + + +struct class *sec_class; + +static int __init mms_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct mms_ts_info *info; + struct input_dev *input_dev; + int ret = 0; + int i; + int boot_v, core_v, config_v, fw_v; +#ifdef SEC_TSP_FACTORY_TEST + struct device *fac_dev_ts; +#endif + touch_is_pressed = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -EIO; + + info = kzalloc(sizeof(struct mms_ts_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, "Failed to allocate memory\n"); + ret = -ENOMEM; + goto err_alloc; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&client->dev, "Failed to allocate memory for input device\n"); + ret = -ENOMEM; + goto err_input_alloc; + } + + info->client = client; + info->input_dev = input_dev; + info->pdata = client->dev.platform_data; + info->irq = -1; + mutex_init(&info->lock); + if (info->pdata) { + info->max_x = info->pdata->max_x; + info->max_y = info->pdata->max_y; + info->invert_x = info->pdata->invert_x; + info->invert_y = info->pdata->invert_y; + } else { + info->max_x = 720; + info->max_y = 1280; + } + + client->irq = gpio_to_irq(info->pdata->gpio_int); + + i2c_set_clientdata(client, info); +/* + ret = get_hw_version(info); + if (ret < 0 && ret != 0xff) { + dev_err(&client->dev, + "failed to i2c transfer..no device[%d]\n", ret); + goto err_i2c_transfer; + } +*/ + info->register_cb = info->pdata->register_cb; + info->callbacks.inform_charger = melfas_ta_cb; + if (info->register_cb) + info->register_cb(&info->callbacks); + + info->use_surface_touch = info->pdata->use_surface_touch; + + input_mt_init_slots(input_dev, MAX_FINGERS, 0); + + snprintf(info->phys, sizeof(info->phys), + "%s/input0", dev_name(&client->dev)); + input_dev->name = "sec_touchscreen"; /*= "Melfas MMSxxx Touchscreen";*/ + input_dev->phys = info->phys; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + printk("mms_ts_probe, max_x %d, max_y %d\n", info->max_x, info->max_y); + input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, MAX_WIDTH, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, info->max_x, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, info->max_y, 0, 0); + if (info->use_surface_touch) { + input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MAJOR, + 0, MAX_PRESSURE, 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MINOR, + 0, MAX_PRESSURE, 0, 0); + +#if 0 /* SPRD's test code */ + input_set_abs_params(input_dev, ABS_MT_ANGLE, + MIN_ANGLE, MAX_ANGLE, 0, 0); + input_set_abs_params(input_dev, ABS_MT_PALM, + 0, 1, 0, 0); +#endif + } + + if (info->pdata->use_touchkey) { + dev_info(&client->dev, "Melfas ts use touchkey\n"); + info->use_touchkey = info->pdata->use_touchkey; + memcpy(info->keycode, info->pdata->touchkey_keycode, + sizeof(info->pdata->touchkey_keycode)); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(EV_LED, input_dev->evbit); + __set_bit(LED_MISC, input_dev->ledbit); + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) + set_bit(info->keycode[i], input_dev->keybit); + } + + input_set_drvdata(input_dev, info); + + ret = input_register_device(input_dev); + if (ret) { + dev_err(&client->dev, + "Failed to register input dev (%d)\n", ret); + goto err_reg_input_dev; + } + +#ifdef CONFIG_SEC_DVFS +#if TOUCH_BOOSTER + mutex_init(&info->dvfs_lock); + INIT_DELAYED_WORK(&info->work_dvfs_off, set_dvfs_off); + info->dvfs_lock_status = false; +#endif +#endif + /* Turn on touch screen power */ + info->pdata->vdd_on(1); + + /* Key led power */ + info->pdata->tkey_led_vdd_on(1); + +#if ISC_DL_MODE + info->fw_core_ver = get_fw_version(info, SEC_CORE); + dev_info(&client->dev, "core version : 0x%02x\n", info->fw_core_ver); + + if (info->fw_core_ver != 0x53) { + dev_err(&client->dev, "core version must be 0x53\n"); + dev_info(&client->dev, "excute core firmware update\n"); + ret = isp_fw_update(info); + if (ret) { + dev_err(&client->dev, + "Failed to initialize (%d)\n", ret); + goto err_reg_input_dev; + } + info->fw_core_ver = get_fw_version(info, SEC_CORE); + } + + info->fw_ic_ver = get_fw_version(info, SEC_CONFIG); + if ((info->fw_ic_ver < FW_VERSION) || (info->fw_ic_ver == 0xff)) { + dev_info(&client->dev, "firmware update\n"); + dev_info(&client->dev, "ic:0x%x, bin:0x%x\n", + info->fw_ic_ver, FW_VERSION); + ret = isc_fw_update(info); + if (ret) { + dev_err(&client->dev, "retry isp fw update\n"); + ret = isp_fw_update(info); + if (ret) { + dev_err(&client->dev, + "Failed to initialize (%d)\n", ret); + goto err_reg_input_dev; + } + } + } +#else + info->fw_ic_ver = get_fw_version(info, SEC_CONFIG); + if (info->fw_ic_ver == FW_VERSION) + dev_info(&client->dev, "fw update does not need(1)\n"); +/* SPRD remove this part */ +/* + else if (machine_is_jasper2()) + ret = isp_fw_update(info); +*/ + else + dev_info(&client->dev, "fw update does not need(2)\n"); + +#endif + info->palm_status = 0; + info->enabled = true; + + mms_ts_finish_config(info); + +#ifdef CONFIG_HAS_EARLYSUSPEND + info->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 1; + info->early_suspend.suspend = mms_ts_early_suspend; + info->early_suspend.resume = mms_ts_late_resume; + register_early_suspend(&info->early_suspend); +#endif + + boot_v = i2c_smbus_read_byte_data(info->client, 0xE1); + core_v = i2c_smbus_read_byte_data(info->client, 0xE2); + config_v = i2c_smbus_read_byte_data(info->client, 0xE3); + fw_v = i2c_smbus_read_byte_data(info->client, 0xF3); + + dev_info(&client->dev, "Boot:0x%02x, CORE:0x%02x, CONFIG:0x%02x, %d\n", + boot_v, core_v, config_v, fw_v); + +#ifdef SEC_TSP_FACTORY_TEST + INIT_LIST_HEAD(&info->cmd_list_head); + for (i = 0; i < ARRAY_SIZE(tsp_cmds); i++) + list_add_tail(&tsp_cmds[i].list, &info->cmd_list_head); + + mutex_init(&info->cmd_lock); + info->cmd_is_running = false; + + sec_class = class_create(THIS_MODULE, "sec"); + if (IS_ERR(sec_class)) { + pr_err("Failed to create class(sec)!\n"); + return PTR_ERR(sec_class); + } + + fac_dev_ts = device_create(sec_class, + NULL, 0, info, "tsp"); + if (IS_ERR(fac_dev_ts)) + dev_err(&client->dev, "Failed to create device for the sysfs\n"); + + ret = sysfs_create_group(&fac_dev_ts->kobj, + &sec_touch_factory_attr_group); + if (ret < 0) { + dev_err(&client->dev, "Failed to create sysfs group\n"); + goto err_sysfs_create_group_touch; + } +#endif + +#ifdef SEC_TKEY_FACTORY_TEST + ret = factory_init_tk(info); + if (ret < 0) { + dev_err(&client->dev, "Failed to init factory init (tk)\n"); + goto err_factory_init; + } +#endif + +#ifdef CONFIG_LEDS_CLASS + if (info->pdata->use_touchkey) { + info->leds.name = TOUCHKEY_BACKLIGHT; + info->leds.brightness = LED_FULL; + info->leds.max_brightness = LED_FULL; + info->leds.brightness_set = msm_tkey_led_set; + + ret = led_classdev_register(&client->dev, &info->leds); + if (ret) { + dev_err(&client->dev, + "Failed to register led(%d)\n", ret); + goto fail_led_reg; + } + } +#endif + + return 0; +#ifdef CONFIG_LEDS_CLASS +fail_led_reg: + led_classdev_unregister(&info->leds); +#endif +#ifdef SEC_TSP_FACTORY_TEST +err_sysfs_create_group_touch: + sysfs_remove_group(&fac_dev_ts->kobj, + &sec_touch_factory_attr_group); +#endif +#ifdef SEC_TKEY_FACTORY_TEST +err_factory_init: + free_irq(info->irq, info); +#endif +err_reg_input_dev: + input_free_device(input_dev); +//err_i2c_transfer: +err_input_alloc: + kfree(info->fw_name); + kfree(info); +err_alloc: + /* turn off power */ + info->pdata->vdd_on(0); + /* Key led power */ + info->pdata->tkey_led_vdd_on(0); + return ret; +} + +static int __exit mms_ts_remove(struct i2c_client *client) +{ + struct mms_ts_info *info = i2c_get_clientdata(client); + + led_classdev_unregister(&info->leds); + if (info->irq >= 0) + free_irq(info->irq, info); + input_unregister_device(info->input_dev); +#ifdef SEC_TKEY_FACTORY_TEST + sysfs_remove_group(&info->dev_tk->kobj, &touchkey_attr_group); + kfree(info->key_pressed); +#endif + kfree(info->fw_name); + kfree(info); + + return 0; +} + +#if defined(CONFIG_PM) || defined(CONFIG_HAS_EARLYSUSPEND) +static int mms_ts_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mms_ts_info *info = i2c_get_clientdata(client); + + if (!info->enabled) + return 0; + + pr_notice("%s: users=%d\n", __func__, info->input_dev->users); + mutex_lock(&info->input_dev->mutex); + if (!info->input_dev->users) + goto out; +#ifdef CONFIG_LEDS_CLASS + if (info->pdata->use_touchkey) { + info->tkey_led_reserved = true; + info->pdata->tkey_led_vdd_on(0); + } +#endif + disable_irq(info->irq); + info->enabled = false; + touch_is_pressed = 0; + release_all_fingers(info); + info->pdata->vdd_on(0); + msleep(50); + +out: + mutex_unlock(&info->input_dev->mutex); + return 0; +} + +static int mms_ts_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mms_ts_info *info = i2c_get_clientdata(client); + + if (info->enabled) + return 0; + + pr_notice("%s: users=%d\n", __func__, info->input_dev->users); + + info->pdata->vdd_on(1); + msleep(120); +#ifdef CONFIG_LEDS_CLASS + if (info->pdata->use_touchkey && info->tkey_led_reserved) { + info->tkey_led_reserved = false; + info->pdata->tkey_led_vdd_on(1); + } +#endif + + if (info->ta_status) { + dev_notice(&client->dev, "TA connect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x1); + } else { + dev_notice(&client->dev, "TA disconnect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x2); + } + + mutex_lock(&info->input_dev->mutex); + info->enabled = true; + mms_set_noise_mode(info); + enable_irq(info->irq); + mutex_unlock(&info->input_dev->mutex); + + return 0; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mms_ts_early_suspend(struct early_suspend *h) +{ + struct mms_ts_info *info; + info = container_of(h, struct mms_ts_info, early_suspend); + mms_ts_suspend(&info->client->dev); +} + +static void mms_ts_late_resume(struct early_suspend *h) +{ + struct mms_ts_info *info; + info = container_of(h, struct mms_ts_info, early_suspend); + mms_ts_resume(&info->client->dev); +} +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static const struct dev_pm_ops mms_ts_pm_ops = { + .suspend = mms_ts_suspend, + .resume = mms_ts_resume, +}; +#endif + +static const struct i2c_device_id mms_ts_id[] = { + { "mms_ts", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mms_ts_id); + +static struct i2c_driver mms_ts_driver = { + .probe = mms_ts_probe, + .remove = mms_ts_remove, + .driver = { + .name = "mms_ts", +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) + .pm = &mms_ts_pm_ops, +#endif + }, + .id_table = mms_ts_id, +}; + +static int __init mms_ts_init(void) +{ +#ifdef CONFIG_SAMSUNG_LPM_MODE + if (poweroff_charging) { + pr_notice("%s : LPM Charging Mode!!\n", __func__); + return 0; + } +#endif + + return i2c_add_driver(&mms_ts_driver); +} + +static void __exit mms_ts_exit(void) +{ + i2c_del_driver(&mms_ts_driver); +} + +module_init(mms_ts_init); +module_exit(mms_ts_exit); + +/* Module information */ +MODULE_DESCRIPTION("Touchscreen driver for Melfas MMS-series controllers"); +MODULE_LICENSE("GPL"); -- cgit v1.3.1