[PATCH 2/2] s3c2410_ts-improve-interrupt-handling.patch

Nelson Castillo nelsoneci at gmail.com
Sat Nov 22 09:24:31 CET 2008


Let's improve interrupt handling logic. We do not need to
to call the timer function (touch_timer_fire) from the
stylus_updown interrupt handler. With this patch the filters
work much better. We were getting many erratic results when
tapping that were making this driver unusable.

I tested using this program by Tick:

http://svn.openmoko.org/developers/tick/touchtest/touch_test.py

The driver is behaving much better now. Please help us test.

Signed-off-by: Nelson Castillo <nelsoneci at gmail.com>
---

 0 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
index 8f0afc3..8e580a8 100644
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ b/drivers/input/touchscreen/s3c2410_ts.c
@@ -98,9 +98,10 @@ static char *s3c2410ts_name = "s3c2410 TouchScreen";
 
 struct s3c2410ts {
 	struct input_dev *dev;
-	int flag_first_touch_sent;
 	struct ts_filter *tsf[MAX_TS_FILTER_CHAIN];
 	int coords[2]; /* just X and Y for us */
+	int is_down;
+	int need_to_send_first_touch;
 };
 
 static struct s3c2410ts ts;
@@ -116,69 +117,58 @@ static inline void s3c2410_ts_connect(void)
 	s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);
 }
 
-static void touch_timer_fire(unsigned long data)
-{
-  	unsigned long data0;
-  	unsigned long data1;
-	int updown;
-
-	data0 = readl(base_addr + S3C2410_ADCDAT0);
-	data1 = readl(base_addr + S3C2410_ADCDAT1);
+enum ts_input_event {IE_DOWN = 0, IE_UP, IE_UPDATE};
 
-	updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
-					    (!(data1 & S3C2410_ADCDAT0_UPDOWN));
-
-	// if we need to send an untouch event, but we haven't yet sent the
-	// touch event (this happens if the touchscreen was tapped lightly),
-	// send the touch event first
-	if (!updown && !ts.flag_first_touch_sent) {
-		if (ts.tsf[0])
-			(ts.tsf[0]->api->scale)(ts.tsf[0], &ts.coords[0]);
+static void ts_input_report(int event)
+{
+	if (event == IE_DOWN || event == IE_UPDATE) {
 		input_report_abs(ts.dev, ABS_X, ts.coords[0]);
 		input_report_abs(ts.dev, ABS_Y, ts.coords[1]);
-
 		input_report_key(ts.dev, BTN_TOUCH, 1);
 		input_report_abs(ts.dev, ABS_PRESSURE, 1);
-		input_sync(ts.dev);
-		ts.flag_first_touch_sent = 1;
+	} else {
+		input_report_key(ts.dev, BTN_TOUCH, 0);
+		input_report_abs(ts.dev, ABS_PRESSURE, 0);
 	}
 
-	if (updown) {
-
-		if (ts.tsf[0])
-			(ts.tsf[0]->api->scale)(ts.tsf[0], &ts.coords[0]);
+	input_sync(ts.dev);
 
 #ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
-		{
-			struct timeval tv;
-
-			do_gettimeofday(&tv);
-			printk(DEBUG_LVL "T:%06d, X:%03ld, Y:%03ld\n",
-				   (int)tv.tv_usec, ts.coords[0], ts.coords[1]);
-		}
+	{
+		static char *s[] = {"down", "up", "update"};
+		struct timeval tv;
+		do_gettimeofday(&tv);
+		printk(DEBUG_LVL "T:%06d %6s (X:%03d, Y:%03d)\n",
+		       (int)tv.tv_usec, s[event], ts.coords[0], ts.coords[1]);
+	}
 #endif
+}
+static void touch_timer_fire(unsigned long data)
+{
+	if (ts.tsf[0])
+		(ts.tsf[0]->api->scale)(ts.tsf[0], &ts.coords[0]);
+
+	if (ts.need_to_send_first_touch) {
+		ts.need_to_send_first_touch = 0;
+		ts_input_report(IE_DOWN);
+		if (!ts.is_down) { /* Do we need this? I think so. */
+			ts_input_report(IE_UPDATE);
+			ts_input_report(IE_UP);
+		}
+	} else if (ts.is_down) {
+		ts_input_report(IE_UPDATE);
+	} else {
+		ts_input_report(IE_UP);
+	}
 
-		input_report_abs(ts.dev, ABS_X, ts.coords[0]);
-		input_report_abs(ts.dev, ABS_Y, ts.coords[1]);
-
-		input_report_key(ts.dev, BTN_TOUCH, 1);
-		input_report_abs(ts.dev, ABS_PRESSURE, 1);
-		input_sync(ts.dev);
-
+	if (ts.is_down) {
 		writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
 						      base_addr+S3C2410_ADCTSC);
 		writel(readl(base_addr+S3C2410_ADCCON) |
 			 S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
 	} else {
-
 		if (ts.tsf[0])
 			(ts.tsf[0]->api->clear)(ts.tsf[0]);
-
-		input_report_key(ts.dev, BTN_TOUCH, 0);
-		input_report_abs(ts.dev, ABS_PRESSURE, 0);
-		input_sync(ts.dev);
-		ts.flag_first_touch_sent = 0;
-
 		writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
 	}
 }
@@ -190,20 +180,20 @@ static irqreturn_t stylus_updown(int irq, void *dev_id)
 {
 	unsigned long data0;
 	unsigned long data1;
-	int updown;
 
 	data0 = readl(base_addr+S3C2410_ADCDAT0);
 	data1 = readl(base_addr+S3C2410_ADCDAT1);
 
-	updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
+	ts.is_down = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
 					    (!(data1 & S3C2410_ADCDAT0_UPDOWN));
 
-	/* TODO we should never get an interrupt with updown set while
-	 * the timer is running, but maybe we ought to verify that the
-	 * timer isn't running anyways. */
-
-	if (updown)
-		touch_timer_fire(0);
+	if (ts.is_down) {
+		ts.need_to_send_first_touch = 1;
+		writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
+						      base_addr+S3C2410_ADCTSC);
+		writel(readl(base_addr+S3C2410_ADCCON) |
+			 S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -336,7 +326,9 @@ static int __init s3c2410ts_probe(struct platform_device *pdev)
 	else /* this is OK, just means there won't be any filtering */
 		dev_info(&pdev->dev, "Unfiltered output selected\n");
 
-	if (!ts.tsf[0])
+	if (ts.tsf[0])
+		(ts.tsf[0]->api->clear)(ts.tsf[0]);
+	else
 		dev_info(&pdev->dev, "No filtering\n");
 
 	/* Get irqs */




More information about the openmoko-kernel mailing list