mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			139 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 8d52c64a49246ccab0028999578982c44ef0bf42 Mon Sep 17 00:00:00 2001
 | 
						|
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
 | 
						|
Date: Mon, 30 Jan 2023 14:46:16 +0000
 | 
						|
Subject: [PATCH] input: goodix: Add option to poll instead of relying on IRQ
 | 
						|
 line
 | 
						|
 | 
						|
The interrupt line from the touch controller is not necessarily
 | 
						|
connected to the SoC, so add the option to poll for touch info.
 | 
						|
 | 
						|
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 | 
						|
---
 | 
						|
 drivers/input/touchscreen/goodix.c | 70 +++++++++++++++++++++++++++---
 | 
						|
 drivers/input/touchscreen/goodix.h |  2 +
 | 
						|
 2 files changed, 66 insertions(+), 6 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/input/touchscreen/goodix.c
 | 
						|
+++ b/drivers/input/touchscreen/goodix.c
 | 
						|
@@ -48,6 +48,8 @@
 | 
						|
 #define MAX_CONTACTS_LOC	5
 | 
						|
 #define TRIGGER_LOC		6
 | 
						|
 
 | 
						|
+#define POLL_INTERVAL_MS		17	/* 17ms = 60fps */
 | 
						|
+
 | 
						|
 /* Our special handling for GPIO accesses through ACPI is x86 specific */
 | 
						|
 #if defined CONFIG_X86 && defined CONFIG_ACPI
 | 
						|
 #define ACPI_GPIO_SUPPORT
 | 
						|
@@ -513,16 +515,67 @@ static irqreturn_t goodix_ts_irq_handler
 | 
						|
 	return IRQ_HANDLED;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static void goodix_ts_irq_poll_timer(struct timer_list *t)
 | 
						|
+{
 | 
						|
+	struct goodix_ts_data *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 goodix_ts_work_i2c_poll(struct work_struct *work)
 | 
						|
+{
 | 
						|
+	struct goodix_ts_data *ts = container_of(work,
 | 
						|
+			struct goodix_ts_data, work_i2c_poll);
 | 
						|
+
 | 
						|
+	goodix_process_events(ts);
 | 
						|
+	goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0);
 | 
						|
+}
 | 
						|
+
 | 
						|
+static void goodix_enable_irq(struct goodix_ts_data *ts)
 | 
						|
+{
 | 
						|
+	if (ts->client->irq) {
 | 
						|
+		enable_irq(ts->client->irq);
 | 
						|
+	} else {
 | 
						|
+		ts->timer.expires = jiffies + msecs_to_jiffies(POLL_INTERVAL_MS);
 | 
						|
+		add_timer(&ts->timer);
 | 
						|
+	}
 | 
						|
+}
 | 
						|
+
 | 
						|
+static void goodix_disable_irq(struct goodix_ts_data *ts)
 | 
						|
+{
 | 
						|
+	if (ts->client->irq) {
 | 
						|
+		disable_irq(ts->client->irq);
 | 
						|
+	} else {
 | 
						|
+		del_timer(&ts->timer);
 | 
						|
+		cancel_work_sync(&ts->work_i2c_poll);
 | 
						|
+	}
 | 
						|
+}
 | 
						|
+
 | 
						|
 static void goodix_free_irq(struct goodix_ts_data *ts)
 | 
						|
 {
 | 
						|
-	devm_free_irq(&ts->client->dev, ts->client->irq, ts);
 | 
						|
+	if (ts->client->irq) {
 | 
						|
+		devm_free_irq(&ts->client->dev, ts->client->irq, ts);
 | 
						|
+	} else {
 | 
						|
+		del_timer(&ts->timer);
 | 
						|
+		cancel_work_sync(&ts->work_i2c_poll);
 | 
						|
+	}
 | 
						|
 }
 | 
						|
 
 | 
						|
 static int goodix_request_irq(struct goodix_ts_data *ts)
 | 
						|
 {
 | 
						|
-	return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
 | 
						|
-					 NULL, goodix_ts_irq_handler,
 | 
						|
-					 ts->irq_flags, ts->client->name, ts);
 | 
						|
+	if (ts->client->irq) {
 | 
						|
+		return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
 | 
						|
+						 NULL, goodix_ts_irq_handler,
 | 
						|
+						 ts->irq_flags, ts->client->name, ts);
 | 
						|
+	} else {
 | 
						|
+		INIT_WORK(&ts->work_i2c_poll,
 | 
						|
+			  goodix_ts_work_i2c_poll);
 | 
						|
+		timer_setup(&ts->timer, goodix_ts_irq_poll_timer, 0);
 | 
						|
+		if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE)
 | 
						|
+			goodix_enable_irq(ts);
 | 
						|
+		return 0;
 | 
						|
+	}
 | 
						|
 }
 | 
						|
 
 | 
						|
 static int goodix_check_cfg_8(struct goodix_ts_data *ts, const u8 *cfg, int len)
 | 
						|
@@ -1425,6 +1478,11 @@ static void goodix_ts_remove(struct i2c_
 | 
						|
 {
 | 
						|
 	struct goodix_ts_data *ts = i2c_get_clientdata(client);
 | 
						|
 
 | 
						|
+	if (!client->irq) {
 | 
						|
+		del_timer(&ts->timer);
 | 
						|
+		cancel_work_sync(&ts->work_i2c_poll);
 | 
						|
+	}
 | 
						|
+
 | 
						|
 	if (ts->load_cfg_from_disk)
 | 
						|
 		wait_for_completion(&ts->firmware_loading_complete);
 | 
						|
 }
 | 
						|
@@ -1440,7 +1498,7 @@ static int __maybe_unused goodix_suspend
 | 
						|
 
 | 
						|
 	/* We need gpio pins to suspend/resume */
 | 
						|
 	if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
 | 
						|
-		disable_irq(client->irq);
 | 
						|
+		goodix_disable_irq(ts);
 | 
						|
 		return 0;
 | 
						|
 	}
 | 
						|
 
 | 
						|
@@ -1484,7 +1542,7 @@ static int __maybe_unused goodix_resume(
 | 
						|
 	int error;
 | 
						|
 
 | 
						|
 	if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
 | 
						|
-		enable_irq(client->irq);
 | 
						|
+		goodix_enable_irq(ts);
 | 
						|
 		return 0;
 | 
						|
 	}
 | 
						|
 
 | 
						|
--- a/drivers/input/touchscreen/goodix.h
 | 
						|
+++ b/drivers/input/touchscreen/goodix.h
 | 
						|
@@ -104,6 +104,8 @@ struct goodix_ts_data {
 | 
						|
 	u8 main_clk[GOODIX_MAIN_CLK_LEN];
 | 
						|
 	int bak_ref_len;
 | 
						|
 	u8 *bak_ref;
 | 
						|
+	struct timer_list timer;
 | 
						|
+	struct work_struct work_i2c_poll;
 | 
						|
 };
 | 
						|
 
 | 
						|
 int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);
 |