---
 arch/arm/Kconfig                                         |    2 
 arch/arm/mach-pxa/Kconfig                                |   89 +
 arch/arm/mach-pxa/Makefile                               |    1 
 arch/arm/mach-pxa/generic.c                              |   13 
 arch/arm/mach-pxa/htcuniversal/Makefile                  |   19 
 arch/arm/mach-pxa/htcuniversal/htcuniversal.c            |  468 +++++
 arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.c     |  917 +++++++++++
 arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.h     |   65 
 arch/arm/mach-pxa/htcuniversal/htcuniversal_asic3_leds.c |  143 +
 arch/arm/mach-pxa/htcuniversal/htcuniversal_bl.c         |   61 
 arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.c         |  135 +
 arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.h         |   17 
 arch/arm/mach-pxa/htcuniversal/htcuniversal_buttons.c    |   87 +
 arch/arm/mach-pxa/htcuniversal/htcuniversal_core.c       |  226 ++
 arch/arm/mach-pxa/htcuniversal/htcuniversal_lcd.c        |  212 ++
 arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.c      |  167 ++
 arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.h      |   16 
 arch/arm/mach-pxa/htcuniversal/htcuniversal_pm.c         |   69 
 arch/arm/mach-pxa/htcuniversal/htcuniversal_power2.c     |   97 +
 arch/arm/mach-pxa/htcuniversal/htcuniversal_ts2.c        |  490 ++++++
 arch/arm/mach-pxa/htcuniversal/htcuniversal_udc.c        |   71 
 arch/arm/mach-pxa/htcuniversal/tsc2046_ts.h              |   20 
 drivers/input/keyboard/Kconfig                           |    7 
 drivers/input/keyboard/Makefile                          |    1 
 drivers/input/keyboard/asic3_keys.c                      |  131 +
 drivers/leds/Kconfig                                     |    7 
 drivers/leds/Makefile                                    |    1 
 drivers/leds/leds-asic3.c                                |  189 ++
 drivers/mfd/Kconfig                                      |   10 
 drivers/mfd/Makefile                                     |    2 
 drivers/mfd/asic3_base.c                                 | 1208 +++++++++++++++
 drivers/mfd/soc-core.c                                   |  106 +
 drivers/mfd/soc-core.h                                   |   30 
 drivers/mmc/host/Kconfig                                 |    6 
 drivers/mmc/host/Makefile                                |    1 
 drivers/mmc/host/asic3_mmc.c                             |  900 +++++++++++
 drivers/mmc/host/asic3_mmc.h                             |   25 
 drivers/serial/pxa.c                                     |   22 
 include/asm-arm/arch-pxa/clock.h                         |   27 
 include/asm-arm/arch-pxa/htcuniversal-asic.h             |  213 ++
 include/asm-arm/arch-pxa/htcuniversal-gpio.h             |  220 ++
 include/asm-arm/arch-pxa/htcuniversal-init.h             |   14 
 include/asm-arm/arch-pxa/htcuniversal.h                  |    3 
 include/asm-arm/arch-pxa/irqs.h                          |    2 
 include/asm-arm/arch-pxa/pxa-pm_ll.h                     |    6 
 include/asm-arm/arch-pxa/pxa-regs.h                      |    2 
 include/asm-arm/arch-pxa/serial.h                        |   78 
 include/asm-arm/hardware/asic3_keys.h                    |   18 
 include/asm-arm/hardware/asic3_leds.h                    |   34 
 include/asm-arm/hardware/ipaq-asic3.h                    |  602 +++++++
 include/linux/backlight.h                                |    7 
 include/linux/gpiodev.h                                  |   44 
 include/linux/input_pda.h                                |   47 
 include/linux/ioport.h                                   |    1 
 include/linux/soc/asic3_base.h                           |  104 +
 include/linux/soc/tmio_mmc.h                             |   17 
 56 files changed, 7469 insertions(+), 1 deletion(-)

Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/Makefile	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,19 @@
+#
+# Makefile for HTC Universal
+#
+
+snd-htcuniversal-ak4641-objs := htcuniversal_ak4641.o
+
+obj-$(CONFIG_MACH_HTCUNIVERSAL)		+= htcuniversal.o
+obj-$(CONFIG_HTCUNIVERSAL_CORE)		+= htcuniversal_core.o
+obj-$(CONFIG_HTCUNIVERSAL_POWER)	+= htcuniversal_power2.o
+obj-$(CONFIG_HTCUNIVERSAL_LCD)		+= htcuniversal_lcd.o
+obj-$(CONFIG_HTCUNIVERSAL_BACKLIGHT)	+= htcuniversal_bl.o
+obj-$(CONFIG_HTCUNIVERSAL_TS2)		+= htcuniversal_ts2.o
+obj-$(CONFIG_HTCUNIVERSAL_BUTTONS) 	+= htcuniversal_buttons.o
+obj-$(CONFIG_HTCUNIVERSAL_BLUETOOTH)	+= htcuniversal_bt.o
+obj-$(CONFIG_HTCUNIVERSAL_PHONE)	+= htcuniversal_phone.o
+obj-$(CONFIG_HTCUNIVERSAL_ASIC3_LEDS)	+= htcuniversal_asic3_leds.o
+obj-$(CONFIG_HTCUNIVERSAL_UDC)		+= htcuniversal_udc.o
+
+obj-$(CONFIG_HTCUNIVERSAL_AK4641)	+= htcuniversal_ak4641.o
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,468 @@
+/*
+ * Hardware definitions for HTC Universal
+ *
+ * Copyright (c) 2006 Oleg Gusev
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/soc/asic3_base.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/setup.h>
+
+#include <asm/mach/irq.h>
+#include <asm/mach/arch.h>
+
+#include <asm/arch/bitfield.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/serial.h>
+#include <asm/arch/pxa27x_keyboard.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/irda.h>
+#include <asm/arch/ohci.h>
+
+#include <asm/arch/htcuniversal.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-init.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+#include <asm/hardware/ipaq-asic3.h>
+
+#include "../generic.h"
+
+#include "htcuniversal_bt.h"
+#include "htcuniversal_phone.h"
+#include "tsc2046_ts.h"
+
+/*
+ * IRDA
+ */
+
+static void htcuniversal_irda_transceiver_mode(struct device *dev, int mode)
+{
+ /* */
+}
+
+static struct pxaficp_platform_data htcuniversal_ficp_platform_data = {
+	.transceiver_cap  = IR_SIRMODE | IR_FIRMODE,
+	.transceiver_mode = htcuniversal_irda_transceiver_mode,
+};
+
+/*
+ * Bluetooth - Relies on other loadable modules, like ASIC3 and Core,
+ * so make the calls indirectly through pointers. Requires that the
+ * htcuniversal_bt module be loaded before any attempt to use
+ * bluetooth (obviously).
+ */
+
+static struct htcuniversal_bt_funcs bt_funcs;
+
+static void
+htcuniversal_bt_configure( int state )
+{
+	if (bt_funcs.configure != NULL)
+		bt_funcs.configure( state );
+}
+
+static struct htcuniversal_phone_funcs phone_funcs;
+
+static void
+htcuniversal_phone_configure( int state )
+{
+	if (phone_funcs.configure != NULL)
+		phone_funcs.configure( state );
+}
+
+//void htcuniversal_ll_pm_init(void);
+
+extern struct platform_device htcuniversal_bl;
+static struct platform_device htcuniversal_lcd       = { .name = "htcuniversal_lcd", };
+//static struct platform_device htcuniversal_kbd       = { .name = "htcuniversal_kbd", };
+static struct platform_device htcuniversal_buttons   = { .name = "htcuniversal_buttons", };
+//static struct platform_device htcuniversal_ts        = { .name = "htcuniversal_ts", };
+//static struct platform_device htcuniversal_bt        = { .name = "htcuniversal_bt", };
+//static struct platform_device htcuniversal_phone        = { .name = "htcuniversal_phone", };
+static struct platform_device htcuniversal_power        = { .name = "htcuniversal_power", };
+static struct platform_device htcuniversal_udc       = { .name = "htcuniversal_udc", };
+
+static struct tsc2046_mach_info htcuniversal_ts_platform_data = {
+       .port     = 1,
+       .clock    = CKEN_SSP1,
+       .pwrbit_X = 1,
+       .pwrbit_Y = 1,
+       .irq	 = 0  /* asic3 irq */
+};
+
+static struct platform_device htcuniversal_ts        = {
+       .name = "htcuniversal_ts",
+       .dev  = {
+              .platform_data = &htcuniversal_ts_platform_data,
+       },
+};
+
+
+/* Bluetooth */
+
+static struct platform_device htcuniversal_bt = {
+	.name = "htcuniversal_bt",
+	.id = -1,
+	.dev = {
+		.platform_data = &bt_funcs,
+	},
+};
+
+static struct platform_device htcuniversal_phone = {
+	.name = "htcuniversal_phone",
+	.id = -1,
+	.dev = {
+		.platform_data = &phone_funcs,
+	},
+};
+
+/* PXA2xx Keys */
+
+static struct gpio_keys_button htcuniversal_button_table[] = {
+	{ KEY_POWER, GPIO_NR_HTCUNIVERSAL_KEY_ON_N, 1 },
+};
+
+static struct gpio_keys_platform_data htcuniversal_pxa_keys_data = {
+	.buttons = htcuniversal_button_table,
+	.nbuttons = ARRAY_SIZE(htcuniversal_button_table),
+};
+
+static struct platform_device htcuniversal_pxa_keys = {
+	.name = "gpio-keys",
+	.dev = {
+		.platform_data = &htcuniversal_pxa_keys_data,
+	},
+	.id = -1,
+};
+
+/****************************************************************
+ * Keyboard
+ ****************************************************************/
+
+static struct pxa27x_keyboard_platform_data htcuniversal_kbd = {
+	.nr_rows = 8,
+	.nr_cols = 8,
+	.keycodes = {
+		{
+			/* row 0 */
+			KEY_ENTER,
+			KEY_MINUS,
+			KEY_ESC,
+			KEY_1,
+			KEY_TAB,
+			KEY_CAPSLOCK,
+			KEY_LEFTSHIFT,
+			KEY_RIGHTALT,	/* Fn */
+		}, {	/* row 1 */
+			KEY_COMMA,
+			KEY_EQUAL,
+			KEY_F1,
+			KEY_2,
+			KEY_Q,
+			KEY_A,
+			KEY_Z,
+			KEY_LEFTCTRL,
+		}, {	/* row 2 */
+			KEY_UP,
+			KEY_I,
+			KEY_F2,
+			KEY_3,
+			KEY_W,
+			KEY_S,
+			KEY_X,
+			KEY_F6,
+		}, {	/* row 3 */
+			KEY_DOT,
+			KEY_O,
+			KEY_F3,
+			KEY_4,
+			KEY_E,
+			KEY_D,
+			KEY_C,
+			KEY_LEFTALT,
+		}, {	/* row 4 */
+			KEY_F9,
+			KEY_P,
+			KEY_F4,
+			KEY_5,
+			KEY_R,
+			KEY_F,
+			KEY_V,
+			KEY_SPACE,
+		}, {	/* row 5 */
+			KEY_RIGHT,
+			KEY_BACKSPACE,
+			KEY_F5,
+			KEY_6,
+			KEY_T,
+			KEY_G,
+			KEY_B,
+			KEY_F7,
+		}, {	/* row 6 */
+			KEY_F9,
+			KEY_K,
+			KEY_9,
+			KEY_7,
+			KEY_Y,
+			KEY_H,
+			KEY_N,
+			KEY_LEFT,
+		}, {	/* row 7 */
+			KEY_F10,
+			KEY_L,
+			KEY_0,
+			KEY_8,
+			KEY_U,
+			KEY_J,
+			KEY_M,
+			KEY_DOWN,
+		},
+	},
+	.gpio_modes = {
+		 GPIO_NR_HTCUNIVERSAL_KP_MKIN0_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKIN1_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKIN2_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKIN3_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKIN4_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKIN5_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKIN6_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKIN7_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKOUT0_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKOUT1_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKOUT2_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKOUT3_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKOUT4_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKOUT5_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKOUT6_MD,
+		 GPIO_NR_HTCUNIVERSAL_KP_MKOUT7_MD,
+	 },
+};
+
+static struct platform_device htcuniversal_pxa_keyboard = {
+        .name   = "pxa27x-keyboard",
+        .id     = -1,
+	.dev	=  {
+		.platform_data	= &htcuniversal_kbd,
+	},
+};
+/* Core Hardware Functions */
+
+struct platform_device htcuniversal_core = {
+	.name		= "htcuniversal_core",
+	.id		= 0,
+	.dev = {
+		.platform_data = NULL,
+	},
+};
+
+static struct platform_device *devices[] __initdata = {
+	&htcuniversal_core,
+//	&htcuniversal_flash,
+	&htcuniversal_pxa_keyboard,
+	&htcuniversal_pxa_keys,
+};
+
+static struct platform_device *htcuniversal_asic3_devices[] __initdata = {
+	&htcuniversal_lcd,
+#ifdef CONFIG_HTCUNIVERSAL_BACKLIGHT
+	&htcuniversal_bl,
+#endif
+	&htcuniversal_buttons,
+	&htcuniversal_ts,
+	&htcuniversal_bt,
+	&htcuniversal_phone,
+	&htcuniversal_power,
+	&htcuniversal_udc,
+};
+
+static struct asic3_platform_data htcuniversal_asic3_platform_data = {
+
+   /* Setting ASIC3 GPIO registers to the below initialization states
+    * HTC Universal asic3 information:
+    * http://wiki.xda-developers.com/index.php?pagename=UniversalASIC3
+    * http://wiki.xda-developers.com/index.php?pagename=ASIC3
+    *
+    * dir:	Direction of the GPIO pin. 0: input, 1: output.
+    *      	If unknown, set as output to avoid power consuming floating input nodes
+    * init:	Initial state of the GPIO bits
+    *
+    * These registers are configured as they are on Wince.
+    */
+        .gpio_a = {
+		.dir            = (1<<GPIOA_LCD_PWR5_ON)    |
+				  (1<<GPIOA_FLASHLIGHT)     |
+				  (1<<GPIOA_UNKNOWN9)       |
+				  (1<<GPIOA_SPK_PWR2_ON)    |
+				  (1<<GPIOA_UNKNOWN4)       |
+				  (1<<GPIOA_EARPHONE_PWR_ON)|
+				  (1<<GPIOA_AUDIO_PWR_ON)   |
+				  (1<<GPIOA_SPK_PWR1_ON)    |
+				  (1<<GPIOA_I2C_EN),
+		.init           = (1<<GPIOA_LCD_PWR5_ON)    |
+				  (1<<GPIOA_I2C_EN),
+		.sleep_out      = 0x0000,
+		.batt_fault_out = 0x0000,
+		.alt_function   = 0x0000,
+		.sleep_conf     = 0x000c,
+        },
+        .gpio_b = {
+		.dir            = 0xc142,
+		.init           = 0x8842, // TODO: 0x0900
+		.sleep_out      = 0x0000,
+		.batt_fault_out = 0x0000,
+		.alt_function   = 0x0000,
+                .sleep_conf     = 0x000c,
+        },
+        .gpio_c = {
+                .dir            = 0xc7e7,
+                .init           = 0xc6e0, // TODO: 0x8000
+                .sleep_out      = 0x0000,
+                .batt_fault_out = 0x0000,
+		.alt_function   = 0x0007, // GPIOC_LED_RED | GPIOC_LED_GREEN | GPIOC_LED_BLUE
+                .sleep_conf     = 0x000c,
+        },
+        .gpio_d = {
+		.dir            = 0xffc0,
+		.init           = 0x7840, // TODO: 0x0000
+		.sleep_out      = 0x0000,
+		.batt_fault_out = 0x0000,
+		.alt_function   = 0x0000,
+		.sleep_conf     = 0x0008,
+        },
+	.bus_shift = 1,
+	.irq_base = HTCUNIVERSAL_ASIC3_IRQ_BASE,
+
+	.child_platform_devs     = htcuniversal_asic3_devices,
+	.num_child_platform_devs = ARRAY_SIZE(htcuniversal_asic3_devices),
+};
+
+static struct resource htcuniversal_asic3_resources[] = {
+	[0] = {
+		.start	= HTCUNIVERSAL_ASIC3_GPIO_PHYS,
+		.end	= HTCUNIVERSAL_ASIC3_GPIO_PHYS + IPAQ_ASIC3_MAP_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= HTCUNIVERSAL_IRQ(ASIC3_EXT_INT),
+		.end	= HTCUNIVERSAL_IRQ(ASIC3_EXT_INT),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start  = HTCUNIVERSAL_ASIC3_MMC_PHYS,
+		.end    = HTCUNIVERSAL_ASIC3_MMC_PHYS + IPAQ_ASIC3_MAP_SIZE,
+		.flags  = IORESOURCE_MEM,
+	},
+	[3] = {
+		.start  = HTCUNIVERSAL_IRQ(ASIC3_SDIO_INT_N),
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device htcuniversal_asic3 = {
+	.name           = "asic3",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(htcuniversal_asic3_resources),
+	.resource       = htcuniversal_asic3_resources,
+	.dev = { .platform_data = &htcuniversal_asic3_platform_data, },
+};
+EXPORT_SYMBOL(htcuniversal_asic3);
+
+static struct pxafb_mode_info htcuniversal_lcd_modes[] = {
+{
+	.pixclock		= 96153,
+	.xres			= 480,
+	.yres			= 640,
+	.bpp			= 16,
+	.hsync_len		= 4,
+	.vsync_len		= 1,
+	.left_margin		= 20,
+	.right_margin		= 8,
+	.upper_margin		= 7,
+	.lower_margin		= 8,
+
+//	.sync			= FB_SYNC_HOR_LOW_ACT|FB_SYNC_VERT_LOW_ACT,
+
+},
+};
+
+static struct pxafb_mach_info sony_acx526akm = {
+        .modes		= htcuniversal_lcd_modes,
+        .num_modes	= ARRAY_SIZE(htcuniversal_lcd_modes),
+
+	/* fixme: use constants defined in pxafb.h */
+	.lccr0			= 0x00000080,
+	.lccr3			= 0x00400000,
+//	.lccr4			= 0x80000000,
+};
+
+static void __init htcuniversal_init_irq(void)
+{
+	pxa27x_init_irq();
+}
+
+static struct platform_pxa_serial_funcs htcuniversal_pxa_bt_funcs = {
+	.configure = htcuniversal_bt_configure,
+};
+static struct platform_pxa_serial_funcs htcuniversal_pxa_phone_funcs = {
+	.configure = htcuniversal_phone_configure,
+};
+
+/* USB OHCI */
+
+static int htcuniversal_ohci_init(struct device *dev)
+{
+	/* missing GPIO setup here */
+
+	/* got the value from wince */
+	UHCHR=UHCHR_CGR;
+
+	return 0;
+}
+
+static struct pxaohci_platform_data htcuniversal_ohci_platform_data = {
+	.port_mode = PMM_PERPORT_MODE,
+	.init = htcuniversal_ohci_init,
+};
+
+static void __init htcuniversal_map_io(void)
+{
+	pxa_map_io();
+
+	pxa_set_btuart_info(&htcuniversal_pxa_bt_funcs);
+	pxa_set_ffuart_info(&htcuniversal_pxa_phone_funcs);
+}
+
+static void __init htcuniversal_init(void)
+{
+	set_pxa_fb_info(&sony_acx526akm);
+
+	platform_device_register(&htcuniversal_asic3);
+	platform_add_devices(devices, ARRAY_SIZE(devices) );
+	pxa_set_ficp_info(&htcuniversal_ficp_platform_data);
+	pxa_set_ohci_info(&htcuniversal_ohci_platform_data);
+}
+
+MACHINE_START(HTCUNIVERSAL, "HTC Universal")
+	/* Maintainer xanadux.org */
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params	= 0xa0000100,
+	.map_io		= htcuniversal_map_io,
+	.init_irq	= htcuniversal_init_irq,
+	.init_machine	= htcuniversal_init,
+	.timer		= &pxa_timer,
+MACHINE_END
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,917 @@
+/*
+ * Audio support for codec Asahi Kasei AK4641
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (c) 2006 Giorgio Padrin <giorgio@mandarinlogiq.org>
+ *
+ * History:
+ *
+ * 2006-03	Written -- Giorgio Padrin
+ * 2006-09	Test and debug on machine (HP hx4700) -- Elshin Roman <roxmail@list.ru>
+ *
+ * AK4641 codec device driver
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * Based on code:
+ *   Copyright (c) 2002 Hewlett-Packard Company
+ *   Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
+ *   Copyright (c) 2000 Lernout & Hauspie Speech Products, N.V.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License.
+ */
+
+#include <sound/driver.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/info.h>
+
+#include "htcuniversal_ak4641.h"
+
+/* Registers */
+#define R_PM1		0x00
+#define R_PM2		0x01
+#define R_SEL1		0x02
+#define R_SEL2		0x03
+#define	R_MODE1		0x04
+#define R_MODE2		0x05
+#define R_DAC		0x06
+#define R_MIC		0x07
+#define REG_TIMER	0x08
+#define REG_ALC1	0x09
+#define REG_ALC2	0x0a
+#define R_PGA		0x0b
+#define R_ATTL		0x0c
+#define R_ATTR		0x0d
+#define REG_VOL		0x0e
+#define R_STATUS	0x0f
+#define REG_EQLO	0x10
+#define REG_EQMID	0x11
+#define REG_EQHI	0x12
+#define REG_BTIF	0x13
+
+/* Register flags */
+/* REG_PWR1 */
+#define R_PM1_PMADC	0x01
+#define R_PM1_PMMIC	0x02
+#define REG_PWR1_PMAUX  0x04
+#define REG_PWR1_PMMO   0x08
+#define R_PM1_PMLO	0x10
+/* unused               0x20 */
+/* unused               0x40 */
+#define R_PM1_PMVCM	0x80
+
+/* REG_PWR2 */
+#define R_PM2_PMDAC	0x01
+/* unused               0x02 */
+/* unused               0x04 */
+#define R_PM2_PMMO2	0x08
+#define REG_PWR2_MCKAC  0x10
+/* unused               0x20 */
+/* unused               0x40 */
+#define R_PM2_MCKPD	0x80
+
+/* REG_SEL1 */
+#define R_SEL1_PSMO2	0x01
+/* unused               0x02 */
+/* unused               0x04 */
+/* unused               0x08 */
+#define REG_SEL1_MICM   0x10
+#define REG_SEL1_DACM   0x20
+#define REG_SEL1_PSMO   0x40
+#define REG_SEL1_MOGN   0x80
+
+/* REG_SEL2 */
+#define R_SEL2_PSLOR	0x01
+#define R_SEL2_PSLOL	0x02
+#define REG_SEL2_AUXSI  0x04
+/* unused               0x08 */
+#define REG_SEL2_MICL   0x10
+#define REG_SEL2_AUXL   0x20
+/* unused               0x40 */
+#define R_SEL2_DACL	0x80
+
+/* REG_MODE1 */
+#define REG_MODE1_DIF0  0x01
+#define REG_MODE1_DIF1  0x02
+/* unused               0x04 */
+/* unused               0x08 */
+/* unused               0x10 */
+/* unused               0x20 */
+/* unused               0x40 */
+/* unused               0x80 */
+
+/* REG_MODE2 */
+/* unused               0x01 */
+#define REG_MODE2_LOOP  0x02
+#define REG_MODE2_HPM   0x04
+/* unused               0x08 */
+/* unused               0x10 */
+#define REG_MODE2_MCK0  0x20
+#define REG_MODE2_MCK1  0x40
+/* unused               0x80 */
+
+/* REG_DAC */
+#define REG_DAC_DEM0    0x01
+#define REG_DAC_DEM1    0x02
+#define REG_DAC_EQ      0x04
+/* unused               0x08 */
+#define R_DAC_DATTC	0x10
+#define R_DAC_SMUTE	0x20
+#define REG_DAC_TM      0x40
+/* unused               0x80 */
+
+/* REG_MIC */
+#define R_MIC_MGAIN	0x01
+#define R_MIC_MSEL	0x02
+#define R_MIC_MICAD	0x04
+#define R_MIC_MPWRI	0x08
+#define R_MIC_MPWRE	0x10
+#define REG_MIC_AUXAD   0x20
+/* unused               0x40 */
+/* unused               0x80 */
+
+/* REG_TIMER */
+
+#define REG_TIMER_LTM0  0x01
+#define REG_TIMER_LTM1  0x02
+#define REG_TIMER_WTM0  0x04
+#define REG_TIMER_WTM1  0x08
+#define REG_TIMER_ZTM0  0x10
+#define REG_TIMER_ZTM1  0x20
+/* unused               0x40 */
+/* unused               0x80 */
+
+#define REG_ALC1_LMTH   0x01
+#define REG_ALC1_RATT   0x02
+#define REG_ALC1_LMAT0  0x04
+#define REG_ALC1_LMAT1  0x08
+#define REG_ALC1_ZELM   0x10
+#define REG_ALC1_ALC1   0x20
+/* unused               0x40 */
+/* unused               0x80 */
+
+/* REG_ALC2 */
+
+/* REG_PGA */
+
+/* REG_ATTL */
+
+/* REG_ATTR */
+
+/* REG_VOL */
+#define REG_VOL_ATTM	0x80
+
+/* REG_STATUS */
+#define R_STATUS_DTMIC	0x01
+
+/* REG_EQ controls use 4 bits for each of 5 EQ levels */
+
+/* Bluetooth not yet implemented */
+#define REG_BTIF_PMAD2  0x01
+#define REG_BTIF_PMDA2  0x02
+#define REG_BTIF_PMBIF  0x04
+#define REG_BTIF_ADC2   0x08
+#define REG_BTIF_DAC2   0x10
+#define REG_BTIF_BTFMT0 0x20
+#define REG_BTIF_BTFMT1 0x40
+/* unused               0x80 */
+
+/* begin {{ I2C }} */
+
+static struct i2c_driver snd_ak4641_i2c_driver = {
+	.driver = {
+		.name = "ak4641-i2c"
+	},
+};
+
+static int snd_ak4641_i2c_init(void)
+{
+	return i2c_add_driver(&snd_ak4641_i2c_driver);
+}
+
+static void snd_ak4641_i2c_free(void)
+{
+	i2c_del_driver(&snd_ak4641_i2c_driver);
+}
+
+static inline int snd_ak4641_i2c_probe(struct snd_ak4641 *ak)
+{
+	if (ak->i2c_client.adapter == NULL) return -EINVAL;
+	ak->i2c_client.addr = 0x12;
+	if (i2c_smbus_xfer(ak->i2c_client.adapter, ak->i2c_client.addr,
+			   0, 0, 0, I2C_SMBUS_QUICK, NULL) < 0)
+		return -ENODEV;
+	else return 0;
+}
+
+static int snd_ak4641_i2c_attach(struct snd_ak4641 *ak)
+{
+	int ret = 0;
+	if ((ret = snd_ak4641_i2c_probe(ak)) < 0) return ret;
+	snprintf(ak->i2c_client.name, sizeof(ak->i2c_client.name),
+		 "ak4641-i2c at %d-%04x",
+		 i2c_adapter_id(ak->i2c_client.adapter), ak->i2c_client.addr);
+	return i2c_attach_client(&ak->i2c_client);
+}
+
+static void snd_ak4641_i2c_detach(struct snd_ak4641 *ak)
+{
+	i2c_detach_client(&ak->i2c_client);
+}
+
+/* end {{ I2C }} */
+
+
+/* begin {{ Registers & Cache Ops }} */
+
+static int snd_ak4641_hwsync(struct snd_ak4641 *ak, int read, u8 reg)
+{
+	struct i2c_msg msgs[2];
+	u8 buf[2];
+	int ret;
+
+	snd_assert(reg < ARRAY_SIZE(ak->regs), return -EINVAL);
+
+	/* setup i2c msgs */
+	msgs[0].addr = ak->i2c_client.addr;
+	msgs[0].flags = 0;
+	msgs[0].buf = buf;
+	if (!read)
+		msgs[0].len = 2;
+	else {
+		msgs[1].flags = I2C_M_RD;
+		msgs[1].addr = msgs[0].addr;
+		msgs[1].buf = msgs[0].buf + 1;
+		msgs[0].len = 1;
+		msgs[1].len = 1;
+	}
+
+	buf[0] = reg;
+
+	/* regs[reg] -> buffer, on write */
+	if (!read) buf[1] = ak->regs[reg];
+
+	/* i2c transfer */
+	ret = i2c_transfer(ak->i2c_client.adapter, msgs, read ? 2 : 1);
+	if (ret != (read ? 2 : 1)) return ret; /* transfer error */ //@@ error ret < 0, or not ?
+
+	/* regs[reg] <- buffer, on read */
+	if (read) ak->regs[reg] = buf[1];
+
+	return 0;
+}
+
+static inline int snd_ak4641_hwsync_read(struct snd_ak4641 *ak, u8 reg)
+{
+	return snd_ak4641_hwsync(ak, 1, reg);
+}
+
+static inline int snd_ak4641_hwsync_write(struct snd_ak4641 *ak, u8 reg)
+{
+	return snd_ak4641_hwsync(ak, 0, reg);
+}
+
+static int snd_ak4641_hwsync_read_all(struct snd_ak4641 *ak)
+{
+	u8 reg;
+	for (reg = 0; reg < ARRAY_SIZE(ak->regs); reg++)
+		if (snd_ak4641_hwsync_read(ak, reg) < 0) return -1;
+	return 0;
+}
+
+static int snd_ak4641_hwsync_write_all(struct snd_ak4641 *ak)
+{
+	u8 reg;
+	for (reg = 0; reg < ARRAY_SIZE(ak->regs); reg++)
+		if (snd_ak4641_hwsync_write(ak, reg) < 0) return -1;
+	return 0;
+}
+
+static int snd_ak4641_reg_changed(struct snd_ak4641 *ak, u8 reg)
+{
+	if ((reg != R_PGA && ak->powered_on) ||
+	    (reg == R_PGA && (ak->regs[R_PM1] & R_PM1_PMMIC)))
+ 		return snd_ak4641_hwsync_write(ak, reg);
+	return 0;
+}
+
+/* end {{ Registers & Cache Ops }}*/
+
+
+static inline void snd_ak4641_lock(struct snd_ak4641 *ak)
+{
+	down(&ak->sem);
+}
+
+static inline void snd_ak4641_unlock(struct snd_ak4641 *ak)
+{
+	up(&ak->sem);
+}
+
+#define WRITE_MASK(i, val, mask)	(((i) & ~(mask)) | ((val) & (mask)))
+
+
+/* begin {{ Controls }} */
+
+#define INV_RANGE(val, mask) \
+	(~(val) & (mask))
+
+/*-begin----------------------------------------------------------*/
+static int snd_ak4641_actl_playback_volume_info(struct snd_kcontrol *kcontrol,
+						struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xff;
+	return 0;
+}
+
+static int snd_ak4641_actl_playback_volume_get(struct snd_kcontrol *kcontrol,
+					       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+
+	snd_ak4641_lock(ak);
+	ucontrol->value.integer.value[0] = INV_RANGE(ak->regs[R_ATTL], 0xff);
+	ucontrol->value.integer.value[1] = INV_RANGE(ak->regs[R_ATTR], 0xff);
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+
+static int snd_ak4641_actl_playback_volume_put(struct snd_kcontrol *kcontrol,
+					       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+
+	snd_ak4641_lock(ak);
+	ak->regs[R_ATTL] = INV_RANGE(ucontrol->value.integer.value[0], 0xff);
+	ak->regs[R_ATTR] = INV_RANGE(ucontrol->value.integer.value[1], 0xff);
+	snd_ak4641_reg_changed(ak, R_ATTL);
+	snd_ak4641_reg_changed(ak, R_ATTR);
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+/*-end------------------------------------------------------------*/
+
+/*-begin----------------------------------------------------------*/
+static int snd_ak4641_actl_mic_gain_info(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0x7f;
+	return 0;
+}
+
+static int snd_ak4641_actl_mic_gain_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+
+	ucontrol->value.integer.value[0] = ak->regs[R_PGA];
+	return 0;
+}
+
+static int snd_ak4641_actl_mic_gain_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+
+	snd_ak4641_lock(ak);
+	ak->regs[R_PGA] = ucontrol->value.integer.value[0];
+	snd_ak4641_reg_changed(ak, R_PGA);
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+/*-end------------------------------------------------------------*/
+
+#define ACTL(ctl_name, _name) \
+static struct snd_kcontrol_new snd_ak4641_actl_ ## ctl_name = \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = _name, \
+  .info = snd_ak4641_actl_ ## ctl_name ## _info, \
+  .get = snd_ak4641_actl_ ## ctl_name ## _get, .put = snd_ak4641_actl_ ## ctl_name ## _put };
+
+ACTL(playback_volume, "Master Playback Volume")
+ACTL(mic_gain, "Mic Capture Gain")
+
+struct snd_ak4641_uctl_bool {
+	int (*get) (struct snd_ak4641 *uda);
+	int (*set) (struct snd_ak4641 *uda, int on);
+};
+
+static int snd_ak4641_actl_bool_info(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_ak4641_actl_bool_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+	struct snd_ak4641_uctl_bool *uctl =
+		(struct snd_ak4641_uctl_bool *) kcontrol->private_value;
+
+	ucontrol->value.integer.value[0] = uctl->get(ak);
+	return 0;
+}
+
+static int snd_ak4641_actl_bool_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+	struct snd_ak4641_uctl_bool *uctl =
+		(struct snd_ak4641_uctl_bool *) kcontrol->private_value;
+
+	return uctl->set(ak, ucontrol->value.integer.value[0]);
+}
+
+/*-begin----------------------------------------------------------*/
+static int snd_ak4641_uctl_playback_switch_get(struct snd_ak4641 *ak)
+{
+	return (ak->regs[R_DAC] & R_DAC_SMUTE) == 0x00;
+}
+
+static int snd_ak4641_uctl_playback_switch_set(struct snd_ak4641 *ak, int on)
+{
+	snd_ak4641_lock(ak);
+	ak->regs[R_DAC] = WRITE_MASK(ak->regs[R_DAC],
+				     on ? 0x00 : R_DAC_SMUTE, R_DAC_SMUTE);
+	snd_ak4641_reg_changed(ak, R_DAC);
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+/*-end------------------------------------------------------------*/
+
+/*-begin----------------------------------------------------------*/
+static int snd_ak4641_uctl_mic_boost_get(struct snd_ak4641 *ak)
+{
+	return (ak->regs[R_MIC] & R_MIC_MGAIN) == R_MIC_MGAIN;
+}
+
+static int snd_ak4641_uctl_mic_boost_set(struct snd_ak4641 *ak, int on)
+{
+	snd_ak4641_lock(ak);
+	ak->regs[R_MIC] = WRITE_MASK(ak->regs[R_MIC],
+				     on ? R_MIC_MGAIN : 0x00, R_MIC_MGAIN);
+	snd_ak4641_reg_changed(ak, R_MIC);
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+/*-end------------------------------------------------------------*/
+
+/*-begin----------------------------------------------------------*/
+static int snd_ak4641_uctl_mono_out_get(struct snd_ak4641 *ak)
+{
+        printk("mono_out status 0x%8.8x -> 0x%8.8x\n",ak->regs[R_SEL1], ak->regs[R_SEL1] & REG_SEL1_PSMO);
+	return (ak->regs[R_SEL1] & REG_SEL1_PSMO) == REG_SEL1_PSMO;
+}
+
+static int snd_ak4641_uctl_mono_out_set(struct snd_ak4641 *ak, int on)
+{
+        printk("phone mic enable called. on=%d\n",on);
+	snd_ak4641_lock(ak);
+	ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], on ? R_PM1_PMMIC : 0x00, R_PM1_PMMIC);
+	ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], on ? REG_PWR1_PMMO : 0x00, REG_PWR1_PMMO);
+	snd_ak4641_reg_changed(ak, R_PM1);
+
+	snd_ak4641_hwsync_write(ak, R_PGA);	/* mic PGA gain is reset when PMMIC = 0 */
+
+	/* internal mic */
+        ak->regs[R_MIC]	= WRITE_MASK(ak->regs[R_MIC], on ? R_MIC_MPWRI : 0x0, R_MIC_MPWRI);
+        ak->regs[R_MIC]	= WRITE_MASK(ak->regs[R_MIC],                    0x0, R_MIC_MSEL);
+        snd_ak4641_hwsync_write(ak, R_MIC);
+
+//        ak->regs[REG_BTIF]	= WRITE_MASK(ak->regs[REG_BTIF], 0x0, REG_BTIF_DAC2);
+//        snd_ak4641_hwsync_write(ak, REG_BTIF);
+	/* */
+//	ak->regs[REG_VOL] = WRITE_MASK(ak->regs[REG_VOL], on ? REG_VOL_ATTM : 0x00, REG_VOL_ATTM);
+//	ak->regs[R_SEL1] = WRITE_MASK(ak->regs[R_SEL1], on ? REG_SEL1_MOGN : 0x00, REG_SEL1_MOGN);
+	ak->regs[R_SEL1] = WRITE_MASK(ak->regs[R_SEL1], on ? REG_SEL1_MICM : 0x00, REG_SEL1_MICM);
+	ak->regs[R_SEL1] = WRITE_MASK(ak->regs[R_SEL1], on ? REG_SEL1_PSMO : 0x00, REG_SEL1_PSMO);
+	snd_ak4641_reg_changed(ak, R_SEL1);
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+/*-end------------------------------------------------------------*/
+
+#define ACTL_BOOL(ctl_name, _name) \
+static struct snd_ak4641_uctl_bool snd_ak4641_actl_ ## ctl_name ## _pvalue = \
+{ .get = snd_ak4641_uctl_ ## ctl_name ## _get, \
+  .set = snd_ak4641_uctl_ ## ctl_name ## _set }; \
+static struct snd_kcontrol_new snd_ak4641_actl_ ## ctl_name = \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = _name, .info = snd_ak4641_actl_bool_info, \
+  .get = snd_ak4641_actl_bool_get, .put = snd_ak4641_actl_bool_put, \
+  .private_value = (unsigned long) &snd_ak4641_actl_ ## ctl_name ## _pvalue };
+
+ACTL_BOOL(playback_switch, "Master Playback Switch")
+ACTL_BOOL(mic_boost, "Mic Boost (+20dB)")
+ACTL_BOOL(mono_out, "Phone mic enable")
+
+static void snd_ak4641_headphone_on(struct snd_ak4641 *ak, int on);
+static void snd_ak4641_speaker_on(struct snd_ak4641 *ak, int on);
+static void snd_ak4641_select_mic(struct snd_ak4641 *ak);
+
+void snd_ak4641_hp_connected(struct snd_ak4641 *ak, int connected)
+{
+	snd_ak4641_lock(ak);
+	if (connected != ak->hp_connected) {
+		ak->hp_connected = connected;
+
+		/* headphone or speaker, on playback */
+		if (ak->playback_on) {
+			if (connected) {
+				snd_ak4641_headphone_on(ak, 1);
+				snd_ak4641_speaker_on(ak, 0);
+			} else {
+				snd_ak4641_speaker_on(ak, 1);
+				snd_ak4641_headphone_on(ak, 0);
+			}
+		}
+
+		/* headset or internal mic, on capture */
+		if (ak->capture_on)
+			snd_ak4641_select_mic(ak);
+	}
+	snd_ak4641_unlock(ak);
+}
+
+/* end {{ Controls }} */
+
+
+/* begin {{ Headphone Detected Notification }} */
+
+static void snd_ak4641_hp_detected_w_fn(void *p)
+{
+	struct snd_ak4641 *ak = (struct snd_ak4641 *)p;
+
+	snd_ak4641_hp_connected(ak, ak->hp_detected.detected);
+}
+
+void snd_ak4641_hp_detected(struct snd_ak4641 *ak, int detected)
+{
+	if (detected != ak->hp_detected.detected) {
+		ak->hp_detected.detected = detected;
+		queue_work(ak->hp_detected.wq, &ak->hp_detected.w);
+	}
+}
+
+static int snd_ak4641_hp_detected_init(struct snd_ak4641 *ak)
+{
+	INIT_WORK(&ak->hp_detected.w, snd_ak4641_hp_detected_w_fn);
+	ak->hp_detected.detected = ak->hp_connected;
+	ak->hp_detected.wq = create_singlethread_workqueue("ak4641");
+	if (ak->hp_detected.wq) return 0;
+	else return -1;
+}
+
+static void snd_ak4641_hp_detected_free(struct snd_ak4641 *ak)
+{
+	destroy_workqueue(ak->hp_detected.wq);
+}
+
+/* end {{ Headphone Detected Notification }} */
+
+
+/* begin {{ Codec Control }} */
+
+static void snd_ak4641_headphone_on(struct snd_ak4641 *ak, int on)
+{
+	if (on) {
+		ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], R_PM1_PMLO, R_PM1_PMLO);
+		snd_ak4641_hwsync_write(ak, R_PM1);
+		ak->headphone_out_on(1);
+		ak->regs[R_SEL2] = WRITE_MASK(ak->regs[R_SEL2],
+					      R_SEL2_PSLOL | R_SEL2_PSLOR,
+					      R_SEL2_PSLOL | R_SEL2_PSLOR);
+		snd_ak4641_hwsync_write(ak, R_SEL2);
+	} else {
+		ak->regs[R_SEL2] = WRITE_MASK(ak->regs[R_SEL2],
+					      0x00, R_SEL2_PSLOL | R_SEL2_PSLOR);
+		snd_ak4641_hwsync_write(ak, R_SEL2);
+		ak->headphone_out_on(0);
+		ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], 0x00, R_PM1_PMLO);
+		snd_ak4641_hwsync_write(ak, R_PM1);
+	}
+}
+
+static void snd_ak4641_speaker_on(struct snd_ak4641 *ak, int on)
+{
+	if (on) {
+		ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], R_PM1_PMLO, R_PM1_PMLO);
+		snd_ak4641_hwsync_write(ak, R_PM1);
+		ak->speaker_out_on(1);
+		ak->regs[R_SEL2] = WRITE_MASK(ak->regs[R_SEL2],
+					      R_SEL2_PSLOL | R_SEL2_PSLOR,
+					      R_SEL2_PSLOL | R_SEL2_PSLOR);
+		snd_ak4641_hwsync_write(ak, R_SEL2);
+	} else {
+		ak->regs[R_SEL2] = WRITE_MASK(ak->regs[R_SEL2],
+					      0x00, R_SEL2_PSLOL | R_SEL2_PSLOR);
+		snd_ak4641_hwsync_write(ak, R_SEL2);
+		ak->speaker_out_on(0);
+		ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], 0x00, R_PM1_PMLO);
+		snd_ak4641_hwsync_write(ak, R_PM1);
+	}
+}
+
+static inline int snd_ak4641_power_on(struct snd_ak4641 *ak)
+{
+	ak->reset_pin(1);
+	ak->power_on_chip(1);
+	msleep(1);
+	ak->reset_pin(0);
+	ak->powered_on = 1;
+	return 0;
+}
+
+static inline int snd_ak4641_power_off(struct snd_ak4641 *ak)
+{
+	ak->powered_on = 0;
+	ak->power_on_chip(0);
+	return 0;
+}
+
+static inline void snd_ak4641_headphone_out_on(struct snd_ak4641 *ak, int on)
+{
+	if (ak->headphone_out_on) ak->headphone_out_on(on);
+}
+
+static inline void snd_ak4641_speaker_out_on(struct snd_ak4641 *ak, int on)
+{
+	if (ak->speaker_out_on) ak->speaker_out_on(on);
+}
+
+static int snd_ak4641_playback_on(struct snd_ak4641 *ak)
+{
+	if (ak->playback_on) return 0;
+
+	ak->regs[R_PM2] = WRITE_MASK(ak->regs[R_PM2],
+				     R_PM2_PMDAC, R_PM2_MCKPD | R_PM2_PMDAC);
+	ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], R_PM1_PMLO, R_PM1_PMLO);
+	snd_ak4641_hwsync_write(ak, R_PM2);
+	snd_ak4641_hwsync_write(ak, R_PM1);
+	if (ak->hp_connected) snd_ak4641_headphone_on(ak, 1);
+	else snd_ak4641_speaker_on(ak, 1);
+
+	ak->playback_on = 1;
+
+	return 0;
+}
+
+static int snd_ak4641_playback_off(struct snd_ak4641 *ak)
+{
+	if (!ak->playback_on) return 0;
+
+	ak->playback_on = 0;
+
+	if (ak->hp_connected) snd_ak4641_headphone_on(ak, 0);
+	else snd_ak4641_speaker_on(ak, 0);
+	ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], 0x00, R_PM1_PMLO);
+	ak->regs[R_PM2] = WRITE_MASK(ak->regs[R_PM2],
+				    (!ak->capture_on ? R_PM2_MCKPD : 0x00) | R_PM2_PMDAC,
+				    R_PM2_MCKPD | R_PM2_PMDAC);
+	snd_ak4641_hwsync_write(ak, R_PM1);
+	snd_ak4641_hwsync_write(ak, R_PM2);
+
+	return 0;
+}
+
+static void snd_ak4641_select_mic(struct snd_ak4641 *ak)
+{
+	int mic = 0;
+	u8 r_mic;
+
+	if (ak->hp_connected) {
+		/* check headset mic */
+		ak->regs[R_MIC]	= WRITE_MASK(ak->regs[R_MIC], R_MIC_MPWRE, R_MIC_MPWRE);
+		snd_ak4641_hwsync_write(ak, R_MIC);
+		snd_ak4641_hwsync_read(ak, R_STATUS);
+		mic = (ak->regs[R_STATUS] & R_STATUS_DTMIC) == R_STATUS_DTMIC;
+
+		printk("htcuniversal_ak4641_select_mic: mic=%d\n",mic);
+
+	 r_mic = WRITE_MASK(ak->regs[R_MIC],
+			   R_MIC_MSEL | (ak->capture_on ? R_MIC_MPWRE : 0x00),
+			   R_MIC_MSEL | R_MIC_MPWRI | R_MIC_MPWRE);
+	}
+	else
+	 r_mic = WRITE_MASK(ak->regs[R_MIC],
+			         0x00 | (ak->capture_on ? R_MIC_MPWRI : 0x00),
+			   R_MIC_MSEL | R_MIC_MPWRI | R_MIC_MPWRE);
+
+	if (r_mic != ak->regs[R_MIC]) {
+		ak->regs[R_MIC] = r_mic;
+		snd_ak4641_hwsync_write(ak, R_MIC);
+	}
+}
+
+static int snd_ak4641_capture_on(struct snd_ak4641 *ak)
+{
+	if (ak->capture_on) return 0;
+
+	if (!ak->playback_on) {
+		ak->regs[R_PM2] = WRITE_MASK(ak->regs[R_PM2], 0x00, R_PM2_MCKPD);
+		snd_ak4641_hwsync_write(ak, R_PM2);
+	}
+	ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], R_PM1_PMMIC | R_PM1_PMADC,
+						      R_PM1_PMMIC | R_PM1_PMADC);
+	snd_ak4641_hwsync_write(ak, R_PM1);
+	snd_ak4641_hwsync_write(ak, R_PGA);	/* mic PGA gain is reset when PMMIC = 0 */
+
+	ak->capture_on = 1;
+
+	snd_ak4641_select_mic(ak);
+
+	msleep(47);	/* accounts for ADC init cycle, time enough for fs >= 44.1 kHz */
+
+	return 0;
+}
+
+static int snd_ak4641_capture_off(struct snd_ak4641 *ak)
+{
+	if (!ak->capture_on) return 0;
+
+	ak->regs[R_MIC] = WRITE_MASK(ak->regs[R_MIC],
+				     0x00, R_MIC_MPWRI | R_MIC_MPWRE | R_MIC_MSEL);
+	ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], 0x00, R_PM1_PMMIC | R_PM1_PMADC);
+	snd_ak4641_hwsync_write(ak, R_MIC);
+	snd_ak4641_hwsync_write(ak, R_PM1);
+	if (!ak->playback_on) {
+		ak->regs[R_PM2] = WRITE_MASK(ak->regs[R_PM2], R_PM2_MCKPD, R_PM2_MCKPD);
+		snd_ak4641_hwsync_write(ak, R_PM2);
+	}
+
+	ak->capture_on = 0;
+
+	return 0;
+}
+
+int snd_ak4641_open_stream(struct snd_ak4641 *ak, int stream)
+{
+	snd_ak4641_lock(ak);
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ak->playback_stream_opened = 1;
+		snd_ak4641_playback_on(ak);
+	} else {
+		ak->capture_stream_opened = 1;
+		snd_ak4641_capture_on(ak);
+	}
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+
+int snd_ak4641_close_stream(struct snd_ak4641 *ak, int stream)
+{
+	snd_ak4641_lock(ak);
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ak->playback_stream_opened = 0;
+		snd_ak4641_playback_off(ak);
+	} else {
+		ak->capture_stream_opened = 0;
+		snd_ak4641_capture_off(ak);
+	}
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+
+static int snd_ak4641_init_regs(struct snd_ak4641 *ak)
+{
+	snd_ak4641_hwsync_read_all(ak);
+
+	//@@ MEMO: add some configs
+
+	ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], R_PM1_PMVCM, R_PM1_PMVCM);
+	ak->regs[R_DAC] = WRITE_MASK(ak->regs[R_DAC], 0x00, R_DAC_DATTC);
+	snd_ak4641_hwsync_write(ak, R_PM1);
+	snd_ak4641_hwsync_write(ak, R_DAC);
+
+	return 0;
+}
+
+int snd_ak4641_suspend(struct snd_ak4641 *ak, pm_message_t state)
+{
+	snd_ak4641_lock(ak);
+	if (ak->playback_on) snd_ak4641_playback_off(ak);
+	if (ak->capture_on) snd_ak4641_capture_off(ak);
+	snd_ak4641_power_off(ak);
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+
+int snd_ak4641_resume(struct snd_ak4641 *ak)
+{
+	snd_ak4641_lock(ak);
+	snd_ak4641_power_on(ak);
+	snd_ak4641_hwsync_write_all(ak);
+	if (ak->playback_stream_opened) snd_ak4641_playback_on(ak);
+	if (ak->capture_stream_opened) snd_ak4641_capture_on(ak);
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+
+static void snd_ak4641_init_ak(struct snd_ak4641 *ak)
+{
+	init_MUTEX(&ak->sem);
+	ak->i2c_client.driver = &snd_ak4641_i2c_driver;
+}
+
+int snd_ak4641_activate(struct snd_ak4641 *ak)
+{
+	int ret = 0;
+
+	snd_ak4641_init_ak(ak);
+	snd_ak4641_lock(ak);
+	snd_ak4641_power_on(ak);
+	if ((ret = snd_ak4641_i2c_attach(ak)) < 0)
+		goto failed_i2c_attach;
+	snd_ak4641_init_regs(ak);
+	if ((ret = snd_ak4641_hp_detected_init(ak)) < 0)
+		goto failed_hp_detected_init;
+	snd_ak4641_unlock(ak);
+	return 0;
+
+ failed_hp_detected_init:
+	snd_ak4641_i2c_detach(ak);
+ failed_i2c_attach:
+	snd_ak4641_power_off(ak);
+	snd_ak4641_unlock(ak);
+	return ret;
+}
+
+void snd_ak4641_deactivate(struct snd_ak4641 *ak)
+{
+	snd_ak4641_lock(ak);
+	snd_ak4641_hp_detected_free(ak);
+	snd_ak4641_i2c_detach(ak);
+	snd_ak4641_power_off(ak);
+	snd_ak4641_unlock(ak);
+}
+
+int snd_ak4641_add_mixer_controls(struct snd_ak4641 *ak, struct snd_card *card)
+{
+	snd_ak4641_lock(ak);
+	snd_ctl_add(card, snd_ctl_new1(&snd_ak4641_actl_playback_volume, ak));
+	snd_ctl_add(card, snd_ctl_new1(&snd_ak4641_actl_playback_switch, ak));
+	snd_ctl_add(card, snd_ctl_new1(&snd_ak4641_actl_mic_gain, ak));
+	snd_ctl_add(card, snd_ctl_new1(&snd_ak4641_actl_mic_boost, ak));
+	snd_ctl_add(card, snd_ctl_new1(&snd_ak4641_actl_mono_out, ak));
+	snd_ak4641_unlock(ak);
+	return 0;
+}
+
+/* end {{ Codec Control }} */
+
+
+/* begin {{ Module }} */
+
+static int __init snd_ak4641_module_on_load(void)
+{
+	snd_ak4641_i2c_init();
+	return 0;
+}
+
+static void __exit snd_ak4641_module_on_unload(void)
+{
+	snd_ak4641_i2c_free();
+}
+
+module_init(snd_ak4641_module_on_load);
+module_exit(snd_ak4641_module_on_unload);
+
+EXPORT_SYMBOL(snd_ak4641_activate);
+EXPORT_SYMBOL(snd_ak4641_deactivate);
+EXPORT_SYMBOL(snd_ak4641_add_mixer_controls);
+EXPORT_SYMBOL(snd_ak4641_open_stream);
+EXPORT_SYMBOL(snd_ak4641_close_stream);
+EXPORT_SYMBOL(snd_ak4641_suspend);
+EXPORT_SYMBOL(snd_ak4641_resume);
+EXPORT_SYMBOL(snd_ak4641_hp_connected);
+EXPORT_SYMBOL(snd_ak4641_hp_detected);
+
+MODULE_AUTHOR("Giorgio Padrin");
+MODULE_DESCRIPTION("Audio support for codec Asahi Kasei AK4641");
+MODULE_LICENSE("GPL");
+
+/* end {{ Module }} */
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,65 @@
+/*
+ * Audio support for codec Asahi Kasei AK4641
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (c) 2006 Giorgio Padrin <giorgio@mandarinlogiq.org>
+ */
+
+#ifndef __SOUND_AK4641_H
+#define __SOUND_AK4641_H
+
+#include <linux/i2c.h>
+
+struct snd_ak4641 {
+	struct semaphore sem;
+
+	u8 regs[0x14];	/* registers cache */
+
+	unsigned int
+		powered_on:1,
+		playback_on:1,
+		playback_stream_opened:1,
+		capture_on:1,
+		capture_stream_opened:1;
+
+	unsigned int
+		hp_connected:1;
+
+	/* -- configuration (to fill before activation) -- */
+	void (*power_on_chip)(int on);
+	void (*reset_pin)(int on);
+	void (*headphone_out_on)(int on);
+	void (*speaker_out_on)(int on);
+
+	struct i2c_client i2c_client; /* to fill .adapter */
+	/* ----------------------------------------------- */
+
+	struct {
+		int detected;
+		struct workqueue_struct *wq;
+		struct work_struct w;
+	} hp_detected;
+};
+
+
+/* Note: opening, closing, suspending and resuming a stream
+ * require the clocks (MCLK and I2S ones) running
+ */
+
+/* don't forget to specify I2C adapter in i2c_client field */
+int snd_ak4641_activate(struct snd_ak4641 *ak);
+
+void snd_ak4641_deactivate(struct snd_ak4641 *ak);
+int snd_ak4641_add_mixer_controls(struct snd_ak4641 *ak, struct snd_card *card);
+int snd_ak4641_open_stream(struct snd_ak4641 *ak, int stream);
+int snd_ak4641_close_stream(struct snd_ak4641 *ak, int stream);
+int snd_ak4641_suspend(struct snd_ak4641 *ak, pm_message_t state);
+int snd_ak4641_resume(struct snd_ak4641 *ak);
+
+void snd_ak4641_hp_connected(struct snd_ak4641 *ak, int connected); /* non atomic context */
+void snd_ak4641_hp_detected(struct snd_ak4641 *ak, int detected); /* atomic context */
+
+#endif /* __SOUND_AK4641_H */
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_asic3_leds.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_asic3_leds.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,143 @@
+/*
+ * LEDs support for the HP iPaq hx4700
+ *
+ * Copyright (c) 2006  Anton Vorontsov <cbou@mail.ru>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/soc/asic3_base.h>
+
+#include <asm/hardware/ipaq-asic3.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/asic3_leds.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+//FIXME
+//DEFINE_LED_TRIGGER_SHARED_GLOBAL(htcuniversal_radio_trig);
+//EXPORT_LED_TRIGGER_SHARED(htcuniversal_radio_trig);
+
+static struct asic3_led htcuniversal_leds[] = {
+	{
+		.led_cdev  = {
+			.name	        = "htcuniversal:red",
+			.default_trigger = "htcuniversal-charging",
+		},
+		.hw_num = 2,
+
+	},
+	{
+		.led_cdev  = {
+			.name	         = "htcuniversal:green",
+			.default_trigger = "htcuniversal-chargefull",
+		},
+		.hw_num = 1,
+	},
+	{
+		.led_cdev  = {
+			.name	         = "htcuniversal:wifi-bt",
+			.default_trigger = "htcuniversal-radio",
+		},
+		.hw_num = 0,
+	},
+	{
+		.led_cdev  = {
+			.name	         = "htcuniversal:phonebuttons",
+			.default_trigger = "htcuniversal-phonebuttons",
+		},
+		.hw_num = -1,
+		.gpio_num = ('D'-'A')*16+GPIOD_BL_KEYP_PWR_ON,
+	},
+	{
+		.led_cdev  = {
+			.name	         = "htcuniversal:vibra",
+			.default_trigger = "htcuniversal-vibra",
+		},
+		.hw_num = -1,
+		.gpio_num = ('D'-'A')*16+GPIOD_VIBRA_PWR_ON,
+	},
+	{
+		.led_cdev  = {
+			.name	         = "htcuniversal:flashlight1",
+			.default_trigger = "htcuniversal-flashlight1",
+		},
+		.hw_num = -1,
+		.gpio_num = ('A'-'A')*16+GPIOA_FLASHLIGHT,
+	},
+	{
+		.led_cdev  = {
+			.name	         = "htcuniversal:kbdbacklight",
+			.default_trigger = "htcuniversal-kbdbacklight",
+		},
+		.hw_num = -1,
+		.gpio_num = ('D'-'A')*16+GPIOD_BL_KEYB_PWR_ON,
+	},
+};
+
+void htcuniversal_leds_release(struct device *dev)
+{
+	return;
+}
+
+static
+struct asic3_leds_machinfo htcuniversal_leds_machinfo = {
+	.num_leds = ARRAY_SIZE(htcuniversal_leds),
+	.leds = htcuniversal_leds,
+	.asic3_pdev = &htcuniversal_asic3,
+};
+
+static
+struct platform_device htcuniversal_leds_pdev = {
+	.name = "asic3-leds",
+	.dev = {
+		.platform_data = &htcuniversal_leds_machinfo,
+		.release = htcuniversal_leds_release,
+	},
+};
+
+static
+int __init htcuniversal_leds_init(void)
+{
+	int ret;
+	printk("htcuniversal LEDs Driver\n");
+//	led_trigger_register_shared("htcuniversal-radio", &htcuniversal_radio_trig);
+
+	ret = asic3_leds_register();
+	if (ret) goto asic3_leds_failed;
+
+	ret = platform_device_register(&htcuniversal_leds_pdev);
+	if (ret) goto platform_device_failed;
+
+	goto success;
+
+platform_device_failed:
+	asic3_leds_unregister();
+asic3_leds_failed:
+//	led_trigger_unregister_shared(htcuniversal_radio_trig);
+	printk("htcuniversal LEDs Driver failed to init");
+success:
+	return ret;
+}
+
+static
+void __exit htcuniversal_leds_exit(void)
+{
+//	led_trigger_unregister_shared(htcuniversal_radio_trig);
+	platform_device_unregister(&htcuniversal_leds_pdev);
+	asic3_leds_unregister();
+	return;
+}
+
+module_init(htcuniversal_leds_init);
+module_exit(htcuniversal_leds_exit);
+
+MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
+MODULE_DESCRIPTION("htcuniversal LEDs driver");
+MODULE_LICENSE("GPL");
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bl.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bl.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,61 @@
+/*
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * Copyright (C) 2006 Paul Sokolosvky
+ * Based on code from older versions of htcuniversal_lcd.c
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <asm/arch/hardware.h>  /* for pxa-regs.h (__REG) */
+#include <asm/arch/pxa-regs.h>
+#include <asm/mach-types.h>     /* machine_is_htcuniversal */
+//#include <linux/corgi_bl.h>
+#include <linux/backlight.h>
+#include <linux/err.h>
+
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+#include <asm/hardware/ipaq-asic3.h>
+#include <linux/soc/asic3_base.h>
+
+#define HTCUNIVERSAL_MAX_INTENSITY 0xc7
+
+static void htcuniversal_set_bl_intensity(int intensity)
+{
+	PWM_CTRL1 = 1;            /* pre-scaler */
+	PWM_PWDUTY1 = intensity; /* duty cycle */
+	PWM_PERVAL1 = HTCUNIVERSAL_MAX_INTENSITY+1;      /* period */
+
+	if (intensity > 0) {
+		pxa_set_cken(CKEN_PWM1, 1);
+                asic3_set_gpio_out_d(&htcuniversal_asic3.dev,
+                        (1<<GPIOD_FL_PWR_ON), (1<<GPIOD_FL_PWR_ON));
+	} else {
+		pxa_set_cken(CKEN_PWM1, 0);
+                asic3_set_gpio_out_d(&htcuniversal_asic3.dev,
+                        (1<<GPIOD_FL_PWR_ON), 0);
+	}
+}
+
+
+static struct generic_bl_info htcuniversal_bl_machinfo = {
+        .default_intensity = HTCUNIVERSAL_MAX_INTENSITY / 4,
+        .limit_mask = 0xff,
+        .max_intensity = HTCUNIVERSAL_MAX_INTENSITY,
+        .set_bl_intensity = htcuniversal_set_bl_intensity,
+};
+
+struct platform_device htcuniversal_bl = {
+        .name = "corgi-bl",
+        .dev = {
+    		.platform_data = &htcuniversal_bl_machinfo,
+	},
+};
+
+MODULE_AUTHOR("Paul Sokolovsky <pmiscml@gmail.com>");
+MODULE_DESCRIPTION("Backlight driver for HTC Universal");
+MODULE_LICENSE("GPL");
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,135 @@
+/* Bluetooth interface driver for TI BRF6150 on HX4700
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * 2005-04-21   Todd Blumer             Created.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/soc/asic3_base.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/serial.h>
+#include <asm/hardware/ipaq-asic3.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+#include "htcuniversal_bt.h"
+
+static uint use_led=1;
+
+static void
+htcuniversal_bt_configure( int state )
+{
+	int tries;
+
+	printk( KERN_NOTICE "htcuniversal configure bluetooth: %d\n", state );
+	switch (state) {
+
+	case PXA_UART_CFG_PRE_STARTUP:
+		break;
+
+	case PXA_UART_CFG_POST_STARTUP:
+		/* pre-serial-up hardware configuration */
+		htcuniversal_egpio_enable(1<<EGPIO5_BT_3V3_ON);
+		mdelay(50);
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_BT_PWR_ON, 1<<GPIOC_BT_PWR_ON);
+		mdelay(10);
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_BT_RESET, 0);
+		mdelay(10);
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_BT_RESET, 1<<GPIOC_BT_RESET);
+		mdelay(10);
+
+		/*
+		 * BRF6150's RTS goes low when firmware is ready
+		 * so check for CTS=1 (nCTS=0 -> CTS=1). Typical 150ms
+		 */
+		tries = 0;
+		do {
+			mdelay(10);
+		} while ((BTMSR & MSR_CTS) == 0 && tries++ < 50);
+		if (use_led) {
+//			htcuniversal_set_led(2, 16, 16);
+		}
+		break;
+
+	case PXA_UART_CFG_PRE_SHUTDOWN:
+		htcuniversal_egpio_disable(1<<EGPIO5_BT_3V3_ON );
+		mdelay(50);
+//		htcuniversal_clear_led(2);
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_BT_PWR_ON, 0);
+		break;
+
+	default:
+		break;
+	}
+}
+
+
+static int
+htcuniversal_bt_probe( struct platform_device *dev )
+{
+	struct htcuniversal_bt_funcs *funcs = dev->dev.platform_data;
+
+	/* configure bluetooth UART */
+	pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_BT_RXD_MD );
+	pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_BT_TXD_MD );
+	pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_BT_UART_CTS_MD );
+	pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_BT_UART_RTS_MD );
+
+	funcs->configure = htcuniversal_bt_configure;
+
+	/* Make sure the LED is off */
+//	htcuniversal_clear_led(2);
+
+	return 0;
+}
+
+static int
+htcuniversal_bt_remove( struct platform_device *dev )
+{
+	struct htcuniversal_bt_funcs *funcs = dev->dev.platform_data;
+
+	funcs->configure = NULL;
+
+	/* Make sure the LED is off */
+//	htcuniversal_clear_led(2);
+
+	return 0;
+}
+
+static struct platform_driver bt_driver = {
+	.driver = {
+		.name     = "htcuniversal_bt",
+	},
+	.probe    = htcuniversal_bt_probe,
+	.remove   = htcuniversal_bt_remove,
+};
+
+module_param(use_led, uint, 0);
+
+static int __init
+htcuniversal_bt_init( void )
+{
+	printk(KERN_NOTICE "htcuniversal Bluetooth Driver\n");
+	return platform_driver_register( &bt_driver );
+}
+
+static void __exit
+htcuniversal_bt_exit( void )
+{
+	platform_driver_unregister( &bt_driver );
+}
+
+module_init( htcuniversal_bt_init );
+module_exit( htcuniversal_bt_exit );
+
+MODULE_AUTHOR("Todd Blumer, SDG Systems, LLC");
+MODULE_DESCRIPTION("HTC Universal Bluetooth Support Driver");
+MODULE_LICENSE("GPL");
+
+/* vim600: set noexpandtab sw=8 ts=8 :*/
+
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,17 @@
+/*
+ * Bluetooth support file for calling bluetooth configuration functions
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * 2005-06	Todd Blumer             Initial Revision
+ */
+
+#ifndef _HTCUNIVERSAL_BT_H
+#define _HTCUNIVERSAL_BT_H
+
+struct htcuniversal_bt_funcs {
+	void (*configure) ( int state );
+};
+
+
+#endif
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_buttons.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_buttons.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,87 @@
+/*
+ * Buttons driver for HTC Universal
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.
+ *
+ * Copyright (C) 2005 Pawel Kolodziejski
+ * Copyright (C) 2003 Joshua Wise
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/input_pda.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_keys.h>
+#include <linux/soc/asic3_base.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/asic3_keys.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+static struct asic3_keys_button asic3_buttons[] = {
+//{KEY_SCREEN,		ASIC3_GPIOA_IRQ_BASE+GPIOA_COVER_ROTATE_N,	1, 	"screen_cover", EV_SW},
+//{KEY_SWITCHVIDEOMODE,	ASIC3_GPIOB_IRQ_BASE+GPIOB_CLAMSHELL_N,		1, 	"clamshell_rotate", EV_SW},
+//{KEY_KBDILLUMTOGGLE,	ASIC3_GPIOB_IRQ_BASE+GPIOB_NIGHT_SENSOR,	1, 	"night_sensor", EV_SW},
+{SW_LID,		ASIC3_GPIOA_IRQ_BASE+GPIOA_COVER_ROTATE_N,	1, 	"screen_cover", EV_SW},
+{SW_TABLET_MODE,	ASIC3_GPIOB_IRQ_BASE+GPIOB_CLAMSHELL_N,		1, 	"clamshell_rotate", EV_SW},
+//{SW_NIGHT_SENSOR,	ASIC3_GPIOB_IRQ_BASE+GPIOB_NIGHT_SENSOR,	1, 	"night_sensor", EV_SW},
+{KEY_F10,		ASIC3_GPIOA_IRQ_BASE+GPIOA_BUTTON_BACKLIGHT_N,	1, 	"backlight_button"},
+{KEY_RECORD,		ASIC3_GPIOA_IRQ_BASE+GPIOA_BUTTON_RECORD_N,	1, 	"record_button"},
+{KEY_CAMERA,		ASIC3_GPIOA_IRQ_BASE+GPIOA_BUTTON_CAMERA_N,	1, 	"camera_button"},
+{KEY_VOLUMEDOWN,	ASIC3_GPIOA_IRQ_BASE+GPIOA_VOL_UP_N,		1, 	"volume_slider_down"},
+{KEY_VOLUMEUP,		ASIC3_GPIOA_IRQ_BASE+GPIOA_VOL_DOWN_N,		1, 	"volume_slider_up"},
+{KEY_KPENTER,		ASIC3_GPIOD_IRQ_BASE+GPIOD_KEY_OK_N,		1, 	"select"},
+{KEY_RIGHT,		ASIC3_GPIOD_IRQ_BASE+GPIOD_KEY_RIGHT_N,		1, 	"right"},
+{KEY_LEFT,		ASIC3_GPIOD_IRQ_BASE+GPIOD_KEY_LEFT_N,		1, 	"left"},
+{KEY_DOWN,		ASIC3_GPIOD_IRQ_BASE+GPIOD_KEY_DOWN_N,		1, 	"down"},
+{KEY_UP,		ASIC3_GPIOD_IRQ_BASE+GPIOD_KEY_UP_N,		1, 	"up"},
+};
+
+static struct asic3_keys_platform_data asic3_keys_data = {
+        .buttons = asic3_buttons,
+        .nbuttons = ARRAY_SIZE(asic3_buttons),
+        .asic3_dev = &htcuniversal_asic3.dev,
+};
+
+static struct platform_device htcuniversal_keys_asic3 = {
+        .name = "asic3-keys",
+        .dev = { .platform_data = &asic3_keys_data, }
+};
+
+static int __init htcuniversal_buttons_probe(struct platform_device *dev)
+{
+	platform_device_register(&htcuniversal_keys_asic3);
+	return 0;
+}
+
+static struct platform_driver htcuniversal_buttons_driver = {
+	.driver		= {
+	    .name       = "htcuniversal_buttons",
+	},
+	.probe          = htcuniversal_buttons_probe,
+};
+
+static int __init htcuniversal_buttons_init(void)
+{
+	if (!machine_is_htcuniversal())
+		return -ENODEV;
+
+	return platform_driver_register(&htcuniversal_buttons_driver);
+}
+
+static void __exit htcuniversal_buttons_exit(void)
+{
+	platform_driver_unregister(&htcuniversal_buttons_driver);
+}
+
+module_init(htcuniversal_buttons_init);
+module_exit(htcuniversal_buttons_exit);
+
+MODULE_AUTHOR ("Joshua Wise, Pawel Kolodziejski, Paul Sokolosvky");
+MODULE_DESCRIPTION ("Buttons support for HTC Universal");
+MODULE_LICENSE ("GPL");
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_core.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_core.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,226 @@
+/* Core Hardware driver for Hx4700 (Serial, ASIC3, EGPIOs)
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * 2005-03-29   Todd Blumer             Converted  basic structure to support hx4700
+ * 2005-04-30	Todd Blumer		Add IRDA code from H2200
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/mach/irq.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa-pm_ll.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+#include <linux/soc/asic3_base.h>
+#include <asm/hardware/ipaq-asic3.h>
+
+volatile u_int16_t *egpios;
+u_int16_t egpio_reg;
+
+static int htc_bootloader = 0;	/* Is the stock HTC bootloader installed? */
+
+/*
+ * may make sense to put egpios elsewhere, but they're here now
+ * since they share some of the same address space with the TI WLAN
+ *
+ * EGPIO register is write-only
+ */
+
+void
+htcuniversal_egpio_enable( u_int16_t bits )
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	egpio_reg |= bits;
+	*egpios = egpio_reg;
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(htcuniversal_egpio_enable);
+
+void
+htcuniversal_egpio_disable( u_int16_t bits )
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	egpio_reg &= ~bits;
+	*egpios = egpio_reg;
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(htcuniversal_egpio_disable);
+
+#ifdef CONFIG_PM
+
+//void htcuniversal_ll_pm_init(void);
+
+static int htcuniversal_suspend(struct platform_device *dev, pm_message_t state)
+{
+	/* Turn off external clocks here, because htcuniversal_power and asic3_mmc
+	 * scared to do so to not hurt each other. (-5 mA) */
+
+
+	/* 0x20c2 is HTC clock value
+	 * CLOCK_CDEX_SOURCE		2
+	 * CLOCK_CDEX_SPI		0
+	 * CLOCK_CDEX_OWM		0
+	 *
+	 * CLOCK_CDEX_PWM0		0
+	 * CLOCK_CDEX_PWM1		0
+	 * CLOCK_CDEX_LED0		1
+	 * CLOCK_CDEX_LED1		1
+	 *
+	 * CLOCK_CDEX_LED2		0
+	 * CLOCK_CDEX_SD_HOST		0
+	 * CLOCK_CDEX_SD_BUS		0
+	 * CLOCK_CDEX_SMBUS		0
+	 *
+	 * CLOCK_CDEX_CONTROL_CX	0
+	 * CLOCK_CDEX_EX0		1
+	 * CLOCK_CDEX_EX1		0
+	 * */
+	asic3_set_clock_cdex(&htcuniversal_asic3.dev, 0xffff, CLOCK_CDEX_SOURCE1
+	                                                     |CLOCK_CDEX_LED0
+	                                                     |CLOCK_CDEX_LED1
+	                                                     |CLOCK_CDEX_LED2
+	                                                     |CLOCK_CDEX_EX0
+	                                                     |CLOCK_CDEX_EX1);
+
+	*egpios = 0;	/* turn off all egpio power */
+
+	/* Wake up enable. */
+	PWER =    PWER_GPIO0
+		| PWER_GPIO1 /* reset */
+		| PWER_GPIO9 /* USB */
+		| PWER_GPIO10 /* AC on USB */
+		| PWER_GPIO14 /* ASIC3 mux */
+		| PWER_RTC;
+	/* Wake up on falling edge. */
+	PFER =    PWER_GPIO0
+		| PWER_GPIO1
+		| PWER_GPIO9
+		| PWER_GPIO10
+		| PWER_GPIO14;
+
+	/* Wake up on rising edge. */
+	PRER =    PWER_GPIO0
+		| PWER_GPIO1
+		| PWER_GPIO9
+		| PWER_GPIO10;
+	/* 3.6864 MHz oscillator power-down enable */
+	PCFR = PCFR_OPDE | PCFR_PI2CEN | PCFR_GPROD | PCFR_GPR_EN;
+
+	PGSR0 = 0x09088004;
+	PGSR1 = 0x00020002;
+	PGSR2 = 0x8001c000;
+	PGSR3 = 0x00106284;
+
+	PSLR  = 0xcc000000;
+
+#if 0
+	/*
+	 * If we're using bootldr and not the stock HTC bootloader,
+	 * we want to wake up periodically to see if the charge is full while
+	 * it is suspended.  We do this with the OS timer 4 in the pxa270.
+	 */
+	if (!htc_bootloader) {
+		OMCR4 = 0x4b;   /* Periodic, self-resetting, 1-second timer */
+		OSMR4 = 5;      /* Wake up bootldr after x seconds so it can
+				   figure out what to do with the LEDs. */
+		OIER |= 0x10;   /* Enable interrupt source for Timer 4 */
+		OSCR4 = 0;      /* This starts the timer */
+	}
+#endif
+
+	asic3_set_extcf_select(&htcuniversal_asic3.dev, ASIC3_EXTCF_OWM_EN, 0);
+
+	return 0;
+}
+
+static int htcuniversal_resume(struct platform_device *dev)
+{
+	htcuniversal_egpio_enable(0);
+
+	return 0;
+}
+#else
+#   define htcuniversal_suspend NULL
+#   define htcuniversal_resume NULL
+#endif
+
+static int
+htcuniversal_core_probe( struct platform_device *dev )
+{
+
+	printk( KERN_NOTICE "HTC Universal Core Hardware Driver\n" );
+
+	egpios = (volatile u_int16_t *)ioremap_nocache(HTCUNIVERSAL_EGPIO_BASE, sizeof *egpios );
+	if (!egpios)
+		return -ENODEV;
+	else
+	 printk( KERN_NOTICE "HTC Universal Core: egpio at phy=0x%8.8x is at virt=0x%p\n",
+	  HTCUNIVERSAL_EGPIO_BASE, egpios );
+
+	printk("Using stock HTC first stage bootloader\n");
+	htc_bootloader = 1;
+
+//	htcuniversal_ll_pm_init();
+
+	return 0;
+}
+
+static int
+htcuniversal_core_remove( struct platform_device *dev )
+{
+
+	if (egpios != NULL)
+		iounmap( (void *)egpios );
+
+	return 0;
+}
+
+static struct platform_driver htcuniversal_core_driver = {
+	.driver = {
+		.name     = "htcuniversal_core",
+	},
+	.probe    = htcuniversal_core_probe,
+	.remove   = htcuniversal_core_remove,
+	.suspend  = htcuniversal_suspend,
+	.resume   = htcuniversal_resume,
+};
+
+static int __init
+htcuniversal_core_init( void )
+{
+	return platform_driver_register( &htcuniversal_core_driver );
+}
+
+
+static void __exit
+htcuniversal_core_exit( void )
+{
+	platform_driver_unregister( &htcuniversal_core_driver );
+}
+
+module_init( htcuniversal_core_init );
+module_exit( htcuniversal_core_exit );
+
+MODULE_AUTHOR("Todd Blumer, SDG Systems, LLC");
+MODULE_DESCRIPTION("HTC Universal Core Hardware Driver");
+MODULE_LICENSE("GPL");
+
+/* vim600: set noexpandtab sw=8 ts=8 :*/
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_lcd.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_lcd.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,212 @@
+/*
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * History:
+ *
+ * 2004-03-01   Eddi De Pieri      Adapted for htcuniversal using h3900_lcd.c
+ * 2004         Shawn Anderson     Lcd hacking on htcuniversal
+ * see h3900_lcd.c for more history.
+ *
+ */
+
+#include <linux/types.h>
+#include <asm/arch/hardware.h>  /* for pxa-regs.h (__REG) */
+#include <linux/platform_device.h>
+#include <asm/arch/pxa-regs.h>  /* LCCR[0,1,2,3]* */
+#include <asm/arch/bitfield.h>  /* for pxa-regs.h (Fld, etc) */
+#include <asm/arch/pxafb.h>     /* pxafb_mach_info, set_pxa_fb_info */
+#include <asm/mach-types.h>     /* machine_is_htcuniversal */
+#include <linux/lcd.h>          /* lcd_device */
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+#include <asm/hardware/ipaq-asic3.h>
+#include <linux/soc/asic3_base.h>
+
+static int saved_lcdpower=-1;
+
+static int powerup_lcd(void)
+{
+	printk( KERN_INFO "htcuniversal powerup_lcd: called\n");
+
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR1_ON, 0);
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR2_ON, 0);
+		asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_LCD_PWR3_ON, 0);
+		asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_LCD_PWR4_ON, 0);
+		asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_LCD_PWR5_ON, 0);
+#if 1
+		LCCR4|=LCCR4_PCDDIV;
+#endif
+		pxa_set_cken(CKEN_LCD, 0);
+
+		mdelay(100);
+		asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_LCD_PWR5_ON, 1<<GPIOA_LCD_PWR5_ON);
+		mdelay(5);
+		asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_LCD_PWR3_ON, 1<<GPIOB_LCD_PWR3_ON);
+		mdelay(2);
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR1_ON, 1<<GPIOC_LCD_PWR1_ON);
+		mdelay(2);
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR2_ON, 1<<GPIOC_LCD_PWR2_ON);
+		mdelay(20);
+		asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_LCD_PWR4_ON, 1<<GPIOD_LCD_PWR4_ON);
+		mdelay(1);
+		pxa_set_cken(CKEN_LCD, 1);
+
+		SET_HTCUNIVERSAL_GPIO(LCD1,1);
+		SET_HTCUNIVERSAL_GPIO(LCD2,1);
+ return 0;
+}
+
+static int powerdown_lcd(void)
+{
+	printk( KERN_INFO "htcuniversal powerdown_lcd: called\n");
+
+#if 1
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR2_ON, 0);
+		mdelay(100);
+		asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_LCD_PWR4_ON, 0);
+		mdelay(10);
+		asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_LCD_PWR5_ON, 0);
+		mdelay(1);
+		asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_LCD_PWR3_ON, 0);
+		mdelay(1);
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR1_ON, 0);
+		pxa_set_cken(CKEN_LCD, 0);
+
+		SET_HTCUNIVERSAL_GPIO(LCD1,0);
+		SET_HTCUNIVERSAL_GPIO(LCD2,0);
+#else
+		pxa_set_cken(CKEN_LCD, 0);
+
+		SET_HTCUNIVERSAL_GPIO(LCD1,0);
+		SET_HTCUNIVERSAL_GPIO(LCD2,0);
+
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR2_ON, 0);
+		mdelay(100);
+		asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_LCD_PWR4_ON, 0);
+		mdelay(10);
+		asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_LCD_PWR5_ON, 0);
+		mdelay(1);
+		asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_LCD_PWR3_ON, 0);
+		mdelay(1);
+		asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR1_ON, 0);
+#endif
+ return 0;
+}
+
+static int htcuniversal_lcd_set_power(struct lcd_device *lm, int power)
+{
+	 /* Enable or disable power to the LCD (0: on; 4: off) */
+
+	if ( power < 1 ) {
+
+	powerup_lcd();
+
+	} else {
+
+	powerdown_lcd();
+
+	}
+
+	saved_lcdpower=power;
+
+	return 0;
+}
+
+static int htcuniversal_lcd_get_power(struct lcd_device *lm)
+{
+	/* Get the LCD panel power status (0: full on, 1..3: controller
+	 * power on, flat panel power off, 4: full off) */
+
+	if (saved_lcdpower == -1)
+	{
+	 htcuniversal_lcd_set_power(lm, 4);
+	 saved_lcdpower=4;
+	}
+
+ return saved_lcdpower;
+}
+
+static struct lcd_ops htcuniversal_lcd_properties =
+{
+	.get_power      = htcuniversal_lcd_get_power,
+	.set_power      = htcuniversal_lcd_set_power,
+};
+
+static struct lcd_device *htcuniversal_lcd_dev;
+
+static int htcuniversal_lcd_probe(struct platform_device * dev)
+{
+	htcuniversal_lcd_dev = lcd_device_register("pxa2xx-fb", &dev->dev, NULL,
+			&htcuniversal_lcd_properties);
+	if (IS_ERR(htcuniversal_lcd_dev)) {
+		printk("htcuniversal_lcd_probe: error registering devices\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int htcuniversal_lcd_remove(struct platform_device * dev)
+{
+	htcuniversal_lcd_set_power(htcuniversal_lcd_dev, 4);
+	lcd_device_unregister(htcuniversal_lcd_dev);
+
+	return 0;
+}
+
+static int htcuniversal_lcd_suspend(struct platform_device * dev, pm_message_t state)
+{
+//	printk("htcuniversal_lcd_suspend: called.\n");
+	htcuniversal_lcd_set_power(htcuniversal_lcd_dev, 4);
+	return 0;
+}
+
+static int htcuniversal_lcd_resume(struct platform_device * dev)
+{
+//	printk("htcuniversal_lcd_resume: called.\n");
+
+	/* */
+#if 1
+	LCCR4|=LCCR4_PCDDIV;
+#endif
+
+	htcuniversal_lcd_set_power(htcuniversal_lcd_dev, 0);
+	return 0;
+}
+
+static struct platform_driver htcuniversal_lcd_driver = {
+	.driver = {
+		.name     = "htcuniversal_lcd",
+	},
+	.probe    = htcuniversal_lcd_probe,
+	.remove   = htcuniversal_lcd_remove,
+	.suspend  = htcuniversal_lcd_suspend,
+	.resume   = htcuniversal_lcd_resume,
+};
+
+static int htcuniversal_lcd_init(void)
+{
+	if (!machine_is_htcuniversal())
+		return -ENODEV;
+
+	return platform_driver_register(&htcuniversal_lcd_driver);
+}
+
+static void htcuniversal_lcd_exit(void)
+{
+	lcd_device_unregister(htcuniversal_lcd_dev);
+	platform_driver_unregister(&htcuniversal_lcd_driver);
+}
+
+module_init(htcuniversal_lcd_init);
+module_exit(htcuniversal_lcd_exit);
+
+MODULE_AUTHOR("xanadux.org");
+MODULE_DESCRIPTION("Framebuffer driver for HTC Universal");
+MODULE_LICENSE("GPL");
+
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,167 @@
+
+/* Phone interface driver for Qualcomm MSM6250 on HTC Universal
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * 2005-04-21   Todd Blumer             Created.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/soc/asic3_base.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/serial.h>
+#include <asm/hardware/ipaq-asic3.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+#include "htcuniversal_phone.h"
+
+static void phone_reset(void)
+{
+	asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_RESET2, 0);
+
+	SET_HTCUNIVERSAL_GPIO(PHONE_RESET,0);
+	asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_BB_RESET1, 0);
+	mdelay(1);
+	asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_BB_RESET1, 1<<GPIOD_BB_RESET1);
+	mdelay(20);
+	SET_HTCUNIVERSAL_GPIO(PHONE_RESET,1);
+	mdelay(200);
+	asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_BB_RESET1, 0);
+}
+
+static void phone_off(void)
+{
+	asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_BB_RESET1, 1<<GPIOD_BB_RESET1);
+	mdelay(2000);
+	asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_BB_RESET1, 0);
+
+	asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_RESET2, 1<<GPIOB_BB_RESET2);
+	SET_HTCUNIVERSAL_GPIO(PHONE_OFF,0);
+}
+
+static void
+htcuniversal_phone_configure( int state )
+{
+	int tries;
+	unsigned short statusb;
+
+	printk( KERN_NOTICE "htcuniversal configure phone: %d\n", state );
+	switch (state) {
+
+	case PXA_UART_CFG_PRE_STARTUP:
+		break;
+
+	case PXA_UART_CFG_POST_STARTUP:
+		/* pre-serial-up hardware configuration */
+
+		SET_HTCUNIVERSAL_GPIO(PHONE_START,0);   /* "bootloader" */
+		SET_HTCUNIVERSAL_GPIO(PHONE_UNKNOWN,0); /* not used     */
+		SET_HTCUNIVERSAL_GPIO(PHONE_OFF,0);     /* PHONE_OFF    */
+
+		phone_reset();
+
+		SET_HTCUNIVERSAL_GPIO(PHONE_START,1); /* phone */
+
+		phone_reset();
+
+		asic3_set_gpio_dir_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_READY, 0);
+		asic3_set_gpio_dir_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_UNKNOWN3, 0);
+
+		/*
+		 */
+		tries = 0;
+		do {
+			mdelay(10);
+			statusb = asic3_get_gpio_status_b( &htcuniversal_asic3.dev );
+		} while ( (statusb & (1<<GPIOB_UMTS_DCD)) == 0 && tries++ < 200);
+
+		printk("UMTS_DCD tries=%d of 200\n",tries);
+
+		tries = 0;
+		do {
+			SET_HTCUNIVERSAL_GPIO(PHONE_OFF,1);
+			mdelay(10);
+			SET_HTCUNIVERSAL_GPIO(PHONE_OFF,0);
+			mdelay(20);
+			statusb = asic3_get_gpio_status_b( &htcuniversal_asic3.dev );
+		} while ( (statusb & (1<<GPIOB_BB_READY)) == 0 && tries++ < 200);
+
+		printk("BB_READY tries=%d of 200\n",tries);
+
+		break;
+
+	case PXA_UART_CFG_PRE_SHUTDOWN:
+
+			phone_off();
+
+		break;
+
+	default:
+		break;
+	}
+}
+
+
+static int
+htcuniversal_phone_probe( struct platform_device *dev )
+{
+	struct htcuniversal_phone_funcs *funcs = dev->dev.platform_data;
+
+	/* configure phone UART */
+	pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_PHONE_RXD_MD );
+	pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_PHONE_TXD_MD );
+	pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_PHONE_UART_CTS_MD );
+	pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_PHONE_UART_RTS_MD );
+
+	funcs->configure = htcuniversal_phone_configure;
+
+	return 0;
+}
+
+static int
+htcuniversal_phone_remove( struct platform_device *dev )
+{
+	struct htcuniversal_phone_funcs *funcs = dev->dev.platform_data;
+
+	funcs->configure = NULL;
+
+	asic3_set_gpio_dir_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_READY, 1<<GPIOB_BB_READY);
+	asic3_set_gpio_dir_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_UNKNOWN3, 1<<GPIOB_BB_UNKNOWN3);
+
+	return 0;
+}
+
+static struct platform_driver phone_driver = {
+	.driver   = {
+		.name     = "htcuniversal_phone",
+	},
+	.probe    = htcuniversal_phone_probe,
+	.remove   = htcuniversal_phone_remove,
+};
+
+static int __init
+htcuniversal_phone_init( void )
+{
+	printk(KERN_NOTICE "htcuniversal Phone Driver\n");
+	return platform_driver_register( &phone_driver );
+}
+
+static void __exit
+htcuniversal_phone_exit( void )
+{
+	platform_driver_unregister( &phone_driver );
+}
+
+module_init( htcuniversal_phone_init );
+module_exit( htcuniversal_phone_exit );
+
+MODULE_AUTHOR("Todd Blumer, SDG Systems, LLC");
+MODULE_DESCRIPTION("HTC Universal Phone Support Driver");
+MODULE_LICENSE("GPL");
+
+/* vim600: set noexpandtab sw=8 ts=8 :*/
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,16 @@
+/*
+ * Bluetooth support file for calling bluetooth configuration functions
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * 2005-06	Todd Blumer             Initial Revision
+ */
+
+#ifndef _HTCUNIVERSAL_PHONE_H
+#define _HTCUNIVERSAL_PHONE_H
+
+struct htcuniversal_phone_funcs {
+	void (*configure) ( int state );
+};
+
+#endif
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_pm.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_pm.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,69 @@
+/*
+ * MyPal 716 power management support for the original HTC IPL in DoC G3
+ *
+ * Use consistent with the GNU GPL is permitted, provided that this
+ * copyright notice is preserved in its entirety in all copies and
+ * derived works.
+ *
+ * Copyright (C) 2005 Pawel Kolodziejski
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/pm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa-pm_ll.h>
+
+#ifdef CONFIG_PM
+
+static u32 *addr_a0040000;
+static u32 *addr_a0040004;
+static u32 *addr_a0040008;
+static u32 *addr_a004000c;
+
+static u32 save_a0040000;
+static u32 save_a0040004;
+static u32 save_a0040008;
+static u32 save_a004000c;
+
+static void htcuniversal_pxa_ll_pm_suspend(unsigned long resume_addr)
+{
+	save_a0040000 = *addr_a0040000;
+	save_a0040004 = *addr_a0040004;
+	save_a0040008 = *addr_a0040008;
+	save_a004000c = *addr_a004000c;
+
+	/* jump to PSPR */
+	*addr_a0040000 = 0xe3a00101; // mov r0, #0x40000000
+	*addr_a0040004 = 0xe380060f; // orr r0, r0, #0x0f000000
+	*addr_a0040008 = 0xe3800008; // orr r0, r0, #8
+	*addr_a004000c = 0xe590f000; // ldr pc, [r0]
+}
+
+static void htcuniversal_pxa_ll_pm_resume(void)
+{
+	*addr_a0040000 = save_a0040000;
+	*addr_a0040004 = save_a0040004;
+	*addr_a0040008 = save_a0040008;
+	*addr_a004000c = save_a004000c;
+}
+
+static struct pxa_ll_pm_ops htcuniversal_ll_pm_ops = {
+	.suspend = htcuniversal_pxa_ll_pm_suspend,
+	.resume  = htcuniversal_pxa_ll_pm_resume,
+};
+
+void htcuniversal_ll_pm_init(void) {
+	addr_a0040000 = phys_to_virt(0xa0040000);
+	addr_a0040004 = phys_to_virt(0xa0040004);
+	addr_a0040008 = phys_to_virt(0xa0040008);
+	addr_a004000c = phys_to_virt(0xa004000c);
+
+	pxa_pm_set_ll_ops(&htcuniversal_ll_pm_ops);
+}
+#endif /* CONFIG_PM */
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_power2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_power2.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,97 @@
+/*
+ * pda_power driver for HTC Universal
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/pda_power.h>
+#include <linux/soc/asic3_base.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+static void charge_on(int flags)
+{
+        asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_CHARGE_EN, 0);
+}
+
+static int ac_on(void)
+{
+ return (GET_HTCUNIVERSAL_GPIO(POWER_DET) == 0);
+}
+
+static int usb_on(void)
+{
+ return (GET_HTCUNIVERSAL_GPIO(USB_DET) == 0);
+}
+
+static char *supplicants[] = {
+	"ds2760-battery.0", "backup-battery"
+};
+
+static struct pda_power_pdata power_pdata = {
+	.is_ac_online	= ac_on,
+	.is_usb_online	= usb_on,
+	.set_charge	= charge_on,
+	.supplied_to = supplicants,
+	.num_supplicants = ARRAY_SIZE(supplicants),
+};
+
+static struct resource power_resources[] = {
+	[0] = {
+		.name	= "ac",
+		.start	= HTCUNIVERSAL_IRQ(POWER_DET),
+		.end	= HTCUNIVERSAL_IRQ(POWER_DET),
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+	},
+	[1] = {
+		.name	= "usb",
+		.start	= HTCUNIVERSAL_IRQ(USB_DET),
+		.end	= HTCUNIVERSAL_IRQ(USB_DET),
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+	},
+};
+
+static void dev_release(struct device *dev)
+{
+	return;
+}
+
+static struct platform_device power_dev =
+{
+	.name		= "pda-power",
+	.id		= -1,
+	.resource	= power_resources,
+	.num_resources	= ARRAY_SIZE(power_resources),
+	.dev =
+	 {
+		.platform_data	= &power_pdata,
+		.release	= dev_release,
+	 },
+};
+
+static int htcuniversal_power_init(void)
+{
+ return platform_device_register(&power_dev);
+}
+
+static void htcuniversal_power_exit(void)
+{
+	platform_device_unregister(&power_dev);
+
+	return;
+}
+
+module_init(htcuniversal_power_init);
+module_exit(htcuniversal_power_exit);
+
+MODULE_DESCRIPTION("Power driver for HTC Universal");
+MODULE_LICENSE("GPL");
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ts2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ts2.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,490 @@
+/* Touch screen driver for the TI something-or-other
+ *
+ * Copyright © 2005 SDG Systems, LLC
+ *
+ * Based on code that was based on the SAMCOP driver.
+ *     Copyright © 2003, 2004 Compaq Computer Corporation.
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author:  Keith Packard <keith.packard@hp.com>
+ *          May 2003
+ *
+ * Updates:
+ *
+ * 2004-02-11   Michael Opdenacker      Renamed names from samcop to shamcop,
+ *                                      Goal:support HAMCOP and SAMCOP.
+ * 2004-02-14   Michael Opdenacker      Temporary fix for device id handling
+ *
+ * 2005-02-18   Aric Blumer             Converted  basic structure to support hx4700
+ *
+ * 2005-06-07   Aric Blumer             Added tssim device handling so we can
+ *                                      hook in the fbvncserver.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/mach/irq.h>
+#include <asm/io.h>
+
+/* remove me */
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+#include <asm/mach-types.h>
+
+#include <asm/hardware/ipaq-asic3.h>
+#include <linux/soc/asic3_base.h>
+
+
+#include "tsc2046_ts.h"
+
+enum touchscreen_state {
+    STATE_WAIT_FOR_TOUCH,   /* Waiting for a PEN interrupt */
+    STATE_SAMPLING          /* Actively sampling ADC */
+};
+
+struct touchscreen_data {
+    enum touchscreen_state state;
+    struct timer_list      timer;
+    int                    irq;
+    struct input_dev       *input;
+    /* */
+    int			port;
+    int			clock;
+    int			pwrbit_X;
+    int			pwrbit_Y;
+    int			(*pen_down)(void);
+};
+
+static unsigned long poll_sample_time   = 10; /* Sample every 10 milliseconds */
+
+static struct touchscreen_data *ts_data;
+
+static int irqblock;
+
+module_param(poll_sample_time, ulong, 0644);
+MODULE_PARM_DESC(poll_sample_time, "Poll sample time");
+
+static inline void
+report_touchpanel(struct touchscreen_data *ts, int pressure, int x, int y)
+{
+    input_report_abs(ts->input, ABS_PRESSURE, pressure);
+    input_report_abs(ts->input, ABS_X, x);
+    input_report_abs(ts->input, ABS_Y, y);
+    input_sync(ts->input);
+}
+
+static void start_read(struct touchscreen_data *touch);
+
+static irqreturn_t
+pen_isr(int irq, void *irq_desc)
+{
+    struct touchscreen_data *ts = ts_data;
+
+    if(irq == ts->irq /* && !irqblock */) {
+        irqblock = 1;
+
+        /*
+         * Disable the pen interrupt.  It's reenabled when the user lifts the
+         * pen.
+         */
+        disable_irq(ts->irq);
+
+        if (ts->state == STATE_WAIT_FOR_TOUCH) {
+            ts->state = STATE_SAMPLING;
+            start_read(ts);
+        } else {
+            /* Shouldn't happen */
+            printk(KERN_ERR "Unexpected ts interrupt\n");
+        }
+
+    }
+    return IRQ_HANDLED;
+}
+
+static void
+ssp_init(int port, int clock)
+{
+
+    pxa_set_cken(clock, 0);
+
+    pxa_gpio_mode(GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_CLK_MD);
+    pxa_gpio_mode(GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_FRM_MD);
+    pxa_gpio_mode(GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_DO_MD);
+    pxa_gpio_mode(GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_DI_MD);
+
+    SET_HTCUNIVERSAL_GPIO(SPI_FRM,1);
+
+    /* *** Set up the SPI Registers *** */
+    SSCR0_P(port) =
+          SSCR0_EDSS         /* Extended Data Size Select */
+        | SSCR0_SerClkDiv(7) /* Serial Clock Rate */
+                             /* Synchronous Serial Enable (Disable for now) */
+        | SSCR0_Motorola     /* Motorola SPI Interface */
+        | SSCR0_DataSize(8)  /* Data Size Select  (24-bit) */
+        ;
+    SSCR1_P(port) = 0;
+    SSPSP_P(port) = 0;
+
+    /* Clear the Status */
+    SSSR_P(port)  = SSSR_P(port) & 0x00fcfffc;
+
+    /* Now enable it */
+    SSCR0_P(port) =
+          SSCR0_EDSS         /* Extended Data Size Select */
+        | SSCR0_SerClkDiv(7) /* Serial Clock Rate */
+        | SSCR0_SSE          /* Synchronous Serial Enable */
+        | SSCR0_Motorola     /* Motorola SPI Interface */
+        | SSCR0_DataSize(8)  /* Data Size Select  (24-bit) */
+        ;
+
+    pxa_set_cken(clock, 1);
+}
+
+static void
+start_read(struct touchscreen_data *touch)
+{
+    unsigned long inc = (poll_sample_time * HZ) / 1000;
+    int i;
+
+    /* Write here to the serial port. We request X and Y only for now.
+     * Then we have to wait for poll_sample_time before we read out the serial
+     * port.  Then, when we read it out, we check to see if the pen is still
+     * down.  If so, then we issue another request here.
+     */
+#define TS_SAMPLES 7
+
+    /*
+     * We do four samples for each, and throw out the highest and lowest, then
+     * average the other two.
+     */
+
+    for(i = 0; i < TS_SAMPLES; i++) {
+        while(!(SSSR_P(touch->port) & SSSR_TNF))
+            ;
+        /* It's not full. Write the command for X */
+        SSDR_P(touch->port) = (TSC2046_SAMPLE_X|(touch->pwrbit_X))<<16;
+    }
+
+    for(i = 0; i < TS_SAMPLES; i++) {
+        while(!(SSSR_P(touch->port) & SSSR_TNF))
+            ;
+        /* It's not full. Write the command for Y */
+        SSDR_P(touch->port)  = (TSC2046_SAMPLE_Y|(touch->pwrbit_Y))<<16;
+    }
+
+    /*
+     * Enable the timer. We should get an interrupt, but we want keep a timer
+     * to ensure that we can detect missing data
+     */
+    mod_timer(&touch->timer, jiffies + inc);
+}
+
+static void
+ts_timer_callback(unsigned long data)
+{
+    struct touchscreen_data *ts = (struct touchscreen_data *)data;
+    int x, a[TS_SAMPLES], y;
+    static int oldx, oldy;
+    int ssrval;
+
+    /*
+     * Check here to see if there is anything in the SPI FIFO.  If so,
+     * return it if there has been a change.  If not, then we have a
+     * timeout.  Generate an erro somehow.
+     */
+    ssrval = SSSR_P(ts->port);
+
+    if(ssrval & SSSR_RNE) { /* Look at Rx Not Empty bit */
+        int number_of_entries_in_fifo;
+
+        /* The FIFO is not emtpy. Good! Now make sure there are at least two
+         * entries. (Should be two exactly.) */
+
+        number_of_entries_in_fifo = ((ssrval >> 12) & 0xf) + 1;
+
+        if(number_of_entries_in_fifo < TS_SAMPLES * 2) {
+            /* Not ready yet. Come back later. */
+            unsigned long inc = (poll_sample_time * HZ) / 1000;
+            mod_timer(&ts->timer, jiffies + inc);
+            return;
+        }
+
+        if(number_of_entries_in_fifo == TS_SAMPLES * 2) {
+            int i, j;
+
+            for(i = 0; i < TS_SAMPLES; i++) {
+                a[i] = SSDR_P(ts->port);
+            }
+            /* Sort them (bubble) */
+            for(j = TS_SAMPLES - 1; j > 0; j--) {
+                for(i = 0; i < j; i++) {
+                    if(a[i] > a[i + 1]) {
+                        int tmp;
+                        tmp    = a[i+1];
+                        a[i+1] = a[i];
+                        a[i]   = tmp;
+                    }
+                }
+            }
+
+            /* Take the average of the middle two */
+            /* x = (a[TS_SAMPLES/2 - 1] + a[TS_SAMPLES/2] + a[TS_SAMPLES/2+1] + a[TS_SAMPLES/2+2]) >> 2; */
+            x = a[TS_SAMPLES/2];
+
+            for(i = 0; i < TS_SAMPLES; i++) {
+                a[i] = SSDR_P(ts->port);
+            }
+            /* Sort them (bubble) */
+            for(j = TS_SAMPLES - 1; j > 0; j--) {
+                for(i = 0; i < j; i++) {
+                    if(a[i] > a[i + 1]) {
+                        int tmp;
+                        tmp    = a[i+1];
+                        a[i+1] = a[i];
+                        a[i]   = tmp;
+                    }
+                }
+            }
+
+
+            /* Take the average of the middle two */
+            /* y = (a[TS_SAMPLES/2 - 1] + a[TS_SAMPLES/2] + a[TS_SAMPLES/2+1] + a[TS_SAMPLES/2+2]) >> 2; */
+            y = a[TS_SAMPLES/2];
+        } else {
+            /* We have an error! Too many entries. */
+            printk(KERN_ERR "TS: Expected %d entries. Got %d\n", TS_SAMPLES*2, number_of_entries_in_fifo);
+            /* Try to clear the FIFO */
+            while(number_of_entries_in_fifo--) {
+                (void)SSDR_P(ts->port);
+            }
+
+            if (ts->pen_down())
+                start_read(ts);
+
+            return;
+        }
+    } else {
+        /* Not ready yet. Come back later. */
+        unsigned long inc = (poll_sample_time * HZ) / 1000;
+        mod_timer(&ts->timer, jiffies + inc);
+        return;
+    }
+
+    /*
+     * Now we check to see if the pen is still down.  If it is, then call
+     * start_read().
+     */
+    if (ts->pen_down())
+    {
+        /* Still down */
+        if(oldx != x || oldy != y) {
+            oldx = x;
+            oldy = y;
+            report_touchpanel(ts, 1, x, y);
+        }
+        start_read(ts);
+    } else {
+        /* Up */
+        report_touchpanel(ts, 0, 0, 0);
+        irqblock = 0;
+        ts->state = STATE_WAIT_FOR_TOUCH;
+        /* Re-enable pen down interrupt */
+        enable_irq(ts->irq);
+    }
+}
+
+static int pen_down(void)
+{
+ return ( asic3_get_gpio_status_a( &htcuniversal_asic3.dev ) & (1<<GPIOA_TOUCHSCREEN_N)) == 0 ;
+}
+
+static int
+ts_probe (struct platform_device *dev)
+{
+    int retval;
+    struct touchscreen_data *ts;
+    struct tsc2046_mach_info *mach = dev->dev.platform_data;
+
+    printk("htcuniversal: ts_probe\n");
+
+    ts = ts_data = kmalloc (sizeof (*ts), GFP_KERNEL);
+    if (ts == NULL) {
+	printk( KERN_NOTICE "htcuniversal_ts: unable to allocate memory\n" );
+	return -ENOMEM;
+    }
+    memset (ts, 0, sizeof (*ts));
+
+    ts->input = input_allocate_device();
+    if (ts->input == NULL) {
+	printk( KERN_NOTICE "htcuniversal_ts: unable to allocation touchscreen input\n" );
+	kfree(ts);
+	return -ENOMEM;
+    }
+    ts->input->evbit[0]             = BIT(EV_ABS);
+    ts->input->absbit[0]            = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+    ts->input->absmin[ABS_X]        = 0;
+    ts->input->absmax[ABS_X]        = 32767;
+    ts->input->absmin[ABS_Y]        = 0;
+    ts->input->absmax[ABS_Y]        = 32767;
+    ts->input->absmin[ABS_PRESSURE] = 0;
+    ts->input->absmax[ABS_PRESSURE] = 1;
+
+    ts->input->name = "htcuniversal_ts";
+    ts->input->phys =  "touchscreen/htcuniversal_ts";
+    ts->input->private = ts;
+
+    input_register_device(ts->input);
+
+    ts->timer.function = ts_timer_callback;
+    ts->timer.data = (unsigned long)ts;
+    ts->state = STATE_WAIT_FOR_TOUCH;
+    init_timer (&ts->timer);
+
+    platform_set_drvdata(dev, ts);
+
+    ts->port=-1;
+
+    if (mach) {
+        ts->port = mach->port;
+        ts->clock = mach->clock;
+        ts->pwrbit_X = mach->pwrbit_X;
+        ts->pwrbit_Y = mach->pwrbit_Y;
+
+        /* static irq */
+        if (mach->irq)
+         ts->irq = mach->irq;
+
+        if (mach->pen_down)
+         ts->pen_down=mach->pen_down;
+    }
+
+    if (ts->port == -1)
+    {
+     printk("tsc2046: your device is not supported by this driver\n");
+     return -ENODEV;
+    }
+
+    /* *** Initialize the SSP interface *** */
+    ssp_init(ts->port, ts->clock);
+
+    while(!(SSSR_P(ts->port) & SSSR_TNF))
+        ;
+    SSDR_P(ts->port) = (TSC2046_SAMPLE_X|(ts->pwrbit_X))<<16;
+
+    for(retval = 0; retval < 100; retval++) {
+        if(SSSR_P(ts->port) & SSSR_RNE) {
+            while(SSSR_P(ts->port) & SSSR_RNE) {
+                (void)SSDR_P(ts->port);
+            }
+            break;
+        }
+        mdelay(1);
+    }
+
+    if (machine_is_htcuniversal() )
+    {
+     ts->irq = asic3_irq_base( &htcuniversal_asic3.dev ) + ASIC3_GPIOA_IRQ_BASE + GPIOA_TOUCHSCREEN_N;
+     ts->pen_down=pen_down;
+    }
+
+    retval = request_irq(ts->irq, pen_isr, IRQF_DISABLED, "tsc2046_ts", ts);
+    if(retval) {
+        printk("Unable to get interrupt\n");
+        input_unregister_device (ts->input);
+        return -ENODEV;
+    }
+    set_irq_type(ts->irq, IRQ_TYPE_EDGE_FALLING);
+
+    return 0;
+}
+
+static int
+ts_remove (struct platform_device *dev)
+{
+    struct touchscreen_data *ts = platform_get_drvdata(dev);
+
+    input_unregister_device (ts->input);
+    del_timer_sync (&ts->timer);
+    free_irq (ts->irq, ts);
+    pxa_set_cken(ts->clock, 0);
+
+    kfree(ts);
+    return 0;
+}
+
+static int
+ts_suspend (struct platform_device *dev, pm_message_t state)
+{
+    struct touchscreen_data *ts = platform_get_drvdata(dev);
+
+    disable_irq(ts->irq);
+
+    printk("htcuniversal_ts2_suspend: called.\n");
+    return 0;
+}
+
+static int
+ts_resume (struct platform_device *dev)
+{
+    struct touchscreen_data *ts = platform_get_drvdata(dev);
+
+    ts->state = STATE_WAIT_FOR_TOUCH;
+    ssp_init(ts->port, ts->clock);
+    enable_irq(ts->irq);
+
+    printk("htcuniversal_ts2_resume: called.\n");
+    return 0;
+}
+
+static struct platform_driver ts_driver = {
+    .probe    = ts_probe,
+    .remove   = ts_remove,
+    .suspend  = ts_suspend,
+    .resume   = ts_resume,
+    .driver = {
+		.name = "htcuniversal_ts",
+	},
+};
+
+
+static int
+ts_module_init (void)
+{
+    printk(KERN_NOTICE "HTC Universal Touch Screen Driver\n");
+
+    return platform_driver_register(&ts_driver);
+}
+
+static void
+ts_module_cleanup (void)
+{
+    platform_driver_unregister (&ts_driver);
+}
+
+module_init(ts_module_init);
+module_exit(ts_module_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Aric Blumer, SDG Systems, LLC");
+MODULE_DESCRIPTION("HTC Universal Touch Screen Driver");
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_udc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_udc.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,71 @@
+
+/*
+ *
+ * htcuniversal_udc.c:
+ * htcuniversal specific code for the pxa27x usb device controller.
+ *
+ * Use consistent with the GNU GPL is permitted.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/udc.h>
+#include <linux/soc/asic3_base.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+static void htcuniversal_udc_command(int cmd)
+{
+	switch (cmd) {
+	case PXA2XX_UDC_CMD_DISCONNECT:
+		asic3_set_gpio_out_b(&htcuniversal_asic3.dev,
+					   1<<GPIOB_USB_PUEN, 0);
+//		SET_HTCUNIVERSAL_GPIO(USB_PUEN,0);
+		break;
+	case PXA2XX_UDC_CMD_CONNECT:
+		asic3_set_gpio_out_b(&htcuniversal_asic3.dev,
+					   1<<GPIOB_USB_PUEN,  1<<GPIOB_USB_PUEN);
+//		SET_HTCUNIVERSAL_GPIO(USB_PUEN,1);
+		break;
+	default:
+		printk("_udc_control: unknown command!\n");
+		break;
+	}
+}
+
+static int htcuniversal_udc_is_connected(void)
+{
+	return (GET_HTCUNIVERSAL_GPIO(USB_DET) != 0);
+}
+
+static struct pxa2xx_udc_mach_info htcuniversal_udc_info __initdata = {
+	.udc_is_connected = htcuniversal_udc_is_connected,
+	.udc_command      = htcuniversal_udc_command,
+};
+
+static int htcuniversal_udc_probe(struct platform_device * dev)
+{
+	asic3_set_gpio_dir_b(&htcuniversal_asic3.dev, 1<<GPIOB_USB_PUEN, 1<<GPIOB_USB_PUEN);
+
+	pxa_set_udc_info(&htcuniversal_udc_info);
+	return 0;
+}
+
+static struct platform_driver htcuniversal_udc_driver = {
+	.driver	  = {
+		.name     = "htcuniversal_udc",
+	},
+	.probe    = htcuniversal_udc_probe,
+};
+
+static int __init htcuniversal_udc_init(void)
+{
+	return platform_driver_register(&htcuniversal_udc_driver);
+}
+
+module_init(htcuniversal_udc_init);
+MODULE_LICENSE("GPL");
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/tsc2046_ts.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/tsc2046_ts.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,20 @@
+/*
+ * temporary TSC2046 touchscreen hack
+ */
+
+#ifndef _TSC2046_TS_H
+#define _TSC2046_TS_H
+
+struct tsc2046_mach_info {
+    int port;
+    int clock;
+    int pwrbit_X;
+    int pwrbit_Y;
+    int irq;
+    int (*pen_down)(void);
+};
+
+#define TSC2046_SAMPLE_X 0xd0
+#define TSC2046_SAMPLE_Y 0x90
+
+#endif
Index: linux-2.6.24/arch/arm/mach-pxa/Kconfig
===================================================================
--- linux-2.6.24.orig/arch/arm/mach-pxa/Kconfig	2008-03-10 16:08:01.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/Kconfig	2008-03-10 16:09:23.000000000 +0000
@@ -92,6 +92,14 @@
 	bool "Sharp PXA270 models (SL-Cxx00)"
 	select PXA27x
 
+config MACH_HTCUNIVERSAL
+	bool "HTC Universal"
+	select PXA27x
+	help
+	  Say Y here if you intend to run this kernel on a
+	  HTC Universal. Currently there is only basic support
+	  for this PDA.
+
 endchoice
 
 endif
@@ -111,6 +119,86 @@
 
 endif
 
+if MACH_HTCUNIVERSAL
+
+menu "HTC Universal support"
+
+config HTCUNIVERSAL_CORE
+        tristate "HTC Universal core"
+        depends on MACH_HTCUNIVERSAL
+        help
+          This selection enables HTC Universal core support.
+
+config HTCUNIVERSAL_UDC
+        bool "USB Device Controller support"
+        depends on MACH_HTCUNIVERSAL && HTC_ASIC3 && USB_PXA27X
+        help
+          Enables HTC Universal specific USB detection
+
+config HTCUNIVERSAL_POWER
+        tristate "HTC Universal power"
+        depends on MACH_HTCUNIVERSAL && HTC_ASIC3
+        help
+          This selection enables HTC Universal power monitoring
+	            hardware support (through ASIC3).
+
+config HTCUNIVERSAL_BACKLIGHT
+	bool "HTC Universal Backlight"
+	depends on MACH_HTCUNIVERSAL && HTC_ASIC3 && BACKLIGHT_CLASS_DEVICE
+	help
+	  This driver provides support for changing power and brightness
+	  on HTC Universal LCD backlight.
+
+config HTCUNIVERSAL_LCD
+	tristate "HTC Universal LCD"
+	depends on MACH_HTCUNIVERSAL && HTC_ASIC3 && LCD_CLASS_DEVICE
+	help
+	  This driver provides support for changing power and brightness
+	  on HTC Universal LCD display.
+
+config HTCUNIVERSAL_TS2
+	tristate "HTC Universal Touchscreen (old)"
+	depends on MACH_HTCUNIVERSAL && HTC_ASIC3
+	help
+	  Enable support for the HTC Universal Touchscreen Panel.
+
+config HTCUNIVERSAL_BUTTONS
+        tristate "HTC Universal buttons support"
+        depends on MACH_HTCUNIVERSAL && HTC_ASIC3
+
+config HTCUNIVERSAL_BLUETOOTH
+	tristate "HTC Universal Bluetooth"
+	depends on MACH_HTCUNIVERSAL && HTCUNIVERSAL_CORE && HTC_ASIC3
+	help
+	  Enables support for the TI BRF6150 Bluetooth Module
+	  in the HTC Universal.
+
+config HTCUNIVERSAL_ASIC3_LEDS
+	tristate "HTC Universal ASIC3 LED support"
+	select LEDS_ASIC3
+	depends on MACH_HTCUNIVERSAL && HTCUNIVERSAL_CORE && HTC_ASIC3
+	---help---
+	Support for right (colors red+green+(amber)) and left (green+blue) led
+	Off/on hook keys LED backlight
+	Keyboard backlight
+	Vibra
+	Flashlight
+
+config HTCUNIVERSAL_PHONE
+	tristate "HTC Universal Phone"
+	depends on MACH_HTCUNIVERSAL && HTCUNIVERSAL_CORE && HTC_ASIC3
+	help
+	  Enables support for the Qualcomm MSM6520 Phone Module
+	  in the HTC Universal.
+
+config HTCUNIVERSAL_AK4641
+	depends on SND && I2C
+	tristate "AK4641 chipset support"
+
+endmenu
+
+endif
+
 endmenu
 
 config MACH_POODLE
@@ -196,4 +284,3 @@
 	depends on (PXA25x || PXA27x) && INPUT
 
 endif
-
Index: linux-2.6.24/arch/arm/mach-pxa/Makefile
===================================================================
--- linux-2.6.24.orig/arch/arm/mach-pxa/Makefile	2008-03-10 16:08:01.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/Makefile	2008-03-10 16:09:23.000000000 +0000
@@ -23,6 +23,7 @@
 obj-$(CONFIG_MACH_TOSA)		+= tosa.o
 obj-$(CONFIG_MACH_EM_X270)	+= em-x270.o
 obj-$(CONFIG_MACH_HX2750)	+= hx2750.o hx2750_test.o
+obj-$(CONFIG_MACH_HTCUNIVERSAL) += htcuniversal/
 
 ifeq ($(CONFIG_MACH_ZYLONITE),y)
   obj-y				+= zylonite.o
Index: linux-2.6.24/drivers/leds/Kconfig
===================================================================
--- linux-2.6.24.orig/drivers/leds/Kconfig	2008-01-24 22:58:37.000000000 +0000
+++ linux-2.6.24/drivers/leds/Kconfig	2008-03-10 16:09:23.000000000 +0000
@@ -114,6 +114,13 @@
 	help
 	  This option enables support for the CM-X270 LEDs.
 
+config LEDS_ASIC3
+	tristate "LED Support for the HTC ASIC3 chip"
+	depends on LEDS_CLASS && HTC_ASIC3
+	help
+	  This option enables support for the LEDs connected to the
+	  HTC ASIC3 chip.
+
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
Index: linux-2.6.24/drivers/leds/leds-asic3.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/drivers/leds/leds-asic3.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,189 @@
+/*
+ * LEDs support for HTC ASIC3 devices.
+ *
+ * Copyright (c) 2006  Anton Vorontsov <cbou@mail.ru>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+#include <asm/hardware/ipaq-asic3.h>
+#include <linux/soc/asic3_base.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/asic3_leds.h>
+
+#ifdef DEBUG
+#define dbg(msg, ...) printk(msg, __VA_ARGS__)
+#else
+#define dbg(msg, ...)
+#endif
+
+static
+void asic3_leds_set(struct led_classdev *led_cdev, enum led_brightness b)
+{
+	struct asic3_led *led = container_of(led_cdev, struct asic3_led,
+	                                     led_cdev);
+	struct asic3_leds_machinfo *machinfo = led->machinfo;
+	struct device *asic3_dev = &machinfo->asic3_pdev->dev;
+
+	dbg("%s:%s %d(%d)-%s %d\n", __FILE__, __FUNCTION__, led->hw_num,
+	    led->gpio_num, led->led_cdev.name, b);
+
+	if (led->hw_num == -1) {
+		asic3_gpio_set_value(asic3_dev, led->gpio_num, b);
+		return;
+	}
+
+	if (b == LED_OFF) {
+		asic3_set_led(asic3_dev, led->hw_num, 0, 16, 6);
+		asic3_set_gpio_out_c(asic3_dev, led->hw_num, 0);
+	}
+	else {
+		asic3_set_gpio_out_c(asic3_dev, led->hw_num, led->hw_num);
+		#ifdef CONFIG_LEDS_TRIGGER_HWTIMER
+		if (led_cdev->trigger && led_cdev->trigger->is_led_supported &&
+			       (led_cdev->trigger->is_led_supported(led_cdev) &
+			        LED_SUPPORTS_HWTIMER)) {
+			struct hwtimer_data *td = led_cdev->trigger_data;
+			if (!td) return;
+			asic3_set_led(asic3_dev, led->hw_num, td->delay_on/8,
+					   (td->delay_on + td->delay_off)/8, 6);
+		}
+		else
+		#endif
+		asic3_set_led(asic3_dev, led->hw_num, 16, 16, 6);
+	}
+
+	return;
+}
+
+static
+int asic3_leds_probe(struct platform_device *pdev)
+{
+	struct asic3_leds_machinfo *machinfo = pdev->dev.platform_data;
+	struct asic3_led *leds = machinfo->leds;
+	int ret, i = 0;
+
+	dbg("%s:%s\n", __FILE__, __FUNCTION__);
+
+	// Turn on clocks early, for the case if trigger would enable
+	// led immediately after led_classdev_register().
+	asic3_set_clock_cdex(&machinfo->asic3_pdev->dev,
+		CLOCK_CDEX_LED0 | CLOCK_CDEX_LED1 | CLOCK_CDEX_LED2,
+		CLOCK_CDEX_LED0 | CLOCK_CDEX_LED1 | CLOCK_CDEX_LED2);
+
+	for (i = 0; i < machinfo->num_leds; i++) {
+		leds[i].machinfo = machinfo;
+		leds[i].led_cdev.brightness_set = asic3_leds_set;
+		ret = led_classdev_register(&pdev->dev, &leds[i].led_cdev);
+		if (ret) {
+			printk(KERN_ERR "Error: can't register %s led\n",
+			       leds[i].led_cdev.name);
+			goto out_err;
+		}
+	}
+
+	return 0;
+
+out_err:
+	while (--i >= 0) led_classdev_unregister(&leds[i].led_cdev);
+
+	asic3_set_clock_cdex(&machinfo->asic3_pdev->dev,
+		CLOCK_CDEX_LED0 | CLOCK_CDEX_LED1 | CLOCK_CDEX_LED2,
+		0               | 0               | 0);
+
+	return ret;
+}
+
+static
+int asic3_leds_remove(struct platform_device *pdev)
+{
+	struct asic3_leds_machinfo *machinfo = pdev->dev.platform_data;
+	struct asic3_led *leds = machinfo->leds;
+	int i = 0;
+
+	dbg("%s:%s\n", __FILE__, __FUNCTION__);
+
+	for (i = 0; i < machinfo->num_leds; i++)
+		led_classdev_unregister(&leds[i].led_cdev);
+
+	asic3_set_clock_cdex(&machinfo->asic3_pdev->dev,
+		CLOCK_CDEX_LED0 | CLOCK_CDEX_LED1 | CLOCK_CDEX_LED2,
+		0               | 0               | 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static
+int asic3_leds_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct asic3_leds_machinfo *machinfo = pdev->dev.platform_data;
+	struct asic3_led *leds = machinfo->leds;
+	int i = 0;
+
+	dbg("%s:%s\n", __FILE__, __FUNCTION__);
+
+	for (i = 0; i < machinfo->num_leds; i++)
+		led_classdev_suspend(&leds[i].led_cdev);
+
+	return 0;
+}
+
+static
+int asic3_leds_resume(struct platform_device *pdev)
+{
+	struct asic3_leds_machinfo *machinfo = pdev->dev.platform_data;
+	struct asic3_led *leds = machinfo->leds;
+	int i = 0;
+
+	dbg("%s:%s\n", __FILE__, __FUNCTION__);
+
+	for (i = 0; i < machinfo->num_leds; i++)
+		led_classdev_resume(&leds[i].led_cdev);
+
+	return 0;
+}
+
+#endif
+
+static
+struct platform_driver asic3_leds_driver = {
+	.probe = asic3_leds_probe,
+	.remove = asic3_leds_remove,
+#ifdef CONFIG_PM
+	.suspend = asic3_leds_suspend,
+	.resume = asic3_leds_resume,
+#endif
+	.driver = {
+		.name = "asic3-leds",
+	},
+};
+
+int asic3_leds_register(void)
+{
+	dbg("%s:%s\n", __FILE__, __FUNCTION__);
+	return platform_driver_register(&asic3_leds_driver);
+}
+
+void asic3_leds_unregister(void)
+{
+	platform_driver_unregister(&asic3_leds_driver);
+	return;
+}
+
+EXPORT_SYMBOL_GPL(asic3_leds_register);
+EXPORT_SYMBOL_GPL(asic3_leds_unregister);
+
+MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
+MODULE_DESCRIPTION("HTC ASIC3 LEDs driver");
+MODULE_LICENSE("GPL");
Index: linux-2.6.24/drivers/mfd/Kconfig
===================================================================
--- linux-2.6.24.orig/drivers/mfd/Kconfig	2008-03-10 16:07:51.000000000 +0000
+++ linux-2.6.24/drivers/mfd/Kconfig	2008-03-10 16:09:23.000000000 +0000
@@ -21,6 +21,16 @@
 	help
 	  Support for TI TSC2101 Touchscreen and Audio Codec
 
+config HTC_ASIC3
+        tristate "HTC ASIC3 (iPAQ h1900/h3900/h4000/hx4700/rx3000) support"
+
+config HTC_ASIC3_DS1WM
+       bool "Support HTC ASIC3 builtin DS1WM block"
+       help
+           Choose Y here if you want to include support for ASIC3's builtin
+           W1 controller. Some devices do not use it, and yet other have
+           separate DS1WM controller. For them, choose N.
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
Index: linux-2.6.24/drivers/mfd/Makefile
===================================================================
--- linux-2.6.24.orig/drivers/mfd/Makefile	2008-03-10 16:07:51.000000000 +0000
+++ linux-2.6.24/drivers/mfd/Makefile	2008-03-10 16:09:23.000000000 +0000
@@ -2,6 +2,8 @@
 # Makefile for multifunction miscellaneous devices
 #
 
+obj-$(CONFIG_HTC_ASIC3)         += asic3_base.o soc-core.o
+
 obj-$(CONFIG_MFD_SM501)		+= sm501.o
 
 obj-$(CONFIG_MCP)		+= mcp-core.o
Index: linux-2.6.24/drivers/mfd/asic3_base.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/drivers/mfd/asic3_base.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,1208 @@
+/*
+ * Driver interface to HTC "ASIC3"
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ * Copyright 2004-2005 Phil Blundell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author:  Andrew Christian
+ *          <Andrew.Christian@compaq.com>
+ *          October 2001
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/ds1wm.h>
+#include <asm/arch/clock.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/hardware/ipaq-asic3.h>
+#include <linux/soc/asic3_base.h>
+#include <linux/soc/tmio_mmc.h>
+#include "soc-core.h"
+
+
+struct asic3_data {
+	void *mapping;
+	unsigned int bus_shift;
+	int irq_base;
+	int irq_nr;
+
+	u16 irq_bothedge[4];
+	struct device *dev;
+
+	struct platform_device *mmc_dev;
+};
+
+static DEFINE_SPINLOCK(asic3_gpio_lock);
+
+static int asic3_remove(struct platform_device *dev);
+
+static inline unsigned long asic3_address(struct device *dev,
+					  unsigned int reg)
+{
+	struct asic3_data *adata;
+
+	adata = (struct asic3_data *)dev->driver_data;
+
+	return (unsigned long)adata->mapping + (reg >> (2 - adata->bus_shift));
+}
+
+void asic3_write_register(struct device *dev, unsigned int reg, u32 value)
+{
+	__raw_writew(value, asic3_address(dev, reg));
+}
+EXPORT_SYMBOL(asic3_write_register);
+
+u32 asic3_read_register(struct device *dev, unsigned int reg)
+{
+	return __raw_readw(asic3_address(dev, reg));
+}
+EXPORT_SYMBOL(asic3_read_register);
+
+static inline void __asic3_write_register(struct asic3_data *asic,
+					  unsigned int reg, u32 value)
+{
+	__raw_writew(value, (unsigned long)asic->mapping
+			    + (reg >> (2 - asic->bus_shift)));
+}
+
+static inline u32 __asic3_read_register(struct asic3_data *asic,
+					unsigned int reg)
+{
+	return __raw_readw((unsigned long)asic->mapping
+			   + (reg >> (2 - asic->bus_shift)));
+}
+
+#define ASIC3_GPIO_FN(get_fn_name, set_fn_name, REG)			\
+u32 get_fn_name(struct device *dev)					\
+{                                                                       \
+	return asic3_read_register(dev, REG);				\
+}                                                                       \
+EXPORT_SYMBOL(get_fn_name);						\
+									\
+void set_fn_name(struct device *dev, u32 bits, u32 val)			\
+{                                                                       \
+	unsigned long flags;						\
+									\
+	spin_lock_irqsave(&asic3_gpio_lock, flags);			\
+	val |= (asic3_read_register(dev, REG) & ~bits);			\
+	asic3_write_register(dev, REG, val);				\
+	spin_unlock_irqrestore(&asic3_gpio_lock, flags);		\
+}                                                                       \
+EXPORT_SYMBOL(set_fn_name);
+
+#define ASIC3_GPIO_REGISTER(ACTION, action, fn, FN)			\
+	ASIC3_GPIO_FN(asic3_get_gpio_ ## action ## _ ## fn ,		\
+		       asic3_set_gpio_ ## action ## _ ## fn ,		\
+		       _IPAQ_ASIC3_GPIO_ ## FN ## _Base 		\
+		       + _IPAQ_ASIC3_GPIO_ ## ACTION )
+
+#define ASIC3_GPIO_FUNCTIONS(fn, FN)					\
+	ASIC3_GPIO_REGISTER(Direction, dir, fn, FN)			\
+	ASIC3_GPIO_REGISTER(Out, out, fn, FN)				\
+	ASIC3_GPIO_REGISTER(SleepMask, sleepmask, fn, FN)		\
+	ASIC3_GPIO_REGISTER(SleepOut, sleepout, fn, FN)		\
+	ASIC3_GPIO_REGISTER(BattFaultOut, battfaultout, fn, FN)	\
+	ASIC3_GPIO_REGISTER(AltFunction, alt_fn, fn, FN)		\
+	ASIC3_GPIO_REGISTER(SleepConf, sleepconf, fn, FN)		\
+	ASIC3_GPIO_REGISTER(Status, status, fn, FN)
+
+#if 0
+	ASIC3_GPIO_REGISTER(Mask, mask, fn, FN)
+	ASIC3_GPIO_REGISTER(TriggerType, trigtype, fn, FN)
+	ASIC3_GPIO_REGISTER(EdgeTrigger, rising, fn, FN)
+	ASIC3_GPIO_REGISTER(LevelTrigger, triglevel, fn, FN)
+	ASIC3_GPIO_REGISTER(IntStatus, intstatus, fn, FN)
+#endif
+
+ASIC3_GPIO_FUNCTIONS(a, A)
+ASIC3_GPIO_FUNCTIONS(b, B)
+ASIC3_GPIO_FUNCTIONS(c, C)
+ASIC3_GPIO_FUNCTIONS(d, D)
+
+int asic3_gpio_get_value(struct device *dev, unsigned gpio)
+{
+	u32 mask = ASIC3_GPIO_bit(gpio);
+	printk("%s(%d)\n", __FUNCTION__, gpio);
+	switch (gpio >> 4) {
+	case _IPAQ_ASIC3_GPIO_BANK_A:
+		return asic3_get_gpio_status_a(dev) & mask;
+	case _IPAQ_ASIC3_GPIO_BANK_B:
+		return asic3_get_gpio_status_b(dev) & mask;
+	case _IPAQ_ASIC3_GPIO_BANK_C:
+		return asic3_get_gpio_status_c(dev) & mask;
+	case _IPAQ_ASIC3_GPIO_BANK_D:
+		return asic3_get_gpio_status_d(dev) & mask;
+	}
+
+	printk(KERN_ERR "%s: invalid GPIO value 0x%x", __FUNCTION__, gpio);
+	return 0;
+}
+EXPORT_SYMBOL(asic3_gpio_get_value);
+
+void asic3_gpio_set_value(struct device *dev, unsigned gpio, int val)
+{
+	u32 mask = ASIC3_GPIO_bit(gpio);
+	u32 bitval = 0;
+	if (val)  bitval = mask;
+	printk("%s(%d, %d)\n", __FUNCTION__, gpio, val);
+
+	switch (gpio >> 4) {
+	case _IPAQ_ASIC3_GPIO_BANK_A:
+		asic3_set_gpio_out_a(dev, mask, bitval);
+		return;
+	case _IPAQ_ASIC3_GPIO_BANK_B:
+		asic3_set_gpio_out_b(dev, mask, bitval);
+		return;
+	case _IPAQ_ASIC3_GPIO_BANK_C:
+		asic3_set_gpio_out_c(dev, mask, bitval);
+		return;
+	case _IPAQ_ASIC3_GPIO_BANK_D:
+		asic3_set_gpio_out_d(dev, mask, bitval);
+		return;
+	}
+
+	printk(KERN_ERR "%s: invalid GPIO value 0x%x", __FUNCTION__, gpio);
+}
+EXPORT_SYMBOL(asic3_gpio_set_value);
+
+int asic3_irq_base(struct device *dev)
+{
+	struct asic3_data *asic = dev->driver_data;
+
+	return asic->irq_base;
+}
+EXPORT_SYMBOL(asic3_irq_base);
+
+static int asic3_gpio_to_irq(struct device *dev, unsigned gpio)
+{
+	struct asic3_data *asic = dev->driver_data;
+	printk("%s(%d)\n", __FUNCTION__, gpio);
+
+	return asic->irq_base + gpio;
+}
+
+void asic3_set_led(struct device *dev, int led_num, int duty_time,
+		   int cycle_time, int timebase)
+{
+	struct asic3_data *asic = dev->driver_data;
+	unsigned int led_base;
+
+	/* it's a macro thing: see #define _IPAQ_ASIC_LED_0_Base for why you
+	 * can't substitute led_num in the macros below...
+	 */
+
+	switch (led_num) {
+	case 0:
+		led_base = _IPAQ_ASIC3_LED_0_Base;
+		break;
+	case 1:
+		led_base = _IPAQ_ASIC3_LED_1_Base;
+		break;
+	case 2:
+		led_base = _IPAQ_ASIC3_LED_2_Base;
+		break;
+	default:
+		printk(KERN_ERR "%s: invalid led number %d", __FUNCTION__,
+		       led_num);
+		return;
+	}
+
+	__asic3_write_register(asic, led_base + _IPAQ_ASIC3_LED_TimeBase,
+			       timebase | LED_EN);
+	__asic3_write_register(asic, led_base + _IPAQ_ASIC3_LED_PeriodTime,
+			       cycle_time);
+	__asic3_write_register(asic, led_base + _IPAQ_ASIC3_LED_DutyTime,
+			       0);
+	udelay(20);     /* asic voodoo - possibly need a whole duty cycle? */
+	__asic3_write_register(asic, led_base + _IPAQ_ASIC3_LED_DutyTime,
+			       duty_time);
+}
+EXPORT_SYMBOL(asic3_set_led);
+
+void asic3_set_clock_sel(struct device *dev, u32 bits, u32 val)
+{
+	struct asic3_data *asic = dev->driver_data;
+	unsigned long flags;
+	u32 v;
+
+	spin_lock_irqsave(&asic3_gpio_lock, flags);
+	v = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, SEL));
+	v = (v & ~bits) | val;
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, SEL), v);
+	spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_clock_sel);
+
+void asic3_set_clock_cdex(struct device *dev, u32 bits, u32 val)
+{
+	struct asic3_data *asic = dev->driver_data;
+	unsigned long flags;
+	u32 v;
+
+	spin_lock_irqsave(&asic3_gpio_lock, flags);
+	v = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX));
+	v = (v & ~bits) | val;
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX), v);
+	spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_clock_cdex);
+
+static void asic3_clock_cdex_enable(struct clk *clk)
+{
+	struct asic3_data *asic = (struct asic3_data *)clk->parent->ctrlbit;
+	unsigned long flags, val;
+
+	local_irq_save(flags);
+
+	val = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX));
+	val |= clk->ctrlbit;
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX), val);
+
+	local_irq_restore(flags);
+}
+
+static void asic3_clock_cdex_disable(struct clk *clk)
+{
+	struct asic3_data *asic = (struct asic3_data *)clk->parent->ctrlbit;
+	unsigned long flags, val;
+
+	local_irq_save(flags);
+
+	val = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX));
+	val &= ~clk->ctrlbit;
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX), val);
+
+	local_irq_restore(flags);
+}
+
+/* base clocks */
+
+static struct clk clk_g = {
+	.name		= "gclk",
+	.rate		= 0,
+	.parent		= NULL,
+};
+
+/* clock definitions */
+
+static struct clk asic3_clocks[] = {
+	{
+		.name    = "spi",
+		.id      = -1,
+		.parent  = &clk_g,
+		.enable  = asic3_clock_cdex_enable,
+		.disable = asic3_clock_cdex_disable,
+		.ctrlbit = CLOCK_CDEX_SPI,
+	},
+#ifdef CONFIG_HTC_ASIC3_DS1WM
+	{
+		.name    = "ds1wm",
+		.id      = -1,
+		.rate	 = 5000000,
+		.parent  = &clk_g,
+		.enable  = asic3_clock_cdex_enable,
+		.disable = asic3_clock_cdex_disable,
+		.ctrlbit = CLOCK_CDEX_OWM,
+	},
+#endif
+	{
+		.name    = "pwm0",
+		.id      = -1,
+		.parent  = &clk_g,
+		.enable  = asic3_clock_cdex_enable,
+		.disable = asic3_clock_cdex_disable,
+		.ctrlbit = CLOCK_CDEX_PWM0,
+	},
+	{
+		.name    = "pwm1",
+		.id      = -1,
+		.parent  = &clk_g,
+		.enable  = asic3_clock_cdex_enable,
+		.disable = asic3_clock_cdex_disable,
+		.ctrlbit = CLOCK_CDEX_PWM1,
+	},
+	{
+		.name    = "led0",
+		.id      = -1,
+		.parent  = &clk_g,
+		.enable  = asic3_clock_cdex_enable,
+		.disable = asic3_clock_cdex_disable,
+		.ctrlbit = CLOCK_CDEX_LED0,
+	},
+	{
+		.name    = "led1",
+		.id      = -1,
+		.parent  = &clk_g,
+		.enable  = asic3_clock_cdex_enable,
+		.disable = asic3_clock_cdex_disable,
+		.ctrlbit = CLOCK_CDEX_LED1,
+	},
+	{
+		.name    = "led2",
+		.id      = -1,
+		.parent  = &clk_g,
+		.enable  = asic3_clock_cdex_enable,
+		.disable = asic3_clock_cdex_disable,
+		.ctrlbit = CLOCK_CDEX_LED2,
+	},
+	{
+		.name    = "smbus",
+		.id      = -1,
+		.parent  = &clk_g,
+		.enable  = asic3_clock_cdex_enable,
+		.disable = asic3_clock_cdex_disable,
+		.ctrlbit = CLOCK_CDEX_SMBUS,
+	},
+	{
+		.name    = "ex0",
+		.id      = -1,
+		.parent  = &clk_g,
+		.enable  = asic3_clock_cdex_enable,
+		.disable = asic3_clock_cdex_disable,
+		.ctrlbit = CLOCK_CDEX_EX0,
+	},
+	{
+		.name    = "ex1",
+		.id      = -1,
+		.parent  = &clk_g,
+		.enable  = asic3_clock_cdex_enable,
+		.disable = asic3_clock_cdex_disable,
+		.ctrlbit = CLOCK_CDEX_EX1,
+	},
+};
+
+void asic3_set_extcf_select(struct device *dev, u32 bits, u32 val)
+{
+	struct asic3_data *asic = dev->driver_data;
+	unsigned long flags;
+	u32 v;
+
+	spin_lock_irqsave(&asic3_gpio_lock, flags);
+	v = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(EXTCF, Select));
+	v = (v & ~bits) | val;
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(EXTCF, Select), v);
+	spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_extcf_select);
+
+void asic3_set_extcf_reset(struct device *dev, u32 bits, u32 val)
+{
+	struct asic3_data *asic = dev->driver_data;
+	unsigned long flags;
+	u32 v;
+
+	spin_lock_irqsave(&asic3_gpio_lock, flags);
+	v = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(EXTCF, Reset));
+	v = (v & ~bits) | val;
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(EXTCF, Reset), v);
+	spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_extcf_reset);
+
+void asic3_set_sdhwctrl(struct device *dev, u32 bits, u32 val)
+{
+	struct asic3_data *asic = dev->driver_data;
+	unsigned long flags;
+	u32 v;
+
+	spin_lock_irqsave (&asic3_gpio_lock, flags);
+	v = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(SDHWCTRL, SDConf));
+	v = (v & ~bits) | val;
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(SDHWCTRL, SDConf), v);
+	spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_sdhwctrl);
+
+
+#define MAX_ASIC_ISR_LOOPS    20
+#define _IPAQ_ASIC3_GPIO_Base_INCR \
+	(_IPAQ_ASIC3_GPIO_B_Base - _IPAQ_ASIC3_GPIO_A_Base)
+
+static inline void asic3_irq_flip_edge(struct asic3_data *asic,
+				       u32 base, int bit)
+{
+	u16 edge = __asic3_read_register(asic,
+		base + _IPAQ_ASIC3_GPIO_EdgeTrigger);
+	edge ^= bit;
+	__asic3_write_register(asic,
+		base + _IPAQ_ASIC3_GPIO_EdgeTrigger, edge);
+}
+
+static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+	int iter;
+	struct asic3_data *asic;
+
+	/* Acknowledge the parrent (i.e. CPU's) IRQ */
+	desc->chip->ack(irq);
+
+	asic = desc->handler_data;
+
+	/* printk( KERN_NOTICE "asic3_irq_demux: irq=%d\n", irq ); */
+	for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) {
+		u32 status;
+		int bank;
+
+		status = __asic3_read_register(asic,
+			IPAQ_ASIC3_OFFSET(INTR, PIntStat));
+		/* Check all ten register bits */
+		if ((status & 0x3ff) == 0)
+			break;
+
+		/* Handle GPIO IRQs */
+		for (bank = 0; bank < 4; bank++) {
+			if (status & (1 << bank)) {
+				unsigned long base, i, istat;
+
+				base = _IPAQ_ASIC3_GPIO_A_Base
+				       + bank * _IPAQ_ASIC3_GPIO_Base_INCR;
+				istat = __asic3_read_register(asic,
+					base + _IPAQ_ASIC3_GPIO_IntStatus);
+				/* IntStatus is write 0 to clear */
+				/* XXX could miss interrupts! */
+				__asic3_write_register(asic,
+					base + _IPAQ_ASIC3_GPIO_IntStatus, 0);
+
+				for (i = 0; i < 16; i++) {
+					int bit = (1 << i);
+					unsigned int irqnr;
+					if (!(istat & bit))
+						continue;
+
+					irqnr = asic->irq_base
+						+ (16 * bank) + i;
+					desc = irq_desc + irqnr;
+					desc->handle_irq(irqnr, desc);
+					if (asic->irq_bothedge[bank] & bit) {
+						asic3_irq_flip_edge(asic, base,
+								    bit);
+					}
+				}
+			}
+		}
+
+		/* Handle remaining IRQs in the status register */
+		{
+			int i;
+
+			for (i = ASIC3_LED0_IRQ; i <= ASIC3_OWM_IRQ; i++) {
+				/* They start at bit 4 and go up */
+				if (status & (1 << (i - ASIC3_LED0_IRQ + 4))) {
+					desc = irq_desc + asic->irq_base + i;
+					desc->handle_irq(asic->irq_base + i,
+							 desc);
+				}
+			}
+		}
+
+	}
+
+	if (iter >= MAX_ASIC_ISR_LOOPS)
+		printk(KERN_ERR "%s: interrupt processing overrun\n",
+		       __FUNCTION__);
+}
+
+static inline int asic3_irq_to_bank(struct asic3_data *asic, int irq)
+{
+	int n;
+
+	n = (irq - asic->irq_base) >> 4;
+
+	return (n * (_IPAQ_ASIC3_GPIO_B_Base - _IPAQ_ASIC3_GPIO_A_Base));
+}
+
+static inline int asic3_irq_to_index(struct asic3_data *asic, int irq)
+{
+	return (irq - asic->irq_base) & 15;
+}
+
+static void asic3_mask_gpio_irq(unsigned int irq)
+{
+	struct asic3_data *asic = get_irq_chip_data(irq);
+	u32 val, bank, index;
+	unsigned long flags;
+
+	bank = asic3_irq_to_bank(asic, irq);
+	index = asic3_irq_to_index(asic, irq);
+
+	spin_lock_irqsave(&asic3_gpio_lock, flags);
+	val = __asic3_read_register(asic, bank + _IPAQ_ASIC3_GPIO_Mask);
+	val |= 1 << index;
+	__asic3_write_register(asic, bank + _IPAQ_ASIC3_GPIO_Mask, val);
+	spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+
+static void asic3_mask_irq(unsigned int irq)
+{
+	struct asic3_data *asic = get_irq_chip_data(irq);
+	int regval;
+
+	if (irq < ASIC3_NR_GPIO_IRQS) {
+		printk(KERN_ERR "asic3_base: gpio mask attempt, irq %d\n",
+		       irq);
+		return;
+	}
+
+	regval = __asic3_read_register(asic,
+		_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask);
+
+	switch (irq - asic->irq_base) {
+	case ASIC3_LED0_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval & ~ASIC3_INTMASK_MASK0);
+		break;
+	case ASIC3_LED1_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval & ~ASIC3_INTMASK_MASK1);
+		break;
+	case ASIC3_LED2_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval & ~ASIC3_INTMASK_MASK2);
+		break;
+	case ASIC3_SPI_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval & ~ASIC3_INTMASK_MASK3);
+		break;
+	case ASIC3_SMBUS_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval & ~ASIC3_INTMASK_MASK4);
+		break;
+	case ASIC3_OWM_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval & ~ASIC3_INTMASK_MASK5);
+		break;
+	default:
+		printk(KERN_ERR "asic3_base: bad non-gpio irq %d\n", irq);
+		break;
+	}
+}
+
+static void asic3_unmask_gpio_irq(unsigned int irq)
+{
+	struct asic3_data *asic = get_irq_chip_data(irq);
+	u32 val, bank, index;
+	unsigned long flags;
+
+	bank = asic3_irq_to_bank(asic, irq);
+	index = asic3_irq_to_index(asic, irq);
+
+	spin_lock_irqsave(&asic3_gpio_lock, flags);
+	val = __asic3_read_register(asic, bank + _IPAQ_ASIC3_GPIO_Mask);
+	val &= ~(1 << index);
+	__asic3_write_register(asic, bank + _IPAQ_ASIC3_GPIO_Mask, val);
+	spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+
+static void asic3_unmask_irq(unsigned int irq)
+{
+	struct asic3_data *asic = get_irq_chip_data(irq);
+	int regval;
+
+	if (irq < ASIC3_NR_GPIO_IRQS) {
+		printk(KERN_ERR "asic3_base: gpio unmask attempt, irq %d\n",
+		       irq);
+		return;
+	}
+
+	regval = __asic3_read_register(asic,
+		_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask);
+
+	switch (irq - asic->irq_base) {
+	case ASIC3_LED0_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval | ASIC3_INTMASK_MASK0);
+		break;
+	case ASIC3_LED1_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval | ASIC3_INTMASK_MASK1);
+		break;
+	case ASIC3_LED2_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval | ASIC3_INTMASK_MASK2);
+		break;
+	case ASIC3_SPI_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval | ASIC3_INTMASK_MASK3);
+		break;
+	case ASIC3_SMBUS_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval | ASIC3_INTMASK_MASK4);
+		break;
+	case ASIC3_OWM_IRQ:
+		__asic3_write_register(asic,
+			_IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+			regval | ASIC3_INTMASK_MASK5);
+		break;
+	default:
+		printk(KERN_ERR "asic3_base: bad non-gpio irq %d\n", irq);
+		break;
+	}
+}
+
+static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+	struct asic3_data *asic = get_irq_chip_data(irq);
+	u32 bank, index;
+	unsigned long flags;
+	u16 trigger, level, edge, bit;
+
+	bank = asic3_irq_to_bank(asic, irq);
+	index = asic3_irq_to_index(asic, irq);
+	bit = 1<<index;
+
+	spin_lock_irqsave(&asic3_gpio_lock, flags);
+	level = __asic3_read_register(asic,
+		bank + _IPAQ_ASIC3_GPIO_LevelTrigger);
+	edge = __asic3_read_register(asic,
+		bank + _IPAQ_ASIC3_GPIO_EdgeTrigger);
+	trigger = __asic3_read_register(asic,
+		bank + _IPAQ_ASIC3_GPIO_TriggerType);
+	asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit;
+
+	if (type == IRQT_RISING) {
+		trigger |= bit;
+		edge |= bit;
+	} else if (type == IRQT_FALLING) {
+		trigger |= bit;
+		edge &= ~bit;
+	} else if (type == IRQT_BOTHEDGE) {
+		trigger |= bit;
+		if (asic3_gpio_get_value(asic->dev, irq - asic->irq_base))
+			edge &= ~bit;
+		else
+			edge |= bit;
+		asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit;
+	} else if (type == IRQT_LOW) {
+		trigger &= ~bit;
+		level &= ~bit;
+	} else if (type == IRQT_HIGH) {
+		trigger &= ~bit;
+		level |= bit;
+	} else {
+		/*
+		 * if type == IRQT_NOEDGE, we should mask interrupts, but
+		 * be careful to not unmask them if mask was also called.
+		 * Probably need internal state for mask.
+		 */
+		printk(KERN_NOTICE "asic3: irq type not changed.\n");
+	}
+	__asic3_write_register(asic, bank + _IPAQ_ASIC3_GPIO_LevelTrigger,
+			       level);
+	__asic3_write_register(asic, bank + _IPAQ_ASIC3_GPIO_EdgeTrigger,
+			       edge);
+	__asic3_write_register(asic, bank + _IPAQ_ASIC3_GPIO_TriggerType,
+			       trigger);
+	spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+	return 0;
+}
+
+static struct irq_chip asic3_gpio_irq_chip = {
+	.name		= "ASIC3-GPIO",
+	.ack		= asic3_mask_gpio_irq,
+	.mask		= asic3_mask_gpio_irq,
+	.unmask		= asic3_unmask_gpio_irq,
+	.set_type	= asic3_gpio_irq_type,
+};
+
+static struct irq_chip asic3_irq_chip = {
+	.name		= "ASIC3",
+	.ack		= asic3_mask_irq,
+	.mask		= asic3_mask_irq,
+	.unmask		= asic3_unmask_irq,
+};
+
+static void asic3_release(struct device *dev)
+{
+	struct platform_device *sdev = to_platform_device(dev);
+
+	kfree(sdev->resource);
+	kfree(sdev);
+}
+
+int asic3_register_mmc(struct device *dev)
+{
+	struct platform_device *sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+	struct tmio_mmc_hwconfig *mmc_config = kmalloc(sizeof(*mmc_config),
+						       GFP_KERNEL);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct asic3_data *asic = dev->driver_data;
+	struct asic3_platform_data *asic3_pdata = dev->platform_data;
+	struct resource *res;
+	int rc;
+
+	if (sdev == NULL || mmc_config == NULL)
+		return -ENOMEM;
+
+	if (asic3_pdata->tmio_mmc_hwconfig) {
+		memcpy(mmc_config, asic3_pdata->tmio_mmc_hwconfig,
+		       sizeof(*mmc_config));
+	} else {
+		memset(mmc_config, 0, sizeof(*mmc_config));
+	}
+	mmc_config->address_shift = asic->bus_shift;
+
+	sdev->id = -1;
+	sdev->name = "asic3_mmc";
+	sdev->dev.parent = dev;
+	sdev->num_resources = 2;
+	sdev->dev.platform_data = mmc_config;
+	sdev->dev.release = asic3_release;
+
+	res = kzalloc(sdev->num_resources * sizeof(struct resource),
+		      GFP_KERNEL);
+	if (res == NULL) {
+		kfree(sdev);
+		kfree(mmc_config);
+		return -ENOMEM;
+	}
+	sdev->resource = res;
+
+	res[0].start = pdev->resource[2].start;
+	res[0].end   = pdev->resource[2].end;
+	res[0].flags = IORESOURCE_MEM;
+	res[1].start = res[1].end = pdev->resource[3].start;
+	res[1].flags = IORESOURCE_IRQ;
+
+	rc = platform_device_register(sdev);
+	if (rc) {
+		printk(KERN_ERR "asic3_base: "
+		       "Could not register asic3_mmc device\n");
+		kfree(res);
+		kfree(sdev);
+		return rc;
+	}
+
+	asic->mmc_dev = sdev;
+
+	return 0;
+}
+EXPORT_SYMBOL(asic3_register_mmc);
+
+int asic3_unregister_mmc(struct device *dev)
+{
+	struct asic3_data *asic = dev->driver_data;
+	platform_device_unregister(asic->mmc_dev);
+	asic->mmc_dev = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(asic3_unregister_mmc);
+
+#ifdef CONFIG_HTC_ASIC3_DS1WM
+/*
+ * 	DS1WM subdevice
+ */
+
+static void asic3_ds1wm_enable(struct platform_device *ds1wm_dev)
+{
+	struct device *dev = ds1wm_dev->dev.parent;
+
+	/* Turn on external clocks and the OWM clock */
+	asic3_set_clock_cdex(dev,
+		CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | CLOCK_CDEX_OWM,
+		CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | CLOCK_CDEX_OWM);
+
+	mdelay(1);
+
+	asic3_set_extcf_reset(dev, ASIC3_EXTCF_OWM_RESET,
+			      ASIC3_EXTCF_OWM_RESET);
+	mdelay(1);
+	asic3_set_extcf_reset(dev, ASIC3_EXTCF_OWM_RESET, 0);
+	mdelay(1);
+
+	/* Clear OWM_SMB, set OWM_EN */
+	asic3_set_extcf_select(dev,
+		ASIC3_EXTCF_OWM_SMB | ASIC3_EXTCF_OWM_EN,
+		0                   | ASIC3_EXTCF_OWM_EN);
+
+	mdelay(1);
+}
+
+static void asic3_ds1wm_disable(struct platform_device *ds1wm_dev)
+{
+	struct device *dev = ds1wm_dev->dev.parent;
+
+	asic3_set_extcf_select(dev,
+		ASIC3_EXTCF_OWM_SMB | ASIC3_EXTCF_OWM_EN,
+		0                   | 0);
+
+	asic3_set_clock_cdex(dev,
+		CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | CLOCK_CDEX_OWM,
+		CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | 0);
+}
+
+
+static struct resource asic3_ds1wm_resources[] = {
+	{
+		.start = _IPAQ_ASIC3_OWM_Base,
+		.end   = _IPAQ_ASIC3_OWM_Base + 0x14 - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = ASIC3_OWM_IRQ,
+		.end   = ASIC3_OWM_IRQ,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+			 IORESOURCE_IRQ_SOC_SUBDEVICE,
+	},
+};
+
+static struct ds1wm_platform_data ds1wm_pd = {
+	.enable = asic3_ds1wm_enable,
+	.disable = asic3_ds1wm_disable,
+};
+#endif
+
+static struct soc_device_data asic3_blocks[] = {
+#ifdef CONFIG_HTC_ASIC3_DS1WM
+	{
+		.name = "ds1wm",
+		.res = asic3_ds1wm_resources,
+		.num_resources = ARRAY_SIZE(asic3_ds1wm_resources),
+		.hwconfig = &ds1wm_pd,
+	},
+#endif
+};
+
+static int asic3_probe(struct platform_device *pdev)
+{
+	struct asic3_platform_data *pdata = pdev->dev.platform_data;
+	struct asic3_data *asic;
+	struct device *dev = &pdev->dev;
+	unsigned long clksel;
+	int i, rc;
+
+	asic = kzalloc(sizeof(struct asic3_data), GFP_KERNEL);
+	if (!asic)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, asic);
+	asic->dev = &pdev->dev;
+
+	asic->mapping = ioremap(pdev->resource[0].start, IPAQ_ASIC3_MAP_SIZE);
+	if (!asic->mapping) {
+		printk(KERN_ERR "asic3: couldn't ioremap ASIC3\n");
+		kfree (asic);
+		return -ENOMEM;
+	}
+
+	if (pdata && pdata->bus_shift)
+		asic->bus_shift = pdata->bus_shift;
+	else
+		asic->bus_shift = 2;
+
+	/* XXX: should get correct SD clock values from pdata struct  */
+	clksel = 0;
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, SEL), clksel);
+
+	/* Register ASIC3's clocks. */
+	clk_g.ctrlbit = (int)asic;
+
+	if (clk_register(&clk_g) < 0)
+		printk(KERN_ERR "asic3: failed to register ASIC3 gclk\n");
+
+	for (i = 0; i < ARRAY_SIZE(asic3_clocks); i++) {
+		rc = clk_register(&asic3_clocks[i]);
+		if (rc < 0)
+			printk(KERN_ERR "asic3: "
+			       "failed to register clock %s (%d)\n",
+			       asic3_clocks[i].name, rc);
+	}
+
+	__asic3_write_register(asic, IPAQ_ASIC3_GPIO_OFFSET(A, Mask), 0xffff);
+	__asic3_write_register(asic, IPAQ_ASIC3_GPIO_OFFSET(B, Mask), 0xffff);
+	__asic3_write_register(asic, IPAQ_ASIC3_GPIO_OFFSET(C, Mask), 0xffff);
+	__asic3_write_register(asic, IPAQ_ASIC3_GPIO_OFFSET(D, Mask), 0xffff);
+
+	asic3_set_gpio_sleepmask_a(dev, 0xffff, 0xffff);
+	asic3_set_gpio_sleepmask_b(dev, 0xffff, 0xffff);
+	asic3_set_gpio_sleepmask_c(dev, 0xffff, 0xffff);
+	asic3_set_gpio_sleepmask_d(dev, 0xffff, 0xffff);
+
+	if (pdata) {
+		asic3_set_gpio_out_a(dev, 0xffff, pdata->gpio_a.init);
+		asic3_set_gpio_out_b(dev, 0xffff, pdata->gpio_b.init);
+		asic3_set_gpio_out_c(dev, 0xffff, pdata->gpio_c.init);
+		asic3_set_gpio_out_d(dev, 0xffff, pdata->gpio_d.init);
+
+		asic3_set_gpio_dir_a(dev, 0xffff, pdata->gpio_a.dir);
+		asic3_set_gpio_dir_b(dev, 0xffff, pdata->gpio_b.dir);
+		asic3_set_gpio_dir_c(dev, 0xffff, pdata->gpio_c.dir);
+		asic3_set_gpio_dir_d(dev, 0xffff, pdata->gpio_d.dir);
+
+		asic3_set_gpio_sleepmask_a(dev, 0xffff,
+					   pdata->gpio_a.sleep_mask);
+		asic3_set_gpio_sleepmask_b(dev, 0xffff,
+					   pdata->gpio_b.sleep_mask);
+		asic3_set_gpio_sleepmask_c(dev, 0xffff,
+					   pdata->gpio_c.sleep_mask);
+		asic3_set_gpio_sleepmask_d(dev, 0xffff,
+					   pdata->gpio_d.sleep_mask);
+
+		asic3_set_gpio_sleepout_a(dev, 0xffff,
+					  pdata->gpio_a.sleep_out);
+		asic3_set_gpio_sleepout_b(dev, 0xffff,
+					  pdata->gpio_b.sleep_out);
+		asic3_set_gpio_sleepout_c(dev, 0xffff,
+					  pdata->gpio_c.sleep_out);
+		asic3_set_gpio_sleepout_d(dev, 0xffff,
+					  pdata->gpio_d.sleep_out);
+
+		asic3_set_gpio_battfaultout_a(dev, 0xffff,
+					      pdata->gpio_a.batt_fault_out);
+		asic3_set_gpio_battfaultout_b(dev, 0xffff,
+					      pdata->gpio_b.batt_fault_out);
+		asic3_set_gpio_battfaultout_c(dev, 0xffff,
+					      pdata->gpio_c.batt_fault_out);
+		asic3_set_gpio_battfaultout_d(dev, 0xffff,
+					      pdata->gpio_d.batt_fault_out);
+
+		asic3_set_gpio_sleepconf_a(dev, 0xffff,
+					   pdata->gpio_a.sleep_conf);
+		asic3_set_gpio_sleepconf_b(dev, 0xffff,
+					   pdata->gpio_b.sleep_conf);
+		asic3_set_gpio_sleepconf_c(dev, 0xffff,
+					   pdata->gpio_c.sleep_conf);
+		asic3_set_gpio_sleepconf_d(dev, 0xffff,
+					   pdata->gpio_d.sleep_conf);
+
+		asic3_set_gpio_alt_fn_a(dev, 0xffff,
+					pdata->gpio_a.alt_function);
+		asic3_set_gpio_alt_fn_b(dev, 0xffff,
+					pdata->gpio_b.alt_function);
+		asic3_set_gpio_alt_fn_c(dev, 0xffff,
+					pdata->gpio_c.alt_function);
+		asic3_set_gpio_alt_fn_d(dev, 0xffff,
+					pdata->gpio_d.alt_function);
+	}
+
+	asic->irq_nr = -1;
+	asic->irq_base = -1;
+
+	if (pdev->num_resources > 1)
+		asic->irq_nr = pdev->resource[1].start;
+
+	if (asic->irq_nr != -1) {
+		unsigned int i;
+
+		if (!pdata->irq_base) {
+			printk(KERN_ERR "asic3: IRQ base not specified\n");
+			asic3_remove(pdev);
+			return -EINVAL;
+		}
+
+		asic->irq_base = pdata->irq_base;
+
+		/* turn on clock to IRQ controller */
+		clksel |= CLOCK_SEL_CX;
+		__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, SEL),
+				       clksel);
+
+		printk(KERN_INFO "asic3: using irq %d-%d on irq %d\n",
+		       asic->irq_base, asic->irq_base + ASIC3_NR_IRQS - 1,
+		       asic->irq_nr);
+
+		for (i = 0 ; i < ASIC3_NR_IRQS ; i++) {
+			int irq = i + asic->irq_base;
+			if (i < ASIC3_NR_GPIO_IRQS) {
+				set_irq_chip(irq, &asic3_gpio_irq_chip);
+				set_irq_chip_data(irq, asic);
+				set_irq_handler(irq, handle_level_irq);
+				set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+			} else {
+				/* The remaining IRQs are not GPIO */
+				set_irq_chip(irq, &asic3_irq_chip);
+				set_irq_chip_data(irq, asic);
+				set_irq_handler(irq, handle_level_irq);
+				set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+			}
+		}
+
+		__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(INTR, IntMask),
+					ASIC3_INTMASK_GINTMASK);
+
+		set_irq_chained_handler(asic->irq_nr, asic3_irq_demux);
+		set_irq_type(asic->irq_nr, IRQT_RISING);
+		set_irq_data(asic->irq_nr, asic);
+	}
+
+#ifdef CONFIG_HTC_ASIC3_DS1WM
+	ds1wm_pd.bus_shift = asic->bus_shift;
+#endif
+
+	pdata->gpiodev_ops.get = asic3_gpio_get_value;
+	pdata->gpiodev_ops.set = asic3_gpio_set_value;
+	pdata->gpiodev_ops.to_irq = asic3_gpio_to_irq;
+
+	soc_add_devices(pdev, asic3_blocks, ARRAY_SIZE(asic3_blocks),
+			&pdev->resource[0],
+			asic->bus_shift - ASIC3_DEFAULT_ADDR_SHIFT,
+			asic->irq_base);
+
+	if (pdev->num_resources > 2) {
+		int rc;
+		rc = asic3_register_mmc(dev);
+		if (rc) {
+			asic3_remove(pdev);
+			return rc;
+		}
+	}
+
+	if (pdata && pdata->num_child_platform_devs != 0)
+		platform_add_devices(pdata->child_platform_devs,
+				     pdata->num_child_platform_devs);
+
+	return 0;
+}
+
+static int asic3_remove(struct platform_device *pdev)
+{
+	struct asic3_platform_data *pdata = pdev->dev.platform_data;
+	struct asic3_data *asic = platform_get_drvdata(pdev);
+	int i;
+
+	if (pdata && pdata->num_child_platform_devs != 0) {
+		for (i = 0; i < pdata->num_child_platform_devs; i++) {
+			platform_device_unregister(
+				pdata->child_platform_devs[i]);
+		}
+	}
+
+	if (asic->irq_nr != -1) {
+		unsigned int i;
+
+		for (i = 0 ; i < ASIC3_NR_IRQS ; i++) {
+			int irq = i + asic->irq_base;
+			set_irq_flags(irq, 0);
+			set_irq_handler (irq, NULL);
+			set_irq_chip (irq, NULL);
+			set_irq_chip_data(irq, NULL);
+		}
+
+		set_irq_chained_handler(asic->irq_nr, NULL);
+	}
+
+	if (asic->mmc_dev)
+		asic3_unregister_mmc(&pdev->dev);
+
+	for (i = 0; i < ARRAY_SIZE(asic3_clocks); i++)
+		clk_unregister(&asic3_clocks[i]);
+	clk_unregister(&clk_g);
+
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, SEL), 0);
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(INTR, IntMask), 0);
+
+	iounmap(asic->mapping);
+
+	kfree(asic);
+
+	return 0;
+}
+
+static void asic3_shutdown(struct platform_device *pdev)
+{
+}
+
+#define ASIC3_SUSPEND_CDEX_MASK \
+	(CLOCK_CDEX_LED0 | CLOCK_CDEX_LED1 | CLOCK_CDEX_LED2)
+static unsigned short suspend_cdex;
+
+static int asic3_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct asic3_data *asic = platform_get_drvdata(pdev);
+	suspend_cdex = __asic3_read_register(asic,
+		_IPAQ_ASIC3_CLOCK_Base + _IPAQ_ASIC3_CLOCK_CDEX);
+	/* The LEDs are still active during suspend */
+	__asic3_write_register(asic,
+		_IPAQ_ASIC3_CLOCK_Base + _IPAQ_ASIC3_CLOCK_CDEX,
+		suspend_cdex & ASIC3_SUSPEND_CDEX_MASK);
+	return 0;
+}
+
+static int asic3_resume(struct platform_device *pdev)
+{
+	struct asic3_data *asic = platform_get_drvdata(pdev);
+	unsigned short intmask;
+
+	__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX),
+			       suspend_cdex);
+
+	if (asic->irq_nr != -1) {
+		/* Toggle the interrupt mask to try to get ASIC3 to show
+		 * the CPU an interrupt edge. For more details see the
+		 * kernel-discuss thread around 13 June 2005 with the
+		 * subject "asic3 suspend / resume". */
+		intmask = __asic3_read_register(asic,
+				IPAQ_ASIC3_OFFSET(INTR, IntMask));
+		__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(INTR, IntMask),
+				       intmask & ~ASIC3_INTMASK_GINTMASK);
+		mdelay(1);
+		__asic3_write_register(asic, IPAQ_ASIC3_OFFSET(INTR, IntMask),
+				       intmask | ASIC3_INTMASK_GINTMASK);
+	}
+
+	return 0;
+}
+
+static struct platform_driver asic3_device_driver = {
+	.driver		= {
+		.name	= "asic3",
+	},
+	.probe		= asic3_probe,
+	.remove		= asic3_remove,
+	.suspend	= asic3_suspend,
+	.resume		= asic3_resume,
+	.shutdown	= asic3_shutdown,
+};
+
+static int __init asic3_base_init(void)
+{
+	int retval = 0;
+	retval = platform_driver_register(&asic3_device_driver);
+	return retval;
+}
+
+static void __exit asic3_base_exit(void)
+{
+	platform_driver_unregister(&asic3_device_driver);
+}
+
+#ifdef MODULE
+module_init(asic3_base_init);
+#else	/* start early for dependencies */
+subsys_initcall(asic3_base_init);
+#endif
+module_exit(asic3_base_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
+MODULE_DESCRIPTION("Core driver for HTC ASIC3");
+MODULE_SUPPORTED_DEVICE("asic3");
Index: linux-2.6.24/drivers/mfd/soc-core.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/drivers/mfd/soc-core.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,106 @@
+/*
+ * drivers/soc/soc-core.c
+ *
+ * core SoC support
+ * Copyright (c) 2006 Ian Molton
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains functionality used by many SoC type devices.
+ *
+ * Created: 2006-11-28
+ *
+ */
+
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include "soc-core.h"
+
+void soc_free_devices(struct platform_device *devices, int nr_devs)
+{
+	struct platform_device *dev = devices;
+	int i;
+
+	for (i = 0; i < nr_devs; i++) {
+		struct resource *res = dev->resource;
+		platform_device_unregister(dev++);
+		kfree(res);
+	}
+	kfree(devices);
+}
+EXPORT_SYMBOL_GPL(soc_free_devices);
+
+#define SIGNED_SHIFT(val, shift) ((shift) >= 0 ? ((val) << (shift)) : ((val) >> -(shift)))
+
+struct platform_device *soc_add_devices(struct platform_device *dev,
+					struct soc_device_data *soc, int nr_devs,
+					struct resource *mem,
+					int relative_addr_shift, int irq_base)
+{
+	struct platform_device *devices;
+	int i, r, base;
+
+	devices = kzalloc(nr_devs * sizeof(struct platform_device), GFP_KERNEL);
+	if (!devices)
+		return NULL;
+
+	for (i = 0; i < nr_devs; i++) {
+		struct platform_device *sdev = &devices[i];
+		struct soc_device_data *blk = &soc[i];
+		struct resource *res;
+
+		sdev->id = -1;
+		sdev->name = blk->name;
+
+		sdev->dev.parent = &dev->dev;
+		sdev->dev.platform_data = (void *)blk->hwconfig;
+		sdev->num_resources = blk->num_resources;
+
+		/* Allocate space for the subdevice resources */
+		res = kzalloc (blk->num_resources * sizeof (struct resource), GFP_KERNEL);
+		if (!res)
+			goto fail;
+
+		for (r = 0 ; r < blk->num_resources ; r++) {
+			res[r].name = blk->res[r].name; // Fixme - should copy
+
+			/* Find out base to use */
+			base = 0;
+			if (blk->res[r].flags & IORESOURCE_MEM) {
+				base = mem->start;
+			} else if ((blk->res[r].flags & IORESOURCE_IRQ) &&
+				(blk->res[r].flags & IORESOURCE_IRQ_MFD_SUBDEVICE)) {
+				base = irq_base;
+			}
+
+			/* Adjust resource */
+			if (blk->res[r].flags & IORESOURCE_MEM) {
+				res[r].parent = mem;
+				res[r].start = base + SIGNED_SHIFT(blk->res[r].start, relative_addr_shift);
+				res[r].end   = base + SIGNED_SHIFT(blk->res[r].end,   relative_addr_shift);
+			} else {
+				res[r].start = base + blk->res[r].start;
+				res[r].end   = base + blk->res[r].end;
+			}
+			res[r].flags = blk->res[r].flags;
+		}
+
+		sdev->resource = res;
+		if (platform_device_register(sdev)) {
+			kfree(res);
+			goto fail;
+		}
+
+		printk(KERN_INFO "SoC: registering %s\n", blk->name);
+	}
+	return devices;
+
+fail:
+	soc_free_devices(devices, i + 1);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(soc_add_devices);
Index: linux-2.6.24/drivers/mfd/soc-core.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/drivers/mfd/soc-core.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,30 @@
+/*
+ * drivers/soc/soc-core.h
+ *
+ * core SoC support
+ * Copyright (c) 2006 Ian Molton
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains prototypes for the functions in soc-core.c
+ *
+ * Created: 2006-11-28
+ *
+ */
+
+struct soc_device_data {
+	char *name;
+	struct resource *res;
+	int num_resources;
+	void *hwconfig; /* platform_data to pass to the subdevice */
+};
+
+struct platform_device *soc_add_devices(struct platform_device *dev,
+					struct soc_device_data *soc, int n_devs,
+					struct resource *mem,
+					int relative_addr_shift, int irq_base);
+
+void soc_free_devices(struct platform_device *devices, int nr_devs);
+
Index: linux-2.6.24/include/asm-arm/arch-pxa/clock.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/asm-arm/arch-pxa/clock.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,27 @@
+/*
+ *  linux/include/asm-arm/arch-pxa/clock.h
+ *
+ *  Copyright (C) 2006 Erik Hovland
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+struct clk {
+	struct list_head	node;
+	struct module		*owner;
+	struct clk		*parent;
+	const char		*name;
+	int			id;
+	unsigned int		enabled;
+	unsigned long		rate;
+	unsigned long		ctrlbit;
+
+	void			(*enable)(struct clk *);
+	void			(*disable)(struct clk *);
+};
+
+
+extern int clk_register(struct clk *clk);
+extern void clk_unregister(struct clk *clk);
Index: linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal-asic.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal-asic.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,213 @@
+/*
+ * include/asm/arm/arch-pxa/htcuniversal-asic.h
+ *
+ * Authors: Giuseppe Zompatori <giuseppe_zompatori@yahoo.it>
+ *
+ * based on previews work, see below:
+ *
+ * include/asm/arm/arch-pxa/hx4700-asic.h
+ *      Copyright (c) 2004 SDG Systems, LLC
+ *
+ */
+
+#ifndef _HTCUNIVERSAL_ASIC_H_
+#define _HTCUNIVERSAL_ASIC_H_
+
+#include <asm/hardware/ipaq-asic3.h>
+
+/* ASIC3 */
+
+#define HTCUNIVERSAL_ASIC3_GPIO_PHYS	PXA_CS4_PHYS
+#define HTCUNIVERSAL_ASIC3_MMC_PHYS	PXA_CS3_PHYS
+
+/* TODO: some information is missing here */
+
+/* ASIC3 GPIO A bank */
+
+#define GPIOA_I2C_EN	 	 	 0	/* Output */
+#define GPIOA_SPK_PWR1_ON	 	 1	/* Output */
+#define GPIOA_AUDIO_PWR_ON	 	 2	/* Output */
+#define GPIOA_EARPHONE_PWR_ON	 	 3	/* Output */
+
+#define GPIOA_UNKNOWN4			 4	/* Output */
+#define GPIOA_BUTTON_BACKLIGHT_N	 5	/* Input  */
+#define GPIOA_SPK_PWR2_ON	 	 6	/* Output */
+#define GPIOA_BUTTON_RECORD_N		 7	/* Input  */
+
+#define GPIOA_BUTTON_CAMERA_N		 8	/* Input  */
+#define GPIOA_UNKNOWN9			 9	/* Output */
+#define GPIOA_FLASHLIGHT 		10	/* Output */
+#define GPIOA_COVER_ROTATE_N 		11	/* Input  */
+
+#define GPIOA_TOUCHSCREEN_N		12	/* Input  */
+#define GPIOA_VOL_UP_N  		13	/* Input  */
+#define GPIOA_VOL_DOWN_N 		14	/* Input  */
+#define GPIOA_LCD_PWR5_ON 		15	/* Output */
+
+/* ASIC3 GPIO B bank */
+
+#define GPIOB_BB_READY			 0	/* Input */
+#define GPIOB_CODEC_PDN			 1	/* Output */
+#define GPIOB_UNKNOWN2			 2	/* Input  */
+#define GPIOB_BB_UNKNOWN3		 3	/* Input  */
+
+#define GPIOB_BT_IRQ			 4	/* Input  */
+#define GPIOB_CLAMSHELL_N		 5	/* Input  */
+#define GPIOB_LCD_PWR3_ON		 6	/* Output */
+#define GPIOB_BB_ALERT			 7	/* Input  */
+
+#define GPIOB_BB_RESET2			 8	/* Output */
+#define GPIOB_EARPHONE_N		 9	/* Input  */
+#define GPIOB_MICRECORD_N		10	/* Input  */
+#define GPIOB_NIGHT_SENSOR		11	/* Input  */
+
+#define GPIOB_UMTS_DCD			12	/* Input  */
+#define GPIOB_UNKNOWN13			13	/* Input  */
+#define GPIOB_CHARGE_EN 		14	/* Output */
+#define GPIOB_USB_PUEN 			15	/* Output */
+
+/* ASIC3 GPIO C bank */
+
+#define GPIOC_LED_BTWIFI  	   	 0	/* Output */
+#define GPIOC_LED_RED		   	 1	/* Output */
+#define GPIOC_LED_GREEN			 2	/* Output */
+#define GPIOC_BOARDID3  		 3	/* Input  */
+
+#define GPIOC_WIFI_IRQ_N  		 4	/* Input  */
+#define GPIOC_WIFI_RESET  		 5	/* Output */
+#define GPIOC_WIFI_PWR1_ON  		 6	/* Output */
+#define GPIOC_BT_RESET  		 7	/* Output */
+
+#define GPIOC_UNKNOWN8  		 8	/* Output */
+#define GPIOC_LCD_PWR1_ON		 9	/* Output */
+#define GPIOC_LCD_PWR2_ON 		10	/* Output */
+#define GPIOC_BOARDID2  		11	/* Input  */
+
+#define GPIOC_BOARDID1			12	/* Input  */
+#define GPIOC_BOARDID0  		13	/* Input  */
+#define GPIOC_BT_PWR_ON			14	/* Output */
+#define GPIOC_CHARGE_ON			15	/* Output */
+
+/* ASIC3 GPIO D bank */
+
+#define GPIOD_KEY_OK_N			 0	/* Input  */
+#define GPIOD_KEY_RIGHT_N		 1	/* Input  */
+#define GPIOD_KEY_LEFT_N		 2	/* Input  */
+#define GPIOD_KEY_DOWN_N		 3	/* Input  */
+
+#define GPIOD_KEY_UP_N  		 4	/* Input  */
+#define GPIOD_SDIO_DET			 5	/* Input  */
+#define GPIOD_WIFI_PWR2_ON		 6	/* Output */
+#define GPIOD_HW_REBOOT			 7	/* Output */
+
+#define GPIOD_BB_RESET1			 8	/* Output */
+#define GPIOD_UNKNOWN9			 9	/* Output */
+#define GPIOD_VIBRA_PWR_ON		10	/* Output */
+#define GPIOD_WIFI_PWR3_ON		11	/* Output */
+
+#define GPIOD_FL_PWR_ON  		12	/* Output */
+#define GPIOD_LCD_PWR4_ON		13	/* Output */
+#define GPIOD_BL_KEYP_PWR_ON		14	/* Output */
+#define GPIOD_BL_KEYB_PWR_ON		15	/* Output */
+
+extern struct platform_device htcuniversal_asic3;
+
+/* ASIC3 GPIO A bank */
+
+#define GPIO_I2C_EN	 	 	0*16+GPIOA_I2C_EN
+#define GPIO_SPK_PWR1_ON	 	0*16+GPIOA_SPK_PWR1_ON
+#define GPIO_AUDIO_PWR_ON	 	0*16+GPIOA_AUDIO_PWR_ON
+#define GPIO_EARPHONE_PWR_ON	 	0*16+GPIOA_EARPHONE_PWR_ON
+
+#define GPIO_UNKNOWNA4			0*16+GPIOA_UNKNOWN4
+#define GPIO_BUTTON_BACKLIGHT_N		0*16+GPIOA_BUTTON_BACKLIGHT_N
+#define GPIO_SPK_PWR2_ON	 	0*16+GPIOA_SPK_PWR2_ON
+#define GPIO_BUTTON_RECORD_N		0*16+GPIOA_BUTTON_RECORD_N
+
+#define GPIO_BUTTON_CAMERA_N		0*16+GPIOA_BUTTON_CAMERA_N
+#define GPIO_UNKNOWNA9			0*16+GPIOA_UNKNOWN9
+#define GPIO_FLASHLIGHT 		0*16+GPIOA_FLASHLIGHT
+#define GPIO_COVER_ROTATE_N 		0*16+GPIOA_COVER_ROTATE_N
+
+#define GPIO_TOUCHSCREEN_N		0*16+GPIOA_TOUCHSCREEN_N
+#define GPIO_VOL_UP_N  			0*16+GPIOA_VOL_UP_N
+#define GPIO_VOL_DOWN_N 		0*16+GPIOA_VOL_DOWN_N
+#define GPIO_LCD_PWR5_ON 		0*16+GPIOA_LCD_PWR5_ON
+
+/* ASIC3 GPIO B bank */
+
+#define GPIO_BB_READY			1*16+GPIOB_BB_READY
+#define GPIO_CODEC_PDN			1*16+GPIOB_CODEC_PDN
+#define GPIO_UNKNOWNB2			1*16+GPIOB_UNKNOWN2
+#define GPIO_BB_UNKNOWN3		1*16+GPIOB_BB_UNKNOWN3
+
+#define GPIO_BT_IRQ			1*16+GPIOB_BT_IRQ
+#define GPIO_CLAMSHELL_N		1*16+GPIOB_CLAMSHELL_N
+#define GPIO_LCD_PWR3_ON		1*16+GPIOB_LCD_PWR3_ON
+#define GPIO_BB_ALERT			1*16+GPIOB_BB_ALERT
+
+#define GPIO_BB_RESET2			1*16+GPIOB_BB_RESET2
+#define GPIO_EARPHONE_N			1*16+GPIOB_EARPHONE_N
+#define GPIO_MICRECORD_N		1*16+GPIOB_MICRECORD_N
+#define GPIO_NIGHT_SENSOR		1*16+GPIOB_NIGHT_SENSOR
+
+#define GPIO_UMTS_DCD			1*16+GPIOB_UMTS_DCD
+#define GPIO_UNKNOWNB13			1*16+GPIOB_UNKNOWN13
+#define GPIO_CHARGE_EN 			1*16+GPIOB_CHARGE_EN
+#define GPIO_USB_PUEN 			1*16+GPIOB_USB_PUEN
+
+/* ASIC3 GPIO C bank */
+
+#define GPIO_LED_BTWIFI  	   	2*16+GPIOC_LED_BTWIFI
+#define GPIO_LED_RED		   	2*16+GPIOC_LED_RED
+#define GPIO_LED_GREEN			2*16+GPIOC_LED_GREEN
+#define GPIO_BOARDID3  			2*16+GPIOC_BOARDID3
+
+#define GPIO_WIFI_IRQ_N  		2*16+GPIOC_WIFI_IRQ_N
+#define GPIO_WIFI_RESET  		2*16+GPIOC_WIFI_RESET
+#define GPIO_WIFI_PWR1_ON  		2*16+GPIOC_WIFI_PWR1_ON
+#define GPIO_BT_RESET  			2*16+GPIOC_BT_RESET
+
+#define GPIO_UNKNOWNC8  		2*16+GPIOC_UNKNOWN8
+#define GPIO_LCD_PWR1_ON		2*16+GPIOC_LCD_PWR1_ON
+#define GPIO_LCD_PWR2_ON 		2*16+GPIOC_LCD_PWR2_ON
+#define GPIO_BOARDID2  			2*16+GPIOC_BOARDID2
+
+#define GPIO_BOARDID1			2*16+GPIOC_BOARDID1
+#define GPIO_BOARDID0  			2*16+GPIOC_BOARDID0
+#define GPIO_BT_PWR_ON			2*16+GPIOC_BT_PWR_ON
+#define GPIO_CHARGE_ON			2*16+GPIOC_CHARGE_ON
+
+/* ASIC3 GPIO D bank */
+
+#define GPIO_KEY_OK_N			3*16+GPIOD_KEY_OK_N
+#define GPIO_KEY_RIGHT_N		3*16+GPIOD_KEY_RIGHT_N
+#define GPIO_KEY_LEFT_N			3*16+GPIOD_KEY_LEFT_N
+#define GPIO_KEY_DOWN_N			3*16+GPIOD_KEY_DOWN_N
+
+#define GPIO_KEY_UP_N  			3*16+GPIOD_KEY_UP_N
+#define GPIO_SDIO_DET			3*16+GPIOD_SDIO_DET
+#define GPIO_WIFI_PWR2_ON		3*16+GPIOD_WIFI_PWR2_ON
+#define GPIO_HW_REBOOT			3*16+GPIOD_HW_REBOOT
+
+#define GPIO_BB_RESET1			3*16+GPIOD_BB_RESET1
+#define GPIO_UNKNOWND9			3*16+GPIOD_UNKNOWN9
+#define GPIO_VIBRA_PWR_ON		3*16+GPIOD_VIBRA_PWR_ON
+#define GPIO_WIFI_PWR3_ON		3*16+GPIOD_WIFI_PWR3_ON
+
+#define GPIO_FL_PWR_ON  		3*16+GPIOD_FL_PWR_ON
+#define GPIO_LCD_PWR4_ON		3*16+GPIOD_LCD_PWR4_ON
+#define GPIO_BL_KEYP_PWR_ON		3*16+GPIOD_BL_KEYP_PWR_ON
+#define GPIO_BL_KEYB_PWR_ON		3*16+GPIOD_BL_KEYB_PWR_ON
+
+#define HTCUNIVERSAL_EGPIO_BASE	PXA_CS2_PHYS+0x02000000
+
+#define EGPIO4_ON			 4  /* something */
+#define EGPIO5_BT_3V3_ON		 5  /* Bluetooth related */
+#define EGPIO6_WIFI_ON			 6  /* WLAN related*/
+
+extern void htcuniversal_egpio_enable( u_int16_t bits );
+extern void htcuniversal_egpio_disable( u_int16_t bits );
+
+#endif /* _HTCUNIVERSAL_ASIC_H_ */
+
Index: linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal-gpio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal-gpio.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,220 @@
+/*
+ * include/asm-arm/arch-pxa/htcuniversal-gpio.h
+ * History:
+ *
+ * 2004-12-10 Michael Opdenacker. Wrote down GPIO settings as identified by Jamey Hicks.
+ *            Reused the h2200-gpio.h file as a template.
+ */
+
+#ifndef _HTCUNIVERSAL_GPIO_H_
+#define _HTCUNIVERSAL_GPIO_H_
+
+#include <asm/arch/pxa-regs.h>
+
+#define GET_HTCUNIVERSAL_GPIO(gpio) \
+	(GPLR(GPIO_NR_HTCUNIVERSAL_ ## gpio) & GPIO_bit(GPIO_NR_HTCUNIVERSAL_ ## gpio))
+
+#define SET_HTCUNIVERSAL_GPIO(gpio, setp) \
+do { \
+if (setp) \
+	GPSR(GPIO_NR_HTCUNIVERSAL_ ## gpio) = GPIO_bit(GPIO_NR_HTCUNIVERSAL_ ## gpio); \
+else \
+	GPCR(GPIO_NR_HTCUNIVERSAL_ ## gpio) = GPIO_bit(GPIO_NR_HTCUNIVERSAL_ ## gpio); \
+} while (0)
+
+#define SET_HTCUNIVERSAL_GPIO_N(gpio, setp) \
+do { \
+if (setp) \
+	GPCR(GPIO_NR_HTCUNIVERSAL_ ## gpio ## _N) = GPIO_bit(GPIO_NR_HTCUNIVERSAL_ ## gpio ## _N); \
+else \
+	GPSR(GPIO_NR_HTCUNIVERSAL_ ## gpio ## _N) = GPIO_bit(GPIO_NR_HTCUNIVERSAL_ ## gpio ## _N); \
+} while (0)
+
+#define HTCUNIVERSAL_IRQ(gpio) \
+	IRQ_GPIO(GPIO_NR_HTCUNIVERSAL_ ## gpio)
+
+#define GPIO_NR_HTCUNIVERSAL_KEY_ON_N			0
+#define GPIO_NR_HTCUNIVERSAL_GP_RST_N			1
+
+#define GPIO_NR_HTCUNIVERSAL_USB_DET			9
+#define GPIO_NR_HTCUNIVERSAL_POWER_DET			10
+
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD7			12
+#define GPIO_NR_HTCUNIVERSAL_ASIC3_SDIO_INT_N		13
+#define GPIO_NR_HTCUNIVERSAL_ASIC3_EXT_INT		14
+#define GPIO_NR_HTCUNIVERSAL_CS1_N			15
+
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD6			17
+#define GPIO_NR_HTCUNIVERSAL_RDY			18
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_START		19
+
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT7			22
+#define GPIO_NR_HTCUNIVERSAL_SPI_CLK			23
+#define GPIO_NR_HTCUNIVERSAL_SPI_FRM			24
+#define GPIO_NR_HTCUNIVERSAL_SPI_DO			25
+#define GPIO_NR_HTCUNIVERSAL_SPI_DI			26
+
+#define GPIO_NR_HTCUNIVERSAL_CODEC_ON			27
+#define GPIO_NR_HTCUNIVERSAL_I2S_BCK			28
+#define GPIO_NR_HTCUNIVERSAL_I2S_DIN			29
+#define GPIO_NR_HTCUNIVERSAL_I2S_DOUT			30
+#define GPIO_NR_HTCUNIVERSAL_I2S_SYNC			31
+
+#define GPIO_NR_HTCUNIVERSAL_RS232_ON			32
+#define GPIO_NR_HTCUNIVERSAL_CS5_N			33
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_RXD			34
+#define GPIO_NR_HTCUNIVERSAL_PHONE_UART_CTS		35
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN7			36
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN3			37
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN4			38
+#define GPIO_NR_HTCUNIVERSAL_PHONE_TXD			39
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT6			40
+#define GPIO_NR_HTCUNIVERSAL_PHONE_UART_RTS		41
+#define GPIO_NR_HTCUNIVERSAL_BT_RXD			42
+#define GPIO_NR_HTCUNIVERSAL_BT_TXD			43
+#define GPIO_NR_HTCUNIVERSAL_BT_UART_CTS		44
+#define GPIO_NR_HTCUNIVERSAL_BT_UART_RTS		45
+
+#define GPIO_NR_HTCUNIVERSAL_SIR_RXD			42
+#define GPIO_NR_HTCUNIVERSAL_SIR_TXD			43
+
+#define GPIO_NR_HTCUNIVERSAL_POE_N			48
+#define GPIO_NR_HTCUNIVERSAL_PWE_N			49
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD3			50
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD2			51
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD4			52
+
+#define GPIO_NR_HTCUNIVERSAL_CIF_MCLK			53
+#define GPIO_NR_HTCUNIVERSAL_CIF_PCLK			54
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD1			55
+
+#define GPIO_NR_HTCUNIVERSAL_LDD0			58
+#define GPIO_NR_HTCUNIVERSAL_LDD1			59
+#define GPIO_NR_HTCUNIVERSAL_LDD2			60
+#define GPIO_NR_HTCUNIVERSAL_LDD3			61
+#define GPIO_NR_HTCUNIVERSAL_LDD4			62
+#define GPIO_NR_HTCUNIVERSAL_LDD5			63
+#define GPIO_NR_HTCUNIVERSAL_LDD6			64
+#define GPIO_NR_HTCUNIVERSAL_LDD7			65
+#define GPIO_NR_HTCUNIVERSAL_LDD8			66
+#define GPIO_NR_HTCUNIVERSAL_LDD9			67
+#define GPIO_NR_HTCUNIVERSAL_LDD10			68
+#define GPIO_NR_HTCUNIVERSAL_LDD11			69
+#define GPIO_NR_HTCUNIVERSAL_LDD12			70
+#define GPIO_NR_HTCUNIVERSAL_LDD13			71
+#define GPIO_NR_HTCUNIVERSAL_LDD14			72
+#define GPIO_NR_HTCUNIVERSAL_LDD15			73
+
+#define GPIO_NR_HTCUNIVERSAL_LFCLK_RD			74
+#define GPIO_NR_HTCUNIVERSAL_LFCLK_A0			75
+#define GPIO_NR_HTCUNIVERSAL_LFCLK_WR			76
+#define GPIO_NR_HTCUNIVERSAL_LBIAS			77
+
+#define GPIO_NR_HTCUNIVERSAL_CS2_N			78
+#define GPIO_NR_HTCUNIVERSAL_CS3_N			79
+#define GPIO_NR_HTCUNIVERSAL_CS4_N			80
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD0			81
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD5			82
+
+#define GPIO_NR_HTCUNIVERSAL_CIF_LV			84
+#define GPIO_NR_HTCUNIVERSAL_CIF_FV			85
+
+#define GPIO_NR_HTCUNIVERSAL_LCD1			86
+#define GPIO_NR_HTCUNIVERSAL_LCD2			87
+
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN5			90
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN6			91
+
+#define GPIO_NR_HTCUNIVERSAL_DREQ1			97
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_RESET		98
+
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN0			100
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN1			101
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN2			102
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT0			103
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT1			104
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT2			105
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT3			106
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT4			107
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT5			108
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_UNKNOWN 		109
+#define GPIO_NR_HTCUNIVERSAL_PHONE_OFF			110
+
+#define GPIO_NR_HTCUNIVERSAL_USB_PUEN			112
+#define GPIO_NR_HTCUNIVERSAL_I2S_SYSCLK			113
+
+#define GPIO_NR_HTCUNIVERSAL_PWM_OUT1			115
+
+#define GPIO_NR_HTCUNIVERSAL_I2C_SCL			117
+#define GPIO_NR_HTCUNIVERSAL_I2C_SDA			118
+
+#if 0
+#define GPIO_NR_HTCUNIVERSAL_CPU_BATT_FAULT_N
+#define GPIO_NR_HTCUNIVERSAL_ASIC3_RESET_N
+#define GPIO_NR_HTCUNIVERSAL_CHARGE_EN_N
+#define GPIO_NR_HTCUNIVERSAL_FLASH_VPEN
+#define GPIO_NR_HTCUNIVERSAL_BATT_OFF
+#define GPIO_NR_HTCUNIVERSAL_USB_CHARGE_RATE
+#define GPIO_NR_HTCUNIVERSAL_BL_DETECT_N
+#define GPIO_NR_HTCUNIVERSAL_CPU_HW_RESET_N
+#endif
+
+
+#define GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_CLK_MD	(23 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_FRM_MD	(24 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_DO_MD	(25 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_DI_MD	(26 | GPIO_ALT_FN_1_IN)
+
+#define GPIO_NR_HTCUNIVERSAL_I2S_BCK_MD			(28 | GPIO_ALT_FN_1_OUT)
+#define GPIO_NR_HTCUNIVERSAL_I2S_DIN_MD			(29 | GPIO_ALT_FN_2_IN)
+#define GPIO_NR_HTCUNIVERSAL_I2S_DOUT_MD		(30 | GPIO_ALT_FN_1_OUT)
+#define GPIO_NR_HTCUNIVERSAL_I2S_SYNC_MD		(31 | GPIO_ALT_FN_1_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_RXD_MD		(34 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_PHONE_UART_CTS_MD		(35 | GPIO_ALT_FN_1_IN)
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_TXD_MD		(39 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_PHONE_UART_RTS_MD		(41 | GPIO_ALT_FN_2_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_BT_RXD_MD			(42 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_BT_TXD_MD			(43 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_BT_UART_CTS_MD		(44 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_BT_UART_RTS_MD		(45 | GPIO_ALT_FN_2_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_SIR_RXD_MD			(46 | GPIO_ALT_FN_2_IN)
+#define GPIO_NR_HTCUNIVERSAL_SIR_TXD_MD			(47 | GPIO_ALT_FN_1_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_POE_N_MD			(48 | GPIO_ALT_FN_2_OUT | GPIO_DFLT_HIGH)
+#define GPIO_NR_HTCUNIVERSAL_PWE_N_MD			(49 | GPIO_ALT_FN_2_OUT | GPIO_DFLT_HIGH)
+
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN0_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKIN0 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN1_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKIN1 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN2_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKIN2 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN3_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKIN3 | GPIO_ALT_FN_3_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN4_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKIN4 | GPIO_ALT_FN_2_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN5_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKIN5 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN6_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKIN6 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN7_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKIN7 | GPIO_ALT_FN_3_IN)
+
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT0_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKOUT0 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT1_MD		(GPIO_NR_HTCUNIVERSAL_KP_MKOUT1 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT2_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKOUT2 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT3_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKOUT3 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT4_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKOUT4 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT5_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKOUT5 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT6_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKOUT6 | GPIO_ALT_FN_1_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT7_MD 		(GPIO_NR_HTCUNIVERSAL_KP_MKOUT7 | GPIO_ALT_FN_1_OUT)
+
+
+#define GPIO_NR_HTCUNIVERSAL_I2S_SYSCLK_MD		(113 | GPIO_ALT_FN_1_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_PWM1OUT_MD			(115 | GPIO_ALT_FN_3_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_I2C_SCL_MD			(117 | GPIO_ALT_FN_1_OUT)
+#define GPIO_NR_HTCUNIVERSAL_I2C_SDA_MD			(118 | GPIO_ALT_FN_1_OUT)
+
+#endif /* _HTCUNIVERSAL_GPIO_H */
Index: linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal-init.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal-init.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,14 @@
+/*
+ * include/asm/arm/arch-pxa/htcuniversal-init.h
+ *      Copyright (c) 2004 SDG Systems, LLC
+ */
+
+#ifndef _HTCUNIVERSAL_INIT_H_
+#define _HTCUNIVERSAL_INIT_H_
+
+/* htcuniversal initialization data should be found here
+ * See -init.h files from other devices for details
+ */
+
+#endif /* _HTCUNIVERSAL_INIT_H_ */
+
Index: linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,3 @@
+#include <asm/arch/irqs.h>
+
+#define HTCUNIVERSAL_ASIC3_IRQ_BASE IRQ_BOARD_START
Index: linux-2.6.24/include/asm-arm/arch-pxa/pxa-pm_ll.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/asm-arm/arch-pxa/pxa-pm_ll.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,6 @@
+struct pxa_ll_pm_ops {
+	void (*suspend)(unsigned long);
+	void (*resume)(void);
+};
+
+extern struct pxa_ll_pm_ops *pxa_pm_set_ll_ops(struct pxa_ll_pm_ops *new_ops);
Index: linux-2.6.24/include/asm-arm/hardware/asic3_keys.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/asm-arm/hardware/asic3_keys.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,18 @@
+#include <linux/input.h>
+
+struct asic3_keys_button {
+	/* Configuration parameters */
+	int keycode;
+	int gpio;
+	int active_low;
+	char *desc;
+	int type;
+	/* Internal state vars - add below */
+};
+
+struct asic3_keys_platform_data {
+	struct asic3_keys_button *buttons;
+	int nbuttons;
+        struct input_dev *input;
+        struct device *asic3_dev;
+};
Index: linux-2.6.24/include/asm-arm/hardware/asic3_leds.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/asm-arm/hardware/asic3_leds.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,34 @@
+/*
+ * LEDs support for HTC ASIC3 devices.
+ *
+ * Copyright (c) 2006  Anton Vorontsov <cbou@mail.ru>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+struct asic3_leds_machinfo;
+
+struct asic3_led {
+	struct led_classdev led_cdev;
+	int hw_num;	/* Number of "hardware-accelerated" led */
+	int gpio_num;	/* Number of GPIO if hw_num == -1 */
+	struct asic3_leds_machinfo *machinfo;
+};
+
+struct asic3_leds_machinfo {
+	int num_leds;
+	struct asic3_led *leds;
+	struct platform_device *asic3_pdev;
+};
+
+extern int asic3_leds_register(void);
+extern void asic3_leds_unregister(void);
+
Index: linux-2.6.24/include/asm-arm/hardware/ipaq-asic3.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/asm-arm/hardware/ipaq-asic3.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,602 @@
+/*
+ *
+ * Definitions for the HTC ASIC3 chip found in several handheld devices
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author: Andrew Christian
+ *
+ */
+
+#ifndef IPAQ_ASIC3_H
+#define IPAQ_ASIC3_H
+
+/****************************************************/
+/* IPAQ, ASIC #3, replaces ASIC #1 */
+
+#define IPAQ_ASIC3_OFFSET(x,y) (_IPAQ_ASIC3_ ## x ## _Base + _IPAQ_ASIC3_ ## x ## _ ## y)
+#define IPAQ_ASIC3_GPIO_OFFSET(x,y) (_IPAQ_ASIC3_GPIO_ ## x ## _Base + _IPAQ_ASIC3_GPIO_ ## y)
+
+
+/* All offsets below are specified with the following address bus shift */
+#define ASIC3_DEFAULT_ADDR_SHIFT 2
+
+#define _IPAQ_ASIC3_GPIO_A_Base      0x0000
+#define _IPAQ_ASIC3_GPIO_B_Base      0x0100
+#define _IPAQ_ASIC3_GPIO_C_Base      0x0200
+#define _IPAQ_ASIC3_GPIO_D_Base      0x0300
+
+#define _IPAQ_ASIC3_GPIO_Mask          0x00    /* R/W 0:don't mask, 1:mask interrupt */
+#define _IPAQ_ASIC3_GPIO_Direction     0x04    /* R/W 0:input, 1:output              */
+#define _IPAQ_ASIC3_GPIO_Out           0x08    /* R/W 0:output low, 1:output high    */
+#define _IPAQ_ASIC3_GPIO_TriggerType   0x0c    /* R/W 0:level, 1:edge                */
+#define _IPAQ_ASIC3_GPIO_EdgeTrigger   0x10    /* R/W 0:falling, 1:rising            */
+#define _IPAQ_ASIC3_GPIO_LevelTrigger  0x14    /* R/W 0:low, 1:high level detect     */
+#define _IPAQ_ASIC3_GPIO_SleepMask     0x18    /* R/W 0:don't mask, 1:mask trigger in sleep mode  */
+#define _IPAQ_ASIC3_GPIO_SleepOut      0x1c    /* R/W level 0:low, 1:high in sleep mode           */
+#define _IPAQ_ASIC3_GPIO_BattFaultOut  0x20    /* R/W level 0:low, 1:high in batt_fault           */
+#define _IPAQ_ASIC3_GPIO_IntStatus     0x24    /* R/W 0:none, 1:detect               */
+#define _IPAQ_ASIC3_GPIO_AltFunction   0x28	/* R/W 0:normal control 1:LED register control */
+#define _IPAQ_ASIC3_GPIO_SleepConf     0x2c    /* R/W bit 1: autosleep 0: disable gposlpout in normal mode, enable gposlpout in sleep mode */
+#define _IPAQ_ASIC3_GPIO_Status        0x30    /* R   Pin status                                  */
+
+#define IPAQ_ASIC3_GPIO_A_MASK(_b)            IPAQ_ASIC3_GPIO( _b, u16, A, Mask )
+#define IPAQ_ASIC3_GPIO_A_DIR(_b)             IPAQ_ASIC3_GPIO( _b, u16, A, Direction )
+#define IPAQ_ASIC3_GPIO_A_OUT(_b)             IPAQ_ASIC3_GPIO( _b, u16, A, Out )
+#define IPAQ_ASIC3_GPIO_A_LEVELTRI(_b)        IPAQ_ASIC3_GPIO( _b, u16, A, TriggerType )
+#define IPAQ_ASIC3_GPIO_A_RISING(_b)          IPAQ_ASIC3_GPIO( _b, u16, A, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_A_LEVEL(_b)           IPAQ_ASIC3_GPIO( _b, u16, A, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_A_SLEEP_MASK(_b)      IPAQ_ASIC3_GPIO( _b, u16, A, SleepMask )
+#define IPAQ_ASIC3_GPIO_A_SLEEP_OUT(_b)       IPAQ_ASIC3_GPIO( _b, u16, A, SleepOut )
+#define IPAQ_ASIC3_GPIO_A_BATT_FAULT_OUT(_b)  IPAQ_ASIC3_GPIO( _b, u16, A, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_A_INT_STATUS(_b)      IPAQ_ASIC3_GPIO( _b, u16, A, IntStatus )
+#define IPAQ_ASIC3_GPIO_A_ALT_FUNCTION(_b)    IPAQ_ASIC3_GPIO( _b, u16, A, AltFunction )
+#define IPAQ_ASIC3_GPIO_A_SLEEP_CONF(_b)      IPAQ_ASIC3_GPIO( _b, u16, A, SleepConf )
+#define IPAQ_ASIC3_GPIO_A_STATUS(_b)          IPAQ_ASIC3_GPIO( _b, u16, A, Status )
+
+#define IPAQ_ASIC3_GPIO_B_MASK(_b)            IPAQ_ASIC3_GPIO( _b, u16, B, Mask )
+#define IPAQ_ASIC3_GPIO_B_DIR(_b)             IPAQ_ASIC3_GPIO( _b, u16, B, Direction )
+#define IPAQ_ASIC3_GPIO_B_OUT(_b)             IPAQ_ASIC3_GPIO( _b, u16, B, Out )
+#define IPAQ_ASIC3_GPIO_B_LEVELTRI(_b)        IPAQ_ASIC3_GPIO( _b, u16, B, TriggerType )
+#define IPAQ_ASIC3_GPIO_B_RISING(_b)          IPAQ_ASIC3_GPIO( _b, u16, B, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_B_LEVEL(_b)           IPAQ_ASIC3_GPIO( _b, u16, B, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_B_SLEEP_MASK(_b)      IPAQ_ASIC3_GPIO( _b, u16, B, SleepMask )
+#define IPAQ_ASIC3_GPIO_B_SLEEP_OUT(_b)       IPAQ_ASIC3_GPIO( _b, u16, B, SleepOut )
+#define IPAQ_ASIC3_GPIO_B_BATT_FAULT_OUT(_b)  IPAQ_ASIC3_GPIO( _b, u16, B, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_B_INT_STATUS(_b)      IPAQ_ASIC3_GPIO( _b, u16, B, IntStatus )
+#define IPAQ_ASIC3_GPIO_B_ALT_FUNCTION(_b)    IPAQ_ASIC3_GPIO( _b, u16, B, AltFunction )
+#define IPAQ_ASIC3_GPIO_B_SLEEP_CONF(_b)      IPAQ_ASIC3_GPIO( _b, u16, B, SleepConf )
+#define IPAQ_ASIC3_GPIO_B_STATUS(_b)          IPAQ_ASIC3_GPIO( _b, u16, B, Status )
+
+#define IPAQ_ASIC3_GPIO_C_MASK(_b)            IPAQ_ASIC3_GPIO( _b, u16, C, Mask )
+#define IPAQ_ASIC3_GPIO_C_DIR(_b)             IPAQ_ASIC3_GPIO( _b, u16, C, Direction )
+#define IPAQ_ASIC3_GPIO_C_OUT(_b)             IPAQ_ASIC3_GPIO( _b, u16, C, Out )
+#define IPAQ_ASIC3_GPIO_C_LEVELTRI(_b)        IPAQ_ASIC3_GPIO( _b, u16, C, TriggerType )
+#define IPAQ_ASIC3_GPIO_C_RISING(_b)          IPAQ_ASIC3_GPIO( _b, u16, C, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_C_LEVEL(_b)           IPAQ_ASIC3_GPIO( _b, u16, C, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_C_SLEEP_MASK(_b)      IPAQ_ASIC3_GPIO( _b, u16, C, SleepMask )
+#define IPAQ_ASIC3_GPIO_C_SLEEP_OUT(_b)       IPAQ_ASIC3_GPIO( _b, u16, C, SleepOut )
+#define IPAQ_ASIC3_GPIO_C_BATT_FAULT_OUT(_b)  IPAQ_ASIC3_GPIO( _b, u16, C, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_C_INT_STATUS(_b)      IPAQ_ASIC3_GPIO( _b, u16, C, IntStatus )
+#define IPAQ_ASIC3_GPIO_C_ALT_FUNCTION(_b)    IPAQ_ASIC3_GPIO( _b, u16, C, AltFunction )
+#define IPAQ_ASIC3_GPIO_C_SLEEP_CONF(_b)      IPAQ_ASIC3_GPIO( _b, u16, C, SleepConf )
+#define IPAQ_ASIC3_GPIO_C_STATUS(_b)          IPAQ_ASIC3_GPIO( _b, u16, C, Status )
+
+#define IPAQ_ASIC3_GPIO_D_MASK(_b)            IPAQ_ASIC3_GPIO( _b, u16, D, Mask )
+#define IPAQ_ASIC3_GPIO_D_DIR(_b)             IPAQ_ASIC3_GPIO( _b, u16, D, Direction )
+#define IPAQ_ASIC3_GPIO_D_OUT(_b)             IPAQ_ASIC3_GPIO( _b, u16, D, Out )
+#define IPAQ_ASIC3_GPIO_D_LEVELTRI(_b)        IPAQ_ASIC3_GPIO( _b, u16, D, TriggerType )
+#define IPAQ_ASIC3_GPIO_D_RISING(_b)          IPAQ_ASIC3_GPIO( _b, u16, D, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_D_LEVEL(_b)           IPAQ_ASIC3_GPIO( _b, u16, D, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_D_SLEEP_MASK(_b)      IPAQ_ASIC3_GPIO( _b, u16, D, SleepMask )
+#define IPAQ_ASIC3_GPIO_D_SLEEP_OUT(_b)       IPAQ_ASIC3_GPIO( _b, u16, D, SleepOut )
+#define IPAQ_ASIC3_GPIO_D_BATT_FAULT_OUT(_b)  IPAQ_ASIC3_GPIO( _b, u16, D, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_D_INT_STATUS(_b)      IPAQ_ASIC3_GPIO( _b, u16, D, IntStatus )
+#define IPAQ_ASIC3_GPIO_D_ALT_FUNCTION(_b)    IPAQ_ASIC3_GPIO( _b, u16, D, AltFunction )
+#define IPAQ_ASIC3_GPIO_D_SLEEP_CONF(_b)      IPAQ_ASIC3_GPIO( _b, u16, D, SleepConf )
+#define IPAQ_ASIC3_GPIO_D_STATUS(_b)          IPAQ_ASIC3_GPIO( _b, u16, D, Status )
+
+#define _IPAQ_ASIC3_SPI_Base		      0x0400
+#define _IPAQ_ASIC3_SPI_Control               0x0000
+#define _IPAQ_ASIC3_SPI_TxData                0x0004
+#define _IPAQ_ASIC3_SPI_RxData                0x0008
+#define _IPAQ_ASIC3_SPI_Int                   0x000c
+#define _IPAQ_ASIC3_SPI_Status                0x0010
+
+#define IPAQ_ASIC3_SPI_Control(_b)            IPAQ_ASIC3( _b, u16, SPI, Control )
+#define IPAQ_ASIC3_SPI_TxData(_b)             IPAQ_ASIC3( _b, u16, SPI, TxData )
+#define IPAQ_ASIC3_SPI_RxData(_b)             IPAQ_ASIC3( _b, u16, SPI, RxData )
+#define IPAQ_ASIC3_SPI_Int(_b)                IPAQ_ASIC3( _b, u16, SPI, Int )
+#define IPAQ_ASIC3_SPI_Status(_b)             IPAQ_ASIC3( _b, u16, SPI, Status )
+
+#define SPI_CONTROL_SPR(clk)      ((clk) & 0x0f)  /* Clock rate */
+
+#define _IPAQ_ASIC3_PWM_0_Base                0x0500
+#define _IPAQ_ASIC3_PWM_1_Base                0x0600
+#define _IPAQ_ASIC3_PWM_TimeBase              0x0000
+#define _IPAQ_ASIC3_PWM_PeriodTime            0x0004
+#define _IPAQ_ASIC3_PWM_DutyTime              0x0008
+
+#define IPAQ_ASIC3_PWM_TimeBase(_b, x)        IPAQ_ASIC3_N( _b, u16, PWM, x, TimeBase )
+#define IPAQ_ASIC3_PWM_PeriodTime(_b, x)      IPAQ_ASIC3_N( _b, u16, PWM, x, PeriodTime )
+#define IPAQ_ASIC3_PWM_DutyTime(_b, x)        IPAQ_ASIC3_N( _b, u16, PWM, x, DutyTime )
+
+#define PWM_TIMEBASE_VALUE(x)    ((x)&0xf)   /* Low 4 bits sets time base */
+#define PWM_TIMEBASE_ENABLE     (1 << 4)   /* Enable clock */
+
+#define _IPAQ_ASIC3_LED_0_Base                0x0700
+#define _IPAQ_ASIC3_LED_1_Base                0x0800
+#define _IPAQ_ASIC3_LED_2_Base 		      0x0900
+#define _IPAQ_ASIC3_LED_TimeBase              0x0000    /* R/W  7 bits */
+#define _IPAQ_ASIC3_LED_PeriodTime            0x0004    /* R/W 12 bits */
+#define _IPAQ_ASIC3_LED_DutyTime              0x0008    /* R/W 12 bits */
+#define _IPAQ_ASIC3_LED_AutoStopCount         0x000c    /* R/W 16 bits */
+
+#define IPAQ_ASIC3_LED_TimeBase(_b, x)         IPAQ_ASIC3_N( _b,  u8, LED, x, TimeBase )
+#define IPAQ_ASIC3_LED_PeriodTime(_b, x)       IPAQ_ASIC3_N( _b, u16, LED, x, PeriodTime )
+#define IPAQ_ASIC3_LED_DutyTime(_b, x)         IPAQ_ASIC3_N( _b, u16, LED, x, DutyTime )
+#define IPAQ_ASIC3_LED_AutoStopCount(_b, x)    IPAQ_ASIC3_N( _b, u16, LED, x, AutoStopCount )
+
+/* LED TimeBase bits - match ASIC2 */
+#define LED_TBS		0x0f		/* Low 4 bits sets time base, max = 13		*/
+					/* Note: max = 5 on hx4700			*/
+					/* 0: maximum time base				*/
+					/* 1: maximum time base / 2			*/
+					/* n: maximum time base / 2^n			*/
+
+#define LED_EN		(1 << 4)	/* LED ON/OFF 0:off, 1:on			*/
+#define LED_AUTOSTOP	(1 << 5)	/* LED ON/OFF auto stop set 0:disable, 1:enable */
+#define LED_ALWAYS	(1 << 6)	/* LED Interrupt Mask 0:No mask, 1:mask		*/
+
+#define _IPAQ_ASIC3_CLOCK_Base		0x0A00
+#define _IPAQ_ASIC3_CLOCK_CDEX           0x00
+#define _IPAQ_ASIC3_CLOCK_SEL            0x04
+
+#define IPAQ_ASIC3_CLOCK_CDEX(_b)         IPAQ_ASIC3( _b, u16, CLOCK, CDEX )
+#define IPAQ_ASIC3_CLOCK_SEL(_b)          IPAQ_ASIC3( _b, u16, CLOCK, SEL )
+
+#define CLOCK_CDEX_SOURCE       (1 << 0)  /* 2 bits */
+#define CLOCK_CDEX_SOURCE0      (1 << 0)
+#define CLOCK_CDEX_SOURCE1      (1 << 1)
+#define CLOCK_CDEX_SPI          (1 << 2)
+#define CLOCK_CDEX_OWM          (1 << 3)
+#define CLOCK_CDEX_PWM0         (1 << 4)
+#define CLOCK_CDEX_PWM1         (1 << 5)
+#define CLOCK_CDEX_LED0         (1 << 6)
+#define CLOCK_CDEX_LED1         (1 << 7)
+#define CLOCK_CDEX_LED2         (1 << 8)
+
+#define CLOCK_CDEX_SD_HOST      (1 << 9)   /* R/W: SD host clock source 24.576M/12.288M */
+#define CLOCK_CDEX_SD_BUS       (1 << 10)  /* R/W: SD bus clock source control 24.576M/12.288M */
+#define CLOCK_CDEX_SMBUS        (1 << 11)
+#define CLOCK_CDEX_CONTROL_CX   (1 << 12)
+
+#define CLOCK_CDEX_EX0          (1 << 13)  /* R/W: 32.768 kHz crystal */
+#define CLOCK_CDEX_EX1          (1 << 14)  /* R/W: 24.576 MHz crystal */
+
+#define CLOCK_SEL_SD_HCLK_SEL   (1 << 0)   /* R/W: SDIO host clock select  -  1: 24.576 Mhz, 0: 12.288 MHz */
+#define CLOCK_SEL_SD_BCLK_SEL   (1 << 1)   /* R/W: SDIO bus clock select -  1: 24.576 MHz, 0: 12.288 MHz */
+#define CLOCK_SEL_CX            (1 << 2)   /* R/W: INT clock source control (32.768 kHz) */
+
+
+#define _IPAQ_ASIC3_INTR_Base		0x0B00
+
+#define _IPAQ_ASIC3_INTR_IntMask       0x00  /* Interrupt mask control */
+#define _IPAQ_ASIC3_INTR_PIntStat      0x04  /* Peripheral interrupt status */
+#define _IPAQ_ASIC3_INTR_IntCPS        0x08  /* Interrupt timer clock pre-scale */
+#define _IPAQ_ASIC3_INTR_IntTBS        0x0c  /* Interrupt timer set */
+
+#define IPAQ_ASIC3_INTR_IntMask(_b)       IPAQ_ASIC3( _b, u8, INTR, IntMask )
+#define IPAQ_ASIC3_INTR_PIntStat(_b)      IPAQ_ASIC3( _b, u8, INTR, PIntStat )
+#define IPAQ_ASIC3_INTR_IntCPS(_b)        IPAQ_ASIC3( _b, u8, INTR, IntCPS )
+#define IPAQ_ASIC3_INTR_IntTBS(_b)        IPAQ_ASIC3( _b, u16, INTR, IntTBS )
+
+#define ASIC3_INTMASK_GINTMASK    (1 << 0)  /* Global interrupt mask 1:enable */
+#define ASIC3_INTMASK_GINTEL      (1 << 1)  /* 1: rising edge, 0: hi level */
+#define ASIC3_INTMASK_MASK0       (1 << 2)
+#define ASIC3_INTMASK_MASK1       (1 << 3)
+#define ASIC3_INTMASK_MASK2       (1 << 4)
+#define ASIC3_INTMASK_MASK3       (1 << 5)
+#define ASIC3_INTMASK_MASK4       (1 << 6)
+#define ASIC3_INTMASK_MASK5       (1 << 7)
+
+#define ASIC3_INTR_PERIPHERAL_A   (1 << 0)
+#define ASIC3_INTR_PERIPHERAL_B   (1 << 1)
+#define ASIC3_INTR_PERIPHERAL_C   (1 << 2)
+#define ASIC3_INTR_PERIPHERAL_D   (1 << 3)
+#define ASIC3_INTR_LED0           (1 << 4)
+#define ASIC3_INTR_LED1           (1 << 5)
+#define ASIC3_INTR_LED2           (1 << 6)
+#define ASIC3_INTR_SPI            (1 << 7)
+#define ASIC3_INTR_SMBUS          (1 << 8)
+#define ASIC3_INTR_OWM            (1 << 9)
+
+#define ASIC3_INTR_CPS(x)         ((x)&0x0f)    /* 4 bits, max 14 */
+#define ASIC3_INTR_CPS_SET        ( 1 << 4 )    /* Time base enable */
+
+
+/* Basic control of the SD ASIC */
+#define _IPAQ_ASIC3_SDHWCTRL_Base	0x0E00
+
+#define _IPAQ_ASIC3_SDHWCTRL_SDConf    0x00
+#define IPAQ_ASIC3_SDHWCTRL_SDConf(_b)    IPAQ_ASIC3( _b, u8, SDHWCTRL, SDConf )
+
+#define ASIC3_SDHWCTRL_SUSPEND    (1 << 0)  /* 1=suspend all SD operations */
+#define ASIC3_SDHWCTRL_CLKSEL     (1 << 1)  /* 1=SDICK, 0=HCLK */
+#define ASIC3_SDHWCTRL_PCLR       (1 << 2)  /* All registers of SDIO cleared */
+#define ASIC3_SDHWCTRL_LEVCD      (1 << 3)  /* Level of SD card detection: 1:high, 0:low */
+#define ASIC3_SDHWCTRL_LEVWP      (1 << 4)  /* Level of SD card write protection: 1=low, 0=high */
+#define ASIC3_SDHWCTRL_SDLED      (1 << 5)  /* SD card LED signal 1=enable, 0=disable */
+#define ASIC3_SDHWCTRL_SDPWR      (1 << 6)  /* SD card power supply control 1=enable */
+
+
+/* This is a pointer to an array of 12 u32 values - but only the lower 2 bytes matter */
+/* Use it as "IPAQ_ASIC3_HWPROTECT_ARRAY[x]" */
+
+#define _IPAQ_ASIC3_HWPROTECT_Base	0x1000
+#define IPAQ_ASIC3_HWPROTECT_ARRAY  ((volatile u32*)(_IPAQ_ASIC3_Base + _IPAQ_ASIC3_HWPROTECT_Base))
+#define HWPROTECT_ARRAY_LEN 12
+#define HWPROTECT_ARRAY_VALUES {0x4854,0x432d,0x5344,0x494f,0x2050,0x2f4e,0x3a33,0x3048,0x3830,0x3032,0x382d,0x3030}
+
+
+#define _IPAQ_ASIC3_EXTCF_Base		0x1100
+
+#define _IPAQ_ASIC3_EXTCF_Select         0x00
+#define _IPAQ_ASIC3_EXTCF_Reset          0x04
+
+#define IPAQ_ASIC3_EXTCF_Select(_b)    IPAQ_ASIC3( _b, u16, EXTCF, Select )
+#define IPAQ_ASIC3_EXTCF_Reset(_b)     IPAQ_ASIC3( _b, u16, EXTCF, Reset )
+
+#define ASIC3_EXTCF_SMOD0	         (1 << 0)  /* slot number of mode 0 */
+#define ASIC3_EXTCF_SMOD1	         (1 << 1)  /* slot number of mode 1 */
+#define ASIC3_EXTCF_SMOD2	         (1 << 2)  /* slot number of mode 2 */
+#define ASIC3_EXTCF_OWM_EN	         (1 << 4)  /* enable onewire module */
+#define ASIC3_EXTCF_OWM_SMB	         (1 << 5)  /* OWM bus selection */
+#define ASIC3_EXTCF_OWM_RESET            (1 << 6)  /* undocumented, used by OWM and CF */
+#define ASIC3_EXTCF_CF0_SLEEP_MODE       (1 << 7)  /* CF0 sleep state control */
+#define ASIC3_EXTCF_CF1_SLEEP_MODE       (1 << 8)  /* CF1 sleep state control */
+#define ASIC3_EXTCF_CF0_PWAIT_EN         (1 << 10)  /* CF0 PWAIT_n control */
+#define ASIC3_EXTCF_CF1_PWAIT_EN         (1 << 11)  /* CF1 PWAIT_n control */
+#define ASIC3_EXTCF_CF0_BUF_EN           (1 << 12)  /* CF0 buffer control */
+#define ASIC3_EXTCF_CF1_BUF_EN           (1 << 13)  /* CF1 buffer control */
+#define ASIC3_EXTCF_SD_MEM_ENABLE        (1 << 14)
+#define ASIC3_EXTCF_CF_SLEEP             (1 << 15)  /* CF sleep mode control */
+
+/*****************************************************************************
+ *  The Onewire interface registers
+ *
+ *  OWM_CMD
+ *  OWM_DAT
+ *  OWM_INTR
+ *  OWM_INTEN
+ *  OWM_CLKDIV
+ *
+ *****************************************************************************/
+
+#define _IPAQ_ASIC3_OWM_Base		0xC00
+
+#define _IPAQ_ASIC3_OWM_CMD         0x00
+#define _IPAQ_ASIC3_OWM_DAT         0x04
+#define _IPAQ_ASIC3_OWM_INTR        0x08
+#define _IPAQ_ASIC3_OWM_INTEN       0x0C
+#define _IPAQ_ASIC3_OWM_CLKDIV      0x10
+
+#define ASIC3_OWM_CMD_ONEWR         (1 << 0)
+#define ASIC3_OWM_CMD_SRA           (1 << 1)
+#define ASIC3_OWM_CMD_DQO           (1 << 2)
+#define ASIC3_OWM_CMD_DQI           (1 << 3)
+
+#define ASIC3_OWM_INTR_PD          (1 << 0)
+#define ASIC3_OWM_INTR_PDR         (1 << 1)
+#define ASIC3_OWM_INTR_TBE         (1 << 2)
+#define ASIC3_OWM_INTR_TEMP        (1 << 3)
+#define ASIC3_OWM_INTR_RBF         (1 << 4)
+
+#define ASIC3_OWM_INTEN_EPD        (1 << 0)
+#define ASIC3_OWM_INTEN_IAS        (1 << 1)
+#define ASIC3_OWM_INTEN_ETBE       (1 << 2)
+#define ASIC3_OWM_INTEN_ETMT       (1 << 3)
+#define ASIC3_OWM_INTEN_ERBF       (1 << 4)
+
+#define ASIC3_OWM_CLKDIV_PRE       (3 << 0) /* two bits wide at bit position 0 */
+#define ASIC3_OWM_CLKDIV_DIV       (7 << 2) /* 3 bits wide at bit position 2 */
+
+
+/*****************************************************************************
+ *  The SD configuration registers are at a completely different location
+ *  in memory.  They are divided into three sets of registers:
+ *
+ *  SD_CONFIG         Core configuration register
+ *  SD_CTRL           Control registers for SD operations
+ *  SDIO_CTRL         Control registers for SDIO operations
+ *
+ *****************************************************************************/
+
+#define IPAQ_ASIC3_SD_CONFIG(_b, s,x)   \
+     (*((volatile s *) ((_b) + _IPAQ_ASIC3_SD_CONFIG_Base + (_IPAQ_ASIC3_SD_CONFIG_ ## x))))
+
+#define _IPAQ_ASIC3_SD_CONFIG_Base            0x0400    // Assumes 32 bit addressing
+
+#define _IPAQ_ASIC3_SD_CONFIG_Command           0x08   /* R/W: Command */
+#define _IPAQ_ASIC3_SD_CONFIG_Addr0             0x20   /* [9:31] SD Control Register Base Address */
+#define _IPAQ_ASIC3_SD_CONFIG_Addr1             0x24   /* [9:31] SD Control Register Base Address */
+#define _IPAQ_ASIC3_SD_CONFIG_IntPin            0x78   /* R/O: interrupt assigned to pin */
+#define _IPAQ_ASIC3_SD_CONFIG_ClkStop           0x80   /* Set to 0x1f to clock SD controller, 0 otherwise. */
+							/* at 0x82 - Gated Clock Control */
+#define _IPAQ_ASIC3_SD_CONFIG_ClockMode         0x84   /* Control clock of SD controller */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_PinStatus    0x88   /* R/0: read status of SD pins */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_Power1       0x90   /* Power1 - manual power control */
+							/* Power2 is at 0x92 - auto power up after card inserted */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_Power3       0x94   /* auto power down when card removed */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_CardDetect   0x98   /* */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_Slot         0xA0   /* R/O: define support slot number */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk1  0x1E0  /* Could be used for gated clock (don't use) */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk2  0x1E2  /* Could be used for gated clock (don't use) */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_GPIO_OutAndEnable  0x1E8  /* GPIO Output Reg. , at 0x1EA - GPIO Output Enable Reg. */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_GPIO_Status  0x1EC  /* GPIO Status Reg. */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk3  0x1F0  /* Bit 1: double buffer/single buffer */
+
+#define IPAQ_ASIC3_SD_CONFIG_Command(_b)           IPAQ_ASIC3_SD_CONFIG(_b, u16, Command )
+#define IPAQ_ASIC3_SD_CONFIG_Addr0(_b)             IPAQ_ASIC3_SD_CONFIG(_b, u16, Addr0 )
+#define IPAQ_ASIC3_SD_CONFIG_Addr1(_b)             IPAQ_ASIC3_SD_CONFIG(_b, u16, Addr1 )
+#define IPAQ_ASIC3_SD_CONFIG_IntPin(_b)            IPAQ_ASIC3_SD_CONFIG(_b, u8, IntPin )
+#define IPAQ_ASIC3_SD_CONFIG_ClkStop(_b)           IPAQ_ASIC3_SD_CONFIG(_b, u8, ClkStop )
+#define IPAQ_ASIC3_SD_CONFIG_ClockMode(_b)         IPAQ_ASIC3_SD_CONFIG(_b, u8, ClockMode )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_PinStatus(_b)    IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_PinStatus )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_Power1(_b)       IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_Power1 )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_Power3(_b)       IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_Power3 )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_CardDetect(_b)   IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_CardDetect )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_Slot(_b)         IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_Slot )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk1(_b)  IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_ExtGateClk1 )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk3(_b)  IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_ExtGateClk3 )
+
+#define SD_CONFIG_
+
+#define SD_CONFIG_COMMAND_MAE                (1<<1)    /* Memory access enable (set to 1 to access SD Controller) */
+
+#define SD_CONFIG_CLK_ENABLE_ALL             0x1f
+
+#define SD_CONFIG_POWER1_PC_33V              0x0200    /* Set for 3.3 volts */
+#define SD_CONFIG_POWER1_PC_OFF              0x0000    /* Turn off power */
+
+#define SD_CONFIG_CARDDETECTMODE_CLK           ((x)&0x3) /* two bits - number of cycles for card detection */
+
+
+#define _IPAQ_ASIC3_SD_CTRL_Base            0x1000
+
+#define IPAQ_ASIC3_SD(_b, s,x)   \
+     (*((volatile s *) ((_b) + _IPAQ_ASIC3_SD_CTRL_Base + (_IPAQ_ASIC3_SD_CTRL_ ## x))))
+
+#define _IPAQ_ASIC3_SD_CTRL_Cmd                  0x00
+#define _IPAQ_ASIC3_SD_CTRL_Arg0                 0x08
+#define _IPAQ_ASIC3_SD_CTRL_Arg1                 0x0C
+#define _IPAQ_ASIC3_SD_CTRL_StopInternal         0x10
+#define _IPAQ_ASIC3_SD_CTRL_TransferSectorCount  0x14
+#define _IPAQ_ASIC3_SD_CTRL_Response0            0x18
+#define _IPAQ_ASIC3_SD_CTRL_Response1            0x1C
+#define _IPAQ_ASIC3_SD_CTRL_Response2            0x20
+#define _IPAQ_ASIC3_SD_CTRL_Response3            0x24
+#define _IPAQ_ASIC3_SD_CTRL_Response4            0x28
+#define _IPAQ_ASIC3_SD_CTRL_Response5            0x2C
+#define _IPAQ_ASIC3_SD_CTRL_Response6            0x30
+#define _IPAQ_ASIC3_SD_CTRL_Response7            0x34
+#define _IPAQ_ASIC3_SD_CTRL_CardStatus           0x38
+#define _IPAQ_ASIC3_SD_CTRL_BufferCtrl           0x3C
+#define _IPAQ_ASIC3_SD_CTRL_IntMaskCard          0x40
+#define _IPAQ_ASIC3_SD_CTRL_IntMaskBuffer        0x44
+#define _IPAQ_ASIC3_SD_CTRL_CardClockCtrl        0x48
+#define _IPAQ_ASIC3_SD_CTRL_MemCardXferDataLen   0x4C
+#define _IPAQ_ASIC3_SD_CTRL_MemCardOptionSetup   0x50
+#define _IPAQ_ASIC3_SD_CTRL_ErrorStatus0         0x58
+#define _IPAQ_ASIC3_SD_CTRL_ErrorStatus1         0x5C
+#define _IPAQ_ASIC3_SD_CTRL_DataPort             0x60
+#define _IPAQ_ASIC3_SD_CTRL_TransactionCtrl      0x68
+#define _IPAQ_ASIC3_SD_CTRL_SoftwareReset        0x1C0
+
+#define IPAQ_ASIC3_SD_CTRL_Cmd(_b)                  IPAQ_ASIC3_SD( _b, u16, Cmd )   /* */
+#define IPAQ_ASIC3_SD_CTRL_Arg0(_b)                 IPAQ_ASIC3_SD( _b, u16, Arg0 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_Arg1(_b)                 IPAQ_ASIC3_SD( _b, u16, Arg1 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_StopInternal(_b)         IPAQ_ASIC3_SD( _b, u16, StopInternal )   /* */
+#define IPAQ_ASIC3_SD_CTRL_TransferSectorCount(_b)  IPAQ_ASIC3_SD( _b, u16, TransferSectorCount )   /* */
+#define IPAQ_ASIC3_SD_CTRL_Response0(_b)            IPAQ_ASIC3_SD( _b, u16, Response0 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_Response1(_b)            IPAQ_ASIC3_SD( _b, u16, Response1 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_Response2(_b)            IPAQ_ASIC3_SD( _b, u16, Response2 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_Response3(_b)            IPAQ_ASIC3_SD( _b, u16, Response3 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_Response4(_b)            IPAQ_ASIC3_SD( _b, u16, Response4 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_Response5(_b)            IPAQ_ASIC3_SD( _b, u16, Response5 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_Response6(_b)            IPAQ_ASIC3_SD( _b, u16, Response6 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_Response7(_b)            IPAQ_ASIC3_SD( _b, u16, Response7 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_CardStatus(_b)           IPAQ_ASIC3_SD( _b, u16, CardStatus )   /* */
+#define IPAQ_ASIC3_SD_CTRL_BufferCtrl(_b)           IPAQ_ASIC3_SD( _b, u16, BufferCtrl )   /* and error status*/
+#define IPAQ_ASIC3_SD_CTRL_IntMaskCard(_b)          IPAQ_ASIC3_SD( _b, u16, IntMaskCard )   /* */
+#define IPAQ_ASIC3_SD_CTRL_IntMaskBuffer(_b)        IPAQ_ASIC3_SD( _b, u16, IntMaskBuffer )   /* */
+#define IPAQ_ASIC3_SD_CTRL_CardClockCtrl(_b)        IPAQ_ASIC3_SD( _b, u16, CardClockCtrl )   /* */
+#define IPAQ_ASIC3_SD_CTRL_MemCardXferDataLen(_b)   IPAQ_ASIC3_SD( _b, u16, MemCardXferDataLen )   /* */
+#define IPAQ_ASIC3_SD_CTRL_MemCardOptionSetup(_b)   IPAQ_ASIC3_SD( _b, u16, MemCardOptionSetup )   /* */
+#define IPAQ_ASIC3_SD_CTRL_ErrorStatus0(_b)         IPAQ_ASIC3_SD( _b, u16, ErrorStatus0 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_ErrorStatus1(_b)         IPAQ_ASIC3_SD( _b, u16, ErrorStatus1 )   /* */
+#define IPAQ_ASIC3_SD_CTRL_DataPort(_b)             IPAQ_ASIC3_SD( _b, u16, DataPort )   /* */
+#define IPAQ_ASIC3_SD_CTRL_TransactionCtrl(_b)      IPAQ_ASIC3_SD( _b, u16, TransactionCtrl )   /* */
+#define IPAQ_ASIC3_SD_CTRL_SoftwareReset(_b)        IPAQ_ASIC3_SD( _b, u16, SoftwareReset )   /* */
+
+#define SD_CTRL_SOFTWARE_RESET_CLEAR            (1<<0)
+
+#define SD_CTRL_TRANSACTIONCONTROL_SET          (1<<8) // 0x0100
+
+#define SD_CTRL_CARDCLOCKCONTROL_FOR_SD_CARD    (1<<15)// 0x8000
+#define SD_CTRL_CARDCLOCKCONTROL_ENABLE_CLOCK   (1<<8) // 0x0100
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_512    (1<<7) // 0x0080
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_256    (1<<6) // 0x0040
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_128    (1<<5) // 0x0020
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_64     (1<<4) // 0x0010
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_32     (1<<3) // 0x0008
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_16     (1<<2) // 0x0004
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_8      (1<<1) // 0x0002
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_4      (1<<0) // 0x0001
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_2      (0<<0) // 0x0000
+
+#define MEM_CARD_OPTION_REQUIRED                   0x000e
+#define MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(x)   (((x)&0x0f)<<4)      /* Four bits */
+#define MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT      (1<<14) // 0x4000
+#define MEM_CARD_OPTION_DATA_XFR_WIDTH_1           (1<<15) // 0x8000
+#define MEM_CARD_OPTION_DATA_XFR_WIDTH_4           (0<<15) //~0x8000
+
+#define SD_CTRL_COMMAND_INDEX(x)                   ((x)&0x3f)           /* 0=CMD0, 1=CMD1, ..., 63=CMD63 */
+#define SD_CTRL_COMMAND_TYPE_CMD                   (0 << 6)
+#define SD_CTRL_COMMAND_TYPE_ACMD                  (1 << 6)
+#define SD_CTRL_COMMAND_TYPE_AUTHENTICATION        (2 << 6)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_NORMAL       (0 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1       (4 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1B      (5 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R2       (6 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3       (7 << 8)
+#define SD_CTRL_COMMAND_DATA_PRESENT               (1 << 11)
+#define SD_CTRL_COMMAND_TRANSFER_READ              (1 << 12)
+#define SD_CTRL_COMMAND_TRANSFER_WRITE             (0 << 12)
+#define SD_CTRL_COMMAND_MULTI_BLOCK                (1 << 13)
+#define SD_CTRL_COMMAND_SECURITY_CMD               (1 << 14)
+
+#define SD_CTRL_STOP_INTERNAL_ISSSUE_CMD12         (1 << 0)
+#define SD_CTRL_STOP_INTERNAL_AUTO_ISSUE_CMD12     (1 << 8)
+
+#define SD_CTRL_CARDSTATUS_RESPONSE_END            (1 << 0)
+#define SD_CTRL_CARDSTATUS_RW_END                  (1 << 2)
+#define SD_CTRL_CARDSTATUS_CARD_REMOVED_0          (1 << 3)
+#define SD_CTRL_CARDSTATUS_CARD_INSERTED_0         (1 << 4)
+#define SD_CTRL_CARDSTATUS_SIGNAL_STATE_PRESENT_0  (1 << 5)
+#define SD_CTRL_CARDSTATUS_WRITE_PROTECT           (1 << 7)
+#define SD_CTRL_CARDSTATUS_CARD_REMOVED_3          (1 << 8)
+#define SD_CTRL_CARDSTATUS_CARD_INSERTED_3         (1 << 9)
+#define SD_CTRL_CARDSTATUS_SIGNAL_STATE_PRESENT_3  (1 << 10)
+
+#define SD_CTRL_BUFFERSTATUS_CMD_INDEX_ERROR       (1 << 0) // 0x0001
+#define SD_CTRL_BUFFERSTATUS_CRC_ERROR             (1 << 1) // 0x0002
+#define SD_CTRL_BUFFERSTATUS_STOP_BIT_END_ERROR    (1 << 2) // 0x0004
+#define SD_CTRL_BUFFERSTATUS_DATA_TIMEOUT          (1 << 3) // 0x0008
+#define SD_CTRL_BUFFERSTATUS_BUFFER_OVERFLOW       (1 << 4) // 0x0010
+#define SD_CTRL_BUFFERSTATUS_BUFFER_UNDERFLOW      (1 << 5) // 0x0020
+#define SD_CTRL_BUFFERSTATUS_CMD_TIMEOUT           (1 << 6) // 0x0040
+#define SD_CTRL_BUFFERSTATUS_UNK7                  (1 << 7) // 0x0080
+#define SD_CTRL_BUFFERSTATUS_BUFFER_READ_ENABLE    (1 << 8) // 0x0100
+#define SD_CTRL_BUFFERSTATUS_BUFFER_WRITE_ENABLE   (1 << 9) // 0x0200
+#define SD_CTRL_BUFFERSTATUS_ILLEGAL_FUNCTION      (1 << 13)// 0x2000
+#define SD_CTRL_BUFFERSTATUS_CMD_BUSY              (1 << 14)// 0x4000
+#define SD_CTRL_BUFFERSTATUS_ILLEGAL_ACCESS        (1 << 15)// 0x8000
+
+#define SD_CTRL_INTMASKCARD_RESPONSE_END           (1 << 0) // 0x0001
+#define SD_CTRL_INTMASKCARD_RW_END                 (1 << 2) // 0x0004
+#define SD_CTRL_INTMASKCARD_CARD_REMOVED_0         (1 << 3) // 0x0008
+#define SD_CTRL_INTMASKCARD_CARD_INSERTED_0        (1 << 4) // 0x0010
+#define SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_0 (1 << 5) // 0x0020
+#define SD_CTRL_INTMASKCARD_UNK6                   (1 << 6) // 0x0040
+#define SD_CTRL_INTMASKCARD_WRITE_PROTECT          (1 << 7) // 0x0080
+#define SD_CTRL_INTMASKCARD_CARD_REMOVED_3         (1 << 8) // 0x0100
+#define SD_CTRL_INTMASKCARD_CARD_INSERTED_3        (1 << 9) // 0x0200
+#define SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_3 (1 << 10)// 0x0400
+
+#define SD_CTRL_INTMASKBUFFER_CMD_INDEX_ERROR      (1 << 0) // 0x0001
+#define SD_CTRL_INTMASKBUFFER_CRC_ERROR            (1 << 1) // 0x0002
+#define SD_CTRL_INTMASKBUFFER_STOP_BIT_END_ERROR   (1 << 2) // 0x0004
+#define SD_CTRL_INTMASKBUFFER_DATA_TIMEOUT         (1 << 3) // 0x0008
+#define SD_CTRL_INTMASKBUFFER_BUFFER_OVERFLOW      (1 << 4) // 0x0010
+#define SD_CTRL_INTMASKBUFFER_BUFFER_UNDERFLOW     (1 << 5) // 0x0020
+#define SD_CTRL_INTMASKBUFFER_CMD_TIMEOUT          (1 << 6) // 0x0040
+#define SD_CTRL_INTMASKBUFFER_UNK7                 (1 << 7) // 0x0080
+#define SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE   (1 << 8) // 0x0100
+#define SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE  (1 << 9) // 0x0200
+#define SD_CTRL_INTMASKBUFFER_ILLEGAL_FUNCTION     (1 << 13)// 0x2000
+#define SD_CTRL_INTMASKBUFFER_CMD_BUSY             (1 << 14)// 0x4000
+#define SD_CTRL_INTMASKBUFFER_ILLEGAL_ACCESS       (1 << 15)// 0x8000
+
+#define SD_CTRL_DETAIL0_RESPONSE_CMD_ERROR                   (1 << 0) // 0x0001
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_RESPONSE_NON_CMD12 (1 << 2) // 0x0004
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_RESPONSE_CMD12     (1 << 3) // 0x0008
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_READ_DATA          (1 << 4) // 0x0010
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_WRITE_CRC_STATUS   (1 << 5) // 0x0020
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_RESPONSE_NON_CMD12     (1 << 8) // 0x0100
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_RESPONSE_CMD12         (1 << 9) // 0x0200
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_READ_DATA              (1 << 10)// 0x0400
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_WRITE_CMD              (1 << 11)// 0x0800
+
+#define SD_CTRL_DETAIL1_NO_CMD_RESPONSE                      (1 << 0) // 0x0001
+#define SD_CTRL_DETAIL1_TIMEOUT_READ_DATA                    (1 << 4) // 0x0010
+#define SD_CTRL_DETAIL1_TIMEOUT_CRS_STATUS                   (1 << 5) // 0x0020
+#define SD_CTRL_DETAIL1_TIMEOUT_CRC_BUSY                     (1 << 6) // 0x0040
+
+#define _IPAQ_ASIC3_SDIO_CTRL_Base          0x1200
+
+#define IPAQ_ASIC3_SDIO(_b, s,x)   \
+     (*((volatile s *) ((_b) + _IPAQ_ASIC3_SDIO_CTRL_Base + (_IPAQ_ASIC3_SDIO_CTRL_ ## x))))
+
+#define _IPAQ_ASIC3_SDIO_CTRL_Cmd                  0x00
+#define _IPAQ_ASIC3_SDIO_CTRL_CardPortSel          0x04
+#define _IPAQ_ASIC3_SDIO_CTRL_Arg0                 0x08
+#define _IPAQ_ASIC3_SDIO_CTRL_Arg1                 0x0C
+#define _IPAQ_ASIC3_SDIO_CTRL_TransferBlockCount   0x14
+#define _IPAQ_ASIC3_SDIO_CTRL_Response0            0x18
+#define _IPAQ_ASIC3_SDIO_CTRL_Response1            0x1C
+#define _IPAQ_ASIC3_SDIO_CTRL_Response2            0x20
+#define _IPAQ_ASIC3_SDIO_CTRL_Response3            0x24
+#define _IPAQ_ASIC3_SDIO_CTRL_Response4            0x28
+#define _IPAQ_ASIC3_SDIO_CTRL_Response5            0x2C
+#define _IPAQ_ASIC3_SDIO_CTRL_Response6            0x30
+#define _IPAQ_ASIC3_SDIO_CTRL_Response7            0x34
+#define _IPAQ_ASIC3_SDIO_CTRL_CardStatus           0x38
+#define _IPAQ_ASIC3_SDIO_CTRL_BufferCtrl           0x3C
+#define _IPAQ_ASIC3_SDIO_CTRL_IntMaskCard          0x40
+#define _IPAQ_ASIC3_SDIO_CTRL_IntMaskBuffer        0x44
+#define _IPAQ_ASIC3_SDIO_CTRL_CardXferDataLen      0x4C
+#define _IPAQ_ASIC3_SDIO_CTRL_CardOptionSetup      0x50
+#define _IPAQ_ASIC3_SDIO_CTRL_ErrorStatus0         0x54
+#define _IPAQ_ASIC3_SDIO_CTRL_ErrorStatus1         0x58
+#define _IPAQ_ASIC3_SDIO_CTRL_DataPort             0x60
+#define _IPAQ_ASIC3_SDIO_CTRL_TransactionCtrl      0x68
+#define _IPAQ_ASIC3_SDIO_CTRL_CardIntCtrl          0x6C
+#define _IPAQ_ASIC3_SDIO_CTRL_ClocknWaitCtrl       0x70
+#define _IPAQ_ASIC3_SDIO_CTRL_HostInformation      0x74
+#define _IPAQ_ASIC3_SDIO_CTRL_ErrorCtrl            0x78
+#define _IPAQ_ASIC3_SDIO_CTRL_LEDCtrl              0x7C
+#define _IPAQ_ASIC3_SDIO_CTRL_SoftwareReset        0x1C0
+
+#define IPAQ_ASIC3_SDIO_CTRL_Cmd(_b)                  IPAQ_ASIC3_SDIO( _b, u16, Cmd )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardPortSel(_b)          IPAQ_ASIC3_SDIO( _b, u16, CardPortSel )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Arg0(_b)                 IPAQ_ASIC3_SDIO( _b, u16, Arg0 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Arg1(_b)                 IPAQ_ASIC3_SDIO( _b, u16, Arg1 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_TransferBlockCount(_b)   IPAQ_ASIC3_SDIO( _b, u16, TransferBlockCount )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response0(_b)            IPAQ_ASIC3_SDIO( _b, u16, Response0 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response1(_b)            IPAQ_ASIC3_SDIO( _b, u16, Response1 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response2(_b)            IPAQ_ASIC3_SDIO( _b, u16, Response2 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response3(_b)            IPAQ_ASIC3_SDIO( _b, u16, Response3 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response4(_b)            IPAQ_ASIC3_SDIO( _b, u16, Response4 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response5(_b)            IPAQ_ASIC3_SDIO( _b, u16, Response5 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response6(_b)            IPAQ_ASIC3_SDIO( _b, u16, Response6 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response7(_b)            IPAQ_ASIC3_SDIO( _b, u16, Response7 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardStatus(_b)           IPAQ_ASIC3_SDIO( _b, u16, CardStatus )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_BufferCtrl(_b)           IPAQ_ASIC3_SDIO( _b, u16, BufferCtrl )   /* and error status*/
+#define IPAQ_ASIC3_SDIO_CTRL_IntMaskCard(_b)          IPAQ_ASIC3_SDIO( _b, u16, IntMaskCard )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_IntMaskBuffer(_b)        IPAQ_ASIC3_SDIO( _b, u16, IntMaskBuffer )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardXferDataLen(_b)      IPAQ_ASIC3_SDIO( _b, u16, CardXferDataLen )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardOptionSetup(_b)      IPAQ_ASIC3_SDIO( _b, u16, CardOptionSetup )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ErrorStatus0(_b)         IPAQ_ASIC3_SDIO( _b, u16, ErrorStatus0 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ErrorStatus1(_b)         IPAQ_ASIC3_SDIO( _b, u16, ErrorStatus1 )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_DataPort(_b)             IPAQ_ASIC3_SDIO( _b, u16, DataPort )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_TransactionCtrl(_b)      IPAQ_ASIC3_SDIO( _b, u16, TransactionCtrl )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardIntCtrl(_b)          IPAQ_ASIC3_SDIO( _b, u16, CardIntCtrl )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ClocknWaitCtrl(_b)       IPAQ_ASIC3_SDIO( _b, u16, ClocknWaitCtrl )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_HostInformation(_b)      IPAQ_ASIC3_SDIO( _b, u16, HostInformation )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ErrorCtrl(_b)            IPAQ_ASIC3_SDIO( _b, u16, ErrorCtrl )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_LEDCtrl(_b)              IPAQ_ASIC3_SDIO( _b, u16, LEDCtrl )   /* */
+#define IPAQ_ASIC3_SDIO_CTRL_SoftwareReset(_b)        IPAQ_ASIC3_SDIO( _b, u16, SoftwareReset )   /* */
+
+#define IPAQ_ASIC3_MAP_SIZE	     0x2000
+
+#endif
Index: linux-2.6.24/include/linux/gpiodev.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/linux/gpiodev.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,44 @@
+#ifndef __GPIODEV_H
+#define __GPIODEV_H
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/gpio.h>
+
+/* Interface */
+
+/* This structure must be first member of device platform_data structure
+   of a device which provides gpiodev interface. All method pointers
+   must be non-NULL, so stubs must be used for non-implemented ones. */
+struct gpiodev_ops {
+        int (*get)(struct device *this, unsigned gpio_no);
+        void (*set)(struct device *this, unsigned gpio_no, int val);
+        int (*to_irq)(struct device *this, unsigned gpio_no);
+};
+
+/* Generalized GPIO structure */
+
+struct gpio {
+	struct device *gpio_dev;
+	unsigned gpio_no;
+};
+
+/* API functions */
+
+static inline int gpiodev_get_value(struct gpio *gpio)
+{
+	struct gpiodev_ops *ops = gpio->gpio_dev->platform_data;
+	return ops->get(gpio->gpio_dev, gpio->gpio_no);
+}
+static inline void gpiodev_set_value(struct gpio *gpio, int val)
+{
+	struct gpiodev_ops *ops = gpio->gpio_dev->platform_data;
+	ops->set(gpio->gpio_dev, gpio->gpio_no, val);
+}
+static inline int gpiodev_to_irq(struct gpio *gpio)
+{
+	struct gpiodev_ops *ops = gpio->gpio_dev->platform_data;
+	return ops->to_irq(gpio->gpio_dev, gpio->gpio_no);
+}
+
+#endif /* __GPIODEV_H */
Index: linux-2.6.24/include/linux/input_pda.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/linux/input_pda.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,47 @@
+#ifndef _INPUT_PDA_H
+#define _INPUT_PDA_H
+
+/*
+ * This is temporary virtual button key codes map
+ * for keyboardless handheld computers.
+ * Its purpose is to provide map common to all devices
+ * and known to work with current software and its bugs
+ * and misfeatures. Once issues with the software are
+ * solved, codes from input.h will be used directly
+ * (missing key definitions will be added).
+ */
+
+/* Some directly usable keycodes:
+KEY_POWER - Power/suspend button
+KEY_ENTER - Enter/Action/Central button on joypad
+KEY_UP
+KEY_DOWN
+KEY_LEFT
+KEY_RIGHT
+*/
+
+/* XXX Instead of using any values in include/linux/input.h, we have to use
+       use values < 128 due to some munging that kdrive does to get keystrokes.
+       When kdrive gets its key events from evdev instead of the console,
+       we should be able to switch to using input.h values and get rid of
+       xmodmap. */
+
+#define _KEY_APP1	KEY_F9		// xmodmap sees 67 + 8 = 75
+#define _KEY_APP2	KEY_F10		// xmodmap 76
+#define _KEY_APP3	KEY_F11		// xmodmap 95
+#define _KEY_APP4	KEY_F12		// xmodmap 96
+
+#define _KEY_RECORD	KEY_RO
+
+/* It is highly recommended to use exactly 4 codes above for
+   4 buttons the device has. This will ensure that console and
+   framebuffer applications (e.g. games) will work ok on all
+   devices. If you'd like more distinguishable names, following
+   convenience defines are provided, suiting many devices. */
+
+#define _KEY_CALENDAR	_KEY_APP1
+#define _KEY_CONTACTS	_KEY_APP2
+#define _KEY_MAIL	_KEY_APP3
+#define _KEY_HOMEPAGE	_KEY_APP4
+
+#endif
Index: linux-2.6.24/include/linux/soc/asic3_base.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/linux/soc/asic3_base.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,104 @@
+#include <asm/types.h>
+#include <linux/gpiodev.h>
+
+/* Private API - for ASIC3 devices internal use only */
+#define HDR_IPAQ_ASIC3_ACTION(ACTION,action,fn,FN)                  \
+u32  asic3_get_gpio_ ## action ## _ ## fn (struct device *dev);      \
+void asic3_set_gpio_ ## action ## _ ## fn (struct device *dev, u32 bits, u32 val);
+
+#define HDR_IPAQ_ASIC3_FN(fn,FN)					\
+	HDR_IPAQ_ASIC3_ACTION ( MASK,mask,fn,FN)			\
+	HDR_IPAQ_ASIC3_ACTION ( DIR, dir, fn, FN)			\
+	HDR_IPAQ_ASIC3_ACTION ( OUT, out, fn, FN)			\
+	HDR_IPAQ_ASIC3_ACTION ( LEVELTRI, trigtype, fn, FN)		\
+	HDR_IPAQ_ASIC3_ACTION ( RISING, rising, fn, FN)			\
+	HDR_IPAQ_ASIC3_ACTION ( LEVEL, triglevel, fn, FN)		\
+	HDR_IPAQ_ASIC3_ACTION ( SLEEP_MASK, sleepmask, fn, FN)		\
+	HDR_IPAQ_ASIC3_ACTION ( SLEEP_OUT, sleepout, fn, FN)		\
+	HDR_IPAQ_ASIC3_ACTION ( BATT_FAULT_OUT, battfaultout, fn, FN)	\
+	HDR_IPAQ_ASIC3_ACTION ( INT_STATUS, intstatus, fn, FN)		\
+	HDR_IPAQ_ASIC3_ACTION ( ALT_FUNCTION, alt_fn, fn, FN)		\
+	HDR_IPAQ_ASIC3_ACTION ( SLEEP_CONF, sleepconf, fn, FN)		\
+	HDR_IPAQ_ASIC3_ACTION ( STATUS, status, fn, FN)
+
+/* Public API */
+
+#define ASIC3_GPIOA_IRQ_BASE	0
+#define ASIC3_GPIOB_IRQ_BASE	16
+#define ASIC3_GPIOC_IRQ_BASE	32
+#define ASIC3_GPIOD_IRQ_BASE	48
+#define ASIC3_LED0_IRQ		64
+#define ASIC3_LED1_IRQ		65
+#define ASIC3_LED2_IRQ		66
+#define ASIC3_SPI_IRQ		67
+#define ASIC3_SMBUS_IRQ		68
+#define ASIC3_OWM_IRQ		69
+
+#define ASIC3_NR_GPIO_IRQS	64	/* 16 bits each GPIO A...D banks */
+#define ASIC3_NR_IRQS		(ASIC3_OWM_IRQ + 1)
+
+extern int asic3_irq_base(struct device *dev);
+
+extern void asic3_write_register(struct device *dev, unsigned int reg,
+                                 u32 value);
+extern u32  asic3_read_register(struct device *dev, unsigned int reg);
+
+/* old clock api */
+extern void asic3_set_clock_sel(struct device *dev, u32 bits, u32 val);
+extern u32  asic3_get_clock_cdex(struct device *dev);
+extern void asic3_set_clock_cdex(struct device *dev, u32 bits, u32 val);
+
+extern void asic3_set_extcf_select(struct device *dev, u32 bits, u32 val);
+extern void asic3_set_extcf_reset(struct device *dev, u32 bits, u32 val);
+extern void asic3_set_sdhwctrl(struct device *dev, u32 bits, u32 val);
+
+extern void asic3_set_led(struct device *dev, int led_num, int duty_time,
+                          int cycle_time, int timebase);
+
+extern int asic3_register_mmc(struct device *dev);
+extern int asic3_unregister_mmc(struct device *dev);
+
+/* Accessors for GPIO banks */
+HDR_IPAQ_ASIC3_FN(a, A)
+HDR_IPAQ_ASIC3_FN(b, B)
+HDR_IPAQ_ASIC3_FN(c, C)
+HDR_IPAQ_ASIC3_FN(d, D)
+
+#define _IPAQ_ASIC3_GPIO_BANK_A      0
+#define _IPAQ_ASIC3_GPIO_BANK_B      1
+#define _IPAQ_ASIC3_GPIO_BANK_C      2
+#define _IPAQ_ASIC3_GPIO_BANK_D      3
+
+#define ASIC3_GPIO_bit(gpio) (1 << (gpio & 0xf))
+
+extern int asic3_get_gpio_bit(struct device *dev, int gpio);
+extern void asic3_set_gpio_bit(struct device *dev, int gpio, int val);
+extern int asic3_gpio_get_value(struct device *dev, unsigned gpio);
+extern void asic3_gpio_set_value(struct device *dev, unsigned gpio, int val);
+
+
+struct tmio_mmc_hwconfig;
+
+struct asic3_platform_data
+{
+	// Must be first member
+	struct gpiodev_ops gpiodev_ops;
+
+	struct {
+		u32 dir;
+		u32 init;
+		u32 sleep_mask;
+		u32 sleep_out;
+		u32 batt_fault_out;
+		u32 sleep_conf;
+		u32 alt_function;
+	} gpio_a, gpio_b, gpio_c, gpio_d;
+
+	int irq_base;
+	unsigned int bus_shift;
+
+	struct platform_device **child_platform_devs;
+	int num_child_platform_devs;
+
+	struct tmio_mmc_hwconfig *tmio_mmc_hwconfig;
+};
Index: linux-2.6.24/include/linux/soc/tmio_mmc.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/linux/soc/tmio_mmc.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,17 @@
+#include <linux/platform_device.h>
+
+#define MMC_CLOCK_DISABLED 0
+#define MMC_CLOCK_ENABLED  1
+
+#define TMIO_WP_ALWAYS_RW ((void*)-1)
+
+struct tmio_mmc_hwconfig {
+	void (*hwinit)(struct platform_device *sdev);
+	void (*set_mmc_clock)(struct platform_device *sdev, int state);
+
+	/* NULL - use ASIC3 signal,
+	   TMIO_WP_ALWAYS_RW - assume always R/W (e.g. miniSD)
+	   otherwise - machine-specific handler */
+	int (*mmc_get_ro)(struct platform_device *pdev);
+	short address_shift;
+};
Index: linux-2.6.24/include/asm-arm/arch-pxa/pxa-regs.h
===================================================================
--- linux-2.6.24.orig/include/asm-arm/arch-pxa/pxa-regs.h	2008-03-10 16:07:59.000000000 +0000
+++ linux-2.6.24/include/asm-arm/arch-pxa/pxa-regs.h	2008-03-10 16:09:23.000000000 +0000
@@ -2058,6 +2058,8 @@
 #define LDCMD_SOFINT	(1 << 22)
 #define LDCMD_EOFINT	(1 << 21)
 
+#define LCCR4_13M_PCD_EN        (1<<25)          /* 13M PCD enable */
+#define LCCR4_PCDDIV            (1<<31)          /* PCD selection */
 
 #define LCCR5_SOFM1	(1<<0)		/* Start Of Frame Mask for Overlay 1 (channel 1) */
 #define LCCR5_SOFM2	(1<<1)		/* Start Of Frame Mask for Overlay 2 (channel 2) */
Index: linux-2.6.24/drivers/mmc/host/Makefile
===================================================================
--- linux-2.6.24.orig/drivers/mmc/host/Makefile	2008-01-24 22:58:37.000000000 +0000
+++ linux-2.6.24/drivers/mmc/host/Makefile	2008-03-10 16:09:23.000000000 +0000
@@ -13,6 +13,7 @@
 obj-$(CONFIG_MMC_RICOH_MMC)	+= ricoh_mmc.o
 obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
 obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
+obj-$(CONFIG_MMC_ASIC3)         += asic3_mmc.o
 obj-$(CONFIG_MMC_OMAP)		+= omap.o
 obj-$(CONFIG_MMC_AT91)		+= at91_mci.o
 obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o
Index: linux-2.6.24/drivers/mmc/host/asic3_mmc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/drivers/mmc/host/asic3_mmc.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,900 @@
+/* Note that this driver can likely be merged into the tmio driver, so
+ * consider this code temporary.  It works, though.
+ */
+/*
+ *  linux/drivers/mmc/asic3_mmc.c
+ *
+ *  Copyright (c) 2005 SDG Systems, LLC
+ *
+ *  based on tmio_mmc.c
+ *      Copyright (C) 2004 Ian Molton
+ *
+ *  Refactored to support all ASIC3 devices, 2006 Paul Sokolovsky
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for the SD / SDIO cell found in:
+ *
+ * TC6393XB
+ *
+ * This driver draws mainly on scattered spec sheets, Reverse engineering
+ * of the toshiba e800  SD driver and some parts of the 2.4 ASIC3 driver (4 bit
+ * support).
+ *
+ * Supports MMC 1 bit transfers and SD 1 and 4 bit modes.
+ *
+ * TODO:
+ *   Eliminate FIXMEs
+ *   SDIO support
+ *   Power management
+ *   Handle MMC errors (at all)
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+//#include <linux/mmc/protocol.h>
+#include <linux/mmc/sd.h>
+#include <linux/scatterlist.h>
+//#include <linux/soc-old.h>
+#include <linux/soc/asic3_base.h>
+#include <linux/soc/tmio_mmc.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <linux/clk.h>
+#include <asm/mach-types.h>
+
+#include <asm/hardware/ipaq-asic3.h>
+#include "asic3_mmc.h"
+
+struct asic3_mmc_host {
+    void                    *ctl_base;
+    struct device           *asic3_dev;       /* asic3 device */
+    struct tmio_mmc_hwconfig *hwconfig;       /* HW config data/handlers, guaranteed != NULL */
+    unsigned long           bus_shift;
+    struct mmc_command      *cmd;
+    struct mmc_request      *mrq;
+    struct mmc_data         *data;
+    struct mmc_host         *mmc;
+    int                     irq;
+    unsigned short          clock_for_sd;
+
+    /* I/O related stuff */
+    struct scatterlist      *sg_ptr;
+    unsigned int            sg_len;
+    unsigned int            sg_off;
+};
+
+static void
+mmc_finish_request(struct asic3_mmc_host *host)
+{
+    struct mmc_request *mrq = host->mrq;
+
+    /* Write something to end the command */
+    host->mrq  = NULL;
+    host->cmd  = NULL;
+    host->data = NULL;
+
+    mmc_request_done(host->mmc, mrq);
+}
+
+
+#define ASIC3_MMC_REG(host, block, reg) (*((volatile u16 *) ((host->ctl_base) + ((_IPAQ_ASIC3_## block ## _Base + _IPAQ_ASIC3_ ## block ## _ ## reg) >> (2 - host->bus_shift))) ))
+
+static void
+mmc_start_command(struct asic3_mmc_host *host, struct mmc_command *cmd)
+{
+    struct mmc_data *data = host->data;
+    int c                 = cmd->opcode;
+
+    DBG("[1;33mOpcode: %d[0m, base: %p\n", cmd->opcode, host->ctl_base);
+
+    if(cmd->opcode == MMC_STOP_TRANSMISSION) {
+        ASIC3_MMC_REG(host, SD_CTRL, StopInternal) = SD_CTRL_STOP_INTERNAL_ISSSUE_CMD12;
+        cmd->resp[0] = cmd->opcode;
+        cmd->resp[1] = 0;
+        cmd->resp[2] = 0;
+        cmd->resp[3] = 0;
+        cmd->resp[4] = 0;
+        return;
+    }
+
+    switch(cmd->flags & 0x1f) {
+        case MMC_RSP_NONE: c |= SD_CTRL_COMMAND_RESPONSE_TYPE_NORMAL; break;
+        case MMC_RSP_R1:   c |= SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1;   break;
+        case MMC_RSP_R1B:  c |= SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1B;  break;
+        case MMC_RSP_R2:   c |= SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R2;   break;
+        case MMC_RSP_R3:   c |= SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3;   break;
+        default:
+            DBG("Unknown response type %d\n", cmd->flags & 0x1f);
+            break;
+    }
+
+    host->cmd = cmd;
+
+    if(cmd->opcode == MMC_APP_CMD) {
+        c |= APP_CMD;
+    }
+    if (cmd->opcode == MMC_GO_IDLE_STATE) {
+        c |= (3 << 8); /* This was removed from ipaq-asic3.h for some reason */
+    }
+    if(data) {
+        c |= SD_CTRL_COMMAND_DATA_PRESENT;
+        if(data->blocks > 1) {
+            ASIC3_MMC_REG(host, SD_CTRL, StopInternal) = SD_CTRL_STOP_INTERNAL_AUTO_ISSUE_CMD12;
+            c |= SD_CTRL_COMMAND_MULTI_BLOCK;
+        }
+        if(data->flags & MMC_DATA_READ) {
+            c |= SD_CTRL_COMMAND_TRANSFER_READ;
+        }
+        /* MMC_DATA_WRITE does not require a bit to be set */
+    }
+
+    /* Enable the command and data interrupts */
+    ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard) = ~(
+          SD_CTRL_INTMASKCARD_RESPONSE_END
+        | SD_CTRL_INTMASKCARD_RW_END
+        | SD_CTRL_INTMASKCARD_CARD_REMOVED_0
+        | SD_CTRL_INTMASKCARD_CARD_INSERTED_0
+#if 0
+        | SD_CTRL_INTMASKCARD_CARD_REMOVED_3
+        | SD_CTRL_INTMASKCARD_CARD_INSERTED_3
+#endif
+    );
+
+    ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) = ~(
+          SD_CTRL_INTMASKBUFFER_UNK7
+        | SD_CTRL_INTMASKBUFFER_CMD_BUSY
+#if 0
+        | SD_CTRL_INTMASKBUFFER_CMD_INDEX_ERROR
+        | SD_CTRL_INTMASKBUFFER_CRC_ERROR
+        | SD_CTRL_INTMASKBUFFER_STOP_BIT_END_ERROR
+        | SD_CTRL_INTMASKBUFFER_DATA_TIMEOUT
+        | SD_CTRL_INTMASKBUFFER_BUFFER_OVERFLOW
+        | SD_CTRL_INTMASKBUFFER_BUFFER_UNDERFLOW
+        | SD_CTRL_INTMASKBUFFER_CMD_TIMEOUT
+        | SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE
+        | SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE
+        | SD_CTRL_INTMASKBUFFER_ILLEGAL_ACCESS
+#endif
+    );
+
+    /* Send the command */
+    ASIC3_MMC_REG(host, SD_CTRL, Arg1) = cmd->arg >> 16;
+    ASIC3_MMC_REG(host, SD_CTRL, Arg0) = cmd->arg & 0xffff;
+    ASIC3_MMC_REG(host, SD_CTRL, Cmd) = c;
+}
+
+/* This chip always returns (at least?) as much data as you ask for.  I'm
+ * unsure what happens if you ask for less than a block. This should be looked
+ * into to ensure that a funny length read doesnt mess up the controller data
+ * state machine.
+ *
+ * Aric: Statement above may not apply to ASIC3.
+ *
+ * FIXME - this chip cannot do 1 and 2 byte data requests in 4 bit mode
+ *
+ * Aric: Statement above may not apply to ASIC3.
+ */
+
+static struct tasklet_struct mmc_data_read_tasklet;
+
+static void
+mmc_data_transfer(unsigned long h)
+{
+    struct asic3_mmc_host *host = (struct asic3_mmc_host *)h;
+    struct mmc_data *data = host->data;
+    unsigned short *buf;
+    int count;
+    /* unsigned long flags; */
+
+    if(!data){
+        printk(KERN_WARNING DRIVER_NAME ": Spurious Data IRQ\n");
+        return;
+    }
+
+    /* local_irq_save(flags); */
+    /* buf = kmap_atomic(host->sg_ptr->page, KM_BIO_SRC_IRQ); */
+    buf = kmap(host->sg_ptr->page);
+    buf += host->sg_ptr->offset/2 + host->sg_off/2;
+
+    /*
+     * Ensure we dont read more than one block. The chip will interrupt us
+     * When the next block is available.
+     */
+    count = host->sg_ptr->length - host->sg_off;
+    if(count > data->blksz) {
+        count = data->blksz;
+    }
+
+    DBG("count: %08x, page: %p, offset: %08x flags %08x\n",
+        count, host->sg_ptr->page, host->sg_off, data->flags);
+
+    host->sg_off += count;
+
+    /* Transfer the data */
+    if(data->flags & MMC_DATA_READ) {
+        while(count > 0) {
+            /* Read two bytes from SD/MMC controller. */
+            *buf = ASIC3_MMC_REG(host, SD_CTRL, DataPort);
+            buf++;
+            count -= 2;
+        }
+	//flush_dcache_page(host->sg_ptr->page);
+    } else {
+        while(count > 0) {
+            /* Write two bytes to SD/MMC controller. */
+            ASIC3_MMC_REG(host, SD_CTRL, DataPort) = *buf;
+            buf++;
+            count -= 2;
+        }
+    }
+
+    /* kunmap_atomic(host->sg_ptr->page, KM_BIO_SRC_IRQ); */
+    kunmap(host->sg_ptr->page);
+    /* local_irq_restore(flags); */
+    if(host->sg_off == host->sg_ptr->length) {
+        host->sg_ptr++;
+        host->sg_off = 0;
+        --host->sg_len;
+    }
+
+    return;
+}
+
+static void
+mmc_data_end_irq(struct asic3_mmc_host *host)
+{
+    struct mmc_data *data = host->data;
+
+    host->data = NULL;
+
+    if(!data){
+        printk(KERN_WARNING DRIVER_NAME ": Spurious data end IRQ\n");
+        return;
+    }
+
+    if (data->error == MMC_ERR_NONE) {
+        data->bytes_xfered = data->blocks * data->blksz;
+    } else {
+        data->bytes_xfered = 0;
+    }
+
+    DBG("Completed data request\n");
+
+    ASIC3_MMC_REG(host, SD_CTRL, StopInternal) = 0;
+
+    /* Make sure read enable interrupt and write enable interrupt are disabled */
+    if(data->flags & MMC_DATA_READ) {
+        ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) |= SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE;
+    } else {
+        ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) |= SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE;
+    }
+
+    mmc_finish_request(host);
+}
+
+static void
+mmc_cmd_irq(struct asic3_mmc_host *host, unsigned int buffer_stat)
+{
+    struct mmc_command *cmd = host->cmd;
+    u8 *buf = (u8 *)cmd->resp;
+    u16 data;
+
+    if(!host->cmd) {
+        printk(KERN_WARNING DRIVER_NAME ": Spurious CMD irq\n");
+        return;
+    }
+
+    host->cmd = NULL;
+    if(cmd->flags & MMC_RSP_PRESENT && cmd->flags & MMC_RSP_136) {
+        /* R2 */
+        buf[12] = 0xff;
+        data = ASIC3_MMC_REG(host, SD_CTRL, Response0);
+        buf[13] = data & 0xff;
+        buf[14] = data >> 8;
+        data = ASIC3_MMC_REG(host, SD_CTRL, Response1);
+        buf[15] = data & 0xff;
+        buf[8] = data >> 8;
+        data = ASIC3_MMC_REG(host, SD_CTRL, Response2);
+        buf[9] = data & 0xff;
+        buf[10] = data >> 8;
+        data = ASIC3_MMC_REG(host, SD_CTRL, Response3);
+        buf[11] = data & 0xff;
+        buf[4] = data >> 8;
+        data = ASIC3_MMC_REG(host, SD_CTRL, Response4);
+        buf[5] = data & 0xff;
+        buf[6] = data >> 8;
+        data = ASIC3_MMC_REG(host, SD_CTRL, Response5);
+        buf[7] = data & 0xff;
+        buf[0] = data >> 8;
+        data = ASIC3_MMC_REG(host, SD_CTRL, Response6);
+        buf[1] = data & 0xff;
+        buf[2] = data >> 8;
+        data = ASIC3_MMC_REG(host, SD_CTRL, Response7);
+        buf[3] = data & 0xff;
+    } else if(cmd->flags & MMC_RSP_PRESENT) {
+        /* R1, R1B, R3 */
+        data = ASIC3_MMC_REG(host, SD_CTRL, Response0);
+        buf[0] = data & 0xff;
+        buf[1] = data >> 8;
+        data = ASIC3_MMC_REG(host, SD_CTRL, Response1);
+        buf[2] = data & 0xff;
+        buf[3] = data >> 8;
+    }
+    DBG("Response: %08x %08x %08x %08x\n", cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
+    if(buffer_stat & SD_CTRL_BUFFERSTATUS_CMD_TIMEOUT) {
+        cmd->error = MMC_ERR_TIMEOUT;
+    } else if((buffer_stat & SD_CTRL_BUFFERSTATUS_CRC_ERROR) && (cmd->flags & MMC_RSP_CRC)) {
+        cmd->error = MMC_ERR_BADCRC;
+    } else if(buffer_stat &
+                (
+                      SD_CTRL_BUFFERSTATUS_ILLEGAL_ACCESS
+                    | SD_CTRL_BUFFERSTATUS_CMD_INDEX_ERROR
+                    | SD_CTRL_BUFFERSTATUS_STOP_BIT_END_ERROR
+                    | SD_CTRL_BUFFERSTATUS_BUFFER_OVERFLOW
+                    | SD_CTRL_BUFFERSTATUS_BUFFER_UNDERFLOW
+                    | SD_CTRL_BUFFERSTATUS_DATA_TIMEOUT
+                )
+    ) {
+        DBG("Buffer status ERROR 0x%04x - inside check buffer\n", buffer_stat);
+        DBG("detail0 error status 0x%04x\n", ASIC3_MMC_REG(host, SD_CTRL, ErrorStatus0));
+        DBG("detail1 error status 0x%04x\n", ASIC3_MMC_REG(host, SD_CTRL, ErrorStatus1));
+        cmd->error = MMC_ERR_FAILED;
+    }
+
+    if(cmd->error == MMC_ERR_NONE) {
+        switch (cmd->opcode) {
+            case SD_APP_SET_BUS_WIDTH:
+                if(cmd->arg == SD_BUS_WIDTH_4) {
+                    host->clock_for_sd = SD_CTRL_CARDCLOCKCONTROL_FOR_SD_CARD;
+                    ASIC3_MMC_REG(host, SD_CTRL, MemCardOptionSetup) =
+                              MEM_CARD_OPTION_REQUIRED
+                            | MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(14)
+                            | MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT
+                            | MEM_CARD_OPTION_DATA_XFR_WIDTH_4;
+                } else {
+                    host->clock_for_sd = 0;
+                    ASIC3_MMC_REG(host, SD_CTRL, MemCardOptionSetup) =
+                              MEM_CARD_OPTION_REQUIRED
+                            | MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(14)
+                            | MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT
+                            | MEM_CARD_OPTION_DATA_XFR_WIDTH_1;
+                }
+                break;
+            case MMC_SELECT_CARD:
+                if((cmd->arg >> 16) == 0) {
+                    /* We have been deselected. */
+                    ASIC3_MMC_REG(host, SD_CTRL, MemCardOptionSetup) =
+                          MEM_CARD_OPTION_REQUIRED
+                        | MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(14)
+                        | MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT
+                        | MEM_CARD_OPTION_DATA_XFR_WIDTH_1;
+                }
+        }
+    }
+
+    /*
+     * If there is data to handle we enable data IRQs here, and we will
+     * ultimatley finish the request in the mmc_data_end_irq handler.
+     */
+    if(host->data && (cmd->error == MMC_ERR_NONE)){
+        if(host->data->flags & MMC_DATA_READ) {
+            /* Enable the read enable interrupt */
+            ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) &=
+                ~SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE;
+        } else {
+            /* Enable the write enable interrupt */
+            ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) &=
+                ~SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE;
+        }
+    } else {
+        /* There's no data, or we encountered an error, so finish now. */
+        mmc_finish_request(host);
+    }
+
+    return;
+}
+
+static void hwinit2_irqsafe(struct asic3_mmc_host *host);
+
+static irqreturn_t
+mmc_irq(int irq, void *irq_desc)
+{
+    struct asic3_mmc_host *host;
+    unsigned int breg, bmask, bstatus, creg, cmask, cstatus;
+
+    host = irq_desc;
+
+    /* asic3 bstatus has errors */
+    bstatus = ASIC3_MMC_REG(host, SD_CTRL, BufferCtrl);
+    bmask   = ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer);
+    cstatus = ASIC3_MMC_REG(host, SD_CTRL, CardStatus);
+    cmask   = ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard);
+    breg    = bstatus & ~bmask & ~DONT_CARE_BUFFER_BITS;
+    creg    = cstatus & ~cmask & ~DONT_CARE_CARD_BITS;
+
+    if (!breg && !creg) {
+        /* This occurs sometimes for no known reason.  It doesn't hurt
+         * anything, so I don't print it.  */
+        ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) &= ~breg;
+        ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard) &= ~creg;
+        goto out;
+    }
+
+    while (breg || creg) {
+
+        /* XXX TODO: Need to handle errors in breg here. */
+
+        /*
+         * Card insert/remove.  The mmc controlling code is stateless.  That
+         * is, it doesn't care if it was an insert or a remove.  It treats
+         * both the same.
+         */
+        /* XXX Asic3 has _3 versions of these status bits, too, for a second slot, perhaps? */
+        if (creg & (SD_CTRL_CARDSTATUS_CARD_INSERTED_0 | SD_CTRL_CARDSTATUS_CARD_REMOVED_0)) {
+            ASIC3_MMC_REG(host, SD_CTRL, CardStatus) &=
+                ~(SD_CTRL_CARDSTATUS_CARD_REMOVED_0 | SD_CTRL_CARDSTATUS_CARD_INSERTED_0);
+            if(creg & SD_CTRL_CARDSTATUS_CARD_INSERTED_0) {
+                hwinit2_irqsafe(host);
+            }
+            mmc_detect_change(host->mmc,1);
+        }
+
+        /* Command completion */
+        if (creg & SD_CTRL_CARDSTATUS_RESPONSE_END) {
+            ASIC3_MMC_REG(host, SD_CTRL, CardStatus) &=
+                ~(SD_CTRL_CARDSTATUS_RESPONSE_END);
+            mmc_cmd_irq(host, bstatus);
+        }
+
+        /* Data transfer */
+        if (breg & (SD_CTRL_BUFFERSTATUS_BUFFER_READ_ENABLE | SD_CTRL_BUFFERSTATUS_BUFFER_WRITE_ENABLE)) {
+            ASIC3_MMC_REG(host, SD_CTRL, BufferCtrl) &=
+                ~(SD_CTRL_BUFFERSTATUS_BUFFER_WRITE_ENABLE | SD_CTRL_BUFFERSTATUS_BUFFER_READ_ENABLE);
+	    tasklet_schedule(&mmc_data_read_tasklet);
+        }
+
+        /* Data transfer completion */
+        if (creg & SD_CTRL_CARDSTATUS_RW_END) {
+            ASIC3_MMC_REG(host, SD_CTRL, CardStatus) &= ~(SD_CTRL_CARDSTATUS_RW_END);
+            mmc_data_end_irq(host);
+        }
+
+        /* Check status - keep going until we've handled it all */
+        bstatus = ASIC3_MMC_REG(host, SD_CTRL, BufferCtrl);
+        bmask   = ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer);
+        cstatus = ASIC3_MMC_REG(host, SD_CTRL, CardStatus);
+        cmask   = ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard);
+        breg    = bstatus & ~bmask & ~DONT_CARE_BUFFER_BITS;
+        creg    = cstatus & ~cmask & ~DONT_CARE_CARD_BITS;
+    }
+
+out:
+    /* Ensure all interrupt sources are cleared */
+    ASIC3_MMC_REG(host, SD_CTRL, BufferCtrl) = 0;
+    ASIC3_MMC_REG(host, SD_CTRL, CardStatus) = 0;
+    return IRQ_HANDLED;
+}
+
+static void
+mmc_start_data(struct asic3_mmc_host *host, struct mmc_data *data)
+{
+    DBG("setup data transfer: blocksize %08x  nr_blocks %d, page: %08x, offset: %08x\n", data->blksz,
+        data->blocks, (int)data->sg->page, data->sg->offset);
+
+    host->sg_len = data->sg_len;
+    host->sg_ptr = data->sg;
+    host->sg_off = 0;
+    host->data   = data;
+
+    /* Set transfer length and blocksize */
+    ASIC3_MMC_REG(host, SD_CTRL, TransferSectorCount) = data->blocks;
+    ASIC3_MMC_REG(host, SD_CTRL, MemCardXferDataLen)  = data->blksz;
+}
+
+/* Process requests from the MMC layer */
+static void
+mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+    struct asic3_mmc_host *host = mmc_priv(mmc);
+
+    WARN_ON(host->mrq != NULL);
+
+    host->mrq = mrq;
+
+    /* If we're performing a data request we need to setup some
+       extra information */
+    if(mrq->data) {
+        mmc_start_data(host, mrq->data);
+    }
+
+    mmc_start_command(host, mrq->cmd);
+}
+
+/* Set MMC clock / power.
+ * Note: This controller uses a simple divider scheme therefore it cannot run
+ * a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as MMC
+ * wont run that fast, it has to be clocked at 12MHz which is the next slowest
+ * setting.  This is likely not an issue because we are doing single 16-bit
+ * writes for data I/O.
+ */
+static void
+mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+    struct asic3_mmc_host *host = mmc_priv(mmc);
+    u32 clk = 0;
+
+    DBG("clock %uHz busmode %u powermode %u Vdd %u\n",
+        ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
+
+    if (ios->clock) {
+        clk = 0x80; /* slowest by default */
+        if(ios->clock >= 24000000 / 256) clk >>= 1;
+        if(ios->clock >= 24000000 / 128) clk >>= 1;
+        if(ios->clock >= 24000000 / 64)  clk >>= 1;
+        if(ios->clock >= 24000000 / 32)  clk >>= 1;
+        if(ios->clock >= 24000000 / 16)  clk >>= 1;
+        if(ios->clock >= 24000000 / 8)   clk >>= 1;
+        if(ios->clock >= 24000000 / 4)   clk >>= 1;
+        if(ios->clock >= 24000000 / 2)   clk >>= 1;
+        if(ios->clock >= 24000000 / 1)   clk >>= 1;
+        if(clk == 0) { /* For fastest speed we disable the divider. */
+            ASIC3_MMC_REG(host, SD_CONFIG, ClockMode) = 0;
+        } else {
+            ASIC3_MMC_REG(host, SD_CONFIG, ClockMode) = 1;
+        }
+        ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) = 0;
+        ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) =
+              host->clock_for_sd
+            | SD_CTRL_CARDCLOCKCONTROL_ENABLE_CLOCK
+            | clk;
+        msleep(10);
+    } else {
+        ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) = 0;
+    }
+
+    switch (ios->power_mode) {
+        case MMC_POWER_OFF:
+            ASIC3_MMC_REG(host, SD_CONFIG, SDHC_Power1) = 0;
+            msleep(1);
+            break;
+        case MMC_POWER_UP:
+            break;
+        case MMC_POWER_ON:
+            ASIC3_MMC_REG(host, SD_CONFIG, SDHC_Power1) = SD_CONFIG_POWER1_PC_33V;
+            msleep(20);
+            break;
+    }
+}
+
+static int
+mmc_get_ro(struct mmc_host *mmc)
+{
+    struct asic3_mmc_host *host = mmc_priv(mmc);
+
+    /* Call custom handler for RO status */
+    if(host->hwconfig->mmc_get_ro) {
+            /* Special case for cards w/o WP lock (like miniSD) */
+            if (host->hwconfig->mmc_get_ro == (void*)-1) {
+		    return 0;
+            } else {
+		    struct platform_device *pdev = to_platform_device(mmc_dev(mmc));
+        	    return host->hwconfig->mmc_get_ro(pdev);
+            }
+    }
+
+    /* WRITE_PROTECT is active low */
+    return (ASIC3_MMC_REG(host, SD_CTRL, CardStatus) & SD_CTRL_CARDSTATUS_WRITE_PROTECT)?0:1;
+}
+
+static struct mmc_host_ops mmc_ops = {
+    .request        = mmc_request,
+    .set_ios        = mmc_set_ios,
+    .get_ro         = mmc_get_ro,
+};
+
+static void
+hwinit2_irqsafe(struct asic3_mmc_host *host)
+{
+    ASIC3_MMC_REG(host, SD_CONFIG, Addr1) = 0x0000;
+    ASIC3_MMC_REG(host, SD_CONFIG, Addr0) = 0x0800;
+
+    ASIC3_MMC_REG(host, SD_CONFIG, ClkStop) = SD_CONFIG_CLKSTOP_ENABLE_ALL;
+    ASIC3_MMC_REG(host, SD_CONFIG, SDHC_CardDetect) = 2;
+    ASIC3_MMC_REG(host, SD_CONFIG, Command) = SD_CONFIG_COMMAND_MAE;
+
+    ASIC3_MMC_REG(host, SD_CTRL, SoftwareReset) = 0; /* reset on */
+    mdelay(2);
+
+    ASIC3_MMC_REG(host, SD_CTRL, SoftwareReset) = 1; /* reset off */
+    mdelay(2);
+
+    ASIC3_MMC_REG(host, SD_CTRL, MemCardOptionSetup) =
+          MEM_CARD_OPTION_REQUIRED
+        | MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(14)
+        | MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT
+        | MEM_CARD_OPTION_DATA_XFR_WIDTH_1
+        ;
+    host->clock_for_sd = 0;
+
+    ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) = 0;
+    ASIC3_MMC_REG(host, SD_CTRL, CardStatus) = 0;
+    ASIC3_MMC_REG(host, SD_CTRL, BufferCtrl) = 0;
+    ASIC3_MMC_REG(host, SD_CTRL, ErrorStatus0) = 0;
+    ASIC3_MMC_REG(host, SD_CTRL, ErrorStatus1) = 0;
+    ASIC3_MMC_REG(host, SD_CTRL, StopInternal) = 0;
+
+    ASIC3_MMC_REG(host, SDIO_CTRL, ClocknWaitCtrl) = 0x100;
+    /* *((unsigned short *)(((char *)host->ctl_base) + 0x938)) = 0x100; */
+
+    ASIC3_MMC_REG(host, SD_CONFIG, ClockMode) = 0;
+    ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) = 0;
+
+    mdelay(1);
+
+
+    ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard) = ~(
+          SD_CTRL_INTMASKCARD_RESPONSE_END
+        | SD_CTRL_INTMASKCARD_RW_END
+        | SD_CTRL_INTMASKCARD_CARD_REMOVED_0
+        | SD_CTRL_INTMASKCARD_CARD_INSERTED_0
+#if 0
+        | SD_CTRL_INTMASKCARD_CARD_REMOVED_3
+        | SD_CTRL_INTMASKCARD_CARD_INSERTED_3
+#endif
+        )
+        ; /* check */
+    ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) = 0xffff;  /* IRQs off */
+
+    /*
+     * ASIC3_MMC_REG(host, SD_CTRL, TransactionCtrl) = SD_CTRL_TRANSACTIONCONTROL_SET;
+     *   Wince has 0x1000
+     */
+    /* ASIC3_MMC_REG(host, SD_CTRL, TransactionCtrl) = 0x1000; */
+
+
+    asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_SDPWR, ASIC3_SDHWCTRL_SDPWR); /* turn on power at controller(?) */
+
+}
+
+static void
+hwinit(struct asic3_mmc_host *host, struct platform_device *pdev)
+{
+    /* Call custom handler for enabling clock (if needed) */
+    if(host->hwconfig->set_mmc_clock)
+            host->hwconfig->set_mmc_clock(pdev, MMC_CLOCK_ENABLED);
+
+    /* Not sure if it must be done bit by bit, but leaving as-is */
+    asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_LEVCD, ASIC3_SDHWCTRL_LEVCD);
+    asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_LEVWP, ASIC3_SDHWCTRL_LEVWP);
+    asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_SUSPEND, 0);
+    asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_PCLR, 0);
+
+    asic3_set_clock_cdex (host->asic3_dev,
+        CLOCK_CDEX_EX1 | CLOCK_CDEX_EX0, CLOCK_CDEX_EX1 | CLOCK_CDEX_EX0);
+    msleep(1);
+
+    asic3_set_clock_sel (host->asic3_dev,
+        CLOCK_SEL_SD_HCLK_SEL | CLOCK_SEL_SD_BCLK_SEL,
+	CLOCK_SEL_SD_HCLK_SEL | 0);	/* ? */
+
+    asic3_set_clock_cdex (host->asic3_dev,
+        CLOCK_CDEX_SD_HOST | CLOCK_CDEX_SD_BUS,
+	CLOCK_CDEX_SD_HOST | CLOCK_CDEX_SD_BUS);
+    msleep(1);
+
+    asic3_set_extcf_select(host->asic3_dev, ASIC3_EXTCF_SD_MEM_ENABLE, ASIC3_EXTCF_SD_MEM_ENABLE);
+
+    /* Long Delay */
+    if( !machine_is_h4700())
+        msleep(500);
+
+    hwinit2_irqsafe(host);
+}
+
+#ifdef CONFIG_PM
+static int
+mmc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+    struct mmc_host *mmc = platform_get_drvdata(pdev);
+    struct asic3_mmc_host *host = mmc_priv(mmc);
+    int ret;
+
+    ret = mmc_suspend_host(mmc, state);
+
+    if (ret) {
+	printk(KERN_ERR DRIVER_NAME ": Could not suspend MMC host, hardware not suspended");
+	return ret;
+    }
+
+    /* disable the card insert / remove interrupt while sleeping */
+    ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard) = ~(
+          SD_CTRL_INTMASKCARD_RESPONSE_END
+        | SD_CTRL_INTMASKCARD_RW_END);
+
+    /* disable clock */
+    ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) = 0;
+    ASIC3_MMC_REG(host, SD_CONFIG, ClkStop) = 0;
+
+    /* power down */
+    ASIC3_MMC_REG(host, SD_CONFIG, SDHC_Power1) = 0;
+
+    asic3_set_clock_cdex (host->asic3_dev,
+        CLOCK_CDEX_SD_HOST | CLOCK_CDEX_SD_BUS, 0);
+
+    /* disable core clock */
+    if(host->hwconfig->set_mmc_clock)
+        host->hwconfig->set_mmc_clock(pdev, MMC_CLOCK_DISABLED);
+
+    /* Put in suspend mode */
+    asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_SUSPEND, ASIC3_SDHWCTRL_SUSPEND);
+    return 0;
+}
+
+static int
+mmc_resume(struct platform_device *pdev)
+{
+    struct mmc_host *mmc = platform_get_drvdata(pdev);
+    struct asic3_mmc_host *host = mmc_priv(mmc);
+
+    printk(KERN_INFO "%s: starting resume\n", DRIVER_NAME);
+
+    asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_SUSPEND, 0);
+    hwinit(host, pdev);
+
+    /* re-enable card remove / insert interrupt */
+    ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard) = ~(
+          SD_CTRL_INTMASKCARD_RESPONSE_END
+        | SD_CTRL_INTMASKCARD_RW_END
+        | SD_CTRL_INTMASKCARD_CARD_REMOVED_0
+        | SD_CTRL_INTMASKCARD_CARD_INSERTED_0 );
+
+    mmc_resume_host(mmc);
+
+    printk(KERN_INFO "%s: finished resume\n", DRIVER_NAME);
+    return 0;
+}
+#endif
+
+static int
+mmc_probe(struct platform_device *pdev)
+{
+    struct mmc_host *mmc;
+    struct asic3_mmc_host *host = NULL;
+    int retval = 0;
+    struct tmio_mmc_hwconfig *mmc_config = (struct tmio_mmc_hwconfig *)pdev->dev.platform_data;
+
+    /* bus_shift is mandatory */
+    if (!mmc_config) {
+        printk(KERN_ERR DRIVER_NAME ": Invalid configuration\n");
+    	return -EINVAL;
+    }
+
+    mmc = mmc_alloc_host(sizeof(struct asic3_mmc_host) + 128, &pdev->dev);
+    if (!mmc) {
+        retval = -ENOMEM;
+        goto exceptional_return;
+    }
+
+    host = mmc_priv(mmc);
+    host->mmc = mmc;
+    platform_set_drvdata(pdev, mmc);
+
+    host->ctl_base = 0;
+    host->hwconfig = mmc_config;
+    host->bus_shift = mmc_config->address_shift;
+    host->asic3_dev = pdev->dev.parent;
+    host->clock_for_sd = 0;
+
+    tasklet_init(&mmc_data_read_tasklet, mmc_data_transfer, (unsigned long)host);
+
+    host->ctl_base = ioremap_nocache ((unsigned long)pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start);
+    if(!host->ctl_base){
+	printk(KERN_ERR DRIVER_NAME ": Could not map ASIC3 SD controller\n");
+        retval = -ENODEV;
+        goto exceptional_return;
+    }
+
+    printk(DRIVER_NAME ": ASIC3 MMC/SD Driver, controller at 0x%lx\n", (unsigned long)pdev->resource[0].start);
+
+    mmc->ops = &mmc_ops;
+    mmc->caps = MMC_CAP_4_BIT_DATA;
+    mmc->f_min = 46875; /* ARIC: not sure what these should be */
+    mmc->f_max = 24000000; /* ARIC: not sure what these should be */
+    mmc->ocr_avail = MMC_VDD_32_33;
+
+    hwinit(host, pdev);
+
+
+    host->irq = pdev->resource[1].start;
+
+    retval = request_irq(host->irq, mmc_irq, 0, DRIVER_NAME, host);
+    if(retval) {
+        printk(KERN_ERR DRIVER_NAME ": Unable to get interrupt\n");
+        retval = -ENODEV;
+        goto exceptional_return;
+    }
+    set_irq_type(host->irq, IRQT_FALLING);
+
+    mmc_add_host(mmc);
+
+#ifdef CONFIG_PM
+    // resume_timer.function = resume_timer_callback;
+    // resume_timer.data = 0;
+    // init_timer(&resume_timer);
+#endif
+
+    return 0;
+
+exceptional_return:
+    if (mmc) {
+        mmc_free_host(mmc);
+    }
+    if(host && host->ctl_base) iounmap(host->ctl_base);
+    return retval;
+}
+
+static int
+mmc_remove(struct platform_device *pdev)
+{
+    struct mmc_host *mmc = platform_get_drvdata(pdev);
+
+    platform_set_drvdata(pdev, NULL);
+
+    if (mmc) {
+        struct asic3_mmc_host *host = mmc_priv(mmc);
+        mmc_remove_host(mmc);
+        free_irq(host->irq, host);
+        /* FIXME - we might want to consider stopping the chip here... */
+        iounmap(host->ctl_base);
+        mmc_free_host(mmc); /* FIXME - why does this call hang? */
+    }
+    return 0;
+}
+
+/* ------------------- device registration ----------------------- */
+
+static struct platform_driver mmc_asic3_driver = {
+    .driver = {
+	.name    = DRIVER_NAME,
+    },
+    .probe   = mmc_probe,
+    .remove  = mmc_remove,
+#ifdef CONFIG_PM
+    .suspend = mmc_suspend,
+    .resume  = mmc_resume,
+#endif
+};
+
+static int __init mmc_init(void)
+{
+    return platform_driver_register(&mmc_asic3_driver);
+}
+
+static void __exit mmc_exit(void)
+{
+    platform_driver_unregister(&mmc_asic3_driver);
+}
+
+late_initcall(mmc_init);
+module_exit(mmc_exit);
+
+MODULE_DESCRIPTION("HTC ASIC3 SD/MMC driver");
+MODULE_AUTHOR("Aric Blumer, SDG Systems, LLC");
+MODULE_LICENSE("GPL");
+
Index: linux-2.6.24/drivers/mmc/host/asic3_mmc.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/drivers/mmc/host/asic3_mmc.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,25 @@
+#ifndef __ASIC3_MMC_H
+#define __ASIC3_MMC_H
+
+#define DRIVER_NAME	"asic3_mmc"
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(x...)       printk(DRIVER_NAME ": " x)
+#else
+#define DBG(x...)       do { } while (0)
+#endif
+
+/* Response types */
+#define APP_CMD        0x0040
+
+#define SD_CONFIG_CLKSTOP_ENABLE_ALL 0x1f
+
+#define DONT_CARE_CARD_BITS ( \
+      SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_3 \
+    | SD_CTRL_INTMASKCARD_WRITE_PROTECT \
+    | SD_CTRL_INTMASKCARD_UNK6 \
+    | SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_0 \
+  )
+#define DONT_CARE_BUFFER_BITS ( SD_CTRL_INTMASKBUFFER_UNK7 | SD_CTRL_INTMASKBUFFER_CMD_BUSY )
+
+#endif // __ASIC3_MMC_H
Index: linux-2.6.24/drivers/input/keyboard/asic3_keys.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/drivers/input/keyboard/asic3_keys.c	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,131 @@
+/*
+ * Generic buttons driver for ASIC3 SoC.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2003 Joshua Wise
+ * Copyright (C) 2005 Pawel Kolodziejski
+ * Copyright (C) 2006 Paul Sokolovsky
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/soc/asic3_base.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/arch/irqs.h>
+#include <asm/hardware.h>
+#include <asm/hardware/ipaq-asic3.h>
+#include <asm/hardware/asic3_keys.h>
+
+static irqreturn_t asic3_keys_asic_handle(int irq, void *data)
+{
+	struct asic3_keys_platform_data *pdata = data;
+	int i, base_irq;
+
+	base_irq = asic3_irq_base(pdata->asic3_dev);
+	for (i = 0; i < pdata->nbuttons; i++) {
+		struct asic3_keys_button *b = &pdata->buttons[i];
+		if ((base_irq + b->gpio) == irq) {
+			int state = !!asic3_gpio_get_value(pdata->asic3_dev, b->gpio);
+
+			if (pdata->buttons[i].type == EV_SW)
+				input_report_switch(pdata->input, pdata->buttons[i].keycode, state ^ b->active_low);
+			else
+				input_report_key(pdata->input, b->keycode, state ^ b->active_low);
+			input_sync(pdata->input);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit asic3_keys_probe(struct platform_device *pdev)
+{
+	struct asic3_keys_platform_data *pdata = pdev->dev.platform_data;
+	int i, base_irq;
+	int j, ret;
+
+	pdata->input = input_allocate_device();
+
+	base_irq = asic3_irq_base(pdata->asic3_dev);
+
+	for (i = 0; i < pdata->nbuttons; i++) {
+		struct asic3_keys_button *b = &pdata->buttons[i];
+		set_bit(b->keycode, pdata->input->keybit);
+                ret=request_irq(base_irq + b->gpio, asic3_keys_asic_handle, SA_SAMPLE_RANDOM, b->desc, pdata);
+                if (ret)
+                {
+                 printk(KERN_NOTICE "Failed to allocate asic3_keys irq=%d.\n",b->gpio);
+
+                 for(j=0; j<i ; j++)
+                  free_irq(base_irq + pdata->buttons[i].gpio, NULL);
+
+                 input_unregister_device (pdata->input);
+
+                 return -ENODEV;
+                }
+
+		set_irq_type(base_irq + b->gpio, IRQT_BOTHEDGE);
+		if (pdata->buttons[i].type == EV_SW) {
+			pdata->input->evbit[0] |= BIT(EV_SW);
+			set_bit(b->keycode, pdata->input->swbit);
+		} else {
+			pdata->input->evbit[0] |= BIT(EV_KEY);
+			set_bit(b->keycode, pdata->input->keybit);
+		}
+	}
+
+	pdata->input->name = pdev->name;
+	input_register_device(pdata->input);
+
+	return 0;
+}
+
+static int __devexit asic3_keys_remove(struct platform_device *pdev)
+{
+	struct asic3_keys_platform_data *pdata = pdev->dev.platform_data;
+	int i, base_irq;
+
+	base_irq = asic3_irq_base(pdata->asic3_dev);
+	for (i = 0; i < pdata->nbuttons; i++) {
+		free_irq(base_irq + pdata->buttons[i].gpio, NULL);
+	}
+
+	input_unregister_device(pdata->input);
+
+	return 0;
+}
+
+
+static struct platform_driver asic3_keys_driver = {
+	.probe          = asic3_keys_probe,
+        .remove         = __devexit_p(asic3_keys_remove),
+	.driver		= {
+	    .name       = "asic3-keys",
+	},
+};
+
+static int __init asic3_keys_init(void)
+{
+	return platform_driver_register(&asic3_keys_driver);
+}
+
+static void __exit asic3_keys_exit(void)
+{
+	platform_driver_unregister(&asic3_keys_driver);
+}
+
+module_init(asic3_keys_init);
+module_exit(asic3_keys_exit);
+
+MODULE_AUTHOR("Joshua Wise, Pawel Kolodziejski, Paul Sokolovsky");
+MODULE_DESCRIPTION("Buttons driver for HTC ASIC3 SoC");
+MODULE_LICENSE("GPL");
Index: linux-2.6.24/include/asm-arm/arch-pxa/irqs.h
===================================================================
--- linux-2.6.24.orig/include/asm-arm/arch-pxa/irqs.h	2008-01-24 22:58:37.000000000 +0000
+++ linux-2.6.24/include/asm-arm/arch-pxa/irqs.h	2008-03-10 16:09:23.000000000 +0000
@@ -182,6 +182,8 @@
       defined(CONFIG_MACH_LOGICPD_PXA270) || \
       defined(CONFIG_MACH_MAINSTONE)
 #define NR_IRQS			(IRQ_BOARD_END)
+#elif defined(CONFIG_MACH_HTCUNIVERSAL)
+#define NR_IRQS			(IRQ_BOARD_START + 96)
 #else
 #define NR_IRQS			(IRQ_BOARD_START)
 #endif
Index: linux-2.6.24/include/asm-arm/arch-pxa/serial.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24/include/asm-arm/arch-pxa/serial.h	2008-03-10 16:09:23.000000000 +0000
@@ -0,0 +1,78 @@
+/*
+ *  linux/include/asm-arm/arch-pxa/serial.h
+ *
+ * Author:	Nicolas Pitre
+ * Copyright:	(C) 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/arch/pxa-regs.h>
+
+#define BAUD_BASE	921600
+
+/* Standard COM flags */
+#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
+
+#define STD_SERIAL_PORT_DEFNS	\
+	{	\
+		type:			PORT_PXA,	\
+		xmit_fifo_size:		64,		\
+		baud_base:		BAUD_BASE,	\
+		iomem_base:		&FFUART,	\
+		iomem_reg_shift:	2,		\
+		io_type:		SERIAL_IO_MEM,	\
+		irq:			IRQ_FFUART,	\
+		flags:			STD_COM_FLAGS,	\
+	}, {	\
+		type:			PORT_PXA,	\
+		xmit_fifo_size:		64,		\
+		baud_base:		BAUD_BASE,	\
+		iomem_base:		&STUART,	\
+		iomem_reg_shift:	2,		\
+		io_type:		SERIAL_IO_MEM,	\
+		irq:			IRQ_STUART,	\
+		flags:			STD_COM_FLAGS,	\
+	}, {	\
+		type:			PORT_PXA,	\
+		xmit_fifo_size:		64,		\
+		baud_base:		BAUD_BASE,	\
+		iomem_base:		&BTUART,	\
+		iomem_reg_shift:	2,		\
+		io_type:		SERIAL_IO_MEM,	\
+		irq:			IRQ_BTUART,	\
+		flags:			STD_COM_FLAGS,	\
+	}
+
+#define EXTRA_SERIAL_PORT_DEFNS
+
+struct platform_pxa_serial_funcs {
+
+	/* Initialize whatever is connected to this serial port. */
+	void (*configure)(int state);
+#define PXA_UART_CFG_PRE_STARTUP   0
+#define PXA_UART_CFG_POST_STARTUP  1
+#define PXA_UART_CFG_PRE_SHUTDOWN  2
+#define PXA_UART_CFG_POST_SHUTDOWN 3
+
+	/* Enable or disable the individual transmitter/receiver submodules.
+	 * On transceivers without echo cancellation (e.g. SIR)
+	 * transmitter always has priority; e.g. if both bits are set,
+	 * only the transmitter is enabled. */
+        void (*set_txrx)(int txrx);
+#define PXA_SERIAL_TX 1
+#define PXA_SERIAL_RX 2
+
+	/* Get the current state of tx/rx. */
+	int (*get_txrx)(void);
+
+	int (*suspend)(struct platform_device *dev, pm_message_t state);
+	int (*resume)(struct platform_device *dev);
+};
+
+void pxa_set_ffuart_info(struct platform_pxa_serial_funcs *ffuart_funcs);
+void pxa_set_btuart_info(struct platform_pxa_serial_funcs *btuart_funcs);
+void pxa_set_stuart_info(struct platform_pxa_serial_funcs *stuart_funcs);
+void pxa_set_hwuart_info(struct platform_pxa_serial_funcs *hwuart_funcs);
Index: linux-2.6.24/drivers/serial/pxa.c
===================================================================
--- linux-2.6.24.orig/drivers/serial/pxa.c	2008-01-24 22:58:37.000000000 +0000
+++ linux-2.6.24/drivers/serial/pxa.c	2008-03-10 16:09:23.000000000 +0000
@@ -47,6 +47,7 @@
 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/irq.h>
+#include <asm/arch/serial.h>
 #include <asm/arch/pxa-regs.h>
 
 
@@ -60,6 +61,14 @@
 	char			*name;
 };
 
+
+#define IS_METHOD(dev, method) (dev && (dev)->platform_data && ((struct platform_pxa_serial_funcs *)(dev)->platform_data)->method)
+#define METHOD_CALL(dev, method) \
+		((struct platform_pxa_serial_funcs *)(dev)->platform_data)->method()
+#define SAFE_METHOD_CALL(dev, method, args...) \
+	if (IS_METHOD(dev, method)) \
+		((struct platform_pxa_serial_funcs *)(dev)->platform_data)->method(args)
+
 static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
 {
 	offset <<= 2;
@@ -347,6 +356,9 @@
 	unsigned long flags;
 	int retval;
 
+	/* Perform platform-specific port initialization, if needed. */
+	SAFE_METHOD_CALL(port->dev, configure, PXA_UART_CFG_PRE_STARTUP);
+
 	if (port->line == 3) /* HWUART */
 		up->mcr |= UART_MCR_AFE;
 	else
@@ -404,6 +416,12 @@
 	(void) serial_in(up, UART_IIR);
 	(void) serial_in(up, UART_MSR);
 
+	/*
+	 * Perform platform-specific port initialization if needed
+	 */
+	SAFE_METHOD_CALL(port->dev, configure, PXA_UART_CFG_POST_STARTUP);
+	SAFE_METHOD_CALL(port->dev, set_txrx, PXA_SERIAL_RX);
+
 	return 0;
 }
 
@@ -412,6 +430,8 @@
 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
 	unsigned long flags;
 
+	SAFE_METHOD_CALL(port->dev, configure, PXA_UART_CFG_PRE_SHUTDOWN);
+
 	free_irq(up->port.irq, up);
 
 	/*
@@ -433,6 +453,8 @@
 				  UART_FCR_CLEAR_RCVR |
 				  UART_FCR_CLEAR_XMIT);
 	serial_out(up, UART_FCR, 0);
+
+	SAFE_METHOD_CALL(port->dev, configure, PXA_UART_CFG_POST_SHUTDOWN);
 }
 
 static void
Index: linux-2.6.24/arch/arm/mach-pxa/generic.c
===================================================================
--- linux-2.6.24.orig/arch/arm/mach-pxa/generic.c	2008-01-24 22:58:37.000000000 +0000
+++ linux-2.6.24/arch/arm/mach-pxa/generic.c	2008-03-10 16:09:23.000000000 +0000
@@ -38,6 +38,7 @@
 #include <asm/arch/mmc.h>
 #include <asm/arch/irda.h>
 #include <asm/arch/i2c.h>
+#include <asm/arch/serial.h>
 
 #include "devices.h"
 #include "generic.h"
@@ -412,6 +413,18 @@
 	.num_resources	= ARRAY_SIZE(pxa_resource_hwuart),
 };
 
+void __init pxa_set_ffuart_info(struct platform_pxa_serial_funcs *info)
+{
+ 	pxa_device_ffuart.dev.platform_data = info;
+}
+EXPORT_SYMBOL(pxa_set_ffuart_info);
+
+void __init pxa_set_btuart_info(struct platform_pxa_serial_funcs *info)
+{
+ 	pxa_device_btuart.dev.platform_data = info;
+}
+EXPORT_SYMBOL(pxa_set_btuart_info);
+
 static struct resource pxai2c_resources[] = {
 	{
 		.start	= 0x40301680,
Index: linux-2.6.24/drivers/leds/Makefile
===================================================================
--- linux-2.6.24.orig/drivers/leds/Makefile	2008-01-24 22:58:37.000000000 +0000
+++ linux-2.6.24/drivers/leds/Makefile	2008-03-10 16:09:23.000000000 +0000
@@ -15,6 +15,7 @@
 obj-$(CONFIG_LEDS_NET48XX)		+= leds-net48xx.o
 obj-$(CONFIG_LEDS_WRAP)			+= leds-wrap.o
 obj-$(CONFIG_LEDS_H1940)		+= leds-h1940.o
+obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
 obj-$(CONFIG_LEDS_COBALT_QUBE)		+= leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)		+= leds-cobalt-raq.o
 obj-$(CONFIG_LEDS_GPIO)			+= leds-gpio.o
Index: linux-2.6.24/drivers/input/keyboard/Kconfig
===================================================================
--- linux-2.6.24.orig/drivers/input/keyboard/Kconfig	2008-01-24 22:58:37.000000000 +0000
+++ linux-2.6.24/drivers/input/keyboard/Kconfig	2008-03-10 16:09:23.000000000 +0000
@@ -293,4 +293,11 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called bf54x-keys.
 
+config KEYBOARD_ASIC3
+        tristate "Buttons on ASIC3 SoC GPIOs (iPaqs, etc.)"
+        depends on HTC_ASIC3
+        help
+          This enables support for the buttons attached to GPIOs of
+          HTC ASIC3 peripheral controller.
+
 endif
Index: linux-2.6.24/drivers/mmc/host/Kconfig
===================================================================
--- linux-2.6.24.orig/drivers/mmc/host/Kconfig	2008-01-24 22:58:37.000000000 +0000
+++ linux-2.6.24/drivers/mmc/host/Kconfig	2008-03-10 16:09:59.000000000 +0000
@@ -24,6 +24,13 @@
 
 	  If unsure, say N.
 
+config MMC_ASIC3
+	tristate "HTC ASIC3 SD/MMC support"
+	depends on MMC && HTC_ASIC3
+	help
+	  This provides support for the ASIC3 SD/MMC controller, used
+	  in the iPAQ hx4700 and others.
+
 config MMC_SDHCI
 	tristate "Secure Digital Host Controller Interface support  (EXPERIMENTAL)"
 	depends on PCI && EXPERIMENTAL
Index: linux-2.6.24/drivers/input/keyboard/Makefile
===================================================================
--- linux-2.6.24.orig/drivers/input/keyboard/Makefile	2008-01-24 22:58:37.000000000 +0000
+++ linux-2.6.24/drivers/input/keyboard/Makefile	2008-03-10 16:10:28.000000000 +0000
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)		+= sunkbd.o
+obj-$(CONFIG_KEYBOARD_ASIC3)		+= asic3_keys.o
 obj-$(CONFIG_KEYBOARD_LKKBD)		+= lkkbd.o
 obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
