1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2024-11-19 13:27:49 +00:00
a155-U-u1/kernel-5.10/drivers/input/touchscreen/GT9895/sec_common_fn.c
2024-03-11 06:53:12 +11:00

1478 lines
47 KiB
C

/*
* sec_common_fn.c - samsung common functions
*
* Copyright (C) 2020 Samsung Electronics
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include "sec_input.h"
#if !IS_ENABLED(CONFIG_SEC_KUNIT)
#define __visible_for_testing static
#endif
static char *lcd_id;
module_param(lcd_id, charp, S_IRUGO);
struct device *ptsp;
EXPORT_SYMBOL(ptsp);
static int sec_input_lcd_parse_panel_id(void)
{
char *pt;
int lcd_id_p = 0;
if (IS_ERR_OR_NULL(lcd_id))
return lcd_id_p;
for (pt = lcd_id; *pt != 0; pt++) {
lcd_id_p <<= 4;
switch (*pt) {
case '0' ... '9':
lcd_id_p += *pt - '0';
break;
case 'a' ... 'f':
lcd_id_p += 10 + *pt - 'a';
break;
case 'A' ... 'F':
lcd_id_p += 10 + *pt - 'A';
break;
}
}
return lcd_id_p;
}
int sec_input_get_lcd_id(struct device *dev)
{
#if !IS_ENABLED(CONFIG_SMCDSD_PANEL)
int lcdtype = 0;
#endif
#if IS_ENABLED(CONFIG_EXYNOS_DPU30) || IS_ENABLED(CONFIG_MCD_PANEL)
int connected;
#endif
int lcd_id_param = 0;
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
lcdtype = get_lcd_attached("GET");
if (lcdtype == 0xFFFFFF) {
input_err(true, dev, "%s: lcd is not attached(GET)\n", __func__);
return -ENODEV;
}
#endif
#if IS_ENABLED(CONFIG_EXYNOS_DPU30) || IS_ENABLED(CONFIG_MCD_PANEL)
connected = get_lcd_info("connected");
if (connected < 0) {
input_err(true, dev, "%s: Failed to get lcd info(connected)\n", __func__);
return -EINVAL;
}
if (!connected) {
input_err(true, dev, "%s: lcd is disconnected(connected)\n", __func__);
return -ENODEV;
}
input_info(true, dev, "%s: lcd is connected\n", __func__);
lcdtype = get_lcd_info("id");
if (lcdtype < 0) {
input_err(true, dev, "%s: Failed to get lcd info(id)\n", __func__);
return -EINVAL;
}
#endif
#if IS_ENABLED(CONFIG_SMCDSD_PANEL)
if (!lcdtype) {
input_err(true, dev, "%s: lcd is disconnected(lcdtype)\n", __func__);
return -ENODEV;
}
#endif
lcd_id_param = sec_input_lcd_parse_panel_id();
if (lcdtype <= 0 && lcd_id_param != 0) {
lcdtype = lcd_id_param;
if (lcdtype == 0xFFFFFF) {
input_err(true, dev, "%s: lcd is not attached(PARAM)\n", __func__);
return -ENODEV;
}
}
input_info(true, dev, "%s: lcdtype 0x%08X\n", __func__, lcdtype);
return lcdtype;
}
EXPORT_SYMBOL(sec_input_get_lcd_id);
int sec_input_handler_start(struct device *dev)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
int ret = 0;
if (gpio_get_value(pdata->irq_gpio) == 1)
return SEC_ERROR;
if (pdata->power_state == SEC_INPUT_STATE_LPM) {
__pm_wakeup_event(pdata->sec_ws, SEC_TS_WAKE_LOCK_TIME);
ret = wait_for_completion_interruptible_timeout(&pdata->resume_done, msecs_to_jiffies(500));
if (ret == 0) {
input_err(true, dev, "%s: LPM: pm resume is not handled\n", __func__);
return SEC_ERROR;
}
if (ret < 0) {
input_err(true, dev, "%s: LPM: -ERESTARTSYS if interrupted, %d\n", __func__, ret);
return ret;
}
input_info(true, dev, "%s: run LPM interrupt handler, %d\n", __func__, ret);
}
return SEC_SUCCESS;
}
EXPORT_SYMBOL(sec_input_handler_start);
/************************************************************
* 720 * 1480 : <48 96 60>
* indicator: 24dp navigator:48dp edge:60px dpi=320
* 1080 * 2220 : 4096 * 4096 : <133 266 341> (approximately value)
************************************************************/
static void location_detect(struct sec_ts_plat_data *pdata, int t_id)
{
int x = pdata->coord[t_id].x, y = pdata->coord[t_id].y;
memset(pdata->location, 0x00, SEC_TS_LOCATION_DETECT_SIZE);
if (x < pdata->area_edge)
strlcat(pdata->location, "E.", SEC_TS_LOCATION_DETECT_SIZE);
else if (x < (pdata->max_x - pdata->area_edge))
strlcat(pdata->location, "C.", SEC_TS_LOCATION_DETECT_SIZE);
else
strlcat(pdata->location, "e.", SEC_TS_LOCATION_DETECT_SIZE);
if (y < pdata->area_indicator)
strlcat(pdata->location, "S", SEC_TS_LOCATION_DETECT_SIZE);
else if (y < (pdata->max_y - pdata->area_navigation))
strlcat(pdata->location, "C", SEC_TS_LOCATION_DETECT_SIZE);
else
strlcat(pdata->location, "N", SEC_TS_LOCATION_DETECT_SIZE);
}
void sec_delay(unsigned int ms)
{
if (ms < 20)
usleep_range(ms * 1000, ms * 1000);
else
msleep(ms);
}
EXPORT_SYMBOL(sec_delay);
int sec_input_set_temperature(struct device *dev, int state)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
int ret = 0;
u8 temperature_data = 0;
bool bforced = false;
if (pdata->set_temperature == NULL) {
input_dbg(true, dev, "%s: vendor function is not allocated\n", __func__);
return SEC_ERROR;
}
if (state == SEC_INPUT_SET_TEMPERATURE_NORMAL) {
if (pdata->touch_count) {
pdata->tsp_temperature_data_skip = true;
input_err(true, dev, "%s: skip, t_cnt(%d)\n",
__func__, pdata->touch_count);
return SEC_SUCCESS;
}
} else if (state == SEC_INPUT_SET_TEMPERATURE_IN_IRQ) {
if (pdata->touch_count != 0 || pdata->tsp_temperature_data_skip == false)
return SEC_SUCCESS;
} else if (state == SEC_INPUT_SET_TEMPERATURE_FORCE) {
bforced = true;
} else {
input_err(true, dev, "%s: invalid param %d\n", __func__, state);
return SEC_ERROR;
}
pdata->tsp_temperature_data_skip = false;
if (!pdata->psy)
pdata->psy = power_supply_get_by_name("battery");
if (!pdata->psy) {
input_err(true, dev, "%s: cannot find power supply\n", __func__);
return SEC_ERROR;
}
ret = power_supply_get_property(pdata->psy, POWER_SUPPLY_PROP_TEMP, &pdata->psy_value);
if (ret < 0) {
input_err(true, dev, "%s: couldn't get temperature value, ret:%d\n", __func__, ret);
return ret;
}
temperature_data = (u8)(pdata->psy_value.intval / 10);
if (bforced || pdata->tsp_temperature_data != temperature_data) {
ret = pdata->set_temperature(dev, temperature_data);
if (ret < 0) {
input_err(true, dev, "%s: failed to write temperature %u, ret=%d\n",
__func__, temperature_data, ret);
return ret;
}
pdata->tsp_temperature_data = temperature_data;
input_info(true, dev, "%s set temperature:%u\n", __func__, temperature_data);
} else {
input_dbg(true, dev, "%s skip temperature:%u\n", __func__, temperature_data);
}
return SEC_SUCCESS;
}
EXPORT_SYMBOL(sec_input_set_temperature);
void sec_input_set_grip_type(struct device *dev, u8 set_type)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
u8 mode = G_NONE;
if (pdata->set_grip_data == NULL) {
input_dbg(true, dev, "%s: vendor function is not allocated\n", __func__);
return;
}
input_info(true, dev, "%s: re-init grip(%d), edh:%d, edg:%d, lan:%d\n", __func__,
set_type, pdata->grip_data.edgehandler_direction,
pdata->grip_data.edge_range, pdata->grip_data.landscape_mode);
if (pdata->grip_data.edgehandler_direction != 0)
mode |= G_SET_EDGE_HANDLER;
if (set_type == GRIP_ALL_DATA) {
/* edge */
if (pdata->grip_data.edge_range != 60)
mode |= G_SET_EDGE_ZONE;
/* dead zone default 0 mode, 32 */
if (pdata->grip_data.landscape_mode == 1)
mode |= G_SET_LANDSCAPE_MODE;
else
mode |= G_SET_NORMAL_MODE;
}
if (mode)
pdata->set_grip_data(dev, mode);
}
EXPORT_SYMBOL(sec_input_set_grip_type);
int sec_input_check_cover_type(struct device *dev)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
int cover_cmd = 0;
switch (pdata->cover_type) {
case SEC_TS_FLIP_COVER:
case SEC_TS_SVIEW_COVER:
case SEC_TS_SVIEW_CHARGER_COVER:
case SEC_TS_S_VIEW_WALLET_COVER:
case SEC_TS_LED_COVER:
case SEC_TS_CLEAR_COVER:
case SEC_TS_KEYBOARD_KOR_COVER:
case SEC_TS_KEYBOARD_US_COVER:
case SEC_TS_CLEAR_SIDE_VIEW_COVER:
case SEC_TS_MINI_SVIEW_WALLET_COVER:
case SEC_TS_MONTBLANC_COVER:
case SEC_TS_CLEAR_CAMERA_VIEW_COVER:
cover_cmd = pdata->cover_type;
break;
default:
input_err(true, dev, "%s: not change touch state, cover_type=%d\n",
__func__, pdata->cover_type);
break;
}
return cover_cmd;
}
EXPORT_SYMBOL(sec_input_check_cover_type);
void sec_input_set_fod_info(struct device *dev, int vi_x, int vi_y, int vi_size, int vi_event)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
int byte_size = vi_x * vi_y / 8;
if (vi_x * vi_y % 8)
byte_size++;
pdata->fod_data.vi_x = vi_x;
pdata->fod_data.vi_y = vi_y;
pdata->fod_data.vi_size = vi_size;
pdata->fod_data.vi_event = vi_event;
if (byte_size != vi_size)
input_err(true, dev, "%s: NEED TO CHECK! vi size %d maybe wrong (byte size should be %d)\n",
__func__, vi_size, byte_size);
input_info(true, dev, "%s: vi_event:%d, x:%d, y:%d, size:%d\n",
__func__, pdata->fod_data.vi_event, pdata->fod_data.vi_x, pdata->fod_data.vi_y,
pdata->fod_data.vi_size);
}
EXPORT_SYMBOL(sec_input_set_fod_info);
ssize_t sec_input_get_fod_info(struct device *dev, char *buf)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
if (!pdata->support_fod) {
input_err(true, dev, "%s: fod is not supported\n", __func__);
return snprintf(buf, SEC_CMD_BUF_SIZE, "NG");
}
if (pdata->x_node_num <= 0 || pdata->y_node_num <= 0) {
input_err(true, dev, "%s: x/y node num value is wrong\n", __func__);
return snprintf(buf, SEC_CMD_BUF_SIZE, "NG");
}
input_info(true, dev, "%s: x:%d/%d, y:%d/%d, size:%d\n",
__func__, pdata->fod_data.vi_x, pdata->x_node_num,
pdata->fod_data.vi_y, pdata->y_node_num, pdata->fod_data.vi_size);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%d,%d,%d,%d,%d",
pdata->fod_data.vi_x, pdata->fod_data.vi_y,
pdata->fod_data.vi_size, pdata->x_node_num, pdata->y_node_num);
}
EXPORT_SYMBOL(sec_input_get_fod_info);
bool sec_input_set_fod_rect(struct device *dev, int *rect_data)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
int i;
pdata->fod_data.set_val = 1;
if (rect_data[0] <= 0 || rect_data[1] <= 0 || rect_data[2] <= 0 || rect_data[3] <= 0)
pdata->fod_data.set_val = 0;
if (pdata->display_x > 0 && pdata->display_y > 0)
if (rect_data[0] >= pdata->display_x || rect_data[1] >= pdata->display_y
|| rect_data[2] >= pdata->display_x || rect_data[3] >= pdata->display_y)
pdata->fod_data.set_val = 0;
if (pdata->fod_data.set_val)
for (i = 0; i < 4; i++)
pdata->fod_data.rect_data[i] = rect_data[i];
return pdata->fod_data.set_val;
}
EXPORT_SYMBOL(sec_input_set_fod_rect);
int sec_input_check_wirelesscharger_mode(struct device *dev, int mode, int force)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
if (mode != TYPE_WIRELESS_CHARGER_NONE
&& mode != TYPE_WIRELESS_CHARGER
&& mode != TYPE_WIRELESS_BATTERY_PACK) {
input_err(true, dev,
"%s: invalid param %d\n", __func__, mode);
return SEC_ERROR;
}
if (pdata->force_wirelesscharger_mode == true && force == 0) {
input_err(true, dev,
"%s: [force enable] skip %d\n", __func__, mode);
return SEC_SKIP;
}
if (force == 1) {
if (mode == TYPE_WIRELESS_CHARGER_NONE) {
pdata->force_wirelesscharger_mode = false;
input_err(true, dev,
"%s: force enable off\n", __func__);
return SEC_SKIP;
}
pdata->force_wirelesscharger_mode = true;
}
pdata->wirelesscharger_mode = mode & 0xFF;
return SEC_SUCCESS;
}
EXPORT_SYMBOL(sec_input_check_wirelesscharger_mode);
ssize_t sec_input_get_common_hw_param(struct sec_ts_plat_data *pdata, char *buf)
{
char buff[SEC_INPUT_HW_PARAM_SIZE];
char tbuff[SEC_CMD_STR_LEN];
memset(buff, 0x00, sizeof(buff));
memset(tbuff, 0x00, sizeof(tbuff));
snprintf(tbuff, sizeof(tbuff), "\"TITO\":\"%02X%02X%02X%02X\",",
pdata->hw_param.ito_test[0], pdata->hw_param.ito_test[1],
pdata->hw_param.ito_test[2], pdata->hw_param.ito_test[3]);
strlcat(buff, tbuff, sizeof(buff));
memset(tbuff, 0x00, sizeof(tbuff));
snprintf(tbuff, sizeof(tbuff), "\"TMUL\":\"%d\",", pdata->hw_param.multi_count);
strlcat(buff, tbuff, sizeof(buff));
memset(tbuff, 0x00, sizeof(tbuff));
snprintf(tbuff, sizeof(tbuff), "\"TWET\":\"%d\",", pdata->hw_param.wet_count);
strlcat(buff, tbuff, sizeof(buff));
memset(tbuff, 0x00, sizeof(tbuff));
snprintf(tbuff, sizeof(tbuff), "\"TNOI\":\"%d\",", pdata->hw_param.noise_count);
strlcat(buff, tbuff, sizeof(buff));
memset(tbuff, 0x00, sizeof(tbuff));
snprintf(tbuff, sizeof(tbuff), "\"TCOM\":\"%d\",", pdata->hw_param.comm_err_count);
strlcat(buff, tbuff, sizeof(buff));
memset(tbuff, 0x00, sizeof(tbuff));
snprintf(tbuff, sizeof(tbuff), "\"TCHK\":\"%d\",", pdata->hw_param.checksum_result);
strlcat(buff, tbuff, sizeof(buff));
memset(tbuff, 0x00, sizeof(tbuff));
snprintf(tbuff, sizeof(tbuff), "\"TTCN\":\"%d\",\"TACN\":\"%d\",\"TSCN\":\"%d\",",
pdata->hw_param.all_finger_count, pdata->hw_param.all_aod_tap_count,
pdata->hw_param.all_spay_count);
strlcat(buff, tbuff, sizeof(buff));
memset(tbuff, 0x00, sizeof(tbuff));
snprintf(tbuff, sizeof(tbuff), "\"TMCF\":\"%d\",", pdata->hw_param.mode_change_failed_count);
strlcat(buff, tbuff, sizeof(buff));
memset(tbuff, 0x00, sizeof(tbuff));
snprintf(tbuff, sizeof(tbuff), "\"TRIC\":\"%d\"", pdata->hw_param.ic_reset_count);
strlcat(buff, tbuff, sizeof(buff));
return snprintf(buf, SEC_INPUT_HW_PARAM_SIZE, "%s", buff);
}
EXPORT_SYMBOL(sec_input_get_common_hw_param);
void sec_input_clear_common_hw_param(struct sec_ts_plat_data *pdata)
{
pdata->hw_param.multi_count = 0;
pdata->hw_param.wet_count = 0;
pdata->hw_param.noise_count = 0;
pdata->hw_param.comm_err_count = 0;
pdata->hw_param.checksum_result = 0;
pdata->hw_param.all_finger_count = 0;
pdata->hw_param.all_aod_tap_count = 0;
pdata->hw_param.all_spay_count = 0;
pdata->hw_param.mode_change_failed_count = 0;
pdata->hw_param.ic_reset_count = 0;
}
EXPORT_SYMBOL(sec_input_clear_common_hw_param);
void sec_input_print_info(struct device *dev, struct sec_tclm_data *tdata)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
char tclm_buff[INPUT_TCLM_LOG_BUF_SIZE] = { 0 };
pdata->print_info_cnt_open++;
if (pdata->print_info_cnt_open > 0xfff0)
pdata->print_info_cnt_open = 0;
if (pdata->touch_count == 0)
pdata->print_info_cnt_release++;
#if IS_ENABLED(CONFIG_INPUT_TOUCHSCREEN_TCLMV2)
if (tdata && (tdata->tclm_level == TCLM_LEVEL_NOT_SUPPORT))
snprintf(tclm_buff, sizeof(tclm_buff), "");
else if (tdata && tdata->tclm_string)
snprintf(tclm_buff, sizeof(tclm_buff), "C%02XT%04X.%4s%s Cal_flag:%d fail_cnt:%d",
tdata->nvdata.cal_count, tdata->nvdata.tune_fix_ver,
tdata->tclm_string[tdata->nvdata.cal_position].f_name,
(tdata->tclm_level == TCLM_LEVEL_LOCKDOWN) ? ".L" : " ",
tdata->nvdata.cal_fail_falg, tdata->nvdata.cal_fail_cnt);
else
snprintf(tclm_buff, sizeof(tclm_buff), "TCLM data is empty");
#else
snprintf(tclm_buff, sizeof(tclm_buff), "");
#endif
input_info(true, dev,
"mode:%04X tc:%d noise:%d/%d ext_n:%d wet:%d wc:%d(f:%d) lp:%x fn:%04X/%04X ED:%d PK:%d// v:%02X%02X %s // id:%d,%d tmp:%d // #%d %d\n",
pdata->print_info_currnet_mode, pdata->touch_count,
pdata->touch_noise_status, pdata->touch_pre_noise_status,
pdata->external_noise_mode, pdata->wet_mode,
pdata->wirelesscharger_mode, pdata->force_wirelesscharger_mode,
pdata->lowpower_mode, pdata->touch_functions, pdata->ic_status, pdata->ed_enable,
pdata->pocket_mode, pdata->img_version_of_ic[2], pdata->img_version_of_ic[3],
tclm_buff, pdata->tspid_val, pdata->tspicid_val,
pdata->tsp_temperature_data,
pdata->print_info_cnt_open, pdata->print_info_cnt_release);
}
EXPORT_SYMBOL(sec_input_print_info);
void sec_input_proximity_report(struct device *dev, int data)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
if (!pdata->support_ear_detect || !pdata->input_dev_proximity)
return;
if (!(pdata->ed_enable || pdata->pocket_mode))
return;
input_info(true, dev, "%s: PROX(%d)\n", __func__, data);
input_report_abs(pdata->input_dev_proximity, ABS_MT_CUSTOM, data);
input_sync(pdata->input_dev_proximity);
}
EXPORT_SYMBOL(sec_input_proximity_report);
void sec_input_gesture_report(struct device *dev, int id, int x, int y)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
char buff[SEC_TS_GESTURE_REPORT_BUFF_SIZE] = { 0 };
pdata->gesture_id = id;
pdata->gesture_x = x;
pdata->gesture_y = y;
input_report_key(pdata->input_dev, KEY_BLACK_UI_GESTURE, 1);
input_sync(pdata->input_dev);
input_report_key(pdata->input_dev, KEY_BLACK_UI_GESTURE, 0);
input_sync(pdata->input_dev);
if (id == SPONGE_EVENT_TYPE_SPAY) {
snprintf(buff, sizeof(buff), "SPAY");
pdata->hw_param.all_spay_count++;
} else if (id == SPONGE_EVENT_TYPE_SINGLE_TAP) {
snprintf(buff, sizeof(buff), "SINGLE TAP");
} else if (id == SPONGE_EVENT_TYPE_AOD_DOUBLETAB) {
snprintf(buff, sizeof(buff), "AOD");
pdata->hw_param.all_aod_tap_count++;
} else if (id == SPONGE_EVENT_TYPE_FOD_PRESS) {
snprintf(buff, sizeof(buff), "FOD PRESS");
} else if (id == SPONGE_EVENT_TYPE_FOD_RELEASE) {
snprintf(buff, sizeof(buff), "FOD RELEASE");
} else if (id == SPONGE_EVENT_TYPE_FOD_OUT) {
snprintf(buff, sizeof(buff), "FOD OUT");
} else if (id == SPONGE_EVENT_TYPE_TSP_SCAN_UNBLOCK) {
snprintf(buff, sizeof(buff), "SCAN UNBLOCK");
} else if (id == SPONGE_EVENT_TYPE_TSP_SCAN_BLOCK) {
snprintf(buff, sizeof(buff), "SCAN BLOCK");
} else {
snprintf(buff, sizeof(buff), "");
}
#if IS_ENABLED(CONFIG_SAMSUNG_PRODUCT_SHIP)
input_info(true, dev, "%s: %s: %d\n", __func__, buff, pdata->gesture_id);
#else
input_info(true, dev, "%s: %s: %d, %d, %d\n",
__func__, buff, pdata->gesture_id, pdata->gesture_x, pdata->gesture_y);
#endif
}
EXPORT_SYMBOL(sec_input_gesture_report);
static void sec_input_coord_report(struct device *dev, u8 t_id)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
int action = pdata->coord[t_id].action;
if (action == SEC_TS_COORDINATE_ACTION_RELEASE) {
input_mt_slot(pdata->input_dev, t_id);
if (pdata->support_mt_pressure)
input_report_abs(pdata->input_dev, ABS_MT_PRESSURE, 0);
input_mt_report_slot_state(pdata->input_dev, MT_TOOL_FINGER, 0);
pdata->palm_flag &= ~(1 << t_id);
if (pdata->touch_count > 0)
pdata->touch_count--;
if (pdata->touch_count == 0) {
input_report_key(pdata->input_dev, BTN_TOUCH, 0);
input_report_key(pdata->input_dev, BTN_TOOL_FINGER, 0);
pdata->hw_param.check_multi = 0;
pdata->print_info_cnt_release = 0;
pdata->palm_flag = 0;
}
input_report_key(pdata->input_dev, BTN_PALM, pdata->palm_flag);
} else if (action == SEC_TS_COORDINATE_ACTION_PRESS || action == SEC_TS_COORDINATE_ACTION_MOVE) {
if (action == SEC_TS_COORDINATE_ACTION_PRESS) {
pdata->touch_count++;
pdata->coord[t_id].p_x = pdata->coord[t_id].x;
pdata->coord[t_id].p_y = pdata->coord[t_id].y;
pdata->hw_param.all_finger_count++;
if ((pdata->touch_count > 4) && (pdata->hw_param.check_multi == 0)) {
pdata->hw_param.check_multi = 1;
pdata->hw_param.multi_count++;
}
} else {
/* action == SEC_TS_COORDINATE_ACTION_MOVE */
pdata->coord[t_id].mcount++;
}
input_mt_slot(pdata->input_dev, t_id);
input_mt_report_slot_state(pdata->input_dev, MT_TOOL_FINGER, 1);
input_report_key(pdata->input_dev, BTN_TOUCH, 1);
input_report_key(pdata->input_dev, BTN_TOOL_FINGER, 1);
input_report_key(pdata->input_dev, BTN_PALM, pdata->palm_flag);
input_report_abs(pdata->input_dev, ABS_MT_POSITION_X, pdata->coord[t_id].x);
input_report_abs(pdata->input_dev, ABS_MT_POSITION_Y, pdata->coord[t_id].y);
input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR, pdata->coord[t_id].major);
input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MINOR, pdata->coord[t_id].minor);
if (pdata->support_mt_pressure)
input_report_abs(pdata->input_dev, ABS_MT_PRESSURE, pdata->coord[t_id].z);
}
}
static void sec_input_coord_log(struct device *dev, u8 t_id, int action)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
location_detect(pdata, t_id);
if (action == SEC_TS_COORDINATE_ACTION_PRESS) {
#if !IS_ENABLED(CONFIG_SAMSUNG_PRODUCT_SHIP)
input_info(true, dev,
"[P] tID:%d.%d x:%d y:%d z:%d major:%d minor:%d loc:%s tc:%d type:%X noise:(%x,%d%d), nlvl:%d, maxS:%d, hid:%d\n",
t_id, (pdata->input_dev->mt->trkid - 1) & TRKID_MAX,
pdata->coord[t_id].x, pdata->coord[t_id].y, pdata->coord[t_id].z,
pdata->coord[t_id].major, pdata->coord[t_id].minor,
pdata->location, pdata->touch_count,
pdata->coord[t_id].ttype,
pdata->coord[t_id].noise_status, pdata->touch_noise_status,
pdata->touch_pre_noise_status, pdata->coord[t_id].noise_level,
pdata->coord[t_id].max_strength, pdata->coord[t_id].hover_id_num);
#else
input_info(true, dev,
"[P] tID:%d.%d z:%d major:%d minor:%d loc:%s tc:%d type:%X noise:(%x,%d%d), nlvl:%d, maxS:%d, hid:%d\n",
t_id, (pdata->input_dev->mt->trkid - 1) & TRKID_MAX,
pdata->coord[t_id].z, pdata->coord[t_id].major,
pdata->coord[t_id].minor, pdata->location, pdata->touch_count,
pdata->coord[t_id].ttype,
pdata->coord[t_id].noise_status, pdata->touch_noise_status,
pdata->touch_pre_noise_status, pdata->coord[t_id].noise_level,
pdata->coord[t_id].max_strength, pdata->coord[t_id].hover_id_num);
#endif
} else if (action == SEC_TS_COORDINATE_ACTION_MOVE) {
#if !IS_ENABLED(CONFIG_SAMSUNG_PRODUCT_SHIP)
input_info(true, dev,
"[M] tID:%d.%d x:%d y:%d z:%d major:%d minor:%d loc:%s tc:%d type:%X noise:(%x,%d%d), nlvl:%d, maxS:%d, hid:%d\n",
t_id, pdata->input_dev->mt->trkid & TRKID_MAX,
pdata->coord[t_id].x, pdata->coord[t_id].y, pdata->coord[t_id].z,
pdata->coord[t_id].major, pdata->coord[t_id].minor,
pdata->location, pdata->touch_count,
pdata->coord[t_id].ttype, pdata->coord[t_id].noise_status,
pdata->touch_noise_status, pdata->touch_pre_noise_status,
pdata->coord[t_id].noise_level, pdata->coord[t_id].max_strength,
pdata->coord[t_id].hover_id_num);
#else
input_info(true, dev,
"[M] tID:%d.%d z:%d major:%d minor:%d loc:%s tc:%d type:%X noise:(%x,%d%d), nlvl:%d, maxS:%d, hid:%d\n",
t_id, pdata->input_dev->mt->trkid & TRKID_MAX, pdata->coord[t_id].z,
pdata->coord[t_id].major, pdata->coord[t_id].minor,
pdata->location, pdata->touch_count,
pdata->coord[t_id].ttype, pdata->coord[t_id].noise_status,
pdata->touch_noise_status, pdata->touch_pre_noise_status,
pdata->coord[t_id].noise_level, pdata->coord[t_id].max_strength,
pdata->coord[t_id].hover_id_num);
#endif
} else if (action == SEC_TS_COORDINATE_ACTION_RELEASE || action == SEC_TS_COORDINATE_ACTION_FORCE_RELEASE) {
#if !IS_ENABLED(CONFIG_SAMSUNG_PRODUCT_SHIP)
input_info(true, dev,
"[R%s] tID:%d loc:%s dd:%d,%d mc:%d tc:%d lx:%d ly:%d p:%d noise:(%x,%d%d) nlvl:%d, maxS:%d, hid:%d\n",
action == SEC_TS_COORDINATE_ACTION_FORCE_RELEASE ? "A" : "",
t_id, pdata->location,
pdata->coord[t_id].x - pdata->coord[t_id].p_x,
pdata->coord[t_id].y - pdata->coord[t_id].p_y,
pdata->coord[t_id].mcount, pdata->touch_count,
pdata->coord[t_id].x, pdata->coord[t_id].y,
pdata->coord[t_id].palm_count,
pdata->coord[t_id].noise_status, pdata->touch_noise_status,
pdata->touch_pre_noise_status, pdata->coord[t_id].noise_level,
pdata->coord[t_id].max_strength, pdata->coord[t_id].hover_id_num);
#else
input_info(true, dev,
"[R%s] tID:%d loc:%s dd:%d,%d mc:%d tc:%d p:%d noise:(%x,%d%d) nlvl:%d, maxS:%d, hid:%d\n",
action == SEC_TS_COORDINATE_ACTION_FORCE_RELEASE ? "A" : "",
t_id, pdata->location,
pdata->coord[t_id].x - pdata->coord[t_id].p_x,
pdata->coord[t_id].y - pdata->coord[t_id].p_y,
pdata->coord[t_id].mcount, pdata->touch_count,
pdata->coord[t_id].palm_count,
pdata->coord[t_id].noise_status, pdata->touch_noise_status,
pdata->touch_pre_noise_status, pdata->coord[t_id].noise_level,
pdata->coord[t_id].max_strength, pdata->coord[t_id].hover_id_num);
#endif
}
}
void sec_input_coord_event(struct device *dev, int t_id)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
if (pdata->coord[t_id].action == SEC_TS_COORDINATE_ACTION_RELEASE) {
if (pdata->prev_coord[t_id].action == SEC_TS_COORDINATE_ACTION_NONE
|| pdata->prev_coord[t_id].action == SEC_TS_COORDINATE_ACTION_RELEASE) {
input_err(true, dev,
"%s: tID %d released without press\n", __func__, t_id);
return;
}
sec_input_coord_report(dev, t_id);
if ((pdata->touch_count == 0) && !IS_ERR_OR_NULL(&pdata->interrupt_notify_work.work)) {
schedule_work(&pdata->interrupt_notify_work.work);
}
sec_input_coord_log(dev, t_id, SEC_TS_COORDINATE_ACTION_RELEASE);
pdata->coord[t_id].action = SEC_TS_COORDINATE_ACTION_NONE;
pdata->coord[t_id].mcount = 0;
pdata->coord[t_id].palm_count = 0;
pdata->coord[t_id].noise_level = 0;
pdata->coord[t_id].max_strength = 0;
pdata->coord[t_id].hover_id_num = 0;
} else if (pdata->coord[t_id].action == SEC_TS_COORDINATE_ACTION_PRESS) {
sec_input_coord_report(dev, t_id);
if ((pdata->touch_count == 1) && !IS_ERR_OR_NULL(&pdata->interrupt_notify_work.work)) {
schedule_work(&pdata->interrupt_notify_work.work);
}
sec_input_coord_log(dev, t_id, SEC_TS_COORDINATE_ACTION_PRESS);
} else if (pdata->coord[t_id].action == SEC_TS_COORDINATE_ACTION_MOVE) {
if (pdata->prev_coord[t_id].action == SEC_TS_COORDINATE_ACTION_NONE
|| pdata->prev_coord[t_id].action == SEC_TS_COORDINATE_ACTION_RELEASE) {
pdata->coord[t_id].action = SEC_TS_COORDINATE_ACTION_PRESS;
sec_input_coord_report(dev, t_id);
sec_input_coord_log(dev, t_id, SEC_TS_COORDINATE_ACTION_MOVE);
} else {
sec_input_coord_report(dev, t_id);
}
} else {
input_dbg(true, dev,
"%s: do not support coordinate action(%d)\n",
__func__, pdata->coord[t_id].action);
}
if ((pdata->coord[t_id].action == SEC_TS_COORDINATE_ACTION_PRESS)
|| (pdata->coord[t_id].action == SEC_TS_COORDINATE_ACTION_MOVE)) {
if (pdata->coord[t_id].ttype != pdata->prev_coord[t_id].ttype) {
input_info(true, dev, "%s : tID:%d ttype(%x->%x)\n",
__func__, pdata->coord[t_id].id,
pdata->prev_coord[t_id].ttype, pdata->coord[t_id].ttype);
}
}
input_sync(pdata->input_dev);
}
EXPORT_SYMBOL(sec_input_coord_event);
void sec_input_release_all_finger(struct device *dev)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
int i;
if (!pdata->input_dev)
return;
if (pdata->prox_power_off) {
input_report_key(pdata->input_dev, KEY_INT_CANCEL, 1);
input_sync(pdata->input_dev);
input_report_key(pdata->input_dev, KEY_INT_CANCEL, 0);
input_sync(pdata->input_dev);
}
if (pdata->input_dev_proximity) {
input_report_abs(pdata->input_dev_proximity, ABS_MT_CUSTOM, 0xff);
input_sync(pdata->input_dev_proximity);
}
for (i = 0; i < SEC_TS_SUPPORT_TOUCH_COUNT; i++) {
input_mt_slot(pdata->input_dev, i);
input_mt_report_slot_state(pdata->input_dev, MT_TOOL_FINGER, false);
if (pdata->coord[i].action == SEC_TS_COORDINATE_ACTION_PRESS
|| pdata->coord[i].action == SEC_TS_COORDINATE_ACTION_MOVE) {
sec_input_coord_log(dev, i, SEC_TS_COORDINATE_ACTION_FORCE_RELEASE);
pdata->coord[i].action = SEC_TS_COORDINATE_ACTION_RELEASE;
}
pdata->coord[i].mcount = 0;
pdata->coord[i].palm_count = 0;
pdata->coord[i].noise_level = 0;
pdata->coord[i].max_strength = 0;
pdata->coord[i].hover_id_num = 0;
}
input_mt_slot(pdata->input_dev, 0);
input_report_key(pdata->input_dev, BTN_PALM, false);
input_report_key(pdata->input_dev, BTN_LARGE_PALM, false);
input_report_key(pdata->input_dev, BTN_TOUCH, false);
input_report_key(pdata->input_dev, BTN_TOOL_FINGER, false);
pdata->palm_flag = 0;
pdata->touch_count = 0;
pdata->hw_param.check_multi = 0;
input_sync(pdata->input_dev);
}
EXPORT_SYMBOL(sec_input_release_all_finger);
static void sec_input_set_prop(struct device *dev, struct input_dev *input_dev, u8 propbit, void *data)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
static char sec_input_phys[64] = { 0 };
snprintf(sec_input_phys, sizeof(sec_input_phys), "%s/input1", input_dev->name);
input_dev->phys = sec_input_phys;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = dev;
set_bit(EV_SYN, input_dev->evbit);
set_bit(EV_KEY, input_dev->evbit);
set_bit(EV_ABS, input_dev->evbit);
set_bit(EV_SW, input_dev->evbit);
set_bit(BTN_TOUCH, input_dev->keybit);
set_bit(BTN_TOOL_FINGER, input_dev->keybit);
set_bit(BTN_PALM, input_dev->keybit);
set_bit(BTN_LARGE_PALM, input_dev->keybit);
set_bit(KEY_BLACK_UI_GESTURE, input_dev->keybit);
set_bit(KEY_INT_CANCEL, input_dev->keybit);
set_bit(propbit, input_dev->propbit);
set_bit(KEY_WAKEUP, input_dev->keybit);
set_bit(KEY_WATCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, pdata->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, pdata->max_y, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
if (pdata->support_mt_pressure)
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
if (propbit == INPUT_PROP_POINTER)
input_mt_init_slots(input_dev, SEC_TS_SUPPORT_TOUCH_COUNT, INPUT_MT_POINTER);
else
input_mt_init_slots(input_dev, SEC_TS_SUPPORT_TOUCH_COUNT, INPUT_MT_DIRECT);
input_set_drvdata(input_dev, data);
}
static void sec_input_set_prop_proximity(struct device *dev, struct input_dev *input_dev, void *data)
{
static char sec_input_phys[64] = { 0 };
snprintf(sec_input_phys, sizeof(sec_input_phys), "%s/input1", input_dev->name);
input_dev->phys = sec_input_phys;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = dev;
set_bit(EV_SYN, input_dev->evbit);
set_bit(EV_SW, input_dev->evbit);
set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
input_set_abs_params(input_dev, ABS_MT_CUSTOM, 0, 0xFFFFFFFF, 0, 0);
input_set_drvdata(input_dev, data);
}
int sec_input_device_register(struct device *dev, void *data)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
int ret = 0;
/* register input_dev */
pdata->input_dev = devm_input_allocate_device(dev);
if (!pdata->input_dev) {
input_err(true, dev, "%s: allocate input_dev err!\n", __func__);
return -ENOMEM;
}
#if IS_ENABLED(CONFIG_TOUCHSCREEN_DUAL_FOLDABLE)
if (pdata->support_dual_foldable == SUB_TOUCH)
pdata->input_dev->name = "sec_touchscreen2";
else
#endif
pdata->input_dev->name = "sec_touchscreen";
sec_input_set_prop(dev, pdata->input_dev, INPUT_PROP_DIRECT, data);
ret = input_register_device(pdata->input_dev);
if (ret) {
input_err(true, dev, "%s: Unable to register %s input device\n",
__func__, pdata->input_dev->name);
return ret;
}
if (pdata->support_dex) {
/* register input_dev_pad */
pdata->input_dev_pad = devm_input_allocate_device(dev);
if (!pdata->input_dev_pad) {
input_err(true, dev, "%s: allocate input_dev_pad err!\n", __func__);
return -ENOMEM;
}
pdata->input_dev_pad->name = "sec_touchpad";
sec_input_set_prop(dev, pdata->input_dev_pad, INPUT_PROP_POINTER, data);
ret = input_register_device(pdata->input_dev_pad);
if (ret) {
input_err(true, dev, "%s: Unable to register %s input device\n",
__func__, pdata->input_dev_pad->name);
return ret;
}
}
if (pdata->support_ear_detect || pdata->support_lightsensor_detect) {
/* register input_dev_proximity */
pdata->input_dev_proximity = devm_input_allocate_device(dev);
if (!pdata->input_dev_proximity) {
input_err(true, dev, "%s: allocate input_dev_proximity err!\n", __func__);
return -ENOMEM;
}
#if IS_ENABLED(CONFIG_TOUCHSCREEN_DUAL_FOLDABLE)
if (pdata->support_dual_foldable == SUB_TOUCH)
pdata->input_dev_proximity->name = "sec_touchproximity2";
else
#endif
pdata->input_dev_proximity->name = "sec_touchproximity";
sec_input_set_prop_proximity(dev, pdata->input_dev_proximity, data);
ret = input_register_device(pdata->input_dev_proximity);
if (ret) {
input_err(true, dev, "%s: Unable to register %s input device\n",
__func__, pdata->input_dev_proximity->name);
return ret;
}
}
return 0;
}
EXPORT_SYMBOL(sec_input_device_register);
int sec_input_pinctrl_configure(struct device *dev, bool on)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
struct pinctrl_state *state;
input_info(true, dev, "%s: %s\n", __func__, on ? "ACTIVE" : "SUSPEND");
if (on) {
state = pinctrl_lookup_state(pdata->pinctrl, "on_state");
if (IS_ERR(pdata->pinctrl))
input_err(true, dev, "%s: could not get active pinstate\n", __func__);
} else {
state = pinctrl_lookup_state(pdata->pinctrl, "off_state");
if (IS_ERR(pdata->pinctrl))
input_err(true, dev, "%s: could not get suspend pinstate\n", __func__);
}
if (!IS_ERR_OR_NULL(state))
return pinctrl_select_state(pdata->pinctrl, state);
return 0;
}
EXPORT_SYMBOL(sec_input_pinctrl_configure);
int sec_input_power(struct device *dev, bool on)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
int ret = 0;
struct pinctrl_state *state;
if (pdata->power_enabled == on) {
input_info(true, dev, "%s: power_enabled %d\n", __func__, pdata->power_enabled);
return ret;
}
#if 1 // LDO by GPIO control
if (on) {
state = pinctrl_lookup_state(pdata->pinctrl, "tsp_ldo_en1_gpio");
if (IS_ERR(pdata->pinctrl))
input_err(true, dev, "%s: could not get ldo en1 pinstate\n", __func__);
} else {
state = pinctrl_lookup_state(pdata->pinctrl, "tsp_ldo_en0_gpio");
if (IS_ERR(pdata->pinctrl))
input_err(true, dev, "%s: could not get ldo en0 pinstate\n", __func__);
}
pdata->power_enabled = on;
if (!IS_ERR_OR_NULL(state))
return pinctrl_select_state(pdata->pinctrl, state);
#else // LDO by regulator
if (on) {
if (!pdata->not_support_io_ldo) {
ret = regulator_enable(pdata->dvdd);
if (ret) {
input_err(true, dev, "%s: Failed to enable dvdd: %d\n", __func__, ret);
goto out;
}
sec_delay(1);
}
ret = regulator_enable(pdata->avdd);
if (ret) {
input_err(true, dev, "%s: Failed to enable avdd: %d\n", __func__, ret);
goto out;
}
} else {
regulator_disable(pdata->avdd);
if (!pdata->not_support_io_ldo) {
sec_delay(4);
regulator_disable(pdata->dvdd);
}
}
pdata->power_enabled = on;
out:
if (!pdata->not_support_io_ldo) {
input_info(true, dev, "%s: %s: avdd:%s, dvdd:%s\n", __func__, on ? "on" : "off",
regulator_is_enabled(pdata->avdd) ? "on" : "off",
regulator_is_enabled(pdata->dvdd) ? "on" : "off");
} else {
input_info(true, dev, "%s: %s: avdd:%s\n", __func__, on ? "on" : "off",
regulator_is_enabled(pdata->avdd) ? "on" : "off");
}
#endif
return ret;
}
EXPORT_SYMBOL(sec_input_power);
int sec_input_parse_dt(struct device *dev)
{
struct sec_ts_plat_data *pdata = dev->platform_data;
struct device_node *np = dev->of_node;
u32 coords[2];
int ret = 0;
int count = 0, i;
u32 ic_match_value;
u32 px_zone[3] = { 0 };
int lcd_type = 0, lcd_type_unload = 0;
lcd_type = sec_input_get_lcd_id(dev);
#if !defined(DUAL_FOLDABLE_GKI)
if (lcd_type < 0) {
input_err(true, dev, "%s: lcd is not attached\n", __func__);
#if !IS_ENABLED(CONFIG_TOUCHSCREEN_STM_SUB)
return -ENODEV;
#endif
}
#endif
input_info(true, dev, "%s: lcdtype 0x%08X\n", __func__, lcd_type);
if (!of_property_read_u32(np, "sec,lcd_type_unload", &lcd_type_unload)) {
if ((lcd_type != 0) && (lcd_type == lcd_type_unload)) {
input_err(true, dev, "%s: do not load lcdtype 0x%08X\n", __func__, lcd_type);
return -ENODEV;
}
}
pdata->tsp_icid = of_get_named_gpio(np, "sec,tsp-icid_gpio", 0);
if (gpio_is_valid(pdata->tsp_icid)) {
input_info(true, dev, "%s: TSP_ICID : %d\n", __func__, gpio_get_value(pdata->tsp_icid));
if (of_property_read_u32(np, "sec,icid_match_value", &ic_match_value)) {
input_err(true, dev, "%s: not use icid match value\n", __func__);
return -EINVAL;
}
pdata->tspicid_val = gpio_get_value(pdata->tsp_icid);
if (pdata->tspicid_val != ic_match_value) {
input_err(true, dev, "%s: Do not match TSP_ICID\n", __func__);
return -EINVAL;
}
} else {
input_err(true, dev, "%s: not use tsp-icid gpio\n", __func__);
}
pdata->irq_gpio = of_get_named_gpio(np, "sec,irq_gpio", 0);
if (gpio_is_valid(pdata->irq_gpio)) {
ret = devm_gpio_request_one(dev, pdata->irq_gpio, GPIOF_DIR_IN, "sec,tsp_int");
if (ret) {
input_err(true, dev, "%s: Unable to request tsp_int [%d]\n", __func__, pdata->irq_gpio);
return -EINVAL;
}
} else {
input_err(true, dev, "%s: Failed to get irq gpio\n", __func__);
return -EINVAL;
}
if (of_property_read_u32(np, "sec,irq_flag", &pdata->irq_flag))
pdata->irq_flag = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
input_dbg(true, dev, "%s: irq_flag property 0x%X\n", __func__, pdata->irq_flag);
pdata->gpio_spi_cs = of_get_named_gpio(np, "sec,gpio_spi_cs", 0);
if (gpio_is_valid(pdata->gpio_spi_cs)) {
ret = gpio_request(pdata->gpio_spi_cs, "tsp,gpio_spi_cs");
input_info(true, dev, "%s: gpio_spi_cs: %d, ret: %d\n", __func__, pdata->gpio_spi_cs, ret);
ret = 0;
}
if (of_property_read_u32(np, "sec,i2c-burstmax", &pdata->i2c_burstmax)) {
input_dbg(false, dev, "%s: Failed to get i2c_burstmax property\n", __func__);
pdata->i2c_burstmax = 0xffff;
}
if (of_property_read_u32_array(np, "sec,max_coords", coords, 2)) {
input_err(true, dev, "%s: Failed to get max_coords property\n", __func__);
return -EINVAL;
}
pdata->max_x = coords[0] - 1;
pdata->max_y = coords[1] - 1;
if (of_property_read_u32(np, "sec,bringup", &pdata->bringup) < 0)
pdata->bringup = 0;
pdata->tsp_id = of_get_named_gpio(np, "sec,tsp-id_gpio", 0);
if (gpio_is_valid(pdata->tsp_id)) {
pdata->tspid_val = gpio_get_value(pdata->tsp_id);
input_info(true, dev, "%s: TSP_ID : %d\n", __func__, pdata->tspid_val);
} else {
input_err(true, dev, "%s: not use tsp-id gpio\n", __func__);
}
count = of_property_count_strings(np, "sec,firmware_name");
if (count <= 0) {
pdata->firmware_name = NULL;
} else {
if (gpio_is_valid(pdata->tsp_id) && pdata->tspid_val) {
of_property_read_string_index(np, "sec,firmware_name",
pdata->tspid_val, &pdata->firmware_name);
if (pdata->bringup == 4)
pdata->bringup = 2;
} else {
u8 lcd_id_num = of_property_count_u32_elems(np, "sec,select_lcdid");
if ((lcd_id_num != count) || (lcd_id_num <= 0)) {
of_property_read_string_index(np, "sec,firmware_name", 0, &pdata->firmware_name);
} else {
u32 *lcd_id_t;
u32 lcd_id_mask;
lcd_id_t = kcalloc(lcd_id_num, sizeof(u32), GFP_KERNEL);
if (!lcd_id_t)
return -ENOMEM;
of_property_read_u32_array(np, "sec,select_lcdid", lcd_id_t, lcd_id_num);
if (of_property_read_u32(np, "sec,lcdid_mask", &lcd_id_mask) < 0)
lcd_id_mask = 0xFFFFFF;
else
input_info(true, dev, "%s: lcd_id_mask: 0x%06X\n", __func__, lcd_id_mask);
for (i = 0; i < lcd_id_num; i++) {
if ((lcd_id_t[i] & lcd_id_mask) == (lcd_type & lcd_id_mask)) {
of_property_read_string_index(np, "sec,firmware_name", i, &pdata->firmware_name);
break;
}
if (i == (lcd_id_num - 1))
of_property_read_string_index(np, "sec,firmware_name", i, &pdata->firmware_name);
}
if (!pdata->firmware_name)
pdata->bringup = 1;
else if (strlen(pdata->firmware_name) == 0)
pdata->bringup = 1;
input_info(true, dev, "%s: count: %d, index:%d, lcd_id: 0x%X, firmware: %s\n",
__func__, count, i, lcd_id_t[i], pdata->firmware_name);
kfree(lcd_id_t);
}
if (pdata->bringup == 4)
pdata->bringup = 3;
}
}
pdata->not_support_vdd = of_property_read_bool(np, "not_support_vdd");
if (!pdata->not_support_vdd) {
pdata->not_support_io_ldo = of_property_read_bool(np, "not_support_io_ldo");
if (!pdata->not_support_io_ldo) {
pdata->dvdd = regulator_get(dev, "tsp_io_ldo");
if (IS_ERR_OR_NULL(pdata->dvdd)) {
input_err(true, dev, "%s: Failed to get %s regulator.\n",
__func__, "tsp_io_ldo");
ret = PTR_ERR(pdata->dvdd);
#if !IS_ENABLED(CONFIG_QGKI)
if (gpio_is_valid(pdata->gpio_spi_cs))
gpio_free(pdata->gpio_spi_cs);
#endif
return -EINVAL;
}
}
pdata->avdd = regulator_get(dev, "tsp_avdd_ldo");
if (IS_ERR_OR_NULL(pdata->avdd)) {
input_err(true, dev, "%s: Failed to get %s regulator.\n",
__func__, "tsp_avdd_ldo");
ret = PTR_ERR(pdata->avdd);
#if !IS_ENABLED(CONFIG_QGKI)
if (gpio_is_valid(pdata->gpio_spi_cs))
gpio_free(pdata->gpio_spi_cs);
#endif
return -EINVAL;
}
}
pdata->regulator_boot_on = of_property_read_bool(np, "sec,regulator_boot_on");
pdata->support_dex = of_property_read_bool(np, "support_dex_mode");
pdata->support_fod = of_property_read_bool(np, "support_fod");
pdata->support_fod_lp_mode = of_property_read_bool(np, "support_fod_lp_mode");
pdata->enable_settings_aot = of_property_read_bool(np, "enable_settings_aot");
pdata->sync_reportrate_120 = of_property_read_bool(np, "sync-reportrate-120");
pdata->support_refresh_rate_mode = of_property_read_bool(np, "support_refresh_rate_mode");
pdata->support_vrr = of_property_read_bool(np, "support_vrr");
pdata->support_ear_detect = of_property_read_bool(np, "support_ear_detect_mode");
pdata->support_open_short_test = of_property_read_bool(np, "support_open_short_test");
pdata->support_mis_calibration_test = of_property_read_bool(np, "support_mis_calibration_test");
pdata->support_wireless_tx = of_property_read_bool(np, "support_wireless_tx");
pdata->support_input_monitor = of_property_read_bool(np, "support_input_monitor");
pdata->chip_on_board = of_property_read_bool(np, "chip_on_board");
pdata->disable_vsync_scan = of_property_read_bool(np, "disable_vsync_scan");
pdata->unuse_dvdd_power = of_property_read_bool(np, "sec,unuse_dvdd_power");
pdata->sense_off_when_cover_closed = of_property_read_bool(np, "sense_off_when_cover_closed");
of_property_read_u32(np, "support_rawdata_map_num", &pdata->support_rawdata_map_num);
if (of_property_read_u32(np, "sec,support_dual_foldable", &pdata->support_dual_foldable) < 0)
pdata->support_dual_foldable = 0;
if (of_property_read_u32(np, "sec,support_sensor_hall", &pdata->support_sensor_hall) < 0)
pdata->support_sensor_hall = 0;
if (of_property_read_u32(np, "sec,dump_ic_ver", &pdata->dump_ic_ver) < 0)
pdata->dump_ic_ver = 0;
pdata->support_flex_mode = of_property_read_bool(np, "support_flex_mode");
pdata->support_lightsensor_detect = of_property_read_bool(np, "support_lightsensor_detect");
pdata->enable_sysinput_enabled = of_property_read_bool(np, "sec,enable_sysinput_enabled");
input_info(true, dev, "%s: Sysinput enabled %s\n",
__func__, pdata->enable_sysinput_enabled ? "ON" : "OFF");
if (of_property_read_u32_array(np, "sec,area-size", px_zone, 3)) {
input_info(true, dev, "Failed to get zone's size\n");
pdata->area_indicator = 48;
pdata->area_navigation = 96;
pdata->area_edge = 60;
} else {
pdata->area_indicator = px_zone[0];
pdata->area_navigation = px_zone[1];
pdata->area_edge = px_zone[2];
}
input_info(true, dev, "%s : zone's size - indicator:%d, navigation:%d, edge:%d\n",
__func__, pdata->area_indicator, pdata->area_navigation ,pdata->area_edge);
#if IS_ENABLED(CONFIG_INPUT_SEC_SECURE_TOUCH)
of_property_read_u32(np, "sec,ss_touch_num", &pdata->ss_touch_num);
input_err(true, dev, "%s: ss_touch_num:%d\n", __func__, pdata->ss_touch_num);
#endif
#if IS_ENABLED(CONFIG_SEC_FACTORY)
pdata->support_mt_pressure = true;
#endif
input_err(true, dev, "%s: i2c buffer limit: %d, lcd_id:%06X, bringup:%d,"
" id:%d,%d, dex:%d, max(%d/%d), FOD:%d, AOT:%d, ED:%d, FLM:%d,"
" COB:%d, disable_vsync_scan:%d, unuse_dvdd_power:%d\n",
__func__, pdata->i2c_burstmax, lcd_type, pdata->bringup,
pdata->tsp_id, pdata->tsp_icid,
pdata->support_dex, pdata->max_x, pdata->max_y,
pdata->support_fod, pdata->enable_settings_aot,
pdata->support_ear_detect, pdata->support_fod_lp_mode,
pdata->chip_on_board, pdata->disable_vsync_scan, pdata->unuse_dvdd_power);
return ret;
}
EXPORT_SYMBOL(sec_input_parse_dt);
void sec_tclm_parse_dt(struct device *dev, struct sec_tclm_data *tdata)
{
struct device_node *np = dev->of_node;
if (of_property_read_u32(np, "sec,tclm_level", &tdata->tclm_level) < 0) {
tdata->tclm_level = 0;
input_err(true, dev, "%s: Failed to get tclm_level property\n", __func__);
}
if (of_property_read_u32(np, "sec,afe_base", &tdata->afe_base) < 0) {
tdata->afe_base = 0;
input_err(true, dev, "%s: Failed to get afe_base property\n", __func__);
}
tdata->support_tclm_test = of_property_read_bool(np, "support_tclm_test");
input_err(true, dev, "%s: tclm_level %d, sec_afe_base %04X\n", __func__, tdata->tclm_level, tdata->afe_base);
}
EXPORT_SYMBOL(sec_tclm_parse_dt);
void sec_tclm_parse_dt_dev(struct device *dev, struct sec_tclm_data *tdata)
{
struct device_node *np = dev->of_node;
if (of_property_read_u32(np, "sec,tclm_level", &tdata->tclm_level) < 0) {
tdata->tclm_level = 0;
input_err(true, dev, "%s: Failed to get tclm_level property\n", __func__);
}
if (of_property_read_u32(np, "sec,afe_base", &tdata->afe_base) < 0) {
tdata->afe_base = 0;
input_err(true, dev, "%s: Failed to get afe_base property\n", __func__);
}
tdata->support_tclm_test = of_property_read_bool(np, "support_tclm_test");
input_err(true, dev, "%s: tclm_level %d, sec_afe_base %04X\n", __func__, tdata->tclm_level, tdata->afe_base);
}
EXPORT_SYMBOL(sec_tclm_parse_dt_dev);
int stui_tsp_enter(void)
{
struct sec_ts_plat_data *pdata = NULL;
if (ptsp == NULL)
return -EINVAL;
pdata = ptsp->platform_data;
if (pdata == NULL)
return -EINVAL;
return pdata->stui_tsp_enter();
}
EXPORT_SYMBOL(stui_tsp_enter);
int stui_tsp_exit(void)
{
struct sec_ts_plat_data *pdata = NULL;
if (ptsp == NULL)
return -EINVAL;
pdata = ptsp->platform_data;
if (pdata == NULL)
return -EINVAL;
return pdata->stui_tsp_exit();
}
EXPORT_SYMBOL(stui_tsp_exit);
int stui_tsp_type(void)
{
struct sec_ts_plat_data *pdata = NULL;
if (ptsp == NULL)
return -EINVAL;
pdata = ptsp->platform_data;
if (pdata == NULL)
return -EINVAL;
return pdata->stui_tsp_type();
}
EXPORT_SYMBOL(stui_tsp_type);
int sec_input_enable_device(struct input_dev *dev)
{
int retval;
retval = mutex_lock_interruptible(&dev->mutex);
if (retval)
return retval;
if (dev->users && dev->open)
retval = dev->open(dev);
mutex_unlock(&dev->mutex);
return retval;
}
EXPORT_SYMBOL(sec_input_enable_device);
int sec_input_disable_device(struct input_dev *dev)
{
int retval;
retval = mutex_lock_interruptible(&dev->mutex);
if (retval)
return retval;
if (dev->users && dev->close)
dev->close(dev);
mutex_unlock(&dev->mutex);
return 0;
}
EXPORT_SYMBOL(sec_input_disable_device);
__visible_for_testing ssize_t sec_input_enabled_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct input_dev *input_dev = to_input_dev(dev);
struct sec_ts_plat_data *pdata = input_dev->dev.parent->platform_data;
return scnprintf(buf, PAGE_SIZE, "%d\n", pdata->enabled);
}
__visible_for_testing ssize_t sec_input_enabled_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
int ret;
bool enable;
struct input_dev *input_dev = to_input_dev(dev);
struct sec_ts_plat_data *pdata = input_dev->dev.parent->platform_data;
ret = strtobool(buf, &enable);
if (ret)
return ret;
if (pdata->enabled == enable) {
pr_info("%s %s: device already %s\n", SECLOG, __func__,
enable ? "enabled" : "disabled");
goto out;
}
if (enable)
ret = sec_input_enable_device(input_dev);
else
ret = sec_input_disable_device(input_dev);
if (ret)
return ret;
out:
return size;
}
static DEVICE_ATTR(enabled, 0664, sec_input_enabled_show, sec_input_enabled_store);
static struct attribute *sec_input_attrs[] = {
&dev_attr_enabled.attr,
NULL
};
static const struct attribute_group sec_input_attr_group = {
.attrs = sec_input_attrs,
};
int sec_input_sysfs_create(struct kobject *kobj)
{
struct kernfs_node *enabled_sd = NULL;
int retval = 0;
enabled_sd = sysfs_get_dirent(kobj->sd, "enabled");
if (IS_ERR_OR_NULL(enabled_sd)) {
pr_info("%s %s: make 'enabled' node\n", SECLOG, __func__);
retval = sysfs_create_group(kobj, &sec_input_attr_group);
if (retval < 0) {
pr_err("%s %s: Failed to create sysfs attributes %d\n", SECLOG, __func__, retval);
}
} else {
pr_info("%s %s: 'enabled' is already exist\n", SECLOG, __func__);
}
return retval;
}
EXPORT_SYMBOL(sec_input_sysfs_create);
void sec_input_sysfs_remove(struct kobject *kobj)
{
sysfs_remove_group(kobj, &sec_input_attr_group);
}
EXPORT_SYMBOL(sec_input_sysfs_remove);
MODULE_DESCRIPTION("Samsung common functions");
MODULE_LICENSE("GPL");