diff options
author | Daniel Stone <daniel.stone@nokia.com> | 2009-09-22 19:46:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 10:39:50 -0400 |
commit | 4c88ef170f0f9b1f26923b43af526c973c5a74da (patch) | |
tree | 358d55e961ad7c4d20143c52e7ae511326ffd879 | |
parent | 48a00e7fe9a6abeedb62c99ca7b7860754aae3d8 (diff) |
omapfb: dispc: allow multiple external IRQ handlers
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: Daniel Stone <daniel.stone@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Imre Deak <imre.deak@nokia.com>
Acked-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/video/omap/dispc.c | 95 | ||||
-rw-r--r-- | drivers/video/omap/dispc.h | 7 | ||||
-rw-r--r-- | drivers/video/omap/rfbi.c | 7 |
3 files changed, 67 insertions, 42 deletions
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c index 04b7b8ae5583..80a11d078df4 100644 --- a/drivers/video/omap/dispc.c +++ b/drivers/video/omap/dispc.c | |||
@@ -155,6 +155,8 @@ struct resmap { | |||
155 | unsigned long *map; | 155 | unsigned long *map; |
156 | }; | 156 | }; |
157 | 157 | ||
158 | #define MAX_IRQ_HANDLERS 4 | ||
159 | |||
158 | static struct { | 160 | static struct { |
159 | void __iomem *base; | 161 | void __iomem *base; |
160 | 162 | ||
@@ -167,9 +169,11 @@ static struct { | |||
167 | 169 | ||
168 | int ext_mode; | 170 | int ext_mode; |
169 | 171 | ||
170 | unsigned long enabled_irqs; | 172 | struct { |
171 | void (*irq_callback)(void *); | 173 | u32 irq_mask; |
172 | void *irq_callback_data; | 174 | void (*callback)(void *); |
175 | void *data; | ||
176 | } irq_handlers[MAX_IRQ_HANDLERS]; | ||
173 | struct completion frame_done; | 177 | struct completion frame_done; |
174 | 178 | ||
175 | int fir_hinc[OMAPFB_PLANE_NUM]; | 179 | int fir_hinc[OMAPFB_PLANE_NUM]; |
@@ -809,56 +813,70 @@ static void set_lcd_timings(void) | |||
809 | panel->pixel_clock = fck / lck_div / pck_div / 1000; | 813 | panel->pixel_clock = fck / lck_div / pck_div / 1000; |
810 | } | 814 | } |
811 | 815 | ||
812 | int omap_dispc_request_irq(void (*callback)(void *data), void *data) | 816 | static void recalc_irq_mask(void) |
813 | { | 817 | { |
814 | int r = 0; | 818 | int i; |
819 | unsigned long irq_mask = DISPC_IRQ_MASK_ERROR; | ||
815 | 820 | ||
816 | BUG_ON(callback == NULL); | 821 | for (i = 0; i < MAX_IRQ_HANDLERS; i++) { |
822 | if (!dispc.irq_handlers[i].callback) | ||
823 | continue; | ||
817 | 824 | ||
818 | if (dispc.irq_callback) | 825 | irq_mask |= dispc.irq_handlers[i].irq_mask; |
819 | r = -EBUSY; | ||
820 | else { | ||
821 | dispc.irq_callback = callback; | ||
822 | dispc.irq_callback_data = data; | ||
823 | } | 826 | } |
824 | 827 | ||
825 | return r; | ||
826 | } | ||
827 | EXPORT_SYMBOL(omap_dispc_request_irq); | ||
828 | |||
829 | void omap_dispc_enable_irqs(int irq_mask) | ||
830 | { | ||
831 | enable_lcd_clocks(1); | 828 | enable_lcd_clocks(1); |
832 | dispc.enabled_irqs = irq_mask; | ||
833 | irq_mask |= DISPC_IRQ_MASK_ERROR; | ||
834 | MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); | 829 | MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); |
835 | enable_lcd_clocks(0); | 830 | enable_lcd_clocks(0); |
836 | } | 831 | } |
837 | EXPORT_SYMBOL(omap_dispc_enable_irqs); | ||
838 | 832 | ||
839 | void omap_dispc_disable_irqs(int irq_mask) | 833 | int omap_dispc_request_irq(unsigned long irq_mask, void (*callback)(void *data), |
834 | void *data) | ||
840 | { | 835 | { |
841 | enable_lcd_clocks(1); | 836 | int i; |
842 | dispc.enabled_irqs &= ~irq_mask; | 837 | |
843 | irq_mask &= ~DISPC_IRQ_MASK_ERROR; | 838 | BUG_ON(callback == NULL); |
844 | MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); | 839 | |
845 | enable_lcd_clocks(0); | 840 | for (i = 0; i < MAX_IRQ_HANDLERS; i++) { |
841 | if (dispc.irq_handlers[i].callback) | ||
842 | continue; | ||
843 | |||
844 | dispc.irq_handlers[i].irq_mask = irq_mask; | ||
845 | dispc.irq_handlers[i].callback = callback; | ||
846 | dispc.irq_handlers[i].data = data; | ||
847 | recalc_irq_mask(); | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | return -EBUSY; | ||
846 | } | 853 | } |
847 | EXPORT_SYMBOL(omap_dispc_disable_irqs); | 854 | EXPORT_SYMBOL(omap_dispc_request_irq); |
848 | 855 | ||
849 | void omap_dispc_free_irq(void) | 856 | void omap_dispc_free_irq(unsigned long irq_mask, void (*callback)(void *data), |
857 | void *data) | ||
850 | { | 858 | { |
851 | enable_lcd_clocks(1); | 859 | int i; |
852 | omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL); | 860 | |
853 | dispc.irq_callback = NULL; | 861 | for (i = 0; i < MAX_IRQ_HANDLERS; i++) { |
854 | dispc.irq_callback_data = NULL; | 862 | if (dispc.irq_handlers[i].callback == callback && |
855 | enable_lcd_clocks(0); | 863 | dispc.irq_handlers[i].data == data) { |
864 | dispc.irq_handlers[i].irq_mask = 0; | ||
865 | dispc.irq_handlers[i].callback = NULL; | ||
866 | dispc.irq_handlers[i].data = NULL; | ||
867 | recalc_irq_mask(); | ||
868 | return; | ||
869 | } | ||
870 | } | ||
871 | |||
872 | BUG(); | ||
856 | } | 873 | } |
857 | EXPORT_SYMBOL(omap_dispc_free_irq); | 874 | EXPORT_SYMBOL(omap_dispc_free_irq); |
858 | 875 | ||
859 | static irqreturn_t omap_dispc_irq_handler(int irq, void *dev) | 876 | static irqreturn_t omap_dispc_irq_handler(int irq, void *dev) |
860 | { | 877 | { |
861 | u32 stat; | 878 | u32 stat; |
879 | int i = 0; | ||
862 | 880 | ||
863 | enable_lcd_clocks(1); | 881 | enable_lcd_clocks(1); |
864 | 882 | ||
@@ -873,8 +891,12 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev) | |||
873 | } | 891 | } |
874 | } | 892 | } |
875 | 893 | ||
876 | if ((stat & dispc.enabled_irqs) && dispc.irq_callback) | 894 | for (i = 0; i < MAX_IRQ_HANDLERS; i++) { |
877 | dispc.irq_callback(dispc.irq_callback_data); | 895 | if (unlikely(dispc.irq_handlers[i].callback && |
896 | (stat & dispc.irq_handlers[i].irq_mask))) | ||
897 | dispc.irq_handlers[i].callback( | ||
898 | dispc.irq_handlers[i].data); | ||
899 | } | ||
878 | 900 | ||
879 | dispc_write_reg(DISPC_IRQSTATUS, stat); | 901 | dispc_write_reg(DISPC_IRQSTATUS, stat); |
880 | 902 | ||
@@ -1410,8 +1432,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode, | |||
1410 | l = dispc_read_reg(DISPC_IRQSTATUS); | 1432 | l = dispc_read_reg(DISPC_IRQSTATUS); |
1411 | dispc_write_reg(DISPC_IRQSTATUS, l); | 1433 | dispc_write_reg(DISPC_IRQSTATUS, l); |
1412 | 1434 | ||
1413 | /* Enable those that we handle always */ | 1435 | recalc_irq_mask(); |
1414 | omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK); | ||
1415 | 1436 | ||
1416 | if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler, | 1437 | if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler, |
1417 | 0, MODULE_NAME, fbdev)) < 0) { | 1438 | 0, MODULE_NAME, fbdev)) < 0) { |
diff --git a/drivers/video/omap/dispc.h b/drivers/video/omap/dispc.h index ef720a78f6d5..c15ea77f0604 100644 --- a/drivers/video/omap/dispc.h +++ b/drivers/video/omap/dispc.h | |||
@@ -37,9 +37,10 @@ extern void omap_dispc_set_lcd_size(int width, int height); | |||
37 | extern void omap_dispc_enable_lcd_out(int enable); | 37 | extern void omap_dispc_enable_lcd_out(int enable); |
38 | extern void omap_dispc_enable_digit_out(int enable); | 38 | extern void omap_dispc_enable_digit_out(int enable); |
39 | 39 | ||
40 | extern int omap_dispc_request_irq(void (*callback)(void *data), void *data); | 40 | extern int omap_dispc_request_irq(unsigned long irq_mask, |
41 | extern void omap_dispc_free_irq(void); | 41 | void (*callback)(void *data), void *data); |
42 | extern void omap_dispc_free_irq(unsigned long irq_mask, | ||
43 | void (*callback)(void *data), void *data); | ||
42 | 44 | ||
43 | extern const struct lcd_ctrl omap2_int_ctrl; | 45 | extern const struct lcd_ctrl omap2_int_ctrl; |
44 | |||
45 | #endif | 46 | #endif |
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c index 9332d6ca6456..ee01e84e19c1 100644 --- a/drivers/video/omap/rfbi.c +++ b/drivers/video/omap/rfbi.c | |||
@@ -57,6 +57,7 @@ | |||
57 | 57 | ||
58 | #define DISPC_BASE 0x48050400 | 58 | #define DISPC_BASE 0x48050400 |
59 | #define DISPC_CONTROL 0x0040 | 59 | #define DISPC_CONTROL 0x0040 |
60 | #define DISPC_IRQ_FRAMEMASK 0x0001 | ||
60 | 61 | ||
61 | static struct { | 62 | static struct { |
62 | void __iomem *base; | 63 | void __iomem *base; |
@@ -553,7 +554,9 @@ static int rfbi_init(struct omapfb_device *fbdev) | |||
553 | l = (0x01 << 2); | 554 | l = (0x01 << 2); |
554 | rfbi_write_reg(RFBI_CONTROL, l); | 555 | rfbi_write_reg(RFBI_CONTROL, l); |
555 | 556 | ||
556 | if ((r = omap_dispc_request_irq(rfbi_dma_callback, NULL)) < 0) { | 557 | r = omap_dispc_request_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback, |
558 | NULL); | ||
559 | if (r < 0) { | ||
557 | dev_err(fbdev->dev, "can't get DISPC irq\n"); | 560 | dev_err(fbdev->dev, "can't get DISPC irq\n"); |
558 | rfbi_enable_clocks(0); | 561 | rfbi_enable_clocks(0); |
559 | return r; | 562 | return r; |
@@ -570,7 +573,7 @@ static int rfbi_init(struct omapfb_device *fbdev) | |||
570 | 573 | ||
571 | static void rfbi_cleanup(void) | 574 | static void rfbi_cleanup(void) |
572 | { | 575 | { |
573 | omap_dispc_free_irq(); | 576 | omap_dispc_free_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback, NULL); |
574 | rfbi_put_clocks(); | 577 | rfbi_put_clocks(); |
575 | iounmap(rfbi.base); | 578 | iounmap(rfbi.base); |
576 | } | 579 | } |