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 ...@@ -847,8 +847,9 @@ config MCP_SA11X0
# Chip drivers # Chip drivers
config MCP_UCB1200 config MCP_UCB1200
tristate "Support for UCB1200 / UCB1300" bool "Support for UCB1200 / UCB1300"
depends on MCP depends on MCP_SA11X0
select MCP
config MCP_UCB1200_TS config MCP_UCB1200_TS
tristate "Touchscreen interface support" tristate "Touchscreen interface support"
......
This diff is collapsed.
...@@ -20,8 +20,9 @@ ...@@ -20,8 +20,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/smp.h> #include <linux/interrupt.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -41,6 +42,8 @@ struct ucb1x00_ts { ...@@ -41,6 +42,8 @@ struct ucb1x00_ts {
struct input_dev *idev; struct input_dev *idev;
struct ucb1x00 *ucb; struct ucb1x00 *ucb;
spinlock_t irq_lock;
unsigned irq_disabled;
wait_queue_head_t irq_wait; wait_queue_head_t irq_wait;
struct task_struct *rtask; struct task_struct *rtask;
u16 x_res; u16 x_res;
...@@ -237,7 +240,12 @@ static int ucb1x00_thread(void *_ts) ...@@ -237,7 +240,12 @@ static int ucb1x00_thread(void *_ts)
if (ucb1x00_ts_pen_down(ts)) { if (ucb1x00_ts_pen_down(ts)) {
set_current_state(TASK_INTERRUPTIBLE); 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); ucb1x00_disable(ts->ucb);
/* /*
...@@ -280,23 +288,37 @@ static int ucb1x00_thread(void *_ts) ...@@ -280,23 +288,37 @@ static int ucb1x00_thread(void *_ts)
* We only detect touch screen _touches_ with this interrupt * We only detect touch screen _touches_ with this interrupt
* handler, and even then we just schedule our task. * 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; 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); wake_up(&ts->irq_wait);
return IRQ_HANDLED;
} }
static int ucb1x00_ts_open(struct input_dev *idev) static int ucb1x00_ts_open(struct input_dev *idev)
{ {
struct ucb1x00_ts *ts = input_get_drvdata(idev); struct ucb1x00_ts *ts = input_get_drvdata(idev);
unsigned long flags = 0;
int ret = 0; int ret = 0;
BUG_ON(ts->rtask); 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); 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) if (ret < 0)
goto out; goto out;
...@@ -313,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev) ...@@ -313,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev)
if (!IS_ERR(ts->rtask)) { if (!IS_ERR(ts->rtask)) {
ret = 0; ret = 0;
} else { } else {
ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
ts->rtask = NULL; ts->rtask = NULL;
ret = -EFAULT; ret = -EFAULT;
} }
...@@ -333,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev) ...@@ -333,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev)
kthread_stop(ts->rtask); kthread_stop(ts->rtask);
ucb1x00_enable(ts->ucb); 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_reg_write(ts->ucb, UCB_TS_CR, 0);
ucb1x00_disable(ts->ucb); ucb1x00_disable(ts->ucb);
} }
...@@ -358,6 +380,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) ...@@ -358,6 +380,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
ts->ucb = dev->ucb; ts->ucb = dev->ucb;
ts->idev = idev; ts->idev = idev;
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
spin_lock_init(&ts->irq_lock);
idev->name = "Touchscreen panel"; idev->name = "Touchscreen panel";
idev->id.product = ts->ucb->id; idev->id.product = ts->ucb->id;
......
...@@ -112,18 +112,15 @@ enum ucb1x00_reset { ...@@ -112,18 +112,15 @@ enum ucb1x00_reset {
struct ucb1x00_plat_data { struct ucb1x00_plat_data {
void (*reset)(enum ucb1x00_reset); void (*reset)(enum ucb1x00_reset);
unsigned irq_base;
int gpio_base; int gpio_base;
}; };
struct ucb1x00_irq {
void *devid;
void (*fn)(int, void *);
};
struct ucb1x00 { struct ucb1x00 {
spinlock_t lock; raw_spinlock_t irq_lock;
struct mcp *mcp; struct mcp *mcp;
unsigned int irq; unsigned int irq;
int irq_base;
struct mutex adc_mutex; struct mutex adc_mutex;
spinlock_t io_lock; spinlock_t io_lock;
u16 id; u16 id;
...@@ -132,7 +129,7 @@ struct ucb1x00 { ...@@ -132,7 +129,7 @@ struct ucb1x00 {
u16 adc_cr; u16 adc_cr;
u16 irq_fal_enbl; u16 irq_fal_enbl;
u16 irq_ris_enbl; u16 irq_ris_enbl;
struct ucb1x00_irq irq_handler[16]; u16 irq_mask;
struct device dev; struct device dev;
struct list_head node; struct list_head node;
struct list_head devs; struct list_head devs;
...@@ -255,15 +252,4 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync); ...@@ -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_enable(struct ucb1x00 *ucb);
void ucb1x00_adc_disable(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 #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