All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch 2.6.20-rc1 6/6] input: ads7846 directly senses PENUP state
@ 2006-12-22 19:25 David Brownell
  2006-12-28 22:37 ` David Brownell
  0 siblings, 1 reply; 15+ messages in thread
From: David Brownell @ 2006-12-22 19:25 UTC (permalink / raw)
  To: nicolas.ferre, linux-kernel, dtor_core

From: imre.deak@solidboot.com <imre.deak@solidboot.com>
Date:  Wed Jul 5 19:18:32 2006 +0300

Input: ads7846: detect pen up from GPIO state

We can't depend on the pressure value to determine when the pen was
lifted, so use the GPIO line state instead.  This also helps with
chips (like ads7843) that don't have pressure sensors.

Signed-off-by: Imre Deak <imre.deak@solidboot.com>
Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>


Index: osk/drivers/input/touchscreen/ads7846.c
===================================================================
--- osk.orig/drivers/input/touchscreen/ads7846.c	2006-12-22 11:08:46.000000000 -0800
+++ osk/drivers/input/touchscreen/ads7846.c	2006-12-22 11:08:47.000000000 -0800
@@ -430,6 +430,39 @@ static struct attribute_group ads7845_at
 
 /*--------------------------------------------------------------------------*/
 
+static void ads7846_report_pen_state(struct ads7846 *ts, int down)
+{
+	struct input_dev	*input_dev = ts->input;
+
+	input_report_key(input_dev, BTN_TOUCH, down);
+	if (!down)
+		input_report_abs(input_dev, ABS_PRESSURE, 0);
+#ifdef VERBOSE
+	pr_debug("%s: %s\n", ts->spi->dev.bus_id, down ? "DOWN" : "UP");
+#endif
+}
+
+static void ads7846_report_pen_position(struct ads7846 *ts, int x, int y,
+					int pressure)
+{
+	struct input_dev	*input_dev = ts->input;
+
+	input_report_abs(input_dev, ABS_X, x);
+	input_report_abs(input_dev, ABS_Y, y);
+	input_report_abs(input_dev, ABS_PRESSURE, pressure);
+
+#ifdef VERBOSE
+	pr_debug("%s: %d/%d/%d\n", ts->spi->dev.bus_id, x, y, pressure);
+#endif
+}
+
+static void ads7846_sync_events(struct ads7846 *ts)
+{
+	struct input_dev	*input_dev = ts->input;
+
+	input_sync(input_dev);
+}
+
 /*
  * PENIRQ only kicks the timer.  The timer only reissues the SPI transfer,
  * to retrieve touchscreen status.
@@ -441,11 +474,8 @@ static struct attribute_group ads7845_at
 static void ads7846_rx(void *ads)
 {
 	struct ads7846		*ts = ads;
-	struct input_dev	*input_dev = ts->input;
 	unsigned		Rt;
-	unsigned		sync = 0;
 	u16			x, y, z1, z2;
-	unsigned long		flags;
 
 	/* ads7846_rx_val() did in-place conversion (including byteswap) from
 	 * on-the-wire format as part of debouncing to get stable readings.
@@ -459,7 +489,7 @@ static void ads7846_rx(void *ads)
 	if (x == MAX_12BIT)
 		x = 0;
 
-	if (likely(x && z1 && !device_suspended(&ts->spi->dev))) {
+	if (likely(x && z1)) {
 		/* compute touch pressure resistance using equation #2 */
 		Rt = z2;
 		Rt -= z1;
@@ -475,52 +505,33 @@ static void ads7846_rx(void *ads)
 	 * once more the measurement
 	 */
 	if (ts->tc.ignore || Rt > ts->pressure_max) {
+#ifdef VERBOSE
+		pr_debug("%s: ignored %d pressure %d\n",
+			ts->spi->dev.bus_id, ts->tc.ignore, Rt);
+#endif
 		hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
 			      HRTIMER_REL);
 		return;
 	}
 
-	/* NOTE:  "pendown" is inferred from pressure; we don't rely on
-	 * being able to check nPENIRQ status, or "friendly" trigger modes
-	 * (both-edges is much better than just-falling or low-level).
-	 *
-	 * REVISIT:  some boards may require reading nPENIRQ; it's
-	 * needed on 7843.  and 7845 reads pressure differently...
+	/* NOTE: We can't rely on the pressure to determine the pen down
+	 * state, even this controller has a pressure sensor.  The pressure
+	 * value can fluctuate for quite a while after lifting the pen and
+	 * in some cases may not even settle at the expected value.
 	 *
-	 * REVISIT:  the touchscreen might not be connected; this code
-	 * won't notice that, even if nPENIRQ never fires ...
+	 * The only safe way to check for the pen up condition is in the
+	 * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
 	 */
-	if (!ts->pendown && Rt != 0) {
-		input_report_key(input_dev, BTN_TOUCH, 1);
-		sync = 1;
-	} else if (ts->pendown && Rt == 0) {
-		input_report_key(input_dev, BTN_TOUCH, 0);
-		sync = 1;
-	}
-
 	if (Rt) {
-		input_report_abs(input_dev, ABS_X, x);
-		input_report_abs(input_dev, ABS_Y, y);
-		sync = 1;
-	}
-
-	if (sync) {
-		input_report_abs(input_dev, ABS_PRESSURE, Rt);
-		input_sync(input_dev);
+		if (!ts->pendown) {
+			ads7846_report_pen_state(ts, 1);
+			ts->pendown = 1;
+		}
+		ads7846_report_pen_position(ts, x, y, Rt);
+		ads7846_sync_events(ts);
 	}
 
-#ifdef	VERBOSE
-	if (Rt || ts->pendown)
-		pr_debug("%s: %d/%d/%d%s\n", ts->spi->dev.bus_id,
-			x, y, Rt, Rt ? "" : " UP");
-#endif
-
-	spin_lock_irqsave(&ts->lock, flags);
-
-	ts->pendown = (Rt != 0);
 	hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL);
-
-	spin_unlock_irqrestore(&ts->lock, flags);
 }
 
 static int ads7846_debounce(void *ads, int data_idx, int *val)
@@ -616,14 +627,20 @@ static int ads7846_timer(struct hrtimer 
 
 	spin_lock_irq(&ts->lock);
 
-	if (unlikely(ts->msg_idx && !ts->pendown)) {
+	if (unlikely(!ts->get_pendown_state()
+			|| device_suspended(&ts->spi->dev))) {
+		if (ts->pendown) {
+			ads7846_report_pen_state(ts, 0);
+			ads7846_sync_events(ts);
+			ts->pendown = 0;
+		}
+
 		/* measurement cycle ended */
 		if (!device_suspended(&ts->spi->dev)) {
 			ts->irq_disabled = 0;
 			enable_irq(ts->spi->irq);
 		}
 		ts->pending = 0;
-		ts->msg_idx = 0;
 	} else {
 		/* pen is still down, continue with the measurement */
 		ts->msg_idx = 0;

^ permalink raw reply	[flat|nested] 15+ messages in thread
* [PATCH] input/spi: add ads7843 support to ads7846 touchscreen driver
@ 2006-12-15 14:45 Nicolas FERRE
  2006-12-20 22:03 ` Andrew Morton
  0 siblings, 1 reply; 15+ messages in thread
From: Nicolas FERRE @ 2006-12-15 14:45 UTC (permalink / raw)
  To: David Brownell; +Cc: linux-kernel

Add support for the ads7843 touchscreen controller to the ads7846
driver code.
The "pen down" information is managed quite differently as we
do not have a touch-pressure measurement on the ads7843.

Signed-off-by: Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
---

I add a ads7843_rx function to manage the end of a measurement cycle.
As for ads7846_rx, it does the real work and communicates with the
input subsystem.
The timer function is responsible of taking the pen up/pen down state
through the board specific get_pendown_state() callback.

As the SPI underlying code behaves quite differently from a controller
driver to another while not having a tx_buf filled, I have add a
zeroed buffer to give to the SPI layer while receiving data.

===================================================================
--- a/input/touchscreen/ads7846.c	(.../linux-2.6.19-at91/drivers)	(revision 634)
+++ b/input/touchscreen/ads7846.c	(.../linux-2.6.19-atmel-devel/drivers)	(revision 634)
@@ -4,6 +4,7 @@
  * Copyright (c) 2005 David Brownell
  * Copyright (c) 2006 Nokia Corporation
  * Various changes: Imre Deak <imre.deak@nokia.com>
+ * Ads7843 support: Atmel, Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
  *
  * Using code from:
  *  - corgi_ts.c
@@ -38,7 +39,8 @@
 /*
  * This code has been heavily tested on a Nokia 770, and lightly
  * tested on other ads7846 devices (OSK/Mistral, Lubbock).
- * Support for ads7843 and ads7845 has only been stubbed in.
+ * Support for ads7843 tested on Atmel at91sam926x-EK.
+ * Support for ads7845 has only been stubbed in.
  *
  * IRQ handling needs a workaround because of a shortcoming in handling
  * edge triggered IRQs on some platforms like the OMAP1/2. These
@@ -82,6 +84,7 @@ struct ads7846 {
 	u16			pressure_max;
 
 	u8			read_x, read_y, read_z1, read_z2, pwrdown;
+	u16			zerro;		/* to send zerros while receiving */
 	u16			dummy;		/* for the pwrdown read */
 	struct ts_event		tc;
 
@@ -151,6 +154,10 @@ struct ads7846 {
 #define	READ_X	(READ_12BIT_DFR(x)  | ADS_PD10_ADC_ON)
 #define	PWRDOWN	(READ_12BIT_DFR(y)  | ADS_PD10_PDOWN)	/* LAST */
 
+/* alternate ads7843 commands */
+#define	ALT_READ_Y	(READ_12BIT_DFR(y)  | ADS_PD10_ALL_ON)
+#define	ALT_READ_X	(READ_12BIT_DFR(x)  | ADS_PD10_ALL_ON)
+
 /* single-ended samples need to first power up reference voltage;
  * we leave both ADC and VREF powered
  */
@@ -171,6 +178,7 @@ struct ser_req {
 	u8			command;
 	u8			ref_off;
 	u16			scratch;
+	u16			zerro;
 	__be16			sample;
 	struct spi_message	msg;
 	struct spi_transfer	xfer[6];
@@ -203,6 +211,7 @@ static int ads7846_read12_ser(struct dev
 	req->ref_on = REF_ON;
 	req->xfer[0].tx_buf = &req->ref_on;
 	req->xfer[0].len = 1;
+	req->xfer[1].tx_buf = &req->zerro;
 	req->xfer[1].rx_buf = &req->scratch;
 	req->xfer[1].len = 2;
 
@@ -217,6 +226,7 @@ static int ads7846_read12_ser(struct dev
 	req->command = (u8) command;
 	req->xfer[2].tx_buf = &req->command;
 	req->xfer[2].len = 1;
+	req->xfer[3].tx_buf = &req->zerro;
 	req->xfer[3].rx_buf = &req->sample;
 	req->xfer[3].len = 2;
 
@@ -226,6 +236,7 @@ static int ads7846_read12_ser(struct dev
 	req->ref_off = REF_OFF;
 	req->xfer[4].tx_buf = &req->ref_off;
 	req->xfer[4].len = 1;
+	req->xfer[3].tx_buf = &req->zerro;
 	req->xfer[5].rx_buf = &req->scratch;
 	req->xfer[5].len = 2;
 
@@ -410,6 +421,50 @@ static void ads7846_rx(void *ads)
 	spin_unlock_irqrestore(&ts->lock, flags);
 }
 
+static void ads7843_rx(void *ads)
+{
+	struct ads7846		*ts = ads;
+	struct input_dev	*input_dev = ts->input;
+	u16			x, y;
+	unsigned long		flags;
+
+	
+	/* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
+	 * built from two 8 bit values written msb-first.
+	 */
+	x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
+	y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
+
+	/* range filtering */
+	if (x == MAX_12BIT)
+		x = 0;
+
+	if (ts->pendown) {
+		input_report_key(input_dev, BTN_TOUCH, 1);
+		input_report_abs(input_dev, ABS_PRESSURE, ts->pressure_max / 2);
+		input_report_abs(input_dev, ABS_X, x);
+		input_report_abs(input_dev, ABS_Y, y);
+	} else {
+		input_report_key(input_dev, BTN_TOUCH, 0);
+		input_report_abs(input_dev, ABS_PRESSURE, 0);
+	}
+
+	input_sync(input_dev);
+
+#ifdef	VERBOSE
+	pr_debug("%s: %d/%d%s\n", ts->spi->dev.bus_id,
+		x, y, ts->pendown ? "" : " UP");
+#endif
+
+	if (ts->pendown) {
+		spin_lock_irqsave(&ts->lock, flags);
+
+		mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+
+		spin_unlock_irqrestore(&ts->lock, flags);
+	}
+}
+
 static void ads7846_debounce(void *ads)
 {
 	struct ads7846		*ts = ads;
@@ -465,11 +520,25 @@ static void ads7846_timer(unsigned long 
 {
 	struct ads7846	*ts = (void *)handle;
 	int		status = 0;
+	int		alt_end_cycle = 0; /* ads7843 alternative cycle end */
+
+	if (ts->model == 7843) {
+		/* get sample */
+		ts->pendown = ts->get_pendown_state();
+		alt_end_cycle = ts->pending;
+	}
 
 	spin_lock_irq(&ts->lock);
 
-	if (unlikely(ts->msg_idx && !ts->pendown)) {
+	if (unlikely(!ts->pendown && (ts->msg_idx || alt_end_cycle))) {
 		/* measurement cycle ended */
+		if (ts->model == 7843) {
+			status = spi_async(ts->spi, ts->last_msg);
+			if (status)
+				dev_err(&ts->spi->dev,
+					"spi_async --> %d\n", status);
+		}
+
 		if (!device_suspended(&ts->spi->dev)) {
 			ts->irq_disabled = 0;
 			enable_irq(ts->spi->irq);
@@ -684,12 +753,17 @@ static int __devinit ads7846_probe(struc
 	spi_message_init(m);
 
 	/* y- still on; turn on only y+ (and ADC) */
-	ts->read_y = READ_Y;
+	if (ts->model == 7843) {
+		ts->read_y = ALT_READ_Y;
+	} else {
+		ts->read_y = READ_Y;
+	}
 	x->tx_buf = &ts->read_y;
 	x->len = 1;
 	spi_message_add_tail(x, m);
 
 	x++;
+	x->tx_buf = &ts->zerro;
 	x->rx_buf = &ts->tc.y;
 	x->len = 2;
 	spi_message_add_tail(x, m);
@@ -702,12 +776,17 @@ static int __devinit ads7846_probe(struc
 
 	/* turn y- off, x+ on, then leave in lowpower */
 	x++;
-	ts->read_x = READ_X;
+	if (ts->model == 7843) {
+		ts->read_x = ALT_READ_X;
+	} else {
+		ts->read_x = READ_X;
+	}
 	x->tx_buf = &ts->read_x;
 	x->len = 1;
 	spi_message_add_tail(x, m);
 
 	x++;
+	x->tx_buf = &ts->zerro;
 	x->rx_buf = &ts->tc.x;
 	x->len = 2;
 	spi_message_add_tail(x, m);
@@ -763,12 +842,17 @@ static int __devinit ads7846_probe(struc
 	spi_message_add_tail(x, m);
 
 	x++;
+	x->tx_buf = &ts->zerro;
 	x->rx_buf = &ts->dummy;
 	x->len = 2;
 	CS_CHANGE(*x);
 	spi_message_add_tail(x, m);
 
-	m->complete = ads7846_rx;
+	if (ts->model == 7843) {
+		m->complete = ads7843_rx;
+	} else {
+		m->complete = ads7846_rx;
+	}
 	m->context = ts;
 
 	ts->last_msg = m;
@@ -782,11 +866,16 @@ static int __devinit ads7846_probe(struc
 
 	dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
 
-	/* take a first sample, leaving nPENIRQ active; avoid
-	 * the touchscreen, in case it's not connected.
-	 */
-	(void) ads7846_read12_ser(&spi->dev,
-			  READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+	if (ts->model != 7843) {
+		/* take a first sample, leaving nPENIRQ active; avoid
+		 * the touchscreen, in case it's not connected.
+		 */
+		(void) ads7846_read12_ser(&spi->dev,
+				  READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+	} else {
+		(void) ads7846_read12_ser(&spi->dev,
+				  READ_12BIT_DFR(y) | ADS_PD10_ALL_ON);
+	}
 
 	/* ads7843/7845 don't have temperature sensors, and
 	 * use the other sensors a bit differently too
@@ -795,12 +884,14 @@ static int __devinit ads7846_probe(struc
 		device_create_file(&spi->dev, &dev_attr_temp0);
 		device_create_file(&spi->dev, &dev_attr_temp1);
 	}
-	if (ts->model != 7845)
+	if (ts->model != 7845 && ts->model != 7843)
 		device_create_file(&spi->dev, &dev_attr_vbatt);
-	device_create_file(&spi->dev, &dev_attr_vaux);
 
-	device_create_file(&spi->dev, &dev_attr_pen_down);
+	if (ts->model != 7843) {
+		device_create_file(&spi->dev, &dev_attr_vaux);
+	}
 
+	device_create_file(&spi->dev, &dev_attr_pen_down);
 	device_create_file(&spi->dev, &dev_attr_disable);
 
 	err = input_register_device(input_dev);
@@ -816,9 +907,12 @@ static int __devinit ads7846_probe(struc
 		device_remove_file(&spi->dev, &dev_attr_temp1);
 		device_remove_file(&spi->dev, &dev_attr_temp0);
 	}
-	if (ts->model != 7845)
+	if (ts->model != 7845 && ts->model != 7843)
 		device_remove_file(&spi->dev, &dev_attr_vbatt);
-	device_remove_file(&spi->dev, &dev_attr_vaux);
+
+	if (ts->model != 7843) {
+		device_remove_file(&spi->dev, &dev_attr_vaux);
+	}
 
 	free_irq(spi->irq, ts);
  err_free_mem:
@@ -841,9 +935,12 @@ static int __devexit ads7846_remove(stru
 		device_remove_file(&spi->dev, &dev_attr_temp1);
 		device_remove_file(&spi->dev, &dev_attr_temp0);
 	}
-	if (ts->model != 7845)
+	if (ts->model != 7845 && ts->model != 7843)
 		device_remove_file(&spi->dev, &dev_attr_vbatt);
-	device_remove_file(&spi->dev, &dev_attr_vaux);
+
+	if (ts->model != 7843) {
+		device_remove_file(&spi->dev, &dev_attr_vaux);
+	}
 
 	free_irq(ts->spi->irq, ts);
 	/* suspend left the IRQ disabled */



^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2007-03-01  4:53 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <4582BD29.4020203@rfo.atmel.com>
2006-12-20 23:13 ` [PATCH] input/spi: add ads7843 support to ads7846 touchscreen driver David Brownell
2006-12-21 13:08   ` Nicolas Ferre
2006-12-21 14:40     ` Nicolas Ferre
2006-12-22 20:05       ` David Brownell
2006-12-22 19:31     ` David Brownell
2006-12-22 20:14       ` Dmitry Torokhov
2006-12-22 19:25 [patch 2.6.20-rc1 6/6] input: ads7846 directly senses PENUP state David Brownell
2006-12-28 22:37 ` David Brownell
2006-12-29  6:22   ` Dmitry Torokhov
2006-12-29 20:26     ` David Brownell
2007-02-16 17:37       ` [PATCH] input/spi: add ads7843 support to ads7846 touchscreen driver Nicolas Ferre
2007-02-16 19:08         ` David Brownell
2007-02-19 12:48           ` Nicolas Ferre
2007-02-19 18:46             ` David Brownell
2007-02-20  9:19               ` Nicolas Ferre
2007-03-01  4:49                 ` Dmitry Torokhov
  -- strict thread matches above, loose matches on Subject: below --
2006-12-15 14:45 Nicolas FERRE
2006-12-20 22:03 ` Andrew Morton
2006-12-21  9:57   ` Nicolas Ferre

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.