/*
- * This code has been tested on an ads7846 / N770 device.
+ * 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.
*
- * Not yet done: How accurate are the temperature and voltage
- * readings? (System-specific calibration should support
- * accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.)
- *
* IRQ handling needs a workaround because of a shortcoming in handling
* edge triggered IRQs on some platforms like the OMAP1/2. These
* platforms don't handle the ARM lazy IRQ disabling properly, thus we
__be16 x;
__be16 y;
__be16 z1, z2;
+ int ignore;
};
struct ads7846 {
u16 model;
u16 vref_delay_usecs;
u16 x_plate_ohms;
+ u16 pressure_max;
u8 read_x, read_y, read_z1, read_z2, pwrdown;
u16 dummy; /* for the pwrdown read */
struct spi_transfer xfer[10];
struct spi_message msg[5];
+ struct spi_message *last_msg;
int msg_idx;
int read_cnt;
+ int read_rep;
int last_read;
u16 debounce_max;
u16 debounce_tol;
+ u16 debounce_rep;
spinlock_t lock;
struct timer_list timer; /* P: lock */
if (req->msg.status)
status = req->msg.status;
+
+ /* on-wire is a must-ignore bit, a BE12 value, then padding */
sample = be16_to_cpu(req->sample);
- sample = sample >> 4;
- kfree(req);
+ sample = sample >> 3;
+ sample &= 0x0fff;
+ kfree(req);
return status ? status : sample;
}
u16 x, y, z1, z2;
unsigned long flags;
- /* adjust: 12 bit samples (left aligned), built from
- * two 8 bit values writen msb-first.
+ /* 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) >> 4;
- y = be16_to_cpu(ts->tc.y) >> 4;
- z1 = be16_to_cpu(ts->tc.z1) >> 4;
- z2 = be16_to_cpu(ts->tc.z2) >> 4;
+ x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
+ y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
+ z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff;
+ z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff;
/* range filtering */
if (x == MAX_12BIT)
} else
Rt = 0;
+ /* Sample found inconsistent by debouncing or pressure is beyond
+ * the maximum. Don't report it to user space, repeat at least
+ * once more the measurement */
+ if (ts->tc.ignore || Rt > ts->pressure_max) {
+ mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+ 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).
if (Rt) {
input_report_abs(input_dev, ABS_X, x);
input_report_abs(input_dev, ABS_Y, y);
- input_report_abs(input_dev, ABS_PRESSURE, Rt);
sync = 1;
}
- if (sync)
+
+ if (sync) {
+ input_report_abs(input_dev, ABS_PRESSURE, Rt);
input_sync(input_dev);
+ }
#ifdef VERBOSE
if (Rt || ts->pendown)
struct ads7846 *ts = ads;
struct spi_message *m;
struct spi_transfer *t;
- u16 val;
+ int val;
int status;
m = &ts->msg[ts->msg_idx];
t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
- val = (*(u16 *)t->rx_buf) >> 3;
-
- if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol
- && ts->read_cnt < ts->debounce_max)) {
- /* Repeat it, if this was the first read or the read wasn't
- * consistent enough
- */
- ts->read_cnt++;
- ts->last_read = val;
+ val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff;
+ if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
+ /* Repeat it, if this was the first read or the read
+ * wasn't consistent enough. */
+ if (ts->read_cnt < ts->debounce_max) {
+ ts->last_read = val;
+ ts->read_cnt++;
+ } else {
+ /* Maximum number of debouncing reached and still
+ * not enough number of consistent readings. Abort
+ * the whole sample, repeat it in the next sampling
+ * period.
+ */
+ ts->tc.ignore = 1;
+ ts->read_cnt = 0;
+ /* Last message will contain ads7846_rx() as the
+ * completion function.
+ */
+ m = ts->last_msg;
+ }
+ /* Start over collecting consistent readings. */
+ ts->read_rep = 0;
} else {
- /* Go for the next read */
- ts->msg_idx++;
- ts->read_cnt = 0;
- m++;
+ if (++ts->read_rep > ts->debounce_rep) {
+ /* Got a good reading for this coordinate,
+ * go for the next one. */
+ ts->tc.ignore = 0;
+ ts->msg_idx++;
+ ts->read_cnt = 0;
+ ts->read_rep = 0;
+ m++;
+ } else
+ /* Read more values that are consistent. */
+ ts->read_cnt++;
}
status = spi_async(ts->spi, m);
if (status)
spin_lock_irq(&ts->lock);
if (unlikely(ts->msg_idx && !ts->pendown)) {
- /* measurment cycle ended */
+ /* measurement cycle ended */
if (!device_suspended(&ts->spi->dev)) {
ts->irq_disabled = 0;
enable_irq(ts->spi->irq);
spin_lock_irqsave(&ts->lock, flags);
if (likely(ts->get_pendown_state())) {
if (!ts->irq_disabled) {
- /* REVISIT irq logic for many ARM chips has cloned a
- * bug wherein disabling an irq in its handler won't
- * work;(it's disabled lazily, and too late to work.
- * until all their irq logic is fixed, we must shadow
- * that state here.
+ /* The ARM do_simple_IRQ() dispatcher doesn't act
+ * like the other dispatchers: it will report IRQs
+ * even after they've been disabled. We work around
+ * that here. (The "generic irq" framework may help...)
*/
ts->irq_disabled = 1;
disable_irq(ts->spi->irq);
return -EINVAL;
}
+ /* REVISIT when the irq can be triggered active-low, or if for some
+ * reason the touchscreen isn't hooked up, we don't need to access
+ * the pendown state.
+ */
if (pdata->get_pendown_state == NULL) {
dev_dbg(&spi->dev, "no get_pendown_state function?\n");
return -EINVAL;
}
- /* We'd set the wordsize to 12 bits ... except that some controllers
- * will then treat the 8 bit command words as 12 bits (and drop the
- * four MSBs of the 12 bit result). Result: inputs must be shifted
- * to discard the four garbage LSBs.
+ /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
+ * that even if the hardware can do that, the SPI controller driver
+ * may not. So we stick to very-portable 8 bit words, both RX and TX.
*/
+ spi->bits_per_word = 8;
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
input_dev = input_allocate_device();
ts->model = pdata->model ? : 7846;
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
- ts->debounce_max = pdata->debounce_max ? : 1;
- ts->debounce_tol = pdata->debounce_tol ? : 10;
+ ts->pressure_max = pdata->pressure_max ? : ~0;
+ if (pdata->debounce_max) {
+ ts->debounce_max = pdata->debounce_max;
+ ts->debounce_tol = pdata->debounce_tol;
+ ts->debounce_rep = pdata->debounce_rep;
+ if (ts->debounce_rep > ts->debounce_max + 1)
+ ts->debounce_rep = ts->debounce_max - 1;
+ } else
+ ts->debounce_tol = ~0;
ts->get_pendown_state = pdata->get_pendown_state;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
m->complete = ads7846_rx;
m->context = ts;
+ ts->last_msg = m;
+
if (request_irq(spi->irq, ads7846_irq,
SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
- spi->dev.bus_id, ts)) {
+ spi->dev.driver->name, ts)) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
err = -EBUSY;
goto err_free_mem;