/******************** (C) COPYRIGHT 2012 STMicroelectronics ******************** * * File Name : fts.c * Authors : AMS(Analog Mems Sensor) Team * Description : FTS Capacitive touch screen controller (FingerTipS) * ******************************************************************************** * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES * OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE * PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. * AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * * THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS. ******************************************************************************** * REVISON HISTORY * DATE | DESCRIPTION * 03/09/2012| First Release * 08/11/2012| Code migration * 23/01/2013| SEC Factory Test * 29/01/2013| Support Hover Events * 08/04/2013| SEC Factory Test Add more - hover_enable, glove_mode, clear_cover_mode, fast_glove_mode * 09/04/2013| Support Blob Information *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_TRUSTONIC_TRUSTED_UI #include #endif #define SCAILE_FOR_LSI #ifdef CONFIG_OF #ifndef USE_OPEN_CLOSE #define USE_OPEN_CLOSE #undef CONFIG_HAS_EARLYSUSPEND #undef CONFIG_PM #endif #endif #ifdef CONFIG_HAS_EARLYSUSPEND #include #endif #include #include "fts_ts.h" static struct i2c_driver fts_i2c_driver; #ifdef FTS_SUPPORT_TOUCH_KEY struct fts_touchkey fts_touchkeys[] = { { .value = 0x01, .keycode = KEY_RECENT, .name = "recent", }, { .value = 0x02, .keycode = KEY_BACK, .name = "back", }, }; #endif #ifdef CONFIG_GLOVE_TOUCH enum TOUCH_MODE { FTS_TM_NORMAL = 0, FTS_TM_GLOVE, }; #endif #ifdef USE_OPEN_CLOSE static int fts_input_open(struct input_dev *dev); static void fts_input_close(struct input_dev *dev); #ifdef USE_OPEN_DWORK static void fts_open_work(struct work_struct *work); #endif #endif static int fts_stop_device(struct fts_ts_info *info); static int fts_start_device(struct fts_ts_info *info); static int fts_irq_enable(struct fts_ts_info *info, bool enable); static void fts_reset_work(struct work_struct *work); void fts_release_all_finger(struct fts_ts_info *info); #ifdef CONFIG_SEC_DEBUG_TSP_LOG static void dump_tsp_rawdata(struct work_struct *work); struct delayed_work * p_debug_work; #endif #if (!defined(CONFIG_HAS_EARLYSUSPEND)) && (!defined(CONFIG_PM)) && !defined(USE_OPEN_CLOSE) static int fts_suspend(struct i2c_client *client, pm_message_t mesg); static int fts_resume(struct i2c_client *client); #endif #ifdef CONFIG_HAS_EARLYSUSPEND static void fts_early_suspend(struct early_suspend *h) { struct fts_ts_info *info; info = container_of(h, struct fts_ts_info, early_suspend); fts_suspend(info->client, PMSG_SUSPEND); } static void fts_late_resume(struct early_suspend *h) { struct fts_ts_info *info; info = container_of(h, struct fts_ts_info, early_suspend); fts_resume(info->client); } #endif int fts_write_reg(struct fts_ts_info *info, unsigned char *reg, unsigned short num_com) { struct i2c_msg xfer_msg[2]; int ret; if (info->touch_stopped) { tsp_debug_err(true, &info->client->dev, "%s: Sensor stopped\n", __func__); goto exit; } #ifdef CONFIG_TRUSTONIC_TRUSTED_UI if (TRUSTEDUI_MODE_INPUT_SECURED & trustedui_get_current_mode()) { tsp_debug_err(true, &info->client->dev, "%s TSP no accessible from Linux, TUI is enabled!\n", __func__); return -EIO; } #endif mutex_lock(&info->i2c_mutex); xfer_msg[0].addr = info->client->addr; xfer_msg[0].len = num_com; xfer_msg[0].flags = 0; xfer_msg[0].buf = reg; ret = i2c_transfer(info->client->adapter, xfer_msg, 1); mutex_unlock(&info->i2c_mutex); return ret; exit: return 0; } int fts_read_reg(struct fts_ts_info *info, unsigned char *reg, int cnum, unsigned char *buf, int num) { struct i2c_msg xfer_msg[2]; int ret; if (info->touch_stopped) { tsp_debug_err(true, &info->client->dev, "%s: Sensor stopped\n", __func__); goto exit; } #ifdef CONFIG_TRUSTONIC_TRUSTED_UI if (TRUSTEDUI_MODE_INPUT_SECURED & trustedui_get_current_mode()) { tsp_debug_err(true, &info->client->dev, "%s TSP no accessible from Linux, TUI is enabled!\n", __func__); return -EIO; } #endif mutex_lock(&info->i2c_mutex); xfer_msg[0].addr = info->client->addr; xfer_msg[0].len = cnum; xfer_msg[0].flags = 0; xfer_msg[0].buf = reg; xfer_msg[1].addr = info->client->addr; xfer_msg[1].len = num; xfer_msg[1].flags = I2C_M_RD; xfer_msg[1].buf = buf; ret = i2c_transfer(info->client->adapter, xfer_msg, 2); mutex_unlock(&info->i2c_mutex); return ret; exit: return 0; } #ifdef FTS_SUPPORT_STRINGLIB static int fts_read_from_string(struct fts_ts_info *info, unsigned short *reg, unsigned char *data, int length) { unsigned char string_reg[3]; unsigned char *buf; #ifdef CONFIG_TRUSTONIC_TRUSTED_UI if (TRUSTEDUI_MODE_INPUT_SECURED & trustedui_get_current_mode()) { tsp_debug_err(true, &info->client->dev, "%s TSP no accessible from Linux, TUI is enabled!\n", __func__); return -EIO; } #endif string_reg[0] = 0xD0; string_reg[1] = (*reg >> 8) & 0xFF; string_reg[2] = *reg & 0xFF; if (info->digital_rev == FTS_DIGITAL_REV_1) { return fts_read_reg(info, string_reg, 3, data, length); } else { int rtn; buf = kzalloc(length + 1, GFP_KERNEL); if (buf == NULL) { tsp_debug_info(true, &info->client->dev, "%s: kzalloc error.\n", __func__); return -1; } rtn = fts_read_reg(info, string_reg, 3, buf, length + 1); if (rtn >= 0) memcpy(data, &buf[1], length); kfree(buf); return rtn; } } /* * int fts_write_to_string(struct fts_ts_info *, unsigned short *, unsigned char *, int) * send command or write specfic value to the string area. * string area means guest image or brane firmware.. etc.. */ static int fts_write_to_string(struct fts_ts_info *info, unsigned short *reg, unsigned char *data, int length) { struct i2c_msg xfer_msg[3]; unsigned char *regAdd; int ret; if (info->touch_stopped) { tsp_debug_err(true, &info->client->dev, "%s: Sensor stopped\n", __func__); return 0; } regAdd = kzalloc(length + 6, GFP_KERNEL); if (regAdd == NULL) { tsp_debug_info(true, &info->client->dev, "%s: kzalloc error.\n", __func__); return -1; } mutex_lock(&info->i2c_mutex); /* msg[0], length 3*/ regAdd[0] = 0xb3; regAdd[1] = 0x20; regAdd[2] = 0x01; xfer_msg[0].addr = info->client->addr; xfer_msg[0].len = 3; xfer_msg[0].flags = 0; xfer_msg[0].buf = ®Add[0]; /* msg[0], length 3*/ /* msg[1], length 4*/ regAdd[3] = 0xb1; regAdd[4] = (*reg >> 8) & 0xFF; regAdd[5] = *reg & 0xFF; memcpy(®Add[6], data, length); /*regAdd[3] : B1 address, [4], [5] : String Address, [6]...: data */ xfer_msg[1].addr = info->client->addr; xfer_msg[1].len = 3 + length; xfer_msg[1].flags = 0; xfer_msg[1].buf = ®Add[3]; /* msg[1], length 4*/ ret = i2c_transfer(info->client->adapter, xfer_msg, 2); if (ret == 2) { tsp_debug_info(true, &info->client->dev, "%s: string command is OK.\n", __func__); regAdd[0] = FTS_CMD_NOTIFY; regAdd[1] = *reg & 0xFF; regAdd[2] = (*reg >> 8) & 0xFF; xfer_msg[0].addr = info->client->addr; xfer_msg[0].len = 3; xfer_msg[0].flags = 0; xfer_msg[0].buf = regAdd; ret = i2c_transfer(info->client->adapter, xfer_msg, 1); if (ret != 1) tsp_debug_info(true, &info->client->dev, "%s: string notify is failed.\n", __func__); else tsp_debug_info(true, &info->client->dev, "%s: string notify is OK[%X].\n", __func__, *data); } else tsp_debug_info(true, &info->client->dev, "%s: string command is failed. ret: %d\n", __func__, ret); mutex_unlock(&info->i2c_mutex); kfree(regAdd); return ret; } #endif static void fts_delay(unsigned int ms) { if (ms < 20) usleep_range(ms * 1000, ms * 1000); else msleep(ms); } void fts_command(struct fts_ts_info *info, unsigned char cmd) { unsigned char regAdd = 0; int ret = 0; regAdd = cmd; ret = fts_write_reg(info, ®Add, 1); tsp_debug_info(true, &info->client->dev, "FTS Command (%02X) , ret = %d \n", cmd, ret); } void fts_enable_feature(struct fts_ts_info *info, unsigned char cmd, int enable) { unsigned char regAdd[2] = {0xC1, 0x00}; int ret = 0; if (!enable) regAdd[0] = 0xC2; regAdd[1] = cmd; ret = fts_write_reg(info, ®Add[0], 2); tsp_debug_info(true, &info->client->dev, "FTS %s Feature (%02X %02X) , ret = %d \n", (enable)?"Enable":"Disable", regAdd[0], regAdd[1], ret); } static void fts_set_cover_type(struct fts_ts_info *info, bool enable) { tsp_debug_info(true, &info->client->dev, "%s: %d\n", __func__, info->cover_type); switch (info->cover_type) { case FTS_VIEW_WIRELESS: case FTS_VIEW_COVER: fts_enable_feature(info, FTS_FEATURE_COVER_GLASS, enable); break; case FTS_VIEW_WALLET: fts_enable_feature(info, FTS_FEATURE_COVER_WALLET, enable); break; case FTS_FLIP_WALLET: case FTS_LED_COVER: case FTS_MONTBLANC_COVER: fts_enable_feature(info, FTS_FEATURE_COVER_LED, enable); break; case FTS_CLEAR_FLIP_COVER : fts_enable_feature(info, FTS_FEATURE_COVER_CLEAR_FLIP, enable); break; case FTS_CHARGER_COVER: case FTS_COVER_NOTHING1: case FTS_COVER_NOTHING2: default: tsp_debug_err(true, &info->client->dev, "%s: not change touch state, %d\n", __func__, info->cover_type); break; } } void fts_change_scan_rate(struct fts_ts_info *info, unsigned char cmd) { unsigned char regAdd[2] = {0xC3, 0x00}; int ret = 0; regAdd[1] = cmd; ret = fts_write_reg(info, ®Add[0], 2); tsp_debug_dbg(true, &info->client->dev, "FTS %s Scan Rate (%02X %02X) , ret = %d \n", (cmd == FTS_CMD_FAST_SCAN) ? "90Hz" : (cmd == FTS_CMD_SLOW_SCAN) ? "60Hz" : "30Hz", regAdd[0], regAdd[1], ret); } void fts_systemreset(struct fts_ts_info *info) { unsigned char regAdd[4] = { 0xB6, 0x00, 0x23, 0x01 }; tsp_debug_info(true, &info->client->dev, "FTS SystemReset\n"); fts_write_reg(info, ®Add[0], 4); fts_delay(10); } static void fts_interrupt_set(struct fts_ts_info *info, int enable) { unsigned char regAdd[4] = { 0xB6, 0x00, 0x1C, enable }; if (enable) tsp_debug_info(true, &info->client->dev, "FTS INT Enable\n"); else tsp_debug_info(true, &info->client->dev, "FTS INT Disable\n"); fts_write_reg(info, ®Add[0], 4); } static int fts_read_chip_id(struct fts_ts_info *info) { unsigned char regAdd[3] = {0xB6, 0x00, 0x07}; unsigned char val[7] = {0}; int ret; ret = fts_read_reg(info, regAdd, 3, (unsigned char *)val, 7); if (ret < 0) { tsp_debug_err(true, &info->client->dev, "%s failed. ret: %d\n", __func__, ret); return ret; } tsp_debug_info(true, &info->client->dev, "FTS %02X%02X%02X = %02X %02X %02X %02X %02X %02X\n", regAdd[0], regAdd[1], regAdd[2], val[1], val[2], val[3], val[4], val[5], val[6]); if (val[1] != FTS_ID0) return -FTS_ERROR_INVALID_CHIP_ID; if (val[2] == FTS_ID1) info->digital_rev = FTS_DIGITAL_REV_1; else if (val[2] == FTS_ID2) info->digital_rev = FTS_DIGITAL_REV_2; else return -FTS_ERROR_INVALID_CHIP_VERSION_ID; return ret; } static int fts_wait_for_ready(struct fts_ts_info *info) { int rc; unsigned char regAdd; unsigned char data[FTS_EVENT_SIZE]; int retry = 0; int err_cnt=0; memset(data, 0x0, FTS_EVENT_SIZE); regAdd = READ_ONE_EVENT; rc = -1; while (fts_read_reg(info, ®Add, 1, (unsigned char *)data, FTS_EVENT_SIZE)) { if (data[0] == EVENTID_CONTROLLER_READY) { rc = 0; break; } if (data[0] == EVENTID_ERROR) { if (err_cnt++ > 32) { rc = -FTS_ERROR_EVENT_ID; break; } continue; } if (retry++ > FTS_RETRY_COUNT) { rc = -FTS_ERROR_TIMEOUT; tsp_debug_err(true, &info->client->dev, "%s: Time Over\n", __func__); if (info->lowpower_mode) { schedule_delayed_work(&info->reset_work, msecs_to_jiffies(10)); } break; } fts_delay(20); } tsp_debug_info(true, &info->client->dev, "%s: %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); return rc; } int fts_get_version_info(struct fts_ts_info *info) { int rc; unsigned char regAdd[3]; unsigned char data[FTS_EVENT_SIZE]; int retry = 0; fts_command(info, FTS_CMD_RELEASEINFO); memset(data, 0x0, FTS_EVENT_SIZE); regAdd[0] = READ_ONE_EVENT; rc = -1; while (fts_read_reg(info, ®Add[0], 1, (unsigned char *)data, FTS_EVENT_SIZE)) { if (data[0] == EVENTID_INTERNAL_RELEASE_INFO) { // Internal release Information info->fw_version_of_ic = (data[3] << 8) + data[4]; info->config_version_of_ic = (data[6] << 8) + data[5]; info->ic_product_id = data[2]; } else if (data[0] == EVENTID_EXTERNAL_RELEASE_INFO) { // External release Information info->fw_main_version_of_ic = (data[1] << 8) + data[2]; rc = 0; break; } if (retry++ > FTS_RETRY_COUNT) { rc = -FTS_ERROR_TIMEOUT; tsp_debug_err(true, &info->client->dev, "%s: Time Over\n", __func__); break; } } tsp_debug_info(true, &info->client->dev, "IC product id : 0x%02X " "IC Firmware Version : 0x%04X " "IC Config Version : 0x%04X " "IC Main Version : 0x%04X\n", info->ic_product_id, info->fw_version_of_ic, info->config_version_of_ic, info->fw_main_version_of_ic); return rc; } #ifdef FTS_SUPPORT_NOISE_PARAM int fts_get_noise_param_address(struct fts_ts_info *info) { int rc; unsigned char regAdd[3]; unsigned char rData[3]; struct fts_noise_param *noise_param; int i; noise_param = (struct fts_noise_param *)&info->noise_param; regAdd[0] = 0xd0; regAdd[1] = 0x00; regAdd[2] = 32 * 2; if (info->digital_rev == FTS_DIGITAL_REV_1) rc = fts_read_reg(info, regAdd, 3, (unsigned char *)noise_param->pAddr, 2); else { rc = fts_read_reg(info, regAdd, 3, (unsigned char *)rData, 3); noise_param->pAddr[0] = rData[1] + (rData[2]<<8); } for (i = 1; i < MAX_NOISE_PARAM; i++) { noise_param->pAddr[i] = noise_param->pAddr[0] + i * 2; } for (i = 0; i < MAX_NOISE_PARAM; i++) { tsp_debug_dbg(true, &info->client->dev, "Get Noise Param%d Address = 0x%4x\n", i, noise_param->pAddr[i]); } return rc; } static int fts_get_noise_param(struct fts_ts_info *info) { int rc; unsigned char regAdd[3]; unsigned char data[MAX_NOISE_PARAM * 2]; struct fts_noise_param *noise_param; int i; unsigned char buf[3]; noise_param = (struct fts_noise_param *)&info->noise_param; memset(data, 0x0, MAX_NOISE_PARAM * 2); for (i = 0; i < MAX_NOISE_PARAM; i++) { regAdd[0] = 0xb3; regAdd[1] = 0x00; regAdd[2] = 0x10; fts_write_reg(info, regAdd, 3); regAdd[0] = 0xb1; regAdd[1] = (noise_param->pAddr[i] >> 8) & 0xff; regAdd[2] = noise_param->pAddr[i] & 0xff; rc = fts_read_reg(info, regAdd, 3, &buf[0], 3); noise_param->pData[i] = buf[1]+(buf[2]<<8); //tsp_debug_info(true, &info->client->dev, "0x%2x%2x%2x 0x%2x 0x%2x\n", regAdd[0],regAdd[1],regAdd[2], buf[1], buf[2]); } for (i = 0; i < MAX_NOISE_PARAM; i++) { tsp_debug_dbg(true, &info->client->dev, "Get Noise Param%d Address [ 0x%04x ] = 0x%04x\n", i, noise_param->pAddr[i], noise_param->pData[i]); } return rc; } static int fts_set_noise_param(struct fts_ts_info *info) { int i; unsigned char regAdd[5]; struct fts_noise_param *noise_param; noise_param = (struct fts_noise_param *)&info->noise_param; for (i = 0; i < MAX_NOISE_PARAM; i++) { regAdd[0] = 0xb3; regAdd[1] = 0x00; regAdd[2] = 0x10; fts_write_reg(info, regAdd, 3); regAdd[0] = 0xb1; regAdd[1] = (noise_param->pAddr[i] >> 8) & 0xff; regAdd[2] = noise_param->pAddr[i] & 0xff; regAdd[3] = noise_param->pData[i] & 0xff; regAdd[4] = (noise_param->pData[i] >> 8) & 0xff; fts_write_reg(info, regAdd, 5); } for (i = 0; i < MAX_NOISE_PARAM; i++) { tsp_debug_dbg(true, &info->client->dev, "Set Noise Param%d Address [ 0x%04x ] = 0x%04x\n", i, noise_param->pAddr[i], noise_param->pData[i]); } return 0; } #endif #ifdef FTS_SUPPORT_TOUCH_KEY void fts_release_all_key(struct fts_ts_info *info) { unsigned char key_recent = TOUCH_KEY_RECENT; unsigned char key_back = TOUCH_KEY_BACK; if (info->board->support_mskey && info->tsp_keystatus != TOUCH_KEY_NULL) { if (info->tsp_keystatus & key_recent) { input_report_key(info->input_dev, KEY_RECENT, KEY_RELEASE); tsp_debug_info(true, &info->client->dev, "[TSP_KEY] Recent R!\n"); } if (info->tsp_keystatus & key_back) { input_report_key(info->input_dev, KEY_BACK, KEY_RELEASE); tsp_debug_info(true, &info->client->dev, "[TSP_KEY] back R!\n"); } input_sync(info->input_dev); info->tsp_keystatus = TOUCH_KEY_NULL; #if defined (CONFIG_INPUT_BOOSTER) input_booster_send_event(BOOSTER_DEVICE_TOUCHKEY, BOOSTER_MODE_OFF); #endif } } #endif /* Added for samsung dependent codes such as Factory test, * Touch booster, Related debug sysfs. */ #include "fts_sec.c" static int fts_init(struct fts_ts_info *info) { unsigned char val[16]; unsigned char regAdd[8]; int rc; fts_systemreset(info); rc = fts_wait_for_ready(info); if (rc == -FTS_ERROR_EVENT_ID) { info->fw_version_of_ic = 0; info->config_version_of_ic = 0; info->fw_main_version_of_ic = 0; } else fts_get_version_info(info); rc = fts_read_chip_id(info); if (rc < 0) return 1; rc = fts_fw_update_on_probe(info); if (rc < 0) tsp_debug_err(true, &info->client->dev, "%s: Failed to firmware update\n", __func__); fts_command(info, SLEEPOUT); fts_command(info, SENSEON); #ifdef FTS_SUPPORT_TOUCH_KEY if (info->board->support_mskey) fts_command(info, FTS_CMD_KEY_SENSE_ON); #endif #ifdef FTS_SUPPORT_NOISE_PARAM fts_get_noise_param_address(info); #endif /* fts driver set functional feature */ info->touch_count = 0; info->hover_enabled = false; info->hover_ready = false; info->flip_enable = false; info->mainscr_disable = false; info->deepsleep_mode = false; info->lowpower_mode = false; info->lowpower_flag = 0x00; info->fts_power_state = 0; #ifdef FTS_SUPPORT_TOUCH_KEY info->tsp_keystatus = 0x00; #endif #ifdef FTS_SUPPORT_2NDSCREEN if (info->board->support_2ndscreen) { info->SIDE_Flag = 0; info->previous_SIDE_value = 0; info->run_autotune = true; } #endif #ifdef SEC_TSP_FACTORY_TEST rc = fts_get_channel_info(info); if (rc >= 0) { tsp_debug_info(true, &info->client->dev, "FTS Sense(%02d) Force(%02d)\n", info->SenseChannelLength, info->ForceChannelLength); } else { tsp_debug_info(true, &info->client->dev, "FTS read failed rc = %d\n", rc); tsp_debug_info(true, &info->client->dev, "FTS Initialise Failed\n"); return 1; } info->pFrame = kzalloc(info->SenseChannelLength * info->ForceChannelLength * 2, GFP_KERNEL); if (info->pFrame == NULL) { tsp_debug_info(true, &info->client->dev, "FTS pFrame kzalloc Failed\n"); return 1; } info->cx_data = kzalloc(info->SenseChannelLength * info->ForceChannelLength, GFP_KERNEL); if (!info->cx_data) tsp_debug_err(true, &info->client->dev, "%s: cx_data kzalloc Failed\n", __func__); #endif fts_command(info, FORCECALIBRATION); fts_command(info, FLUSHBUFFER); fts_interrupt_set(info, INT_ENABLE); memset(val, 0x0, 4); regAdd[0] = READ_STATUS; fts_read_reg(info, regAdd, 1, (unsigned char *)val, 4); tsp_debug_info(true, &info->client->dev, "FTS ReadStatus(0x84) : %02X %02X %02X %02X\n", val[0], val[1], val[2], val[3]); tsp_debug_info(true, &info->client->dev, "FTS Initialized\n"); return 0; } static void fts_debug_msg_event_handler(struct fts_ts_info *info, unsigned char data[]) { tsp_debug_dbg(true, &info->client->dev, "%s: %02X %02X %02X %02X %02X %02X %02X %02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); } static unsigned char fts_event_handler_type_b(struct fts_ts_info *info, unsigned char data[], unsigned char LeftEvent) { unsigned char EventNum = 0; unsigned char NumTouches = 0; unsigned char TouchID = 0, EventID = 0, status = 0; unsigned char LastLeftEvent = 0; int x = 0, y = 0, z = 0; int bw = 0, bh = 0, palm = 0, sumsize = 0; #if defined (CONFIG_INPUT_BOOSTER) bool booster_restart = false; #endif #ifdef FTS_SUPPORT_2NDSCREEN u8 currentSideFlag = 0; #endif #ifdef FTS_SUPPORT_SIDE_GESTURE static int longpress_release[FINGER_MAX] = {0, }; #endif #ifdef FTS_SUPPORT_STRINGLIB unsigned short string_addr; unsigned char string_data[10] = {0, }; unsigned char string_clear = 0; #endif for (EventNum = 0; EventNum < LeftEvent; EventNum++) { #if 0 tsp_debug_info(true, &info->client->dev, "%d %2x %2x %2x %2x %2x %2x %2x %2x\n", EventNum, data[EventNum * FTS_EVENT_SIZE], data[EventNum * FTS_EVENT_SIZE+1], data[EventNum * FTS_EVENT_SIZE+2], data[EventNum * FTS_EVENT_SIZE+3], data[EventNum * FTS_EVENT_SIZE+4], data[EventNum * FTS_EVENT_SIZE+5], data[EventNum * FTS_EVENT_SIZE+6], data[EventNum * FTS_EVENT_SIZE+7]); #endif EventID = data[EventNum * FTS_EVENT_SIZE] & 0x0F; if ((EventID >= 3) && (EventID <= 5)) { LastLeftEvent = 0; NumTouches = 1; TouchID = (data[EventNum * FTS_EVENT_SIZE] >> 4) & 0x0F; } else { LastLeftEvent = data[7 + EventNum * FTS_EVENT_SIZE] & 0x0F; NumTouches = (data[1 + EventNum * FTS_EVENT_SIZE] & 0xF0) >> 4; TouchID = data[1 + EventNum * FTS_EVENT_SIZE] & 0x0F; EventID = data[EventNum * FTS_EVENT_SIZE] & 0xFF; status = data[1 + EventNum * FTS_EVENT_SIZE] & 0xFF; } switch (EventID) { case EVENTID_NO_EVENT: break; #ifdef FTS_SUPPORT_TOUCH_KEY case EVENTID_MSKEY: if (info->board->support_mskey) { unsigned char input_keys; input_keys = data[2 + EventNum * FTS_EVENT_SIZE]; if (input_keys == 0x00) fts_release_all_key(info); else { unsigned char change_keys; unsigned char key_state; unsigned char key_recent = TOUCH_KEY_RECENT; unsigned char key_back = TOUCH_KEY_BACK; change_keys = input_keys ^ info->tsp_keystatus; if (change_keys & key_recent) { key_state = input_keys & key_recent; input_report_key(info->input_dev, KEY_RECENT, key_state != 0 ? KEY_PRESS : KEY_RELEASE); tsp_debug_info(true, &info->client->dev, "[TSP_KEY] RECENT %s\n", key_state != 0 ? "P" : "R"); } if (change_keys & key_back) { key_state = input_keys & key_back; input_report_key(info->input_dev, KEY_BACK, key_state != 0 ? KEY_PRESS : KEY_RELEASE); tsp_debug_info(true, &info->client->dev, "[TSP_KEY] BACK %s\n" , key_state != 0 ? "P" : "R"); } #if defined (CONFIG_INPUT_BOOSTER) if ((change_keys & key_recent)||(change_keys & key_back)) { input_booster_send_event(BOOSTER_DEVICE_TOUCHKEY, (key_state != 0 ? KEY_PRESS : KEY_RELEASE)); } #endif input_sync(info->input_dev); } info->tsp_keystatus = input_keys; } break; #endif #ifdef FTS_SUPPORT_SIDE_GESTURE case EVENTID_SIDE_TOUCH: case EVENTID_SIDE_TOUCH_DEBUG: if (info->board->support_sidegesture) { unsigned char event_type = data[1 + EventNum * FTS_EVENT_SIZE]; if ((event_type == FTS_SIDEGESTURE_EVENT_SINGLE_STROKE) || (event_type == FTS_SIDEGESTURE_EVENT_DOUBLE_STROKE) || (event_type == FTS_SIDEGESTURE_EVENT_INNER_STROKE)) { int direction, distance; direction = data[2 + EventNum * FTS_EVENT_SIZE]; distance = *(int *)&data[3 + EventNum * FTS_EVENT_SIZE]; if (direction) input_report_key(info->input_dev, KEY_SIDE_GESTURE_RIGHT, 1); else input_report_key(info->input_dev, KEY_SIDE_GESTURE_LEFT, 1); tsp_debug_info(true, &info->client->dev, "%s: [Gesture] %02X %02X %02X %02X %02X %02X %02X %02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); input_sync(info->input_dev); fts_delay(1); if (direction) input_report_key(info->input_dev, KEY_SIDE_GESTURE_RIGHT, 0); else input_report_key(info->input_dev, KEY_SIDE_GESTURE_LEFT, 0); } else if (event_type == FTS_SIDETOUCH_EVENT_LONG_PRESS) { int sideLongPressfingerID = 0; sideLongPressfingerID = data[2 + EventNum * FTS_EVENT_SIZE]; //Todo : event processing longpress_release[sideLongPressfingerID - 1] = 1; tsp_debug_info(true, &info->client->dev, "%s: [Side Long Press] id:%d %02X %02X %02X %02X %02X %02X %02X %02X\n", __func__, sideLongPressfingerID, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); } else if(event_type == FTS_SIDETOUCH_EVENT_REBOOT_BY_ESD) { tsp_debug_info(true, &info->client->dev, "%s: ESD detected! %02X %02X %02X %02X %02X %02X %02X %02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); schedule_delayed_work(&info->reset_work, msecs_to_jiffies(10)); } else { fts_debug_msg_event_handler(info, &data[EventNum * FTS_EVENT_SIZE]); } } else { unsigned char event_type = data[1 + EventNum * FTS_EVENT_SIZE]; if(event_type == FTS_SIDETOUCH_EVENT_REBOOT_BY_ESD) { tsp_debug_info(true, &info->client->dev, "%s: ESD detected! %02X %02X %02X %02X %02X %02X %02X %02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); schedule_delayed_work(&info->reset_work, msecs_to_jiffies(10)); } else { fts_debug_msg_event_handler(info, &data[EventNum * FTS_EVENT_SIZE]); } } break; #endif case EVENTID_ERROR: if (data[1 + EventNum * FTS_EVENT_SIZE] == 0x08) { // Get Auto tune fail event if (data[2 + EventNum * FTS_EVENT_SIZE] == 0x00) { tsp_debug_info(true, &info->client->dev, "[FTS] Fail Mutual Auto tune\n"); } else if (data[2 + EventNum * FTS_EVENT_SIZE] == 0x01) { tsp_debug_info(true, &info->client->dev, "[FTS] Fail Self Auto tune\n"); } } else if (data[1 + EventNum * FTS_EVENT_SIZE] == 0x09) // Get detect SYNC fail event tsp_debug_info(true, &info->client->dev, "[FTS] Fail detect SYNC\n"); break; case EVENTID_HOVER_ENTER_POINTER: case EVENTID_HOVER_MOTION_POINTER: x = ((data[4 + EventNum * FTS_EVENT_SIZE] & 0xF0) >> 4) | ((data[2 + EventNum * FTS_EVENT_SIZE]) << 4); y = ((data[4 + EventNum * FTS_EVENT_SIZE] & 0x0F) | ((data[3 + EventNum * FTS_EVENT_SIZE]) << 4)); z = data[5 + EventNum * FTS_EVENT_SIZE]; input_mt_slot(info->input_dev, 0); input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 1); input_report_key(info->input_dev, BTN_TOUCH, 0); input_report_key(info->input_dev, BTN_TOOL_FINGER, 1); #ifdef FTS_SUPPORT_2NDSCREEN if (info->board->support_2ndscreen) { info->SIDE_Flag = 0; info->previous_SIDE_value = 0; input_report_key(info->input_dev, BTN_SUBSCREEN_FLAG, 0); } #endif input_report_abs(info->input_dev, ABS_MT_POSITION_X, x); input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y); input_report_abs(info->input_dev, ABS_MT_DISTANCE, 255 - z); break; case EVENTID_HOVER_LEAVE_POINTER: input_mt_slot(info->input_dev, 0); input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0); break; case EVENTID_ENTER_POINTER: if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) break; info->touch_count++; #if defined (CONFIG_INPUT_BOOSTER) booster_restart = true; #endif case EVENTID_MOTION_POINTER: if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) { tsp_debug_info(true, &info->client->dev, "%s: low power mode\n", __func__); fts_release_all_finger(info); break; } if (info->touch_count == 0) { tsp_debug_info(true, &info->client->dev, "%s: count 0\n", __func__); fts_release_all_finger(info); break; } if ((EventID == EVENTID_MOTION_POINTER) && (info->finger[TouchID].state == EVENTID_LEAVE_POINTER)) { tsp_debug_info(true, &info->client->dev, "%s: state leave but point is moved.\n", __func__); break; } if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) break; #ifdef SCAILE_FOR_LSI if (!strncmp(info->board->model_name, "espresso", 8)) { x = data[1 + EventNum * FTS_EVENT_SIZE] + ((data[2 + EventNum * FTS_EVENT_SIZE] & 0x0f) << 8); y = ((data[2 + EventNum * FTS_EVENT_SIZE] & 0xf0) >> 4) + (data[3 + EventNum * FTS_EVENT_SIZE] << 4); } else { x = (data[1 + EventNum * FTS_EVENT_SIZE] + ((data[2 + EventNum * FTS_EVENT_SIZE] & 0x0f) << 8)) * info->board->max_x / 4096; y = (((data[2 + EventNum * FTS_EVENT_SIZE] & 0xf0) >> 4) + (data[3 + EventNum * FTS_EVENT_SIZE] << 4)) * info->board->max_y / 4096; } #else x = data[1 + EventNum * FTS_EVENT_SIZE] + ((data[2 + EventNum * FTS_EVENT_SIZE] & 0x0f) << 8); y = ((data[2 + EventNum * FTS_EVENT_SIZE] & 0xf0) >> 4) + (data[3 + EventNum * FTS_EVENT_SIZE] << 4); #endif bw = data[4 + EventNum * FTS_EVENT_SIZE]; bh = data[5 + EventNum * FTS_EVENT_SIZE]; palm = (data[6 + EventNum * FTS_EVENT_SIZE] >> 7) & 0x01; sumsize = (data[6 + EventNum * FTS_EVENT_SIZE] & 0x7f) << 1; if ((info->touch_count == 1) && (sumsize < 40)) sumsize = 39; #ifdef FTS_SUPPORT_2NDSCREEN if (info->board->support_2ndscreen) { currentSideFlag = (data[7 + EventNum * FTS_EVENT_SIZE] >> 7) & 0x01; z = data[7 + EventNum * FTS_EVENT_SIZE] & 0x7f; } else z = data[7 + EventNum * FTS_EVENT_SIZE]; #else z = data[7 + EventNum * FTS_EVENT_SIZE]; #endif input_mt_slot(info->input_dev, TouchID); input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 1 + (palm << 1)); input_report_key(info->input_dev, BTN_TOUCH, 1); input_report_key(info->input_dev, BTN_TOOL_FINGER, 1); input_report_abs(info->input_dev, ABS_MT_POSITION_X, x); input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y); input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, max(bw, bh)); input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR, min(bw, bh)); #ifdef FTS_SUPPORT_SEC_SWIPE input_report_abs(info->input_dev, ABS_MT_PALM, palm); #endif #if defined(FTS_SUPPORT_SIDE_GESTURE) if (info->board->support_sidegesture) input_report_abs(info->input_dev, ABS_MT_GRIP, 0); #endif info->finger[TouchID].lx = x; info->finger[TouchID].ly = y; break; case EVENTID_LEAVE_POINTER: if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) break; if (info->touch_count <= 0) { tsp_debug_info(true, &info->client->dev, "%s: count 0\n", __func__); fts_release_all_finger(info); break; } info->touch_count--; input_mt_slot(info->input_dev, TouchID); #if defined(FTS_SUPPORT_SIDE_GESTURE) if (info->board->support_sidegesture) { if (longpress_release[TouchID] == 1) { input_report_abs(info->input_dev, ABS_MT_GRIP, 1); tsp_debug_info(true, &info->client->dev, "[FTS] GRIP [%d] %s\n", TouchID, longpress_release[TouchID] ? "LONGPRESS" : "RELEASE"); longpress_release[TouchID] = 0; input_sync(info->input_dev); } } #endif input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0); if (info->touch_count == 0) { /* Clear BTN_TOUCH when All touch are released */ input_report_key(info->input_dev, BTN_TOUCH, 0); input_report_key(info->input_dev, BTN_TOOL_FINGER, 0); #ifdef FTS_SUPPORT_SIDE_SCROLL if (info->board->support_sidescroll) { input_report_key(info->input_dev, BTN_R_FLICK_FLAG, 0); input_report_key(info->input_dev, BTN_L_FLICK_FLAG, 0); } #endif #ifdef FTS_SUPPORT_2NDSCREEN if (info->board->support_2ndscreen) { info->SIDE_Flag = 0; info->previous_SIDE_value = 0; input_report_key(info->input_dev, BTN_SUBSCREEN_FLAG, 0); } #endif #ifdef FTS_SUPPORT_SIDE_GESTURE if (info->board->support_sidegesture) { input_report_key(info->input_dev, KEY_SIDE_GESTURE, 0); input_report_key(info->input_dev, KEY_SIDE_GESTURE_RIGHT, 0); input_report_key(info->input_dev, KEY_SIDE_GESTURE_LEFT, 0); } #endif } break; case EVENTID_STATUS_EVENT: if (status == STATUS_EVENT_GLOVE_MODE) { #ifdef CONFIG_GLOVE_TOUCH int tm; if (data[2 + EventNum * FTS_EVENT_SIZE] == 0x01) info->touch_mode = FTS_TM_GLOVE; else info->touch_mode = FTS_TM_NORMAL; tm = info->touch_mode; input_report_switch(info->input_dev, SW_GLOVE, tm); #endif } else if (status == STATUS_EVENT_RAW_DATA_READY) { unsigned char regAdd[4] = {0xB0, 0x01, 0x29, 0x01}; fts_write_reg(info, ®Add[0], 4); info->hover_ready = true; tsp_debug_info(true, &info->client->dev, "[FTS] Received the Hover Raw Data Ready Event\n"); } else if (status == STATUS_EVENT_FORCE_CAL_MUTUAL) { tsp_debug_dbg(true, &info->client->dev, "[FTS] Received Force Calibration Mutual only Event\n"); } else if (status == STATUS_EVENT_FORCE_CAL_SELF) { tsp_debug_dbg(true, &info->client->dev, "[FTS] Received Force Calibration Self only Event\n"); } else if (status == STATUS_EVENT_WATERMODE_ON) { tsp_debug_info(true, &info->client->dev, "[FTS] Received Water Mode On Event\n"); } else if (status == STATUS_EVENT_WATERMODE_OFF) { tsp_debug_info(true, &info->client->dev, "[FTS] Received Water Mode Off Event\n"); } else if (status == STATUS_EVENT_MUTUAL_CAL_FRAME_CHECK) { tsp_debug_info(true, &info->client->dev, "[FTS] Received Mutual Calib Frame Check Event\n"); } else if (status == STATUS_EVENT_SELF_CAL_FRAME_CHECK) { tsp_debug_info(true, &info->client->dev, "[FTS] Received Self Calib Frame Check Event\n"); } else { fts_debug_msg_event_handler(info, &data[EventNum * FTS_EVENT_SIZE]); } break; #ifdef SEC_TSP_FACTORY_TEST case EVENTID_RESULT_READ_REGISTER: procedure_cmd_event(info, &data[EventNum * FTS_EVENT_SIZE]); break; #endif #ifdef FTS_SUPPORT_SIDE_SCROLL case EVENTID_SIDE_SCROLL: if (info->board->support_sidescroll) { int scroll_flag = data[3 + EventNum * FTS_EVENT_SIZE]; int scroll_thr = data[6 + EventNum * FTS_EVENT_SIZE]; tsp_debug_info(true, &info->client->dev,"[TB] side scroll flag: event: %02X, thr: %02X\n", scroll_flag, scroll_thr); // TODO : Report function call this area if (scroll_flag == 1) { input_report_key(info->input_dev, BTN_R_FLICK_FLAG, 1); input_report_key(info->input_dev, BTN_L_FLICK_FLAG, 0); input_sync(info->input_dev); } else if (scroll_flag == 2) { input_report_key(info->input_dev, BTN_R_FLICK_FLAG, 0); input_report_key(info->input_dev, BTN_L_FLICK_FLAG, 1); input_sync(info->input_dev); } } break; #endif #ifdef FTS_SUPPORT_STRINGLIB case EVENTID_FROM_STRING: string_addr = FTS_CMD_STRING_ACCESS; fts_read_from_string(info, &string_addr, string_data, 6); tsp_debug_info(true, &info->client->dev, "%s: [String] %02X %02X %02X %02X %02X %02X %02X %02X || %04X: %02X, %02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], string_addr, string_data[0], string_data[1]); switch(string_data[1]) { case FTS_STRING_EVENT_REAR_CAM: tsp_debug_info(true, &info->client->dev, "%s: REAR_CAM\n", __func__); break; case FTS_STRING_EVENT_FRONT_CAM: tsp_debug_info(true, &info->client->dev, "%s: FRONT_CAM\n", __func__); break; case FTS_STRING_EVENT_WATCH_STATUS: case FTS_STRING_EVENT_FAST_ACCESS: case FTS_STRING_EVENT_DIRECT_INDICATOR: tsp_debug_info(true, &info->client->dev, "%s: SCRUB[%X]\n", __func__, string_data[1]); input_report_key(info->input_dev, KEY_BLACK_UI_GESTURE, 1); info->scrub_id = (string_data[1] >> 2) & 0x3; info->scrub_x = string_data[2] | (string_data[3] << 8); info->scrub_y = string_data[4] | (string_data[5] << 8); break; case FTS_STRING_EVENT_SPAY: case FTS_STRING_EVENT_SPAY1: case FTS_STRING_EVENT_SPAY2: dev_info(&info->client->dev, "%s: SPAY[%X]\n", __func__, string_data[1]); input_report_key(info->input_dev, KEY_BLACK_UI_GESTURE, 1); info->scrub_id = (string_data[1] >> 2) & 0xF; break; default: tsp_debug_info(true, &info->client->dev, "%s: no event:%X\n", __func__, string_data[1]); break; } input_sync(info->input_dev); if (!info->debug_string) { /* request by display lab, buf clear */ string_clear |= string_data[1]; string_addr = FTS_CMD_STRING_ACCESS + 1; string_data[1] &= ~(string_clear); tsp_debug_info(true, &info->client->dev, "%s: clear bit : string_data[1]: %X, string_clear: %X\n", __func__, string_data[1], string_clear); fts_write_to_string(info, &string_addr, &string_data[1], 1); } else { tsp_debug_info(true, &info->client->dev, "%s: do not clear string_bit\n", __func__); } input_report_key(info->input_dev, KEY_BLACK_UI_GESTURE, 0); break; #endif default: fts_debug_msg_event_handler(info, &data[EventNum * FTS_EVENT_SIZE]); continue; } #ifdef FTS_SUPPORT_2NDSCREEN if (info->board->support_2ndscreen) { if (currentSideFlag != info->previous_SIDE_value) { tsp_debug_info(true, &info->client->dev,"[TB] 2nd screen flag was changed, old:%d c:%d f:%d\n", info->previous_SIDE_value, currentSideFlag, info->SIDE_Flag); info->SIDE_Flag = currentSideFlag; // TODO : Report function call this area input_report_key(info->input_dev, BTN_SUBSCREEN_FLAG, !(!(info->SIDE_Flag)) ); } info->previous_SIDE_value = currentSideFlag; } #endif #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) if (EventID == EVENTID_ENTER_POINTER) tsp_debug_info(true, &info->client->dev, "[P] tID:%d x:%d y:%d w:%d h:%d z:%d s:%d p:%d tc:%d tm:%d\n", TouchID, x, y, bw, bh, z, sumsize, palm, info->touch_count, info->touch_mode); else if (EventID == EVENTID_HOVER_ENTER_POINTER) tsp_debug_dbg(true, &info->client->dev, "[HP] tID:%d x:%d y:%d z:%d\n", TouchID, x, y, z); #else if (EventID == EVENTID_ENTER_POINTER) tsp_debug_info(true, &info->client->dev, "[P] tID:%d tc:%d tm:%d\n", TouchID, info->touch_count, info->touch_mode); else if (EventID == EVENTID_HOVER_ENTER_POINTER) tsp_debug_dbg(true, &info->client->dev, "[HP] tID:%d\n", TouchID); #endif else if (EventID == EVENTID_LEAVE_POINTER) { #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) if (strncmp(info->board->model_name, "G925", 4) == 0) { tsp_debug_info(true, &info->client->dev, "[R] tID:%d mc: %d tc:%d lx: %d ly: %d Ver[%01X%01X%04X%01X%01X%01X]\n", TouchID, info->finger[TouchID].mcount, info->touch_count, info->finger[TouchID].lx, info->finger[TouchID].ly, info->tspid_val,info->tspid2_val, info->fw_main_version_of_ic, info->flip_enable, info->mshover_enabled, info->mainscr_disable); }else{ tsp_debug_info(true, &info->client->dev, "[R] tID:%d mc: %d tc:%d lx: %d ly: %d Ver[%02X%04X%01X%01X%01X]\n", TouchID, info->finger[TouchID].mcount, info->touch_count, info->finger[TouchID].lx, info->finger[TouchID].ly, info->panel_revision, info->fw_main_version_of_ic, info->flip_enable, info->mshover_enabled, info->mainscr_disable); } #else if (strncmp(info->board->model_name, "G925", 4) == 0) { tsp_debug_info(true, &info->client->dev, "[R] tID:%d mc: %d tc:%d Ver[%01X%01X%04X%01X%01X%01X]\n", TouchID, info->finger[TouchID].mcount, info->touch_count, info->tspid_val,info->tspid2_val, info->fw_main_version_of_ic, info->flip_enable, info->mshover_enabled, info->mainscr_disable); }else{ tsp_debug_info(true, &info->client->dev, "[R] tID:%d mc: %d tc:%d Ver[%02X%04X%01X%01X%01X]\n", TouchID, info->finger[TouchID].mcount, info->touch_count, info->panel_revision, info->fw_main_version_of_ic, info->flip_enable, info->mshover_enabled, info->mainscr_disable); } #endif info->finger[TouchID].mcount = 0; } else if (EventID == EVENTID_HOVER_LEAVE_POINTER) { tsp_debug_dbg(true, &info->client->dev, "[HR] tID:%d Ver[%02X%04X%01X%01X]\n", TouchID, info->panel_revision, info->fw_main_version_of_ic, info->flip_enable, info->mshover_enabled); info->finger[TouchID].mcount = 0; } else if (EventID == EVENTID_MOTION_POINTER) info->finger[TouchID].mcount++; if ((EventID == EVENTID_ENTER_POINTER) || (EventID == EVENTID_MOTION_POINTER) || (EventID == EVENTID_LEAVE_POINTER)) info->finger[TouchID].state = EventID; } input_sync(info->input_dev); #if defined (CONFIG_INPUT_BOOSTER) if ((EventID == EVENTID_ENTER_POINTER) || (EventID == EVENTID_LEAVE_POINTER)) { if (booster_restart) input_booster_send_event(BOOSTER_DEVICE_TOUCH, BOOSTER_MODE_ON); if (!info->touch_count) input_booster_send_event(BOOSTER_DEVICE_TOUCH, BOOSTER_MODE_OFF); } #endif return LastLeftEvent; } #ifdef FTS_SUPPORT_TA_MODE static void fts_ta_cb(struct fts_callbacks *cb, int ta_status) { struct fts_ts_info *info = container_of(cb, struct fts_ts_info, callbacks); if (ta_status == 0x01 || ta_status == 0x03) { fts_command(info, FTS_CMD_CHARGER_PLUGGED); info->TA_Pluged = true; tsp_debug_info(true, &info->client->dev, "%s: device_control : CHARGER CONNECTED, ta_status : %x\n", __func__, ta_status); } else { fts_command(info, FTS_CMD_CHARGER_UNPLUGGED); info->TA_Pluged = false; tsp_debug_info(true, &info->client->dev, "%s: device_control : CHARGER DISCONNECTED, ta_status : %x\n", __func__, ta_status); } } #endif /** * fts_interrupt_handler() * * Called by the kernel when an interrupt occurs (when the sensor * asserts the attention irq). * * This function is the ISR thread and handles the acquisition * and the reporting of finger data when the presence of fingers * is detected. */ static irqreturn_t fts_interrupt_handler(int irq, void *handle) { struct fts_ts_info *info = handle; unsigned char regAdd[4] = {0xb6, 0x00, 0x45, READ_ALL_EVENT}; unsigned short evtcount = 0; #ifdef FTS_SUPPORT_SIDE_GESTURE if ((info->board->support_sidegesture) && (info->fts_power_state == FTS_POWER_STATE_LOWPOWER)) { pm_wakeup_event(info->input_dev->dev.parent, 1000); } #endif evtcount = 0; fts_read_reg(info, ®Add[0], 3, (unsigned char *)&evtcount, 2); evtcount = evtcount >> 10; if (evtcount > FTS_FIFO_MAX) evtcount = FTS_FIFO_MAX; if (evtcount > 0) { memset(info->data, 0x0, FTS_EVENT_SIZE * evtcount); fts_read_reg(info, ®Add[3], 1, (unsigned char *)info->data, FTS_EVENT_SIZE * evtcount); fts_event_handler_type_b(info, info->data, evtcount); } #ifdef FTS_SUPPORT_SIDE_GESTURE if ((info->board->support_sidegesture) && (info->fts_power_state == FTS_POWER_STATE_LOWPOWER)) pm_relax(info->input_dev->dev.parent); #endif return IRQ_HANDLED; } static int fts_irq_enable(struct fts_ts_info *info, bool enable) { int retval = 0; if (enable) { if (info->irq_enabled) return retval; retval = request_threaded_irq(info->irq, NULL, fts_interrupt_handler, info->board->irq_type, FTS_TS_DRV_NAME, info); if (retval < 0) { tsp_debug_info(true, &info->client->dev, "%s: Failed to create irq thread %d\n", __func__, retval); return retval; } info->irq_enabled = true; } else { if (info->irq_enabled) { disable_irq(info->irq); free_irq(info->irq, info); info->irq_enabled = false; } } return retval; } #ifdef CONFIG_OF #ifdef FTS_SUPPORT_TA_MODE struct fts_callbacks *fts_charger_callbacks; void tsp_charger_infom(bool en) { pr_err("[TSP]%s: ta:%d\n", __func__, en); if (fts_charger_callbacks && fts_charger_callbacks->inform_charger) fts_charger_callbacks->inform_charger(fts_charger_callbacks, en); } static void fts_tsp_register_callback(void *cb) { fts_charger_callbacks = cb; } #endif #ifdef FTS_SUPPORT_TOUCH_KEY static int fts_led_power_ctrl(void *data, bool on) { struct fts_ts_info *info = (struct fts_ts_info *)data; const struct fts_i2c_platform_data *pdata = info->board; struct device *dev = &info->client->dev; struct regulator *regulator_tk_led = NULL; static bool enabled; int retval = 0; if (enabled == on) return retval; regulator_tk_led = regulator_get(NULL, pdata->regulator_tk_led); if (IS_ERR_OR_NULL(regulator_tk_led)) { tsp_debug_err(true, dev, "%s: Failed to get %s regulator.\n", __func__, pdata->regulator_tk_led); goto out; } tsp_debug_info(true, dev, "%s: %s\n", __func__, on ? "on" : "off"); if (on) { retval = regulator_enable(regulator_tk_led); if (retval) { tsp_debug_err(true, dev, "%s: Failed to enable led%d\n", __func__, retval); goto out; } } else { if (regulator_is_enabled(regulator_tk_led)) regulator_disable(regulator_tk_led); } enabled = on; out: regulator_put(regulator_tk_led); return retval; } #endif static int fts_power_ctrl(void *data, bool on) { struct fts_ts_info *info = (struct fts_ts_info *)data; const struct fts_i2c_platform_data *pdata = info->board; struct device *dev = &info->client->dev; struct regulator *regulator_dvdd = NULL; struct regulator *regulator_avdd = NULL; static bool enabled; int retval = 0; if (enabled == on) return retval; regulator_dvdd = regulator_get(NULL, pdata->regulator_dvdd); if (IS_ERR_OR_NULL(regulator_dvdd)) { tsp_debug_err(true, dev, "%s: Failed to get %s regulator.\n", __func__, pdata->regulator_dvdd); goto out; } regulator_avdd = regulator_get(NULL, pdata->regulator_avdd); if (IS_ERR_OR_NULL(regulator_avdd)) { tsp_debug_err(true, dev, "%s: Failed to get %s regulator.\n", __func__, pdata->regulator_avdd); goto out; } tsp_debug_info(true, dev, "%s: %s\n", __func__, on ? "on" : "off"); if (on) { retval = regulator_enable(regulator_avdd); if (retval) { tsp_debug_err(true, dev, "%s: Failed to enable avdd: %d\n", __func__, retval); goto out; } retval = regulator_enable(regulator_dvdd); if (retval) { tsp_debug_err(true, dev, "%s: Failed to enable vdd: %d\n", __func__, retval); goto out; } retval = pinctrl_select_state(pdata->pinctrl, pdata->pins_default); if (retval < 0) tsp_debug_err(true, dev, "%s: Failed to configure tsp_attn pin\n", __func__); fts_delay(5); } else { if (regulator_is_enabled(regulator_dvdd)) regulator_disable(regulator_dvdd); if (regulator_is_enabled(regulator_avdd)) regulator_disable(regulator_avdd); retval = pinctrl_select_state(pdata->pinctrl, pdata->pins_sleep); if (retval < 0) tsp_debug_err(true, dev, "%s: Failed to configure tsp_attn pin\n", __func__); } enabled = on; out: regulator_put(regulator_dvdd); regulator_put(regulator_avdd); return retval; } static int fts_parse_dt(struct i2c_client *client) { struct device *dev = &client->dev; struct fts_i2c_platform_data *pdata = dev->platform_data; struct device_node *np = dev->of_node; u32 coords[2], lines[2]; int retval = 0; pdata->tspid = of_get_named_gpio(np, "stm,tspid_gpio", 0); if (gpio_is_valid(pdata->tspid)) tsp_debug_info(true, dev, "TSP_ID : %d\n", gpio_get_value(pdata->tspid)); else tsp_debug_err(true, dev, "Failed to get tspid gpio\n"); pdata->tspid2 = of_get_named_gpio(np, "stm,tspid2_gpio", 0); if (gpio_is_valid(pdata->tspid2)) tsp_debug_info(true, dev, "TSP_ID2 : %d\n", gpio_get_value(pdata->tspid2)); else tsp_debug_err(true, dev, "Failed to get tspid2 gpio\n"); pdata->gpio = of_get_named_gpio(np, "stm,irq_gpio", 0); if (gpio_is_valid(pdata->gpio)) { retval = gpio_request_one(pdata->gpio, GPIOF_DIR_IN, "stm,tsp_int"); if (retval) { tsp_debug_err(true, dev, "Unable to request tsp_int [%d]\n", pdata->gpio); return -EINVAL; } } else { tsp_debug_err(true, dev, "Failed to get irq gpio\n"); return -EINVAL; } client->irq = gpio_to_irq(pdata->gpio); if (of_property_read_u32(np, "stm,irq_type", &pdata->irq_type)) { tsp_debug_err(true, dev, "Failed to get irq_type property\n"); return -EINVAL; } if (of_property_read_u32(np, "stm,grip_area", &pdata->grip_area)) tsp_debug_err(true, dev, "Failed to get grip_area property\n"); if (of_property_read_u32_array(np, "stm,max_coords", coords, 2)) { tsp_debug_err(true, dev, "Failed to get max_coords property\n"); return -EINVAL; } pdata->max_x = coords[0]; pdata->max_y = coords[1]; #ifdef CONFIG_SEC_FACTORY if ((lcdtype == S6E3HF2_WQXGA_ID1) || (lcdtype == S6E3HF2_WQXGA_ID2)) { pdata->max_x = 1439; pdata->max_y = 2559; pdata->grip_area = 160; } #endif if (of_property_read_u32_array(np, "stm,num_lines", lines, 2)) tsp_debug_dbg(true, dev, "skipped to get num_lines property\n"); else { pdata->SenseChannelLength = lines[0]; pdata->ForceChannelLength = lines[1]; tsp_debug_info(true, dev, "num_of[rx,tx]: [%d,%d]\n", pdata->SenseChannelLength, pdata->ForceChannelLength); } if (of_property_read_string(np, "stm,regulator_dvdd", &pdata->regulator_dvdd)) { tsp_debug_err(true, dev, "Failed to get regulator_dvdd name property\n"); return -EINVAL; } if (of_property_read_string(np, "stm,regulator_avdd", &pdata->regulator_avdd)) { tsp_debug_err(true, dev, "Failed to get regulator_avdd name property\n"); return -EINVAL; } pdata->power = fts_power_ctrl; /* Optional parmeters(those values are not mandatory) * do not return error value even if fail to get the value */ of_property_read_string(np, "stm,firmware_name", &pdata->firmware_name); if (of_property_read_string_index(np, "stm,project_name", 0, &pdata->project_name)) tsp_debug_dbg(true, dev, "skipped to get project_name property\n"); if (of_property_read_string_index(np, "stm,project_name", 1, &pdata->model_name)) tsp_debug_dbg(true, dev, "skipped to get model_name property\n"); pdata->max_width = 28; pdata->support_hover = true; pdata->support_mshover = true; #ifdef FTS_SUPPORT_TA_MODE pdata->register_cb = fts_tsp_register_callback; #endif #ifdef FTS_SUPPORT_TOUCH_KEY if (of_property_read_u32(np, "stm,num_touchkey", &pdata->num_touchkey)) tsp_debug_dbg(true, dev, "skipped to get num_touchkey property\n"); else { #ifdef FTS_SUPPORT_SIDE_GESTURE pdata->support_sidegesture = true; #endif pdata->support_mskey = true; pdata->touchkey = fts_touchkeys; if (of_property_read_string(np, "stm,regulator_tk_led", &pdata->regulator_tk_led)) tsp_debug_dbg(true, dev, "skipped to get regulator_tk_led name property\n"); else pdata->led_power = fts_led_power_ctrl; } #endif #ifdef CONFIG_SEC_FACTORY pdata->panel_revision = (lcdtype & 0xF000) >> 12; #endif tsp_debug_info(true, dev, "irq :%d, irq_type: 0x%04x, max[x,y]: [%d,%d], grip_area :%d, project/model_name: %s/%s, panel_revision: %d\n", pdata->gpio, pdata->irq_type, pdata->max_x, pdata->max_y, pdata->grip_area, pdata->project_name, pdata->model_name, pdata->panel_revision); return retval; } #endif static int fts_setup_drv_data(struct i2c_client *client) { int retval = 0; struct fts_i2c_platform_data *pdata; struct fts_ts_info *info; /* parse dt */ if (client->dev.of_node) { pdata = devm_kzalloc(&client->dev, sizeof(struct fts_i2c_platform_data), GFP_KERNEL); if (!pdata) { tsp_debug_err(true, &client->dev, "Failed to allocate platform data\n"); return -ENOMEM; } client->dev.platform_data = pdata; retval = fts_parse_dt(client); if (retval) { tsp_debug_err(true, &client->dev, "Failed to parse dt\n"); return retval; } } else { pdata = client->dev.platform_data; } if (!pdata) { tsp_debug_err(true, &client->dev, "No platform data found\n"); return -EINVAL; } if (!pdata->power) { tsp_debug_err(true, &client->dev, "No power contorl found\n"); return -EINVAL; } pdata->pinctrl = devm_pinctrl_get(&client->dev); if (IS_ERR(pdata->pinctrl)) { tsp_debug_err(true, &client->dev, "could not get pinctrl\n"); return PTR_ERR(pdata->pinctrl); } pdata->pins_default = pinctrl_lookup_state(pdata->pinctrl, "on_state"); if (IS_ERR(pdata->pins_default)) tsp_debug_err(true, &client->dev, "could not get default pinstate\n"); pdata->pins_sleep = pinctrl_lookup_state(pdata->pinctrl, "off_state"); if (IS_ERR(pdata->pins_sleep)) tsp_debug_err(true, &client->dev, "could not get sleep pinstate\n"); info = kzalloc(sizeof(struct fts_ts_info), GFP_KERNEL); if (!info) { tsp_debug_err(true, &client->dev, "%s: Failed to alloc mem for info\n", __func__); return -ENOMEM; } info->client = client; info->board = pdata; info->irq = client->irq; info->irq_type = info->board->irq_type; info->irq_enabled = false; info->touch_stopped = false; info->panel_revision = info->board->panel_revision; info->stop_device = fts_stop_device; info->start_device = fts_start_device; info->fts_command = fts_command; info->fts_enable_feature = fts_enable_feature; info->fts_read_reg = fts_read_reg; info->fts_write_reg = fts_write_reg; info->fts_systemreset = fts_systemreset; info->fts_get_version_info = fts_get_version_info; info->fts_wait_for_ready = fts_wait_for_ready; #ifdef FTS_SUPPORT_STRINGLIB info->fts_read_from_string = fts_read_from_string; info->fts_write_to_string = fts_write_to_string; #endif #ifdef FTS_SUPPORT_NOISE_PARAM info->fts_get_noise_param_address = fts_get_noise_param_address; #endif #ifdef USE_OPEN_DWORK INIT_DELAYED_WORK(&info->open_work, fts_open_work); #endif info->delay_time = 300; INIT_DELAYED_WORK(&info->reset_work, fts_reset_work); #ifdef CONFIG_SEC_DEBUG_TSP_LOG INIT_DELAYED_WORK(&info->debug_work, dump_tsp_rawdata); p_debug_work = &info->debug_work; #endif #ifdef SEC_TSP_FACTORY_TEST INIT_DELAYED_WORK(&info->cover_cmd_work, clear_cover_cmd_work); #endif if (info->board->support_hover) tsp_debug_info(true, &info->client->dev, "FTS Support Hover Event \n"); else tsp_debug_info(true, &info->client->dev, "FTS Not support Hover Event \n"); i2c_set_clientdata(client, info); if (pdata->get_ddi_type) { info->ddi_type = pdata->get_ddi_type(); tsp_debug_info(true, &client->dev, "%s: DDI Type is %s[%d]\n", __func__, info->ddi_type ? "MAGNA" : "SDC", info->ddi_type); } return retval; } #ifdef CONFIG_BATTERY_SAMSUNG extern unsigned int lpcharge; #endif static int fts_probe(struct i2c_client *client, const struct i2c_device_id *idp) { int retval; struct fts_ts_info *info = NULL; static char fts_ts_phys[64] = { 0 }; int i = 0; #ifdef SEC_TSP_FACTORY_TEST long j = 0; #endif tsp_debug_info(true, &client->dev, "FTS Driver [12%s]\n", FTS_TS_DRV_VERSION); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { tsp_debug_err(true, &client->dev, "FTS err = EIO!\n"); return -EIO; } #ifdef CONFIG_BATTERY_SAMSUNG if (lpcharge == 1) { tsp_debug_err(true, &client->dev, "%s : Do not load driver due to : lpm %d\n", __func__, lpcharge); return -ENODEV; } #endif /* Build up driver data */ retval = fts_setup_drv_data(client); if (retval < 0) { tsp_debug_err(true, &client->dev, "%s: Failed to set up driver data\n", __func__); goto err_setup_drv_data; } info = (struct fts_ts_info *)i2c_get_clientdata(client); if (!info) { tsp_debug_err(true, &client->dev, "%s: Failed to get driver data\n", __func__); retval = -ENODEV; goto err_get_drv_data; } if (info->board->power) info->board->power(info, true); info->dev = &info->client->dev; info->input_dev = input_allocate_device(); if (!info->input_dev) { tsp_debug_info(true, &info->client->dev, "FTS err = ENOMEM!\n"); retval = -ENOMEM; goto err_input_allocate_device; } info->input_dev->dev.parent = &client->dev; info->input_dev->name = "sec_touchscreen"; snprintf(fts_ts_phys, sizeof(fts_ts_phys), "%s/input1", info->input_dev->name); info->input_dev->phys = fts_ts_phys; info->input_dev->id.bustype = BUS_I2C; #ifdef USE_OPEN_CLOSE info->input_dev->open = fts_input_open; info->input_dev->close = fts_input_close; #endif #ifdef CONFIG_GLOVE_TOUCH input_set_capability(info->input_dev, EV_SW, SW_GLOVE); #endif set_bit(EV_SYN, info->input_dev->evbit); set_bit(EV_KEY, info->input_dev->evbit); set_bit(EV_ABS, info->input_dev->evbit); #ifdef INPUT_PROP_DIRECT set_bit(INPUT_PROP_DIRECT, info->input_dev->propbit); #endif set_bit(BTN_TOUCH, info->input_dev->keybit); set_bit(BTN_TOOL_FINGER, info->input_dev->keybit); #ifdef FTS_SUPPORT_2NDSCREEN if (info->board->support_2ndscreen) set_bit(BTN_SUBSCREEN_FLAG, info->input_dev->keybit); #endif #ifdef FTS_SUPPORT_SIDE_SCROLL if (info->board->support_sidescroll) { set_bit(BTN_R_FLICK_FLAG, info->input_dev->keybit); set_bit(BTN_L_FLICK_FLAG, info->input_dev->keybit); } #endif #ifdef FTS_SUPPORT_STRINGLIB set_bit(KEY_BLACK_UI_GESTURE, info->input_dev->keybit); #endif #ifdef FTS_SUPPORT_TOUCH_KEY if (info->board->support_mskey) { for (i = 0 ; i < info->board->num_touchkey ; i++) set_bit(info->board->touchkey[i].keycode, info->input_dev->keybit); set_bit(EV_LED, info->input_dev->evbit); set_bit(LED_MISC, info->input_dev->ledbit); } #endif #ifdef FTS_SUPPORT_SIDE_GESTURE if (info->board->support_sidegesture) { set_bit(KEY_SIDE_GESTURE, info->input_dev->keybit); set_bit(KEY_SIDE_GESTURE_RIGHT, info->input_dev->keybit); set_bit(KEY_SIDE_GESTURE_LEFT, info->input_dev->keybit); } #endif input_mt_init_slots(info->input_dev, FINGER_MAX, INPUT_MT_DIRECT); input_set_abs_params(info->input_dev, ABS_MT_POSITION_X, 0, info->board->max_x, 0, 0); input_set_abs_params(info->input_dev, ABS_MT_POSITION_Y, 0, info->board->max_y, 0, 0); mutex_init(&info->lock); mutex_init(&info->device_mutex); mutex_init(&info->i2c_mutex); info->enabled = false; mutex_lock(&info->lock); retval = fts_init(info); info->reinit_done = true; mutex_unlock(&info->lock); if (retval) { tsp_debug_err(true, &info->client->dev, "FTS fts_init fail!\n"); goto err_fts_init; } input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0); #ifdef FTS_SUPPORT_SEC_SWIPE input_set_abs_params(info->input_dev, ABS_MT_PALM, 0, 1, 0, 0); #endif #if defined(FTS_SUPPORT_SIDE_GESTURE) if (info->board->support_sidegesture) input_set_abs_params(info->input_dev, ABS_MT_GRIP, 0, 1, 0, 0); #endif input_set_abs_params(info->input_dev, ABS_MT_DISTANCE, 0, 255, 0, 0); input_set_drvdata(info->input_dev, info); i2c_set_clientdata(client, info); retval = input_register_device(info->input_dev); if (retval) { tsp_debug_err(true, &info->client->dev, "FTS input_register_device fail!\n"); goto err_register_input; } for (i = 0; i < FINGER_MAX; i++) { info->finger[i].state = EVENTID_LEAVE_POINTER; info->finger[i].mcount = 0; } info->enabled = true; retval = fts_irq_enable(info, true); if (retval < 0) { tsp_debug_info(true, &info->client->dev, "%s: Failed to enable attention interrupt\n", __func__); goto err_enable_irq; } #ifdef CONFIG_TRUSTONIC_TRUSTED_UI trustedui_set_tsp_irq(info->irq); tsp_debug_info(true, &client->dev, "%s[%d] called!\n", __func__, info->irq); #endif #ifdef CONFIG_HAS_EARLYSUSPEND info->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; info->early_suspend.suspend = fts_early_suspend; info->early_sfts_start_deviceuspend.resume = fts_late_resume; register_early_suspend(&info->early_suspend); #endif #ifdef FTS_SUPPORT_TA_MODE info->register_cb = info->board->register_cb; info->callbacks.inform_charger = fts_ta_cb; if (info->register_cb) info->register_cb(&info->callbacks); #endif #ifdef SEC_TSP_FACTORY_TEST INIT_LIST_HEAD(&info->cmd_list_head); info->cmd_buffer_size = 0; for (j = 0; j < ARRAY_SIZE(ft_commands); j++) { list_add_tail(&ft_commands[j].list, &info->cmd_list_head); if(ft_commands[j].cmd_name) info->cmd_buffer_size += strlen(ft_commands[j].cmd_name) + 1; } mutex_init(&info->cmd_lock); info->cmd_is_running = false; info->fac_dev_ts = sec_device_create(info, "tsp"); if (IS_ERR(info->fac_dev_ts)) { tsp_debug_err(true, &info->client->dev, "FTS Failed to create device for the sysfs\n"); retval = -ENOENT; goto err_sysfs; } dev_set_drvdata(info->fac_dev_ts, info); retval = sysfs_create_group(&info->fac_dev_ts->kobj, &sec_touch_factory_attr_group); if (retval < 0) { tsp_debug_err(true, &info->client->dev, "FTS Failed to create sysfs group\n"); goto err_sysfs; } retval = sysfs_create_link(&info->fac_dev_ts->kobj, &info->input_dev->dev.kobj, "input"); if (retval < 0) { tsp_debug_err(true, &info->client->dev, "%s: Failed to create link\n", __func__); goto err_sysfs; } #ifdef FTS_SUPPORT_TOUCH_KEY if (info->board->support_mskey) { info->fac_dev_tk = sec_device_create(info, "sec_touchkey"); if (IS_ERR(info->fac_dev_tk)) tsp_debug_err(true, &info->client->dev, "Failed to create device for the touchkey sysfs\n"); else { dev_set_drvdata(info->fac_dev_tk, info); retval = sysfs_create_group(&info->fac_dev_tk->kobj, &sec_touchkey_factory_attr_group); if (retval < 0) tsp_debug_err(true, &info->client->dev, "FTS Failed to create sysfs group\n"); else { retval = sysfs_create_link(&info->fac_dev_tk->kobj, &info->input_dev->dev.kobj, "input"); if (retval < 0) tsp_debug_err(true, &info->client->dev, "%s: Failed to create link\n", __func__); } } } #endif #endif device_init_wakeup(&client->dev, true); return 0; #ifdef SEC_TSP_FACTORY_TEST err_sysfs: if (info->irq_enabled) fts_irq_enable(info, false); mutex_destroy(&info->cmd_lock); #endif err_enable_irq: input_unregister_device(info->input_dev); info->input_dev = NULL; err_register_input: if (info->input_dev) input_free_device(info->input_dev); err_fts_init: mutex_destroy(&info->lock); mutex_destroy(&info->device_mutex); mutex_destroy(&info->i2c_mutex); err_input_allocate_device: info->board->power(info, false); kfree(info); err_get_drv_data: err_setup_drv_data: return retval; } static int fts_remove(struct i2c_client *client) { struct fts_ts_info *info = i2c_get_clientdata(client); tsp_debug_info(true, &info->client->dev, "FTS removed \n"); #ifdef CONFIG_HAS_EARLYSUSPEND unregister_early_suspend(&info->early_suspend); #endif fts_interrupt_set(info, INT_DISABLE); fts_command(info, FLUSHBUFFER); fts_irq_enable(info, false); input_mt_destroy_slots(info->input_dev); #ifdef SEC_TSP_FACTORY_TEST #ifdef FTS_SUPPORT_TOUCH_KEY if (info->board->support_mskey) { sysfs_remove_link(&info->fac_dev_tk->kobj, "input"); sysfs_remove_group(&info->fac_dev_tk->kobj, &sec_touchkey_factory_attr_group); sec_device_destroy(info->fac_dev_tk->devt); } #endif sysfs_remove_link(&info->fac_dev_ts->kobj, "input"); sysfs_remove_group(&info->fac_dev_ts->kobj, &sec_touch_factory_attr_group); sec_device_destroy(info->fac_dev_ts->devt); list_del(&info->cmd_list_head); mutex_destroy(&info->cmd_lock); if (info->cx_data) kfree(info->cx_data); if (info->pFrame) kfree(info->pFrame); #endif mutex_destroy(&info->lock); input_unregister_device(info->input_dev); info->input_dev = NULL; info->board->power(info, false); kfree(info); return 0; } #ifdef USE_OPEN_CLOSE #ifdef USE_OPEN_DWORK static void fts_open_work(struct work_struct *work) { int retval; struct fts_ts_info *info = container_of(work, struct fts_ts_info, open_work.work); tsp_debug_info(true, &info->client->dev, "%s\n", __func__); retval = fts_start_device(info); if (retval < 0) tsp_debug_err(true, &info->client->dev, "%s: Failed to start device\n", __func__); } #endif static int fts_input_open(struct input_dev *dev) { struct fts_ts_info *info = input_get_drvdata(dev); int retval; tsp_debug_dbg(false, &info->client->dev, "%s\n", __func__); #ifdef USE_OPEN_DWORK schedule_delayed_work(&info->open_work, msecs_to_jiffies(TOUCH_OPEN_DWORK_TIME)); #else retval = fts_start_device(info); if (retval < 0){ tsp_debug_err(true, &info->client->dev, "%s: Failed to start device\n", __func__); goto out; } #endif tsp_debug_err(true, &info->client->dev, "FTS cmd after wakeup : h%d \n", info->retry_hover_enable_after_wakeup); if(info->retry_hover_enable_after_wakeup == 1){ unsigned char regAdd[4] = {0xB0, 0x01, 0x29, 0x41}; fts_write_reg(info, ®Add[0], 4); fts_command(info, FTS_CMD_HOVER_ON); info->hover_enabled = true; } out: return 0; } static void fts_input_close(struct input_dev *dev) { struct fts_ts_info *info = input_get_drvdata(dev); tsp_debug_dbg(false, &info->client->dev, "%s\n", __func__); #ifdef USE_OPEN_DWORK cancel_delayed_work(&info->open_work); #endif fts_stop_device(info); info->retry_hover_enable_after_wakeup = 0; } #endif #ifdef CONFIG_SEC_FACTORY #include #define LCD_LDI_FILE_PATH "/sys/class/lcd/panel/window_type" static int fts_get_panel_revision(struct fts_ts_info *info) { int iRet = 0; mm_segment_t old_fs; struct file *window_type; unsigned char lcdtype[4] = {0,}; old_fs = get_fs(); set_fs(KERNEL_DS); window_type = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0666); if (IS_ERR(window_type)) { iRet = PTR_ERR(window_type); if (iRet != -ENOENT) tsp_debug_err(true, &info->client->dev, "%s: window_type file open fail\n", __func__); set_fs(old_fs); goto exit; } iRet = window_type->f_op->read(window_type, (u8 *)lcdtype, sizeof(u8) * 4, &window_type->f_pos); if (iRet != (sizeof(u8) * 4)) { tsp_debug_err(true, &info->client->dev, "%s: Can't read the lcd ldi data\n", __func__); iRet = -EIO; } /* The variable of lcdtype has ASCII values(40 81 45) at 0x08 OCTA, * so if someone need a TSP panel revision then to read third parameter.*/ #ifdef CONFIG_SEC_FACTORY info->panel_revision = lcdtype[3] & 0x0F; tsp_debug_info(true, &info->client->dev, "%s: update panel_revision 0x%02X\n", __func__, info->panel_revision); #endif filp_close(window_type, current->files); set_fs(old_fs); exit: return iRet; } static void fts_reinit_fac(struct fts_ts_info *info) { int rc; info->touch_count = 0; fts_command(info, SLEEPOUT); fts_delay(50); fts_command(info, SENSEON); fts_delay(50); #ifdef FTS_SUPPORT_TOUCH_KEY if (info->board->support_mskey) info->fts_command(info, FTS_CMD_KEY_SENSE_ON); #endif #ifdef FTS_SUPPORT_NOISE_PARAM fts_get_noise_param_address(info); #endif if (info->flip_enable) fts_set_cover_type(info, true); /* enable glove touch when flip cover is closed */ if (info->fast_mshover_enabled) fts_command(info, FTS_CMD_SET_FAST_GLOVE_MODE); else if (info->mshover_enabled) fts_command(info, FTS_CMD_MSHOVER_ON); rc = fts_get_channel_info(info); if (rc >= 0) { tsp_debug_info(true, &info->client->dev, "FTS Sense(%02d) Force(%02d)\n", info->SenseChannelLength, info->ForceChannelLength); } else { tsp_debug_info(true, &info->client->dev, "FTS read failed rc = %d\n", rc); tsp_debug_info(true, &info->client->dev, "FTS Initialise Failed\n"); return; } info->pFrame = kzalloc(info->SenseChannelLength * info->ForceChannelLength * 2, GFP_KERNEL); if (info->pFrame == NULL) { tsp_debug_info(true, &info->client->dev, "FTS pFrame kzalloc Failed\n"); return; } info->cx_data = kzalloc(info->SenseChannelLength * info->ForceChannelLength, GFP_KERNEL); if (!info->cx_data) tsp_debug_err(true, &info->client->dev, "%s: cx_data kzalloc Failed\n", __func__); fts_command(info, FORCECALIBRATION); fts_command(info, FLUSHBUFFER); fts_interrupt_set(info, INT_ENABLE); tsp_debug_info(true, &info->client->dev, "FTS Re-Initialised\n"); } #endif static void fts_reinit(struct fts_ts_info *info) { if (!info->lowpower_mode) { fts_wait_for_ready(info); fts_read_chip_id(info); } fts_systemreset(info); fts_wait_for_ready(info); #ifdef CONFIG_SEC_FACTORY /* Read firmware version from IC when every power up IC. * During Factory process touch panel can be changed manually. */ { unsigned short orig_fw_main_version_of_ic = info->fw_main_version_of_ic; fts_get_panel_revision(info); fts_get_version_info(info); if (info->fw_main_version_of_ic != orig_fw_main_version_of_ic) { fts_fw_init(info); fts_reinit_fac(info); return; } } #endif #ifdef FTS_SUPPORT_NOISE_PARAM fts_set_noise_param(info); #endif fts_command(info, SLEEPOUT); fts_delay(50); fts_command(info, SENSEON); fts_delay(50); #ifdef FTS_SUPPORT_TOUCH_KEY if (info->board->support_mskey) info->fts_command(info, FTS_CMD_KEY_SENSE_ON); #endif if (info->flip_enable) fts_set_cover_type(info, true); else if (info->fast_mshover_enabled) fts_command(info, FTS_CMD_SET_FAST_GLOVE_MODE); else if (info->mshover_enabled) fts_command(info, FTS_CMD_MSHOVER_ON); #ifdef FTS_SUPPORT_TA_MODE if (info->TA_Pluged) fts_command(info, FTS_CMD_CHARGER_PLUGGED); #endif info->touch_count = 0; #ifdef FTS_SUPPORT_2NDSCREEN if (info->board->support_2ndscreen) { info->SIDE_Flag = 0; info->previous_SIDE_value = 0; } #endif fts_command(info, FLUSHBUFFER); fts_interrupt_set(info, INT_ENABLE); } void fts_release_all_finger(struct fts_ts_info *info) { int i; for (i = 0; i < FINGER_MAX; i++) { input_mt_slot(info->input_dev, i); input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0); if ((info->finger[i].state == EVENTID_ENTER_POINTER) || (info->finger[i].state == EVENTID_MOTION_POINTER)) { info->touch_count--; if (info->touch_count < 0) info->touch_count = 0; tsp_debug_info(true, &info->client->dev, "[RA] tID:%d mc: %d tc:%d Ver[%02X%04X%01X%01X%01X]\n", i, info->finger[i].mcount, info->touch_count, info->panel_revision, info->fw_main_version_of_ic, info->flip_enable, info->mshover_enabled, info->mainscr_disable); } info->finger[i].state = EVENTID_LEAVE_POINTER; info->finger[i].mcount = 0; } input_report_key(info->input_dev, BTN_TOUCH, 0); input_report_key(info->input_dev, BTN_TOOL_FINGER, 0); #ifdef FTS_SUPPORT_2NDSCREEN if (info->board->support_2ndscreen) { info->SIDE_Flag = 0; info->previous_SIDE_value = 0; input_report_key(info->input_dev, BTN_SUBSCREEN_FLAG, 0); } #endif #ifdef FTS_SUPPORT_SIDE_SCROLL if (info->board->support_sidescroll) { input_report_key(info->input_dev, BTN_R_FLICK_FLAG, 0); input_report_key(info->input_dev, BTN_L_FLICK_FLAG, 0); } #endif #ifdef CONFIG_GLOVE_TOUCH input_report_switch(info->input_dev, SW_GLOVE, false); info->touch_mode = FTS_TM_NORMAL; #endif #ifdef FTS_SUPPORT_STRINGLIB input_report_key(info->input_dev, KEY_BLACK_UI_GESTURE, 0); #endif #ifdef FTS_SUPPORT_SIDE_GESTURE if (info->board->support_sidegesture) { input_report_key(info->input_dev, KEY_SIDE_GESTURE, 0); input_report_key(info->input_dev, KEY_SIDE_GESTURE_RIGHT, 0); input_report_key(info->input_dev, KEY_SIDE_GESTURE_LEFT, 0); } #endif #ifdef CONFIG_INPUT_BOOSTER input_booster_send_event(BOOSTER_DEVICE_TOUCH, BOOSTER_MODE_FORCE_OFF); #endif input_sync(info->input_dev); } #ifdef CONFIG_SEC_DEBUG_TSP_LOG static void dump_tsp_rawdata(struct work_struct *work) { struct fts_ts_info *info = container_of(work, struct fts_ts_info, debug_work.work); int i; if (info->rawdata_read_lock == true) tsp_debug_err(true, &info->client->dev, "%s, ## checking.. ignored.\n", __func__); info->rawdata_read_lock = true; tsp_debug_info(true, &info->client->dev, "%s, ## run CX data ##, %d\n", __func__, __LINE__); run_cx_data_read((void *)info); for (i = 0; i < 5; i++) { tsp_debug_info(true, &info->client->dev, "%s, ## run Raw Cap data ##, %d\n", __func__, __LINE__); run_rawcap_read((void *)info); tsp_debug_info(true, &info->client->dev, "%s, ## run Delta ##, %d\n", __func__, __LINE__); run_delta_read((void *)info); fts_delay(50); } tsp_debug_info(true, &info->client->dev, "%s, ## Done ##, %d\n", __func__, __LINE__); info->rawdata_read_lock = false; } void tsp_dump(void) { #ifdef CONFIG_BATTERY_SAMSUNG if (lpcharge) return; #endif if (!p_debug_work) return; printk(KERN_ERR "FTS %s: start \n", __func__); schedule_delayed_work(p_debug_work, msecs_to_jiffies(100)); } #endif static void fts_reset_work(struct work_struct *work) { struct fts_ts_info *info = container_of(work, struct fts_ts_info, reset_work.work); bool temp_lpm; temp_lpm = info->lowpower_mode; /* Reset-routine must go to power off state */ info->lowpower_mode = 0; tsp_debug_info(true, &info->client->dev,"%s, Call Power-Off to recover IC, lpm:%d\n", __func__, temp_lpm); fts_stop_device(info); msleep(100); /* Delay to discharge the IC from ESD or On-state.*/ if (fts_start_device(info) < 0) { tsp_debug_err(true, &info->client->dev, "%s: Failed to start device\n", __func__); } info->lowpower_mode = temp_lpm; } static int fts_stop_device(struct fts_ts_info *info) { tsp_debug_info(true, &info->client->dev, "%s\n", __func__); mutex_lock(&info->device_mutex); if (info->touch_stopped) { tsp_debug_err(true, &info->client->dev, "%s already power off\n", __func__); goto out; } if (info->lowpower_mode) { #ifdef FTS_SUPPORT_SIDE_GESTURE if (info->board->support_sidegesture) { tsp_debug_info(true, &info->client->dev, "%s mainscreen disable flag:%d, clear\n", __func__, info->mainscr_disable); set_mainscreen_disable_cmd((void *)info, 0); } #endif tsp_debug_info(true, &info->client->dev, "%s lowpower flag:%d\n", __func__, info->lowpower_flag); info->fts_power_state = FTS_POWER_STATE_LOWPOWER; fts_command(info, FLUSHBUFFER); #ifdef FTS_SUPPORT_SIDE_GESTURE if (info->board->support_sidegesture) { fts_enable_feature(info, FTS_FEATURE_SIDE_GUSTURE, true); fts_delay(20); } #endif fts_command(info, FTS_CMD_LOWPOWER_MODE); if (device_may_wakeup(&info->client->dev)) enable_irq_wake(info->irq); fts_command(info, FLUSHBUFFER); fts_release_all_finger(info); #ifdef FTS_SUPPORT_TOUCH_KEY fts_release_all_key(info); #endif #ifdef FTS_SUPPORT_NOISE_PARAM fts_get_noise_param(info); #endif } else { fts_interrupt_set(info, INT_DISABLE); disable_irq(info->irq); fts_command(info, FLUSHBUFFER); fts_command(info, SLEEPIN); fts_release_all_finger(info); #ifdef FTS_SUPPORT_TOUCH_KEY fts_release_all_key(info); #endif #ifdef FTS_SUPPORT_NOISE_PARAM fts_get_noise_param(info); #endif info->touch_stopped = true; info->hover_enabled = false; info->hover_ready = false; if (info->board->power) info->board->power(info, false); info->fts_power_state = FTS_POWER_STATE_POWERDOWN; } out: mutex_unlock(&info->device_mutex); return 0; } static int fts_start_device(struct fts_ts_info *info) { tsp_debug_info(true, &info->client->dev, "%s %s\n", __func__, info->lowpower_mode ? "exit low power mode" : ""); mutex_lock(&info->device_mutex); if (!info->touch_stopped && !info->lowpower_mode) { tsp_debug_err(true, &info->client->dev, "%s already power on\n", __func__); goto out; } fts_release_all_finger(info); #ifdef FTS_SUPPORT_TOUCH_KEY fts_release_all_key(info); #endif if (info->lowpower_mode) { /* low power mode command is sent after LCD OFF. turn on touch power @ LCD ON */ if (info->touch_stopped) goto tsp_power_on; disable_irq(info->irq); info->reinit_done = false; fts_reinit(info); info->reinit_done = true; enable_irq(info->irq); if (device_may_wakeup(&info->client->dev)) disable_irq_wake(info->irq); } else { tsp_power_on: if (info->board->power) info->board->power(info, true); info->touch_stopped = false; info->reinit_done = false; fts_reinit(info); info->reinit_done = true; enable_irq(info->irq); } #ifdef FTS_SUPPORT_STRINGLIB if (info->fts_mode) { unsigned short addr = FTS_CMD_STRING_ACCESS; int ret; ret = info->fts_write_to_string(info, &addr, &info->fts_mode, sizeof(info->fts_mode)); if (ret < 0) tsp_debug_err(true, &info->client->dev, "%s: failed. ret: %d\n", __func__, ret); } #endif if (strncmp(info->board->model_name, "G925", 4) == 0) { info->tspid_val= gpio_get_value(info->board->tspid); info->tspid2_val= gpio_get_value(info->board->tspid2); } out: mutex_unlock(&info->device_mutex); info->fts_power_state = FTS_POWER_STATE_ACTIVE; return 0; } static void fts_shutdown(struct i2c_client *client) { struct fts_ts_info *info = i2c_get_clientdata(client); tsp_debug_info(true, &info->client->dev, "FTS %s called!\n", __func__); if (info->lowpower_mode) { info->lowpower_mode = 0; tsp_debug_info(true, &info->client->dev, "FTS lowpower_mode off!\n"); } fts_stop_device(info); #ifdef FTS_SUPPORT_TOUCH_KEY if (info->board->led_power) info->board->led_power(info, false); #endif } #ifdef CONFIG_PM static int fts_pm_suspend(struct device *dev) { struct fts_ts_info *info = dev_get_drvdata(dev); tsp_debug_err(true, &info->client->dev, "%s\n", __func__);; mutex_lock(&info->input_dev->mutex); if (info->input_dev->users) fts_stop_device(info); mutex_unlock(&info->input_dev->mutex); return 0; } static int fts_pm_resume(struct device *dev) { struct fts_ts_info *info = dev_get_drvdata(dev); tsp_debug_err(true, &info->client->dev, "%s\n", __func__); mutex_lock(&info->input_dev->mutex); if (info->input_dev->users) fts_start_device(info); mutex_unlock(&info->input_dev->mutex); return 0; } #endif #if (!defined(CONFIG_HAS_EARLYSUSPEND)) && (!defined(CONFIG_PM)) && !defined(USE_OPEN_CLOSE) static int fts_suspend(struct i2c_client *client, pm_message_t mesg) { struct fts_ts_info *info = i2c_get_clientdata(client); tsp_debug_info(true, &info->client->dev, "%s\n", __func__); fts_stop_device(info); return 0; } static int fts_resume(struct i2c_client *client) { struct fts_ts_info *info = i2c_get_clientdata(client); tsp_debug_info(true, &info->client->dev, "%s\n", __func__); fts_start_device(info); return 0; } #endif static const struct i2c_device_id fts_device_id[] = { {FTS_TS_DRV_NAME, 0}, {} }; #ifdef CONFIG_PM static const struct dev_pm_ops fts_dev_pm_ops = { .suspend = fts_pm_suspend, .resume = fts_pm_resume, }; #endif #ifdef CONFIG_OF static struct of_device_id fts_match_table[] = { { .compatible = "stm,fts_touch",}, { }, }; #else #define fts_match_table NULL #endif static struct i2c_driver fts_i2c_driver = { .driver = { .name = FTS_TS_DRV_NAME, .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = fts_match_table, #endif #ifdef CONFIG_PM .pm = &fts_dev_pm_ops, #endif }, .probe = fts_probe, .remove = fts_remove, .shutdown = fts_shutdown, #if (!defined(CONFIG_HAS_EARLYSUSPEND)) && (!defined(CONFIG_PM)) && !defined(USE_OPEN_CLOSE) .suspend = fts_suspend, .resume = fts_resume, #endif .id_table = fts_device_id, }; static int __init fts_driver_init(void) { return i2c_add_driver(&fts_i2c_driver); } static void __exit fts_driver_exit(void) { i2c_del_driver(&fts_i2c_driver); } MODULE_DESCRIPTION("STMicroelectronics MultiTouch IC Driver"); MODULE_AUTHOR("STMicroelectronics, Inc."); MODULE_LICENSE("GPL v2"); module_init(fts_driver_init); module_exit(fts_driver_exit);