diff options
| author | Imre Deak <imre.deak@nokia.com> | 2006-04-11 23:42:03 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-04-11 23:42:03 -0400 |
| commit | 0b7018aae7e1798f55f736b9a77c201708aa0e33 (patch) | |
| tree | b561dbcdb07540ffc76616894dddfa8f787f9202 /drivers/input/touchscreen | |
| parent | 53a0ef89e95c725f3faab98573770aeb7429c1a3 (diff) | |
Input: ads7846 - debouncing and rudimentary sample filtering
Some touchscreens seem to oscillate heavily for a while after touching
the screen. Implement support for sampling the screen until we get two
consecutive values that are close enough.
Signed-off-by: Imre Deak <imre.deak@nokia.com>
Signed-off-by: Juha Yrjola <juha.yrjola@nokia.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/touchscreen')
| -rw-r--r-- | drivers/input/touchscreen/ads7846.c | 156 |
1 files changed, 118 insertions, 38 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 54d433477860..8670cd13bd5d 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c | |||
| @@ -77,7 +77,13 @@ struct ads7846 { | |||
| 77 | struct ts_event tc; | 77 | struct ts_event tc; |
| 78 | 78 | ||
| 79 | struct spi_transfer xfer[10]; | 79 | struct spi_transfer xfer[10]; |
| 80 | struct spi_message msg; | 80 | struct spi_message msg[5]; |
| 81 | int msg_idx; | ||
| 82 | int read_cnt; | ||
| 83 | int last_read; | ||
| 84 | |||
| 85 | u16 debounce_max; | ||
| 86 | u16 debounce_tol; | ||
| 81 | 87 | ||
| 82 | spinlock_t lock; | 88 | spinlock_t lock; |
| 83 | struct timer_list timer; /* P: lock */ | 89 | struct timer_list timer; /* P: lock */ |
| @@ -167,7 +173,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) | |||
| 167 | if (!req) | 173 | if (!req) |
| 168 | return -ENOMEM; | 174 | return -ENOMEM; |
| 169 | 175 | ||
| 170 | INIT_LIST_HEAD(&req->msg.transfers); | 176 | spi_message_init(&req->msg); |
| 171 | 177 | ||
| 172 | /* activate reference, so it has time to settle; */ | 178 | /* activate reference, so it has time to settle; */ |
| 173 | req->ref_on = REF_ON; | 179 | req->ref_on = REF_ON; |
| @@ -344,31 +350,76 @@ static void ads7846_rx(void *ads) | |||
| 344 | spin_unlock_irqrestore(&ts->lock, flags); | 350 | spin_unlock_irqrestore(&ts->lock, flags); |
| 345 | } | 351 | } |
| 346 | 352 | ||
| 353 | static void ads7846_debounce(void *ads) | ||
| 354 | { | ||
| 355 | struct ads7846 *ts = ads; | ||
| 356 | struct spi_message *m; | ||
| 357 | struct spi_transfer *t; | ||
| 358 | u16 val; | ||
| 359 | int status; | ||
| 360 | |||
| 361 | m = &ts->msg[ts->msg_idx]; | ||
| 362 | t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); | ||
| 363 | val = (*(u16 *)t->rx_buf) >> 3; | ||
| 364 | |||
| 365 | if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol | ||
| 366 | && ts->read_cnt < ts->debounce_max)) { | ||
| 367 | /* Repeat it, if this was the first read or the read wasn't | ||
| 368 | * consistent enough | ||
| 369 | */ | ||
| 370 | ts->read_cnt++; | ||
| 371 | ts->last_read = val; | ||
| 372 | } else { | ||
| 373 | /* Go for the next read */ | ||
| 374 | ts->msg_idx++; | ||
| 375 | ts->read_cnt = 0; | ||
| 376 | m++; | ||
| 377 | } | ||
| 378 | status = spi_async(ts->spi, m); | ||
| 379 | if (status) | ||
| 380 | dev_err(&ts->spi->dev, "spi_async --> %d\n", | ||
| 381 | status); | ||
| 382 | } | ||
| 383 | |||
| 347 | static void ads7846_timer(unsigned long handle) | 384 | static void ads7846_timer(unsigned long handle) |
| 348 | { | 385 | { |
| 349 | struct ads7846 *ts = (void *)handle; | 386 | struct ads7846 *ts = (void *)handle; |
| 350 | int status = 0; | 387 | int status = 0; |
| 351 | unsigned long flags; | 388 | |
| 389 | ts->msg_idx = 0; | ||
| 390 | status = spi_async(ts->spi, &ts->msg[0]); | ||
| 391 | if (status) | ||
| 392 | dev_err(&ts->spi->dev, "spi_async --> %d\n", status); | ||
| 393 | } | ||
| 394 | |||
| 395 | static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) | ||
| 396 | { | ||
| 397 | struct ads7846 *ts = handle; | ||
| 398 | unsigned long flags; | ||
| 399 | int r = IRQ_HANDLED; | ||
| 352 | 400 | ||
| 353 | spin_lock_irqsave(&ts->lock, flags); | 401 | spin_lock_irqsave(&ts->lock, flags); |
| 354 | if (!ts->pending) { | 402 | if (ts->irq_disabled) |
| 355 | ts->pending = 1; | 403 | r = IRQ_HANDLED; |
| 404 | else { | ||
| 356 | if (!ts->irq_disabled) { | 405 | if (!ts->irq_disabled) { |
| 406 | /* REVISIT irq logic for many ARM chips has cloned a | ||
| 407 | * bug wherein disabling an irq in its handler won't | ||
| 408 | * work;(it's disabled lazily, and too late to work. | ||
| 409 | * until all their irq logic is fixed, we must shadow | ||
| 410 | * that state here. | ||
| 411 | */ | ||
| 357 | ts->irq_disabled = 1; | 412 | ts->irq_disabled = 1; |
| 413 | |||
| 358 | disable_irq(ts->spi->irq); | 414 | disable_irq(ts->spi->irq); |
| 359 | } | 415 | } |
| 360 | status = spi_async(ts->spi, &ts->msg); | 416 | if (!ts->pending) { |
| 361 | if (status) | 417 | ts->pending = 1; |
| 362 | dev_err(&ts->spi->dev, "spi_async --> %d\n", | 418 | mod_timer(&ts->timer, jiffies); |
| 363 | status); | 419 | } |
| 364 | } | 420 | } |
| 365 | spin_unlock_irqrestore(&ts->lock, flags); | 421 | spin_unlock_irqrestore(&ts->lock, flags); |
| 366 | } | 422 | return r; |
| 367 | |||
| 368 | static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) | ||
| 369 | { | ||
| 370 | ads7846_timer((unsigned long) handle); | ||
| 371 | return IRQ_HANDLED; | ||
| 372 | } | 423 | } |
| 373 | 424 | ||
| 374 | /*--------------------------------------------------------------------------*/ | 425 | /*--------------------------------------------------------------------------*/ |
| @@ -426,6 +477,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
| 426 | struct ads7846 *ts; | 477 | struct ads7846 *ts; |
| 427 | struct input_dev *input_dev; | 478 | struct input_dev *input_dev; |
| 428 | struct ads7846_platform_data *pdata = spi->dev.platform_data; | 479 | struct ads7846_platform_data *pdata = spi->dev.platform_data; |
| 480 | struct spi_message *m; | ||
| 429 | struct spi_transfer *x; | 481 | struct spi_transfer *x; |
| 430 | int err; | 482 | int err; |
| 431 | 483 | ||
| @@ -472,6 +524,8 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
| 472 | ts->model = pdata->model ? : 7846; | 524 | ts->model = pdata->model ? : 7846; |
| 473 | ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; | 525 | ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; |
| 474 | ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; | 526 | ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; |
| 527 | ts->debounce_max = pdata->debounce_max ? : 1; | ||
| 528 | ts->debounce_tol = pdata->debounce_tol ? : 10; | ||
| 475 | 529 | ||
| 476 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); | 530 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); |
| 477 | 531 | ||
| @@ -495,72 +549,98 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
| 495 | /* set up the transfers to read touchscreen state; this assumes we | 549 | /* set up the transfers to read touchscreen state; this assumes we |
| 496 | * use formula #2 for pressure, not #3. | 550 | * use formula #2 for pressure, not #3. |
| 497 | */ | 551 | */ |
| 498 | INIT_LIST_HEAD(&ts->msg.transfers); | 552 | m = &ts->msg[0]; |
| 499 | x = ts->xfer; | 553 | x = ts->xfer; |
| 500 | 554 | ||
| 555 | spi_message_init(m); | ||
| 556 | |||
| 501 | /* y- still on; turn on only y+ (and ADC) */ | 557 | /* y- still on; turn on only y+ (and ADC) */ |
| 502 | ts->read_y = READ_Y; | 558 | ts->read_y = READ_Y; |
| 503 | x->tx_buf = &ts->read_y; | 559 | x->tx_buf = &ts->read_y; |
| 504 | x->len = 1; | 560 | x->len = 1; |
| 505 | spi_message_add_tail(x, &ts->msg); | 561 | spi_message_add_tail(x, m); |
| 506 | 562 | ||
| 507 | x++; | 563 | x++; |
| 508 | x->rx_buf = &ts->tc.y; | 564 | x->rx_buf = &ts->tc.y; |
| 509 | x->len = 2; | 565 | x->len = 2; |
| 510 | spi_message_add_tail(x, &ts->msg); | 566 | spi_message_add_tail(x, m); |
| 567 | |||
| 568 | m->complete = ads7846_debounce; | ||
| 569 | m->context = ts; | ||
