diff options
| author | Imre Deak <imre.deak@nokia.com> | 2006-04-11 23:43:55 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-04-11 23:43:55 -0400 |
| commit | 7de90a8cb9c51145d7f60d8db17ce0fa07d1b281 (patch) | |
| tree | 81e2c0a54974c0a552474f5c5cc66d6082a8bfdd /drivers/input | |
| parent | c4febb94dae915da4423b81c487eabed9cef5cba (diff) | |
Input: ads7846 - miscellaneous fixes
- Add disable attribute to support device locking mode where
unintentional touch event shouldn't wake up the system;
- Update comments;
- Add missing spin_lock_init;
- Do device resume with the lock held;
- Do cleanup calls / free memory in the reverse order of initialization.
Signed-off-by: Imre Deak <imre.deak@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 | 144 |
1 files changed, 114 insertions, 30 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index bdec112e89c4..fec3b9b22309 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | * ADS7846 based touchscreen and sensor driver | 2 | * ADS7846 based touchscreen and sensor driver |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2005 David Brownell | 4 | * Copyright (c) 2005 David Brownell |
| 5 | * Copyright (c) 2006 Nokia Corporation | ||
| 6 | * Various changes: Imre Deak <imre.deak@nokia.com> | ||
| 5 | * | 7 | * |
| 6 | * Using code from: | 8 | * Using code from: |
| 7 | * - corgi_ts.c | 9 | * - corgi_ts.c |
| @@ -34,17 +36,25 @@ | |||
| 34 | 36 | ||
| 35 | 37 | ||
| 36 | /* | 38 | /* |
| 37 | * This code has been lightly tested on an ads7846. | 39 | * This code has been tested on an ads7846 / N770 device. |
| 38 | * Support for ads7843 and ads7845 has only been stubbed in. | 40 | * Support for ads7843 and ads7845 has only been stubbed in. |
| 39 | * | 41 | * |
| 40 | * Not yet done: investigate the values reported. Are x/y/pressure | 42 | * Not yet done: How accurate are the temperature and voltage |
| 41 | * event values sane enough for X11? How accurate are the temperature | 43 | * readings? (System-specific calibration should support |
| 42 | * and voltage readings? (System-specific calibration should support | ||
| 43 | * accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.) | 44 | * accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.) |
| 44 | * | 45 | * |
| 46 | * IRQ handling needs a workaround because of a shortcoming in handling | ||
| 47 | * edge triggered IRQs on some platforms like the OMAP1/2. These | ||
| 48 | * platforms don't handle the ARM lazy IRQ disabling properly, thus we | ||
| 49 | * have to maintain our own SW IRQ disabled status. This should be | ||
| 50 | * removed as soon as the affected platform's IRQ handling is fixed. | ||
| 51 | * | ||
| 45 | * app note sbaa036 talks in more detail about accurate sampling... | 52 | * app note sbaa036 talks in more detail about accurate sampling... |
| 46 | * that ought to help in situations like LCDs inducing noise (which | 53 | * that ought to help in situations like LCDs inducing noise (which |
| 47 | * can also be helped by using synch signals) and more generally. | 54 | * can also be helped by using synch signals) and more generally. |
| 55 | * This driver tries to utilize the measures described in the app | ||
| 56 | * note. The strength of filtering can be set in the board-* specific | ||
| 57 | * files. | ||
| 48 | */ | 58 | */ |
| 49 | 59 | ||
| 50 | #define TS_POLL_PERIOD msecs_to_jiffies(10) | 60 | #define TS_POLL_PERIOD msecs_to_jiffies(10) |
| @@ -91,6 +101,7 @@ struct ads7846 { | |||
| 91 | unsigned pending:1; /* P: lock */ | 101 | unsigned pending:1; /* P: lock */ |
| 92 | // FIXME remove "irq_disabled" | 102 | // FIXME remove "irq_disabled" |
| 93 | unsigned irq_disabled:1; /* P: lock */ | 103 | unsigned irq_disabled:1; /* P: lock */ |
| 104 | unsigned disabled:1; | ||
| 94 | }; | 105 | }; |
| 95 | 106 | ||
| 96 | /* leave chip selected when we're done, for quicker re-select? */ | 107 | /* leave chip selected when we're done, for quicker re-select? */ |
| @@ -161,6 +172,9 @@ struct ser_req { | |||
| 161 | struct spi_transfer xfer[6]; | 172 | struct spi_transfer xfer[6]; |
| 162 | }; | 173 | }; |
| 163 | 174 | ||
| 175 | static void ads7846_enable(struct ads7846 *ts); | ||
| 176 | static void ads7846_disable(struct ads7846 *ts); | ||
| 177 | |||
| 164 | static int ads7846_read12_ser(struct device *dev, unsigned command) | 178 | static int ads7846_read12_ser(struct device *dev, unsigned command) |
| 165 | { | 179 | { |
| 166 | struct spi_device *spi = to_spi_device(dev); | 180 | struct spi_device *spi = to_spi_device(dev); |
| @@ -257,6 +271,37 @@ static ssize_t ads7846_pen_down_show(struct device *dev, | |||
| 257 | 271 | ||
| 258 | static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL); | 272 | static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL); |
| 259 | 273 | ||
| 274 | static ssize_t ads7846_disable_show(struct device *dev, | ||
| 275 | struct device_attribute *attr, char *buf) | ||
| 276 | { | ||
| 277 | struct ads7846 *ts = dev_get_drvdata(dev); | ||
| 278 | |||
| 279 | return sprintf(buf, "%u\n", ts->disabled); | ||
| 280 | } | ||
| 281 | |||
| 282 | static ssize_t ads7846_disable_store(struct device *dev, | ||
| 283 | struct device_attribute *attr, | ||
| 284 | const char *buf, size_t count) | ||
| 285 | { | ||
| 286 | struct ads7846 *ts = dev_get_drvdata(dev); | ||
| 287 | char *endp; | ||
| 288 | int i; | ||
| 289 | |||
| 290 | i = simple_strtoul(buf, &endp, 10); | ||
| 291 | spin_lock_irq(&ts->lock); | ||
| 292 | |||
| 293 | if (i) | ||
| 294 | ads7846_disable(ts); | ||
| 295 | else | ||
| 296 | ads7846_enable(ts); | ||
| 297 | |||
| 298 | spin_unlock_irq(&ts->lock); | ||
| 299 | |||
| 300 | return count; | ||
| 301 | } | ||
| 302 | |||
| 303 | static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store); | ||
| 304 | |||
| 260 | /*--------------------------------------------------------------------------*/ | 305 | /*--------------------------------------------------------------------------*/ |
| 261 | 306 | ||
| 262 | /* | 307 | /* |
| @@ -396,12 +441,9 @@ static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) | |||
| 396 | { | 441 | { |
| 397 | struct ads7846 *ts = handle; | 442 | struct ads7846 *ts = handle; |
| 398 | unsigned long flags; | 443 | unsigned long flags; |
| 399 | int r = IRQ_HANDLED; | ||
| 400 | 444 | ||
| 401 | spin_lock_irqsave(&ts->lock, flags); | 445 | spin_lock_irqsave(&ts->lock, flags); |
| 402 | if (ts->irq_disabled) | 446 | if (likely(!ts->irq_disabled && !ts->disabled)) { |
| 403 | r = IRQ_HANDLED; | ||
| 404 | else { | ||
| 405 | if (!ts->irq_disabled) { | 447 | if (!ts->irq_disabled) { |
| 406 | /* REVISIT irq logic for many ARM chips has cloned a | 448 | /* REVISIT irq logic for many ARM chips has cloned a |
| 407 | * bug wherein disabling an irq in its handler won't | 449 | * bug wherein disabling an irq in its handler won't |
| @@ -419,20 +461,17 @@ static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) | |||
| 419 | } | 461 | } |
| 420 | } | 462 | } |
| 421 | spin_unlock_irqrestore(&ts->lock, flags); | 463 | spin_unlock_irqrestore(&ts->lock, flags); |
| 422 | return r; | 464 | |
| 465 | return IRQ_HANDLED; | ||
| 423 | } | 466 | } |
| 424 | 467 | ||
| 425 | /*--------------------------------------------------------------------------*/ | 468 | /*--------------------------------------------------------------------------*/ |
| 426 | 469 | ||
| 427 | static int | 470 | /* Must be called with ts->lock held */ |
| 428 | ads7846_suspend(struct spi_device *spi, pm_message_t message) | 471 | static void ads7846_disable(struct ads7846 *ts) |
| 429 | { | 472 | { |
| 430 | struct ads7846 *ts = dev_get_drvdata(&spi->dev); | 473 | if (ts->disabled) |
| 431 | unsigned long flags; | 474 | return; |
| 432 | |||
| 433 | spin_lock_irqsave(&ts->lock, flags); | ||
| 434 | |||
| 435 | spi->dev.power.power_state = message; | ||
| 436 | 475 | ||
| 437 | /* are we waiting for IRQ, or polling? */ | 476 | /* are we waiting for IRQ, or polling? */ |
| 438 | if (!ts->pendown) { | 477 | if (!ts->pendown) { |
| @@ -448,9 +487,9 @@ ads7846_suspend(struct spi_device *spi, pm_message_t message) | |||
| 448 | mod_timer(&ts->timer, jiffies); | 487 | mod_timer(&ts->timer, jiffies); |
| 449 | 488 | ||
| 450 | while (ts->pendown || ts->pending) { | 489 | while (ts->pendown || ts->pending) { |
| 451 | spin_unlock_irqrestore(&ts->lock, flags); | 490 | spin_unlock_irq(&ts->lock); |
| 452 | msleep(1); | 491 | msleep(1); |
| 453 | spin_lock_irqsave(&ts->lock, flags); | 492 | spin_lock_irq(&ts->lock); |
| 454 | } | 493 | } |
| 455 | } | 494 | } |
| 456 | 495 | ||
| @@ -458,17 +497,46 @@ ads7846_suspend(struct spi_device *spi, pm_message_t message) | |||
| 458 | * leave it that way after every request | 497 | * leave it that way after every request |
| 459 | */ | 498 | */ |
| 460 | 499 | ||
| 461 | spin_unlock_irqrestore(&ts->lock, flags); | 500 | ts->disabled = 1; |
| 501 | } | ||
| 502 | |||
| 503 | /* Must be called with ts->lock held */ | ||
