Commit accc0785 authored by Daniel Stone's avatar Daniel Stone Committed by James Toy

Previously, the only external (to dispc.c) IRQ handler was RFBI's frame

done handler.  dispc's IRQ framework was very dumb: you could only have
one handler, and the semantics of {request,free}_irq were odd, to say the
least.

The new framework allows multiple consumers to register arbitrary IRQ
masks.
Signed-off-by: default avatarDaniel Stone <daniel.stone@nokia.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarImre Deak <imre.deak@nokia.com>
Acked-by: default avatarKrzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 8dbc53d6
......@@ -155,6 +155,8 @@ struct resmap {
unsigned long *map;
};
#define MAX_IRQ_HANDLERS 4
static struct {
void __iomem *base;
......@@ -167,9 +169,11 @@ static struct {
int ext_mode;
unsigned long enabled_irqs;
void (*irq_callback)(void *);
void *irq_callback_data;
struct {
u32 irq_mask;
void (*callback)(void *);
void *data;
} irq_handlers[MAX_IRQ_HANDLERS];
struct completion frame_done;
int fir_hinc[OMAPFB_PLANE_NUM];
......@@ -809,56 +813,70 @@ static void set_lcd_timings(void)
panel->pixel_clock = fck / lck_div / pck_div / 1000;
}
int omap_dispc_request_irq(void (*callback)(void *data), void *data)
static void recalc_irq_mask(void)
{
int r = 0;
int i;
unsigned long irq_mask = DISPC_IRQ_MASK_ERROR;
BUG_ON(callback == NULL);
for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
if (!dispc.irq_handlers[i].callback)
continue;
if (dispc.irq_callback)
r = -EBUSY;
else {
dispc.irq_callback = callback;
dispc.irq_callback_data = data;
irq_mask |= dispc.irq_handlers[i].irq_mask;
}
return r;
}
EXPORT_SYMBOL(omap_dispc_request_irq);
void omap_dispc_enable_irqs(int irq_mask)
{
enable_lcd_clocks(1);
dispc.enabled_irqs = irq_mask;
irq_mask |= DISPC_IRQ_MASK_ERROR;
MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
enable_lcd_clocks(0);
}
EXPORT_SYMBOL(omap_dispc_enable_irqs);
void omap_dispc_disable_irqs(int irq_mask)
int omap_dispc_request_irq(unsigned long irq_mask, void (*callback)(void *data),
void *data)
{
enable_lcd_clocks(1);
dispc.enabled_irqs &= ~irq_mask;
irq_mask &= ~DISPC_IRQ_MASK_ERROR;
MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
enable_lcd_clocks(0);
int i;
BUG_ON(callback == NULL);
for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
if (dispc.irq_handlers[i].callback)
continue;
dispc.irq_handlers[i].irq_mask = irq_mask;
dispc.irq_handlers[i].callback = callback;
dispc.irq_handlers[i].data = data;
recalc_irq_mask();
return 0;
}
return -EBUSY;
}
EXPORT_SYMBOL(omap_dispc_disable_irqs);
EXPORT_SYMBOL(omap_dispc_request_irq);
void omap_dispc_free_irq(void)
void omap_dispc_free_irq(unsigned long irq_mask, void (*callback)(void *data),
void *data)
{
enable_lcd_clocks(1);
omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL);
dispc.irq_callback = NULL;
dispc.irq_callback_data = NULL;
enable_lcd_clocks(0);
int i;
for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
if (dispc.irq_handlers[i].callback == callback &&
dispc.irq_handlers[i].data == data) {
dispc.irq_handlers[i].irq_mask = 0;
dispc.irq_handlers[i].callback = NULL;
dispc.irq_handlers[i].data = NULL;
recalc_irq_mask();
return;
}
}
BUG();
}
EXPORT_SYMBOL(omap_dispc_free_irq);
static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
{
u32 stat;
int i = 0;
enable_lcd_clocks(1);
......@@ -873,8 +891,12 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
}
}
if ((stat & dispc.enabled_irqs) && dispc.irq_callback)
dispc.irq_callback(dispc.irq_callback_data);
for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
if (unlikely(dispc.irq_handlers[i].callback &&
(stat & dispc.irq_handlers[i].irq_mask)))
dispc.irq_handlers[i].callback(
dispc.irq_handlers[i].data);
}
dispc_write_reg(DISPC_IRQSTATUS, stat);
......@@ -1410,8 +1432,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
l = dispc_read_reg(DISPC_IRQSTATUS);
dispc_write_reg(DISPC_IRQSTATUS, l);
/* Enable those that we handle always */
omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK);
recalc_irq_mask();
if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
0, MODULE_NAME, fbdev)) < 0) {
......
......@@ -37,9 +37,10 @@ extern void omap_dispc_set_lcd_size(int width, int height);
extern void omap_dispc_enable_lcd_out(int enable);
extern void omap_dispc_enable_digit_out(int enable);
extern int omap_dispc_request_irq(void (*callback)(void *data), void *data);
extern void omap_dispc_free_irq(void);
extern int omap_dispc_request_irq(unsigned long irq_mask,
void (*callback)(void *data), void *data);
extern void omap_dispc_free_irq(unsigned long irq_mask,
void (*callback)(void *data), void *data);
extern const struct lcd_ctrl omap2_int_ctrl;
#endif
......@@ -57,6 +57,7 @@
#define DISPC_BASE 0x48050400
#define DISPC_CONTROL 0x0040
#define DISPC_IRQ_FRAMEMASK 0x0001
static struct {
void __iomem *base;
......@@ -553,7 +554,9 @@ static int rfbi_init(struct omapfb_device *fbdev)
l = (0x01 << 2);
rfbi_write_reg(RFBI_CONTROL, l);
if ((r = omap_dispc_request_irq(rfbi_dma_callback, NULL)) < 0) {
r = omap_dispc_request_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback,
NULL);
if (r < 0) {
dev_err(fbdev->dev, "can't get DISPC irq\n");
rfbi_enable_clocks(0);
return r;
......@@ -570,7 +573,7 @@ static int rfbi_init(struct omapfb_device *fbdev)
static void rfbi_cleanup(void)
{
omap_dispc_free_irq();
omap_dispc_free_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback, NULL);
rfbi_put_clocks();
iounmap(rfbi.base);
}
......
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