Commit a3364409 authored by Russell King's avatar Russell King

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: default avatarJochen Friedrich <jochen@scram.de>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent cf4abfcc
......@@ -847,8 +847,9 @@ config MCP_SA11X0
# Chip drivers
config MCP_UCB1200
tristate "Support for UCB1200 / UCB1300"
depends on MCP
bool "Support for UCB1200 / UCB1300"
depends on MCP_SA11X0
select MCP
config MCP_UCB1200_TS
tristate "Touchscreen interface support"
......
This diff is collapsed.
......@@ -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;
......
......@@ -112,18 +112,15 @@ enum ucb1x00_reset {
struct ucb1x00_plat_data {
void (*reset)(enum ucb1x00_reset);
unsigned irq_base;
int gpio_base;
};
struct ucb1x00_irq {
void *devid;
void (*fn)(int, void *);
};
struct ucb1x00 {
spinlock_t lock;
raw_spinlock_t irq_lock;
struct mcp *mcp;
unsigned int irq;
int irq_base;
struct mutex adc_mutex;
spinlock_t io_lock;
u16 id;
......@@ -132,7 +129,7 @@ struct ucb1x00 {
u16 adc_cr;
u16 irq_fal_enbl;
u16 irq_ris_enbl;
struct ucb1x00_irq irq_handler[16];
u16 irq_mask;
struct device dev;
struct list_head node;
struct list_head devs;
......@@ -255,15 +252,4 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
void ucb1x00_adc_enable(struct ucb1x00 *ucb);
void ucb1x00_adc_disable(struct ucb1x00 *ucb);
/*
* Which edges of the IRQ do you want to control today?
*/
#define UCB_RISING (1 << 0)
#define UCB_FALLING (1 << 1)
int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment