summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHyungwoo Yang <hyungwooyang@google.com>2022-10-27 05:12:53 +0000
committerHyungwoo Yang <hyungwooyang@google.com>2022-11-10 06:05:02 +0000
commit7cf5c745c81dd988befb46585ba054fc5407d7d2 (patch)
treed8dd9e012c11c8c8d4284b76e57fac0eef8474f1
parent0087d1e5deff0334780c8e076cc1bd6bf2f2da43 (diff)
downloadnovatek_touch-7cf5c745c81dd988befb46585ba054fc5407d7d2.tar.gz
touch/novatek: report pen information
This patch exposes firmware information and serial number to user. Test: The data is shown properly via HID Get Request and getevent. Bug: 253322792 Signed-off-by: Hyungwoo Yang <hyungwooyang@google.com> Change-Id: Iafc3f38694a37c3fdc86dbbd09cf0aac87bc0256
-rw-r--r--nt36xxx/nt36xxx.c115
-rw-r--r--nt36xxx/nt36xxx.h28
-rw-r--r--nt36xxx/nt36xxx_ext_usi.c169
-rw-r--r--nt36xxx/nt36xxx_mem_map.h2
4 files changed, 291 insertions, 23 deletions
diff --git a/nt36xxx/nt36xxx.c b/nt36xxx/nt36xxx.c
index a93ea5c..8547ad3 100644
--- a/nt36xxx/nt36xxx.c
+++ b/nt36xxx/nt36xxx.c
@@ -31,6 +31,8 @@
#define NVT_PRODUCT_ID 0x7806
#define NVT_VERSION 0x0100
+#define INFO_BUF_SIZE (64 + 1)
+
#if defined(CONFIG_DRM_PANEL)
#include <drm/drm_panel.h>
#elif defined(CONFIG_DRM_MSM)
@@ -1453,6 +1455,9 @@ static enum power_supply_property pen_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+#if NVT_TOUCH_EXT_USI
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
+#endif
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_SCOPE,
};
@@ -1498,6 +1503,15 @@ static int pen_get_battery_property(struct power_supply *psy,
break;
+#if NVT_TOUCH_EXT_USI
+ case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+ /* the latest serial number */
+ mutex_lock(&ts->lock);
+ val->strval = ts->battery_serial_number_str;
+ mutex_unlock(&ts->lock);
+
+ break;
+#endif
case POWER_SUPPLY_PROP_STATUS:
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
break;
@@ -1550,6 +1564,50 @@ static void pen_clean_battery(struct power_supply *battery)
kfree(psy_desc);
}
+#if NVT_TOUCH_EXT_USI
+static void process_usi_responses(uint16_t info_buf_flags, const uint8_t *info_buf)
+{
+ uint32_t pen_serial_high;
+ uint32_t pen_serial_low;
+ uint8_t pen_bat_capa;
+
+ if (info_buf_flags & USI_GID_FLAG) {
+ nvt_usi_store_gid(info_buf + USI_GID_OFFSET);
+ nvt_usi_get_serial_number(&pen_serial_high, &pen_serial_low);
+ if (ts->pen_serial_high != pen_serial_high ||
+ ts->pen_serial_low != pen_serial_low) {
+ int idx = 0;
+ int sz = sizeof(ts->battery_serial_number_str);
+
+ idx += scnprintf(ts->battery_serial_number_str + idx, sz - idx,
+ "%08X", pen_serial_high);
+ idx += scnprintf(ts->battery_serial_number_str + idx, sz - idx,
+ "%08X", pen_serial_low);
+
+ ts->pen_serial_high = pen_serial_high;
+ ts->pen_serial_low = pen_serial_low;
+
+ power_supply_changed(ts->pen_bat_psy);
+ }
+ }
+
+ if (info_buf_flags & USI_BATTERY_FLAG) {
+ nvt_usi_store_battery(info_buf + USI_BATTERY_OFFSET);
+ nvt_usi_get_battery(&pen_bat_capa);
+ if (ts->pen_bat_capa != pen_bat_capa) {
+ ts->pen_bat_capa = pen_bat_capa;
+ power_supply_changed(ts->pen_bat_psy);
+ }
+ }
+
+ if (info_buf_flags & USI_FW_VERSION_FLAG)
+ nvt_usi_store_fw_version(info_buf + USI_FW_VERSION_OFFSET);
+
+ if (info_buf_flags & USI_CAPABILITY_FLAG)
+ nvt_usi_store_capability(info_buf + USI_CAPABILITY_OFFSET);
+}
+#endif
+
static irqreturn_t nvt_ts_isr(int irq, void *handle)
{
struct nvt_ts_data *ts = (struct nvt_ts_data *)handle;
@@ -1592,6 +1650,11 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data)
uint32_t pen_btn2 = 0;
uint8_t touch_freq_index;
uint8_t pen_freq_index;
+#if NVT_TOUCH_EXT_USI
+ uint8_t info_buf[INFO_BUF_SIZE] = {0};
+ uint16_t info_buf_flags;
+ uint32_t pen_serial_low;
+#endif
if (!ts->probe_done)
return IRQ_HANDLED;
@@ -1871,10 +1934,6 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data)
#endif
pen_btn1 = (uint32_t)(point_data[77] & 0x01);
pen_btn2 = (uint32_t)((point_data[77] >> 1) & 0x01);
- if (point_data[78] && ts->pen_bat_capa != (uint32_t)point_data[78]) {
- ts->pen_bat_capa = (uint32_t)point_data[78];
- power_supply_changed(ts->pen_bat_psy);
- }
// printk("x=%d,y=%d,p=%d,tx=%d,ty=%d,d=%d,b1=%d,b2=%d,bat=%d\n", pen_x, pen_y, pen_pressure,
// pen_tilt_x, pen_tilt_y, pen_distance, pen_btn1, pen_btn2, pen_battery);
@@ -1902,13 +1961,35 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data)
input_report_key(ts->pen_input_dev, BTN_TOOL_PEN, 1);
input_report_key(ts->pen_input_dev, BTN_STYLUS, pen_btn1);
input_report_key(ts->pen_input_dev, BTN_STYLUS2, pen_btn2);
+#if NVT_TOUCH_EXT_USI
+ /*
+ * Input Subsystem doesn't support 64bits serial number.
+ * So we only reports the lower 32bit.
+ */
+ if (!nvt_usi_get_serial_number(NULL, &pen_serial_low))
+ input_event(ts->pen_input_dev, EV_MSC,
+ MSC_SERIAL, pen_serial_low);
+#endif
+ input_sync(ts->pen_input_dev);
+#if NVT_TOUCH_EXT_USI
+ info_buf_flags = point_data[63] + (point_data[64] << 8);
+
+ if (info_buf_flags) {
+ nvt_set_page(ts->mmap->EB_INFO_ADDR);
+ info_buf[0] = ts->mmap->EB_INFO_ADDR & 0x7F;
+ CTP_SPI_READ(ts->client, info_buf, INFO_BUF_SIZE);
+ nvt_set_page(ts->mmap->EVENT_BUF_ADDR);
+
+ process_usi_responses(info_buf_flags, info_buf);
+ }
+#endif
} else if (ts->pen_format_id == 0xF0) {
// report Pen ID
} else {
NVT_ERR("Unknown pen format id!\n");
goto XFER_ERROR;
}
- } else { // pen_format_id = 0xFF, i.e. no pen present
+ } else if (ts->pen_active) { // pen_format_id = 0xFF and a pen was reporting
input_set_timestamp(ts->pen_input_dev, ts->timestamp);
/* Snapshot some stylus context information for offload */
@@ -1929,9 +2010,15 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data)
input_report_key(ts->pen_input_dev, BTN_TOOL_PEN, 0);
input_report_key(ts->pen_input_dev, BTN_STYLUS, 0);
input_report_key(ts->pen_input_dev, BTN_STYLUS2, 0);
+#if NVT_TOUCH_EXT_USI
+ if (!nvt_usi_get_serial_number(NULL, &pen_serial_low))
+ input_event(ts->pen_input_dev, EV_MSC, MSC_SERIAL, pen_serial_low);
+#endif
+ input_sync(ts->pen_input_dev);
+#if NVT_TOUCH_EXT_USI
+ nvt_usi_clear_stylus_read_map();
+#endif
}
-
- input_sync(ts->pen_input_dev);
} /* if (ts->pen_support) */
/* Check any sensing freq hopping for touch or stylus. */
@@ -2399,6 +2486,10 @@ static int32_t nvt_ts_probe(struct spi_device *client)
input_set_abs_params(ts->pen_input_dev, ABS_TILT_Y, PEN_TILT_MIN,
PEN_TILT_MAX, 0, 0);
+#if NVT_TOUCH_EXT_USI
+ __set_bit(EV_MSC, ts->pen_input_dev->evbit);
+ __set_bit(MSC_SERIAL, ts->pen_input_dev->mscbit);
+#endif
snprintf(ts->pen_phys, sizeof(ts->pen_phys), "input/pen");
ts->pen_input_dev->name = NVT_PEN_NAME;
ts->pen_input_dev->uniq = ts->pen_input_dev->name;
@@ -2882,6 +2973,9 @@ int nvt_ts_suspend(struct device *dev)
{
uint8_t buf[4] = {0};
uint32_t i = 0;
+#if NVT_TOUCH_EXT_USI
+ uint32_t pen_serial_low;
+#endif
if (!ts->bTouchIsAwake) {
NVT_LOG("Touch is already suspend\n");
@@ -2955,12 +3049,19 @@ int nvt_ts_suspend(struct device *dev)
input_report_key(ts->pen_input_dev, BTN_TOOL_PEN, 0);
input_report_key(ts->pen_input_dev, BTN_STYLUS, 0);
input_report_key(ts->pen_input_dev, BTN_STYLUS2, 0);
+#if NVT_TOUCH_EXT_USI
+ if (!nvt_usi_get_serial_number(NULL, &pen_serial_low))
+ input_event(ts->pen_input_dev, EV_MSC, MSC_SERIAL, pen_serial_low);
+#endif
input_sync(ts->pen_input_dev);
ts->pen_active = 0;
ts->pen_offload_coord_timestamp = ts->timestamp;
memset(&ts->pen_offload_coord, 0,
sizeof(ts->pen_offload_coord));
+#if NVT_TOUCH_EXT_USI
+ nvt_usi_clear_stylus_read_map();
+#endif
}
#if (WAKEUP_GESTURE) && (NVT_TOUCH_EXT_API)
diff --git a/nt36xxx/nt36xxx.h b/nt36xxx/nt36xxx.h
index 95a8dd8..c8c9ceb 100644
--- a/nt36xxx/nt36xxx.h
+++ b/nt36xxx/nt36xxx.h
@@ -259,6 +259,11 @@ struct nvt_ts_data {
uint8_t pen_format_id;
uint32_t pen_bat_capa;
struct power_supply *pen_bat_psy;
+#if NVT_TOUCH_EXT_USI
+ char battery_serial_number_str[17]; /* 16 hex digits */
+ uint32_t pen_serial_high; /* transducer serial number high 32 bits */
+ uint32_t pen_serial_low; /* transducer serial number low 32 bits */
+#endif
#if NVT_TOUCH_EXT_API
uint16_t dttw_touch_area_max;
uint16_t dttw_touch_area_min;
@@ -398,6 +403,29 @@ extern ssize_t nvt_set_dttw(uint8_t wkg_flag, bool check_result);
#if NVT_TOUCH_EXT_USI
extern int32_t nvt_extra_usi_init(void);
extern void nvt_extra_usi_deinit(void);
+extern int32_t nvt_usi_clear_stylus_read_map(void);
+extern int32_t nvt_usi_store_battery(const uint8_t *buf_bat);
+extern int32_t nvt_usi_store_capability(const uint8_t *buf_cap);
+extern int32_t nvt_usi_store_fw_version(const uint8_t *buf_fw_ver);
+extern int32_t nvt_usi_store_gid(const uint8_t *buf_gid);
+
+extern int32_t nvt_usi_get_battery(uint8_t *bat);
+extern int32_t nvt_usi_get_serial_number(uint32_t *serial_high, uint32_t *serial_low);
+/* Flags for the responses of the USI read commands */
+enum {
+ USI_GID_FLAG = 1U << 0, /* C.GetGID() */
+ USI_BATTERY_FLAG = 1U << 1, /* C.GetBattery() */
+ USI_CAPABILITY_FLAG = 1U << 2, /* C.GetCapacity() */
+ USI_FW_VERSION_FLAG = 1U << 3, /* C.GetFirmwareVersion() */
+};
+
+/* location of the data in the response buffer */
+enum {
+ USI_GID_OFFSET = 1,
+ USI_BATTERY_OFFSET = 13,
+ USI_FW_VERSION_OFFSET = 15,
+ USI_CAPABILITY_OFFSET = 17
+};
#endif
#if NVT_TOUCH_ESD_PROTECT
diff --git a/nt36xxx/nt36xxx_ext_usi.c b/nt36xxx/nt36xxx_ext_usi.c
index 56e0eb4..55d3209 100644
--- a/nt36xxx/nt36xxx_ext_usi.c
+++ b/nt36xxx/nt36xxx_ext_usi.c
@@ -26,6 +26,10 @@
#if NVT_TOUCH_EXT_USI
+#define GID_NUM 12
+#define CAP_NUM 12
+#define FW_VER_NUM 2
+
/*
* The following HID Report Descriptor is copied from
* USIv2-HID-Report-Descriptor.h from universalstylus.org.
@@ -465,6 +469,21 @@ static uint8_t USI_report_descriptor_v2_0[] = {
0xc0 // END_COLLECTION
};
+struct nvt_usi_context {
+ /*
+ * Bit Fields:
+ * A bit represents if the corresponding read command is done or not.
+ */
+ uint32_t stylus_read_map;
+
+ /* responses from a paired stylus. */
+ uint8_t stylus_cap[CAP_NUM]; /* C.GetCapability() */
+ uint8_t stylus_GID[GID_NUM]; /* C.GetGID() */
+ uint8_t stylus_fw_ver[FW_VER_NUM]; /* C.GetFirmwareVersion() */
+ uint8_t stylus_battery; /* C.GetBattery() */
+};
+
+static struct nvt_usi_context *usi_ctx;
#define DEFAULT_STYLUS_INDEX 1
@@ -537,6 +556,121 @@ static int32_t device_release(struct inode *inode, struct file *file)
return 0;
}
+int32_t nvt_usi_store_gid(const uint8_t *buf_gid)
+{
+ if (!usi_ctx)
+ return -EINVAL;
+
+ memcpy(usi_ctx->stylus_GID, buf_gid, sizeof(usi_ctx->stylus_GID));
+ usi_ctx->stylus_read_map |= USI_GID_FLAG;
+
+ return 0;
+}
+
+int32_t nvt_usi_store_fw_version(const uint8_t *buf_fw_ver)
+{
+ if (!usi_ctx)
+ return -EINVAL;
+
+ memcpy(usi_ctx->stylus_fw_ver, buf_fw_ver,
+ sizeof(usi_ctx->stylus_fw_ver));
+ usi_ctx->stylus_read_map |= USI_FW_VERSION_FLAG;
+
+ return 0;
+}
+
+int32_t nvt_usi_store_capability(const uint8_t *buf_cap)
+{
+ if (!usi_ctx)
+ return -EINVAL;
+
+ memcpy(usi_ctx->stylus_cap, buf_cap, sizeof(usi_ctx->stylus_cap));
+ usi_ctx->stylus_read_map |= USI_CAPABILITY_FLAG;
+
+ return 0;
+}
+
+int32_t nvt_usi_store_battery(const uint8_t *buf_bat)
+{
+ if (!usi_ctx)
+ return -EINVAL;
+
+ usi_ctx->stylus_battery = buf_bat[0];
+ usi_ctx->stylus_read_map |= USI_BATTERY_FLAG;
+
+ return 0;
+}
+
+int32_t nvt_usi_get_battery(uint8_t *bat)
+{
+ if (!usi_ctx)
+ return -EINVAL;
+
+ if (!(usi_ctx->stylus_read_map & USI_BATTERY_FLAG))
+ return -ENODATA;
+
+ *bat = usi_ctx->stylus_battery;
+
+ return 0;
+}
+
+int32_t nvt_usi_get_serial_number(uint32_t *serial_high, uint32_t *serial_low)
+{
+ if (!usi_ctx)
+ return -EINVAL;
+
+ if (!(usi_ctx->stylus_read_map & USI_GID_FLAG))
+ return -ENODATA;
+
+ if (serial_low)
+ *serial_low = usi_ctx->stylus_GID[0] |
+ usi_ctx->stylus_GID[1] << 8 |
+ usi_ctx->stylus_GID[2] << 16 |
+ usi_ctx->stylus_GID[3] << 24;
+
+ if (serial_high)
+ *serial_high = usi_ctx->stylus_GID[4] |
+ usi_ctx->stylus_GID[5] << 8 |
+ usi_ctx->stylus_GID[6] << 16 |
+ usi_ctx->stylus_GID[7] << 24;
+
+ return 0;
+}
+
+int32_t nvt_usi_clear_stylus_read_map(void)
+{
+ if (!usi_ctx)
+ return -EINVAL;
+
+ usi_ctx->stylus_read_map = 0;
+
+ return 0;
+}
+
+#define USI_HID_FIRMWARE_INFO_READY (USI_GID_FLAG | USI_FW_VERSION_FLAG)
+static int32_t get_hid_firmware_info(uint8_t *hid_buf)
+{
+ if ((usi_ctx->stylus_read_map & USI_HID_FIRMWARE_INFO_READY) !=
+ USI_HID_FIRMWARE_INFO_READY)
+ return -ENODATA;
+
+ /* USI 2.0 spec. 7.3.3.1.3 Get Stylus Firmware Info */
+ /* 64bits Transducer Serial Number : GID0 ~ GID3 */
+ memcpy(hid_buf + 2, usi_ctx->stylus_GID, 8);
+
+ /* 32bits Transducer Serial Number Part 2 : GID2 ~ GID3 */
+ memcpy(hid_buf + 10, usi_ctx->stylus_GID + 4, 4);
+
+ /* VID/PID : GID4 ~ GID5 */
+ memcpy(hid_buf + 14, usi_ctx->stylus_GID + 8, 4);
+
+ /* FW version major/minor */
+ hid_buf[18] = usi_ctx->stylus_fw_ver[1];
+ hid_buf[19] = usi_ctx->stylus_fw_ver[0];
+
+ return 0;
+}
+
static struct hid_feature_report_info *get_feature_report_info(int32_t rpt_id)
{
int32_t i;
@@ -673,22 +807,11 @@ static int32_t get_hid_feature_report(uint8_t *hid_buf, int32_t buf_size,
}
break;
case HID_REPORTID_GET_FIRMWARE:
- ret = get_usi_data(spi_buf, rpt_info->vendor_get_cmd, 14);
- if (ret > 0) {
- /* Transducer Serial Number: 64bits */
- memcpy(hid_buf + 2, spi_buf + 1, 8);
- /* Transducer Serial Number part 2: 32bits */
- memcpy(hid_buf + 10, spi_buf + 5, 4);
- /* Vendor ID: 16bits */
- memcpy(hid_buf + 14, spi_buf + 9, 2);
- /* Product ID: 16bits */
- memcpy(hid_buf + 16, spi_buf + 11, 2);
- /* Major version: 8bits */
- memcpy(hid_buf + 18, spi_buf + 13, 1);
- /* Minor version: 8bits */
- memcpy(hid_buf + 19, spi_buf + 14, 1);
+ ret = get_hid_firmware_info(hid_buf);
+ if (!ret)
ret = rpt_info->size;
- }
+ else /* data is not ready yet */
+ ret = 0;
break;
case HID_REPORTID_GET_PROTOCOL:
hid_buf[2] = 2;
@@ -893,12 +1016,24 @@ int32_t nvt_extra_usi_init(void)
int32_t ret;
NVT_LOG("++\n");
+
+ usi_ctx = kzalloc(sizeof(*usi_ctx), GFP_KERNEL);
+ if (!usi_ctx)
+ return -ENOMEM;
+
ret = misc_register(&nvt_hid_usi_dev);
if (ret < 0) {
NVT_ERR("Register %s failed\n", nvt_hid_usi_dev.name);
- return ret;
+ goto usi_init_error;
}
NVT_LOG("--\n");
+
+ return ret;
+
+usi_init_error:
+ kfree(usi_ctx);
+ usi_ctx = NULL;
+
return ret;
}
@@ -906,6 +1041,8 @@ void nvt_extra_usi_deinit(void)
{
NVT_LOG("++\n");
misc_deregister(&nvt_hid_usi_dev);
+ kfree(usi_ctx);
+ usi_ctx = NULL;
NVT_LOG("--\n");
}
#endif
diff --git a/nt36xxx/nt36xxx_mem_map.h b/nt36xxx/nt36xxx_mem_map.h
index a80ff11..559e54f 100644
--- a/nt36xxx/nt36xxx_mem_map.h
+++ b/nt36xxx/nt36xxx_mem_map.h
@@ -73,6 +73,7 @@ struct nvt_ts_mem_map {
uint32_t DMA_CRC_EN_ADDR;
uint32_t BLD_ILM_DLM_CRC_ADDR;
uint32_t DMA_CRC_FLAG_ADDR;
+ uint32_t EB_INFO_ADDR;
};
struct nvt_ts_hw_info {
@@ -81,6 +82,7 @@ struct nvt_ts_hw_info {
static const struct nvt_ts_mem_map NT36523_memory_map = {
.EVENT_BUF_ADDR = 0x2FE00,
+ .EB_INFO_ADDR = 0x2B32A,
.RAW_PIPE0_ADDR = 0x30FA0,
.RAW_PIPE1_ADDR = 0x30FA0,
.BASELINE_ADDR = 0x36510,