blob: 73ca5c158c09027ef78b93377c472ba99b6bde90 [file] [log] [blame]
/* drivers/input/touchscreen/sec_ts_fw.c
*
* Copyright (C) 2016 Samsung Electronics Co., Ltd.
* http://www.samsungsemi.com/
*
* Core file for Samsung TSC driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/uaccess.h>
#include "sec_ts.h"
#define SEC_TS_FW_BLK_SIZE 256
/*for hardware info get tp fw version */
extern unsigned int ctp_fw_version_1;
extern unsigned int ctp_fw_version_2;
static u8 sec_ts_fw_data[] = {
#include "s6d6ft0_v1.10_20170918.i"
};
u8 *sec_get_fwdata(void) { return sec_ts_fw_data; }
int sec_ts_sw_reset(struct sec_ts_data *ts) {
int ret;
ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_SW_RESET, NULL, 0);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: write fail, sw_reset\n", __func__);
return 0;
}
sec_ts_delay(500);
input_info(true, &ts->client->dev, "%s: sw_reset\n", __func__);
return 1;
}
int sec_ts_check_firmware_version(struct sec_ts_data *ts, const u8 *fw_info) {
struct fw_header *fw_hd;
u8 data[20] = {0};
u8 device_id[3] = {0};
u8 fw_ver[4];
int ret;
/*
* sec_ts_check_firmware_version
* return value = 2 : bootloader mode
* return value = 1 : firmware download needed,
* return value = 0 : skip firmware download
*/
fw_hd = (struct fw_header *)fw_info;
ret = ts->sec_ts_i2c_read(ts, SEC_TS_READ_DEVICE_ID, device_id, 3);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: failed to read device id(%d)\n",
__func__, ret);
return -1;
}
input_info(true, &ts->client->dev, "%s: %X, %X, %X\n", __func__, device_id[0],
device_id[1], device_id[2]);
if (device_id[0] == SEC_TS_ID_ON_BOOT)
return 2;
ret = ts->sec_ts_i2c_read(ts, SEC_TS_READ_SUB_ID, data, 20);
if (ret < 0) {
input_info(true, &ts->client->dev, "%s: firmware version read error\n ",
__func__);
return -1;
}
input_info(true, &ts->client->dev,
"%s: [IC] Image version info : %x.%x.%x.%x // [BIN] %08X\n",
__func__, data[9], data[10], data[11], data[12], fw_hd->version);
fw_ver[0] = data[9];
fw_ver[1] = data[10];
fw_ver[2] = data[11];
fw_ver[3] = data[12];
ts->plat_data->img_version_of_ic[0] = fw_ver[0];
ts->plat_data->img_version_of_ic[1] = fw_ver[1];
ts->plat_data->img_version_of_ic[2] = fw_ver[2];
ts->plat_data->img_version_of_ic[3] = fw_ver[3];
ts->plat_data->img_version_of_bin[0] = (fw_hd->version && 0xFF);
ts->plat_data->img_version_of_bin[1] = (fw_hd->version >> 8 && 0xFF);
ts->plat_data->img_version_of_bin[2] = (fw_hd->version >> 16 && 0xFF);
ts->plat_data->img_version_of_bin[3] = (fw_hd->version >> 24 && 0xFF);
input_info(true, &ts->client->dev,
"%s: [FW] IMG version : %x.%x. [IC] IMG version %x.%x.\n",
__func__, (fw_hd->version >> 16) & 0xff,
(fw_hd->version >> 24) & 0xff, fw_ver[2], fw_ver[3]);
if (((fw_hd->version) & 0xff) != fw_ver[0]) {
input_err(true, &ts->client->dev, "%s: f/w product 0 is not equal: %x\n ",
__func__, fw_ver[0]);
return -1;
}
if (((fw_hd->version >> 8) & 0xff) != fw_ver[1]) {
input_err(true, &ts->client->dev, "%s: f/w project 1 is not equal : %x\n ",
__func__, fw_ver[1]);
return -1;
}
if (((fw_hd->version >> 16) & 0xff) > fw_ver[2]) {
return 1;
} else if ((((fw_hd->version >> 16) & 0xff) == fw_ver[2]) &&
(((fw_hd->version >> 24) & 0xff) > fw_ver[3])) {
return 1;
}
return 0;
}
static u8 sec_ts_checksum(u8 *data, int offset, int size) {
int i;
u8 checksum = 0;
for (i = 0; i < size; i++)
checksum += data[i + offset];
return checksum;
}
/***********************/
/** Ext-flash control **/
/***********************/
#define SEC_TS_CMD_CS_CONTROL 0x8B
#define SEC_TS_CMD_SET_DATA_NUM 0xD1
#define FLASH_CMD_RDSR 0x05
#define FLASH_CMD_WREN 0x06
#define FLASH_CMD_SE 0x20
#define FLASH_CMD_PP 0x02
#define SEC_TS_CMD_FLASH_SEND_DATA 0xEB
#define SEC_TS_CMD_FLASH_READ_DATA 0xEC
#define CS_LOW 0
#define CS_HIGH 1
#define BYTE_PER_SECTOR 4096
#define BYTE_PER_PAGE 256
#define PAGE_DATA_HEADER_SIZE 4
#define SEC_TS_FLASH_WIP_MASK 0x01
#define SEC_TS_FLASH_SIZE_256 256
#define BYTE_PER_SECTOR 4096
#define BYTE_PER_PAGE 256
#define PAGE_PER_SECTOR 16
static int sec_ts_flash_set_datanum(struct sec_ts_data *ts, u16 num) {
u8 tData[2];
int ret;
tData[0] = (num >> 8) & 0xFF;
tData[1] = num & 0xFF;
ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_SET_DATA_NUM, tData, 2);
if (ret < 0)
input_err(true, &ts->client->dev, "%s: Set datanum Fail %d\n", __func__,
num);
return ret;
}
static int sec_ts_flash_cs_control(struct sec_ts_data *ts, bool cs_level) {
u8 tData;
int ret;
tData = cs_level ? 1 : 0;
ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_CS_CONTROL, &tData, 1);
if (ret < 0)
input_info(true, &ts->client->dev, "%s: %s control Fail!\n", __func__,
cs_level ? "CS High" : "CS Low");
return ret;
}
static int sec_ts_wren(struct sec_ts_data *ts) {
u8 tData[2];
int ret;
sec_ts_flash_cs_control(ts, CS_LOW);
sec_ts_flash_set_datanum(ts, 6);
tData[0] = FLASH_CMD_WREN;
ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_FLASH_SEND_DATA, &tData[0], 1);
if (ret < 0)
input_err(true, &ts->client->dev, "%s: Send WREN fail!\n", __func__);
sec_ts_flash_cs_control(ts, CS_HIGH);
return ret;
}
static u8 sec_ts_rdsr(struct sec_ts_data *ts) {
u8 tData[2];
sec_ts_flash_cs_control(ts, CS_LOW);
sec_ts_flash_set_datanum(ts, 2);
tData[0] = FLASH_CMD_RDSR;
ts->sec_ts_i2c_write(ts, SEC_TS_CMD_FLASH_SEND_DATA, tData, 1);
sec_ts_flash_set_datanum(ts, 1);
ts->sec_ts_i2c_read(ts, SEC_TS_CMD_FLASH_READ_DATA, tData, 1);
sec_ts_flash_cs_control(ts, CS_HIGH);
return tData[0];
}
static bool IsFlashBusy(struct sec_ts_data *ts) {
u8 tBuf;
sec_ts_wren(ts);
tBuf = sec_ts_rdsr(ts);
if ((tBuf & SEC_TS_FLASH_WIP_MASK) == SEC_TS_FLASH_WIP_MASK)
return true;
return false;
}
static int sec_ts_wait_for_flash_busy(struct sec_ts_data *ts) {
int retry_cnt = 0;
int ret = 0;
while (IsFlashBusy(ts)) {
sec_ts_delay(10);
if (retry_cnt++ > SEC_TS_WAIT_RETRY_CNT) { /*RETRY_CNT = 100*/
input_err(true, &ts->client->dev, "%s: Retry Cnt over!\n", __func__);
ret = -1;
}
}
return ret;
}
static int sec_ts_cmd_flash_se(struct sec_ts_data *ts, u32 flash_addr) {
int ret;
u8 tBuf[5];
if (IsFlashBusy(ts))
return false;
sec_ts_wren(ts);
sec_ts_flash_cs_control(ts, CS_LOW);
sec_ts_flash_set_datanum(ts, 5);
tBuf[0] = SEC_TS_CMD_FLASH_SEND_DATA;
tBuf[1] = FLASH_CMD_SE;
tBuf[2] = (flash_addr >> 16) & 0xFF;
tBuf[3] = (flash_addr >> 8) & 0xFF;
tBuf[4] = (flash_addr >> 0) & 0xFF;
ret = ts->sec_ts_i2c_write_burst(ts, tBuf, 5);
sec_ts_flash_cs_control(ts, CS_HIGH);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: Send sector erase cmd fail!\n",
__func__);
return ret;
}
ret = sec_ts_wait_for_flash_busy(ts);
if (ret < 0)
input_err(true, &ts->client->dev, "%s: Time out! - flash busy wait\n",
__func__);
return ret;
}
#ifdef CONFIG_CMD_PP
bool sec_ts_cmd_pp(struct sec_ts_data *ts, int flash_address, u8 *source_data,
int byte_length) {
int data_byte_total_length;
u8 *tCmd;
int ret, i;
if (IsFlashBusy(ts))
return false;
sec_ts_wren(ts);
data_byte_total_length = 1 + 3 + byte_length + 1;
tCmd = kzalloc(data_byte_total_length, GFP_KERNEL);
sec_ts_flash_cs_control(ts, CS_LOW);
sec_ts_flash_set_datanum(ts, 0x104);
tCmd[0] = SEC_TS_CMD_FLASH_SEND_DATA;
tCmd[1] = FLASH_CMD_PP;
tCmd[2] = (flash_address >> 16) & 0xFF;
tCmd[3] = (flash_address >> 8) & 0xFF;
tCmd[4] = (flash_address >> 0) & 0xFF;
for (i = 0; i < byte_length; i++)
tCmd[5 + i] = source_data[i];
ret = ts->sec_ts_i2c_write_burst(ts, tCmd, data_byte_total_length);
sec_ts_flash_cs_control(ts, CS_HIGH);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: PP cmd fail!\n", __func__);
return false;
}
input_dbg(true, &ts->client->dev, "%s : addr = %X%X%X\n", __func__, tCmd[2],
tCmd[3], tCmd[4]);
kfree(tCmd);
while (IsFlashBusy(ts))
sec_ts_delay(10);
return true;
}
#endif
static int sec_ts_FlashSectorErase(struct sec_ts_data *ts, u32 sector_idx) {
u32 addr;
int ret = 0;
addr = sector_idx * BYTE_PER_PAGE;
ret = sec_ts_cmd_flash_se(ts, addr);
if (ret < 0)
input_err(true, &ts->client->dev, "%s: Fail!\n", __func__);
return ret;
}
static bool sec_ts_flashpagewrite(struct sec_ts_data *ts, u32 page_idx,
u8 *page_data) {
#ifndef CONFIG_CMD_PP
int ret;
int i, j;
u8 *tCmd;
u8 copy_data[3 + SEC_TS_FLASH_SIZE_256];
int copy_left = SEC_TS_FLASH_SIZE_256 + 3;
int copy_size = 0;
int copy_max = SEC_TS_FLASH_SIZE_256 + 3;
copy_data[0] = (u8)((page_idx >> 8) & 0xFF);
copy_data[1] = (u8)((page_idx >> 0) & 0xFF);
for (i = 0; i < SEC_TS_FLASH_SIZE_256; i++)
copy_data[2 + i] = page_data[i];
copy_data[2 + SEC_TS_FLASH_SIZE_256] =
sec_ts_checksum(copy_data, 0, 2 + SEC_TS_FLASH_SIZE_256);
sec_ts_flash_cs_control(ts, CS_LOW);
while (copy_left > 0) {
int copy_cur = (copy_left > copy_max) ? copy_max : copy_left;
tCmd = (u8 *)kzalloc(copy_cur + 1, GFP_KERNEL);
if (copy_size == 0)
tCmd[0] = 0xD9;
else
tCmd[0] = 0xDA;
for (j = 0; j < copy_cur; j++)
tCmd[j + 1] = copy_data[copy_size + j];
ret = ts->sec_ts_i2c_write_burst(ts, tCmd, 1 + copy_cur);
if (ret < 0)
input_err(true, &ts->client->dev, "%s i2c error = %d\n", __func__,
copy_left);
copy_size += copy_cur;
copy_left -= copy_cur;
kfree(tCmd);
}
sec_ts_delay(5); // add for test
sec_ts_flash_cs_control(ts, CS_HIGH);
return ret;
#else
int size;
int addr;
size = BYTE_PER_PAGE;
addr = page_idx * BYTE_PER_PAGE;
sec_ts_cmd_pp(ts, addr, page_data, size);
return true;
#endif
}
static bool sec_ts_flashlimitread(struct sec_ts_data *ts, u32 mem_addr,
u32 mem_size, u8 *mem_data) {
int ret = 0;
int copy_left = mem_size;
int copy_size = 0;
int copy_max = 32;
u32 copy_addr = mem_addr;
u8 tCmd[5];
u8 *copy_data = mem_data;
sec_ts_flash_cs_control(ts, CS_LOW);
while (copy_left > 0) {
int copy_cur = (copy_left > copy_max) ? copy_max : copy_left;
tCmd[0] = 0xD0;
tCmd[1] = (u8)((copy_addr >> 24) & 0xff);
tCmd[2] = (u8)((copy_addr >> 16) & 0xff);
tCmd[3] = (u8)((copy_addr >> 8) & 0xff);
tCmd[4] = (u8)((copy_addr >> 0) & 0xff);
ret = ts->sec_ts_i2c_write_burst(ts, tCmd, 5);
if (ret < 0) {
input_info(true, &ts->client->dev, "%s: D0 fail\n", __func__);
goto burst_err;
}
tCmd[0] = 0xD1;
tCmd[1] = (u8)((copy_cur >> 8) & 0xff);
tCmd[2] = (u8)((copy_cur >> 0) & 0xff);
ret = ts->sec_ts_i2c_write_burst(ts, tCmd, 3);
if (ret < 0) {
input_info(true, &ts->client->dev, "%s: D1 fail\n", __func__);
goto burst_err;
}
tCmd[0] = 0xDC;
ret = ts->sec_ts_i2c_read(ts, tCmd[0], &copy_data[copy_size], copy_cur);
if (ret < 0) {
input_info(true, &ts->client->dev, "%s: memroy read fail\n", __func__);
goto burst_err;
}
copy_addr += copy_cur;
copy_size += copy_cur;
copy_left -= copy_cur;
}
sec_ts_flash_cs_control(ts, CS_HIGH);
burst_err:
return ret;
}
static int sec_ts_flashwrite(struct sec_ts_data *ts, u32 mem_addr, u8 *mem_data,
u32 mem_size) {
int ret;
int page_idx;
int size_left;
int size_copy;
u32 flash_page_size;
u32 page_idx_start;
u32 page_idx_end;
u32 page_num;
u8 page_buf[SEC_TS_FLASH_SIZE_256];
if (mem_size == 0) {
input_err(true, &ts->client->dev,
"%s, mem_size 0\n", __func__);
return 0;
}
flash_page_size = SEC_TS_FLASH_SIZE_256;
page_idx_start = mem_addr / flash_page_size;
page_idx_end = (mem_addr + mem_size - 1) / flash_page_size;
page_num = page_idx_end - page_idx_start + 1;
for (page_idx = (int)((page_num - 1) / 16); page_idx >= 0; page_idx--) {
ret = sec_ts_FlashSectorErase(ts, (page_idx_start + page_idx * 16));
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: Sector erase fail! sector_idx = %08X\n", __func__,
page_idx_start + page_idx * 16);
return -EIO;
}
}
input_info(true, &ts->client->dev, "%s flash sector erase done\n", __func__);
sec_ts_delay(page_num + 10);
size_left = (int)mem_size;
size_copy = (int)(mem_size % flash_page_size);
if (size_copy == 0)
size_copy = (int)flash_page_size;
memset(page_buf, 0, SEC_TS_FLASH_SIZE_256);
for (page_idx = (int)page_num - 1; page_idx >= 0; page_idx--) {
memcpy(page_buf, mem_data + (page_idx * flash_page_size), size_copy);
ret = sec_ts_flashpagewrite(ts, (u32)(page_idx + page_idx_start), page_buf);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s fw write failed, page_idx = %d\n",
__func__, page_idx);
goto err;
}
size_copy = (int)flash_page_size;
sec_ts_delay(5);
}
input_info(true, &ts->client->dev, "%s flash page write done\n", __func__);
return mem_size;
err:
return -EIO;
}
static int sec_ts_flashread(struct sec_ts_data *ts, u32 mem_addr, u8 *mem_data,
u32 mem_size) {
int ret;
if ((mem_size == 0) || (mem_size > 128000))
return 0;
ret = sec_ts_flashlimitread(ts, mem_addr, mem_size, mem_data);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s fw read failed\n", __func__);
goto err;
}
return mem_size;
err:
return -EIO;
}
static int sec_ts_chunk_update(struct sec_ts_data *ts, u32 addr, u32 size,
u8 *data) {
int i;
int ret;
u32 fw_size;
u32 write_size;
u8 *mem_data;
u8 *mem_rb;
fw_size = size;
mem_data = kzalloc(fw_size, GFP_KERNEL);
if (!mem_data)
return -ENOMEM;
memcpy(mem_data, data, sizeof(u8) * fw_size);
write_size = sec_ts_flashwrite(ts, addr, mem_data, fw_size);
if (write_size != fw_size) {
input_err(true, &ts->client->dev, "%s fw write failed\n", __func__);
return -1;
}
input_info(true, &ts->client->dev, "%s flash write done\n", __func__);
kfree(mem_data);
sec_ts_delay(1000);
return 0;
verify_err:
input_info(true, &ts->client->dev, "%s flash verify failed\n", __func__);
kfree(mem_data);
return -ENOMEM;
}
static int sec_ts_firmware_update(struct sec_ts_data *ts, const u8 *data,
size_t size) {
int i, ret;
u8 device_id[3];
u8 *fd = (u8 *)data;
u8 num_chunk;
struct fw_header *fw_hd;
fw_hd = (struct fw_header *)fd;
if (fw_hd->signature != SEC_TS_FW_HEADER_SIGN) {
input_err(true, &ts->client->dev, "%s: firmware header error = %08X\n",
__func__, fw_hd->signature);
return -1;
}
num_chunk = fw_hd->NumberOfChunk[0] && 0xFF;
input_info(true, &ts->client->dev, "%s: num_chunk : %d\n", __func__,
num_chunk);
input_info(true, &ts->client->dev, "%s: 0x%08X, 0x%08X, 0x%zu, 0x%08X\n",
__func__, fw_hd->signature, fw_hd->flag, size, fw_hd->setting);
for (i = 0; i < num_chunk; i++) {
ret = sec_ts_chunk_update(ts, 0, (u32)size, fd);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: firmware chunk write failed\n",
__func__);
return -1;
}
}
ts->sec_ts_i2c_write(ts, SEC_TS_CMD_SW_RESET, NULL, 0);
sec_ts_delay(500);
sec_ts_wait_for_ready(ts, SEC_TS_ACK_BOOT_COMPLETE);
if (ts->sec_ts_i2c_read(ts, SEC_TS_READ_DEVICE_ID, device_id, 3) < 0) {
input_err(true, &ts->client->dev,
"%s: read fail, read_boot_status = 0x%x\n", __func__,
device_id[0]);
return -1;
}
if (device_id[0] != SEC_TS_ID_ON_FW) {
input_err(
true, &ts->client->dev,
"%s: fw update sequence done, BUT fw is not loaded (id[0] = 0x%x)\n",
__func__, device_id[0]);
return -1;
}
input_err(true, &ts->client->dev, "%s: fw update Success! id[0] = 0x%x\n",
__func__, device_id[0]);
return 0;
}
int sec_ts_firmware_update_on_probe(struct sec_ts_data *ts) {
const struct firmware *fw_entry;
char fw_path[SEC_TS_MAX_FW_PATH];
int result = -1;
disable_irq(ts->client->irq);
if (!ts->plat_data->firmware_name)
snprintf(fw_path, SEC_TS_MAX_FW_PATH, "%s", SEC_TS_DEFAULT_FW_NAME);
else
snprintf(fw_path, SEC_TS_MAX_FW_PATH, "%s", ts->plat_data->firmware_name);
input_info(true, &ts->client->dev, "%s: initial firmware update %s\n",
__func__, fw_path);
/* Loading Firmware */
if (request_firmware(&fw_entry, fw_path, &ts->client->dev) != 0) {
input_err(true, &ts->client->dev, "%s: firmware is not available\n",
__func__);
goto err_request_fw;
}
input_info(true, &ts->client->dev, "%s: request firmware done! size = %d\n",
__func__, (int)fw_entry->size);
result = sec_ts_check_firmware_version(ts, fw_entry->data);
if (result <= 0)
goto err_request_fw;
if (sec_ts_firmware_update(ts, fw_entry->data, fw_entry->size) < 0)
result = -1;
else
result = 0;
err_request_fw:
release_firmware(fw_entry);
enable_irq(ts->client->irq);
return result;
}
int sec_ts_firmwarei_update_on_probe(struct sec_ts_data *ts) {
int ret;
int result = -1;
int fw_size;
int ctp_fw_version_1;
int ctp_fw_version_2;
input_info(true, &ts->client->dev,
"%s: initial firmware update with i file\n", __func__);
fw_size = sizeof(sec_ts_fw_data);
/* Loading Firmware */
input_info(true, &ts->client->dev, "%s: request firmware done! size = %d\n",
__func__, (int)fw_size);
result = sec_ts_check_firmware_version(ts, sec_ts_fw_data);
/*for hardware info get tp fw version */
ctp_fw_version_1 = ts->plat_data->img_version_of_ic[2];
ctp_fw_version_2 = ts->plat_data->img_version_of_ic[3];
if (!ts->force_fwup) {
if (result < 0)
goto err_request_fw;
else if (result == 0)
goto skip_request_fw;
}
if (sec_ts_firmware_update(ts, sec_ts_fw_data, fw_size) < 0) {
result = -1;
return result;
}
ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_CALIBRATION_OFFSET_SDC, NULL, 0);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: calibration fail\n", __func__);
goto err_request_fw;
}
sec_ts_delay(1000);
ts->sec_ts_i2c_write(ts, SEC_TS_CMD_SW_RESET, NULL, 0);
sec_ts_delay(500);
sec_ts_wait_for_ready(ts, SEC_TS_ACK_BOOT_COMPLETE);
if (result >= 1)
sec_ts_check_firmware_version(ts, sec_ts_fw_data);
ctp_fw_version_1 = ts->plat_data->img_version_of_bin[2];
ctp_fw_version_2 = ts->plat_data->img_version_of_bin[3];
// after update
return 0;
err_request_fw:
return -1;
skip_request_fw:
return result;
}
static int sec_ts_load_fw_from_ums(struct sec_ts_data *ts) {
struct fw_header *fw_hd;
struct file *fp;
mm_segment_t old_fs;
long fw_size, nread;
int error = 0;
old_fs = get_fs();
set_fs(KERNEL_DS);
fp = filp_open(SEC_TS_DEFAULT_UMS_FW, O_RDONLY, S_IRUSR);
if (IS_ERR(fp)) {
input_err(true, ts->dev, "%s: failed to open %s.\n", __func__,
SEC_TS_DEFAULT_UMS_FW);
error = -ENOENT;
goto open_err;
}
fw_size = fp->f_path.dentry->d_inode->i_size;
if (0 < fw_size) {
unsigned char *fw_data;
fw_data = kzalloc(fw_size, GFP_KERNEL);
nread = vfs_read(fp, (char __user *)fw_data, fw_size, &fp->f_pos);
input_info(true, ts->dev, "%s: start, file path %s, size %ld Bytes\n",
__func__, SEC_TS_DEFAULT_UMS_FW, fw_size);
if (nread != fw_size) {
input_err(true, ts->dev,
"%s: failed to read firmware file, nread %ld Bytes\n", __func__,
nread);
error = -EIO;
} else {
fw_hd = (struct fw_header *)fw_data;
input_info(true, &ts->client->dev, "%s: IMG version %08X\n ", __func__,
fw_hd->version);
if (ts->irq)
disable_irq(ts->irq);
if (sec_ts_firmware_update(ts, fw_data, fw_size) < 0)
goto done;
if (ts->irq)
enable_irq(ts->irq);
}
if (error < 0)
input_err(true, ts->dev, "%s: failed update firmware\n", __func__);
done:
kfree(fw_data);
}
filp_close(fp, NULL);
open_err:
set_fs(old_fs);
return error;
}
int sec_ts_firmware_update_on_hidden_menu(struct sec_ts_data *ts,
int update_type) {
int ret = 0;
/* Factory cmd for firmware update
* argument represent what is source of firmware like below.
*
* 0 : [BUILT_IN] Getting firmware which is for user.
* 1 : [UMS] Getting firmware from sd card.
* 2 : none
* 3 : [FFU] Getting firmware from air.
*/
switch (update_type) {
case BUILT_IN:
ret = sec_ts_firmware_update_on_probe(ts);
break;
case UMS:
ret = sec_ts_load_fw_from_ums(ts);
break;
case FFU:
input_err(true, ts->dev, "%s: Not support yet\n", __func__);
break;
default:
input_err(true, ts->dev, "%s: Not support command[%d]\n", __func__,
update_type);
break;
}
return ret;
}
EXPORT_SYMBOL(sec_ts_firmware_update_on_hidden_menu);