blob: 299c969c9a908f363536e1a2f3a4851faf59b05e [file] [log] [blame]
/*
* drivers/input/touchscreen/hyncst226.c
*
* Copyright (c) 2017 ShenZheng Hynitron
* Ying Zhang<ying.zhang@hynitron.com.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#endif
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/async.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <asm/irq.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/input/mt.h>
#include"cst226firmware.h"
#define TP_RESET_PIN 3
#define TP_I2C_ADAPTER (1)
#define TP_I2C_ADDR 0x1A
#define TP_NAME "CST226"
#define TP_IRQ_PORT 100
#define TP_MAX_X 1024
#define TP_MAX_Y 600
static unsigned int gpio_reset;
static unsigned int gpio_irq;
static unsigned int gpio_irq_exist;
static unsigned int gpio_reset_exist;
#define CST226_I2C_NAME "cst226"
#define CST226_I2C_ADDR 0x1A
#define CFG_TP_USE_CONFIG 1
#if CFG_TP_USE_CONFIG
struct tp_cfg_xml {
unsigned int sirq;
unsigned int i2cNum;
unsigned int i2cAddr;
unsigned int xMax;
unsigned int yMax;
unsigned int rotate;
unsigned int xRevert;
unsigned int yRevert;
};
static struct tp_cfg_xml cfg_xml;
#endif
#define RESUME_INIT_CHIP_WORK
#define REPORT_DATA_PROTOCOL_B
#define SLEEP_RESUME_CLEAR_POINT
#define ICS_SLOT_REPORT
#define HIGH_SPEED_IIC_TRANSFER
#define RECORD_POINT
#ifdef FILTER_POINT
#define FILTER_MAX 9
#endif
#define HYN_DATA_REG 0x80
#define HYN_STATUS_REG 0xe0
#define HYN_PAGE_REG 0xf0
#define PRESS_MAX 255
#define MAX_FINGERS 10
#define MAX_CONTACTS 10
#define DMA_TRANS_LEN 0x10
#define SCREEN_MAX_X 600
#define SCREEN_MAX_Y 1024
struct mutex mutex;
static int power_is_on;
#ifdef HYN_MONITOR
static struct delayed_work hyn_monitor_work;
static struct workqueue_struct *hyn_monitor_workqueue;
static char int_1st[4] = { 0 };
static char int_2nd[4] = { 0 };
static char bc_counter;
static char b0_counter;
static char i2c_lock_flag;
static int clk_tick_cnt = 300;
#endif
static struct i2c_client *hyn_client;
static struct hyn_ts *this_ts;
#ifdef HAVE_TOUCH_KEY
static u16 key;
static int key_state_flag;
struct key_data {
u16 key;
u16 x_min;
u16 x_max;
u16 y_min;
u16 y_max;
};
const u16 key_array[] = {
KEY_BACK,
KEY_HOME,
KEY_MENU,
KEY_SEARCH,
};
struct key_data hyn_key_data[ARRAY_SIZE(key_array)] = {
{KEY_BACK, 2048, 2048, 2048, 2048},
{KEY_HOME, 2048, 2048, 2048, 2048},
{KEY_MENU, 2048, 2048, 2048, 2048},
{KEY_SEARCH, 2048, 2048, 2048, 2048},
};
#endif
struct hyn_ts_data {
u8 x_index;
u8 y_index;
u8 z_index;
u8 id_index;
u8 touch_index;
u8 data_reg;
u8 status_reg;
u8 data_size;
u8 touch_bytes;
u8 update_data;
u8 touch_meta_data;
u8 finger_size;
};
static struct hyn_ts_data devices[] = {
{
.x_index = 6,
.y_index = 4,
.z_index = 5,
.id_index = 7,
.data_reg = HYN_DATA_REG,
.status_reg = HYN_STATUS_REG,
.update_data = 0x4,
.touch_bytes = 4,
.touch_meta_data = 4,
.finger_size = 70,
},
};
struct hyn_ts {
struct i2c_client *client;
struct input_dev *input;
struct work_struct work;
struct workqueue_struct *wq;
#ifdef RESUME_INIT_CHIP_WORK
struct work_struct init_work;
struct workqueue_struct *init_wq;
#endif
struct hyn_ts_data *dd;
u8 *touch_data;
u8 device_id;
int irq;
#if defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif
};
#define CTP_POWER_ID ("sensor28")
#define CTP_POWER_MIN_VOL (3300000)
#define CTP_POWER_MAX_VOL (3300000)
int current_val;
static int cst226_shutdown_low(void)
{
gpio_direction_output(gpio_reset, 0);
return 0;
}
static int cst226_shutdown_high(void)
{
gpio_direction_output(gpio_reset, 1);
return 0;
}
#ifdef HIGH_SPEED_IIC_TRANSFER
static int cst2xx_i2c_read_register(struct i2c_client *client,
unsigned char *buf, int len)
{
struct i2c_msg msgs[2];
int ret = -1;
int retries = 0;
msgs[0].flags = 0;
msgs[0].addr = client->addr;
msgs[0].len = 2;
msgs[0].buf = buf;
msgs[1].flags = I2C_M_RD;
msgs[1].addr = client->addr;
msgs[1].len = len;
msgs[1].buf = buf;
while (retries < 5) {
ret = i2c_transfer(client->adapter, msgs, 2);
if (ret == 2)
break;
retries++;
}
return ret;
}
static int cst2xx_i2c_write(struct i2c_client *client, unsigned char *buf,
int len)
{
struct i2c_msg msg;
int ret = -1;
int retries = 0;
msg.flags = 0;
msg.addr = client->addr;
msg.len = len;
msg.buf = buf;
while (retries < 5) {
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret == 1)
break;
retries++;
}
return ret;
}
#else
static int cst2xx_i2c_read(struct i2c_client *client, unsigned char *buf,
int len)
{
int ret = -1;
int retries = 0;
while (retries < 5) {
ret = i2c_master_recv(client, buf, len);
if (ret <= 0)
retries++;
else
break;
}
return ret;
}
static int cst2xx_i2c_write(struct i2c_client *client, unsigned char *buf,
int len)
{
int ret = -1;
int retries = 0;
while (retries < 5) {
ret = i2c_master_send(client, buf, len);
if (ret <= 0)
retries++;
else
break;
}
return ret;
}
static int cst2xx_i2c_read_register(struct i2c_client *client,
unsigned char *buf, int len)
{
int ret = -1;
ret = cst2xx_i2c_write(client, buf, 2);
ret = cst2xx_i2c_read(client, buf, len);
return ret;
}
#endif
static int test_i2c(struct i2c_client *client)
{
int retry = 0;
int ret;
u8 buf[4];
buf[0] = 0xD1;
buf[1] = 0x06;
while (retry++ < 2) {
ret = cst2xx_i2c_write(client, buf, 2);
if (ret > 0)
return ret;
usleep_range(2000, 2010);
}
return ret;
}
void hard_reset_chip(int delay)
{
cst226_shutdown_high();
msleep(delay);
cst226_shutdown_low();
msleep(delay);
cst226_shutdown_high();
}
#if CFG_TP_USE_CONFIG
static int tp_get_config(struct i2c_client *client)
{
struct device_node *np;
np = client->dev.of_node;
gpio_irq = of_get_named_gpio(np, "irq-gpio", 0);
gpio_reset = of_get_named_gpio(np, "reset-gpio", 0);
if (!gpio_is_valid(gpio_irq) || !gpio_is_valid(gpio_reset))
return -EINVAL;
gpio_reset_exist = 1;
gpio_irq_exist = 1;
cfg_xml.xMax = TP_MAX_X;
cfg_xml.yMax = TP_MAX_Y;
cfg_xml.xRevert = 0;
cfg_xml.yRevert = 0;
cfg_xml.rotate = 1;
if (gpio_irq_exist == 1) {
if (gpio_request(gpio_irq, "ts_irq_gpio") != 0) {
gpio_free(gpio_irq);
return -EIO;
}
gpio_direction_input(gpio_irq);
}
if (gpio_reset_exist == 1) {
if (gpio_request(gpio_reset, CST226_I2C_NAME) != 0) {
gpio_free(gpio_reset);
return -EIO;
}
}
return 0;
}
#endif
#define CST2XX_BASE_ADDR (24 * 1024)
static int cst2xx_enter_download_mode(struct i2c_client *client)
{
int ret;
int i;
u8 buf[2];
hard_reset_chip(5);
for (i = 0; i < 20; i++) {
buf[0] = 0xD1;
buf[1] = 0x11;
ret = cst2xx_i2c_write(client, buf, 2);
if (ret < 0) {
usleep_range(1000, 1010);
continue;
}
usleep_range(4000, 4010);
buf[0] = 0xD0;
buf[1] = 0x01;
ret = cst2xx_i2c_read_register(client, buf, 1);
if (ret < 0) {
usleep_range(1000, 1010);
continue;
}
if (buf[0] == 0x55)
break;
}
if (buf[0] != 0x55)
return -1;
buf[0] = 0xD1;
buf[1] = 0x10;
ret = cst2xx_i2c_write(client, buf, 2);
if (ret < 0)
return -1;
return 0;
}
static int cst2xx_download_program(struct i2c_client *client,
unsigned char *data, int len)
{
int ret;
int i, j;
unsigned int wr_addr;
unsigned char *pData;
unsigned char *pSrc;
unsigned char *pDst;
unsigned char i2c_buf[8];
pData = kmalloc(sizeof(unsigned char) * (1024 + 4), GFP_KERNEL);
if (pData == NULL)
return -1;
pSrc = data;
for (i = 0; i < (len / 1024); i++) {
wr_addr = (i << 10) + CST2XX_BASE_ADDR;
pData[0] = (wr_addr >> 24) & 0xFF;
pData[1] = (wr_addr >> 16) & 0xFF;
pData[2] = (wr_addr >> 8) & 0xFF;
pData[3] = wr_addr & 0xFF;
pDst = pData + 4;
for (j = 0; j < 256; j++) {
*pDst = *(pSrc + 3);
*(pDst + 1) = *(pSrc + 2);
*(pDst + 2) = *(pSrc + 1);
*(pDst + 3) = *pSrc;
pDst += 4;
pSrc += 4;
}
#ifdef HIGH_SPEED_IIC_TRANSFER
for (j = 0; j < 256; j++) {
i2c_buf[0] = (wr_addr >> 24) & 0xFF;
i2c_buf[1] = (wr_addr >> 16) & 0xFF;
i2c_buf[2] = (wr_addr >> 8) & 0xFF;
i2c_buf[3] = wr_addr & 0xFF;
i2c_buf[4] = pData[j * 4 + 4 + 0];
i2c_buf[5] = pData[j * 4 + 4 + 1];
i2c_buf[6] = pData[j * 4 + 4 + 2];
i2c_buf[7] = pData[j * 4 + 4 + 3];
ret = cst2xx_i2c_write(client, i2c_buf, 8);
if (ret < 0)
goto ERR_OUT;
wr_addr += 4;
}
#else
ret = cst2xx_i2c_write(client, pData, 1024 + 4);
if (ret < 0)
goto ERR_OUT;
#endif
}
pData[3] = 0x20000FFC & 0xFF;
pData[2] = (0x20000FFC >> 8) & 0xFF;
pData[1] = (0x20000FFC >> 16) & 0xFF;
pData[0] = (0x20000FFC >> 24) & 0xFF;
pData[4] = 0x00;
pData[5] = 0x00;
pData[6] = 0x00;
pData[7] = 0x00;
ret = cst2xx_i2c_write(client, pData, 8);
if (ret < 0)
goto ERR_OUT;
pData[3] = 0xD013D013 & 0xFF;
pData[2] = (0xD013D013 >> 8) & 0xFF;
pData[1] = (0xD013D013 >> 16) & 0xFF;
pData[0] = (0xD013D013 >> 24) & 0xFF;
ret = cst2xx_i2c_write(client, pData, 4);
if (ret < 0)
goto ERR_OUT;
if (pData != NULL) {
kfree(pData);
pData = NULL;
}
return 0;
ERR_OUT:
if (pData != NULL) {
kfree(pData);
pData = NULL;
}
return -1;
}
static int cst2xx_read_checksum(struct i2c_client *client)
{
int ret;
int i;
unsigned int checksum;
unsigned int bin_checksum;
unsigned char buf[4];
unsigned char *pData;
for (i = 0; i < 10; i++) {
buf[0] = 0xD0;
buf[1] = 0x00;
ret = cst2xx_i2c_read_register(client, buf, 1);
if (ret < 0) {
usleep_range(2000, 2010);
continue;
}
if ((buf[0] == 0x01) || (buf[0] == 0x02))
break;
usleep_range(2000, 2010);
}
if ((buf[0] == 0x01) || (buf[0] == 0x02)) {
buf[0] = 0xD0;
buf[1] = 0x08;
ret = cst2xx_i2c_read_register(client, buf, 4);
if (ret < 0)
return -1;
checksum =
buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
pData = fwbin + 6160; //6*1024+16
bin_checksum =
pData[0] + (pData[1] << 8) + (pData[2] << 16) +
(pData[3] << 24);
buf[0] = 0xD0;
buf[1] = 0x01;
buf[2] = 0xA5;
ret = cst2xx_i2c_write(client, buf, 3);
if (ret < 0)
return -1;
} else {
return -1;
}
return 0;
}
static int cst2xx_update_firmware(struct i2c_client *client,
unsigned char *pdata, int data_len)
{
int ret;
int retry;
retry = 0;
start_flow:
ret = cst2xx_enter_download_mode(client);
if (ret < 0)
goto fail_retry;
ret = cst2xx_download_program(client, pdata, data_len);
if (ret < 0)
goto fail_retry;
usleep_range(3000, 3010);
ret = cst2xx_read_checksum(client);
if (ret < 0)
goto fail_retry;
return 0;
fail_retry:
if (retry < 4) {
retry++;
goto start_flow;
}
return -1;
}
static int cst2xx_boot_update_fw(struct i2c_client *client)
{
return cst2xx_update_firmware(client, fwbin, FW_BIN_SIZE);
}
static int cst2xx_check_code(struct i2c_client *client)
{
int retry = 0;
int ret;
unsigned char buf[4];
buf[0] = 0xD0;
buf[1] = 0x4C;
while (retry++ < 3) {
ret = cst2xx_i2c_read_register(client, buf, 1);
if (ret > 0)
break;
usleep_range(2000, 2010);
}
if ((buf[0] == 226) || (buf[0] == 237) || (buf[0] == 240))
return 0;
ret = cst2xx_boot_update_fw(client);
if (ret < 0)
return -2;
else
return 0;
}
static void init_chip(struct i2c_client *client)
{
int rc;
if (gpio_reset_exist == 1) {
cst226_shutdown_low();
msleep(20);
cst226_shutdown_high();
msleep(20);
}
rc = test_i2c(client);
if (rc <= 0)
return;
cst2xx_boot_update_fw(client);
}
static void cst2xx_touch_down(struct input_dev *input_dev, s32 id, s32 x, s32 y,
s32 w)
{
s32 temp_w = (w >> 1);
s32 temp = 0;
temp_w += (temp & 0x0007);
x = x * cfg_xml.xMax / 2048;
y = y * cfg_xml.yMax / 2048;
#if CFG_TP_USE_CONFIG
if (cfg_xml.rotate == 1) {
int tmp;
tmp = x;
x = y;
y = cfg_xml.xMax - tmp;
} else if (cfg_xml.rotate == 2) {
x = cfg_xml.xMax - x;
y = cfg_xml.yMax - y;
} else if (cfg_xml.rotate == 3) {
int tmp;
tmp = x;
x = cfg_xml.yMax - y;
y = tmp;
}
if (cfg_xml.xRevert == 1)
x = cfg_xml.xMax - x;
if (cfg_xml.yRevert == 1)
y = cfg_xml.yMax - y;
#endif
#ifdef ICS_SLOT_REPORT
input_mt_slot(input_dev, id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
input_report_abs(input_dev, ABS_MT_TRACKING_ID, id);
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, temp_w);
input_report_abs(input_dev, ABS_MT_WIDTH_MAJOR, temp_w);
#else
input_report_key(input_dev, BTN_TOUCH, 1);
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, temp_w);
input_report_abs(input_dev, ABS_MT_WIDTH_MAJOR, temp_w);
input_report_abs(input_dev, ABS_MT_TRACKING_ID, id);
input_mt_sync(input_dev);
#endif
}
static void cst2xx_touch_up(struct input_dev *input_dev, int id)
{
#ifdef ICS_SLOT_REPORT
input_mt_slot(input_dev, id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
#else
input_report_key(input_dev, BTN_TOUCH, 0);
input_mt_sync(input_dev);
#endif
}
int report_flag;
static void hyn_ts_xy_worker(struct work_struct *work)
{
u8 buf[30];
u8 i2c_buf[8];
u8 key_status, key_id, finger_id, sw;
u16 input_x = 0;
u16 input_y = 0;
u16 input_w = 0;
u8 cnt_up, cnt_down;
int i, ret, idx;
int cnt, i2c_len, len_1, len_2;
struct hyn_ts *ts = container_of(work, struct hyn_ts, work);
key_status = 0;
#ifdef HYN_MONITOR
if (i2c_lock_flag == 0)
i2c_lock_flag = 1;
else
return;
#endif
buf[0] = 0xD0;
buf[1] = 0x00;
ret = cst2xx_i2c_read_register(ts->client, buf, 7);
if (ret < 0)
goto OUT_PROCESS;
if (buf[0] == 0xAB)
goto OUT_PROCESS;
if (buf[6] != 0xAB)
goto OUT_PROCESS;
cnt = buf[5] & 0x7F;
if (cnt > MAX_FINGERS)
goto OUT_PROCESS;
if (buf[5] == 0x80) {
key_status = buf[0];
key_id = buf[1];
goto KEY_PROCESS;
} else if (cnt == 0x01) {
goto FINGER_PROCESS;
} else {
#ifdef HIGH_SPEED_IIC_TRANSFER
if ((buf[5] & 0x80) == 0x80) {
i2c_len = (cnt - 1) * 5 + 3;
len_1 = i2c_len;
for (idx = 0; idx < i2c_len; idx += 6) {
i2c_buf[0] = 0xD0;
i2c_buf[1] = 0x07 + idx;
if (len_1 >= 6) {
len_2 = 6;
len_1 -= 6;
} else {
len_2 = len_1;
len_1 = 0;
}
ret =
cst2xx_i2c_read_register(ts->client,
i2c_buf, len_2);
if (ret < 0)
goto OUT_PROCESS;
for (i = 0; i < len_2; i++)
buf[5 + idx + i] = i2c_buf[i];
}
i2c_len += 5;
key_status = buf[i2c_len - 3];
key_id = buf[i2c_len - 2];
} else {
i2c_len = (cnt - 1) * 5 + 1;
len_1 = i2c_len;
for (idx = 0; idx < i2c_len; idx += 6) {
i2c_buf[0] = 0xD0;
i2c_buf[1] = 0x07 + idx;
if (len_1 >= 6) {
len_2 = 6;
len_1 -= 6;
} else {
len_2 = len_1;
len_1 = 0;
}
ret =
cst2xx_i2c_read_register(ts->client,
i2c_buf, len_2);
if (ret < 0)
goto OUT_PROCESS;
for (i = 0; i < len_2; i++)
buf[5 + idx + i] = i2c_buf[i];
}
i2c_len += 5;
}
#else
if ((buf[5] & 0x80) == 0x80) {
buf[5] = 0xD0;
buf[6] = 0x07;
i2c_len = (cnt - 1) * 5 + 3;
ret =
cst2xx_i2c_read_register(ts->client, &buf[5],
i2c_len);
if (ret < 0)
goto OUT_PROCESS;
i2c_len += 5;
key_status = buf[i2c_len - 3];
key_id = buf[i2c_len - 2];
} else {
buf[5] = 0xD0;
buf[6] = 0x07;
i2c_len = (cnt - 1) * 5 + 1;
ret =
cst2xx_i2c_read_register(ts->client, &buf[5],
i2c_len);
if (ret < 0)
goto OUT_PROCESS;
i2c_len += 5;
}
#endif
if (buf[i2c_len - 1] != 0xAB)
goto OUT_PROCESS;
}
if ((cnt > 0) && (key_status & 0x80)) {
if (report_flag == 0xA5)
goto KEY_PROCESS;
}
FINGER_PROCESS:
i2c_buf[0] = 0xD0;
i2c_buf[1] = 0x00;
i2c_buf[2] = 0xAB;
ret = cst2xx_i2c_write(ts->client, i2c_buf, 3);
if (ret < 0)
hard_reset_chip(20);
idx = 0;
cnt_up = 0;
cnt_down = 0;
for (i = 0; i < cnt; i++) {
input_x =
(unsigned int)((buf[idx + 1] << 4) |
((buf[idx + 3] >> 4) & 0x0F));
input_y =
(unsigned int)((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0F));
input_w = (unsigned int)(buf[idx + 4]);
sw = (buf[idx] & 0x0F) >> 1;
finger_id = (buf[idx] >> 4) & 0x0F;
if (sw == 0x03) {
cst2xx_touch_down(ts->input, finger_id, input_x,
input_y, input_w);
cnt_down++;
} else {
cnt_up++;
cst2xx_touch_up(ts->input, finger_id);
}
idx += 5;
}
if (cnt_down == 0)
report_flag = 0;
else
report_flag = 0xCA;
input_sync(ts->input);
goto XY_WORK_END;
KEY_PROCESS:
i2c_buf[0] = 0xD0;
i2c_buf[1] = 0x00;
i2c_buf[2] = 0xAB;
ret = cst2xx_i2c_write(ts->client, i2c_buf, 3);
if (ret < 0)
hard_reset_chip(20);
#ifdef TPD_HAVE_BUTTON
if (key_status & 0x80) {
if ((key_status & 0x7F) == 0x03) {
i = (key_id >> 4) - 1;
cst2xx_touch_down(ts->input, tpd_keys_dim_local[i][0],
tpd_keys_dim_local[i][1], 0, 0);
report_flag = 0xA5;
} else {
cst2xx_touch_up(ts->input, 0);
report_flag = 0;
}
}
#endif
input_sync(ts->input);
goto XY_WORK_END;
OUT_PROCESS:
buf[0] = 0xD0;
buf[1] = 0x00;
buf[2] = 0xAB;
ret = cst2xx_i2c_write(ts->client, buf, 3);
if (ret < 0)
hard_reset_chip(20);
XY_WORK_END:
#ifdef HYN_MONITOR
i2c_lock_flag = 0;
i2c_lock_schedule:;
#endif
return;
}
#ifdef HYN_MONITOR
static void hyn_monitor_worker(struct work_struct *work)
{
int retry = 0;
int ret;
unsigned char buf[4];
if (i2c_lock_flag != 0)
goto MONITOR_END;
else
i2c_lock_flag = 1;
buf[0] = 0xD0;
buf[1] = 0x4C;
while (retry++ < 3) {
ret = cst2xx_i2c_read_register(this_ts->client, buf, 1);
if (ret > 0)
break;
usleep_range(2000, 2010);
}
if ((retry > 3)
|| ((buf[0] != 226) && (buf[0] != 237) && (buf[0] != 240))) {
hard_reset_chip(20);
cst2xx_check_code(this_ts->client);
}
i2c_lock_flag = 0;
MONITOR_END:
queue_delayed_work(hyn_monitor_workqueue, &hyn_monitor_work,
clk_tick_cnt);
}
#endif
#ifdef RESUME_INIT_CHIP_WORK
static void cst226_init_worker(struct work_struct *work)
{
init_chip(this_ts->client);
cst2xx_check_code(this_ts->client);
}
#endif
static irqreturn_t hyn_ts_irq(int irq, void *dev_id)
{
struct hyn_ts *ts = dev_id;
disable_irq_nosync(ts->irq);
if (!work_pending(&ts->work))
queue_work(ts->wq, &ts->work);
enable_irq(ts->irq);
return IRQ_HANDLED;
}
static int cst226_ts_init(struct i2c_client *client, struct hyn_ts *ts)
{
struct input_dev *input_device;
int rc = 0;
ts->dd = &devices[ts->device_id];
if (ts->device_id == 0) {
ts->dd->data_size =
MAX_FINGERS * ts->dd->touch_bytes + ts->dd->touch_meta_data;
ts->dd->touch_index = 0;
}
ts->touch_data = kzalloc(ts->dd->data_size, GFP_KERNEL);
if (!ts->touch_data)
return -ENOMEM;
input_device = input_allocate_device();
if (!input_device) {
rc = -ENOMEM;
goto error_alloc_dev;
}
ts->input = input_device;
input_device->name = TP_NAME;
input_device->id.bustype = BUS_I2C;
input_device->dev.parent = &client->dev;
input_set_drvdata(input_device, ts);
__set_bit(EV_ABS, input_device->evbit);
__set_bit(INPUT_PROP_DIRECT, input_device->propbit);
input_mt_init_slots(input_device, MAX_CONTACTS, 0);
input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
#if CFG_TP_USE_CONFIG
if (cfg_xml.rotate == 1 || cfg_xml.rotate == 3) {
input_set_abs_params(input_device, ABS_MT_POSITION_Y, 0,
cfg_xml.xMax, 0, 0);
input_set_abs_params(input_device, ABS_MT_POSITION_X, 0,
cfg_xml.yMax, 0, 0);
} else {
input_set_abs_params(input_device, ABS_MT_POSITION_X, 0,
cfg_xml.xMax, 0, 0);
input_set_abs_params(input_device, ABS_MT_POSITION_Y, 0,
cfg_xml.yMax, 0, 0);
}
#else
input_set_abs_params(input_device, ABS_MT_POSITION_X, 0, TP_MAX_X, 0,
0);
input_set_abs_params(input_device, ABS_MT_POSITION_Y, 0, TP_MAX_Y, 0,
0);
#endif
#ifdef HAVE_TOUCH_KEY
set_bit(EV_KEY, input_device->evbit);
input_device->evbit[0] = BIT_MASK(EV_KEY);
for (i = 0; i < ARRAY_SIZE(key_array); i++)
set_bit(key_array[i], input_device->keybit);
#endif
#if CFG_TP_USE_CONFIG
if (gpio_irq_exist == 0)
client->irq = 4;
else if (gpio_irq_exist == 1)
client->irq = gpio_to_irq(gpio_irq);
#else
client->irq = TP_IRQ_PORT;
#endif
ts->irq = client->irq;
ts->wq = create_singlethread_workqueue("kworkqueue_ts");
if (!ts->wq) {
dev_err(&client->dev, "Could not create workqueue\n");
goto error_wq_create;
}
flush_workqueue(ts->wq);
INIT_WORK(&ts->work, hyn_ts_xy_worker);
#ifdef RESUME_INIT_CHIP_WORK
ts->init_wq = create_singlethread_workqueue("ts_init_wq");
if (!ts->init_wq) {
dev_err(&client->dev,
"Could not create ts_init_wq workqueue\n");
goto error_wq_create;
}
flush_workqueue(ts->init_wq);
INIT_WORK(&ts->init_work, cst226_init_worker);
#endif
rc = input_register_device(input_device);
if (rc)
goto error_unreg_device;
this_ts = ts;
return 0;
error_unreg_device:
destroy_workqueue(ts->wq);
error_wq_create:
input_free_device(input_device);
error_alloc_dev:
kfree(ts->touch_data);
return rc;
}
static int hyn_ts_suspend(struct device *dev)
{
flush_workqueue(this_ts->init_wq);
if (gpio_reset_exist == 1)
cst226_shutdown_low();
msleep(20);
msleep(20);
return 0;
}
static int hyn_ts_early_resume(struct device *dev)
{
queue_work(this_ts->init_wq, &this_ts->init_work);
power_is_on = 1;
return 0;
}
static int hyn_ts_resume(struct device *dev)
{
if (power_is_on == 0) {
queue_work(this_ts->init_wq, &this_ts->init_work);
power_is_on = 1;
}
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void hyn_ts_early_suspend(struct early_suspend *h)
{
disable_irq_nosync(this_ts->irq);
#ifdef SLEEP_RESUME_CLEAR_POINT
#ifdef REPORT_DATA_PROTOCOL_B
int i = 0;
for (i = 1; i <= MAX_CONTACTS; i++) {
input_mt_slot(this_ts->input, i);
input_mt_report_slot_state(this_ts->input, MT_TOOL_FINGER,
false);
}
#endif
input_sync(this_ts->input);
#endif
flush_workqueue(this_ts->wq);
#ifdef HYN_MONITOR
cancel_delayed_work_sync(&hyn_monitor_work);
#endif
}
static void hyn_ts_late_resume(struct early_suspend *h)
{
#ifdef HYN_MONITOR
queue_delayed_work(hyn_monitor_workqueue, &hyn_monitor_work, 500);
#endif
enable_irq(this_ts->irq);
#ifdef SLEEP_RESUME_CLEAR_POINT
#ifdef REPORT_DATA_PROTOCOL_B
int i = 0;
for (i = 1; i <= MAX_CONTACTS; i++) {
input_mt_slot(this_ts->input, i);
input_mt_report_slot_state(this_ts->input, MT_TOOL_FINGER,
false);
}
#endif
input_sync(this_ts->input);
#endif
}
#endif
static int hyn_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct hyn_ts *ts;
int rc;
#if CFG_TP_USE_CONFIG
rc = tp_get_config(client);
if (rc < 0)
return -ENODEV;
#endif
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "I2C functionality not supported\n");
return -ENODEV;
}
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
hyn_client = client;
ts->client = client;
i2c_set_clientdata(client, ts);
ts->device_id = id->driver_data;
rc = cst226_ts_init(client, ts);
if (rc < 0) {
dev_err(&client->dev, "cst226 init failed\n");
goto error_mutex_destroy;
}
init_chip(ts->client);
cst2xx_check_code(ts->client);
rc = request_irq(client->irq, hyn_ts_irq, IRQF_TRIGGER_RISING,
client->name, ts);
if (rc < 0)
goto error_req_irq_fail;
#ifdef CONFIG_HAS_EARLYSUSPEND
ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
ts->early_suspend.suspend = hyn_ts_early_suspend;
ts->early_suspend.resume = hyn_ts_late_resume;
register_early_suspend(&ts->early_suspend);
#endif
mutex_init(&mutex);
#ifdef HYN_MONITOR
INIT_DELAYED_WORK(&hyn_monitor_work, hyn_monitor_worker);
hyn_monitor_workqueue =
create_singlethread_workqueue("hyn_monitor_workqueue");
queue_delayed_work(hyn_monitor_workqueue, &hyn_monitor_work, 500);
#endif
return 0;
error_req_irq_fail:
free_irq(ts->irq, ts);
error_mutex_destroy:
input_free_device(ts->input);
kfree(ts);
return rc;
}
static int hyn_ts_remove(struct i2c_client *client)
{
struct hyn_ts *ts = i2c_get_clientdata(client);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&ts->early_suspend);
#endif
device_init_wakeup(&client->dev, 0);
cancel_work_sync(&ts->work);
free_irq(ts->irq, ts);
destroy_workqueue(ts->wq);
cancel_work_sync(&ts->init_work);
destroy_workqueue(ts->init_wq);
input_unregister_device(ts->input);
#ifdef HYN_MONITOR
cancel_delayed_work_sync(&hyn_monitor_work);
destroy_workqueue(hyn_monitor_workqueue);
#endif
#if CFG_TP_USE_CONFIG
gpio_free(gpio_irq);
gpio_free(gpio_reset);
#endif
kfree(ts->touch_data);
kfree(ts);
return 0;
}
static const struct of_device_id hyn_match_table[] = {
{.compatible = "hyn, cst226",},
{},
};
static const struct i2c_device_id hyn_ts_id[] = {
{CST226_I2C_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, hyn_ts_id);
static unsigned short hyn_addresses[] = {
CST226_I2C_ADDR,
I2C_CLIENT_END,
};
static const struct dev_pm_ops tp_pm_ops = {
.resume_early = hyn_ts_early_resume,
.suspend = hyn_ts_suspend,
.resume = hyn_ts_resume,
};
static struct i2c_driver hyn_ts_driver = {
.driver = {
.name = CST226_I2C_NAME,
.owner = THIS_MODULE,
.pm = &tp_pm_ops,
.of_match_table = hyn_match_table,
},
.probe = hyn_ts_probe,
.remove = hyn_ts_remove,
.id_table = hyn_ts_id,
.address_list = hyn_addresses,
};
module_i2c_driver(hyn_ts_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CST2XX touchscreen controller driver");
MODULE_AUTHOR("Ying Zhang, ying.zhang@hynitron.com.cn");
MODULE_ALIAS("platform:HYN_ts");