diff options
author | Robert Collins <rcollins@nvidia.com> | 2011-06-06 14:57:01 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:47:08 -0800 |
commit | 39719e13c46683a26ee9f325f7444d181be47be1 (patch) | |
tree | 518a47ae5e53e3dfe623c3b17e8e34f258815660 /drivers/input/touchscreen | |
parent | 8d4a3af40d235e6e78a9ec8b04be999d4f0d23bd (diff) |
Input: atmel_mxt_ts: Atmel customizations to touch.
Integrate changes made by Atmel. These changes are in addition to
mainline driver.
NOTE: Driver will compile as a stand-alone.
BUG 826854
Original-Change-Id: If13688d90d97b71718576f3fb756496f57a965d7
Reviewed-on: http://git-master/r/35280
Reviewed-by: Robert R Collins <rcollins@nvidia.com>
Tested-by: Robert R Collins <rcollins@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Reviewed-by: Daniel Willemsen <dwillemsen@nvidia.com>
Rebase-Id: Reb8ae14299d248c0ce69e52b26a8816d1a0ee057
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 291 |
1 files changed, 212 insertions, 79 deletions
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index f5d66859f232..bbc6c151d1d1 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2,6 +2,7 @@ * Atmel maXTouch Touchscreen driver * * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Copyright (C) 2011 Atmel Corporation * Author: Joonyoung Shim <jy0922.shim@samsung.com> * * This program is free software; you can redistribute it and/or modify it @@ -17,7 +18,7 @@ #include <linux/firmware.h> #include <linux/i2c.h> #include <linux/i2c/atmel_mxt_ts.h> -#include <linux/input/mt.h> +#include <linux/input.h> #include <linux/interrupt.h> #include <linux/slab.h> @@ -175,8 +176,9 @@ /* Define for MXT_GEN_COMMAND_T6 */ #define MXT_BOOT_VALUE 0xa5 #define MXT_BACKUP_VALUE 0x55 -#define MXT_BACKUP_TIME 25 /* msec */ -#define MXT_RESET_TIME 65 /* msec */ +#define MXT_BACKUP_TIME 200 /* msec */ +#define MXT_RESET_TIME 650 /* msec */ +#define MXT_SAFE_CYCLE_TIME 30 /* msec */ #define MXT_FWRESET_TIME 175 /* msec */ @@ -258,8 +260,15 @@ struct mxt_data { unsigned int irq; unsigned int max_x; unsigned int max_y; + u8(*read_chg) (void); + u16 msg_address; + u16 last_address; + u8 actv_cycle_time; + u8 idle_cycle_time; + struct mutex access_mutex; }; + static bool mxt_object_readable(unsigned int type) { switch (type) { @@ -402,6 +411,20 @@ static int __mxt_read_reg(struct i2c_client *client, { struct i2c_msg xfer[2]; u8 buf[2]; + struct mxt_data *data = i2c_get_clientdata(client); + + if ((data->last_address == reg) && (reg == data->msg_address)) { + mutex_lock(&data->access_mutex); + if (i2c_master_recv(client, val, len) != len) { + dev_err(&client->dev, + "%s: Failure reading maxTouch device\n", + __func__); + mutex_unlock(&data->access_mutex); + return -EIO; + } + mutex_unlock(&data->access_mutex); + return 0; + } buf[0] = reg & 0xff; buf[1] = (reg >> 8) & 0xff; @@ -418,11 +441,15 @@ static int __mxt_read_reg(struct i2c_client *client, xfer[1].len = len; xfer[1].buf = val; + mutex_lock(&data->access_mutex); if (i2c_transfer(client->adapter, xfer, 2) != 2) { dev_err(&client->dev, "%s: i2c transfer failed\n", __func__); + mutex_unlock(&data->access_mutex); return -EIO; } + mutex_unlock(&data->access_mutex); + data->last_address = reg; return 0; } @@ -434,16 +461,20 @@ static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val) static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) { u8 buf[3]; + struct mxt_data *data = i2c_get_clientdata(client); buf[0] = reg & 0xff; buf[1] = (reg >> 8) & 0xff; buf[2] = val; + mutex_lock(&data->access_mutex); if (i2c_master_send(client, buf, 3) != 3) { dev_err(&client->dev, "%s: i2c send failed\n", __func__); + mutex_unlock(&data->access_mutex); return -EIO; } - + data->last_address = reg + 1; + mutex_unlock(&data->access_mutex); return 0; } @@ -525,23 +556,21 @@ static void mxt_input_report(struct mxt_data *data, int single_id) if (!finger[id].status) continue; - input_mt_slot(input_dev, id); - input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, - finger[id].status != MXT_RELEASE); - - if (finger[id].status != MXT_RELEASE) { - finger_num++; - input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, - finger[id].area); - input_report_abs(input_dev, ABS_MT_POSITION_X, - finger[id].x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, - finger[id].y); - input_report_abs(input_dev, ABS_MT_PRESSURE, - finger[id].pressure); - } else { + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, + finger[id].status != MXT_RELEASE ? + finger[id].area : 0); + input_report_abs(input_dev, ABS_MT_POSITION_X, + finger[id].x); + input_report_abs(input_dev, ABS_MT_POSITION_Y, + finger[id].y); + input_report_abs(input_dev, ABS_MT_PRESSURE, + finger[id].pressure); + input_mt_sync(input_dev); + + if (finger[id].status == MXT_RELEASE) finger[id].status = 0; - } + else + finger_num++; } input_report_key(input_dev, BTN_TOUCH, finger_num > 0); @@ -622,7 +651,6 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) dev_err(dev, "Failed to read message\n"); goto end; } - reportid = message.reportid; /* whether reportid is thing of MXT_TOUCH_MULTI_T9 */ @@ -648,27 +676,68 @@ static int mxt_check_reg_init(struct mxt_data *data) { const struct mxt_platform_data *pdata = data->pdata; struct mxt_object *object; + struct mxt_message message; struct device *dev = &data->client->dev; int index = 0; int i, j, config_offset; + int error; + unsigned long current_crc; if (!pdata->config) { dev_dbg(dev, "No cfg data defined, skipping reg init\n"); return 0; } + /* Try to read the config checksum of the existing cfg */ + mxt_write_object(data, MXT_GEN_COMMAND_T6, + MXT_COMMAND_CALIBRATE, 1); + msleep(30); + + error = mxt_read_message(data, &message); + if (error) + return error; + + object = mxt_get_object(data, MXT_GEN_COMMAND_T6); + if (!object) + return -EIO; + + /* Check if this message is from command processor (which has + only one reporting ID), if so, bytes 1-3 are the checksum. */ + if (message.reportid == object->max_reportid) { + current_crc = message.message[1] | (message.message[2] << 8) | + (message.message[3] << 16); + } else { + dev_info(dev, "Couldn't retrieve the current cfg checksum, " + "forcing load\n"); + current_crc = 0xFFFFFFFF; + } + dev_info(dev, + "Config CRC read from the mXT: %X\n", + (unsigned int) current_crc); + + if (current_crc == pdata->config_crc) { + dev_info(dev, + "Matching CRC's, skipping CFG load.\n"); + return 0; + } else { + dev_info(dev, "Doesn't match platform data config CRC (%X), " + "writing config from platform data...\n", + (unsigned int) pdata->config_crc); + } + for (i = 0; i < data->info.object_num; i++) { object = data->object_table + i; if (!mxt_object_writable(object->type)) continue; - + dev_info(dev, "Writing object type %d, config offset %d", data->object_table[i].type, index); for (j = 0; j < (object->size + 1) * (object->instances + 1); j++) { config_offset = index + j; if (config_offset > pdata->config_length) { dev_err(dev, "Not enough config data!\n"); + dev_err(dev, "config base is %d, offset is %d\n", index, config_offset); return -EINVAL; } mxt_write_object(data, object->type, j, @@ -676,7 +745,7 @@ static int mxt_check_reg_init(struct mxt_data *data) } index += (object->size + 1) * (object->instances + 1); } - + dev_info(dev, "Config written!"); return 0; } @@ -705,49 +774,10 @@ static int mxt_make_highchg(struct mxt_data *data) static void mxt_handle_pdata(struct mxt_data *data) { const struct mxt_platform_data *pdata = data->pdata; - u8 voltage; - - /* Set touchscreen lines */ - mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_XSIZE, - pdata->x_line); - mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_YSIZE, - pdata->y_line); - - /* Set touchscreen orient */ - mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_ORIENT, - pdata->orient); - - /* Set touchscreen burst length */ - mxt_write_object(data, MXT_TOUCH_MULTI_T9, - MXT_TOUCH_BLEN, pdata->blen); - - /* Set touchscreen threshold */ - mxt_write_object(data, MXT_TOUCH_MULTI_T9, - MXT_TOUCH_TCHTHR, pdata->threshold); - - /* Set touchscreen resolution */ - mxt_write_object(data, MXT_TOUCH_MULTI_T9, - MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); - mxt_write_object(data, MXT_TOUCH_MULTI_T9, - MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); - mxt_write_object(data, MXT_TOUCH_MULTI_T9, - MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); - mxt_write_object(data, MXT_TOUCH_MULTI_T9, - MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); - - /* Set touchscreen voltage */ - if (pdata->voltage) { - if (pdata->voltage < MXT_VOLTAGE_DEFAULT) { - voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) / - MXT_VOLTAGE_STEP; - voltage = 0xff - voltage + 1; - } else - voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) / - MXT_VOLTAGE_STEP; - - mxt_write_object(data, MXT_SPT_CTECONFIG_T28, - MXT_CTE_VOLTAGE, voltage); - } + + if (pdata->read_chg != NULL) + data->read_chg = pdata->read_chg; + } static int mxt_get_info(struct mxt_data *data) @@ -812,6 +842,12 @@ static int mxt_get_object_table(struct mxt_data *data) (object->instances + 1); object->max_reportid = reportid; } + + /* Store message window address so we don't have to + search the object table every time we read message */ + if (object->type == MXT_GEN_MESSAGE_T5) + data->msg_address = object->start_address; + } return 0; @@ -823,6 +859,8 @@ static int mxt_initialize(struct mxt_data *data) struct mxt_info *info = &data->info; int error; u8 val; + u8 idle_cycle_time; + u8 actv_cycle_time; error = mxt_get_info(data); if (error) @@ -841,23 +879,74 @@ static int mxt_initialize(struct mxt_data *data) if (error) return error; - /* Check register init values */ + /* Load initial touch chip configuration */ error = mxt_check_reg_init(data); if (error) return error; mxt_handle_pdata(data); + /* Read current cycle times */ + error = mxt_read_object(data, MXT_GEN_POWER_T7, MXT_POWER_IDLEACQINT, + &idle_cycle_time); + if (error) + return error; + error = mxt_read_object(data, MXT_GEN_POWER_T7, MXT_POWER_ACTVACQINT, + &actv_cycle_time); + if (error) + return error; + + error = mxt_make_highchg(data); + if (error) + return error; + /* Backup to memory */ mxt_write_object(data, MXT_GEN_COMMAND_T6, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); - msleep(MXT_BACKUP_TIME); + + if (data->pdata->read_chg == NULL) { + msleep(MXT_BACKUP_TIME + + (actv_cycle_time > idle_cycle_time) ? + actv_cycle_time : idle_cycle_time); + } else { + msleep(MXT_SAFE_CYCLE_TIME); + while (data->pdata->read_chg()) { + dev_info(&client->dev, + "Waiting for backup to complete...\n"); + msleep(2); + } + } + + /* Clear the interrupt line */ + error = mxt_make_highchg(data); + if (error) + return error; /* Soft reset */ mxt_write_object(data, MXT_GEN_COMMAND_T6, MXT_COMMAND_RESET, 1); - msleep(MXT_RESET_TIME); + if (data->pdata->read_chg == NULL) { + msleep(MXT_RESET_TIME + MXT_SAFE_CYCLE_TIME); + } else { + msleep(MXT_SAFE_CYCLE_TIME); + while (data->pdata->read_chg()) { + dev_info(&client->dev, + "Waiting for reset to complete...\n"); + msleep(2); + } + } + + /* Restore the cycle time settings */ + error = mxt_write_object(data, MXT_GEN_POWER_T7, + MXT_POWER_IDLEACQINT, idle_cycle_time); + if (error) + return error; + + error = mxt_write_object(data, MXT_GEN_POWER_T7, + MXT_POWER_ACTVACQINT, actv_cycle_time); + if (error) + return error; /* Update matrix size at info struct */ error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val); @@ -1055,24 +1144,67 @@ static const struct attribute_group mxt_attr_group = { static void mxt_start(struct mxt_data *data) { - /* Touch enable */ - mxt_write_object(data, - MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0x83); + int error; + + printk(KERN_WARNING "in MXT_START(), idle time: %d %d", data->idle_cycle_time, data->actv_cycle_time); + /* Restore the cycle time settings to wake from sleep */ + error = mxt_write_object(data, MXT_GEN_POWER_T7, MXT_POWER_ACTVACQINT, + data->actv_cycle_time); + if (error) + printk("\n\nresume failed!"); + error = mxt_write_object(data, MXT_GEN_POWER_T7, MXT_POWER_IDLEACQINT, + data->idle_cycle_time); + if (error) + printk("\n\nresume failed!"); + + printk(KERN_WARNING "Restored ACTV %d, IDLE %d", data->actv_cycle_time, + data->idle_cycle_time); } static void mxt_stop(struct mxt_data *data) { - /* Touch disable */ - mxt_write_object(data, - MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0); + u8 actv_cycle_time; + u8 idle_cycle_time; + int error; + + + error = mxt_read_object(data, MXT_GEN_POWER_T7, MXT_POWER_ACTVACQINT, + &actv_cycle_time); + if (error) + goto i2c_error; + + data->actv_cycle_time = actv_cycle_time; + + error = mxt_read_object(data, MXT_GEN_POWER_T7, MXT_POWER_IDLEACQINT, + &idle_cycle_time); + if (error) + goto i2c_error; + + data->idle_cycle_time = idle_cycle_time; + + /* Set to deep sleep mode for maximum power savings */ + error = mxt_write_object(data, MXT_GEN_POWER_T7, MXT_POWER_ACTVACQINT, 0); + if (error) + goto i2c_error; + + error = mxt_write_object(data, MXT_GEN_POWER_T7, MXT_POWER_IDLEACQINT, 0); + if (error) + goto i2c_error; + + printk(KERN_WARNING "MXT Suspended, saved ACTV %d and IDLE %d", + actv_cycle_time, idle_cycle_time); + return; + +i2c_error: + printk(KERN_WARNING "MXT Suspend failed!"); + } static int mxt_input_open(struct input_dev *dev) { + /* struct mxt_data *data = input_get_drvdata(dev); - - mxt_start(data); - + */ return 0; } @@ -1128,7 +1260,6 @@ static int __devinit mxt_probe(struct i2c_client *client, 0, 255, 0, 0); /* For multi touch */ - input_mt_init_slots(input_dev, MXT_MAX_FINGER); input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MXT_MAX_AREA, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, @@ -1141,6 +1272,8 @@ static int __devinit mxt_probe(struct i2c_client *client, input_set_drvdata(input_dev, data); i2c_set_clientdata(client, data); + mutex_init(&data->access_mutex); + error = mxt_initialize(data); if (error) goto err_free_object; |