blob: 53961f44be8bef177f9a6b49ecd85bf2533caa83 [file] [log] [blame]
/* Touch_synaptics.c
*
* Copyright (C) 2011 LGE.
*
* Author: yehan.ahn@lge.com, hyesung.shin@lge.com
*
* 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/err.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/earlysuspend.h>
#include <linux/input/mt.h>
#include <linux/input/lge_touch_core.h>
#include <linux/input/touch_synaptics.h>
#include "SynaImage.h"
#include <linux/regulator/machine.h>
/* RMI4 spec from (RMI4 spec)511-000136-01_revD
* Function Purpose See page
* $01 RMI Device Control 29
* $08 BIST(Built-in Self Test) 38
* $09 BIST(Built-in Self Test) 42
* $11 2-D TouchPad sensors 46
* $19 0-D capacitive button sensors 69
* $30 GPIO/LEDs (includes mechanical buttons) 76
* $32 Timer 89
* $34 Flash Memory Management 93
*/
#define RMI_DEVICE_CONTROL 0x01
#define TOUCHPAD_SENSORS 0x11
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
#define CAPACITIVE_BUTTON_SENSORS 0x1A
#define GPIO_LEDS 0x31
#define ANALOG_CONTROL 0x54
#else
#define CAPACITIVE_BUTTON_SENSORS 0x19
#define GPIO_LEDS 0x30
#endif
#define TIMER 0x32
#define FLASH_MEMORY_MANAGEMENT 0x34
/* Register Map & Register bit mask
* - Please check "One time" this map before using this device driver
*/
#define MANUFACTURER_ID_REG (ts->common_dsc.query_base) /* Manufacturer ID */
#define FW_REVISION_REG (ts->common_dsc.query_base+3) /* FW revision */
#define PRODUCT_ID_REG (ts->common_dsc.query_base+11) /* Product ID */
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
#define FW_VERSION (ts->flash_dsc.control_base)
#endif
#define DEVICE_CONTROL_REG (ts->common_dsc.control_base) /* Device Control */
#define DEVICE_CONTROL_NORMAL_OP 0x00 /* sleep mode : go to doze mode after 500 ms */
#define DEVICE_CONTROL_SLEEP 0x01 /* sleep mode : go to sleep */
#define DEVICE_CONTROL_SPECIFIC 0x02 /* sleep mode : go to doze mode after 5 sec */
#define DEVICE_CONTROL_NOSLEEP 0x04
#define DEVICE_CONTROL_CONFIGURED 0x80
#define INTERRUPT_ENABLE_REG (ts->common_dsc.control_base+1) /* Interrupt Enable 0 */
#define DEVICE_STATUS_REG (ts->common_dsc.data_base) /* Device Status */
#define DEVICE_FAILURE_MASK 0x03
#define DEVICE_CRC_ERROR_MASK 0x04
#define DEVICE_STATUS_FLASH_PROG 0x40
#define DEVICE_STATUS_UNCONFIGURED 0x80
#define INTERRUPT_STATUS_REG (ts->common_dsc.data_base+1) /* Interrupt Status */
#define BUTTON_DATA_REG (ts->button_dsc.data_base) /* Button Data */
#define MAX_NUM_OF_BUTTON 4
#define FINGER_STATE_REG (ts->finger_dsc.data_base) /* Finger State */
#define FINGER_DATA_REG_START (ts->finger_dsc.data_base+3) /* Finger Data Register */
#define FINGER_STATE_MASK 0x03
#define REG_X_POSITION 0
#define REG_Y_POSITION 1
#define REG_YX_POSITION 2
#define REG_WY_WX 3
#define REG_Z 4
#define TWO_D_REPORTING_MODE (ts->finger_dsc.control_base+0) /* 2D Reporting Mode */
#define REPORT_MODE_CONTINUOUS 0x00
#define REPORT_MODE_REDUCED 0x01
#define ABS_FILTER 0x08
#define PALM_DETECT_REG (ts->finger_dsc.control_base+1) /* Palm Detect */
#define DELTA_X_THRESH_REG (ts->finger_dsc.control_base+2) /* Delta-X Thresh */
#define DELTA_Y_THRESH_REG (ts->finger_dsc.control_base+3) /* Delta-Y Thresh */
#define SENSOR_MAX_X_POS (ts->finger_dsc.control_base+6) /* SensorMaxXPos */
#define SENSOR_MAX_Y_POS (ts->finger_dsc.control_base+8) /* SensorMaxYPos */
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
/*do nothing*/
#else
#define GESTURE_ENABLE_1_REG (ts->finger_dsc.control_base+10) /* Gesture Enables 1 */
#define GESTURE_ENABLE_2_REG (ts->finger_dsc.control_base+11) /* Gesture Enables 2 */
#endif
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
#define PAGE_SELECT_REG 0xFF /* Button exists Page 02 */
#define ANALOG_CONTROL_REG (ts->analog_dsc.control_base)
#define ANALOG_COMMAND_REG (ts->analog_dsc.command_base)
#define FAST_RELAXATION_RATE (ts->analog_dsc.control_base+16)
#define FORCE_FAST_RELAXATION 0x04
#define FORCE_UPDATE 0x04
#else
#define MELT_CONTROL_REG 0xF0
#define MELT_CONTROL_NO_MELT 0x00
#define MELT_CONTROL_MELT 0x01
#define MELT_CONTROL_NUKE_MELT 0x80
#endif
#define DEVICE_COMMAND_REG (ts->common_dsc.command_base)
#define FINGER_COMMAND_REG (ts->finger_dsc.command_base)
#define BUTTON_COMMAND_REG (ts->button_dsc.command_base)
#define FLASH_CONTROL_REG (ts->flash_dsc.data_base+18) /* Flash Control */
#define FLASH_STATUS_MASK 0xF0
#define FW_OFFSET_PRODUCT_ID 0x40
#define FW_OFFSET_IMAGE_VERSION 0xB100
/* Get user-finger-data from register.
*/
#define TS_SNTS_GET_X_POSITION(_high_reg, _low_reg) \
(((u16)(((_high_reg) << 4) & 0x0FF0) | (u16)((_low_reg) & 0x0F)))
#define TS_SNTS_GET_Y_POSITION(_high_reg, _low_reg) \
(((u16)(((_high_reg) << 4) & 0x0FF0) | (u16)(((_low_reg) >> 4) & 0x0F)))
#define TS_SNTS_GET_WIDTH_MAJOR(_width) \
((((((_width) & 0xF0) >> 4) - ((_width) & 0x0F)) > 0) ? \
((_width) & 0xF0) >> 4 : (_width) & 0x0F)
#define TS_SNTS_GET_WIDTH_MINOR(_width) \
((((((_width) & 0xF0) >> 4) - ((_width) & 0x0F)) > 0) ? \
(_width) & 0x0F : ((_width) & 0xF0) >> 4)
#define TS_SNTS_GET_ORIENTATION(_width) \
((((((_width) & 0xF0) >> 4) - ((_width) & 0x0F)) >= 0) ? 0 : 1)
#define TS_SNTS_GET_PRESSURE(_pressure) (_pressure)
#define FINGER_STATE_NO_PRESENT 0
#define FINGER_STATE_PRESENT_VALID 1
#define FINGER_STATE_PRESENT_NOVALID 2
#define FINGER_STATE_REVSERVED 3
#define CHARGER_CONNECTED 0x20
static inline int get_highest_id(u32 fs)
{
int id = 10;
int tmp = 0x000C0000;
while(!(fs & tmp)) {
id--;
tmp >>= 2;
}
return id;
}
int synaptics_ts_get_data(struct i2c_client *client, struct t_data* data,
struct b_data* button, u8* total_num)
{
struct synaptics_ts_data* ts =
(struct synaptics_ts_data*)get_touch_handle(client);
u32 finger_status=0;
u8 id=0;
u8 cnt;
if (unlikely(touch_debug_mask & DEBUG_TRACE))
TOUCH_DEBUG_MSG("\n");
if (unlikely(touch_i2c_read(client, DEVICE_STATUS_REG,
sizeof(ts->ts_data.device_status_reg),
&ts->ts_data.device_status_reg) < 0)) {
TOUCH_ERR_MSG("DEVICE_STATUS_REG read fail\n");
goto err_synaptics_getdata;
}
/* ESD damage check */
if ((ts->ts_data.device_status_reg & DEVICE_FAILURE_MASK) ==
DEVICE_FAILURE_MASK) {
TOUCH_ERR_MSG("ESD damage occured. Reset Touch IC\n");
goto err_synaptics_device_damage;
}
/* Internal reset check */
if (((ts->ts_data.device_status_reg & DEVICE_STATUS_UNCONFIGURED) >> 7) == 1) {
TOUCH_ERR_MSG("Touch IC resetted internally. "
"Reconfigure register setting\n");
goto err_synaptics_device_damage;
}
if (unlikely(touch_i2c_read(client, INTERRUPT_STATUS_REG,
sizeof(ts->ts_data.interrupt_status_reg),
&ts->ts_data.interrupt_status_reg) < 0)) {
TOUCH_ERR_MSG("INTERRUPT_STATUS_REG read fail\n");
goto err_synaptics_getdata;
}
if (unlikely(touch_debug_mask & DEBUG_GET_DATA))
TOUCH_INFO_MSG("Interrupt_status : 0x%x\n",
ts->ts_data.interrupt_status_reg);
/* IC bug Exception handling - Interrupt status reg is 0 when interrupt occur */
if (ts->ts_data.interrupt_status_reg == 0) {
TOUCH_ERR_MSG("Interrupt_status reg is 0. -> ignore\n");
goto err_synaptics_ignore;
}
/* Because of ESD damage... */
if (unlikely(ts->ts_data.interrupt_status_reg & ts->interrupt_mask.flash)) {
TOUCH_ERR_MSG("Impossible Interrupt\n");
goto err_synaptics_device_damage;
}
/* Finger */
if (likely(ts->ts_data.interrupt_status_reg & ts->interrupt_mask.abs)) {
if (unlikely(touch_i2c_read(client, FINGER_STATE_REG,
sizeof(ts->ts_data.finger.finger_status_reg),
ts->ts_data.finger.finger_status_reg) < 0)) {
TOUCH_ERR_MSG("FINGER_STATE_REG read fail\n");
goto err_synaptics_getdata;
}
finger_status = ts->ts_data.finger.finger_status_reg[0] |
ts->ts_data.finger.finger_status_reg[1] << 8 |
(ts->ts_data.finger.finger_status_reg[2] & 0xF) << 16;
if (unlikely(touch_debug_mask & DEBUG_GET_DATA)) {
TOUCH_INFO_MSG("Finger_status : 0x%x, 0x%x, 0x%x\n",
ts->ts_data.finger.finger_status_reg[0],
ts->ts_data.finger.finger_status_reg[1],
ts->ts_data.finger.finger_status_reg[2]);
TOUCH_INFO_MSG("Touch_bit_mask: 0x%x\n", finger_status);
}
if (finger_status) {
int max_id = get_highest_id(finger_status);
if (unlikely(touch_i2c_read(ts->client,
FINGER_DATA_REG_START,
NUM_OF_EACH_FINGER_DATA_REG * max_id,
ts->ts_data.finger.finger_reg[0]) < 0)) {
TOUCH_ERR_MSG("FINGER_STATE_REG read fail\n");
goto err_synaptics_getdata;
}
}
for (id = 0; id < ts->pdata->caps->max_id; id++) {
switch (((finger_status >> (id*2)) & 0x3)) {
case FINGER_STATE_PRESENT_VALID:
data[id].state = ABS_PRESS;
data[id].x_position = TS_SNTS_GET_X_POSITION(
ts->ts_data.finger.finger_reg[id][REG_X_POSITION],
ts->ts_data.finger.finger_reg[id][REG_YX_POSITION]);
data[id].y_position = TS_SNTS_GET_Y_POSITION(ts->ts_data.finger.finger_reg[id][REG_Y_POSITION], ts->ts_data.finger.finger_reg[id][REG_YX_POSITION]);
data[id].width_major = TS_SNTS_GET_WIDTH_MAJOR(ts->ts_data.finger.finger_reg[id][REG_WY_WX]);
data[id].width_minor = TS_SNTS_GET_WIDTH_MINOR(ts->ts_data.finger.finger_reg[id][REG_WY_WX]);
data[id].tool_type = MT_TOOL_FINGER;
data[id].width_orientation = TS_SNTS_GET_ORIENTATION(ts->ts_data.finger.finger_reg[id][REG_WY_WX]);
data[id].pressure = TS_SNTS_GET_PRESSURE(ts->ts_data.finger.finger_reg[id][REG_Z]);
if (unlikely(touch_debug_mask & DEBUG_GET_DATA))
TOUCH_INFO_MSG("[%d] pos(%4d,%4d) w_m[%2d] w_n[%2d] w_o[%2d] p[%2d]\n",
id,
data[id].x_position,
data[id].y_position,
data[id].width_major,
data[id].width_minor,
data[id].width_orientation,
data[id].pressure);
(*total_num)++;
break;
case FINGER_STATE_NO_PRESENT:
if (data[id].state == ABS_PRESS)
data[id].state = ABS_RELEASE;
break;
default:
/* Do nothing including inacurate data */
break;
}
}
if (unlikely(touch_debug_mask & DEBUG_GET_DATA))
TOUCH_INFO_MSG("Total_num: %d\n", *total_num);
}
/* Button */
if ((ts->button_dsc.id != 0) && (ts->ts_data.interrupt_status_reg &
ts->interrupt_mask.button)) {
if (unlikely(touch_i2c_write_byte(client,
PAGE_SELECT_REG, 0x02) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_read(client, BUTTON_DATA_REG,
sizeof(ts->ts_data.button_data_reg),
&ts->ts_data.button_data_reg) < 0)) {
TOUCH_ERR_MSG("BUTTON_DATA_REG read fail\n");
goto err_synaptics_getdata;
}
if (unlikely(touch_i2c_write_byte(client,
PAGE_SELECT_REG, 0x00) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
if (unlikely(touch_debug_mask & DEBUG_BUTTON))
TOUCH_DEBUG_MSG("Button register: 0x%x\n",
ts->ts_data.button_data_reg);
if (ts->ts_data.button_data_reg) {
/* pressed - find first one */
for (cnt = 0; cnt < ts->pdata->caps->number_of_button; cnt++) {
if ((ts->ts_data.button_data_reg >> cnt) & 1)
{
ts->ts_data.button.key_code =
ts->pdata->caps->button_name[cnt];
button->key_code =
ts->ts_data.button.key_code;
button->state = 1;
break;
}
}
} else {
/* release */
button->key_code = ts->ts_data.button.key_code;
button->state = 0;
}
}
return 0;
err_synaptics_device_damage:
err_synaptics_getdata:
return -EIO;
err_synaptics_ignore:
return -EINVAL;
}
static int read_page_description_table(struct i2c_client* client)
{
struct synaptics_ts_data* ts =
(struct synaptics_ts_data*)get_touch_handle(client);
struct ts_function_descriptor buffer;
unsigned short u_address;
if (touch_debug_mask & DEBUG_TRACE)
TOUCH_DEBUG_MSG("\n");
memset(&buffer, 0x0, sizeof(struct ts_function_descriptor));
ts->common_dsc.id = 0;
ts->finger_dsc.id = 0;
ts->button_dsc.id = 0;
ts->flash_dsc.id = 0;
ts->analog_dsc.id = 0;
for (u_address = DESCRIPTION_TABLE_START; u_address > 10;
u_address -= sizeof(struct ts_function_descriptor)) {
if (unlikely(touch_i2c_read(client, u_address, sizeof(buffer),
(unsigned char *)&buffer) < 0)) {
TOUCH_ERR_MSG("RMI4 Function Descriptor read fail\n");
return -EIO;
}
if (buffer.id == 0)
break;
switch (buffer.id) {
case RMI_DEVICE_CONTROL:
ts->common_dsc = buffer;
break;
case TOUCHPAD_SENSORS:
ts->finger_dsc = buffer;
break;
case FLASH_MEMORY_MANAGEMENT:
ts->flash_dsc = buffer;
break;
}
}
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
if (unlikely(touch_i2c_write_byte(client, PAGE_SELECT_REG, 0x01) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_read(client, ANALOG_TABLE_START, sizeof(buffer), (unsigned char *)&buffer) < 0)) {
TOUCH_ERR_MSG("RMI4 Function Descriptor read fail\n");
return -EIO;
}
if (buffer.id == ANALOG_CONTROL) {
ts->analog_dsc = buffer;
}
if (unlikely(touch_i2c_write_byte(client, PAGE_SELECT_REG, 0x02) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_read(ts->client, BUTTON_TABLE_START, sizeof(buffer), (unsigned char *)&buffer))) {
TOUCH_ERR_MSG("Button ts_function_descriptor read fail\n");
return -EIO;
}
if (buffer.id == CAPACITIVE_BUTTON_SENSORS)
ts->button_dsc = buffer;
if (unlikely(touch_i2c_write_byte(client, PAGE_SELECT_REG, 0x00) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
#endif
/* set interrupt mask */
ts->interrupt_mask.flash = 0x1;
ts->interrupt_mask.status = 0x2;
if (ts->button_dsc.id == 0) {
ts->interrupt_mask.abs = 0x4;
} else {
if (ts->finger_dsc.data_base > ts->button_dsc.data_base) {
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
ts->interrupt_mask.abs = 0x4;
ts->interrupt_mask.button = 0x20;
#else
ts->interrupt_mask.abs = 0x8;
ts->interrupt_mask.button = 0x4;
#endif
} else {
ts->interrupt_mask.abs = 0x4;
ts->interrupt_mask.button = 0x8;
}
}
if (ts->common_dsc.id == 0 || ts->finger_dsc.id == 0 ||
ts->flash_dsc.id == 0) {
TOUCH_ERR_MSG("common_dsc/finger_dsc/flash_dsc are not initiailized\n");
return -EPERM;
}
if (touch_debug_mask & DEBUG_BASE_INFO)
TOUCH_INFO_MSG("common[%d] finger[%d] flash[%d] button[%d]\n",
ts->common_dsc.id, ts->finger_dsc.id,
ts->flash_dsc.id, ts->button_dsc.id);
return 0;
}
int get_ic_info(struct synaptics_ts_data* ts, struct touch_fw_info* fw_info)
{
#if defined(ARRAYED_TOUCH_FW_BIN)
int cnt;
#endif
u8 device_status = 0;
u8 flash_control = 0;
read_page_description_table(ts->client);
memset(fw_info, 0, sizeof(fw_info));
if (unlikely(touch_i2c_read(ts->client, FW_REVISION_REG,
sizeof(fw_info->fw_rev), &fw_info->fw_rev) < 0)) {
TOUCH_ERR_MSG("FW_REVISION_REG read fail\n");
return -EIO;
}
if (unlikely(touch_i2c_read(ts->client, MANUFACTURER_ID_REG,
sizeof(fw_info->manufacturer_id),
&fw_info->manufacturer_id) < 0)) {
TOUCH_ERR_MSG("MANUFACTURER_ID_REG read fail\n");
return -EIO;
}
if (unlikely(touch_i2c_read(ts->client, PRODUCT_ID_REG,
sizeof(fw_info->product_id) - 1,
fw_info->product_id) < 0)) {
TOUCH_ERR_MSG("PRODUCT_ID_REG read fail\n");
return -EIO;
}
if (unlikely(touch_i2c_read(ts->client, FW_VERSION,
sizeof(fw_info->fw_version) - 1,
fw_info->fw_version) < 0)) {
TOUCH_ERR_MSG("FW_VERSION read fail\n");
return -EIO;
}
ts->ic_panel_type = IC7020_G2_H_PTN;
TOUCH_INFO_MSG("IC is 7020, H pattern, panel is G2, Firmware: %s.", fw_info->fw_version);
#if defined(ARRAYED_TOUCH_FW_BIN)
for (cnt = 0; cnt < sizeof(SynaFirmware)/sizeof(SynaFirmware[0]); cnt++) {
strncpy(fw_info->fw_image_product_id,
&SynaFirmware[cnt][FW_OFFSET_PRODUCT_ID], 10);
if (!(strncmp(fw_info->product_id,
fw_info->fw_image_product_id, 10)))
break;
}
fw_info->fw_start = (unsigned char *)&SynaFirmware[cnt][0];
fw_info->fw_size = sizeof(SynaFirmware[0]);
#else
fw_info->fw_start = (unsigned char *)&SynaFirmware[0];
fw_info->fw_size = sizeof(SynaFirmware);
#endif
strncpy(fw_info->fw_image_product_id,
&fw_info->fw_start[FW_OFFSET_PRODUCT_ID], 10);
strncpy(fw_info->fw_image_version,
&fw_info->fw_start[FW_OFFSET_IMAGE_VERSION],4);
if (unlikely(touch_i2c_read(ts->client, FLASH_CONTROL_REG,
sizeof(flash_control), &flash_control) < 0)) {
TOUCH_ERR_MSG("FLASH_CONTROL_REG read fail\n");
return -EIO;
}
if (unlikely(touch_i2c_read(ts->client, DEVICE_STATUS_REG,
sizeof(device_status), &device_status) < 0)) {
TOUCH_ERR_MSG("DEVICE_STATUS_REG read fail\n");
return -EIO;
}
/* Firmware has a problem, so we should firmware-upgrade */
if (device_status & DEVICE_STATUS_FLASH_PROG
|| (device_status & DEVICE_CRC_ERROR_MASK) != 0
|| (flash_control & FLASH_STATUS_MASK) != 0) {
TOUCH_ERR_MSG("Firmware has a unknown-problem, "
"so it needs firmware-upgrade.\n");
TOUCH_ERR_MSG("FLASH_CONTROL[%x] DEVICE_STATUS_REG[%x]\n",
(u32)flash_control, (u32)device_status);
fw_info->fw_rev = 0;
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
fw_info->fw_force_rework = true;
#endif
}
ts->fw_info = fw_info;
return 0;
}
int synaptics_ts_init(struct i2c_client* client, struct touch_fw_info* fw_info)
{
struct synaptics_ts_data* ts =
(struct synaptics_ts_data*)get_touch_handle(client);
struct lge_touch_data *lg_ts =
(struct lge_touch_data *) i2c_get_clientdata(client);
u8 buf;
if (touch_debug_mask & DEBUG_TRACE)
TOUCH_DEBUG_MSG("\n");
if (!ts->is_probed)
if (unlikely(get_ic_info(ts, fw_info) < 0))
return -EIO;
if (unlikely(touch_i2c_write_byte(client, DEVICE_CONTROL_REG,
DEVICE_CONTROL_NOSLEEP | DEVICE_CONTROL_CONFIGURED |
(lg_ts->charger_type ? CHARGER_CONNECTED : 0)) < 0)) {
TOUCH_ERR_MSG("DEVICE_CONTROL_REG write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_read(client, INTERRUPT_ENABLE_REG,
1, &buf) < 0)) {
TOUCH_ERR_MSG("INTERRUPT_ENABLE_REG read fail\n");
return -EIO;
}
if (!lg_ts->pdata->caps->button_support) {
buf &= ~ts->interrupt_mask.button;
ts->interrupt_mask.button = 0;
}
if (unlikely(touch_i2c_write_byte(client, INTERRUPT_ENABLE_REG,
buf | ts->interrupt_mask.abs | ts->interrupt_mask.button) < 0)) {
TOUCH_ERR_MSG("INTERRUPT_ENABLE_REG write fail\n");
return -EIO;
}
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
if (unlikely(touch_i2c_read(client, TWO_D_REPORTING_MODE, 1, &buf) < 0)) {
TOUCH_ERR_MSG("TWO_D_REPORTING_MODE read fail\n");
return -EIO;
}
if (ts->pdata->role->report_mode == CONTINUOUS_REPORT_MODE) {
if (unlikely(touch_i2c_write_byte(client, TWO_D_REPORTING_MODE,
(buf & ~7) | REPORT_MODE_CONTINUOUS) < 0)) {
TOUCH_ERR_MSG("TWO_D_REPORTING_MODE write fail\n");
return -EIO;
}
} else { /* REDUCED_REPORT_MODE */
if (unlikely(touch_i2c_write_byte(client, TWO_D_REPORTING_MODE,
(buf & ~7) | REPORT_MODE_REDUCED) < 0)) {
TOUCH_ERR_MSG("TWO_D_REPORTING_MODE write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client, DELTA_X_THRESH_REG,
ts->pdata->role->delta_pos_threshold) < 0)) {
TOUCH_ERR_MSG("DELTA_X_THRESH_REG write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client, DELTA_Y_THRESH_REG,
ts->pdata->role->delta_pos_threshold) < 0)) {
TOUCH_ERR_MSG("DELTA_Y_THRESH_REG write fail\n");
return -EIO;
}
}
#else
if (unlikely(touch_i2c_write_byte(client,
GESTURE_ENABLE_1_REG, 0x00) < 0)) {
TOUCH_ERR_MSG("GESTURE_ENABLE_1_REG write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client, GESTURE_ENABLE_2_REG, 0x00) < 0)) {
TOUCH_ERR_MSG("GESTURE_ENABLE_2_REG write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_read(client, TWO_D_REPORTING_MODE, 1, &buf) < 0)) {
TOUCH_ERR_MSG("TWO_D_REPORTING_MODE read fail\n");
return -EIO;
}
if (ts->pdata->role->report_mode == CONTINUOUS_REPORT_MODE) {
if (unlikely(touch_i2c_write_byte(client, TWO_D_REPORTING_MODE,
(buf & ~7) | REPORT_MODE_CONTINUOUS) < 0)) {
TOUCH_ERR_MSG("TWO_D_REPORTING_MODE write fail\n");
return -EIO;
}
} else { /* REDUCED_REPORT_MODE */
if (unlikely(touch_i2c_write_byte(client, TWO_D_REPORTING_MODE,
(buf & ~7) | REPORT_MODE_REDUCED) < 0)) {
TOUCH_ERR_MSG("TWO_D_REPORTING_MODE write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client, DELTA_X_THRESH_REG,
ts->pdata->role->delta_pos_threshold) < 0)) {
TOUCH_ERR_MSG("DELTA_X_THRESH_REG write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client, DELTA_Y_THRESH_REG,
ts->pdata->role->delta_pos_threshold) < 0)) {
TOUCH_ERR_MSG("DELTA_Y_THRESH_REG write fail\n");
return -EIO;
}
}
#endif
if (unlikely(touch_i2c_read(client, INTERRUPT_STATUS_REG, 1, &buf) < 0)) {
TOUCH_ERR_MSG("INTERRUPT_STATUS_REG read fail\n");
return -EIO; /* it is critical problem because interrupt will not occur. */
}
if (unlikely(touch_i2c_read(client, FINGER_STATE_REG,
sizeof(ts->ts_data.finger.finger_status_reg),
ts->ts_data.finger.finger_status_reg) < 0)) {
TOUCH_ERR_MSG("FINGER_STATE_REG read fail\n");
/* it is critical problem because interrupt will not occur on some FW. */
return -EIO;
}
ts->is_probed = 1;
return 0;
}
int synaptics_ts_power(struct i2c_client* client, int power_ctrl)
{
struct synaptics_ts_data* ts =
(struct synaptics_ts_data*)get_touch_handle(client);
struct lge_touch_data *lg_ts =
(struct lge_touch_data *) i2c_get_clientdata(client);
if (touch_debug_mask & DEBUG_TRACE)
TOUCH_DEBUG_MSG("\n");
switch (power_ctrl) {
case POWER_OFF:
if (ts->pdata->reset_pin > 0)
gpio_set_value(ts->pdata->reset_pin, 0);
if (ts->pdata->pwr->use_regulator) {
regulator_disable(ts->regulator_vio);
regulator_disable(ts->regulator_vdd);
}
else
ts->pdata->pwr->power(0);
break;
case POWER_ON:
if (ts->pdata->pwr->use_regulator) {
regulator_enable(ts->regulator_vdd);
regulator_enable(ts->regulator_vio);
}
else
ts->pdata->pwr->power(1);
if (ts->pdata->reset_pin > 0)
gpio_set_value(ts->pdata->reset_pin, 1);
break;
case POWER_SLEEP:
if (unlikely(touch_i2c_write_byte(client, DEVICE_CONTROL_REG,
DEVICE_CONTROL_SLEEP |
(lg_ts->charger_type ? CHARGER_CONNECTED : 0) |
DEVICE_CONTROL_CONFIGURED) < 0)) {
TOUCH_ERR_MSG("DEVICE_CONTROL_REG write fail\n");
return -EIO;
}
break;
case POWER_WAKE:
if (unlikely(touch_i2c_write_byte(client, DEVICE_CONTROL_REG,
DEVICE_CONTROL_SPECIFIC |
(lg_ts->charger_type ? CHARGER_CONNECTED : 0) |
DEVICE_CONTROL_CONFIGURED) < 0)) {
TOUCH_ERR_MSG("DEVICE_CONTROL_REG write fail\n");
return -EIO;
}
break;
default:
return -EIO;
break;
}
return 0;
}
int synaptics_ts_probe(struct i2c_client* client)
{
struct synaptics_ts_data* ts;
int ret = 0;
if (touch_debug_mask & DEBUG_TRACE)
TOUCH_DEBUG_MSG("\n");
ts = kzalloc(sizeof(struct synaptics_ts_data), GFP_KERNEL);
if (!ts) {
TOUCH_ERR_MSG("Can not allocate memory\n");
ret = -ENOMEM;
goto err_alloc_data_failed;
}
set_touch_handle(client, ts);
ts->client = client;
ts->pdata = client->dev.platform_data;
#if defined(CONFIG_TOUCH_REG_MAP_TM2000)
ts->ic_panel_type = IC7020_G2_H_PTN;
#elif defined(CONFIG_TOUCH_REG_MAP_TM2372)
ts->ic_panel_type = IC7020_GFF_H_PTN;
#endif
if (ts->pdata->pwr->use_regulator) {
ts->regulator_vdd =
regulator_get_exclusive(NULL, ts->pdata->pwr->vdd);
if (IS_ERR(ts->regulator_vdd)) {
TOUCH_ERR_MSG("FAIL: regulator_get_vdd - %s\n",
ts->pdata->pwr->vdd);
ret = -EPERM;
goto err_get_vdd_failed;
}
ts->regulator_vio = regulator_get_exclusive(NULL,
ts->pdata->pwr->vio);
if (IS_ERR(ts->regulator_vio)) {
TOUCH_ERR_MSG("FAIL: regulator_get_vio - %s\n",
ts->pdata->pwr->vio);
ret = -EPERM;
goto err_get_vio_failed;
}
if (ts->pdata->pwr->vdd_voltage > 0) {
ret = regulator_set_voltage(ts->regulator_vdd,
ts->pdata->pwr->vdd_voltage,
ts->pdata->pwr->vdd_voltage);
if (ret < 0) {
TOUCH_ERR_MSG("FAIL: VDD voltage setting"
" - (%duV)\n",
ts->pdata->pwr->vdd_voltage);
ret = -EPERM;
goto err_set_voltage;
}
}
if (ts->pdata->pwr->vio_voltage > 0) {
ret = regulator_set_voltage(ts->regulator_vio,
ts->pdata->pwr->vio_voltage,
ts->pdata->pwr->vio_voltage);
if (ret < 0) {
TOUCH_ERR_MSG("FAIL: VIO voltage setting"
" - (%duV)\n",
ts->pdata->pwr->vio_voltage);
ret = -EPERM;
goto err_set_voltage;
}
}
}
return ret;
err_set_voltage:
if (ts->pdata->pwr->use_regulator) {
regulator_put(ts->regulator_vio);
}
err_get_vio_failed:
if (ts->pdata->pwr->use_regulator) {
regulator_put(ts->regulator_vdd);
}
err_get_vdd_failed:
kfree(ts);
err_alloc_data_failed:
return ret;
}
void synaptics_ts_remove(struct i2c_client* client)
{
struct synaptics_ts_data* ts =
(struct synaptics_ts_data*)get_touch_handle(client);
if (touch_debug_mask & DEBUG_TRACE)
TOUCH_DEBUG_MSG("\n");
if (ts->pdata->pwr->use_regulator) {
regulator_put(ts->regulator_vio);
regulator_put(ts->regulator_vdd);
}
kfree(ts);
}
int synaptics_ts_fw_upgrade(struct i2c_client* client, const char* fw_path)
{
struct synaptics_ts_data* ts =
(struct synaptics_ts_data*)get_touch_handle(client);
int ret = 0;
ts->is_probed = 0;
ret = FirmwareUpgrade(ts, fw_path);
/* update IC info */
get_ic_info(ts, ts->fw_info);
return ret;
}
int synaptics_ts_ic_ctrl(struct i2c_client *client, u8 code, u16 value)
{
struct synaptics_ts_data* ts =
(struct synaptics_ts_data*)get_touch_handle(client);
u8 buf = 0;
u8 new;
switch (code) {
case IC_CTRL_BASELINE:
switch (value) {
case BASELINE_OPEN:
if (!ts->analog_dsc.id) /* If not supported, ignore */
break;
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
if (unlikely(touch_i2c_write_byte(client,
PAGE_SELECT_REG, 0x01) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client,
ANALOG_CONTROL_REG,
FORCE_FAST_RELAXATION) < 0)) {
TOUCH_ERR_MSG("ANALOG_CONTROL_REG write fail\n");
return -EIO;
}
msleep(10);
if (unlikely(touch_i2c_write_byte(client,
ANALOG_COMMAND_REG,
FORCE_UPDATE) < 0)) {
TOUCH_ERR_MSG("force fast relaxation command write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client,
PAGE_SELECT_REG, 0x00) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
if (unlikely(touch_debug_mask & DEBUG_GHOST))
TOUCH_INFO_MSG("BASELINE_OPEN ~~~~~~~~\n");
#else
if (unlikely(touch_i2c_write_byte(client,
MELT_CONTROL_REG,
MELT_CONTROL_MELT) < 0)) {
TOUCH_ERR_MSG("MELT_CONTROL_REG write fail\n");
return -EIO;
}
#endif
break;
case BASELINE_FIX:
if (!ts->analog_dsc.id) /* If not supported, ignore */
break;
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
if (unlikely(touch_i2c_write_byte(client,
PAGE_SELECT_REG, 0x01) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client,
ANALOG_CONTROL_REG, 0x0) < 0)) {
TOUCH_ERR_MSG("ANALOG_CONTROL_REG write fail\n");
return -EIO;
}
msleep(10);
if (unlikely(touch_i2c_write_byte(client,
ANALOG_COMMAND_REG,
FORCE_UPDATE) < 0)) {
TOUCH_ERR_MSG("force fast relaxation command write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client,
PAGE_SELECT_REG, 0x00) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
if (unlikely(touch_debug_mask & DEBUG_GHOST))
TOUCH_INFO_MSG("BASELINE_FIX ~~~~~~~~\n");
#else
if (unlikely(touch_i2c_write_byte(client,
MELT_CONTROL_REG,
MELT_CONTROL_NO_MELT) < 0)) {
TOUCH_ERR_MSG("MELT_CONTROL_REG write fail\n");
return -EIO;
}
#endif
break;
case BASELINE_REBASE:
/* rebase base line */
if (likely(ts->finger_dsc.id != 0)) {
if (unlikely(touch_i2c_write_byte(client,
FINGER_COMMAND_REG, 0x1) < 0)) {
TOUCH_ERR_MSG("finger baseline reset "
"command write fail\n");
return -EIO;
}
}
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
/* do nothing */
#else
if (unlikely(ts->button_dsc.id != 0)) {
if (unlikely(touch_i2c_write_byte(client,
BUTTON_COMMAND_REG, 0x1) < 0)) {
TOUCH_ERR_MSG("finger baseline reset "
"command write fail\n");
return -EIO;
}
}
#endif
break;
default:
break;
}
break;
case IC_CTRL_READ:
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
if (unlikely(touch_i2c_write_byte(client,
PAGE_SELECT_REG, ((value & 0xFF00) >> 8)) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
if (touch_i2c_read(client, (value & 0xFF), 1, &buf) < 0) {
TOUCH_ERR_MSG("IC register read fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client,
PAGE_SELECT_REG, 0x00) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
#else
if (touch_i2c_read(client, value, 1, &buf) < 0) {
TOUCH_ERR_MSG("IC register read fail\n");
return -EIO;
}
#endif
break;
case IC_CTRL_WRITE:
#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
if (unlikely(touch_i2c_write_byte(client,
PAGE_SELECT_REG, ((value & 0xFF0000) >> 16)) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
if (touch_i2c_write_byte(client,
((value & 0xFF00) >> 8), (value & 0xFF)) < 0) {
TOUCH_ERR_MSG("IC register write fail\n");
return -EIO;
}
if (unlikely(touch_i2c_write_byte(client,
PAGE_SELECT_REG, 0x00) < 0)) {
TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
return -EIO;
}
#else
if (touch_i2c_write_byte(client,
((value & 0xFF00) >> 8), (value & 0xFF)) < 0) {
TOUCH_ERR_MSG("IC register write fail\n");
return -EIO;
}
#endif
break;
case IC_CTRL_RESET_CMD:
if (unlikely(touch_i2c_write_byte(client,
DEVICE_COMMAND_REG, 0x1) < 0)) {
TOUCH_ERR_MSG("IC Reset command write fail\n");
return -EIO;
}
break;
case IC_CTRL_CHARGER:
if (touch_i2c_read(client, DEVICE_CONTROL_REG, 1, &buf) < 0) {
TOUCH_ERR_MSG("IC register read fail\n");
return -EIO;
}
new = buf & ~CHARGER_CONNECTED;
new |= value ? CHARGER_CONNECTED : 0;
if (new != buf) {
if (unlikely(touch_i2c_write_byte(client,
DEVICE_CONTROL_REG, new) < 0)) {
TOUCH_ERR_MSG("IC Reset command write fail\n");
return -EIO;
}
TOUCH_INFO_MSG("CHARGER = %d\n", !!value);
}
break;
default:
break;
}
return buf;
}
int synaptics_ts_fw_upgrade_check(struct lge_touch_data *ts)
{
if (ts->fw_info.fw_force_rework || ts->fw_upgrade.fw_force_upgrade) {
TOUCH_INFO_MSG("FW-upgrade Force Rework.\n");
} else {
if (((int)simple_strtoul(&ts->fw_info.fw_version[1], NULL, 10) >= (int)simple_strtoul(&ts->fw_info.fw_image_version[1], NULL, 10))) {
TOUCH_INFO_MSG("DO NOT UPDATE 7020 G2 H " "pattern FW-upgrade is not executed\n");
return -1;
} else {
TOUCH_INFO_MSG("7020 G2 H pattern FW-upgrade " "is executed\n");
}
}
return 0;
}
struct touch_device_driver synaptics_ts_driver = {
.probe = synaptics_ts_probe,
.remove = synaptics_ts_remove,
.init = synaptics_ts_init,
.data = synaptics_ts_get_data,
.power = synaptics_ts_power,
.fw_upgrade = synaptics_ts_fw_upgrade,
.ic_ctrl = synaptics_ts_ic_ctrl,
.fw_upgrade_check = synaptics_ts_fw_upgrade_check,
};
static int __devinit touch_init(void)
{
if (touch_debug_mask & DEBUG_TRACE)
TOUCH_DEBUG_MSG("\n");
return touch_driver_register(&synaptics_ts_driver);
}
static void __exit touch_exit(void)
{
if (touch_debug_mask & DEBUG_TRACE)
TOUCH_DEBUG_MSG("\n");
touch_driver_unregister();
}
module_init(touch_init);
module_exit(touch_exit);
MODULE_AUTHOR("yehan.ahn@lge.com, hyesung.shin@lge.com");
MODULE_DESCRIPTION("LGE Touch Driver");
MODULE_LICENSE("GPL");