[PATCH] input/spi: add ads7843 support to ads7846 touchscreen driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <[email protected]>
---

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 <[email protected]>
+ * Ads7843 support: Atmel, Nicolas Ferre <[email protected]>
 *
 * 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 */


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux