diff options
author | Mark Chang <changmark@google.com> | 2021-04-01 15:29:19 +0800 |
---|---|---|
committer | Mark Chang <changmark@google.com> | 2021-04-06 13:51:12 +0800 |
commit | aa71ff13976a3ac8aa3e30887cb28433880f475d (patch) | |
tree | 56fe1a683667634954247a04d3de872c91ce5421 | |
parent | b14f9d30fb76bf1e6ade5cbd49950dbc0a4ee088 (diff) | |
download | sec_touch-aa71ff13976a3ac8aa3e30887cb28433880f475d.tar.gz |
touch/sec: support encoded heatmap in custom library.
Bug: 182246865
Test: Verified encoded heatmap with locally built ROM.
Signed-off-by: Mark Chang <changmark@google.com>
Change-Id: I97132cad3ea1486d0bfc4974284caa03f163355d
-rw-r--r-- | sec_ts.c | 235 | ||||
-rw-r--r-- | sec_ts.h | 7 | ||||
-rw-r--r-- | sec_ts_fn.c | 50 |
3 files changed, 288 insertions, 4 deletions
@@ -1103,6 +1103,118 @@ int sec_ts_read_calibration_report(struct sec_ts_data *ts) return ts->cali_report_status; } +#define PTFLIB_ENCODED_ENABLED_OFFSET_LSB 0xA0 +#define PTFLIB_ENCODED_ENABLED_OFFSET_MSB 0x00 +#define PTFLIB_ENCODED_ENABLED_TRUE 0x01 +#define PTFLIB_ENCODED_ENABLED_FALSE 0x00 +static int sec_ts_ptflib_reinit(struct sec_ts_data *ts) +{ + u8 r_data[2] = {0x00, 0x00}; + u8 w_data[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + int ret = 0; + + /* Check whether encoded heatmap is inited in custom library. */ + r_data[0] = PTFLIB_ENCODED_ENABLED_OFFSET_LSB; + r_data[1] = PTFLIB_ENCODED_ENABLED_OFFSET_MSB; + ret = sec_ts_read_from_customlib(ts, r_data, 2); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: Read encoded heatmap's inited failed.\n", + __func__); + return -EIO; + } + + if (r_data[1] != 0x01) { + input_err(true, &ts->client->dev, + "%s: Encoded heatmap was not initialized.\n", + __func__); + return -EIO; + } + + /* Return if encoded heatmap is already enabled. */ + if (r_data[0] == 0x01) { + input_info(true, &ts->client->dev, + "%s: Encoded heatmap is already enabled.\n", + __func__); + return 0; + } + + /* Enable encoded heatmap. */ + w_data[0] = PTFLIB_ENCODED_ENABLED_OFFSET_LSB; + w_data[1] = PTFLIB_ENCODED_ENABLED_OFFSET_MSB; + w_data[2] = PTFLIB_ENCODED_ENABLED_TRUE; + ret = sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM, w_data, 3); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: ptlib - Writing encoded heatmap's enabled register failed.\n", + __func__); + return -EIO; + } + + /* Check whether encoded heatmap is enabled in customlib. */ + r_data[0] = PTFLIB_ENCODED_ENABLED_OFFSET_LSB; + r_data[1] = PTFLIB_ENCODED_ENABLED_OFFSET_MSB; + ret = sec_ts_read_from_customlib(ts, r_data, 2); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: ptlib - Read encoded heatmap's enabled status failed.\n", + __func__); + return -EIO; + } + + if (r_data[0] != PTFLIB_ENCODED_ENABLED_TRUE) { + input_err(true, &ts->client->dev, + "%s: ptlib - Enabling encoded heatmap failed.\n", + __func__); + return -EIO; + } + + return 0; +} + +static int sec_ts_ptflib_rle_decoder(struct sec_ts_data *ts, + const u16 *in_array, + const int in_array_size, u16 *out_array, + const int out_array_max_size) +{ + const u16 ESCAPE_MASK = 0xF000; + const u16 ESCAPE_BIT = 0x8000; + + int i; + int j; + int out_array_size = 0; + u16 prev_word = 0; + + for (i = 0; i < in_array_size; i++) { + u16 curr_word = in_array[i]; + if ((curr_word & ESCAPE_MASK) == ESCAPE_BIT) { + u16 repetition = (curr_word & ~ESCAPE_MASK) - 1; + if (out_array_size + repetition > out_array_max_size) { + input_err(true, &ts->client->dev, + "%s: decoding failed at %d.\n", + __func__, i); + return -1; + } + for (j = 0; j < repetition; j++) { + *out_array++ = prev_word; + out_array_size++; + } + } else { + if (out_array_size + 1 > out_array_max_size) { + input_err(true, &ts->client->dev, + "%s: decoding failed at %d.\n", + __func__, i); + return -1; + } + *out_array++ = curr_word; + out_array_size++; + prev_word = curr_word; + } + } + + return out_array_size; +} + static void sec_ts_reinit(struct sec_ts_data *ts) { u8 w_data[2] = {0x00, 0x00}; @@ -1965,6 +2077,102 @@ static void sec_ts_populate_coordinate_channel(struct sec_ts_data *ts, } } +#define PTFLIB_ENCODED_COUNTER_OFFSET_LSB 0xA8 +#define PTFLIB_ENCODED_COUNTER_OFFSET_MSB 0x00 +#define PTFLIB_ENCODED_DATA_OFFSET_LSB 0xAE +#define PTFLIB_ENCODED_DATA_OFFSET_MSB 0x00 +static int sec_ts_populate_encoded_channel(struct sec_ts_data *ts, + struct touch_offload_frame *frame, + int channel) +{ + u32 heatmap_array_len = 0; + u32 decoded_size = 0; + u32 encoded_counter = 0; + u8 r_data[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + u16 encoded_data_size = 0; + int i; + int x; + int y; + int ret = 0; + struct TouchOffloadData2d *mutual_strength = + (struct TouchOffloadData2d *)frame->channel_data[channel]; + + mutual_strength->tx_size = ts->tx_count; + mutual_strength->rx_size = ts->rx_count; + 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); + + r_data[0] = PTFLIB_ENCODED_COUNTER_OFFSET_LSB; + r_data[1] = PTFLIB_ENCODED_COUNTER_OFFSET_MSB; + ret = sec_ts_read_from_customlib(ts, r_data, sizeof(r_data)); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: Read customlib's data size failed\n", + __func__); + return -EIO; + } + + heatmap_array_len = mutual_strength->tx_size * mutual_strength->rx_size; + encoded_counter = le32_to_cpup((uint32_t *) r_data); + encoded_data_size = le16_to_cpup((uint16_t *) &r_data[4]); + + if (encoded_counter == 0 || encoded_data_size == 0 || + encoded_data_size > heatmap_array_len * 2) { + input_err(true, &ts->client->dev, + "%s: Invalid encoded data size %d (%d)\n", + __func__, encoded_data_size, encoded_counter); + return -EIO; + } + + if (!ts->encoded_buff) { + ts->encoded_buff = kmalloc(heatmap_array_len * 2, GFP_KERNEL); + if (!ts->encoded_buff) { + input_err(true, &ts->client->dev, + "%s: kmalloc for encoded_buff failed.\n", + __func__); + return -ENOMEM; + } else { + input_info(true, &ts->client->dev, + "%s: kmalloc for encoded_buff was successful.\n", + __func__); + } + } + + /* Read encoded heatmap from customlib. */ + *((u8 *) ts->encoded_buff) = PTFLIB_ENCODED_DATA_OFFSET_LSB; + *(((u8 *) ts->encoded_buff) + 1) = PTFLIB_ENCODED_DATA_OFFSET_MSB; + ret = sec_ts_read_from_customlib(ts, (u8 *) ts->encoded_buff, + encoded_data_size); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: Read encoded data (size=%d) failed.\n", + __func__, encoded_data_size); + return -EIO; + } + + decoded_size = sec_ts_ptflib_rle_decoder( + ts, (u16 *) ts->encoded_buff, encoded_data_size / 2, + (u16 *) ts->heatmap_buff, heatmap_array_len); + if (decoded_size != heatmap_array_len) { + input_info(true, &ts->client->dev, + "%s: Decoding data failed (decoded_size=%d).", + __func__, decoded_size); + return -EIO; + } + + i = 0; + for (y = mutual_strength->rx_size - 1; y >= 0; y--) { + for (x = mutual_strength->tx_size - 1; x >= 0; x--) { + ((uint16_t *) mutual_strength->data)[i++] = + ts->heatmap_buff[x * mutual_strength->rx_size + y]; + } + } + + return 0; +} + static void sec_ts_populate_mutual_channel(struct sec_ts_data *ts, struct touch_offload_frame *frame, int channel) @@ -2179,6 +2387,8 @@ static void sec_ts_populate_frame(struct sec_ts_data *ts, { static u64 index; int i; + int retval = -1; + const struct sec_ts_plat_data *pdata = ts->plat_data; frame->header.index = index++; frame->header.timestamp = ts->timestamp; @@ -2190,12 +2400,21 @@ static void sec_ts_populate_frame(struct sec_ts_data *ts, /* Populate all channels */ for (i = 0; i < frame->num_channels; i++) { - if (frame->channel_type[i] == TOUCH_DATA_TYPE_COORD) + u8 channel_type = frame->channel_type[i]; + + if (channel_type == TOUCH_DATA_TYPE_COORD) { sec_ts_populate_coordinate_channel(ts, frame, i); - else if ((frame->channel_type[i] & TOUCH_SCAN_TYPE_MUTUAL) != 0) - sec_ts_populate_mutual_channel(ts, frame, i); - else if ((frame->channel_type[i] & TOUCH_SCAN_TYPE_SELF) != 0) + } else if ((channel_type & TOUCH_SCAN_TYPE_MUTUAL) != 0) { + if ((pdata->encoded_enable == ENCODED_ENABLE_ON) && + ((channel_type & ~TOUCH_SCAN_TYPE_MUTUAL) == + TOUCH_DATA_TYPE_STRENGTH)) + retval = sec_ts_populate_encoded_channel( + ts, frame, i); + if (retval < 0) + sec_ts_populate_mutual_channel(ts, frame, i); + } else if ((channel_type & TOUCH_SCAN_TYPE_SELF) != 0) { sec_ts_populate_self_channel(ts, frame, i); + } } } @@ -2224,6 +2443,9 @@ int sec_ts_enable_grip(struct sec_ts_data *ts, bool enable) final_result = ret; } + if (!enable) + sec_ts_ptflib_reinit(ts); + return final_result; } @@ -3270,6 +3492,10 @@ static int sec_ts_parse_dt(struct spi_device *client) &pdata->mis_cal_check) < 0) pdata->mis_cal_check = 0; + if (of_property_read_u32(np, "sec,encoded_enable", + &pdata->encoded_enable) < 0) + pdata->encoded_enable = 0; + if (of_property_read_u32(np, "sec,heatmap_mode", &pdata->heatmap_mode) < 0) pdata->heatmap_mode = 0; @@ -4621,6 +4847,7 @@ static int sec_ts_remove(struct spi_device *client) #if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP) kfree(ts->heatmap_buff); + kfree(ts->encoded_buff); #endif #ifdef USE_STIM_PAD kfree(ts->gainTable); @@ -650,6 +650,11 @@ enum { HEATMAP_FULL = 2 }; +enum { + ENCODED_ENABLE_OFF = 0, + ENCODED_ENABLE_ON = 1 +}; + /* Motion filter finite state machine (FSM) states * SEC_TS_MF_FILTERED - default coordinate filtering * SEC_TS_MF_UNFILTERED - unfiltered single-touch coordinates @@ -914,6 +919,7 @@ struct sec_ts_data { #if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP) struct v4l2_heatmap v4l2; strength_t *heatmap_buff; + strength_t *encoded_buff; #endif #if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD) @@ -1104,6 +1110,7 @@ struct sec_ts_plat_data { int bringup; int mis_cal_check; int heatmap_mode; + int encoded_enable; #ifdef PAT_CONTROL int pat_function; int afe_base; diff --git a/sec_ts_fn.c b/sec_ts_fn.c index fa63c1f..8c3cc69 100644 --- a/sec_ts_fn.c +++ b/sec_ts_fn.c @@ -1052,6 +1052,54 @@ static ssize_t heatmap_mode_show(struct device *dev, #endif } +/* sysfs file node to store encoded_enable control + * "echo cmd > encoded_enable" to change + * Possible commands: + * 0 = ENCODED_ENABLE_OFF + * 1 = ENCODED_ENABLE_ON + */ +static ssize_t encoded_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP) + struct sec_cmd_data *sec = dev_get_drvdata(dev); + struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec); + struct sec_ts_plat_data *pdata = ts->plat_data; + int result; + int val; + + result = kstrtoint(buf, 10, &val); + if (result < 0 || val < ENCODED_ENABLE_OFF || + val > ENCODED_ENABLE_ON) { + input_err(true, &ts->client->dev, + "%s: Invalid input.\n", __func__); + return -EINVAL; + } + pdata->encoded_enable = val; + + return count; +#else + return 0; +#endif +} + +static ssize_t encoded_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ +#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP) + struct sec_cmd_data *sec = dev_get_drvdata(dev); + struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec); + const struct sec_ts_plat_data *pdata = ts->plat_data; + + return scnprintf(buf, PAGE_SIZE, "%d\n", pdata->encoded_enable); +#else + return scnprintf(buf, PAGE_SIZE, "N/A\n"); +#endif +} + + /* sysfs file node to dump heatmap * "echo cmd > heatmap_dump" to change * Possible commands: @@ -1256,6 +1304,7 @@ static DEVICE_ATTR_RW(pressure_enable); static DEVICE_ATTR_RO(get_lp_dump); static DEVICE_ATTR_RO(force_recal_count); static DEVICE_ATTR_RW(heatmap_mode); +static DEVICE_ATTR_RW(encoded_enable); static DEVICE_ATTR_RW(heatmap_dump); static DEVICE_ATTR_RO(fw_version); static DEVICE_ATTR_RO(status); @@ -1278,6 +1327,7 @@ static struct attribute *cmd_attributes[] = { &dev_attr_get_lp_dump.attr, &dev_attr_force_recal_count.attr, &dev_attr_heatmap_mode.attr, + &dev_attr_encoded_enable.attr, &dev_attr_heatmap_dump.attr, &dev_attr_fw_version.attr, &dev_attr_status.attr, |