From: hhb Date: Thu, 3 May 2012 02:18:04 +0000 (+0800) Subject: add synaptics_i2c_rmi4 touch screen driver X-Git-Tag: firefly_0821_release~9269 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=6c88a8c8e36cf6a9cf20fefa690aeb0b978dbfe4;p=firefly-linux-kernel-4.4.55.git add synaptics_i2c_rmi4 touch screen driver --- diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index feec9ba34e5d..11ca0d0ace01 100755 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -977,6 +977,15 @@ config TOUCHSCREEN_GT818_IIC config TOUCHSCREEN_PIXCIR tristate "PIXCIR_IIC based touchscreens" depends on I2C2_RK29 + +config TOUCHSCREEN_SYNAPTICS_RMI4_I2C_RK + tristate "Synaptics i2c rmi4 touchscreen" + depends on I2C2_RK30 + help + This enables support for Synaptics RMI over I2C based touchscreens. + config TOUCHSCREEN_SYNAPTICS_S3202 + tristate "SYNAPTICS S3202 touchscreen" + depends on TOUCHSCREEN_SYNAPTICS_RMI4_I2C_RK config D70_L3188A tristate "D70-L3188A based touchscreens" @@ -988,7 +997,7 @@ config TOUCHSCREEN_GT819 config TOUCHSCREEN_FT5306 tristate "FT5306 based touchscreens: FT5306 Interface" - depends on I2C2_RK29 + depends on I2C2_RK29 || I2C2_RK30 config TOUCHSCREEN_FT5406 tristate "FT5406 based touchscreens: FT5406 Interface" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 5650e9a9ecc9..c00b73cd1131 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -85,3 +85,4 @@ obj-$(CONFIG_TOUCHSCREEN_GT819) += gt819.o obj-$(CONFIG_TOUCHSCREEN_NAS) += nas_ts.o obj-$(CONFIG_LAIBAO_TS) += ft5x0x_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_RK) += synaptics_i2c_rmi4.o diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c new file mode 100644 index 000000000000..c01fcea65e70 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c @@ -0,0 +1,1603 @@ +/** + * + * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver. + * Copyright (c) 2007-2010, Synaptics Incorporated + * + * Author: Js HA for ST-Ericsson + * Author: Naveen Kumar G for ST-Ericsson + * Copyright 2010 (c) ST-Ericsson AB + */ +/* + * This file is licensed under the GPL2 license. + * + *############################################################################# + * GPL + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "synaptics_i2c_rmi4.h" + +/* TODO: for multiple device support will need a per-device mutex */ +#define DRIVER_NAME "synaptics_rmi4_i2c" + +#define MAX_ERROR_REPORT 6 +#define MAX_TOUCH_MAJOR 15 +#define MAX_RETRY_COUNT 5 +#define STD_QUERY_LEN 21 +#define PAGE_LEN 2 +#define DATA_BUF_LEN 32 +#define BUF_LEN 37 +#define QUERY_LEN 9 +#define DATA_LEN 12 +#define HAS_TAP 0x01 +#define HAS_PALMDETECT 0x01 +#define HAS_ROTATE 0x02 +#define HAS_TAPANDHOLD 0x02 +#define HAS_DOUBLETAP 0x04 +#define HAS_EARLYTAP 0x08 +#define HAS_RELEASE 0x08 +#define HAS_FLICK 0x10 +#define HAS_PRESS 0x20 +#define HAS_PINCH 0x40 + +#define MASK_16BIT 0xFFFF +#define MASK_8BIT 0xFF +#define MASK_7BIT 0x7F +#define MASK_5BIT 0x1F +#define MASK_4BIT 0x0F +#define MASK_3BIT 0x07 +#define MASK_2BIT 0x03 +/* cwz: change 0x08 -> 0x04 for RMI version 4.03 */ +#if 0 +#define TOUCHPAD_CTRL_INTR 0x8 +#else +#define TOUCHPAD_CTRL_INTR 0x4 //rmi4_acgzx modified +#endif +#define PDT_START_SCAN_LOCATION (0x00E9) +#define PDT_END_SCAN_LOCATION (0x000A) +#define PDT_ENTRY_SIZE (0x0006) + +#define RMI4_NUMBER_OF_MAX_FINGERS (8) +#define SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM (0x11) +#define SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM (0x01) + +#define SYNA_SUPPORT_POINT_MAX (5) +#define SYNA_FINGER_MAX (5) + +#define SYNA_I2C_BUS_IO 1 /* cwz: 1 for i2c io poart. */ +#define RMI4_MULTI_TOUCH 1 /* cwz: 1 for kernel new report mode */ + +#define RMI4_I2C_SPEED (400*1000) /* cwz: i2c io speed */ + +#define SYNA_WIDTH_DELTA (2) /* rmi4_acgzx: test empirical value */ + +#define SYNA_AIXS_REVISE_FORCE (0) +#if SYNA_AIXS_REVISE_FORCE +#define SYNA_AIXS_X_DELTA (0x40) //rmi4_acgzx: revise synaptics s7010 demo tp axis x for kindle +#define SYNA_WIDTH_DELTA_FOR_X_MAX (6) +#else +#define SYNA_AIXS_X_DELTA (0) +#define SYNA_WIDTH_DELTA_FOR_X_MAX (0) +#endif + +static struct i2c_client *syna_client; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void synaptics_rmi4_early_suspend(struct early_suspend *h); +static void synaptics_rmi4_late_resume(struct early_suspend *h); +#endif + +#if 1 +#define rmi4_debug(level, ...) \ + do { \ + printk(KERN_ERR __VA_ARGS__); \ + } while (0) +#else +#define rmi4_debug(level, ...) +#endif + +#if (RMI4_MULTI_TOUCH != 0) +enum synaptics_rmi4_touch_status { + SYNA_TOUCH_ORIGINAL = 0, + SYNA_TOUCH_PRESS, + SYNA_TOUCH_RELEASE +}; +#endif + +/** + * struct synaptics_rmi4_fn_desc - contains the function descriptor information + * @query_base_addr: base address for query + * @cmd_base_addr: base address for command + * @ctrl_base_addr: base address for control + * @data_base_addr: base address for data + * @intr_src_count: count for the interrupt source + * @fn_number: function number + * + * This structure is used to gives the function descriptor information + * of the particular functionality. + */ +struct synaptics_rmi4_fn_desc { + unsigned char query_base_addr; + unsigned char cmd_base_addr; + unsigned char ctrl_base_addr; + unsigned char data_base_addr; + unsigned char intr_src_count; + unsigned char fn_number; +}; + +/** + * struct synaptics_rmi4_fn - contains the function information + * @fn_number: function number + * @num_of_data_sources: number of data sources + * @num_of_data_points: number of fingers touched + * @size_of_data_register_block: data register block size + * @index_to_intr_reg: index for interrupt register + * @intr_mask: interrupt mask value + * @fn_desc: variable for function descriptor structure + * @link: linked list for function descriptors + * + * This structure gives information about the number of data sources and + * the number of data registers associated with the function. + */ +struct synaptics_rmi4_fn { + unsigned char fn_number; + unsigned char num_of_data_sources; + unsigned char num_of_data_points; + unsigned char size_of_data_register_block; + unsigned char index_to_intr_reg; + unsigned char intr_mask; + struct synaptics_rmi4_fn_desc fn_desc; + struct list_head link; +}; + +/** + * struct synaptics_rmi4_device_info - contains the rmi4 device information + * @version_major: protocol major version number + * @version_minor: protocol minor version number + * @manufacturer_id: manufacturer identification byte + * @product_props: product properties information + * @product_info: product info array + * @date_code: device manufacture date + * @tester_id: tester id array + * @serial_number: serial number for that device + * @product_id_string: product id for the device + * @support_fn_list: linked list for device information + * + * This structure gives information about the number of data sources and + * the number of data registers associated with the function. + */ +struct synaptics_rmi4_device_info { + unsigned int version_major; + unsigned int version_minor; + unsigned char manufacturer_id; + unsigned char product_props; + unsigned char product_info[2]; + unsigned char date_code[3]; + unsigned short tester_id; + unsigned short serial_number; + unsigned char product_id_string[11]; + struct list_head support_fn_list; +}; + +/** + * struct synaptics_rmi4_data - contains the rmi4 device data + * @rmi4_mod_info: structure variable for rmi4 device info + * @input_dev: pointer for input device + * @i2c_client: pointer for i2c client + * @board: constant pointer for touch platform data + * @fn_list_mutex: mutex for function list + * @rmi4_page_mutex: mutex for rmi4 page + * @current_page: variable for integer + * @number_of_interrupt_register: interrupt registers count + * @fn01_ctrl_base_addr: control base address for fn01 + * @fn01_query_base_addr: query base address for fn01 + * @fn01_data_base_addr: data base address for fn01 + * @sensor_max_x: sensor maximum x value + * @sensor_max_y: sensor maximum y value + * @regulator: pointer to the regulator structure + * @wait: wait queue structure variable + * @touch_stopped: flag to stop the thread function + * + * This structure gives the device data information. + */ +struct synaptics_rmi4_data { + struct synaptics_rmi4_device_info rmi4_mod_info; + struct input_dev *input_dev; + struct i2c_client *i2c_client; + const struct synaptics_rmi4_platform_data *board; + struct mutex fn_list_mutex; + struct mutex rmi4_page_mutex; + int current_page; + unsigned int number_of_interrupt_register; + unsigned short fn01_ctrl_base_addr; + unsigned short fn01_query_base_addr; + unsigned short fn01_data_base_addr; + int sensor_max_x; + int sensor_max_y; + struct regulator *regulator; + wait_queue_head_t wait; + bool touch_stopped; + + struct mutex rmi4_wq_mutex; + struct work_struct work; + struct workqueue_struct *rmi4_wq; + struct early_suspend m_early_suspend; +}; + +#if (SYNA_I2C_BUS_IO != 0) +static int synaptics_rmi4_read_block(struct i2c_client *client, + u16 addr, + u16 length, + u8 *value) +{ + struct i2c_adapter *adapter = client->adapter; + struct i2c_msg msg[2]; + __le16 le_addr; + int ret; + + le_addr = cpu_to_le16(addr); + + msg[0].scl_rate = RMI4_I2C_SPEED; + msg[0].addr = client->addr; + msg[0].flags = 0x00; + msg[0].len = 1; + msg[0].buf = (u8*) &le_addr; + + msg[1].scl_rate = RMI4_I2C_SPEED; + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = (u8*) value; + + ret = i2c_transfer(adapter, msg, 2); + + return (ret == 2)? length : ret; +} +#endif + +/** + * synaptics_rmi4_set_page() - sets the page + * @pdata: pointer to synaptics_rmi4_data structure + * @address: set the address of the page + * + * This function is used to set the page and returns integer. + */ +static int synaptics_rmi4_set_page(struct synaptics_rmi4_data *pdata, + unsigned int address) +{ + unsigned char txbuf[PAGE_LEN]; + int retval; + unsigned int page; + struct i2c_client *i2c = pdata->i2c_client; + + page = ((address >> 8) & MASK_8BIT); + if (page != pdata->current_page) { + txbuf[0] = MASK_8BIT; + txbuf[1] = page; + retval = i2c_master_send(i2c, txbuf, PAGE_LEN); + if (retval != PAGE_LEN) + dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval); + else + pdata->current_page = page; + } else + retval = PAGE_LEN; + return retval; +} +/** + * synaptics_rmi4_i2c_block_read() - read the block of data + * @pdata: pointer to synaptics_rmi4_data structure + * @address: read the block of data from this offset + * @valp: pointer to a buffer containing the data to be read + * @size: number of bytes to read + * + * This function is to read the block of data and returns integer. + */ +static int synaptics_rmi4_i2c_block_read(struct synaptics_rmi4_data *pdata, + unsigned short address, + unsigned char *valp, int size) +{ + int retval = 0; + int retry_count = 0; + int index; + struct i2c_client *i2c = pdata->i2c_client; + + mutex_lock(&(pdata->rmi4_page_mutex)); + retval = synaptics_rmi4_set_page(pdata, address); + if (retval != PAGE_LEN) + goto exit; + index = address & MASK_8BIT; +retry: +#if (SYNA_I2C_BUS_IO != 0) + retval = synaptics_rmi4_read_block(i2c, index, size, valp); +#else + retval = i2c_smbus_read_i2c_block_data(i2c, index, size, valp); +#endif + if (retval != size) { + if (++retry_count == MAX_RETRY_COUNT) + dev_err(&i2c->dev, + "%s:address 0x%04x size %d failed:%d\n", + __func__, address, size, retval); + else { + synaptics_rmi4_set_page(pdata, address); + goto retry; + } + } +exit: + mutex_unlock(&(pdata->rmi4_page_mutex)); + return retval; +} + +/** + * synaptics_rmi4_i2c_byte_write() - write the single byte data + * @pdata: pointer to synaptics_rmi4_data structure + * @address: write the block of data from this offset + * @data: data to be write + * + * This function is to write the single byte data and returns integer. + */ +static int synaptics_rmi4_i2c_byte_write(struct synaptics_rmi4_data *pdata, + unsigned short address, + unsigned char data) +{ + unsigned char txbuf[2]; + int retval = 0; + struct i2c_client *i2c = pdata->i2c_client; + + /* Can't have anyone else changing the page behind our backs */ + mutex_lock(&(pdata->rmi4_page_mutex)); + + retval = synaptics_rmi4_set_page(pdata, address); + if (retval != PAGE_LEN) + goto exit; + txbuf[0] = address & MASK_8BIT; + txbuf[1] = data; + retval = i2c_master_send(pdata->i2c_client, txbuf, 2); + /* Add in retry on writes only in certain error return values */ + if (retval != 2) { + dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval); + retval = -EIO; + } else + retval = 1; +exit: + mutex_unlock(&(pdata->rmi4_page_mutex)); + return retval; +} +//hhb@rock-chips.com +static int synaptics_rmi4_i2c_block_write(struct synaptics_rmi4_data *pdata, + unsigned short address, unsigned char *data, unsigned char size) +{ + unsigned char txbuf[8]; + int retval = 0; + struct i2c_client *i2c = pdata->i2c_client; + + /* Can't have anyone else changing the page behind our backs */ + mutex_lock(&(pdata->rmi4_page_mutex)); + + retval = synaptics_rmi4_set_page(pdata, address); + if (retval != PAGE_LEN) + goto exit; + txbuf[0] = address & MASK_8BIT; + memcpy(txbuf + 1, data, size); + retval = i2c_master_send(pdata->i2c_client, txbuf, size + 1); + /* Add in retry on writes only in certain error return values */ + if (retval != 2) { + dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval); + retval = -EIO; + } else + retval = 1; +exit: + mutex_unlock(&(pdata->rmi4_page_mutex)); + return retval; +} + + +/** + * synpatics_rmi4_touchpad_report() - reports for the rmi4 touchpad device + * @pdata: pointer to synaptics_rmi4_data structure + * @rfi: pointer to synaptics_rmi4_fn structure + * + * This function calls to reports for the rmi4 touchpad device + */ +static int synpatics_rmi4_touchpad_report(struct synaptics_rmi4_data *pdata, + struct synaptics_rmi4_fn *rfi) +{ + /* number of touch points - fingers down in this case */ + int touch_count = 0; + int finger; + int fingers_supported; + int finger_registers; + int reg; + int finger_shift; + int finger_status; + int retval; + unsigned short data_base_addr; + unsigned short data_offset; + unsigned char data_reg_blk_size; + unsigned char values[2]; + unsigned char data[DATA_LEN]; + int x[RMI4_NUMBER_OF_MAX_FINGERS]; + int y[RMI4_NUMBER_OF_MAX_FINGERS]; + int wx[RMI4_NUMBER_OF_MAX_FINGERS]; + int wy[RMI4_NUMBER_OF_MAX_FINGERS]; + struct i2c_client *client = pdata->i2c_client; + +#if (RMI4_MULTI_TOUCH != 0) + volatile enum synaptics_rmi4_touch_status cur_touch_status[SYNA_SUPPORT_POINT_MAX]; + static volatile enum synaptics_rmi4_touch_status pre_touch_status[SYNA_SUPPORT_POINT_MAX]; +#endif + + /* get 2D sensor finger data */ + /* + * First get the finger status field - the size of the finger status + * field is determined by the number of finger supporte - 2 bits per + * finger, so the number of registers to read is: + * registerCount = ceil(numberOfFingers/4). + * Read the required number of registers and check each 2 bit field to + * determine if a finger is down: + * 00 = finger not present, + * 01 = finger present and data accurate, + * 10 = finger present but data may not be accurate, + * 11 = reserved for product use. + */ + fingers_supported = rfi->num_of_data_points; + finger_registers = (fingers_supported + 3)/4; + data_base_addr = rfi->fn_desc.data_base_addr; + retval = synaptics_rmi4_i2c_block_read(pdata, data_base_addr, values, + finger_registers); + if (retval != finger_registers) { + dev_err(&client->dev, "%s:read status registers failed\n", + __func__); + return 0; + } + /* + * For each finger present, read the proper number of registers + * to get absolute data. + */ + data_reg_blk_size = rfi->size_of_data_register_block; + + for (finger = 0; finger < fingers_supported; finger++) { + //mutex_lock(&pdata->rmi4_wq_mutex); + cur_touch_status[finger] = SYNA_TOUCH_ORIGINAL; + //mutex_unlock(&pdata->rmi4_wq_mutex); + } + + for (finger = 0; finger < fingers_supported; finger++) { + /* determine which data byte the finger status is in */ + reg = finger/4; + /* bit shift to get finger's status */ + finger_shift = (finger % 4) * 2; + finger_status = (values[reg] >> finger_shift) & 3; + /* + * if finger status indicates a finger is present then + * read the finger data and report it + */ + if (finger_status == 1 || finger_status == 2) { + rmi4_debug(DEBUG_TRACE, "---> finger[%d] press ??\n", finger); + + //mutex_lock(&pdata->rmi4_wq_mutex); + cur_touch_status[finger] = SYNA_TOUCH_PRESS; + //mutex_unlock(&pdata->rmi4_wq_mutex); + + /* Read the finger data */ + data_offset = data_base_addr + + ((finger * data_reg_blk_size) + + finger_registers); + retval = synaptics_rmi4_i2c_block_read(pdata, + data_offset, data, data_reg_blk_size); + if (retval != data_reg_blk_size) { + printk(KERN_ERR "%s:read data failed\n", __func__); + //mutex_lock(&pdata->rmi4_wq_mutex); + cur_touch_status[finger] = SYNA_TOUCH_ORIGINAL; + //mutex_unlock(&pdata->rmi4_wq_mutex); + return 0; + } else { + x[finger] = + (data[0] << 4) | (data[2] & MASK_4BIT); + y[finger] = + (data[1] << 4) | + ((data[2] >> 4) & MASK_4BIT); + wy[finger] = + (data[3] >> 4) & MASK_4BIT; + wx[finger] = + (data[3] & MASK_4BIT); + + #if 0 + if (x[finger] >= pdata->sensor_max_x) + rmi4_debug(DEBUG_TRACE, "x[%d] = 0x%x, y[%d] = 0x%x\n" + "wx[%d] = 0x%x, wy[%d] = 0x%x\n" + "sensor_max_x = 0x%x, sensor_max_y = 0x%x\n", + finger, x[finger], finger, y[finger], + finger, wx[finger], finger, wy[finger], + pdata->sensor_max_x, pdata->sensor_max_y + ); + #endif + + #if SYNA_AIXS_REVISE_FORCE + { + int axis_bak; + + axis_bak = x[finger]; + + /*rmi4_acgzx: because these s7010 tp is assembling for a short time, sensor and lines isn't matching. + * force revise axis x and special handing. + */ + x[finger] -= SYNA_AIXS_X_DELTA; + x[finger] = (x[finger] < 0) ? 0 : x[finger]; + + //rmi4_acgzx: special handing for sensor_max_x. + if (axis_bak >= pdata->sensor_max_x && wx[finger] <= SYNA_WIDTH_DELTA_FOR_X_MAX) + x[finger] += SYNA_AIXS_X_DELTA; + } + #endif + + /* rmi4_acgzx: do not support touch key, ignore outside touch */ + if (x[finger] >= (pdata->sensor_max_x - SYNA_AIXS_X_DELTA) && wx[finger] <= SYNA_WIDTH_DELTA) { + //mutex_lock(&pdata->rmi4_wq_mutex); + cur_touch_status[finger] = SYNA_TOUCH_RELEASE; + //mutex_unlock(&pdata->rmi4_wq_mutex); + rmi4_debug(DEBUG_TRACE, "touch point beyond lcd display area.\n"); + } + + if (pdata->board->x_flip) + x[finger] = pdata->sensor_max_x - x[finger]; + if (pdata->board->y_flip) + y[finger] = pdata->sensor_max_y - y[finger]; + + } + /* rmi4_acgzx: touch press, touch_count increase */ + if (SYNA_TOUCH_PRESS == cur_touch_status[finger]) + touch_count++; + } + else { + //mutex_lock(&pdata->rmi4_wq_mutex); + cur_touch_status[finger] = SYNA_TOUCH_RELEASE; + //mutex_unlock(&pdata->rmi4_wq_mutex); + } + } + + for (finger = 0; finger < fingers_supported; finger++) { + if (SYNA_TOUCH_PRESS == cur_touch_status[finger]) { + rmi4_debug(DEBUG_TRACE, "====> finger[%d] press!\n", finger); + /* number of active touch points */ + input_mt_slot(pdata->input_dev, finger); + input_mt_report_slot_state(pdata->input_dev, MT_TOOL_FINGER, true); + input_report_abs(pdata->input_dev, ABS_MT_TRACKING_ID, finger); + input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR, MAX_TOUCH_MAJOR); + input_report_abs(pdata->input_dev, ABS_MT_POSITION_X, x[finger]); + input_report_abs(pdata->input_dev, ABS_MT_POSITION_Y, y[finger]); + //mutex_lock(&pdata->rmi4_wq_mutex); + pre_touch_status[finger] = cur_touch_status[finger]; + //mutex_unlock(&pdata->rmi4_wq_mutex); + } + } + + for (finger = 0; finger < fingers_supported; finger++) { + if (SYNA_TOUCH_RELEASE == cur_touch_status[finger] && + SYNA_TOUCH_PRESS == pre_touch_status[finger]) { + rmi4_debug(DEBUG_TRACE, "====> finger[%d] release!\n", finger); + /* number of active touch points */ + input_mt_slot(pdata->input_dev, finger); + input_mt_report_slot_state(pdata->input_dev, MT_TOOL_FINGER, false); + input_report_abs(pdata->input_dev, ABS_MT_TRACKING_ID, -1); + //mutex_lock(&pdata->rmi4_wq_mutex); + pre_touch_status[finger] = cur_touch_status[finger]; + //mutex_unlock(&pdata->rmi4_wq_mutex); + } + } + + /* sync after groups of events */ + input_sync(pdata->input_dev); + /* return the number of touch points */ + return touch_count; +} + +/** + * synaptics_rmi4_report_device() - reports the rmi4 device + * @pdata: pointer to synaptics_rmi4_data structure + * @rfi: pointer to synaptics_rmi4_fn + * + * This function is used to call the report function of the rmi4 device. + */ +static int synaptics_rmi4_report_device(struct synaptics_rmi4_data *pdata, + struct synaptics_rmi4_fn *rfi) +{ + int touch = 0; + struct i2c_client *client = pdata->i2c_client; + static int num_error_reports; + if (rfi->fn_number != SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM) { + rmi4_debug(DEBUG_TRACE, "====> %s fn_number no equal enter!\n", __func__); + num_error_reports++; + if (num_error_reports < MAX_ERROR_REPORT) + dev_err(&client->dev, "%s:report not supported\n", + __func__); + } else + touch = synpatics_rmi4_touchpad_report(pdata, rfi); + return touch; +} +/** + * synaptics_rmi4_sensor_report() - reports to input subsystem + * @pdata: pointer to synaptics_rmi4_data structure + * + * This function is used to reads in all data sources and reports + * them to the input subsystem. + */ +static int synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *pdata) +{ + unsigned char intr_status[4]; + /* number of touch points - fingers or buttons */ + int touch = 0; + unsigned int retval; + struct synaptics_rmi4_fn *rfi; + struct synaptics_rmi4_device_info *rmi; + struct i2c_client *client = pdata->i2c_client; + + /* + * Get the interrupt status from the function $01 + * control register+1 to find which source(s) were interrupting + * so we can read the data from the source(s) (2D sensor, buttons..) + */ + retval = synaptics_rmi4_i2c_block_read(pdata, + pdata->fn01_data_base_addr + 1, + intr_status, + pdata->number_of_interrupt_register); + if (retval != pdata->number_of_interrupt_register) { + dev_err(&client->dev, + "could not read interrupt status registers\n"); + return 0; + } + /* + * check each function that has data sources and if the interrupt for + * that triggered then call that RMI4 functions report() function to + * gather data and report it to the input subsystem + */ + rmi = &(pdata->rmi4_mod_info); + list_for_each_entry(rfi, &rmi->support_fn_list, link) { + if (rfi->num_of_data_sources) { + if (intr_status[rfi->index_to_intr_reg] & + rfi->intr_mask) + touch = synaptics_rmi4_report_device(pdata, + rfi); + } + } + /* return the number of touch points */ + return touch; +} + +static void synaptics_rmi4_work_func(struct work_struct *work) +{ + struct synaptics_rmi4_data *rmi4_data = container_of(work, struct synaptics_rmi4_data, work); + struct i2c_client *client = rmi4_data->i2c_client; + unsigned char intr_status; + + /* rmi4_acgzx note: important!! disable tp interrupt avoid lost attn */ + synaptics_rmi4_i2c_byte_write(rmi4_data, rmi4_data->fn01_data_base_addr + 1, 0x00); + + synaptics_rmi4_sensor_report(rmi4_data); + + enable_irq(client->irq); + + /* rmi4_acgzx note: important!! enable tp interrupt again*/ + synaptics_rmi4_i2c_byte_write(rmi4_data, rmi4_data->fn01_data_base_addr + 1, 0x0f); + + /* rmi4_acgzx note: may be cause lose attn, gpio irq is low, that is small probability in rk30 platform. + * need read int status register again just in case. + */ + if (0 == gpio_get_value(client->irq)) { + rmi4_debug(DEBUG_TRACE, "----> %s: irq change low value enter! <----\n", __func__); + synaptics_rmi4_i2c_block_read(rmi4_data, + rmi4_data->fn01_data_base_addr + 1, + &intr_status, + rmi4_data->number_of_interrupt_register); + + } + + //rmi4_debug(DEBUG_TRACE, "%s: exit!\n", __func__); //rmi4_acgzx +} + +/** + * synaptics_rmi4_irq() - thread function for rmi4 attention line + * @irq: irq value + * @data: void pointer + * + * This function is interrupt thread function. It just notifies the + * application layer that attention is required. + */ +static irqreturn_t synaptics_rmi4_irq(int irq, void *data) +{ + struct synaptics_rmi4_data *pdata = data; + + //rmi4_debug(DEBUG_TRACE, "%s: enter!\n", __func__); //rmi4_acgzx + + disable_irq_nosync(irq); + queue_work(pdata->rmi4_wq, &pdata->work); + + return IRQ_HANDLED; +} + +/** + * synpatics_rmi4_touchpad_detect() - detects the rmi4 touchpad device + * @pdata: pointer to synaptics_rmi4_data structure + * @rfi: pointer to synaptics_rmi4_fn structure + * @fd: pointer to synaptics_rmi4_fn_desc structure + * @interruptcount: count the number of interrupts + * + * This function calls to detects the rmi4 touchpad device + */ +static int synpatics_rmi4_touchpad_detect(struct synaptics_rmi4_data *pdata, + struct synaptics_rmi4_fn *rfi, + struct synaptics_rmi4_fn_desc *fd, + unsigned int interruptcount) +{ + unsigned char queries[QUERY_LEN]; + unsigned short intr_offset; + unsigned char abs_data_size; + unsigned char abs_data_blk_size; + unsigned char egr_0, egr_1; + unsigned int all_data_blk_size; + int has_pinch, has_flick, has_tap; + int has_tapandhold, has_doubletap; + int has_earlytap, has_press; + int has_palmdetect, has_rotate; + int has_rel; + int i; + int retval; + struct i2c_client *client = pdata->i2c_client; + + rfi->fn_desc.query_base_addr = fd->query_base_addr; + rfi->fn_desc.data_base_addr = fd->data_base_addr; + rfi->fn_desc.intr_src_count = fd->intr_src_count; + rfi->fn_desc.fn_number = fd->fn_number; + rfi->fn_number = fd->fn_number; + rfi->num_of_data_sources = fd->intr_src_count; + rfi->fn_desc.ctrl_base_addr = fd->ctrl_base_addr; + rfi->fn_desc.cmd_base_addr = fd->cmd_base_addr; + + /* + * need to get number of fingers supported, data size, etc. + * to be used when getting data since the number of registers to + * read depends on the number of fingers supported and data size. + */ + retval = synaptics_rmi4_i2c_block_read(pdata, fd->query_base_addr, + queries, + sizeof(queries)); + if (retval != sizeof(queries)) { + dev_err(&client->dev, "%s:read function query registers\n", + __func__); + return retval; + } + /* + * 2D data sources have only 3 bits for the number of fingers + * supported - so the encoding is a bit weird. + */ + if ((queries[1] & MASK_3BIT) <= 4) + /* add 1 since zero based */ + rfi->num_of_data_points = (queries[1] & MASK_3BIT) + 1; + else { + /* + * a value of 5 is up to 10 fingers - 6 and 7 are reserved + * (shouldn't get these i int retval;n a normal 2D source). + */ + if ((queries[1] & MASK_3BIT) == 5) + rfi->num_of_data_points = 10; + } + /* Need to get interrupt info for handling interrupts */ + rfi->index_to_intr_reg = (interruptcount + 7)/8; + if (rfi->index_to_intr_reg != 0) + rfi->index_to_intr_reg -= 1; + /* + * loop through interrupts for each source in fn $11 + * and or in a bit to the interrupt mask for each. + */ + intr_offset = interruptcount % 8; + rfi->intr_mask = 0; + for (i = intr_offset; + i < ((fd->intr_src_count & MASK_3BIT) + intr_offset); i++) + rfi->intr_mask |= 1 << i; + + /* Size of just the absolute data for one finger */ + abs_data_size = queries[5] & MASK_2BIT; + /* One each for X and Y, one for LSB for X & Y, one for W, one for Z */ + abs_data_blk_size = 3 + (2 * (abs_data_size == 0 ? 1 : 0)); + rfi->size_of_data_register_block = abs_data_blk_size; + + /* + * need to determine the size of data to read - this depends on + * conditions such as whether Relative data is reported and if Gesture + * data is reported. + */ + egr_0 = queries[7]; + egr_1 = queries[8]; + + /* + * Get info about what EGR data is supported, whether it has + * Relative data supported, etc. + */ + has_pinch = egr_0 & HAS_PINCH; + has_flick = egr_0 & HAS_FLICK; + has_tap = egr_0 & HAS_TAP; + has_earlytap = egr_0 & HAS_EARLYTAP; + has_press = egr_0 & HAS_PRESS; + has_rotate = egr_1 & HAS_ROTATE; + has_rel = queries[1] & HAS_RELEASE; + has_tapandhold = egr_0 & HAS_TAPANDHOLD; + has_doubletap = egr_0 & HAS_DOUBLETAP; + has_palmdetect = egr_1 & HAS_PALMDETECT; + + /* + * Size of all data including finger status, absolute data for each + * finger, relative data and EGR data + */ + all_data_blk_size = + /* finger status, four fingers per register */ + ((rfi->num_of_data_points + 3) / 4) + + /* absolute data, per finger times number of fingers */ + (abs_data_blk_size * rfi->num_of_data_points) + + /* + * two relative registers (if relative is being reported) + */ + 2 * has_rel + + /* + * F11_2D_data8 is only present if the egr_0 + * register is non-zero. + */ + !!(egr_0) + + /* + * F11_2D_data9 is only present if either egr_0 or + * egr_1 registers are non-zero. + */ + (egr_0 || egr_1) + + /* + * F11_2D_data10 is only present if EGR_PINCH or EGR_FLICK of + * egr_0 reports as 1. + */ + !!(has_pinch | has_flick) + + /* + * F11_2D_data11 and F11_2D_data12 are only present if + * EGR_FLICK of egr_0 reports as 1. + */ + 2 * !!(has_flick); + return retval; +} + +/** + * synpatics_rmi4_touchpad_config() - confiures the rmi4 touchpad device + * @pdata: pointer to synaptics_rmi4_data structure + * @rfi: pointer to synaptics_rmi4_fn structure + * + * This function calls to confiures the rmi4 touchpad device + */ +int synpatics_rmi4_touchpad_config(struct synaptics_rmi4_data *pdata, + struct synaptics_rmi4_fn *rfi) +{ + /* + * For the data source - print info and do any + * source specific configuration. + */ + unsigned char data[BUF_LEN]; + int retval = 0; + struct i2c_client *client = pdata->i2c_client; + + /* Get and print some info about the data source... */ + /* To Query 2D devices we need to read from the address obtained + * from the function descriptor stored in the RMI function info. + */ + retval = synaptics_rmi4_i2c_block_read(pdata, + rfi->fn_desc.query_base_addr, + data, QUERY_LEN); + if (retval != QUERY_LEN) + dev_err(&client->dev, "%s:read query registers failed\n", + __func__); + else { + + //hhb@rock-chips.com add virtual_keys function + if (pdata->board->virtual_keys == true) { + + int w, h; + char buf[2]; + + pdata->sensor_max_x = pdata->board->lcd_width; + pdata->sensor_max_y = pdata->board->lcd_height; + + w = pdata->board->lcd_width + pdata->board->w_delta; + h = pdata->board->lcd_height + pdata->board->h_delta; + +#if 0 + buf[0] = w & MASK_8BIT; + buf[1] = (w >> 8) & MASK_4BIT; + synaptics_rmi4_i2c_block_write(pdata, rfi->fn_desc.ctrl_base_addr + 6, buf, 2); + buf[0] = h & MASK_8BIT; + buf[1] = (h >> 8) & MASK_4BIT; + synaptics_rmi4_i2c_block_write(pdata, rfi->fn_desc.ctrl_base_addr + 8, buf, 2); +#else + synaptics_rmi4_i2c_byte_write(pdata, rfi->fn_desc.ctrl_base_addr + 6, w & MASK_8BIT); + synaptics_rmi4_i2c_byte_write(pdata, rfi->fn_desc.ctrl_base_addr + 7, (w >> 8) & MASK_4BIT); + + synaptics_rmi4_i2c_byte_write(pdata, rfi->fn_desc.ctrl_base_addr + 8, h & MASK_8BIT); + synaptics_rmi4_i2c_byte_write(pdata, rfi->fn_desc.ctrl_base_addr + 9, (h >> 8) & MASK_4BIT); +#endif + + retval = synaptics_rmi4_i2c_block_read(pdata, + rfi->fn_desc.ctrl_base_addr, + data, DATA_BUF_LEN); + if (retval != DATA_BUF_LEN) { + dev_err(&client->dev, + "%s:read control registers failed\n", + __func__); + return retval; + } + + w = ((data[6] & MASK_8BIT) << 0) | + ((data[7] & MASK_4BIT) << 8); + h = ((data[8] & MASK_8BIT) << 0) | + ((data[9] & MASK_4BIT) << 8); + + if(pdata->board->lcd_width != w || pdata->board->lcd_height != h){ + printk("set tp x:%d, y:%d, but read x:%d, y:%d\n", pdata->board->lcd_width, pdata->board->lcd_height, w, h); + } + + } else { + + retval = synaptics_rmi4_i2c_block_read(pdata, + rfi->fn_desc.ctrl_base_addr, + data, DATA_BUF_LEN); + if (retval != DATA_BUF_LEN) { + dev_err(&client->dev, + "%s:read control registers failed\n", + __func__); + return retval; + } + + /* Store these for use later*/ + + pdata->sensor_max_x = ((data[6] & MASK_8BIT) << 0) | + ((data[7] & MASK_4BIT) << 8); + pdata->sensor_max_y = ((data[8] & MASK_8BIT) << 0) | + ((data[9] & MASK_4BIT) << 8); + } + + rmi4_debug(DEBUG_TRACE, "sensor_max_x = 0x%x, sensor_max_y = 0x%x.\n", + pdata->sensor_max_x, pdata->sensor_max_y); + } + return retval; +} + +/** + * synaptics_rmi4_i2c_query_device() - query the rmi4 device + * @pdata: pointer to synaptics_rmi4_data structure + * + * This function is used to query the rmi4 device. + */ +static int synaptics_rmi4_i2c_query_device(struct synaptics_rmi4_data *pdata) +{ + int i; + int retval; + unsigned char std_queries[STD_QUERY_LEN]; + unsigned char intr_count = 0; + int data_sources = 0; + unsigned int ctrl_offset; + struct synaptics_rmi4_fn *rfi; + struct synaptics_rmi4_fn_desc rmi_fd; + struct synaptics_rmi4_device_info *rmi; + struct i2c_client *client = pdata->i2c_client; + + /* + * init the physical drivers RMI module + * info list of functions + */ + INIT_LIST_HEAD(&pdata->rmi4_mod_info.support_fn_list); + + /* + * Read the Page Descriptor Table to determine what functions + * are present + */ + for (i = PDT_START_SCAN_LOCATION; i > PDT_END_SCAN_LOCATION; + i -= PDT_ENTRY_SIZE) { + retval = synaptics_rmi4_i2c_block_read(pdata, i, + (unsigned char *)&rmi_fd, + sizeof(rmi_fd)); + if (retval != sizeof(rmi_fd)) { + /* failed to read next PDT entry */ + dev_err(&client->dev, "%s: read error\n", __func__); + return -EIO; + } + + rmi4_debug(DEBUG_TRACE, "----> query_base_addr = 0x%x\n" + "cmd_base_addr = 0x%x\n" + "ctrl_base_addr = 0x%x\n" + "data_base_addr = 0x%x\n" + "intr_src_count = 0x%x\n" + "fn_number = 0x%x\n", + rmi_fd.query_base_addr, + rmi_fd.cmd_base_addr, + rmi_fd.ctrl_base_addr, + rmi_fd.data_base_addr, + rmi_fd.intr_src_count, + rmi_fd.fn_number + ); + + rfi = NULL; + if (rmi_fd.fn_number) { + switch (rmi_fd.fn_number & MASK_8BIT) { + case SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM: + pdata->fn01_query_base_addr = + rmi_fd.query_base_addr; + pdata->fn01_ctrl_base_addr = + rmi_fd.ctrl_base_addr; + pdata->fn01_data_base_addr = + rmi_fd.data_base_addr; + + rmi4_debug(DEBUG_TRACE, "----> fn01_query_base_addr = 0x%x\n," + "fn01_ctrl_base_addr = 0x%x\n," + "fn01_data_base_addr = 0x%x\n,", + pdata->fn01_query_base_addr, + pdata->fn01_ctrl_base_addr, + pdata->fn01_data_base_addr + ); + break; + case SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM: + if (rmi_fd.intr_src_count) { + rfi = kmalloc(sizeof(*rfi), + GFP_KERNEL); + if (!rfi) { + dev_err(&client->dev, + "%s:kmalloc failed\n", + __func__); + return -ENOMEM; + } + retval = synpatics_rmi4_touchpad_detect + (pdata, rfi, + &rmi_fd, + intr_count); + if (retval < 0) { + kfree(rfi); + return retval; + } + } + break; + } + /* interrupt count for next iteration */ + intr_count += (rmi_fd.intr_src_count & MASK_3BIT); + /* + * We only want to add functions to the list + * that have data associated with them. + */ + if (rfi && rmi_fd.intr_src_count) { + /* link this function info to the RMI module */ + mutex_lock(&(pdata->fn_list_mutex)); + list_add_tail(&rfi->link, + &pdata->rmi4_mod_info.support_fn_list); + mutex_unlock(&(pdata->fn_list_mutex)); + } + } else { + /* + * A zero in the function number + * signals the end of the PDT + */ + dev_dbg(&client->dev, + "%s:end of PDT\n", __func__); + break; + } + } + /* + * calculate the interrupt register count - used in the + * ISR to read the correct number of interrupt registers + */ + pdata->number_of_interrupt_register = (intr_count + 7) / 8; + /* + * Function $01 will be used to query the product properties, + * and product ID so we had to read the PDT above first to get + * the Fn $01 query address and prior to filling in the product + * info. NOTE: Even an unflashed device will still have FN $01. + */ + + /* Load up the standard queries and get the RMI4 module info */ + retval = synaptics_rmi4_i2c_block_read(pdata, + pdata->fn01_query_base_addr, + std_queries, + sizeof(std_queries)); + if (retval != sizeof(std_queries)) { + dev_err(&client->dev, "%s:Failed reading queries\n", + __func__); + return -EIO; + } + + /* Currently supported RMI version is 4.0 */ + pdata->rmi4_mod_info.version_major = 4; + pdata->rmi4_mod_info.version_minor = 0; + /* + * get manufacturer id, product_props, product info, + * date code, tester id, serial num and product id (name) + */ + pdata->rmi4_mod_info.manufacturer_id = std_queries[0]; + pdata->rmi4_mod_info.product_props = std_queries[1]; + pdata->rmi4_mod_info.product_info[0] = std_queries[2]; + pdata->rmi4_mod_info.product_info[1] = std_queries[3]; + /* year - 2001-2032 */ + pdata->rmi4_mod_info.date_code[0] = std_queries[4] & MASK_5BIT; + /* month - 1-12 */ + pdata->rmi4_mod_info.date_code[1] = std_queries[5] & MASK_4BIT; + /* day - 1-31 */ + pdata->rmi4_mod_info.date_code[2] = std_queries[6] & MASK_5BIT; + pdata->rmi4_mod_info.tester_id = ((std_queries[7] & MASK_7BIT) << 8) | + (std_queries[8] & MASK_7BIT); + pdata->rmi4_mod_info.serial_number = + ((std_queries[9] & MASK_7BIT) << 8) | + (std_queries[10] & MASK_7BIT); + memcpy(pdata->rmi4_mod_info.product_id_string, &std_queries[11], 10); + + rmi4_debug(DEBUG_TRACE, "version_major = 0x%x, version_minor = 0x%x.\n" + "manufacturer_id = 0x%x, product_props = 0x%x.\n" + "product_info[1] = 0x%x, product_info[0] = 0x%x.\n" + "date_code[2] = 0x%x, date_code[1] = 0x%x, date_code[0] = 0x%x.\n" + "tester_id = 0x%x, serial_number = 0x%x.\n" + "product_id_string = %s.\n", + pdata->rmi4_mod_info.version_major, pdata->rmi4_mod_info.version_minor, + pdata->rmi4_mod_info.manufacturer_id, pdata->rmi4_mod_info.product_props, + pdata->rmi4_mod_info.product_info[1], pdata->rmi4_mod_info.product_info[0], + pdata->rmi4_mod_info.date_code[2], pdata->rmi4_mod_info.date_code[1], pdata->rmi4_mod_info.date_code[0], + pdata->rmi4_mod_info.tester_id, pdata->rmi4_mod_info.serial_number, + pdata->rmi4_mod_info.product_id_string + ); + + /* Check if this is a Synaptics device - report if not. */ + if (pdata->rmi4_mod_info.manufacturer_id != 1) + dev_err(&client->dev, "%s: non-Synaptics mfg id:%d\n", + __func__, pdata->rmi4_mod_info.manufacturer_id); + + list_for_each_entry(rfi, &pdata->rmi4_mod_info.support_fn_list, link) + data_sources += rfi->num_of_data_sources; + if (data_sources) { + rmi = &(pdata->rmi4_mod_info); + list_for_each_entry(rfi, &rmi->support_fn_list, link) { + if (rfi->num_of_data_sources) { + if (rfi->fn_number == + SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM) { + retval = synpatics_rmi4_touchpad_config + (pdata, rfi); + if (retval < 0) + return retval; + } else + dev_err(&client->dev, + "%s:fn_number not supported\n", + __func__); + /* + * Turn on interrupts for this + * function's data sources. + */ + ctrl_offset = pdata->fn01_ctrl_base_addr + 1 + + rfi->index_to_intr_reg; + + rmi4_debug(DEBUG_TRACE, "----> fn01_ctrl_base_addr = 0x%x, intr_mask = 0x%x\n" + "index_to_intr_reg = 0x%x, ctrl_offset = 0x%x.\n", + pdata->fn01_ctrl_base_addr, rfi->intr_mask, + rfi->index_to_intr_reg, ctrl_offset + ); + + retval = synaptics_rmi4_i2c_byte_write(pdata, + ctrl_offset, + rfi->intr_mask); + if (retval < 0) + return retval; + } + } + } + return 0; +} + + +/** + * synaptics_rmi4_probe() - Initialze the i2c-client touchscreen driver + * @i2c: i2c client structure pointer + * @id:i2c device id pointer + * + * This function will allocate and initialize the instance + * data and request the irq and set the instance data as the clients + * platform data then register the physical driver which will do a scan of + * the rmi4 Physical Device Table and enumerate any rmi4 functions that + * have data sources associated with them. + */ +static int __devinit synaptics_rmi4_probe + (struct i2c_client *client, const struct i2c_device_id *dev_id) +{ + int retval; + unsigned char intr_status[4]; + struct synaptics_rmi4_data *rmi4_data; + struct synaptics_rmi4_platform_data *platformdata = + client->dev.platform_data; + +#if (SYNA_I2C_BUS_IO != 0) + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c smbus byte data not supported\n"); + return -EIO; + } +#else + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "i2c smbus byte data not supported\n"); + return -EIO; + } +#endif + + if (!platformdata) { + dev_err(&client->dev, "%s: no platform data\n", __func__); + return -EINVAL; + } + + //if (platformdata->init_hw) + // platformdata->init_hw(); + + platformdata->irq_number = gpio_to_irq(client->irq); + //platformdata->x_flip = false; // hhb + //platformdata->y_flip = false; + //platformdata->irq_type = IRQF_TRIGGER_FALLING; + //platformdata->regulator_en = false; + + rmi4_debug(DEBUG_TRACE, "irq_number = %d, client->irq = %d\n", + platformdata->irq_number, client->irq); + + /* Allocate and initialize the instance data for this client */ + rmi4_data = kzalloc(sizeof(struct synaptics_rmi4_data) * 2, + GFP_KERNEL); + if (!rmi4_data) { + dev_err(&client->dev, "%s: no memory allocated\n", __func__); + return -ENOMEM; + } + + rmi4_data->input_dev = input_allocate_device(); + if (rmi4_data->input_dev == NULL) { + dev_err(&client->dev, "%s:input device alloc failed\n", + __func__); + retval = -ENOMEM; + goto err_input; + } + + if (platformdata->regulator_en) { + rmi4_data->regulator = regulator_get(&client->dev, "vdd"); + if (IS_ERR(rmi4_data->regulator)) { + dev_err(&client->dev, "%s:get regulator failed\n", + __func__); + retval = PTR_ERR(rmi4_data->regulator); + goto err_regulator; + } + regulator_enable(rmi4_data->regulator); + } + + init_waitqueue_head(&rmi4_data->wait); + /* + * Copy i2c_client pointer into RTID's i2c_client pointer for + * later use in rmi4_read, rmi4_write, etc. + */ + rmi4_data->i2c_client = client; + /* So we set the page correctly the first time */ + rmi4_data->current_page = MASK_16BIT; + rmi4_data->board = platformdata; + rmi4_data->touch_stopped = false; + + /* init the mutexes for maintain the lists */ + mutex_init(&(rmi4_data->fn_list_mutex)); + mutex_init(&(rmi4_data->rmi4_page_mutex)); + + mutex_init(&(rmi4_data->rmi4_wq_mutex)); + + /* + * Register physical driver - this will call the detect function that + * will then scan the device and determine the supported + * rmi4 functions. + */ + retval = synaptics_rmi4_i2c_query_device(rmi4_data); + if (retval) { + dev_err(&client->dev, "%s: rmi4 query device failed\n", + __func__); + goto err_query_dev; + } + + /* Store the instance data in the i2c_client */ + i2c_set_clientdata(client, rmi4_data); + + /*initialize the input device parameters */ + rmi4_data->input_dev->name = DRIVER_NAME; + rmi4_data->input_dev->phys = "Synaptics_Clearpad"; + rmi4_data->input_dev->id.bustype = BUS_I2C; + rmi4_data->input_dev->dev.parent = &client->dev; + input_set_drvdata(rmi4_data->input_dev, rmi4_data); + + /* Initialize the function handlers for rmi4 */ + + __set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit); + __set_bit(EV_ABS, rmi4_data->input_dev->evbit); + + input_mt_init_slots(rmi4_data->input_dev, SYNA_SUPPORT_POINT_MAX); + + input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_X, 0, + rmi4_data->sensor_max_x, 0, 0); + input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_Y, 0, + rmi4_data->sensor_max_y, 0, 0); + input_set_abs_params(rmi4_data->input_dev, ABS_MT_TOUCH_MAJOR, 0, + MAX_TOUCH_MAJOR, 0, 0); + + /* Clear interrupts */ + synaptics_rmi4_i2c_block_read(rmi4_data, + rmi4_data->fn01_data_base_addr + 1, intr_status, + rmi4_data->number_of_interrupt_register); + + rmi4_debug(DEBUG_TRACE, "intr_status: %d %d %d %d, number_of_interrupt_register = %d\n", + intr_status[0], intr_status[1], intr_status[2], intr_status[3], + rmi4_data->number_of_interrupt_register); + + rmi4_data->rmi4_wq = create_workqueue("rmi4_wq"); + rmi4_debug(DEBUG_TRACE, "----> create_workqueue start!\n"); + + INIT_WORK(&rmi4_data->work, synaptics_rmi4_work_func); + + retval = request_threaded_irq(platformdata->irq_number, NULL, + synaptics_rmi4_irq, + platformdata->irq_type, + DRIVER_NAME, rmi4_data); + if (retval) { + dev_err(&client->dev, "%s:Unable to get attn irq %d\n", + __func__, platformdata->irq_number); + goto err_query_dev; + } + + retval = input_register_device(rmi4_data->input_dev); + if (retval) { + dev_err(&client->dev, "%s:input register failed\n", __func__); + goto err_free_irq; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + syna_client = client; + + rmi4_data->m_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1; + rmi4_data->m_early_suspend.suspend = synaptics_rmi4_early_suspend; + rmi4_data->m_early_suspend.resume = synaptics_rmi4_late_resume; + register_early_suspend(&rmi4_data->m_early_suspend); +#else + rmi4_data->m_early_suspend.level = -1; + rmi4_data->m_early_suspend.suspend = NULL; + rmi4_data->m_early_suspend.resume = NULL; +#endif + + return retval; + +err_free_irq: + free_irq(platformdata->irq_number, rmi4_data); +err_query_dev: + if (platformdata->regulator_en) { + regulator_disable(rmi4_data->regulator); + regulator_put(rmi4_data->regulator); + } +err_regulator: + input_free_device(rmi4_data->input_dev); + rmi4_data->input_dev = NULL; +err_input: + kfree(rmi4_data); + + return retval; +} +/** + * synaptics_rmi4_remove() - Removes the i2c-client touchscreen driver + * @client: i2c client structure pointer + * + * This function uses to remove the i2c-client + * touchscreen driver and returns integer. + */ +static int __devexit synaptics_rmi4_remove(struct i2c_client *client) +{ + struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client); + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + +#ifdef CONFIG_HAS_EARLYSUSPEND + if (rmi4_data->m_early_suspend.suspend && rmi4_data->m_early_suspend.resume) + unregister_early_suspend(&rmi4_data->m_early_suspend); +#endif + + rmi4_data->touch_stopped = true; + wake_up(&rmi4_data->wait); + free_irq(pdata->irq_number, rmi4_data); + input_unregister_device(rmi4_data->input_dev); + if (pdata->regulator_en) { + regulator_disable(rmi4_data->regulator); + regulator_put(rmi4_data->regulator); + } + kfree(rmi4_data); + + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void synaptics_rmi4_early_suspend(struct early_suspend *h) +{ + struct i2c_client *client = syna_client; + struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client); + + rmi4_debug(DEBUG_TRACE, "%s: enter!\n", __func__); //rmi4_acgzx + + disable_irq(client->irq); + synaptics_rmi4_i2c_byte_write(rmi4_data, rmi4_data->fn01_data_base_addr + 1, 0x00); + +} +static void synaptics_rmi4_late_resume(struct early_suspend *h) +{ + struct i2c_client *client = syna_client; + struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client); + int retval; + unsigned char intr_status; + + rmi4_debug(DEBUG_TRACE, "%s: enter!\n", __func__); //rmi4_acgzx + + enable_irq(client->irq); + + retval = synaptics_rmi4_i2c_block_read(rmi4_data, + rmi4_data->fn01_data_base_addr + 1, + &intr_status, + rmi4_data->number_of_interrupt_register); + if (retval < 0) + return; + + synaptics_rmi4_i2c_byte_write(rmi4_data, rmi4_data->fn01_data_base_addr + 1, 0x0f); + +} +#endif + +#ifdef CONFIG_PM +/** + * synaptics_rmi4_suspend() - suspend the touch screen controller + * @dev: pointer to device structure + * + * This function is used to suspend the + * touch panel controller and returns integer + */ +static int synaptics_rmi4_suspend(struct device *dev) +{ + /* Touch sleep mode */ + int retval; + unsigned char intr_status; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + rmi4_debug(DEBUG_TRACE, "%s: enter!\n", __func__); //rmi4_acgzx + + rmi4_data->touch_stopped = true; + disable_irq(pdata->irq_number); + + retval = synaptics_rmi4_i2c_block_read(rmi4_data, + rmi4_data->fn01_data_base_addr + 1, + &intr_status, + rmi4_data->number_of_interrupt_register); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_i2c_byte_write(rmi4_data, + rmi4_data->fn01_ctrl_base_addr + 1, + (intr_status & ~TOUCHPAD_CTRL_INTR)); + if (retval < 0) + return retval; + + if (pdata->regulator_en) + regulator_disable(rmi4_data->regulator); + + return 0; +} +/** + * synaptics_rmi4_resume() - resume the touch screen controller + * @dev: pointer to device structure + * + * This function is used to resume the touch panel + * controller and returns integer. + */ +static int synaptics_rmi4_resume(struct device *dev) +{ + int retval; + unsigned char intr_status; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + rmi4_debug(DEBUG_TRACE, "%s: enter!\n", __func__); //rmi4_acgzx + + if (pdata->regulator_en) + regulator_enable(rmi4_data->regulator); + + enable_irq(pdata->irq_number); + rmi4_data->touch_stopped = false; + + retval = synaptics_rmi4_i2c_block_read(rmi4_data, + rmi4_data->fn01_data_base_addr + 1, + &intr_status, + rmi4_data->number_of_interrupt_register); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_i2c_byte_write(rmi4_data, + rmi4_data->fn01_ctrl_base_addr + 1, + (intr_status | TOUCHPAD_CTRL_INTR)); + if (retval < 0) + return retval; + + return 0; +} + +static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = { + .suspend = synaptics_rmi4_suspend, + .resume = synaptics_rmi4_resume, +}; +#endif + +static const struct i2c_device_id synaptics_rmi4_id_table[] = { + { DRIVER_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table); + +static struct i2c_driver synaptics_rmi4_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, +#if (0 == CONFIG_HAS_EARLYSUSPEND) //rmi4_acgzx +#ifdef CONFIG_PM + .pm = &synaptics_rmi4_dev_pm_ops, +#endif +#endif + }, + .probe = synaptics_rmi4_probe, + .remove = __devexit_p(synaptics_rmi4_remove), + .id_table = synaptics_rmi4_id_table, +}; +/** + * synaptics_rmi4_init() - Initialize the touchscreen driver + * + * This function uses to initializes the synaptics + * touchscreen driver and returns integer. + */ +static int __init synaptics_rmi4_init(void) +{ + return i2c_add_driver(&synaptics_rmi4_driver); +} +/** + * synaptics_rmi4_exit() - De-initialize the touchscreen driver + * + * This function uses to de-initialize the synaptics + * touchscreen driver and returns none. + */ +static void __exit synaptics_rmi4_exit(void) +{ + i2c_del_driver(&synaptics_rmi4_driver); +} + + +module_init(synaptics_rmi4_init); +module_exit(synaptics_rmi4_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("naveen.gaddipati@stericsson.com, js.ha@stericsson.com"); +MODULE_DESCRIPTION("synaptics rmi4 i2c touch Driver"); +MODULE_ALIAS("i2c:synaptics_rmi4_ts"); + + + + diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h new file mode 100644 index 000000000000..bb53d31f6930 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h @@ -0,0 +1,379 @@ +/** + * + * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver. + * Copyright (c) 2007-2010, Synaptics Incorporated + * + * Author: Js HA for ST-Ericsson + * Author: Naveen Kumar G for ST-Ericsson + * Copyright 2010 (c) ST-Ericsson AB + */ +/* + * This file is licensed under the GPL2 license. + * + *############################################################################# + * GPL + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * 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. + * + *############################################################################# + */ + +#ifndef _SYNAPTICS_RMI4_H_INCLUDED_ +#define _SYNAPTICS_RMI4_H_INCLUDED_ + + +/* Register Name Address Register Description */ +/* ------------- ------- -------------------- */ +#define SYNA_F34_FLASH_DATA00 0x0000 /* Block Number Low */ +#define SYNA_F34_FLASH_DATA01 0x0001 /* Block Number High */ +#define SYNA_F34_FLASH_DATA02_00 0x0002 /* Block Data 0 */ +#define SYNA_F34_FLASH_DATA02_01 0x0003 /* Block Data 1 */ +#define SYNA_F34_FLASH_DATA02_02 0x0004 /* Block Data 2 */ +#define SYNA_F34_FLASH_DATA02_03 0x0005 /* Block Data 3 */ +#define SYNA_F34_FLASH_DATA02_04 0x0006 /* Block Data 4 */ +#define SYNA_F34_FLASH_DATA02_05 0x0007 /* Block Data 5 */ +#define SYNA_F34_FLASH_DATA02_06 0x0008 /* Block Data 6 */ +#define SYNA_F34_FLASH_DATA02_07 0x0009 /* Block Data 7 */ +#define SYNA_F34_FLASH_DATA02_08 0x000A /* Block Data 8 */ +#define SYNA_F34_FLASH_DATA02_09 0x000B /* Block Data 9 */ +#define SYNA_F34_FLASH_DATA02_10 0x000C /* Block Data 10 */ +#define SYNA_F34_FLASH_DATA02_11 0x000D /* Block Data 11 */ +#define SYNA_F34_FLASH_DATA02_12 0x000E /* Block Data 12 */ +#define SYNA_F34_FLASH_DATA02_13 0x000F /* Block Data 13 */ +#define SYNA_F34_FLASH_DATA02_14 0x0010 /* Block Data 14 */ +#define SYNA_F34_FLASH_DATA02_15 0x0011 /* Block Data 15 */ +#define SYNA_F34_FLASH_DATA03 0x0012 /* Flash Control */ +#define SYNA_F01_RMI_DATA00 0x0013 /* Device Status */ +#define SYNA_F01_RMI_DATA01_00 0x0014 /* Interrupt Status */ +#define SYNA_F11_2D_DATA00_00 0x0015 /* 2D Finger State */ +#define SYNA_F11_2D_DATA00_01 0x0016 /* 2D Finger State */ +#define SYNA_F11_2D_DATA01_00 0x0017 /* 2D X Position (11:4) Finger 0 */ +#define SYNA_F11_2D_DATA02_00 0x0018 /* 2D Y Position (11:4) Finger 0 */ +#define SYNA_F11_2D_DATA03_00 0x0019 /* 2D Y/X Position (3:0) Finger 0 */ +#define SYNA_F11_2D_DATA04_00 0x001A /* 2D Wy/Wx Finger 0 */ +#define SYNA_F11_2D_DATA05_00 0x001B /* 2D Z Finger 0 */ +#define SYNA_F11_2D_DATA01_01 0x001C /* 2D X Position (11:4) Finger 1 */ +#define SYNA_F11_2D_DATA02_01 0x001D /* 2D Y Position (11:4) Finger 1 */ +#define SYNA_F11_2D_DATA03_01 0x001E /* 2D Y/X Position (3:0) Finger 1 */ +#define SYNA_F11_2D_DATA04_01 0x001F /* 2D Wy/Wx Finger 1 */ +#define SYNA_F11_2D_DATA05_01 0x0020 /* 2D Z Finger 1 */ +#define SYNA_F11_2D_DATA01_02 0x0021 /* 2D X Position (11:4) Finger 2 */ +#define SYNA_F11_2D_DATA02_02 0x0022 /* 2D Y Position (11:4) Finger 2 */ +#define SYNA_F11_2D_DATA03_02 0x0023 /* 2D Y/X Position (3:0) Finger 2 */ +#define SYNA_F11_2D_DATA04_02 0x0024 /* 2D Wy/Wx Finger 2 */ +#define SYNA_F11_2D_DATA05_02 0x0025 /* 2D Z Finger 2 */ +#define SYNA_F11_2D_DATA01_03 0x0026 /* 2D X Position (11:4) Finger 3 */ +#define SYNA_F11_2D_DATA02_03 0x0027 /* 2D Y Position (11:4) Finger 3 */ +#define SYNA_F11_2D_DATA03_03 0x0028 /* 2D Y/X Position (3:0) Finger 3 */ +#define SYNA_F11_2D_DATA04_03 0x0029 /* 2D Wy/Wx Finger 3 */ +#define SYNA_F11_2D_DATA05_03 0x002A /* 2D Z Finger 3 */ +#define SYNA_F11_2D_DATA01_04 0x002B /* 2D X Position (11:4) Finger 4 */ +#define SYNA_F11_2D_DATA02_04 0x002C /* 2D Y Position (11:4) Finger 4 */ +#define SYNA_F11_2D_DATA03_04 0x002D /* 2D Y/X Position (3:0) Finger 4 */ +#define SYNA_F11_2D_DATA04_04 0x002E /* 2D Wy/Wx Finger 4 */ +#define SYNA_F11_2D_DATA05_04 0x002F /* 2D Z Finger 4 */ +#define SYNA_F01_RMI_CTRL00 0x0030 /* Device Control */ +#define SYNA_F01_RMI_CTRL01_00 0x0031 /* Interrupt Enable 0 */ +#define SYNA_F11_2D_CTRL00 0x0032 /* 2D Report Mode */ +#define SYNA_F11_2D_CTRL01 0x0033 /* 2D Palm Detect */ +#define SYNA_F11_2D_CTRL02 0x0034 /* 2D Delta-X Thresh */ +#define SYNA_F11_2D_CTRL03 0x0035 /* 2D Delta-Y Thresh */ +#define SYNA_F11_2D_CTRL04 0x0036 /* 2D Velocity */ +#define SYNA_F11_2D_CTRL05 0x0037 /* 2D Acceleration */ +#define SYNA_F11_2D_CTRL06 0x0038 /* 2D Max X Position (7:0) */ +#define SYNA_F11_2D_CTRL07 0x0039 /* 2D Max X Position (11:8) */ +#define SYNA_F11_2D_CTRL08 0x003A /* 2D Max Y Position (7:0) */ +#define SYNA_F11_2D_CTRL09 0x003B /* 2D Max Y Position (11:8) */ +#define SYNA_F11_2D_CTRL12_00 0x003C /* 2D Sensor Map 0 */ +#define SYNA_F11_2D_CTRL12_01 0x003D /* 2D Sensor Map 1 */ +#define SYNA_F11_2D_CTRL12_02 0x003E /* 2D Sensor Map 2 */ +#define SYNA_F11_2D_CTRL12_03 0x003F /* 2D Sensor Map 3 */ +#define SYNA_F11_2D_CTRL12_04 0x0040 /* 2D Sensor Map 4 */ +#define SYNA_F11_2D_CTRL12_05 0x0041 /* 2D Sensor Map 5 */ +#define SYNA_F11_2D_CTRL12_06 0x0042 /* 2D Sensor Map 6 */ +#define SYNA_F11_2D_CTRL12_07 0x0043 /* 2D Sensor Map 7 */ +#define SYNA_F11_2D_CTRL12_08 0x0044 /* 2D Sensor Map 8 */ +#define SYNA_F11_2D_CTRL12_09 0x0045 /* 2D Sensor Map 9 */ +#define SYNA_F11_2D_CTRL12_10 0x0046 /* 2D Sensor Map 10 */ +#define SYNA_F11_2D_CTRL12_11 0x0047 /* 2D Sensor Map 11 */ +#define SYNA_F11_2D_CTRL12_12 0x0048 /* 2D Sensor Map 12 */ +#define SYNA_F11_2D_CTRL12_13 0x0049 /* 2D Sensor Map 13 */ +#define SYNA_F11_2D_CTRL12_14 0x004A /* 2D Sensor Map 14 */ +#define SYNA_F11_2D_CTRL12_15 0x004B /* 2D Sensor Map 15 */ +#define SYNA_F11_2D_CTRL12_16 0x004C /* 2D Sensor Map 16 */ +#define SYNA_F11_2D_CTRL12_17 0x004D /* 2D Sensor Map 17 */ +#define SYNA_F11_2D_CTRL12_18 0x004E /* 2D Sensor Map 18 */ +#define SYNA_F11_2D_CTRL12_19 0x004F /* 2D Sensor Map 19 */ +#define SYNA_F11_2D_CTRL12_20 0x0050 /* 2D Sensor Map 20 */ +#define SYNA_F11_2D_CTRL12_21 0x0051 /* 2D Sensor Map 21 */ +#define SYNA_F11_2D_CTRL12_22 0x0052 /* 2D Sensor Map 22 */ +#define SYNA_F11_2D_CTRL12_23 0x0053 /* 2D Sensor Map 23 */ +#define SYNA_F11_2D_CTRL12_24 0x0054 /* 2D Sensor Map 24 */ +#define SYNA_F11_2D_CTRL12_25 0x0055 /* 2D Sensor Map 25 */ +#define SYNA_F11_2D_CTRL12_26 0x0056 /* 2D Sensor Map 26 */ +#define SYNA_F11_2D_CTRL12_27 0x0057 /* 2D Sensor Map 27 */ +#define SYNA_F11_2D_CTRL12_28 0x0058 /* 2D Sensor Map 28 */ +#define SYNA_F11_2D_CTRL12_29 0x0059 /* 2D Sensor Map 29 */ +#define SYNA_F11_2D_CTRL12_30 0x005A /* 2D Sensor Map 30 */ +#define SYNA_F11_2D_CTRL12_31 0x005B /* 2D Sensor Map 31 */ +#define SYNA_F11_2D_CTRL12_32 0x005C /* 2D Sensor Map 32 */ +#define SYNA_F11_2D_CTRL12_33 0x005D /* 2D Sensor Map 33 */ +#define SYNA_F11_2D_CTRL12_34 0x005E /* 2D Sensor Map 34 */ +#define SYNA_F11_2D_CTRL12_35 0x005F /* 2D Sensor Map 35 */ +#define SYNA_F11_2D_CTRL12_36 0x0060 /* 2D Sensor Map 36 */ +#define SYNA_F11_2D_CTRL12_37 0x0061 /* 2D Sensor Map 37 */ +#define SYNA_F11_2D_CTRL12_38 0x0062 /* 2D Sensor Map 38 */ +#define SYNA_F11_2D_CTRL12_39 0x0063 /* 2D Sensor Map 39 */ +#define SYNA_F11_2D_CTRL12_40 0x0064 /* 2D Sensor Map 40 */ +#define SYNA_F11_2D_CTRL12_41 0x0065 /* 2D Sensor Map 41 */ +#define SYNA_F11_2D_CTRL12_42 0x0066 /* 2D Sensor Map 42 */ +#define SYNA_F11_2D_CTRL12_43 0x0067 /* 2D Sensor Map 43 */ +#define SYNA_F11_2D_CTRL12_44 0x0068 /* 2D Sensor Map 44 */ +#define SYNA_F11_2D_CTRL14 0x0096 /* 2D Sensitivity Adjustment */ +#define SYNA_F01_RMI_CMD00 0x0097 /* Device Command */ +#define SYNA_F11_2D_CMD00 0x0098 /* 2D Command */ +#define SYNA_F34_FLASH_QUERY00 0x0099 /* Bootloader ID 0 */ +#define SYNA_F34_FLASH_QUERY01 0x009A /* Bootloader ID 1 */ +#define SYNA_F34_FLASH_QUERY02 0x009B /* Flash Properties */ +#define SYNA_F34_FLASH_QUERY03 0x009C /* Block Size 0 */ +#define SYNA_F34_FLASH_QUERY04 0x009D /* Block Size 1 */ +#define SYNA_F34_FLASH_QUERY05 0x009E /* Firmware Block Count 0 */ +#define SYNA_F34_FLASH_QUERY06 0x009F /* Firmware Block Count 1 */ +#define SYNA_F34_FLASH_QUERY07 0x00A0 /* Configuration Block Count 0 */ +#define SYNA_F34_FLASH_QUERY08 0x00A1 /* Configuration Block Count 1 */ +#define SYNA_F01_RMI_QUERY00 0x00A2 /* Manufacturer ID Query */ +#define SYNA_F01_RMI_QUERY01 0x00A3 /* Product Properties Query */ +#define SYNA_F01_RMI_QUERY02 0x00A4 /* Customer Family Query */ +#define SYNA_F01_RMI_QUERY03 0x00A5 /* Firmware Revision Query */ +#define SYNA_F01_RMI_QUERY04 0x00A6 /* Device Serialization Query 0 */ +#define SYNA_F01_RMI_QUERY05 0x00A7 /* Device Serialization Query 1 */ +#define SYNA_F01_RMI_QUERY06 0x00A8 /* Device Serialization Query 2 */ +#define SYNA_F01_RMI_QUERY07 0x00A9 /* Device Serialization Query 3 */ +#define SYNA_F01_RMI_QUERY08 0x00AA /* Device Serialization Query 4 */ +#define SYNA_F01_RMI_QUERY09 0x00AB /* Device Serialization Query 5 */ +#define SYNA_F01_RMI_QUERY10 0x00AC /* Device Serialization Query 6 */ +#define SYNA_F01_RMI_QUERY11 0x00AD /* Product ID Query 0 */ +#define SYNA_F01_RMI_QUERY12 0x00AE /* Product ID Query 1 */ +#define SYNA_F01_RMI_QUERY13 0x00AF /* Product ID Query 2 */ +#define SYNA_F01_RMI_QUERY14 0x00B0 /* Product ID Query 3 */ +#define SYNA_F01_RMI_QUERY15 0x00B1 /* Product ID Query 4 */ +#define SYNA_F01_RMI_QUERY16 0x00B2 /* Product ID Query 5 */ +#define SYNA_F01_RMI_QUERY17 0x00B3 /* Product ID Query 6 */ +#define SYNA_F01_RMI_QUERY18 0x00B4 /* Product ID Query 7 */ +#define SYNA_F01_RMI_QUERY19 0x00B5 /* Product ID Query 8 */ +#define SYNA_F01_RMI_QUERY20 0x00B6 /* Product ID Query 9 */ +#define SYNA_F11_2D_QUERY00 0x00B7 /* Per-device Query */ +#define SYNA_F11_2D_QUERY01 0x00B8 /* 2D Reporting Mode */ +#define SYNA_F11_2D_QUERY02 0x00B9 /* 2D Number of X Electrodes */ +#define SYNA_F11_2D_QUERY03 0x00BA /* 2D Number of Y Electrodes */ +#define SYNA_F11_2D_QUERY04 0x00BB /* 2D Maximum Electrodes */ +#define SYNA_F11_2D_QUERY05 0x00BC /* 2D Absolute Query */ + +/* Start of Page Description Table (PDT) */ + +#define SYNA_PDT_P00_F11_2D_QUERY_BASE 0x00DD /* Query Base */ +#define SYNA_PDT_P00_F11_2D_COMMAND_BASE 0x00DE /* Command Base */ +#define SYNA_PDT_P00_F11_2D_CONTROL_BASE 0x00DF /* Control Base */ +#define SYNA_PDT_P00_F11_2D_DATA_BASE 0x00E0 /* Data Base */ +#define SYNA_PDT_P00_F11_2D_INTERRUPTS 0x00E1 /* Interrupt Source Count */ +#define SYNA_PDT_P00_F11_2D_EXISTS 0x00E2 /* Function Exists */ +#define SYNA_PDT_P00_F01_RMI_QUERY_BASE 0x00E3 /* Query Base */ +#define SYNA_PDT_P00_F01_RMI_COMMAND_BASE 0x00E4 /* Command Base */ +#define SYNA_PDT_P00_F01_RMI_CONTROL_BASE 0x00E5 /* Control Base */ +#define SYNA_PDT_P00_F01_RMI_DATA_BASE 0x00E6 /* Data Base */ +#define SYNA_PDT_P00_F01_RMI_INTERRUPTS 0x00E7 /* Interrupt Source Count */ +#define SYNA_PDT_P00_F01_RMI_EXISTS 0x00E8 /* Function Exists */ +#define SYNA_PDT_P00_F34_FLASH_QUERY_BASE 0x00E9 /* Query Base */ +#define SYNA_PDT_P00_F34_FLASH_COMMAND_BASE 0x00EA /* Command Base */ +#define SYNA_PDT_P00_F34_FLASH_CONTROL_BASE 0x00EB /* Control Base */ +#define SYNA_PDT_P00_F34_FLASH_DATA_BASE 0x00EC /* Data Base */ +#define SYNA_PDT_P00_F34_FLASH_INTERRUPTS 0x00ED /* Interrupt Source Count */ +#define SYNA_PDT_P00_F34_FLASH_EXISTS 0x00EE /* Function Exists */ +#define SYNA_P00_PDT_PROPERTIES 0x00EF /* P00_PDT Properties */ +#define SYNA_P00_PAGESELECT 0x00FF /* Page Select register */ + +/* Registers on Page 0x01 */ + +/* Register Name Address Register Description */ +/* ------------- ------- -------------------- */ +#define SYNA_F05_ANALOG_DATA00 0x0100 /* Reserved */ +#define SYNA_F05_ANALOG_DATA01 0x0101 /* Report Mode and Index */ +#define SYNA_F05_ANALOG_DATA02_00 0x0102 /* Report Data Window 0 */ +#define SYNA_F05_ANALOG_DATA02_01 0x0103 /* Report Data Window 1 */ +#define SYNA_F05_ANALOG_DATA02_02 0x0104 /* Report Data Window 2 */ +#define SYNA_F05_ANALOG_DATA02_03 0x0105 /* Report Data Window 3 */ +#define SYNA_F05_ANALOG_DATA02_04 0x0106 /* Report Data Window 4 */ +#define SYNA_F05_ANALOG_DATA02_05 0x0107 /* Report Data Window 5 */ +#define SYNA_F05_ANALOG_DATA02_06 0x0108 /* Report Data Window 6 */ +#define SYNA_F05_ANALOG_DATA02_07 0x0109 /* Report Data Window 7 */ +#define SYNA_F05_ANALOG_DATA02_08 0x010A /* Report Data Window 8 */ +#define SYNA_F05_ANALOG_DATA02_09 0x010B /* Report Data Window 9 */ +#define SYNA_F05_ANALOG_DATA02_10 0x010C /* Report Data Window 10 */ +#define SYNA_F05_ANALOG_DATA02_11 0x010D /* Report Data Window 11 */ +#define SYNA_F05_ANALOG_DATA02_12 0x010E /* Report Data Window 12 */ +#define SYNA_F05_ANALOG_DATA02_13 0x010F /* Report Data Window 13 */ +#define SYNA_F05_ANALOG_DATA02_14 0x0110 /* Report Data Window 14 */ +#define SYNA_F05_ANALOG_DATA02_15 0x0111 /* Report Data Window 15 */ +#define SYNA_F05_ANALOG_DATA02_16 0x0112 /* Report Data Window 16 */ +#define SYNA_F05_ANALOG_DATA02_17 0x0113 /* Report Data Window 17 */ +#define SYNA_F05_ANALOG_DATA02_18 0x0114 /* Report Data Window 18 */ +#define SYNA_F05_ANALOG_DATA02_19 0x0115 /* Report Data Window 19 */ +#define SYNA_F05_ANALOG_DATA02_20 0x0116 /* Report Data Window 20 */ +#define SYNA_F05_ANALOG_DATA02_21 0x0117 /* Report Data Window 21 */ +#define SYNA_F05_ANALOG_DATA02_22 0x0118 /* Report Data Window 22 */ +#define SYNA_F05_ANALOG_DATA02_23 0x0119 /* Report Data Window 23 */ +#define SYNA_F05_ANALOG_DATA02_24 0x011A /* Report Data Window 24 */ +#define SYNA_F05_ANALOG_DATA02_25 0x011B /* Report Data Window 25 */ +#define SYNA_F05_ANALOG_DATA02_26 0x011C /* Report Data Window 26 */ +#define SYNA_F05_ANALOG_DATA02_27 0x011D /* Report Data Window 27 */ +#define SYNA_F05_ANALOG_DATA02_28 0x011E /* Report Data Window 28 */ +#define SYNA_F05_ANALOG_DATA02_29 0x011F /* Report Data Window 29 */ +#define SYNA_F05_ANALOG_DATA02_30 0x0120 /* Report Data Window 30 */ +#define SYNA_F05_ANALOG_DATA02_31 0x0121 /* Report Data Window 31 */ +#define SYNA_F05_ANALOG_DATA02_32 0x0122 /* Report Data Window 32 */ +#define SYNA_F05_ANALOG_DATA02_33 0x0123 /* Report Data Window 33 */ +#define SYNA_F05_ANALOG_CTRL00 0x0124 /* Algo Control */ +#define SYNA_F05_ANALOG_CTRL01 0x0125 /* Reserved */ +#define SYNA_F05_ANALOG_CTRL02 0x0126 /* Reserved */ +#define SYNA_F05_ANALOG_CTRL03 0x0127 /* Reserved */ +#define SYNA_F05_ANALOG_CTRL04 0x0128 /* Reserved */ +#define SYNA_F05_ANALOG_CTRL05 0x0129 /* Reserved */ +#define SYNA_F05_ANALOG_CMD00 0x012A /* Analog Command */ +#define SYNA_F05_ANALOG_QUERY00 0x012B /* Receiver Electrodes */ +#define SYNA_F05_ANALOG_QUERY01 0x012C /* Transmitter Electrodes */ +#define SYNA_F05_ANALOG_QUERY02 0x012D /* Reserved */ +#define SYNA_F05_ANALOG_QUERY03 0x012E /* Features */ +#define SYNA_F05_ANALOG_QUERY04 0x012F /* Image Window Count */ +#define SYNA_F05_ANALOG_QUERY05 0x0130 /* Reserved */ + +/* Start of Page Description Table (PDT) for Page 0x01 */ + +#define SYNA_PDT_P01_F05_ANALOG_QUERY_BASE 0x01E9 /* Query Base */ +#define SYNA_PDT_P01_F05_ANALOG_COMMAND_BASE 0x01EA /* Command Base */ +#define SYNA_PDT_P01_F05_ANALOG_CONTROL_BASE 0x01EB /* Control Base */ +#define SYNA_PDT_P01_F05_ANALOG_DATA_BASE 0x01EC /* Data Base */ +#define SYNA_PDT_P01_F05_ANALOG_INTERRUPTS 0x01ED /* Interrupt Source Count */ +#define SYNA_PDT_P01_F05_ANALOG_EXISTS 0x01EE /* Function Exists */ +#define SYNA_P01_PDT_PROPERTIES 0x01EF /* P01_PDT Properties */ +#define SYNA_P01_PAGESELECT 0x01FF /* Page Select register */ + +/* Offsets within the configuration block */ + +/* Register Name Offset Register Description */ +/* ------------- ------ -------------------- */ +#define SYNA_F01_RMI_CTRL00_CFGBLK_OFS 0x0000 /* Device Control */ +#define SYNA_F01_RMI_CTRL01_00_CFGBLK_OFS 0x0001 /* Interrupt Enable 0 */ +#define SYNA_F11_2D_CTRL00_CFGBLK_OFS 0x0002 /* 2D Report Mode */ +#define SYNA_F11_2D_CTRL01_CFGBLK_OFS 0x0003 /* 2D Palm Detect */ +#define SYNA_F11_2D_CTRL02_CFGBLK_OFS 0x0004 /* 2D Delta-X Thresh */ +#define SYNA_F11_2D_CTRL03_CFGBLK_OFS 0x0005 /* 2D Delta-Y Thresh */ +#define SYNA_F11_2D_CTRL04_CFGBLK_OFS 0x0006 /* 2D Velocity */ +#define SYNA_F11_2D_CTRL05_CFGBLK_OFS 0x0007 /* 2D Acceleration */ +#define SYNA_F11_2D_CTRL06_CFGBLK_OFS 0x0008 /* 2D Max X Position (7:0) */ +#define SYNA_F11_2D_CTRL07_CFGBLK_OFS 0x0009 /* 2D Max X Position (11:8) */ +#define SYNA_F11_2D_CTRL08_CFGBLK_OFS 0x000A /* 2D Max Y Position (7:0) */ +#define SYNA_F11_2D_CTRL09_CFGBLK_OFS 0x000B /* 2D Max Y Position (11:8) */ +#define SYNA_F11_2D_CTRL12_00_CFGBLK_OFS 0x000C /* 2D Sensor Map 0 */ +#define SYNA_F11_2D_CTRL12_01_CFGBLK_OFS 0x000D /* 2D Sensor Map 1 */ +#define SYNA_F11_2D_CTRL12_02_CFGBLK_OFS 0x000E /* 2D Sensor Map 2 */ +#define SYNA_F11_2D_CTRL12_03_CFGBLK_OFS 0x000F /* 2D Sensor Map 3 */ +#define SYNA_F11_2D_CTRL12_04_CFGBLK_OFS 0x0010 /* 2D Sensor Map 4 */ +#define SYNA_F11_2D_CTRL12_05_CFGBLK_OFS 0x0011 /* 2D Sensor Map 5 */ +#define SYNA_F11_2D_CTRL12_06_CFGBLK_OFS 0x0012 /* 2D Sensor Map 6 */ +#define SYNA_F11_2D_CTRL12_07_CFGBLK_OFS 0x0013 /* 2D Sensor Map 7 */ +#define SYNA_F11_2D_CTRL12_08_CFGBLK_OFS 0x0014 /* 2D Sensor Map 8 */ +#define SYNA_F11_2D_CTRL12_09_CFGBLK_OFS 0x0015 /* 2D Sensor Map 9 */ +#define SYNA_F11_2D_CTRL12_10_CFGBLK_OFS 0x0016 /* 2D Sensor Map 10 */ +#define SYNA_F11_2D_CTRL12_11_CFGBLK_OFS 0x0017 /* 2D Sensor Map 11 */ +#define SYNA_F11_2D_CTRL12_12_CFGBLK_OFS 0x0018 /* 2D Sensor Map 12 */ +#define SYNA_F11_2D_CTRL12_13_CFGBLK_OFS 0x0019 /* 2D Sensor Map 13 */ +#define SYNA_F11_2D_CTRL12_14_CFGBLK_OFS 0x001A /* 2D Sensor Map 14 */ +#define SYNA_F11_2D_CTRL12_15_CFGBLK_OFS 0x001B /* 2D Sensor Map 15 */ +#define SYNA_F11_2D_CTRL12_16_CFGBLK_OFS 0x001C /* 2D Sensor Map 16 */ +#define SYNA_F11_2D_CTRL12_17_CFGBLK_OFS 0x001D /* 2D Sensor Map 17 */ +#define SYNA_F11_2D_CTRL12_18_CFGBLK_OFS 0x001E /* 2D Sensor Map 18 */ +#define SYNA_F11_2D_CTRL12_19_CFGBLK_OFS 0x001F /* 2D Sensor Map 19 */ +#define SYNA_F11_2D_CTRL12_20_CFGBLK_OFS 0x0020 /* 2D Sensor Map 20 */ +#define SYNA_F11_2D_CTRL12_21_CFGBLK_OFS 0x0021 /* 2D Sensor Map 21 */ +#define SYNA_F11_2D_CTRL12_22_CFGBLK_OFS 0x0022 /* 2D Sensor Map 22 */ +#define SYNA_F11_2D_CTRL12_23_CFGBLK_OFS 0x0023 /* 2D Sensor Map 23 */ +#define SYNA_F11_2D_CTRL12_24_CFGBLK_OFS 0x0024 /* 2D Sensor Map 24 */ +#define SYNA_F11_2D_CTRL12_25_CFGBLK_OFS 0x0025 /* 2D Sensor Map 25 */ +#define SYNA_F11_2D_CTRL12_26_CFGBLK_OFS 0x0026 /* 2D Sensor Map 26 */ +#define SYNA_F11_2D_CTRL12_27_CFGBLK_OFS 0x0027 /* 2D Sensor Map 27 */ +#define SYNA_F11_2D_CTRL12_28_CFGBLK_OFS 0x0028 /* 2D Sensor Map 28 */ +#define SYNA_F11_2D_CTRL12_29_CFGBLK_OFS 0x0029 /* 2D Sensor Map 29 */ +#define SYNA_F11_2D_CTRL12_30_CFGBLK_OFS 0x002A /* 2D Sensor Map 30 */ +#define SYNA_F11_2D_CTRL12_31_CFGBLK_OFS 0x002B /* 2D Sensor Map 31 */ +#define SYNA_F11_2D_CTRL12_32_CFGBLK_OFS 0x002C /* 2D Sensor Map 32 */ +#define SYNA_F11_2D_CTRL12_33_CFGBLK_OFS 0x002D /* 2D Sensor Map 33 */ +#define SYNA_F11_2D_CTRL12_34_CFGBLK_OFS 0x002E /* 2D Sensor Map 34 */ +#define SYNA_F11_2D_CTRL12_35_CFGBLK_OFS 0x002F /* 2D Sensor Map 35 */ +#define SYNA_F11_2D_CTRL12_36_CFGBLK_OFS 0x0030 /* 2D Sensor Map 36 */ +#define SYNA_F11_2D_CTRL12_37_CFGBLK_OFS 0x0031 /* 2D Sensor Map 37 */ +#define SYNA_F11_2D_CTRL12_38_CFGBLK_OFS 0x0032 /* 2D Sensor Map 38 */ +#define SYNA_F11_2D_CTRL12_39_CFGBLK_OFS 0x0033 /* 2D Sensor Map 39 */ +#define SYNA_F11_2D_CTRL12_40_CFGBLK_OFS 0x0034 /* 2D Sensor Map 40 */ +#define SYNA_F11_2D_CTRL12_41_CFGBLK_OFS 0x0035 /* 2D Sensor Map 41 */ +#define SYNA_F11_2D_CTRL12_42_CFGBLK_OFS 0x0036 /* 2D Sensor Map 42 */ +#define SYNA_F11_2D_CTRL12_43_CFGBLK_OFS 0x0037 /* 2D Sensor Map 43 */ +#define SYNA_F11_2D_CTRL12_44_CFGBLK_OFS 0x0038 /* 2D Sensor Map 44 */ +#define SYNA_F11_2D_CTRL14_CFGBLK_OFS 0x0066 /* 2D Sensitivity Adjustment */ +#define SYNA_F05_ANALOG_CTRL00_CFGBLK_OFS 0x0067 /* Algo Control */ +#define SYNA_F05_ANALOG_CTRL01_CFGBLK_OFS 0x0068 /* Reserved */ +#define SYNA_F05_ANALOG_CTRL02_CFGBLK_OFS 0x0069 /* Reserved */ +#define SYNA_F05_ANALOG_CTRL03_CFGBLK_OFS 0x006A /* Reserved */ +#define SYNA_F05_ANALOG_CTRL04_CFGBLK_OFS 0x006B /* Reserved */ +#define SYNA_F05_ANALOG_CTRL05_CFGBLK_OFS 0x006C /* Reserved */ +#define SYNA_CFGBLK_CRC1_CFGBLK_OFS 0x01FC /* Configuration CRC [7:0] */ +#define SYNA_CFGBLK_CRC2_CFGBLK_OFS 0x01FD /* Configuration CRC [15:8] */ +#define SYNA_CFGBLK_CRC3_CFGBLK_OFS 0x01FE /* Configuration CRC [23:16] */ +#define SYNA_CFGBLK_CRC4_CFGBLK_OFS 0x01FF /* Configuration CRC [31:24] */ + +/* Masks for interrupt sources */ + +/* Symbol Name Mask Description */ +/* ----------- ---- ----------- */ +#define SYNA_F01_RMI_INT_SOURCE_MASK_ALL 0x0002 /* Mask of all Func $01 (RMI) interrupts */ +#define SYNA_F01_RMI_INT_SOURCE_MASK_STATUS 0x0002 /* Mask of Func $01 (RMI) 'STATUS' interrupt */ +#define SYNA_F05_ANALOG_INT_SOURCE_MASK_ALL 0x0008 /* Mask of all Func $05 (ANALOG) interrupts */ +#define SYNA_F05_ANALOG_INT_SOURCE_MASK_ANALOG 0x0008 /* Mask of Func $05 (ANALOG) 'ANALOG' interrupt */ +#define SYNA_F11_2D_INT_SOURCE_MASK_ABS0 0x0004 /* Mask of Func $11 (2D) 'ABS0' interrupt */ +#define SYNA_F11_2D_INT_SOURCE_MASK_ALL 0x0004 /* Mask of all Func $11 (2D) interrupts */ +#define SYNA_F34_FLASH_INT_SOURCE_MASK_ALL 0x0001 /* Mask of all Func $34 (FLASH) interrupts */ +#define SYNA_F34_FLASH_INT_SOURCE_MASK_FLASH 0x0001 /* Mask of Func $34 (FLASH) 'FLASH' interrupt */ + +/* cwz: change to arch/board.h */ +#if 1 +/** + * struct synaptics_rmi4_platform_data - contains the rmi4 platform data + * @irq_number: irq number + * @irq_type: irq type + * @x flip: x flip flag + * @y flip: y flip flag + * @regulator_en: regulator enable flag + * + * This structure gives platform data for rmi4. + */ +struct synaptics_rmi4_platform_data { + int irq_number; + int irq_type; + bool virtual_keys; //virtual_keys for touch screen without real keys + int lcd_width; + int lcd_height; + int w_delta; + int h_delta; + bool x_flip; + bool y_flip; + bool regulator_en; +}; +#endif + +#endif /* _SYNAPTICS_RMI4_H_INCLUDED_ */