Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,48 @@
#
# Kconfig for MELFAS MMS400 Touchscreen driver
#
if INPUT_TOUCHSCREEN
config TOUCHSCREEN_MELFAS_MMS438
tristate "MELFAS MMS438 Touchscreen"
depends on I2C
help
Say Y here if you have a MELFAS MMS438 touchscreen device in your system.
# If unsure, say N.
# To compile this driver as a module, choose M here: the module will be called mms_ts.
config TOUCHSCREEN_MELFAS_MMS449
tristate "MELFAS MMS449 Touchscreen"
depends on I2C
help
Say Y here if you have a MELFAS MMS449 touchscreen device in your system.
# If unsure, say N.
# To compile this driver as a module, choose M here: the module will be called mms_ts.
config TOUCHSCREEN_MELFAS_MMS458
tristate "MELFAS MMS458 Touchscreen"
depends on I2C
help
Say Y here if you have a MELFAS MMS458 touchscreen device in your system.
# If unsure, say N.
# To compile this driver as a module, choose M here: the module will be called mms_ts.
config TOUCHSCREEN_MELFAS_MMS492
tristate "MELFAS MMS492 Touchscreen"
depends on I2C
help
Say Y here if you have a MELFAS MMS492 touchscreen device in your system.
# If unsure, say N.
# To compile this driver as a module, choose M here: the module will be called mms_ts.
endif

View file

@ -0,0 +1,15 @@
#
# Makefile for MELFAS MMS400 Touchscreen driver
#
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MMS438) += melfas_mms400.o melfas_mms400_mod.o melfas_mms400_test.o melfas_mms400_cmd.o melfas_mms438_fw_update.o
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MMS449) += melfas_mms400.o melfas_mms400_mod.o melfas_mms400_test.o melfas_mms400_cmd.o melfas_mms438_fw_update.o
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MMS458) += melfas_mms400.o melfas_mms400_mod.o melfas_mms400_test.o melfas_mms400_cmd.o melfas_mms438_fw_update.o
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MMS492) += melfas_mms400.o melfas_mms400_mod.o melfas_mms400_test.o melfas_mms400_cmd.o melfas_mms492_fw_update.o
#CFLAGS_melfas_mms400.o += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-label
#CFLAGS_melfas_mms400_test.o += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-label
#CFLAGS_melfas_mms400_cmd.o += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-label
#CFLAGS_melfas_mms438_fw_update.o += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-label
#CFLAGS_melfas_mms492_fw_update.o += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-label

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,407 @@
/*
* MELFAS MMS400 Touchscreen Driver
*
* Copyright (C) 2014 MELFAS Inc.
*
*/
#ifndef __MELFAS_MMS400_H
#define __MELFAS_MMS400_H
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/cdev.h>
#include <linux/err.h>
#include <linux/limits.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/gpio_event.h>
#include <linux/wakelock.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include "melfas_mms400_reg.h"
#include <linux/sec_sysfs.h>
#ifdef CONFIG_BATTERY_SAMSUNG
#include <linux/sec_batt.h>
#endif
#ifdef CONFIG_VBUS_NOTIFIER
#include <linux/muic/muic.h>
#include <linux/muic/muic_notifier.h>
#include <linux/vbus_notifier.h>
#endif
#ifdef CONFIG_SEC_DEBUG_TSP_LOG
#include <linux/sec_debug.h>
#endif
#ifdef CONFIG_SEC_DEBUG_TSP_LOG
#define tsp_debug_dbg(mode, dev, fmt, ...) \
({ \
if (mode) { \
dev_dbg(dev, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
else \
dev_dbg(dev, fmt, ## __VA_ARGS__); \
})
#define tsp_debug_info(mode, dev, fmt, ...) \
({ \
if (mode) { \
dev_info(dev, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
else \
dev_info(dev, fmt, ## __VA_ARGS__); \
})
#define tsp_debug_err(mode, dev, fmt, ...) \
({ \
if (mode) { \
dev_err(dev, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
else \
dev_err(dev, fmt, ## __VA_ARGS__); \
})
#else
#define tsp_debug_dbg(mode, dev, fmt, ...) dev_dbg(dev, fmt, ## __VA_ARGS__)
#define tsp_debug_info(mode, dev, fmt, ...) dev_info(dev, fmt, ## __VA_ARGS__)
#define tsp_debug_err(mode, dev, fmt, ...) dev_err(dev, fmt, ## __VA_ARGS__)
#endif
#ifdef CONFIG_OF
#define MMS_USE_DEVICETREE 1
#else
#define MMS_USE_DEVICETREE 0
#endif
#if defined(CONFIG_GLOVE_TOUCH)
#define GLOVE_MODE
#endif
#define COVER_MODE
#define MMS_DEVICE_NAME "mms_ts"
#define MMS_CONFIG_DATE {0x00, 0x00, 0x00, 0x00}
//Chip info
#if defined(CONFIG_TOUCHSCREEN_MELFAS_MMS438)
#define CHIP_MMS438
#define CHIP_NAME "MMS438"
#define CHIP_FW_CODE "M4H0"
#define FW_UPDATE_TYPE "MMS438"
#elif defined(CONFIG_TOUCHSCREEN_MELFAS_MMS449)
#define CHIP_MMS449
#define CHIP_NAME "MMS449"
#define CHIP_FW_CODE "M4HP"
#define FW_UPDATE_TYPE "MMS438"
#elif defined(CONFIG_TOUCHSCREEN_MELFAS_MMS458)
#define CHIP_MMS458
#define CHIP_NAME "MMS458"
#define CHIP_FW_CODE "M4HN"
#define FW_UPDATE_TYPE "MMS438"
#elif defined(CONFIG_TOUCHSCREEN_MELFAS_MMS492)
#define CHIP_MMS492
#define CHIP_NAME "MMS492"
#define CHIP_FW_CODE "M4HL"
#define FW_UPDATE_TYPE "MMS492"
#endif
//Config driver
#define MMS_USE_INPUT_OPEN_CLOSE 1
#define I2C_RETRY_COUNT 3
#define RESET_ON_EVENT_ERROR 0
#define ESD_COUNT_FOR_DISABLE 7
#define MMS_USE_TOUCHKEY 0
//Features
#define MMS_USE_NAP_MODE 0
#define MMS_USE_TEST_MODE 1
#define MMS_USE_CMD_MODE 1
#ifdef CONFIG_SAMSUNG_PRODUCT_SHIP
#define MMS_USE_DEV_MODE 0
#else
#define MMS_USE_DEV_MODE 1
#endif
//Input value
#define MAX_FINGER_NUM 10
#define INPUT_AREA_MIN 0
#define INPUT_AREA_MAX 255
#define INPUT_PRESSURE_MIN 0
#define INPUT_PRESSURE_MAX 255
#define INPUT_TOUCH_MAJOR_MIN 0
#define INPUT_TOUCH_MAJOR_MAX 255
#define INPUT_TOUCH_MINOR_MIN 0
#define INPUT_TOUCH_MINOR_MAX 255
#define INPUT_ANGLE_MIN 0
#define INPUT_ANGLE_MAX 255
#define INPUT_HOVER_MIN 0
#define INPUT_HOVER_MAX 255
#define INPUT_PALM_MIN 0
#define INPUT_PALM_MAX 1
//Firmware update
#define INTERNAL_FW_PATH "tsp_melfas/mms449_carmen2.fw"
#define EXTERNAL_FW_PATH "/sdcard/melfas.mfsb"
#define FFU_FW_PATH "ffu_tsp.bin"
#define MMS_USE_AUTO_FW_UPDATE 1
#define MMS_FW_MAX_SECT_NUM 4
#define MMS_FW_UPDATE_DEBUG 0
#define MMS_FW_UPDATE_SECTION 1
#define MMS_EXT_FW_FORCE_UPDATE 1
//Command mode
#define CMD_LEN 32
#define CMD_RESULT_LEN 512
#define CMD_PARAM_NUM 8
/**
* Device info structure
*/
struct mms_ts_info {
struct i2c_client *client;
struct input_dev *input_dev;
char phys[32];
struct mms_devicetree_data *dtdata;
struct pinctrl *pinctrl;
dev_t mms_dev;
struct class *class;
struct mutex lock;
struct mutex lock_test;
struct mutex lock_cmd;
struct mutex lock_dev;
int irq;
bool enabled;
bool init;
char *fw_name;
u8 product_name[16];
int max_x;
int max_y;
u8 node_x;
u8 node_y;
u8 node_key;
u8 boot_ver_ic;
u8 core_ver_ic;
u8 config_ver_ic;
u8 event_size;
u16 fw_year;
u8 fw_month;
u8 fw_date;
u16 pre_chksum;
u16 rt_chksum;
unsigned char finger_state[MAX_FINGER_NUM];
int touch_count;
bool tkey_enable;
u8 nap_mode;
u8 glove_mode;
u8 charger_mode;
u8 cover_mode;
u8 esd_cnt;
bool disable_esd;
u8 *print_buf;
int *image_buf;
bool test_busy;
bool cmd_busy;
bool dev_busy;
#if MMS_USE_CMD_MODE
dev_t cmd_dev_t;
struct device *cmd_dev;
struct class *cmd_class;
struct list_head cmd_list_head;
u8 cmd_state;
char cmd[CMD_LEN];
char *cmd_result;
int cmd_param[CMD_PARAM_NUM];
int cmd_buffer_size;
#endif
#if MMS_USE_DEV_MODE
struct cdev cdev;
u8 *dev_fs_buf;
#endif
#ifdef CONFIG_VBUS_NOTIFIER
struct notifier_block vbus_nb;
bool ta_stsatus;
#endif
#ifdef USE_TSP_TA_CALLBACKS
void (*register_cb)(struct tsp_callbacks *);
struct tsp_callbacks callbacks;
#endif
#ifdef CONFIG_SEC_DEBUG_TSP_LOG
struct delayed_work ghost_check;
u8 tsp_dump_lock;
u8 add_log_header;
#endif
};
/**
* Platform Data
*/
struct mms_devicetree_data {
unsigned int max_x;
unsigned int max_y;
int gpio_intr;
const char *gpio_vdd_en;
const char *gpio_io_en;
int gpio_sda;
int gpio_scl;
int panel;
struct regulator *vdd_io;
const char *fw_name;
};
/**
* Firmware binary header info
*/
struct mms_bin_hdr {
char tag[8];
u16 core_version;
u16 section_num;
u16 contains_full_binary;
u16 reserved0;
u32 binary_offset;
u32 binary_length;
u32 extention_offset;
u32 reserved1;
} __attribute__ ((packed));
/**
* Firmware image info
*/
struct mms_fw_img {
u16 type;
u16 version;
u16 start_page;
u16 end_page;
u32 offset;
u32 length;
} __attribute__ ((packed));
/**
* Firmware update error code
*/
enum fw_update_errno{
fw_err_file_read = -4,
fw_err_file_open = -3,
fw_err_file_type = -2,
fw_err_download = -1,
fw_err_none = 0,
fw_err_uptodate = 1,
};
/**
* Declarations
*/
//main
void mms_reboot(struct mms_ts_info *info);
int mms_i2c_read(struct mms_ts_info *info, char *write_buf, unsigned int write_len,
char *read_buf, unsigned int read_len);
int mms_i2c_read_next(struct mms_ts_info *info, char *read_buf, int start_idx,
unsigned int read_len);
int mms_i2c_write(struct mms_ts_info *info, char *write_buf, unsigned int write_len);
int mms_enable(struct mms_ts_info *info);
int mms_disable(struct mms_ts_info *info);
int mms_get_ready_status(struct mms_ts_info *info);
int mms_get_fw_version(struct mms_ts_info *info, u8 *ver_buf);
int mms_get_fw_version_u16(struct mms_ts_info *info, u16 *ver_buf_u16);
int mms_disable_esd_alert(struct mms_ts_info *info);
int mms_fw_update_from_kernel(struct mms_ts_info *info, bool force);
int mms_fw_update_from_storage(struct mms_ts_info *info, bool force);
int mms_fw_update_from_ffu(struct mms_ts_info *info, bool force);
int mms_suspend(struct device *dev);
int mms_resume(struct device *dev);
//mod
int mms_power_control(struct mms_ts_info *info, int enable);
void mms_clear_input(struct mms_ts_info *info);
void mms_report_input_event(struct mms_ts_info *info, u8 sz, u8 *buf);
void mms_input_event_handler(struct mms_ts_info *info, u8 sz, u8 *buf);
#ifdef CONFIG_VBUS_NOTIFIER
int mms_charger_attached(struct mms_ts_info *info, bool status);
#endif
#if MMS_USE_DEVICETREE
int mms_parse_devicetree(struct device *dev, struct mms_ts_info *info);
#endif
void mms_config_input(struct mms_ts_info *info);
//fw_update
int mms_flash_fw(struct mms_ts_info *info, const u8 *fw_data, size_t fw_size,
bool force, bool section);
//test
#if MMS_USE_DEV_MODE
int mms_dev_create(struct mms_ts_info *info);
int mms_get_log(struct mms_ts_info *info);
#endif
int mms_run_test(struct mms_ts_info *info, u8 test_type);
int mms_get_image(struct mms_ts_info *info, u8 image_type);
#if MMS_USE_TEST_MODE
int mms_sysfs_create(struct mms_ts_info *info);
void mms_sysfs_remove(struct mms_ts_info *info);
static const struct attribute_group mms_test_attr_group;
#endif
//cmd
#if MMS_USE_CMD_MODE
int mms_sysfs_cmd_create(struct mms_ts_info *info);
void mms_sysfs_cmd_remove(struct mms_ts_info *info);
static const struct attribute_group mms_cmd_attr_group;
extern struct class *sec_class;
#endif
#ifdef USE_TSP_TA_CALLBACKS
void mms_charger_status_cb(struct tsp_callbacks *cb, int status);
void mms_register_callback(struct tsp_callbacks *cb);
#endif
#ifdef CONFIG_VBUS_NOTIFIER
int mms_vbus_notification(struct notifier_block *nb,
unsigned long cmd, void *data);
#endif
#ifdef CONFIG_SAMSUNG_LPM_MODE
extern int poweroff_charging;
#endif
#endif /* __MELFAS_MMS400_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,399 @@
/*
* MELFAS MMS400 Touchscreen
*
* Copyright (C) 2014 MELFAS Inc.
*
*
* Model dependent functions
*
*/
#include "melfas_mms400.h"
#ifdef USE_TSP_TA_CALLBACKS
static bool ta_connected = 0;
#endif
/**
* Control power supply
*/
int mms_power_control(struct mms_ts_info *info, int enable)
{
int ret = 0;
struct i2c_client *client = info->client;
struct regulator *regulator_dvdd;
struct regulator *regulator_avdd;
struct pinctrl_state *pinctrl_state;
static bool on;
tsp_debug_info(true, &info->client->dev, "%s [START %s] \n",
__func__, enable? "on":"off");
if (on == enable) {
tsp_debug_err(true, &client->dev, "%s : TSP power already %s\n",
__func__,(on)?"on":"off");
return ret;
}
if (info->dtdata->gpio_io_en) {
regulator_dvdd = regulator_get(NULL, info->dtdata->gpio_io_en);
if (IS_ERR(regulator_dvdd)) {
tsp_debug_err(true, &client->dev,"%s: Failed to get %s regulator.\n",
__func__, info->dtdata->gpio_io_en);
ret = PTR_ERR(regulator_dvdd);
goto out;
}
}
regulator_avdd = regulator_get(NULL, info->dtdata->gpio_vdd_en);
if (IS_ERR(regulator_avdd)) {
tsp_debug_err(true, &client->dev,"%s: Failed to get %s regulator.\n",
__func__, info->dtdata->gpio_vdd_en);
ret = PTR_ERR(regulator_avdd);
goto out;
}
if (enable) {
ret = regulator_enable(regulator_avdd);
if (ret) {
tsp_debug_err(true, &client->dev, "%s: Failed to enable avdd: %d\n", __func__, ret);
goto out;
}
if (info->dtdata->gpio_io_en) {
ret = regulator_enable(regulator_dvdd);
if (ret) {
tsp_debug_err(true, &client->dev,"%s: Failed to enable vdd: %d\n", __func__, ret);
goto out;
}
}
pinctrl_state = pinctrl_lookup_state(info->pinctrl, "on_state");
} else {
if (info->dtdata->gpio_io_en) {
if (regulator_is_enabled(regulator_dvdd))
regulator_disable(regulator_dvdd);
}
if (regulator_is_enabled(regulator_avdd))
regulator_disable(regulator_avdd);
pinctrl_state = pinctrl_lookup_state(info->pinctrl, "off_state");
}
if (IS_ERR(pinctrl_state)) {
tsp_debug_err(true, &client->dev,"%s: Failed to lookup pinctrl.\n", __func__);
} else {
ret = pinctrl_select_state(info->pinctrl, pinctrl_state);
if (ret)
tsp_debug_err(true, &client->dev, "%s: Failed to configure pinctrl.\n", __func__);
}
on = enable;
out:
if (info->dtdata->gpio_io_en) {
regulator_put(regulator_dvdd);
}
regulator_put(regulator_avdd);
if (!enable)
usleep_range(10 * 1000, 11 * 1000);
else
msleep(50);
tsp_debug_info(true, &info->client->dev, "%s [DONE %s] \n",
__func__, enable? "on":"off");
return ret;
}
/**
* Clear touch input events
*/
void mms_clear_input(struct mms_ts_info *info)
{
int i;
input_report_key(info->input_dev, BTN_TOUCH, 0);
input_report_key(info->input_dev, BTN_TOOL_FINGER, 0);
for (i = 0; i< MAX_FINGER_NUM; i++) {
info->finger_state[i] = 0;
input_mt_slot(info->input_dev, i);
input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, false);
}
info->touch_count = 0;
input_sync(info->input_dev);
return;
}
/**
* Input event handler - Report touch input event
*/
void mms_input_event_handler(struct mms_ts_info *info, u8 sz, u8 *buf)
{
struct i2c_client *client = info->client;
int i;
tsp_debug_dbg(false, &client->dev, "%s [START]\n", __func__);
tsp_debug_dbg(false, &client->dev, "%s - sz[%d] buf[0x%02X]\n", __func__, sz, buf[0]);
for (i = 1; i < sz; i += info->event_size) {
u8 *tmp = &buf[i];
int id = (tmp[0] & MIP_EVENT_INPUT_ID) - 1;
int x = tmp[2] | ((tmp[1] & 0xf) << 8);
int y = tmp[3] | (((tmp[1] >> 4) & 0xf) << 8);
int pressure = tmp[4];
//int size = tmp[5]; // sumsize
int touch_major = tmp[6];
int touch_minor = tmp[7];
int palm = (tmp[0] & MIP_EVENT_INPUT_PALM) >> 4;
// Report input data
#if MMS_USE_TOUCHKEY
if ((tmp[0] & MIP_EVENT_INPUT_SCREEN) == 0) {
//Touchkey Event
int key = tmp[0] & 0xf;
int key_state = (tmp[0] & MIP_EVENT_INPUT_PRESS) ? 1 : 0;
int key_code = 0;
//Report touchkey event
switch (key) {
case 1:
key_code = KEY_MENU;
//tsp_debug_dbg(true, &client->dev, "Key : KEY_MENU\n");
break;
case 2:
key_code = KEY_BACK;
//tsp_debug_dbg(true, &client->dev, "Key : KEY_BACK\n");
break;
default:
tsp_debug_err(true, &client->dev,
"%s [ERROR] Unknown key code [%d]\n",
__func__, key);
continue;
break;
}
input_report_key(info->input_dev, key_code, key_state);
tsp_debug_dbg(true, &client->dev, "%s - Key : ID[%d] Code[%d] State[%d]\n",
__func__, key, key_code, key_state);
} else
#endif
{
//Report touchscreen event
if ((tmp[0] & MIP_EVENT_INPUT_PRESS) == 0) {
//Release
input_mt_slot(info->input_dev, id);
#ifdef CONFIG_SEC_FACTORY
input_report_abs(info->input_dev, ABS_MT_PRESSURE, 0);
#endif
input_mt_report_slot_state(info->input_dev,
MT_TOOL_FINGER, false);
if (info->finger_state[id] != 0){
info->touch_count--;
if (!info->touch_count) {
input_report_key(info->input_dev, BTN_TOUCH, 0);
input_report_key(info->input_dev,
BTN_TOOL_FINGER, 0);
}
info->finger_state[id] = 0;
tsp_debug_dbg(true, &client->dev,
"R[%d] V[%02x%02x%02x] tc:%d\n",
id, info->boot_ver_ic, info->core_ver_ic,
info->config_ver_ic, info->touch_count);
}
continue;
}
//Press or Move
input_mt_slot(info->input_dev, id);
input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, true);
input_report_key(info->input_dev, BTN_TOUCH, 1);
input_report_key(info->input_dev, BTN_TOOL_FINGER, 1);
input_report_abs(info->input_dev, ABS_MT_POSITION_X, x);
input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y);
#ifdef CONFIG_SEC_FACTORY
if (pressure)
input_report_abs(info->input_dev, ABS_MT_PRESSURE, pressure);
else
input_report_abs(info->input_dev, ABS_MT_PRESSURE, 1);
#endif
input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, touch_major);
input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR, touch_minor);
input_report_abs(info->input_dev, ABS_MT_PALM, palm);
if (info->finger_state[id] == 0){
info->finger_state[id] = 1;
info->touch_count++;
#ifdef CONFIG_SAMSUNG_PRODUCT_SHIP
tsp_debug_info(true, &client->dev,
"P[%d] z:%d p:%d m:%d,%d tc:%d\n",
id, pressure, palm, touch_major, touch_minor, info->touch_count);
#else
tsp_debug_dbg(true, &client->dev,
"P[%d] (%d, %d) z:%d p:%d m:%d,%d tc:%d\n",
id, x, y, pressure, palm, touch_major, touch_minor, info->touch_count);
#endif
}
}
}
input_sync(info->input_dev);
tsp_debug_dbg(false, &client->dev, "%s [DONE]\n", __func__);
return;
}
#if MMS_USE_DEVICETREE
/**
* Parse device tree
*/
int mms_parse_devicetree(struct device *dev, struct mms_ts_info *info)
{
struct device_node *np = dev->of_node;
int ret;
tsp_debug_info(true, dev, "%s [START]\n", __func__);
ret = of_property_read_u32(np, "melfas,max_x", &info->dtdata->max_x);
if (ret) {
tsp_debug_err(true, dev, "%s [ERROR] max_x\n", __func__);
info->dtdata->max_x = 720;
}
ret = of_property_read_u32(np, "melfas,max_y", &info->dtdata->max_y);
if (ret) {
tsp_debug_err(true, dev, "%s [ERROR] max_y\n", __func__);
info->dtdata->max_y = 1280;
}
info->dtdata->gpio_intr = of_get_named_gpio(np, "melfas,irq-gpio", 0);
gpio_request(info->dtdata->gpio_intr, "irq-gpio");
gpio_direction_input(info->dtdata->gpio_intr);
info->client->irq = gpio_to_irq(info->dtdata->gpio_intr);
info->dtdata->gpio_scl = of_get_named_gpio(np, "melfas,scl-gpio", 0);
gpio_request(info->dtdata->gpio_scl, "melfas_scl_gpio");
info->dtdata->gpio_sda = of_get_named_gpio(np, "melfas,sda-gpio", 0);
gpio_request(info->dtdata->gpio_sda, "melfas_sda_gpio");
if (of_property_read_string(np, "melfas,vdd_en", &info->dtdata->gpio_vdd_en)) {
tsp_debug_err(true, dev, "Failed to get regulator_dvdd name property\n");
}
if (of_property_read_string(np, "melfas,io_en", &info->dtdata->gpio_io_en)) {
tsp_debug_err(true, dev, "Failed to get regulator_avdd name property\n");
info->dtdata->gpio_io_en = NULL;
}
if (of_property_read_string(np, "melfas,fw_name", &info->dtdata->fw_name)) {
tsp_debug_err(true, dev, "Failed to get fw_name property\n");
info->dtdata->fw_name = INTERNAL_FW_PATH;
}
tsp_debug_info(true, dev, "%s: fw_name %s max_x:%d max_y:%d int:%d irq:%d sda:%d scl:%d \n",
__func__, info->dtdata->fw_name, info->dtdata->max_x, info->dtdata->max_y,
info->dtdata->gpio_intr, info->client->irq, info->dtdata->gpio_sda,
info->dtdata->gpio_scl);
return 0;
}
#endif
/**
* Config input interface
*/
void mms_config_input(struct mms_ts_info *info)
{
struct input_dev *input_dev = info->input_dev;
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
//Screen
set_bit(EV_SYN, input_dev->evbit);
set_bit(EV_ABS, input_dev->evbit);
set_bit(BTN_TOUCH, input_dev->keybit);
set_bit(BTN_TOOL_FINGER, input_dev->keybit);
set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
input_mt_init_slots(input_dev, MAX_FINGER_NUM, INPUT_MT_DIRECT);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, info->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, info->max_y, 0, 0);
#ifdef CONFIG_SEC_FACTORY
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, INPUT_PRESSURE_MAX, 0, 0);
#endif
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, INPUT_TOUCH_MAJOR_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, INPUT_TOUCH_MINOR_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_MT_PALM, 0, 1, 0, 0);
//Key
set_bit(EV_KEY, input_dev->evbit);
#if MMS_USE_TOUCHKEY
set_bit(KEY_BACK, input_dev->keybit);
set_bit(KEY_MENU, input_dev->keybit);
#endif
#if MMS_USE_NAP_MODE
set_bit(EV_KEY, input_dev->evbit);
set_bit(KEY_POWER, input_dev->keybit);
#endif
tsp_debug_dbg(true, &info->client->dev, "%s [DONE]\n", __func__);
return;
}
#ifdef CONFIG_VBUS_NOTIFIER
int mms_vbus_notification(struct notifier_block *nb,
unsigned long cmd, void *data)
{
struct mms_ts_info *info = container_of(nb, struct mms_ts_info, vbus_nb);
vbus_status_t vbus_type = *(vbus_status_t *)data;
tsp_debug_info(true, &info->client->dev, "%s cmd=%lu, vbus_type=%d\n", __func__, cmd, vbus_type);
if (!info->enabled) {
tsp_debug_err(true, &info->client->dev, "%s tsp disabled",__func__);
return 0;
}
switch (vbus_type) {
case STATUS_VBUS_HIGH:
tsp_debug_info(true, &info->client->dev, "%s : attach\n",__func__);
info->ta_stsatus = true;
break;
case STATUS_VBUS_LOW:
tsp_debug_info(true, &info->client->dev, "%s : detach\n",__func__);
info->ta_stsatus = false;
break;
default:
break;
}
mms_charger_attached(info, info->ta_stsatus);
return 0;
}
#endif
/**
* Callback - get charger status
*/
#ifdef USE_TSP_TA_CALLBACKS
void mms_charger_status_cb(struct tsp_callbacks *cb, int status)
{
pr_info("%s: TA %s\n",
__func__, status ? "connected" : "disconnected");
if (status)
ta_connected = true;
else
ta_connected = false;
/* not yet defined functions */
}
void mms_register_callback(struct tsp_callbacks *cb)
{
charger_callbacks = cb;
pr_info("%s\n", __func__);
}
#endif

View file

@ -0,0 +1,136 @@
/*
* MELFAS MMS400 Touchscreen
*
* Copyright (C) 2014 MELFAS Inc.
*
*
* Protocol information
*
* Protocol Version : MIP 4.0
*
*/
#ifndef __MELFAS_MMS400_REG_H
#define __MELFAS_MMS400_REG_H
//Address
#define MIP_R0_INFO 0x01
#define MIP_R1_INFO_PRODUCT_NAME 0x00
#define MIP_R1_INFO_RESOLUTION_X 0x10
#define MIP_R1_INFO_RESOLUTION_Y 0x12
#define MIP_R1_INFO_NODE_NUM_X 0x14
#define MIP_R1_INFO_NODE_NUM_Y 0x15
#define MIP_R1_INFO_KEY_NUM 0x16
#define MIP_R1_INFO_VERSION_BOOT 0x20
#define MIP_R1_INFO_VERSION_CORE 0x22
#define MIP_R1_INFO_VERSION_CUSTOM 0x24
#define MIP_R1_INFO_VERSION_PARAM 0x26
#define MIP_R1_INFO_SECT_BOOT_START 0x30
#define MIP_R1_INFO_SECT_BOOT_END 0x31
#define MIP_R1_INFO_SECT_CORE_START 0x32
#define MIP_R1_INFO_SECT_CORE_END 0x33
#define MIP_R1_INFO_SECT_CUSTOM_START 0x34
#define MIP_R1_INFO_SECT_CUSTOM_END 0x35
#define MIP_R1_INFO_SECT_PARAM_START 0x36
#define MIP_R1_INFO_SECT_PARAM_END 0x37
#define MIP_R1_INFO_BUILD_DATE 0x40
#define MIP_R1_INFO_BUILD_TIME 0x44
#define MIP_R1_INFO_CHECKSUM_PRECALC 0x48
#define MIP_R1_INFO_CHECKSUM_REALTIME 0x4A
#define MIP_R1_INFO_CHECKSUM_CALC 0x4C
#define MIP_R1_INFO_PROTOCOL_NAME 0x50
#define MIP_R1_INFO_PROTOCOL_VERSION 0x58
#define MIP_R1_INFO_IC_ID 0x70
#define MIP_R0_EVENT 0x02
#define MIP_R1_EVENT_SUPPORTED_FUNC 0x00
#define MIP_R1_EVENT_FORMAT 0x04
#define MIP_R1_EVENT_SIZE 0x06
#define MIP_R1_EVENT_PACKET_INFO 0x10
#define MIP_R1_EVENT_PACKET_DATA 0x11
#define MIP_R0_CTRL 0x06
#define MIP_R1_CTRL_READY_STATUS 0x00
#define MIP_R1_CTRL_EVENT_READY 0x01
#define MIP_R1_CTRL_MODE 0x10
#define MIP_R1_CTRL_EVENT_TRIGGER_TYPE 0x11
#define MIP_R1_CTRL_RECALIBRATE 0x12
#define MIP_R1_CTRL_POWER_STATE 0x13
#define MIP_R1_CTRL_GESTURE_TYPE 0x14
#define MIP_R1_CTRL_DISABLE_ESD_ALERT 0x18
#define MIP_R1_CTRL_CHARGER_MODE 0x19
#define MIP_R1_CTRL_GLOVE_MODE 0x1A
#define MIP_R1_CTRL_WINDOW_MODE 0x1B
#define MIP_R1_CTRL_PALM_REJECTION 0x1C
#define MIP_R1_CTRL_DISABLE_EDGE_EXPAND 0x1D
#define MIP_R0_PARAM 0x08
#define MIP_R1_PARAM_BUFFER_ADDR 0x00
#define MIP_R1_PARAM_PROTOCOL 0x04
#define MIP_R1_PARAM_MODE 0x10
#define MIP_R0_TEST 0x0A
#define MIP_R1_TEST_BUF_ADDR 0x00
#define MIP_R1_TEST_PROTOCOL 0x02
#define MIP_R1_TEST_TYPE 0x10
#define MIP_R1_TEST_DATA_FORMAT 0x20
#define MIP_R1_TEST_ROW_NUM 0x20
#define MIP_R1_TEST_COL_NUM 0x21
#define MIP_R1_TEST_BUFFER_COL_NUM 0x22
#define MIP_R1_TEST_COL_AXIS 0x23
#define MIP_R1_TEST_KEY_NUM 0x24
#define MIP_R1_TEST_DATA_TYPE 0x25
#define MIP_R0_IMAGE 0x0C
#define MIP_R1_IMAGE_BUF_ADDR 0x00
#define MIP_R1_IMAGE_PROTOCOL_ID 0x04
#define MIP_R1_IMAGE_TYPE 0x10
#define MIP_R1_IMAGE_DATA_FORMAT 0x20
#define MIP_R1_IMAGE_ROW_NUM 0x20
#define MIP_R1_IMAGE_COL_NUM 0x21
#define MIP_R1_IMAGE_BUFFER_COL_NUM 0x22
#define MIP_R1_IMAGE_COL_AXIS 0x23
#define MIP_R1_IMAGE_KEY_NUM 0x24
#define MIP_R1_IMAGE_DATA_TYPE 0x25
#define MIP_R1_IMAGE_FINGER_NUM 0x30
#define MIP_R1_IMAGE_FINGER_AREA 0x31
#define MIP_R0_LOG 0x10
#define MIP_R1_LOG_TRIGGER 0x14
//Value
#define MIP_EVENT_INPUT_PRESS 0x80
#define MIP_EVENT_INPUT_SCREEN 0x40
#define MIP_EVENT_INPUT_HOVER 0x20
#define MIP_EVENT_INPUT_PALM 0x10
#define MIP_EVENT_INPUT_ID 0x0F
#define MIP_ALERT_ESD 1
#define MIP_ALERT_WAKEUP 2
#define MIP_CTRL_STATUS_NONE 0x05
#define MIP_CTRL_STATUS_READY 0xA0
#define MIP_CTRL_STATUS_LOG 0x77
#define MIP_CTRL_MODE_NORMAL 0
#define MIP_CTRL_MODE_PARAM 1
#define MIP_CTRL_MODE_TEST_CM 2
#define MIP_TEST_TYPE_NONE 0
#define MIP_TEST_TYPE_CM_DELTA 1
#define MIP_TEST_TYPE_CM_ABS 2
#define MIP_TEST_TYPE_CM_JITTER 3
#define MIP_TEST_TYPE_SHORT 4
#define MIP_IMG_TYPE_NONE 0
#define MIP_IMG_TYPE_INTENSITY 1
#define MIP_IMG_TYPE_RAWDATA 2
#define MIP_IMG_TYPE_WAIT 255
#define MIP_TRIGGER_TYPE_NONE 0
#define MIP_TRIGGER_TYPE_INTR 1
#define MIP_TRIGGER_TYPE_REG 2
#define MIP_LOG_MODE_NONE 0
#define MIP_LOG_MODE_TRIG 1
#endif /* __MELFAS_MMS400_REG_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,497 @@
/*
* MELFAS MMS438/449/458 Touchscreen
*
* Copyright (C) 2014 MELFAS Inc.
*
*
* Firmware update functions
*
*/
#include "melfas_mms400.h"
//ISC Info
#define ISC_PAGE_SIZE 128
//ISC Command
#define ISC_CMD_ERASE_ALL {0xFB,0x4A,0x00,0x15,0x00,0x00}
#define ISC_CMD_ERASE_PAGE {0xFB,0x4A,0x00,0x8F,0x00,0x00}
#define ISC_CMD_READ_PAGE {0xFB,0x4A,0x00,0xC2,0x00,0x00}
#define ISC_CMD_WRITE_PAGE {0xFB,0x4A,0x00,0xA5,0x00,0x00}
#define ISC_CMD_PROGRAM_PAGE {0xFB,0x4A,0x00,0x54,0x00,0x00}
#define ISC_CMD_READ_STATUS {0xFB,0x4A,0x36,0xC2,0x00,0x00}
#define ISC_CMD_EXIT {0xFB,0x4A,0x00,0x66,0x00,0x00}
//ISC Status
#define ISC_STATUS_BUSY 0x96
#define ISC_STATUS_DONE 0xAD
/**
* Read ISC status
*/
static int mms_isc_read_status(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
u8 cmd[6] = ISC_CMD_READ_STATUS;
u8 result = 0;
int cnt = 100;
int ret = 0;
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.flags = 0,
.buf = cmd,
.len = 6,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
.buf = &result,
.len = 1,
},
};
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
do {
if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg))!=ARRAY_SIZE(msg)) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] i2c_transfer\n", __func__);
return -1;
}
if (result == ISC_STATUS_DONE) {
ret = 0;
break;
} else if (result == ISC_STATUS_BUSY) {
ret = -1;
msleep(1);
} else {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] wrong value [0x%02X]\n",
__func__, result);
ret = -1;
msleep(1);
}
} while (--cnt);
if (!cnt) {
tsp_debug_err(true, &info->client->dev,
"%s [ERROR] count overflow - cnt [%d] status [0x%02X]\n",
__func__, cnt, result);
goto ERROR;
}
tsp_debug_dbg(true, &info->client->dev, "%s [DONE]\n", __func__);
return ret;
ERROR:
return ret;
}
/**
* Command : Erase Page
*/
static int mms_isc_erase_page(struct mms_ts_info *info, int offset)
{
u8 write_buf[6] =ISC_CMD_ERASE_PAGE;
struct i2c_msg msg[1] = {
{
.addr = info->client->addr,
.flags = 0,
.buf = write_buf,
.len = 6,
},
};
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
write_buf[4] = (u8)(((offset)>>8) & 0xFF);
write_buf[5] = (u8)(((offset)>>0) & 0xFF);
if (i2c_transfer(info->client->adapter, msg, ARRAY_SIZE(msg)) != ARRAY_SIZE(msg)) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] i2c_transfer\n", __func__);
goto ERROR;
}
if (mms_isc_read_status(info) != 0) {
goto ERROR;
}
tsp_debug_dbg(true, &info->client->dev, "%s [DONE] - Offset [0x%04X]\n", __func__, offset);
return 0;
ERROR:
return -1;
}
/**
* Command : Read Page
*/
static int mms_isc_read_page(struct mms_ts_info *info, int offset, u8 *data)
{
u8 write_buf[6] =ISC_CMD_READ_PAGE;
struct i2c_msg msg[2] = {
{
.addr = info->client->addr,
.flags = 0,
.buf = write_buf,
.len = 6,
}, {
.addr = info->client->addr,
.flags = I2C_M_RD,
.buf = data,
.len = ISC_PAGE_SIZE,
},
};
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
write_buf[4] = (u8)(((offset)>>8) & 0xFF);
write_buf[5] = (u8)(((offset)>>0) & 0xFF);
if (i2c_transfer(info->client->adapter, msg, ARRAY_SIZE(msg)) != ARRAY_SIZE(msg)) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] i2c_transfer\n", __func__);
goto ERROR;
}
tsp_debug_dbg(true, &info->client->dev, "%s [DONE] - Offset [0x%04X]\n", __func__, offset);
return 0;
ERROR:
return -1;
}
/**
* Command : Program Page
*/
static int mms_isc_program_page(struct mms_ts_info *info, int offset,
const u8 *data, int length)
{
u8 write_buf[134] = ISC_CMD_PROGRAM_PAGE;
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
if (length > 128) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] page length overflow\n", __func__);
goto ERROR;
}
write_buf[4] = (u8)(((offset)>>8) & 0xFF);
write_buf[5] = (u8)(((offset)>>0) & 0xFF);
memcpy(&write_buf[6], data, length);
if (i2c_master_send(info->client, write_buf, length+6 )!=length+6) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] i2c_master_send\n", __func__);
goto ERROR;
}
if (mms_isc_read_status(info) != 0) {
goto ERROR;
}
tsp_debug_dbg(true, &info->client->dev, "%s [DONE] - Offset[0x%04X] Length[%d]\n",
__func__, offset, length);
return 0;
ERROR:
return -1;
}
/**
* Command : Exit ISC
*/
static int mms_isc_exit(struct mms_ts_info *info)
{
u8 write_buf[6] = ISC_CMD_EXIT;
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
if (i2c_master_send(info->client, write_buf, 6) != 6) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] i2c_master_send\n", __func__);
goto ERROR;
}
tsp_debug_dbg(true, &info->client->dev, "%s [DONE]\n", __func__);
return 0;
ERROR:
return -1;
}
/**
* Flash chip firmware (main function)
*/
int mms_flash_fw(struct mms_ts_info *info, const u8 *fw_data,
size_t fw_size, bool force, bool section)
{
struct mms_bin_hdr *fw_hdr;
struct mms_fw_img **img;
struct i2c_client *client = info->client;
int i;
int retires = 3;
int ret;
int nRet;
int nStartAddr;
int nWriteLength;
int nLast;
int nOffset;
int nTransferLength;
int size;
u8 *data;
u8 *cpydata;
int offset = sizeof(struct mms_bin_hdr);
bool update_flag = false;
bool update_flags[MMS_FW_MAX_SECT_NUM] = {false, };
u16 ver_chip[MMS_FW_MAX_SECT_NUM];
u16 ver_file[MMS_FW_MAX_SECT_NUM];
int offsetStart = 0;
u8 initData[ISC_PAGE_SIZE];
memset(initData, 0xFF, sizeof(initData));
tsp_debug_dbg(true, &client->dev, "%s [START]\n", __func__);
//Read firmware file
fw_hdr = (struct mms_bin_hdr *)fw_data;
img = vzalloc(sizeof(*img) * fw_hdr->section_num);
if (!img) {
tsp_debug_err(true, &client->dev, "Failed to img allocate memory\n");
nRet = -ENOMEM;
goto err_alloc_img;
}
//Check firmware file
if (memcmp(CHIP_FW_CODE, &fw_hdr->tag[4], 4)) {
tsp_debug_err(true, &client->dev, "%s [ERROR] F/W file is not for %s\n",
__func__, CHIP_NAME);
nRet = fw_err_file_type;
goto EXIT;
}
//Check chip firmware version
while (retires--) {
if (!mms_get_fw_version_u16(info, ver_chip))
break;
else
mms_reboot(info);
}
if (retires < 0) {
tsp_debug_err(true, &client->dev,
"%s [ERROR] cannot read chip firmware version\n",__func__);
memset(ver_chip, 0xFFFF, sizeof(ver_chip));
tsp_debug_dbg(true, &client->dev,
"%s - Chip firmware version is set to [0xFFFF]\n", __func__);
} else {
tsp_debug_info(true, &client->dev,
"%s - Chip firmware version [0x%04X 0x%04X 0x%04X 0x%04X]\n",
__func__, ver_chip[0], ver_chip[1], ver_chip[2], ver_chip[3]);
}
//Set update flag
tsp_debug_info(true, &client->dev,
"%s - Firmware file info : Sections[%d] Offset[0x%08X] Length[0x%08X]\n",
__func__, fw_hdr->section_num, fw_hdr->binary_offset, fw_hdr->binary_length);
for (i = 0; i < fw_hdr->section_num; i++, offset += sizeof(struct mms_fw_img)) {
img[i] = (struct mms_fw_img *)(fw_data + offset);
ver_file[i] = img[i]->version;
tsp_debug_dbg(true, &client->dev,
"%s - Section info : Section[%d] Version[0x%04X] StartPage[%d]"
" EndPage[%d] Offset[0x%08X] Length[0x%08X]\n",
__func__, i, img[i]->version, img[i]->start_page,
img[i]->end_page,img[i]->offset, img[i]->length);
tsp_debug_err(true, &client->dev,
"%s - Section[%d] IC: %04X / BIN: %04X\n",
__func__, i, ver_chip[i], ver_file[i]);
//Compare section version
if (ver_chip[i] < ver_file[i] || ver_chip[i] > ver_file[i] + 0x20) {
//Set update flag
update_flag = true;
update_flags[i] = true;
tsp_debug_info(true, &client->dev,
"%s - Section[%d] is need to be updated.", __func__, i);
}
}
//Set force update flag
if (force == true) {
update_flag = true;
update_flags[0] = true;
update_flags[1] = true;
update_flags[2] = true;
update_flags[3] = true;
tsp_debug_info(true, &client->dev, "%s - Force update\n", __func__);
}
//Exit when up-to-date
if (update_flag == false) {
nRet = fw_err_uptodate;
tsp_debug_dbg(true, &client->dev,
"%s [DONE] Chip firmware is already up-to-date\n", __func__);
goto EXIT;
}
//Set start addr offset
if (section == true) {
if (update_flags[0] == true) {
//boot
offsetStart = img[0]->start_page;
} else if (update_flags[1] == true) {
//core
offsetStart = img[1]->start_page;
} else if (update_flags[2] == true) {
//custom
offsetStart = img[2]->start_page;
} else if (update_flags[3] == true) {
//param
offsetStart = img[3]->start_page;
}
} else
offsetStart = 0;
offsetStart = offsetStart * 1024;
//Load firmware data
data = vzalloc(sizeof(u8) * fw_hdr->binary_length);
if (!data) {
tsp_debug_err(true, &client->dev, "Failed to data allocate memory\n");
nRet = -ENOMEM;
goto err_alloc_data;
}
size = fw_hdr->binary_length;
cpydata = vzalloc(ISC_PAGE_SIZE);
if (!cpydata) {
tsp_debug_err(true, &client->dev, "Failed to cpydata allocate memory\n");
nRet = -ENOMEM;
goto err_alloc_cpydata;
}
//Check firmware size
if (size % ISC_PAGE_SIZE !=0) {
size += ( ISC_PAGE_SIZE - (size % ISC_PAGE_SIZE) );
}
nStartAddr = 0;
nWriteLength = size;
nLast = nStartAddr + nWriteLength;
if ((nLast) % 8 != 0) {
nRet = fw_err_file_type;
tsp_debug_err(true, &client->dev, "%s [ERROR] Firmware size mismatch\n", __func__);
goto ERROR;
} else
memcpy(data,fw_data+fw_hdr->binary_offset,fw_hdr->binary_length);
//Set address
nOffset = nStartAddr + nWriteLength - ISC_PAGE_SIZE;
nTransferLength = ISC_PAGE_SIZE;
//Erase first page
tsp_debug_info(true, &client->dev, "%s - Erase first page : Offset[0x%04X]\n",
__func__, offsetStart);
nRet = mms_isc_erase_page(info, offsetStart);
if (nRet != 0) {
tsp_debug_err(true, &client->dev, "%s [ERROR] clear first page failed\n", __func__);
goto ERROR;
}
//Flash firmware
tsp_debug_info(true, &client->dev, "%s - Start Download : Offset Start[0x%04X] End[0x%04X]\n",
__func__, nOffset, offsetStart);
while( nOffset >= offsetStart )
{
tsp_debug_dbg(true, &client->dev, "%s - Downloading : Offset[0x%04X]\n", __func__, nOffset);
//Program (erase and write) a page
nRet = mms_isc_program_page(info, nOffset, &data[nOffset], nTransferLength);
if (nRet != 0) {
tsp_debug_err(true, &client->dev, "%s [ERROR] isc_program_page\n", __func__);
goto ERROR;
}
//Verify (read and compare)
if (mms_isc_read_page(info, nOffset, cpydata)) {
tsp_debug_err(true, &client->dev, "%s [ERROR] mms_isc_read_page\n", __func__);
goto ERROR;
}
if (memcmp(&data[nOffset], cpydata, ISC_PAGE_SIZE)) {
#if MMS_FW_UPDATE_DEBUG
print_hex_dump(KERN_ERR, "Firmware Page Write : ",
DUMP_PREFIX_OFFSET, 16, 1, data, ISC_PAGE_SIZE, false);
print_hex_dump(KERN_ERR, "Firmware Page Read : ",
DUMP_PREFIX_OFFSET, 16, 1, cpydata, ISC_PAGE_SIZE, false);
#endif
tsp_debug_err(true, &client->dev, "%s [ERROR] verify page failed\n", __func__);
ret = -1;
goto ERROR;
}
nOffset -= nTransferLength;
}
//Exit ISC
nRet = mms_isc_exit(info);
if (nRet != 0) {
tsp_debug_err(true, &client->dev, "%s [ERROR] mms_isc_exit\n", __func__);
goto ERROR;
}
//Reboot chip
mms_reboot(info);
//Check chip firmware version
if (mms_get_fw_version_u16(info, ver_chip)) {
tsp_debug_err(true, &client->dev,
"%s [ERROR] cannot read chip firmware version after flash\n", __func__);
nRet = -1;
goto ERROR;
} else {
for (i = 0; i < fw_hdr->section_num; i++) {
if (ver_chip[i] != ver_file[i]) {
tsp_debug_err(true, &client->dev,
"%s [ERROR] version mismatch after flash."
" Section[%d] : Chip[0x%04X] != File[0x%04X]\n",
__func__, i, ver_chip[i], ver_file[i]);
nRet = -1;
goto ERROR;
}
}
}
nRet = 0;
tsp_debug_dbg(true, &client->dev, "%s [DONE]\n", __func__);
goto DONE;
ERROR:
tsp_debug_err(true, &client->dev, "%s [ERROR]\n", __func__);
DONE:
vfree(cpydata);
err_alloc_cpydata:
vfree(data);
err_alloc_data:
EXIT:
vfree(img);
err_alloc_img:
return nRet;
}