3648 lines
91 KiB
C
Executable file
3648 lines
91 KiB
C
Executable file
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* Himax Android Driver Sample Code for common functions
|
|
*
|
|
* Copyright (C) 2022 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_platform.h"
|
|
#include "himax_common.h"
|
|
#include "himax_ic_core.h"
|
|
#include "himax_modular.h"
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
#define GEST_SUP_NUM 28
|
|
/* Setting cust key define (DF = double finger) */
|
|
/* {Double Tap, Up, Down, Left, Right, C, Z, M,
|
|
* O, S, V, W, e, m, @, (reserve),
|
|
* Finger gesture, ^, >, <, f(R), f(L), Up(DF), Down(DF),
|
|
* Left(DF), Right(DF)}
|
|
* Pen single click, Pen double click
|
|
*/
|
|
uint8_t gest_event[GEST_SUP_NUM] = {
|
|
0x80, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
0x81, 0x1D, 0x2D, 0x3D, 0x1F, 0x2F, 0x51, 0x52,
|
|
0x53, 0x54, 0xA0, 0xA1};
|
|
|
|
/*gest_event mapping to gest_key_def*/
|
|
uint16_t gest_key_def[GEST_SUP_NUM] = {
|
|
HX_KEY_DOUBLE_CLICK, HX_KEY_UP, HX_KEY_DOWN, HX_KEY_LEFT,
|
|
HX_KEY_RIGHT, HX_KEY_C, HX_KEY_Z, HX_KEY_M,
|
|
HX_KEY_O, HX_KEY_S, HX_KEY_V, HX_KEY_W,
|
|
HX_KEY_E, HX_KEY_LC_M, HX_KEY_AT, HX_KEY_RESERVE,
|
|
HX_KEY_FINGER_GEST, HX_KEY_V_DOWN, HX_KEY_V_LEFT, HX_KEY_V_RIGHT,
|
|
HX_KEY_F_RIGHT, HX_KEY_F_LEFT, HX_KEY_DF_UP, HX_KEY_DF_DOWN,
|
|
HX_KEY_DF_LEFT, HX_KEY_DF_RIGHT,
|
|
HX_KEY_PEN_SINGLE_CLICK, HX_KEY_PEN_DOUBLE_CLICK};
|
|
|
|
uint8_t *wake_event_buffer;
|
|
#endif
|
|
|
|
struct frame_ring_buf g_rb_frame;
|
|
#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F
|
|
#define TS_WAKE_LOCK_TIMEOUT (5000)
|
|
#define FRAME_COUNT 5
|
|
|
|
#if defined(HX_TP_PROC_GUEST_INFO)
|
|
struct hx_guest_info *g_guest_info_data;
|
|
EXPORT_SYMBOL(g_guest_info_data);
|
|
|
|
char *g_guest_info_item[] = {
|
|
"projectID",
|
|
"CGColor",
|
|
"BarCode",
|
|
"Reserve1",
|
|
"Reserve2",
|
|
"Reserve3",
|
|
"Reserve4",
|
|
"Reserve5",
|
|
"VCOM",
|
|
"Vcom-3Gar",
|
|
NULL
|
|
};
|
|
#endif
|
|
|
|
#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH)
|
|
#if defined(HX_UID_PASSWORD)
|
|
char *g_remodify_fw = NULL;
|
|
unsigned int g_remodify_fw_len;
|
|
#endif
|
|
|
|
bool g_boot_upgrade_flag;
|
|
const struct firmware *hxfw;
|
|
int g_i_FW_VER;
|
|
int g_i_CFG_VER;
|
|
int g_i_CID_MAJ; /*GUEST ID*/
|
|
int g_i_CID_MIN; /*VER for GUEST*/
|
|
#if defined(HX_ZERO_FLASH)
|
|
int g_f_0f_updat;
|
|
uint8_t *g_update_cfg_buf;
|
|
EXPORT_SYMBOL(g_update_cfg_buf);
|
|
#endif
|
|
#ifdef HX_PARSE_FROM_DT
|
|
char *g_fw_boot_upgrade_name;
|
|
EXPORT_SYMBOL(g_fw_boot_upgrade_name);
|
|
#if defined(HX_ZERO_FLASH)
|
|
char *g_fw_mp_upgrade_name;
|
|
EXPORT_SYMBOL(g_fw_mp_upgrade_name);
|
|
#endif
|
|
#else
|
|
char *g_fw_boot_upgrade_name = BOOT_UPGRADE_FWNAME;
|
|
EXPORT_SYMBOL(g_fw_boot_upgrade_name);
|
|
#if defined(HX_ZERO_FLASH)
|
|
char *g_fw_mp_upgrade_name = MPAP_FWNAME;
|
|
EXPORT_SYMBOL(g_fw_mp_upgrade_name);
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(HX_ZERO_FLASH)
|
|
struct zf_opt_crc g_zf_opt_crc;
|
|
EXPORT_SYMBOL(g_zf_opt_crc);
|
|
#endif
|
|
|
|
#ifdef HX_PARSE_FROM_DT
|
|
uint32_t g_proj_id = 0xffff;
|
|
EXPORT_SYMBOL(g_proj_id);
|
|
#endif
|
|
|
|
struct himax_ts_data *hx_s_ts;
|
|
EXPORT_SYMBOL(hx_s_ts);
|
|
|
|
struct himax_ic_data *hx_s_ic_data;
|
|
EXPORT_SYMBOL(hx_s_ic_data);
|
|
|
|
struct himax_report_data *hx_s_touch_data;
|
|
EXPORT_SYMBOL(hx_s_touch_data);
|
|
|
|
struct himax_core_fp hx_s_core_fp;
|
|
EXPORT_SYMBOL(hx_s_core_fp);
|
|
|
|
struct himax_debug *hx_s_debug_data;
|
|
EXPORT_SYMBOL(hx_s_debug_data);
|
|
|
|
struct proc_dir_entry *hx_touch_proc_dir;
|
|
EXPORT_SYMBOL(hx_touch_proc_dir);
|
|
|
|
struct ic_setup_collect hx_s_ic_setup;
|
|
EXPORT_SYMBOL(hx_s_ic_setup);
|
|
|
|
int g_mmi_refcnt;
|
|
EXPORT_SYMBOL(g_mmi_refcnt);
|
|
|
|
#if defined(HX_FIRMWARE_HEADER)
|
|
int32_t g_hx_panel_id;
|
|
#endif
|
|
|
|
/*ts_work about start*/
|
|
struct himax_target_report_data *g_target_report_data;
|
|
EXPORT_SYMBOL(g_target_report_data);
|
|
|
|
static void himax_report_all_leave_event(struct himax_ts_data *ts);
|
|
/*ts_work about end*/
|
|
|
|
unsigned long FW_VER_MAJ_FLASH_ADDR;
|
|
EXPORT_SYMBOL(FW_VER_MAJ_FLASH_ADDR);
|
|
|
|
unsigned long FW_VER_MIN_FLASH_ADDR;
|
|
EXPORT_SYMBOL(FW_VER_MIN_FLASH_ADDR);
|
|
|
|
unsigned long CFG_VER_MAJ_FLASH_ADDR;
|
|
EXPORT_SYMBOL(CFG_VER_MAJ_FLASH_ADDR);
|
|
|
|
unsigned long CFG_VER_MIN_FLASH_ADDR;
|
|
EXPORT_SYMBOL(CFG_VER_MIN_FLASH_ADDR);
|
|
|
|
unsigned long CID_VER_MAJ_FLASH_ADDR;
|
|
EXPORT_SYMBOL(CID_VER_MAJ_FLASH_ADDR);
|
|
|
|
unsigned long CID_VER_MIN_FLASH_ADDR;
|
|
EXPORT_SYMBOL(CID_VER_MIN_FLASH_ADDR);
|
|
/*unsigned long PANEL_VERSION_ADDR;*/
|
|
uint32_t CFG_TABLE_FLASH_ADDR;
|
|
EXPORT_SYMBOL(CFG_TABLE_FLASH_ADDR);
|
|
|
|
uint32_t g_cfg_table_hw_opt_crc;
|
|
EXPORT_SYMBOL(g_cfg_table_hw_opt_crc);
|
|
|
|
|
|
uint32_t CFG_TABLE_FLASH_ADDR_T;
|
|
EXPORT_SYMBOL(CFG_TABLE_FLASH_ADDR_T);
|
|
|
|
unsigned char IC_CHECKSUM;
|
|
EXPORT_SYMBOL(IC_CHECKSUM);
|
|
|
|
#if defined(HX_EXCP_RECOVERY)
|
|
u8 HX_EXCP_RESET_ACTIVATE;
|
|
EXPORT_SYMBOL(HX_EXCP_RESET_ACTIVATE);
|
|
|
|
int g_flag_eb_event;
|
|
EXPORT_SYMBOL(g_flag_eb_event);
|
|
|
|
int g_flag_ec_event;
|
|
EXPORT_SYMBOL(g_flag_ec_event);
|
|
|
|
#if defined(HW_ED_EXCP_EVENT)
|
|
int g_flag_ee_event;
|
|
EXPORT_SYMBOL(g_flag_ee_event);
|
|
#else
|
|
int g_flag_ed_event;
|
|
EXPORT_SYMBOL(g_flag_ed_event);
|
|
#endif
|
|
|
|
int g_zero_event_count;
|
|
|
|
#endif
|
|
|
|
static bool chip_test_r_flag;
|
|
u8 g_hw_rst_activate;
|
|
|
|
static uint8_t AA_press;
|
|
static uint8_t EN_NoiseFilter;
|
|
static uint8_t Last_EN_NoiseFilter;
|
|
|
|
static int p_point_num = 0xFFFF;
|
|
static uint8_t p_stylus_num = 0xFF;
|
|
static int probe_fail_flag;
|
|
#if defined(HX_USB_DETECT_GLOBAL)
|
|
bool USB_detect_flag;
|
|
#endif
|
|
|
|
#if defined(HX_GESTURE_TRACK)
|
|
static int gest_pt_cnt;
|
|
static int gest_pt_x[GEST_PT_MAX_NUM];
|
|
static int gest_pt_y[GEST_PT_MAX_NUM];
|
|
static int gest_start_x, gest_start_y, gest_end_x, gest_end_y;
|
|
static int gest_width, gest_height, gest_mid_x, gest_mid_y;
|
|
static int hx_gesture_coor[16];
|
|
#endif
|
|
|
|
int g_ts_dbg;
|
|
EXPORT_SYMBOL(g_ts_dbg);
|
|
|
|
/* File node for Selftest, SMWP and HSEN - Start*/
|
|
#define HX_PROC_TOUCH_FOLDER "android_touch"
|
|
#define HX_PROC_SELF_TEST_FILE "self_test"
|
|
struct proc_dir_entry *proc_self_test_file;
|
|
|
|
uint8_t HX_PROC_SEND_FLAG;
|
|
EXPORT_SYMBOL(HX_PROC_SEND_FLAG);
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
#define HX_PROC_SMWP_FILE "SMWP"
|
|
struct proc_dir_entry *proc_SMWP_file;
|
|
#define HX_PROC_GESTURE_FILE "GESTURE"
|
|
struct proc_dir_entry *proc_gesture_file;
|
|
uint8_t HX_SMWP_EN;
|
|
#if defined(HX_ULTRA_LOW_POWER)
|
|
#define HX_PROC_PSENSOR_FILE "Psensor"
|
|
struct proc_dir_entry *proc_psensor_file;
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(HX_HIGH_SENSE)
|
|
#define HX_PROC_HSEN_FILE "HSEN"
|
|
struct proc_dir_entry *proc_hsen_file;
|
|
#endif
|
|
|
|
#if defined(HX_HEADPHONE)
|
|
#define HX_PROC_HEADPHONE_FILE "headphone"
|
|
struct proc_dir_entry *proc_headphone_file;
|
|
#endif
|
|
|
|
#define HX_PROC_VENDOR_FILE "vendor"
|
|
struct proc_dir_entry *proc_vendor_file;
|
|
|
|
#if defined(HX_PALM_REPORT)
|
|
static int himax_palm_detect(const uint8_t *buf)
|
|
{
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
int32_t i;
|
|
int base = 0;
|
|
int x = 0, y = 0, w = 0;
|
|
|
|
i = 0;
|
|
base = i * 4;
|
|
x = buf[base] << 8 | buf[base + 1];
|
|
y = (buf[base + 2] << 8 | buf[base + 3]);
|
|
w = buf[(ts->nFinger_support * 4) + i];
|
|
I(" %s HX_PALM_REPORT_loopi=%d,base=%x,X=%x,Y=%x,W=%x\n",
|
|
__func__, i, base, x, y, w);
|
|
if ((!atomic_read(&ts->suspend_mode))
|
|
&& (x == 0xFA5A)
|
|
&& (y == 0xFA5A)
|
|
&& (w == 0x00))
|
|
return PALM_REPORT;
|
|
else
|
|
return NOT_REPORT;
|
|
}
|
|
#endif
|
|
|
|
#if defined(HX_FIRMWARE_HEADER)
|
|
int32_t get_fw_index(int32_t fw_type)
|
|
{
|
|
uint32_t i = 0;
|
|
int ret = -1;
|
|
|
|
for (i = 0; i < gTotal_N_firmware; i++) {
|
|
if (gHimax_firmware_id[i] == g_hx_panel_id) {
|
|
if (gHimax_firmware_type[i] == fw_type)
|
|
return i;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
void hx_get_embedded_fw(int type)
|
|
{
|
|
if (type == HX_FWTYPE_NORMAL)
|
|
I("%s: Normal Type!\n", __func__);
|
|
else if (type == HX_FWTYPE_MP)
|
|
I("%s: MP Type!\n", __func__);
|
|
|
|
if (get_fw_index(type) >= 0) {
|
|
hx_s_ts->is_set_embedded_fw = 1;
|
|
hx_s_ts->_embedded_fw.data = gHimax_firmware_list[
|
|
get_fw_index(type)];
|
|
hx_s_ts->_embedded_fw.size = gHimax_firmware_size[
|
|
get_fw_index(type)];
|
|
} else {
|
|
hx_s_ts->is_set_embedded_fw = 0;
|
|
E("%s: Embedded no this type fw!\n", __func__);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static ssize_t himax_self_test(struct seq_file *s, void *v)
|
|
{
|
|
|
|
size_t ret = 0;
|
|
|
|
I("%s: enter, %d\n", __func__, __LINE__);
|
|
|
|
if (hx_s_ts->suspended == 1) {
|
|
E("%s: please do self test in normal active mode\n", __func__);
|
|
return HX_INIT_FAIL;
|
|
}
|
|
|
|
if (hx_s_ts->in_self_test == 1) {
|
|
W("%s: Self test is running now!\n", __func__);
|
|
return ret;
|
|
}
|
|
hx_s_ts->in_self_test = 1;
|
|
|
|
himax_int_enable(0);/* disable irq */
|
|
if (hx_s_core_fp._chip_self_test != NULL)
|
|
hx_s_core_fp._chip_self_test(s, v);
|
|
else {
|
|
E("%s: Doesn't turn on inspection function!\n", __func__);
|
|
seq_puts(s, "Doesn't turn on inspection function!\n");
|
|
}
|
|
/*
|
|
*#if defined(HX_EXCP_RECOVERY)
|
|
* HX_EXCP_RESET_ACTIVATE = 1;
|
|
*#endif
|
|
* himax_int_enable(1); //enable irq
|
|
*/
|
|
|
|
#if defined(HX_EXCP_RECOVERY)
|
|
HX_EXCP_RESET_ACTIVATE = 1;
|
|
#endif
|
|
himax_int_enable(1);
|
|
|
|
hx_s_ts->in_self_test = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void *hx_proc_selftest_seq_start(struct seq_file *s, loff_t *pos)
|
|
{
|
|
if (*pos >= 1)
|
|
return NULL;
|
|
|
|
|
|
return (void *)((unsigned long) *pos + 1);
|
|
}
|
|
|
|
static void *hx_proc_selftest_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static void hx_proc_selftest_seq_stop(struct seq_file *s, void *v)
|
|
{
|
|
}
|
|
|
|
static int hx_proc_selftest_seq_read(struct seq_file *s, void *v)
|
|
{
|
|
size_t ret = 0;
|
|
|
|
if (chip_test_r_flag) {
|
|
if (g_rslt_data) {
|
|
if (s->size < g_rslt_data_len) {
|
|
s->size = g_rslt_data_len;
|
|
s->buf = kcalloc(s->size,
|
|
sizeof(char), GFP_KERNEL);
|
|
if (s->buf == NULL) {
|
|
E("%s,%d: Memory allocation falied!\n",
|
|
__func__, __LINE__);
|
|
seq_puts(s, "Allocate Memory Fail!\n");
|
|
return -ENOMEM;
|
|
}
|
|
memset(s->buf, 0, s->size * sizeof(char));
|
|
}
|
|
seq_printf(s, "%s", g_rslt_data);
|
|
} else
|
|
seq_puts(s, "No chip test data.\n");
|
|
} else {
|
|
himax_self_test(s, v);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct seq_operations hx_proc_selftest_seq_ops = {
|
|
.start = hx_proc_selftest_seq_start,
|
|
.next = hx_proc_selftest_seq_next,
|
|
.stop = hx_proc_selftest_seq_stop,
|
|
.show = hx_proc_selftest_seq_read,
|
|
};
|
|
|
|
static int hx_proc_selftest_open(struct inode *inode, struct file *file)
|
|
{
|
|
return seq_open(file, &hx_proc_selftest_seq_ops);
|
|
};
|
|
|
|
static ssize_t hx_proc_selftest_write(struct file *filp,
|
|
const char __user *buff, size_t len, loff_t *data)
|
|
{
|
|
char buf[80];
|
|
|
|
if (len >= 80) {
|
|
I("%s: no command exceeds 80 chars.\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (copy_from_user(buf, buff, len))
|
|
return -EFAULT;
|
|
|
|
if (buf[0] == 'r') {
|
|
chip_test_r_flag = true;
|
|
I("%s: Start to read chip test data.\n", __func__);
|
|
} else {
|
|
chip_test_r_flag = false;
|
|
I("%s: Back to do self test.\n", __func__);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static const struct proc_ops_name hx_proc_selftest_ops = {
|
|
owner_line
|
|
.proc_op(open) = hx_proc_selftest_open,
|
|
.proc_op(read) = seq_read,
|
|
.proc_op(write) = hx_proc_selftest_write,
|
|
.proc_op(release) = seq_release,
|
|
};
|
|
|
|
#if defined(HX_HIGH_SENSE)
|
|
static ssize_t hx_proc_hsen_read(struct file *file, char *buf,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
size_t count = 0;
|
|
char *temp_buf = NULL;
|
|
|
|
if (!HX_PROC_SEND_FLAG) {
|
|
temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL);
|
|
if (temp_buf != NULL) {
|
|
count = snprintf(temp_buf, PAGE_SIZE, "%d\n",
|
|
ts->HSEN_enable);
|
|
|
|
if (copy_to_user(buf, temp_buf, len))
|
|
I("%s, here:%d\n", __func__, __LINE__);
|
|
|
|
kfree(temp_buf);
|
|
HX_PROC_SEND_FLAG = 1;
|
|
} else {
|
|
E("%s, Failed to allocate memory\n", __func__);
|
|
}
|
|
} else {
|
|
HX_PROC_SEND_FLAG = 0;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t hx_proc_hsen_write(struct file *file, const char *buff,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
char buf[80] = {0};
|
|
|
|
if (len >= 80) {
|
|
I("%s: no command exceeds 80 chars.\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (copy_from_user(buf, buff, len))
|
|
return -EFAULT;
|
|
|
|
if (buf[0] == '0')
|
|
ts->HSEN_enable = 0;
|
|
else if (buf[0] == '1')
|
|
ts->HSEN_enable = 1;
|
|
else
|
|
return -EINVAL;
|
|
|
|
hx_s_core_fp._set_HSEN_enable(ts->HSEN_enable, ts->suspended);
|
|
I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable);
|
|
return len;
|
|
}
|
|
|
|
static const struct proc_ops_name hx_proc_hsen_ops = {
|
|
owner_line
|
|
.proc_op(read) = hx_proc_hsen_read,
|
|
.proc_op(write) = hx_proc_hsen_write,
|
|
};
|
|
#endif
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
static ssize_t hx_proc_smwp_read(struct file *file, char *buf,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
size_t count = 0;
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
char *temp_buf = NULL;
|
|
|
|
if (!HX_PROC_SEND_FLAG) {
|
|
temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL);
|
|
if (temp_buf != NULL) {
|
|
count = snprintf(temp_buf, PAGE_SIZE, "%d\n",
|
|
ts->SMWP_enable);
|
|
|
|
if (copy_to_user(buf, temp_buf, len))
|
|
I("%s, here:%d\n", __func__, __LINE__);
|
|
|
|
kfree(temp_buf);
|
|
HX_PROC_SEND_FLAG = 1;
|
|
} else {
|
|
E("%s, Failed to allocate memory\n", __func__);
|
|
}
|
|
} else {
|
|
HX_PROC_SEND_FLAG = 0;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t hx_proc_smwp_write(struct file *file, const char *buff,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
char buf[80] = {0};
|
|
|
|
if (len >= 80) {
|
|
I("%s: no command exceeds 80 chars.\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (copy_from_user(buf, buff, len))
|
|
return -EFAULT;
|
|
|
|
if (buf[0] == '0')
|
|
ts->SMWP_enable = 0;
|
|
else if (buf[0] == '1')
|
|
ts->SMWP_enable = 1;
|
|
else
|
|
return -EINVAL;
|
|
|
|
hx_s_core_fp._set_SMWP_enable(ts->SMWP_enable, ts->suspended);
|
|
HX_SMWP_EN = ts->SMWP_enable;
|
|
I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN);
|
|
return len;
|
|
}
|
|
|
|
static const struct proc_ops_name hx_proc_smwp_ops = {
|
|
owner_line
|
|
.proc_op(read) = hx_proc_smwp_read,
|
|
.proc_op(write) = hx_proc_smwp_write,
|
|
};
|
|
|
|
static ssize_t hx_proc_gesture_read(struct file *file, char *buf,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
int i;
|
|
size_t ret = 0;
|
|
char *temp_buf = NULL;
|
|
|
|
if (!HX_PROC_SEND_FLAG) {
|
|
temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL);
|
|
if (temp_buf != NULL) {
|
|
for (i = 0; i < GEST_SUP_NUM; i++)
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"ges_en[%d]=%d\n",
|
|
i, ts->gesture_cust_en[i]);
|
|
|
|
if (copy_to_user(buf, temp_buf, len))
|
|
I("%s, here:%d\n", __func__, __LINE__);
|
|
|
|
kfree(temp_buf);
|
|
HX_PROC_SEND_FLAG = 1;
|
|
} else {
|
|
E("%s, Failed to allocate memory\n", __func__);
|
|
}
|
|
} else {
|
|
HX_PROC_SEND_FLAG = 0;
|
|
ret = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t hx_proc_gesture_write(struct file *file, const char *buff,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
int i = 0;
|
|
int j = 0;
|
|
char buf[80] = {0};
|
|
|
|
if (len >= 80) {
|
|
I("%s: no command exceeds 80 chars.\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (copy_from_user(buf, buff, len))
|
|
return -EFAULT;
|
|
|
|
I("himax_GESTURE_store= %s, len = %d\n", buf, (int)len);
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (buf[i] == '0' && j < GEST_SUP_NUM) {
|
|
ts->gesture_cust_en[j] = 0;
|
|
I("gesture en[%d]=%d\n", j, ts->gesture_cust_en[j]);
|
|
j++;
|
|
} else if (buf[i] == '1' && j < GEST_SUP_NUM) {
|
|
ts->gesture_cust_en[j] = 1;
|
|
I("gesture en[%d]=%d\n", j, ts->gesture_cust_en[j]);
|
|
j++;
|
|
} else
|
|
I("Not 0/1 or >=GEST_SUP_NUM : buf[%d] = %c\n",
|
|
i, buf[i]);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static const struct proc_ops_name himax_proc_Gesture_ops = {
|
|
owner_line
|
|
.proc_op(read) = hx_proc_gesture_read,
|
|
.proc_op(write) = hx_proc_gesture_write,
|
|
};
|
|
|
|
#if defined(HX_ULTRA_LOW_POWER)
|
|
static ssize_t hx_proc_psensor_read(struct file *file, char *buf,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
size_t count = 0;
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
char *temp_buf = NULL;
|
|
|
|
if (!HX_PROC_SEND_FLAG) {
|
|
temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL);
|
|
if (temp_buf != NULL) {
|
|
count = snprintf(temp_buf, PAGE_SIZE,
|
|
"p-sensor flag = %d\n",
|
|
ts->psensor_flag);
|
|
|
|
if (copy_to_user(buf, temp_buf, len))
|
|
I("%s, here:%d\n", __func__, __LINE__);
|
|
|
|
kfree(temp_buf);
|
|
HX_PROC_SEND_FLAG = 1;
|
|
} else {
|
|
E("%s, Failed to allocate memory\n", __func__);
|
|
}
|
|
} else {
|
|
HX_PROC_SEND_FLAG = 0;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t hx_proc_psensor_write(struct file *file, const char *buff,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
char buf[80] = {0};
|
|
|
|
if (len >= 80) {
|
|
I("%s: no command exceeds 80 chars.\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (copy_from_user(buf, buff, len))
|
|
return -EFAULT;
|
|
|
|
if (buf[0] == '0' && ts->SMWP_enable == 1) {
|
|
ts->psensor_flag = false;
|
|
hx_s_core_fp._black_gest_ctrl(false);
|
|
} else if (buf[0] == '1' && ts->SMWP_enable == 1) {
|
|
ts->psensor_flag = true;
|
|
hx_s_core_fp._black_gest_ctrl(true);
|
|
} else if (ts->SMWP_enable == 0) {
|
|
I("%s: SMWP is disable, not supprot to ctrl p-sensor.\n",
|
|
__func__);
|
|
} else
|
|
return -EINVAL;
|
|
|
|
I("%s: psensor_flag = %d.\n", __func__, ts->psensor_flag);
|
|
return len;
|
|
}
|
|
|
|
static const struct proc_ops_name himax_proc_psensor_ops = {
|
|
owner_line
|
|
.proc_op(read) = hx_proc_psensor_read,
|
|
.proc_op(write) = hx_proc_psensor_write,
|
|
};
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(HX_HEADPHONE)
|
|
static ssize_t hx_proc_headphone_read(struct file *file, char *buf,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
size_t count = 0;
|
|
char *temp_buf = NULL;
|
|
|
|
if (!HX_PROC_SEND_FLAG) {
|
|
temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL);
|
|
if (temp_buf != NULL) {
|
|
count = snprintf(temp_buf, PAGE_SIZE, "%d\n",
|
|
ts->hp_en);
|
|
|
|
if (copy_to_user(buf, temp_buf, len))
|
|
I("%s, here:%d\n", __func__, __LINE__);
|
|
|
|
kfree(temp_buf);
|
|
HX_PROC_SEND_FLAG = 1;
|
|
} else {
|
|
E("%s, Failed to allocate memory\n", __func__);
|
|
}
|
|
} else {
|
|
HX_PROC_SEND_FLAG = 0;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t hx_proc_headphone_write(struct file *file, const char *buff,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
char buf[80] = {0};
|
|
|
|
if (len >= 80) {
|
|
I("%s: no command exceeds 80 chars.\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (copy_from_user(buf, buff, len))
|
|
return -EFAULT;
|
|
|
|
if (buf[0] == '0')
|
|
ts->hp_en = 0;
|
|
else if (buf[0] == '1')
|
|
ts->hp_en = 1;
|
|
else
|
|
return -EINVAL;
|
|
|
|
hx_s_core_fp._set_headphone_en(ts->hp_en, ts->suspended);
|
|
I("%s: Headphone enable = %d.\n", __func__, ts->hp_en);
|
|
return len;
|
|
}
|
|
|
|
static const struct proc_ops_name hx_proc_headphone_ops = {
|
|
owner_line
|
|
.proc_op(read) = hx_proc_headphone_read,
|
|
.proc_op(write) = hx_proc_headphone_write,
|
|
};
|
|
#endif
|
|
|
|
static ssize_t hx_proc_vendor_read(struct file *file, char *buf,
|
|
size_t len, loff_t *pos)
|
|
{
|
|
ssize_t ret = 0;
|
|
char *temp_buf = NULL;
|
|
|
|
if (!HX_PROC_SEND_FLAG) {
|
|
temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL);
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"IC = %s\n", hx_s_ts->chip_name);
|
|
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"FW_VER = 0x%2.2X\n", hx_s_ic_data->vendor_fw_ver);
|
|
|
|
if (hx_s_ts->chip_cell_type == CHIP_IS_ON_CELL) {
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"CONFIG_VER = 0x%2.2X\n",
|
|
hx_s_ic_data->vendor_config_ver);
|
|
} else {
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"TOUCH_VER = 0x%2.2X\n",
|
|
hx_s_ic_data->vendor_touch_cfg_ver);
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"DISPLAY_VER = 0x%2.2X\n",
|
|
hx_s_ic_data->vendor_display_cfg_ver);
|
|
}
|
|
|
|
if (hx_s_ic_data->vendor_cid_maj_ver < 0
|
|
&& hx_s_ic_data->vendor_cid_min_ver < 0) {
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"CID_VER = NULL\n");
|
|
} else {
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"CID_VER = 0x%2.2X\n",
|
|
(hx_s_ic_data->vendor_cid_maj_ver << 8 |
|
|
hx_s_ic_data->vendor_cid_min_ver));
|
|
}
|
|
|
|
if (hx_s_ic_data->vendor_panel_ver < 0) {
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"PANEL_VER = NULL\n");
|
|
} else {
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"PANEL_VER = 0x%2.2X\n",
|
|
hx_s_ic_data->vendor_panel_ver);
|
|
}
|
|
if (hx_s_ts->chip_cell_type == CHIP_IS_IN_CELL) {
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"Cusomer = %s\n",
|
|
hx_s_ic_data->vendor_cus_info);
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"Project = %s\n",
|
|
hx_s_ic_data->vendor_proj_info);
|
|
}
|
|
ret += snprintf(temp_buf + ret, len - ret, "\n");
|
|
ret += snprintf(temp_buf + ret, len - ret,
|
|
"Himax Touch Driver Version:\n");
|
|
ret += snprintf(temp_buf + ret, len - ret, "%s\n",
|
|
HIMAX_DRIVER_VER);
|
|
|
|
if (copy_to_user(buf, temp_buf, len))
|
|
I("%s,here:%d\n", __func__, __LINE__);
|
|
|
|
kfree(temp_buf);
|
|
HX_PROC_SEND_FLAG = 1;
|
|
} else {
|
|
HX_PROC_SEND_FLAG = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
static const struct proc_ops_name hx_proc_vendor_ops = {
|
|
owner_line
|
|
.proc_op(read) = hx_proc_vendor_read,
|
|
};
|
|
|
|
int himax_common_proc_init(void)
|
|
{
|
|
hx_touch_proc_dir = proc_mkdir(HX_PROC_TOUCH_FOLDER, NULL);
|
|
|
|
if (hx_touch_proc_dir == NULL) {
|
|
E(" %s: hx_touch_proc_dir file create failed!\n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
if (_himax_self_test_init != NULL)
|
|
_himax_self_test_init();
|
|
|
|
proc_self_test_file = proc_create(HX_PROC_SELF_TEST_FILE, 0444,
|
|
hx_touch_proc_dir, &hx_proc_selftest_ops);
|
|
if (proc_self_test_file == NULL) {
|
|
E(" %s: proc self_test file create failed!\n", __func__);
|
|
goto fail_1;
|
|
}
|
|
|
|
#if defined(HX_HIGH_SENSE)
|
|
proc_hsen_file = proc_create(HX_PROC_HSEN_FILE, 0666,
|
|
hx_touch_proc_dir, &hx_proc_hsen_ops);
|
|
|
|
if (proc_hsen_file == NULL) {
|
|
E(" %s: proc HSEN file create failed!\n", __func__);
|
|
goto fail_2;
|
|
}
|
|
|
|
#endif
|
|
#if defined(HX_SMART_WAKEUP)
|
|
proc_SMWP_file = proc_create(HX_PROC_SMWP_FILE, 0666,
|
|
hx_touch_proc_dir, &hx_proc_smwp_ops);
|
|
|
|
if (proc_SMWP_file == NULL) {
|
|
E(" %s: proc SMWP file create failed!\n", __func__);
|
|
goto fail_3;
|
|
}
|
|
|
|
proc_gesture_file = proc_create(HX_PROC_GESTURE_FILE, 0666,
|
|
hx_touch_proc_dir, &himax_proc_Gesture_ops);
|
|
|
|
if (proc_gesture_file == NULL) {
|
|
E(" %s: proc GESTURE file create failed!\n", __func__);
|
|
goto fail_4;
|
|
}
|
|
#if defined(HX_ULTRA_LOW_POWER)
|
|
proc_psensor_file = proc_create(HX_PROC_PSENSOR_FILE, 0666,
|
|
hx_touch_proc_dir, &himax_proc_psensor_ops);
|
|
|
|
if (proc_psensor_file == NULL) {
|
|
E(" %s: proc GESTURE file create failed!\n", __func__);
|
|
goto fail_5;
|
|
}
|
|
#endif
|
|
#endif
|
|
proc_vendor_file = proc_create(HX_PROC_VENDOR_FILE, 0444,
|
|
hx_touch_proc_dir, &hx_proc_vendor_ops);
|
|
if (proc_vendor_file == NULL) {
|
|
E(" %s: proc vendor file create failed!\n", __func__);
|
|
goto fail_6;
|
|
}
|
|
#if defined(HX_HEADPHONE)
|
|
proc_headphone_file = proc_create(HX_PROC_HEADPHONE_FILE, 0444,
|
|
hx_touch_proc_dir, &hx_proc_headphone_ops);
|
|
if (proc_headphone_file == NULL) {
|
|
E(" %s: proc headphone file create failed!\n", __func__);
|
|
goto fail_7;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
#if defined(HX_HEADPHONE)
|
|
fail_7:
|
|
#endif
|
|
remove_proc_entry(HX_PROC_VENDOR_FILE, hx_touch_proc_dir);
|
|
fail_6:
|
|
#if defined(HX_SMART_WAKEUP)
|
|
#if defined(HX_ULTRA_LOW_POWER)
|
|
remove_proc_entry(HX_PROC_PSENSOR_FILE, hx_touch_proc_dir);
|
|
fail_5:
|
|
#endif
|
|
remove_proc_entry(HX_PROC_GESTURE_FILE, hx_touch_proc_dir);
|
|
fail_4:
|
|
remove_proc_entry(HX_PROC_SMWP_FILE, hx_touch_proc_dir);
|
|
fail_3:
|
|
#endif
|
|
#if defined(HX_HIGH_SENSE)
|
|
remove_proc_entry(HX_PROC_HSEN_FILE, hx_touch_proc_dir);
|
|
fail_2:
|
|
#endif
|
|
remove_proc_entry(HX_PROC_SELF_TEST_FILE, hx_touch_proc_dir);
|
|
fail_1:
|
|
return -ENOMEM;
|
|
}
|
|
|
|
void himax_common_proc_deinit(void)
|
|
{
|
|
#if defined(HX_HEADPHONE)
|
|
remove_proc_entry(HX_PROC_HEADPHONE_FILE, hx_touch_proc_dir);
|
|
#endif
|
|
remove_proc_entry(HX_PROC_VENDOR_FILE, hx_touch_proc_dir);
|
|
#if defined(HX_SMART_WAKEUP)
|
|
#if defined(HX_ULTRA_LOW_POWER)
|
|
remove_proc_entry(HX_PROC_PSENSOR_FILE, hx_touch_proc_dir);
|
|
#endif
|
|
remove_proc_entry(HX_PROC_GESTURE_FILE, hx_touch_proc_dir);
|
|
remove_proc_entry(HX_PROC_SMWP_FILE, hx_touch_proc_dir);
|
|
#endif
|
|
#if defined(HX_HIGH_SENSE)
|
|
remove_proc_entry(HX_PROC_HSEN_FILE, hx_touch_proc_dir);
|
|
#endif
|
|
remove_proc_entry(HX_PROC_SELF_TEST_FILE, hx_touch_proc_dir);
|
|
|
|
remove_proc_entry(HX_PROC_TOUCH_FOLDER, NULL);
|
|
}
|
|
|
|
/* File node for SMWP and HSEN - End*/
|
|
|
|
void hx_parse_assign_cmd(uint32_t addr, uint8_t *cmd, int len)
|
|
{
|
|
/*I("%s: Entering!\n", __func__);*/
|
|
|
|
switch (len) {
|
|
case 1:
|
|
cmd[0] = addr;
|
|
/*I("%s: cmd[0] = 0x%02X\n", __func__, cmd[0]);*/
|
|
break;
|
|
|
|
case 2:
|
|
cmd[0] = addr & 0xFF;
|
|
cmd[1] = (addr >> 8) & 0xFF;
|
|
/*I("%s: cmd[0] = 0x%02X,cmd[1] = 0x%02X\n",*/
|
|
/* __func__, cmd[0], cmd[1]);*/
|
|
break;
|
|
|
|
case 4:
|
|
cmd[0] = addr & 0xFF;
|
|
cmd[1] = (addr >> 8) & 0xFF;
|
|
cmd[2] = (addr >> 16) & 0xFF;
|
|
cmd[3] = (addr >> 24) & 0xFF;
|
|
/* I("%s: cmd[0] = 0x%02X,cmd[1] = 0x%02X,*/
|
|
/*cmd[2] = 0x%02X,cmd[3] = 0x%02X\n", */
|
|
/* __func__, cmd[0], cmd[1], cmd[2], cmd[3]);*/
|
|
break;
|
|
|
|
default:
|
|
E("%s: input length fault,len = %d!\n", __func__, len);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(hx_parse_assign_cmd);
|
|
|
|
int himax_input_register(struct himax_ts_data *ts)
|
|
{
|
|
int ret = 0;
|
|
#if defined(HX_SMART_WAKEUP)
|
|
int i = 0;
|
|
#endif
|
|
ret = himax_dev_set(ts);
|
|
if (ret < 0) {
|
|
I("%s, input device register fail!\n", __func__);
|
|
return INPUT_REGISTER_FAIL;
|
|
}
|
|
|
|
set_bit(EV_SYN, ts->input_dev->evbit);
|
|
set_bit(EV_ABS, ts->input_dev->evbit);
|
|
set_bit(EV_KEY, ts->input_dev->evbit);
|
|
set_bit(KEY_BACK, ts->input_dev->keybit);
|
|
set_bit(KEY_HOME, ts->input_dev->keybit);
|
|
set_bit(KEY_MENU, ts->input_dev->keybit);
|
|
set_bit(KEY_SEARCH, ts->input_dev->keybit);
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
for (i = 0; i < GEST_SUP_NUM; i++)
|
|
set_bit(gest_key_def[i], ts->input_dev->keybit);
|
|
#elif defined(HX_PALM_REPORT)
|
|
set_bit(KEY_POWER, ts->input_dev->keybit);
|
|
#endif
|
|
set_bit(BTN_TOUCH, ts->input_dev->keybit);
|
|
set_bit(KEY_APPSELECT, ts->input_dev->keybit);
|
|
set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
|
|
#if defined(HX_PROTOCOL_A)
|
|
/*ts->input_dev->mtsize = ts->nFinger_support;*/
|
|
input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 1, 10, 0, 0);
|
|
#else
|
|
set_bit(MT_TOOL_FINGER, ts->input_dev->keybit);
|
|
#if defined(HX_PROTOCOL_B_3PA)
|
|
input_mt_init_slots(ts->input_dev, ts->nFinger_support,
|
|
INPUT_MT_DIRECT);
|
|
#else
|
|
input_mt_init_slots(ts->input_dev, ts->nFinger_support);
|
|
#endif
|
|
#endif
|
|
I("input_set_abs_params: mix_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);
|
|
#if !defined(HX_PROTOCOL_A)
|
|
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);
|
|
#endif
|
|
/* 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);*/
|
|
|
|
if (himax_input_register_device(ts->input_dev) == 0) {
|
|
ret = NO_ERR;
|
|
} else {
|
|
E("%s: input register fail\n", __func__);
|
|
input_free_device(ts->input_dev);
|
|
return INPUT_REGISTER_FAIL;
|
|
}
|
|
|
|
if (!hx_s_ic_data->stylus_func)
|
|
goto skip_stylus_operation;
|
|
|
|
set_bit(EV_SYN, ts->stylus_dev->evbit);
|
|
set_bit(EV_ABS, ts->stylus_dev->evbit);
|
|
set_bit(EV_KEY, ts->stylus_dev->evbit);
|
|
set_bit(BTN_TOUCH, ts->stylus_dev->keybit);
|
|
set_bit(INPUT_PROP_DIRECT, ts->stylus_dev->propbit);
|
|
|
|
set_bit(BTN_TOOL_PEN, ts->stylus_dev->keybit);
|
|
set_bit(BTN_TOOL_RUBBER, ts->stylus_dev->keybit);
|
|
|
|
input_set_abs_params(ts->stylus_dev, ABS_PRESSURE, 0, 4095, 0, 0);
|
|
input_set_abs_params(ts->stylus_dev, ABS_DISTANCE, 0, 1, 0, 0);
|
|
input_set_abs_params(ts->stylus_dev, ABS_TILT_X, -60, 60, 0, 0);
|
|
input_set_abs_params(ts->stylus_dev, ABS_TILT_Y, -60, 60, 0, 0);
|
|
/*input_set_capability(ts->hx_pen_dev, EV_SW, SW_PEN_INSERT);*/
|
|
input_set_capability(ts->stylus_dev, EV_KEY, BTN_TOUCH);
|
|
input_set_capability(ts->stylus_dev, EV_KEY, BTN_STYLUS);
|
|
input_set_capability(ts->stylus_dev, EV_KEY, BTN_STYLUS2);
|
|
|
|
input_set_abs_params(ts->stylus_dev, ABS_X, ts->pdata->abs_x_min,
|
|
((ts->pdata->abs_x_max+1)*hx_s_ic_data->stylus_ratio-1),
|
|
ts->pdata->abs_x_fuzz, 0);
|
|
input_set_abs_params(ts->stylus_dev, ABS_Y, ts->pdata->abs_y_min,
|
|
((ts->pdata->abs_y_max+1)*hx_s_ic_data->stylus_ratio-1),
|
|
ts->pdata->abs_y_fuzz, 0);
|
|
|
|
if (himax_input_register_device(ts->stylus_dev) == 0) {
|
|
ret = NO_ERR;
|
|
} else {
|
|
E("%s: input register stylus fail\n", __func__);
|
|
input_unregister_device(ts->input_dev);
|
|
input_free_device(ts->stylus_dev);
|
|
return INPUT_REGISTER_FAIL;
|
|
}
|
|
|
|
skip_stylus_operation:
|
|
|
|
I("%s, input device registered.\n", __func__);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(himax_input_register);
|
|
|
|
|
|
#if defined(HX_BOOT_UPGRADE)
|
|
int himax_get_fw_ver_bin(const struct firmware *hxfw)
|
|
{
|
|
I("%s: use default address.\n", __func__);
|
|
if (hxfw != NULL) {
|
|
I("Catch fw version in bin file!\n");
|
|
if (FW_VER_MAJ_FLASH_ADDR <= (hxfw->size-2))
|
|
g_i_FW_VER = (hxfw->data[FW_VER_MAJ_FLASH_ADDR] << 8)
|
|
| hxfw->data[FW_VER_MIN_FLASH_ADDR];
|
|
if (CFG_VER_MAJ_FLASH_ADDR <= (hxfw->size-2))
|
|
g_i_CFG_VER = (hxfw->data[CFG_VER_MAJ_FLASH_ADDR] << 8)
|
|
| hxfw->data[CFG_VER_MIN_FLASH_ADDR];
|
|
if (CID_VER_MAJ_FLASH_ADDR <= (hxfw->size-2))
|
|
g_i_CID_MAJ = hxfw->data[CID_VER_MAJ_FLASH_ADDR];
|
|
if (CID_VER_MIN_FLASH_ADDR <= (hxfw->size-1))
|
|
g_i_CID_MIN = hxfw->data[CID_VER_MIN_FLASH_ADDR];
|
|
} else {
|
|
I("FW data is null!\n");
|
|
return 1;
|
|
}
|
|
return NO_ERR;
|
|
}
|
|
static int himax_auto_update_check(void)
|
|
{
|
|
int32_t ret;
|
|
|
|
I("%s: Entering!\n", __func__);
|
|
if (himax_get_fw_ver_bin(hxfw) == 0) {
|
|
if (((hx_s_ic_data->vendor_fw_ver < g_i_FW_VER)
|
|
|| (hx_s_ic_data->vendor_config_ver < g_i_CFG_VER))) {
|
|
I("%s: Need update\n", __func__);
|
|
ret = 0;
|
|
} else {
|
|
I("%s: Need not update!\n", __func__);
|
|
ret = 1;
|
|
}
|
|
} else {
|
|
E("%s: FW bin fail!\n", __func__);
|
|
ret = 1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH)
|
|
|
|
#if defined(HX_UID_PASSWORD)
|
|
int i_add_uid_for_FW(const struct firmware *fw_entry)
|
|
{
|
|
|
|
int g_fw_crc;
|
|
int tempaddr=0x15800; //0xc9d0;
|
|
int i=0;
|
|
int result = NO_ERR;
|
|
|
|
I("%s: update firmware with UID number, \n", __func__);
|
|
g_remodify_fw_len = fw_entry->size;
|
|
g_remodify_fw = kzalloc(sizeof(char)*g_remodify_fw_len, GFP_KERNEL);
|
|
|
|
if (g_remodify_fw != NULL) {
|
|
memcpy(g_remodify_fw, fw_entry->data, sizeof(char)*g_remodify_fw_len);
|
|
I("%s: orignal fw_len = %d ; orignal_fw checksum= %02X%02X%02X%02X\n",
|
|
__func__, g_remodify_fw_len, g_remodify_fw[g_remodify_fw_len-4], g_remodify_fw[g_remodify_fw_len-3], g_remodify_fw[g_remodify_fw_len-2], g_remodify_fw[g_remodify_fw_len-1]);
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
g_remodify_fw[tempaddr+i]=g_password[i];
|
|
|
|
I("%s: g_remodify_fw-password = %02X\n",__func__, g_password[i]);
|
|
|
|
}
|
|
|
|
g_fw_crc = hx_s_core_fp._calc_crc_by_ap(g_remodify_fw,0, g_remodify_fw_len-4);
|
|
I("Now g_fw_crc=%X\n", g_fw_crc);
|
|
g_remodify_fw[g_remodify_fw_len-4] = (uint8_t)((g_fw_crc)&0X000000FF);
|
|
g_remodify_fw[g_remodify_fw_len-3] = (uint8_t)((g_fw_crc>>8)&0X000000FF);
|
|
g_remodify_fw[g_remodify_fw_len-2] = (uint8_t)((g_fw_crc>>16)&0X000000FF);
|
|
g_remodify_fw[g_remodify_fw_len-1] = (uint8_t)((g_fw_crc>>24)&0X000000FF);
|
|
|
|
I("%s: g_remodify_fw checksum = %02X%02X%02X%02X\n",
|
|
__func__, g_remodify_fw[g_remodify_fw_len-4], g_remodify_fw[g_remodify_fw_len-3], g_remodify_fw[g_remodify_fw_len-2], g_remodify_fw[g_remodify_fw_len-1]);
|
|
|
|
} else {
|
|
E("%s,%d: Allocate Memory Fail !!!!!\n", __func__, __LINE__);
|
|
result = MEM_ALLOC_FAIL;
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
static int i_get_FW(void)
|
|
{
|
|
int ret = -1;
|
|
int result = NO_ERR;
|
|
|
|
ret = request_firmware(&hxfw, g_fw_boot_upgrade_name, hx_s_ts->dev);
|
|
I("%s: request file %s finished\n", __func__, g_fw_boot_upgrade_name);
|
|
#if defined(HX_UID_PASSWORD)
|
|
if (ret == 0) {
|
|
result=i_add_uid_for_FW(hxfw);
|
|
}
|
|
|
|
#endif
|
|
if (ret < 0) {
|
|
#if defined(HX_FIRMWARE_HEADER)
|
|
hx_get_embedded_fw(HX_FWTYPE_NORMAL);
|
|
if (hx_s_ts->is_set_embedded_fw == 1) {
|
|
hxfw = &hx_s_ts->_embedded_fw;
|
|
I("%s: Not find FW, use Header FW(size:%zu)",
|
|
__func__, hxfw->size);
|
|
result = HX_EMBEDDED_FW;
|
|
} else {
|
|
E("%s,%d: error code = %d\n", __func__, __LINE__, ret);
|
|
result = OPEN_FILE_FAIL;
|
|
}
|
|
#else
|
|
E("%s,%d: error code = %d\n", __func__, __LINE__, ret);
|
|
result = OPEN_FILE_FAIL;
|
|
#endif
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static int i_update_FW(void)
|
|
{
|
|
int upgrade_times = 0;
|
|
int8_t ret = 0;
|
|
int8_t result = 0;
|
|
|
|
update_retry:
|
|
#if defined(HX_ZERO_FLASH)
|
|
|
|
ret = hx_s_core_fp._firmware_update_0f(hxfw, 0);
|
|
if (ret != 0) {
|
|
upgrade_times++;
|
|
E("%s: TP upgrade error, upgrade_times = %d\n",
|
|
__func__, upgrade_times);
|
|
|
|
if (upgrade_times < 3)
|
|
goto update_retry;
|
|
else
|
|
result = -1;
|
|
|
|
} else {
|
|
result = 1;/*upgrade success*/
|
|
I("%s: TP upgrade OK\n", __func__);
|
|
}
|
|
|
|
#else
|
|
I("%s:Now fw size = %d!\n", __func__, (int)hxfw->size);
|
|
#if defined(HX_UID_PASSWORD)
|
|
ret = hx_s_core_fp._fts_ctpm_fw_upgrade_with_sys_fs(
|
|
(unsigned char *)g_remodify_fw, g_remodify_fw_len, false);
|
|
#else
|
|
ret = hx_s_core_fp._fts_ctpm_fw_upgrade_with_sys_fs(
|
|
(unsigned char *)hxfw->data, hxfw->size, false);
|
|
#endif
|
|
if (ret == 0) {
|
|
upgrade_times++;
|
|
E("%s: TP upgrade error, upgrade_times = %d\n",
|
|
__func__, upgrade_times);
|
|
|
|
if (upgrade_times < 3)
|
|
goto update_retry;
|
|
else
|
|
result = -1;
|
|
|
|
} else {
|
|
result = 1;/*upgrade success*/
|
|
I("%s: TP upgrade OK\n", __func__);
|
|
}
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
/*
|
|
*static int himax_loadSensorConfig(struct himax_platform_data *pdata)
|
|
*{
|
|
* I("%s: initialization complete\n", __func__);
|
|
* return NO_ERR;
|
|
*}
|
|
*/
|
|
#if defined(HX_EXCP_RECOVERY)
|
|
static void himax_excp_hw_reset(void)
|
|
{
|
|
#if defined(HX_ZERO_FLASH)
|
|
int result = 0;
|
|
#endif
|
|
I("%s: START EXCEPTION Reset\n", __func__);
|
|
#if defined(HX_ZERO_FLASH)
|
|
result = hx_s_core_fp._0f_op_file_dirly(g_fw_boot_upgrade_name);
|
|
if (result)
|
|
E("%s: update FW fail, code[%d]!!\n", __func__, result);
|
|
#else
|
|
hx_s_core_fp._excp_ic_reset();
|
|
#endif
|
|
himax_report_all_leave_event(hx_s_ts);
|
|
if (hx_s_ts->diag_cmd != 0)
|
|
hx_s_core_fp._diag_register_set(hx_s_ts->diag_cmd,
|
|
hx_s_ts->diag_storage_type,
|
|
hx_s_ts->diag_dirly);
|
|
I("%s: END EXCEPTION Reset\n", __func__);
|
|
}
|
|
#endif
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
#if defined(HX_GESTURE_TRACK)
|
|
static void gest_pt_log_coordinate(int rx, int tx)
|
|
{
|
|
/*driver report x y with range 0 - 255 , we scale it up to x/y pixel*/
|
|
gest_pt_x[gest_pt_cnt] = rx * (hx_s_ic_data->x_res) / 255;
|
|
gest_pt_y[gest_pt_cnt] = tx * (hx_s_ic_data->y_res) / 255;
|
|
}
|
|
#endif
|
|
static int himax_wake_event_parse(struct himax_ts_data *ts, int ts_status)
|
|
{
|
|
uint8_t *buf = wake_event_buffer;
|
|
#if defined(HX_GESTURE_TRACK)
|
|
int tmp_max_x = 0x00;
|
|
int tmp_min_x = 0xFFFF;
|
|
int tmp_max_y = 0x00;
|
|
int tmp_min_y = 0xFFFF;
|
|
int gest_len;
|
|
#endif
|
|
int i = 0, check_FC = 0, ret;
|
|
int j = 0, gesture_pos = 0, gesture_flag = 0;
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: Entering!, ts_status=%d\n", __func__, ts_status);
|
|
|
|
if (buf == NULL) {
|
|
ret = -ENOMEM;
|
|
goto END;
|
|
}
|
|
|
|
memcpy(buf, hx_s_touch_data->event_buf, hx_s_touch_data->event_size);
|
|
|
|
for (i = 0; i < GEST_PTLG_ID_LEN; i++) {
|
|
for (j = 0; j < GEST_SUP_NUM; j++) {
|
|
if (buf[i] == gest_event[j]) {
|
|
gesture_flag = buf[i];
|
|
gesture_pos = j;
|
|
break;
|
|
}
|
|
}
|
|
I("0x%2.2X ", buf[i]);
|
|
if (buf[i] == gesture_flag) {
|
|
check_FC++;
|
|
} else {
|
|
I("ID START at %x , value = 0x%2X skip the event\n",
|
|
i, buf[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
I("Himax gesture_flag= %x\n", gesture_flag);
|
|
I("Himax check_FC is %d\n", check_FC);
|
|
|
|
if (check_FC != GEST_PTLG_ID_LEN) {
|
|
ret = 0;
|
|
goto END;
|
|
}
|
|
|
|
if (buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1
|
|
|| buf[GEST_PTLG_ID_LEN + 1] != GEST_PTLG_HDR_ID2) {
|
|
ret = 0;
|
|
goto END;
|
|
}
|
|
|
|
#if defined(HX_GESTURE_TRACK)
|
|
|
|
if (buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1
|
|
&& buf[GEST_PTLG_ID_LEN + 1] == GEST_PTLG_HDR_ID2) {
|
|
gest_len = buf[GEST_PTLG_ID_LEN + 2];
|
|
I("gest_len = %d\n", gest_len);
|
|
i = 0;
|
|
gest_pt_cnt = 0;
|
|
I("gest doornidate start\n %s", __func__);
|
|
|
|
while (i < (gest_len + 1) / 2) {
|
|
gest_pt_log_coordinate(
|
|
buf[GEST_PTLG_ID_LEN + 4 + i * 2],
|
|
buf[GEST_PTLG_ID_LEN + 4 + i * 2 + 1]);
|
|
i++;
|
|
I("gest_pt_x[%d]=%d,gest_pt_y[%d]=%d\n",
|
|
gest_pt_cnt,
|
|
gest_pt_x[gest_pt_cnt],
|
|
gest_pt_cnt,
|
|
gest_pt_y[gest_pt_cnt]);
|
|
gest_pt_cnt += 1;
|
|
}
|
|
|
|
if (gest_pt_cnt) {
|
|
for (i = 0; i < gest_pt_cnt; i++) {
|
|
if (tmp_max_x < gest_pt_x[i])
|
|
tmp_max_x = gest_pt_x[i];
|
|
if (tmp_min_x > gest_pt_x[i])
|
|
tmp_min_x = gest_pt_x[i];
|
|
if (tmp_max_y < gest_pt_y[i])
|
|
tmp_max_y = gest_pt_y[i];
|
|
if (tmp_min_y > gest_pt_y[i])
|
|
tmp_min_y = gest_pt_y[i];
|
|
}
|
|
|
|
I("gest_point x_min=%d,x_max=%d,y_min=%d,y_max=%d\n",
|
|
tmp_min_x, tmp_max_x, tmp_min_y, tmp_max_y);
|
|
|
|
gest_start_x = gest_pt_x[0];
|
|
hx_gesture_coor[0] = gest_start_x;
|
|
gest_start_y = gest_pt_y[0];
|
|
hx_gesture_coor[1] = gest_start_y;
|
|
gest_end_x = gest_pt_x[gest_pt_cnt - 1];
|
|
hx_gesture_coor[2] = gest_end_x;
|
|
gest_end_y = gest_pt_y[gest_pt_cnt - 1];
|
|
hx_gesture_coor[3] = gest_end_y;
|
|
gest_width = tmp_max_x - tmp_min_x;
|
|
hx_gesture_coor[4] = gest_width;
|
|
gest_height = tmp_max_y - tmp_min_y;
|
|
hx_gesture_coor[5] = gest_height;
|
|
gest_mid_x = (tmp_max_x + tmp_min_x) / 2;
|
|
hx_gesture_coor[6] = gest_mid_x;
|
|
gest_mid_y = (tmp_max_y + tmp_min_y) / 2;
|
|
hx_gesture_coor[7] = gest_mid_y;
|
|
/*gest_up_x*/
|
|
hx_gesture_coor[8] = gest_mid_x;
|
|
/*gest_up_y*/
|
|
hx_gesture_coor[9] = gest_mid_y - gest_height / 2;
|
|
/*gest_down_x*/
|
|
hx_gesture_coor[10] = gest_mid_x;
|
|
/*gest_down_y*/
|
|
hx_gesture_coor[11] = gest_mid_y + gest_height / 2;
|
|
/*gest_left_x*/
|
|
hx_gesture_coor[12] = gest_mid_x - gest_width / 2;
|
|
/*gest_left_y*/
|
|
hx_gesture_coor[13] = gest_mid_y;
|
|
/*gest_right_x*/
|
|
hx_gesture_coor[14] = gest_mid_x + gest_width / 2;
|
|
/*gest_right_y*/
|
|
hx_gesture_coor[15] = gest_mid_y;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!ts->gesture_cust_en[gesture_pos]) {
|
|
I("%s NOT report key [%d] = %d\n", __func__,
|
|
gesture_pos, gest_key_def[gesture_pos]);
|
|
g_target_report_data->SMWP_event_chk = 0;
|
|
ret = 0;
|
|
} else {
|
|
g_target_report_data->SMWP_event_chk =
|
|
gest_key_def[gesture_pos];
|
|
ret = gesture_pos;
|
|
}
|
|
END:
|
|
return ret;
|
|
}
|
|
|
|
static void himax_wake_event_report(void)
|
|
{
|
|
int KEY_EVENT = g_target_report_data->SMWP_event_chk;
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: Entering!\n", __func__);
|
|
|
|
if (KEY_EVENT) {
|
|
I("%s SMART WAKEUP KEY event %d press\n", __func__, KEY_EVENT);
|
|
input_report_key(hx_s_ts->input_dev, KEY_EVENT, 1);
|
|
input_sync(hx_s_ts->input_dev);
|
|
I("%s SMART WAKEUP KEY event %d release\n",
|
|
__func__, KEY_EVENT);
|
|
input_report_key(hx_s_ts->input_dev, KEY_EVENT, 0);
|
|
input_sync(hx_s_ts->input_dev);
|
|
#if defined(HX_GESTURE_TRACK)
|
|
I("gest_start_x=%d,start_y=%d,end_x=%d,end_y=%d\n",
|
|
gest_start_x,
|
|
gest_start_y,
|
|
gest_end_x,
|
|
gest_end_y);
|
|
I("gest_width=%d,height=%d,mid_x=%d,mid_y=%d\n",
|
|
gest_width,
|
|
gest_height,
|
|
gest_mid_x,
|
|
gest_mid_y);
|
|
I("gest_up_x=%d,up_y=%d,down_x=%d,down_y=%d\n",
|
|
hx_gesture_coor[8],
|
|
hx_gesture_coor[9],
|
|
hx_gesture_coor[10],
|
|
hx_gesture_coor[11]);
|
|
I("gest_left_x=%d,left_y=%d,right_x=%d,right_y=%d\n",
|
|
hx_gesture_coor[12],
|
|
hx_gesture_coor[13],
|
|
hx_gesture_coor[14],
|
|
hx_gesture_coor[15]);
|
|
#endif
|
|
g_target_report_data->SMWP_event_chk = 0;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
int himax_report_data_init(void)
|
|
{
|
|
if (hx_s_touch_data->coord_buf != NULL) {
|
|
kfree(hx_s_touch_data->coord_buf);
|
|
hx_s_touch_data->coord_buf = NULL;
|
|
}
|
|
|
|
if (hx_s_touch_data->rawdata_buf != NULL) {
|
|
kfree(hx_s_touch_data->rawdata_buf);
|
|
hx_s_touch_data->rawdata_buf = NULL;
|
|
}
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
hx_s_touch_data->event_size = hx_s_core_fp._get_touch_data_size();
|
|
|
|
if (hx_s_touch_data->event_buf != NULL) {
|
|
kfree(hx_s_touch_data->event_buf);
|
|
hx_s_touch_data->event_buf = NULL;
|
|
}
|
|
|
|
if (wake_event_buffer != NULL) {
|
|
kfree(wake_event_buffer);
|
|
wake_event_buffer = NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
if (g_target_report_data != NULL) {
|
|
if (hx_s_ic_data->stylus_func) {
|
|
kfree(g_target_report_data->s);
|
|
g_target_report_data->s = NULL;
|
|
}
|
|
|
|
kfree(g_target_report_data->p);
|
|
g_target_report_data->p = NULL;
|
|
kfree(g_target_report_data);
|
|
g_target_report_data = NULL;
|
|
}
|
|
|
|
hx_s_touch_data->touch_all_size =
|
|
HX_FULL_STACK_RAWDATA_SIZE;
|
|
hx_s_touch_data->touch_all_size_full_stack =
|
|
HX_FULL_STACK_RAWDATA_SIZE;
|
|
hx_s_touch_data->touch_all_size_normal =
|
|
hx_s_core_fp._get_touch_data_size();
|
|
|
|
hx_s_touch_data->raw_cnt_max = hx_s_ic_data->max_pt / 4;
|
|
hx_s_touch_data->raw_cnt_rmd = hx_s_ic_data->max_pt % 4;
|
|
/* more than 4 fingers */
|
|
if (hx_s_touch_data->raw_cnt_rmd != 0x00) {
|
|
hx_s_touch_data->rawdata_size =
|
|
hx_s_core_fp._cal_data_len(
|
|
hx_s_touch_data->raw_cnt_rmd,
|
|
hx_s_ic_data->max_pt,
|
|
hx_s_touch_data->raw_cnt_max);
|
|
|
|
hx_s_touch_data->touch_info_size = (hx_s_ic_data->max_pt
|
|
+ hx_s_touch_data->raw_cnt_max + 2) * 4;
|
|
} else { /* less than 4 fingers */
|
|
hx_s_touch_data->rawdata_size =
|
|
hx_s_core_fp._cal_data_len(
|
|
hx_s_touch_data->raw_cnt_rmd,
|
|
hx_s_ic_data->max_pt,
|
|
hx_s_touch_data->raw_cnt_max);
|
|
|
|
hx_s_touch_data->touch_info_size = (hx_s_ic_data->max_pt
|
|
+ hx_s_touch_data->raw_cnt_max + 1) * 4;
|
|
}
|
|
|
|
if (hx_s_ic_data->stylus_func) {
|
|
hx_s_touch_data->touch_info_size += STYLUS_INFO_SZ;
|
|
hx_s_touch_data->rawdata_size -= STYLUS_INFO_SZ;
|
|
}
|
|
|
|
// hx_s_touch_data->touch_info_size = HX_STACK_ORG_LEN;
|
|
hx_s_touch_data->rawdata_size_normal =
|
|
hx_s_touch_data->rawdata_size;
|
|
// hx_s_touch_data->rawdata_size =
|
|
// hx_s_touch_data->touch_all_size - HX_STACK_ORG_LEN;
|
|
hx_s_touch_data->rawdata_size_full_stack =
|
|
hx_s_touch_data->touch_all_size - HX_STACK_ORG_LEN;
|
|
|
|
if ((hx_s_ic_data->tx_num
|
|
* hx_s_ic_data->rx_num
|
|
+ hx_s_ic_data->tx_num
|
|
+ hx_s_ic_data->rx_num)
|
|
% hx_s_touch_data->rawdata_size == 0)
|
|
hx_s_touch_data->rawdata_frame_size =
|
|
(hx_s_ic_data->tx_num
|
|
* hx_s_ic_data->rx_num
|
|
+ hx_s_ic_data->tx_num
|
|
+ hx_s_ic_data->rx_num)
|
|
/ hx_s_touch_data->rawdata_size;
|
|
else
|
|
hx_s_touch_data->rawdata_frame_size =
|
|
(hx_s_ic_data->tx_num
|
|
* hx_s_ic_data->rx_num
|
|
+ hx_s_ic_data->tx_num
|
|
+ hx_s_ic_data->rx_num)
|
|
/ hx_s_touch_data->rawdata_size
|
|
+ 1;
|
|
|
|
I("%s:rawdata_fsz = %d,max_pt:%d,hx_raw_cnt_max:%d\n",
|
|
__func__,
|
|
hx_s_touch_data->rawdata_frame_size,
|
|
hx_s_ic_data->max_pt,
|
|
hx_s_touch_data->raw_cnt_max);
|
|
I("%s:hx_raw_cnt_rmd:%d,g_hx_rawdata_size:%d,touch_info_size:%d\n",
|
|
__func__,
|
|
hx_s_touch_data->raw_cnt_rmd,
|
|
hx_s_touch_data->rawdata_size,
|
|
hx_s_touch_data->touch_info_size);
|
|
|
|
hx_s_touch_data->coord_buf = kzalloc(sizeof(uint8_t)
|
|
* (hx_s_touch_data->touch_info_size),
|
|
GFP_KERNEL);
|
|
|
|
if (hx_s_touch_data->coord_buf == NULL)
|
|
goto mem_alloc_fail_coord_buf;
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
wake_event_buffer = kcalloc(hx_s_touch_data->event_size,
|
|
sizeof(uint8_t), GFP_KERNEL);
|
|
if (wake_event_buffer == NULL)
|
|
goto mem_alloc_fail_smwp;
|
|
|
|
hx_s_touch_data->event_buf = kzalloc(sizeof(uint8_t)
|
|
* (hx_s_touch_data->event_size), GFP_KERNEL);
|
|
if (hx_s_touch_data->event_buf == NULL)
|
|
goto mem_alloc_fail_event_buf;
|
|
#endif
|
|
|
|
hx_s_touch_data->rawdata_buf = kzalloc(sizeof(uint8_t)
|
|
* (hx_s_touch_data->touch_all_size
|
|
- HX_STACK_ORG_LEN),
|
|
GFP_KERNEL);
|
|
|
|
if (hx_s_touch_data->rawdata_buf == NULL)
|
|
goto mem_alloc_fail_rawdata_buf;
|
|
|
|
if (g_target_report_data == NULL) {
|
|
g_target_report_data =
|
|
kzalloc(sizeof(struct himax_target_report_data),
|
|
GFP_KERNEL);
|
|
if (g_target_report_data == NULL)
|
|
goto mem_alloc_fail_report_data;
|
|
/*
|
|
*#if defined(HX_SMART_WAKEUP)
|
|
* g_target_report_data->SMWP_event_chk = 0;
|
|
*#endif
|
|
* I("%s: SMWP_event_chk = %d\n", __func__,
|
|
* g_target_report_data->SMWP_event_chk);
|
|
*/
|
|
|
|
g_target_report_data->p = kzalloc(
|
|
sizeof(struct himax_target_point_data)
|
|
*(hx_s_ic_data->max_pt), GFP_KERNEL);
|
|
if (g_target_report_data->p == NULL)
|
|
goto mem_alloc_fail_report_data_p;
|
|
|
|
if (!hx_s_ic_data->stylus_func)
|
|
goto skip_stylus_operation;
|
|
|
|
g_target_report_data->s = kzalloc(
|
|
sizeof(struct himax_target_stylus_data)*2, GFP_KERNEL);
|
|
if (g_target_report_data->s == NULL)
|
|
goto mem_alloc_fail_report_data_s;
|
|
}
|
|
|
|
skip_stylus_operation:
|
|
hx_s_touch_data->touch_all_size =
|
|
hx_s_touch_data->touch_all_size_normal;
|
|
hx_s_touch_data->rawdata_size =
|
|
hx_s_touch_data->rawdata_size_normal;
|
|
return NO_ERR;
|
|
|
|
mem_alloc_fail_report_data_s:
|
|
kfree(g_target_report_data->p);
|
|
g_target_report_data->p = NULL;
|
|
mem_alloc_fail_report_data_p:
|
|
kfree(g_target_report_data);
|
|
g_target_report_data = NULL;
|
|
mem_alloc_fail_report_data:
|
|
kfree(hx_s_touch_data->rawdata_buf);
|
|
hx_s_touch_data->rawdata_buf = NULL;
|
|
mem_alloc_fail_rawdata_buf:
|
|
#if defined(HX_SMART_WAKEUP)
|
|
kfree(hx_s_touch_data->event_buf);
|
|
hx_s_touch_data->event_buf = NULL;
|
|
mem_alloc_fail_event_buf:
|
|
kfree(wake_event_buffer);
|
|
wake_event_buffer = NULL;
|
|
mem_alloc_fail_smwp:
|
|
#endif
|
|
kfree(hx_s_touch_data->coord_buf);
|
|
hx_s_touch_data->coord_buf = NULL;
|
|
mem_alloc_fail_coord_buf:
|
|
|
|
E("%s: Failed to allocate memory\n", __func__);
|
|
return MEM_ALLOC_FAIL;
|
|
}
|
|
EXPORT_SYMBOL(himax_report_data_init);
|
|
|
|
void himax_report_data_deinit(void)
|
|
{
|
|
if (hx_s_ic_data->stylus_func) {
|
|
kfree(g_target_report_data->s);
|
|
g_target_report_data->s = NULL;
|
|
}
|
|
|
|
kfree(g_target_report_data->p);
|
|
g_target_report_data->p = NULL;
|
|
kfree(g_target_report_data);
|
|
g_target_report_data = NULL;
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
kfree(wake_event_buffer);
|
|
wake_event_buffer = NULL;
|
|
kfree(hx_s_touch_data->event_buf);
|
|
hx_s_touch_data->event_buf = NULL;
|
|
#endif
|
|
kfree(hx_s_touch_data->rawdata_buf);
|
|
hx_s_touch_data->rawdata_buf = NULL;
|
|
kfree(hx_s_touch_data->coord_buf);
|
|
hx_s_touch_data->coord_buf = NULL;
|
|
}
|
|
|
|
/*start ts_work*/
|
|
#if defined(HX_USB_DETECT_GLOBAL)
|
|
void himax_cable_detect_func(bool force_renew)
|
|
{
|
|
struct himax_ts_data *ts;
|
|
|
|
/*u32 connect_status = 0;*/
|
|
uint8_t connect_status = 0;
|
|
|
|
connect_status = USB_detect_flag;/* upmu_is_chr_det(); */
|
|
ts = hx_s_ts;
|
|
|
|
/* I("Touch: cable status=%d, cable_config=%p, usb_connected=%d\n",*/
|
|
/* connect_status, ts->cable_config, ts->usb_connected); */
|
|
if (ts->cable_config) {
|
|
if ((connect_status != ts->usb_connected) || force_renew) {
|
|
if (connect_status) {
|
|
ts->cable_config[1] = 0x01;
|
|
ts->usb_connected = 0x01;
|
|
} else {
|
|
ts->cable_config[1] = 0x00;
|
|
ts->usb_connected = 0x00;
|
|
}
|
|
|
|
hx_s_core_fp._usb_detect_set(ts->cable_config);
|
|
I("%s: Cable status change: 0x%2.2X\n", __func__,
|
|
ts->usb_connected);
|
|
}
|
|
|
|
/*else*/
|
|
/* I("%s: Cable status is the same as*/
|
|
/* previous one, ignore.\n", __func__);*/
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int himax_ts_work_status(struct himax_ts_data *ts)
|
|
{
|
|
/* 1: normal, 2:SMWP */
|
|
int result = HX_REPORT_COORD;
|
|
|
|
hx_s_touch_data->diag_cmd = ts->diag_cmd;
|
|
if (hx_s_touch_data->diag_cmd)
|
|
result = HX_REPORT_COORD_RAWDATA;
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
if (atomic_read(&ts->suspend_mode)
|
|
&& (ts->SMWP_enable)
|
|
&& (!hx_s_touch_data->diag_cmd))
|
|
result = HX_REPORT_SMWP_EVENT;
|
|
#endif
|
|
/* I("Now Status is %d\n", result); */
|
|
return result;
|
|
}
|
|
|
|
static int himax_touch_get(struct himax_ts_data *ts, uint8_t *buf,
|
|
int ts_path, int ts_status)
|
|
{
|
|
uint32_t read_size = 0;
|
|
|
|
if (g_ts_dbg != 0) {
|
|
I("%s: Entering, ts_status=%d!\n",
|
|
__func__, ts_status);
|
|
I("%s: Max Size=%d\n",
|
|
__func__, hx_s_touch_data->touch_all_size);
|
|
}
|
|
|
|
switch (ts_path) {
|
|
/*normal*/
|
|
case HX_REPORT_COORD:
|
|
if ((g_hw_rst_activate)
|
|
#if defined(HX_EXCP_RECOVERY)
|
|
|| (HX_EXCP_RESET_ACTIVATE)
|
|
#endif
|
|
) {
|
|
read_size = hx_s_touch_data->touch_all_size;
|
|
} else {
|
|
read_size = hx_s_touch_data->touch_info_size;
|
|
}
|
|
break;
|
|
#if defined(HX_SMART_WAKEUP)
|
|
|
|
/*SMWP*/
|
|
case HX_REPORT_SMWP_EVENT:
|
|
__pm_wakeup_event(ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT);
|
|
msleep(20);
|
|
read_size = hx_s_touch_data->event_size;
|
|
|
|
break;
|
|
#endif
|
|
case HX_REPORT_COORD_RAWDATA:
|
|
read_size = hx_s_touch_data->touch_all_size;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (read_size == 0) {
|
|
E("%s: Read size fault!\n", __func__);
|
|
ts_status = HX_TS_GET_DATA_FAIL;
|
|
} else {
|
|
if (!hx_s_core_fp._read_event_stack(buf, read_size)) {
|
|
E("%s: can't read data from chip!\n", __func__);
|
|
ts_status = HX_TS_GET_DATA_FAIL;
|
|
}
|
|
}
|
|
|
|
return ts_status;
|
|
}
|
|
|
|
/* start error_control*/
|
|
static int himax_checksum_cal(struct himax_ts_data *ts, uint8_t *buf,
|
|
int ts_path, int ts_status)
|
|
{
|
|
uint16_t check_sum_cal = 0;
|
|
int32_t i = 0;
|
|
int length = 0;
|
|
int zero_cnt = 0;
|
|
int raw_data_sel = 0;
|
|
int ret_val = ts_status;
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: Entering, ts_status=%d!\n", __func__, ts_status);
|
|
|
|
/* Normal */
|
|
switch (ts_path) {
|
|
case HX_REPORT_COORD:
|
|
length = hx_s_touch_data->touch_info_size;
|
|
break;
|
|
#if defined(HX_SMART_WAKEUP)
|
|
/* SMWP */
|
|
case HX_REPORT_SMWP_EVENT:
|
|
length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN);
|
|
break;
|
|
#endif
|
|
case HX_REPORT_COORD_RAWDATA:
|
|
length = hx_s_touch_data->touch_info_size;
|
|
break;
|
|
default:
|
|
I("%s, Neither Normal Nor SMWP error!\n", __func__);
|
|
ret_val = HX_PATH_FAIL;
|
|
goto END_FUNCTION;
|
|
}
|
|
|
|
for (i = 0; i < length; i++) {
|
|
check_sum_cal += buf[i];
|
|
if (buf[i] == 0x00)
|
|
zero_cnt++;
|
|
}
|
|
|
|
if (check_sum_cal % 0x100 != 0) {
|
|
I("point data_checksum not match check_sum_cal: 0x%02X",
|
|
check_sum_cal);
|
|
ret_val = HX_CHKSUM_FAIL;
|
|
} else if (zero_cnt == length) {
|
|
if (ts->use_irq)
|
|
I("[HIMAX TP MSG] All Zero event\n");
|
|
|
|
ret_val = HX_CHKSUM_FAIL;
|
|
} else {
|
|
raw_data_sel = buf[HX_TOUCH_INFO_POINT_CNT]>>4 & 0x0F;
|
|
/*I("%s:raw_out_sel=%x , hx_s_touch_data->diag_cmd=%x.\n",*/
|
|
/* __func__, raw_data_sel,*/
|
|
/* hx_s_touch_data->diag_cmd);*/
|
|
/*raw data out not match skip it*/
|
|
if (g_ts_dbg != 0)
|
|
I("%s: skip check rawout select, now val=%d!\n",
|
|
__func__, raw_data_sel);
|
|
if (!hx_s_debug_data->
|
|
is_stack_full_raw) {
|
|
if ((raw_data_sel != 0x0F)
|
|
&& (raw_data_sel != hx_s_touch_data->diag_cmd)) {
|
|
/*I("%s:raw data out not match.\n", __func__);*/
|
|
if (!hx_s_touch_data->diag_cmd) {
|
|
/*Need to clear event stack here*/
|
|
hx_s_core_fp._read_event_stack(buf,
|
|
(HX_STACK_ORG_LEN -
|
|
hx_s_touch_data->
|
|
touch_info_size));
|
|
}
|
|
ret_val = HX_READY_SERVE;
|
|
}
|
|
}
|
|
}
|
|
|
|
END_FUNCTION:
|
|
if (g_ts_dbg != 0)
|
|
I("%s: END, ret_val=%d!\n", __func__, ret_val);
|
|
return ret_val;
|
|
}
|
|
|
|
#if defined(HX_EXCP_RECOVERY)
|
|
#if defined(HW_ED_EXCP_EVENT)
|
|
static int himax_ts_event_check(struct himax_ts_data *ts,
|
|
const uint8_t *buf, int ts_path, int ts_status)
|
|
{
|
|
uint32_t hx_EB_event = 0;
|
|
uint32_t hx_EC_event = 0;
|
|
uint32_t hx_EE_event = 0;
|
|
uint32_t hx_ED_event = 0;
|
|
uint32_t hx_excp_event = 0;
|
|
int shaking_ret = 0;
|
|
|
|
uint32_t i = 0;
|
|
uint32_t length = 0;
|
|
int ret_val = ts_status;
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: Entering, ts_status=%d!\n", __func__, ts_status);
|
|
|
|
/* Normal */
|
|
switch (ts_path) {
|
|
case HX_REPORT_COORD:
|
|
length = hx_s_touch_data->touch_info_size;
|
|
break;
|
|
#if defined(HX_SMART_WAKEUP)
|
|
/* SMWP */
|
|
case HX_REPORT_SMWP_EVENT:
|
|
length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN);
|
|
break;
|
|
#endif
|
|
case HX_REPORT_COORD_RAWDATA:
|
|
length = hx_s_touch_data->touch_info_size;
|
|
break;
|
|
default:
|
|
I("%s, Neither Normal Nor SMWP error!\n", __func__);
|
|
ret_val = HX_PATH_FAIL;
|
|
goto END_FUNCTION;
|
|
}
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("Now Path=%d, Now status=%d, length=%d\n",
|
|
ts_path, ts_status, length);
|
|
|
|
if (ts_path == HX_REPORT_COORD || ts_path == HX_REPORT_COORD_RAWDATA) {
|
|
if (hx_s_ic_data->stylus_func)
|
|
length -= STYLUS_INFO_SZ;
|
|
for (i = 0; i < length; i++) {
|
|
/* case 1 EXCEEPTION recovery flow */
|
|
if (buf[i] == 0xEB) {
|
|
hx_EB_event++;
|
|
} else if (buf[i] == 0xEC) {
|
|
hx_EC_event++;
|
|
} else if (buf[i] == 0xEE) {
|
|
hx_EE_event++;
|
|
/* case 2 EXCEPTION recovery flow-Disable */
|
|
} else if (buf[i] == 0xED) {
|
|
hx_ED_event++;
|
|
} else {
|
|
g_zero_event_count = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hx_EB_event == length) {
|
|
hx_excp_event = length;
|
|
g_flag_eb_event++;
|
|
I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEB.\n");
|
|
} else if (hx_EC_event == length) {
|
|
hx_excp_event = length;
|
|
g_flag_ec_event++;
|
|
I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEC.\n");
|
|
} else if (hx_EE_event == length) {
|
|
hx_excp_event = length;
|
|
g_flag_ee_event++;
|
|
I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEE.\n");
|
|
} else if (hx_ED_event == length) {
|
|
hx_s_core_fp._0f_reload_to_active();
|
|
}
|
|
|
|
if ((hx_excp_event == length || hx_ED_event == length)
|
|
&& (g_hw_rst_activate == 0)
|
|
&& (HX_EXCP_RESET_ACTIVATE == 0)
|
|
&& (hx_s_touch_data->diag_cmd == 0)) {
|
|
shaking_ret = hx_s_core_fp._ic_excp_recovery(
|
|
hx_excp_event, hx_ED_event, length);
|
|
|
|
if (shaking_ret == HX_EXCP_EVENT) {
|
|
hx_s_core_fp._read_FW_status();
|
|
himax_excp_hw_reset();
|
|
ret_val = HX_EXCP_EVENT;
|
|
} else if (shaking_ret == HX_ZERO_EVENT_COUNT) {
|
|
hx_s_core_fp._read_FW_status();
|
|
ret_val = HX_ZERO_EVENT_COUNT;
|
|
} else {
|
|
I("IC is running. Nothing to be done!\n");
|
|
ret_val = HX_IC_RUNNING;
|
|
}
|
|
|
|
/* drop 1st interrupts after chip reset */
|
|
} else if (HX_EXCP_RESET_ACTIVATE) {
|
|
HX_EXCP_RESET_ACTIVATE = 0;
|
|
I("%s: Skip by HX_EXCP_RESET_ACTIVATE.\n", __func__);
|
|
ret_val = HX_EXCP_REC_OK;
|
|
}
|
|
|
|
END_FUNCTION:
|
|
if (g_ts_dbg != 0)
|
|
I("%s: END, ret_val=%d!\n", __func__, ret_val);
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
#else
|
|
static int himax_ts_event_check(struct himax_ts_data *ts,
|
|
const uint8_t *buf, int ts_path, int ts_status)
|
|
{
|
|
uint32_t hx_EB_event = 0;
|
|
uint32_t hx_EC_event = 0;
|
|
uint32_t hx_ED_event = 0;
|
|
uint32_t hx_excp_event = 0;
|
|
uint32_t hx_zero_event = 0;
|
|
int shaking_ret = 0;
|
|
|
|
uint32_t i = 0;
|
|
uint32_t length = 0;
|
|
int ret_val = ts_status;
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: Entering, ts_status=%d!\n", __func__, ts_status);
|
|
|
|
/* Normal */
|
|
switch (ts_path) {
|
|
case HX_REPORT_COORD:
|
|
length = hx_s_touch_data->touch_info_size;
|
|
break;
|
|
#if defined(HX_SMART_WAKEUP)
|
|
/* SMWP */
|
|
case HX_REPORT_SMWP_EVENT:
|
|
length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN);
|
|
break;
|
|
#endif
|
|
case HX_REPORT_COORD_RAWDATA:
|
|
length = hx_s_touch_data->touch_info_size;
|
|
break;
|
|
default:
|
|
I("%s, Neither Normal Nor SMWP error!\n", __func__);
|
|
ret_val = HX_PATH_FAIL;
|
|
goto END_FUNCTION;
|
|
}
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("Now Path=%d, Now status=%d, length=%d\n",
|
|
ts_path, ts_status, length);
|
|
|
|
if (ts_path == HX_REPORT_COORD || ts_path == HX_REPORT_COORD_RAWDATA) {
|
|
if (hx_s_ic_data->stylus_func)
|
|
length -= STYLUS_INFO_SZ;
|
|
for (i = 0; i < length; i++) {
|
|
/* case 1 EXCEEPTION recovery flow */
|
|
if (buf[i] == 0xEB) {
|
|
hx_EB_event++;
|
|
} else if (buf[i] == 0xEC) {
|
|
hx_EC_event++;
|
|
} else if (buf[i] == 0xED) {
|
|
hx_ED_event++;
|
|
|
|
/* case 2 EXCEPTION recovery flow-Disable */
|
|
} else if (buf[i] == 0x00) {
|
|
hx_zero_event++;
|
|
} else {
|
|
g_zero_event_count = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hx_EB_event == length) {
|
|
hx_excp_event = length;
|
|
g_flag_eb_event++;
|
|
I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEB.\n");
|
|
} else if (hx_EC_event == length) {
|
|
hx_excp_event = length;
|
|
g_flag_ec_event++;
|
|
I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEC.\n");
|
|
} else if (hx_ED_event == length) {
|
|
hx_excp_event = length;
|
|
g_flag_ed_event++;
|
|
I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xED.\n");
|
|
}
|
|
/*#if defined(HX_ZERO_FLASH)
|
|
* //This is for previous version(a, b) because HW pull TSIX
|
|
* low continuely after watchdog timeout reset
|
|
* else if (hx_zero_event == length) {
|
|
* //check zero flash status
|
|
* if (hx_s_core_fp._0f_esd_check() < 0) {
|
|
* g_zero_event_count = 6;
|
|
* I("[HIMAX TP MSG]: ESD event checked
|
|
- ALL Zero in ZF.\n");
|
|
* } else {
|
|
* I("[HIMAX TP MSG]: Status check pass in ZF.\n");
|
|
* }
|
|
* }
|
|
*#endif
|
|
*/
|
|
|
|
if ((hx_excp_event == length || hx_zero_event == length)
|
|
&& (g_hw_rst_activate == 0)
|
|
&& (HX_EXCP_RESET_ACTIVATE == 0)) {
|
|
shaking_ret = hx_s_core_fp._ic_excp_recovery(
|
|
hx_excp_event, hx_zero_event, length);
|
|
|
|
if (shaking_ret == HX_EXCP_EVENT) {
|
|
hx_s_core_fp._read_FW_status();
|
|
himax_excp_hw_reset();
|
|
ret_val = HX_EXCP_EVENT;
|
|
} else if (shaking_ret == HX_ZERO_EVENT_COUNT) {
|
|
hx_s_core_fp._read_FW_status();
|
|
ret_val = HX_ZERO_EVENT_COUNT;
|
|
} else {
|
|
I("IC is running. Nothing to be done!\n");
|
|
ret_val = HX_IC_RUNNING;
|
|
}
|
|
|
|
/* drop 1st interrupts after chip reset */
|
|
} else if (HX_EXCP_RESET_ACTIVATE) {
|
|
HX_EXCP_RESET_ACTIVATE = 0;
|
|
I("%s: Skip by HX_EXCP_RESET_ACTIVATE.\n", __func__);
|
|
ret_val = HX_EXCP_REC_OK;
|
|
}
|
|
|
|
END_FUNCTION:
|
|
if (g_ts_dbg != 0)
|
|
I("%s: END, ret_val=%d!\n", __func__, ret_val);
|
|
|
|
return ret_val;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
static int himax_err_ctrl(struct himax_ts_data *ts,
|
|
uint8_t *buf, int ts_path, int ts_status)
|
|
{
|
|
#if defined(HX_RST_PIN_FUNC)
|
|
if (g_hw_rst_activate) {
|
|
/* drop 1st interrupts after chip reset */
|
|
g_hw_rst_activate = 0;
|
|
I("[g_hw_rst_activate]%s:Back from reset,ready to serve.\n",
|
|
__func__);
|
|
ts_status = HX_RST_OK;
|
|
goto END_FUNCTION;
|
|
}
|
|
#endif
|
|
|
|
ts_status = himax_checksum_cal(ts, buf, ts_path, ts_status);
|
|
if (ts_status == HX_CHKSUM_FAIL) {
|
|
goto CHK_FAIL;
|
|
} else {
|
|
#if defined(HX_EXCP_RECOVERY)
|
|
/* continuous N times record, not total N times. */
|
|
g_zero_event_count = 0;
|
|
#endif
|
|
goto END_FUNCTION;
|
|
}
|
|
|
|
CHK_FAIL:
|
|
#if defined(HX_EXCP_RECOVERY)
|
|
ts_status = himax_ts_event_check(ts, buf, ts_path, ts_status);
|
|
#endif
|
|
|
|
END_FUNCTION:
|
|
if (g_ts_dbg != 0)
|
|
I("%s: END, ts_status=%d!\n", __func__, ts_status);
|
|
return ts_status;
|
|
}
|
|
/* end error_control*/
|
|
|
|
/* start distribute_data*/
|
|
static int himax_distribute_touch_data(uint8_t *buf,
|
|
int ts_path, int ts_status)
|
|
{
|
|
uint8_t hx_state_info_pos = hx_s_touch_data->touch_info_size - 3;
|
|
|
|
if (hx_s_ic_data->stylus_func)
|
|
hx_state_info_pos -= STYLUS_INFO_SZ;
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: Entering, ts_status=%d!\n", __func__, ts_status);
|
|
|
|
if (ts_path == HX_REPORT_COORD) {
|
|
memcpy(hx_s_touch_data->coord_buf, &buf[0],
|
|
hx_s_touch_data->touch_info_size);
|
|
|
|
if (buf[hx_state_info_pos] != 0xFF
|
|
&& buf[hx_state_info_pos + 1] != 0xFF)
|
|
memcpy(hx_s_touch_data->state_info,
|
|
&buf[hx_state_info_pos], 2);
|
|
else
|
|
memset(hx_s_touch_data->state_info, 0x00,
|
|
sizeof(hx_s_touch_data->state_info));
|
|
|
|
if ((g_hw_rst_activate)
|
|
#if defined(HX_EXCP_RECOVERY)
|
|
|| (HX_EXCP_RESET_ACTIVATE)
|
|
#endif
|
|
) {
|
|
if (!hx_s_debug_data->
|
|
is_stack_full_raw) {
|
|
memcpy(hx_s_touch_data->rawdata_buf,
|
|
&buf[hx_s_touch_data->
|
|
touch_info_size],
|
|
hx_s_touch_data->touch_all_size
|
|
- hx_s_touch_data->
|
|
touch_info_size);
|
|
} else {
|
|
memcpy(hx_s_touch_data->rawdata_buf,
|
|
&buf[HX_STACK_ORG_LEN],
|
|
hx_s_touch_data->touch_all_size
|
|
- HX_STACK_ORG_LEN);
|
|
}
|
|
}
|
|
} else if (ts_path == HX_REPORT_COORD_RAWDATA) {
|
|
memcpy(hx_s_touch_data->coord_buf, &buf[0],
|
|
hx_s_touch_data->touch_info_size);
|
|
|
|
if (buf[hx_state_info_pos] != 0xFF
|
|
&& buf[hx_state_info_pos + 1] != 0xFF)
|
|
memcpy(hx_s_touch_data->state_info,
|
|
&buf[hx_state_info_pos], 2);
|
|
else
|
|
memset(hx_s_touch_data->state_info, 0x00,
|
|
sizeof(hx_s_touch_data->state_info));
|
|
if (!hx_s_debug_data->
|
|
is_stack_full_raw) {
|
|
memcpy(hx_s_touch_data->rawdata_buf,
|
|
&buf[hx_s_touch_data->touch_info_size],
|
|
hx_s_touch_data->touch_all_size
|
|
- hx_s_touch_data->touch_info_size);
|
|
} else {
|
|
memcpy(hx_s_touch_data->rawdata_buf,
|
|
&buf[HX_STACK_ORG_LEN],
|
|
hx_s_touch_data->touch_all_size
|
|
- HX_STACK_ORG_LEN);
|
|
}
|
|
if (g_ts_dbg != 0)
|
|
I("%s:Assign rawdata done!\n", __func__);
|
|
#if defined(HX_SMART_WAKEUP)
|
|
} else if (ts_path == HX_REPORT_SMWP_EVENT) {
|
|
memcpy(hx_s_touch_data->event_buf, buf,
|
|
hx_s_touch_data->event_size);
|
|
#endif
|
|
} else {
|
|
E("%s, Fail Path!\n", __func__);
|
|
ts_status = HX_PATH_FAIL;
|
|
}
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: End, ts_status=%d!\n", __func__, ts_status);
|
|
return ts_status;
|
|
}
|
|
/* end assign_data*/
|
|
|
|
#define READ_VAR_BIT(var, nb) (((var) >> (nb)) & 0x1)
|
|
|
|
static bool wgp_pen_id_crc(uint8_t *p_id)
|
|
{
|
|
uint64_t pen_id, input;
|
|
uint8_t hash_id, devidend;
|
|
uint8_t pol = 0x43;
|
|
int i = 0;
|
|
|
|
if (g_ts_dbg != 0) {
|
|
for (i = 0; i < 8; i++)
|
|
I("%s:pen id[%d]= %x\n", __func__,
|
|
i, p_id[i]);
|
|
}
|
|
pen_id = (uint64_t)p_id[0] | ((uint64_t)p_id[1] << 8) |
|
|
((uint64_t)p_id[2] << 16) | ((uint64_t)p_id[3] << 24) |
|
|
((uint64_t)p_id[4] << 32) | ((uint64_t)p_id[5] << 40) |
|
|
((uint64_t)p_id[6] << 48);
|
|
hash_id = p_id[7];
|
|
if (g_ts_dbg != 0)
|
|
I("%s:pen id=%llx, hash id=%x\n", __func__,
|
|
pen_id, hash_id);
|
|
|
|
input = pen_id << 6;
|
|
devidend = input >> (44 + 6);
|
|
|
|
for (i = (44 + 6 - 1); i >= 0; i--) {
|
|
if (READ_VAR_BIT(devidend, 6))
|
|
devidend = devidend ^ pol;
|
|
devidend = devidend << 1 | READ_VAR_BIT(input, i);
|
|
}
|
|
if (READ_VAR_BIT(devidend, 6))
|
|
devidend = devidend ^ pol;
|
|
if (g_ts_dbg != 0)
|
|
I("%s:devidend=%x\n", __func__, devidend);
|
|
|
|
if (devidend == hash_id) {
|
|
g_target_report_data->s[0].id = pen_id;
|
|
return 1;
|
|
}
|
|
|
|
g_target_report_data->s[0].id = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* start parse_report_data*/
|
|
static uint8_t p_id[8];
|
|
|
|
int himax_parse_report_points(struct himax_ts_data *ts,
|
|
int ts_path, int ts_status)
|
|
{
|
|
int x = 0, y = 0, w = 0;
|
|
uint8_t p_hover = 0, p_btn = 0, p_btn2 = 0;
|
|
uint8_t ratio = hx_s_ic_data->stylus_ratio;
|
|
uint8_t p_id_en = 0, p_id_sel = 0;
|
|
int8_t p_tilt_x = 0, p_tilt_y = 0;
|
|
int p_x = 0, p_y = 0, p_w = 0;
|
|
bool ret;
|
|
static uint8_t p_p_on;
|
|
|
|
int base = 0;
|
|
int32_t i = 0;
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: start!\n", __func__);
|
|
|
|
base = hx_s_touch_data->touch_info_size;
|
|
|
|
if (!hx_s_ic_data->stylus_func)
|
|
goto skip_stylus_operation;
|
|
|
|
p_p_on = 0;
|
|
base -= STYLUS_INFO_SZ;
|
|
if (hx_s_ic_data->stylus_id_v2) {/*Pen format ver2*/
|
|
p_x = hx_s_touch_data->coord_buf[base] << 8
|
|
| hx_s_touch_data->coord_buf[base + 1];
|
|
p_y = (hx_s_touch_data->coord_buf[base + 2] << 8
|
|
| hx_s_touch_data->coord_buf[base + 3]);
|
|
p_w = (hx_s_touch_data->coord_buf[base + 4] << 8
|
|
| hx_s_touch_data->coord_buf[base + 5]);
|
|
p_tilt_x = (int8_t)hx_s_touch_data->coord_buf[base + 6];
|
|
p_tilt_y = (int8_t)hx_s_touch_data->coord_buf[base + 7];
|
|
p_hover = hx_s_touch_data->coord_buf[base + 8] & 0x01;
|
|
p_btn = hx_s_touch_data->coord_buf[base + 8] & 0x02;
|
|
p_btn2 = hx_s_touch_data->coord_buf[base + 8] & 0x04;
|
|
p_id_en = hx_s_touch_data->coord_buf[base + 8] & 0x08;
|
|
if (!p_id_en) {
|
|
g_target_report_data->s[0].battery_info =
|
|
hx_s_touch_data->coord_buf[base + 9];
|
|
if (g_ts_dbg != 0) {
|
|
I("%s:update battery info = %x\n", __func__,
|
|
g_target_report_data->s[0].battery_info);
|
|
}
|
|
} else {
|
|
p_id_sel =
|
|
(hx_s_touch_data->coord_buf[base + 8] & 0xF0) >> 4;
|
|
p_id[p_id_sel*2] =
|
|
hx_s_touch_data->coord_buf[base + 9];
|
|
p_id[p_id_sel*2 + 1] =
|
|
hx_s_touch_data->coord_buf[base + 10];
|
|
if (g_ts_dbg != 0) {
|
|
I("%s:update pen id, p_id_sel = %d\n", __func__,
|
|
p_id_sel);
|
|
}
|
|
if (p_id_sel == 3) {
|
|
ret = wgp_pen_id_crc(p_id);
|
|
if (!ret)
|
|
I("Pen_ID CRC not match\n");
|
|
}
|
|
}
|
|
} else {/*Pen format ver1*/
|
|
p_x = hx_s_touch_data->coord_buf[base] << 8
|
|
| hx_s_touch_data->coord_buf[base + 1];
|
|
p_y = (hx_s_touch_data->coord_buf[base + 2] << 8
|
|
| hx_s_touch_data->coord_buf[base + 3]);
|
|
p_w = (hx_s_touch_data->coord_buf[base + 4] << 8
|
|
| hx_s_touch_data->coord_buf[base + 5]);
|
|
p_tilt_x = (int8_t)hx_s_touch_data->coord_buf[base + 6];
|
|
p_hover = hx_s_touch_data->coord_buf[base + 7];
|
|
p_btn = hx_s_touch_data->coord_buf[base + 8];
|
|
p_btn2 = hx_s_touch_data->coord_buf[base + 9];
|
|
p_tilt_y = (int8_t)hx_s_touch_data->coord_buf[base + 10];
|
|
}
|
|
if (g_ts_dbg != 0) {
|
|
D("%s: p_x=%d, p_y=%d, p_w=%d,p_tilt_x=%d, p_hover=%d\n",
|
|
__func__, p_x, p_y, p_w, p_tilt_x, p_hover);
|
|
D("%s: p_btn=%d, p_btn2=%d, p_tilt_y=%d\n",
|
|
__func__, p_btn, p_btn2, p_tilt_y);
|
|
}
|
|
|
|
if (p_x >= 0
|
|
&& p_x <= ((ts->pdata->abs_x_max+1)*ratio-1)
|
|
&& p_y >= 0
|
|
&& p_y <= ((ts->pdata->abs_y_max+1)*ratio-1)) {
|
|
g_target_report_data->s[0].x = p_x;
|
|
g_target_report_data->s[0].y = p_y;
|
|
g_target_report_data->s[0].w = p_w;
|
|
g_target_report_data->s[0].hover = p_hover;
|
|
g_target_report_data->s[0].btn = p_btn;
|
|
g_target_report_data->s[0].btn2 = p_btn2;
|
|
g_target_report_data->s[0].tilt_x = p_tilt_x;
|
|
g_target_report_data->s[0].tilt_y = p_tilt_y;
|
|
g_target_report_data->s[0].on = 1;
|
|
ts->hx_stylus_num++;
|
|
} else {/* report coordinates */
|
|
g_target_report_data->s[0].x = 0;
|
|
g_target_report_data->s[0].y = 0;
|
|
g_target_report_data->s[0].w = 0;
|
|
g_target_report_data->s[0].hover = 0;
|
|
g_target_report_data->s[0].btn = 0;
|
|
g_target_report_data->s[0].btn2 = 0;
|
|
g_target_report_data->s[0].tilt_x = 0;
|
|
g_target_report_data->s[0].tilt_y = 0;
|
|
g_target_report_data->s[0].on = 0;
|
|
}
|
|
|
|
if (g_ts_dbg != 0) {
|
|
if (p_p_on != g_target_report_data->s[0].on) {
|
|
I("s[0].on = %d, hx_stylus_num=%d\n",
|
|
g_target_report_data->s[0].on,
|
|
ts->hx_stylus_num);
|
|
p_p_on = g_target_report_data->s[0].on;
|
|
}
|
|
}
|
|
skip_stylus_operation:
|
|
|
|
ts->old_finger = ts->pre_finger_mask;
|
|
if (ts->hx_point_num == 0) {
|
|
if (g_ts_dbg != 0)
|
|
I("%s: hx_point_num = 0!\n", __func__);
|
|
return ts_status;
|
|
}
|
|
ts->pre_finger_mask = 0;
|
|
hx_s_touch_data->finger_num =
|
|
hx_s_touch_data->coord_buf[base - 4] & 0x0F;
|
|
hx_s_touch_data->finger_on = 1;
|
|
AA_press = 1;
|
|
|
|
g_target_report_data->finger_num = hx_s_touch_data->finger_num;
|
|
g_target_report_data->finger_on = hx_s_touch_data->finger_on;
|
|
g_target_report_data->ig_count =
|
|
hx_s_touch_data->coord_buf[base - 5];
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s:finger_num = 0x%2X, finger_on = %d\n", __func__,
|
|
g_target_report_data->finger_num,
|
|
g_target_report_data->finger_on);
|
|
|
|
for (i = 0; i < ts->nFinger_support; i++) {
|
|
base = i * 4;
|
|
x = hx_s_touch_data->coord_buf[base] << 8
|
|
| hx_s_touch_data->coord_buf[base + 1];
|
|
y = (hx_s_touch_data->coord_buf[base + 2] << 8
|
|
| hx_s_touch_data->coord_buf[base + 3]);
|
|
w = hx_s_touch_data->coord_buf[(ts->nFinger_support * 4) + i];
|
|
|
|
if (g_ts_dbg != 0)
|
|
D("%s: now parsing[%d]:x=%d, y=%d, w=%d\n", __func__,
|
|
i, x, y, w);
|
|
|
|
if (x >= 0
|
|
&& x <= ts->pdata->abs_x_max
|
|
&& y >= 0
|
|
&& y <= ts->pdata->abs_y_max) {
|
|
hx_s_touch_data->finger_num--;
|
|
|
|
g_target_report_data->p[i].x = x;
|
|
g_target_report_data->p[i].y = y;
|
|
g_target_report_data->p[i].w = w;
|
|
g_target_report_data->p[i].id = 1;
|
|
|
|
/*I("%s: g_target_report_data->x[loop_i]=%d,*/
|
|
/*g_target_report_data->y[loop_i]=%d,*/
|
|
/*g_target_report_data->w[loop_i]=%d",*/
|
|
/*__func__, g_target_report_data->x[loop_i],*/
|
|
/*g_target_report_data->y[loop_i],*/
|
|
/*g_target_report_data->w[loop_i]); */
|
|
|
|
if (!ts->first_pressed) {
|
|
ts->first_pressed = 1;
|
|
I("S1@%d, %d\n", x, y);
|
|
}
|
|
|
|
ts->pre_finger_data[i][0] = x;
|
|
ts->pre_finger_data[i][1] = y;
|
|
|
|
ts->pre_finger_mask = ts->pre_finger_mask + (1<<i);
|
|
} else {/* report coordinates */
|
|
g_target_report_data->p[i].x = x;
|
|
g_target_report_data->p[i].y = y;
|
|
g_target_report_data->p[i].w = w;
|
|
g_target_report_data->p[i].id = 0;
|
|
|
|
if (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 (g_ts_dbg != 0) {
|
|
for (i = 0; i < ts->nFinger_support; i++)
|
|
D("DBG X=%d Y=%d ID=%d\n",
|
|
g_target_report_data->p[i].x,
|
|
g_target_report_data->p[i].y,
|
|
g_target_report_data->p[i].id);
|
|
|
|
D("DBG finger number %d\n", g_target_report_data->finger_num);
|
|
}
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: end!\n", __func__);
|
|
return ts_status;
|
|
}
|
|
|
|
static int himax_parse_report_data(struct himax_ts_data *ts,
|
|
int ts_path, int ts_status)
|
|
{
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: start now_status=%d!\n", __func__, ts_status);
|
|
|
|
|
|
EN_NoiseFilter =
|
|
(hx_s_touch_data->coord_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 = ts->hx_point_num;
|
|
|
|
if (hx_s_touch_data->coord_buf[HX_TOUCH_INFO_POINT_CNT] == 0xff)
|
|
ts->hx_point_num = 0;
|
|
else
|
|
ts->hx_point_num =
|
|
hx_s_touch_data->coord_buf[HX_TOUCH_INFO_POINT_CNT]
|
|
& 0x0f;
|
|
|
|
if (hx_s_ic_data->stylus_func) {
|
|
p_stylus_num = ts->hx_stylus_num;
|
|
ts->hx_stylus_num = 0;
|
|
}
|
|
|
|
switch (ts_path) {
|
|
case HX_REPORT_COORD:
|
|
ts_status = himax_parse_report_points(ts, ts_path, ts_status);
|
|
break;
|
|
case HX_REPORT_COORD_RAWDATA:
|
|
/* touch monitor rawdata */
|
|
if (hx_s_debug_data != NULL) {
|
|
if (hx_s_debug_data->is_stack_full_raw) {
|
|
if (g_ts_dbg != 0)
|
|
I("%s: full stack raw!\n", __func__);
|
|
if (hx_s_debug_data->
|
|
_raw_full_stack(hx_s_ic_data,
|
|
hx_s_touch_data))
|
|
I("%s:raw data_checksum not match\n",
|
|
__func__);
|
|
} else{
|
|
if (g_ts_dbg != 0)
|
|
I("%s: event stack raw!\n", __func__);
|
|
if (hx_s_debug_data->_set_diag_cmd(hx_s_ic_data,
|
|
hx_s_touch_data))
|
|
I("%s:raw data_checksum not match\n",
|
|
__func__);
|
|
}
|
|
|
|
} else {
|
|
E("%s,There is no init set_diag_cmd\n", __func__);
|
|
}
|
|
ts_status = himax_parse_report_points(ts, ts_path, ts_status);
|
|
break;
|
|
#if defined(HX_SMART_WAKEUP)
|
|
case HX_REPORT_SMWP_EVENT:
|
|
himax_wake_event_parse(ts, ts_status);
|
|
break;
|
|
#endif
|
|
default:
|
|
E("%s:Fail Path!\n", __func__);
|
|
ts_status = HX_PATH_FAIL;
|
|
break;
|
|
}
|
|
if (g_ts_dbg != 0)
|
|
I("%s: end now_status=%d!\n", __func__, ts_status);
|
|
return ts_status;
|
|
}
|
|
|
|
/* end parse_report_data*/
|
|
|
|
static void himax_report_all_leave_event(struct himax_ts_data *ts)
|
|
{
|
|
int i = 0;
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: entering!\n", __func__);
|
|
|
|
for (i = 0; i < ts->nFinger_support; i++) {
|
|
#if !defined(HX_PROTOCOL_A)
|
|
input_mt_slot(ts->input_dev, i);
|
|
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
|
|
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
|
|
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
|
|
input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
|
|
#endif
|
|
}
|
|
input_report_key(ts->input_dev, BTN_TOUCH, 0);
|
|
input_sync(ts->input_dev);
|
|
}
|
|
|
|
/* start report_point*/
|
|
static void himax_point_report(struct himax_ts_data *ts)
|
|
{
|
|
int i;
|
|
bool valid;
|
|
|
|
|
|
if (g_ts_dbg != 0) {
|
|
I("%s:start hx_s_touch_data->finger_num=%d\n",
|
|
__func__, hx_s_touch_data->finger_num);
|
|
}
|
|
for (i = 0; i < ts->nFinger_support; i++) {
|
|
if (g_target_report_data->p[i].x >= 0
|
|
&& g_target_report_data->p[i].x <= ts->pdata->abs_x_max
|
|
&& g_target_report_data->p[i].y >= 0
|
|
&& g_target_report_data->p[i].y <= ts->pdata->abs_y_max)
|
|
valid = true;
|
|
else
|
|
valid = false;
|
|
if (g_ts_dbg != 0)
|
|
I("valid=%d\n", valid);
|
|
if (valid) {
|
|
if (g_ts_dbg != 0) {
|
|
I("report_data->x[i]=%d,y[i]=%d,w[i]=%d",
|
|
g_target_report_data->p[i].x,
|
|
g_target_report_data->p[i].y,
|
|
g_target_report_data->p[i].w);
|
|
}
|
|
#if !defined(HX_PROTOCOL_A)
|
|
input_mt_slot(ts->input_dev, i);
|
|
input_mt_report_slot_state(ts->input_dev,
|
|
MT_TOOL_FINGER, 1);
|
|
#else
|
|
input_report_key(ts->input_dev, BTN_TOUCH, 1);
|
|
#endif
|
|
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
|
|
g_target_report_data->p[i].w);
|
|
#if !defined(HX_PROTOCOL_A)
|
|
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
|
|
g_target_report_data->p[i].w);
|
|
input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
|
|
g_target_report_data->p[i].w);
|
|
#else
|
|
input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID,
|
|
i + 1);
|
|
#endif
|
|
input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
|
|
g_target_report_data->p[i].x);
|
|
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
|
|
g_target_report_data->p[i].y);
|
|
#if !defined(HX_PROTOCOL_A)
|
|
ts->last_slot = i;
|
|
#else
|
|
input_mt_sync(ts->input_dev);
|
|
#endif
|
|
} else {
|
|
#if !defined(HX_PROTOCOL_A)
|
|
input_mt_slot(ts->input_dev, i);
|
|
input_mt_report_slot_state(ts->input_dev,
|
|
MT_TOOL_FINGER, 0);
|
|
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
|
|
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
|
|
input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
|
|
#endif
|
|
}
|
|
}
|
|
#if !defined(HX_PROTOCOL_A)
|
|
input_report_key(ts->input_dev, BTN_TOUCH, 1);
|
|
#endif
|
|
input_sync(ts->input_dev);
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s:end\n", __func__);
|
|
}
|
|
|
|
static void himax_point_leave(struct himax_ts_data *ts)
|
|
{
|
|
#if !defined(HX_PROTOCOL_A)
|
|
int32_t i = 0;
|
|
#endif
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: start!\n", __func__);
|
|
#if defined(HX_PALM_REPORT)
|
|
if (himax_palm_detect(hx_s_touch_data->coord_buf) == PALM_REPORT) {
|
|
I(" %s HX_PALM_REPORT KEY power event press\n", __func__);
|
|
input_report_key(ts->input_dev, KEY_POWER, 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_POWER, 0);
|
|
input_sync(ts->input_dev);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
hx_s_touch_data->finger_on = 0;
|
|
g_target_report_data->finger_on = 0;
|
|
g_target_report_data->finger_num = 0;
|
|
AA_press = 0;
|
|
|
|
#if defined(HX_PROTOCOL_A)
|
|
input_mt_sync(ts->input_dev);
|
|
#endif
|
|
#if !defined(HX_PROTOCOL_A)
|
|
for (i = 0; i < ts->nFinger_support; i++) {
|
|
input_mt_slot(ts->input_dev, i);
|
|
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
|
|
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
|
|
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
|
|
input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
|
|
}
|
|
#endif
|
|
if (ts->pre_finger_mask > 0)
|
|
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))*/
|
|
/* himax_log_touch_event(x, y, w, loop_i, EN_NoiseFilter,*/
|
|
/* HX_FINGER_LEAVE); */
|
|
|
|
input_report_key(ts->input_dev, BTN_TOUCH, 0);
|
|
input_sync(ts->input_dev);
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: end!\n", __func__);
|
|
}
|
|
|
|
static void himax_stylus_report(struct himax_ts_data *ts)
|
|
{
|
|
bool valid = false;
|
|
uint8_t ratio = hx_s_ic_data->stylus_ratio;
|
|
|
|
if (g_ts_dbg != 0) {
|
|
I("%s:start hx_s_touch_data->stylus_num=%d\n",
|
|
__func__, ts->hx_stylus_num);
|
|
}
|
|
|
|
if (g_target_report_data->s[0].x >= 0
|
|
&& g_target_report_data->s[0].x <= ((ts->pdata->abs_x_max+1)*ratio-1)
|
|
&& g_target_report_data->s[0].y >= 0
|
|
&& g_target_report_data->s[0].y <= ((ts->pdata->abs_y_max+1)*ratio-1)
|
|
&& (g_target_report_data->s[0].on == 1))
|
|
valid = true;
|
|
else
|
|
valid = false;
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("stylus valid=%d\n", valid);
|
|
|
|
if (valid) {/*stylus down*/
|
|
if (g_ts_dbg != 0)
|
|
I("s[i].x=%d, s[i].y=%d, s[i].w=%d\n",
|
|
g_target_report_data->s[0].x,
|
|
g_target_report_data->s[0].y,
|
|
g_target_report_data->s[0].w);
|
|
|
|
input_report_abs(ts->stylus_dev, ABS_X,
|
|
g_target_report_data->s[0].x);
|
|
input_report_abs(ts->stylus_dev, ABS_Y,
|
|
g_target_report_data->s[0].y);
|
|
|
|
if (g_target_report_data->s[0].btn !=
|
|
g_target_report_data->s[0].pre_btn) {
|
|
if (g_ts_dbg != 0)
|
|
I("BTN_STYLUS:%d\n",
|
|
g_target_report_data->s[0].btn);
|
|
|
|
input_report_key(ts->stylus_dev, BTN_STYLUS,
|
|
g_target_report_data->s[0].btn);
|
|
|
|
g_target_report_data->s[0].pre_btn =
|
|
g_target_report_data->s[0].btn;
|
|
} else {
|
|
if (g_ts_dbg != 0)
|
|
I("BTN_STYLUS status is %d!\n",
|
|
g_target_report_data->s[0].btn);
|
|
}
|
|
|
|
if (g_target_report_data->s[0].btn2
|
|
!= g_target_report_data->s[0].pre_btn2) {
|
|
if (g_ts_dbg != 0)
|
|
I("BTN_STYLUS2:%d\n",
|
|
g_target_report_data->s[0].btn2);
|
|
|
|
input_report_key(ts->stylus_dev, BTN_STYLUS2,
|
|
g_target_report_data->s[0].btn2);
|
|
|
|
g_target_report_data->s[0].pre_btn2 =
|
|
g_target_report_data->s[0].btn2;
|
|
} else {
|
|
if (g_ts_dbg != 0)
|
|
I("BTN_STYLUS2 status is %d!\n",
|
|
g_target_report_data->s[0].btn2);
|
|
}
|
|
input_report_abs(ts->stylus_dev, ABS_TILT_X,
|
|
g_target_report_data->s[0].tilt_x);
|
|
|
|
input_report_abs(ts->stylus_dev, ABS_TILT_Y,
|
|
g_target_report_data->s[0].tilt_y);
|
|
|
|
input_report_key(ts->stylus_dev, BTN_TOOL_PEN, 1);
|
|
|
|
if (g_target_report_data->s[0].hover == 0) {
|
|
input_report_key(ts->stylus_dev, BTN_TOUCH, 1);
|
|
input_report_abs(ts->stylus_dev, ABS_DISTANCE, 0);
|
|
input_report_abs(ts->stylus_dev, ABS_PRESSURE,
|
|
g_target_report_data->s[0].w);
|
|
} else {
|
|
input_report_key(ts->stylus_dev, BTN_TOUCH, 0);
|
|
input_report_abs(ts->stylus_dev, ABS_DISTANCE, 1);
|
|
input_report_abs(ts->stylus_dev, ABS_PRESSURE, 0);
|
|
}
|
|
} else {/*Pen up*/
|
|
g_target_report_data->s[0].pre_btn = 0;
|
|
g_target_report_data->s[0].pre_btn2 = 0;
|
|
input_report_key(ts->stylus_dev, BTN_STYLUS, 0);
|
|
input_report_key(ts->stylus_dev, BTN_STYLUS2, 0);
|
|
input_report_key(ts->stylus_dev, BTN_TOUCH, 0);
|
|
input_report_abs(ts->stylus_dev, ABS_PRESSURE, 0);
|
|
input_sync(ts->stylus_dev);
|
|
|
|
input_report_abs(ts->stylus_dev, ABS_DISTANCE, 0);
|
|
input_report_key(ts->stylus_dev, BTN_TOOL_RUBBER, 0);
|
|
input_report_key(ts->stylus_dev, BTN_TOOL_PEN, 0);
|
|
input_report_abs(ts->stylus_dev, ABS_PRESSURE, 0);
|
|
}
|
|
input_sync(ts->stylus_dev);
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s:end\n", __func__);
|
|
}
|
|
|
|
static void himax_stylus_leave(struct himax_ts_data *ts)
|
|
{
|
|
if (g_ts_dbg != 0)
|
|
I("%s: start!\n", __func__);
|
|
|
|
g_target_report_data->s[0].pre_btn = 0;
|
|
g_target_report_data->s[0].pre_btn2 = 0;
|
|
input_report_key(ts->stylus_dev, BTN_STYLUS, 0);
|
|
input_report_key(ts->stylus_dev, BTN_STYLUS2, 0);
|
|
input_report_key(ts->stylus_dev, BTN_TOUCH, 0);
|
|
input_report_abs(ts->stylus_dev, ABS_PRESSURE, 0);
|
|
input_sync(ts->stylus_dev);
|
|
|
|
input_report_abs(ts->stylus_dev, ABS_DISTANCE, 0);
|
|
input_report_abs(ts->stylus_dev, ABS_TILT_X, 0);
|
|
input_report_abs(ts->stylus_dev, ABS_TILT_Y, 0);
|
|
input_report_key(ts->stylus_dev, BTN_TOOL_RUBBER, 0);
|
|
input_report_key(ts->stylus_dev, BTN_TOOL_PEN, 0);
|
|
input_sync(ts->stylus_dev);
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: end!\n", __func__);
|
|
}
|
|
|
|
int himax_report_data(struct himax_ts_data *ts, int ts_path, int ts_status)
|
|
{
|
|
if (g_ts_dbg != 0)
|
|
I("%s: Entering, ts_status=%d!\n", __func__, ts_status);
|
|
|
|
if (ts_path == HX_REPORT_COORD || ts_path == HX_REPORT_COORD_RAWDATA) {
|
|
/* Touch Point information */
|
|
|
|
if (ts->hx_point_num != 0)
|
|
himax_point_report(ts);
|
|
else if ((ts->hx_point_num == 0) && (p_point_num != 0))
|
|
himax_point_leave(ts);
|
|
|
|
if (hx_s_ic_data->stylus_func) {
|
|
if (ts->hx_stylus_num != 0)
|
|
himax_stylus_report(ts);
|
|
else if ((ts->hx_stylus_num == 0)
|
|
&& (p_stylus_num != 0))
|
|
himax_stylus_leave(ts);
|
|
}
|
|
|
|
Last_EN_NoiseFilter = EN_NoiseFilter;
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
} else if (ts_path == HX_REPORT_SMWP_EVENT) {
|
|
himax_wake_event_report();
|
|
#endif
|
|
} else {
|
|
E("%s:Fail Path!\n", __func__);
|
|
ts_status = HX_PATH_FAIL;
|
|
}
|
|
|
|
if (g_ts_dbg != 0)
|
|
I("%s: END, ts_status=%d!\n", __func__, ts_status);
|
|
return ts_status;
|
|
}
|
|
/* end report_data */
|
|
|
|
void himax_ts_work(struct himax_ts_data *ts)
|
|
{
|
|
|
|
int ts_status = HX_TS_NORMAL_END;
|
|
int ts_path = 0;
|
|
|
|
if (!ts->initialized) {
|
|
I("%s: Entering, but init doesn't done, skip\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
if (hx_s_debug_data != NULL) {
|
|
if (hx_s_debug_data->is_checking_irq) {
|
|
if (g_ts_dbg != 0)
|
|
I("Now checking IRQ, skip it!\n");
|
|
return;
|
|
}
|
|
hx_s_debug_data->_ts_dbg_func(ts, HX_FINGER_ON);
|
|
}
|
|
|
|
#if defined(HX_USB_DETECT_GLOBAL)
|
|
himax_cable_detect_func(false);
|
|
#endif
|
|
|
|
ts_path = himax_ts_work_status(ts);
|
|
|
|
memset(ts->xfer_buff,
|
|
0x00,
|
|
hx_s_touch_data->touch_all_size * sizeof(uint8_t));
|
|
ts_status = himax_touch_get(ts, ts->xfer_buff, ts_path, ts_status);
|
|
if (ts_status == HX_TS_GET_DATA_FAIL)
|
|
goto END_FUNCTION;
|
|
|
|
ts_status = himax_distribute_touch_data(ts->xfer_buff,
|
|
ts_path, ts_status);
|
|
ts_status = himax_err_ctrl(ts, ts->xfer_buff, ts_path, ts_status);
|
|
if (ts_status == HX_REPORT_DATA || ts_status == HX_TS_NORMAL_END)
|
|
ts_status = himax_parse_report_data(ts, ts_path, ts_status);
|
|
else
|
|
goto END_FUNCTION;
|
|
|
|
ts_status = himax_report_data(ts, ts_path, ts_status);
|
|
|
|
if (ts_status == HX_TS_GET_DATA_FAIL)
|
|
goto GET_TOUCH_FAIL;
|
|
else
|
|
goto END_FUNCTION;
|
|
|
|
GET_TOUCH_FAIL:
|
|
I("%s: Now reset the Touch chip.\n", __func__);
|
|
hx_s_core_fp._ic_reset(0);
|
|
|
|
#if defined(HX_ZERO_FLASH)
|
|
if (hx_s_core_fp._0f_reload_to_active)
|
|
hx_s_core_fp._0f_reload_to_active();
|
|
#endif
|
|
END_FUNCTION:
|
|
if (hx_s_debug_data != NULL)
|
|
hx_s_debug_data->_ts_dbg_func(ts, HX_FINGER_LEAVE);
|
|
|
|
}
|
|
/*end ts_work*/
|
|
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;
|
|
}
|
|
|
|
#if !defined(HX_ZERO_FLASH)
|
|
static int hx_chk_flash_sts(uint32_t size)
|
|
{
|
|
int rslt = 0;
|
|
|
|
I("%s: Entering, %d\n", __func__, size);
|
|
|
|
rslt = (!hx_s_core_fp._calculateChecksum(false, size));
|
|
/*avoid the FW is full of zero*/
|
|
rslt |= hx_s_core_fp._flash_lastdata_check(size);
|
|
|
|
return rslt;
|
|
}
|
|
#endif
|
|
|
|
static void himax_boot_upgrade(struct work_struct *work)
|
|
{
|
|
#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH)
|
|
int fw_sts = -1;
|
|
#endif
|
|
|
|
#if defined(HX_ZERO_FLASH)
|
|
g_boot_upgrade_flag = true;
|
|
#else
|
|
if (hx_chk_flash_sts(hx_s_ic_data->flash_size) == 1) {
|
|
E("%s: check flash fail, please upgrade FW\n", __func__);
|
|
#if defined(HX_BOOT_UPGRADE)
|
|
g_boot_upgrade_flag = true;
|
|
#else
|
|
goto END;
|
|
#endif
|
|
} else {
|
|
hx_s_core_fp._reload_disable(0);
|
|
hx_s_core_fp._power_on_init();
|
|
hx_s_core_fp._read_FW_ver();
|
|
hx_s_core_fp._tp_info_check();
|
|
}
|
|
#endif
|
|
|
|
#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH)
|
|
fw_sts = i_get_FW();
|
|
if (fw_sts < NO_ERR)
|
|
goto END;
|
|
|
|
hx_s_core_fp._bin_desc_get((unsigned char *)hxfw->data, HX1K);
|
|
|
|
#if defined(HX_BOOT_UPGRADE)
|
|
if (g_boot_upgrade_flag == false) {
|
|
if (himax_auto_update_check() == 0)
|
|
g_boot_upgrade_flag = true;
|
|
}
|
|
#endif
|
|
|
|
if (g_boot_upgrade_flag == true) {
|
|
if (i_update_FW() <= 0) {
|
|
E("%s: Update FW fail\n", __func__);
|
|
} else {
|
|
I("%s: Update FW success\n", __func__);
|
|
if (!g_has_alg_overlay) {
|
|
hx_s_core_fp._reload_disable(0);
|
|
hx_s_core_fp._power_on_init();
|
|
}
|
|
hx_s_core_fp._read_FW_ver();
|
|
hx_s_core_fp._tp_info_check();
|
|
}
|
|
}
|
|
|
|
if (fw_sts == NO_ERR)
|
|
release_firmware(hxfw);
|
|
hxfw = NULL;
|
|
#endif
|
|
|
|
END:
|
|
ic_boot_done = 1;
|
|
himax_int_enable(1);
|
|
}
|
|
|
|
#if defined(HX_CONTAINER_SPEED_UP)
|
|
static void himax_resume_work_func(struct work_struct *work)
|
|
{
|
|
himax_chip_common_resume(hx_s_ts);
|
|
}
|
|
|
|
#endif
|
|
int hx_ic_register(void)
|
|
{
|
|
int ret = !NO_ERR;
|
|
|
|
I("%s:Entering!\n", __func__);
|
|
if (_hx83108_init()) {
|
|
ret = NO_ERR;
|
|
goto END;
|
|
}
|
|
|
|
#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83122A)
|
|
if (_hx83122a_init()) {
|
|
ret = NO_ERR;
|
|
goto END;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83102J)
|
|
if (_hx83102j_init()) {
|
|
ret = NO_ERR;
|
|
goto END;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112F)
|
|
if (_hx83112f_init()) {
|
|
ret = NO_ERR;
|
|
goto END;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83121A)
|
|
if (_hx83121a_init()) {
|
|
ret = NO_ERR;
|
|
goto END;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX85200A)
|
|
if (_hx85200a_init()) {
|
|
ret = NO_ERR;
|
|
goto END;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83132A)
|
|
if (_hx83132a_init()) {
|
|
ret = NO_ERR;
|
|
goto END;
|
|
}
|
|
#endif
|
|
|
|
END:
|
|
if (ret == NO_ERR)
|
|
I("%s: detect IC!\n", __func__);
|
|
else
|
|
E("%s: There is no IC!\n", __func__);
|
|
I("%s:END!\n", __func__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if defined(HX_FIRMWARE_HEADER)
|
|
void mapping_panel_id_from_dt(struct device_node *dt)
|
|
{
|
|
const char *panel_id_dt = "panel_id";
|
|
uint32_t data = 0;
|
|
|
|
if (of_property_read_u32(dt, panel_id_dt, &data) == 0) {
|
|
I(" Found %s = %d\n", panel_id_dt, data);
|
|
g_hx_panel_id = data;
|
|
} else {
|
|
I(" %s not found! set to default 0\n", panel_id_dt);
|
|
g_hx_panel_id = 0;
|
|
}
|
|
I(" DT:panel_id = %d\n", g_hx_panel_id);
|
|
}
|
|
#endif
|
|
|
|
int himax_chip_common_init(void)
|
|
{
|
|
int ret = 0;
|
|
int err = PROBE_FAIL;
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
struct himax_platform_data *pdata;
|
|
|
|
|
|
ts->xfer_buff = devm_kzalloc(ts->dev,
|
|
HX_FULL_STACK_RAWDATA_SIZE * sizeof(uint8_t),
|
|
GFP_KERNEL);
|
|
|
|
if (ts->xfer_buff == NULL) {
|
|
err = -ENOMEM;
|
|
goto err_xfer_buff_fail;
|
|
}
|
|
|
|
I("PDATA START\n");
|
|
pdata = kzalloc(sizeof(struct himax_platform_data), GFP_KERNEL);
|
|
|
|
if (pdata == NULL) { /*Allocate Platform data space*/
|
|
err = -ENOMEM;
|
|
goto err_dt_platform_data_fail;
|
|
}
|
|
|
|
I("hx_s_ic_data START\n");
|
|
hx_s_ic_data = kzalloc(sizeof(struct himax_ic_data), GFP_KERNEL);
|
|
if (hx_s_ic_data == NULL) { /*Allocate IC data space*/
|
|
err = -ENOMEM;
|
|
goto err_dt_ic_data_fail;
|
|
}
|
|
memset(hx_s_ic_data, 0xFF, sizeof(struct himax_ic_data));
|
|
/* default 128k, different size please follow HX83121A style */
|
|
hx_s_ic_data->flash_size = 131072;
|
|
|
|
/* allocate report data */
|
|
hx_s_touch_data = kzalloc(sizeof(struct himax_report_data), GFP_KERNEL);
|
|
if (hx_s_touch_data == NULL) {
|
|
err = -ENOMEM;
|
|
goto err_alloc_touch_data_failed;
|
|
}
|
|
|
|
ts->pdata = pdata;
|
|
|
|
if (himax_parse_dt(ts, pdata) < 0) {
|
|
I(" pdata is NULL for DT\n");
|
|
goto err_alloc_dt_pdata_failed;
|
|
}
|
|
|
|
#if defined(HX_RST_PIN_FUNC)
|
|
ts->rst_gpio = pdata->gpio_reset;
|
|
#endif
|
|
|
|
if (himax_gpio_power_config(pdata) < 0) {
|
|
E("%s: gpio config fail, exit!\n", __func__);
|
|
goto err_alloc_dt_pdata_failed;
|
|
}
|
|
|
|
#if !defined(CONFIG_OF)
|
|
if (pdata->power) {
|
|
ret = pdata->power(1);
|
|
if (ret < 0) {
|
|
E("%s: power on failed\n", __func__);
|
|
goto err_power_failed;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_OF)
|
|
ts->power = pdata->power;
|
|
#endif
|
|
|
|
|
|
if (hx_ic_register() != NO_ERR) {
|
|
E("%s: can't detect IC!\n", __func__);
|
|
goto error_ic_detect_failed;
|
|
}
|
|
|
|
|
|
if (hx_s_core_fp._chip_init != NULL) {
|
|
hx_s_core_fp._chip_init();
|
|
} else {
|
|
E("%s: function point of chip_init is NULL!\n", __func__);
|
|
goto error_ic_detect_failed;
|
|
}
|
|
#ifdef HX_PARSE_FROM_DT
|
|
himax_parse_dt_ic_info(ts, pdata);
|
|
#endif
|
|
hx_s_core_fp._touch_information();
|
|
|
|
spin_lock_init(&ts->irq_lock);
|
|
|
|
if (himax_ts_register_interrupt()) {
|
|
E("%s: register interrupt failed\n", __func__);
|
|
goto err_register_interrupt_failed;
|
|
}
|
|
|
|
himax_int_enable(0);
|
|
|
|
#if defined(HX_ZERO_FLASH)
|
|
g_update_cfg_buf = kzalloc(hx_s_ic_data->dsram_sz *
|
|
sizeof(uint8_t),
|
|
GFP_KERNEL);
|
|
if (g_update_cfg_buf == NULL) {
|
|
err = -ENOMEM;
|
|
goto err_update_cfg_buf_adlled;
|
|
}
|
|
#endif
|
|
|
|
ts->himax_boot_upgrade_wq =
|
|
create_singlethread_workqueue("HX_boot_upgrade");
|
|
if (!ts->himax_boot_upgrade_wq) {
|
|
E("allocate himax_boot_upgrade_wq failed\n");
|
|
err = -ENOMEM;
|
|
goto err_boot_upgrade_wq_failed;
|
|
}
|
|
INIT_DELAYED_WORK(&ts->work_boot_upgrade, himax_boot_upgrade);
|
|
queue_delayed_work(ts->himax_boot_upgrade_wq, &ts->work_boot_upgrade,
|
|
msecs_to_jiffies(HX_DELAY_BOOT_UPDATE));
|
|
|
|
hx_s_core_fp._calc_touch_data_size();
|
|
|
|
/*Himax Power On and Load Config*/
|
|
/* if (himax_loadSensorConfig(pdata)) {
|
|
* E("%s: Load Sesnsor configuration failed, unload driver.\n",
|
|
* __func__);
|
|
* goto err_detect_failed;
|
|
* }
|
|
*/
|
|
|
|
#if defined(CONFIG_OF)
|
|
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;
|
|
#endif
|
|
|
|
ts->suspended = false;
|
|
|
|
#if defined(HX_USB_DETECT_GLOBAL)
|
|
ts->usb_connected = 0x00;
|
|
ts->cable_config = pdata->cable_config;
|
|
#endif
|
|
|
|
#if defined(HX_PROTOCOL_A)
|
|
ts->protocol_type = PROTOCOL_TYPE_A;
|
|
#else
|
|
ts->protocol_type = PROTOCOL_TYPE_B;
|
|
#endif
|
|
I("%s: Use Protocol Type %c\n", __func__,
|
|
ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B');
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
ts->SMWP_enable = 0;
|
|
#if defined(KERNEL_VER_ABOVE_4_19)
|
|
ts->ts_SMWP_wake_lock =
|
|
wakeup_source_register(ts->dev, HIMAX_common_NAME);
|
|
#else
|
|
if (!ts->ts_SMWP_wake_lock)
|
|
ts->ts_SMWP_wake_lock = kzalloc(sizeof(struct wakeup_source),
|
|
GFP_KERNEL);
|
|
|
|
if (!ts->ts_SMWP_wake_lock) {
|
|
E("%s: allocate ts_SMWP_wake_lock failed\n", __func__);
|
|
goto err_smwp_wake_lock_failed;
|
|
}
|
|
|
|
wakeup_source_init(ts->ts_SMWP_wake_lock, HIMAX_common_NAME);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(HX_HIGH_SENSE)
|
|
ts->HSEN_enable = 0;
|
|
#endif
|
|
|
|
if (himax_common_proc_init()) {
|
|
E(" %s: himax_common proc_init failed!\n", __func__);
|
|
goto err_creat_proc_file_failed;
|
|
}
|
|
|
|
if (himax_debug_init()) {
|
|
E(" %s: debug initial failed!\n", __func__);
|
|
goto err_debug_init_failed;
|
|
}
|
|
|
|
ret = himax_input_register(ts);
|
|
if (ret) {
|
|
E("%s: Unable to register %s input device\n",
|
|
__func__, ts->input_dev->name);
|
|
goto err_input_register_device_failed;
|
|
}
|
|
|
|
#if defined(HX_CONTAINER_SPEED_UP)
|
|
ts->ts_int_workqueue =
|
|
create_singlethread_workqueue("himax_ts_resume_wq");
|
|
if (!ts->ts_int_workqueue) {
|
|
E("create ts_resume workqueue failed\n");
|
|
goto err_create_ts_resume_wq_failed;
|
|
}
|
|
INIT_DELAYED_WORK(&ts->ts_int_work, himax_resume_work_func);
|
|
#endif
|
|
|
|
ts->initialized = true;
|
|
|
|
I("%s: Now load:%s\n", __func__, HIMAX_DRIVER_VER);
|
|
|
|
return 0;
|
|
|
|
#if defined(HX_CONTAINER_SPEED_UP)
|
|
err_create_ts_resume_wq_failed:
|
|
#endif
|
|
input_unregister_device(ts->input_dev);
|
|
if (hx_s_ic_data->stylus_func)
|
|
input_unregister_device(ts->stylus_dev);
|
|
err_input_register_device_failed:
|
|
himax_debug_remove();
|
|
err_debug_init_failed:
|
|
himax_common_proc_deinit();
|
|
err_creat_proc_file_failed:
|
|
#if defined(HX_SMART_WAKEUP)
|
|
#if defined(KERNEL_VER_ABOVE_4_19)
|
|
wakeup_source_unregister(ts->ts_SMWP_wake_lock);
|
|
#else
|
|
wakeup_source_trash(ts->ts_SMWP_wake_lock);
|
|
kfree(ts->ts_SMWP_wake_lock);
|
|
ts->ts_SMWP_wake_lock = NULL;
|
|
err_smwp_wake_lock_failed:
|
|
#endif
|
|
#endif
|
|
cancel_delayed_work_sync(&ts->work_boot_upgrade);
|
|
destroy_workqueue(ts->himax_boot_upgrade_wq);
|
|
err_boot_upgrade_wq_failed:
|
|
himax_ts_unregister_interrupt();
|
|
#if defined(HX_ZERO_FLASH)
|
|
kfree(g_update_cfg_buf);
|
|
err_update_cfg_buf_adlled:
|
|
#endif
|
|
err_register_interrupt_failed:
|
|
/*err_detect_failed:*/
|
|
error_ic_detect_failed:
|
|
#if !defined(CONFIG_OF)
|
|
err_power_failed:
|
|
#endif
|
|
himax_gpio_power_deconfig(pdata);
|
|
err_alloc_dt_pdata_failed:
|
|
kfree(hx_s_touch_data);
|
|
hx_s_touch_data = NULL;
|
|
err_alloc_touch_data_failed:
|
|
kfree(hx_s_ic_data);
|
|
hx_s_ic_data = NULL;
|
|
err_dt_ic_data_fail:
|
|
kfree(pdata);
|
|
pdata = NULL;
|
|
err_dt_platform_data_fail:
|
|
devm_kfree(ts->dev, ts->xfer_buff);
|
|
ts->xfer_buff = NULL;
|
|
err_xfer_buff_fail:
|
|
probe_fail_flag = 1;
|
|
return err;
|
|
}
|
|
|
|
void himax_chip_common_deinit(void)
|
|
{
|
|
struct himax_ts_data *ts = hx_s_ts;
|
|
|
|
#if defined(HX_ZERO_FLASH)
|
|
if (g_update_cfg_buf != NULL)
|
|
kfree(g_update_cfg_buf);
|
|
#endif
|
|
|
|
himax_ts_unregister_interrupt();
|
|
himax_inspect_data_clear();
|
|
himax_debug_remove();
|
|
|
|
himax_common_proc_deinit();
|
|
himax_report_data_deinit();
|
|
|
|
#if defined(HX_SMART_WAKEUP)
|
|
#if defined(KERNEL_VER_ABOVE_4_19)
|
|
wakeup_source_unregister(ts->ts_SMWP_wake_lock);
|
|
#else
|
|
wakeup_source_trash(ts->ts_SMWP_wake_lock);
|
|
kfree(ts->ts_SMWP_wake_lock);
|
|
ts->ts_SMWP_wake_lock = NULL;
|
|
#endif
|
|
#endif
|
|
|
|
input_unregister_device(ts->input_dev);
|
|
if (hx_s_ic_data->stylus_func)
|
|
input_unregister_device(ts->stylus_dev);
|
|
#if defined(HX_CONTAINER_SPEED_UP)
|
|
cancel_delayed_work_sync(&ts->ts_int_work);
|
|
destroy_workqueue(ts->ts_int_workqueue);
|
|
#endif
|
|
|
|
#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH)
|
|
cancel_delayed_work_sync(&ts->work_boot_upgrade);
|
|
destroy_workqueue(ts->himax_boot_upgrade_wq);
|
|
#endif
|
|
himax_gpio_power_deconfig(ts->pdata);
|
|
if (himax_mcu_cmd_struct_free)
|
|
himax_mcu_cmd_struct_free();
|
|
|
|
kfree(hx_s_touch_data);
|
|
hx_s_touch_data = NULL;
|
|
kfree(hx_s_ic_data);
|
|
hx_s_ic_data = NULL;
|
|
devm_kfree(ts->dev, ts->xfer_buff);
|
|
ts->xfer_buff = NULL;
|
|
kfree(ts->pdata);
|
|
ts->pdata = NULL;
|
|
kfree(ts);
|
|
ts = NULL;
|
|
probe_fail_flag = 0;
|
|
#if defined(HX_USE_KSYM)
|
|
hx_release_chip_entry();
|
|
#endif
|
|
|
|
I("%s: Common section deinited!\n", __func__);
|
|
}
|
|
|
|
int himax_chip_common_suspend(struct himax_ts_data *ts)
|
|
{
|
|
if (ts->suspended) {
|
|
I("%s: Already suspended, skip...\n", __func__);
|
|
goto END;
|
|
} else {
|
|
ts->suspended = true;
|
|
}
|
|
|
|
if (hx_s_debug_data != NULL
|
|
&& hx_s_debug_data->flash_dump_going == true) {
|
|
I("%s: It is dumping flash, reject suspend\n", __func__);
|
|
goto END;
|
|
}
|
|
|
|
I("%s: enter\n", __func__);
|
|
|
|
if (ts->in_self_test == 1) {
|
|
atomic_set(&ts->suspend_mode, 1);
|
|
ts->pre_finger_mask = 0;
|
|
if (hx_s_core_fp._ap_notify_fw_sus != NULL)
|
|
hx_s_core_fp._ap_notify_fw_sus(1);
|
|
ts->suspend_resume_done = 1;
|
|
goto END;
|
|
}
|
|
|
|
hx_s_core_fp._suspend_proc(ts->suspended);
|
|
|
|
if (ts->SMWP_enable) {
|
|
if (hx_s_core_fp._0f_overlay != NULL)
|
|
hx_s_core_fp._0f_overlay(2, 0);
|
|
|
|
if (hx_s_core_fp._ap_notify_fw_sus != NULL)
|
|
hx_s_core_fp._ap_notify_fw_sus(1);
|
|
atomic_set(&ts->suspend_mode, 1);
|
|
ts->pre_finger_mask = 0;
|
|
I("%s: SMART WAKE UP enable, reject suspend\n", __func__);
|
|
goto END;
|
|
}
|
|
|
|
himax_int_enable(0);
|
|
if (hx_s_core_fp._suspend_ic_action != NULL)
|
|
hx_s_core_fp._suspend_ic_action();
|
|
|
|
if (!ts->use_irq) {
|
|
int32_t cancel_state;
|
|
|
|
cancel_state = cancel_work_sync(&ts->work);
|
|
if (cancel_state)
|
|
himax_int_enable(1);
|
|
}
|
|
|
|
/*ts->first_pressed = 0;*/
|
|
atomic_set(&ts->suspend_mode, 1);
|
|
ts->pre_finger_mask = 0;
|
|
|
|
if (ts->pdata)
|
|
if (ts->pdata->powerOff3V3 && ts->pdata->power)
|
|
ts->pdata->power(0);
|
|
|
|
END:
|
|
himax_report_all_leave_event(ts);
|
|
I("%s: END\n", __func__);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int himax_chip_common_resume(struct himax_ts_data *ts)
|
|
{
|
|
if (ts->suspended == false) {
|
|
I("%s: Already resumed, skip...\n", __func__);
|
|
goto END;
|
|
} else {
|
|
ts->suspended = false;
|
|
}
|
|
|
|
I("%s: enter\n", __func__);
|
|
|
|
if (ts->in_self_test == 1) {
|
|
atomic_set(&ts->suspend_mode, 0);
|
|
ts->diag_cmd = 0;
|
|
if (hx_s_core_fp._ap_notify_fw_sus != NULL)
|
|
hx_s_core_fp._ap_notify_fw_sus(0);
|
|
ts->suspend_resume_done = 1;
|
|
goto END;
|
|
}
|
|
|
|
#if defined(HX_EXCP_RECOVERY)
|
|
/* continuous N times record, not total N times. */
|
|
g_zero_event_count = 0;
|
|
#endif
|
|
|
|
atomic_set(&ts->suspend_mode, 0);
|
|
ts->diag_cmd = 0;
|
|
if (ts->SMWP_enable)
|
|
himax_int_enable(0);
|
|
if (ts->pdata)
|
|
if (ts->pdata->powerOff3V3 && ts->pdata->power)
|
|
ts->pdata->power(1);
|
|
#if defined(HX_RESUME_HW_RESET)
|
|
if (hx_s_core_fp._ic_reset != NULL)
|
|
hx_s_core_fp._ic_reset(0);
|
|
#endif
|
|
|
|
hx_s_core_fp._resume_proc(ts->suspended);
|
|
himax_report_all_leave_event(ts);
|
|
himax_int_enable(1);
|
|
/*
|
|
*#if defined(HX_ZERO_FLASH) && defined(HX_RESUME_SET_FW)
|
|
*ESCAPE_0F_UPDATE:
|
|
*#*endif
|
|
*/
|
|
END:
|
|
|
|
I("%s: END\n", __func__);
|
|
return 0;
|
|
}
|