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>
This commit is contained in:
@@ -20,8 +20,9 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/string.h>
|
||||
@@ -41,6 +42,8 @@ struct ucb1x00_ts {
|
||||
struct input_dev *idev;
|
||||
struct ucb1x00 *ucb;
|
||||
|
||||
spinlock_t irq_lock;
|
||||
unsigned irq_disabled;
|
||||
wait_queue_head_t irq_wait;
|
||||
struct task_struct *rtask;
|
||||
u16 x_res;
|
||||
@@ -237,7 +240,12 @@ static int ucb1x00_thread(void *_ts)
|
||||
if (ucb1x00_ts_pen_down(ts)) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
|
||||
spin_lock_irq(&ts->irq_lock);
|
||||
if (ts->irq_disabled) {
|
||||
ts->irq_disabled = 0;
|
||||
enable_irq(ts->ucb->irq_base + UCB_IRQ_TSPX);
|
||||
}
|
||||
spin_unlock_irq(&ts->irq_lock);
|
||||
ucb1x00_disable(ts->ucb);
|
||||
|
||||
/*
|
||||
@@ -280,23 +288,37 @@ static int ucb1x00_thread(void *_ts)
|
||||
* We only detect touch screen _touches_ with this interrupt
|
||||
* handler, and even then we just schedule our task.
|
||||
*/
|
||||
static void ucb1x00_ts_irq(int idx, void *id)
|
||||
static irqreturn_t ucb1x00_ts_irq(int irq, void *id)
|
||||
{
|
||||
struct ucb1x00_ts *ts = id;
|
||||
|
||||
ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
|
||||
spin_lock(&ts->irq_lock);
|
||||
ts->irq_disabled = 1;
|
||||
disable_irq_nosync(ts->ucb->irq_base + UCB_IRQ_TSPX);
|
||||
spin_unlock(&ts->irq_lock);
|
||||
wake_up(&ts->irq_wait);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ucb1x00_ts_open(struct input_dev *idev)
|
||||
{
|
||||
struct ucb1x00_ts *ts = input_get_drvdata(idev);
|
||||
unsigned long flags = 0;
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(ts->rtask);
|
||||
|
||||
if (machine_is_collie())
|
||||
flags = IRQF_TRIGGER_RISING;
|
||||
else
|
||||
flags = IRQF_TRIGGER_FALLING;
|
||||
|
||||
ts->irq_disabled = 0;
|
||||
|
||||
init_waitqueue_head(&ts->irq_wait);
|
||||
ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
|
||||
ret = request_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ucb1x00_ts_irq,
|
||||
flags, "ucb1x00-ts", ts);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -313,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev)
|
||||
if (!IS_ERR(ts->rtask)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
|
||||
free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
|
||||
ts->rtask = NULL;
|
||||
ret = -EFAULT;
|
||||
}
|
||||
@@ -333,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev)
|
||||
kthread_stop(ts->rtask);
|
||||
|
||||
ucb1x00_enable(ts->ucb);
|
||||
ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
|
||||
free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
|
||||
ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
|
||||
ucb1x00_disable(ts->ucb);
|
||||
}
|
||||
@@ -358,6 +380,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
|
||||
ts->ucb = dev->ucb;
|
||||
ts->idev = idev;
|
||||
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
|
||||
spin_lock_init(&ts->irq_lock);
|
||||
|
||||
idev->name = "Touchscreen panel";
|
||||
idev->id.product = ts->ucb->id;
|
||||
|
Reference in New Issue
Block a user