You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
kernel_samsung_sm7125/drivers/input/touchscreen/imagis_40xx/ist40xx_sys.c

870 lines
20 KiB

/*
* Copyright (C) 2010,Imagis Technology Co. Ltd. All Rights Reserved.
*
* 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.
*
*/
#include <asm/io.h>
#include <asm/unaligned.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/machine.h>
#include "ist40xx.h"
#include "ist40xx_update.h"
#ifdef CONFIG_TRUSTONIC_TRUSTED_UI
#include <linux/trustedui.h>
#endif
/******************************************************************************
* Return value of Error
* EPERM : 1 (Operation not permitted)
* ENOENT : 2 (No such file or directory)
* EIO : 5 (I/O error)
* ENXIO : 6 (No such device or address)
* EINVAL : 22 (Invalid argument)
*****************************************************************************/
int ist40xx_write_sponge_reg(struct ist40xx_data *data, u16 idx, u16 *buf16,
int len, bool hold)
{
int i;
int ret = -EIO;
if (hold)
ist40xx_cmd_hold(data, IST40XX_ENABLE);
data->ignore_delay = true;
for (i = 0; i < len; i++) {
ret = ist40xx_write_cmd(data, IST40XX_HIB_CMD,
(eHCOM_SET_SP_REG_IDX << 16) | (idx + (sizeof(u16) * i)));
if (ret) {
input_err(true, &data->client->dev, "%s: fail to write idx\n",
__func__);
goto err_write_sponge_reg;
}
ist40xx_delay(1);
ret = ist40xx_write_cmd(data, IST40XX_HIB_CMD,
(eHCOM_SET_SP_REG_W_DATA << 16) | *(buf16 + i));
if (ret) {
input_err(true, &data->client->dev, "%s: fail to write data\n",
__func__);
goto err_write_sponge_reg;
}
}
err_write_sponge_reg:
data->ignore_delay = false;
if (hold)
ist40xx_cmd_hold(data, IST40XX_DISABLE);
ist40xx_delay(1);
return ret;
}
int ist40xx_read_sponge_reg(struct ist40xx_data *data, u16 idx, u16 *buf16,
int len, bool hold)
{
int i;
int ret = -EIO;
u32 rdata = 0;
if (hold)
ist40xx_cmd_hold(data, IST40XX_ENABLE);
data->ignore_delay = true;
for (i = 0; i < len; i++) {
ret = ist40xx_write_cmd(data, IST40XX_HIB_CMD,
(eHCOM_SET_SP_REG_IDX << 16) | (idx + (sizeof(u16) * i)));
if (ret) {
input_err(true, &data->client->dev, "%s: fail to write idx\n",
__func__);
goto err_read_sponge_reg;
}
ist40xx_delay(1);
ret = ist40xx_read_reg(data->client, IST40XX_SPONGE_REG_R_DATA,
&rdata);
if (ret) {
input_err(true, &data->client->dev, "%s: fail to read data\n",
__func__);
goto err_read_sponge_reg;
}
*(buf16 + i) = rdata & 0xFFFF;
}
err_read_sponge_reg:
data->ignore_delay = false;
if (hold)
ist40xx_cmd_hold(data, IST40XX_DISABLE);
ist40xx_delay(1);
return ret;
}
int ist40xx_cmd_gesture(struct ist40xx_data *data, u16 value)
{
int ret = -EIO;
struct timeval utc_time;
mutex_lock(&data->aod_lock);
ret = ist40xx_write_cmd(data, IST40XX_HIB_INTR_MSG, IST40XX_LPM_VALUE);
if (ret)
input_err(true, &data->client->dev, "fail to write LPM TAG value.\n");
if (value == IST40XX_ENABLE) {
input_info(true, &data->client->dev, "%s\n", __func__);
ist40xx_set_halfaod_mode(data->prox_power_off);
do_gettimeofday(&utc_time);
input_info(true, &data->client->dev, "Write UTC to Sponge = %X\n",
(int)utc_time.tv_sec);
ist40xx_cmd_hold(data, IST40XX_ENABLE);
ist40xx_write_sponge_reg(data, IST40XX_SPONGE_CTRL,
(u16*)&data->lpm_mode, 1, false);
ist40xx_write_sponge_reg(data, IST40XX_SPONGE_UTC,
(u16 *)&utc_time.tv_sec, 2, false);
ist40xx_write_sponge_reg(data, IST40XX_SPONGE_RECT, data->rect_data,
4, false);
data->ignore_delay = true;
ist40xx_write_cmd(data, IST40XX_HIB_CMD,
(eHCOM_NOTIRY_G_REGMAP << 16) | IST40XX_ENABLE);
data->ignore_delay = false;
ist40xx_cmd_hold(data, IST40XX_DISABLE);
}
ret = ist40xx_write_cmd(data, IST40XX_HIB_CMD,
(eHCOM_GESTURE_EN << 16) | (value & 0xFFFF));
if (ret) {
input_err(true, &data->client->dev, "fail to write gesture command.\n");
} else {
if (value == IST40XX_ENABLE) {
input_info(true, &data->client->dev,
"%s: spay : %d, aod : %d, singletap : %d, aot : %d\n", __func__,
(data->lpm_mode & IST40XX_SPAY) ? 1 : 0,
(data->lpm_mode & IST40XX_AOD) ? 1 : 0,
(data->lpm_mode & IST40XX_SINGLETAP) ? 1 : 0,
(data->lpm_mode & IST40XX_DOUBLETAP_WAKEUP) ? 1 : 0);
} else {
input_err(true, &data->client->dev, "%s: normal mode\n",
__func__);
}
}
mutex_unlock(&data->aod_lock);
return ret;
}
int ist40xx_cmd_start_scan(struct ist40xx_data *data)
{
int ret = ist40xx_write_cmd(data, IST40XX_HIB_CMD,
(eHCOM_FW_START << 16) | (IST40XX_ENABLE & 0xFFFF));
data->status.noise_mode = true;
return ret;
}
int ist40xx_cmd_calibrate(struct ist40xx_data *data)
{
int ret = ist40xx_write_cmd(data, IST40XX_HIB_CMD,
(eHCOM_RUN_CAL_AUTO << 16));
input_info(true, &data->client->dev, "%s\n", __func__);
return ret;
}
int ist40xx_cmd_miscalibrate(struct ist40xx_data *data)
{
int ret = ist40xx_write_cmd(data, IST40XX_HIB_CMD,
(eHCOM_RUN_CAL_MIS << 16) | (IST40XX_ENABLE & 0xFFFF));
input_info(true, &data->client->dev, "%s\n", __func__);
return ret;
}
int ist40xx_cmd_hold(struct ist40xx_data *data, int enable)
{
int ret;
if (!data->initialized || (data->status.update == 1))
return 0;
ret = ist40xx_write_cmd(data, IST40XX_HIB_CMD,
(eHCOM_FW_HOLD << 16) | (enable & 0xFFFF));
input_info(true, &data->client->dev, "%s: FW HOLDE %s\n", __func__,
enable ? "Enable" : "Disable");
return ret;
}
int ist40xx_i2c_transfer(struct i2c_client *client, struct i2c_msg *msgs,
int msg_num, u8 *cmd_buf)
{
int ret = 0;
int idx = msg_num - 1;
int size = msgs[idx].len;
u8 *msg_buf = NULL;
u8 *pbuf = NULL;
int trans_size, max_size = 0;
#ifdef CONFIG_INPUT_SEC_SECURE_TOUCH
struct ist40xx_data *data = i2c_get_clientdata(client);
if (atomic_read(&data->st_enabled) == SECURE_TOUCH_ENABLED) {
input_err(true, &client->dev,
"%s: TSP no accessible from Linux, TUI is enabled!\n",
__func__);
return -EBUSY;
}
#endif
#ifdef CONFIG_TRUSTONIC_TRUSTED_UI
if (TRUSTEDUI_MODE_INPUT_SECURED & trustedui_get_current_mode()) {
input_err(true, &client->dev, "%s: TSP no accessible from Linux, TUI is enabled!\n",
__func__);
return -EIO;
}
#endif
if (msg_num == WRITE_CMD_MSG_LEN)
max_size = I2C_MAX_WRITE_SIZE;
else if (msg_num == READ_CMD_MSG_LEN)
max_size = I2C_MAX_READ_SIZE;
if (max_size == 0) {
input_err(true, &client->dev, "%s: transaction size(%d)\n",
__func__, max_size);
return -EINVAL;
}
if (msg_num == WRITE_CMD_MSG_LEN) {
msg_buf = kmalloc(max_size + IST40XX_ADDR_LEN, GFP_KERNEL);
if (!msg_buf)
return -ENOMEM;
memcpy(msg_buf, cmd_buf, IST40XX_ADDR_LEN);
pbuf = msgs[idx].buf;
}
while (size > 0) {
trans_size = (size >= max_size ? max_size : size);
msgs[idx].len = trans_size;
if (msg_num == WRITE_CMD_MSG_LEN) {
memcpy(&msg_buf[IST40XX_ADDR_LEN], pbuf, trans_size);
msgs[idx].buf = msg_buf;
msgs[idx].len += IST40XX_ADDR_LEN;
}
ret = i2c_transfer(client->adapter, msgs, msg_num);
if (ret != msg_num) {
input_err(true, &client->dev,
"%s: i2c_transfer failed(%d), num=%d\n",
__func__, ret, msg_num);
break;
}
/*
{
int i;
pr_info("sec_input: I2C: %s\n", __func__);
pr_info("sec_input: I2C: W: ");
for (i = 0; i < msgs[0].len; i++) {
pr_cont("%02X ", msgs[0].buf[i]);
}
pr_cont("\n");
if (msg_num > 1) {
pr_info("sec_input: I2C: R: ");
for (i = 0; i < msgs[1].len; i++) {
pr_cont("%02X ", msgs[1].buf[i]);
}
pr_cont("\n");
}
}
*/
if (msg_num == WRITE_CMD_MSG_LEN)
pbuf += trans_size;
else
msgs[idx].buf += trans_size;
size -= trans_size;
}
if (msg_num == WRITE_CMD_MSG_LEN)
kfree(msg_buf);
return ret;
}
int ist40xx_read_buf(struct i2c_client *client, u32 cmd, u32 *buf, u16 len)
{
struct ist40xx_data *data = i2c_get_clientdata(client);
int ret, i;
u32 le_reg = cpu_to_be32(cmd);
u32 *msg_buf = NULL;
u8 *t_u8_reg;
struct i2c_msg msg[READ_CMD_MSG_LEN] = {
{
.addr = client->addr,
.flags = 0,
.len = IST40XX_ADDR_LEN,
// .buf = (u8 *)&le_reg,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len * IST40XX_DATA_LEN,
},
};
t_u8_reg = kzalloc(4, GFP_KERNEL);
if (!t_u8_reg)
return -ENOMEM;
t_u8_reg[3] = (u8)((le_reg >> 24) & 0xFF);
t_u8_reg[2] = (u8)((le_reg >> 16) & 0xFF);
t_u8_reg[1] = (u8)((le_reg >> 8) & 0xFF);
t_u8_reg[0] = (u8)(le_reg & 0xFF);
msg[0].buf = t_u8_reg;
if (data->status.sys_mode == STATE_POWER_OFF) {
input_err(true, &client->dev,
"%s: now sys_mode status is STATE_POWER_OFF!\n", __func__);
kfree(t_u8_reg);
return -ENODEV;
}
mutex_lock(&data->i2c_lock);
msg_buf = kmalloc(len * IST40XX_DATA_LEN, GFP_KERNEL);
memcpy(msg_buf, buf, len * IST40XX_DATA_LEN);
msg[1].buf = (u8 *)msg_buf;
ret = ist40xx_i2c_transfer(client, msg, READ_CMD_MSG_LEN, NULL);
if (ret != READ_CMD_MSG_LEN) {
data->comm_err_count++;
kfree(msg_buf);
kfree(t_u8_reg);
mutex_unlock(&data->i2c_lock);
return -EIO;
}
for (i = 0; i < len; i++)
msg_buf[i] = cpu_to_be32(msg_buf[i]);
memcpy(buf, msg_buf, len * IST40XX_DATA_LEN);
kfree(msg_buf);
kfree(t_u8_reg);
mutex_unlock(&data->i2c_lock);
return 0;
}
int ist40xx_write_buf(struct i2c_client *client, u32 cmd, u32 *buf, u16 len)
{
struct ist40xx_data *data = i2c_get_clientdata(client);
int i;
int ret;
struct i2c_msg msg;
u8 *cmd_buf = NULL;
u8 *msg_buf = NULL;
if (data->status.sys_mode == STATE_POWER_OFF) {
input_err(true, &client->dev,
"%s: now sys_mode status is STATE_POWER_OFF!\n", __func__);
return -ENODEV;
}
cmd_buf = kmalloc(IST40XX_DATA_LEN, GFP_KERNEL);
msg_buf = kmalloc((len + 1) * IST40XX_DATA_LEN, GFP_KERNEL);
put_unaligned_be32(cmd, cmd_buf);
if (len > 0) {
for (i = 0; i < len; i++)
put_unaligned_be32(buf[i], msg_buf + (i * IST40XX_DATA_LEN));
} else {
/* then add dummy data(4byte) */
put_unaligned_be32(0, msg_buf);
len = 1;
}
msg.addr = client->addr;
msg.flags = 0;
msg.len = len * IST40XX_DATA_LEN;
msg.buf = msg_buf;
mutex_lock(&data->i2c_lock);
ret = ist40xx_i2c_transfer(client, &msg, WRITE_CMD_MSG_LEN,
cmd_buf);
if (ret != WRITE_CMD_MSG_LEN) {
data->comm_err_count++;
mutex_unlock(&data->i2c_lock);
kfree(cmd_buf);
kfree(msg_buf);
return -EIO;
}
mutex_unlock(&data->i2c_lock);
kfree(cmd_buf);
kfree(msg_buf);
return 0;
}
int ist40xx_read_reg(struct i2c_client *client, u32 reg, u32 *buf)
{
struct ist40xx_data *data = i2c_get_clientdata(client);
int ret;
u32 le_reg = cpu_to_be32(reg);
u32 *msg_buf = NULL;
u8 *t_u8_reg;
struct i2c_msg msg[READ_CMD_MSG_LEN] = {
{
.addr = client->addr,
.flags = 0,
.len = IST40XX_ADDR_LEN,
// .buf = (u8 *)&le_reg,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = IST40XX_DATA_LEN,
},
};
t_u8_reg = kzalloc(4, GFP_KERNEL);
if (!t_u8_reg)
return -ENOMEM;
t_u8_reg[3] = (u8)((le_reg >> 24) & 0xFF);
t_u8_reg[2] = (u8)((le_reg >> 16) & 0xFF);
t_u8_reg[1] = (u8)((le_reg >> 8) & 0xFF);
t_u8_reg[0] = (u8)(le_reg & 0xFF);
msg[0].buf = t_u8_reg;
if (data->status.sys_mode == STATE_POWER_OFF) {
input_err(true, &client->dev,
"%s: now sys_mode status is STATE_POWER_OFF!\n", __func__);
kfree(t_u8_reg);
return -ENODEV;
}
#ifdef CONFIG_INPUT_SEC_SECURE_TOUCH
if (atomic_read(&data->st_enabled) == SECURE_TOUCH_ENABLED) {
input_err(true, &client->dev,
"%s: TSP no accessible from Linux, TUI is enabled!\n",
__func__);
kfree(t_u8_reg);
return -EBUSY;
}
#endif
#ifdef CONFIG_TRUSTONIC_TRUSTED_UI
if (TRUSTEDUI_MODE_INPUT_SECURED & trustedui_get_current_mode()) {
input_err(true, &client->dev,
"%s: TSP no accessible from Linux, TUI is enabled!\n",
__func__);
kfree(t_u8_reg);
return -EIO;
}
#endif
mutex_lock(&data->i2c_lock);
msg_buf = kmalloc(IST40XX_DATA_LEN, GFP_KERNEL);
memcpy(msg_buf, buf, IST40XX_DATA_LEN);
msg[1].buf = (u8 *)msg_buf;
ret = i2c_transfer(client->adapter, msg, READ_CMD_MSG_LEN);
if (ret != READ_CMD_MSG_LEN) {
data->comm_err_count++;
kfree(msg_buf);
mutex_unlock(&data->i2c_lock);
input_err(true, &client->dev, "%s: i2c failed (%d), cmd: %x\n",
__func__, ret, reg);
kfree(t_u8_reg);
return -EIO;
}
/*
{
int i;
pr_info("sec_input: I2C: %s\n", __func__);
pr_info("sec_input: I2C: W: ");
for (i = 0; i < msg[0].len; i++) {
pr_cont("%02X ", msg[0].buf[i]);
}
pr_cont("\n");
pr_info("sec_input: I2C: R: ");
for (i = 0; i < msg[1].len; i++) {
pr_cont("%02X ", msg[1].buf[i]);
}
pr_cont("\n");
}
*/
*buf = cpu_to_be32(*msg_buf);
kfree(msg_buf);
kfree(t_u8_reg);
mutex_unlock(&data->i2c_lock);
return 0;
}
int ist40xx_read_cmd(struct ist40xx_data *data, u32 cmd, u32 *buf)
{
int ret;
ret = ist40xx_cmd_hold(data, IST40XX_ENABLE);
if (ret)
return ret;
ist40xx_read_reg(data->client, IST40XX_DA_ADDR(cmd), buf);
ret = ist40xx_cmd_hold(data, IST40XX_DISABLE);
if (ret) {
ist40xx_reset(data, false);
return ret;
}
return ret;
}
int ist40xx_write_cmd(struct ist40xx_data *data, u32 cmd, u32 val)
{
int ret;
struct i2c_msg msg;
u8 *msg_buf = NULL;
if (data->status.sys_mode == STATE_POWER_OFF) {
input_err(true, &data->client->dev,
"%s: now sys_mode status is STATE_POWER_OFF!\n", __func__);
return -ENODEV;
}
#ifdef CONFIG_INPUT_SEC_SECURE_TOUCH
if (atomic_read(&data->st_enabled) == SECURE_TOUCH_ENABLED) {
input_err(true, &data->client->dev,
"%s: TSP no accessible from Linux, TUI is enabled!\n",
__func__);
return -EBUSY;
}
#endif
#ifdef CONFIG_TRUSTONIC_TRUSTED_UI
if (TRUSTEDUI_MODE_INPUT_SECURED & trustedui_get_current_mode()) {
input_err(true, &data->client->dev,
"%s: TSP no accessible from Linux, TUI is enabled!\n",
__func__);
return -EIO;
}
#endif
msg_buf = kmalloc(IST40XX_ADDR_LEN + IST40XX_DATA_LEN, GFP_KERNEL);
put_unaligned_be32(cmd, msg_buf);
put_unaligned_be32(val, msg_buf + IST40XX_ADDR_LEN);
msg.addr = data->client->addr;
msg.flags = 0;
msg.len = IST40XX_ADDR_LEN + IST40XX_DATA_LEN;
msg.buf = msg_buf;
mutex_lock(&data->i2c_wc_lock);
mutex_lock(&data->i2c_lock);
ret = i2c_transfer(data->client->adapter, &msg, WRITE_CMD_MSG_LEN);
if (ret != WRITE_CMD_MSG_LEN) {
data->comm_err_count++;
mutex_unlock(&data->i2c_lock);
mutex_unlock(&data->i2c_wc_lock);
kfree(msg_buf);
input_err(true, &data->client->dev, "%s: i2c failed (%d), cmd: %x(%x)\n",
__func__, ret, cmd, val);
return -EIO;
}
mutex_unlock(&data->i2c_lock);
/*
{
int i;
pr_info("sec_input: I2C: %s\n", __func__);
pr_info("sec_input: I2C: W: ");
for (i = 0; i < msg.len; i++) {
pr_cont("%02X ", msg.buf[i]);
}
pr_cont("\n");
}
*/
if (data->initialized && (data->status.update != 1) && !data->ignore_delay)
ist40xx_delay(50);
else
ist40xx_delay(1);
mutex_unlock(&data->i2c_wc_lock);
kfree(msg_buf);
return 0;
}
int ist40xx_burst_read(struct i2c_client *client, u32 addr, u32 *buf32, u16 len,
bool bit_en)
{
int ret = 0;
int i;
u16 max_len = I2C_MAX_READ_SIZE / IST40XX_DATA_LEN;
u16 remain_len = len;
if (bit_en)
addr = IST40XX_BA_ADDR(addr);
for (i = 0; i < len; i += max_len) {
if (remain_len < max_len)
max_len = remain_len;
ret = ist40xx_read_buf(client, addr, buf32, max_len);
if (ret) {
input_err(true, &client->dev, "%s: Burst fail, addr: %x\n",
__func__, addr);
return ret;
}
addr += max_len * IST40XX_DATA_LEN;
buf32 += max_len;
remain_len -= max_len;
}
return 0;
}
int ist40xx_burst_write(struct i2c_client *client, u32 addr,
u32 *buf32, u16 len)
{
int ret = 0;
int i;
u16 max_len = I2C_MAX_WRITE_SIZE / IST40XX_DATA_LEN;
u16 remain_len = len;
addr = IST40XX_BA_ADDR(addr);
for (i = 0; i < len; i += max_len) {
if (remain_len < max_len)
max_len = remain_len;
ret = ist40xx_write_buf(client, addr, buf32, max_len);
if (ret) {
input_err(true, &client->dev, "%s: Burst fail, addr: %x\n",
__func__, addr);
return ret;
}
addr += max_len * IST40XX_DATA_LEN;
buf32 += max_len;
remain_len -= max_len;
}
return 0;
}
int ts_power_enable(struct ist40xx_data *data, int en)
{
int ret = 0;
input_info(true, &data->client->dev, "%s %s\n", __func__,
(en) ? "on" : "off");
if(data->dt_data->is_power_by_gpio) {
if (gpio_is_valid(data->dt_data->power_gpio)) {
gpio_set_value(data->dt_data->power_gpio, en);
}
} else {
struct regulator *regulator_avdd;
regulator_avdd = regulator_get(NULL, data->dt_data->regulator_avdd);
if (IS_ERR(regulator_avdd)) {
input_err(true, &data->client->dev,
"%s: Failed to get %s regulator.\n", __func__,
data->dt_data->regulator_avdd);
return PTR_ERR(regulator_avdd);
}
if (en) {
ret = regulator_enable(regulator_avdd);
if (ret) {
input_err(true, &data->client->dev,
"%s: Failed to enable avdd: %d\n",
__func__, ret);
return ret;
}
} else {
if (regulator_is_enabled(regulator_avdd))
regulator_disable(regulator_avdd);
}
regulator_put(regulator_avdd);
}
return ret;
}
int ist40xx_power_on(struct ist40xx_data *data, bool download)
{
int ret = 0;
if (data->status.sys_mode != STATE_POWER_OFF) {
input_err(true, &data->client->dev,
"%s: now state is already power_on\n", __func__);
return 0;
}
/* VDD enable */
/* VDDIO enable */
ret = ts_power_enable(data, 1);
if (ret) {
input_err(true, &data->client->dev,
"%s: ts_power_enable fail.\n", __func__);
return ret;
}
if (download)
ist40xx_delay(10);
else
ist40xx_delay(60);
data->status.sys_mode = STATE_POWER_ON;
data->ignore_delay = true;
ret = ist40xx_set_i2c_32bit(data);
if (ret) {
input_err(true, &data->client->dev,
"%s: ist40xx_set_i2c_32bit fail.\n", __func__);
}
data->ignore_delay = false;
return ret;
}
int ist40xx_power_off(struct ist40xx_data *data)
{
int ret = 0;
if (data->status.sys_mode == STATE_POWER_OFF) {
input_err(true, &data->client->dev,
"%s: now state is already power_off \n", __func__);
return 0;
}
/* VDDIO disable */
/* VDD disable */
data->status.sys_mode = STATE_POWER_OFF;
ret = ts_power_enable(data, 0);
if (ret) {
input_err(true, &data->client->dev,
"%s: ts_power_enable fail.\n", __func__);
}
data->status.noise_mode = false;
ist40xx_delay(30);
return ret;
}
int ist40xx_reset(struct ist40xx_data *data, bool download)
{
int ret = 0;
int temp_sys_mode = data->status.sys_mode;
input_info(true, &data->client->dev, "%s: temp_sys_mode:%d\n",
__func__, temp_sys_mode);
ret = ist40xx_power_off(data);
if (ret) {
input_err(true, &data->client->dev,
"%s: ist40xx_power_off fail.\n", __func__);
return ret;
}
ret = ist40xx_power_on(data, download);
if (ret) {
input_err(true, &data->client->dev,
"%s: ist40xx_power_on fail.\n", __func__);
return ret;
}
ist40xx_write_sponge_reg(data, IST40XX_SPONGE_CTRL, (u16*)&data->lpm_mode,
1, false);
data->ignore_delay = true;
ist40xx_write_cmd(data, IST40XX_HIB_CMD,
(eHCOM_NOTIRY_G_REGMAP << 16) | IST40XX_ENABLE);
data->ignore_delay = false;
if (temp_sys_mode == STATE_LPM) {
ist40xx_cmd_gesture(data, IST40XX_ENABLE);
data->status.noise_mode = false;
data->status.sys_mode = STATE_LPM;
}
return 0;
}
int ist40xx_init_system(struct ist40xx_data *data)
{
int ret;
// TODO : place additional code here.
ret = ist40xx_reset(data, false);
if (ret) {
input_err(true, &data->client->dev,
"%s: ist40xx_reset failed (%d)\n", __func__, ret);
return ret;
}
return 0;
}