blob: f217a5f7cdf217305f186be5e119f98cae7dcdc3 [file] [log] [blame]
/* drivers/input/touchscreen/synaptics_3200.c - Synaptics 3200 serious touch panel driver
*
* Copyright (C) 2011 HTC Corporation.
*
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/earlysuspend.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/synaptics_i2c_rmi.h>
#include <linux/slab.h>
#include <linux/rmi.h>
#include <mach/board.h>
#include <mach/msm_hsusb.h>
#include <asm/gpio.h>
#include <linux/input/mt.h>
#include <linux/pl_sensor.h>
#define SYN_I2C_RETRY_TIMES 10
#define SHIFT_BITS 10
#define SYN_WIRELESS_DEBUG
struct synaptics_ts_data {
uint16_t addr;
struct i2c_client *client;
struct input_dev *input_dev;
struct input_dev *sr_input_dev;
struct workqueue_struct *syn_wq;
struct function_t *address_table;
int use_irq;
int gpio_irq;
int gpio_reset;
struct hrtimer timer;
struct work_struct work;
uint16_t max[2];
uint32_t flags;
uint8_t num_function;
uint8_t finger_support;
uint16_t finger_pressed;
int (*power)(int on);
struct early_suspend early_suspend;
int pre_finger_data[11][4];
uint32_t debug_log_level;
uint32_t raw_base;
uint32_t raw_ref;
uint64_t timestamp;
uint16_t *filter_level;
uint8_t *reduce_report_level;
unsigned long tap_timeout[10];
int16_t *report_data;
uint8_t *temp_report_data;
uint8_t grip_suppression;
uint8_t grip_b_suppression;
uint16_t tap_suppression;
uint8_t ambiguous_state;
uint8_t diag_command;
uint8_t cable_support;
uint8_t cable_config;
uint8_t key_number;
uint16_t key_postion_x[4];
uint16_t key_postion_y;
uint8_t intr_bit;
uint8_t finger_count;
uint8_t page_select;
uint8_t config_table[SYN_CONFIG_SIZE];
uint8_t x_channel;
uint8_t y_channel;
uint8_t *config;
uint32_t config_version;
uint16_t package_id;
uint32_t packrat_number;
int layout[4];
uint8_t htc_event;
atomic_t data_ready;
uint8_t relaxation;
uint8_t irq_enabled;
uint8_t large_obj_check;
uint8_t default_large_obj;
uint16_t tw_vendor;
uint16_t tw_pin_mask;
uint8_t support_htc_event;
uint8_t mfg_flag;
uint8_t first_pressed;
uint8_t segmentation_bef_unlock;
uint8_t segmentation_aft_unlock;
uint8_t psensor_status;
uint8_t i2c_err_handler_en;
uint8_t threshold_bef_unlock;
uint8_t threshold_aft_unlock;
uint16_t saturation_bef_unlock;
uint16_t saturation_aft_unlock;
uint8_t energy_ratio_relaxation;
uint8_t multitouch_calibration;
uint32_t width_factor;
uint32_t height_factor;
uint8_t psensor_detection;
uint8_t psensor_resume_enable;
uint8_t psensor_phone_enable;
uint8_t PixelTouchThreshold_bef_unlock;
uint8_t PixelTouchThreshold_aft_unlock;
struct work_struct psensor_work;
struct workqueue_struct *syn_psensor_wq;
struct synaptics_virtual_key *button;
};
#ifdef CONFIG_HAS_EARLYSUSPEND
static void synaptics_ts_early_suspend(struct early_suspend *h);
static void synaptics_ts_late_resume(struct early_suspend *h);
#endif
static DECLARE_WAIT_QUEUE_HEAD(syn_data_ready_wq);
static DEFINE_MUTEX(syn_mutex);
static struct synaptics_ts_data *gl_ts;
static uint16_t syn_panel_version;
static uint8_t vk_press;
static int i2c_syn_write_byte_data(struct i2c_client *client, uint16_t addr, uint8_t value);
static int syn_pdt_scan(struct synaptics_ts_data *ts, int num_page);
static int synaptics_init_panel(struct synaptics_ts_data *ts);
static irqreturn_t synaptics_irq_thread(int irq, void *ptr);
extern unsigned int get_tamper_sf(void);
static void syn_page_select(struct i2c_client *client, uint8_t page)
{
struct synaptics_ts_data *ts = i2c_get_clientdata(client);
if (page ^ ts->page_select) {
i2c_smbus_write_byte_data(client, 0xFF, page);
ts->page_select = page;
}
}
static int i2c_syn_read(struct i2c_client *client, uint16_t addr, uint8_t *data, uint16_t length)
{
uint8_t retry, buf;
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = &buf,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = data,
}
};
buf = addr & 0xFF;
mutex_lock(&syn_mutex);
syn_page_select(client, addr >> 8);
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
if (i2c_transfer(client->adapter, msg, 2) == 2)
break;
msleep(10);
}
mutex_unlock(&syn_mutex);
if (retry == SYN_I2C_RETRY_TIMES) {
printk(KERN_INFO "[TP] i2c_read retry over %d\n",
SYN_I2C_RETRY_TIMES);
return -EIO;
}
return 0;
}
static int i2c_syn_write(struct i2c_client *client, uint16_t addr, uint8_t *data, uint16_t length)
{
uint8_t retry;
uint8_t buf[length + 1];
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = 0,
.len = length + 1,
.buf = buf,
}
};
mutex_lock(&syn_mutex);
syn_page_select(client, addr >> 8);
buf[0] = addr & 0xFF;
memcpy(&buf[1], &data[0], length);
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
if (i2c_transfer(client->adapter, msg, 1) == 1)
break;
mdelay(10);
}
mutex_unlock(&syn_mutex);
if (retry == SYN_I2C_RETRY_TIMES) {
printk(KERN_INFO "[TP] i2c_write retry over %d\n",
SYN_I2C_RETRY_TIMES);
return -EIO;
}
return 0;
}
int i2c_rmi_read(uint16_t addr, uint8_t *data, uint16_t length)
{
uint8_t retry, buf;
struct synaptics_ts_data *ts = gl_ts;
struct i2c_msg msg[] = {
{
.addr = ts->client->addr,
.flags = 0,
.len = 1,
.buf = &buf,
},
{
.addr = ts->client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = data,
}
};
buf = addr & 0xFF;
mutex_lock(&syn_mutex);
syn_page_select(ts->client, addr >> 8);
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
if (i2c_transfer(ts->client->adapter, msg, 2) == 2)
break;
msleep(10);
}
mutex_unlock(&syn_mutex);
if (retry == SYN_I2C_RETRY_TIMES) {
printk(KERN_INFO "[TP] i2c_read retry over %d\n",
SYN_I2C_RETRY_TIMES);
return -EIO;
}
return 0;
}
EXPORT_SYMBOL(i2c_rmi_read);
int i2c_rmi_write(uint16_t addr, uint8_t *data, uint16_t length)
{
uint8_t retry;
uint8_t buf[length + 1];
struct synaptics_ts_data *ts = gl_ts;
struct i2c_msg msg[] = {
{
.addr = ts->client->addr,
.flags = 0,
.len = length + 1,
.buf = buf,
}
};
mutex_lock(&syn_mutex);
syn_page_select(ts->client, addr >> 8);
buf[0] = addr & 0xFF;
memcpy(&buf[1], &data[0], length);
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
if (i2c_transfer(ts->client->adapter, msg, 1) == 1)
break;
mdelay(10);
}
mutex_unlock(&syn_mutex);
if (retry == SYN_I2C_RETRY_TIMES) {
printk(KERN_INFO "[TP] i2c_write retry over %d\n",
SYN_I2C_RETRY_TIMES);
return -EIO;
}
return 0;
}
EXPORT_SYMBOL(i2c_rmi_write);
static int i2c_syn_write_byte_data(struct i2c_client *client, uint16_t addr, uint8_t value)
{
return i2c_syn_write(client, addr, &value, 1);
}
static int i2c_syn_error_handler(struct synaptics_ts_data *ts, uint8_t reset, char *reason, const char *fun_name)
{
int ret;
if (reason && fun_name)
printk(KERN_ERR "[TP] TOUCH_ERR: I2C Error: %s:%s, reset = %d\n", fun_name, reason, reset);
else
printk(KERN_INFO "[TP] %s: rason and fun_name can't be null\n", __func__);
if (reset) {
if (ts->power) {
ret = ts->power(0);
if (ret < 0)
printk(KERN_ERR "[TP] TOUCH_ERR: synaptics i2c error handler power off failed\n");
msleep(10);
ret = ts->power(1);
if (ret < 0)
printk(KERN_ERR "[TP] TOUCH_ERR: synaptics i2c error handler power on failed\n");
ret = synaptics_init_panel(ts);
if (ret < 0)
printk(KERN_ERR "[TP] TOUCH_ERR: synaptics i2c error handler init panel failed\n");
} else if (ts->gpio_reset) {
gpio_direction_output(ts->gpio_reset, 0);
msleep(1);
gpio_direction_output(ts->gpio_reset, 1);
printk(KERN_INFO "[TP] %s: synaptics touch chip reseted.\n", __func__);
}
if (!ts->use_irq) {
hrtimer_cancel(&ts->timer);
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
}
}
return -EIO;
}
static int get_address_base(struct synaptics_ts_data *ts, uint8_t command, uint8_t type)
{
uint8_t i;
for (i = 0; i < ts->num_function; i++) {
if (ts->address_table[i].function_type == command) {
switch (type) {
case QUERY_BASE:
return ts->address_table[i].query_base;
case COMMAND_BASE:
return ts->address_table[i].command_base;
case CONTROL_BASE:
return ts->address_table[i].control_base;
case DATA_BASE:
return ts->address_table[i].data_base;
case INTR_SOURCE:
return ts->address_table[i].interrupt_source;
case FUNCTION:
return 1;
}
}
}
if (type == FUNCTION)
return 0;
else
return -1;
}
static int get_int_mask(uint8_t number, uint8_t offset)
{
uint8_t i, mask = 0;
for (i = 0; i < number; i++)
mask |= BIT(i);
return mask << offset;
}
static uint32_t syn_crc(uint16_t *data, uint16_t len)
{
uint32_t sum1, sum2;
sum1 = sum2 = 0xFFFF;
while (len--) {
sum1 += *data++;
sum2 += sum1;
sum1 = (sum1 & 0xFFFF) + (sum1 >> 16);
sum2 = (sum2 & 0xFFFF) + (sum2 >> 16);
}
return sum1 | (sum2 << 16);
}
static int wait_flash_interrupt(struct synaptics_ts_data *ts, int attr)
{
uint8_t data = 0;
int i, ret;
for (i = 0; i < 5; i++) {
#ifdef SYN_FLASH_PROGRAMMING_LOG
printk(KERN_INFO "[TP] ATT: %d\n", gpio_get_value(attr));
#endif
if (!gpio_get_value(attr)) {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x01, DATA_BASE) + 1, &data, 1);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
if ((data & 0x01) == 0x01) {
#ifdef SYN_FLASH_PROGRAMMING_LOG
printk(KERN_INFO "[TP] ATT: %d, status: %x\n", gpio_get_value(attr), data);
#endif
break;
}
}
msleep(20);
}
if (i == 5 && syn_panel_version == 0) {
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, DATA_BASE) + 1, &data, 1);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
} else if (i == 5) {
printk(KERN_INFO "[TP] wait_flash_interrupt: interrupt over time!\n");
return SYN_PROCESS_ERR;
}
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 18, &data, 1);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:3", __func__);
if (data != 0x80) {
printk(KERN_INFO "[TP] wait_flash_interrupt: block config fail!\n");
return SYN_PROCESS_ERR;
}
return 0;
}
static int enable_flash_programming(struct synaptics_ts_data *ts, int attr)
{
int ret;
uint8_t data[2];
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x34, QUERY_BASE), data, 2);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
ret = i2c_syn_write(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 2, data, 2);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 18, 0x0F);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:3", __func__);
ret = wait_flash_interrupt(ts, attr);
if (ret < 0)
return ret;
return 0;
}
static int crc_comparison(struct synaptics_ts_data *ts, uint32_t config_crc, int attr)
{
int ret;
uint8_t data[17];
uint32_t flash_crc;
#ifdef SYN_FLASH_PROGRAMMING_LOG
uint8_t i, j;
for (i = 0; i < 0x20; i++) {
data[0] = i;
data[1] = 0x00;
#else
data[0] = 0x1F;
data[1] = 0x00;
#endif
ret = i2c_syn_write(ts->client,
get_address_base(ts, 0x34, DATA_BASE), data, 2);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 18, 0x05);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
ret = wait_flash_interrupt(ts, attr);
if (ret < 0)
return ret;
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 2, data, 17);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:3", __func__);
memcpy(&flash_crc, &data[12], 4);
#ifdef SYN_FLASH_PROGRAMMING_LOG
printk(KERN_INFO "[TP] config_crc = %X, flash_crc = %X\n", config_crc, flash_crc);
for (j = 0; j < 0x11; j++)
printk(KERN_INFO " %d:%X ", j, data[j]);
printk(KERN_INFO "\n");
}
#endif
if (flash_crc == config_crc)
return 0;
else
return 1;
}
static int program_config(struct synaptics_ts_data *ts, uint8_t *config, int attr)
{
int ret;
uint8_t data[19];
uint16_t i;
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x34, QUERY_BASE), data, 2);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
ret = i2c_syn_write(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 2, data, 2);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 18, 0x07);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:3", __func__);
ret = wait_flash_interrupt(ts, attr);
if (ret < 0)
return ret;
for (i = 0; i < 0x20; i++) {
data[0] = i & 0xFF;
data[1] = (i & 0xFF00) >> 8;
memcpy(&data[2], &config[16 * i], 16);
data[18] = 0x06;
ret = i2c_syn_write(ts->client,
get_address_base(ts, 0x34, DATA_BASE), data, 19);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:4", __func__);
ret = wait_flash_interrupt(ts, attr);
if (ret < 0)
return ret;
}
return 0;
}
static int disable_flash_programming(struct synaptics_ts_data *ts, int status)
{
int ret;
uint8_t data = 0, i;
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x01, COMMAND_BASE), 0x01);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
for (i = 0; i < 25; i++) {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x01, DATA_BASE), &data, 1);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
if ((data & 0x40) == 0)
break;
else
msleep(20);
}
if (i == 25) {
printk(KERN_INFO "[TP] Disable flash programming fail! F01_data: %X\n", data);
return SYN_PROCESS_ERR;
} else {
printk(KERN_INFO "[TP] Disable flash programming success! F01_data: %X\n", data);
return status;
}
}
static int syn_config_update(struct synaptics_ts_data *ts, int attr)
{
uint8_t retry;
uint32_t crc_checksum;
int ret;
crc_checksum =
syn_crc((uint16_t *)ts->config, SYN_CONFIG_SIZE / 2 - 2);
memcpy(&ts->config[SYN_CONFIG_SIZE - 4], &crc_checksum, 4);
printk(KERN_INFO "[TP] CRC = %X\n" , syn_crc((uint16_t *)ts->config, SYN_CONFIG_SIZE / 2 - 2));
if (ts->tw_pin_mask == 0) {
ret = enable_flash_programming(ts, attr);
if (ret < 0) {
printk(KERN_INFO "[TP] syn_config_update: Enable flash programming fail!\n");
return disable_flash_programming(ts, ret);
}
ret = syn_pdt_scan(ts, SYN_BL_PAGE);
if (ret < 0) {
printk(KERN_INFO "[TP] syn_config_update: pdt scan failed\n");
return disable_flash_programming(ts, ret);
}
}
if ((ts->config != NULL && (ts->config[0] << 24 | ts->config[1] << 16 |
ts->config[2] << 8 | ts->config[3]) == ts->config_version)) {
ret = crc_comparison(ts, crc_checksum, attr);
if (ret < 0) {
printk(KERN_INFO "[TP] syn_config_update: CRC comparison fail!\n");
return disable_flash_programming(ts, ret);
} else if (ret == 0)
return disable_flash_programming(ts, 1);
}
for (retry = 0; retry < 3; retry++) {
ret = program_config(ts, ts->config, attr);
if (ret < 0) {
#ifdef SYN_FLASH_PROGRAMMING_LOG
printk(KERN_INFO "[TP] syn_config_update: Program config fail %d!\n", retry + 1);
#endif
continue;
}
ret = disable_flash_programming(ts, 0);
if (ret == 0)
break;
else
printk(KERN_INFO "[TP] syn_config_update: Disable flash programming fail %d\n", retry + 1);
}
if (retry == 3) {
printk(KERN_INFO "[TP] syn_config_update: Program config fail 3 times\n");
return ret;
}
return 0;
}
static int syn_get_tw_vendor(struct synaptics_ts_data *ts, int attr)
{
uint8_t data[2] = {0};
int ret;
ret = enable_flash_programming(ts, attr);
if (ret < 0) {
printk(KERN_INFO "[TP] Enable flash programming fail!\n");
return disable_flash_programming(ts, -1);
}
ret = syn_pdt_scan(ts, SYN_BL_PAGE);
if (ret < 0) {
printk(KERN_INFO "[TP] syn_config_update: pdt scan failed\n");
return disable_flash_programming(ts, ret);
}
memcpy(&data, &ts->tw_pin_mask, sizeof(ts->tw_pin_mask));
printk(KERN_INFO "[TP] tw mask = %X %X , %X\n", data[0], data[1], ts->tw_pin_mask);
i2c_syn_write(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 2, data, 2);
i2c_syn_write(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 4, data, 2);
i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 18, 0x08);
if (wait_flash_interrupt(ts, attr) < 0)
return disable_flash_programming(ts, -1);
i2c_syn_read(ts->client,
get_address_base(ts, 0x34, DATA_BASE) + 6, data, 2);
ts->tw_vendor = (data[1] << 8) | data[0];
printk(KERN_INFO "[TP] tw vendor= %x %x\n", data[1], data[0]);
return 0;
}
static int synaptics_input_register(struct synaptics_ts_data *ts)
{
int ret;
ts->input_dev = input_allocate_device();
if (ts->input_dev == NULL) {
ret = -ENOMEM;
printk(KERN_ERR "[TP] TOUCH_ERR: %s: Failed to allocate input device\n", __func__);
return ret;
}
ts->input_dev->name = "synaptics-rmi-touchscreen";
set_bit(EV_SYN, ts->input_dev->evbit);
set_bit(EV_KEY, ts->input_dev->evbit);
set_bit(EV_ABS, ts->input_dev->evbit);
set_bit(KEY_BACK, ts->input_dev->keybit);
set_bit(KEY_HOME, ts->input_dev->keybit);
set_bit(KEY_MENU, ts->input_dev->keybit);
set_bit(KEY_SEARCH, ts->input_dev->keybit);
set_bit(KEY_APP_SWITCH, ts->input_dev->keybit);
printk(KERN_INFO "[TP] input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n",
ts->layout[0], ts->layout[1], ts->layout[2], ts->layout[3]);
if (ts->htc_event == SYN_AND_REPORT_TYPE_B) {
input_mt_init_slots(ts->input_dev, ts->finger_support);
} else {
ts->input_dev->mtsize = ts->finger_support;
input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0,
ts->finger_support - 1, 0, 0);
}
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
ts->layout[0], ts->layout[1], 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
ts->layout[2], ts->layout[3], 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 30, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, 30, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE,
0, ((255 << 16) | 15), 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION,
0, ((1 << 31) | (ts->layout[1] << 16) | ts->layout[3]), 0, 0);
return input_register_device(ts->input_dev);
}
static ssize_t touch_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret = 0;
char fw_version[2];
struct synaptics_ts_data *ts;
ts = gl_ts;
memcpy(fw_version, &syn_panel_version, 2);
ret = sprintf(buf, "synaptics-%d_%c.%c", ts->package_id, fw_version[1], fw_version[0]);
if (ts->tw_pin_mask != 0)
ret += sprintf(buf+ret, "_twID-%x", ts->tw_vendor);
else
ret += sprintf(buf+ret, "\n");
ret += sprintf(buf+ret, "_PR: %d\n", ts->packrat_number);
return ret;
}
static DEVICE_ATTR(vendor, S_IRUGO, touch_vendor_show, NULL);
static ssize_t gpio_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret = 0;
struct synaptics_ts_data *ts;
ts = gl_ts;
ret = gpio_get_value(ts->gpio_irq);
printk(KERN_DEBUG "[TP] GPIO_TP_INT_N=%d\n", ret);
sprintf(buf, "GPIO_TP_INT_N=%d\n", ret);
ret = strlen(buf) + 1;
return ret;
}
static DEVICE_ATTR(gpio, S_IRUGO, gpio_show, NULL);
static uint16_t syn_reg_addr;
static ssize_t register_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret = 0;
uint8_t data = 0;
struct synaptics_ts_data *ts;
ts = gl_ts;
ret = i2c_syn_read(ts->client, syn_reg_addr, &data, 1);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r", __func__);
ret += sprintf(buf, "addr: 0x , data: 0x \n");
} else {
ret += sprintf(buf, "addr: 0x%X, data: 0x%X\n", syn_reg_addr, data);
}
return ret;
}
static ssize_t register_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
struct synaptics_ts_data *ts;
char buf_tmp[4];
uint8_t write_da;
unsigned long addr;
ts = gl_ts;
memset(buf_tmp, 0x0, sizeof(buf_tmp));
if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':' &&
(buf[5] == ':' || buf[5] == '\n')) {
memcpy(buf_tmp, buf + 2, 3);
ret = strict_strtoul(buf_tmp, 16, &addr);
syn_reg_addr = addr;
printk(KERN_DEBUG "[TP] %s: set syn_reg_addr is: 0x%X\n",
__func__, syn_reg_addr);
if (buf[0] == 'w' && buf[5] == ':' && buf[9] == '\n') {
memcpy(buf_tmp, buf + 6, 3);
ret = strict_strtoul(buf_tmp, 16, &addr);
write_da = addr;
printk(KERN_DEBUG "[TP] write addr: 0x%X, data: 0x%X\n",
syn_reg_addr, write_da);
ret = i2c_syn_write_byte_data(ts->client,
syn_reg_addr, write_da);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w", __func__);
}
}
}
return count;
}
static DEVICE_ATTR(register, (S_IWUSR|S_IRUGO),
register_show, register_store);
static ssize_t debug_level_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct synaptics_ts_data *ts = gl_ts;
return sprintf(buf, "%d\n", ts->debug_log_level);
}
static ssize_t debug_level_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct synaptics_ts_data *ts = gl_ts;
int i;
ts->debug_log_level = 0;
for(i=0; i<count-1; i++)
{
if( buf[i]>='0' && buf[i]<='9' )
ts->debug_log_level |= (buf[i]-'0');
else if( buf[i]>='A' && buf[i]<='F' )
ts->debug_log_level |= (buf[i]-'A'+10);
else if( buf[i]>='a' && buf[i]<='f' )
ts->debug_log_level |= (buf[i]-'a'+10);
if(i!=count-2)
ts->debug_log_level <<= 4;
}
return count;
}
static DEVICE_ATTR(debug_level, (S_IWUSR|S_IRUGO),
debug_level_show, debug_level_store);
static ssize_t syn_diag_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct synaptics_ts_data *ts = gl_ts;
size_t count = 0;
uint16_t i, j;
int ret;
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x54, DATA_BASE), ts->diag_command);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
count += sprintf(buf, "[TP] TOUCH_ERR: %s: i2c write fail(%d)\n", __func__, ret);
return count;
}
atomic_set(&ts->data_ready, 0);
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x54, COMMAND_BASE), 0x01);
if (ret < 0) {
atomic_set(&ts->data_ready, 1);
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
count += sprintf(buf, "[TP] TOUCH_ERR: %s: i2c write fail(%d)\n", __func__, ret);
return count;
}
wait_event_interruptible_timeout(syn_data_ready_wq,
atomic_read(&ts->data_ready), 50);
for (i = 0; i < ts->y_channel; i++) {
for (j = 0; j < ts->x_channel; j++) {
if(ts->package_id == 3201)
count += sprintf(buf + count, "%5d", ts->report_data[i*ts->x_channel + j]);
else
count += sprintf(buf + count, "%5d", ts->report_data[i + j*ts->y_channel]);
}
count += sprintf(buf + count, "\n");
}
return count;
}
static ssize_t syn_diag_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct synaptics_ts_data *ts;
ts = gl_ts;
if (buf[0] == '1')
ts->diag_command = 2;
else if (buf[0] == '2')
ts->diag_command = 3;
return count;
}
static DEVICE_ATTR(diag, (S_IWUSR|S_IRUGO),
syn_diag_show, syn_diag_store);
static ssize_t syn_unlock_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct synaptics_ts_data *ts;
int unlock = -1;
int ret;
ts = gl_ts;
if (buf[0] >= '0' && buf[0] <= '9' && buf[1] == '\n')
unlock = buf[0] - '0';
printk(KERN_INFO "[TP] Touch: unlock change to %d\n", unlock);
if (unlock == 2 && ts->first_pressed && ts->pre_finger_data[0][0] < 2) {
ts->pre_finger_data[0][0] = 2;
if(ts->psensor_detection) {
if(ts->psensor_resume_enable == 1) {
printk(KERN_INFO "[TP] %s: Disable P-sensor by Touch\n", __func__);
psensor_enable_by_touch_driver(0);
ts->psensor_resume_enable = 0;
}
else if(ts->psensor_resume_enable == 2) {
ts->psensor_resume_enable = 0;
}
}
if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT) {
if (ts->large_obj_check) {
if (ts->package_id == 2200) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x26, ts->default_large_obj);
} else {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x29, ts->default_large_obj);
}
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:7", __func__);
printk(KERN_INFO "[TP] %s: unlock confirmed. set large obj suppression: %x\n"
, __func__, ts->default_large_obj);
}
if (ts->segmentation_bef_unlock) {
if (ts->package_id == 2200) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x25, ts->segmentation_aft_unlock);
} else {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x22, ts->segmentation_aft_unlock);
}
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:8", __func__);
printk(KERN_INFO "[TP] %s: unlock confirmed. set segmentation aggressiveness: %x\n"
, __func__, ts->segmentation_aft_unlock);
}
if (ts->threshold_bef_unlock) {
if (ts->package_id == 2200) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x0A, ts->threshold_aft_unlock);
} else {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x0C, ts->threshold_aft_unlock);
}
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:9", __func__);
printk(KERN_INFO "[TP] %s: unlock confirmed. set Z Touch threshold: %x\n"
, __func__, ts->threshold_aft_unlock);
}
}
}
return count;
}
static DEVICE_ATTR(unlock, (S_IWUSR|S_IRUGO),
NULL, syn_unlock_store);
static ssize_t syn_config_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct synaptics_ts_data *ts = gl_ts;
uint16_t i, length = 0;
uint8_t j, temp_func_cmd = 0, temp_func_query = 0, size = 0;
size_t count = 0;
int ret;
printk(KERN_INFO "[TP] ts->num_function: %d\n", ts->num_function);
for (i = 0; i < SYN_MAX_PAGE; i++) {
for (j = 0; j < ts->num_function; j++) {
if (((ts->address_table[j].control_base >> 8) & 0xFF) == i) {
temp_func_query = 0;
for (temp_func_cmd = j; temp_func_cmd < ts->num_function; temp_func_cmd++) {
uint16_t max_addr = (i << 8) | 0xFF;
uint16_t min_addr = (i << 8) | 0;
if ((ts->address_table[temp_func_cmd].command_base > min_addr) &&
(ts->address_table[temp_func_cmd].command_base <= max_addr))
break;
if ((ts->address_table[temp_func_cmd].query_base > min_addr) &&
(ts->address_table[temp_func_cmd].query_base <= max_addr)
&& temp_func_query == 0)
temp_func_query = temp_func_cmd;
}
if (temp_func_cmd != ts->num_function) {
size = ts->address_table[temp_func_cmd].command_base -
ts->address_table[j].control_base;
printk(KERN_INFO "[TP] page%d has command function, function: %X\n"
, i, ts->address_table[temp_func_cmd].function_type);
} else {
size = ts->address_table[temp_func_query].query_base -
ts->address_table[j].control_base;
printk(KERN_INFO "[TP] page%d has no command function, use query function, function: %X\n"
, i, ts->address_table[temp_func_query].function_type);
}
ret = i2c_syn_read(ts->client, ts->address_table[j].control_base,
&ts->config_table[length], size);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w", __func__);
count += sprintf(buf, "[TP] TOUCH_ERR: %s: i2c write fail(%d)\n", __func__, ret);
return count;
}
length += size;
printk(KERN_INFO "[TP] Size: %x, Length: %x\n", size, length);
break;
}
}
}
if(length > SYN_CONFIG_SIZE)
length = SYN_CONFIG_SIZE;
printk(KERN_INFO "");
for (i = 0; i < length; i++) {
printk(KERN_INFO "%2.2X ", ts->config_table[i]);
if ((i % 16) == 15)
printk(KERN_INFO "\n");
}
for (i = 0; i < length; i++) {
count += sprintf(buf + count, "%2.2X ", ts->config_table[i]);
if ((i % 16) == (16 - 1))
count += sprintf(buf + count, "\n");
}
count += sprintf(buf + count, "\n");
return count;
}
static ssize_t syn_config_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct synaptics_ts_data *ts = gl_ts;
uint8_t i, j, k = 0, length = 0;
printk(KERN_INFO "[TP] ts->num_function: %d\n", ts->num_function);
for (i = 0; i < SYN_MAX_PAGE; i++) {
for (j = 0; j < ts->num_function; j++) {
if (((ts->address_table[j].control_base >> 8) & 0xFF) == i) {
for (k = j; k < ts->num_function; k++)
if (ts->address_table[k].command_base != 0)
break;
length += ts->address_table[k].command_base -
ts->address_table[j].control_base;
printk(KERN_INFO "[%d]Length: %x\n", i, length);
break;
}
}
}
return count;
}
static DEVICE_ATTR(config, (S_IWUSR|S_IRUGO),
syn_config_show, syn_config_store);
static ssize_t syn_layout_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct synaptics_ts_data *ts = gl_ts;
uint8_t i;
size_t count = 0;
for (i = 0; i < 4; i++)
count += sprintf(buf + count, "%d ", ts->layout[i]);
count += sprintf(buf + count, "\n");
return count;
}
static ssize_t syn_layout_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct synaptics_ts_data *ts = gl_ts;
char buf_tmp[5];
int i = 0, j = 0, k = 0, ret;
unsigned long value;
int layout[4] = {0};
for (i = 0; i < 20; i++) {
if (buf[i] == ',' || buf[i] == '\n') {
memset(buf_tmp, 0x0, sizeof(buf_tmp));
if (i - j <= 5)
memcpy(buf_tmp, buf + j, i - j);
else {
printk(KERN_INFO "[TP] buffer size is over 5 char\n");
return count;
}
j = i + 1;
if (k < 4) {
ret = strict_strtol(buf_tmp, 10, &value);
layout[k++] = value;
}
}
}
if (k == 4) {
memcpy(ts->layout, layout, sizeof(layout));
printk(KERN_INFO "[TP] %d, %d, %d, %d\n",
ts->layout[0], ts->layout[1], ts->layout[2], ts->layout[3]);
input_unregister_device(ts->input_dev);
synaptics_input_register(ts);
} else
printk(KERN_INFO "[TP] ERR@%d, %d, %d, %d\n",
ts->layout[0], ts->layout[1], ts->layout[2], ts->layout[3]);
return count;
}
static DEVICE_ATTR(layout, (S_IWUSR|S_IRUGO),
syn_layout_show, syn_layout_store);
static ssize_t syn_pdt_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct synaptics_ts_data *ts = gl_ts;
uint8_t i;
size_t count = 0;
for (i = 0; i < ts->num_function; i++) {
count += sprintf(buf + count,
"Funtion: %2X, Query: %3X, Command: %3X, "
"Control: %3X, Data: %3X, INTR: %2X\n",
ts->address_table[i].function_type, ts->address_table[i].query_base ,
ts->address_table[i].command_base, ts->address_table[i].control_base,
ts->address_table[i].data_base, ts->address_table[i].interrupt_source);
}
return count;
}
static DEVICE_ATTR(pdt, S_IRUGO, syn_pdt_show, NULL);
static ssize_t syn_htc_event_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct synaptics_ts_data *ts = gl_ts;
return sprintf(buf, "%d\n", ts->htc_event);
}
static ssize_t syn_htc_event_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct synaptics_ts_data *ts = gl_ts;
if (buf[0] >= '0' && buf[0] <= '9' && buf[1] == '\n')
ts->htc_event = buf[0] - '0';
return count;
}
static DEVICE_ATTR(htc_event, (S_IWUSR|S_IRUGO),
syn_htc_event_show, syn_htc_event_store);
#ifdef SYN_WIRELESS_DEBUG
static ssize_t syn_int_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct synaptics_ts_data *ts = gl_ts;
size_t count = 0;
count += sprintf(buf + count, "%d ", ts->irq_enabled);
count += sprintf(buf + count, "\n");
return count;
}
static ssize_t syn_int_status_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct synaptics_ts_data *ts = gl_ts;
int value, ret=0;
if (sysfs_streq(buf, "0"))
value = false;
else if (sysfs_streq(buf, "1"))
value = true;
else
return -EINVAL;
if (value) {
ret = request_threaded_irq(ts->client->irq, NULL, synaptics_irq_thread,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts);
if (ret == 0) {
ts->irq_enabled = 1;
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x01, CONTROL_BASE) + 1, &ts->intr_bit, 1);
printk(KERN_INFO "[TP] %s: interrupt enable: %x\n", __func__, ts->intr_bit);
if (ret)
free_irq(ts->client->irq, ts);
}
} else {
disable_irq(ts->client->irq);
free_irq(ts->client->irq, ts);
ts->irq_enabled = 0;
}
return count;
}
static DEVICE_ATTR(enabled, (S_IWUSR|S_IRUGO),
syn_int_status_show, syn_int_status_store);
static ssize_t syn_reset(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct synaptics_ts_data *ts = gl_ts;
if (buf[0] == '1' && ts->gpio_reset) {
gpio_direction_output(ts->gpio_reset, 0);
msleep(1);
gpio_direction_output(ts->gpio_reset, 1);
printk(KERN_INFO "[TP] %s: synaptics touch chip reseted.\n", __func__);
}
return count;
}
static DEVICE_ATTR(reset, (S_IWUSR),
0, syn_reset);
#endif
enum SR_REG_STATE{
ALLOCATE_DEV_FAIL = -2,
REGISTER_DEV_FAIL,
SUCCESS,
};
static char *vk_name = "virtualkeys.sr_touchscreen";
static struct kobj_attribute vk_dev;
static int register_sr_touch_device(void)
{
struct synaptics_ts_data *ts = gl_ts;
struct synaptics_i2c_rmi_platform_data *pdata = ts->client->dev.platform_data;
int ret = 0;
ts->sr_input_dev = input_allocate_device();
if (ts->sr_input_dev == NULL) {
printk(KERN_ERR "[TP][TOUCH_ERR]%s: Failed to allocate SR input device\n", __func__);
return ALLOCATE_DEV_FAIL;
}
if (pdata->vk_obj) {
memcpy(&vk_dev, pdata->vk2Use, sizeof(struct kobj_attribute));
vk_dev.attr.name = vk_name;
ret = sysfs_create_file(pdata->vk_obj, &(vk_dev.attr));
}
ts->sr_input_dev->name = "sr_touchscreen";
set_bit(EV_SYN, ts->sr_input_dev->evbit);
set_bit(EV_ABS, ts->sr_input_dev->evbit);
set_bit(EV_KEY, ts->sr_input_dev->evbit);
set_bit(KEY_BACK, ts->sr_input_dev->keybit);
set_bit(KEY_HOME, ts->sr_input_dev->keybit);
set_bit(KEY_MENU, ts->sr_input_dev->keybit);
set_bit(KEY_SEARCH, ts->sr_input_dev->keybit);
set_bit(BTN_TOUCH, ts->sr_input_dev->keybit);
set_bit(KEY_APP_SWITCH, ts->sr_input_dev->keybit);
set_bit(INPUT_PROP_DIRECT, ts->sr_input_dev->propbit);
ts->sr_input_dev->mtsize = ts->finger_support;
input_set_abs_params(ts->sr_input_dev, ABS_MT_TRACKING_ID,
0, ts->finger_support - 1, 0, 0);
printk(KERN_INFO "[TP][SR]input_set_abs_params: mix_x %d, max_x %d,"
" min_y %d, max_y %d\n", ts->layout[0],
ts->layout[1], ts->layout[2], ts->layout[3]);
input_set_abs_params(ts->sr_input_dev, ABS_MT_POSITION_X,
ts->layout[0], ts->layout[1], 0, 0);
input_set_abs_params(ts->sr_input_dev, ABS_MT_POSITION_Y,
ts->layout[2], ts->layout[3], 0, 0);
input_set_abs_params(ts->sr_input_dev, ABS_MT_TOUCH_MAJOR,
0, 255, 0, 0);
input_set_abs_params(ts->sr_input_dev, ABS_MT_PRESSURE,
0, 30, 0, 0);
input_set_abs_params(ts->sr_input_dev, ABS_MT_WIDTH_MAJOR,
0, 30, 0, 0);
if (input_register_device(ts->sr_input_dev)) {
input_free_device(ts->sr_input_dev);
printk(KERN_ERR "[TP][SR][TOUCH_ERR]%s: Unable to register %s input device\n",
__func__, ts->sr_input_dev->name);
return REGISTER_DEV_FAIL;
}
return SUCCESS;
}
static ssize_t set_en_sr(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct synaptics_ts_data *ts = gl_ts;
if (buf[0]) {
if (ts->sr_input_dev)
printk(KERN_INFO "[TP]%s: SR device already exist!\n", __func__);
else
printk(KERN_INFO "[TP]%s: SR touch device enable result:%X\n", __func__, register_sr_touch_device());
}
return count;
}
static DEVICE_ATTR(sr_en, S_IWUSR, 0, set_en_sr);
static struct kobject *android_touch_kobj;
static int synaptics_touch_sysfs_init(void)
{
int ret;
#ifdef SYN_WIRELESS_DEBUG
struct synaptics_ts_data *ts = gl_ts;
#endif
android_touch_kobj = kobject_create_and_add("android_touch", NULL);
if (android_touch_kobj == NULL) {
printk(KERN_ERR "[TP] TOUCH_ERR: %s: subsystem_register failed\n", __func__);
ret = -ENOMEM;
return ret;
}
syn_reg_addr = 0;
if (sysfs_create_file(android_touch_kobj, &dev_attr_vendor.attr) ||
sysfs_create_file(android_touch_kobj, &dev_attr_gpio.attr) ||
sysfs_create_file(android_touch_kobj, &dev_attr_debug_level.attr) ||
sysfs_create_file(android_touch_kobj, &dev_attr_register.attr) ||
sysfs_create_file(android_touch_kobj, &dev_attr_unlock.attr) ||
sysfs_create_file(android_touch_kobj, &dev_attr_config.attr) ||
sysfs_create_file(android_touch_kobj, &dev_attr_layout.attr) ||
sysfs_create_file(android_touch_kobj, &dev_attr_pdt.attr) ||
sysfs_create_file(android_touch_kobj, &dev_attr_htc_event.attr) ||
sysfs_create_file(android_touch_kobj, &dev_attr_reset.attr) ||
sysfs_create_file(android_touch_kobj, &dev_attr_sr_en.attr)
#ifdef SYN_WIRELESS_DEBUG
|| sysfs_create_file(android_touch_kobj, &dev_attr_enabled.attr)
#endif
)
return -ENOMEM;
if (get_address_base(gl_ts, 0x54, FUNCTION))
if (sysfs_create_file(android_touch_kobj, &dev_attr_diag.attr))
return -ENOMEM;
#ifdef SYN_WIRELESS_DEBUG
ret= gpio_request(ts->gpio_irq, "synaptics_attn");
if (ret) {
printk(KERN_INFO "[TP]%s: Failed to obtain touchpad IRQ %d. Code: %d.", __func__, ts->gpio_irq, ret);
return ret;
}
if (ts->gpio_reset) {
ret = gpio_request(ts->gpio_reset, "synaptics_reset");
if (ret)
printk(KERN_INFO "[TP]%s: Failed to obtain reset pin: %d. Code: %d.", __func__, ts->gpio_reset, ret);
}
ret = gpio_export(ts->gpio_irq, true);
if (ret) {
printk(KERN_INFO "[TP]%s: Failed to "
"export ATTN gpio!\n", __func__);
ret = 0;
} else {
ret = gpio_export_link(&(ts->input_dev->dev), "attn",
ts->gpio_irq);
if (ret) {
printk(KERN_INFO "[TP]%s: Failed to "
"symlink ATTN gpio!\n", __func__);
ret = 0;
} else {
printk(KERN_INFO "[TP]%s: Exported GPIO %d.", __func__, ts->gpio_irq);
}
}
#endif
return 0;
}
static void synaptics_touch_sysfs_remove(void)
{
sysfs_remove_file(android_touch_kobj, &dev_attr_vendor.attr);
sysfs_remove_file(android_touch_kobj, &dev_attr_gpio.attr);
sysfs_remove_file(android_touch_kobj, &dev_attr_debug_level.attr);
if (get_address_base(gl_ts, 0x54, FUNCTION))
sysfs_remove_file(android_touch_kobj, &dev_attr_diag.attr);
sysfs_remove_file(android_touch_kobj, &dev_attr_register.attr);
sysfs_remove_file(android_touch_kobj, &dev_attr_unlock.attr);
sysfs_remove_file(android_touch_kobj, &dev_attr_config.attr);
sysfs_remove_file(android_touch_kobj, &dev_attr_layout.attr);
sysfs_remove_file(android_touch_kobj, &dev_attr_pdt.attr);
sysfs_remove_file(android_touch_kobj, &dev_attr_htc_event.attr);
sysfs_remove_file(android_touch_kobj, &dev_attr_reset.attr);
sysfs_remove_file(android_touch_kobj, &dev_attr_sr_en.attr);
#ifdef SYN_WIRELESS_DEBUG
sysfs_remove_file(android_touch_kobj, &dev_attr_enabled.attr);
#endif
kobject_del(android_touch_kobj);
}
static int synaptics_init_panel(struct synaptics_ts_data *ts)
{
int ret = 0;
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x01, CONTROL_BASE), 0x80);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
if (ts->pre_finger_data[0][0] < 2) {
if (ts->large_obj_check) {
if (ts->package_id == 2200) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x26, ts->default_large_obj & 0x7F);
} else {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x29, ts->default_large_obj & 0x7F);
}
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
printk(KERN_INFO "[TP] %s: set large obj suppression register to: %x\n", __func__, ts->default_large_obj & 0x7F);
}
if (ts->segmentation_bef_unlock) {
if (ts->package_id == 2200) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x25, ts->segmentation_bef_unlock);
} else {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x22, ts->segmentation_bef_unlock);
}
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:3", __func__);
printk(KERN_INFO "[TP] %s: set segmentation aggressiveness to: %x\n", __func__, ts->segmentation_bef_unlock);
}
if (ts->threshold_bef_unlock) {
if (ts->package_id == 2200) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x0A, ts->threshold_bef_unlock);
} else {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x0C, ts->threshold_bef_unlock);
}
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:4", __func__);
printk(KERN_INFO "[TP] %s: set Z Touch threshold to: %x\n", __func__, ts->threshold_bef_unlock);
}
if (ts->saturation_bef_unlock) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x54, CONTROL_BASE) + 0x02, ts->saturation_bef_unlock & 0xFF);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "saturation capacitance", __func__);
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x54, CONTROL_BASE) + 0x03, (ts->saturation_bef_unlock & 0xFF00) >> 8);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "saturation capacitance", __func__);
printk(KERN_INFO "[TP] %s: set saturation to: %x\n", __func__, ts->saturation_bef_unlock);
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x54, COMMAND_BASE), 0x04);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:5", __func__);
}
if ( ts->PixelTouchThreshold_bef_unlock ) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x54, CONTROL_BASE) + 0x04, ts->PixelTouchThreshold_bef_unlock );
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "F54_ANALOG_CTRL03 Pixel Touch Threshold", __func__);
printk(KERN_INFO "[TP] %s: set F54_ANALOG_CTRL03 Pixel Touch Threshold: %x\n", __func__, ts->PixelTouchThreshold_bef_unlock);
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x54, COMMAND_BASE), 0x04);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:6", __func__);
}
}
return ret;
}
static void synaptics_ts_finger_func(struct synaptics_ts_data *ts)
{
int ret;
uint8_t buf[((ts->finger_support * 21 + 3) / 4)];
memset(buf, 0x0, sizeof(buf));
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x11, DATA_BASE), buf, sizeof(buf));
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
} else {
int finger_data[ts->finger_support][4];
int base = (ts->finger_support + 3) / 4;
uint8_t i, j;
uint16_t finger_press_changed = 0, finger_release_changed = 0, finger_pressed = 0;
ts->finger_count = 0;
if (ts->debug_log_level & BIT(0)) {
printk(KERN_INFO "[TP] Touch:");
for (i = 0; i < sizeof(buf); i++)
printk(KERN_INFO " %2x", buf[i]);
printk(KERN_INFO "\n");
}
for (i = 0; i < ts->finger_support; i++) {
uint8_t finger_state = buf[(i / 4)] >> ((i * 2) % 8);
if (finger_state & 0x03) {
finger_pressed |= BIT(i);
ts->finger_count++;
if (finger_state == 0x02)
printk(KERN_INFO "[TP] Finger state[%d] = 0x02\n", i);
else if (finger_state == 0x03)
printk(KERN_INFO "[TP] Finger state[%d] = 0x03\n", i);
}
#ifdef SYN_FILTER_CONTROL
else if ((ts->grip_suppression | ts->grip_b_suppression) & BIT(i)) {
ts->grip_suppression &= ~BIT(i);
ts->grip_b_suppression &= ~BIT(i);
}
#endif
}
if (ts->finger_pressed != finger_pressed
) {
finger_press_changed = ts->finger_pressed ^ finger_pressed;
finger_release_changed = finger_press_changed & ts->finger_pressed;
finger_press_changed &= finger_pressed;
ts->finger_pressed = finger_pressed;
}
if(ts->debug_log_level & BIT(3)) {
for(i = 0; i < ts->finger_support; i++) {
if (finger_release_changed & BIT(i) ) {
uint32_t flip_flag = SYNAPTICS_FLIP_X;
uint8_t pos_mask = 0x0f;
for (j = 0; j < 2; j++) {
finger_data[i][j]
= (buf[base+2] & pos_mask) >> (j * 4) |
(uint16_t)buf[base + j] << 4;
if (ts->flags & flip_flag)
finger_data[i][j] = ts->max[j] - finger_data[i][j];
flip_flag <<= 1;
pos_mask <<= 4;
}
finger_data[i][2] = (buf[base+3] >> 4 & 0x0F) + (buf[base+3] & 0x0F);
finger_data[i][3] = buf[base+4];
if (ts->flags & SYNAPTICS_SWAP_XY)
swap(finger_data[i][0], finger_data[i][1]);
if (ts->layout[1] < finger_data[i][0])
finger_data[i][0] = ts->layout[1];
if(ts->width_factor && ts->height_factor){
printk(KERN_INFO
"[TP] Screen:F[%02d]:Up, X=%d, Y=%d, W=%d, Z=%d\n",
i+1, (finger_data[i][0]*ts->width_factor)>>SHIFT_BITS,
(finger_data[i][1]*ts->height_factor)>>SHIFT_BITS,
finger_data[i][2], finger_data[i][3]);
} else {
printk(KERN_INFO
"[TP] Raw:F[%02d]:Up, X=%d, Y=%d, W=%d, Z=%d\n",
i+1, finger_data[i][0], finger_data[i][1],
finger_data[i][2], finger_data[i][3]);
}
}
base += 5;
}
}
if (ts->htc_event == SYN_AND_REPORT_TYPE_B && finger_release_changed) {
for (i = 0; i < ts->finger_support; i++) {
if (finger_release_changed & BIT(i)) {
input_mt_slot(ts->input_dev, i);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
ts->tap_suppression &= ~BIT(i);
}
}
}
if (finger_pressed == 0
) {
if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
if (ts->support_htc_event) {
input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
}
input_mt_sync(ts->input_dev);
}
else if (ts->htc_event == SYN_AND_REPORT_TYPE_HTC) {
input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
}
#ifdef SYN_FILTER_CONTROL
if (ts->filter_level[0])
ts->ambiguous_state = 0;
ts->grip_b_suppression = 0;
#endif
if (ts->reduce_report_level[0])
ts->tap_suppression = 0;
if (ts->debug_log_level & BIT(1))
printk(KERN_INFO "[TP] Finger leave\n");
}
if (ts->pre_finger_data[0][0] < 2 || finger_pressed) {
base = (ts->finger_support + 3) / 4;
for (i = 0; i < ts->finger_support; i++) {
uint32_t flip_flag = SYNAPTICS_FLIP_X;
if ((finger_pressed | finger_release_changed) & BIT(i)) {
uint8_t pos_mask = 0x0f;
for (j = 0; j < 2; j++) {
finger_data[i][j]
= (buf[base+2] & pos_mask) >> (j * 4) |
(uint16_t)buf[base + j] << 4;
if (ts->flags & flip_flag)
finger_data[i][j] = ts->max[j] - finger_data[i][j];
flip_flag <<= 1;
pos_mask <<= 4;
}
finger_data[i][2] = (buf[base+3] >> 4 & 0x0F) + (buf[base+3] & 0x0F);
finger_data[i][3] = buf[base+4];
if (ts->flags & SYNAPTICS_SWAP_XY)
swap(finger_data[i][0], finger_data[i][1]);
if (ts->layout[1] < finger_data[i][0])
finger_data[i][0] = ts->layout[1];
if ((finger_release_changed & BIT(i)) && ts->pre_finger_data[0][0] < 2) {
if (!ts->first_pressed) {
if (ts->finger_count == 0)
ts->first_pressed = 1;
printk(KERN_INFO "[TP] E%d@%d, %d\n", i + 1,
finger_data[i][0], finger_data[i][1]);
}
}
#ifdef SYN_FILTER_CONTROL
if (abs((buf[base+3] >> 4 & 0x0F) - (buf[base+3] & 0x0F)) >= 10)
ts->grip_b_suppression |= BIT(i);
if (ts->filter_level[0] &&
((finger_press_changed | ts->grip_suppression) & BIT(i))) {
if ((finger_data[i][0] < (ts->filter_level[0] + ts->ambiguous_state * 20) ||
finger_data[i][0] > (ts->filter_level[3] - ts->ambiguous_state * 20)) &&
!(ts->grip_suppression & BIT(i))) {
ts->grip_suppression |= BIT(i);
} else if ((finger_data[i][0] < (ts->filter_level[1] + ts->ambiguous_state * 20) ||
finger_data[i][0] > (ts->filter_level[2] - ts->ambiguous_state * 20)) &&
(ts->grip_suppression & BIT(i)))
ts->grip_suppression |= BIT(i);
else if (finger_data[i][0] > (ts->filter_level[1] + ts->ambiguous_state * 20) &&
finger_data[i][0] < (ts->filter_level[2] - ts->ambiguous_state * 20)) {
ts->grip_suppression &= ~BIT(i);
}
}
if ((ts->grip_suppression | ts->grip_b_suppression) & BIT(i)) {
finger_pressed &= ~BIT(i);
} else
#endif
if (ts->htc_event == SYN_AND_REPORT_TYPE_B && ts->reduce_report_level[0]) {
if (ts->tap_suppression & BIT(i) && finger_pressed & BIT(i)) {
int dx, dy = 0;
dx = abs(ts->pre_finger_data[i + 1][2] - finger_data[i][0]);
dy = abs(ts->pre_finger_data[i + 1][3] - finger_data[i][1]);
if (dx > ts->reduce_report_level[TAP_DX_OUTER] || dy > ts->reduce_report_level[TAP_DY_OUTER]) {
ts->tap_suppression &= ~BIT(i);
} else if (ts->reduce_report_level[TAP_TIMEOUT] && time_after(jiffies, ts->tap_timeout[i]) && (dx > ts->reduce_report_level[TAP_DX_INTER] || dy > ts->reduce_report_level[TAP_DY_INTER])) {
ts->tap_suppression &= ~BIT(i);
} else {
finger_pressed &= ~BIT(i);
if (ts->debug_log_level & (BIT(1) | BIT(3)))
printk(KERN_INFO
"[TP] Filtered Finger %d=> X:%d, Y:%d w:%d, z:%d\n",
i + 1, finger_data[i][0], finger_data[i][1],
finger_data[i][2], finger_data[i][3]);
}
}
}
if ((finger_pressed & BIT(i)) == BIT(i)) {
finger_pressed &= ~BIT(i);
if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
if (ts->support_htc_event) {
input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE,
finger_data[i][3] << 16 | finger_data[i][2]);
input_report_abs(ts->input_dev, ABS_MT_POSITION,
(finger_pressed == 0) << 31 |
finger_data[i][0] << 16 | finger_data[i][1]);
}
input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, i);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
finger_data[i][3]);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
finger_data[i][2]);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
finger_data[i][2]);
input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
finger_data[i][0]);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
finger_data[i][1]);
input_mt_sync(ts->input_dev);
} else if (ts->htc_event == SYN_AND_REPORT_TYPE_B) {
if (ts->support_htc_event) {
input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE,
finger_data[i][3] << 16 | finger_data[i][2]);
input_report_abs(ts->input_dev, ABS_MT_POSITION,
(finger_pressed == 0) << 31 |
finger_data[i][0] << 16 | finger_data[i][1]);
}
input_mt_slot(ts->input_dev, i);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
1);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
finger_data[i][3]);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
finger_data[i][2]);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
finger_data[i][2]);
input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
finger_data[i][0]);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
finger_data[i][1]);
} else if (ts->htc_event == SYN_AND_REPORT_TYPE_HTC) {
input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, i);
input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE,
finger_data[i][3] << 16 | finger_data[i][2]);
input_report_abs(ts->input_dev, ABS_MT_POSITION,
(finger_pressed == 0) << 31 |
finger_data[i][0] << 16 | finger_data[i][1]);
}
if ((finger_press_changed & BIT(i)) && ts->debug_log_level & BIT(3)) {
if(ts->width_factor && ts->height_factor){
printk(KERN_INFO
"[TP] Screen:F[%02d]:Down, X=%d, Y=%d, W=%d, Z=%d\n",
i+1, (finger_data[i][0]*ts->width_factor)>>SHIFT_BITS,
(finger_data[i][1]*ts->height_factor)>>SHIFT_BITS,
finger_data[i][2], finger_data[i][3]);
} else {
printk(KERN_INFO
"[TP] Raw:F[%02d]:Down, X=%d, Y=%d, W=%d, Z=%d\n",
i+1, finger_data[i][0], finger_data[i][1],
finger_data[i][2], finger_data[i][3]);
}
}
if (ts->pre_finger_data[0][0] < 2) {
if (finger_press_changed & BIT(i)) {
ts->pre_finger_data[i + 1][0] = finger_data[i][0];
ts->pre_finger_data[i + 1][1] = finger_data[i][1];
if (!ts->first_pressed)
printk(KERN_INFO "[TP] S%d@%d, %d\n", i + 1,
finger_data[i][0], finger_data[i][1]);
if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT) {
}
}
}
if (ts->htc_event == SYN_AND_REPORT_TYPE_B && ts->reduce_report_level[TAP_DX_OUTER]) {
if (finger_press_changed & BIT(i)) {
ts->tap_suppression &= ~BIT(i);
ts->tap_suppression |= BIT(i);
ts->pre_finger_data[i + 1][2] = finger_data[i][0];
ts->pre_finger_data[i + 1][3] = finger_data[i][1];
if (ts->reduce_report_level[TAP_TIMEOUT] && (ts->tap_suppression))
ts->tap_timeout[i] = jiffies + msecs_to_jiffies(ts->reduce_report_level[TAP_TIMEOUT]);
}
}
if (ts->debug_log_level & BIT(1))
printk(KERN_INFO
"[TP] Finger %d=> X:%d, Y:%d w:%d, z:%d\n",
i + 1, finger_data[i][0], finger_data[i][1],
finger_data[i][2], finger_data[i][3]);
}
if (!ts->finger_count)
ts->pre_finger_data[0][0] = 0;
}
base += 5;
}
#ifdef SYN_FILTER_CONTROL
if (ts->filter_level[0] && ts->grip_suppression) {
ts->ambiguous_state = 0;
for (i = 0; i < ts->finger_support; i++)
if (ts->grip_suppression & BIT(i))
ts->ambiguous_state++;
}
if (ts->debug_log_level & BIT(16))
printk(KERN_INFO "[TP] ts->grip_suppression: %x, ts->ambiguous_state: %x\n",
ts->grip_suppression, ts->ambiguous_state);
#endif
}
}
input_sync(ts->input_dev);
}
static void synaptics_ts_report_func(struct synaptics_ts_data *ts)
{
int ret;
uint8_t data[2] = {0};
ret = i2c_syn_write(ts->client,
get_address_base(ts, 0x54, DATA_BASE) + 1, &data[0], 2);
if (ret < 0)
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
else {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x54, DATA_BASE) + 3, ts->temp_report_data,
ts->x_channel * ts->y_channel * 2);
if (ret >= 0)
memcpy(&ts->report_data[0], &ts->temp_report_data[0], ts->x_channel * ts->y_channel * 2);
else {
memset(&ts->report_data[0], 0x0, sizeof(ts->report_data));
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
}
}
atomic_set(&ts->data_ready, 1);
wake_up(&syn_data_ready_wq);
}
static void synaptics_ts_button_func(struct synaptics_ts_data *ts)
{
int ret;
uint8_t data = 0;
uint16_t x_position = 0, y_position = 0;
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x1A, DATA_BASE), &data, 1);
if (data) {
if (data & 0x01) {
printk("[TP] back key pressed\n");
vk_press = 1;
if (ts->button) {
if (ts->button[0].index) {
x_position = (ts->button[0].x_range_min + ts->button[0].x_range_max) / 2;
y_position = (ts->button[0].y_range_min + ts->button[0].y_range_max) / 2;
}
}
if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
100);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
100);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
100);
input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
x_position);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
y_position);
input_mt_sync(ts->input_dev);
} else if (ts->htc_event == SYN_AND_REPORT_TYPE_B) {
input_mt_slot(ts->input_dev, 0);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
1);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
100);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
100);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
100);
input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
x_position);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
y_position);
}
}
else if (data & 0x02) {
printk("[TP] home key pressed\n");
vk_press = 1;
if (ts->button) {
if (ts->button[1].index) {
x_position = (ts->button[1].x_range_min + ts->button[1].x_range_max) / 2;
y_position = (ts->button[1].y_range_min + ts->button[1].y_range_max) / 2;
}
}
if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
100);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
100);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
100);
input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
x_position);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
y_position);
input_mt_sync(ts->input_dev);
} else if (ts->htc_event == SYN_AND_REPORT_TYPE_B) {
input_mt_slot(ts->input_dev, 0);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
1);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
100);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
100);
input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
100);
input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
x_position);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
y_position);
}
}
}else {
printk("[TP] virtual key released\n");
vk_press = 0;
if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
if (ts->support_htc_event) {
input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
}
input_mt_sync(ts->input_dev);
}
else if (ts->htc_event == SYN_AND_REPORT_TYPE_B) {
input_mt_slot(ts->input_dev, 0);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
}
}
input_sync(ts->input_dev);
}
static void synaptics_ts_status_func(struct synaptics_ts_data *ts)
{
int ret;
uint8_t data = 0;
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, DATA_BASE), &data, 1);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r", __func__);
} else {
data &= 0x0F;
printk(KERN_INFO "[TP] Device Status = %x\n", data);
if (data == 1) {
mutex_lock(&syn_mutex);
ts->page_select = 0;
mutex_unlock(&syn_mutex);
printk(KERN_INFO "[TP] TOUCH: Page Select: %s: %d\n", __func__, ts->page_select);
ret = synaptics_init_panel(ts);
if (ret < 0)
printk(KERN_INFO "[TP]%s: synaptics_init_panel fail\n", __func__);
}
}
}
static void synaptics_ts_work_func(struct work_struct *work)
{
struct synaptics_ts_data *ts = container_of(work, struct synaptics_ts_data, work);
int ret;
uint8_t buf = 0;
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, DATA_BASE) + 1, &buf, 1);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r", __func__);
} else {
if (buf & get_address_base(ts, 0x11, INTR_SOURCE))
synaptics_ts_finger_func(ts);
if (buf & get_address_base(ts, 0x01, INTR_SOURCE))
synaptics_ts_status_func(ts);
if (buf & get_address_base(ts, 0x54, INTR_SOURCE))
synaptics_ts_report_func(ts);
}
}
static irqreturn_t synaptics_irq_thread(int irq, void *ptr)
{
struct synaptics_ts_data *ts = ptr;
int ret;
uint8_t buf = 0;
struct timespec timeStart, timeEnd, timeDelta;
if (ts->debug_log_level & BIT(2)) {
getnstimeofday(&timeStart);
}
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, DATA_BASE) + 1, &buf, 1);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r", __func__);
} else {
if (buf & get_address_base(ts, 0x1A, INTR_SOURCE)) {
if (!ts->finger_count)
synaptics_ts_button_func(ts);
else
printk("[TP] Ignore VK interrupt due to 2d points did not leave\n");
}
if (buf & get_address_base(ts, 0x11, INTR_SOURCE)) {
if (!vk_press) {
synaptics_ts_finger_func(ts);
if(ts->debug_log_level & BIT(2)) {
getnstimeofday(&timeEnd);
timeDelta.tv_nsec = (timeEnd.tv_sec*1000000000+timeEnd.tv_nsec)
-(timeStart.tv_sec*1000000000+timeStart.tv_nsec);
printk(KERN_INFO "[TP] Touch latency = %ld us\n", timeDelta.tv_nsec/1000);
}
}
}
if (buf & get_address_base(ts, 0x01, INTR_SOURCE))
synaptics_ts_status_func(ts);
if (buf & get_address_base(ts, 0x54, INTR_SOURCE))
synaptics_ts_report_func(ts);
}
return IRQ_HANDLED;
}
static enum hrtimer_restart synaptics_ts_timer_func(struct hrtimer *timer)
{
struct synaptics_ts_data *ts = container_of(timer, struct synaptics_ts_data, timer);
queue_work(ts->syn_wq, &ts->work);
hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL);
return HRTIMER_NORESTART;
}
#ifdef SYN_CABLE_CONTROL
static void cable_tp_status_handler_func(int connect_status)
{
struct synaptics_ts_data *ts = gl_ts;
uint8_t data;
int ret;
printk(KERN_INFO "[TP] Touch: cable change to %d\n", connect_status);
if (connect_status)
connect_status = 1;
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, CONTROL_BASE), &data, 1);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
} else {
ts->cable_config = (data & 0xDF) | (connect_status << 5);
printk(KERN_INFO "[TP] %s: ts->cable_config: %x\n", __func__, ts->cable_config);
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x01, CONTROL_BASE), ts->cable_config);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
}
}
}
static struct t_usb_status_notifier cable_status_handler = {
.name = "usb_tp_connected",
.func = cable_tp_status_handler_func,
};
#endif
static void synaptics_ts_close_psensor_func(struct work_struct *work)
{
struct synaptics_ts_data *ts = container_of(work, struct synaptics_ts_data, psensor_work);
if(ts->psensor_resume_enable == 1) {
printk(KERN_INFO "[TP] %s: Disable P-sensor by Touch\n", __func__);
psensor_enable_by_touch_driver(0);
ts->psensor_resume_enable = 0;
}
}
static int psensor_tp_status_handler_func(struct notifier_block *this,
unsigned long status, void *unused)
{
struct synaptics_ts_data *ts = gl_ts;
int ret;
printk(KERN_INFO "[TP] psensor status %d -> %lu\n",
ts->psensor_status, status);
if(ts->psensor_detection) {
if(status == 3 && ts->psensor_resume_enable >= 1) {
if(!(ts->psensor_status==1 && ts->psensor_resume_enable==1)) {
ret = i2c_syn_write_byte_data(ts->client, get_address_base(ts, 0x11, COMMAND_BASE), 0x01);
if (ret < 0)
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:Rezero_1", __func__);
printk(KERN_INFO "[TP] %s: Touch Calibration Confirmed, rezero\n", __func__);
}
if(ts->psensor_resume_enable == 1)
queue_work(ts->syn_psensor_wq, &ts->psensor_work);
else
ts->psensor_resume_enable = 0;
}
}
if (ts->psensor_status == 0) {
if (status == 1)
ts->psensor_status = status;
else
ts->psensor_status = 0;
} else
ts->psensor_status = status;
if(ts->psensor_detection) {
if(ts->psensor_status == 0) {
ts->psensor_resume_enable = 0;
ts->psensor_phone_enable = 0;
}
}
return NOTIFY_OK;
}
static struct notifier_block psensor_status_handler = {
.notifier_call = psensor_tp_status_handler_func,
};
static int syn_pdt_scan(struct synaptics_ts_data *ts, int num_page)
{
uint8_t intr_count = 0, data[6] = {0}, num_function[SYN_MAX_PAGE] = {0};
uint16_t i, j, k = 0;
int ret = 0;
ts->num_function = 0;
for (i = 0; i < num_page; i++) {
for (j = (0xEE | (i << 8)); j >= (0xBE | (i << 8)); j -= 6) {
ret = i2c_syn_read(ts->client, j, data, 1);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r1", __func__);
if (data[0] == 0)
break;
else
num_function[i]++;
}
ts->num_function += num_function[i];
}
if (ts->address_table == NULL) {
ts->address_table = kzalloc(sizeof(struct function_t) * ts->num_function, GFP_KERNEL);
if (ts->address_table == NULL) {
printk(KERN_INFO "[TP] syn_pdt_scan: memory allocate fail\n");
return -ENOMEM;
}
printk(KERN_INFO "[TP] syn_pdt_scan: memory allocate success. ptr: %p\n", ts->address_table);
}
printk(KERN_INFO "[TP] synaptics: %d function supported\n", ts->num_function);
for (i = 0; i < num_page; i++) {
for (j = 0; j < num_function[i]; j++) {
ret = i2c_syn_read(ts->client, i << 8 | (0xE9 - 6*j), data, 6);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
ts->address_table[j + k].query_base = i << 8 | data[0];
ts->address_table[j + k].command_base = i << 8 | data[1];
ts->address_table[j + k].control_base = i << 8 | data[2];
ts->address_table[j + k].data_base = i << 8 | data[3];
if (data[4] & 0x07) {
ts->address_table[j + k].interrupt_source =
get_int_mask(data[4] & 0x07, intr_count);
intr_count += (data[4] & 0x07);
}
ts->address_table[j + k].function_type = data[5];
printk(KERN_INFO
"Query: %2.2X, Command: %4.4X, Control: %2X, Data: %2X, INTR: %2X, Funtion: %2X\n",
ts->address_table[j + k].query_base , ts->address_table[j + k].command_base,
ts->address_table[j + k].control_base, ts->address_table[j + k].data_base,
ts->address_table[j + k].interrupt_source, ts->address_table[j + k].function_type);
}
k += num_function[i];
}
return ts->num_function;
}
static int syn_get_version(struct synaptics_ts_data *ts)
{
uint8_t data[16] = {0};
int ret = 0;
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, QUERY_BASE) + 17, data, 4);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
ts->package_id = data[1] << 8 | data[0];
printk(KERN_INFO "[TP] %s: package_id: %d\n", __func__, ts->package_id);
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, QUERY_BASE) + 18, data, 3);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:3", __func__);
ts->packrat_number = data[2] << 16 | data[1] << 8 | data[0];
printk(KERN_INFO "[TP] %s: packrat_number: %d\n", __func__, ts->packrat_number);
if (ts->packrat_number < SYNAPTICS_FW_3_2_PACKRAT) {
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, QUERY_BASE) + 16, data, 3);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
syn_panel_version = data[0] << 8 | data[2];
printk(KERN_INFO "[TP] %s: panel_version: %x\n", __func__, syn_panel_version);
} else {
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, QUERY_BASE) + 28, data, 16);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
syn_panel_version = data[5] << 8 | data[7];
printk(KERN_INFO "[TP] %s: panel_version: %x\n", __func__, syn_panel_version);
}
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x34, CONTROL_BASE), data, 4);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:4", __func__);
ts->config_version = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
printk(KERN_INFO "[TP] %s: config version: %x\n", __func__, ts->config_version);
return 0;
}
static int syn_get_information(struct synaptics_ts_data *ts)
{
uint8_t data[4] = {0}, i, num_channel, *buf;
int ret = 0;
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x11, QUERY_BASE) + 1, data, 1);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
if ((data[0] & 0x07) == 5)
ts->finger_support = 10;
else if ((data[0] & 0x07) < 5)
ts->finger_support = (data[0] & 0x07) + 1;
else {
printk(KERN_INFO "[TP] %s: number of fingers not define: %x\n",
__func__, data[0] & 0x07);
return SYN_PROCESS_ERR;
}
printk(KERN_INFO "[TP] %s: finger_support: %d\n", __func__, ts->finger_support);
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x11, CONTROL_BASE) + 6, data, 4);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
ts->max[0] = data[0] | data[1] << 8;
ts->max[1] = data[2] | data[3] << 8;
printk(KERN_INFO "[TP] %s: max_x: %d, max_y: %d\n", __func__, ts->max[0], ts->max[1]);
if (get_address_base(ts, 0x54, FUNCTION)) {
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x54, QUERY_BASE), data, 2);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:3", __func__);
ts->y_channel = data[0];
ts->x_channel = data[1];
num_channel = ts->y_channel + ts->x_channel;
buf = kzalloc(num_channel + 1, GFP_KERNEL);
if (buf == NULL) {
printk(KERN_INFO "[TP] %s: memory allocate fail\n", __func__);
return -ENOMEM;
}
if (ts->packrat_number < SYNAPTICS_FW_3_2_PACKRAT)
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x54, CONTROL_BASE) + 17,
buf, num_channel + 1);
else
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x55, CONTROL_BASE),
buf, num_channel + 1);
if (ret < 0) {
kfree(buf);
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:4", __func__);
}
for (i = 1; i < num_channel + 1; i++) {
if (buf[i] == 0xFF) {
if (i <= num_channel - ts->x_channel)
ts->y_channel--;
else
ts->x_channel--;
}
}
if (buf[0] & 0x01)
swap(ts->y_channel, ts->x_channel);
printk(KERN_INFO "[TP] %s: X: %d, Y: %d\n", __func__,
ts->x_channel, ts->y_channel);
kfree(buf);
ts->temp_report_data = kzalloc(2 * ts->x_channel * ts->y_channel, GFP_KERNEL);
ts->report_data = kzalloc(2 * ts->x_channel * ts->y_channel, GFP_KERNEL);
if(ts->temp_report_data == NULL || ts->report_data == NULL)
return -ENOMEM;
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x54, CONTROL_BASE) + 0x10, &ts->relaxation, 1);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:5", __func__);
printk(KERN_INFO "[TP] %s: ts->relaxation: %d\n", __func__, ts->relaxation);
}
if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT) {
if (ts->large_obj_check) {
if (ts->package_id == 2200) {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x26, &ts->default_large_obj, 1);
} else {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x29, &ts->default_large_obj, 1);
}
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:6", __func__);
printk(KERN_INFO "[TP] %s: ts->default_large_obj: %x\n", __func__, ts->default_large_obj);
}
if (ts->segmentation_bef_unlock) {
if (ts->package_id == 2200) {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x25, &ts->segmentation_aft_unlock, 1);
} else {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x22, &ts->segmentation_aft_unlock, 1);
}
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:7", __func__);
printk(KERN_INFO "[TP] %s: ts->segmentation_aft_unlock: %x\n", __func__, ts->segmentation_aft_unlock);
}
if (ts->threshold_bef_unlock) {
if (ts->package_id == 2200) {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x0A, &ts->threshold_aft_unlock, 1);
} else {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x0C, &ts->threshold_aft_unlock, 1);
}
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:8", __func__);
printk(KERN_INFO "[TP] %s: ts->z_threshold_aft_unlock: %x\n", __func__, ts->threshold_aft_unlock);
}
if (ts->saturation_bef_unlock) {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x54, CONTROL_BASE) + 0x02, data, 2);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:8", __func__);
ts->saturation_aft_unlock = (data[1] << 8) | data[0];
printk(KERN_INFO "[TP] %s: ts->saturation_aft_unlock: %x\n", __func__, ts->saturation_aft_unlock);
}
if (ts->PixelTouchThreshold_bef_unlock) {
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x54, CONTROL_BASE) + 0x04, &ts->PixelTouchThreshold_aft_unlock, 1);
if (ret < 0)
return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:9", __func__);
printk(KERN_INFO "[TP] %s: ts->PixelTouchThreshold_aft_unlock: %x\n", __func__, ts->PixelTouchThreshold_aft_unlock);
}
}
return 0;
}
static int synaptics_ts_probe(
struct i2c_client *client, const struct i2c_device_id *id)
{
struct synaptics_ts_data *ts;
uint8_t i;
int ret = 0;
struct synaptics_i2c_rmi_platform_data *pdata;
uint8_t data = 0;
printk(KERN_INFO "[TP] %s: enter", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
printk(KERN_ERR "[TP] TOUCH_ERR: synaptics_ts_probe: need I2C_FUNC_I2C\n");
ret = -ENODEV;
goto err_check_functionality_failed;
}
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
if (ts == NULL) {
ret = -ENOMEM;
goto err_alloc_data_failed;
}
ts->client = client;
i2c_set_clientdata(client, ts);
pdata = client->dev.platform_data;
if (pdata == NULL) {
printk(KERN_INFO "[TP] pdata is NULL\n");
goto err_get_platform_data_fail;
}
ret = i2c_syn_read(ts->client, 0x00EE, &data, 1);
if (ret < 0) {
printk(KERN_INFO "[TP] No Synaptics chip\n");
goto err_detect_failed;
}
for (i = 0; i < 10; i++) {
ret = i2c_syn_read(ts->client, SYN_F01DATA_BASEADDR, &data, 1);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "read device status failed!", __func__);
goto err_detect_failed;
}
if (data & 0x44) {
msleep(20);
#ifdef SYN_FLASH_PROGRAMMING_LOG
printk(KERN_INFO "[TP] synaptics probe: F01_data: %x touch controller stay in bootloader mode!\n", data);
#endif
} else if (data & 0x40) {
printk(KERN_ERR "[TP] TOUCH_ERR: synaptics probe: F01_data: %x touch controller stay in bootloader mode!\n", data);
goto err_detect_failed;
} else
break;
}
if (i == 10) {
uint8_t num = 0;
printk(KERN_INFO "[TP] synaptics probe: touch controller doesn't enter UI mode! F01_data: %x\n", data);
if (syn_pdt_scan(ts, SYN_BL_PAGE) < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: PDT scan fail\n");
goto err_init_failed;
}
if (pdata) {
while (pdata->default_config != 1) {
if (pdata->default_config == 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: touch controller stays in bootloader mode "
"and recovery method doesn't enable\n");
goto err_init_failed;
}
pdata++;
num++;
}
ts->config = pdata->config;
ret = syn_config_update(ts, pdata->gpio_irq);
if (ret < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: syn_config_update fail\n");
goto err_init_failed;
} else if (ret == 0)
printk(KERN_INFO "[TP] syn_config_update success\n");
else
printk(KERN_INFO "[TP] Warning: syn_config_update: the same "
"config version and CRC but touch controller always stay in bootloader mode\n");
pdata = pdata - num;
}
if (ts->address_table != NULL) {
kfree(ts->address_table);
ts->address_table = NULL;
}
}
if (syn_pdt_scan(ts, SYN_MAX_PAGE) < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: PDT scan fail\n");
goto err_init_failed;
}
if (syn_get_version(ts) < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: syn_get_version fail\n");
goto err_init_failed;
}
if (pdata) {
while (pdata->packrat_number && pdata->packrat_number > ts->packrat_number) {
pdata++;
}
if (pdata->tw_pin_mask) {
ts->tw_pin_mask = pdata->tw_pin_mask;
ret = syn_get_tw_vendor(ts, pdata->gpio_irq);
if (ret < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: syn_get_tw_vendor fail\n");
goto err_init_failed;
}
}
while (pdata->sensor_id > 0 && pdata->sensor_id != (SENSOR_ID_CHECKING_EN | ts->tw_vendor)) {
pdata++;
}
printk(KERN_INFO "[TP] synaptics_ts_probe: pdata->version = %x, pdata->packrat_number = %d,"
" pdata->sensor_id = %x\n", pdata->version, pdata->packrat_number, pdata->sensor_id);
if (!pdata->packrat_number) {
printk(KERN_ERR "[TP] TOUCH_ERR: get null platform data\n");
goto err_init_failed;
}
ts->power = pdata->power;
ts->flags = pdata->flags;
ts->htc_event = pdata->report_type;
ts->filter_level = pdata->filter_level;
ts->reduce_report_level = pdata->reduce_report_level;
ts->gpio_irq = pdata->gpio_irq;
ts->gpio_reset = pdata->gpio_reset;
ts->large_obj_check = pdata->large_obj_check;
ts->support_htc_event = pdata->support_htc_event;
ts->mfg_flag = pdata->mfg_flag;
ts->segmentation_bef_unlock = pdata->segmentation_bef_unlock;
ts->i2c_err_handler_en = pdata->i2c_err_handler_en;
ts->threshold_bef_unlock = pdata->threshold_bef_unlock;
ts->saturation_bef_unlock = pdata->saturation_bef_unlock;
ts->energy_ratio_relaxation = pdata->energy_ratio_relaxation;
ts->multitouch_calibration = pdata->multitouch_calibration;
ts->psensor_detection = pdata->psensor_detection;
ts->PixelTouchThreshold_bef_unlock = pdata->PixelTouchThreshold_bef_unlock;
#ifdef SYN_CABLE_CONTROL
ts->cable_support = pdata->cable_support;
#endif
ts->config = pdata->config;
if (pdata->virtual_key)
ts->button = pdata->virtual_key;
}
#ifndef SYN_DISABLE_CONFIG_UPDATE
ret = syn_config_update(ts, pdata->gpio_irq);
if (ret < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: syn_config_update fail\n");
goto err_init_failed;
} else if (ret == 0)
printk(KERN_INFO "[TP] syn_config_update success\n");
else
printk(KERN_INFO "[TP] syn_config_update: the same config version and CRC\n");
#else
if (pdata->tw_pin_mask) {
ret = disable_flash_programming(ts, 0);
if (ret < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: disable_flash_programming fail\n");
goto err_init_failed;
}
}
#endif
if (syn_pdt_scan(ts, SYN_MAX_PAGE) < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: PDT scan fail\n");
goto err_init_failed;
}
#ifndef SYN_DISABLE_CONFIG_UPDATE
if (pdata->customer_register[CUS_REG_BASE]) {
ret = i2c_syn_write(ts->client, pdata->customer_register[CUS_REG_BASE],
&pdata->customer_register[CUS_BALLISTICS_CTRL], CUS_REG_SIZE - 1);
printk(KERN_INFO "[TP] Loads customer register\n");
}
#endif
if (syn_get_information(ts) < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: syn_get_information fail\n");
goto err_syn_get_info_failed;
}
if (pdata->abs_x_max == 0 && pdata->abs_y_max == 0) {
ts->layout[0] = ts->layout[2] = 0;
ts->layout[1] = ts->max[0];
ts->layout[3] = ts->max[1];
} else {
ts->layout[0] = pdata->abs_x_min;
ts->layout[1] = pdata->abs_x_max;
ts->layout[2] = pdata->abs_y_min;
ts->layout[3] = pdata->abs_y_max;
}
if(pdata->display_width && pdata->display_height){
printk(KERN_INFO "[TP] Load display resolution: %dx%d\n", pdata->display_width, pdata->display_height);
ts->width_factor = (pdata->display_width<<SHIFT_BITS)/(ts->layout[1]-ts->layout[0]);
ts->height_factor = (pdata->display_height<<SHIFT_BITS)/(ts->layout[3]-ts->layout[2]);
}
if(get_tamper_sf()==0) {
ts->debug_log_level |= BIT(3);
printk(KERN_INFO "[TP] Debug log level=0x%02X\n", ts->debug_log_level);
}
if (get_address_base(ts, 0x19, FUNCTION)) {
ret = i2c_syn_read(ts->client, get_address_base(ts, 0x19, QUERY_BASE) + 1,
&ts->key_number, 1);
if (ret < 0) {
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "F19 Query fail", __func__);
goto err_F19_query_failed;
}
for (i = 0; i < ts->key_number; i++) {
ts->key_postion_x[i] =
(ts->layout[1] - ts->layout[0]) * (i * 2 + 1) / (ts->key_number * 2)
+ ts->layout[0];
printk(KERN_INFO "[TP] ts->key_postion_x[%d]: %d\n",
i, ts->key_postion_x[i]);
}
ts->key_postion_y = ts->layout[2] +
(21 * (ts->layout[3] - ts->layout[2]) / 20);
printk(KERN_INFO "[TP] ts->key_postion_y: %d\n", ts->key_postion_y);
}
ret = synaptics_init_panel(ts);
if (ret < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: synaptics_init_panel fail\n");
goto err_init_panel_failed;
}
init_waitqueue_head(&syn_data_ready_wq);
if(ts->psensor_detection) {
INIT_WORK(&ts->psensor_work, synaptics_ts_close_psensor_func);
ts->syn_psensor_wq = create_singlethread_workqueue("synaptics_psensor_wq");
if (!ts->syn_psensor_wq)
goto err_create_wq_failed;
}
ret = synaptics_input_register(ts);
if (ret) {
printk(KERN_ERR "[TP] TOUCH_ERR: synaptics_ts_probe: "
"Unable to register %s input device\n",
ts->input_dev->name);
goto err_input_register_device_failed;
}
gl_ts = ts;
ts->irq_enabled = 0;
if (client->irq) {
ts->use_irq = 1;
ret = request_threaded_irq(client->irq, NULL, synaptics_irq_thread,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts);
if (ret == 0) {
ts->irq_enabled = 1;
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x01, CONTROL_BASE) + 1, &ts->intr_bit, 1);
if (ret < 0) {
free_irq(client->irq, ts);
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "get interrupt bit failed", __func__);
goto err_get_intr_bit_failed;
}
printk(KERN_INFO "[TP] %s: interrupt enable: %x\n", __func__, ts->intr_bit);
} else {
dev_err(&client->dev, "[TP] TOUCH_ERR: request_irq failed\n");
ts->use_irq = 0;
}
}
if (!ts->use_irq) {
ts->syn_wq = create_singlethread_workqueue("synaptics_wq");
if (!ts->syn_wq)
goto err_create_wq_failed;
INIT_WORK(&ts->work, synaptics_ts_work_func);
hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = synaptics_ts_timer_func;
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
}
#ifdef CONFIG_HAS_EARLYSUSPEND
ts->early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING - 1;
ts->early_suspend.suspend = synaptics_ts_early_suspend;
ts->early_suspend.resume = synaptics_ts_late_resume;
register_early_suspend(&ts->early_suspend);
#endif
#ifdef SYN_CABLE_CONTROL
if (ts->cable_support) {
usb_register_notifier(&cable_status_handler);
ret = i2c_syn_read(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE), &ts->cable_config, 1);
if (ret < 0) {
printk(KERN_ERR "[TP] TOUCH_ERR: get cable config failed\n");
goto err_get_cable_config_failed;
}
if (usb_get_connect_type())
cable_tp_status_handler_func(1);
printk(KERN_INFO "[TP] %s: ts->cable_config: %x\n", __func__, ts->cable_config);
}
#endif
register_notifier_by_psensor(&psensor_status_handler);
synaptics_touch_sysfs_init();
#ifdef SYN_WIRELESS_DEBUG
if (rmi_char_dev_register())
printk(KERN_INFO "[TP] %s: error register char device", __func__);
#endif
printk(KERN_INFO "[TP] synaptics_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
return 0;
#ifdef SYN_CABLE_CONTROL
err_get_cable_config_failed:
if (ts->use_irq)
free_irq(client->irq, ts);
else
destroy_workqueue(ts->syn_wq);
#endif
err_create_wq_failed:
err_get_intr_bit_failed:
err_input_register_device_failed:
input_free_device(ts->input_dev);
err_init_panel_failed:
err_F19_query_failed:
err_syn_get_info_failed:
if(ts->report_data != NULL)
kfree(ts->report_data);
if(ts->temp_report_data != NULL)
kfree(ts->temp_report_data);
err_init_failed:
if(ts->address_table != NULL)
kfree(ts->address_table);
err_detect_failed:
err_get_platform_data_fail:
kfree(ts);
err_alloc_data_failed:
err_check_functionality_failed:
return ret;
}
static int synaptics_ts_remove(struct i2c_client *client)
{
struct synaptics_ts_data *ts = i2c_get_clientdata(client);
unregister_early_suspend(&ts->early_suspend);
if (ts->use_irq)
free_irq(client->irq, ts);
else {
hrtimer_cancel(&ts->timer);
if (ts->syn_wq)
destroy_workqueue(ts->syn_wq);
}
if(ts->sr_input_dev != NULL)
input_unregister_device(ts->sr_input_dev);
input_unregister_device(ts->input_dev);
synaptics_touch_sysfs_remove();
if(ts->report_data != NULL)
kfree(ts->report_data);
if(ts->temp_report_data != NULL)
kfree(ts->temp_report_data);
if(ts->address_table != NULL)
kfree(ts->address_table);
kfree(ts);
return 0;
}
static int synaptics_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
int ret;
struct synaptics_ts_data *ts = i2c_get_clientdata(client);
printk(KERN_INFO "[TP] %s: enter\n", __func__);
if (ts->use_irq) {
disable_irq(client->irq);
ts->irq_enabled = 0;
} else {
hrtimer_cancel(&ts->timer);
ret = cancel_work_sync(&ts->work);
}
if(ts->psensor_detection) {
if(ts->psensor_resume_enable == 1){
printk(KERN_INFO "[TP] %s: Disable P-sensor by Touch\n", __func__);
psensor_enable_by_touch_driver(0);
ts->psensor_resume_enable = 0;
}
}
if (ts->psensor_status == 0) {
ts->pre_finger_data[0][0] = 0;
if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT) {
ts->first_pressed = 0;
if (ts->large_obj_check) {
if (ts->package_id == 2200) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x26, ts->default_large_obj & 0x7F);
} else {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x29, ts->default_large_obj & 0x7F);
}
if (ret < 0)
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "large obj suppression", __func__);
printk(KERN_INFO "[TP] touch suspend, set large obj suppression: %x\n", ts->default_large_obj & 0x7F);
}
if (ts->segmentation_bef_unlock) {
if (ts->package_id == 2200) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x25, ts->segmentation_bef_unlock);
} else {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x22, ts->segmentation_bef_unlock);
}
if (ret < 0)
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "segmentation aggressiveness", __func__);
printk(KERN_INFO "[TP] touch suspend, set segmentation aggressiveness: %x\n", ts->segmentation_bef_unlock);
}
if (ts->threshold_bef_unlock) {
if (ts->package_id == 2200) {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x0A, ts->threshold_bef_unlock);
} else {
ret = i2c_syn_write_byte_data(ts->client,
get_address_base(ts, 0x11, CONTROL_BASE) + 0x0C, ts->threshold_bef_unlock);
}
if (ret < 0)
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "Z Touch threshold", __func__);
printk(KERN_INFO "[TP] touch suspend, set Z Touch threshold: %x\n", ts->threshold_bef_unlock);
}
}
}
else if(ts->psensor_detection)
ts->psensor_phone_enable = 1;
if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT)
printk(KERN_INFO "[TP][PWR][STATE] get power key state = %d\n", getPowerKeyState());
if (ts->power)
ts->power(0);
else {
if (ts->packrat_number >= SYNAPTICS_FW_NOCAL_PACKRAT) {
ret = i2c_syn_write_byte_data(client,
get_address_base(ts, 0x01, CONTROL_BASE), 0x01);
if (ret < 0)
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "sleep: 0x01", __func__);
} else {
if (ts->psensor_status > 0 && getPowerKeyState() == 0) {
ret = i2c_syn_write_byte_data(client,
get_address_base(ts, 0x01, CONTROL_BASE), 0x02);
if (ret < 0)
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "sleep: 0x02", __func__);
} else {
ret = i2c_syn_write_byte_data(client,
get_address_base(ts, 0x01, CONTROL_BASE), 0x01);
if (ret < 0)
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "sleep: 0x01", __func__);
}
}
}
return 0;
}
static int synaptics_ts_resume(struct i2c_client *client)
{
int ret;
struct synaptics_ts_data *ts = i2c_get_clientdata(client);
printk(KERN_INFO "[TP] %s: enter\n", __func__);
if (ts->power) {
ts->power(1);
msleep(100);
#ifdef SYN_CABLE_CONTROL
if (ts->cable_support) {
if (usb_get_connect_type())
cable_tp_status_handler_func(1);
printk(KERN_INFO "%s: ts->cable_config: %x\n", __func__, ts->cable_config);
}
#endif
} else {
ret = i2c_syn_write_byte_data(client,
get_address_base(ts, 0x01, CONTROL_BASE), 0x00);
if (ret < 0)
i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "wake up", __func__);
}
if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
if (ts->support_htc_event) {
input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
input_sync(ts->input_dev);
}
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
input_sync(ts->input_dev);
} else if (ts->htc_event == SYN_AND_REPORT_TYPE_HTC) {
input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
}
if (ts->psensor_detection) {
if(ts->psensor_status == 0) {
ts->psensor_resume_enable = 1;
printk(KERN_INFO "[TP] %s: Enable P-sensor by Touch\n", __func__);
psensor_enable_by_touch_driver(1);
}
else if(ts->psensor_phone_enable == 0) {
if(ts->psensor_status != 3)
ts->psensor_resume_enable = 2;
ts->psensor_phone_enable = 1;
}
}
if (ts->use_irq) {
enable_irq(client->irq);
ts->irq_enabled = 1;
}
else
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void synaptics_ts_early_suspend(struct early_suspend *h)
{
struct synaptics_ts_data *ts;
ts = container_of(h, struct synaptics_ts_data, early_suspend);
synaptics_ts_suspend(ts->client, PMSG_SUSPEND);
}
static void synaptics_ts_late_resume(struct early_suspend *h)
{
struct synaptics_ts_data *ts;
ts = container_of(h, struct synaptics_ts_data, early_suspend);
synaptics_ts_resume(ts->client);
}
#endif
static const struct i2c_device_id synaptics_ts_id[] = {
{ SYNAPTICS_3200_NAME, 0 },
{ }
};
static struct i2c_driver synaptics_ts_driver = {
.probe = synaptics_ts_probe,
.remove = synaptics_ts_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = synaptics_ts_suspend,
.resume = synaptics_ts_resume,
#endif
.id_table = synaptics_ts_id,
.driver = {
.name = SYNAPTICS_3200_NAME,
},
};
static int __devinit synaptics_ts_init(void)
{
return i2c_add_driver(&synaptics_ts_driver);
}
static void __exit synaptics_ts_exit(void)
{
i2c_del_driver(&synaptics_ts_driver);
}
module_init(synaptics_ts_init);
module_exit(synaptics_ts_exit);
MODULE_DESCRIPTION("Synaptics Touchscreen Driver");
MODULE_LICENSE("GPL");