Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/arm/mach-pxa/mainstone.c | |
3 | * | |
4 | * Support for the Intel HCDDBBVA0 Development Platform. | |
5 | * (go figure how they came up with such name...) | |
6 | * | |
7 | * Author: Nicolas Pitre | |
8 | * Created: Nov 05, 2002 | |
9 | * Copyright: MontaVista Software Inc. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify | |
12 | * it under the terms of the GNU General Public License version 2 as | |
13 | * published by the Free Software Foundation. | |
14 | */ | |
15 | ||
16 | #include <linux/init.h> | |
d052d1be | 17 | #include <linux/platform_device.h> |
22f11c4e | 18 | #include <linux/sysdev.h> |
1da177e4 LT |
19 | #include <linux/interrupt.h> |
20 | #include <linux/sched.h> | |
21 | #include <linux/bitops.h> | |
22 | #include <linux/fb.h> | |
23 | ||
24 | #include <asm/types.h> | |
25 | #include <asm/setup.h> | |
26 | #include <asm/memory.h> | |
27 | #include <asm/mach-types.h> | |
28 | #include <asm/hardware.h> | |
29 | #include <asm/irq.h> | |
30 | ||
31 | #include <asm/mach/arch.h> | |
32 | #include <asm/mach/map.h> | |
33 | #include <asm/mach/irq.h> | |
34 | ||
35 | #include <asm/arch/pxa-regs.h> | |
36 | #include <asm/arch/mainstone.h> | |
37 | #include <asm/arch/audio.h> | |
38 | #include <asm/arch/pxafb.h> | |
39 | #include <asm/arch/mmc.h> | |
6f475c01 | 40 | #include <asm/arch/irda.h> |
1da177e4 LT |
41 | |
42 | #include "generic.h" | |
43 | ||
44 | ||
45 | static unsigned long mainstone_irq_enabled; | |
46 | ||
47 | static void mainstone_mask_irq(unsigned int irq) | |
48 | { | |
49 | int mainstone_irq = (irq - MAINSTONE_IRQ(0)); | |
50 | MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq)); | |
51 | } | |
52 | ||
53 | static void mainstone_unmask_irq(unsigned int irq) | |
54 | { | |
55 | int mainstone_irq = (irq - MAINSTONE_IRQ(0)); | |
56 | /* the irq can be acknowledged only if deasserted, so it's done here */ | |
57 | MST_INTSETCLR &= ~(1 << mainstone_irq); | |
58 | MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq)); | |
59 | } | |
60 | ||
61 | static struct irqchip mainstone_irq_chip = { | |
62 | .ack = mainstone_mask_irq, | |
63 | .mask = mainstone_mask_irq, | |
64 | .unmask = mainstone_unmask_irq, | |
65 | }; | |
66 | ||
1da177e4 LT |
67 | static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc, |
68 | struct pt_regs *regs) | |
69 | { | |
70 | unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled; | |
71 | do { | |
72 | GEDR(0) = GPIO_bit(0); /* clear useless edge notification */ | |
73 | if (likely(pending)) { | |
74 | irq = MAINSTONE_IRQ(0) + __ffs(pending); | |
75 | desc = irq_desc + irq; | |
664399e1 | 76 | desc_handle_irq(irq, desc, regs); |
1da177e4 LT |
77 | } |
78 | pending = MST_INTSETCLR & mainstone_irq_enabled; | |
79 | } while (pending); | |
80 | } | |
81 | ||
82 | static void __init mainstone_init_irq(void) | |
83 | { | |
84 | int irq; | |
85 | ||
86 | pxa_init_irq(); | |
87 | ||
88 | /* setup extra Mainstone irqs */ | |
89 | for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) { | |
90 | set_irq_chip(irq, &mainstone_irq_chip); | |
91 | set_irq_handler(irq, do_level_IRQ); | |
92 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | |
93 | } | |
94 | set_irq_flags(MAINSTONE_IRQ(8), 0); | |
95 | set_irq_flags(MAINSTONE_IRQ(12), 0); | |
96 | ||
97 | MST_INTMSKENA = 0; | |
98 | MST_INTSETCLR = 0; | |
99 | ||
100 | set_irq_chained_handler(IRQ_GPIO(0), mainstone_irq_handler); | |
101 | set_irq_type(IRQ_GPIO(0), IRQT_FALLING); | |
102 | } | |
103 | ||
22f11c4e NP |
104 | #ifdef CONFIG_PM |
105 | ||
106 | static int mainstone_irq_resume(struct sys_device *dev) | |
107 | { | |
108 | MST_INTMSKENA = mainstone_irq_enabled; | |
109 | return 0; | |
110 | } | |
111 | ||
112 | static struct sysdev_class mainstone_irq_sysclass = { | |
113 | set_kset_name("cpld_irq"), | |
114 | .resume = mainstone_irq_resume, | |
115 | }; | |
116 | ||
117 | static struct sys_device mainstone_irq_device = { | |
118 | .cls = &mainstone_irq_sysclass, | |
119 | }; | |
120 | ||
121 | static int __init mainstone_irq_device_init(void) | |
122 | { | |
123 | int ret = sysdev_class_register(&mainstone_irq_sysclass); | |
124 | if (ret == 0) | |
125 | ret = sysdev_register(&mainstone_irq_device); | |
126 | return ret; | |
127 | } | |
128 | ||
129 | device_initcall(mainstone_irq_device_init); | |
130 | ||
131 | #endif | |
132 | ||
1da177e4 LT |
133 | |
134 | static struct resource smc91x_resources[] = { | |
135 | [0] = { | |
136 | .start = (MST_ETH_PHYS + 0x300), | |
137 | .end = (MST_ETH_PHYS + 0xfffff), | |
138 | .flags = IORESOURCE_MEM, | |
139 | }, | |
140 | [1] = { | |
141 | .start = MAINSTONE_IRQ(3), | |
142 | .end = MAINSTONE_IRQ(3), | |
143 | .flags = IORESOURCE_IRQ, | |
144 | } | |
145 | }; | |
146 | ||
147 | static struct platform_device smc91x_device = { | |
148 | .name = "smc91x", | |
149 | .id = 0, | |
150 | .num_resources = ARRAY_SIZE(smc91x_resources), | |
151 | .resource = smc91x_resources, | |
152 | }; | |
153 | ||
154 | static int mst_audio_startup(snd_pcm_substream_t *substream, void *priv) | |
155 | { | |
156 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
157 | MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF; | |
158 | return 0; | |
159 | } | |
160 | ||
161 | static void mst_audio_shutdown(snd_pcm_substream_t *substream, void *priv) | |
162 | { | |
163 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
164 | MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF; | |
165 | } | |
166 | ||
167 | static long mst_audio_suspend_mask; | |
168 | ||
169 | static void mst_audio_suspend(void *priv) | |
170 | { | |
171 | mst_audio_suspend_mask = MST_MSCWR2; | |
172 | MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF; | |
173 | } | |
174 | ||
175 | static void mst_audio_resume(void *priv) | |
176 | { | |
177 | MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF; | |
178 | } | |
179 | ||
180 | static pxa2xx_audio_ops_t mst_audio_ops = { | |
181 | .startup = mst_audio_startup, | |
182 | .shutdown = mst_audio_shutdown, | |
183 | .suspend = mst_audio_suspend, | |
184 | .resume = mst_audio_resume, | |
185 | }; | |
186 | ||
187 | static struct platform_device mst_audio_device = { | |
188 | .name = "pxa2xx-ac97", | |
189 | .id = -1, | |
190 | .dev = { .platform_data = &mst_audio_ops }, | |
191 | }; | |
192 | ||
193 | static void mainstone_backlight_power(int on) | |
194 | { | |
195 | if (on) { | |
196 | pxa_gpio_mode(GPIO16_PWM0_MD); | |
197 | pxa_set_cken(CKEN0_PWM0, 1); | |
198 | PWM_CTRL0 = 0; | |
199 | PWM_PWDUTY0 = 0x3ff; | |
200 | PWM_PERVAL0 = 0x3ff; | |
201 | } else { | |
202 | PWM_CTRL0 = 0; | |
203 | PWM_PWDUTY0 = 0x0; | |
204 | PWM_PERVAL0 = 0x3FF; | |
205 | pxa_set_cken(CKEN0_PWM0, 0); | |
206 | } | |
207 | } | |
208 | ||
209 | static struct pxafb_mach_info toshiba_ltm04c380k __initdata = { | |
210 | .pixclock = 50000, | |
211 | .xres = 640, | |
212 | .yres = 480, | |
213 | .bpp = 16, | |
214 | .hsync_len = 1, | |
215 | .left_margin = 0x9f, | |
216 | .right_margin = 1, | |
217 | .vsync_len = 44, | |
218 | .upper_margin = 0, | |
219 | .lower_margin = 0, | |
220 | .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, | |
221 | .lccr0 = LCCR0_Act, | |
222 | .lccr3 = LCCR3_PCP, | |
223 | .pxafb_backlight_power = mainstone_backlight_power, | |
224 | }; | |
225 | ||
226 | static struct pxafb_mach_info toshiba_ltm035a776c __initdata = { | |
227 | .pixclock = 110000, | |
228 | .xres = 240, | |
229 | .yres = 320, | |
230 | .bpp = 16, | |
231 | .hsync_len = 4, | |
232 | .left_margin = 8, | |
233 | .right_margin = 20, | |
234 | .vsync_len = 3, | |
235 | .upper_margin = 1, | |
236 | .lower_margin = 10, | |
237 | .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, | |
238 | .lccr0 = LCCR0_Act, | |
239 | .lccr3 = LCCR3_PCP, | |
240 | .pxafb_backlight_power = mainstone_backlight_power, | |
241 | }; | |
242 | ||
243 | static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *, struct pt_regs *), void *data) | |
244 | { | |
245 | int err; | |
246 | ||
247 | /* | |
248 | * setup GPIO for PXA27x MMC controller | |
249 | */ | |
250 | pxa_gpio_mode(GPIO32_MMCCLK_MD); | |
251 | pxa_gpio_mode(GPIO112_MMCCMD_MD); | |
252 | pxa_gpio_mode(GPIO92_MMCDAT0_MD); | |
253 | pxa_gpio_mode(GPIO109_MMCDAT1_MD); | |
254 | pxa_gpio_mode(GPIO110_MMCDAT2_MD); | |
255 | pxa_gpio_mode(GPIO111_MMCDAT3_MD); | |
256 | ||
257 | /* make sure SD/Memory Stick multiplexer's signals | |
258 | * are routed to MMC controller | |
259 | */ | |
260 | MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL; | |
261 | ||
262 | err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, SA_INTERRUPT, | |
263 | "MMC card detect", data); | |
264 | if (err) { | |
265 | printk(KERN_ERR "mainstone_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); | |
266 | return -1; | |
267 | } | |
268 | ||
269 | return 0; | |
270 | } | |
271 | ||
272 | static void mainstone_mci_setpower(struct device *dev, unsigned int vdd) | |
273 | { | |
274 | struct pxamci_platform_data* p_d = dev->platform_data; | |
275 | ||
276 | if (( 1 << vdd) & p_d->ocr_mask) { | |
277 | printk(KERN_DEBUG "%s: on\n", __FUNCTION__); | |
278 | MST_MSCWR1 |= MST_MSCWR1_MMC_ON; | |
279 | MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL; | |
280 | } else { | |
281 | printk(KERN_DEBUG "%s: off\n", __FUNCTION__); | |
282 | MST_MSCWR1 &= ~MST_MSCWR1_MMC_ON; | |
283 | } | |
284 | } | |
285 | ||
286 | static void mainstone_mci_exit(struct device *dev, void *data) | |
287 | { | |
288 | free_irq(MAINSTONE_MMC_IRQ, data); | |
289 | } | |
290 | ||
291 | static struct pxamci_platform_data mainstone_mci_platform_data = { | |
292 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | |
293 | .init = mainstone_mci_init, | |
294 | .setpower = mainstone_mci_setpower, | |
295 | .exit = mainstone_mci_exit, | |
296 | }; | |
297 | ||
6f475c01 NP |
298 | static void mainstone_irda_transceiver_mode(struct device *dev, int mode) |
299 | { | |
300 | unsigned long flags; | |
301 | ||
302 | local_irq_save(flags); | |
303 | if (mode & IR_SIRMODE) { | |
304 | MST_MSCWR1 &= ~MST_MSCWR1_IRDA_FIR; | |
305 | } else if (mode & IR_FIRMODE) { | |
306 | MST_MSCWR1 |= MST_MSCWR1_IRDA_FIR; | |
307 | } | |
308 | if (mode & IR_OFF) { | |
309 | MST_MSCWR1 = (MST_MSCWR1 & ~MST_MSCWR1_IRDA_MASK) | MST_MSCWR1_IRDA_OFF; | |
310 | } else { | |
311 | MST_MSCWR1 = (MST_MSCWR1 & ~MST_MSCWR1_IRDA_MASK) | MST_MSCWR1_IRDA_FULL; | |
312 | } | |
313 | local_irq_restore(flags); | |
314 | } | |
315 | ||
316 | static struct pxaficp_platform_data mainstone_ficp_platform_data = { | |
317 | .transceiver_cap = IR_SIRMODE | IR_FIRMODE | IR_OFF, | |
318 | .transceiver_mode = mainstone_irda_transceiver_mode, | |
319 | }; | |
320 | ||
1da177e4 LT |
321 | static void __init mainstone_init(void) |
322 | { | |
323 | /* | |
324 | * On Mainstone, we route AC97_SYSCLK via GPIO45 to | |
325 | * the audio daughter card | |
326 | */ | |
327 | pxa_gpio_mode(GPIO45_SYSCLK_AC97_MD); | |
328 | ||
329 | platform_device_register(&smc91x_device); | |
330 | platform_device_register(&mst_audio_device); | |
331 | ||
332 | /* reading Mainstone's "Virtual Configuration Register" | |
333 | might be handy to select LCD type here */ | |
334 | if (0) | |
335 | set_pxa_fb_info(&toshiba_ltm04c380k); | |
336 | else | |
337 | set_pxa_fb_info(&toshiba_ltm035a776c); | |
338 | ||
339 | pxa_set_mci_info(&mainstone_mci_platform_data); | |
6f475c01 | 340 | pxa_set_ficp_info(&mainstone_ficp_platform_data); |
1da177e4 LT |
341 | } |
342 | ||
343 | ||
344 | static struct map_desc mainstone_io_desc[] __initdata = { | |
6f9182eb DS |
345 | { /* CPLD */ |
346 | .virtual = MST_FPGA_VIRT, | |
347 | .pfn = __phys_to_pfn(MST_FPGA_PHYS), | |
348 | .length = 0x00100000, | |
349 | .type = MT_DEVICE | |
350 | } | |
1da177e4 LT |
351 | }; |
352 | ||
353 | static void __init mainstone_map_io(void) | |
354 | { | |
355 | pxa_map_io(); | |
356 | iotable_init(mainstone_io_desc, ARRAY_SIZE(mainstone_io_desc)); | |
357 | ||
358 | /* initialize sleep mode regs (wake-up sources, etc) */ | |
359 | PGSR0 = 0x00008800; | |
360 | PGSR1 = 0x00000002; | |
361 | PGSR2 = 0x0001FC00; | |
362 | PGSR3 = 0x00001F81; | |
363 | PWER = 0xC0000002; | |
364 | PRER = 0x00000002; | |
365 | PFER = 0x00000002; | |
8775420d TP |
366 | /* for use I SRAM as framebuffer. */ |
367 | PSLR |= 0xF04; | |
368 | PCFR = 0x66; | |
369 | /* For Keypad wakeup. */ | |
370 | KPC &=~KPC_ASACT; | |
371 | KPC |=KPC_AS; | |
372 | PKWR = 0x000FD000; | |
373 | /* Need read PKWR back after set it. */ | |
374 | PKWR; | |
1da177e4 LT |
375 | } |
376 | ||
377 | MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)") | |
e9dea0c6 RK |
378 | /* Maintainer: MontaVista Software Inc. */ |
379 | .phys_ram = 0xa0000000, | |
380 | .phys_io = 0x40000000, | |
68070bde | 381 | .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, |
e9dea0c6 RK |
382 | .map_io = mainstone_map_io, |
383 | .init_irq = mainstone_init_irq, | |
1da177e4 | 384 | .timer = &pxa_timer, |
e9dea0c6 | 385 | .init_machine = mainstone_init, |
1da177e4 | 386 | MACHINE_END |