input: ft5x06_ts: Upgrade firmware based on version

Upgrade firmware on the controller only when a new
version of firmware is available.

This patch is propagated from msm-3.18 kernel
'commit 88d102ef081f ("input: ft5x06_ts: Upgrade
firmware based on version")'

Change-Id: I4cf75b3c5efb90f151da09ed73b1ba62b9b5bb1c
Signed-off-by: Mohan Pallaka <mpallaka@codeaurora.org>
This commit is contained in:
Mohan Pallaka 2013-08-28 13:44:36 +05:30 committed by Abinaya P
parent 72436be454
commit bf71f01cc7
3 changed files with 90 additions and 27 deletions

View file

@ -45,6 +45,8 @@ Optional properties:
- focaltech,fw-delay-readid-ms : specify the read id delay in ms for firmware upgrade - focaltech,fw-delay-readid-ms : specify the read id delay in ms for firmware upgrade
- focaltech,fw-delay-era-flsh-ms : specify the erase flash delay in ms for firmware upgrade - focaltech,fw-delay-era-flsh-ms : specify the erase flash delay in ms for firmware upgrade
- focaltech,fw-auto-cal : specify whether calibration is needed after firmware upgrade - focaltech,fw-auto-cal : specify whether calibration is needed after firmware upgrade
- focaltech,fw-vkey-support : specify if virtual keys are supported through firmware
Example: Example:
i2c@f9923000{ i2c@f9923000{
focaltech@38{ focaltech@38{

View file

@ -41,7 +41,7 @@
#define FT_SUSPEND_LEVEL 1 #define FT_SUSPEND_LEVEL 1
#endif #endif
#define FT_DRIVER_VERSION 0x01 #define FT_DRIVER_VERSION 0x02
#define FT_META_REGS 3 #define FT_META_REGS 3
#define FT_ONE_TCH_LEN 6 #define FT_ONE_TCH_LEN 6
@ -69,6 +69,9 @@
#define FT_REG_THGROUP 0x80 #define FT_REG_THGROUP 0x80
#define FT_REG_ECC 0xCC #define FT_REG_ECC 0xCC
#define FT_REG_RESET_FW 0x07 #define FT_REG_RESET_FW 0x07
#define FT_REG_FW_MAJ_VER 0xB1
#define FT_REG_FW_MIN_VER 0xB2
#define FT_REG_FW_SUB_MIN_VER 0xB3
/* power register bits */ /* power register bits */
#define FT_PMODE_ACTIVE 0x00 #define FT_PMODE_ACTIVE 0x00
@ -107,7 +110,12 @@
#define FT_FW_MIN_SIZE 8 #define FT_FW_MIN_SIZE 8
#define FT_FW_MAX_SIZE 32768 #define FT_FW_MAX_SIZE 32768
#define FT_FW_FILE_VER(x) ((x)->data[(x)->size - 2])
/* Firmware file is not supporting minor and sub minor so use 0 */
#define FT_FW_FILE_MAJ_VER(x) ((x)->data[(x)->size - 2])
#define FT_FW_FILE_MIN_VER(x) 0
#define FT_FW_FILE_SUB_MIN_VER(x) 0
#define FT_FW_CHECK(x) \ #define FT_FW_CHECK(x) \
(((x)->data[(x)->size - 8] ^ (x)->data[(x)->size - 6]) == 0xFF \ (((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 - 7] ^ (x)->data[(x)->size - 5]) == 0xFF \
@ -134,7 +142,8 @@
#define FT_INFO_MAX_LEN 512 #define FT_INFO_MAX_LEN 512
#define FT_STORE_TS_INFO(buf, id, name, max_tch, group_id, fw_name, fw_ver) \ #define FT_STORE_TS_INFO(buf, id, name, max_tch, group_id, fw_vkey_support, \
fw_name, fw_maj, fw_min, fw_sub_min) \
snprintf(buf, FT_INFO_MAX_LEN, \ snprintf(buf, FT_INFO_MAX_LEN, \
"controller\t= focaltech\n" \ "controller\t= focaltech\n" \
"model\t\t= 0x%x\n" \ "model\t\t= 0x%x\n" \
@ -142,10 +151,12 @@
"max_touches\t= %d\n" \ "max_touches\t= %d\n" \
"drv_ver\t\t= 0x%x\n" \ "drv_ver\t\t= 0x%x\n" \
"group_id\t= 0x%x\n" \ "group_id\t= 0x%x\n" \
"fw_vkey_support\t= %s\n" \
"fw_name\t\t= %s\n" \ "fw_name\t\t= %s\n" \
"fw_ver\t\t= 0x%x\n", id, name, \ "fw_ver\t\t= %d.%d.%d\n", id, name, \
max_tch, FT_DRIVER_VERSION, group_id, \ max_tch, FT_DRIVER_VERSION, group_id, \
fw_name, fw_ver) fw_vkey_support, fw_name, fw_maj, fw_min, \
fw_sub_min)
#define FT_DEBUG_DIR_NAME "ts_debug" #define FT_DEBUG_DIR_NAME "ts_debug"
@ -164,6 +175,7 @@ struct ft5x06_ts_data {
char *ts_info; char *ts_info;
u8 *tch_data; u8 *tch_data;
u32 tch_data_len; u32 tch_data_len;
u8 fw_ver[3];
#if defined(CONFIG_FB) #if defined(CONFIG_FB)
struct notifier_block fb_notif; struct notifier_block fb_notif;
#elif defined(CONFIG_HAS_EARLYSUSPEND) #elif defined(CONFIG_HAS_EARLYSUSPEND)
@ -246,6 +258,31 @@ static int ft5x0x_read_reg(struct i2c_client *client, u8 addr, u8 *val)
return ft5x06_i2c_read(client, &addr, 1, val, 1); return ft5x06_i2c_read(client, &addr, 1, val, 1);
} }
static void ft5x06_update_fw_ver(struct ft5x06_ts_data *data)
{
struct i2c_client *client = data->client;
u8 reg_addr;
int err;
reg_addr = FT_REG_FW_MAJ_VER;
err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[0], 1);
if (err < 0)
dev_err(&client->dev, "fw major version read failed");
reg_addr = FT_REG_FW_MIN_VER;
err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[1], 1);
if (err < 0)
dev_err(&client->dev, "fw minor version read failed");
reg_addr = FT_REG_FW_SUB_MIN_VER;
err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[2], 1);
if (err < 0)
dev_err(&client->dev, "fw sub minor version read failed");
dev_info(&client->dev, "Firmware version = %d.%d.%d\n",
data->fw_ver[0], data->fw_ver[1], data->fw_ver[2]);
}
static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id) static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id)
{ {
struct ft5x06_ts_data *data = dev_id; struct ft5x06_ts_data *data = dev_id;
@ -297,8 +334,10 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id)
input_report_abs(ip_dev, ABS_MT_POSITION_X, x); input_report_abs(ip_dev, ABS_MT_POSITION_X, x);
input_report_abs(ip_dev, ABS_MT_POSITION_Y, y); input_report_abs(ip_dev, ABS_MT_POSITION_Y, y);
input_report_abs(ip_dev, ABS_MT_PRESSURE, pressure); input_report_abs(ip_dev, ABS_MT_PRESSURE, pressure);
} else } else {
input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0); input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0);
input_report_abs(ip_dev, ABS_MT_PRESSURE, 0);
}
} }
if (update_input) { if (update_input) {
@ -746,7 +785,8 @@ static int ft5x06_fw_upgrade(struct device *dev, bool force)
struct ft5x06_ts_data *data = dev_get_drvdata(dev); struct ft5x06_ts_data *data = dev_get_drvdata(dev);
const struct firmware *fw = NULL; const struct firmware *fw = NULL;
int rc; int rc;
u8 val = 0; u8 fw_file_maj, fw_file_min, fw_file_sub_min;
bool fw_upgrade = false;
rc = request_firmware(&fw, data->fw_name, dev); rc = request_firmware(&fw, data->fw_name, dev);
if (rc < 0) { if (rc < 0) {
@ -761,27 +801,38 @@ static int ft5x06_fw_upgrade(struct device *dev, bool force)
goto rel_fw; goto rel_fw;
} }
/* check firmware version */ fw_file_maj = FT_FW_FILE_MAJ_VER(fw);
rc = ft5x0x_read_reg(data->client, FT_REG_FW_VER, &val); fw_file_min = FT_FW_FILE_MIN_VER(fw);
if (rc < 0) { fw_file_sub_min = FT_FW_FILE_SUB_MIN_VER(fw);
dev_err(dev, "Get firmware version failed\n");
goto rel_fw;
}
if (val == FT_FW_FILE_VER(fw) && !force) { dev_info(dev, "Current firmware: %d.%d.%d", data->fw_ver[0],
dev_err(dev, "No need to update (0x%x)\n", val); data->fw_ver[1], data->fw_ver[2]);
dev_info(dev, "New firmware: %d.%d.%d", fw_file_maj,
fw_file_min, fw_file_sub_min);
if (force) {
fw_upgrade = true;
} else if (data->fw_ver[0] == fw_file_maj) {
if (data->fw_ver[1] < fw_file_min)
fw_upgrade = true;
else if (data->fw_ver[2] < fw_file_sub_min)
fw_upgrade = true;
else
dev_info(dev, "No need to upgrade\n");
} else
dev_info(dev, "Firmware versions do not match\n");
if (!fw_upgrade) {
dev_info(dev, "Exiting fw upgrade...\n");
rc = -EFAULT; rc = -EFAULT;
goto rel_fw; 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 */ /* start firmware upgrade */
if (FT_FW_CHECK(fw)) { if (FT_FW_CHECK(fw)) {
rc = ft5x06_fw_upgrade_start(data->client, fw->data, fw->size); rc = ft5x06_fw_upgrade_start(data->client, fw->data, fw->size);
if (rc < 0) if (rc < 0)
dev_err(dev, "update failed (%d)\n", rc); dev_err(dev, "update failed (%d). try later...\n", rc);
else if (data->pdata->info.auto_cal) else if (data->pdata->info.auto_cal)
ft5x06_auto_cal(data->client); ft5x06_auto_cal(data->client);
} else { } else {
@ -789,9 +840,13 @@ static int ft5x06_fw_upgrade(struct device *dev, bool force)
rc = -EIO; rc = -EIO;
} }
ft5x06_update_fw_ver(data);
FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name, FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name,
data->pdata->num_max_touches, data->pdata->group_id, data->pdata->num_max_touches, data->pdata->group_id,
data->pdata->fw_name, FT_FW_FILE_VER(fw)); data->pdata->fw_vkey_support ? "yes" : "no",
data->pdata->fw_name, data->fw_ver[0],
data->fw_ver[1], data->fw_ver[2]);
rel_fw: rel_fw:
release_firmware(fw); release_firmware(fw);
return rc; return rc;
@ -820,6 +875,11 @@ static ssize_t ft5x06_update_fw_store(struct device *dev,
if (rc != 0) if (rc != 0)
return rc; return rc;
if (data->suspended) {
dev_info(dev, "In suspend state, try again later...\n");
return size;
}
mutex_lock(&data->input_dev->mutex); mutex_lock(&data->input_dev->mutex);
if (!data->loading_fw && val) { if (!data->loading_fw && val) {
data->loading_fw = true; data->loading_fw = true;
@ -1186,6 +1246,9 @@ static int ft5x06_parse_dt(struct device *dev,
pdata->info.auto_cal = of_property_read_bool(np, pdata->info.auto_cal = of_property_read_bool(np,
"focaltech,fw-auto-cal"); "focaltech,fw-auto-cal");
pdata->fw_vkey_support = of_property_read_bool(np,
"focaltech,fw-vkey-support");
rc = of_property_read_u32(np, "focaltech,family-id", &temp_val); rc = of_property_read_u32(np, "focaltech,family-id", &temp_val);
if (!rc) if (!rc)
pdata->family_id = temp_val; pdata->family_id = temp_val;
@ -1472,16 +1535,13 @@ static int ft5x06_ts_probe(struct i2c_client *client,
dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4); dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);
reg_addr = FT_REG_FW_VER; ft5x06_update_fw_ver(data);
err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
if (err < 0)
dev_err(&client->dev, "version read failed");
dev_info(&client->dev, "Firmware version = 0x%x\n", reg_value);
FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name, FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name,
data->pdata->num_max_touches, data->pdata->group_id, data->pdata->num_max_touches, data->pdata->group_id,
data->pdata->fw_name, reg_value); data->pdata->fw_vkey_support ? "yes" : "no",
data->pdata->fw_name, data->fw_ver[0],
data->fw_ver[1], data->fw_ver[2]);
#if defined(CONFIG_FB) #if defined(CONFIG_FB)
data->fb_notif.notifier_call = fb_notifier_callback; data->fb_notif.notifier_call = fb_notifier_callback;

View file

@ -55,6 +55,7 @@ struct ft5x06_ts_platform_data {
u32 hard_rst_dly; u32 hard_rst_dly;
u32 soft_rst_dly; u32 soft_rst_dly;
u32 num_max_touches; u32 num_max_touches;
bool fw_vkey_support;
bool no_force_update; bool no_force_update;
bool i2c_pull_up; bool i2c_pull_up;
int (*power_init)(bool); int (*power_init)(bool);