| /** |
| * |
| * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver. |
| * Copyright (c) 2007-2010, Synaptics Incorporated |
| * |
| * Author: Js HA <js.ha@stericsson.com> for ST-Ericsson |
| * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> 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 <linux/input.h> |
| #include <linux/slab.h> |
| #include <linux/i2c.h> |
| #include <linux/interrupt.h> |
| #include <linux/regulator/consumer.h> |
| #include <linux/module.h> |
| #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 |
| #define TOUCHPAD_CTRL_INTR 0x8 |
| #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) |
| |
| /** |
| * 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; |
| }; |
| |
| /** |
| * 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: |
| retval = i2c_smbus_read_i2c_block_data(i2c, index, size, valp); |
| 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; |
| } |
| |
| /** |
| * 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; |
| |
| /* 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++) { |
| /* 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) { |
| /* 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__); |
| return 0; |
| } else { |
| x[touch_count] = |
| (data[0] << 4) | (data[2] & MASK_4BIT); |
| y[touch_count] = |
| (data[1] << 4) | |
| ((data[2] >> 4) & MASK_4BIT); |
| wy[touch_count] = |
| (data[3] >> 4) & MASK_4BIT; |
| wx[touch_count] = |
| (data[3] & MASK_4BIT); |
| |
| if (pdata->board->x_flip) |
| x[touch_count] = |
| pdata->sensor_max_x - |
| x[touch_count]; |
| if (pdata->board->y_flip) |
| y[touch_count] = |
| pdata->sensor_max_y - |
| y[touch_count]; |
| } |
| /* number of active touch points */ |
| touch_count++; |
| } |
| } |
| |
| /* report to input subsystem */ |
| if (touch_count) { |
| for (finger = 0; finger < touch_count; finger++) { |
| input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR, |
| max(wx[finger] , wy[finger])); |
| input_report_abs(pdata->input_dev, ABS_MT_POSITION_X, |
| x[finger]); |
| input_report_abs(pdata->input_dev, ABS_MT_POSITION_Y, |
| y[finger]); |
| input_mt_sync(pdata->input_dev); |
| } |
| } else |
| input_mt_sync(pdata->input_dev); |
| |
| /* 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) { |
| 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; |
| } |
| |
| /** |
| * 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; |
| int touch_count; |
| do { |
| touch_count = synaptics_rmi4_sensor_report(pdata); |
| if (touch_count) |
| wait_event_timeout(pdata->wait, pdata->touch_stopped, |
| msecs_to_jiffies(1)); |
| else |
| break; |
| } while (!pdata->touch_stopped); |
| 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 { |
| 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_5BIT) << 0) | |
| ((data[9] & MASK_4BIT) << 8); |
| } |
| 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; |
| } |
| 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; |
| 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); |
| |
| /* 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; |
| 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; |
| const struct synaptics_rmi4_platform_data *platformdata = |
| client->dev.platform_data; |
| |
| if (!i2c_check_functionality(client->adapter, |
| I2C_FUNC_SMBUS_BYTE_DATA)) { |
| dev_err(&client->dev, "i2c smbus byte data not supported\n"); |
| return -EIO; |
| } |
| |
| if (!platformdata) { |
| dev_err(&client->dev, "%s: no platform data\n", __func__); |
| return -EINVAL; |
| } |
| |
| /* 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; |
| } |
| |
| 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_get_regulator; |
| } |
| retval = regulator_enable(rmi4_data->regulator); |
| if (retval < 0) { |
| dev_err(&client->dev, "%s:regulator enable failed\n", |
| __func__); |
| goto err_regulator_enable; |
| } |
| 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)); |
| |
| /* |
| * 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(EV_SYN, rmi4_data->input_dev->evbit); |
| set_bit(EV_KEY, rmi4_data->input_dev->evbit); |
| set_bit(EV_ABS, rmi4_data->input_dev->evbit); |
| |
| 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); |
| 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; |
| } |
| |
| return retval; |
| |
| err_free_irq: |
| free_irq(platformdata->irq_number, rmi4_data); |
| err_query_dev: |
| regulator_disable(rmi4_data->regulator); |
| err_regulator_enable: |
| regulator_put(rmi4_data->regulator); |
| err_get_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; |
| |
| rmi4_data->touch_stopped = true; |
| wake_up(&rmi4_data->wait); |
| free_irq(pdata->irq_number, rmi4_data); |
| input_unregister_device(rmi4_data->input_dev); |
| regulator_disable(rmi4_data->regulator); |
| regulator_put(rmi4_data->regulator); |
| kfree(rmi4_data); |
| |
| return 0; |
| } |
| |
| #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_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; |
| |
| 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; |
| |
| 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, |
| #ifdef CONFIG_PM |
| .pm = &synaptics_rmi4_dev_pm_ops, |
| #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"); |