blob: 515e6a28f100337a812b8a72dbb0d2feca7095fc [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Sysfs APIs for Google Pixel devices.
*
* Copyright 2022 Google LLC.
*/
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "touch_apis.h"
struct touch_apis_data *apis;
static ssize_t fw_ver_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
char fw_ver[0x100];
int ret = 0;
if (apis->get_fw_version != NULL) {
ret = apis->get_fw_version(dev, fw_ver, 0x100);
if (ret < 0) {
ret = snprintf(buf, PAGE_SIZE, "error: %d\n", ret);
} else {
ret = snprintf(buf, PAGE_SIZE, "result: %s\n", fw_ver);
}
} else {
ret = snprintf(buf, PAGE_SIZE, "error: not support\n");
}
return ret;
}
static ssize_t help_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
char fw_ver[0x100];
int ret = 0;
char *help_str = "APIs\n"
" fw_ver\n"
" help\n"
" irq_enabled\n"
" list_scan_mode\n"
" ping\n"
" reset\n"
" scan_mode\n"
" sensing_enabled\n"
" wake_lock\n";
ret = snprintf(buf, PAGE_SIZE, help_str, fw_ver);
return ret;
}
static ssize_t irq_enabled_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int ret = 0;
if (apis->get_irq_enabled != NULL && apis->set_irq_enabled != NULL) {
ret = apis->get_irq_enabled(dev);
if (ret < 0) {
ret = snprintf(buf, PAGE_SIZE, "error: %d\n", ret);
} else {
ret = snprintf(buf, PAGE_SIZE, "result: %s\n",
ret ? "enabled" : "disabled");
}
} else {
ret = snprintf(buf, PAGE_SIZE, "error: not support\n");
}
return ret;
}
static ssize_t irq_enabled_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool enabled = false;
if (buf == NULL || count <= 0)
return -EINVAL;
if (strncmp(buf, "1", 1) == 0) {
enabled = true;
} else if (strncmp(buf, "0", 1) == 0) {
enabled = false;
} else {
return -EINVAL;
}
if (apis->set_irq_enabled != NULL) {
apis->set_irq_enabled(dev, enabled);
}
return count;
}
static ssize_t list_scan_mode_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int ret = 0;
enum scan_mode mode = SCAN_MODE_AUTO;
int len = 0;
static const char *mode_name[SCAN_MODE_MAX] = {
"auto mode",
"normal active mode",
"normal idle mode",
"low power active mode",
"low power idle mode",
};
if (apis->is_scan_mode_supported != NULL) {
len = snprintf(buf, PAGE_SIZE, "result:\n");
for (mode = SCAN_MODE_AUTO; mode < SCAN_MODE_MAX; mode++) {
ret = apis->is_scan_mode_supported(dev, mode);
if (ret) {
len += snprintf(buf + len, PAGE_SIZE - len,
"%d: %s\n", mode, mode_name[mode]);
}
}
ret = len;
} else {
ret = snprintf(buf, PAGE_SIZE, "error: not support\n");
}
return ret;
}
#if IS_ENABLED(CONFIG_TOUCHSCREEN_MOTION_FILTER)
static ssize_t mf_mode_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "result: %d\n", apis->mf_mode);
}
static ssize_t mf_mode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
enum touch_mf_mode mode = 0;
int ret = 0;
if (buf == NULL || count < 0)
return -EINVAL;
if (kstrtoint(buf, 10, (int *)&mode)) {
return -EINVAL;
}
if (mode < TOUCH_MF_MODE_UNFILTERED ||
mode > TOUCH_MF_MODE_AUTO_REPORT) {
return -EINVAL;
}
ret = touch_mf_set_mode(apis->tmf, mode);
if (ret != 0) {
return ret;
}
apis->mf_mode = mode;
return count;
}
#endif
static ssize_t ping_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int ret = 0;
if (apis->ping != NULL) {
ret = apis->ping(dev);
ret = snprintf(buf, PAGE_SIZE, "result: %s\n",
ret == 0 ? "ack" : "non ack");
} else {
ret = snprintf(buf, PAGE_SIZE, "error: not support\n");
}
return ret;
}
static ssize_t reset_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int ret = 0;
if (apis->reset_result > RESET_RESULT_NOT_SUPPORT) {
ret = snprintf(buf, PAGE_SIZE, "result: %s\n",
apis->reset_result == RESET_RESULT_SUCCESS ? "success"
: apis->reset_result == RESET_RESULT_FAIL
? "fail"
: "haven't reset");
} else {
ret = snprintf(buf, PAGE_SIZE, "error: not support\n");
}
return ret;
}
static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = 0;
if (buf == NULL || count <= 0)
return -EINVAL;
if (strncmp(buf, "1", 1) == 0) {
if (apis->hardware_reset != NULL) {
ret = apis->hardware_reset(dev);
apis->reset_result = ret == 0 ? RESET_RESULT_SUCCESS
: RESET_RESULT_FAIL;
} else {
apis->reset_result = RESET_RESULT_NOT_SUPPORT;
}
} else if (strncmp(buf, "2", 0) == 0) {
if (apis->software_reset != NULL) {
ret = apis->software_reset(dev);
apis->reset_result = ret == 0 ? RESET_RESULT_SUCCESS
: RESET_RESULT_FAIL;
} else {
apis->reset_result = RESET_RESULT_NOT_SUPPORT;
}
} else {
apis->reset_result = RESET_RESULT_NOT_SUPPORT;
return -EINVAL;
}
return count;
}
static ssize_t scan_mode_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "result: %d\n", apis->scan_mode);
}
static ssize_t scan_mode_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
enum scan_mode mode = 0;
int ret = 0;
if (buf == NULL || count < 0)
return -EINVAL;
if (kstrtoint(buf, 10, (int *)&mode)) {
return -EINVAL;
}
if (apis->is_scan_mode_supported == NULL ||
!apis->is_scan_mode_supported(dev, mode)) {
return -EINVAL;
}
if (apis->set_scan_mode != NULL) {
ret = apis->set_scan_mode(dev, mode);
if (ret != 0) {
return ret;
}
apis->scan_mode = mode;
}
return count;
}
static ssize_t sensing_enabled_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int ret = 0;
if (apis->ping != NULL) {
ret = apis->ping(dev);
ret = snprintf(buf, PAGE_SIZE, "result: %s\n",
ret == 0 ? "enabled" : "disabled");
} else {
ret = snprintf(buf, PAGE_SIZE, "error: not support\n");
}
return ret;
}
static ssize_t sensing_enabled_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool enabled = false;
if (buf == NULL || count <= 0)
return -EINVAL;
if (strncmp(buf, "1", 1) == 0) {
enabled = true;
} else if (strncmp(buf, "0", 1) == 0) {
enabled = false;
} else {
return -EINVAL;
}
if (apis->set_sensing_enabled != NULL) {
apis->set_sensing_enabled(dev, enabled);
}
return count;
}
#if IS_ENABLED(CONFIG_GOOG_TOUCH_INTERFACE) && IS_ENABLED(CONFIG_GTI_PM)
static ssize_t wake_lock_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int ret = 0;
bool locked = false;
if (apis->get_wake_lock_state != NULL) {
locked = apis->get_wake_lock_state(
dev, GTI_PM_WAKELOCK_TYPE_FORCE_ACTIVE);
ret = snprintf(buf, PAGE_SIZE, "result: %s\n",
locked ? "locked" : "unlocked");
} else {
ret = snprintf(buf, PAGE_SIZE, "error: not support\n");
}
return ret;
}
static ssize_t wake_lock_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool locked = false;
int ret = 0;
if (buf == NULL || count <= 0)
return -EINVAL;
if (strncmp(buf, "1", 1) == 0) {
locked = true;
} else if (strncmp(buf, "0", 1) == 0) {
locked = false;
} else {
return -EINVAL;
}
if (apis->set_wake_lock_state != NULL) {
ret = apis->set_wake_lock_state(
dev, GTI_PM_WAKELOCK_TYPE_FORCE_ACTIVE, locked);
if (ret < 0) {
return ret;
}
}
return count;
}
#endif
static DEVICE_ATTR_RO(fw_ver);
static DEVICE_ATTR_RO(help);
static DEVICE_ATTR_RW(irq_enabled);
static DEVICE_ATTR_RO(list_scan_mode);
#if IS_ENABLED(CONFIG_TOUCHSCREEN_MOTION_FILTER)
static DEVICE_ATTR_RW(mf_mode);
#endif
static DEVICE_ATTR_RO(ping);
static DEVICE_ATTR_RW(reset);
static DEVICE_ATTR_RW(scan_mode);
static DEVICE_ATTR_RW(sensing_enabled);
#if IS_ENABLED(CONFIG_GOOG_TOUCH_INTERFACE) && IS_ENABLED(CONFIG_GTI_PM)
static DEVICE_ATTR_RW(wake_lock);
#endif
static struct attribute *sysfs_attrs[] = {
&dev_attr_fw_ver.attr,
&dev_attr_help.attr,
&dev_attr_irq_enabled.attr,
&dev_attr_list_scan_mode.attr,
#if IS_ENABLED(CONFIG_TOUCHSCREEN_MOTION_FILTER)
&dev_attr_mf_mode.attr,
#endif
&dev_attr_ping.attr,
&dev_attr_reset.attr,
&dev_attr_scan_mode.attr,
&dev_attr_sensing_enabled.attr,
#if IS_ENABLED(CONFIG_GOOG_TOUCH_INTERFACE) && IS_ENABLED(CONFIG_GTI_PM)
&dev_attr_wake_lock.attr,
#endif
NULL,
};
static const struct attribute_group sysfs_group = {
.attrs = sysfs_attrs,
};
int touch_apis_init(struct device *dev, struct touch_apis_data *data)
{
int ret = 0;
apis = data;
apis->scan_mode = SCAN_MODE_AUTO;
apis->reset_result = RESET_RESULT_NOT_READY;
ret = sysfs_create_group(&dev->kobj, &sysfs_group);
if (ret) {
dev_err(dev, "failed create core sysfs group");
return ret;
}
return ret;
}
void touch_apis_deinit(struct device *dev)
{
sysfs_remove_group(&dev->kobj, &sysfs_group);
if (apis != NULL) {
apis = NULL;
}
}