diff options
author | Marc Zyngier <marc.zyngier@altran.com> | 2008-08-14 11:20:31 -0400 |
---|---|---|
committer | Marc Zyngier <maz@young-lust.wild-wind.fr.eu.org> | 2008-09-09 11:41:46 -0400 |
commit | 352699a3d7ccb027e0139a7a67931e7907af6249 (patch) | |
tree | aa8c9e763d50ac736c37c238318cedd4361ed605 /arch/arm/mach-pxa/viper.c | |
parent | fb683f1627745e937ef199edd3428ac4b2ef1e08 (diff) |
Basic support for the Arcom/Eurotech Viper SBC.
Signed-off-by: Marc Zyngier <marc.zyngier@altran.com>
Diffstat (limited to 'arch/arm/mach-pxa/viper.c')
-rw-r--r-- | arch/arm/mach-pxa/viper.c | 951 |
1 files changed, 951 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c new file mode 100644 index 000000000000..d7632f63603c --- /dev/null +++ b/arch/arm/mach-pxa/viper.c | |||
@@ -0,0 +1,951 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/viper.c | ||
3 | * | ||
4 | * Support for the Arcom VIPER SBC. | ||
5 | * | ||
6 | * Author: Ian Campbell | ||
7 | * Created: Feb 03, 2003 | ||
8 | * Copyright: Arcom Control Systems | ||
9 | * | ||
10 | * Maintained by Marc Zyngier <maz@misterjones.org> | ||
11 | * <marc.zyngier@altran.com> | ||
12 | * | ||
13 | * Based on lubbock.c: | ||
14 | * Author: Nicolas Pitre | ||
15 | * Created: Jun 15, 2001 | ||
16 | * Copyright: MontaVista Software Inc. | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License version 2 as | ||
20 | * published by the Free Software Foundation. | ||
21 | */ | ||
22 | |||
23 | #include <linux/types.h> | ||
24 | #include <linux/memory.h> | ||
25 | #include <linux/cpu.h> | ||
26 | #include <linux/cpufreq.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/fs.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/major.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/pm.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/gpio.h> | ||
36 | #include <linux/i2c-gpio.h> | ||
37 | #include <linux/serial_8250.h> | ||
38 | #include <linux/smc91x.h> | ||
39 | #include <linux/pwm_backlight.h> | ||
40 | #include <linux/usb/isp116x.h> | ||
41 | #include <linux/mtd/mtd.h> | ||
42 | #include <linux/mtd/partitions.h> | ||
43 | #include <linux/mtd/physmap.h> | ||
44 | |||
45 | #include <mach/pxa-regs.h> | ||
46 | #include <mach/pxa2xx-regs.h> | ||
47 | #include <mach/bitfield.h> | ||
48 | #include <mach/audio.h> | ||
49 | #include <mach/pxafb.h> | ||
50 | #include <mach/mfp-pxa25x.h> | ||
51 | #include <mach/i2c.h> | ||
52 | #include <mach/viper.h> | ||
53 | |||
54 | #include <asm/setup.h> | ||
55 | #include <asm/mach-types.h> | ||
56 | #include <asm/irq.h> | ||
57 | #include <asm/sizes.h> | ||
58 | |||
59 | #include <asm/mach/arch.h> | ||
60 | #include <asm/mach/map.h> | ||
61 | #include <asm/mach/irq.h> | ||
62 | |||
63 | #include "generic.h" | ||
64 | #include "devices.h" | ||
65 | |||
66 | static unsigned int icr; | ||
67 | |||
68 | static void viper_icr_set_bit(unsigned int bit) | ||
69 | { | ||
70 | icr |= bit; | ||
71 | VIPER_ICR = icr; | ||
72 | } | ||
73 | |||
74 | static void viper_icr_clear_bit(unsigned int bit) | ||
75 | { | ||
76 | icr &= ~bit; | ||
77 | VIPER_ICR = icr; | ||
78 | } | ||
79 | |||
80 | /* This function is used from the pcmcia module to reset the CF */ | ||
81 | void viper_cf_rst(int state) | ||
82 | { | ||
83 | if (state) | ||
84 | viper_icr_set_bit(VIPER_ICR_CF_RST); | ||
85 | else | ||
86 | viper_icr_clear_bit(VIPER_ICR_CF_RST); | ||
87 | } | ||
88 | EXPORT_SYMBOL(viper_cf_rst); | ||
89 | |||
90 | /* | ||
91 | * The CPLD version register was not present on VIPER boards prior to | ||
92 | * v2i1. On v1 boards where the version register is not present we | ||
93 | * will just read back the previous value from the databus. | ||
94 | * | ||
95 | * Therefore we do two reads. The first time we write 0 to the | ||
96 | * (read-only) register before reading and the second time we write | ||
97 | * 0xff first. If the two reads do not match or they read back as 0xff | ||
98 | * or 0x00 then we have version 1 hardware. | ||
99 | */ | ||
100 | static u8 viper_hw_version(void) | ||
101 | { | ||
102 | u8 v1, v2; | ||
103 | unsigned long flags; | ||
104 | |||
105 | local_irq_save(flags); | ||
106 | |||
107 | VIPER_VERSION = 0; | ||
108 | v1 = VIPER_VERSION; | ||
109 | VIPER_VERSION = 0xff; | ||
110 | v2 = VIPER_VERSION; | ||
111 | |||
112 | v1 = (v1 != v2 || v1 == 0xff) ? 0 : v1; | ||
113 | |||
114 | local_irq_restore(flags); | ||
115 | return v1; | ||
116 | } | ||
117 | |||
118 | /* CPU sysdev */ | ||
119 | static int viper_cpu_suspend(struct sys_device *sysdev, pm_message_t state) | ||
120 | { | ||
121 | viper_icr_set_bit(VIPER_ICR_R_DIS); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int viper_cpu_resume(struct sys_device *sysdev) | ||
126 | { | ||
127 | viper_icr_clear_bit(VIPER_ICR_R_DIS); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static struct sysdev_driver viper_cpu_sysdev_driver = { | ||
132 | .suspend = viper_cpu_suspend, | ||
133 | .resume = viper_cpu_resume, | ||
134 | }; | ||
135 | |||
136 | static unsigned int current_voltage_divisor; | ||
137 | |||
138 | /* | ||
139 | * If force is not true then step from existing to new divisor. If | ||
140 | * force is true then jump straight to the new divisor. Stepping is | ||
141 | * used because if the jump in voltage is too large, the VCC can dip | ||
142 | * too low and the regulator cuts out. | ||
143 | * | ||
144 | * force can be used to initialize the divisor to a know state by | ||
145 | * setting the value for the current clock speed, since we are already | ||
146 | * running at that speed we know the voltage should be pretty close so | ||
147 | * the jump won't be too large | ||
148 | */ | ||
149 | static void viper_set_core_cpu_voltage(unsigned long khz, int force) | ||
150 | { | ||
151 | int i = 0; | ||
152 | unsigned int divisor = 0; | ||
153 | const char *v; | ||
154 | |||
155 | if (khz < 200000) { | ||
156 | v = "1.0"; divisor = 0xfff; | ||
157 | } else if (khz < 300000) { | ||
158 | v = "1.1"; divisor = 0xde5; | ||
159 | } else { | ||
160 | v = "1.3"; divisor = 0x325; | ||
161 | } | ||
162 | |||
163 | pr_debug("viper: setting CPU core voltage to %sV at %d.%03dMHz\n", | ||
164 | v, (int)khz / 1000, (int)khz % 1000); | ||
165 | |||
166 | #define STEP 0x100 | ||
167 | do { | ||
168 | int step; | ||
169 | |||
170 | if (force) | ||
171 | step = divisor; | ||
172 | else if (current_voltage_divisor < divisor - STEP) | ||
173 | step = current_voltage_divisor + STEP; | ||
174 | else if (current_voltage_divisor > divisor + STEP) | ||
175 | step = current_voltage_divisor - STEP; | ||
176 | else | ||
177 | step = divisor; | ||
178 | force = 0; | ||
179 | |||
180 | gpio_set_value(VIPER_PSU_CLK_GPIO, 0); | ||
181 | gpio_set_value(VIPER_PSU_nCS_LD_GPIO, 0); | ||
182 | |||
183 | for (i = 1 << 11 ; i > 0 ; i >>= 1) { | ||
184 | udelay(1); | ||
185 | |||
186 | gpio_set_value(VIPER_PSU_DATA_GPIO, step & i); | ||
187 | udelay(1); | ||
188 | |||
189 | gpio_set_value(VIPER_PSU_CLK_GPIO, 1); | ||
190 | udelay(1); | ||
191 | |||
192 | gpio_set_value(VIPER_PSU_CLK_GPIO, 0); | ||
193 | } | ||
194 | udelay(1); | ||
195 | |||
196 | gpio_set_value(VIPER_PSU_nCS_LD_GPIO, 1); | ||
197 | udelay(1); | ||
198 | |||
199 | gpio_set_value(VIPER_PSU_nCS_LD_GPIO, 0); | ||
200 | |||
201 | current_voltage_divisor = step; | ||
202 | } while (current_voltage_divisor != divisor); | ||
203 | } | ||
204 | |||
205 | /* Interrupt handling */ | ||
206 | static unsigned long viper_irq_enabled_mask; | ||
207 | |||
208 | static void viper_ack_irq(unsigned int irq) | ||
209 | { | ||
210 | int viper_irq = irq - PXA_ISA_IRQ(0); | ||
211 | |||
212 | if (viper_irq < 8) | ||
213 | VIPER_LO_IRQ_STATUS = 1 << viper_irq; | ||
214 | else | ||
215 | VIPER_HI_IRQ_STATUS = 1 << (viper_irq - 8); | ||
216 | } | ||
217 | |||
218 | static void viper_mask_irq(unsigned int irq) | ||
219 | { | ||
220 | viper_irq_enabled_mask &= ~(1 << (irq - PXA_ISA_IRQ(0))); | ||
221 | } | ||
222 | |||
223 | static void viper_unmask_irq(unsigned int irq) | ||
224 | { | ||
225 | viper_irq_enabled_mask |= (1 << (irq - PXA_ISA_IRQ(0))); | ||
226 | } | ||
227 | |||
228 | static inline unsigned long viper_irq_pending(void) | ||
229 | { | ||
230 | return (VIPER_HI_IRQ_STATUS << 8 | VIPER_LO_IRQ_STATUS) & | ||
231 | viper_irq_enabled_mask; | ||
232 | } | ||
233 | |||
234 | static void viper_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
235 | { | ||
236 | unsigned long pending; | ||
237 | |||
238 | pending = viper_irq_pending(); | ||
239 | do { | ||
240 | if (likely(pending)) { | ||
241 | irq = PXA_ISA_IRQ(0) + __ffs(pending); | ||
242 | generic_handle_irq(irq); | ||
243 | } | ||
244 | pending = viper_irq_pending(); | ||
245 | } while (pending); | ||
246 | } | ||
247 | |||
248 | static struct irq_chip viper_irq_chip = { | ||
249 | .name = "ISA", | ||
250 | .ack = viper_ack_irq, | ||
251 | .mask = viper_mask_irq, | ||
252 | .unmask = viper_unmask_irq | ||
253 | }; | ||
254 | |||
255 | static void __init viper_init_irq(void) | ||
256 | { | ||
257 | const int isa_irqs[] = { 3, 4, 5, 6, 7, 10, 11, 12, 9, 14, 15 }; | ||
258 | int irq; | ||
259 | int isa_irq; | ||
260 | |||
261 | pxa25x_init_irq(); | ||
262 | |||
263 | /* setup ISA IRQs */ | ||
264 | for (irq = 0; irq < ARRAY_SIZE(isa_irqs); irq++) { | ||
265 | isa_irq = isa_irqs[irq]; | ||
266 | set_irq_chip(isa_irq, &viper_irq_chip); | ||
267 | set_irq_handler(isa_irq, handle_edge_irq); | ||
268 | set_irq_flags(isa_irq, IRQF_VALID | IRQF_PROBE); | ||
269 | } | ||
270 | |||
271 | set_irq_chained_handler(gpio_to_irq(VIPER_CPLD_GPIO), | ||
272 | viper_irq_handler); | ||
273 | set_irq_type(gpio_to_irq(VIPER_CPLD_GPIO), IRQ_TYPE_EDGE_BOTH); | ||
274 | |||
275 | #ifndef CONFIG_SERIAL_PXA | ||
276 | /* | ||
277 | * 8250 doesn't support IRQ_TYPE being passed as part | ||
278 | * of the plat_serial8250_port structure... | ||
279 | */ | ||
280 | set_irq_type(gpio_to_irq(VIPER_UARTA_GPIO), IRQ_TYPE_EDGE_RISING); | ||
281 | set_irq_type(gpio_to_irq(VIPER_UARTB_GPIO), IRQ_TYPE_EDGE_RISING); | ||
282 | #endif | ||
283 | } | ||
284 | |||
285 | /* Flat Panel */ | ||
286 | static struct pxafb_mode_info fb_mode_info[] = { | ||
287 | { | ||
288 | .pixclock = 157500, | ||
289 | |||
290 | .xres = 320, | ||
291 | .yres = 240, | ||
292 | |||
293 | .bpp = 16, | ||
294 | |||
295 | .hsync_len = 63, | ||
296 | .left_margin = 7, | ||
297 | .right_margin = 13, | ||
298 | |||
299 | .vsync_len = 20, | ||
300 | .upper_margin = 0, | ||
301 | .lower_margin = 0, | ||
302 | |||
303 | .sync = 0, | ||
304 | }, | ||
305 | }; | ||
306 | |||
307 | static struct pxafb_mach_info fb_info = { | ||
308 | .modes = fb_mode_info, | ||
309 | .num_modes = 1, | ||
310 | .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL, | ||
311 | }; | ||
312 | |||
313 | static int viper_backlight_init(struct device *dev) | ||
314 | { | ||
315 | int ret; | ||
316 | |||
317 | /* GPIO9 and 10 control FB backlight. Initialise to off */ | ||
318 | ret = gpio_request(VIPER_BCKLIGHT_EN_GPIO, "Backlight"); | ||
319 | if (ret) | ||
320 | goto err_request_bckl; | ||
321 | |||
322 | ret = gpio_request(VIPER_LCD_EN_GPIO, "LCD"); | ||
323 | if (ret) | ||
324 | goto err_request_lcd; | ||
325 | |||
326 | ret = gpio_direction_output(VIPER_BCKLIGHT_EN_GPIO, 0); | ||
327 | if (ret) | ||
328 | goto err_dir; | ||
329 | |||
330 | ret = gpio_direction_output(VIPER_LCD_EN_GPIO, 0); | ||
331 | if (ret) | ||
332 | goto err_dir; | ||
333 | |||
334 | return 0; | ||
335 | |||
336 | err_dir: | ||
337 | gpio_free(VIPER_LCD_EN_GPIO); | ||
338 | err_request_lcd: | ||
339 | gpio_free(VIPER_BCKLIGHT_EN_GPIO); | ||
340 | err_request_bckl: | ||
341 | dev_err(dev, "Failed to setup LCD GPIOs\n"); | ||
342 | |||
343 | return ret; | ||
344 | } | ||
345 | |||
346 | static int viper_backlight_notify(int brightness) | ||
347 | { | ||
348 | gpio_set_value(VIPER_LCD_EN_GPIO, !!brightness); | ||
349 | gpio_set_value(VIPER_BCKLIGHT_EN_GPIO, !!brightness); | ||
350 | |||
351 | return brightness; | ||
352 | } | ||
353 | |||
354 | static void viper_backlight_exit(struct device *dev) | ||
355 | { | ||
356 | gpio_free(VIPER_LCD_EN_GPIO); | ||
357 | gpio_free(VIPER_BCKLIGHT_EN_GPIO); | ||
358 | } | ||
359 | |||
360 | static struct platform_pwm_backlight_data viper_backlight_data = { | ||
361 | .pwm_id = 0, | ||
362 | .max_brightness = 100, | ||
363 | .dft_brightness = 100, | ||
364 | .pwm_period_ns = 1000000, | ||
365 | .init = viper_backlight_init, | ||
366 | .notify = viper_backlight_notify, | ||
367 | .exit = viper_backlight_exit, | ||
368 | }; | ||
369 | |||
370 | static struct platform_device viper_backlight_device = { | ||
371 | .name = "pwm-backlight", | ||
372 | .dev = { | ||
373 | .parent = &pxa25x_device_pwm0.dev, | ||
374 | .platform_data = &viper_backlight_data, | ||
375 | }, | ||
376 | }; | ||
377 | |||
378 | /* Ethernet */ | ||
379 | static struct resource smc91x_resources[] = { | ||
380 | [0] = { | ||
381 | .name = "smc91x-regs", | ||
382 | .start = VIPER_ETH_PHYS + 0x300, | ||
383 | .end = VIPER_ETH_PHYS + 0x30f, | ||
384 | .flags = IORESOURCE_MEM, | ||
385 | }, | ||
386 | [1] = { | ||
387 | .start = gpio_to_irq(VIPER_ETH_GPIO), | ||
388 | .end = gpio_to_irq(VIPER_ETH_GPIO), | ||
389 | .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, | ||
390 | }, | ||
391 | [2] = { | ||
392 | .name = "smc91x-data32", | ||
393 | .start = VIPER_ETH_DATA_PHYS, | ||
394 | .end = VIPER_ETH_DATA_PHYS + 3, | ||
395 | .flags = IORESOURCE_MEM, | ||
396 | }, | ||
397 | }; | ||
398 | |||
399 | static struct smc91x_platdata viper_smc91x_info = { | ||
400 | .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, | ||
401 | .leda = RPC_LED_100_10, | ||
402 | .ledb = RPC_LED_TX_RX, | ||
403 | }; | ||
404 | |||
405 | static struct platform_device smc91x_device = { | ||
406 | .name = "smc91x", | ||
407 | .id = -1, | ||
408 | .num_resources = ARRAY_SIZE(smc91x_resources), | ||
409 | .resource = smc91x_resources, | ||
410 | .dev = { | ||
411 | .platform_data = &viper_smc91x_info, | ||
412 | }, | ||
413 | }; | ||
414 | |||
415 | /* i2c */ | ||
416 | static struct i2c_gpio_platform_data i2c_bus_data = { | ||
417 | .sda_pin = VIPER_RTC_I2C_SDA_GPIO, | ||
418 | .scl_pin = VIPER_RTC_I2C_SCL_GPIO, | ||
419 | .udelay = 10, | ||
420 | .timeout = 100, | ||
421 | }; | ||
422 | |||
423 | static struct platform_device i2c_bus_device = { | ||
424 | .name = "i2c-gpio", | ||
425 | .id = 1, /* pxa2xx-i2c is bus 0, so start at 1 */ | ||
426 | .dev = { | ||
427 | .platform_data = &i2c_bus_data, | ||
428 | } | ||
429 | }; | ||
430 | |||
431 | static struct i2c_board_info __initdata viper_i2c_devices[] = { | ||
432 | { | ||
433 | I2C_BOARD_INFO("ds1338", 0x68), | ||
434 | }, | ||
435 | }; | ||
436 | |||
437 | /* | ||
438 | * Serial configuration: | ||
439 | * You can either have the standard PXA ports driven by the PXA driver, | ||
440 | * or all the ports (PXA + 16850) driven by the 8250 driver. | ||
441 | * Choose your poison. | ||
442 | */ | ||
443 | |||
444 | static struct resource viper_serial_resources[] = { | ||
445 | #ifndef CONFIG_SERIAL_PXA | ||
446 | { | ||
447 | .start = 0x40100000, | ||
448 | .end = 0x4010001f, | ||
449 | .flags = IORESOURCE_MEM, | ||
450 | }, | ||
451 | { | ||
452 | .start = 0x40200000, | ||
453 | .end = 0x4020001f, | ||
454 | .flags = IORESOURCE_MEM, | ||
455 | }, | ||
456 | { | ||
457 | .start = 0x40700000, | ||
458 | .end = 0x4070001f, | ||
459 | .flags = IORESOURCE_MEM, | ||
460 | }, | ||
461 | { | ||
462 | .start = VIPER_UARTA_PHYS, | ||
463 | .end = VIPER_UARTA_PHYS + 0xf, | ||
464 | .flags = IORESOURCE_MEM, | ||
465 | }, | ||
466 | { | ||
467 | .start = VIPER_UARTB_PHYS, | ||
468 | .end = VIPER_UARTB_PHYS + 0xf, | ||
469 | .flags = IORESOURCE_MEM, | ||
470 | }, | ||
471 | #else | ||
472 | { | ||
473 | 0, | ||
474 | }, | ||
475 | #endif | ||
476 | }; | ||
477 | |||
478 | static struct plat_serial8250_port serial_platform_data[] = { | ||
479 | #ifndef CONFIG_SERIAL_PXA | ||
480 | /* Internal UARTs */ | ||
481 | { | ||
482 | .membase = (void *)&FFUART, | ||
483 | .mapbase = __PREG(FFUART), | ||
484 | .irq = IRQ_FFUART, | ||
485 | .uartclk = 921600 * 16, | ||
486 | .regshift = 2, | ||
487 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, | ||
488 | .iotype = UPIO_MEM, | ||
489 | }, | ||
490 | { | ||
491 | .membase = (void *)&BTUART, | ||
492 | .mapbase = __PREG(BTUART), | ||
493 | .irq = IRQ_BTUART, | ||
494 | .uartclk = 921600 * 16, | ||
495 | .regshift = 2, | ||
496 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, | ||
497 | .iotype = UPIO_MEM, | ||
498 | }, | ||
499 | { | ||
500 | .membase = (void *)&STUART, | ||
501 | .mapbase = __PREG(STUART), | ||
502 | .irq = IRQ_STUART, | ||
503 | .uartclk = 921600 * 16, | ||
504 | .regshift = 2, | ||
505 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, | ||
506 | .iotype = UPIO_MEM, | ||
507 | }, | ||
508 | /* External UARTs */ | ||
509 | { | ||
510 | .mapbase = VIPER_UARTA_PHYS, | ||
511 | .irq = gpio_to_irq(VIPER_UARTA_GPIO), | ||
512 | .uartclk = 1843200, | ||
513 | .regshift = 1, | ||
514 | .iotype = UPIO_MEM, | ||
515 | .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | | ||
516 | UPF_SKIP_TEST, | ||
517 | }, | ||
518 | { | ||
519 | .mapbase = VIPER_UARTB_PHYS, | ||
520 | .irq = gpio_to_irq(VIPER_UARTB_GPIO), | ||
521 | .uartclk = 1843200, | ||
522 | .regshift = 1, | ||
523 | .iotype = UPIO_MEM, | ||
524 | .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | | ||
525 | UPF_SKIP_TEST, | ||
526 | }, | ||
527 | #endif | ||
528 | { }, | ||
529 | }; | ||
530 | |||
531 | static struct platform_device serial_device = { | ||
532 | .name = "serial8250", | ||
533 | .id = 0, | ||
534 | .dev = { | ||
535 | .platform_data = serial_platform_data, | ||
536 | }, | ||
537 | .num_resources = ARRAY_SIZE(viper_serial_resources), | ||
538 | .resource = viper_serial_resources, | ||
539 | }; | ||
540 | |||
541 | /* USB */ | ||
542 | static void isp116x_delay(struct device *dev, int delay) | ||
543 | { | ||
544 | ndelay(delay); | ||
545 | } | ||
546 | |||
547 | static struct resource isp116x_resources[] = { | ||
548 | [0] = { /* DATA */ | ||
549 | .start = VIPER_USB_PHYS + 0, | ||
550 | .end = VIPER_USB_PHYS + 1, | ||
551 | .flags = IORESOURCE_MEM, | ||
552 | }, | ||
553 | [1] = { /* ADDR */ | ||
554 | .start = VIPER_USB_PHYS + 2, | ||
555 | .end = VIPER_USB_PHYS + 3, | ||
556 | .flags = IORESOURCE_MEM, | ||
557 | }, | ||
558 | [2] = { | ||
559 | .start = gpio_to_irq(VIPER_USB_GPIO), | ||
560 | .end = gpio_to_irq(VIPER_USB_GPIO), | ||
561 | .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, | ||
562 | }, | ||
563 | }; | ||
564 | |||
565 | /* (DataBusWidth16|AnalogOCEnable|DREQOutputPolarity|DownstreamPort15KRSel ) */ | ||
566 | static struct isp116x_platform_data isp116x_platform_data = { | ||
567 | /* Enable internal resistors on downstream ports */ | ||
568 | .sel15Kres = 1, | ||
569 | /* On-chip overcurrent protection */ | ||
570 | .oc_enable = 1, | ||
571 | /* INT output polarity */ | ||
572 | .int_act_high = 1, | ||
573 | /* INT edge or level triggered */ | ||
574 | .int_edge_triggered = 0, | ||
575 | |||
576 | /* WAKEUP pin connected - NOT SUPPORTED */ | ||
577 | /* .remote_wakeup_connected = 0, */ | ||
578 | /* Wakeup by devices on usb bus enabled */ | ||
579 | .remote_wakeup_enable = 0, | ||
580 | .delay = isp116x_delay, | ||
581 | }; | ||
582 | |||
583 | static struct platform_device isp116x_device = { | ||
584 | .name = "isp116x-hcd", | ||
585 | .id = -1, | ||
586 | .num_resources = ARRAY_SIZE(isp116x_resources), | ||
587 | .resource = isp116x_resources, | ||
588 | .dev = { | ||
589 | .platform_data = &isp116x_platform_data, | ||
590 | }, | ||
591 | |||
592 | }; | ||
593 | |||
594 | /* MTD */ | ||
595 | static struct resource mtd_resources[] = { | ||
596 | [0] = { /* RedBoot config + filesystem flash */ | ||
597 | .start = VIPER_FLASH_PHYS, | ||
598 | .end = VIPER_FLASH_PHYS + SZ_32M - 1, | ||
599 | .flags = IORESOURCE_MEM, | ||
600 | }, | ||
601 | [1] = { /* Boot flash */ | ||
602 | .start = VIPER_BOOT_PHYS, | ||
603 | .end = VIPER_BOOT_PHYS + SZ_1M - 1, | ||
604 | .flags = IORESOURCE_MEM, | ||
605 | }, | ||
606 | [2] = { /* | ||
607 | * SRAM size is actually 256KB, 8bits, with a sparse mapping | ||
608 | * (each byte is on a 16bit boundary). | ||
609 | */ | ||
610 | .start = _VIPER_SRAM_BASE, | ||
611 | .end = _VIPER_SRAM_BASE + SZ_512K - 1, | ||
612 | .flags = IORESOURCE_MEM, | ||
613 | }, | ||
614 | }; | ||
615 | |||
616 | static struct mtd_partition viper_boot_flash_partition = { | ||
617 | .name = "RedBoot", | ||
618 | .size = SZ_1M, | ||
619 | .offset = 0, | ||
620 | .mask_flags = MTD_WRITEABLE, /* force R/O */ | ||
621 | }; | ||
622 | |||
623 | static struct physmap_flash_data viper_flash_data[] = { | ||
624 | [0] = { | ||
625 | .width = 2, | ||
626 | .parts = NULL, | ||
627 | .nr_parts = 0, | ||
628 | }, | ||
629 | [1] = { | ||
630 | .width = 2, | ||
631 | .parts = &viper_boot_flash_partition, | ||
632 | .nr_parts = 1, | ||
633 | }, | ||
634 | }; | ||
635 | |||
636 | static struct platform_device viper_mtd_devices[] = { | ||
637 | [0] = { | ||
638 | .name = "physmap-flash", | ||
639 | .id = 0, | ||
640 | .dev = { | ||
641 | .platform_data = &viper_flash_data[0], | ||
642 | }, | ||
643 | .resource = &mtd_resources[0], | ||
644 | .num_resources = 1, | ||
645 | }, | ||
646 | [1] = { | ||
647 | .name = "physmap-flash", | ||
648 | .id = 1, | ||
649 | .dev = { | ||
650 | .platform_data = &viper_flash_data[1], | ||
651 | }, | ||
652 | .resource = &mtd_resources[1], | ||
653 | .num_resources = 1, | ||
654 | }, | ||
655 | }; | ||
656 | |||
657 | static struct platform_device *viper_devs[] __initdata = { | ||
658 | &smc91x_device, | ||
659 | &i2c_bus_device, | ||
660 | &serial_device, | ||
661 | &isp116x_device, | ||
662 | &viper_mtd_devices[0], | ||
663 | &viper_mtd_devices[1], | ||
664 | &viper_backlight_device, | ||
665 | }; | ||
666 | |||
667 | static mfp_cfg_t viper_pin_config[] __initdata = { | ||
668 | /* Chip selects */ | ||
669 | GPIO15_nCS_1, | ||
670 | GPIO78_nCS_2, | ||
671 | GPIO79_nCS_3, | ||
672 | GPIO80_nCS_4, | ||
673 | GPIO33_nCS_5, | ||
674 | |||
675 | /* FP Backlight */ | ||
676 | GPIO9_GPIO, /* VIPER_BCKLIGHT_EN_GPIO */ | ||
677 | GPIO10_GPIO, /* VIPER_LCD_EN_GPIO */ | ||
678 | GPIO16_PWM0_OUT, | ||
679 | |||
680 | /* Ethernet PHY Ready */ | ||
681 | GPIO18_RDY, | ||
682 | |||
683 | /* Serial shutdown */ | ||
684 | GPIO12_GPIO | MFP_LPM_DRIVE_HIGH, /* VIPER_UART_SHDN_GPIO */ | ||
685 | |||
686 | /* Compact-Flash / PC104 */ | ||
687 | GPIO48_nPOE, | ||
688 | GPIO49_nPWE, | ||
689 | GPIO50_nPIOR, | ||
690 | GPIO51_nPIOW, | ||
691 | GPIO52_nPCE_1, | ||
692 | GPIO53_nPCE_2, | ||
693 | GPIO54_nPSKTSEL, | ||
694 | GPIO55_nPREG, | ||
695 | GPIO56_nPWAIT, | ||
696 | GPIO57_nIOIS16, | ||
697 | GPIO8_GPIO, /* VIPER_CF_RDY_GPIO */ | ||
698 | GPIO32_GPIO, /* VIPER_CF_CD_GPIO */ | ||
699 | GPIO82_GPIO, /* VIPER_CF_POWER_GPIO */ | ||
700 | |||
701 | /* Integrated UPS control */ | ||
702 | GPIO20_GPIO, /* VIPER_UPS_GPIO */ | ||
703 | |||
704 | /* Vcc regulator control */ | ||
705 | GPIO6_GPIO, /* VIPER_PSU_DATA_GPIO */ | ||
706 | GPIO11_GPIO, /* VIPER_PSU_CLK_GPIO */ | ||
707 | GPIO19_GPIO, /* VIPER_PSU_nCS_LD_GPIO */ | ||
708 | |||
709 | /* i2c busses */ | ||
710 | GPIO26_GPIO, /* VIPER_TPM_I2C_SDA_GPIO */ | ||
711 | GPIO27_GPIO, /* VIPER_TPM_I2C_SCL_GPIO */ | ||
712 | GPIO83_GPIO, /* VIPER_RTC_I2C_SDA_GPIO */ | ||
713 | GPIO84_GPIO, /* VIPER_RTC_I2C_SCL_GPIO */ | ||
714 | |||
715 | /* PC/104 Interrupt */ | ||
716 | GPIO1_GPIO | WAKEUP_ON_EDGE_RISE, /* VIPER_CPLD_GPIO */ | ||
717 | }; | ||
718 | |||
719 | static unsigned long viper_tpm; | ||
720 | |||
721 | static int __init viper_tpm_setup(char *str) | ||
722 | { | ||
723 | strict_strtoul(str, 10, &viper_tpm); | ||
724 | return 1; | ||
725 | } | ||
726 | |||
727 | __setup("tpm=", viper_tpm_setup); | ||
728 | |||
729 | static void __init viper_tpm_init(void) | ||
730 | { | ||
731 | struct platform_device *tpm_device; | ||
732 | struct i2c_gpio_platform_data i2c_tpm_data = { | ||
733 | .sda_pin = VIPER_TPM_I2C_SDA_GPIO, | ||
734 | .scl_pin = VIPER_TPM_I2C_SCL_GPIO, | ||
735 | .udelay = 10, | ||
736 | .timeout = 100, | ||
737 | }; | ||
738 | char *errstr; | ||
739 | |||
740 | /* Allocate TPM i2c bus if requested */ | ||
741 | if (!viper_tpm) | ||
742 | return; | ||
743 | |||
744 | tpm_device = platform_device_alloc("i2c-gpio", 2); | ||
745 | if (tpm_device) { | ||
746 | if (!platform_device_add_data(tpm_device, | ||
747 | &i2c_tpm_data, | ||
748 | sizeof(i2c_tpm_data))) { | ||
749 | if (platform_device_add(tpm_device)) { | ||
750 | errstr = "register TPM i2c bus"; | ||
751 | goto error_free_tpm; | ||
752 | } | ||
753 | } else { | ||
754 | errstr = "allocate TPM i2c bus data"; | ||
755 | goto error_free_tpm; | ||
756 | } | ||
757 | } else { | ||
758 | errstr = "allocate TPM i2c device"; | ||
759 | goto error_tpm; | ||
760 | } | ||
761 | |||
762 | return; | ||
763 | |||
764 | error_free_tpm: | ||
765 | kfree(tpm_device); | ||
766 | error_tpm: | ||
767 | pr_err("viper: Couldn't %s, giving up\n", errstr); | ||
768 | } | ||
769 | |||
770 | static void __init viper_init_vcore_gpios(void) | ||
771 | { | ||
772 | if (gpio_request(VIPER_PSU_DATA_GPIO, "PSU data")) | ||
773 | goto err_request_data; | ||
774 | |||
775 | if (gpio_request(VIPER_PSU_CLK_GPIO, "PSU clock")) | ||
776 | goto err_request_clk; | ||
777 | |||
778 | if (gpio_request(VIPER_PSU_nCS_LD_GPIO, "PSU cs")) | ||
779 | goto err_request_cs; | ||
780 | |||
781 | if (gpio_direction_output(VIPER_PSU_DATA_GPIO, 0) || | ||
782 | gpio_direction_output(VIPER_PSU_CLK_GPIO, 0) || | ||
783 | gpio_direction_output(VIPER_PSU_nCS_LD_GPIO, 0)) | ||
784 | goto err_dir; | ||
785 | |||
786 | /* c/should assume redboot set the correct level ??? */ | ||
787 | viper_set_core_cpu_voltage(get_clk_frequency_khz(0), 1); | ||
788 | |||
789 | return; | ||
790 | |||
791 | err_dir: | ||
792 | gpio_free(VIPER_PSU_nCS_LD_GPIO); | ||
793 | err_request_cs: | ||
794 | gpio_free(VIPER_PSU_CLK_GPIO); | ||
795 | err_request_clk: | ||
796 | gpio_free(VIPER_PSU_DATA_GPIO); | ||
797 | err_request_data: | ||
798 | pr_err("viper: Failed to setup vcore control GPIOs\n"); | ||
799 | } | ||
800 | |||
801 | static void __init viper_init_serial_gpio(void) | ||
802 | { | ||
803 | if (gpio_request(VIPER_UART_SHDN_GPIO, "UARTs shutdown")) | ||
804 | goto err_request; | ||
805 | |||
806 | if (gpio_direction_output(VIPER_UART_SHDN_GPIO, 0)) | ||
807 | goto err_dir; | ||
808 | |||
809 | return; | ||
810 | |||
811 | err_dir: | ||
812 | gpio_free(VIPER_UART_SHDN_GPIO); | ||
813 | err_request: | ||
814 | pr_err("viper: Failed to setup UART shutdown GPIO\n"); | ||
815 | } | ||
816 | |||
817 | #ifdef CONFIG_CPU_FREQ | ||
818 | static int viper_cpufreq_notifier(struct notifier_block *nb, | ||
819 | unsigned long val, void *data) | ||
820 | { | ||
821 | struct cpufreq_freqs *freq = data; | ||
822 | |||
823 | /* TODO: Adjust timings??? */ | ||
824 | |||
825 | switch (val) { | ||
826 | case CPUFREQ_PRECHANGE: | ||
827 | if (freq->old < freq->new) { | ||
828 | /* we are getting faster so raise the voltage | ||
829 | * before we change freq */ | ||
830 | viper_set_core_cpu_voltage(freq->new, 0); | ||
831 | } | ||
832 | break; | ||
833 | case CPUFREQ_POSTCHANGE: | ||
834 | if (freq->old > freq->new) { | ||
835 | /* we are slowing down so drop the power | ||
836 | * after we change freq */ | ||
837 | viper_set_core_cpu_voltage(freq->new, 0); | ||
838 | } | ||
839 | break; | ||
840 | case CPUFREQ_RESUMECHANGE: | ||
841 | viper_set_core_cpu_voltage(freq->new, 0); | ||
842 | break; | ||
843 | default: | ||
844 | /* ignore */ | ||
845 | break; | ||
846 | } | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static struct notifier_block viper_cpufreq_notifier_block = { | ||
852 | .notifier_call = viper_cpufreq_notifier | ||
853 | }; | ||
854 | |||
855 | static void __init viper_init_cpufreq(void) | ||
856 | { | ||
857 | if (cpufreq_register_notifier(&viper_cpufreq_notifier_block, | ||
858 | CPUFREQ_TRANSITION_NOTIFIER)) | ||
859 | pr_err("viper: Failed to setup cpufreq notifier\n"); | ||
860 | } | ||
861 | #else | ||
862 | static inline void viper_init_cpufreq(void) {} | ||
863 | #endif | ||
864 | |||
865 | static void viper_power_off(void) | ||
866 | { | ||
867 | pr_notice("Shutting off UPS\n"); | ||
868 | gpio_set_value(VIPER_UPS_GPIO, 1); | ||
869 | /* Spin to death... */ | ||
870 | while (1); | ||
871 | } | ||
872 | |||
873 | static void __init viper_init(void) | ||
874 | { | ||
875 | u8 version; | ||
876 | |||
877 | pm_power_off = viper_power_off; | ||
878 | |||
879 | pxa2xx_mfp_config(ARRAY_AND_SIZE(viper_pin_config)); | ||
880 | |||
881 | /* Wake-up serial console */ | ||
882 | viper_init_serial_gpio(); | ||
883 | |||
884 | set_pxa_fb_info(&fb_info); | ||
885 | |||
886 | /* v1 hardware cannot use the datacs line */ | ||
887 | version = viper_hw_version(); | ||
888 | if (version == 0) | ||
889 | smc91x_device.num_resources--; | ||
890 | |||
891 | pxa_set_i2c_info(NULL); | ||
892 | platform_add_devices(viper_devs, ARRAY_SIZE(viper_devs)); | ||
893 | |||
894 | viper_init_vcore_gpios(); | ||
895 | viper_init_cpufreq(); | ||
896 | |||
897 | sysdev_driver_register(&cpu_sysdev_class, &viper_cpu_sysdev_driver); | ||
898 | |||
899 | if (version) { | ||
900 | pr_info("viper: hardware v%di%d detected. " | ||
901 | "CPLD revision %d.\n", | ||
902 | VIPER_BOARD_VERSION(version), | ||
903 | VIPER_BOARD_ISSUE(version), | ||
904 | VIPER_CPLD_REVISION(version)); | ||
905 | system_rev = (VIPER_BOARD_VERSION(version) << 8) | | ||
906 | (VIPER_BOARD_ISSUE(version) << 4) | | ||
907 | VIPER_CPLD_REVISION(version); | ||
908 | } else { | ||
909 | pr_info("viper: No version register.\n"); | ||
910 | } | ||
911 | |||
912 | i2c_register_board_info(1, ARRAY_AND_SIZE(viper_i2c_devices)); | ||
913 | |||
914 | viper_tpm_init(); | ||
915 | pxa_set_ac97_info(NULL); | ||
916 | } | ||
917 | |||
918 | static struct map_desc viper_io_desc[] __initdata = { | ||
919 | { | ||
920 | .virtual = VIPER_CPLD_BASE, | ||
921 | .pfn = __phys_to_pfn(VIPER_CPLD_PHYS), | ||
922 | .length = 0x00300000, | ||
923 | .type = MT_DEVICE, | ||
924 | }, | ||
925 | { | ||
926 | .virtual = VIPER_PC104IO_BASE, | ||
927 | .pfn = __phys_to_pfn(_PCMCIA1IO), | ||
928 | .length = 0x00800000, | ||
929 | .type = MT_DEVICE, | ||
930 | }, | ||
931 | }; | ||
932 | |||
933 | static void __init viper_map_io(void) | ||
934 | { | ||
935 | pxa_map_io(); | ||
936 | |||
937 | iotable_init(viper_io_desc, ARRAY_SIZE(viper_io_desc)); | ||
938 | |||
939 | PCFR |= PCFR_OPDE; | ||
940 | } | ||
941 | |||
942 | MACHINE_START(VIPER, "Arcom/Eurotech VIPER SBC") | ||
943 | /* Maintainer: Marc Zyngier <maz@misterjones.org> */ | ||
944 | .phys_io = 0x40000000, | ||
945 | .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, | ||
946 | .boot_params = 0xa0000100, | ||
947 | .map_io = viper_map_io, | ||
948 | .init_irq = viper_init_irq, | ||
949 | .timer = &pxa_timer, | ||
950 | .init_machine = viper_init, | ||
951 | MACHINE_END | ||