summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
authorRobert Collins <rcollins@nvidia.com>2011-06-06 14:57:01 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:47:08 -0800
commit39719e13c46683a26ee9f325f7444d181be47be1 (patch)
tree518a47ae5e53e3dfe623c3b17e8e34f258815660 /drivers/input/touchscreen
parent8d4a3af40d235e6e78a9ec8b04be999d4f0d23bd (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.c291
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;