| /* Himax Android Driver Sample Code for HMX852xES chipset |
| * |
| * Copyright (C) 2014 Himax Corporation. |
| * |
| * This software is licensed under the terms of the GNU General Public |
| * License version 2, as published by the Free Software Foundation, and |
| * may be copied, distributed, and modified under those terms. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| |
| #include "himax_852xES.h" |
| |
| #define SUPPORT_FINGER_DATA_CHECKSUM 0x0F |
| #define TS_WAKE_LOCK_TIMEOUT (2 * HZ) |
| |
| static unsigned char IC_CHECKSUM = 0; |
| static unsigned char IC_TYPE = 0; |
| |
| static int HX_TOUCH_INFO_POINT_CNT = 0; |
| |
| static int HX_RX_NUM = 0; |
| static int HX_TX_NUM = 0; |
| static int HX_BT_NUM = 0; |
| static int HX_X_RES = 0; |
| static int HX_Y_RES = 0; |
| static int HX_MAX_PT = 0; |
| static bool HX_XY_REVERSE = false; |
| static bool HX_INT_IS_EDGE = false; |
| |
| static unsigned int FW_VER_MAJ_FLASH_ADDR; |
| static unsigned int FW_VER_MAJ_FLASH_LENG; |
| static unsigned int FW_VER_MIN_FLASH_ADDR; |
| static unsigned int FW_VER_MIN_FLASH_LENG; |
| |
| static unsigned int FW_CFG_VER_FLASH_ADDR; |
| |
| static unsigned int CFG_VER_MAJ_FLASH_ADDR; |
| static unsigned int CFG_VER_MAJ_FLASH_LENG; |
| static unsigned int CFG_VER_MIN_FLASH_ADDR; |
| static unsigned int CFG_VER_MIN_FLASH_LENG; |
| |
| static uint8_t AA_press = 0x00; |
| static uint8_t EN_NoiseFilter = 0x00; |
| static uint8_t Last_EN_NoiseFilter = 0x00; |
| static uint8_t HX_DRIVER_PROBE_Fial = 0; |
| static int hx_point_num = 0; //for himax_ts_work_func use |
| static int p_point_num = 0xFFFF; |
| static int point_flag[2] = {0}; |
| static int haspoint = false; |
| |
| static bool config_load = false; |
| static struct himax_config *config_selected = NULL; |
| |
| static int iref_number = 11; |
| static bool iref_found = false; |
| |
| #ifdef CONFIG_FB |
| static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); |
| #endif |
| |
| #ifdef CONFIG_OF |
| #if defined(HX_LOADIN_CONFIG)||defined(HX_AUTO_UPDATE_CONFIG) |
| static int himax_parse_config(struct himax_ts_data *ts, struct himax_config *pdata); |
| #endif |
| #endif |
| |
| #ifdef HX_TP_PROC_DEBUG |
| static int himax_hand_shaking(void) //0:Running, 1:Stop, 2:I2C Fail |
| { |
| int ret, result; |
| uint8_t hw_reset_check[1]; |
| uint8_t hw_reset_check_2[1]; |
| uint8_t buf0[2]; |
| memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); |
| memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2)); |
| buf0[0] = 0xF2; |
| if (IC_STATUS_CHECK == 0xAA) { |
| buf0[1] = 0xAA; |
| IC_STATUS_CHECK = 0x55; |
| } else { |
| buf0[1] = 0x55; |
| IC_STATUS_CHECK = 0xAA; |
| } |
| ret = i2c_himax_master_write(private_ts->client, buf0, 2, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("[%d] %s: write 0xF2 failed\n", __LINE__, __func__); |
| goto work_func_send_i2c_msg_fail; |
| } |
| msleep(50); |
| buf0[0] = 0xF2; |
| buf0[1] = 0x00; |
| ret = i2c_himax_master_write(private_ts->client, buf0, 2, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("[%d] %s: write 0x92 failed\n", __LINE__, __func__); |
| goto work_func_send_i2c_msg_fail; |
| } |
| msleep(2); |
| ret = i2c_himax_read(private_ts->client, 0x90, hw_reset_check, 1, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("[%d] %s: i2c_himax_read 0x90 failed\n", __LINE__, __func__); |
| goto work_func_send_i2c_msg_fail; |
| } |
| if ((IC_STATUS_CHECK != hw_reset_check[0])) { |
| msleep(2); |
| ret = i2c_himax_read(private_ts->client, 0x90, hw_reset_check_2, 1, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("[%d] %s: i2c_himax_read 0x90 failed\n", __LINE__, __func__); |
| goto work_func_send_i2c_msg_fail; |
| } |
| if (hw_reset_check[0] == hw_reset_check_2[0]) { |
| result = 1; |
| } else { |
| result = 0; |
| } |
| } else { |
| result = 0; |
| } |
| return result; |
| work_func_send_i2c_msg_fail: |
| return 2; |
| } |
| #endif |
| |
| static int himax_ManualMode(int enter) |
| { |
| uint8_t cmd[2]; |
| cmd[0] = enter; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_MANUALMODE , &cmd[0], 1, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| return 0; |
| } |
| |
| static int himax_FlashMode(int enter) |
| { |
| uint8_t cmd[2]; |
| cmd[0] = enter; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 1, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| return 0; |
| } |
| |
| static int himax_lock_flash(int enable) |
| { |
| uint8_t cmd[5]; |
| if (i2c_himax_write(private_ts->client, 0xAA , &cmd[0], 0, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| /* lock sequence start */ |
| cmd[0] = 0x01; |
| cmd[1] = 0x00; |
| cmd[2] = 0x06; |
| if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x03; |
| cmd[1] = 0x00; |
| cmd[2] = 0x00; |
| if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| if (enable != 0) { |
| cmd[0] = 0x63; |
| cmd[1] = 0x02; |
| cmd[2] = 0x70; |
| cmd[3] = 0x03; |
| } else { |
| cmd[0] = 0x63; |
| cmd[1] = 0x02; |
| cmd[2] = 0x30; |
| cmd[3] = 0x00; |
| } |
| if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_WRITE_REGISTER , &cmd[0], 4, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| if (i2c_himax_write_command(private_ts->client, HX_CMD_4A, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| msleep(50); |
| if (i2c_himax_write(private_ts->client, 0xA9 , &cmd[0], 0, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| return 0; |
| /* lock sequence stop */ |
| } |
| |
| |
| static void himax_changeIref(int selected_iref) |
| { |
| unsigned char temp_iref[16][2] = { |
| {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, |
| {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, |
| {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, |
| {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00} |
| }; |
| uint8_t cmd[10]; |
| int i = 0; |
| int j = 0; |
| I("%s: start to check iref,iref number = %d\n", __func__, selected_iref); |
| if (i2c_himax_write(private_ts->client, 0xAA , &cmd[0], 0, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return; |
| } |
| for (i = 0; i < 16; i++) { |
| for (j = 0; j < 2; j++) { |
| if (selected_iref == 1) { |
| temp_iref[i][j] = E_IrefTable_1[i][j]; |
| } else if (selected_iref == 2) { |
| temp_iref[i][j] = E_IrefTable_2[i][j]; |
| } else if (selected_iref == 3) { |
| temp_iref[i][j] = E_IrefTable_3[i][j]; |
| } else if (selected_iref == 4) { |
| temp_iref[i][j] = E_IrefTable_4[i][j]; |
| } else if (selected_iref == 5) { |
| temp_iref[i][j] = E_IrefTable_5[i][j]; |
| } else if (selected_iref == 6) { |
| temp_iref[i][j] = E_IrefTable_6[i][j]; |
| } else if (selected_iref == 7) { |
| temp_iref[i][j] = E_IrefTable_7[i][j]; |
| } |
| } |
| } |
| if (!iref_found) { |
| //Read Iref |
| //Register 0x43 |
| cmd[0] = 0x01; |
| cmd[1] = 0x00; |
| cmd[2] = 0x0A; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return; |
| } |
| //Register 0x44 |
| cmd[0] = 0x00; |
| cmd[1] = 0x00; |
| cmd[2] = 0x00; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| //Register 0x46 |
| if ( i2c_himax_write(private_ts->client, 0x46 , &cmd[0], 0, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| //Register 0x59 |
| if ( i2c_himax_read(private_ts->client, 0x59, cmd, 4, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| //find iref group , default is iref 3 |
| for (i = 0; i < 16; i++) { |
| if ((cmd[0] == temp_iref[i][0]) && |
| (cmd[1] == temp_iref[i][1])) { |
| iref_number = i; |
| iref_found = true; |
| break; |
| } |
| } |
| if (!iref_found ) { |
| E("%s: Can't find iref number!\n", __func__); |
| return ; |
| } else { |
| I("%s: iref_number=%d, cmd[0]=0x%x, cmd[1]=0x%x\n", __func__, iref_number, cmd[0], cmd[1]); |
| } |
| } |
| msleep(5); |
| //iref write |
| //Register 0x43 |
| cmd[0] = 0x01; |
| cmd[1] = 0x00; |
| cmd[2] = 0x06; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| //Register 0x44 |
| cmd[0] = 0x00; |
| cmd[1] = 0x00; |
| cmd[2] = 0x00; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| //Register 0x45 |
| cmd[0] = temp_iref[iref_number][0]; |
| cmd[1] = temp_iref[iref_number][1]; |
| cmd[2] = 0x17; |
| cmd[3] = 0x28; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_WRITE_REGISTER , &cmd[0], 4, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| //Register 0x4A |
| if ( i2c_himax_write(private_ts->client, HX_CMD_4A , &cmd[0], 0, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| //Read SFR to check the result |
| //Register 0x43 |
| cmd[0] = 0x01; |
| cmd[1] = 0x00; |
| cmd[2] = 0x0A; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| //Register 0x44 |
| cmd[0] = 0x00; |
| cmd[1] = 0x00; |
| cmd[2] = 0x00; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| //Register 0x46 |
| if ( i2c_himax_write(private_ts->client, 0x46 , &cmd[0], 0, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| //Register 0x59 |
| if ( i2c_himax_read(private_ts->client, 0x59, cmd, 4, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return ; |
| } |
| I("%s: cmd[0]=%d,cmd[1]=%d,temp_iref_1=%d,temp_iref_2=%d\n", __func__, cmd[0], cmd[1], temp_iref[iref_number][0], temp_iref[iref_number][1]); |
| if (cmd[0] != temp_iref[iref_number][0] || cmd[1] != temp_iref[iref_number][1]) { |
| E("%s: IREF Read Back is not match.\n", __func__); |
| E("%s: Iref [0]=%d,[1]=%d\n", __func__, cmd[0], cmd[1]); |
| } else { |
| I("%s: IREF Pass", __func__); |
| } |
| if (i2c_himax_write(private_ts->client, 0xA9 , &cmd[0], 0, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return; |
| } |
| } |
| |
| static uint8_t himax_calculateChecksum(bool change_iref, bool sense_off) |
| { |
| int iref_flag = 0; |
| uint8_t cmd[10]; |
| memset(cmd, 0x00, sizeof(cmd)); |
| if (sense_off) { |
| if ( i2c_himax_write(private_ts->client, HX_CMD_TSSOFF , &cmd[0], 0, DEFAULT_RETRY_CNT) < 0) { |
| return 0; |
| } |
| msleep(30); |
| } |
| //Sleep out |
| if ( i2c_himax_write(private_ts->client, HX_CMD_TSSLPOUT , &cmd[0], 0, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| msleep(120); |
| while (true) { |
| if (change_iref) { |
| if (iref_flag == 0) { |
| himax_changeIref(2); //iref 2 |
| } else if (iref_flag == 1) { |
| himax_changeIref(5); //iref 5 |
| } else if (iref_flag == 2) { |
| himax_changeIref(1); //iref 1 |
| } else { |
| goto CHECK_FAIL; |
| } |
| iref_flag ++; |
| } |
| cmd[0] = 0x00; |
| cmd[1] = 0x04; |
| cmd[2] = 0x0A; |
| cmd[3] = 0x02; |
| if (i2c_himax_write(private_ts->client, 0xED , &cmd[0], 4, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| //Enable Flash |
| cmd[0] = 0x01; |
| cmd[1] = 0x00; |
| cmd[2] = 0x02; |
| if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x05; |
| if (i2c_himax_write(private_ts->client, 0xD2 , &cmd[0], 1, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| if (i2c_himax_write(private_ts->client, 0x53 , &cmd[0], 1, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| msleep(200); |
| if (i2c_himax_read(private_ts->client, 0xAD, cmd, 4, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return -1; |
| } |
| I("%s 0xAD[0,1,2,3] = %d,%d,%d,%d \n", __func__, cmd[0], cmd[1], cmd[2], cmd[3]); |
| IC_checksum[0] = cmd[0]; |
| IC_checksum[1] = cmd[1]; |
| IC_checksum[2] = cmd[2]; |
| IC_checksum[3] = cmd[3]; |
| if (cmd[0] == 0 && cmd[1] == 0 && cmd[2] == 0 && cmd[3] == 0 ) { |
| himax_FlashMode(0); |
| goto CHECK_PASS; |
| } else { |
| himax_FlashMode(0); |
| goto CHECK_FAIL; |
| } |
| CHECK_PASS: |
| if (change_iref) { |
| if (iref_flag < 3) { |
| continue; |
| } else { |
| if (sense_off) |
| i2c_himax_write_command(private_ts->client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); |
| return 1; |
| } |
| } else { |
| if (sense_off) |
| i2c_himax_write_command(private_ts->client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); |
| return 1; |
| } |
| CHECK_FAIL: |
| if (sense_off) |
| i2c_himax_write_command(private_ts->client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); |
| return 0; |
| } |
| if (sense_off) |
| i2c_himax_write_command(private_ts->client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); |
| return 0; |
| } |
| |
| int fts_ctpm_fw_upgrade_with_fs(unsigned char *fw, int len, bool change_iref) |
| { |
| unsigned char *ImageBuffer = fw; |
| int fullFileLength = len; |
| int i; |
| uint8_t cmd[5], last_byte, prePage; |
| int FileLength; |
| uint8_t checksumResult = 0; |
| FileLength = fullFileLength; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_TSSLPOUT , &cmd[0], 0, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| msleep(120); |
| himax_lock_flash(0); |
| cmd[0] = 0x05; |
| cmd[1] = 0x00; |
| cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| if ( i2c_himax_write(private_ts->client, 0x4F , &cmd[0], 0, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| msleep(50); |
| himax_ManualMode(1); |
| himax_FlashMode(1); |
| FileLength = (FileLength + 3) / 4; |
| for (i = 0, prePage = 0; i < FileLength; i++) { |
| last_byte = 0; |
| cmd[0] = i & 0x1F; |
| if (cmd[0] == 0x1F || i == FileLength - 1) { |
| last_byte = 1; |
| } |
| cmd[1] = (i >> 5) & 0x1F; |
| cmd[2] = (i >> 10) & 0x1F; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| if (prePage != cmd[1] || i == 0) { |
| prePage = cmd[1]; |
| cmd[0] = 0x01; |
| cmd[1] = 0x09;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x0D;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x09;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| } |
| memcpy(&cmd[0], &ImageBuffer[4 * i], 4); |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_WRITE_REGISTER , &cmd[0], 4, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x0D;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x09;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| if (last_byte == 1) { |
| cmd[0] = 0x01; |
| cmd[1] = 0x01;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x05;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x01;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x00;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| msleep(10); |
| if (i == (FileLength - 1)) { |
| himax_FlashMode(0); |
| himax_ManualMode(0); |
| checksumResult = himax_calculateChecksum(change_iref, false); |
| //himax_ManualMode(0); |
| himax_lock_flash(1); |
| if (checksumResult) { //Success |
| return 1; |
| } else { //Fail |
| E("%s: checksumResult fail!\n", __func__); |
| return 0; |
| } |
| } |
| } |
| } |
| return 0; |
| } |
| |
| static int himax_input_register(struct himax_ts_data *ts) |
| { |
| int ret; |
| ts->input_dev = input_allocate_device(); |
| if (ts->input_dev == NULL) { |
| ret = -ENOMEM; |
| E("%s: Failed to allocate input device\n", __func__); |
| return ret; |
| } |
| ts->input_dev->name = INPUT_DEV_NAME; |
| set_bit(EV_SYN, ts->input_dev->evbit); |
| set_bit(EV_ABS, ts->input_dev->evbit); |
| set_bit(EV_KEY, ts->input_dev->evbit); |
| #ifdef HX_SMART_WAKEUP |
| set_bit(KEY_POWER, ts->input_dev->keybit); |
| #endif |
| #ifdef HX_PALM_REPORT |
| set_bit(KEY_SLEEP, ts->input_dev->keybit); |
| #endif |
| set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); |
| if (ts->protocol_type == PROTOCOL_TYPE_A) { |
| //ts->input_dev->mtsize = ts->nFinger_support; |
| input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, |
| 0, 3, 0, 0); |
| } else {/* PROTOCOL_TYPE_B */ |
| set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); |
| input_mt_init_slots(ts->input_dev, ts->nFinger_support, 0); |
| } |
| I("input_set_abs_params: min_x %d, max_x %d, min_y %d, max_y %d\n", |
| ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); |
| input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); |
| input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); |
| input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); |
| input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); |
| input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, ts->pdata->abs_width_min, ts->pdata->abs_width_max, ts->pdata->abs_pressure_fuzz, 0); |
| // input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0); |
| // input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, (BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0); |
| return input_register_device(ts->input_dev); |
| } |
| |
| static void calcDataSize(uint8_t finger_num) |
| { |
| struct himax_ts_data *ts_data = private_ts; |
| ts_data->coord_data_size = 4 * finger_num; |
| ts_data->area_data_size = ((finger_num / 4) + (finger_num % 4 ? 1 : 0)) * 4; |
| ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size - ts_data->area_data_size - 4 - 4 - 1; |
| ts_data->raw_data_nframes = ((uint32_t)ts_data->x_channel * ts_data->y_channel + |
| ts_data->x_channel + ts_data->y_channel) / ts_data->raw_data_frame_size + |
| (((uint32_t)ts_data->x_channel * ts_data->y_channel + |
| ts_data->x_channel + ts_data->y_channel) % ts_data->raw_data_frame_size) ? 1 : 0; |
| I("%s: coord_data_size: %d, area_data_size:%d, raw_data_frame_size:%d, raw_data_nframes:%d\n", __func__, ts_data->coord_data_size, ts_data->area_data_size, ts_data->raw_data_frame_size, ts_data->raw_data_nframes); |
| } |
| |
| static void calculate_point_number(void) |
| { |
| HX_TOUCH_INFO_POINT_CNT = HX_MAX_PT * 4 ; |
| if ( (HX_MAX_PT % 4) == 0) |
| HX_TOUCH_INFO_POINT_CNT += (HX_MAX_PT / 4) * 4 ; |
| else |
| HX_TOUCH_INFO_POINT_CNT += ((HX_MAX_PT / 4) + 1) * 4 ; |
| } |
| #ifdef HX_LOADIN_CONFIG |
| static int himax_config_reg_write(struct i2c_client *client, uint8_t StartAddr, uint8_t *data, uint8_t length, uint8_t toRetry) |
| { |
| char cmd[12] = {0}; |
| cmd[0] = 0x8C; |
| cmd[1] = 0x14; |
| if ((i2c_himax_master_write(client, &cmd[0], 2, toRetry)) < 0) |
| return -1; |
| cmd[0] = 0x8B; |
| cmd[1] = 0x00; |
| cmd[2] = StartAddr; //Start addr |
| if ((i2c_himax_master_write(client, &cmd[0], 3, toRetry)) < 0) |
| return -1; |
| if ((i2c_himax_master_write(client, data, length, toRetry)) < 0) |
| return -1; |
| cmd[0] = 0x8C; |
| cmd[1] = 0x00; |
| if ((i2c_himax_master_write(client, &cmd[0], 2, toRetry)) < 0) |
| return -1; |
| return 0; |
| } |
| #endif |
| void himax_touch_information(void) |
| { |
| char data[12] = {0}; |
| I("%s: IC_TYPE =%d\n", __func__, IC_TYPE); |
| if (IC_TYPE == HX_85XX_ES_SERIES_PWON) { |
| data[0] = 0x8C; |
| data[1] = 0x14; |
| i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); |
| msleep(10); |
| data[0] = 0x8B; |
| data[1] = 0x00; |
| data[2] = 0x70; |
| i2c_himax_master_write(private_ts->client, &data[0], 3, DEFAULT_RETRY_CNT); |
| msleep(10); |
| i2c_himax_read(private_ts->client, 0x5A, data, 12, DEFAULT_RETRY_CNT); |
| HX_RX_NUM = data[0]; // FE(70) |
| HX_TX_NUM = data[1]; // FE(71) |
| //HX_MAX_PT = (data[2] & 0xF0) >> 4; // FE(72) |
| HX_MAX_PT = 2; |
| if ((data[4] & 0x04) == 0x04) { //FE(74) |
| HX_XY_REVERSE = true; |
| HX_Y_RES = data[6] * 256 + data[7]; //FE(76),FE(77) |
| HX_X_RES = data[8] * 256 + data[9]; //FE(78),FE(79) |
| } else { |
| HX_XY_REVERSE = false; |
| HX_X_RES = data[6] * 256 + data[7]; //FE(76),FE(77) |
| HX_Y_RES = data[8] * 256 + data[9]; //FE(78),FE(79) |
| } |
| data[0] = 0x8C; |
| data[1] = 0x00; |
| i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); |
| msleep(10); |
| #ifdef HX_TP_PROC_2T2R |
| data[0] = 0x8C; |
| data[1] = 0x14; |
| i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); |
| msleep(10); |
| data[0] = 0x8B; |
| data[1] = 0x00; |
| data[2] = HX_2T2R_Addr; |
| i2c_himax_master_write(private_ts->client, &data[0], 3, DEFAULT_RETRY_CNT); |
| msleep(10); |
| i2c_himax_read(private_ts->client, 0x5A, data, 10, DEFAULT_RETRY_CNT); |
| HX_RX_NUM_2 = data[0]; |
| HX_TX_NUM_2 = data[1]; |
| I("%s: Touch Panel Type=%d\n", __func__, data[2]); |
| if (data[2] == HX_2T2R_en_setting) //2T2R type panel |
| Is_2T2R = true; |
| else |
| Is_2T2R = false; |
| data[0] = 0x8C; |
| data[1] = 0x00; |
| i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); |
| msleep(10); |
| #endif |
| data[0] = 0x8C; |
| data[1] = 0x14; |
| i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); |
| msleep(10); |
| data[0] = 0x8B; |
| data[1] = 0x00; |
| data[2] = 0x02; |
| i2c_himax_master_write(private_ts->client, &data[0], 3, DEFAULT_RETRY_CNT); |
| msleep(10); |
| i2c_himax_read(private_ts->client, 0x5A, data, 10, DEFAULT_RETRY_CNT); |
| if ((data[1] & 0x01) == 1) { //FE(02) |
| HX_INT_IS_EDGE = true; |
| } else { |
| HX_INT_IS_EDGE = false; |
| } |
| data[0] = 0x8C; |
| data[1] = 0x00; |
| i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); |
| msleep(10); |
| I("%s: HX_RX_NUM=%d,HX_TX_NUM=%d,HX_MAX_PT=%d \n", __func__, HX_RX_NUM, HX_TX_NUM, HX_MAX_PT); |
| if (i2c_himax_read(private_ts->client, HX_VER_FW_CFG, data, 1, 3) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| } |
| private_ts->vendor_config_ver = data[0]; |
| //I("config_ver=%x.\n", private_ts->vendor_config_ver); |
| } else { |
| HX_RX_NUM = 0; |
| HX_TX_NUM = 0; |
| HX_BT_NUM = 0; |
| HX_X_RES = 0; |
| HX_Y_RES = 0; |
| HX_MAX_PT = 0; |
| HX_XY_REVERSE = false; |
| HX_INT_IS_EDGE = false; |
| } |
| } |
| static uint8_t himax_read_Sensor_ID(struct i2c_client *client) |
| { |
| uint8_t val_high[1], val_low[1], ID0 = 0, ID1 = 0; |
| uint8_t sensor_id; |
| char data[3]; |
| data[0] = 0x56; |
| data[1] = 0x02; |
| data[2] = 0x02;/*ID pin PULL High*/ |
| i2c_himax_master_write(client, &data[0], 3, DEFAULT_RETRY_CNT); |
| msleep(1); |
| //read id pin high |
| i2c_himax_read(client, 0x57, val_high, 1, DEFAULT_RETRY_CNT); |
| data[0] = 0x56; |
| data[1] = 0x01; |
| data[2] = 0x01;/*ID pin PULL Low*/ |
| i2c_himax_master_write(client, &data[0], 3, DEFAULT_RETRY_CNT); |
| msleep(1); |
| //read id pin low |
| i2c_himax_read(client, 0x57, val_low, 1, DEFAULT_RETRY_CNT); |
| if ((val_high[0] & 0x01) == 0) |
| ID0 = 0x02; /*GND*/ |
| else if ((val_low[0] & 0x01) == 0) |
| ID0 = 0x01; /*Floating*/ |
| else |
| ID0 = 0x04; /*VCC*/ |
| if ((val_high[0] & 0x02) == 0) |
| ID1 = 0x02; /*GND*/ |
| else if ((val_low[0] & 0x02) == 0) |
| ID1 = 0x01; /*Floating*/ |
| else |
| ID1 = 0x04; /*VCC*/ |
| if ((ID0 == 0x04) && (ID1 != 0x04)) { |
| data[0] = 0x56; |
| data[1] = 0x02; |
| data[2] = 0x01;/*ID pin PULL High,Low*/ |
| i2c_himax_master_write(client, &data[0], 3, DEFAULT_RETRY_CNT); |
| msleep(1); |
| } else if ((ID0 != 0x04) && (ID1 == 0x04)) { |
| data[0] = 0x56; |
| data[1] = 0x01; |
| data[2] = 0x02;/*ID pin PULL Low,High*/ |
| i2c_himax_master_write(client, &data[0], 3, DEFAULT_RETRY_CNT); |
| msleep(1); |
| } else if ((ID0 == 0x04) && (ID1 == 0x04)) { |
| data[0] = 0x56; |
| data[1] = 0x02; |
| data[2] = 0x02;/*ID pin PULL High,High*/ |
| i2c_himax_master_write(client, &data[0], 3, DEFAULT_RETRY_CNT); |
| msleep(1); |
| } |
| sensor_id = (ID1 << 4) | ID0; |
| data[0] = 0xF3; |
| data[1] = sensor_id; |
| i2c_himax_master_write(client, &data[0], 2, DEFAULT_RETRY_CNT); /*Write to MCU*/ |
| msleep(1); |
| return sensor_id; |
| } |
| static void himax_power_on_initCMD(struct i2c_client *client) |
| { |
| //I("%s:\n", __func__); |
| //Sense on to update the information |
| i2c_himax_write_command(client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); |
| msleep(30); |
| i2c_himax_write_command(client, HX_CMD_TSSLPOUT, DEFAULT_RETRY_CNT); |
| msleep(50); |
| i2c_himax_write_command(client, HX_CMD_TSSOFF, DEFAULT_RETRY_CNT); |
| msleep(50); |
| i2c_himax_write_command(client, HX_CMD_TSSLPIN, DEFAULT_RETRY_CNT); |
| msleep(50); |
| himax_touch_information(); |
| i2c_himax_write_command(client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); |
| msleep(30); |
| i2c_himax_write_command(client, HX_CMD_TSSLPOUT, DEFAULT_RETRY_CNT); |
| msleep(50); |
| } |
| |
| #ifdef HX_CHECK_CRC_AP |
| static bool Calculate_CRC_with_AP(unsigned char *FW_content) |
| { |
| int i, j; |
| int fw_data; |
| int fw_data_2; |
| int CRC = 0xFFFFFFFF; |
| int PolyNomial = 0x82F63B78; |
| int length = 0; |
| |
| length = 0x2000; //32k |
| for (i = 0; i < length; i++) { |
| fw_data = FW_content[i * 4 ]; |
| for (j = 1; j < 4; j++) { |
| fw_data_2 = FW_content[i * 4 + j]; |
| fw_data += (fw_data_2) << (8 * j); |
| } |
| CRC = fw_data ^ CRC; |
| for (j = 0; j < 32; j++) { |
| if ((CRC % 2) != 0) { |
| CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; |
| } else { |
| CRC = (((CRC >> 1) & 0x7FFFFFFF)& 0x7FFFFFFF); |
| } |
| } |
| } |
| I("CRC calculate from bin file is %x", CRC); |
| |
| if (CRC == 0) |
| return true; |
| else |
| return false; |
| } |
| #endif |
| |
| #ifdef HX_AUTO_UPDATE_FW |
| static int i_update_FW(bool manual) |
| { |
| struct file *hx_filp = NULL; |
| mm_segment_t oldfs; |
| unsigned char *ImageBuffer; |
| int fullFileLength; |
| int upgrade_times = 0; |
| int result; |
| uint8_t FW_MAJ, FW_MIN, NEW_FW_MAJ, NEW_FW_MIN; |
| uint8_t CFG_VER, NEW_CFG_VER; |
| bool need_update_flag = false; |
| bool asus_load_fail = false; |
| unsigned char *upgrade_fwfile = NULL; |
| int fw_size = 32*1024; |
| |
| if (private_ts->suspended) { |
| goto no_update; |
| } |
| I("Start to update fw\n"); |
| wake_lock(&private_ts->ts_flash_wake_lock); |
| fw_update_processing= true; |
| |
| // load bin from ASUSFW |
| hx_filp = filp_open(ASUS_FW_NAME, O_RDONLY, 0); |
| if (IS_ERR(hx_filp)) { |
| asus_load_fail = true; |
| } else { |
| upgrade_fwfile = kmalloc(fw_size, GFP_USER); |
| if (!upgrade_fwfile) { |
| asus_load_fail = true; |
| } else { |
| oldfs = get_fs(); |
| set_fs(get_ds()); |
| memset(upgrade_fwfile, 0, fw_size); |
| result = hx_filp->f_op->read(hx_filp, upgrade_fwfile, fw_size, &hx_filp->f_pos); |
| if (result < 0) { |
| asus_load_fail = true; |
| } else { |
| set_fs(oldfs); |
| filp_close(hx_filp, NULL); |
| I("Update firmware from ASUSFW\n"); |
| ImageBuffer = upgrade_fwfile; |
| fullFileLength = result; |
| } |
| } |
| } |
| |
| // load bin by using request_firmware |
| if (asus_load_fail) { |
| I("Load firmware by using request_fw\n"); |
| result = request_firmware(&private_ts->fw, HMX_FW_NAME, &private_ts->client->dev); |
| if (private_ts->fw == NULL) { |
| E("No firmware file, ignored firmware update\n"); |
| goto no_update; |
| } else if (result) { |
| E("Request_firmware failed, ret = %d\n", result); |
| goto no_update; |
| } |
| private_ts->fw_data_start = (u8 *)private_ts->fw->data; |
| private_ts->fw_size = private_ts->fw->size; |
| ImageBuffer = private_ts->fw_data_start; |
| fullFileLength = private_ts->fw->size; |
| } |
| |
| FW_MAJ = private_ts->vendor_fw_ver_H; |
| FW_MIN = private_ts->vendor_fw_ver_L; |
| CFG_VER = private_ts->vendor_config_ver; |
| NEW_FW_MAJ = ImageBuffer[FW_VER_MAJ_FLASH_ADDR]; |
| NEW_FW_MIN = ImageBuffer[FW_VER_MIN_FLASH_ADDR]; |
| NEW_CFG_VER = ImageBuffer[FW_CFG_VER_FLASH_ADDR]; |
| I("FW_VER=%x.%x CFG_VER=%x\n", FW_MAJ, FW_MIN, CFG_VER); |
| I("NEW FW_VER=%x.%x NEW CFG_VER=%x\n", NEW_FW_MAJ, NEW_FW_MIN, NEW_CFG_VER); |
| |
| #ifdef HX_CHECK_CRC_AP |
| if (!Calculate_CRC_with_AP(ImageBuffer)) { |
| I("New FW CRC fail, do not update."); |
| goto no_update; |
| } |
| #endif |
| if (NEW_FW_MAJ != ASUS_FW_MAJ) { |
| I("Non ASUS FW, do not update."); |
| goto no_update; |
| } |
| |
| if (!manual) { |
| if ( (NEW_FW_MIN < FW_MIN) || ( (NEW_FW_MIN == FW_MIN) && (NEW_CFG_VER <= CFG_VER) )) { |
| if ( himax_calculateChecksum(false, true) == 0 ) { |
| I("IC Checksum fail, update to new FW. \n"); |
| need_update_flag = true; |
| } else { |
| I("No new FW version and IC Checksum pass, do not update. \n"); |
| goto no_update; |
| } |
| } else { |
| I("Larger new FW version, update to new FW. \n"); |
| need_update_flag = true; |
| } |
| } else |
| need_update_flag = true; |
| |
| if (need_update_flag) { |
| update_retry: |
| #ifdef HX_RST_PIN_FUNC |
| himax_HW_reset(false, true); |
| #endif |
| if (fts_ctpm_fw_upgrade_with_fs(ImageBuffer, fullFileLength, true) == 0) { |
| if (upgrade_times < 3) { |
| upgrade_times++; |
| E("TP upgrade Error, Count: %d\n", upgrade_times); |
| goto update_retry; |
| } else { |
| if (private_ts->fw_size) |
| release_firmware(private_ts->fw); |
| if (upgrade_fwfile != NULL) |
| kfree(upgrade_fwfile); |
| fw_update_result = false; |
| fw_update_processing= false; |
| wake_unlock(&private_ts->ts_flash_wake_lock); |
| return -1;//upgrade fail |
| } |
| } else { |
| I("TP upgrade OK\n"); |
| private_ts->vendor_fw_ver_H = NEW_FW_MAJ; |
| private_ts->vendor_fw_ver_L = NEW_FW_MIN; |
| private_ts->vendor_config_ver = NEW_CFG_VER; |
| } |
| #ifdef HX_RST_PIN_FUNC |
| himax_HW_reset(true, true); |
| #endif |
| if (private_ts->fw_size) |
| release_firmware(private_ts->fw); |
| if (upgrade_fwfile != NULL) |
| kfree(upgrade_fwfile); |
| fw_update_result = true; |
| fw_update_processing= false; |
| wake_unlock(&private_ts->ts_flash_wake_lock); |
| return 1;//upgrade success |
| } else |
| goto no_update; |
| no_update: |
| if (private_ts->fw_size) |
| release_firmware(private_ts->fw); |
| if (upgrade_fwfile != NULL) |
| kfree(upgrade_fwfile); |
| fw_update_result = true; |
| fw_update_processing= false; |
| wake_unlock(&private_ts->ts_flash_wake_lock); |
| return 0;//NO upgrade |
| } |
| #endif |
| |
| #ifdef HX_AUTO_UPDATE_CONFIG |
| int fts_ctpm_fw_upgrade_with_i_file_flash_cfg(struct himax_config *cfg) |
| { |
| unsigned char *ImageBuffer = i_CTPM_FW; //NULL ;// |
| int fullFileLength = FLASH_SIZE; |
| int i, k; |
| uint8_t cmd[5], last_byte, prePage; |
| uint8_t tmp[5]; |
| int FileLength; |
| int Polynomial = 0x82F63B78; |
| int CRC32 = 0xFFFFFFFF; |
| int BinDataWord = 0; |
| int current_index = 0; |
| uint8_t checksumResult = 0; |
| I("%s: flash CONFIG only START!\n", __func__); |
| #if 0 |
| //=========Dump FW image from Flash======== |
| setSysOperation(1); |
| setFlashCommand(0x0F); |
| setFlashDumpProgress(0); |
| setFlashDumpComplete(0); |
| setFlashDumpFail(0); |
| queue_work(private_ts->flash_wq, &private_ts->flash_work); |
| for (i = 0 ; i < 1024 ; i++) { |
| if (getFlashDumpComplete()) { |
| ImageBuffer = flash_buffer; |
| fullFileLength = FLASH_SIZE; |
| I(" %s: Load FW from flash OK! cycle=%d fullFileLength=%x\n", __func__, i, fullFileLength); |
| break; |
| } |
| msleep(5); |
| } |
| if (i == 400) { |
| E(" %s: Load FW from flash time out fail!\n", __func__); |
| return 0; |
| } |
| //=================================== |
| #endif |
| current_index = CFB_START_ADDR + CFB_INFO_LENGTH; |
| //Update the Config Part from config array |
| for (i = 1 ; i < sizeof(cfg->c1) / sizeof(cfg->c1[0]) ; i++) ImageBuffer[current_index++] = cfg->c1[i]; |
| for (i = 1 ; i < sizeof(cfg->c2) / sizeof(cfg->c2[0]) ; i++) ImageBuffer[current_index++] = cfg->c2[i]; |
| for (i = 1 ; i < sizeof(cfg->c3) / sizeof(cfg->c3[0]) ; i++) ImageBuffer[current_index++] = cfg->c3[i]; |
| for (i = 1 ; i < sizeof(cfg->c4) / sizeof(cfg->c4[0]) ; i++) ImageBuffer[current_index++] = cfg->c4[i]; |
| for (i = 1 ; i < sizeof(cfg->c5) / sizeof(cfg->c5[0]) ; i++) ImageBuffer[current_index++] = cfg->c5[i]; |
| for (i = 1 ; i < sizeof(cfg->c6) / sizeof(cfg->c6[0]) ; i++) ImageBuffer[current_index++] = cfg->c6[i]; |
| for (i = 1 ; i < sizeof(cfg->c7) / sizeof(cfg->c7[0]) ; i++) ImageBuffer[current_index++] = cfg->c7[i]; |
| for (i = 1 ; i < sizeof(cfg->c8) / sizeof(cfg->c8[0]) ; i++) ImageBuffer[current_index++] = cfg->c8[i]; |
| for (i = 1 ; i < sizeof(cfg->c9) / sizeof(cfg->c9[0]) ; i++) ImageBuffer[current_index++] = cfg->c9[i]; |
| for (i = 1 ; i < sizeof(cfg->c10) / sizeof(cfg->c10[0]) ; i++) ImageBuffer[current_index++] = cfg->c10[i]; |
| for (i = 1 ; i < sizeof(cfg->c11) / sizeof(cfg->c11[0]) ; i++) ImageBuffer[current_index++] = cfg->c11[i]; |
| for (i = 1 ; i < sizeof(cfg->c12) / sizeof(cfg->c12[0]) ; i++) ImageBuffer[current_index++] = cfg->c12[i]; |
| for (i = 1 ; i < sizeof(cfg->c13) / sizeof(cfg->c13[0]) ; i++) ImageBuffer[current_index++] = cfg->c13[i]; |
| for (i = 1 ; i < sizeof(cfg->c14) / sizeof(cfg->c14[0]) ; i++) ImageBuffer[current_index++] = cfg->c14[i]; |
| for (i = 1 ; i < sizeof(cfg->c15) / sizeof(cfg->c15[0]) ; i++) ImageBuffer[current_index++] = cfg->c15[i]; |
| for (i = 1 ; i < sizeof(cfg->c16) / sizeof(cfg->c16[0]) ; i++) ImageBuffer[current_index++] = cfg->c16[i]; |
| for (i = 1 ; i < sizeof(cfg->c17) / sizeof(cfg->c17[0]) ; i++) ImageBuffer[current_index++] = cfg->c17[i]; |
| for (i = 1 ; i < sizeof(cfg->c18) / sizeof(cfg->c18[0]) ; i++) ImageBuffer[current_index++] = cfg->c18[i]; |
| for (i = 1 ; i < sizeof(cfg->c19) / sizeof(cfg->c19[0]) ; i++) ImageBuffer[current_index++] = cfg->c19[i]; |
| for (i = 1 ; i < sizeof(cfg->c20) / sizeof(cfg->c20[0]) ; i++) ImageBuffer[current_index++] = cfg->c20[i]; |
| for (i = 1 ; i < sizeof(cfg->c21) / sizeof(cfg->c21[0]) ; i++) ImageBuffer[current_index++] = cfg->c21[i]; |
| for (i = 1 ; i < sizeof(cfg->c22) / sizeof(cfg->c22[0]) ; i++) ImageBuffer[current_index++] = cfg->c22[i]; |
| for (i = 1 ; i < sizeof(cfg->c23) / sizeof(cfg->c23[0]) ; i++) ImageBuffer[current_index++] = cfg->c23[i]; |
| for (i = 1 ; i < sizeof(cfg->c24) / sizeof(cfg->c24[0]) ; i++) ImageBuffer[current_index++] = cfg->c24[i]; |
| for (i = 1 ; i < sizeof(cfg->c25) / sizeof(cfg->c25[0]) ; i++) ImageBuffer[current_index++] = cfg->c25[i]; |
| for (i = 1 ; i < sizeof(cfg->c26) / sizeof(cfg->c26[0]) ; i++) ImageBuffer[current_index++] = cfg->c26[i]; |
| for (i = 1 ; i < sizeof(cfg->c27) / sizeof(cfg->c27[0]) ; i++) ImageBuffer[current_index++] = cfg->c27[i]; |
| for (i = 1 ; i < sizeof(cfg->c28) / sizeof(cfg->c28[0]) ; i++) ImageBuffer[current_index++] = cfg->c28[i]; |
| for (i = 1 ; i < sizeof(cfg->c29) / sizeof(cfg->c29[0]) ; i++) ImageBuffer[current_index++] = cfg->c29[i]; |
| for (i = 1 ; i < sizeof(cfg->c30) / sizeof(cfg->c30[0]) ; i++) ImageBuffer[current_index++] = cfg->c30[i]; |
| for (i = 1 ; i < sizeof(cfg->c31) / sizeof(cfg->c31[0]) ; i++) ImageBuffer[current_index++] = cfg->c31[i]; |
| for (i = 1 ; i < sizeof(cfg->c32) / sizeof(cfg->c32[0]) ; i++) ImageBuffer[current_index++] = cfg->c32[i]; |
| for (i = 1 ; i < sizeof(cfg->c33) / sizeof(cfg->c33[0]) ; i++) ImageBuffer[current_index++] = cfg->c33[i]; |
| for (i = 1 ; i < sizeof(cfg->c34) / sizeof(cfg->c34[0]) ; i++) ImageBuffer[current_index++] = cfg->c34[i]; |
| for (i = 1 ; i < sizeof(cfg->c35) / sizeof(cfg->c35[0]) ; i++) ImageBuffer[current_index++] = cfg->c35[i]; |
| for (i = 1 ; i < sizeof(cfg->c36) / sizeof(cfg->c36[0]) ; i++) ImageBuffer[current_index++] = cfg->c36[i]; |
| for (i = 1 ; i < sizeof(cfg->c37) / sizeof(cfg->c37[0]) ; i++) ImageBuffer[current_index++] = cfg->c37[i]; |
| for (i = 1 ; i < sizeof(cfg->c38) / sizeof(cfg->c38[0]) ; i++) ImageBuffer[current_index++] = cfg->c38[i]; |
| for (i = 1 ; i < sizeof(cfg->c39) / sizeof(cfg->c39[0]) ; i++) ImageBuffer[current_index++] = cfg->c39[i]; |
| current_index = current_index + 50; //dummy data |
| //I(" %s: current_index=%d\n", __func__,current_index); |
| for (i = 1 ; i < sizeof(cfg->c40) / sizeof(cfg->c40[0]) ; i++) ImageBuffer[current_index++] = cfg->c40[i]; |
| for (i = 1 ; i < sizeof(cfg->c41) / sizeof(cfg->c41[0]) ; i++) ImageBuffer[current_index++] = cfg->c41[i]; |
| //cal_checksum start// |
| FileLength = fullFileLength; |
| FileLength = (FileLength + 3) / 4; |
| for (i = 0; i < FileLength; i++) { |
| memcpy(&cmd[0], &ImageBuffer[4 * i], 4); |
| if (i < (FileLength - 1)) { /*cal_checksum*/ |
| for (k = 0; k < 4; k++) { |
| BinDataWord |= cmd[k] << (k * 8); |
| } |
| CRC32 = BinDataWord ^ CRC32; |
| for (k = 0; k < 32; k++) { |
| if ((CRC32 % 2) != 0) { |
| CRC32 = ((CRC32 >> 1) & 0x7FFFFFFF) ^ Polynomial; |
| } else { |
| CRC32 = ((CRC32 >> 1) & 0x7FFFFFFF); |
| } |
| } |
| BinDataWord = 0; |
| } |
| } |
| //cal_checksum end// |
| FileLength = fullFileLength; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_TSSLPOUT , &cmd[0], 0, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| msleep(120); |
| himax_lock_flash(0); |
| himax_ManualMode(1); |
| himax_FlashMode(1); |
| FileLength = (FileLength + 3) / 4; |
| for (i = 0, prePage = 0; i < FileLength; i++) { |
| last_byte = 0; |
| if (i < 0x20) |
| continue; |
| else if ((i > 0xBF) && (i < (FileLength - 0x20))) |
| continue; |
| cmd[0] = i & 0x1F; |
| if (cmd[0] == 0x1F || i == FileLength - 1) { |
| last_byte = 1; |
| } |
| cmd[1] = (i >> 5) & 0x1F; |
| cmd[2] = (i >> 10) & 0x1F; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| //I(" %s: CMD 44 [0,1,2]=[%x,%x,%x]\n", __func__,cmd[0],cmd[1],cmd[2]); |
| if (prePage != cmd[1] || i == 0x20) { |
| prePage = cmd[1]; |
| //I(" %s: %d page erase\n",__func__,prePage); |
| tmp[0] = 0x01; |
| tmp[1] = 0x09;//tmp[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| tmp[0] = 0x05; |
| tmp[1] = 0x2D;//tmp[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| msleep(30); |
| tmp[0] = 0x01; |
| tmp[1] = 0x09;//tmp[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| //I(" %s: CMD 44-47 [0,1,2]=[%x,%x,%x]\n", __func__,cmd[0],cmd[1],cmd[2]); |
| tmp[0] = 0x01; |
| tmp[1] = 0x09;//tmp[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| tmp[0] = 0x01; |
| tmp[1] = 0x0D;//tmp[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| tmp[0] = 0x01; |
| tmp[1] = 0x09;//tmp[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| //I(" %s: CMD 44-45 [0,1,2]=[%x,%x,%x]\n", __func__,cmd[0],cmd[1],cmd[2]); |
| //I(" %s: Erase Page num=%x\n", __func__,prePage); |
| } |
| memcpy(&cmd[0], &ImageBuffer[4 * i], 4); |
| if (i == (FileLength - 1)) { |
| tmp[0] = (CRC32 & 0xFF); |
| tmp[1] = ((CRC32 >> 8) & 0xFF); |
| tmp[2] = ((CRC32 >> 16) & 0xFF); |
| tmp[3] = ((CRC32 >> 24) & 0xFF); |
| memcpy(&cmd[0], &tmp[0], 4); |
| I("%s last_byte = 1, CRC32= %x, =[0,1,2,3] = %x,%x,%x,%x \n", __func__, CRC32, tmp[0], tmp[1], tmp[2], tmp[3]); |
| } |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_WRITE_REGISTER , &cmd[0], 4, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| //I(" %s: CMD 48 \n", __func__); |
| cmd[0] = 0x01; |
| cmd[1] = 0x0D;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x09;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| if (last_byte == 1) { |
| cmd[0] = 0x01; |
| cmd[1] = 0x01;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x05;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x01;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| cmd[0] = 0x01; |
| cmd[1] = 0x00;//cmd[2] = 0x02; |
| if ( i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) { |
| E("[%d] %s: i2c access fail!\n", __LINE__, __func__); |
| return 0; |
| } |
| msleep(10); |
| if (i == (FileLength - 1)) { |
| himax_FlashMode(0); |
| himax_ManualMode(0); |
| checksumResult = himax_calculateChecksum(true, false); |
| //himax_ManualMode(0); |
| himax_lock_flash(1); |
| I("%s: flash CONFIG only END!\n", __func__); |
| if (checksumResult) { //Success |
| return 1; |
| } else { //Fail |
| E("%s: checksumResult fail!\n", __func__); |
| return 0; |
| } |
| } |
| } |
| } |
| return 0; |
| } |
| |
| static int i_update_FWCFG(struct himax_config *cfg) |
| { |
| int upgrade_times = 0; |
| I("%s: CHIP CONFG version=%x\n", __func__, private_ts->vendor_config_ver); |
| I("%s: LOAD CONFG version=%x\n", __func__, cfg->c40[1]); |
| if ( private_ts->vendor_config_ver != cfg->c40[1] ) { |
| update_retry: |
| #ifdef HX_RST_PIN_FUNC |
| himax_HW_reset(false, true); |
| #endif |
| if (fts_ctpm_fw_upgrade_with_i_file_flash_cfg(cfg) == 0) { |
| upgrade_times++; |
| E("%s: TP upgrade error times=%d\n", __func__, upgrade_times); |
| if (upgrade_times < 3) |
| goto update_retry; |
| } else |
| I("%s: TP upgrade OK\n", __func__); |
| #ifdef HX_RST_PIN_FUNC |
| himax_HW_reset(false, true); |
| #endif |
| return 1; |
| } else |
| return 0; |
| } |
| |
| #endif |
| |
| static int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata) |
| { |
| #if defined(HX_LOADIN_CONFIG)||defined(HX_AUTO_UPDATE_CONFIG) |
| int rc = 0; |
| #endif |
| #ifndef CONFIG_OF |
| #if defined(HX_LOADIN_CONFIG)||defined(HX_AUTO_UPDATE_CONFIG) |
| int i = 0; |
| #endif |
| #endif |
| #ifdef HX_ESD_WORKAROUND |
| char data[12] = {0}; |
| #endif |
| if (!client) { |
| E("%s: Necessary parameters client are null!\n", __func__); |
| return -1; |
| } |
| if (config_load == false) { |
| config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); |
| if (config_selected == NULL) { |
| E("%s: alloc config_selected fail!\n", __func__); |
| return -1; |
| } |
| } |
| #ifndef CONFIG_OF |
| pdata = client->dev.platform_data; |
| if (!pdata) { |
| E("%s: Necessary parameters pdata are null!\n", __func__); |
| return -1; |
| } |
| #endif |
| #if defined(HX_LOADIN_CONFIG)||defined(HX_AUTO_UPDATE_CONFIG) |
| #ifdef CONFIG_OF |
| //I("%s, config_selected, %X\n", __func__ ,(uint32_t)config_selected); |
| if (config_load == false) { |
| rc = himax_parse_config(private_ts, config_selected); |
| if (rc < 0) { |
| E(" DT:cfg table parser FAIL. ret=%d\n", rc); |
| goto HimaxErr; |
| } else if (rc == 0) { |
| if ((private_ts->tw_x_max) && (private_ts->tw_y_max)) { |
| pdata->abs_x_min = private_ts->tw_x_min; |
| pdata->abs_x_max = private_ts->tw_x_max; |
| pdata->abs_y_min = private_ts->tw_y_min; |
| pdata->abs_y_max = private_ts->tw_y_max; |
| I(" DT-%s:config-panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min, |
| pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); |
| } |
| if ((private_ts->pl_x_max) && (private_ts->pl_y_max)) { |
| pdata->screenWidth = private_ts->pl_x_max; |
| pdata->screenHeight = private_ts->pl_y_max; |
| I(" DT-%s:config-display-coords = (%d, %d)", __func__, pdata->screenWidth, |
| pdata->screenHeight); |
| } |
| config_load = true; |
| I(" DT parser Done\n"); |
| } |
| } |
| #else |
| I("pdata->hx_config_size=%x.\n", (pdata->hx_config_size + 1)); |
| I("config_type_size=%x.\n", sizeof(struct himax_config)); |
| if (pdata->hx_config) { |
| for (i = 0; i < pdata->hx_config_size / sizeof(struct himax_config); ++i) { |
| I("(pdata->hx_config)[%x].fw_ver_main=%x.\n", i, (pdata->hx_config)[i].fw_ver_main); |
| I("(pdata->hx_config)[%x].fw_ver_minor=%x.\n", i, (pdata->hx_config)[i].fw_ver_minor); |
| I("(pdata->hx_config)[%x].sensor_id=%x.\n", i, (pdata->hx_config)[i].sensor_id); |
| if ((private_ts->vendor_fw_ver_H << 8 | private_ts->vendor_fw_ver_L) < |
| ((pdata->hx_config)[i].fw_ver_main << 8 | (pdata->hx_config)[i].fw_ver_minor)) { |
| continue; |
| } else { |
| if ((private_ts->vendor_sensor_id == (pdata->hx_config)[i].sensor_id)) { |
| config_selected = &((pdata->hx_config)[i]); |
| I("hx_config selected, %X\n", (uint32_t)config_selected); |
| config_load = true; |
| break; |
| } else if ((pdata->hx_config)[i].default_cfg) { |
| I("default_cfg detected.\n"); |
| config_selected = &((pdata->hx_config)[i]); |
| I("hx_config selected, %X\n", (uint32_t)config_selected); |
| config_load = true; |
| break; |
| } |
| } |
| } |
| } else { |
| E("%s: pdata->hx_config is not exist.\n", __func__); |
| goto HimaxErr; |
| } |
| #endif |
| #endif |
| #ifdef HX_LOADIN_CONFIG |
| if (config_selected) { |
| //Read config id |
| private_ts->vendor_config_ver = config_selected->c40[1]; |
| //Normal Register c1~c35 |
| i2c_himax_master_write(client, config_selected->c1, sizeof(config_selected->c1), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c2, sizeof(config_selected->c2), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c3, sizeof(config_selected->c3), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c4, sizeof(config_selected->c4), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c5, sizeof(config_selected->c5), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c6, sizeof(config_selected->c6), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c7, sizeof(config_selected->c7), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c8, sizeof(config_selected->c8), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c9, sizeof(config_selected->c9), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c10, sizeof(config_selected->c10), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c11, sizeof(config_selected->c11), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c12, sizeof(config_selected->c12), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c13, sizeof(config_selected->c13), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c14, sizeof(config_selected->c14), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c15, sizeof(config_selected->c15), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c16, sizeof(config_selected->c16), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c17, sizeof(config_selected->c17), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c18, sizeof(config_selected->c18), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c19, sizeof(config_selected->c19), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c20, sizeof(config_selected->c20), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c21, sizeof(config_selected->c21), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c22, sizeof(config_selected->c22), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c23, sizeof(config_selected->c23), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c24, sizeof(config_selected->c24), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c25, sizeof(config_selected->c25), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c26, sizeof(config_selected->c26), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c27, sizeof(config_selected->c27), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c28, sizeof(config_selected->c28), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c29, sizeof(config_selected->c29), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c30, sizeof(config_selected->c30), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c31, sizeof(config_selected->c31), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c32, sizeof(config_selected->c32), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c33, sizeof(config_selected->c33), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c34, sizeof(config_selected->c34), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c35, sizeof(config_selected->c35), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c36, sizeof(config_selected->c36), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c37, sizeof(config_selected->c37), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c38, sizeof(config_selected->c38), DEFAULT_RETRY_CNT); |
| i2c_himax_master_write(client, config_selected->c39, sizeof(config_selected->c39), DEFAULT_RETRY_CNT); |
| //Config Bank register |
| himax_config_reg_write(client, 0x00, config_selected->c40, sizeof(config_selected->c40), DEFAULT_RETRY_CNT); |
| himax_config_reg_write(client, 0x9E, config_selected->c41, sizeof(config_selected->c41), DEFAULT_RETRY_CNT); |
| msleep(1); |
| } else { |
| E("%s: config_selected is null.\n", __func__); |
| goto HimaxErr; |
| } |
| #endif |
| #ifdef HX_ESD_WORKAROUND |
| //Check R36 to check IC Status |
| i2c_himax_read(client, 0x36, data, 2, 10); |
| if (data[0] != 0x0F || data[1] != 0x53) { |
| //IC is abnormal |
| E("%s: R36 Fail: R36[0]=%d, R36[1]=%d, R36 Counter=%d\n", __func__, data[0], data[1], ESD_R36_FAIL); |
| return -1; |
| } |
| #endif |
| #ifdef HX_AUTO_UPDATE_CONFIG |
| if (i_update_FWCFG(config_selected) == false) |
| I("NOT Have new FWCFG=NOT UPDATE=\n"); |
| else |
| I("Have new FWCFG=UPDATE=\n"); |
| #endif |
| himax_power_on_initCMD(client); |
| I("%s: initialization complete\n", __func__); |
| return 1; |
| #if defined(HX_LOADIN_CONFIG)||defined(HX_AUTO_UPDATE_CONFIG) |
| HimaxErr: |
| return -1; |
| #endif |
| } |
| |
| #ifdef HX_RST_PIN_FUNC |
| void himax_HW_reset(uint8_t loadconfig, uint8_t int_off) |
| { |
| struct himax_ts_data *ts = private_ts; |
| int ret = 0; |
| HW_RESET_ACTIVATE = 1; |
| if (ts->rst_gpio) { |
| if (!int_off) { |
| if (ts->use_irq) |
| himax_int_enable(private_ts->client->irq, 0, true); |
| else { |
| hrtimer_cancel(&ts->timer); |
| ret = cancel_work_sync(&ts->work); |
| } |
| } |
| I("%s: Now reset the Touch chip.\n", __func__); |
| himax_rst_gpio_set(ts->rst_gpio, 0); |
| msleep(20); |
| himax_rst_gpio_set(ts->rst_gpio, 1); |
| msleep(20); |
| if (loadconfig) |
| himax_loadSensorConfig(private_ts->client, private_ts->pdata); |
| if (!int_off) { |
| if (ts->use_irq) |
| himax_int_enable(private_ts->client->irq, 1, true); |
| else |
| hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); |
| } |
| } |
| } |
| #endif |
| |
| static u8 himax_read_FW_ver(bool hw_reset) |
| { |
| uint8_t cmd[3]; |
| himax_int_enable(private_ts->client->irq, 0, true); |
| #ifdef HX_RST_PIN_FUNC |
| if (hw_reset) { |
| himax_HW_reset(false, true); |
| } |
| #endif |
| msleep(120); |
| if (i2c_himax_read(private_ts->client, HX_VER_FW_MAJ, cmd, 1, 3) < 0) { |
| E("%s: i2c access fail!\n", __func__); |
| return 0; |
| } |
| private_ts->vendor_fw_ver_H = cmd[0]; |
| if (i2c_himax_read(private_ts->client, HX_VER_FW_MIN, cmd, 1, 3) < 0) { |
| E("%s: i2c access fail!\n", __func__); |
| return 0; |
| } |
| private_ts->vendor_fw_ver_L = cmd[0]; |
| I("FW_VER: %x.%x\n", private_ts->vendor_fw_ver_H, private_ts->vendor_fw_ver_L); |
| if (i2c_himax_read(private_ts->client, HX_VER_FW_CFG, cmd, 1, 3) < 0) { |
| E("%s: i2c access fail!\n", __func__); |
| return 0; |
| } |
| private_ts->vendor_config_ver = cmd[0]; |
| I("CFG_VER: %x\n", private_ts->vendor_config_ver); |
| #ifdef HX_RST_PIN_FUNC |
| if (hw_reset) |
| himax_HW_reset(true, true); |
| #endif |
| himax_int_enable(private_ts->client->irq, 1, true); |
| return 0; |
| } |
| |
| static bool himax_ic_package_check(struct himax_ts_data *ts) |
| { |
| uint8_t cmd[3]; |
| memset(cmd, 0x00, sizeof(cmd)); |
| if (i2c_himax_read(ts->client, 0xD1, cmd, 3, DEFAULT_RETRY_CNT) < 0) |
| return false ; |
| if (cmd[0] == 0x05 && cmd[1] == 0x85 && |
| (cmd[2] == 0x25 || cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28)) { |
| IC_TYPE = HX_85XX_ES_SERIES_PWON; |
| IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; |
| //Himax: Set FW and CFG Flash Address |
| FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 |
| FW_VER_MAJ_FLASH_LENG = 1; |
| FW_VER_MIN_FLASH_ADDR = 134; //0x0086 |
| FW_VER_MIN_FLASH_LENG = 1; |
| CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 |
| CFG_VER_MAJ_FLASH_LENG = 12; |
| CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC |
| CFG_VER_MIN_FLASH_LENG = 12; |
| FW_CFG_VER_FLASH_ADDR = 132; //0x0084 |
| #ifdef HX_AUTO_UPDATE_CONFIG |
| CFB_START_ADDR = 0x80; |
| CFB_LENGTH = 638; |
| CFB_INFO_LENGTH = 68; |
| #endif |
| I("Himax IC package 852x ES\n"); |
| } else { |
| E("Himax IC package incorrect!!PKG[0]=%x,PKG[1]=%x,PKG[2]=%x\n", cmd[0], cmd[1], cmd[2]); |
| return false ; |
| } |
| return true; |
| } |
| |
| static void himax_read_TP_info(struct i2c_client *client) |
| { |
| char data[12] = {0}; |
| //read fw version |
| if (i2c_himax_read(client, HX_VER_FW_MAJ, data, 1, 3) < 0) { |
| E("%s: i2c access fail!\n", __func__); |
| return; |
| } |
| private_ts->vendor_fw_ver_H = data[0]; |
| if (i2c_himax_read(client, HX_VER_FW_MIN, data, 1, 3) < 0) { |
| E("%s: i2c access fail!\n", __func__); |
| return; |
| } |
| private_ts->vendor_fw_ver_L = data[0]; |
| //read config version |
| if (i2c_himax_read(client, HX_VER_FW_CFG, data, 1, 3) < 0) { |
| E("%s: i2c access fail!\n", __func__); |
| return; |
| } |
| private_ts->vendor_config_ver = data[0]; |
| //read sensor ID |
| private_ts->vendor_sensor_id = himax_read_Sensor_ID(client); |
| I("sensor_id=%x.\n", private_ts->vendor_sensor_id); |
| I("fw_ver=%x.%x.\n", private_ts->vendor_fw_ver_H, private_ts->vendor_fw_ver_L); |
| I("config_ver=%x.\n", private_ts->vendor_config_ver); |
| } |
| |
| #ifdef HX_ESD_WORKAROUND |
| void ESD_HW_REST(void) |
| { |
| ESD_RESET_ACTIVATE = 1; |
| ESD_COUNTER = 0; |
| ESD_R36_FAIL = 0; |
| #ifdef HX_CHIP_STATUS_MONITOR |
| HX_CHIP_POLLING_COUNT = 0; |
| #endif |
| I("START_Himax TP: ESD - Reset\n"); |
| while (ESD_R36_FAIL <= 3 ) { |
| himax_rst_gpio_set(private_ts->rst_gpio, 0); |
| msleep(20); |
| himax_rst_gpio_set(private_ts->rst_gpio, 1); |
| msleep(20); |
| if (himax_loadSensorConfig(private_ts->client, private_ts->pdata) < 0) |
| ESD_R36_FAIL++; |
| else |
| break; |
| } |
| I("END_Himax TP: ESD - Reset\n"); |
| } |
| #endif |
| |
| #ifdef HX_CHIP_STATUS_MONITOR |
| static void himax_chip_monitor_function(struct work_struct *work) //for ESD solution |
| { |
| int ret = 0; |
| I("%s: POLLING_COUNT=%x, STATUS=%x \n", __func__, HX_CHIP_POLLING_COUNT, ret); |
| if (HX_CHIP_POLLING_COUNT >= (HX_POLLING_TIMES - 1)) { //POLLING TIME |
| HX_ON_HAND_SHAKING = 1; |
| ret = himax_hand_shaking(); //0:Running, 1:Stop, 2:I2C Fail |
| HX_ON_HAND_SHAKING = 0; |
| if (ret == 2) { |
| I("%s: I2C Fail\n", __func__); |
| ESD_HW_REST(); |
| } else if (ret == 1) { |
| I("%s: MCU Stop\n", __func__); |
| ESD_HW_REST(); |
| } |
| HX_CHIP_POLLING_COUNT = 0; //clear polling counter |
| } else |
| HX_CHIP_POLLING_COUNT++; |
| queue_delayed_work(private_ts->himax_chip_monitor_wq, &private_ts->himax_chip_monitor, HX_POLLING_TIMER * HZ); |
| return; |
| } |
| #endif |
| |
| #ifdef HX_SMART_WAKEUP |
| static int himax_parse_wake_event(struct himax_ts_data *ts) |
| { |
| uint8_t buf[5]; |
| if (i2c_himax_read(ts->client, 0x86, buf, 4, DEFAULT_RETRY_CNT)) |
| E("%s: can't read data from chip!\n", __func__); |
| if ((buf[0] == 0x57) && (buf[1] == 0x61) && (buf[2] == 0x6B) && (buf[3] == 0x65)) { |
| I("%s: WAKE UP system!\n", __func__); |
| return 1;//Yes, wake up system |
| } else { |
| I("%s: NOT WKAE packet, SKIP!\n", __func__); |
| I("%s: buf[0]=%x, buf[1]=%x, buf[2]=%x, buf[3]=%x\n", __func__, buf[0], buf[1], buf[2], buf[3]); |
| return 0; |
| } |
| } |
| #endif |
| |
| inline void himax_ts_work(struct himax_ts_data *ts) |
| { |
| uint8_t buf[128], finger_num, hw_reset_check[2]; |
| uint16_t finger_pressed; |
| int32_t loop_i; |
| unsigned char check_sum_cal = 0; |
| int RawDataLen = 0; |
| int raw_cnt_max, raw_cnt_rmd, hx_touch_info_size; |
| int base, x, y, w; |
| uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4; |
| #ifdef HX_TP_PROC_DIAG |
| uint8_t *mutual_data; |
| uint8_t *self_data; |
| uint8_t diag_cmd; |
| int i, mul_num, self_num; |
| int index = 0; |
| int temp1, temp2; |
| int ret = 0; |
| //coordinate dump start |
| char coordinate_char[15 + (HX_MAX_PT + 5) * 2 * 5 + 2]; |
| struct timeval t; |
| struct tm broken; |
| //coordinate dump end |
| #endif |
| #ifdef HX_CHIP_STATUS_MONITOR |
| int j = 0; |
| #endif |
| memset(buf, 0x00, sizeof(buf)); |
| memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); |
| #ifdef HX_CHIP_STATUS_MONITOR |
| HX_CHIP_POLLING_COUNT = 0; |
| if (HX_ON_HAND_SHAKING) { //chip on hand shaking,wait hand shaking |
| for (j = 0; j < 100; j++) { |
| if (HX_ON_HAND_SHAKING == 0) { //chip on hand shaking end |
| I("%s: HX_ON_HAND_SHAKING OK check %d times\n", __func__, j); |
| break; |
| } else |
| msleep(1); |
| } |
| if (j == 100) { |
| E("%s: HX_ON_HAND_SHAKING timeout reject interrupt\n", __func__); |
| return; |
| } |
| } |
| #endif |
| raw_cnt_max = HX_MAX_PT / 4; |
| raw_cnt_rmd = HX_MAX_PT % 4; |
| if (raw_cnt_rmd != 0x00) { //more than 4 fingers |
| RawDataLen = 128 - ((HX_MAX_PT + raw_cnt_max + 3) * 4) - 1; |
| hx_touch_info_size = (HX_MAX_PT + raw_cnt_max + 2) * 4; |
| } else { //less than 4 fingers |
| RawDataLen = 128 - ((HX_MAX_PT + raw_cnt_max + 2) * 4) - 1; |
| hx_touch_info_size = (HX_MAX_PT + raw_cnt_max + 1) * 4; |
| } |
| #ifdef HX_TP_PROC_DIAG |
| diag_cmd = getDiagCommand(); |
| #ifdef HX_ESD_WORKAROUND |
| if ((diag_cmd) || (ESD_RESET_ACTIVATE) || (HW_RESET_ACTIVATE)) |
| #else |
| if ((diag_cmd) || (HW_RESET_ACTIVATE)) |
| #endif |
| { |
| ret = i2c_himax_read(ts->client, 0x86, buf, 128, DEFAULT_RETRY_CNT); |
| } else { |
| if (touch_monitor_stop_flag != 0) { |
| ret = i2c_himax_read(ts->client, 0x86, buf, 128, DEFAULT_RETRY_CNT); |
| touch_monitor_stop_flag-- ; |
| } else { |
| ret = i2c_himax_read(ts->client, 0x86, buf, hx_touch_info_size, DEFAULT_RETRY_CNT); |
| } |
| } |
| if (ret < 0) |
| #else |
| if (i2c_himax_read(ts->client, 0x86, buf, hx_touch_info_size, DEFAULT_RETRY_CNT)) |
| #endif |
| { |
| E("%s: can't read data from chip!\n", __func__); |
| goto err_workqueue_out; |
| } else { |
| #ifdef HX_ESD_WORKAROUND |
| for (i = 0; i < hx_touch_info_size; i++) { |
| if (buf[i] == 0x00) { //case 2 ESD recovery flow-Disable |
| check_sum_cal = 1; |
| } else if (buf[i] == 0xED) { /*case 1 ESD recovery flow*/ |
| check_sum_cal = 2; |
| } else { |
| check_sum_cal = 0; |
| i = hx_touch_info_size; |
| break; |
| } |
| } |
| //IC status is abnormal ,do hand shaking |
| #ifdef HX_TP_PROC_DIAG |
| diag_cmd = getDiagCommand(); |
| #ifdef HX_ESD_WORKAROUND |
| if (check_sum_cal != 0 && ESD_RESET_ACTIVATE == 0 && HW_RESET_ACTIVATE == 0 && diag_cmd == 0) //ESD Check |
| #else |
| if (check_sum_cal != 0 && diag_cmd == 0) |
| #endif |
| #else |
| #ifdef HX_ESD_WORKAROUND |
| if (check_sum_cal != 0 && ESD_RESET_ACTIVATE == 0 && HW_RESET_ACTIVATE == 0 ) //ESD Check |
| #else |
| if (check_sum_cal != 0) |
| #endif |
| #endif |
| { |
| ret = himax_hand_shaking(); //0:Running, 1:Stop, 2:I2C Fail |
| if (ret == 2) { |
| goto err_workqueue_out; |
| } |
| if ((ret == 1) && (check_sum_cal == 1)) { |
| I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); |
| ESD_HW_REST(); |
| } else if (check_sum_cal == 2) { |
| I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); |
| ESD_HW_REST(); |
| } |
| //himax_int_enable(ts->client->irq,1,true); |
| return; |
| } else if (ESD_RESET_ACTIVATE) { |
| ESD_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/ |
| I("[HIMAX TP MSG]:%s: Back from reset, ready to serve.\n", __func__); |
| return; |
| } else if (HW_RESET_ACTIVATE) |
| #else |
| if (HW_RESET_ACTIVATE) |
| #endif |
| { |
| HW_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/ |
| I("[HIMAX TP MSG]:%s: HW_RST Back from reset, ready to serve.\n", __func__); |
| return; |
| } |
| for (loop_i = 0, check_sum_cal = 0; loop_i < hx_touch_info_size; loop_i++) |
| check_sum_cal += buf[loop_i]; |
| if ((check_sum_cal != 0x00)) { |
| if (ts->debug_log_level & BIT(1)) |
| I("[HIMAX TP MSG] check_sum_cal: 0x%02X\n", check_sum_cal); |
| return; |
| } |
| } |
| if (ts->debug_log_level & BIT(0)) { |
| I("%s: raw data:\n", __func__); |
| for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) { |
| I("0x%2.2X ", buf[loop_i]); |
| if (loop_i % 8 == 7) |
| I("\n"); |
| } |
| } |
| //touch monitor raw data fetch |
| #ifdef HX_TP_PROC_DIAG |
| diag_cmd = getDiagCommand(); |
| if (diag_cmd >= 1 && diag_cmd <= 6) { |
| //Check 128th byte CRC |
| for (i = hx_touch_info_size, check_sum_cal = 0; i < 128; i++) { |
| check_sum_cal += buf[i]; |
| } |
| if (check_sum_cal % 0x100 != 0) { |
| goto bypass_checksum_failed_packet; |
| } |
| #ifdef HX_TP_PROC_2T2R |
| if (Is_2T2R && diag_cmd == 4) { |
| mutual_data = getMutualBuffer_2(); |
| self_data = getSelfBuffer(); |
| // initiallize the block number of mutual and self |
| mul_num = getXChannel_2() * getYChannel_2(); |
| self_num = getXChannel_2() + getYChannel_2(); |
| } else |
| #endif |
| { |
| mutual_data = getMutualBuffer(); |
| self_data = getSelfBuffer(); |
| // initiallize the block number of mutual and self |
| mul_num = getXChannel() * getYChannel(); |
| self_num = getXChannel() + getYChannel(); |
| } |
| //Himax: Check Raw-Data Header |
| if (buf[hx_touch_info_size] == buf[hx_touch_info_size + 1] && buf[hx_touch_info_size + 1] == buf[hx_touch_info_size + 2] |
| && buf[hx_touch_info_size + 2] == buf[hx_touch_info_size + 3] && buf[hx_touch_info_size] > 0) { |
| index = (buf[hx_touch_info_size] - 1) * RawDataLen; |
| //I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); |
| for (i = 0; i < RawDataLen; i++) { |
| temp1 = index + i; |
| if (temp1 < mul_num) { //mutual |
| mutual_data[index + i] = buf[i + hx_touch_info_size + 4]; //4: RawData Header |
| } else {//self |
| temp1 = i + index; |
| temp2 = self_num + mul_num; |
| if (temp1 >= temp2) { |
| break; |
| } |
| self_data[i + index - mul_num] = buf[i + hx_touch_info_size + 4]; //4: RawData Header |
| } |
| } |
| } else { |
| if (ts->debug_log_level & BIT(1)) |
| I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__); |
| } |
| } else if (diag_cmd == 7) { |
| memcpy(&(diag_coor[0]), &buf[0], 128); |
| } |
| //coordinate dump start |
| if (coordinate_dump_enable == 1) { |
| for (i = 0; i < (15 + (HX_MAX_PT + 5) * 2 * 5); i++) { |
| coordinate_char[i] = 0x20; |
| } |
| coordinate_char[15 + (HX_MAX_PT + 5) * 2 * 5] = 0xD; |
| coordinate_char[15 + (HX_MAX_PT + 5) * 2 * 5 + 1] = 0xA; |
| } |
| //coordinate dump end |
| bypass_checksum_failed_packet: |
| #endif |
| EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 3); |
| //I("EN_NoiseFilter=%d\n",EN_NoiseFilter); |
| EN_NoiseFilter = EN_NoiseFilter & 0x01; |
| //I("EN_NoiseFilter2=%d\n",EN_NoiseFilter); |
| p_point_num = hx_point_num; |
| if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) |
| hx_point_num = 0; |
| else |
| hx_point_num = buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; |
| // Touch Point information |
| if (hx_point_num != 0 ) { |
| uint16_t old_finger = ts->pre_finger_mask; |
| finger_num = buf[coordInfoSize - 4] & 0x0F; |
| finger_pressed = buf[coordInfoSize - 2] << 8 | buf[coordInfoSize - 3]; |
| AA_press = 1; |
| for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { |
| if (((finger_pressed >> loop_i) & 1) == 1) { |
| base = loop_i * 4; |
| x = buf[base] << 8 | buf[base + 1]; |
| y = (buf[base + 2] << 8 | buf[base + 3]); |
| w = buf[(ts->nFinger_support * 4) + loop_i]; |
| finger_num--; |
| if ((ts->debug_log_level & BIT(3)) > 0) { |
| if ((((old_finger >> loop_i) ^ (finger_pressed >> loop_i)) & 1) == 1) { |
| if (ts->useScreenRes) { |
| I("status:%X, Screen:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", |
| finger_pressed, loop_i + 1, x * ts->widthFactor >> SHIFTBITS, |
| y * ts->heightFactor >> SHIFTBITS, w, EN_NoiseFilter); |
| } else { |
| I("status:%X, Raw:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", |
| finger_pressed, loop_i + 1, x, y, w, EN_NoiseFilter); |
| } |
| } |
| } |
| if (ts->protocol_type == PROTOCOL_TYPE_B) { |
| input_mt_slot(ts->input_dev, loop_i); |
| } |
| input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); |
| input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); |
| input_report_abs(ts->input_dev, ABS_MT_PRESSURE, w); |
| input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); |
| input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); |
| if (point_flag[loop_i] == 0) { //print out touch down coordinate |
| point_flag[loop_i] = 1; |
| I("P%d DOWN, x = %d, y = %d \n", loop_i+1, x, y); |
| haspoint = true; |
| } |
| if (ts->protocol_type == PROTOCOL_TYPE_A) { |
| input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, loop_i); |
| input_mt_sync(ts->input_dev); |
| } else { |
| ts->last_slot = loop_i; |
| input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); |
| } |
| if (!ts->first_pressed) { |
| ts->first_pressed = 1; |
| I("S1@%d, %d\n", x, y); |
| } |
| ts->pre_finger_data[loop_i][0] = x; |
| ts->pre_finger_data[loop_i][1] = y; |
| if (ts->debug_log_level & BIT(1)) |
| I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, N:%d\n", |
| loop_i + 1, x, y, w, w, loop_i + 1, EN_NoiseFilter); |
| } else { |
| if (ts->protocol_type == PROTOCOL_TYPE_B) { |
| input_mt_slot(ts->input_dev, loop_i); |
| input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); |
| if (point_flag[loop_i] == 1) { |
| point_flag[loop_i] = 0; |
| I("P%d Up \n", loop_i+1); |
| } |
| if (ts->debug_log_level & BIT(1)) |
| I("All Finger leave_Clear_last_event\n"); |
| } |
| if (loop_i == 0 && ts->first_pressed == 1) { |
| ts->first_pressed = 2; |
| I("E1@%d, %d\n", |
| ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); |
| } |
| if ((ts->debug_log_level & BIT(3)) > 0) { |
| if ((((old_finger >> loop_i) ^ (finger_pressed >> loop_i)) & 1) == 1) { |
| if (ts->useScreenRes) { |
| I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", |
| finger_pressed, loop_i + 1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, |
| ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); |
| } else { |
| I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n", |
| finger_pressed, loop_i + 1, ts->pre_finger_data[loop_i][0], |
| ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); |
| } |
| } |
| } |
| } |
| } |
| ts->pre_finger_mask = finger_pressed; |
| #ifdef HX_ESD_WORKAROUND |
| ESD_COUNTER = 0; |
| #endif |
| input_sync(ts->input_dev); |
| } else if (hx_point_num == 0) { |
| #ifdef HX_PALM_REPORT |
| loop_i = 0; |
| base = loop_i * 4; |
| x = buf[base] << 8 | buf[base + 1]; |
| y = (buf[base + 2] << 8 | buf[base + 3]); |
| w = buf[(ts->nFinger_support * 4) + loop_i]; |
| if ((!atomic_read(&ts->suspend_mode)) && (x == 0xFA5A) && (y == 0xFA5A) && (w == 0x00)) { |
| I("%s: HX_PALM_REPORT KEY power event press\n", __func__); |
| input_report_key(ts->input_dev, KEY_SLEEP, 1); |
| input_sync(ts->input_dev); |
| msleep(100); |
| I("%s: HX_PALM_REPORT KEY power event release\n", __func__); |
| input_report_key(ts->input_dev, KEY_SLEEP, 0); |
| input_sync(ts->input_dev); |
| return; |
| } else { |
| if (!AA_press) |
| I("%s: HX_PALM_REPORT_loopi=%d,base=%x,X=%x,Y=%x,W=%x \n", __func__, loop_i, base, x, y, w); |
| } |
| #endif |
| if (AA_press) { // leave event |
| AA_press = 0; |
| if (ts->protocol_type == PROTOCOL_TYPE_A) |
| input_mt_sync(ts->input_dev); |
| for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { |
| if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { |
| if (ts->protocol_type == PROTOCOL_TYPE_B) { |
| input_mt_slot(ts->input_dev, loop_i); |
| input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); |
| if (haspoint) { |
| point_flag[loop_i] = 0; |
| I("P%d Up \n",loop_i+1); |
| } |
| } |
| } |
| } |
| if (ts->pre_finger_mask > 0) { |
| for (loop_i = 0; loop_i < ts->nFinger_support && (ts->debug_log_level & BIT(3)) > 0; loop_i++) { |
| if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { |
| if (ts->useScreenRes) { |
| I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i + 1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, |
| ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); |
| } else { |
| I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i + 1, ts->pre_finger_data[loop_i][0], ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); |
| } |
| } |
| } |
| ts->pre_finger_mask = 0; |
| } |
| if (ts->first_pressed == 1) { |
| ts->first_pressed = 2; |
| I("E1@%d, %d\n", ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); |
| } |
| if (ts->debug_log_level & BIT(1)) |
| I("All Finger leave\n"); |
| #ifdef HX_TP_PROC_DIAG |
| //coordinate dump start |
| if (coordinate_dump_enable == 1) { |
| do_gettimeofday(&t); |
| time_to_tm(t.tv_sec, 0, &broken); |
| sprintf(&coordinate_char[0], "%2d:%2d:%2d:%lu,", broken.tm_hour, broken.tm_min, broken.tm_sec, t.tv_usec / 1000); |
| sprintf(&coordinate_char[15], "Touch up!"); |
| coordinate_fn->f_op->write(coordinate_fn, &coordinate_char[0], 15 + (HX_MAX_PT + 5) * 2 * sizeof(char) * 5 + 2, &coordinate_fn->f_pos); |
| } |
| //coordinate dump end |
| #endif |
| } |
| #ifdef HX_ESD_WORKAROUND |
| ESD_COUNTER = 0; |
| #endif |
| input_sync(ts->input_dev); |
| } |
| Last_EN_NoiseFilter = EN_NoiseFilter; |
| workqueue_out: |
| return; |
| err_workqueue_out: |
| I("%s: Now reset the Touch chip.\n", __func__); |
| #ifdef HX_RST_PIN_FUNC |
| himax_HW_reset(true, false); |
| #endif |
| goto workqueue_out; |
| } |
| |
| static enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) |
| { |
| struct himax_ts_data *ts; |
| ts = container_of(timer, struct himax_ts_data, timer); |
| queue_work(ts->himax_wq, &ts->work); |
| hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); |
| return HRTIMER_NORESTART; |
| } |
| |
| static irqreturn_t himax_ts_thread(int irq, void *ptr) |
| { |
| struct himax_ts_data *ts = ptr; |
| struct timespec timeStart, timeEnd, timeDelta; |
| if (ts->debug_log_level & BIT(2)) { |
| getnstimeofday(&timeStart); |
| /*I(" Irq start time = %ld.%06ld s\n", |
| timeStart.tv_sec, timeStart.tv_nsec/1000);*/ |
| } |
| #ifdef HX_SMART_WAKEUP |
| if (atomic_read(&ts->suspend_mode) && (!FAKE_POWER_KEY_SEND) && (ts->SMWP_enable)) { |
| wake_lock_timeout(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); |
| if (himax_parse_wake_event((struct himax_ts_data *)ptr)) { |
| ASUSEvtlog("[PM] GPIO triggered: %d\n", irq); |
| input_mt_slot(ts->input_dev,0); |
| input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); |
| input_report_abs(ts->input_dev, ABS_MT_POSITION_X, 1); |
| input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, 1); |
| input_sync(ts->input_dev); |
| input_mt_slot(ts->input_dev,0); |
| input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); |
| input_sync(ts->input_dev); |
| FAKE_POWER_KEY_SEND = true; |
| return IRQ_HANDLED; |
| } |
| } |
| #endif |
| himax_ts_work((struct himax_ts_data *)ptr); |
| if (ts->debug_log_level & BIT(2)) { |
| getnstimeofday(&timeEnd); |
| timeDelta.tv_nsec = (timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) |
| - (timeStart.tv_sec * 1000000000 + timeStart.tv_nsec); |
| /*I("Irq finish time = %ld.%06ld s\n", |
| timeEnd.tv_sec, timeEnd.tv_nsec/1000);*/ |
| I("Touch latency = %ld us\n", timeDelta.tv_nsec / 1000); |
| } |
| return IRQ_HANDLED; |
| } |
| |
| static void himax_ts_work_func(struct work_struct *work) |
| { |
| struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work); |
| himax_ts_work(ts); |
| } |
| |
| int himax_ts_register_interrupt(struct i2c_client *client) |
| { |
| struct himax_ts_data *ts = i2c_get_clientdata(client); |
| int ret = 0; |
| ts->irq_enabled = 0; |
| ts->use_irq = 0; |
| //Work functon |
| if (client->irq) {/*INT mode*/ |
| ts->use_irq = 1; |
| if (HX_INT_IS_EDGE) { |
| I("%s: edge trigger falling\n", __func__); |
| ret = request_threaded_irq(client->irq, NULL, himax_ts_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts); |
| } else { |
| I("%s: level trigger low\n", __func__); |
| ret = request_threaded_irq(client->irq, NULL, himax_ts_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts); |
| } |
| if (ret == 0) { |
| ts->irq_enabled = 1; |
| irq_enable_count = 1; |
| I("%s: irq register at qpio: %d\n", __func__, client->irq); |
| #ifdef HX_SMART_WAKEUP |
| irq_set_irq_wake(client->irq, 1); |
| #endif |
| } else { |
| E("%s: request_irq failed\n", __func__); |
| } |
| } else { |
| I("%s: client->irq is empty, use polling mode.\n", __func__); |
| } |
| if (!ts->use_irq) {/*if use polling mode need to disable HX_ESD_WORKAROUND function*/ |
| ts->himax_wq = create_singlethread_workqueue("himax_touch"); |
| INIT_WORK(&ts->work, himax_ts_work_func); |
| hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| ts->timer.function = himax_ts_timer_func; |
| hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); |
| I("%s: polling mode enabled\n", __func__); |
| } |
| return ret; |
| } |
| |
| #ifdef CONFIG_FB |
| static void himax_fb_register(struct work_struct *work) |
| { |
| int ret = 0; |
| struct himax_ts_data *ts = container_of(work, struct himax_ts_data, |
| work_att.work); |
| I("%s enter", __func__); |
| ts->fb_notif.notifier_call = fb_notifier_callback; |
| ret = fb_register_client(&ts->fb_notif); |
| if (ret) |
| E("Unable to register fb_notifier: %d\n", ret); |
| } |
| #endif |
| |
| //============================================================================================================= |
| // |
| // Segment : Himax SYS Debug Function |
| // |
| //============================================================================================================= |
| #ifdef CONFIG_TOUCHSCREEN_HIMAX_DEBUG |
| |
| static ssize_t himax_debug_level_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct himax_ts_data *ts_data; |
| ssize_t ret = 0; |
| ts_data = private_ts; |
| if (!HX_PROC_SEND_FLAG) { |
| ret += sprintf(buf, "%d\n", ts_data->debug_log_level); |
| HX_PROC_SEND_FLAG = 1; |
| } else |
| HX_PROC_SEND_FLAG = 0; |
| return ret; |
| } |
| |
| static ssize_t himax_debug_level_write(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| struct himax_ts_data *ts; |
| int i; |
| int len = strlen(buf); |
| if (len >= 12) { |
| E("%s: no command exceeds 12 chars.\n", __func__); |
| return -EFAULT; |
| } |
| ts = private_ts; |
| ts->debug_log_level = 0; |
| for (i = 0; i < len - 1; i++) { |
| if ( buf[i] >= '0' && buf[i] <= '9' ) |
| ts->debug_log_level |= (buf[i] - '0'); |
| else if ( buf[i] >= 'A' && buf[i] <= 'F' ) |
| ts->debug_log_level |= (buf[i] - 'A' + 10); |
| else if ( buf[i] >= 'a' && buf[i] <= 'f' ) |
| ts->debug_log_level |= (buf[i] - 'a' + 10); |
| if (i != len - 2) |
| ts->debug_log_level <<= 4; |
| } |
| if (ts->debug_log_level & BIT(3)) { |
| if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 && |
| (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 && |
| (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { |
| ts->widthFactor = (ts->pdata->screenWidth << SHIFTBITS) / (ts->pdata->abs_x_max - ts->pdata->abs_x_min); |
| ts->heightFactor = (ts->pdata->screenHeight << SHIFTBITS) / (ts->pdata->abs_y_max - ts->pdata->abs_y_min); |
| if (ts->widthFactor > 0 && ts->heightFactor > 0) |
| ts->useScreenRes = 1; |
| else { |
| ts->heightFactor = 0; |
| ts->widthFactor = 0; |
| ts->useScreenRes = 0; |
| } |
| } else |
| I("Enable finger debug with raw position mode!\n"); |
| } else { |
| ts->useScreenRes = 0; |
| ts->widthFactor = 0; |
| ts->heightFactor = 0; |
| } |
| return len; |
| } |
| |
| static ssize_t himax_vendor_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| ssize_t ret = 0; |
| struct himax_ts_data *ts_data; |
| ts_data = private_ts; |
| if (!HX_PROC_SEND_FLAG) { |
| ret += sprintf(buf, "%s_FW:%#x,%x_CFG:%#x_SensorId:%#x\n", HIMAX852xes_NAME, |
| ts_data->vendor_fw_ver_H, ts_data->vendor_fw_ver_L, ts_data->vendor_config_ver, ts_data->vendor_sensor_id); |
| HX_PROC_SEND_FLAG = 1; |
| } else |
| HX_PROC_SEND_FLAG = 0; |
| return ret; |
| } |
| |
| static ssize_t himax_attn_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| ssize_t ret = 0; |
| struct himax_ts_data *ts_data; |
| ts_data = private_ts; |
| if (!HX_PROC_SEND_FLAG) { |
| sprintf(buf, "attn = %x\n", himax_int_gpio_read(ts_data->pdata->gpio_irq)); |
| ret = strlen(buf) + 1; |
| HX_PROC_SEND_FLAG = 1; |
| } else |
| HX_PROC_SEND_FLAG = 0; |
| return ret; |
| } |
| |
| static ssize_t himax_int_en_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct himax_ts_data *ts = private_ts; |
| size_t ret = 0; |
| if (!HX_PROC_SEND_FLAG) { |
| ret += sprintf(buf + ret, "%d ", ts->irq_enabled); |
| ret += sprintf(buf + ret, "\n"); |
| HX_PROC_SEND_FLAG = 1; |
| } else |
| HX_PROC_SEND_FLAG = 0; |
| return ret; |
| } |
| |
| static ssize_t himax_int_en_write(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| struct himax_ts_data *ts = private_ts; |
| int value, ret = 0; |
| int len = strlen(buf); |
| if (len >= 12) { |
| I("%s: no command exceeds 12 chars.\n", __func__); |
| return -EFAULT; |
| } |
| if (buf[0] == '0') |
| value = false; |
| else if (buf[0] == '1') |
| value = true; |
| else |
| return -EINVAL; |
| if (value) { |
| if (HX_INT_IS_EDGE) { |
| ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, |
| IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->client->name, ts); |
| } else { |
| ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, |
| IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts); |
| } |
| if (ret == 0) { |
| ts->irq_enabled = 1; |
| irq_enable_count = 1; |
| } |
| } else { |
| himax_int_enable(ts->client->irq, 0, true); |
| free_irq(ts->client->irq, ts); |
| ts->irq_enabled = 0; |
| } |
| return len; |
| } |
| static ssize_t himax_layout_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct himax_ts_data *ts = private_ts; |
| size_t ret = 0; |
| if (!HX_PROC_SEND_FLAG) { |
| ret += sprintf(buf + ret, "%d ", ts->pdata->abs_x_min); |
| ret += sprintf(buf + ret, "%d ", ts->pdata->abs_x_max); |
| ret += sprintf(buf + ret, "%d ", ts->pdata->abs_y_min); |
| ret += sprintf(buf + ret, "%d ", ts->pdata->abs_y_max); |
| ret += sprintf(buf + ret, "\n"); |
| HX_PROC_SEND_FLAG = 1; |
| } else |
| HX_PROC_SEND_FLAG = 0; |
| return ret; |
| } |
| |
| static ssize_t himax_layout_write(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| struct himax_ts_data *ts = private_ts; |
| char buf_tmp[5]; |
| int i = 0, j = 0, k = 0, ret; |
| int len = strlen(buf); |
| unsigned long value; |
| int layout[4] = {0}; |
| if (len >= 80) { |
| E("%s: no command exceeds 80 chars.\n", __func__); |
| return -EFAULT; |
| } |
| for (i = 0; i < 20; i++) { |
| if (buf[i] == ',' || buf[i] == '\n') { |
| memset(buf_tmp, 0x0, sizeof(buf_tmp)); |
| if (i - j <= 5) |
| memcpy(buf_tmp, buf + j, i - j); |
| else { |
| I("buffer size is over 5 char\n"); |
| return len; |
| } |
| j = i + 1; |
| if (k < 4) { |
| ret = kstrtoul(buf_tmp, 10, &value); |
| layout[k++] = value; |
| } |
| } |
| } |
| if (k == 4) { |
| ts->pdata->abs_x_min = layout[0]; |
| ts->pdata->abs_x_max = layout[1]; |
| ts->pdata->abs_y_min = layout[2]; |
| ts->pdata->abs_y_max = layout[3]; |
| I("%d, %d, %d, %d\n", |
| ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); |
| input_unregister_device(ts->input_dev); |
| himax_input_register(ts); |
| } else |
| E("%s: %d, %d, %d, %d\n", __func__, |
| ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); |
| return len; |
| } |
| #ifdef HX_TP_PROC_RESET |
| static ssize_t himax_reset_write(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| int len = strlen(buf); |
| if (len >= 12) { |
| E("%s: no command exceeds 12 chars.\n", __func__); |
| return -EFAULT; |
| } |
| if (buf[0] == '1') |
| himax_HW_reset(true, false); |
| //else if (buf_tmp[0] == '2') |
| // himax_HW_reset(true,true); |
| //else if (buf_tmp[0] == '3') |
| // himax_HW_reset(false,true); |
| //else if (buf_tmp[0] == '4') |
| // ESD_HW_REST(); |
| return len; |
| } |
| #endif |
| |
| #ifdef HX_TP_PROC_DIAG |
| static uint8_t *getMutualBuffer(void) |
| { |
| return diag_mutual; |
| } |
| static uint8_t *getSelfBuffer(void) |
| { |
| return &diag_self[0]; |
| } |
| static uint8_t getXChannel(void) |
| { |
| return x_channel; |
| } |
| static uint8_t getYChannel(void) |
| { |
| return y_channel; |
| } |
| static uint8_t getDiagCommand(void) |
| { |
| return diag_command; |
| } |
| static void setXChannel(uint8_t x) |
| { |
| x_channel = x; |
| } |
| static void setYChannel(uint8_t y) |
| { |
| y_channel = y; |
| } |
| static void setMutualBuffer(void) |
| { |
| diag_mutual = kzalloc(x_channel * y_channel * sizeof(uint8_t), GFP_KERNEL); |
| } |
| |
| #ifdef HX_TP_PROC_2T2R |
| static uint8_t *getMutualBuffer_2(void) |
| { |
| return diag_mutual_2; |
| } |
| static uint8_t getXChannel_2(void) |
| { |
| return x_channel_2; |
| } |
| static uint8_t getYChannel_2(void) |
| { |
| return y_channel_2; |
| } |
| static void setXChannel_2(uint8_t x) |
| { |
| x_channel_2 = x; |
| } |
| static void setYChannel_2(uint8_t y) |
| { |
| y_channel_2 = y; |
| } |
| static void setMutualBuffer_2(void) |
| { |
| diag_mutual_2 = kzalloc(x_channel_2 * y_channel_2 * sizeof(uint8_t), GFP_KERNEL); |
| } |
| #endif |
| static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) |
| { |
| if (*pos >= 1) return NULL; |
| return (void *)((unsigned long) * pos + 1); |
| } |
| |
| static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) |
| { |
| return NULL; |
| } |
| static void himax_diag_seq_stop(struct seq_file *s, void *v) |
| { |
| } |
| static int himax_diag_seq_read(struct seq_file *s, void *v) |
| { |
| size_t count = 0; |
| uint32_t loop_i; |
| uint16_t mutual_num, self_num, width; |
| #ifdef HX_TP_PROC_2T2R |
| if (Is_2T2R && diag_command == 4) { |
| mutual_num = x_channel_2 * y_channel_2; |
| self_num = x_channel_2 + y_channel_2; //don't add KEY_COUNT |
| width = x_channel_2; |
| seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel_2, y_channel_2); |
| } else |
| #endif |
| { |
| mutual_num = x_channel * y_channel; |
| self_num = x_channel + y_channel; //don't add KEY_COUNT |
| width = x_channel; |
| seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel, y_channel); |
| } |
| // start to show out the raw data in adb shell |
| if (diag_command >= 1 && diag_command <= 6) { |
| if (diag_command <= 3) { |
| for (loop_i = 0; loop_i < mutual_num; loop_i++) { |
| seq_printf(s, "%4d", diag_mutual[loop_i]); |
| if ((loop_i % width) == (width - 1)) |
| seq_printf(s, " %3d\n", diag_self[width + loop_i / width]); |
| } |
| seq_printf(s, "\n"); |
| for (loop_i = 0; loop_i < width; loop_i++) { |
| seq_printf(s, "%4d", diag_self[loop_i]); |
| if (((loop_i) % width) == (width - 1)) |
| seq_printf(s, "\n"); |
| } |
| #ifdef HX_TP_PROC_2T2R |
| } else if (Is_2T2R && diag_command == 4 ) { |
| for (loop_i = 0; loop_i < mutual_num; loop_i++) { |
| seq_printf(s, "%4d", diag_mutual_2[loop_i]); |
| if ((loop_i % width) == (width - 1)) |
| seq_printf(s, " %3d\n", diag_self[width + loop_i / width]); |
| } |
| seq_printf(s, "\n"); |
| for (loop_i = 0; loop_i < width; loop_i++) { |
| seq_printf(s, "%4d", diag_self[loop_i]); |
| if (((loop_i) % width) == (width - 1)) |
| seq_printf(s, "\n"); |
| } |
| #endif |
| } else if (diag_command > 4) { |
| for (loop_i = 0; loop_i < self_num; loop_i++) { |
| seq_printf(s, "%4d", diag_self[loop_i]); |
| if (((loop_i - mutual_num) % width) == (width - 1)) |
| seq_printf(s, "\n"); |
| } |
| } else { |
| for (loop_i = 0; loop_i < mutual_num; loop_i++) { |
| seq_printf(s, "%4d", diag_mutual[loop_i]); |
| if ((loop_i % width) == (width - 1)) |
| seq_printf(s, "\n"); |
| } |
| } |
| seq_printf(s, "ChannelEnd"); |
| seq_printf(s, "\n"); |
| } else if (diag_command == 7) { |
| for (loop_i = 0; loop_i < 128 ; loop_i++) { |
| if ((loop_i % 16) == 0) |
| seq_printf(s, "LineStart:"); |
| seq_printf(s, "%4d", diag_coor[loop_i]); |
| if ((loop_i % 16) == 15) |
| seq_printf(s, "\n"); |
| } |
| } |
| return count; |
| } |
| |
| static struct seq_operations himax_diag_seq_ops = { |
| .start = himax_diag_seq_start, |
| .next = himax_diag_seq_next, |
| .stop = himax_diag_seq_stop, |
| .show = himax_diag_seq_read, |
| }; |
| static int himax_diag_proc_open(struct inode *inode, struct file *file) |
| { |
| return seq_open(file, &himax_diag_seq_ops); |
| }; |
| static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size_t len, loff_t *data) |
| { |
| const uint8_t command_ec_128_raw_flag = 0x02; |
| const uint8_t command_ec_24_normal_flag = 0x00; |
| uint8_t command_ec_128_raw_baseline_flag = 0x01; |
| uint8_t command_ec_128_raw_bank_flag = 0x03; |
| uint8_t command_F1h[2] = {0xF1, 0x00}; |
| char messages[80] = {0}; |
| if (len >= 80) { |
| E("%s: no command exceeds 80 chars.\n", __func__); |
| return -EFAULT; |
| } |
| if (copy_from_user(messages, buff, len)) { |
| return -EFAULT; |
| } |
| diag_command = messages[0] - '0'; |
| I("%s: diag_command=0x%x\n", __func__, diag_command); |
| if (diag_command == 0x01) {//DC |
| command_F1h[1] = command_ec_128_raw_baseline_flag; |
| i2c_himax_write(private_ts->client, command_F1h[0] , &command_F1h[1], 1, DEFAULT_RETRY_CNT); |
| } else if (diag_command == 0x02) {//IIR |
| command_F1h[1] = command_ec_128_raw_flag; |
| i2c_himax_write(private_ts->client, command_F1h[0] , &command_F1h[1], 1, DEFAULT_RETRY_CNT); |
| } else if (diag_command == 0x03) { //BANK |
| command_F1h[1] = command_ec_128_raw_bank_flag; //0x03 |
| i2c_himax_write(private_ts->client, command_F1h[0] , &command_F1h[1], 1, DEFAULT_RETRY_CNT); |
| } else if (diag_command == 0x04 ) { // 2T3R IIR |
| command_F1h[1] = 0x04; //2T3R IIR |
| i2c_himax_write(private_ts->client, command_F1h[0] , &command_F1h[1], 1, DEFAULT_RETRY_CNT); |
| } else if (diag_command == 0x00) {//Disable |
| command_F1h[1] = command_ec_24_normal_flag; |
| i2c_himax_write(private_ts->client, command_F1h[0] , &command_F1h[1], 1, DEFAULT_RETRY_CNT); |
| touch_monitor_stop_flag = touch_monitor_stop_limit; |
| } |
| //coordinate dump start |
| else if (diag_command == 0x08) { |
| coordinate_fn = filp_open(DIAG_COORDINATE_FILE, O_CREAT | O_WRONLY | O_APPEND | O_TRUNC, 0666); |
| if (IS_ERR(coordinate_fn)) { |
| E("%s: coordinate_dump_file_create error.\n", __func__); |
| coordinate_dump_enable = 0; |
| filp_close(coordinate_fn, NULL); |
| } |
| coordinate_dump_enable = 1; |
| } else if (diag_command == 0x09) { |
| coordinate_dump_enable = 0; |
| if (!IS_ERR(coordinate_fn)) { |
| filp_close(coordinate_fn, NULL); |
| } |
| } |
| //coordinate dump end |
| else { |
| E("%s: Diag command error! diag_command=0x%x\n", __func__ ,diag_command); |
| } |
| return len; |
| } |
| |
| static struct file_operations himax_proc_diag_ops = { |
| .owner = THIS_MODULE, |
| .open = himax_diag_proc_open, |
| .read = seq_read, |
| .write = himax_diag_write, |
| }; |
| #endif |
| |
| #ifdef HX_TP_PROC_REGISTER |
| static ssize_t himax_register_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| int ret = 0; |
| int base = 0; |
| uint16_t loop_i, loop_j; |
| uint8_t inData[128]; |
| uint8_t outData[5]; |
| memset(outData, 0x00, sizeof(outData)); |
| memset(inData, 0x00, sizeof(inData)); |
| I("Himax multi_register_command = %d \n", multi_register_command); |
| if (!HX_PROC_SEND_FLAG) { |
| if (multi_register_command == 1) { |
| base = 0; |
| for (loop_i = 0; loop_i < 6; loop_i++) { |
| if (multi_register[loop_i] != 0x00) { |
| if (multi_cfg_bank[loop_i] == 1) {//config bank register |
| outData[0] = 0x14; |
| i2c_himax_write(private_ts->client, 0x8C , &outData[0], 1, DEFAULT_RETRY_CNT); |
| msleep(10); |
| outData[0] = 0x00; |
| outData[1] = multi_register[loop_i]; |
| i2c_himax_write(private_ts->client, 0x8B , &outData[0], 2, DEFAULT_RETRY_CNT); |
| msleep(10); |
| i2c_himax_read(private_ts->client, 0x5A, inData, 128, DEFAULT_RETRY_CNT); |
| outData[0] = 0x00; |
| i2c_himax_write(private_ts->client, 0x8C , &outData[0], 1, DEFAULT_RETRY_CNT); |
| for (loop_j = 0; loop_j < 128; loop_j++) |
| multi_value[base++] = inData[loop_j]; |
| } else {//normal register |
| i2c_himax_read(private_ts->client, multi_register[loop_i], inData, 128, DEFAULT_RETRY_CNT); |
| for (loop_j = 0; loop_j < 128; loop_j++) |
| multi_value[base++] = inData[loop_j]; |
| } |
| } |
| } |
| base = 0; |
| for (loop_i = 0; loop_i < 6; loop_i++) { |
| if (multi_register[loop_i] != 0x00) { |
| if (multi_cfg_bank[loop_i] == 1) |
| ret += sprintf(buf + ret, "Register: FE(%x)\n", multi_register[loop_i]); |
| else |
| ret += sprintf(buf + ret, "Register: %x\n", multi_register[loop_i]); |
| for (loop_j = 0; loop_j < 128; loop_j++) { |
| ret += sprintf(buf + ret, "0x%2.2X ", multi_value[base++]); |
| if ((loop_j % 16) == 15) |
| ret += sprintf(buf + ret, "\n"); |
| } |
| } |
| } |
| return ret; |
| } |
| if (config_bank_reg) { |
| I("%s: register_command = FE(%x)\n", __func__, register_command); |
| //Config bank register read flow. |
| outData[0] = 0x14; |
| i2c_himax_write(private_ts->client, 0x8C, &outData[0], 1, DEFAULT_RETRY_CNT); |
| msleep(10); |
| outData[0] = 0x00; |
| outData[1] = register_command; |
| i2c_himax_write(private_ts->client, 0x8B, &outData[0], 2, DEFAULT_RETRY_CNT); |
| msleep(10); |
| i2c_himax_read(private_ts->client, 0x5A, inData, 128, DEFAULT_RETRY_CNT); |
| msleep(10); |
| outData[0] = 0x00; |
| i2c_himax_write(private_ts->client, 0x8C, &outData[0], 1, DEFAULT_RETRY_CNT); |
| } else { |
| if (i2c_himax_read(private_ts->client, register_command, inData, 128, DEFAULT_RETRY_CNT) < 0) |
| return ret; |
| } |
| if (config_bank_reg) |
| ret += sprintf(buf, "command: FE(%x)\n", register_command); |
| else |
| ret += sprintf(buf, "command: %x\n", register_command); |
| for (loop_i = 0; loop_i < 128; loop_i++) { |
| ret += sprintf(buf + ret, "0x%2.2X ", inData[loop_i]); |
| if ((loop_i % 16) == 15) |
| ret += sprintf(buf + ret, "\n"); |
| } |
| ret += sprintf(buf + ret, "\n"); |
| HX_PROC_SEND_FLAG = 1; |
| } else |
| HX_PROC_SEND_FLAG = 0; |
| return ret; |
| } |
| |
| static ssize_t himax_register_write(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| char buf_tmp[6], length = 0; |
| unsigned long result = 0; |
| uint8_t loop_i = 0; |
| uint16_t base = 5; |
| uint8_t write_da[128]; |
| uint8_t outData[5]; |
| int len = strlen(buf); |
| if (len >= 80) { |
| E("%s: no command exceeds 80 chars.\n", __func__); |
| return -EFAULT; |
| } |
| memset(buf_tmp, 0x0, sizeof(buf_tmp)); |
| memset(write_da, 0x0, sizeof(write_da)); |
| memset(outData, 0x0, sizeof(outData)); |
| I("himax %s \n", buf); |
| if (buf[0] == 'm' && buf[1] == 'r' && buf[2] == ':') { |
| memset(multi_register, 0x00, sizeof(multi_register)); |
| memset(multi_cfg_bank, 0x00, sizeof(multi_cfg_bank)); |
| memset(multi_value, 0x00, sizeof(multi_value)); |
| I("himax multi register enter\n"); |
| multi_register_command = 1; |
| base = 2; |
| loop_i = 0; |
| while (true) { |
| if (buf[base] == '\n') |
| break; |
| if (loop_i >= 6 ) |
| break; |
| if (buf[base] == ':' && buf[base + 1] == 'x' && buf[base + 2] == 'F' && |
| buf[base + 3] == 'E' && buf[base + 4] != ':') { |
| memcpy(buf_tmp, buf + base + 4, 2); |
| if (!kstrtoul(buf_tmp, 16, &result)) { |
| multi_register[loop_i] = result; |
| multi_cfg_bank[loop_i++] = 1; |
| } |
| base += 6; |
| } else { |
| memcpy(buf_tmp, buf + base + 2, 2); |
| if (!kstrtoul(buf_tmp, 16, &result)) { |
| multi_register[loop_i] = result; |
| multi_cfg_bank[loop_i++] = 0; |
| } |
| base += 4; |
| } |
| } |
| I("========================== \n"); |
| for (loop_i = 0; loop_i < 6; loop_i++) |
| I("%d,%d:", multi_register[loop_i], multi_cfg_bank[loop_i]); |
| I("\n"); |
| } else if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') { |
| multi_register_command = 0; |
| if (buf[2] == 'x') { |
| if (buf[3] == 'F' && buf[4] == 'E') {//Config bank register |
| config_bank_reg = true; |
| memcpy(buf_tmp, buf + 5, 2); |
| if (!kstrtoul(buf_tmp, 16, &result)) |
| register_command = result; |
| base = 7; |
| I("CMD: FE(%x)\n", register_command); |
| } else { |
| config_bank_reg = false; |
| memcpy(buf_tmp, buf + 3, 2); |
| if (!kstrtoul(buf_tmp, 16, &result)) |
| register_command = result; |
| base = 5; |
| I("CMD: %x\n", register_command); |
| } |
| for (loop_i = 0; loop_i < 128; loop_i++) { |
| if (buf[base] == '\n') { |
| if (buf[0] == 'w') { |
| if (config_bank_reg) { |
| outData[0] = 0x14; |
| i2c_himax_write(private_ts->client, 0x8C, &outData[0], 1, DEFAULT_RETRY_CNT); |
| msleep(10); |
| outData[0] = 0x00; |
| outData[1] = register_command; |
| i2c_himax_write(private_ts->client, 0x8B, &outData[0], 2, DEFAULT_RETRY_CNT); |
| msleep(10); |
| i2c_himax_write(private_ts->client, 0x40, &write_da[0], length, DEFAULT_RETRY_CNT); |
| msleep(10); |
| outData[0] = 0x00; |
| i2c_himax_write(private_ts->client, 0x8C, &outData[0], 1, DEFAULT_RETRY_CNT); |
| I("CMD: FE(%x), %x, %d\n", register_command, write_da[0], length); |
| } else { |
| i2c_himax_write(private_ts->client, register_command, &write_da[0], length, DEFAULT_RETRY_CNT); |
| I("CMD: %x, %x, %d\n", register_command, write_da[0], length); |
| } |
| } |
| I("\n"); |
| return len; |
| } |
| if (buf[base + 1] == 'x') { |
| buf_tmp[4] = '\n'; |
| buf_tmp[5] = '\0'; |
| memcpy(buf_tmp, buf + base + 2, 2); |
| if (!kstrtoul(buf_tmp, 16, &result)) { |
| write_da[loop_i] = result; |
| } |
| length++; |
| } |
| base += 4; |
| } |
| } |
| } |
| return len; |
| } |
| #endif |
| |
| #ifdef HX_TP_PROC_DEBUG |
| static ssize_t himax_debug_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| size_t ret = 0; |
| if (!HX_PROC_SEND_FLAG) { |
| if (debug_level_cmd == 't') { |
| if (fw_update_complete) { |
| ret += sprintf(buf, "FW Update Complete "); |
| } else { |
| ret += sprintf(buf, "FW Update Fail "); |
| } |
| } else if (debug_level_cmd == 'h') { |
| if (handshaking_result == 0) { |
| ret += sprintf(buf, "Handshaking Result = %d (MCU Running)\n", handshaking_result); |
| } else if (handshaking_result == 1) { |
| ret += sprintf(buf, "Handshaking Result = %d (MCU Stop)\n", handshaking_result); |
| } else if (handshaking_result == 2) { |
| ret += sprintf(buf, "Handshaking Result = %d (I2C Error)\n", handshaking_result); |
| } else { |
| ret += sprintf(buf, "Handshaking Result = error \n"); |
| } |
| } else if (debug_level_cmd == 'v') { |
| ret += sprintf(buf + ret, "FW_VER = "); |
| ret += sprintf(buf + ret, "0x%2.2X, %2.2X \n", private_ts->vendor_fw_ver_H, private_ts->vendor_fw_ver_L); |
| ret += sprintf(buf + ret, "CONFIG_VER = "); |
| ret += sprintf(buf + ret, "0x%2.2X \n", private_ts->vendor_config_ver); |
| ret += sprintf(buf + ret, "\n"); |
| } else if (debug_level_cmd == 'd') { |
| ret += sprintf(buf + ret, "Himax Touch IC Information :\n"); |
| if (IC_TYPE == HX_85XX_D_SERIES_PWON) { |
| ret += sprintf(buf + ret, "IC Type : D\n"); |
| } else if (IC_TYPE == HX_85XX_E_SERIES_PWON) { |
| ret += sprintf(buf + ret, "IC Type : E\n"); |
| } else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) { |
| ret += sprintf(buf + ret, "IC Type : ES\n"); |
| } else { |
| ret += sprintf(buf + ret, "IC Type error.\n"); |
| } |
| if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) { |
| ret += sprintf(buf + ret, "IC Checksum : SW\n"); |
| } else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) { |
| ret += sprintf(buf + ret, "IC Checksum : HW\n"); |
| } else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) { |
| ret += sprintf(buf + ret, "IC Checksum : CRC\n"); |
| } else { |
| ret += sprintf(buf + ret, "IC Checksum error.\n"); |
| } |
| if (HX_INT_IS_EDGE) { |
| ret += sprintf(buf + ret, "Interrupt : EDGE TIRGGER\n"); |
| } else { |
| ret += sprintf(buf + ret, "Interrupt : LEVEL TRIGGER\n"); |
| } |
| ret += sprintf(buf + ret, "RX Num : %d\n", HX_RX_NUM); |
| ret += sprintf(buf + ret, "TX Num : %d\n", HX_TX_NUM); |
| ret += sprintf(buf + ret, "BT Num : %d\n", HX_BT_NUM); |
| ret += sprintf(buf + ret, "X Resolution : %d\n", HX_X_RES); |
| ret += sprintf(buf + ret, "Y Resolution : %d\n", HX_Y_RES); |
| ret += sprintf(buf + ret, "Max Point : %d\n", HX_MAX_PT); |
| #ifdef HX_TP_PROC_2T2R |
| if (Is_2T2R) { |
| ret += sprintf(buf + ret, "2T2R panel\n"); |
| ret += sprintf(buf + ret, "RX Num_2 : %d\n", HX_RX_NUM_2); |
| ret += sprintf(buf + ret, "TX Num_2 : %d\n", HX_TX_NUM_2); |
| } |
| #endif |
| } else if (debug_level_cmd == 'i') { |
| ret += sprintf(buf + ret, "Himax Touch Driver Version:\n"); |
| ret += sprintf(buf + ret, "%s \n", HIMAX_DRIVER_VER); |
| } |
| HX_PROC_SEND_FLAG = 1; |
| } else |
| HX_PROC_SEND_FLAG = 0; |
| return ret; |
| } |
| |
| static ssize_t himax_debug_write(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| struct file *hx_filp = NULL; |
| mm_segment_t oldfs; |
| int result = 0; |
| int len = strlen(buf); |
| char fileName[128]; |
| if (len >= 80) { |
| E("%s: no command exceeds 80 chars.\n", __func__); |
| return -EFAULT; |
| } |
| if ( buf[0] == 'h') { //handshaking |
| debug_level_cmd = buf[0]; |
| himax_int_enable(private_ts->client->irq, 0, true); |
| handshaking_result = himax_hand_shaking(); //0:Running, 1:Stop, 2:I2C Fail |
| himax_int_enable(private_ts->client->irq, 1, true); |
| return len; |
| } else if ( buf[0] == 'v') { //firmware version |
| debug_level_cmd = buf[0]; |
| himax_read_FW_ver(true); |
| return len; |
| } else if ( buf[0] == 'd') { //test |
| debug_level_cmd = buf[0]; |
| return len; |
| } else if ( buf[0] == 'i') { //driver version |
| debug_level_cmd = buf[0]; |
| return len; |
| } else if (buf[0] == 't') { |
| himax_int_enable(private_ts->client->irq, 0, true); |
| wake_lock(&private_ts->ts_flash_wake_lock); |
| #ifdef HX_CHIP_STATUS_MONITOR |
| HX_CHIP_POLLING_COUNT = 0; |
| cancel_delayed_work_sync(&private_ts->himax_chip_monitor); |
| #endif |
| debug_level_cmd = buf[0]; |
| fw_update_complete = false; |
| memset(fileName, 0, 128); |
| // parse the file name |
| snprintf(fileName, len - 2, "%s", &buf[2]); |
| I("%s: upgrade from file(%s) start!\n", __func__, fileName); |
| // open file |
| hx_filp = filp_open(fileName, O_RDONLY, 0); |
| if (IS_ERR(hx_filp)) { |
| E("%s: open firmware file failed.\n", __func__); |
| goto firmware_upgrade_done; |
| //return len; |
| } |
| oldfs = get_fs(); |
| set_fs(get_ds()); |
| // read the latest firmware binary file |
| result = hx_filp->f_op->read(hx_filp, upgrade_fw, sizeof(upgrade_fw), &hx_filp->f_pos); |
| if (result < 0) { |
| E("%s: read firmware file failed.\n", __func__); |
| goto firmware_upgrade_done; |
| //return len; |
| } |
| set_fs(oldfs); |
| filp_close(hx_filp, NULL); |
| I("%s: upgrade start,len %d: %02X, %02X, %02X, %02X\n", __func__, result, upgrade_fw[0], upgrade_fw[1], upgrade_fw[2], upgrade_fw[3]); |
| if (result > 0) { |
| // start to upgrade |
| #ifdef HX_RST_PIN_FUNC |
| himax_HW_reset(false, true); |
| #endif |
| if (fts_ctpm_fw_upgrade_with_fs(upgrade_fw, result, true) == 0) { |
| E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); |
| fw_update_complete = false; |
| } else { |
| I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); |
| fw_update_complete = true; |
| } |
| goto firmware_upgrade_done; |
| //return len; |
| } |
| } |
| firmware_upgrade_done: |
| #ifdef HX_RST_PIN_FUNC |
| himax_HW_reset(true, true); |
| #endif |
| wake_unlock(&private_ts->ts_flash_wake_lock); |
| himax_int_enable(private_ts->client->irq, 1, true); |
| #ifdef HX_CHIP_STATUS_MONITOR |
| HX_CHIP_POLLING_COUNT = 0; |
| queue_delayed_work(private_ts->himax_chip_monitor_wq, &private_ts->himax_chip_monitor, HX_POLLING_TIMES * HZ); |
| #endif |
| //todo himax_chip->tp_firmware_upgrade_proceed = 0; |
| //todo himax_chip->suspend_state = 0; |
| //todo enable_irq(himax_chip->irq); |
| return len; |
| } |
| #endif |
| |
| #ifdef HX_TP_PROC_FLASH_DUMP |
| |
| static uint8_t getFlashCommand(void) |
| { |
| return flash_command; |
| } |
| |
| static uint8_t getFlashDumpProgress(void) |
| { |
| return flash_progress; |
| } |
| |
| static uint8_t getFlashDumpComplete(void) |
| { |
| return flash_dump_complete; |
| } |
| |
| static uint8_t getFlashDumpFail(void) |
| { |
| return flash_dump_fail; |
| } |
| |
| static uint8_t getSysOperation(void) |
| { |
| return sys_operation; |
| } |
| |
| static uint8_t getFlashReadStep(void) |
| { |
| return flash_read_step; |
| } |
| |
| static uint8_t getFlashDumpSector(void) |
| { |
| return flash_dump_sector; |
| } |
| |
| static uint8_t getFlashDumpPage(void) |
| { |
| return flash_dump_page; |
| } |
| |
| static bool getFlashDumpGoing(void) |
| { |
| return flash_dump_going; |
| } |
| |
| static void setFlashBuffer(void) |
| { |
| //int i=0; |
| flash_buffer = kzalloc(FLASH_SIZE * sizeof(uint8_t), GFP_KERNEL); |
| memset(flash_buffer, 0x00, FLASH_SIZE); |
| //for(i=0; i<FLASH_SIZE; i++) |
| //{ |
| // flash_buffer[i] = 0x00; |
| //} |
| } |
| |
| static void setSysOperation(uint8_t operation) |
| { |
| sys_operation = operation; |
| } |
| |
| static void setFlashDumpProgress(uint8_t progress) |
| { |
| flash_progress = progress; |
| //I("setFlashDumpProgress : progress = %d ,flash_progress = %d \n",progress,flash_progress); |
| } |
| |
| static void setFlashDumpComplete(uint8_t status) |
| { |
| flash_dump_complete = status; |
| } |
| |
| static void setFlashDumpFail(uint8_t fail) |
| { |
| flash_dump_fail = fail; |
| } |
| |
| static void setFlashCommand(uint8_t command) |
| { |
| flash_command = command; |
| } |
| |
| static void setFlashReadStep(uint8_t step) |
| { |
| flash_read_step = step; |
| } |
| |
| static void setFlashDumpSector(uint8_t sector) |
| { |
| flash_dump_sector = sector; |
| } |
| |
| static void setFlashDumpPage(uint8_t page) |
| { |
| flash_dump_page = page; |
| } |
| |
| static void setFlashDumpGoing(bool going) |
| { |
| flash_dump_going = going; |
| } |
| |
| static void himax_ts_flash_work_func(struct work_struct *work) |
| { |
| struct himax_ts_data *ts = container_of(work, struct himax_ts_data, flash_work); |
| uint8_t page_tmp[128]; |
| uint8_t x59_tmp[4] = {0, 0, 0, 0}; |
| int i = 0, j = 0, k = 0, l = 0,/* j_limit = 0,*/ buffer_ptr = 0/*, flash_end_count = 0*/; |
| uint8_t local_flash_command = 0; |
| uint8_t sector = 0; |
| uint8_t page = 0; |
| /*uint8_t xAA_command[2] = {0xAA,0x00};*/ |
| uint8_t x81_command[2] = {HX_CMD_TSSLPOUT, 0x00}; |
| uint8_t x82_command[2] = {HX_CMD_TSSOFF, 0x00}; |
| uint8_t x35_command[2] = {HX_CMD_SETMICROOFF, 0x00}; |
| uint8_t x43_command[4] = {HX_CMD_FLASH_ENABLE, 0x00, 0x00, 0x00}; |
| uint8_t x44_command[4] = {HX_CMD_FLASH_SET_ADDRESS, 0x00, 0x00, 0x00}; |
| uint8_t x45_command[5] = {HX_CMD_FLASH_WRITE_REGISTER, 0x00, 0x00, 0x00, 0x00}; |
| uint8_t x46_command[2] = {0x46, 0x00}; |
| /*uint8_t x4A_command[2] = {HX_CMD_4A,0x00};*/ |
| uint8_t x4D_command[2] = {0x4D, 0x00}; |
| /*uint8_t x59_command[2] = {0x59,0x00};*/ |
| himax_int_enable(private_ts->client->irq, 0, true); |
| #ifdef HX_CHIP_STATUS_MONITOR |
| HX_CHIP_POLLING_COUNT = 0; |
| cancel_delayed_work_sync(&private_ts->himax_chip_monitor); |
| #endif |
| setFlashDumpGoing(true); |
| sector = getFlashDumpSector(); |
| page = getFlashDumpPage(); |
| local_flash_command = getFlashCommand(); |
| #ifdef HX_RST_PIN_FUNC |
| if (local_flash_command < 0x0F) |
| himax_HW_reset(false, true); |
| #endif |
| //if( i2c_himax_master_write(ts->client, xAA_command, 1, 3) < 0 )//sleep out |
| //{ |
| // E("%s i2c write AA fail.\n",__func__); |
| // goto Flash_Dump_i2c_transfer_error; |
| //} |
| //msleep(120); |
| if ( i2c_himax_master_write(ts->client, x81_command, 1, 3) < 0 ) { //sleep out |
| E("%s i2c write 81 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(120); |
| if ( i2c_himax_master_write(ts->client, x82_command, 1, 3) < 0 ) { |
| E("%s i2c write 82 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(100); |
| I("%s: local_flash_command = %d enter.\n", __func__, local_flash_command); |
| if ((local_flash_command == 1 || local_flash_command == 2) || (local_flash_command == 0x0F)) { |
| x43_command[1] = 0x01; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 1, DEFAULT_RETRY_CNT) < 0) { |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(100); |
| for ( i = 0 ; i < 8 ; i++) { |
| for (j = 0 ; j < 32 ; j++) { |
| //I(" Step 2 i=%d , j=%d %s\n",i,j,__func__); |
| //read page start |
| for (k = 0; k < 128; k++) { |
| page_tmp[k] = 0x00; |
| } |
| for (k = 0; k < 32; k++) { |
| x44_command[1] = k; |
| x44_command[2] = j; |
| x44_command[3] = i; |
| if ( i2c_himax_write(ts->client, x44_command[0], &x44_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 44 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| if ( i2c_himax_write_command(ts->client, x46_command[0], DEFAULT_RETRY_CNT) < 0) { |
| E("%s i2c write 46 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| //msleep(2); |
| if ( i2c_himax_read(ts->client, 0x59, x59_tmp, 4, DEFAULT_RETRY_CNT) < 0) { |
| E("%s i2c write 59 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| //msleep(2); |
| for (l = 0; l < 4; l++) { |
| page_tmp[k * 4 + l] = x59_tmp[l]; |
| } |
| //msleep(10); |
| } |
| //read page end |
| for (k = 0; k < 128; k++) { |
| flash_buffer[buffer_ptr++] = page_tmp[k]; |
| } |
| setFlashDumpProgress(i * 32 + j); |
| } |
| } |
| } else if (local_flash_command == 3) { |
| x43_command[1] = 0x01; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 1, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(100); |
| for (i = 0; i < 128; i++) { |
| page_tmp[i] = 0x00; |
| } |
| for (i = 0; i < 32; i++) { |
| x44_command[1] = i; |
| x44_command[2] = page; |
| x44_command[3] = sector; |
| if ( i2c_himax_write(ts->client, x44_command[0], &x44_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 44 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| if ( i2c_himax_write_command(ts->client, x46_command[0], DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 46 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| //msleep(2); |
| if ( i2c_himax_read(ts->client, 0x59, x59_tmp, 4, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 59 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| //msleep(2); |
| for (j = 0; j < 4; j++) { |
| page_tmp[i * 4 + j] = x59_tmp[j]; |
| } |
| //msleep(10); |
| } |
| //read page end |
| for (i = 0; i < 128; i++) { |
| flash_buffer[buffer_ptr++] = page_tmp[i]; |
| } |
| } else if (local_flash_command == 4) { |
| //page write flow. |
| //I("%s: local_flash_command = 4, enter.\n", __func__); |
| // unlock flash |
| himax_lock_flash(0); |
| msleep(50); |
| // page erase |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x00; |
| x43_command[3] = 0x02; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| x44_command[1] = 0x00; |
| x44_command[2] = page; |
| x44_command[3] = sector; |
| if ( i2c_himax_write(ts->client, x44_command[0], &x44_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 44 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| if ( i2c_himax_write_command(ts->client, x4D_command[0], DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 4D fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(100); |
| // enter manual mode |
| x35_command[1] = 0x01; |
| if ( i2c_himax_write(ts->client, x35_command[0], &x35_command[1], 1, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 35 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(100); |
| // flash enable |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x00; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| // set flash address |
| x44_command[1] = 0x00; |
| x44_command[2] = page; |
| x44_command[3] = sector; |
| if ( i2c_himax_write(ts->client, x44_command[0], &x44_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 44 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| // manual mode command : 47 to latch the flash address when page address change. |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x09; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x0D; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x09; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| for (i = 0; i < 32; i++) { |
| I("himax :i=%d \n", i); |
| x44_command[1] = i; |
| x44_command[2] = page; |
| x44_command[3] = sector; |
| if ( i2c_himax_write(ts->client, x44_command[0], &x44_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 44 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| x45_command[1] = flash_buffer[i * 4 + 0]; |
| x45_command[2] = flash_buffer[i * 4 + 1]; |
| x45_command[3] = flash_buffer[i * 4 + 2]; |
| x45_command[4] = flash_buffer[i * 4 + 3]; |
| if ( i2c_himax_write(ts->client, x45_command[0], &x45_command[1], 4, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 45 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| // manual mode command : 48 ,data will be written into flash buffer |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x0D; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x09; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| } |
| // manual mode command : 49 ,program data from flash buffer to this page |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x01; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x05; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x01; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| x43_command[1] = 0x01; |
| x43_command[2] = 0x00; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| // flash disable |
| x43_command[1] = 0x00; |
| if ( i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 1, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 43 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| // leave manual mode |
| x35_command[1] = 0x01; |
| if ( i2c_himax_write(ts->client, x35_command[0], &x35_command[1], 1, DEFAULT_RETRY_CNT) < 0 ) { |
| E("%s i2c write 35 fail.\n", __func__); |
| goto Flash_Dump_i2c_transfer_error; |
| } |
| msleep(10); |
| // lock flash |
| himax_lock_flash(1); |
| msleep(50); |
| buffer_ptr = 128; |
| I("Himax: Flash page write Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); |
| } |
| I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); |
| if (local_flash_command == 0x01) { |
| I(" buffer_ptr = %d \n", buffer_ptr); |
| for (i = 0; i < buffer_ptr; i++) { |
| I("%2.2X ", flash_buffer[i]); |
| if ((i % 16) == 15) { |
| I("\n"); |
| } |
| } |
| I("End~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); |
| } |
| i2c_himax_master_write(ts->client, x43_command, 1, 3); |
| msleep(50); |
| if (local_flash_command == 2) { |
| struct file *fn; |
| fn = filp_open(FLASH_DUMP_FILE, O_CREAT | O_WRONLY , 0); |
| if (!IS_ERR(fn)) { |
| fn->f_op->write(fn, flash_buffer, buffer_ptr * sizeof(uint8_t), &fn->f_pos); |
| filp_close(fn, NULL); |
| } |
| } |
| #ifdef HX_RST_PIN_FUNC |
| if (local_flash_command < 0x0F) |
| himax_HW_reset(true, true); |
| #endif |
| himax_int_enable(private_ts->client->irq, 1, true); |
| #ifdef HX_CHIP_STATUS_MONITOR |
| HX_CHIP_POLLING_COUNT = 0; |
| queue_delayed_work(private_ts->himax_chip_monitor_wq, &private_ts->himax_chip_monitor, HX_POLLING_TIMES * HZ); |
| #endif |
| setFlashDumpGoing(false); |
| setFlashDumpComplete(1); |
| setSysOperation(0); |
| return; |
| Flash_Dump_i2c_transfer_error: |
| #ifdef HX_RST_PIN_FUNC |
| himax_HW_reset(true, true); |
| #endif |
| himax_int_enable(private_ts->client->irq, 1, true); |
| #ifdef HX_CHIP_STATUS_MONITOR |
| HX_CHIP_POLLING_COUNT = 0; |
| queue_delayed_work(private_ts->himax_chip_monitor_wq, &private_ts->himax_chip_monitor, HX_POLLING_TIMES * HZ); |
| #endif |
| setFlashDumpGoing(false); |
| setFlashDumpComplete(0); |
| setFlashDumpFail(1); |
| setSysOperation(0); |
| return; |
| } |
| |
| static ssize_t himax_flash_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| int ret = 0; |
| int loop_i; |
| uint8_t local_flash_read_step = 0; |
| uint8_t local_flash_complete = 0; |
| uint8_t local_flash_progress = 0; |
| uint8_t local_flash_command = 0; |
| uint8_t local_flash_fail = 0; |
| local_flash_complete = getFlashDumpComplete(); |
| local_flash_progress = getFlashDumpProgress(); |
| local_flash_command = getFlashCommand(); |
| local_flash_fail = getFlashDumpFail(); |
| I("flash_progress = %d\n", local_flash_progress); |
| if (!HX_PROC_SEND_FLAG) { |
| if (local_flash_fail) { |
| ret += sprintf(buf + ret, "FlashStart:Fail \n"); |
| ret += sprintf(buf + ret, "FlashEnd"); |
| ret += sprintf(buf + ret, "\n"); |
| HX_PROC_SEND_FLAG = 1; |
| return ret; |
| } |
| if (!local_flash_complete) { |
| ret += sprintf(buf + ret, "FlashStart:Ongoing:0x%2.2x \n", flash_progress); |
| ret += sprintf(buf + ret, "FlashEnd"); |
| ret += sprintf(buf + ret, "\n"); |
| HX_PROC_SEND_FLAG = 1; |
| return ret; |
| } |
| if (local_flash_command == 1 && local_flash_complete) { |
| ret += sprintf(buf + ret, "FlashStart:Complete \n"); |
| ret += sprintf(buf + ret, "FlashEnd"); |
| ret += sprintf(buf + ret, "\n"); |
| HX_PROC_SEND_FLAG = 1; |
| return ret; |
| } |
| if (local_flash_command == 3 && local_flash_complete) { |
| ret += sprintf(buf + ret, "FlashStart: \n"); |
| for (loop_i = 0; loop_i < 128; loop_i++) { |
| ret += sprintf(buf + ret, "x%2.2x", flash_buffer[loop_i]); |
| if ((loop_i % 16) == 15) { |
| ret += sprintf(buf + ret, "\n"); |
| } |
| } |
| ret += sprintf(buf + ret, "FlashEnd"); |
| ret += sprintf(buf + ret, "\n"); |
| HX_PROC_SEND_FLAG = 1; |
| return ret; |
| } |
| //flash command == 0 , report the data |
| local_flash_read_step = getFlashReadStep(); |
| ret += sprintf(buf + ret, "FlashStart:%2.2x \n", local_flash_read_step); |
| for (loop_i = 0; loop_i < 1024; loop_i++) { |
| ret += sprintf(buf + ret, "x%2.2X", flash_buffer[local_flash_read_step * 1024 + loop_i]); |
| if ((loop_i % 16) == 15) { |
| ret += sprintf(buf + ret, "\n"); |
| } |
| } |
| ret += sprintf(buf + ret, "FlashEnd"); |
| ret += sprintf(buf + ret, "\n"); |
| HX_PROC_SEND_FLAG = 1; |
| } else |
| HX_PROC_SEND_FLAG = 0; |
| return ret; |
| } |
| |
| static ssize_t himax_flash_write(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| char buf_tmp[6]; |
| unsigned long result = 0; |
| uint8_t loop_i = 0; |
| int base = 0; |
| int len = strlen(buf); |
| if (len >= 80) { |
| I("%s: no command exceeds 80 chars.\n", __func__); |
| return -EFAULT; |
| } |
| memset(buf_tmp, 0x0, sizeof(buf_tmp)); |
| I("%s: buf[0] = %s\n", __func__, buf); |
| if (getSysOperation() == 1) { |
| E("%s: SYS is busy , return!\n", __func__); |
| return len; |
| } |
| if (buf[0] == '0') { |
| setFlashCommand(0); |
| if (buf[1] == ':' && buf[2] == 'x') { |
| memcpy(buf_tmp, buf + 3, 2); |
| I("%s: read_Step = %s\n", __func__, buf_tmp); |
| if (!kstrtoul(buf_tmp, 16, &result)) { |
| I("%s: read_Step = %lu \n", __func__, result); |
| setFlashReadStep(result); |
| } |
| } |
| } else if (buf[0] == '1') { |
| setSysOperation(1); |
| setFlashCommand(1); |
| setFlashDumpProgress(0); |
| setFlashDumpComplete(0); |
| setFlashDumpFail(0); |
| queue_work(private_ts->flash_wq, &private_ts->flash_work); |
| } else if (buf[0] == '2') { |
| setSysOperation(1); |
| setFlashCommand(2); |
| setFlashDumpProgress(0); |
| setFlashDumpComplete(0); |
| setFlashDumpFail(0); |
| queue_work(private_ts->flash_wq, &private_ts->flash_work); |
| } else if (buf[0] == '3') { |
| setSysOperation(1); |
| setFlashCommand(3); |
| setFlashDumpProgress(0); |
| setFlashDumpComplete(0); |
| setFlashDumpFail(0); |
| memcpy(buf_tmp, buf + 3, 2); |
| if (!kstrtoul(buf_tmp, 16, &result)) { |
| setFlashDumpSector(result); |
| } |
| memcpy(buf_tmp, buf + 7, 2); |
| if (!kstrtoul(buf_tmp, 16, &result)) { |
| setFlashDumpPage(result); |
| } |
| queue_work(private_ts->flash_wq, &private_ts->flash_work); |
| } else if (buf[0] == '4') { |
| I("%s: command 4 enter.\n", __func__); |
| setSysOperation(1); |
| setFlashCommand(4); |
| setFlashDumpProgress(0); |
| setFlashDumpComplete(0); |
| setFlashDumpFail(0); |
| memcpy(buf_tmp, buf + 3, 2); |
| if (!kstrtoul(buf_tmp, 16, &result)) { |
| setFlashDumpSector(result); |
| } else { |
| E("%s: command 4, sector error.\n", __func__); |
| return len; |
| } |
| memcpy(buf_tmp, buf + 7, 2); |
| if (!kstrtoul(buf_tmp, 16, &result)) { |
| setFlashDumpPage(result); |
| } else { |
| E("%s: command 4, page error.\n", __func__); |
| return len; |
| } |
| base = 11; |
| I("=========Himax flash page buffer start=========\n"); |
| for (loop_i = 0; loop_i < 128; loop_i++) { |
| memcpy(buf_tmp, buf + base, 2); |
| if (!kstrtoul(buf_tmp, 16, &result)) { |
| flash_buffer[loop_i] = result; |
| I("%d ", flash_buffer[loop_i]); |
| if (loop_i % 16 == 15) { |
| I("\n"); |
| } |
| } |
| base += 3; |
| } |
| I("=========Himax flash page buffer end=========\n"); |
| queue_work(private_ts->flash_wq, &private_ts->flash_work); |
| } |
| return len; |
| } |
| #endif |
| |
| #ifdef HX_TP_PROC_SELF_TEST |
| static int himax_chip_self_test(void) |
| { |
| uint8_t cmdbuf[11]; |
| uint8_t valuebuf[16]; |
| int i = 0, pf_value = 0x00; |
| memset(cmdbuf, 0x00, sizeof(cmdbuf)); |
| memset(valuebuf, 0x00, sizeof(valuebuf)); |
| cmdbuf[0] = 0x06; |
| i2c_himax_write(private_ts->client, 0xF1, &cmdbuf[0], 1, DEFAULT_RETRY_CNT); |
| msleep(120); |
| i2c_himax_write(private_ts->client, HX_CMD_TSSON, &cmdbuf[0], 0, DEFAULT_RETRY_CNT); |
| msleep(120); |
| i2c_himax_write(private_ts->client, HX_CMD_TSSLPOUT, &cmdbuf[0], 0, DEFAULT_RETRY_CNT); |
| msleep(2000); |
| i2c_himax_write(private_ts->client, HX_CMD_TSSOFF, &cmdbuf[0], 0, DEFAULT_RETRY_CNT); |
| msleep(120); |
| i2c_himax_write(private_ts->client, HX_CMD_TSSLPIN, &cmdbuf[0], 0, DEFAULT_RETRY_CNT); |
| msleep(120); |
| cmdbuf[0] = 0x00; |
| i2c_himax_write(private_ts->client, 0xF1, &cmdbuf[0], 1, DEFAULT_RETRY_CNT); |
| msleep(120); |
| i2c_himax_read(private_ts->client, 0xB1, valuebuf, 8, DEFAULT_RETRY_CNT); |
| msleep(10); |
| for (i = 0; i < 8; i++) { |
| I("After slf test 0xB1 buff_back[%d] = 0x%x\n", i, valuebuf[i]); |
| } |
| msleep(30); |
| if (valuebuf[0] == 0xAA) { |
| I("self-test pass\n"); |
| pf_value = 0x0; |
| } else { |
| E("self-test fail\n"); |
| pf_value = 0x1; |
| } |
| return pf_value; |
| } |
| |
| static ssize_t himax_self_test_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| int val = 0x00; |
| int ret = 0; |
| val = himax_chip_self_test(); |
| if (!HX_PROC_SEND_FLAG) { |
| if (val == 0x00) { |
| ret += sprintf(buf + ret, "Self_Test Pass\n"); |
| } else { |
| ret += sprintf(buf + ret, "Self_Test Fail\n"); |
| } |
| HX_PROC_SEND_FLAG = 1; |
| } else |
| HX_PROC_SEND_FLAG = 0; |
| return ret; |
| } |
| #endif |
| |
| #ifdef HX_TP_PROC_HITOUCH |
| static ssize_t himax_hitouch_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| int ret = 0; |
| if (!HX_PROC_SEND_FLAG) { |
| if (hitouch_command == 0) { |
| ret += sprintf(buf + ret, "Himax Touch Driver Version:\n"); |
| ret += sprintf(buf + ret, "%s \n", HIMAX_DRIVER_VER); |
| } else if (hitouch_command == 1) { |
| ret += sprintf(buf + ret, "hitouch_is_connect = true\n"); |
| } else if (hitouch_command == 2) { |
| ret += sprintf(buf + ret, "hitouch_is_connect = false\n"); |
| } |
| HX_PROC_SEND_FLAG = 1; |
| } else |
| HX_PROC_SEND_FLAG = 0; |
| return ret; |
| } |
| |
| //----------------------------------------------------------------------------------- |
| //himax_hitouch_store |
| //command 0 : Get Driver Version |
| //command 1 : Hitouch Connect |
| //command 2 : Hitouch Disconnect |
| //----------------------------------------------------------------------------------- |
| static ssize_t himax_hitouch_write(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| int len = strlen(buf); |
| if (len >= 80) { |
| E("%s: no command exceeds 80 chars.\n", __func__); |
| return -EFAULT; |
| } |
| if (buf[0] == '0') { |
| hitouch_command = 0; |
| } else if (buf[0] == '1') { |
| hitouch_command = 1; |
| hitouch_is_connect = true; |
| I("hitouch_is_connect = true\n"); |
| } else if (buf[0] == '2') { |
| hitouch_command = 2; |
| hitouch_is_connect = false; |
| I("hitouch_is_connect = false\n"); |
| } |
| return len; |
| } |
| #endif |
| |
| #ifdef HX_TP_PROC_DIAG |
| static int himax_touch_proc_init(void) |
| { |
| himax_touch_proc_dir = proc_mkdir( HIMAX_PROC_TOUCH_FOLDER, NULL); |
| if (himax_touch_proc_dir == NULL) { |
| E("%s: himax_touch_proc_dir file create failed!\n", __func__); |
| return -ENOMEM; |
| } |
| himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, (S_IWUSR | S_IRUGO), |
| himax_touch_proc_dir, &himax_proc_diag_ops); |
| if (himax_proc_diag_file == NULL) { |
| E("%s: proc diag file create failed!\n", __func__); |
| goto fail; |
| } |
| return 0 ; |
| fail: |
| remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); |
| return -ENOMEM; |
| } |
| #endif |
| |
| #ifdef HX_TP_PROC_DIAG |
| static void himax_touch_proc_deinit(void) |
| { |
| remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); |
| remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); |
| } |
| #endif |
| |
| #endif //end of CONFIG_TOUCHSCREEN_HIMAX_DEBUG |
| |
| #ifdef HX_SMART_WAKEUP |
| static ssize_t himax_SMWP_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct himax_ts_data *ts = private_ts; |
| size_t ret = 0; |
| ret = snprintf(buf, PAGE_SIZE, "%d\n", ts->SMWP_enable); |
| return ret; |
| } |
| |
| static ssize_t himax_SMWP_write(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| int len = strlen(buf); |
| struct himax_ts_data *ts = private_ts; |
| if (len >= 80) { |
| E("%s: no command exceeds 80 chars.\n", __func__); |
| return -EFAULT; |
| } |
| if (buf[0] == '0') |
| ts->SMWP_enable = 0; |
| else if (buf[0] == '1') |
| ts->SMWP_enable = 1; |
| else |
| return -EINVAL; |
| I("SMART_WAKEUP_enable = %d.\n", ts->SMWP_enable); |
| return len; |
| } |
| #endif |
| |
| #ifdef HX_TIME_TELLING |
| static int himax_sleepmode_switch(int supplymode) |
| { |
| uint8_t buf[2] = {0}; |
| int ret; |
| |
| switch (supplymode) { |
| case TOUCH_ACTIVE: |
| //Himax 852xes IC enter active mode |
| private_ts->resumed = true; |
| i2c_himax_write_command(private_ts->client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); |
| msleep(30); |
| i2c_himax_write_command(private_ts->client, HX_CMD_TSSLPOUT, DEFAULT_RETRY_CNT); |
| himax_int_enable(private_ts->client->irq, 1, true); |
| atomic_set(&private_ts->suspend_mode, 0); |
| private_ts->suspended = false; |
| private_ts->sleepmode = 0; |
| touch_mode = TOUCH_ACTIVE; |
| I("%s: Enable Active mode\n", __func__); |
| break; |
| case TOUCH_SLEEP: |
| //Himax 852xes IC enter sleep mode |
| private_ts->suspended = true; |
| himax_int_enable(private_ts->client->irq, 0, true); |
| buf[0] = HX_CMD_TSSOFF; |
| ret = i2c_himax_master_write(private_ts->client, buf, 1, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("%s: I2C access failed addr = 0x%x\n", __func__, private_ts->client->addr); |
| return -EINVAL; |
| } |
| msleep(40); |
| buf[0] = HX_CMD_TSSLPIN; |
| ret = i2c_himax_master_write(private_ts->client, buf, 1, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("%s: I2C access failed addr = 0x%x\n", __func__, private_ts->client->addr); |
| return -EINVAL; |
| } |
| if (touch_mode == TOUCH_IDLE) { |
| buf[0] = 0x8F; |
| buf[1] = 0x00; |
| ret = i2c_himax_master_write(private_ts->client, buf, 2, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("%s: I2C access failed addr = 0x%x\n", __func__, private_ts->client->addr); |
| } |
| msleep(50); |
| } |
| atomic_set(&private_ts->suspend_mode, 1); |
| private_ts->pre_finger_mask = 0; |
| private_ts->sleepmode = 1; |
| private_ts->resumed = false; |
| touch_mode = TOUCH_SLEEP; |
| I("%s: Enable Sleep mode\n", __func__); |
| break; |
| default: |
| I("supplymode not in case\n"); |
| } |
| return 0; |
| } |
| |
| static void himax_sleepmode_switch_work(struct work_struct *work) |
| { |
| if (!fw_update_processing) { |
| himax_sleepmode_switch(private_ts->timetellmode); |
| } else { |
| I("FW updating, reject sleepmode switch\n"); |
| } |
| } |
| |
| void himax_timetelling_detection(int supplymode) |
| { |
| if (private_ts == NULL) { |
| E("himax touch screen is null\n"); |
| return; |
| } |
| if (!HX_DRIVER_PROBE_Fial) { |
| //0:off, 1:on |
| //I("Time-telling mode = %d\n", supplymode); |
| private_ts->timetellmode = supplymode; |
| I("supplymode: %d, DisableTouch_flag: %d", supplymode, DisableTouch_flag); |
| if (DisableTouch_flag!=supplymode) { |
| DisableTouch_flag = private_ts->timetellmode; |
| queue_work(private_ts->himax_sleepmode_wq, &private_ts->sleepmode_work); |
| } |
| } |
| } |
| EXPORT_SYMBOL(himax_timetelling_detection); |
| #endif |
| |
| #ifdef CONFIG_OF |
| #if defined(HX_LOADIN_CONFIG)||defined(HX_AUTO_UPDATE_CONFIG) |
| static int himax_parse_config(struct himax_ts_data *ts, struct himax_config *pdata) |
| { |
| struct himax_config *cfg_table; |
| struct device_node *node, *pp = NULL; |
| struct property *prop; |
| uint8_t cnt = 0, i = 0; |
| u32 data = 0; |
| uint32_t coords[4] = {0}; |
| int len = 0; |
| char str[6] = {0}; |
| node = ts->client->dev.of_node; |
| if (node == NULL) { |
| E("%s: can't find device_node\n", __func__); |
| return -ENODEV; |
| } |
| while ((pp = of_get_next_child(node, pp))) |
| cnt++; |
| if (!cnt) |
| return -ENODEV; |
| cfg_table = kzalloc(cnt * (sizeof * cfg_table), GFP_KERNEL); |
| if (!cfg_table) |
| return -ENOMEM; |
| pp = NULL; |
| while ((pp = of_get_next_child(node, pp))) { |
| if (of_property_read_u32(pp, "default_cfg", &data) == 0) |
| cfg_table[i].default_cfg = data; |
| if (of_property_read_u32(pp, "sensor_id", &data) == 0) |
| cfg_table[i].sensor_id = (data); |
| if (of_property_read_u32(pp, "fw_ver_main", &data) == 0) |
| cfg_table[i].fw_ver_main = data; |
| if (of_property_read_u32(pp, "fw_ver_minor", &data) == 0) |
| cfg_table[i].fw_ver_minor = data; |
| if (of_property_read_u32_array(pp, "himax,tw-coords", coords, 4) == 0) { |
| cfg_table[i].tw_x_min = coords[0], cfg_table[i].tw_x_max = coords[1]; //x |
| cfg_table[i].tw_y_min = coords[2], cfg_table[i].tw_y_max = coords[3]; //y |
| } |
| if (of_property_read_u32_array(pp, "himax,pl-coords", coords, 4) == 0) { |
| cfg_table[i].pl_x_min = coords[0], cfg_table[i].pl_x_max = coords[1]; //x |
| cfg_table[i].pl_y_min = coords[2], cfg_table[i].pl_y_max = coords[3]; //y |
| } |
| prop = of_find_property(pp, "c1", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c1"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c1, prop->value, len); |
| prop = of_find_property(pp, "c2", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c2"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c2, prop->value, len); |
| prop = of_find_property(pp, "c3", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c3"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c3, prop->value, len); |
| prop = of_find_property(pp, "c4", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c4"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c4, prop->value, len); |
| prop = of_find_property(pp, "c5", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c5"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c5, prop->value, len); |
| prop = of_find_property(pp, "c6", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c6"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c6, prop->value, len); |
| prop = of_find_property(pp, "c7", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c7"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c7, prop->value, len); |
| prop = of_find_property(pp, "c8", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c8"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c8, prop->value, len); |
| prop = of_find_property(pp, "c9", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c9"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c9, prop->value, len); |
| prop = of_find_property(pp, "c10", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c10"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c10, prop->value, len); |
| prop = of_find_property(pp, "c11", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c11"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c11, prop->value, len); |
| prop = of_find_property(pp, "c12", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c12"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c12, prop->value, len); |
| prop = of_find_property(pp, "c13", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c13"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c13, prop->value, len); |
| prop = of_find_property(pp, "c14", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c14"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c14, prop->value, len); |
| prop = of_find_property(pp, "c15", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c15"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c15, prop->value, len); |
| prop = of_find_property(pp, "c16", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c16"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c16, prop->value, len); |
| prop = of_find_property(pp, "c17", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c17"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c17, prop->value, len); |
| prop = of_find_property(pp, "c18", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c18"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c18, prop->value, len); |
| prop = of_find_property(pp, "c19", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c19"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c19, prop->value, len); |
| prop = of_find_property(pp, "c20", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c20"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c20, prop->value, len); |
| prop = of_find_property(pp, "c21", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c21"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c21, prop->value, len); |
| prop = of_find_property(pp, "c22", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c22"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c22, prop->value, len); |
| prop = of_find_property(pp, "c23", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c23"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c23, prop->value, len); |
| prop = of_find_property(pp, "c24", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c24"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c24, prop->value, len); |
| prop = of_find_property(pp, "c25", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c25"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c25, prop->value, len); |
| prop = of_find_property(pp, "c26", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c26"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c26, prop->value, len); |
| prop = of_find_property(pp, "c27", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c27"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c27, prop->value, len); |
| prop = of_find_property(pp, "c28", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c28"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c28, prop->value, len); |
| prop = of_find_property(pp, "c29", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c29"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c29, prop->value, len); |
| prop = of_find_property(pp, "c30", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c30"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c30, prop->value, len); |
| prop = of_find_property(pp, "c31", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c31"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c31, prop->value, len); |
| prop = of_find_property(pp, "c32", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c32"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c32, prop->value, len); |
| prop = of_find_property(pp, "c33", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c33"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c33, prop->value, len); |
| prop = of_find_property(pp, "c34", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c34"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c34, prop->value, len); |
| prop = of_find_property(pp, "c35", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c35"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c35, prop->value, len); |
| prop = of_find_property(pp, "c36", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c36"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c36, prop->value, len); |
| prop = of_find_property(pp, "c37", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c37"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c37, prop->value, len); |
| prop = of_find_property(pp, "c38", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c38"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c38, prop->value, len); |
| prop = of_find_property(pp, "c39", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c39"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c39, prop->value, len); |
| prop = of_find_property(pp, "c40", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c40"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c40, prop->value, len); |
| #if 1 |
| I(" config version=[%02x]\n", cfg_table[i].c40[1]); |
| #endif |
| prop = of_find_property(pp, "c41", &len); |
| if ((!prop) || (!len)) { |
| strcpy(str, "c41"); |
| goto of_find_property_error; |
| } |
| memcpy(cfg_table[i].c41, prop->value, len); |
| #if 1 |
| I(" DT#%d-def_cfg:%d,id:%05x, FW:%x.%x, len:%d,", i, |
| cfg_table[i].default_cfg, cfg_table[i].sensor_id, |
| cfg_table[i].fw_ver_main, cfg_table[i].fw_ver_minor, cfg_table[i].length); |
| //I(" pl=[x_m%02d y_M%04d]\n", cfg_table[i].pl_x_min, cfg_table[i].pl_y_max); |
| #endif |
| i++; |
| of_find_property_error: |
| if (!prop) { |
| D(" %s:Looking up %s property in node %s failed\n", |
| __func__, str, pp->full_name); |
| return -ENODEV; |
| } else if (!len) { |
| D(" %s:Invalid length of configuration data in %s\n", |
| __func__, str); |
| return -EINVAL; |
| } |
| } |
| i = 0; //confirm which config we should load |
| while ((ts->vendor_fw_ver_H << 8 | ts->vendor_fw_ver_L) < |
| (cfg_table[i].fw_ver_main << 8 | cfg_table[i].fw_ver_minor)) { |
| i++; |
| } |
| if (cfg_table[i].default_cfg != 0) |
| goto startloadconf; |
| while (cfg_table[i].sensor_id > 0 && (cfg_table[i].sensor_id != ts->vendor_sensor_id)) { |
| I(" id:%#x!=%#x, (i++)\n", cfg_table[i].sensor_id, ts->vendor_sensor_id); |
| i++; |
| } |
| startloadconf: |
| if (i <= cnt) { |
| I(" DT-%s cfg idx(%d) in cnt(%d)\n", __func__, i, cnt); |
| pdata->fw_ver_main = cfg_table[i].fw_ver_main; |
| pdata->fw_ver_minor = cfg_table[i].fw_ver_minor; |
| pdata->sensor_id = cfg_table[i].sensor_id; |
| memcpy(pdata->c1, cfg_table[i].c1, sizeof(pdata->c1)); |
| memcpy(pdata->c2, cfg_table[i].c2, sizeof(pdata->c2)); |
| memcpy(pdata->c3, cfg_table[i].c3, sizeof(pdata->c3)); |
| memcpy(pdata->c4, cfg_table[i].c4, sizeof(pdata->c4)); |
| memcpy(pdata->c5, cfg_table[i].c5, sizeof(pdata->c5)); |
| memcpy(pdata->c6, cfg_table[i].c6, sizeof(pdata->c6)); |
| memcpy(pdata->c7, cfg_table[i].c7, sizeof(pdata->c7)); |
| memcpy(pdata->c8, cfg_table[i].c8, sizeof(pdata->c8)); |
| memcpy(pdata->c9, cfg_table[i].c9, sizeof(pdata->c9)); |
| memcpy(pdata->c10, cfg_table[i].c10, sizeof(pdata->c10)); |
| memcpy(pdata->c11, cfg_table[i].c11, sizeof(pdata->c11)); |
| memcpy(pdata->c12, cfg_table[i].c12, sizeof(pdata->c12)); |
| memcpy(pdata->c13, cfg_table[i].c13, sizeof(pdata->c13)); |
| memcpy(pdata->c14, cfg_table[i].c14, sizeof(pdata->c14)); |
| memcpy(pdata->c15, cfg_table[i].c15, sizeof(pdata->c15)); |
| memcpy(pdata->c16, cfg_table[i].c16, sizeof(pdata->c16)); |
| memcpy(pdata->c17, cfg_table[i].c17, sizeof(pdata->c17)); |
| memcpy(pdata->c18, cfg_table[i].c18, sizeof(pdata->c18)); |
| memcpy(pdata->c19, cfg_table[i].c19, sizeof(pdata->c19)); |
| memcpy(pdata->c20, cfg_table[i].c20, sizeof(pdata->c20)); |
| memcpy(pdata->c21, cfg_table[i].c21, sizeof(pdata->c21)); |
| memcpy(pdata->c22, cfg_table[i].c22, sizeof(pdata->c22)); |
| memcpy(pdata->c23, cfg_table[i].c23, sizeof(pdata->c23)); |
| memcpy(pdata->c24, cfg_table[i].c24, sizeof(pdata->c24)); |
| memcpy(pdata->c25, cfg_table[i].c25, sizeof(pdata->c25)); |
| memcpy(pdata->c26, cfg_table[i].c26, sizeof(pdata->c26)); |
| memcpy(pdata->c27, cfg_table[i].c27, sizeof(pdata->c27)); |
| memcpy(pdata->c28, cfg_table[i].c28, sizeof(pdata->c28)); |
| memcpy(pdata->c29, cfg_table[i].c29, sizeof(pdata->c29)); |
| memcpy(pdata->c30, cfg_table[i].c30, sizeof(pdata->c30)); |
| memcpy(pdata->c31, cfg_table[i].c31, sizeof(pdata->c31)); |
| memcpy(pdata->c32, cfg_table[i].c32, sizeof(pdata->c32)); |
| memcpy(pdata->c33, cfg_table[i].c33, sizeof(pdata->c33)); |
| memcpy(pdata->c34, cfg_table[i].c34, sizeof(pdata->c34)); |
| memcpy(pdata->c35, cfg_table[i].c35, sizeof(pdata->c35)); |
| memcpy(pdata->c36, cfg_table[i].c36, sizeof(pdata->c36)); |
| memcpy(pdata->c37, cfg_table[i].c37, sizeof(pdata->c37)); |
| memcpy(pdata->c38, cfg_table[i].c38, sizeof(pdata->c38)); |
| memcpy(pdata->c39, cfg_table[i].c39, sizeof(pdata->c39)); |
| memcpy(pdata->c40, cfg_table[i].c40, sizeof(pdata->c40)); |
| memcpy(pdata->c41, cfg_table[i].c41, sizeof(pdata->c41)); |
| ts->tw_x_min = cfg_table[i].tw_x_min, ts->tw_x_max = cfg_table[i].tw_x_max; //x |
| ts->tw_y_min = cfg_table[i].tw_y_min, ts->tw_y_max = cfg_table[i].tw_y_max; //y |
| ts->pl_x_min = cfg_table[i].pl_x_min, ts->pl_x_max = cfg_table[i].pl_x_max; //x |
| ts->pl_y_min = cfg_table[i].pl_y_min, ts->pl_y_max = cfg_table[i].pl_y_max; //y |
| I(" DT#%d-def_cfg:%d,id:%05x, FW:%x.%x, len:%d\n", i, |
| cfg_table[i].default_cfg, cfg_table[i].sensor_id, |
| cfg_table[i].fw_ver_main, cfg_table[i].fw_ver_minor, cfg_table[i].length); |
| I(" DT-%s:tw-coords = %d, %d, %d, %d\n", __func__, ts->tw_x_min, |
| ts->tw_x_max, ts->tw_y_min, ts->tw_y_max); |
| I(" DT-%s:pl-coords = %d, %d, %d, %d\n", __func__, ts->pl_x_min, |
| ts->pl_x_max, ts->pl_y_min, ts->pl_y_max); |
| I(" config version=[%02x]\n", pdata->c40[1]); |
| } else { |
| E(" DT-%s cfg idx(%d) > cnt(%d)\n", __func__, i, cnt); |
| return -EINVAL; |
| } |
| return 0; |
| } |
| #endif |
| |
| static int himax_parse_dt(struct himax_ts_data *ts, |
| struct himax_i2c_platform_data *pdata) |
| { |
| int rc, coords_size = 0; |
| uint32_t coords[4] = {0}; |
| struct property *prop; |
| struct device_node *dt = ts->client->dev.of_node; |
| u32 data = 0; |
| prop = of_find_property(dt, "himax,panel-coords", NULL); |
| if (prop) { |
| coords_size = prop->length / sizeof(u32); |
| if (coords_size != 4) |
| D(" %s:Invalid panel coords size %d\n", __func__, coords_size); |
| } |
| if (of_property_read_u32_array(dt, "himax,panel-coords", coords, coords_size) == 0) { |
| pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1]; |
| pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3]; |
| I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min, |
| pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); |
| } |
| prop = of_find_property(dt, "himax,display-coords", NULL); |
| if (prop) { |
| coords_size = prop->length / sizeof(u32); |
| if (coords_size != 4) |
| D(" %s:Invalid display coords size %d\n", __func__, coords_size); |
| } |
| rc = of_property_read_u32_array(dt, "himax,display-coords", coords, coords_size); |
| if (rc && (rc != -EINVAL)) { |
| D(" %s:Fail to read display-coords %d\n", __func__, rc); |
| return rc; |
| } |
| pdata->screenWidth = coords[1]; |
| pdata->screenHeight = coords[3]; |
| I(" DT-%s:display-coords = (%d, %d)\n", __func__, pdata->screenWidth, |
| pdata->screenHeight); |
| pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); |
| if (!gpio_is_valid(pdata->gpio_irq)) { |
| I(" DT:gpio_irq value is not valid\n"); |
| } |
| pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); |
| if (!gpio_is_valid(pdata->gpio_reset)) { |
| I(" DT:gpio_rst value is not valid\n"); |
| } |
| pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); |
| if (!gpio_is_valid(pdata->gpio_3v3_en)) { |
| I(" DT:gpio_3v3_en value is not valid\n"); |
| } |
| I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d\n", pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); |
| if (of_property_read_u32(dt, "report_type", &data) == 0) { |
| pdata->protocol_type = data; |
| I(" DT:protocol_type=%d\n", pdata->protocol_type); |
| } |
| return 0; |
| } |
| #endif |
| |
| #ifdef HX_AUTO_UPDATE_FW |
| static ssize_t himax_fw_update_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| int ret; |
| if (fw_update_result) |
| ret += sprintf(buf, "FW Update Success\n"); |
| else |
| ret += sprintf(buf, "FW Update Fail\n"); |
| return ret; |
| } |
| |
| static ssize_t himax_fw_update_write(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| int mode = 0; |
| int ret; |
| bool manualUpgrade = false; |
| |
| sscanf(buf, "%d", &mode); |
| manualUpgrade = mode == FW_UPDATE_MANUAL_MODE; |
| himax_int_enable(private_ts->client->irq, 0, true); |
| ret = i_update_FW(manualUpgrade); |
| himax_int_enable(private_ts->client->irq, 1, true); |
| return size; |
| } |
| |
| static ssize_t himax_fw_version_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| int ret; |
| himax_read_FW_ver(false); |
| ret = sprintf(buf, "%x.%x.%x\n", private_ts->vendor_fw_ver_H, |
| private_ts->vendor_fw_ver_L, private_ts->vendor_config_ver); |
| return ret; |
| } |
| |
| static ssize_t himax_checksum_read(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| int ret; |
| ret = himax_calculateChecksum(false, true); |
| #ifdef HX_RST_PIN_FUNC |
| himax_HW_reset(true, false); |
| #endif |
| return sprintf(buf, "%d%d%d%d\n", IC_checksum[0],IC_checksum[1],IC_checksum[2],IC_checksum[3]); |
| } |
| #endif |
| |
| #ifdef ASUS_FACTORY_BUILD |
| static int g_bmmi_status = 0; |
| |
| static ssize_t himax_show_status(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| return snprintf(buf, 20, "%d\n", g_bmmi_status); |
| } |
| |
| static DEVICE_ATTR(mode, S_IRUGO, himax_show_status, NULL); |
| #endif |
| |
| #ifdef CONFIG_TOUCHSCREEN_HIMAX_DEBUG |
| static DEVICE_ATTR(debug_level, S_IWUSR|S_IWGRP|S_IRUGO, himax_debug_level_read, himax_debug_level_write); |
| static DEVICE_ATTR(vendor, S_IRUGO, himax_vendor_read, NULL); |
| static DEVICE_ATTR(attn, S_IRUGO, himax_attn_read, NULL); |
| static DEVICE_ATTR(int_en, S_IWUSR|S_IWGRP|S_IRUGO, himax_int_en_read, himax_int_en_write); |
| static DEVICE_ATTR(layout, S_IWUSR|S_IWGRP|S_IRUGO, himax_layout_read, himax_layout_write); |
| #endif |
| #ifdef HX_TP_PROC_RESET |
| static DEVICE_ATTR(reset, S_IWUSR|S_IWGRP|S_IRUGO, NULL, himax_reset_write); |
| #endif |
| #ifdef HX_TP_PROC_REGISTER |
| static DEVICE_ATTR(register, S_IWUSR|S_IWGRP|S_IRUGO, himax_register_read, himax_register_write); |
| #endif |
| #ifdef HX_TP_PROC_DEBUG |
| static DEVICE_ATTR(debug, S_IWUSR|S_IWGRP|S_IRUGO, himax_debug_read, himax_debug_write); |
| #endif |
| #ifdef HX_TP_PROC_FLASH_DUMP |
| static DEVICE_ATTR(flash_dump, S_IWUSR|S_IWGRP|S_IRUGO, himax_flash_read, himax_flash_write); |
| #endif |
| #ifdef HX_TP_PROC_SELF_TEST |
| static DEVICE_ATTR(self_test, S_IRUGO, himax_self_test_read, NULL); |
| #endif |
| #ifdef HX_TP_PROC_HITOUCH |
| static DEVICE_ATTR(hitouch, S_IWUSR|S_IWGRP|S_IRUGO, himax_hitouch_read, himax_hitouch_write); |
| #endif |
| #ifdef HX_SMART_WAKEUP |
| static DEVICE_ATTR(SMWP, S_IWUSR|S_IWGRP|S_IRUGO, himax_SMWP_read, himax_SMWP_write); |
| #endif |
| #ifdef HX_AUTO_UPDATE_FW |
| static DEVICE_ATTR(fw_update, S_IWUSR|S_IWGRP|S_IRUGO, himax_fw_update_read, himax_fw_update_write); |
| static DEVICE_ATTR(fw_version, S_IRUGO, himax_fw_version_read, NULL); |
| static DEVICE_ATTR(checksum, S_IRUGO, himax_checksum_read, NULL); |
| #endif |
| |
| static struct attribute *himax_attrs[] = { |
| #ifdef ASUS_FACTORY_BUILD |
| &dev_attr_mode.attr, |
| #endif |
| #ifdef CONFIG_TOUCHSCREEN_HIMAX_DEBUG |
| &dev_attr_debug_level.attr, |
| &dev_attr_vendor.attr, |
| &dev_attr_attn.attr, |
| &dev_attr_int_en.attr, |
| &dev_attr_layout.attr, |
| #endif |
| #ifdef HX_TP_PROC_RESET |
| &dev_attr_reset.attr, |
| #endif |
| #ifdef HX_TP_PROC_REGISTER |
| &dev_attr_register.attr, |
| #endif |
| #ifdef HX_TP_PROC_DEBUG |
| &dev_attr_debug.attr, |
| #endif |
| #ifdef HX_TP_PROC_FLASH_DUMP |
| &dev_attr_flash_dump.attr, |
| #endif |
| #ifdef HX_TP_PROC_SELF_TEST |
| &dev_attr_self_test.attr, |
| #endif |
| #ifdef HX_TP_PROC_HITOUCH |
| &dev_attr_hitouch.attr, |
| #endif |
| #ifdef HX_SMART_WAKEUP |
| &dev_attr_SMWP.attr, |
| #endif |
| #ifdef HX_AUTO_UPDATE_FW |
| &dev_attr_fw_update.attr, |
| &dev_attr_fw_version.attr, |
| &dev_attr_checksum.attr, |
| #endif |
| NULL |
| }; |
| |
| static const struct attribute_group himax_attribute_group = { |
| .attrs = himax_attrs, |
| }; |
| |
| static int himax852xes_probe(struct i2c_client *client, const struct i2c_device_id *id) |
| { |
| int err = -ENOMEM; |
| struct himax_ts_data *ts; |
| struct himax_i2c_platform_data *pdata; |
| I("Start to probe\n"); |
| //Check I2C functionality |
| if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { |
| E("%s: i2c check functionality error\n", __func__); |
| err = -ENODEV; |
| goto err_check_functionality_failed; |
| } |
| ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL); |
| if (ts == NULL) { |
| E("%s: allocate himax_ts_data failed\n", __func__); |
| err = -ENOMEM; |
| goto err_alloc_data_failed; |
| } |
| i2c_set_clientdata(client, ts); |
| ts->client = client; |
| ts->dev = &client->dev; |
| #if 0 |
| /* Remove this since this will cause request_firmware fail. |
| Thie line has no use to touch function. */ |
| dev_set_name(ts->dev, HIMAX852xes_NAME); |
| #endif |
| pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); |
| if (pdata == NULL) { /*Allocate Platform data space*/ |
| err = -ENOMEM; |
| goto err_dt_platform_data_fail; |
| } |
| #ifdef CONFIG_OF |
| if (client->dev.of_node) { /*DeviceTree Init Platform_data*/ |
| err = himax_parse_dt(ts, pdata); |
| if (err < 0) { |
| I("pdata is NULL for DT\n"); |
| goto err_alloc_dt_pdata_failed; |
| } |
| } |
| #else |
| pdata = client->dev.platform_data; |
| if (pdata == NULL) { |
| I("pdata is NULL(dev.platform_data)\n"); |
| goto err_get_platform_data_fail; |
| } |
| #endif |
| #ifdef HX_RST_PIN_FUNC |
| ts->rst_gpio = pdata->gpio_reset; |
| #endif |
| himax_gpio_power_config(ts->client, pdata); |
| #ifndef CONFIG_OF |
| if (pdata->power) { |
| err = pdata->power(1); |
| if (err < 0) { |
| E("%s: power on failed\n", __func__); |
| goto err_power_failed; |
| } |
| } |
| #endif |
| private_ts = ts; |
| //Get Himax IC Type / FW information / Calculate the point number |
| if (himax_ic_package_check(ts) == false) { |
| E("%s: Himax chip doesn NOT EXIST", __func__); |
| goto err_ic_package_failed; |
| } |
| if (pdata->virtual_key) |
| ts->button = pdata->virtual_key; |
| #ifdef HX_TP_PROC_FLASH_DUMP |
| ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); |
| if (!ts->flash_wq) { |
| E("%s: create flash workqueue failed\n", __func__); |
| err = -ENOMEM; |
| goto err_create_flash_wq_failed; |
| } |
| INIT_WORK(&ts->flash_work, himax_ts_flash_work_func); |
| setSysOperation(0); |
| setFlashBuffer(); |
| #endif |
| himax_read_TP_info(client); |
| |
| //Himax Power On and Load Config |
| if (himax_loadSensorConfig(client, pdata) < 0) { |
| E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__); |
| goto err_detect_failed; |
| } |
| calculate_point_number(); |
| #ifdef HX_TP_PROC_DIAG |
| setXChannel(HX_RX_NUM); // X channel |
| setYChannel(HX_TX_NUM); // Y channel |
| setMutualBuffer(); |
| if (getMutualBuffer() == NULL) { |
| E("%s: mutual buffer allocate fail failed\n", __func__); |
| goto err_setchannel_failed; |
| } |
| #ifdef HX_TP_PROC_2T2R |
| if (Is_2T2R) { |
| setXChannel_2(HX_RX_NUM_2); // X channel |
| setYChannel_2(HX_TX_NUM_2); // Y channel |
| setMutualBuffer_2(); |
| if (getMutualBuffer_2() == NULL) { |
| E("%s: mutual buffer 2 allocate fail failed\n", __func__); |
| goto err_setchannel_failed; |
| } |
| } |
| #endif |
| #endif |
| #ifdef CONFIG_OF |
| ts->power = pdata->power; |
| #endif |
| ts->pdata = pdata; |
| ts->x_channel = HX_RX_NUM; |
| ts->y_channel = HX_TX_NUM; |
| ts->nFinger_support = HX_MAX_PT; |
| //calculate the i2c data size |
| calcDataSize(ts->nFinger_support); |
| //I("%s: calcDataSize complete\n", __func__); |
| ts->pdata->abs_pressure_min = 0; |
| ts->pdata->abs_pressure_max = 200; |
| ts->pdata->abs_width_min = 0; |
| ts->pdata->abs_width_max = 200; |
| pdata->cable_config[0] = 0xF0; |
| pdata->cable_config[1] = 0x00; |
| ts->suspended = false; |
| ts->resumed = true; |
| ts->protocol_type = pdata->protocol_type; |
| I("Use Protocol Type %c\n", ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); |
| err = himax_input_register(ts); |
| if (err) { |
| E("%s: Unable to register %s input device\n", |
| __func__, ts->input_dev->name); |
| goto err_input_register_device_failed; |
| } |
| #ifdef CONFIG_FB |
| ts->himax_att_wq = create_singlethread_workqueue("HMX_ATT_reuqest"); |
| if (!ts->himax_att_wq) { |
| E("%s: allocate HMX_att_wq failed\n", __func__); |
| err = -ENOMEM; |
| goto err_get_intr_bit_failed; |
| } |
| INIT_DELAYED_WORK(&ts->work_att, himax_fb_register); |
| queue_delayed_work(ts->himax_att_wq, &ts->work_att, msecs_to_jiffies(15000)); |
| #endif |
| #ifdef HX_CHIP_STATUS_MONITOR //for ESD solution |
| ts->himax_chip_monitor_wq = create_singlethread_workqueue("himax_chip_monitor_wq"); |
| if (!ts->himax_chip_monitor_wq) { |
| E("%s: create workqueue failed\n", __func__); |
| err = -ENOMEM; |
| goto err_create_chip_monitor_wq_failed; |
| } |
| INIT_DELAYED_WORK(&ts->himax_chip_monitor, himax_chip_monitor_function); |
| queue_delayed_work(ts->himax_chip_monitor_wq, &ts->himax_chip_monitor, HX_POLLING_TIMER * HZ); |
| #endif |
| #ifdef HX_TIME_TELLING |
| ts->himax_sleepmode_wq = create_singlethread_workqueue("himax_sleepmode_wq"); |
| if (!ts->himax_sleepmode_wq) { |
| E("%s: create sleepmode workqueue failed\n", __func__); |
| goto err_create_sleepmode_wq_failed; |
| } |
| INIT_WORK(&ts->sleepmode_work, himax_sleepmode_switch_work); |
| #endif |
| #ifdef HX_SMART_WAKEUP |
| ts->SMWP_enable = 1; |
| wake_lock_init(&ts->ts_SMWP_wake_lock, WAKE_LOCK_SUSPEND, HIMAX852xes_NAME); |
| #endif |
| wake_lock_init(&ts->ts_flash_wake_lock, WAKE_LOCK_SUSPEND, HIMAX852xes_NAME); |
| #ifdef HX_TP_PROC_DIAG |
| himax_touch_proc_init(); |
| #endif |
| #ifdef HX_ESD_WORKAROUND |
| ESD_RESET_ACTIVATE = 0; |
| #endif |
| HW_RESET_ACTIVATE = 0; |
| #ifdef ASUS_FACTORY_BUILD |
| g_bmmi_status = 1; |
| #endif |
| err = sysfs_create_group(&client->dev.kobj, &himax_attribute_group); |
| if (err) |
| goto exit_sysfs; |
| err = himax_ts_register_interrupt(ts->client); |
| if (err) |
| goto err_register_interrupt_failed; |
| ts->sleepmode = 0; |
| touch_mode = TOUCH_ACTIVE; |
| I("Probe complete\n"); |
| return 0; |
| err_register_interrupt_failed: |
| if (ts->irq_enabled) { |
| himax_int_enable(ts->client->irq, 0, true); |
| free_irq(ts->client->irq, ts); |
| } |
| if (!ts->use_irq) { |
| hrtimer_cancel(&ts->timer); |
| destroy_workqueue(ts->himax_wq); |
| } |
| #ifdef HX_TP_PROC_DIAG |
| himax_touch_proc_deinit(); |
| #endif |
| wake_lock_destroy(&ts->ts_flash_wake_lock); |
| #ifdef HX_SMART_WAKEUP |
| wake_lock_destroy(&ts->ts_SMWP_wake_lock); |
| #endif |
| #ifdef HX_CHIP_STATUS_MONITOR |
| cancel_delayed_work_sync(&ts->himax_chip_monitor); |
| destroy_workqueue(ts->himax_chip_monitor_wq); |
| err_create_chip_monitor_wq_failed: |
| #endif |
| #ifdef HX_TIME_TELLING |
| destroy_workqueue(ts->himax_sleepmode_wq); |
| err_create_sleepmode_wq_failed: |
| #endif |
| exit_sysfs: |
| sysfs_remove_group(&client->dev.kobj, &himax_attribute_group); |
| #ifdef CONFIG_FB |
| cancel_delayed_work_sync(&ts->work_att); |
| destroy_workqueue(ts->himax_att_wq); |
| if (fb_unregister_client(&ts->fb_notif)) |
| I("Error occurred while unregistering fb_notifier.\n"); |
| err_get_intr_bit_failed: |
| #endif |
| input_free_device(ts->input_dev); |
| err_input_register_device_failed: |
| #ifdef HX_TP_PROC_DIAG |
| err_setchannel_failed: |
| #endif |
| err_detect_failed: |
| #ifdef HX_TP_PROC_FLASH_DUMP |
| destroy_workqueue(ts->flash_wq); |
| err_create_flash_wq_failed: |
| #endif |
| err_ic_package_failed: |
| #ifndef CONFIG_OF |
| err_power_failed: |
| #endif |
| #ifdef CONFIG_OF |
| err_alloc_dt_pdata_failed: |
| #else |
| err_get_platform_data_fail: |
| #endif |
| kfree(pdata); |
| err_dt_platform_data_fail: |
| kfree(ts); |
| err_alloc_data_failed: |
| err_check_functionality_failed: |
| HX_DRIVER_PROBE_Fial = 1; |
| return err; |
| } |
| |
| static int himax852xes_remove(struct i2c_client *client) |
| { |
| struct himax_ts_data *ts = i2c_get_clientdata(client); |
| if (ts->irq_enabled) { |
| himax_int_enable(ts->client->irq, 0, true); |
| free_irq(ts->client->irq, ts); |
| } |
| if (!ts->use_irq) { |
| hrtimer_cancel(&ts->timer); |
| destroy_workqueue(ts->himax_wq); |
| } |
| #ifdef HX_TP_PROC_DIAG |
| himax_touch_proc_deinit(); |
| #endif |
| #ifdef HX_SMART_WAKEUP |
| wake_lock_destroy(&ts->ts_SMWP_wake_lock); |
| #endif |
| #ifdef HX_CHIP_STATUS_MONITOR |
| cancel_delayed_work_sync(&ts->himax_chip_monitor); |
| destroy_workqueue(ts->himax_chip_monitor_wq); |
| #endif |
| #ifdef HX_TIME_TELLING |
| destroy_workqueue(ts->himax_sleepmode_wq); |
| #endif |
| #ifdef CONFIG_FB |
| cancel_delayed_work_sync(&ts->work_att); |
| destroy_workqueue(ts->himax_att_wq); |
| if (fb_unregister_client(&ts->fb_notif)) |
| I("Error occurred while unregistering fb_notifier.\n"); |
| #endif |
| input_free_device(ts->input_dev); |
| #ifdef HX_TP_PROC_FLASH_DUMP |
| destroy_workqueue(ts->flash_wq); |
| #endif |
| kfree(ts); |
| return 0; |
| } |
| |
| static int himax852xes_suspend(struct device *dev) |
| { |
| int ret; |
| int i = 0; |
| uint8_t buf[2] = {0}; |
| #ifdef HX_CHIP_STATUS_MONITOR |
| int t = 0; |
| #endif |
| struct himax_ts_data *ts; |
| if (HX_DRIVER_PROBE_Fial) { |
| I("%s: Driver probe fail\n", __func__); |
| return 0; |
| } |
| if (fw_update_processing) { |
| I("FW updating, reject suspend\n"); |
| return 0; |
| } else { |
| ts = dev_get_drvdata(dev); |
| if (ts->suspended) { |
| I("Already suspended. Skip\n"); |
| return 0; |
| } else { |
| ts->suspended = true; |
| I("%s: enter\n", __func__); |
| } |
| #ifdef HX_TP_PROC_FLASH_DUMP |
| if (getFlashDumpGoing()) { |
| I("[himax] %s: Flash dump is going, reject suspend\n", __func__); |
| return 0; |
| } |
| #endif |
| #ifdef HX_TP_PROC_HITOUCH |
| if (hitouch_is_connect) { |
| I("[himax] %s: Hitouch connect, reject suspend\n", __func__); |
| return 0; |
| } |
| #endif |
| #ifdef HX_CHIP_STATUS_MONITOR |
| if (HX_ON_HAND_SHAKING) { //chip on hand shaking,wait hand shaking |
| for (t = 0; t < 100; t++) { |
| if (HX_ON_HAND_SHAKING == 0) { //chip on hand shaking end |
| I("%s:HX_ON_HAND_SHAKING OK check %d times\n", __func__, t); |
| break; |
| } else |
| msleep(1); |
| } |
| if (t == 100) { |
| E("%s:HX_ON_HAND_SHAKING timeout reject suspend\n", __func__); |
| return 0; |
| } |
| } |
| #endif |
| if (haspoint) { |
| for (i = 0; i < ts->nFinger_support; i++) { |
| if (point_flag[i] == 1) { |
| point_flag[i] = 0; |
| input_mt_slot(ts->input_dev, i); |
| input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); |
| } |
| } |
| input_sync(ts->input_dev); |
| haspoint = false; |
| } |
| #ifdef HX_SMART_WAKEUP |
| if (ts->SMWP_enable && touch_mode == TOUCH_ACTIVE) { |
| atomic_set(&ts->suspend_mode, 1); |
| ts->pre_finger_mask = 0; |
| FAKE_POWER_KEY_SEND = false; |
| buf[0] = 0x8F; |
| buf[1] = 0x20; |
| ret = i2c_himax_master_write(ts->client, buf, 2, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("[himax] %s: I2C access failed addr = 0x%x\n", __func__, ts->client->addr); |
| } |
| touch_mode = TOUCH_IDLE; |
| ts->resumed = false; |
| I("%s: Enable IDLE mode\n", __func__); |
| return 0; |
| } |
| #endif |
| himax_int_enable(ts->client->irq, 0, true); |
| #ifdef HX_CHIP_STATUS_MONITOR |
| HX_CHIP_POLLING_COUNT = 0; |
| cancel_delayed_work_sync(&ts->himax_chip_monitor); |
| #endif |
| //Himax 852xes IC enter sleep mode |
| buf[0] = HX_CMD_TSSOFF; |
| ret = i2c_himax_master_write(ts->client, buf, 1, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("[himax] %s: I2C access failed addr = 0x%x\n", __func__, ts->client->addr); |
| } |
| msleep(40); |
| buf[0] = HX_CMD_TSSLPIN; |
| ret = i2c_himax_master_write(ts->client, buf, 1, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("[himax] %s: I2C access failed addr = 0x%x\n", __func__, ts->client->addr); |
| } |
| touch_mode = TOUCH_SLEEP; |
| I("%s: Enable SLEEP mode\n", __func__); |
| if (!ts->use_irq) { |
| ret = cancel_work_sync(&ts->work); |
| if (ret) |
| himax_int_enable(ts->client->irq, 1, true); |
| } |
| //ts->first_pressed = 0; |
| atomic_set(&ts->suspend_mode, 1); |
| ts->pre_finger_mask = 0; |
| if (ts->pdata->powerOff3V3 && ts->pdata->power) |
| ts->pdata->power(0); |
| ts->resumed = false; |
| return 0; |
| } |
| } |
| |
| static int himax852xes_resume(struct device *dev) |
| { |
| #ifdef HX_SMART_WAKEUP |
| int ret; |
| uint8_t buf[2] = {0}; |
| #endif |
| #ifdef HX_CHIP_STATUS_MONITOR |
| int t = 0; |
| #endif |
| struct himax_ts_data *ts; |
| if (HX_DRIVER_PROBE_Fial) { |
| I("%s: Driver probe fail.\n", __func__); |
| return 0; |
| } |
| if (fw_update_processing) { |
| I("FW updating, reject resume\n"); |
| return 0; |
| } else { |
| ts = dev_get_drvdata(dev); |
| if (ts->resumed) { |
| I("Already resumed. Skip\n"); |
| return 0; |
| } else { |
| ts->resumed = true; |
| I("%s: enter\n", __func__); |
| } |
| |
| if (ts->pdata->powerOff3V3 && ts->pdata->power) |
| ts->pdata->power(1); |
| #ifdef HX_CHIP_STATUS_MONITOR |
| if (HX_ON_HAND_SHAKING) { //chip on hand shaking,wait hand shaking |
| for (t = 0; t < 100; t++) { |
| if (HX_ON_HAND_SHAKING == 0) { //chip on hand shaking end |
| I("%s: HX_ON_HAND_SHAKING OK check %d times.\n", __func__, t); |
| break; |
| } else |
| msleep(1); |
| } |
| if (t == 100) { |
| E("%s: HX_ON_HAND_SHAKING timeout reject resume.\n", __func__); |
| return 0; |
| } |
| } |
| #endif |
| if (!ts->sleepmode && touch_mode != TOUCH_ACTIVE) { |
| #ifdef HX_SMART_WAKEUP |
| if (ts->SMWP_enable && touch_mode == TOUCH_IDLE) { |
| //Sense Off |
| i2c_himax_write_command(ts->client, HX_CMD_TSSOFF, DEFAULT_RETRY_CNT); |
| msleep(40); |
| //Sleep in |
| i2c_himax_write_command(ts->client, HX_CMD_TSSLPIN, DEFAULT_RETRY_CNT); |
| buf[0] = 0x8F; |
| buf[1] = 0x00; |
| ret = i2c_himax_master_write(ts->client, buf, 2, DEFAULT_RETRY_CNT); |
| if (ret < 0) { |
| E("[himax] %s: I2C access failed addr = 0x%x\n", __func__, ts->client->addr); |
| } |
| msleep(50); |
| //I("%s: Leave IDLE mode\n", __func__); |
| } |
| #endif |
| //Sense On |
| i2c_himax_write_command(ts->client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); |
| msleep(30); |
| i2c_himax_write_command(ts->client, HX_CMD_TSSLPOUT, DEFAULT_RETRY_CNT); |
| atomic_set(&ts->suspend_mode, 0); |
| if (touch_mode == TOUCH_SLEEP) |
| himax_int_enable(ts->client->irq, 1, true); |
| #ifdef HX_CHIP_STATUS_MONITOR |
| HX_CHIP_POLLING_COUNT = 0; |
| queue_delayed_work(ts->himax_chip_monitor_wq, &ts->himax_chip_monitor, HX_POLLING_TIMER * HZ); //for ESD solution |
| #endif |
| touch_mode = TOUCH_ACTIVE; |
| ts->suspended = false; |
| I("%s: Enable ACTIVE mode\n", __func__); |
| return 0; |
| } else { |
| I("In Time-telling mode or already in Active mode, skip resume\n"); |
| return 0; |
| } |
| } |
| } |
| |
| #ifdef CONFIG_FB |
| static int fb_notifier_callback(struct notifier_block *self, |
| unsigned long event, void *data) |
| { |
| struct fb_event *evdata = data; |
| int *blank; |
| struct himax_ts_data *ts = |
| container_of(self, struct himax_ts_data, fb_notif); |
| if (evdata && evdata->data && event == FB_EVENT_BLANK && ts && |
| ts->client) { |
| blank = evdata->data; |
| switch (*blank) { |
| case FB_BLANK_UNBLANK: |
| //I("%s: call resume\n", __func__); |
| himax852xes_resume(&ts->client->dev); |
| break; |
| case FB_BLANK_POWERDOWN: |
| case FB_BLANK_HSYNC_SUSPEND: |
| case FB_BLANK_VSYNC_SUSPEND: |
| case FB_BLANK_NORMAL: |
| //I("%s: call suspend\n", __func__); |
| himax852xes_suspend(&ts->client->dev); |
| break; |
| } |
| } |
| return 0; |
| } |
| #endif |
| |
| static const struct i2c_device_id himax852xes_ts_id[] = { |
| {HIMAX852xes_NAME, 0 }, |
| {} |
| }; |
| |
| static const struct dev_pm_ops himax852xes_pm_ops = { |
| .suspend = himax852xes_suspend, |
| .resume = himax852xes_resume, |
| }; |
| |
| #ifdef CONFIG_OF |
| static struct of_device_id himax_match_table[] = { |
| {.compatible = "himax,852xes" }, |
| {}, |
| }; |
| #else |
| #define himax_match_table NULL |
| #endif |
| |
| static struct i2c_driver himax852xes_driver = { |
| .id_table = himax852xes_ts_id, |
| .probe = himax852xes_probe, |
| .remove = himax852xes_remove, |
| .driver = { |
| .name = HIMAX852xes_NAME, |
| .owner = THIS_MODULE, |
| .of_match_table = himax_match_table, |
| //#ifdef CONFIG_PM |
| #if 0 |
| .pm = &himax852xes_pm_ops, |
| #endif |
| }, |
| }; |
| |
| static void __init himax852xes_init_async(void *unused, async_cookie_t cookie) |
| { |
| i2c_add_driver(&himax852xes_driver); |
| } |
| |
| static int __init himax852xes_init(void) |
| { |
| I("Himax 852xES touch panel driver init\n"); |
| async_schedule(himax852xes_init_async, NULL); |
| return 0; |
| } |
| |
| static void __exit himax852xes_exit(void) |
| { |
| i2c_del_driver(&himax852xes_driver); |
| } |
| |
| module_init(himax852xes_init); |
| module_exit(himax852xes_exit); |
| |
| MODULE_DESCRIPTION("Himax852xes driver"); |
| MODULE_LICENSE("GPL"); |