hh.org updates
[hh.org.git] / arch / arm / mach-pxa / h5400 / h5400.c
blob9703b9ad861367bb54c6a1d160958c2627d634f1
1 /*
2 * Hardware definitions for HP iPAQ Handheld Computers
4 * Copyright 2000-2003 Hewlett-Packard Company.
5 * Copyright 2004, 2005 Phil Blundell
7 * Use consistent with the GNU GPL is permitted,
8 * provided that this copyright notice is
9 * preserved in its entirety in all copies and derived works.
11 * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
12 * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
13 * FITNESS FOR ANY PARTICULAR PURPOSE.
15 * Author: Jamey Hicks.
17 * History:
19 * 2002-08-23 Jamey Hicks GPIO and IRQ support for iPAQ H5400
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/kernel.h>
26 #include <linux/tty.h>
27 #include <linux/sched.h>
28 #include <linux/interrupt.h>
29 #include <linux/pm.h>
30 #include <linux/bootmem.h>
31 #include <linux/delay.h>
32 #include <linux/platform_device.h>
33 #include <linux/fb.h>
34 #include <../drivers/video/pxafb.h>
35 #include <linux/input.h>
36 #include <linux/input_pda.h>
38 #include <asm/irq.h>
39 #include <asm/mach-types.h>
40 #include <asm/hardware.h>
41 #include <asm/setup.h>
43 #include <asm/mach/irq.h>
44 #include <asm/mach/arch.h>
45 #include <asm/mach/map.h>
46 #include <asm/arch/h5400-gpio.h>
47 #include <asm/arch/h5400-asic.h>
48 #include <asm/arch/h5400-init.h>
49 #include <asm/arch/ipaq.h>
50 #include <asm/arch/udc.h>
52 #include <asm/arch/pxa-regs.h>
53 #include <asm/arch/serial.h>
54 #include <asm/hardware/gpio_keys.h>
55 #include <asm/arch/pxa-dmabounce.h>
56 #include <asm/arch/irq.h>
57 #include <asm/types.h>
58 #include <asm/hardware/samcop_base.h>
60 #include "../generic.h"
62 /***********************************************************************************/
63 /* EGPIO, etc */
64 /***********************************************************************************/
66 #ifdef DeadCode
68 static void h5400_control_egpio( enum ipaq_egpio_type x, int setp )
70 switch (x) {
72 case IPAQ_EGPIO_RS232_ON:
73 SET_H5400_GPIO (POWER_RS232_N, !setp);
74 break;
76 default:
77 printk("%s: unhandled ipaq gpio=%d\n", __FUNCTION__, x);
81 static void h5400_set_led (enum led_color color, int duty_time, int cycle_time)
83 static const u8 h5400_lednum[5] = { 4, 0, 1, 2, 3 };
84 static unsigned long led_state;
85 int lednum, ledvalue;
86 unsigned long flags;
88 lednum = h5400_lednum[color];
89 ledvalue = duty_time ? 0x3 | (duty_time << 4) | (cycle_time << 12) : 0;
91 local_irq_save (flags);
93 /* Clock needs to be left enabled if any LEDs are flashing */
94 if (duty_time && (duty_time < cycle_time))
95 led_state |= 1 << lednum;
96 else
97 led_state &= ~1 << lednum;
99 H5400_ASIC_CPM_ClockControl |= H5400_ASIC_CPM_CLKCON_LED_CLKEN;
101 H5400_ASIC_LED_CONTROL(lednum) = ledvalue;
103 if (led_state == 0)
104 H5400_ASIC_CPM_ClockControl &= ~H5400_ASIC_CPM_CLKCON_LED_CLKEN;
106 local_irq_restore (flags);
109 #endif
111 /****************************************************************************
112 * Bluetooth functions and data structures
113 ****************************************************************************/
115 /* We need a little magic function switching here to keep samcop_base as
116 * a kernel module
119 void (*h5400_set_samcop_gpio_b) (struct device *dev, u32 mask, u32 bits);
120 EXPORT_SYMBOL(h5400_set_samcop_gpio_b);
122 void
123 h5400_set_gpio_b (struct device *dev, u32 mask, u32 bits)
125 if (h5400_set_samcop_gpio_b)
126 h5400_set_samcop_gpio_b(dev, mask, bits);
129 static void h5400_bluetooth_power(int on)
131 if (on) {
132 /* apply reset. The chip requires that the reset pins go
133 * high 2ms after voltage is applied to VCC and IOVCC. So it
134 * is driven low now before we set the power pins. It
135 * is assumed that the reset pins are tied together
136 * on the h5[1,4,5]xx handhelds. */
137 SET_H5400_GPIO(BT_M_RESET, !on);
139 /* Select the 'operating environment' pins to run/normal mode.
140 * Setting these pins to ENV_0 = 0 and ENV_1 = 1 would put the
141 * In-System-Programming (ISP) mode. In theory that would
142 * allow the host computer to rewrite the firmware.
144 SET_H5400_GPIO(BT_ENV_0, on);
145 SET_H5400_GPIO(BT_ENV_1, on);
146 /* configure power pins */
147 h5400_set_gpio_b(&h5400_samcop.dev,
148 SAMCOP_GPIO_GPB_BLUETOOTH_3V0_ON,
149 SAMCOP_GPIO_GPB_BLUETOOTH_3V0_ON);
150 SET_H5400_GPIO(BT_2V8_N, !on);
151 /* A 2ms delay between voltage application and reset driven
152 * high is a requirement of the power-on cycle of the device.
154 mdelay(2);
155 SET_H5400_GPIO(BT_M_RESET, on);
156 } else {
157 h5400_set_gpio_b(&h5400_samcop.dev,
158 SAMCOP_GPIO_GPB_BLUETOOTH_3V0_ON,
159 ~SAMCOP_GPIO_GPB_BLUETOOTH_3V0_ON);
160 SET_H5400_GPIO(BT_2V8_N, !on);
164 static void h5400_btuart_configure(int state)
166 switch (state) {
167 case PXA_UART_CFG_PRE_STARTUP:
168 pxa_gpio_mode(GPIO42_BTRXD_MD);
169 pxa_gpio_mode(GPIO43_BTTXD_MD);
170 pxa_gpio_mode(GPIO44_BTCTS_MD);
171 pxa_gpio_mode(GPIO45_BTRTS_MD);
172 h5400_bluetooth_power(1);
173 break;
175 case PXA_UART_CFG_PRE_SHUTDOWN:
176 h5400_bluetooth_power(0);
177 break;
179 default:
180 break;
184 static void h5400_hwuart_configure(int state)
186 switch (state) {
187 case PXA_UART_CFG_PRE_STARTUP:
188 pxa_gpio_mode(GPIO42_HWRXD_MD);
189 pxa_gpio_mode(GPIO43_HWTXD_MD);
190 pxa_gpio_mode(GPIO44_HWCTS_MD);
191 pxa_gpio_mode(GPIO45_HWRTS_MD);
192 h5400_bluetooth_power(1);
193 break;
195 case PXA_UART_CFG_PRE_SHUTDOWN:
196 h5400_bluetooth_power(0);
197 break;
199 default:
200 break;
204 static struct platform_pxa_serial_funcs h5400_btuart_funcs = {
205 .configure = h5400_btuart_configure,
208 static struct platform_pxa_serial_funcs h5400_hwuart_funcs = {
209 .configure = h5400_hwuart_configure,
212 static __inline__ void
213 fix_msc (void)
215 /* fix CS0 for h5400 flash. */
216 /* fix CS1 for MediaQ chip. select 16-bit bus and vlio. */
217 /* fix CS5 for SAMCOP. */
218 MSC0 = 0x129c24f2;
219 (void)MSC0;
220 MSC1 = 0x7ff424fa;
221 (void)MSC1;
222 MSC2 = 0x7ff47ff4;
223 (void)MSC2;
225 MDREFR |= 0x02080000;
228 #if 0
229 static int h5400_pm_callback( int req )
231 int result = 0;
232 static int gpio_0, gpio_1, gpio_2; /* PXA GPIOs */
234 printk("%s: %d\n", __FUNCTION__, req);
236 switch (req) {
237 case PM_RESUME:
238 /* bootldr will have screwed up MSCs, so set them right again */
239 fix_msc ();
241 #if 0
242 H5400_ASIC_GPIO_GPA_DAT = gpio_a;
243 H5400_ASIC_GPIO_GPB_DAT = gpio_b;
244 #endif
246 GPSR0 = gpio_0;
247 GPCR0 = ~gpio_0;
248 GPSR1 = gpio_1;
249 GPCR1 = ~gpio_1;
250 GPSR2 = gpio_2;
251 GPCR2 = ~gpio_2;
253 #ifdef DeadCode
254 if ( ipaq_model_ops.pm_callback_aux )
255 result = ipaq_model_ops.pm_callback_aux(req);
256 #endif
257 break;
259 case PM_SUSPEND:
260 #ifdef DeadCode
261 if ( ipaq_model_ops.pm_callback_aux &&
262 ((result = ipaq_model_ops.pm_callback_aux(req)) != 0))
263 return result;
264 #endif
266 #if 0
267 gpio_a = H5400_ASIC_GPIO_GPA_DAT;
268 gpio_b = H5400_ASIC_GPIO_GPB_DAT;
269 #endif
271 gpio_0 = GPLR0;
272 gpio_1 = GPLR1;
273 gpio_2 = GPLR2;
274 break;
276 default:
277 printk("%s: unrecognized PM callback\n", __FUNCTION__);
278 break;
280 return result;
282 #endif
284 /***********************************************************************************/
285 /* Miscellaneous */
286 /***********************************************************************************/
290 /***********************************************************************************/
291 /* Initialisation */
292 /***********************************************************************************/
294 static short h5400_gpio_modes[] __initdata = {
295 GPIO_NR_H5400_POWER_BUTTON | GPIO_IN, /* GPIO0 */
296 GPIO_NR_H5400_RESET_BUTTON_N | GPIO_IN, /* GPIO1 */
297 GPIO_NR_H5400_OPT_INT | GPIO_IN, /* GPIO2 */
298 GPIO_NR_H5400_BACKUP_POWER | GPIO_IN, /* GPIO3 */ /* XXX should be an output? */
299 GPIO_NR_H5400_ACTION_BUTTON | GPIO_IN, /* GPIO4 */
300 GPIO_NR_H5400_COM_DCD_SOMETHING | GPIO_IN, /* GPIO5 */
301 6 | GPIO_IN, /* GPIO6 NC */
302 GPIO_NR_H5400_RESET_BUTTON_AGAIN_N | GPIO_IN, /* GPIO7 */
303 8 | GPIO_OUT, /* GPIO8 NC */
304 GPIO_NR_H5400_RSO_N | GPIO_IN, /* GPIO9 BATT_FAULT */
305 GPIO_NR_H5400_ASIC_INT_N | GPIO_IN, /* GPIO10 */
306 GPIO_NR_H5400_BT_ENV_0 | GPIO_OUT, /* GPIO11 */
307 GPIO12_32KHz_MD | GPIO_OUT, /* GPIO12 NC */
308 GPIO_NR_H5400_BT_ENV_1 | GPIO_OUT, /* GPIO13 */
309 GPIO_NR_H5400_BT_WU | GPIO_IN, /* GPIO14 */
310 GPIO15_nCS_1_MD, /* GPIO15 */
311 16 | GPIO_OUT, /* GPIO16 NC */
312 17 | GPIO_OUT, /* GPIO17 NC */
314 22 | GPIO_OUT, /* GPIO22 NC */
315 GPIO23_SCLK_MD,
316 GPIO_NR_H5400_OPT_SPI_CS_N | GPIO_OUT,
317 GPIO25_STXD_MD,
318 GPIO26_SRXD_MD,
319 27 | GPIO_OUT, /* GPIO27 NC */
321 GPIO34_FFRXD_MD,
322 GPIO35_FFCTS_MD,
323 GPIO36_FFDCD_MD,
324 GPIO37_FFDSR_MD,
325 GPIO38_FFRI_MD,
326 GPIO39_FFTXD_MD,
327 GPIO40_FFDTR_MD,
328 GPIO41_FFRTS_MD,
329 GPIO42_BTRXD_MD,
330 GPIO43_BTTXD_MD,
331 GPIO44_BTCTS_MD,
332 GPIO45_BTRTS_MD,
334 GPIO_NR_H5400_IRDA_SD | GPIO_OUT, /* GPIO58 */
335 59 | GPIO_OUT, /* GPIO59 XXX docs say "usb charge on" input */
336 GPIO_NR_H5400_POWER_SD_N | GPIO_OUT, /* GPIO60 XXX not really active low? */
337 GPIO_NR_H5400_POWER_RS232_N | GPIO_OUT | GPIO_DFLT_HIGH,
338 GPIO_NR_H5400_POWER_ACCEL_N | GPIO_OUT | GPIO_DFLT_HIGH,
339 63 | GPIO_OUT, /* GPIO63 NC */
340 GPIO_NR_H5400_OPT_NVRAM | GPIO_OUT ,
341 GPIO_NR_H5400_CHG_EN | GPIO_OUT ,
342 GPIO_NR_H5400_USB_PULLUP | GPIO_OUT ,
343 GPIO_NR_H5400_BT_2V8_N | GPIO_OUT | GPIO_DFLT_HIGH,
344 GPIO_NR_H5400_EXT_CHG_RATE | GPIO_OUT ,
345 69 | GPIO_OUT, /* GPIO69 NC */
346 GPIO_NR_H5400_CIR_RESET | GPIO_OUT ,
347 GPIO_NR_H5400_POWER_LIGHT_SENSOR_N | GPIO_OUT | GPIO_DFLT_HIGH,
348 GPIO_NR_H5400_BT_M_RESET | GPIO_OUT ,
349 GPIO_NR_H5400_STD_CHG_RATE | GPIO_OUT ,
350 GPIO_NR_H5400_SD_WP_N | GPIO_IN, /* GPIO74 XXX docs say output */
351 GPIO_NR_H5400_MOTOR_ON_N | GPIO_OUT | GPIO_DFLT_HIGH,
352 GPIO_NR_H5400_HEADPHONE_DETECT | GPIO_IN ,
353 GPIO_NR_H5400_USB_CHG_RATE | GPIO_OUT ,
354 GPIO78_nCS_2_MD,
355 GPIO79_nCS_3_MD,
356 GPIO80_nCS_4_MD
359 static void __init h5400_map_io(void)
361 int i;
362 int cpuid;
364 pxa_map_io ();
366 /* Configure power management stuff. */
367 PWER = PWER_GPIO0 | PWER_RTC;
368 PFER = PWER_GPIO0 | PWER_RTC;
369 PRER = 0;
370 PCFR = PCFR_OPDE;
371 CKEN = CKEN6_FFUART;
373 #if 0
374 h5400_asic_write_register (H5400_ASIC_CPM_ClockControl, H5400_ASIC_CPM_CLKCON_LED_CLKEN);
375 h5400_asic_write_register (H5400_ASIC_LED_LEDPS, 0xf42400); /* 4Hz */
377 H5400_ASIC_SET_BIT (H5400_ASIC_CPM_ClockControl, H5400_ASIC_CPM_CLKCON_GPIO_CLKEN);
378 H5400_ASIC_SET_BIT (H5400_ASIC_GPIO_GPA_CON2, 0x16);
379 #endif
381 for (i = 0; i < ARRAY_SIZE(h5400_gpio_modes); i++) {
382 int mode = h5400_gpio_modes[i];
383 pxa_gpio_mode(mode);
386 #if 0
387 /* Does not currently work */
388 /* Add wakeup on AC plug/unplug */
389 PWER |= PWER_GPIO12;
390 #endif
392 fix_msc ();
394 /* Set sleep states for PXA GPIOs */
395 PGSR0 = GPSRx_SleepValue;
396 PGSR1 = GPSRy_SleepValue;
397 PGSR2 = GPSRz_SleepValue;
399 /* hook up btuart & hwuart and power bluetooth */
400 /* The h54xx has pxa-250, so it gets btuart */
401 /* and h51xx and h55xx have pxa-255, so they get hwuart */
402 cpuid = read_cpuid(CPUID_ID);
403 if (((cpuid >> 4) & 0xfff) == 0x2d0) {
404 hwuart_device.dev.platform_data = &h5400_hwuart_funcs;
405 } else {
406 btuart_device.dev.platform_data = &h5400_btuart_funcs;
410 /* ------------------- */
412 static int
413 h5400_udc_is_connected (void)
415 return 1;
418 static void
419 h5400_udc_command (int cmd)
421 switch (cmd)
423 case PXA2XX_UDC_CMD_DISCONNECT:
424 GPCR(GPIO_NR_H5400_USB_PULLUP) |= GPIO_bit(GPIO_NR_H5400_USB_PULLUP);
425 GPDR(GPIO_NR_H5400_USB_PULLUP) &= ~GPIO_bit(GPIO_NR_H5400_USB_PULLUP);
426 break;
427 case PXA2XX_UDC_CMD_CONNECT:
428 GPDR(GPIO_NR_H5400_USB_PULLUP) |= GPIO_bit(GPIO_NR_H5400_USB_PULLUP);
429 GPSR(GPIO_NR_H5400_USB_PULLUP) |= GPIO_bit(GPIO_NR_H5400_USB_PULLUP);
430 break;
431 default:
432 printk("_udc_control: unknown command!\n");
433 break;
437 static struct pxa2xx_udc_mach_info h5400_udc_mach_info = {
438 .udc_is_connected = h5400_udc_is_connected,
439 .udc_command = h5400_udc_command,
442 /* ------------------- */
444 static struct resource samcop_resources[] = {
445 [0] = {
446 .start = H5400_SAMCOP_BASE,
447 .end = H5400_SAMCOP_BASE + 0x00ffffff,
448 .flags = IORESOURCE_MEM,
450 [1] = {
451 .start = IRQ_GPIO_H5400_ASIC_INT,
452 .flags = IORESOURCE_IRQ,
456 static struct samcop_platform_data samcop_platform_data = {
457 .clocksleep = SAMCOP_CPM_CLKSLEEP_UCLK_ON,
458 .pllcontrol = 0x60002, /* value from wince via bootblaster */
461 struct platform_device h5400_samcop = {
462 .name = "samcop",
463 .id = 0,
464 .num_resources = ARRAY_SIZE(samcop_resources),
465 .resource = samcop_resources,
466 .dev = {
467 .platform_data = &samcop_platform_data,
470 EXPORT_SYMBOL(h5400_samcop);
472 static struct gpio_keys_button h5400_button_table[] = {
473 { _KEY_POWER, GPIO_NR_H5400_POWER_BUTTON, 1 },
476 static struct gpio_keys_platform_data h5400_pxa_keys_data = {
477 .buttons = h5400_button_table,
478 .nbuttons = ARRAY_SIZE(h5400_button_table),
481 static struct platform_device h5400_pxa_keys = {
482 .name = "gpio-keys",
483 .dev = {
484 .platform_data = &h5400_pxa_keys_data,
488 static void __init
489 h5400_init (void)
491 platform_device_register (&h5400_samcop);
492 platform_device_register (&h5400_pxa_keys);
493 pxa_set_udc_info (&h5400_udc_mach_info);
496 MACHINE_START(H5400, "HP iPAQ H5400")
497 .phys_io = 0x40000000,
498 .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
499 .boot_params = 0xa0000100,
500 .map_io = h5400_map_io,
501 .init_irq = pxa_init_irq,
502 .timer = &pxa_timer,
503 .init_machine = h5400_init,
504 MACHINE_END