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 | |
| 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')
| -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; | ||
| 570 | |||
| 571 | m++; | ||
| 572 | spi_message_init(m); | ||
| 573 | |||
| 574 | /* turn y- off, x+ on, then leave in lowpower */ | ||
| 575 | x++; | ||
| 576 | ts->read_x = READ_X; | ||
| 577 | x->tx_buf = &ts->read_x; | ||
| 578 | x->len = 1; | ||
| 579 | spi_message_add_tail(x, m); | ||
| 580 | |||
| 581 | x++; | ||
| 582 | x->rx_buf = &ts->tc.x; | ||
| 583 | x->len = 2; | ||
| 584 | spi_message_add_tail(x, m); | ||
| 585 | |||
| 586 | m->complete = ads7846_debounce; | ||
| 587 | m->context = ts; | ||
| 511 | 588 | ||
| 512 | /* turn y+ off, x- on; we'll use formula #2 */ | 589 | /* turn y+ off, x- on; we'll use formula #2 */ |
| 513 | if (ts->model == 7846) { | 590 | if (ts->model == 7846) { |
| 591 | m++; | ||
| 592 | spi_message_init(m); | ||
| 593 | |||
| 514 | x++; | 594 | x++; |
| 515 | ts->read_z1 = READ_Z1; | 595 | ts->read_z1 = READ_Z1; |
| 516 | x->tx_buf = &ts->read_z1; | 596 | x->tx_buf = &ts->read_z1; |
| 517 | x->len = 1; | 597 | x->len = 1; |
| 518 | spi_message_add_tail(x, &ts->msg); | 598 | spi_message_add_tail(x, m); |
| 519 | 599 | ||
| 520 | x++; | 600 | x++; |
| 521 | x->rx_buf = &ts->tc.z1; | 601 | x->rx_buf = &ts->tc.z1; |
| 522 | x->len = 2; | 602 | x->len = 2; |
| 523 | spi_message_add_tail(x, &ts->msg); | 603 | spi_message_add_tail(x, m); |
| 604 | |||
| 605 | m->complete = ads7846_debounce; | ||
| 606 | m->context = ts; | ||
| 607 | |||
| 608 | m++; | ||
| 609 | spi_message_init(m); | ||
| 524 | 610 | ||
| 525 | x++; | 611 | x++; |
| 526 | ts->read_z2 = READ_Z2; | 612 | ts->read_z2 = READ_Z2; |
| 527 | x->tx_buf = &ts->read_z2; | 613 | x->tx_buf = &ts->read_z2; |
| 528 | x->len = 1; | 614 | x->len = 1; |
| 529 | spi_message_add_tail(x, &ts->msg); | 615 | spi_message_add_tail(x, m); |
| 530 | 616 | ||
| 531 | x++; | 617 | x++; |
| 532 | x->rx_buf = &ts->tc.z2; | 618 | x->rx_buf = &ts->tc.z2; |
| 533 | x->len = 2; | 619 | x->len = 2; |
| 534 | spi_message_add_tail(x, &ts->msg); | 620 | spi_message_add_tail(x, m); |
| 535 | } | ||
| 536 | 621 | ||
| 537 | /* turn y- off, x+ on, then leave in lowpower */ | 622 | m->complete = ads7846_debounce; |
| 538 | x++; | 623 | m->context = ts; |
| 539 | ts->read_x = READ_X; | 624 | } |
| 540 | x->tx_buf = &ts->read_x; | ||
| 541 | x->len = 1; | ||
| 542 | spi_message_add_tail(x, &ts->msg); | ||
| 543 | |||
| 544 | x++; | ||
| 545 | x->rx_buf = &ts->tc.x; | ||
| 546 | x->len = 2; | ||
| 547 | spi_message_add_tail(x, &ts->msg); | ||
| 548 | 625 | ||
| 549 | /* power down */ | 626 | /* power down */ |
| 627 | m++; | ||
| 628 | spi_message_init(m); | ||
| 629 | |||
| 550 | x++; | 630 | x++; |
| 551 | ts->pwrdown = PWRDOWN; | 631 | ts->pwrdown = PWRDOWN; |
| 552 | x->tx_buf = &ts->pwrdown; | 632 | x->tx_buf = &ts->pwrdown; |
| 553 | x->len = 1; | 633 | x->len = 1; |
| 554 | spi_message_add_tail(x, &ts->msg); | 634 | spi_message_add_tail(x, m); |
| 555 | 635 | ||
| 556 | x++; | 636 | x++; |
| 557 | x->rx_buf = &ts->dummy; | 637 | x->rx_buf = &ts->dummy; |
| 558 | x->len = 2; | 638 | x->len = 2; |
| 559 | CS_CHANGE(*x); | 639 | CS_CHANGE(*x); |
| 560 | spi_message_add_tail(x, &ts->msg); | 640 | spi_message_add_tail(x, m); |
| 561 | 641 | ||
| 562 | ts->msg.complete = ads7846_rx; | 642 | m->complete = ads7846_rx; |
| 563 | ts->msg.context = ts; | 643 | m->context = ts; |
| 564 | 644 | ||
| 565 | if (request_irq(spi->irq, ads7846_irq, | 645 | if (request_irq(spi->irq, ads7846_irq, |
| 566 | SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING, | 646 | SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING, |
