Update goodix berlin code to V1.1.21

TP:
Update goodix berlin driver code to V1.1.21.

Change-Id: I56ac06c10f7c3ea9bb3bf936fe8e791f8753740a
Reviewed-on: https://gerrit.mot.com/2027427
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Jichao Zou <zoujc@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
litong20 2021-07-29 11:39:58 +08:00 • committed by litong
commit d7e576198b
20 changed files with 4629 additions and 1038 deletions

View file

@ -5,9 +5,4 @@ include $(CLEAR_VARS)
LOCAL_MODULE := goodix_brl_mmi.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
ifneq ($(findstring goodix_brl_i2c.ko,$(BOARD_VENDOR_KERNEL_MODULES)),)
LOCAL_ADDITIONAL_DEPENDENCIES += $(KERNEL_MODULES_OUT)/goodix_brl_i2c.ko
else
LOCAL_ADDITIONAL_DEPENDENCIES += $(KERNEL_MODULES_OUT)/goodix_brl_spi.ko
endif
include $(DLKM_DIR)/AndroidKernelModule.mk

View file

@ -0,0 +1,17 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += \
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include
obj-m := goodix_brl_mmi.o
goodix_brl_mmi-objs := \
goodix_brl_i2c.o \
goodix_brl_spi.o \
goodix_ts_core.o \
goodix_brl_hw.o \
goodix_cfg_bin.o \
goodix_ts_utils.o \
goodix_brl_fwupdate.o \
goodix_ts_gesture.o \
goodix_ts_inspect.o \
goodix_ts_tools.o

36
drivers/input/touchscreen/goodix_berlin_mmi/Kconfig Executable file → Normal file
View file

@ -3,48 +3,18 @@
#
menuconfig TOUCHSCREEN_GOODIX_BRL
tristate "Goodix berlin touchscreen"
default y
help
Say Y here if you have a Goodix berlin series touch controller
to your system.
If build module, say M.
If unsure, say N.
if TOUCHSCREEN_GOODIX_BRL
config TOUCHSCREEN_GOODIX_BRL_I2C
tristate "support I2C bus connection"
depends on I2C
help
Say Y here if the touchscreen is connected via I2C bus.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_GOODIX_BRL_SPI
tristate "support SPI bus connection"
depends on SPI_MASTER
bool "support SPI bus connection"
help
Say Y here if the touchscreen is connected via SPI bus.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_GOODIX_TS_TOOLS
tristate "Goodix debug tools support"
default y
help
Say Y here to enable debug tools.
If unsure, say N.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_GOODIX_TS_GESTURE
tristate "Goodix gesture support"
default y
help
Say Y here to enable gesture.
If unsure, say N.
To compile this driver as a module, choose M here.
Say Y here if the touchscreen is connected via SPI bus.
endif

20
drivers/input/touchscreen/goodix_berlin_mmi/Makefile Executable file → Normal file
View file

@ -1,6 +1,14 @@
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BRL_I2C) += goodix_brl_i2c.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BRL_SPI) += goodix_brl_spi.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BRL) += goodix_core.o
goodix_core-y := goodix_ts_core.o goodix_brl_hw.o goodix_cfg_bin.o goodix_ts_utils.o goodix_brl_fwupdate.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_TS_TOOLS) += goodix_ts_tools.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_TS_GESTURE) += goodix_ts_gesture.o
all: modules
modules:
$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)
modules_install:
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install
%:
$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)
clean:
rm -f *.o *.ko *.mod.c *.mod.o *~ .*.cmd Module.symvers
rm -rf .tmp_versions

View file

@ -1,14 +0,0 @@
DLKM_DIR := motorola/kernel/modules
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
ifneq ($(findstring goodix_brl_i2c.ko,$(BOARD_VENDOR_KERNEL_MODULES)),)
KERNEL_CFLAGS += CONFIG_USE_TOUCHSCREEN_MMI_I2C=y
LOCAL_MODULE := goodix_brl_i2c.ko
else
LOCAL_MODULE := goodix_brl_spi.ko
endif
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk

View file

@ -1,11 +0,0 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += \
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include \
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/drivers/input/touchscreen/goodix_berlin_mmi/include
ifneq ($(filter m y,$(CONFIG_USE_TOUCHSCREEN_MMI_I2C)),)
obj-m = goodix_brl_i2c.o
else
obj-m = goodix_brl_spi.o
endif

View file

@ -1,11 +0,0 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += \
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include \
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/drivers/input/touchscreen/goodix_berlin_mmi/include
obj-m += goodix_brl_mmi.o
goodix_brl_mmi-objs := goodix_brl_fwupdate.o goodix_brl_hw.o goodix_cfg_bin.o goodix_ts_core.o goodix_ts_utils.o
KBUILD_EXTRA_SYMBOLS += $(CURDIR)/$(KBUILD_EXTMOD)/../goodix_brl_bus/Module.symvers

View file

@ -1,16 +0,0 @@
DLKM_DIR := motorola/kernel/modules
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := goodix_brl_tools_mmi.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
LOCAL_ADDITIONAL_DEPENDENCIES += $(KERNEL_MODULES_OUT)/goodix_brl_mmi.ko
include $(DLKM_DIR)/AndroidKernelModule.mk
include $(CLEAR_VARS)
LOCAL_MODULE := goodix_brl_gesture_mmi.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
LOCAL_ADDITIONAL_DEPENDENCIES += $(KERNEL_MODULES_OUT)/goodix_brl_mmi.ko
include $(DLKM_DIR)/AndroidKernelModule.mk

View file

@ -1,14 +0,0 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += \
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include \
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/drivers/input/touchscreen/goodix_berlin_mmi/include
obj-m += goodix_brl_tools_mmi.o
goodix_brl_tools_mmi-objs = goodix_ts_tools.o
obj-m += goodix_brl_gesture_mmi.o
goodix_brl_gesture_mmi-objs = goodix_ts_gesture.o
KBUILD_EXTRA_SYMBOLS += $(CURDIR)/$(KBUILD_EXTMOD)/../goodix_brl_core/Module.symvers

View file

@ -16,56 +16,130 @@
*/
#include "goodix_ts_core.h"
#define TS_DEFAULT_FIRMWARE "goodix_firmware.bin"
#define BUS_TYPE_SPI 1
#define BUS_TYPE_I2C 0
#define BUS_TYPE_SPI 0x01
#define BUS_TYPE_I2C 0
#define GOODIX_BUS_RETRY_TIMES 3
#define GOODIX_BUS_RETRY_TIMES 3
#define FW_HEADER_SIZE_BRA 256
#define FW_HEADER_SIZE 512
#define FW_SUBSYS_INFO_SIZE 10
#define FW_SUBSYS_INFO_OFFSET_BRA 36
#define FW_SUBSYS_INFO_OFFSET 42
#define FW_SUBSYS_MAX_NUM 47
#define FW_HEADER_SIZE 256
#define FW_SUBSYS_INFO_SIZE 10
#define FW_SUBSYS_INFO_OFFSET 36
#define FW_SUBSYS_MAX_NUM 28
#define ISP_MAX_BUFFERSIZE 4096
#define ISP_MAX_BUFFERSIZE (1024 * 4)
#define FW_PID_LEN 8
#define FW_VID_LEN 4
#define FLASH_CMD_LEN 11
#define NO_NEED_UPDATE 99
#define FW_FILE_CHECKSUM_OFFSET 8
#define CONFIG_DATA_TYPE 4
#define FW_PID_LEN 8
#define FW_VID_LEN 4
#define FLASH_CMD_LEN 11
#define ISP_RAM_ADDR_BRA 0x18400
#define ISP_RAM_ADDR_BRB 0x57000
#define ISP_RAM_ADDR_BRD 0x23800
#define HW_REG_CPU_RUN_FROM 0x10000
#define FLASH_CMD_REG_BRA 0x10400
#define FLASH_CMD_REG_BRB 0x13400
#define FLASH_CMD_REG_BRD 0x12400
#define HW_REG_ISP_BUFFER_BRA 0x10410
#define HW_REG_ISP_BUFFER_BRB 0x13410
#define HW_REG_ISP_BUFFER_BRD 0x12410
#define CONFIG_DATA_ADDR_BRA 0x3E000
#define CONFIG_DATA_ADDR_BRB 0x40000
#define CONFIG_DATA_ADDR_BRD 0x3E000
#define GOODIX_CFG_ID_ADDR_BRA 0x1006E
#define GOODIX_CFG_ID_ADDR_BRB 0x10076
#define GOODIX_CFG_ID_ADDR_BRD 0x10076
#define FW_FILE_CHECKSUM_OFFSET 8
#define CONFIG_ID_OFFSET 30
#define CONFIG_DATA_TYPE 4
#define HOLD_CPU_REG_W 0x0002
#define HOLD_CPU_REG_R 0x2000
#define MISCTL_REG_BRA 0xD807
#define MISCTL_REG_BRB 0xD80B
#define MISCTL_REG_BRD 0xD804
#define ENABLE_MISCTL_BRA 0x08
#define ENABLE_MISCTL_BRB 0x40
#define ENABLE_MISCTL_BRD 0x20700000
#define ESD_KEY_REG 0xCC58
#define WATCH_DOG_REG_BRA 0xCC54
#define WATCH_DOG_REG_BRB 0xD054
#define WATCH_DOG_REG_BRD 0xD040
#define ISP_RAM_ADDR 0x18400
#define HW_REG_CPU_RUN_FROM 0x10000
#define FLASH_CMD_REG 0x10400
#define HW_REG_ISP_BUFFER 0x10410
#define CONFIG_DATA_ADDR 0x3E000
#define FLASH_CMD_TYPE_READ 0xAA
#define FLASH_CMD_TYPE_WRITE 0xBB
#define FLASH_CMD_ACK_CHK_PASS 0xEE
#define FLASH_CMD_ACK_CHK_ERROR 0x33
#define FLASH_CMD_ACK_IDLE 0x11
#define FLASH_CMD_W_STATUS_CHK_PASS 0x22
#define FLASH_CMD_W_STATUS_CHK_FAIL 0x33
#define FLASH_CMD_W_STATUS_ADDR_ERR 0x44
#define FLASH_CMD_W_STATUS_WRITE_ERR 0x55
#define FLASH_CMD_W_STATUS_WRITE_OK 0xEE
#define HOLD_CPU_REG_W 0x0002
#define HOLD_CPU_REG_R 0x2000
#define MISCTL_REG 0xD807
#define ESD_KEY_REG 0xCC58
#define WATCH_DOG_REG 0xCC54
#define CHIP_TYPE_BRA 0x96
#define CHIP_TYPE_BRB 0x97
#define CHIP_TYPE_BRD 0x98
#define FLASH_CMD_TYPE_READ 0xAA
#define FLASH_CMD_TYPE_WRITE 0xBB
#define FLASH_CMD_ACK_CHK_PASS 0xEE
#define FLASH_CMD_ACK_CHK_ERROR 0x33
#define FLASH_CMD_ACK_IDLE 0x11
#define FLASH_CMD_W_STATUS_CHK_PASS 0x22
#define FLASH_CMD_W_STATUS_CHK_FAIL 0x33
#define FLASH_CMD_W_STATUS_ADDR_ERR 0x44
#define FLASH_CMD_W_STATUS_WRITE_ERR 0x55
#define FLASH_CMD_W_STATUS_WRITE_OK 0xEE
struct update_info_t {
int header_size;
int subsys_info_offset;
u32 isp_ram_reg;
u32 flash_cmd_reg;
u32 isp_buffer_reg;
u32 config_data_reg;
u32 misctl_reg;
u32 watch_dog_reg;
u32 config_id_reg;
u32 enable_misctl_val;
};
/* berlinA update into */
struct update_info_t update_bra = {
FW_HEADER_SIZE_BRA,
FW_SUBSYS_INFO_OFFSET_BRA,
ISP_RAM_ADDR_BRA,
FLASH_CMD_REG_BRA,
HW_REG_ISP_BUFFER_BRA,
CONFIG_DATA_ADDR_BRA,
MISCTL_REG_BRA,
WATCH_DOG_REG_BRA,
GOODIX_CFG_ID_ADDR_BRA,
ENABLE_MISCTL_BRA,
};
/* berlinB update info */
struct update_info_t update_brb = {
FW_HEADER_SIZE,
FW_SUBSYS_INFO_OFFSET,
ISP_RAM_ADDR_BRB,
FLASH_CMD_REG_BRB,
HW_REG_ISP_BUFFER_BRB,
CONFIG_DATA_ADDR_BRB,
MISCTL_REG_BRB,
WATCH_DOG_REG_BRB,
GOODIX_CFG_ID_ADDR_BRB,
ENABLE_MISCTL_BRB,
};
/* berlinD update info */
struct update_info_t update_brd = {
FW_HEADER_SIZE,
FW_SUBSYS_INFO_OFFSET,
ISP_RAM_ADDR_BRD,
FLASH_CMD_REG_BRD,
HW_REG_ISP_BUFFER_BRD,
CONFIG_DATA_ADDR_BRD,
MISCTL_REG_BRD,
WATCH_DOG_REG_BRD,
GOODIX_CFG_ID_ADDR_BRD,
ENABLE_MISCTL_BRD,
};
/**
* fw_subsys_info - subsytem firmware infomation
* fw_subsys_info - subsytem firmware information
* @type: sybsystem type
* @size: firmware size
* @flash_addr: flash address
@ -106,14 +180,14 @@ struct firmware_summary {
u8 protocol_ver;
u8 bus_type;
u8 flash_protect;
u8 reserved[2];
// u8 reserved[8];
struct fw_subsys_info subsys[FW_SUBSYS_MAX_NUM];
};
#pragma pack()
/**
* firmware_data - firmware data structure
* @fw_summary: firmware infomation
* @fw_summary: firmware information
* @firmware: firmware data structure
*/
struct firmware_data {
@ -128,24 +202,40 @@ struct config_data {
#pragma pack(1)
struct goodix_flash_cmd {
union {
struct {
u8 status;
u8 ack;
u8 len;
u8 cmd;
u8 fw_type;
u16 fw_len;
u32 fw_addr;
//u16 checksum;
union {
struct {
u8 status;
u8 ack;
u8 len;
u8 cmd;
u8 fw_type;
u16 fw_len;
u32 fw_addr;
//u16 checksum;
};
u8 buf[16];
};
u8 buf[16];
};
};
#pragma pack()
enum update_status {
UPSTA_NOTWORK = 0,
UPSTA_PREPARING,
UPSTA_UPDATING,
UPSTA_SUCCESS,
UPSTA_FAILED
};
enum compare_status {
COMPARE_EQUAL = 0,
COMPARE_NOCODE,
COMPARE_PIDMISMATCH,
COMPARE_FW_NOTEQUAL,
COMPARE_CFG_NOTEQUAL,
};
/**
* fw_update_ctrl - sturcture used to control the
* fw_update_ctrl - structure used to control the
* firmware update process
* @initialized: struct init state
* @mode: indicate weather reflash config or not, fw data source,
@ -163,10 +253,13 @@ struct fw_update_ctrl {
int initialized;
char fw_name[GOODIX_MAX_STR_LABLE_LEN];
int mode;
enum update_status status;
int spend_time;
struct firmware_data fw_data;
struct goodix_ic_config *ic_config;
struct goodix_ts_core *core_data;
struct update_info_t *update_info;
struct bin_attribute attr_fwimage;
struct kobject *kobj;
@ -211,8 +304,8 @@ static int goodix_reg_read(unsigned int addr,
}
/**
* goodix_parse_firmware - parse firmware header infomation
* and subsystem infomation from firmware data buffer
* goodix_parse_firmware - parse firmware header information
* and subsystem information from firmware data buffer
*
* @fw_data: firmware struct, contains firmware header info
* and firmware data.
@ -226,13 +319,19 @@ static int goodix_parse_firmware(struct firmware_data *fw_data)
struct firmware_summary *fw_summary;
unsigned int i, fw_offset, info_offset;
u32 checksum;
int ic_type =
goodix_fw_update_ctrl.core_data->bus->ic_type;
int subsys_info_offset =
goodix_fw_update_ctrl.update_info->subsys_info_offset;
int header_size =
goodix_fw_update_ctrl.update_info->header_size;
int r = 0;
fw_summary = &fw_data->fw_summary;
/* copy firmware head info */
firmware = fw_data->firmware;
if (firmware->size < FW_SUBSYS_INFO_OFFSET) {
if (firmware->size < subsys_info_offset) {
ts_err("Invalid firmware size:%zu", firmware->size);
r = -EINVAL;
goto err_size;
@ -249,7 +348,7 @@ static int goodix_parse_firmware(struct firmware_data *fw_data)
}
for (i = FW_FILE_CHECKSUM_OFFSET, checksum = 0;
i < firmware->size; i+=2)
i < firmware->size; i += 2)
checksum += firmware->data[i] + (firmware->data[i+1] << 8);
/* byte order change, and check */
@ -268,9 +367,9 @@ static int goodix_parse_firmware(struct firmware_data *fw_data)
}
/* parse subsystem info */
fw_offset = FW_HEADER_SIZE;
fw_offset = header_size;
for (i = 0; i < fw_summary->subsys_num; i++) {
info_offset = FW_SUBSYS_INFO_OFFSET +
info_offset = subsys_info_offset +
i * FW_SUBSYS_INFO_SIZE;
fw_summary->subsys[i].type = firmware->data[info_offset];
@ -289,9 +388,9 @@ static int goodix_parse_firmware(struct firmware_data *fw_data)
}
ts_info("Firmware package protocol: V%u", fw_summary->protocol_ver);
ts_info("Fimware PID:GT%s", fw_summary->fw_pid);
ts_info("Fimware VID:%*ph", 4, fw_summary->fw_vid);
ts_info("Firmware chip type:%02X", fw_summary->chip_type);
ts_info("Firmware PID:GT%s", fw_summary->fw_pid);
ts_info("Firmware VID:%*ph", 4, fw_summary->fw_vid);
ts_info("Firmware chip type:0x%02X", fw_summary->chip_type);
ts_info("Firmware bus type:%s",
(fw_summary->bus_type & BUS_TYPE_SPI) ? "SPI" : "I2C");
ts_info("Firmware size:%u", fw_summary->size);
@ -307,6 +406,20 @@ static int goodix_parse_firmware(struct firmware_data *fw_data)
ts_debug("Subsystem Ptr:%p", fw_summary->subsys[i].data);
}
if (fw_summary->chip_type == CHIP_TYPE_BRA &&
ic_type != IC_TYPE_BERLIN_A) {
ts_err("ic type mismatch!");
r = -EINVAL;
} else if (fw_summary->chip_type == CHIP_TYPE_BRB &&
ic_type != IC_TYPE_BERLIN_B) {
ts_err("ic type mismatch!");
r = -EINVAL;
} else if (fw_summary->chip_type == CHIP_TYPE_BRD &&
ic_type != IC_TYPE_BERLIN_D) {
ts_err("ic type mismatch!");
r = -EINVAL;
}
err_size:
return r;
}
@ -314,39 +427,61 @@ err_size:
/**
* goodix_fw_version_compare - compare the active version with
* firmware file version.
* @fwu_ctrl: firmware infomation to be compared
* @fwu_ctrl: firmware information to be compared
* return: 0 equal, < 0 unequal
*/
#define GOODIX_NOCODE "NOCODE"
static int goodix_fw_version_compare(struct fw_update_ctrl *fwu_ctrl)
{
int ret = 0;
struct goodix_fw_version fw_version = {{0}};
struct goodix_fw_version fw_version;
struct firmware_summary *fw_summary = &fwu_ctrl->fw_data.fw_summary;
u32 config_id_reg = goodix_fw_update_ctrl.update_info->config_id_reg;
u32 file_cfg_id;
u32 ic_cfg_id;
/* compare fw_version */
ret = get_fw_version_info(&fw_version);
if (ret) {
ts_info("failed get active fw version");
if (ret)
return -EINVAL;
if (!memcmp(fw_version.rom_pid, GOODIX_NOCODE, 6) ||
!memcmp(fw_version.patch_pid, GOODIX_NOCODE, 6)) {
ts_info("there is no code in the chip");
return COMPARE_NOCODE;
}
if (memcmp(fw_version.patch_pid, fw_summary->fw_pid, FW_PID_LEN)) {
ts_err("Product ID mismatch:%s:%s",
ts_err("Product ID mismatch:%s != %s",
fw_version.patch_pid, fw_summary->fw_pid);
return -EINVAL;
return COMPARE_PIDMISMATCH;
}
ret = memcmp(fw_version.patch_vid, fw_summary->fw_vid, FW_VID_LEN);
if (ret) {
ts_info("active firmware version:%*ph", FW_VID_LEN,
fw_version.patch_vid);
ts_info("firmware file version: %*ph", FW_VID_LEN,
fw_summary->fw_vid);
return -EINVAL;
return COMPARE_FW_NOTEQUAL;
}
ts_info("fw_version equal");
/* compare config id */
if (fwu_ctrl->ic_config && fwu_ctrl->ic_config->len > 0) {
file_cfg_id =
goodix_get_file_config_id(fwu_ctrl->ic_config->data);
goodix_reg_read(config_id_reg,
(u8 *)&ic_cfg_id, sizeof(ic_cfg_id));
if (ic_cfg_id != file_cfg_id) {
ts_info("ic_cfg_id:0x%x != file_cfg_id:0x%x",
ic_cfg_id, file_cfg_id);
return COMPARE_CFG_NOTEQUAL;
}
ts_info("config_id equal");
}
ts_info("Firmware version equal");
return 0;
return COMPARE_EQUAL;
}
/**
@ -359,7 +494,8 @@ static int goodix_fw_version_compare(struct fw_update_ctrl *fwu_ctrl)
* return: 0 write success and confirm ok
* < 0 failed
*/
static int goodix_reg_write_confirm(unsigned int addr, unsigned char *data, unsigned int len)
static int goodix_reg_write_confirm(unsigned int addr,
unsigned char *data, unsigned int len)
{
u8 *cfm = NULL;
u8 cfm_buf[32];
@ -367,10 +503,8 @@ static int goodix_reg_write_confirm(unsigned int addr, unsigned char *data, unsi
if (len > sizeof(cfm_buf)) {
cfm = kzalloc(len, GFP_KERNEL);
if (!cfm) {
ts_err("Mem alloc failed");
if (!cfm)
return -ENOMEM;
}
} else {
cfm = &cfm_buf[0];
}
@ -401,23 +535,25 @@ exit:
/**
* goodix_load_isp - load ISP program to deivce ram
* goodix_load_isp - load ISP program to device ram
* @dev: pointer to touch device
* @fw_data: firmware data
* return 0 ok, <0 error
*/
static int goodix_load_isp(struct firmware_data *fw_data)
{
struct goodix_fw_version isp_fw_version = {{0}};
struct goodix_fw_version isp_fw_version;
struct fw_subsys_info *fw_isp;
u32 isp_ram_reg = goodix_fw_update_ctrl.update_info->isp_ram_reg;
u8 reg_val[8] = {0x00};
int r;
memset(&isp_fw_version, 0, sizeof(isp_fw_version));
fw_isp = &fw_data->fw_summary.subsys[0];
ts_info("Loading ISP start");
r = goodix_reg_write_confirm(ISP_RAM_ADDR,
(u8 *)fw_isp->data, fw_isp->size);
r = goodix_reg_write_confirm(isp_ram_reg,
(u8 *)fw_isp->data, fw_isp->size);
if (r < 0) {
ts_err("Loading ISP error");
return r;
@ -459,6 +595,9 @@ static int goodix_load_isp(struct firmware_data *fw_data)
*/
static int goodix_update_prepare(struct fw_update_ctrl *fwu_ctrl)
{
u32 misctl_reg = fwu_ctrl->update_info->misctl_reg;
u32 watch_dog_reg = fwu_ctrl->update_info->watch_dog_reg;
u32 enable_misctl_val = fwu_ctrl->update_info->enable_misctl_val;
u8 reg_val[4] = {0};
u8 temp_buf[64] = {0};
int retry = 20;
@ -494,52 +633,59 @@ static int goodix_update_prepare(struct fw_update_ctrl *fwu_ctrl)
ts_info("Success hold CPU");
/* enable misctl clock */
reg_val[0] = 0x08;
r = goodix_reg_write(MISCTL_REG, reg_val, 1);
if (fwu_ctrl->core_data->bus->ic_type == IC_TYPE_BERLIN_D)
goodix_reg_write(misctl_reg, (u8 *)&enable_misctl_val, 4);
else
goodix_reg_write(misctl_reg, (u8 *)&enable_misctl_val, 1);
ts_info("enbale misctl clock");
/* open ESD_KEY */
retry = 20;
do {
reg_val[0] = 0x95;
r = goodix_reg_write(ESD_KEY_REG, reg_val, 1);
r |= goodix_reg_read(ESD_KEY_REG, temp_buf, 1);
if (!r && temp_buf[0] == 0x01)
break;
usleep_range(1000, 1100);
ts_info("retry %d enable esd key, 0x%x", retry, temp_buf[0]);
} while (--retry);
if (!retry) {
ts_err("Failed to enable esd key, return =%d", r);
return -2;
if (fwu_ctrl->core_data->bus->ic_type == IC_TYPE_BERLIN_A) {
/* open ESD_KEY */
retry = 20;
do {
reg_val[0] = 0x95;
r = goodix_reg_write(ESD_KEY_REG, reg_val, 1);
r |= goodix_reg_read(ESD_KEY_REG, temp_buf, 1);
if (!r && temp_buf[0] == 0x01)
break;
usleep_range(1000, 1100);
ts_info("retry %d enable esd key, 0x%x",
retry, temp_buf[0]);
} while (--retry);
if (!retry) {
ts_err("Failed to enable esd key, return =%d", r);
return -2;
}
ts_info("success enable esd key");
}
ts_info("success enable esd key");
/* disable watch dog */
reg_val[0] = 0x00;
r = goodix_reg_write(WATCH_DOG_REG, reg_val, 1);
r = goodix_reg_write(watch_dog_reg, reg_val, 1);
ts_info("disable watch dog");
/* load ISP code and run form isp */
r = goodix_load_isp(&fwu_ctrl->fw_data);
if (r < 0)
ts_err("Failed lode and run isp");
ts_err("Failed load and run isp");
return r;
}
/* goodix_send_flash_cmd: send command to read or write flash data
* @flash_cmd: command need to send.
* */
/* goodix_send_flash_cmd: send command to read or write flash data
* @flash_cmd: command need to send.
*/
static int goodix_send_flash_cmd(struct goodix_flash_cmd *flash_cmd)
{
int i, ret, retry;
struct goodix_flash_cmd tmp_cmd;
u32 flash_cmd_reg = goodix_fw_update_ctrl.update_info->flash_cmd_reg;
ts_info("try send flash cmd:%*ph", (int)sizeof(flash_cmd->buf),
flash_cmd->buf);
memset(tmp_cmd.buf, 0, sizeof(tmp_cmd));
ret = goodix_reg_write(FLASH_CMD_REG, flash_cmd->buf, sizeof(flash_cmd->buf));
ret = goodix_reg_write(flash_cmd_reg,
flash_cmd->buf, sizeof(flash_cmd->buf));
if (ret) {
ts_err("failed send flash cmd %d", ret);
return ret;
@ -547,14 +693,17 @@ static int goodix_send_flash_cmd(struct goodix_flash_cmd *flash_cmd)
retry = 5;
for (i = 0; i < retry; i++) {
ret = goodix_reg_read(FLASH_CMD_REG, tmp_cmd.buf, sizeof(tmp_cmd.buf));
ret = goodix_reg_read(flash_cmd_reg,
tmp_cmd.buf, sizeof(tmp_cmd.buf));
if (!ret && tmp_cmd.ack == FLASH_CMD_ACK_CHK_PASS)
break;
usleep_range(5000, 5100);
ts_info("flash cmd ack error retry %d, ack 0x%x, ret %d", i, tmp_cmd.ack, ret);
ts_info("flash cmd ack error retry %d, ack 0x%x, ret %d",
i, tmp_cmd.ack, ret);
}
if (tmp_cmd.ack != FLASH_CMD_ACK_CHK_PASS) {
ts_err("flash cmd ack error, ack 0x%x, ret %d", tmp_cmd.ack, ret);
ts_err("flash cmd ack error, ack 0x%x, ret %d",
tmp_cmd.ack, ret);
ts_err("data:%*ph", (int)sizeof(tmp_cmd.buf), tmp_cmd.buf);
return -EINVAL;
}
@ -563,7 +712,8 @@ static int goodix_send_flash_cmd(struct goodix_flash_cmd *flash_cmd)
msleep(80);
retry = 20;
for (i = 0; i < retry; i++) {
ret = goodix_reg_read(FLASH_CMD_REG, tmp_cmd.buf, sizeof(tmp_cmd.buf));
ret = goodix_reg_read(flash_cmd_reg,
tmp_cmd.buf, sizeof(tmp_cmd.buf));
if (!ret && tmp_cmd.ack == FLASH_CMD_ACK_CHK_PASS &&
tmp_cmd.status == FLASH_CMD_W_STATUS_WRITE_OK) {
ts_info("flash status check pass");
@ -572,7 +722,7 @@ static int goodix_send_flash_cmd(struct goodix_flash_cmd *flash_cmd)
ts_info("flash cmd status not ready, retry %d, ack 0x%x, status 0x%x, ret %d",
i, tmp_cmd.ack, tmp_cmd.status, ret);
msleep(15);
msleep(20);
}
ts_err("flash cmd status error %d, ack 0x%x, status 0x%x, ret %d",
@ -583,21 +733,21 @@ static int goodix_send_flash_cmd(struct goodix_flash_cmd *flash_cmd)
}
switch (tmp_cmd.status) {
case FLASH_CMD_W_STATUS_CHK_PASS:
ts_err("data check pass, but failed get follow-up results");
return -EFAULT;
case FLASH_CMD_W_STATUS_CHK_FAIL:
ts_err("data check failed, please retry");
return -EAGAIN;
case FLASH_CMD_W_STATUS_ADDR_ERR:
ts_err("flash target addr error, please check");
return -EFAULT;
case FLASH_CMD_W_STATUS_WRITE_ERR:
ts_err("flash data write err, please retry");
return -EAGAIN;
default:
ts_err("unknown status");
return -EFAULT;
case FLASH_CMD_W_STATUS_CHK_PASS:
ts_err("data check pass, but failed get follow-up results");
return -EFAULT;
case FLASH_CMD_W_STATUS_CHK_FAIL:
ts_err("data check failed, please retry");
return -EAGAIN;
case FLASH_CMD_W_STATUS_ADDR_ERR:
ts_err("flash target addr error, please check");
return -EFAULT;
case FLASH_CMD_W_STATUS_WRITE_ERR:
ts_err("flash data write err, please retry");
return -EAGAIN;
default:
ts_err("unknown status");
return -EFAULT;
}
}
@ -606,10 +756,11 @@ static int goodix_flash_package(u8 subsys_type, u8 *pkg,
{
int ret, retry;
struct goodix_flash_cmd flash_cmd;
u32 isp_buffer_reg = goodix_fw_update_ctrl.update_info->isp_buffer_reg;
retry = 2;
do {
ret = goodix_reg_write_confirm(HW_REG_ISP_BUFFER, pkg, pkg_len);
ret = goodix_reg_write(isp_buffer_reg, pkg, pkg_len);
if (ret < 0) {
ts_err("Failed to write firmware packet");
return ret;
@ -628,7 +779,8 @@ static int goodix_flash_package(u8 subsys_type, u8 *pkg,
ret = goodix_send_flash_cmd(&flash_cmd);
if (!ret) {
ts_info("success write package to 0x%x, len %d", flash_addr, pkg_len - 4);
ts_info("success write package to 0x%x, len %d",
flash_addr, pkg_len - 4);
return 0;
}
} while (ret == -EAGAIN && --retry);
@ -643,12 +795,12 @@ static int goodix_flash_package(u8 subsys_type, u8 *pkg,
* packets, the max size of packet is limited to
* @{ISP_MAX_BUFFERSIZE}
* @dev: pointer to touch device
* @subsys: subsystem infomation
* @subsys: subsystem information
* return: 0 ok, < 0 error
*/
static int goodix_flash_subsystem(struct fw_subsys_info *subsys)
{
u16 data_size, offset;
u32 data_size, offset;
u32 total_size;
//TODO: confirm flash addr ,<< 8??
u32 subsys_base_addr = subsys->flash_addr;
@ -706,11 +858,13 @@ static int goodix_flash_firmware(struct fw_update_ctrl *fw_ctrl)
struct firmware_summary *fw_summary;
struct fw_subsys_info *fw_x;
struct fw_subsys_info subsys_cfg = {0};
u32 config_data_reg = fw_ctrl->update_info->config_data_reg;
int retry = GOODIX_BUS_RETRY_TIMES;
int i, r = 0, fw_num;
/* start from subsystem 1,
* subsystem 0 is the ISP program */
/* start from subsystem 1,
* subsystem 0 is the ISP program
*/
fw_summary = &fw_data->fw_summary;
fw_num = fw_summary->subsys_num;
@ -719,7 +873,7 @@ static int goodix_flash_firmware(struct fw_update_ctrl *fw_ctrl)
if (fw_ctrl->ic_config && fw_ctrl->ic_config->len) {
subsys_cfg.data = fw_ctrl->ic_config->data;
subsys_cfg.size = fw_ctrl->ic_config->len;
subsys_cfg.flash_addr = CONFIG_DATA_ADDR;
subsys_cfg.flash_addr = config_data_reg;
subsys_cfg.type = CONFIG_DATA_TYPE;
r = goodix_flash_subsystem(&subsys_cfg);
if (r) {
@ -759,12 +913,15 @@ exit_flash:
*/
static int goodix_update_finish(struct fw_update_ctrl *fwu_ctrl)
{
int ret;
if (goodix_fw_update_reset(100))
ts_err("reset abnormal");
if (goodix_fw_version_compare(fwu_ctrl))
return -EINVAL;
ret = goodix_fw_version_compare(fwu_ctrl);
if (ret == COMPARE_EQUAL || ret == COMPARE_CFG_NOTEQUAL)
return 0;
return 0;
return -EINVAL;
}
/**
@ -789,10 +946,12 @@ int goodix_fw_update_proc(struct fw_update_ctrl *fwu_ctrl)
if (!ret) {
ts_info("firmware upgraded");
return 0;
}
} else
ts_info("need to upgrade");
}
start_update:
fwu_ctrl->status = UPSTA_PREPARING;
do {
ret = goodix_update_prepare(fwu_ctrl);
if (ret) {
@ -806,14 +965,15 @@ start_update:
}
/* progress: 20%~100% */
fwu_ctrl->status = UPSTA_UPDATING;
ret = goodix_flash_firmware(fwu_ctrl);
if (ret == -EAGAIN && --retry1 > 0) {
if (ret < 0 && --retry1 > 0) {
ts_err("Bus error, retry firmware update:%d",
FW_UPDATE_RETRY - retry1);
goto start_update;
}
if (ret)
ts_info("flash fw data enter error");
ts_err("flash fw data enter error, ret:%d", ret);
else
ts_info("flash fw data success, need check version");
@ -822,7 +982,7 @@ err_fw_prepare:
if (!ret)
ts_info("Firmware update successfully");
else
ts_err("Firmware update failed");
ts_err("Firmware update failed, ret:%d", ret);
return ret;
}
@ -853,13 +1013,15 @@ static ssize_t goodix_sysfs_update_en_store(
ts_info("set update mode:0x%x", buf[0]);
if (buf[0] == '1') {
mode = UPDATE_MODE_FORCE|UPDATE_MODE_BLOCK|UPDATE_MODE_SRC_SYSFS;
mode = UPDATE_MODE_FORCE | UPDATE_MODE_BLOCK |
UPDATE_MODE_SRC_SYSFS;
} else if (buf[0] == '2') {
mode = UPDATE_MODE_FORCE|UPDATE_MODE_BLOCK|UPDATE_MODE_SRC_REQUEST;
mode = UPDATE_MODE_FORCE | UPDATE_MODE_BLOCK |
UPDATE_MODE_SRC_REQUEST;
} else if (buf[0] == '5') {
mode = UPDATE_MODE_FORCE|UPDATE_MODE_SRC_SYSFS;
mode = UPDATE_MODE_FORCE | UPDATE_MODE_SRC_SYSFS;
} else if (buf[0] == '6') {
mode = UPDATE_MODE_FORCE|UPDATE_MODE_SRC_REQUEST;
mode = UPDATE_MODE_FORCE | UPDATE_MODE_SRC_REQUEST;
} else {
ts_err("invalid update mode:0x%x", buf[0]);
return -EINVAL;
@ -906,11 +1068,8 @@ static ssize_t goodix_sysfs_fwsize_store(
/* use vmalloc to alloc huge memory */
fw = vmalloc(sizeof(*fw) + size);
if (fw == NULL) {
ts_err("Failed to alloc memory,size:%zu",
size + sizeof(*fw));
if (!fw)
return -ENOMEM;
}
mutex_lock(&fw_ctrl->mutex);
memset(fw, 0x00, sizeof(*fw) + size);
data = (u8 **)&fw->data;
@ -949,21 +1108,61 @@ static ssize_t goodix_sysfs_fwimage_store(struct file *file,
return count;
}
/* return fw_update result */
static ssize_t goodix_sysfs_result_show(
struct device *dev, struct device_attribute *attr,
char *buf)
{
struct fw_update_ctrl *fw_ctrl = &goodix_fw_update_ctrl;
char str[GOODIX_MAX_STR_LABLE_LEN] = {0};
int r = -EINVAL;
if (!fw_ctrl)
return r;
switch (fw_ctrl->status) {
case UPSTA_PREPARING:
sprintf(str, "preparing");
break;
case UPSTA_UPDATING:
sprintf(str, "updating");
break;
case UPSTA_SUCCESS:
sprintf(str, "success");
break;
case UPSTA_FAILED:
sprintf(str, "failed");
break;
case UPSTA_NOTWORK:
default:
sprintf(str, "notwork");
break;
}
r = snprintf(buf, PAGE_SIZE, "result:%s spend_time:%dms\n",
str, fw_ctrl->spend_time);
return r;
}
static DEVICE_ATTR(update_en, 0220, NULL, goodix_sysfs_update_en_store);
static DEVICE_ATTR(fwsize, 0664, goodix_sysfs_fwsize_show,
goodix_sysfs_fwsize_store);
static DEVICE_ATTR(result, 0664, goodix_sysfs_result_show, NULL);
static struct attribute *goodix_fwu_attrs[] = {
&dev_attr_update_en.attr,
&dev_attr_fwsize.attr,
&dev_attr_result.attr
};
static int goodix_fw_sysfs_init(struct goodix_ts_core *core_data, struct fw_update_ctrl *fw_ctrl)
static int goodix_fw_sysfs_init(struct goodix_ts_core *core_data,
struct fw_update_ctrl *fw_ctrl)
{
int ret = 0, i;
fw_ctrl->kobj = kobject_create_and_add("fwupdate", &core_data->pdev->dev.kobj);
fw_ctrl->kobj = kobject_create_and_add("fwupdate",
&core_data->pdev->dev.kobj);
if (!fw_ctrl->kobj) {
ts_err("failed create sub dir for fwupdate");
return -EINVAL;
@ -982,7 +1181,7 @@ static int goodix_fw_sysfs_init(struct goodix_ts_core *core_data, struct fw_upda
}
fw_ctrl->attr_fwimage.attr.name = "fwimage";
fw_ctrl->attr_fwimage.attr.mode = S_IRUGO | S_IWUGO;
fw_ctrl->attr_fwimage.attr.mode = 0666;
fw_ctrl->attr_fwimage.size = 0;
fw_ctrl->attr_fwimage.write = goodix_sysfs_fwimage_store;
ret = sysfs_create_bin_file(fw_ctrl->kobj, &fw_ctrl->attr_fwimage);
@ -1025,14 +1224,24 @@ static int goodix_request_firmware(struct firmware_data *fw_data,
container_of(fw_data, struct fw_update_ctrl, fw_data);
struct device *dev = &(fw_ctrl->core_data->pdev->dev);
int r;
int retry = GOODIX_RETRY_3;
ts_info("Request firmware image [%s]", name);
r = request_firmware(&fw_data->firmware, name, dev);
if (r < 0)
while (retry--) {
r = request_firmware(&fw_data->firmware, name, dev);
if (!r)
break;
ts_info("get fw bin retry:[%d]", GOODIX_RETRY_3 - retry);
msleep(200);
}
if (retry < 0) {
ts_err("Firmware image [%s] not available,errno:%d", name, r);
else
ts_info("Firmware image [%s] is ready", name);
return r;
return r;
}
ts_info("Firmware image [%s] is ready", name);
return 0;
}
/**
@ -1051,8 +1260,12 @@ static int goodix_fw_update_thread(void *data)
{
struct fw_update_ctrl *fwu_ctrl = data;
struct firmware *temp_firmware = NULL;
ktime_t start, end;
int r = -EINVAL;
start = ktime_get();
fwu_ctrl->spend_time = 0;
fwu_ctrl->status = UPSTA_NOTWORK;
mutex_lock(&fwu_ctrl->mutex);
if (fwu_ctrl->mode & UPDATE_MODE_SRC_REQUEST) {
@ -1095,11 +1308,17 @@ out:
if (r) {
ts_err("fw update failed, %d", r);
fwu_ctrl->status = UPSTA_FAILED;
goodix_ts_blocking_notify(NOTIFY_FWUPDATE_FAILED, NULL);
} else {
ts_info("fw update success");
fwu_ctrl->status = UPSTA_SUCCESS;
goodix_ts_blocking_notify(NOTIFY_FWUPDATE_SUCCESS, NULL);
}
end = ktime_get();
fwu_ctrl->spend_time = ktime_to_ms(ktime_sub(end, start));
return r;
}
@ -1147,7 +1366,7 @@ int goodix_fw_update_init(struct goodix_ts_core *core_data)
goodix_fw_update_ctrl.core_data = core_data;
goodix_fw_update_ctrl.mode = 0;
strlcpy(goodix_fw_update_ctrl.fw_name, TS_DEFAULT_FIRMWARE,
strlcpy(goodix_fw_update_ctrl.fw_name, core_data->board_data.fw_name,
sizeof(goodix_fw_update_ctrl.fw_name));
ret = goodix_fw_sysfs_init(core_data, &goodix_fw_update_ctrl);
@ -1155,6 +1374,13 @@ int goodix_fw_update_init(struct goodix_ts_core *core_data)
ts_err("failed create fwupate sysfs node");
return ret;
}
if (core_data->bus->ic_type == IC_TYPE_BERLIN_A)
goodix_fw_update_ctrl.update_info = &update_bra;
else if (core_data->bus->ic_type == IC_TYPE_BERLIN_B)
goodix_fw_update_ctrl.update_info = &update_brb;
else
goodix_fw_update_ctrl.update_info = &update_brd;
goodix_fw_update_ctrl.initialized = 1;
return 0;
}

View file

@ -20,8 +20,8 @@
#include "goodix_ts_core.h"
#define TS_DRIVER_NAME "gtx8_i2c"
#define I2C_MAX_TRANSFER_SIZE 255
#define TS_DRIVER_NAME "gtx8_i2c"
#define I2C_MAX_TRANSFER_SIZE 60
#define GOODIX_BUS_RETRY_TIMES 3
#define GOODIX_REG_ADDR_SIZE 4
@ -174,6 +174,12 @@ static int goodix_i2c_probe(struct i2c_client *client,
if (!ret)
return -EIO;
/* get ic type */
ret = goodix_get_ic_type(client->dev.of_node);
if (ret < 0)
return ret;
goodix_i2c_bus.ic_type = ret;
goodix_i2c_bus.bus_type = GOODIX_BUS_TYPE_I2C;
goodix_i2c_bus.dev = &client->dev;
goodix_i2c_bus.read = goodix_i2c_read;
@ -188,14 +194,14 @@ static int goodix_i2c_probe(struct i2c_client *client,
goodix_pdev->num_resources = 0;
/*
* you can find this platform dev in
* /sys/devices/platfrom/goodix_ts.0
* /sys/devices/platform/goodix_ts.0
* goodix_pdev->dev.parent = &client->dev;
*/
goodix_pdev->dev.platform_data = &goodix_i2c_bus;
goodix_pdev->dev.release = goodix_pdev_release;
/* register platform device, then the goodix_ts_core
* module will probe the touch deivce.
* module will probe the touch device.
*/
ret = platform_device_register(goodix_pdev);
if (ret) {
@ -220,8 +226,9 @@ static int goodix_i2c_remove(struct i2c_client *client)
#ifdef CONFIG_OF
static const struct of_device_id i2c_matchs[] = {
{.compatible = "goodix,brl-generic",},
{.compatible = "goodix,gt9897",},
{.compatible = "goodix,gt9966",},
{.compatible = "goodix,gt9916",},
{},
};
MODULE_DEVICE_TABLE(of, i2c_matchs);
@ -244,20 +251,14 @@ static struct i2c_driver goodix_i2c_driver = {
.id_table = i2c_id_table,
};
int goodix_bus_init(void)
int goodix_i2c_bus_init(void)
{
ts_info("Goodix i2c driver init");
return i2c_add_driver(&goodix_i2c_driver);
}
EXPORT_SYMBOL(goodix_bus_init);
void goodix_bus_exit(void)
void goodix_i2c_bus_exit(void)
{
ts_info("Goodix i2c driver exit");
i2c_del_driver(&goodix_i2c_driver);
}
EXPORT_SYMBOL(goodix_bus_exit);
MODULE_DESCRIPTION("Goodix Touchscreen Hardware Module");
MODULE_AUTHOR("Goodix, Inc.");
MODULE_LICENSE("GPL v2");

View file

@ -34,14 +34,14 @@ static struct platform_device *goodix_pdev;
struct goodix_bus_interface goodix_spi_bus;
/**
* goodix_spi_read- read device register through spi bus
* goodix_spi_read_bra- read device register through spi bus
* @dev: pointer to device data
* @addr: register address
* @data: read buffer
* @len: bytes to read
* return: 0 - read ok, < 0 - spi transter error
*/
int goodix_spi_read(struct device *dev, unsigned int addr,
static int goodix_spi_read_bra(struct device *dev, unsigned int addr,
unsigned char *data, unsigned int len)
{
struct spi_device *spi = to_spi_device(dev);
@ -54,7 +54,7 @@ int goodix_spi_read(struct device *dev, unsigned int addr,
rx_buf = kzalloc(SPI_READ_PREFIX_LEN + len, GFP_KERNEL);
tx_buf = kzalloc(SPI_READ_PREFIX_LEN + len, GFP_KERNEL);
if (!rx_buf || !tx_buf) {
ts_err("alloc tx/rx_buf failed, size:%d\n",
ts_err("alloc tx/rx_buf failed, size:%d",
SPI_READ_PREFIX_LEN + len);
return -ENOMEM;
}
@ -62,7 +62,7 @@ int goodix_spi_read(struct device *dev, unsigned int addr,
spi_message_init(&spi_msg);
memset(&xfers, 0, sizeof(xfers));
/*spi_read tx_buf format: 0xF1 + addr(2bytes) + data*/
/*spi_read tx_buf format: 0xF1 + addr(4bytes) + data*/
tx_buf[0] = SPI_READ_FLAG;
tx_buf[1] = (addr >> 24) & 0xFF;
tx_buf[2] = (addr >> 16) & 0xFF;
@ -80,7 +80,7 @@ int goodix_spi_read(struct device *dev, unsigned int addr,
spi_message_add_tail(&xfers, &spi_msg);
ret = spi_sync(spi, &spi_msg);
if (ret < 0) {
ts_err("spi transfer error:%d\n",ret);
ts_err("spi transfer error:%d",ret);
goto exit;
}
memcpy(data, &rx_buf[SPI_READ_PREFIX_LEN], len);
@ -91,6 +91,55 @@ exit:
return ret;
}
static int goodix_spi_read(struct device *dev, unsigned int addr,
unsigned char *data, unsigned int len)
{
struct spi_device *spi = to_spi_device(dev);
u8 *rx_buf = NULL;
u8 *tx_buf = NULL;
struct spi_transfer xfers;
struct spi_message spi_msg;
int ret = 0;
rx_buf = kzalloc(SPI_READ_PREFIX_LEN - 1 + len, GFP_KERNEL);
tx_buf = kzalloc(SPI_READ_PREFIX_LEN - 1 + len, GFP_KERNEL);
if (!rx_buf || !tx_buf) {
ts_err("alloc tx/rx_buf failed, size:%d",
SPI_READ_PREFIX_LEN - 1 + len);
return -ENOMEM;
}
spi_message_init(&spi_msg);
memset(&xfers, 0, sizeof(xfers));
/*spi_read tx_buf format: 0xF1 + addr(4bytes) + data*/
tx_buf[0] = SPI_READ_FLAG;
tx_buf[1] = (addr >> 24) & 0xFF;
tx_buf[2] = (addr >> 16) & 0xFF;
tx_buf[3] = (addr >> 8) & 0xFF;
tx_buf[4] = addr & 0xFF;
tx_buf[5] = 0xFF;
tx_buf[6] = 0xFF;
tx_buf[7] = 0xFF;
xfers.tx_buf = tx_buf;
xfers.rx_buf = rx_buf;
xfers.len = SPI_READ_PREFIX_LEN - 1 + len;
xfers.cs_change = 0;
spi_message_add_tail(&xfers, &spi_msg);
ret = spi_sync(spi, &spi_msg);
if (ret < 0) {
ts_err("spi transfer error:%d",ret);
goto exit;
}
memcpy(data, &rx_buf[SPI_READ_PREFIX_LEN - 1], len);
exit:
kfree(rx_buf);
kfree(tx_buf);
return ret;
}
/**
* goodix_spi_write- write device register through spi bus
* @dev: pointer to device data
@ -99,7 +148,7 @@ exit:
* @len: bytes to write
* return: 0 - write ok; < 0 - spi transter error.
*/
int goodix_spi_write(struct device *dev, unsigned int addr,
static int goodix_spi_write(struct device *dev, unsigned int addr,
unsigned char *data, unsigned int len)
{
struct spi_device *spi = to_spi_device(dev);
@ -110,7 +159,7 @@ int goodix_spi_write(struct device *dev, unsigned int addr,
tx_buf = kzalloc(SPI_WRITE_PREFIX_LEN + len, GFP_KERNEL);
if (!tx_buf) {
ts_err("alloc tx_buf failed, size:%d\n",
ts_err("alloc tx_buf failed, size:%d",
SPI_WRITE_PREFIX_LEN + len);
return -ENOMEM;
}
@ -130,7 +179,7 @@ int goodix_spi_write(struct device *dev, unsigned int addr,
spi_message_add_tail(&xfers, &spi_msg);
ret = spi_sync(spi, &spi_msg);
if (ret < 0)
ts_err("spi transfer error:%d\n",ret);
ts_err("spi transfer error:%d",ret);
kfree(tx_buf);
return ret;
@ -151,7 +200,6 @@ static int goodix_spi_probe(struct spi_device *spi)
/* init spi_device */
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
spi->max_speed_hz = 1000000;
ret = spi_setup(spi);
if (ret) {
@ -159,9 +207,18 @@ static int goodix_spi_probe(struct spi_device *spi)
return ret;
}
/* get ic type */
ret = goodix_get_ic_type(spi->dev.of_node);
if (ret < 0)
return ret;
goodix_spi_bus.ic_type = ret;
goodix_spi_bus.bus_type = GOODIX_BUS_TYPE_SPI;
goodix_spi_bus.dev = &spi->dev;
goodix_spi_bus.read = goodix_spi_read;
if (goodix_spi_bus.ic_type == IC_TYPE_BERLIN_A)
goodix_spi_bus.read = goodix_spi_read_bra;
else
goodix_spi_bus.read = goodix_spi_read;
goodix_spi_bus.write = goodix_spi_write;
/* ts core device */
goodix_pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
@ -207,6 +264,8 @@ static int goodix_spi_remove(struct spi_device *spi)
static const struct of_device_id spi_matchs[] = {
{.compatible = "goodix,gt9897S",},
{.compatible = "goodix,gt9897T",},
{.compatible = "goodix,gt9966S",},
{.compatible = "goodix,gt9916S",},
{},
};
#endif
@ -227,20 +286,14 @@ static struct spi_driver goodix_spi_driver = {
.remove = goodix_spi_remove,
};
int goodix_bus_init(void)
int goodix_spi_bus_init(void)
{
ts_info("Goodix spi driver init");
return spi_register_driver(&goodix_spi_driver);
}
EXPORT_SYMBOL(goodix_bus_init);
void goodix_bus_exit(void)
void goodix_spi_bus_exit(void)
{
ts_info("Goodix spi driver exit");
spi_unregister_driver(&goodix_spi_driver);
}
EXPORT_SYMBOL(goodix_bus_exit);
MODULE_DESCRIPTION("Goodix Touchscreen Hardware Module");
MODULE_AUTHOR("Goodix, Inc.");
MODULE_LICENSE("GPL v2");

View file

@ -16,17 +16,16 @@
*/
#include "goodix_ts_core.h"
#define TS_DEFAULT_CFG_BIN "goodix_cfg_group.bin"
#define TS_BIN_VERSION_START_INDEX 5
#define TS_BIN_VERSION_LEN 4
#define TS_BIN_VERSION_START_INDEX 5
#define TS_BIN_VERSION_LEN 4
#define TS_CFG_BIN_HEAD_RESERVED_LEN 6
#define TS_CFG_OFFSET_LEN 2
#define TS_IC_TYPE_NAME_MAX_LEN 15
#define TS_CFG_BIN_HEAD_LEN (sizeof(struct goodix_cfg_bin_head) + \
TS_CFG_BIN_HEAD_RESERVED_LEN)
#define TS_PKG_CONST_INFO_LEN (sizeof(struct goodix_cfg_pkg_const_info))
#define TS_PKG_REG_INFO_LEN (sizeof(struct goodix_cfg_pkg_reg_info))
#define TS_PKG_HEAD_LEN (TS_PKG_CONST_INFO_LEN + TS_PKG_REG_INFO_LEN)
#define TS_CFG_OFFSET_LEN 2
#define TS_IC_TYPE_NAME_MAX_LEN 15
#define TS_CFG_BIN_HEAD_LEN (sizeof(struct goodix_cfg_bin_head) + \
TS_CFG_BIN_HEAD_RESERVED_LEN)
#define TS_PKG_CONST_INFO_LEN (sizeof(struct goodix_cfg_pkg_const_info))
#define TS_PKG_REG_INFO_LEN (sizeof(struct goodix_cfg_pkg_reg_info))
#define TS_PKG_HEAD_LEN (TS_PKG_CONST_INFO_LEN + TS_PKG_REG_INFO_LEN)
/*cfg block definitin*/
#define TS_CFG_BLOCK_PID_LEN 8
@ -35,8 +34,8 @@
#define TS_CFG_BLOCK_FW_PATCH_LEN 4
#define TS_CFG_BLOCK_RESERVED_LEN 9
#define TS_NORMAL_CFG 0x01
#define TS_HIGH_SENSE_CFG 0x03
#define TS_NORMAL_CFG 0x01
#define TS_HIGH_SENSE_CFG 0x03
#define TS_RQST_FW_RETRY_TIMES 2
#pragma pack(1)
@ -101,20 +100,24 @@ struct goodix_cfg_bin {
struct goodix_cfg_package *cfg_pkgs;
};
static int goodix_read_cfg_bin(struct device *dev, struct goodix_cfg_bin *cfg_bin)
static int goodix_read_cfg_bin(struct device *dev, const char *cfg_name,
struct goodix_cfg_bin *cfg_bin)
{
const struct firmware *firmware = NULL;
char cfg_bin_name[GOODIX_MAX_STR_LABLE_LEN] = {0x00};
int ret;
int retry = GOODIX_RETRY_3;
/*get cfg_bin_name*/
strlcpy(cfg_bin_name, TS_DEFAULT_CFG_BIN, sizeof(cfg_bin_name));
ts_info("cfg_bin_name:%s", cfg_bin_name);
ts_info("cfg_bin_name:%s", cfg_name);
ret = request_firmware(&firmware, cfg_bin_name, dev);
if (ret) {
ts_err("failed get cfg bin[%s] error:%d",
cfg_bin_name, ret);
while (retry--) {
ret = request_firmware(&firmware, cfg_name, dev);
if (!ret)
break;
ts_info("get cfg bin retry:[%d]", GOODIX_RETRY_3 - retry);
msleep(200);
}
if (retry < 0) {
ts_err("failed get cfg bin[%s] error:%d", cfg_name, ret);
return ret;
}
@ -126,7 +129,7 @@ static int goodix_read_cfg_bin(struct device *dev, struct goodix_cfg_bin *cfg_bi
}
cfg_bin->bin_data_len = firmware->size;
/*allocate memory for cfg_bin->bin_data*/
/* allocate memory for cfg_bin->bin_data */
cfg_bin->bin_data = kzalloc(cfg_bin->bin_data_len, GFP_KERNEL);
if (!cfg_bin->bin_data) {
ret = -ENOMEM;
@ -209,8 +212,6 @@ static int goodix_parse_cfg_bin(struct goodix_cfg_bin *cfg_bin)
memcpy(&cfg_bin->cfg_pkgs[i].reg_info,
&cfg_bin->bin_data[offset1 + TS_PKG_CONST_INFO_LEN],
TS_PKG_REG_INFO_LEN);
/*TODO compatible little edition and big edition*/
//goodix_cfg_pkg_leToCpu(&cfg_bin->cfg_pkgs[i]);
/*get configuration data*/
cfg_bin->cfg_pkgs[i].cfg = &cfg_bin->bin_data[offset1 + TS_PKG_HEAD_LEN];
@ -290,10 +291,11 @@ err_out:
static int goodix_get_config_data(struct goodix_ts_core *cd, u8 sensor_id)
{
struct goodix_cfg_bin cfg_bin = {0};
char *cfg_name = cd->board_data.cfg_bin_name;
int ret;
/*get cfg_bin from file system*/
ret = goodix_read_cfg_bin(&cd->pdev->dev, &cfg_bin);
ret = goodix_read_cfg_bin(&cd->pdev->dev, cfg_name, &cfg_bin);
if (ret) {
ts_err("failed get valid config bin data");
return ret;
@ -328,3 +330,5 @@ int goodix_get_config_proc(struct goodix_ts_core *cd)
return goodix_get_config_data(cd, cd->fw_version.sensor_id);
}

View file

@ -14,7 +14,6 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/of_irq.h>
#ifdef CONFIG_OF
#include <linux/of_gpio.h>
@ -25,18 +24,33 @@
#include <linux/fb.h>
#endif
#define GOODIX_CORE_DRIVER_NAME "goodix_ts"
#define GOODIX_PEN_DRIVER_NAME "goodix_ts,pen"
#define GOODIX_DRIVER_VERSION "v1.0.1"
#define GOODIX_MAX_TOUCH 10
#define GOODIX_PEN_MAX_PRESSURE 4096
#define GOODIX_MAX_PEN_KEY 2
#define GOODIX_CFG_MAX_SIZE 4096
#define GOODIX_MAX_STR_LABLE_LEN 32
#define GOODIX_CORE_DRIVER_NAME "goodix_ts"
#define GOODIX_PEN_DRIVER_NAME "goodix_ts,pen"
#define GOODIX_DRIVER_VERSION "v1.1.21"
#define GOODIX_MAX_TOUCH 10
#define GOODIX_PEN_MAX_PRESSURE 4096
#define GOODIX_MAX_PEN_KEY 2
#define GOODIX_PEN_MAX_TILT 90
#define GOODIX_CFG_MAX_SIZE 4096
#define GOODIX_MAX_STR_LABLE_LEN 32
#define GOODIX_NORMAL_RESET_DELAY_MS 100
#define GOODIX_HOLD_CPU_RESET_DELAY_MS 5
#define GOODIX_RETRY_3 3
#define GOODIX_RETRY_5 5
#define GOODIX_RETRY_10 10
#define TS_DEFAULT_FIRMWARE "goodix_firmware.bin"
#define TS_DEFAULT_CFG_BIN "goodix_cfg_group.bin"
enum CORD_PROB_STA {
CORE_MODULE_UNPROBED = 0,
CORE_MODULE_PROB_SUCCESS = 1,
CORE_MODULE_PROB_FAILED = -1,
CORE_MODULE_REMOVED = -2,
};
enum GOODIX_ERR_CODE {
GOODIX_EBUS = (1<<0),
GOODIX_ECHECKSUM = (1<<1),
@ -52,7 +66,9 @@ enum IC_TYPE_ID {
IC_TYPE_NORMANDY,
IC_TYPE_NANJING,
IC_TYPE_YELLOWSTONE,
IC_TYPE_BERLIN,
IC_TYPE_BERLIN_A,
IC_TYPE_BERLIN_B,
IC_TYPE_BERLIN_D
};
enum GOODIX_IC_CONFIG_TYPE {
@ -180,6 +196,18 @@ struct goodix_ic_info {
};
#pragma pack()
/*
* struct ts_rawdata_info
*
*/
#define TS_RAWDATA_BUFF_MAX 7000
#define TS_RAWDATA_RESULT_MAX 100
struct ts_rawdata_info {
int used_size; //fill in rawdata size
s16 buff[TS_RAWDATA_BUFF_MAX];
char result[TS_RAWDATA_RESULT_MAX];
};
/*
* struct goodix_module - external modules container
* @head: external modules list
@ -193,7 +221,6 @@ struct goodix_module {
bool initilized;
struct mutex mutex;
struct workqueue_struct *wq;
struct completion core_comp;
struct goodix_ts_core *core_data;
};
@ -214,6 +241,8 @@ struct goodix_ts_board_data {
char iovdd_name[GOODIX_MAX_STR_LABLE_LEN];
int reset_gpio;
int irq_gpio;
int avdd_gpio;
int iovdd_gpio;
unsigned int irq_flags;
unsigned int swap_axis;
@ -223,8 +252,8 @@ struct goodix_ts_board_data {
unsigned int panel_max_p; /*pressure*/
bool pen_enable;
const char *fw_name;
const char *cfg_bin_name;
char fw_name[GOODIX_MAX_STR_LABLE_LEN];
char cfg_bin_name[GOODIX_MAX_STR_LABLE_LEN];
};
enum goodix_fw_update_mode {
@ -324,6 +353,7 @@ struct goodix_pen_data {
* @event_data: event data
*/
struct goodix_ts_event {
int retry;
enum ts_event_type event_type;
u8 request_code; /* represent the request type */
u8 gesture_type;
@ -339,6 +369,7 @@ enum goodix_ic_bus_type {
struct goodix_bus_interface {
int bus_type;
int ic_type;
struct device *dev;
int (*read)(struct device *dev, unsigned int addr,
unsigned char *data, unsigned int len);
@ -366,6 +397,7 @@ struct goodix_ts_hw_ops {
int (*esd_check)(struct goodix_ts_core *cd);
int (*event_handler)(struct goodix_ts_core *cd, struct goodix_ts_event *ts_event);
int (*after_event_handler)(struct goodix_ts_core *cd); /* clean sync flag */
int (*get_capacitance_data)(struct goodix_ts_core *cd, struct ts_rawdata_info *info);
};
/*
@ -375,6 +407,7 @@ struct goodix_ts_hw_ops {
* off esd protection
*/
struct goodix_ts_esd {
bool irq_status;
atomic_t esd_on;
struct delayed_work esd_work;
struct notifier_block esd_notifier;
@ -403,7 +436,7 @@ struct goodix_ts_core {
struct goodix_ts_hw_ops *hw_ops;
struct input_dev *input_dev;
struct input_dev *pen_dev;
/* TODO counld we remove this from core data? */
/* TODO counld we remove this from core data? */
struct goodix_ts_event ts_event;
/* every pointer of this array represent a kind of config */
@ -417,6 +450,8 @@ struct goodix_ts_core {
atomic_t irq_enabled;
atomic_t suspended;
/* when this flag is true, driver should not clean the sync flag */
bool tools_ctrl_sync;
struct notifier_block ts_notifier;
struct goodix_ts_esd ts_esd;
@ -436,9 +471,9 @@ enum goodix_ext_priority {
EXTMOD_PRIO_DEFAULT,
};
#define EVT_HANDLED 0
#define EVT_HANDLED 0
#define EVT_CONTINUE 0
#define EVT_CANCEL 1
#define EVT_CANCEL 1
#define EVT_CANCEL_IRQEVT 1
#define EVT_CANCEL_SUSPEND 1
#define EVT_CANCEL_RESUME 1
@ -511,16 +546,11 @@ struct goodix_ext_attribute {
static struct goodix_ext_attribute ext_attr_##_name = \
__EXTMOD_ATTR(_name, _mode, _show, _store);
//#define CONFIG_GOODIX_DEBUG
/* log macro */
extern bool debug_log_flag;
#define ts_info(fmt, arg...) pr_info("[GTP-INF][%s:%d] "fmt"\n", __func__, __LINE__, ##arg)
#define ts_err(fmt, arg...) pr_err("[GTP-ERR][%s:%d] "fmt"\n", __func__, __LINE__, ##arg)
#ifdef CONFIG_GOODIX_DEBUG
#define ts_debug(fmt, arg...) pr_info("[GTP-DBG][%s:%d] "fmt"\n", __func__, __LINE__, ##arg)
#else
#define ts_debug(fmt, arg...) do {} while (0)
#endif
#define ts_err(fmt, arg...) pr_err("[GTP-ERR][%s:%d] "fmt"\n", __func__, __LINE__, ##arg)
#define ts_debug(fmt, arg...) {if (debug_log_flag) pr_info("[GTP-DBG][%s:%d] "fmt"\n", __func__, __LINE__, ##arg);}
/*
* get board data pointer
@ -554,24 +584,35 @@ int goodix_unregister_ext_module(struct goodix_ext_module *module);
/* remove all registered ext module
* return 0 on success, otherwise return < 0
*/
int goodix_unregister_all_module(void);
int goodix_ts_blocking_notify(enum ts_notify_event evt, void *v);
void goodix_debugfs_printf(const char *fmt, ...);
struct kobj_type *goodix_get_default_ktype(void);
struct kobject *goodix_get_default_kobj(void);
struct goodix_ts_hw_ops *goodix_get_hw_ops(void);
int goodix_get_config_proc(struct goodix_ts_core *cd);
int goodix_bus_init(void);
void goodix_bus_exit(void);
int goodix_spi_bus_init(void);
void goodix_spi_bus_exit(void);
int goodix_i2c_bus_init(void);
void goodix_i2c_bus_exit(void);
u32 goodix_append_checksum(u8 *data, int len, int mode);
int checksum_cmp(const u8 *data, int size, int mode);
int is_risk_data(const u8 *data, int size);
u32 goodix_get_file_config_id(u8 *ic_config);
void goodix_rotate_abcd2cbad(int tx, int rx, s16 *data);
int goodix_gesture_enable(int enable);
int goodix_fw_update_init(struct goodix_ts_core *core_data);
void goodix_fw_update_uninit(void);
int goodix_do_fw_update(struct goodix_ic_config *ic_config, int mode);
int goodix_get_ic_type(struct device_node *node);
int gesture_module_init(void);
void gesture_module_exit(void);
int inspect_module_init(void);
void inspect_module_exit(void);
int goodix_tools_init(void);
void goodix_tools_exit(void);
#endif

View file

@ -48,6 +48,30 @@ struct gesture_module {
};
static struct gesture_module *gsx_gesture; /*allocated in gesture init module*/
static bool module_initialized;
int goodix_gesture_enable(int enable)
{
int ret = 0;
if (!module_initialized)
return 0;
if (enable) {
if (atomic_read(&gsx_gesture->registered))
ts_info("gesture module has been already registered");
else
ret = goodix_register_ext_module_no_wait(&gsx_gesture->module);
} else {
if (!atomic_read(&gsx_gesture->registered))
ts_info("gesture module has been already unregistered");
else
ret = goodix_unregister_ext_module(&gsx_gesture->module);
}
return ret;
}
/**
* gsx_gesture_type_show - show valid gesture type
@ -125,10 +149,10 @@ static ssize_t gsx_gesture_enable_store(struct goodix_ext_module *module,
return ret;
if (val) {
ret = goodix_register_ext_module_no_wait(&gsx_gesture->module);
ret = goodix_gesture_enable(1);
return ret ? ret : count;
} else {
ret = goodix_unregister_ext_module(&gsx_gesture->module);
ret = goodix_gesture_enable(0);
return ret ? ret : count;
}
}
@ -157,46 +181,33 @@ const struct goodix_ext_attribute gesture_attrs[] = {
static int gsx_gesture_init(struct goodix_ts_core *cd,
struct goodix_ext_module *module)
{
int i, ret = -EINVAL;
if (!cd || !cd->hw_ops->gesture) {
ts_err("gesture unsupported");
return -EINVAL;
}
if (atomic_read(&gsx_gesture->registered))
return 0;
ts_info("gesture switch: ON");
ts_debug("enable all gesture type");
/* set all bit to 1 to enable all gesture wakeup */
memset(gsx_gesture->gesture_type, 0xff, GSX_GESTURE_TYPE_LEN);
module->priv_data = cd;
ret = kobject_init_and_add(&module->kobj, goodix_get_default_ktype(),
&cd->pdev->dev.kobj, "gesture");
if (ret) {
ts_err("failed create gesture sysfs node!");
return ret;
}
for (i = 0; i < ARRAY_SIZE(gesture_attrs) && !ret; i++)
ret = sysfs_create_file(&module->kobj, &gesture_attrs[i].attr);
if (ret) {
ts_err("failed create gst sysfs files");
while (--i >= 0)
sysfs_remove_file(&module->kobj, &gesture_attrs[i].attr);
kobject_put(&module->kobj);
return ret;
}
atomic_set(&gsx_gesture->registered, 1);
return 0;
}
static int gsx_gesture_exit(struct goodix_ts_core *cd,
struct goodix_ext_module *module)
{
if (!cd || !cd->hw_ops->gesture) {
ts_err("gesture unsupported");
return -EINVAL;
}
ts_info("gesture switch: OFF");
ts_debug("disable all gesture type");
memset(gsx_gesture->gesture_type, 0x00, GSX_GESTURE_TYPE_LEN);
atomic_set(&gsx_gesture->registered, 0);
return 0;
}
@ -248,9 +259,10 @@ static int gsx_gesture_ist(struct goodix_ts_core *cd,
re_send_ges_cmd:
if (hw_ops->gesture(cd, 0))
ts_info("warning: failed re_send gesture cmd\n");
ts_info("warning: failed re_send gesture cmd");
gesture_ist_exit:
hw_ops->after_event_handler(cd);
if (!cd->tools_ctrl_sync)
hw_ops->after_event_handler(cd);
return EVT_CANCEL_IRQEVT;
}
@ -268,29 +280,49 @@ static int gsx_gesture_before_suspend(struct goodix_ts_core *cd,
int ret;
const struct goodix_ts_hw_ops *hw_ops = cd->hw_ops;
atomic_set(&cd->suspended, 1);
ret = hw_ops->gesture(cd, 0);
if (ret)
ts_err("failed enter gesture mode");
else
ts_info("enter gesture mode");
hw_ops->irq_enable(cd, true);
enable_irq_wake(cd->irq);
return EVT_CANCEL_SUSPEND;
}
static int gsx_gesture_before_resume(struct goodix_ts_core *cd,
struct goodix_ext_module *module)
{
const struct goodix_ts_hw_ops *hw_ops = cd->hw_ops;
hw_ops->irq_enable(cd, false);
disable_irq_wake(cd->irq);
hw_ops->reset(cd, GOODIX_NORMAL_RESET_DELAY_MS);
return EVT_CANCEL_RESUME;
}
static struct goodix_ext_module_funcs gsx_gesture_funcs = {
.irq_event = gsx_gesture_ist,
.init = gsx_gesture_init,
.exit = gsx_gesture_exit,
.before_suspend = gsx_gesture_before_suspend
.before_suspend = gsx_gesture_before_suspend,
.before_resume = gsx_gesture_before_resume,
};
static int __init goodix_gsx_gesture_init(void)
int gesture_module_init(void)
{
ts_info("gesture module init");
int ret;
int i;
struct kobject *def_kobj = goodix_get_default_kobj();
struct kobj_type *def_kobj_type = goodix_get_default_ktype();
gsx_gesture = kzalloc(sizeof(struct gesture_module), GFP_KERNEL);
if (!gsx_gesture)
return -ENOMEM;
gsx_gesture->module.funcs = &gsx_gesture_funcs;
gsx_gesture->module.priority = EXTMOD_PRIO_GESTURE;
gsx_gesture->module.name = "Goodix_gsx_gesture";
@ -298,32 +330,55 @@ static int __init goodix_gsx_gesture_init(void)
atomic_set(&gsx_gesture->registered, 0);
rwlock_init(&gsx_gesture->rwlock);
goodix_register_ext_module(&(gsx_gesture->module));
/* gesture sysfs init */
ret = kobject_init_and_add(&gsx_gesture->module.kobj,
def_kobj_type, def_kobj, "gesture");
if (ret) {
ts_err("failed create gesture sysfs node!");
goto err_out;
}
for (i = 0; i < ARRAY_SIZE(gesture_attrs) && !ret; i++)
ret = sysfs_create_file(&gsx_gesture->module.kobj,
&gesture_attrs[i].attr);
if (ret) {
ts_err("failed create gst sysfs files");
while (--i >= 0)
sysfs_remove_file(&gsx_gesture->module.kobj,
&gesture_attrs[i].attr);
kobject_put(&gsx_gesture->module.kobj);
goto err_out;
}
module_initialized = true;
ts_info("gesture module init success");
return 0;
err_out:
ts_err("gesture module init failed!");
kfree(gsx_gesture);
return ret;
}
static void __exit goodix_gsx_gesture_exit(void)
void gesture_module_exit(void)
{
int i;
ts_info("gesture module exit");
if (atomic_read(&gsx_gesture->registered)) {
goodix_unregister_ext_module(&gsx_gesture->module);
atomic_set(&gsx_gesture->registered, 0);
if (!module_initialized)
return;
for (i = 0; i < ARRAY_SIZE(gesture_attrs); i++)
sysfs_remove_file(&gsx_gesture->module.kobj,
&gesture_attrs[i].attr);
goodix_gesture_enable(0);
kobject_put(&gsx_gesture->module.kobj);
}
/* deinit sysfs */
for (i = 0; i < ARRAY_SIZE(gesture_attrs); i++)
sysfs_remove_file(&gsx_gesture->module.kobj,
&gesture_attrs[i].attr);
kobject_put(&gsx_gesture->module.kobj);
kfree(gsx_gesture);
}
late_initcall(goodix_gsx_gesture_init);
module_exit(goodix_gsx_gesture_exit);
MODULE_DESCRIPTION("Goodix Touchscreen Gesture Module");
MODULE_AUTHOR("Goodix, Inc.");
MODULE_LICENSE("GPL v2");
module_initialized = false;
}

File diff suppressed because it is too large Load diff

View file

@ -45,30 +45,13 @@ static const u16 goodix_tools_ver = ((GOODIX_TOOLS_VER_MAJOR << 8) +
#define GTP_READ_CONFIG (_IOW(GOODIX_TS_IOC_MAGIC, 7, u8) & NEGLECT_SIZE_MASK)
#define GTP_ESD_ENABLE _IO(GOODIX_TS_IOC_MAGIC, 8)
#define GTP_TOOLS_VER (_IOR(GOODIX_TS_IOC_MAGIC, 9, u8) & NEGLECT_SIZE_MASK)
#define GTP_TOOLS_CTRL_SYNC (_IOW(GOODIX_TS_IOC_MAGIC, 10, u8) & NEGLECT_SIZE_MASK)
#define GOODIX_TS_IOC_MAXNR 10
#define MAX_BUF_LENGTH (16*1024)
#define IRQ_FALG (0x01 << 2)
#define I2C_MSG_HEAD_LEN 20
/*
* struct goodix_tools_data - goodix tools data message used in sync read
* @data: The buffer into which data is written
* @reg_addr: Slave device register start address to start read data
* @length: Number of data bytes in @data being read from slave device
* @filled: When buffer @data be filled will set this flag with 1, outhrwise 0
* @list_head:Eonnet every goodix_tools_data struct into a list
*/
struct goodix_tools_data {
u32 reg_addr;
u32 length;
u8 *data;
bool filled;
struct list_head list;
};
/*
* struct goodix_tools_dev - goodix tools device struct
* @ts_core: The core data struct of ts driver
@ -188,64 +171,6 @@ err_out:
return ret;
}
/* read data from i2c synchronous,
* return data length when success, otherwise return < 0
*/
static int sync_read(struct goodix_tools_dev *dev, void __user *arg)
{
int ret = 0;
u8 i2c_msg_head[I2C_MSG_HEAD_LEN];
struct goodix_tools_data tools_data;
ret = copy_from_user(&i2c_msg_head, arg, I2C_MSG_HEAD_LEN);
if (ret) {
ts_err("Copy data from user failed");
return -EFAULT;
}
tools_data.reg_addr = i2c_msg_head[0] + (i2c_msg_head[1] << 8)
+ (i2c_msg_head[2] << 16) + (i2c_msg_head[3] << 24);
tools_data.length = i2c_msg_head[4] + (i2c_msg_head[5] << 8)
+ (i2c_msg_head[6] << 16) + (i2c_msg_head[7] << 24);
tools_data.filled = 0;
if (tools_data.length > MAX_BUF_LENGTH) {
ts_err("buffer too long:%d > %d",
tools_data.length, MAX_BUF_LENGTH);
return -EINVAL;
}
tools_data.data = kzalloc(tools_data.length, GFP_KERNEL);
if (!tools_data.data) {
ts_err("Alloc memory failed");
return -ENOMEM;
}
mutex_lock(&dev->mutex);
list_add_tail(&tools_data.list, &dev->head);
mutex_unlock(&dev->mutex);
/* wait queue will timeout after 1 seconds */
wait_event_interruptible_timeout(dev->wq, tools_data.filled == 1, HZ * 3);
mutex_lock(&dev->mutex);
list_del(&tools_data.list);
mutex_unlock(&dev->mutex);
if (!tools_data.filled) {
ret = -EAGAIN;
ts_err("Wait queue timeout");
goto out;
}
ret = copy_to_user((u8 *)arg + I2C_MSG_HEAD_LEN,
tools_data.data, tools_data.length);
if (ret) {
ret = -EFAULT;
ts_err("Copy_to_user failed");
goto out;
}
ret = tools_data.length;
out:
kfree(tools_data.data);
return ret;
}
/* write data to i2c asynchronous,
* success return bytes write, else return <= 0
*/
@ -351,11 +276,6 @@ static long goodix_tools_ioctl(struct file *filp, unsigned int cmd,
ts_err("Bad magic num:%c", _IOC_TYPE(cmd));
return -ENOTTY;
}
if (_IOC_NR(cmd) > GOODIX_TS_IOC_MAXNR) {
ts_err("Bad cmd num:%d > %d",
_IOC_NR(cmd), GOODIX_TS_IOC_MAXNR);
return -ENOTTY;
}
switch (cmd & NEGLECT_SIZE_MASK) {
case GTP_IRQ_ENABLE:
@ -425,14 +345,7 @@ static long goodix_tools_ioctl(struct file *filp, unsigned int cmd,
ts_err("Async data read failed");
break;
case GTP_SYNC_READ:
if (filp->f_flags & O_NONBLOCK) {
ts_err("Goodix tools now worked in sync_bus mode");
ret = -EAGAIN;
goto err_out;
}
ret = sync_read(dev, (void __user *)arg);
if (ret < 0)
ts_err("Sync data read failed");
ts_info("unsupport sync read");
break;
case GTP_ASYNC_WRITE:
ret = async_write(dev, (void __user *)arg);
@ -445,6 +358,10 @@ static long goodix_tools_ioctl(struct file *filp, unsigned int cmd,
if (ret)
ts_err("failed copy driver version info to user");
break;
case GTP_TOOLS_CTRL_SYNC:
ts_core->tools_ctrl_sync = !!arg;
ts_info("set tools ctrl sync %d", ts_core->tools_ctrl_sync);
break;
default:
ts_info("Invalid cmd");
ret = -ENOTTY;
@ -489,41 +406,13 @@ static int goodix_tools_release(struct inode *inode, struct file *filp)
{
int ret = 0;
/* when the last close this dev node unregister the module */
goodix_tools_dev->ts_core->tools_ctrl_sync = false;
atomic_set(&goodix_tools_dev->in_use, 0);
goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL);
ret = goodix_unregister_ext_module(&goodix_tools_dev->module);
return ret;
}
/**
* goodix_tools_module_irq - goodix tools Irq handle
* This functions is excuted when interrupt happended
*
* @core_data: pointer to touch core data
* @module: pointer to goodix_ext_module struct
* return: EVT_CONTINUE let other module handle this irq
*/
static int goodix_tools_module_irq(struct goodix_ts_core *core_data,
struct goodix_ext_module *module)
{
struct goodix_tools_dev *dev = module->priv_data;
const struct goodix_ts_hw_ops *hw_ops = core_data->hw_ops;
struct goodix_tools_data *tools_data, *next;
mutex_lock(&dev->mutex);
if (!list_empty(&dev->head)) {
list_for_each_entry_safe(tools_data, next, &dev->head, list) {
if (!hw_ops->read(core_data, tools_data->reg_addr,
tools_data->data, tools_data->length)) {
tools_data->filled = 1;
}
}
wake_up(&dev->wq);
}
mutex_unlock(&dev->mutex);
return EVT_CONTINUE;
}
static int goodix_tools_module_init(struct goodix_ts_core *core_data,
struct goodix_ext_module *module)
{
@ -566,7 +455,6 @@ static struct miscdevice goodix_tools_miscdev = {
};
static struct goodix_ext_module_funcs goodix_tools_module_funcs = {
.irq_event = goodix_tools_module_irq,
.init = goodix_tools_module_init,
.exit = goodix_tools_module_exit,
};
@ -576,7 +464,7 @@ static struct goodix_ext_module_funcs goodix_tools_module_funcs = {
*
* return: 0 success, else failed
*/
static int __init goodix_tools_init(void)
int goodix_tools_init(void)
{
int ret;
@ -601,20 +489,15 @@ static int __init goodix_tools_init(void)
ret = misc_register(&goodix_tools_miscdev);
if (ret)
ts_err("Debug tools miscdev register failed");
else
ts_info("Debug tools miscdev register success");
return ret;
}
static void __exit goodix_tools_exit(void)
void goodix_tools_exit(void)
{
misc_deregister(&goodix_tools_miscdev);
kfree(goodix_tools_dev);
ts_info("Goodix tools miscdev exit");
ts_info("Debug tools miscdev exit");
}
late_initcall(goodix_tools_init);
module_exit(goodix_tools_exit);
MODULE_DESCRIPTION("Goodix tools Module");
MODULE_AUTHOR("Goodix, Inc.");
MODULE_LICENSE("GPL v2");

View file

@ -16,6 +16,8 @@
*/
#include "goodix_ts_core.h"
bool debug_log_flag = false;
/*****************************************************************************
* goodix_append_checksum
* @summary
@ -119,3 +121,59 @@ u32 goodix_get_file_config_id(u8 *ic_config)
return 0;
return le32_to_cpup((__le32 *)&ic_config[CONFIG_ID_OFFSET]);
}
/* matrix transpose */
void goodix_rotate_abcd2cbad(int tx, int rx, s16 *data)
{
s16 *temp_buf = NULL;
int size = tx * rx;
int i;
int j;
int col;
temp_buf = kcalloc(size, sizeof(s16), GFP_KERNEL);
if (!temp_buf) {
ts_err("malloc failed");
return;
}
for (i = 0, j = 0, col = 0; i < size; i++) {
temp_buf[i] = data[j++ * rx + col];
if (j == tx) {
j = 0;
col++;
}
}
memcpy(data, temp_buf, size * sizeof(s16));
kfree(temp_buf);
}
/* get ic type */
int goodix_get_ic_type(struct device_node *node)
{
const char *name_tmp;
int ret;
ret = of_property_read_string(node, "compatible", &name_tmp);
if (ret < 0) {
ts_err("get compatible failed");
return ret;
}
if (strstr(name_tmp, "9897")) {
ts_info("ic type is BerlinA");
ret = IC_TYPE_BERLIN_A;
} else if (strstr(name_tmp, "9966") || strstr(name_tmp, "7986")) {
ts_info("ic type is BerlinB");
ret = IC_TYPE_BERLIN_B;
} else if (strstr(name_tmp, "9916")) {
ts_info("ic type is BerlinD");
ret = IC_TYPE_BERLIN_D;
} else {
ts_info("can't find valid ic_type");
ret = -EINVAL;
}
return ret;
}