sec_mmi: plug in mmi interfaces

First step to align reference driver's code with MMI requirements

Change-Id: I832c7d2927ccd0d04c6ea44548198fe2e54131d3
Signed-off-by: Konstantin Makariev <hcv867@motorola.com>
Reviewed-on: https://gerrit.mot.com/1387460
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Konstantin Makariev <kmakariev@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
Konstantin Makariev 2019-06-25 13:46:01 -05:00 • committed by Konstantin Makariev
commit 9a8a94046a
11 changed files with 1326 additions and 356 deletions

View file

@ -1,7 +1,9 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include \
EXTRA_CFLAGS += \
-I$(TOP)/motorola/kernel/modules/include \
-I$(TOP)/motorola/kernel/modules/drivers/input/touchscreen/sec_mmi
obj-m := sec_mmi.o
sec_mmi-objs = sec_ts.o sec_ts_fn.o sec_ts_fw.o sec_ts_only_vendor.o sec_ts_mmi.o
sec_mmi-objs = sec_ts.o sec_ts_fn.o sec_ts_fw.o sec_ts_mmi.o sec_cmd.o
# sec_ts_only_vendor.o

View file

@ -0,0 +1,558 @@
/*
* sec_cmd.c - samsung factory command driver
*
* Copyright (C) 2014 Samsung Electronics
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include "sec_ts.h"
#if defined USE_SEC_CMD_QUEUE
static void sec_cmd_store_function(struct sec_cmd_data *data);
#endif
void sec_cmd_set_cmd_exit(struct sec_cmd_data *data)
{
mutex_lock(&data->cmd_lock);
data->cmd_is_running = false;
mutex_unlock(&data->cmd_lock);
#ifdef USE_SEC_CMD_QUEUE
mutex_lock(&data->fifo_lock);
if (kfifo_len(&data->cmd_queue)) {
pr_info("%s: do next cmd, left cmd[%d]\n", __func__,
(int)(kfifo_len(&data->cmd_queue) / sizeof(struct command)));
mutex_unlock(&data->fifo_lock);
/* check lock */
mutex_lock(&data->cmd_lock);
data->cmd_is_running = true;
mutex_unlock(&data->cmd_lock);
data->cmd_state = SEC_CMD_STATUS_RUNNING;
sec_cmd_store_function(data);
} else {
mutex_unlock(&data->fifo_lock);
}
#endif
}
void sec_cmd_set_default_result(struct sec_cmd_data *data)
{
char delim = ':';
memset(data->cmd_result, 0x00, SEC_CMD_RESULT_STR_LEN);
memcpy(data->cmd_result, data->cmd, SEC_CMD_STR_LEN);
strncat(data->cmd_result, &delim, 1);
}
void sec_cmd_set_cmd_result(struct sec_cmd_data *data, char *buff, int len)
{
strlcat(data->cmd_result, buff, SEC_CMD_RESULT_STR_LEN);
}
#ifndef USE_SEC_CMD_QUEUE
static ssize_t sec_cmd_store(struct device *dev,
struct device_attribute *devattr, const char *buf, size_t count)
{
struct sec_cmd_data *data = dev_get_drvdata(dev);
char *cur, *start, *end;
char buff[SEC_CMD_STR_LEN] = { 0 };
int len, i;
struct sec_cmd *sec_cmd_ptr = NULL;
char delim = ',';
bool cmd_found = false;
int param_cnt = 0;
if (!data) {
pr_err("%s: No platform data found\n", __func__);
return -EINVAL;
}
if (strlen(buf) >= SEC_CMD_STR_LEN) {
pr_err("%s: cmd length is over (%s,%d)!!\n", __func__, buf, (int)strlen(buf));
return -EINVAL;
}
if (data->cmd_is_running == true) {
pr_err("%s: other cmd is running.\n", __func__);
return -EBUSY;
}
/* check lock */
mutex_lock(&data->cmd_lock);
data->cmd_is_running = true;
mutex_unlock(&data->cmd_lock);
data->cmd_state = SEC_CMD_STATUS_RUNNING;
for (i = 0; i < ARRAY_SIZE(data->cmd_param); i++)
data->cmd_param[i] = 0;
len = (int)count;
if (*(buf + len - 1) == '\n')
len--;
memset(data->cmd, 0x00, ARRAY_SIZE(data->cmd));
memcpy(data->cmd, buf, len);
cur = strchr(buf, (int)delim);
if (cur)
memcpy(buff, buf, cur - buf);
else
memcpy(buff, buf, len);
pr_debug("%s: COMMAND = %s\n", __func__, buff);
/* find command */
list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
if (!strncmp(buff, sec_cmd_ptr->cmd_name, SEC_CMD_STR_LEN)) {
cmd_found = true;
break;
}
}
/* set not_support_cmd */
if (!cmd_found) {
list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
if (!strncmp("not_support_cmd", sec_cmd_ptr->cmd_name,
SEC_CMD_STR_LEN))
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 + strnlen(buff, ARRAY_SIZE(buff))) = '\0';
if (kstrtoint(buff, 10, data->cmd_param + param_cnt) < 0)
goto err_out;
start = cur + 1;
memset(buff, 0x00, ARRAY_SIZE(buff));
param_cnt++;
}
cur++;
} while ((cur - buf <= len) && (param_cnt < SEC_CMD_PARAM_NUM));
}
if (cmd_found) {
pr_info("%s: cmd = %s", __func__, sec_cmd_ptr->cmd_name);
for (i = 0; i < param_cnt; i++) {
if (i == 0)
pr_cont(" param =");
pr_cont(" %d", data->cmd_param[i]);
}
pr_cont("\n");
} else {
pr_info("%s: cmd = %s(%s)\n", __func__, buff, sec_cmd_ptr->cmd_name);
}
sec_cmd_ptr->cmd_func(data);
sec_cmd_set_cmd_exit(data);
err_out:
return count;
}
#else /* defined USE_SEC_CMD_QUEUE */
static void sec_cmd_store_function(struct sec_cmd_data *data)
{
char *cur, *start, *end;
char buff[SEC_CMD_STR_LEN] = { 0 };
int len, i;
struct sec_cmd *sec_cmd_ptr = NULL;
char delim = ',';
bool cmd_found = false;
int param_cnt = 0;
int ret;
const char *buf;
size_t count;
struct command cmd = {{0}};
if (!data) {
pr_err("%s: No platform data found\n", __func__);
return;
}
mutex_lock(&data->fifo_lock);
if (kfifo_len(&data->cmd_queue)) {
ret = kfifo_out(&data->cmd_queue, &cmd, sizeof(struct command));
if (!ret) {
pr_err("%s: kfifo_out failed, it seems empty, ret=%d\n", __func__, ret);
mutex_unlock(&data->fifo_lock);
return;
}
} else {
pr_err("%s: left cmd is nothing\n", __func__);
mutex_unlock(&data->fifo_lock);
return;
}
mutex_unlock(&data->fifo_lock);
buf = cmd.cmd;
count = strlen(buf);
for (i = 0; i < (int)ARRAY_SIZE(data->cmd_param); i++)
data->cmd_param[i] = 0;
len = (int)count;
if (*(buf + len - 1) == '\n')
len--;
memset(data->cmd, 0x00, ARRAY_SIZE(data->cmd));
memcpy(data->cmd, buf, len);
cur = strchr(buf, (int)delim);
if (cur)
memcpy(buff, buf, cur - buf);
else
memcpy(buff, buf, len);
pr_debug("%s: COMMAND : %s\n", __func__, buff);
/* find command */
list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
if (!strncmp(buff, sec_cmd_ptr->cmd_name, SEC_CMD_STR_LEN)) {
cmd_found = true;
break;
}
}
/* set not_support_cmd */
if (!cmd_found) {
list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
if (!strncmp("not_support_cmd", sec_cmd_ptr->cmd_name,
SEC_CMD_STR_LEN))
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 + strnlen(buff, ARRAY_SIZE(buff))) = '\0';
if (kstrtoint(buff, 10, data->cmd_param + param_cnt) < 0)
return;
start = cur + 1;
memset(buff, 0x00, ARRAY_SIZE(buff));
param_cnt++;
}
cur++;
} while ((cur - buf <= len) && (param_cnt < SEC_CMD_PARAM_NUM));
}
if (cmd_found) {
pr_info("%s: cmd = %s", __func__, sec_cmd_ptr->cmd_name);
for (i = 0; i < param_cnt; i++) {
if (i == 0)
pr_cont(" param =");
pr_cont(" %d", data->cmd_param[i]);
}
pr_cont("\n");
} else {
pr_info("%s: cmd = %s(%s)\n", __func__, buff, sec_cmd_ptr->cmd_name);
}
sec_cmd_ptr->cmd_func(data);
}
static ssize_t sec_cmd_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sec_cmd_data *data = dev_get_drvdata(dev);
struct command cmd = {{0}};
int queue_size;
if (!data) {
pr_err("%s: No platform data found\n", __func__);
return -EINVAL;
}
if (strlen(buf) >= SEC_CMD_STR_LEN) {
pr_err("%s: cmd length is over (%s,%d)!!\n", __func__, buf, (int)strlen(buf));
return -EINVAL;
}
strncpy(cmd.cmd, buf, count);
mutex_lock(&data->fifo_lock);
queue_size = (kfifo_len(&data->cmd_queue) / sizeof(struct command));
if (kfifo_avail(&data->cmd_queue) && (queue_size < SEC_CMD_MAX_QUEUE)) {
kfifo_in(&data->cmd_queue, &cmd, sizeof(struct command));
pr_info("%s: push cmd: %s\n", __func__, cmd.cmd);
} else {
pr_err("%s: cmd_queue is full!!\n", __func__);
kfifo_reset(&data->cmd_queue);
pr_err("%s: cmd_queue is reset!!\n", __func__);
mutex_unlock(&data->fifo_lock);
mutex_lock(&data->cmd_lock);
data->cmd_is_running = false;
mutex_unlock(&data->cmd_lock);
return -ENOSPC;
}
if (data->cmd_is_running == true) {
pr_err("%s: other cmd is running. Wait until previous cmd is done[%d]\n",
__func__, (int)(kfifo_len(&data->cmd_queue) / sizeof(struct command)));
mutex_unlock(&data->fifo_lock);
return -EBUSY;
}
mutex_unlock(&data->fifo_lock);
/* check lock */
mutex_lock(&data->cmd_lock);
data->cmd_is_running = true;
mutex_unlock(&data->cmd_lock);
data->cmd_state = SEC_CMD_STATUS_RUNNING;
sec_cmd_store_function(data);
return count;
}
#endif
static ssize_t sec_cmd_show_status(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sec_cmd_data *data = dev_get_drvdata(dev);
char buff[16] = { 0 };
if (!data) {
pr_err("%s: No platform data found\n", __func__);
return -EINVAL;
}
if (data->cmd_state == SEC_CMD_STATUS_WAITING)
snprintf(buff, sizeof(buff), "WAITING");
else if (data->cmd_state == SEC_CMD_STATUS_RUNNING)
snprintf(buff, sizeof(buff), "RUNNING");
else if (data->cmd_state == SEC_CMD_STATUS_OK)
snprintf(buff, sizeof(buff), "OK");
else if (data->cmd_state == SEC_CMD_STATUS_FAIL)
snprintf(buff, sizeof(buff), "FAIL");
else if (data->cmd_state == SEC_CMD_STATUS_NOT_APPLICABLE)
snprintf(buff, sizeof(buff), "NOT_APPLICABLE");
pr_debug("%s: %d, %s\n", __func__, data->cmd_state, buff);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buff);
}
static ssize_t sec_cmd_show_result(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sec_cmd_data *data = dev_get_drvdata(dev);
int size;
if (!data) {
pr_err("%s: No platform data found\n", __func__);
return -EINVAL;
}
data->cmd_state = SEC_CMD_STATUS_WAITING;
pr_info("%s: %s\n", __func__, data->cmd_result);
size = snprintf(buf, SEC_CMD_RESULT_STR_LEN, "%s\n", data->cmd_result);
sec_cmd_set_cmd_exit(data);
return size;
}
static ssize_t sec_cmd_list_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *data = dev_get_drvdata(dev);
struct sec_cmd *sec_cmd_ptr = NULL;
char buffer[data->cmd_buffer_size + 30];
char buffer_name[SEC_CMD_STR_LEN];
snprintf(buffer, 30, "++factory command list++\n");
list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
if (strncmp(sec_cmd_ptr->cmd_name, "not_support_cmd", 15)) {
snprintf(buffer_name, SEC_CMD_STR_LEN, "%s\n", sec_cmd_ptr->cmd_name);
strncat(buffer, buffer_name, SEC_CMD_STR_LEN);
}
}
return snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buffer);
}
static DEVICE_ATTR(cmd, S_IWUSR | S_IWGRP, NULL, sec_cmd_store);
static DEVICE_ATTR(cmd_status, S_IRUGO, sec_cmd_show_status, NULL);
static DEVICE_ATTR(cmd_result, S_IRUGO, sec_cmd_show_result, NULL);
static DEVICE_ATTR(cmd_list, S_IRUGO, sec_cmd_list_show, NULL);
static struct attribute *sec_fac_attrs[] = {
&dev_attr_cmd.attr,
&dev_attr_cmd_status.attr,
&dev_attr_cmd_result.attr,
&dev_attr_cmd_list.attr,
NULL,
};
static struct attribute_group sec_fac_attr_group = {
.attrs = sec_fac_attrs,
};
static inline struct device *sec_device_create(struct sec_cmd_data *data, char *dev_name) {
return NULL;
}
static inline void sec_device_destroy(int devt) {
}
struct class *sec_class;
int sec_cmd_init(struct sec_cmd_data *data, struct sec_cmd *cmds,
int len, int devt)
{
const char *dev_name;
int ret, i;
sec_class = class_create(THIS_MODULE, "sec_cmd");
ret = IS_ERR_OR_NULL(sec_class);
if (ret) {
pr_err("%s: fail - class_create\n", __func__);
return -ENODEV;
}
INIT_LIST_HEAD(&data->cmd_list_head);
data->cmd_buffer_size = 0;
for (i = 0; i < len; i++) {
list_add_tail(&cmds[i].list, &data->cmd_list_head);
if (cmds[i].cmd_name)
data->cmd_buffer_size += strlen(cmds[i].cmd_name) + 1;
}
mutex_init(&data->cmd_lock);
mutex_lock(&data->cmd_lock);
data->cmd_is_running = false;
mutex_unlock(&data->cmd_lock);
#ifdef USE_SEC_CMD_QUEUE
if (kfifo_alloc(&data->cmd_queue,
SEC_CMD_MAX_QUEUE * sizeof(struct command), GFP_KERNEL)) {
pr_err("%s: failed to alloc queue for cmd\n", __func__);
goto err_alloc_queue;
}
mutex_init(&data->fifo_lock);
#endif
if (devt == SEC_CLASS_DEVT_TSP) {
dev_name = SEC_CLASS_DEV_NAME_TSP;
} else if (devt == SEC_CLASS_DEVT_TKEY) {
dev_name = SEC_CLASS_DEV_NAME_TKEY;
} else if (devt == SEC_CLASS_DEVT_WACOM) {
dev_name = SEC_CLASS_DEV_NAME_WACOM;
} else {
pr_err("%s: not defined devt=%d\n", __func__, devt);
goto err_get_dev_name;
}
#ifdef CONFIG_SEC_SYSFS
data->fac_dev = sec_device_create(data, dev_name);
#else
data->fac_dev = device_create(sec_class, NULL, devt, data, dev_name);
#endif
if (IS_ERR(data->fac_dev)) {
pr_err("%s: failed to create device for the sysfs\n", __func__);
goto err_sysfs_device;
}
dev_set_drvdata(data->fac_dev, data);
ret = sysfs_create_group(&data->fac_dev->kobj, &sec_fac_attr_group);
if (ret < 0) {
pr_err("%s: failed to create sysfs group\n", __func__);
goto err_sysfs_group;
}
return 0;
sysfs_remove_group(&data->fac_dev->kobj, &sec_fac_attr_group);
err_sysfs_group:
#ifdef CONFIG_SEC_SYSFS
sec_device_destroy(data->fac_dev->devt);
#else
device_destroy(sec_class, devt);
#endif
err_sysfs_device:
err_get_dev_name:
#ifdef USE_SEC_CMD_QUEUE
mutex_destroy(&data->fifo_lock);
kfifo_free(&data->cmd_queue);
err_alloc_queue:
#endif
mutex_destroy(&data->cmd_lock);
list_del(&data->cmd_list_head);
return -ENODEV;
}
void sec_cmd_exit(struct sec_cmd_data *data, int devt)
{
#ifdef USE_SEC_CMD_QUEUE
struct command cmd = {{0}};
int ret;
#endif
pr_info("%s", __func__);
sysfs_remove_group(&data->fac_dev->kobj, &sec_fac_attr_group);
dev_set_drvdata(data->fac_dev, NULL);
#ifdef CONFIG_SEC_SYSFS
sec_device_destroy(data->fac_dev->devt);
#else
device_destroy(sec_class, devt);
#endif
#ifdef USE_SEC_CMD_QUEUE
mutex_lock(&data->fifo_lock);
while (kfifo_len(&data->cmd_queue)) {
ret = kfifo_out(&data->cmd_queue, &cmd, sizeof(struct command));
if (!ret) {
pr_err("%s: kfifo_out failed, it seems empty, ret=%d\n", __func__, ret);
}
pr_info("%s: remove pending commands: %s", __func__, cmd.cmd);
}
mutex_unlock(&data->fifo_lock);
mutex_destroy(&data->fifo_lock);
kfifo_free(&data->cmd_queue);
#endif
mutex_destroy(&data->cmd_lock);
list_del(&data->cmd_list_head);
}
MODULE_DESCRIPTION("Samsung factory command");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,91 @@
#ifndef _SEC_CMD_H_
#define _SEC_CMD_H_
#undef CONFIG_SEC_SYSFS
#undef CONFIG_SEC_FACTORY
#undef USE_SEC_CMD_QUEUE
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/workqueue.h>
#include <linux/stat.h>
#include <linux/err.h>
#include <linux/input.h>
#if 0
#ifdef CONFIG_SEC_SYSFS
//#include <linux/sec_sysfs.h>
#endif
#ifndef CONFIG_SEC_FACTORY
#include <linux/kfifo.h>
#endif
#ifndef CONFIG_SEC_SYSFS
extern struct class *sec_class;
#endif
#endif
#define SEC_CLASS_DEVT_TSP 10
#define SEC_CLASS_DEVT_TKEY 11
#define SEC_CLASS_DEVT_WACOM 12
#define SEC_CLASS_DEV_NAME_TSP "tsp"
#define SEC_CLASS_DEV_NAME_TKEY "sec_touchkey"
#define SEC_CLASS_DEV_NAME_WACOM "sec_epen"
#define SEC_CMD(name, func) .cmd_name = name, .cmd_func = func
#define SEC_CMD_BUF_SIZE (4096 - 1)
#define SEC_CMD_STR_LEN 256
#define SEC_CMD_RESULT_STR_LEN (4096 - 1)
#define SEC_CMD_PARAM_NUM 8
struct sec_cmd {
struct list_head list;
const char *cmd_name;
void (*cmd_func)(void *device_data);
};
enum SEC_CMD_STATUS {
SEC_CMD_STATUS_WAITING = 0,
SEC_CMD_STATUS_RUNNING, // = 1
SEC_CMD_STATUS_OK, // = 2
SEC_CMD_STATUS_FAIL, // = 3
SEC_CMD_STATUS_NOT_APPLICABLE, // = 4
};
#ifdef USE_SEC_CMD_QUEUE
#define SEC_CMD_MAX_QUEUE 10
struct command {
char cmd[SEC_CMD_STR_LEN];
};
#endif
struct sec_cmd_data {
struct device *fac_dev;
struct list_head cmd_list_head;
u8 cmd_state;
char cmd[SEC_CMD_STR_LEN];
int cmd_param[SEC_CMD_PARAM_NUM];
char cmd_result[SEC_CMD_RESULT_STR_LEN];
int cmd_buffer_size;
bool cmd_is_running;
struct mutex cmd_lock;
#ifdef USE_SEC_CMD_QUEUE
struct kfifo cmd_queue;
struct mutex fifo_lock;
#endif
};
extern void sec_cmd_set_cmd_exit(struct sec_cmd_data *data);
extern void sec_cmd_set_default_result(struct sec_cmd_data *data);
extern void sec_cmd_set_cmd_result(struct sec_cmd_data *data, char *buff, int len);
extern int sec_cmd_init(struct sec_cmd_data *data,
struct sec_cmd *cmds, int len, int devt);
extern void sec_cmd_exit(struct sec_cmd_data *data, int devt);
#endif /* _SEC_CMD_H_ */

View file

@ -0,0 +1,14 @@
#ifndef _SEC_CUSTOM_H_
#define _SEC_CUSTOM_H_
/* ABS_MT */
#define ABS_MT_CUSTOM 0x3e
/* SW_ */
#define SW_GLOVE 0x0f
/* KEY_ */
#define KEY_SIDE_GESTURE 0x1c6
#define KEY_BLACK_UI_GESTURE 0x1c7
#define KEY_SIDE_GESTURE_RIGHT 0x1ca
#define KEY_SIDE_GESTURE_LEFT 0x1cb
#endif /* _SEC_CUSTOM_H_ */

View file

@ -4,22 +4,43 @@
#include <linux/major.h>
#include <linux/kdev_t.h>
#include <linux/notifier.h>
#if defined(CONFIG_DRM)
#include <linux/msm_drm_notify.h>
extern bool dsi_display_is_panel_enable(int id, int *probe_status, char **pname);
#endif
#define TSDEV_MINOR_BASE 128
#define TSDEV_MINOR_MAX 32
struct sec_ts_data;
struct sec_mmi_data {
struct sec_ts_data *ts_ptr;
struct i2c_client *i2c_client;
struct device *ts_class_dev;
struct notifier_block panel_nb;
struct work_struct resume_work;
struct delayed_work resume_work;
struct delayed_work detection_work;
int ctrl_dsi;
unsigned int build_id;
unsigned int config_id;
char product_id[10];
char *image_name;
const char *class_entry_name;
const char *bound_display;
void (*hard_reset)(struct sec_mmi_data *data);
};
int sec_mmi_data_init(struct sec_ts_data *ts, bool enable);
#define DEV_MMI (&data->i2c_client->dev)
#define DEV_TS (&ts->client->dev)
extern struct class *get_touchscreen_class_ptr(void);
extern void set_touchscreen_class_ptr(struct class *ptr);
#endif

View file

@ -13,6 +13,7 @@
struct sec_ts_data *tsp_info;
#include "sec_ts.h"
#include "sec_mmi.h"
struct sec_ts_data *ts_dup;
@ -26,8 +27,18 @@ static int sec_ts_input_open(struct input_dev *dev);
static void sec_ts_input_close(struct input_dev *dev);
#endif
int sec_ts_read_information(struct sec_ts_data *ts);
void sec_ts_irq_enable(struct sec_ts_data *ts, bool on)
{
if (on) {
if (ts->irq_enabled)
return;
ts->irq_enabled = true;
enable_irq(ts->client->irq);
} else if (ts->irq_enabled) {
ts->irq_enabled = false;
disable_irq(ts->client->irq);
}
}
int sec_ts_i2c_write(struct sec_ts_data *ts, u8 reg, u8 *data, int len)
{
@ -350,17 +361,17 @@ static void sec_ts_check_rawdata(struct work_struct *work)
static void dump_tsp_log(void)
{
pr_info("%s: %s %s: start\n", SEC_TS_I2C_NAME, SECLOG, __func__);
pr_info("%s: %s: start\n", SEC_TS_I2C_NAME, __func__);
#ifdef CONFIG_BATTERY_SAMSUNG
if (lpcharge == 1) {
pr_err("%s: %s %s: ignored ## lpm charging Mode!!\n", SEC_TS_I2C_NAME, SECLOG, __func__);
pr_err("%s: %s: ignored ## lpm charging Mode!!\n", SEC_TS_I2C_NAME, __func__);
return;
}
#endif
if (p_ghost_check == NULL) {
pr_err("%s: %s %s: ignored ## tsp probe fail!!\n", SEC_TS_I2C_NAME, SECLOG, __func__);
pr_err("%s: %s: ignored ## tsp probe fail!!\n", SEC_TS_I2C_NAME, __func__);
return;
}
schedule_delayed_work(p_ghost_check, msecs_to_jiffies(100));
@ -551,7 +562,7 @@ static void sec_ts_read_event(struct sec_ts_data *ts)
int pre_ttype = 0;
if (ts->power_status == SEC_TS_STATE_LPM) {
wake_lock_timeout(&ts->wakelock, msecs_to_jiffies(500));
//wake_lock_timeout(&ts->wakelock, msecs_to_jiffies(500));
/* waiting for blsp block resuming, if not occurs i2c error */
ret = wait_for_completion_interruptible_timeout(&ts->resume_done, msecs_to_jiffies(500));
@ -1178,6 +1189,16 @@ static int sec_ts_parse_dt(struct i2c_client *client)
input_err(true, dev, "%s: Failed to get tsp-icid gpio\n", __func__);
}
pdata->rst_gpio = of_get_named_gpio(np, "sec,rst_gpio", 0);
if (gpio_is_valid(pdata->rst_gpio)) {
ret = gpio_request_one(pdata->rst_gpio, GPIOF_DIR_OUT, "sec,tsp_rst");
if (ret) {
input_err(true, &client->dev, "%s: Unable to request tsp_rst [%d]\n", __func__, pdata->rst_gpio);
return -EINVAL;
}
} else
input_info(true, &client->dev, "%s: has no rst gpio\n", __func__);
pdata->tsp_vsync = of_get_named_gpio(np, "sec,tsp_vsync_gpio", 0);
if (gpio_is_valid(pdata->tsp_vsync))
input_info(true, &client->dev, "%s: vsync %s\n", __func__,
@ -1235,6 +1256,7 @@ static int sec_ts_parse_dt(struct i2c_client *client)
if (of_property_read_string_index(np, "sec,project_name", 0, &pdata->project_name))
input_err(true, &client->dev, "%s: skipped to get project_name property\n", __func__);
if (of_property_read_string_index(np, "sec,project_name", 1, &pdata->model_name))
input_err(true, &client->dev, "%s: skipped to get model_name property\n", __func__);
@ -1274,87 +1296,6 @@ static int sec_ts_parse_dt(struct i2c_client *client)
return ret;
}
int sec_ts_read_information(struct sec_ts_data *ts)
{
unsigned char data[13] = { 0 };
int ret;
memset(data, 0x0, 3);
ret = sec_ts_i2c_read(ts, SEC_TS_READ_ID, data, 3);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read device id(%d)\n",
__func__, ret);
return ret;
}
input_info(true, &ts->client->dev,
"%s: %X, %X, %X\n",
__func__, data[0], data[1], data[2]);
memset(data, 0x0, 11);
ret = sec_ts_i2c_read(ts, SEC_TS_READ_PANEL_INFO, data, 11);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read sub id(%d)\n",
__func__, ret);
return ret;
}
input_info(true, &ts->client->dev,
"%s: nTX:%X, nRX:%X, rY:%d, rX:%d\n",
__func__, data[8], data[9],
(data[2] << 8) | data[3], (data[0] << 8) | data[1]);
/* Set X,Y Resolution from IC information. */
if (((data[0] << 8) | data[1]) > 0)
ts->plat_data->max_x = ((data[0] << 8) | data[1]) - 1;
if (((data[2] << 8) | data[3]) > 0)
ts->plat_data->max_y = ((data[2] << 8) | data[3]) - 1;
ts->tx_count = data[8];
ts->rx_count = data[9];
data[0] = 0;
ret = sec_ts_i2c_read(ts, SEC_TS_READ_BOOT_STATUS, data, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read sub id(%d)\n",
__func__, ret);
return ret;
}
input_info(true, &ts->client->dev,
"%s: STATUS : %X\n",
__func__, data[0]);
memset(data, 0x0, 4);
ret = sec_ts_i2c_read(ts, SEC_TS_READ_TS_STATUS, data, 4);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read sub id(%d)\n",
__func__, ret);
return ret;
}
input_info(true, &ts->client->dev,
"%s: TOUCH STATUS : %02X, %02X, %02X, %02X\n",
__func__, data[0], data[1], data[2], data[3]);
ret = sec_ts_i2c_read(ts, SEC_TS_CMD_SET_TOUCHFUNCTION, (u8 *)&(ts->touch_functions), 2);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read touch functions(%d)\n",
__func__, ret);
return ret;
}
input_info(true, &ts->client->dev,
"%s: Functions : %02X\n",
__func__, ts->touch_functions);
return ret;
}
#ifdef SEC_TS_SUPPORT_CUSTOMLIB
int sec_ts_set_custom_library(struct sec_ts_data *ts)
{
@ -1459,16 +1400,184 @@ static void sec_ts_set_input_prop(struct sec_ts_data *ts, struct input_dev *dev,
input_set_drvdata(dev, ts);
}
void sec_ts_sense_on(struct sec_ts_data *ts)
{
int ret;
ts->touch_functions |= SEC_TS_DEFAULT_ENABLE_BIT_SETFUNC;
ret = sec_ts_i2c_write(ts, SEC_TS_CMD_SET_TOUCHFUNCTION,
(u8 *)&ts->touch_functions, 2);
if (ret < 0)
input_err(true, &ts->client->dev,
"%s: Failed to send touch func_mode command", __func__);
/* Sense_on */
ret = sec_ts_i2c_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0);
if (ret < 0)
input_err(true, &ts->client->dev,
"%s: fail to write Sense_on\n", __func__);
}
static int sec_ts_read_fw_info(struct sec_ts_data *ts)
{
unsigned char data[13] = { 0 };
int ret;
memset(data, 0x0, 3);
ret = sec_ts_i2c_read(ts, SEC_TS_READ_ID, data, 3);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read device id(%d)\n",
__func__, ret);
return ret;
}
input_info(true, &ts->client->dev,
"%s: %X, %X, %X\n",
__func__, data[0], data[1], data[2]);
memset(data, 0x0, 11);
ret = sec_ts_i2c_read(ts, SEC_TS_READ_PANEL_INFO, data, 11);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read sub id(%d)\n",
__func__, ret);
return ret;
}
input_info(true, &ts->client->dev,
"%s: nTX:%X, nRX:%X, rY:%d, rX:%d\n",
__func__, data[8], data[9],
(data[2] << 8) | data[3], (data[0] << 8) | data[1]);
/* Set X,Y Resolution from IC information. */
if (((data[0] << 8) | data[1]) > 0)
ts->plat_data->max_x = ((data[0] << 8) | data[1]) - 1;
if (((data[2] << 8) | data[3]) > 0)
ts->plat_data->max_y = ((data[2] << 8) | data[3]) - 1;
ts->tx_count = data[8];
ts->rx_count = data[9];
if (ts->pFrame)
kfree(ts->pFrame);
ts->pFrame = kzalloc(ts->tx_count * ts->rx_count * 2, GFP_KERNEL);
if (!ts->pFrame) {
input_err(true, &ts->client->dev,
"%s: failed to alloc frame\n", __func__);
return -ENOMEM;
}
data[0] = 0;
ret = sec_ts_i2c_read(ts, SEC_TS_READ_BOOT_STATUS, data, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read sub id(%d)\n",
__func__, ret);
return ret;
}
input_info(true, &ts->client->dev,
"%s: STATUS : %X\n",
__func__, data[0]);
memset(data, 0x0, 4);
ret = sec_ts_i2c_read(ts, SEC_TS_READ_TS_STATUS, data, 4);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read sub id(%d)\n",
__func__, ret);
return ret;
}
input_info(true, &ts->client->dev,
"%s: TOUCH STATUS : %02X, %02X, %02X, %02X\n",
__func__, data[0], data[1], data[2], data[3]);
ret = sec_ts_i2c_read(ts, SEC_TS_CMD_SET_TOUCHFUNCTION, (u8 *)&(ts->touch_functions), 2);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read touch functions(%d)\n",
__func__, ret);
return ret;
}
input_info(true, &ts->client->dev,
"%s: Functions : %02X\n",
__func__, ts->touch_functions);
return ret;
}
static void sec_ts_read_hw_info(struct sec_ts_data *ts)
{
unsigned char result;
unsigned char buffer[5] = { 0 };
bool valid_firmware_integrity = false;
int ret;
ret = sec_ts_i2c_read(ts, SEC_TS_READ_DEVICE_ID, buffer, 5);
if (ret < 0)
input_err(true, &ts->client->dev,
"%s: failed to read device ID(%d)\n", __func__, ret);
else {
memcpy(ts->device_id, buffer, sizeof(ts->device_id));
input_info(true, &ts->client->dev,
"%s: TOUCH DEVICE ID : %02X, %02X, %02X, %02X, %02X\n", __func__,
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
}
ret = sec_ts_i2c_read(ts, SEC_TS_READ_FIRMWARE_INTEGRITY, &result, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to integrity check (%d)\n", __func__, ret);
} else {
if (result & 0x80) {
valid_firmware_integrity = true;
} else if (result & 0x40) {
valid_firmware_integrity = false;
input_err(true, &ts->client->dev,
"%s: invalid firmware (0x%x)\n", __func__, result);
} else {
valid_firmware_integrity = false;
input_err(true, &ts->client->dev,
"%s: invalid integrity result (0x%x)\n", __func__, result);
}
}
memset(buffer, 0, sizeof(buffer));
ret = sec_ts_i2c_read(ts, SEC_TS_READ_BOOT_STATUS, &buffer[0], 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read sub id(%d)\n",
__func__, ret);
} else {
ret = sec_ts_i2c_read(ts, SEC_TS_READ_TS_STATUS, &buffer[1], 4);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to touch status(%d)\n",
__func__, ret);
}
}
input_info(true, &ts->client->dev,
"%s: TOUCH STATUS : %02X || %02X, %02X, %02X, %02X\n",
__func__, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
if (buffer[0] == SEC_TS_STATUS_BOOT_MODE) {
ts->checksum_result = 1;
ts->fw_invalid = true;
}
if ((buffer[0] == SEC_TS_STATUS_APP_MODE &&
buffer[2] == TOUCH_SYSTEM_MODE_FLASH) ||
(valid_firmware_integrity == false))
ts->fw_invalid = true;
}
static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct sec_ts_data *ts;
struct sec_ts_plat_data *pdata;
int ret = 0;
bool force_update = false;
bool valid_firmware_integrity = false;
unsigned char data[5] = { 0 };
unsigned char deviceID[5] = { 0 };
unsigned char result = 0;
input_info(true, &client->dev, "%s\n", __func__);
@ -1502,20 +1611,13 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i
}
}
if (!pdata->power) {
input_err(true, &client->dev, "%s: No power contorl found\n", __func__);
goto error_allocate_mem;
}
pdata->pinctrl = devm_pinctrl_get(&client->dev);
if (IS_ERR(pdata->pinctrl))
input_err(true, &client->dev, "%s: could not get pinctrl\n", __func__);
/* init TS static elements */
ts = kzalloc(sizeof(struct sec_ts_data), GFP_KERNEL);
if (!ts)
goto error_allocate_mem;
ts->client = client;
ts->dev = &client->dev;
ts->plat_data = pdata;
ts->crc_addr = 0x0001FE00;
ts->fw_addr = 0x00002000;
@ -1526,6 +1628,16 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i
ts->sec_ts_i2c_write_burst = sec_ts_i2c_write_burst;
ts->sec_ts_i2c_read_bulk = sec_ts_i2c_read_bulk;
ts->i2c_burstmax = pdata->i2c_burstmax;
if (!pdata->power) {
input_err(true, &client->dev, "%s: No power contorl found\n", __func__);
goto error_allocate_mem;
}
pdata->pinctrl = devm_pinctrl_get(&client->dev);
if (IS_ERR(pdata->pinctrl))
input_err(true, &client->dev, "%s: could not get pinctrl\n", __func__);
#ifdef USE_POWER_RESET_WORK
INIT_DELAYED_WORK(&ts->reset_work, sec_ts_reset_work);
#endif
@ -1556,8 +1668,6 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i
}
ts->touch_count = 0;
ts->sec_ts_i2c_write = sec_ts_i2c_write;
ts->sec_ts_i2c_read = sec_ts_i2c_read;
ts->sec_ts_read_customlib = sec_ts_read_from_customlib;
ts->max_z_value = 0;
@ -1570,7 +1680,7 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i
mutex_init(&ts->eventlock);
mutex_init(&ts->modechange);
wake_lock_init(&ts->wakelock, WAKE_LOCK_SUSPEND, "tsp_wakelock");
wakeup_source_init(&ts->wakelock, "tsp_wakelock");
init_completion(&ts->resume_done);
complete_all(&ts->resume_done);
@ -1594,55 +1704,8 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i
input_info(true, &client->dev, "%s: power enable\n", __func__);
ret = sec_ts_i2c_read(ts, SEC_TS_READ_DEVICE_ID, deviceID, 5);
if (ret < 0)
input_err(true, &ts->client->dev, "%s: failed to read device ID(%d)\n", __func__, ret);
else
input_info(true, &ts->client->dev,
"%s: TOUCH DEVICE ID : %02X, %02X, %02X, %02X, %02X\n", __func__,
deviceID[0], deviceID[1], deviceID[2], deviceID[3], deviceID[4]);
ret = sec_ts_i2c_read(ts, SEC_TS_READ_FIRMWARE_INTEGRITY, &result, 1);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: failed to integrity check (%d)\n", __func__, ret);
} else {
if (result & 0x80) {
valid_firmware_integrity = true;
} else if (result & 0x40) {
valid_firmware_integrity = false;
input_err(true, &ts->client->dev, "%s: invalid firmware (0x%x)\n", __func__, result);
} else {
valid_firmware_integrity = false;
input_err(true, &ts->client->dev, "%s: invalid integrity result (0x%x)\n", __func__, result);
}
}
ret = sec_ts_i2c_read(ts, SEC_TS_READ_BOOT_STATUS, &data[0], 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read sub id(%d)\n",
__func__, ret);
} else {
ret = sec_ts_i2c_read(ts, SEC_TS_READ_TS_STATUS, &data[1], 4);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to touch status(%d)\n",
__func__, ret);
}
}
input_info(true, &ts->client->dev,
"%s: TOUCH STATUS : %02X || %02X, %02X, %02X, %02X\n",
__func__, data[0], data[1], data[2], data[3], data[4]);
if (data[0] == SEC_TS_STATUS_BOOT_MODE)
ts->checksum_result = 1;
if ((data[0] == SEC_TS_STATUS_APP_MODE && data[2] == TOUCH_SYSTEM_MODE_FLASH) ||
(valid_firmware_integrity == false))
force_update = true;
else
force_update = false;
sec_ts_read_hw_info(ts);
#if 0
#ifdef SEC_TS_FW_UPDATE_ON_PROBE
ret = sec_ts_firmware_update_on_probe(ts, force_update);
if (ret < 0)
@ -1650,8 +1713,8 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i
#else
input_info(true, &ts->client->dev, "%s: fw update on probe disabled!\n", __func__);
#endif
ret = sec_ts_read_information(ts);
#endif
ret = sec_ts_read_fw_info(ts);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: fail to read information 0x%x\n", __func__, ret);
goto err_init;
@ -1662,19 +1725,6 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i
if (ret < 0)
input_err(true, &ts->client->dev, "%s: Failed to send touch func_mode command", __func__);
/* Sense_on */
ret = sec_ts_i2c_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: fail to write Sense_on\n", __func__);
goto err_init;
}
ts->pFrame = kzalloc(ts->tx_count * ts->rx_count * 2, GFP_KERNEL);
if (!ts->pFrame) {
ret = -ENOMEM;
goto err_allocate_frame;
}
if (ts->plat_data->support_dex) {
ts->input_dev_pad->name = "sec_touchpad";
sec_ts_set_input_prop(ts, ts->input_dev_pad, INPUT_PROP_POINTER);
@ -1711,13 +1761,15 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i
goto err_irq;
}
/* prevent unbalanced irq enable */
ts->irq_enabled = true;
/* need remove below resource @ remove driver */
#if (1) //!defined(CONFIG_SAMSUNG_PRODUCT_SHIP)
#if 0 //!defined(CONFIG_SAMSUNG_PRODUCT_SHIP)
sec_ts_raw_device_init(ts);
#endif
sec_ts_fn_init(ts);
#ifdef SEC_TS_SUPPORT_CUSTOMLIB
sec_ts_check_custom_library(ts);
if (ts->use_customlib)
@ -1725,6 +1777,10 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i
#endif
ret = sec_mmi_data_init(ts, true);
if (ret)
goto err_mmi_data;
device_init_wakeup(&client->dev, true);
schedule_delayed_work(&ts->work_read_info, msecs_to_jiffies(50));
@ -1743,11 +1799,9 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i
return 0;
/* need to be enabled when new goto statement is added */
#if 0
err_mmi_data:
sec_ts_fn_remove(ts);
free_irq(client->irq, ts);
#endif
err_irq:
if (ts->plat_data->support_dex) {
input_unregister_device(ts->input_dev_pad);
@ -1759,9 +1813,8 @@ err_input_pad_register_device:
ts->input_dev_touch = NULL;
err_input_register_device:
kfree(ts->pFrame);
err_allocate_frame:
err_init:
wake_lock_destroy(&ts->wakelock);
wakeup_source_trash(&ts->wakelock);
sec_ts_power(ts, false);
if (ts->plat_data->support_dex) {
if (ts->input_dev_pad)
@ -1912,7 +1965,7 @@ static void sec_ts_reset_work(struct work_struct *work)
}
mutex_lock(&ts->modechange);
wake_lock(&ts->wakelock);
__pm_stay_awake(&ts->wakelock);
ts->reset_is_on_going = true;
input_info(true, &ts->client->dev, "%s\n", __func__);
@ -1929,12 +1982,12 @@ static void sec_ts_reset_work(struct work_struct *work)
schedule_delayed_work(&ts->reset_work, msecs_to_jiffies(TOUCH_RESET_DWORK_TIME));
mutex_unlock(&ts->modechange);
wake_unlock(&ts->wakelock);
__pm_relax(&ts->wakelock);
return;
}
if (ts->input_dev_touch->disabled) {
// FIXME:
// if (ts->input_dev_touch->disabled) {
input_err(true, &ts->client->dev , "%s: call input_close\n", __func__);
if (ts->lowpower_mode) {
@ -1945,7 +1998,7 @@ static void sec_ts_reset_work(struct work_struct *work)
cancel_delayed_work(&ts->reset_work);
schedule_delayed_work(&ts->reset_work, msecs_to_jiffies(TOUCH_RESET_DWORK_TIME));
mutex_unlock(&ts->modechange);
wake_unlock(&ts->wakelock);
__pm_relax(&ts->wakelock);
return;
}
} else {
@ -1961,7 +2014,7 @@ static void sec_ts_reset_work(struct work_struct *work)
data[i * 2 + 3] = (ts->rect_data[i] >> 8) & 0xFF;
}
disable_irq(ts->client->irq);
sec_ts_irq_enable(ts, false);
ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM, &data[0], 10);
if (ret < 0)
input_err(true, &ts->client->dev, "%s: Failed to write offset\n", __func__);
@ -1969,13 +2022,14 @@ static void sec_ts_reset_work(struct work_struct *work)
ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_CUSTOMLIB_NOTIFY_PACKET, NULL, 0);
if (ret < 0)
input_err(true, &ts->client->dev, "%s: Failed to send notify\n", __func__);
enable_irq(ts->client->irq);
sec_ts_irq_enable(ts, true);
}
}
// FIXME:
// }
ts->reset_is_on_going = false;
mutex_unlock(&ts->modechange);
wake_unlock(&ts->wakelock);
__pm_relax(&ts->wakelock);
}
#endif
@ -1989,9 +2043,9 @@ static void sec_ts_read_info_work(struct work_struct *work)
input_info(true, &ts->client->dev, "%s\n", __func__);
/* run self-test */
disable_irq(ts->client->irq);
sec_ts_irq_enable(ts, false);
execute_selftest(ts, false);
enable_irq(ts->client->irq);
sec_ts_irq_enable(ts, true);
input_info(true, &ts->client->dev, "%s: %02X %02X %02X %02X\n",
__func__, ts->ito_test[0], ts->ito_test[1]
@ -2184,7 +2238,7 @@ static int sec_ts_remove(struct i2c_client *client)
p_ghost_check = NULL;
#endif
device_init_wakeup(&client->dev, false);
wake_lock_destroy(&ts->wakelock);
wakeup_source_trash(&ts->wakelock);
ts->lowpower_mode = false;
ts->probe_done = false;
@ -2347,14 +2401,14 @@ err:
if (ret < 0)
input_err(true, &ts->client->dev, "%s: fail to write Sense_on\n", __func__);
enable_irq(ts->client->irq);
sec_ts_irq_enable(ts, true);
out:
mutex_unlock(&ts->device_mutex);
return ret;
}
#ifdef CONFIG_PM
#if defined(CONFIG_PM) && !defined(CONFIG_DRM)
static int sec_ts_pm_suspend(struct device *dev)
{
struct sec_ts_data *ts = dev_get_drvdata(dev);
@ -2381,7 +2435,7 @@ static const struct i2c_device_id sec_ts_id[] = {
{ },
};
#ifdef CONFIG_PM
#if defined(CONFIG_PM) && !defined(CONFIG_DRM)
static const struct dev_pm_ops sec_ts_dev_pm_ops = {
.suspend = sec_ts_pm_suspend,
.resume = sec_ts_pm_resume,
@ -2408,7 +2462,7 @@ static struct i2c_driver sec_ts_driver = {
#ifdef CONFIG_OF
.of_match_table = sec_ts_match_table,
#endif
#ifdef CONFIG_PM
#if defined(CONFIG_PM) && !defined(CONFIG_DRM)
.pm = &sec_ts_dev_pm_ops,
#endif
},
@ -2418,12 +2472,11 @@ static int __init sec_ts_init(void)
{
#ifdef CONFIG_BATTERY_SAMSUNG
if (lpcharge == 1) {
pr_err("%s %s: Do not load driver due to : lpm %d\n",
SECLOG, __func__, lpcharge);
pr_err("%s: Do not load driver due to : lpm %d\n", __func__, lpcharge);
return -ENODEV;
}
#endif
pr_err("%s %s\n", SECLOG, __func__);
pr_err("%s\n", __func__);
return i2c_add_driver(&sec_ts_driver);
}

View file

@ -23,7 +23,6 @@
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/sec_cmd.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@ -36,24 +35,38 @@
#include <linux/time.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/wakelock.h>
#include <linux/workqueue.h>
#include "sec_cmd.h"
#ifdef CONFIG_INPUT_BOOSTER
#include <linux/input/input_booster.h>
#endif
#ifndef ABS_MT_CUSTOM
#include "sec_custom.h"
#endif
#ifndef input_info
#define input_info(f, d, fmt, args...) dev_info(d, fmt ##args)
#define input_info(f, d, fmt, args...) dev_info(d, fmt, ##args)
#endif
#ifndef input_err
#define input_info(f, d, fmt, args...) dev_info(d, fmt ##args)
#define input_err(f, d, fmt, args...) dev_err(d, fmt, ##args)
#endif
#ifndef input_dbg
#define input_dbg(f, d, fmt, args...) dev_dbg(d, fmt, ##args)
#endif
#ifndef input_raw_info
#define input_raw_info(f, d, fmt, args...) dev_info(d, fmt, ##args)
#endif
#define SEC_TS_I2C_NAME "sec_ts"
#define SEC_TS_DEVICE_NAME "SEC_TS"
#undef USE_EXTRA_INPUT_FEATURES
#define USE_OPEN_CLOSE
#undef USE_RESET_DURING_POWER_ON
#undef USE_RESET_EXIT_LPM
@ -565,6 +578,7 @@ struct sec_ts_coordinate {
u8 left_event;
};
struct sec_mmi_data;
struct sec_ts_data {
u32 isr_pin;
@ -574,6 +588,7 @@ struct sec_ts_data {
u32 para_addr;
u32 flash_page_size;
u8 boot_ver[3];
u8 device_id[5];
struct device *dev;
struct i2c_client *client;
@ -622,7 +637,7 @@ struct sec_ts_data {
volatile bool reset_is_on_going;
#endif
struct completion resume_done;
struct wake_lock wakelock;
struct wakeup_source wakelock;
struct sec_cmd_data sec;
short *pFrame;
@ -653,10 +668,8 @@ struct sec_ts_data {
int grip_landscape_edge;
u16 grip_landscape_deadzone;
#ifdef CONFIG_TOUCHSCREEN_DUMP_MODE
struct delayed_work ghost_check;
u8 tsp_dump_lock;
#endif
int nv;
int cal_count;
@ -703,11 +716,16 @@ struct sec_ts_data {
int (*sec_ts_i2c_write_burst)(struct sec_ts_data *ts, u8 *data, int len);
int (*sec_ts_i2c_read_bulk)(struct sec_ts_data *ts, u8 *data, int len);
int (*sec_ts_read_customlib)(struct sec_ts_data *ts, u8 *data, int len);
struct sec_mmi_data *mmi_ptr;
bool fw_invalid;
bool irq_enabled;
};
struct sec_ts_plat_data {
int max_x;
int max_y;
unsigned rst_gpio;
unsigned irq_gpio;
int irq_type;
int i2c_burstmax;
@ -773,6 +791,7 @@ int sec_ts_power(void *data, bool on);
int sec_ts_stop_device(struct sec_ts_data *ts);
int sec_ts_start_device(struct sec_ts_data *ts);
int sec_ts_set_lowpowermode(struct sec_ts_data *ts, u8 mode);
int sec_ts_firmware_update(struct sec_ts_data *ts, const u8 *data, size_t size, int bl_update, int restore_cal, int retry);
int sec_ts_firmware_update_on_probe(struct sec_ts_data *ts, bool force_update);
int sec_ts_firmware_update_on_hidden_menu(struct sec_ts_data *ts, int update_type);
int sec_ts_glove_mode_enables(struct sec_ts_data *ts, int mode);
@ -801,6 +820,8 @@ int execute_selftest(struct sec_ts_data *ts, bool save_result);
void sec_ts_run_rawdata_all(struct sec_ts_data *ts, bool full_read);
void sec_ts_reinit(struct sec_ts_data *ts);
void sec_ts_sense_on(struct sec_ts_data *ts);
void sec_ts_irq_enable(struct sec_ts_data *ts, bool on);
#if (1)//!defined(CONFIG_SAMSUNG_PRODUCT_SHIP)
@ -818,5 +839,10 @@ extern unsigned int lpcharge;
extern void set_grip_data_to_ic(struct sec_ts_data *ts, u8 flag);
extern void sec_ts_set_grip_type(struct sec_ts_data *ts, u8 set_type);
#ifndef input_log_fix
#define input_log_fix()
#endif
#ifndef input_raw_data_clear
#define input_raw_data_clear()
#endif
#endif

View file

@ -1480,11 +1480,11 @@ static void module_on_master(void *device_data)
int ret = 0;
ret = sec_ts_start_device(ts);
if (ts->input_dev->disabled) {
// FIXME
// if (ts->input_dev->disabled) {
sec_ts_set_lowpowermode(ts, TO_LOWPOWER_MODE);
ts->power_status = SEC_TS_STATE_LPM;
}
// }
if (ret == 0)
snprintf(buff, sizeof(buff), "%s", "OK");
@ -1550,7 +1550,7 @@ static void set_mis_cal_spec(void *device_data)
sec_cmd_set_default_result(sec);
if (ts->plat_data->mis_cal_check == 0) {
input_err(true, &ts->client->dev, "%s: [ERROR] not support, %d\n", __func__);
input_err(true, &ts->client->dev, "%s: [ERROR] not support\n", __func__);
goto NG;
} else if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
input_err(true, &ts->client->dev, "%s: [ERROR] Touch is stopped\n", __func__);
@ -1620,7 +1620,7 @@ static void get_mis_cal_info(void *device_data)
sec_cmd_set_default_result(sec);
if (ts->plat_data->mis_cal_check == 0) {
input_err(true, &ts->client->dev, "%s: [ERROR] not support, %d\n", __func__);
input_err(true, &ts->client->dev, "%s: [ERROR] not support\n", __func__);
mis_cal_data = 0xF1;
goto NG;
} else if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
@ -2461,7 +2461,7 @@ int get_tsp_nvm_data_by_size(struct sec_ts_data *ts, u8 offset, int length, u8 *
if (!buff)
return -ENOMEM;
input_info(true, &ts->client->dev, "%s: offset:%u, length:%d, size:%d\n", __func__, offset, length, sizeof(data));
input_info(true, &ts->client->dev, "%s: offset:%u, length:%d, size:%zu\n", __func__, offset, length, sizeof(data));
/* SENSE OFF -> CELAR EVENT STACK -> READ NV -> SENSE ON */
ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_SENSE_OFF, NULL, 0);
@ -3819,7 +3819,7 @@ void sec_ts_fn_remove(struct sec_ts_data *ts)
{
input_err(true, &ts->client->dev, "%s\n", __func__);
sysfs_delete_link(&ts->sec.fac_dev->kobj, &ts->input_dev->dev.kobj, "input");
sysfs_remove_link(&ts->sec.fac_dev->kobj, "input");
sysfs_remove_group(&ts->sec.fac_dev->kobj,
&cmd_attr_group);

View file

@ -571,7 +571,7 @@ err_write_fail:
return ret;
}
static int sec_ts_firmware_update(struct sec_ts_data *ts, const u8 *data,
int sec_ts_firmware_update(struct sec_ts_data *ts, const u8 *data,
size_t size, int bl_update, int restore_cal, int retry)
{
int i;

View file

@ -10,6 +10,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define DEBUG 511
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
@ -29,14 +32,12 @@
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include "sec_ts.h"
#include "sec_mmi.h"
/* MMI specific sysfs entries and API */
#define DEV_MMI (&data->i2c_client->dev)
#define DEV_TS (&ts->client->dev)
static inline ssize_t sec_mmi_store_error(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
static ssize_t sec_mmi_reset_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size);
static ssize_t sec_mmi_forcereflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size);
static ssize_t sec_mmi_doreflash_store(struct device *dev,
@ -45,7 +46,7 @@ static ssize_t sec_mmi_drv_irq_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size);
static ssize_t sec_mmi_drv_irq_show(struct device *dev,
struct device_attribute *attr, char *buf);
static inline ssize_t sec_mmi_show_error(struct device *dev,
static ssize_t sec_mmi_hw_irqstat_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t sec_mmi_ic_ver_show(struct device *dev,
struct device_attribute *attr, char *buf);
@ -58,14 +59,16 @@ static DEVICE_ATTR(drv_irq, (S_IWUSR | S_IWGRP | S_IRUGO), sec_mmi_drv_irq_show,
static DEVICE_ATTR(hw_irqstat, S_IRUGO, sec_mmi_hw_irqstat_show, NULL);
static DEVICE_ATTR(ic_ver, S_IRUGO, sec_mmi_ic_ver_show, NULL);
static DEVICE_ATTR(poweron, S_IRUGO, sec_mmi_poweron_show, NULL);
static DEVICE_ATTR(reset, (S_IWUSR | S_IWGRP), NULL, sec_mmi_reset_store);
static struct attribute *mmi_attributes[] = {
&dev_attr_sec_mmi_forcereflash.attr,
&dev_attr_sec_mmi_fdoreflash.attr,
&dev_attr_sec_mmi_drv_irq.attr,
&dev_attr_sec_mmi_hw_irqstat.attr,
&dev_attr_sec_mmi_ic_ver.attr,
&dev_attr_sec_mmi_poweron.attr,
&dev_attr_forcereflash.attr,
&dev_attr_doreflash.attr,
&dev_attr_drv_irq.attr,
&dev_attr_hw_irqstat.attr,
&dev_attr_ic_ver.attr,
&dev_attr_poweron.attr,
&dev_attr_reset.attr,
NULL,
};
@ -82,7 +85,7 @@ static ssize_t path_show(struct device *dev,
const char *path;
if (!data) {
dev_err(DEV_MMI "data pointer is NULL\n");
dev_err(DEV_MMI, "data pointer is NULL\n");
return (ssize_t)0;
}
path = kobject_get_path(&data->i2c_client->dev.kobj, GFP_KERNEL);
@ -107,7 +110,8 @@ static struct device_attribute class_attributes[] = {
static int sec_mmi_touchscreen_class(
struct sec_mmi_data *data, bool create)
{
struct device_attribute *attrs = touchscreen_attributes;
struct device_attribute *attrs = class_attributes;
bool unreg_class = false;
int i, error = 0;
const char *class_fname = "primary";
static struct class *touchscreen_class;
@ -119,8 +123,10 @@ static int sec_mmi_touchscreen_class(
if (minor < 0)
minor = input_get_new_minor(TSDEV_MINOR_BASE,
TSDEV_MINOR_MAX, true);
dev_info(DEV_MMI, "assigned minor %d\n", minor);
dev_dbg(DEV_MMI, "assigned minor %d\n", minor);
touchscreen_class = get_touchscreen_class_ptr();
dev_dbg(DEV_MMI, "class ptr %p\n", touchscreen_class);
if (!touchscreen_class) {
touchscreen_class = class_create(THIS_MODULE, "touchscreen");
if (IS_ERR(touchscreen_class)) {
@ -128,11 +134,14 @@ static int sec_mmi_touchscreen_class(
touchscreen_class = NULL;
return error;
}
set_touchscreen_class_ptr(touchscreen_class);
unreg_class = true;
}
if (data->class_entry_name)
class_fname = data->class_entry_name;
dev_dbg(DEV_MMI, "class entry name %s\n", class_fname);
data->ts_class_dev = device_create(touchscreen_class,
NULL, MKDEV(INPUT_MAJOR, minor), data, class_fname);
if (IS_ERR(data->ts_class_dev)) {
@ -143,8 +152,8 @@ static int sec_mmi_touchscreen_class(
dev_set_drvdata(data->ts_class_dev, data);
for (i = 0; class_attrs[i].attr.name != NULL; ++i) {
error = device_create_file(data->ts_class_dev, &class_attrs[i]);
for (i = 0; attrs[i].attr.name != NULL; ++i) {
error = device_create_file(data->ts_class_dev, &attrs[i]);
if (error)
break;
}
@ -155,10 +164,10 @@ static int sec_mmi_touchscreen_class(
if (!touchscreen_class || !data->ts_class_dev)
return -ENODEV;
dev_set_drvdata(rmi4_data->ts_class_dev, NULL);
dev_set_drvdata(data->ts_class_dev, NULL);
for (i = 0; class_attrs[i].attr.name != NULL; ++i)
device_remove_file(data->ts_class_dev, &class_attrs[i]);
for (i = 0; attrs[i].attr.name != NULL; ++i)
device_remove_file(data->ts_class_dev, &attrs[i]);
device_unregister(data->ts_class_dev);
data->ts_class_dev = NULL;
@ -168,15 +177,202 @@ static int sec_mmi_touchscreen_class(
device_destroy:
for (--i; i >= 0; --i)
device_remove_file(data->ts_class_dev, &class_attrs[i]);
device_remove_file(data->ts_class_dev, &attrs[i]);
device_destroy(touchscreen_class, MKDEV(INPUT_MAJOR, minor));
data->ts_class_dev = NULL;
class_unregister(touchscreen_class);
if (unreg_class)
class_unregister(touchscreen_class);
touchscreen_class = NULL;
dev_err(DEV_MMI, "%s: error creating touchscreen class attrs\n", __func__);
return -ENODEV;
}
static int sec_mmi_dt(struct sec_mmi_data *data)
{
struct device *dev = &data->i2c_client->dev;
struct device_node *np = dev->of_node;
if (!of_property_read_string(np, "sec,class-entry-name", &data->class_entry_name))
input_info(true, dev, "%s: class-entry-name property %s\n",
__func__, data->class_entry_name);
if (!of_property_read_string(np, "sec,bound-display", &data->bound_display))
input_info(true, dev, "%s: bound-display property %s\n",
__func__, data->bound_display);
if (!of_property_read_u32(np, "sec,control-dsi", &data->ctrl_dsi))
input_info(true, dev, "%s: ctrl-dsi property %d\n",
__func__, data->ctrl_dsi);
return 0;
}
static inline void batohui(unsigned int *dest, unsigned char *src, size_t size)
{
int si = size;
*dest = 0;
for (; --si >= 0;)
*dest += src[si] << (si << 3);
}
static void sec_mmi_fw_read_id(struct sec_mmi_data *data)
{
struct sec_ts_data *ts = data->ts_ptr;
unsigned char buffer[8];
int ret;
ret = ts->sec_ts_i2c_read(ts, SEC_TS_READ_FW_VERSION, buffer, sizeof(buffer));
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read fw version (%d)\n",
__func__, ret);
} else {
batohui(&data->build_id, buffer, sizeof(data->build_id));
dev_dbg(DEV_MMI, "%s: FW VERSION: " \
"%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n",
__func__, buffer[0], buffer[1], buffer[2], buffer[3],
buffer[4], buffer[5], buffer[6], buffer[7]);
}
memset(buffer, 0, sizeof(buffer));
ret = ts->sec_ts_i2c_read(ts, SEC_TS_READ_PARA_VERSION, buffer, sizeof(buffer));
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read fw version (%d)\n",
__func__, ret);
} else {
batohui(&data->config_id, buffer, sizeof(data->config_id));
dev_dbg(DEV_MMI, "%s: CONFIG VER: " \
"%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n",
__func__, buffer[0], buffer[1], buffer[2], buffer[3],
buffer[4], buffer[5], buffer[6], buffer[7]);
}
memset(buffer, 0, sizeof(buffer));
ret = ts->sec_ts_i2c_read(ts, SEC_TS_READ_IMG_VERSION, buffer, sizeof(buffer));
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read fw version (%d)\n",
__func__, ret);
} else {
batohui(&data->config_id, buffer, sizeof(data->config_id));
dev_dbg(DEV_MMI, "%s: IMAGE VER: " \
"%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n",
__func__, buffer[0], buffer[1], buffer[2], buffer[3],
buffer[4], buffer[5], buffer[6], buffer[7]);
}
}
static void sec_mmi_ic_reset(struct sec_mmi_data *data)
{
struct sec_ts_data *ts = data->ts_ptr;
if (!gpio_is_valid(ts->plat_data->rst_gpio) ||
!gpio_get_value(ts->plat_data->rst_gpio))
return;
mutex_lock(&ts->modechange);
__pm_stay_awake(&ts->wakelock);
gpio_set_value(ts->plat_data->rst_gpio, 0);
usleep_range(10, 10);
gpio_set_value(ts->plat_data->rst_gpio, 1);
sec_ts_wait_for_ready(ts, SEC_TS_ACK_BOOT_COMPLETE);
mutex_unlock(&ts->modechange);
__pm_relax(&ts->wakelock);
dev_dbg(DEV_MMI, "%s: hw reset done\n", __func__);
}
static void sec_mmi_wait4idle(struct sec_mmi_data *data)
{
struct sec_ts_data *ts = data->ts_ptr;
unsigned long start_wait_jiffies = jiffies;
do {
if (!ts->wakelock.active)
break;
usleep_range(1000, 1000);
} while (1);
if ((jiffies - start_wait_jiffies))
dev_info(DEV_MMI, "%s: entering suspend delayed for %ums\n",
__func__, jiffies_to_msecs(jiffies - start_wait_jiffies));
}
static void sec_mmi_work(struct work_struct *w)
{
struct delayed_work *dw =
container_of(w, struct delayed_work, work);
struct sec_mmi_data *data =
container_of(dw, struct sec_mmi_data, detection_work);
struct sec_ts_data *ts = data->ts_ptr;
int probe_status;
bool panel_ready = true;
char *pname = NULL;
#if defined(CONFIG_DRM)
/* DRM panel status */
panel_ready = dsi_display_is_panel_enable(data->ctrl_dsi,
&probe_status, &pname);
dev_dbg(DEV_MMI, "%s: drm: probe=%d, enable=%d, panel'%s'\n",
__func__, probe_status, panel_ready, pname);
/* check if bound panel is not present */
if (pname && strstr(pname, "dummy")) {
dev_info(DEV_MMI, "%s: dummy panel detected\n", __func__);
//rmi4_data->drm_state = DRM_ST_TERM;
} else if (panel_ready) {
dev_dbg(DEV_MMI, "%s: panel ready\n", __func__);
//rmi4_data->drm_state = DRM_ST_READY;
}
#endif
if (!ts->fw_invalid) {
sec_ts_sense_on(ts);
dev_dbg(DEV_MMI, "%s: sensing turned on\n", __func__);
sec_mmi_fw_read_id(data);
}
}
static void sec_mmi_queued_resume(struct work_struct *w)
{
struct delayed_work *dw =
container_of(w, struct delayed_work, work);
struct sec_mmi_data *data =
container_of(dw, struct sec_mmi_data, resume_work);
struct sec_ts_data *ts = data->ts_ptr;
if (ts->lowpower_mode)
complete_all(&ts->resume_done);
dev_dbg(DEV_MMI, "%s: touch resumed\n", __func__);
}
static int inline sec_mmi_display_on(struct sec_mmi_data *data)
{
/* schedule_delayed_work returns true if work has been scheduled */
/* and false otherwise, thus return 0 on success to comply POSIX */
return schedule_delayed_work(&data->resume_work, 0) == false;
}
static int inline sec_mmi_display_off(struct sec_mmi_data *data)
{
struct sec_ts_data *ts = data->ts_ptr;
cancel_delayed_work_sync(&data->resume_work);
sec_mmi_wait4idle(data);
if (ts->lowpower_mode)
reinit_completion(&ts->resume_done);
dev_dbg(DEV_MMI, "%s: touch suspended\n", __func__);
return 0;
}
static int sec_mmi_panel_cb(struct notifier_block *nb,
unsigned long event, void *evd)
{
@ -202,9 +398,9 @@ static int sec_mmi_panel_cb(struct notifier_block *nb,
if (event == MSM_DRM_EARLY_EVENT_BLANK) {
if (*blank != MSM_DRM_BLANK_POWERDOWN)
return 0;
synaptics_dsx_display_off(&data->i2c_client->dev);
sec_mmi_display_off(data);
} else if (*blank == MSM_DRM_BLANK_UNBLANK) {
synaptics_dsx_display_on(&data->i2c_client->dev);
sec_mmi_display_on(data);
}
}
@ -240,14 +436,70 @@ static ssize_t sec_mmi_poweron_show(struct device *dev,
ts->power_status != SEC_TS_STATE_POWER_OFF);
}
static ssize_t sec_mmi_hw_irqstat_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_ts_data *ts = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%d\n",
ts->power_status != SEC_TS_STATE_POWER_OFF);
}
static ssize_t sec_mmi_drv_irq_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_ts_data *ts = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%s\n",
ts->irq_enabled ? "ENABLED" : "DISABLED");
}
static ssize_t sec_mmi_drv_irq_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct sec_ts_data *ts = dev_get_drvdata(dev);
unsigned long value = 0;
int err = 0;
err = kstrtoul(buf, 10, &value);
if (err < 0) {
dev_err(DEV_TS, "%s: Failed to convert value\n", __func__);
return -EINVAL;
}
switch (value) {
case 0: /* Disable irq */
sec_ts_irq_enable(ts, false);
break;
case 1: /* Enable irq */
sec_ts_irq_enable(ts, true);
break;
default:
dev_err(DEV_TS, "%s: invalid value\n", __func__);
return -EINVAL;
}
return size;
}
static ssize_t sec_mmi_reset_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct sec_ts_data *ts = dev_get_drvdata(dev);
sec_mmi_ic_reset(ts->mmi_ptr);
return 0;
}
static ssize_t sec_mmi_ic_ver_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_ts_data *ts = dev_get_drvdata(dev);
struct sec_mmi_data *data = ts->mmi_ptr;
return scnprintf(buf, PAGE_SIZE, "%s%s\n%s%x\n%s%x\n",
"Product ID: ", rmi->product_id_string,
"Build ID: ", build_id,
"Config ID: ", config_id);
"Product ID: ", data->product_id,
"Build ID: ", data->build_id,
"Config ID: ", data->config_id);
}
static ssize_t sec_mmi_forcereflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
return 0;
}
static ssize_t sec_mmi_doreflash_store(struct device *dev,
@ -259,9 +511,7 @@ static ssize_t sec_mmi_doreflash_store(struct device *dev,
int result = -1;
if (size > SEC_TS_MAX_FW_PATH) {
dev_err(&rmi4_data->i2c_client->dev,
"%s: FW filename is too long\n",
__func__);
dev_err(DEV_TS, "%s: FW filename is too long\n", __func__);
return -EINVAL;
}
@ -285,135 +535,90 @@ err_request_fw:
return result;
}
static ssize_t sec_ts_regreadsize_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
static void sec_mmi_sysfs(struct sec_mmi_data *data, bool enable)
{
struct sec_ts_data *ts = dev_get_drvdata(dev);
struct sec_ts_data *ts = data->ts_ptr;
mutex_lock(&ts->device_mutex);
if (enable) {
int ret;
lv1cmd = buf[0];
lv1_readsize = ((unsigned int)buf[4] << 24) |
((unsigned int)buf[3] << 16) | ((unsigned int) buf[2] << 8) | ((unsigned int)buf[1] << 0);
lv1_readoffset = 0;
lv1_readremain = 0;
mutex_unlock(&ts->device_mutex);
return size;
ret = sysfs_create_group(&ts->dev->kobj, &mmi_attr_group);
if (ret < 0) {
input_err(true, DEV_TS,
"%s: Failed to create MMI sysfs attributes\n", __func__);
}
} else
sysfs_remove_group(&ts->dev->kobj, &mmi_attr_group);
}
static ssize_t sec_ts_enter_recovery_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
int sec_mmi_data_init(struct sec_ts_data *ts, bool enable)
{
struct sec_ts_data *ts = dev_get_drvdata(dev);
struct sec_ts_plat_data *pdata = ts->plat_data;
int ret;
unsigned long on;
struct sec_mmi_data *data;
ret = kstrtoul(buf, 10, &on);
if (ret != 0) {
input_err(true, &ts->client->dev, "%s: failed to read:%d\n",
__func__, ret);
return -EINVAL;
if (enable)
data = kzalloc(sizeof(*data), GFP_KERNEL);
else
data = ts->mmi_ptr;
if (!data) {
input_err(true, DEV_TS, "%s: MMI data is NULL\n", __func__);
return 0;
}
if (on == 1) {
disable_irq(ts->client->irq);
gpio_free(pdata->irq_gpio);
if (enable) {
#if defined(CONFIG_DRM)
int probe_status;
bool panel_ready = true;
char *pname = NULL;
#endif
input_info(true, &ts->client->dev, "%s: gpio free\n", __func__);
if (gpio_is_valid(pdata->irq_gpio)) {
ret = gpio_request_one(pdata->irq_gpio, GPIOF_OUT_INIT_LOW, "sec,tsp_int");
input_info(true, &ts->client->dev, "%s: gpio request one\n", __func__);
if (ret < 0)
input_err(true, &ts->client->dev, "%s: Unable to request tsp_int [%d]: %d\n", __func__, pdata->irq_gpio, ret);
} else {
input_err(true, &ts->client->dev, "%s: Failed to get irq gpio\n", __func__);
return -EINVAL;
ts->mmi_ptr = (void *)data;
data->ts_ptr = ts;
data->i2c_client = ts->client;
data->hard_reset = sec_mmi_ic_reset;
sec_mmi_dt(data);
#if defined(CONFIG_DRM)
/* DRM panel status */
panel_ready = dsi_display_is_panel_enable(data->ctrl_dsi,
&probe_status, &pname);
input_info(true, DEV_TS, "%s: drm: probe=%d, enable=%d, panel'%s'\n",
__func__, probe_status, panel_ready, pname);
/* check panel binding */
if (data->bound_display && (probe_status == -ENODEV ||
(pname && strncmp(pname, data->bound_display,
strlen(data->bound_display))))) {
input_err(true, DEV_TS, "%s: panel binding failed\n", __func__);
return -ENODEV;
}
pdata->power(ts, false);
sec_ts_delay(100);
pdata->power(ts, true);
} else {
gpio_free(pdata->irq_gpio);
if (gpio_is_valid(pdata->irq_gpio)) {
ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN, "sec,tsp_int");
if (ret) {
input_err(true, &ts->client->dev, "%s: Unable to request tsp_int [%d]\n", __func__, pdata->irq_gpio);
return -EINVAL;
}
} else {
input_err(true, &ts->client->dev, "%s: Failed to get irq gpio\n", __func__);
return -EINVAL;
if (pname && strstr(pname, "dummy")) {
input_info(true, DEV_TS, "%s: dummy panel; exiting...\n", __func__);
return -ENODEV;
}
#endif
snprintf(data->product_id, sizeof(data->product_id), "%c%c%c%02x",
tolower(ts->device_id[0]), tolower(ts->device_id[1]),
ts->device_id[2], ts->device_id[3]);
pdata->power(ts, false);
sec_ts_delay(500);
pdata->power(ts, true);
sec_ts_delay(500);
INIT_DELAYED_WORK(&data->resume_work, sec_mmi_queued_resume);
INIT_DELAYED_WORK(&data->detection_work, sec_mmi_work);
/* AFE Calibration */
ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_CALIBRATION_AMBIENT, NULL, 0);
if (ret < 0)
input_err(true, &ts->client->dev, "%s: fail to write AFE_CAL\n", __func__);
sec_ts_delay(1000);
enable_irq(ts->client->irq);
schedule_delayed_work(&data->detection_work, msecs_to_jiffies(50));
}
sec_ts_read_information(ts);
sec_mmi_touchscreen_class(data, enable);
sec_mmi_register_notifier(data, enable);
sec_mmi_sysfs(data, enable);
return size;
}
static inline ssize_t sec_ts_show_error(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_ts_data *ts = dev_get_drvdata(dev);
input_err(true, &ts->client->dev, "%s: read only function, %s\n", __func__, attr->attr.name);
return -EPERM;
}
static inline ssize_t sec_ts_store_error(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct sec_ts_data *ts = dev_get_drvdata(dev);
input_err(true, &ts->client->dev, "%s: write only function, %s\n", __func__, attr->attr.name);
return -EPERM;
}
int sec_ts_raw_device_init(struct sec_ts_data *ts)
{
int ret;
struct class *sec_class = NULL;
sec_class = class_create(THIS_MODULE, "sec");
ret = IS_ERR_OR_NULL(sec_class);
if (ret) {
input_err(true, &ts->client->dev, "%s: fail - class_create\n", __func__);
return;
if (!enable) {
sec_mmi_sysfs(data, true);
cancel_delayed_work(&data->resume_work);
cancel_delayed_work(&data->detection_work);
kfree(data);
ts->mmi_ptr = NULL;
}
ts->dev = device_create(sec_class, NULL, 0, ts, "sec_ts");
ret = IS_ERR(ts->dev);
if (ret) {
input_err(true, &ts->client->dev, "%s: fail - device_create\n", __func__);
return ret;
}
ret = sysfs_create_group(&ts->dev->kobj, &cmd_attr_group);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: fail - sysfs_create_group\n", __func__);
goto err_sysfs;
}
return ret;
err_sysfs:
input_err(true, &ts->client->dev, "%s: fail\n", __func__);
return ret;
return 0;
}

View file

@ -271,7 +271,7 @@ int sec_ts_raw_device_init(struct sec_ts_data *ts)
ret = IS_ERR_OR_NULL(sec_class);
if (ret) {
input_err(true, &ts->client->dev, "%s: fail - class_create\n", __func__);
return;
return ret;
}
ts->dev = device_create(sec_class, NULL, 0, ts, "sec_ts");