blob: 03328d040539665cf25c97e5e8fb4217fbc9ef6b [file] [log] [blame]
/*
* Goodix GT9xx touchscreen driver
*
* Copyright (C) 2016 - 2017 Goodix. Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be a reference
* to you, when you are integrating the GOODiX's CTP IC into your system,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*/
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/input/mt.h>
#include "gt9xx.h"
#define GOODIX_VTG_MIN_UV 2600000
#define GOODIX_VTG_MAX_UV 3300000
#define GOODIX_I2C_VTG_MIN_UV 1800000
#define GOODIX_I2C_VTG_MAX_UV 1800000
#define DELAY_FOR_DISCHARGING 35
#define GOODIX_COORDS_ARR_SIZE 4
#define PROP_NAME_SIZE 24
#define I2C_MAX_TRANSFER_SIZE 255
#define GTP_PEN_BUTTON1 BTN_STYLUS
#define GTP_PEN_BUTTON2 BTN_STYLUS2
static const char *goodix_ts_name = "goodix-ts";
static const char *goodix_input_phys = "input/ts";
struct i2c_client *i2c_connect_client;
static struct proc_dir_entry *gtp_config_proc;
enum doze {
DOZE_DISABLED = 0,
DOZE_ENABLED = 1,
DOZE_WAKEUP = 2,
};
static enum doze doze_status = DOZE_DISABLED;
static int gtp_i2c_test(struct i2c_client *client);
static int gtp_enter_doze(struct goodix_ts_data *ts);
static int gtp_unregister_powermanager(struct goodix_ts_data *ts);
static int gtp_register_powermanager(struct goodix_ts_data *ts);
static int gtp_esd_init(struct goodix_ts_data *ts);
static void gtp_esd_check_func(struct work_struct *);
static int gtp_init_ext_watchdog(struct i2c_client *client);
/*
* return: 2 - ok, < 0 - i2c transfer error
*/
int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len)
{
unsigned int transfer_length = 0;
unsigned int pos = 0, address = (buf[0] << 8) + buf[1];
unsigned char get_buf[64], addr_buf[2];
int retry, r = 2;
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = !I2C_M_RD,
.buf = &addr_buf[0],
.len = GTP_ADDR_LENGTH,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
}
};
len -= GTP_ADDR_LENGTH;
if (likely(len < sizeof(get_buf))) {
/* code optimize, use stack memory */
msgs[1].buf = &get_buf[0];
} else {
msgs[1].buf = kzalloc(len > I2C_MAX_TRANSFER_SIZE
? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL);
if (!msgs[1].buf)
return -ENOMEM;
}
while (pos != len) {
if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE))
transfer_length = I2C_MAX_TRANSFER_SIZE;
else
transfer_length = len - pos;
msgs[0].buf[0] = (address >> 8) & 0xFF;
msgs[0].buf[1] = address & 0xFF;
msgs[1].len = transfer_length;
for (retry = 0; retry < RETRY_MAX_TIMES; retry++) {
if (likely(i2c_transfer(client->adapter,
msgs, 2) == 2)) {
memcpy(&buf[2 + pos], msgs[1].buf,
transfer_length);
pos += transfer_length;
address += transfer_length;
break;
}
dev_dbg(&client->dev, "I2c read retry[%d]:0x%x\n",
retry + 1, address);
usleep_range(2000, 2100);
}
if (unlikely(retry == RETRY_MAX_TIMES)) {
dev_err(&client->dev,
"I2c read failed,dev:%02x,reg:%04x,size:%u\n",
client->addr, address, len);
r = -EAGAIN;
goto read_exit;
}
}
read_exit:
if (len >= sizeof(get_buf))
kfree(msgs[1].buf);
return r;
}
/*******************************************************
* Function:
* Write data to the i2c slave device.
* Input:
* client: i2c device.
* buf[0~1]: write start address.
* buf[2~len-1]: data buffer
* len: GTP_ADDR_LENGTH + write bytes count
* Output:
* numbers of i2c_msgs to transfer:
* 1: succeed, otherwise: failed
*********************************************************/
int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len)
{
unsigned int pos = 0, transfer_length = 0;
unsigned int address = (buf[0] << 8) + buf[1];
unsigned char put_buf[64];
int retry, r = 1;
struct i2c_msg msg = {
.addr = client->addr,
.flags = !I2C_M_RD,
};
if (likely(len < sizeof(put_buf))) {
/* code optimize,use stack memory*/
msg.buf = &put_buf[0];
} else {
msg.buf = kmalloc(len > I2C_MAX_TRANSFER_SIZE
? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL);
if (!msg.buf)
return -ENOMEM;
}
len -= GTP_ADDR_LENGTH;
while (pos != len) {
if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE
- GTP_ADDR_LENGTH))
transfer_length = I2C_MAX_TRANSFER_SIZE
- GTP_ADDR_LENGTH;
else
transfer_length = len - pos;
msg.buf[0] = (unsigned char)((address >> 8) & 0xFF);
msg.buf[1] = (unsigned char)(address & 0xFF);
msg.len = transfer_length + 2;
memcpy(&msg.buf[2], &buf[2 + pos], transfer_length);
for (retry = 0; retry < RETRY_MAX_TIMES; retry++) {
if (likely(i2c_transfer(client->adapter,
&msg, 1) == 1)) {
pos += transfer_length;
address += transfer_length;
break;
}
dev_dbg(&client->dev, "I2C write retry[%d]\n",
retry + 1);
usleep_range(2000, 2100);
}
if (unlikely(retry == RETRY_MAX_TIMES)) {
dev_err(&client->dev,
"I2c write failed,dev:%02x,reg:%04x,size:%u\n",
client->addr, address, len);
r = -EAGAIN;
goto write_exit;
}
}
write_exit:
if (len + GTP_ADDR_LENGTH >= sizeof(put_buf))
kfree(msg.buf);
return r;
}
/*******************************************************
* Function:
* i2c read twice, compare the results
* Input:
* client: i2c device
* addr: operate address
* rxbuf: read data to store, if compare successful
* len: bytes to read
* Output:
* FAIL: read failed
* SUCCESS: read successful
*********************************************************/
s32 gtp_i2c_read_dbl_check(struct i2c_client *client,
u16 addr, u8 *rxbuf, int len)
{
u8 buf[16] = {0};
u8 confirm_buf[16] = {0};
u8 retry = 0;
if (len + 2 > sizeof(buf)) {
dev_warn(&client->dev,
"%s, only support length less then %zu\n",
__func__, sizeof(buf) - 2);
return FAIL;
}
while (retry++ < 3) {
memset(buf, 0xAA, 16);
buf[0] = (u8)(addr >> 8);
buf[1] = (u8)(addr & 0xFF);
gtp_i2c_read(client, buf, len + 2);
memset(confirm_buf, 0xAB, 16);
confirm_buf[0] = (u8)(addr >> 8);
confirm_buf[1] = (u8)(addr & 0xFF);
gtp_i2c_read(client, confirm_buf, len + 2);
if (!memcmp(buf, confirm_buf, len + 2)) {
memcpy(rxbuf, confirm_buf + 2, len);
return SUCCESS;
}
}
dev_err(&client->dev,
"I2C read 0x%04X, %d bytes, double check failed!\n",
addr, len);
return FAIL;
}
/*******************************************************
* Function:
* Send config.
* Input:
* client: i2c device.
* Output:
* result of i2c write operation.
* 1: succeed, otherwise
* 0: Not executed
* < 0: failed
*********************************************************/
s32 gtp_send_cfg(struct i2c_client *client)
{
s32 ret, i;
u8 check_sum;
s32 retry = 0;
struct goodix_ts_data *ts = i2c_get_clientdata(client);
struct goodix_config_data *cfg = &ts->pdata->config;
if (!cfg->length || !ts->pdata->driver_send_cfg) {
dev_info(&ts->client->dev,
"No config data or error occurred in panel_init\n");
return 0;
}
check_sum = 0;
for (i = GTP_ADDR_LENGTH; i < cfg->length; i++)
check_sum += cfg->data[i];
cfg->data[cfg->length] = (~check_sum) + 1;
dev_info(&ts->client->dev, "Driver send config\n");
for (retry = 0; retry < RETRY_MAX_TIMES; retry++) {
ret = gtp_i2c_write(client, cfg->data,
GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
if (ret > 0)
break;
}
return ret;
}
/*******************************************************
* Function:
* Control enable or disable of work thread.
* Input:
* ts: goodix i2c_client private data
* enable: enable var.
*********************************************************/
void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable)
{
if (enable) {
set_bit(REPORT_THREAD_ENABLED, &ts->flags);
dev_dbg(&ts->client->dev, "Input report thread enabled!\n");
} else {
clear_bit(REPORT_THREAD_ENABLED, &ts->flags);
dev_dbg(&ts->client->dev, "Input report thread disabled!\n");
}
}
static int gtp_gesture_handler(struct goodix_ts_data *ts)
{
u8 doze_buf[3] = {GTP_REG_DOZE_BUF >> 8, GTP_REG_DOZE_BUF & 0xFF};
int ret;
ret = gtp_i2c_read(ts->client, doze_buf, 3);
if (ret < 0) {
dev_err(&ts->client->dev, "Failed read doze buf");
return -EINVAL;
}
dev_dbg(&ts->client->dev, "0x814B = 0x%02X", doze_buf[2]);
if ((doze_buf[2] == 'a') || (doze_buf[2] == 'b') ||
(doze_buf[2] == 'c') || (doze_buf[2] == 'd') ||
(doze_buf[2] == 'e') || (doze_buf[2] == 'g') ||
(doze_buf[2] == 'h') || (doze_buf[2] == 'm') ||
(doze_buf[2] == 'o') || (doze_buf[2] == 'q') ||
(doze_buf[2] == 's') || (doze_buf[2] == 'v') ||
(doze_buf[2] == 'w') || (doze_buf[2] == 'y') ||
(doze_buf[2] == 'z') || (doze_buf[2] == 0x5E) ||
(doze_buf[2] == 0xAA) || (doze_buf[2] == 0xAB) ||
(doze_buf[2] == 0xBA) || (doze_buf[2] == 0xBB) ||
(doze_buf[2] == 0xCC)) {
doze_status = DOZE_WAKEUP;
input_report_key(ts->input_dev, KEY_POWER, 1);
input_sync(ts->input_dev);
input_report_key(ts->input_dev, KEY_POWER, 0);
input_sync(ts->input_dev);
/* clear 0x814B */
doze_buf[2] = 0x00;
gtp_i2c_write(ts->client, doze_buf, 3);
} else {
/* clear 0x814B */
doze_buf[2] = 0x00;
gtp_i2c_write(ts->client, doze_buf, 3);
gtp_enter_doze(ts);
}
return 0;
}
/*
* return touch state register value
* pen event id fixed with 9 and set tool type TOOL_PEN
*
*/
static u8 gtp_get_points(struct goodix_ts_data *ts,
struct goodix_point_t *points,
u8 *key_value)
{
int ret;
int i;
u8 *coor_data = NULL;
u8 finger_state = 0;
u8 touch_num = 0;
u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8,
GTP_READ_COOR_ADDR & 0xFF, 0 };
u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH_ID + 1] = {
GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF };
ret = gtp_i2c_read(ts->client, point_data, 12);
if (ret < 0) {
dev_err(&ts->client->dev,
"I2C transfer error. errno:%d\n ", ret);
return 0;
}
finger_state = point_data[GTP_ADDR_LENGTH];
if (finger_state == 0x00)
return 0;
touch_num = finger_state & 0x0f;
if ((finger_state & MASK_BIT_8) == 0 ||
touch_num > ts->pdata->max_touch_id) {
dev_err(&ts->client->dev,
"Invalid touch state: 0x%x", finger_state);
finger_state = 0;
goto exit_get_point;
}
if (touch_num > 1) {
u8 buf[8 * GTP_MAX_TOUCH_ID] = {
(GTP_READ_COOR_ADDR + 10) >> 8,
(GTP_READ_COOR_ADDR + 10) & 0xff };
ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1));
if (ret < 0) {
dev_err(&ts->client->dev, "I2C error. %d\n", ret);
finger_state = 0;
goto exit_get_point;
}
memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
}
/* panel have touch key */
/* 0x20_UPKEY 0X10_DOWNKEY 0X40_ALLKEYDOWN */
*key_value = point_data[3 + 8 * touch_num];
memset(points, 0, sizeof(*points) * GTP_MAX_TOUCH_ID);
for (i = 0; i < touch_num; i++) {
coor_data = &point_data[i * 8 + 3];
points[i].id = coor_data[0];
points[i].x = coor_data[1] | (coor_data[2] << 8);
points[i].y = coor_data[3] | (coor_data[4] << 8);
points[i].w = coor_data[5] | (coor_data[6] << 8);
/* if pen hover points[].p must set to zero */
points[i].p = coor_data[5] | (coor_data[6] << 8);
if (ts->pdata->swap_x2y)
GTP_SWAP(points[i].x, points[i].y);
dev_dbg(&ts->client->dev, "[%d][%d %d %d]\n",
points[i].id, points[i].x, points[i].y, points[i].p);
/* pen device coordinate */
if (points[i].id & 0x80) {
points[i].tool_type = GTP_TOOL_PEN;
points[i].id = 10;
if (ts->pdata->pen_suppress_finger) {
points[0] = points[i];
memset(++points, 0, sizeof(*points) *
(GTP_MAX_TOUCH_ID - 1));
finger_state &= 0xf0;
finger_state |= 0x01;
break;
}
} else {
points[i].tool_type = GTP_TOOL_FINGER;
}
}
exit_get_point:
if (!test_bit(RAW_DATA_MODE, &ts->flags)) {
ret = gtp_i2c_write(ts->client, end_cmd, 3);
if (ret < 0)
dev_info(&ts->client->dev, "I2C write end_cmd error!");
}
return finger_state;
}
static void gtp_type_a_report(struct goodix_ts_data *ts, u8 touch_num,
struct goodix_point_t *points)
{
int i;
u16 cur_touch = 0;
static u16 pre_touch;
static u8 pre_pen_id;
if (touch_num)
input_report_key(ts->input_dev, BTN_TOUCH, 1);
for (i = 0; i < ts->pdata->max_touch_id; i++) {
if (touch_num && i == points->id) {
input_report_abs(ts->input_dev,
ABS_MT_TRACKING_ID, points->id);
if (points->tool_type == GTP_TOOL_PEN) {
input_report_key(ts->input_dev,
BTN_TOOL_PEN, true);
pre_pen_id = points->id;
} else {
input_report_key(ts->input_dev,
BTN_TOOL_FINGER, true);
}
input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
points->x);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
points->y);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
points->w);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
points->p);
input_mt_sync(ts->input_dev);
cur_touch |= 0x01 << points->id;
points++;
} else if (pre_touch & 0x01 << i) {
if (pre_pen_id == i) {
input_report_key(ts->input_dev,
BTN_TOOL_PEN, false);
/* valid id will < 10, so id to 0xff to indicate a invalid state */
pre_pen_id = 0xff;
} else {
input_report_key(ts->input_dev,
BTN_TOOL_FINGER, false);
}
}
}
pre_touch = cur_touch;
if (!pre_touch) {
input_mt_sync(ts->input_dev);
input_report_key(ts->input_dev, BTN_TOUCH, 0);
}
input_sync(ts->input_dev);
}
static void gtp_mt_slot_report(struct goodix_ts_data *ts, u8 touch_num,
struct goodix_point_t *points)
{
int i;
u16 cur_touch = 0;
static u16 pre_touch;
static u8 pre_pen_id;
for (i = 0; i < ts->pdata->max_touch_id; i++) {
if (touch_num && i == points->id) {
input_mt_slot(ts->input_dev, points->id);
if (points->tool_type == GTP_TOOL_PEN) {
input_mt_report_slot_state(ts->input_dev,
MT_TOOL_PEN, true);
pre_pen_id = points->id;
} else {
input_mt_report_slot_state(ts->input_dev,
MT_TOOL_FINGER, true);
}
input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
points->x);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
points->y);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
points->w);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
points->p);
cur_touch |= 0x01 << points->id;
points++;
} else if (pre_touch & 0x01 << i) {
input_mt_slot(ts->input_dev, i);
if (pre_pen_id == i) {
input_mt_report_slot_state(ts->input_dev,
MT_TOOL_PEN, false);
/* valid id will < 10, so set id to 0xff to
* indicate a invalid state
*/
pre_pen_id = 0xff;
} else {
input_mt_report_slot_state(ts->input_dev,
MT_TOOL_FINGER, false);
}
}
}
pre_touch = cur_touch;
/* report BTN_TOUCH event */
input_mt_sync_frame(ts->input_dev);
input_sync(ts->input_dev);
}
/*******************************************************
* Function:
* Goodix touchscreen sensor report function
* Input:
* ts: goodix tp private data
* Output:
* None.
*********************************************************/
static void gtp_work_func(struct goodix_ts_data *ts)
{
u8 point_state = 0;
u8 key_value = 0;
s32 i = 0;
s32 ret = -1;
static u8 pre_key;
struct goodix_point_t points[GTP_MAX_TOUCH_ID];
if (test_bit(PANEL_RESETTING, &ts->flags))
return;
if (!test_bit(REPORT_THREAD_ENABLED, &ts->flags))
return;
/* gesture event */
if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) {
ret = gtp_gesture_handler(ts);
if (ret)
dev_err(&ts->client->dev,
"Failed handler gesture event %d\n", ret);
return;
}
point_state = gtp_get_points(ts, points, &key_value);
if (!point_state) {
dev_dbg(&ts->client->dev, "Invalid finger points\n");
return;
}
/* touch key event */
if (key_value & 0xf0 || pre_key & 0xf0) {
/* pen button */
switch (key_value) {
case 0x40:
input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1);
input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1);
break;
case 0x10:
input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1);
input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0);
dev_dbg(&ts->client->dev, "pen button1 down\n");
break;
case 0x20:
input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0);
input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1);
break;
default:
input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0);
input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0);
dev_dbg(&ts->client->dev, "button1 up\n");
break;
}
input_sync(ts->input_dev);
pre_key = key_value;
} else if (key_value & 0x0f || pre_key & 0x0f) {
/* panel key */
for (i = 0; i < ts->pdata->key_nums; i++) {
if ((pre_key | key_value) & (0x01 << i))
input_report_key(ts->input_dev,
ts->pdata->key_map[i],
key_value & (0x01 << i));
}
input_sync(ts->input_dev);
pre_key = key_value;
}
if (!ts->pdata->type_a_report)
gtp_mt_slot_report(ts, point_state & 0x0f, points);
else
gtp_type_a_report(ts, point_state & 0x0f, points);
}
/*******************************************************
* Function:
* Timer interrupt service routine for polling mode.
* Input:
* timer: timer struct pointer
* Output:
* Timer work mode.
* HRTIMER_NORESTART:
* no restart mode
*********************************************************/
static enum hrtimer_restart gtp_timer_handler(struct hrtimer *timer)
{
struct goodix_ts_data *ts =
container_of(timer, struct goodix_ts_data, timer);
gtp_work_func(ts);
hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
HRTIMER_MODE_REL);
return HRTIMER_NORESTART;
}
static irqreturn_t gtp_irq_handler(int irq, void *dev_id)
{
struct goodix_ts_data *ts = dev_id;
gtp_work_func(ts);
return IRQ_HANDLED;
}
void gtp_int_output(struct goodix_ts_data *ts, int level)
{
if (!ts->pdata->int_sync)
return;
if (level == 0) {
if (ts->pinctrl.pinctrl)
pinctrl_select_state(ts->pinctrl.pinctrl,
ts->pinctrl.int_out_low);
else if (gpio_is_valid(ts->pdata->irq_gpio))
gpio_direction_output(ts->pdata->irq_gpio, 0);
else
dev_err(&ts->client->dev,
"Failed set int pin output low\n");
} else {
if (ts->pinctrl.pinctrl)
pinctrl_select_state(ts->pinctrl.pinctrl,
ts->pinctrl.int_out_high);
else if (gpio_is_valid(ts->pdata->irq_gpio))
gpio_direction_output(ts->pdata->irq_gpio, 1);
else
dev_err(&ts->client->dev,
"Failed set int pin output high\n");
}
}
void gtp_int_sync(struct goodix_ts_data *ts, s32 ms)
{
if (!ts->pdata->int_sync)
return;
if (ts->pinctrl.pinctrl) {
gtp_int_output(ts, 0);
msleep(ms);
pinctrl_select_state(ts->pinctrl.pinctrl,
ts->pinctrl.int_input);
} else if (gpio_is_valid(ts->pdata->irq_gpio)) {
gpio_direction_output(ts->pdata->irq_gpio, 0);
msleep(ms);
gpio_direction_input(ts->pdata->irq_gpio);
} else {
dev_err(&ts->client->dev, "Failed sync int pin\n");
}
}
void gtp_rst_output(struct goodix_ts_data *ts, int level)
{
if (level == 0) {
if (ts->pinctrl.pinctrl)
pinctrl_select_state(ts->pinctrl.pinctrl,
ts->pinctrl.rst_out_low);
else if (gpio_is_valid(ts->pdata->rst_gpio))
gpio_direction_output(ts->pdata->rst_gpio, 0);
else
dev_err(&ts->client->dev,
"Failed set rst pin output low\n");
} else {
if (ts->pinctrl.pinctrl)
pinctrl_select_state(ts->pinctrl.pinctrl,
ts->pinctrl.rst_out_high);
else if (gpio_is_valid(ts->pdata->rst_gpio))
gpio_direction_output(ts->pdata->rst_gpio, 1);
else
dev_err(&ts->client->dev,
"Failed set rst pin output high\n");
}
}
void gtp_rst_input(struct goodix_ts_data *ts)
{
if (ts->pinctrl.pinctrl)
pinctrl_select_state(ts->pinctrl.pinctrl,
ts->pinctrl.rst_input);
else if (gpio_is_valid(ts->pdata->rst_gpio))
gpio_direction_input(ts->pdata->rst_gpio);
else
dev_err(&ts->client->dev,
"Failed set rst pin input\n");
}
/*******************************************************
* Function:
* Reset chip. Control the reset pin and int-pin(if
* defined),
* Input:
* client: i2c device.
* ms: reset time in millisecond
* Output:
* None.
*******************************************************/
void gtp_reset_guitar(struct i2c_client *client, s32 ms)
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
dev_info(&client->dev, "Guitar reset");
set_bit(PANEL_RESETTING, &ts->flags);
if (!gpio_is_valid(ts->pdata->rst_gpio)) {
dev_warn(&client->dev, "reset failed no valid reset gpio");
return;
}
gtp_rst_output(ts, 0);
usleep_range(ms * 1000, ms * 1000 + 100); /* T2: > 10ms */
gtp_int_output(ts, client->addr == 0x14);
usleep_range(2000, 3000); /* T3: > 100us (2ms)*/
gtp_rst_output(ts, 1);
usleep_range(6000, 7000); /* T4: > 5ms */
gtp_rst_input(ts);
gtp_int_sync(ts, 50);
if (ts->pdata->esd_protect)
gtp_init_ext_watchdog(client);
clear_bit(PANEL_RESETTING, &ts->flags);
}
/*******************************************************
* Function:
* Enter doze mode for sliding wakeup.
* Input:
* ts: goodix tp private data
* Output:
* 1: succeed, otherwise failed
*******************************************************/
static int gtp_enter_doze(struct goodix_ts_data *ts)
{
int ret = -1;
int retry = 0;
u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8),
(u8)GTP_REG_COMMAND, 8 };
/* resend doze command
* if (test_and_set_bit(DOZE_MODE, &ts->flags)) {
* dev_info(&ts->client->dev, "Already in doze mode\n");
* return SUCCESS;
* }
*/
set_bit(DOZE_MODE, &ts->flags);
dev_dbg(&ts->client->dev, "Entering gesture mode.");
while (retry++ < 5) {
i2c_control_buf[0] = (u8)(GTP_REG_COMMAND_CHECK >> 8);
i2c_control_buf[1] = (u8)GTP_REG_COMMAND_CHECK;
ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
if (ret < 0) {
dev_dbg(&ts->client->dev,
"failed to set doze flag into 0x8046, %d\n",
retry);
continue;
}
i2c_control_buf[0] = (u8)(GTP_REG_COMMAND >> 8);
i2c_control_buf[1] = (u8)GTP_REG_COMMAND;
ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
if (ret > 0) {
dev_dbg(&ts->client->dev, "Gesture mode enabled\n");
return ret;
}
usleep_range(10000, 11000);
}
dev_err(&ts->client->dev, "Failed enter doze mode\n");
clear_bit(DOZE_MODE, &ts->flags);
return ret;
}
static s8 gtp_enter_sleep(struct goodix_ts_data *ts)
{
s8 ret = -1;
s8 retry = 0;
u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8),
(u8)GTP_REG_COMMAND, 5 };
gtp_int_output(ts, 0);
usleep_range(5000, 6000);
while (retry++ < 5) {
ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
if (ret > 0) {
dev_info(&ts->client->dev, "Enter sleep mode\n");
return ret;
}
usleep_range(10000, 11000);
}
dev_err(&ts->client->dev, "Failed send sleep cmd\n");
return ret;
}
static int gtp_wakeup_sleep(struct goodix_ts_data *ts)
{
u8 retry = 0;
int ret = -1;
while (retry++ < 10) {
gtp_int_output(ts, 1);
usleep_range(5000, 6000);
ret = gtp_i2c_test(ts->client);
if (!ret) {
dev_dbg(&ts->client->dev, "Success wakeup sleep\n");
gtp_int_sync(ts, 25);
if (ts->pdata->esd_protect)
gtp_init_ext_watchdog(ts->client);
return ret;
}
gtp_reset_guitar(ts->client, 20);
}
dev_err(&ts->client->dev, "Failed wakeup from sleep mode\n");
return -EINVAL;
}
static int gtp_find_valid_cfg_data(struct goodix_ts_data *ts)
{
int ret = -1;
u8 sensor_id = 0;
struct goodix_config_data *cfg = &ts->pdata->config;
/* if defined CONFIG_OF, parse config data from dtsi
* else parse config data form header file.
*/
cfg->length = 0;
#ifndef CONFIG_OF
u8 cfg_info_group0[] = CTP_CFG_GROUP0;
u8 cfg_info_group1[] = CTP_CFG_GROUP1;
u8 cfg_info_group2[] = CTP_CFG_GROUP2;
u8 cfg_info_group3[] = CTP_CFG_GROUP3;
u8 cfg_info_group4[] = CTP_CFG_GROUP4;
u8 cfg_info_group5[] = CTP_CFG_GROUP5;
u8 *send_cfg_buf[] = { cfg_info_group0, cfg_info_group1,
cfg_info_group2, cfg_info_group3,
cfg_info_group4, cfg_info_group5 };
u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group0),
CFG_GROUP_LEN(cfg_info_group1),
CFG_GROUP_LEN(cfg_info_group2),
CFG_GROUP_LEN(cfg_info_group3),
CFG_GROUP_LEN(cfg_info_group4),
CFG_GROUP_LEN(cfg_info_group5)};
dev_dbg(&ts->client->dev,
"Config Groups\' Lengths: %d, %d, %d, %d, %d, %d",
cfg_info_len[0], cfg_info_len[1], cfg_info_len[2],
cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]);
#endif
/* read sensor id */
ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
&sensor_id, 1);
if (ret != SUCCESS || sensor_id >= 0x06) {
dev_err(&ts->client->dev,
"Failed get valid sensor_id(0x%02X), No Config Sent\n",
sensor_id);
return -EINVAL;
}
dev_dbg(&ts->client->dev, "Sensor_ID: %d", sensor_id);
/* parse config data */
#ifdef CONFIG_OF
dev_dbg(&ts->client->dev, "Get config data from device tree\n");
ret = gtp_parse_dt_cfg(&ts->client->dev,
&cfg->data[GTP_ADDR_LENGTH],
&cfg->length, sensor_id);
if (ret < 0) {
dev_err(&ts->client->dev,
"Failed to parse config data form device tree\n");
cfg->length = 0;
return -EPERM;
}
#else
dev_dbg(&ts->client->dev, "Get config data from header file\n");
if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
(!cfg_info_len[3]) && (!cfg_info_len[4]) &&
(!cfg_info_len[5])) {
sensor_id = 0;
}
cfg->length = cfg_info_len[sensor_id];
memset(&cfg->data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
memcpy(&cfg->data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
cfg->length);
#endif
if (cfg->length < GTP_CONFIG_MIN_LENGTH) {
dev_err(&ts->client->dev,
"Failed get valid config data with sensor id %d\n",
sensor_id);
cfg->length = 0;
return -EPERM;
}
dev_info(&ts->client->dev, "Config group%d used,length: %d\n",
sensor_id, cfg->length);
return 0;
}
/*******************************************************
* Function:
* Get valid config data from dts or .h file.
* Read firmware version info and judge firmware
* working state
* Input:
* ts: goodix private data
* Output:
* Executive outcomes.
* 0: succeed, otherwise: failed
*******************************************************/
static s32 gtp_init_panel(struct goodix_ts_data *ts)
{
s32 ret = -1;
u8 opr_buf[16] = {0};
u8 drv_cfg_version = 0;
u8 flash_cfg_version = 0;
struct goodix_config_data *cfg = &ts->pdata->config;
if (!ts->pdata->driver_send_cfg) {
dev_info(&ts->client->dev, "Driver set not send config\n");
cfg->length = GTP_CONFIG_MAX_LENGTH;
ret = gtp_i2c_read(ts->client,
cfg->data, cfg->length +
GTP_ADDR_LENGTH);
if (ret < 0)
dev_err(&ts->client->dev, "Read origin Config Failed\n");
return 0;
}
gtp_find_valid_cfg_data(ts);
/* check firmware */
ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
if (ret == SUCCESS) {
if (opr_buf[0] != 0xBE) {
set_bit(FW_ERROR, &ts->flags);
dev_err(&ts->client->dev,
"Firmware error, no config sent!\n");
return -EINVAL;
}
}
ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
&opr_buf[0], 1);
if (ret == SUCCESS) {
dev_dbg(&ts->client->dev,
"Config Version: %d; IC Config Version: %d\n",
cfg->data[GTP_ADDR_LENGTH], opr_buf[0]);
flash_cfg_version = opr_buf[0];
drv_cfg_version = cfg->data[GTP_ADDR_LENGTH];
if (flash_cfg_version < 120 &&
flash_cfg_version > drv_cfg_version)
cfg->data[GTP_ADDR_LENGTH] = 0x00;
} else {
dev_err(&ts->client->dev,
"Failed to get ic config version!No config sent\n");
return -EPERM;
}
ret = gtp_send_cfg(ts->client);
if (ret < 0)
dev_err(&ts->client->dev, "Send config error\n");
else
usleep_range(10000, 11000); /* 10 ms */
/* restore config version */
cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version;
return 0;
}
static ssize_t gtp_config_read_proc(struct file *file, char __user *page,
size_t size, loff_t *ppos)
{
int i, ret;
char *ptr;
size_t data_len = 0;
char temp_data[GTP_CONFIG_MAX_LENGTH + 2] = {
(u8)(GTP_REG_CONFIG_DATA >> 8),
(u8)GTP_REG_CONFIG_DATA };
struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
struct goodix_config_data *cfg = &ts->pdata->config;
ptr = kzalloc(4096, GFP_KERNEL);
if (!ptr)
return -ENOMEM;
data_len += snprintf(ptr + data_len, 4096 - data_len,
"====init value====\n");
for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++) {
data_len += snprintf(ptr + data_len, 4096 - data_len,
"0x%02X ", cfg->data[i + 2]);
if (i % 8 == 7)
data_len += snprintf(ptr + data_len,
4096 - data_len, "\n");
}
data_len += snprintf(ptr + data_len, 4096 - data_len, "\n");
data_len += snprintf(ptr + data_len, 4096 - data_len,
"====real value====\n");
ret = gtp_i2c_read(i2c_connect_client, temp_data,
GTP_CONFIG_MAX_LENGTH + 2);
if (ret < 0) {
data_len += snprintf(ptr + data_len, 4096 - data_len,
"Failed read real config data\n");
} else {
for (i = 0; i < GTP_CONFIG_MAX_LENGTH; i++) {
data_len += snprintf(ptr + data_len, 4096 - data_len,
"0x%02X ", temp_data[i + 2]);
if (i % 8 == 7)
data_len += snprintf(ptr + data_len,
4096 - data_len, "\n");
}
}
data_len = simple_read_from_buffer(page, size, ppos, ptr, data_len);
kfree(ptr);
ptr = NULL;
return data_len;
}
int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf)
{
int i, ret;
int cfg_len = 0;
long val;
char temp_buf[5];
for (i = 0; i < src_len;) {
if (src_buf[i] == ' ' || src_buf[i] == '\r' ||
src_buf[i] == '\n') {
i++;
continue;
}
temp_buf[0] = src_buf[i];
temp_buf[1] = src_buf[i + 1];
temp_buf[2] = src_buf[i + 2];
temp_buf[3] = src_buf[i + 3];
temp_buf[4] = '\0';
if (!kstrtol(temp_buf, 16, &val)) {
if (cfg_len < GTP_CONFIG_MAX_LENGTH) {
dst_buf[cfg_len++] = val & 0xFF;
i += 5;
} else {
ret = -2;
goto convert_failed;
}
} else {
ret = -3;
goto convert_failed;
}
}
return cfg_len;
convert_failed:
return ret;
}
static ssize_t gtp_config_write_proc(struct file *filp,
const char __user *buffer,
size_t count, loff_t *off)
{
u8 *temp_buf;
u8 *file_config;
int file_cfg_len;
s32 ret = 0, i;
struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
dev_dbg(&ts->client->dev, "write count %zu\n", count);
if (count > PAGE_SIZE) {
dev_err(&ts->client->dev, "config to long %zu\n", count);
return -EFAULT;
}
temp_buf = kzalloc(count, GFP_KERNEL);
if (!temp_buf)
return -ENOMEM;
file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
GFP_KERNEL);
if (!file_config) {
kfree(temp_buf);
return -ENOMEM;
}
file_config[0] = GTP_REG_CONFIG_DATA >> 8;
file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
if (copy_from_user(temp_buf, buffer, count)) {
dev_err(&ts->client->dev, "Failed copy from user\n");
ret = -EFAULT;
goto send_cfg_err;
}
file_cfg_len = gtp_ascii_to_array(temp_buf, (int)count,
&file_config[GTP_ADDR_LENGTH]);
if (file_cfg_len < 0) {
dev_err(&ts->client->dev, "failed covert ascii to hex");
ret = -EFAULT;
goto send_cfg_err;
}
GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len);
i = 0;
while (i++ < 5) {
ret = gtp_i2c_write(ts->client, file_config, file_cfg_len + 2);
if (ret > 0) {
dev_info(&ts->client->dev, "Send config SUCCESS.");
break;
}
dev_err(&ts->client->dev, "Send config i2c error.");
ret = -EFAULT;
goto send_cfg_err;
}
ret = count;
send_cfg_err:
kfree(temp_buf);
kfree(file_config);
return ret;
}
static const struct file_operations config_proc_ops = {
.owner = THIS_MODULE,
.read = gtp_config_read_proc,
.write = gtp_config_write_proc,
};
static ssize_t gtp_workmode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
size_t data_len = 0;
struct goodix_ts_data *data = dev_get_drvdata(dev);
if (test_bit(DOZE_MODE, &data->flags))
data_len = scnprintf(buf, PAGE_SIZE, "%s\n",
"doze_mode");
else if (test_bit(SLEEP_MODE, &data->flags))
data_len = scnprintf(buf, PAGE_SIZE, "%s\n",
"sleep_mode");
else
data_len = scnprintf(buf, PAGE_SIZE, "%s\n",
"normal_mode");
return data_len;
}
static DEVICE_ATTR(workmode, 0444, gtp_workmode_show, NULL);
#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
#define FW_NAME_MAX_LEN 80
static ssize_t gtp_dofwupdate_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct goodix_ts_data *ts = dev_get_drvdata(dev);
char update_file_name[FW_NAME_MAX_LEN];
int retval;
if (count > FW_NAME_MAX_LEN) {
dev_info(&ts->client->dev, "FW filename is too long\n");
retval = -EINVAL;
goto exit;
}
strlcpy(update_file_name, buf, count);
ts->force_update = true;
retval = gup_update_proc(update_file_name);
if (retval == FAIL)
dev_err(&ts->client->dev, "Fail to update GTP firmware.\n");
else
dev_info(&ts->client->dev, "Update success\n");
return count;
exit:
return retval;
}
static DEVICE_ATTR(dofwupdate, 0664, NULL, gtp_dofwupdate_store);
#endif
static ssize_t gtp_productinfo_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct goodix_ts_data *data = dev_get_drvdata(dev);
struct goodix_fw_info *fw_info = &data->fw_info;
return scnprintf(buf, PAGE_SIZE, "GT%s_%x_%d\n",
fw_info->pid, fw_info->version, fw_info->sensor_id);
}
static DEVICE_ATTR(productinfo, 0444, gtp_productinfo_show, NULL);
static ssize_t gtp_drv_irq_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned long value = 0;
int err = 0;
struct goodix_ts_data *data = dev_get_drvdata(dev);
err = kstrtoul(buf, 10, &value);
if (err < 0) {
dev_err(dev, "Failed to convert value\n");
return -EINVAL;
}
switch (value) {
case 0:
/* Disable irq */
gtp_work_control_enable(data, false);
break;
case 1:
/* Enable irq */
gtp_work_control_enable(data, true);
break;
default:
dev_err(dev, "Invalid value\n");
return -EINVAL;
}
return count;
}
static ssize_t gtp_drv_irq_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct goodix_ts_data *data = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%s\n",
test_bit(REPORT_THREAD_ENABLED, &data->flags)
? "enabled" : "disabled");
}
static DEVICE_ATTR(drv_irq, 0664, gtp_drv_irq_show, gtp_drv_irq_store);
static ssize_t gtp_reset_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct goodix_ts_data *data = dev_get_drvdata(dev);
if ('1' != buf[0]) {
dev_err(dev, "Invalid argument for reset\n");
return -EINVAL;
}
gtp_reset_guitar(data->client, 20);
return count;
}
static DEVICE_ATTR(reset, 0220, NULL, gtp_reset_store);
static struct attribute *gtp_attrs[] = {
&dev_attr_workmode.attr,
&dev_attr_productinfo.attr,
#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
&dev_attr_dofwupdate.attr,
#endif
&dev_attr_drv_irq.attr,
&dev_attr_reset.attr,
NULL
};
static const struct attribute_group gtp_attr_group = {
.attrs = gtp_attrs,
};
static int gtp_create_file(struct goodix_ts_data *ts)
{
int ret;
struct i2c_client *client = ts->client;
/* Create proc file system */
gtp_config_proc = NULL;
gtp_config_proc = proc_create(GT91XX_CONFIG_PROC_FILE, 0664,
NULL, &config_proc_ops);
if (!gtp_config_proc)
dev_err(&client->dev, "create_proc_entry %s failed\n",
GT91XX_CONFIG_PROC_FILE);
else
dev_info(&client->dev, "create proc entry %s success\n",
GT91XX_CONFIG_PROC_FILE);
ret = sysfs_create_group(&client->dev.kobj, &gtp_attr_group);
if (ret) {
dev_err(&client->dev, "Failure create sysfs group %d\n", ret);
/*TODO: debug change */
goto exit_free_config_proc;
}
return 0;
exit_free_config_proc:
remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc);
return -ENODEV;
}
s32 gtp_get_fw_info(struct i2c_client *client, struct goodix_fw_info *fw_info)
{
s32 ret = -1;
u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};
ret = gtp_i2c_read(client, buf, sizeof(buf));
if (ret < 0) {
dev_err(&client->dev, "Failed read fw_info\n");
return ret;
}
/* product id */
memset(fw_info, 0, sizeof(*fw_info));
if (buf[5] == 0x00) {
memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 3);
dev_info(&client->dev, "IC Version: %c%c%c_%02X%02X\n",
buf[2], buf[3], buf[4], buf[7], buf[6]);
} else {
memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 4);
dev_info(&client->dev, "IC Version: %c%c%c%c_%02X%02X\n",
buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
}
/* current firmware version */
fw_info->version = (buf[7] << 8) | buf[6];
/* read sensor id */
fw_info->sensor_id = 0xff;
ret = gtp_i2c_read_dbl_check(client, GTP_REG_SENSOR_ID,
&fw_info->sensor_id, 1);
if (ret != SUCCESS || fw_info->sensor_id >= 0x06) {
dev_err(&client->dev,
"Failed get valid sensor_id(0x%02X), No Config Sent\n",
fw_info->sensor_id);
fw_info->sensor_id = 0xff;
}
return ret;
}
static int gtp_i2c_test(struct i2c_client *client)
{
u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
u8 retry = 0;
int ret = -1;
while (retry++ < 3) {
ret = gtp_i2c_read(client, test, 3);
if (ret == 2)
return 0;
dev_err(&client->dev, "GTP i2c test failed time %d\n", retry);
usleep_range(10000, 11000); /* 10 ms */
}
return -EAGAIN;
}
static int gtp_pinctrl_init(struct goodix_ts_data *ts)
{
struct goodix_pinctrl *pinctrl = &ts->pinctrl;
pinctrl->pinctrl = devm_pinctrl_get(&ts->client->dev);
if (IS_ERR_OR_NULL(pinctrl->pinctrl)) {
dev_info(&ts->client->dev, "No pinctrl found\n");
pinctrl->pinctrl = NULL;
return 0;
}
/* INT pinctrl */
pinctrl->int_default = pinctrl_lookup_state(pinctrl->pinctrl,
"gdix_ts_int_default");
if (IS_ERR_OR_NULL(pinctrl->int_default)) {
dev_info(&ts->client->dev,
"Failed get pinctrl state:INT default state\n");
goto exit_pinctrl_init;
}
pinctrl->int_out_high = pinctrl_lookup_state(pinctrl->pinctrl,
"gdix_ts_int_output_high");
if (IS_ERR_OR_NULL(pinctrl->int_out_high)) {
dev_info(&ts->client->dev,
"Failed get pinctrl state:INT output_high\n");
goto exit_pinctrl_init;
}
pinctrl->int_out_low = pinctrl_lookup_state(pinctrl->pinctrl,
"gdix_ts_int_output_low");
if (IS_ERR_OR_NULL(pinctrl->int_out_low)) {
dev_info(&ts->client->dev,
"Failed get pinctrl state:INT output_low\n");
goto exit_pinctrl_init;
}
pinctrl->int_input = pinctrl_lookup_state(pinctrl->pinctrl,
"gdix_ts_int_input");
if (IS_ERR_OR_NULL(pinctrl->int_input)) {
dev_info(&ts->client->dev,
"Failed get pinctrl state:int-input\n");
goto exit_pinctrl_init;
}
dev_info(&ts->client->dev, "Success init INT pinctrl\n");
/* RST pinctrl */
pinctrl->rst_default = pinctrl_lookup_state(pinctrl->pinctrl,
"gdix_ts_rst_default");
if (IS_ERR_OR_NULL(pinctrl->rst_default)) {
dev_info(&ts->client->dev,
"Failed get pinctrl state:RST default state\n");
goto exit_pinctrl_init;
}
pinctrl->rst_out_high = pinctrl_lookup_state(pinctrl->pinctrl,
"gdix_ts_rst_output_high");
if (IS_ERR_OR_NULL(pinctrl->rst_out_high)) {
dev_info(&ts->client->dev,
"Failed get pinctrl state:RST output_high\n");
goto exit_pinctrl_init;
}
pinctrl->rst_out_low = pinctrl_lookup_state(pinctrl->pinctrl,
"gdix_ts_rst_output_low");
if (IS_ERR_OR_NULL(pinctrl->rst_out_low)) {
dev_info(&ts->client->dev,
"Failed get pinctrl state:RST output_low\n");
goto exit_pinctrl_init;
}
pinctrl->rst_input = pinctrl_lookup_state(pinctrl->pinctrl,
"gdix_ts_rst_input");
if (IS_ERR_OR_NULL(pinctrl->rst_input)) {
dev_info(&ts->client->dev,
"Failed get pinctrl state:rst-input\n");
goto exit_pinctrl_init;
}
dev_info(&ts->client->dev, "Success init RST pinctrl\n");
return 0;
exit_pinctrl_init:
devm_pinctrl_put(pinctrl->pinctrl);
pinctrl->pinctrl = NULL;
pinctrl->int_default = NULL;
pinctrl->int_out_high = NULL;
pinctrl->int_out_low = NULL;
pinctrl->int_input = NULL;
pinctrl->rst_default = NULL;
pinctrl->rst_out_high = NULL;
pinctrl->rst_out_low = NULL;
pinctrl->rst_input = NULL;
return -EINVAL;
}
static void gtp_pinctrl_deinit(struct goodix_ts_data *ts)
{
if (ts->pinctrl.pinctrl)
devm_pinctrl_put(ts->pinctrl.pinctrl);
}
static int gtp_request_io_port(struct goodix_ts_data *ts)
{
int ret = 0;
if (gpio_is_valid(ts->pdata->irq_gpio)) {
ret = gpio_request(ts->pdata->irq_gpio, "goodix_ts_int");
if (ret < 0) {
dev_err(&ts->client->dev,
"Failed to request GPIO:%d, ERRNO:%d\n",
(s32)ts->pdata->irq_gpio, ret);
return -ENODEV;
}
gpio_direction_input(ts->pdata->irq_gpio);
dev_info(&ts->client->dev, "Success request irq-gpio\n");
}
if (gpio_is_valid(ts->pdata->rst_gpio)) {
ret = gpio_request(ts->pdata->rst_gpio, "goodix_ts_rst");
if (ret < 0) {
dev_err(&ts->client->dev,
"Failed to request GPIO:%d, ERRNO:%d\n",
(s32)ts->pdata->rst_gpio, ret);
if (gpio_is_valid(ts->pdata->irq_gpio))
gpio_free(ts->pdata->irq_gpio);
return -ENODEV;
}
gpio_direction_input(ts->pdata->rst_gpio);
dev_info(&ts->client->dev, "Success request rst-gpio\n");
}
return 0;
}
/*******************************************************
* Function:
* Request interrupt if define irq pin, else use hrtimer
* as interrupt source
* Input:
* ts: private data.
* Output:
* Executive outcomes.
* 0: succeed, -1: failed.
*******************************************************/
static int gtp_request_irq(struct goodix_ts_data *ts)
{
int ret = -1;
/* use irq */
if (gpio_is_valid(ts->pdata->irq_gpio) || ts->client->irq > 0) {
if (gpio_is_valid(ts->pdata->irq_gpio))
ts->client->irq = gpio_to_irq(ts->pdata->irq_gpio);
dev_info(&ts->client->dev, "INT num %d, trigger type:%d\n",
ts->client->irq, ts->pdata->irq_flags);
ret = request_threaded_irq(ts->client->irq, NULL,
gtp_irq_handler,
ts->pdata->irq_flags | IRQF_ONESHOT,
ts->client->name,
ts);
if (ret < 0) {
dev_err(&ts->client->dev,
"Failed to request irq %d\n", ts->client->irq);
return ret;
}
} else { /* use hrtimer */
dev_info(&ts->client->dev, "No hardware irq, use hrtimer\n");
hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = gtp_timer_handler;
hrtimer_start(&ts->timer,
ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
HRTIMER_MODE_REL);
set_bit(HRTIMER_USED, &ts->flags);
ret = 0;
}
return ret;
}
static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
{
s8 ret = -1;
u8 index = 0;
ts->input_dev = input_allocate_device();
if (!ts->input_dev) {
dev_err(&ts->client->dev, "Failed to allocate input device\n");
return -ENOMEM;
}
ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY)
| BIT_MASK(EV_ABS);
if (!ts->pdata->type_a_report) {
input_mt_init_slots(ts->input_dev, 16, INPUT_MT_DIRECT);
dev_info(&ts->client->dev, "Use slot report protocol\n");
} else {
__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
__set_bit(BTN_TOUCH, ts->input_dev->keybit);
dev_info(&ts->client->dev, "Use type A report protocol\n");
}
input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON1);
input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON2);
/* touch key register */
for (index = 0; index < ts->pdata->key_nums; index++)
input_set_capability(ts->input_dev, EV_KEY,
ts->pdata->key_map[index]);
if (ts->pdata->slide_wakeup)
input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
if (ts->pdata->swap_x2y)
GTP_SWAP(ts->pdata->abs_size_x, ts->pdata->abs_size_y);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0,
ts->pdata->abs_size_x, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0,
ts->pdata->abs_size_y, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0,
ts->pdata->max_touch_width, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0,
ts->pdata->max_touch_pressure, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0,
ts->pdata->max_touch_id, 0, 0);
if (!ts->pdata->type_a_report) {
input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0);
} else {
__set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
__set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit);
}
ts->input_dev->name = goodix_ts_name;
ts->input_dev->phys = goodix_input_phys;
ts->input_dev->id.bustype = BUS_I2C;
ts->input_dev->id.vendor = 0xDEAD;
ts->input_dev->id.product = 0xBEEF;
ts->input_dev->id.version = 10427;
ret = input_register_device(ts->input_dev);
if (ret) {
dev_err(&ts->client->dev, "Register %s input device failed\n",
ts->input_dev->name);
input_free_device(ts->input_dev);
return -ENODEV;
}
return 0;
}
/*
* Devices Tree support
*/
#ifdef CONFIG_OF
static void gtp_parse_dt_coords(struct device *dev,
struct goodix_ts_platform_data *pdata)
{
struct device_node *np = dev->of_node;
int ret;
ret = of_property_read_u32(np, "touchscreen-max-id",
&pdata->max_touch_id);
if (ret || pdata->max_touch_id > GTP_MAX_TOUCH_ID) {
dev_info(dev, "Unset touchscreen-max-id, use default\n");
pdata->max_touch_id = GTP_MAX_TOUCH_ID;
}
ret = of_property_read_u32(np, "touchscreen-size-x",
&pdata->abs_size_x);
if (ret) {
dev_info(dev, "Unset touchscreen-size-x, use default\n");
pdata->abs_size_x = GTP_DEFAULT_MAX_X;
}
ret = of_property_read_u32(np, "touchscreen-size-y",
&pdata->abs_size_y);
if (ret) {
dev_info(dev, "Unset touchscreen-size-y, use default\n");
pdata->abs_size_y = GTP_DEFAULT_MAX_Y;
}
ret = of_property_read_u32(np, "touchscreen-max-w",
&pdata->max_touch_width);
if (ret) {
dev_info(dev, "Unset touchscreen-max-w, use default\n");
pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH;
}
ret = of_property_read_u32(np, "touchscreen-max-p",
&pdata->max_touch_pressure);
if (ret) {
dev_info(dev, "Unset touchscreen-max-p, use default\n");
pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE;
}
dev_info(dev, "touch input parameters is [id x y w p]<%d %d %d %d %d>\n",
pdata->max_touch_id, pdata->abs_size_x, pdata->abs_size_y,
pdata->max_touch_width, pdata->max_touch_pressure);
}
static int gtp_parse_dt(struct device *dev,
struct goodix_ts_platform_data *pdata)
{
int ret;
u32 key_nums;
struct property *prop;
u32 key_map[MAX_KEY_NUMS];
struct device_node *np = dev->of_node;
gtp_parse_dt_coords(dev, pdata);
ret = of_property_read_u32(np, "irq-flags",
&pdata->irq_flags);
if (ret) {
dev_info(dev,
"Failed get int-trigger-type from dts,set default\n");
pdata->irq_flags = GTP_DEFAULT_INT_TRIGGER;
}
of_property_read_u32(np, "goodix,int-sync", &pdata->int_sync);
if (pdata->int_sync)
dev_info(dev, "int-sync enabled\n");
of_property_read_u32(np, "goodix,driver-send-cfg",
&pdata->driver_send_cfg);
if (pdata->driver_send_cfg)
dev_info(dev, "driver-send-cfg enabled\n");
of_property_read_u32(np, "goodix,swap-x2y", &pdata->swap_x2y);
if (pdata->swap_x2y)
dev_info(dev, "swap-x2y enabled\n");
of_property_read_u32(np, "goodix,slide-wakeup", &pdata->slide_wakeup);
if (pdata->slide_wakeup)
dev_info(dev, "slide-wakeup enabled\n");
of_property_read_u32(np, "goodix,auto-update", &pdata->auto_update);
if (pdata->auto_update)
dev_info(dev, "auto-update enabled\n");
of_property_read_u32(np, "goodix,auto-update-cfg",
&pdata->auto_update_cfg);
if (pdata->auto_update_cfg)
dev_info(dev, "auto-update-cfg enabled\n");
of_property_read_u32(np, "goodix,esd-protect", &pdata->esd_protect);
if (pdata->esd_protect)
dev_info(dev, "esd-protect enabled\n");
of_property_read_u32(np, "goodix,type-a-report",
&pdata->type_a_report);
if (pdata->type_a_report)
dev_info(dev, "type-a-report enabled\n");
of_property_read_u32(np, "goodix,resume-in-workqueue",
&pdata->resume_in_workqueue);
if (pdata->resume_in_workqueue)
dev_info(dev, "resume-in-workqueue enabled\n");
of_property_read_u32(np, "goodix,power-off-sleep",
&pdata->power_off_sleep);
if (pdata->power_off_sleep)
dev_info(dev, "power-off-sleep enabled\n");
of_property_read_u32(np, "goodix,pen-suppress-finger",
&pdata->pen_suppress_finger);
if (pdata->pen_suppress_finger)
dev_info(dev, "pen-suppress-finger enabled\n");
prop = of_find_property(np, "touchscreen-key-map", NULL);
if (prop) {
key_nums = prop->length / sizeof(key_map[0]);
key_nums = key_nums > MAX_KEY_NUMS ? MAX_KEY_NUMS : key_nums;
dev_dbg(dev, "key nums %d\n", key_nums);
ret = of_property_read_u32_array(np,
"touchscreen-key-map", key_map,
key_nums);
if (ret) {
dev_err(dev, "Unable to read key codes\n");
pdata->key_nums = 0;
memset(pdata->key_map, 0,
MAX_KEY_NUMS * sizeof(pdata->key_map[0]));
}
pdata->key_nums = key_nums;
memcpy(pdata->key_map, key_map,
key_nums * sizeof(pdata->key_map[0]));
dev_info(dev, "key-map is [%x %x %x %x]\n",
pdata->key_map[0], pdata->key_map[1],
pdata->key_map[2], pdata->key_map[3]);
}
pdata->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0);
if (!gpio_is_valid(pdata->irq_gpio))
dev_err(dev, "No valid irq gpio");
pdata->rst_gpio = of_get_named_gpio(np, "reset-gpios", 0);
if (!gpio_is_valid(pdata->rst_gpio))
dev_err(dev, "No valid rst gpio");
return 0;
}
/*******************************************************
* Function:
* parse config data from devices tree.
* Input:
* dev: device that this driver attached.
* cfg: pointer of the config array.
* cfg_len: pointer of the config length.
* sid: sensor id.
* Output:
* Executive outcomes.
* 0-succeed, -1-faileds.
*******************************************************/
int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid)
{
struct device_node *np = dev->of_node;
struct property *prop;
char cfg_name[18];
int ret;
snprintf(cfg_name, sizeof(cfg_name), "goodix,cfg-group%d", sid);
prop = of_find_property(np, cfg_name, cfg_len);
if (!prop || !prop->value || *cfg_len == 0 ||
*cfg_len > GTP_CONFIG_MAX_LENGTH) {
*cfg_len = 0;
ret = -EPERM;/* failed */
} else {
memcpy(cfg, prop->value, *cfg_len);
ret = 0;
}
return ret;
}
#endif
static int gtp_power_on(struct goodix_ts_data *ts)
{
int ret = 0;
if (ts->vdd_ana) {
ret = regulator_set_voltage(ts->vdd_ana, GOODIX_VTG_MIN_UV,
GOODIX_VTG_MAX_UV);
if (ret) {
dev_err(&ts->client->dev,
"Regulator set_vtg failed vdd ret=%d\n",
ret);
goto err_set_vtg_vdd_ana;
}
ret = regulator_enable(ts->vdd_ana);
if (ret) {
dev_err(&ts->client->dev,
"Regulator vdd enable failed ret=%d\n",
ret);
goto err_enable_vdd_ana;
}
}
if (ts->vcc_i2c) {
ret = regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV,
GOODIX_I2C_VTG_MAX_UV);
if (ret) {
dev_err(&ts->client->dev,
"Regulator set_vtg failed vcc_i2c ret=%d\n",
ret);
goto err_set_vtg_vcc_i2c;
}
ret = regulator_enable(ts->vcc_i2c);
if (ret) {
dev_err(&ts->client->dev,
"Regulator vcc_i2c enable failed ret=%d\n",
ret);
goto err_enable_vcc_i2c;
}
}
clear_bit(POWER_OFF_MODE, &ts->flags);
return 0;
err_enable_vcc_i2c:
if (ts->vcc_i2c)
regulator_set_voltage(ts->vcc_i2c, 0, GOODIX_I2C_VTG_MAX_UV);
err_set_vtg_vcc_i2c:
if (ts->vdd_ana)
regulator_disable(ts->vdd_ana);
err_enable_vdd_ana:
if (ts->vdd_ana)
regulator_set_voltage(ts->vdd_ana, 0, GOODIX_VTG_MAX_UV);
err_set_vtg_vdd_ana:
set_bit(POWER_OFF_MODE, &ts->flags);
return ret;
}
static int gtp_power_off(struct goodix_ts_data *ts)
{
int ret = 0;
if (ts->vcc_i2c) {
set_bit(POWER_OFF_MODE, &ts->flags);
ret = regulator_set_voltage(ts->vcc_i2c, 0,
GOODIX_I2C_VTG_MAX_UV);
if (ret < 0) {
dev_err(&ts->client->dev,
"Regulator vcc_i2c set_vtg failed ret=%d\n",
ret);
goto err_set_vtg_vcc_i2c;
}
ret = regulator_disable(ts->vcc_i2c);
if (ret) {
dev_err(&ts->client->dev,
"Regulator vcc_i2c disable failed ret=%d\n",
ret);
goto err_disable_vcc_i2c;
}
dev_info(&ts->client->dev,
"Regulator vcc_i2c disabled\n");
}
if (ts->vdd_ana) {
set_bit(POWER_OFF_MODE, &ts->flags);
ret = regulator_set_voltage(ts->vdd_ana, 0, GOODIX_VTG_MAX_UV);
if (ret < 0) {
dev_err(&ts->client->dev,
"Regulator vdd set_vtg failed ret=%d\n",
ret);
goto err_set_vtg_vdd_ana;
}
ret = regulator_disable(ts->vdd_ana);
if (ret) {
dev_err(&ts->client->dev,
"Regulator vdd disable failed ret=%d\n",
ret);
goto err_disable_vdd_ana;
}
dev_info(&ts->client->dev,
"Regulator vdd_ana disabled\n");
}
return ret;
err_disable_vdd_ana:
if (ts->vdd_ana)
regulator_set_voltage(ts->vdd_ana, GOODIX_VTG_MIN_UV,
GOODIX_VTG_MAX_UV);
err_set_vtg_vdd_ana:
if (ts->vcc_i2c)
ret = regulator_enable(ts->vcc_i2c);
err_disable_vcc_i2c:
if (ts->vcc_i2c)
regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV,
GOODIX_I2C_VTG_MAX_UV);
err_set_vtg_vcc_i2c:
clear_bit(POWER_OFF_MODE, &ts->flags);
return ret;
}
static int gtp_power_init(struct goodix_ts_data *ts)
{
int ret;
ts->vdd_ana = regulator_get(&ts->client->dev, "vdd_ana");
if (IS_ERR(ts->vdd_ana)) {
ts->vdd_ana = NULL;
ret = PTR_ERR(ts->vdd_ana);
dev_info(&ts->client->dev,
"Regulator get failed vdd ret=%d\n", ret);
}
ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc_i2c");
if (IS_ERR(ts->vcc_i2c)) {
ts->vcc_i2c = NULL;
ret = PTR_ERR(ts->vcc_i2c);
dev_info(&ts->client->dev,
"Regulator get failed vcc_i2c ret=%d\n", ret);
}
return 0;
}
static int gtp_power_deinit(struct goodix_ts_data *ts)
{
if (ts->vdd_ana)
regulator_put(ts->vdd_ana);
if (ts->vcc_i2c)
regulator_put(ts->vcc_i2c);
return 0;
}
static void gtp_shutdown(struct i2c_client *client)
{
struct goodix_ts_data *data = i2c_get_clientdata(client);
if (!data->init_done)
return;
gtp_work_control_enable(data, false);
gtp_power_off(data);
}
static int gtp_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret = -1;
struct goodix_ts_data *ts;
struct goodix_ts_platform_data *pdata;
/* do NOT remove these logs */
dev_info(&client->dev, "GTP Driver Version: %s\n", GTP_DRIVER_VERSION);
dev_info(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr);
i2c_connect_client = client;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "Failed check I2C functionality");
return -ENODEV;
}
ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
devm_kfree(&client->dev, ts);
return -EINVAL;
}
ts->init_done = false;
#ifdef CONFIG_OF
if (client->dev.of_node) {
ret = gtp_parse_dt(&client->dev, pdata);
if (ret) {
dev_err(&client->dev, "Failed parse dts\n");
goto exit_free_client_data;
}
}
#else
/* set parameters at here if you platform doesn't DTS */
pdata->rst_gpio = GTP_RST_PORT;
pdata->irq_gpio = GTP_INT_PORT;
pdata->slide_wakeup = false;
pdata->auto_update = true;
pdata->auto_update_cfg = false;
pdata->type_a_report = false;
pdata->esd_protect = false;
pdata->max_touch_id = GTP_MAX_TOUCH_ID;
pdata->abs_size_x = GTP_DEFAULT_MAX_X;
pdata->abs_size_y = GTP_DEFAULT_MAX_Y;
pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH;
pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE;
#endif
ts->client = client;
ts->pdata = pdata;
i2c_set_clientdata(client, ts);
ret = gtp_power_init(ts);
if (ret) {
dev_err(&client->dev, "Failed get regulator\n");
ret = -EINVAL;
goto exit_free_client_data;
}
ret = gtp_pinctrl_init(ts);
if (ret < 0) {
/* if define pinctrl must define the following state
* to let int-pin work normally: default, int_output_high,
* int_output_low, int_input
*/
dev_err(&client->dev, "Failed get wanted pinctrl state\n");
goto exit_deinit_power;
}
ret = gtp_request_io_port(ts);
if (ret < 0) {
dev_err(&client->dev, "Failed request IO port\n");
goto exit_pinctrl;
}
/*wait for discharging power, which from i2c pull-up flow backward*/
gtp_rst_output(ts, 0);
msleep(DELAY_FOR_DISCHARGING);
ret = gtp_power_on(ts);
if (ret) {
dev_err(&client->dev, "Failed power on device\n");
ret = -EINVAL;
goto exit_free_io_port;
}
gtp_reset_guitar(ts->client, 20);
ret = gtp_i2c_test(client);
if (ret) {
dev_err(&client->dev, "Failed communicate with IC use I2C\n");
goto exit_power_off;
}
dev_info(&client->dev, "I2C Addr is %x\n", client->addr);
ret = gtp_get_fw_info(client, &ts->fw_info);
if (ret < 0) {
dev_err(&client->dev, "Failed read FW version\n");
goto exit_power_off;
}
pdata->config.data[0] = GTP_REG_CONFIG_DATA >> 8;
pdata->config.data[1] = GTP_REG_CONFIG_DATA & 0xff;
ret = gtp_init_panel(ts);
if (ret < 0)
dev_info(&client->dev, "Panel un-initialize\n");
#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
if (ts->pdata->auto_update) {
ret = gup_init_update_proc(ts);
if (ret < 0)
dev_err(&client->dev, "Failed create update thread\n");
}
#endif
ret = gtp_request_input_dev(ts);
if (ret < 0) {
dev_err(&client->dev, "Failed request input device\n");
goto exit_power_off;
}
mutex_init(&ts->lock);
ret = gtp_request_irq(ts);
if (ret < 0) {
dev_err(&client->dev, "Failed create work thread");
goto exit_unreg_input_dev;
}
gtp_work_control_enable(ts, false);
if (ts->pdata->slide_wakeup) {
dev_info(&client->dev, "slide wakeup enabled\n");
ret = enable_irq_wake(client->irq);
if (ret < 0)
dev_err(&client->dev, "Failed set irq wake\n");
}
gtp_register_powermanager(ts);
ret = gtp_create_file(ts);
if (ret) {
dev_info(&client->dev, "Failed create attributes file");
goto exit_powermanager;
}
#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL
init_wr_node(client);/*TODO judge return value */
#endif
gtp_esd_init(ts);
gtp_esd_on(ts);
/* probe init finished */
ts->init_done = true;
gtp_work_control_enable(ts, true);
return 0;
exit_powermanager:
gtp_unregister_powermanager(ts);
exit_unreg_input_dev:
input_unregister_device(ts->input_dev);
exit_power_off:
gtp_power_off(ts);
exit_free_io_port:
if (gpio_is_valid(ts->pdata->rst_gpio))
gpio_free(ts->pdata->rst_gpio);
if (gpio_is_valid(ts->pdata->irq_gpio))
gpio_free(ts->pdata->irq_gpio);
exit_pinctrl:
gtp_pinctrl_deinit(ts);
exit_deinit_power:
gtp_power_deinit(ts);
exit_free_client_data:
devm_kfree(&client->dev, pdata);
devm_kfree(&client->dev, ts);
i2c_set_clientdata(client, NULL);
return ret;
}
static int gtp_drv_remove(struct i2c_client *client)
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
gtp_work_control_enable(ts, false);
gtp_unregister_powermanager(ts);
remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc);
sysfs_remove_group(&client->dev.kobj, &gtp_attr_group);
#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL
uninit_wr_node();
#endif
if (ts->pdata->esd_protect)
gtp_esd_off(ts);
/* TODO: how to judge a irq numbers validity */
if (ts->client->irq)
free_irq(client->irq, ts);
else
hrtimer_cancel(&ts->timer);
if (gpio_is_valid(ts->pdata->rst_gpio))
gpio_free(ts->pdata->rst_gpio);
if (gpio_is_valid(ts->pdata->irq_gpio))
gpio_free(ts->pdata->irq_gpio);
gtp_power_off(ts);
gtp_power_deinit(ts);
gtp_pinctrl_deinit(ts);
dev_info(&client->dev, "goodix ts driver removed");
i2c_set_clientdata(client, NULL);
input_unregister_device(ts->input_dev);
mutex_destroy(&ts->lock);
devm_kfree(&client->dev, ts->pdata);
devm_kfree(&client->dev, ts);
return 0;
}
static void gtp_suspend(struct goodix_ts_data *ts)
{
int ret = -1;
if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) {
dev_warn(&ts->client->dev,
"Fw upgrade in progress, can't go to suspend\n");
return;
}
if (test_and_set_bit(SLEEP_MODE, &ts->flags)) {
dev_info(&ts->client->dev, "Already in suspend state\n");
return;
}
dev_dbg(&ts->client->dev, "Try enter suspend mode\n");
gtp_esd_off(ts);
gtp_work_control_enable(ts, false);
if (ts->pdata->slide_wakeup) {
ret = gtp_enter_doze(ts);
gtp_work_control_enable(ts, true);
} else if (ts->pdata->power_off_sleep) {
/*TODO: power off routine */
gtp_power_off(ts);
ret = SUCCESS;
} else {
ret = gtp_enter_sleep(ts);
}
if (ret < 0)
dev_err(&ts->client->dev, "Failed enter suspend\n");
/* to avoid waking up while not sleeping */
/* delay 48 + 10ms to ensure reliability */
msleep(GTP_58_DLY_MS);
}
static int gtp_gesture_wakeup(struct goodix_ts_data *ts)
{
int ret;
int retry = 10;
do {
gtp_reset_guitar(ts->client, 10);
ret = gtp_i2c_test(ts->client);
if (!ret)
break;
} while (--retry);
if (!retry)
ret = -EIO;
clear_bit(DOZE_MODE, &ts->flags);
return ret;
}
static void gtp_resume(struct goodix_ts_data *ts)
{
int ret = 0;
if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) {
dev_info(&ts->client->dev,
"Fw upgrade in progress, can't do resume\n");
return;
}
if (!test_bit(SLEEP_MODE, &ts->flags)) {
dev_dbg(&ts->client->dev, "Already in awake state\n");
return;
}
dev_info(&ts->client->dev, "Try resume from sleep mode\n");
gtp_work_control_enable(ts, false);
if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) {
ret = gtp_gesture_wakeup(ts);
if (ret)
dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n");
} else if (ts->pdata->power_off_sleep) {
ret = gtp_power_on(ts);
if (ret) {
dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n");
} else {
gtp_reset_guitar(ts->client, 20);
ret = gtp_i2c_test(ts->client);
if (ret)
dev_warn(&ts->client->dev,
"I2C communicate failed after power on\n");
}
} else {
ret = gtp_wakeup_sleep(ts);
if (ret)
dev_warn(&ts->client->dev,
"Failed wakeup from sleep mode\n");
}
if (ret)
dev_warn(&ts->client->dev, "Later resume failed\n");
else
gtp_esd_on(ts);
clear_bit(SLEEP_MODE, &ts->flags);
gtp_work_control_enable(ts, true);
}
#if defined(CONFIG_FB)
static void fb_notify_resume_work(struct work_struct *work)
{
struct goodix_ts_data *ts =
container_of(work, struct goodix_ts_data, fb_notify_work);
dev_info(&ts->client->dev, "try resume in workqueue\n");
gtp_resume(ts);
}
/* frame buffer notifier block control the suspend/resume procedure */
static int gtp_fb_notifier_callback(struct notifier_block *noti,
unsigned long event, void *data)
{
struct fb_event *ev_data = data;
struct goodix_ts_data *ts = container_of(noti,
struct goodix_ts_data, notifier);
int *blank;
if (ev_data && ev_data->data && event == FB_EVENT_BLANK && ts) {
blank = ev_data->data;
if (*blank == FB_BLANK_UNBLANK ||
*blank == FB_BLANK_NORMAL) {
dev_dbg(&ts->client->dev, "ts_resume");
if (ts->pdata->resume_in_workqueue)
schedule_work(&ts->fb_notify_work);
else
gtp_resume(ts);
} else if (*blank == FB_BLANK_POWERDOWN) {
dev_dbg(&ts->client->dev, "ts_suspend");
if (ts->pdata->resume_in_workqueue)
flush_work(&ts->fb_notify_work);
gtp_suspend(ts);
}
}
return 0;
}
#elif defined(CONFIG_PM)
static int gtp_pm_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct goodix_ts_data *ts = i2c_get_clientdata(client);
if (ts) {
dev_dbg(&ts->client->dev, "Suspend by i2c pm.");
gtp_suspend(ts);
}
return 0;
}
static int gtp_pm_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct goodix_ts_data *ts = i2c_get_clientdata(client);
if (ts) {
dev_dbg(&ts->client->dev, "Resume by i2c pm.");
gtp_resume(ts);
}
return 0;
}
static const struct dev_pm_ops gtp_pm_ops = {
.suspend = gtp_pm_suspend,
.resume = gtp_pm_resume,
};
#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void gtp_early_suspend(struct early_suspend *h)
{
struct goodix_ts_data *ts = container_of(h,
struct goodix_ts_data, early_suspend);
if (ts) {
dev_dbg(&ts->client->dev, "Suspend by earlysuspend module.");
gtp_suspend(ts);
}
}
static void gtp_late_resume(struct early_suspend *h)
{
struct goodix_ts_data *ts = container_of(h,
struct goodix_ts_data, early_suspend);
if (ts) {
dev_dbg(&ts->client->dev, "Resume by earlysuspend module.");
gtp_resume(ts);
}
}
#endif
static int gtp_register_powermanager(struct goodix_ts_data *ts)
{
int ret;
#if defined(CONFIG_FB)
INIT_WORK(&ts->fb_notify_work, fb_notify_resume_work);
ts->notifier.notifier_call = gtp_fb_notifier_callback;
ret = fb_register_client(&ts->notifier);
if (ret)
dev_err(&ts->client->dev,
"Unable to register fb_notifier: %d\n", ret);
#elif defined(CONFIG_HAS_EARLYSUSPEND)
ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
ts->early_suspend.suspend = goodix_ts_early_suspend;
ts->early_suspend.resume = goodix_ts_late_resume;
register_early_suspend(&ts->early_suspend);
#endif
return ret;
}
static int gtp_unregister_powermanager(struct goodix_ts_data *ts)
{
#if defined(CONFIG_FB)
fb_unregister_client(&ts->notifier);
#elif defined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&ts->early_suspend);
#endif
return 0;
}
/*******************************************************
* Function:
* Initialize external watchdog for esd protect
* Input:
* client: i2c device.
* Output:
* result of i2c write operation.
* 0: succeed, otherwise: failed
********************************************************/
static int gtp_init_ext_watchdog(struct i2c_client *client)
{
int ret;
u8 opr_buffer[3] = { (u8)(GTP_REG_ESD_CHECK >> 8),
(u8)GTP_REG_ESD_CHECK,
(u8)GTP_ESD_CHECK_VALUE };
dev_dbg(&client->dev, "[Esd]Init external watchdog\n");
ret = gtp_i2c_write(client, opr_buffer, 3);
if (ret == 1)
return 0;
dev_err(&client->dev, "Failed init ext watchdog\n");
return -EINVAL;
}
static void gtp_esd_check_func(struct work_struct *work)
{
s32 i;
s32 ret = -1;
u8 esd_buf[5] = { (u8)(GTP_REG_COMMAND >> 8), (u8)GTP_REG_COMMAND };
struct delayed_work *dwork = to_delayed_work(work);
struct goodix_ts_esd *ts_esd = container_of(dwork, struct goodix_ts_esd,
delayed_work);
struct goodix_ts_data *ts = container_of(ts_esd, struct goodix_ts_data,
ts_esd);
if (test_bit(SLEEP_MODE, &ts->flags) ||
test_bit(FW_UPDATE_RUNNING, &ts->flags)) {
dev_dbg(&ts->client->dev,
"Esd cancled by power_suspend or fw_update!");
return;
}
if (ts_esd->esd_on == false)
return;
for (i = 0; i < 3; i++) {
ret = gtp_i2c_read(ts->client, esd_buf, 4);
if (ret < 0)
continue;
dev_dbg(&ts->client->dev,
"[Esd]0x8040 = 0x%02X, 0x8041 = 0x%02X",
esd_buf[2], esd_buf[3]);
if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE ||
esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) {
gtp_i2c_read(ts->client, esd_buf, 4);
if (ret < 0)
continue;
if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE ||
esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) {
i = 3;
break;
}
} else {
/* IC works normally, Write 0x8040 0xAA, feed the dog */
esd_buf[2] = (u8)GTP_ESD_CHECK_VALUE;
gtp_i2c_write(ts->client, esd_buf, 3);
break;
}
}
if (i >= 3) {
dev_err(&ts->client->dev, "IC working abnormally! Reset IC\n");
esd_buf[0] = 0x42;
esd_buf[1] = 0x26;
esd_buf[2] = 0x01;
esd_buf[3] = 0x01;
esd_buf[4] = 0x01;
gtp_i2c_write(ts->client, esd_buf, 5);
/* TODO: Is power off really need? */
msleep(GTP_50_DLY_MS);
gtp_power_off(ts);
msleep(GTP_20_DLY_MS);
gtp_power_on(ts);
msleep(GTP_20_DLY_MS);
gtp_reset_guitar(ts->client, 50);
msleep(GTP_50_DLY_MS);
gtp_send_cfg(ts->client);
}
if (ts_esd->esd_on == true && !test_bit(SLEEP_MODE, &ts->flags)) {
schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ);
dev_dbg(&ts->client->dev, "ESD work rescheduled\n");
}
}
static int gtp_esd_init(struct goodix_ts_data *ts)
{
struct goodix_ts_esd *ts_esd = &ts->ts_esd;
INIT_DELAYED_WORK(&ts_esd->delayed_work, gtp_esd_check_func);
mutex_init(&ts_esd->mutex);
ts_esd->esd_on = false;
return 0;
}
void gtp_esd_on(struct goodix_ts_data *ts)
{
struct goodix_ts_esd *ts_esd = &ts->ts_esd;
if (!ts->pdata->esd_protect)
return;
mutex_lock(&ts_esd->mutex);
if (ts_esd->esd_on == false) {
ts_esd->esd_on = true;
schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ);
dev_info(&ts->client->dev, "ESD on");
}
mutex_unlock(&ts_esd->mutex);
}
void gtp_esd_off(struct goodix_ts_data *ts)
{
struct goodix_ts_esd *ts_esd = &ts->ts_esd;
if (!ts->pdata->esd_protect)
return;
mutex_lock(&ts_esd->mutex);
if (ts_esd->esd_on == true) {
ts_esd->esd_on = false;
cancel_delayed_work_sync(&ts_esd->delayed_work);
dev_info(&ts->client->dev, "ESD off");
}
mutex_unlock(&ts_esd->mutex);
}
#ifdef CONFIG_OF
static const struct of_device_id gtp_match_table[] = {
{.compatible = "goodix,gt9xx",},
{ },
};
#endif
static const struct i2c_device_id gtp_device_id[] = {
{ GTP_I2C_NAME, 0 },
{ }
};
static struct i2c_driver goodix_ts_driver = {
.probe = gtp_probe,
.remove = gtp_drv_remove,
.id_table = gtp_device_id,
.shutdown = gtp_shutdown,
.driver = {
.name = GTP_I2C_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = gtp_match_table,
#endif
#if !defined(CONFIG_FB) && defined(CONFIG_PM)
.pm = &gtp_pm_ops,
#endif
},
};
static int __init gtp_init(void)
{
s32 ret;
pr_info("Gt9xx driver installing..\n");
ret = i2c_add_driver(&goodix_ts_driver);
return ret;
}
static void __exit gtp_exit(void)
{
pr_info("Gt9xx driver exited\n");
i2c_del_driver(&goodix_ts_driver);
}
module_init(gtp_init);
module_exit(gtp_exit);
MODULE_DESCRIPTION("GT9 serials touch controller Driver");
MODULE_LICENSE("GPL v2");