// SPDX-License-Identifier: GPL-2.0 /* * Sysfs APIs for Google Pixel devices. * * Copyright 2022 Google LLC. */ #include #include #include #include #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; } }