input: touchscreen: Import Synaptics S3908P driver

* From branch: taoyao-s-oss

Change-Id: I1a2825f2467df647e80175974720b2db0b2bfde6
This commit is contained in:
Giovanni Ricca 2023-01-29 19:38:26 +05:30
parent c098cb3d97
commit d05542098f
No known key found for this signature in database
16 changed files with 18451 additions and 0 deletions

View File

@ -1349,4 +1349,6 @@ source "drivers/input/touchscreen/gt9916/Kconfig"
source "drivers/input/touchscreen/gt9897t/Kconfig"
source "drivers/input/touchscreen/synaptics_s3908p/Kconfig"
endif

View File

@ -123,3 +123,4 @@ obj-$(CONFIG_TOUCHSCREEN_ST_FTS_V521_SPI) += fts_spi/
obj-$(CONFIG_TOUCHSCREEN_ST_FTS_V521_DUAL) += fts_dual/
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BRL_9916) += gt9916/
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BRL) += gt9897t/
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_S3908P) += synaptics_s3908p/

View File

@ -0,0 +1,80 @@
#
# Synaptics TCM touchscreen driver configuration
#
config TOUCHSCREEN_SYNAPTICS_TCM_S3908P
tristate "synaptics s3908 Touchscreen"
default n
depends on SPI_MASTER
help
Say Y here if you have synaptics series SPI touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_SYNAPTICS_TCM_SPI
tristate "synaptics spi support"
default n
depends on TOUCHSCREEN_SYNAPTICS_TCM_S3908P
help
Say Y here to enable debug tools
If unsure, say N.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_SYNAPTICS_TCM_CORE
tristate "Synaptics TCM core module"
depends on TOUCHSCREEN_SYNAPTICS_TCM_S3908P
help
Say Y here to enable core functionality.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called synaptics_tcm_core.
config TOUCHSCREEN_SYNAPTICS_TCM_REFLASH
tristate "Synaptics reflash tools support"
default n
depends on TOUCHSCREEN_SYNAPTICS_TCM_S3908P
help
Say Y here to enable debug tools
If unsure, say N.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_SYNAPTICS_TCM_TESTING
tristate "Synaptics test tools support"
default n
depends on TOUCHSCREEN_SYNAPTICS_TCM_S3908P
help
Say Y here to enable debug tools
If unsure, say N.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_SYNAPTICS_TCM_DEVICE
tristate "Synaptics device support"
default n
depends on TOUCHSCREEN_SYNAPTICS_TCM_S3908P
help
Say Y here to enable debug tools
If unsure, say N.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_SYNAPTICS_TCM_DIAGNOSTIC
tristate "Synaptics diagnostic tools support"
default n
depends on TOUCHSCREEN_SYNAPTICS_TCM_S3908P
help
Say Y here to enable debug tools
If unsure, say N.
To compile this driver as a module, choose M here.

View File

@ -0,0 +1,36 @@
#
# Makefile for the Synaptics TCM touchscreen driver.
#
# Each configuration option enables a list of files.
#
# Makefile for the Synaptics TCM touchscreen driver.
#
# Each configuration option enables a list of files.
ifneq ($(KERNELRELEASE),)
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_SPI) += synaptics_tcm_spi.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_CORE) += synaptics_tcm_core_module.o
synaptics_tcm_core_module-y := synaptics_tcm_core.o synaptics_tcm_touch.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH) += synaptics_tcm_reflash.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_DEVICE) += synaptics_tcm_device.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_TESTING) += synaptics_tcm_testing.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_DIAGNOSTIC) += synaptics_tcm_diagnostics.o
else
KDIR = $(OUT)/obj/KERNEL_OBJ
CROSS_COMPILE = $(ANDROID_TOOLCHAIN)/aarch64-linux-android-
CLANG = $(ANDROID_BUILD_TOP)/prebuilts/clang/host/linux-x86/clang-r370808
REAL_CC = $(CLANG)/bin/clang
AR = $(CLANG)/bin/llvm-ar
LLVM_NM = $(CLANG)/bin/llvm-nm
LD = $(CLANG)/bin/ld.lld
.PHONY: clean
default:
$(MAKE) ARCH=arm64 CROSS_COMPILE=$(CROSS_COMPILE) REAL_CC=$(REAL_CC) CLANG_TRIPLE=aarch64-linux-gnu- AR=$(AR) LLVM_NM=$(LLVM_NM) LD=$(LD) -C $(KDIR) M=$(PWD) modules
clean:
@rm -rf *.o* *.order *.symvers *.mod* .*.o.cmd .*.mod.o.cmd .*.ko.cmd .tmp_versions *.ko
@find -name *.o | xargs rm -f
endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,938 @@
/*
* Synaptics TCM touchscreen driver
*
* Copyright (C) 2017-2018 Synaptics Incorporated. All rights reserved.
*
* Copyright (C) 2017-2018 Scott Lin <scott.lin@tw.synaptics.com>
* Copyright (C) 2018-2019 Ian Su <ian.su@tw.synaptics.com>
* Copyright (C) 2018-2019 Joey Zhou <joey.zhou@synaptics.com>
* Copyright (C) 2018-2019 Yuehao Qiu <yuehao.qiu@synaptics.com>
* Copyright (C) 2018-2019 Aaron Chen <aaron.chen@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.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#ifndef _SYNAPTICS_TCM_CORE_H_
#define _SYNAPTICS_TCM_CORE_H_
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input/synaptics_tcm.h>
#include <linux/slab.h>
#include <linux/sched/signal.h>
#include <linux/proc_fs.h>
#include <linux/spi/spi.h>
#include <linux/of_gpio.h>
#include <drm/mi_disp_notifier.h>
#include <linux/fb.h>
#include <linux/notifier.h>
#include "../xiaomi/xiaomi_touch.h"
#define GRIP_RECT_NUM 12
#define GRIP_PARAMETER_NUM 8
#define TP_INFO_MAX_LENGTH 50
#define SYNAPTICS_DEBUGFS_ENABLE
#define SYNAPTICS_POWERSUPPLY_CB
enum charge_status {
NOT_CHARGING,
CHARGING,
WIRED_CHARGING,
WIRELESS_CHARGING,
};
extern int power_supply_is_system_supplied(void);
#ifdef SYNAPTICS_DEBUGFS_ENABLE
#include <linux/debugfs.h>
#endif
#include "./synaptics_tcm_xiaomi_board_data.h"
#define SYNAPTICS_TCM_ID_PRODUCT (1 << 0)
#define SYNAPTICS_TCM_ID_VERSION 0x0201
#define SYNAPTICS_TCM_ID_SUBVERSION 0
#define PLATFORM_DRIVER_NAME "synaptics_tcm"
#define TOUCH_INPUT_NAME "synaptics_tcm_touch"
#define TOUCH_INPUT_PHYS_PATH "synaptics_tcm/touch_input"
#define WAKEUP_GESTURE (1)
/* The chunk size RD_CHUNK_SIZE/WR_CHUNK_SIZE will not apply in HDL sensors */
#define RD_CHUNK_SIZE 256 /* read length limit in bytes, 0 = unlimited */
#define WR_CHUNK_SIZE 256 /* write length limit in bytes, 0 = unlimited */
#define HDL_RD_CHUNK_SIZE 0 /* For HDL, 0 = unlimited */
#define HDL_WR_CHUNK_SIZE 0 /* For HDL, 0 = unlimited */
#define MESSAGE_HEADER_SIZE 4
#define MESSAGE_MARKER 0xa5
#define MESSAGE_PADDING 0x5a
/*
#define REPORT_NOTIFIER
*/
/*
#define WATCHDOG_SW
*/
#ifdef WATCHDOG_SW
#define RUN_WATCHDOG false
#define WATCHDOG_TRIGGER_COUNT 2
#define WATCHDOG_DELAY_MS 1000
#endif
#define HOST_DOWNLOAD_WAIT_MS 100
#define HOST_DOWNLOAD_TIMEOUT_MS 5000
#define SYNA_TCM_XIAOMI_TOUCHFEATURE
#define PANEL_ORIENTATION_DEGREE_0 0 /* normal portrait orientation */
#define PANEL_ORIENTATION_DEGREE_90 1 /* anticlockwise 90 degrees */
#define PANEL_ORIENTATION_DEGREE_180 2 /* anticlockwise 180 degrees */
#define PANEL_ORIENTATION_DEGREE_270 3 /* anticlockwise 270 degrees */
#define USE_KOBJ_SYSFS (1)
#define LOGx(func, dev, log, ...) \
func(dev, "%s info: " log, __func__, ##__VA_ARGS__)
#define LOGy(func, dev, log, ...) \
func(dev, "%s(line %d) " log, __func__, __LINE__, ##__VA_ARGS__)
#define LOGD(dev, log, ...) LOGx(dev_dbg, dev, log, ##__VA_ARGS__)
#define LOGI(dev, log, ...) LOGx(dev_info, dev, log, ##__VA_ARGS__)
#define LOGN(dev, log, ...) LOGx(dev_notice, dev, log, ##__VA_ARGS__)
#define LOGW(dev, log, ...) LOGy(dev_warn, dev, log, ##__VA_ARGS__)
#define LOGE(dev, log, ...) LOGy(dev_err, dev, log, ##__VA_ARGS__)
#define INIT_BUFFER(buffer, is_clone) \
mutex_init(&buffer.buf_mutex); \
buffer.clone = is_clone
#define LOCK_BUFFER(buffer) \
mutex_lock(&buffer.buf_mutex)
#define UNLOCK_BUFFER(buffer) \
mutex_unlock(&buffer.buf_mutex)
#define RELEASE_BUFFER(buffer) \
do { \
if (buffer.clone == false) { \
kfree(buffer.buf); \
buffer.buf_size = 0; \
buffer.data_length = 0; \
} \
} while (0)
#define MAX(a, b) \
({__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a > _b ? _a : _b; })
#define MIN(a, b) \
({__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a < _b ? _a : _b; })
#define STR(x) #x
#define CONCAT(a, b) a##b
#define IS_NOT_FW_MODE(mode) \
((mode != MODE_APPLICATION_FIRMWARE) && (mode != MODE_HOSTDOWNLOAD_FIRMWARE))
#define IS_FW_MODE(mode) \
((mode == MODE_APPLICATION_FIRMWARE) || (mode == MODE_HOSTDOWNLOAD_FIRMWARE))
#define SHOW_PROTOTYPE(m_name, a_name) \
static ssize_t CONCAT(m_name##_sysfs, _##a_name##_show)(struct device *dev, \
struct device_attribute *attr, char *buf); \
\
static struct device_attribute dev_attr_##a_name = \
__ATTR(a_name, S_IRUGO, \
CONCAT(m_name##_sysfs, _##a_name##_show), \
syna_tcm_store_error);
#define STORE_PROTOTYPE(m_name, a_name) \
static ssize_t CONCAT(m_name##_sysfs, _##a_name##_store)(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count); \
\
static struct device_attribute dev_attr_##a_name = \
__ATTR(a_name, (S_IWUSR | S_IWGRP), \
syna_tcm_show_error, \
CONCAT(m_name##_sysfs, _##a_name##_store));
#define SHOW_STORE_PROTOTYPE(m_name, a_name) \
static ssize_t CONCAT(m_name##_sysfs, _##a_name##_show)(struct device *dev, \
struct device_attribute *attr, char *buf); \
\
static ssize_t CONCAT(m_name##_sysfs, _##a_name##_store)(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count); \
\
static struct device_attribute dev_attr_##a_name = \
__ATTR(a_name, (S_IRUGO | S_IWUSR | S_IWGRP), \
CONCAT(m_name##_sysfs, _##a_name##_show), \
CONCAT(m_name##_sysfs, _##a_name##_store));
#define ATTRIFY(a_name) (&dev_attr_##a_name)
#if (USE_KOBJ_SYSFS)
#define KOBJ_SHOW_PROTOTYPE(m_name, a_name) \
static ssize_t CONCAT(m_name##_sysfs, _##a_name##_show)(struct kobject *kobj, \
struct kobj_attribute *attr, char *buf); \
\
static struct kobj_attribute kobj_attr_##a_name = \
__ATTR(a_name, S_IRUGO, \
CONCAT(m_name##_sysfs, _##a_name##_show), NULL);
#define KOBJ_STORE_PROTOTYPE(m_name, a_name) \
static ssize_t CONCAT(m_name##_sysfs, _##a_name##_store)(struct kobject *kobj, \
struct kobj_attribute *attr, const char *buf, size_t count); \
\
static struct kobj_attribute kobj_attr_##a_name = \
__ATTR(a_name, (S_IWUSR | S_IWGRP), \
NULL, CONCAT(m_name##_sysfs, _##a_name##_store));
#define KOBJ_SHOW_STORE_PROTOTYPE(m_name, a_name) \
static ssize_t CONCAT(m_name##_sysfs, _##a_name##_show)(struct kobject *kobj, \
struct kobj_attribute *attr, char *buf); \
\
static ssize_t CONCAT(m_name##_sysfs, _##a_name##_store)(struct kobject *kobj, \
struct kobj_attribute *attr, const char *buf, size_t count); \
\
static struct kobj_attribute kobj_attr_##a_name = \
__ATTR(a_name, (S_IRUGO | S_IWUSR | S_IWGRP), \
CONCAT(m_name##_sysfs, _##a_name##_show), \
CONCAT(m_name##_sysfs, _##a_name##_store));
#define KOBJ_ATTRIFY(a_name) (&kobj_attr_##a_name)
#endif
enum module_type {
TCM_ZEROFLASH = 0,
TCM_REFLASH = 1,
TCM_DEVICE = 2,
TCM_TESTING = 3,
TCM_RECOVERY = 4,
TCM_DIAGNOSTICS = 5,
TCM_LAST,
};
enum boot_mode {
MODE_APPLICATION_FIRMWARE = 0x01,
MODE_HOSTDOWNLOAD_FIRMWARE = 0x02,
MODE_ROMBOOTLOADER = 0x04,
MODE_BOOTLOADER = 0x0b,
MODE_TDDI_BOOTLOADER = 0x0c,
MODE_TDDI_HOSTDOWNLOAD_BOOTLOADER = 0x0d,
MODE_PRODUCTIONTEST_FIRMWARE = 0x0e,
};
enum sensor_types {
TYPE_UNKNOWN = 0,
TYPE_FLASH = 1,
TYPE_F35 = 2,
TYPE_ROMBOOT = 3,
};
enum boot_status {
BOOT_STATUS_OK = 0x00,
BOOT_STATUS_BOOTING = 0x01,
BOOT_STATUS_APP_BAD_DISPLAY_CRC = 0xfc,
BOOT_STATUS_BAD_DISPLAY_CONFIG = 0xfd,
BOOT_STATUS_BAD_APP_FIRMWARE = 0xfe,
BOOT_STATUS_WARM_BOOT = 0xff,
};
enum app_status {
APP_STATUS_OK = 0x00,
APP_STATUS_BOOTING = 0x01,
APP_STATUS_UPDATING = 0x02,
APP_STATUS_BAD_APP_CONFIG = 0xff,
};
enum firmware_mode {
FW_MODE_BOOTLOADER = 0,
FW_MODE_APPLICATION = 1,
FW_MODE_PRODUCTION_TEST = 2,
};
enum dynamic_config_id {
DC_UNKNOWN = 0x00,
DC_NO_DOZE,
DC_DISABLE_NOISE_MITIGATION,
DC_INHIBIT_FREQUENCY_SHIFT,
DC_REQUESTED_FREQUENCY,
DC_DISABLE_HSYNC,
DC_REZERO_ON_EXIT_DEEP_SLEEP,
DC_CHARGER_CONNECTED,
DC_NO_BASELINE_RELAXATION,
DC_IN_WAKEUP_GESTURE_MODE,
DC_STIMULUS_FINGERS,
DC_GRIP_SUPPRESSION_ENABLED,
DC_ENABLE_THICK_GLOVE,
DC_ENABLE_GLOVE,
DC_ENABLE_TOUCH_AND_HOLD = 0xD4,
DC_GAME_MODE_CTRL = 0xD5,
DC_SWIPE_IIRFILTER = 0xD8,
DC_FAST_TAP_HYTERESIS = 0xD9, /* UP_THRESHOLD */
DC_MOTION_TOLERANCE = 0xDA,
DC_TAP_JITTER = 0xDB,
DC_PALM_AREA_CHANGE = 0xDC,
DC_SET_REPORT_RATE = 0xE6,
DC_GESTURE_TYPE_ENABLE = 0xFE,
};
enum command {
CMD_NONE = 0x00,
CMD_CONTINUE_WRITE = 0x01,
CMD_IDENTIFY = 0x02,
CMD_RESET = 0x04,
CMD_ENABLE_REPORT = 0x05,
CMD_DISABLE_REPORT = 0x06,
CMD_GET_BOOT_INFO = 0x10,
CMD_ERASE_FLASH = 0x11,
CMD_WRITE_FLASH = 0x12,
CMD_READ_FLASH = 0x13,
CMD_RUN_APPLICATION_FIRMWARE = 0x14,
CMD_SPI_MASTER_WRITE_THEN_READ = 0x15,
CMD_REBOOT_TO_ROM_BOOTLOADER = 0x16,
CMD_RUN_BOOTLOADER_FIRMWARE = 0x1f,
CMD_GET_APPLICATION_INFO = 0x20,
CMD_GET_STATIC_CONFIG = 0x21,
CMD_SET_STATIC_CONFIG = 0x22,
CMD_GET_DYNAMIC_CONFIG = 0x23,
CMD_SET_DYNAMIC_CONFIG = 0x24,
CMD_GET_TOUCH_REPORT_CONFIG = 0x25,
CMD_SET_TOUCH_REPORT_CONFIG = 0x26,
CMD_REZERO = 0x27,
CMD_COMMIT_CONFIG = 0x28,
CMD_DESCRIBE_DYNAMIC_CONFIG = 0x29,
CMD_PRODUCTION_TEST = 0x2a,
CMD_SET_CONFIG_ID = 0x2b,
CMD_ENTER_DEEP_SLEEP = 0x2c,
CMD_EXIT_DEEP_SLEEP = 0x2d,
CMD_GET_TOUCH_INFO = 0x2e,
CMD_GET_DATA_LOCATION = 0x2f,
CMD_DOWNLOAD_CONFIG = 0x30,
CMD_ENTER_PRODUCTION_TEST_MODE = 0x31,
CMD_GET_FEATURES = 0x32,
CMD_GET_ROMBOOT_INFO = 0x40,
CMD_WRITE_PROGRAM_RAM = 0x41,
CMD_ROMBOOT_RUN_BOOTLOADER_FIRMWARE = 0x42,
CMD_SPI_MASTER_WRITE_THEN_READ_EXTENDED = 0x43,
CMD_ENTER_IO_BRIDGE_MODE = 0x44,
CMD_ROMBOOT_DOWNLOAD = 0x45,
CMD_MultiFunction = 0xC7,
};
enum cmd_c7_sub_cmd {
C7_SUB_CMD_SET_GRIP_ZONE = 0x00,
C7_SUB_CMD_GET_GRIP_ZONE = 0x01,
};
enum status_code {
STATUS_IDLE = 0x00,
STATUS_OK = 0x01,
STATUS_BUSY = 0x02,
STATUS_CONTINUED_READ = 0x03,
STATUS_CRC_ERROR = 0x0A,
STATUS_NOT_EXECUTED_IN_DEEP_SLEEP = 0x0b,
STATUS_RECEIVE_BUFFER_OVERFLOW = 0x0c,
STATUS_PREVIOUS_COMMAND_PENDING = 0x0d,
STATUS_NOT_IMPLEMENTED = 0x0e,
STATUS_ERROR = 0x0f,
STATUS_INVALID = 0xff,
};
enum report_type {
REPORT_IDENTIFY = 0x10,
REPORT_TOUCH = 0x11,
REPORT_DELTA = 0x12,
REPORT_RAW = 0x13,
REPORT_STATUS = 0x1b,
REPORT_PRINTF = 0x82,
REPORT_RID161 = 0xA1,
REPORT_HDL_ROMBOOT = 0xfd,
REPORT_HDL_F35 = 0xfe,
};
enum command_status {
CMD_IDLE = 0,
CMD_BUSY = 1,
CMD_ERROR = -1,
};
enum flash_area {
BOOTLOADER = 0,
BOOT_CONFIG,
APP_FIRMWARE,
APP_CONFIG,
DISP_CONFIG,
CUSTOM_OTP,
CUSTOM_LCM,
CUSTOM_OEM,
PPDT,
};
enum flash_data {
LCM_DATA = 1,
OEM_DATA,
PPDT_DATA,
};
enum helper_task {
HELP_NONE = 0,
HELP_RUN_APPLICATION_FIRMWARE,
HELP_SEND_REINIT_NOTIFICATION,
HELP_TOUCH_REINIT,
HELP_SEND_ROMBOOT_HDL,
};
enum fod_status {
FOD_STATUS_INVALID = -1,
FOD_STATUS_UNLOCKED = 0,
FOD_STATUS_UNLOCKING = 1,
FOD_STATUS_INPUT_FINGERPRINT = 2,
FOD_STATUS_UNLOCK_FAILED = 3,
FOD_STATUS_DELETED = 100,
};
enum grip_zone_type {
CORNER_ZONE = 0x00,
EDGE_ZONE = 0x01,
DEAD_ZONE = 0x02,
CORNERCASE2_ZONE = 0x03,
};
struct syna_tcm_helper {
atomic_t task;
struct work_struct work;
struct workqueue_struct *workqueue;
};
struct syna_tcm_watchdog {
bool run;
unsigned char count;
struct delayed_work work;
struct workqueue_struct *workqueue;
};
struct syna_tcm_buffer {
bool clone;
unsigned char *buf;
unsigned int buf_size;
unsigned int data_length;
struct mutex buf_mutex;
};
struct syna_tcm_report {
unsigned char id;
struct syna_tcm_buffer buffer;
};
struct syna_tcm_identification {
unsigned char version;
unsigned char mode;
unsigned char part_number[16];
unsigned char build_id[4];
unsigned char max_write_size[2];
};
struct syna_tcm_boot_info {
unsigned char version;
unsigned char status;
unsigned char asic_id[2];
unsigned char write_block_size_words;
unsigned char erase_page_size_words[2];
unsigned char max_write_payload_size[2];
unsigned char last_reset_reason;
unsigned char pc_at_time_of_last_reset[2];
unsigned char boot_config_start_block[2];
unsigned char boot_config_size_blocks[2];
unsigned char display_config_start_block[4];
unsigned char display_config_length_blocks[2];
unsigned char backup_display_config_start_block[4];
unsigned char backup_display_config_length_blocks[2];
unsigned char custom_otp_start_block[2];
unsigned char custom_otp_length_blocks[2];
};
struct syna_tcm_app_info {
unsigned char version[2];
unsigned char status[2];
unsigned char static_config_size[2];
unsigned char dynamic_config_size[2];
unsigned char app_config_start_write_block[2];
unsigned char app_config_size[2];
unsigned char max_touch_report_config_size[2];
unsigned char max_touch_report_payload_size[2];
unsigned char customer_config_id[16];
unsigned char max_x[2];
unsigned char max_y[2];
unsigned char max_objects[2];
unsigned char num_of_buttons[2];
unsigned char num_of_image_rows[2];
unsigned char num_of_image_cols[2];
unsigned char has_hybrid_data[2];
unsigned char num_of_force_elecs[2];
};
struct syna_tcm_romboot_info {
unsigned char version;
unsigned char status;
unsigned char asic_id[2];
unsigned char write_block_size_words;
unsigned char max_write_payload_size[2];
unsigned char last_reset_reason;
unsigned char pc_at_time_of_last_reset[2];
};
struct syna_tcm_touch_info {
unsigned char image_2d_scale_factor[4];
unsigned char image_0d_scale_factor[4];
unsigned char hybrid_x_scale_factor[4];
unsigned char hybrid_y_scale_factor[4];
};
struct syna_tcm_message_header {
unsigned char marker;
unsigned char code;
unsigned char length[2];
};
struct syna_tcm_features {
unsigned char byte_0_reserved;
unsigned char byte_1_reserved;
unsigned char dual_firmware:1;
unsigned char byte_2_reserved:7;
} __packed;
struct syna_zone {
unsigned char x0[2];
unsigned char y0[2];
unsigned char x1[2];
unsigned char y1[2];
unsigned char x2[2];
unsigned char y2[2];
unsigned char x3[2];
unsigned char y3[2];
unsigned char x4[2];
unsigned char y4[2];
unsigned char x5[2];
unsigned char y5[2];
unsigned char x6[2];
unsigned char y6[2];
unsigned char x7[2];
unsigned char y7[2];
};
struct syna_grip_zone {
unsigned char type; /* BIT[3:0]: Panel Orientaton; BIT?:Game Mode */
unsigned char reserved;
struct syna_zone edge_zone;
struct syna_zone dead_zone;
struct syna_zone corner_zone;
};
struct syna_tcm_hcd {
struct regulator *avdd;
struct regulator *iovdd;
pid_t isr_pid;
atomic_t command_status;
atomic_t host_downloading;
atomic_t firmware_flashing;
wait_queue_head_t hdl_wq;
wait_queue_head_t reflash_wq;
int irq;
bool do_polling;
bool in_suspending;
bool in_suspend;
bool irq_enabled;
bool in_hdl_mode;
bool is_detected;
bool wakeup_gesture_enabled;
bool fod_enabled;
bool fod_finger;
bool in_sleep;
bool fod_display_enabled;
unsigned char sensor_type;
unsigned char fb_ready;
unsigned char command;
unsigned char async_report_id;
unsigned char status_report_code;
unsigned char response_code;
unsigned int read_length;
unsigned int payload_length;
unsigned int packrat_number;
unsigned int rd_chunk_size;
unsigned int wr_chunk_size;
unsigned int app_status;
struct platform_device *pdev;
struct regulator *pwr_reg;
struct regulator *bus_reg;
struct kobject *sysfs_dir;
struct kobject *dynamnic_config_sysfs_dir;
struct mutex extif_mutex;
struct mutex reset_mutex;
struct mutex irq_en_mutex;
struct mutex io_ctrl_mutex;
struct mutex rw_ctrl_mutex;
struct mutex command_mutex;
struct mutex identify_mutex;
struct delayed_work polling_work;
struct workqueue_struct *polling_workqueue;
struct task_struct *notifier_thread;
bool tp_pm_suspend;
struct completion pm_resume_completion;
struct class *syna_tcm_class;
struct device *syna_tcm_dev;
dev_t tp_dev_num;
struct notifier_block fb_notifier;
struct notifier_block power_supply_notifier;
int charging_status;
struct delayed_work power_supply_work;
struct syna_tcm_buffer in;
struct syna_tcm_buffer out;
struct syna_tcm_buffer resp;
struct syna_tcm_buffer temp;
struct syna_tcm_buffer config;
struct syna_tcm_report report;
struct syna_tcm_app_info app_info;
struct syna_tcm_boot_info boot_info;
struct syna_tcm_romboot_info romboot_info;
struct syna_tcm_touch_info touch_info;
struct syna_tcm_identification id_info;
struct syna_tcm_helper helper;
struct syna_tcm_watchdog watchdog;
struct syna_tcm_features features;
const struct syna_tcm_hw_interface *hw_if;
int (*reset)(struct syna_tcm_hcd *tcm_hcd);
int (*reset_n_reinit)(struct syna_tcm_hcd *tcm_hcd, bool hw, bool update_wd);
int (*sleep)(struct syna_tcm_hcd *tcm_hcd, bool en);
int (*identify)(struct syna_tcm_hcd *tcm_hcd, bool id);
int (*enable_irq)(struct syna_tcm_hcd *tcm_hcd, bool en, bool ns);
int (*switch_mode)(struct syna_tcm_hcd *tcm_hcd,
enum firmware_mode mode);
int (*read_message)(struct syna_tcm_hcd *tcm_hcd,
unsigned char *in_buf, unsigned int length);
int (*write_message)(struct syna_tcm_hcd *tcm_hcd,
unsigned char command, unsigned char *payload,
unsigned int length, unsigned char **resp_buf,
unsigned int *resp_buf_size, unsigned int *resp_length,
unsigned char *response_code,
unsigned int polling_delay_ms);
int (*get_dynamic_config)(struct syna_tcm_hcd *tcm_hcd,
enum dynamic_config_id id, unsigned short *value);
int (*set_dynamic_config)(struct syna_tcm_hcd *tcm_hcd,
enum dynamic_config_id id, unsigned short value);
int (*get_data_location)(struct syna_tcm_hcd *tcm_hcd,
enum flash_area area, unsigned int *addr,
unsigned int *length);
int (*read_flash_data)(enum flash_area area, bool run_app_firmware,
struct syna_tcm_buffer *output);
int (*syna_tcm_lockdown_info)(void);
void (*report_touch)(void);
void (*update_watchdog)(struct syna_tcm_hcd *tcm_hcd, bool en);
struct proc_dir_entry *tp_irq_debug;
struct work_struct early_suspend_work;
struct work_struct suspend_work;
struct work_struct resume_work;
struct work_struct fod_work;
struct work_struct set_report_rate_work;
struct workqueue_struct *event_wq;
int gamemode_enable;
int fod_icon_status;
int non_ui_status;
int finger_unlock_status;
int palm_sensor_enable;
int palm_enable_status;
int nonui_status;
bool aod_enable;
int fod_status;
bool doubletap_enable;
int power_status;
int charger_connected;
int report_rate_mode;
unsigned int gesture_type;
int maintenance_result;
struct mutex cmd_update_mutex;
#ifdef SYNA_TCM_XIAOMI_TOUCHFEATURE
struct work_struct cmd_update_work;
struct work_struct grip_mode_work;
struct workqueue_struct *game_wq;
#endif
#ifdef SYNAPTICS_DEBUGFS_ENABLE
struct dentry *debugfs;
#endif
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
bool lockdown_info_ready;
char lockdown_info[8];
struct proc_dir_entry *tp_selftest_proc;
struct proc_dir_entry *tp_data_dump_proc;
struct proc_dir_entry *tp_fw_version_proc;
struct proc_dir_entry *tp_lockdown_info_proc;
int (*testing_xiaomi_report_data)(int report_type, char *buf);
int (*testing_xiaomi_self_test)(char *buf);
int (*testing_xiaomi_chip_id_read)(void);
struct syna_tcm_xiaomi_board_data xiaomi_board_data;
struct mutex long_mode_value_mutex;
struct mutex esd_recovery_mutex;
};
struct syna_tcm_module_cb {
enum module_type type;
int (*init)(struct syna_tcm_hcd *tcm_hcd);
int (*remove)(struct syna_tcm_hcd *tcm_hcd);
int (*syncbox)(struct syna_tcm_hcd *tcm_hcd);
#ifdef REPORT_NOTIFIER
int (*asyncbox)(struct syna_tcm_hcd *tcm_hcd);
#endif
int (*reinit)(struct syna_tcm_hcd *tcm_hcd);
int (*suspend)(struct syna_tcm_hcd *tcm_hcd);
int (*resume)(struct syna_tcm_hcd *tcm_hcd);
int (*early_suspend)(struct syna_tcm_hcd *tcm_hcd);
};
struct syna_tcm_module_handler {
bool insert;
bool detach;
struct list_head link;
struct syna_tcm_module_cb *mod_cb;
};
struct syna_tcm_module_pool {
bool initialized;
bool queue_work;
struct mutex mutex;
struct list_head list;
struct work_struct work;
struct workqueue_struct *workqueue;
struct syna_tcm_hcd *tcm_hcd;
};
struct syna_tcm_bus_io {
unsigned char type;
int (*rmi_read)(struct syna_tcm_hcd *tcm_hcd, unsigned short addr,
unsigned char *data, unsigned int length);
int (*rmi_write)(struct syna_tcm_hcd *tcm_hcd, unsigned short addr,
unsigned char *data, unsigned int length);
int (*read)(struct syna_tcm_hcd *tcm_hcd, unsigned char *data,
unsigned int length);
int (*write)(struct syna_tcm_hcd *tcm_hcd, unsigned char *data,
unsigned int length);
};
struct syna_tcm_hw_interface {
struct syna_tcm_board_data *bdata;
const struct syna_tcm_bus_io *bus_io;
};
int syna_tcm_bus_init(void);
void syna_tcm_bus_exit(void);
int syna_tcm_add_module(struct syna_tcm_module_cb *mod_cb, bool insert);
int touch_init(struct syna_tcm_hcd *tcm_hcd);
int touch_remove(struct syna_tcm_hcd *tcm_hcd);
int touch_reinit(struct syna_tcm_hcd *tcm_hcd);
int touch_early_suspend(struct syna_tcm_hcd *tcm_hcd);
int touch_suspend(struct syna_tcm_hcd *tcm_hcd);
int touch_resume(struct syna_tcm_hcd *tcm_hcd);
static inline int syna_tcm_rmi_read(struct syna_tcm_hcd *tcm_hcd,
unsigned short addr, unsigned char *data, unsigned int length)
{
return tcm_hcd->hw_if->bus_io->rmi_read(tcm_hcd, addr, data, length);
}
static inline int syna_tcm_rmi_write(struct syna_tcm_hcd *tcm_hcd,
unsigned short addr, unsigned char *data, unsigned int length)
{
return tcm_hcd->hw_if->bus_io->rmi_write(tcm_hcd, addr, data, length);
}
static inline int syna_tcm_read(struct syna_tcm_hcd *tcm_hcd,
unsigned char *data, unsigned int length)
{
return tcm_hcd->hw_if->bus_io->read(tcm_hcd, data, length);
}
static inline int syna_tcm_write(struct syna_tcm_hcd *tcm_hcd,
unsigned char *data, unsigned int length)
{
return tcm_hcd->hw_if->bus_io->write(tcm_hcd, data, length);
}
static inline ssize_t syna_tcm_show_error(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_err("%s: Attribute not readable\n",
__func__);
return -EPERM;
}
static inline ssize_t syna_tcm_store_error(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
pr_err("%s: Attribute not writable\n",
__func__);
return -EPERM;
}
static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size,
const unsigned char *src, unsigned int src_size,
unsigned int count)
{
if (dest == NULL || src == NULL)
return -EINVAL;
if (count > dest_size || count > src_size) {
pr_err("%s: src_size = %d, dest_size = %d, count = %d\n",
__func__, src_size, dest_size, count);
return -EINVAL;
}
memcpy((void *)dest, (const void *)src, count);
return 0;
}
static inline int syna_tcm_realloc_mem(struct syna_tcm_hcd *tcm_hcd,
struct syna_tcm_buffer *buffer, unsigned int size)
{
int retval;
unsigned char *temp;
if (size > buffer->buf_size) {
temp = buffer->buf;
buffer->buf = kmalloc(size, GFP_KERNEL);
if (!(buffer->buf)) {
dev_err(tcm_hcd->pdev->dev.parent,
"%s: Failed to allocate memory\n",
__func__);
kfree(temp);
buffer->buf_size = 0;
return -ENOMEM;
}
retval = secure_memcpy(buffer->buf,
size,
temp,
buffer->buf_size,
buffer->buf_size);
if (retval < 0) {
dev_err(tcm_hcd->pdev->dev.parent,
"%s: Failed to copy data\n",
__func__);
kfree(temp);
kfree(buffer->buf);
buffer->buf_size = 0;
return retval;
}
kfree(temp);
buffer->buf_size = size;
}
return 0;
}
static inline int syna_tcm_alloc_mem(struct syna_tcm_hcd *tcm_hcd,
struct syna_tcm_buffer *buffer, unsigned int size)
{
if (size > buffer->buf_size) {
kfree(buffer->buf);
buffer->buf = kmalloc(size, GFP_KERNEL);
if (!(buffer->buf)) {
dev_err(tcm_hcd->pdev->dev.parent,
"%s: Failed to allocate memory\n",
__func__);
dev_err(tcm_hcd->pdev->dev.parent,
"%s: Allocation size = %d\n",
__func__, size);
buffer->buf_size = 0;
buffer->data_length = 0;
return -ENOMEM;
}
buffer->buf_size = size;
}
memset(buffer->buf, 0x00, buffer->buf_size);
buffer->data_length = 0;
return 0;
}
static inline unsigned int le2_to_uint(const unsigned char *src)
{
return (unsigned int)src[0] +
(unsigned int)src[1] * 0x100;
}
static inline unsigned int le4_to_uint(const unsigned char *src)
{
return (unsigned int)src[0] +
(unsigned int)src[1] * 0x100 +
(unsigned int)src[2] * 0x10000 +
(unsigned int)src[3] * 0x1000000;
}
static inline unsigned int ceil_div(unsigned int dividend, unsigned divisor)
{
return (dividend + divisor - 1) / divisor;
}
int touch_free_objects(struct syna_tcm_hcd *tcm_hcd);
int touch_flush_slots(struct syna_tcm_hcd *tcm_hcd);
extern int mi_disp_set_fod_queue_work(u32 fod_btn, bool from_touch);
void touch_fod_test(int value);
#endif

View File

@ -0,0 +1,724 @@
/*
* Synaptics TCM touchscreen driver
*
* Copyright (C) 2017-2018 Synaptics Incorporated. All rights reserved.
*
* Copyright (C) 2017-2018 Scott Lin <scott.lin@tw.synaptics.com>
* Copyright (C) 2018-2019 Ian Su <ian.su@tw.synaptics.com>
* Copyright (C) 2018-2019 Joey Zhou <joey.zhou@synaptics.com>
* Copyright (C) 2018-2019 Yuehao Qiu <yuehao.qiu@synaptics.com>
* Copyright (C) 2018-2019 Aaron Chen <aaron.chen@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.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include "synaptics_tcm_core.h"
#define CHAR_DEVICE_NAME "tcm"
#define CONCURRENT true
#define DEVICE_IOC_MAGIC 's'
#define DEVICE_IOC_RESET _IO(DEVICE_IOC_MAGIC, 0) /* 0x00007300 */
#define DEVICE_IOC_IRQ _IOW(DEVICE_IOC_MAGIC, 1, int) /* 0x40047301 */
#define DEVICE_IOC_RAW _IOW(DEVICE_IOC_MAGIC, 2, int) /* 0x40047302 */
#define DEVICE_IOC_CONCURRENT _IOW(DEVICE_IOC_MAGIC, 3, int) /* 0x40047303 */
struct device_hcd {
dev_t dev_num;
bool raw_mode;
bool concurrent;
unsigned int ref_count;
struct cdev char_dev;
struct class *class;
struct device *device;
struct syna_tcm_buffer out;
struct syna_tcm_buffer resp;
struct syna_tcm_buffer report;
struct syna_tcm_hcd *tcm_hcd;
};
DECLARE_COMPLETION(device_remove_complete);
static struct device_hcd *device_hcd;
static int rmidev_major_num;
static void device_capture_touch_report(unsigned int count)
{
int retval;
unsigned char id;
unsigned int idx;
unsigned int size;
unsigned char *data;
struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
static bool report;
static unsigned int offset;
static unsigned int remaining_size;
if (count < 2)
return;
data = &device_hcd->resp.buf[0];
if (data[0] != MESSAGE_MARKER)
return;
id = data[1];
size = 0;
LOCK_BUFFER(device_hcd->report);
switch (id) {
case REPORT_TOUCH:
if (count >= 4) {
remaining_size = le2_to_uint(&data[2]);
} else {
report = false;
goto exit;
}
retval = syna_tcm_alloc_mem(tcm_hcd,
&device_hcd->report,
remaining_size);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to allocate memory for device_hcd->report.buf\n");
report = false;
goto exit;
}
idx = 4;
size = count - idx;
offset = 0;
report = true;
break;
case STATUS_CONTINUED_READ:
if (report == false)
goto exit;
if (count >= 2) {
idx = 2;
size = count - idx;
}
break;
default:
goto exit;
}
if (size) {
size = MIN(size, remaining_size);
retval = secure_memcpy(&device_hcd->report.buf[offset],
device_hcd->report.buf_size - offset,
&data[idx],
count - idx,
size);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to copy touch report data\n");
report = false;
goto exit;
} else {
offset += size;
remaining_size -= size;
device_hcd->report.data_length += size;
}
}
if (remaining_size)
goto exit;
LOCK_BUFFER(tcm_hcd->report.buffer);
tcm_hcd->report.buffer.buf = device_hcd->report.buf;
tcm_hcd->report.buffer.buf_size = device_hcd->report.buf_size;
tcm_hcd->report.buffer.data_length = device_hcd->report.data_length;
tcm_hcd->report_touch();
UNLOCK_BUFFER(tcm_hcd->report.buffer);
report = false;
exit:
UNLOCK_BUFFER(device_hcd->report);
return;
}
static int device_capture_touch_report_config(unsigned int count)
{
int retval;
unsigned int size;
unsigned int buf_size;
unsigned char *data;
struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
if (device_hcd->raw_mode) {
if (count < 3) {
LOGE(tcm_hcd->pdev->dev.parent,
"Invalid write data\n");
return -EINVAL;
}
size = le2_to_uint(&device_hcd->out.buf[1]);
if (count - 3 < size) {
LOGE(tcm_hcd->pdev->dev.parent,
"Incomplete write data\n");
return -EINVAL;
}
if (!size)
return 0;
data = &device_hcd->out.buf[3];
buf_size = device_hcd->out.buf_size - 3;
} else {
size = count - 1;
if (!size)
return 0;
data = &device_hcd->out.buf[1];
buf_size = device_hcd->out.buf_size - 1;
}
LOCK_BUFFER(tcm_hcd->config);
retval = syna_tcm_alloc_mem(tcm_hcd,
&tcm_hcd->config,
size);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to allocate memory for tcm_hcd->config.buf\n");
UNLOCK_BUFFER(tcm_hcd->config);
return retval;
}
retval = secure_memcpy(tcm_hcd->config.buf,
tcm_hcd->config.buf_size,
data,
buf_size,
size);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to copy touch report config data\n");
UNLOCK_BUFFER(tcm_hcd->config);
return retval;
}
tcm_hcd->config.data_length = size;
UNLOCK_BUFFER(tcm_hcd->config);
return 0;
}
#ifdef HAVE_UNLOCKED_IOCTL
static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#else
static int device_ioctl(struct inode *inp, struct file *filp, unsigned int cmd,
unsigned long arg)
#endif
{
int retval;
struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
mutex_lock(&tcm_hcd->extif_mutex);
retval = 0;
switch (cmd) {
case DEVICE_IOC_RESET:
retval = tcm_hcd->reset_n_reinit(tcm_hcd, false, true);
break;
case DEVICE_IOC_IRQ:
if (arg == 0)
retval = tcm_hcd->enable_irq(tcm_hcd, false, false);
else if (arg == 1)
retval = tcm_hcd->enable_irq(tcm_hcd, true, NULL);
break;
case DEVICE_IOC_RAW:
if (arg == 0) {
device_hcd->raw_mode = false;
#ifdef WATCHDOG_SW
tcm_hcd->update_watchdog(tcm_hcd, true);
#endif
} else if (arg == 1) {
device_hcd->raw_mode = true;
#ifdef WATCHDOG_SW
tcm_hcd->update_watchdog(tcm_hcd, false);
#endif
}
break;
case DEVICE_IOC_CONCURRENT:
if (arg == 0)
device_hcd->concurrent = false;
else if (arg == 1)
device_hcd->concurrent = true;
break;
default:
retval = -ENOTTY;
break;
}
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static loff_t device_llseek(struct file *filp, loff_t off, int whence)
{
return -EINVAL;
}
static ssize_t device_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
int retval;
struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
if (count == 0)
return 0;
mutex_lock(&tcm_hcd->extif_mutex);
LOCK_BUFFER(device_hcd->resp);
if (device_hcd->raw_mode) {
retval = syna_tcm_alloc_mem(tcm_hcd,
&device_hcd->resp,
count);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to allocate memory for device_hcd->resp.buf\n");
UNLOCK_BUFFER(device_hcd->resp);
goto exit;
}
retval = tcm_hcd->read_message(tcm_hcd,
device_hcd->resp.buf,
count);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to read message\n");
UNLOCK_BUFFER(device_hcd->resp);
goto exit;
}
} else {
if (count != device_hcd->resp.data_length) {
LOGE(tcm_hcd->pdev->dev.parent,
"Invalid length information\n");
UNLOCK_BUFFER(device_hcd->resp);
retval = -EINVAL;
goto exit;
}
}
if (copy_to_user(buf, device_hcd->resp.buf, count)) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to copy data to user space\n");
UNLOCK_BUFFER(device_hcd->resp);
retval = -EINVAL;
goto exit;
}
if (!device_hcd->concurrent)
goto skip_concurrent;
if (tcm_hcd->report_touch == NULL) {
LOGE(tcm_hcd->pdev->dev.parent,
"Unable to report touch\n");
device_hcd->concurrent = false;
}
if (device_hcd->raw_mode)
device_capture_touch_report(count);
skip_concurrent:
UNLOCK_BUFFER(device_hcd->resp);
retval = count;
exit:
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static ssize_t device_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
int retval;
struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
if (count == 0)
return 0;
mutex_lock(&tcm_hcd->extif_mutex);
LOCK_BUFFER(device_hcd->out);
retval = syna_tcm_alloc_mem(tcm_hcd,
&device_hcd->out,
count == 1 ? count + 1 : count);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to allocate memory for device_hcd->out.buf\n");
UNLOCK_BUFFER(device_hcd->out);
goto exit;
}
if (copy_from_user(device_hcd->out.buf, buf, count)) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to copy data from user space\n");
UNLOCK_BUFFER(device_hcd->out);
retval = -EINVAL;
goto exit;
}
LOCK_BUFFER(device_hcd->resp);
if (device_hcd->raw_mode) {
retval = tcm_hcd->write_message(tcm_hcd,
device_hcd->out.buf[0],
&device_hcd->out.buf[1],
count - 1,
NULL,
NULL,
NULL,
NULL,
0);
} else {
mutex_lock(&tcm_hcd->reset_mutex);
retval = tcm_hcd->write_message(tcm_hcd,
device_hcd->out.buf[0],
&device_hcd->out.buf[1],
count - 1,
&device_hcd->resp.buf,
&device_hcd->resp.buf_size,
&device_hcd->resp.data_length,
NULL,
0);
mutex_unlock(&tcm_hcd->reset_mutex);
}
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to write command 0x%02x\n",
device_hcd->out.buf[0]);
UNLOCK_BUFFER(device_hcd->resp);
UNLOCK_BUFFER(device_hcd->out);
goto exit;
}
if (count && device_hcd->out.buf[0] == CMD_SET_TOUCH_REPORT_CONFIG) {
retval = device_capture_touch_report_config(count);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to capture touch report config\n");
}
}
UNLOCK_BUFFER(device_hcd->out);
if (device_hcd->raw_mode)
retval = count;
else
retval = device_hcd->resp.data_length;
UNLOCK_BUFFER(device_hcd->resp);
exit:
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static int device_open(struct inode *inp, struct file *filp)
{
int retval;
struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
mutex_lock(&tcm_hcd->extif_mutex);
if (device_hcd->ref_count < 1) {
device_hcd->ref_count++;
retval = 0;
} else {
retval = -EACCES;
}
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static int device_release(struct inode *inp, struct file *filp)
{
struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
mutex_lock(&tcm_hcd->extif_mutex);
if (device_hcd->ref_count)
device_hcd->ref_count--;
mutex_unlock(&tcm_hcd->extif_mutex);
return 0;
}
static char *device_devnode(struct device *dev, umode_t *mode)
{
if (!mode)
return NULL;
*mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
return kasprintf(GFP_KERNEL, "%s/%s", PLATFORM_DRIVER_NAME,
dev_name(dev));
}
static int device_create_class(void)
{
struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
if (device_hcd->class != NULL)
return 0;
device_hcd->class = class_create(THIS_MODULE, PLATFORM_DRIVER_NAME);
if (IS_ERR(device_hcd->class)) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to create class\n");
return -ENODEV;
}
device_hcd->class->devnode = device_devnode;
return 0;
}
static const struct file_operations device_fops = {
.owner = THIS_MODULE,
#ifdef HAVE_UNLOCKED_IOCTL
.unlocked_ioctl = device_ioctl,
#ifdef HAVE_COMPAT_IOCTL
.compat_ioctl = device_ioctl,
#endif
#else
.ioctl = device_ioctl,
#endif
.llseek = device_llseek,
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release,
};
static int device_init(struct syna_tcm_hcd *tcm_hcd)
{
int retval;
dev_t dev_num;
/* const struct syna_tcm_board_data *bdata = tcm_hcd->hw_if->bdata; */
LOGE(tcm_hcd->pdev->dev.parent, "-----enter-----%s\n", __func__);
device_hcd = kzalloc(sizeof(*device_hcd), GFP_KERNEL);
if (!device_hcd) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to allocate memory for device_hcd\n");
return -ENOMEM;
}
device_hcd->tcm_hcd = tcm_hcd;
device_hcd->concurrent = CONCURRENT;
INIT_BUFFER(device_hcd->out, false);
INIT_BUFFER(device_hcd->resp, false);
INIT_BUFFER(device_hcd->report, false);
if (rmidev_major_num) {
dev_num = MKDEV(rmidev_major_num, 0);
retval = register_chrdev_region(dev_num, 1,
PLATFORM_DRIVER_NAME);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to register char device\n");
goto err_register_chrdev_region;
}
} else {
retval = alloc_chrdev_region(&dev_num, 0, 1,
PLATFORM_DRIVER_NAME);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to allocate char device\n");
goto err_alloc_chrdev_region;
}
rmidev_major_num = MAJOR(dev_num);
}
device_hcd->dev_num = dev_num;
tcm_hcd->tp_dev_num = dev_num;
cdev_init(&device_hcd->char_dev, &device_fops);
retval = cdev_add(&device_hcd->char_dev, dev_num, 1);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to add char device\n");
goto err_add_chardev;
}
retval = device_create_class();
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to create class\n");
goto err_create_class;
}
device_hcd->device = device_create(device_hcd->class, NULL,
device_hcd->dev_num, NULL, CHAR_DEVICE_NAME"%d",
MINOR(device_hcd->dev_num));
if (IS_ERR(device_hcd->device)) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to create device\n");
retval = -ENODEV;
goto err_create_device;
}
/* LOGE(tcm_hcd->pdev->dev.parent, "-----enter-----%s---irq_gpio = %d\n", __func__,bdata->irq_gpio);
if (bdata->irq_gpio >= 0) {
retval = gpio_export(bdata->irq_gpio, false);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to export GPIO\n");
} else {
retval = gpio_export_link(&tcm_hcd->pdev->dev,
"attn", bdata->irq_gpio);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to export GPIO link\n");
}
}
} */
return 0;
err_create_device:
class_destroy(device_hcd->class);
err_create_class:
cdev_del(&device_hcd->char_dev);
err_add_chardev:
unregister_chrdev_region(dev_num, 1);
err_alloc_chrdev_region:
err_register_chrdev_region:
RELEASE_BUFFER(device_hcd->report);
RELEASE_BUFFER(device_hcd->resp);
RELEASE_BUFFER(device_hcd->out);
kfree(device_hcd);
device_hcd = NULL;
return retval;
}
static int device_remove(struct syna_tcm_hcd *tcm_hcd)
{
if (!device_hcd)
goto exit;
device_destroy(device_hcd->class, device_hcd->dev_num);
class_destroy(device_hcd->class);
cdev_del(&device_hcd->char_dev);
unregister_chrdev_region(device_hcd->dev_num, 1);
RELEASE_BUFFER(device_hcd->report);
RELEASE_BUFFER(device_hcd->resp);
RELEASE_BUFFER(device_hcd->out);
kfree(device_hcd);
device_hcd = NULL;
exit:
complete(&device_remove_complete);
return 0;
}
static int device_reinit(struct syna_tcm_hcd *tcm_hcd)
{
int retval;
if (!device_hcd) {
retval = device_init(tcm_hcd);
return retval;
}
return 0;
}
static struct syna_tcm_module_cb device_module = {
.type = TCM_DEVICE,
.init = device_init,
.remove = device_remove,
.syncbox = NULL,
#ifdef REPORT_NOTIFIER
.asyncbox = NULL,
#endif
.reinit = device_reinit,
.suspend = NULL,
.resume = NULL,
.early_suspend = NULL,
};
static int __init device_module_init(void)
{
return syna_tcm_add_module(&device_module, true);
}
static void __exit device_module_exit(void)
{
syna_tcm_add_module(&device_module, false);
wait_for_completion(&device_remove_complete);
return;
}
module_init(device_module_init);
module_exit(device_module_exit);
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics TCM Device Module");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,573 @@
/*
* Synaptics TCM touchscreen driver
*
* Copyright (C) 2017-2018 Synaptics Incorporated. All rights reserved.
*
* Copyright (C) 2017-2018 Scott Lin <scott.lin@tw.synaptics.com>
* Copyright (C) 2018-2019 Ian Su <ian.su@tw.synaptics.com>
* Copyright (C) 2018-2019 Joey Zhou <joey.zhou@synaptics.com>
* Copyright (C) 2018-2019 Yuehao Qiu <yuehao.qiu@synaptics.com>
* Copyright (C) 2018-2019 Aaron Chen <aaron.chen@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.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#include "synaptics_tcm_core.h"
#define SYSFS_DIR_NAME "diagnostics"
enum pingpong_state {
PING = 0,
PONG = 1,
};
struct diag_hcd {
pid_t pid;
unsigned char report_type;
enum pingpong_state state;
struct kobject *sysfs_dir;
struct kernel_siginfo sigio;
struct task_struct *task;
struct syna_tcm_buffer ping;
struct syna_tcm_buffer pong;
struct syna_tcm_hcd *tcm_hcd;
};
DECLARE_COMPLETION(diag_remove_complete);
static struct diag_hcd *diag_hcd;
STORE_PROTOTYPE(diag, pid)
SHOW_PROTOTYPE(diag, size)
STORE_PROTOTYPE(diag, type)
SHOW_PROTOTYPE(diag, rows)
SHOW_PROTOTYPE(diag, cols)
SHOW_PROTOTYPE(diag, hybrid)
SHOW_PROTOTYPE(diag, buttons)
static struct device_attribute *attrs[] = {
ATTRIFY(pid),
ATTRIFY(size),
ATTRIFY(type),
ATTRIFY(rows),
ATTRIFY(cols),
ATTRIFY(hybrid),
ATTRIFY(buttons),
};
static ssize_t diag_sysfs_data_show(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count);
static struct bin_attribute bin_attr = {
.attr = {
.name = "data",
.mode = S_IRUGO,
},
.size = 0,
.read = diag_sysfs_data_show,
};
static ssize_t diag_sysfs_pid_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int retval;
unsigned int input;
struct syna_tcm_hcd *tcm_hcd = diag_hcd->tcm_hcd;
if (sscanf(buf, "%u", &input) != 1)
return -EINVAL;
mutex_lock(&tcm_hcd->extif_mutex);
diag_hcd->pid = input;
if (diag_hcd->pid) {
diag_hcd->task = pid_task(find_vpid(diag_hcd->pid),
PIDTYPE_PID);
if (!diag_hcd->task) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to locate task\n");
retval = -EINVAL;
goto exit;
}
}
retval = count;
exit:
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static ssize_t diag_sysfs_size_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int retval;
struct syna_tcm_hcd *tcm_hcd = diag_hcd->tcm_hcd;
mutex_lock(&tcm_hcd->extif_mutex);
if (diag_hcd->state == PING) {
LOCK_BUFFER(diag_hcd->ping);
retval = snprintf(buf, PAGE_SIZE,
"%u\n",
diag_hcd->ping.data_length);
UNLOCK_BUFFER(diag_hcd->ping);
} else {
LOCK_BUFFER(diag_hcd->pong);
retval = snprintf(buf, PAGE_SIZE,
"%u\n",
diag_hcd->pong.data_length);
UNLOCK_BUFFER(diag_hcd->pong);
}
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static ssize_t diag_sysfs_type_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned int input;
struct syna_tcm_hcd *tcm_hcd = diag_hcd->tcm_hcd;
if (sscanf(buf, "%u", &input) != 1)
return -EINVAL;
mutex_lock(&tcm_hcd->extif_mutex);
diag_hcd->report_type = (unsigned char)input;
mutex_unlock(&tcm_hcd->extif_mutex);
return count;
}
static ssize_t diag_sysfs_rows_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int retval;
unsigned int rows;
struct syna_tcm_app_info *app_info;
struct syna_tcm_hcd *tcm_hcd = diag_hcd->tcm_hcd;
mutex_lock(&tcm_hcd->extif_mutex);
if (IS_NOT_FW_MODE(tcm_hcd->id_info.mode) ||
tcm_hcd->app_status != APP_STATUS_OK) {
retval = -ENODEV;
goto exit;
}
app_info = &tcm_hcd->app_info;
rows = le2_to_uint(app_info->num_of_image_rows);
retval = snprintf(buf, PAGE_SIZE, "%u\n", rows);
exit:
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static ssize_t diag_sysfs_cols_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int retval;
unsigned int cols;
struct syna_tcm_app_info *app_info;
struct syna_tcm_hcd *tcm_hcd = diag_hcd->tcm_hcd;
mutex_lock(&tcm_hcd->extif_mutex);
if (IS_NOT_FW_MODE(tcm_hcd->id_info.mode) ||
tcm_hcd->app_status != APP_STATUS_OK) {
retval = -ENODEV;
goto exit;
}
app_info = &tcm_hcd->app_info;
cols = le2_to_uint(app_info->num_of_image_cols);
retval = snprintf(buf, PAGE_SIZE, "%u\n", cols);
exit:
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static ssize_t diag_sysfs_hybrid_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int retval;
unsigned int hybrid;
struct syna_tcm_app_info *app_info;
struct syna_tcm_hcd *tcm_hcd = diag_hcd->tcm_hcd;
mutex_lock(&tcm_hcd->extif_mutex);
if (IS_NOT_FW_MODE(tcm_hcd->id_info.mode) ||
tcm_hcd->app_status != APP_STATUS_OK) {
retval = -ENODEV;
goto exit;
}
app_info = &tcm_hcd->app_info;
hybrid = le2_to_uint(app_info->has_hybrid_data);
retval = snprintf(buf, PAGE_SIZE, "%u\n", hybrid);
exit:
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static ssize_t diag_sysfs_buttons_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int retval;
unsigned int buttons;
struct syna_tcm_app_info *app_info;
struct syna_tcm_hcd *tcm_hcd = diag_hcd->tcm_hcd;
mutex_lock(&tcm_hcd->extif_mutex);
if (IS_NOT_FW_MODE(tcm_hcd->id_info.mode) ||
tcm_hcd->app_status != APP_STATUS_OK) {
retval = -ENODEV;
goto exit;
}
app_info = &tcm_hcd->app_info;
buttons = le2_to_uint(app_info->num_of_buttons);
retval = snprintf(buf, PAGE_SIZE, "%u\n", buttons);
exit:
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static ssize_t diag_sysfs_data_show(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count)
{
int retval;
unsigned int readlen;
struct syna_tcm_hcd *tcm_hcd = diag_hcd->tcm_hcd;
mutex_lock(&tcm_hcd->extif_mutex);
retval = 0;
if (diag_hcd->state == PING) {
LOCK_BUFFER(diag_hcd->ping);
if (diag_hcd->ping.data_length == 0) {
readlen = 0;
goto exit;
}
readlen = MIN(count, diag_hcd->ping.data_length - pos);
if (diag_hcd->ping.data_length) {
retval = secure_memcpy(buf,
count,
&diag_hcd->ping.buf[pos],
diag_hcd->ping.buf_size - pos,
readlen);
}
UNLOCK_BUFFER(diag_hcd->ping);
} else {
LOCK_BUFFER(diag_hcd->pong);
if (diag_hcd->pong.data_length == 0) {
readlen = 0;
goto exit;
}
readlen = MIN(count, diag_hcd->pong.data_length - pos);
if (diag_hcd->pong.data_length) {
retval = secure_memcpy(buf,
count,
&diag_hcd->pong.buf[pos],
diag_hcd->pong.buf_size - pos,
readlen);
}
UNLOCK_BUFFER(diag_hcd->pong);
}
exit:
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to copy report data\n");
} else {
retval = readlen;
}
mutex_unlock(&tcm_hcd->extif_mutex);
return retval;
}
static void diag_report(void)
{
int retval;
static enum pingpong_state state = PING;
struct syna_tcm_hcd *tcm_hcd = diag_hcd->tcm_hcd;
if (state == PING) {
LOCK_BUFFER(diag_hcd->ping);
retval = syna_tcm_alloc_mem(tcm_hcd,
&diag_hcd->ping,
tcm_hcd->report.buffer.data_length);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to allocate memory for diag_hcd->ping.buf\n");
UNLOCK_BUFFER(diag_hcd->ping);
return;
}
retval = secure_memcpy(diag_hcd->ping.buf,
diag_hcd->ping.buf_size,
tcm_hcd->report.buffer.buf,
tcm_hcd->report.buffer.buf_size,
tcm_hcd->report.buffer.data_length);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to copy report data\n");
UNLOCK_BUFFER(diag_hcd->ping);
return;
}
diag_hcd->ping.data_length = tcm_hcd->report.buffer.data_length;
UNLOCK_BUFFER(diag_hcd->ping);
diag_hcd->state = state;
state = PONG;
} else {
LOCK_BUFFER(diag_hcd->pong);
retval = syna_tcm_alloc_mem(tcm_hcd,
&diag_hcd->pong,
tcm_hcd->report.buffer.data_length);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to allocate memory for diag_hcd->pong.buf\n");
UNLOCK_BUFFER(diag_hcd->pong);
return;
}
retval = secure_memcpy(diag_hcd->pong.buf,
diag_hcd->pong.buf_size,
tcm_hcd->report.buffer.buf,
tcm_hcd->report.buffer.buf_size,
tcm_hcd->report.buffer.data_length);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to copy report data\n");
UNLOCK_BUFFER(diag_hcd->pong);
return;
}
diag_hcd->pong.data_length = tcm_hcd->report.buffer.data_length;
UNLOCK_BUFFER(diag_hcd->pong);
diag_hcd->state = state;
state = PING;
}
if (diag_hcd->pid)
send_sig_info(SIGIO, &diag_hcd->sigio, diag_hcd->task);
return;
}
static int diag_init(struct syna_tcm_hcd *tcm_hcd)
{
int retval;
int idx;
diag_hcd = kzalloc(sizeof(*diag_hcd), GFP_KERNEL);
if (!diag_hcd) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to allocate memory for diag_hcd\n");
return -ENOMEM;
}
diag_hcd->tcm_hcd = tcm_hcd;
diag_hcd->state = PING;
INIT_BUFFER(diag_hcd->ping, false);
INIT_BUFFER(diag_hcd->pong, false);
memset(&diag_hcd->sigio, 0x00, sizeof(diag_hcd->sigio));
diag_hcd->sigio.si_signo = SIGIO;
diag_hcd->sigio.si_code = SI_USER;
diag_hcd->sysfs_dir = kobject_create_and_add(SYSFS_DIR_NAME,
tcm_hcd->sysfs_dir);
if (!diag_hcd->sysfs_dir) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to create sysfs directory\n");
retval = -EINVAL;
goto err_sysfs_create_dir;
}
for (idx = 0; idx < ARRAY_SIZE(attrs); idx++) {
retval = sysfs_create_file(diag_hcd->sysfs_dir,
&(*attrs[idx]).attr);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to create sysfs file\n");
goto err_sysfs_create_file;
}
}
retval = sysfs_create_bin_file(diag_hcd->sysfs_dir, &bin_attr);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to create sysfs bin file\n");
goto err_sysfs_create_bin_file;
}
return 0;
err_sysfs_create_bin_file:
err_sysfs_create_file:
for (idx--; idx >= 0; idx--)
sysfs_remove_file(diag_hcd->sysfs_dir, &(*attrs[idx]).attr);
kobject_put(diag_hcd->sysfs_dir);
err_sysfs_create_dir:
RELEASE_BUFFER(diag_hcd->pong);
RELEASE_BUFFER(diag_hcd->ping);
kfree(diag_hcd);
diag_hcd = NULL;
return retval;
}
static int diag_remove(struct syna_tcm_hcd *tcm_hcd)
{
int idx;
if (!diag_hcd)
goto exit;
sysfs_remove_bin_file(diag_hcd->sysfs_dir, &bin_attr);
for (idx = 0; idx < ARRAY_SIZE(attrs); idx++)
sysfs_remove_file(diag_hcd->sysfs_dir, &(*attrs[idx]).attr);
kobject_put(diag_hcd->sysfs_dir);
RELEASE_BUFFER(diag_hcd->pong);
RELEASE_BUFFER(diag_hcd->ping);
kfree(diag_hcd);
diag_hcd = NULL;
exit:
complete(&diag_remove_complete);
return 0;
}
static int diag_syncbox(struct syna_tcm_hcd *tcm_hcd)
{
if (!diag_hcd)
return 0;
if (tcm_hcd->report.id == diag_hcd->report_type)
diag_report();
return 0;
}
static int diag_reinit(struct syna_tcm_hcd *tcm_hcd)
{
int retval;
if (!diag_hcd) {
retval = diag_init(tcm_hcd);
return retval;
}
return 0;
}
static struct syna_tcm_module_cb diag_module = {
.type = TCM_DIAGNOSTICS,
.init = diag_init,
.remove = diag_remove,
.syncbox = diag_syncbox,
#ifdef REPORT_NOTIFIER
.asyncbox = NULL,
#endif
.reinit = diag_reinit,
.suspend = NULL,
.resume = NULL,
.early_suspend = NULL,
};
static int __init diag_module_init(void)
{
return syna_tcm_add_module(&diag_module, true);
}
static void __exit diag_module_exit(void)
{
syna_tcm_add_module(&diag_module, false);
wait_for_completion(&diag_remove_complete);
return;
}
module_init(diag_module_init);
module_exit(diag_module_exit);
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics TCM Diagnostics Module");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,742 @@
/*
* Synaptics TCM touchscreen driver
*
* Copyright (C) 2017-2018 Synaptics Incorporated. All rights reserved.
*
* Copyright (C) 2017-2018 Scott Lin <scott.lin@tw.synaptics.com>
* Copyright (C) 2018-2019 Ian Su <ian.su@tw.synaptics.com>
* Copyright (C) 2018-2019 Joey Zhou <joey.zhou@synaptics.com>
* Copyright (C) 2018-2019 Yuehao Qiu <yuehao.qiu@synaptics.com>
* Copyright (C) 2018-2019 Aaron Chen <aaron.chen@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.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#include "synaptics_tcm_core.h"
static unsigned char *buf;
static unsigned int buf_size;
static struct spi_transfer *xfer;
static struct syna_tcm_bus_io bus_io;
static struct syna_tcm_hw_interface hw_if;
static struct platform_device *syna_tcm_spi_device;
#ifdef CONFIG_OF
static int parse_dt(struct device *dev, struct syna_tcm_board_data *bdata)
{
int retval;
u32 value;
struct property *prop;
struct device_node *np = dev->of_node;
const char *name_tmp;
LOGE(dev, "-----entert-----%s\n", __func__);
prop = of_find_property(np, "synaptics,irq-gpio", NULL);
if (prop && prop->length) {
bdata->irq_gpio = of_get_named_gpio_flags(np,
"synaptics,irq-gpio", 0,
(enum of_gpio_flags *)&bdata->irq_flags);
} else {
bdata->irq_gpio = -1;
}
retval = of_property_read_u32(np, "synaptics,irq-on-state", &value);
if (retval < 0)
bdata->irq_on_state = 0;
else
bdata->irq_on_state = value;
/* retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
if (retval < 0)
bdata->pwr_reg_name = NULL;
else
bdata->pwr_reg_name = name; */
/* retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
if (retval < 0)
bdata->bus_reg_name = NULL;
else
bdata->bus_reg_name = name; */
prop = of_find_property(np, "synaptics,power-gpio", NULL);
if (prop && prop->length) {
bdata->power_gpio = of_get_named_gpio_flags(np,
"synaptics,power-gpio", 0, NULL);
} else {
bdata->power_gpio = -1;
}
prop = of_find_property(np, "synaptics,power-on-state", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,power-on-state",
&value);
if (retval < 0) {
LOGE(dev,
"Failed to read synaptics,power-on-state property\n");
return retval;
} else {
bdata->power_on_state = value;
}
} else {
bdata->power_on_state = 0;
}
prop = of_find_property(np, "synaptics,power-delay-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,power-delay-ms",
&value);
if (retval < 0) {
LOGE(dev,
"Failed to read synaptics,power-delay-ms property\n");
return retval;
} else {
bdata->power_delay_ms = value;
}
} else {
bdata->power_delay_ms = 0;
}
memset(bdata->avdd_name, 0, sizeof(bdata->avdd_name));
retval = of_property_read_string(np, "synaptics,avdd-name", &name_tmp);
if (!retval) {
LOGE(dev, "avdd name form dt: %s\n", name_tmp);
if (strlen(name_tmp) < sizeof(bdata->avdd_name))
strncpy(bdata->avdd_name,
name_tmp, sizeof(bdata->avdd_name));
else
LOGE(dev, "invalied avdd name length: %ld > %ld", strlen(name_tmp), sizeof(bdata->avdd_name));
}
memset(bdata->iovdd_name, 0, sizeof(bdata->iovdd_name));
retval = of_property_read_string(np, "synaptics,iovdd-name", &name_tmp);
if (!retval) {
LOGE(dev, "iovdd name form dt: %s", name_tmp);
if (strlen(name_tmp) < sizeof(bdata->iovdd_name))
strncpy(bdata->iovdd_name,
name_tmp, sizeof(bdata->iovdd_name));
else
LOGE(dev, "invalied iovdd name length: %ld > %ld",
strlen(name_tmp),
sizeof(bdata->iovdd_name));
}
prop = of_find_property(np, "synaptics,reset-gpio", NULL);
if (prop && prop->length) {
bdata->reset_gpio = of_get_named_gpio_flags(np,
"synaptics,reset-gpio", 0, NULL);
} else {
bdata->reset_gpio = -1;
}
prop = of_find_property(np, "synaptics,reset-on-state", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,reset-on-state",
&value);
if (retval < 0) {
LOGE(dev,
"Failed to read synaptics,reset-on-state property\n");
return retval;
} else {
bdata->reset_on_state = value;
}
} else {
bdata->reset_on_state = 0;
}
prop = of_find_property(np, "synaptics,reset-active-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,reset-active-ms",
&value);
if (retval < 0) {
LOGE(dev,
"Failed to read synaptics,reset-active-ms property\n");
return retval;
} else {
bdata->reset_active_ms = value;
}
} else {
bdata->reset_active_ms = 0;
}
prop = of_find_property(np, "synaptics,reset-delay-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
&value);
if (retval < 0) {
LOGE(dev,
"Unable to read synaptics,reset-delay-ms property\n");
return retval;
} else {
bdata->reset_delay_ms = value;
}
} else {
bdata->reset_delay_ms = 0;
}
/*prop = of_find_property(np, "synaptics,tpio-reset-gpio", NULL);
if (prop && prop->length) {
bdata->tpio_reset_gpio = of_get_named_gpio_flags(np,
"synaptics,tpio-reset-gpio", 0, NULL);
} else {
bdata->tpio_reset_gpio = -1;
}*/
prop = of_find_property(np, "synaptics,x-flip", NULL);
bdata->x_flip = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,y-flip", NULL);
bdata->y_flip = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,swap-axes", NULL);
bdata->swap_axes = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,byte-delay-us", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,byte-delay-us",
&value);
if (retval < 0) {
LOGE(dev,
"Unable to read synaptics,byte-delay-us property\n");
return retval;
} else {
bdata->byte_delay_us = value;
}
} else {
bdata->byte_delay_us = 0;
}
prop = of_find_property(np, "synaptics,block-delay-us", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,block-delay-us",
&value);
if (retval < 0) {
LOGE(dev,
"Unable to read synaptics,block-delay-us property\n");
return retval;
} else {
bdata->block_delay_us = value;
}
} else {
bdata->block_delay_us = 0;
}
prop = of_find_property(np, "synaptics,spi-mode", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,spi-mode",
&value);
if (retval < 0) {
LOGE(dev,
"Unable to read synaptics,spi-mode property\n");
return retval;
} else {
bdata->spi_mode = value;
}
} else {
bdata->spi_mode = 0;
}
prop = of_find_property(np, "synaptics,ubl-max-freq", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,ubl-max-freq",
&value);
if (retval < 0) {
LOGE(dev,
"Unable to read synaptics,ubl-max-freq property\n");
return retval;
} else {
bdata->ubl_max_freq = value;
}
} else {
bdata->ubl_max_freq = 0;
}
prop = of_find_property(np, "synaptics,ubl-byte-delay-us", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,ubl-byte-delay-us",
&value);
if (retval < 0) {
LOGE(dev,
"Unable to read synaptics,ubl-byte-delay-us property\n");
return retval;
} else {
bdata->ubl_byte_delay_us = value;
}
} else {
bdata->ubl_byte_delay_us = 0;
}
return 0;
}
#endif
static int syna_tcm_spi_alloc_mem(struct syna_tcm_hcd *tcm_hcd,
unsigned int count, unsigned int size)
{
static unsigned int xfer_count;
struct spi_device *spi = to_spi_device(tcm_hcd->pdev->dev.parent);
if (count > xfer_count) {
kfree(xfer);
xfer = kcalloc(count, sizeof(*xfer), GFP_KERNEL);
if (!xfer) {
LOGE(&spi->dev,
"Failed to allocate memory for xfer\n");
xfer_count = 0;
return -ENOMEM;
}
xfer_count = count;
} else {
memset(xfer, 0, count * sizeof(*xfer));
}
if (size > buf_size) {
if (buf_size)
kfree(buf);
buf = kmalloc(size, GFP_KERNEL);
if (!buf) {
LOGE(&spi->dev,
"Failed to allocate memory for buf\n");
buf_size = 0;
return -ENOMEM;
}
buf_size = size;
}
return 0;
}
static int syna_tcm_spi_rmi_read(struct syna_tcm_hcd *tcm_hcd,
unsigned short addr, unsigned char *data, unsigned int length)
{
int retval;
unsigned int idx;
unsigned int mode;
unsigned int byte_count;
struct spi_message msg;
struct spi_device *spi = to_spi_device(tcm_hcd->pdev->dev.parent);
const struct syna_tcm_board_data *bdata = tcm_hcd->hw_if->bdata;
mutex_lock(&tcm_hcd->io_ctrl_mutex);
spi_message_init(&msg);
byte_count = length + 2;
if (bdata->ubl_byte_delay_us == 0)
retval = syna_tcm_spi_alloc_mem(tcm_hcd, 2, byte_count);
else
retval = syna_tcm_spi_alloc_mem(tcm_hcd, byte_count, 3);
if (retval < 0) {
LOGE(&spi->dev,
"Failed to allocate memory\n");
goto exit;
}
buf[0] = (unsigned char)(addr >> 8) | 0x80;
buf[1] = (unsigned char)addr;
if (bdata->ubl_byte_delay_us == 0) {
xfer[0].len = 2;
xfer[0].tx_buf = buf;
xfer[0].speed_hz = bdata->ubl_max_freq;
spi_message_add_tail(&xfer[0], &msg);
memset(&buf[2], 0xff, length);
xfer[1].len = length;
xfer[1].tx_buf = &buf[2];
xfer[1].rx_buf = data;
if (bdata->block_delay_us)
xfer[1].delay_usecs = bdata->block_delay_us;
xfer[1].speed_hz = bdata->ubl_max_freq;
spi_message_add_tail(&xfer[1], &msg);
} else {
buf[2] = 0xff;
for (idx = 0; idx < byte_count; idx++) {
xfer[idx].len = 1;
if (idx < 2) {
xfer[idx].tx_buf = &buf[idx];
} else {
xfer[idx].tx_buf = &buf[2];
xfer[idx].rx_buf = &data[idx - 2];
}
xfer[idx].delay_usecs = bdata->ubl_byte_delay_us;
if (bdata->block_delay_us && (idx == byte_count - 1))
xfer[idx].delay_usecs = bdata->block_delay_us;
xfer[idx].speed_hz = bdata->ubl_max_freq;
spi_message_add_tail(&xfer[idx], &msg);
}
}
mode = spi->mode;
spi->mode = SPI_MODE_3;
retval = spi_sync(spi, &msg);
if (retval == 0) {
retval = length;
} else {
LOGE(&spi->dev,
"Failed to complete SPI transfer, error = %d\n",
retval);
}
spi->mode = mode;
exit:
mutex_unlock(&tcm_hcd->io_ctrl_mutex);
return retval;
}
static int syna_tcm_spi_rmi_write(struct syna_tcm_hcd *tcm_hcd,
unsigned short addr, unsigned char *data, unsigned int length)
{
int retval;
unsigned int mode;
unsigned int byte_count;
struct spi_message msg;
struct spi_device *spi = to_spi_device(tcm_hcd->pdev->dev.parent);
const struct syna_tcm_board_data *bdata = tcm_hcd->hw_if->bdata;
mutex_lock(&tcm_hcd->io_ctrl_mutex);
spi_message_init(&msg);
byte_count = length + 2;
retval = syna_tcm_spi_alloc_mem(tcm_hcd, 1, byte_count);
if (retval < 0) {
LOGE(&spi->dev,
"Failed to allocate memory\n");
goto exit;
}
buf[0] = (unsigned char)(addr >> 8) & ~0x80;
buf[1] = (unsigned char)addr;
retval = secure_memcpy(&buf[2],
buf_size - 2,
data,
length,
length);
if (retval < 0) {
LOGE(&spi->dev,
"Failed to copy write data\n");
goto exit;
}
xfer[0].len = byte_count;
xfer[0].tx_buf = buf;
if (bdata->block_delay_us)
xfer[0].delay_usecs = bdata->block_delay_us;
spi_message_add_tail(&xfer[0], &msg);
mode = spi->mode;
spi->mode = SPI_MODE_3;
retval = spi_sync(spi, &msg);
if (retval == 0) {
retval = length;
} else {
LOGE(&spi->dev,
"Failed to complete SPI transfer, error = %d\n",
retval);
}
spi->mode = mode;
exit:
mutex_unlock(&tcm_hcd->io_ctrl_mutex);
return retval;
}
static int syna_tcm_spi_read(struct syna_tcm_hcd *tcm_hcd, unsigned char *data,
unsigned int length)
{
int retval;
unsigned int idx;
struct spi_message msg;
struct spi_device *spi = to_spi_device(tcm_hcd->pdev->dev.parent);
const struct syna_tcm_board_data *bdata = tcm_hcd->hw_if->bdata;
mutex_lock(&tcm_hcd->io_ctrl_mutex);
pm_wakeup_event(&syna_tcm_spi_device->dev, 0);
pm_stay_awake(&syna_tcm_spi_device->dev);
if (tcm_hcd->tp_pm_suspend) {
LOGI(tcm_hcd->pdev->dev.parent,
"Touch is in pm_suspend status!\n");
retval = wait_for_completion_timeout(&tcm_hcd->pm_resume_completion,
msecs_to_jiffies(500));
if (!retval) {
LOGE(tcm_hcd->pdev->dev.parent,
"wait_for_completion_timeout!\n");
goto exit;
}
}
spi_message_init(&msg);
if (bdata->byte_delay_us == 0)
retval = syna_tcm_spi_alloc_mem(tcm_hcd, 1, length);
else
retval = syna_tcm_spi_alloc_mem(tcm_hcd, length, 1);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to allocate memory\n");
goto exit;
}
if (bdata->byte_delay_us == 0) {
memset(buf, 0xff, length);
xfer[0].len = length;
xfer[0].tx_buf = buf;
xfer[0].rx_buf = data;
if (bdata->block_delay_us)
xfer[0].delay_usecs = bdata->block_delay_us;
spi_message_add_tail(&xfer[0], &msg);
} else {
buf[0] = 0xff;
for (idx = 0; idx < length; idx++) {
xfer[idx].len = 1;
xfer[idx].tx_buf = buf;
xfer[idx].rx_buf = &data[idx];
xfer[idx].delay_usecs = bdata->byte_delay_us;
if (bdata->block_delay_us && (idx == length - 1))
xfer[idx].delay_usecs = bdata->block_delay_us;
spi_message_add_tail(&xfer[idx], &msg);
}
}
retval = spi_sync(spi, &msg);
if (retval == 0) {
retval = length;
} else {
LOGE(&spi->dev,
"Failed to complete SPI transfer, error = %d\n",
retval);
}
exit:
pm_relax(&syna_tcm_spi_device->dev);
mutex_unlock(&tcm_hcd->io_ctrl_mutex);
return retval;
}
static int syna_tcm_spi_write(struct syna_tcm_hcd *tcm_hcd, unsigned char *data,
unsigned int length)
{
int retval;
unsigned int idx;
struct spi_message msg;
struct spi_device *spi = to_spi_device(tcm_hcd->pdev->dev.parent);
const struct syna_tcm_board_data *bdata = tcm_hcd->hw_if->bdata;
mutex_lock(&tcm_hcd->io_ctrl_mutex);
pm_wakeup_event(&syna_tcm_spi_device->dev, 0);
pm_stay_awake(&syna_tcm_spi_device->dev);
if (tcm_hcd->tp_pm_suspend) {
LOGI(tcm_hcd->pdev->dev.parent,
"Touch is in pm_suspend status!\n");
retval = wait_for_completion_timeout(&tcm_hcd->pm_resume_completion,
msecs_to_jiffies(500));
if (!retval) {
LOGE(tcm_hcd->pdev->dev.parent,
"wait_for_completion_timeout!\n");
goto exit;
}
}
spi_message_init(&msg);
if (bdata->byte_delay_us == 0)
retval = syna_tcm_spi_alloc_mem(tcm_hcd, 1, 0);
else
retval = syna_tcm_spi_alloc_mem(tcm_hcd, length, 0);
if (retval < 0) {
LOGE(&spi->dev,
"Failed to allocate memory\n");
goto exit;
}
if (bdata->byte_delay_us == 0) {
xfer[0].len = length;
xfer[0].tx_buf = data;
if (bdata->block_delay_us)
xfer[0].delay_usecs = bdata->block_delay_us;
spi_message_add_tail(&xfer[0], &msg);
} else {
for (idx = 0; idx < length; idx++) {
xfer[idx].len = 1;
xfer[idx].tx_buf = &data[idx];
xfer[idx].delay_usecs = bdata->byte_delay_us;
if (bdata->block_delay_us && (idx == length - 1))
xfer[idx].delay_usecs = bdata->block_delay_us;
spi_message_add_tail(&xfer[idx], &msg);
}
}
retval = spi_sync(spi, &msg);
if (retval == 0) {
retval = length;
} else {
LOGE(&spi->dev,
"Failed to complete SPI transfer, error = %d\n",
retval);
}
exit:
pm_relax(&syna_tcm_spi_device->dev);
mutex_unlock(&tcm_hcd->io_ctrl_mutex);
return retval;
}
static int syna_tcm_spi_probe(struct spi_device *spi)
{
int retval;
LOGE(&spi->dev, "-----enter-----%s\n", __func__);
if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) {
LOGE(&spi->dev,
"Full duplex not supported by host\n");
return -EIO;
}
syna_tcm_spi_device = platform_device_alloc(PLATFORM_DRIVER_NAME, 0);
if (!syna_tcm_spi_device) {
LOGE(&spi->dev,
"Failed to allocate platform device\n");
return -ENOMEM;
}
#ifdef CONFIG_OF
hw_if.bdata = devm_kzalloc(&spi->dev, sizeof(*hw_if.bdata), GFP_KERNEL);
if (!hw_if.bdata) {
LOGE(&spi->dev,
"Failed to allocate memory for board data\n");
return -ENOMEM;
}
parse_dt(&spi->dev, hw_if.bdata);
#else
hw_if.bdata = spi->dev.platform_data;
#endif
switch (hw_if.bdata->spi_mode) {
case 0:
spi->mode = SPI_MODE_0;
break;
case 1:
spi->mode = SPI_MODE_1;
break;
case 2:
spi->mode = SPI_MODE_2;
break;
case 3:
spi->mode = SPI_MODE_3;
break;
}
bus_io.type = BUS_SPI;
bus_io.read = syna_tcm_spi_read;
bus_io.write = syna_tcm_spi_write;
bus_io.rmi_read = syna_tcm_spi_rmi_read;
bus_io.rmi_write = syna_tcm_spi_rmi_write;
hw_if.bus_io = &bus_io;
spi->bits_per_word = 8;
retval = spi_setup(spi);
if (retval < 0) {
LOGE(&spi->dev,
"Failed to set up SPI protocol driver\n");
return retval;
}
syna_tcm_spi_device->dev.parent = &spi->dev;
syna_tcm_spi_device->dev.platform_data = &hw_if;
retval = platform_device_add(syna_tcm_spi_device);
if (retval < 0) {
LOGE(&spi->dev,
"Failed to add platform device\n");
return retval;
}
return 0;
}
static int syna_tcm_spi_remove(struct spi_device *spi)
{
syna_tcm_spi_device->dev.platform_data = NULL;
platform_device_unregister(syna_tcm_spi_device);
return 0;
}
static const struct spi_device_id syna_tcm_id_table[] = {
{SPI_MODULE_NAME, 0},
{},
};
MODULE_DEVICE_TABLE(spi, syna_tcm_id_table);
#ifdef CONFIG_OF
static struct of_device_id syna_tcm_of_match_table[] = {
{
.compatible = "synaptics,tcm-spi",
},
{},
};
MODULE_DEVICE_TABLE(of, syna_tcm_of_match_table);
#else
#define syna_tcm_of_match_table NULL
#endif
static struct spi_driver syna_tcm_spi_driver = {
.driver = {
.name = SPI_MODULE_NAME,
.owner = THIS_MODULE,
.of_match_table = syna_tcm_of_match_table,
},
.probe = syna_tcm_spi_probe,
.remove = syna_tcm_spi_remove,
.id_table = syna_tcm_id_table,
};
int syna_tcm_bus_init(void)
{
return spi_register_driver(&syna_tcm_spi_driver);
}
EXPORT_SYMBOL(syna_tcm_bus_init);
void syna_tcm_bus_exit(void)
{
kfree(buf);
kfree(xfer);
spi_unregister_driver(&syna_tcm_spi_driver);
return;
}
EXPORT_SYMBOL(syna_tcm_bus_exit);
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics TCM SPI Bus Module");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,271 @@
/*
* Synaptics TCM touchscreen driver
*
* Copyright (C) 2017-2018 Synaptics Incorporated. All rights reserved.
*
* Copyright (C) 2017-2018 Scott Lin <scott.lin@tw.synaptics.com>
* Copyright (C) 2018-2019 Ian Su <ian.su@tw.synaptics.com>
* Copyright (C) 2018-2019 Joey Zhou <joey.zhou@synaptics.com>
* Copyright (C) 2018-2019 Yuehao Qiu <yuehao.qiu@synaptics.com>
* Copyright (C) 2018-2019 Aaron Chen <aaron.chen@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.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#ifndef _SYNAPTICS_TCM_TESTING_H_
#define _SYNAPTICS_TCM_TESTING_H_
#define ABS(x) (((x) < 0) ? (-(x)) : (x))
#define DATA_SIZE_MAX (30)
#define SAVE_BUF_SIZE (4096*2)
#define RESULT_INFO_LEN (200)
#define PT1_PT3_LIMITS_BYTES_SIZE (8)
#define PT10_LIMITS_BYTES_SIZE (1)
#define SYNA_TCM_TESTING_LIMITS_FILE_NAME "k9b_test_limits_S3908P.csv"
#define CSV_PT1_TESTING_LIMITS "PT1_TRx_TRx_short_test"
#define CSV_PT3_TESTING_LIMITS "PT3_TRX_GND_short_test"
#define CSV_PT5_TESTING_LIMITS_MIN "PT5_Full_raw_cap_test_min"
#define CSV_PT5_TESTING_LIMITS_MAX "PT5_Full_raw_cap_test_max"
#define CSV_PT10_TESTING_LIMITS "PT10_(Mutal)_noise_test"
#define CSV_PT18_TESTING_LIMITS_MIN "PT18_Abs_raw_cap_test_min"
#define CSV_PT18_TESTING_LIMITS_MAX "PT18_Abs_raw_cap_test_max"
#define CSV_PT22_TESTING_LIMITS_MIN "PT22_Trans_raw_cap_test_min"
#define CSV_PT22_TESTING_LIMITS_MAX "PT22_Trans_raw_cap_test_max"
#define CSV_GAP_DIFF_TESTING_LIMITS_MAX "Gap_Diff_test_max"
#define TESTING_RESULT_IN_CSV (1)
#if TESTING_RESULT_IN_CSV
#define SYNA_TCM_TESTING_RESULT_SAVE_PATH "/data/k9b_tp_test_result.csv"
#endif
static inline void uint_to_le1(unsigned char *dest, unsigned int val)
{
dest[0] = val%0x100;
}
static inline void uint_to_le2(unsigned char *dest, unsigned int val)
{
dest[0] = val%0x100;
dest[1] = val/0x100;
}
static inline void uint_to_le4(unsigned char *dest, unsigned int val)
{
unsigned int vl, vh;
vl = val%0x10000;
vh = val/0x10000;
uint_to_le2(dest, vl);
uint_to_le2(dest + 2, vh);
}
/* test limit for the device id checking */
static const char *device_id_limit = "s3908p-15.0.0";
/* test limit for the config id checking */
static const char config_id_limit[16] = {
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47
};
/* test limit for the pt7 testing */
/* including upper and lower bounds */
static const unsigned short pt7_hi_limits[40][40] = {
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700},
};
static const unsigned short pt7_lo_limits[40][40] = {
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300},
{300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300}
};
/* test limit for the pt11 testing */
/* including upper and lower bounds */
static const short pt11_hi_limits[40][40] = {
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
};
static const short pt11_lo_limits[40][40] = {
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,-8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
{-8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8},
};
/* test limit for the hw reset pin testing */
static const unsigned char reset_open_limit = 0x13;
#endif /* end of _SYNAPTICS_TCM_TESTING_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
/*
* Synaptics TCM touchscreen driver
*
* Copyright (C) 2017-2018 Synaptics Incorporated. All rights reserved.
*
* Copyright (C) 2017-2018 Scott Lin <scott.lin@tw.synaptics.com>
* Copyright (C) 2018-2019 Ian Su <ian.su@tw.synaptics.com>
* Copyright (C) 2018-2019 Joey Zhou <joey.zhou@synaptics.com>
* Copyright (C) 2018-2019 Yuehao Qiu <yuehao.qiu@synaptics.com>
* Copyright (C) 2018-2019 Aaron Chen <aaron.chen@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.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#ifndef _SYNAPTICS_TCM_XIAOMI_BOARD_DATA_H_
#define _SYNAPTICS_TCM_XIAOMI_BOARD_DATA_H_
#define SYNA_GRIP_PARAMETERS_SIZE 32
#define SYNA_TOUCH_MODE_PARAMETERS_SIZE 5
#define SYNA_CORNERFILTER_AREA_STEP_SIZE 4
#define SYNA_DISPLAY_RESOLUTION_SIZE 2
struct syna_tcm_xiaomi_board_data {
int x_max;
int y_max;
unsigned int game_mode[SYNA_TOUCH_MODE_PARAMETERS_SIZE];
unsigned int active_mode[SYNA_TOUCH_MODE_PARAMETERS_SIZE];
unsigned int up_threshold[SYNA_TOUCH_MODE_PARAMETERS_SIZE];
unsigned int tolerance[SYNA_TOUCH_MODE_PARAMETERS_SIZE];
unsigned int edge_filter[SYNA_TOUCH_MODE_PARAMETERS_SIZE];
unsigned int panel_orien[SYNA_TOUCH_MODE_PARAMETERS_SIZE];
unsigned int report_rate[SYNA_TOUCH_MODE_PARAMETERS_SIZE];
unsigned int cornerfilter_area_step0;
unsigned int cornerfilter_area_step1;
unsigned int cornerfilter_area_step2;
unsigned int cornerfilter_area_step3;
unsigned int cornerzone_filter_hor1[SYNA_GRIP_PARAMETERS_SIZE];
unsigned int cornerzone_filter_hor2[SYNA_GRIP_PARAMETERS_SIZE];
unsigned int cornerzone_filter_ver[SYNA_GRIP_PARAMETERS_SIZE];
unsigned int deadzone_filter_hor[SYNA_GRIP_PARAMETERS_SIZE];
unsigned int deadzone_filter_ver[SYNA_GRIP_PARAMETERS_SIZE];
unsigned int edgezone_filter_hor[SYNA_GRIP_PARAMETERS_SIZE];
unsigned int edgezone_filter_ver[SYNA_GRIP_PARAMETERS_SIZE];
};
#endif

View File

@ -35,8 +35,11 @@
#define I2C_MODULE_NAME "synaptics_tcm_i2c"
#define SPI_MODULE_NAME "synaptics_tcm_spi"
#define SYNAP_MAX_STR_LABLE_LEN 32
struct syna_tcm_board_data {
char avdd_name[SYNAP_MAX_STR_LABLE_LEN];
char iovdd_name[SYNAP_MAX_STR_LABLE_LEN];
bool x_flip;
bool y_flip;
bool swap_axes;