[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <4582B4F4.2050106@rfo.atmel.com>
Date: Fri, 15 Dec 2006 15:45:08 +0100
From: Nicolas FERRE <nicolas.ferre@....atmel.com>
To: David Brownell <d-b@...bell.net>
CC: linux-kernel@...r.kernel.org
Subject: [PATCH] input/spi: add ads7843 support to ads7846 touchscreen driver
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@....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@...ia.com>
+ * Ads7843 support: Atmel, Nicolas Ferre <nicolas.ferre@....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 */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists