dlkm: bo: Bringup touch driver for novatek

- Support for kernel 5.4.0.
- Support for new panel notifier api.
- Sync below changes from bq-sm2019
(CR) Minsk: Pen status notification to touch for novatek.
(CR) dlkm: add palm rejection for nova_0flash_mmi.
(CR) dlkm: add interface for plam rejection.
(CR) Minsk: Improve palm event handler

Change-Id: Ia8bec432561e3d717baab5e54e3ffd43736e045c
Signed-off-by: wengjun1 <wengjun1@motorola.com>
Reviewed-on: https://gerrit.mot.com/1760990
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Jianqiu Huang <huangjq9@motorola.com>
Reviewed-by: Yeqing Wang <wangyq13@motorola.com>
Reviewed-by: Huosheng Liao <liaohs@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
wengjun1 2020-09-27 12:46:35 +08:00 • committed by Jun Weng
commit 5ff1939898
7 changed files with 605 additions and 87 deletions

View file

@ -15,6 +15,17 @@ ifneq ($(BOARD_USES_PANEL_NOTIFICATIONS),)
KERNEL_CFLAGS += CONFIG_INPUT_NOVA_PANEL_NOTIFICATIONS=y
endif
ifneq ($(BOARD_USES_PEN_NOTIFIER),)
KERNEL_CFLAGS += CONFIG_INPUT_NOVA_0FLASH_MMI_PEN_NOTIFIER=y
endif
ifneq ($(BOARD_USES_STYLUS_PALM),)
KERNEL_CFLAGS += CONFIG_INPUT_NOVA_0FLASH_MMI_STYLUS_PALM=y
endif
ifneq ($(BOARD_USES_STYLUS_PALM_RANGE),)
KERNEL_CFLAGS += CONFIG_INPUT_NOVA_0FLASH_MMI_STYLUS_PALM_RANGE=y
endif
include $(CLEAR_VARS)
LOCAL_MODULE := nova_0flash_mmi.ko
LOCAL_MODULE_TAGS := optional

View file

@ -1,7 +1,7 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include \
-I$(TOP)/motorola/kernel/modules/drivers/input/touchscreen/nova_0flash_mmi
EXTRA_CFLAGS += -I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include \
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/drivers/input/touchscreen/nova_0flash_mmi
ifeq ($(filter m y, $(CONFIG_TOUCHSCREEN_NT36xxx_HOSTDL_SPI)),)
obj-m := nova_0flash_mmi.o
@ -13,6 +13,16 @@ ifneq ($(filter m y,$(CONFIG_INPUT_NOVA_PANEL_NOTIFICATIONS)),)
EXTRA_CFLAGS += -DNVT_CONFIG_PANEL_NOTIFICATIONS
endif
ifneq ($(filter m y,$(CONFIG_INPUT_NOVA_0FLASH_MMI_STYLUS_PALM)),)
EXTRA_CFLAGS += -DPALM_GESTURE
endif
ifneq ($(filter m y,$(CONFIG_INPUT_NOVA_0FLASH_MMI_STYLUS_PALM_RANGE)),)
EXTRA_CFLAGS += -DPALM_GESTURE_RANGE
endif
ifneq ($(filter m y,$(CONFIG_INPUT_NOVA_0FLASH_MMI_PEN_NOTIFIER)),)
KBUILD_EXTRA_SYMBOLS += $(CURDIR)/$(KBUILD_EXTMOD)/../../../misc/pen/Module.symvers
EXTRA_CFLAGS += -DNOVATECH_PEN_NOTIFIER
endif
nova_0flash_mmi-objs += nt36xxx.o
nova_0flash_mmi-objs += nt36xxx_ext_proc.o
nova_0flash_mmi-objs += nt36xxx_fw_update.o

View file

@ -27,6 +27,14 @@
#include <linux/power_supply.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
#if defined(CONFIG_DRM)
#include <linux/msm_drm_notify.h>
#include <linux/notifier.h>
#include <linux/fb.h>
#include <drm/drm_panel.h>
#endif
#else //vension code < 5.4.0
#if defined(CONFIG_FB)
#ifdef CONFIG_DRM_MSM
#include <linux/msm_drm_notify.h>
@ -36,7 +44,7 @@
#elif defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#endif
#endif //end version code >= 5.4.0
#include "nt36xxx.h"
#if NVT_TOUCH_ESD_PROTECT
#include <linux/jiffies.h>
@ -103,11 +111,26 @@ extern void nvt_mp_proc_deinit(void);
struct nvt_ts_data *ts;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
#if defined(CONFIG_DRM)
static struct drm_panel *active_panel;
#endif
#endif
#if BOOT_UPDATE_FIRMWARE
static struct workqueue_struct *nvt_fwu_wq;
extern void Boot_Update_Firmware(struct work_struct *work);
#endif
#ifdef NOVATECH_PEN_NOTIFIER
int nvt_mcu_pen_detect_set(uint8_t pen_detect);
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
#if defined(CONFIG_DRM)
static int nvt_drm_notifier_callback(struct notifier_block *self, unsigned long event, void *data);
#endif
#else //vension code < 5.4.0
#if defined(CONFIG_FB)
#ifdef _MSM_DRM_NOTIFY_H_
static int nvt_drm_notifier_callback(struct notifier_block *self, unsigned long event, void *data);
@ -122,6 +145,7 @@ static void nvt_ts_late_resume(struct early_suspend *h);
#ifdef NVT_CONFIG_PANEL_NOTIFICATIONS
static int nvt_panel_notifier_callback(struct notifier_block *self, unsigned long event, void *data);
#endif
#endif //end version code >= 5.4.0
uint32_t ENG_RST_ADDR = 0x7FFF80;
uint32_t SWRST_N8_ADDR = 0; //read from dtsi
@ -131,6 +155,9 @@ static int nvt_set_charger(uint8_t charger_on_off);
static void nvt_charger_notify_work(struct work_struct *work);
static int usb_detect_flag = 0;
char *nvt_boot_firmware_name = NULL;
char *nvt_mp_firmware_name = NULL;
#if TOUCH_KEY_NUM > 0
const uint16_t touch_key_array[TOUCH_KEY_NUM] = {
KEY_BACK,
@ -1105,6 +1132,34 @@ static int nvt_get_dt_def_coords(struct device *dev, char *name)
return rc;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
#if defined(CONFIG_DRM)
static int nova_check_dt(struct device_node *np)
{
int i;
int count;
struct device_node *node;
struct drm_panel *panel;
count = of_count_phandle_with_args(np, "panel", NULL);
if (count <= 0)
return 0;
for (i = 0; i < count; i++) {
node = of_parse_phandle(np, "panel", i);
panel = of_drm_find_panel(node);
of_node_put(node);
if (!IS_ERR(panel)) {
active_panel = panel;
return 0;
}
}
return -ENODEV;
}
#endif
#endif
static int32_t nvt_parse_dt(struct device *dev)
{
struct device_node *np = dev->of_node;
@ -1125,6 +1180,29 @@ static int32_t nvt_parse_dt(struct device *dev)
NVT_LOG("SWRST_N8_ADDR=0x%06X\n", SWRST_N8_ADDR);
}
ret = of_property_read_string(np, "novatek,panel-supplier",
&ts->panel_supplier);
if (ret < 0) {
NVT_LOG("Unable to read panel supplier\n");
} else {
NVT_LOG("panel supplier is %s", (char *)ts->panel_supplier);
nvt_boot_firmware_name = kzalloc(NVT_FILE_NAME_LENGTH, GFP_KERNEL);
if (!nvt_boot_firmware_name) {
NVT_LOG("%s: alloc nvt_boot_firmware_name failed\n", __func__);
goto nvt_boot_firmware_name_alloc_failed;
}
nvt_mp_firmware_name = kzalloc(NVT_FILE_NAME_LENGTH, GFP_KERNEL);
if (!nvt_boot_firmware_name) {
NVT_LOG("%s: alloc nvt_boot_firmware_name failed\n", __func__);
goto nvt_mp_firmware_name_alloc_failed;
}
snprintf(nvt_boot_firmware_name, NVT_FILE_NAME_LENGTH, "%s_novatek_ts_fw.bin",
ts->panel_supplier);
snprintf(nvt_mp_firmware_name, NVT_FILE_NAME_LENGTH, "%s_novatek_ts_mp.bin",
ts->panel_supplier);
}
NVT_LOG("boot firmware %s, mp firmware %s", nvt_boot_firmware_name, nvt_mp_firmware_name);
ret = nvt_get_dt_def_coords(dev, "novatek,def-max-resolution");
if (ret) {
ts->abs_x_max = TOUCH_DEFAULT_MAX_WIDTH;
@ -1169,6 +1247,13 @@ static int32_t nvt_parse_dt(struct device *dev)
} else {
ts->report_gesture_key = 0;
}
return ret;
nvt_mp_firmware_name_alloc_failed:
kfree(nvt_boot_firmware_name);
nvt_boot_firmware_name = NULL;
nvt_boot_firmware_name_alloc_failed:
return ret;
}
#else
@ -1277,7 +1362,10 @@ static void nvt_esd_check_func(struct work_struct *work)
mutex_lock(&ts->lock);
NVT_ERR("do ESD recovery, timer = %d, retry = %d\n", timer, esd_retry);
/* do esd recovery, reload fw */
nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
if(nvt_boot_firmware_name)
nvt_update_firmware(nvt_boot_firmware_name);
else
nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
mutex_unlock(&ts->lock);
/* update interrupt timer */
irq_timer = jiffies;
@ -1348,7 +1436,17 @@ static int32_t nvt_ts_point_data_checksum(uint8_t *buf, uint8_t length)
}
#endif /* POINT_DATA_CHECKSUM */
#define FINGER_ENTER 0x01
#define FINGER_MOVING 0x02
#ifdef PALM_GESTURE
#define PALM_TOUCH 0x05
#define POINT_DATA_LEN 120
#define MINOR_DATA_OFFSET 70
#define ORIENT_DATA_OFFSET 110
#else
#define POINT_DATA_LEN 65
#endif
/*******************************************************
Description:
Novatek touchscreen work function.
@ -1363,7 +1461,11 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data)
uint32_t position = 0;
uint32_t input_x = 0;
uint32_t input_y = 0;
uint32_t input_w = 0;
uint32_t input_major = 0;
#ifdef PALM_GESTURE
uint32_t input_minor = 0;
int32_t input_orient = 0;
#endif
uint32_t input_p = 0;
uint8_t input_id = 0;
#if MT_PROTOCOL_B
@ -1396,10 +1498,13 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data)
#if NVT_TOUCH_WDT_RECOVERY
/* ESD protect by WDT */
if (nvt_wdt_fw_recovery(point_data)) {
NVT_ERR("Recover for fw reset, %02X\n", point_data[1]);
nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
goto XFER_ERROR;
if (nvt_wdt_fw_recovery(point_data)) {
NVT_ERR("Recover for fw reset, %02X\n", point_data[1]);
if(nvt_boot_firmware_name)
nvt_update_firmware(nvt_boot_firmware_name);
else
nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
goto XFER_ERROR;
}
#endif /* #if NVT_TOUCH_WDT_RECOVERY */
@ -1436,8 +1541,13 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data)
input_id = (uint8_t)(point_data[position + 0] >> 3);
if ((input_id == 0) || (input_id > ts->max_touch_num))
continue;
if (((point_data[position] & 0x07) == 0x01) || ((point_data[position] & 0x07) == 0x02)) { //finger down (enter & moving)
#ifdef PALM_GESTURE
if (((point_data[position] & 0x07) == FINGER_ENTER)
|| ((point_data[position] & 0x07) == FINGER_MOVING)
|| ((point_data[position] & 0x07) == PALM_TOUCH)) { //finger down (enter & moving) or palm
#else
if (((point_data[position] & 0x07) == FINGER_ENTER) || ((point_data[position] & 0x07) == FINGER_MOVING)) { //finger down (enter & moving)
#endif
#if NVT_TOUCH_ESD_PROTECT
/* update interrupt timer */
irq_timer = jiffies;
@ -1448,15 +1558,43 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data)
continue;
if ((input_x > ts->abs_x_max) || (input_y > ts->abs_y_max))
continue;
input_w = (uint32_t)(point_data[position + 4]);
if (input_w == 0)
input_w = 1;
if (i < 2) {
input_p = (uint32_t)(point_data[position + 5]) + (uint32_t)(point_data[i + 63] << 8);
if (input_p > TOUCH_FORCE_NUM)
input_p = TOUCH_FORCE_NUM;
} else {
#ifdef PALM_GESTURE_RANGE
if((point_data[position] & 0x07) == PALM_TOUCH) { //palm
input_minor = (uint32_t)(point_data[1 + MINOR_DATA_OFFSET + i]);
if (input_minor == 0)
input_minor = 1;
input_orient = (int8_t)(point_data[1 + ORIENT_DATA_OFFSET + i]);
}
#endif
input_major = (uint32_t)(point_data[position + 4]);
if (input_major == 0)
input_major = 1;
#ifdef PALM_GESTURE
if ((point_data[position] & 0x07) == PALM_TOUCH) { //palm
input_p = (uint32_t)(point_data[position + 5]);
if(input_p == 255)
input_p = PALM_HANG;
else if (input_p == 254)
input_p = PALM_HAND_HOLDE;
#ifdef PALM_GESTURE_RANGE
//dimension-to-pixel
input_minor = input_minor * TOUCH_DEFAULT_MAX_WIDTH / PANEL_REAL_WIDTH * 100;
input_major = input_major * TOUCH_DEFAULT_MAX_HEIGHT / PANEL_REAL_HEIGHT * 100;
#endif
} else
#endif
{
if (i < 2) {
input_p = (uint32_t)(point_data[position + 5]) + (uint32_t)(point_data[i + 63] << 8);
if (input_p > TOUCH_FORCE_NUM)
input_p = TOUCH_FORCE_NUM;
} else {
input_p = (uint32_t)(point_data[position + 5]);
}
}
if (input_p == 0)
input_p = 1;
@ -1470,11 +1608,28 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data)
input_report_key(ts->input_dev, BTN_TOUCH, 1);
#endif /* MT_PROTOCOL_B */
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE, input_p);
#ifdef PALM_GESTURE
if((point_data[position] & 0x07) == PALM_TOUCH) { //palm
dev_dbg(&ts->client->dev, "id=%d, pressure=%d, (%d,%d), major=%d, minor=%d, orient=%d\n",
input_id, input_p, input_x, input_y, input_major, input_minor, input_orient);
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_major);
#ifdef PALM_GESTURE_RANGE
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, input_minor);
input_report_abs(ts->input_dev, ABS_MT_ORIENTATION, input_orient);
#endif
input_report_abs(ts->input_dev, ABS_MT_PRESSURE, input_p);
} else
#endif
{
dev_dbg(&ts->client->dev, "id=%d, pressure=%d, (%d,%d), major=%d\n",
input_id, input_p, input_x, input_y, input_major);
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_major);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE, input_p);
}
#if MT_PROTOCOL_B
#else /* MT_PROTOCOL_B */
input_mt_sync(ts->input_dev);
@ -1488,6 +1643,10 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data)
for (i = 0; i < ts->max_touch_num; i++) {
if (press_id[i] != 1) {
input_mt_slot(ts->input_dev, i);
#ifdef PALM_GESTURE_RANGE
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, 0);
input_report_abs(ts->input_dev, ABS_MT_ORIENTATION, 0);
#endif
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);
@ -1688,6 +1847,14 @@ int nvt_sensor_remove(struct nvt_ts_data *data)
data->sensor_pdata = NULL;
data->wakeable = false;
data->should_enable_gesture = false;
if (!nvt_boot_firmware_name) {
kfree(nvt_boot_firmware_name);
nvt_boot_firmware_name = NULL;
}
if (!nvt_mp_firmware_name) {
kfree(nvt_mp_firmware_name);
nvt_mp_firmware_name = NULL;
}
return 0;
}
#endif
@ -1728,10 +1895,55 @@ static ssize_t ic_ver_show(struct device *dev,
"Config ID: ", ts->nvt_pid ? ts->nvt_pid : ts->config_id);
}
#ifdef PALM_GESTURE
static ssize_t nvt_palm_settings_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%d", ts->palm_enabled);
}
static ssize_t nvt_palm_settings_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int value;
int err = 0;
if (count > 2)
return -EINVAL;
if (sscanf(buf, "%d", &value) != 1)
return -EINVAL;
err = count;
switch (value) {
case 0:
ts->palm_enabled = false;
break;
case 1:
ts->palm_enabled = true;
break;
default:
err = -EINVAL;
ts->palm_enabled = false;
NVT_ERR("Invalid Value! %d\n", value);
break;
}
nvt_palm_set(ts->palm_enabled);
return err;
}
#endif
static struct device_attribute touchscreen_attributes[] = {
__ATTR_RO(path),
__ATTR_RO(vendor),
__ATTR_RO(ic_ver),
#ifdef PALM_GESTURE
__ATTR(palm_settings, S_IRUGO | S_IWUSR | S_IWGRP, nvt_palm_settings_show, nvt_palm_settings_store),
#endif
__ATTR_NULL
};
@ -1771,7 +1983,11 @@ int32_t nvt_fw_class_init(bool create)
ts_class_dev = device_create(touchscreen_class, NULL,
MKDEV(INPUT_MAJOR, minor),
#ifdef PALM_GESTURE
ts, NVT_PRIMARY_NAME);
#else
ts, NVT_SPI_NAME);
#endif
if (IS_ERR(ts_class_dev)) {
error = PTR_ERR(ts_class_dev);
ts_class_dev = NULL;
@ -1787,7 +2003,11 @@ int32_t nvt_fw_class_init(bool create)
if (error)
goto device_destroy;
else
#ifdef PALM_GESTURE
NVT_LOG("create /sys/class/touchscreen/%s Succeeded!\n", NVT_PRIMARY_NAME);
#else
NVT_LOG("create /sys/class/touchscreen/%s Succeeded!\n", NVT_SPI_NAME);
#endif
} else {
if (!touchscreen_class || !ts_class_dev)
return -ENODEV;
@ -1812,7 +2032,30 @@ device_destroy:
return -ENODEV;
}
#ifdef NOVATECH_PEN_NOTIFIER
static int pen_notifier_callback(struct notifier_block *self,
unsigned long event, void *data)
{
int ret = 0;
NVT_LOG("Received event(%lu) for pen detection\n", event);
if (event == PEN_DETECTION_INSERT)
ts->nvt_pen_detect_flag = PEN_DETECTION_INSERT;
else if (event == PEN_DETECTION_PULL)
ts->nvt_pen_detect_flag = PEN_DETECTION_PULL;
if (!bTouchIsAwake || !ts->fw_ready_flag) {
NVT_LOG("touch in suspend or no firmware, so store.");
} else {
ret = nvt_mcu_pen_detect_set(ts->nvt_pen_detect_flag);
if (ret < 0) {
NVT_ERR("write pen state fail");
}
}
return 0;
}
#endif
/*******************************************************
Description:
@ -1830,6 +2073,15 @@ static int32_t nvt_ts_probe(struct spi_device *client)
#ifdef NVT_SENSOR_EN
static bool initialized_sensor;
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
struct device_node *dp = client->dev.of_node;
ret = nova_check_dt(dp);
if (ret == -EPROBE_DEFER) {
NVT_LOG("panel error\n");
return ret;
}
#endif
NVT_LOG("start\n");
@ -1952,8 +2204,13 @@ static int32_t nvt_ts_probe(struct spi_device *client)
input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, TOUCH_FORCE_NUM, 0, 0); //pressure = TOUCH_FORCE_NUM
#if TOUCH_MAX_FINGER_NUM > 1
#ifdef PALM_GESTURE_RANGE
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, TOUCH_DEFAULT_MAX_HEIGHT, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, TOUCH_DEFAULT_MAX_HEIGHT, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_ORIENTATION, TOUCH_ORIENTATION_MIN, TOUCH_ORIENTATION_MAX, 0, 0);
#else
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); //area = 255
#endif
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0);
#if MT_PROTOCOL_B
@ -1975,6 +2232,10 @@ static int32_t nvt_ts_probe(struct spi_device *client)
}
#endif
#ifdef PALM_GESTURE
ts->palm_enabled = false;
#endif
sprintf(ts->phys, "input/ts");
ts->input_dev->name = NVT_TS_NAME;
ts->input_dev->phys = ts->phys;
@ -2125,6 +2386,28 @@ static int32_t nvt_ts_probe(struct spi_device *client)
}
#endif
#ifdef NOVATECH_PEN_NOTIFIER
ts->fw_ready_flag = false;
ts->nvt_pen_detect_flag = PEN_DETECTION_INSERT;
ts->pen_notif.notifier_call = pen_notifier_callback;
ret = pen_detection_register_client(&ts->pen_notif);
if (ret) {
NVT_ERR("[PEN]Unable to register pen_notifier: %d\n", ret);
goto err_register_pen_notif_failed;
}
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
#if defined(CONFIG_DRM)
ts->drm_notif.notifier_call = nvt_drm_notifier_callback;
if (active_panel &&
drm_panel_notifier_register(active_panel,
&ts->drm_notif) < 0) {
NVT_LOG("register notifier failed!\n");
goto err_register_drm_notif_failed;
}
#endif
#else //vension code < 5.4.0
#if defined(CONFIG_FB)
#ifdef _MSM_DRM_NOTIFY_H_
ts->drm_notif.notifier_call = nvt_drm_notifier_callback;
@ -2161,6 +2444,7 @@ static int32_t nvt_ts_probe(struct spi_device *client)
goto err_register_early_suspend_failed;
}
#endif
#endif //end version code >= 5.4.0
ret = nvt_fw_class_init(true);
if (ret) {
@ -2175,6 +2459,15 @@ static int32_t nvt_ts_probe(struct spi_device *client)
return 0;
err_create_touchscreen_class_failed:
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
#if defined(CONFIG_DRM)
if (active_panel) {
drm_panel_notifier_unregister(active_panel, &ts->drm_notif);
NVT_ERR("Error occurred while unregistering drm_notifier.\n");
}
err_register_drm_notif_failed:
#endif
#else //vension code < 5.4.0
#if defined(CONFIG_FB)
#ifdef _MSM_DRM_NOTIFY_H_
if (msm_drm_unregister_client(&ts->drm_notif))
@ -2189,6 +2482,12 @@ err_register_fb_notif_failed:
unregister_early_suspend(&ts->early_suspend);
err_register_early_suspend_failed:
#endif
#endif //end version code >= 5.4.0
#ifdef NOVATECH_PEN_NOTIFIER
if (pen_detection_unregister_client(&ts->pen_notif))
NVT_ERR("Error occurred while unregistering pen_notifier.\n");
err_register_pen_notif_failed:
#endif
#if NVT_TOUCH_MP
nvt_mp_proc_deinit();
err_mp_proc_init_failed:
@ -2272,6 +2571,15 @@ static int32_t nvt_ts_remove(struct spi_device *client)
NVT_LOG("Removing driver...\n");
nvt_fw_class_init(false);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
#if defined(CONFIG_DRM)
if (active_panel) {
drm_panel_notifier_unregister(active_panel, &ts->drm_notif);
NVT_ERR("Error occurred while unregistering drm_notifier.\n");
}
#endif
#else //vension code < 5.4.0
#if defined(CONFIG_FB)
#ifdef _MSM_DRM_NOTIFY_H_
if (msm_drm_unregister_client(&ts->drm_notif))
@ -2288,6 +2596,11 @@ static int32_t nvt_ts_remove(struct spi_device *client)
if (unregister_panel_notifier(&ts->panel_notif))
NVT_ERR("Error occurred while unregistering panel_notifier.\n");
#endif
#endif //end version code >= 5.4.0
#ifdef NOVATECH_PEN_NOTIFIER
if (pen_detection_unregister_client(&ts->pen_notif))
NVT_ERR("Error occurred while unregistering pen_notifier.\n");
#endif
#if NVT_TOUCH_MP
nvt_mp_proc_deinit();
@ -2358,6 +2671,14 @@ static void nvt_ts_shutdown(struct spi_device *client)
nvt_irq_enable(false);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
#if defined(CONFIG_DRM)
if (active_panel) {
drm_panel_notifier_unregister(active_panel, &ts->drm_notif);
NVT_ERR("Error occurred while unregistering drm_notifier.\n");
}
#endif
#else //vension code < 5.4.0
#if defined(CONFIG_FB)
#ifdef _MSM_DRM_NOTIFY_H_
if (msm_drm_unregister_client(&ts->drm_notif))
@ -2374,7 +2695,7 @@ static void nvt_ts_shutdown(struct spi_device *client)
if (unregister_panel_notifier(&ts->panel_notif))
NVT_ERR("Error occurred while unregistering panel_notifier.\n");
#endif
#endif //end version code >= 5.4.0
#if NVT_TOUCH_MP
nvt_mp_proc_deinit();
#endif
@ -2491,6 +2812,10 @@ static int32_t nvt_ts_suspend(struct device *dev)
#if MT_PROTOCOL_B
for (i = 0; i < ts->max_touch_num; i++) {
input_mt_slot(ts->input_dev, i);
#ifdef PALM_GESTURE_RANGE
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, 0);
input_report_abs(ts->input_dev, ABS_MT_ORIENTATION, 0);
#endif
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
@ -2586,6 +2911,48 @@ static int32_t nvt_ts_resume(struct device *dev)
return 0;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
#if defined(CONFIG_DRM)
static int nvt_drm_notifier_callback(struct notifier_block *self, unsigned long event, void *data)
{
struct msm_drm_notifier *evdata = data;
int *blank;
struct nvt_ts_data *ts =
container_of(self, struct nvt_ts_data, drm_notif);
if (!evdata)
return 0;
if (!(event == MSM_DRM_EARLY_EVENT_BLANK ||
event == MSM_DRM_EVENT_BLANK)) {
NVT_LOG("event(%lu) do not need process\n", event);
return 0;
}
blank = evdata->data;
NVT_LOG("event=%lu, *blank=%d\n", event, *blank);
if (event == MSM_DRM_EARLY_EVENT_BLANK) {
if (*blank == MSM_DRM_BLANK_POWERDOWN) {
NVT_LOG("event=%lu, *blank=%d\n", event, *blank);
nvt_ts_suspend(&ts->client->dev);
#ifdef NVT_SENSOR_EN
if (ts->should_enable_gesture) {
NVT_LOG("double tap gesture suspend\n");
return 1;
}
#endif
}
} else if (event == MSM_DRM_EVENT_BLANK) {
if (*blank == MSM_DRM_BLANK_UNBLANK) {
NVT_LOG("event=%lu, *blank=%d\n", event, *blank);
nvt_ts_resume(&ts->client->dev);
}
}
return 0;
}
#endif
#else //vension code < 5.4.0
#ifdef NVT_CONFIG_PANEL_NOTIFICATIONS
static int nvt_panel_notifier_callback(struct notifier_block *self, unsigned long event, void *data)
{
@ -2704,6 +3071,7 @@ static void nvt_ts_late_resume(struct early_suspend *h)
nvt_ts_resume(ts->client);
}
#endif
#endif //version code >= 5.4.0
static const struct spi_device_id nvt_ts_id[] = {
{ NVT_SPI_NAME, 0 },

View file

@ -23,6 +23,9 @@
#include <linux/of.h>
#include <linux/spi/spi.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include <linux/mmi_kernel_common.h>
#ifdef NVT_SENSOR_EN
#include <linux/sensors.h>
#endif
@ -30,6 +33,9 @@
#ifdef NVT_CONFIG_PANEL_NOTIFICATIONS
#include <linux/panel_notifier.h>
#endif
#ifdef NOVATECH_PEN_NOTIFIER
#include <linux/pen_detection_notify.h>
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
@ -63,6 +69,7 @@
//---SPI driver info.---
#define NVT_SPI_NAME "NVT-ts"
#define NVT_PRIMARY_NAME "primary"
#if NVT_DEBUG
#define NVT_LOG(fmt, args...) pr_err("[%s] %s %d: " fmt, NVT_SPI_NAME, __func__, __LINE__, ##args)
@ -85,6 +92,16 @@
extern const uint16_t touch_key_array[TOUCH_KEY_NUM];
#endif
#define TOUCH_FORCE_NUM 1000
#ifdef PALM_GESTURE
#define PALM_HAND_HOLDE 900
#define PALM_HANG 1000
#ifdef PALM_GESTURE_RANGE
#define TOUCH_ORIENTATION_MIN 0
#define TOUCH_ORIENTATION_MAX 90
#define PANEL_REAL_WIDTH 7096
#define PANEL_REAL_HEIGHT 15768
#endif
#endif
/* Enable only when module have tp reset pin and connected to host */
#define NVT_TOUCH_SUPPORT_HW_RST 0
@ -107,7 +124,7 @@ extern const uint16_t gesture_key_array[];
#define MP_UPDATE_FIRMWARE_NAME "novatek_ts_mp.bin"
#define POINT_DATA_CHECKSUM 1
#define POINT_DATA_CHECKSUM_LEN 65
#define NVT_FILE_NAME_LENGTH 128
//---ESD Protect.---
#define NVT_TOUCH_ESD_PROTECT 0
#define NVT_TOUCH_ESD_CHECK_PERIOD 1500 /* ms */
@ -148,18 +165,7 @@ struct nvt_ts_data {
struct delayed_work nvt_fwu_work;
uint16_t addr;
int8_t phys[32];
#if defined(CONFIG_FB)
#ifdef _MSM_DRM_NOTIFY_H_
struct notifier_block drm_notif;
#else
struct notifier_block fb_notif;
#endif
#elif defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif
#ifdef NVT_CONFIG_PANEL_NOTIFICATIONS
struct notifier_block panel_notif;
#endif
uint8_t fw_ver;
uint8_t x_num;
uint8_t y_num;
@ -181,6 +187,7 @@ struct nvt_ts_data {
uint8_t *xbuf;
struct mutex xbuf_lock;
bool irq_enabled;
const char *panel_supplier;
#ifdef CONFIG_MTK_SPI
struct mt_chip_conf spi_ctrl;
#endif
@ -194,14 +201,40 @@ struct nvt_ts_data {
bool wakeable;
bool should_enable_gesture;
bool gesture_enabled;
#ifdef NOVATECH_PEN_NOTIFIER
bool fw_ready_flag;
int nvt_pen_detect_flag;
struct notifier_block pen_notif;
#endif
enum display_state screen_state;
struct mutex state_mutex;
struct nvt_sensor_platform_data *sensor_pdata;
#endif
#ifdef PALM_GESTURE
bool palm_enabled;
#endif
char product_id[10];
uint8_t fw_type;
uint32_t build_id;
uint32_t config_id;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
#if defined(CONFIG_DRM)
struct notifier_block drm_notif;
#endif
#else //vension code < 5.4.0
#if defined(CONFIG_FB)
#ifdef _MSM_DRM_NOTIFY_H_
struct notifier_block drm_notif;
#else
struct notifier_block fb_notif;
#endif
#elif defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif
#ifdef NVT_CONFIG_PANEL_NOTIFICATIONS
struct notifier_block panel_notif;
#endif
#endif //version code >= 5.4.0
};
#if NVT_TOUCH_PROC
@ -241,6 +274,9 @@ typedef enum {
//---extern structures---
extern struct nvt_ts_data *ts;
extern char *nvt_boot_firmware_name;
extern char *nvt_mp_firmware_name;
//---extern functions---
int32_t CTP_SPI_READ(struct spi_device *client, uint8_t *buf, uint16_t len);
int32_t CTP_SPI_WRITE(struct spi_device *client, uint8_t *buf, uint16_t len);
@ -261,5 +297,10 @@ int32_t nvt_write_addr(uint32_t addr, uint8_t data);
#if NVT_TOUCH_ESD_PROTECT
extern void nvt_esd_check_enable(uint8_t enable);
#endif /* #if NVT_TOUCH_ESD_PROTECT */
#ifdef NOVATECH_PEN_NOTIFIER
extern int nvt_mcu_pen_detect_set(uint8_t pen_detect);
#endif
#ifdef PALM_GESTURE
extern int nvt_palm_set(bool enabled);
#endif
#endif /* _LINUX_NVT_TOUCH_H */

View file

@ -39,6 +39,16 @@
#define XDATA_SECTOR_SIZE 256
#define ENABLE_PASSIVE_PEN_MODE_CMD 0x73
#define DISABLE_PASSIVE_PEN_MODE_CMD 0x74
#define ENABLE_PALM_GESTURE_MODE_CMD 0x75
#define DISABLE_PALM_GESTURE_MODE_CMD 0x76
#define ENABLE_DOZE_MODE_CMD 0xB7
#define DISABLE_DOZE_MODE_CMD 0xB8
static uint8_t monitor_control_status = 1;
static uint8_t xdata_tmp[2048] = {0};
static int32_t xdata[2048] = {0};
@ -562,10 +572,16 @@ static ssize_t nvt_fwupdate_read(struct file *file, char __user *buff, size_t co
switch (fwtype) {
case FWTYPE_Normal:
nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
if(nvt_boot_firmware_name)
nvt_update_firmware(nvt_boot_firmware_name);
else
nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
break;
case FWTYPE_MP:
nvt_update_firmware(MP_UPDATE_FIRMWARE_NAME);
if(nvt_mp_firmware_name)
nvt_update_firmware(nvt_mp_firmware_name);
else
nvt_update_firmware(MP_UPDATE_FIRMWARE_NAME);
break;
default:
NVT_ERR("fwtype error\n");
@ -586,61 +602,85 @@ static const struct file_operations nvt_fwupdate_fops = {
.read = nvt_fwupdate_read,
};
uint8_t status = 1;
#define ENABLE_MONITOR 1
#define DISABLE_MONITOR 0
#define ENABLE_DOZE_MODE_CMD 0xB7
#define DISABLE_DOZE_MODE_CMD 0xB8
int32_t nvt_monitor_control(uint8_t status)
int32_t nvt_cmd_store(uint8_t u8Cmd)
{
uint8_t buf[8] = {0};
int i, retry = 5;
uint8_t buf[3] = {0};
int32_t ret = 0;
NVT_LOG("set monitor control: %d\n", status);
if (mutex_lock_interruptible(&ts->lock)) {
return -ERESTARTSYS;
}
//---set xdata index to EVENT BUF ADDR---
ret = nvt_set_page(ts->mmap->EVENT_BUF_ADDR | EVENT_MAP_HOST_CMD);
if (ret < 0) {
NVT_ERR("Set event buffer index fail!\n");
goto nvt_monitor_control_out;
mutex_unlock(&ts->lock);
return ret;
}
if (status == ENABLE_MONITOR) {
for (i = 0; i < retry; i++) {
//---set cmd status---
buf[0] = EVENT_MAP_HOST_CMD;
buf[1] = ENABLE_DOZE_MODE_CMD;
ret = CTP_SPI_WRITE(ts->client, buf, 2);
if (ret < 0) {
NVT_ERR("Write enable doze mode command fail!\n");
goto nvt_monitor_control_out;
} else {
NVT_LOG("set enable doze mode cmd succeeded\n");
}
} else if (status == DISABLE_MONITOR) {
buf[1] = u8Cmd;
CTP_SPI_WRITE(ts->client, buf, 2);
msleep(20);
//---read cmd status---
buf[0] = EVENT_MAP_HOST_CMD;
buf[1] = DISABLE_DOZE_MODE_CMD;
ret = CTP_SPI_WRITE(ts->client, buf, 2);
if (ret < 0) {
NVT_ERR("Write disable doze mode command fail!\n");
goto nvt_monitor_control_out;
} else {
NVT_LOG("set disable doze mode cmd succeeded\n");
}
buf[1] = 0xFF;
CTP_SPI_READ(ts->client, buf, 2);
if (buf[1] == 0x00)
break;
}
if (unlikely(i == retry)) {
NVT_LOG("send Cmd 0x%02X failed, buf[1]=0x%02X\n", u8Cmd, buf[1]);
ret = -1;
} else {
NVT_ERR("Invalid monitor_control parameter!\n");
ret = -EINVAL;
NVT_LOG("send Cmd 0x%02X success, tried %d times\n", u8Cmd, i);
}
nvt_monitor_control_out:
mutex_unlock(&ts->lock);
return ret;
}
#ifdef NOVATECH_PEN_NOTIFIER
int nvt_mcu_pen_detect_set(uint8_t pen_detect) {
int ret = 0;
if (pen_detect == PEN_DETECTION_PULL) {
ret = nvt_cmd_store(ENABLE_PASSIVE_PEN_MODE_CMD);
} else if (pen_detect == PEN_DETECTION_INSERT) {
ret = nvt_cmd_store(DISABLE_PASSIVE_PEN_MODE_CMD);
}
return ret;
}
#endif
#ifdef PALM_GESTURE
int nvt_palm_set(bool enabled) {
int ret = 0;
if (enabled) {
ret = nvt_cmd_store(ENABLE_PALM_GESTURE_MODE_CMD);
} else if (!enabled) {
ret = nvt_cmd_store(DISABLE_PALM_GESTURE_MODE_CMD);
}
return ret;
}
#endif
static int nvt_monitor_control_show(struct seq_file *sfile, void *v)
{
if(status == ENABLE_MONITOR)
if(monitor_control_status == 1)
seq_printf(sfile, "Enable Doze MODE!\n");
else if (status == DISABLE_MONITOR)
else if (monitor_control_status == 0)
seq_printf(sfile, "Disable Doze MODE!\n");
else
seq_printf(sfile, "UNKNOW MODE!\n");
@ -670,8 +710,17 @@ static ssize_t nvt_monitor_control_store(struct file *file, const char *buffer,
return -EINVAL;
}
status = input;
nvt_monitor_control(status);
monitor_control_status = input;
NVT_LOG("set monitor control: %d\n", monitor_control_status);
if (monitor_control_status == 1) {
nvt_cmd_store(ENABLE_DOZE_MODE_CMD);
} else if (monitor_control_status == 0) {
nvt_cmd_store(DISABLE_DOZE_MODE_CMD);
} else {
NVT_ERR("Invalid parameter %d!\n", monitor_control_status);
}
kfree(str);
return count;

View file

@ -34,7 +34,7 @@
#define NVT_DUMP_PARTITION_LEN (1024)
#define NVT_DUMP_PARTITION_PATH "/data/local/tmp"
struct timeval start, end;
struct TIME_TYPE start, end;
const struct firmware *fw_entry = NULL;
static size_t fw_need_write_size = 0;
static uint8_t *fwbuf = NULL;
@ -402,7 +402,11 @@ static int32_t nvt_read_ram_and_save_file(uint32_t addr, uint16_t len, char *nam
CTP_SPI_READ(ts->client, fbufp, len+1);
/* Write to file */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
ret = kernel_write(fp, (char __user *)fbufp+1, len, &file_offset);
#else
ret = vfs_write(fp, (char __user *)fbufp+1, len, &file_offset);
#endif
if (ret != len) {
NVT_ERR("write file failed\n");
goto open_file_fail;
@ -803,7 +807,7 @@ static int32_t nvt_download_firmware_hw_crc(void)
uint8_t retry = 0;
int32_t ret = 0;
do_gettimeofday(&start);
GET_TIME_OF_DAY(&start);
while (1) {
/* bootloader reset to reset MCU */
@ -852,7 +856,7 @@ fail:
}
}
do_gettimeofday(&end);
GET_TIME_OF_DAY(&end);
return ret;
}
@ -870,7 +874,7 @@ static int32_t nvt_download_firmware(void)
uint8_t retry = 0;
int32_t ret = 0;
do_gettimeofday(&start);
GET_TIME_OF_DAY(&start);
while (1) {
/*
@ -931,7 +935,7 @@ fail:
}
}
do_gettimeofday(&end);
GET_TIME_OF_DAY(&end);
return ret;
}
@ -971,8 +975,13 @@ int32_t nvt_update_firmware(char *firmware_name)
goto download_fail;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
NVT_LOG("Update firmware success! <%lld us>\n",
(end.tv_sec - start.tv_sec)*1000000L + (end.tv_nsec - start.tv_nsec)/1000);
#else
NVT_LOG("Update firmware success! <%ld us>\n",
(end.tv_sec - start.tv_sec)*1000000L + (end.tv_usec - start.tv_usec));
#endif
/* Get FW Info */
ret = nvt_get_fw_info();
@ -1002,16 +1011,33 @@ return:
*******************************************************/
void Boot_Update_Firmware(struct work_struct *work)
{
int32_t ret = 0;
mutex_lock(&ts->lock);
if (nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME)) {
if(nvt_boot_firmware_name)
ret = nvt_update_firmware(nvt_boot_firmware_name);
else
ret = nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
if (ret) {
NVT_ERR("download firmware failed, ignore check fw state\n");
} else {
nvt_check_fw_reset_state(RESET_STATE_REK);
}
mutex_unlock(&ts->lock);
if (ts->charger_detection) {
queue_work(ts->charger_detection->nvt_charger_notify_wq, &ts->charger_detection->charger_notify_work);
}
mutex_unlock(&ts->lock);
#ifdef NOVATECH_PEN_NOTIFIER
if(!ts->fw_ready_flag)
ts->fw_ready_flag = true;
nvt_mcu_pen_detect_set(ts->nvt_pen_detect_flag);
#endif
#ifdef PALM_GESTURE
nvt_palm_set(ts->palm_enabled);
#endif
}
#endif /* BOOT_UPDATE_FIRMWARE */

View file

@ -414,7 +414,11 @@ static int32_t nvt_save_rawdata_to_csv(int32_t *rawdata, uint8_t x_ch, uint8_t y
output_len = y_ch * x_ch * 7 + y_ch * 2;
#endif /* #if TOUCH_KEY_NUM > 0 */
pos = offset;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
write_ret = kernel_write(fp, (char __user *)fbufp, output_len, &pos);
#else
write_ret = vfs_write(fp, (char __user *)fbufp, output_len, &pos);
#endif
if (write_ret <= 0) {
NVT_ERR("write %s failed\n", file_path);
set_fs(org_fs);
@ -1216,7 +1220,10 @@ static int32_t nvt_selftest_open(struct inode *inode, struct file *file)
#endif /* #if NVT_TOUCH_ESD_PROTECT */
//---Download MP FW---
nvt_update_firmware(MP_UPDATE_FIRMWARE_NAME);
if(nvt_mp_firmware_name)
nvt_update_firmware(nvt_mp_firmware_name);
else
nvt_update_firmware(MP_UPDATE_FIRMWARE_NAME);
if (nvt_get_fw_info()) {
mutex_unlock(&ts->lock);
@ -1240,7 +1247,10 @@ static int32_t nvt_selftest_open(struct inode *inode, struct file *file)
if (nvt_mp_parse_dt(np, mpcriteria)) {
//---Download Normal FW---
nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
if(nvt_boot_firmware_name)
nvt_update_firmware(nvt_boot_firmware_name);
else
nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
mutex_unlock(&ts->lock);
NVT_ERR("mp parse device tree failed!\n");
return -EINVAL;
@ -1343,7 +1353,10 @@ static int32_t nvt_selftest_open(struct inode *inode, struct file *file)
}
//---Download Normal FW---
nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
if(nvt_boot_firmware_name)
nvt_update_firmware(nvt_boot_firmware_name);
else
nvt_update_firmware(BOOT_UPDATE_FIRMWARE_NAME);
mutex_unlock(&ts->lock);