aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Stone <daniel.stone@nokia.com>2009-09-22 19:46:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:50 -0400
commit4c88ef170f0f9b1f26923b43af526c973c5a74da (patch)
tree358d55e961ad7c4d20143c52e7ae511326ffd879
parent48a00e7fe9a6abeedb62c99ca7b7860754aae3d8 (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.c95
-rw-r--r--drivers/video/omap/dispc.h7
-rw-r--r--drivers/video/omap/rfbi.c7
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
158static struct { 160static 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
812int omap_dispc_request_irq(void (*callback)(void *data), void *data) 816static 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}
827EXPORT_SYMBOL(omap_dispc_request_irq);
828
829void 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}
837EXPORT_SYMBOL(omap_dispc_enable_irqs);
838 832
839void omap_dispc_disable_irqs(int irq_mask) 833int 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}
847EXPORT_SYMBOL(omap_dispc_disable_irqs); 854EXPORT_SYMBOL(omap_dispc_request_irq);
848 855
849void omap_dispc_free_irq(void) 856void 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}
857EXPORT_SYMBOL(omap_dispc_free_irq); 874EXPORT_SYMBOL(omap_dispc_free_irq);
858 875
859static irqreturn_t omap_dispc_irq_handler(int irq, void *dev) 876static 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);
37extern void omap_dispc_enable_lcd_out(int enable); 37extern void omap_dispc_enable_lcd_out(int enable);
38extern void omap_dispc_enable_digit_out(int enable); 38extern void omap_dispc_enable_digit_out(int enable);
39 39
40extern int omap_dispc_request_irq(void (*callback)(void *data), void *data); 40extern int omap_dispc_request_irq(unsigned long irq_mask,
41extern void omap_dispc_free_irq(void); 41 void (*callback)(void *data), void *data);
42extern void omap_dispc_free_irq(unsigned long irq_mask,
43 void (*callback)(void *data), void *data);
42 44
43extern const struct lcd_ctrl omap2_int_ctrl; 45extern 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
61static struct { 62static 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
571static void rfbi_cleanup(void) 574static 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}