Commit f28a842d authored by Nick Dyer's avatar Nick Dyer Committed by Dmitry Torokhov

Input: atmel_mxt_ts - add additional bootloader addresses

Move bootloaders reads/writes into separate functions. Instead of switching
client->addr, define new field bootloader_addr in mxt_data. Implement
lookup calculation for bootloader addresses.
Signed-off-by: default avatarNick Dyer <nick.dyer@itdev.co.uk>
Acked-by: default avatarBenson Leung <bleung@chromium.org>
Acked-by: default avatarYufeng Shen <miletus@chromium.org>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent c3f78043
...@@ -29,12 +29,6 @@ ...@@ -29,12 +29,6 @@
#define MXT_VER_21 21 #define MXT_VER_21 21
#define MXT_VER_22 22 #define MXT_VER_22 22
/* Slave addresses */
#define MXT_APP_LOW 0x4a
#define MXT_APP_HIGH 0x4b
#define MXT_BOOT_LOW 0x24
#define MXT_BOOT_HIGH 0x25
/* Firmware */ /* Firmware */
#define MXT_FW_NAME "maxtouch.fw" #define MXT_FW_NAME "maxtouch.fw"
...@@ -261,6 +255,7 @@ struct mxt_data { ...@@ -261,6 +255,7 @@ struct mxt_data {
unsigned int max_y; unsigned int max_y;
bool in_bootloader; bool in_bootloader;
u32 config_crc; u32 config_crc;
u8 bootloader_addr;
/* Cached parameters from object table */ /* Cached parameters from object table */
u8 T6_reportid; u8 T6_reportid;
...@@ -378,9 +373,82 @@ static int mxt_wait_for_completion(struct mxt_data *data, ...@@ -378,9 +373,82 @@ static int mxt_wait_for_completion(struct mxt_data *data,
return 0; return 0;
} }
static int mxt_bootloader_read(struct mxt_data *data,
u8 *val, unsigned int count)
{
int ret;
struct i2c_msg msg;
msg.addr = data->bootloader_addr;
msg.flags = data->client->flags & I2C_M_TEN;
msg.flags |= I2C_M_RD;
msg.len = count;
msg.buf = val;
ret = i2c_transfer(data->client->adapter, &msg, 1);
if (ret == 1) {
ret = 0;
} else {
ret = ret < 0 ? ret : -EIO;
dev_err(&data->client->dev, "%s: i2c recv failed (%d)\n",
__func__, ret);
}
return ret;
}
static int mxt_bootloader_write(struct mxt_data *data,
const u8 * const val, unsigned int count)
{
int ret;
struct i2c_msg msg;
msg.addr = data->bootloader_addr;
msg.flags = data->client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (u8 *)val;
ret = i2c_transfer(data->client->adapter, &msg, 1);
if (ret == 1) {
ret = 0;
} else {
ret = ret < 0 ? ret : -EIO;
dev_err(&data->client->dev, "%s: i2c send failed (%d)\n",
__func__, ret);
}
return ret;
}
static int mxt_lookup_bootloader_address(struct mxt_data *data)
{
u8 appmode = data->client->addr;
u8 bootloader;
switch (appmode) {
case 0x4a:
case 0x4b:
case 0x4c:
case 0x4d:
case 0x5a:
case 0x5b:
bootloader = appmode - 0x26;
break;
default:
dev_err(&data->client->dev,
"Appmode i2c address 0x%02x not found\n",
appmode);
return -EINVAL;
}
data->bootloader_addr = bootloader;
return 0;
}
static int mxt_check_bootloader(struct mxt_data *data, unsigned int state) static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)
{ {
struct i2c_client *client = data->client; struct device *dev = &data->client->dev;
u8 val; u8 val;
int ret; int ret;
...@@ -401,15 +469,14 @@ static int mxt_check_bootloader(struct mxt_data *data, unsigned int state) ...@@ -401,15 +469,14 @@ static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)
* by writing length 0x000 to device (iff we are in * by writing length 0x000 to device (iff we are in
* WAITING_FRAME_DATA state). * WAITING_FRAME_DATA state).
*/ */
dev_err(&client->dev, "Update wait error %d\n", ret); dev_err(dev, "Update wait error %d\n", ret);
return ret; return ret;
} }
} }
if (i2c_master_recv(client, &val, 1) != 1) { ret = mxt_bootloader_read(data, &val, 1);
dev_err(&client->dev, "%s: i2c recv failed\n", __func__); if (ret)
return -EIO; return ret;
}
switch (state) { switch (state) {
case MXT_WAITING_BOOTLOAD_CMD: case MXT_WAITING_BOOTLOAD_CMD:
...@@ -425,7 +492,7 @@ static int mxt_check_bootloader(struct mxt_data *data, unsigned int state) ...@@ -425,7 +492,7 @@ static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)
} }
if (val != state) { if (val != state) {
dev_err(&client->dev, "Invalid bootloader state %02X != %02X\n", dev_err(dev, "Invalid bootloader state %02X != %02X\n",
val, state); val, state);
return -EINVAL; return -EINVAL;
} }
...@@ -433,28 +500,17 @@ static int mxt_check_bootloader(struct mxt_data *data, unsigned int state) ...@@ -433,28 +500,17 @@ static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)
return 0; return 0;
} }
static int mxt_unlock_bootloader(struct i2c_client *client) static int mxt_unlock_bootloader(struct mxt_data *data)
{ {
int ret;
u8 buf[2]; u8 buf[2];
buf[0] = MXT_UNLOCK_CMD_LSB; buf[0] = MXT_UNLOCK_CMD_LSB;
buf[1] = MXT_UNLOCK_CMD_MSB; buf[1] = MXT_UNLOCK_CMD_MSB;
if (i2c_master_send(client, buf, 2) != 2) { ret = mxt_bootloader_write(data, buf, 2);
dev_err(&client->dev, "%s: i2c send failed\n", __func__); if (ret)
return -EIO; return ret;
}
return 0;
}
static int mxt_fw_write(struct i2c_client *client,
const u8 *data, unsigned int frame_size)
{
if (i2c_master_send(client, data, frame_size) != frame_size) {
dev_err(&client->dev, "%s: i2c send failed\n", __func__);
return -EIO;
}
return 0; return 0;
} }
...@@ -1102,7 +1158,6 @@ static ssize_t mxt_object_show(struct device *dev, ...@@ -1102,7 +1158,6 @@ static ssize_t mxt_object_show(struct device *dev,
static int mxt_load_fw(struct device *dev, const char *fn) static int mxt_load_fw(struct device *dev, const char *fn)
{ {
struct mxt_data *data = dev_get_drvdata(dev); struct mxt_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
const struct firmware *fw = NULL; const struct firmware *fw = NULL;
unsigned int frame_size; unsigned int frame_size;
unsigned int pos = 0; unsigned int pos = 0;
...@@ -1114,6 +1169,10 @@ static int mxt_load_fw(struct device *dev, const char *fn) ...@@ -1114,6 +1169,10 @@ static int mxt_load_fw(struct device *dev, const char *fn)
return ret; return ret;
} }
ret = mxt_lookup_bootloader_address(data);
if (ret)
goto release_firmware;
/* Change to the bootloader mode */ /* Change to the bootloader mode */
data->in_bootloader = true; data->in_bootloader = true;
...@@ -1123,12 +1182,6 @@ static int mxt_load_fw(struct device *dev, const char *fn) ...@@ -1123,12 +1182,6 @@ static int mxt_load_fw(struct device *dev, const char *fn)
msleep(MXT_RESET_TIME); 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;
reinit_completion(&data->bl_completion); reinit_completion(&data->bl_completion);
ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD); ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
...@@ -1136,7 +1189,7 @@ static int mxt_load_fw(struct device *dev, const char *fn) ...@@ -1136,7 +1189,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
goto disable_irq; goto disable_irq;
/* Unlock bootloader */ /* Unlock bootloader */
mxt_unlock_bootloader(client); mxt_unlock_bootloader(data);
while (pos < fw->size) { while (pos < fw->size) {
ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA); ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
...@@ -1151,7 +1204,9 @@ static int mxt_load_fw(struct device *dev, const char *fn) ...@@ -1151,7 +1204,9 @@ static int mxt_load_fw(struct device *dev, const char *fn)
frame_size += 2; frame_size += 2;
/* Write one frame to device */ /* Write one frame to device */
mxt_fw_write(client, fw->data + pos, frame_size); ret = mxt_bootloader_write(data, fw->data + pos, frame_size);
if (ret)
goto disable_irq;
ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS); ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
if (ret) if (ret)
...@@ -1181,13 +1236,6 @@ static int mxt_load_fw(struct device *dev, const char *fn) ...@@ -1181,13 +1236,6 @@ static int mxt_load_fw(struct device *dev, const char *fn)
disable_irq(data->irq); disable_irq(data->irq);
release_firmware: release_firmware:
release_firmware(fw); release_firmware(fw);
/* Change to slave address of application */
if (client->addr == MXT_BOOT_LOW)
client->addr = MXT_APP_LOW;
else
client->addr = MXT_APP_HIGH;
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment