kernel_samsung_a34x-permissive/drivers/input/sec_input/sec_virtual_tsp.c

443 lines
14 KiB
C
Raw Normal View History

#include "sec_cmd.h"
#include "sec_input.h"
#include "sec_tsp_log.h"
#if IS_ENABLED(CONFIG_HALL_NOTIFIER)
#include <linux/hall/hall_ic_notifier.h>
static struct notifier_block hall_ic_nb;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_SENSOR_FOLD)
#include <linux/sensor/sensors_core.h>
static struct notifier_block hall_ic_nb_ssh;
#endif
static int flip_status;
static struct mutex switching_mutex;
static int fac_flip_status;
static struct sec_cmd_data *dual_sec;
#if IS_ENABLED(CONFIG_TOUCHSCREEN_DUMP_MODE)
#include "sec_tsp_dumpkey.h"
extern struct tsp_dump_callbacks dump_callbacks;
struct tsp_dump_callbacks *tsp_callbacks;
EXPORT_SYMBOL(tsp_callbacks);
static struct tsp_dump_callbacks callbacks[DEV_COUNT];
static void sec_virtual_tsp_dump(struct device *dev)
{
input_info(true, dual_sec->fac_dev, "%s: flip_status %s[%d]\n", __func__,
flip_status ? "close:sub_tsp" : "open:main_tsp", flip_status);
if (flip_status == FLIP_STATUS_MAIN) {
if (callbacks[FLIP_STATUS_MAIN].inform_dump)
callbacks[FLIP_STATUS_MAIN].inform_dump(dual_sec->fac_dev);
} else if (flip_status == FLIP_STATUS_SUB) {
if (callbacks[FLIP_STATUS_SUB].inform_dump)
callbacks[FLIP_STATUS_SUB].inform_dump(dual_sec->fac_dev);
}
}
#endif
static void sec_virtual_tsp_dual_cmd(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
sec_cmd_virtual_tsp_write_cmd(sec, true, true);
}
#if !IS_ENABLED(CONFIG_TOUCHSCREEN_STM_SUB)
static void sec_virtual_tsp_main_cmd(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
bool main = true;
bool sub = false;
mutex_lock(&switching_mutex);
if (!((fac_flip_status == FLIP_STATUS_DEFAULT && flip_status == FLIP_STATUS_MAIN)
|| fac_flip_status == FLIP_STATUS_MAIN)) {
input_err(true, sec->fac_dev, "%s: flip is sub, skip[%d,%d]\n",
__func__, fac_flip_status, flip_status);
main = false;
}
mutex_unlock(&switching_mutex);
sec_cmd_virtual_tsp_write_cmd(sec, main, sub);
}
#endif
#if IS_ENABLED(CONFIG_TOUCHSCREEN_ZINITIX_ZTW522)
static void sec_virtual_tsp_sub_cmd(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
bool main = false;
bool sub = true;
mutex_lock(&switching_mutex);
if (!((fac_flip_status == FLIP_STATUS_DEFAULT && flip_status == FLIP_STATUS_SUB)
|| fac_flip_status == FLIP_STATUS_SUB)) {
input_err(true, sec->fac_dev, "%s: flip is main, skip[%d,%d]\n",
__func__, fac_flip_status, flip_status);
sub = false;
}
mutex_unlock(&switching_mutex);
sec_cmd_virtual_tsp_write_cmd(sec, main, sub);
}
#endif
static void sec_virtual_tsp_switch_cmd(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
bool main = false;
bool sub = false;
mutex_lock(&switching_mutex);
if (fac_flip_status == FLIP_STATUS_DEFAULT) {
/* Using hall_ic */
if (flip_status == FLIP_STATUS_MAIN) {
main = true;
} else if (flip_status == FLIP_STATUS_SUB) {
sub = true;
}
} else if (fac_flip_status == FLIP_STATUS_MAIN) {
main = true;
} else if (fac_flip_status == FLIP_STATUS_SUB) {
sub = true;
}
input_dbg(true, sec->fac_dev, "%s: %d,%d\n", __func__, fac_flip_status, flip_status);
mutex_unlock(&switching_mutex);
sec_cmd_virtual_tsp_write_cmd(sec, main, sub);
}
static void sec_virtual_tsp_factory_cmd_result_all(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
bool main = false;
bool sub = false;
mutex_lock(&switching_mutex);
if (fac_flip_status == FLIP_STATUS_DEFAULT) {
/* Using hall_ic */
if (flip_status == FLIP_STATUS_MAIN) {
main = true;
} else if (flip_status == FLIP_STATUS_SUB) {
sub = true;
}
} else if (fac_flip_status == FLIP_STATUS_MAIN) {
main = true;
} else if (fac_flip_status == FLIP_STATUS_SUB) {
sub = true;
}
input_dbg(true, sec->fac_dev, "%s: %d,%d\n", __func__, fac_flip_status, flip_status);
mutex_unlock(&switching_mutex);
sec_cmd_virtual_tsp_write_cmd_factory_all(sec, main, sub);
}
static void set_factory_panel(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
char buff[16] = { 0 };
sec_cmd_set_default_result(sec);
if (sec->cmd_param[0] < FLIP_STATUS_DEFAULT || sec->cmd_param[0] > FLIP_STATUS_SUB) {
snprintf(buff, sizeof(buff), "%s", "NG");
sec->cmd_state = SEC_CMD_STATUS_FAIL;
goto err;
}
mutex_lock(&switching_mutex);
fac_flip_status = sec->cmd_param[0];
input_err(true, sec->fac_dev, "%s: %d\n", __func__, fac_flip_status);
mutex_unlock(&switching_mutex);
snprintf(buff, sizeof(buff), "%s", "OK");
sec->cmd_state = SEC_CMD_STATUS_OK;
err:
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
}
static void dev_count(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
char buff[16] = { 0 };
sec_cmd_set_default_result(sec);
snprintf(buff, sizeof(buff), "%s,%d", "OK", DEV_COUNT);
sec->cmd_state = SEC_CMD_STATUS_OK;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
}
#if IS_ENABLED(CONFIG_HALL_NOTIFIER)
static int sec_virtual_tsp_hall_ic_notify(struct notifier_block *nb,
unsigned long flip_cover, void *v)
{
struct hall_notifier_context *hall_notifier;
hall_notifier = v;
if (strncmp(hall_notifier->name, "flip", 4))
return 0;
input_info(true, dual_sec->fac_dev, "%s: %s\n", __func__,
flip_cover ? "close" : "open");
mutex_lock(&switching_mutex);
flip_status = flip_cover;
mutex_unlock(&switching_mutex);
return 0;
}
#endif
#if IS_ENABLED(CONFIG_SUPPORT_SENSOR_FOLD)
static int sec_virtual_tsp_hall_ic_ssh_notify(struct notifier_block *nb,
unsigned long flip_cover, void *v)
{
input_info(true, dual_sec->fac_dev, "%s: %s\n", __func__,
flip_cover ? "close" : "open");
mutex_lock(&switching_mutex);
flip_status = flip_cover;
mutex_unlock(&switching_mutex);
return 0;
}
#endif
static struct sec_cmd tsp_commands[] = {
{SEC_CMD_H("glove_mode", sec_virtual_tsp_dual_cmd),},
{SEC_CMD_H("set_wirelesscharger_mode", sec_virtual_tsp_dual_cmd),},
{SEC_CMD_H("spay_enable", sec_virtual_tsp_dual_cmd),},
{SEC_CMD_H("aot_enable", sec_virtual_tsp_dual_cmd),},
{SEC_CMD_H("aod_enable", sec_virtual_tsp_dual_cmd),},
{SEC_CMD_H("fod_enable", sec_virtual_tsp_dual_cmd),},
{SEC_CMD("fod_lp_mode", sec_virtual_tsp_dual_cmd),},
{SEC_CMD_H("external_noise_mode", sec_virtual_tsp_dual_cmd),},
{SEC_CMD_H("brush_enable", sec_virtual_tsp_dual_cmd),},
{SEC_CMD_H("singletap_enable", sec_virtual_tsp_dual_cmd),},
{SEC_CMD_H("set_touchable_area", sec_virtual_tsp_dual_cmd),},
{SEC_CMD("clear_cover_mode", sec_virtual_tsp_dual_cmd),},
{SEC_CMD("ear_detect_enable", sec_virtual_tsp_dual_cmd),},
{SEC_CMD("pocket_mode_enable", sec_virtual_tsp_dual_cmd),},
/* SemInputDeviceManagerService */
{SEC_CMD("set_game_mode", sec_virtual_tsp_dual_cmd),},
{SEC_CMD("set_sip_mode", sec_virtual_tsp_dual_cmd),},
{SEC_CMD("set_note_mode", sec_virtual_tsp_dual_cmd),},
{SEC_CMD("set_scan_rate", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("refresh_rate_mode", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("prox_lp_scan_mode", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("set_grip_data", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("set_temperature", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("set_aod_rect", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("fod_icon_visible", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("set_fod_rect", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("fp_int_control", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("sync_changed", sec_virtual_tsp_switch_cmd),},
/* run_xxx_read_all common */
{SEC_CMD("run_cs_raw_read_all", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("run_cs_delta_read_all", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("run_rawcap_read_all", sec_virtual_tsp_switch_cmd),},
/* only main */
/* only sub */
#if IS_ENABLED(CONFIG_TOUCHSCREEN_STM_SUB)
/* run_xxx_read_all stm */
{SEC_CMD("run_ix_data_read_all", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("run_self_raw_read_all", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("run_cx_data_read_all", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("run_cx_gap_data_rx_all", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("run_cx_gap_data_tx_all", sec_virtual_tsp_switch_cmd),},
{SEC_CMD("run_factory_miscalibration_read_all", sec_virtual_tsp_switch_cmd),},
#else
/* run_xxx_read_all main(stm) */
{SEC_CMD("run_ix_data_read_all", sec_virtual_tsp_main_cmd),},
{SEC_CMD("run_self_raw_read_all", sec_virtual_tsp_main_cmd),},
{SEC_CMD("run_cx_data_read_all", sec_virtual_tsp_main_cmd),},
{SEC_CMD("run_cx_gap_data_rx_all", sec_virtual_tsp_main_cmd),},
{SEC_CMD("run_cx_gap_data_tx_all", sec_virtual_tsp_main_cmd),},
{SEC_CMD("run_factory_miscalibration_read_all", sec_virtual_tsp_main_cmd),},
#endif
#if IS_ENABLED(CONFIG_TOUCHSCREEN_ZINITIX_ZTW522)
/* run_xxx_read_all sub(zinitix) */
{SEC_CMD("run_dnd_read_all", sec_virtual_tsp_sub_cmd),},
{SEC_CMD("run_dnd_v_gap_read_all", sec_virtual_tsp_sub_cmd),},
{SEC_CMD("run_dnd_h_gap_read_all", sec_virtual_tsp_sub_cmd),},
{SEC_CMD("run_selfdnd_read_all", sec_virtual_tsp_sub_cmd),},
{SEC_CMD("run_selfdnd_h_gap_read_all", sec_virtual_tsp_sub_cmd),},
{SEC_CMD("run_jitter_read_all", sec_virtual_tsp_sub_cmd),},
{SEC_CMD("run_self_saturation_read_all", sec_virtual_tsp_sub_cmd),},
/* sub touch test (fold open) */
{SEC_CMD("dead_zone_enable", sec_virtual_tsp_dual_cmd),},
#endif
{SEC_CMD("two_finger_doubletap_enable", sec_virtual_tsp_dual_cmd),},
{SEC_CMD("factory_cmd_result_all", sec_virtual_tsp_factory_cmd_result_all),},
{SEC_CMD("factory_cmd_result_all_imagetest", sec_virtual_tsp_factory_cmd_result_all),},
{SEC_CMD_H("set_factory_panel", set_factory_panel),},
{SEC_CMD("dev_count", dev_count),},
{SEC_CMD("not_support_cmd", sec_virtual_tsp_switch_cmd),},
};
static ssize_t sec_virtual_tsp_support_feature_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
char buffer[16];
int ret;
memset(buffer, 0x00, sizeof(buffer));
ret = sec_cmd_virtual_tsp_read_sysfs(dual_sec, PATH_MAIN_SEC_SYSFS_SUPPORT_FEATURE, buffer, sizeof(buffer));
if (ret < 0)
return snprintf(buf, SEC_CMD_BUF_SIZE, "NG\n");
return snprintf(buf, SEC_CMD_BUF_SIZE, "%s", buffer);
}
static ssize_t sec_virtual_tsp_prox_power_off_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
char buffer[16];
int ret;
memset(buffer, 0x00, sizeof(buffer));
if (flip_status)
ret = sec_cmd_virtual_tsp_read_sysfs(dual_sec, PATH_SUB_SEC_SYSFS_PROX_POWER_OFF, buffer, sizeof(buffer));
else
ret = sec_cmd_virtual_tsp_read_sysfs(dual_sec, PATH_MAIN_SEC_SYSFS_PROX_POWER_OFF, buffer, sizeof(buffer));
input_info(false, dual_sec->fac_dev, "%s: %s, ret:%d\n", __func__,
flip_status ? "close" : "open", ret);
if (ret < 0)
return snprintf(buf, SEC_CMD_BUF_SIZE, "NG\n");
return snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buffer);
}
static ssize_t sec_virtual_tsp_prox_power_off_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int ret;
if (flip_status)
ret = sec_cmd_virtual_tsp_write_sysfs(dual_sec, PATH_SUB_SEC_SYSFS_PROX_POWER_OFF, buf);
else
ret = sec_cmd_virtual_tsp_write_sysfs(dual_sec, PATH_MAIN_SEC_SYSFS_PROX_POWER_OFF, buf);
input_info(false, dual_sec->fac_dev, "%s: %s, ret:%d\n", __func__,
flip_status ? "close" : "open", ret);
return count;
}
static ssize_t dualscreen_policy_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int ret, value;
ret = kstrtoint(buf, 10, &value);
if (ret != 0)
return ret;
if (value <= FLIP_STATUS_DEFAULT || value > FLIP_STATUS_SUB) {
input_info(false, dual_sec->fac_dev, "%s: value=%d %s\n", __func__, value,
flip_status ? "close" : "open");
return count;
}
mutex_lock(&switching_mutex);
flip_status = value;
mutex_unlock(&switching_mutex);
if (value == FLIP_STATUS_MAIN) {
sec_cmd_virtual_tsp_write_sysfs(dual_sec, PATH_MAIN_SEC_SYSFS_DUALSCREEN_POLICY, buf);
sec_cmd_virtual_tsp_write_sysfs(dual_sec, PATH_SUB_SEC_SYSFS_DUALSCREEN_POLICY, buf);
}
input_info(true, dual_sec->fac_dev, "%s: value=%d %s\n", __func__, value,
flip_status ? "close" : "open");
return count;
}
static DEVICE_ATTR(dualscreen_policy, 0644, NULL, dualscreen_policy_store);
static DEVICE_ATTR(support_feature, 0444, sec_virtual_tsp_support_feature_show, NULL);
static DEVICE_ATTR(prox_power_off, 0644, sec_virtual_tsp_prox_power_off_show, sec_virtual_tsp_prox_power_off_store);
static struct attribute *sec_virtual_tsp_attrs[] = {
&dev_attr_support_feature.attr,
&dev_attr_prox_power_off.attr,
&dev_attr_dualscreen_policy.attr,
NULL,
};
static struct attribute_group sec_virtual_tsp_attrs_group = {
.attrs = sec_virtual_tsp_attrs,
};
static int __init __init_sec_virtual_tsp(void)
{
int ret;
dual_sec = kzalloc(sizeof(struct sec_cmd_data), GFP_KERNEL);
if (!dual_sec) {
input_err(true, NULL, "%s: failed to alloc sec_cmd_data for dual tsp\n", __func__);
return -ENOMEM;
}
sec_cmd_init(dual_sec, tsp_commands,
ARRAY_SIZE(tsp_commands), SEC_CLASS_DEVT_TSP);
input_info(true, dual_sec->fac_dev, "%s\n", __func__);
mutex_init(&switching_mutex);
mutex_lock(&switching_mutex);
fac_flip_status = FLIP_STATUS_DEFAULT;
flip_status = FLIP_STATUS_MAIN;
mutex_unlock(&switching_mutex);
#if IS_ENABLED(CONFIG_HALL_NOTIFIER)
hall_ic_nb.priority = 1;
hall_ic_nb.notifier_call = sec_virtual_tsp_hall_ic_notify;
hall_notifier_register(&hall_ic_nb);
input_info(true, dual_sec->fac_dev, "%s: hall ic register\n", __func__);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_SENSOR_FOLD)
hall_ic_nb_ssh.priority = 1;
hall_ic_nb_ssh.notifier_call = sec_virtual_tsp_hall_ic_ssh_notify;
sensorfold_notifier_register(&hall_ic_nb_ssh);
input_info(true, dual_sec->fac_dev, "%s: hall ic(ssh) register\n", __func__);
#endif
#if IS_ENABLED(CONFIG_TOUCHSCREEN_DUMP_MODE)
tsp_callbacks = callbacks;
dump_callbacks.inform_dump = sec_virtual_tsp_dump;
#endif
ret = sysfs_create_group(&dual_sec->fac_dev->kobj, &sec_virtual_tsp_attrs_group);
if (ret < 0) {
pr_err("%s %s: failed to create sysfs group\n", SECLOG, __func__);
return -ENODEV;
}
return 0;
}
module_init(__init_sec_virtual_tsp);
MODULE_DESCRIPTION("Samsung virtual tsp functions");
MODULE_LICENSE("GPL");