build/patch/kernel/archive/sunxi-6.1/patches.armbian/drv-touchscreen-tsc2007-polling.patch

196 lines
4.9 KiB
Diff
Raw Permalink Normal View History

From 7c62c1ea69d7f892555ad697dbefbf4803d0908b Mon Sep 17 00:00:00 2001
From: Alan <Alan>
Date: Sat, 20 May 2023 14:44:07 +0800
Subject: [PATCH 10/13] Optimize: TSC2007 touchscreen add polling method
---
drivers/input/touchscreen/tsc2007.h | 6 ++
drivers/input/touchscreen/tsc2007_core.c | 110 +++++++++++++++++++++--
2 files changed, 108 insertions(+), 8 deletions(-)
diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h
index 69b08dd6c8df..5252b6c6daeb 100644
--- a/drivers/input/touchscreen/tsc2007.h
+++ b/drivers/input/touchscreen/tsc2007.h
@@ -66,10 +66,13 @@ struct tsc2007 {
u16 model;
u16 x_plate_ohms;
u16 max_rt;
+ u16 rt_thr;
+ u8 touched;
unsigned long poll_period; /* in jiffies */
int fuzzx;
int fuzzy;
int fuzzz;
+ bool ignore_nak;
struct gpio_desc *gpiod;
int irq;
@@ -81,6 +84,9 @@ struct tsc2007 {
void (*clear_penirq)(void);
struct mutex mlock;
+
+ struct timer_list timer;
+ struct work_struct work_i2c_poll;
};
int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd);
diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c
index 3e871d182c40..6e3bdf1debe0 100644
--- a/drivers/input/touchscreen/tsc2007_core.c
+++ b/drivers/input/touchscreen/tsc2007_core.c
@@ -28,6 +28,8 @@
#include <linux/platform_data/tsc2007.h>
#include "tsc2007.h"
+#define POLL_INTERVAL_MS 17 /* 17ms = 60fps */
+
int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
{
s32 data;
@@ -172,6 +174,65 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
return IRQ_HANDLED;
}
+static irqreturn_t tsc2007_soft_poll(int irq, void *handle)
+{
+ struct tsc2007 *ts = handle;
+ struct input_dev *input = ts->input;
+ struct ts_event tc;
+ u32 rt;
+
+ if(!ts->stopped) {
+
+ mutex_lock(&ts->mlock);
+ tsc2007_read_values(ts, &tc);
+ mutex_unlock(&ts->mlock);
+
+ rt = tsc2007_calculate_resistance(ts, &tc);
+
+ if (rt == 0 || rt == 256) {
+
+ /*
+ * Sample found inconsistent by debouncing or pressure is
+ * beyond the maximum. Don't report it to user space,
+ * repeat at least once more the measurement.
+ */
+ dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
+
+ } else {
+
+ if (rt < ts->rt_thr) {
+
+ dev_dbg(&ts->client->dev,
+ "DOWN point(%4d,%4d), resistance (%4u)\n",
+ tc.x, tc.y, rt);
+
+ rt = ts->max_rt - rt;
+
+ input_report_key(input, BTN_TOUCH, 1);
+ input_report_abs(input, ABS_X, tc.y);
+ input_report_abs(input, ABS_Y, 4096 - tc.x);
+ input_report_abs(input, ABS_PRESSURE, rt);
+
+ input_sync(input);
+ ts->touched = 1;
+
+ } else if (ts->touched == 1) {
+
+ dev_dbg(&ts->client->dev, "UP\n");
+
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ input_sync(input);
+ ts->touched = 0;
+ }
+ }
+
+
+ }
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
{
struct tsc2007 *ts = handle;
@@ -229,11 +290,32 @@ static int tsc2007_get_pendown_state_gpio(struct device *dev)
return gpiod_get_value(ts->gpiod);
}
+static void tsc2007_ts_irq_poll_timer(struct timer_list *t)
+{
+ struct tsc2007 *ts = from_timer(ts, t, timer);
+
+ schedule_work(&ts->work_i2c_poll);
+ mod_timer(&ts->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS));
+}
+
+static void tsc2007_ts_work_i2c_poll(struct work_struct *work)
+{
+ struct tsc2007 *ts = container_of(work,
+ struct tsc2007, work_i2c_poll);
+
+ tsc2007_soft_poll(0, ts);
+}
+
static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts)
{
u32 val32;
u64 val64;
+ ts->ignore_nak = device_property_read_bool(dev, "i2c,ignore-nak");
+
+ if (!device_property_read_u32(dev, "ti,rt-thr", &val32))
+ ts->rt_thr = val32;
+
if (!device_property_read_u32(dev, "ti,max-rt", &val32))
ts->max_rt = val32;
else
@@ -330,6 +412,9 @@ static int tsc2007_probe(struct i2c_client *client,
if (!input_dev)
return -ENOMEM;
+ if (ts->ignore_nak)
+ client->flags |= I2C_M_IGNORE_NAK;
+
i2c_set_clientdata(client, ts);
ts->client = client;
@@ -375,14 +460,23 @@ static int tsc2007_probe(struct i2c_client *client,
pdata->init_platform_hw();
}
- err = devm_request_threaded_irq(&client->dev, ts->irq,
- tsc2007_hard_irq, tsc2007_soft_irq,
- IRQF_ONESHOT,
- client->dev.driver->name, ts);
- if (err) {
- dev_err(&client->dev, "Failed to request irq %d: %d\n",
- ts->irq, err);
- return err;
+ if (ts->gpiod) {
+ err = devm_request_threaded_irq(&client->dev, ts->irq,
+ tsc2007_hard_irq, tsc2007_soft_irq,
+ IRQF_ONESHOT,
+ client->dev.driver->name, ts);
+ if (err) {
+ dev_err(&client->dev, "Failed to request irq %d: %d\n",
+ ts->irq, err);
+ return err;
+ }
+ } else {
+ INIT_WORK(&ts->work_i2c_poll,
+ tsc2007_ts_work_i2c_poll);
+ timer_setup(&ts->timer, tsc2007_ts_irq_poll_timer, 0);
+ ts->timer.expires = jiffies +
+ msecs_to_jiffies(POLL_INTERVAL_MS);
+ add_timer(&ts->timer);
}
tsc2007_stop(ts);
--
2.34.1