650 lines
18 KiB
C
650 lines
18 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#define LOG_TAG "Earjack"
|
|
|
|
#include "cts_config.h"
|
|
#include "cts_platform.h"
|
|
#include "cts_core.h"
|
|
#include "cts_sysfs.h"
|
|
#include "cts_strerror.h"
|
|
|
|
#ifdef CONFIG_CTS_EARJACK_DETECT
|
|
struct cts_earjack_detect_data {
|
|
bool enable;
|
|
bool running;
|
|
bool state;
|
|
|
|
const char *earjack_state_filepath;
|
|
struct delayed_work poll_work;
|
|
u32 poll_interval;
|
|
|
|
#ifdef CONFIG_CTS_SYSFS
|
|
bool sysfs_attr_group_created;
|
|
#endif /* CONFIG_CTS_SYSFS */
|
|
|
|
struct chipone_ts_data *cts_data;
|
|
};
|
|
|
|
/* Over-ride setting for DTS */
|
|
//#define CFG_CTS_DEF_EARJACK_DET_ENABLE
|
|
|
|
#define CFG_CTS_DEF_EARJACK_POLL_INTERVAL 2000u
|
|
#if defined(CONFIG_MTK_PLATFORM)
|
|
#define CFG_CTS_DEF_EARJACK_STATE_FILEPATH \
|
|
"/sys/bus/platform/drivers/Accdet_Driver/state"
|
|
#elif defined(CONFIG_ARCH_SPREADRUM)
|
|
#define CFG_CTS_DEF_EARJACK_STATE_FILEPATH \
|
|
"/sys/kernel/headset/state"
|
|
#else
|
|
/* Current QCOM NOT support earjack detect, please disable it or define the file path */
|
|
#define CFG_CTS_DEF_EARJACK_STATE_FILEPATH ""
|
|
#endif
|
|
|
|
static const char *earjack_state_str(bool state)
|
|
{
|
|
return state ? "ATTACHED" : "DETACHED";
|
|
}
|
|
|
|
static int parse_earjack_detect_dt(struct cts_earjack_detect_data *ed_data,
|
|
struct device_node *np)
|
|
{
|
|
const char *filepath;
|
|
int ret;
|
|
|
|
cts_info("Parse dt");
|
|
|
|
#ifdef CFG_CTS_DEF_EARJACK_DET_ENABLE
|
|
ed_data->enable = true;
|
|
#else /* CFG_CTS_DEF_EARJACK_DET_ENABLE */
|
|
ed_data->enable =
|
|
of_property_read_bool(np, "chipone,touch-earjack-detect-enable");
|
|
#endif /* CFG_CTS_DEF_EARJACK_DET_ENABLE */
|
|
|
|
ret = of_property_read_string(np,
|
|
"chipone,touch-earjack-state-filepath", &filepath);
|
|
if (ret) {
|
|
cts_warn("Parse state filepath failed %d(%s)", ret, cts_strerror(ret));
|
|
filepath = CFG_CTS_DEF_EARJACK_STATE_FILEPATH;
|
|
}
|
|
ed_data->earjack_state_filepath = kstrdup(filepath, GFP_KERNEL);
|
|
if (ed_data->earjack_state_filepath == NULL) {
|
|
cts_err("Dup earjack state filepath failed");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ed_data->poll_interval = CFG_CTS_DEF_EARJACK_POLL_INTERVAL;
|
|
ret = of_property_read_u32(np,
|
|
"chipone,touch-earjack-poll-interval", &ed_data->poll_interval);
|
|
if (ret) {
|
|
cts_warn("Parse poll interval failed %d(%s)", ret, cts_strerror(ret));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int start_earjack_detect(struct cts_earjack_detect_data *ed_data)
|
|
{
|
|
if (!ed_data->enable) {
|
|
cts_warn("Start detect while NOT enabled");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (ed_data->running) {
|
|
cts_warn("Start detect while already RUNNING");
|
|
return 0;
|
|
}
|
|
|
|
if (ed_data->earjack_state_filepath == NULL ||
|
|
ed_data->earjack_state_filepath[0] == '\n') {
|
|
cts_warn("Start detect with filepath = NULL/NUL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
cts_info("Start detect check file: '%s'", ed_data->earjack_state_filepath);
|
|
|
|
if (!queue_delayed_work(ed_data->cts_data->workqueue,
|
|
&ed_data->poll_work,
|
|
msecs_to_jiffies(ed_data->poll_interval))) {
|
|
cts_warn("Queue detect work while already on the queue");
|
|
}
|
|
|
|
ed_data->running = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int stop_earjack_detect(struct cts_earjack_detect_data *ed_data)
|
|
{
|
|
if (!ed_data->running) {
|
|
cts_warn("Stop detect while NOT running");
|
|
return 0;
|
|
}
|
|
|
|
cts_info("Stop detect");
|
|
|
|
if (!cancel_delayed_work_sync(&ed_data->poll_work)) {
|
|
cts_warn("Cancel poll work while NOT pending");
|
|
}
|
|
ed_data->running = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int get_earjack_state(struct cts_earjack_detect_data *ed_data)
|
|
{
|
|
int ret;
|
|
char buff[10];
|
|
u32 state;
|
|
#ifndef CFG_CTS_FOR_GKI
|
|
struct file *file = NULL;
|
|
loff_t pos = 0;
|
|
int read_size;
|
|
#endif
|
|
|
|
cts_dbg("Get state from file '%s'", ed_data->earjack_state_filepath);
|
|
|
|
#ifdef CFG_CTS_FOR_GKI
|
|
cts_info("%s(): filp_open is forbiddon with GKI Version!", __func__);
|
|
#else
|
|
file = filp_open(ed_data->earjack_state_filepath, O_RDONLY, 0);
|
|
if (IS_ERR(file)) {
|
|
ret = (int)PTR_ERR(file);
|
|
cts_err("Open file '%s' failed %d(%s)",
|
|
ed_data->earjack_state_filepath, ret, cts_strerror(ret));
|
|
return PTR_ERR(file);
|
|
}
|
|
|
|
memset(buff, 0, sizeof(buff));
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
|
|
read_size = kernel_read(file, buff, sizeof(buff), &pos);
|
|
#else
|
|
read_size = kernel_read(file, pos, buff, sizeof(buff));
|
|
#endif
|
|
if (read_size < 0) {
|
|
cts_err("Read state file '%s' failed %d(%s)",
|
|
ed_data->earjack_state_filepath,
|
|
read_size, cts_strerror(read_size));
|
|
filp_close(file, NULL);
|
|
return read_size;
|
|
}
|
|
|
|
cts_dbg("Read state file content: '%s'", buff);
|
|
|
|
ret = filp_close(file, NULL);
|
|
if (ret) {
|
|
cts_warn("Close file '%s' failed %d(%s)",
|
|
ed_data->earjack_state_filepath, ret, cts_strerror(ret));
|
|
}
|
|
#endif
|
|
|
|
ret = kstrtou32(buff, 0, &state);
|
|
if (ret) {
|
|
cts_err("Invalid string from state file: '%s'", buff);
|
|
return ret;
|
|
}
|
|
|
|
/* Assume "0" means detached */
|
|
ed_data->state = !!state;
|
|
|
|
cts_dbg("State: %s", earjack_state_str(ed_data->state));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Sysfs */
|
|
#ifdef CONFIG_CTS_SYSFS
|
|
|
|
#define EARJACK_DET_SYSFS_GROUP_NAME "earjack-det"
|
|
|
|
static int enable_earjack_detect(struct cts_earjack_detect_data *ed_data)
|
|
{
|
|
cts_info("Enable detect");
|
|
|
|
ed_data->enable = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int disable_earjack_detect(struct cts_earjack_detect_data *ed_data)
|
|
{
|
|
int ret;
|
|
|
|
cts_info("Disable detect");
|
|
|
|
ret = stop_earjack_detect(ed_data);
|
|
if (ret) {
|
|
cts_err("Stop detect failed %d(%s)", ret, cts_strerror(ret));
|
|
}
|
|
|
|
ed_data->enable = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t earjack_detect_enable_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
|
|
struct cts_earjack_detect_data *ed_data = cts_data->earjack_detect_data;
|
|
|
|
cts_info("Read sysfs '"EARJACK_DET_SYSFS_GROUP_NAME"/%s'", attr->attr.name);
|
|
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Earjack detect: %s\n",
|
|
ed_data->enable ? "ENABLED" : "DISABLED");
|
|
}
|
|
|
|
/* Echo 0/n/N/of/Of/Of/OF/1/y/Y/on/oN/On/ON > enable */
|
|
static ssize_t earjack_detect_enable_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
|
|
struct cts_earjack_detect_data *ed_data = cts_data->earjack_detect_data;
|
|
bool enable;
|
|
int ret;
|
|
|
|
cts_info("Write sysfs '"EARJACK_DET_SYSFS_GROUP_NAME"/%s' size %zu",
|
|
attr->attr.name, count);
|
|
|
|
cts_parse_arg(buf, count);
|
|
|
|
if (cts_argc != 1) {
|
|
cts_err("Invalid num of args");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = kstrtobool(cts_argv[0], &enable);
|
|
if (ret) {
|
|
cts_err("Invalid param of enable");
|
|
return ret;
|
|
}
|
|
|
|
if (enable) {
|
|
ret = enable_earjack_detect(ed_data);
|
|
} else {
|
|
ret = disable_earjack_detect(ed_data);
|
|
}
|
|
if (ret) {
|
|
cts_err("%s earjack detect failed %d(%s)",
|
|
enable ? "Enable" : "Disable", ret, cts_strerror(ret));
|
|
return ret;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
|
|
earjack_detect_enable_show, earjack_detect_enable_store);
|
|
|
|
static ssize_t earjack_detect_running_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
|
|
struct cts_earjack_detect_data *ed_data = cts_data->earjack_detect_data;
|
|
|
|
cts_info("Read sysfs '"EARJACK_DET_SYSFS_GROUP_NAME"/%s'",
|
|
attr->attr.name);
|
|
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Earjack detect: %sRunning\n",
|
|
ed_data->running ? "" : "Not-");
|
|
}
|
|
|
|
/* Echo 0/n/N/of/Of/Of/OF/1/y/Y/on/oN/On/ON > runing */
|
|
static ssize_t earjack_detect_running_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
|
|
struct cts_earjack_detect_data *ed_data = cts_data->earjack_detect_data;
|
|
bool running;
|
|
int ret;
|
|
|
|
cts_info("Write sysfs '"EARJACK_DET_SYSFS_GROUP_NAME"/%s' size %zu",
|
|
attr->attr.name, count);
|
|
|
|
cts_parse_arg(buf, count);
|
|
|
|
if (cts_argc != 1) {
|
|
cts_err("Invalid num of args");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = kstrtobool(cts_argv[0], &running);
|
|
if (ret) {
|
|
cts_err("Invalid param of running");
|
|
return ret;
|
|
}
|
|
|
|
if (running) {
|
|
ret = start_earjack_detect(ed_data);
|
|
} else {
|
|
ret = stop_earjack_detect(ed_data);
|
|
}
|
|
if (ret) {
|
|
cts_err("%s earjack detect failed %d(%s)",
|
|
running ? "Start" : "Stop", ret, cts_strerror(ret));
|
|
return ret;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(running, S_IWUSR | S_IRUGO,
|
|
earjack_detect_running_show, earjack_detect_running_store);
|
|
|
|
static ssize_t earjack_state_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
|
|
struct cts_earjack_detect_data *ed_data = cts_data->earjack_detect_data;
|
|
int ret;
|
|
|
|
cts_info("Read sysfs '"EARJACK_DET_SYSFS_GROUP_NAME"/%s'",
|
|
attr->attr.name);
|
|
|
|
ret = get_earjack_state(ed_data);
|
|
if (ret) {
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Get earjack state failed %d(%s)\n",
|
|
ret, cts_strerror(ret));
|
|
}
|
|
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Earjack state: %s\n", earjack_state_str(ed_data->state));
|
|
}
|
|
static DEVICE_ATTR(state, S_IRUGO, earjack_state_show, NULL);
|
|
|
|
static ssize_t earjack_detect_param_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
|
|
struct cts_earjack_detect_data *ed_data = cts_data->earjack_detect_data;
|
|
|
|
cts_info("Read sysfs '"EARJACK_DET_SYSFS_GROUP_NAME"/%s'",
|
|
attr->attr.name);
|
|
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Filepath: '%s'\n"
|
|
"Poll int: %dms\n",
|
|
ed_data->earjack_state_filepath, ed_data->poll_interval);
|
|
}
|
|
|
|
/* echo filepath [interval] > param */
|
|
static ssize_t earjack_detect_param_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
|
|
struct cts_earjack_detect_data *ed_data = cts_data->earjack_detect_data;
|
|
u32 interval;
|
|
int ret;
|
|
|
|
cts_info("Write sysfs '"EARJACK_DET_SYSFS_GROUP_NAME"/%s' size %zu",
|
|
attr->attr.name, count);
|
|
|
|
cts_parse_arg(buf, count);
|
|
|
|
if (cts_argc < 1 || cts_argc > 2) {
|
|
cts_err("Invalid num of args");
|
|
return -EINVAL;
|
|
}
|
|
|
|
interval = ed_data->poll_interval;
|
|
if (cts_argc > 1) {
|
|
ret = kstrtou32(cts_argv[1], 0, &interval);
|
|
if (ret) {
|
|
cts_err("Arg interval is invalid");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
if (ed_data->earjack_state_filepath) {
|
|
kfree(ed_data->earjack_state_filepath);
|
|
}
|
|
ed_data->earjack_state_filepath = kstrdup(cts_argv[0], GFP_KERNEL);
|
|
if (ed_data->earjack_state_filepath == NULL) {
|
|
cts_err("Dup earjack state filepath failed");
|
|
return -ENOMEM;
|
|
}
|
|
ed_data->poll_interval = interval;
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(param, S_IWUSR | S_IRUGO,
|
|
earjack_detect_param_show, earjack_detect_param_store);
|
|
|
|
static struct attribute *earjack_detect_attrs[] = {
|
|
&dev_attr_enable.attr,
|
|
&dev_attr_running.attr,
|
|
&dev_attr_state.attr,
|
|
&dev_attr_param.attr,
|
|
NULL
|
|
};
|
|
|
|
static const struct attribute_group earjack_detect_attr_group = {
|
|
.name = EARJACK_DET_SYSFS_GROUP_NAME,
|
|
.attrs = earjack_detect_attrs,
|
|
};
|
|
#endif /* CONFIG_CTS_SYSFS */
|
|
|
|
static void poll_earjack_state_work(struct work_struct *work)
|
|
{
|
|
struct cts_earjack_detect_data *ed_data;
|
|
bool prev_state = false;
|
|
int ret;
|
|
|
|
cts_dbg("Poll earjack state work");
|
|
|
|
ed_data = container_of(to_delayed_work(work),
|
|
struct cts_earjack_detect_data, poll_work);
|
|
|
|
prev_state = ed_data->state;
|
|
|
|
ret = get_earjack_state(ed_data);
|
|
if (ret) {
|
|
cts_err("Get state failed %d(%s)", ret, cts_strerror(ret));
|
|
} else {
|
|
if (ed_data->state != prev_state) {
|
|
cts_info("State changed: %s -> %s",
|
|
earjack_state_str(prev_state),
|
|
earjack_state_str(ed_data->state));
|
|
|
|
cts_lock_device(&ed_data->cts_data->cts_dev);
|
|
ret = cts_set_dev_earjack_attached(
|
|
&ed_data->cts_data->cts_dev, ed_data->state);
|
|
cts_unlock_device(&ed_data->cts_data->cts_dev);
|
|
if (ret) {
|
|
cts_err("Set dev earjack attached to %s failed %d(%s)",
|
|
earjack_state_str(ed_data->state),
|
|
ret, cts_strerror(ret));
|
|
/* Set to previous state, try set again in next loop */
|
|
ed_data->state = prev_state;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!queue_delayed_work(ed_data->cts_data->workqueue,
|
|
&ed_data->poll_work,
|
|
msecs_to_jiffies(ed_data->poll_interval))) {
|
|
cts_warn("Queue detect work while already on the queue");
|
|
}
|
|
}
|
|
|
|
int cts_earjack_detect_init(struct chipone_ts_data *cts_data)
|
|
{
|
|
struct cts_earjack_detect_data *ed_data;
|
|
int ret = 0;
|
|
|
|
if (cts_data == NULL) {
|
|
cts_err("Init detect with cts_data = NULL");
|
|
return -EFAULT;
|
|
}
|
|
|
|
ed_data = kzalloc(sizeof(*ed_data), GFP_KERNEL);
|
|
if (ed_data == NULL) {
|
|
cts_err("Alloc earjack detect data failed");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
cts_info("Init detect");
|
|
|
|
#ifdef CONFIG_CTS_OF
|
|
ret = parse_earjack_detect_dt(ed_data, cts_data->device->of_node);
|
|
#else /* CONFIG_CTS_OF */
|
|
#ifdef CFG_CTS_DEF_EARJACK_DET_ENABLE
|
|
ed_data->enable = true;
|
|
#else /* CFG_CTS_DEF_EARJACK_DET_ENABLE */
|
|
ed_data->enable = false;
|
|
#endif /* CFG_CTS_DEF_EARJACK_DET_ENABLE */
|
|
ed_data->poll_interval = CFG_CTS_DEF_EARJACK_POLL_INTERVAL;
|
|
ed_data->earjack_state_filepath = kstrdup(
|
|
CFG_CTS_DEF_EARJACK_STATE_FILEPATH, GFP_KERNEL);
|
|
if (ed_data->earjack_state_filepath == NULL) {
|
|
cts_err("Dup earjack state filepath failed");
|
|
ret = -ENOMEM;
|
|
}
|
|
#endif /* CONFIG_CTS_OF */
|
|
if (ret) {
|
|
cts_err("Get detect param failed %d(%s)",
|
|
ret, cts_strerror(ret));
|
|
goto free_ed_data;
|
|
}
|
|
|
|
cts_info("Detect: %sABLED", ed_data->enable ? "EN" : "DIS");
|
|
cts_info(" Filepath: '%s'", ed_data->earjack_state_filepath);
|
|
cts_info(" Poll Int: %dms", ed_data->poll_interval);
|
|
|
|
INIT_DELAYED_WORK(&ed_data->poll_work, poll_earjack_state_work);
|
|
|
|
#ifdef CONFIG_CTS_SYSFS
|
|
cts_info("Create sysfs attr group '%s'", EARJACK_DET_SYSFS_GROUP_NAME);
|
|
ret = sysfs_create_group(&cts_data->device->kobj,
|
|
&earjack_detect_attr_group);
|
|
if (ret) {
|
|
cts_warn("Create sysfs attr group '%s' failed %d(%s)",
|
|
EARJACK_DET_SYSFS_GROUP_NAME, ret, cts_strerror(ret));
|
|
} else {
|
|
ed_data->sysfs_attr_group_created = true;
|
|
}
|
|
#endif /* CONFIG_CTS_SYSFS */
|
|
|
|
cts_data->earjack_detect_data = ed_data;
|
|
ed_data->cts_data = cts_data;
|
|
|
|
return 0;
|
|
|
|
free_ed_data:
|
|
kfree(ed_data);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_earjack_detect_deinit(struct chipone_ts_data *cts_data)
|
|
{
|
|
struct cts_earjack_detect_data *ed_data;
|
|
int ret;
|
|
|
|
if (cts_data == NULL) {
|
|
cts_err("Deinit detect with cts_data = NULL");
|
|
return -EFAULT;
|
|
}
|
|
|
|
ed_data = cts_data->earjack_detect_data;
|
|
if (ed_data == NULL) {
|
|
cts_warn("Deinit detect with earjack_detect_data = NULL");
|
|
return 0;
|
|
}
|
|
|
|
cts_info("Deinit detect");
|
|
|
|
if (ed_data->running) {
|
|
ret = stop_earjack_detect(ed_data);
|
|
if (ret) {
|
|
cts_err("Stop detect failed %d(%s)",
|
|
ret, cts_strerror(ret));
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_CTS_SYSFS
|
|
if (ed_data->sysfs_attr_group_created) {
|
|
cts_info("Remove sysfs attr group '%s'", EARJACK_DET_SYSFS_GROUP_NAME);
|
|
sysfs_remove_group(&cts_data->device->kobj, &earjack_detect_attr_group);
|
|
ed_data->sysfs_attr_group_created = false;
|
|
}
|
|
#endif /* CONFIG_CTS_SYSFS */
|
|
|
|
if(ed_data->earjack_state_filepath) {
|
|
kfree(ed_data->earjack_state_filepath);
|
|
ed_data->earjack_state_filepath = NULL;
|
|
}
|
|
|
|
kfree(ed_data);
|
|
cts_data->earjack_detect_data = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int cts_is_earjack_attached(struct chipone_ts_data *cts_data, bool *attached)
|
|
{
|
|
struct cts_earjack_detect_data *ed_data;
|
|
int ret;
|
|
|
|
if (cts_data == NULL) {
|
|
cts_err("Get state with cts_data = NULL");
|
|
return -EFAULT;
|
|
}
|
|
|
|
ed_data = cts_data->earjack_detect_data;
|
|
if (ed_data == NULL) {
|
|
cts_err("Get state with earjack_detect_data = NULL");
|
|
return -ENODEV;
|
|
}
|
|
|
|
ret = get_earjack_state(ed_data);
|
|
if (ret) {
|
|
cts_err("Get state failed %d(%s)", ret, cts_strerror(ret));
|
|
return ret;
|
|
}
|
|
|
|
cts_info("Get curr state: %s", earjack_state_str(ed_data->state));
|
|
|
|
*attached = ed_data->state;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int cts_start_earjack_detect(struct chipone_ts_data *cts_data)
|
|
{
|
|
struct cts_earjack_detect_data *ed_data;
|
|
|
|
if (cts_data == NULL) {
|
|
cts_err("Start detect with cts_data = NULL");
|
|
return -EFAULT;
|
|
}
|
|
|
|
ed_data = cts_data->earjack_detect_data;
|
|
if (ed_data == NULL) {
|
|
cts_err("Start detect with earjack_detect_data = NULL");
|
|
return -ENODEV;
|
|
}
|
|
|
|
return start_earjack_detect(ed_data);
|
|
}
|
|
|
|
int cts_stop_earjack_detect(struct chipone_ts_data *cts_data)
|
|
{
|
|
struct cts_earjack_detect_data *ed_data;
|
|
|
|
if (cts_data == NULL) {
|
|
cts_err("Stop detect with cts_data = NULL");
|
|
return -EFAULT;
|
|
}
|
|
|
|
ed_data = cts_data->earjack_detect_data;
|
|
if (ed_data == NULL) {
|
|
cts_err("Stop detect with earjack_detect_data = NULL");
|
|
return -ENODEV;
|
|
}
|
|
|
|
return stop_earjack_detect(ed_data);
|
|
}
|
|
#endif /* CONFIG_CTS_EARJACK_DETECT */
|
|
|