Skip to content

Instantly share code, notes, and snippets.

@ma34s
Last active December 12, 2015 09:08
Show Gist options
  • Save ma34s/4748942 to your computer and use it in GitHub Desktop.
Save ma34s/4748942 to your computer and use it in GitHub Desktop.
mms_ts.cのデバッグコードについて
/*
* mms_ts.c - Touchscreen driver for Melfas MMS-series touch controllers
*
* Copyright (C) 2011 Google Inc.
* Author: Dima Zavin <dima@android.com>
* Simon Wilson <simonwilson@google.com>
*
* ISP reflashing code based on original code from Melfas.
*
* 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.
*
*/
#define DEBUG
/* #define VERBOSE_DEBUG */
/*#define SEC_TSP_DEBUG*/
/* #define SEC_TSP_VERBOSE_DEBUG */
/* #define FORCE_FW_FLASH */
/* #define FORCE_FW_PASS */
/* #define ESD_DEBUG */
#define SEC_TSP_FACTORY_TEST
#define SEC_TSP_FW_UPDATE
#define TSP_BUF_SIZE 1024
#define FAIL -1
#include <linux/delay.h>
#include <linux/earlysuspend.h>
#include <linux/firmware.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <mach/gpio.h>
#include <linux/uaccess.h>
#include <mach/cpufreq.h>
#include <mach/dev.h>
#include <linux/platform_data/mms_ts.h>
#include <asm/unaligned.h>
#define MAX_FINGERS 10
#define MAX_WIDTH 30
#define MAX_PRESSURE 255
#define MAX_ANGLE 90
#define MIN_ANGLE -90
/* Registers */
#define MMS_MODE_CONTROL 0x01
#define MMS_XYRES_HI 0x02
#define MMS_XRES_LO 0x03
#define MMS_YRES_LO 0x04
#define MMS_INPUT_EVENT_PKT_SZ 0x0F
#define MMS_INPUT_EVENT0 0x10
#define FINGER_EVENT_SZ 8
#define MMS_TSP_REVISION 0xF0
#define MMS_HW_REVISION 0xF1
#define MMS_COMPAT_GROUP 0xF2
#define MMS_FW_VERSION 0xF3
enum {
ISP_MODE_FLASH_ERASE = 0x59F3,
ISP_MODE_FLASH_WRITE = 0x62CD,
ISP_MODE_FLASH_READ = 0x6AC9,
};
/* each address addresses 4-byte words */
#define ISP_MAX_FW_SIZE (0x1F00 * 4)
#define ISP_IC_INFO_ADDR 0x1F00
#ifdef SEC_TSP_FW_UPDATE
#define WORD_SIZE 4
#define ISC_PKT_SIZE 1029
#define ISC_PKT_DATA_SIZE 1024
#define ISC_PKT_HEADER_SIZE 3
#define ISC_PKT_NUM 31
#define ISC_ENTER_ISC_CMD 0x5F
#define ISC_ENTER_ISC_DATA 0x01
#define ISC_CMD 0xAE
#define ISC_ENTER_UPDATE_DATA 0x55
#define ISC_ENTER_UPDATE_DATA_LEN 9
#define ISC_DATA_WRITE_SUB_CMD 0xF1
#define ISC_EXIT_ISC_SUB_CMD 0x0F
#define ISC_EXIT_ISC_SUB_CMD2 0xF0
#define ISC_CHECK_STATUS_CMD 0xAF
#define ISC_CONFIRM_CRC 0x03
#define ISC_DEFAULT_CRC 0xFFFF
#endif
#ifdef SEC_TSP_FACTORY_TEST
#define TX_NUM 26
#define RX_NUM 14
#define NODE_NUM 364 /* 26x14 */
/* VSC(Vender Specific Command) */
#define MMS_VSC_CMD 0xB0 /* vendor specific command */
#define MMS_VSC_MODE 0x1A /* mode of vendor */
#define MMS_VSC_CMD_ENTER 0X01
#define MMS_VSC_CMD_CM_DELTA 0X02
#define MMS_VSC_CMD_CM_ABS 0X03
#define MMS_VSC_CMD_EXIT 0X05
#define MMS_VSC_CMD_INTENSITY 0X04
#define MMS_VSC_CMD_RAW 0X06
#define MMS_VSC_CMD_REFER 0X07
#define TSP_CMD_STR_LEN 32
#define TSP_CMD_RESULT_STR_LEN 512
#define TSP_CMD_PARAM_NUM 8
#endif /* SEC_TSP_FACTORY_TEST */
/* Touch booster */
#if defined(CONFIG_EXYNOS4_CPUFREQ) &&\
defined(CONFIG_BUSFREQ_OPP)
#define TOUCH_BOOSTER 1
#define TOUCH_BOOSTER_OFF_TIME 100
#define TOUCH_BOOSTER_CHG_TIME 200
#else
#define TOUCH_BOOSTER 0
#endif
struct device *sec_touchscreen;
static struct device *bus_dev;
int touch_is_pressed = 0;
static int ma34_debug_probe_status;
static int ma34_debug_fw_status;
#define ISC_DL_MODE 1
/* 4.8" OCTA LCD */
#define FW_VERSION_4_8 0xBD
#define MAX_FW_PATH 255
#define TSP_FW_FILENAME "melfas_fw.bin"
#if ISC_DL_MODE /* ISC_DL_MODE start */
/*
* Default configuration of ISC mode
*/
#define DEFAULT_SLAVE_ADDR 0x48
#define SECTION_NUM 4
#define SECTION_NAME_LEN 5
#define PAGE_HEADER 3
#define PAGE_DATA 1024
#define PAGE_TAIL 2
#define PACKET_SIZE (PAGE_HEADER + PAGE_DATA + PAGE_TAIL)
#define TS_WRITE_REGS_LEN 1030
#define TIMEOUT_CNT 10
#define STRING_BUF_LEN 100
/* State Registers */
#define MIP_ADDR_INPUT_INFORMATION 0x01
#define ISC_ADDR_VERSION 0xE1
#define ISC_ADDR_SECTION_PAGE_INFO 0xE5
/* Config Update Commands */
#define ISC_CMD_ENTER_ISC 0x5F
#define ISC_CMD_ENTER_ISC_PARA1 0x01
#define ISC_CMD_UPDATE_MODE 0xAE
#define ISC_SUBCMD_ENTER_UPDATE 0x55
#define ISC_SUBCMD_DATA_WRITE 0XF1
#define ISC_SUBCMD_LEAVE_UPDATE_PARA1 0x0F
#define ISC_SUBCMD_LEAVE_UPDATE_PARA2 0xF0
#define ISC_CMD_CONFIRM_STATUS 0xAF
#define ISC_STATUS_UPDATE_MODE 0x01
#define ISC_STATUS_CRC_CHECK_SUCCESS 0x03
#define ISC_CHAR_2_BCD(num) (((num/10)<<4) + (num%10))
#define ISC_MAX(x, y) (((x) > (y)) ? (x) : (y))
static const char section_name[SECTION_NUM][SECTION_NAME_LEN] = {
"BOOT", "CORE", "PRIV", "PUBL"
};
static const unsigned char crc0_buf[31] = {
0x1D, 0x2C, 0x05, 0x34, 0x95, 0xA4, 0x8D, 0xBC,
0x59, 0x68, 0x41, 0x70, 0xD1, 0xE0, 0xC9, 0xF8,
0x3F, 0x0E, 0x27, 0x16, 0xB7, 0x86, 0xAF, 0x9E,
0x7B, 0x4A, 0x63, 0x52, 0xF3, 0xC2, 0xEB
};
static const unsigned char crc1_buf[31] = {
0x1E, 0x9C, 0xDF, 0x5D, 0x76, 0xF4, 0xB7, 0x35,
0x2A, 0xA8, 0xEB, 0x69, 0x42, 0xC0, 0x83, 0x01,
0x04, 0x86, 0xC5, 0x47, 0x6C, 0xEE, 0xAD, 0x2F,
0x30, 0xB2, 0xF1, 0x73, 0x58, 0xDA, 0x99
};
static tISCFWInfo_t mbin_info[SECTION_NUM];
static tISCFWInfo_t ts_info[SECTION_NUM]; /* read F/W version from IC */
static bool section_update_flag[SECTION_NUM];
const struct firmware *fw_mbin[SECTION_NUM];
static unsigned char g_wr_buf[1024 + 3 + 2];
#endif
enum fw_flash_mode {
ISP_FLASH,
ISC_FLASH,
};
enum {
BUILT_IN = 0,
UMS,
REQ_FW,
};
struct tsp_callbacks {
void (*inform_charger)(struct tsp_callbacks *tsp_cb, bool mode);
};
struct mms_ts_info {
struct i2c_client *client;
struct input_dev *input_dev;
char phys[32];
int max_x;
int max_y;
bool invert_x;
bool invert_y;
const u8 *config_fw_version;
int irq;
int (*power) (bool on);
struct melfas_tsi_platform_data *pdata;
struct early_suspend early_suspend;
/* protects the enabled flag */
struct mutex lock;
bool enabled;
void (*register_cb)(void *);
struct tsp_callbacks callbacks;
bool ta_status;
bool noise_mode;
unsigned char finger_state[MAX_FINGERS];
#if defined(SEC_TSP_FW_UPDATE)
u8 fw_update_state;
#endif
u8 fw_ic_ver;
enum fw_flash_mode fw_flash_mode;
#if TOUCH_BOOSTER
struct delayed_work work_dvfs_off;
struct delayed_work work_dvfs_chg;
bool dvfs_lock_status;
int cpufreq_level;
struct mutex dvfs_lock;
#endif
#if defined(SEC_TSP_FACTORY_TEST)
struct list_head cmd_list_head;
u8 cmd_state;
char cmd[TSP_CMD_STR_LEN];
int cmd_param[TSP_CMD_PARAM_NUM];
char cmd_result[TSP_CMD_RESULT_STR_LEN];
struct mutex cmd_lock;
bool cmd_is_running;
unsigned int reference[NODE_NUM];
unsigned int raw[NODE_NUM]; /* CM_ABS */
unsigned int inspection[NODE_NUM];/* CM_DELTA */
unsigned int intensity[NODE_NUM];
bool ft_flag;
#endif /* SEC_TSP_FACTORY_TEST */
};
struct mms_fw_image {
__le32 hdr_len;
__le32 data_len;
__le32 fw_ver;
__le32 hdr_ver;
u8 data[0];
} __packed;
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mms_ts_early_suspend(struct early_suspend *h);
static void mms_ts_late_resume(struct early_suspend *h);
#endif
#if TOUCH_BOOSTER
static bool dvfs_lock_status = false;
static bool press_status = false;
#endif
#if defined(SEC_TSP_FACTORY_TEST)
#define TSP_CMD(name, func) .cmd_name = name, .cmd_func = func
struct tsp_cmd {
struct list_head list;
const char *cmd_name;
void (*cmd_func)(void *device_data);
};
static void fw_update(void *device_data);
static void get_fw_ver_bin(void *device_data);
static void get_fw_ver_ic(void *device_data);
static void get_config_ver(void *device_data);
static void get_threshold(void *device_data);
static void module_off_master(void *device_data);
static void module_on_master(void *device_data);
static void module_off_slave(void *device_data);
static void module_on_slave(void *device_data);
static void get_chip_vendor(void *device_data);
static void get_chip_name(void *device_data);
static void get_reference(void *device_data);
static void get_cm_abs(void *device_data);
static void get_cm_delta(void *device_data);
static void get_intensity(void *device_data);
static void get_x_num(void *device_data);
static void get_y_num(void *device_data);
static void run_reference_read(void *device_data);
static void run_cm_abs_read(void *device_data);
static void run_cm_delta_read(void *device_data);
static void run_intensity_read(void *device_data);
static void not_support_cmd(void *device_data);
struct tsp_cmd tsp_cmds[] = {
{TSP_CMD("fw_update", fw_update),},
{TSP_CMD("get_fw_ver_bin", get_fw_ver_bin),},
{TSP_CMD("get_fw_ver_ic", get_fw_ver_ic),},
{TSP_CMD("get_config_ver", get_config_ver),},
{TSP_CMD("get_threshold", get_threshold),},
/* {TSP_CMD("module_off_master", module_off_master),},
{TSP_CMD("module_on_master", module_on_master),},
{TSP_CMD("module_off_slave", not_support_cmd),},
{TSP_CMD("module_on_slave", not_support_cmd),}, */
{TSP_CMD("get_chip_vendor", get_chip_vendor),},
{TSP_CMD("get_chip_name", get_chip_name),},
{TSP_CMD("get_x_num", get_x_num),},
{TSP_CMD("get_y_num", get_y_num),},
{TSP_CMD("get_reference", get_reference),},
{TSP_CMD("get_cm_abs", get_cm_abs),},
{TSP_CMD("get_cm_delta", get_cm_delta),},
{TSP_CMD("get_intensity", get_intensity),},
{TSP_CMD("run_reference_read", run_reference_read),},
{TSP_CMD("run_cm_abs_read", run_cm_abs_read),},
{TSP_CMD("run_cm_delta_read", run_cm_delta_read),},
{TSP_CMD("run_intensity_read", run_intensity_read),},
{TSP_CMD("not_support_cmd", not_support_cmd),},
};
#endif
#if TOUCH_BOOSTER
static void change_dvfs_lock(struct work_struct *work)
{
struct mms_ts_info *info = container_of(work,
struct mms_ts_info, work_dvfs_chg.work);
int ret;
mutex_lock(&info->dvfs_lock);
ret = dev_lock(bus_dev, sec_touchscreen, 267160); /* 266 Mhz setting */
if (ret < 0)
pr_err("%s: dev change bud lock failed(%d)\n",\
__func__, __LINE__);
else
pr_info("[TSP] change_dvfs_lock");
mutex_unlock(&info->dvfs_lock);
}
static void set_dvfs_off(struct work_struct *work)
{
struct mms_ts_info *info = container_of(work,
struct mms_ts_info, work_dvfs_off.work);
int ret;
mutex_lock(&info->dvfs_lock);
ret = dev_unlock(bus_dev, sec_touchscreen);
if (ret < 0)
pr_err("%s: dev unlock failed(%d)\n",
__func__, __LINE__);
exynos_cpufreq_lock_free(DVFS_LOCK_ID_TSP);
info->dvfs_lock_status = false;
pr_info("[TSP] DVFS Off!");
mutex_unlock(&info->dvfs_lock);
}
static void set_dvfs_lock(struct mms_ts_info *info, uint32_t on)
{
int ret;
mutex_lock(&info->dvfs_lock);
if (info->cpufreq_level <= 0) {
ret = exynos_cpufreq_get_level(800000, &info->cpufreq_level);
if (ret < 0)
pr_err("[TSP] exynos_cpufreq_get_level error");
goto out;
}
if (on == 0) {
if (info->dvfs_lock_status) {
cancel_delayed_work(&info->work_dvfs_chg);
schedule_delayed_work(&info->work_dvfs_off,
msecs_to_jiffies(TOUCH_BOOSTER_OFF_TIME));
}
} else if (on == 1) {
cancel_delayed_work(&info->work_dvfs_off);
if (!info->dvfs_lock_status) {
ret = dev_lock(bus_dev, sec_touchscreen, 400200);
if (ret < 0) {
pr_err("%s: dev lock failed(%d)\n",\
__func__, __LINE__);
}
ret = exynos_cpufreq_lock(DVFS_LOCK_ID_TSP,
info->cpufreq_level);
if (ret < 0)
pr_err("%s: cpu lock failed(%d)\n",\
__func__, __LINE__);
schedule_delayed_work(&info->work_dvfs_chg,
msecs_to_jiffies(TOUCH_BOOSTER_CHG_TIME));
info->dvfs_lock_status = true;
pr_info("[TSP] DVFS On![%d]", info->cpufreq_level);
}
} else if (on == 2) {
cancel_delayed_work(&info->work_dvfs_off);
cancel_delayed_work(&info->work_dvfs_chg);
schedule_work(&info->work_dvfs_off.work);
}
out:
mutex_unlock(&info->dvfs_lock);
}
#endif
static inline void mms_pwr_on_reset(struct mms_ts_info *info)
{
struct i2c_adapter *adapter = to_i2c_adapter(info->client->dev.parent);
if (!info->pdata->mux_fw_flash) {
dev_info(&info->client->dev,
"missing platform data, can't do power-on-reset\n");
return;
}
i2c_lock_adapter(adapter);
info->pdata->mux_fw_flash(true);
info->pdata->power(false);
gpio_direction_output(info->pdata->gpio_sda, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_int, 0);
msleep(50);
info->pdata->power(true);
msleep(200);
info->pdata->mux_fw_flash(false);
i2c_unlock_adapter(adapter);
/* TODO: Seems long enough for the firmware to boot.
* Find the right value */
msleep(250);
}
static void release_all_fingers(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
int i;
printk(KERN_DEBUG "[TSP] %s\n", __func__);
for (i = 0; i < MAX_FINGERS; i++) {
if (info->finger_state[i] == 1) {
dev_notice(&client->dev, "finger %d up(force)\n", i);
}
info->finger_state[i] = 0;
input_mt_slot(info->input_dev, i);
input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER,
false);
}
input_sync(info->input_dev);
#if TOUCH_BOOSTER
set_dvfs_lock(info, 2);
pr_info("[TSP] dvfs_lock free.\n ");
#endif
}
static void mms_set_noise_mode(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
if (!(info->noise_mode && info->enabled))
return;
dev_notice(&client->dev, "%s\n", __func__);
if (info->ta_status) {
dev_notice(&client->dev, "noise_mode & TA connect!!!\n");
i2c_smbus_write_byte_data(info->client, 0x30, 0x1);
} else {
dev_notice(&client->dev, "noise_mode & TA disconnect!!!\n");
i2c_smbus_write_byte_data(info->client, 0x30, 0x2);
info->noise_mode = 0;
}
}
static void reset_mms_ts(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
if (info->enabled == false)
return;
dev_notice(&client->dev, "%s++\n", __func__);
disable_irq_nosync(info->irq);
info->enabled = false;
touch_is_pressed = 0;
release_all_fingers(info);
mms_pwr_on_reset(info);
enable_irq(info->irq);
info->enabled = true;
if (info->ta_status) {
dev_notice(&client->dev, "TA connect!!!\n");
i2c_smbus_write_byte_data(info->client, 0x33, 0x1);
} else {
dev_notice(&client->dev, "TA disconnect!!!\n");
i2c_smbus_write_byte_data(info->client, 0x33, 0x2);
}
mms_set_noise_mode(info);
dev_notice(&client->dev, "%s--\n", __func__);
}
static void melfas_ta_cb(struct tsp_callbacks *cb, bool ta_status)
{
struct mms_ts_info *info =
container_of(cb, struct mms_ts_info, callbacks);
struct i2c_client *client = info->client;
dev_notice(&client->dev, "%s\n", __func__);
info->ta_status = ta_status;
if (info->enabled) {
if (info->ta_status) {
dev_notice(&client->dev, "TA connect!!!\n");
i2c_smbus_write_byte_data(info->client, 0x33, 0x1);
} else {
dev_notice(&client->dev, "TA disconnect!!!\n");
i2c_smbus_write_byte_data(info->client, 0x33, 0x2);
}
mms_set_noise_mode(info);
}
}
static irqreturn_t mms_ts_interrupt(int irq, void *dev_id)
{
struct mms_ts_info *info = dev_id;
struct i2c_client *client = info->client;
u8 buf[MAX_FINGERS * FINGER_EVENT_SZ] = { 0 };
int ret;
int i;
int sz;
u8 reg = MMS_INPUT_EVENT0;
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = 0,
.buf = &reg,
.len = 1,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
.buf = buf,
},
};
sz = i2c_smbus_read_byte_data(client, MMS_INPUT_EVENT_PKT_SZ);
if (sz < 0) {
dev_err(&client->dev, "%s bytes=%d\n", __func__, sz);
for (i = 0; i < 50; i++) {
sz = i2c_smbus_read_byte_data(client,
MMS_INPUT_EVENT_PKT_SZ);
if (sz > 0)
break;
}
if (i == 50) {
dev_dbg(&client->dev, "i2c failed... reset!!\n");
reset_mms_ts(info);
goto out;
}
}
/* BUG_ON(sz > MAX_FINGERS*FINGER_EVENT_SZ); */
if (sz == 0)
goto out;
if (sz > MAX_FINGERS*FINGER_EVENT_SZ) {
dev_err(&client->dev, "[TSP] abnormal data inputed.\n");
goto out;
}
msg[1].len = sz;
ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
if (ret != ARRAY_SIZE(msg)) {
dev_err(&client->dev,
"failed to read %d bytes of touch data (%d)\n",
sz, ret);
goto out;
}
#if defined(VERBOSE_DEBUG)
print_hex_dump(KERN_DEBUG, "mms_ts raw: ",
DUMP_PREFIX_OFFSET, 32, 1, buf, sz, false);
#endif
if (buf[0] == 0x0F) { /* ESD */
dev_dbg(&client->dev, "ESD DETECT.... reset!!\n");
reset_mms_ts(info);
goto out;
}
if (buf[0] == 0x0E) { /* NOISE MODE */
dev_dbg(&client->dev, "[TSP] noise mode enter!!\n");
info->noise_mode = 1 ;
mms_set_noise_mode(info);
goto out;
}
for (i = 0; i < sz; i += FINGER_EVENT_SZ) {
u8 *tmp = &buf[i];
int id = (tmp[0] & 0xf) - 1;
int x = tmp[2] | ((tmp[1] & 0xf) << 8);
int y = tmp[3] | (((tmp[1] >> 4) & 0xf) << 8);
int angle = (tmp[5] >= 127) ? (-(256 - tmp[5])) : tmp[5];
int palm = (tmp[0] & 0x10) >> 4;
if (info->invert_x) {
x = info->max_x - x;
if (x < 0)
x = 0;
}
if (info->invert_y) {
y = info->max_y - y;
if (y < 0)
y = 0;
}
if (id >= MAX_FINGERS) {
dev_notice(&client->dev, \
"finger id error [%d]\n", id);
reset_mms_ts(info);
goto out;
}
if ((tmp[0] & 0x80) == 0) {
#if defined(SEC_TSP_DEBUG)
dev_dbg(&client->dev,
"finger id[%d]: x=%d y=%d p=%d w=%d major=%d minor=%d angle=%d palm=%d\n",
id, x, y, tmp[5], tmp[4], tmp[6], tmp[7]
, angle, palm);
#else
if (info->finger_state[id] != 0) {
dev_notice(&client->dev,
"finger [%d] up, palm %d\n", id, palm);
}
#endif
input_mt_slot(info->input_dev, id);
input_mt_report_slot_state(info->input_dev,
MT_TOOL_FINGER, false);
info->finger_state[id] = 0;
continue;
}
input_mt_slot(info->input_dev, id);
input_mt_report_slot_state(info->input_dev,
MT_TOOL_FINGER, true);
input_report_abs(info->input_dev, ABS_MT_WIDTH_MAJOR, tmp[4]);
input_report_abs(info->input_dev, ABS_MT_POSITION_X, x);
input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y);
input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, tmp[6]);
input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR, tmp[7]);
input_report_abs(info->input_dev, ABS_MT_ANGLE, angle);
input_report_abs(info->input_dev, ABS_MT_PALM, palm);
#if defined(SEC_TSP_DEBUG)
if (info->finger_state[id] == 0) {
info->finger_state[id] = 1;
dev_dbg(&client->dev,
"finger id[%d]: x=%d y=%d w=%d major=%d minor=%d angle=%d palm=%d\n",
id, x, y, tmp[4], tmp[6], tmp[7]
, angle, palm);
if (finger_event_sz == 10)
dev_dbg(&client->dev, \
"pressure = %d\n", tmp[8]);
}
#else
if (info->finger_state[id] == 0) {
info->finger_state[id] = 1;
dev_notice(&client->dev,
"finger [%d] down, palm %d\n", id, palm);
}
#endif
}
input_sync(info->input_dev);
touch_is_pressed = 0;
for (i = 0; i < MAX_FINGERS; i++) {
if (info->finger_state[i] == 1)
touch_is_pressed++;
}
#if TOUCH_BOOSTER
set_dvfs_lock(info, !!touch_is_pressed);
#endif
out:
return IRQ_HANDLED;
}
int get_tsp_status(void)
{
return touch_is_pressed;
}
EXPORT_SYMBOL(get_tsp_status);
#if ISC_DL_MODE
static int mms100_i2c_read(struct i2c_client *client,
u16 addr, u16 length, u8 *value)
{
struct i2c_adapter *adapter = client->adapter;
struct i2c_msg msg;
int ret = -1;
msg.addr = client->addr;
msg.flags = 0x00;
msg.len = 1;
msg.buf = (u8 *) &addr;
ret = i2c_transfer(adapter, &msg, 1);
if (ret >= 0) {
msg.addr = client->addr;
msg.flags = I2C_M_RD;
msg.len = length;
msg.buf = (u8 *) value;
ret = i2c_transfer(adapter, &msg, 1);
}
if (ret < 0)
pr_err("[TSP] : read error : [%d]", ret);
return ret;
}
static int mms100_reset(struct mms_ts_info *info)
{
info->pdata->power(false);
msleep(30);
info->pdata->power(true);
msleep(300);
return ISC_SUCCESS;
}
/*
static int mms100_check_operating_mode(struct i2c_client *_client,
const int _error_code)
{
int ret;
unsigned char rd_buf = 0x00;
unsigned char count = 0;
if(_client == NULL)
pr_err("[TSP ISC] _client is null");
ret = mms100_i2c_read(_client, ISC_ADDR_VERSION, 1, &rd_buf);
if (ret<0) {
pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n",
__func__, __LINE__, ret);
return _error_code;
}
return ISC_SUCCESS;
}
*/
static int mms100_get_version_info(struct i2c_client *_client)
{
int i, ret;
unsigned char rd_buf[8];
/* config version brust read (core, private, public) */
ret = mms100_i2c_read(_client, ISC_ADDR_VERSION, 4, rd_buf);
if (ret < 0) {
pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n",
__func__, __LINE__, ret);
return ISC_I2C_ERROR;
}
for (i = 0; i < SECTION_NUM; i++)
ts_info[i].version = rd_buf[i];
ts_info[SEC_CORE].compatible_version =
ts_info[SEC_BOOTLOADER].version;
ts_info[SEC_PRIVATE_CONFIG].compatible_version =
ts_info[SEC_PUBLIC_CONFIG].compatible_version =
ts_info[SEC_CORE].version;
ret = mms100_i2c_read(_client, ISC_ADDR_SECTION_PAGE_INFO, 8, rd_buf);
if (ret < 0) {
pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n",
__func__, __LINE__, ret);
return ISC_I2C_ERROR;
}
for (i = 0; i < SECTION_NUM; i++) {
ts_info[i].start_addr = rd_buf[i];
ts_info[i].end_addr = rd_buf[i + SECTION_NUM];
}
for (i = 0; i < SECTION_NUM; i++) {
pr_info("TS : Section(%d) version: 0x%02X\n",
i, ts_info[i].version);
pr_info("TS : Section(%d) Start Address: 0x%02X\n",
i, ts_info[i].start_addr);
pr_info("TS : Section(%d) End Address: 0x%02X\n",
i, ts_info[i].end_addr);
pr_info("TS : Section(%d) Compatibility: 0x%02X\n",
i, ts_info[i].compatible_version);
}
return ISC_SUCCESS;
}
static int mms100_seek_section_info(void)
{
int i;
char str_buf[STRING_BUF_LEN];
char name_buf[SECTION_NAME_LEN];
int version;
int page_num;
const unsigned char *buf;
int next_ptr;
for (i = 0; i < SECTION_NUM; i++) {
if (fw_mbin[i] == NULL) {
buf = NULL;
pr_info("[TSP ISC] fw_mbin[%d]->data is NULL", i);
} else {
buf = fw_mbin[i]->data;
}
if (buf == NULL) {
mbin_info[i].version = ts_info[i].version;
mbin_info[i].compatible_version =
ts_info[i].compatible_version;
mbin_info[i].start_addr = ts_info[i].start_addr;
mbin_info[i].end_addr = ts_info[i].end_addr;
} else {
next_ptr = 0;
do {
sscanf(buf + next_ptr, "%s", str_buf);
next_ptr += strlen(str_buf) + 1;
} while (!strstr(str_buf, "SECTION_NAME"));
sscanf(buf + next_ptr, "%s%s", str_buf, name_buf);
if (strncmp(section_name[i], name_buf,
SECTION_NAME_LEN))
return ISC_FILE_FORMAT_ERROR;
do {
sscanf(buf + next_ptr, "%s", str_buf);
next_ptr += strlen(str_buf) + 1;
} while (!strstr(str_buf, "SECTION_VERSION"));
sscanf(buf + next_ptr, "%s%d", str_buf, &version);
mbin_info[i].version = ISC_CHAR_2_BCD(version);
do {
sscanf(buf + next_ptr, "%s", str_buf);
next_ptr += strlen(str_buf) + 1;
} while (!strstr(str_buf, "START_PAGE_ADDR"));
sscanf(buf + next_ptr, "%s%d", str_buf, &page_num);
mbin_info[i].start_addr = page_num;
do {
sscanf(buf + next_ptr, "%s", str_buf);
next_ptr += strlen(str_buf) + 1;
} while (!strstr(str_buf, "END_PAGE_ADDR"));
sscanf(buf + next_ptr, "%s%d", str_buf, &page_num);
mbin_info[i].end_addr = page_num;
do {
sscanf(buf + next_ptr, "%s", str_buf);
next_ptr += strlen(str_buf) + 1;
} while (!strstr(str_buf, "COMPATIBLE_VERSION"));
sscanf(buf + next_ptr, "%s%d", str_buf, &version);
mbin_info[i].compatible_version =
ISC_CHAR_2_BCD(version);
do {
sscanf(buf + next_ptr, "%s", str_buf);
next_ptr += strlen(str_buf) + 1;
} while (!strstr(str_buf, "[Binary]"));
if (mbin_info[i].version == 0xFF)
return ISC_FILE_FORMAT_ERROR;
}
}
for (i = 0; i < SECTION_NUM; i++) {
pr_info("[TSP ISC] MBin : Section(%d) Version: 0x%02X\n",
i, mbin_info[i].version);
pr_info("[TSP ISC] MBin : Section(%d) Start Address: 0x%02X\n",
i, mbin_info[i].start_addr);
pr_info("[TSP ISC] MBin : Section(%d) End Address: 0x%02X\n",
i, mbin_info[i].end_addr);
pr_info("[TSP ISC] MBin : Section(%d) Compatibility: 0x%02X\n",
i, mbin_info[i].compatible_version);
}
return ISC_SUCCESS;
}
static eISCRet_t mms100_compare_version_info(struct i2c_client *_client)
{
int i, ret;
unsigned char expected_compatibility[SECTION_NUM];
if (mms100_get_version_info(_client) != ISC_SUCCESS)
return ISC_I2C_ERROR;
ret = mms100_seek_section_info();
/* Check update areas , 0 : bootloader 1: core 2: private 3: public */
for (i = 0; i < SECTION_NUM; i++) {
if ((mbin_info[i].version == 0) ||
(mbin_info[i].version != ts_info[i].version)) {
section_update_flag[i] = true;
pr_info("[TSP ISC] [%d] section will be updated!", i);
}
}
section_update_flag[0] = false;
pr_info("[TSP ISC] [%d] [%d] [%d]", section_update_flag[1],
section_update_flag[2], section_update_flag[3]);
if (section_update_flag[SEC_BOOTLOADER]) {
expected_compatibility[SEC_CORE] =
mbin_info[SEC_BOOTLOADER].version;
} else {
expected_compatibility[SEC_CORE] =
ts_info[SEC_BOOTLOADER].version;
}
if (section_update_flag[SEC_CORE]) {
expected_compatibility[SEC_PUBLIC_CONFIG] =
expected_compatibility[SEC_PRIVATE_CONFIG] =
mbin_info[SEC_CORE].version;
} else {
expected_compatibility[SEC_PUBLIC_CONFIG] =
expected_compatibility[SEC_PRIVATE_CONFIG] =
ts_info[SEC_CORE].version;
}
for (i = SEC_CORE; i < SEC_PUBLIC_CONFIG; i++) {
if (section_update_flag[i]) {
pr_info("[TSP ISC] section_update_flag(%d), 0x%02x, 0x%02x\n",
i, expected_compatibility[i],
mbin_info[i].compatible_version);
if (expected_compatibility[i] !=
mbin_info[i].compatible_version)
return ISC_COMPATIVILITY_ERROR;
} else {
pr_info("[TSP ISC] !section_update_flag(%d), 0x%02x, 0x%02x\n",
i, expected_compatibility[i],
ts_info[i].compatible_version);
if (expected_compatibility[i] !=
ts_info[i].compatible_version)
return ISC_COMPATIVILITY_ERROR;
}
}
return ISC_SUCCESS;
}
static int mms100_enter_ISC_mode(struct i2c_client *_client)
{
int ret;
unsigned char wr_buf[2];
pr_info("[TSP ISC] %s\n", __func__);
wr_buf[0] = ISC_CMD_ENTER_ISC;
wr_buf[1] = ISC_CMD_ENTER_ISC_PARA1;
ret = i2c_master_send(_client, wr_buf, 2);
if (ret < 0) {
pr_info("[TSP ISC] %s,%d: i2c write fail[%d]\n",
__func__, __LINE__, ret);
return ISC_I2C_ERROR;
}
msleep(50);
return ISC_SUCCESS;
}
static int mms100_enter_config_update(struct i2c_client *_client)
{
int ret;
unsigned char wr_buf[10] = {0,};
unsigned char rd_buf;
wr_buf[0] = ISC_CMD_UPDATE_MODE;
wr_buf[1] = ISC_SUBCMD_ENTER_UPDATE;
ret = i2c_master_send(_client, wr_buf, 10);
if (ret < 0) {
pr_info("[TSP ISC] %s,%d: i2c write fail[%d]\n",
__func__, __LINE__, ret);
return ISC_I2C_ERROR;
}
ret = mms100_i2c_read(_client, ISC_CMD_CONFIRM_STATUS, 1, &rd_buf);
if (ret < 0) {
pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n",
__func__, __LINE__, ret);
return ISC_I2C_ERROR;
}
if (rd_buf != ISC_STATUS_UPDATE_MODE)
return ISC_UPDATE_MODE_ENTER_ERROR;
pr_info("[TSP ISC]End mms100_enter_config_update()\n");
return ISC_SUCCESS;
}
static int mms100_ISC_clear_page(struct i2c_client *_client,
unsigned char _page_addr)
{
int ret;
unsigned char rd_buf;
memset(&g_wr_buf[3], 0xFF, PAGE_DATA);
g_wr_buf[0] = ISC_CMD_UPDATE_MODE; /* command */
g_wr_buf[1] = ISC_SUBCMD_DATA_WRITE; /* sub_command */
g_wr_buf[2] = _page_addr;
g_wr_buf[PAGE_HEADER + PAGE_DATA] = crc0_buf[_page_addr];
g_wr_buf[PAGE_HEADER + PAGE_DATA + 1] = crc1_buf[_page_addr];
ret = i2c_master_send(_client, g_wr_buf, PACKET_SIZE);
if (ret < 0) {
pr_info("[TSP ISC] %s,%d: i2c write fail[%d]\n",
__func__, __LINE__, ret);
return ISC_I2C_ERROR;
}
ret = mms100_i2c_read(_client, ISC_CMD_CONFIRM_STATUS, 1, &rd_buf);
if (ret < 0) {
pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n",
__func__, __LINE__, ret);
return ISC_I2C_ERROR;
}
if (rd_buf != ISC_STATUS_CRC_CHECK_SUCCESS)
return ISC_UPDATE_MODE_ENTER_ERROR;
pr_info("[TSP ISC]End mms100_ISC_clear_page()\n");
return ISC_SUCCESS;
}
static int mms100_ISC_clear_validate_markers(struct i2c_client *_client)
{
int ret_msg;
int i, j;
bool is_matched_address;
for (i = SEC_CORE; i <= SEC_PUBLIC_CONFIG; i++) {
if (section_update_flag[i]) {
if (ts_info[i].end_addr <= 30 &&
ts_info[i].end_addr > 0) {
ret_msg = mms100_ISC_clear_page(_client,
ts_info[i].end_addr);
if (ret_msg != ISC_SUCCESS)
return ret_msg;
}
}
}
for (i = SEC_CORE; i <= SEC_PUBLIC_CONFIG; i++) {
if (section_update_flag[i]) {
is_matched_address = false;
for (j = SEC_CORE; j <= SEC_PUBLIC_CONFIG; j++) {
if (mbin_info[i].end_addr ==
ts_info[i].end_addr) {
is_matched_address = true;
break;
}
}
if (!is_matched_address) {
if (mbin_info[i].end_addr <= 30 &&
mbin_info[i].end_addr > 0) {
ret_msg = mms100_ISC_clear_page(_client,
mbin_info[i].end_addr);
if (ret_msg != ISC_SUCCESS)
return ret_msg;
}
}
}
}
return ISC_SUCCESS;
}
static int mms100_update_section_data(struct i2c_client *_client)
{
int i, ret, next_ptr;
unsigned char rd_buf;
const unsigned char *ptr_fw;
char str_buf[STRING_BUF_LEN];
int page_addr;
for (i = 0; i < SECTION_NUM; i++) {
if (section_update_flag[i]) {
pr_info("[TSP ISC] section data i2c flash : [%d]", i);
next_ptr = 0;
ptr_fw = fw_mbin[i]->data;
do {
sscanf(ptr_fw + next_ptr, "%s", str_buf);
next_ptr += strlen(str_buf) + 1;
} while (!strstr(str_buf, "[Binary]"));
ptr_fw = ptr_fw + next_ptr + 2;
for (page_addr = mbin_info[i].start_addr;
page_addr <= mbin_info[i].end_addr;
page_addr++) {
if (page_addr - mbin_info[i].start_addr > 0)
ptr_fw += PACKET_SIZE;
if ((ptr_fw[0] != ISC_CMD_UPDATE_MODE) ||
(ptr_fw[1] != ISC_SUBCMD_DATA_WRITE) ||
(ptr_fw[2] != page_addr))
return ISC_WRITE_BUFFER_ERROR;
ret = i2c_master_send(_client,
ptr_fw, PACKET_SIZE);
if (ret < 0) {
pr_info("[TSP ISC] %s,%d: i2c write fail[%d]\n",
__func__, __LINE__, ret);
return ISC_I2C_ERROR;
}
ret = mms100_i2c_read(_client,
ISC_CMD_CONFIRM_STATUS, 1, &rd_buf);
if (ret < 0) {
pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n",
__func__, __LINE__, ret);
return ISC_I2C_ERROR;
}
if (rd_buf != ISC_STATUS_CRC_CHECK_SUCCESS)
return ISC_CRC_ERROR;
section_update_flag[i] = false;
}
}
}
pr_info("[TSP ISC]End mms100_update_section_data()\n");
return ISC_SUCCESS;
}
static eISCRet_t mms100_open_mbinary(struct i2c_client *_client)
{
int i;
char file_name[64];
int ret = 0;
ret += request_firmware(&(fw_mbin[1]),\
"tsp_melfas/CORE.fw", &_client->dev);
ret += request_firmware(&(fw_mbin[2]),\
"tsp_melfas/PRIV.fw", &_client->dev);
ret += request_firmware(&(fw_mbin[3]),\
"tsp_melfas/PUBL.fw", &_client->dev);
if (!ret)
return ISC_SUCCESS;
else {
pr_info("[TSP ISC] request_firmware fail");
return ret;
}
}
static eISCRet_t mms100_close_mbinary(void)
{
int i;
for (i = 0; i < SECTION_NUM; i++) {
if (fw_mbin[i] != NULL)
release_firmware(fw_mbin[i]);
}
return ISC_SUCCESS;
}
eISCRet_t mms100_ISC_download_mbinary(struct mms_ts_info *info)
{
struct i2c_client *_client = info->client;
eISCRet_t ret_msg = ISC_NONE;
ma34_debug_fw_status = 0;
pr_info("[TSP ISC] %s\n", __func__);
mms100_reset(info);
/* ret_msg = mms100_check_operating_mode(_client, EC_BOOT_ON_SUCCEEDED);
if (ret_msg != ISC_SUCCESS)
goto ISC_ERROR_HANDLE;
*/
ret_msg = mms100_open_mbinary(_client);
if (ret_msg != ISC_SUCCESS)
goto ISC_ERROR_HANDLE;
ma34_debug_fw_status = 1;
/*Config version Check*/
ret_msg = mms100_compare_version_info(_client);
if (ret_msg != ISC_SUCCESS)
goto ISC_ERROR_HANDLE;
ma34_debug_fw_status = 2;
ret_msg = mms100_enter_ISC_mode(_client);
if (ret_msg != ISC_SUCCESS)
goto ISC_ERROR_HANDLE;
ma34_debug_fw_status = 3;
ret_msg = mms100_enter_config_update(_client);
if (ret_msg != ISC_SUCCESS)
goto ISC_ERROR_HANDLE;
ma34_debug_fw_status = 4;
ret_msg = mms100_ISC_clear_validate_markers(_client);
if (ret_msg != ISC_SUCCESS)
goto ISC_ERROR_HANDLE;
ma34_debug_fw_status = 5;
pr_info("[TSP ISC]mms100_update_section_data start");
ret_msg = mms100_update_section_data(_client);
if (ret_msg != ISC_SUCCESS)
goto ISC_ERROR_HANDLE;
ma34_debug_fw_status = 6;
pr_info("[TSP ISC]mms100_update_section_data end");
/* mms100_reset(info); */
pr_info("[TSP ISC]FIRMWARE_UPDATE_FINISHED!!!\n");
ret_msg = ISC_SUCCESS;
ISC_ERROR_HANDLE:
if (ret_msg != ISC_SUCCESS)
pr_info("[TSP ISC]ISC_ERROR_CODE: %d\n", ret_msg);
mms100_reset(info);
mms100_close_mbinary();
return ret_msg;
}
#endif /* ISC_DL_MODE start */
static void hw_reboot(struct mms_ts_info *info, bool bootloader)
{
info->pdata->power(false);
gpio_direction_output(info->pdata->gpio_sda, bootloader ? 0 : 1);
gpio_direction_output(info->pdata->gpio_scl, bootloader ? 0 : 1);
gpio_direction_output(info->pdata->gpio_int, 0);
msleep(30);
info->pdata->power(true);
msleep(30);
if (bootloader) {
gpio_set_value(info->pdata->gpio_scl, 0);
gpio_set_value(info->pdata->gpio_sda, 1);
} else {
gpio_set_value(info->pdata->gpio_int, 1);
gpio_direction_input(info->pdata->gpio_int);
gpio_direction_input(info->pdata->gpio_scl);
gpio_direction_input(info->pdata->gpio_sda);
}
msleep(40);
}
static inline void hw_reboot_bootloader(struct mms_ts_info *info)
{
hw_reboot(info, true);
}
static inline void hw_reboot_normal(struct mms_ts_info *info)
{
hw_reboot(info, false);
}
static void isp_toggle_clk(struct mms_ts_info *info, int start_lvl, int end_lvl,
int hold_us)
{
gpio_set_value(info->pdata->gpio_scl, start_lvl);
udelay(hold_us);
gpio_set_value(info->pdata->gpio_scl, end_lvl);
udelay(hold_us);
}
/* 1 <= cnt <= 32 bits to write */
static void isp_send_bits(struct mms_ts_info *info, u32 data, int cnt)
{
gpio_direction_output(info->pdata->gpio_int, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_sda, 0);
/* clock out the bits, msb first */
while (cnt--) {
gpio_set_value(info->pdata->gpio_sda, (data >> cnt) & 1);
udelay(3);
isp_toggle_clk(info, 1, 0, 3);
}
}
/* 1 <= cnt <= 32 bits to read */
static u32 isp_recv_bits(struct mms_ts_info *info, int cnt)
{
u32 data = 0;
gpio_direction_output(info->pdata->gpio_int, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_set_value(info->pdata->gpio_sda, 0);
gpio_direction_input(info->pdata->gpio_sda);
/* clock in the bits, msb first */
while (cnt--) {
isp_toggle_clk(info, 0, 1, 1);
data = (data << 1) | (!!gpio_get_value(info->pdata->gpio_sda));
}
gpio_direction_output(info->pdata->gpio_sda, 0);
return data;
}
static void isp_enter_mode(struct mms_ts_info *info, u32 mode)
{
int cnt;
unsigned long flags;
local_irq_save(flags);
gpio_direction_output(info->pdata->gpio_int, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_sda, 1);
mode &= 0xffff;
for (cnt = 15; cnt >= 0; cnt--) {
gpio_set_value(info->pdata->gpio_int, (mode >> cnt) & 1);
udelay(3);
isp_toggle_clk(info, 1, 0, 3);
}
gpio_set_value(info->pdata->gpio_int, 0);
local_irq_restore(flags);
}
static void isp_exit_mode(struct mms_ts_info *info)
{
int i;
unsigned long flags;
local_irq_save(flags);
gpio_direction_output(info->pdata->gpio_int, 0);
udelay(3);
for (i = 0; i < 10; i++)
isp_toggle_clk(info, 1, 0, 3);
local_irq_restore(flags);
}
static void flash_set_address(struct mms_ts_info *info, u16 addr)
{
/* Only 13 bits of addr are valid.
* The addr is in bits 13:1 of cmd */
isp_send_bits(info, (u32) (addr & 0x1fff) << 1, 18);
}
static void flash_erase(struct mms_ts_info *info)
{
isp_enter_mode(info, ISP_MODE_FLASH_ERASE);
gpio_direction_output(info->pdata->gpio_int, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_sda, 1);
/* 4 clock cycles with different timings for the erase to
* get processed, clk is already 0 from above */
udelay(7);
isp_toggle_clk(info, 1, 0, 3);
udelay(7);
isp_toggle_clk(info, 1, 0, 3);
usleep_range(25000, 35000);
isp_toggle_clk(info, 1, 0, 3);
usleep_range(150, 200);
isp_toggle_clk(info, 1, 0, 3);
gpio_set_value(info->pdata->gpio_sda, 0);
isp_exit_mode(info);
}
static u32 flash_readl(struct mms_ts_info *info, u16 addr)
{
int i;
u32 val;
unsigned long flags;
local_irq_save(flags);
isp_enter_mode(info, ISP_MODE_FLASH_READ);
flash_set_address(info, addr);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_sda, 0);
udelay(40);
/* data load cycle */
for (i = 0; i < 6; i++)
isp_toggle_clk(info, 1, 0, 10);
val = isp_recv_bits(info, 32);
isp_exit_mode(info);
local_irq_restore(flags);
return val;
}
static void flash_writel(struct mms_ts_info *info, u16 addr, u32 val)
{
unsigned long flags;
local_irq_save(flags);
isp_enter_mode(info, ISP_MODE_FLASH_WRITE);
flash_set_address(info, addr);
isp_send_bits(info, val, 32);
gpio_direction_output(info->pdata->gpio_sda, 1);
/* 6 clock cycles with different timings for the data to get written
* into flash */
isp_toggle_clk(info, 0, 1, 3);
isp_toggle_clk(info, 0, 1, 3);
isp_toggle_clk(info, 0, 1, 6);
isp_toggle_clk(info, 0, 1, 12);
isp_toggle_clk(info, 0, 1, 3);
isp_toggle_clk(info, 0, 1, 3);
isp_toggle_clk(info, 1, 0, 1);
gpio_direction_output(info->pdata->gpio_sda, 0);
isp_exit_mode(info);
local_irq_restore(flags);
usleep_range(300, 400);
}
static bool flash_is_erased(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
u32 val;
u16 addr;
for (addr = 0; addr < (ISP_MAX_FW_SIZE / 4); addr++) {
udelay(40);
val = flash_readl(info, addr);
if (val != 0xffffffff) {
dev_dbg(&client->dev,
"addr 0x%x not erased: 0x%08x != 0xffffffff\n",
addr, val);
return false;
}
}
return true;
}
static int fw_write_image(struct mms_ts_info *info, const u8 * data, size_t len)
{
struct i2c_client *client = info->client;
u16 addr = 0;
for (addr = 0; addr < (len / 4); addr++, data += 4) {
u32 val = get_unaligned_le32(data);
u32 verify_val;
int retries = 3;
while (retries--) {
flash_writel(info, addr, val);
verify_val = flash_readl(info, addr);
if (val == verify_val)
break;
dev_err(&client->dev,
"mismatch @ addr 0x%x: 0x%x != 0x%x\n",
addr, verify_val, val);
continue;
}
if (retries < 0)
return -ENXIO;
}
return 0;
}
static int fw_download(struct mms_ts_info *info, const u8 * data, size_t len)
{
struct i2c_client *client = info->client;
u32 val;
int ret = 0;
if (len % 4) {
dev_err(&client->dev,
"fw image size (%d) must be a multiple of 4 bytes\n",
len);
return -EINVAL;
} else if (len > ISP_MAX_FW_SIZE) {
dev_err(&client->dev,
"fw image is too big, %d > %d\n", len, ISP_MAX_FW_SIZE);
return -EINVAL;
}
dev_info(&client->dev, "fw download start\n");
info->pdata->power(false);
gpio_direction_output(info->pdata->gpio_sda, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_int, 0);
hw_reboot_bootloader(info);
val = flash_readl(info, ISP_IC_INFO_ADDR);
dev_info(&client->dev, "IC info: 0x%02x (%x)\n", val & 0xff, val);
dev_info(&client->dev, "fw erase...\n");
flash_erase(info);
if (!flash_is_erased(info)) {
ret = -ENXIO;
goto err;
}
dev_info(&client->dev, "fw write...\n");
/* XXX: what does this do?! */
flash_writel(info, ISP_IC_INFO_ADDR, 0xffffff00 | (val & 0xff));
usleep_range(1000, 1500);
ret = fw_write_image(info, data, len);
if (ret)
goto err;
usleep_range(1000, 1500);
hw_reboot_normal(info);
usleep_range(1000, 1500);
dev_info(&client->dev, "fw download done...\n");
return 0;
err:
dev_err(&client->dev, "fw download failed...\n");
hw_reboot_normal(info);
return ret;
}
#if defined(SEC_TSP_ISC_FW_UPDATE)
static u16 gen_crc(u8 data, u16 pre_crc)
{
u16 crc;
u16 cur;
u16 temp;
u16 bit_1;
u16 bit_2;
int i;
crc = pre_crc;
for (i = 7; i >= 0; i--) {
cur = ((data >> i) & 0x01) ^ (crc & 0x0001);
bit_1 = cur ^ (crc >> 11 & 0x01);
bit_2 = cur ^ (crc >> 4 & 0x01);
temp = (cur << 4) | (crc >> 12 & 0x0F);
temp = (temp << 7) | (bit_1 << 6) | (crc >> 5 & 0x3F);
temp = (temp << 4) | (bit_2 << 3) | (crc >> 1 & 0x0007);
crc = temp;
}
return crc;
}
static int isc_fw_download(struct mms_ts_info *info, const u8 * data,
size_t len)
{
u8 *buff;
u16 crc_buf;
int src_idx;
int dest_idx;
int ret;
int i, j;
buff = kzalloc(ISC_PKT_SIZE, GFP_KERNEL);
if (!buff) {
dev_err(&info->client->dev, "%s: failed to allocate memory\n",
__func__);
ret = -1;
goto err_mem_alloc;
}
/* enterring ISC mode */
*buff = ISC_ENTER_ISC_DATA;
ret = i2c_smbus_write_byte_data(info->client,
ISC_ENTER_ISC_CMD, *buff);
if (ret < 0) {
dev_err(&info->client->dev,
"fail to enter ISC mode(err=%d)\n", ret);
goto fail_to_isc_enter;
}
usleep_range(10000, 20000);
dev_info(&info->client->dev, "Enter ISC mode\n");
/*enter ISC update mode */
*buff = ISC_ENTER_UPDATE_DATA;
ret = i2c_smbus_write_i2c_block_data(info->client,
ISC_CMD,
ISC_ENTER_UPDATE_DATA_LEN, buff);
if (ret < 0) {
dev_err(&info->client->dev,
"fail to enter ISC update mode(err=%d)\n", ret);
goto fail_to_isc_update;
}
dev_info(&info->client->dev, "Enter ISC update mode\n");
/* firmware write */
*buff = ISC_CMD;
*(buff + 1) = ISC_DATA_WRITE_SUB_CMD;
for (i = 0; i < ISC_PKT_NUM; i++) {
*(buff + 2) = i;
crc_buf = gen_crc(*(buff + 2), ISC_DEFAULT_CRC);
for (j = 0; j < ISC_PKT_DATA_SIZE; j++) {
dest_idx = ISC_PKT_HEADER_SIZE + j;
src_idx = i * ISC_PKT_DATA_SIZE +
((int)(j / WORD_SIZE)) * WORD_SIZE -
(j % WORD_SIZE) + 3;
*(buff + dest_idx) = *(data + src_idx);
crc_buf = gen_crc(*(buff + dest_idx), crc_buf);
}
*(buff + ISC_PKT_DATA_SIZE + ISC_PKT_HEADER_SIZE + 1) =
crc_buf & 0xFF;
*(buff + ISC_PKT_DATA_SIZE + ISC_PKT_HEADER_SIZE) =
crc_buf >> 8 & 0xFF;
ret = i2c_master_send(info->client, buff, ISC_PKT_SIZE);
if (ret < 0) {
dev_err(&info->client->dev,
"fail to firmware writing on packet %d.(%d)\n",
i, ret);
goto fail_to_fw_write;
}
usleep_range(1, 5);
/* confirm CRC */
ret = i2c_smbus_read_byte_data(info->client,
ISC_CHECK_STATUS_CMD);
if (ret == ISC_CONFIRM_CRC) {
dev_info(&info->client->dev,
"updating %dth firmware data packet.\n", i);
} else {
dev_err(&info->client->dev,
"fail to firmware update on %dth (%X).\n",
i, ret);
ret = -1;
goto fail_to_confirm_crc;
}
}
ret = 0;
fail_to_confirm_crc:
fail_to_fw_write:
/* exit ISC mode */
*buff = ISC_EXIT_ISC_SUB_CMD;
*(buff + 1) = ISC_EXIT_ISC_SUB_CMD2;
i2c_smbus_write_i2c_block_data(info->client, ISC_CMD, 2, buff);
usleep_range(10000, 20000);
fail_to_isc_update:
hw_reboot_normal(info);
fail_to_isc_enter:
kfree(buff);
err_mem_alloc:
return ret;
}
#endif /* SEC_TSP_ISC_FW_UPDATE */
static int get_fw_version(struct mms_ts_info *info)
{
int ret;
int retries = 3;
/* this seems to fail sometimes after a reset.. retry a few times */
do {
ret = i2c_smbus_read_byte_data(info->client, MMS_FW_VERSION);
} while (ret < 0 && retries-- > 0);
return ret;
}
static int get_hw_version(struct mms_ts_info *info)
{
int ret;
int retries = 3;
/* this seems to fail sometimes after a reset.. retry a few times */
do {
ret = i2c_smbus_read_byte_data(info->client, MMS_HW_REVISION);
} while (ret < 0 && retries-- > 0);
return ret;
}
static int mms_ts_enable(struct mms_ts_info *info, int wakeupcmd)
{
mutex_lock(&info->lock);
if (info->enabled)
goto out;
/* wake up the touch controller. */
if (wakeupcmd == 1) {
i2c_smbus_write_byte_data(info->client, 0, 0);
usleep_range(3000, 5000);
}
info->enabled = true;
enable_irq(info->irq);
out:
mutex_unlock(&info->lock);
return 0;
}
static int mms_ts_disable(struct mms_ts_info *info, int sleepcmd)
{
mutex_lock(&info->lock);
if (!info->enabled)
goto out;
disable_irq_nosync(info->irq);
if (sleepcmd == 1) {
i2c_smbus_write_byte_data(info->client, MMS_MODE_CONTROL, 0);
usleep_range(10000, 12000);
}
info->enabled = false;
touch_is_pressed = 0;
out:
mutex_unlock(&info->lock);
return 0;
}
static int mms_ts_finish_config(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
int ret;
ret = request_threaded_irq(client->irq, NULL, mms_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
MELFAS_TS_NAME, info);
if (ret < 0) {
ret = 1;
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_req_irq;
}
info->irq = client->irq;
barrier();
dev_info(&client->dev,
"Melfas MMS-series touch controller initialized\n");
return 0;
err_req_irq:
return ret;
}
static int mms_ts_fw_info(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret = 0;
int ver, hw_rev;
ver = get_fw_version(info);
info->fw_ic_ver = ver;
dev_info(&client->dev,
"[TSP]fw version 0x%02x !!!!\n", ver);
hw_rev = get_hw_version(info);
dev_info(&client->dev,
"[TSP] hw rev = %x\n", hw_rev);
if (ver < 0 || hw_rev < 0) {
ret = 1;
dev_err(&client->dev,
"i2c fail...tsp driver unload.\n");
return ret;
}
if (!info->pdata || !info->pdata->mux_fw_flash) {
ret = 1;
dev_err(&client->dev,
"fw cannot be updated, missing platform data\n");
return ret;
}
ret = mms_ts_finish_config(info);
return ret;
}
static int mms_ts_fw_load(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret = 0;
int ver, hw_rev;
int retries = 3;
#if 0
ver = get_fw_version(info);
info->fw_ic_ver = ver;
dev_info(&client->dev,
"[TSP]fw version 0x%02x !!!!\n", ver);
hw_rev = get_hw_version(info);
dev_info(&client->dev,
"[TSP]hw rev = 0x%02x\n", hw_rev);
pr_err("[TSP] ISC Ver [0x%02x] [0x%02x] [0x%02x]",
i2c_smbus_read_byte_data(info->client, 0xF3),
i2c_smbus_read_byte_data(info->client, 0xF4),
i2c_smbus_read_byte_data(info->client, 0xF5));
if (!info->pdata || !info->pdata->mux_fw_flash) {
ret = 1;
dev_err(&client->dev,
"fw cannot be updated, missing platform data\n");
goto out;
}
/* 4.8" OCTA LCD FW */
if (ver >= FW_VERSION_4_8 && ver != 0xFF\
&& ver != 0x00 && ver != 0x45) {
dev_info(&client->dev,
"4.8 fw version update does not need\n");
goto done;
}
#endif
while (retries--) {
ret = mms100_ISC_download_mbinary(info);
ver = get_fw_version(info);
info->fw_ic_ver = ver;
if (ret == 0) {
pr_err("[TSP] mms100_ISC_download_mbinary success");
goto done;
} else {
pr_err("[TSP] mms100_ISC_download_mbinary fail [%d]",
ret);
ret = 1;
}
dev_err(&client->dev, "retrying flashing\n");
}
out:
return ret;
done:
#if ISC_DL_MODE /* ISC_DL_MODE start */
pr_err("[TSP] ISC Ver [0x%02x] [0x%02x] [0x%02x]",
i2c_smbus_read_byte_data(info->client, 0xF3),
i2c_smbus_read_byte_data(info->client, 0xF4),
i2c_smbus_read_byte_data(info->client, 0xF5));
#endif
ret = mms_ts_finish_config(info);
return ret;
}
#ifdef SEC_TSP_FACTORY_TEST
static void set_cmd_result(struct mms_ts_info *info, char *buff, int len)
{
strncat(info->cmd_result, buff, len);
}
static void get_raw_data_all(struct mms_ts_info *info, u8 cmd)
{
u8 w_buf[6];
u8 read_buffer[2]; /* 52 */
int gpio;
int ret;
int i, j;
u32 max_value = 0, min_value = 0;
u32 raw_data;
char buff[TSP_CMD_STR_LEN] = {0};
gpio = info->pdata->gpio_int;
/* gpio = msm_irq_to_gpio(info->irq); */
disable_irq(info->irq);
w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */
w_buf[1] = MMS_VSC_MODE; /* mode of vendor */
w_buf[2] = 0; /* tx line */
w_buf[3] = 0; /* rx line */
w_buf[4] = 0; /* reserved */
w_buf[5] = 0; /* sub command */
if (cmd == MMS_VSC_CMD_EXIT) {
w_buf[5] = MMS_VSC_CMD_EXIT; /* exit test mode */
ret = i2c_smbus_write_i2c_block_data(info->client,
w_buf[0], 5, &w_buf[1]);
if (ret < 0)
goto err_i2c;
enable_irq(info->irq);
msleep(200);
return;
}
/* MMS_VSC_CMD_CM_DELTA or MMS_VSC_CMD_CM_ABS
* this two mode need to enter the test mode
* exit command must be followed by testing.
*/
if (cmd == MMS_VSC_CMD_CM_DELTA || cmd == MMS_VSC_CMD_CM_ABS) {
/* enter the debug mode */
w_buf[2] = 0x0; /* tx */
w_buf[3] = 0x0; /* rx */
w_buf[5] = MMS_VSC_CMD_ENTER;
ret = i2c_smbus_write_i2c_block_data(info->client,
w_buf[0], 5, &w_buf[1]);
if (ret < 0)
goto err_i2c;
/* wating for the interrupt */
while (gpio_get_value(gpio))
udelay(100);
}
for (i = 0; i < RX_NUM; i++) {
for (j = 0; j < TX_NUM; j++) {
w_buf[2] = j; /* tx */
w_buf[3] = i; /* rx */
w_buf[5] = cmd;
ret = i2c_smbus_write_i2c_block_data(info->client,
w_buf[0], 5, &w_buf[1]);
if (ret < 0)
goto err_i2c;
usleep_range(1, 5);
ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF,
2, read_buffer);
if (ret < 0)
goto err_i2c;
raw_data = ((u16) read_buffer[1] << 8) | read_buffer[0];
if (i == 0 && j == 0) {
max_value = min_value = raw_data;
} else {
max_value = max(max_value, raw_data);
min_value = min(min_value, raw_data);
}
if (cmd == MMS_VSC_CMD_INTENSITY) {
info->intensity[i * TX_NUM + j] = raw_data;
dev_dbg(&info->client->dev, "[TSP] intensity[%d][%d] = %d\n",
j, i, info->intensity[i * TX_NUM + j]);
} else if (cmd == MMS_VSC_CMD_CM_DELTA) {
info->inspection[i * TX_NUM + j] = raw_data;
dev_dbg(&info->client->dev, "[TSP] delta[%d][%d] = %d\n",
j, i, info->inspection[i * TX_NUM + j]);
} else if (cmd == MMS_VSC_CMD_CM_ABS) {
info->raw[i * TX_NUM + j] = raw_data;
dev_dbg(&info->client->dev, "[TSP] raw[%d][%d] = %d\n",
j, i, info->raw[i * TX_NUM + j]);
} else if (cmd == MMS_VSC_CMD_REFER) {
info->reference[i * TX_NUM + j] =
raw_data >> 3;
dev_dbg(&info->client->dev, "[TSP] reference[%d][%d] = %d\n",
j, i, info->reference[i * TX_NUM + j]);
}
}
}
snprintf(buff, sizeof(buff), "%d,%d", min_value, max_value);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
enable_irq(info->irq);
err_i2c:
dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n",
__func__, cmd);
}
static u32 get_raw_data_one(struct mms_ts_info *info, u16 rx_idx, u16 tx_idx,
u8 cmd)
{
u8 w_buf[6];
u8 read_buffer[2];
int ret;
u32 raw_data;
w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */
w_buf[1] = MMS_VSC_MODE; /* mode of vendor */
w_buf[2] = 0; /* tx line */
w_buf[3] = 0; /* rx line */
w_buf[4] = 0; /* reserved */
w_buf[5] = 0; /* sub command */
if (cmd != MMS_VSC_CMD_INTENSITY && cmd != MMS_VSC_CMD_RAW &&
cmd != MMS_VSC_CMD_REFER) {
dev_err(&info->client->dev, "%s: not profer command(cmd=%d)\n",
__func__, cmd);
return FAIL;
}
w_buf[2] = tx_idx; /* tx */
w_buf[3] = rx_idx; /* rx */
w_buf[5] = cmd; /* sub command */
ret = i2c_smbus_write_i2c_block_data(info->client, w_buf[0], 5,
&w_buf[1]);
if (ret < 0)
goto err_i2c;
ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, 2, read_buffer);
if (ret < 0)
goto err_i2c;
raw_data = ((u16) read_buffer[1] << 8) | read_buffer[0];
if (cmd == MMS_VSC_CMD_REFER)
raw_data = raw_data >> 4;
return raw_data;
err_i2c:
dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n",
__func__, cmd);
return FAIL;
}
static ssize_t show_close_tsp_test(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mms_ts_info *info = dev_get_drvdata(dev);
get_raw_data_all(info, MMS_VSC_CMD_EXIT);
info->ft_flag = 0;
return snprintf(buf, TSP_BUF_SIZE, "%u\n", 0);
}
static void set_default_result(struct mms_ts_info *info)
{
char delim = ':';
memset(info->cmd_result, 0x00, ARRAY_SIZE(info->cmd_result));
memcpy(info->cmd_result, info->cmd, strlen(info->cmd));
strncat(info->cmd_result, &delim, 1);
}
static int check_rx_tx_num(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[TSP_CMD_STR_LEN] = {0};
int node;
if (info->cmd_param[0] < 0 ||
info->cmd_param[0] >= TX_NUM ||
info->cmd_param[1] < 0 ||
info->cmd_param[1] >= RX_NUM) {
snprintf(buff, sizeof(buff) , "%s", "NG");
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 3;
dev_info(&info->client->dev, "%s: parameter error: %u,%u\n",
__func__, info->cmd_param[0],
info->cmd_param[1]);
node = -1;
return node;
}
node = info->cmd_param[1] * TX_NUM + info->cmd_param[0];
dev_info(&info->client->dev, "%s: node = %d\n", __func__,
node);
return node;
}
static void not_support_cmd(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
set_default_result(info);
sprintf(buff, "%s", "NA");
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 4;
dev_info(&info->client->dev, "%s: \"%s(%d)\"\n", __func__,
buff, strnlen(buff, sizeof(buff)));
return;
}
static void fw_update(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
struct i2c_client *client = info->client;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret = 0;
int ver = 0, fw_bin_ver = 0;
int retries = 5;
const u8 *buff = 0;
mm_segment_t old_fs = {0};
struct file *fp = NULL;
long fsize = 0, nread = 0;
char fw_path[MAX_FW_PATH+1];
char result[16] = {0};
set_default_result(info);
dev_info(&client->dev,
"fw_ic_ver = 0x%02x, fw_bin_ver = 0x%02x\n",
info->fw_ic_ver, fw_bin_ver);
switch (info->cmd_param[0]) {
case BUILT_IN:
dev_info(&client->dev, "built in 4.8 fw is loaded!!\n");
while (retries--) {
ret = mms100_ISC_download_mbinary(info);
ver = get_fw_version(info);
info->fw_ic_ver = ver;
if (ret == 0) {
pr_err("[TSP] mms100_ISC_download_mbinary success");
info->cmd_state = 2;
return;
} else {
pr_err("[TSP] mms100_ISC_download_mbinary fail[%d]",
ret);
info->cmd_state = 3;
}
}
return;
break;
case UMS:
old_fs = get_fs();
set_fs(get_ds());
snprintf(fw_path, MAX_FW_PATH, "/sdcard/%s", TSP_FW_FILENAME);
fp = filp_open(fw_path, O_RDONLY, 0);
if (IS_ERR(fp)) {
dev_err(&client->dev,
"file %s open error:%d\n", fw_path, (s32)fp);
info->cmd_state = 3;
goto err_open;
}
fsize = fp->f_path.dentry->d_inode->i_size;
buff = kzalloc((size_t)fsize, GFP_KERNEL);
if (!buff) {
dev_err(&client->dev, "fail to alloc buffer for fw\n");
info->cmd_state = 3;
goto err_alloc;
}
nread = vfs_read(fp, (char __user *)buff, fsize, &fp->f_pos);
if (nread != fsize) {
/*dev_err("fail to read file %s (nread = %d)\n",
fw_path, nread);*/
info->cmd_state = 3;
goto err_fw_size;
}
filp_close(fp, current->files);
set_fs(old_fs);
dev_info(&client->dev, "ums fw is loaded!!\n");
break;
default:
dev_err(&client->dev, "invalid fw file type!!\n");
goto not_support;
}
disable_irq(info->irq);
while (retries--) {
i2c_lock_adapter(adapter);
info->pdata->mux_fw_flash(true);
ret = fw_download(info, (const u8 *)buff,
(const size_t)fsize);
info->pdata->mux_fw_flash(false);
i2c_unlock_adapter(adapter);
if (ret < 0) {
dev_err(&client->dev, "retrying flashing\n");
continue;
}
ver = get_fw_version(info);
info->fw_ic_ver = ver;
if (info->cmd_param[0] == 1 || info->cmd_param[0] == 2) {
dev_info(&client->dev,
"fw update done. ver = 0x%02x\n", ver);
info->cmd_state = 2;
snprintf(result, sizeof(result) , "%s", "OK");
set_cmd_result(info, result,
strnlen(result, sizeof(result)));
enable_irq(info->irq);
kfree(buff);
return;
} else if (ver == fw_bin_ver) {
dev_info(&client->dev,
"fw update done. ver = 0x%02x\n", ver);
info->cmd_state = 2;
snprintf(result, sizeof(result) , "%s", "OK");
set_cmd_result(info, result,
strnlen(result, sizeof(result)));
enable_irq(info->irq);
return;
} else {
dev_err(&client->dev,
"ERROR : fw version is still wrong (0x%x != 0x%x)\n",
ver, fw_bin_ver);
}
dev_err(&client->dev, "retrying flashing\n");
}
if (fp != NULL) {
err_fw_size:
kfree(buff);
err_alloc:
filp_close(fp, NULL);
err_open:
set_fs(old_fs);
}
not_support:
do_not_need_update:
snprintf(result, sizeof(result) , "%s", "NG");
set_cmd_result(info, result, strnlen(result, sizeof(result)));
return;
}
static void get_fw_ver_bin(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
int hw_rev;
set_default_result(info);
snprintf(buff, sizeof(buff), "%#02x", FW_VERSION_4_8);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__,
buff, strnlen(buff, sizeof(buff)));
}
static void get_fw_ver_ic(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
int ver;
set_default_result(info);
ver = info->fw_ic_ver;
snprintf(buff, sizeof(buff), "%#02x", ver);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__,
buff, strnlen(buff, sizeof(buff)));
}
static void get_config_ver(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[20] = {0};
set_default_result(info);
snprintf(buff, sizeof(buff), "%s", info->config_fw_version);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__,
buff, strnlen(buff, sizeof(buff)));
}
static void get_threshold(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
int threshold;
set_default_result(info);
threshold = i2c_smbus_read_byte_data(info->client, 0x05);
if (threshold < 0) {
snprintf(buff, sizeof(buff), "%s", "NG");
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 3;
return;
}
snprintf(buff, sizeof(buff), "%d", threshold);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__,
buff, strnlen(buff, sizeof(buff)));
}
/*
static void module_off_master(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[3] = {0};
mutex_lock(&info->lock);
if (info->enabled) {
disable_irq(info->irq);
info->enabled = false;
touch_is_pressed = 0;
}
mutex_unlock(&info->lock);
info->pdata->power(0);
if (info->pdata->is_vdd_on() == 0)
snprintf(buff, sizeof(buff), "%s", "OK");
else
snprintf(buff, sizeof(buff), "%s", "NG");
set_default_result(info);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
if (strncmp(buff, "OK", 2) == 0)
info->cmd_state = 2;
else
info->cmd_state = 3;
dev_info(&info->client->dev, "%s: %s\n", __func__, buff);
}
static void module_on_master(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[3] = {0};
mms_pwr_on_reset(info);
mutex_lock(&info->lock);
if (!info->enabled) {
enable_irq(info->irq);
info->enabled = true;
}
mutex_unlock(&info->lock);
if (info->pdata->is_vdd_on() == 1)
snprintf(buff, sizeof(buff), "%s", "OK");
else
snprintf(buff, sizeof(buff), "%s", "NG");
set_default_result(info);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
if (strncmp(buff, "OK", 2) == 0)
info->cmd_state = 2;
else
info->cmd_state = 3;
dev_info(&info->client->dev, "%s: %s\n", __func__, buff);
}
static void module_off_slave(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
not_support_cmd(info);
}
static void module_on_slave(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
not_support_cmd(info);
}
*/
static void get_chip_vendor(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
set_default_result(info);
snprintf(buff, sizeof(buff), "%s", "MELFAS");
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__,
buff, strnlen(buff, sizeof(buff)));
}
static void get_chip_name(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
set_default_result(info);
snprintf(buff, sizeof(buff), "%s", "MMS144");
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__,
buff, strnlen(buff, sizeof(buff)));
}
static void get_reference(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
unsigned int val;
int node;
set_default_result(info);
node = check_rx_tx_num(info);
if (node < 0)
return;
val = info->reference[node];
snprintf(buff, sizeof(buff), "%u", val);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__,
buff, strnlen(buff, sizeof(buff)));
}
static void get_cm_abs(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
unsigned int val;
int node;
set_default_result(info);
node = check_rx_tx_num(info);
if (node < 0)
return;
val = info->raw[node];
snprintf(buff, sizeof(buff), "%u", val);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff,
strnlen(buff, sizeof(buff)));
}
static void get_cm_delta(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
unsigned int val;
int node;
set_default_result(info);
node = check_rx_tx_num(info);
if (node < 0)
return;
val = info->inspection[node];
snprintf(buff, sizeof(buff), "%u", val);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff,
strnlen(buff, sizeof(buff)));
}
static void get_intensity(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
unsigned int val;
int node;
set_default_result(info);
node = check_rx_tx_num(info);
if (node < 0)
return;
val = info->intensity[node];
snprintf(buff, sizeof(buff), "%u", val);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff,
strnlen(buff, sizeof(buff)));
}
static void get_x_num(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
int val;
set_default_result(info);
val = i2c_smbus_read_byte_data(info->client, 0xEF);
if (val < 0) {
snprintf(buff, sizeof(buff), "%s", "NG");
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 3;
dev_info(&info->client->dev,
"%s: fail to read num of x (%d).\n", __func__, val);
return;
}
snprintf(buff, sizeof(buff), "%u", val);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff,
strnlen(buff, sizeof(buff)));
}
static void get_y_num(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
char buff[16] = {0};
int val;
set_default_result(info);
val = i2c_smbus_read_byte_data(info->client, 0xEE);
if (val < 0) {
snprintf(buff, sizeof(buff), "%s", "NG");
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 3;
dev_info(&info->client->dev,
"%s: fail to read num of y (%d).\n", __func__, val);
return;
}
snprintf(buff, sizeof(buff), "%u", val);
set_cmd_result(info, buff, strnlen(buff, sizeof(buff)));
info->cmd_state = 2;
dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff,
strnlen(buff, sizeof(buff)));
}
static void run_reference_read(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
set_default_result(info);
get_raw_data_all(info, MMS_VSC_CMD_REFER);
info->cmd_state = 2;
/* dev_info(&info->client->dev, "%s: %s(%d)\n", __func__); */
}
static void run_cm_abs_read(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
set_default_result(info);
get_raw_data_all(info, MMS_VSC_CMD_CM_ABS);
get_raw_data_all(info, MMS_VSC_CMD_EXIT);
info->cmd_state = 2;
/* dev_info(&info->client->dev, "%s: %s(%d)\n", __func__); */
}
static void run_cm_delta_read(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
set_default_result(info);
get_raw_data_all(info, MMS_VSC_CMD_CM_DELTA);
get_raw_data_all(info, MMS_VSC_CMD_EXIT);
info->cmd_state = 2;
/* dev_info(&info->client->dev, "%s: %s(%d)\n", __func__); */
}
static void run_intensity_read(void *device_data)
{
struct mms_ts_info *info = (struct mms_ts_info *)device_data;
set_default_result(info);
get_raw_data_all(info, MMS_VSC_CMD_INTENSITY);
info->cmd_state = 2;
/* dev_info(&info->client->dev, "%s: %s(%d)\n", __func__); */
}
static ssize_t store_cmd(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct mms_ts_info *info = dev_get_drvdata(dev);
struct i2c_client *client = info->client;
char *cur, *start, *end;
char buff[TSP_CMD_STR_LEN] = {0};
int len, i;
struct tsp_cmd *tsp_cmd_ptr = NULL;
char delim = ',';
bool cmd_found = false;
int param_cnt = 0;
int ret;
if (info->cmd_is_running == true) {
dev_err(&info->client->dev, "tsp_cmd: other cmd is running.\n");
goto err_out;
}
/* check lock */
mutex_lock(&info->cmd_lock);
info->cmd_is_running = true;
mutex_unlock(&info->cmd_lock);
info->cmd_state = 1;
for (i = 0; i < ARRAY_SIZE(info->cmd_param); i++)
info->cmd_param[i] = 0;
len = (int)count;
if (*(buf + len - 1) == '\n')
len--;
memset(info->cmd, 0x00, ARRAY_SIZE(info->cmd));
memcpy(info->cmd, buf, len);
cur = strchr(buf, (int)delim);
if (cur)
memcpy(buff, buf, cur - buf);
else
memcpy(buff, buf, len);
/* find command */
list_for_each_entry(tsp_cmd_ptr, &info->cmd_list_head, list) {
if (!strcmp(buff, tsp_cmd_ptr->cmd_name)) {
cmd_found = true;
break;
}
}
/* set not_support_cmd */
if (!cmd_found) {
list_for_each_entry(tsp_cmd_ptr, &info->cmd_list_head, list) {
if (!strcmp("not_support_cmd", tsp_cmd_ptr->cmd_name))
break;
}
}
/* parsing parameters */
if (cur && cmd_found) {
cur++;
start = cur;
memset(buff, 0x00, ARRAY_SIZE(buff));
do {
if (*cur == delim || cur - buf == len) {
end = cur;
memcpy(buff, start, end - start);
*(buff + strlen(buff)) = '\0';
ret = kstrtoint(buff, 10,\
info->cmd_param + param_cnt);
start = cur + 1;
memset(buff, 0x00, ARRAY_SIZE(buff));
param_cnt++;
}
cur++;
} while (cur - buf <= len);
}
dev_info(&client->dev, "cmd = %s\n", tsp_cmd_ptr->cmd_name);
for (i = 0; i < param_cnt; i++)
dev_info(&client->dev, "cmd param %d= %d\n", i,
info->cmd_param[i]);
tsp_cmd_ptr->cmd_func(info);
err_out:
return count;
}
static ssize_t show_cmd_status(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mms_ts_info *info = dev_get_drvdata(dev);
char buff[16] = {0};
dev_info(&info->client->dev, "tsp cmd: status:%d\n",
info->cmd_state);
if (info->cmd_state == 0)
snprintf(buff, sizeof(buff), "WAITING");
else if (info->cmd_state == 1)
snprintf(buff, sizeof(buff), "RUNNING");
else if (info->cmd_state == 2)
snprintf(buff, sizeof(buff), "OK");
else if (info->cmd_state == 3)
snprintf(buff, sizeof(buff), "FAIL");
else if (info->cmd_state == 4)
snprintf(buff, sizeof(buff), "NOT_APPLICABLE");
return snprintf(buf, TSP_BUF_SIZE, "%s\n", buff);
}
static ssize_t show_cmd_result(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct mms_ts_info *info = dev_get_drvdata(dev);
dev_info(&info->client->dev, "tsp cmd: result: %s\n", info->cmd_result);
mutex_lock(&info->cmd_lock);
info->cmd_is_running = false;
mutex_unlock(&info->cmd_lock);
info->cmd_state = 0;
return snprintf(buf, TSP_BUF_SIZE, "%s\n", info->cmd_result);
}
#ifdef ESD_DEBUG
static bool intensity_log_flag;
static ssize_t show_intensity_logging_on(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mms_ts_info *info = dev_get_drvdata(dev);
struct i2c_client *client = info->client;
struct file *fp;
char log_data[160] = { 0, };
char buff[16] = { 0, };
mm_segment_t old_fs;
long nwrite;
u32 val;
int i, y, c;
old_fs = get_fs();
set_fs(KERNEL_DS);
#define MELFAS_DEBUG_LOG_PATH "/sdcard/melfas_log"
dev_info(&client->dev, "%s: start.\n", __func__);
fp = filp_open(MELFAS_DEBUG_LOG_PATH, O_RDWR | O_CREAT,
S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR(fp)) {
dev_err(&client->dev, "%s: fail to open log file\n", __func__);
goto open_err;
}
intensity_log_flag = 1;
do {
for (y = 0; y < 3; y++) {
/* for tx chanel 0~2 */
memset(log_data, 0x00, 160);
snprintf(buff, 16, "%1u: ", y);
strncat(log_data, buff, strnlen(buff, 16));
for (i = 0; i < RX_NUM; i++) {
val = get_raw_data_one(info, i, y,
MMS_VSC_CMD_INTENSITY);
snprintf(buff, 16, "%5u, ", val);
strncat(log_data, buff, strnlen(buff, 16));
}
memset(buff, '\n', 2);
c = (y == 2) ? 2 : 1;
strncat(log_data, buff, c);
nwrite = vfs_write(fp, (const char __user *)log_data,
strnlen(log_data, 160), &fp->f_pos);
}
usleep_range(5000);
} while (intensity_log_flag);
filp_close(fp, current->files);
set_fs(old_fs);
return 0;
open_err:
set_fs(old_fs);
return FAIL;
}
static ssize_t show_intensity_logging_off(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mms_ts_info *info = dev_get_drvdata(dev);
intensity_log_flag = 0;
usleep_range(10000);
get_raw_data_all(info, MMS_VSC_CMD_EXIT);
return 0;
}
#endif
static DEVICE_ATTR(close_tsp_test, S_IRUGO, show_close_tsp_test, NULL);
static DEVICE_ATTR(cmd, S_IWUSR | S_IWGRP, NULL, store_cmd);
static DEVICE_ATTR(cmd_status, S_IRUGO, show_cmd_status, NULL);
static DEVICE_ATTR(cmd_result, S_IRUGO, show_cmd_result, NULL);
#ifdef ESD_DEBUG
static DEVICE_ATTR(intensity_logging_on, S_IRUGO, show_intensity_logging_on,
NULL);
static DEVICE_ATTR(intensity_logging_off, S_IRUGO, show_intensity_logging_off,
NULL);
#endif
static struct attribute *sec_touch_facotry_attributes[] = {
&dev_attr_close_tsp_test.attr,
&dev_attr_cmd.attr,
&dev_attr_cmd_status.attr,
&dev_attr_cmd_result.attr,
#ifdef ESD_DEBUG
&dev_attr_intensity_logging_on.attr,
&dev_attr_intensity_logging_off.attr,
#endif
NULL,
};
static struct attribute_group sec_touch_factory_attr_group = {
.attrs = sec_touch_facotry_attributes,
};
#endif /* SEC_TSP_FACTORY_TEST */
static int __devinit mms_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct mms_ts_info *info;
struct input_dev *input_dev;
int ret = 0;
char buf[4] = { 0, };
#ifdef SEC_TSP_FACTORY_TEST
int i;
struct device *fac_dev_ts;
#endif
touch_is_pressed = 0;
#if 0
gpio_request(GPIO_OLED_DET, "OLED_DET");
ret = gpio_get_value(GPIO_OLED_DET);
printk(KERN_DEBUG
"[TSP] OLED_DET = %d\n", ret);
if (ret == 0) {
printk(KERN_DEBUG
"[TSP] device wasn't connected to board\n");
return -EIO;
}
#endif
ma34_debug_probe_status = 1;
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return -EIO;
ma34_debug_probe_status = 2;
info = kzalloc(sizeof(struct mms_ts_info), GFP_KERNEL);
if (!info) {
dev_err(&client->dev, "Failed to allocate memory\n");
ret = -ENOMEM;
goto err_alloc;
}
ma34_debug_probe_status = 3;
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&client->dev, "Failed to allocate memory for input device\n");
ret = -ENOMEM;
goto err_input_alloc;
}
ma34_debug_probe_status = 4;
info->client = client;
info->input_dev = input_dev;
info->pdata = client->dev.platform_data;
if (NULL == info->pdata) {
pr_err("failed to get platform data\n");
goto err_reg_input_dev;
}
info->irq = -1;
mutex_init(&info->lock);
ma34_debug_probe_status = 5;
if (info->pdata) {
info->max_x = info->pdata->max_x;
info->max_y = info->pdata->max_y;
info->invert_x = info->pdata->invert_x;
info->invert_y = info->pdata->invert_y;
info->config_fw_version = info->pdata->config_fw_version;
info->register_cb = info->pdata->register_cb;
} else {
info->max_x = 720;
info->max_y = 1280;
}
snprintf(info->phys, sizeof(info->phys),
"%s/input0", dev_name(&client->dev));
input_dev->name = "sec_touchscreen"; /*= "Melfas MMSxxx Touchscreen";*/
input_dev->phys = info->phys;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
input_mt_init_slots(input_dev, MAX_FINGERS);
input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR,
0, MAX_WIDTH, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, (info->max_x)-1, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, (info->max_y)-1, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, MAX_PRESSURE, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
0, MAX_PRESSURE, 0, 0);
input_set_abs_params(input_dev, ABS_MT_ANGLE,
MIN_ANGLE, MAX_ANGLE, 0, 0);
input_set_abs_params(input_dev, ABS_MT_PALM,
0, 1, 0, 0);
input_set_drvdata(input_dev, info);
ret = input_register_device(input_dev);
if (ret) {
dev_err(&client->dev, "failed to register input dev (%d)\n",
ret);
goto err_reg_input_dev;
}
ma34_debug_probe_status = 6;
#if TOUCH_BOOSTER
mutex_init(&info->dvfs_lock);
INIT_DELAYED_WORK(&info->work_dvfs_off, set_dvfs_off);
INIT_DELAYED_WORK(&info->work_dvfs_chg, change_dvfs_lock);
bus_dev = dev_get("exynos-busfreq");
info->cpufreq_level = -1;
info->dvfs_lock_status = false;
#endif
i2c_set_clientdata(client, info);
info->pdata->power(true);
msleep(100);
ret = i2c_master_recv(client, buf, 1);
if (ret < 0) { /* tsp connect check */
pr_err("%s: i2c fail...tsp driver unload [%d], Add[%d]\n",
__func__, ret, info->client->addr);
goto err_config;
}
ma34_debug_probe_status = 7;
ret = mms_ts_fw_load(info);
/* ret = mms_ts_fw_info(info); */
if (ret) {
dev_err(&client->dev, "failed to initialize (%d)\n", ret);
goto err_config;
}
ma34_debug_probe_status = 8;
info->enabled = true;
info->callbacks.inform_charger = melfas_ta_cb;
if (info->register_cb)
info->register_cb(&info->callbacks);
#ifdef CONFIG_HAS_EARLYSUSPEND
info->early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING;
info->early_suspend.suspend = mms_ts_early_suspend;
info->early_suspend.resume = mms_ts_late_resume;
register_early_suspend(&info->early_suspend);
#endif
sec_touchscreen = device_create(sec_class,
NULL, 0, info, "sec_touchscreen");
if (IS_ERR(sec_touchscreen)) {
dev_err(&client->dev,
"Failed to create device for the sysfs1\n");
ret = -ENODEV;
}
#ifdef SEC_TSP_FACTORY_TEST
INIT_LIST_HEAD(&info->cmd_list_head);
for (i = 0; i < ARRAY_SIZE(tsp_cmds); i++)
list_add_tail(&tsp_cmds[i].list, &info->cmd_list_head);
mutex_init(&info->cmd_lock);
info->cmd_is_running = false;
fac_dev_ts = device_create(sec_class,
NULL, 0, info, "tsp");
if (IS_ERR(fac_dev_ts))
dev_err(&client->dev, "Failed to create device for the sysfs\n");
ret = sysfs_create_group(&fac_dev_ts->kobj,
&sec_touch_factory_attr_group);
if (ret)
dev_err(&client->dev, "Failed to create sysfs group\n");
#endif
return 0;
err_config:
input_unregister_device(input_dev);
err_reg_input_dev:
input_free_device(input_dev);
err_input_alloc:
input_dev = NULL;
kfree(info);
err_alloc:
return ret;
}
static int __devexit mms_ts_remove(struct i2c_client *client)
{
struct mms_ts_info *info = i2c_get_clientdata(client);
unregister_early_suspend(&info->early_suspend);
if (info->irq >= 0)
free_irq(info->irq, info);
input_unregister_device(info->input_dev);
kfree(info);
return 0;
}
#if defined(CONFIG_PM) || defined(CONFIG_HAS_EARLYSUSPEND)
static int mms_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mms_ts_info *info = i2c_get_clientdata(client);
if (!info->enabled)
return 0;
dev_notice(&info->client->dev, "%s: users=%d\n", __func__,
info->input_dev->users);
disable_irq(info->irq);
info->enabled = false;
touch_is_pressed = 0;
release_all_fingers(info);
info->pdata->power(false);
/* This delay needs to prevent unstable POR by
rapid frequently pressing of PWR key. */
msleep(50);
return 0;
}
static int mms_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mms_ts_info *info = i2c_get_clientdata(client);
int ret = 0;
if (info->enabled)
return 0;
dev_notice(&info->client->dev, "%s: users=%d\n", __func__,
info->input_dev->users);
info->pdata->power(true);
msleep(120);
if (info->ta_status) {
dev_notice(&client->dev, "TA connect!!!\n");
i2c_smbus_write_byte_data(info->client, 0x33, 0x1);
} else {
dev_notice(&client->dev, "TA disconnect!!!\n");
i2c_smbus_write_byte_data(info->client, 0x33, 0x2);
}
/* Because irq_type by EXT_INTxCON register is changed to low_level
* after wakeup, irq_type set to falling edge interrupt again.
*/
enable_irq(info->irq);
info->enabled = true;
mms_set_noise_mode(info);
return 0;
}
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mms_ts_early_suspend(struct early_suspend *h)
{
struct mms_ts_info *info;
info = container_of(h, struct mms_ts_info, early_suspend);
mms_ts_suspend(&info->client->dev);
}
static void mms_ts_late_resume(struct early_suspend *h)
{
struct mms_ts_info *info;
info = container_of(h, struct mms_ts_info, early_suspend);
mms_ts_resume(&info->client->dev);
}
#endif
#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
static const struct dev_pm_ops mms_ts_pm_ops = {
.suspend = mms_ts_suspend,
.resume = mms_ts_resume,
#ifdef CONFIG_HIBERNATION
.freeze = mms_ts_suspend,
.thaw = mms_ts_resume,
.restore = mms_ts_resume,
#endif
};
#endif
static const struct i2c_device_id mms_ts_id[] = {
{MELFAS_TS_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, mms_ts_id);
static struct i2c_driver mms_ts_driver = {
.probe = mms_ts_probe,
.remove = __devexit_p(mms_ts_remove),
.driver = {
.name = MELFAS_TS_NAME,
#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
.pm = &mms_ts_pm_ops,
#endif
},
.id_table = mms_ts_id,
};
#include <linux/proc_fs.h>
static int
proc_read( char* page, char** start, off_t offset, int count, int* eof, void* data )
{
int len = 0;
#if 0
printk( KERN_INFO "%s : read() called\n", msg );
if ( down_interruptible( &proc_sem ) ) {
printk( KERN_INFO "%s : down_interruptible for read failed\n", msg );
return -ERESTARTSYS;
}
if ( buf_pos != 0 ) {
len += sprintf( page, "%s : Internal buffer contents = %s\n", msg, procbuf );
buf_pos = 0;
}
up( &proc_sem );
*eof = 1;
#endif
len += sprintf( page, "probe_status = %d,fw_status=%d\n", ma34_debug_probe_status,ma34_debug_fw_status );
return len;
}
static int
proc_write( struct file* filp, const char* buffer, unsigned long count, void* data )
{
int copy_len = 0;
return copy_len;
}
static int __init mms_ts_init(void)
{
struct proc_dir_entry* entry;
entry = create_proc_entry( "mms_ts",
S_IFREG | S_IRUGO | S_IWUGO, NULL );
ma34_debug_probe_status = 0;
if ( entry != NULL ) {
entry->read_proc = proc_read;
entry->write_proc = proc_write;
}
else {
printk( KERN_INFO "%s : create_proc_entry failed\n", "mms_ts_init" );
return -EBUSY;
}
// sema_init( &proc_sem, 1 );
printk( KERN_INFO "%s : loaded into kernel\n", "mms_ts_init" );
//------------------------------------------------------------------------
return i2c_add_driver(&mms_ts_driver);
}
static void __exit mms_ts_exit(void)
{
i2c_del_driver(&mms_ts_driver);
}
module_init(mms_ts_init);
module_exit(mms_ts_exit);
/* Module information */
MODULE_DESCRIPTION("Touchscreen driver for Melfas MMS-series controllers");
MODULE_LICENSE("GPL");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment