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

Commit d898291c authored by Mohan Pallaka's avatar Mohan Pallaka Committed by Shantanu Jain
Browse files

input: ft5x06: Add support for firmware upgrade



Add sysfs entries to upgrade firmware from userspace.
Firmware upgrade is triggered when the device's firmware
version mismatches with userspace's firmware file.
Force firmware upgrade sysfs entry is added to force
the firmware upgrade even when the firmware versions
match.

Change-Id: I48189abe60b4bd9d54a1bbc4657707213d8eb166
Signed-off-by: default avatarMohan Pallaka <mpallaka@codeaurora.org>
Signed-off-by: default avatarShantanu Jain <shjain@codeaurora.org>
parent 86797e82
Loading
Loading
Loading
Loading
+536 −48
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/firmware.h>
#include <linux/input/ft5x06_ts.h>

#if defined(CONFIG_FB)
@@ -35,7 +36,7 @@
#elif defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
/* Early-suspend level */
#define FT5X06_SUSPEND_LEVEL 1
#define FT_SUSPEND_LEVEL 1
#endif

#define CFG_MAX_TOUCH_POINTS	5
@@ -56,26 +57,116 @@
#define POINT_READ_BUF	(3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS)

/* register address*/
#define FT5X06_REG_ID		0xA3
#define FT5X06_REG_PMODE	0xA5
#define FT5X06_REG_FW_VER	0xA6
#define FT5X06_REG_POINT_RATE	0x88
#define FT5X06_REG_THGROUP	0x80
#define FT_REG_DEV_MODE		0x00
#define FT_DEV_MODE_REG_CAL	0x02
#define FT_REG_ID		0xA3
#define FT_REG_PMODE		0xA5
#define FT_REG_FW_VER		0xA6
#define FT_REG_POINT_RATE	0x88
#define FT_REG_THGROUP		0x80
#define FT_REG_ECC		0xCC
#define FT_REG_RESET_FW		0x07

/* power register bits */
#define FT5X06_PMODE_ACTIVE		0x00
#define FT5X06_PMODE_MONITOR		0x01
#define FT5X06_PMODE_STANDBY		0x02
#define FT5X06_PMODE_HIBERNATE		0x03

#define FT5X06_VTG_MIN_UV	2600000
#define FT5X06_VTG_MAX_UV	3300000
#define FT5X06_I2C_VTG_MIN_UV	1800000
#define FT5X06_I2C_VTG_MAX_UV	1800000

#define FT5X06_COORDS_ARR_SIZE	4
#define FT_PMODE_ACTIVE		0x00
#define FT_PMODE_MONITOR	0x01
#define FT_PMODE_STANDBY	0x02
#define FT_PMODE_HIBERNATE	0x03
#define FT_FACTORYMODE_VALUE	0x40
#define FT_WORKMODE_VALUE	0x00
#define FT_RST_CMD_REG		0xFC
#define FT_READ_ID_REG		0x90
#define FT_ERASE_APP_REG	0x61
#define FT_ERASE_PANEL_REG	0x63
#define FT_FW_START_REG		0xBF


#define FT_VTG_MIN_UV		2600000
#define FT_VTG_MAX_UV		3300000
#define FT_I2C_VTG_MIN_UV	1800000
#define FT_I2C_VTG_MAX_UV	1800000

#define FT_COORDS_ARR_SIZE	4
#define MAX_BUTTONS		4

#define FT_8BIT_SHIFT		8
#define FT_4BIT_SHIFT		4
#define FT_FW_NAME_MAX_LEN	50

#define FT5316_ID		0x0A
#define FT5306I_ID		0x55

#define FT_UPGRADE_AA		0xAA
#define FT_UPGRADE_55		0x55

/* upgrade config of FT5606 */
#define FT5606_UPGRADE_AA_DELAY		50
#define FT5606_UPGRADE_55_DELAY		10
#define FT5606_UPGRADE_ID_1		0x79
#define FT5606_UPGRADE_ID_2		0x06
#define FT5606_UPGRADE_READID_DELAY	100
#define FT5606_UPGRADE_EARSE_DELAY	2000

/* upgrade config of FT5316 */
#define FT5316_UPGRADE_AA_DELAY		50
#define FT5316_UPGRADE_55_DELAY		30
#define FT5316_UPGRADE_ID_1		0x79
#define FT5316_UPGRADE_ID_2		0x07
#define FT5316_UPGRADE_READID_DELAY	1
#define FT5316_UPGRADE_EARSE_DELAY	1500

/* upgrade config of FT5x06(x=2,3,4) */
#define FT5X06_UPGRADE_AA_DELAY		50
#define FT5X06_UPGRADE_55_DELAY		30
#define FT5X06_UPGRADE_ID_1		0x79
#define FT5X06_UPGRADE_ID_2		0x03
#define FT5X06_UPGRADE_READID_DELAY	1
#define FT5X06_UPGRADE_EARSE_DELAY	2000

/* upgrade config of FT6208 */
#define FT6208_UPGRADE_AA_DELAY		60
#define FT6208_UPGRADE_55_DELAY		10
#define FT6208_UPGRADE_ID_1		0x79
#define FT6208_UPGRADE_ID_2		0x05
#define FT6208_UPGRADE_READID_DELAY	10
#define FT6208_UPGRADE_EARSE_DELAY	2000

#define FT_UPGRADE_INFO(x, y)	do { \
		x->delay_55 = y##_UPGRADE_55_DELAY; \
		x->delay_aa = y##_UPGRADE_AA_DELAY; \
		x->upgrade_id_1 = y##_UPGRADE_ID_1; \
		x->upgrade_id_2 = y##_UPGRADE_ID_2; \
		x->delay_readid = y##_UPGRADE_READID_DELAY; \
		x->delay_earse_flash = y##_UPGRADE_EARSE_DELAY; \
		} while (0)

#define FT_FW_MIN_SIZE		8
#define FT_FW_MAX_SIZE		32768
#define FT_FW_FILE_VER(x)	((x)->data[(x)->size - 2])
#define FT_FW_CHECK(x)		\
	(((x)->data[(x)->size - 8] ^ (x)->data[(x)->size - 6]) == 0xFF \
	&& (((x)->data[(x)->size - 7] ^ (x)->data[(x)->size - 5]) == 0xFF \
	&& (((x)->data[(x)->size - 3] ^ (x)->data[(x)->size - 4]) == 0xFF)))

#define FT_MAX_TRIES		5
#define FT_RETRY_DLY		20

#define FT_MAX_WR_BUF		10
#define FT_MAX_RD_BUF		2
#define FT_FW_PKT_LEN		128
#define FT_FW_PKT_META_LEN	6
#define FT_FW_PKT_DLY_MS	20
#define FT_FW_LAST_PKT		0x6ffa
#define FT_EARSE_DLY_MS		100

#define FT_UPGRADE_LOOP		3
#define FT_CAL_START		0x04
#define FT_CAL_FIN		0x00
#define FT_CAL_STORE		0x05
#define FT_CAL_RETRY		100
#define FT_REG_CAL		0x00
#define FT_CAL_MASK		0x70

struct ts_event {
	u16 x[CFG_MAX_TOUCH_POINTS];	/* x coordinate */
	u16 y[CFG_MAX_TOUCH_POINTS];	/* y coordinate */
@@ -86,6 +177,15 @@ struct ts_event {
	u8 touch_point;
};

struct upgrade_info {
	u16 delay_aa;		/* delay of write FT_UPGRADE_AA */
	u16 delay_55;		/* delay of write FT_UPGRADE_55 */
	u8 upgrade_id_1;	/* upgrade id 1 */
	u8 upgrade_id_2;	/* upgrade id 2 */
	u16 delay_readid;	/* delay of read id */
	u16 delay_earse_flash;	/* delay of earse flash */
};

struct ft5x06_ts_data {
	struct i2c_client *client;
	struct input_dev *input_dev;
@@ -93,6 +193,9 @@ struct ft5x06_ts_data {
	const struct ft5x06_ts_platform_data *pdata;
	struct regulator *vdd;
	struct regulator *vcc_i2c;
	char fw_name[FT_FW_NAME_MAX_LEN];
	bool loading_fw;
	u8 family_id;
#if defined(CONFIG_FB)
	struct notifier_block fb_notif;
#elif defined(CONFIG_HAS_EARLYSUSPEND)
@@ -160,6 +263,21 @@ static int ft5x06_i2c_write(struct i2c_client *client, char *writebuf,
	return ret;
}

static int ft5x0x_write_reg(struct i2c_client *client, u8 addr, const u8 val)
{
	u8 buf[2] = {0};

	buf[0] = addr;
	buf[1] = val;

	return ft5x06_i2c_write(client, buf, sizeof(buf));
}

static int ft5x0x_read_reg(struct i2c_client *client, u8 addr, u8 *val)
{
	return ft5x06_i2c_read(client, &addr, 1, val, 1);
}

static void ft5x06_report_value(struct ft5x06_ts_data *data)
{
	struct ts_event *event = &data->event;
@@ -300,8 +418,8 @@ static int ft5x06_power_init(struct ft5x06_ts_data *data, bool on)
	}

	if (regulator_count_voltages(data->vdd) > 0) {
		rc = regulator_set_voltage(data->vdd, FT5X06_VTG_MIN_UV,
					   FT5X06_VTG_MAX_UV);
		rc = regulator_set_voltage(data->vdd, FT_VTG_MIN_UV,
					   FT_VTG_MAX_UV);
		if (rc) {
			dev_err(&data->client->dev,
				"Regulator set_vtg failed vdd rc=%d\n", rc);
@@ -318,8 +436,8 @@ static int ft5x06_power_init(struct ft5x06_ts_data *data, bool on)
	}

	if (regulator_count_voltages(data->vcc_i2c) > 0) {
		rc = regulator_set_voltage(data->vcc_i2c, FT5X06_I2C_VTG_MIN_UV,
					   FT5X06_I2C_VTG_MAX_UV);
		rc = regulator_set_voltage(data->vcc_i2c, FT_I2C_VTG_MIN_UV,
					   FT_I2C_VTG_MAX_UV);
		if (rc) {
			dev_err(&data->client->dev,
			"Regulator set_vtg failed vcc_i2c rc=%d\n", rc);
@@ -333,19 +451,19 @@ reg_vcc_i2c_put:
	regulator_put(data->vcc_i2c);
reg_vdd_set_vtg:
	if (regulator_count_voltages(data->vdd) > 0)
		regulator_set_voltage(data->vdd, 0, FT5X06_VTG_MAX_UV);
		regulator_set_voltage(data->vdd, 0, FT_VTG_MAX_UV);
reg_vdd_put:
	regulator_put(data->vdd);
	return rc;

pwr_deinit:
	if (regulator_count_voltages(data->vdd) > 0)
		regulator_set_voltage(data->vdd, 0, FT5X06_VTG_MAX_UV);
		regulator_set_voltage(data->vdd, 0, FT_VTG_MAX_UV);

	regulator_put(data->vdd);

	if (regulator_count_voltages(data->vcc_i2c) > 0)
		regulator_set_voltage(data->vcc_i2c, 0, FT5X06_I2C_VTG_MAX_UV);
		regulator_set_voltage(data->vcc_i2c, 0, FT_I2C_VTG_MAX_UV);

	regulator_put(data->vcc_i2c);
	return 0;
@@ -360,8 +478,8 @@ static int ft5x06_ts_suspend(struct device *dev)
	disable_irq(data->client->irq);

	if (gpio_is_valid(data->pdata->reset_gpio)) {
		txbuf[0] = FT5X06_REG_PMODE;
		txbuf[1] = FT5X06_PMODE_HIBERNATE;
		txbuf[0] = FT_REG_PMODE;
		txbuf[1] = FT_PMODE_HIBERNATE;
		ft5x06_i2c_write(data->client, txbuf, sizeof(txbuf));
	}

@@ -430,11 +548,345 @@ static const struct dev_pm_ops ft5x06_ts_pm_ops = {
};
#endif

static int ft5x06_auto_cal(struct i2c_client *client)
{
	u8 temp = 0, i;

	/* set to factory mode */
	msleep(2 * FT_STARTUP_DLY);
	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
	msleep(FT_STARTUP_DLY);

	/* start calibration */
	ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_START);
	msleep(2 * FT_STARTUP_DLY);
	for (i = 0; i < FT_CAL_RETRY; i++) {
		ft5x0x_read_reg(client, FT_REG_CAL, &temp);
		/* return to normal mode, calibration finish */
		if (((temp & FT_CAL_MASK) >> FT_4BIT_SHIFT) == FT_CAL_FIN)
			break;
	}

	/* calibration OK */
	msleep(2 * FT_STARTUP_DLY);
	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
	msleep(FT_STARTUP_DLY);

	/* store calibration data */
	ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_STORE);
	msleep(2 * FT_STARTUP_DLY);

	/* set to normal mode */
	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_WORKMODE_VALUE);
	msleep(2 * FT_STARTUP_DLY);

	return 0;
}

static int ft5x06_get_upgrade_info(u8 family_id, struct upgrade_info *info)
{
	switch (family_id) {
	case FT5306I_ID:
		FT_UPGRADE_INFO(info, FT5X06);
		break;
	case FT5316_ID:
		FT_UPGRADE_INFO(info, FT5316);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int ft5x06_fw_upgrade_start(struct i2c_client *client,
			const u8 *data, u32 data_len)
{
	struct ft5x06_ts_data *ts_data = i2c_get_clientdata(client);
	struct upgrade_info info;
	u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0};
	u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN];
	int rc, i, j, temp;
	u32 pkt_num, pkt_len;
	u8 fw_ecc;

	rc = ft5x06_get_upgrade_info(ts_data->family_id, &info);
	if (rc < 0) {
		dev_err(&client->dev, "Cannot get upgrade information!\n");
		return -EINVAL;
	}

	for (i = 0; i < FT_UPGRADE_LOOP; i++) {
		/* reset - write 0xaa and 0x55 to register 0xfc */
		ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_AA);
		msleep(info.delay_aa);

		ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_55);
		msleep(info.delay_55);

		/* Enter upgrade mode */
		w_buf[0] = FT_UPGRADE_55;
		w_buf[1] = FT_UPGRADE_AA;
		do {
			i++;
			rc = ft5x06_i2c_write(client, w_buf, 2);
			msleep(FT_RETRY_DLY);
		} while (rc <= 0 && i < FT_MAX_TRIES);

		/* check READ_ID */
		msleep(info.delay_readid);
		w_buf[0] = FT_READ_ID_REG;
		w_buf[1] = 0x00;
		w_buf[2] = 0x00;
		w_buf[3] = 0x00;

		ft5x06_i2c_read(client, w_buf, 4, r_buf, 2);

		if (r_buf[0] != info.upgrade_id_1
			|| r_buf[1] != info.upgrade_id_2) {
			dev_err(&client->dev, "Upgrade ID mismatch(%d)\n", i);
		} else
			break;
	}

	if (i >= FT_UPGRADE_LOOP) {
		dev_err(&client->dev, "Abort upgrade\n");
		return -EIO;
	}

	/* erase app and panel paramenter area */
	w_buf[0] = FT_ERASE_APP_REG;
	ft5x06_i2c_write(client, w_buf, 1);
	msleep(info.delay_earse_flash);

	w_buf[0] = FT_ERASE_PANEL_REG;
	ft5x06_i2c_write(client, w_buf, 1);
	msleep(FT_EARSE_DLY_MS);

	/* program firmware */
	data_len = data_len - 8;
	pkt_num = (data_len) / FT_FW_PKT_LEN;
	pkt_len = FT_FW_PKT_LEN;
	pkt_buf[0] = FT_FW_START_REG;
	pkt_buf[1] = 0x00;
	fw_ecc = 0;

	for (i = 0; i < pkt_num; i++) {
		temp = i * FT_FW_PKT_LEN;
		pkt_buf[2] = (u8) (temp >> FT_8BIT_SHIFT);
		pkt_buf[3] = (u8) temp;
		pkt_buf[4] = (u8) (pkt_len >> FT_8BIT_SHIFT);
		pkt_buf[5] = (u8) pkt_len;

		for (j = 0; j < FT_FW_PKT_LEN; j++) {
			pkt_buf[6 + j] = data[i * FT_FW_PKT_LEN + j];
			fw_ecc ^= pkt_buf[6 + j];
		}

		ft5x06_i2c_write(client, pkt_buf,
				FT_FW_PKT_LEN + FT_FW_PKT_META_LEN);
		msleep(FT_FW_PKT_DLY_MS);
	}

	/* send remaining bytes */
	if ((data_len) % FT_FW_PKT_LEN > 0) {
		temp = pkt_num * FT_FW_PKT_LEN;
		pkt_buf[2] = (u8) (temp >> FT_8BIT_SHIFT);
		pkt_buf[3] = (u8) temp;
		temp = (data_len) % FT_FW_PKT_LEN;
		pkt_buf[4] = (u8) (temp >> FT_8BIT_SHIFT);
		pkt_buf[5] = (u8) temp;

		for (i = 0; i < temp; i++) {
			pkt_buf[6 + i] = data[pkt_num * FT_FW_PKT_LEN + i];
			fw_ecc ^= pkt_buf[6 + i];
		}

		ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN);
		msleep(FT_FW_PKT_DLY_MS);
	}

	/* send the finishing packet */
	for (i = 0; i < 6; i++) {
		temp = FT_FW_LAST_PKT + i;
		pkt_buf[2] = (u8) (temp >> 8);
		pkt_buf[3] = (u8) temp;
		temp = 1;
		pkt_buf[4] = (u8) (temp >> 8);
		pkt_buf[5] = (u8) temp;
		pkt_buf[6] = data[data_len + i];
		fw_ecc ^= pkt_buf[6];
		ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN);
		msleep(FT_FW_PKT_DLY_MS);
	}

	/* verify checksum */
	w_buf[0] = FT_REG_ECC;
	ft5x06_i2c_read(client, w_buf, 1, r_buf, 1);
	if (r_buf[0] != fw_ecc) {
		dev_err(&client->dev, "ECC error! dev_ecc=%02x fw_ecc=%02x\n",
					r_buf[0], fw_ecc);
		return -EIO;
	}

	/* reset */
	w_buf[0] = FT_REG_RESET_FW;
	ft5x06_i2c_write(client, w_buf, 1);
	msleep(FT_STARTUP_DLY);

	return 0;
}

static int ft5x06_fw_upgrade(struct device *dev, bool force)
{
	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
	const struct firmware *fw = NULL;
	int rc;
	u8 val = 0;

	rc = request_firmware(&fw, data->fw_name, dev);
	if (rc < 0) {
		dev_err(dev, "Request firmware failed - %s (%d)\n",
						data->fw_name, rc);
		return rc;
	}

	if (fw->size < FT_FW_MIN_SIZE || fw->size > FT_FW_MAX_SIZE) {
		dev_err(dev, "Invalid firmware size (%d)\n", fw->size);
		rc = -EIO;
		goto rel_fw;
	}

	/* check firmware version */
	rc = ft5x0x_read_reg(data->client, FT_REG_FW_VER, &val);
	if (rc < 0) {
		dev_err(dev, "Get firmware version failed\n");
		goto rel_fw;
	}

	if (val == FT_FW_FILE_VER(fw) && !force) {
		dev_err(dev, "No need to update (0x%x)\n", val);
		rc = -EFAULT;
		goto rel_fw;
	}

	dev_info(dev, "upgrade to fw ver 0x%x from 0x%x\n",
					FT_FW_FILE_VER(fw), val);

	/* start firmware upgrade */
	if (FT_FW_CHECK(fw)) {
		rc = ft5x06_fw_upgrade_start(data->client, fw->data, fw->size);
		if (rc < 0)
			dev_err(dev, "update failed (%d)\n", rc);
		else
			ft5x06_auto_cal(data->client);
	} else {
		dev_err(dev, "FW format error\n");
		rc = -EIO;
	}

rel_fw:
	release_firmware(fw);
	return rc;
}

static ssize_t ft5x06_update_fw_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct ft5x06_ts_data *data = dev_get_drvdata(dev);

	return snprintf(buf, 2, "%d\n", data->loading_fw);
}

static ssize_t ft5x06_update_fw_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t size)
{
	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
	unsigned long val;
	int rc;

	if (size > 2)
		return -EINVAL;

	rc = kstrtoul(buf, 10, &val);
	if (rc != 0)
		return rc;

	mutex_lock(&data->input_dev->mutex);
	if (!data->loading_fw  && val) {
		data->loading_fw = true;
		ft5x06_fw_upgrade(dev, false);
		data->loading_fw = false;
	}
	mutex_unlock(&data->input_dev->mutex);

	return size;
}

static DEVICE_ATTR(update_fw, 0664, ft5x06_update_fw_show,
				ft5x06_update_fw_store);

static ssize_t ft5x06_force_update_fw_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t size)
{
	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
	unsigned long val;
	int rc;

	if (size > 2)
		return -EINVAL;

	rc = kstrtoul(buf, 10, &val);
	if (rc != 0)
		return rc;

	mutex_lock(&data->input_dev->mutex);
	if (!data->loading_fw  && val) {
		data->loading_fw = true;
		ft5x06_fw_upgrade(dev, true);
		data->loading_fw = false;
	}
	mutex_unlock(&data->input_dev->mutex);

	return size;
}

static DEVICE_ATTR(force_update_fw, 0664, ft5x06_update_fw_show,
				ft5x06_force_update_fw_store);

static ssize_t ft5x06_fw_name_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct ft5x06_ts_data *data = dev_get_drvdata(dev);

	return snprintf(buf, FT_FW_NAME_MAX_LEN - 1, "%s\n", data->fw_name);
}

static ssize_t ft5x06_fw_name_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t size)
{
	struct ft5x06_ts_data *data = dev_get_drvdata(dev);

	if (size > FT_FW_NAME_MAX_LEN - 1)
		return -EINVAL;

	strlcpy(data->fw_name, buf, size);
	if (data->fw_name[size-1] == '\n')
		data->fw_name[size-1] = 0;

	return size;
}

static DEVICE_ATTR(fw_name, 0664, ft5x06_fw_name_show, ft5x06_fw_name_store);

#ifdef CONFIG_OF
static int ft5x06_get_dt_coords(struct device *dev, char *name,
				struct ft5x06_ts_platform_data *pdata)
{
	u32 coords[FT5X06_COORDS_ARR_SIZE];
	u32 coords[FT_COORDS_ARR_SIZE];
	struct property *prop;
	struct device_node *np = dev->of_node;
	int coords_size, rc;
@@ -446,7 +898,7 @@ static int ft5x06_get_dt_coords(struct device *dev, char *name,
		return -ENODATA;

	coords_size = prop->length / sizeof(u32);
	if (coords_size != FT5X06_COORDS_ARR_SIZE) {
	if (coords_size != FT_COORDS_ARR_SIZE) {
		dev_err(dev, "invalid %s\n", name);
		return -EINVAL;
	}
@@ -676,37 +1128,43 @@ static int ft5x06_ts_probe(struct i2c_client *client,
	msleep(FT_STARTUP_DLY);

	/* check the controller id */
	reg_addr = FT5X06_REG_ID;
	reg_addr = FT_REG_ID;
	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
	if (err < 0) {
		dev_err(&client->dev, "version read failed");
		return err;
	}

	dev_info(&client->dev, "Device ID = 0x%x\n", reg_value);

	if (pdata->family_id != reg_value) {
		dev_err(&client->dev, "%s:Unsupported controller\n", __func__);
		goto free_reset_gpio;
	}

	data->family_id = reg_value;

	/* get some register information */
	reg_addr = FT5X06_REG_FW_VER;
	reg_addr = FT_REG_FW_VER;
	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
	if (err)
	if (err < 0)
		dev_err(&client->dev, "version read failed");

	dev_info(&client->dev, "[FTS] Firmware version = 0x%x\n", reg_value);
	dev_info(&client->dev, "Firmware version = 0x%x\n", reg_value);

	reg_addr = FT5X06_REG_POINT_RATE;
	reg_addr = FT_REG_POINT_RATE;
	ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
	if (err)
	if (err < 0)
		dev_err(&client->dev, "report rate read failed");
	dev_info(&client->dev, "[FTS] report rate is %dHz.\n", reg_value * 10);

	reg_addr = FT5X06_REG_THGROUP;
	dev_dbg(&client->dev, "report rate = %dHz\n", reg_value * 10);

	reg_addr = FT_REG_THGROUP;
	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
	if (err)
	if (err < 0)
		dev_err(&client->dev, "threshold read failed");
	dev_dbg(&client->dev, "[FTS] touch threshold is %d.\n", reg_value * 4);

	dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);

	err = request_threaded_irq(client->irq, NULL,
				   ft5x06_ts_interrupt, pdata->irqflags,
@@ -715,6 +1173,26 @@ static int ft5x06_ts_probe(struct i2c_client *client,
		dev_err(&client->dev, "request irq failed\n");
		goto free_reset_gpio;
	}

	err = device_create_file(&client->dev, &dev_attr_fw_name);
	if (err) {
		dev_err(&client->dev, "sys file creation failed\n");
		goto irq_free;
	}

	err = device_create_file(&client->dev, &dev_attr_update_fw);
	if (err) {
		dev_err(&client->dev, "sys file creation failed\n");
		goto free_fw_name_sys;
	}

	err = device_create_file(&client->dev, &dev_attr_force_update_fw);
	if (err) {
		dev_err(&client->dev, "sys file creation failed\n");
		goto free_update_fw_sys;
	}


#if defined(CONFIG_FB)
	data->fb_notif.notifier_call = fb_notifier_callback;

@@ -725,7 +1203,7 @@ static int ft5x06_ts_probe(struct i2c_client *client,
			err);
#elif defined(CONFIG_HAS_EARLYSUSPEND)
	data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
	    FT5X06_SUSPEND_LEVEL;
						    FT_SUSPEND_LEVEL;
	data->early_suspend.suspend = ft5x06_ts_early_suspend;
	data->early_suspend.resume = ft5x06_ts_late_resume;
	register_early_suspend(&data->early_suspend);
@@ -733,12 +1211,18 @@ static int ft5x06_ts_probe(struct i2c_client *client,

	return 0;

free_update_fw_sys:
	device_remove_file(&client->dev, &dev_attr_update_fw);
free_fw_name_sys:
	device_remove_file(&client->dev, &dev_attr_fw_name);
irq_free:
	free_irq(client->irq, data);
free_reset_gpio:
	if (gpio_is_valid(pdata->reset_gpio))
		gpio_free(pdata->reset_gpio);
free_irq_gpio:
	if (gpio_is_valid(pdata->irq_gpio))
		gpio_free(pdata->reset_gpio);
		gpio_free(pdata->irq_gpio);
pwr_off:
	if (pdata->power_on)
		pdata->power_on(false);
@@ -763,6 +1247,10 @@ static int ft5x06_ts_remove(struct i2c_client *client)
{
	struct ft5x06_ts_data *data = i2c_get_clientdata(client);

	device_remove_file(&client->dev, &dev_attr_force_update_fw);
	device_remove_file(&client->dev, &dev_attr_update_fw);
	device_remove_file(&client->dev, &dev_attr_fw_name);

#if defined(CONFIG_FB)
	if (fb_unregister_client(&data->fb_notif))
		dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
@@ -775,7 +1263,7 @@ static int ft5x06_ts_remove(struct i2c_client *client)
		gpio_free(data->pdata->reset_gpio);

	if (gpio_is_valid(data->pdata->irq_gpio))
		gpio_free(data->pdata->reset_gpio);
		gpio_free(data->pdata->irq_gpio);

	if (data->pdata->power_on)
		data->pdata->power_on(false);