Merge branch 'upstream' of git://lost.foo-projects.org/~ahkok/git/netdev-2.6 into...
[pandora-kernel.git] / arch / mips / momentum / ocelot_c / uart-irq.c
1 /*
2  * Copyright 2002 Momentum Computer
3  * Author: mdharm@momenco.com
4  *
5  * arch/mips/momentum/ocelot_c/uart-irq.c
6  *     Interrupt routines for UARTs.  Interrupt numbers are assigned from
7  *     80 to 81 (2 interrupt sources).
8  *
9  * This program is free software; you can redistribute  it and/or modify it
10  * under  the terms of  the GNU General  Public License as published by the
11  * Free Software Foundation;  either version 2 of the  License, or (at your
12  * option) any later version.
13  */
14
15 #include <linux/module.h>
16 #include <linux/interrupt.h>
17 #include <linux/irq.h>
18 #include <linux/kernel.h>
19 #include <asm/ptrace.h>
20 #include <linux/sched.h>
21 #include <linux/kernel_stat.h>
22 #include <asm/io.h>
23 #include <asm/irq.h>
24 #include "ocelot_c_fpga.h"
25
26 static inline int ls1bit8(unsigned int x)
27 {
28         int b = 7, s;
29
30         s =  4; if (((unsigned char)(x << 4)) == 0) s = 0; b -= s; x <<= s;
31         s =  2; if (((unsigned char)(x << 2)) == 0) s = 0; b -= s; x <<= s;
32         s =  1; if (((unsigned char)(x << 1)) == 0) s = 0; b -= s;
33
34         return b;
35 }
36
37 /* mask off an interrupt -- 0 is enable, 1 is disable */
38 static inline void mask_uart_irq(unsigned int irq)
39 {
40         uint8_t value;
41
42         value = OCELOT_FPGA_READ(UART_INTMASK);
43         value |= 1 << (irq - 74);
44         OCELOT_FPGA_WRITE(value, UART_INTMASK);
45
46         /* read the value back to assure that it's really been written */
47         value = OCELOT_FPGA_READ(UART_INTMASK);
48 }
49
50 /* unmask an interrupt -- 0 is enable, 1 is disable */
51 static inline void unmask_uart_irq(unsigned int irq)
52 {
53         uint8_t value;
54
55         value = OCELOT_FPGA_READ(UART_INTMASK);
56         value &= ~(1 << (irq - 74));
57         OCELOT_FPGA_WRITE(value, UART_INTMASK);
58
59         /* read the value back to assure that it's really been written */
60         value = OCELOT_FPGA_READ(UART_INTMASK);
61 }
62
63 /*
64  * Enables the IRQ in the FPGA
65  */
66 static void enable_uart_irq(unsigned int irq)
67 {
68         unmask_uart_irq(irq);
69 }
70
71 /*
72  * Initialize the IRQ in the FPGA
73  */
74 static unsigned int startup_uart_irq(unsigned int irq)
75 {
76         unmask_uart_irq(irq);
77         return 0;
78 }
79
80 /*
81  * Disables the IRQ in the FPGA
82  */
83 static void disable_uart_irq(unsigned int irq)
84 {
85         mask_uart_irq(irq);
86 }
87
88 /*
89  * Masks and ACKs an IRQ
90  */
91 static void mask_and_ack_uart_irq(unsigned int irq)
92 {
93         mask_uart_irq(irq);
94 }
95
96 /*
97  * End IRQ processing
98  */
99 static void end_uart_irq(unsigned int irq)
100 {
101         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
102                 unmask_uart_irq(irq);
103 }
104
105 /*
106  * Interrupt handler for interrupts coming from the FPGA chip.
107  */
108 void ll_uart_irq(struct pt_regs *regs)
109 {
110         unsigned int irq_src, irq_mask;
111
112         /* read the interrupt status registers */
113         irq_src = OCELOT_FPGA_READ(UART_INTSTAT);
114         irq_mask = OCELOT_FPGA_READ(UART_INTMASK);
115
116         /* mask for just the interrupts we want */
117         irq_src &= ~irq_mask;
118
119         do_IRQ(ls1bit8(irq_src) + 74, regs);
120 }
121
122 #define shutdown_uart_irq       disable_uart_irq
123
124 struct hw_interrupt_type uart_irq_type = {
125         .typename = "UART/FPGA",
126         .startup = startup_uart_irq,
127         .shutdown = shutdown_uart_irq,
128         .enable = enable_uart_irq,
129         .disable = disable_uart_irq,
130         .ack = mask_and_ack_uart_irq,
131         .end = end_uart_irq,
132 };
133
134 void uart_irq_init(void)
135 {
136         /* Reset irq handlers pointers to NULL */
137         irq_desc[80].status = IRQ_DISABLED;
138         irq_desc[80].action = 0;
139         irq_desc[80].depth = 2;
140         irq_desc[80].chip = &uart_irq_type;
141
142         irq_desc[81].status = IRQ_DISABLED;
143         irq_desc[81].action = 0;
144         irq_desc[81].depth = 2;
145         irq_desc[81].chip = &uart_irq_type;
146 }