[PATCH 07/10] Input: atmel_mxt_ts - refactor bootloader entry/exit

From: Daniel Kurtz
Date: Fri Feb 01 2013 - 03:14:04 EST


From: Benson Leung <bleung@xxxxxxxxxxxx>

Refactor bootloading into a three parts:
1) bl enter that only happens when device is not yet in bl.
bl enter frees old driver state and switches to BL i2c addr.
2) the actual fw_update
3) bl exit that only happens if fw update is successful.
bl exit switches to APP i2c addr and reloads object table and creates
a new input device.

Signed-off-by: Benson Leung <bleung@xxxxxxxxxxxx>
Signed-off-by: Daniel Kurtz <djkurtz@xxxxxxxxxxxx>
Signed-off-by: Yufeng Shen <miletus@xxxxxxxxxxxx>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 128 +++++++++++++++++++++----------
1 file changed, 87 insertions(+), 41 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c74f5a5..be96be3 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -253,6 +253,11 @@ struct mxt_data {
u8 T9_reportid_max;
};

+static void mxt_free_object_table(struct mxt_data *data);
+static int mxt_initialize(struct mxt_data *data);
+static int mxt_input_dev_create(struct mxt_data *data);
+static int mxt_make_highchg(struct mxt_data *data);
+
static bool mxt_object_readable(unsigned int type)
{
switch (type) {
@@ -402,6 +407,8 @@ recheck:

if (val != state) {
dev_err(&client->dev, "Unvalid bootloader mode state\n");
+ dev_err(&client->dev, "Invalid bootloader mode state %d, %d\n",
+ val, state);
return -EINVAL;
}

@@ -581,6 +588,81 @@ 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 int mxt_enter_bl(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ int ret;
+
+ if (mxt_in_bootloader(data))
+ return 0;
+
+ disable_irq(data->irq);
+
+ /* Change to the bootloader mode */
+ ret = mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_RESET, MXT_BOOT_VALUE);
+ if (ret) {
+ enable_irq(data->irq);
+ return ret;
+ }
+
+ /* Change to slave address of bootloader */
+ if (client->addr == MXT_APP_LOW)
+ client->addr = MXT_BOOT_LOW;
+ else
+ client->addr = MXT_BOOT_HIGH;
+
+ /* Free any driver state. It will get reinitialized after fw update. */
+ mxt_free_object_table(data);
+ if (data->input_dev) {
+ input_unregister_device(data->input_dev);
+ data->input_dev = NULL;
+ }
+
+ enable_irq(data->irq);
+ msleep(MXT_RESET_TIME);
+ return 0;
+}
+
+static void mxt_exit_bl(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ struct device *dev = &client->dev;
+ int error;
+
+ if (!mxt_in_bootloader(data))
+ return;
+
+ disable_irq(data->irq);
+ /* Wait for reset */
+ msleep(MXT_FWRESET_TIME);
+
+ if (client->addr == MXT_BOOT_LOW)
+ client->addr = MXT_APP_LOW;
+ else
+ client->addr = MXT_APP_HIGH;
+
+ error = mxt_initialize(data);
+ if (error) {
+ dev_err(dev, "Failed to initialize on exit bl. error = %d\n",
+ error);
+ return;
+ }
+
+ error = mxt_input_dev_create(data);
+ if (error) {
+ dev_err(dev, "Create input dev failed after init. error = %d\n",
+ error);
+ return;
+ }
+
+ error = mxt_make_highchg(data);
+ if (error)
+ dev_err(dev, "Failed to clear CHG after init. error = %d\n",
+ error);
+ enable_irq(data->irq);
+}
+
static irqreturn_t mxt_interrupt(int irq, void *dev_id)
{
struct mxt_data *data = dev_id;
@@ -984,28 +1066,10 @@ static int mxt_load_fw(struct device *dev, const char *fn)
return ret;
}

- if (mxt_in_bootloader(data))
- goto bootloader_ready;
-
- /* Change to the bootloader mode */
- ret = mxt_write_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_RESET, MXT_BOOT_VALUE);
- if (ret)
+ ret = mxt_enter_bl(data);
+ if (ret) {
+ dev_err(dev, "Failed to reset to bootloader.\n");
goto out;
- msleep(MXT_RESET_TIME);
-
- /* Change to slave address of bootloader */
- if (client->addr == MXT_APP_LOW)
- client->addr = MXT_BOOT_LOW;
- else
- client->addr = MXT_BOOT_HIGH;
-
-bootloader_ready:
- /* Free any driver state. It will get reinitialized after fw update. */
- mxt_free_object_table(data);
- if (data->input_dev) {
- input_unregister_device(data->input_dev);
- data->input_dev = NULL;
}

ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
@@ -1045,11 +1109,8 @@ bootloader_ready:
dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
}

- /* Change to slave address of application */
- if (client->addr == MXT_BOOT_LOW)
- client->addr = MXT_APP_LOW;
- else
- client->addr = MXT_APP_HIGH;
+ /* Device exits bl mode to app mode only if successful */
+ mxt_exit_bl(data);
out:
release_firmware(fw);

@@ -1060,31 +1121,16 @@ static ssize_t mxt_update_fw_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- 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);
count = error;
} else {
dev_dbg(dev, "The firmware update succeeded\n");
-
- /* Wait for reset */
- msleep(MXT_FWRESET_TIME);
-
- mxt_initialize(data);
- mxt_input_dev_create(data);
}

- enable_irq(data->irq);
-
- error = mxt_make_highchg(data);
- if (error)
- return error;
-
return count;
}

--
1.8.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/