diff options
-rw-r--r-- | fts.c | 298 | ||||
-rw-r--r-- | fts.h | 6 | ||||
-rw-r--r-- | fts_lib/ftsFrame.c | 6 |
3 files changed, 293 insertions, 17 deletions
@@ -58,6 +58,8 @@ #include <linux/input/mt.h> #endif +#include <linux/input/touch_offload.h> + #include <drm/drm_panel.h> #include <video/display_timing.h> @@ -3023,7 +3025,6 @@ static bool fts_enter_pointer_event_handler(struct fts_ts_info *info, unsigned if (y > info->board->y_axis_max) y = info->board->y_axis_max; - input_mt_slot(info->input_dev, touchId); switch (touchType) { #ifdef STYLUS_MODE case TOUCH_TYPE_STYLUS: @@ -3083,12 +3084,19 @@ static bool fts_enter_pointer_event_handler(struct fts_ts_info *info, unsigned goto no_report; } - input_report_key(info->input_dev, BTN_TOUCH, touch_condition); - input_mt_report_slot_state(info->input_dev, tool, 1); - /* pr_info("%s : TouchID = %d,Touchcount = %d\n", __func__, - * touchId,touchcount); */ +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + info->offload.coords[touchId].x = x; + info->offload.coords[touchId].y = y; + info->offload.coords[touchId].status = COORD_STATUS_FINGER; + + if (!info->offload.offload_running) { +#endif + + input_mt_slot(info->input_dev, touchId); + input_report_key(info->input_dev, BTN_TOUCH, touch_condition); + input_mt_report_slot_state(info->input_dev, tool, 1); input_report_abs(info->input_dev, ABS_MT_POSITION_X, x); input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y); input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, major); @@ -3100,6 +3108,10 @@ static bool fts_enter_pointer_event_handler(struct fts_ts_info *info, unsigned #ifndef SKIP_DISTANCE input_report_abs(info->input_dev, ABS_MT_DISTANCE, distance); #endif + +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + } +#endif /* pr_info("%s : Event 0x%02x - ID[%d], (x, y) = (%3d, %3d) * Size = %d\n", * __func__, *event, touchId, x, y, touchType); */ @@ -3123,9 +3135,6 @@ static bool fts_leave_pointer_event_handler(struct fts_ts_info *info, unsigned touchType = event[1] & 0x0F; touchId = (event[1] & 0xF0) >> 4; - input_mt_slot(info->input_dev, touchId); - - input_report_abs(info->input_dev, ABS_MT_PRESSURE, 0); switch (touchType) { #ifdef STYLUS_MODE case TOUCH_TYPE_STYLUS: @@ -3160,15 +3169,20 @@ static bool fts_leave_pointer_event_handler(struct fts_ts_info *info, unsigned return false; } - input_mt_report_slot_state(info->input_dev, tool, 0); +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + info->offload.coords[touchId].status = COORD_STATUS_INACTIVE; + if (!info->offload.offload_running) { +#endif - /* pr_info("%s : TouchID = %d, Touchcount = %d\n", __func__, - * touchId,touchcount); */ + input_mt_slot(info->input_dev, touchId); + input_report_abs(info->input_dev, ABS_MT_PRESSURE, 0); + input_mt_report_slot_state(info->input_dev, tool, 0); + input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, -1); +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + } +#endif - input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, -1); - /* pr_info("%s : Event 0x%02x - release ID[%d]\n", __func__, - * event[0], touchId); */ return true; } @@ -4061,6 +4075,154 @@ static int update_motion_filter(struct fts_ts_info *info) return 0; } +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + +static void fts_populate_coordinate_channel(struct fts_ts_info *info, + struct touch_offload_frame *frame, + int channel) +{ + int j; + + 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; + + 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].status = info->offload.coords[j].status; + } +} + +static void fts_populate_mutual_channel(struct fts_ts_info *info, + struct touch_offload_frame *frame, + int channel) +{ + MutualSenseFrame ms_frame = { 0 }; + uint32_t frame_index = 0, x, y; + uint32_t x_val, y_val; + uint16_t heatmap_value; + int result; + uint32_t data_type = 0; + struct TouchOffloadData2d *mutual_strength = + (struct TouchOffloadData2d *)frame->channel_data[channel]; + + switch (frame->channel_type[channel] & ~TOUCH_SCAN_TYPE_MUTUAL) { + case TOUCH_DATA_TYPE_RAW: + data_type = MS_RAW; + break; + case TOUCH_DATA_TYPE_FILTERED: + data_type = MS_FILTER; + break; + case TOUCH_DATA_TYPE_STRENGTH: + data_type = MS_STRENGTH; + break; + case TOUCH_DATA_TYPE_BASELINE: + data_type = MS_BASELINE; + break; + } + mutual_strength->tx_size = getForceLen(); + mutual_strength->rx_size = getSenseLen(); + mutual_strength->size_bytes = + TOUCH_OFFLOAD_FRAME_SIZE_2D(mutual_strength->rx_size, + mutual_strength->tx_size); + + result = getMSFrame3(data_type, &ms_frame); + if (result <= 0) { + pr_err("getMSFrame3 failed with result=0x%08X.\n", result); + } else { + uint32_t max_x = mutual_strength->tx_size; + uint32_t max_y = mutual_strength->rx_size; + + for (y = 0; y < mutual_strength->rx_size; y++) { + for (x = 0; x < mutual_strength->tx_size; x++) { + /* Rotate frame counter-clockwise and invert + * if necessary. + */ + if (info->board->sensor_inverted_x) + x_val = (max_x - 1) - x; + else + x_val = x; + if (info->board->sensor_inverted_y) + y_val = (max_y - 1) - y; + else + y_val = y; + + heatmap_value = + ms_frame.node_data[ + x_val * max_y + y_val]; + + ((uint16_t *) + mutual_strength->data)[frame_index++] = + heatmap_value; + } + } + } +} + +static void fts_populate_self_channel(struct fts_ts_info *info, + struct touch_offload_frame *frame, + int channel) +{ + SelfSenseFrame ss_frame = { 0 }; + int result; + uint32_t data_type = 0; + struct TouchOffloadData1d *self_strength = + (struct TouchOffloadData1d *)frame->channel_data[channel]; + self_strength->tx_size = getForceLen(); + self_strength->rx_size = getSenseLen(); + self_strength->size_bytes = + TOUCH_OFFLOAD_FRAME_SIZE_1D(self_strength->rx_size, + self_strength->tx_size); + + switch (frame->channel_type[channel] & ~TOUCH_SCAN_TYPE_SELF) { + case TOUCH_DATA_TYPE_RAW: + data_type = SS_RAW; + break; + case TOUCH_DATA_TYPE_FILTERED: + data_type = SS_FILTER; + break; + case TOUCH_DATA_TYPE_STRENGTH: + data_type = SS_STRENGTH; + break; + case TOUCH_DATA_TYPE_BASELINE: + data_type = SS_BASELINE; + break; + } + result = getSSFrame3(data_type, &ss_frame); + if (result <= 0) { + pr_err("getSSFrame3 failed with result=0x%08X.\n", result); + } else { + memcpy(self_strength->data, ss_frame.force_data, + 2 * self_strength->tx_size); + memcpy(&self_strength->data[2 * self_strength->tx_size], + ss_frame.sense_data, 2 * self_strength->rx_size); + } +} + +static void fts_populate_frame(struct fts_ts_info *info, + struct touch_offload_frame *frame) +{ + static u64 index; + int i; + + frame->header.index = index++; + frame->header.timestamp = info->timestamp; + + /* Populate all channels */ + for (i = 0; i < frame->num_channels; i++) { + if (frame->channel_type[i] == TOUCH_DATA_TYPE_COORD) + fts_populate_coordinate_channel(info, frame, i); + else if ((frame->channel_type[i] & TOUCH_SCAN_TYPE_MUTUAL) != 0) + fts_populate_mutual_channel(info, frame, i); + else if ((frame->channel_type[i] & TOUCH_SCAN_TYPE_SELF) != 0) + fts_populate_self_channel(info, frame, i); + } +} + +#endif /* CONFIG_TOUCHSCREEN_OFFLOAD */ + /** * Bottom Half Interrupt Handler function * This handler is called each time there is at least one new event in the FIFO @@ -4081,6 +4243,10 @@ static irqreturn_t fts_interrupt_handler(int irq, void *handle) unsigned char *evt_data; bool processed_pointer_event = false; +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + struct touch_offload_frame *frame = NULL; +#endif + /* It is possible that interrupts were disabled while the handler is * executing, before acquiring the mutex. If so, simply return. */ @@ -4127,11 +4293,41 @@ static irqreturn_t fts_interrupt_handler(int irq, void *handle) } } +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + if (!info->offload.offload_running) { +#endif + if (info->touch_id == 0) input_report_key(info->input_dev, BTN_TOUCH, 0); input_sync(info->input_dev); +#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 (error != 0) { + pr_err("%s: Failed to queue reserved frame: error=%d.\n", + __func__, error); + } + } +#endif + + /* TODO(spfetsch): if the mutual strength heatmap was already read into + * the touch offload interface, use it here instead of reading again. + */ #ifdef TOUCHSCREEN_HEATMAP if (processed_pointer_event) heatmap_read(&info->v4l2, ktime_to_ns(info->timestamp)); @@ -4145,6 +4341,47 @@ static irqreturn_t fts_interrupt_handler(int irq, void *handle) return IRQ_HANDLED; } +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) +static void fts_offload_report(void *handle, + struct TouchOffloadIocReport *report) +{ + struct fts_ts_info *info = (struct fts_ts_info *)handle; + bool touch_down = 0; + int i; + + for (i = 0; i < MAX_COORDS; i++) { + if (report->coords[i].status == COORD_STATUS_FINGER) { + input_mt_slot(info->input_dev, i); + touch_down = 1; + input_report_key(info->input_dev, BTN_TOUCH, + touch_down); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, 1); + input_report_abs(info->input_dev, ABS_MT_POSITION_X, + report->coords[i].x); + input_report_abs(info->input_dev, ABS_MT_POSITION_Y, + report->coords[i].y); + +#ifndef SKIP_PRESSURE + input_report_abs(info->input_dev, ABS_MT_PRESSURE, + 0x30); +#endif + } else { + input_mt_slot(info->input_dev, i); + input_report_abs(info->input_dev, ABS_MT_PRESSURE, 0); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, 0); + input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, + -1); + } + } + + input_report_key(info->input_dev, BTN_TOUCH, touch_down); + + input_sync(info->input_dev); +} +#endif /* CONFIG_TOUCHSCREEN_OFFLOAD */ + /* * Read the display panel's extinfo from the display driver. * @@ -6019,6 +6256,31 @@ static int fts_probe(struct spi_device *client) goto ProbeErrorExit_6; #endif +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + info->offload.caps.tx_size = getForceLen(); + info->offload.caps.rx_size = getSenseLen(); + info->offload.caps.bus_type = BUS_TYPE_SPI; + info->offload.caps.bus_speed_hz = 10000000; + info->offload.caps.heatmap_size = HEATMAP_SIZE_FULL; + info->offload.caps.touch_data_types = + TOUCH_DATA_TYPE_COORD | TOUCH_DATA_TYPE_RAW | + TOUCH_DATA_TYPE_STRENGTH | TOUCH_DATA_TYPE_FILTERED | + TOUCH_DATA_TYPE_BASELINE; + info->offload.caps.touch_scan_types = + TOUCH_SCAN_TYPE_MUTUAL | TOUCH_SCAN_TYPE_SELF; + info->offload.caps.continuous_reporting = true; + info->offload.caps.noise_reporting = false; + info->offload.caps.cancel_reporting = false; + info->offload.caps.size_reporting = true; + info->offload.caps.filter_grip = true; + info->offload.caps.filter_palm = true; + info->offload.caps.num_sensitivity_settings = 1; + + info->offload.hcallback = (void *)info; + info->offload.report_cb = fts_offload_report; + touch_offload_init(&info->offload); +#endif + #if defined(FW_UPDATE_ON_PROBE) && defined(FW_H_FILE) pr_info("FW Update and Sensing Initialization:\n"); error = fts_fw_update(info); @@ -6081,6 +6343,10 @@ ProbeErrorExit_7: drm_panel_notifier_unregister(info->board->panel, &info->notifier); #endif +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + touch_offload_cleanup(&info->offload); +#endif + #ifdef TOUCHSCREEN_HEATMAP heatmap_remove(&info->v4l2); #endif @@ -6150,6 +6416,10 @@ static int fts_remove(struct spi_device *client) /* remove interrupt and event handlers */ fts_interrupt_uninstall(info); +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + touch_offload_cleanup(&info->offload); +#endif + #ifdef TOUCHSCREEN_HEATMAP heatmap_remove(&info->v4l2); #endif @@ -39,6 +39,7 @@ #include <linux/input/heatmap.h> #endif #include <linux/pm_qos.h> +#include <linux/input/touch_offload.h> #include <drm/drm_panel.h> #include "fts_lib/ftsSoftware.h" #include "fts_lib/ftsHardware.h" @@ -416,6 +417,11 @@ struct fts_ts_info { #ifdef TOUCHSCREEN_HEATMAP struct v4l2_heatmap v4l2; #endif + +#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) + struct touch_offload_context offload; +#endif + struct delayed_work fwu_work; /* Work for fw update */ struct workqueue_struct *fwu_workqueue; /* Fw update work queue */ event_dispatch_handler_t *event_dispatch_table; /* Dispatch table */ diff --git a/fts_lib/ftsFrame.c b/fts_lib/ftsFrame.c index b79f498..7ea3778 100644 --- a/fts_lib/ftsFrame.c +++ b/fts_lib/ftsFrame.c @@ -288,7 +288,7 @@ int getSSFrame3(SSFrameType type, SelfSenseFrame *frame) } - pr_info("%s: Starting to get frame %02X\n", __func__, type); + pr_debug("%s: Starting to get frame %02X\n", __func__, type); switch (type) { case SS_RAW: offset_force = systemInfo.u16_ssTchTxRawAddr; @@ -396,7 +396,7 @@ int getSSFrame3(SSFrameType type, SelfSenseFrame *frame) frame->header.type = type; - pr_info("%s: Force_len = %d Sense_len = %d Offset_force = %04X Offset_sense = %04X\n", + pr_debug("%s: Force_len = %d Sense_len = %d Offset_force = %04X Offset_sense = %04X\n", __func__, frame->header.force_node, frame->header.sense_node, offset_force, offset_sense); @@ -445,7 +445,7 @@ int getSSFrame3(SSFrameType type, SelfSenseFrame *frame) /* if you want to access one node i,j, * the offset like: offset = i*columns + j = > frame[i, j] */ - pr_info("Frame acquired!\n"); + pr_debug("Frame acquired!\n"); return frame->header.force_node + frame->header.sense_node; /* return the number of data put inside frame */ } |