diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/input/mouse/synaptics_i2c.c')
-rw-r--r-- | ANDROID_3.4.5/drivers/input/mouse/synaptics_i2c.c | 680 |
1 files changed, 0 insertions, 680 deletions
diff --git a/ANDROID_3.4.5/drivers/input/mouse/synaptics_i2c.c b/ANDROID_3.4.5/drivers/input/mouse/synaptics_i2c.c deleted file mode 100644 index f1467570..00000000 --- a/ANDROID_3.4.5/drivers/input/mouse/synaptics_i2c.c +++ /dev/null @@ -1,680 +0,0 @@ -/* - * Synaptics touchpad with I2C interface - * - * Copyright (C) 2009 Compulab, Ltd. - * Mike Rapoport <mike@compulab.co.il> - * Igor Grinberg <grinberg@compulab.co.il> - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/input.h> -#include <linux/delay.h> -#include <linux/workqueue.h> -#include <linux/slab.h> -#include <linux/pm.h> - -#define DRIVER_NAME "synaptics_i2c" -/* maximum product id is 15 characters */ -#define PRODUCT_ID_LENGTH 15 -#define REGISTER_LENGTH 8 - -/* - * after soft reset, we should wait for 1 ms - * before the device becomes operational - */ -#define SOFT_RESET_DELAY_MS 3 -/* and after hard reset, we should wait for max 500ms */ -#define HARD_RESET_DELAY_MS 500 - -/* Registers by SMBus address */ -#define PAGE_SEL_REG 0xff -#define DEVICE_STATUS_REG 0x09 - -/* Registers by RMI address */ -#define DEV_CONTROL_REG 0x0000 -#define INTERRUPT_EN_REG 0x0001 -#define ERR_STAT_REG 0x0002 -#define INT_REQ_STAT_REG 0x0003 -#define DEV_COMMAND_REG 0x0004 - -#define RMI_PROT_VER_REG 0x0200 -#define MANUFACT_ID_REG 0x0201 -#define PHYS_INT_VER_REG 0x0202 -#define PROD_PROPERTY_REG 0x0203 -#define INFO_QUERY_REG0 0x0204 -#define INFO_QUERY_REG1 (INFO_QUERY_REG0 + 1) -#define INFO_QUERY_REG2 (INFO_QUERY_REG0 + 2) -#define INFO_QUERY_REG3 (INFO_QUERY_REG0 + 3) - -#define PRODUCT_ID_REG0 0x0210 -#define PRODUCT_ID_REG1 (PRODUCT_ID_REG0 + 1) -#define PRODUCT_ID_REG2 (PRODUCT_ID_REG0 + 2) -#define PRODUCT_ID_REG3 (PRODUCT_ID_REG0 + 3) -#define PRODUCT_ID_REG4 (PRODUCT_ID_REG0 + 4) -#define PRODUCT_ID_REG5 (PRODUCT_ID_REG0 + 5) -#define PRODUCT_ID_REG6 (PRODUCT_ID_REG0 + 6) -#define PRODUCT_ID_REG7 (PRODUCT_ID_REG0 + 7) -#define PRODUCT_ID_REG8 (PRODUCT_ID_REG0 + 8) -#define PRODUCT_ID_REG9 (PRODUCT_ID_REG0 + 9) -#define PRODUCT_ID_REG10 (PRODUCT_ID_REG0 + 10) -#define PRODUCT_ID_REG11 (PRODUCT_ID_REG0 + 11) -#define PRODUCT_ID_REG12 (PRODUCT_ID_REG0 + 12) -#define PRODUCT_ID_REG13 (PRODUCT_ID_REG0 + 13) -#define PRODUCT_ID_REG14 (PRODUCT_ID_REG0 + 14) -#define PRODUCT_ID_REG15 (PRODUCT_ID_REG0 + 15) - -#define DATA_REG0 0x0400 -#define ABS_PRESSURE_REG 0x0401 -#define ABS_MSB_X_REG 0x0402 -#define ABS_LSB_X_REG (ABS_MSB_X_REG + 1) -#define ABS_MSB_Y_REG 0x0404 -#define ABS_LSB_Y_REG (ABS_MSB_Y_REG + 1) -#define REL_X_REG 0x0406 -#define REL_Y_REG 0x0407 - -#define DEV_QUERY_REG0 0x1000 -#define DEV_QUERY_REG1 (DEV_QUERY_REG0 + 1) -#define DEV_QUERY_REG2 (DEV_QUERY_REG0 + 2) -#define DEV_QUERY_REG3 (DEV_QUERY_REG0 + 3) -#define DEV_QUERY_REG4 (DEV_QUERY_REG0 + 4) -#define DEV_QUERY_REG5 (DEV_QUERY_REG0 + 5) -#define DEV_QUERY_REG6 (DEV_QUERY_REG0 + 6) -#define DEV_QUERY_REG7 (DEV_QUERY_REG0 + 7) -#define DEV_QUERY_REG8 (DEV_QUERY_REG0 + 8) - -#define GENERAL_2D_CONTROL_REG 0x1041 -#define SENSOR_SENSITIVITY_REG 0x1044 -#define SENS_MAX_POS_MSB_REG 0x1046 -#define SENS_MAX_POS_LSB_REG (SENS_MAX_POS_UPPER_REG + 1) - -/* Register bits */ -/* Device Control Register Bits */ -#define REPORT_RATE_1ST_BIT 6 - -/* Interrupt Enable Register Bits (INTERRUPT_EN_REG) */ -#define F10_ABS_INT_ENA 0 -#define F10_REL_INT_ENA 1 -#define F20_INT_ENA 2 - -/* Interrupt Request Register Bits (INT_REQ_STAT_REG | DEVICE_STATUS_REG) */ -#define F10_ABS_INT_REQ 0 -#define F10_REL_INT_REQ 1 -#define F20_INT_REQ 2 -/* Device Status Register Bits (DEVICE_STATUS_REG) */ -#define STAT_CONFIGURED 6 -#define STAT_ERROR 7 - -/* Device Command Register Bits (DEV_COMMAND_REG) */ -#define RESET_COMMAND 0x01 -#define REZERO_COMMAND 0x02 - -/* Data Register 0 Bits (DATA_REG0) */ -#define GESTURE 3 - -/* Device Query Registers Bits */ -/* DEV_QUERY_REG3 */ -#define HAS_PALM_DETECT 1 -#define HAS_MULTI_FING 2 -#define HAS_SCROLLER 4 -#define HAS_2D_SCROLL 5 - -/* General 2D Control Register Bits (GENERAL_2D_CONTROL_REG) */ -#define NO_DECELERATION 1 -#define REDUCE_REPORTING 3 -#define NO_FILTER 5 - -/* Function Masks */ -/* Device Control Register Masks (DEV_CONTROL_REG) */ -#define REPORT_RATE_MSK 0xc0 -#define SLEEP_MODE_MSK 0x07 - -/* Device Sleep Modes */ -#define FULL_AWAKE 0x0 -#define NORMAL_OP 0x1 -#define LOW_PWR_OP 0x2 -#define VERY_LOW_PWR_OP 0x3 -#define SENS_SLEEP 0x4 -#define SLEEP_MOD 0x5 -#define DEEP_SLEEP 0x6 -#define HIBERNATE 0x7 - -/* Interrupt Register Mask */ -/* (INT_REQ_STAT_REG | DEVICE_STATUS_REG | INTERRUPT_EN_REG) */ -#define INT_ENA_REQ_MSK 0x07 -#define INT_ENA_ABS_MSK 0x01 -#define INT_ENA_REL_MSK 0x02 -#define INT_ENA_F20_MSK 0x04 - -/* Device Status Register Masks (DEVICE_STATUS_REG) */ -#define CONFIGURED_MSK 0x40 -#define ERROR_MSK 0x80 - -/* Data Register 0 Masks */ -#define FINGER_WIDTH_MSK 0xf0 -#define GESTURE_MSK 0x08 -#define SENSOR_STATUS_MSK 0x07 - -/* - * MSB Position Register Masks - * ABS_MSB_X_REG | ABS_MSB_Y_REG | SENS_MAX_POS_MSB_REG | - * DEV_QUERY_REG3 | DEV_QUERY_REG5 - */ -#define MSB_POSITION_MSK 0x1f - -/* Device Query Registers Masks */ - -/* DEV_QUERY_REG2 */ -#define NUM_EXTRA_POS_MSK 0x07 - -/* When in IRQ mode read the device every THREAD_IRQ_SLEEP_SECS */ -#define THREAD_IRQ_SLEEP_SECS 2 -#define THREAD_IRQ_SLEEP_MSECS (THREAD_IRQ_SLEEP_SECS * MSEC_PER_SEC) - -/* - * When in Polling mode and no data received for NO_DATA_THRES msecs - * reduce the polling rate to NO_DATA_SLEEP_MSECS - */ -#define NO_DATA_THRES (MSEC_PER_SEC) -#define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4) - -/* Control touchpad's No Deceleration option */ -static bool no_decel = 1; -module_param(no_decel, bool, 0644); -MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)"); - -/* Control touchpad's Reduced Reporting option */ -static bool reduce_report; -module_param(reduce_report, bool, 0644); -MODULE_PARM_DESC(reduce_report, "Reduced Reporting. Default = 0 (off)"); - -/* Control touchpad's No Filter option */ -static bool no_filter; -module_param(no_filter, bool, 0644); -MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)"); - -/* - * touchpad Attention line is Active Low and Open Drain, - * therefore should be connected to pulled up line - * and the irq configuration should be set to Falling Edge Trigger - */ -/* Control IRQ / Polling option */ -static bool polling_req; -module_param(polling_req, bool, 0444); -MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)"); - -/* Control Polling Rate */ -static int scan_rate = 80; -module_param(scan_rate, int, 0644); -MODULE_PARM_DESC(scan_rate, "Polling rate in times/sec. Default = 80"); - -/* The main device structure */ -struct synaptics_i2c { - struct i2c_client *client; - struct input_dev *input; - struct delayed_work dwork; - spinlock_t lock; - int no_data_count; - int no_decel_param; - int reduce_report_param; - int no_filter_param; - int scan_rate_param; - int scan_ms; -}; - -static inline void set_scan_rate(struct synaptics_i2c *touch, int scan_rate) -{ - touch->scan_ms = MSEC_PER_SEC / scan_rate; - touch->scan_rate_param = scan_rate; -} - -/* - * Driver's initial design makes no race condition possible on i2c bus, - * so there is no need in any locking. - * Keep it in mind, while playing with the code. - */ -static s32 synaptics_i2c_reg_get(struct i2c_client *client, u16 reg) -{ - int ret; - - ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); - if (ret == 0) - ret = i2c_smbus_read_byte_data(client, reg & 0xff); - - return ret; -} - -static s32 synaptics_i2c_reg_set(struct i2c_client *client, u16 reg, u8 val) -{ - int ret; - - ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); - if (ret == 0) - ret = i2c_smbus_write_byte_data(client, reg & 0xff, val); - - return ret; -} - -static s32 synaptics_i2c_word_get(struct i2c_client *client, u16 reg) -{ - int ret; - - ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); - if (ret == 0) - ret = i2c_smbus_read_word_data(client, reg & 0xff); - - return ret; -} - -static int synaptics_i2c_config(struct i2c_client *client) -{ - int ret, control; - u8 int_en; - - /* set Report Rate to Device Highest (>=80) and Sleep to normal */ - ret = synaptics_i2c_reg_set(client, DEV_CONTROL_REG, 0xc1); - if (ret) - return ret; - - /* set Interrupt Disable to Func20 / Enable to Func10) */ - int_en = (polling_req) ? 0 : INT_ENA_ABS_MSK | INT_ENA_REL_MSK; - ret = synaptics_i2c_reg_set(client, INTERRUPT_EN_REG, int_en); - if (ret) - return ret; - - control = synaptics_i2c_reg_get(client, GENERAL_2D_CONTROL_REG); - /* No Deceleration */ - control |= no_decel ? 1 << NO_DECELERATION : 0; - /* Reduced Reporting */ - control |= reduce_report ? 1 << REDUCE_REPORTING : 0; - /* No Filter */ - control |= no_filter ? 1 << NO_FILTER : 0; - ret = synaptics_i2c_reg_set(client, GENERAL_2D_CONTROL_REG, control); - if (ret) - return ret; - - return 0; -} - -static int synaptics_i2c_reset_config(struct i2c_client *client) -{ - int ret; - - /* Reset the Touchpad */ - ret = synaptics_i2c_reg_set(client, DEV_COMMAND_REG, RESET_COMMAND); - if (ret) { - dev_err(&client->dev, "Unable to reset device\n"); - } else { - msleep(SOFT_RESET_DELAY_MS); - ret = synaptics_i2c_config(client); - if (ret) - dev_err(&client->dev, "Unable to config device\n"); - } - - return ret; -} - -static int synaptics_i2c_check_error(struct i2c_client *client) -{ - int status, ret = 0; - - status = i2c_smbus_read_byte_data(client, DEVICE_STATUS_REG) & - (CONFIGURED_MSK | ERROR_MSK); - - if (status != CONFIGURED_MSK) - ret = synaptics_i2c_reset_config(client); - - return ret; -} - -static bool synaptics_i2c_get_input(struct synaptics_i2c *touch) -{ - struct input_dev *input = touch->input; - int xy_delta, gesture; - s32 data; - s8 x_delta, y_delta; - - /* Deal with spontanious resets and errors */ - if (synaptics_i2c_check_error(touch->client)) - return 0; - - /* Get Gesture Bit */ - data = synaptics_i2c_reg_get(touch->client, DATA_REG0); - gesture = (data >> GESTURE) & 0x1; - - /* - * Get Relative axes. we have to get them in one shot, - * so we get 2 bytes starting from REL_X_REG. - */ - xy_delta = synaptics_i2c_word_get(touch->client, REL_X_REG) & 0xffff; - - /* Separate X from Y */ - x_delta = xy_delta & 0xff; - y_delta = (xy_delta >> REGISTER_LENGTH) & 0xff; - - /* Report the button event */ - input_report_key(input, BTN_LEFT, gesture); - - /* Report the deltas */ - input_report_rel(input, REL_X, x_delta); - input_report_rel(input, REL_Y, -y_delta); - input_sync(input); - - return xy_delta || gesture; -} - -static void synaptics_i2c_reschedule_work(struct synaptics_i2c *touch, - unsigned long delay) -{ - unsigned long flags; - - spin_lock_irqsave(&touch->lock, flags); - - /* - * If work is already scheduled then subsequent schedules will not - * change the scheduled time that's why we have to cancel it first. - */ - __cancel_delayed_work(&touch->dwork); - schedule_delayed_work(&touch->dwork, delay); - - spin_unlock_irqrestore(&touch->lock, flags); -} - -static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id) -{ - struct synaptics_i2c *touch = dev_id; - - synaptics_i2c_reschedule_work(touch, 0); - - return IRQ_HANDLED; -} - -static void synaptics_i2c_check_params(struct synaptics_i2c *touch) -{ - bool reset = false; - - if (scan_rate != touch->scan_rate_param) - set_scan_rate(touch, scan_rate); - - if (no_decel != touch->no_decel_param) { - touch->no_decel_param = no_decel; - reset = true; - } - - if (no_filter != touch->no_filter_param) { - touch->no_filter_param = no_filter; - reset = true; - } - - if (reduce_report != touch->reduce_report_param) { - touch->reduce_report_param = reduce_report; - reset = true; - } - - if (reset) - synaptics_i2c_reset_config(touch->client); -} - -/* Control the Device polling rate / Work Handler sleep time */ -static unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch, - bool have_data) -{ - unsigned long delay, nodata_count_thres; - - if (polling_req) { - delay = touch->scan_ms; - if (have_data) { - touch->no_data_count = 0; - } else { - nodata_count_thres = NO_DATA_THRES / touch->scan_ms; - if (touch->no_data_count < nodata_count_thres) - touch->no_data_count++; - else - delay = NO_DATA_SLEEP_MSECS; - } - return msecs_to_jiffies(delay); - } else { - delay = msecs_to_jiffies(THREAD_IRQ_SLEEP_MSECS); - return round_jiffies_relative(delay); - } -} - -/* Work Handler */ -static void synaptics_i2c_work_handler(struct work_struct *work) -{ - bool have_data; - struct synaptics_i2c *touch = - container_of(work, struct synaptics_i2c, dwork.work); - unsigned long delay; - - synaptics_i2c_check_params(touch); - - have_data = synaptics_i2c_get_input(touch); - delay = synaptics_i2c_adjust_delay(touch, have_data); - - /* - * While interrupt driven, there is no real need to poll the device. - * But touchpads are very sensitive, so there could be errors - * related to physical environment and the attention line isn't - * necessarily asserted. In such case we can lose the touchpad. - * We poll the device once in THREAD_IRQ_SLEEP_SECS and - * if error is detected, we try to reset and reconfigure the touchpad. - */ - synaptics_i2c_reschedule_work(touch, delay); -} - -static int synaptics_i2c_open(struct input_dev *input) -{ - struct synaptics_i2c *touch = input_get_drvdata(input); - int ret; - - ret = synaptics_i2c_reset_config(touch->client); - if (ret) - return ret; - - if (polling_req) - synaptics_i2c_reschedule_work(touch, - msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); - - return 0; -} - -static void synaptics_i2c_close(struct input_dev *input) -{ - struct synaptics_i2c *touch = input_get_drvdata(input); - - if (!polling_req) - synaptics_i2c_reg_set(touch->client, INTERRUPT_EN_REG, 0); - - cancel_delayed_work_sync(&touch->dwork); - - /* Save some power */ - synaptics_i2c_reg_set(touch->client, DEV_CONTROL_REG, DEEP_SLEEP); -} - -static void synaptics_i2c_set_input_params(struct synaptics_i2c *touch) -{ - struct input_dev *input = touch->input; - - input->name = touch->client->name; - input->phys = touch->client->adapter->name; - input->id.bustype = BUS_I2C; - input->id.version = synaptics_i2c_word_get(touch->client, - INFO_QUERY_REG0); - input->dev.parent = &touch->client->dev; - input->open = synaptics_i2c_open; - input->close = synaptics_i2c_close; - input_set_drvdata(input, touch); - - /* Register the device as mouse */ - __set_bit(EV_REL, input->evbit); - __set_bit(REL_X, input->relbit); - __set_bit(REL_Y, input->relbit); - - /* Register device's buttons and keys */ - __set_bit(EV_KEY, input->evbit); - __set_bit(BTN_LEFT, input->keybit); -} - -static struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client) -{ - struct synaptics_i2c *touch; - - touch = kzalloc(sizeof(struct synaptics_i2c), GFP_KERNEL); - if (!touch) - return NULL; - - touch->client = client; - touch->no_decel_param = no_decel; - touch->scan_rate_param = scan_rate; - set_scan_rate(touch, scan_rate); - INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler); - spin_lock_init(&touch->lock); - - return touch; -} - -static int __devinit synaptics_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - int ret; - struct synaptics_i2c *touch; - - touch = synaptics_i2c_touch_create(client); - if (!touch) - return -ENOMEM; - - ret = synaptics_i2c_reset_config(client); - if (ret) - goto err_mem_free; - - if (client->irq < 1) - polling_req = true; - - touch->input = input_allocate_device(); - if (!touch->input) { - ret = -ENOMEM; - goto err_mem_free; - } - - synaptics_i2c_set_input_params(touch); - - if (!polling_req) { - dev_dbg(&touch->client->dev, - "Requesting IRQ: %d\n", touch->client->irq); - - ret = request_irq(touch->client->irq, synaptics_i2c_irq, - IRQ_TYPE_EDGE_FALLING, - DRIVER_NAME, touch); - if (ret) { - dev_warn(&touch->client->dev, - "IRQ request failed: %d, " - "falling back to polling\n", ret); - polling_req = true; - synaptics_i2c_reg_set(touch->client, - INTERRUPT_EN_REG, 0); - } - } - - if (polling_req) - dev_dbg(&touch->client->dev, - "Using polling at rate: %d times/sec\n", scan_rate); - - /* Register the device in input subsystem */ - ret = input_register_device(touch->input); - if (ret) { - dev_err(&client->dev, - "Input device register failed: %d\n", ret); - goto err_input_free; - } - - i2c_set_clientdata(client, touch); - - return 0; - -err_input_free: - input_free_device(touch->input); -err_mem_free: - kfree(touch); - - return ret; -} - -static int __devexit synaptics_i2c_remove(struct i2c_client *client) -{ - struct synaptics_i2c *touch = i2c_get_clientdata(client); - - if (!polling_req) - free_irq(client->irq, touch); - - input_unregister_device(touch->input); - kfree(touch); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int synaptics_i2c_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct synaptics_i2c *touch = i2c_get_clientdata(client); - - cancel_delayed_work_sync(&touch->dwork); - - /* Save some power */ - synaptics_i2c_reg_set(touch->client, DEV_CONTROL_REG, DEEP_SLEEP); - - return 0; -} - -static int synaptics_i2c_resume(struct device *dev) -{ - int ret; - struct i2c_client *client = to_i2c_client(dev); - struct synaptics_i2c *touch = i2c_get_clientdata(client); - - ret = synaptics_i2c_reset_config(client); - if (ret) - return ret; - - synaptics_i2c_reschedule_work(touch, - msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend, - synaptics_i2c_resume); - -static const struct i2c_device_id synaptics_i2c_id_table[] = { - { "synaptics_i2c", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table); - -static struct i2c_driver synaptics_i2c_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .pm = &synaptics_i2c_pm, - }, - - .probe = synaptics_i2c_probe, - .remove = __devexit_p(synaptics_i2c_remove), - - .id_table = synaptics_i2c_id_table, -}; - -module_i2c_driver(synaptics_i2c_driver); - -MODULE_DESCRIPTION("Synaptics I2C touchpad driver"); -MODULE_AUTHOR("Mike Rapoport, Igor Grinberg, Compulab"); -MODULE_LICENSE("GPL"); - |