aboutsummaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/synaptics_dsx_test_reporting.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/synaptics_dsx_test_reporting.c')
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_test_reporting.c5070
1 files changed, 5070 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/synaptics_dsx_test_reporting.c b/drivers/input/touchscreen/synaptics_dsx_test_reporting.c
new file mode 100644
index 00000000..52e34afb
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_dsx_test_reporting.c
@@ -0,0 +1,5070 @@
+/*
+ * Synaptics DSX touchscreen driver
+ *
+ * Copyright (C) 2012 Synaptics Incorporated
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/ctype.h>
+#include <linux/hrtimer.h>
+#include <linux/wakelock.h>
+#include <linux/input/synaptics_rmi_dsx.h>
+#include "synaptics_dsx_i2c.h"
+
+#define WATCHDOG_HRTIMER
+#define WATCHDOG_TIMEOUT_S 1
+#define STATUS_WORK_INTERVAL 20 /* ms */
+
+/*
+#define RAW_HEX
+#define HUMAN_READABLE
+*/
+
+#define STATUS_IDLE 0
+#define STATUS_BUSY 1
+
+#define DATA_REPORT_INDEX_OFFSET 1
+#define DATA_REPORT_DATA_OFFSET 3
+
+#define COMMAND_GET_REPORT 1
+#define COMMAND_FORCE_CAL 2
+#define COMMAND_FORCE_UPDATE 4
+#define COMMAND_ENTER_IN_CELL_TESTMODE 16
+
+#define HIGH_RESISTANCE_DATA_SIZE 6
+#define FULL_RAW_CAP_MIN_MAX_DATA_SIZE 4
+#define TREX_DATA_SIZE 7
+
+#define NO_AUTO_CAL_MASK 0x01
+
+#define concat(a, b) a##b
+
+#define GROUP(_attrs) {\
+ .attrs = _attrs,\
+}
+
+#define attrify(propname) (&dev_attr_##propname.attr)
+
+#define show_prototype_ext(propname, perm)\
+static ssize_t concat(synaptics_rmi4_f54, _##propname##_show)(\
+ struct device *dev,\
+ struct device_attribute *attr,\
+ char *buf);\
+\
+struct device_attribute dev_attr_##propname =\
+ __ATTR(propname, (perm),\
+ concat(synaptics_rmi4_f54, _##propname##_show),\
+ synaptics_rmi4_store_error);
+
+#define show_prototype(propname)\
+ show_prototype_ext(propname, S_IRUSR | S_IRGRP | S_IROTH)
+
+#define store_prototype(propname)\
+static ssize_t concat(synaptics_rmi4_f54, _##propname##_store)(\
+ struct device *dev,\
+ struct device_attribute *attr,\
+ const char *buf, size_t count);\
+\
+struct device_attribute dev_attr_##propname =\
+ __ATTR(propname, S_IWUSR | S_IWGRP,\
+ synaptics_rmi4_show_error,\
+ concat(synaptics_rmi4_f54, _##propname##_store));
+
+#define show_store_prototype_ext(propname, perm)\
+static ssize_t concat(synaptics_rmi4_f54, _##propname##_show)(\
+ struct device *dev,\
+ struct device_attribute *attr,\
+ char *buf);\
+\
+static ssize_t concat(synaptics_rmi4_f54, _##propname##_store)(\
+ struct device *dev,\
+ struct device_attribute *attr,\
+ const char *buf, size_t count);\
+\
+struct device_attribute dev_attr_##propname =\
+ __ATTR(propname, (perm),\
+ concat(synaptics_rmi4_f54, _##propname##_show),\
+ concat(synaptics_rmi4_f54, _##propname##_store));
+
+#define show_store_prototype(propname)\
+ show_store_prototype_ext(propname, \
+ S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP)
+
+#define simple_show_func(rtype, propname, fmt)\
+static ssize_t concat(synaptics_rmi4_f54, _##propname##_show)(\
+ struct device *dev,\
+ struct device_attribute *attr,\
+ char *buf)\
+{\
+ return snprintf(buf, PAGE_SIZE, fmt, f54->rtype.propname);\
+} \
+
+#define simple_show_func_unsigned(rtype, propname)\
+simple_show_func(rtype, propname, "%u\n")
+
+#define show_func(rtype, rgrp, propname, fmt)\
+static ssize_t concat(synaptics_rmi4_f54, _##propname##_show)(\
+ struct device *dev,\
+ struct device_attribute *attr,\
+ char *buf)\
+{\
+ int retval;\
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;\
+\
+ mutex_lock(&f54->rtype##_mutex);\
+\
+ retval = f54->fn_ptr->read(rmi4_data,\
+ f54->rtype.rgrp->address,\
+ f54->rtype.rgrp->data,\
+ sizeof(f54->rtype.rgrp->data));\
+ mutex_unlock(&f54->rtype##_mutex);\
+ if (retval < 0) {\
+ dev_err(&rmi4_data->i2c_client->dev,\
+ "%s: Failed to read " #rtype\
+ " " #rgrp "\n",\
+ __func__);\
+ return retval;\
+ } \
+\
+ return snprintf(buf, PAGE_SIZE, fmt,\
+ f54->rtype.rgrp->propname);\
+} \
+
+#define show_func_unsigned(rtype, rgrp, propname)\
+show_func(rtype, rgrp, propname, "%u\n")
+
+#define show_store_func(rtype, rgrp, propname, fmt)\
+show_func(rtype, rgrp, propname, fmt)\
+\
+static ssize_t concat(synaptics_rmi4_f54, _##propname##_store)(\
+ struct device *dev,\
+ struct device_attribute *attr,\
+ const char *buf, size_t count)\
+{\
+ int retval;\
+ unsigned long setting;\
+ unsigned long o_setting;\
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;\
+\
+ retval = sstrtoul(buf, 10, &setting);\
+ if (retval)\
+ return retval;\
+\
+ mutex_lock(&f54->rtype##_mutex);\
+ retval = f54->fn_ptr->read(rmi4_data,\
+ f54->rtype.rgrp->address,\
+ f54->rtype.rgrp->data,\
+ sizeof(f54->rtype.rgrp->data));\
+ if (retval < 0) {\
+ mutex_unlock(&f54->rtype##_mutex);\
+ dev_err(&rmi4_data->i2c_client->dev,\
+ "%s: Failed to read " #rtype\
+ " " #rgrp "\n",\
+ __func__);\
+ return retval;\
+ } \
+\
+ if (f54->rtype.rgrp->propname == setting) {\
+ mutex_unlock(&f54->rtype##_mutex);\
+ return count;\
+ } \
+\
+ o_setting = f54->rtype.rgrp->propname;\
+ f54->rtype.rgrp->propname = setting;\
+\
+ retval = f54->fn_ptr->write(rmi4_data,\
+ f54->rtype.rgrp->address,\
+ f54->rtype.rgrp->data,\
+ sizeof(f54->rtype.rgrp->data));\
+ if (retval < 0) {\
+ dev_err(&rmi4_data->i2c_client->dev,\
+ "%s: Failed to write " #rtype\
+ " " #rgrp "\n",\
+ __func__);\
+ f54->rtype.rgrp->propname = o_setting;\
+ mutex_unlock(&f54->rtype##_mutex);\
+ return retval;\
+ } \
+\
+ mutex_unlock(&f54->rtype##_mutex);\
+ return count;\
+} \
+
+#define show_store_func_unsigned(rtype, rgrp, propname)\
+show_store_func(rtype, rgrp, propname, "%u\n")
+
+#define show_replicated_func(rtype, rgrp, propname, fmt)\
+static ssize_t concat(synaptics_rmi4_f54, _##propname##_show)(\
+ struct device *dev,\
+ struct device_attribute *attr,\
+ char *buf)\
+{\
+ int retval;\
+ int size = 0;\
+ unsigned char ii;\
+ unsigned char length;\
+ unsigned char element_count;\
+ unsigned char *temp;\
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;\
+\
+ mutex_lock(&f54->rtype##_mutex);\
+\
+ length = f54->rtype.rgrp->length;\
+ element_count = length / sizeof(*f54->rtype.rgrp->data);\
+\
+ retval = f54->fn_ptr->read(rmi4_data,\
+ f54->rtype.rgrp->address,\
+ (unsigned char *)f54->rtype.rgrp->data,\
+ length);\
+ mutex_unlock(&f54->rtype##_mutex);\
+ if (retval < 0) {\
+ dev_dbg(&rmi4_data->i2c_client->dev,\
+ "%s: Failed to read " #rtype\
+ " " #rgrp "\n",\
+ __func__);\
+ } \
+\
+ temp = buf;\
+\
+ for (ii = 0; ii < element_count; ii++) {\
+ retval = snprintf(temp, PAGE_SIZE - size, fmt " ",\
+ f54->rtype.rgrp->data[ii].propname);\
+ if (retval < 0) {\
+ dev_err(&rmi4_data->i2c_client->dev,\
+ "%s: Failed to write output\n",\
+ __func__);\
+ return retval;\
+ } \
+ size += retval;\
+ temp += retval;\
+ } \
+\
+ retval = snprintf(temp, PAGE_SIZE - size, "\n");\
+ if (retval < 0) {\
+ dev_err(&rmi4_data->i2c_client->dev,\
+ "%s: Faild to write null terminator\n",\
+ __func__);\
+ return retval;\
+ } \
+\
+ return size + retval;\
+} \
+
+#define show_replicated_func_unsigned(rtype, rgrp, propname)\
+show_replicated_func(rtype, rgrp, propname, "%u")
+
+#define show_store_replicated_func(rtype, rgrp, propname, fmt)\
+show_replicated_func(rtype, rgrp, propname, fmt)\
+\
+static ssize_t concat(synaptics_rmi4_f54, _##propname##_store)(\
+ struct device *dev,\
+ struct device_attribute *attr,\
+ const char *buf, size_t count)\
+{\
+ int retval;\
+ unsigned int setting;\
+ unsigned char ii;\
+ unsigned char length;\
+ unsigned char element_count;\
+ const unsigned char *temp;\
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;\
+\
+ mutex_lock(&f54->rtype##_mutex);\
+\
+ length = f54->rtype.rgrp->length;\
+ element_count = length / sizeof(*f54->rtype.rgrp->data);\
+\
+ retval = f54->fn_ptr->read(rmi4_data,\
+ f54->rtype.rgrp->address,\
+ (unsigned char *)f54->rtype.rgrp->data,\
+ length);\
+ if (retval < 0) {\
+ dev_dbg(&rmi4_data->i2c_client->dev,\
+ "%s: Failed to read " #rtype\
+ " " #rgrp "\n",\
+ __func__);\
+ } \
+\
+ temp = buf;\
+\
+ for (ii = 0; ii < element_count; ii++) {\
+ if (sscanf(temp, fmt, &setting) == 1) {\
+ f54->rtype.rgrp->data[ii].propname = setting;\
+ } else {\
+ mutex_unlock(&f54->rtype##_mutex);\
+ return -EINVAL;\
+ } \
+\
+ while (*temp != 0) {\
+ temp++;\
+ if (isspace(*(temp - 1)) && !isspace(*temp))\
+ break;\
+ } \
+ } \
+\
+ retval = f54->fn_ptr->write(rmi4_data,\
+ f54->rtype.rgrp->address,\
+ (unsigned char *)f54->rtype.rgrp->data,\
+ length);\
+ mutex_unlock(&f54->rtype##_mutex);\
+ if (retval < 0) {\
+ dev_err(&rmi4_data->i2c_client->dev,\
+ "%s: Failed to write " #rtype\
+ " " #rgrp "\n",\
+ __func__);\
+ return retval;\
+ } \
+\
+ return count;\
+} \
+
+#define show_store_replicated_func_unsigned(rtype, rgrp, propname)\
+show_store_replicated_func(rtype, rgrp, propname, "%u")
+
+#define CTRL_REG_ADD(reg, skip, cond) \
+ do { if (cond) { \
+ attrs_ctrl_regs_exist[reg_num] = true;\
+ control->reg_##reg = kzalloc(sizeof(*control->reg_##reg),\
+ GFP_KERNEL);\
+ if (!control->reg_##reg)\
+ goto exit_no_mem;\
+ pr_debug("c%s addr = 0x%02x added\n",\
+ #reg, reg_addr);\
+ control->reg_##reg->address = reg_addr;\
+ reg_addr += skip;\
+ } \
+ reg_num++;\
+ } while (0)
+
+#define CTRL_REG_ADD_EXT(reg, skip, cond, size) \
+ do { if (cond) { \
+ attrs_ctrl_regs_exist[reg_num] = true;\
+ control->reg_##reg = kzalloc(sizeof(*control->reg_##reg),\
+ GFP_KERNEL);\
+ if (!control->reg_##reg)\
+ goto exit_no_mem;\
+ control->reg_##reg->data = kzalloc(size, GFP_KERNEL);\
+ if (!control->reg_##reg->data)\
+ goto exit_no_mem;\
+ pr_debug("c%s addr = 0x%02x size = %zu added\n",\
+ #reg, reg_addr, size);\
+ control->reg_##reg->length = size;\
+ control->reg_##reg->address = reg_addr;\
+ reg_addr += skip;\
+ } \
+ reg_num++;\
+ } while (0)
+
+#define CTRL_REG_PRESENCE(reg, skip, cond) \
+ do { if ((cond)) {\
+ pr_debug("c%s addr = 0x%02x\n",\
+ #reg, reg_addr);\
+ reg_addr += (skip);\
+ } } while (0)
+
+#define CTRL_REG_RESERVED_PRESENCE(reg, skip, cond) \
+ do { if ((cond)) {\
+ pr_debug("c%s addr = 0x%02x (reserved)\n",\
+ #reg, reg_addr);\
+ reg_addr += skip;\
+ } } while (0)
+
+#define QUERY_REG_READ(reg, cond)\
+ do { if (cond) {\
+ retval = f54->fn_ptr->read(rmi4_data,\
+ reg_addr,\
+ f54->query##reg.data,\
+ sizeof(f54->query##reg.data));\
+ if (retval < 0) {\
+ dev_err(&rmi4_data->i2c_client->dev,\
+ "%s: Failed to read query %s register\n",\
+ #reg, __func__);\
+ goto err;\
+ } \
+ pr_debug("q%s addr = 0x%02x, val = 0x%02x\n",\
+ #reg, reg_addr, f54->query##reg.data[0]);\
+ reg_addr += 1;\
+ } \
+ else {\
+ memset(&f54->query##reg.data, 0, sizeof(f54->query##reg.data));\
+ } } while (0)
+
+enum f54_report_types {
+ F54_8BIT_IMAGE = 1,
+ F54_16BIT_IMAGE = 2,
+ F54_RAW_16BIT_IMAGE = 3,
+ F54_HIGH_RESISTANCE = 4,
+ F54_TX_TO_TX_SHORT = 5,
+ F54_RX_TO_RX1 = 7,
+ F54_TRUE_BASELINE = 9,
+ F54_FULL_RAW_CAP_MIN_MAX = 13,
+ F54_RX_OPENS1 = 14,
+ F54_TX_OPEN = 15,
+ F54_TX_TO_GROUND = 16,
+ F54_RX_TO_RX2 = 17,
+ F54_RX_OPENS2 = 18,
+ F54_FULL_RAW_CAP = 19,
+ F54_FULL_RAW_CAP_RX_COUPLING_COMP = 20,
+ F54_SENSOR_SPEED = 22,
+ F54_ADC_RANGE = 23,
+ F54_TREX_OPENS = 24,
+ F54_TREX_TO_GND = 25,
+ F54_TREX_SHORTS = 26,
+ INVALID_REPORT_TYPE = -1,
+};
+
+struct f54_query {
+ union {
+ struct {
+ /* query 0 */
+ unsigned char num_of_rx_electrodes;
+
+ /* query 1 */
+ unsigned char num_of_tx_electrodes;
+
+ /* query 2 */
+ unsigned char f54_query2_b0__1:2;
+ unsigned char has_baseline:1;
+ unsigned char has_image8:1;
+ unsigned char f54_query2_b4__5:2;
+ unsigned char has_image16:1;
+ unsigned char f54_query2_b7:1;
+
+ /* queries 3.0 and 3.1 */
+ unsigned short clock_rate;
+
+ /* query 4 */
+ unsigned char touch_controller_family;
+
+ /* query 5 */
+ unsigned char has_pixel_touch_threshold_adjustment:1;
+ unsigned char f54_query5_b1__7:7;
+
+ /* query 6 */
+ unsigned char has_sensor_assignment:1;
+ unsigned char has_interference_metric:1;
+ unsigned char has_sense_frequency_control:1;
+ unsigned char has_firmware_noise_mitigation:1;
+ unsigned char has_ctrl11:1;
+ unsigned char has_two_byte_report_rate:1;
+ unsigned char has_one_byte_report_rate:1;
+ unsigned char has_relaxation_control:1;
+
+ /* query 7 */
+ unsigned char curve_compensation_mode:2;
+ unsigned char f54_query7_b2__7:6;
+
+ /* query 8 */
+ unsigned char f54_query8_b0:1;
+ unsigned char has_iir_filter:1;
+ unsigned char has_cmn_removal:1;
+ unsigned char has_cmn_maximum:1;
+ unsigned char has_touch_hysteresis:1;
+ unsigned char has_edge_compensation:1;
+ unsigned char has_per_frequency_noise_control:1;
+ unsigned char has_enhanced_stretch:1;
+
+ /* query 9 */
+ unsigned char has_force_fast_relaxation:1;
+ unsigned char has_multi_metric_state_machine:1;
+ unsigned char has_signal_clarity:1;
+ unsigned char has_variance_metric:1;
+ unsigned char has_0d_relaxation_control:1;
+ unsigned char has_0d_acquisition_control:1;
+ unsigned char has_status:1;
+ unsigned char has_slew_metric:1;
+
+ /* query 10 */
+ unsigned char has_h_blank:1;
+ unsigned char has_v_blank:1;
+ unsigned char has_long_h_blank:1;
+ unsigned char has_startup_fast_relaxation:1;
+ unsigned char has_esd_control:1;
+ unsigned char has_noise_mitigation2:1;
+ unsigned char has_noise_state:1;
+ unsigned char has_energy_ratio_relaxation:1;
+
+ /* query 11 */
+ unsigned char has_excessive_noise_reporting:1;
+ unsigned char has_slew_option:1;
+ unsigned char has_two_overhead_bursts:1;
+ unsigned char has_query13:1;
+ unsigned char has_one_overhead_burst:1;
+ unsigned char f54_query11_b5:1;
+ unsigned char has_ctrl88:1;
+ unsigned char has_query15:1;
+ } __packed;
+ unsigned char data[13];
+ };
+};
+
+struct f54_query12 {
+ union {
+ struct {
+ unsigned char number_of_sensing_frequencies:4;
+ unsigned char f54_query12_b4__7:4;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query13 {
+ union {
+ struct {
+ unsigned char has_ctrl86:1;
+ unsigned char has_ctrl87:1;
+ unsigned char has_ctrl87_sub0:1;
+ unsigned char has_ctrl87_sub1:1;
+ unsigned char has_ctrl87_sub2:1;
+ unsigned char has_cid_im:1;
+ unsigned char has_noise_mitigation_enh:1;
+ unsigned char has_rail_im:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query14 {
+ union {
+ struct {
+ unsigned char size_of_ctr87;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query15 {
+ union {
+ struct {
+ unsigned char has_ctrl90:1;
+ unsigned char has_traismit_strength:1;
+ unsigned char has_ctrl87_sub3:1;
+ unsigned char has_query16:1;
+ unsigned char has_query20:1;
+ unsigned char has_query21:1;
+ unsigned char has_query22:1;
+ unsigned char has_query25:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query16 {
+ union {
+ struct {
+ unsigned char has_query17:1;
+ unsigned char has_data17:1;
+ unsigned char has_ctrl92:1;
+ unsigned char has_ctrl93:1;
+ unsigned char has_ctrl94_query18:1;
+ unsigned char has_ctrl95_query19:1;
+ unsigned char has_ctrl99:1;
+ unsigned char has_ctrl100:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query17 {
+ union {
+ struct {
+ unsigned char q17_num_of_sense_freqs;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query18 {
+ union {
+ struct {
+ unsigned char has_ctrl94_sub0:1;
+ unsigned char has_ctrl94_sub1:1;
+ unsigned char has_ctrl94_sub2:1;
+ unsigned char has_ctrl94_sub3:1;
+ unsigned char has_ctrl94_sub4:1;
+ unsigned char has_ctrl94_sub5:1;
+ unsigned char has_ctrl94_sub6:1;
+ unsigned char has_ctrl94_sub7:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query19 {
+ union {
+ struct {
+ unsigned char size_of_ctrl95;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query20 {
+ union {
+ struct {
+ unsigned char adc_clock_divisor;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query21 {
+ union {
+ struct {
+ unsigned char has_abs_rx:1;
+ unsigned char has_abs_tx:1;
+ unsigned char has_ctrl91:1;
+ unsigned char has_ctrl96:1;
+ unsigned char has_ctrl97:1;
+ unsigned char has_ctrl98:1;
+ unsigned char has_data19:1;
+ unsigned char has_query24_data18:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query22 {
+ union {
+ struct {
+ unsigned char has_packed_image:1;
+ unsigned char has_ctrl101:1;
+ unsigned char has_dynamic_sense_display_ratio:1;
+ unsigned char has_query23:1;
+ unsigned char has_ctrl103_query26:1;
+ unsigned char has_ctrl104:1;
+ unsigned char has_ctrl105:1;
+ unsigned char has_query28:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query23 {
+ union {
+ struct {
+ unsigned char has_ctrl102:1;
+ unsigned char has_ctrl102_sub1:1;
+ unsigned char has_ctrl102_sub2:1;
+ unsigned char has_ctrl102_sub4:1;
+ unsigned char has_ctrl102_sub5:1;
+ unsigned char has_ctrl102_sub9:1;
+ unsigned char has_ctrl102_sub10:1;
+ unsigned char has_ctrl102_sub11:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query24 {
+ union {
+ struct {
+ unsigned char size_of_data18;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query25 {
+ union {
+ struct {
+ unsigned char has_ctrl106:1;
+ unsigned char has_ctrl102_sub12:1;
+ unsigned char has_ctrl107:1;
+ unsigned char has_ctrl108:1;
+ unsigned char has_ctrl109:1;
+ unsigned char has_data20:1;
+ unsigned char has_tags_for_moisture:1;
+ unsigned char has_query27:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query26 {
+ union {
+ struct {
+ unsigned char has_ctrl103_sub0:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query27 {
+ union {
+ struct {
+ unsigned char has_ctrl110:1;
+ unsigned char has_data21:1;
+ unsigned char has_ctrl111:1;
+ unsigned char has_ctrl112:1;
+ unsigned char has_ctrl113:1;
+ unsigned char has_data22:1;
+ unsigned char has_ctrl114:1;
+ unsigned char has_query29:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query28 {
+ union {
+ struct {
+ unsigned char has_capacitance_correction;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query29 {
+ union {
+ struct {
+ unsigned char has_ctrl115:1;
+ unsigned char has_ground_ring_options:1;
+ unsigned char has_lost_burst_tuning:1;
+ unsigned char has_aux_exvcom2_select:1;
+ unsigned char has_ctrl116:1;
+ unsigned char has_data23:1;
+ unsigned char has_ctrl117:1;
+ unsigned char has_query30:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query30 {
+ union {
+ struct {
+ unsigned char has_ctrl118:1;
+ unsigned char has_ctrl119:1;
+ unsigned char has_ctrl120:1;
+ unsigned char has_ctrl121:1;
+ unsigned char has_ctrl122_query31:1;
+ unsigned char has_ctrl123:1;
+ unsigned char has_ctrl124:1;
+ unsigned char has_query32:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query31 {
+ union {
+ struct {
+ unsigned char num_of_active_stylus_sensing_freqs;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query32 {
+ union {
+ struct {
+ unsigned char has_ctrl125:1;
+ unsigned char has_ctrl126:1;
+ unsigned char has_ctrl127:1;
+ unsigned char has_abs_charge_pump_disable:1;
+ unsigned char has_query33:1;
+ unsigned char has_data24:1;
+ unsigned char has_query34:1;
+ unsigned char has_query35:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query33 {
+ union {
+ struct {
+ unsigned char has_ctrl128:1;
+ unsigned char has_ctrl129:1;
+ unsigned char has_ctrl130:1;
+ unsigned char has_ctrl131:1;
+ unsigned char has_ctrl132:1;
+ unsigned char has_ctrl133:1;
+ unsigned char has_ctrl134:1;
+ unsigned char has_query36:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query34 {
+ union {
+ struct {
+ unsigned char max_fnm_sliding_window_width;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query35 {
+ union {
+ struct {
+ unsigned char has_data25:1;
+ unsigned char has_ctrl135:1;
+ unsigned char has_ctrl136:1;
+ unsigned char has_ctrl137:1;
+ unsigned char has_ctrl138:1;
+ unsigned char has_ctrl139:1;
+ unsigned char has_data26:1;
+ unsigned char has_ctrl140:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query36 {
+ union {
+ struct {
+ unsigned char has_ctrl141:1;
+ unsigned char has_ctrl142:1;
+ unsigned char has_query37:1;
+ unsigned char has_ctrl143:1;
+ unsigned char has_ctrl144:1;
+ unsigned char has_ctrl145:1;
+ unsigned char has_ctrl146:1;
+ unsigned char has_query38:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query38 {
+ union {
+ struct {
+ unsigned char has_ctrl147:1;
+ unsigned char has_ctrl148:1;
+ unsigned char has_ctrl149:1;
+ unsigned char f54_q38_b3:1;
+ unsigned char has_ctrl151:1;
+ unsigned char f54_q38_b5b6:2;
+ unsigned char has_query39:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query39 {
+ union {
+ struct {
+ unsigned char f54_b0_to_b6:7;
+ unsigned char has_query40:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query40 {
+ union {
+ struct {
+ unsigned char f54_q40_b0:1;
+ unsigned char has_ctrl163_query41:1;
+ unsigned char f54_q40_b2:1;
+ unsigned char has_ctrl165_query42:1;
+ unsigned char f54_q40_b4:1;
+ unsigned char has_ctrl167:1;
+ unsigned char f54_q40_b6:1;
+ unsigned char has_query43:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query41 {
+ union {
+ struct {
+ unsigned char size_of_ctrl163;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query42 {
+ union {
+ struct {
+ unsigned char size_of_ctrl165;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query43 {
+ union {
+ struct {
+ unsigned char f54_q43_b0_to_b6:7;
+ unsigned char has_query46:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_query46 {
+ union {
+ struct {
+ unsigned char f54_q46_b0b1:2;
+ unsigned char has_ctrl179:1;
+ unsigned char f54_q46_b3:1;
+ unsigned char has_data27:1;
+ unsigned char has_data28:1;
+ unsigned char f54_q46_b6b7:2;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f54_control_0 {
+ union {
+ struct {
+ unsigned char no_relax:1;
+ unsigned char no_scan:1;
+ unsigned char force_fast_relaxation:1;
+ unsigned char startup_fast_relaxation:1;
+ unsigned char gesture_cancels_sfr:1;
+ unsigned char enable_energy_ratio_relaxation:1;
+ unsigned char excessive_noise_attn_enable:1;
+ unsigned char f54_control0_b7:1;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_1 {
+ union {
+ struct {
+ unsigned char bursts_per_cluster:4;
+ unsigned char f54_ctrl1_b4__7:4;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_2 {
+ union {
+ struct {
+ unsigned short saturation_cap;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_3 {
+ union {
+ struct {
+ unsigned char pixel_touch_threshold;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_4__6 {
+ union {
+ struct {
+ /* control 4 */
+ unsigned char rx_feedback_cap:2;
+ unsigned char bias_current:2;
+ unsigned char f54_ctrl4_b4__7:4;
+
+ /* control 5 */
+ unsigned char low_ref_cap:2;
+ unsigned char low_ref_feedback_cap:2;
+ unsigned char low_ref_polarity:1;
+ unsigned char f54_ctrl5_b5__7:3;
+
+ /* control 6 */
+ unsigned char high_ref_cap:2;
+ unsigned char high_ref_feedback_cap:2;
+ unsigned char high_ref_polarity:1;
+ unsigned char f54_ctrl6_b5__7:3;
+ } __packed;
+ struct {
+ unsigned char data[3];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_7 {
+ union {
+ struct {
+ unsigned char cbc_cap:2;
+ unsigned char cbc_polarity:2;
+ unsigned char cbc_tx_carrier_selection:1;
+ unsigned char f54_ctrl7_b5__7:3;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_8__9 {
+ union {
+ struct {
+ /* control 8 */
+ unsigned short integration_duration:10;
+ unsigned short f54_ctrl8_b10__15:6;
+
+ /* control 9 */
+ unsigned char reset_duration;
+ } __packed;
+ struct {
+ unsigned char data[3];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_10 {
+ union {
+ struct {
+ unsigned char noise_sensing_bursts_per_image:4;
+ unsigned char f54_ctrl10_b4__7:4;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_11 {
+ union {
+ struct {
+ unsigned short f54_ctrl11;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_12__13 {
+ union {
+ struct {
+ /* control 12 */
+ unsigned char slow_relaxation_rate;
+
+ /* control 13 */
+ unsigned char fast_relaxation_rate;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_14 {
+ union {
+ struct {
+ unsigned char rxs_on_xaxis:1;
+ unsigned char curve_comp_on_txs:1;
+ unsigned char f54_ctrl14_b2__7:6;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_15n {
+ unsigned char sensor_rx_assignment;
+};
+
+struct f54_control_15 {
+ struct f54_control_15n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_16n {
+ unsigned char sensor_tx_assignment;
+};
+
+struct f54_control_16 {
+ struct f54_control_16n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_17n {
+ unsigned char burst_count_b8__10:3;
+ unsigned char disable:1;
+ unsigned char f54_ctrl17_b4:1;
+ unsigned char filter_bandwidth:3;
+};
+
+struct f54_control_17 {
+ struct f54_control_17n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_18n {
+ unsigned char burst_count_b0__7;
+};
+
+struct f54_control_18 {
+ struct f54_control_18n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_19n {
+ unsigned char stretch_duration;
+};
+
+struct f54_control_19 {
+ struct f54_control_19n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_20 {
+ union {
+ struct {
+ unsigned char disable_noise_mitigation:1;
+ unsigned char f54_ctrl20_b2__7:7;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_21 {
+ union {
+ struct {
+ unsigned short freq_shift_noise_threshold;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_22__26 {
+ union {
+ struct {
+ /* control 22 */
+ unsigned char f54_ctrl22;
+
+ /* control 23 */
+ unsigned short medium_noise_threshold;
+
+ /* control 24 */
+ unsigned short high_noise_threshold;
+
+ /* control 25 */
+ unsigned char noise_density;
+
+ /* control 26 */
+ unsigned char frame_count;
+ } __packed;
+ struct {
+ unsigned char data[7];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_27 {
+ union {
+ struct {
+ unsigned char iir_filter_coef;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_28 {
+ union {
+ struct {
+ unsigned short quiet_threshold;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_29 {
+ union {
+ struct {
+ /* control 29 */
+ unsigned char f54_ctrl29_b0__6:7;
+ unsigned char cmn_filter_disable:1;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_30 {
+ union {
+ struct {
+ unsigned char cmn_filter_max;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_31 {
+ union {
+ struct {
+ unsigned char touch_hysteresis;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_32__35 {
+ union {
+ struct {
+ /* control 32 */
+ unsigned short rx_low_edge_comp;
+
+ /* control 33 */
+ unsigned short rx_high_edge_comp;
+
+ /* control 34 */
+ unsigned short tx_low_edge_comp;
+
+ /* control 35 */
+ unsigned short tx_high_edge_comp;
+ } __packed;
+ struct {
+ unsigned char data[8];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_36n {
+ unsigned char axis1_comp;
+};
+
+struct f54_control_36 {
+ struct f54_control_36n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_37n {
+ unsigned char axis2_comp;
+};
+
+struct f54_control_37 {
+ struct f54_control_37n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_38n {
+ unsigned char noise_control_1;
+};
+
+struct f54_control_38 {
+ struct f54_control_38n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_39n {
+ unsigned char noise_control_2;
+};
+
+struct f54_control_39 {
+ struct f54_control_39n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_40n {
+ unsigned char noise_control_3;
+};
+
+struct f54_control_40 {
+ struct f54_control_40n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_89 {
+ union {
+ struct {
+ unsigned char c89_cid_sel_opt:2;
+ unsigned char c89_cid_voltage_sel:3;
+ unsigned char c89_byte0_b5_b7:3;
+ unsigned char c89_cid_im_noise_threshold_lsb;
+ unsigned char c89_cid_im_noise_threshold_msb;
+ unsigned char c89_fnm_pixel_touch_mult;
+ unsigned char c89_freq_scan_threshold_lsb;
+ unsigned char c89_freq_scan_threshold_msb;
+ unsigned char c89_quiet_im_threshold_lsb;
+ unsigned char c89_quiet_im_threshold_msb;
+ } __packed;
+ struct {
+ unsigned char data[8];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_93 {
+ union {
+ struct {
+ unsigned char c93_freq_shift_noise_threshold_lsb;
+ unsigned char c93_freq_shift_noise_threshold_msb;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_95 {
+ struct f54_control_95n *data;
+ unsigned short address;
+ unsigned char length;
+};
+
+struct f54_control_99 {
+ union {
+ struct {
+ unsigned char c99_int_dur_lsb;
+ unsigned char c99_int_dur_msb;
+ unsigned char c99_reset_dur;
+ } __packed;
+ struct {
+ unsigned char data[3];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_107 {
+ union {
+ struct {
+ unsigned char c107_abs_int_dur;
+ unsigned char c107_abs_reset_dur;
+ unsigned char c107_abs_filter_bw;
+ unsigned char c107_abs_rstretch;
+ unsigned char c107_abs_burst_count_1;
+ unsigned char c107_abs_burst_count_2;
+ unsigned char c107_abs_stretch_dur;
+ unsigned char c107_abs_adc_clock_div;
+ unsigned char c107_abs_sub_burtst_size;
+ unsigned char c107_abs_trigger_delay;
+ } __packed;
+ struct {
+ unsigned char data[10];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control_137 {
+ union {
+ struct {
+ unsigned char c137_cmnr_adjust;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_control {
+ struct f54_control_0 *reg_0;
+ struct f54_control_1 *reg_1;
+ struct f54_control_2 *reg_2;
+ struct f54_control_3 *reg_3;
+ struct f54_control_4__6 *reg_4__6;
+ struct f54_control_7 *reg_7;
+ struct f54_control_8__9 *reg_8__9;
+ struct f54_control_10 *reg_10;
+ struct f54_control_11 *reg_11;
+ struct f54_control_12__13 *reg_12__13;
+ struct f54_control_14 *reg_14;
+ struct f54_control_15 *reg_15;
+ struct f54_control_16 *reg_16;
+ struct f54_control_17 *reg_17;
+ struct f54_control_18 *reg_18;
+ struct f54_control_19 *reg_19;
+ struct f54_control_20 *reg_20;
+ struct f54_control_21 *reg_21;
+ struct f54_control_22__26 *reg_22__26;
+ struct f54_control_27 *reg_27;
+ struct f54_control_28 *reg_28;
+ struct f54_control_29 *reg_29;
+ struct f54_control_30 *reg_30;
+ struct f54_control_31 *reg_31;
+ struct f54_control_32__35 *reg_32__35;
+ struct f54_control_36 *reg_36;
+ struct f54_control_37 *reg_37;
+ struct f54_control_38 *reg_38;
+ struct f54_control_39 *reg_39;
+ struct f54_control_40 *reg_40;
+ struct f54_control_89 *reg_89;
+ struct f54_control_93 *reg_93;
+ struct f54_control_95 *reg_95;
+ struct f54_control_99 *reg_99;
+ struct f54_control_107 *reg_107;
+ struct f54_control_137 *reg_137;
+ struct f55_control_0 *reg_0_f55;
+ struct f55_control_8 *reg_8_f55;
+};
+
+struct f54_data_4 {
+ union {
+ struct {
+ unsigned char d4_sense_freq_sel:4;
+ unsigned char d4_baseline_sel:2;
+ unsigned char d4_b6:1;
+ unsigned char d4_inhibit_freq_shift:1;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+struct f54_data_6 {
+ union {
+ struct {
+ unsigned char d6_interference_metric_lsb;
+ unsigned char d6_interference_metric_msb;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+
+ };
+};
+
+struct f54_data_7_0 {
+ union {
+ struct {
+ unsigned char d7_current_report_rate_lsb;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_data_7_1 {
+ union {
+ struct {
+ unsigned char d7_current_report_rate_msb;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_data_8 {
+ union {
+ struct {
+ unsigned char d8_variance_metric_lsb;
+ unsigned char d8_variance_metric_msb;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_data_9 {
+ union {
+ struct {
+ unsigned char d9_averaged_im_lsb;
+ unsigned char d9_averaged_im_msb;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_data_10 {
+ union {
+ struct {
+ unsigned char d10_noise_state;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_data_14 {
+ union {
+ struct {
+ unsigned char d14_cid_im_lsb;
+ unsigned char d14_cid_im_msb;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_data_16 {
+ union {
+ struct {
+ unsigned char d16_freq_scan_im_lsb;
+ unsigned char d16_freq_scan_im_msb;
+ } __packed;
+ struct {
+ unsigned char data[2];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_data_17 {
+ union {
+ struct {
+ unsigned char d17_freq:7;
+ unsigned char d17_inhibit_freq_shift:1;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f54_data {
+ struct f54_data_4 *reg_4;
+ struct f54_data_6 *reg_6;
+ struct f54_data_7_0 *reg_7_0;
+ struct f54_data_7_1 *reg_7_1;
+ struct f54_data_8 *reg_8;
+ struct f54_data_9 *reg_9;
+ struct f54_data_10 *reg_10;
+ struct f54_data_14 *reg_14;
+ struct f54_data_16 *reg_16;
+ struct f54_data_17 *reg_17;
+};
+
+struct f55_query_0_2 {
+ union {
+ struct {
+ /* query 0 */
+ unsigned char num_of_rx_electrodes;
+
+ /* query 1 */
+ unsigned char num_of_tx_electrodes;
+
+ /* query 2 */
+ unsigned char has_sensor_assignment:1;
+ unsigned char has_edge_compensation:1;
+ unsigned char curve_compensation_mode:2;
+ unsigned char has_ctrl6:1;
+ unsigned char has_alternate_tx_assignment:1;
+ unsigned char f55_q2_has_single_layer_multitouch:1;
+ unsigned char has_query5:1;
+ } __packed;
+ unsigned char data[3];
+ };
+};
+
+struct f55_query_3 {
+ union {
+ struct {
+ unsigned char f55_q3_has_ctrl8:1;
+ unsigned char has_ctrl9:1;
+ unsigned char has_on_cell_pattern:1;
+ unsigned char has_data0:1;
+ unsigned char has_single_wide_pattern:1;
+ unsigned char has_mirrored_tx_pattern:1;
+ unsigned char has_discrete_pattern:1;
+ unsigned char has_query9:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f55_control_0 {
+ union {
+ struct {
+ unsigned char f55_c0_receivers_on_x:1;
+ unsigned char f55_c0_curve_compensation_on_tx:1;
+ unsigned char f55_c0_trx_sense:1;
+ unsigned char f55_c0_trx_config:1;
+ unsigned char f55_c0_guard_disable:1;
+ unsigned char f55_c0_b5_b7:3;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct f55_control_8 {
+ union {
+ struct {
+ unsigned char f55_c8_pattern_type;
+ } __packed;
+ struct {
+ unsigned char data[1];
+ unsigned short address;
+ } __packed;
+ };
+};
+
+struct synaptics_rmi4_fn55_desc {
+ unsigned short query_base_addr;
+ unsigned short control_base_addr;
+};
+
+struct synaptics_rmi4_f54_handle {
+ bool no_auto_cal;
+ int status;
+ unsigned char intr_mask;
+ unsigned char intr_reg_num;
+ unsigned char *report_data;
+ unsigned short query_base_addr;
+ unsigned short control_base_addr;
+ unsigned short data_base_addr;
+ unsigned short command_base_addr;
+ unsigned short fifoindex;
+ unsigned int report_size;
+ unsigned int data_buffer_size;
+ enum f54_report_types report_type;
+ enum f54_report_types user_report_type1;
+ enum f54_report_types user_report_type2;
+ struct mutex status_mutex;
+ struct mutex data_mutex;
+ struct mutex control_mutex;
+ struct f54_query query;
+ struct f54_query12 query12;
+ struct f54_query13 query13;
+ struct f54_query14 query14;
+ struct f54_query15 query15;
+ struct f54_query16 query16;
+ struct f54_query17 query17;
+ struct f54_query18 query18;
+ struct f54_query19 query19;
+ struct f54_query20 query20;
+ struct f54_query21 query21;
+ struct f54_query22 query22;
+ struct f54_query23 query23;
+ struct f54_query24 query24;
+ struct f54_query25 query25;
+ struct f54_query26 query26;
+ struct f54_query27 query27;
+ struct f54_query28 query28;
+ struct f54_query29 query29;
+ struct f54_query30 query30;
+ struct f54_query31 query31;
+ struct f54_query32 query32;
+ struct f54_query33 query33;
+ struct f54_query34 query34;
+ struct f54_query35 query35;
+ struct f54_query36 query36;
+ struct f54_query38 query38;
+ struct f54_query39 query39;
+ struct f54_query40 query40;
+ struct f54_query41 query41;
+ struct f54_query42 query42;
+ struct f54_query43 query43;
+ struct f54_query46 query46;
+ struct f54_control control;
+ struct f54_data data;
+ struct kobject *attr_dir;
+ struct hrtimer watchdog;
+ struct work_struct timeout_work;
+ struct delayed_work status_work;
+ struct workqueue_struct *status_workqueue;
+ struct synaptics_rmi4_exp_fn_ptr *fn_ptr;
+ struct synaptics_rmi4_data *rmi4_data;
+ struct synaptics_rmi4_fn55_desc *fn55;
+ struct f55_query_0_2 query_f55_0_2;
+ struct f55_query_3 query_f55_3;
+ struct wake_lock test_wake_lock;
+};
+
+store_prototype(reset)
+show_prototype_ext(status, S_IRUGO)
+show_prototype_ext(report_size, S_IRUGO)
+show_prototype_ext(num_of_mapped_rx, S_IRUGO)
+show_prototype_ext(num_of_mapped_tx, S_IRUGO)
+show_store_prototype(no_auto_cal)
+show_store_prototype_ext(report_type, S_IRUGO | S_IWUSR | S_IWGRP)
+show_store_prototype_ext(user_report_type1, S_IRUGO | S_IWUSR | S_IWGRP)
+show_store_prototype_ext(user_report_type2, S_IRUGO | S_IWUSR | S_IWGRP)
+show_prototype_ext(user_get_report1, S_IRUGO)
+show_prototype_ext(user_get_report2, S_IRUGO)
+show_store_prototype(fifoindex)
+store_prototype(get_report)
+show_store_prototype(force_update)
+store_prototype(force_cal)
+show_store_prototype(enter_in_cell_test_mode)
+show_prototype_ext(num_of_rx_electrodes, S_IRUGO)
+show_prototype_ext(num_of_tx_electrodes, S_IRUGO)
+show_prototype(has_image16)
+show_prototype(has_image8)
+show_prototype(has_baseline)
+show_prototype(clock_rate)
+show_prototype(touch_controller_family)
+show_prototype(has_pixel_touch_threshold_adjustment)
+show_prototype(has_sensor_assignment)
+show_prototype(has_interference_metric)
+show_prototype(has_sense_frequency_control)
+show_prototype(has_firmware_noise_mitigation)
+show_prototype(has_two_byte_report_rate)
+show_prototype(has_one_byte_report_rate)
+show_prototype(has_relaxation_control)
+show_prototype(curve_compensation_mode)
+show_prototype(has_iir_filter)
+show_prototype(has_cmn_removal)
+show_prototype(has_cmn_maximum)
+show_prototype(has_touch_hysteresis)
+show_prototype(has_edge_compensation)
+show_prototype(has_per_frequency_noise_control)
+show_prototype(has_enhanced_stretch)
+show_prototype(has_force_fast_relaxation)
+show_prototype(has_multi_metric_state_machine)
+show_prototype(has_signal_clarity)
+show_prototype(has_variance_metric)
+show_prototype(has_0d_relaxation_control)
+show_prototype(has_0d_acquisition_control)
+show_prototype(has_status)
+show_prototype(has_slew_metric)
+show_prototype(has_h_blank)
+show_prototype(has_v_blank)
+show_prototype(has_long_h_blank)
+show_prototype(has_startup_fast_relaxation)
+show_prototype(has_esd_control)
+show_prototype(has_noise_mitigation2)
+show_prototype(has_noise_state)
+show_prototype(has_energy_ratio_relaxation)
+show_prototype(number_of_sensing_frequencies)
+show_prototype(q17_num_of_sense_freqs)
+show_store_prototype(no_relax)
+show_store_prototype(no_scan)
+show_store_prototype(bursts_per_cluster)
+show_store_prototype(saturation_cap)
+show_store_prototype(pixel_touch_threshold)
+show_store_prototype(rx_feedback_cap)
+show_store_prototype(low_ref_cap)
+show_store_prototype(low_ref_feedback_cap)
+show_store_prototype(low_ref_polarity)
+show_store_prototype(high_ref_cap)
+show_store_prototype(high_ref_feedback_cap)
+show_store_prototype(high_ref_polarity)
+show_store_prototype(cbc_cap)
+show_store_prototype(cbc_polarity)
+show_store_prototype(cbc_tx_carrier_selection)
+show_store_prototype(integration_duration)
+show_store_prototype(reset_duration)
+show_store_prototype(noise_sensing_bursts_per_image)
+show_store_prototype(slow_relaxation_rate)
+show_store_prototype(fast_relaxation_rate)
+show_store_prototype(rxs_on_xaxis)
+show_store_prototype(curve_comp_on_txs)
+show_prototype(sensor_rx_assignment)
+show_prototype(sensor_tx_assignment)
+show_prototype(burst_count)
+show_prototype(disable)
+show_prototype(filter_bandwidth)
+show_prototype(stretch_duration)
+show_store_prototype(disable_noise_mitigation)
+show_store_prototype(freq_shift_noise_threshold)
+show_store_prototype(medium_noise_threshold)
+show_store_prototype(high_noise_threshold)
+show_store_prototype(noise_density)
+show_store_prototype(frame_count)
+show_store_prototype(iir_filter_coef)
+show_store_prototype(quiet_threshold)
+show_store_prototype(cmn_filter_disable)
+show_store_prototype(cmn_filter_max)
+show_store_prototype(touch_hysteresis)
+show_store_prototype(rx_low_edge_comp)
+show_store_prototype(rx_high_edge_comp)
+show_store_prototype(tx_low_edge_comp)
+show_store_prototype(tx_high_edge_comp)
+show_store_prototype(axis1_comp)
+show_store_prototype(axis2_comp)
+show_prototype(noise_control_1)
+show_prototype(noise_control_2)
+show_prototype(noise_control_3)
+show_store_prototype(d4_sense_freq_sel)
+show_store_prototype(d4_baseline_sel)
+show_store_prototype(d4_inhibit_freq_shift)
+show_prototype(d6_interference_metric_lsb)
+show_prototype(d6_interference_metric_msb)
+show_prototype(d7_current_report_rate_lsb)
+show_prototype(d7_current_report_rate_msb)
+show_prototype(d8_variance_metric_lsb)
+show_prototype(d8_variance_metric_msb)
+show_prototype(d9_averaged_im_lsb)
+show_prototype(d9_averaged_im_msb)
+show_prototype(d10_noise_state)
+show_store_prototype(d16_freq_scan_im_lsb)
+show_store_prototype(d16_freq_scan_im_msb)
+show_prototype(d14_cid_im_lsb)
+show_prototype(d14_cid_im_msb)
+show_store_prototype(d17_inhibit_freq_shift)
+show_store_prototype(d17_freq)
+show_store_prototype(c89_cid_sel_opt)
+show_store_prototype(c89_cid_voltage_sel)
+show_store_prototype(c89_cid_im_noise_threshold_lsb)
+show_store_prototype(c89_cid_im_noise_threshold_msb)
+show_store_prototype(c89_fnm_pixel_touch_mult)
+show_store_prototype(c89_freq_scan_threshold_lsb)
+show_store_prototype(c89_freq_scan_threshold_msb)
+show_store_prototype(c89_quiet_im_threshold_lsb)
+show_store_prototype(c89_quiet_im_threshold_msb)
+show_store_prototype(c93_freq_shift_noise_threshold_lsb)
+show_store_prototype(c93_freq_shift_noise_threshold_msb)
+show_store_prototype(c95_disable)
+show_store_prototype(c95_filter_bw)
+show_store_prototype(c95_first_burst_length_lsb)
+show_store_prototype(c95_first_burst_length_msb)
+show_store_prototype(c95_addl_burst_length_lsb)
+show_store_prototype(c95_addl_burst_length_msb)
+show_store_prototype(c95_i_stretch)
+show_store_prototype(c95_r_stretch)
+show_store_prototype(c95_noise_control1)
+show_store_prototype(c95_noise_control2)
+show_store_prototype(c95_noise_control3)
+show_store_prototype(c95_noise_control4)
+show_store_prototype(c99_int_dur_lsb)
+show_store_prototype(c99_int_dur_msb)
+show_store_prototype(c99_reset_dur)
+show_store_prototype(c107_abs_int_dur)
+show_store_prototype(c107_abs_reset_dur)
+show_store_prototype(c107_abs_filter_bw)
+show_store_prototype(c107_abs_rstretch)
+show_store_prototype(c107_abs_burst_count_1)
+show_store_prototype(c107_abs_burst_count_2)
+show_store_prototype(c107_abs_stretch_dur)
+show_store_prototype(c107_abs_adc_clock_div)
+show_store_prototype(c107_abs_sub_burtst_size)
+show_store_prototype(c107_abs_trigger_delay)
+show_store_prototype(c137_cmnr_adjust)
+show_prototype(f55_q2_has_single_layer_multitouch)
+show_prototype(f55_c0_receivers_on_x)
+show_prototype(f55_c8_pattern_type)
+
+static ssize_t synaptics_rmi4_f54_data_read(struct file *data_file,
+ struct kobject *kobj, struct bin_attribute *attributes,
+ char *buf, loff_t pos, size_t count);
+
+static struct attribute *attrs[] = {
+ attrify(reset),
+ attrify(status),
+ attrify(report_size),
+ attrify(num_of_mapped_rx),
+ attrify(num_of_mapped_tx),
+ attrify(no_auto_cal),
+ attrify(report_type),
+ attrify(user_report_type1),
+ attrify(user_report_type2),
+ attrify(user_get_report1),
+ attrify(user_get_report2),
+ attrify(fifoindex),
+ attrify(get_report),
+ attrify(force_update),
+ attrify(force_cal),
+ attrify(enter_in_cell_test_mode),
+ attrify(num_of_rx_electrodes),
+ attrify(num_of_tx_electrodes),
+ attrify(has_image16),
+ attrify(has_image8),
+ attrify(has_baseline),
+ attrify(clock_rate),
+ attrify(touch_controller_family),
+ attrify(has_pixel_touch_threshold_adjustment),
+ attrify(has_sensor_assignment),
+ attrify(has_interference_metric),
+ attrify(has_sense_frequency_control),
+ attrify(has_firmware_noise_mitigation),
+ attrify(has_two_byte_report_rate),
+ attrify(has_one_byte_report_rate),
+ attrify(has_relaxation_control),
+ attrify(curve_compensation_mode),
+ attrify(has_iir_filter),
+ attrify(has_cmn_removal),
+ attrify(has_cmn_maximum),
+ attrify(has_touch_hysteresis),
+ attrify(has_edge_compensation),
+ attrify(has_per_frequency_noise_control),
+ attrify(has_enhanced_stretch),
+ attrify(has_force_fast_relaxation),
+ attrify(has_multi_metric_state_machine),
+ attrify(has_signal_clarity),
+ attrify(has_variance_metric),
+ attrify(has_0d_relaxation_control),
+ attrify(has_0d_acquisition_control),
+ attrify(has_status),
+ attrify(has_slew_metric),
+ attrify(has_h_blank),
+ attrify(has_v_blank),
+ attrify(has_long_h_blank),
+ attrify(has_startup_fast_relaxation),
+ attrify(has_esd_control),
+ attrify(has_noise_mitigation2),
+ attrify(has_noise_state),
+ attrify(has_energy_ratio_relaxation),
+ attrify(number_of_sensing_frequencies),
+ attrify(q17_num_of_sense_freqs),
+ attrify(f55_q2_has_single_layer_multitouch),
+ NULL,
+};
+
+static struct attribute_group attr_group = GROUP(attrs);
+
+static struct attribute *attrs_reg_0[] = {
+ attrify(no_relax),
+ attrify(no_scan),
+ NULL,
+};
+
+static struct attribute *attrs_reg_1[] = {
+ attrify(bursts_per_cluster),
+ NULL,
+};
+
+static struct attribute *attrs_reg_2[] = {
+ attrify(saturation_cap),
+ NULL,
+};
+
+static struct attribute *attrs_reg_3[] = {
+ attrify(pixel_touch_threshold),
+ NULL,
+};
+
+static struct attribute *attrs_reg_4__6[] = {
+ attrify(rx_feedback_cap),
+ attrify(low_ref_cap),
+ attrify(low_ref_feedback_cap),
+ attrify(low_ref_polarity),
+ attrify(high_ref_cap),
+ attrify(high_ref_feedback_cap),
+ attrify(high_ref_polarity),
+ NULL,
+};
+
+static struct attribute *attrs_reg_7[] = {
+ attrify(cbc_cap),
+ attrify(cbc_polarity),
+ attrify(cbc_tx_carrier_selection),
+ NULL,
+};
+
+static struct attribute *attrs_reg_8__9[] = {
+ attrify(integration_duration),
+ attrify(reset_duration),
+ NULL,
+};
+
+static struct attribute *attrs_reg_10[] = {
+ attrify(noise_sensing_bursts_per_image),
+ NULL,
+};
+
+static struct attribute *attrs_reg_11[] = {
+ NULL,
+};
+
+static struct attribute *attrs_reg_12__13[] = {
+ attrify(slow_relaxation_rate),
+ attrify(fast_relaxation_rate),
+ NULL,
+};
+
+static struct attribute *attrs_reg_14__16[] = {
+ attrify(rxs_on_xaxis),
+ attrify(curve_comp_on_txs),
+ attrify(sensor_rx_assignment),
+ attrify(sensor_tx_assignment),
+ NULL,
+};
+
+static struct attribute *attrs_reg_17__19[] = {
+ attrify(burst_count),
+ attrify(disable),
+ attrify(filter_bandwidth),
+ attrify(stretch_duration),
+ NULL,
+};
+
+static struct attribute *attrs_reg_20[] = {
+ attrify(disable_noise_mitigation),
+ NULL,
+};
+
+static struct attribute *attrs_reg_21[] = {
+ attrify(freq_shift_noise_threshold),
+ NULL,
+};
+
+static struct attribute *attrs_reg_22__26[] = {
+ attrify(medium_noise_threshold),
+ attrify(high_noise_threshold),
+ attrify(noise_density),
+ attrify(frame_count),
+ NULL,
+};
+
+static struct attribute *attrs_reg_27[] = {
+ attrify(iir_filter_coef),
+ NULL,
+};
+
+static struct attribute *attrs_reg_28[] = {
+ attrify(quiet_threshold),
+ NULL,
+};
+
+static struct attribute *attrs_reg_29[] = {
+ attrify(cmn_filter_disable),
+ NULL,
+};
+
+static struct attribute *attrs_reg_30[] = {
+ attrify(cmn_filter_max),
+ NULL,
+};
+
+static struct attribute *attrs_reg_31[] = {
+ attrify(touch_hysteresis),
+ NULL,
+};
+
+static struct attribute *attrs_reg_32__35[] = {
+ attrify(rx_low_edge_comp),
+ attrify(rx_high_edge_comp),
+ attrify(tx_low_edge_comp),
+ attrify(tx_high_edge_comp),
+ NULL,
+};
+
+static struct attribute *attrs_reg_36[] = {
+ attrify(axis1_comp),
+ NULL,
+};
+
+static struct attribute *attrs_reg_37[] = {
+ attrify(axis2_comp),
+ NULL,
+};
+
+static struct attribute *attrs_reg_38__40[] = {
+ attrify(noise_control_1),
+ attrify(noise_control_2),
+ attrify(noise_control_3),
+ NULL,
+};
+
+static struct attribute *attrs_reg_89[] = {
+ attrify(c89_cid_sel_opt),
+ attrify(c89_cid_voltage_sel),
+ attrify(c89_cid_im_noise_threshold_lsb),
+ attrify(c89_cid_im_noise_threshold_msb),
+ attrify(c89_fnm_pixel_touch_mult),
+ attrify(c89_freq_scan_threshold_lsb),
+ attrify(c89_freq_scan_threshold_msb),
+ attrify(c89_quiet_im_threshold_lsb),
+ attrify(c89_quiet_im_threshold_msb),
+ NULL,
+};
+
+static struct attribute *attrs_reg_93[] = {
+ attrify(c93_freq_shift_noise_threshold_lsb),
+ attrify(c93_freq_shift_noise_threshold_msb),
+ NULL,
+};
+
+static struct attribute *attrs_reg_95[] = {
+ attrify(c95_disable),
+ attrify(c95_filter_bw),
+ attrify(c95_first_burst_length_lsb),
+ attrify(c95_first_burst_length_msb),
+ attrify(c95_addl_burst_length_lsb),
+ attrify(c95_addl_burst_length_msb),
+ attrify(c95_i_stretch),
+ attrify(c95_r_stretch),
+ attrify(c95_noise_control1),
+ attrify(c95_noise_control2),
+ attrify(c95_noise_control3),
+ attrify(c95_noise_control4),
+ NULL,
+};
+
+static struct attribute *attrs_reg_99[] = {
+ attrify(c99_int_dur_lsb),
+ attrify(c99_int_dur_msb),
+ attrify(c99_reset_dur),
+ NULL,
+};
+
+static struct attribute *attrs_reg_107[] = {
+ attrify(c107_abs_int_dur),
+ attrify(c107_abs_reset_dur),
+ attrify(c107_abs_filter_bw),
+ attrify(c107_abs_rstretch),
+ attrify(c107_abs_burst_count_1),
+ attrify(c107_abs_burst_count_2),
+ attrify(c107_abs_stretch_dur),
+ attrify(c107_abs_adc_clock_div),
+ attrify(c107_abs_sub_burtst_size),
+ attrify(c107_abs_trigger_delay),
+ NULL,
+};
+
+static struct attribute *attrs_reg_137[] = {
+ attrify(c137_cmnr_adjust),
+ NULL,
+};
+
+static struct attribute *attrs_f55_c0[] = {
+ attrify(f55_c0_receivers_on_x),
+ NULL,
+};
+
+static struct attribute *attrs_f55_c8[] = {
+ attrify(f55_c8_pattern_type),
+ NULL,
+};
+
+static struct attribute_group attrs_ctrl_regs[] = {
+ GROUP(attrs_reg_0),
+ GROUP(attrs_reg_1),
+ GROUP(attrs_reg_2),
+ GROUP(attrs_reg_3),
+ GROUP(attrs_reg_4__6),
+ GROUP(attrs_reg_7),
+ GROUP(attrs_reg_8__9),
+ GROUP(attrs_reg_10),
+ GROUP(attrs_reg_11),
+ GROUP(attrs_reg_12__13),
+ GROUP(attrs_reg_14__16),
+ GROUP(attrs_reg_17__19),
+ GROUP(attrs_reg_20),
+ GROUP(attrs_reg_21),
+ GROUP(attrs_reg_22__26),
+ GROUP(attrs_reg_27),
+ GROUP(attrs_reg_28),
+ GROUP(attrs_reg_29),
+ GROUP(attrs_reg_30),
+ GROUP(attrs_reg_31),
+ GROUP(attrs_reg_32__35),
+ GROUP(attrs_reg_36),
+ GROUP(attrs_reg_37),
+ GROUP(attrs_reg_38__40),
+ GROUP(attrs_reg_89),
+ GROUP(attrs_reg_93),
+ GROUP(attrs_reg_95),
+ GROUP(attrs_reg_99),
+ GROUP(attrs_reg_107),
+ GROUP(attrs_reg_137),
+ GROUP(attrs_f55_c0),
+ GROUP(attrs_f55_c8),
+};
+
+static bool attrs_ctrl_regs_exist[ARRAY_SIZE(attrs_ctrl_regs)];
+
+static struct attribute *data_attrs_reg_4[] = {
+ attrify(d4_sense_freq_sel),
+ attrify(d4_baseline_sel),
+ attrify(d4_inhibit_freq_shift),
+ NULL,
+};
+
+static struct attribute *data_attrs_reg_6[] = {
+ attrify(d6_interference_metric_lsb),
+ attrify(d6_interference_metric_msb),
+ NULL,
+};
+
+static struct attribute *data_attrs_reg_7_0[] = {
+ attrify(d7_current_report_rate_lsb),
+ NULL,
+};
+
+static struct attribute *data_attrs_reg_7_1[] = {
+ attrify(d7_current_report_rate_msb),
+ NULL,
+};
+
+static struct attribute *data_attrs_reg_8[] = {
+ attrify(d8_variance_metric_lsb),
+ attrify(d8_variance_metric_msb),
+ NULL,
+};
+
+static struct attribute *data_attrs_reg_9[] = {
+ attrify(d9_averaged_im_lsb),
+ attrify(d9_averaged_im_msb),
+ NULL,
+};
+
+static struct attribute *data_attrs_reg_10[] = {
+ attrify(d10_noise_state),
+ NULL,
+};
+
+static struct attribute *data_attrs_reg_14[] = {
+ attrify(d14_cid_im_lsb),
+ attrify(d14_cid_im_msb),
+ NULL,
+};
+
+static struct attribute *data_attrs_reg_16[] = {
+ attrify(d16_freq_scan_im_lsb),
+ attrify(d16_freq_scan_im_msb),
+ NULL,
+};
+
+static struct attribute *data_attrs_reg_17[] = {
+ attrify(d17_freq),
+ attrify(d17_inhibit_freq_shift),
+ NULL,
+};
+
+static struct attribute_group attrs_data_regs[] = {
+ GROUP(data_attrs_reg_4),
+ GROUP(data_attrs_reg_6),
+ GROUP(data_attrs_reg_7_0),
+ GROUP(data_attrs_reg_7_1),
+ GROUP(data_attrs_reg_8),
+ GROUP(data_attrs_reg_9),
+ GROUP(data_attrs_reg_10),
+ GROUP(data_attrs_reg_14),
+ GROUP(data_attrs_reg_16),
+ GROUP(data_attrs_reg_17),
+};
+
+static bool attrs_data_regs_exist[ARRAY_SIZE(attrs_data_regs)];
+
+static struct bin_attribute dev_report_data = {
+ .attr = {
+ .name = "report_data",
+ .mode = S_IRUGO,
+ },
+ .size = 0,
+ .read = synaptics_rmi4_f54_data_read,
+};
+
+static struct synaptics_rmi4_f54_handle *f54;
+
+static struct completion remove_complete;
+
+static bool is_report_type_valid(enum f54_report_types report_type)
+{
+ switch (report_type) {
+ case F54_8BIT_IMAGE:
+ case F54_16BIT_IMAGE:
+ case F54_RAW_16BIT_IMAGE:
+ case F54_HIGH_RESISTANCE:
+ case F54_TX_TO_TX_SHORT:
+ case F54_RX_TO_RX1:
+ case F54_TRUE_BASELINE:
+ case F54_FULL_RAW_CAP_MIN_MAX:
+ case F54_RX_OPENS1:
+ case F54_TX_OPEN:
+ case F54_TX_TO_GROUND:
+ case F54_RX_TO_RX2:
+ case F54_RX_OPENS2:
+ case F54_FULL_RAW_CAP:
+ case F54_FULL_RAW_CAP_RX_COUPLING_COMP:
+ case F54_SENSOR_SPEED:
+ case F54_ADC_RANGE:
+ case F54_TREX_OPENS:
+ case F54_TREX_TO_GND:
+ case F54_TREX_SHORTS:
+ return true;
+ break;
+ default:
+ return false;
+ }
+}
+
+static int set_user_report_type(enum f54_report_types *user_report_type,
+ const char *buf, size_t count)
+{
+ unsigned int report_type;
+ int retval = 0;
+ retval = kstrtouint(buf, 10, &report_type);
+ if (retval)
+ goto out;
+
+ if (!is_report_type_valid((enum f54_report_types)report_type)) {
+ dev_err(&f54->rmi4_data->i2c_client->dev,
+ "%s: Report type not supported by driver\n",
+ __func__);
+ retval = -EINVAL;
+ }
+
+out:
+ if (retval == 0) {
+ *user_report_type = report_type;
+ retval = count;
+ } else
+ *user_report_type = INVALID_REPORT_TYPE;
+
+ return retval;
+}
+
+static ssize_t synaptics_rmi4_f54_user_report_type1_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return set_user_report_type(&f54->user_report_type1, buf, count);
+}
+
+static ssize_t synaptics_rmi4_f54_user_report_type2_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return set_user_report_type(&f54->user_report_type2, buf, count);
+}
+
+static void set_report_size(void)
+{
+ unsigned char rx = f54->rmi4_data->num_of_rx;
+ unsigned char tx = f54->rmi4_data->num_of_tx;
+
+ switch (f54->report_type) {
+ case F54_8BIT_IMAGE:
+ f54->report_size = rx * tx;
+ break;
+ case F54_16BIT_IMAGE:
+ case F54_RAW_16BIT_IMAGE:
+ case F54_TRUE_BASELINE:
+ case F54_FULL_RAW_CAP:
+ case F54_FULL_RAW_CAP_RX_COUPLING_COMP:
+ case F54_SENSOR_SPEED:
+ case F54_ADC_RANGE:
+ f54->report_size = 2 * rx * tx;
+ break;
+ case F54_HIGH_RESISTANCE:
+ f54->report_size = HIGH_RESISTANCE_DATA_SIZE;
+ break;
+ case F54_TX_TO_TX_SHORT:
+ case F54_TX_OPEN:
+ case F54_TX_TO_GROUND:
+ f54->report_size = (tx + 7) / 8;
+ break;
+ case F54_RX_TO_RX1:
+ case F54_RX_OPENS1:
+ if (rx < tx)
+ f54->report_size = 2 * rx * rx;
+ else
+ f54->report_size = 2 * rx * tx;
+ break;
+ case F54_FULL_RAW_CAP_MIN_MAX:
+ f54->report_size = FULL_RAW_CAP_MIN_MAX_DATA_SIZE;
+ break;
+ case F54_RX_TO_RX2:
+ case F54_RX_OPENS2:
+ if (rx <= tx)
+ f54->report_size = 0;
+ else
+ f54->report_size = 2 * rx * (rx - tx);
+ break;
+ case F54_TREX_OPENS:
+ case F54_TREX_TO_GND:
+ case F54_TREX_SHORTS:
+ f54->report_size = TREX_DATA_SIZE;
+ break;
+ default:
+ f54->report_size = 0;
+ }
+
+ return;
+}
+
+static int set_interrupt(bool set)
+{
+ int retval;
+ unsigned char ii;
+ unsigned char zero = 0x00;
+ unsigned char *intr_mask;
+ unsigned short f01_ctrl_reg;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ intr_mask = rmi4_data->intr_mask;
+ f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + f54->intr_reg_num;
+
+ if (!set) {
+ retval = f54->fn_ptr->write(rmi4_data,
+ f01_ctrl_reg,
+ &zero,
+ sizeof(zero));
+ if (retval < 0)
+ return retval;
+ }
+
+ for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) {
+ if (intr_mask[ii] != 0x00) {
+ f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + ii;
+ if (set) {
+ retval = f54->fn_ptr->write(rmi4_data,
+ f01_ctrl_reg,
+ &zero,
+ sizeof(zero));
+ if (retval < 0)
+ return retval;
+ } else {
+ retval = f54->fn_ptr->write(rmi4_data,
+ f01_ctrl_reg,
+ &(intr_mask[ii]),
+ sizeof(intr_mask[ii]));
+ if (retval < 0)
+ return retval;
+ }
+ }
+ }
+
+ f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + f54->intr_reg_num;
+
+ if (set) {
+ retval = f54->fn_ptr->write(rmi4_data,
+ f01_ctrl_reg,
+ &f54->intr_mask,
+ 1);
+ if (retval < 0)
+ return retval;
+ }
+
+ return 0;
+}
+
+#ifdef WATCHDOG_HRTIMER
+static void timeout_set_status(struct work_struct *work)
+{
+ int retval;
+ unsigned char command;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ mutex_lock(&f54->status_mutex);
+ if (f54->status == STATUS_BUSY) {
+ retval = f54->fn_ptr->read(rmi4_data,
+ f54->command_base_addr,
+ &command,
+ sizeof(command));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read command register\n",
+ __func__);
+ } else if (command & COMMAND_GET_REPORT) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Report type not supported by FW\n",
+ __func__);
+ } else {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Get report not detected\n",
+ __func__);
+ }
+ f54->status = -ETIMEDOUT;
+ f54->report_type = INVALID_REPORT_TYPE;
+ f54->report_size = 0;
+ set_interrupt(false);
+ wake_unlock(&f54->test_wake_lock);
+ }
+ mutex_unlock(&f54->status_mutex);
+
+ return;
+}
+
+static enum hrtimer_restart get_report_timeout(struct hrtimer *timer)
+{
+ schedule_work(&(f54->timeout_work));
+
+ return HRTIMER_NORESTART;
+}
+#endif
+
+#ifdef RAW_HEX
+static void print_raw_hex_report(void)
+{
+ unsigned int ii;
+
+ pr_info("%s: Report data (raw hex)\n", __func__);
+
+ switch (f54->report_type) {
+ case F54_16BIT_IMAGE:
+ case F54_RAW_16BIT_IMAGE:
+ case F54_HIGH_RESISTANCE:
+ case F54_TRUE_BASELINE:
+ case F54_FULL_RAW_CAP_MIN_MAX:
+ case F54_FULL_RAW_CAP:
+ case F54_FULL_RAW_CAP_RX_COUPLING_COMP:
+ case F54_SENSOR_SPEED:
+ case F54_ADC_RANGE:
+ for (ii = 0; ii < f54->report_size; ii += 2) {
+ pr_info("%03d: 0x%02x%02x\n",
+ ii / 2,
+ f54->report_data[ii + 1],
+ f54->report_data[ii]);
+ }
+ break;
+ default:
+ for (ii = 0; ii < f54->report_size; ii++)
+ pr_info("%03d: 0x%02x\n", ii, f54->report_data[ii]);
+ break;
+ }
+
+ return;
+}
+#endif
+
+#ifdef HUMAN_READABLE
+static void print_image_report(void)
+{
+ unsigned int ii;
+ unsigned int jj;
+ short *report_data;
+
+ switch (f54->report_type) {
+ case F54_16BIT_IMAGE:
+ case F54_RAW_16BIT_IMAGE:
+ case F54_TRUE_BASELINE:
+ case F54_FULL_RAW_CAP:
+ case F54_FULL_RAW_CAP_RX_COUPLING_COMP:
+ pr_info("%s: Report data (image)\n", __func__);
+
+ report_data = (short *)f54->report_data;
+
+ for (ii = 0; ii < f54->rmi4_data->num_of_tx; ii++) {
+ for (jj = 0; jj < f54->rmi4_data->num_of_rx; jj++) {
+ if (*report_data < -64)
+ pr_cont(".");
+ else if (*report_data < 0)
+ pr_cont("-");
+ else if (*report_data > 64)
+ pr_cont("*");
+ else if (*report_data > 0)
+ pr_cont("+");
+ else
+ pr_cont("0");
+
+ report_data++;
+ }
+ pr_info("");
+ }
+ pr_info("%s: End of report\n", __func__);
+ break;
+ default:
+ pr_info("%s: Image not supported for report type %d\n",
+ __func__, f54->report_type);
+ }
+
+ return;
+}
+#endif
+
+static void free_control_mem(void)
+{
+ struct f54_control control = f54->control;
+
+ kfree(control.reg_0);
+ kfree(control.reg_1);
+ kfree(control.reg_2);
+ kfree(control.reg_3);
+ kfree(control.reg_4__6);
+ kfree(control.reg_7);
+ kfree(control.reg_8__9);
+ kfree(control.reg_10);
+ kfree(control.reg_11);
+ kfree(control.reg_12__13);
+ kfree(control.reg_14);
+ kfree(control.reg_15->data);
+ kfree(control.reg_15);
+ kfree(control.reg_16->data);
+ kfree(control.reg_16);
+ kfree(control.reg_17->data);
+ kfree(control.reg_17);
+ kfree(control.reg_18->data);
+ kfree(control.reg_18);
+ kfree(control.reg_19->data);
+ kfree(control.reg_19);
+ kfree(control.reg_20);
+ kfree(control.reg_21);
+ kfree(control.reg_22__26);
+ kfree(control.reg_27);
+ kfree(control.reg_28);
+ kfree(control.reg_29);
+ kfree(control.reg_30);
+ kfree(control.reg_31);
+ kfree(control.reg_32__35);
+ kfree(control.reg_36->data);
+ kfree(control.reg_36);
+ kfree(control.reg_37->data);
+ kfree(control.reg_37);
+ kfree(control.reg_38->data);
+ kfree(control.reg_38);
+ kfree(control.reg_39->data);
+ kfree(control.reg_39);
+ kfree(control.reg_40->data);
+ kfree(control.reg_40);
+ kfree(control.reg_89);
+ kfree(control.reg_95->data);
+ kfree(control.reg_95);
+ kfree(control.reg_99);
+ kfree(control.reg_99);
+
+ return;
+}
+
+static void free_data_mem(void)
+{
+ struct f54_data data = f54->data;
+
+ kfree(data.reg_4);
+ kfree(data.reg_6);
+ kfree(data.reg_7_0);
+ kfree(data.reg_7_1);
+ kfree(data.reg_8);
+ kfree(data.reg_9);
+ kfree(data.reg_10);
+ kfree(data.reg_14);
+ kfree(data.reg_16);
+ kfree(data.reg_17);
+}
+
+static void remove_sysfs(void)
+{
+ int reg_num;
+
+ sysfs_remove_bin_file(f54->attr_dir, &dev_report_data);
+
+ sysfs_remove_group(f54->attr_dir, &attr_group);
+
+ for (reg_num = 0; reg_num < ARRAY_SIZE(attrs_ctrl_regs); reg_num++)
+ sysfs_remove_group(f54->attr_dir, &attrs_ctrl_regs[reg_num]);
+
+ for (reg_num = 0; reg_num < ARRAY_SIZE(attrs_data_regs); reg_num++)
+ sysfs_remove_group(f54->attr_dir, &attrs_data_regs[reg_num]);
+
+ kobject_put(f54->attr_dir);
+
+ return;
+}
+
+static int synaptics_rmi4_f54_reset(void)
+{
+ int retval;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ mutex_lock(&f54->status_mutex);
+
+ rmi4_data->irq_enable(rmi4_data, false);
+
+ retval = rmi4_data->reset_device(rmi4_data);
+
+ rmi4_data->irq_enable(rmi4_data, true);
+
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to issue reset command, error = %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ f54->status = STATUS_IDLE;
+
+ mutex_unlock(&f54->status_mutex);
+
+ return 0;
+}
+
+static ssize_t synaptics_rmi4_f54_reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned int reset;
+
+ if (sscanf(buf, "%u", &reset) != 1)
+ return -EINVAL;
+
+ if (reset != 1)
+ return -EINVAL;
+
+ retval = synaptics_rmi4_f54_reset();
+ if (retval < 0)
+ return retval;
+
+ return count;
+}
+
+static ssize_t synaptics_rmi4_f54_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", f54->status);
+}
+
+static ssize_t synaptics_rmi4_f54_report_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", f54->report_size);
+}
+
+static ssize_t synaptics_rmi4_f54_num_of_mapped_rx_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", f54->rmi4_data->num_of_rx);
+}
+
+static ssize_t synaptics_rmi4_f54_num_of_mapped_tx_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", f54->rmi4_data->num_of_tx);
+}
+
+static ssize_t synaptics_rmi4_f54_no_auto_cal_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", f54->no_auto_cal);
+}
+
+static ssize_t synaptics_rmi4_f54_no_auto_cal_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned char data;
+ unsigned long setting;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ retval = sstrtoul(buf, 10, &setting);
+ if (retval)
+ return retval;
+
+ if (setting > 1)
+ return -EINVAL;
+
+ retval = f54->fn_ptr->read(rmi4_data,
+ f54->control_base_addr,
+ &data,
+ sizeof(data));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read control register\n",
+ __func__);
+ return retval;
+ }
+
+ if ((data & NO_AUTO_CAL_MASK) == setting)
+ return count;
+
+ data = (data & ~NO_AUTO_CAL_MASK) | (data & NO_AUTO_CAL_MASK);
+
+ retval = f54->fn_ptr->write(rmi4_data,
+ f54->control_base_addr,
+ &data,
+ sizeof(data));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to write control register\n",
+ __func__);
+ return retval;
+ }
+
+ f54->no_auto_cal = (setting == 1);
+
+ return count;
+}
+
+static ssize_t synaptics_rmi4_f54_report_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", f54->report_type);
+}
+
+static int synaptics_rmi4_f54_report_type_set(enum f54_report_types report_type)
+{
+ int retval = -EINVAL;
+ unsigned char data;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+ int report_type_valid = is_report_type_valid(report_type);
+
+ if (!report_type_valid)
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Report type not supported by driver\n", __func__);
+
+ if (report_type_valid) {
+ mutex_lock(&f54->status_mutex);
+ f54->report_type = report_type;
+ data = (unsigned char)report_type;
+ retval = f54->fn_ptr->write(rmi4_data,
+ f54->data_base_addr,
+ &data,
+ sizeof(data));
+ mutex_unlock(&f54->status_mutex);
+ } else
+ f54->report_type = INVALID_REPORT_TYPE;
+
+ if (retval < 0)
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to write data register\n", __func__);
+
+ return retval;
+}
+
+static ssize_t synaptics_rmi4_f54_report_type_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned long setting;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ retval = sstrtoul(buf, 10, &setting);
+ if (retval)
+ return retval;
+
+ if (f54->status != STATUS_BUSY) {
+ retval = synaptics_rmi4_f54_report_type_set(
+ (enum f54_report_types)setting);
+
+ if (retval < 0)
+ return retval;
+
+ return count;
+ } else {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Previous get report still ongoing\n",
+ __func__);
+ return -EINVAL;
+ }
+}
+
+static ssize_t synaptics_rmi4_f54_user_report_type1_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", f54->user_report_type1);
+}
+
+static ssize_t synaptics_rmi4_f54_user_report_type2_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", f54->user_report_type2);
+}
+
+static ssize_t synaptics_rmi4_f54_fifoindex_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int retval;
+ unsigned char data[2];
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ retval = f54->fn_ptr->read(rmi4_data,
+ f54->data_base_addr + DATA_REPORT_INDEX_OFFSET,
+ data,
+ sizeof(data));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read data registers\n",
+ __func__);
+ return retval;
+ }
+
+ batohs(&f54->fifoindex, data);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", f54->fifoindex);
+}
+static ssize_t synaptics_rmi4_f54_fifoindex_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned char data[2];
+ unsigned long setting;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ retval = sstrtoul(buf, 10, &setting);
+ if (retval)
+ return retval;
+
+ f54->fifoindex = setting;
+
+ hstoba(data, (unsigned short)setting);
+
+ retval = f54->fn_ptr->write(rmi4_data,
+ f54->data_base_addr + DATA_REPORT_INDEX_OFFSET,
+ data,
+ sizeof(data));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to write data registers\n",
+ __func__);
+ return retval;
+ }
+
+ return count;
+}
+
+ssize_t send_get_report_command(void)
+{
+ int retval;
+ unsigned char command = (unsigned char)COMMAND_GET_REPORT;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+ mutex_lock(&f54->status_mutex);
+
+ if (f54->status != STATUS_IDLE) {
+ if (f54->status != STATUS_BUSY) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Invalid status (%d)\n",
+ __func__, f54->status);
+ } else {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Previous get report still ongoing\n",
+ __func__);
+ }
+ mutex_unlock(&f54->status_mutex);
+ return -EBUSY;
+ }
+
+ wake_lock(&f54->test_wake_lock);
+ set_interrupt(true);
+ f54->status = STATUS_BUSY;
+
+ retval = f54->fn_ptr->write(rmi4_data,
+ f54->command_base_addr,
+ &command,
+ sizeof(command));
+
+ mutex_unlock(&f54->status_mutex);
+
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to write get report command\n",
+ __func__);
+ goto error_exit;
+ }
+
+#ifdef WATCHDOG_HRTIMER
+ hrtimer_start(&f54->watchdog,
+ ktime_set(WATCHDOG_TIMEOUT_S, 0),
+ HRTIMER_MODE_REL);
+#endif
+out:
+ return retval;
+
+error_exit:
+ mutex_lock(&f54->status_mutex);
+ set_interrupt(false);
+ wake_unlock(&f54->test_wake_lock);
+ f54->status = retval;
+ mutex_unlock(&f54->status_mutex);
+
+ goto out;
+}
+
+static ssize_t synaptics_rmi4_f54_get_report_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned long setting;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ retval = sstrtoul(buf, 10, &setting);
+ if (retval)
+ return retval;
+
+ if (setting != 1)
+ return -EINVAL;
+
+ if (!is_report_type_valid(f54->report_type)) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Invalid report type\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ retval = send_get_report_command();
+ if (retval < 0)
+ return retval;
+
+ return count;
+}
+
+static ssize_t synaptics_rmi4_f54_force_update_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int retval;
+ unsigned char data[1];
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ retval = f54->fn_ptr->read(rmi4_data,
+ f54->command_base_addr,
+ data,
+ sizeof(data));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read command 0 register\n",
+ __func__);
+ return retval;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ (data[0] & COMMAND_FORCE_UPDATE) == COMMAND_FORCE_UPDATE);
+}
+
+static ssize_t synaptics_rmi4_f54_force_update_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned char command;
+ unsigned long setting;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ retval = sstrtoul(buf, 10, &setting);
+ if (retval)
+ return retval;
+
+ if (setting != 1)
+ return count;
+
+ command = (unsigned char)COMMAND_FORCE_UPDATE;
+
+ if (f54->status == STATUS_BUSY)
+ return -EBUSY;
+
+ retval = f54->fn_ptr->write(rmi4_data,
+ f54->command_base_addr,
+ &command,
+ sizeof(command));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to write force update command\n",
+ __func__);
+ return retval;
+ }
+
+ return count;
+}
+
+static ssize_t synaptics_rmi4_f54_enter_in_cell_test_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int retval;
+ unsigned char data[1];
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ retval = f54->fn_ptr->read(rmi4_data,
+ f54->command_base_addr,
+ data,
+ sizeof(data));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read command 0 register\n",
+ __func__);
+ return retval;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ (data[0] & COMMAND_ENTER_IN_CELL_TESTMODE) ==
+ COMMAND_ENTER_IN_CELL_TESTMODE);
+}
+
+
+static ssize_t synaptics_rmi4_f54_enter_in_cell_test_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned char command;
+ unsigned long setting;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ retval = sstrtoul(buf, 10, &setting);
+ if (retval)
+ return retval;
+
+ if (setting != 1)
+ return count;
+
+ command = (unsigned char)COMMAND_ENTER_IN_CELL_TESTMODE;
+
+ if (f54->status == STATUS_BUSY)
+ return -EBUSY;
+
+ retval = f54->fn_ptr->write(rmi4_data,
+ f54->command_base_addr,
+ &command,
+ sizeof(command));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to write Enter In-Cell Test Mode command\n",
+ __func__);
+ return retval;
+ }
+
+ return count;
+}
+
+
+static ssize_t synaptics_rmi4_f54_force_cal_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned char command;
+ unsigned long setting;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ retval = sstrtoul(buf, 10, &setting);
+ if (retval)
+ return retval;
+
+ if (setting != 1)
+ return count;
+
+ command = (unsigned char)COMMAND_FORCE_CAL;
+
+ if (f54->status == STATUS_BUSY)
+ return -EBUSY;
+
+ retval = f54->fn_ptr->write(rmi4_data,
+ f54->command_base_addr,
+ &command,
+ sizeof(command));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to write force cal command\n",
+ __func__);
+ return retval;
+ }
+
+ return count;
+}
+
+simple_show_func_unsigned(query, num_of_rx_electrodes)
+simple_show_func_unsigned(query, num_of_tx_electrodes)
+simple_show_func_unsigned(query, has_image16)
+simple_show_func_unsigned(query, has_image8)
+simple_show_func_unsigned(query, has_baseline)
+simple_show_func_unsigned(query, clock_rate)
+simple_show_func_unsigned(query, touch_controller_family)
+simple_show_func_unsigned(query, has_pixel_touch_threshold_adjustment)
+simple_show_func_unsigned(query, has_sensor_assignment)
+simple_show_func_unsigned(query, has_interference_metric)
+simple_show_func_unsigned(query, has_sense_frequency_control)
+simple_show_func_unsigned(query, has_firmware_noise_mitigation)
+simple_show_func_unsigned(query, has_two_byte_report_rate)
+simple_show_func_unsigned(query, has_one_byte_report_rate)
+simple_show_func_unsigned(query, has_relaxation_control)
+simple_show_func_unsigned(query, curve_compensation_mode)
+simple_show_func_unsigned(query, has_iir_filter)
+simple_show_func_unsigned(query, has_cmn_removal)
+simple_show_func_unsigned(query, has_cmn_maximum)
+simple_show_func_unsigned(query, has_touch_hysteresis)
+simple_show_func_unsigned(query, has_edge_compensation)
+simple_show_func_unsigned(query, has_per_frequency_noise_control)
+simple_show_func_unsigned(query, has_enhanced_stretch)
+simple_show_func_unsigned(query, has_force_fast_relaxation)
+simple_show_func_unsigned(query, has_multi_metric_state_machine)
+simple_show_func_unsigned(query, has_signal_clarity)
+simple_show_func_unsigned(query, has_variance_metric)
+simple_show_func_unsigned(query, has_0d_relaxation_control)
+simple_show_func_unsigned(query, has_0d_acquisition_control)
+simple_show_func_unsigned(query, has_status)
+simple_show_func_unsigned(query, has_slew_metric)
+simple_show_func_unsigned(query, has_h_blank)
+simple_show_func_unsigned(query, has_v_blank)
+simple_show_func_unsigned(query, has_long_h_blank)
+simple_show_func_unsigned(query, has_startup_fast_relaxation)
+simple_show_func_unsigned(query, has_esd_control)
+simple_show_func_unsigned(query, has_noise_mitigation2)
+simple_show_func_unsigned(query, has_noise_state)
+simple_show_func_unsigned(query, has_energy_ratio_relaxation)
+simple_show_func_unsigned(query12, number_of_sensing_frequencies)
+simple_show_func_unsigned(query17, q17_num_of_sense_freqs)
+show_store_func_unsigned(data, reg_4, d4_inhibit_freq_shift)
+show_store_func_unsigned(data, reg_4, d4_baseline_sel)
+show_store_func_unsigned(data, reg_4, d4_sense_freq_sel)
+show_store_func_unsigned(data, reg_16, d16_freq_scan_im_lsb)
+show_store_func_unsigned(data, reg_16, d16_freq_scan_im_msb)
+show_store_func_unsigned(data, reg_17, d17_inhibit_freq_shift)
+show_store_func_unsigned(data, reg_17, d17_freq)
+show_func_unsigned(data, reg_6, d6_interference_metric_lsb)
+show_func_unsigned(data, reg_6, d6_interference_metric_msb)
+show_func_unsigned(data, reg_7_0, d7_current_report_rate_lsb)
+show_func_unsigned(data, reg_7_1, d7_current_report_rate_msb)
+show_func_unsigned(data, reg_8, d8_variance_metric_lsb)
+show_func_unsigned(data, reg_8, d8_variance_metric_msb)
+show_func_unsigned(data, reg_9, d9_averaged_im_lsb)
+show_func_unsigned(data, reg_9, d9_averaged_im_msb)
+show_func_unsigned(data, reg_10, d10_noise_state)
+show_func_unsigned(data, reg_14, d14_cid_im_lsb)
+show_func_unsigned(data, reg_14, d14_cid_im_msb)
+
+show_store_func_unsigned(control, reg_0, no_relax)
+show_store_func_unsigned(control, reg_0, no_scan)
+show_store_func_unsigned(control, reg_1, bursts_per_cluster)
+show_store_func_unsigned(control, reg_2, saturation_cap)
+show_store_func_unsigned(control, reg_3, pixel_touch_threshold)
+show_store_func_unsigned(control, reg_4__6, rx_feedback_cap)
+show_store_func_unsigned(control, reg_4__6, low_ref_cap)
+show_store_func_unsigned(control, reg_4__6, low_ref_feedback_cap)
+show_store_func_unsigned(control, reg_4__6, low_ref_polarity)
+show_store_func_unsigned(control, reg_4__6, high_ref_cap)
+show_store_func_unsigned(control, reg_4__6, high_ref_feedback_cap)
+show_store_func_unsigned(control, reg_4__6, high_ref_polarity)
+show_store_func_unsigned(control, reg_7, cbc_cap)
+show_store_func_unsigned(control, reg_7, cbc_polarity)
+show_store_func_unsigned(control, reg_7, cbc_tx_carrier_selection)
+show_store_func_unsigned(control, reg_8__9, integration_duration)
+show_store_func_unsigned(control, reg_8__9, reset_duration)
+show_store_func_unsigned(control, reg_10, noise_sensing_bursts_per_image)
+show_store_func_unsigned(control, reg_12__13, slow_relaxation_rate)
+show_store_func_unsigned(control, reg_12__13, fast_relaxation_rate)
+show_store_func_unsigned(control, reg_14, rxs_on_xaxis)
+show_store_func_unsigned(control, reg_14, curve_comp_on_txs)
+show_store_func_unsigned(control, reg_20, disable_noise_mitigation)
+show_store_func_unsigned(control, reg_21, freq_shift_noise_threshold)
+show_store_func_unsigned(control, reg_22__26, medium_noise_threshold)
+show_store_func_unsigned(control, reg_22__26, high_noise_threshold)
+show_store_func_unsigned(control, reg_22__26, noise_density)
+show_store_func_unsigned(control, reg_22__26, frame_count)
+show_store_func_unsigned(control, reg_27, iir_filter_coef)
+show_store_func_unsigned(control, reg_28, quiet_threshold)
+show_store_func_unsigned(control, reg_29, cmn_filter_disable)
+show_store_func_unsigned(control, reg_30, cmn_filter_max)
+show_store_func_unsigned(control, reg_31, touch_hysteresis)
+show_store_func_unsigned(control, reg_32__35, rx_low_edge_comp)
+show_store_func_unsigned(control, reg_32__35, rx_high_edge_comp)
+show_store_func_unsigned(control, reg_32__35, tx_low_edge_comp)
+show_store_func_unsigned(control, reg_32__35, tx_high_edge_comp)
+
+show_replicated_func_unsigned(control, reg_15, sensor_rx_assignment)
+show_replicated_func_unsigned(control, reg_16, sensor_tx_assignment)
+show_replicated_func_unsigned(control, reg_17, disable)
+show_replicated_func_unsigned(control, reg_17, filter_bandwidth)
+show_replicated_func_unsigned(control, reg_19, stretch_duration)
+show_replicated_func_unsigned(control, reg_38, noise_control_1)
+show_replicated_func_unsigned(control, reg_39, noise_control_2)
+show_replicated_func_unsigned(control, reg_40, noise_control_3)
+
+show_store_replicated_func_unsigned(control, reg_36, axis1_comp)
+show_store_replicated_func_unsigned(control, reg_37, axis2_comp)
+
+show_store_func_unsigned(control, reg_89, c89_cid_sel_opt)
+show_store_func_unsigned(control, reg_89, c89_cid_voltage_sel)
+show_store_func_unsigned(control, reg_89, c89_cid_im_noise_threshold_lsb)
+show_store_func_unsigned(control, reg_89, c89_cid_im_noise_threshold_msb)
+show_store_func_unsigned(control, reg_89, c89_fnm_pixel_touch_mult)
+show_store_func_unsigned(control, reg_89, c89_freq_scan_threshold_lsb)
+show_store_func_unsigned(control, reg_89, c89_freq_scan_threshold_msb)
+show_store_func_unsigned(control, reg_89, c89_quiet_im_threshold_lsb)
+show_store_func_unsigned(control, reg_89, c89_quiet_im_threshold_msb)
+
+show_store_func_unsigned(control, reg_93, c93_freq_shift_noise_threshold_lsb)
+show_store_func_unsigned(control, reg_93, c93_freq_shift_noise_threshold_msb)
+
+show_store_replicated_func_unsigned(control, reg_95, c95_disable)
+show_store_replicated_func_unsigned(control, reg_95, c95_filter_bw)
+show_store_replicated_func_unsigned(control, reg_95, c95_first_burst_length_lsb)
+show_store_replicated_func_unsigned(control, reg_95, c95_first_burst_length_msb)
+show_store_replicated_func_unsigned(control, reg_95, c95_addl_burst_length_lsb)
+show_store_replicated_func_unsigned(control, reg_95, c95_addl_burst_length_msb)
+show_store_replicated_func_unsigned(control, reg_95, c95_i_stretch)
+show_store_replicated_func_unsigned(control, reg_95, c95_r_stretch)
+show_store_replicated_func_unsigned(control, reg_95, c95_noise_control1)
+show_store_replicated_func_unsigned(control, reg_95, c95_noise_control2)
+show_store_replicated_func_unsigned(control, reg_95, c95_noise_control3)
+show_store_replicated_func_unsigned(control, reg_95, c95_noise_control4)
+
+show_store_func_unsigned(control, reg_99, c99_int_dur_lsb)
+show_store_func_unsigned(control, reg_99, c99_int_dur_msb)
+show_store_func_unsigned(control, reg_99, c99_reset_dur)
+
+show_store_func_unsigned(control, reg_107, c107_abs_int_dur)
+show_store_func_unsigned(control, reg_107, c107_abs_reset_dur)
+show_store_func_unsigned(control, reg_107, c107_abs_filter_bw)
+show_store_func_unsigned(control, reg_107, c107_abs_rstretch)
+show_store_func_unsigned(control, reg_107, c107_abs_burst_count_1)
+show_store_func_unsigned(control, reg_107, c107_abs_burst_count_2)
+show_store_func_unsigned(control, reg_107, c107_abs_stretch_dur)
+show_store_func_unsigned(control, reg_107, c107_abs_adc_clock_div)
+show_store_func_unsigned(control, reg_107, c107_abs_sub_burtst_size)
+show_store_func_unsigned(control, reg_107, c107_abs_trigger_delay)
+
+show_store_func_unsigned(control, reg_137, c137_cmnr_adjust)
+
+simple_show_func_unsigned(query_f55_0_2, f55_q2_has_single_layer_multitouch)
+show_func_unsigned(control, reg_0_f55, f55_c0_receivers_on_x)
+show_func_unsigned(control, reg_8_f55, f55_c8_pattern_type)
+
+static ssize_t synaptics_rmi4_f54_burst_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int retval;
+ int size = 0;
+ unsigned char ii;
+ unsigned char *temp;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ mutex_lock(&f54->control_mutex);
+
+ retval = f54->fn_ptr->read(rmi4_data,
+ f54->control.reg_17->address,
+ (unsigned char *)f54->control.reg_17->data,
+ f54->control.reg_17->length);
+ if (retval < 0) {
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read control reg_17\n",
+ __func__);
+ }
+
+ retval = f54->fn_ptr->read(rmi4_data,
+ f54->control.reg_18->address,
+ (unsigned char *)f54->control.reg_18->data,
+ f54->control.reg_18->length);
+ if (retval < 0) {
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read control reg_18\n",
+ __func__);
+ }
+
+ mutex_unlock(&f54->control_mutex);
+
+ temp = buf;
+
+ for (ii = 0; ii < f54->control.reg_17->length; ii++) {
+ retval = snprintf(temp, PAGE_SIZE - size, "%u ", (1 << 8) *
+ f54->control.reg_17->data[ii].burst_count_b8__10 +
+ f54->control.reg_18->data[ii].burst_count_b0__7);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Faild to write output\n",
+ __func__);
+ return retval;
+ }
+ size += retval;
+ temp += retval;
+ }
+
+ retval = snprintf(temp, PAGE_SIZE - size, "\n");
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Faild to write null terminator\n",
+ __func__);
+ return retval;
+ }
+
+ return size + retval;
+}
+
+static ssize_t synaptics_rmi4_f54_user_get_report_show(
+ char *buf, enum f54_report_types report_type)
+{
+ int retval;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ if (f54->status != STATUS_IDLE) {
+ if (f54->status == STATUS_BUSY)
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: WARNING: Resetting in busy state\n",
+ __func__);
+
+ retval = synaptics_rmi4_f54_reset();
+ if (retval < 0)
+ goto out;
+ }
+
+ retval = synaptics_rmi4_f54_report_type_set(report_type);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to set report type\n", __func__);
+ goto out;
+ }
+
+ retval = send_get_report_command();
+
+out:
+ retval = scnprintf(buf, PAGE_SIZE, "%d\n", retval);
+ return retval;
+}
+
+static ssize_t synaptics_rmi4_f54_user_get_report1_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return synaptics_rmi4_f54_user_get_report_show(
+ buf, f54->user_report_type1);
+}
+
+static ssize_t synaptics_rmi4_f54_user_get_report2_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return synaptics_rmi4_f54_user_get_report_show(
+ buf, f54->user_report_type2);
+}
+
+static ssize_t synaptics_rmi4_f54_data_read(struct file *data_file,
+ struct kobject *kobj, struct bin_attribute *attributes,
+ char *buf, loff_t pos, size_t count)
+{
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ mutex_lock(&f54->data_mutex);
+
+ if (!f54->report_data || !f54->report_size) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Report type %d data not available\n",
+ __func__, f54->report_type);
+ mutex_unlock(&f54->data_mutex);
+ return -EINVAL;
+ }
+ if (pos > f54->report_size || pos < 0) {
+ mutex_unlock(&f54->data_mutex);
+ return 0;
+ }
+
+ count = min_t(loff_t, count, f54->report_size - pos);
+ memcpy(buf, f54->report_data + pos, count);
+ mutex_unlock(&f54->data_mutex);
+ return count;
+}
+
+static int synaptics_rmi4_f54_set_sysfs(void)
+{
+ int retval;
+ int reg_num;
+ int dreg_num;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ f54->attr_dir = kobject_create_and_add("f54",
+ &rmi4_data->i2c_client->dev.kobj);
+ if (!f54->attr_dir) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create sysfs directory\n",
+ __func__);
+ goto exit_1;
+ }
+
+ retval = sysfs_create_bin_file(f54->attr_dir, &dev_report_data);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create sysfs bin file\n",
+ __func__);
+ goto exit_2;
+ }
+
+ retval = sysfs_create_group(f54->attr_dir, &attr_group);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create sysfs attributes\n",
+ __func__);
+ goto exit_3;
+ }
+
+ for (reg_num = 0; reg_num < ARRAY_SIZE(attrs_ctrl_regs); reg_num++) {
+ if (attrs_ctrl_regs_exist[reg_num]) {
+ retval = sysfs_create_group(f54->attr_dir,
+ &attrs_ctrl_regs[reg_num]);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create sysfs attributes\n",
+ __func__);
+ goto exit_4;
+ }
+ }
+ }
+
+ for (dreg_num = 0; dreg_num < ARRAY_SIZE(attrs_data_regs); dreg_num++) {
+ if (attrs_data_regs_exist[dreg_num]) {
+ retval = sysfs_create_group(f54->attr_dir,
+ &attrs_data_regs[dreg_num]);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create sysfs attributes for data register %d\n",
+ __func__, dreg_num);
+ goto exit_5;
+ }
+ }
+ }
+
+ return 0;
+
+exit_5:
+ for (dreg_num--; dreg_num >= 0; dreg_num--)
+ sysfs_remove_group(f54->attr_dir, &attrs_data_regs[dreg_num]);
+
+exit_4:
+ for (reg_num--; reg_num >= 0; reg_num--)
+ sysfs_remove_group(f54->attr_dir, &attrs_ctrl_regs[reg_num]);
+
+ sysfs_remove_group(f54->attr_dir, &attr_group);
+
+exit_3:
+ sysfs_remove_bin_file(f54->attr_dir, &dev_report_data);
+
+exit_2:
+ kobject_put(f54->attr_dir);
+
+exit_1:
+ return -ENODEV;
+}
+
+/*
+ * Fill in base register address and offset of F54
+ * control registers to allow run time patching
+ */
+int synaptics_rmi4_scan_f54_ctrl_reg_info(
+ struct synaptics_rmi4_func_packet_regs *f54_ctrl_regs)
+{
+ int ii, error = f54_ctrl_regs->nr_regs;
+ unsigned char *data;
+ struct synaptics_rmi4_packet_reg *reg;
+ struct synaptics_rmi4_subpkt *subpkt;
+
+ f54_ctrl_regs->base_addr = f54->control_base_addr;
+ for (ii = 0; ii < f54_ctrl_regs->nr_regs; ii++) {
+ reg = &f54_ctrl_regs->regs[ii];
+ subpkt = &reg->subpkt[0];
+ if (reg->r_number == 2 && f54->control.reg_2) {
+ data = kzalloc(sizeof(f54->control.reg_2->data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ /* need an offset off of base address here */
+ reg->offset = f54->control.reg_2->address -
+ f54->control_base_addr;
+ reg->size = 2;
+ reg->data = data;
+ subpkt->present = true;
+ subpkt->offset = 0;
+ error--;
+ continue;
+ }
+
+ if (reg->r_number == 95 && f54->control.reg_95) {
+ int jj, num_of_subpkts;
+ data = kzalloc(f54->control.reg_95->length, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ /* need an offset off of base address here */
+ reg->offset = f54->control.reg_95->address -
+ f54->control_base_addr;
+ reg->size = f54->control.reg_95->length;
+ reg->data = data;
+ /* not going over the number of predefined subpackets */
+ num_of_subpkts = min((int)reg->nr_subpkts,
+ (int)(f54->control.reg_95->length /
+ subpkt->size));
+ for (jj = 0; jj < num_of_subpkts; jj++) {
+ subpkt = &reg->subpkt[jj];
+ subpkt->present = true;
+ subpkt->offset = jj * subpkt->size;
+ }
+ error--;
+ }
+ }
+ return error;
+}
+
+/*
+ * Fill in base register address and offset of F54
+ * command register to allow run time patching
+ */
+int synaptics_rmi4_scan_f54_cmd_reg_info(
+ struct synaptics_rmi4_func_packet_regs *f54_cmd_regs)
+{
+ unsigned char *data;
+ struct synaptics_rmi4_packet_reg *reg = f54_cmd_regs->regs;
+ struct synaptics_rmi4_subpkt *subpkt = &reg->subpkt[0];
+
+ f54_cmd_regs->base_addr = f54->command_base_addr;
+ data = kzalloc(1, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ reg->offset = 0;
+ reg->size = 1;
+ reg->data = data;
+ subpkt->present = true;
+ subpkt->offset = 0;
+ return 0;
+}
+
+/*
+ * Fill in base register address and offset of F54 query
+ * register 12 to allow run time access
+ */
+int synaptics_rmi4_scan_f54_query_reg_info(
+ struct synaptics_rmi4_func_packet_regs *f54_query_regs)
+{
+ struct synaptics_rmi4_packet_reg *reg = f54_query_regs->regs;
+ struct synaptics_rmi4_subpkt *subpkt = &reg->subpkt[0];
+ unsigned char *data = kzalloc(sizeof(f54->query12.data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ f54_query_regs->base_addr = f54->query_base_addr;
+ /* need an offset off of base address here */
+ reg->offset = 12;
+ reg->size = sizeof(f54->query12.data);
+ reg->data = data;
+ subpkt->present = true;
+ subpkt->offset = 0;
+ return 0;
+}
+
+/*
+ * Fill in base register address and offset of F54 data
+ * registers 10 & 17 to allow run time access
+ */
+int synaptics_rmi4_scan_f54_data_reg_info(
+ struct synaptics_rmi4_func_packet_regs *f54_data_regs)
+{
+ int ii, error = f54_data_regs->nr_regs;
+ unsigned char *data;
+ struct synaptics_rmi4_subpkt *subpkt;
+ struct synaptics_rmi4_packet_reg *reg;
+
+ f54_data_regs->base_addr = f54->data_base_addr;
+ for (ii = 0; ii < f54_data_regs->nr_regs; ii++) {
+ reg = &f54_data_regs->regs[ii];
+ if (reg->r_number == 6 && f54->data.reg_6) {
+ subpkt = &reg->subpkt[0];
+ data = kzalloc(sizeof(f54->data.reg_6->data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ /* need an offset off of base address here */
+ reg->offset = f54->data.reg_6->address -
+ f54->data_base_addr;
+ reg->size = sizeof(f54->data.reg_6->data);
+ reg->data = data;
+ subpkt->present = true;
+ subpkt->offset = 0;
+ error--;
+ continue;
+ }
+
+ if (reg->r_number == 10 && f54->data.reg_10) {
+ subpkt = &reg->subpkt[0];
+ data = kzalloc(sizeof(f54->data.reg_10->data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ /* need an offset off of base address here */
+ reg->offset = f54->data.reg_10->address -
+ f54->data_base_addr;
+ reg->size = sizeof(f54->data.reg_10->data);
+ reg->data = data;
+ subpkt->present = true;
+ subpkt->offset = 0;
+ error--;
+ continue;
+ }
+
+ if (reg->r_number == 14 && f54->data.reg_14) {
+ subpkt = &reg->subpkt[0];
+ data = kzalloc(sizeof(f54->data.reg_14->data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ /* need an offset off of base address here */
+ reg->offset = f54->data.reg_14->address -
+ f54->data_base_addr;
+ reg->size = sizeof(f54->data.reg_14->data);
+ reg->data = data;
+ subpkt->present = true;
+ subpkt->offset = 0;
+ error--;
+ continue;
+ }
+
+ if (reg->r_number == 16 && f54->data.reg_16) {
+ subpkt = &reg->subpkt[0];
+ data = kzalloc(sizeof(f54->data.reg_16->data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ /* need an offset off of base address here */
+ reg->offset = f54->data.reg_16->address -
+ f54->data_base_addr;
+ reg->size = sizeof(f54->data.reg_16->data);
+ reg->data = data;
+ subpkt->present = true;
+ subpkt->offset = 0;
+ error--;
+ continue;
+ }
+
+ if (reg->r_number == 17 && f54->data.reg_17) {
+ subpkt = &reg->subpkt[0];
+ data = kzalloc(sizeof(f54->data.reg_17->data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ /* need an offset off of base address here */
+ reg->offset = f54->data.reg_17->address -
+ f54->data_base_addr;
+ reg->size = sizeof(f54->data.reg_17->data);
+ reg->data = data;
+ subpkt->present = true;
+ subpkt->offset = 0;
+ error--;
+ }
+ }
+ return error ? -ENOSYS : error;
+}
+
+static int synaptics_rmi4_f54_set_ctrl(void)
+{
+ unsigned char length;
+ unsigned char reg_num = 0;
+ unsigned short reg_addr = f54->control_base_addr;
+ struct f54_control *control = &f54->control;
+ struct f54_query *query = &f54->query;
+ struct f54_query12 *query12 = &f54->query12;
+ struct f54_query13 *query13 = &f54->query13;
+ struct f54_query15 *query15 = &f54->query15;
+ struct f54_query16 *query16 = &f54->query16;
+ struct f54_query17 *query17 = &f54->query17;
+ struct f54_query21 *query21 = &f54->query21;
+ struct f54_query22 *query22 = &f54->query22;
+ struct f54_query23 *query23 = &f54->query23;
+ struct f54_query25 *query25 = &f54->query25;
+ struct f54_query27 *query27 = &f54->query27;
+ struct f54_query29 *query29 = &f54->query29;
+ struct f54_query30 *query30 = &f54->query30;
+ struct f54_query32 *query32 = &f54->query32;
+ struct f54_query33 *query33 = &f54->query33;
+ struct f54_query35 *query35 = &f54->query35;
+ struct f54_query36 *query36 = &f54->query36;
+ struct f54_query38 *query38 = &f54->query38;
+ struct f54_query40 *query40 = &f54->query40;
+ struct f54_query46 *query46 = &f54->query46;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ /* control 0 */
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_0 = kzalloc(sizeof(*(control->reg_0)),
+ GFP_KERNEL);
+ if (!control->reg_0)
+ goto exit_no_mem;
+ control->reg_0->address = reg_addr;
+ reg_addr += sizeof(control->reg_0->data);
+ reg_num++;
+
+ /* control 1 */
+ if ((f54->query.touch_controller_family == 0) ||
+ (f54->query.touch_controller_family == 1)) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_1 = kzalloc(sizeof(*(control->reg_1)),
+ GFP_KERNEL);
+ if (!control->reg_1)
+ goto exit_no_mem;
+ control->reg_1->address = reg_addr;
+ reg_addr += sizeof(control->reg_1->data);
+ }
+ reg_num++;
+
+ /* control 2 */
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_2 = kzalloc(sizeof(*(control->reg_2)),
+ GFP_KERNEL);
+ if (!control->reg_2)
+ goto exit_no_mem;
+ control->reg_2->address = reg_addr;
+ reg_addr += sizeof(control->reg_2->data);
+ reg_num++;
+
+ /* control 3 */
+ if (f54->query.has_pixel_touch_threshold_adjustment == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_3 = kzalloc(sizeof(*(control->reg_3)),
+ GFP_KERNEL);
+ if (!control->reg_3)
+ goto exit_no_mem;
+ control->reg_3->address = reg_addr;
+ reg_addr += sizeof(control->reg_3->data);
+ }
+ reg_num++;
+
+ /* controls 4 5 6 */
+ if ((f54->query.touch_controller_family == 0) ||
+ (f54->query.touch_controller_family == 1)) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_4__6 = kzalloc(sizeof(*(control->reg_4__6)),
+ GFP_KERNEL);
+ if (!control->reg_4__6)
+ goto exit_no_mem;
+ control->reg_4__6->address = reg_addr;
+ reg_addr += sizeof(control->reg_4__6->data);
+ }
+ reg_num++;
+
+ /* control 7 */
+ if (f54->query.touch_controller_family == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_7 = kzalloc(sizeof(*(control->reg_7)),
+ GFP_KERNEL);
+ if (!control->reg_7)
+ goto exit_no_mem;
+ control->reg_7->address = reg_addr;
+ reg_addr += sizeof(control->reg_7->data);
+ }
+ reg_num++;
+
+ /* controls 8 9 */
+ if ((f54->query.touch_controller_family == 0) ||
+ (f54->query.touch_controller_family == 1)) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_8__9 = kzalloc(sizeof(*(control->reg_8__9)),
+ GFP_KERNEL);
+ if (!control->reg_8__9)
+ goto exit_no_mem;
+ control->reg_8__9->address = reg_addr;
+ reg_addr += sizeof(control->reg_8__9->data);
+ }
+ reg_num++;
+
+ /* control 10 */
+ if (f54->query.has_interference_metric == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_10 = kzalloc(sizeof(*(control->reg_10)),
+ GFP_KERNEL);
+ if (!control->reg_10)
+ goto exit_no_mem;
+ control->reg_10->address = reg_addr;
+ reg_addr += sizeof(control->reg_10->data);
+ }
+ reg_num++;
+
+ /* control 11 */
+ if (f54->query.has_ctrl11 == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_11 = kzalloc(sizeof(*(control->reg_11)),
+ GFP_KERNEL);
+ if (!control->reg_11)
+ goto exit_no_mem;
+ control->reg_11->address = reg_addr;
+ reg_addr += sizeof(control->reg_11->data);
+ }
+ reg_num++;
+
+ /* controls 12 13 */
+ if (f54->query.has_relaxation_control == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_12__13 = kzalloc(sizeof(*(control->reg_12__13)),
+ GFP_KERNEL);
+ if (!control->reg_12__13)
+ goto exit_no_mem;
+ control->reg_12__13->address = reg_addr;
+ reg_addr += sizeof(control->reg_12__13->data);
+ }
+ reg_num++;
+
+ /* controls 14 15 16 */
+ if (f54->query.has_sensor_assignment == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+
+ control->reg_14 = kzalloc(sizeof(*(control->reg_14)),
+ GFP_KERNEL);
+ if (!control->reg_14)
+ goto exit_no_mem;
+ control->reg_14->address = reg_addr;
+ reg_addr += sizeof(control->reg_14->data);
+
+ control->reg_15 = kzalloc(sizeof(*(control->reg_15)),
+ GFP_KERNEL);
+ if (!control->reg_15)
+ goto exit_no_mem;
+ control->reg_15->length = f54->query.num_of_rx_electrodes;
+ control->reg_15->data = kzalloc(control->reg_15->length *
+ sizeof(*(control->reg_15->data)), GFP_KERNEL);
+ if (!control->reg_15->data)
+ goto exit_no_mem;
+ control->reg_15->address = reg_addr;
+ reg_addr += control->reg_15->length;
+
+ control->reg_16 = kzalloc(sizeof(*(control->reg_16)),
+ GFP_KERNEL);
+ if (!control->reg_16)
+ goto exit_no_mem;
+ control->reg_16->length = f54->query.num_of_tx_electrodes;
+ control->reg_16->data = kzalloc(control->reg_16->length *
+ sizeof(*(control->reg_16->data)), GFP_KERNEL);
+ if (!control->reg_16->data)
+ goto exit_no_mem;
+ control->reg_16->address = reg_addr;
+ reg_addr += control->reg_16->length;
+ }
+ reg_num++;
+
+ /* controls 17 18 19 */
+ if (f54->query.has_sense_frequency_control == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+
+ length = f54->query12.number_of_sensing_frequencies;
+
+ control->reg_17 = kzalloc(sizeof(*(control->reg_17)),
+ GFP_KERNEL);
+ if (!control->reg_17)
+ goto exit_no_mem;
+ control->reg_17->length = length;
+ control->reg_17->data = kzalloc(length *
+ sizeof(*(control->reg_17->data)), GFP_KERNEL);
+ if (!control->reg_17->data)
+ goto exit_no_mem;
+ control->reg_17->address = reg_addr;
+ reg_addr += length;
+
+ control->reg_18 = kzalloc(sizeof(*(control->reg_18)),
+ GFP_KERNEL);
+ if (!control->reg_18)
+ goto exit_no_mem;
+ control->reg_18->length = length;
+ control->reg_18->data = kzalloc(length *
+ sizeof(*(control->reg_18->data)), GFP_KERNEL);
+ if (!control->reg_18->data)
+ goto exit_no_mem;
+ control->reg_18->address = reg_addr;
+ reg_addr += length;
+
+ control->reg_19 = kzalloc(sizeof(*(control->reg_19)),
+ GFP_KERNEL);
+ if (!control->reg_19)
+ goto exit_no_mem;
+ control->reg_19->length = length;
+ control->reg_19->data = kzalloc(length *
+ sizeof(*(control->reg_19->data)), GFP_KERNEL);
+ if (!control->reg_19->data)
+ goto exit_no_mem;
+ control->reg_19->address = reg_addr;
+ reg_addr += length;
+ }
+ reg_num++;
+
+ /* control 20 */
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_20 = kzalloc(sizeof(*(control->reg_20)),
+ GFP_KERNEL);
+ if (!control->reg_20)
+ goto exit_no_mem;
+ control->reg_20->address = reg_addr;
+ reg_addr += sizeof(control->reg_20->data);
+ reg_num++;
+
+ /* control 21 */
+ if (f54->query.has_sense_frequency_control == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_21 = kzalloc(sizeof(*(control->reg_21)),
+ GFP_KERNEL);
+ if (!control->reg_21)
+ goto exit_no_mem;
+ control->reg_21->address = reg_addr;
+ reg_addr += sizeof(control->reg_21->data);
+ }
+ reg_num++;
+
+ /* controls 22 23 24 25 26 */
+ if (f54->query.has_firmware_noise_mitigation == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_22__26 = kzalloc(sizeof(*(control->reg_22__26)),
+ GFP_KERNEL);
+ if (!control->reg_22__26)
+ goto exit_no_mem;
+ control->reg_22__26->address = reg_addr;
+ reg_addr += sizeof(control->reg_22__26->data);
+ }
+ reg_num++;
+
+ /* control 27 */
+ if (f54->query.has_iir_filter == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_27 = kzalloc(sizeof(*(control->reg_27)),
+ GFP_KERNEL);
+ if (!control->reg_27)
+ goto exit_no_mem;
+ control->reg_27->address = reg_addr;
+ reg_addr += sizeof(control->reg_27->data);
+ }
+ reg_num++;
+
+ /* control 28 */
+ if (f54->query.has_firmware_noise_mitigation == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_28 = kzalloc(sizeof(*(control->reg_28)),
+ GFP_KERNEL);
+ if (!control->reg_28)
+ goto exit_no_mem;
+ control->reg_28->address = reg_addr;
+ reg_addr += sizeof(control->reg_28->data);
+ }
+ reg_num++;
+
+ /* control 29 */
+ if (f54->query.has_cmn_removal == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_29 = kzalloc(sizeof(*(control->reg_29)),
+ GFP_KERNEL);
+ if (!control->reg_29)
+ goto exit_no_mem;
+ control->reg_29->address = reg_addr;
+ reg_addr += sizeof(control->reg_29->data);
+ }
+ reg_num++;
+
+ /* control 30 */
+ if (f54->query.has_cmn_maximum == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_30 = kzalloc(sizeof(*(control->reg_30)),
+ GFP_KERNEL);
+ if (!control->reg_30)
+ goto exit_no_mem;
+ control->reg_30->address = reg_addr;
+ reg_addr += sizeof(control->reg_30->data);
+ }
+ reg_num++;
+
+ /* control 31 */
+ if (f54->query.has_touch_hysteresis == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_31 = kzalloc(sizeof(*(control->reg_31)),
+ GFP_KERNEL);
+ if (!control->reg_31)
+ goto exit_no_mem;
+ control->reg_31->address = reg_addr;
+ reg_addr += sizeof(control->reg_31->data);
+ }
+ reg_num++;
+
+ /* controls 32 33 34 35 */
+ if (f54->query.has_edge_compensation == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+ control->reg_32__35 = kzalloc(sizeof(*(control->reg_32__35)),
+ GFP_KERNEL);
+ if (!control->reg_32__35)
+ goto exit_no_mem;
+ control->reg_32__35->address = reg_addr;
+ reg_addr += sizeof(control->reg_32__35->data);
+ }
+ reg_num++;
+
+ /* control 36 */
+ if ((f54->query.curve_compensation_mode == 1) ||
+ (f54->query.curve_compensation_mode == 2)) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+
+ if (f54->query.curve_compensation_mode == 1) {
+ length = max(f54->query.num_of_rx_electrodes,
+ f54->query.num_of_tx_electrodes);
+ } else if (f54->query.curve_compensation_mode == 2) {
+ length = f54->query.num_of_rx_electrodes;
+ }
+
+ control->reg_36 = kzalloc(sizeof(*(control->reg_36)),
+ GFP_KERNEL);
+ if (!control->reg_36)
+ goto exit_no_mem;
+ control->reg_36->length = length;
+ control->reg_36->data = kzalloc(length *
+ sizeof(*(control->reg_36->data)), GFP_KERNEL);
+ if (!control->reg_36->data)
+ goto exit_no_mem;
+ control->reg_36->address = reg_addr;
+ reg_addr += length;
+ }
+ reg_num++;
+
+ /* control 37 */
+ if (f54->query.curve_compensation_mode == 2) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+
+ control->reg_37 = kzalloc(sizeof(*(control->reg_37)),
+ GFP_KERNEL);
+ if (!control->reg_37)
+ goto exit_no_mem;
+ control->reg_37->length = f54->query.num_of_tx_electrodes;
+ control->reg_37->data = kzalloc(control->reg_37->length *
+ sizeof(*(control->reg_37->data)), GFP_KERNEL);
+ if (!control->reg_37->data)
+ goto exit_no_mem;
+
+ control->reg_37->address = reg_addr;
+ reg_addr += control->reg_37->length;
+ }
+ reg_num++;
+
+ /* controls 38 39 40 */
+ if (f54->query.has_per_frequency_noise_control == 1) {
+ attrs_ctrl_regs_exist[reg_num] = true;
+
+ control->reg_38 = kzalloc(sizeof(*(control->reg_38)),
+ GFP_KERNEL);
+ if (!control->reg_38)
+ goto exit_no_mem;
+ control->reg_38->length =
+ f54->query12.number_of_sensing_frequencies;
+
+ control->reg_38->data = kzalloc(control->reg_38->length *
+ sizeof(*(control->reg_38->data)), GFP_KERNEL);
+ if (!control->reg_38->data)
+ goto exit_no_mem;
+ control->reg_38->address = reg_addr;
+ reg_addr += control->reg_38->length;
+
+ control->reg_39 = kzalloc(sizeof(*(control->reg_39)),
+ GFP_KERNEL);
+ if (!control->reg_39)
+ goto exit_no_mem;
+ control->reg_39->length =
+ f54->query12.number_of_sensing_frequencies;
+ control->reg_39->data = kzalloc(control->reg_39->length *
+ sizeof(*(control->reg_39->data)), GFP_KERNEL);
+ if (!control->reg_39->data)
+ goto exit_no_mem;
+ control->reg_39->address = reg_addr;
+ reg_addr += control->reg_39->length;
+
+ control->reg_40 = kzalloc(sizeof(*(control->reg_40)),
+ GFP_KERNEL);
+ if (!control->reg_40)
+ goto exit_no_mem;
+ control->reg_40->length =
+ f54->query12.number_of_sensing_frequencies;
+ control->reg_40->data = kzalloc(control->reg_40->length *
+ sizeof(*(control->reg_40->data)), GFP_KERNEL);
+ if (!control->reg_40->data)
+ goto exit_no_mem;
+ control->reg_40->address = reg_addr;
+ reg_addr += control->reg_40->length;
+ }
+ reg_num++;
+
+ CTRL_REG_PRESENCE(41, 1, query->has_signal_clarity);
+ CTRL_REG_PRESENCE(42, 2, query->has_variance_metric);
+ CTRL_REG_PRESENCE(43, 2, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(44, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(45, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(46, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(47, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(48, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(49, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(50, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(51, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(52, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(53, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(53, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(54, 1, query->has_multi_metric_state_machine);
+ CTRL_REG_PRESENCE(55, 1, query->has_0d_relaxation_control);
+ CTRL_REG_PRESENCE(56, 1, query->has_0d_relaxation_control);
+ CTRL_REG_PRESENCE(57, 1, query->has_0d_acquisition_control);
+ CTRL_REG_PRESENCE(58, 1, query->has_0d_acquisition_control);
+ CTRL_REG_PRESENCE(59, 2, query->has_h_blank);
+ CTRL_REG_PRESENCE(60, 1, query->has_h_blank || query->has_v_blank ||
+ query->has_long_h_blank);
+ CTRL_REG_PRESENCE(61, 1, query->has_h_blank || query->has_v_blank ||
+ query->has_long_h_blank);
+ CTRL_REG_PRESENCE(62, 1, query->has_h_blank || query->has_v_blank ||
+ query->has_long_h_blank);
+ CTRL_REG_PRESENCE(63, 1, query->has_h_blank || query->has_v_blank ||
+ query->has_long_h_blank ||
+ query->has_slew_metric ||
+ query->has_slew_option ||
+ query->has_noise_mitigation2);
+
+ if (query->has_h_blank) {
+ CTRL_REG_PRESENCE(64, 7, 1);
+ CTRL_REG_PRESENCE(65, 7, 1);
+ } else if (query->has_v_blank || query->has_long_h_blank) {
+ CTRL_REG_PRESENCE(64, 1, 1);
+ CTRL_REG_PRESENCE(65, 1, 1);
+ }
+
+ if (query->has_h_blank || query->has_v_blank ||
+ query->has_long_h_blank) {
+ CTRL_REG_PRESENCE(66, 1, 1);
+ CTRL_REG_PRESENCE(67, 1, 1);
+ CTRL_REG_PRESENCE(68, 1, 1);
+ CTRL_REG_PRESENCE(69, 1, 1);
+ CTRL_REG_PRESENCE(70, 1, 1);
+ CTRL_REG_PRESENCE(71, 1, 1);
+ CTRL_REG_PRESENCE(72, 2, 1);
+ CTRL_REG_PRESENCE(73, 2, 1);
+ }
+ CTRL_REG_PRESENCE(74, 2, query->has_slew_metric);
+ CTRL_REG_PRESENCE(75, query12->number_of_sensing_frequencies,
+ query->has_enhanced_stretch &&
+ query->has_sense_frequency_control);
+ CTRL_REG_PRESENCE(76, 1, query->has_startup_fast_relaxation);
+ CTRL_REG_PRESENCE(77, 1, query->has_esd_control);
+ CTRL_REG_PRESENCE(78, 1, query->has_esd_control);
+ CTRL_REG_PRESENCE(79, 1, query->has_noise_mitigation2);
+ CTRL_REG_PRESENCE(80, 1, query->has_noise_mitigation2);
+ CTRL_REG_PRESENCE(81, 1, query->has_noise_mitigation2);
+ CTRL_REG_PRESENCE(82, 1, query->has_noise_mitigation2);
+ CTRL_REG_PRESENCE(83, 1, query->has_noise_mitigation2);
+ CTRL_REG_PRESENCE(84, 1, query->has_energy_ratio_relaxation);
+ CTRL_REG_PRESENCE(85, 1, query->has_energy_ratio_relaxation);
+ CTRL_REG_PRESENCE(86, 1, query13->has_ctrl86);
+ CTRL_REG_PRESENCE(87, 1, query13->has_ctrl87);
+ CTRL_REG_PRESENCE(88, 1, query->has_ctrl88);
+
+ CTRL_REG_ADD(89, 1, query13->has_cid_im ||
+ query13->has_noise_mitigation_enh ||
+ query13->has_rail_im);
+
+ CTRL_REG_PRESENCE(90, 1, query15->has_ctrl90);
+ CTRL_REG_PRESENCE(91, 1, query21->has_ctrl91);
+ CTRL_REG_PRESENCE(92, 1, query16->has_ctrl92);
+
+ CTRL_REG_ADD(93, 1, query16->has_ctrl93);
+
+ CTRL_REG_PRESENCE(94, 1, query16->has_ctrl94_query18);
+
+ CTRL_REG_ADD_EXT(95, 1, query16->has_ctrl95_query19,
+ sizeof(struct f54_control_95n) *
+ query17->q17_num_of_sense_freqs);
+
+ CTRL_REG_PRESENCE(96, 1, query21->has_ctrl96);
+ CTRL_REG_PRESENCE(97, 1, query21->has_ctrl97);
+ CTRL_REG_PRESENCE(98, 1, query21->has_ctrl98);
+
+ CTRL_REG_ADD(99, 1, query->touch_controller_family == 2);
+
+ CTRL_REG_PRESENCE(100, 1, query16->has_ctrl100);
+ CTRL_REG_PRESENCE(101, 1, query22->has_ctrl101);
+ CTRL_REG_PRESENCE(102, 1, query23->has_ctrl102);
+ CTRL_REG_PRESENCE(103, 1, query22->has_ctrl103_query26);
+ CTRL_REG_PRESENCE(104, 1, query22->has_ctrl104);
+ CTRL_REG_PRESENCE(105, 1, query22->has_ctrl105);
+ CTRL_REG_PRESENCE(106, 1, query25->has_ctrl106);
+
+ CTRL_REG_ADD(107, 1, query25->has_ctrl107);
+
+ CTRL_REG_PRESENCE(108, 1, query25->has_ctrl108);
+ CTRL_REG_PRESENCE(109, 1, query25->has_ctrl109);
+ CTRL_REG_PRESENCE(110, 1, query27->has_ctrl110);
+ CTRL_REG_PRESENCE(111, 1, query27->has_ctrl111);
+ CTRL_REG_PRESENCE(112, 1, query27->has_ctrl112);
+ CTRL_REG_PRESENCE(113, 1, query27->has_ctrl113);
+ CTRL_REG_PRESENCE(114, 1, query27->has_ctrl114);
+ CTRL_REG_PRESENCE(115, 1, query29->has_ctrl115);
+ CTRL_REG_PRESENCE(116, 1, query29->has_ctrl116);
+ CTRL_REG_PRESENCE(117, 1, query29->has_ctrl117);
+ CTRL_REG_PRESENCE(118, 1, query30->has_ctrl118);
+ CTRL_REG_PRESENCE(119, 1, query30->has_ctrl119);
+ CTRL_REG_PRESENCE(120, 1, query30->has_ctrl120);
+ CTRL_REG_PRESENCE(121, 1, query30->has_ctrl121);
+ CTRL_REG_PRESENCE(122, 1, query30->has_ctrl122_query31);
+ CTRL_REG_PRESENCE(123, 1, query30->has_ctrl123);
+ CTRL_REG_PRESENCE(124, 1, query30->has_ctrl124);
+ CTRL_REG_PRESENCE(125, 1, query32->has_ctrl125);
+ CTRL_REG_PRESENCE(126, 1, query32->has_ctrl126);
+ CTRL_REG_PRESENCE(127, 1, query32->has_ctrl127);
+ CTRL_REG_PRESENCE(128, 1, query33->has_ctrl128);
+ CTRL_REG_PRESENCE(129, 1, query33->has_ctrl129);
+ CTRL_REG_PRESENCE(130, 1, query33->has_ctrl130);
+ CTRL_REG_PRESENCE(131, 1, query33->has_ctrl131);
+ CTRL_REG_PRESENCE(132, 1, query33->has_ctrl132);
+ CTRL_REG_PRESENCE(133, 1, query33->has_ctrl133);
+ CTRL_REG_PRESENCE(134, 1, query33->has_ctrl134);
+ CTRL_REG_PRESENCE(135, 1, query35->has_ctrl135);
+ CTRL_REG_PRESENCE(136, 1, query35->has_ctrl136);
+
+ CTRL_REG_ADD(137, 1, query35->has_ctrl137);
+
+ CTRL_REG_PRESENCE(138, 1, query35->has_ctrl138);
+ CTRL_REG_PRESENCE(139, 1, query35->has_ctrl139);
+ CTRL_REG_PRESENCE(140, 1, query35->has_ctrl140);
+ CTRL_REG_PRESENCE(141, 1, query36->has_ctrl141);
+ CTRL_REG_PRESENCE(142, 1, query36->has_ctrl142);
+ CTRL_REG_PRESENCE(143, 1, query36->has_ctrl143);
+ CTRL_REG_PRESENCE(144, 1, query36->has_ctrl144);
+ CTRL_REG_PRESENCE(145, 1, query36->has_ctrl145);
+ CTRL_REG_PRESENCE(146, 1, query36->has_ctrl146);
+ CTRL_REG_PRESENCE(147, 1, query38->has_ctrl147);
+ CTRL_REG_PRESENCE(148, 1, query38->has_ctrl148);
+ CTRL_REG_PRESENCE(149, 1, query38->has_ctrl149);
+ CTRL_REG_RESERVED_PRESENCE(150, 1, 0);
+ CTRL_REG_PRESENCE(151, 1, query38->has_ctrl151);
+ CTRL_REG_RESERVED_PRESENCE(152, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(153, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(154, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(155, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(156, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(157, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(158, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(159, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(160, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(161, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(162, 1, 0);
+ CTRL_REG_PRESENCE(163, 1, query40->has_ctrl163_query41);
+ CTRL_REG_RESERVED_PRESENCE(164, 1, 0);
+ CTRL_REG_PRESENCE(165, 1, query40->has_ctrl165_query42);
+ CTRL_REG_RESERVED_PRESENCE(166, 1, 0);
+ CTRL_REG_PRESENCE(167, 1, query40->has_ctrl167);
+ CTRL_REG_RESERVED_PRESENCE(168, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(169, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(170, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(171, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(172, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(173, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(174, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(175, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(176, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(177, 1, 0);
+ CTRL_REG_RESERVED_PRESENCE(178, 1, 0);
+ CTRL_REG_PRESENCE(179, 1, query46->has_ctrl179);
+
+ /* add F55 control registers */
+ reg_addr = f54->fn55->control_base_addr;
+
+ CTRL_REG_ADD(0_f55, 1, f54->query_f55_0_2.has_sensor_assignment);
+
+ CTRL_REG_PRESENCE(1_f55, 1, f54->query_f55_0_2.has_sensor_assignment);
+ CTRL_REG_PRESENCE(2_f55, 1, f54->query_f55_0_2.has_sensor_assignment);
+ CTRL_REG_PRESENCE(3_f55, 1, f54->query_f55_0_2.has_edge_compensation);
+ CTRL_REG_PRESENCE(4_f55, 1, f54->query_f55_0_2.curve_compensation_mode);
+ CTRL_REG_PRESENCE(5_f55, 1, f54->query_f55_0_2.curve_compensation_mode);
+ CTRL_REG_PRESENCE(6_f55, 1, f54->query_f55_0_2.has_ctrl6);
+ CTRL_REG_PRESENCE(7_f55, 1,
+ f54->query_f55_0_2.has_alternate_tx_assignment);
+
+ CTRL_REG_ADD(8_f55, 1,
+ f54->query_f55_0_2.f55_q2_has_single_layer_multitouch &&
+ f54->query_f55_3.f55_q3_has_ctrl8);
+ return 0;
+
+exit_no_mem:
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for control registers\n",
+ __func__);
+ return -ENOMEM;
+}
+
+static int synaptics_rmi4_f54_set_data(void)
+{
+ unsigned char reg_num = 0;
+ unsigned short reg_addr = f54->data_base_addr;
+ struct f54_data *data = &f54->data;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ /* data 0 - data 3: skip mandatory registers */
+ reg_addr += 4;
+
+ /* data 4 */
+ if (f54->query.has_sense_frequency_control == 1) {
+ pr_debug("d4 addr = 0x%02x num = %d\n", reg_addr, reg_num);
+ attrs_data_regs_exist[reg_num] = true;
+ data->reg_4 = kzalloc(sizeof(*data->reg_4), GFP_KERNEL);
+ if (!data->reg_4)
+ goto exit_no_mem;
+ data->reg_4->address = reg_addr;
+ reg_addr += sizeof(data->reg_4->data);
+ }
+ reg_num++;
+
+ /* F54_ANALOG_Data5 (reserved) is not present */
+ /* - do not increment */
+
+ /* data 6 */
+ if (f54->query.has_interference_metric) {
+ pr_debug("d6 addr = 0x%02x num = %d\n", reg_addr, reg_num);
+ attrs_data_regs_exist[reg_num] = true;
+ data->reg_6 = kzalloc(sizeof(*data->reg_6), GFP_KERNEL);
+ if (!data->reg_6)
+ goto exit_no_mem;
+ data->reg_6->address = reg_addr;
+ reg_addr += sizeof(data->reg_6->data);
+ }
+ reg_num++;
+
+ /* data 7.0 */
+ if (f54->query.has_one_byte_report_rate ||
+ f54->query.has_two_byte_report_rate) {
+ pr_debug("d7.0 addr = 0x%02x\n", reg_addr);
+ attrs_data_regs_exist[reg_num] = true;
+ data->reg_7_0 = kzalloc(sizeof(*data->reg_7_0), GFP_KERNEL);
+ if (!data->reg_7_0)
+ goto exit_no_mem;
+ data->reg_7_0->address = reg_addr;
+ reg_addr += 1;
+ }
+ reg_num++;
+
+ /* data 7.1 */
+ if (f54->query.has_two_byte_report_rate) {
+ pr_debug("d7.1 addr = 0x%02x\n", reg_addr);
+ attrs_data_regs_exist[reg_num] = true;
+ data->reg_7_1 = kzalloc(sizeof(*data->reg_7_1), GFP_KERNEL);
+ if (!data->reg_7_1)
+ goto exit_no_mem;
+ data->reg_7_1->address = reg_addr;
+ reg_addr += 1;
+ }
+ reg_num++;
+
+ /* data 8 */
+ if (f54->query.has_variance_metric) {
+ pr_debug("d8 addr = 0x%02x num = %d\n", reg_addr, reg_num);
+ attrs_data_regs_exist[reg_num] = true;
+ data->reg_8 = kzalloc(sizeof(*data->reg_8), GFP_KERNEL);
+ if (!data->reg_8)
+ goto exit_no_mem;
+ data->reg_8->address = reg_addr;
+ reg_addr += sizeof(data->reg_8->data);
+ }
+ reg_num++;
+
+ /* data 9 */
+ if (f54->query.has_multi_metric_state_machine) {
+ pr_debug("d9 addr = 0x%02x num = %d\n", reg_addr, reg_num);
+ attrs_data_regs_exist[reg_num] = true;
+ data->reg_9 = kzalloc(sizeof(*data->reg_9), GFP_KERNEL);
+ if (!data->reg_9)
+ goto exit_no_mem;
+ data->reg_9->address = reg_addr;
+ reg_addr += sizeof(data->reg_9->data);
+ }
+ reg_num++;
+
+ /* data 10 */
+ if (f54->query.has_multi_metric_state_machine ||
+ f54->query.has_noise_state) {
+ pr_debug("d10 addr = 0x%02x num = %d\n", reg_addr, reg_num);
+ attrs_data_regs_exist[reg_num] = true;
+ data->reg_10 = kzalloc(sizeof(*data->reg_10), GFP_KERNEL);
+ if (!data->reg_10)
+ goto exit_no_mem;
+ data->reg_10->address = reg_addr;
+ reg_addr += sizeof(data->reg_10->data);
+ }
+ reg_num++;
+
+ /* data 11 */
+ if (f54->query.has_status) {
+ pr_debug("d11 addr = 0x%02x\n", reg_addr);
+ reg_addr += 1;
+ }
+
+ /* data 12 */
+ if (f54->query.has_slew_metric) {
+ pr_debug("d12 addr = 0x%02x\n", reg_addr);
+ reg_addr += 2;
+ }
+
+ /* data 13 */
+ if (f54->query.has_multi_metric_state_machine) {
+ pr_debug("d13 addr = 0x%02x\n", reg_addr);
+ reg_addr += 2;
+ }
+
+ /* data 14 */
+ if (f54->query13.has_cid_im) {
+ pr_debug("d14 addr = 0x%02x num = %d\n", reg_addr, reg_num);
+ attrs_data_regs_exist[reg_num] = true;
+ data->reg_14 = kzalloc(sizeof(*data->reg_14), GFP_KERNEL);
+ if (!data->reg_14)
+ goto exit_no_mem;
+ data->reg_14->address = reg_addr;
+ reg_addr += 1; /* replicated register */
+ }
+ reg_num++;
+
+ /* data 15 */
+ if (f54->query13.has_rail_im) {
+ pr_debug("d15 addr = 0x%02x\n", reg_addr);
+ reg_addr += 1;
+ }
+
+ /* data 16 */
+ if (f54->query13.has_noise_mitigation_enh) {
+ pr_debug("d16 addr = 0x%02x num = %d\n", reg_addr, reg_num);
+ attrs_data_regs_exist[reg_num] = true;
+ data->reg_16 = kzalloc(sizeof(*data->reg_16), GFP_KERNEL);
+ if (!data->reg_16)
+ goto exit_no_mem;
+ data->reg_16->address = reg_addr;
+ reg_addr += 1;
+ }
+ reg_num++;
+
+ /* data 17 */
+ if (f54->query16.has_data17) {
+ pr_debug("d17 addr = 0x%02x num = %d\n", reg_addr, reg_num);
+ attrs_data_regs_exist[reg_num] = true;
+ data->reg_17 = kzalloc(sizeof(*data->reg_17), GFP_KERNEL);
+ if (!data->reg_17)
+ goto exit_no_mem;
+ data->reg_17->address = reg_addr;
+ reg_addr += sizeof(data->reg_17->data);
+ }
+ reg_num++;
+
+ return 0;
+
+exit_no_mem:
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for data registers\n",
+ __func__);
+ return -ENOMEM;
+}
+
+static int synaptics_rmi4_f55_read_query(void)
+{
+ int retval;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+ uint16_t reg_addr;
+
+ retval = f54->fn_ptr->read(rmi4_data,
+ f54->fn55->query_base_addr,
+ f54->query_f55_0_2.data,
+ sizeof(f54->query_f55_0_2.data));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read F55 query registers 0-2\n",
+ __func__);
+ goto err;
+ }
+
+ reg_addr = f54->fn55->query_base_addr;
+
+ QUERY_REG_READ(_f55_0_2, 1);
+ QUERY_REG_READ(_f55_3,
+ f54->query_f55_0_2.f55_q2_has_single_layer_multitouch);
+return 0;
+
+err:
+ return retval;
+}
+
+static void synaptics_rmi4_f54_sensor_mapping(void)
+{
+ int retval;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+ struct f54_control *control = &f54->control;
+ unsigned int rx_len;
+ unsigned int tx_len;
+ unsigned char *buffer;
+ unsigned char *rx_buffer;
+ unsigned char *tx_buffer;
+ unsigned short offset;
+ int i;
+
+ rmi4_data->num_of_rx = 0;
+ rmi4_data->num_of_tx = 0;
+
+ if (f54->query.has_sensor_assignment == 1) {
+ rx_len = control->reg_15->length;
+ tx_len = control->reg_16->length;
+ offset = control->reg_15->address;
+
+ } else if (f54->fn55) {
+ if (f54->query_f55_0_2.has_sensor_assignment) {
+ rx_len = f54->query_f55_0_2.num_of_rx_electrodes;
+ tx_len = f54->query_f55_0_2.num_of_tx_electrodes;
+
+ offset = f54->fn55->control_base_addr + 1;
+ } else {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Has sensor assignment is not set in F55\n",
+ __func__);
+ return;
+ }
+ } else {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Cannot find sensor mapping\n",
+ __func__);
+ return;
+ }
+
+ buffer = kzalloc((rx_len + tx_len) * sizeof(unsigned char),
+ GFP_KERNEL);
+
+ retval = f54->fn_ptr->read(rmi4_data, offset, buffer, rx_len + tx_len);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read control registers\n",
+ __func__);
+ goto exit;
+ }
+ rx_buffer = buffer;
+ tx_buffer = buffer + rx_len;
+
+ for (i = 0; i < rx_len; i++) {
+ if (rx_buffer[i] != 0xFF)
+ rmi4_data->num_of_rx++;
+ }
+ for (i = 0; i < tx_len; i++) {
+ if (tx_buffer[i] != 0xFF)
+ rmi4_data->num_of_tx++;
+ }
+
+ dev_info(&rmi4_data->i2c_client->dev,
+ "RxTx mapped from F$%s\n" \
+ "\n\tRx mapped count %d(%d)\n\tTx \
+ mapped count %d(%d)\n\n",
+ f54->fn55 ? "55" : "54",
+ rmi4_data->num_of_rx,
+ rx_len,
+ rmi4_data->num_of_tx,
+ tx_len);
+exit:
+ kfree(buffer);
+}
+
+static void synaptics_rmi4_f54_status_work(struct work_struct *work)
+{
+ int retval;
+ unsigned char report_index[2];
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+
+ if (f54->status != STATUS_BUSY)
+ return;
+
+ set_report_size();
+ if (f54->report_size == 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Report data size = 0\n",
+ __func__);
+ retval = -EINVAL;
+ goto error_exit;
+ }
+
+ if (f54->data_buffer_size < f54->report_size) {
+ mutex_lock(&f54->data_mutex);
+ if (f54->data_buffer_size)
+ kfree(f54->report_data);
+ f54->report_data = kzalloc(f54->report_size, GFP_KERNEL);
+ if (!f54->report_data) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for data buffer\n",
+ __func__);
+ f54->data_buffer_size = 0;
+ mutex_unlock(&f54->data_mutex);
+ retval = -ENOMEM;
+ goto error_exit;
+ }
+ f54->data_buffer_size = f54->report_size;
+ mutex_unlock(&f54->data_mutex);
+ }
+
+ report_index[0] = 0;
+ report_index[1] = 0;
+
+ retval = f54->fn_ptr->write(rmi4_data,
+ f54->data_base_addr + DATA_REPORT_INDEX_OFFSET,
+ report_index,
+ sizeof(report_index));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to write report data index\n",
+ __func__);
+ retval = -EINVAL;
+ goto error_exit;
+ }
+
+ retval = f54->fn_ptr->read(rmi4_data,
+ f54->data_base_addr + DATA_REPORT_DATA_OFFSET,
+ f54->report_data,
+ f54->report_size);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read report data\n",
+ __func__);
+ retval = -EINVAL;
+ goto error_exit;
+ }
+
+ retval = STATUS_IDLE;
+
+#ifdef RAW_HEX
+ print_raw_hex_report();
+#endif
+
+#ifdef HUMAN_READABLE
+ print_image_report();
+#endif
+
+error_exit:
+ mutex_lock(&f54->status_mutex);
+ set_interrupt(false);
+ wake_unlock(&f54->test_wake_lock);
+ f54->status = retval;
+ mutex_unlock(&f54->status_mutex);
+
+ return;
+}
+
+static void synaptics_rmi4_f54_attn(struct synaptics_rmi4_data *rmi4_data,
+ unsigned char intr_mask)
+{
+ if (f54->intr_mask & intr_mask) {
+ queue_delayed_work(f54->status_workqueue,
+ &f54->status_work,
+ msecs_to_jiffies(STATUS_WORK_INTERVAL));
+ }
+
+ return;
+}
+
+int synaptics_rmi4_f54_read_query(void)
+{
+ int retval;
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
+ uint16_t reg_addr;
+
+ retval = f54->fn_ptr->read(rmi4_data,
+ f54->query_base_addr,
+ f54->query.data,
+ sizeof(f54->query.data));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read query registers\n",
+ __func__);
+ goto err;
+ }
+
+ reg_addr = f54->query_base_addr + sizeof(f54->query.data);
+
+ QUERY_REG_READ(12, f54->query.has_sense_frequency_control);
+ QUERY_REG_READ(13, f54->query.has_query13);
+ QUERY_REG_READ(14, f54->query13.has_ctrl87);
+ QUERY_REG_READ(15, f54->query.has_query15);
+ QUERY_REG_READ(16, f54->query15.has_query16);
+ QUERY_REG_READ(17, f54->query16.has_query17);
+ QUERY_REG_READ(18, f54->query16.has_ctrl94_query18);
+ QUERY_REG_READ(19, f54->query16.has_ctrl95_query19);
+ QUERY_REG_READ(20, f54->query15.has_query20);
+ QUERY_REG_READ(21, f54->query15.has_query21);
+ QUERY_REG_READ(22, f54->query15.has_query22);
+ QUERY_REG_READ(23, f54->query22.has_query23);
+ QUERY_REG_READ(24, f54->query21.has_query24_data18);
+ QUERY_REG_READ(25, f54->query15.has_query25);
+ QUERY_REG_READ(26, f54->query22.has_ctrl103_query26);
+ QUERY_REG_READ(27, f54->query25.has_query27);
+ QUERY_REG_READ(28, f54->query22.has_query28);
+ QUERY_REG_READ(29, f54->query27.has_query29);
+ QUERY_REG_READ(30, f54->query29.has_query30);
+ QUERY_REG_READ(31, f54->query30.has_ctrl122_query31);
+ QUERY_REG_READ(32, f54->query30.has_query32);
+ QUERY_REG_READ(33, f54->query32.has_query33);
+ QUERY_REG_READ(34, f54->query32.has_query34);
+ QUERY_REG_READ(35, f54->query32.has_query35);
+ QUERY_REG_READ(36, f54->query33.has_query36);
+ if (f54->query36.has_query37)
+ reg_addr += 1;
+ QUERY_REG_READ(38, f54->query36.has_query38);
+ QUERY_REG_READ(39, f54->query38.has_query39);
+ QUERY_REG_READ(40, f54->query39.has_query40);
+ QUERY_REG_READ(41, f54->query40.has_ctrl163_query41);
+ QUERY_REG_READ(42, f54->query40.has_ctrl165_query42);
+ QUERY_REG_READ(43, f54->query40.has_query43);
+ reg_addr += 1; /* query44 is reserved - always present */
+ reg_addr += 1; /* query45 is reserved - always present */
+ QUERY_REG_READ(46, f54->query43.has_query46);
+
+return 0;
+
+err:
+ return retval;
+}
+
+static int synaptics_rmi4_f54_init(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ bool hasF54 = false;
+ bool hasF55 = false;
+ unsigned short ii;
+ unsigned char page;
+ unsigned char intr_count = 0;
+ unsigned char intr_offset;
+
+ struct synaptics_rmi4_fn_desc rmi_fd;
+
+ f54 = kzalloc(sizeof(*f54), GFP_KERNEL);
+ if (!f54) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for f54\n",
+ __func__);
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ f54->fn_ptr = kzalloc(sizeof(*(f54->fn_ptr)), GFP_KERNEL);
+ if (!f54->fn_ptr) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for fn_ptr\n",
+ __func__);
+ retval = -ENOMEM;
+ goto exit_free_f54;
+ }
+
+ f54->rmi4_data = rmi4_data;
+ f54->fn_ptr->read = rmi4_data->i2c_read;
+ f54->fn_ptr->write = rmi4_data->i2c_write;
+ f54->fn_ptr->enable = rmi4_data->irq_enable;
+
+ for (page = 0; page < PAGES_TO_SERVICE; page++) {
+ for (ii = PDT_START; ii > PDT_END; ii -= PDT_ENTRY_SIZE) {
+ ii |= (page << 8);
+
+ retval = f54->fn_ptr->read(rmi4_data,
+ ii,
+ (unsigned char *)&rmi_fd,
+ sizeof(rmi_fd));
+ if (retval < 0)
+ goto exit_free_mem;
+
+ if (!rmi_fd.fn_number)
+ break;
+
+ if (rmi_fd.fn_number == SYNAPTICS_RMI4_F54) {
+ hasF54 = true;
+ f54->query_base_addr =
+ rmi_fd.query_base_addr | (page << 8);
+ pr_debug("query_base_addr 0x%04x\n",
+ f54->query_base_addr);
+ f54->control_base_addr =
+ rmi_fd.ctrl_base_addr | (page << 8);
+ pr_debug("ctrl_base_addr 0x%04x\n",
+ f54->control_base_addr);
+ f54->data_base_addr =
+ rmi_fd.data_base_addr | (page << 8);
+ pr_debug("data_base_addr 0x%04x\n",
+ f54->data_base_addr);
+ f54->command_base_addr =
+ rmi_fd.cmd_base_addr | (page << 8);
+ pr_debug("command_base_addr 0x%04x\n",
+ f54->command_base_addr);
+ } else if (rmi_fd.fn_number == SYNAPTICS_RMI4_F55) {
+ hasF55 = true;
+ f54->fn55 = kmalloc(sizeof(*f54->fn55),
+ GFP_KERNEL);
+ f54->fn55->query_base_addr =
+ rmi_fd.query_base_addr | (page << 8);
+ f54->fn55->control_base_addr =
+ rmi_fd.ctrl_base_addr | (page << 8);
+ }
+
+ if (hasF54 && hasF55)
+ goto found;
+
+ if (!hasF54)
+ intr_count +=
+ (rmi_fd.intr_src_count & MASK_3BIT);
+ }
+ }
+
+ if (!hasF54) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: F$54 is not available\n",
+ __func__);
+ goto exit;
+ }
+found:
+ f54->intr_reg_num = (intr_count + 7) / 8;
+ if (f54->intr_reg_num != 0)
+ f54->intr_reg_num -= 1;
+
+ f54->intr_mask = 0;
+ intr_offset = intr_count % 8;
+ for (ii = intr_offset;
+ ii < ((rmi_fd.intr_src_count & MASK_3BIT) +
+ intr_offset);
+ ii++) {
+ f54->intr_mask |= 1 << ii;
+ }
+
+ retval = synaptics_rmi4_f54_read_query();
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read query registers\n",
+ __func__);
+ goto exit_free_mem;
+ }
+
+ retval = synaptics_rmi4_f55_read_query();
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to set up F55 query registers\n",
+ __func__);
+ goto exit_free_control;
+ }
+
+ retval = synaptics_rmi4_f54_set_ctrl();
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to set up control registers\n",
+ __func__);
+ goto exit_free_control;
+ }
+
+ synaptics_rmi4_f54_sensor_mapping();
+
+ retval = synaptics_rmi4_f54_set_data();
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to set up data registers\n",
+ __func__);
+ goto exit_free_data;
+ }
+
+ mutex_init(&f54->status_mutex);
+ mutex_init(&f54->data_mutex);
+ mutex_init(&f54->control_mutex);
+
+ retval = synaptics_rmi4_f54_set_sysfs();
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create sysfs entries\n",
+ __func__);
+ goto exit_sysfs;
+ }
+
+ f54->status_workqueue =
+ create_singlethread_workqueue("f54_status_workqueue");
+ INIT_DELAYED_WORK(&f54->status_work,
+ synaptics_rmi4_f54_status_work);
+
+ f54->user_report_type1 = F54_16BIT_IMAGE;
+ f54->user_report_type2 = F54_RAW_16BIT_IMAGE;
+
+ wake_lock_init(&f54->test_wake_lock, WAKE_LOCK_SUSPEND,
+ "synaptics_test_report");
+
+#ifdef WATCHDOG_HRTIMER
+ /* Watchdog timer to catch unanswered get report commands */
+ hrtimer_init(&f54->watchdog, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ f54->watchdog.function = get_report_timeout;
+
+ /* Work function to do actual cleaning up */
+ INIT_WORK(&f54->timeout_work, timeout_set_status);
+#endif
+
+ return 0;
+
+exit_sysfs:
+exit_free_data:
+ free_data_mem();
+
+exit_free_control:
+ free_control_mem();
+
+exit_free_mem:
+ kfree(f54->fn_ptr);
+
+exit_free_f54:
+ kfree(f54);
+
+exit:
+ return retval;
+}
+
+static void synaptics_rmi4_f54_remove(struct synaptics_rmi4_data *rmi4_data)
+{
+#ifdef WATCHDOG_HRTIMER
+ hrtimer_cancel(&f54->watchdog);
+#endif
+
+ cancel_delayed_work_sync(&f54->status_work);
+ flush_workqueue(f54->status_workqueue);
+ destroy_workqueue(f54->status_workqueue);
+
+ remove_sysfs();
+
+ free_data_mem();
+ free_control_mem();
+
+ kfree(f54->report_data);
+ kfree(f54->fn55);
+ kfree(f54->fn_ptr);
+ kfree(f54);
+
+ complete(&remove_complete);
+
+ return;
+}
+
+static int __init rmi4_f54_module_init(void)
+{
+ synaptics_rmi4_new_function(RMI_F54, true,
+ synaptics_rmi4_f54_init,
+ synaptics_rmi4_f54_remove,
+ synaptics_rmi4_f54_attn,
+ IC_MODE_UI);
+
+ return 0;
+}
+
+static void __exit rmi4_f54_module_exit(void)
+{
+ init_completion(&remove_complete);
+ synaptics_rmi4_new_function(RMI_F54, false,
+ synaptics_rmi4_f54_init,
+ synaptics_rmi4_f54_remove,
+ synaptics_rmi4_f54_attn,
+ IC_MODE_UI);
+
+ wait_for_completion(&remove_complete);
+ return;
+}
+
+module_init(rmi4_f54_module_init);
+module_exit(rmi4_f54_module_exit);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("Synaptics DSX Test Reporting Module");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(SYNAPTICS_DSX_DRIVER_VERSION);