From d1fcdd2a49cc65ee697818884646aeb86239c138 Mon Sep 17 00:00:00 2001 From: Konstantin Makariev Date: Fri, 19 Jul 2019 14:12:26 -0500 Subject: [PATCH] sec_mmi: support normal firmware update This commit enables firmware update via MMI doreflash interface. At this point code only covers the case when touch IC has valid firmware at the time of power up. Change-Id: I06c7ba1b7e1f6dd6f463bc6e961845555fb6da5b Signed-off-by: Konstantin Makariev Reviewed-on: https://gerrit.mot.com/1388759 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Konstantin Makariev Submit-Approved: Jira Key --- .../input/touchscreen/sec_mmi/sec_ts_mmi.c | 124 +++++++++++++++--- 1 file changed, 104 insertions(+), 20 deletions(-) diff --git a/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c b/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c index adf0703c3b7b..4e28da1fec18 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c +++ b/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c @@ -44,6 +44,8 @@ static ssize_t sec_mmi_doreflash_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); static ssize_t sec_mmi_drv_irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); +static ssize_t sec_mmi_erase_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size); static ssize_t sec_mmi_drv_irq_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t sec_mmi_hw_irqstat_show(struct device *dev, @@ -52,14 +54,24 @@ static ssize_t sec_mmi_ic_ver_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t sec_mmi_poweron_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t sec_mmi_productinfo_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t sec_mmi_buildid_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t sec_mmi_flashprog_show(struct device *dev, + struct device_attribute *attr, char *buf); static DEVICE_ATTR(forcereflash, (S_IWUSR | S_IWGRP), NULL, sec_mmi_forcereflash_store); static DEVICE_ATTR(doreflash, (S_IWUSR | S_IWGRP), NULL, sec_mmi_doreflash_store); static DEVICE_ATTR(drv_irq, (S_IWUSR | S_IWGRP | S_IRUGO), sec_mmi_drv_irq_show, sec_mmi_drv_irq_store); static DEVICE_ATTR(hw_irqstat, S_IRUGO, sec_mmi_hw_irqstat_show, NULL); static DEVICE_ATTR(ic_ver, S_IRUGO, sec_mmi_ic_ver_show, NULL); +static DEVICE_ATTR(productinfo, S_IRUGO, sec_mmi_productinfo_show, NULL); +static DEVICE_ATTR(buildid, S_IRUGO, sec_mmi_buildid_show, NULL); +static DEVICE_ATTR(flashprog, S_IRUGO, sec_mmi_flashprog_show, NULL); static DEVICE_ATTR(poweron, S_IRUGO, sec_mmi_poweron_show, NULL); static DEVICE_ATTR(reset, (S_IWUSR | S_IWGRP), NULL, sec_mmi_reset_store); +static DEVICE_ATTR(erase_all, (S_IWUSR | S_IWGRP), NULL, sec_mmi_erase_store); static struct attribute *mmi_attributes[] = { &dev_attr_forcereflash.attr, @@ -67,8 +79,12 @@ static struct attribute *mmi_attributes[] = { &dev_attr_drv_irq.attr, &dev_attr_hw_irqstat.attr, &dev_attr_ic_ver.attr, + &dev_attr_productinfo.attr, + &dev_attr_buildid.attr, + &dev_attr_flashprog.attr, &dev_attr_poweron.attr, &dev_attr_reset.attr, + &dev_attr_erase_all.attr, NULL, }; @@ -208,12 +224,12 @@ static int sec_mmi_dt(struct sec_mmi_data *data) return 0; } -static inline void batohui(unsigned int *dest, unsigned char *src, size_t size) +static inline void bdc2ui(unsigned int *dest, unsigned char *src, size_t size) { - int si = size; + int i, shift = 0; *dest = 0; - for (; --si >= 0;) - *dest += src[si] << (si << 3); + for (i = 0; i < size; i++, shift += 8) + *dest += src[i] << (24 - shift); } static void sec_mmi_fw_read_id(struct sec_mmi_data *data) @@ -228,7 +244,7 @@ static void sec_mmi_fw_read_id(struct sec_mmi_data *data) "%s: failed to read fw version (%d)\n", __func__, ret); } else { - batohui(&data->build_id, buffer, sizeof(data->build_id)); + bdc2ui(&data->build_id, buffer, sizeof(data->build_id)); dev_dbg(DEV_MMI, "%s: FW VERSION: " \ "%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", __func__, buffer[0], buffer[1], buffer[2], buffer[3], @@ -242,7 +258,7 @@ static void sec_mmi_fw_read_id(struct sec_mmi_data *data) "%s: failed to read fw version (%d)\n", __func__, ret); } else { - batohui(&data->config_id, buffer, sizeof(data->config_id)); + bdc2ui(&data->config_id, buffer+4, sizeof(data->config_id)); dev_dbg(DEV_MMI, "%s: CONFIG VER: " \ "%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", __func__, buffer[0], buffer[1], buffer[2], buffer[3], @@ -256,7 +272,6 @@ static void sec_mmi_fw_read_id(struct sec_mmi_data *data) "%s: failed to read fw version (%d)\n", __func__, ret); } else { - batohui(&data->config_id, buffer, sizeof(data->config_id)); dev_dbg(DEV_MMI, "%s: IMAGE VER: " \ "%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", __func__, buffer[0], buffer[1], buffer[2], buffer[3], @@ -436,12 +451,44 @@ static ssize_t sec_mmi_poweron_show(struct device *dev, ts->power_status != SEC_TS_STATE_POWER_OFF); } +static ssize_t sec_mmi_productinfo_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sec_ts_data *ts = dev_get_drvdata(dev); + struct sec_mmi_data *data = ts->mmi_ptr; + return scnprintf(buf, PAGE_SIZE, "%s\n", data->product_id); +} + +static ssize_t sec_mmi_buildid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sec_ts_data *ts = dev_get_drvdata(dev); + struct sec_mmi_data *data = ts->mmi_ptr; + return scnprintf(buf, PAGE_SIZE, "%08x-%08x\n", + data->build_id, data->config_id); +} + +static ssize_t sec_mmi_flashprog_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sec_ts_data *ts = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%d\n", ts->fw_invalid ? 1 : 0); +} + static ssize_t sec_mmi_hw_irqstat_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_ts_data *ts = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", - ts->power_status != SEC_TS_STATE_POWER_OFF); + switch (gpio_get_value(ts->plat_data->irq_gpio)) { + case 0: + return scnprintf(buf, PAGE_SIZE, "Low\n"); + case 1: + return scnprintf(buf, PAGE_SIZE, "High\n"); + default: + dev_err(DEV_TS, "%s: Failed to get irq gpio %d state\n", + __func__, ts->plat_data->irq_gpio); + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); + } } static ssize_t sec_mmi_drv_irq_show(struct device *dev, @@ -452,6 +499,35 @@ static ssize_t sec_mmi_drv_irq_show(struct device *dev, ts->irq_enabled ? "ENABLED" : "DISABLED"); } +static ssize_t sec_mmi_erase_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct sec_ts_data *ts = dev_get_drvdata(dev); + unsigned long value = 0; + int err = 0; + + err = kstrtoul(buf, 10, &value); + if (err < 0) { + dev_err(DEV_TS, "%s: Failed to convert value\n", __func__); + return -EINVAL; + } + + if (value != 1) + return -EINVAL; + + mutex_lock(&ts->modechange); + sec_ts_irq_enable(ts, false); + __pm_stay_awake(&ts->wakelock); + + + ts->fw_invalid = true; + + mutex_unlock(&ts->modechange); + __pm_relax(&ts->wakelock); + + return size; +} + static ssize_t sec_mmi_drv_irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { @@ -490,7 +566,7 @@ static ssize_t sec_mmi_ic_ver_show(struct device *dev, { struct sec_ts_data *ts = dev_get_drvdata(dev); struct sec_mmi_data *data = ts->mmi_ptr; - return scnprintf(buf, PAGE_SIZE, "%s%s\n%s%x\n%s%x\n", + return scnprintf(buf, PAGE_SIZE, "%s%s\n%s%08x\n%s%08x\n", "Product ID: ", data->product_id, "Build ID: ", data->build_id, "Config ID: ", data->config_id); @@ -499,7 +575,7 @@ static ssize_t sec_mmi_ic_ver_show(struct device *dev, static ssize_t sec_mmi_forcereflash_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - return 0; + return size; } static ssize_t sec_mmi_doreflash_store(struct device *dev, @@ -508,29 +584,37 @@ static ssize_t sec_mmi_doreflash_store(struct device *dev, struct sec_ts_data *ts = dev_get_drvdata(dev); const struct firmware *fw_entry; char fw_path[SEC_TS_MAX_FW_PATH]; - int result = -1; + int result = -EFAULT; if (size > SEC_TS_MAX_FW_PATH) { dev_err(DEV_TS, "%s: FW filename is too long\n", __func__); return -EINVAL; } - disable_irq(ts->client->irq); - scnprintf(fw_path, SEC_TS_MAX_FW_PATH, "%s", buf); - input_info(true, DEV_TS, "%s: initial bl update %s\n", __func__, fw_path); + strlcpy(fw_path, buf, size); + input_info(true, DEV_TS, "%s: update fw from %s\n", __func__, fw_path); /* Loading Firmware------------------------------------------ */ - if (request_firmware(&fw_entry, fw_path, &ts->client->dev) != 0) { - input_err(true, DEV_TS, "%s: bt is not available\n", __func__); + if (request_firmware(&fw_entry, fw_path, &ts->client->dev) != 0) { + input_err(true, DEV_TS, "%s: fw not available\n", __func__); goto err_request_fw; } - input_info(true, DEV_TS, "%s: request bt done! size = %d\n", __func__, (int)fw_entry->size); + input_info(true, DEV_TS, "%s: fw size = %d\n", __func__, (int)fw_entry->size); - result = sec_ts_firmware_update(ts, fw_entry->data, fw_entry->size, 1, false, 0); + mutex_lock(&ts->modechange); + sec_ts_irq_enable(ts, false); + __pm_stay_awake(&ts->wakelock); + + result = sec_ts_firmware_update(ts, fw_entry->data, fw_entry->size, 0, false, 0); + if (result == 1) + sec_mmi_fw_read_id(ts->mmi_ptr); + + mutex_unlock(&ts->modechange); + sec_ts_irq_enable(ts, true); + __pm_relax(&ts->wakelock); err_request_fw: release_firmware(fw_entry); - enable_irq(ts->client->irq); return result; }