android_kernel_samsung_hero.../drivers/input/wacom/wacom_i2c_flash.c
2016-08-17 16:41:52 +08:00

802 lines
19 KiB
C

/*
* wacom_i2c_flash.c - Wacom G5 Digitizer Controller (I2C bus)
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "wacom_i2c.h"
#include "wacom_i2c_flash.h"
static int wacom_enter_flash_mode(struct wacom_i2c *wac_i2c)
{
int ret, len = 0;
char buf[8];
dev_info(&wac_i2c->client->dev, "%s\n", __func__);
memset(buf, 0, 8);
strncpy(buf, "\rflash\r", 7);
len = sizeof(buf) / sizeof(buf[0]);
ret = wac_i2c->wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
if (ret < 0) {
dev_err(&wac_i2c->client->dev,
"%s: Sending flash command failed, %d\n",
__func__, ret);
return ret;
}
msleep(300);
return 0;
}
static int wacom_set_cmd_feature(struct wacom_i2c *wac_i2c)
{
int ret, len = 0;
u8 buf[4];
usleep_range(60, 61);
buf[len++] = 4;
buf[len++] = 0;
buf[len++] = 0x37;
buf[len++] = CMD_SET_FEATURE;
ret = wac_i2c->wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
if (ret < 0)
dev_err(&wac_i2c->client->dev,
"%s: failed send CMD_SET_FEATURE, %d\n",
__func__, ret);
usleep_range(60, 61);
return ret;
}
static int wacom_get_cmd_feature(struct wacom_i2c *wac_i2c)
{
int ret, len = 0;
u8 buf[6];
usleep_range(60, 61);
buf[len++] = 4;
buf[len++] = 0;
buf[len++] = 0x38;
buf[len++] = CMD_GET_FEATURE;
buf[len++] = 5;
buf[len++] = 0;
ret = wac_i2c->wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
if (ret < 0)
dev_err(&wac_i2c->client->dev,
"%s: failed send CMD_GET_FEATURE, ret: %d\n",
__func__, ret);
usleep_range(60, 61);
return ret;
}
/*
* mode1. BOOT_QUERY: check enter boot mode for flash.
* mode2. BOOT_BLVER : check bootloader version.
* mode3. BOOT_MPU : check MPU version
*/
int wacom_check_flash_mode(struct wacom_i2c *wac_i2c, int mode)
{
int ret, ECH;
unsigned char response_cmd = 0;
unsigned char command[CMD_SIZE];
unsigned char response[RSP_SIZE];
switch (mode) {
case BOOT_QUERY:
response_cmd = QUERY_CMD;
break;
case BOOT_BLVER:
response_cmd = BOOT_CMD;
break;
case BOOT_MPU:
response_cmd = MPU_CMD;
break;
default:
break;
}
dev_info(&wac_i2c->client->dev, "%s, mode = %s\n", __func__,
(mode == BOOT_QUERY) ? "BOOT_QUERY" :
(mode == BOOT_BLVER) ? "BOOT_BLVER" :
(mode == BOOT_MPU) ? "BOOT_MPU" : "Not Support");
ret = wacom_set_cmd_feature(wac_i2c);
if (ret < 0)
return ret;
command[0] = 5;
command[1] = 0;
command[2] = 5;
command[3] = 0;
command[4] = BOOT_CMD_REPORT_ID;
command[5] = mode;
command[6] = ECH = 7;
ret = wac_i2c->wacom_i2c_send(wac_i2c, command, 7, WACOM_I2C_MODE_BOOT);
if (ret < 0) {
dev_err(&wac_i2c->client->dev,
"%s: failed send REPORT_ID, %d\n",
__func__, ret);
return ret;
}
ret = wacom_get_cmd_feature(wac_i2c);
if (ret < 0)
return ret;
ret = wac_i2c->wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE,
WACOM_I2C_MODE_BOOT);
if (ret < 0) {
dev_err(&wac_i2c->client->dev,
"%s: failed receive response, %d\n",
__func__, ret);
return ret;
}
if ((response[3] != response_cmd) || (response[4] != ECH)) {
dev_err(&wac_i2c->client->dev,
"%s: failed matching response3[%x], 4[%x]\n",
__func__, response[3], response[4]);
return -EIO;
}
return response[5];
}
int wacom_enter_bootloader(struct wacom_i2c *wac_i2c)
{
int ret;
int retry = 0;
dev_info(&wac_i2c->client->dev, "%s\n", __func__);
ret = wacom_enter_flash_mode(wac_i2c);
if (ret < 0)
msleep(500);
do {
msleep(100);
ret = wacom_check_flash_mode(wac_i2c, BOOT_QUERY);
if (ret == QUERY_RSP)
dev_info(&wac_i2c->client->dev, "%s: enter flash mode\n", __func__);
else
dev_err(&wac_i2c->client->dev, "%s: retry BOOT_QUERY\n", __func__);
retry++;
} while (ret < 0 && retry < 10);
if (ret < 0)
return -EXIT_FAIL_GET_BOOT_LOADER_VERSION;
ret = wacom_check_flash_mode(wac_i2c, BOOT_MPU);
wac_i2c->boot_ver = ret;
if (ret < 0)
return -EXIT_FAIL_GET_BOOT_LOADER_VERSION;
dev_info(&wac_i2c->client->dev, "%s: MPU:%X\n", __func__, wac_i2c->boot_ver);
return ret;
}
static int wacom_flash_end(struct wacom_i2c *wac_i2c)
{
int ret, ECH;
unsigned char command[CMD_SIZE];
dev_info(&wac_i2c->client->dev, "%s\n", __func__);
command[0] = 4;
command[1] = 0;
command[2] = 0x37;
command[3] = CMD_SET_FEATURE;
command[4] = 5;
command[5] = 0;
command[6] = 5;
command[7] = 0;
command[8] = BOOT_CMD_REPORT_ID;
command[9] = BOOT_EXIT;
/* command[10] = ECH = 7;*/
command[10] = ECH = 0;
ret = wac_i2c->wacom_i2c_send(wac_i2c, command, 11, WACOM_I2C_MODE_BOOT);
if (ret < 0)
dev_err(&wac_i2c->client->dev,
"%s failed, %d\n",
__func__, ret);
return ret;
}
static bool erase_datamem(struct wacom_i2c *wac_i2c)
{
u8 command[CMD_SIZE];
u8 response[BOOT_RSP_SIZE];
unsigned char sum = 0;
unsigned char cmd_chksum;
int ret, ECH, j;
int len = 0;
dev_info(&wac_i2c->client->dev, "%s\n", __func__);
command[len++] = 4; /* Command Register-LSB */
command[len++] = 0; /* Command Register-MSB */
command[len++] = 0x37; /* Command-LSB, ReportType:Feature(11) ReportID:7 */
command[len++] = CMD_SET_FEATURE; /* Command-MSB, SET_REPORT */
command[len++] = 5; /* Data Register-LSB */
command[len++] = 0; /* Data-Register-MSB */
command[len++] = 0x07; /* Length Field-LSB */
command[len++] = 0; /* Length Field-MSB */
command[len++] = BOOT_CMD_REPORT_ID; /* Report:ReportID */
command[len++] = BOOT_ERASE_DATAMEM; /* Report:erase datamem command */
command[len++] = ECH = BOOT_ERASE_DATAMEM; /* Report:echo */
command[len++] = DATAMEM_SECTOR0; /* Report:erased block No. */
sum = 0;
for (j = 4; j < 12; j++)
sum += command[j];
cmd_chksum = ~sum + 1; /* Report:check sum */
command[len++] = cmd_chksum;
udelay(50);
ret = wac_i2c->wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT);
if (ret < 0) {
dev_err(&wac_i2c->client->dev, "%s: failing 1: %d \n", __func__, ret);
return false;
}
udelay(50);
do {
len = 0;
command[len++] = 4;
command[len++] = 0;
command[len++] = 0x38;
command[len++] = CMD_GET_FEATURE;
command[len++] = 5;
command[len++] = 0;
ret = wac_i2c->wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT);
if (ret < 0) {
dev_err(&wac_i2c->client->dev, "%s: failing 2:%d \n", __func__, ret);
return false;
}
udelay(50);
ret = wac_i2c->wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE, WACOM_I2C_MODE_BOOT);
if (ret < 0) {
dev_err(&wac_i2c->client->dev, "%s: failing 3:%d \n", __func__, ret);
return false;
}
if ((response[3] != 0x0e || response[4] != ECH) || (response[5] != 0xff && response[5] != 0x00))
return false;
udelay(50);
} while (response[3] == 0x0e && response[4] == ECH && response[5] == 0xff);
msleep(50);
return true;
}
static bool erase_codemem(struct wacom_i2c *wac_i2c, int *eraseBlock, int num)
{
u8 command[CMD_SIZE];
u8 response[BOOT_RSP_SIZE];
unsigned char sum = 0;
unsigned char cmd_chksum;
int ret, ECH;
int len = 0;
int i, j;
dev_info(&wac_i2c->client->dev,
"%s: total erase code-block number = %d\n", __func__, num);
for (i = 0; i < num; i++) {
len = 0;
command[len++] = 4; /* Command Register-LSB */
command[len++] = 0; /* Command Register-MSB */
command[len++] = 0x37; /* Command-LSB, ReportType:Feature(11) ReportID:7 */
command[len++] = CMD_SET_FEATURE; /* Command-MSB, SET_REPORT */
command[len++] = 5; /* Data Register-LSB */
command[len++] = 0; /* Data-Register-MSB */
command[len++] = 7; /* Length Field-LSB */
command[len++] = 0; /* Length Field-MSB */
command[len++] = BOOT_CMD_REPORT_ID; /* Report:ReportID */
command[len++] = BOOT_ERASE_FLASH; /* Report:erase command */
command[len++] = ECH = i; /* Report:echo */
command[len++] = *eraseBlock; /* Report:erased block No. */
eraseBlock++;
sum = 0;
for (j = 4; j < 12; j++)
sum += command[j];
cmd_chksum = ~sum + 1; /* Report:check sum */
command[len++] = cmd_chksum;
udelay(50);
ret = wac_i2c->wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT);
if (ret < 0) {
dev_err(&wac_i2c->client->dev, "%s: failing 1:%d \n", __func__, i);
return false;
}
udelay(50);
do {
len = 0;
command[len++] = 4;
command[len++] = 0;
command[len++] = 0x38;
command[len++] = CMD_GET_FEATURE;
command[len++] = 5;
command[len++] = 0;
ret = wac_i2c->wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT);
if (ret < 0) {
dev_err(&wac_i2c->client->dev, "%s: failing 2:%d \n", __func__, i);
return false;
}
udelay(50);
ret = wac_i2c->wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE,
WACOM_I2C_MODE_BOOT);
if (ret < 0) {
printk("%s failing 3:%d \n", __func__, i);
return false;
}
if ((response[3] != 0x00 || response[4] != ECH) || (response[5] != 0xff && response[5] != 0x00))
return false;
udelay(50);
} while (response[3] == 0x00 && response[4] == ECH && response[5] == 0xff);
udelay(50);
}
msleep(50);
return true;
}
static bool flash_erase_w9012(struct wacom_i2c *wac_i2c, int *eraseBlock, int num)
{
bool ret;
ret = erase_datamem(wac_i2c);
if (!ret) {
dev_err(&wac_i2c->client->dev, "%s: erasing datamem failed\n",
__func__);
return false;
}
ret = erase_codemem(wac_i2c, eraseBlock, num);
if (!ret) {
dev_err(&wac_i2c->client->dev, "%s: erasing codemem failed\n",
__func__);
return false;
}
return true;
}
static bool flash_write_block_w9012(struct wacom_i2c *wac_i2c, char *flash_data,
unsigned long ulAddress, u8 *pcommand_id, int *ECH)
{
const int MAX_COM_SIZE = (16 + FLASH_BLOCK_SIZE + 2);
/* 16: num of command[0] to command[15]
** FLASH_BLOCK_SIZE: unit to erase the block
** Num of Last 2 checksums
*/
u8 command[300];
unsigned char sum = 0;
int ret, i;
command[0] = 4; /* Command Register-LSB */
command[1] = 0; /* Command Register-MSB */
command[2] = 0x37; /* Command-LSB, ReportType:Feature(11) ReportID:7 */
command[3] = CMD_SET_FEATURE; /* Command-MSB, SET_REPORT */
command[4] = 5; /* Data Register-LSB */
command[5] = 0; /* Data-Register-MSB */
command[6] = 76; /* Length Field-LSB */
command[7] = 0; /* Length Field-MSB */
command[8] = BOOT_CMD_REPORT_ID; /* Report:ReportID */
command[9] = BOOT_WRITE_FLASH; /* Report:program command */
command[10] = *ECH = ++(*pcommand_id); /* Report:echo */
command[11] = ulAddress & 0x000000ff;
command[12] = (ulAddress & 0x0000ff00) >> 8;
command[13] = (ulAddress & 0x00ff0000) >> 16;
command[14] = (ulAddress & 0xff000000) >> 24; /* Report:address(4bytes) */
command[15] = 8; /* Report:size(8*8=64) */
sum = 0;
for (i = 4; i < 16; i++)
sum += command[i];
command[MAX_COM_SIZE - 2] = ~sum+1; /* Report:command checksum */
sum = 0;
for (i = 16; i < (FLASH_BLOCK_SIZE + 16); i++) {
command[i] = flash_data[ulAddress+(i-16)];
sum += flash_data[ulAddress+(i-16)];
}
command[MAX_COM_SIZE - 1] = ~sum+1; /* Report:data checksum */
udelay(50);
ret = wac_i2c->wacom_i2c_send(wac_i2c, command,
(BOOT_CMD_SIZE + 4), WACOM_FLASH_W9012);
if (ret < 0) {
dev_err(&wac_i2c->client->dev, "%s: 1 ret:%d \n",
__func__, ret);
return false;
}
udelay(50);
return true;
}
static bool flash_write_w9012(struct wacom_i2c *wac_i2c, unsigned char *flash_data,
unsigned long start_address, unsigned long *max_address)
{
u8 command_id = 0;
u8 command[BOOT_RSP_SIZE];
u8 response[BOOT_RSP_SIZE];
int ret, i, j, len, ECH = 0, ECH_len = 0;
int ECH_ARRAY[3];
unsigned long ulAddress;
dev_info(&wac_i2c->client->dev, "%s\n", __func__);
j = 0;
for (ulAddress = start_address; ulAddress < *max_address;
ulAddress += FLASH_BLOCK_SIZE) {
for (i = 0; i < FLASH_BLOCK_SIZE; i++) {
if (flash_data[ulAddress+i] != 0xFF)
break;
}
if (i == (FLASH_BLOCK_SIZE))
continue;
if (!flash_write_block_w9012(wac_i2c,
flash_data, ulAddress, &command_id, &ECH))
return false;
if (ECH_len == 3)
ECH_len = 0;
ECH_ARRAY[ECH_len++] = ECH;
if (ECH_len == 3) {
for (j = 0; j < 3; j++) {
do {
len = 0;
command[len++] = 4;
command[len++] = 0;
command[len++] = 0x38;
command[len++] = CMD_GET_FEATURE;
command[len++] = 5;
command[len++] = 0;
udelay(50);
ret = wac_i2c->wacom_i2c_send(wac_i2c,
command, len, WACOM_FLASH_W9012);
if (ret < 0) {
dev_err(&wac_i2c->client->dev,
"%s: failing 2:%d; system returning: %d\n",
__func__, i, ret);
return false;
}
udelay(50);
ret = wac_i2c->wacom_i2c_recv(wac_i2c,
response, BOOT_RSP_SIZE, WACOM_FLASH_W9012);
if (ret < 0) {
dev_err(&wac_i2c->client->dev,
"%s: failing 3:%d system returning %d \n",
__func__, i, ret);
return false;
}
if ((response[3] != 0x01 || response[4] != ECH_ARRAY[j])
|| (response[5] != 0xff && response[5] != 0x00))
return false;
udelay(50);
} while (response[3] == 0x01 && response[4]
== ECH_ARRAY[j] && response[5] == 0xff);
}
}
}
return true;
}
int wacom_i2c_flash(struct wacom_i2c *wac_i2c)
{
unsigned long max_address = 0;
unsigned long start_address;
int i, ret = 0;
int eraseBlock[200], eraseBlockNum;
if (wac_i2c->ic_mpu_ver != MPU_W9007 && wac_i2c->ic_mpu_ver != MPU_W9010 && wac_i2c->ic_mpu_ver != MPU_W9012)
return -EXIT_FAIL_GET_MPU_TYPE;
wac_i2c->compulsory_flash_mode(wac_i2c, true);
/*Reset*/
wac_i2c->reset_platform_hw(wac_i2c);
msleep(300);
dev_err(&wac_i2c->client->dev, "%s: Set FWE\n", __func__);
ret = wacom_enter_bootloader(wac_i2c);
if (ret < 0) {
dev_err(&wac_i2c->client->dev,
"%s: failed to enter bootloader mode\n", __func__);
goto flashing_fw_err;
}
dev_err(&wac_i2c->client->dev,
"%s: enter bootloader mode, erase & writing firmware\n", __func__);
/*Set start and end address and block numbers*/
eraseBlockNum = 0;
start_address = START_ADDR_W9012;
max_address = MAX_ADDR_W9012;
for (i = BLOCK_NUM_W9012; i >= 8; i--) {
eraseBlock[eraseBlockNum] = i;
eraseBlockNum++;
}
/*Erase the old program code */
if (!flash_erase_w9012(wac_i2c, eraseBlock, eraseBlockNum)) {
dev_err(&wac_i2c->client->dev,
"%s: failed erase old firmware, %d\n",
__func__, ret);
goto flashing_fw_err;
}
/*Write the new program */
if (!flash_write_w9012(wac_i2c, wac_i2c->fw_data,
start_address, &max_address)) {
dev_err(&wac_i2c->client->dev,
"%s: failed writing new firmware, %d\n",
__func__, ret);
goto flashing_fw_err;
}
/*Enable */
ret = wacom_flash_end(wac_i2c);
if (ret < 0) {
dev_err(&wac_i2c->client->dev,
"%s: failed flash mode close, %d\n",
__func__, ret);
goto flashing_fw_err;
}
dev_err(&wac_i2c->client->dev,
"%s: Successed new Firmware writing\n",
__func__);
flashing_fw_err:
wac_i2c->compulsory_flash_mode(wac_i2c, false);
msleep(150);
return ret;
}
int wacom_i2c_firm_update(struct wacom_i2c *wac_i2c)
{
int ret = 0;
int retry = 3;
while (retry--) {
ret = wacom_i2c_flash(wac_i2c);
if (ret < 0)
dev_err(&wac_i2c->client->dev,
"%s: failed to write firmware(%d)\n",
__func__, ret);
else
dev_err(&wac_i2c->client->dev,
"%s: Successed to write firmware(%d)\n",
__func__, ret);
/* Reset IC */
wac_i2c->reset_platform_hw(wac_i2c);
if (ret >= 0)
return 0;
}
return ret;
}
int wacom_fw_load_from_UMS(struct wacom_i2c *wac_i2c)
{
struct file *fp;
mm_segment_t old_fs;
long fsize, nread;
int ret = 0;
const struct firmware *firm_data = NULL;
dev_info(&wac_i2c->client->dev,
"%s: Start firmware flashing (UMS).\n", __func__);
old_fs = get_fs();
set_fs(KERNEL_DS);
fp = filp_open(WACOM_UMS_FW_PATH, O_RDONLY, S_IRUSR);
if (IS_ERR(fp)) {
dev_err(&wac_i2c->client->dev,
"%s: failed to open %s.\n",
__func__, WACOM_UMS_FW_PATH);
ret = -ENOENT;
goto open_err;
}
fsize = fp->f_path.dentry->d_inode->i_size;
dev_info(&wac_i2c->client->dev,
"%s: start, file path %s, size %ld Bytes\n",
__func__, WACOM_UMS_FW_PATH, fsize);
firm_data = kzalloc(fsize, GFP_KERNEL);
if (IS_ERR(firm_data)) {
dev_err(&wac_i2c->client->dev,
"%s, kmalloc failed\n", __func__);
ret = -EFAULT;
goto malloc_error;
}
nread = vfs_read(fp, (char __user *)firm_data,
fsize, &fp->f_pos);
dev_info(&wac_i2c->client->dev,
"%s: nread %ld Bytes\n", __func__, nread);
if (nread != fsize) {
dev_err(&wac_i2c->client->dev,
"%s: failed to read firmware file, nread %ld Bytes\n",
__func__, nread);
ret = -EIO;
goto read_err;
}
filp_close(fp, current->files);
set_fs(old_fs);
/*start firm update*/
wac_i2c->fw_data=(unsigned char *)firm_data;
return 0;
read_err:
kfree(firm_data);
malloc_error:
filp_close(fp, current->files);
open_err:
set_fs(old_fs);
return ret;
}
int wacom_load_fw_from_req_fw(struct wacom_i2c *wac_i2c)
{
int ret = 0;
const struct firmware *firm_data = NULL;
char fw_path[WACOM_MAX_FW_PATH];
dev_info(&wac_i2c->client->dev, "%s\n", __func__);
/*Obtain MPU type: this can be manually done in user space */
dev_info(&wac_i2c->client->dev,
"%s: MPU type: %x , BOOT ver: %x\n",
__func__, wac_i2c->ic_mpu_ver, wac_i2c->boot_ver);
memset(&fw_path, 0, WACOM_MAX_FW_PATH);
if (wac_i2c->ic_mpu_ver == MPU_W9012) {
snprintf(fw_path, WACOM_MAX_FW_PATH,
"%s", WACOM_FW_NAME_W9012);
} else {
dev_info(&wac_i2c->client->dev,
"%s: firmware name is NULL. return -1\n",
__func__);
ret = -ENOENT;
goto firm_name_null_err;
}
ret = request_firmware(&firm_data, fw_path, &wac_i2c->client->dev);
if (ret < 0) {
dev_err(&wac_i2c->client->dev,
"%s: Unable to open firmware. ret %d\n",
__func__, ret);
goto request_firm_err;
}
dev_info(&wac_i2c->client->dev, "%s: firmware name: %s, size: %d\n",
__func__, fw_path, (int)firm_data->size);
/* firmware version check */
if (wac_i2c->ic_mpu_ver == MPU_W9010 || wac_i2c->ic_mpu_ver == MPU_W9007 || wac_i2c->ic_mpu_ver == MPU_W9012)
wac_i2c->wac_query_data->fw_version_bin =
(firm_data->data[FIRM_VER_LB_ADDR_W9012] |
(firm_data->data[FIRM_VER_UB_ADDR_W9012] << 8));
dev_info(&wac_i2c->client->dev, "%s: firmware version = %x\n",
__func__, wac_i2c->wac_query_data->fw_version_bin);
wac_i2c->fw_data=(unsigned char *)firm_data->data;
release_firmware(firm_data);
firm_name_null_err:
request_firm_err:
return ret;
}
int wacom_i2c_usermode(struct wacom_i2c *wac_i2c)
{
int ret;
bool bRet = false;
wac_i2c->compulsory_flash_mode(wac_i2c, true);
ret = wacom_enter_flash_mode(wac_i2c);
if (ret < 0) {
dev_err(&wac_i2c->client->dev,
"%s cannot send flash command at user-mode \n",
__func__);
return ret;
}
/*Return to the user mode */
dev_info(&wac_i2c->client->dev,
"%s closing the boot mode \n", __func__);
bRet = wacom_flash_end(wac_i2c);
if (!bRet) {
dev_err(&wac_i2c->client->dev,
"%s closing boot mode failed \n", __func__);
ret = -EXIT_FAIL_WRITING_MARK_NOT_SET;
goto end_usermode;
}
wac_i2c->compulsory_flash_mode(wac_i2c, false);
dev_info(&wac_i2c->client->dev,
"%s making user-mode completed \n", __func__);
ret = EXIT_OK;
end_usermode:
return ret;
}