1827 lines
45 KiB
C
1827 lines
45 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
#include <linux/bitops.h>
|
|
#include <linux/byteorder/generic.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/init.h>
|
|
#include <linux/input.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/module.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
#include <linux/earlysuspend.h>
|
|
#endif
|
|
|
|
#include "mtk_gslX680.h"
|
|
#include "tpd.h"
|
|
|
|
#include "mtk_boot_common.h"
|
|
#include <linux/device.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/of_irq.h>
|
|
#include <uapi/linux/sched/types.h>
|
|
|
|
#if !defined(CONFIG_MTK_I2C_EXTENSION) || defined(GSLTP_ENABLE_I2C_DMA)
|
|
#include <linux/dma-mapping.h>
|
|
#endif
|
|
|
|
#define GSLX680_NAME "gslX680"
|
|
#define GSLX680_ADDR 0x40
|
|
#define MAX_FINGERS 10
|
|
#define MAX_CONTACTS 10
|
|
#define DMA_TRANS_LEN 0x20
|
|
#define SMBUS_TRANS_LEN 0x01
|
|
#define GSL_PAGE_REG 0xf0
|
|
/*#define GREEN_MODE*/ /*IF use this, pls close esd check*/
|
|
#ifdef GREEN_MODE
|
|
#define MODE_ON 1
|
|
#define MODE_OFF 0
|
|
#endif
|
|
#ifndef GREEN_MODE
|
|
/*#define GSL_MONITOR*/ /*if enable ESD, please close GREEN_MODE*/
|
|
#endif
|
|
|
|
enum check_meun {
|
|
power_status = 1,
|
|
interrupt_status = 2,
|
|
esd_scanning = 4
|
|
}; /* select check mode 1,2,4 */
|
|
|
|
enum check_err {
|
|
power_shutdowned = 2,
|
|
interrupt_fail,
|
|
esd_protected
|
|
}; /* check mode err info 2,3,4 */
|
|
|
|
#define GSL_LATE_INIT_CHIP
|
|
#define TPD_PROC_DEBUG
|
|
/* #define ADD_I2C_DEVICE_ANDROID_4_0 */
|
|
/* #define HIGH_SPEED_I2C */
|
|
|
|
#ifdef TPD_PROC_DEBUG
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/seq_file.h> /* lzk */
|
|
#include <linux/uaccess.h>
|
|
/* static struct proc_dir_entry *gsl_config_proc = NULL; */
|
|
#define GSL_CONFIG_PROC_FILE "gsl_config"
|
|
#define CONFIG_LEN 31
|
|
static char gsl_read[CONFIG_LEN];
|
|
static u8 gsl_data_proc[8] = {0};
|
|
static u8 gsl_proc_flag;
|
|
#endif
|
|
|
|
static int tpd_flag;
|
|
static int tpd_halt;
|
|
/*static char eint_flag;*/
|
|
static int touch_irq;
|
|
static struct i2c_client *i2c_client;
|
|
static struct task_struct *thread;
|
|
|
|
#ifdef GSL_LATE_INIT_CHIP
|
|
static struct delayed_work gsl_late_init_work;
|
|
static struct workqueue_struct *gsl_late_init_workqueue;
|
|
#define LATE_INIT_CYCLE_BY_REG_CHECK 10
|
|
#endif
|
|
|
|
#ifdef GSL_MONITOR
|
|
static struct delayed_work gsl_monitor_work;
|
|
static struct workqueue_struct *gsl_monitor_workqueue;
|
|
static u8 int_1st[4] = {0};
|
|
static u8 int_2nd[4] = {0};
|
|
static char b0_counter;
|
|
static char bc_counter;
|
|
/* i2c_lock_flag mean 0:do checking 1:skip once checking; 2:skip anyway*/
|
|
static char i2c_lock_flag;
|
|
#define MONITOR_CYCLE_NORMAL 100
|
|
#define MONITOR_CYCLE_IDLE 800
|
|
#define MONITOR_CYCLE_BY_REG_CHECK 1800
|
|
#endif
|
|
|
|
/* #define TPD_HAVE_BUTTON */
|
|
#define TPD_KEY_COUNT 4
|
|
#define TPD_KEYS \
|
|
{ \
|
|
KEY_MENU, KEY_HOMEPAGE, KEY_BACK, KEY_SEARCH \
|
|
}
|
|
/* {button_center_x, button_center_y, button_width, button_height*/
|
|
#define TPD_KEYS_DIM \
|
|
{ \
|
|
{70, 2048, 60, 50}, {210, 2048, 60, 50}, {340, 2048, 60, 50}, \
|
|
{ \
|
|
470, 2048, 60, 50 \
|
|
} \
|
|
}
|
|
|
|
static DECLARE_WAIT_QUEUE_HEAD(waiter);
|
|
static int init_chip(struct i2c_client *client);
|
|
/*static void green_mode(struct i2c_client *client, int mode);*/
|
|
|
|
#define GSLTP_REG_ADDR_LEN 1
|
|
#ifdef CONFIG_MTK_I2C_EXTENSION
|
|
/*for ARCH_MT6735,ARCH_MT6735M, ARCH_MT6753,ARCH_MT6580,ARCH_MT6755*/
|
|
#define GSLTP_ENABLE_WRRD_MODE
|
|
#ifdef GSLTP_ENABLE_I2C_DMA
|
|
#define GSLTP_DMA_MAX_TRANSACTION_LEN 255 /* for DMA mode */
|
|
#define GSLTP_DMA_MAX_WR_SIZE \
|
|
(GSLTP_DMA_MAX_TRANSACTION_LEN - GSLTP_REG_ADDR_LEN)
|
|
#ifdef GSLTP_ENABLE_WRRD_MODE /*for WRRD(write and read) mode */
|
|
#define GSLTP_DMA_MAX_RD_SIZE 31
|
|
#else
|
|
#define GSLTP_DMA_MAX_RD_SIZE GSLTP_DMA_MAX_TRANSACTION_LEN
|
|
#endif
|
|
#endif
|
|
#else
|
|
#define GSLTP_DMA_MAX_TRANSACTION_LEN 255 /* for DMA mode */
|
|
#define GSLTP_DMA_MAX_RD_SIZE GSLTP_DMA_MAX_TRANSACTION_LEN
|
|
#define GSLTP_DMA_MAX_WR_SIZE \
|
|
(GSLTP_DMA_MAX_TRANSACTION_LEN - GSLTP_REG_ADDR_LEN)
|
|
#endif
|
|
|
|
#ifdef CONFIG_MTK_I2C_EXTENSION
|
|
#define GSLTP_I2C_MASTER_CLOCK 100
|
|
#ifdef GSLTP_ENABLE_I2C_DMA
|
|
static u8 *g_dma_buff_va;
|
|
static u8 *g_dma_buff_pa;
|
|
#endif
|
|
#else
|
|
static u8 *g_i2c_buff;
|
|
static u8 *g_i2c_addr;
|
|
#endif
|
|
#if !defined(CONFIG_MTK_I2C_EXTENSION) || defined(GSLTP_ENABLE_I2C_DMA)
|
|
static int msg_dma_alloc(void);
|
|
static void msg_dma_release(void);
|
|
#endif
|
|
|
|
#define GSL_DEBUG (0)
|
|
#if GSL_DEBUG
|
|
#define GSL_LOGD(fmt, args...) \
|
|
pr_debug(GSLX680_NAME "<-dbg-> [%04d] [@%s]" fmt, __LINE__, __func__, \
|
|
##args)
|
|
#define GSL_LOGF() \
|
|
pr_debug(GSLX680_NAME "<-func-> [%04d] [@%s] is call!\n", __LINE__, \
|
|
__func__)
|
|
|
|
#else
|
|
#define GSL_LOGD(fmt, args...) \
|
|
do { \
|
|
} while (0)
|
|
#define GSL_LOGF() \
|
|
do { \
|
|
} while (0)
|
|
#endif /* end #if GSL_DEBUG */
|
|
|
|
#define GSL_LOGE(fmt, args...) \
|
|
pr_debug(GSLX680_NAME "<-err->[%04d] [@%s]" fmt, __LINE__, __func__, \
|
|
##args)
|
|
|
|
#ifdef TPD_HAVE_BUTTON
|
|
static int tpd_keys_local[TPD_KEY_COUNT] = TPD_KEYS;
|
|
static int tpd_keys_dim_local[TPD_KEY_COUNT][4] = TPD_KEYS_DIM;
|
|
#endif
|
|
|
|
#if (defined(TPD_WARP_START) && defined(TPD_WARP_END))
|
|
static int tpd_wb_start_local[TPD_WARP_CNT] = TPD_WARP_START;
|
|
static int tpd_wb_end_local[TPD_WARP_CNT] = TPD_WARP_END;
|
|
#endif
|
|
#if (defined(TPD_HAVE_CALIBRATION) && !defined(TPD_CUSTOM_CALIBRATION))
|
|
static int tpd_calmat_local[8] = TPD_CALIBRATION_MATRIX;
|
|
static int tpd_def_calmat_local[8] = TPD_CALIBRATION_MATRIX;
|
|
#endif
|
|
|
|
#ifdef CONFIG_MTK_I2C_EXTENSION
|
|
#ifdef GSLTP_ENABLE_I2C_DMA
|
|
static int msg_dma_alloc(void)
|
|
{
|
|
g_dma_buff_va = (u8 *)dma_alloc_coherent(
|
|
NULL, GSLTP_DMA_MAX_TRANSACTION_LEN,
|
|
(dma_addr_t *)(&g_dma_buff_pa), GFP_KERNEL | GFP_DMA);
|
|
if (!g_dma_buff_va) {
|
|
GSL_LOGE("[DMA][Error] Allocate DMA I2C Buffer failed!\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void msg_dma_release(void)
|
|
{
|
|
if (g_dma_buff_va) {
|
|
dma_free_coherent(NULL, GSLTP_DMA_MAX_TRANSACTION_LEN,
|
|
g_dma_buff_va, (dma_addr_t)g_dma_buff_pa);
|
|
g_dma_buff_va = NULL;
|
|
g_dma_buff_pa = NULL;
|
|
GSL_LOGD("[DMA][release]I2C Buffer release!\n");
|
|
}
|
|
}
|
|
|
|
#ifdef GSLTP_ENABLE_WRRD_MODE
|
|
/*WRRD(write and read) mode, no stop condition after write reg addr*/
|
|
/*max DMA read len 31 bytes */
|
|
static s32 i2c_dma_read(struct i2c_client *client, u8 addr, u8 *rxbuf, s32 len)
|
|
{
|
|
int ret;
|
|
s32 retry = 0;
|
|
struct i2c_msg msg;
|
|
|
|
if (rxbuf == NULL)
|
|
return -1;
|
|
memset(&msg, 0, sizeof(struct i2c_msg));
|
|
|
|
*g_dma_buff_va = addr;
|
|
msg.addr = client->addr & I2C_MASK_FLAG;
|
|
msg.flags = 0;
|
|
msg.len = (len << 8) | GSLTP_REG_ADDR_LEN;
|
|
msg.buf = g_dma_buff_pa;
|
|
msg.ext_flag = client->ext_flag | I2C_ENEXT_FLAG | I2C_WR_FLAG |
|
|
I2C_RS_FLAG | I2C_DMA_FLAG;
|
|
msg.timing = GSLTP_I2C_MASTER_CLOCK;
|
|
|
|
/* GSL_LOGD("dma i2c read: 0x%04X, %d bytes(s)", addr, len); */
|
|
for (retry = 0; retry < 5; ++retry) {
|
|
ret = i2c_transfer(client->adapter, &msg, 1);
|
|
if (ret < 0)
|
|
continue;
|
|
memcpy(rxbuf, g_dma_buff_va, len);
|
|
return 0;
|
|
}
|
|
GSL_LOGE("Dma I2C Read Error: 0x%04X, %d byte(s), err-code: %d", addr,
|
|
len, ret);
|
|
return ret;
|
|
}
|
|
#else
|
|
/*read only mode, max read length is 65532bytes*/
|
|
static s32 i2c_dma_read(struct i2c_client *client, u8 addr, u8 *rxbuf, s32 len)
|
|
{
|
|
int ret;
|
|
s32 retry = 0;
|
|
struct i2c_msg msg[2];
|
|
|
|
if (rxbuf == NULL)
|
|
return -1;
|
|
memset(&msg, 0, sizeof(struct i2c_msg));
|
|
|
|
*g_dma_buff_va = addr;
|
|
msg[0].addr = client->addr & I2C_MASK_FLAG;
|
|
msg[0].flags = 0;
|
|
msg[0].len = GSLTP_REG_ADDR_LEN;
|
|
msg[0].buf = g_dma_buff_pa;
|
|
msg[0].ext_flag = I2C_DMA_FLAG;
|
|
msg[0].timing = GSLTP_I2C_MASTER_CLOCK;
|
|
|
|
msg[1].addr = client->addr & I2C_MASK_FLAG;
|
|
msg[1].flags = I2C_M_RD;
|
|
msg[1].len = GSLTP_DMA_MAX_RD_SIZE;
|
|
msg[1].buf = g_dma_buff_pa;
|
|
msg[1].ext_flag = client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG;
|
|
msg[1].timing = GSLTP_I2C_MASTER_CLOCK;
|
|
|
|
/* GSL_LOGD("dma i2c read: 0x%04X, %d bytes(s)", addr, len); */
|
|
for (retry = 0; retry < 5; ++retry) {
|
|
ret = i2c_transfer(client->adapter, &msg[0], 2);
|
|
if (ret < 0)
|
|
continue;
|
|
memcpy(rxbuf, g_dma_buff_va, len);
|
|
return 0;
|
|
}
|
|
GSL_LOGE("Dma I2C Read Error: 0x%04X, %d byte(s), err-code: %d", addr,
|
|
len, ret);
|
|
return ret;
|
|
}
|
|
#endif
|
|
static s32 i2c_dma_write(struct i2c_client *client, u8 addr, u8 *txbuf, s32 len)
|
|
{
|
|
int ret;
|
|
s32 retry = 0;
|
|
struct i2c_msg msg;
|
|
|
|
if (txbuf == NULL)
|
|
return -1;
|
|
|
|
memset(&msg, 0, sizeof(struct i2c_msg));
|
|
*g_dma_buff_va = addr;
|
|
|
|
msg.addr = (client->addr & I2C_MASK_FLAG);
|
|
msg.flags = 0;
|
|
msg.buf = g_dma_buff_pa;
|
|
msg.len = 1 + len;
|
|
msg.ext_flag = (client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG);
|
|
msg.timing = GSLTP_I2C_MASTER_CLOCK;
|
|
|
|
/* GSL_LOGD("dma i2c write: 0x%04X, %d bytes(s)", addr, len); */
|
|
memcpy(g_dma_buff_va + 1, txbuf, len);
|
|
for (retry = 0; retry < 5; ++retry) {
|
|
ret = i2c_transfer(client->adapter, &msg, 1);
|
|
if (ret < 0)
|
|
continue;
|
|
return 0;
|
|
}
|
|
GSL_LOGE("Dma I2C Write Error: 0x%04X, %d bytes, err-code: %d\n", addr,
|
|
len, ret);
|
|
return ret;
|
|
}
|
|
|
|
#else /*GSLTP_ENABLE_I2C_DMA*/
|
|
static s32 i2c_read_nondma(struct i2c_client *client, u8 addr, u8 *rxbuf,
|
|
int len)
|
|
{
|
|
int ret;
|
|
s32 retry = 0;
|
|
struct i2c_msg msg;
|
|
|
|
if (rxbuf == NULL)
|
|
return -1;
|
|
memset(&msg, 0, sizeof(struct i2c_msg));
|
|
|
|
rxbuf[0] = addr;
|
|
msg.addr = client->addr & I2C_MASK_FLAG;
|
|
msg.flags = 0;
|
|
msg.len = (len << 8) | GSLTP_REG_ADDR_LEN;
|
|
msg.buf = rxbuf;
|
|
msg.ext_flag = I2C_WR_FLAG | I2C_RS_FLAG;
|
|
msg.timing = GSLTP_I2C_MASTER_CLOCK;
|
|
|
|
/* GSL_LOGD("dma i2c read: 0x%04X, %d bytes(s)", addr, len); */
|
|
for (retry = 0; retry < 5; ++retry) {
|
|
ret = i2c_transfer(client->adapter, &msg, 1);
|
|
if (ret < 0)
|
|
continue;
|
|
return 0;
|
|
}
|
|
GSL_LOGE("Dma I2C Read Error: 0x%4X, %d bytes, err-code: %d\n", addr,
|
|
len, ret);
|
|
return ret;
|
|
}
|
|
|
|
static s32 i2c_write_nondma(struct i2c_client *client, u8 addr, u8 *txbuf,
|
|
int len)
|
|
{
|
|
int ret;
|
|
s32 retry = 0;
|
|
struct i2c_msg msg;
|
|
u8 wrBuf[C_I2C_FIFO_SIZE + 1];
|
|
|
|
if (txbuf == NULL)
|
|
return -1;
|
|
|
|
memset(&msg, 0, sizeof(struct i2c_msg));
|
|
memset(wrBuf, 0, C_I2C_FIFO_SIZE + 1);
|
|
wrBuf[0] = addr;
|
|
memcpy(wrBuf + 1, txbuf, len);
|
|
|
|
msg.flags = 0;
|
|
msg.buf = wrBuf;
|
|
msg.len = 1 + len;
|
|
msg.addr = (client->addr & I2C_MASK_FLAG);
|
|
msg.ext_flag = (client->ext_flag | I2C_ENEXT_FLAG);
|
|
msg.timing = GSLTP_I2C_MASTER_CLOCK;
|
|
|
|
/* GSL_LOGD("dma i2c write: 0x%04X, %d bytes(s)", addr, len); */
|
|
for (retry = 0; retry < 5; ++retry) {
|
|
ret = i2c_transfer(client->adapter, &msg, 1);
|
|
if (ret < 0)
|
|
continue;
|
|
return 0;
|
|
}
|
|
GSL_LOGE("Dma I2C Write Error: 0x%04X, %d bytes, err-code: %d\n", addr,
|
|
len, ret);
|
|
return ret;
|
|
}
|
|
#endif
|
|
#else /*CONFIG_MTK_I2C_EXTENSION*/
|
|
static int msg_dma_alloc(void)
|
|
{
|
|
g_i2c_buff = kzalloc(GSLTP_DMA_MAX_TRANSACTION_LEN, GFP_KERNEL);
|
|
if (!g_i2c_buff) {
|
|
GSL_LOGE("[DMA][Error] Allocate DMA I2C Buffer failed!\n");
|
|
return -1;
|
|
}
|
|
|
|
g_i2c_addr = kzalloc(GSLTP_REG_ADDR_LEN, GFP_KERNEL);
|
|
if (!g_i2c_addr) {
|
|
GSL_LOGE("[DMA]Allocate DMA I2C addr buf failed!\n");
|
|
kfree(g_i2c_buff);
|
|
g_i2c_buff = NULL;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void msg_dma_release(void)
|
|
{
|
|
kfree(g_i2c_buff);
|
|
g_i2c_buff = NULL;
|
|
|
|
kfree(g_i2c_addr);
|
|
g_i2c_addr = NULL;
|
|
|
|
GSL_LOGD("[DMA][release]I2C Buffer release!\n");
|
|
}
|
|
static s32 i2c_dma_read(struct i2c_client *client, u8 addr, u8 *rxbuf, int len)
|
|
{
|
|
int ret;
|
|
s32 retry = 0;
|
|
struct i2c_msg msg[2];
|
|
|
|
if (rxbuf == NULL)
|
|
return -1;
|
|
|
|
memset(&msg, 0, 2 * sizeof(struct i2c_msg));
|
|
memcpy(g_i2c_addr, &addr, GSLTP_REG_ADDR_LEN);
|
|
msg[0].addr = client->addr;
|
|
msg[0].flags = 0;
|
|
msg[0].buf = g_i2c_addr;
|
|
msg[0].len = 1;
|
|
|
|
msg[1].addr = client->addr;
|
|
msg[1].flags = I2C_M_RD;
|
|
msg[1].buf = g_i2c_buff;
|
|
msg[1].len = len;
|
|
|
|
/* GSL_LOGD("dma i2c read: 0x%04X, %d bytes(s)", addr, len); */
|
|
for (retry = 0; retry < 5; ++retry) {
|
|
ret = i2c_transfer(client->adapter, &msg[0], 2);
|
|
if (ret < 0)
|
|
continue;
|
|
memcpy(rxbuf, g_i2c_buff, len);
|
|
return 0;
|
|
}
|
|
GSL_LOGE("Dma I2C Read Error: 0x%4X, %d bytes, err-code: %d\n", addr,
|
|
len, ret);
|
|
return ret;
|
|
}
|
|
|
|
static s32 i2c_dma_write(struct i2c_client *client, u8 addr, u8 *txbuf, s32 len)
|
|
{
|
|
int ret;
|
|
s32 retry = 0;
|
|
struct i2c_msg msg;
|
|
|
|
if (txbuf == NULL)
|
|
return -1;
|
|
|
|
memset(&msg, 0, sizeof(struct i2c_msg));
|
|
*g_i2c_buff = addr;
|
|
|
|
msg.addr = (client->addr);
|
|
msg.flags = 0;
|
|
msg.buf = g_i2c_buff;
|
|
msg.len = 1 + len;
|
|
|
|
/* GSL_LOGD("dma i2c write: 0x%04X, %d bytes(s)", addr, len); */
|
|
memcpy(g_i2c_buff + 1, txbuf, len);
|
|
for (retry = 0; retry < 5; ++retry) {
|
|
ret = i2c_transfer(client->adapter, &msg, 1);
|
|
if (ret < 0)
|
|
continue;
|
|
return 0;
|
|
}
|
|
GSL_LOGE("Dma I2C Write Error: 0x%04X, %d bytes, err-code: %d\n", addr,
|
|
len, ret);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static int gsl_i2c_read_bytes(struct i2c_client *client, u8 addr, u8 *rxbuf,
|
|
int len)
|
|
{
|
|
int left = len;
|
|
int readLen = 0;
|
|
u8 *rd_buf = rxbuf;
|
|
int ret = 0;
|
|
|
|
/* GSL_LOGD("Read bytes dma: 0x%04X, %d byte(s)", addr, len); */
|
|
while (left > 0) {
|
|
#if !defined(CONFIG_MTK_I2C_EXTENSION) || defined(GSLTP_ENABLE_I2C_DMA)
|
|
readLen = left > GSLTP_DMA_MAX_RD_SIZE ? GSLTP_DMA_MAX_RD_SIZE
|
|
: left;
|
|
ret = i2c_dma_read(client, addr, rd_buf, readLen);
|
|
#else
|
|
readLen = left > C_I2C_FIFO_SIZE ? C_I2C_FIFO_SIZE : left;
|
|
ret = i2c_read_nondma(client, addr, rd_buf, readLen);
|
|
#endif
|
|
|
|
if (ret < 0) {
|
|
GSL_LOGE("dma read failed!\n");
|
|
return -1;
|
|
}
|
|
|
|
left -= readLen;
|
|
if (left > 0) {
|
|
addr += readLen;
|
|
rd_buf += readLen;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static s32 gsl_i2c_write_bytes(struct i2c_client *client, u8 addr, u8 *txbuf,
|
|
int len)
|
|
{
|
|
|
|
int ret = 0;
|
|
int write_len = 0;
|
|
int left = len;
|
|
u8 *wr_buf = txbuf;
|
|
u8 offset = 0;
|
|
u8 wrAddr = addr;
|
|
|
|
/* GSL_LOGD("Write bytes dma: 0x%04X, %d byte(s)", addr, len); */
|
|
while (left > 0) {
|
|
#if !defined(CONFIG_MTK_I2C_EXTENSION) || defined(GSLTP_ENABLE_I2C_DMA)
|
|
write_len = left > GSLTP_DMA_MAX_WR_SIZE ? GSLTP_DMA_MAX_WR_SIZE
|
|
: left;
|
|
ret = i2c_dma_write(client, wrAddr, wr_buf, write_len);
|
|
#else
|
|
write_len = left > C_I2C_FIFO_SIZE ? C_I2C_FIFO_SIZE : left;
|
|
ret = i2c_write_nondma(client, wrAddr, wr_buf, write_len);
|
|
#endif
|
|
|
|
if (ret < 0) {
|
|
GSL_LOGE("dma i2c write failed!\n");
|
|
return -1;
|
|
}
|
|
offset += write_len;
|
|
left -= write_len;
|
|
if (left > 0) {
|
|
wrAddr = addr + offset;
|
|
wr_buf = txbuf + offset;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void startup_chip(struct i2c_client *client)
|
|
{
|
|
u8 write_buf = 0x00;
|
|
|
|
gsl_i2c_write_bytes(client, 0xe0, &write_buf, 1);
|
|
#ifdef GSL_NOID_VERSION
|
|
gsl_DataInit(gsl_config_data_id);
|
|
#endif
|
|
|
|
usleep_range(10000, 11000);
|
|
}
|
|
|
|
#ifdef GSL9XX_CHIP
|
|
static void gsl_io_control(struct i2c_client *client)
|
|
{
|
|
u8 buf[4] = {0};
|
|
int i;
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
buf[0] = 0;
|
|
buf[1] = 0;
|
|
buf[2] = 0xfe;
|
|
buf[3] = 0x1;
|
|
gsl_i2c_write_bytes(client, 0xf0, buf, 4);
|
|
buf[0] = 0x5;
|
|
buf[1] = 0;
|
|
buf[2] = 0;
|
|
buf[3] = 0x80;
|
|
gsl_i2c_write_bytes(client, 0x78, buf, 4);
|
|
usleep_range(5000, 5100);
|
|
}
|
|
msleep(50);
|
|
}
|
|
#endif
|
|
|
|
static int reset_chip(struct i2c_client *client)
|
|
{
|
|
u8 write_buf[4] = {0};
|
|
int ret = 0;
|
|
|
|
write_buf[0] = 0x88;
|
|
ret = gsl_i2c_write_bytes(client, 0xe0, &write_buf[0], 1);
|
|
msleep(20);
|
|
|
|
write_buf[0] = 0x04;
|
|
ret += gsl_i2c_write_bytes(client, 0xe4, &write_buf[0], 1);
|
|
usleep_range(10000, 11000);
|
|
|
|
write_buf[0] = 0x00;
|
|
write_buf[1] = 0x00;
|
|
write_buf[2] = 0x00;
|
|
write_buf[3] = 0x00;
|
|
ret += gsl_i2c_write_bytes(client, 0xbc, write_buf, 4);
|
|
usleep_range(10000, 11000);
|
|
#ifdef GSL9XX_CHIP
|
|
gsl_io_control(client);
|
|
#endif
|
|
|
|
if (ret < 0)
|
|
GSL_LOGE("reset chip fail!\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void clr_reg(struct i2c_client *client)
|
|
{
|
|
u8 write_buf[4] = {0};
|
|
|
|
write_buf[0] = 0x88;
|
|
gsl_i2c_write_bytes(client, 0xe0, &write_buf[0], 1);
|
|
msleep(20);
|
|
|
|
write_buf[0] = 0x03;
|
|
gsl_i2c_write_bytes(client, 0x80, &write_buf[0], 1);
|
|
usleep_range(5000, 5100);
|
|
|
|
write_buf[0] = 0x04;
|
|
gsl_i2c_write_bytes(client, 0xe4, &write_buf[0], 1);
|
|
usleep_range(5000, 5100);
|
|
|
|
write_buf[0] = 0x00;
|
|
gsl_i2c_write_bytes(client, 0xe0, &write_buf[0], 1);
|
|
msleep(20);
|
|
}
|
|
|
|
#ifdef HIGH_SPEED_I2C
|
|
static u32 gsl_read_interface(struct i2c_client *client, u8 reg, u8 *buf,
|
|
u32 num)
|
|
{
|
|
struct i2c_msg xfer_msg[2];
|
|
|
|
xfer_msg[0].addr = client->addr;
|
|
xfer_msg[0].len = 1;
|
|
xfer_msg[0].flags = client->flags & I2C_M_TEN;
|
|
xfer_msg[0].buf = ®
|
|
xfer_msg[0].timing = 400;
|
|
|
|
xfer_msg[1].addr = client->addr;
|
|
xfer_msg[1].len = num;
|
|
xfer_msg[1].flags |= I2C_M_RD;
|
|
xfer_msg[1].buf = buf;
|
|
xfer_msg[1].timing = 400;
|
|
|
|
if (reg < 0x80) {
|
|
i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg));
|
|
usleep_range(5000, 5100);
|
|
}
|
|
|
|
return i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg)) ==
|
|
ARRAY_SIZE(xfer_msg)
|
|
? 0
|
|
: -EFAULT;
|
|
}
|
|
|
|
static u32 gsl_write_interface(struct i2c_client *client, const u8 reg, u8 *buf,
|
|
u32 num)
|
|
{
|
|
struct i2c_msg xfer_msg[1];
|
|
|
|
buf[0] = reg;
|
|
|
|
xfer_msg[0].addr = client->addr;
|
|
xfer_msg[0].len = num + 1;
|
|
xfer_msg[0].flags = client->flags & I2C_M_TEN;
|
|
xfer_msg[0].buf = buf;
|
|
xfer_msg[0].timing = 400;
|
|
|
|
return i2c_transfer(client->adapter, xfer_msg, 1) == 1 ? 0 : -EFAULT;
|
|
}
|
|
|
|
static inline void fw2buf(u8 *buf, const u32 *fw)
|
|
{
|
|
u32 *u32_buf = (int *)buf;
|
|
*u32_buf = *fw;
|
|
}
|
|
|
|
static void gsl_load_fw(struct i2c_client *client)
|
|
{
|
|
u8 buf[DMA_TRANS_LEN * 4 + 1] = {0};
|
|
u8 send_flag = 1;
|
|
u8 *cur = buf + 1;
|
|
u32 source_line = 0;
|
|
u32 source_len;
|
|
struct fw_data *ptr_fw;
|
|
|
|
GSL_LOGD("===gsl load_fw start===\n");
|
|
|
|
ptr_fw = GSLX680_FW;
|
|
source_len = ARRAY_SIZE(GSLX680_FW);
|
|
for (source_line = 0; source_line < source_len; source_line++) {
|
|
/* init page trans, set the page val */
|
|
if (ptr_fw[source_line].offset == GSL_PAGE_REG) {
|
|
fw2buf(cur, &ptr_fw[source_line].val);
|
|
gsl_write_interface(client, GSL_PAGE_REG, buf, 4);
|
|
send_flag = 1;
|
|
} else {
|
|
if (send_flag ==
|
|
1 % (DMA_TRANS_LEN < 0x20 ? DMA_TRANS_LEN : 0x20))
|
|
buf[0] = (u8)ptr_fw[source_line].offset;
|
|
|
|
fw2buf(cur, &ptr_fw[source_line].val);
|
|
cur += 4;
|
|
|
|
if (send_flag ==
|
|
0 % (DMA_TRANS_LEN < 0x20 ? DMA_TRANS_LEN : 0x20)) {
|
|
gsl_write_interface(client, buf[0], buf,
|
|
cur - buf - 1);
|
|
cur = buf + 1;
|
|
}
|
|
|
|
send_flag++;
|
|
}
|
|
}
|
|
|
|
GSL_LOGD("===gsl load_fw end===\n");
|
|
}
|
|
#else
|
|
static void gsl_load_fw(struct i2c_client *client)
|
|
{
|
|
u8 buf[SMBUS_TRANS_LEN * 4] = {0};
|
|
u8 reg = 0, send_flag = 1, cur = 0;
|
|
|
|
unsigned int source_line = 0;
|
|
unsigned int source_len = ARRAY_SIZE(GSLX680_FW);
|
|
|
|
GSL_LOGD("===gsl load_fw start===\n");
|
|
for (source_line = 0; source_line < source_len; source_line++) {
|
|
if (1 == SMBUS_TRANS_LEN) {
|
|
reg = GSLX680_FW[source_line].offset;
|
|
memcpy(&buf[0], &GSLX680_FW[source_line].val, 4);
|
|
gsl_i2c_write_bytes(client, reg, buf, 4);
|
|
} else {
|
|
/* init page trans, set the page val */
|
|
if (GSLX680_FW[source_line].offset == GSL_PAGE_REG) {
|
|
buf[0] = (u8)(GSLX680_FW[source_line].val &
|
|
0x000000ff);
|
|
gsl_i2c_write_bytes(client, GSL_PAGE_REG,
|
|
&buf[0], 1);
|
|
send_flag = 1;
|
|
} else {
|
|
if (send_flag ==
|
|
1 % (SMBUS_TRANS_LEN < 0x08
|
|
? SMBUS_TRANS_LEN
|
|
: 0x08))
|
|
reg = GSLX680_FW[source_line].offset;
|
|
|
|
memcpy(&buf[cur], &GSLX680_FW[source_line].val,
|
|
4);
|
|
cur += 4;
|
|
|
|
if (send_flag ==
|
|
0 % (SMBUS_TRANS_LEN < 0x08
|
|
? SMBUS_TRANS_LEN
|
|
: 0x08)) {
|
|
gsl_i2c_write_bytes(client, reg, buf,
|
|
SMBUS_TRANS_LEN *
|
|
4);
|
|
cur = 0;
|
|
}
|
|
|
|
send_flag++;
|
|
}
|
|
}
|
|
}
|
|
|
|
GSL_LOGD("===gsl load_fw end===\n");
|
|
}
|
|
#endif
|
|
|
|
/* ----------------------check_memdata start-------------*/
|
|
static int arry_compare(u8 *arry_1st, u8 *arry_2nd, int num)
|
|
{
|
|
int i;
|
|
int result = 0;
|
|
|
|
for (i = 0; i < num; i++) {
|
|
if (*(arry_1st + i) != *(arry_2nd + i))
|
|
result++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static int arry_copy(u8 *arry_new, u8 *arry_old, int num)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < num; i++)
|
|
*(arry_new + i) = *(arry_old + i);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int power_check(struct i2c_client *client)
|
|
{
|
|
int result = 0;
|
|
u8 read_buf[4] = {0x00};
|
|
|
|
gsl_i2c_read_bytes(client, 0xb0, read_buf, sizeof(read_buf));
|
|
if (read_buf[3] != 0x5a || read_buf[2] != 0x5a || read_buf[1] != 0x5a ||
|
|
read_buf[0] != 0x5a)
|
|
result = power_shutdowned;
|
|
|
|
return result;
|
|
}
|
|
|
|
static int interrupt_check(struct i2c_client *client)
|
|
{
|
|
int i, num;
|
|
int result = 0;
|
|
u8 read_buf[4] = {0x00};
|
|
u8 arry_1st[4] = {0x00};
|
|
u8 arry_2nd[4] = {0x00};
|
|
|
|
num = sizeof(read_buf);
|
|
for (i = 0; i < (num * num); i++) {
|
|
gsl_i2c_read_bytes(client, 0xb4, read_buf, num);
|
|
usleep_range(10000, 11000);
|
|
if (!(i % num))
|
|
arry_copy(arry_1st, read_buf, num);
|
|
else
|
|
arry_copy(arry_2nd, read_buf, num);
|
|
}
|
|
result = arry_compare(arry_1st, arry_2nd, num);
|
|
if (result)
|
|
result = interrupt_status;
|
|
return result;
|
|
}
|
|
|
|
static int esd_check(struct i2c_client *client)
|
|
{
|
|
int result = 0;
|
|
u8 read_buf[4] = {0x00};
|
|
|
|
gsl_i2c_read_bytes(client, 0xbc, read_buf, sizeof(read_buf));
|
|
if (read_buf[3] != 0x00 || read_buf[2] != 0x00 || read_buf[1] != 0x00 ||
|
|
read_buf[0] != 0x00)
|
|
result = esd_protected;
|
|
return result;
|
|
}
|
|
|
|
static int check_mode(struct i2c_client *client, int mode_set)
|
|
{
|
|
int result = 0;
|
|
|
|
switch (mode_set) {
|
|
case power_status:
|
|
result = power_check(client);
|
|
break;
|
|
case interrupt_status:
|
|
result = interrupt_check(client);
|
|
break;
|
|
case esd_scanning:
|
|
result = esd_check(client);
|
|
break;
|
|
case (power_status + interrupt_status):
|
|
result = power_check(client);
|
|
result += interrupt_check(client);
|
|
break;
|
|
case (power_status + esd_scanning):
|
|
result = power_check(client);
|
|
result += esd_check(client);
|
|
break;
|
|
case (interrupt_status + esd_scanning):
|
|
result = interrupt_check(client);
|
|
result += esd_check(client);
|
|
break;
|
|
case (power_status + interrupt_status + esd_scanning):
|
|
result = power_check(client);
|
|
result += interrupt_check(client);
|
|
result += esd_check(client);
|
|
break;
|
|
default:
|
|
result = mode_set;
|
|
GSL_LOGE("mode_set[%d] not valid!\n", mode_set);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static int check_mem_data(struct i2c_client *client)
|
|
{
|
|
int result = 0;
|
|
|
|
result = check_mode(client, power_status);
|
|
GSL_LOGD("---result num is[%d] ", result);
|
|
GSL_LOGD("power_shutdowned[%d]\n", power_shutdowned);
|
|
if (result)
|
|
result = init_chip(client);
|
|
|
|
return result;
|
|
}
|
|
/* ----------------------check_memdata end-------------*/
|
|
|
|
static int test_i2c(struct i2c_client *client)
|
|
{
|
|
u8 read_buf[4] = {0x00};
|
|
u8 write_buf[4] = {0x00, 0x03, 0x02, 0x01};
|
|
int result = 0;
|
|
|
|
result = gsl_i2c_read_bytes(client, 0xf0, read_buf, sizeof(read_buf));
|
|
GSL_LOGD("gslX680 I read reg 0xf0 is %02x%02x%02x\n", read_buf[2],
|
|
read_buf[1], read_buf[0]);
|
|
|
|
usleep_range(2000, 2100);
|
|
result +=
|
|
gsl_i2c_write_bytes(client, 0xf0, write_buf, sizeof(write_buf));
|
|
|
|
GSL_LOGD("gslX680 I write reg 0xf0 is %02x%02x%02x\n", write_buf[2],
|
|
write_buf[1], write_buf[0]);
|
|
|
|
usleep_range(2000, 2100);
|
|
result += gsl_i2c_read_bytes(client, 0xf0, read_buf, sizeof(read_buf));
|
|
GSL_LOGD("gslX680 I read reg 0xf0 is %02x%02x%02x\n", read_buf[2],
|
|
read_buf[1], read_buf[0]);
|
|
|
|
if (arry_compare(write_buf, read_buf, 3))
|
|
result--;
|
|
return result;
|
|
}
|
|
static int init_chip(struct i2c_client *client)
|
|
{
|
|
int rc;
|
|
|
|
#ifdef GSL_MONITOR
|
|
i2c_lock_flag = 2;
|
|
#endif
|
|
tpd_gpio_output(GTP_RST_PORT, 0);
|
|
msleep(20);
|
|
tpd_gpio_output(GTP_RST_PORT, 1);
|
|
msleep(20);
|
|
|
|
rc = test_i2c(client);
|
|
if (rc < 0) {
|
|
GSL_LOGE("------gslX680 test_i2c error------\n");
|
|
return -1;
|
|
}
|
|
clr_reg(client);
|
|
reset_chip(client);
|
|
clr_reg(client);
|
|
rc = reset_chip(client);
|
|
gsl_load_fw(client);
|
|
startup_chip(client);
|
|
rc += reset_chip(client);
|
|
startup_chip(client);
|
|
#ifdef GSL_MONITOR
|
|
i2c_lock_flag = 0;
|
|
#endif
|
|
return rc;
|
|
}
|
|
|
|
#ifdef TPD_PROC_DEBUG
|
|
static int char_to_int(char ch)
|
|
{
|
|
if (ch >= '0' && ch <= '9')
|
|
return (ch - '0');
|
|
else
|
|
return (ch - 'a' + 10);
|
|
}
|
|
|
|
|
|
static int gsl_config_read_proc(struct seq_file *m, void *v)
|
|
{
|
|
char temp_data[5] = {0};
|
|
unsigned int tmp = 0;
|
|
|
|
if ('v' == gsl_read[0] && 's' == gsl_read[1]) {
|
|
#ifdef GSL_NOID_VERSION
|
|
tmp = gsl_version_id();
|
|
#else
|
|
tmp = 0x20121215;
|
|
#endif
|
|
seq_printf(m, "version:%x\n", tmp);
|
|
} else if ('r' == gsl_read[0] && 'e' == gsl_read[1]) {
|
|
if ('i' == gsl_read[3]) {
|
|
#ifdef GSL_NOID_VERSION
|
|
tmp = (gsl_data_proc[5] << 8) | gsl_data_proc[4];
|
|
seq_printf(m, "gsl_config_data_id[%d] = ", tmp);
|
|
if (tmp >= 0 && tmp < ARRAY_SIZE(gsl_config_data_id))
|
|
seq_printf(m, "%d\n", gsl_config_data_id[tmp]);
|
|
#endif
|
|
} else {
|
|
gsl_i2c_write_bytes(i2c_client, 0Xf0, &gsl_data_proc[4],
|
|
4);
|
|
if (gsl_data_proc[0] < 0x80)
|
|
gsl_i2c_read_bytes(i2c_client, gsl_data_proc[0],
|
|
temp_data, 4);
|
|
gsl_i2c_read_bytes(i2c_client, gsl_data_proc[0],
|
|
temp_data, 4);
|
|
seq_printf(m, "offset : {0x%02x,0x", gsl_data_proc[0]);
|
|
seq_printf(m, "%02x", temp_data[3]);
|
|
seq_printf(m, "%02x", temp_data[2]);
|
|
seq_printf(m, "%02x", temp_data[1]);
|
|
seq_printf(m, "%02x};\n", temp_data[0]);
|
|
}
|
|
}
|
|
/* *eof = 1; */
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t gsl_config_write_proc(struct file *file,
|
|
const char __user *buffer, size_t count,
|
|
loff_t *data)
|
|
{
|
|
u8 buf[8] = {0};
|
|
char temp_buf[CONFIG_LEN];
|
|
char *path_buf;
|
|
#ifdef GSL_NOID_VERSION
|
|
int tmp = 0;
|
|
int tmp1 = 0;
|
|
#endif
|
|
|
|
GSL_LOGD("[tp-gsl]\n");
|
|
if (count > 512) {
|
|
GSL_LOGE("size not match [%d:%d]\n", CONFIG_LEN, (int)count);
|
|
return -EFAULT;
|
|
}
|
|
path_buf = kzalloc(count, GFP_KERNEL);
|
|
if (!path_buf) {
|
|
GSL_LOGE("alloc path_buf memory error\n");
|
|
return -1;
|
|
}
|
|
if (copy_from_user(path_buf, buffer, count)) {
|
|
GSL_LOGE("copy from user fail\n");
|
|
goto exit_write_proc_out;
|
|
}
|
|
memcpy(temp_buf, path_buf, (count < CONFIG_LEN ? count : CONFIG_LEN));
|
|
GSL_LOGD("[tp-gsl][%s][%s]\n", __func__, temp_buf);
|
|
|
|
buf[3] = char_to_int(temp_buf[14]) << 4 | char_to_int(temp_buf[15]);
|
|
buf[2] = char_to_int(temp_buf[16]) << 4 | char_to_int(temp_buf[17]);
|
|
buf[1] = char_to_int(temp_buf[18]) << 4 | char_to_int(temp_buf[19]);
|
|
buf[0] = char_to_int(temp_buf[20]) << 4 | char_to_int(temp_buf[21]);
|
|
|
|
buf[7] = char_to_int(temp_buf[5]) << 4 | char_to_int(temp_buf[6]);
|
|
buf[6] = char_to_int(temp_buf[7]) << 4 | char_to_int(temp_buf[8]);
|
|
buf[5] = char_to_int(temp_buf[9]) << 4 | char_to_int(temp_buf[10]);
|
|
buf[4] = char_to_int(temp_buf[11]) << 4 | char_to_int(temp_buf[12]);
|
|
if ('v' == temp_buf[0] && 's' == temp_buf[1]) {
|
|
memcpy(gsl_read, temp_buf, 4);
|
|
GSL_LOGD("gsl version\n");
|
|
} else if ('s' == temp_buf[0] && 't' == temp_buf[1]) {
|
|
#ifdef GSL_MONITOR
|
|
cancel_delayed_work_sync(&gsl_monitor_work);
|
|
i2c_lock_flag = 2;
|
|
#endif
|
|
gsl_proc_flag = 1;
|
|
reset_chip(i2c_client);
|
|
} else if ('e' == temp_buf[0] && 'n' == temp_buf[1]) {
|
|
msleep(20);
|
|
reset_chip(i2c_client);
|
|
startup_chip(i2c_client);
|
|
gsl_proc_flag = 0;
|
|
} else if ('r' == temp_buf[0] && 'e' == temp_buf[1]) {
|
|
memcpy(gsl_read, temp_buf, 4);
|
|
memcpy(gsl_data_proc, buf, 8);
|
|
} else if ('w' == temp_buf[0] && 'r' == temp_buf[1]) {
|
|
gsl_i2c_write_bytes(i2c_client, buf[4], buf, 4);
|
|
}
|
|
#ifdef GSL_NOID_VERSION
|
|
else if ('i' == temp_buf[0] && 'd' == temp_buf[1]) {
|
|
tmp1 = (buf[7] << 24) | (buf[6] << 16) | (buf[5] << 8) | buf[4];
|
|
tmp = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
|
if (tmp1 >= 0 && tmp1 < ARRAY_SIZE(gsl_config_data_id))
|
|
gsl_config_data_id[tmp1] = tmp;
|
|
}
|
|
#endif
|
|
exit_write_proc_out:
|
|
kfree(path_buf);
|
|
return count;
|
|
}
|
|
static int gsl_server_list_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, gsl_config_read_proc, NULL);
|
|
}
|
|
static const struct file_operations gsl_seq_fops = {
|
|
.open = gsl_server_list_open,
|
|
.read = seq_read,
|
|
.release = single_release,
|
|
.write = gsl_config_write_proc,
|
|
.owner = THIS_MODULE,
|
|
};
|
|
#endif
|
|
|
|
#ifdef TPD_ROTATION_SUPPORT
|
|
static void tpd_swap_xy(int *x, int *y)
|
|
{
|
|
int temp = 0;
|
|
|
|
temp = *x;
|
|
*x = *y;
|
|
*y = temp;
|
|
}
|
|
|
|
static void tpd_rotate_90(int *x, int *y)
|
|
{
|
|
*x = SCREEN_MAX_X + 1 - *x;
|
|
|
|
*x = (*x * SCREEN_MAX_Y) / SCREEN_MAX_X;
|
|
*y = (*y * SCREEN_MAX_X) / SCREEN_MAX_Y;
|
|
|
|
tpd_swap_xy(x, y);
|
|
}
|
|
static void tpd_rotate_180(int *x, int *y)
|
|
{
|
|
*y = SCREEN_MAX_Y + 1 - *y;
|
|
*x = SCREEN_MAX_X + 1 - *x;
|
|
}
|
|
static void tpd_rotate_270(int *x, int *y)
|
|
{
|
|
*y = SCREEN_MAX_Y + 1 - *y;
|
|
|
|
*x = (*x * SCREEN_MAX_Y) / SCREEN_MAX_X;
|
|
*y = (*y * SCREEN_MAX_X) / SCREEN_MAX_Y;
|
|
|
|
tpd_swap_xy(x, y);
|
|
}
|
|
#endif
|
|
|
|
u8 rs_value1;
|
|
static void tpd_down(int id, int x, int y, int p)
|
|
{
|
|
GSL_LOGD("----tpd_down id: %d, x:%d, y:%d----\n", id, x, y);
|
|
|
|
#ifdef TPD_ROTATION_SUPPORT
|
|
switch (tpd_rotation_type) {
|
|
case TPD_ROTATION_90:
|
|
tpd_rotate_90(&x, &y);
|
|
break;
|
|
case TPD_ROTATION_270:
|
|
tpd_rotate_270(&x, &y);
|
|
break;
|
|
case TPD_ROTATION_180:
|
|
tpd_rotate_180(&x, &y);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
input_report_key(tpd->dev, BTN_TOUCH, 1);
|
|
input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, 1);
|
|
input_report_abs(tpd->dev, ABS_MT_POSITION_X, x);
|
|
input_report_abs(tpd->dev, ABS_MT_POSITION_Y, y);
|
|
input_report_abs(tpd->dev, ABS_MT_TRACKING_ID, id);
|
|
input_mt_sync(tpd->dev);
|
|
}
|
|
|
|
static void tpd_up(void)
|
|
{
|
|
GSL_LOGD("------tpd_up------\n");
|
|
|
|
input_report_key(tpd->dev, BTN_TOUCH, 0);
|
|
input_mt_sync(tpd->dev);
|
|
}
|
|
static void gsl_report_point(struct gsl_touch_info *ti)
|
|
{
|
|
int tmp = 0;
|
|
static int gsl_up_flag; /*prevent more up event*/
|
|
|
|
GSL_LOGD("gsl report_point %d\n", ti->finger_num);
|
|
if (unlikely(ti->finger_num == 0)) {
|
|
if (gsl_up_flag == 0)
|
|
return;
|
|
gsl_up_flag = 0;
|
|
tpd_up();
|
|
|
|
if ((get_boot_mode() == FACTORY_BOOT) ||
|
|
(get_boot_mode() == RECOVERY_BOOT))
|
|
tpd_button(ti->x[tmp], ti->y[tmp], 0);
|
|
|
|
} else {
|
|
gsl_up_flag = 1;
|
|
for (tmp = 0; ti->finger_num > tmp; tmp++) {
|
|
|
|
|
|
tpd_down(ti->id[tmp] - 1, ti->x[tmp], ti->y[tmp], 0);
|
|
if ((get_boot_mode() == FACTORY_BOOT) ||
|
|
(get_boot_mode() == RECOVERY_BOOT))
|
|
tpd_button(ti->x[tmp], ti->y[tmp], 1);
|
|
}
|
|
}
|
|
input_sync(tpd->dev);
|
|
}
|
|
|
|
static void report_data_handle(void)
|
|
{
|
|
u8 touch_data[44] = {0};
|
|
unsigned char point_num = 0;
|
|
unsigned int temp_a, temp_b, i;
|
|
|
|
#ifdef GSL_NOID_VERSION
|
|
u8 buf[4] = {0};
|
|
struct gsl_touch_info cinfo = {{0} };
|
|
int tmp1 = 0;
|
|
#endif
|
|
|
|
#ifdef GSL_MONITOR
|
|
if (i2c_lock_flag != 0)
|
|
return;
|
|
|
|
i2c_lock_flag = 1;
|
|
#endif
|
|
|
|
#ifdef TPD_PROC_DEBUG
|
|
if (gsl_proc_flag == 1)
|
|
return;
|
|
#endif
|
|
|
|
gsl_i2c_read_bytes(i2c_client, 0x80, &touch_data[0], 4);
|
|
point_num = touch_data[0];
|
|
if (point_num > 0)
|
|
gsl_i2c_read_bytes(i2c_client, 0x84, &touch_data[4], 4);
|
|
if (point_num > 1)
|
|
gsl_i2c_read_bytes(i2c_client, 0x88, &touch_data[8], 4);
|
|
if (point_num > 2)
|
|
gsl_i2c_read_bytes(i2c_client, 0x8c, &touch_data[12], 4);
|
|
if (point_num > 3)
|
|
gsl_i2c_read_bytes(i2c_client, 0x90, &touch_data[16], 4);
|
|
if (point_num > 4)
|
|
gsl_i2c_read_bytes(i2c_client, 0x94, &touch_data[20], 4);
|
|
if (point_num > 5)
|
|
gsl_i2c_read_bytes(i2c_client, 0x98, &touch_data[24], 4);
|
|
if (point_num > 6)
|
|
gsl_i2c_read_bytes(i2c_client, 0x9c, &touch_data[28], 4);
|
|
if (point_num > 7)
|
|
gsl_i2c_read_bytes(i2c_client, 0xa0, &touch_data[32], 4);
|
|
if (point_num > 8)
|
|
gsl_i2c_read_bytes(i2c_client, 0xa4, &touch_data[36], 4);
|
|
if (point_num > 9)
|
|
gsl_i2c_read_bytes(i2c_client, 0xa8, &touch_data[40], 4);
|
|
|
|
#ifdef GSL_NOID_VERSION
|
|
cinfo.finger_num = point_num;
|
|
GSL_LOGD("tp-gsl finger_num = %d\n", cinfo.finger_num);
|
|
for (i = 0; i < (point_num < MAX_CONTACTS ? point_num : MAX_CONTACTS);
|
|
i++) {
|
|
temp_a = touch_data[(i + 1) * 4 + 3] & 0x0f;
|
|
temp_b = touch_data[(i + 1) * 4 + 2];
|
|
cinfo.x[i] = temp_a << 8 | temp_b;
|
|
temp_a = touch_data[(i + 1) * 4 + 1];
|
|
temp_b = touch_data[(i + 1) * 4 + 0];
|
|
cinfo.y[i] = temp_a << 8 | temp_b;
|
|
cinfo.id[i] = ((touch_data[(i + 1) * 4 + 3] & 0xf0) >> 4);
|
|
GSL_LOGD(
|
|
"tp-gsl before: x[%d] = %d, y[%d] = %d, id[%d] = %d\n",
|
|
i, cinfo.x[i], i, cinfo.y[i], i, cinfo.id[i]);
|
|
}
|
|
cinfo.finger_num = (touch_data[3] << 24) | (touch_data[2] << 16) |
|
|
(touch_data[1] << 8) | touch_data[0];
|
|
gsl_alg_id_main(&cinfo);
|
|
tmp1 = gsl_mask_tiaoping();
|
|
GSL_LOGD("[tp-gsl] tmp1=%x\n", tmp1);
|
|
if (tmp1 > 0 && tmp1 < 0xffffffff) {
|
|
buf[0] = 0xa;
|
|
buf[1] = 0;
|
|
buf[2] = 0;
|
|
buf[3] = 0;
|
|
gsl_i2c_write_bytes(i2c_client, 0xf0, buf, 4);
|
|
buf[0] = (u8)(tmp1 & 0xff);
|
|
buf[1] = (u8)((tmp1 >> 8) & 0xff);
|
|
buf[2] = (u8)((tmp1 >> 16) & 0xff);
|
|
buf[3] = (u8)((tmp1 >> 24) & 0xff);
|
|
GSL_LOGD(
|
|
"tmp1=%08x,buf[0]=%02x,buf[1]=%02x,buf[2]=%02x,buf[3]=%02x\n",
|
|
tmp1, buf[0], buf[1], buf[2], buf[3]);
|
|
gsl_i2c_write_bytes(i2c_client, 0x8, buf, 4);
|
|
}
|
|
point_num = cinfo.finger_num;
|
|
#endif
|
|
gsl_report_point(&cinfo);
|
|
#ifdef GSL_MONITOR
|
|
i2c_lock_flag = 0;
|
|
#endif
|
|
}
|
|
|
|
#ifdef GSL_MONITOR
|
|
static void gsl_monitor_worker(struct work_struct *work)
|
|
{
|
|
int result = 0;
|
|
int mon_work_cycle = MONITOR_CYCLE_NORMAL;
|
|
|
|
GSL_LOGD("---------gsl monitor_worker-------\n");
|
|
#ifdef TPD_PROC_DEBUG
|
|
if (gsl_proc_flag == 1)
|
|
return;
|
|
#endif
|
|
if (i2c_lock_flag == 0) {
|
|
result = check_mode(
|
|
i2c_client,
|
|
(power_status + interrupt_status + esd_scanning));
|
|
if (result)
|
|
init_chip(client);
|
|
GSL_LOGD("---result num is[%d] ", result);
|
|
GSL_LOGD("power_shutdowned[%d]", power_shutdowned);
|
|
GSL_LOGD("interrupt_fail[%d] ", interrupt_fail);
|
|
GSL_LOGD("esd_protected[%d]\n", esd_protected);
|
|
} else if (i2c_lock_flag == 1) {
|
|
mon_work_cycle = MONITOR_CYCLE_IDLE;
|
|
i2c_lock_flag = 0;
|
|
} else if (i2c_lock_flag == 2) {
|
|
mon_work_cycle = MONITOR_CYCLE_BY_REG_CHECK;
|
|
}
|
|
queue_delayed_work(gsl_monitor_workqueue, &gsl_monitor_work,
|
|
mon_work_cycle);
|
|
}
|
|
#endif
|
|
|
|
#define SUPPORT_TP_KERNEL_CHECK
|
|
#ifdef SUPPORT_TP_KERNEL_CHECK
|
|
|
|
#if defined(ATA_TP_ADDR)
|
|
#define RAWDATA_ADDR ATA_TP_ADDR
|
|
#endif
|
|
|
|
#define DRV_NUM 15
|
|
#define SEN_NUM 10
|
|
#define RAWDATA_THRESHOLD 6000
|
|
#define DAC_THRESHOLD 20
|
|
#define MAX_SEN_NUM 15
|
|
static const u8 sen_order[SEN_NUM] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
|
|
|
|
int ctp_factory_test(void)
|
|
{
|
|
u8 buf[4], i, offset;
|
|
u32 rawdata_value, dac_value;
|
|
struct i2c_client *client = i2c_client;
|
|
|
|
if (!client) {
|
|
GSL_LOGE("err ,client is NULL,ctp factory_test\n");
|
|
return -1;
|
|
}
|
|
|
|
msleep(800);
|
|
/* msleep(20000); */
|
|
for (i = 0; i < DRV_NUM; i++) {
|
|
buf[3] = 0;
|
|
buf[2] = 0;
|
|
buf[1] = 0;
|
|
buf[0] = (RAWDATA_ADDR + SEN_NUM * 2 * i) / 0x80;
|
|
offset = (RAWDATA_ADDR + SEN_NUM * 2 * i) % 0x80;
|
|
gsl_i2c_write_bytes(client, 0xf0, buf, 4);
|
|
gsl_i2c_read_bytes(client, offset, buf, 4);
|
|
gsl_i2c_read_bytes(client, offset, buf, 4);
|
|
rawdata_value = (buf[1] << 8) + buf[0];
|
|
GSL_LOGD("rawdata_value = %d\n", rawdata_value);
|
|
if (rawdata_value > RAWDATA_THRESHOLD) {
|
|
rawdata_value = (buf[3] << 8) + buf[2];
|
|
GSL_LOGD("===>rawdata_value = %d\n", rawdata_value);
|
|
if (rawdata_value > RAWDATA_THRESHOLD) {
|
|
GSL_LOGE("###>rawdata_value = %d\n",
|
|
rawdata_value);
|
|
return -1; /* fail */
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < SEN_NUM; i++) {
|
|
buf[3] = 0x01;
|
|
buf[2] = 0xfe;
|
|
buf[1] = 0x10;
|
|
buf[0] = 0x00;
|
|
offset = 0x10 + (sen_order[i] / 4) * 4;
|
|
gsl_i2c_write_bytes(client, 0xf0, buf, 4);
|
|
gsl_i2c_read_bytes(client, offset, buf, 4);
|
|
gsl_i2c_read_bytes(client, offset, buf, 4);
|
|
|
|
dac_value = buf[sen_order[i] % 4];
|
|
GSL_LOGD("===dac_value = %d DAC_THRESHOLD = %d===\n", dac_value,
|
|
DAC_THRESHOLD);
|
|
if (dac_value < DAC_THRESHOLD) {
|
|
GSL_LOGE("dac_value %d < thres %d\n", dac_value,
|
|
DAC_THRESHOLD);
|
|
return -1; /* fail */
|
|
}
|
|
}
|
|
|
|
return 0; /* pass */
|
|
}
|
|
#endif
|
|
static int touch_event_handler(void *unused)
|
|
{
|
|
struct sched_param param = {.sched_priority = 4};
|
|
|
|
sched_setscheduler(current, SCHED_RR, ¶m);
|
|
|
|
GSL_LOGF();
|
|
do {
|
|
enable_irq(touch_irq);
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
wait_event_interruptible(waiter, tpd_flag != 0);
|
|
disable_irq(touch_irq);
|
|
tpd_flag = 0;
|
|
TPD_DEBUG_SET_TIME;
|
|
set_current_state(TASK_RUNNING);
|
|
GSL_LOGD("===touch event_handler, task running===\n");
|
|
|
|
report_data_handle();
|
|
} while (!kthread_should_stop());
|
|
|
|
return 0;
|
|
}
|
|
|
|
static irqreturn_t tpd_eint_interrupt_handler(void)
|
|
{
|
|
tpd_flag = 1;
|
|
wake_up_interruptible(&waiter);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static int tpd_i2c_detect(struct i2c_client *client,
|
|
struct i2c_board_info *info)
|
|
{
|
|
strcpy(info->type, TPD_DEVICE);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef GREEN_MODE
|
|
static void green_mode(struct i2c_client *client, int mode)
|
|
{
|
|
int i;
|
|
u8 buf[4] = {0x00};
|
|
|
|
if ((mode != MODE_ON) && (mode != MODE_OFF))
|
|
return;
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
buf[0] = 0x0a;
|
|
gsl_i2c_write_bytes(client, 0xf0, &buf[0], 1);
|
|
buf[0] = 0x00;
|
|
buf[1] = 0x00;
|
|
if (mode == MODE_ON) {
|
|
GSL_LOGD("green mode is on.");
|
|
buf[2] = 0x01;
|
|
} else if (mode == MODE_OFF) {
|
|
GSL_LOGD("green mode is off.");
|
|
buf[2] = 0x00;
|
|
}
|
|
buf[3] = 0x5a;
|
|
gsl_i2c_write_bytes(client, 0x08, buf, 4);
|
|
msleep(20);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef GSL_LATE_INIT_CHIP
|
|
static void gsl_late_init_worker(struct work_struct *work)
|
|
{
|
|
int result = 0;
|
|
int ret = 0;
|
|
|
|
GSL_LOGD("---------gsl late_init_worker-------\n");
|
|
if (1) {
|
|
result = check_mode(
|
|
i2c_client,
|
|
(power_status + interrupt_status + esd_scanning));
|
|
if (result)
|
|
init_chip(i2c_client);
|
|
GSL_LOGD("---result num is[%d] ", result);
|
|
GSL_LOGD("power_shutdowned[%d]", power_shutdowned);
|
|
GSL_LOGD("interrupt_fail[%d] ", interrupt_fail);
|
|
GSL_LOGD("esd_protected[%d]\n", esd_protected);
|
|
}
|
|
check_mem_data(i2c_client);
|
|
if (ret < 0) {
|
|
GSL_LOGE("Failed to init chip!\n");
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int tpd_i2c_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
int ret = 0;
|
|
struct device_node *node = NULL;
|
|
|
|
GSL_LOGF();
|
|
|
|
tpd_gpio_output(GTP_RST_PORT, 0);
|
|
msleep(100);
|
|
|
|
ret = regulator_enable(tpd->reg);
|
|
if (ret != 0) {
|
|
GSL_LOGE("Failed to enable regulator: %d\n", ret);
|
|
return -1;
|
|
}
|
|
|
|
msleep(100);
|
|
tpd_gpio_output(GTP_RST_PORT, 1);
|
|
tpd_gpio_as_int(GTP_INT_PORT);
|
|
msleep(50);
|
|
|
|
i2c_client = client;
|
|
#ifdef GSL_LATE_INIT_CHIP
|
|
GSL_LOGD("tpd i2c_probe () : queue gsl_late_init_workqueue\n");
|
|
INIT_DELAYED_WORK(&gsl_late_init_work, gsl_late_init_worker);
|
|
gsl_late_init_workqueue =
|
|
create_singlethread_workqueue("gsl_late_init_workqueue");
|
|
queue_delayed_work(gsl_late_init_workqueue, &gsl_late_init_work,
|
|
LATE_INIT_CYCLE_BY_REG_CHECK);
|
|
#else
|
|
ret = init_chip(i2c_client);
|
|
check_mem_data(i2c_client);
|
|
if (ret < 0) {
|
|
GSL_LOGE("Failed to init chip!\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
#ifdef GREEN_MODE
|
|
green_mode(i2c_client, MODE_ON);
|
|
reset_chip(i2c_client);
|
|
startup_chip(i2c_client);
|
|
#endif
|
|
node = of_find_matching_node(NULL, touch_of_match);
|
|
if (node) {
|
|
GSL_LOGD("node -> name = %s , touch_irq = %d\n", node->name,
|
|
touch_irq);
|
|
touch_irq = irq_of_parse_and_map(node, 0);
|
|
GSL_LOGD("touch_irq = %d\n ", touch_irq);
|
|
ret = request_irq(touch_irq,
|
|
(irq_handler_t)tpd_eint_interrupt_handler,
|
|
IRQF_TRIGGER_RISING, TPD_DEVICE, NULL);
|
|
if (ret > 0) {
|
|
ret = -1;
|
|
GSL_LOGE(
|
|
" gslX680 -- error : tpd request_irq IRQ LINE NOT AVAILABLE!.\n");
|
|
return ret;
|
|
}
|
|
} else {
|
|
ret = -1;
|
|
GSL_LOGE("gslX680 -- error : no irq node!!\n");
|
|
return ret;
|
|
}
|
|
disable_irq(touch_irq);
|
|
|
|
tpd_load_status = 1;
|
|
GSL_LOGD("tpd_load_status = 1");
|
|
|
|
thread = kthread_run(touch_event_handler, 0, TPD_DEVICE);
|
|
if (IS_ERR(thread)) {
|
|
ret = PTR_ERR(thread);
|
|
GSL_LOGE(TPD_DEVICE " failed to create kernel thread: %d\n",
|
|
ret);
|
|
return ret;
|
|
}
|
|
#if 0 /* def SUPPORT_TP_KERNEL_CHECK */
|
|
tp_check_flag = ctp_factory_test();
|
|
GSL_LOGD("\ntp_check_flag = %x\n", tp_check_flag);
|
|
if (tp_check_flag == 0)
|
|
tp_check_flag = 1;
|
|
else
|
|
tp_check_flag = 0;
|
|
/* mdelay(500); */
|
|
/* eboda_support_tp_check_put(tp_check_flag); */
|
|
tpd_load_status = tp_check_flag;
|
|
#endif
|
|
|
|
#ifdef GSL_MONITOR
|
|
GSL_LOGD("tpd i2c_probe () : queue gsl_monitor_workqueue\n");
|
|
|
|
INIT_DELAYED_WORK(&gsl_monitor_work, gsl_monitor_worker);
|
|
gsl_monitor_workqueue =
|
|
create_singlethread_workqueue("gsl_monitor_workqueue");
|
|
queue_delayed_work(gsl_monitor_workqueue, &gsl_monitor_work,
|
|
MONITOR_CYCLE_BY_REG_CHECK);
|
|
#endif
|
|
|
|
#ifdef TPD_PROC_DEBUG
|
|
#if 0
|
|
gsl_config_proc = create_proc_entry(GSL_CONFIG_PROC_FILE,
|
|
0666, NULL);
|
|
if (gsl_config_proc == NULL) {
|
|
GSL_LOGD("create_proc_entry %s failed\n",
|
|
GSL_CONFIG_PROC_FILE);
|
|
} else {
|
|
gsl_config_proc->read_proc = gsl_config_read_proc;
|
|
gsl_config_proc->write_proc = gsl_config_write_proc;
|
|
}
|
|
#else
|
|
proc_create(GSL_CONFIG_PROC_FILE, 0660, NULL, &gsl_seq_fops);
|
|
#endif
|
|
gsl_proc_flag = 0;
|
|
#endif
|
|
/* enable_irq(touch_irq); */
|
|
GSL_LOGD("tpd i2c_probe is ok -----------------");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tpd_i2c_remove(struct i2c_client *client)
|
|
{
|
|
GSL_LOGD("==tpd i2c_remove==\n");
|
|
#if !defined(CONFIG_MTK_I2C_EXTENSION) || defined(GSLTP_ENABLE_I2C_DMA)
|
|
msg_dma_release();
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct i2c_device_id tpd_i2c_id[] = {{TPD_DEVICE, 0}, {} };
|
|
|
|
static unsigned short force[] = {0, (GSLX680_ADDR << 1), I2C_CLIENT_END,
|
|
I2C_CLIENT_END};
|
|
static const unsigned short *const forces[] = {force, NULL};
|
|
/* static struct i2c_client_address_data addr_data = { .forces = forces,}; */
|
|
/* #endif */
|
|
|
|
static const struct of_device_id tpd_of_match[] = {
|
|
{.compatible = "mediatek,cap_touch"}, {},
|
|
};
|
|
|
|
struct i2c_driver tpd_i2c_driver = {
|
|
.driver = {
|
|
|
|
.name = TPD_DEVICE,
|
|
.of_match_table = tpd_of_match,
|
|
#ifndef ADD_I2C_DEVICE_ANDROID_4_0
|
|
.owner = THIS_MODULE,
|
|
#endif
|
|
},
|
|
.probe = tpd_i2c_probe,
|
|
.remove = tpd_i2c_remove,
|
|
.id_table = tpd_i2c_id,
|
|
.detect = tpd_i2c_detect,
|
|
#ifndef ADD_I2C_DEVICE_ANDROID_4_0
|
|
/* .address_data = &addr_data, */
|
|
#endif
|
|
.address_list = (const unsigned short *)forces,
|
|
};
|
|
|
|
int tpd_local_init(void)
|
|
{
|
|
int retval;
|
|
|
|
GSL_LOGF();
|
|
#if !defined(CONFIG_MTK_I2C_EXTENSION) || defined(GSLTP_ENABLE_I2C_DMA)
|
|
retval = msg_dma_alloc();
|
|
if (retval)
|
|
return retval;
|
|
#endif
|
|
|
|
tpd->reg = regulator_get(tpd->tpd_dev, "vtouch");
|
|
retval = regulator_set_voltage(tpd->reg, 2800000, 2800000);
|
|
if (retval != 0) {
|
|
GSL_LOGE("Failed to set reg-vgp6 voltage: %d\n", retval);
|
|
return -1;
|
|
}
|
|
|
|
if (i2c_add_driver(&tpd_i2c_driver) != 0) {
|
|
GSL_LOGE("unable to add i2c driver.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (tpd_load_status == 0) {
|
|
GSL_LOGE("add error touch panel driver.\n");
|
|
i2c_del_driver(&tpd_i2c_driver);
|
|
return -1;
|
|
}
|
|
|
|
input_set_abs_params(tpd->dev, ABS_MT_TRACKING_ID, 0,
|
|
(MAX_CONTACTS + 1), 0, 0);
|
|
#ifdef TPD_HAVE_BUTTON
|
|
tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local,
|
|
tpd_keys_dim_local); /* initialize tpd button data */
|
|
#endif
|
|
|
|
#if (defined(TPD_WARP_START) && defined(TPD_WARP_END))
|
|
TPD_DO_WARP = 1;
|
|
memcpy(tpd_wb_start, tpd_wb_start_local, TPD_WARP_CNT * 4);
|
|
memcpy(tpd_wb_end, tpd_wb_start_local, TPD_WARP_CNT * 4);
|
|
#endif
|
|
|
|
#if (defined(TPD_HAVE_CALIBRATION) && !defined(TPD_CUSTOM_CALIBRATION))
|
|
memcpy(tpd_calmat, tpd_calmat_local, 8 * 4);
|
|
memcpy(tpd_def_calmat, tpd_def_calmat_local, 8 * 4);
|
|
#endif
|
|
tpd_type_cap = 1;
|
|
|
|
GSL_LOGD("tpd local_init is ok.");
|
|
return 0;
|
|
}
|
|
|
|
/* Function to manage low power suspend */
|
|
static void tpd_suspend(struct device *h)
|
|
{
|
|
if (tpd_halt == 1) {
|
|
pr_info("gslX680 already in suspended status\n");
|
|
return;
|
|
}
|
|
GSL_LOGF();
|
|
|
|
#ifdef GSL_MONITOR
|
|
GSL_LOGD("gsl_ts_suspend () : cancel gsl_monitor_work\n");
|
|
cancel_delayed_work_sync(&gsl_monitor_work);
|
|
#endif
|
|
tpd_gpio_output(GTP_RST_PORT, 0);
|
|
msleep(20);
|
|
|
|
disable_irq(touch_irq);
|
|
tpd_halt = 1;
|
|
|
|
GSL_LOGD("tpd suspend is ok.");
|
|
}
|
|
|
|
/* Function to manage power-on resume */
|
|
static void tpd_resume(struct device *h)
|
|
{
|
|
if (tpd_halt == 0) {
|
|
pr_info("gslX680 already in resumed status\n");
|
|
return;
|
|
}
|
|
GSL_LOGF();
|
|
|
|
tpd_gpio_output(GTP_RST_PORT, 1);
|
|
msleep(20);
|
|
|
|
reset_chip(i2c_client);
|
|
startup_chip(i2c_client);
|
|
check_mem_data(i2c_client);
|
|
|
|
#if defined(GSL_MONITOR)
|
|
GSL_LOGD("gsl_ts_resume () : queue gsl_monitor_work\n");
|
|
queue_delayed_work(gsl_monitor_workqueue, &gsl_monitor_work,
|
|
MONITOR_CYCLE_IDLE);
|
|
#endif
|
|
enable_irq(touch_irq);
|
|
tpd_halt = 0;
|
|
GSL_LOGD("tpd resume is ok.");
|
|
}
|
|
|
|
static struct tpd_driver_t tpd_device_driver = {
|
|
.tpd_device_name = GSLX680_NAME,
|
|
.tpd_local_init = tpd_local_init,
|
|
.suspend = tpd_suspend,
|
|
.resume = tpd_resume,
|
|
#ifdef TPD_HAVE_BUTTON
|
|
.tpd_have_button = 1,
|
|
#else
|
|
.tpd_have_button = 0,
|
|
#endif
|
|
};
|
|
|
|
#if 0
|
|
static ssize_t db_value_store(struct class *class,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned long rs_tmp;
|
|
|
|
if (kstrtoul(buf, 10, &rs_tmp))
|
|
return 0;
|
|
|
|
rs_value1 = rs_tmp;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t db_value_show(struct class *class,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "rs_value1 = %d \r\n", rs_value1);
|
|
}
|
|
|
|
static struct class_attribute db_class_attrs[] = {
|
|
__ATTR(db, 0644, db_value_show, db_value_store),
|
|
__ATTR_NULL
|
|
};
|
|
#endif
|
|
|
|
static struct class db_interface_class = {
|
|
.name = "db_interface",
|
|
/* .class_attrs = db_class_attrs, */
|
|
};
|
|
|
|
/* called when loaded into kernel */
|
|
static int __init tpd_driver_init(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
GSL_LOGF();
|
|
tpd_get_dts_info();
|
|
/* register usr space */
|
|
ret = class_register(&db_interface_class);
|
|
#ifdef ADD_I2C_DEVICE_ANDROID_4_0
|
|
i2c_register_board_info(1, &gslX680_i2c_tpd, 1);
|
|
#endif
|
|
if (tpd_driver_add(&tpd_device_driver) < 0)
|
|
GSL_LOGE("add gslX680 driver failed\n");
|
|
|
|
GSL_LOGD("gslX680 driver init ok");
|
|
return 0;
|
|
}
|
|
|
|
/* should never be called */
|
|
static void __exit tpd_driver_exit(void)
|
|
{
|
|
GSL_LOGD("Sileadinc gslX680 touch panel driver exit\n");
|
|
/* input_unregister_device(tpd->dev); */
|
|
class_unregister(&db_interface_class);
|
|
tpd_driver_remove(&tpd_device_driver);
|
|
}
|
|
module_init(tpd_driver_init);
|
|
module_exit(tpd_driver_exit);
|
|
|
|
MODULE_AUTHOR("leweihua");
|
|
MODULE_DESCRIPTION("GSLX680 TouchScreen Driver");
|
|
MODULE_LICENSE("GPL v2");
|