514 lines
16 KiB
C
Executable file
514 lines
16 KiB
C
Executable file
/*
|
|
*
|
|
* FocalTech ftxxxx TouchScreen driver.
|
|
*
|
|
* Copyright (c) 2012-2020, Focaltech Ltd. All rights reserved.
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* File Name: focaltech_ex_mode.c
|
|
*
|
|
* Author: Focaltech Driver Team
|
|
*
|
|
* Created: 2016-08-31
|
|
*
|
|
* Abstract:
|
|
*
|
|
* Reference:
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* 1.Included header files
|
|
*****************************************************************************/
|
|
#include "focaltech_core.h"
|
|
|
|
/*****************************************************************************
|
|
* 2.Private constant and macro definitions using #define
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* 4.Static variables
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* 5.Global variable or extern global variabls/functions
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* 6.Static function prototypes
|
|
*******************************************************************************/
|
|
static int fts_ex_mode_set_reg(u8 mode_regaddr, u8 mode_regval)
|
|
{
|
|
int i = 0;
|
|
u8 val = 0xFF;
|
|
|
|
for (i = 0; i < FTS_MAX_RETRIES_WRITEREG; i++) {
|
|
fts_read_reg(mode_regaddr, &val);
|
|
if (val == mode_regval)
|
|
break;
|
|
fts_write_reg(mode_regaddr, mode_regval);
|
|
fts_msleep(1);
|
|
}
|
|
|
|
if (i >= FTS_MAX_RETRIES_WRITEREG) {
|
|
FTS_ERROR("set mode(%x) to %x failed,read val:%x", mode_regaddr, mode_regval, val);
|
|
return -EIO;
|
|
} else if (i > 0) {
|
|
FTS_INFO("set mode(%x) to %x successfully", mode_regaddr, mode_regval);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int fts_ex_mode_switch(enum _ex_mode mode, int value)
|
|
{
|
|
int ret = 0;
|
|
|
|
switch (mode) {
|
|
case MODE_GLOVE:
|
|
ret = fts_ex_mode_set_reg(FTS_REG_GLOVE_MODE_EN, (value ? 0x01 : 0x00));
|
|
if (ret) FTS_ERROR("Set MODE_GLOVE to %d failed", value);
|
|
break;
|
|
case MODE_COVER:
|
|
ret = fts_ex_mode_set_reg(FTS_REG_COVER_MODE_EN, (value ? 0x01 : 0x00));
|
|
if (ret) FTS_ERROR("Set MODE_COVER to %d failed", value);
|
|
break;
|
|
case MODE_CHARGER:
|
|
ret = fts_ex_mode_set_reg(FTS_REG_CHARGER_MODE_EN, (value ? 0x01 : 0x00));
|
|
if (ret) FTS_ERROR("Set MODE_CHARGER to %d failed", value);
|
|
break;
|
|
case MODE_EARPHONE:
|
|
ret = fts_ex_mode_set_reg(FTS_REG_EARPHONE_MODE_EN, (value ? 0x01 : 0x00));
|
|
if (ret) FTS_ERROR("Set MODE_EARPHONE to %d failed", value);
|
|
break;
|
|
case MODE_EDGEPALM:
|
|
/* FW defines the following values: 0:vertical, 1:horizontal, USB on the right,
|
|
* 2:horizontal, USB on the left
|
|
* If host set the value not defined above, you should have a transition.
|
|
*/
|
|
ret = fts_ex_mode_set_reg(FTS_REG_EDGEPALM_MODE_EN, (u8)value);
|
|
if (ret) FTS_ERROR("Set MODE_EDGEPALM to %d failed", value);
|
|
break;
|
|
default:
|
|
FTS_ERROR("mode(%d) unsupport", mode);
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
//drv Added glove function-pzp-20240817-start
|
|
struct fts_ts_data *glove_ts_data = NULL;
|
|
//drv Added glove function-pzp-20240817-end
|
|
static ssize_t fts_glove_mode_show(
|
|
struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
int count = 0;
|
|
u8 reg_addr = FTS_REG_GLOVE_MODE_EN;
|
|
u8 reg_val = 0;
|
|
struct fts_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
fts_read_reg(reg_addr, ®_val);
|
|
count = snprintf(buf + count, PAGE_SIZE, "Glove Mode:%s\n",
|
|
ts_data->glove_mode ? "On" : "Off");
|
|
count += snprintf(buf + count, PAGE_SIZE, "Glove Reg:0x%02x,val:%d\n", reg_addr, reg_val);
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t fts_glove_mode_store(
|
|
struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct fts_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
if (FTS_SYSFS_ECHO_ON(buf)) {
|
|
FTS_DEBUG("enter glove mode");
|
|
ts_data->glove_mode = ENABLE;
|
|
fts_ex_mode_switch(MODE_GLOVE, ENABLE);
|
|
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
|
|
FTS_DEBUG("exit glove mode");
|
|
ts_data->glove_mode = DISABLE;
|
|
fts_ex_mode_switch(MODE_GLOVE, DISABLE);
|
|
}
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
return count;
|
|
}
|
|
|
|
|
|
static ssize_t fts_cover_mode_show(
|
|
struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
int count = 0;
|
|
u8 reg_addr = FTS_REG_COVER_MODE_EN;
|
|
u8 reg_val = 0;
|
|
struct fts_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
fts_read_reg(reg_addr, ®_val);
|
|
count = snprintf(buf + count, PAGE_SIZE, "Cover Mode:%s\n",
|
|
ts_data->cover_mode ? "On" : "Off");
|
|
count += snprintf(buf + count, PAGE_SIZE, "Cover Reg:0x%02x,val:%d\n", reg_addr, reg_val);
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t fts_cover_mode_store(
|
|
struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct fts_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
if (FTS_SYSFS_ECHO_ON(buf)) {
|
|
FTS_DEBUG("enter cover mode");
|
|
ts_data->cover_mode = ENABLE;
|
|
fts_ex_mode_switch(MODE_COVER, ENABLE);
|
|
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
|
|
FTS_DEBUG("exit cover mode");
|
|
ts_data->cover_mode = DISABLE;
|
|
fts_ex_mode_switch(MODE_COVER, DISABLE);
|
|
}
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t fts_charger_mode_show(
|
|
struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
int count = 0;
|
|
u8 reg_addr = FTS_REG_CHARGER_MODE_EN;
|
|
u8 reg_val = 0;
|
|
struct fts_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
fts_read_reg(reg_addr, ®_val);
|
|
count = snprintf(buf + count, PAGE_SIZE, "Charger Mode:%s\n",
|
|
ts_data->charger_mode ? "On" : "Off");
|
|
count += snprintf(buf + count, PAGE_SIZE, "Charger Reg:0x%02x,val:%d\n", reg_addr, reg_val);
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t fts_charger_mode_store(
|
|
struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct fts_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
if (FTS_SYSFS_ECHO_ON(buf)) {
|
|
FTS_DEBUG("enter charger mode");
|
|
ts_data->charger_mode = ENABLE;
|
|
fts_ex_mode_switch(MODE_CHARGER, ENABLE);
|
|
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
|
|
FTS_DEBUG("exit charger mode");
|
|
ts_data->charger_mode = DISABLE;
|
|
fts_ex_mode_switch(MODE_CHARGER, DISABLE);
|
|
}
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
return count;
|
|
}
|
|
|
|
/* sysfs node: fts_earphone_mode */
|
|
static ssize_t fts_earphone_show(
|
|
struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
int count = 0;
|
|
u8 reg_addr = FTS_REG_EARPHONE_MODE_EN;
|
|
u8 reg_val = 0;
|
|
struct fts_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
fts_read_reg(reg_addr, ®_val);
|
|
count = snprintf(buf + count, PAGE_SIZE, "Earphone Mode:%s\n",
|
|
ts_data->earphone_mode ? "On" : "Off");
|
|
count += snprintf(buf + count, PAGE_SIZE, "Earphone Reg:0x%02x,val:%d\n", reg_addr, reg_val);
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t fts_earphone_store(
|
|
struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct fts_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
if (FTS_SYSFS_ECHO_ON(buf)) {
|
|
FTS_DEBUG("enter earphone mode");
|
|
ts_data->earphone_mode = ENABLE;
|
|
fts_ex_mode_switch(MODE_EARPHONE, ENABLE);
|
|
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
|
|
FTS_DEBUG("exit earphone mode");
|
|
ts_data->earphone_mode = DISABLE;
|
|
fts_ex_mode_switch(MODE_EARPHONE, DISABLE);
|
|
}
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
return count;
|
|
}
|
|
|
|
/* sysfs node: fts_edgepalm_mode */
|
|
static ssize_t fts_edgepalm_show(
|
|
struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
int count = 0;
|
|
u8 reg_addr = FTS_REG_EDGEPALM_MODE_EN;
|
|
u8 reg_val = 0;
|
|
struct fts_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
fts_read_reg(reg_addr, ®_val);
|
|
count = snprintf(buf + count, PAGE_SIZE, "Edgepalm Mode:%s,value:%d\n",
|
|
ts_data->edgepalm_mode ? "On" : "Off", ts_data->edgepalm_value);
|
|
count += snprintf(buf + count, PAGE_SIZE, "Edgepalm Reg:0x%02x,val:%d\n", reg_addr, reg_val);
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t fts_edgepalm_store(
|
|
struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int value = 0;
|
|
int n = 0;
|
|
struct fts_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
n = sscanf(buf, "%d", &value);
|
|
if (n == 1) {
|
|
ts_data->edgepalm_value = value;
|
|
ts_data->edgepalm_mode = !!value;
|
|
fts_ex_mode_switch(MODE_EDGEPALM, value);
|
|
}
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
return count;
|
|
}
|
|
|
|
|
|
/* read and write charger mode
|
|
* read example: cat fts_glove_mode ---read glove mode
|
|
* write example:echo 1 > fts_glove_mode ---write glove mode to 01
|
|
*/
|
|
static DEVICE_ATTR(fts_glove_mode, S_IRUGO | S_IWUSR, fts_glove_mode_show, fts_glove_mode_store);
|
|
static DEVICE_ATTR(fts_cover_mode, S_IRUGO | S_IWUSR, fts_cover_mode_show, fts_cover_mode_store);
|
|
static DEVICE_ATTR(fts_charger_mode, S_IRUGO | S_IWUSR, fts_charger_mode_show, fts_charger_mode_store);
|
|
static DEVICE_ATTR(fts_earphone_mode, S_IRUGO | S_IWUSR, fts_earphone_show, fts_earphone_store);
|
|
static DEVICE_ATTR(fts_edgepalm_mode, S_IRUGO | S_IWUSR, fts_edgepalm_show, fts_edgepalm_store);
|
|
|
|
static struct attribute *fts_touch_mode_attrs[] = {
|
|
&dev_attr_fts_glove_mode.attr,
|
|
&dev_attr_fts_cover_mode.attr,
|
|
&dev_attr_fts_charger_mode.attr,
|
|
&dev_attr_fts_earphone_mode.attr,
|
|
&dev_attr_fts_edgepalm_mode.attr,
|
|
NULL,
|
|
};
|
|
|
|
static struct attribute_group fts_touch_mode_group = {
|
|
.attrs = fts_touch_mode_attrs,
|
|
};
|
|
|
|
int fts_ex_mode_recovery(struct fts_ts_data *ts_data)
|
|
{
|
|
if (ts_data->glove_mode) {
|
|
fts_ex_mode_switch(MODE_GLOVE, ENABLE);
|
|
}
|
|
|
|
if (ts_data->cover_mode) {
|
|
fts_ex_mode_switch(MODE_COVER, ENABLE);
|
|
}
|
|
//drv-modify by shenwenbin for TP charger mode 20240304 start
|
|
#if FTS_CHARGER_MODE_EN
|
|
//FTS_INFO("ts_data->charger_status = %d;ts_data->charger_mode = %d",ts_data->charger_status,ts_data->charger_mode);
|
|
fts_ex_mode_switch(MODE_CHARGER, ts_data->charger_mode);
|
|
#else
|
|
if (ts_data->charger_mode) {
|
|
fts_ex_mode_switch(MODE_CHARGER, ENABLE);
|
|
}
|
|
#endif
|
|
//drv-modify by shenwenbin for TP charger mode 20240304 end
|
|
|
|
if (ts_data->earphone_mode) {
|
|
fts_ex_mode_switch(MODE_EARPHONE, ENABLE);
|
|
}
|
|
|
|
if (ts_data->edgepalm_mode) {
|
|
fts_ex_mode_switch(MODE_EDGEPALM, ts_data->edgepalm_value);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//drv Added glove function-pzp-20240817-start
|
|
#if 1
|
|
|
|
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
|
{
|
|
int count = 0;
|
|
u8 reg_addr = FTS_REG_GLOVE_MODE_EN;
|
|
u8 reg_val = 0;
|
|
struct fts_ts_data *ts_data = glove_ts_data;
|
|
|
|
if (!ts_data) {
|
|
pr_err("state_show: ts_data is NULL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
fts_read_reg(reg_addr, ®_val);
|
|
count = snprintf(buf, PAGE_SIZE, "Glove Mode:%s\n",
|
|
ts_data->glove_mode ? "On" : "Off");
|
|
count += snprintf(buf + count, PAGE_SIZE, "Glove Reg:0x%02x,val:%d\n", reg_addr, reg_val);
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct fts_ts_data *ts_data = glove_ts_data;
|
|
struct power_supply *psy = NULL;
|
|
union power_supply_propval online;
|
|
|
|
// Check if the touch panel is suspended
|
|
if (ts_data->suspended) {
|
|
FTS_INFO("Touch panel is suspended, returning without changing glove mode");
|
|
return count;
|
|
}
|
|
// Get power supply object by "mtk-master-charger"
|
|
psy = power_supply_get_by_name("mtk-master-charger");
|
|
|
|
if (!psy) {
|
|
// FTS_ERROR("Couldn't get power supply\n");
|
|
return count;
|
|
}
|
|
// Get POWER_SUPPLY_PROP_ONLINE property
|
|
if (power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online) < 0) {
|
|
// FTS_ERROR("Couldn't get power supply online property\n");
|
|
power_supply_put(psy); // Release power supply object
|
|
return count;
|
|
}
|
|
power_supply_put(psy); // Release power supply object
|
|
|
|
if (!ts_data) {
|
|
pr_err("state_store: ts_data is NULL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
if (FTS_SYSFS_ECHO_ON(buf)) {
|
|
FTS_DEBUG("enter glove mode");
|
|
ts_data->glove_mode = ENABLE;
|
|
ts_data->prev_glove_mode = ENABLE; // Update prev_glove_mode to reflect the manual change
|
|
if (!online.intval) {
|
|
fts_ex_mode_switch(MODE_GLOVE, ENABLE);
|
|
}
|
|
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
|
|
FTS_DEBUG("exit glove mode");
|
|
ts_data->glove_mode = DISABLE;
|
|
ts_data->prev_glove_mode = DISABLE; // Update prev_glove_mode to reflect the manual change
|
|
if (!online.intval) {
|
|
fts_ex_mode_switch(MODE_GLOVE, DISABLE);
|
|
}
|
|
}
|
|
mutex_unlock(&ts_data->input_dev->mutex);
|
|
|
|
return count;
|
|
}
|
|
|
|
static struct kobj_attribute state_attribute = __ATTR(state, 0664, state_show, state_store);
|
|
|
|
static int fts_glove_mode_sysfs_init(void)
|
|
{
|
|
int error = 0;
|
|
struct kobject *common_node_kobj;
|
|
static struct kobject *prize_kobj;
|
|
static struct kobject *smartcover_kobj;
|
|
// Create /sys/kernel/prize
|
|
prize_kobj = kobject_create_and_add("prize", kernel_kobj);
|
|
if (!prize_kobj)
|
|
return error;
|
|
|
|
// Create /sys/kernel/prize/smartcover
|
|
smartcover_kobj = kobject_create_and_add("smartcover", prize_kobj);
|
|
if (!smartcover_kobj) {
|
|
kobject_put(prize_kobj);
|
|
return error;
|
|
}
|
|
|
|
// Create /sys/kernel/prize/smartcover/common_node
|
|
common_node_kobj = kobject_create_and_add("common_node", smartcover_kobj);
|
|
if (!common_node_kobj) {
|
|
kobject_put(smartcover_kobj);
|
|
kobject_put(prize_kobj);
|
|
return error;
|
|
}
|
|
|
|
// Create /sys/kernel/prize/smartcover/common_node/state
|
|
error = sysfs_create_file(common_node_kobj, &state_attribute.attr);
|
|
if (error) {
|
|
kobject_put(common_node_kobj);
|
|
kobject_put(smartcover_kobj);
|
|
kobject_put(prize_kobj);
|
|
return error;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#endif
|
|
//drv Added glove function-pzp-20240817-end
|
|
int fts_ex_mode_init(struct fts_ts_data *ts_data)
|
|
{
|
|
int ret = 0;
|
|
|
|
ts_data->glove_mode = DISABLE;
|
|
ts_data->cover_mode = DISABLE;
|
|
ts_data->charger_mode = DISABLE;
|
|
ts_data->earphone_mode = DISABLE;
|
|
ts_data->edgepalm_mode = DISABLE;
|
|
glove_ts_data = ts_data;////drv Added glove function-pzp-20240817-start
|
|
ret = sysfs_create_group(&ts_data->dev->kobj, &fts_touch_mode_group);
|
|
if (ret < 0) {
|
|
FTS_ERROR("create sysfs(ex_mode) fail");
|
|
sysfs_remove_group(&ts_data->dev->kobj, &fts_touch_mode_group);
|
|
return ret;
|
|
} else {
|
|
FTS_DEBUG("create sysfs(ex_mode) successfully");
|
|
}
|
|
//drv Added glove function-pzp-20240817-start
|
|
#if 1
|
|
|
|
fts_glove_mode_sysfs_init();
|
|
#endif
|
|
//drv Added glove function-pzp-20240817-start
|
|
return 0;
|
|
}
|
|
|
|
int fts_ex_mode_exit(struct fts_ts_data *ts_data)
|
|
{
|
|
sysfs_remove_group(&ts_data->dev->kobj, &fts_touch_mode_group);
|
|
return 0;
|
|
}
|