Skip to content

Commit

Permalink
Input: atmel_mxt_ts - make wait-after-reset period compatible with al…
Browse files Browse the repository at this point in the history
…l chips

The delay before the chip can be accessed after reset varies between
different chips in maXTouch family. Waiting for an interrupt and a T6
status message with the RESET bit set is a better behaviour.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
Acked-by: Yufeng Shen <miletus@chromium.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
Iiro Valkonen authored and Dmitry Torokhov committed May 19, 2014
1 parent a0434b7 commit a4a2ef4
Showing 1 changed file with 87 additions and 22 deletions.
109 changes: 87 additions & 22 deletions drivers/input/touchscreen/atmel_mxt_ts.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@
#define MXT_COMMAND_REPORTALL 3
#define MXT_COMMAND_DIAGNOSTIC 5

/* Define for T6 status byte */
#define MXT_T6_STATUS_RESET (1 << 7)

/* MXT_GEN_POWER_T7 field */
#define MXT_POWER_IDLEACQINT 0
#define MXT_POWER_ACTVACQINT 1
Expand Down Expand Up @@ -178,9 +181,13 @@

/* Define for MXT_GEN_COMMAND_T6 */
#define MXT_BOOT_VALUE 0xa5
#define MXT_RESET_VALUE 0x01
#define MXT_BACKUP_VALUE 0x55

/* Delay times */
#define MXT_BACKUP_TIME 50 /* msec */
#define MXT_RESET_TIME 200 /* msec */
#define MXT_RESET_TIMEOUT 3000 /* msec */
#define MXT_FW_RESET_TIME 3000 /* msec */
#define MXT_FW_CHG_TIMEOUT 300 /* msec */

Expand Down Expand Up @@ -255,12 +262,16 @@ struct mxt_data {

/* Cached parameters from object table */
u8 T6_reportid;
u16 T6_address;
u8 T9_reportid_min;
u8 T9_reportid_max;
u8 T19_reportid;

/* for fw update in bootloader */
struct completion bl_completion;

/* for reset handling */
struct completion reset_completion;
};

static size_t mxt_obj_size(const struct mxt_object *obj)
Expand Down Expand Up @@ -344,10 +355,11 @@ static void mxt_dump_message(struct device *dev,
message->reportid, 7, message->message);
}

static int mxt_wait_for_chg(struct mxt_data *data, unsigned int timeout_ms)
static int mxt_wait_for_completion(struct mxt_data *data,
struct completion *comp,
unsigned int timeout_ms)
{
struct device *dev = &data->client->dev;
struct completion *comp = &data->bl_completion;
unsigned long timeout = msecs_to_jiffies(timeout_ms);
long ret;

Expand Down Expand Up @@ -375,7 +387,8 @@ static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)
* CHG assertion before reading the status byte.
* Once the status byte has been read, the line is deasserted.
*/
ret = mxt_wait_for_chg(data, MXT_FW_CHG_TIMEOUT);
ret = mxt_wait_for_completion(data, &data->bl_completion,
MXT_FW_CHG_TIMEOUT);
if (ret) {
/*
* TODO: handle -ERESTARTSYS better by terminating
Expand Down Expand Up @@ -654,6 +667,9 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
unsigned csum = mxt_extract_T6_csum(&payload[1]);
dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
status, csum);

if (status & MXT_T6_STATUS_RESET)
complete(&data->reset_completion);
} else if (mxt_is_T9_message(data, &message)) {
int id = reportid - data->T9_reportid_min;
mxt_input_touchevent(data, &message, id);
Expand Down Expand Up @@ -687,6 +703,59 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
return mxt_process_messages_until_invalid(data);
}

static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset,
u8 value, bool wait)
{
u16 reg;
u8 command_register;
int timeout_counter = 0;
int ret;

reg = data->T6_address + cmd_offset;

ret = mxt_write_reg(data->client, reg, value);
if (ret)
return ret;

if (!wait)
return 0;

do {
msleep(20);
ret = __mxt_read_reg(data->client, reg, 1, &command_register);
if (ret)
return ret;
} while (command_register != 0 && timeout_counter++ <= 100);

if (timeout_counter > 100) {
dev_err(&data->client->dev, "Command failed!\n");
return -EIO;
}

return 0;
}

static int mxt_soft_reset(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
int ret = 0;

dev_info(dev, "Resetting chip\n");

reinit_completion(&data->reset_completion);

ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_RESET_VALUE, false);
if (ret)
return ret;

ret = mxt_wait_for_completion(data, &data->reset_completion,
MXT_RESET_TIMEOUT);
if (ret)
return ret;

return 0;
}

static int mxt_check_reg_init(struct mxt_data *data)
{
const struct mxt_platform_data *pdata = data->pdata;
Expand Down Expand Up @@ -800,6 +869,7 @@ static int mxt_get_object_table(struct mxt_data *data)
switch (object->type) {
case MXT_GEN_COMMAND_T6:
data->T6_reportid = min_id;
data->T6_address = object->start_address;
break;
case MXT_TOUCH_MULTI_T9:
data->T9_reportid_min = min_id;
Expand Down Expand Up @@ -853,16 +923,10 @@ static int mxt_initialize(struct mxt_data *data)
if (error)
goto err_free_object_table;

/* Backup to memory */
mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_BACKUPNV,
MXT_BACKUP_VALUE);
msleep(MXT_BACKUP_TIME);

/* Soft reset */
mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_RESET, 1);
msleep(MXT_RESET_TIME);
error = mxt_t6_command(data, MXT_COMMAND_BACKUPNV,
MXT_BACKUP_VALUE, false);
if (!error)
mxt_soft_reset(data);

/* Update matrix size at info struct */
error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
Expand Down Expand Up @@ -1004,8 +1068,10 @@ static int mxt_load_fw(struct device *dev, const char *fn)
/* Change to the bootloader mode */
data->in_bootloader = true;

mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_RESET, MXT_BOOT_VALUE);
ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_BOOT_VALUE, false);
if (ret)
goto release_firmware;

msleep(MXT_RESET_TIME);

/* Change to slave address of bootloader */
Expand Down Expand Up @@ -1048,7 +1114,8 @@ static int mxt_load_fw(struct device *dev, const char *fn)
}

/* Wait for flash. */
ret = mxt_wait_for_chg(data, MXT_FW_RESET_TIME);
ret = mxt_wait_for_completion(data, &data->bl_completion,
MXT_FW_RESET_TIME);
if (ret)
goto disable_irq;

Expand All @@ -1057,12 +1124,13 @@ static int mxt_load_fw(struct device *dev, const char *fn)
* the CHG line after bootloading has finished, so ignore potential
* errors.
*/
mxt_wait_for_chg(data, MXT_FW_RESET_TIME);
mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME);

data->in_bootloader = false;

disable_irq:
disable_irq(data->irq);
release_firmware:
release_firmware(fw);

/* Change to slave address of application */
Expand Down Expand Up @@ -1187,6 +1255,7 @@ static int mxt_probe(struct i2c_client *client,
data->irq = client->irq;

init_completion(&data->bl_completion);
init_completion(&data->reset_completion);

mxt_calc_resolution(data);

Expand Down Expand Up @@ -1314,11 +1383,7 @@ static int mxt_resume(struct device *dev)
struct mxt_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;

/* Soft reset */
mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_RESET, 1);

msleep(MXT_RESET_TIME);
mxt_soft_reset(data);

mutex_lock(&input_dev->mutex);

Expand Down

0 comments on commit a4a2ef4

Please sign in to comment.