Merge git://git.infradead.org/battery-2.6
[pandora-kernel.git] / arch / mips / sni / a20r.c
1 /*
2  * A20R specific code
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file "COPYING" in the main directory of this archive
6  * for more details.
7  *
8  * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
9  */
10
11 #include <linux/init.h>
12 #include <linux/interrupt.h>
13 #include <linux/platform_device.h>
14 #include <linux/serial_8250.h>
15
16 #include <asm/sni.h>
17 #include <asm/time.h>
18
19 #define PORT(_base,_irq)                                \
20         {                                               \
21                 .iobase         = _base,                \
22                 .irq            = _irq,                 \
23                 .uartclk        = 1843200,              \
24                 .iotype         = UPIO_PORT,            \
25                 .flags          = UPF_BOOT_AUTOCONF,    \
26         }
27
28 static struct plat_serial8250_port a20r_data[] = {
29         PORT(0x3f8, 4),
30         PORT(0x2f8, 3),
31         { },
32 };
33
34 static struct platform_device a20r_serial8250_device = {
35         .name                   = "serial8250",
36         .id                     = PLAT8250_DEV_PLATFORM,
37         .dev                    = {
38                 .platform_data  = a20r_data,
39         },
40 };
41
42 static struct resource a20r_ds1216_rsrc[] = {
43         {
44                 .start = 0x1c081ffc,
45                 .end   = 0x1c081fff,
46                 .flags = IORESOURCE_MEM
47         }
48 };
49
50 static struct platform_device a20r_ds1216_device = {
51         .name           = "rtc-ds1216",
52         .num_resources  = ARRAY_SIZE(a20r_ds1216_rsrc),
53         .resource       = a20r_ds1216_rsrc
54 };
55
56 static struct resource snirm_82596_rsrc[] = {
57         {
58                 .start = 0x18000000,
59                 .end   = 0x18000004,
60                 .flags = IORESOURCE_MEM
61         },
62         {
63                 .start = 0x18010000,
64                 .end   = 0x18010004,
65                 .flags = IORESOURCE_MEM
66         },
67         {
68                 .start = 0x1ff00000,
69                 .end   = 0x1ff00020,
70                 .flags = IORESOURCE_MEM
71         },
72         {
73                 .start = 22,
74                 .end   = 22,
75                 .flags = IORESOURCE_IRQ
76         },
77         {
78                 .flags = 0x01                /* 16bit mpu port access */
79         }
80 };
81
82 static struct platform_device snirm_82596_pdev = {
83         .name           = "snirm_82596",
84         .num_resources  = ARRAY_SIZE(snirm_82596_rsrc),
85         .resource       = snirm_82596_rsrc
86 };
87
88 static struct resource snirm_53c710_rsrc[] = {
89         {
90                 .start = 0x19000000,
91                 .end   = 0x190fffff,
92                 .flags = IORESOURCE_MEM
93         },
94         {
95                 .start = 19,
96                 .end   = 19,
97                 .flags = IORESOURCE_IRQ
98         }
99 };
100
101 static struct platform_device snirm_53c710_pdev = {
102         .name           = "snirm_53c710",
103         .num_resources  = ARRAY_SIZE(snirm_53c710_rsrc),
104         .resource       = snirm_53c710_rsrc
105 };
106
107 static struct resource sc26xx_rsrc[] = {
108         {
109                 .start = 0x1c070000,
110                 .end   = 0x1c0700ff,
111                 .flags = IORESOURCE_MEM
112         },
113         {
114                 .start = 20,
115                 .end   = 20,
116                 .flags = IORESOURCE_IRQ
117         }
118 };
119
120 static struct platform_device sc26xx_pdev = {
121         .name           = "SC26xx",
122         .num_resources  = ARRAY_SIZE(sc26xx_rsrc),
123         .resource       = sc26xx_rsrc
124 };
125
126 static u32 a20r_ack_hwint(void)
127 {
128         u32 status = read_c0_status();
129
130         write_c0_status(status | 0x00010000);
131         asm volatile(
132         "       .set    push                    \n"
133         "       .set    noat                    \n"
134         "       .set    noreorder               \n"
135         "       lw      $1, 0(%0)               \n"
136         "       sb      $0, 0(%1)               \n"
137         "       sync                            \n"
138         "       lb      %1, 0(%1)               \n"
139         "       b       1f                      \n"
140         "       ori     %1, $1, 2               \n"
141         "       .align  8                       \n"
142         "1:                                     \n"
143         "       nop                             \n"
144         "       sw      %1, 0(%0)               \n"
145         "       sync                            \n"
146         "       li      %1, 0x20                \n"
147         "2:                                     \n"
148         "       nop                             \n"
149         "       bnez    %1,2b                   \n"
150         "       addiu   %1, -1                  \n"
151         "       sw      $1, 0(%0)               \n"
152         "       sync                            \n"
153                 ".set   pop                     \n"
154         :
155         : "Jr" (PCIMT_UCONF), "Jr" (0xbc000000));
156         write_c0_status(status);
157
158         return status;
159 }
160
161 static inline void unmask_a20r_irq(unsigned int irq)
162 {
163         set_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
164         irq_enable_hazard();
165 }
166
167 static inline void mask_a20r_irq(unsigned int irq)
168 {
169         clear_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
170         irq_disable_hazard();
171 }
172
173 static void end_a20r_irq(unsigned int irq)
174 {
175         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
176                 a20r_ack_hwint();
177                 unmask_a20r_irq(irq);
178         }
179 }
180
181 static struct irq_chip a20r_irq_type = {
182         .typename       = "A20R",
183         .ack            = mask_a20r_irq,
184         .mask           = mask_a20r_irq,
185         .mask_ack       = mask_a20r_irq,
186         .unmask         = unmask_a20r_irq,
187         .end            = end_a20r_irq,
188 };
189
190 /*
191  * hwint 0 receive all interrupts
192  */
193 static void a20r_hwint(void)
194 {
195         u32 cause, status;
196         int irq;
197
198         clear_c0_status(IE_IRQ0);
199         status = a20r_ack_hwint();
200         cause = read_c0_cause();
201
202         irq = ffs(((cause & status) >> 8) & 0xf8);
203         if (likely(irq > 0))
204                 do_IRQ(SNI_A20R_IRQ_BASE + irq - 1);
205         set_c0_status(IE_IRQ0);
206 }
207
208 void __init sni_a20r_irq_init(void)
209 {
210         int i;
211
212         for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++)
213                 set_irq_chip(i, &a20r_irq_type);
214         sni_hwint = a20r_hwint;
215         change_c0_status(ST0_IM, IE_IRQ0);
216         setup_irq(SNI_A20R_IRQ_BASE + 3, &sni_isa_irq);
217 }
218
219 void sni_a20r_init(void)
220 {
221         /* FIXME, remove if not needed */
222 }
223
224 static int __init snirm_a20r_setup_devinit(void)
225 {
226         switch (sni_brd_type) {
227         case SNI_BRD_TOWER_OASIC:
228         case SNI_BRD_MINITOWER:
229                 platform_device_register(&snirm_82596_pdev);
230                 platform_device_register(&snirm_53c710_pdev);
231                 platform_device_register(&sc26xx_pdev);
232                 platform_device_register(&a20r_serial8250_device);
233                 platform_device_register(&a20r_ds1216_device);
234                 break;
235         }
236
237         return 0;
238 }
239
240 device_initcall(snirm_a20r_setup_devinit);