aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/ucb1x00-ts.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-01-21 09:58:28 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-02-18 18:15:43 -0500
commita3364409c4af8bae42d04def48dc11409787e503 (patch)
tree317d68920998bc5823d2879a49d49f27a8aed279 /drivers/mfd/ucb1x00-ts.c
parentcf4abfcc0df2985ff6061f74e63b8353f2a1d0bc (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.c37
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 */
283static void ucb1x00_ts_irq(int idx, void *id) 291static 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
291static int ucb1x00_ts_open(struct input_dev *idev) 304static 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;