diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-01-21 09:58:28 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-02-18 18:15:43 -0500 |
commit | a3364409c4af8bae42d04def48dc11409787e503 (patch) | |
tree | 317d68920998bc5823d2879a49d49f27a8aed279 /drivers/mfd/ucb1x00-ts.c | |
parent | cf4abfcc0df2985ff6061f74e63b8353f2a1d0bc (diff) |
MFD: ucb1x00: convert to use genirq
Convert the ucb1x00 driver to use genirq's interrupt services, rather
than its own private implementation. This allows a wider range of
drivers to use the GPIO interrupts (such as the gpio_keys driver)
without being aware of the UCB1x00's private IRQ system.
This prevents the UCB1x00 core driver from being built as a module,
so adjust the configuration to add that restriction.
Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mfd/ucb1x00-ts.c')
-rw-r--r-- | drivers/mfd/ucb1x00-ts.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 742d0c7bbbc2..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> |
@@ -41,6 +42,8 @@ struct ucb1x00_ts { | |||
41 | struct input_dev *idev; | 42 | struct input_dev *idev; |
42 | struct ucb1x00 *ucb; | 43 | struct ucb1x00 *ucb; |
43 | 44 | ||
45 | spinlock_t irq_lock; | ||
46 | unsigned irq_disabled; | ||
44 | wait_queue_head_t irq_wait; | 47 | wait_queue_head_t irq_wait; |
45 | struct task_struct *rtask; | 48 | struct task_struct *rtask; |
46 | u16 x_res; | 49 | u16 x_res; |
@@ -237,7 +240,12 @@ static int ucb1x00_thread(void *_ts) | |||
237 | if (ucb1x00_ts_pen_down(ts)) { | 240 | if (ucb1x00_ts_pen_down(ts)) { |
238 | set_current_state(TASK_INTERRUPTIBLE); | 241 | set_current_state(TASK_INTERRUPTIBLE); |
239 | 242 | ||
240 | 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); | ||
241 | ucb1x00_disable(ts->ucb); | 249 | ucb1x00_disable(ts->ucb); |
242 | 250 | ||
243 | /* | 251 | /* |
@@ -280,23 +288,37 @@ static int ucb1x00_thread(void *_ts) | |||
280 | * We only detect touch screen _touches_ with this interrupt | 288 | * We only detect touch screen _touches_ with this interrupt |
281 | * handler, and even then we just schedule our task. | 289 | * handler, and even then we just schedule our task. |
282 | */ | 290 | */ |
283 | static void ucb1x00_ts_irq(int idx, void *id) | 291 | static irqreturn_t ucb1x00_ts_irq(int irq, void *id) |
284 | { | 292 | { |
285 | struct ucb1x00_ts *ts = id; | 293 | struct ucb1x00_ts *ts = id; |
286 | 294 | ||
287 | 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); | ||
288 | wake_up(&ts->irq_wait); | 299 | wake_up(&ts->irq_wait); |
300 | |||
301 | return IRQ_HANDLED; | ||
289 | } | 302 | } |
290 | 303 | ||
291 | static int ucb1x00_ts_open(struct input_dev *idev) | 304 | static int ucb1x00_ts_open(struct input_dev *idev) |
292 | { | 305 | { |
293 | struct ucb1x00_ts *ts = input_get_drvdata(idev); | 306 | struct ucb1x00_ts *ts = input_get_drvdata(idev); |
307 | unsigned long flags = 0; | ||
294 | int ret = 0; | 308 | int ret = 0; |
295 | 309 | ||
296 | BUG_ON(ts->rtask); | 310 | BUG_ON(ts->rtask); |
297 | 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 | |||
298 | init_waitqueue_head(&ts->irq_wait); | 319 | init_waitqueue_head(&ts->irq_wait); |
299 | 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); | ||
300 | if (ret < 0) | 322 | if (ret < 0) |
301 | goto out; | 323 | goto out; |
302 | 324 | ||
@@ -313,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev) | |||
313 | if (!IS_ERR(ts->rtask)) { | 335 | if (!IS_ERR(ts->rtask)) { |
314 | ret = 0; | 336 | ret = 0; |
315 | } else { | 337 | } else { |
316 | ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); | 338 | free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts); |
317 | ts->rtask = NULL; | 339 | ts->rtask = NULL; |
318 | ret = -EFAULT; | 340 | ret = -EFAULT; |
319 | } | 341 | } |
@@ -333,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev) | |||
333 | kthread_stop(ts->rtask); | 355 | kthread_stop(ts->rtask); |
334 | 356 | ||
335 | ucb1x00_enable(ts->ucb); | 357 | ucb1x00_enable(ts->ucb); |
336 | ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); | 358 | free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts); |
337 | ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); | 359 | ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); |
338 | ucb1x00_disable(ts->ucb); | 360 | ucb1x00_disable(ts->ucb); |
339 | } | 361 | } |
@@ -358,6 +380,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) | |||
358 | ts->ucb = dev->ucb; | 380 | ts->ucb = dev->ucb; |
359 | ts->idev = idev; | 381 | ts->idev = idev; |
360 | ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; | 382 | ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; |
383 | spin_lock_init(&ts->irq_lock); | ||
361 | 384 | ||
362 | idev->name = "Touchscreen panel"; | 385 | idev->name = "Touchscreen panel"; |
363 | idev->id.product = ts->ucb->id; | 386 | idev->id.product = ts->ucb->id; |