input: touchscreen: stm: improve touch_offload support

Fully route pressure and major/minor size of touch points, apply
routed timestamps, and keep firmware grip closely synced with
touch_offload. Additional miscellaneous changes to support updated
touch_offload interface.

Bug: 167758661
Bug: 168076476
Signed-off-by: Steve Pfetsch <spfetsch@google.com>
Change-Id: I937357fe5f5b7fc3c63f255c17d27c231cd3d495
diff --git a/fts.c b/fts.c
index a601334..8ba47f8 100644
--- a/fts.c
+++ b/fts.c
@@ -3092,8 +3092,17 @@
 #if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
 	info->offload.coords[touchId].x = x;
 	info->offload.coords[touchId].y = y;
+	info->offload.coords[touchId].major = major;
+	info->offload.coords[touchId].minor = minor;
 	info->offload.coords[touchId].status = COORD_STATUS_FINGER;
 
+#ifndef SKIP_PRESSURE
+	info->offload.coords[touchId].pressure = z;
+#else
+	/* Select a reasonable constant pressure */
+	info->offload.coords[touchId].pressure = 0x30;
+#endif
+
 	if (!info->offload.offload_running) {
 #endif
 
@@ -4078,12 +4087,19 @@
 	return 0;
 }
 
-int fts_disable_grip(struct fts_ts_info *info)
+
+int fts_enable_grip(struct fts_ts_info *info, bool enable)
 {
-	uint8_t cmd[] = {0xC0, 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	static uint8_t enable_cmd[]  =
+		{0xC0, 0x03, 0x10, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00};
+	static uint8_t disable_cmd[] =
+		{0xC0, 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 	int res;
 
-	res = fts_write(cmd, sizeof(cmd));
+	if (enable)
+		res = fts_write(enable_cmd, sizeof(enable_cmd));
+	else
+		res = fts_write(disable_cmd, sizeof(disable_cmd));
 	if (res < 0)
 		pr_err("%s: fts_write failed with res=%d.\n", __func__,
 		       res);
@@ -4100,7 +4116,7 @@
 	struct fts_ts_info *info = container_of(dwork, struct fts_ts_info,
 						offload_resume_work);
 
-	fts_disable_grip(info);
+	fts_enable_grip(info, false);
 }
 
 static void fts_populate_coordinate_channel(struct fts_ts_info *info,
@@ -4112,11 +4128,15 @@
 	struct TouchOffloadDataCoord *dc =
 		(struct TouchOffloadDataCoord *)frame->channel_data[channel];
 	memset(dc, 0, frame->channel_data_size[channel]);
-	dc->size_bytes = TOUCH_OFFLOAD_FRAME_SIZE_COORD;
+	dc->header.channel_type = TOUCH_DATA_TYPE_COORD;
+	dc->header.channel_size = TOUCH_OFFLOAD_FRAME_SIZE_COORD;
 
 	for (j = 0; j < MAX_COORDS; j++) {
 		dc->coords[j].x = info->offload.coords[j].x;
 		dc->coords[j].y = info->offload.coords[j].y;
+		dc->coords[j].major = info->offload.coords[j].major;
+		dc->coords[j].minor = info->offload.coords[j].minor;
+		dc->coords[j].pressure = info->offload.coords[j].pressure;
 		dc->coords[j].status = info->offload.coords[j].status;
 	}
 }
@@ -4150,7 +4170,8 @@
 	}
 	mutual_strength->tx_size = getForceLen();
 	mutual_strength->rx_size = getSenseLen();
-	mutual_strength->size_bytes =
+	mutual_strength->header.channel_type = frame->channel_type[channel];
+	mutual_strength->header.channel_size =
 		TOUCH_OFFLOAD_FRAME_SIZE_2D(mutual_strength->rx_size,
 					    mutual_strength->tx_size);
 
@@ -4198,7 +4219,8 @@
 		(struct TouchOffloadData1d *)frame->channel_data[channel];
 	self_strength->tx_size = getForceLen();
 	self_strength->rx_size = getSenseLen();
-	self_strength->size_bytes =
+	self_strength->header.channel_type = frame->channel_type[channel];
+	self_strength->header.channel_size =
 		TOUCH_OFFLOAD_FRAME_SIZE_1D(self_strength->rx_size,
 					    self_strength->tx_size);
 
@@ -4247,6 +4269,20 @@
 	}
 }
 
+static void fts_offload_set_running(struct fts_ts_info *info, bool running)
+{
+	if (info->offload.offload_running != running) {
+		info->offload.offload_running = running;
+		if (running) {
+			pr_info("%s: disabling FW grip.\n", __func__);
+			fts_enable_grip(info, false);
+		} else {
+			pr_info("%s: enabling FW grip.\n", __func__);
+			fts_enable_grip(info, true);
+		}
+	}
+}
+
 #endif /* CONFIG_TOUCHSCREEN_OFFLOAD */
 
 /**
@@ -4331,22 +4367,25 @@
 #if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
 	}
 
-	error = touch_offload_reserve_frame(&info->offload, &frame);
-	if (error != 0) {
-		pr_debug("%s: Could not reserve a frame: error=%d.\n",
-			 __func__, error);
-
-		/* Consider a lack of buffers to be the feature stopping */
-		info->offload.offload_running = false;
-	} else {
-		info->offload.offload_running = true;
-
-		fts_populate_frame(info, frame);
-
-		error = touch_offload_queue_frame(&info->offload, frame);
+	if (processed_pointer_event) {
+		error = touch_offload_reserve_frame(&info->offload, &frame);
 		if (error != 0) {
-			pr_err("%s: Failed to queue reserved frame: error=%d.\n",
-			       __func__, error);
+			pr_debug("%s: Could not reserve a frame: error=%d.\n",
+				 __func__, error);
+
+			/* Stop offload when there are no buffers available */
+			fts_offload_set_running(info, false);
+		} else {
+			fts_offload_set_running(info, true);
+
+			fts_populate_frame(info, frame);
+
+			error = touch_offload_queue_frame(&info->offload,
+							  frame);
+			if (error != 0) {
+				pr_err("%s: Failed to queue reserved frame: error=%d.\n",
+				       __func__, error);
+			}
 		}
 	}
 #endif
@@ -4375,6 +4414,8 @@
 	bool touch_down = 0;
 	int i;
 
+	input_set_timestamp(info->input_dev, report->timestamp);
+
 	for (i = 0; i < MAX_COORDS; i++) {
 		if (report->coords[i].status == COORD_STATUS_FINGER) {
 			input_mt_slot(info->input_dev, i);
@@ -4387,10 +4428,14 @@
 					 report->coords[i].x);
 			input_report_abs(info->input_dev, ABS_MT_POSITION_Y,
 					 report->coords[i].y);
+			input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR,
+					 report->coords[i].major);
+			input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR,
+					 report->coords[i].minor);
 
 #ifndef SKIP_PRESSURE
 			input_report_abs(info->input_dev, ABS_MT_PRESSURE,
-					 0x30);
+					 report->coords[i].pressure);
 #endif
 		} else {
 			input_mt_slot(info->input_dev, i);
@@ -4890,7 +4935,9 @@
 	struct fts_ts_info *info = handle;
 
 	info->timestamp = ktime_get();
+#if !IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
 	input_set_timestamp(info->input_dev, info->timestamp);
+#endif
 
 	return IRQ_WAKE_THREAD;
 }
@@ -6296,6 +6343,13 @@
 #endif
 
 #if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+	info->offload.caps.touch_offload_major_version = 1;
+	info->offload.caps.touch_offload_minor_version = 0;
+	/* ID equivalent to the 4-byte, little-endian string: '00b5' */
+	info->offload.caps.device_id =
+	    '5' << 24 | 'b' << 16 | '0' << 8 | '0' << 0;
+	info->offload.caps.display_width = info->board->x_axis_max;
+	info->offload.caps.display_height = info->board->y_axis_max;
 	info->offload.caps.tx_size = getForceLen();
 	info->offload.caps.rx_size = getSenseLen();
 	info->offload.caps.bus_type = BUS_TYPE_SPI;