Skip to content

Commit

Permalink
Input: atmel_mxt_ts - wait for CHG assert in mxt_check_bootloader
Browse files Browse the repository at this point in the history
The driver should not immediately read bootloader status when in
Application Update Mode. The CHG line will assert when the device has made
a state transition and is ready to report a new status via i2c.

This change adds a wait for completion in mxt_check_bootloader, and changes
the mxt_interrupt handler to signal the completion.

Signed-off-by: Benson Leung <bleung@chromium.org>
Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Yufeng Shen <miletus@chromium.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
Benson Leung authored and Dmitry Torokhov committed May 19, 2014
1 parent 82c2c0d commit d79e7e4
Showing 1 changed file with 81 additions and 21 deletions.
102 changes: 81 additions & 21 deletions drivers/input/touchscreen/atmel_mxt_ts.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
Expand Down Expand Up @@ -246,16 +248,19 @@ struct mxt_data {
const struct mxt_platform_data *pdata;
struct mxt_object *object_table;
struct mxt_info info;

unsigned int irq;
unsigned int max_x;
unsigned int max_y;
bool in_bootloader;

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

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

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

static int mxt_check_bootloader(struct i2c_client *client,
unsigned int state)
static int mxt_wait_for_chg(struct mxt_data *data, 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;

ret = wait_for_completion_interruptible_timeout(comp, timeout);
if (ret < 0) {
return ret;
} else if (ret == 0) {
dev_err(dev, "Wait for completion timed out.\n");
return -ETIMEDOUT;
}
return 0;
}

static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)
{
struct i2c_client *client = data->client;
u8 val;
int ret;

recheck:
if (state != MXT_WAITING_BOOTLOAD_CMD) {
/*
* In application update mode, the interrupt
* line signals state transitions. We must wait for the
* CHG assertion before reading the status byte.
* Once the status byte has been read, the line is deasserted.
*/
ret = mxt_wait_for_chg(data, 300);
if (ret) {
/*
* TODO: handle -ERESTARTSYS better by terminating
* fw update process before returning to userspace
* by writing length 0x000 to device (iff we are in
* WAITING_FRAME_DATA state).
*/
dev_err(&client->dev, "Update wait error %d\n", ret);
return ret;
}
}

if (i2c_master_recv(client, &val, 1) != 1) {
dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
return -EIO;
Expand Down Expand Up @@ -590,9 +633,8 @@ static bool mxt_is_T9_message(struct mxt_data *data, struct mxt_message *msg)
return (id >= data->T9_reportid_min && id <= data->T9_reportid_max);
}

static irqreturn_t mxt_interrupt(int irq, void *dev_id)
static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
{
struct mxt_data *data = dev_id;
struct mxt_message message;
const u8 *payload = &message.message[0];
struct device *dev = &data->client->dev;
Expand Down Expand Up @@ -632,6 +674,19 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}

static irqreturn_t mxt_interrupt(int irq, void *dev_id)
{
struct mxt_data *data = dev_id;

if (data->in_bootloader) {
/* bootloader state transition completion */
complete(&data->bl_completion);
return IRQ_HANDLED;
}

return mxt_process_messages_until_invalid(data);
}

static int mxt_check_reg_init(struct mxt_data *data)
{
const struct mxt_platform_data *pdata = data->pdata;
Expand Down Expand Up @@ -947,6 +1002,8 @@ 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);
msleep(MXT_RESET_TIME);
Expand All @@ -957,18 +1014,19 @@ static int mxt_load_fw(struct device *dev, const char *fn)
else
client->addr = MXT_BOOT_HIGH;

ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
reinit_completion(&data->bl_completion);

ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
if (ret)
goto out;
goto disable_irq;

/* Unlock bootloader */
mxt_unlock_bootloader(client);

while (pos < fw->size) {
ret = mxt_check_bootloader(client,
MXT_WAITING_FRAME_DATA);
ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
if (ret)
goto out;
goto disable_irq;

frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));

Expand All @@ -980,17 +1038,19 @@ static int mxt_load_fw(struct device *dev, const char *fn)
/* Write one frame to device */
mxt_fw_write(client, fw->data + pos, frame_size);

ret = mxt_check_bootloader(client,
MXT_FRAME_CRC_PASS);
ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
if (ret)
goto out;
goto disable_irq;

pos += frame_size;

dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
}

out:
data->in_bootloader = false;

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

/* Change to slave address of application */
Expand All @@ -1009,8 +1069,6 @@ static ssize_t mxt_update_fw_store(struct device *dev,
struct mxt_data *data = dev_get_drvdata(dev);
int error;

disable_irq(data->irq);

error = mxt_load_fw(dev, MXT_FW_NAME);
if (error) {
dev_err(dev, "The firmware update failed(%d)\n", error);
Expand All @@ -1024,13 +1082,13 @@ static ssize_t mxt_update_fw_store(struct device *dev,
mxt_free_object_table(data);

mxt_initialize(data);
}

enable_irq(data->irq);
enable_irq(data->irq);

error = mxt_make_highchg(data);
if (error)
return error;
error = mxt_make_highchg(data);
if (error)
return error;
}

return count;
}
Expand Down Expand Up @@ -1120,6 +1178,8 @@ static int mxt_probe(struct i2c_client *client,
data->pdata = pdata;
data->irq = client->irq;

init_completion(&data->bl_completion);

mxt_calc_resolution(data);

error = mxt_initialize(data);
Expand Down

0 comments on commit d79e7e4

Please sign in to comment.