/* * * FocalTech ftxxxx TouchScreen driver. * * Copyright (c) 2012-2019, 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 *****************************************************************************/ /***************************************************************************** * 3.Private enumerations, structures and unions using typedef *****************************************************************************/ enum _ex_mode { MODE_GLOVE = 0, MODE_COVER, MODE_CHARGER, REPORT_RATE, }; /***************************************************************************** * 4.Static variables *****************************************************************************/ /***************************************************************************** * 5.Global variable or extern global variabls/functions *****************************************************************************/ /***************************************************************************** * 6.Static function prototypes *******************************************************************************/ static int fts_ex_mode_switch(enum _ex_mode mode, u8 value) { int ret = 0; switch (mode) { case MODE_GLOVE: ret = fts_write_reg(FTS_REG_GLOVE_MODE_EN, value > 0 ? 1 : 0); if (ret < 0) FTS_ERROR("MODE_GLOVE switch to %d fail", value); break; case MODE_COVER: ret = fts_write_reg(FTS_REG_COVER_MODE_EN, value > 0 ? 1 : 0); if (ret < 0) FTS_ERROR("MODE_COVER switch to %d fail", value); break; case MODE_CHARGER: ret = fts_write_reg(FTS_REG_CHARGER_MODE_EN, value > 0 ? 1 : 0); if (ret < 0) FTS_ERROR("MODE_CHARGER switch to %d fail", value); break; case REPORT_RATE: ret = fts_write_reg(FTS_REG_REPORT_RATE, value); if (ret < 0) FTS_ERROR("REPORT_RATE switch to %d fail", value); break; default: FTS_ERROR("mode(%d) unsupport", mode); ret = -EINVAL; break; } return ret; } static ssize_t fts_glove_mode_show( struct device *dev, struct device_attribute *attr, char *buf) { int count = 0; u8 val = 0; struct fts_ts_data *ts_data = fts_data; struct input_dev *input_dev = ts_data->input_dev; mutex_lock(&input_dev->mutex); fts_read_reg(FTS_REG_GLOVE_MODE_EN, &val); count = scnprintf(buf + count, PAGE_SIZE, "Glove Mode:%s\n", ts_data->glove_mode ? "On" : "Off"); count += scnprintf(buf + count, PAGE_SIZE - count, "Glove Reg(0xC0):%d\n", val); mutex_unlock(&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) { int ret = 0; struct fts_ts_data *ts_data = fts_data; if (FTS_SYSFS_ECHO_ON(buf)) { if (!ts_data->glove_mode) { FTS_DEBUG("enter glove mode"); ret = fts_ex_mode_switch(MODE_GLOVE, ENABLE); if (ret >= 0) { ts_data->glove_mode = ENABLE; } } } else if (FTS_SYSFS_ECHO_OFF(buf)) { if (ts_data->glove_mode) { FTS_DEBUG("exit glove mode"); ret = fts_ex_mode_switch(MODE_GLOVE, DISABLE); if (ret >= 0) { ts_data->glove_mode = DISABLE; } } } FTS_DEBUG("glove mode:%d", ts_data->glove_mode); return count; } static ssize_t fts_cover_mode_show( struct device *dev, struct device_attribute *attr, char *buf) { int count = 0; u8 val = 0; struct fts_ts_data *ts_data = fts_data; struct input_dev *input_dev = ts_data->input_dev; mutex_lock(&input_dev->mutex); fts_read_reg(FTS_REG_COVER_MODE_EN, &val); count = scnprintf(buf + count, PAGE_SIZE, "Cover Mode:%s\n", ts_data->cover_mode ? "On" : "Off"); count += scnprintf(buf + count, PAGE_SIZE - count, "Cover Reg(0xC1):%d\n", val); mutex_unlock(&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) { int ret = 0; struct fts_ts_data *ts_data = fts_data; if (FTS_SYSFS_ECHO_ON(buf)) { if (!ts_data->cover_mode) { FTS_DEBUG("enter cover mode"); ret = fts_ex_mode_switch(MODE_COVER, ENABLE); if (ret >= 0) { ts_data->cover_mode = ENABLE; } } } else if (FTS_SYSFS_ECHO_OFF(buf)) { if (ts_data->cover_mode) { FTS_DEBUG("exit cover mode"); ret = fts_ex_mode_switch(MODE_COVER, DISABLE); if (ret >= 0) { ts_data->cover_mode = DISABLE; } } } FTS_DEBUG("cover mode:%d", ts_data->cover_mode); return count; } static ssize_t fts_charger_mode_show( struct device *dev, struct device_attribute *attr, char *buf) { int count = 0; u8 val = 0; struct fts_ts_data *ts_data = fts_data; struct input_dev *input_dev = ts_data->input_dev; mutex_lock(&input_dev->mutex); fts_read_reg(FTS_REG_CHARGER_MODE_EN, &val); count = scnprintf(buf + count, PAGE_SIZE, "Charger Mode:%s\n", ts_data->charger_mode ? "On" : "Off"); count += scnprintf(buf + count, PAGE_SIZE - count, "Charger Reg(0x8B):%d\n", val); mutex_unlock(&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) { int ret = 0; struct fts_ts_data *ts_data = fts_data; if (FTS_SYSFS_ECHO_ON(buf)) { if (!ts_data->charger_mode) { FTS_DEBUG("enter charger mode"); ret = fts_ex_mode_switch(MODE_CHARGER, ENABLE); if (ret >= 0) { ts_data->charger_mode = ENABLE; } } } else if (FTS_SYSFS_ECHO_OFF(buf)) { if (ts_data->charger_mode) { FTS_DEBUG("exit charger mode"); ret = fts_ex_mode_switch(MODE_CHARGER, DISABLE); if (ret >= 0) { ts_data->charger_mode = DISABLE; } } } FTS_DEBUG("charger mode:%d", ts_data->glove_mode); return count; } static ssize_t fts_report_rate_show( struct device *dev, struct device_attribute *attr, char *buf) { int count = 0; u8 val = 0; struct fts_ts_data *ts_data = fts_data; struct input_dev *input_dev = ts_data->input_dev; mutex_lock(&input_dev->mutex); fts_read_reg(FTS_REG_REPORT_RATE, &val); count = scnprintf(buf + count, PAGE_SIZE, "Report Rate:%d\n", ts_data->report_rate); count += scnprintf(buf + count, PAGE_SIZE - count, "Report Rate Reg(0x88):%d\n", val); mutex_unlock(&input_dev->mutex); return count; } static ssize_t fts_report_rate_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret = 0; struct fts_ts_data *ts_data = fts_data; int rate; ret = kstrtoint(buf, 16, &rate); if (ret) return ret; if (rate != ts_data->report_rate) { ret = fts_ex_mode_switch(REPORT_RATE, (u8)rate); if (ret >= 0) ts_data->report_rate = rate; } FTS_DEBUG("report rate:%d", ts_data->report_rate); 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_RW(fts_report_rate); 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_report_rate.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); } if (ts_data->charger_mode) { fts_ex_mode_switch(MODE_CHARGER, ENABLE); } if (ts_data->report_rate > 0) fts_ex_mode_switch(REPORT_RATE, ts_data->report_rate); return 0; } 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->report_rate = 0; 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) succeedfully"); } 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; }