kernel_samsung_a34x-permissive/drivers/input/touchscreen/melfas_mip4/mip4_ts.c
2024-04-28 15:51:13 +02:00

1938 lines
45 KiB
C

/*
* MELFAS MIP4 Touchscreen
*
* Copyright (C) 2000-2018 MELFAS Inc.
*
*
* mip4_ts.c
*
* Version : 2019.08.22
*/
#include "mip4_ts.h"
/*
* Start-up run command
*/
int mip4_ts_startup_run(struct mip4_ts_info *info)
{
u8 wbuf[4];
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
wbuf[0] = MIP4_R0_CTRL;
wbuf[1] = MIP4_R1_CTRL_RUN;
wbuf[2] = 1;
if (mip4_ts_i2c_write(info, wbuf, 3)) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_write\n", __func__);
goto error;
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Start-up process
*/
int mip4_ts_startup(struct mip4_ts_info *info)
{
int ret = 0;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
#if 0
reinit_completion(&info->startup_done);
dev_dbg(&info->client->dev, "%s - startup : reinit_completion\n", __func__);
#else
init_completion(&info->startup_done);
dev_dbg(&info->client->dev, "%s - startup : init_completion\n", __func__);
#endif
mip4_ts_power_on(info, 30);
if (!info->irq_enabled) {
enable_irq(info->client->irq);
info->irq_enabled = true;
}
/* Wait start-up interrupt */
dev_dbg(&info->client->dev, "%s - startup : wait_for_completion_interruptible_timeout[%d]\n", __func__, STARTUP_TIMEOUT);
ret = wait_for_completion_interruptible_timeout(&info->startup_done, msecs_to_jiffies(STARTUP_TIMEOUT));
if (ret > 0) {
dev_dbg(&info->client->dev, "%s - startup : completed[%d]\n", __func__, jiffies_to_msecs(ret));
} else {
dev_dbg(&info->client->dev, "%s - startup : timeout[%d]\n", __func__, ret);
#if USE_FW_RECOVERY
/* Restore firmware */
dev_dbg(&info->client->dev, "%s - flash_fail_type : critical\n", __func__);
ret = mip4_ts_fw_restore_critical_section(info);
if (ret < 0) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_fw_restore_critical_section\n", __func__);
}
#endif /* USE_FW_RECOVERY */
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
}
/*
* Reset chip
*/
void mip4_ts_reset(struct mip4_ts_info *info)
{
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
mip4_ts_power_off(info, POWER_OFF_DELAY);
mip4_ts_power_on(info, POWER_ON_DELAY);
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
}
/*
* Restart chip
*/
void mip4_ts_restart(struct mip4_ts_info *info)
{
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
mip4_ts_power_off(info, POWER_OFF_DELAY);
#if USE_STARTUP_WAITING
mip4_ts_startup(info);
#else
mip4_ts_power_on(info, POWER_ON_DELAY);
#endif /* USE_STARTUP_WAITING */
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
}
/*
* I2C Read
*/
int mip4_ts_i2c_read(struct mip4_ts_info *info, char *write_buf, unsigned int write_len, char *read_buf, unsigned int read_len)
{
int retry = I2C_RETRY_COUNT;
int res;
struct i2c_msg msg[] = {
{
.addr = info->client->addr,
.flags = 0,
.buf = write_buf,
.len = write_len,
}, {
.addr = info->client->addr,
.flags = I2C_M_RD,
.buf = read_buf,
.len = read_len,
},
};
while (retry--) {
res = i2c_transfer(info->client->adapter, msg, ARRAY_SIZE(msg));
if (res == ARRAY_SIZE(msg)) {
goto exit;
} else if (res < 0) {
dev_err(&info->client->dev, "%s [ERROR] i2c_transfer - errno[%d]\n", __func__, res);
} else {
dev_err(&info->client->dev, "%s [ERROR] i2c_transfer - size[%zu] result[%d]\n", __func__, ARRAY_SIZE(msg), res);
}
}
goto error_reboot;
error_reboot:
#if RESET_ON_I2C_ERROR
//mip4_ts_restart(info);
#endif /* RESET_ON_I2C_ERROR */
return 1;
exit:
return 0;
}
/*
* I2C Write
*/
int mip4_ts_i2c_write(struct mip4_ts_info *info, char *write_buf, unsigned int write_len)
{
int retry = I2C_RETRY_COUNT;
int res;
while (retry--) {
res = i2c_master_send(info->client, write_buf, write_len);
if (res == write_len) {
goto exit;
} else if (res < 0) {
dev_err(&info->client->dev, "%s [ERROR] i2c_master_send - errno [%d]\n", __func__, res);
} else {
dev_err(&info->client->dev, "%s [ERROR] i2c_master_send - write[%d] result[%d]\n", __func__, write_len, res);
}
}
goto error_reboot;
error_reboot:
#if RESET_ON_I2C_ERROR
//mip4_ts_restart(info);
#endif /* RESET_ON_I2C_ERROR */
return 1;
exit:
return 0;
}
/*
* Enable device
*/
int mip4_ts_enable(struct mip4_ts_info *info)
{
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
#if 0
if (info->enabled) {
dev_warn(&info->client->dev, "%s - Device is already enabled\n", __func__);
goto exit;
}
#else
if (info->init) {
mip4_ts_power_off(info, POWER_OFF_DELAY);
mip4_ts_power_on(info, POWER_ON_DELAY);
#if USE_LPM
#if USE_STARTUP_WAITING
mip4_ts_startup(info);
#else
if (!info->irq_enabled) {
enable_irq(info->client->irq);
info->irq_enabled = true;
}
#endif /* USE_STARTUP_WAITING */
#endif /* USE_LPM */
info->init = false;
} else {
if (info->enabled) {
dev_warn(&info->client->dev, "%s - Device is already enabled\n", __func__);
goto exit;
}
}
#endif
mutex_lock(&info->lock);
mip4_ts_clear_input(info);
#if USE_LPM
#if 1
mip4_ts_set_power_state(info, MIP4_CTRL_POWER_ACTIVE);
#else
mip4_ts_restart(info);
#endif
#if USE_WAKELOCK
if (wake_lock_active(&info->wake_lock)) {
wake_unlock(&info->wake_lock);
dev_dbg(&info->client->dev, "%s - wake_unlock\n", __func__);
}
#endif /* USE_WAKELOCK */
info->low_power_mode = false;
dev_dbg(&info->client->dev, "%s - low power mode : off\n", __func__);
#if USE_WAKEUP_GESTURE
info->gesture_wakeup_mode = false;
dev_dbg(&info->client->dev, "%s - gesture wake-up mode : off\n", __func__);
#endif /* USE_WAKEUP_GESTURE */
#else /* USE_LPM */
#if USE_STARTUP_WAITING
mip4_ts_startup(info);
#else
mip4_ts_power_on(info, POWER_ON_DELAY);
if (!info->irq_enabled) {
enable_irq(info->client->irq);
info->irq_enabled = true;
}
#endif /* USE_STARTUP_WAITING */
#endif /* USE_LPM */
info->enabled = true;
info->i2c_error_cnt = 0;
mutex_unlock(&info->lock);
exit:
dev_info(&info->client->dev, MIP4_TS_DEVICE_NAME" - Enabled\n");
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
}
/*
* Disable device
*/
int mip4_ts_disable(struct mip4_ts_info *info)
{
struct timeval current_time;
u32 time_val = 0;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
if (!info->enabled) {
dev_warn(&info->client->dev, "%s - Device is already disabled\n", __func__);
goto exit;
}
mutex_lock(&info->lock);
#if USE_LPM
#if USE_WAKEUP_GESTURE
info->wakeup_gesture_code = 0;
mip4_ts_set_wakeup_gesture_type(info, MIP4_EVENT_GESTURE_ALL);
#endif /* USE_WAKEUP_GESTURE */
do_gettimeofday(&current_time);
time_val = (u32)current_time.tv_sec;
mip4_ts_set_power_state(info, MIP4_CTRL_POWER_LOW);
info->low_power_mode = true;
dev_dbg(&info->client->dev, "%s - low power mode : on\n", __func__);
#if 0 // USE_SPONGE
mip4_ts_sponge_write_time(info, time_val);
#endif
#if USE_WAKEUP_GESTURE
info->gesture_wakeup_mode = true;
dev_dbg(&info->client->dev, "%s - gesture wake-up mode : on\n", __func__);
#endif /* USE_WAKEUP_GESTURE */
#if USE_WAKELOCK
if (!wake_lock_active(&info->wake_lock)) {
wake_lock(&info->wake_lock);
dev_dbg(&info->client->dev, "%s - wake_lock\n", __func__);
}
#endif /* USE_WAKELOCK */
#else /* USE_LPM */
disable_irq(info->client->irq);
info->irq_enabled = false;
mip4_ts_power_off(info, POWER_OFF_DELAY);
#endif /* USE_LPM */
mip4_ts_clear_input(info);
info->enabled = false;
mutex_unlock(&info->lock);
exit:
dev_info(&info->client->dev, MIP4_TS_DEVICE_NAME" - Disabled\n");
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
}
#if USE_FB_NOTIFY
/*
* FB notifier callback
*/
static int mip4_ts_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data)
{
struct mip4_ts_info *info = container_of(self, struct mip4_ts_info, fb_notifier);
struct fb_event *event_data = data;
unsigned int blank;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
/* Check event */
//if (event != FB_EARLY_EVENT_BLANK) {
if (event != FB_EVENT_BLANK) {
dev_dbg(&info->client->dev, "%s - skip event [0x%02X]\n", __func__, event);
goto exit;
}
/* Check blank */
blank = *(int *)event_data->data;
dev_dbg(&info->client->dev, "%s - blank[0x%02X]\n", __func__, blank);
switch (blank) {
case FB_BLANK_UNBLANK:
/* Enable */
dev_dbg(&info->client->dev, "%s - FB_BLANK_UNBLANK\n", __func__);
break;
case FB_BLANK_POWERDOWN:
/* Disable */
dev_dbg(&info->client->dev, "%s - FB_BLANK_POWERDOWN\n", __func__);
break;
default:
dev_dbg(&info->client->dev, "%s - skip blank [0x%02X]\n", __func__, blank);
break;
}
exit:
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
}
#endif /* USE_FB_NOTIFY */
#if USE_INPUT_OPEN_CLOSE
/*
* Open input device
*/
static int mip4_ts_input_open(struct input_dev *dev)
{
struct mip4_ts_info *info = input_get_drvdata(dev);
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
#if 0
if (info->init == true) {
mip4_ts_restart(info);
info->init = false;
} else {
mip4_ts_enable(info);
}
#else
mip4_ts_enable(info);
#endif
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
}
/*
* Close input device
*/
static void mip4_ts_input_close(struct input_dev *dev)
{
struct mip4_ts_info *info = input_get_drvdata(dev);
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
mip4_ts_disable(info);
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
}
#endif /* USE_INPUT_OPEN_CLOSE */
/*
* Get ready status
*/
int mip4_ts_get_ready_status(struct mip4_ts_info *info)
{
u8 wbuf[16];
u8 rbuf[16];
int ret = 0;
//dev_dbg(&info->client->dev, "%s [START]\n", __func__);
wbuf[0] = MIP4_R0_CTRL;
wbuf[1] = MIP4_R1_CTRL_READY_STATUS;
if (mip4_ts_i2c_read(info, wbuf, 2, rbuf, 1)) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_read\n", __func__);
goto error;
}
ret = rbuf[0];
/* Check status */
if ((ret == MIP4_CTRL_STATUS_NONE) || (ret == MIP4_CTRL_STATUS_LOG) || (ret == MIP4_CTRL_STATUS_READY)) {
//dev_dbg(&info->client->dev, "%s - status[0x%02X]\n", __func__, ret);
} else {
dev_err(&info->client->dev, "%s [ERROR] Unknown status[0x%02X]\n", __func__, ret);
goto error;
}
if (ret == MIP4_CTRL_STATUS_LOG) {
/* Skip log event */
wbuf[0] = MIP4_R0_LOG;
wbuf[1] = MIP4_R1_LOG_TRIGGER;
wbuf[2] = 0;
if (mip4_ts_i2c_write(info, wbuf, 3)) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_write\n", __func__);
}
}
//dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return ret;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Read chip firmware version
*/
int mip4_ts_get_fw_version(struct mip4_ts_info *info, u8 *ver_buf)
{
u8 rbuf[8];
u8 wbuf[2];
int i;
wbuf[0] = MIP4_R0_INFO;
wbuf[1] = MIP4_R1_INFO_VERSION_BOOT;
if (mip4_ts_i2c_read(info, wbuf, 2, rbuf, 8)) {
goto error;
};
for (i = 0; i < 8; i++) {
ver_buf[i] = rbuf[i];
}
return 0;
error:
for (i = 0; i < 8; i++) {
ver_buf[i] = 0xFF;
}
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Read chip firmware version for u16
*/
int mip4_ts_get_fw_version_u16(struct mip4_ts_info *info, u16 *ver_buf_u16)
{
u8 rbuf[8];
int i;
if (mip4_ts_get_fw_version(info, rbuf)) {
goto error;
}
for (i = 0; i < 4; i++) {
ver_buf_u16[i] = (rbuf[i * 2 + 1] << 8) | rbuf[i * 2];
}
return 0;
error:
for (i = 0; i < 4; i++) {
ver_buf_u16[i] = 0xFFFF;
}
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
#if (CHIP_MODEL != CHIP_NONE)
/*
* Read bin(file) firmware version
*/
int mip4_ts_get_fw_version_from_bin(struct mip4_ts_info *info, u8 *ver_buf)
{
const struct firmware *fw;
int i;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
request_firmware(&fw, FW_PATH_INTERNAL, &info->client->dev);
if (!fw) {
dev_err(&info->client->dev, "%s [ERROR] request_firmware\n", __func__);
goto error;
}
if (mip4_ts_bin_fw_version(info, fw->data, fw->size, ver_buf)) {
for (i = 0; i < (4 * 2); i++) {
ver_buf[i] = 0xFF;
}
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_bin_fw_version\n", __func__);
goto error;
}
release_firmware(fw);
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
#endif /* CHIP_MODEL */
/*
* Set power state
*/
int mip4_ts_set_power_state(struct mip4_ts_info *info, u8 mode)
{
u8 wbuf[3];
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
dev_dbg(&info->client->dev, "%s - mode[%u]\n", __func__, mode);
wbuf[0] = MIP4_R0_CTRL;
wbuf[1] = MIP4_R1_CTRL_POWER_STATE;
wbuf[2] = mode;
if (mip4_ts_i2c_write(info, wbuf, 3)) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_write\n", __func__);
goto error;
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Set wake-up gesture type
*/
int mip4_ts_set_wakeup_gesture_type(struct mip4_ts_info *info, u32 type)
{
u8 wbuf[6];
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
dev_dbg(&info->client->dev, "%s - type[%08X]\n", __func__, type);
wbuf[0] = MIP4_R0_CTRL;
wbuf[1] = MIP4_R1_CTRL_GESTURE_TYPE;
wbuf[2] = (type >> 24) & 0xFF;
wbuf[3] = (type >> 16) & 0xFF;
wbuf[4] = (type >> 8) & 0xFF;
wbuf[5] = type & 0xFF;
if (mip4_ts_i2c_write(info, wbuf, 6)) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_write\n", __func__);
goto error;
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Disable ESD alert
*/
int mip4_ts_disable_esd_alert(struct mip4_ts_info *info)
{
u8 wbuf[4];
u8 rbuf[4];
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
wbuf[0] = MIP4_R0_CTRL;
wbuf[1] = MIP4_R1_CTRL_DISABLE_ESD_ALERT;
wbuf[2] = 1;
if (mip4_ts_i2c_write(info, wbuf, 3)) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_write\n", __func__);
goto error;
}
if (mip4_ts_i2c_read(info, wbuf, 2, rbuf, 1)) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_read\n", __func__);
goto error;
}
if (rbuf[0] != 1) {
dev_dbg(&info->client->dev, "%s [ERROR] failed\n", __func__);
goto error;
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Alert event handler - ESD
*/
static int mip4_ts_alert_handler_esd(struct mip4_ts_info *info, u8 *rbuf)
{
u8 frame_cnt = rbuf[1];
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
dev_dbg(&info->client->dev, "%s - frame_cnt[%d]\n", __func__, frame_cnt);
if (frame_cnt == 0) {
/* Panel defect, not ESD */
info->esd_cnt++;
dev_dbg(&info->client->dev, "%s - esd_cnt[%d]\n", __func__, info->esd_cnt);
if (info->disable_esd == true) {
mip4_ts_disable_esd_alert(info);
info->esd_cnt = 0;
} else if (info->esd_cnt > ESD_COUNT_FOR_DISABLE) {
if (!mip4_ts_disable_esd_alert(info)) {
info->disable_esd = true;
info->esd_cnt = 0;
}
} else {
mip4_ts_restart(info);
}
} else {
/* ESD detected */
info->esd_cnt = 0;
mip4_ts_restart(info);
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
}
/*
* Alert event handler - Wake-up
*/
static int mip4_ts_alert_handler_wakeup(struct mip4_ts_info *info, u8 *rbuf)
{
int gesture_code = rbuf[1];
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
if (mip4_ts_gesture_wakeup_event_handler(info, gesture_code)) {
goto error;
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Alert event handler - Input type
*/
static int mip4_ts_alert_handler_inputtype(struct mip4_ts_info *info, u8 *rbuf)
{
u8 input_type = rbuf[1];
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
switch (input_type) {
case 0:
dev_dbg(&info->client->dev, "%s - Input type : Finger\n", __func__);
break;
case 1:
dev_dbg(&info->client->dev, "%s - Input type : Glove\n", __func__);
break;
default:
dev_err(&info->client->dev, "%s - Input type : Unknown[%d]\n", __func__, input_type);
goto error;
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Alert event handler - Image
*/
static int mip4_ts_alert_handler_image(struct mip4_ts_info *info, u8 *rbuf)
{
u8 image_type = rbuf[1];
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
switch (image_type) {
#if USE_WAKEUP_GESTURE
case MIP4_IMG_TYPE_GESTURE:
if (mip4_ts_gesture_wakeup_event_handler(info, 1)) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_wakeup_event_handler\n", __func__);
goto error;
}
if (mip4_ts_get_image(info, rbuf[1])) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_get_image\n", __func__);
goto error;
}
break;
#endif /* USE_WAKEUP_GESTURE */
default:
goto error;
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Alert event handler - Flash failure
*/
int mip4_ts_alert_handler_flash(struct mip4_ts_info *info, u8 *data)
{
#if USE_FW_RECOVERY
int ret = 0;
int retry = 1;
u8 sections[64];
int i_byte = 0;
int i_bit = 0;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
print_hex_dump(KERN_ERR, MIP4_TS_DEVICE_NAME " Sections : ", DUMP_PREFIX_OFFSET, 16, 1, data, 8, false);
for (i_byte = 0; i_byte < 8; i_byte++) {
dev_info(&info->client->dev, "%s - packet #%d [0x%02X]\n", __func__, i_byte, data[i_byte]);
for (i_bit = 0; i_bit < 8; i_bit++) {
sections[i_byte * 8 + i_bit] = (data[i_byte] >> i_bit) & 0x01;
dev_info(&info->client->dev, "%s - section #%d [%d]\n", __func__, i_byte * 8 + i_bit, sections[i_byte * 8 + i_bit]);
}
}
ret = mip4_ts_fw_restore_from_kernel(info, sections, retry);
if (ret < FW_ERR_NONE) {
dev_err(&info->client->dev, "%s - fw_err[%d]\n", __func__, ret);
goto error;
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
#else
return 0;
#endif /* USE_FW_RECOVERY */
}
/*
* Alert event handler - SRAM failure
*/
static int mip4_ts_alert_handler_sram(struct mip4_ts_info *info, u8 *data)
{
int i;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
info->sram_addr_num = (unsigned int) (data[0] | (data[1] << 8));
dev_info(&info->client->dev, "%s - sram_addr_num [%d]\n", __func__, info->sram_addr_num);
if (info->sram_addr_num > 8) {
dev_err(&info->client->dev, "%s [ERROR] sram_addr_num [%d]\n", __func__, info->sram_addr_num);
goto error;
}
for (i = 0; i < info->sram_addr_num; i++) {
info->sram_addr[i] = data[2 + 4 * i] | (data[2 + 4 * i + 1] << 8) | (data[2 + 4 * i + 2] << 16) | (data[2 + 4 * i + 3] << 24);
dev_info(&info->client->dev, "%s - sram_addr #%d [0x%08X]\n", __func__, i, info->sram_addr[i]);
}
for (i = info->sram_addr_num; i < 8; i++) {
info->sram_addr[i] = 0;
dev_info(&info->client->dev, "%s - sram_addr #%d [0x%08X]\n", __func__, i, info->sram_addr[i]);
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Alert event handler - Custom
*/
static int __maybe_unused mip4_ts_alert_handler_f1(struct mip4_ts_info *info, u8 *rbuf, u8 size)
{
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
#if 0
if (rbuf[1] == 2) {
if (mip4_ts_custom_event_handler(info, rbuf, size)) {
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
}
}
#endif
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
}
/*
* Interrupt handler
*/
static irqreturn_t __maybe_unused mip4_ts_interrupt(int irq, void *dev_id)
{
struct mip4_ts_info *info = dev_id;
u8 wbuf[8];
u8 rbuf[256];
unsigned int size = 0;
u8 category = 0;
u8 alert_type = 0;
bool startup = false;
u8 flash_fail_type = FLASH_FAIL_NONE;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
#if USE_STARTUP_WAITING
/* Start-up interrupt */
if (info->startup_init == false) {
dev_dbg(&info->client->dev, "%s - skip\n", __func__);
goto exit;
}
if (!completion_done(&info->startup_done)) {
startup = true;
dev_dbg(&info->client->dev, "%s - start-up\n", __func__);
}
#endif /* USE_STARTUP_WAITING */
/* Read packet info */
wbuf[0] = MIP4_R0_EVENT;
wbuf[1] = MIP4_R1_EVENT_PACKET_INFO;
if (mip4_ts_i2c_read(info, wbuf, 2, rbuf, 1)) {
dev_err(&info->client->dev, "%s [ERROR] Read packet info\n", __func__);
if (!startup) {
info->i2c_error_cnt++;
goto error;
} else {
flash_fail_type = FLASH_FAIL_CRITICAL;
goto startup_exit;
}
}
size = (rbuf[0] & 0x7F);
category = ((rbuf[0] >> 7) & 0x1);
if (info->event_size_type == 1 && category == 0)
size = info->event_size * size;
dev_dbg(&info->client->dev, "%s - packet info : size_type[%d] size[%d] category[%d]\n", __func__, info->event_size_type, size, category);
/* Check packet size */
if ((size <= 0) || (size > 200)) {
dev_err(&info->client->dev, "%s [ERROR] Packet size [%d]\n", __func__, size);
if (!startup) {
info->i2c_error_cnt++;
goto error;
} else {
flash_fail_type = FLASH_FAIL_CRITICAL;
goto startup_exit;
}
}
/* Read packet data */
wbuf[0] = MIP4_R0_EVENT;
wbuf[1] = MIP4_R1_EVENT_PACKET_DATA;
if (mip4_ts_i2c_read(info, wbuf, 2, rbuf, size)) {
dev_err(&info->client->dev, "%s [ERROR] Read packet data\n", __func__);
if (!startup) {
info->i2c_error_cnt++;
goto error;
} else {
flash_fail_type = FLASH_FAIL_CRITICAL;
goto startup_exit;
}
}
/* Event handler */
if (startup == false) {
if (category == 0) {
/* Input event */
info->esd_cnt = 0;
mip4_ts_input_event_handler(info, size, rbuf);
} else {
/* Alert event */
alert_type = rbuf[0];
dev_dbg(&info->client->dev, "%s - alert type[%d]\n", __func__, alert_type);
switch (alert_type) {
case MIP4_ALERT_ESD:
if (mip4_ts_alert_handler_esd(info, rbuf)) {
goto error;
}
break;
case MIP4_ALERT_WAKEUP:
if (mip4_ts_alert_handler_wakeup(info, rbuf)) {
goto error;
}
break;
case MIP4_ALERT_INPUT_TYPE:
if (mip4_ts_alert_handler_inputtype(info, rbuf)) {
goto error;
}
break;
case MIP4_ALERT_IMAGE:
if (mip4_ts_alert_handler_image(info, rbuf)) {
goto error;
}
break;
case MIP4_ALERT_FLASH_FAILURE:
if (mip4_ts_alert_handler_flash(info, &rbuf[1])) {
goto error;
}
break;
case MIP4_ALERT_SRAM_FAILURE:
if (mip4_ts_alert_handler_sram(info, &rbuf[1])) {
goto error;
}
break;
case MIP4_ALERT_BOOT_SUCCEEDED:
mip4_ts_startup_config(info);
mip4_ts_startup_run(info);
break;
case MIP4_ALERT_F1:
if (mip4_ts_alert_handler_f1(info, rbuf, size)) {
goto error;
}
break;
default:
dev_err(&info->client->dev, "%s [ERROR] Unknown alert type[%d]\n", __func__, alert_type);
goto error;
}
}
} else {
#if USE_STARTUP_WAITING
/* Start-up */
if (category == 1) {
alert_type = rbuf[0];
dev_dbg(&info->client->dev, "%s - alert type[%d]\n", __func__, alert_type);
switch (alert_type) {
case MIP4_ALERT_FLASH_FAILURE:
flash_fail_type = FLASH_FAIL_SECTION;
break;
case MIP4_ALERT_BOOT_SUCCEEDED:
flash_fail_type = FLASH_FAIL_NONE;
break;
default:
dev_err(&info->client->dev, "%s [ERROR] Unknown alert type[%d]\n", __func__, alert_type);
flash_fail_type = FLASH_FAIL_CRITICAL;
break;
}
} else {
dev_err(&info->client->dev, "%s [ERROR] Unknown catetory[%d]\n", __func__, category);
flash_fail_type = FLASH_FAIL_CRITICAL;
}
goto startup_exit;
#endif /* USE_STARTUP_WAITING */
}
#if USE_STARTUP_WAITING
exit:
#endif /* USE_STARTUP_WAITING */
info->i2c_error_cnt = 0;
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return IRQ_HANDLED;
startup_exit:
#if USE_STARTUP_WAITING
complete_all(&info->startup_done);
dev_dbg(&info->client->dev, "%s - startup : complete_all\n", __func__);
if (alert_type == MIP4_ALERT_BOOT_SUCCEEDED) {
mip4_ts_startup_config(info);
mip4_ts_startup_run(info);
}
#if USE_FW_RECOVERY
if (flash_fail_type == FLASH_FAIL_CRITICAL) {
mip4_ts_fw_restore_critical_section(info);
} else if (flash_fail_type == FLASH_FAIL_SECTION) {
mip4_ts_alert_handler_flash(info, &rbuf[1]);
}
#endif /* USE_FW_RECOVERY */
#endif /* USE_STARTUP_WAITING */
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return IRQ_HANDLED;
error:
#if RESET_ON_EVENT_ERROR
//dev_err(&info->client->dev, "%s - Reset on event error\n", __func__);
//mip4_ts_restart(info);
#endif /* RESET_ON_EVENT_ERROR */
#if USE_STARTUP_WAITING
#endif /* USE_STARTUP_WAITING */
#if USE_FW_RECOVERY
if (info->i2c_error_cnt >= I2C_ERR_CNT_FOR_FW_RECOVERY) {
mip4_ts_fw_restore_critical_section(info);
}
#endif /* USE_FW_RECOVERY */
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return IRQ_HANDLED;
}
/*
* Config module
*/
int mip4_ts_config(struct mip4_ts_info *info)
{
u8 wbuf[4];
u8 rbuf[16];
int ret = 0;
int retry = I2C_RETRY_COUNT;
int tmp;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
/* Product name */
wbuf[0] = MIP4_R0_INFO;
wbuf[1] = MIP4_R1_INFO_PRODUCT_NAME;
ret = mip4_ts_i2c_read(info, wbuf, 2, rbuf, 16);
if (ret) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_read\n", __func__);
goto error;
}
memcpy(info->product_name, rbuf, 16);
dev_dbg(&info->client->dev, "%s - product_name[%s]\n", __func__, info->product_name);
/* Firmware version */
ret = mip4_ts_get_fw_version(info, rbuf);
if (ret) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_read\n", __func__);
goto error;
}
memcpy(info->fw_version, rbuf, 8);
dev_info(&info->client->dev, "%s - F/W Version : %02X.%02X / %02X.%02X.%02X.%02X / %02X.%02X\n", __func__, info->fw_version[0], info->fw_version[1], info->fw_version[2], info->fw_version[3], info->fw_version[4], info->fw_version[5], info->fw_version[6], info->fw_version[7]);
/* Resolution */
wbuf[0] = MIP4_R0_INFO;
wbuf[1] = MIP4_R1_INFO_RESOLUTION_X;
retry = 10;
while (retry--){
if (mip4_ts_i2c_read(info, wbuf, 2, rbuf, 14)){
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_read\n", __func__);
} else {
tmp = (rbuf[4] & rbuf[5]) | rbuf[6];
if (0 == (rbuf[0]) | (rbuf[1] << 8) || 0xFFFF == (rbuf[0]) | (rbuf[1] << 8) ||
0 == (rbuf[2]) | (rbuf[3] << 8) || 0xFFFF == (rbuf[2]) | (rbuf[3] << 8) ||
0 == tmp || 0xFF == tmp)
{
dev_err(&info->client->dev,
"%s: Fail to read tsp info[%x,%x,%x,%x,%x,%x,%x]\n",
__func__, rbuf[0], rbuf[1], rbuf[2], rbuf[3], rbuf[4], rbuf[5], rbuf[6]);
msleep(20);
continue;
}
break;
}
}
if (retry <= 0) {
dev_err(&info->client->dev, "%s [ERROR] Resolution - retry limit\n", __func__);
////////////////////////////////////////////////////
// PLEASE MODIFY HERE (default value) !!!
// resolution_x / y, node_x / y / key
//
//
////////////////////////////////////////////////////
info->max_x = 4095;
info->max_y = 4095;
info->node_x = 15;
info->node_y = 33;
info->node_key = 0;
} else {
info->max_x = (rbuf[0]) | (rbuf[1] << 8);
info->max_y = (rbuf[2]) | (rbuf[3] << 8);
dev_dbg(&info->client->dev, "%s - max_x[%d] max_y[%d]\n", __func__, info->max_x, info->max_y);
info->ppm_x = rbuf[12];
info->ppm_y = rbuf[13];
dev_dbg(&info->client->dev, "%s - ppm_x[%d] ppm_y[%d]\n", __func__, info->ppm_x, info->ppm_y);
/* Node info */
info->node_x = rbuf[4];
info->node_y = rbuf[5];
info->node_key = rbuf[6];
dev_dbg(&info->client->dev, "%s - node_x[%d] node_y[%d] node_key[%d]\n", __func__, info->node_x, info->node_y, info->node_key);
}
/* Key info */
if (info->node_key > 0) {
/* Enable touchkey */
info->key_enable = true;
info->key_num = info->node_key;
}
/* Protocol */
wbuf[0] = MIP4_R0_EVENT;
wbuf[1] = MIP4_R1_EVENT_FORMAT;
retry = 10;
while (retry--) {
if (mip4_ts_i2c_read(info, wbuf, 2, rbuf, 4)) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_i2c_read - event format\n", __func__);
} else {
info->event_format = (int)(rbuf[0] | (rbuf[1] << 8));
switch (info->event_format) {
case 0:
case 1:
case 3:
case 4:
case 8:
case 10:
break;
default:
dev_err(&info->client->dev, "%s [ERROR] event_format[%d]\n", __func__, info->event_format);
continue;
}
info->event_size = rbuf[2];
if (info->event_size <= 0 || rbuf[2] == 0xFF) {
dev_err(&info->client->dev, "%s [ERROR] event_size[%d]\n", __func__, info->event_size);
continue;
}
info->event_size_type = (rbuf[3] & 0x01);
dev_dbg(&info->client->dev, "%s - event_format[%d] event_size[%d], event_size_type[%d]\n", __func__, info->event_format, info->event_size, info->event_size_type);
break;
}
}
if (retry <= 0) {
dev_err(&info->client->dev, "%s [ERROR] event format - retry limit\n", __func__);
////////////////////////////////////////////////////
// PLEASE MODIFY HERE (default value) !!!
// event_format / event_size
//
//
////////////////////////////////////////////////////
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Config platform
*/
static int mip4_ts_config_platform(struct mip4_ts_info *info)
{
//#ifdef CONFIG_ACPI
#if 0
struct acpi_device *a_dev;
acpi_status a_status;
#endif /* CONFIG_ACPI */
int ret = 0;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
//#ifdef CONFIG_ACPI
#if 0
/* ACPI */
dev_dbg(&info->client->dev, "%s - ACPI\n", __func__);
a_status = acpi_bus_get_device(ACPI_HANDLE(&info->client->dev), &a_dev);
if (ACPI_SUCCESS(a_status)) {
if (strncmp(dev_name(&a_dev->dev), ACPI_ID, 8) != 0) {
dev_err(&info->client->dev, "%s [ERROR] ACPI_ID mismatch [%s]\n", __func__, dev_name(&a_dev->dev));
ret = -EINVAL;
goto exit;
}
}
#else
#ifdef CONFIG_OF
/* Devicetree */
if (&info->client->dev.of_node) {
dev_dbg(&info->client->dev, "%s - Devicetree\n", __func__);
ret = mip4_ts_parse_devicetree(&info->client->dev, info);
if (ret) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_parse_devicetree\n", __func__);
goto exit;
}
} else {
dev_err(&info->client->dev, "%s [ERROR] of_node\n", __func__);
goto exit;
}
#else
/* Platform device */
dev_dbg(&info->client->dev, "%s - Platform device\n", __func__);
info->pdata = dev_get_platdata(&info->client->dev);
if (info->pdata == NULL) {
ret = -EINVAL;
dev_err(&info->client->dev, "%s [ERROR] dev_get_platdata\n", __func__);
goto exit;
}
info->gpio_intr = info->pdata->gpio_intr;
info->gpio_ce = info->pdata->gpio_ce;
info->gpio_vd33_en = info->pdata->gpio_vd33_en;
ret = mip4_ts_config_gpio(info);
if (ret) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_config_gpio\n", __func__);
goto exit;
}
#endif /* CONFIG_OF */
#endif /* CONFIG_ACPI */
exit:
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return ret;
}
#if (CHIP_MODEL != CHIP_NONE)
#if USE_FW_RECOVERY
/*
* Restore critical section of firmware from kernel built-in firmware file
*/
int mip4_ts_fw_restore_critical_section(struct mip4_ts_info *info)
{
int ret = 0;
int i;
u8 sections[FW_SECTION_NUM];
int retry = 1;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
/* Restore firmware */
memset(sections, 0, FW_SECTION_NUM);
for (i = 0; i < FW_CRITICAL_SECTION_NUM; i++) {
sections[i] = 1;
}
ret = mip4_ts_fw_restore_from_kernel(info, sections, retry);
if (ret < 0) {
dev_err(&info->client->dev, "%s [ERROR] mms_fw_restore_from_kernel\n", __func__);
goto error;
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return 1;
}
/*
* Restore firmware from kernel built-in firmware file
*/
int mip4_ts_fw_restore_from_kernel(struct mip4_ts_info *info, u8 *sections, int retry)
{
const char *fw_name = FW_PATH_INTERNAL;
const struct firmware *fw;
int ret = FW_ERR_NONE;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
//mutex_lock(&info->lock);
mip4_ts_clear_input(info);
print_hex_dump(KERN_ERR, MIP4_TS_DEVICE_NAME " Sections : ", DUMP_PREFIX_OFFSET, 16, 1, sections, FW_SECTION_NUM, false);
/* Get firmware */
request_firmware(&fw, fw_name, &info->client->dev);
if (!fw) {
dev_err(&info->client->dev, "%s [ERROR] request_firmware\n", __func__);
ret = FW_ERR_FILE_OPEN;
goto error;
}
/* Restore firmware */
while (retry > 0) {
ret = mip4_ts_restore_fw(info, fw->data, fw->size, sections);
dev_err(&info->client->dev, "%s - mip4_ts_restore_fw[%d]\n", __func__, ret);
if (ret >= FW_ERR_NONE) {
break;
}
retry--;
}
if (retry <= 0) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_restore_fw failed\n", __func__);
ret = FW_ERR_DOWNLOAD;
} else {
ret = FW_ERR_NONE;
}
release_firmware(fw);
if (ret < FW_ERR_NONE) {
goto error;
}
//mutex_unlock(&info->lock);
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
//mutex_unlock(&info->lock);
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return ret;
}
#endif
/*
* Update firmware from kernel built-in firmware file
*/
int mip4_ts_fw_update_from_kernel(struct mip4_ts_info *info)
{
const char *fw_name = FW_PATH_INTERNAL;
const struct firmware *fw;
int retry = 3;
int ret = FW_ERR_NONE;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
/* Disable IRQ */
mutex_lock(&info->lock);
disable_irq(info->client->irq);
mip4_ts_clear_input(info);
/* Get firmware */
request_firmware(&fw, fw_name, &info->client->dev);
if (!fw) {
dev_err(&info->client->dev, "%s [ERROR] request_firmware\n", __func__);
ret = FW_ERR_FILE_OPEN;
goto error;
}
/* Update firmware */
do {
ret = mip4_ts_flash_fw(info, fw->data, fw->size, false, true);
if (ret >= FW_ERR_NONE) {
break;
}
} while (--retry);
if (!retry) {
dev_err(&info->client->dev, "%s [ERROR] mip4_ts_flash_fw failed\n", __func__);
ret = FW_ERR_DOWNLOAD;
}
release_firmware(fw);
/* Enable IRQ */
enable_irq(info->client->irq);
mutex_unlock(&info->lock);
if (ret < FW_ERR_NONE) {
goto error;
}
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
return 0;
error:
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
return ret;
}
/*
* Update firmware from external storage
*/
int mip4_ts_fw_update_from_storage(struct mip4_ts_info *info, char *path, bool force)
{
struct file *fp;
mm_segment_t old_fs;
size_t fw_size, nread;
unsigned char *fw_data;
int ret = FW_ERR_NONE;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
/* Disable IRQ */
mutex_lock(&info->lock);
disable_irq(info->client->irq);
mip4_ts_clear_input(info);
/* Get firmware */
old_fs = get_fs();
set_fs(KERNEL_DS);
fp = filp_open(path, O_RDONLY, S_IRUSR);
if (IS_ERR(fp)) {
dev_err(&info->client->dev, "%s [ERROR] file_open - path[%s]\n", __func__, path);
ret = FW_ERR_FILE_OPEN;
goto error;
}
fw_size = fp->f_path.dentry->d_inode->i_size;
if (fw_size > 0) {
/* Read firmware */
fw_data = kzalloc(fw_size, GFP_KERNEL);
nread = vfs_read(fp, (char __user *)fw_data, fw_size, &fp->f_pos);
dev_dbg(&info->client->dev, "%s - path[%s] size[%zu]\n", __func__, path, fw_size);
if (nread != fw_size) {
dev_err(&info->client->dev, "%s [ERROR] vfs_read - size[%zu] read[%zu]\n", __func__, fw_size, nread);
ret = FW_ERR_FILE_READ;
} else {
/* Update firmware */
ret = mip4_ts_flash_fw(info, fw_data, fw_size, force, true);
}
kfree(fw_data);
} else {
dev_err(&info->client->dev, "%s [ERROR] fw_size[%zu]\n", __func__, fw_size);
ret = FW_ERR_FILE_READ;
}
filp_close(fp, current->files);
error:
set_fs(old_fs);
/* Enable IRQ */
enable_irq(info->client->irq);
mutex_unlock(&info->lock);
if (ret < FW_ERR_NONE) {
dev_err(&info->client->dev, "%s [ERROR]\n", __func__);
} else {
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
}
return ret;
}
/*
* Sysfs - firmware update
*/
static ssize_t mip4_ts_sys_fw_update(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts_info *info = i2c_get_clientdata(client);
int result = 0;
u8 data[255];
int ret = 0;
dev_dbg(&info->client->dev, "%s [START]\n", __func__);
ret = mip4_ts_fw_update_from_kernel(info);
switch (ret) {
case FW_ERR_NONE:
snprintf(data, sizeof(data), "F/W update success.\n");
break;
case FW_ERR_UPTODATE:
snprintf(data, sizeof(data), "F/W is already up-to-date.\n");
break;
case FW_ERR_DOWNLOAD:
snprintf(data, sizeof(data), "F/W update failed : Download error\n");
break;
case FW_ERR_FILE_TYPE:
snprintf(data, sizeof(data), "F/W update failed : Firmware type error\n");
break;
case FW_ERR_FILE_OPEN:
snprintf(data, sizeof(data), "F/W update failed : Firmware open error[%s]\n", FW_PATH_INTERNAL);
break;
case FW_ERR_FILE_READ:
snprintf(data, sizeof(data), "F/W update failed : Firmware read error\n");
break;
default:
snprintf(data, sizeof(data), "F/W update failed.\n");
break;
}
/* Re-config driver */
mip4_ts_config(info);
mip4_ts_config_input(info);
dev_dbg(&info->client->dev, "%s [DONE]\n", __func__);
result = snprintf(buf, 255, "%s\n", data);
return result;
}
static DEVICE_ATTR(fw_update, S_IRUGO, mip4_ts_sys_fw_update, NULL);
#endif /* CHIP_MODEL */
/*
* Sysfs attr info
*/
static struct attribute *mip4_ts_attrs[] = {
#if (CHIP_MODEL != CHIP_NONE)
&dev_attr_fw_update.attr,
#endif /* CHIP_MODEL */
NULL,
};
/*
* Sysfs attr group info
*/
static const struct attribute_group mip4_ts_attr_group = {
.attrs = mip4_ts_attrs,
};
/*
* Initialize driver
*/
static int mip4_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct mip4_ts_info *info;
struct input_dev *input_dev;
int ret = 0;
dev_dbg(&client->dev, "%s [START]\n", __func__);
/* Check I2C functionality */
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "%s [ERROR] i2c_check_functionality\n", __func__);
ret = -EIO;
goto error_i2c;
}
/* Init info data */
info = devm_kzalloc(&client->dev, sizeof(struct mip4_ts_info), GFP_KERNEL);
input_dev = devm_input_allocate_device(&client->dev);
if (!info || !input_dev) {
dev_err(&client->dev, "%s [ERROR]\n", __func__);
ret = -ENOMEM;
goto error_info;
}
info->client = client;
info->input_dev = input_dev;
info->init = true;
info->power = -1;
info->irq_enabled = false;
info->fw_path_ext = devm_kstrdup(&client->dev, FW_PATH_EXTERNAL, GFP_KERNEL);
mutex_init(&info->lock);
init_completion(&info->startup_done);
info->startup_init = false;
info->debug_event = DEBUG_EVENT;
/* Config platform */
ret = mip4_ts_config_platform(info);
if (ret) {
dev_err(&client->dev, "%s [ERROR] mip4_ts_config_platform\n", __func__);
goto error_info;
}
/* Config input device */
//info->input_dev->name = "MELFAS_" CHIP_NAME "_Touchscreen";
info->input_dev->name = "sec_touchscreen";
//snprintf(info->phys, sizeof(info->phys), "%s/input0", dev_name(&client->dev));
snprintf(info->phys, sizeof(info->phys), "%s/input1", input_dev->name);
info->input_dev->phys = info->phys;
info->input_dev->id.bustype = BUS_I2C;
info->input_dev->id.vendor = 0x13C5;
info->input_dev->dev.parent = &client->dev;
#if USE_INPUT_OPEN_CLOSE
info->input_dev->open = mip4_ts_input_open;
info->input_dev->close = mip4_ts_input_close;
#endif /* USE_INPUT_OPEN_CLOSE */
/* Set info data */
input_set_drvdata(input_dev, info);
i2c_set_clientdata(client, info);
/* Config regulator */
mip4_ts_config_regulator(info);
#if 0
mip4_ts_power_off(info, POWER_OFF_DELAY);
#endif
/* Firmware update */
#if USE_AUTO_FW_UPDATE
mip4_ts_power_on(info, POWER_ON_DELAY);
#if 1
ret = mip4_ts_fw_update_from_kernel(info);
if (ret) {
dev_err(&client->dev, "%s [ERROR] mip4_ts_fw_update_from_kernel\n", __func__);
}
#else
ret = mip4_ts_fw_update_from_storage(info, FW_PATH_EXTERNAL, false);
if (ret) {
dev_err(&client->dev, "%s [ERROR] mip4_ts_fw_update_from_storage\n", __func__);
}
#endif
mip4_ts_power_off(info, POWER_OFF_DELAY);
#endif /* USE_AUTO_FW_UPDATE */
/* Set interrupt handler */
#if 1
//ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, mip4_ts_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, MIP4_TS_DEVICE_NAME, info);
ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, mip4_ts_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, MIP4_TS_DEVICE_NAME, info);
//ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, mip4_ts_interrupt, 8200, MIP4_TS_DEVICE_NAME, info);
//ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, mip4_ts_interrupt, 0, MIP4_TS_DEVICE_NAME, info);
#else
ret = 0;
#endif
if (ret) {
dev_err(&client->dev, "%s [ERROR] request_threaded_irq\n", __func__);
goto error_irq;
}
#if USE_WAKELOCK
/* Wake-lock for low power mode */
wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND, "mip4_ts_wake_lock");
#endif /* USE_WAKELOCK */
disable_irq(info->client->irq);
info->irq_enabled = false;
info->startup_init = true;
/* Enable device */
mip4_ts_enable(info);
/* Config module */
ret = mip4_ts_config(info);
if (ret) {
dev_err(&client->dev, "%s [ERROR] mip4_ts_config\n", __func__);
}
/* Config input interface */
mip4_ts_config_input(info);
/* Register input device */
ret = input_register_device(input_dev);
if (ret) {
dev_err(&client->dev, "%s [ERROR] input_register_device\n", __func__);
ret = -EIO;
goto error_device;
}
#if USE_FB_NOTIFY
info->fb_notifier.notifier_call = mip4_ts_fb_notifier_callback;
fb_register_client(&info->fb_notifier);
#endif /* USE_FB_NOTIFY */
device_init_wakeup(&client->dev, true);
#if USE_DEV
/* Create dev node (optional) */
if (mip4_ts_dev_create(info)) {
dev_err(&client->dev, "%s [ERROR] mip4_ts_dev_create\n", __func__);
}
info->class = class_create(THIS_MODULE, MIP4_TS_DEVICE_NAME);
device_create(info->class, NULL, info->mip4_ts_dev, NULL, MIP4_TS_DEVICE_NAME);
#endif /* USE_DEV */
#if USE_SYS
/* Create sysfs for development functions (optional) */
if (mip4_ts_sysfs_create(info)) {
dev_err(&client->dev, "%s [ERROR] mip4_ts_sysfs_create\n", __func__);
}
#endif /* USE_SYS */
#if 0//USE_CMD
/* Create sysfs for command functions (optional) */
if (mip4_ts_sysfs_cmd_create(info)) {
dev_err(&client->dev, "%s [ERROR] mip4_ts_sysfs_cmd_create\n", __func__);
}
#endif /* USE_CMD */
/* Create sysfs */
if (sysfs_create_group(&client->dev.kobj, &mip4_ts_attr_group)) {
dev_err(&client->dev, "%s [ERROR] sysfs_create_group\n", __func__);
}
if (sysfs_create_link(NULL, &client->dev.kobj, MIP4_TS_DEVICE_NAME)) {
dev_err(&client->dev, "%s [ERROR] sysfs_create_link\n", __func__);
}
dev_dbg(&client->dev, "%s [DONE]\n", __func__);
dev_info(&client->dev, "MELFAS " CHIP_NAME " Touchscreen\n");
return 0;
error_irq:
free_irq(info->irq, info);
error_device:
input_unregister_device(info->input_dev);
error_info:
error_i2c:
dev_dbg(&client->dev, "%s [ERROR]\n", __func__);
dev_err(&client->dev, "MELFAS " CHIP_NAME " Touchscreen initialization failed.\n");
return ret;
}
/*
* Remove driver
*/
static int mip4_ts_remove(struct i2c_client *client)
{
struct mip4_ts_info *info = i2c_get_clientdata(client);
disable_irq(info->client->irq);
free_irq(info->client->irq, info);
#if 0// USE_CMD
mip4_ts_sysfs_cmd_remove(info);
#endif /* USE_CMD */
#if USE_SYS
mip4_ts_sysfs_remove(info);
#endif /* USE_SYS */
sysfs_remove_group(&info->client->dev.kobj, &mip4_ts_attr_group);
sysfs_remove_link(NULL, MIP4_TS_DEVICE_NAME);
#if USE_DEV
device_destroy(info->class, info->mip4_ts_dev);
class_destroy(info->class);
#endif /* USE_DEV */
#if USE_FB_NOTIFY
fb_unregister_client(&info->fb_notifier);
#endif /* USE_FB_NOTIFY */
input_unregister_device(info->input_dev);
info->input_dev = NULL;
return 0;
}
/*
* Shutdown
*/
static void mip4_ts_shutdown(struct i2c_client *client)
{
mip4_ts_remove(client);
}
#ifdef CONFIG_PM
/*
* Device suspend event handler
*/
int mip4_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts_info *info = i2c_get_clientdata(client);
dev_dbg(&client->dev, "%s [START]\n", __func__);
mip4_ts_disable(info);
dev_dbg(&client->dev, "%s [DONE]\n", __func__);
return 0;
}
/*
* Device resume event handler
*/
int mip4_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts_info *info = i2c_get_clientdata(client);
int ret = 0;
dev_dbg(&client->dev, "%s [START]\n", __func__);
mip4_ts_enable(info);
dev_dbg(&client->dev, "%s [DONE]\n", __func__);
return ret;
}
/*
* PM info
*/
const struct dev_pm_ops mip4_ts_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mip4_ts_suspend, mip4_ts_resume)
};
#endif /* CONFIG_PM */
#ifdef CONFIG_OF
/*
* Devicetree match table
*/
static const struct of_device_id mip4_ts_of_match_table[] = {
{.compatible = "melfas,mip4_ts",},
{},
};
MODULE_DEVICE_TABLE(of, mip4_ts_of_match_table);
#endif /* CONFIG_OF */
#ifdef CONFIG_ACPI
/*
* ACPI match table
*/
static const struct acpi_device_id mip4_ts_acpi_match_table[] = {
{ACPI_ID, 0},
{},
};
MODULE_DEVICE_TABLE(acpi, mip4_ts_acpi_match_table);
#endif /* CONFIG_ACPI */
/*
* I2C Device ID
*/
static const struct i2c_device_id mip4_ts_id[] = {
{MIP4_TS_DEVICE_NAME, 0},
{},
};
MODULE_DEVICE_TABLE(i2c, mip4_ts_id);
/*
* I2C driver info
*/
static struct i2c_driver mip4_ts_driver = {
.id_table = mip4_ts_id,
.probe = mip4_ts_probe,
.remove = mip4_ts_remove,
.shutdown = mip4_ts_shutdown,
.driver = {
.name = MIP4_TS_DEVICE_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = of_match_ptr(mip4_ts_of_match_table),
#endif /* CONFIG_OF */
#ifdef CONFIG_ACPI
.acpi_match_table = ACPI_PTR(mip4_ts_acpi_match_table),
#endif /* CONFIG_ACPI */
#ifdef CONFIG_PM
.pm = &mip4_ts_pm_ops,
#endif /* CONFIG_PM */
},
};
module_i2c_driver(mip4_ts_driver);
MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen");
MODULE_VERSION("2018.12.04");
MODULE_AUTHOR("MELFAS Inc. <dev@melfas.com>");
MODULE_LICENSE("GPL");