Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+93 −45
Original line number Original line Diff line number Diff line
@@ -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 {
	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,
	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 @@ recheck:
			 * 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 @@ recheck:
	}
	}


	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 @@ recheck:
	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 @@ done:
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)
		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)


	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)
		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)
		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 @@ disable_irq:
	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;
}
}