diff options
Diffstat (limited to 'drivers/mfd/ucb1x00-ts.c')
-rw-r--r-- | drivers/mfd/ucb1x00-ts.c | 39 |
1 files changed, 31 insertions, 8 deletions
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 63a3cbdfa3f3..1e0e20c0e082 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c | |||
@@ -20,8 +20,9 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/moduleparam.h> | 21 | #include <linux/moduleparam.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/smp.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
25 | #include <linux/spinlock.h> | ||
25 | #include <linux/completion.h> | 26 | #include <linux/completion.h> |
26 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
27 | #include <linux/string.h> | 28 | #include <linux/string.h> |
@@ -32,7 +33,6 @@ | |||
32 | #include <linux/kthread.h> | 33 | #include <linux/kthread.h> |
33 | #include <linux/mfd/ucb1x00.h> | 34 | #include <linux/mfd/ucb1x00.h> |
34 | 35 | ||
35 | #include <mach/dma.h> | ||
36 | #include <mach/collie.h> | 36 | #include <mach/collie.h> |
37 | #include <asm/mach-types.h> | 37 | #include <asm/mach-types.h> |
38 | 38 | ||
@@ -42,6 +42,8 @@ struct ucb1x00_ts { | |||
42 | struct input_dev *idev; | 42 | struct input_dev *idev; |
43 | struct ucb1x00 *ucb; | 43 | struct ucb1x00 *ucb; |
44 | 44 | ||
45 | spinlock_t irq_lock; | ||
46 | unsigned irq_disabled; | ||
45 | wait_queue_head_t irq_wait; | 47 | wait_queue_head_t irq_wait; |
46 | struct task_struct *rtask; | 48 | struct task_struct *rtask; |
47 | u16 x_res; | 49 | u16 x_res; |
@@ -238,7 +240,12 @@ static int ucb1x00_thread(void *_ts) | |||
238 | if (ucb1x00_ts_pen_down(ts)) { | 240 | if (ucb1x00_ts_pen_down(ts)) { |
239 | set_current_state(TASK_INTERRUPTIBLE); | 241 | set_current_state(TASK_INTERRUPTIBLE); |
240 | 242 | ||
241 | ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING); | 243 | spin_lock_irq(&ts->irq_lock); |
244 | if (ts->irq_disabled) { | ||
245 | ts->irq_disabled = 0; | ||
246 | enable_irq(ts->ucb->irq_base + UCB_IRQ_TSPX); | ||
247 | } | ||
248 | spin_unlock_irq(&ts->irq_lock); | ||
242 | ucb1x00_disable(ts->ucb); | 249 | ucb1x00_disable(ts->ucb); |
243 | 250 | ||
244 | /* | 251 | /* |
@@ -281,23 +288,37 @@ static int ucb1x00_thread(void *_ts) | |||
281 | * We only detect touch screen _touches_ with this interrupt | 288 | * We only detect touch screen _touches_ with this interrupt |
282 | * handler, and even then we just schedule our task. | 289 | * handler, and even then we just schedule our task. |
283 | */ | 290 | */ |
284 | static void ucb1x00_ts_irq(int idx, void *id) | 291 | static irqreturn_t ucb1x00_ts_irq(int irq, void *id) |
285 | { | 292 | { |
286 | struct ucb1x00_ts *ts = id; | 293 | struct ucb1x00_ts *ts = id; |
287 | 294 | ||
288 | ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); | 295 | spin_lock(&ts->irq_lock); |
296 | ts->irq_disabled = 1; | ||
297 | disable_irq_nosync(ts->ucb->irq_base + UCB_IRQ_TSPX); | ||
298 | spin_unlock(&ts->irq_lock); | ||
289 | wake_up(&ts->irq_wait); | 299 | wake_up(&ts->irq_wait); |
300 | |||
301 | return IRQ_HANDLED; | ||
290 | } | 302 | } |
291 | 303 | ||
292 | static int ucb1x00_ts_open(struct input_dev *idev) | 304 | static int ucb1x00_ts_open(struct input_dev *idev) |
293 | { | 305 | { |
294 | struct ucb1x00_ts *ts = input_get_drvdata(idev); | 306 | struct ucb1x00_ts *ts = input_get_drvdata(idev); |
307 | unsigned long flags = 0; | ||
295 | int ret = 0; | 308 | int ret = 0; |
296 | 309 | ||
297 | BUG_ON(ts->rtask); | 310 | BUG_ON(ts->rtask); |
298 | 311 | ||
312 | if (machine_is_collie()) | ||
313 | flags = IRQF_TRIGGER_RISING; | ||
314 | else | ||
315 | flags = IRQF_TRIGGER_FALLING; | ||
316 | |||
317 | ts->irq_disabled = 0; | ||
318 | |||
299 | init_waitqueue_head(&ts->irq_wait); | 319 | init_waitqueue_head(&ts->irq_wait); |
300 | ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); | 320 | ret = request_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ucb1x00_ts_irq, |
321 | flags, "ucb1x00-ts", ts); | ||
301 | if (ret < 0) | 322 | if (ret < 0) |
302 | goto out; | 323 | goto out; |
303 | 324 | ||
@@ -314,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev) | |||
314 | if (!IS_ERR(ts->rtask)) { | 335 | if (!IS_ERR(ts->rtask)) { |
315 | ret = 0; | 336 | ret = 0; |
316 | } else { | 337 | } else { |
317 | ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); | 338 | free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts); |
318 | ts->rtask = NULL; | 339 | ts->rtask = NULL; |
319 | ret = -EFAULT; | 340 | ret = -EFAULT; |
320 | } | 341 | } |
@@ -334,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev) | |||
334 | kthread_stop(ts->rtask); | 355 | kthread_stop(ts->rtask); |
335 | 356 | ||
336 | ucb1x00_enable(ts->ucb); | 357 | ucb1x00_enable(ts->ucb); |
337 | ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); | 358 | free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts); |
338 | ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); | 359 | ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); |
339 | ucb1x00_disable(ts->ucb); | 360 | ucb1x00_disable(ts->ucb); |
340 | } | 361 | } |
@@ -359,11 +380,13 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) | |||
359 | ts->ucb = dev->ucb; | 380 | ts->ucb = dev->ucb; |
360 | ts->idev = idev; | 381 | ts->idev = idev; |
361 | ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; | 382 | ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; |
383 | spin_lock_init(&ts->irq_lock); | ||
362 | 384 | ||
363 | idev->name = "Touchscreen panel"; | 385 | idev->name = "Touchscreen panel"; |
364 | idev->id.product = ts->ucb->id; | 386 | idev->id.product = ts->ucb->id; |
365 | idev->open = ucb1x00_ts_open; | 387 | idev->open = ucb1x00_ts_open; |
366 | idev->close = ucb1x00_ts_close; | 388 | idev->close = ucb1x00_ts_close; |
389 | idev->dev.parent = &ts->ucb->dev; | ||
367 | 390 | ||
368 | idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); | 391 | idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); |
369 | idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | 392 | idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); |