Merge remote branch 'common/android-2.6.35' into android-msm-2.6.35
diff --git a/Documentation/android.txt b/Documentation/android.txt
index 72a62af..e1e4188 100644
--- a/Documentation/android.txt
+++ b/Documentation/android.txt
@@ -14,6 +14,12 @@
   1.3 Recommended enabled config options
 2. Contact
 
+0. Getting sources:
+-----------------
+
+git clone  --reference /path/to/linux-git/for/speedup/ git://android.git.kernel.org/kernel/msm.git
+git checkout -b android-msm-2.6.29 origin/android-msm-2.6.29
+
 
 1. Android
 ==========
@@ -26,6 +32,7 @@
 which can be found at http://android.git.kernel.org in kernel/common.git
 and kernel/msm.git
 
+msm_defconfig should work on qualcomm reference design, HTC Magic and G1/ADP1.
 
 1.1 Required enabled config options
 -----------------------------------
@@ -114,6 +121,23 @@
 SERIAL_CORE_CONSOLE
 
 
+Board code names
+----------------
+
+board-halibut - Qualcomm SURF 7201A
+board-sapphire - HTC Magic
+board-trout - HTC Dream / T-Mobile G1 / Android ADP1
+
+Booting your kernel
+-------------------
+
+hold down camera and red button to boot into rainbow screen. Then
+
+./fastboot boot linux-msm/arch/arm/boot/zImage ramdisk.img
+
+Machine will freeze at rainbow screen for a while, be
+patient. ramdisk.img is required.
+
 2. Contact
 ==========
 website: http://android.git.kernel.org
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4824fb4f..ce16900 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -584,7 +584,10 @@
 
 config ARCH_MSM
 	bool "Qualcomm MSM"
+	select ARCH_HAS_CPUFREQ
+	select ARCH_REQUIRE_GPIOLIB
 	select HAVE_CLK
+	select GENERIC_GPIO
 	select GENERIC_CLOCKEVENTS
 	help
 	  Support for Qualcomm MSM/QSD based systems.  This runs on the
@@ -1302,6 +1305,13 @@
 	  Enable hardware performance counter support for perf events. If
 	  disabled, perf events will use software events only.
 
+config VMALLOC_RESERVE
+	hex "Reserved vmalloc space"
+	default 0x08000000
+	depends on MMU
+	help
+	  Reserved vmalloc space if not specified on the kernel commandline.
+
 source "mm/Kconfig"
 
 config LEDS
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 95327b4..1659f471 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -21,7 +21,7 @@
 
 #if defined(CONFIG_DEBUG_ICEDCC)
 
-#ifdef defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V7)
+#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V7)
 		.macro	loadsp, rb, tmp
 		.endm
 		.macro	writeb, ch, rb
diff --git a/arch/arm/configs/mahimahi_defconfig b/arch/arm/configs/mahimahi_defconfig
new file mode 100644
index 0000000..9da5f98
--- /dev/null
+++ b/arch/arm/configs/mahimahi_defconfig
@@ -0,0 +1,291 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_ELF_CORE is not set
+CONFIG_ASHMEM=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_QSD8X50=y
+CONFIG_MSM_DEBUG_UART1=y
+CONFIG_HTC_35MM_JACK=y
+# CONFIG_HTC_PWRSINK is not set
+CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=50000000
+CONFIG_MSM_SERIAL_DEBUGGER=y
+CONFIG_MSM_SERIAL_DEBUGGER_NO_SLEEP=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_WIFI_CONTROL_FUNC=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x30000000
+CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=64M console=ttyMSM,115200n8"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_PM=y
+CONFIG_WAKELOCK=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LED=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_ADDRTYPE=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_RFKILL=y
+# CONFIG_RFKILL_PM is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_UID_STAT=y
+CONFIG_SENSORS_AKM8973=y
+CONFIG_VP_A1026=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_IFB=y
+CONFIG_DUMMY=y
+CONFIG_BCM4329=m
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+CONFIG_INPUT_CAPELLA_CM3602=y
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_BCM_BT_LPM=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_W1_MASTER_DS2482=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_DS2784=y
+# CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+CONFIG_REGULATOR_TPS65023=y
+CONFIG_MEDIA_SUPPORT=y
+# CONFIG_IR_CORE is not set
+CONFIG_MSM_CAMERA=y
+CONFIG_S5K3E2FX=y
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+# CONFIG_FB_MSM_MDDI is not set
+CONFIG_GPU_MSM_KGSL=y
+CONFIG_MSM_KGSL_MMU=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_ANDROID=y
+CONFIG_USB_ANDROID_ADB=y
+CONFIG_USB_ANDROID_DIAG=y
+CONFIG_USB_ANDROID_MASS_STORAGE=y
+CONFIG_USB_ANDROID_RNDIS=y
+CONFIG_USB_ANDROID_RNDIS_WCEIS=y
+CONFIG_USB_ANDROID_ACCESSORY=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_MSM7X00A=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_SLEEP=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_INTF_SYSFS is not set
+# CONFIG_RTC_INTF_PROC is not set
+# CONFIG_RTC_INTF_DEV is not set
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_ARM_UNWIND is not set
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/arm/configs/msm_defconfig b/arch/arm/configs/msm_defconfig
old mode 100644
new mode 100755
index 2b8f7af..6eb7696
--- a/arch/arm/configs/msm_defconfig
+++ b/arch/arm/configs/msm_defconfig
@@ -1,72 +1,267 @@
 CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_ELF_CORE is not set
+CONFIG_ASHMEM=y
 CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARCH_MSM=y
-CONFIG_MACH_HALIBUT=y
+CONFIG_HTC_HEADSET=y
+CONFIG_MSM_SERIAL_DEBUGGER=y
+CONFIG_WIFI_CONTROL_FUNC=y
+CONFIG_WIFI_MEM_PREALLOC=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 # CONFIG_OABI_COMPAT is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="mem=64M console=ttyMSM,115200n8"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_PM=y
+CONFIG_WAKELOCK=y
 CONFIG_NET=y
+CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_NET_KEY=y
 CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+CONFIG_INET_ESP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LED=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_ADDRTYPE=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_RFKILL=y
+# CONFIG_RFKILL_PM is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_UID_STAT=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
 CONFIG_NETDEVICES=y
+CONFIG_IFB=y
 CONFIG_DUMMY=y
+CONFIG_TUN=y
 CONFIG_NET_ETHERNET=y
 CONFIG_SMC91X=y
 CONFIG_PPP=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_DEFLATE=y
 CONFIG_PPP_BSDCOMP=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_MSM_RMNET_DEBUG=y
+# CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ELAN_I2C_8232=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI=y
 CONFIG_INPUT_MISC=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
 # CONFIG_SERIO is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_VT is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_RX_WAKEUP=y
+CONFIG_SERIAL_MSM_HS=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
+CONFIG_POWER_SUPPLY=y
 # CONFIG_HWMON is not set
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+CONFIG_MSM_CAMERA=y
+CONFIG_MT9T013=y
+CONFIG_DAB=y
 CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_FB_MSM=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_ANDROID=y
+CONFIG_USB_ANDROID_ADB=y
+CONFIG_USB_ANDROID_MASS_STORAGE=y
+CONFIG_USB_ANDROID_RNDIS=y
+CONFIG_USB_ANDROID_RNDIS_WCEIS=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_MSM7X00A=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_SLEEP=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_INTF_SYSFS is not set
+# CONFIG_RTC_INTF_PROC is not set
+# CONFIG_RTC_INTF_DEV is not set
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
 CONFIG_INOTIFY=y
+CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_SCHEDSTATS=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_LL=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/arm/configs/surf7x30_defconfig b/arch/arm/configs/surf7x30_defconfig
new file mode 100644
index 0000000..4538e22
--- /dev/null
+++ b/arch/arm/configs/surf7x30_defconfig
@@ -0,0 +1,210 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_ELF_CORE is not set
+CONFIG_ASHMEM=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM7X30=y
+CONFIG_MSM_DEBUG_UART1=y
+# CONFIG_HTC_PWRSPLY is not set
+# CONFIG_HTC_PWRSINK is not set
+CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT=y
+CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT=y
+CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=50000000
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_HW3D is not set
+CONFIG_WIFI_CONTROL_FUNC=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x30000000
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyMSM,115200n8"
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_PM=y
+CONFIG_WAKELOCK=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_RFKILL=y
+# CONFIG_RFKILL_PM is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_KERNEL_DEBUGGER_CORE=y
+CONFIG_UID_STAT=y
+CONFIG_APANIC=y
+CONFIG_APANIC_PLABEL="crashdata"
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMC91X=y
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_MSM=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+CONFIG_INPUT_CAPELLA_CM3602=y
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_W1=y
+CONFIG_W1_MASTER_DS2482=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+CONFIG_DAB=y
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_ANDROID=y
+CONFIG_USB_ANDROID_ACM=y
+CONFIG_USB_ANDROID_ADB=y
+CONFIG_USB_ANDROID_DIAG=y
+CONFIG_USB_ANDROID_MASS_STORAGE=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_SLEEP=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_INTF_SYSFS is not set
+# CONFIG_RTC_INTF_PROC is not set
+# CONFIG_RTC_INTF_DEV is not set
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_SLAB=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+CONFIG_DEBUG_HIGHMEM=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+CONFIG_DEBUG_SG=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/arm/configs/swordfish_defconfig b/arch/arm/configs/swordfish_defconfig
new file mode 100644
index 0000000..38fc1f1d
--- /dev/null
+++ b/arch/arm/configs/swordfish_defconfig
@@ -0,0 +1,167 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_ELF_CORE is not set
+CONFIG_ASHMEM=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_QSD8X50=y
+CONFIG_MSM_DEBUG_UART3=y
+# CONFIG_HTC_PWRSINK is not set
+CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT=y
+CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT=y
+# CONFIG_MSM_IDLE_STATS is not set
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_HW3D is not set
+# CONFIG_MSM_ADSP is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=64M console=ttyMSM,115200n8"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_PM=y
+CONFIG_WAKELOCK=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_RFKILL=y
+# CONFIG_RFKILL_PM is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_KERNEL_DEBUGGER_CORE=y
+CONFIG_UID_STAT=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMC91X=y
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_MSM=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_HWMON is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_GPU_MSM_KGSL=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_MSM7X00A=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_SLEEP=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_INTF_SYSFS is not set
+# CONFIG_RTC_INTF_PROC is not set
+# CONFIG_RTC_INTF_DEV is not set
+# CONFIG_RTC_DRV_MSM7X00A is not set
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+CONFIG_DEBUG_SG=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_DEBUG_LL=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h
index cc7ef40..5fc2fdb 100644
--- a/arch/arm/include/asm/domain.h
+++ b/arch/arm/include/asm/domain.h
@@ -27,8 +27,13 @@
  *
  * 36-bit addressing and supersections are only available on
  * CPUs based on ARMv6+ or the Intel XSC3 core.
+ *
+ * We cannot use domain 0 for the kernel on QSD8x50 since the kernel domain
+ * is set to manager mode when set_fs(KERNEL_DS) is called. Setting domain 0
+ * to manager mode will disable the workaround for a cpu bug that can cause an
+ * invalid fault status and/or tlb corruption (CONFIG_VERIFY_PERMISSION_FAULT).
  */
-#ifndef CONFIG_IO_36
+#if !defined(CONFIG_IO_36) && !defined(CONFIG_VERIFY_PERMISSION_FAULT)
 #define DOMAIN_KERNEL	0
 #define DOMAIN_TABLE	0
 #define DOMAIN_USER	1
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
new file mode 100644
index 0000000..f8d391a
--- /dev/null
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -0,0 +1,27 @@
+/*
+ *  arch/arm/include/asm/mach/mmc.h
+ */
+#ifndef ASMARM_MACH_MMC_H
+#define ASMARM_MACH_MMC_H
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+
+struct embedded_sdio_data {
+        struct sdio_cis cis;
+        struct sdio_cccr cccr;
+        struct sdio_embedded_func *funcs;
+        int num_funcs;
+};
+
+struct mmc_platform_data {
+	unsigned int ocr_mask;			/* available voltages */
+	int built_in;				/* built-in device flag */
+	u32 (*translate_vdd)(struct device *, unsigned int);
+	unsigned int (*status)(struct device *);
+	struct embedded_sdio_data *embedded_sdio;
+	int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
+};
+
+#endif
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index ab68cf1..bd5a47b 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -21,6 +21,7 @@
 
 #include <asm/memory.h>
 #include <mach/vmalloc.h>
+#include <mach/memory.h>
 #include <asm/pgtable-hwdef.h>
 
 /*
@@ -314,6 +315,8 @@
 	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
 #define pgprot_writecombine(prot) \
 	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
+#define pgprot_device(prot) \
+	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_NONSHARED)
 #ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
 #define pgprot_dmacoherent(prot) \
 	__pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_BUFFERABLE)
@@ -451,8 +454,17 @@
  * remap a physical page `pfn' of size `size' with page protection `prot'
  * into virtual address `from'
  */
+
+
+#ifndef HAS_ARCH_IO_REMAP_PFN_RANGE
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
-		remap_pfn_range(vma, from, pfn, size, prot)
+	remap_pfn_range(vma,from,pfn,size,prot)
+#else
+extern int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, unsigned long size, pgprot_t prot);
+#define io_remap_pfn_range(vma,from,pfn,size,prot) \
+	arch_io_remap_pfn_range(vma,from,pfn,size,prot)
+#endif
+
 
 #define pgtable_cache_init() do { } while (0)
 
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 763e29f..f6771bf 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -75,7 +75,7 @@
 	.flags		= 0,						\
 	.preempt_count	= INIT_PREEMPT_COUNT,				\
 	.addr_limit	= KERNEL_DS,					\
-	.cpu_domain	= domain_val(DOMAIN_USER, DOMAIN_MANAGER) |	\
+	.cpu_domain	= domain_val(DOMAIN_USER, DOMAIN_CLIENT) |	\
 			  domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) |	\
 			  domain_val(DOMAIN_IO, DOMAIN_CLIENT),		\
 	.restart_block	= {						\
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index eb62bf9..49dbcd3 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -172,9 +172,9 @@
 #ifdef CONFIG_CPU_ICACHE_DISABLE
 	bic	r0, r0, #CR_I
 #endif
-	mov	r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
+	mov	r5, #(domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \
 		      domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
-		      domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
+		      domain_val(DOMAIN_TABLE, DOMAIN_CLIENT) | \
 		      domain_val(DOMAIN_IO, DOMAIN_CLIENT))
 	mcr	p15, 0, r5, c3, c0, 0		@ load domain access register
 	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 47264a7..041d977 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -15,17 +15,19 @@
 	bool "MSM7x30"
 	select ARCH_MSM_SCORPION
 	select MSM_SMD
-	select MSM_VIC
 	select CPU_V7
 	select MSM_REMOTE_SPINLOCK_DEKKERS
+	select VERIFY_PERMISSION_FAULT
+	select MSM_DAL
 
 config ARCH_QSD8X50
 	bool "QSD8X50"
 	select ARCH_MSM_SCORPION
 	select MSM_SMD
-	select MSM_VIC
 	select CPU_V7
 	select MSM_REMOTE_SPINLOCK_LDREX
+	select MSM_DAL
+	select VERIFY_PERMISSION_FAULT
 endchoice
 
 config MSM_SOC_REV_A
@@ -36,14 +38,74 @@
 config  ARCH_MSM_SCORPION
 	bool
 
-config  MSM_VIC
+config MSM_MDP22
 	bool
+	depends on ARCH_MSM7X00A
+	default y
+
+config MSM_MDP31
+	bool
+	depends on ARCH_QSD8X50
+	default y
+
+config MSM_MDP40
+	bool
+	depends on ARCH_MSM7X30
+	default y
+
+config MSM_REMOTE_SPINLOCK_DEKKERS
+	bool
+
+config MSM_REMOTE_SPINLOCK_SWP
+	bool
+
+config MSM_REMOTE_SPINLOCK_LDREX
+	bool
+
+config MSM_REMOTE_SPINLOCK
+	bool
+	depends on MSM_REMOTE_SPINLOCK_LDREX || MSM_REMOTE_SPINLOCK_SWP || \
+		MSM_REMOTE_SPINLOCK_DEKKERS
+	default y
+
+config MSM_LEGACY_7X00A_AMSS
+	bool
+
+config MSM_AMSS_VERSION
+	int
+	default 6210 if MSM_AMSS_VERSION_6210
+	default 6220 if MSM_AMSS_VERSION_6220
+	default 6225 if MSM_AMSS_VERSION_6225
+	default 6350 if MSM_AMSS_VERSION_6350
+
+choice
+	prompt "AMSS modem firmware version"
+
+	depends on ARCH_MSM7X00A
+	default MSM_AMSS_VERSION_6225
+
+	config MSM_AMSS_VERSION_6210
+		bool "6.2.10"
+		select MSM_LEGACY_7X00A_AMSS
+
+	config MSM_AMSS_VERSION_6220
+		bool "6.2.20"
+		select MSM_LEGACY_7X00A_AMSS
+
+	config MSM_AMSS_VERSION_6225
+		bool "6.2.20 + New ADSP"
+		select MSM_LEGACY_7X00A_AMSS
+
+	config MSM_AMSS_VERSION_6350
+		bool "6.3.50"
+endchoice
 
 menu "Qualcomm MSM Board Type"
 
 config MACH_HALIBUT
 	depends on ARCH_MSM
 	depends on ARCH_MSM7X00A
+	default n
 	bool "Halibut Board (QCT SURF7201A)"
 	help
 	  Support for the Qualcomm SURF7201A eval board.
@@ -51,6 +113,7 @@
 config MACH_TROUT
 	depends on ARCH_MSM
 	depends on ARCH_MSM7X00A
+	default n
 	bool "HTC Dream (aka trout)"
 	help
 	  Support for the HTC Dream, T-Mobile G1, Android ADP1 devices.
@@ -61,6 +124,13 @@
 	help
 	  Support for the Qualcomm MSM7x30 SURF eval board.
 
+config MACH_SWORDFISH
+	depends on ARCH_QSD8X50
+	default y
+	bool "Swordfish Board (QCT SURF8250)"
+	help
+	  Support for the Qualcomm SURF8250 eval board.
+
 config MACH_QSD8X50_SURF
 	depends on ARCH_QSD8X50
 	bool "QSD8x50 SURF"
@@ -103,7 +173,354 @@
 config MSM_SMD_PKG3
 	bool
 
+config MACH_SAPPHIRE
+	depends on ARCH_MSM7X00A && !MACH_TROUT && !MACH_HALIBUT
+	default y
+	bool "Sapphire"
+
+config MACH_MAHIMAHI
+	depends on ARCH_QSD8X50
+	default y
+	bool "Mahi-Mahi"
+	help
+	  Select this to support the Mahi-Mahi device
+
+config MACH_QSD8X50_FFA
+	depends on ARCH_QSD8X50
+	default y
+	bool "8x50-ffa"
+	help
+	  Select this to support the 8x50 ffa device
+
+config MACH_MSM7X30_SURF
+	depends on ARCH_MSM7X30
+	default y
+	bool "QCT SURF7x30 Board"
+	help
+	  Select this to support the Qualcomm SURF7X30 development board
+
+config HTC_HEADSET
+	tristate "HTC 2 Wire detection driver"
+	default n
+	help
+	 Provides support for detecting HTC 2 wire devices, such as wired
+	 headset, on the trout platform. Can be used with the msm serial
+	 debugger, but not with serial console.
+
+config HTC_35MM_JACK
+	bool "HTC 3.5mm headset jack"
+	default n
+	help
+	 Provides support for 3.5mm headset jack devices, like wired headsets.
+
+config TROUT_BATTCHG
+	depends on (MACH_TROUT || MACH_SAPPHIRE) && POWER_SUPPLY
+	default y
+	bool "Trout battery / charger driver"
+
+config HTC_PWRSPLY
+	depends on MSM_ONCRPCROUTER && POWER_SUPPLY && !TROUT_BATTCHG
+	default y
+	bool "HTC Power supply driver"
+	help
+	  Used by HTC devices with a dedicated battery gauge"
+
+config HTC_PWRSINK
+	depends on MSM_SMD
+	default y
+	bool "HTC Power Sink Driver"
+
+config CACHE_FLUSH_RANGE_LIMIT
+	hex "Cache flush range limit"
+	default 0x40000
+	help
+	  When flushing a cache range larger then this (hex) limit, flush the
+	  entire cache instead. Flushing a large range can be slower than
+	  flushing, then refilling, the entire cache.
+
+choice
+	prompt "Default Timer"
+	default MSM7X00A_USE_GP_TIMER
+
+	config MSM7X00A_USE_GP_TIMER
+		bool "GP Timer"
+	help
+	  Low resolution timer that allows power collapse from idle.
+
+	config MSM7X00A_USE_DG_TIMER
+		bool "DG Timer"
+	help
+	  High resolution timer.
+endchoice	  
+
+choice
+	prompt "Suspend sleep mode"
+	default MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+	help
+	  Allows overriding the sleep mode used. Leave at power
+	  collapse suspend unless the arm9 image has problems.
+
+	config MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+		bool "Power collapse suspend"
+	help
+	  Lowest sleep state. Returns through reset vector.
+
+	config MSM7X00A_SLEEP_MODE_POWER_COLLAPSE
+		bool "Power collapse"
+	help
+	  Sleep state that returns through reset vector.
+
+	config MSM7X00A_SLEEP_MODE_APPS_SLEEP
+		bool "Apps Sleep"
+
+	config MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+		bool "Ramp down cpu clock and wait for interrupt"
+
+	config MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT
+		bool "Wait for interrupt"
+endchoice	  
+
+config MSM7X00A_SLEEP_MODE
+	int
+	default 0 if MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+	default 1 if MSM7X00A_SLEEP_MODE_POWER_COLLAPSE
+	default 2 if MSM7X00A_SLEEP_MODE_APPS_SLEEP
+	default 3 if MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+	default 4 if MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT
+
+choice
+	prompt "Idle sleep mode"
+	default MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE
+	help
+	  Allows overriding the sleep mode used from idle. Leave at power
+	  collapse suspend unless the arm9 image has problems.
+
+	config MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+		bool "Power collapse suspend"
+	help
+	  Lowest sleep state. Returns through reset vector.
+
+	config MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE
+		bool "Power collapse"
+	help
+	  Sleep state that returns through reset vector.
+
+	config MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP
+		bool "Apps Sleep"
+
+	config MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+		bool "Ramp down cpu clock and wait for interrupt"
+
+	config MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT
+		bool "Wait for interrupt"
+endchoice	  
+
+config MSM7X00A_IDLE_SLEEP_MODE
+	int
+	default 0 if MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+	default 1 if MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE
+	default 2 if MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP
+	default 3 if MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+	default 4 if MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT
+
+config MSM7X00A_IDLE_SLEEP_MIN_TIME
+	int "Minimum idle time before sleep"
+	default 20000000
+	help
+	  Minimum idle time in nanoseconds before entering low power mode.
+
+config MSM7X00A_IDLE_SPIN_TIME
+	int "Idle spin time before cpu ramp down"
+	default 80000
+	help
+	  Spin time in nanoseconds before ramping down cpu clock and entering
+	  any low power state.
+
+menuconfig MSM_IDLE_STATS
+	bool "Collect idle statistics"
+	default y
+	help
+	  Collect idle statistics and export them in proc/msm_pm_stats.
+
+if MSM_IDLE_STATS
+
+config MSM_IDLE_STATS_FIRST_BUCKET
+	int "First bucket time"
+	default 62500
+	help
+	  Upper time limit in nanosconds of first bucket.
+
+config MSM_IDLE_STATS_BUCKET_SHIFT
+	int "Bucket shift"
+	default 2
+
+config MSM_IDLE_STATS_BUCKET_COUNT
+	int "Bucket count"
+	default 10
+
+endif # MSM_IDLE_STATS
+
+config MSM_FIQ_SUPPORT
+	default y
+	bool "Enable installation of an FIQ handler."
+
+config MSM_SERIAL_DEBUGGER
+	select MSM_FIQ_SUPPORT
+	select KERNEL_DEBUGGER_CORE
+	default n
+	bool "FIQ Mode Serial Debugger"
+	help
+	  The FIQ serial debugger can accept commands even when the
+	  kernel is unresponsive due to being stuck with interrupts
+	  disabled.  Depends on the kernel debugger core in drivers/misc.
+
+config MSM_SERIAL_DEBUGGER_NO_SLEEP
+	depends on MSM_SERIAL_DEBUGGER
+	default n
+	bool "Keep serial debugger active"
+	help
+	  Enables the serial debugger at boot. Passing
+	  msm_serial_debugger.no_sleep on the kernel commandline will
+	  override this config option.
+
+config MSM_SERIAL_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
+	depends on MSM_SERIAL_DEBUGGER
+	default n
+	bool "Don't disable wakeup IRQ when debugger is active"
+	help
+	  Don't disable the wakeup irq when enabling the uart clock. This will
+	  cause extra interrupts, but it makes the serial debugger usable with
+	  radio builds that ignore the uart clock request in power collapse.
+
+config MSM_SERIAL_DEBUGGER_CONSOLE
+	depends on MSM_SERIAL_DEBUGGER
+	default n
+	bool "Console on FIQ Serial Debugger port"
+	help
+	  Enables a console so that printk messages are displayed on
+	  the debugger serial port as the occur.
+
 config MSM_SMD
 	bool
 
+config MSM_DAL
+	default n 
+	bool "MSM Driver Access Layer (DAL RPC)"
+	help
+	  Support for the DAL RPC interface used to communicate with
+	  the baseband processor or DSP in newer Qualcomm MSM/QSD
+	  chips.
+
+config MSM_ONCRPCROUTER
+	depends on MSM_SMD
+	default y
+	bool "MSM ONCRPC router support"
+	help
+	  Support for the MSM ONCRPC router for communication between
+	  the ARM9 and ARM11
+
+config MSM_RPCSERVERS
+	depends on MSM_ONCRPCROUTER && ARCH_MSM7X00A
+	default y
+	bool "Kernel side RPC server bundle"
+	help
+	  none
+
+config MSM_CPU_FREQ_SCREEN
+	bool
+	default n
+	depends on HAS_EARLYSUSPEND
+	help
+	  Simple cpufreq scaling based on screen ON/OFF.
+
+if MSM_CPU_FREQ_SCREEN
+
+config MSM_CPU_FREQ_SCREEN_OFF
+	int "Screen off cpu frequency"
+	default 245760
+
+config MSM_CPU_FREQ_SCREEN_ON
+	int "Screen on cpu frequency"
+	default 384000
+
+endif # MSM_CPU_FREQ_SCREEN
+
+config MSM_HW3D
+	tristate "MSM Hardware 3D Register Driver"
+	depends on EARLYSUSPEND
+	default y
+	help
+	  Provides access to registers needed by the userspace OpenGL|ES
+	  library.
+
+config MSM_ADSP
+	depends on ARCH_MSM7X00A
+	tristate "MSM ADSP driver"
+	default y
+	help
+	  Provides access to registers needed by the userspace aDSP library.
+
+config MSM_ADSP_REPORT_EVENTS
+	bool "Report modem events from the DSP"
+	default y
+	depends on MSM_ADSP
+	help
+	  Normally, only messages from the aDSP are reported to userspace.
+	  With this option, we report events from the aDSP as well.
+
+config MSM_QDSP6
+	tristate "QDSP6 support"
+	depends on ARCH_QSD8X50
+	default y
+	help
+	  Enable support for qdsp6. This provides audio and video functionality.
+
+config MSM_QDSP5V2
+	tristate "QDSP5V2 support"
+	depends on ARCH_MSM7X30
+	default y
+	help
+	  Enable support for qdsp5v2, which provides audio processing on 7x30.
+
+config MSM_SSBI
+	tristate "SSBI support"
+	depends on ARCH_MSM7X30
+	default n
+	help
+	  Enable support for SSBI bus. This is required for communicatinig with
+	  Qualcomm PMICs and Audio codecs.
+
+config WIFI_CONTROL_FUNC
+	bool "Enable WiFi control function abstraction"
+	help
+	  Enables Power/Reset/Carddetect function abstraction
+	
+config WIFI_MEM_PREALLOC
+	depends on WIFI_CONTROL_FUNC
+	bool "Preallocate memory for WiFi buffers"
+	help
+	  Preallocates memory buffers for WiFi driver
+
+config VIRTUAL_KPANIC_PARTITION
+	bool "Create virtual kpanic partition"
+	default n
+	help
+	  Creates a virtual mtd partition named 'kpanic', stealing space from
+	  the specified mtd partition label.
+	  *** DO NOT USE IF YOU ARE USING OTA/RECOVERY ***
+
+config VIRTUAL_KPANIC_PSIZE
+	depends on VIRTUAL_KPANIC_PARTITION
+	int "Default kpanic partition size"
+	default 1048576
+	help
+	  Sets the size of the virtual kpanic paritition to create.
+
+config VIRTUAL_KPANIC_SRC
+	depends on VIRTUAL_KPANIC_PARTITION
+	string "Partition to steal from"
+	default "cache"
+	help
+	  Sets the partition to steal from to make the virtual one.
+	
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 66677f0..e52f964 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -1,22 +1,74 @@
 obj-y += proc_comm.o
-obj-y += io.o idle.o timer.o dma.o
+obj-y += io.o irq.o timer.o dma.o memory.o
 obj-y += vreg.o
-obj-y += acpuclock-arm11.o
+obj-y += pmic.o
+obj-$(CONFIG_ARCH_MSM_ARM11) += acpuclock-arm11.o idle.o
+obj-$(CONFIG_ARCH_MSM_SCORPION) += idle-v7.o
+obj-$(CONFIG_ARCH_MSM_SCORPION) += arch-init-scorpion.o
+obj-$(CONFIG_ARCH_QSD8X50) += acpuclock-qsd8x50.o
+obj-$(CONFIG_ARCH_MSM7X30) += acpuclock-7x30.o
 obj-y += clock.o clock-pcom.o
-obj-y += gpio.o
-
-ifdef CONFIG_MSM_VIC
-obj-y += irq-vic.o
-else
-obj-y += irq.o
-endif
+obj-y += gpio.o generic_gpio.o
+obj-y += nand_partitions.o
 
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
+obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
+obj-$(CONFIG_MSM_SMD) += smd_tty.o smd_qmi.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
+obj-$(CONFIG_MSM_DAL) += dal.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o
+obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o
+obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o
+obj-$(CONFIG_MSM_ADSP) += qdsp5/
+obj-$(CONFIG_MSM_QDSP5V2) += qdsp5v2/
+obj-$(CONFIG_MSM_QDSP6) += qdsp6/
+obj-$(CONFIG_MSM_HW3D) += hw3d.o
+obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+obj-$(CONFIG_MSM_REMOTE_SPINLOCK) += remote_spinlock.o
+obj-$(CONFIG_MSM_SSBI) += ssbi.o
 
 obj-$(CONFIG_MACH_TROUT) += board-trout.o devices-msm7x00.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-gpio.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-keypad.o board-trout-panel.o
+obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-wifi.o
+obj-$(CONFIG_MACH_TROUT) += devices_htc.o
+obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-mmc.o board-sapphire-wifi.o
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-rfkill.o msm_vibrator.o
+obj-$(CONFIG_MACH_SAPPHIRE) += devices_htc.o
+obj-$(CONFIG_MACH_SAPPHIRE) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o
+obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi.o board-mahimahi-panel.o
+obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-keypad.o board-mahimahi-mmc.o
+obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-rfkill.o htc_wifi_nvs.o
+obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-wifi.o board-mahimahi-audio.o
+obj-$(CONFIG_MACH_MAHIMAHI) += msm_vibrator.o
+obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-microp.o
+obj-$(CONFIG_MACH_MAHIMAHI) += htc_acoustic_qsd.o
+obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-flashlight.o
 obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o
+obj-$(CONFIG_MACH_HALIBUT) += board-halibut-keypad.o
+obj-$(CONFIG_MACH_HALIBUT) += board-halibut-panel.o fish_battery.o
+obj-$(CONFIG_MACH_SWORDFISH) += board-swordfish.o
+obj-$(CONFIG_MACH_SWORDFISH) += board-swordfish-keypad.o fish_battery.o
+obj-$(CONFIG_MACH_SWORDFISH) += board-swordfish-panel.o
+obj-$(CONFIG_MACH_SWORDFISH) += board-swordfish-mmc.o
+obj-$(CONFIG_MACH_MSM7X30_SURF) += board-surf7x30.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o
 obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o
 
+obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o
+obj-$(CONFIG_HTC_PWRSPLY) += htc_power_supply.o
+obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
+obj-$(CONFIG_HTC_35MM_JACK) += htc_35mm_jack.o
+
+obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-tpa2018d1.o
+obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-smb329.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 24dfbf8..a423a2e 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -1,3 +1,17 @@
   zreladdr-y		:= 0x10008000
 params_phys-y		:= 0x10000100
 initrd_phys-y		:= 0x10800000
+
+# override for Sapphire
+  zreladdr-$(CONFIG_MACH_SAPPHIRE)		:= 0x02008000
+params_phys-$(CONFIG_MACH_SAPPHIRE)		:= 0x02000100
+initrd_phys-$(CONFIG_MACH_SAPPHIRE)		:= 0x02800000
+
+# for now, override for QSD8x50
+  zreladdr-$(CONFIG_ARCH_QSD8X50)		:= 0x20008000
+params_phys-$(CONFIG_ARCH_QSD8X50)		:= 0x20000100
+initrd_phys-$(CONFIG_ARCH_QSD8X50)		:= 0x21000000
+
+  zreladdr-$(CONFIG_ARCH_MSM7X30)		:= 0x00208000
+params_phys-$(CONFIG_ARCH_MSM7X30)		:= 0x00200100
+initrd_phys-$(CONFIG_ARCH_MSM7X30)		:= 0x01200000
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
new file mode 100644
index 0000000..03087e0
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/sort.h>
+#include <mach/board.h>
+
+#include "acpuclock.h"
+
+unsigned long acpuclk_power_collapse(void)
+{
+	return 0;
+}
+
+unsigned long acpuclk_wait_for_irq(void)
+{
+	return 0;
+}
+
+unsigned long acpuclk_get_wfi_rate(void)
+{
+	return 0;
+}
+
+int acpuclk_set_rate(unsigned long rate, int for_power_collapse)
+{
+	return 0;
+}
+
+unsigned long acpuclk_get_rate(void)
+{
+	return 0;
+}
+
+uint32_t acpuclk_get_switch_time(void)
+{
+	return 0;
+}
+
+static void __init acpuclk_init(void)
+{
+}
+
+void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+{
+	pr_info("acpu_clock_init()\n");
+	acpuclk_init();
+}
diff --git a/arch/arm/mach-msm/acpuclock-qsd8x50.c b/arch/arm/mach-msm/acpuclock-qsd8x50.c
new file mode 100644
index 0000000..691acde
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-qsd8x50.c
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2009 Google, Inc.
+ * Copyright (c) 2008 QUALCOMM Incorporated.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/cpufreq.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+
+#include "acpuclock.h"
+#include "proc_comm.h"
+
+#if 0
+#define DEBUG(x...) pr_info(x)
+#else
+#define DEBUG(x...) do {} while (0)
+#endif
+
+#define SHOT_SWITCH	4
+#define HOP_SWITCH	5
+#define SIMPLE_SLEW	6
+#define COMPLEX_SLEW	7
+
+#define SPSS_CLK_CNTL_ADDR	(MSM_CSR_BASE + 0x100)
+#define SPSS_CLK_SEL_ADDR	(MSM_CSR_BASE + 0x104)
+
+/* Scorpion PLL registers */
+#define SCPLL_CTL_ADDR		(MSM_SCPLL_BASE + 0x4)
+#define SCPLL_STATUS_ADDR	(MSM_SCPLL_BASE + 0x18)
+#define SCPLL_FSM_CTL_EXT_ADDR	(MSM_SCPLL_BASE + 0x10)
+
+struct clkctl_acpu_speed {
+	unsigned acpu_khz;
+	unsigned clk_cfg;
+	unsigned clk_sel;
+	unsigned sc_l_value;
+	unsigned lpj;
+	int      vdd;
+};
+
+/* clock sources */
+#define CLK_TCXO	0 /* 19.2 MHz */
+#define CLK_GLOBAL_PLL	1 /* 768 MHz */
+#define CLK_MODEM_PLL	4 /* 245 MHz (UMTS) or 235.93 MHz (CDMA) */
+
+#define CCTL(src, div) (((src) << 4) | (div - 1))
+
+/* core sources */
+#define SRC_RAW		0 /* clock from SPSS_CLK_CNTL */
+#define SRC_SCPLL	1 /* output of scpll 128-998 MHZ */
+#define SRC_AXI		2 /* 128 MHz */
+#define SRC_PLL1	3 /* 768 MHz */
+
+struct clkctl_acpu_speed acpu_freq_tbl[] = {
+	{  19200, CCTL(CLK_TCXO, 1),		SRC_RAW, 0, 0, 1050 },
+	{ 128000, CCTL(CLK_TCXO, 1),		SRC_AXI, 0, 0, 1050 },
+	{ 245000, CCTL(CLK_MODEM_PLL, 1),	SRC_RAW, 0, 0, 1050 },
+	{ 256000, CCTL(CLK_GLOBAL_PLL, 3),	SRC_RAW, 0, 0, 1050 },
+	{ 384000, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x0A, 0, 1050 },
+	{ 422400, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x0B, 0, 1050 },
+	{ 460800, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x0C, 0, 1050 },
+	{ 499200, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x0D, 0, 1075 },
+	{ 537600, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x0E, 0, 1100 },
+	{ 576000, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x0F, 0, 1100 },
+	{ 614400, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x10, 0, 1125 },
+	{ 652800, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x11, 0, 1150 },
+	{ 691200, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x12, 0, 1175 },
+	{ 729600, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x13, 0, 1200 },
+	{ 768000, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x14, 0, 1200 },
+	{ 806400, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x15, 0, 1225 },
+	{ 844800, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x16, 0, 1250 },
+	{ 883200, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x17, 0, 1275 },
+	{ 921600, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x18, 0, 1275 },
+	{ 960000, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x19, 0, 1275 },
+	{ 998400, CCTL(CLK_TCXO, 1),		SRC_SCPLL, 0x1A, 0, 1275 },
+	{ 0 },
+};
+
+/* select the standby clock that is used when switching scpll
+ * frequencies
+ *
+ * Currently: MPLL
+ */
+struct clkctl_acpu_speed *acpu_stby = &acpu_freq_tbl[2];
+#define IS_ACPU_STANDBY(x)	(((x)->clk_cfg == acpu_stby->clk_cfg) && \
+				 ((x)->clk_sel == acpu_stby->clk_sel))
+
+struct clkctl_acpu_speed *acpu_mpll = &acpu_freq_tbl[2];
+
+#ifdef CONFIG_CPU_FREQ_TABLE
+static struct cpufreq_frequency_table freq_table[ARRAY_SIZE(acpu_freq_tbl)];
+
+static void __init acpuclk_init_cpufreq_table(void)
+{
+	int i;
+	int vdd;
+	for (i = 0; acpu_freq_tbl[i].acpu_khz; i++) {
+		freq_table[i].index = i;
+		freq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+
+		/* Skip speeds using the global pll */
+		if (acpu_freq_tbl[i].acpu_khz == 256000 ||
+				acpu_freq_tbl[i].acpu_khz == 19200)
+			continue;
+
+		vdd = acpu_freq_tbl[i].vdd;
+		/* Allow mpll and the first scpll speeds */
+		if (acpu_freq_tbl[i].acpu_khz == acpu_mpll->acpu_khz ||
+				acpu_freq_tbl[i].acpu_khz == 384000) {
+			freq_table[i].frequency = acpu_freq_tbl[i].acpu_khz;
+			continue;
+		}
+
+		/* Take the fastest speed available at the specified VDD level */
+		if (vdd != acpu_freq_tbl[i + 1].vdd)
+			freq_table[i].frequency = acpu_freq_tbl[i].acpu_khz;
+	}
+
+	freq_table[i].index = i;
+	freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
+}
+#else
+#define acpuclk_init_cpufreq_table() do {} while (0);
+#endif
+
+struct clock_state {
+	struct clkctl_acpu_speed	*current_speed;
+	struct mutex			lock;
+	uint32_t			acpu_switch_time_us;
+	uint32_t			max_speed_delta_khz;
+	uint32_t			vdd_switch_time_us;
+	unsigned long			power_collapse_khz;
+	unsigned long			wait_for_irq_khz;
+	struct regulator                *regulator;
+};
+
+static struct clock_state drv_state = { 0 };
+
+static DEFINE_SPINLOCK(acpu_lock);
+
+#define PLLMODE_POWERDOWN	0
+#define PLLMODE_BYPASS		1
+#define PLLMODE_STANDBY		2
+#define PLLMODE_FULL_CAL	4
+#define PLLMODE_HALF_CAL	5
+#define PLLMODE_STEP_CAL	6
+#define PLLMODE_NORMAL		7
+#define PLLMODE_MASK		7
+
+static void scpll_power_down(void)
+{
+	uint32_t val;
+
+	/* Wait for any frequency switches to finish. */
+	while (readl(SCPLL_STATUS_ADDR) & 0x1)
+		;
+
+	/* put the pll in standby mode */
+	val = readl(SCPLL_CTL_ADDR);
+	val = (val & (~PLLMODE_MASK)) | PLLMODE_STANDBY;
+	writel(val, SCPLL_CTL_ADDR);
+	dmb();
+
+	/* wait to stabilize in standby mode */
+	udelay(10);
+
+	val = (val & (~PLLMODE_MASK)) | PLLMODE_POWERDOWN;
+	writel(val, SCPLL_CTL_ADDR);
+	dmb();
+}
+
+static void scpll_set_freq(uint32_t lval)
+{
+	uint32_t val, ctl;
+
+	if (lval > 33)
+		lval = 33;
+	if (lval < 10)
+		lval = 10;
+
+	/* wait for any calibrations or frequency switches to finish */
+	while (readl(SCPLL_STATUS_ADDR) & 0x3)
+		;
+
+	ctl = readl(SCPLL_CTL_ADDR);
+
+	if ((ctl & PLLMODE_MASK) != PLLMODE_NORMAL) {
+		/* put the pll in standby mode */
+		writel((ctl & (~PLLMODE_MASK)) | PLLMODE_STANDBY, SCPLL_CTL_ADDR);
+		dmb();
+
+		/* wait to stabilize in standby mode */
+		udelay(10);
+
+		/* switch to 384 MHz */
+		val = readl(SCPLL_FSM_CTL_EXT_ADDR);
+		val = (val & (~0x1FF)) | (0x0A << 3) | SHOT_SWITCH;
+		writel(val, SCPLL_FSM_CTL_EXT_ADDR);
+		dmb();
+
+		ctl = readl(SCPLL_CTL_ADDR);
+		writel(ctl | PLLMODE_NORMAL, SCPLL_CTL_ADDR);
+		dmb();
+
+		/* wait for frequency switch to finish */
+		while (readl(SCPLL_STATUS_ADDR) & 0x1)
+			;
+
+		/* completion bit is not reliable for SHOT switch */
+		udelay(25);
+	}
+
+	/* write the new L val and switch mode */
+	val = readl(SCPLL_FSM_CTL_EXT_ADDR);
+	val = (val & (~0x1FF)) | (lval << 3) | HOP_SWITCH;
+	writel(val, SCPLL_FSM_CTL_EXT_ADDR);
+	dmb();
+
+	ctl = readl(SCPLL_CTL_ADDR);
+	writel(ctl | PLLMODE_NORMAL, SCPLL_CTL_ADDR);
+	dmb();
+
+	/* wait for frequency switch to finish */
+	while (readl(SCPLL_STATUS_ADDR) & 0x1)
+		;
+}
+
+/* this is still a bit weird... */
+static void select_clock(unsigned src, unsigned config)
+{
+	uint32_t val;
+
+	if (src == SRC_RAW) {
+		uint32_t sel = readl(SPSS_CLK_SEL_ADDR);
+		unsigned shift = (sel & 1) ? 8 : 0;
+
+		/* set other clock source to the new configuration */
+		val = readl(SPSS_CLK_CNTL_ADDR);
+		val = (val & (~(0x7F << shift))) | (config << shift);
+		writel(val, SPSS_CLK_CNTL_ADDR);
+
+		/* switch to other clock source */
+		writel(sel ^ 1, SPSS_CLK_SEL_ADDR);
+
+		dmb(); /* necessary? */
+	}
+
+	/* switch to new source */
+	val = readl(SPSS_CLK_SEL_ADDR) & (~6);
+	writel(val | ((src & 3) << 1), SPSS_CLK_SEL_ADDR);
+}
+
+static int acpuclk_set_vdd_level(int vdd)
+{
+	if (!drv_state.regulator || IS_ERR(drv_state.regulator)) {
+		drv_state.regulator = regulator_get(NULL, "acpu_vcore");
+		if (IS_ERR(drv_state.regulator)) {
+			pr_info("acpuclk_set_vdd_level %d no regulator\n", vdd);
+			/* Assume that the PMIC supports scaling the processor
+			 * to its maximum frequency at its default voltage.
+			 */
+			return 0;
+		}
+		pr_info("acpuclk_set_vdd_level got regulator\n");
+	}
+	vdd *= 1000; /* mV -> uV */
+	return regulator_set_voltage(drv_state.regulator, vdd, vdd);
+}
+
+int acpuclk_set_rate(unsigned long rate, int for_power_collapse)
+{
+	struct clkctl_acpu_speed *cur, *next;
+	unsigned long flags;
+
+	cur = drv_state.current_speed;
+
+	/* convert to KHz */
+	rate /= 1000;
+
+	DEBUG("acpuclk_set_rate(%d,%d)\n", (int) rate, for_power_collapse);
+
+	if (rate == 0 || rate == cur->acpu_khz)
+		return 0;
+
+	next = acpu_freq_tbl;
+	for (;;) {
+		if (next->acpu_khz == rate)
+			break;
+		if (next->acpu_khz == 0)
+			return -EINVAL;
+		next++;
+	}
+
+	if (!for_power_collapse) {
+		mutex_lock(&drv_state.lock);
+		/* Increase VDD if needed. */
+		if (next->vdd > cur->vdd) {
+			if (acpuclk_set_vdd_level(next->vdd)) {
+				pr_err("acpuclock: Unable to increase ACPU VDD.\n");
+				mutex_unlock(&drv_state.lock);
+				return -EINVAL;
+			}
+		}
+	}
+
+	spin_lock_irqsave(&acpu_lock, flags);
+
+	DEBUG("sel=%d cfg=%02x lv=%02x -> sel=%d, cfg=%02x lv=%02x\n",
+	      cur->clk_sel, cur->clk_cfg, cur->sc_l_value,
+	      next->clk_sel, next->clk_cfg, next->sc_l_value);
+
+	if (next->clk_sel == SRC_SCPLL) {
+		if (!IS_ACPU_STANDBY(cur))
+			select_clock(acpu_stby->clk_sel, acpu_stby->clk_cfg);
+		loops_per_jiffy = next->lpj;
+		scpll_set_freq(next->sc_l_value);
+		select_clock(SRC_SCPLL, 0);
+	} else {
+		loops_per_jiffy = next->lpj;
+		if (cur->clk_sel == SRC_SCPLL) {
+			select_clock(acpu_stby->clk_sel, acpu_stby->clk_cfg);
+			select_clock(next->clk_sel, next->clk_cfg);
+			scpll_power_down();
+		} else {
+			select_clock(next->clk_sel, next->clk_cfg);
+		}
+	}
+
+	drv_state.current_speed = next;
+
+	spin_unlock_irqrestore(&acpu_lock, flags);
+	if (!for_power_collapse) {
+		/* Drop VDD level if we can. */
+		if (next->vdd < cur->vdd) {
+			if (acpuclk_set_vdd_level(next->vdd))
+				pr_err("acpuclock: Unable to drop ACPU VDD.\n");
+		}
+		mutex_unlock(&drv_state.lock);
+	}
+
+	return 0;
+}
+
+static unsigned __init acpuclk_find_speed(void)
+{
+	uint32_t sel, val;
+
+	sel = readl(SPSS_CLK_SEL_ADDR);
+	switch ((sel & 6) >> 1) {
+	case 1:
+		val = readl(SCPLL_FSM_CTL_EXT_ADDR);
+		val = (val >> 3) & 0x3f;
+		return val * 38400;
+	case 2:
+		return 128000;
+	default:
+		pr_err("acpu_find_speed: failed\n");
+		BUG();
+		return 0;
+	}
+}
+
+#define PCOM_MODEM_PLL	0
+static int pll_request(unsigned id, unsigned on)
+{
+	on = !!on;
+	return msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on);
+}
+
+static void __init acpuclk_init(void)
+{
+	struct clkctl_acpu_speed *speed;
+	unsigned init_khz;
+
+	init_khz = acpuclk_find_speed();
+
+	/* request the modem pll, and then drop it. We don't want to keep a
+	 * ref to it, but we do want to make sure that it is initialized at
+	 * this point. The ARM9 will ensure that the MPLL is always on
+	 * once it is fully booted, but it may not be up by the time we get
+	 * to here. So, our pll_request for it will block until the mpll is
+	 * actually up. We want it up because we will want to use it as a
+	 * temporary step during frequency scaling. */
+	pll_request(PCOM_MODEM_PLL, 1);
+	pll_request(PCOM_MODEM_PLL, 0);
+
+	if (!(readl(MSM_CLK_CTL_BASE + 0x300) & 1)) {
+		pr_err("%s: MPLL IS NOT ON!!! RUN AWAY!!\n", __func__);
+		BUG();
+	}
+
+	/* Move to 768MHz for boot, which is a safe frequency
+	 * for all versions of Scorpion at the moment.
+	 */
+	speed = acpu_freq_tbl;
+	for (;;) {
+		if (speed->acpu_khz == 768000)
+			break;
+		if (speed->acpu_khz == 0) {
+			pr_err("acpuclk_init: cannot find 768MHz\n");
+			BUG();
+		}
+		speed++;
+	}
+
+	if (init_khz != speed->acpu_khz) {
+		/* Bootloader needs to have SCPLL operating, but we're
+		 * going to step over to the standby clock and make sure
+		 * we select the right frequency on SCPLL and then
+		 * step back to it, to make sure we're sane here.
+		 */
+		select_clock(acpu_stby->clk_sel, acpu_stby->clk_cfg);
+		scpll_power_down();
+		scpll_set_freq(speed->sc_l_value);
+		select_clock(SRC_SCPLL, 0);
+	}
+	drv_state.current_speed = speed;
+
+	for (speed = acpu_freq_tbl; speed->acpu_khz; speed++)
+		speed->lpj = cpufreq_scale(loops_per_jiffy,
+					   init_khz, speed->acpu_khz);
+
+	loops_per_jiffy = drv_state.current_speed->lpj;
+}
+
+unsigned long acpuclk_get_rate(void)
+{
+	return drv_state.current_speed->acpu_khz;
+}
+
+uint32_t acpuclk_get_switch_time(void)
+{
+	return drv_state.acpu_switch_time_us;
+}
+
+unsigned long acpuclk_power_collapse(void)
+{
+	int ret = acpuclk_get_rate();
+	if (ret > drv_state.power_collapse_khz)
+		acpuclk_set_rate(drv_state.power_collapse_khz * 1000, 1);
+	return ret * 1000;
+}
+
+unsigned long acpuclk_get_wfi_rate(void)
+{
+	return drv_state.wait_for_irq_khz * 1000;
+}
+
+unsigned long acpuclk_wait_for_irq(void)
+{
+	int ret = acpuclk_get_rate();
+	if (ret > drv_state.wait_for_irq_khz)
+		acpuclk_set_rate(drv_state.wait_for_irq_khz * 1000, 1);
+	return ret * 1000;
+}
+
+void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+{
+	spin_lock_init(&acpu_lock);
+	mutex_init(&drv_state.lock);
+
+	drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
+	drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz;
+	drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
+	drv_state.power_collapse_khz = clkdata->power_collapse_khz;
+	drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz;
+
+	if (clkdata->mpll_khz)
+		acpu_mpll->acpu_khz = clkdata->mpll_khz;
+
+	acpuclk_init();
+	acpuclk_init_cpufreq_table();
+}
diff --git a/arch/arm/mach-msm/arch-init-scorpion.S b/arch/arm/mach-msm/arch-init-scorpion.S
new file mode 100644
index 0000000..2eaf4ea
--- /dev/null
+++ b/arch/arm/mach-msm/arch-init-scorpion.S
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2008, QUALCOMM Incorporated.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+/* TODO:
+ * - style cleanup
+ * - do we need to do *all* of this at boot?
+ */
+
+.text		
+.code 32
+
+#define DSB .byte 0x4f, 0xf0, 0x7f, 0xf5
+#define ISB .byte 0x6f, 0xf0, 0x7f, 0xf5
+
+.equ TCSR_SPARE2,      0xA8700060
+
+SET_SA:
+	ldr r0, =TCSR_SPARE2
+	ldr r12, [r0]
+
+	/* pack bits 8,2,0 into 2,1,0 */
+	and r0, r12, #0x001
+	and r1, r12, #0x004
+	and r2, r12, #0x100
+	orr r0, r1, lsr #1
+	orr r0, r2, lsr #6
+
+	adr r1, table_l1_acc
+	mov r0, r0, lsl #2
+	ldr r3, [r1, r0]
+
+	/* write 3800XXXX to PVR0F0 */
+	orr r0, r3, #0x38000000
+	mcr p15, 0, r0, c15, c15, 0
+
+	/* write XXXX0000 to PVR2F0 */
+	mov r1, r3, lsl #16
+	mcr p15, 2, r1, c15, c15, 0
+
+	adr r1, table_l2_acc
+	and r0, r12, #0x008
+	and r2, r12, #0x002
+	orr r0, r0, r2, lsl #1
+	ldr r2, [r1, r0]
+
+	/* write to L2VR3F1 */
+	mcr p15, 3, r2, c15, c15, 1
+
+	bx lr
+
+table_l1_acc:
+	.word 0xFC00
+	.word 0xFC00
+	.word 0x7C00
+	.word 0xFC00
+	.word 0x3C00
+	.word 0x0400
+	.word 0x0C00
+	.word 0x1C00
+
+table_l2_acc:
+	.word 0x010102
+	.word 0x010102
+	.word 0x010101
+	.word 0x212102
+
+.globl __cpu_early_init
+__cpu_early_init:
+        //; Zero out r0 for use throughout this code. All other GPRs
+        //; (r1-r3) are set throughout this code to help establish
+        //; a consistent startup state for any code that follows.
+        //; Users should add code at the end of this routine to establish
+        //; their own stack address (r13), add translation page tables, enable
+        //; the caches, etc.
+        MOV    r0,  #0x0
+
+
+        //; Remove hardcoded cache settings. appsbl_handler.s calls Set_SA
+        //;   API to dynamically configure cache for slow/nominal/fast parts
+
+        //; DCIALL to invalidate L2 cache bank (needs to be run 4 times, once per bank)
+        //; This must be done early in code (prior to enabling the caches)
+        MOV    r1, #0x2
+        MCR    p15, 0, r1, c9, c0, 6   //; DCIALL bank D ([15:14] == 2'b00)
+        ORR    r1, r1, #0x00004000
+        MCR    p15, 0, r1, c9, c0, 6   //; DCIALL bank C ([15:14] == 2'b01)
+        ADD    r1, r1, #0x00004000
+        MCR    p15, 0, r1, c9, c0, 6   //; DCIALL bank B ([15:14] == 2'b10)
+        ADD    r1, r1, #0x00004000
+        MCR    p15, 0, r1, c9, c0, 6   //; DCIALL bank A ([15:14] == 2'b11)
+
+        //; Initialize the BPCR - setup Global History Mask (GHRM) to all 1's
+        //; and have all address bits (AM) participate.
+        //; Different settings can be used to improve performance
+        // MOVW   r1, #0x01FF
+.word 0xe30011ff  // hardcoded MOVW instruction due to lack of compiler support
+        // MOVT   r1, #0x01FF
+.word 0xe34011ff  // hardcoded MOVT instruction due to lack of compiler support
+        MCR    p15, 7, r1, c15, c0, 2   //; WCP15_BPCR
+
+
+        //; Initialize all I$ Victim Registers to 0 for startup
+        MCR    p15, 0, r0, c9, c1, 0    //; WCP15_ICVIC0    r0
+        MCR    p15, 0, r0, c9, c1, 1    //; WCP15_ICVIC1    r0
+        MCR    p15, 0, r0, c9, c1, 2    //; WCP15_ICVIC2    r0
+        MCR    p15, 0, r0, c9, c1, 3    //; WCP15_ICVIC3    r0
+        MCR    p15, 0, r0, c9, c1, 4    //; WCP15_ICVIC4    r0
+        MCR    p15, 0, r0, c9, c1, 5    //; WCP15_ICVIC5    r0
+        MCR    p15, 0, r0, c9, c1, 6    //; WCP15_ICVIC5    r0
+        MCR    p15, 0, r0, c9, c1, 7    //; WCP15_ICVIC7    r0
+
+        //; Initialize all I$ Locked Victim Registers (Unlocked Floors) to 0
+        MCR    p15, 1, r0, c9, c1, 0    //; WCP15_ICFLOOR0  r0
+        MCR    p15, 1, r0, c9, c1, 1    //; WCP15_ICFLOOR1  r0
+        MCR    p15, 1, r0, c9, c1, 2    //; WCP15_ICFLOOR2  r0
+        MCR    p15, 1, r0, c9, c1, 3    //; WCP15_ICFLOOR3  r0
+        MCR    p15, 1, r0, c9, c1, 4    //; WCP15_ICFLOOR4  r0
+        MCR    p15, 1, r0, c9, c1, 5    //; WCP15_ICFLOOR5  r0
+        MCR    p15, 1, r0, c9, c1, 6    //; WCP15_ICFLOOR6  r0
+        MCR    p15, 1, r0, c9, c1, 7    //; WCP15_ICFLOOR7  r0
+
+        //; Initialize all D$ Victim Registers to 0
+        MCR    p15, 2, r0, c9, c1, 0    //; WP15_DCVIC0    r0
+        MCR    p15, 2, r0, c9, c1, 1    //; WP15_DCVIC1    r0
+        MCR    p15, 2, r0, c9, c1, 2    //; WP15_DCVIC2    r0
+        MCR    p15, 2, r0, c9, c1, 3    //; WP15_DCVIC3    r0
+        MCR    p15, 2, r0, c9, c1, 4    //; WP15_DCVIC4    r0
+        MCR    p15, 2, r0, c9, c1, 5    //; WP15_DCVIC5    r0
+        MCR    p15, 2, r0, c9, c1, 6    //; WP15_DCVIC6    r0
+        MCR    p15, 2, r0, c9, c1, 7    //; WP15_DCVIC7    r0
+
+        //; Initialize all D$ Locked VDCtim Registers (Unlocked Floors) to 0
+        MCR    p15, 3, r0, c9, c1, 0    //; WCP15_DCFLOOR0  r0
+        MCR    p15, 3, r0, c9, c1, 1    //; WCP15_DCFLOOR1  r0
+        MCR    p15, 3, r0, c9, c1, 2    //; WCP15_DCFLOOR2  r0
+        MCR    p15, 3, r0, c9, c1, 3    //; WCP15_DCFLOOR3  r0
+        MCR    p15, 3, r0, c9, c1, 4    //; WCP15_DCFLOOR4  r0
+        MCR    p15, 3, r0, c9, c1, 5    //; WCP15_DCFLOOR5  r0
+        MCR    p15, 3, r0, c9, c1, 6    //; WCP15_DCFLOOR6  r0
+        MCR    p15, 3, r0, c9, c1, 7    //; WCP15_DCFLOOR7  r0
+
+        //; Initialize ASID to zero
+        MCR    p15, 0, r0, c13, c0, 1   //; WCP15_CONTEXTIDR r0
+
+        //; ICIALL to invalidate entire I-Cache
+        MCR    p15, 0, r0, c7, c5, 0    //; ICIALLU
+
+        //; DCIALL to invalidate entire D-Cache
+        MCR    p15, 0, r0, c9, c0, 6    //; DCIALL  r0
+
+
+        //; The VBAR (Vector Base Address Register) should be initialized
+        //; early in your code. We are setting it to zero
+        MCR    p15, 0, r0, c12, c0, 0   //; WCP15_VBAR  r0
+
+        //; Ensure the MCR's above have completed their operation before continuing
+        DSB
+        ISB
+
+        //;-------------------------------------------------------------------
+        //; There are a number of registers that must be set prior to enabling
+        //; the MMU. The DCAR is one of these registers. We are setting
+        //; it to zero (no access) to easily detect improper setup in subsequent
+        //; code sequences
+        //;-------------------------------------------------------------------
+        //; Setup DACR (Domain Access Control Register) to zero
+        MCR    p15, 0, r0, c3, c0, 0    //; WCP15_DACR  r0
+
+        //; Setup DCLKCR to allow normal D-Cache line fills
+        MCR    p15, 1, r0, c9, c0, 7    //; WCP15_DCLKCR r0
+
+        //; Initialize the ADFSR and EFSR registers.
+        MCR    p15, 0, r0,  c5, c1, 0   //; ADFSR
+        MCR    p15, 7, r0, c15, c0, 1   //; EFSR
+
+        //; Setup the TLBLKCR
+        //; Victim = 6'b000000; Floor = 6'b000000;
+        //; IASIDCFG = 2'b00 (State-Machine); IALLCFG = 2'b01 (Flash); BNA = 1'b0;
+        MOV    r1, #0x02
+        MCR    p15, 0, r1, c10, c1, 3     //; WCP15_TLBLKCR  r1
+
+        //;Make sure TLBLKCR is complete before continuing
+        ISB
+
+        //; Invalidate the UTLB
+        MCR    p15, 0, r0, c8, c7, 0      //; UTLBIALL
+
+        //; Make sure UTLB request has been presented to macro before continuing
+        ISB
+
+        //; setup L2CR1 to some default Instruction and data prefetching values
+        //; Users may want specific settings for various performance enhancements
+        //; In Halcyon we do not have broadcasting barriers. So we need to turn
+        //  ; on bit 8 of L2CR1; which DBB:( Disable barrier broadcast )
+        MOV r2, #0x100
+        MCR    p15, 3, r2, c15, c0, 3     //; WCP15_L2CR1  r0
+
+
+        //; Enable Z bit to enable branch prediction (default is off)
+        MRC    p15, 0, r2, c1, c0, 0      //; RCP15_SCTLR  r2
+        ORR    r2, r2, #0x00000800
+        MCR    p15, 0, r2, c1, c0, 0      //; WCP15_SCTLR  r2
+
+#ifdef CONFIG_ARCH_QSD8X50
+        /* disable predecode repair cache for thumb2 (DPRC, set bit 4 in PVR0F2) */
+        mrc p15, 0, r2, c15, c15, 2
+        orr r2, r2, #0x10
+        mcr p15, 0, r2, c15, c15, 2
+#endif
+
+        mov r1, lr
+        //; Make sure Link stack is initialized with branch and links to sequential addresses
+        //; This aids in creating a predictable startup environment
+       BL      SEQ1
+SEQ1:  BL      SEQ2
+SEQ2:  BL      SEQ3
+SEQ3:  BL      SEQ4
+SEQ4:  BL      SEQ5
+SEQ5:  BL      SEQ6
+SEQ6:  BL      SEQ7
+SEQ7:  BL      SEQ8
+SEQ8:
+        mov lr, r1
+
+        //; REMOVE FOLLOWING THREE INSTRUCTIONS WHEN POWER COLLAPSE IS ENA
+        //;Make sure the DBGOSLSR[LOCK] bit is cleared to allow access to the debug registers
+        //; Writing anything but the "secret code" to the DBGOSLAR clears the DBGOSLSR[LOCK] bit
+        MCR    p14, 0, r0, c1, c0, 4       //; WCP14_DBGOSLAR r0
+
+
+        //; Read the DBGPRSR to clear the DBGPRSR[STICKYPD]
+        //; Any read to DBGPRSR clear the STICKYPD bit
+        //; ISB guarantees the read completes before attempting to
+        //; execute a CP14 instruction.
+        MRC    p14, 0, r3, c1, c5, 4       //; RCP14_DBGPRSR r3
+        ISB
+
+        //; Initialize the Watchpoint Control Registers to zero (optional)
+        //;;; MCR    p14, 0, r0, c0, c0, 7       ; WCP14_DBGWCR0  r0
+        //;;; MCR    p14, 0, r0, c0, c1, 7       ; WCP14_DBGWCR1  r0
+
+
+        //;----------------------------------------------------------------------
+        //; The saved Program Status Registers (SPSRs) should be setup
+        //; prior to any automatic mode switches. The following
+        //; code sets these registers up to a known state. Users will need to
+        //; customize these settings to meet their needs.
+        //;----------------------------------------------------------------------
+        MOV    r2,  #0x1f
+        MOV    r1,  #0x17                 //;ABT mode
+        msr    cpsr_c, r1                 //;ABT mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+        MOV    r1,  #0x1b                 //;UND mode
+        msr    cpsr_c, r1                 //;UND mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+        MOV    r1,  #0x11                 //;FIQ mode
+        msr    cpsr_c, r1                 //;FIQ mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+        MOV    r1,  #0x12                 //;IRQ mode
+        msr    cpsr_c, r1                 //;IRQ mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+        MOV    r1,  #0x16                 //;Monitor mode
+        msr    cpsr_c, r1                 //;Monitor mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+        MOV    r1,  #0x13                 //;SVC mode
+        msr    cpsr_c, r1                 //;SVC mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+
+
+        //;----------------------------------------------------------------------
+        //; Enabling Error reporting is something users may want to do at
+        //; some other point in time. We have chosen some default settings
+        //; that should be reviewed. Most of these registers come up in an
+        //; unpredictable state after reset.
+        //;----------------------------------------------------------------------
+//;Start of error and control setting
+
+        //; setup L2CR0 with various L2/TCM control settings
+        //; enable out of order bus attributes and error reporting
+        //; this register comes up unpredictable after reset
+        // MOVW   r1, #0x0F0F
+.word 0xe3001f0f  // hardcoded MOVW instruction due to lack of compiler support
+        // MOVT   r1, #0xC005
+.word 0xe34c1005  // hardcoded MOVW instruction due to lack of compiler support
+        MCR    p15, 3, r1, c15, c0, 1    //; WCP15_L2CR0  r1
+
+        //; setup L2CPUCR
+        //; MOV    r2, #0xFF
+        //; Enable I and D cache parity
+        //;L2CPUCR[7:5] = 3~Rh7 ~V enable parity error reporting for modified,
+        //;tag, and data parity errors
+        MOV    r2, #0xe0
+        MCR    p15, 3, r2, c15, c0, 2    //; WCP15_L2CPUCR  r2
+
+        //; setup SPCR
+        //; enable all error reporting (reset value is unpredicatble for most bits)
+        MOV    r3, #0x0F
+        MCR    p15, 0, r3, c9, c7, 0     //; WCP15_SPCR  r3
+
+        //; setup DMACHCRs (reset value unpredictable)
+        //; control setting and enable all error reporting
+        MOV   r1, #0x0F
+
+        //; DMACHCR0 = 0000000F
+        MOV   r2, #0x00                  //; channel 0
+        MCR   p15, 0, r2, c11, c0, 0     //; WCP15_DMASELR  r2
+        MCR   p15, 0, r1, c11, c0, 2     //; WCP15_DMACHCR  r1
+
+        //; DMACHCR1 = 0000000F
+        MOV   r2, #0x01                  //; channel 1
+        MCR   p15, 0, r2, c11, c0, 0     //; WCP15_DMASELR  r2
+        MCR   p15, 0, r1, c11, c0, 2     //; WCP15_DMACHCR  r1
+
+        //; DMACHCR2 = 0000000F
+        MOV   r2, #0x02                  //; channel 2
+        MCR   p15, 0, r2, c11, c0, 0     //; WCP15_DMASELR  r2
+        MCR   p15, 0, r1, c11, c0, 2     //; WCP15_DMACHCR  r1
+
+        //; DMACHCR3 = 0000000F
+        MOV   r2, #0x03                  //; channel 3
+        MCR   p15, 0, r2, c11, c0, 0     //; WCP15_DMASELR  r2
+        MCR   p15, 0, r1, c11, c0, 2     //; WCP15_DMACHCR  r1
+
+        //; Set ACTLR (reset unpredictable)
+        //; Set AVIVT control, error reporting, etc.
+        //; MOV   r3, #0x07
+        //; Enable I and D cache parity
+        //;ACTLR[2:0] = 3'h7 - enable parity error reporting from L2/I$/D$)
+        //;ACTLR[5:4] = 2'h3 - enable parity
+        //;ACTLR[19:18] =2'h3 - always generate and check parity(when MMU disabled).
+        //;Value to be written #0xC0037
+        // MOVW   r3, #0x0037
+.word 0xe3003037  // hardcoded MOVW instruction due to lack of compiler support
+        // MOVT   r3, #0x000C
+.word 0xe340300c  // hardcoded MOVW instruction due to lack of compiler support
+            //; read the version_id to determine if d-cache should be disabled
+            LDR r2, = 0xa8e00270  //;Read HW_REVISION_NUMBER, HWIO_HW_REVISION_NUMBER_ADDR
+            LDR r2,[r2]
+            AND r2,r2,#0xf0000000 //;hw_revision mask off bits 28-31
+                //;if HW_revision is 1.0 or older, (revision==0)
+                CMP r2,#0
+        //; Disable d-cache on older QSD8650 (Rev 1.0) silicon
+        orreq   r3, r3, #0x4000          //;disable dcache
+        MCR   p15, 0, r3, c1, c0, 1      //; WCP15_ACTLR  r3
+
+//;End of error and control setting
+
+        //;----------------------------------------------------------------------
+        //; Unlock ETM and read StickyPD to halt the ETM clocks from running.
+        //; This is required for power saving whether the ETM is used or not.
+        //;----------------------------------------------------------------------
+
+        //;Clear ETMOSLSR[LOCK] bit
+        MOV   r1, #0x00000000
+        MCR   p14, 1, r1, c1, c0, 4        //; WCP14_ETMOSLAR      r1
+
+        //;Clear ETMPDSR[STICKYPD] bit
+        MRC   p14, 1, r2, c1, c5, 4        //; RCP14_ETMPDSR       r2
+
+/*
+#ifdef APPSBL_ETM_ENABLE
+        ;----------------------------------------------------------------------
+        ; Optionally Enable the ETM (Embedded Trace Macro) which is used for debug
+        ;----------------------------------------------------------------------
+
+        ; enable ETM clock if disabled
+        MRC   p15, 7, r1, c15, c0, 5       ; RCP15_CPMR           r1
+        ORR   r1, r1, #0x00000008
+        MCR   p15, 7, r1, c15, c0, 5       ; WCP15_CPMR           r1
+        ISB
+
+        ; set trigger event to counter1 being zero
+        MOV   r3, #0x00000040
+        MCR   p14, 1, r3, c0, c2, 0        ; WCP14_ETMTRIGGER     r3
+
+        ; clear ETMSR
+        MOV   r2, #0x00000000
+        MCR   p14, 1, r2, c0, c4, 0        ; WCP14_ETMSR          r2
+
+        ; clear trace enable single address comparator usage
+        MCR   p14, 1, r2, c0, c7, 0        ; WCP14_ETMTECR2       r2
+
+        ; set trace enable to always
+        MOV   r2, #0x0000006F
+        MCR   p14, 1, r2, c0, c8, 0        ; WCP14_ETMTEEVR       r2
+
+        ; clear trace enable address range comparator usage and exclude nothing
+        MOV   r2, #0x01000000
+        MCR   p14, 1, r2, c0, c9, 0        ; WCP14_ETMTECR1       r2
+
+        ; set view data to always
+        MOV   r2, #0x0000006F
+        MCR   p14, 1, r2, c0, c12, 0       ; WCP14_ETMVDEVR       r2
+
+        ; clear view data single address comparator usage
+        MOV   r2, #0x00000000
+        MCR   p14, 1, r2, c0, c13, 0       ;  WCP14_ETMVDCR1       r2
+
+        ; clear view data address range comparator usage and exclude nothing
+        MOV   r2, #0x00010000
+        MCR   p14, 1, r2, c0, c15, 0       ;  WCP14_ETMVDCR3       r2
+
+        ; set counter1 to 194
+        MOV   r2, #0x000000C2
+        MCR   p14, 1, r2, c0, c0, 5        ;  WCP14_ETMCNTRLDVR1   r2
+
+        ; set counter1 to never reload
+        MOV   r2, #0x0000406F
+        MCR   p14, 1, r2, c0, c8, 5        ;  WCP14_ETMCNTRLDEVR1  r2
+
+        ; set counter1 to decrement every cycle
+        MOV   r2, #0x0000006F
+        MCR   p14, 1, r2, c0, c4, 5        ; WCP14_ETMCNTENR1     r2
+
+        ; Set trace synchronization frequency 1024 bytes
+        MOV   r2, #0x00000400
+        MCR   p14, 1, r2, c0, c8, 7        ; WCP14_ETMSYNCFR      r2
+
+        ; Program etm control register
+        ;  - Set the CPU to ETM clock ratio to 1:1
+        ;  - Set the ETM to perform data address tracing
+        MOV   r2, #0x00002008
+        MCR   p14, 1, r2, c0, c0, 0        ; WCP14_ETMCR          r2
+        ISB
+#endif *//* APPSBL_ETM_ENABLE */
+
+/*
+#ifdef APPSBL_VFP_ENABLE
+       ;----------------------------------------------------------------------
+       ; Perform the following operations if you intend to make use of
+       ; the VFP/Neon unit. Note that the FMXR instruction requires a CPU ID
+       ; indicating the VFP unit is present (i.e.Cortex-A8). .
+       ; Some tools will require full double precision floating point support
+       ; which will become available in Scorpion pass 2
+       ;----------------------------------------------------------------------
+       ; allow full access to CP 10 and 11 space for VFP/NEON use
+        MRC   p15, 0, r1, c1, c0, 2        ; Read CP Access Control Register
+        ORR   r1, r1, #0x00F00000          ; enable full access for p10,11
+        MCR   p15, 0, r1, c1, c0, 2        ; Write CPACR
+
+        ;make sure the CPACR is complete before continuing
+        ISB
+
+       ; Enable VFP itself (certain OSes may want to dynamically set/clear
+       ; the enable bit based on the application being executed
+        MOV   r1, #0x40000000
+        FMXR  FPEXC, r1
+#endif *//* APPSBL_VFP_ENABLE */
+
+	/* we have no stack, so just tail-call into the SET_SA routine... */
+	b SET_SA
+
+.ltorg
diff --git a/arch/arm/mach-msm/board-halibut-keypad.c b/arch/arm/mach-msm/board-halibut-keypad.c
new file mode 100644
index 0000000..49c1075
--- /dev/null
+++ b/arch/arm/mach-msm/board-halibut-keypad.c
@@ -0,0 +1,177 @@
+/* linux/arch/arm/mach-msm/board-halibut-keypad.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <asm/mach-types.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_event.h>
+
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_halibut."
+static int halibut_ffa;
+module_param_named(ffa, halibut_ffa, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SCAN_FUNCTION_KEYS 0 /* don't turn this on without updating the ffa support */
+
+static unsigned int halibut_row_gpios[] = {
+	31, 32, 33, 34, 35, 41
+#if SCAN_FUNCTION_KEYS
+	, 42
+#endif
+};
+
+static unsigned int halibut_col_gpios[] = { 36, 37, 38, 39, 40 };
+
+/* FFA:
+ 36: KEYSENSE_N(0)
+ 37: KEYSENSE_N(1)
+ 38: KEYSENSE_N(2)
+ 39: KEYSENSE_N(3)
+ 40: KEYSENSE_N(4)
+
+ 31: KYPD_17
+ 32: KYPD_15
+ 33: KYPD_13
+ 34: KYPD_11
+ 35: KYPD_9
+ 41: KYPD_MEMO
+*/
+
+#define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(halibut_col_gpios) + (col))
+
+static const unsigned short halibut_keymap[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_5,
+	[KEYMAP_INDEX(0, 1)] = KEY_9,
+	[KEYMAP_INDEX(0, 2)] = 229,            /* SOFT1 */
+	[KEYMAP_INDEX(0, 3)] = KEY_6,
+	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_0,
+	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 2)] = KEY_1,
+	[KEYMAP_INDEX(1, 3)] = 228,           /* KEY_SHARP */
+	[KEYMAP_INDEX(1, 4)] = KEY_SEND,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(2, 1)] = KEY_HOME,      /* FA   */
+	[KEYMAP_INDEX(2, 2)] = KEY_F8,        /* QCHT */
+	[KEYMAP_INDEX(2, 3)] = KEY_F6,        /* R+   */
+	[KEYMAP_INDEX(2, 4)] = KEY_F7,        /* R-   */
+
+	[KEYMAP_INDEX(3, 0)] = KEY_UP,
+	[KEYMAP_INDEX(3, 1)] = KEY_CLEAR,
+	[KEYMAP_INDEX(3, 2)] = KEY_4,
+	[KEYMAP_INDEX(3, 3)] = KEY_MUTE,      /* SPKR */
+	[KEYMAP_INDEX(3, 4)] = KEY_2,
+
+	[KEYMAP_INDEX(4, 0)] = 230,           /* SOFT2 */
+	[KEYMAP_INDEX(4, 1)] = 232,           /* KEY_CENTER */
+	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+	[KEYMAP_INDEX(4, 3)] = KEY_BACK,      /* FB */
+	[KEYMAP_INDEX(4, 4)] = KEY_8,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[KEYMAP_INDEX(5, 2)] = KEY_MAIL,      /* MESG */
+	[KEYMAP_INDEX(5, 3)] = KEY_3,
+	[KEYMAP_INDEX(5, 4)] = KEY_7,
+
+#if SCAN_FUNCTION_KEYS
+	[KEYMAP_INDEX(6, 0)] = KEY_F5,
+	[KEYMAP_INDEX(6, 1)] = KEY_F4,
+	[KEYMAP_INDEX(6, 2)] = KEY_F3,
+	[KEYMAP_INDEX(6, 3)] = KEY_F2,
+	[KEYMAP_INDEX(6, 4)] = KEY_F1
+#endif
+};
+
+static const unsigned short halibut_keymap_ffa[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = {
+	/*[KEYMAP_INDEX(0, 0)] = ,*/
+	/*[KEYMAP_INDEX(0, 1)] = ,*/
+	[KEYMAP_INDEX(0, 2)] = KEY_1,
+	[KEYMAP_INDEX(0, 3)] = KEY_SEND,
+	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_3,
+	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 2)] = KEY_VOLUMEUP,
+	/*[KEYMAP_INDEX(1, 3)] = ,*/
+	[KEYMAP_INDEX(1, 4)] = KEY_6,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_HOME,      /* A */
+	[KEYMAP_INDEX(2, 1)] = KEY_BACK,      /* B */
+	[KEYMAP_INDEX(2, 2)] = KEY_0,
+	[KEYMAP_INDEX(2, 3)] = 228,           /* KEY_SHARP */
+	[KEYMAP_INDEX(2, 4)] = KEY_9,
+
+	[KEYMAP_INDEX(3, 0)] = KEY_UP,
+	[KEYMAP_INDEX(3, 1)] = 232, /* KEY_CENTER */ /* i */
+	[KEYMAP_INDEX(3, 2)] = KEY_4,
+	/*[KEYMAP_INDEX(3, 3)] = ,*/
+	[KEYMAP_INDEX(3, 4)] = KEY_2,
+
+	[KEYMAP_INDEX(4, 0)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(4, 1)] = KEY_SOUND,
+	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+	[KEYMAP_INDEX(4, 3)] = KEY_8,
+	[KEYMAP_INDEX(4, 4)] = KEY_5,
+
+	/*[KEYMAP_INDEX(5, 0)] = ,*/
+	[KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */
+	[KEYMAP_INDEX(5, 3)] = KEY_MENU,      /* 1 */
+	[KEYMAP_INDEX(5, 4)] = KEY_7,
+};
+
+static struct gpio_event_matrix_info halibut_matrix_info = {
+	.info.func	= gpio_event_matrix_func,
+	.keymap		= halibut_keymap,
+	.output_gpios	= halibut_row_gpios,
+	.input_gpios	= halibut_col_gpios,
+	.noutputs	= ARRAY_SIZE(halibut_row_gpios),
+	.ninputs	= ARRAY_SIZE(halibut_col_gpios),
+	.settle_time.tv.nsec = 0,
+	.poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.flags		= GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE | GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+struct gpio_event_info *halibut_keypad_info[] = {
+	&halibut_matrix_info.info
+};
+
+static struct gpio_event_platform_data halibut_keypad_data = {
+	.name		= "halibut_keypad",
+	.info		= halibut_keypad_info,
+	.info_count	= ARRAY_SIZE(halibut_keypad_info)
+};
+
+static struct platform_device halibut_keypad_device = {
+	.name	= GPIO_EVENT_DEV_NAME,
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &halibut_keypad_data,
+	},
+};
+
+static int __init halibut_init_keypad(void)
+{
+	if (!machine_is_halibut())
+		return 0;
+	if (halibut_ffa)
+		halibut_matrix_info.keymap = halibut_keymap_ffa;
+	return platform_device_register(&halibut_keypad_device);
+}
+
+device_initcall(halibut_init_keypad);
diff --git a/arch/arm/mach-msm/board-halibut-panel.c b/arch/arm/mach-msm/board-halibut-panel.c
new file mode 100644
index 0000000..a498c65
--- /dev/null
+++ b/arch/arm/mach-msm/board-halibut-panel.c
@@ -0,0 +1,73 @@
+/* linux/arch/arm/mach-msm/board-halibut-mddi.c
+** Author: Brian Swetland <swetland@google.com>
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+#include <mach/vreg.h>
+
+#include "proc_comm.h"
+#include "devices.h"
+#include "board-halibut.h"
+
+static void halibut_mddi_power_client(struct msm_mddi_client_data *mddi,
+	int on)
+{
+}
+
+static struct resource resources_msm_fb = {
+	.start = MSM_FB_BASE,
+	.end = MSM_FB_BASE + MSM_FB_SIZE - 1,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct msm_fb_data fb_data = {
+	.xres = 800,
+	.yres = 480,
+	.output_format = 0,
+};
+
+static struct msm_mddi_platform_data mddi_pdata = {
+	.clk_rate = 122880000,
+	.power_client = halibut_mddi_power_client,
+	.fb_resource = &resources_msm_fb,
+	.num_clients = 1,
+	.client_platform_data = {
+		{
+			.product_id = (0x4474 << 16 | 0xc065),
+			.name = "mddi_c_dummy",
+			.id = 0,
+			.client_data = &fb_data,
+			.clk_rate = 0,
+		},
+	},
+};
+
+int __init halibut_init_panel(void)
+{
+	int rc;
+
+	if (!machine_is_halibut())
+		return 0;
+
+	rc = platform_device_register(&msm_device_mdp);
+	if (rc)
+		return rc;
+
+	msm_device_mddi0.dev.platform_data = &mddi_pdata;
+	return platform_device_register(&msm_device_mddi0);
+}
+
+device_initcall(halibut_init_panel);
diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
index 7bd72e8..1940436 100644
--- a/arch/arm/mach-msm/board-halibut.c
+++ b/arch/arm/mach-msm/board-halibut.c
@@ -20,8 +20,11 @@
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/bootmem.h>
 
 #include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/gpio.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -31,11 +34,18 @@
 #include <mach/irqs.h>
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
+#include <mach/msm_hsusb.h>
+#include <mach/camera.h>
 
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/i2c.h>
+#include <linux/android_pmem.h>
+#include <linux/usb/android_composite.h>
 
 #include "devices.h"
+#include "board-halibut.h"
+#include "proc_comm.h"
 
 static struct resource smc91x_resources[] = {
 	[0] = {
@@ -57,13 +67,355 @@
 	.resource	= smc91x_resources,
 };
 
+static struct i2c_board_info i2c_devices[] = {
+#ifdef CONFIG_MT9D112
+	{
+		I2C_BOARD_INFO("mt9d112", 0x78 >> 1),
+	},
+#endif
+#ifdef CONFIG_S5K3E2FX
+	{
+		I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1),
+	},
+#endif
+#ifdef CONFIG_MT9P012
+	{
+		I2C_BOARD_INFO("mt9p012", 0x6C >> 1),
+	},
+#endif
+#if defined(CONFIG_MT9T013) || defined(CONFIG_SENSORS_MT9T013)
+	{
+		I2C_BOARD_INFO("mt9t013", 0x6C), // 0x78>>1
+	},
+#endif
+};
+
+#ifdef CONFIG_MSM_CAMERA
+static uint32_t camera_off_gpio_table[] = {
+	/* parallel CAMERA interfaces */
+	PCOM_GPIO_CFG(0,  0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */
+	PCOM_GPIO_CFG(1,  0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */
+	PCOM_GPIO_CFG(2,  0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */
+	PCOM_GPIO_CFG(3,  0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */
+	PCOM_GPIO_CFG(4,  0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */
+	PCOM_GPIO_CFG(5,  0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */
+	PCOM_GPIO_CFG(6,  0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */
+	PCOM_GPIO_CFG(7,  0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */
+	PCOM_GPIO_CFG(8,  0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */
+	PCOM_GPIO_CFG(9,  0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */
+	PCOM_GPIO_CFG(10, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */
+	PCOM_GPIO_CFG(11, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */
+	PCOM_GPIO_CFG(12, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCLK */
+	PCOM_GPIO_CFG(13, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */
+	PCOM_GPIO_CFG(14, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */
+	PCOM_GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_table[] = {
+	/* parallel CAMERA interfaces */
+	PCOM_GPIO_CFG(0,  1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */
+	PCOM_GPIO_CFG(1,  1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */
+	PCOM_GPIO_CFG(2,  1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */
+	PCOM_GPIO_CFG(3,  1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */
+	PCOM_GPIO_CFG(4,  1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */
+	PCOM_GPIO_CFG(5,  1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */
+	PCOM_GPIO_CFG(6,  1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */
+	PCOM_GPIO_CFG(7,  1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */
+	PCOM_GPIO_CFG(8,  1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */
+	PCOM_GPIO_CFG(9,  1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */
+	PCOM_GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */
+	PCOM_GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */
+	PCOM_GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */
+	PCOM_GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */
+	PCOM_GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */
+	PCOM_GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */
+};
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for (n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+static void config_camera_on_gpios(void)
+{
+	config_gpio_table(camera_on_gpio_table,
+		ARRAY_SIZE(camera_on_gpio_table));
+}
+
+static void config_camera_off_gpios(void)
+{
+	config_gpio_table(camera_off_gpio_table,
+		ARRAY_SIZE(camera_off_gpio_table));
+}
+
+static struct msm_camera_device_platform_data msm_camera_device_data = {
+	.camera_gpio_on  = config_camera_on_gpios,
+	.camera_gpio_off = config_camera_off_gpios,
+	.ioext.mdcphy = MSM_MDC_PHYS,
+	.ioext.mdcsz  = MSM_MDC_SIZE,
+	.ioext.appphy = MSM_CLK_CTL_PHYS,
+	.ioext.appsz  = MSM_CLK_CTL_SIZE,
+};
+
+#ifdef CONFIG_MT9D112
+static struct msm_camera_sensor_info msm_camera_sensor_mt9d112_data = {
+	.sensor_name	= "mt9d112",
+	.sensor_reset	= 89,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= 0,
+	.pdata		= &msm_camera_device_data,
+};
+
+static struct platform_device msm_camera_sensor_mt9d112 = {
+	.name	   = "msm_camera_mt9d112",
+	.dev	    = {
+		.platform_data = &msm_camera_sensor_mt9d112_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_S5K3E2FX
+static struct msm_camera_sensor_info msm_camera_sensor_s5k3e2fx_data = {
+	.sensor_name	= "s5k3e2fx",
+	.sensor_reset	= 89,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= 0,
+	.pdata		= &msm_camera_device_data,
+};
+
+static struct platform_device msm_camera_sensor_s5k3e2fx = {
+	.name	   = "msm_camera_s5k3e2fx",
+	.dev	    = {
+		.platform_data = &msm_camera_sensor_s5k3e2fx_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9P012
+static struct msm_camera_sensor_info msm_camera_sensor_mt9p012_data = {
+	.sensor_name	= "mt9p012",
+	.sensor_reset	= 89,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= 88,
+	.pdata		= &msm_camera_device_data,
+};
+
+static struct platform_device msm_camera_sensor_mt9p012 = {
+	.name	   = "msm_camera_mt9p012",
+	.dev	    = {
+		.platform_data = &msm_camera_sensor_mt9p012_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9T013
+static struct msm_camera_sensor_info msm_camera_sensor_mt9t013_data = {
+	.sensor_name	= "mt9t013",
+	.sensor_reset	= 89,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= 0,
+	.pdata		= &msm_camera_device_data,
+};
+
+static struct platform_device msm_camera_sensor_mt9t013 = {
+	.name	   = "msm_camera_mt9t013",
+	.dev	    = {
+		.platform_data = &msm_camera_sensor_mt9t013_data,
+	},
+};
+#endif
+#endif /*CONFIG_MSM_CAMERA*/
+
+#define SND(desc, num) { .name = #desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+	SND(HANDSET, 0),
+	SND(HEADSET, 2),
+	SND(SPEAKER, 6),
+	SND(BT, 12),
+	SND(CURRENT, 25),
+};
+#undef SND
+
+static struct msm_snd_endpoints halibut_snd_endpoints = {
+	.endpoints = snd_endpoints_list,
+	.num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint)
+};
+
+static struct platform_device halibut_snd = {
+	.name = "msm_snd",
+	.id = -1,
+	.dev    = {
+		.platform_data = &halibut_snd_endpoints
+	},
+};
+
+static struct android_pmem_platform_data android_pmem_pdata = {
+	.name = "pmem",
+	.start = MSM_PMEM_MDP_BASE,
+	.size = MSM_PMEM_MDP_SIZE,
+	.no_allocator = 0,
+	.cached = 1,
+};
+
+static struct android_pmem_platform_data android_pmem_camera_pdata = {
+	.name = "pmem_camera",
+	.start = MSM_PMEM_CAMERA_BASE,
+	.size = MSM_PMEM_CAMERA_SIZE,
+	.no_allocator = 1,
+	.cached = 1,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.start = MSM_PMEM_ADSP_BASE,
+	.size = MSM_PMEM_ADSP_SIZE,
+	.no_allocator = 0,
+	.cached = 0,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu0_pdata = {
+	.name = "pmem_gpu0",
+	.start = MSM_PMEM_GPU0_BASE,
+	.size = MSM_PMEM_GPU0_SIZE,
+	.no_allocator = 1,
+	.cached = 0,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu1_pdata = {
+	.name = "pmem_gpu1",
+	.start = MSM_PMEM_GPU1_BASE,
+	.size = MSM_PMEM_GPU1_SIZE,
+	.no_allocator = 1,
+	.cached = 0,
+};
+
+static struct platform_device android_pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = { .platform_data = &android_pmem_pdata },
+};
+
+static struct platform_device android_pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 1,
+	.dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static struct platform_device android_pmem_gpu0_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &android_pmem_gpu0_pdata },
+};
+
+static struct platform_device android_pmem_gpu1_device = {
+	.name = "android_pmem",
+	.id = 3,
+	.dev = { .platform_data = &android_pmem_gpu1_pdata },
+};
+
+static struct platform_device android_pmem_camera_device = {
+	.name = "android_pmem",
+	.id = 4,
+	.dev = { .platform_data = &android_pmem_camera_pdata },
+};
+
+static int halibut_phy_init_seq[] = { 0x1D, 0x0D, 0x1D, 0x10, -1 };
+
+static struct msm_hsusb_platform_data msm_hsusb_pdata = {
+	.phy_init_seq = halibut_phy_init_seq,
+};
+
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+	.nluns = 1,
+	.vendor = "Qualcomm",
+	.product = "Halibut",
+	.release = 0x0100,
+};
+
+static struct platform_device usb_mass_storage_device = {
+	.name = "usb_mass_storage",
+	.id = -1,
+	.dev = {
+		.platform_data = &mass_storage_pdata,
+	},
+};
+
+static char *usb_functions[] = { "usb_mass_storage" };
+static char *usb_functions_adb[] = { "usb_mass_storage", "adb" };
+
+static struct android_usb_product usb_products[] = {
+	{
+		.product_id	= 0x0c01,
+		.num_functions	= ARRAY_SIZE(usb_functions),
+		.functions	= usb_functions,
+	},
+	{
+		.product_id	= 0x0c02,
+		.num_functions	= ARRAY_SIZE(usb_functions_adb),
+		.functions	= usb_functions_adb,
+	},
+};
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.vendor_id = 0x18d1,
+	.product_id = 0x0c01,
+	.version = 0x0100,
+	.serial_number = "42",
+	.product_name = "Halibutdroid",
+	.manufacturer_name = "Qualcomm",
+	.num_products = ARRAY_SIZE(usb_products),
+	.products = usb_products,
+	.num_functions = ARRAY_SIZE(usb_functions_adb),
+	.functions = usb_functions_adb,
+};
+
+static struct platform_device android_usb_device = {
+	.name = "android_usb",
+	.id = -1,
+	.dev = {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+static struct platform_device fish_battery_device = {
+	.name = "fish_battery",
+};
+
 static struct platform_device *devices[] __initdata = {
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER)
 	&msm_device_uart3,
+#endif
 	&msm_device_smd,
 	&msm_device_nand,
 	&msm_device_hsusb,
+	&usb_mass_storage_device,
+	&android_usb_device,
 	&msm_device_i2c,
 	&smc91x_device,
+	&halibut_snd,
+#ifdef CONFIG_MT9T013
+	&msm_camera_sensor_mt9t013,
+#endif
+#ifdef CONFIG_MT9D112
+	&msm_camera_sensor_mt9d112,
+#endif
+#ifdef CONFIG_S5K3E2FX
+	&msm_camera_sensor_s5k3e2fx,
+#endif
+#ifdef CONFIG_MT9P012
+	&msm_camera_sensor_mt9p012,
+#endif
+	&android_pmem_device,
+	&android_pmem_adsp_device,
+	&android_pmem_gpu0_device,
+	&android_pmem_gpu1_device,
+	&android_pmem_camera_device,
+	&fish_battery_device,
 };
 
 extern struct sys_timer msm_timer;
@@ -73,15 +425,38 @@
 	msm_init_irq();
 }
 
+static struct msm_acpu_clock_platform_data halibut_clock_data = {
+	.acpu_switch_time_us = 50,
+	.max_speed_delta_khz = 256000,
+	.vdd_switch_time_us = 62,
+	.power_collapse_khz = 19200000,
+	.wait_for_irq_khz = 128000000,
+};
+
+extern void msm_serial_debug_init(unsigned int base, int irq,
+				struct device *clk_device, int signal_irq);
+
 static void __init halibut_init(void)
 {
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+	msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3,
+			      &msm_device_uart3.dev, 1);
+#endif
+	msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata;
+	msm_acpu_clock_init(&halibut_clock_data);
+#ifdef CONFIG_MSM_CAMERA
+	config_camera_off_gpios(); /* might not be necessary */
+#endif
+	i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
 	platform_add_devices(devices, ARRAY_SIZE(devices));
+	i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
+	msm_hsusb_set_vbus_state(1);
 }
 
 static void __init halibut_fixup(struct machine_desc *desc, struct tag *tags,
 				 char **cmdline, struct meminfo *mi)
 {
-	mi->nr_banks=1;
+	mi->nr_banks = 1;
 	mi->bank[0].start = PHYS_OFFSET;
 	mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
 	mi->bank[0].size = (101*1024*1024);
@@ -95,7 +470,7 @@
 
 MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io        = MSM_DEBUG_UART_PHYS,
+	.phys_io	= MSM_DEBUG_UART_PHYS,
 	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-msm/board-halibut.h b/arch/arm/mach-msm/board-halibut.h
new file mode 100644
index 0000000..edcdacb
--- /dev/null
+++ b/arch/arm/mach-msm/board-halibut.h
@@ -0,0 +1,20 @@
+/* linux/arch/arm/mach-msm/board-trout.h
+ * ** Author: Brian Swetland <swetland@google.com>
+ * */
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_HALIBUT_H
+#define __ARCH_ARM_MACH_MSM_BOARD_HALIBUT_H
+
+#define MSM_PMEM_GPU0_BASE      (0x10000000 + 64*SZ_1M)
+#define MSM_PMEM_GPU0_SIZE      0x800000
+#define MSM_PMEM_MDP_BASE       (MSM_PMEM_GPU0_BASE + MSM_PMEM_GPU0_SIZE)
+#define MSM_PMEM_MDP_SIZE       0x800000
+#define MSM_PMEM_ADSP_BASE      (MSM_PMEM_MDP_BASE + MSM_PMEM_MDP_SIZE)
+#define MSM_PMEM_ADSP_SIZE      0x800000
+#define MSM_PMEM_GPU1_BASE      (MSM_PMEM_ADSP_BASE + MSM_PMEM_ADSP_SIZE)
+#define MSM_PMEM_GPU1_SIZE      0x800000
+#define MSM_FB_BASE		(MSM_PMEM_GPU1_BASE + MSM_PMEM_GPU1_SIZE)
+#define MSM_FB_SIZE             0x200000
+#define MSM_PMEM_CAMERA_BASE	(MSM_FB_BASE + MSM_FB_SIZE)
+#define MSM_PMEM_CAMERA_SIZE	0xA00000
+
+#endif
diff --git a/arch/arm/mach-msm/board-mahimahi-audio.c b/arch/arm/mach-msm/board-mahimahi-audio.c
new file mode 100644
index 0000000..074d84e
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-audio.c
@@ -0,0 +1,283 @@
+/* arch/arm/mach-msm/board-mahimahi-audio.c
+ *
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (C) 2009 Google Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/htc_acoustic_qsd.h>
+
+#include "board-mahimahi.h"
+#include "proc_comm.h"
+#include "pmic.h"
+#include "board-mahimahi-tpa2018d1.h"
+
+#if 0
+#define D(fmt, args...) printk(KERN_INFO "Audio: "fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static struct mutex mic_lock;
+static struct mutex bt_sco_lock;
+
+static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = {
+	[Q6_HW_HANDSET] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_HEADSET] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_SPEAKER] = {
+		.min_gain = -1500,
+		.max_gain = 0,
+	},
+	[Q6_HW_TTY] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_BT_SCO] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_BT_A2DP] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+};
+
+void mahimahi_headset_enable(int en)
+{
+	D("%s %d\n", __func__, en);
+	/* enable audio amp */
+	if (en) mdelay(15);
+	gpio_set_value(MAHIMAHI_AUD_JACKHP_EN, !!en);
+}
+
+void mahimahi_speaker_enable(int en)
+{
+	struct spkr_config_mode scm;
+	memset(&scm, 0, sizeof(scm));
+
+	D("%s %d\n", __func__, en);
+	if (en) {
+		scm.is_right_chan_en = 0;
+		scm.is_left_chan_en = 1;
+		scm.is_stereo_en = 0;
+		scm.is_hpf_en = 1;
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+		pmic_set_spkr_configuration(&scm);
+		pmic_spkr_en(LEFT_SPKR, 1);
+		pmic_spkr_en(RIGHT_SPKR, 0);
+
+		/* unmute */
+		pmic_spkr_en_mute(LEFT_SPKR, 1);
+	} else {
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+
+		pmic_spkr_en(LEFT_SPKR, 0);
+		pmic_spkr_en(RIGHT_SPKR, 0);
+
+		pmic_set_spkr_configuration(&scm);
+	}
+
+	if (is_cdma_version(system_rev))
+		tpa2018d1_set_speaker_amp(en);
+}
+
+void mahimahi_receiver_enable(int en)
+{
+	if (is_cdma_version(system_rev) &&
+		((system_rev == 0xC1) || (system_rev == 0xC2))) {
+		struct spkr_config_mode scm;
+		memset(&scm, 0, sizeof(scm));
+
+		D("%s %d\n", __func__, en);
+		if (en) {
+			scm.is_right_chan_en = 1;
+			scm.is_left_chan_en = 0;
+			scm.is_stereo_en = 0;
+			scm.is_hpf_en = 1;
+			pmic_spkr_en_mute(RIGHT_SPKR, 0);
+			pmic_set_spkr_configuration(&scm);
+			pmic_spkr_en(RIGHT_SPKR, 1);
+
+			/* unmute */
+			pmic_spkr_en_mute(RIGHT_SPKR, 1);
+		} else {
+			pmic_spkr_en_mute(RIGHT_SPKR, 0);
+
+			pmic_spkr_en(RIGHT_SPKR, 0);
+
+			pmic_set_spkr_configuration(&scm);
+		}
+	}
+}
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for (n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+static uint32_t bt_sco_enable[] = {
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_OUT, 1, GPIO_OUTPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_IN, 1, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_SYNC, 2, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_CLK, 2, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+};
+
+static uint32_t bt_sco_disable[] = {
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_OUT, 0, GPIO_OUTPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_IN, 0, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_SYNC, 0, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_CLK, 0, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+};
+
+void mahimahi_bt_sco_enable(int en)
+{
+	static int bt_sco_refcount;
+	D("%s %d\n", __func__, en);
+
+	mutex_lock(&bt_sco_lock);
+	if (en) {
+		if (++bt_sco_refcount == 1)
+			config_gpio_table(bt_sco_enable,
+					ARRAY_SIZE(bt_sco_enable));
+	} else {
+		if (--bt_sco_refcount == 0) {
+			config_gpio_table(bt_sco_disable,
+					ARRAY_SIZE(bt_sco_disable));
+			gpio_set_value(MAHIMAHI_BT_PCM_OUT, 0);
+		}
+	}
+	mutex_unlock(&bt_sco_lock);
+}
+
+void mahimahi_mic_enable(int en)
+{
+	static int old_state = 0, new_state = 0;
+
+	D("%s %d\n", __func__, en);
+
+	mutex_lock(&mic_lock);
+	if (!!en)
+		new_state++;
+	else
+		new_state--;
+
+	if (new_state == 1 && old_state == 0) {
+		gpio_set_value(MAHIMAHI_AUD_2V5_EN, 1);
+		mdelay(60);
+	} else if (new_state == 0 && old_state == 1)
+		gpio_set_value(MAHIMAHI_AUD_2V5_EN, 0);
+	else
+		D("%s: do nothing %d %d\n", __func__, old_state, new_state);
+
+	old_state = new_state;
+	mutex_unlock(&mic_lock);
+}
+
+void mahimahi_analog_init(void)
+{
+	D("%s\n", __func__);
+	/* stereo pmic init */
+	pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_spkr_en_right_chan(OFF_CMD);
+	pmic_spkr_en_left_chan(OFF_CMD);
+	pmic_spkr_add_right_left_chan(OFF_CMD);
+	pmic_spkr_en_stereo(OFF_CMD);
+	pmic_spkr_select_usb_with_hpf_20hz(OFF_CMD);
+	pmic_spkr_bypass_mux(OFF_CMD);
+	pmic_spkr_en_hpf(ON_CMD);
+	pmic_spkr_en_sink_curr_from_ref_volt_cir(OFF_CMD);
+	pmic_spkr_set_mux_hpf_corner_freq(SPKR_FREQ_0_73KHZ);
+	pmic_mic_set_volt(MIC_VOLT_1_80V);
+
+	gpio_request(MAHIMAHI_AUD_JACKHP_EN, "aud_jackhp_en");
+	gpio_request(MAHIMAHI_BT_PCM_OUT, "bt_pcm_out");
+
+	gpio_direction_output(MAHIMAHI_AUD_JACKHP_EN, 0);
+
+	mutex_lock(&bt_sco_lock);
+	config_gpio_table(bt_sco_disable,
+			ARRAY_SIZE(bt_sco_disable));
+	gpio_direction_output(MAHIMAHI_BT_PCM_OUT, 0);
+	mutex_unlock(&bt_sco_lock);
+}
+
+int mahimahi_get_rx_vol(uint8_t hw, int level)
+{
+	int vol;
+
+	if (level > 100)
+		level = 100;
+	else if (level < 0)
+		level = 0;
+
+	if (is_cdma_version(system_rev) && hw == Q6_HW_HANDSET) {
+		int handset_volume[6] = { -1600, -1300, -1000, -600, -300, 0 };
+		vol = handset_volume[5 * level / 100];
+	} else {
+		struct q6_hw_info *info;
+		info = &q6_audio_hw[hw];
+		vol = info->min_gain + ((info->max_gain - info->min_gain) * level) / 100;
+	}
+
+	D("%s %d\n", __func__, vol);
+	return vol;
+}
+
+static struct qsd_acoustic_ops acoustic = {
+	.enable_mic_bias = mahimahi_mic_enable,
+};
+
+static struct q6audio_analog_ops ops = {
+	.init = mahimahi_analog_init,
+	.speaker_enable = mahimahi_speaker_enable,
+	.headset_enable = mahimahi_headset_enable,
+	.receiver_enable = mahimahi_receiver_enable,
+	.bt_sco_enable = mahimahi_bt_sco_enable,
+	.int_mic_enable = mahimahi_mic_enable,
+	.ext_mic_enable = mahimahi_mic_enable,
+	.get_rx_vol = mahimahi_get_rx_vol,
+};
+
+void __init mahimahi_audio_init(void)
+{
+	mutex_init(&mic_lock);
+	mutex_init(&bt_sco_lock);
+	q6audio_register_analog_ops(&ops);
+	acoustic_register_ops(&acoustic);
+	if (is_cdma_version(system_rev) &&
+		((system_rev == 0xC1) || (system_rev == 0xC2)))
+		q6audio_set_acdb_file("default_PMIC.acdb");
+}
diff --git a/arch/arm/mach-msm/board-mahimahi-flashlight.c b/arch/arm/mach-msm/board-mahimahi-flashlight.c
new file mode 100644
index 0000000..829b1f1
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-flashlight.c
@@ -0,0 +1,279 @@
+/*
+ * arch/arm/mach-msm/flashlight.c - flashlight driver
+ *
+ *  Copyright (C) 2009 zion huang <zion_huang@htc.com>
+ *
+ *  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; version 2 of the License.
+ */
+
+#define DEBUG
+
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/wakelock.h>
+#include <linux/hrtimer.h>
+#include <mach/msm_iomap.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#include "board-mahimahi-flashlight.h"
+
+struct flashlight_struct {
+	struct led_classdev fl_lcdev;
+	struct early_suspend early_suspend_flashlight;
+	spinlock_t spin_lock;
+	struct hrtimer timer;
+	int brightness;
+	int gpio_torch;
+	int gpio_flash;
+	int flash_duration_ms;
+};
+
+static struct flashlight_struct the_fl;
+
+static inline void toggle(void)
+{
+	gpio_direction_output(the_fl.gpio_torch, 0);
+	udelay(2);
+	gpio_direction_output(the_fl.gpio_torch, 1);
+	udelay(2);
+}
+
+static void flashlight_hw_command(uint8_t addr, uint8_t data)
+{
+	int i;
+
+	for (i = 0; i < addr + 17; i++)
+		toggle();
+	udelay(500);
+
+	for (i = 0; i < data; i++)
+		toggle();
+	udelay(500);
+}
+
+static enum hrtimer_restart flashlight_timeout(struct hrtimer *timer)
+{
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+
+	spin_lock_irqsave(&the_fl.spin_lock, flags);
+	gpio_direction_output(the_fl.gpio_flash, 0);
+	the_fl.brightness = LED_OFF;
+	spin_unlock_irqrestore(&the_fl.spin_lock, flags);
+
+	return HRTIMER_NORESTART;
+}
+
+int flashlight_control(int mode)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	pr_debug("%s: mode %d -> %d\n", __func__,
+			the_fl.brightness, mode);
+
+	spin_lock_irqsave(&the_fl.spin_lock, flags);
+
+	the_fl.brightness = mode;
+
+	switch (mode) {
+	case FLASHLIGHT_TORCH:
+		pr_info("%s: half\n", __func__);
+		/* If we are transitioning from flash to torch, make sure to
+		 * cancel the flash timeout timer, otherwise when it expires,
+		 * the torch will go off as well.
+		 */
+		hrtimer_cancel(&the_fl.timer);
+		flashlight_hw_command(2, 4);
+		break;
+
+	case FLASHLIGHT_FLASH:
+		pr_info("%s: full\n", __func__);
+		hrtimer_cancel(&the_fl.timer);
+		gpio_direction_output(the_fl.gpio_flash, 0);
+		udelay(40);
+		gpio_direction_output(the_fl.gpio_flash, 1);
+		hrtimer_start(&the_fl.timer,
+			ktime_set(the_fl.flash_duration_ms / 1000,
+					(the_fl.flash_duration_ms % 1000) *
+						NSEC_PER_MSEC),
+				HRTIMER_MODE_REL);
+		/* Flash overrides torch mode, and after the flash period, the
+		 * flash LED will turn off.
+		 */
+		mode = LED_OFF;
+		break;
+
+	case FLASHLIGHT_OFF:
+		pr_info("%s: off\n", __func__);
+		gpio_direction_output(the_fl.gpio_flash, 0);
+		gpio_direction_output(the_fl.gpio_torch, 0);
+		break;
+
+	default:
+		pr_err("%s: unknown flash_light flags: %d\n", __func__, mode);
+		ret = -EINVAL;
+		goto done;
+	}
+
+done:
+	spin_unlock_irqrestore(&the_fl.spin_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(flashlight_control);
+
+static void fl_lcdev_brightness_set(struct led_classdev *led_cdev,
+		enum led_brightness brightness)
+{
+	int level;
+	switch (brightness) {
+	case LED_HALF:
+		level = FLASHLIGHT_TORCH;
+		break;
+	case LED_FULL:
+		level = FLASHLIGHT_FLASH;
+		break;
+	case LED_OFF:
+	default:
+		level = FLASHLIGHT_OFF;
+	};
+
+	flashlight_control(level);
+}
+
+static void flashlight_early_suspend(struct early_suspend *handler)
+{
+	flashlight_control(FLASHLIGHT_OFF);
+}
+
+static int flashlight_setup_gpio(struct flashlight_platform_data *fl_pdata)
+{
+	int ret;
+
+	pr_debug("%s\n", __func__);
+
+	if (fl_pdata->gpio_init) {
+		ret = fl_pdata->gpio_init();
+		if (ret < 0) {
+			pr_err("%s: gpio init failed: %d\n", __func__,
+				ret);
+			return ret;
+		}
+	}
+
+	if (fl_pdata->torch) {
+		ret = gpio_request(fl_pdata->torch, "flashlight_torch");
+		if (ret < 0) {
+			pr_err("%s: gpio_request failed\n", __func__);
+			return ret;
+		}
+	}
+
+	if (fl_pdata->flash) {
+		ret = gpio_request(fl_pdata->flash, "flashlight_flash");
+		if (ret < 0) {
+			pr_err("%s: gpio_request failed\n", __func__);
+			gpio_free(fl_pdata->torch);
+			return ret;
+		}
+	}
+
+	the_fl.gpio_torch = fl_pdata->torch;
+	the_fl.gpio_flash = fl_pdata->flash;
+	the_fl.flash_duration_ms = fl_pdata->flash_duration_ms;
+	return 0;
+}
+
+static int flashlight_probe(struct platform_device *pdev)
+{
+	struct flashlight_platform_data *fl_pdata = pdev->dev.platform_data;
+	int err = 0;
+
+	pr_debug("%s\n", __func__);
+
+	err = flashlight_setup_gpio(fl_pdata);
+	if (err < 0) {
+		pr_err("%s: setup GPIO failed\n", __func__);
+		goto fail_free_mem;
+	}
+
+	spin_lock_init(&the_fl.spin_lock);
+	the_fl.fl_lcdev.name = pdev->name;
+	the_fl.fl_lcdev.brightness_set = fl_lcdev_brightness_set;
+	the_fl.fl_lcdev.brightness = LED_OFF;
+	err = led_classdev_register(&pdev->dev, &the_fl.fl_lcdev);
+	if (err < 0) {
+		pr_err("failed on led_classdev_register\n");
+		goto fail_free_gpio;
+	}
+
+	hrtimer_init(&the_fl.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	the_fl.timer.function = flashlight_timeout;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	the_fl.early_suspend_flashlight.suspend = flashlight_early_suspend;
+	the_fl.early_suspend_flashlight.resume = NULL;
+	register_early_suspend(&the_fl.early_suspend_flashlight);
+#endif
+
+	return 0;
+
+fail_free_gpio:
+	if (fl_pdata->torch)
+		gpio_free(fl_pdata->torch);
+	if (fl_pdata->flash)
+		gpio_free(fl_pdata->flash);
+fail_free_mem:
+	return err;
+}
+
+static int flashlight_remove(struct platform_device *pdev)
+{
+	struct flashlight_platform_data *fl_pdata = pdev->dev.platform_data;
+
+	pr_debug("%s\n", __func__);
+
+	hrtimer_cancel(&the_fl.timer);
+	unregister_early_suspend(&the_fl.early_suspend_flashlight);
+	flashlight_control(FLASHLIGHT_OFF);
+	led_classdev_unregister(&the_fl.fl_lcdev);
+	if (fl_pdata->torch)
+		gpio_free(fl_pdata->torch);
+	if (fl_pdata->flash)
+		gpio_free(fl_pdata->flash);
+	return 0;
+}
+
+static struct platform_driver flashlight_driver = {
+	.probe		= flashlight_probe,
+	.remove		= flashlight_remove,
+	.driver		= {
+		.name		= FLASHLIGHT_NAME,
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init flashlight_init(void)
+{
+	pr_debug("%s\n", __func__);
+	return platform_driver_register(&flashlight_driver);
+}
+
+static void __exit flashlight_exit(void)
+{
+	pr_debug("%s\n", __func__);
+	platform_driver_unregister(&flashlight_driver);
+}
+
+module_init(flashlight_init);
+module_exit(flashlight_exit);
+
+MODULE_AUTHOR("Zion Huang <zion_huang@htc.com>");
+MODULE_DESCRIPTION("flash light driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-mahimahi-flashlight.h b/arch/arm/mach-msm/board-mahimahi-flashlight.h
new file mode 100644
index 0000000..93b4095
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-flashlight.h
@@ -0,0 +1,20 @@
+#ifndef __ASM_ARM_ARCH_FLASHLIGHT_H
+#define __ASM_ARM_ARCH_FLASHLIGHT_H
+
+#define FLASHLIGHT_NAME "flashlight"
+
+#define FLASHLIGHT_OFF   0
+#define FLASHLIGHT_TORCH 1
+#define FLASHLIGHT_FLASH 2
+#define FLASHLIGHT_NUM   3
+
+struct flashlight_platform_data {
+	int (*gpio_init) (void);
+	int torch;
+	int flash;
+	int flash_duration_ms;
+};
+
+int flashlight_control(int level);
+
+#endif /*__ASM_ARM_ARCH_FLASHLIGHT_H*/
diff --git a/arch/arm/mach-msm/board-mahimahi-keypad.c b/arch/arm/mach-msm/board-mahimahi-keypad.c
new file mode 100644
index 0000000..ab38847
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-keypad.c
@@ -0,0 +1,265 @@
+/* arch/arm/mach-msm/board-mahimahi-keypad.c
+ *
+ * Copyright (C) 2009 Google, Inc
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * Author: Dima Zavin <dima@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/gpio_event.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/keyreset.h>
+#include <linux/platform_device.h>
+#include <mach/vreg.h>
+
+#include <asm/mach-types.h>
+
+#include "board-mahimahi.h"
+
+struct jog_axis_info {
+	struct gpio_event_axis_info	info;
+	uint16_t			in_state;
+	uint16_t			out_state;
+};
+
+static struct vreg *jog_vreg;
+static bool jog_just_on;
+static unsigned long jog_on_jiffies;
+
+static unsigned int mahimahi_col_gpios[] = { 33, 32, 31 };
+static unsigned int mahimahi_row_gpios[] = { 42, 41, 40 };
+
+#define KEYMAP_INDEX(col, row)	((col)*ARRAY_SIZE(mahimahi_row_gpios) + (row))
+#define KEYMAP_SIZE		(ARRAY_SIZE(mahimahi_col_gpios) * \
+				 ARRAY_SIZE(mahimahi_row_gpios))
+
+/* keypad */
+static const unsigned short mahimahi_keymap[KEYMAP_SIZE] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(0, 1)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(1, 1)] = MATRIX_KEY(1, BTN_MOUSE),
+};
+
+static const unsigned short mahimahi_cdma_keymap[KEYMAP_SIZE] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(0, 1)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(1, 1)] = MATRIX_KEY(1, BTN_MOUSE),
+
+	/* Key (2, 2) is not a physical key on mahimahi. The purpose of
+	 * registering the unused matrix key as a dummy <end> key is to make
+	 * userland able to send/receive the key event for some requested tests
+	 * in lab. of some CDMA carriers (e.g. Verizon).
+	 */
+	[KEYMAP_INDEX(2, 2)] = KEY_END,
+};
+
+static struct gpio_event_matrix_info mahimahi_keypad_matrix_info = {
+	.info.func = gpio_event_matrix_func,
+	.keymap = mahimahi_keymap,
+	.output_gpios = mahimahi_col_gpios,
+	.input_gpios = mahimahi_row_gpios,
+	.noutputs = ARRAY_SIZE(mahimahi_col_gpios),
+	.ninputs = ARRAY_SIZE(mahimahi_row_gpios),
+	.settle_time.tv.nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.flags = (GPIOKPF_LEVEL_TRIGGERED_IRQ |
+		  GPIOKPF_REMOVE_PHANTOM_KEYS |
+		  GPIOKPF_PRINT_UNMAPPED_KEYS),
+};
+
+static struct gpio_event_direct_entry mahimahi_keypad_key_map[] = {
+	{
+		.gpio	= MAHIMAHI_GPIO_POWER_KEY,
+		.code	= KEY_POWER,
+	},
+};
+
+static struct gpio_event_input_info mahimahi_keypad_key_info = {
+	.info.func = gpio_event_input_func,
+	.info.no_suspend = true,
+	.debounce_time.tv.nsec = 5 * NSEC_PER_MSEC,
+	.flags = 0,
+	.type = EV_KEY,
+	.keymap = mahimahi_keypad_key_map,
+	.keymap_size = ARRAY_SIZE(mahimahi_keypad_key_map)
+};
+
+/* jogball */
+static uint16_t jogball_axis_map(struct gpio_event_axis_info *info, uint16_t in)
+{
+	struct jog_axis_info *ai =
+		container_of(info, struct jog_axis_info, info);
+	uint16_t out = ai->out_state;
+
+	if (jog_just_on) {
+		if (jiffies == jog_on_jiffies || jiffies == jog_on_jiffies + 1)
+			goto ignore;
+		jog_just_on = 0;
+	}
+	if((ai->in_state ^ in) & 1)
+		out--;
+	if((ai->in_state ^ in) & 2)
+		out++;
+	ai->out_state = out;
+ignore:
+	ai->in_state = in;
+	return out;
+}
+
+static int jogball_power(const struct gpio_event_platform_data *pdata, bool on)
+{
+	if (on) {
+		vreg_enable(jog_vreg);
+		jog_just_on = 1;
+		jog_on_jiffies = jiffies;
+	} else {
+		vreg_disable(jog_vreg);
+	}
+
+	return 0;
+}
+
+static int jogball_power_cdma(const struct gpio_event_platform_data *pdata, bool on)
+{
+	if (on) {
+		gpio_set_value(MAHIMAHI_CDMA_JOG_2V6_EN, 1);
+		jog_just_on = 1;
+		jog_on_jiffies = jiffies;
+	} else {
+		gpio_set_value(MAHIMAHI_CDMA_JOG_2V6_EN, 0);
+	}
+
+	return 0;
+}
+
+static uint32_t jogball_x_gpios[] = {
+	MAHIMAHI_GPIO_BALL_LEFT, MAHIMAHI_GPIO_BALL_RIGHT,
+};
+static uint32_t jogball_y_gpios[] = {
+	MAHIMAHI_GPIO_BALL_UP, MAHIMAHI_GPIO_BALL_DOWN,
+};
+
+static struct jog_axis_info jogball_x_axis = {
+	.info = {
+		.info.func = gpio_event_axis_func,
+		.count = ARRAY_SIZE(jogball_x_gpios),
+		.dev = 1,
+		.type = EV_REL,
+		.code = REL_X,
+		.decoded_size = 1U << ARRAY_SIZE(jogball_x_gpios),
+		.map = jogball_axis_map,
+		.gpio = jogball_x_gpios,
+		.flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION,
+	}
+};
+
+static struct jog_axis_info jogball_y_axis = {
+	.info = {
+		.info.func = gpio_event_axis_func,
+		.count = ARRAY_SIZE(jogball_y_gpios),
+		.dev = 1,
+		.type = EV_REL,
+		.code = REL_Y,
+		.decoded_size = 1U << ARRAY_SIZE(jogball_y_gpios),
+		.map = jogball_axis_map,
+		.gpio = jogball_y_gpios,
+		.flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION,
+	}
+};
+
+static struct gpio_event_info *mahimahi_input_info[] = {
+	&mahimahi_keypad_matrix_info.info,
+	&mahimahi_keypad_key_info.info,
+	&jogball_x_axis.info.info,
+	&jogball_y_axis.info.info,
+};
+
+static struct gpio_event_platform_data mahimahi_input_data = {
+	.names = {
+		"mahimahi-keypad",
+		"mahimahi-nav",
+		NULL,
+	},
+	.info = mahimahi_input_info,
+	.info_count = ARRAY_SIZE(mahimahi_input_info),
+	.power = jogball_power,
+};
+
+static struct platform_device mahimahi_input_device = {
+	.name = GPIO_EVENT_DEV_NAME,
+	.id = 0,
+	.dev = {
+		.platform_data = &mahimahi_input_data,
+	},
+};
+
+static int mahimahi_reset_keys_up[] = {
+	KEY_VOLUMEUP,
+	0,
+};
+
+static struct keyreset_platform_data mahimahi_reset_keys_pdata = {
+	.keys_up	= mahimahi_reset_keys_up,
+	.keys_down	= {
+		KEY_POWER,
+		KEY_VOLUMEDOWN,
+		BTN_MOUSE,
+		0
+	},
+};
+
+struct platform_device mahimahi_reset_keys_device = {
+	.name	= KEYRESET_NAME,
+	.dev	= {
+		.platform_data = &mahimahi_reset_keys_pdata,
+	},
+};
+
+
+static int __init mahimahi_init_keypad_jogball(void)
+{
+	int ret;
+
+	if (!machine_is_mahimahi())
+		return 0;
+
+	ret = platform_device_register(&mahimahi_reset_keys_device);
+	if (ret != 0)
+		return ret;
+
+	if (is_cdma_version(system_rev)) {
+		mahimahi_keypad_matrix_info.keymap = mahimahi_cdma_keymap;
+		/* In the CDMA version, jogball power is supplied by a gpio. */
+		ret = gpio_request(MAHIMAHI_CDMA_JOG_2V6_EN, "jog_en");
+		if (ret < 0) {
+			pr_err("%s: gpio_request(%d) failed: %d\n", __func__,
+				MAHIMAHI_CDMA_JOG_2V6_EN, ret);
+			return ret;
+		}
+		mahimahi_input_data.power = jogball_power_cdma;
+	} else {
+		/* in UMTS version, jogball power is supplied by pmic */
+		jog_vreg = vreg_get(&mahimahi_input_device.dev, "gp2");
+		if (jog_vreg == NULL)
+			return -ENOENT;
+	}
+
+	ret = platform_device_register(&mahimahi_input_device);
+	if (ret != 0)
+		return ret;
+
+	return 0;
+}
+
+device_initcall(mahimahi_init_keypad_jogball);
diff --git a/arch/arm/mach-msm/board-mahimahi-microp.c b/arch/arm/mach-msm/board-mahimahi-microp.c
new file mode 100644
index 0000000..da30672
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-microp.c
@@ -0,0 +1,2261 @@
+/* board-mahimahi-microp.c
+ * Copyright (C) 2009 Google.
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * The Microp on mahimahi is an i2c device that supports
+ * the following functions
+ *   - LEDs (Green, Amber, Jogball backlight)
+ *   - Lightsensor
+ *   - Headset remotekeys
+ *   - G-sensor
+ *   - Interrupts
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/miscdevice.h>
+#include <linux/input.h>
+#include <asm/uaccess.h>
+#include <linux/wakelock.h>
+#include <asm/mach-types.h>
+#include <mach/htc_pwrsink.h>
+#include <linux/earlysuspend.h>
+#include <linux/bma150.h>
+#include <linux/lightsensor.h>
+#include <asm/mach/mmc.h>
+#include <mach/htc_35mm_jack.h>
+#include <asm/setup.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+
+#include "board-mahimahi.h"
+
+
+#define MICROP_I2C_NAME "mahimahi-microp"
+
+#define MICROP_LSENSOR_ADC_CHAN		6
+#define MICROP_REMOTE_KEY_ADC_CHAN	7
+
+#define MICROP_I2C_WCMD_MISC				0x20
+#define MICROP_I2C_WCMD_SPI_EN				0x21
+#define MICROP_I2C_WCMD_AUTO_BL_CTL			0x23
+#define MICROP_I2C_RCMD_SPI_BL_STATUS			0x24
+#define MICROP_I2C_WCMD_BUTTONS_LED_CTRL		0x25
+#define MICROP_I2C_RCMD_VERSION				0x30
+#define MICROP_I2C_WCMD_ADC_TABLE			0x42
+#define MICROP_I2C_WCMD_LED_MODE			0x53
+#define MICROP_I2C_RCMD_GREEN_LED_REMAIN_TIME		0x54
+#define MICROP_I2C_RCMD_AMBER_RED_LED_REMAIN_TIME	0x55
+#define MICROP_I2C_RCMD_BLUE_LED_REMAIN_TIME		0x57
+#define MICROP_I2C_WCMD_JOGBALL_LED_MODE		0x5A
+#define MICROP_I2C_RCMD_JOGBALL_LED_REMAIN_TIME		0x5B
+#define MICROP_I2C_WCMD_JOGBALL_LED_PWM_SET		0x5C
+#define MICROP_I2C_WCMD_JOGBALL_LED_PERIOD_SET		0x5D
+#define MICROP_I2C_WCMD_READ_ADC_VALUE_REQ		0x60
+#define MICROP_I2C_RCMD_ADC_VALUE			0x62
+#define MICROP_I2C_WCMD_REMOTEKEY_TABLE			0x63
+#define MICROP_I2C_WCMD_LCM_REGISTER			0x70
+#define MICROP_I2C_WCMD_GSENSOR_REG			0x73
+#define MICROP_I2C_WCMD_GSENSOR_REG_DATA_REQ		0x74
+#define MICROP_I2C_RCMD_GSENSOR_REG_DATA		0x75
+#define MICROP_I2C_WCMD_GSENSOR_DATA_REQ		0x76
+#define MICROP_I2C_RCMD_GSENSOR_X_DATA			0x77
+#define MICROP_I2C_RCMD_GSENSOR_Y_DATA			0x78
+#define MICROP_I2C_RCMD_GSENSOR_Z_DATA			0x79
+#define MICROP_I2C_RCMD_GSENSOR_DATA			0x7A
+#define MICROP_I2C_WCMD_OJ_REG				0x7B
+#define MICROP_I2C_WCMD_OJ_REG_DATA_REQ			0x7C
+#define MICROP_I2C_RCMD_OJ_REG_DATA			0x7D
+#define MICROP_I2C_WCMD_OJ_POS_DATA_REQ			0x7E
+#define MICROP_I2C_RCMD_OJ_POS_DATA			0x7F
+#define MICROP_I2C_WCMD_GPI_INT_CTL_EN			0x80
+#define MICROP_I2C_WCMD_GPI_INT_CTL_DIS			0x81
+#define MICROP_I2C_RCMD_GPI_INT_STATUS			0x82
+#define MICROP_I2C_RCMD_GPI_STATUS			0x83
+#define MICROP_I2C_WCMD_GPI_INT_STATUS_CLR		0x84
+#define MICROP_I2C_RCMD_GPI_INT_SETTING			0x85
+#define MICROP_I2C_RCMD_REMOTE_KEYCODE			0x87
+#define MICROP_I2C_WCMD_REMOTE_KEY_DEBN_TIME		0x88
+#define MICROP_I2C_WCMD_REMOTE_PLUG_DEBN_TIME		0x89
+#define MICROP_I2C_WCMD_SIMCARD_DEBN_TIME		0x8A
+#define MICROP_I2C_WCMD_GPO_LED_STATUS_EN		0x90
+#define MICROP_I2C_WCMD_GPO_LED_STATUS_DIS		0x91
+
+#define IRQ_GSENSOR	(1<<10)
+#define IRQ_LSENSOR  	(1<<9)
+#define IRQ_REMOTEKEY	(1<<7)
+#define IRQ_HEADSETIN	(1<<2)
+#define IRQ_SDCARD	(1<<0)
+
+#define READ_GPI_STATE_HPIN	(1<<2)
+#define READ_GPI_STATE_SDCARD	(1<<0)
+
+#define ALS_CALIBRATE_MODE  147
+
+/* Check pattern, to check if ALS has been calibrated */
+#define ALS_CALIBRATED	0x6DA5
+
+/* delay for deferred light sensor read */
+#define LS_READ_DELAY   (HZ/2)
+
+/*#define DEBUG_BMA150  */
+#ifdef DEBUG_BMA150
+/* Debug logging of accelleration data */
+#define GSENSOR_LOG_MAX 2048  /* needs to be power of 2 */
+#define GSENSOR_LOG_MASK (GSENSOR_LOG_MAX - 1)
+
+struct gsensor_log {
+	ktime_t timestamp;
+	short x;
+	short y;
+	short z;
+};
+
+static DEFINE_MUTEX(gsensor_log_lock);
+static struct gsensor_log gsensor_log[GSENSOR_LOG_MAX];
+static unsigned gsensor_log_head;
+static unsigned gsensor_log_tail;
+
+void gsensor_log_status(ktime_t time, short x, short y, short z)
+{
+	unsigned n;
+	mutex_lock(&gsensor_log_lock);
+	n = gsensor_log_head;
+	gsensor_log[n].timestamp = time;
+	gsensor_log[n].x = x;
+	gsensor_log[n].y = y;
+	gsensor_log[n].z = z;
+	n = (n + 1) & GSENSOR_LOG_MASK;
+	if (n == gsensor_log_tail)
+		gsensor_log_tail = (gsensor_log_tail + 1) & GSENSOR_LOG_MASK;
+	gsensor_log_head = n;
+	mutex_unlock(&gsensor_log_lock);
+}
+
+static int gsensor_log_print(struct seq_file *sf, void *private)
+{
+	unsigned n;
+
+	mutex_lock(&gsensor_log_lock);
+	seq_printf(sf, "timestamp                  X      Y      Z\n");
+	for (n = gsensor_log_tail;
+	     n != gsensor_log_head;
+	     n = (n + 1) & GSENSOR_LOG_MASK) {
+		seq_printf(sf, "%10d.%010d %6d %6d %6d\n",
+			   gsensor_log[n].timestamp.tv.sec,
+			   gsensor_log[n].timestamp.tv.nsec,
+			   gsensor_log[n].x, gsensor_log[n].y,
+			   gsensor_log[n].z);
+	}
+	mutex_unlock(&gsensor_log_lock);
+	return 0;
+}
+
+static int gsensor_log_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, gsensor_log_print, NULL);
+}
+
+static struct file_operations gsensor_log_fops = {
+	.open = gsensor_log_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+#endif /* def DEBUG_BMA150 */
+
+static int microp_headset_has_mic(void);
+static int microp_enable_headset_plug_event(void);
+static int microp_enable_key_event(void);
+static int microp_disable_key_event(void);
+
+static struct h35mm_platform_data mahimahi_h35mm_data = {
+	.plug_event_enable = microp_enable_headset_plug_event,
+	.headset_has_mic = microp_headset_has_mic,
+	.key_event_enable = microp_enable_key_event,
+	.key_event_disable = microp_disable_key_event,
+};
+
+static struct platform_device mahimahi_h35mm = {
+	.name           = "htc_headset",
+	.id                     = -1,
+	.dev            = {
+		.platform_data  = &mahimahi_h35mm_data,
+	},
+};
+
+enum led_type {
+	GREEN_LED,
+	AMBER_LED,
+	RED_LED,
+	BLUE_LED,
+	JOGBALL_LED,
+	BUTTONS_LED,
+	NUM_LEDS,
+};
+
+static uint16_t lsensor_adc_table[10] = {
+	0x000, 0x001, 0x00F, 0x01E, 0x03C, 0x121, 0x190, 0x2BA, 0x26E, 0x3FF
+};
+
+static uint16_t remote_key_adc_table[6] = {
+	0, 33, 43, 110, 129, 220
+};
+
+static uint32_t golden_adc = 0xC0;
+static uint32_t als_kadc;
+
+static struct wake_lock microp_i2c_wakelock;
+
+static struct i2c_client *private_microp_client;
+
+struct microp_int_pin {
+	uint16_t int_gsensor;
+	uint16_t int_lsensor;
+	uint16_t int_reset;
+	uint16_t int_simcard;
+	uint16_t int_hpin;
+	uint16_t int_remotekey;
+};
+
+struct microp_led_data {
+	int type;
+	struct led_classdev ldev;
+	struct mutex led_data_mutex;
+	struct work_struct brightness_work;
+	spinlock_t brightness_lock;
+	enum led_brightness brightness;
+	uint8_t mode;
+	uint8_t blink;
+};
+
+struct microp_i2c_work {
+	struct work_struct work;
+	struct i2c_client *client;
+	int (*intr_debounce)(uint8_t *pin_status);
+	void (*intr_function)(uint8_t *pin_status);
+};
+
+struct microp_i2c_client_data {
+	struct microp_led_data leds[NUM_LEDS];
+	uint16_t version;
+	struct microp_i2c_work work;
+	struct delayed_work hpin_debounce_work;
+	struct delayed_work ls_read_work;
+	struct early_suspend early_suspend;
+	uint8_t enable_early_suspend;
+	uint8_t enable_reset_button;
+	int microp_is_suspend;
+	int auto_backlight_enabled;
+	uint8_t light_sensor_enabled;
+	uint8_t force_light_sensor_read;
+	uint8_t button_led_value;
+	int headset_is_in;
+	int is_hpin_pin_stable;
+	struct input_dev *ls_input_dev;
+	uint32_t als_kadc;
+	uint32_t als_gadc;
+	uint8_t als_calibrating;
+};
+
+static char *hex2string(uint8_t *data, int len)
+{
+	static char buf[101];
+	int i;
+
+	i = (sizeof(buf) - 1) / 4;
+	if (len > i)
+		len = i;
+
+	for (i = 0; i < len; i++)
+		sprintf(buf + i * 4, "[%02X]", data[i]);
+
+	return buf;
+}
+
+#define I2C_READ_RETRY_TIMES  10
+#define I2C_WRITE_RETRY_TIMES 10
+
+static int i2c_read_block(struct i2c_client *client, uint8_t addr,
+	uint8_t *data, int length)
+{
+	int retry;
+	int ret;
+	struct i2c_msg msgs[] = {
+	{
+		.addr = client->addr,
+		.flags = 0,
+		.len = 1,
+		.buf = &addr,
+	},
+	{
+		.addr = client->addr,
+		.flags = I2C_M_RD,
+		.len = length,
+		.buf = data,
+	}
+	};
+
+	mdelay(1);
+	for (retry = 0; retry <= I2C_READ_RETRY_TIMES; retry++) {
+		ret = i2c_transfer(client->adapter, msgs, 2);
+		if (ret == 2) {
+			dev_dbg(&client->dev, "R [%02X] = %s\n", addr,
+					hex2string(data, length));
+			return 0;
+		}
+		msleep(10);
+	}
+
+	dev_err(&client->dev, "i2c_read_block retry over %d\n",
+			I2C_READ_RETRY_TIMES);
+	return -EIO;
+}
+
+#define MICROP_I2C_WRITE_BLOCK_SIZE 21
+static int i2c_write_block(struct i2c_client *client, uint8_t addr,
+	uint8_t *data, int length)
+{
+	int retry;
+	uint8_t buf[MICROP_I2C_WRITE_BLOCK_SIZE];
+	int ret;
+
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = length + 1,
+			.buf = buf,
+		}
+	};
+
+	dev_dbg(&client->dev, "W [%02X] = %s\n", addr,
+			hex2string(data, length));
+
+	if (length + 1 > MICROP_I2C_WRITE_BLOCK_SIZE) {
+		dev_err(&client->dev, "i2c_write_block length too long\n");
+		return -E2BIG;
+	}
+
+	buf[0] = addr;
+	memcpy((void *)&buf[1], (void *)data, length);
+
+	mdelay(1);
+	for (retry = 0; retry <= I2C_WRITE_RETRY_TIMES; retry++) {
+		ret = i2c_transfer(client->adapter, msg, 1);
+		if (ret == 1)
+			return 0;
+		msleep(10);
+	}
+	dev_err(&client->dev, "i2c_write_block retry over %d\n",
+			I2C_WRITE_RETRY_TIMES);
+	return -EIO;
+}
+
+static int microp_read_adc(uint8_t channel, uint16_t *value)
+{
+	struct i2c_client *client;
+	int ret;
+	uint8_t cmd[2], data[2];
+
+	client = private_microp_client;
+	cmd[0] = 0;
+	cmd[1] = channel;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_READ_ADC_VALUE_REQ,
+			      cmd, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: request adc fail\n", __func__);
+		return -EIO;
+	}
+
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_ADC_VALUE, data, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: read adc fail\n", __func__);
+		return -EIO;
+	}
+	*value = data[0] << 8 | data[1];
+	return 0;
+}
+
+static int microp_read_gpi_status(struct i2c_client *client, uint16_t *status)
+{
+	uint8_t data[2];
+	int ret;
+
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_GPI_STATUS, data, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: read failed\n", __func__);
+		return -EIO;
+	}
+	*status = (data[0] << 8) | data[1];
+	return 0;
+}
+
+static int microp_interrupt_enable(struct i2c_client *client,
+				   uint16_t interrupt_mask)
+{
+	uint8_t data[2];
+	int ret = -1;
+
+	data[0] = interrupt_mask >> 8;
+	data[1] = interrupt_mask & 0xFF;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GPI_INT_CTL_EN, data, 2);
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: enable 0x%x interrupt failed\n",
+			__func__, interrupt_mask);
+	return ret;
+}
+
+static int microp_interrupt_disable(struct i2c_client *client,
+				    uint16_t interrupt_mask)
+{
+	uint8_t data[2];
+	int ret = -1;
+
+	data[0] = interrupt_mask >> 8;
+	data[1] = interrupt_mask & 0xFF;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GPI_INT_CTL_DIS, data, 2);
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: disable 0x%x interrupt failed\n",
+			__func__, interrupt_mask);
+	return ret;
+}
+
+
+/*
+ * SD slot card-detect support
+ */
+static unsigned int sdslot_cd = 0;
+static void (*sdslot_status_cb)(int card_present, void *dev_id);
+static void *sdslot_mmc_dev;
+
+int mahimahi_microp_sdslot_status_register(
+		void (*cb)(int card_present, void *dev_id),
+		void *dev_id)
+{
+	if (sdslot_status_cb)
+		return -EBUSY;
+	sdslot_status_cb = cb;
+	sdslot_mmc_dev = dev_id;
+	return 0;
+}
+
+unsigned int mahimahi_microp_sdslot_status(struct device *dev)
+{
+	return sdslot_cd;
+}
+
+static void mahimahi_microp_sdslot_update_status(int status)
+{
+	sdslot_cd = !(status & READ_GPI_STATE_SDCARD);
+	if (sdslot_status_cb)
+		sdslot_status_cb(sdslot_cd, sdslot_mmc_dev);
+}
+
+/*
+ *Headset Support
+*/
+static void hpin_debounce_do_work(struct work_struct *work)
+{
+	uint16_t gpi_status = 0;
+	struct microp_i2c_client_data *cdata;
+	int insert = 0;
+	struct i2c_client *client;
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	microp_read_gpi_status(client, &gpi_status);
+	insert = (gpi_status & READ_GPI_STATE_HPIN) ? 0 : 1;
+	if (insert != cdata->headset_is_in) {
+		cdata->headset_is_in = insert;
+		pr_debug("headset %s\n", insert ? "inserted" : "removed");
+		htc_35mm_jack_plug_event(cdata->headset_is_in,
+					 &cdata->is_hpin_pin_stable);
+	}
+}
+
+static int microp_enable_headset_plug_event(void)
+{
+	int ret;
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	uint16_t stat;
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	/* enable microp interrupt to detect changes */
+	ret = microp_interrupt_enable(client, IRQ_HEADSETIN);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: failed to enable irqs\n",
+			__func__);
+		return 0;
+	}
+	/* see if headset state has changed */
+	microp_read_gpi_status(client, &stat);
+	stat = !(stat & READ_GPI_STATE_HPIN);
+	if(cdata->headset_is_in != stat) {
+		cdata->headset_is_in = stat;
+		pr_debug("Headset state changed\n");
+		htc_35mm_jack_plug_event(stat, &cdata->is_hpin_pin_stable);
+	}
+
+	return 1;
+}
+
+static int microp_headset_detect_mic(void)
+{
+	uint16_t data;
+
+	microp_read_adc(MICROP_REMOTE_KEY_ADC_CHAN, &data);
+	if (data >= 200)
+		return 1;
+	else
+		return 0;
+}
+
+static int microp_headset_has_mic(void)
+{
+	int mic1 = -1;
+	int mic2 = -1;
+	int count = 0;
+
+	mic2 = microp_headset_detect_mic();
+
+	/* debounce the detection wait until 2 consecutive read are equal */
+	while ((mic1 != mic2) && (count < 10)) {
+		mic1 = mic2;
+		msleep(600);
+		mic2 = microp_headset_detect_mic();
+		count++;
+	}
+
+	pr_info("%s: microphone (%d) %s\n", __func__, count,
+		mic1 ? "present" : "not present");
+
+	return mic1;
+}
+
+static int microp_enable_key_event(void)
+{
+	int ret;
+	struct i2c_client *client;
+
+	client = private_microp_client;
+
+	if (!is_cdma_version(system_rev))
+		gpio_set_value(MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN, 1);
+
+	/* turn on  key interrupt */
+	/* enable microp interrupt to detect changes */
+	ret = microp_interrupt_enable(client, IRQ_REMOTEKEY);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: failed to enable irqs\n",
+			__func__);
+		return ret;
+	}
+	return 0;
+}
+
+static int microp_disable_key_event(void)
+{
+	int ret;
+	struct i2c_client *client;
+
+	client = private_microp_client;
+
+	/* shutdown key interrupt */
+	if (!is_cdma_version(system_rev))
+		gpio_set_value(MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN, 0);
+
+	/* disable microp interrupt to detect changes */
+	ret = microp_interrupt_disable(client, IRQ_REMOTEKEY);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: failed to disable irqs\n",
+			__func__);
+		return ret;
+	}
+	return 0;
+}
+
+static int get_remote_keycode(int *keycode)
+{
+	struct i2c_client *client = private_microp_client;
+	int ret;
+	uint8_t data[2];
+
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_REMOTE_KEYCODE, data, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: read remote keycode fail\n",
+			 __func__);
+		return -EIO;
+	}
+	pr_debug("%s: key = 0x%x\n", __func__, data[1]);
+	if (!data[1]) {
+		*keycode = 0;
+		return 1;		/* no keycode */
+	} else {
+		*keycode = data[1];
+	}
+	return 0;
+}
+
+static ssize_t microp_i2c_remotekey_adc_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client;
+	uint16_t value;
+	int i, button = 0;
+	int ret;
+
+	client = to_i2c_client(dev);
+
+	microp_read_adc(MICROP_REMOTE_KEY_ADC_CHAN, &value);
+
+	for (i = 0; i < 3; i++) {
+		if ((value >= remote_key_adc_table[2 * i]) &&
+		    (value <= remote_key_adc_table[2 * i + 1])) {
+			button = i + 1;
+		}
+
+	}
+
+	ret = sprintf(buf, "Remote Key[0x%03X] => button %d\n",
+		      value, button);
+
+	return ret;
+}
+
+static DEVICE_ATTR(key_adc, 0644, microp_i2c_remotekey_adc_show, NULL);
+
+/*
+ * LED support
+*/
+static int microp_i2c_write_led_mode(struct i2c_client *client,
+				struct led_classdev *led_cdev,
+				uint8_t mode, uint16_t off_timer)
+{
+	struct microp_i2c_client_data *cdata;
+	struct microp_led_data *ldata;
+	uint8_t data[7];
+	int ret;
+
+	cdata = i2c_get_clientdata(client);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+
+
+	if (ldata->type == GREEN_LED) {
+		data[0] = 0x01;
+		data[1] = mode;
+		data[2] = off_timer >> 8;
+		data[3] = off_timer & 0xFF;
+		data[4] = 0x00;
+		data[5] = 0x00;
+		data[6] = 0x00;
+	} else if (ldata->type == AMBER_LED) {
+		data[0] = 0x02;
+		data[1] = 0x00;
+		data[2] = 0x00;
+		data[3] = 0x00;
+		data[4] = mode;
+		data[5] = off_timer >> 8;
+		data[6] = off_timer & 0xFF;
+	} else if (ldata->type == RED_LED) {
+		data[0] = 0x02;
+		data[1] = 0x00;
+		data[2] = 0x00;
+		data[3] = 0x00;
+		data[4] = mode? 5: 0;
+		data[5] = off_timer >> 8;
+		data[6] = off_timer & 0xFF;
+	} else if (ldata->type == BLUE_LED) {
+		data[0] = 0x04;
+		data[1] = mode;
+		data[2] = off_timer >> 8;
+		data[3] = off_timer & 0xFF;
+		data[4] = 0x00;
+		data[5] = 0x00;
+		data[6] = 0x00;
+	}
+
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_LED_MODE, data, 7);
+	if (ret == 0) {
+		mutex_lock(&ldata->led_data_mutex);
+		if (mode > 1)
+			ldata->blink = mode;
+		else
+			ldata->mode = mode;
+		mutex_unlock(&ldata->led_data_mutex);
+	}
+	return ret;
+}
+
+static ssize_t microp_i2c_led_blink_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	int ret;
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+
+	mutex_lock(&ldata->led_data_mutex);
+	ret = sprintf(buf, "%d\n", ldata->blink ? ldata->blink - 1 : 0);
+	mutex_unlock(&ldata->led_data_mutex);
+
+	return ret;
+}
+
+static ssize_t microp_i2c_led_blink_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	struct i2c_client *client;
+	int val, ret;
+	uint8_t mode;
+
+	val = -1;
+	sscanf(buf, "%u", &val);
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+	client = to_i2c_client(dev->parent);
+
+	mutex_lock(&ldata->led_data_mutex);
+	switch (val) {
+	case 0: /* stop flashing */
+		mode = ldata->mode;
+		ldata->blink = 0;
+		break;
+	case 1:
+	case 2:
+	case 3:
+		mode = val + 1;
+		break;
+
+	default:
+		mutex_unlock(&ldata->led_data_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(&ldata->led_data_mutex);
+
+	ret = microp_i2c_write_led_mode(client, led_cdev, mode, 0xffff);
+	if (ret)
+		dev_err(&client->dev, "%s set blink failed\n", led_cdev->name);
+
+	return count;
+}
+
+static DEVICE_ATTR(blink, 0644, microp_i2c_led_blink_show,
+				microp_i2c_led_blink_store);
+
+static ssize_t microp_i2c_led_off_timer_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct microp_i2c_client_data *cdata;
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	struct i2c_client *client;
+	uint8_t data[2];
+	int ret, offtime;
+
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+	client = to_i2c_client(dev->parent);
+	cdata = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "Getting %s remaining time\n", led_cdev->name);
+
+	if (ldata->type == GREEN_LED) {
+		ret = i2c_read_block(client,
+				MICROP_I2C_RCMD_GREEN_LED_REMAIN_TIME, data, 2);
+	} else if (ldata->type == AMBER_LED) {
+		ret = i2c_read_block(client,
+				MICROP_I2C_RCMD_AMBER_RED_LED_REMAIN_TIME,
+				data, 2);
+	} else if (ldata->type == RED_LED) {
+		ret = i2c_read_block(client,
+				MICROP_I2C_RCMD_AMBER_RED_LED_REMAIN_TIME,
+				data, 2);
+	} else if (ldata->type == BLUE_LED) {
+		ret = i2c_read_block(client,
+				MICROP_I2C_RCMD_BLUE_LED_REMAIN_TIME, data, 2);
+	} else {
+		dev_err(&client->dev, "Unknown led %s\n", ldata->ldev.name);
+		return -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(&client->dev,
+			"%s get off_timer failed\n", led_cdev->name);
+	}
+	offtime = (int)((data[1] | data[0] << 8) * 2);
+
+	ret = sprintf(buf, "Time remains %d:%d\n", offtime / 60, offtime % 60);
+	return ret;
+}
+
+static ssize_t microp_i2c_led_off_timer_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	struct i2c_client *client;
+	int min, sec, ret;
+	uint16_t off_timer;
+
+	min = -1;
+	sec = -1;
+	sscanf(buf, "%d %d", &min, &sec);
+
+	if (min < 0 || min > 255)
+		return -EINVAL;
+	if (sec < 0 || sec > 255)
+		return -EINVAL;
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+	client = to_i2c_client(dev->parent);
+
+	dev_dbg(&client->dev, "Setting %s off_timer to %d min %d sec\n",
+			led_cdev->name, min, sec);
+
+	if (!min && !sec)
+		off_timer = 0xFFFF;
+	else
+		off_timer = (min * 60 + sec) / 2;
+
+	ret = microp_i2c_write_led_mode(client, led_cdev,
+					ldata->mode, off_timer);
+	if (ret) {
+		dev_err(&client->dev,
+			"%s set off_timer %d min %d sec failed\n",
+			led_cdev->name, min, sec);
+	}
+	return count;
+}
+
+static DEVICE_ATTR(off_timer, 0644, microp_i2c_led_off_timer_show,
+			microp_i2c_led_off_timer_store);
+
+static ssize_t microp_i2c_jogball_color_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	struct i2c_client *client;
+	int rpwm, gpwm, bpwm, ret;
+	uint8_t data[4];
+
+	rpwm = -1;
+	gpwm = -1;
+	bpwm = -1;
+	sscanf(buf, "%d %d %d", &rpwm, &gpwm, &bpwm);
+
+	if (rpwm < 0 || rpwm > 255)
+		return -EINVAL;
+	if (gpwm < 0 || gpwm > 255)
+		return -EINVAL;
+	if (bpwm < 0 || bpwm > 255)
+		return -EINVAL;
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+	client = to_i2c_client(dev->parent);
+
+	dev_dbg(&client->dev, "Setting %s color to R=%d, G=%d, B=%d\n",
+			led_cdev->name, rpwm, gpwm, bpwm);
+
+	data[0] = rpwm;
+	data[1] = gpwm;
+	data[2] = bpwm;
+	data[3] = 0x00;
+
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_JOGBALL_LED_PWM_SET,
+			      data, 4);
+	if (ret) {
+		dev_err(&client->dev,
+			"%s set color R=%d G=%d B=%d failed\n",
+			led_cdev->name, rpwm, gpwm, bpwm);
+	}
+	return count;
+}
+
+static DEVICE_ATTR(color, 0644, NULL, microp_i2c_jogball_color_store);
+
+static ssize_t microp_i2c_jogball_period_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	struct i2c_client *client;
+	int period = -1;
+	int ret;
+	uint8_t data[4];
+
+	sscanf(buf, "%d", &period);
+
+	if (period < 2 || period > 12)
+		return -EINVAL;
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+	client = to_i2c_client(dev->parent);
+
+	dev_info(&client->dev, "Setting Jogball flash period to %d\n", period);
+
+	data[0] = 0x00;
+	data[1] = period;
+
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_JOGBALL_LED_PERIOD_SET,
+			      data, 2);
+	if (ret) {
+		dev_err(&client->dev, "%s set period=%d failed\n",
+			led_cdev->name, period);
+	}
+	return count;
+}
+
+static DEVICE_ATTR(period, 0644, NULL, microp_i2c_jogball_period_store);
+
+static void microp_brightness_set(struct led_classdev *led_cdev,
+			       enum led_brightness brightness)
+{
+	unsigned long flags;
+	struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
+	struct microp_led_data *ldata =
+		container_of(led_cdev, struct microp_led_data, ldev);
+
+	dev_dbg(&client->dev, "Setting %s brightness current %d new %d\n",
+			led_cdev->name, led_cdev->brightness, brightness);
+
+	if (brightness > 255)
+		brightness = 255;
+	led_cdev->brightness = brightness;
+
+	spin_lock_irqsave(&ldata->brightness_lock, flags);
+	ldata->brightness = brightness;
+	spin_unlock_irqrestore(&ldata->brightness_lock, flags);
+
+	schedule_work(&ldata->brightness_work);
+}
+
+static void microp_led_brightness_set_work(struct work_struct *work)
+{
+	unsigned long flags;
+	struct microp_led_data *ldata =
+		container_of(work, struct microp_led_data, brightness_work);
+	struct led_classdev *led_cdev = &ldata->ldev;
+
+	struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
+
+	enum led_brightness brightness;
+	int ret;
+	uint8_t mode;
+
+	spin_lock_irqsave(&ldata->brightness_lock, flags);
+	brightness = ldata->brightness;
+	spin_unlock_irqrestore(&ldata->brightness_lock, flags);
+
+	if (brightness)
+		mode = 1;
+	else
+		mode = 0;
+
+	ret = microp_i2c_write_led_mode(client, led_cdev, mode, 0xffff);
+	if (ret) {
+		dev_err(&client->dev,
+			 "led_brightness_set failed to set mode\n");
+	}
+}
+
+struct device_attribute *green_amber_attrs[] = {
+	&dev_attr_blink,
+	&dev_attr_off_timer,
+};
+
+struct device_attribute *jogball_attrs[] = {
+	&dev_attr_color,
+	&dev_attr_period,
+};
+
+static void microp_led_buttons_brightness_set_work(struct work_struct *work)
+{
+
+	unsigned long flags;
+	struct microp_led_data *ldata =
+		container_of(work, struct microp_led_data, brightness_work);
+	struct led_classdev *led_cdev = &ldata->ldev;
+
+	struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
+	struct microp_i2c_client_data *cdata = i2c_get_clientdata(client);
+
+
+	uint8_t data[4] = {0, 0, 0};
+	int ret = 0;
+	enum led_brightness brightness;
+	uint8_t value;
+
+
+	spin_lock_irqsave(&ldata->brightness_lock, flags);
+	brightness = ldata->brightness;
+	spin_unlock_irqrestore(&ldata->brightness_lock, flags);
+
+	value = brightness >= 255 ? 0x20 : 0;
+
+	/* avoid a flicker that can occur when writing the same value */
+	if (cdata->button_led_value == value)
+		return;
+	cdata->button_led_value = value;
+
+	/* in 40ms */
+	data[0] = 0x05;
+	/* duty cycle 0-255 */
+	data[1] = value;
+	/* bit2 == change brightness */
+	data[3] = 0x04;
+
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_BUTTONS_LED_CTRL,
+			      data, 4);
+	if (ret < 0)
+		dev_err(&client->dev, "%s failed on set buttons\n", __func__);
+}
+
+static void microp_led_jogball_brightness_set_work(struct work_struct *work)
+{
+	unsigned long flags;
+	struct microp_led_data *ldata =
+		container_of(work, struct microp_led_data, brightness_work);
+	struct led_classdev *led_cdev = &ldata->ldev;
+
+	struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
+	uint8_t data[3] = {0, 0, 0};
+	int ret = 0;
+	enum led_brightness brightness;
+
+	spin_lock_irqsave(&ldata->brightness_lock, flags);
+	brightness = ldata->brightness;
+	spin_unlock_irqrestore(&ldata->brightness_lock, flags);
+
+	switch (brightness) {
+	case 0:
+		data[0] = 0;
+		break;
+	case 3:
+		data[0] = 1;
+		data[1] = data[2] = 0xFF;
+		break;
+	case 7:
+		data[0] = 2;
+		data[1] = 0;
+		data[2] = 60;
+		break;
+	default:
+		dev_warn(&client->dev, "%s: unknown value: %d\n",
+			__func__, brightness);
+		break;
+	}
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_JOGBALL_LED_MODE,
+			      data, 3);
+	if (ret < 0)
+		dev_err(&client->dev, "%s failed on set jogball mode:0x%2.2X\n",
+				__func__, data[0]);
+}
+
+/*
+ * Light Sensor Support
+ */
+static int microp_i2c_auto_backlight_mode(struct i2c_client *client,
+					    uint8_t enabled)
+{
+	uint8_t data[2];
+	int ret = 0;
+
+	data[0] = 0;
+	if (enabled)
+		data[1] = 1;
+	else
+		data[1] = 0;
+
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_AUTO_BL_CTL, data, 2);
+	if (ret != 0)
+		pr_err("%s: set auto light sensor fail\n", __func__);
+
+	return ret;
+}
+
+static int lightsensor_enable(void)
+{
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	int ret;
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	if (cdata->microp_is_suspend) {
+		pr_err("%s: abort, uP is going to suspend after #\n",
+		       __func__);
+		return -EIO;
+	}
+
+	disable_irq(client->irq);
+	ret = microp_i2c_auto_backlight_mode(client, 1);
+	if (ret < 0) {
+		pr_err("%s: set auto light sensor fail\n", __func__);
+		enable_irq(client->irq);
+		return ret;
+	}
+
+	cdata->auto_backlight_enabled = 1;
+	/* TEMPORARY HACK: schedule a deferred light sensor read
+	 * to work around sensor manager race condition
+	 */
+	schedule_delayed_work(&cdata->ls_read_work, LS_READ_DELAY);
+	schedule_work(&cdata->work.work);
+
+	return 0;
+}
+
+static int lightsensor_disable(void)
+{
+	/* update trigger data when done */
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	int ret;
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	if (cdata->microp_is_suspend) {
+		pr_err("%s: abort, uP is going to suspend after #\n",
+		       __func__);
+		return -EIO;
+	}
+
+	cancel_delayed_work(&cdata->ls_read_work);
+
+	ret = microp_i2c_auto_backlight_mode(client, 0);
+	if (ret < 0)
+		pr_err("%s: disable auto light sensor fail\n",
+		       __func__);
+	else
+		cdata->auto_backlight_enabled = 0;
+	return 0;
+}
+
+static int microp_lightsensor_read(uint16_t *adc_value,
+					  uint8_t *adc_level)
+{
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	uint8_t i;
+	int ret;
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	ret = microp_read_adc(MICROP_LSENSOR_ADC_CHAN, adc_value);
+	if (ret != 0)
+		return -1;
+
+	if (*adc_value > 0x3FF) {
+		pr_warning("%s: get wrong value: 0x%X\n",
+			__func__, *adc_value);
+		return -1;
+	} else {
+		if (!cdata->als_calibrating) {
+			*adc_value = *adc_value
+				* cdata->als_gadc / cdata->als_kadc;
+			if (*adc_value > 0x3FF)
+				*adc_value = 0x3FF;
+		}
+
+		*adc_level = ARRAY_SIZE(lsensor_adc_table) - 1;
+		for (i = 0; i < ARRAY_SIZE(lsensor_adc_table); i++) {
+			if (*adc_value <= lsensor_adc_table[i]) {
+				*adc_level = i;
+				break;
+			}
+		}
+		pr_debug("%s: ADC value: 0x%X, level: %d #\n",
+				__func__, *adc_value, *adc_level);
+	}
+
+	return 0;
+}
+
+static ssize_t microp_i2c_lightsensor_adc_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	uint8_t adc_level = 0;
+	uint16_t adc_value = 0;
+	int ret;
+
+	ret = microp_lightsensor_read(&adc_value, &adc_level);
+
+	ret = sprintf(buf, "ADC[0x%03X] => level %d\n", adc_value, adc_level);
+
+	return ret;
+}
+
+static DEVICE_ATTR(ls_adc, 0644, microp_i2c_lightsensor_adc_show, NULL);
+
+static ssize_t microp_i2c_ls_auto_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client;
+	uint8_t data[2] = {0, 0};
+	int ret;
+
+	client = to_i2c_client(dev);
+
+	i2c_read_block(client, MICROP_I2C_RCMD_SPI_BL_STATUS, data, 2);
+	ret = sprintf(buf, "Light sensor Auto = %d, SPI enable = %d\n",
+			data[0], data[1]);
+
+	return ret;
+}
+
+static ssize_t microp_i2c_ls_auto_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	uint8_t enable = 0;
+	int ls_auto;
+
+	ls_auto = -1;
+	sscanf(buf, "%d", &ls_auto);
+
+	if (ls_auto != 0 && ls_auto != 1 && ls_auto != ALS_CALIBRATE_MODE)
+		return -EINVAL;
+
+	client = to_i2c_client(dev);
+	cdata = i2c_get_clientdata(client);
+
+	if (ls_auto) {
+		enable = 1;
+		cdata->als_calibrating = (ls_auto == ALS_CALIBRATE_MODE) ? 1 : 0;
+		cdata->auto_backlight_enabled = 1;
+	} else {
+		enable = 0;
+		cdata->als_calibrating = 0;
+		cdata->auto_backlight_enabled = 0;
+	}
+
+	microp_i2c_auto_backlight_mode(client, enable);
+
+	return count;
+}
+
+static DEVICE_ATTR(ls_auto, 0644,  microp_i2c_ls_auto_show,
+			microp_i2c_ls_auto_store);
+
+DEFINE_MUTEX(api_lock);
+static int lightsensor_opened;
+
+static int lightsensor_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	pr_debug("%s\n", __func__);
+	mutex_lock(&api_lock);
+	if (lightsensor_opened) {
+		pr_err("%s: already opened\n", __func__);
+		rc = -EBUSY;
+	}
+	lightsensor_opened = 1;
+	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static int lightsensor_release(struct inode *inode, struct file *file)
+{
+	pr_debug("%s\n", __func__);
+	mutex_lock(&api_lock);
+	lightsensor_opened = 0;
+	mutex_unlock(&api_lock);
+	return 0;
+}
+
+static long lightsensor_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	int rc, val;
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+
+	mutex_lock(&api_lock);
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	pr_debug("%s cmd %d\n", __func__, _IOC_NR(cmd));
+
+	switch (cmd) {
+	case LIGHTSENSOR_IOCTL_ENABLE:
+		if (get_user(val, (unsigned long __user *)arg)) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = val ? lightsensor_enable() : lightsensor_disable();
+		break;
+	case LIGHTSENSOR_IOCTL_GET_ENABLED:
+		val = cdata->auto_backlight_enabled;
+		pr_debug("%s enabled %d\n", __func__, val);
+		rc = put_user(val, (unsigned long __user *)arg);
+		break;
+	default:
+		pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd));
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static struct file_operations lightsensor_fops = {
+	.owner = THIS_MODULE,
+	.open = lightsensor_open,
+	.release = lightsensor_release,
+	.unlocked_ioctl = lightsensor_ioctl
+};
+
+struct miscdevice lightsensor_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "lightsensor",
+	.fops = &lightsensor_fops
+};
+
+/*
+ * G-sensor
+ */
+static int microp_spi_enable(uint8_t on)
+{
+	struct i2c_client *client;
+	int ret;
+
+	client = private_microp_client;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_SPI_EN, &on, 1);
+	if (ret < 0) {
+		dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
+		return ret;
+	}
+	msleep(10);
+	return ret;
+}
+
+static int gsensor_read_reg(uint8_t reg, uint8_t *data)
+{
+	struct i2c_client *client;
+	int ret;
+	uint8_t tmp[2];
+
+	client = private_microp_client;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GSENSOR_REG_DATA_REQ,
+			      &reg, 1);
+	if (ret < 0) {
+		dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
+		return ret;
+	}
+	msleep(10);
+
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_REG_DATA, tmp, 2);
+	if (ret < 0) {
+		dev_err(&client->dev,"%s: i2c_read_block fail\n", __func__);
+		return ret;
+	}
+	*data = tmp[1];
+	return ret;
+}
+
+static int gsensor_write_reg(uint8_t reg, uint8_t data)
+{
+	struct i2c_client *client;
+	int ret;
+	uint8_t tmp[2];
+
+	client = private_microp_client;
+
+	tmp[0] = reg;
+	tmp[1] = data;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GSENSOR_REG, tmp, 2);
+	if (ret < 0) {
+		dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int gsensor_read_acceleration(short *buf)
+{
+	struct i2c_client *client;
+	int ret;
+	uint8_t tmp[6];
+	struct microp_i2c_client_data *cdata;
+
+	client = private_microp_client;
+
+	cdata = i2c_get_clientdata(client);
+
+	tmp[0] = 1;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GSENSOR_DATA_REQ,
+			      tmp, 1);
+	if (ret < 0) {
+		dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
+		return ret;
+	}
+
+	msleep(10);
+
+	if (cdata->version <= 0x615) {
+		/*
+		 * Note the data is a 10bit signed value from the chip.
+		*/
+		ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_X_DATA,
+				     tmp, 2);
+		if (ret < 0) {
+			dev_err(&client->dev, "%s: i2c_read_block fail\n",
+				__func__);
+			return ret;
+		}
+		buf[0] = (short)(tmp[0] << 8 | tmp[1]);
+		buf[0] >>= 6;
+
+		ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_Y_DATA,
+				     tmp, 2);
+		if (ret < 0) {
+			dev_err(&client->dev, "%s: i2c_read_block fail\n",
+				__func__);
+			return ret;
+		}
+		buf[1] = (short)(tmp[0] << 8 | tmp[1]);
+		buf[1] >>= 6;
+
+		ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_Z_DATA,
+				     tmp, 2);
+		if (ret < 0) {
+			dev_err(&client->dev, "%s: i2c_read_block fail\n",
+				__func__);
+			return ret;
+		}
+		buf[2] = (short)(tmp[0] << 8 | tmp[1]);
+		buf[2] >>= 6;
+	} else {
+		ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_DATA,
+				     tmp, 6);
+		if (ret < 0) {
+			dev_err(&client->dev, "%s: i2c_read_block fail\n",
+				__func__);
+			return ret;
+		}
+		buf[0] = (short)(tmp[0] << 8 | tmp[1]);
+		buf[0] >>= 6;
+		buf[1] = (short)(tmp[2] << 8 | tmp[3]);
+		buf[1] >>= 6;
+		buf[2] = (short)(tmp[4] << 8 | tmp[5]);
+		buf[2] >>= 6;
+	}
+
+#ifdef DEBUG_BMA150
+	/* Log this to debugfs */
+	gsensor_log_status(ktime_get(), buf[0], buf[1], buf[2]);
+#endif
+	return 1;
+}
+
+static int gsensor_init_hw(void)
+{
+	uint8_t reg;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+
+	microp_spi_enable(1);
+
+	ret = gsensor_read_reg(RANGE_BWIDTH_REG, &reg);
+	if (ret < 0 )
+		return -EIO;
+	reg &= 0xe0;
+	ret = gsensor_write_reg(RANGE_BWIDTH_REG, reg);
+	if (ret < 0 )
+		return -EIO;
+
+	ret = gsensor_read_reg(SMB150_CONF2_REG, &reg);
+	if (ret < 0 )
+		return -EIO;
+	reg |= (1 << 3);
+	ret = gsensor_write_reg(SMB150_CONF2_REG, reg);
+
+	return ret;
+}
+
+static int bma150_set_mode(char mode)
+{
+	uint8_t reg;
+	int ret;
+
+	pr_debug("%s mode = %d\n", __func__, mode);
+	if (mode == BMA_MODE_NORMAL)
+		microp_spi_enable(1);
+
+
+	ret = gsensor_read_reg(SMB150_CTRL_REG, &reg);
+	if (ret < 0 )
+		return -EIO;
+	reg = (reg & 0xfe) | mode;
+	ret = gsensor_write_reg(SMB150_CTRL_REG, reg);
+
+	if (mode == BMA_MODE_SLEEP)
+		microp_spi_enable(0);
+
+	return ret;
+}
+static int gsensor_read(uint8_t *data)
+{
+	int ret;
+	uint8_t reg = data[0];
+
+	ret = gsensor_read_reg(reg, &data[1]);
+	pr_debug("%s reg = %x data = %x\n", __func__, reg, data[1]);
+	return ret;
+}
+
+static int gsensor_write(uint8_t *data)
+{
+	int ret;
+	uint8_t reg = data[0];
+
+	pr_debug("%s reg = %x data = %x\n", __func__, reg, data[1]);
+	ret = gsensor_write_reg(reg, data[1]);
+	return ret;
+}
+
+static int bma150_open(struct inode *inode, struct file *file)
+{
+	pr_debug("%s\n", __func__);
+	return nonseekable_open(inode, file);
+}
+
+static int bma150_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int bma150_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	char rwbuf[8];
+	int ret = -1;
+	short buf[8], temp;
+
+	switch (cmd) {
+	case BMA_IOCTL_READ:
+	case BMA_IOCTL_WRITE:
+	case BMA_IOCTL_SET_MODE:
+		if (copy_from_user(&rwbuf, argp, sizeof(rwbuf)))
+			return -EFAULT;
+		break;
+	case BMA_IOCTL_READ_ACCELERATION:
+		if (copy_from_user(&buf, argp, sizeof(buf)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	switch (cmd) {
+	case BMA_IOCTL_INIT:
+		ret = gsensor_init_hw();
+		if (ret < 0)
+			return ret;
+		break;
+
+	case BMA_IOCTL_READ:
+		if (rwbuf[0] < 1)
+			return -EINVAL;
+		ret = gsensor_read(rwbuf);
+		if (ret < 0)
+			return ret;
+		break;
+	case BMA_IOCTL_WRITE:
+		if (rwbuf[0] < 2)
+			return -EINVAL;
+		ret = gsensor_write(rwbuf);
+		if (ret < 0)
+			return ret;
+		break;
+	case BMA_IOCTL_READ_ACCELERATION:
+		ret = gsensor_read_acceleration(&buf[0]);
+		if (ret < 0)
+			return ret;
+		break;
+	case BMA_IOCTL_SET_MODE:
+		bma150_set_mode(rwbuf[0]);
+		break;
+	case BMA_IOCTL_GET_INT:
+		temp = 0;
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	switch (cmd) {
+	case BMA_IOCTL_READ:
+		if (copy_to_user(argp, &rwbuf, sizeof(rwbuf)))
+			return -EFAULT;
+		break;
+	case BMA_IOCTL_READ_ACCELERATION:
+		if (copy_to_user(argp, &buf, sizeof(buf)))
+			return -EFAULT;
+		break;
+	case BMA_IOCTL_GET_INT:
+		if (copy_to_user(argp, &temp, sizeof(temp)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static struct file_operations bma_fops = {
+	.owner = THIS_MODULE,
+	.open = bma150_open,
+	.release = bma150_release,
+	.ioctl = bma150_ioctl,
+};
+
+static struct miscdevice spi_bma_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = BMA150_G_SENSOR_NAME,
+	.fops = &bma_fops,
+};
+
+/*
+ * Interrupt
+ */
+static irqreturn_t microp_i2c_intr_irq_handler(int irq, void *dev_id)
+{
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+
+	client = to_i2c_client(dev_id);
+	cdata = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "intr_irq_handler\n");
+
+	disable_irq_nosync(client->irq);
+	schedule_work(&cdata->work.work);
+	return IRQ_HANDLED;
+}
+
+static void microp_i2c_intr_work_func(struct work_struct *work)
+{
+	struct microp_i2c_work *up_work;
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	uint8_t data[3], adc_level;
+	uint16_t intr_status = 0, adc_value, gpi_status = 0;
+	int keycode = 0, ret = 0;
+
+	up_work = container_of(work, struct microp_i2c_work, work);
+	client = up_work->client;
+	cdata = i2c_get_clientdata(client);
+
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_GPI_INT_STATUS, data, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: read interrupt status fail\n",
+			 __func__);
+	}
+
+	intr_status = data[0]<<8 | data[1];
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GPI_INT_STATUS_CLR,
+			      data, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: clear interrupt status fail\n",
+			 __func__);
+	}
+	pr_debug("intr_status=0x%02x\n", intr_status);
+
+	if ((intr_status & IRQ_LSENSOR) || cdata->force_light_sensor_read) {
+		ret = microp_lightsensor_read(&adc_value, &adc_level);
+		if (cdata->force_light_sensor_read) {
+			/* report an invalid value first to ensure we trigger an event
+			 * when adc_level is zero.
+			 */
+			input_report_abs(cdata->ls_input_dev, ABS_MISC, -1);
+			input_sync(cdata->ls_input_dev);
+			cdata->force_light_sensor_read = 0;
+		}
+		input_report_abs(cdata->ls_input_dev, ABS_MISC, (int)adc_level);
+		input_sync(cdata->ls_input_dev);
+	}
+
+	if (intr_status & IRQ_SDCARD) {
+		microp_read_gpi_status(client, &gpi_status);
+		mahimahi_microp_sdslot_update_status(gpi_status);
+	}
+
+	if (intr_status & IRQ_HEADSETIN) {
+		cdata->is_hpin_pin_stable = 0;
+		wake_lock_timeout(&microp_i2c_wakelock, 3*HZ);
+		if (!cdata->headset_is_in)
+			schedule_delayed_work(&cdata->hpin_debounce_work,
+					msecs_to_jiffies(500));
+		else
+			schedule_delayed_work(&cdata->hpin_debounce_work,
+					msecs_to_jiffies(300));
+	}
+	if (intr_status & IRQ_REMOTEKEY) {
+		if ((get_remote_keycode(&keycode) == 0) &&
+			(cdata->is_hpin_pin_stable)) {
+			htc_35mm_key_event(keycode, &cdata->is_hpin_pin_stable);
+		}
+	}
+
+	enable_irq(client->irq);
+}
+
+static void ls_read_do_work(struct work_struct *work)
+{
+	struct i2c_client *client = private_microp_client;
+	struct microp_i2c_client_data *cdata = i2c_get_clientdata(client);
+
+	/* force a light sensor reading */
+	disable_irq(client->irq);
+	cdata->force_light_sensor_read = 1;
+	schedule_work(&cdata->work.work);
+}
+
+static int microp_function_initialize(struct i2c_client *client)
+{
+	struct microp_i2c_client_data *cdata;
+	uint8_t data[20];
+	uint16_t stat, interrupts = 0;
+	int i;
+	int ret;
+	struct led_classdev *led_cdev;
+
+	cdata = i2c_get_clientdata(client);
+
+	/* Light Sensor */
+	if (als_kadc >> 16 == ALS_CALIBRATED)
+		cdata->als_kadc = als_kadc & 0xFFFF;
+	else {
+		cdata->als_kadc = 0;
+		pr_info("%s: no ALS calibrated\n", __func__);
+	}
+
+	if (cdata->als_kadc && golden_adc) {
+		cdata->als_kadc =
+			(cdata->als_kadc > 0 && cdata->als_kadc < 0x400)
+			? cdata->als_kadc : golden_adc;
+		cdata->als_gadc =
+			(golden_adc > 0)
+			? golden_adc : cdata->als_kadc;
+	} else {
+		cdata->als_kadc = 1;
+		cdata->als_gadc = 1;
+	}
+	pr_info("%s: als_kadc=0x%x, als_gadc=0x%x\n",
+		__func__, cdata->als_kadc, cdata->als_gadc);
+
+	for (i = 0; i < 10; i++) {
+		data[i] = (uint8_t)(lsensor_adc_table[i]
+			* cdata->als_kadc / cdata->als_gadc >> 8);
+		data[i + 10] = (uint8_t)(lsensor_adc_table[i]
+			* cdata->als_kadc / cdata->als_gadc);
+	}
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_ADC_TABLE, data, 20);
+	if (ret)
+		goto exit;
+
+	ret = gpio_request(MAHIMAHI_GPIO_LS_EN_N, "microp_i2c");
+	if (ret < 0) {
+		dev_err(&client->dev, "failed on request gpio ls_on\n");
+		goto exit;
+	}
+	ret = gpio_direction_output(MAHIMAHI_GPIO_LS_EN_N, 0);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed on gpio_direction_output"
+				"ls_on\n");
+		goto err_gpio_ls;
+	}
+	cdata->light_sensor_enabled = 1;
+
+	/* Headset */
+	for (i = 0; i < 6; i++) {
+		data[i] = (uint8_t)(remote_key_adc_table[i] >> 8);
+		data[i + 6] = (uint8_t)(remote_key_adc_table[i]);
+	}
+	ret = i2c_write_block(client,
+		MICROP_I2C_WCMD_REMOTEKEY_TABLE, data, 12);
+	if (ret)
+		goto exit;
+
+	INIT_DELAYED_WORK(
+		&cdata->hpin_debounce_work, hpin_debounce_do_work);
+	INIT_DELAYED_WORK(
+		&cdata->ls_read_work, ls_read_do_work);
+
+	/* SD Card */
+	interrupts |= IRQ_SDCARD;
+
+	/* set LED initial state */
+	for (i = 0; i < BLUE_LED; i++) {
+		led_cdev = &cdata->leds[i].ldev;
+		microp_i2c_write_led_mode(client, led_cdev, 0, 0xffff);
+	}
+
+	/* enable the interrupts */
+	ret = microp_interrupt_enable(client, interrupts);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: failed to enable gpi irqs\n",
+			__func__);
+		goto err_irq_en;
+	}
+
+	microp_read_gpi_status(client, &stat);
+	mahimahi_microp_sdslot_update_status(stat);
+
+	return 0;
+
+err_irq_en:
+err_gpio_ls:
+	gpio_free(MAHIMAHI_GPIO_LS_EN_N);
+exit:
+	return ret;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void microp_early_suspend(struct early_suspend *h)
+{
+	struct microp_i2c_client_data *cdata;
+	struct i2c_client *client = private_microp_client;
+	int ret;
+
+	if (!client) {
+		pr_err("%s: dataset: client is empty\n", __func__);
+		return;
+	}
+	cdata = i2c_get_clientdata(client);
+
+	cdata->microp_is_suspend = 1;
+
+	disable_irq(client->irq);
+	ret = cancel_work_sync(&cdata->work.work);
+	if (ret != 0) {
+		enable_irq(client->irq);
+	}
+
+	if (cdata->auto_backlight_enabled)
+		microp_i2c_auto_backlight_mode(client, 0);
+	if (cdata->light_sensor_enabled == 1) {
+		gpio_set_value(MAHIMAHI_GPIO_LS_EN_N, 1);
+		cdata->light_sensor_enabled = 0;
+	}
+}
+
+void microp_early_resume(struct early_suspend *h)
+{
+	struct i2c_client *client = private_microp_client;
+	struct microp_i2c_client_data *cdata;
+
+	if (!client) {
+		pr_err("%s: dataset: client is empty\n", __func__);
+		return;
+	}
+	cdata = i2c_get_clientdata(client);
+
+	gpio_set_value(MAHIMAHI_GPIO_LS_EN_N, 0);
+	cdata->light_sensor_enabled = 1;
+
+	if (cdata->auto_backlight_enabled)
+		microp_i2c_auto_backlight_mode(client, 1);
+
+	cdata->microp_is_suspend = 0;
+	enable_irq(client->irq);
+}
+#endif
+
+static int microp_i2c_suspend(struct i2c_client *client,
+	pm_message_t mesg)
+{
+	return 0;
+}
+
+static int microp_i2c_resume(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct {
+	const char *name;
+	void (*led_set_work)(struct work_struct *);
+	struct device_attribute **attrs;
+	int attr_cnt;
+} microp_leds[] = {
+	[GREEN_LED] = {
+		.name		= "green",
+		.led_set_work   = microp_led_brightness_set_work,
+		.attrs		= green_amber_attrs,
+		.attr_cnt	= ARRAY_SIZE(green_amber_attrs)
+	},
+	[AMBER_LED] = {
+		.name		= "amber",
+		.led_set_work   = microp_led_brightness_set_work,
+		.attrs		= green_amber_attrs,
+		.attr_cnt	= ARRAY_SIZE(green_amber_attrs)
+	},
+	[RED_LED] = {
+		.name		= "red",
+		.led_set_work   = microp_led_brightness_set_work,
+		.attrs		= green_amber_attrs,
+		.attr_cnt	= ARRAY_SIZE(green_amber_attrs)
+	},
+	[BLUE_LED] = {
+		.name		= "blue",
+		.led_set_work   = microp_led_brightness_set_work,
+		.attrs		= green_amber_attrs,
+		.attr_cnt	= ARRAY_SIZE(green_amber_attrs)
+	},
+	[JOGBALL_LED] = {
+		.name		= "jogball-backlight",
+		.led_set_work	= microp_led_jogball_brightness_set_work,
+		.attrs		= jogball_attrs,
+		.attr_cnt	= ARRAY_SIZE(jogball_attrs)
+	},
+	[BUTTONS_LED] = {
+		.name		= "button-backlight",
+		.led_set_work	= microp_led_buttons_brightness_set_work
+	},
+};
+
+static int microp_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct microp_i2c_client_data *cdata;
+	uint8_t data[6];
+	int ret;
+	int i;
+	int j;
+
+	private_microp_client = client;
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_VERSION, data, 2);
+	if (ret || !(data[0] && data[1])) {
+		ret = -ENODEV;
+		dev_err(&client->dev, "failed on get microp version\n");
+		goto err_exit;
+	}
+	dev_info(&client->dev, "microp version [%02X][%02X]\n",
+		  data[0], data[1]);
+
+	ret = gpio_request(MAHIMAHI_GPIO_UP_RESET_N, "microp_i2c_wm");
+	if (ret < 0) {
+		dev_err(&client->dev, "failed on request gpio reset\n");
+		goto err_exit;
+	}
+	ret = gpio_direction_output(MAHIMAHI_GPIO_UP_RESET_N, 1);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			 "failed on gpio_direction_output reset\n");
+		goto err_gpio_reset;
+	}
+
+	cdata = kzalloc(sizeof(struct microp_i2c_client_data), GFP_KERNEL);
+	if (!cdata) {
+		ret = -ENOMEM;
+		dev_err(&client->dev, "failed on allocat cdata\n");
+		goto err_cdata;
+	}
+
+	i2c_set_clientdata(client, cdata);
+	cdata->version = data[0] << 8 | data[1];
+	cdata->microp_is_suspend = 0;
+	cdata->auto_backlight_enabled = 0;
+	cdata->light_sensor_enabled = 0;
+
+	wake_lock_init(&microp_i2c_wakelock, WAKE_LOCK_SUSPEND,
+			 "microp_i2c_present");
+
+	/* Light Sensor */
+	ret = device_create_file(&client->dev, &dev_attr_ls_adc);
+	ret = device_create_file(&client->dev, &dev_attr_ls_auto);
+	cdata->ls_input_dev = input_allocate_device();
+	if (!cdata->ls_input_dev) {
+		pr_err("%s: could not allocate input device\n", __func__);
+		ret = -ENOMEM;
+		goto err_request_input_dev;
+	}
+	cdata->ls_input_dev->name = "lightsensor-level";
+	set_bit(EV_ABS, cdata->ls_input_dev->evbit);
+	input_set_abs_params(cdata->ls_input_dev, ABS_MISC, 0, 9, 0, 0);
+
+	ret = input_register_device(cdata->ls_input_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: can not register input device\n",
+				__func__);
+		goto err_register_input_dev;
+	}
+
+	ret = misc_register(&lightsensor_misc);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: can not register misc device\n",
+				__func__);
+		goto err_register_misc_register;
+	}
+
+	/* LEDs */
+	ret = 0;
+	for (i = 0; i < ARRAY_SIZE(microp_leds) && !ret; ++i) {
+		struct microp_led_data *ldata = &cdata->leds[i];
+
+		ldata->type = i;
+		ldata->ldev.name = microp_leds[i].name;
+		ldata->ldev.brightness_set = microp_brightness_set;
+		mutex_init(&ldata->led_data_mutex);
+		INIT_WORK(&ldata->brightness_work, microp_leds[i].led_set_work);
+		spin_lock_init(&ldata->brightness_lock);
+		ret = led_classdev_register(&client->dev, &ldata->ldev);
+		if (ret) {
+			ldata->ldev.name = NULL;
+			break;
+		}
+
+		for (j = 0; j < microp_leds[i].attr_cnt && !ret; ++j)
+			ret = device_create_file(ldata->ldev.dev,
+						 microp_leds[i].attrs[j]);
+	}
+	if (ret) {
+		dev_err(&client->dev, "failed to add leds\n");
+		goto err_add_leds;
+	}
+
+	/* Headset */
+	cdata->headset_is_in = 0;
+	cdata->is_hpin_pin_stable = 1;
+	platform_device_register(&mahimahi_h35mm);
+
+	ret = device_create_file(&client->dev, &dev_attr_key_adc);
+
+	/* G-sensor */
+	ret = misc_register(&spi_bma_device);
+	if (ret < 0) {
+		pr_err("%s: init bma150 misc_register fail\n",
+				__func__);
+		goto err_register_bma150;
+	}
+#ifdef DEBUG_BMA150
+	debugfs_create_file("gsensor_log", 0444, NULL, NULL, &gsensor_log_fops);
+#endif
+	/* Setup IRQ handler */
+	INIT_WORK(&cdata->work.work, microp_i2c_intr_work_func);
+	cdata->work.client = client;
+
+	ret = request_irq(client->irq,
+			microp_i2c_intr_irq_handler,
+			IRQF_TRIGGER_LOW,
+			"microp_interrupt",
+			&client->dev);
+	if (ret) {
+		dev_err(&client->dev, "request_irq failed\n");
+		goto err_intr;
+	}
+	ret = set_irq_wake(client->irq, 1);
+	if (ret) {
+		dev_err(&client->dev, "set_irq_wake failed\n");
+		goto err_intr;
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	if (cdata->enable_early_suspend) {
+		cdata->early_suspend.level =
+				EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+		cdata->early_suspend.suspend = microp_early_suspend;
+		cdata->early_suspend.resume = microp_early_resume;
+		register_early_suspend(&cdata->early_suspend);
+	}
+#endif
+
+	ret = microp_function_initialize(client);
+	if (ret) {
+		dev_err(&client->dev, "failed on microp function initialize\n");
+		goto err_fun_init;
+	}
+
+	return 0;
+
+err_fun_init:
+err_intr:
+	misc_deregister(&spi_bma_device);
+
+err_register_bma150:
+	platform_device_unregister(&mahimahi_h35mm);
+	device_remove_file(&client->dev, &dev_attr_key_adc);
+
+err_add_leds:
+	for (i = 0; i < ARRAY_SIZE(microp_leds); ++i) {
+		if (!cdata->leds[i].ldev.name)
+			continue;
+		led_classdev_unregister(&cdata->leds[i].ldev);
+		for (j = 0; j < microp_leds[i].attr_cnt; ++j)
+			device_remove_file(cdata->leds[i].ldev.dev,
+					   microp_leds[i].attrs[j]);
+	}
+
+	misc_deregister(&lightsensor_misc);
+
+err_register_misc_register:
+	input_unregister_device(cdata->ls_input_dev);
+
+err_register_input_dev:
+	input_free_device(cdata->ls_input_dev);
+
+err_request_input_dev:
+	wake_lock_destroy(&microp_i2c_wakelock);
+	device_remove_file(&client->dev, &dev_attr_ls_adc);
+	device_remove_file(&client->dev, &dev_attr_ls_auto);
+	kfree(cdata);
+	i2c_set_clientdata(client, NULL);
+
+err_cdata:
+err_gpio_reset:
+	gpio_free(MAHIMAHI_GPIO_UP_RESET_N);
+err_exit:
+	return ret;
+}
+
+static int __devexit microp_i2c_remove(struct i2c_client *client)
+{
+	struct microp_i2c_client_data *cdata;
+	int i;
+	int j;
+
+	cdata = i2c_get_clientdata(client);
+
+	for (i = 0; i < ARRAY_SIZE(microp_leds); ++i) {
+		struct microp_led_data *ldata = &cdata->leds[i];
+		cancel_work_sync(&ldata->brightness_work);
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	if (cdata->enable_early_suspend) {
+		unregister_early_suspend(&cdata->early_suspend);
+	}
+#endif
+
+	for (i = 0; i < ARRAY_SIZE(microp_leds); ++i) {
+		if (!cdata->leds[i].ldev.name)
+			continue;
+		led_classdev_unregister(&cdata->leds[i].ldev);
+		for (j = 0; j < microp_leds[i].attr_cnt; ++j)
+			device_remove_file(cdata->leds[i].ldev.dev,
+					   microp_leds[i].attrs[j]);
+	}
+
+	free_irq(client->irq, &client->dev);
+
+	gpio_free(MAHIMAHI_GPIO_UP_RESET_N);
+
+	misc_deregister(&lightsensor_misc);
+	input_unregister_device(cdata->ls_input_dev);
+	input_free_device(cdata->ls_input_dev);
+	device_remove_file(&client->dev, &dev_attr_ls_adc);
+	device_remove_file(&client->dev, &dev_attr_key_adc);
+	device_remove_file(&client->dev, &dev_attr_ls_auto);
+
+	platform_device_unregister(&mahimahi_h35mm);
+
+	/* G-sensor */
+	misc_deregister(&spi_bma_device);
+
+	kfree(cdata);
+
+	return 0;
+}
+
+#define ATAG_ALS	0x5441001b
+static int __init parse_tag_als_kadc(const struct tag *tags)
+{
+	int found = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_ALS) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found)
+		als_kadc = t->u.revision.rev;
+	pr_debug("%s: als_kadc = 0x%x\n", __func__, als_kadc);
+	return 0;
+}
+__tagtable(ATAG_ALS, parse_tag_als_kadc);
+
+static const struct i2c_device_id microp_i2c_id[] = {
+	{ MICROP_I2C_NAME, 0 },
+	{ }
+};
+
+static struct i2c_driver microp_i2c_driver = {
+	.driver = {
+		   .name = MICROP_I2C_NAME,
+		   },
+	.id_table = microp_i2c_id,
+	.probe = microp_i2c_probe,
+	.suspend = microp_i2c_suspend,
+	.resume = microp_i2c_resume,
+	.remove = __devexit_p(microp_i2c_remove),
+};
+
+
+static int __init microp_i2c_init(void)
+{
+	return i2c_add_driver(&microp_i2c_driver);
+}
+
+static void __exit microp_i2c_exit(void)
+{
+	i2c_del_driver(&microp_i2c_driver);
+}
+
+module_init(microp_i2c_init);
+module_exit(microp_i2c_exit);
+
+MODULE_AUTHOR("Eric Olsen <eolsen@android.com>");
+MODULE_DESCRIPTION("MicroP I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-mahimahi-mmc.c b/arch/arm/mach-msm/board-mahimahi-mmc.c
new file mode 100644
index 0000000..78ed97f
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-mmc.c
@@ -0,0 +1,454 @@
+/* linux/arch/arm/mach-msm/board-mahimahi-mmc.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/platform_device.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+
+#include <mach/vreg.h>
+
+#include "board-mahimahi.h"
+#include "devices.h"
+#include "proc_comm.h"
+
+#undef MAHIMAHI_DEBUG_MMC
+
+static bool opt_disable_sdcard;
+static int __init mahimahi_disablesdcard_setup(char *str)
+{
+	opt_disable_sdcard = (bool)simple_strtol(str, NULL, 0);
+	return 1;
+}
+
+__setup("board_mahimahi.disable_sdcard=", mahimahi_disablesdcard_setup);
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for(n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+static uint32_t sdcard_on_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+};
+
+static uint32_t sdcard_off_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+};
+
+static struct vreg	*sdslot_vreg;
+static uint32_t		sdslot_vdd = 0xffffffff;
+static uint32_t		sdslot_vreg_enabled;
+
+static struct {
+	int mask;
+	int level;
+} mmc_vdd_table[] = {
+	{ MMC_VDD_165_195,	1800 },
+	{ MMC_VDD_20_21,	2050 },
+	{ MMC_VDD_21_22,	2150 },
+	{ MMC_VDD_22_23,	2250 },
+	{ MMC_VDD_23_24,	2350 },
+	{ MMC_VDD_24_25,	2450 },
+	{ MMC_VDD_25_26,	2550 },
+	{ MMC_VDD_26_27,	2650 },
+	{ MMC_VDD_27_28,	2750 },
+	{ MMC_VDD_28_29,	2850 },
+	{ MMC_VDD_29_30,	2950 },
+};
+
+static uint32_t mahimahi_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+	int i;
+	int ret;
+
+	if (vdd == sdslot_vdd)
+		return 0;
+
+	sdslot_vdd = vdd;
+
+	if (vdd == 0) {
+		config_gpio_table(sdcard_off_gpio_table,
+				  ARRAY_SIZE(sdcard_off_gpio_table));
+		vreg_disable(sdslot_vreg);
+		sdslot_vreg_enabled = 0;
+		return 0;
+	}
+
+	if (!sdslot_vreg_enabled) {
+		ret = vreg_enable(sdslot_vreg);
+		if (ret)
+			pr_err("%s: Error enabling vreg (%d)\n", __func__, ret);
+		config_gpio_table(sdcard_on_gpio_table,
+				  ARRAY_SIZE(sdcard_on_gpio_table));
+		sdslot_vreg_enabled = 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+		if (mmc_vdd_table[i].mask != (1 << vdd))
+			continue;
+		ret = vreg_set_level(sdslot_vreg, mmc_vdd_table[i].level);
+		if (ret)
+			pr_err("%s: Error setting level (%d)\n", __func__, ret);
+		return 0;
+	}
+
+	pr_err("%s: Invalid VDD (%d) specified\n", __func__, vdd);
+	return 0;
+}
+
+static uint32_t mahimahi_cdma_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+	if (!vdd == !sdslot_vdd)
+		return 0;
+
+	/* In CDMA version, the vdd of sdslot is not configurable, and it is
+	 * fixed in 2.85V by hardware design.
+	 */
+
+	sdslot_vdd = vdd ? MMC_VDD_28_29 : 0;
+
+	if (vdd) {
+		gpio_set_value(MAHIMAHI_CDMA_SD_2V85_EN, 1);
+		config_gpio_table(sdcard_on_gpio_table,
+				  ARRAY_SIZE(sdcard_on_gpio_table));
+	} else {
+		config_gpio_table(sdcard_off_gpio_table,
+				  ARRAY_SIZE(sdcard_off_gpio_table));
+		gpio_set_value(MAHIMAHI_CDMA_SD_2V85_EN, 0);
+	}
+
+	sdslot_vreg_enabled = !!vdd;
+
+	return 0;
+}
+
+static unsigned int mahimahi_sdslot_status_rev0(struct device *dev)
+{
+	return !gpio_get_value(MAHIMAHI_GPIO_SDMC_CD_REV0_N);
+}
+
+#define MAHIMAHI_MMC_VDD	(MMC_VDD_165_195 | MMC_VDD_20_21 | \
+				 MMC_VDD_21_22  | MMC_VDD_22_23 | \
+				 MMC_VDD_23_24 | MMC_VDD_24_25 | \
+				 MMC_VDD_25_26 | MMC_VDD_26_27 | \
+				 MMC_VDD_27_28 | MMC_VDD_28_29 | \
+				 MMC_VDD_29_30)
+
+int mahimahi_microp_sdslot_status_register(void (*cb)(int, void *), void *);
+unsigned int mahimahi_microp_sdslot_status(struct device *);
+
+static struct mmc_platform_data mahimahi_sdslot_data = {
+	.ocr_mask		= MAHIMAHI_MMC_VDD,
+	.status			= mahimahi_microp_sdslot_status,
+	.register_status_notify	= mahimahi_microp_sdslot_status_register,
+	.translate_vdd		= mahimahi_sdslot_switchvdd,
+};
+
+static uint32_t wifi_on_gpio_table[] = {
+	PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+	PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(152, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_4MA),  /* WLAN IRQ */
+};
+
+static uint32_t wifi_off_gpio_table[] = {
+	PCOM_GPIO_CFG(51, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(52, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(53, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(54, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+	PCOM_GPIO_CFG(55, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(56, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(152, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),  /* WLAN IRQ */
+};
+
+/* BCM4329 returns wrong sdio_vsn(1) when we read cccr,
+ * we use predefined value (sdio_vsn=2) here to initial sdio driver well
+ */
+static struct embedded_sdio_data mahimahi_wifi_emb_data = {
+	.cccr	= {
+		.sdio_vsn	= 2,
+		.multi_block	= 1,
+		.low_speed	= 0,
+		.wide_bus	= 0,
+		.high_power	= 1,
+		.high_speed	= 1,
+	},
+};
+
+static int mahimahi_wifi_cd = 0; /* WIFI virtual 'card detect' status */
+static void (*wifi_status_cb)(int card_present, void *dev_id);
+static void *wifi_status_cb_devid;
+
+static int mahimahi_wifi_status_register(
+			void (*callback)(int card_present, void *dev_id),
+			void *dev_id)
+{
+	if (wifi_status_cb)
+		return -EAGAIN;
+	wifi_status_cb = callback;
+	wifi_status_cb_devid = dev_id;
+	return 0;
+}
+
+static unsigned int mahimahi_wifi_status(struct device *dev)
+{
+	return mahimahi_wifi_cd;
+}
+
+static struct mmc_platform_data mahimahi_wifi_data = {
+	.ocr_mask		= MMC_VDD_28_29,
+	.built_in		= 1,
+	.status			= mahimahi_wifi_status,
+	.register_status_notify	= mahimahi_wifi_status_register,
+	.embedded_sdio		= &mahimahi_wifi_emb_data,
+};
+
+int mahimahi_wifi_set_carddetect(int val)
+{
+	pr_info("%s: %d\n", __func__, val);
+	mahimahi_wifi_cd = val;
+	if (wifi_status_cb) {
+		wifi_status_cb(val, wifi_status_cb_devid);
+	} else
+		pr_warning("%s: Nobody to notify\n", __func__);
+	return 0;
+}
+
+static int mahimahi_wifi_power_state;
+
+int mahimahi_wifi_power(int on)
+{
+	printk("%s: %d\n", __func__, on);
+
+	if (on) {
+		config_gpio_table(wifi_on_gpio_table,
+				  ARRAY_SIZE(wifi_on_gpio_table));
+		mdelay(50);
+	} else {
+		config_gpio_table(wifi_off_gpio_table,
+				  ARRAY_SIZE(wifi_off_gpio_table));
+	}
+
+	mdelay(100);
+	gpio_set_value(MAHIMAHI_GPIO_WIFI_SHUTDOWN_N, on); /* WIFI_SHUTDOWN */
+	mdelay(200);
+
+	mahimahi_wifi_power_state = on;
+	return 0;
+}
+
+static int mahimahi_wifi_reset_state;
+
+int mahimahi_wifi_reset(int on)
+{
+	printk("%s: do nothing\n", __func__);
+	mahimahi_wifi_reset_state = on;
+	return 0;
+}
+
+int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+		 unsigned int stat_irq, unsigned long stat_irq_flags);
+
+int __init mahimahi_init_mmc(unsigned int sys_rev, unsigned debug_uart)
+{
+	uint32_t id;
+
+	printk("%s()+\n", __func__);
+
+	/* initial WIFI_SHUTDOWN# */
+	id = PCOM_GPIO_CFG(MAHIMAHI_GPIO_WIFI_SHUTDOWN_N, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+	msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+
+	msm_add_sdcc(1, &mahimahi_wifi_data, 0, 0);
+
+	if (debug_uart) {
+		pr_info("%s: sdcard disabled due to debug uart\n", __func__);
+		goto done;
+	}
+	if (opt_disable_sdcard) {
+		pr_info("%s: sdcard disabled on cmdline\n", __func__);
+		goto done;
+	}
+
+	sdslot_vreg_enabled = 0;
+
+	if (is_cdma_version(sys_rev)) {
+		/* In the CDMA version, sdslot is supplied by a gpio. */
+		int rc = gpio_request(MAHIMAHI_CDMA_SD_2V85_EN, "sdslot_en");
+		if (rc < 0) {
+			pr_err("%s: gpio_request(%d) failed: %d\n", __func__,
+				MAHIMAHI_CDMA_SD_2V85_EN, rc);
+			return rc;
+		}
+		mahimahi_sdslot_data.translate_vdd = mahimahi_cdma_sdslot_switchvdd;
+	} else {
+		/* in UMTS version, sdslot is supplied by pmic */
+		sdslot_vreg = vreg_get(0, "gp6");
+		if (IS_ERR(sdslot_vreg))
+			return PTR_ERR(sdslot_vreg);
+	}
+
+	if (system_rev > 0)
+		msm_add_sdcc(2, &mahimahi_sdslot_data, 0, 0);
+	else {
+		mahimahi_sdslot_data.status = mahimahi_sdslot_status_rev0;
+		mahimahi_sdslot_data.register_status_notify = NULL;
+		set_irq_wake(MSM_GPIO_TO_INT(MAHIMAHI_GPIO_SDMC_CD_REV0_N), 1);
+		msm_add_sdcc(2, &mahimahi_sdslot_data,
+			     MSM_GPIO_TO_INT(MAHIMAHI_GPIO_SDMC_CD_REV0_N),
+			     IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE);
+	}
+
+done:
+	printk("%s()-\n", __func__);
+	return 0;
+}
+
+#if defined(MAHIMAHI_DEBUG_MMC) && defined(CONFIG_DEBUG_FS)
+
+static int mahimahimmc_dbg_wifi_reset_set(void *data, u64 val)
+{
+	mahimahi_wifi_reset((int) val);
+	return 0;
+}
+
+static int mahimahimmc_dbg_wifi_reset_get(void *data, u64 *val)
+{
+	*val = mahimahi_wifi_reset_state;
+	return 0;
+}
+
+static int mahimahimmc_dbg_wifi_cd_set(void *data, u64 val)
+{
+	mahimahi_wifi_set_carddetect((int) val);
+	return 0;
+}
+
+static int mahimahimmc_dbg_wifi_cd_get(void *data, u64 *val)
+{
+	*val = mahimahi_wifi_cd;
+	return 0;
+}
+
+static int mahimahimmc_dbg_wifi_pwr_set(void *data, u64 val)
+{
+	mahimahi_wifi_power((int) val);
+	return 0;
+}
+
+static int mahimahimmc_dbg_wifi_pwr_get(void *data, u64 *val)
+{
+	*val = mahimahi_wifi_power_state;
+	return 0;
+}
+
+static int mahimahimmc_dbg_sd_pwr_set(void *data, u64 val)
+{
+	mahimahi_sdslot_switchvdd(NULL, (unsigned int) val);
+	return 0;
+}
+
+static int mahimahimmc_dbg_sd_pwr_get(void *data, u64 *val)
+{
+	*val = sdslot_vdd;
+	return 0;
+}
+
+static int mahimahimmc_dbg_sd_cd_set(void *data, u64 val)
+{
+	return -ENOSYS;
+}
+
+static int mahimahimmc_dbg_sd_cd_get(void *data, u64 *val)
+{
+	*val = mahimahi_sdslot_data.status(NULL);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_wifi_reset_fops,
+			mahimahimmc_dbg_wifi_reset_get,
+			mahimahimmc_dbg_wifi_reset_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_wifi_cd_fops,
+			mahimahimmc_dbg_wifi_cd_get,
+			mahimahimmc_dbg_wifi_cd_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_wifi_pwr_fops,
+			mahimahimmc_dbg_wifi_pwr_get,
+			mahimahimmc_dbg_wifi_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_sd_pwr_fops,
+			mahimahimmc_dbg_sd_pwr_get,
+			mahimahimmc_dbg_sd_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_sd_cd_fops,
+			mahimahimmc_dbg_sd_cd_get,
+			mahimahimmc_dbg_sd_cd_set, "%llu\n");
+
+static int __init mahimahimmc_dbg_init(void)
+{
+	struct dentry *dent;
+
+	if (!machine_is_mahimahi())
+		return 0;
+
+	dent = debugfs_create_dir("mahimahi_mmc_dbg", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("wifi_reset", 0644, dent, NULL,
+			    &mahimahimmc_dbg_wifi_reset_fops);
+	debugfs_create_file("wifi_cd", 0644, dent, NULL,
+			    &mahimahimmc_dbg_wifi_cd_fops);
+	debugfs_create_file("wifi_pwr", 0644, dent, NULL,
+			    &mahimahimmc_dbg_wifi_pwr_fops);
+	debugfs_create_file("sd_pwr", 0644, dent, NULL,
+			    &mahimahimmc_dbg_sd_pwr_fops);
+	debugfs_create_file("sd_cd", 0644, dent, NULL,
+			    &mahimahimmc_dbg_sd_cd_fops);
+	return 0;
+}
+
+device_initcall(mahimahimmc_dbg_init);
+#endif
diff --git a/arch/arm/mach-msm/board-mahimahi-panel.c b/arch/arm/mach-msm/board-mahimahi-panel.c
new file mode 100644
index 0000000..64b66b7
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-panel.c
@@ -0,0 +1,998 @@
+/* linux/arch/arm/mach-msm/board-mahimahi-panel.c
+ *
+ * Copyright (c) 2009 Google Inc.
+ * Author: Dima Zavin <dima@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+#include <mach/msm_iomap.h>
+#include <mach/vreg.h>
+#include "proc_comm.h"
+
+#include "board-mahimahi.h"
+#include "devices.h"
+
+
+#define SPI_CONFIG              (0x00000000)
+#define SPI_IO_CONTROL          (0x00000004)
+#define SPI_OPERATIONAL         (0x00000030)
+#define SPI_ERROR_FLAGS_EN      (0x00000038)
+#define SPI_ERROR_FLAGS         (0x00000038)
+#define SPI_OUTPUT_FIFO         (0x00000100)
+
+static void __iomem *spi_base;
+static struct clk *spi_clk ;
+static struct vreg *vreg_lcm_rftx_2v6;
+static struct vreg *vreg_lcm_aux_2v6;
+
+static int qspi_send(uint32_t id, uint8_t data)
+{
+	uint32_t err;
+
+	/* bit-5: OUTPUT_FIFO_NOT_EMPTY */
+	while (readl(spi_base + SPI_OPERATIONAL) & (1<<5)) {
+		if ((err = readl(spi_base + SPI_ERROR_FLAGS))) {
+			pr_err("%s: ERROR: SPI_ERROR_FLAGS=0x%08x\n", __func__,
+			       err);
+			return -EIO;
+		}
+	}
+	writel((0x7000 | (id << 9) | data) << 16, spi_base + SPI_OUTPUT_FIFO);
+	udelay(100);
+
+	return 0;
+}
+
+static int qspi_send_9bit(uint32_t id, uint8_t data)
+{
+	uint32_t err;
+
+	while (readl(spi_base + SPI_OPERATIONAL) & (1<<5)) {
+		err = readl(spi_base + SPI_ERROR_FLAGS);
+		if (err) {
+			pr_err("%s: ERROR: SPI_ERROR_FLAGS=0x%08x\n", __func__,
+			       err);
+			return -EIO;
+		}
+	}
+	writel(((id << 8) | data) << 23, spi_base + SPI_OUTPUT_FIFO);
+	udelay(100);
+
+	return 0;
+}
+
+static int lcm_writeb(uint8_t reg, uint8_t val)
+{
+	qspi_send(0x0, reg);
+	qspi_send(0x1, val);
+	return 0;
+}
+
+static int lcm_writew(uint8_t reg, uint16_t val)
+{
+	qspi_send(0x0, reg);
+	qspi_send(0x1, val >> 8);
+	qspi_send(0x1, val & 0xff);
+	return 0;
+}
+
+static struct resource resources_msm_fb[] = {
+	{
+		.start = MSM_FB_BASE,
+		.end = MSM_FB_BASE + MSM_FB_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct lcm_tbl {
+	uint8_t		reg;
+	uint8_t		val;
+};
+
+static struct lcm_tbl samsung_oled_rgb565_init_table[] = {
+	{ 0x31, 0x08 },
+	{ 0x32, 0x14 },
+	{ 0x30, 0x2 },
+	{ 0x27, 0x1 },
+	{ 0x12, 0x8 },
+	{ 0x13, 0x8 },
+	{ 0x15, 0x0 },
+	{ 0x16, 0x02 },
+	{ 0x39, 0x24 },
+	{ 0x17, 0x22 },
+	{ 0x18, 0x33 },
+	{ 0x19, 0x3 },
+	{ 0x1A, 0x1 },
+	{ 0x22, 0xA4 },
+	{ 0x23, 0x0 },
+	{ 0x26, 0xA0 },
+};
+
+static struct lcm_tbl samsung_oled_rgb666_init_table[] = {
+	{ 0x31, 0x08 },
+	{ 0x32, 0x14 },
+	{ 0x30, 0x2  },
+	{ 0x27, 0x1  },
+	{ 0x12, 0x8  },
+	{ 0x13, 0x8  },
+	{ 0x15, 0x0  },
+	{ 0x16, 0x01 },
+	{ 0x39, 0x24 },
+	{ 0x17, 0x22 },
+	{ 0x18, 0x33 },
+	{ 0x19, 0x3  },
+	{ 0x1A, 0x1  },
+	{ 0x22, 0xA4 },
+	{ 0x23, 0x0  },
+	{ 0x26, 0xA0 },
+};
+
+static struct lcm_tbl *init_tablep = samsung_oled_rgb565_init_table;
+static size_t init_table_sz = ARRAY_SIZE(samsung_oled_rgb565_init_table);
+
+#define OLED_GAMMA_TABLE_SIZE		(7 * 3)
+static struct lcm_tbl samsung_oled_gamma_table[][OLED_GAMMA_TABLE_SIZE] = {
+	/* level 10 */
+	{
+		/* Gamma-R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x3f },
+		{ 0x43, 0x35 },
+		{ 0x44, 0x30 },
+		{ 0x45, 0x2c },
+		{ 0x46, 0x13 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x0 },
+		{ 0x53, 0x0 },
+		{ 0x54, 0x27 },
+		{ 0x55, 0x2b },
+		{ 0x56, 0x12 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x3f },
+		{ 0x63, 0x34 },
+		{ 0x64, 0x2f },
+		{ 0x65, 0x2b },
+		{ 0x66, 0x1b },
+	},
+
+	/* level 40 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x3e },
+		{ 0x43, 0x2e },
+		{ 0x44, 0x2d },
+		{ 0x45, 0x28 },
+		{ 0x46, 0x21 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x0 },
+		{ 0x53, 0x21 },
+		{ 0x54, 0x2a },
+		{ 0x55, 0x28 },
+		{ 0x56, 0x20 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x3e },
+		{ 0x63, 0x2d },
+		{ 0x64, 0x2b },
+		{ 0x65, 0x26 },
+		{ 0x66, 0x2d },
+	},
+
+	/* level 70 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x35 },
+		{ 0x43, 0x2c },
+		{ 0x44, 0x2b },
+		{ 0x45, 0x26 },
+		{ 0x46, 0x29 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x0 },
+		{ 0x53, 0x25 },
+		{ 0x54, 0x29 },
+		{ 0x55, 0x26 },
+		{ 0x56, 0x28 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x34 },
+		{ 0x63, 0x2b },
+		{ 0x64, 0x2a },
+		{ 0x65, 0x23 },
+		{ 0x66, 0x37 },
+	},
+
+	/* level 100 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x30 },
+		{ 0x43, 0x2a },
+		{ 0x44, 0x2b },
+		{ 0x45, 0x24 },
+		{ 0x46, 0x2f },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x0 },
+		{ 0x53, 0x25 },
+		{ 0x54, 0x29 },
+		{ 0x55, 0x24 },
+		{ 0x56, 0x2e },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x2f },
+		{ 0x63, 0x29 },
+		{ 0x64, 0x29 },
+		{ 0x65, 0x21 },
+		{ 0x66, 0x3f },
+	},
+
+	/* level 130 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x2e },
+		{ 0x43, 0x29 },
+		{ 0x44, 0x2a },
+		{ 0x45, 0x23 },
+		{ 0x46, 0x34 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0xa },
+		{ 0x53, 0x25 },
+		{ 0x54, 0x28 },
+		{ 0x55, 0x23 },
+		{ 0x56, 0x33 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x2d },
+		{ 0x63, 0x28 },
+		{ 0x64, 0x27 },
+		{ 0x65, 0x20 },
+		{ 0x66, 0x46 },
+	},
+
+	/* level 160 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x2b },
+		{ 0x43, 0x29 },
+		{ 0x44, 0x28 },
+		{ 0x45, 0x23 },
+		{ 0x46, 0x38 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0xb },
+		{ 0x53, 0x25 },
+		{ 0x54, 0x27 },
+		{ 0x55, 0x23 },
+		{ 0x56, 0x37 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x29 },
+		{ 0x63, 0x28 },
+		{ 0x64, 0x25 },
+		{ 0x65, 0x20 },
+		{ 0x66, 0x4b },
+	},
+
+	/* level 190 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x29 },
+		{ 0x43, 0x29 },
+		{ 0x44, 0x27 },
+		{ 0x45, 0x22 },
+		{ 0x46, 0x3c },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x10 },
+		{ 0x53, 0x26 },
+		{ 0x54, 0x26 },
+		{ 0x55, 0x22 },
+		{ 0x56, 0x3b },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x28 },
+		{ 0x63, 0x28 },
+		{ 0x64, 0x24 },
+		{ 0x65, 0x1f },
+		{ 0x66, 0x50 },
+	},
+
+	/* level 220 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x28 },
+		{ 0x43, 0x28 },
+		{ 0x44, 0x28 },
+		{ 0x45, 0x20 },
+		{ 0x46, 0x40 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x11 },
+		{ 0x53, 0x25 },
+		{ 0x54, 0x27 },
+		{ 0x55, 0x20 },
+		{ 0x56, 0x3f },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x27 },
+		{ 0x63, 0x26 },
+		{ 0x64, 0x26 },
+		{ 0x65, 0x1c },
+		{ 0x66, 0x56 },
+	},
+
+	/* level 250 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x2a },
+		{ 0x43, 0x27 },
+		{ 0x44, 0x27 },
+		{ 0x45, 0x1f },
+		{ 0x46, 0x44 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x17 },
+		{ 0x53, 0x24 },
+		{ 0x54, 0x26 },
+		{ 0x55, 0x1f },
+		{ 0x56, 0x43 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x2a },
+		{ 0x63, 0x25 },
+		{ 0x64, 0x24 },
+		{ 0x65, 0x1b },
+		{ 0x66, 0x5c },
+	},
+};
+#define SAMSUNG_OLED_NUM_LEVELS		ARRAY_SIZE(samsung_oled_gamma_table)
+
+#define SAMSUNG_OLED_MIN_VAL		10
+#define SAMSUNG_OLED_MAX_VAL		250
+#define SAMSUNG_OLED_DEFAULT_VAL	(SAMSUNG_OLED_MIN_VAL +		\
+					 (SAMSUNG_OLED_MAX_VAL -	\
+					  SAMSUNG_OLED_MIN_VAL) / 2)
+
+#define SAMSUNG_OLED_LEVEL_STEP		((SAMSUNG_OLED_MAX_VAL -	\
+					  SAMSUNG_OLED_MIN_VAL) /	\
+					 (SAMSUNG_OLED_NUM_LEVELS - 1))
+
+
+#define SONY_TFT_DEF_USER_VAL         102
+#define SONY_TFT_MIN_USER_VAL         30
+#define SONY_TFT_MAX_USER_VAL         255
+#define SONY_TFT_DEF_PANEL_VAL        155
+#define SONY_TFT_MIN_PANEL_VAL        26
+#define SONY_TFT_MAX_PANEL_VAL        255
+
+
+static DEFINE_MUTEX(panel_lock);
+static struct work_struct brightness_delayed_work;
+static DEFINE_SPINLOCK(brightness_lock);
+static uint8_t new_val = SAMSUNG_OLED_DEFAULT_VAL;
+static uint8_t last_val = SAMSUNG_OLED_DEFAULT_VAL;
+static uint8_t table_sel_vals[] = { 0x43, 0x34 };
+static int table_sel_idx = 0;
+static uint8_t tft_panel_on;
+
+static void gamma_table_bank_select(void)
+{
+	lcm_writeb(0x39, table_sel_vals[table_sel_idx]);
+	table_sel_idx ^= 1;
+}
+
+static void samsung_oled_set_gamma_val(int val)
+{
+	int i;
+	int level;
+	int frac;
+
+	val = clamp(val, SAMSUNG_OLED_MIN_VAL, SAMSUNG_OLED_MAX_VAL);
+	val = (val / 2) * 2;
+
+	level = (val - SAMSUNG_OLED_MIN_VAL) / SAMSUNG_OLED_LEVEL_STEP;
+	frac = (val - SAMSUNG_OLED_MIN_VAL) % SAMSUNG_OLED_LEVEL_STEP;
+
+	clk_enable(spi_clk);
+
+	for (i = 0; i < OLED_GAMMA_TABLE_SIZE; ++i) {
+		unsigned int v1;
+		unsigned int v2 = 0;
+		u8 v;
+		if (frac == 0) {
+			v = samsung_oled_gamma_table[level][i].val;
+		} else {
+
+			v1 = samsung_oled_gamma_table[level][i].val;
+			v2 = samsung_oled_gamma_table[level+1][i].val;
+			v = (v1 * (SAMSUNG_OLED_LEVEL_STEP - frac) +
+			     v2 * frac) / SAMSUNG_OLED_LEVEL_STEP;
+		}
+		lcm_writeb(samsung_oled_gamma_table[level][i].reg, v);
+	}
+
+	gamma_table_bank_select();
+	clk_disable(spi_clk);
+	last_val = val;
+}
+
+static int samsung_oled_panel_init(struct msm_lcdc_panel_ops *ops)
+{
+	pr_info("%s: +()\n", __func__);
+	mutex_lock(&panel_lock);
+
+	clk_enable(spi_clk);
+	/* Set the gamma write target to 4, leave the current gamma set at 2 */
+	lcm_writeb(0x39, 0x24);
+	clk_disable(spi_clk);
+
+	mutex_unlock(&panel_lock);
+	pr_info("%s: -()\n", __func__);
+	return 0;
+}
+
+static int samsung_oled_panel_unblank(struct msm_lcdc_panel_ops *ops)
+{
+	int i;
+
+	pr_info("%s: +()\n", __func__);
+
+	mutex_lock(&panel_lock);
+
+	gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
+	udelay(50);
+	gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
+	udelay(20);
+	gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
+	msleep(20);
+
+	clk_enable(spi_clk);
+
+	for (i = 0; i < init_table_sz; i++)
+		lcm_writeb(init_tablep[i].reg, init_tablep[i].val);
+
+	lcm_writew(0xef, 0xd0e8);
+	lcm_writeb(0x1d, 0xa0);
+	table_sel_idx = 0;
+	gamma_table_bank_select();
+	samsung_oled_set_gamma_val(last_val);
+	msleep(250);
+	lcm_writeb(0x14, 0x03);
+	clk_disable(spi_clk);
+
+	mutex_unlock(&panel_lock);
+
+	pr_info("%s: -()\n", __func__);
+	return 0;
+}
+
+static int samsung_oled_panel_blank(struct msm_lcdc_panel_ops *ops)
+{
+	pr_info("%s: +()\n", __func__);
+	mutex_lock(&panel_lock);
+
+	clk_enable(spi_clk);
+	lcm_writeb(0x14, 0x0);
+	mdelay(1);
+	lcm_writeb(0x1d, 0xa1);
+	clk_disable(spi_clk);
+	msleep(200);
+
+	gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
+
+	mutex_unlock(&panel_lock);
+	pr_info("%s: -()\n", __func__);
+	return 0;
+}
+
+struct lcm_cmd {
+	int reg;
+	uint32_t val;
+	unsigned delay;
+};
+
+#define LCM_GPIO_CFG(gpio, func, str) \
+		PCOM_GPIO_CFG(gpio, func, GPIO_OUTPUT, GPIO_NO_PULL, str)
+
+static uint32_t sony_tft_display_on_gpio_table[] = {
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R1, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R2, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R3, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R4, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R5, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G0, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G1, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G2, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G3, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G4, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G5, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B1, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B2, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B3, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B4, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B5, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_PCLK, 1, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_VSYNC, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_HSYNC, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_DE, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CLK, 1, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_DO, 1, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CSz, 1, GPIO_4MA),
+};
+
+static uint32_t sony_tft_display_off_gpio_table[] = {
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R1, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R2, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R3, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R4, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R5, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G0, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G1, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G2, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G3, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G4, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G5, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B1, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B2, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B3, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B4, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B5, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_PCLK, 0, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_VSYNC, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_HSYNC, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_DE, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CLK, 0, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_DO, 0, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CSz, 0, GPIO_4MA),
+};
+
+#undef LCM_GPIO_CFG
+
+#define SONY_TFT_DEF_PANEL_DELTA \
+		(SONY_TFT_DEF_PANEL_VAL - SONY_TFT_MIN_PANEL_VAL)
+#define SONY_TFT_DEF_USER_DELTA \
+		(SONY_TFT_DEF_USER_VAL - SONY_TFT_MIN_USER_VAL)
+
+static void sony_tft_set_pwm_val(int val)
+{
+	pr_info("%s: %d\n", __func__, val);
+
+	last_val = val;
+
+	if (!tft_panel_on)
+		return;
+
+	if (val <= SONY_TFT_DEF_USER_VAL) {
+		if (val <= SONY_TFT_MIN_USER_VAL)
+			val = SONY_TFT_MIN_PANEL_VAL;
+		else
+			val = SONY_TFT_DEF_PANEL_DELTA *
+				(val - SONY_TFT_MIN_USER_VAL) /
+				SONY_TFT_DEF_USER_DELTA +
+				SONY_TFT_MIN_PANEL_VAL;
+	} else
+		val = (SONY_TFT_MAX_PANEL_VAL - SONY_TFT_DEF_PANEL_VAL) *
+			(val - SONY_TFT_DEF_USER_VAL) /
+			(SONY_TFT_MAX_USER_VAL - SONY_TFT_DEF_USER_VAL) +
+			SONY_TFT_DEF_PANEL_VAL;
+
+	clk_enable(spi_clk);
+	qspi_send_9bit(0x0, 0x51);
+	qspi_send_9bit(0x1, val);
+	qspi_send_9bit(0x0, 0x53);
+	qspi_send_9bit(0x1, 0x24);
+	clk_disable(spi_clk);
+}
+
+#undef SONY_TFT_DEF_PANEL_DELTA
+#undef SONY_TFT_DEF_USER_DELTA
+
+static void sony_tft_panel_config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for (n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+
+static int sony_tft_panel_power(int on)
+{
+	unsigned id, on_off;
+
+	if (on) {
+		on_off = 0;
+
+		vreg_enable(vreg_lcm_aux_2v6);
+		vreg_enable(vreg_lcm_rftx_2v6);
+
+		id = PM_VREG_PDOWN_AUX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+
+		id = PM_VREG_PDOWN_RFTX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+		mdelay(10);
+		gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
+		mdelay(10);
+		gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
+		udelay(500);
+		gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
+		mdelay(10);
+		sony_tft_panel_config_gpio_table(
+			sony_tft_display_on_gpio_table,
+			ARRAY_SIZE(sony_tft_display_on_gpio_table));
+	} else {
+		on_off = 1;
+
+		gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
+
+		mdelay(120);
+
+		vreg_disable(vreg_lcm_rftx_2v6);
+		vreg_disable(vreg_lcm_aux_2v6);
+
+		id = PM_VREG_PDOWN_RFTX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+
+		id = PM_VREG_PDOWN_AUX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+		sony_tft_panel_config_gpio_table(
+			sony_tft_display_off_gpio_table,
+			ARRAY_SIZE(sony_tft_display_off_gpio_table));
+	}
+	return 0;
+}
+
+static int sony_tft_panel_init(struct msm_lcdc_panel_ops *ops)
+{
+	return 0;
+}
+
+static int sony_tft_panel_unblank(struct msm_lcdc_panel_ops *ops)
+{
+	pr_info("%s: +()\n", __func__);
+
+	mutex_lock(&panel_lock);
+
+	if (tft_panel_on) {
+		pr_info("%s: -() already unblanked\n", __func__);
+		goto done;
+	}
+
+	sony_tft_panel_power(1);
+	msleep(45);
+
+	clk_enable(spi_clk);
+	qspi_send_9bit(0x0, 0x11);
+	msleep(5);
+	qspi_send_9bit(0x0, 0x3a);
+	qspi_send_9bit(0x1, 0x05);
+	msleep(100);
+	qspi_send_9bit(0x0, 0x29);
+	/* unlock register page for pwm setting */
+	qspi_send_9bit(0x0, 0xf0);
+	qspi_send_9bit(0x1, 0x5a);
+	qspi_send_9bit(0x1, 0x5a);
+	qspi_send_9bit(0x0, 0xf1);
+	qspi_send_9bit(0x1, 0x5a);
+	qspi_send_9bit(0x1, 0x5a);
+	qspi_send_9bit(0x0, 0xd0);
+	qspi_send_9bit(0x1, 0x5a);
+	qspi_send_9bit(0x1, 0x5a);
+
+	qspi_send_9bit(0x0, 0xc2);
+	qspi_send_9bit(0x1, 0x53);
+	qspi_send_9bit(0x1, 0x12);
+	clk_disable(spi_clk);
+	msleep(100);
+	tft_panel_on = 1;
+	sony_tft_set_pwm_val(last_val);
+
+	pr_info("%s: -()\n", __func__);
+done:
+	mutex_unlock(&panel_lock);
+	return 0;
+}
+
+static int sony_tft_panel_blank(struct msm_lcdc_panel_ops *ops)
+{
+	pr_info("%s: +()\n", __func__);
+
+	mutex_lock(&panel_lock);
+
+	clk_enable(spi_clk);
+	qspi_send_9bit(0x0, 0x28);
+	qspi_send_9bit(0x0, 0x10);
+	clk_disable(spi_clk);
+
+	msleep(40);
+	sony_tft_panel_power(0);
+	tft_panel_on = 0;
+
+	mutex_unlock(&panel_lock);
+
+	pr_info("%s: -()\n", __func__);
+	return 0;
+}
+
+static struct msm_lcdc_panel_ops mahimahi_lcdc_amoled_panel_ops = {
+	.init		= samsung_oled_panel_init,
+	.blank		= samsung_oled_panel_blank,
+	.unblank	= samsung_oled_panel_unblank,
+};
+
+static struct msm_lcdc_panel_ops mahimahi_lcdc_tft_panel_ops = {
+	.init		= sony_tft_panel_init,
+	.blank		= sony_tft_panel_blank,
+	.unblank	= sony_tft_panel_unblank,
+};
+
+
+static struct msm_lcdc_timing mahimahi_lcdc_amoled_timing = {
+		.clk_rate		= 24576000,
+		.hsync_pulse_width	= 4,
+		.hsync_back_porch	= 8,
+		.hsync_front_porch	= 8,
+		.hsync_skew		= 0,
+		.vsync_pulse_width	= 2,
+		.vsync_back_porch	= 8,
+		.vsync_front_porch	= 8,
+		.vsync_act_low		= 1,
+		.hsync_act_low		= 1,
+		.den_act_low		= 1,
+};
+
+static struct msm_lcdc_timing mahimahi_lcdc_tft_timing = {
+		.clk_rate		= 24576000,
+		.hsync_pulse_width	= 2,
+		.hsync_back_porch	= 20,
+		.hsync_front_porch	= 20,
+		.hsync_skew		= 0,
+		.vsync_pulse_width	= 2,
+		.vsync_back_porch	= 6,
+		.vsync_front_porch	= 4,
+		.vsync_act_low		= 1,
+		.hsync_act_low		= 1,
+		.den_act_low		= 0,
+};
+
+static struct msm_fb_data mahimahi_lcdc_fb_data = {
+		.xres		= 480,
+		.yres		= 800,
+		.width		= 48,
+		.height		= 80,
+		.output_format	= MSM_MDP_OUT_IF_FMT_RGB565,
+};
+
+static struct msm_lcdc_platform_data mahimahi_lcdc_amoled_platform_data = {
+	.panel_ops	= &mahimahi_lcdc_amoled_panel_ops,
+	.timing		= &mahimahi_lcdc_amoled_timing,
+	.fb_id		= 0,
+	.fb_data	= &mahimahi_lcdc_fb_data,
+	.fb_resource	= &resources_msm_fb[0],
+};
+
+static struct msm_lcdc_platform_data mahimahi_lcdc_tft_platform_data = {
+	.panel_ops	= &mahimahi_lcdc_tft_panel_ops,
+	.timing		= &mahimahi_lcdc_tft_timing,
+	.fb_id		= 0,
+	.fb_data	= &mahimahi_lcdc_fb_data,
+	.fb_resource	= &resources_msm_fb[0],
+};
+
+static struct platform_device mahimahi_lcdc_amoled_device = {
+	.name	= "msm_mdp_lcdc",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mahimahi_lcdc_amoled_platform_data,
+	},
+};
+
+static struct platform_device mahimahi_lcdc_tft_device = {
+	.name	= "msm_mdp_lcdc",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mahimahi_lcdc_tft_platform_data,
+	},
+};
+
+static int mahimahi_init_spi_hack(void)
+{
+	int ret;
+
+	spi_base = ioremap(MSM_SPI_PHYS, MSM_SPI_SIZE);
+	if (!spi_base)
+		return -1;
+
+	spi_clk = clk_get(&msm_device_spi.dev, "spi_clk");
+	if (IS_ERR(spi_clk)) {
+		pr_err("%s: unable to get spi_clk\n", __func__);
+		ret = PTR_ERR(spi_clk);
+		goto err_clk_get;
+	}
+
+	clk_enable(spi_clk);
+
+	printk("spi: SPI_CONFIG=%x\n", readl(spi_base + SPI_CONFIG));
+	printk("spi: SPI_IO_CONTROL=%x\n", readl(spi_base + SPI_IO_CONTROL));
+	printk("spi: SPI_OPERATIONAL=%x\n", readl(spi_base + SPI_OPERATIONAL));
+	printk("spi: SPI_ERROR_FLAGS_EN=%x\n",
+	       readl(spi_base + SPI_ERROR_FLAGS_EN));
+	printk("spi: SPI_ERROR_FLAGS=%x\n", readl(spi_base + SPI_ERROR_FLAGS));
+	printk("-%s()\n", __FUNCTION__);
+	clk_disable(spi_clk);
+
+	return 0;
+
+err_clk_get:
+	iounmap(spi_base);
+	return ret;
+}
+
+static void mahimahi_brightness_set(struct led_classdev *led_cdev,
+				    enum led_brightness val)
+{
+	unsigned long flags;
+	led_cdev->brightness = val;
+
+	spin_lock_irqsave(&brightness_lock, flags);
+	new_val = val;
+	spin_unlock_irqrestore(&brightness_lock, flags);
+
+	schedule_work(&brightness_delayed_work);
+}
+
+static void mahimahi_brightness_amoled_set_work(struct work_struct *work_ptr)
+{
+	unsigned long flags;
+	uint8_t val;
+
+	spin_lock_irqsave(&brightness_lock, flags);
+	val = new_val;
+	spin_unlock_irqrestore(&brightness_lock, flags);
+
+	mutex_lock(&panel_lock);
+	samsung_oled_set_gamma_val(val);
+	mutex_unlock(&panel_lock);
+}
+
+static void mahimahi_brightness_tft_set_work(struct work_struct *work_ptr)
+{
+	unsigned long flags;
+	uint8_t val;
+
+	spin_lock_irqsave(&brightness_lock, flags);
+	val = new_val;
+	spin_unlock_irqrestore(&brightness_lock, flags);
+
+	mutex_lock(&panel_lock);
+	sony_tft_set_pwm_val(val);
+	mutex_unlock(&panel_lock);
+}
+
+static struct led_classdev mahimahi_brightness_led = {
+	.name = "lcd-backlight",
+	.brightness = LED_FULL,
+	.brightness_set = mahimahi_brightness_set,
+};
+
+int __init mahimahi_init_panel(void)
+{
+	int ret;
+
+	if (!machine_is_mahimahi())
+		return 0;
+
+	if (system_rev > 0xC0) {
+		/* CDMA version (except for EVT1) supports RGB666 */
+		init_tablep = samsung_oled_rgb666_init_table;
+		init_table_sz = ARRAY_SIZE(samsung_oled_rgb666_init_table);
+		mahimahi_lcdc_fb_data.output_format = MSM_MDP_OUT_IF_FMT_RGB666;
+	}
+
+	ret = platform_device_register(&msm_device_mdp);
+	if (ret != 0)
+		return ret;
+
+	ret = mahimahi_init_spi_hack();
+	if (ret != 0)
+		return ret;
+
+	if (gpio_get_value(MAHIMAHI_GPIO_LCD_ID0)) {
+		pr_info("%s: tft panel\n", __func__);
+		vreg_lcm_rftx_2v6 = vreg_get(0, "rftx");
+		if (IS_ERR(vreg_lcm_rftx_2v6))
+			return PTR_ERR(vreg_lcm_rftx_2v6);
+		vreg_set_level(vreg_lcm_rftx_2v6, 2600);
+
+		vreg_lcm_aux_2v6 = vreg_get(0, "gp4");
+		if (IS_ERR(vreg_lcm_aux_2v6))
+			return PTR_ERR(vreg_lcm_aux_2v6);
+
+		if (gpio_get_value(MAHIMAHI_GPIO_LCD_RST_N))
+			tft_panel_on = 1;
+		ret = platform_device_register(&mahimahi_lcdc_tft_device);
+		INIT_WORK(&brightness_delayed_work, mahimahi_brightness_tft_set_work);
+	} else {
+		pr_info("%s: amoled panel\n", __func__);
+		ret = platform_device_register(&mahimahi_lcdc_amoled_device);
+		INIT_WORK(&brightness_delayed_work, mahimahi_brightness_amoled_set_work);
+	}
+
+	if (ret != 0)
+		return ret;
+
+	ret = led_classdev_register(NULL, &mahimahi_brightness_led);
+	if (ret != 0) {
+		pr_err("%s: Cannot register brightness led\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+device_initcall(mahimahi_init_panel);
diff --git a/arch/arm/mach-msm/board-mahimahi-rfkill.c b/arch/arm/mach-msm/board-mahimahi-rfkill.c
new file mode 100644
index 0000000..05c9bb0
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-rfkill.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+
+#include "board-mahimahi.h"
+
+static struct rfkill *bt_rfk;
+static const char bt_name[] = "bcm4329";
+
+static int bluetooth_set_power(void *data, bool blocked)
+{
+	if (!blocked) {
+ 		gpio_direction_output(MAHIMAHI_GPIO_BT_RESET_N, 1);
+		gpio_direction_output(MAHIMAHI_GPIO_BT_SHUTDOWN_N, 1);
+	} else {
+ 		gpio_direction_output(MAHIMAHI_GPIO_BT_SHUTDOWN_N, 0);
+		gpio_direction_output(MAHIMAHI_GPIO_BT_RESET_N, 0);
+	}
+	return 0;
+}
+
+static struct rfkill_ops mahimahi_rfkill_ops = {
+	.set_block = bluetooth_set_power,
+};
+
+static int mahimahi_rfkill_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	bool default_state = true;  /* off */
+
+	rc = gpio_request(MAHIMAHI_GPIO_BT_RESET_N, "bt_reset");
+	if (rc)
+		goto err_gpio_reset;
+	rc = gpio_request(MAHIMAHI_GPIO_BT_SHUTDOWN_N, "bt_shutdown");
+	if (rc)
+		goto err_gpio_shutdown;
+
+	bluetooth_set_power(NULL, default_state);
+
+	bt_rfk = rfkill_alloc(bt_name, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
+				&mahimahi_rfkill_ops, NULL);
+	if (!bt_rfk) {
+		rc = -ENOMEM;
+		goto err_rfkill_alloc;
+	}
+
+	rfkill_set_states(bt_rfk, default_state, false);
+
+	/* userspace cannot take exclusive control */
+
+	rc = rfkill_register(bt_rfk);
+	if (rc)
+		goto err_rfkill_reg;
+
+	return 0;
+
+err_rfkill_reg:
+	rfkill_destroy(bt_rfk);
+err_rfkill_alloc:
+	gpio_free(MAHIMAHI_GPIO_BT_SHUTDOWN_N);
+err_gpio_shutdown:
+	gpio_free(MAHIMAHI_GPIO_BT_RESET_N);
+err_gpio_reset:
+	return rc;
+}
+
+static int mahimahi_rfkill_remove(struct platform_device *dev)
+{
+	rfkill_unregister(bt_rfk);
+	rfkill_destroy(bt_rfk);
+	gpio_free(MAHIMAHI_GPIO_BT_SHUTDOWN_N);
+	gpio_free(MAHIMAHI_GPIO_BT_RESET_N);
+
+	return 0;
+}
+
+static struct platform_driver mahimahi_rfkill_driver = {
+	.probe = mahimahi_rfkill_probe,
+	.remove = mahimahi_rfkill_remove,
+	.driver = {
+		.name = "mahimahi_rfkill",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mahimahi_rfkill_init(void)
+{
+	if (!machine_is_mahimahi())
+		return 0;
+
+	return platform_driver_register(&mahimahi_rfkill_driver);
+}
+
+static void __exit mahimahi_rfkill_exit(void)
+{
+	platform_driver_unregister(&mahimahi_rfkill_driver);
+}
+
+module_init(mahimahi_rfkill_init);
+module_exit(mahimahi_rfkill_exit);
+MODULE_DESCRIPTION("mahimahi rfkill");
+MODULE_AUTHOR("Nick Pelly <npelly@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-mahimahi-smb329.c b/arch/arm/mach-msm/board-mahimahi-smb329.c
new file mode 100755
index 0000000..b80db78
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-smb329.c
@@ -0,0 +1,177 @@
+/* drivers/i2c/chips/smb329.c
+ *
+ * SMB329B Switch Charger (SUMMIT Microelectronics)
+ *
+ * Copyright (C) 2009 HTC Corporation
+ * Author: Justin Lin <Justin_Lin@htc.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <asm/atomic.h>
+
+#include "board-mahimahi-smb329.h"
+
+static struct smb329_data {
+	struct i2c_client *client;
+	uint8_t version;
+	struct work_struct work;
+	struct mutex state_lock;
+	int chg_state;
+} smb329;
+
+static int smb329_i2c_write(uint8_t *value, uint8_t reg, uint8_t num_bytes)
+{
+	int ret;
+	struct i2c_msg msg;
+
+	/* write the first byte of buffer as the register address */
+	value[0] = reg;
+	msg.addr = smb329.client->addr;
+	msg.len = num_bytes + 1;
+	msg.flags = 0;
+	msg.buf = value;
+
+	ret = i2c_transfer(smb329.client->adapter, &msg, 1);
+
+	return (ret >= 0) ? 0 : ret;
+}
+
+static int smb329_i2c_read(uint8_t *value, uint8_t reg, uint8_t num_bytes)
+{
+	int ret;
+	struct i2c_msg msg[2];
+
+	/* setup the address to read */
+	msg[0].addr = smb329.client->addr;
+	msg[0].len = 1;
+	msg[0].flags = 0;
+	msg[0].buf = &reg;
+
+	/* setup the read buffer */
+	msg[1].addr = smb329.client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = num_bytes;
+	msg[1].buf = value;
+
+	ret = i2c_transfer(smb329.client->adapter, msg, 2);
+
+	return (ret >= 0) ? 0 : ret;
+}
+
+static int smb329_i2c_write_byte(uint8_t value, uint8_t reg)
+{
+	int ret;
+	uint8_t buf[2] = { 0 };
+
+	buf[1] = value;
+	ret = smb329_i2c_write(buf, reg, 1);
+	if (ret)
+		pr_err("smb329: write byte error (%d)\n", ret);
+
+	return ret;
+}
+
+static int smb329_i2c_read_byte(uint8_t *value, uint8_t reg)
+{
+	int ret = smb329_i2c_read(value, reg, 1);
+	if (ret)
+		pr_err("smb329: read byte error (%d)\n", ret);
+
+	return ret;
+}
+
+int smb329_set_charger_ctrl(uint32_t ctl)
+{
+	mutex_lock(&smb329.state_lock);
+	smb329.chg_state = ctl;
+	schedule_work(&smb329.work);
+	mutex_unlock(&smb329.state_lock);
+	return 0;
+}
+
+static void smb329_work_func(struct work_struct *work)
+{
+	mutex_lock(&smb329.state_lock);
+
+	switch (smb329.chg_state) {
+	case SMB329_ENABLE_FAST_CHG:
+		pr_info("smb329: charger on (fast)\n");
+		smb329_i2c_write_byte(0x84, 0x31);
+		smb329_i2c_write_byte(0x08, 0x05);
+		if ((smb329.version & 0x18) == 0x0)
+			smb329_i2c_write_byte(0xA9, 0x00);
+		break;
+
+	case SMB329_DISABLE_CHG:
+	case SMB329_ENABLE_SLOW_CHG:
+		pr_info("smb329: charger off/slow\n");
+		smb329_i2c_write_byte(0x88, 0x31);
+		smb329_i2c_write_byte(0x08, 0x05);
+		break;
+	default:
+		pr_err("smb329: unknown charger state %d\n",
+			smb329.chg_state);
+	}
+
+	mutex_unlock(&smb329.state_lock);
+}
+
+static int smb329_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+		dev_dbg(&client->dev, "[SMB329]:I2C fail\n");
+		return -EIO;
+	}
+
+	smb329.client = client;
+	mutex_init(&smb329.state_lock);
+	INIT_WORK(&smb329.work, smb329_work_func);
+
+	smb329_i2c_read_byte(&smb329.version, 0x3B);
+	pr_info("smb329 version: 0x%02x\n", smb329.version);
+
+	return 0;
+}
+
+static const struct i2c_device_id smb329_id[] = {
+	{ "smb329", 0 },
+	{  },
+};
+
+static struct i2c_driver smb329_driver = {
+	.driver.name    = "smb329",
+	.id_table   = smb329_id,
+	.probe      = smb329_probe,
+};
+
+static int __init smb329_init(void)
+{
+	int ret = i2c_add_driver(&smb329_driver);
+	if (ret)
+		pr_err("smb329_init: failed\n");
+
+	return ret;
+}
+
+module_init(smb329_init);
+
+MODULE_AUTHOR("Justin Lin <Justin_Lin@htc.com>");
+MODULE_DESCRIPTION("SUMMIT Microelectronics SMB329B switch charger");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-mahimahi-smb329.h b/arch/arm/mach-msm/board-mahimahi-smb329.h
new file mode 100644
index 0000000..13b326f
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-smb329.h
@@ -0,0 +1,32 @@
+/* include/linux/smb329.h - smb329 switch charger driver
+ *
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SMB329_H
+#define _LINUX_SMB329_H
+
+#ifdef __KERNEL__
+
+enum {
+	SMB329_DISABLE_CHG,
+	SMB329_ENABLE_SLOW_CHG,
+	SMB329_ENABLE_FAST_CHG,
+};
+
+extern int smb329_set_charger_ctrl(uint32_t ctl);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SMB329_H */
+
diff --git a/arch/arm/mach-msm/board-mahimahi-tpa2018d1.c b/arch/arm/mach-msm/board-mahimahi-tpa2018d1.c
new file mode 100644
index 0000000..78919b9b
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-tpa2018d1.c
@@ -0,0 +1,368 @@
+/* drivers/i2c/chips/tpa2018d1.c
+ *
+ * TI TPA2018D1 Speaker Amplifier
+ *
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/* TODO: content validation in TPA2018_SET_CONFIG */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/tpa2018d1.h>
+
+#include "board-mahimahi-tpa2018d1.h"
+
+static struct i2c_client *this_client;
+static struct tpa2018d1_platform_data *pdata;
+static int is_on;
+static char spk_amp_cfg[8];
+static const char spk_amp_on[8] = { /* same length as spk_amp_cfg */
+	0x01, 0xc3, 0x20, 0x01, 0x00, 0x08, 0x1a, 0x21
+};
+static const char spk_amp_off[] = {0x01, 0xa2};
+
+static DEFINE_MUTEX(spk_amp_lock);
+static int tpa2018d1_opened;
+static char *config_data;
+static int tpa2018d1_num_modes;
+
+#define DEBUG 0
+
+static int tpa2018_i2c_write(const char *txData, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = this_client->addr,
+			.flags = 0,
+			.len = length,
+			.buf = txData,
+		},
+	};
+
+	if (i2c_transfer(this_client->adapter, msg, 1) < 0) {
+		pr_err("%s: I2C transfer error\n", __func__);
+		return -EIO;
+	} else
+		return 0;
+}
+
+static int tpa2018_i2c_read(char *rxData, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr = this_client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = rxData,
+		},
+	};
+
+	if (i2c_transfer(this_client->adapter, msgs, 1) < 0) {
+		pr_err("%s: I2C transfer error\n", __func__);
+		return -EIO;
+	}
+
+#if DEBUG
+	do {
+		int i = 0;
+		for (i = 0; i < length; i++)
+			pr_info("%s: rx[%d] = %2x\n",
+				__func__, i, rxData[i]);
+	} while(0);
+#endif
+
+	return 0;
+}
+
+static int tpa2018d1_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	mutex_lock(&spk_amp_lock);
+
+	if (tpa2018d1_opened) {
+		pr_err("%s: busy\n", __func__);
+		rc = -EBUSY;
+		goto done;
+	}
+
+	tpa2018d1_opened = 1;
+done:
+	mutex_unlock(&spk_amp_lock);
+	return rc;
+}
+
+static int tpa2018d1_release(struct inode *inode, struct file *file)
+{
+	mutex_lock(&spk_amp_lock);
+	tpa2018d1_opened = 0;
+	mutex_unlock(&spk_amp_lock);
+
+	return 0;
+}
+
+static int tpa2018d1_read_config(void __user *argp)
+{
+	int rc = 0;
+	unsigned char reg_idx = 0x01;
+	unsigned char tmp[7];
+
+	if (!is_on) {
+		gpio_set_value(pdata->gpio_tpa2018_spk_en, 1);
+		msleep(5); /* According to TPA2018D1 Spec */
+	}
+
+	rc = tpa2018_i2c_write(&reg_idx, sizeof(reg_idx));
+	if (rc < 0)
+		goto err;
+
+	rc = tpa2018_i2c_read(tmp, sizeof(tmp));
+	if (rc < 0)
+		goto err;
+
+	if (copy_to_user(argp, &tmp, sizeof(tmp)))
+		rc = -EFAULT;
+
+err:
+	if (!is_on)
+		gpio_set_value(pdata->gpio_tpa2018_spk_en, 0);
+	return rc;
+}
+
+static int tpa2018d1_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int rc = 0;
+	int mode = -1;
+	int offset = 0;
+	struct tpa2018d1_config_data cfg;
+
+	mutex_lock(&spk_amp_lock);
+
+	switch (cmd) {
+	case TPA2018_SET_CONFIG:
+		if (copy_from_user(spk_amp_cfg, argp, sizeof(spk_amp_cfg)))
+			rc = -EFAULT;
+		break;
+
+	case TPA2018_READ_CONFIG:
+		rc = tpa2018d1_read_config(argp);
+		break;
+
+	case TPA2018_SET_MODE:
+		if (copy_from_user(&mode, argp, sizeof(mode))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (mode >= tpa2018d1_num_modes || mode < 0) {
+			pr_err("%s: unsupported tpa2018d1 mode %d\n",
+				__func__, mode);
+			rc = -EINVAL;
+			break;
+		}
+		if (!config_data) {
+			pr_err("%s: no config data!\n", __func__);
+			rc = -EIO;
+			break;
+		}
+		memcpy(spk_amp_cfg, config_data + mode * TPA2018D1_CMD_LEN,
+			TPA2018D1_CMD_LEN);
+		break;
+
+	case TPA2018_SET_PARAM:
+		if (copy_from_user(&cfg, argp, sizeof(cfg))) {
+			pr_err("%s: copy from user failed.\n", __func__);
+			rc = -EFAULT;
+			break;
+		}
+		tpa2018d1_num_modes = cfg.mode_num;
+		if (tpa2018d1_num_modes > TPA2018_NUM_MODES) {
+			pr_err("%s: invalid number of modes %d\n", __func__,
+				tpa2018d1_num_modes);
+			rc = -EINVAL;
+			break;
+		}
+		if (cfg.data_len != tpa2018d1_num_modes*TPA2018D1_CMD_LEN) {
+			pr_err("%s: invalid data length %d, expecting %d\n",
+				__func__, cfg.data_len,
+				tpa2018d1_num_modes * TPA2018D1_CMD_LEN);
+			rc = -EINVAL;
+			break;
+		}
+		/* Free the old data */
+		if (config_data)
+			kfree(config_data);
+		config_data = kmalloc(cfg.data_len, GFP_KERNEL);
+		if (!config_data) {
+			pr_err("%s: out of memory\n", __func__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(config_data, cfg.cmd_data, cfg.data_len)) {
+			pr_err("%s: copy data from user failed.\n", __func__);
+			kfree(config_data);
+			config_data = NULL;
+			rc = -EFAULT;
+			break;
+		}
+		/* replace default setting with playback setting */
+		if (tpa2018d1_num_modes >= TPA2018_MODE_PLAYBACK) {
+			offset = TPA2018_MODE_PLAYBACK * TPA2018D1_CMD_LEN;
+			memcpy(spk_amp_cfg, config_data + offset,
+					TPA2018D1_CMD_LEN);
+		}
+		break;
+
+	default:
+		pr_err("%s: invalid command %d\n", __func__, _IOC_NR(cmd));
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&spk_amp_lock);
+	return rc;
+}
+
+static struct file_operations tpa2018d1_fops = {
+	.owner = THIS_MODULE,
+	.open = tpa2018d1_open,
+	.release = tpa2018d1_release,
+	.ioctl = tpa2018d1_ioctl,
+};
+
+static struct miscdevice tpa2018d1_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "tpa2018d1",
+	.fops = &tpa2018d1_fops,
+};
+
+void tpa2018d1_set_speaker_amp(int on)
+{
+	if (!pdata) {
+		pr_err("%s: no platform data!\n", __func__);
+		return;
+	}
+	mutex_lock(&spk_amp_lock);
+	if (on && !is_on) {
+		gpio_set_value(pdata->gpio_tpa2018_spk_en, 1);
+		msleep(5); /* According to TPA2018D1 Spec */
+
+		if (tpa2018_i2c_write(spk_amp_cfg, sizeof(spk_amp_cfg)) == 0) {
+			is_on = 1;
+			pr_info("%s: ON\n", __func__);
+		}
+	} else if (!on && is_on) {
+		if (tpa2018_i2c_write(spk_amp_off, sizeof(spk_amp_off)) == 0) {
+			is_on = 0;
+			msleep(2);
+			gpio_set_value(pdata->gpio_tpa2018_spk_en, 0);
+			pr_info("%s: OFF\n", __func__);
+		}
+	}
+	mutex_unlock(&spk_amp_lock);
+}
+
+static int tpa2018d1_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int ret = 0;
+
+	pdata = client->dev.platform_data;
+
+	if (!pdata) {
+		ret = -EINVAL;
+		pr_err("%s: platform data is NULL\n", __func__);
+		goto err_no_pdata;
+	}
+
+	this_client = client;
+
+	ret = gpio_request(pdata->gpio_tpa2018_spk_en, "tpa2018");
+	if (ret < 0) {
+		pr_err("%s: gpio request aud_spk_en pin failed\n", __func__);
+		goto err_free_gpio;
+	}
+
+	ret = gpio_direction_output(pdata->gpio_tpa2018_spk_en, 1);
+	if (ret < 0) {
+		pr_err("%s: request aud_spk_en gpio direction failed\n",
+			__func__);
+		goto err_free_gpio;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s: i2c check functionality error\n", __func__);
+		ret = -ENODEV;
+		goto err_free_gpio;
+	}
+
+	gpio_set_value(pdata->gpio_tpa2018_spk_en, 0); /* Default Low */
+
+	ret = misc_register(&tpa2018d1_device);
+	if (ret) {
+		pr_err("%s: tpa2018d1_device register failed\n", __func__);
+		goto err_free_gpio;
+	}
+	memcpy(spk_amp_cfg, spk_amp_on, sizeof(spk_amp_on));
+	return 0;
+
+err_free_gpio:
+	gpio_free(pdata->gpio_tpa2018_spk_en);
+err_no_pdata:
+	return ret;
+}
+
+static int tpa2018d1_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	return 0;
+}
+
+static int tpa2018d1_resume(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id tpa2018d1_id[] = {
+	{ TPA2018D1_I2C_NAME, 0 },
+	{ }
+};
+
+static struct i2c_driver tpa2018d1_driver = {
+	.probe = tpa2018d1_probe,
+	.suspend = tpa2018d1_suspend,
+	.resume = tpa2018d1_resume,
+	.id_table = tpa2018d1_id,
+	.driver = {
+		.name = TPA2018D1_I2C_NAME,
+	},
+};
+
+static int __init tpa2018d1_init(void)
+{
+	pr_info("%s\n", __func__);
+	return i2c_add_driver(&tpa2018d1_driver);
+}
+
+module_init(tpa2018d1_init);
+
+MODULE_DESCRIPTION("tpa2018d1 speaker amp driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-mahimahi-tpa2018d1.h b/arch/arm/mach-msm/board-mahimahi-tpa2018d1.h
new file mode 100644
index 0000000..dc11012
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-tpa2018d1.h
@@ -0,0 +1,35 @@
+/* include/linux/tpa2018d1.h - tpa2018d1 speaker amplifier driver
+ *
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+#ifndef __ASM_ARM_ARCH_TPA2018D1_H
+#define __ASM_ARM_ARCH_TPA2018D1_H
+
+#define TPA2018D1_I2C_NAME "tpa2018d1"
+#define TPA2018D1_CMD_LEN 8
+
+struct tpa2018d1_platform_data {
+	uint32_t gpio_tpa2018_spk_en;
+};
+
+struct tpa2018d1_config_data {
+	unsigned char *cmd_data;  /* [mode][cmd_len][cmds..] */
+	unsigned int mode_num;
+	unsigned int data_len;
+};
+
+extern void tpa2018d1_set_speaker_amp(int on);
+
+#endif /* __ASM_ARM_ARCH_TPA2018D1_H */
diff --git a/arch/arm/mach-msm/board-mahimahi-wifi.c b/arch/arm/mach-msm/board-mahimahi-wifi.c
new file mode 100644
index 0000000..8cd2476
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-wifi.c
@@ -0,0 +1,146 @@
+/* linux/arch/arm/mach-msm/board-mahimahi-wifi.c
+*/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/mach-types.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/skbuff.h>
+#include <linux/wlan_plat.h>
+
+#include "board-mahimahi.h"
+
+int mahimahi_wifi_power(int on);
+int mahimahi_wifi_reset(int on);
+int mahimahi_wifi_set_carddetect(int on);
+
+#define PREALLOC_WLAN_NUMBER_OF_SECTIONS	4
+#define PREALLOC_WLAN_NUMBER_OF_BUFFERS		160
+#define PREALLOC_WLAN_SECTION_HEADER		24
+
+#define WLAN_SECTION_SIZE_0	(PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
+#define WLAN_SECTION_SIZE_1	(PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
+#define WLAN_SECTION_SIZE_2	(PREALLOC_WLAN_NUMBER_OF_BUFFERS * 512)
+#define WLAN_SECTION_SIZE_3	(PREALLOC_WLAN_NUMBER_OF_BUFFERS * 1024)
+
+#define WLAN_SKB_BUF_NUM	16
+
+static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
+
+typedef struct wifi_mem_prealloc_struct {
+	void *mem_ptr;
+	unsigned long size;
+} wifi_mem_prealloc_t;
+
+static wifi_mem_prealloc_t wifi_mem_array[PREALLOC_WLAN_NUMBER_OF_SECTIONS] = {
+	{ NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER) },
+	{ NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER) },
+	{ NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER) },
+	{ NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER) }
+};
+
+static void *mahimahi_wifi_mem_prealloc(int section, unsigned long size)
+{
+	if (section == PREALLOC_WLAN_NUMBER_OF_SECTIONS)
+		return wlan_static_skb;
+	if ((section < 0) || (section > PREALLOC_WLAN_NUMBER_OF_SECTIONS))
+		return NULL;
+	if (wifi_mem_array[section].size < size)
+		return NULL;
+	return wifi_mem_array[section].mem_ptr;
+}
+
+int __init mahimahi_init_wifi_mem(void)
+{
+	int i;
+
+	for(i=0;( i < WLAN_SKB_BUF_NUM );i++) {
+		if (i < (WLAN_SKB_BUF_NUM/2))
+			wlan_static_skb[i] = dev_alloc_skb(4096);
+		else
+			wlan_static_skb[i] = dev_alloc_skb(8192);
+	}
+	for(i=0;( i < PREALLOC_WLAN_NUMBER_OF_SECTIONS );i++) {
+		wifi_mem_array[i].mem_ptr = kmalloc(wifi_mem_array[i].size,
+							GFP_KERNEL);
+		if (wifi_mem_array[i].mem_ptr == NULL)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+static struct resource mahimahi_wifi_resources[] = {
+	[0] = {
+		.name		= "bcm4329_wlan_irq",
+		.start		= MSM_GPIO_TO_INT(MAHIMAHI_GPIO_WIFI_IRQ),
+		.end		= MSM_GPIO_TO_INT(MAHIMAHI_GPIO_WIFI_IRQ),
+		.flags          = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE,
+	},
+};
+
+static struct wifi_platform_data mahimahi_wifi_control = {
+	.set_power      = mahimahi_wifi_power,
+	.set_reset      = mahimahi_wifi_reset,
+	.set_carddetect = mahimahi_wifi_set_carddetect,
+	.mem_prealloc	= mahimahi_wifi_mem_prealloc,
+};
+
+static struct platform_device mahimahi_wifi_device = {
+        .name           = "bcm4329_wlan",
+        .id             = 1,
+        .num_resources  = ARRAY_SIZE(mahimahi_wifi_resources),
+        .resource       = mahimahi_wifi_resources,
+        .dev            = {
+                .platform_data = &mahimahi_wifi_control,
+        },
+};
+
+extern unsigned char *get_wifi_nvs_ram(void);
+extern int wifi_calibration_size_set(void);
+
+static unsigned mahimahi_wifi_update_nvs(char *str, int add_flag)
+{
+#define NVS_LEN_OFFSET		0x0C
+#define NVS_DATA_OFFSET		0x40
+	unsigned char *ptr;
+	unsigned len;
+
+	if (!str)
+		return -EINVAL;
+	ptr = get_wifi_nvs_ram();
+	/* Size in format LE assumed */
+	memcpy(&len, ptr + NVS_LEN_OFFSET, sizeof(len));
+	/* if the last byte in NVRAM is 0, trim it */
+	if (ptr[NVS_DATA_OFFSET + len - 1] == 0)
+		len -= 1;
+	if (add_flag) {
+		strcpy(ptr + NVS_DATA_OFFSET + len, str);
+		len += strlen(str);
+	} else {
+		if (strnstr(ptr + NVS_DATA_OFFSET, str, len))
+			len -= strlen(str);
+	}
+	memcpy(ptr + NVS_LEN_OFFSET, &len, sizeof(len));
+	wifi_calibration_size_set();
+	return 0;
+}
+
+static int __init mahimahi_wifi_init(void)
+{
+	int ret;
+
+	if (!machine_is_mahimahi())
+		return 0;
+
+	printk("%s: start\n", __func__);
+	mahimahi_wifi_update_nvs("sd_oobonly=1\r\n", 0);
+	mahimahi_wifi_update_nvs("btc_params70=0x32\r\n", 1);
+	mahimahi_init_wifi_mem();
+	ret = platform_device_register(&mahimahi_wifi_device);
+        return ret;
+}
+
+late_initcall(mahimahi_wifi_init);
diff --git a/arch/arm/mach-msm/board-mahimahi.c b/arch/arm/mach-msm/board-mahimahi.c
index bcbefdf..23285d5 100644
--- a/arch/arm/mach-msm/board-mahimahi.c
+++ b/arch/arm/mach-msm/board-mahimahi.c
@@ -15,13 +15,27 @@
  *
  */
 
+#include <linux/cy8c_tmg_ts.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
+#include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/usb/android_composite.h>
+#include <linux/usb/f_accessory.h>
+
+#include <linux/android_pmem.h>
+#include <linux/synaptics_i2c_rmi.h>
+#include <linux/a1026.h>
+#include <linux/capella_cm3602.h>
+#include <linux/akm8973.h>
+#include <linux/regulator/machine.h>
+#include <linux/ds2784_battery.h>
+#include <../../../drivers/staging/android/timed_gpio.h>
+#include <../../../drivers/w1/w1.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -30,27 +44,1120 @@
 
 #include <mach/board.h>
 #include <mach/hardware.h>
+#include <mach/msm_hsusb.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_serial_debugger.h>
 #include <mach/system.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/bcm_bt_lpm.h>
+#include <mach/msm_smd.h>
 
 #include "board-mahimahi.h"
 #include "devices.h"
 #include "proc_comm.h"
+#include "board-mahimahi-flashlight.h"
+#include "board-mahimahi-tpa2018d1.h"
+#include "board-mahimahi-smb329.h"
 
 static uint debug_uart;
 
 module_param_named(debug_uart, debug_uart, uint, 0);
 
+extern void notify_usb_connected(int);
+extern void msm_init_pmic_vibrator(void);
+extern void __init mahimahi_audio_init(void);
+
+extern int microp_headset_has_mic(void);
+
+static void config_gpio_table(uint32_t *table, int len);
+
+static int mahimahi_phy_init_seq[] = {
+	0x0C, 0x31,
+	0x31, 0x32,
+	0x1D, 0x0D,
+	0x1D, 0x10,
+	-1 };
+
+static void mahimahi_usb_phy_reset(void)
+{
+	u32 id;
+	int ret;
+
+	id = PCOM_CLKRGM_APPS_RESET_USB_PHY;
+	ret = msm_proc_comm(PCOM_CLK_REGIME_SEC_RESET_ASSERT, &id, NULL);
+	if (ret) {
+		pr_err("%s: Cannot assert (%d)\n", __func__, ret);
+		return;
+	}
+
+	msleep(1);
+
+	id = PCOM_CLKRGM_APPS_RESET_USB_PHY;
+	ret = msm_proc_comm(PCOM_CLK_REGIME_SEC_RESET_DEASSERT, &id, NULL);
+	if (ret) {
+		pr_err("%s: Cannot assert (%d)\n", __func__, ret);
+		return;
+	}
+}
+
+static void mahimahi_usb_hw_reset(bool enable)
+{
+	u32 id;
+	int ret;
+	u32 func;
+
+	id = PCOM_CLKRGM_APPS_RESET_USBH;
+	if (enable)
+		func = PCOM_CLK_REGIME_SEC_RESET_ASSERT;
+	else
+		func = PCOM_CLK_REGIME_SEC_RESET_DEASSERT;
+	ret = msm_proc_comm(func, &id, NULL);
+	if (ret)
+		pr_err("%s: Cannot set reset to %d (%d)\n", __func__, enable,
+		       ret);
+}
+
+
+static struct msm_hsusb_platform_data msm_hsusb_pdata = {
+	.phy_init_seq		= mahimahi_phy_init_seq,
+	.phy_reset		= mahimahi_usb_phy_reset,
+	.hw_reset		= mahimahi_usb_hw_reset,
+	.usb_connected		= notify_usb_connected,
+};
+
+static char *usb_functions_ums[] = {
+	"usb_mass_storage",
+};
+
+static char *usb_functions_ums_adb[] = {
+	"usb_mass_storage",
+	"adb",
+};
+
+static char *usb_functions_rndis[] = {
+	"rndis",
+};
+
+static char *usb_functions_rndis_adb[] = {
+	"rndis",
+	"adb",
+};
+
+#ifdef CONFIG_USB_ANDROID_ACCESSORY
+static char *usb_functions_accessory[] = { "accessory" };
+static char *usb_functions_accessory_adb[] = { "accessory", "adb" };
+#endif
+
+#ifdef CONFIG_USB_ANDROID_DIAG
+static char *usb_functions_adb_diag[] = {
+	"usb_mass_storage",
+	"adb",
+	"diag",
+};
+#endif
+
+static char *usb_functions_all[] = {
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	"rndis",
+#endif
+#ifdef CONFIG_USB_ANDROID_ACCESSORY
+	"accessory",
+#endif
+	"usb_mass_storage",
+	"adb",
+#ifdef CONFIG_USB_ANDROID_ACM
+	"acm",
+#endif
+#ifdef CONFIG_USB_ANDROID_DIAG
+	"diag",
+#endif
+};
+
+static struct android_usb_product usb_products[] = {
+	{
+		.product_id	= 0x4e11,
+		.num_functions	= ARRAY_SIZE(usb_functions_ums),
+		.functions	= usb_functions_ums,
+	},
+	{
+		.product_id	= 0x4e12,
+		.num_functions	= ARRAY_SIZE(usb_functions_ums_adb),
+		.functions	= usb_functions_ums_adb,
+	},
+	{
+		.product_id	= 0x4e13,
+		.num_functions	= ARRAY_SIZE(usb_functions_rndis),
+		.functions	= usb_functions_rndis,
+	},
+	{
+		.product_id	= 0x4e14,
+		.num_functions	= ARRAY_SIZE(usb_functions_rndis_adb),
+		.functions	= usb_functions_rndis_adb,
+	},
+#ifdef CONFIG_USB_ANDROID_ACCESSORY
+	{
+		.vendor_id	= USB_ACCESSORY_VENDOR_ID,
+		.product_id	= USB_ACCESSORY_PRODUCT_ID,
+		.num_functions	= ARRAY_SIZE(usb_functions_accessory),
+		.functions	= usb_functions_accessory,
+	},
+	{
+		.vendor_id	= USB_ACCESSORY_VENDOR_ID,
+		.product_id	= USB_ACCESSORY_ADB_PRODUCT_ID,
+		.num_functions	= ARRAY_SIZE(usb_functions_accessory_adb),
+		.functions	= usb_functions_accessory_adb,
+	},
+#endif
+#ifdef CONFIG_USB_ANDROID_DIAG
+	{
+		.product_id	= 0x4e17,
+		.num_functions	= ARRAY_SIZE(usb_functions_adb_diag),
+		.functions	= usb_functions_adb_diag,
+	},
+#endif
+};
+
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+	.nluns		= 1,
+	.vendor		= "Google, Inc.",
+	.product	= "Nexus One",
+	.release	= 0x0100,
+};
+
+static struct platform_device usb_mass_storage_device = {
+	.name	= "usb_mass_storage",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mass_storage_pdata,
+	},
+};
+
+#ifdef CONFIG_USB_ANDROID_RNDIS
+static struct usb_ether_platform_data rndis_pdata = {
+	/* ethaddr is filled by board_serialno_setup */
+	.vendorID	= 0x18d1,
+	.vendorDescr	= "Google, Inc.",
+};
+
+static struct platform_device rndis_device = {
+	.name	= "rndis",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &rndis_pdata,
+	},
+};
+#endif
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.vendor_id	= 0x18d1,
+	.product_id	= 0x4e11,
+	.version	= 0x0100,
+	.product_name		= "Nexus One",
+	.manufacturer_name	= "Google, Inc.",
+	.num_products = ARRAY_SIZE(usb_products),
+	.products = usb_products,
+	.num_functions = ARRAY_SIZE(usb_functions_all),
+	.functions = usb_functions_all,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+static struct platform_device mahimahi_rfkill = {
+	.name = "mahimahi_rfkill",
+	.id = -1,
+};
+
+static struct resource msm_kgsl_resources[] = {
+	{
+		.name	= "kgsl_reg_memory",
+		.start	= MSM_GPU_REG_PHYS,
+		.end	= MSM_GPU_REG_PHYS + MSM_GPU_REG_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "kgsl_phys_memory",
+		.start	= MSM_GPU_MEM_BASE,
+		.end	= MSM_GPU_MEM_BASE + MSM_GPU_MEM_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_GRAPHICS,
+		.end	= INT_GRAPHICS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+#define PWR_RAIL_GRP_CLK		8
+static int mahimahi_kgsl_power_rail_mode(int follow_clk)
+{
+	int mode = follow_clk ? 0 : 1;
+	int rail_id = PWR_RAIL_GRP_CLK;
+
+	return msm_proc_comm(PCOM_CLKCTL_RPC_RAIL_CONTROL, &rail_id, &mode);
+}
+
+static int mahimahi_kgsl_power(bool on)
+{
+	int cmd;
+	int rail_id = PWR_RAIL_GRP_CLK;
+
+	cmd = on ? PCOM_CLKCTL_RPC_RAIL_ENABLE : PCOM_CLKCTL_RPC_RAIL_DISABLE;
+	return msm_proc_comm(cmd, &rail_id, NULL);
+}
+
+static struct platform_device msm_kgsl_device = {
+	.name		= "kgsl",
+	.id		= -1,
+	.resource	= msm_kgsl_resources,
+	.num_resources	= ARRAY_SIZE(msm_kgsl_resources),
+};
+
+static struct android_pmem_platform_data mdp_pmem_pdata = {
+	.name		= "pmem",
+	.start		= MSM_PMEM_MDP_BASE,
+	.size		= MSM_PMEM_MDP_SIZE,
+	.no_allocator	= 0,
+	.cached		= 1,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+	.name		= "pmem_adsp",
+	.start		= MSM_PMEM_ADSP_BASE,
+	.size		= MSM_PMEM_ADSP_SIZE,
+	.no_allocator	= 0,
+	.cached		= 1,
+};
+
+static struct android_pmem_platform_data android_pmem_camera_pdata = {
+	.name		= "pmem_camera",
+	.start		= MSM_PMEM_CAMERA_BASE,
+	.size		= MSM_PMEM_CAMERA_SIZE,
+	.no_allocator	= 1,
+	.cached		= 1,
+};
+
+static struct platform_device android_pmem_mdp_device = {
+	.name		= "android_pmem",
+	.id		= 0,
+	.dev		= {
+		.platform_data = &mdp_pmem_pdata
+	},
+};
+
+static struct platform_device android_pmem_adsp_device = {
+	.name		= "android_pmem",
+	.id		= 1,
+	.dev		= {
+		.platform_data = &android_pmem_adsp_pdata,
+	},
+};
+
+static struct platform_device android_pmem_camera_device = {
+	.name		= "android_pmem",
+	.id		= 2,
+	.dev		= {
+		.platform_data = &android_pmem_camera_pdata,
+	},
+};
+
+static struct resource ram_console_resources[] = {
+	{
+		.start	= MSM_RAM_CONSOLE_BASE,
+		.end	= MSM_RAM_CONSOLE_BASE + MSM_RAM_CONSOLE_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device ram_console_device = {
+	.name		= "ram_console",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ram_console_resources),
+	.resource	= ram_console_resources,
+};
+
+static int mahimahi_ts_power(int on)
+{
+	pr_info("%s: power %d\n", __func__, on);
+
+	if (on) {
+		/* level shifter should be off */
+		gpio_set_value(MAHIMAHI_GPIO_TP_EN, 1);
+		msleep(120);
+		/* enable touch panel level shift */
+		gpio_set_value(MAHIMAHI_GPIO_TP_LS_EN, 1);
+		msleep(3);
+	} else {
+		gpio_set_value(MAHIMAHI_GPIO_TP_LS_EN, 0);
+		gpio_set_value(MAHIMAHI_GPIO_TP_EN, 0);
+		udelay(50);
+	}
+
+	return 0;
+}
+
+struct cy8c_i2c_platform_data mahimahi_cy8c_ts_data = {
+	.version = 0x0001,
+	.abs_x_min = 0,
+	.abs_x_max = 479,
+	.abs_y_min = 0,
+	.abs_y_max = 799,
+	.abs_pressure_min = 0,
+	.abs_pressure_max = 255,
+	.abs_width_min = 0,
+	.abs_width_max = 10,
+	.power = mahimahi_ts_power,
+};
+
+static struct synaptics_i2c_rmi_platform_data mahimahi_synaptics_ts_data[] = {
+	{
+		.version = 0x105,
+		.power = mahimahi_ts_power,
+		.flags = SYNAPTICS_FLIP_Y,
+		.inactive_left = -15 * 0x10000 / 480,
+		.inactive_right = -15 * 0x10000 / 480,
+		.inactive_top = -15 * 0x10000 / 800,
+		.inactive_bottom = -50 * 0x10000 / 800,
+		.sensitivity_adjust = 9,
+	},
+	{
+		.flags = SYNAPTICS_FLIP_Y,
+		.inactive_left = -15 * 0x10000 / 480,
+		.inactive_right = -15 * 0x10000 / 480,
+		.inactive_top = -15 * 0x10000 / 800,
+		.inactive_bottom = -40 * 0x10000 / 800,
+		.sensitivity_adjust = 12,
+	},
+};
+
+static struct a1026_platform_data a1026_data = {
+	.gpio_a1026_micsel = MAHIMAHI_AUD_MICPATH_SEL,
+	.gpio_a1026_wakeup = MAHIMAHI_AUD_A1026_WAKEUP,
+	.gpio_a1026_reset = MAHIMAHI_AUD_A1026_RESET,
+	.gpio_a1026_clk = MAHIMAHI_AUD_A1026_CLK,
+	/*.gpio_a1026_int = MAHIMAHI_AUD_A1026_INT,*/
+};
+
+static struct akm8973_platform_data compass_platform_data = {
+	.layouts = MAHIMAHI_LAYOUTS,
+	.project_name = MAHIMAHI_PROJECT_NAME,
+	.reset = MAHIMAHI_GPIO_COMPASS_RST_N,
+	.intr = MAHIMAHI_GPIO_COMPASS_INT_N,
+};
+
+static struct regulator_consumer_supply tps65023_dcdc1_supplies[] = {
+	{
+		.supply = "acpu_vcore",
+	},
+};
+
+static struct regulator_init_data tps65023_data[5] = {
+	{
+		.constraints = {
+			.name = "dcdc1", /* VREG_MSMC2_1V29 */
+			.min_uV = 1000000,
+			.max_uV = 1300000,
+			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+		},
+		.consumer_supplies = tps65023_dcdc1_supplies,
+		.num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc1_supplies),
+	},
+	/* dummy values for unused regulators to not crash driver: */
+	{
+		.constraints = {
+			.name = "dcdc2", /* VREG_MSMC1_1V26 */
+			.min_uV = 1260000,
+			.max_uV = 1260000,
+		},
+	},
+	{
+		.constraints = {
+			.name = "dcdc3", /* unused */
+			.min_uV = 800000,
+			.max_uV = 3300000,
+		},
+	},
+	{
+		.constraints = {
+			.name = "ldo1", /* unused */
+			.min_uV = 1000000,
+			.max_uV = 3150000,
+		},
+	},
+	{
+		.constraints = {
+			.name = "ldo2", /* V_USBPHY_3V3 */
+			.min_uV = 3300000,
+			.max_uV = 3300000,
+		},
+	},
+};
+
+
+static void ds2482_set_slp_n(unsigned n)
+{
+	gpio_direction_output(MAHIMAHI_GPIO_DS2482_SLP_N, n);
+}
+
+static struct tpa2018d1_platform_data tpa2018_data = {
+	.gpio_tpa2018_spk_en = MAHIMAHI_CDMA_GPIO_AUD_SPK_AMP_EN,
+};
+
+static struct i2c_board_info base_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("ds2482", 0x30 >> 1),
+		.platform_data = ds2482_set_slp_n,
+	},
+	{
+		I2C_BOARD_INFO("cy8c-tmg-ts", 0x34),
+		.platform_data = &mahimahi_cy8c_ts_data,
+		.irq = MSM_GPIO_TO_INT(MAHIMAHI_GPIO_TP_INT_N),
+	},
+	{
+		I2C_BOARD_INFO(SYNAPTICS_I2C_RMI_NAME, 0x40),
+		.platform_data = mahimahi_synaptics_ts_data,
+		.irq = MSM_GPIO_TO_INT(MAHIMAHI_GPIO_TP_INT_N)
+	},
+	{
+		I2C_BOARD_INFO("mahimahi-microp", 0x66),
+		.irq = MSM_GPIO_TO_INT(MAHIMAHI_GPIO_UP_INT_N)
+	},
+	{
+		I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1),
+	},
+	{
+		I2C_BOARD_INFO("tps65023", 0x48),
+		.platform_data = tps65023_data,
+	},
+};
+
+static struct i2c_board_info rev0_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO(AKM8973_I2C_NAME, 0x1C),
+		.platform_data = &compass_platform_data,
+		.irq = MSM_GPIO_TO_INT(MAHIMAHI_REV0_GPIO_COMPASS_INT_N),
+	},
+};
+
+static struct i2c_board_info rev1_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("audience_a1026", 0x3E),
+		.platform_data = &a1026_data,
+		/*.irq = MSM_GPIO_TO_INT(MAHIMAHI_AUD_A1026_INT)*/
+	},
+	{
+		I2C_BOARD_INFO(AKM8973_I2C_NAME, 0x1C),
+		.platform_data = &compass_platform_data,
+		.irq = MSM_GPIO_TO_INT(MAHIMAHI_GPIO_COMPASS_INT_N),
+	},
+};
+
+static struct i2c_board_info rev_CX_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("tpa2018d1", 0x58),
+		.platform_data = &tpa2018_data,
+	},
+	{
+		I2C_BOARD_INFO("smb329", 0x6E >> 1),
+	},
+};
+
+static void config_gpio_table(uint32_t *table, int len);
+
+static uint32_t camera_off_gpio_table[] = {
+	/* CAMERA */
+	PCOM_GPIO_CFG(0, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT0 */
+	PCOM_GPIO_CFG(1, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(2, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(3, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(4, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT4 */
+	PCOM_GPIO_CFG(5, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT5 */
+	PCOM_GPIO_CFG(6, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT6 */
+	PCOM_GPIO_CFG(7, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT7 */
+	PCOM_GPIO_CFG(8, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT8 */
+	PCOM_GPIO_CFG(9, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT9 */
+	PCOM_GPIO_CFG(10, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT10 */
+	PCOM_GPIO_CFG(11, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* DAT11 */
+	PCOM_GPIO_CFG(12, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* PCLK */
+	PCOM_GPIO_CFG(13, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* HSYNC */
+	PCOM_GPIO_CFG(14, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), /* VSYNC */
+	PCOM_GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_table[] = {
+	/* CAMERA */
+	PCOM_GPIO_CFG(0, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT0 */
+	PCOM_GPIO_CFG(1, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT1 */
+	PCOM_GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT2 */
+	PCOM_GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT3 */
+	PCOM_GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT4 */
+	PCOM_GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT5 */
+	PCOM_GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT6 */
+	PCOM_GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT7 */
+	PCOM_GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT8 */
+	PCOM_GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT9 */
+	PCOM_GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT10 */
+	PCOM_GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* DAT11 */
+	PCOM_GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_16MA), /* PCLK */
+	PCOM_GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* HSYNC */
+	PCOM_GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), /* VSYNC */
+	PCOM_GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* MCLK */
+};
+
+void config_camera_on_gpios(void)
+{
+	config_gpio_table(camera_on_gpio_table,
+		ARRAY_SIZE(camera_on_gpio_table));
+}
+
+void config_camera_off_gpios(void)
+{
+	config_gpio_table(camera_off_gpio_table,
+		ARRAY_SIZE(camera_off_gpio_table));
+}
+
+static struct resource msm_camera_resources[] = {
+	{
+		.start	= MSM_VFE_PHYS,
+		.end	= MSM_VFE_PHYS + MSM_VFE_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_VFE,
+		 INT_VFE,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct msm_camera_device_platform_data msm_camera_device_data = {
+	.camera_gpio_on  = config_camera_on_gpios,
+	.camera_gpio_off = config_camera_off_gpios,
+	.ioext.mdcphy = MSM_MDC_PHYS,
+	.ioext.mdcsz  = MSM_MDC_SIZE,
+	.ioext.appphy = MSM_CLK_CTL_PHYS,
+	.ioext.appsz  = MSM_CLK_CTL_SIZE,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k3e2fx_data = {
+	.sensor_name = "s5k3e2fx",
+	.sensor_reset = 144, /* CAM1_RST */
+	.sensor_pwd = 143,  /* CAM1_PWDN, enabled in a9 */
+	/*.vcm_pwd = 31, */  /* CAM1_VCM_EN, enabled in a9 */
+	.pdata = &msm_camera_device_data,
+	.resource = msm_camera_resources,
+	.num_resources = ARRAY_SIZE(msm_camera_resources),
+	.camera_flash = flashlight_control,
+	.num_flash_levels = FLASHLIGHT_NUM,
+};
+
+static struct platform_device msm_camera_sensor_s5k3e2fx = {
+	.name      = "msm_camera_s5k3e2fx",
+	.dev      = {
+		.platform_data = &msm_camera_sensor_s5k3e2fx_data,
+	},
+};
+
+static int capella_cm3602_power(int on)
+{
+	/* TODO eolsen Add Voltage reg control */
+	if (on) {
+		gpio_direction_output(MAHIMAHI_GPIO_PROXIMITY_EN, 0);
+	} else {
+		gpio_direction_output(MAHIMAHI_GPIO_PROXIMITY_EN, 1);
+	}
+
+	return 0;
+}
+
+
+static struct capella_cm3602_platform_data capella_cm3602_pdata = {
+	.power = capella_cm3602_power,
+	.p_out = MAHIMAHI_GPIO_PROXIMITY_INT_N
+};
+
+static struct platform_device capella_cm3602 = {
+	.name = CAPELLA_CM3602,
+	.id = -1,
+	.dev = {
+		.platform_data = &capella_cm3602_pdata
+	}
+};
+
+static uint32_t flashlight_gpio_table[] = {
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_FLASHLIGHT_TORCH, 0, GPIO_OUTPUT,
+						GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_FLASHLIGHT_FLASH, 0, GPIO_OUTPUT,
+						GPIO_NO_PULL, GPIO_2MA),
+};
+
+static uint32_t flashlight_gpio_table_rev_CX[] = {
+	PCOM_GPIO_CFG(MAHIMAHI_CDMA_GPIO_FLASHLIGHT_TORCH, 0, GPIO_OUTPUT,
+						GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_FLASHLIGHT_FLASH, 0, GPIO_OUTPUT,
+						GPIO_NO_PULL, GPIO_2MA),
+};
+
+
+static int config_mahimahi_flashlight_gpios(void)
+{
+	if (is_cdma_version(system_rev)) {
+		config_gpio_table(flashlight_gpio_table_rev_CX,
+			ARRAY_SIZE(flashlight_gpio_table_rev_CX));
+	} else {
+		config_gpio_table(flashlight_gpio_table,
+			ARRAY_SIZE(flashlight_gpio_table));
+	}
+	return 0;
+}
+
+static struct flashlight_platform_data mahimahi_flashlight_data = {
+	.gpio_init  = config_mahimahi_flashlight_gpios,
+	.torch = MAHIMAHI_GPIO_FLASHLIGHT_TORCH,
+	.flash = MAHIMAHI_GPIO_FLASHLIGHT_FLASH,
+	.flash_duration_ms = 600
+};
+
+static struct platform_device mahimahi_flashlight_device = {
+	.name = "flashlight",
+	.dev = {
+		.platform_data  = &mahimahi_flashlight_data,
+	},
+};
+static struct timed_gpio timed_gpios[] = {
+	{
+		.name = "vibrator",
+		.gpio = MAHIMAHI_GPIO_VIBRATOR_ON,
+		.max_timeout = 15000,
+	},
+};
+
+static struct timed_gpio_platform_data timed_gpio_data = {
+	.num_gpios	= ARRAY_SIZE(timed_gpios),
+	.gpios		= timed_gpios,
+};
+
+static struct platform_device mahimahi_timed_gpios = {
+	.name		= "timed-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &timed_gpio_data,
+	},
+};
+
+static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = {
+	.rx_wakeup_irq = -1,
+	.inject_rx_on_wakeup = 0,
+	.exit_lpm_cb = bcm_bt_lpm_exit_lpm_locked,
+};
+
+static struct bcm_bt_lpm_platform_data bcm_bt_lpm_pdata = {
+	.gpio_wake = MAHIMAHI_GPIO_BT_WAKE,
+	.gpio_host_wake = MAHIMAHI_GPIO_BT_HOST_WAKE,
+	.request_clock_off_locked = msm_hs_request_clock_off_locked,
+	.request_clock_on_locked = msm_hs_request_clock_on_locked,
+};
+
+struct platform_device bcm_bt_lpm_device = {
+	.name = "bcm_bt_lpm",
+	.id = 0,
+	.dev = {
+		.platform_data = &bcm_bt_lpm_pdata,
+	},
+};
+
+static int ds2784_charge(int on, int fast)
+{
+	if (is_cdma_version(system_rev)) {
+		if (!on)
+			smb329_set_charger_ctrl(SMB329_DISABLE_CHG);
+		else
+			smb329_set_charger_ctrl(fast ? SMB329_ENABLE_FAST_CHG : SMB329_ENABLE_SLOW_CHG);
+	}
+	else
+		gpio_direction_output(MAHIMAHI_GPIO_BATTERY_CHARGER_CURRENT, !!fast);
+	gpio_direction_output(MAHIMAHI_GPIO_BATTERY_CHARGER_EN, !on);
+	return 0;
+}
+
+static int w1_ds2784_add_slave(struct w1_slave *sl)
+{
+	struct dd {
+		struct platform_device pdev;
+		struct ds2784_platform_data pdata;
+	} *p;
+
+	int rc;
+
+	p = kzalloc(sizeof(struct dd), GFP_KERNEL);
+	if (!p) {
+		pr_err("%s: out of memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	rc = gpio_request(MAHIMAHI_GPIO_BATTERY_CHARGER_EN, "charger_en");
+	if (rc < 0) {
+		pr_err("%s: gpio_request(%d) failed: %d\n", __func__,
+			MAHIMAHI_GPIO_BATTERY_CHARGER_EN, rc);
+		kfree(p);
+		return rc;
+	}
+
+	if (!is_cdma_version(system_rev)) {
+		rc = gpio_request(MAHIMAHI_GPIO_BATTERY_CHARGER_CURRENT, "charger_current");
+		if (rc < 0) {
+			pr_err("%s: gpio_request(%d) failed: %d\n", __func__,
+				MAHIMAHI_GPIO_BATTERY_CHARGER_CURRENT, rc);
+			gpio_free(MAHIMAHI_GPIO_BATTERY_CHARGER_EN);
+			kfree(p);
+			return rc;
+		}
+	}
+
+	p->pdev.name = "ds2784-battery";
+	p->pdev.id = -1;
+	p->pdev.dev.platform_data = &p->pdata;
+	p->pdata.charge = ds2784_charge;
+	p->pdata.w1_slave = sl;
+
+	platform_device_register(&p->pdev);
+
+	return 0;
+}
+
+static struct w1_family_ops w1_ds2784_fops = {
+	.add_slave = w1_ds2784_add_slave,
+};
+
+static struct w1_family w1_ds2784_family = {
+	.fid = W1_FAMILY_DS2784,
+	.fops = &w1_ds2784_fops,
+};
+
+static int __init ds2784_battery_init(void)
+{
+	return w1_register_family(&w1_ds2784_family);
+}
+
 static struct platform_device *devices[] __initdata = {
 #if !defined(CONFIG_MSM_SERIAL_DEBUGGER)
 	&msm_device_uart1,
 #endif
+	&bcm_bt_lpm_device,
 	&msm_device_uart_dm1,
+	&ram_console_device,
+	&mahimahi_rfkill,
+	&msm_device_smd,
 	&msm_device_nand,
+	&msm_device_hsusb,
+	&usb_mass_storage_device,
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	&rndis_device,
+#endif
+	&android_usb_device,
+	&android_pmem_mdp_device,
+	&android_pmem_adsp_device,
+	&android_pmem_camera_device,
+	&msm_kgsl_device,
+	&msm_device_i2c,
+	&capella_cm3602,
+	&msm_camera_sensor_s5k3e2fx,
+	&mahimahi_flashlight_device,
+};
+
+
+static uint32_t bt_gpio_table[] = {
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_UART1_RTS, 2, GPIO_OUTPUT,
+		      GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_UART1_CTS, 2, GPIO_INPUT,
+		      GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_UART1_RX, 2, GPIO_INPUT,
+		      GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_UART1_TX, 2, GPIO_OUTPUT,
+		      GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_RESET_N, 0, GPIO_OUTPUT,
+		      GPIO_PULL_DOWN, GPIO_4MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_SHUTDOWN_N, 0, GPIO_OUTPUT,
+		      GPIO_PULL_DOWN, GPIO_4MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_WAKE, 0, GPIO_OUTPUT,
+		      GPIO_PULL_DOWN, GPIO_4MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_HOST_WAKE, 0, GPIO_INPUT,
+		      GPIO_PULL_DOWN, GPIO_4MA),
+};
+
+static uint32_t bt_gpio_table_rev_CX[] = {
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_UART1_RTS, 2, GPIO_OUTPUT,
+		      GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_UART1_CTS, 2, GPIO_INPUT,
+		      GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_UART1_RX, 2, GPIO_INPUT,
+		      GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_UART1_TX, 2, GPIO_OUTPUT,
+		      GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_RESET_N, 0, GPIO_OUTPUT,
+		      GPIO_PULL_DOWN, GPIO_4MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_SHUTDOWN_N, 0, GPIO_OUTPUT,
+		      GPIO_PULL_DOWN, GPIO_4MA),
+	PCOM_GPIO_CFG(MAHIMAHI_CDMA_GPIO_BT_WAKE, 0, GPIO_OUTPUT,
+		      GPIO_PULL_DOWN, GPIO_4MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_BT_HOST_WAKE, 0, GPIO_INPUT,
+		      GPIO_PULL_DOWN, GPIO_4MA),
+};
+
+static uint32_t misc_gpio_table[] = {
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_LCD_RST_N, 0, GPIO_OUTPUT,
+		      GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_LED_3V3_EN, 0, GPIO_OUTPUT,
+		      GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_DOCK, 0, GPIO_OUTPUT,
+		      GPIO_NO_PULL, GPIO_4MA),
+};
+
+static uint32_t key_int_shutdown_gpio_table[] = {
+	PCOM_GPIO_CFG(MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN, 0, GPIO_OUTPUT,
+		      GPIO_NO_PULL, GPIO_2MA),
+};
+
+static void mahimahi_headset_init(void)
+{
+	if (is_cdma_version(system_rev))
+		return;
+	config_gpio_table(key_int_shutdown_gpio_table,
+			ARRAY_SIZE(key_int_shutdown_gpio_table));
+	gpio_set_value(MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN, 0);
+}
+
+#define ATAG_BDADDR 0x43294329  /* mahimahi bluetooth address tag */
+#define ATAG_BDADDR_SIZE 4
+#define BDADDR_STR_SIZE 18
+
+static char bdaddr[BDADDR_STR_SIZE];
+
+module_param_string(bdaddr, bdaddr, sizeof(bdaddr), 0400);
+MODULE_PARM_DESC(bdaddr, "bluetooth address");
+
+static int __init parse_tag_bdaddr(const struct tag *tag)
+{
+	unsigned char *b = (unsigned char *)&tag->u;
+
+	if (tag->hdr.size != ATAG_BDADDR_SIZE)
+		return -EINVAL;
+
+	snprintf(bdaddr, BDADDR_STR_SIZE, "%02X:%02X:%02X:%02X:%02X:%02X",
+			b[0], b[1], b[2], b[3], b[4], b[5]);
+
+        return 0;
+}
+
+__tagtable(ATAG_BDADDR, parse_tag_bdaddr);
+
+static int __init board_serialno_setup(char *serialno)
+{
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	int i;
+	char *src = serialno;
+
+	/* create a fake MAC address from our serial number.
+	 * first byte is 0x02 to signify locally administered.
+	 */
+	rndis_pdata.ethaddr[0] = 0x02;
+	for (i = 0; *src; i++) {
+		/* XOR the USB serial across the remaining bytes */
+		rndis_pdata.ethaddr[i % (ETH_ALEN - 1) + 1] ^= *src++;
+	}
+#endif
+
+	android_usb_pdata.serial_number = serialno;
+	return 1;
+}
+__setup("androidboot.serialno=", board_serialno_setup);
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for(n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+static struct msm_acpu_clock_platform_data mahimahi_clock_data = {
+	.acpu_switch_time_us	= 20,
+	.max_speed_delta_khz	= 256000,
+	.vdd_switch_time_us	= 62,
+	.power_collapse_khz	= 245000,
+	.wait_for_irq_khz	= 245000,
+	.mpll_khz		= 245000
+};
+
+static struct msm_acpu_clock_platform_data mahimahi_cdma_clock_data = {
+	.acpu_switch_time_us	= 20,
+	.max_speed_delta_khz	= 256000,
+	.vdd_switch_time_us	= 62,
+	.power_collapse_khz	= 235930,
+	.wait_for_irq_khz	= 235930,
+	.mpll_khz		= 235930
+};
+
+static ssize_t mahimahi_virtual_keys_show(struct kobject *kobj,
+			       struct kobj_attribute *attr, char *buf)
+{
+	if (system_rev > 2 && system_rev != 0xC0) {
+		/* center: x: back: 55, menu: 172, home: 298, search 412, y: 835 */
+		return sprintf(buf,
+			__stringify(EV_KEY) ":" __stringify(KEY_BACK)  ":55:835:90:55"
+		   ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU)   ":172:835:125:55"
+		   ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME)   ":298:835:115:55"
+		   ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":412:835:95:55"
+		   "\n");
+	} else {
+		/* center: x: home: 55, menu: 185, back: 305, search 425, y: 835 */
+		return sprintf(buf,
+			__stringify(EV_KEY) ":" __stringify(KEY_HOME)  ":55:835:70:55"
+		   ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU)   ":185:835:100:55"
+		   ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK)   ":305:835:70:55"
+		   ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":425:835:70:55"
+		   "\n");
+	}
+}
+
+static struct kobj_attribute mahimahi_virtual_keys_attr = {
+	.attr = {
+		.name = "virtualkeys.synaptics-rmi-touchscreen",
+		.mode = S_IRUGO,
+	},
+	.show = &mahimahi_virtual_keys_show,
+};
+
+static struct attribute *mahimahi_properties_attrs[] = {
+	&mahimahi_virtual_keys_attr.attr,
+	NULL
+};
+
+static struct attribute_group mahimahi_properties_attr_group = {
+	.attrs = mahimahi_properties_attrs,
+};
+
+static void mahimahi_reset(void)
+{
+	gpio_set_value(MAHIMAHI_GPIO_PS_HOLD, 0);
+}
+
+int mahimahi_init_mmc(int sysrev, unsigned debug_uart);
+
+static const struct smd_tty_channel_desc smd_cdma_default_channels[] = {
+	{ .id = 0, .name = "SMD_DS" },
+	{ .id = 19, .name = "SMD_DATA3" },
+	{ .id = 27, .name = "SMD_GPSNMEA" }
 };
 
 static void __init mahimahi_init(void)
 {
+	int ret;
+	struct kobject *properties_kobj;
+
+	printk("mahimahi_init() revision=%d\n", system_rev);
+
+	if (is_cdma_version(system_rev))
+		smd_set_channel_list(smd_cdma_default_channels,
+					ARRAY_SIZE(smd_cdma_default_channels));
+
+	msm_hw_reset_hook = mahimahi_reset;
+
+	if (is_cdma_version(system_rev))
+		msm_acpu_clock_init(&mahimahi_cdma_clock_data);
+	else
+		msm_acpu_clock_init(&mahimahi_clock_data);
+
+	msm_serial_debug_init(MSM_UART1_PHYS, INT_UART1,
+			      &msm_device_uart1.dev, 1, MSM_GPIO_TO_INT(139));
+
+	config_gpio_table(misc_gpio_table, ARRAY_SIZE(misc_gpio_table));
+
+	if (is_cdma_version(system_rev)) {
+		bcm_bt_lpm_pdata.gpio_wake = MAHIMAHI_CDMA_GPIO_BT_WAKE;
+		mahimahi_flashlight_data.torch = MAHIMAHI_CDMA_GPIO_FLASHLIGHT_TORCH;
+		config_gpio_table(bt_gpio_table_rev_CX, ARRAY_SIZE(bt_gpio_table_rev_CX));
+	} else {
+		config_gpio_table(bt_gpio_table, ARRAY_SIZE(bt_gpio_table));
+	}
+
+	gpio_request(MAHIMAHI_GPIO_TP_LS_EN, "tp_ls_en");
+	gpio_direction_output(MAHIMAHI_GPIO_TP_LS_EN, 0);
+	gpio_request(MAHIMAHI_GPIO_TP_EN, "tp_en");
+	gpio_direction_output(MAHIMAHI_GPIO_TP_EN, 0);
+	gpio_request(MAHIMAHI_GPIO_PROXIMITY_EN, "proximity_en");
+	gpio_direction_output(MAHIMAHI_GPIO_PROXIMITY_EN, 1);
+	gpio_request(MAHIMAHI_GPIO_COMPASS_RST_N, "compass_rst");
+	gpio_direction_output(MAHIMAHI_GPIO_COMPASS_RST_N, 1);
+	gpio_request(MAHIMAHI_GPIO_COMPASS_INT_N, "compass_int");
+	gpio_direction_input(MAHIMAHI_GPIO_COMPASS_INT_N);
+
+	gpio_request(MAHIMAHI_GPIO_DS2482_SLP_N, "ds2482_slp_n");
+
+	/* set the gpu power rail to manual mode so clk en/dis will not
+	 * turn off gpu power, and hang it on resume */
+	mahimahi_kgsl_power_rail_mode(0);
+	mahimahi_kgsl_power(true);
+
+	msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata;
+	msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+	i2c_register_board_info(0, base_i2c_devices,
+		ARRAY_SIZE(base_i2c_devices));
+
+	if (system_rev == 0) {
+		/* Only board after XB with Audience A1026 */
+		i2c_register_board_info(0, rev0_i2c_devices,
+			ARRAY_SIZE(rev0_i2c_devices));
+	}
+
+	if (system_rev > 0) {
+		/* Only board after XB with Audience A1026 */
+		i2c_register_board_info(0, rev1_i2c_devices,
+			ARRAY_SIZE(rev1_i2c_devices));
+	}
+
+	if (is_cdma_version(system_rev)) {
+		/* Only CDMA version with TI TPA2018D1 Speaker Amp. */
+		i2c_register_board_info(0, rev_CX_i2c_devices,
+			ARRAY_SIZE(rev_CX_i2c_devices));
+		if ((system_rev & 0x0F) == 0x00) {
+			a1026_data.gpio_a1026_clk = MAHIMAHI_CDMA_XA_AUD_A1026_CLK;
+		} else if ((system_rev & 0x0F) >= 0x01) {
+			a1026_data.gpio_a1026_wakeup = MAHIMAHI_CDMA_XB_AUD_A1026_WAKEUP;
+			a1026_data.gpio_a1026_reset = MAHIMAHI_CDMA_XB_AUD_A1026_RESET;
+			a1026_data.gpio_a1026_clk = MAHIMAHI_CDMA_XB_AUD_A1026_CLK;
+		}
+	}
+
+	ret = mahimahi_init_mmc(system_rev, debug_uart);
+	if (ret != 0)
+		pr_crit("%s: Unable to initialize MMC\n", __func__);
+
+	properties_kobj = kobject_create_and_add("board_properties", NULL);
+	if (properties_kobj)
+		ret = sysfs_create_group(properties_kobj,
+					 &mahimahi_properties_attr_group);
+	if (!properties_kobj || ret)
+		pr_err("failed to create board_properties\n");
+
+	mahimahi_audio_init();
+	mahimahi_headset_init();
+
+	if (system_rev > 0)
+		platform_device_register(&mahimahi_timed_gpios);
+	else
+		msm_init_pmic_vibrator();
+
+	ds2784_battery_init();
 }
 
 static void __init mahimahi_fixup(struct machine_desc *desc, struct tag *tags,
@@ -67,8 +1174,8 @@
 
 static void __init mahimahi_map_io(void)
 {
-	msm_map_common_io();
-	msm_clock_init();
+	msm_map_qsd8x50_io();
+	msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50);
 }
 
 extern struct sys_timer msm_timer;
diff --git a/arch/arm/mach-msm/board-mahimahi.h b/arch/arm/mach-msm/board-mahimahi.h
new file mode 100644
index 0000000..9696a47
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi.h
@@ -0,0 +1,175 @@
+/* arch/arm/mach-msm/board-mahimahi.h
+ *
+ * Copyright (C) 2009 HTC Corporation.
+ * Author: Haley Teng <Haley_Teng@htc.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_MAHIMAHI_H
+#define __ARCH_ARM_MACH_MSM_BOARD_MAHIMAHI_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE		0x02B00000
+#define MSM_SMI_SIZE		0x01500000
+
+#define MSM_RAM_CONSOLE_BASE	0x03A00000
+#define MSM_RAM_CONSOLE_SIZE	0x00040000
+
+#define MSM_FB_BASE		0x03B00000
+#define MSM_FB_SIZE		0x00465000
+
+#define MSM_EBI1_BANK0_BASE	0x20000000
+#define MSM_EBI1_BANK0_SIZE	0x0E000000
+
+#define MSM_GPU_MEM_BASE	0x2DB00000
+#define MSM_GPU_MEM_SIZE	0x00500000
+
+#define MSM_EBI1_BANK1_BASE	0x30000000
+#define MSM_EBI1_BANK1_SIZE	0x10000000
+
+#define MSM_PMEM_MDP_BASE	0x30000000
+#define MSM_PMEM_MDP_SIZE	0x02000000
+
+#define MSM_PMEM_ADSP_BASE	0x32000000
+#define MSM_PMEM_ADSP_SIZE	0x02900000
+
+#define MSM_PMEM_CAMERA_BASE	0x34900000
+#define MSM_PMEM_CAMERA_SIZE	0x00800000
+
+#define MSM_HIGHMEM_BASE	0x35100000
+#define MSM_HIGHMEM_SIZE	0x0AF00000
+
+#define MAHIMAHI_GPIO_PS_HOLD		25
+
+#define MAHIMAHI_GPIO_UP_INT_N		35
+#define MAHIMAHI_GPIO_UP_RESET_N	82
+#define MAHIMAHI_GPIO_LS_EN_N		119
+
+#define MAHIMAHI_GPIO_TP_INT_N		92
+#define MAHIMAHI_GPIO_TP_LS_EN		93
+#define MAHIMAHI_GPIO_TP_EN		160
+
+#define MAHIMAHI_GPIO_POWER_KEY		94
+#define MAHIMAHI_GPIO_SDMC_CD_REV0_N	153
+
+#define MAHIMAHI_GPIO_WIFI_SHUTDOWN_N	127
+#define MAHIMAHI_GPIO_WIFI_IRQ		152
+
+#define MAHIMAHI_GPIO_BALL_UP		38
+#define MAHIMAHI_GPIO_BALL_DOWN		37
+#define MAHIMAHI_GPIO_BALL_LEFT		145
+#define MAHIMAHI_GPIO_BALL_RIGHT	21
+
+#define MAHIMAHI_GPIO_BT_UART1_RTS	43
+#define MAHIMAHI_GPIO_BT_UART1_CTS	44
+#define MAHIMAHI_GPIO_BT_UART1_RX	45
+#define MAHIMAHI_GPIO_BT_UART1_TX	46
+#define MAHIMAHI_GPIO_BT_RESET_N	146
+#define MAHIMAHI_GPIO_BT_SHUTDOWN_N	128
+
+#define MAHIMAHI_GPIO_BT_WAKE		57
+#define MAHIMAHI_GPIO_BT_HOST_WAKE	86
+
+#define MAHIMAHI_GPIO_PROXIMITY_INT_N	90
+#define MAHIMAHI_GPIO_PROXIMITY_EN	120
+
+#define MAHIMAHI_GPIO_DS2482_SLP_N	87
+#define MAHIMAHI_GPIO_VIBRATOR_ON	89
+/* Compass */
+#define MAHIMAHI_REV0_GPIO_COMPASS_INT_N	36
+
+#define MAHIMAHI_GPIO_COMPASS_INT_N	153
+#define MAHIMAHI_GPIO_COMPASS_RST_N	107
+#define MAHIMAHI_PROJECT_NAME          "mahimahi"
+#define MAHIMAHI_LAYOUTS { 			   \
+	{ {-1,  0, 0}, { 0, -1,  0}, {0, 0,  1} }, \
+	{ { 0, -1, 0}, { 1,  0,  0}, {0, 0, -1} }, \
+	{ { 0, -1, 0}, { 1,  0,  0}, {0, 0,  1} }, \
+	{ {-1,  0, 0}, { 0,  0, -1}, {0, 1,  0} }  \
+}
+
+/* Audio */
+#define MAHIMAHI_AUD_JACKHP_EN		157
+#define MAHIMAHI_AUD_2V5_EN		158
+#define MAHIMAHI_AUD_MICPATH_SEL 	111
+#define MAHIMAHI_AUD_A1026_INT		112
+#define MAHIMAHI_AUD_A1026_WAKEUP 	113
+#define MAHIMAHI_AUD_A1026_RESET 	129
+#define MAHIMAHI_AUD_A1026_CLK		 -1
+#define MAHIMAHI_CDMA_XA_AUD_A1026_CLK	105
+/* NOTE: MAHIMAHI_CDMA_XB_AUD_A1026_WAKEUP on CDMA is the same GPIO as
+ * MAHIMAHI_GPIO_BATTERY_CHARGER_CURRENT on UMTS.  Also,
+ * MAHIMAHI_CDMA_XB_AUD_A1026_RESET is the same as
+ * GPIO MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN on UMTS.
+ */
+#define MAHIMAHI_CDMA_XB_AUD_A1026_WAKEUP	16
+#define MAHIMAHI_CDMA_XB_AUD_A1026_RESET	19
+#define MAHIMAHI_CDMA_XB_AUD_A1026_CLK	-1
+
+/* Bluetooth PCM */
+#define MAHIMAHI_BT_PCM_OUT		68
+#define MAHIMAHI_BT_PCM_IN		69
+#define MAHIMAHI_BT_PCM_SYNC		70
+#define MAHIMAHI_BT_PCM_CLK		71
+/* flash light */
+#define MAHIMAHI_GPIO_FLASHLIGHT_TORCH	58
+#define MAHIMAHI_GPIO_FLASHLIGHT_FLASH	84
+
+#define MAHIMAHI_GPIO_LED_3V3_EN	85
+#define MAHIMAHI_GPIO_LCD_RST_N		29
+#define MAHIMAHI_GPIO_LCD_ID0		147
+
+/* 3.5mm remote control key interrupt shutdown signal */
+#define MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN	19
+
+#define MAHIMAHI_GPIO_DOCK		106
+
+/* speaker amplifier enable pin for mahimahi CDMA version */
+#define MAHIMAHI_CDMA_GPIO_AUD_SPK_AMP_EN	104
+
+#define MAHIMAHI_GPIO_BATTERY_DETECTION		39
+#define MAHIMAHI_GPIO_BATTERY_CHARGER_EN	22
+#define MAHIMAHI_GPIO_BATTERY_CHARGER_CURRENT	16
+
+#define MAHIMAHI_CDMA_GPIO_BT_WAKE		28
+#define MAHIMAHI_CDMA_GPIO_FLASHLIGHT_TORCH	26
+
+#define MAHIMAHI_CDMA_SD_2V85_EN		100
+#define MAHIMAHI_CDMA_JOG_2V6_EN		150
+/* display relative */
+#define MAHIMAHI_LCD_SPI_CLK            (17)
+#define MAHIMAHI_LCD_SPI_DO             (18)
+#define MAHIMAHI_LCD_SPI_CSz            (20)
+#define MAHIMAHI_LCD_RSTz               (29)
+#define MAHIMAHI_LCD_R1                 (114)
+#define MAHIMAHI_LCD_R2                 (115)
+#define MAHIMAHI_LCD_R3                 (116)
+#define MAHIMAHI_LCD_R4                 (117)
+#define MAHIMAHI_LCD_R5                 (118)
+#define MAHIMAHI_LCD_G0                 (121)
+#define MAHIMAHI_LCD_G1                 (122)
+#define MAHIMAHI_LCD_G2                 (123)
+#define MAHIMAHI_LCD_G3                 (124)
+#define MAHIMAHI_LCD_G4                 (125)
+#define MAHIMAHI_LCD_G5                 (126)
+#define MAHIMAHI_LCD_B1                 (130)
+#define MAHIMAHI_LCD_B2                 (131)
+#define MAHIMAHI_LCD_B3                 (132)
+#define MAHIMAHI_LCD_B4                 (133)
+#define MAHIMAHI_LCD_B5                 (134)
+#define MAHIMAHI_LCD_PCLK               (135)
+#define MAHIMAHI_LCD_VSYNC              (136)
+#define MAHIMAHI_LCD_HSYNC              (137)
+#define MAHIMAHI_LCD_DE                 (138)
+#define is_cdma_version(rev) (((rev) & 0xF0) == 0xC0)
+
+#endif /* __ARCH_ARM_MACH_MSM_BOARD_MAHIMAHI_H */
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index e3cc807..2bbaee7 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -36,8 +36,8 @@
 extern struct sys_timer msm_timer;
 
 static struct msm_gpio uart3_config_data[] = {
-	{ GPIO_CFG(86, 1, GPIO_INPUT,   GPIO_PULL_DOWN, GPIO_2MA), "UART2_Rx"},
-	{ GPIO_CFG(87, 1, GPIO_OUTPUT,  GPIO_PULL_DOWN, GPIO_2MA), "UART2_Tx"},
+	{ GPIO_CFG(86, 1, GPIO_CFG_INPUT,   GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART2_Rx"},
+	{ GPIO_CFG(87, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART2_Tx"},
 };
 
 static struct platform_device *devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-sapphire-gpio.c b/arch/arm/mach-msm/board-sapphire-gpio.c
new file mode 100644
index 0000000..375440c
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-gpio.c
@@ -0,0 +1,326 @@
+/* arch/arm/mach-msm/board-sapphire-gpio.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/sysdev.h>
+
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+
+#ifdef DEBUG_SAPPHIRE_GPIO
+#define DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n", __func__, ## arg)
+#else
+#define DBG(fmt, arg...) do {} while (0)
+#endif
+
+#define	SAPPHIRE_CPLD_INT_STATUS	(SAPPHIRE_CPLD_BASE + 0x0E)
+#define	SAPPHIRE_CPLD_INT_LEVEL		(SAPPHIRE_CPLD_BASE + 0x08)
+#define	SAPPHIRE_CPLD_INT_MASK		(SAPPHIRE_CPLD_BASE + 0x0C)
+
+/*CPLD misc reg offset*/
+static const int _g_CPLD_MISCn_Offset[] = {	0x0A,		/*misc1 reg*/
+						0x00,		/*misc2 reg*/
+						0x02,		/*misc3 reg*/
+						0x04,		/*misc4 reg*/
+						0x06};		/*misc5 reg*/
+/*CPLD INT Bank*/
+/*BANK0: int1 status, int2 level, int3 mask*/
+static const int _g_INT_BANK_Offset[][3] = {{0x0E, 0x08, 0x0C} };
+
+static uint8_t sapphire_cpld_initdata[4]  = {
+	[0] = 0x80, /* for serial debug UART3, low current	misc2*/
+	[1] = 0x34, /* jog & tp enable, I2C pull		misc3*/
+	[3] = 0x04, /* mmdi 32k en				misc5*/
+};
+
+/*save current working int mask, so the value can be restored after resume.
+Sapphire has only bank0.*/
+static uint8_t sapphire_int_mask[] = {
+	[0] = 0xfb, /* enable all interrupts, bit 2 is not used */
+};
+
+/*Sleep have to prepare the wake up source in advance.
+default to disable all wakeup sources when suspend.*/
+static uint8_t sapphire_sleep_int_mask[] = {
+	[0] = 0x00,	/* bit2 is not used */
+};
+
+static int sapphire_suspended;
+
+static int sapphire_gpio_read(struct gpio_chip *chip, unsigned n)
+{
+	if (n < SAPPHIRE_GPIO_INT_B0_BASE)	/*MISCn*/
+		return !!(readb(CPLD_GPIO_REG(n)) & CPLD_GPIO_BIT_POS_MASK(n));
+	else if (n <= SAPPHIRE_GPIO_END)	/*gpio n is INT pin*/
+		return !!(readb(CPLD_INT_LEVEL_REG_G(n)) &
+						CPLD_GPIO_BIT_POS_MASK(n));
+	return 0;
+}
+
+/*CPLD Write only register :MISC2, MISC3, MISC4, MISC5 => reg=0,2,4,6
+Reading from write-only registers is undefined, so the writing value
+should be kept in shadow for later usage.*/
+int sapphire_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+	if (n > SAPPHIRE_GPIO_END)
+		return -1;
+
+	local_irq_save(flags);
+	reg_val = readb(CPLD_GPIO_REG(n));
+	if (on)
+		reg_val |= CPLD_GPIO_BIT_POS_MASK(n);
+	else
+		reg_val &= ~CPLD_GPIO_BIT_POS_MASK(n);
+	writeb(reg_val, CPLD_GPIO_REG(n));
+
+	DBG("gpio=%d, l=0x%x\r\n", n, readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static int sapphire_gpio_configure(struct gpio_chip *chip, unsigned int gpio,
+				   unsigned long flags)
+{
+	if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH))
+		sapphire_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH);
+
+	DBG("gpio=%d, l=0x%x\r\n", gpio, readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+	return 0;
+}
+
+static int sapphire_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio,
+				unsigned int *irqp, unsigned long *irqnumflagsp)
+{
+	DBG("gpio=%d, l=0x%x\r\n", gpio, readb(SAPPHIRE_CPLD_INT_LEVEL));
+	DBG("SAPPHIRE_GPIO_INT_B0_BASE=%d, SAPPHIRE_GPIO_LAST_INT=%d\r\n",
+	    SAPPHIRE_GPIO_INT_B0_BASE, SAPPHIRE_GPIO_LAST_INT);
+	if ((gpio < SAPPHIRE_GPIO_INT_B0_BASE) ||
+	     (gpio > SAPPHIRE_GPIO_LAST_INT))
+		return -ENOENT;
+	*irqp = SAPPHIRE_GPIO_TO_INT(gpio);
+	DBG("*irqp=%d\r\n", *irqp);
+	if (irqnumflagsp)
+		*irqnumflagsp = 0;
+	return 0;
+}
+
+/*write 1 to clear INT status bit.*/
+static void sapphire_gpio_irq_ack(unsigned int irq)
+{
+	/*write 1 to clear*/
+	writeb(SAPPHIRE_INT_BIT_MASK(irq), CPLD_INT_STATUS_REG(irq));
+}
+
+/*unmask/enable the INT
+static void sapphire_gpio_irq_unmask(unsigned int irq)*/
+static void sapphire_gpio_irq_enable(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+
+	local_irq_save(flags);	/*disabling all interrupts*/
+
+	reg_val = readb(CPLD_INT_MASK_REG(irq)) | SAPPHIRE_INT_BIT_MASK(irq);
+	DBG("(irq=%d,0x%x, 0x%x)\r\n", irq, CPLD_INT_MASK_REG(irq),
+	    SAPPHIRE_INT_BIT_MASK(irq));
+	DBG("sapphire_suspended=%d\r\n", sapphire_suspended);
+	/*printk(KERN_INFO "sapphire_gpio_irq_mask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	if (!sapphire_suspended)
+		writeb(reg_val, CPLD_INT_MASK_REG(irq));
+
+	reg_val = readb(CPLD_INT_MASK_REG(irq));
+	DBG("reg_val= 0x%x\r\n", reg_val);
+	DBG("l=0x%x\r\n", readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+	local_irq_restore(flags); /*restore the interrupts*/
+}
+
+/*mask/disable INT
+static void sapphire_gpio_irq_mask(unsigned int irq)*/
+static void sapphire_gpio_irq_disable(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+
+	local_irq_save(flags);
+	reg_val = readb(CPLD_INT_MASK_REG(irq)) & ~SAPPHIRE_INT_BIT_MASK(irq);
+	/*CPLD INT MASK is r/w now.*/
+
+	/*printk(KERN_INFO "sapphire_gpio_irq_unmask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	DBG("(%d,0x%x, 0x%x, 0x%x)\r\n", irq, reg_val, CPLD_INT_MASK_REG(irq),
+	    SAPPHIRE_INT_BIT_MASK(irq));
+	DBG("sapphire_suspended=%d\r\n", sapphire_suspended);
+	if (!sapphire_suspended)
+		writeb(reg_val, CPLD_INT_MASK_REG(irq));
+
+	reg_val = readb(CPLD_INT_MASK_REG(irq));
+	DBG("reg_val= 0x%x\r\n", reg_val);
+	DBG("l=0x%x\r\n", readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+	local_irq_restore(flags);
+}
+
+/*preparing enable/disable wake source before sleep*/
+int sapphire_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	unsigned long flags;
+	uint8_t mask = SAPPHIRE_INT_BIT_MASK(irq);
+
+	local_irq_save(flags);
+
+	if (on)	/*wake on -> mask the bit*/
+		sapphire_sleep_int_mask[CPLD_INT_TO_BANK(irq)] |= mask;
+	else	/*no wake -> unmask the bit*/
+		sapphire_sleep_int_mask[CPLD_INT_TO_BANK(irq)] &= ~mask;
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*Sapphire has only one INT Bank.*/
+static void sapphire_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int j;
+	unsigned v;
+	int int_base = SAPPHIRE_INT_START;
+
+	v = readb(SAPPHIRE_CPLD_INT_STATUS);	/*INT1 status reg, BANK0*/
+
+	for (j = 0; j < 8 ; j++) {	/*8 bit per bank*/
+		if (v & (1U << j)) {	/*got the INT Bit*/
+			DBG("generic_handle_irq j=0x%x\r\n", j);
+			generic_handle_irq(int_base + j);
+		}
+	}
+
+	desc->chip->ack(irq);	/*clear CPLD INT in SOC side.*/
+	DBG("irq=%d, l=0x%x\r\n", irq, readb(SAPPHIRE_CPLD_INT_LEVEL));
+}
+
+/*Save current working sources before sleep, so we can restore it after
+ * resume.*/
+static int sapphire_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+{
+	sapphire_suspended = 1;
+	/*save current masking*/
+	sapphire_int_mask[0] = readb(SAPPHIRE_CPLD_BASE +
+					SAPPHIRE_GPIO_INT_B0_MASK_REG);
+
+	/*set waking source before sleep.*/
+	writeb(sapphire_sleep_int_mask[0],
+	       SAPPHIRE_CPLD_BASE +  SAPPHIRE_GPIO_INT_B0_MASK_REG);
+
+	return 0;
+}
+
+/*All the registers will be kept till a power loss...*/
+int sapphire_sysdev_resume(struct sys_device *dev)
+{
+	/*restore the working mask saved before sleep*/
+	writeb(sapphire_int_mask[0], SAPPHIRE_CPLD_BASE +
+					SAPPHIRE_GPIO_INT_B0_MASK_REG);
+	sapphire_suspended = 0;
+	return 0;
+}
+
+/**
+ * linux/irq.h :: struct irq_chip
+ * @enable:		enable the interrupt (defaults to chip->unmask if NULL)
+ * @disable:	disable the interrupt (defaults to chip->mask if NULL)
+ * @ack:		start of a new interrupt
+ * @mask:		mask an interrupt source
+ * @mask_ack:		ack and mask an interrupt source
+ * @unmask:		unmask an interrupt source
+ */
+static struct irq_chip sapphire_gpio_irq_chip = {
+	.name      = "sapphiregpio",
+	.ack       = sapphire_gpio_irq_ack,
+	.mask      = sapphire_gpio_irq_disable,	/*sapphire_gpio_irq_mask,*/
+	.unmask    = sapphire_gpio_irq_enable,	/*sapphire_gpio_irq_unmask,*/
+	.set_wake  = sapphire_gpio_irq_set_wake,
+	/*.set_type  = sapphire_gpio_irq_set_type,*/
+};
+
+/*Thomas:For CPLD*/
+static struct gpio_chip sapphire_gpio_chip = {
+	.start = SAPPHIRE_GPIO_START,
+	.end = SAPPHIRE_GPIO_END,
+	.configure = sapphire_gpio_configure,
+	.get_irq_num = sapphire_gpio_get_irq_num,
+	.read = sapphire_gpio_read,
+	.write = sapphire_gpio_write,
+/*	.read_detect_status = sapphire_gpio_read_detect_status,
+	.clear_detect_status = sapphire_gpio_clear_detect_status */
+};
+
+struct sysdev_class sapphire_sysdev_class = {
+	.name = "sapphiregpio_irq",
+	.suspend = sapphire_sysdev_suspend,
+	.resume = sapphire_sysdev_resume,
+};
+
+static struct sys_device sapphire_irq_device = {
+	.cls    = &sapphire_sysdev_class,
+};
+
+int sapphire_init_gpio(void)
+{
+	int i;
+	if (!machine_is_sapphire())
+		return 0;
+
+	DBG("%d,%d\r\n", SAPPHIRE_INT_START, SAPPHIRE_INT_END);
+	DBG("NR_MSM_IRQS=%d, NR_GPIO_IRQS=%d\r\n", NR_MSM_IRQS, NR_GPIO_IRQS);
+	for (i = SAPPHIRE_INT_START; i <= SAPPHIRE_INT_END; i++) {
+		set_irq_chip(i, &sapphire_gpio_irq_chip);
+		set_irq_handler(i, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	register_gpio_chip(&sapphire_gpio_chip);
+
+	/*setup CPLD INT connecting to SOC's gpio 17 */
+	set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);
+	set_irq_chained_handler(MSM_GPIO_TO_INT(17), sapphire_gpio_irq_handler);
+	set_irq_wake(MSM_GPIO_TO_INT(17), 1);
+
+	if (sysdev_class_register(&sapphire_sysdev_class) == 0)
+		sysdev_register(&sapphire_irq_device);
+
+	return 0;
+}
+
+int sapphire_init_cpld(unsigned int sys_rev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sapphire_cpld_initdata); i++)
+		writeb(sapphire_cpld_initdata[i], SAPPHIRE_CPLD_BASE + i * 2);
+	return 0;
+}
+
+postcore_initcall(sapphire_init_gpio);
diff --git a/arch/arm/mach-msm/board-sapphire-h2w.c b/arch/arm/mach-msm/board-sapphire-h2w.c
new file mode 100644
index 0000000..aa83e21
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-h2w.c
@@ -0,0 +1,545 @@
+/*
+ *  H2W device detection driver.
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * Authors:
+ *  Laurence Chen <Laurence_Chen@htc.com>
+ *  Nick Pelly <npelly@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*  For detecting HTC 2 Wire devices, such as wired headset.
+
+    Logically, the H2W driver is always present, and H2W state (hi->state)
+    indicates what is currently plugged into the H2W interface.
+
+    When the headset is plugged in, CABLE_IN1 is pulled low. When the headset
+    button is pressed, CABLE_IN2 is pulled low. These two lines are shared with
+    the TX and RX (respectively) of UART3 - used for serial debugging.
+
+    This headset driver keeps the CPLD configured as UART3 for as long as
+    possible, so that we can do serial FIQ debugging even when the kernel is
+    locked and this driver no longer runs. So it only configures the CPLD to
+    GPIO while the headset is plugged in, and for 10ms during detection work.
+
+    Unfortunately we can't leave the CPLD as UART3 while a headset is plugged
+    in, UART3 is pullup on TX but the headset is pull-down, causing a 55 mA
+    drain on sapphire.
+
+    The headset detection work involves setting CPLD to GPIO, and then pulling
+    CABLE_IN1 high with a stronger pullup than usual. A H2W headset will still
+    pull this line low, whereas other attachments such as a serial console
+    would get pulled up by this stronger pullup.
+
+    Headset insertion/removal causes UEvent's to be sent, and
+    /sys/class/switch/h2w/state to be updated.
+
+    Button presses are interpreted as input event (KEY_MEDIA). Button presses
+    are ignored if the headset is plugged in, so the buttons on 11 pin -> 3.5mm
+    jack adapters do not work until a headset is plugged into the adapter. This
+    is to avoid serial RX traffic causing spurious button press events.
+
+    We tend to check the status of CABLE_IN1 a few more times than strictly
+    necessary during headset detection, to avoid spurious headset insertion
+    events caused by serial debugger TX traffic.
+*/
+
+
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/switch.h>
+#include <linux/input.h>
+#include <linux/debugfs.h>
+#include <linux/gpio.h>
+#include <asm/atomic.h>
+#include <mach/board.h>
+#include <mach/vreg.h>
+#include <asm/mach-types.h>
+#include "board-sapphire.h"
+
+#ifdef CONFIG_DEBUG_SAPPHIRE_H2W
+#define H2W_DBG(fmt, arg...) printk(KERN_INFO "[H2W] %s " fmt "\n", __FUNCTION__, ## arg)
+#else
+#define H2W_DBG(fmt, arg...) do {} while (0)
+#endif
+
+static struct workqueue_struct *g_detection_work_queue;
+static void detection_work(struct work_struct *work);
+static DECLARE_WORK(g_detection_work, detection_work);
+enum {
+	NO_DEVICE	= 0,
+	HTC_HEADSET	= 1,
+};
+
+enum {
+	UART3		= 0,
+	GPIO		= 1,
+};
+
+struct h2w_info {
+	struct switch_dev sdev;
+	struct input_dev *input;
+
+	atomic_t btn_state;
+	int ignore_btn;
+
+	unsigned int irq;
+	unsigned int irq_btn;
+
+	struct hrtimer timer;
+	ktime_t debounce_time;
+
+	struct hrtimer btn_timer;
+	ktime_t btn_debounce_time;
+};
+static struct h2w_info *hi;
+
+static ssize_t sapphire_h2w_print_name(struct switch_dev *sdev, char *buf)
+{
+	switch (switch_get_state(&hi->sdev)) {
+	case NO_DEVICE:
+		return sprintf(buf, "No Device\n");
+	case HTC_HEADSET:
+		return sprintf(buf, "Headset\n");
+	}
+	return -EINVAL;
+}
+
+static void configure_cpld(int route)
+{
+	H2W_DBG(" route = %s", route == UART3 ? "UART3" : "GPIO");
+	switch (route) {
+	case UART3:
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1);
+		break;
+	case GPIO:
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 0);
+		break;
+	}
+}
+
+static void button_pressed(void)
+{
+	H2W_DBG("");
+	atomic_set(&hi->btn_state, 1);
+	input_report_key(hi->input, KEY_MEDIA, 1);
+	input_sync(hi->input);
+}
+
+static void button_released(void)
+{
+	H2W_DBG("");
+	atomic_set(&hi->btn_state, 0);
+	input_report_key(hi->input, KEY_MEDIA, 0);
+	input_sync(hi->input);
+}
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+extern void msm_serial_debug_enable(int);
+#endif
+
+static void insert_headset(void)
+{
+	unsigned long irq_flags;
+
+	H2W_DBG("");
+
+	switch_set_state(&hi->sdev, HTC_HEADSET);
+	configure_cpld(GPIO);
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+	msm_serial_debug_enable(false);
+#endif
+
+
+	/* On some non-standard headset adapters (usually those without a
+	 * button) the btn line is pulled down at the same time as the detect
+	 * line. We can check here by sampling the button line, if it is
+	 * low then it is probably a bad adapter so ignore the button.
+	 * If the button is released then we stop ignoring the button, so that
+	 * the user can recover from the situation where a headset is plugged
+	 * in with button held down.
+	 */
+	hi->ignore_btn = !gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2);
+
+	/* Enable button irq */
+	local_irq_save(irq_flags);
+	enable_irq(hi->irq_btn);
+	local_irq_restore(irq_flags);
+
+	hi->debounce_time = ktime_set(0, 20000000);  /* 20 ms */
+}
+
+static void remove_headset(void)
+{
+	unsigned long irq_flags;
+
+	H2W_DBG("");
+
+	switch_set_state(&hi->sdev, NO_DEVICE);
+	configure_cpld(UART3);
+
+	/* Disable button */
+	local_irq_save(irq_flags);
+	disable_irq(hi->irq_btn);
+	local_irq_restore(irq_flags);
+
+	if (atomic_read(&hi->btn_state))
+		button_released();
+
+	hi->debounce_time = ktime_set(0, 100000000);  /* 100 ms */
+}
+
+static void detection_work(struct work_struct *work)
+{
+	unsigned long irq_flags;
+	int clk, cable_in1;
+
+	H2W_DBG("");
+
+	if (gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1) != 0) {
+		/* Headset not plugged in */
+		if (switch_get_state(&hi->sdev) == HTC_HEADSET)
+			remove_headset();
+		return;
+	}
+
+	/* Something plugged in, lets make sure its a headset */
+
+	/* Switch CPLD to GPIO to do detection */
+	configure_cpld(GPIO);
+	/* Disable headset interrupt while detecting.*/
+	local_irq_save(irq_flags);
+	disable_irq(hi->irq);
+	local_irq_restore(irq_flags);
+
+	/* Set GPIO_CABLE_IN1 as output high */
+	gpio_direction_output(SAPPHIRE_GPIO_CABLE_IN1, 1);
+	/* Delay 10ms for pin stable. */
+	msleep(10);
+	/* Save H2W_CLK */
+	clk = gpio_get_value(SAPPHIRE_GPIO_H2W_CLK_GPI);
+	/* Set GPIO_CABLE_IN1 as input */
+	gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN1);
+
+	/* Restore IRQs */
+	local_irq_save(irq_flags);
+	enable_irq(hi->irq);
+	local_irq_restore(irq_flags);
+
+	cable_in1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1);
+
+	if (cable_in1 == 0 && clk == 0) {
+		if (switch_get_state(&hi->sdev) == NO_DEVICE)
+			insert_headset();
+	} else {
+		configure_cpld(UART3);
+		H2W_DBG("CABLE_IN1 was low, but not a headset "
+			"(recent cable_in1 = %d, clk = %d)", cable_in1, clk);
+	}
+}
+
+static enum hrtimer_restart button_event_timer_func(struct hrtimer *data)
+{
+	H2W_DBG("");
+
+	if (switch_get_state(&hi->sdev) == HTC_HEADSET) {
+		if (gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2)) {
+			if (hi->ignore_btn)
+				hi->ignore_btn = 0;
+			else if (atomic_read(&hi->btn_state))
+				button_released();
+		} else {
+			if (!hi->ignore_btn && !atomic_read(&hi->btn_state))
+				button_pressed();
+		}
+	}
+
+	return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart detect_event_timer_func(struct hrtimer *data)
+{
+	H2W_DBG("");
+
+	queue_work(g_detection_work_queue, &g_detection_work);
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t detect_irq_handler(int irq, void *dev_id)
+{
+	int value1, value2;
+	int retry_limit = 10;
+
+	H2W_DBG("");
+	do {
+		value1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1);
+		set_irq_type(hi->irq, value1 ?
+				IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+		value2 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1);
+	} while (value1 != value2 && retry_limit-- > 0);
+
+	H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit));
+
+	if ((switch_get_state(&hi->sdev) == NO_DEVICE) ^ value2) {
+		if (switch_get_state(&hi->sdev) == HTC_HEADSET)
+			hi->ignore_btn = 1;
+		/* Do the rest of the work in timer context */
+		hrtimer_start(&hi->timer, hi->debounce_time, HRTIMER_MODE_REL);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t button_irq_handler(int irq, void *dev_id)
+{
+	int value1, value2;
+	int retry_limit = 10;
+
+	H2W_DBG("");
+	do {
+		value1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2);
+		set_irq_type(hi->irq_btn, value1 ?
+				IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+		value2 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2);
+	} while (value1 != value2 && retry_limit-- > 0);
+
+	H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit));
+
+	hrtimer_start(&hi->btn_timer, hi->btn_debounce_time, HRTIMER_MODE_REL);
+
+	return IRQ_HANDLED;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static void h2w_debug_set(void *data, u64 val)
+{
+	switch_set_state(&hi->sdev, (int)val);
+}
+
+static u64 h2w_debug_get(void *data)
+{
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(h2w_debug_fops, h2w_debug_get, h2w_debug_set, "%llu\n");
+static int __init h2w_debug_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("h2w", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("state", 0644, dent, NULL, &h2w_debug_fops);
+
+	return 0;
+}
+
+device_initcall(h2w_debug_init);
+#endif
+
+static int sapphire_h2w_probe(struct platform_device *pdev)
+{
+	int ret;
+	unsigned long irq_flags;
+
+	printk(KERN_INFO "H2W: Registering H2W (headset) driver\n");
+	hi = kzalloc(sizeof(struct h2w_info), GFP_KERNEL);
+	if (!hi)
+		return -ENOMEM;
+
+	atomic_set(&hi->btn_state, 0);
+	hi->ignore_btn = 0;
+
+	hi->debounce_time = ktime_set(0, 100000000);  /* 100 ms */
+	hi->btn_debounce_time = ktime_set(0, 10000000); /* 10 ms */
+	hi->sdev.name = "h2w";
+	hi->sdev.print_name = sapphire_h2w_print_name;
+
+	ret = switch_dev_register(&hi->sdev);
+	if (ret < 0)
+		goto err_switch_dev_register;
+
+	g_detection_work_queue = create_workqueue("detection");
+	if (g_detection_work_queue == NULL) {
+		ret = -ENOMEM;
+		goto err_create_work_queue;
+	}
+
+	ret = gpio_request(SAPPHIRE_GPIO_CABLE_IN1, "h2w_detect");
+	if (ret < 0)
+		goto err_request_detect_gpio;
+
+	ret = gpio_request(SAPPHIRE_GPIO_CABLE_IN2, "h2w_button");
+	if (ret < 0)
+		goto err_request_button_gpio;
+
+	ret = gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN1);
+	if (ret < 0)
+		goto err_set_detect_gpio;
+
+	ret = gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN2);
+	if (ret < 0)
+		goto err_set_button_gpio;
+
+	hi->irq = gpio_to_irq(SAPPHIRE_GPIO_CABLE_IN1);
+	if (hi->irq < 0) {
+		ret = hi->irq;
+		goto err_get_h2w_detect_irq_num_failed;
+	}
+
+	hi->irq_btn = gpio_to_irq(SAPPHIRE_GPIO_CABLE_IN2);
+	if (hi->irq_btn < 0) {
+		ret = hi->irq_btn;
+		goto err_get_button_irq_num_failed;
+	}
+
+	/* Set CPLD MUX to H2W <-> CPLD GPIO */
+	configure_cpld(UART3);
+	/* Set the CPLD connected H2W GPIO's to input */
+	gpio_set_value(SAPPHIRE_GPIO_H2W_CLK_DIR, 0);
+	gpio_set_value(SAPPHIRE_GPIO_H2W_DAT_DIR, 0);
+
+	hrtimer_init(&hi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hi->timer.function = detect_event_timer_func;
+	hrtimer_init(&hi->btn_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hi->btn_timer.function = button_event_timer_func;
+
+	ret = request_irq(hi->irq, detect_irq_handler,
+			  IRQF_TRIGGER_LOW, "h2w_detect", NULL);
+	if (ret < 0)
+		goto err_request_detect_irq;
+
+	/* Disable button until plugged in */
+	set_irq_flags(hi->irq_btn, IRQF_VALID | IRQF_NOAUTOEN);
+	ret = request_irq(hi->irq_btn, button_irq_handler,
+			  IRQF_TRIGGER_LOW, "h2w_button", NULL);
+	if (ret < 0)
+		goto err_request_h2w_headset_button_irq;
+
+	ret = set_irq_wake(hi->irq, 1);
+	if (ret < 0)
+		goto err_request_input_dev;
+	ret = set_irq_wake(hi->irq_btn, 1);
+	if (ret < 0)
+		goto err_request_input_dev;
+
+	hi->input = input_allocate_device();
+	if (!hi->input) {
+		ret = -ENOMEM;
+		goto err_request_input_dev;
+	}
+
+	hi->input->name = "h2w headset";
+	hi->input->evbit[0] = BIT_MASK(EV_KEY);
+	hi->input->keybit[BIT_WORD(KEY_MEDIA)] = BIT_MASK(KEY_MEDIA);
+
+	ret = input_register_device(hi->input);
+	if (ret < 0)
+		goto err_register_input_dev;
+
+	return 0;
+
+err_register_input_dev:
+	input_free_device(hi->input);
+err_request_input_dev:
+	free_irq(hi->irq_btn, 0);
+err_request_h2w_headset_button_irq:
+	free_irq(hi->irq, 0);
+err_request_detect_irq:
+err_get_button_irq_num_failed:
+err_get_h2w_detect_irq_num_failed:
+err_set_button_gpio:
+err_set_detect_gpio:
+	gpio_free(SAPPHIRE_GPIO_CABLE_IN2);
+err_request_button_gpio:
+	gpio_free(SAPPHIRE_GPIO_CABLE_IN1);
+err_request_detect_gpio:
+	destroy_workqueue(g_detection_work_queue);
+err_create_work_queue:
+	switch_dev_unregister(&hi->sdev);
+err_switch_dev_register:
+	printk(KERN_ERR "H2W: Failed to register driver\n");
+
+	return ret;
+}
+
+static int sapphire_h2w_remove(struct platform_device *pdev)
+{
+	H2W_DBG("");
+	if (switch_get_state(&hi->sdev))
+		remove_headset();
+	input_unregister_device(hi->input);
+	gpio_free(SAPPHIRE_GPIO_CABLE_IN2);
+	gpio_free(SAPPHIRE_GPIO_CABLE_IN1);
+	free_irq(hi->irq_btn, 0);
+	free_irq(hi->irq, 0);
+	destroy_workqueue(g_detection_work_queue);
+	switch_dev_unregister(&hi->sdev);
+
+	return 0;
+}
+
+static struct platform_device sapphire_h2w_device = {
+	.name		= "sapphire-h2w",
+};
+
+static struct platform_driver sapphire_h2w_driver = {
+	.probe		= sapphire_h2w_probe,
+	.remove		= sapphire_h2w_remove,
+	.driver		= {
+		.name		= "sapphire-h2w",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init sapphire_h2w_init(void)
+{
+	if (!machine_is_sapphire())
+		return 0;
+	int ret;
+	H2W_DBG("");
+	ret = platform_driver_register(&sapphire_h2w_driver);
+	if (ret)
+		return ret;
+	return platform_device_register(&sapphire_h2w_device);
+}
+
+static void __exit sapphire_h2w_exit(void)
+{
+	platform_device_unregister(&sapphire_h2w_device);
+	platform_driver_unregister(&sapphire_h2w_driver);
+}
+
+module_init(sapphire_h2w_init);
+module_exit(sapphire_h2w_exit);
+
+MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>");
+MODULE_DESCRIPTION("HTC 2 Wire detection driver for sapphire");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-sapphire-keypad.c b/arch/arm/mach-msm/board-sapphire-keypad.c
new file mode 100755
index 0000000..5c8fc37
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-keypad.c
@@ -0,0 +1,132 @@
+/* arch/arm/mach-msm/board-sapphire-keypad.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/gpio_event.h>
+#include <asm/mach-types.h>
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+static char *keycaps = "--qwerty";
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_sapphire."
+module_param_named(keycaps, keycaps, charp, 0);
+
+
+static unsigned int sapphire_col_gpios[] = { 35, 34 };
+
+/* KP_MKIN2 (GPIO40) is not used? */
+static unsigned int sapphire_row_gpios[] = { 42, 41 };
+
+#define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(sapphire_row_gpios) + (row))
+
+/*scan matrix key*/
+/* HOME(up) MENU (up) Back Search */
+static const unsigned short sapphire_keymap2[ARRAY_SIZE(sapphire_col_gpios) * ARRAY_SIZE(sapphire_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_COMPOSE,
+	[KEYMAP_INDEX(0, 1)] = KEY_BACK,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_MENU,
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+};
+
+/* HOME(up) + MENU (down)*/
+static const unsigned short sapphire_keymap1[ARRAY_SIZE(sapphire_col_gpios) *
+					ARRAY_SIZE(sapphire_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_BACK,
+	[KEYMAP_INDEX(0, 1)] = KEY_MENU,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_HOME,
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+};
+
+/* MENU(up) + HOME (down)*/
+static const unsigned short sapphire_keymap0[ARRAY_SIZE(sapphire_col_gpios) *
+					ARRAY_SIZE(sapphire_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_BACK,
+	[KEYMAP_INDEX(0, 1)] = KEY_HOME,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_MENU,
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+};
+
+static struct gpio_event_matrix_info sapphire_keypad_matrix_info = {
+	.info.func = gpio_event_matrix_func,
+	.keymap = sapphire_keymap2,
+	.output_gpios = sapphire_col_gpios,
+	.input_gpios = sapphire_row_gpios,
+	.noutputs = ARRAY_SIZE(sapphire_col_gpios),
+	.ninputs = ARRAY_SIZE(sapphire_row_gpios),
+	.settle_time.tv.nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.debounce_delay.tv.nsec = 50 * NSEC_PER_MSEC,
+	.flags = GPIOKPF_LEVEL_TRIGGERED_IRQ |
+		 GPIOKPF_REMOVE_PHANTOM_KEYS |
+		 GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+static struct gpio_event_direct_entry sapphire_keypad_nav_map[] = {
+	{ SAPPHIRE_POWER_KEY,              KEY_END        },
+	{ SAPPHIRE_VOLUME_UP,              KEY_VOLUMEUP   },
+	{ SAPPHIRE_VOLUME_DOWN,            KEY_VOLUMEDOWN },
+};
+
+static struct gpio_event_input_info sapphire_keypad_nav_info = {
+	.info.func = gpio_event_input_func,
+	.flags = 0,
+	.type = EV_KEY,
+	.keymap = sapphire_keypad_nav_map,
+	.debounce_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.keymap_size = ARRAY_SIZE(sapphire_keypad_nav_map)
+};
+
+static struct gpio_event_info *sapphire_keypad_info[] = {
+	&sapphire_keypad_matrix_info.info,
+	&sapphire_keypad_nav_info.info,
+};
+
+static struct gpio_event_platform_data sapphire_keypad_data = {
+	.name = "sapphire-keypad",
+	.info = sapphire_keypad_info,
+	.info_count = ARRAY_SIZE(sapphire_keypad_info)
+};
+
+static struct platform_device sapphire_keypad_device = {
+	.name = GPIO_EVENT_DEV_NAME,
+	.id = 0,
+	.dev		= {
+		.platform_data	= &sapphire_keypad_data,
+	},
+};
+
+static int __init sapphire_init_keypad(void)
+{
+	if (!machine_is_sapphire())
+		return 0;
+
+	switch (sapphire_get_hwid()) {
+	case 0:
+		sapphire_keypad_matrix_info.keymap = sapphire_keymap0;
+		break;
+	default:
+		if(system_rev != 0x80)
+			sapphire_keypad_matrix_info.keymap = sapphire_keymap1;
+		break;
+	}
+	return platform_device_register(&sapphire_keypad_device);
+}
+
+device_initcall(sapphire_init_keypad);
+
diff --git a/arch/arm/mach-msm/board-sapphire-mmc.c b/arch/arm/mach-msm/board-sapphire-mmc.c
new file mode 100755
index 0000000..a8a7963
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-mmc.c
@@ -0,0 +1,486 @@
+/* linux/arch/arm/mach-msm/board-sapphire-mmc.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/vreg.h>
+#include <mach/htc_pwrsink.h>
+
+#include <asm/mach/mmc.h>
+
+#include "devices.h"
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+#include "proc_comm.h"
+
+#define DEBUG_SDSLOT_VDD 0
+
+extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+			unsigned int stat_irq, unsigned long stat_irq_flags);
+
+/* ---- COMMON ---- */
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for (n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+/* ---- SDCARD ---- */
+
+static uint32_t sdcard_on_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+};
+
+static uint32_t sdcard_off_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+};
+
+static uint opt_disable_sdcard;
+
+static int __init sapphire_disablesdcard_setup(char *str)
+{
+	int cal = simple_strtol(str, NULL, 0);
+
+	opt_disable_sdcard = cal;
+	return 1;
+}
+
+__setup("board_sapphire.disable_sdcard=", sapphire_disablesdcard_setup);
+
+static struct vreg *vreg_sdslot;	/* SD slot power */
+
+struct mmc_vdd_xlat {
+	int mask;
+	int level;
+};
+
+static struct mmc_vdd_xlat mmc_vdd_table[] = {
+	{ MMC_VDD_165_195,	1800 },
+	{ MMC_VDD_20_21,	2050 },
+	{ MMC_VDD_21_22,	2150 },
+	{ MMC_VDD_22_23,	2250 },
+	{ MMC_VDD_23_24,	2350 },
+	{ MMC_VDD_24_25,	2450 },
+	{ MMC_VDD_25_26,	2550 },
+	{ MMC_VDD_26_27,	2650 },
+	{ MMC_VDD_27_28,	2750 },
+	{ MMC_VDD_28_29,	2850 },
+	{ MMC_VDD_29_30,	2950 },
+};
+
+static unsigned int sdslot_vdd = 0xffffffff;
+static unsigned int sdslot_vreg_enabled;
+
+static uint32_t sapphire_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+	int i, rc;
+
+	BUG_ON(!vreg_sdslot);
+
+	if (vdd == sdslot_vdd)
+		return 0;
+
+	sdslot_vdd = vdd;
+
+	if (vdd == 0) {
+#if DEBUG_SDSLOT_VDD
+		printk(KERN_DEBUG "%s: Disabling SD slot power\n", __func__);
+#endif
+		config_gpio_table(sdcard_off_gpio_table,
+				  ARRAY_SIZE(sdcard_off_gpio_table));
+		vreg_disable(vreg_sdslot);
+		sdslot_vreg_enabled = 0;
+		return 0;
+	}
+
+	if (!sdslot_vreg_enabled) {
+		rc = vreg_enable(vreg_sdslot);
+		if (rc) {
+			printk(KERN_ERR "%s: Error enabling vreg (%d)\n",
+			       __func__, rc);
+		}
+		config_gpio_table(sdcard_on_gpio_table,
+				  ARRAY_SIZE(sdcard_on_gpio_table));
+		sdslot_vreg_enabled = 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+		if (mmc_vdd_table[i].mask == (1 << vdd)) {
+#if DEBUG_SDSLOT_VDD
+			printk(KERN_DEBUG "%s: Setting level to %u\n",
+				__func__, mmc_vdd_table[i].level);
+#endif
+			rc = vreg_set_level(vreg_sdslot,
+					    mmc_vdd_table[i].level);
+			if (rc) {
+				printk(KERN_ERR
+				       "%s: Error setting vreg level (%d)\n",
+				       __func__, rc);
+			}
+			return 0;
+		}
+	}
+
+	printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd);
+	return 0;
+}
+
+static unsigned int sapphire_sdslot_status(struct device *dev)
+{
+	unsigned int status;
+
+	status = (unsigned int) gpio_get_value(SAPPHIRE_GPIO_SDMC_CD_N);
+	return !status;
+}
+
+#define SAPPHIRE_MMC_VDD (MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \
+			| MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \
+			| MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
+			| MMC_VDD_28_29 | MMC_VDD_29_30)
+
+static struct mmc_platform_data sapphire_sdslot_data = {
+	.ocr_mask	= SAPPHIRE_MMC_VDD,
+	.status		= sapphire_sdslot_status,
+	.translate_vdd	= sapphire_sdslot_switchvdd,
+};
+
+/* ---- WIFI ---- */
+
+static uint32_t wifi_on_gpio_table[] = {
+	PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+	PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(29, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_4MA),  /* WLAN IRQ */
+};
+
+static uint32_t wifi_off_gpio_table[] = {
+	PCOM_GPIO_CFG(51, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(52, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(53, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(54, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+	PCOM_GPIO_CFG(55, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(56, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(29, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),  /* WLAN IRQ */
+};
+
+static struct vreg *vreg_wifi_osc;	/* WIFI 32khz oscilator */
+static int sapphire_wifi_cd = 0;	/* WIFI virtual 'card detect' status */
+
+static struct sdio_embedded_func wifi_func = {
+	.f_class	= SDIO_CLASS_WLAN,
+	.f_maxblksize	= 512,
+};
+
+static struct embedded_sdio_data sapphire_wifi_emb_data = {
+	.cis	= {
+		.vendor		= 0x104c,
+		.device		= 0x9066,
+		.blksize	= 512,
+		.max_dtr	= 20000000,
+	},
+	.cccr	= {
+		.multi_block	= 0,
+		.low_speed	= 0,
+		.wide_bus	= 1,
+		.high_power	= 0,
+		.high_speed	= 0,
+	},
+	.funcs	= &wifi_func,
+	.num_funcs = 1,
+};
+
+static void (*wifi_status_cb)(int card_present, void *dev_id);
+static void *wifi_status_cb_devid;
+
+static int sapphire_wifi_status_register(void (*callback)(int card_present,
+							  void *dev_id),
+					 void *dev_id)
+{
+	if (wifi_status_cb)
+		return -EAGAIN;
+	wifi_status_cb = callback;
+	wifi_status_cb_devid = dev_id;
+	return 0;
+}
+
+static unsigned int sapphire_wifi_status(struct device *dev)
+{
+	return sapphire_wifi_cd;
+}
+
+int sapphire_wifi_set_carddetect(int val)
+{
+	printk(KERN_DEBUG "%s: %d\n", __func__, val);
+	sapphire_wifi_cd = val;
+	if (wifi_status_cb)
+		wifi_status_cb(val, wifi_status_cb_devid);
+	else
+		printk(KERN_WARNING "%s: Nobody to notify\n", __func__);
+	return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(sapphire_wifi_set_carddetect);
+#endif
+
+int sapphire_wifi_power_state=0;
+int sapphire_bt_power_state=0;
+
+int sapphire_wifi_power(int on)
+{
+	int rc;
+
+	printk(KERN_DEBUG "%s: %d\n", __func__, on);
+
+	if (on) {
+		config_gpio_table(wifi_on_gpio_table,
+				  ARRAY_SIZE(wifi_on_gpio_table));
+		rc = vreg_enable(vreg_wifi_osc);
+		if (rc)
+			return rc;
+		htc_pwrsink_set(PWRSINK_WIFI, 70);
+	} else {
+		config_gpio_table(wifi_off_gpio_table,
+				  ARRAY_SIZE(wifi_off_gpio_table));
+		htc_pwrsink_set(PWRSINK_WIFI, 0);
+	}
+	gpio_set_value(SAPPHIRE_GPIO_MAC_32K_EN, on);
+	mdelay(100);
+	gpio_set_value(SAPPHIRE_GPIO_WIFI_EN, on);
+	mdelay(100);
+	if (!on) {
+		if(!sapphire_bt_power_state)
+		{
+		vreg_disable(vreg_wifi_osc);
+			printk("WiFi disable vreg_wifi_osc.\n");
+		}
+		else
+			printk("WiFi shouldn't disable vreg_wifi_osc. BT is using it!!\n");
+	}
+	sapphire_wifi_power_state = on;
+	return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(sapphire_wifi_power);
+#endif
+
+/* Eenable VREG_MMC pin to turn on fastclock oscillator : colin */
+int sapphire_bt_fastclock_power(int on)
+{
+	int rc;
+
+	printk(KERN_DEBUG "sapphire_bt_fastclock_power on = %d\n", on);
+	if (vreg_wifi_osc) {
+		if (on) {
+			rc = vreg_enable(vreg_wifi_osc);
+			printk(KERN_DEBUG "BT vreg_enable vreg_mmc, rc=%d\n",
+			       rc);
+			if (rc) {
+				printk("Error turn sapphire_bt_fastclock_power rc=%d\n", rc);
+				return rc;
+			}
+		} else {
+			if (!sapphire_wifi_power_state) {
+				vreg_disable(vreg_wifi_osc);
+				printk(KERN_DEBUG "BT disable vreg_wifi_osc.\n");
+			} else
+				printk(KERN_DEBUG "BT shouldn't disable vreg_wifi_osc. WiFi is using it!!\n");
+		}
+	}
+	sapphire_bt_power_state = on;
+	return 0;
+}
+EXPORT_SYMBOL(sapphire_bt_fastclock_power);
+
+static int sapphire_wifi_reset_state;
+void sapphire_wifi_reset(int on)
+{
+	printk(KERN_DEBUG "%s: %d\n", __func__, on);
+	gpio_set_value(SAPPHIRE_GPIO_WIFI_PA_RESETX, !on);
+	sapphire_wifi_reset_state = on;
+	mdelay(50);
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(sapphire_wifi_reset);
+#endif
+
+static struct mmc_platform_data sapphire_wifi_data = {
+	.ocr_mask		= MMC_VDD_28_29,
+	.status			= sapphire_wifi_status,
+	.register_status_notify	= sapphire_wifi_status_register,
+	.embedded_sdio		= &sapphire_wifi_emb_data,
+};
+
+int __init sapphire_init_mmc(unsigned int sys_rev)
+{
+	wifi_status_cb = NULL;
+
+	sdslot_vreg_enabled = 0;
+
+	vreg_sdslot = vreg_get(0, "gp6");
+	if (IS_ERR(vreg_sdslot))
+		return PTR_ERR(vreg_sdslot);
+	vreg_wifi_osc = vreg_get(0, "mmc");
+	if (IS_ERR(vreg_wifi_osc))
+		return PTR_ERR(vreg_wifi_osc);
+
+	set_irq_wake(SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_SDMC_CD_N), 1);
+
+	msm_add_sdcc(1, &sapphire_wifi_data, 0, 0);
+
+	if (!opt_disable_sdcard)
+		msm_add_sdcc(2, &sapphire_sdslot_data,
+			     SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_SDMC_CD_N), 0);
+	else
+		printk(KERN_INFO "sapphire: SD-Card interface disabled\n");
+	return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int sapphiremmc_dbg_wifi_reset_set(void *data, u64 val)
+{
+	sapphire_wifi_reset((int) val);
+	return 0;
+}
+
+static int sapphiremmc_dbg_wifi_reset_get(void *data, u64 *val)
+{
+	*val = sapphire_wifi_reset_state;
+	return 0;
+}
+
+static int sapphiremmc_dbg_wifi_cd_set(void *data, u64 val)
+{
+	sapphire_wifi_set_carddetect((int) val);
+	return 0;
+}
+
+static int sapphiremmc_dbg_wifi_cd_get(void *data, u64 *val)
+{
+	*val = sapphire_wifi_cd;
+	return 0;
+}
+
+static int sapphiremmc_dbg_wifi_pwr_set(void *data, u64 val)
+{
+	sapphire_wifi_power((int) val);
+	return 0;
+}
+
+static int sapphiremmc_dbg_wifi_pwr_get(void *data, u64 *val)
+{
+
+	*val = sapphire_wifi_power_state;
+	return 0;
+}
+
+static int sapphiremmc_dbg_sd_pwr_set(void *data, u64 val)
+{
+	sapphire_sdslot_switchvdd(NULL, (unsigned int) val);
+	return 0;
+}
+
+static int sapphiremmc_dbg_sd_pwr_get(void *data, u64 *val)
+{
+	*val = sdslot_vdd;
+	return 0;
+}
+
+static int sapphiremmc_dbg_sd_cd_set(void *data, u64 val)
+{
+	return -ENOSYS;
+}
+
+static int sapphiremmc_dbg_sd_cd_get(void *data, u64 *val)
+{
+	*val = sapphire_sdslot_status(NULL);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_reset_fops,
+			sapphiremmc_dbg_wifi_reset_get,
+			sapphiremmc_dbg_wifi_reset_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_cd_fops,
+			sapphiremmc_dbg_wifi_cd_get,
+			sapphiremmc_dbg_wifi_cd_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_pwr_fops,
+			sapphiremmc_dbg_wifi_pwr_get,
+			sapphiremmc_dbg_wifi_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_sd_pwr_fops,
+			sapphiremmc_dbg_sd_pwr_get,
+			sapphiremmc_dbg_sd_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_sd_cd_fops,
+			sapphiremmc_dbg_sd_cd_get,
+			sapphiremmc_dbg_sd_cd_set, "%llu\n");
+
+static int __init sapphiremmc_dbg_init(void)
+{
+	struct dentry *dent;
+
+	if (!machine_is_sapphire())
+		return 0;
+
+	dent = debugfs_create_dir("sapphiremmc_dbg", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("wifi_reset", 0644, dent, NULL,
+			    &sapphiremmc_dbg_wifi_reset_fops);
+	debugfs_create_file("wifi_cd", 0644, dent, NULL,
+			    &sapphiremmc_dbg_wifi_cd_fops);
+	debugfs_create_file("wifi_pwr", 0644, dent, NULL,
+			    &sapphiremmc_dbg_wifi_pwr_fops);
+
+	debugfs_create_file("sd_pwr", 0644, dent, NULL,
+			    &sapphiremmc_dbg_sd_pwr_fops);
+	debugfs_create_file("sd_cd", 0644, dent, NULL,
+			    &sapphiremmc_dbg_sd_cd_fops);
+
+	return 0;
+}
+
+device_initcall(sapphiremmc_dbg_init);
+
+#endif
diff --git a/arch/arm/mach-msm/board-sapphire-panel.c b/arch/arm/mach-msm/board-sapphire-panel.c
new file mode 100644
index 0000000..f71ca01
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-panel.c
@@ -0,0 +1,1272 @@
+/* linux/arch/arm/mach-msm/board-sapphire-panel.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+#include <mach/vreg.h>
+#include <mach/htc_pwrsink.h>
+
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+#include "proc_comm.h"
+#include "devices.h"
+
+#define DEBUG_SAPPHIRE_PANEL 0
+#define userid 0xD10
+
+#define VSYNC_GPIO 97
+
+enum sapphire_panel_type {
+	SAPPHIRE_PANEL_SHARP = 0,
+	SAPPHIRE_PANEL_TOPPOLY,
+	NUM_OF_SAPPHIRE_PANELS,
+};
+static int g_panel_id = -1 ;
+static int g_panel_inited = 0 ;
+
+#define SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS	132
+#define GOOGLE_DEFAULT_BACKLIGHT_BRIGHTNESS 	102
+#define SDBB 					SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS
+#define GDBB 					GOOGLE_DEFAULT_BACKLIGHT_BRIGHTNESS
+
+static int sapphire_backlight_off;
+static int sapphire_backlight_brightness =
+					SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS;
+
+static uint8_t sapphire_backlight_last_level = 33;
+static DEFINE_MUTEX(sapphire_backlight_lock);
+
+/* Divide dimming level into 12 sections, and restrict maximum level to 27 */
+#define DIMMING_STEPS       12
+static unsigned dimming_levels[NUM_OF_SAPPHIRE_PANELS][DIMMING_STEPS] = {
+	{0, 1, 2, 3, 6, 9, 11, 13, 16, 19, 22, 25},         /* Sharp */
+	{0, 1, 2, 4, 7, 10, 13, 15, 18, 21, 24, 27},        /* Toppolly */
+};
+static unsigned pwrsink_percents[] = {0, 6, 8, 15, 26, 34, 46, 54, 65, 77, 87,
+				      100};
+
+static void sapphire_set_backlight_level(uint8_t level)
+{
+	unsigned dimming_factor = 255/DIMMING_STEPS + 1;
+	int index, new_level ;
+	unsigned percent;
+	unsigned long flags;
+	int i = 0;
+
+	/* Non-linear transform for the difference between two 
+         * kind of default backlight settings. 
+	 */
+	new_level = level<=GDBB ? 
+		level*SDBB/GDBB : (SDBB + (level-GDBB)*(255-SDBB) / (255-GDBB)) ;
+	index = new_level/dimming_factor ;
+
+#if DEBUG_SAPPHIRE_PANEL
+	printk(KERN_INFO "level=%d, new level=%d, dimming_levels[%d]=%d\n",
+		level, new_level, index, dimming_levels[g_panel_id][index]);
+#endif
+	percent = pwrsink_percents[index];
+	level = dimming_levels[g_panel_id][index];
+
+	if (sapphire_backlight_last_level == level)
+		return;
+
+	if (level == 0) {
+		gpio_set_value(27, 0);
+		msleep(2);
+	} else {
+		local_irq_save(flags);
+		if (sapphire_backlight_last_level == 0) {
+			gpio_set_value(27, 1);
+			udelay(40);
+			sapphire_backlight_last_level = 33;
+		}
+		i = (sapphire_backlight_last_level - level + 33) % 33;
+		while (i-- > 0) {
+			gpio_set_value(27, 0);
+			udelay(1);
+			gpio_set_value(27, 1);
+			udelay(1);
+		}
+		local_irq_restore(flags);
+	}
+	sapphire_backlight_last_level = level;
+	htc_pwrsink_set(PWRSINK_BACKLIGHT, percent);
+}
+
+#define MDDI_CLIENT_CORE_BASE  0x108000
+#define LCD_CONTROL_BLOCK_BASE 0x110000
+#define SPI_BLOCK_BASE         0x120000
+#define I2C_BLOCK_BASE         0x130000
+#define PWM_BLOCK_BASE         0x140000
+#define GPIO_BLOCK_BASE        0x150000
+#define SYSTEM_BLOCK1_BASE     0x160000
+#define SYSTEM_BLOCK2_BASE     0x170000
+
+
+#define	DPSUS       (MDDI_CLIENT_CORE_BASE|0x24)
+#define	SYSCLKENA   (MDDI_CLIENT_CORE_BASE|0x2C)
+#define	PWM0OFF	      (PWM_BLOCK_BASE|0x1C)
+
+#define V_VDDE2E_VDD2_GPIO 0
+#define V_VDDE2E_VDD2_GPIO_5M 89
+#define MDDI_RST_N 82
+
+#define	MDDICAP0    (MDDI_CLIENT_CORE_BASE|0x00)
+#define	MDDICAP1    (MDDI_CLIENT_CORE_BASE|0x04)
+#define	MDDICAP2    (MDDI_CLIENT_CORE_BASE|0x08)
+#define	MDDICAP3    (MDDI_CLIENT_CORE_BASE|0x0C)
+#define	MDCAPCHG    (MDDI_CLIENT_CORE_BASE|0x10)
+#define	MDCRCERC    (MDDI_CLIENT_CORE_BASE|0x14)
+#define	TTBUSSEL    (MDDI_CLIENT_CORE_BASE|0x18)
+#define	DPSET0      (MDDI_CLIENT_CORE_BASE|0x1C)
+#define	DPSET1      (MDDI_CLIENT_CORE_BASE|0x20)
+#define	DPSUS       (MDDI_CLIENT_CORE_BASE|0x24)
+#define	DPRUN       (MDDI_CLIENT_CORE_BASE|0x28)
+#define	SYSCKENA    (MDDI_CLIENT_CORE_BASE|0x2C)
+#define	TESTMODE    (MDDI_CLIENT_CORE_BASE|0x30)
+#define	FIFOMONI    (MDDI_CLIENT_CORE_BASE|0x34)
+#define	INTMONI     (MDDI_CLIENT_CORE_BASE|0x38)
+#define	MDIOBIST    (MDDI_CLIENT_CORE_BASE|0x3C)
+#define	MDIOPSET    (MDDI_CLIENT_CORE_BASE|0x40)
+#define	BITMAP0     (MDDI_CLIENT_CORE_BASE|0x44)
+#define	BITMAP1     (MDDI_CLIENT_CORE_BASE|0x48)
+#define	BITMAP2     (MDDI_CLIENT_CORE_BASE|0x4C)
+#define	BITMAP3     (MDDI_CLIENT_CORE_BASE|0x50)
+#define	BITMAP4     (MDDI_CLIENT_CORE_BASE|0x54)
+
+#define	SRST        (LCD_CONTROL_BLOCK_BASE|0x00)
+#define	PORT_ENB    (LCD_CONTROL_BLOCK_BASE|0x04)
+#define	START       (LCD_CONTROL_BLOCK_BASE|0x08)
+#define	PORT        (LCD_CONTROL_BLOCK_BASE|0x0C)
+#define	CMN         (LCD_CONTROL_BLOCK_BASE|0x10)
+#define	GAMMA       (LCD_CONTROL_BLOCK_BASE|0x14)
+#define	INTFLG      (LCD_CONTROL_BLOCK_BASE|0x18)
+#define	INTMSK      (LCD_CONTROL_BLOCK_BASE|0x1C)
+#define	MPLFBUF     (LCD_CONTROL_BLOCK_BASE|0x20)
+#define	HDE_LEFT    (LCD_CONTROL_BLOCK_BASE|0x24)
+#define	VDE_TOP     (LCD_CONTROL_BLOCK_BASE|0x28)
+#define	PXL         (LCD_CONTROL_BLOCK_BASE|0x30)
+#define	HCYCLE      (LCD_CONTROL_BLOCK_BASE|0x34)
+#define	HSW         (LCD_CONTROL_BLOCK_BASE|0x38)
+#define	HDE_START   (LCD_CONTROL_BLOCK_BASE|0x3C)
+#define	HDE_SIZE    (LCD_CONTROL_BLOCK_BASE|0x40)
+#define	VCYCLE      (LCD_CONTROL_BLOCK_BASE|0x44)
+#define	VSW         (LCD_CONTROL_BLOCK_BASE|0x48)
+#define	VDE_START   (LCD_CONTROL_BLOCK_BASE|0x4C)
+#define	VDE_SIZE    (LCD_CONTROL_BLOCK_BASE|0x50)
+#define	WAKEUP      (LCD_CONTROL_BLOCK_BASE|0x54)
+#define	WSYN_DLY    (LCD_CONTROL_BLOCK_BASE|0x58)
+#define	REGENB      (LCD_CONTROL_BLOCK_BASE|0x5C)
+#define	VSYNIF      (LCD_CONTROL_BLOCK_BASE|0x60)
+#define	WRSTB       (LCD_CONTROL_BLOCK_BASE|0x64)
+#define	RDSTB       (LCD_CONTROL_BLOCK_BASE|0x68)
+#define	ASY_DATA    (LCD_CONTROL_BLOCK_BASE|0x6C)
+#define	ASY_DATB    (LCD_CONTROL_BLOCK_BASE|0x70)
+#define	ASY_DATC    (LCD_CONTROL_BLOCK_BASE|0x74)
+#define	ASY_DATD    (LCD_CONTROL_BLOCK_BASE|0x78)
+#define	ASY_DATE    (LCD_CONTROL_BLOCK_BASE|0x7C)
+#define	ASY_DATF    (LCD_CONTROL_BLOCK_BASE|0x80)
+#define	ASY_DATG    (LCD_CONTROL_BLOCK_BASE|0x84)
+#define	ASY_DATH    (LCD_CONTROL_BLOCK_BASE|0x88)
+#define	ASY_CMDSET  (LCD_CONTROL_BLOCK_BASE|0x8C)
+
+#define	SSICTL      (SPI_BLOCK_BASE|0x00)
+#define	SSITIME     (SPI_BLOCK_BASE|0x04)
+#define	SSITX       (SPI_BLOCK_BASE|0x08)
+#define	SSIRX       (SPI_BLOCK_BASE|0x0C)
+#define	SSIINTC     (SPI_BLOCK_BASE|0x10)
+#define	SSIINTS     (SPI_BLOCK_BASE|0x14)
+#define	SSIDBG1     (SPI_BLOCK_BASE|0x18)
+#define	SSIDBG2     (SPI_BLOCK_BASE|0x1C)
+#define	SSIID       (SPI_BLOCK_BASE|0x20)
+
+#define	WKREQ       (SYSTEM_BLOCK1_BASE|0x00)
+#define	CLKENB      (SYSTEM_BLOCK1_BASE|0x04)
+#define	DRAMPWR     (SYSTEM_BLOCK1_BASE|0x08)
+#define	INTMASK     (SYSTEM_BLOCK1_BASE|0x0C)
+#define	GPIOSEL     (SYSTEM_BLOCK2_BASE|0x00)
+
+#define	GPIODATA    (GPIO_BLOCK_BASE|0x00)
+#define	GPIODIR     (GPIO_BLOCK_BASE|0x04)
+#define	GPIOIS      (GPIO_BLOCK_BASE|0x08)
+#define	GPIOIBE     (GPIO_BLOCK_BASE|0x0C)
+#define	GPIOIEV     (GPIO_BLOCK_BASE|0x10)
+#define	GPIOIE      (GPIO_BLOCK_BASE|0x14)
+#define	GPIORIS     (GPIO_BLOCK_BASE|0x18)
+#define	GPIOMIS     (GPIO_BLOCK_BASE|0x1C)
+#define	GPIOIC      (GPIO_BLOCK_BASE|0x20)
+#define	GPIOOMS     (GPIO_BLOCK_BASE|0x24)
+#define	GPIOPC      (GPIO_BLOCK_BASE|0x28)
+#define	GPIOID      (GPIO_BLOCK_BASE|0x30)
+
+#define SPI_WRITE(reg, val) \
+	{ SSITX,        0x00010000 | (((reg) & 0xff) << 8) | ((val) & 0xff) }, \
+	{ 0, 5 },
+
+#define SPI_WRITE1(reg) \
+	{ SSITX,        (reg) & 0xff }, \
+	{ 0, 5 },
+
+struct mddi_table {
+	uint32_t reg;
+	uint32_t value;
+};
+static struct mddi_table mddi_toshiba_init_table[] = {
+	{ DPSET0,       0x09e90046 },
+	{ DPSET1,       0x00000118 },
+	{ DPSUS,        0x00000000 },
+	{ DPRUN,        0x00000001 },
+	{ 1,            14         }, /* msleep 14 */
+	{ SYSCKENA,     0x00000001 },
+	/*{ CLKENB,       0x000000EF } */
+	{ CLKENB,       0x0000A1EF },  /*    # SYS.CLKENB  # Enable clocks for each module (without DCLK , i2cCLK) */
+	/*{ CLKENB,       0x000025CB },  Clock enable register */
+
+	{ GPIODATA,     0x02000200 },  /*   # GPI .GPIODATA  # GPIO2(RESET_LCD_N) set to 0 , GPIO3(eDRAM_Power) set to 0 */
+	{ GPIODIR,      0x000030D  },  /* 24D   # GPI .GPIODIR  # Select direction of GPIO port (0,2,3,6,9 output) */
+	{ GPIOSEL,      0/*0x00000173*/},  /*   # SYS.GPIOSEL  # GPIO port multiplexing control */
+	{ GPIOPC,       0x03C300C0 },  /*   # GPI .GPIOPC  # GPIO2,3 PD cut */
+	{ WKREQ,        0x00000000 },  /*   # SYS.WKREQ  # Wake-up request event is VSYNC alignment */
+
+	{ GPIOIBE,      0x000003FF },
+	{ GPIOIS,       0x00000000 },
+	{ GPIOIC,       0x000003FF },
+	{ GPIOIE,       0x00000000 },
+
+	{ GPIODATA,     0x00040004 },  /*   # GPI .GPIODATA  # eDRAM VD supply */
+	{ 1,            1          }, /* msleep 1 */
+	{ GPIODATA,     0x02040004 },  /*   # GPI .GPIODATA  # eDRAM VD supply */
+	{ DRAMPWR,      0x00000001 }, /* eDRAM power */
+};
+
+static struct mddi_table mddi_toshiba_panel_init_table[] = {
+	{ SRST,         0x00000003 }, /* FIFO/LCDC not reset */
+	{ PORT_ENB,     0x00000001 }, /* Enable sync. Port */
+	{ START,        0x00000000 }, /* To stop operation */
+	/*{ START,        0x00000001 }, To start operation */
+	{ PORT,         0x00000004 }, /* Polarity of VS/HS/DE. */
+	{ CMN,          0x00000000 },
+	{ GAMMA,        0x00000000 }, /* No Gamma correction */
+	{ INTFLG,       0x00000000 }, /* VSYNC interrupt flag clear/status */
+	{ INTMSK,       0x00000000 }, /* VSYNC interrupt mask is off. */
+	{ MPLFBUF,      0x00000000 }, /* Select frame buffer's base address. */
+	{ HDE_LEFT,     0x00000000 }, /* The value of HDE_LEFT. */
+	{ VDE_TOP,      0x00000000 }, /* The value of VDE_TPO. */
+	{ PXL,          0x00000001 }, /* 1. RGB666 */
+				      /* 2. Data is valid from 1st frame of beginning. */
+	{ HDE_START,    0x00000006 }, /* HDE_START= 14 PCLK */
+	{ HDE_SIZE,     0x0000009F }, /* HDE_SIZE=320 PCLK */
+	{ HSW,          0x00000004 }, /* HSW= 10 PCLK */
+	{ VSW,          0x00000001 }, /* VSW=2 HCYCLE */
+	{ VDE_START,    0x00000003 }, /* VDE_START=4 HCYCLE */
+	{ VDE_SIZE,     0x000001DF }, /* VDE_SIZE=480 HCYCLE */
+	{ WAKEUP,       0x000001e2 }, /* Wakeup position in VSYNC mode. */
+	{ WSYN_DLY,     0x00000000 }, /* Wakeup position in VSIN mode. */
+	{ REGENB,       0x00000001 }, /* Set 1 to enable to change the value of registers. */
+	{ CLKENB,       0x000025CB }, /* Clock enable register */
+
+	{ SSICTL,       0x00000170 }, /* SSI control register */
+	{ SSITIME,      0x00000250 }, /* SSI timing control register */
+	{ SSICTL,       0x00000172 }, /* SSI control register */
+};
+
+
+static struct mddi_table mddi_sharp_init_table[] = {
+	{ VCYCLE,       0x000001eb },
+	{ HCYCLE,       0x000000ae },
+	{ REGENB,       0x00000001 }, /* Set 1 to enable to change the value of registers. */
+	{ GPIODATA,     0x00040000 }, /* GPIO2 low */
+	{ GPIODIR,      0x00000004 }, /* GPIO2 out */
+	{ 1,            1          }, /* msleep 1 */
+	{ GPIODATA,     0x00040004 }, /* GPIO2 high */
+	{ 1,            10         }, /* msleep 10 */
+	SPI_WRITE(0x5f, 0x01)
+	SPI_WRITE1(0x11)
+	{ 1,            200        }, /* msleep 200 */
+	SPI_WRITE1(0x29)
+	SPI_WRITE1(0xde)
+	{ START,        0x00000001 }, /* To start operation */
+};
+
+static struct mddi_table mddi_sharp_deinit_table[] = {
+	{ 1,            200        }, /* msleep 200 */
+	SPI_WRITE(0x10, 0x1)
+	{ 1,            100        }, /* msleep 100 */
+	{ GPIODATA,     0x00040004 }, /* GPIO2 high */
+	{ GPIODIR,      0x00000004 }, /* GPIO2 out */
+	{ GPIODATA,     0x00040000 }, /* GPIO2 low */
+	{ 1,            10         }, /* msleep 10 */
+};
+
+static struct mddi_table mddi_tpo_init_table[] = {
+	{ VCYCLE,       0x000001e5 },
+	{ HCYCLE,       0x000000ac },
+	{ REGENB,       0x00000001 }, /* Set 1 to enable to change the value of registers. */
+	{ 0,            20         }, /* udelay 20 */
+	{ GPIODATA,     0x00000004 }, /* GPIO2 high */
+	{ GPIODIR,      0x00000004 }, /* GPIO2 out */
+	{ 0,            20         }, /* udelay 20 */
+
+	SPI_WRITE(0x08, 0x01)
+	{ 0,            500        }, /* udelay 500 */
+	SPI_WRITE(0x08, 0x00)
+	SPI_WRITE(0x02, 0x00)
+	SPI_WRITE(0x03, 0x04)
+	SPI_WRITE(0x04, 0x0e)
+	SPI_WRITE(0x09, 0x02)
+	SPI_WRITE(0x0b, 0x08)
+	SPI_WRITE(0x0c, 0x53)
+	SPI_WRITE(0x0d, 0x01)
+	SPI_WRITE(0x0e, 0xe0)
+	SPI_WRITE(0x0f, 0x01)
+	SPI_WRITE(0x10, 0x58)
+	SPI_WRITE(0x20, 0x1e)
+	SPI_WRITE(0x21, 0x0a)
+	SPI_WRITE(0x22, 0x0a)
+	SPI_WRITE(0x23, 0x1e)
+	SPI_WRITE(0x25, 0x32)
+	SPI_WRITE(0x26, 0x00)
+	SPI_WRITE(0x27, 0xac)
+	SPI_WRITE(0x29, 0x06)
+	SPI_WRITE(0x2a, 0xa4)
+	SPI_WRITE(0x2b, 0x45)
+	SPI_WRITE(0x2c, 0x45)
+	SPI_WRITE(0x2d, 0x15)
+	SPI_WRITE(0x2e, 0x5a)
+	SPI_WRITE(0x2f, 0xff)
+	SPI_WRITE(0x30, 0x6b)
+	SPI_WRITE(0x31, 0x0d)
+	SPI_WRITE(0x32, 0x48)
+	SPI_WRITE(0x33, 0x82)
+	SPI_WRITE(0x34, 0xbd)
+	SPI_WRITE(0x35, 0xe7)
+	SPI_WRITE(0x36, 0x18)
+	SPI_WRITE(0x37, 0x94)
+	SPI_WRITE(0x38, 0x01)
+	SPI_WRITE(0x39, 0x5d)
+	SPI_WRITE(0x3a, 0xae)
+	SPI_WRITE(0x3b, 0xff)
+	SPI_WRITE(0x07, 0x09)
+	{ 0,            10         }, /* udelay 10 */
+	{ START,        0x00000001 }, /* To start operation */
+};
+
+static struct mddi_table mddi_tpo_deinit_table[] = {
+	SPI_WRITE(0x07, 0x19)
+	{ START,        0x00000000 }, /* To stop operation */
+	{ GPIODATA,     0x00040004 }, /* GPIO2 high */
+	{ GPIODIR,      0x00000004 }, /* GPIO2 out */
+	{ GPIODATA,     0x00040000 }, /* GPIO2 low */
+	{ 0,            5        }, /* usleep 5 */
+};
+
+
+#define GPIOSEL_VWAKEINT (1U << 0)
+#define INTMASK_VWAKEOUT (1U << 0)
+
+static void sapphire_process_mddi_table(
+				     struct msm_mddi_client_data *client_data,
+				     const struct mddi_table *table,
+				     size_t count)
+{
+	int i;
+	for (i = 0; i < count; i++) {
+		uint32_t reg = table[i].reg;
+		uint32_t value = table[i].value;
+
+		if (reg == 0)
+			udelay(value);
+		else if (reg == 1)
+			msleep(value);
+		else
+			client_data->remote_write(client_data, value, reg);
+	}
+}
+
+static struct vreg *vreg_lcm_2v85;
+
+static void sapphire_mddi_power_client(struct msm_mddi_client_data *client_data,
+				    int on)
+{
+	unsigned id, on_off;
+#if DEBUG_SAPPHIRE_PANEL
+	printk(KERN_INFO "sapphire_mddi_client_power:%d\r\n", on);
+#endif
+	if (on) {
+		on_off = 0;
+		id = PM_VREG_PDOWN_MDDI_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+
+		gpio_set_value(SAPPHIRE_MDDI_1V5_EN, 1);
+		mdelay(5); /* delay time >5ms and <10ms */
+
+		if  (is_12pin_camera())
+			gpio_set_value(V_VDDE2E_VDD2_GPIO_5M, 1);
+		else
+			gpio_set_value(V_VDDE2E_VDD2_GPIO, 1);
+
+		gpio_set_value(SAPPHIRE_GPIO_MDDI_32K_EN, 1);
+		msleep(3);
+		id = PM_VREG_PDOWN_AUX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+		vreg_enable(vreg_lcm_2v85);
+		msleep(3);
+	} else {
+		gpio_set_value(SAPPHIRE_GPIO_MDDI_32K_EN, 0);
+		gpio_set_value(MDDI_RST_N, 0);
+		msleep(10);
+		vreg_disable(vreg_lcm_2v85);
+		on_off = 1;
+		id = PM_VREG_PDOWN_AUX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+		msleep(5);
+		if (is_12pin_camera())
+			gpio_set_value(V_VDDE2E_VDD2_GPIO_5M, 0);
+		else
+			gpio_set_value(V_VDDE2E_VDD2_GPIO, 0);
+
+		msleep(200);
+		gpio_set_value(SAPPHIRE_MDDI_1V5_EN, 0);
+		id = PM_VREG_PDOWN_MDDI_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+	}
+}
+
+static int sapphire_mddi_toshiba_client_init(
+			struct msm_mddi_bridge_platform_data *bridge_data,
+			struct msm_mddi_client_data *client_data)
+{
+	int panel_id;
+
+	/* Set the MDDI_RST_N accroding to MDDI client repectively(
+	 * been set in sapphire_mddi_power_client() originally)
+	 */
+	gpio_set_value(MDDI_RST_N, 1);
+	msleep(10);
+
+	client_data->auto_hibernate(client_data, 0);
+	sapphire_process_mddi_table(client_data, mddi_toshiba_init_table,
+				 ARRAY_SIZE(mddi_toshiba_init_table));
+	client_data->auto_hibernate(client_data, 1);
+	g_panel_id = panel_id =
+		(client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
+	if (panel_id > 1) {
+#if DEBUG_SAPPHIRE_PANEL
+		printk(KERN_ERR "unknown panel id at mddi_enable\n");
+#endif
+		return -1;
+	}
+	return 0;
+}
+
+static int sapphire_mddi_toshiba_client_uninit(
+			struct msm_mddi_bridge_platform_data *bridge_data,
+			struct msm_mddi_client_data *client_data)
+{
+	gpio_set_value(MDDI_RST_N, 0);
+	msleep(10);
+
+	return 0;
+}
+
+static int sapphire_mddi_panel_unblank(
+			struct msm_mddi_bridge_platform_data *bridge_data,
+			struct msm_mddi_client_data *client_data)
+{
+	int panel_id, ret = 0;
+
+	sapphire_set_backlight_level(0);
+	client_data->auto_hibernate(client_data, 0);
+	sapphire_process_mddi_table(client_data, mddi_toshiba_panel_init_table,
+		ARRAY_SIZE(mddi_toshiba_panel_init_table));
+	panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
+	switch (panel_id) {
+	case 0:
+#if DEBUG_SAPPHIRE_PANEL
+		printk(KERN_DEBUG "init sharp panel\n");
+#endif
+		sapphire_process_mddi_table(client_data,
+					 mddi_sharp_init_table,
+					 ARRAY_SIZE(mddi_sharp_init_table));
+		break;
+	case 1:
+#if DEBUG_SAPPHIRE_PANEL
+		printk(KERN_DEBUG "init tpo panel\n");
+#endif
+		sapphire_process_mddi_table(client_data,
+					 mddi_tpo_init_table,
+					 ARRAY_SIZE(mddi_tpo_init_table));
+		break;
+	default:
+
+		printk(KERN_DEBUG "unknown panel_id: %d\n", panel_id);
+		ret = -1;
+	};
+	mutex_lock(&sapphire_backlight_lock);
+	sapphire_set_backlight_level(sapphire_backlight_brightness);
+	sapphire_backlight_off = 0;
+	mutex_unlock(&sapphire_backlight_lock);
+	client_data->auto_hibernate(client_data, 1);
+	/* reenable vsync */
+	client_data->remote_write(client_data, GPIOSEL_VWAKEINT,
+				  GPIOSEL);
+	client_data->remote_write(client_data, INTMASK_VWAKEOUT,
+				  INTMASK);
+	return ret;
+
+}
+
+static int sapphire_mddi_panel_blank(
+			struct msm_mddi_bridge_platform_data *bridge_data,
+			struct msm_mddi_client_data *client_data)
+{
+	int panel_id, ret = 0;
+
+	panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
+	client_data->auto_hibernate(client_data, 0);
+	switch (panel_id) {
+	case 0:
+		printk(KERN_DEBUG "deinit sharp panel\n");
+		sapphire_process_mddi_table(client_data,
+					 mddi_sharp_deinit_table,
+					 ARRAY_SIZE(mddi_sharp_deinit_table));
+		break;
+	case 1:
+		printk(KERN_DEBUG "deinit tpo panel\n");
+		sapphire_process_mddi_table(client_data,
+					 mddi_tpo_deinit_table,
+					 ARRAY_SIZE(mddi_tpo_deinit_table));
+		break;
+	default:
+		printk(KERN_DEBUG "unknown panel_id: %d\n", panel_id);
+		ret = -1;
+	};
+	client_data->auto_hibernate(client_data, 1);
+	mutex_lock(&sapphire_backlight_lock);
+	sapphire_set_backlight_level(0);
+	sapphire_backlight_off = 1;
+	mutex_unlock(&sapphire_backlight_lock);
+	client_data->remote_write(client_data, 0, SYSCLKENA);
+	client_data->remote_write(client_data, 1, DPSUS);
+
+	return ret;
+}
+
+
+/* Initial sequence of sharp panel with Novatek NT35399 MDDI client */
+static const struct mddi_table sharp2_init_table[] = {
+	{ 0x02A0, 0x00 },
+	{ 0x02A1, 0x00 },
+	{ 0x02A2, 0x3F },
+	{ 0x02A3, 0x01 },
+	{ 0x02B0, 0x00 },
+	{ 0x02B1, 0x00 },
+	{ 0x02B2, 0xDF },
+	{ 0x02B3, 0x01 },
+	{ 0x02D0, 0x00 },
+	{ 0x02D1, 0x00 },
+	{ 0x02D2, 0x00 },
+	{ 0x02D3, 0x00 },
+	{ 0x0350, 0x80 },	/* Set frame tearing effect(FTE) position */
+	{ 0x0351, 0x00 },
+	{ 0x0360, 0x30 },
+	{ 0x0361, 0xC1 },
+	{ 0x0362, 0x00 },
+	{ 0x0370, 0x00 },
+	{ 0x0371, 0xEF },
+	{ 0x0372, 0x01 },
+
+	{ 0x0B00, 0x10 },
+
+	{ 0x0B10, 0x00 },
+	{ 0x0B20, 0x22 },
+	{ 0x0B30, 0x46 },
+	{ 0x0B40, 0x07 },
+	{ 0x0B41, 0x1C },
+	{ 0x0B50, 0x0F },
+	{ 0x0B51, 0x7A },
+	{ 0x0B60, 0x16 },
+	{ 0x0B70, 0x0D },
+	{ 0x0B80, 0x04 },
+	{ 0x0B90, 0x07 },
+	{ 0x0BA0, 0x04 },
+	{ 0x0BA1, 0x86 },
+	{ 0x0BB0, 0xFF },
+	{ 0x0BB1, 0x01 },
+	{ 0x0BB2, 0xF7 },
+	{ 0x0BB3, 0x01 },
+	{ 0x0BC0, 0x00 },
+	{ 0x0BC1, 0x00 },
+	{ 0x0BC2, 0x00 },
+	{ 0x0BC3, 0x00 },
+	{ 0x0BE0, 0x01 },
+	{ 0x0BE1, 0x3F },
+
+	{ 0x0BF0, 0x03 },
+
+	{ 0x0C10, 0x02 },
+
+	{ 0x0C30, 0x22 },
+	{ 0x0C31, 0x20 },
+	{ 0x0C40, 0x48 },
+	{ 0x0C41, 0x06 },
+
+	{ 0xE00, 0x0028},
+	{ 0xE01, 0x002F},
+	{ 0xE02, 0x0032},
+	{ 0xE03, 0x000A},
+	{ 0xE04, 0x0023},
+	{ 0xE05, 0x0024},
+	{ 0xE06, 0x0022},
+	{ 0xE07, 0x0012},
+	{ 0xE08, 0x000D},
+	{ 0xE09, 0x0035},
+	{ 0xE0A, 0x000E},
+	{ 0xE0B, 0x001A},
+	{ 0xE0C, 0x003C},
+	{ 0xE0D, 0x003A},
+	{ 0xE0E, 0x0050},
+	{ 0xE0F, 0x0069},
+	{ 0xE10, 0x0006},
+	{ 0xE11, 0x001F},
+	{ 0xE12, 0x0035},
+	{ 0xE13, 0x0020},
+	{ 0xE14, 0x0043},
+	{ 0xE15, 0x0030},
+	{ 0xE16, 0x003C},
+	{ 0xE17, 0x0010},
+	{ 0xE18, 0x0009},
+	{ 0xE19, 0x0051},
+	{ 0xE1A, 0x001D},
+	{ 0xE1B, 0x003C},
+	{ 0xE1C, 0x0053},
+	{ 0xE1D, 0x0041},
+	{ 0xE1E, 0x0045},
+	{ 0xE1F, 0x004B},
+	{ 0xE20, 0x000A},
+	{ 0xE21, 0x0014},
+	{ 0xE22, 0x001C},
+	{ 0xE23, 0x0013},
+	{ 0xE24, 0x002E},
+	{ 0xE25, 0x0029},
+	{ 0xE26, 0x001B},
+	{ 0xE27, 0x0014},
+	{ 0xE28, 0x000E},
+	{ 0xE29, 0x0032},
+	{ 0xE2A, 0x000D},
+	{ 0xE2B, 0x001B},
+	{ 0xE2C, 0x0033},
+	{ 0xE2D, 0x0033},
+	{ 0xE2E, 0x005B},
+	{ 0xE2F, 0x0069},
+	{ 0xE30, 0x0006},
+	{ 0xE31, 0x0014},
+	{ 0xE32, 0x003D},
+	{ 0xE33, 0x0029},
+	{ 0xE34, 0x0042},
+	{ 0xE35, 0x0032},
+	{ 0xE36, 0x003F},
+	{ 0xE37, 0x000E},
+	{ 0xE38, 0x0008},
+	{ 0xE39, 0x0059},
+	{ 0xE3A, 0x0015},
+	{ 0xE3B, 0x002E},
+	{ 0xE3C, 0x0049},
+	{ 0xE3D, 0x0058},
+	{ 0xE3E, 0x0061},
+	{ 0xE3F, 0x006B},
+	{ 0xE40, 0x000A},
+	{ 0xE41, 0x001A},
+	{ 0xE42, 0x0022},
+	{ 0xE43, 0x0014},
+	{ 0xE44, 0x002F},
+	{ 0xE45, 0x002A},
+	{ 0xE46, 0x001A},
+	{ 0xE47, 0x0014},
+	{ 0xE48, 0x000E},
+	{ 0xE49, 0x002F},
+	{ 0xE4A, 0x000F},
+	{ 0xE4B, 0x001B},
+	{ 0xE4C, 0x0030},
+	{ 0xE4D, 0x002C},
+	{ 0xE4E, 0x0051},
+	{ 0xE4F, 0x0069},
+	{ 0xE50, 0x0006},
+	{ 0xE51, 0x001E},
+	{ 0xE52, 0x0043},
+	{ 0xE53, 0x002F},
+	{ 0xE54, 0x0043},
+	{ 0xE55, 0x0032},
+	{ 0xE56, 0x0043},
+	{ 0xE57, 0x000D},
+	{ 0xE58, 0x0008},
+	{ 0xE59, 0x0059},
+	{ 0xE5A, 0x0016},
+	{ 0xE5B, 0x0030},
+	{ 0xE5C, 0x004B},
+	{ 0xE5D, 0x0051},
+	{ 0xE5E, 0x005A},
+	{ 0xE5F, 0x006B},
+
+        { 0x0290, 0x01 },
+};
+
+#undef TPO2_ONE_GAMMA
+/* Initial sequence of TPO panel with Novatek NT35399 MDDI client */
+
+static const struct mddi_table tpo2_init_table[] = {
+	/* Panel interface control */
+	{ 0xB30, 0x44 },
+	{ 0xB40, 0x00 },
+	{ 0xB41, 0x87 },
+	{ 0xB50, 0x06 },
+	{ 0xB51, 0x7B },
+	{ 0xB60, 0x0E },
+	{ 0xB70, 0x0F },
+	{ 0xB80, 0x03 },
+	{ 0xB90, 0x00 },
+	{ 0x350, 0x70 },        /* FTE is at line 0x70 */
+
+	/* Entry Mode */
+	{ 0x360, 0x30 },
+	{ 0x361, 0xC1 },
+	{ 0x362, 0x04 },
+
+/* 0x2 for gray scale gamma correction, 0x12 for RGB gamma correction  */
+#ifdef TPO2_ONE_GAMMA
+	{ 0xB00, 0x02 },
+#else
+	{ 0xB00, 0x12 },
+#endif
+	/* Driver output control */
+	{ 0x371, 0xEF },
+	{ 0x372, 0x03 },
+
+	/* DCDC on glass control */
+	{ 0xC31, 0x10 },
+	{ 0xBA0, 0x00 },
+	{ 0xBA1, 0x86 },
+
+	/* VCOMH voltage control */
+	{ 0xC50, 0x3b },
+
+	/* Special function control */
+	{ 0xC10, 0x82 },
+
+	/* Power control */
+	{ 0xC40, 0x44 },
+	{ 0xC41, 0x02 },
+
+	/* Source output control */
+	{ 0xBE0, 0x01 },
+	{ 0xBE1, 0x00 },
+
+	/* Windows address setting */
+	{ 0x2A0, 0x00 },
+	{ 0x2A1, 0x00 },
+	{ 0x2A2, 0x3F },
+	{ 0x2A3, 0x01 },
+	{ 0x2B0, 0x00 },
+	{ 0x2B1, 0x00 },
+	{ 0x2B2, 0xDF },
+	{ 0x2B3, 0x01 },
+
+	/* RAM address setting */
+	{ 0x2D0, 0x00 },
+	{ 0x2D1, 0x00 },
+	{ 0x2D2, 0x00 },
+	{ 0x2D3, 0x00 },
+
+	{ 0xF20, 0x55 },
+	{ 0xF21, 0xAA },
+	{ 0xF22, 0x66 },
+	{ 0xF57, 0x45 },
+
+/*
+ * The NT35399 provides gray or RGB gamma correction table,
+ * which determinated by register-0xb00, and following table
+ */
+#ifdef TPO2_ONE_GAMMA
+	/* Positive Gamma setting */
+	{ 0xE00, 0x04 },
+	{ 0xE01, 0x12 },
+	{ 0xE02, 0x18 },
+	{ 0xE03, 0x10 },
+	{ 0xE04, 0x29 },
+	{ 0xE05, 0x26 },
+	{ 0xE06, 0x1f },
+	{ 0xE07, 0x11 },
+	{ 0xE08, 0x0c },
+	{ 0xE09, 0x3a },
+	{ 0xE0A, 0x0d },
+	{ 0xE0B, 0x28 },
+	{ 0xE0C, 0x40 },
+	{ 0xE0D, 0x4e },
+	{ 0xE0E, 0x6f },
+	{ 0xE0F, 0x5E },
+
+	/* Negative Gamma setting */
+	{ 0xE10, 0x0B },
+	{ 0xE11, 0x00 },
+	{ 0xE12, 0x00 },
+	{ 0xE13, 0x1F },
+	{ 0xE14, 0x4b },
+	{ 0xE15, 0x33 },
+	{ 0xE16, 0x13 },
+	{ 0xE17, 0x12 },
+	{ 0xE18, 0x0d },
+	{ 0xE19, 0x2f },
+	{ 0xE1A, 0x16 },
+	{ 0xE1B, 0x2e },
+	{ 0xE1C, 0x49 },
+	{ 0xE1D, 0x41 },
+	{ 0xE1E, 0x46 },
+	{ 0xE1F, 0x55 },
+#else
+	/* Red Positive Gamma  */
+	{ 0xE00, 0x0f },
+	{ 0xE01, 0x19 },
+	{ 0xE02, 0x22 },
+	{ 0xE03, 0x0b },
+	{ 0xE04, 0x23 },
+	{ 0xE05, 0x23 },
+	{ 0xE06, 0x14 },
+	{ 0xE07, 0x13 },
+	{ 0xE08, 0x0f },
+	{ 0xE09, 0x2a },
+	{ 0xE0A, 0x0d },
+	{ 0xE0B, 0x26 },
+	{ 0xE0C, 0x43 },
+	{ 0xE0D, 0x20 },
+	{ 0xE0E, 0x2a },
+	{ 0xE0F, 0x5c },
+
+	/* Red Negative Gamma   */
+	{ 0xE10, 0x0d },
+	{ 0xE11, 0x45 },
+	{ 0xE12, 0x4c },
+	{ 0xE13, 0x1c },
+	{ 0xE14, 0x4d },
+	{ 0xE15, 0x33 },
+	{ 0xE16, 0x23 },
+	{ 0xE17, 0x0f },
+	{ 0xE18, 0x0b },
+	{ 0xE19, 0x3a },
+	{ 0xE1A, 0x19 },
+	{ 0xE1B, 0x32 },
+	{ 0xE1C, 0x4e },
+	{ 0xE1D, 0x37 },
+	{ 0xE1E, 0x38 },
+	{ 0xE1F, 0x3b },
+
+	/* Green Positive Gamma */
+	{ 0xE20, 0x00 },
+	{ 0xE21, 0x09 },
+	{ 0xE22, 0x10 },
+	{ 0xE23, 0x0f },
+	{ 0xE24, 0x29 },
+	{ 0xE25, 0x23 },
+	{ 0xE26, 0x0b },
+	{ 0xE27, 0x14 },
+	{ 0xE28, 0x12 },
+	{ 0xE29, 0x25 },
+	{ 0xE2A, 0x12 },
+	{ 0xE2B, 0x2f },
+	{ 0xE2C, 0x43 },
+	{ 0xE2D, 0x2d },
+	{ 0xE2E, 0x52 },
+	{ 0xE2F, 0x61 },
+
+	/* Green Negative Gamma */
+	{ 0xE30, 0x08 },
+	{ 0xE31, 0x1d },
+	{ 0xE32, 0x3f },
+	{ 0xE33, 0x1c },
+	{ 0xE34, 0x44 },
+	{ 0xE35, 0x2e },
+	{ 0xE36, 0x28 },
+	{ 0xE37, 0x0c },
+	{ 0xE38, 0x0a },
+	{ 0xE39, 0x42 },
+	{ 0xE3A, 0x17 },
+	{ 0xE3B, 0x30 },
+	{ 0xE3C, 0x4b },
+	{ 0xE3D, 0x3f },
+	{ 0xE3E, 0x43 },
+	{ 0xE3F, 0x45 },
+
+	/* Blue Positive Gamma */
+	{ 0xE40, 0x32 },
+	{ 0xE41, 0x32 },
+	{ 0xE42, 0x31 },
+	{ 0xE43, 0x06 },
+	{ 0xE44, 0x08 },
+	{ 0xE45, 0x0d },
+	{ 0xE46, 0x04 },
+	{ 0xE47, 0x14 },
+	{ 0xE48, 0x0f },
+	{ 0xE49, 0x1d },
+	{ 0xE4A, 0x1a },
+	{ 0xE4B, 0x39 },
+	{ 0xE4C, 0x4c },
+	{ 0xE4D, 0x1e },
+	{ 0xE4E, 0x43 },
+	{ 0xE4F, 0x61 },
+
+	/* Blue Negative Gamma */
+	{ 0xE50, 0x08 },
+	{ 0xE51, 0x2c },
+	{ 0xE52, 0x4e },
+	{ 0xE53, 0x13 },
+	{ 0xE54, 0x3a },
+	{ 0xE55, 0x26 },
+	{ 0xE56, 0x30 },
+	{ 0xE57, 0x0f },
+	{ 0xE58, 0x0a },
+	{ 0xE59, 0x49 },
+	{ 0xE5A, 0x34 },
+	{ 0xE5B, 0x4a },
+	{ 0xE5C, 0x53 },
+	{ 0xE5D, 0x28 },
+	{ 0xE5E, 0x26 },
+	{ 0xE5F, 0x27 },
+
+#endif
+	/* Sleep in mode 		*/
+	{ 0x110, 0x00 },
+	{ 0x1,   0x23 },
+	/* Display on mode 		*/
+	{ 0x290, 0x00 },
+	{ 0x1,   0x27 },
+	/* Driver output control	*/
+	{ 0x372, 0x01 },
+	{ 0x1,   0x40 },
+	/* Display on mode		*/
+	{ 0x290, 0x01 },
+};
+
+static const struct mddi_table tpo2_display_on[] = {
+	{ 0x290, 0x01 },
+};
+
+static const struct mddi_table tpo2_display_off[] = {
+	{ 0x110, 0x01 },
+	{ 0x290, 0x00 },
+	{ 0x1,   100 },
+};
+
+static const struct mddi_table tpo2_power_off[] = {
+	{ 0x0110, 0x01 },
+};
+
+static int nt35399_detect_panel(struct msm_mddi_client_data *client_data)
+{
+	int id = -1, i ;
+
+	/* If the MDDI client is failed to report the panel ID,
+	 * perform retrial 5 times.
+	 */
+	for( i=0; i < 5; i++ ) {
+		client_data->remote_write(client_data, 0, 0x110);
+		msleep(5);
+		id = client_data->remote_read(client_data, userid) ;
+		if( id == 0 || id == 1 ) {
+			if(i==0) {
+				printk(KERN_ERR "%s: got valid panel ID=%d, "
+						"without retry\n",
+						__FUNCTION__, id);
+			}
+			else {
+				printk(KERN_ERR "%s: got valid panel ID=%d, "
+						"after %d retry\n",
+						__FUNCTION__, id, i+1);
+			}
+			break ;
+		}
+		printk(KERN_ERR "%s: got invalid panel ID:%d, trial #%d\n",
+				__FUNCTION__, id, i+1);
+
+		gpio_set_value(MDDI_RST_N, 0);
+		msleep(5);
+
+		gpio_set_value(MDDI_RST_N, 1);
+		msleep(10);
+		gpio_set_value(MDDI_RST_N, 0);
+		udelay(100);
+		gpio_set_value(MDDI_RST_N, 1);
+		mdelay(10);
+	}
+	printk(KERN_INFO "%s: final panel id=%d\n", __FUNCTION__, id);
+
+	switch(id) {
+	case 0:
+		return SAPPHIRE_PANEL_TOPPOLY;
+	case 1:
+		return SAPPHIRE_PANEL_SHARP;
+	default :
+		printk(KERN_ERR "%s(): Invalid panel ID: %d, "
+				"treat as sharp panel.", __FUNCTION__, id);
+		return SAPPHIRE_PANEL_SHARP;
+	}
+}
+
+static int nt35399_client_init(
+		struct msm_mddi_bridge_platform_data *bridge_data,
+		struct msm_mddi_client_data *client_data)
+{
+	int panel_id;
+
+	if (g_panel_inited == 0) {
+		g_panel_id = panel_id = nt35399_detect_panel(client_data);
+		g_panel_inited = 1 ;
+	} else {
+		gpio_set_value(MDDI_RST_N, 1);
+		msleep(10);
+		gpio_set_value(MDDI_RST_N, 0);
+		udelay(100);
+		gpio_set_value(MDDI_RST_N, 1);
+		mdelay(10);
+
+		g_panel_id = panel_id = nt35399_detect_panel(client_data);
+		if (panel_id == -1) {
+			printk("Invalid panel id\n");
+			return -1;
+		}
+
+		client_data->auto_hibernate(client_data, 0);
+		if (panel_id == SAPPHIRE_PANEL_TOPPOLY) {
+			sapphire_process_mddi_table(client_data, tpo2_init_table,
+						    ARRAY_SIZE(tpo2_init_table));
+		} else if(panel_id == SAPPHIRE_PANEL_SHARP) {
+			sapphire_process_mddi_table(client_data, sharp2_init_table,
+						    ARRAY_SIZE(sharp2_init_table));
+		}
+
+		client_data->auto_hibernate(client_data, 1);
+	}
+
+	return 0;
+}
+
+static int nt35399_client_uninit(
+		struct msm_mddi_bridge_platform_data *bridge_data,
+		struct msm_mddi_client_data *cdata)
+{
+	return 0;
+}
+
+static int nt35399_panel_unblank(
+		struct msm_mddi_bridge_platform_data *bridge_data,
+		struct msm_mddi_client_data *client_data)
+{
+	int ret = 0;
+
+	mdelay(20);
+	sapphire_set_backlight_level(0);
+	client_data->auto_hibernate(client_data, 0);
+
+	mutex_lock(&sapphire_backlight_lock);
+	sapphire_set_backlight_level(sapphire_backlight_brightness);
+	sapphire_backlight_off = 0;
+	mutex_unlock(&sapphire_backlight_lock);
+
+	client_data->auto_hibernate(client_data, 1);
+
+	return ret;
+}
+
+static int nt35399_panel_blank(
+		struct msm_mddi_bridge_platform_data *bridge_data,
+		struct msm_mddi_client_data *client_data)
+{
+	int ret = 0;
+
+	client_data->auto_hibernate(client_data, 0);
+	sapphire_process_mddi_table(client_data, tpo2_display_off,
+			ARRAY_SIZE(tpo2_display_off));
+	client_data->auto_hibernate(client_data, 1);
+
+	mutex_lock(&sapphire_backlight_lock);
+	sapphire_set_backlight_level(0);
+	sapphire_backlight_off = 1;
+	mutex_unlock(&sapphire_backlight_lock);
+
+	return ret;
+}
+
+static void sapphire_brightness_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	mutex_lock(&sapphire_backlight_lock);
+	sapphire_backlight_brightness = value;
+	if (!sapphire_backlight_off)
+		sapphire_set_backlight_level(sapphire_backlight_brightness);
+	mutex_unlock(&sapphire_backlight_lock);
+}
+
+static struct led_classdev sapphire_backlight_led = {
+	.name			= "lcd-backlight",
+	.brightness = SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS,
+	.brightness_set = sapphire_brightness_set,
+};
+
+static int sapphire_backlight_probe(struct platform_device *pdev)
+{
+	led_classdev_register(&pdev->dev, &sapphire_backlight_led);
+	return 0;
+}
+
+static int sapphire_backlight_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&sapphire_backlight_led);
+	return 0;
+}
+
+static struct platform_driver sapphire_backlight_driver = {
+	.probe		= sapphire_backlight_probe,
+	.remove		= sapphire_backlight_remove,
+	.driver		= {
+		.name		= "sapphire-backlight",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static struct resource resources_msm_fb[] = {
+	{
+		.start = SMI64_MSM_FB_BASE,
+		.end = SMI64_MSM_FB_BASE + SMI64_MSM_FB_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_mddi_bridge_platform_data toshiba_client_data = {
+	.init = sapphire_mddi_toshiba_client_init,
+	.uninit = sapphire_mddi_toshiba_client_uninit,
+	.blank = sapphire_mddi_panel_blank,
+	.unblank = sapphire_mddi_panel_unblank,
+	.fb_data = {
+		.xres = 320,
+		.yres = 480,
+		.width = 45,
+		.height = 67,
+		.output_format = 0,
+	},
+};
+
+#define NT35399_MFR_NAME	0x0bda
+#define NT35399_PRODUCT_CODE 	0x8a47
+
+static void nt35399_fixup(uint16_t * mfr_name, uint16_t * product_code)
+{
+	printk(KERN_DEBUG "%s: enter.\n", __func__);
+	*mfr_name = NT35399_MFR_NAME ;
+	*product_code= NT35399_PRODUCT_CODE ;
+}
+
+static struct msm_mddi_bridge_platform_data nt35399_client_data = {
+
+	.init = nt35399_client_init,
+	.uninit = nt35399_client_uninit,
+	.blank = nt35399_panel_blank,
+	.unblank = nt35399_panel_unblank,
+	.fb_data = {
+		.xres = 320,
+		.yres = 480,
+		.output_format = 0,
+	},
+};
+
+static struct msm_mddi_platform_data mddi_pdata = {
+	.clk_rate = 122880000,
+	.power_client = sapphire_mddi_power_client,
+	.fixup = nt35399_fixup,
+	.vsync_irq = MSM_GPIO_TO_INT(VSYNC_GPIO),
+	.fb_resource = resources_msm_fb,
+	.num_clients = 2,
+	.client_platform_data = {
+		{
+			.product_id = (0xd263 << 16 | 0),
+			.name = "mddi_c_d263_0000",
+			.id = 0,
+			.client_data = &toshiba_client_data,
+			.clk_rate = 0,
+		},
+		{
+			.product_id =
+				(NT35399_MFR_NAME << 16 | NT35399_PRODUCT_CODE),
+			.name = "mddi_c_simple" ,
+			.id = 0,
+			.client_data = &nt35399_client_data,
+			.clk_rate = 0,
+		},
+	},
+};
+
+static struct platform_device sapphire_backlight = {
+	.name = "sapphire-backlight",
+};
+
+int __init sapphire_init_panel(void)
+{
+	int rc = -1;
+	uint32_t config = PCOM_GPIO_CFG(27, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA); /* GPIO27 */
+
+	if (!machine_is_sapphire())
+		return 0;
+
+	/* checking board as soon as possible */
+	printk("sapphire_init_panel:machine_is_sapphire=%d, machine_arch_type=%d, MACH_TYPE_SAPPHIRE=%d\r\n", machine_is_sapphire(), machine_arch_type, MACH_TYPE_SAPPHIRE);
+	if (!machine_is_sapphire())
+		return 0;
+
+	vreg_lcm_2v85 = vreg_get(0, "gp4");
+	if (IS_ERR(vreg_lcm_2v85))
+		return PTR_ERR(vreg_lcm_2v85);
+
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0);
+
+	/* setup FB by SMI size */
+	if (sapphire_get_smi_size() == 32) {
+		resources_msm_fb[0].start = SMI32_MSM_FB_BASE;
+		resources_msm_fb[0].end = SMI32_MSM_FB_BASE + SMI32_MSM_FB_SIZE - 1;
+	}
+
+	rc = gpio_request(VSYNC_GPIO, "vsync");
+	if (rc)
+		return rc;
+	rc = gpio_direction_input(VSYNC_GPIO);
+	if (rc)
+		return rc;
+	rc = platform_device_register(&msm_device_mdp);
+	if (rc)
+		return rc;
+	msm_device_mddi0.dev.platform_data = &mddi_pdata;
+	rc = platform_device_register(&msm_device_mddi0);
+	if (rc)
+		return rc;
+	platform_device_register(&sapphire_backlight);
+	return platform_driver_register(&sapphire_backlight_driver);
+}
+
+device_initcall(sapphire_init_panel);
diff --git a/arch/arm/mach-msm/board-sapphire-rfkill.c b/arch/arm/mach-msm/board-sapphire-rfkill.c
new file mode 100644
index 0000000..2fd6ea1
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-rfkill.c
@@ -0,0 +1,105 @@
+/* linux/arch/arm/mach-msm/board-sapphire-rfkill.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+/* Control bluetooth power for sapphire platform */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/rfkill.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+
+static struct rfkill *bt_rfk;
+static const char bt_name[] = "brf6300";
+
+extern int sapphire_bt_fastclock_power(int on);
+
+static int bluetooth_set_power(void *data, bool blocked)
+{
+	if (!blocked) {
+		sapphire_bt_fastclock_power(1);
+		gpio_set_value(SAPPHIRE_GPIO_BT_32K_EN, 1);
+		udelay(10);
+		gpio_direction_output(101, 1);
+	} else {
+		gpio_direction_output(101, 0);
+		gpio_set_value(SAPPHIRE_GPIO_BT_32K_EN, 0);
+		sapphire_bt_fastclock_power(0);
+	}
+	return 0;
+}
+
+static struct rfkill_ops sapphire_rfkill_ops = {
+	.set_block = bluetooth_set_power,
+};
+
+static int sapphire_rfkill_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	bool default_state = true;  /* off */
+
+	bluetooth_set_power(NULL, default_state);
+
+	bt_rfk = rfkill_alloc(bt_name, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
+			      &sapphire_rfkill_ops, NULL);
+	if (!bt_rfk)
+		return -ENOMEM;
+
+	/* userspace cannot take exclusive control */
+
+	rfkill_set_states(bt_rfk, default_state, false);
+
+	rc = rfkill_register(bt_rfk);
+
+	if (rc)
+		rfkill_destroy(bt_rfk);
+	return rc;
+}
+
+static int sapphire_rfkill_remove(struct platform_device *dev)
+{
+	rfkill_unregister(bt_rfk);
+	rfkill_destroy(bt_rfk);
+
+	return 0;
+}
+
+static struct platform_driver sapphire_rfkill_driver = {
+	.probe = sapphire_rfkill_probe,
+	.remove = sapphire_rfkill_remove,
+	.driver = {
+		.name = "sapphire_rfkill",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init sapphire_rfkill_init(void)
+{
+	return platform_driver_register(&sapphire_rfkill_driver);
+}
+
+static void __exit sapphire_rfkill_exit(void)
+{
+	platform_driver_unregister(&sapphire_rfkill_driver);
+}
+
+module_init(sapphire_rfkill_init);
+module_exit(sapphire_rfkill_exit);
+MODULE_DESCRIPTION("sapphire rfkill");
+MODULE_AUTHOR("Nick Pelly <npelly@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-sapphire-wifi.c b/arch/arm/mach-msm/board-sapphire-wifi.c
new file mode 100644
index 0000000..43f827c
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-wifi.c
@@ -0,0 +1,74 @@
+/* arch/arm/mach-msm/board-sapphire-wifi.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Dmitry Shmidt <dimitrysh@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+#include <linux/wifi_tiwlan.h>
+
+extern int sapphire_wifi_set_carddetect(int val);
+extern int sapphire_wifi_power(int on);
+extern int sapphire_wifi_reset(int on);
+
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+typedef struct wifi_mem_prealloc_struct {
+	void *mem_ptr;
+	unsigned long size;
+} wifi_mem_prealloc_t;
+
+static wifi_mem_prealloc_t wifi_mem_array[WMPA_NUMBER_OF_SECTIONS] = {
+	{ NULL, (WMPA_SECTION_SIZE_0 + WMPA_SECTION_HEADER) },
+	{ NULL, (WMPA_SECTION_SIZE_1 + WMPA_SECTION_HEADER) },
+	{ NULL, (WMPA_SECTION_SIZE_2 + WMPA_SECTION_HEADER) }
+};
+
+static void *sapphire_wifi_mem_prealloc(int section, unsigned long size)
+{
+	if ((section < 0) || (section >= WMPA_NUMBER_OF_SECTIONS))
+		return NULL;
+	if (wifi_mem_array[section].size < size)
+		return NULL;
+	return wifi_mem_array[section].mem_ptr;
+}
+
+int __init sapphire_init_wifi_mem (void)
+{
+	int i;
+
+	for (i = 0; (i < WMPA_NUMBER_OF_SECTIONS); i++) {
+		wifi_mem_array[i].mem_ptr = vmalloc(wifi_mem_array[i].size);
+		if (wifi_mem_array[i].mem_ptr == NULL)
+			return -ENOMEM;
+	}
+	return 0;
+}
+#endif
+
+struct wifi_platform_data sapphire_wifi_control = {
+	.set_power		= sapphire_wifi_power,
+	.set_reset		= sapphire_wifi_reset,
+	.set_carddetect		= sapphire_wifi_set_carddetect,
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+	.mem_prealloc		= sapphire_wifi_mem_prealloc,
+#else
+	.mem_prealloc		= NULL,
+#endif
+};
+
+#endif
diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c
index 2bc1b9d..3f05c436 100644
--- a/arch/arm/mach-msm/board-sapphire.c
+++ b/arch/arm/mach-msm/board-sapphire.c
@@ -17,8 +17,17 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/i2c.h>
 #include <linux/irq.h>
+#include <linux/keyreset.h>
+#include <linux/leds.h>
+#include <linux/switch.h>
+#include <linux/synaptics_i2c_rmi.h>
+#include <linux/elan_i2c.h>
+#include <linux/akm8976.h>
+#include <mach/htc_headset.h>
 #include <linux/sysdev.h>
+#include <linux/android_pmem.h>
 
 #include <linux/delay.h>
 
@@ -31,40 +40,1156 @@
 #include <asm/system.h>
 #include <mach/system.h>
 #include <mach/vreg.h>
-#include <mach/board.h>
 
 #include <asm/io.h>
 #include <asm/delay.h>
 #include <asm/setup.h>
 
+#include <linux/gpio_event.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
+#include <asm/mach/mmc.h>
+#include <linux/mmc/sdio_ids.h>
+
+
 #include "gpio_chip.h"
 #include "board-sapphire.h"
+
+#include <mach/board.h>
+#include <mach/board_htc.h>
+#include <mach/msm_serial_debugger.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/htc_pwrsink.h>
+
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+extern int sapphire_init_wifi_mem(void);
+#endif
+extern struct wifi_platform_data sapphire_wifi_control;
+#endif
+
 #include "proc_comm.h"
 #include "devices.h"
 
 void msm_init_irq(void);
 void msm_init_gpio(void);
+void msm_init_pmic_vibrator(void);
+
+extern int sapphire_init_mmc(unsigned int);
+
+struct sapphire_axis_info {
+	struct gpio_event_axis_info info;
+	uint16_t in_state;
+	uint16_t out_state;
+	uint16_t temp_state;
+	uint16_t threshold;
+};
+static bool nav_just_on;
+static int nav_on_jiffies;
+static int smi_sz = 64;
+static unsigned int hwid = 0;
+static unsigned int skuid = 0;
+static unsigned engineerid = (0x01 << 1);	/* default is 3M sensor */
+
+uint16_t sapphire_axis_map(struct gpio_event_axis_info *info, uint16_t in)
+{
+	struct sapphire_axis_info *ai = container_of(info, struct sapphire_axis_info, info);
+	uint16_t out = ai->out_state;
+
+	if (nav_just_on) {
+		if (jiffies == nav_on_jiffies || jiffies == nav_on_jiffies + 1)
+			goto ignore;
+		nav_just_on = 0;
+	}
+	if ((ai->in_state ^ in) & 1)
+		out--;
+	if ((ai->in_state ^ in) & 2)
+		out++;
+	ai->out_state = out;
+ignore:
+	ai->in_state = in;
+	if (ai->out_state - ai->temp_state == ai->threshold) {
+		ai->temp_state++;
+		ai->out_state = ai->temp_state;
+	} else if (ai->temp_state - ai->out_state == ai->threshold) {
+		ai->temp_state--;
+		ai->out_state = ai->temp_state;
+	} else if (abs(ai->out_state - ai->temp_state) > ai->threshold)
+		ai->temp_state = ai->out_state;
+
+	return ai->temp_state;
+}
+
+int sapphire_nav_power(const struct gpio_event_platform_data *pdata, bool on)
+{
+	gpio_set_value(SAPPHIRE_GPIO_JOG_EN, on);
+	if (on) {
+		nav_just_on = 1;
+		nav_on_jiffies = jiffies;
+	}
+	return 0;
+}
+
+static uint32_t sapphire_x_axis_gpios[] = {
+	SAPPHIRE_BALL_LEFT_0, SAPPHIRE_BALL_RIGHT_0
+};
+
+static struct sapphire_axis_info sapphire_x_axis = {
+	.threshold = 2,
+	.info = {
+		.info.func = gpio_event_axis_func,
+		.count = ARRAY_SIZE(sapphire_x_axis_gpios),
+		.type = EV_REL,
+		.code = REL_X,
+		.decoded_size = 1U << ARRAY_SIZE(sapphire_x_axis_gpios),
+		.map = sapphire_axis_map,
+		.gpio = sapphire_x_axis_gpios,
+		.flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */
+	}
+};
+
+static uint32_t sapphire_y_axis_gpios[] = {
+	SAPPHIRE_BALL_UP_0, SAPPHIRE_BALL_DOWN_0
+};
+
+static struct sapphire_axis_info sapphire_y_axis = {
+	.threshold = 2,
+	.info = {
+		.info.func = gpio_event_axis_func,
+		.count = ARRAY_SIZE(sapphire_y_axis_gpios),
+		.type = EV_REL,
+		.code = REL_Y,
+		.decoded_size = 1U << ARRAY_SIZE(sapphire_y_axis_gpios),
+		.map = sapphire_axis_map,
+		.gpio = sapphire_y_axis_gpios,
+		.flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT  */
+	}
+};
+
+static struct gpio_event_direct_entry sapphire_nav_buttons[] = {
+	{ SAPPHIRE_GPIO_NAVI_ACT_N, BTN_MOUSE },
+};
+
+static struct gpio_event_input_info sapphire_nav_button_info = {
+	.info.func = gpio_event_input_func,
+	.flags = GPIOEDF_PRINT_KEYS | GPIOEDF_PRINT_KEY_DEBOUNCE,
+	.poll_time.tv.nsec = 40 * NSEC_PER_MSEC,
+	.type = EV_KEY,
+	.keymap = sapphire_nav_buttons,
+	.keymap_size = ARRAY_SIZE(sapphire_nav_buttons)
+};
+
+static struct gpio_event_info *sapphire_nav_info[] = {
+	&sapphire_x_axis.info.info,
+	&sapphire_y_axis.info.info,
+	&sapphire_nav_button_info.info
+};
+
+static struct gpio_event_platform_data sapphire_nav_data = {
+	.name = "sapphire-nav",
+	.info = sapphire_nav_info,
+	.info_count = ARRAY_SIZE(sapphire_nav_info),
+	.power = sapphire_nav_power,
+};
+
+static struct platform_device sapphire_nav_device = {
+	.name = GPIO_EVENT_DEV_NAME,
+	.id = 2,
+	.dev = {
+		.platform_data = &sapphire_nav_data,
+	},
+};
+
+/* a new search button to be a wake-up source */
+static struct gpio_event_direct_entry sapphire_search_button_v1[] = {
+	{ SAPPHIRE_GPIO_SEARCH_ACT_N, KEY_COMPOSE }, /* CPLD Key Search*/
+};
+
+static struct gpio_event_direct_entry sapphire_search_button_v2[] = {
+	{ SAPPHIRE_GPIO_SEARCH_ACT_N, KEY_HOME }, /* CPLD Key Home */
+};
+
+static struct gpio_event_input_info sapphire_search_button_info = {
+	.info.func = gpio_event_input_func,
+	/* .flags = GPIOEDF_PRINT_KEYS | GPIOEDF_PRINT_KEY_DEBOUNCE, */
+	.flags = 0,
+	.poll_time.tv.nsec = 40 * NSEC_PER_MSEC,
+	.type = EV_KEY,
+	.keymap = sapphire_search_button_v2,
+	.keymap_size = ARRAY_SIZE(sapphire_search_button_v2)
+};
+
+static struct gpio_event_info *sapphire_search_info[] = {
+	&sapphire_search_button_info.info
+};
+
+static struct gpio_event_platform_data sapphire_search_button_data = {
+	.name = "sapphire-nav-button",
+	.info = sapphire_search_info,
+	.info_count = ARRAY_SIZE(sapphire_search_info),
+};
+
+static struct platform_device sapphire_search_button_device = {
+	.name = GPIO_EVENT_DEV_NAME,
+	.id = 1,
+	.dev = {
+		.platform_data = &sapphire_search_button_data,
+	},
+};
+
+static int sapphire_reset_keys_up[] = {
+	BTN_MOUSE,
+	0
+};
+
+static struct keyreset_platform_data sapphire_reset_keys_pdata = {
+	.keys_up = sapphire_reset_keys_up,
+	.keys_down = {
+		KEY_SEND,
+		KEY_MENU,
+		KEY_END,
+		0
+	},
+};
+
+struct platform_device sapphire_reset_keys_device = {
+	.name = KEYRESET_NAME,
+	.dev.platform_data = &sapphire_reset_keys_pdata,
+};
+
+static int gpio_tp_ls_en = SAPPHIRE_TP_LS_EN;
+
+static int sapphire_ts_power(int on)
+{
+	if (on) {
+		sapphire_gpio_write(NULL, SAPPHIRE_GPIO_TP_EN, 1);
+		/* touchscreen must be powered before we enable i2c pullup */
+		msleep(2);
+		/* enable touch panel level shift */
+		gpio_direction_output(gpio_tp_ls_en, 1);
+		msleep(2);
+	} else {
+		gpio_direction_output(gpio_tp_ls_en, 0);
+		udelay(50);
+		sapphire_gpio_write(NULL, SAPPHIRE_GPIO_TP_EN, 0);
+	}
+
+	return 0;
+}
+
+static struct synaptics_i2c_rmi_platform_data sapphire_ts_data[] = {
+{
+		.version = 0x0101,
+		.power = sapphire_ts_power,
+		.flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE,
+		.inactive_left = -50 * 0x10000 / 4334,
+		.inactive_right = -50 * 0x10000 / 4334,
+		.inactive_top = -40 * 0x10000 / 6696,
+		.inactive_bottom = -40 * 0x10000 / 6696,
+		.snap_left_on = 50 * 0x10000 / 4334,
+		.snap_left_off = 60 * 0x10000 / 4334,
+		.snap_right_on = 50 * 0x10000 / 4334,
+		.snap_right_off = 60 * 0x10000 / 4334,
+		.snap_top_on = 100 * 0x10000 / 6696,
+		.snap_top_off = 110 * 0x10000 / 6696,
+		.snap_bottom_on = 100 * 0x10000 / 6696,
+		.snap_bottom_off = 110 * 0x10000 / 6696,
+	},
+	{
+		.flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE,
+		.inactive_left = ((4674 - 4334) / 2 + 200) * 0x10000 / 4334,
+		.inactive_right = ((4674 - 4334) / 2 + 200) * 0x10000 / 4334,
+		.inactive_top = ((6946 - 6696) / 2) * 0x10000 / 6696,
+		.inactive_bottom = ((6946 - 6696) / 2) * 0x10000 / 6696,
+	}
+};
+
+static struct akm8976_platform_data compass_platform_data = {
+	.reset = SAPPHIRE_GPIO_COMPASS_RST_N,
+	.clk_on = SAPPHIRE_GPIO_COMPASS_32K_EN,
+	.intr = SAPPHIRE_GPIO_COMPASS_IRQ,
+};
+
+static struct elan_i2c_platform_data elan_i2c_data[] = {
+	{
+		.version = 0x104,
+		.abs_x_min = 0,
+		.abs_y_min = 0,
+		.intr_gpio = SAPPHIRE_GPIO_TP_ATT_N,
+		.power = sapphire_ts_power,
+	},
+	{
+		.version = 0x103,
+		.abs_x_min = 0,
+		.abs_x_max = 512 * 2,
+		.abs_y_min = 0,
+		.abs_y_max = 896 * 2,
+		.intr_gpio = SAPPHIRE_GPIO_TP_ATT_N,
+		.power = sapphire_ts_power,
+	},
+	{
+		.version = 0x102,
+		.abs_x_min = 0,
+		.abs_x_max = 384,
+		.abs_y_min = 0,
+		.abs_y_max = 576,
+		.intr_gpio = SAPPHIRE_GPIO_TP_ATT_N,
+		.power = sapphire_ts_power,
+	},
+	{
+		.version = 0x101,
+		.abs_x_min = 32 + 1,
+		.abs_x_max = 352 - 1,
+		.abs_y_min = 32 + 1,
+		.abs_y_max = 544 - 1,
+		.intr_gpio = SAPPHIRE_GPIO_TP_ATT_N,
+		.power = sapphire_ts_power,
+	}
+};
+
+static struct i2c_board_info i2c_devices[] = {
+	{
+		I2C_BOARD_INFO(SYNAPTICS_I2C_RMI_NAME, 0x20),
+		.platform_data = sapphire_ts_data,
+		.irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_TP_ATT_N)
+	},
+	{
+		I2C_BOARD_INFO(ELAN_8232_I2C_NAME, 0x10),
+		.platform_data = &elan_i2c_data,
+		.irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_TP_ATT_N),
+	},
+	{
+		I2C_BOARD_INFO("akm8976", 0x1C),
+		.platform_data = &compass_platform_data,
+		.irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_COMPASS_IRQ),
+	},
+#ifdef CONFIG_MSM_CAMERA
+#ifdef CONFIG_MT9P012
+	{
+		I2C_BOARD_INFO("mt9p012", 0x6C >> 1),
+	},
+#endif
+#ifdef CONFIG_MT9T013
+	{
+		I2C_BOARD_INFO("mt9t013", 0x6C),
+	},
+#endif
+#endif/*CONIFIG_MSM_CAMERA*/
+#ifdef CONFIG_SENSORS_MT9T013
+	{
+		I2C_BOARD_INFO("mt9t013", 0x6C >> 1),
+	},
+#endif
+};
+
+#ifdef CONFIG_LEDS_CPLD
+static struct resource cpldled_resources[] = {
+	{
+		.start	= SAPPHIRE_CPLD_LED_BASE,
+		.end	= SAPPHIRE_CPLD_LED_BASE + SAPPHIRE_CPLD_LED_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device android_CPLD_leds = {
+	.name		= "leds-cpld",
+	.id			= -1,
+	.num_resources	= ARRAY_SIZE(cpldled_resources),
+	.resource	= cpldled_resources,
+};
+#endif
+
+static struct gpio_led android_led_list[] = {
+	{
+		.name = "button-backlight",
+		.gpio = SAPPHIRE_GPIO_APKEY_LED_EN,
+	},
+};
+
+static struct gpio_led_platform_data android_leds_data = {
+	.num_leds	= ARRAY_SIZE(android_led_list),
+	.leds		= android_led_list,
+};
+
+static struct platform_device android_leds = {
+	.name		= "leds-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &android_leds_data,
+	},
+};
+
+#ifdef CONFIG_HTC_HEADSET
+/* RTS/CTS to GPO/GPI. */
+static uint32_t uart1_on_gpio_table[] = {
+	/* allenou, uart hs test, 2008/11/18 */
+	#ifdef CONFIG_SERIAL_MSM_HS
+	/* RTS */
+	PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_RTS, 2,
+		      GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	/* CTS */
+	PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_CTS, 2,
+		      GPIO_INPUT, GPIO_PULL_UP, GPIO_8MA),
+	#else
+	/* RTS */
+	PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_RTS, 1,
+		      GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA),
+	/* CTS */
+	PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_CTS, 1,
+		      GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA),
+	#endif
+};
+
+/* RTS,CTS to BT. */
+static uint32_t uart1_off_gpio_table[] = {
+	/* RTS */
+	PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_RTS, 0,
+		      GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+	/* CTS */
+	PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_CTS, 0,
+		      GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA),
+};
+
+/* Sapphire: Switch between UART3 and GPIO */
+static uint32_t uart3_on_gpio_table[] = {
+	/* RX */
+	PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART3_RX, 1,
+		      GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA),
+	/* TX */
+	PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART3_TX, 1,
+		      GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+};
+
+/* set TX,RX to GPI */
+static uint32_t uart3_off_gpi_table[] = {
+	/* RX, H2W DATA */
+	PCOM_GPIO_CFG(SAPPHIRE_GPIO_H2W_DATA, 0,
+		      GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA),
+	/* TX, H2W CLK */
+	PCOM_GPIO_CFG(SAPPHIRE_GPIO_H2W_CLK, 0,
+		      GPIO_INPUT, GPIO_KEEPER, GPIO_2MA),
+};
+
+static int sapphire_h2w_path = H2W_GPIO;
+
+static void h2w_config_cpld(int route)
+{
+	switch (route) {
+	case H2W_UART1:
+		/* Make sure uart1 funtion pin opened. */
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart1_on_gpio_table+0, 0);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart1_on_gpio_table+1, 0);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 1);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 0);
+		sapphire_h2w_path = H2W_UART1;
+		printk(KERN_INFO "H2W route = H2W-UART1, BT-X, UART3-X \n");
+		break;
+	case H2W_BT:
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 1);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1);
+		/* UART1 RTS/CTS to GPO/GPI. */
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart1_off_gpio_table+0, 0);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart1_off_gpio_table+1, 0);
+		sapphire_h2w_path = H2W_BT;
+		printk(KERN_INFO "H2W route = H2W-BT, UART1-X, UART3-X \n");
+		break;
+	case H2W_UART3:
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart3_on_gpio_table+0, 0);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart3_on_gpio_table+1, 0);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1);
+		/* Make sure uart1 funtion pin opened. */
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart1_on_gpio_table+0, 0);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart1_on_gpio_table+1, 0);
+		sapphire_h2w_path = H2W_UART3;
+		printk(KERN_INFO "H2W route = H2W-UART3, BT-UART1 \n");
+		break;
+	case H2W_GPIO: /*H2W_UART3 TX,RX are changed to H2W_GPIO */
+	default:
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 0);
+		/* Set the CPLD connected H2W GPIO's to input */
+		gpio_set_value(SAPPHIRE_GPIO_H2W_CLK_DIR, 0);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_DAT_DIR, 0);
+		/* TX,RX GPI first. */
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart3_off_gpi_table+0, 0);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart3_off_gpi_table+1, 0);
+		/* Make sure uart1 funtion pin opened. */
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart1_on_gpio_table+0, 0);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			      uart1_on_gpio_table+1, 0);
+		sapphire_h2w_path = H2W_GPIO;
+		printk(KERN_INFO "H2W route = H2W-GPIO, BT-UART1 \n");
+		break;
+	}
+}
+
+static void h2w_init_cpld(void)
+{
+	h2w_config_cpld(H2W_UART3);
+}
+
+static int h2w_dat_value;
+static void set_h2w_dat(int n)
+{
+	h2w_dat_value = n;
+	gpio_set_value(SAPPHIRE_GPIO_H2W_DATA, n);
+}
+
+static int h2w_clk_value;
+static void set_h2w_clk(int n)
+{
+	h2w_clk_value = n;
+	gpio_set_value(SAPPHIRE_GPIO_H2W_CLK, n);
+}
+
+static void set_h2w_dat_dir(int n)
+{
+	if (n == 0) /* input */
+		gpio_direction_input(SAPPHIRE_GPIO_H2W_DATA);
+	else
+		gpio_direction_output(SAPPHIRE_GPIO_H2W_DATA, h2w_dat_value);
+
+	gpio_set_value(SAPPHIRE_GPIO_H2W_DAT_DIR, n);
+
+}
+
+static void set_h2w_clk_dir(int n)
+{
+	if (n == 0) /* input */
+		gpio_direction_input(SAPPHIRE_GPIO_H2W_CLK);
+	else
+		gpio_direction_output(SAPPHIRE_GPIO_H2W_CLK, h2w_clk_value);
+
+	gpio_set_value(SAPPHIRE_GPIO_H2W_CLK_DIR, n);
+}
+
+static int get_h2w_dat(void)
+{
+	return gpio_get_value(SAPPHIRE_GPIO_H2W_DATA);
+}
+
+static int get_h2w_clk(void)
+{
+	return gpio_get_value(SAPPHIRE_GPIO_H2W_CLK);
+}
+
+static int set_h2w_path(const char *val, struct kernel_param *kp)
+{
+	int ret = -EINVAL;
+
+	ret = param_set_int(val, kp);
+	if (ret)
+		return ret;
+
+	switch (sapphire_h2w_path) {
+	case H2W_GPIO:
+	case H2W_UART1:
+	case H2W_UART3:
+	case H2W_BT:
+		break;
+	default:
+		sapphire_h2w_path = -1;
+		return -EINVAL;
+	}
+
+	h2w_config_cpld(sapphire_h2w_path);
+	return ret;
+}
+module_param_call(h2w_path, set_h2w_path, param_get_int,
+		&sapphire_h2w_path, S_IWUSR | S_IRUGO);
+
+
+static struct h2w_platform_data sapphire_h2w_data = {
+	.power_name		= "wlan",
+	.cable_in1		= SAPPHIRE_GPIO_CABLE_IN1,
+	.cable_in2		= SAPPHIRE_GPIO_CABLE_IN2,
+	.h2w_clk		= SAPPHIRE_GPIO_H2W_CLK,
+	.h2w_data		= SAPPHIRE_GPIO_H2W_DATA,
+	.headset_mic_35mm	= SAPPHIRE_GPIO_AUD_HSMIC_DET_N,
+	.debug_uart 		= H2W_UART3,
+	.config_cpld 		= h2w_config_cpld,
+	.init_cpld 		= h2w_init_cpld,
+	.set_dat		= set_h2w_dat,
+	.set_clk		= set_h2w_clk,
+	.set_dat_dir		= set_h2w_dat_dir,
+	.set_clk_dir		= set_h2w_clk_dir,
+	.get_dat		= get_h2w_dat,
+	.get_clk		= get_h2w_clk,
+};
+
+static struct platform_device sapphire_h2w = {
+	.name		= "h2w",
+	.id			= -1,
+	.dev		= {
+		.platform_data	= &sapphire_h2w_data,
+	},
+};
+#endif
+
+static void sapphire_phy_reset(void)
+{
+	gpio_set_value(SAPPHIRE_GPIO_USB_PHY_RST_N, 0);
+	mdelay(10);
+	gpio_set_value(SAPPHIRE_GPIO_USB_PHY_RST_N, 1);
+	mdelay(10);
+}
+
+static struct pwr_sink sapphire_pwrsink_table[] = {
+	{
+		.id	= PWRSINK_AUDIO,
+		.ua_max	= 100000,
+	},
+	{
+		.id	= PWRSINK_BACKLIGHT,
+		.ua_max	= 125000,
+	},
+	{
+		.id	= PWRSINK_LED_BUTTON,
+		.ua_max	= 0,
+	},
+	{
+		.id	= PWRSINK_LED_KEYBOARD,
+		.ua_max	= 0,
+	},
+	{
+		.id	= PWRSINK_GP_CLK,
+		.ua_max	= 0,
+	},
+	{
+		.id	= PWRSINK_BLUETOOTH,
+		.ua_max	= 15000,
+	},
+	{
+		.id	= PWRSINK_CAMERA,
+		.ua_max	= 0,
+	},
+	{
+		.id	= PWRSINK_SDCARD,
+		.ua_max	= 0,
+	},
+	{
+		.id	= PWRSINK_VIDEO,
+		.ua_max	= 0,
+	},
+	{
+		.id	= PWRSINK_WIFI,
+		.ua_max = 200000,
+	},
+	{
+		.id	= PWRSINK_SYSTEM_LOAD,
+		.ua_max	= 100000,
+		.percent_util = 38,
+	},
+};
+
+static int sapphire_pwrsink_resume_early(struct platform_device *pdev)
+{
+	htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 7);
+	return 0;
+}
+
+static void sapphire_pwrsink_resume_late(struct early_suspend *h)
+{
+	htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 38);
+}
+
+static void sapphire_pwrsink_suspend_early(struct early_suspend *h)
+{
+	htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 7);
+}
+
+static int sapphire_pwrsink_suspend_late(struct platform_device *pdev, pm_message_t state)
+{
+	htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 1);
+	return 0;
+}
+
+static struct pwr_sink_platform_data sapphire_pwrsink_data = {
+	.num_sinks	= ARRAY_SIZE(sapphire_pwrsink_table),
+	.sinks		= sapphire_pwrsink_table,
+	.suspend_late	= sapphire_pwrsink_suspend_late,
+	.resume_early	= sapphire_pwrsink_resume_early,
+	.suspend_early	= sapphire_pwrsink_suspend_early,
+	.resume_late	= sapphire_pwrsink_resume_late,
+};
+
+static struct platform_device sapphire_pwr_sink = {
+	.name = "htc_pwrsink",
+	.id = -1,
+	.dev	= {
+		.platform_data = &sapphire_pwrsink_data,
+	},
+};
+
+static struct platform_device sapphire_rfkill = {
+	.name = "sapphire_rfkill",
+	.id = -1,
+};
+
+static struct msm_pmem_setting pmem_setting_32 = {
+	.pmem_start = SMI32_MSM_PMEM_MDP_BASE,
+	.pmem_size = SMI32_MSM_PMEM_MDP_SIZE,
+	.pmem_adsp_start = SMI32_MSM_PMEM_ADSP_BASE,
+	.pmem_adsp_size = SMI32_MSM_PMEM_ADSP_SIZE,
+	.pmem_gpu0_start = MSM_PMEM_GPU0_BASE,
+	.pmem_gpu0_size = MSM_PMEM_GPU0_SIZE,
+	.pmem_gpu1_start = MSM_PMEM_GPU1_BASE,
+	.pmem_gpu1_size = MSM_PMEM_GPU1_SIZE,
+	.pmem_camera_start = 0,
+	.pmem_camera_size = 0,
+	.ram_console_start = MSM_RAM_CONSOLE_BASE,
+	.ram_console_size = MSM_RAM_CONSOLE_SIZE,
+};
+
+static struct msm_pmem_setting pmem_setting_64 = {
+	.pmem_start = SMI64_MSM_PMEM_MDP_BASE,
+	.pmem_size = SMI64_MSM_PMEM_MDP_SIZE,
+	.pmem_adsp_start = SMI64_MSM_PMEM_ADSP_BASE,
+	.pmem_adsp_size = SMI64_MSM_PMEM_ADSP_SIZE,
+	.pmem_gpu0_start = MSM_PMEM_GPU0_BASE,
+	.pmem_gpu0_size = MSM_PMEM_GPU0_SIZE,
+	.pmem_gpu1_start = MSM_PMEM_GPU1_BASE,
+	.pmem_gpu1_size = MSM_PMEM_GPU1_SIZE,
+	.pmem_camera_start = SMI64_MSM_PMEM_CAMERA_BASE,
+	.pmem_camera_size = SMI64_MSM_PMEM_CAMERA_SIZE,
+	.ram_console_start = MSM_RAM_CONSOLE_BASE,
+	.ram_console_size = MSM_RAM_CONSOLE_SIZE,
+};
+
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+static struct platform_device sapphire_wifi = {
+	.name		= "msm_wifi",
+	.id		= 1,
+	.num_resources	= 0,
+	.resource	= NULL,
+	.dev		= {
+		.platform_data = &sapphire_wifi_control,
+	},
+};
+#endif
+
+#define SND(num, desc) { .name = desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+	SND(0, "HANDSET"),
+	SND(1, "SPEAKER"),
+	SND(2, "HEADSET"),
+	SND(3, "BT"),
+	SND(44, "BT_EC_OFF"),
+	SND(10, "HEADSET_AND_SPEAKER"),
+	SND(256, "CURRENT"),
+
+	/* Bluetooth accessories. */
+
+	SND(12, "HTC BH S100"),
+	SND(13, "HTC BH M100"),
+	SND(14, "Motorola H500"),
+	SND(15, "Nokia HS-36W"),
+	SND(16, "PLT 510v.D"),
+	SND(17, "M2500 by Plantronics"),
+	SND(18, "Nokia HDW-3"),
+	SND(19, "HBH-608"),
+	SND(20, "HBH-DS970"),
+	SND(21, "i.Tech BlueBAND"),
+	SND(22, "Nokia BH-800"),
+	SND(23, "Motorola H700"),
+	SND(24, "HTC BH M200"),
+	SND(25, "Jabra JX10"),
+	SND(26, "320Plantronics"),
+	SND(27, "640Plantronics"),
+	SND(28, "Jabra BT500"),
+	SND(29, "Motorola HT820"),
+	SND(30, "HBH-IV840"),
+	SND(31, "6XXPlantronics"),
+	SND(32, "3XXPlantronics"),
+	SND(33, "HBH-PV710"),
+	SND(34, "Motorola H670"),
+	SND(35, "HBM-300"),
+	SND(36, "Nokia BH-208"),
+	SND(37, "Samsung WEP410"),
+	SND(38, "Jabra BT8010"),
+	SND(39, "Motorola S9"),
+	SND(40, "Jabra BT620s"),
+	SND(41, "Nokia BH-902"),
+	SND(42, "HBH-DS220"),
+	SND(43, "HBH-DS980"),
+};
+#undef SND
+
+static struct msm_snd_endpoints sapphire_snd_endpoints = {
+	.endpoints = snd_endpoints_list,
+	.num = ARRAY_SIZE(snd_endpoints_list),
+};
+
+static struct platform_device sapphire_snd = {
+	.name = "msm_snd",
+	.id = -1,
+	.dev	= {
+		.platform_data = &sapphire_snd_endpoints,
+	},
+};
+
+#ifdef CONFIG_MSM_CAMERA
+void config_sapphire_camera_on_gpios(void);
+void config_sapphire_camera_on_gpios(void);
+static struct msm_camera_device_platform_data msm_camera_device_data = {
+	.camera_gpio_on  = config_sapphire_camera_on_gpios,
+	.camera_gpio_off = config_sapphire_camera_off_gpios,
+	.ioext.mdcphy = MSM_MDC_PHYS,
+	.ioext.mdcsz  = MSM_MDC_SIZE,
+	.ioext.appphy = MSM_CLK_CTL_PHYS,
+	.ioext.appsz  = MSM_CLK_CTL_SIZE,
+};
+
+#ifdef CONFIG_MT9T013
+static struct msm_camera_sensor_info msm_camera_sensor_mt9t013_data = {
+	.sensor_name    = "mt9t013",
+	.sensor_reset   = 108,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = SAPPHIRE_GPIO_VCM_PWDN,
+	.pdata          = &msm_camera_device_data,
+};
+
+static struct platform_device msm_camera_sensor_mt9t013 = {
+	.name           = "msm_camera_mt9t013",
+	.dev            = {
+		.platform_data = &msm_camera_sensor_mt9t013_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9P012
+static struct msm_camera_sensor_info msm_camera_sensor_mt9p012_data = {
+	.sensor_name	= "mt9p012",
+	.sensor_reset	= 108,
+	.sensor_pwd	= 85,
+	.vcm_pwd        = SAPPHIRE_GPIO_VCM_PWDN,
+	.pdata		= &msm_camera_device_data,
+};
+
+static struct platform_device msm_camera_sensor_mt9p012 = {
+	.name           = "msm_camera_mt9p012",
+	.dev            = {
+		.platform_data = &msm_camera_sensor_mt9p012_data,
+	},
+};
+#endif
+#endif/*CONFIG_MSM_CAMERA*/
+
+#ifdef CONFIG_SENSORS_MT9T013
+static struct msm_camera_legacy_device_platform_data msm_camera_device_mt9t013 = {
+	.sensor_reset	= 108,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= SAPPHIRE_GPIO_VCM_PWDN,
+	.config_gpio_on = config_sapphire_camera_on_gpios,
+	.config_gpio_off = config_sapphire_camera_off_gpios,
+};
+
+static struct platform_device sapphire_camera = {
+	.name           = "camera",
+	.dev            = {
+		.platform_data = &msm_camera_device_mt9t013,
+	},
+};
+#endif
 
 static struct platform_device *devices[] __initdata = {
 	&msm_device_smd,
-	&msm_device_dmov,
 	&msm_device_nand,
+	&msm_device_i2c,
 	&msm_device_uart1,
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER) && !defined(CONFIG_TROUT_H2W)
 	&msm_device_uart3,
+#endif
+#ifdef CONFIG_SERIAL_MSM_HS
+	&msm_device_uart_dm1,
+#endif
+	&sapphire_nav_device,
+	&sapphire_search_button_device,
+	&sapphire_reset_keys_device,
+	&android_leds,
+#ifdef CONFIG_LEDS_CPLD
+	&android_CPLD_leds,
+#endif
+#ifdef CONFIG_HTC_HEADSET
+	&sapphire_h2w,
+#endif
+#ifdef CONFIG_MT9T013
+	&msm_camera_sensor_mt9t013,
+#endif
+#ifdef CONFIG_MT9P012
+	&msm_camera_sensor_mt9p012,
+#endif
+	&sapphire_rfkill,
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+	&sapphire_wifi,
+#endif
+
+#ifdef CONFIG_HTC_PWRSINK
+	&sapphire_pwr_sink,
+#endif
+	&sapphire_snd,
+#ifdef CONFIG_SENSORS_MT9T013
+	&sapphire_camera,
+#endif
 };
 
 extern struct sys_timer msm_timer;
 
 static void __init sapphire_init_irq(void)
 {
+	printk(KERN_DEBUG "sapphire_init_irq()\n");
 	msm_init_irq();
 }
 
+static uint cpld_iset;
+static uint cpld_charger_en;
+static uint cpld_usb_h2w_sw;
+static uint opt_disable_uart3;
+
+module_param_named(iset, cpld_iset, uint, 0);
+module_param_named(charger_en, cpld_charger_en, uint, 0);
+module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0);
+module_param_named(disable_uart3, opt_disable_uart3, uint, 0);
+
+static void sapphire_reset(void)
+{
+	gpio_set_value(SAPPHIRE_GPIO_PS_HOLD, 0);
+}
+
+static uint32_t gpio_table[] = {
+	/* BLUETOOTH */
+#ifdef CONFIG_SERIAL_MSM_HS
+	PCOM_GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */
+	PCOM_GPIO_CFG(44, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */
+	PCOM_GPIO_CFG(45, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */
+	PCOM_GPIO_CFG(46, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */
+#else
+	PCOM_GPIO_CFG(43, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */
+	PCOM_GPIO_CFG(44, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */
+	PCOM_GPIO_CFG(45, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */
+	PCOM_GPIO_CFG(46, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */
+#endif
+};
+
+
+static uint32_t camera_off_gpio_table[] = {
+	/* CAMERA */
+	PCOM_GPIO_CFG(2, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(3, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(4, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT4 */
+	PCOM_GPIO_CFG(5, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT5 */
+	PCOM_GPIO_CFG(6, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT6 */
+	PCOM_GPIO_CFG(7, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT7 */
+	PCOM_GPIO_CFG(8, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT8 */
+	PCOM_GPIO_CFG(9, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT9 */
+	PCOM_GPIO_CFG(10, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT10 */
+	PCOM_GPIO_CFG(11, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT11 */
+	PCOM_GPIO_CFG(12, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* PCLK */
+	PCOM_GPIO_CFG(13, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* HSYNC_IN */
+	PCOM_GPIO_CFG(14, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* VSYNC_IN */
+	PCOM_GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_table[] = {
+	/* CAMERA */
+	PCOM_GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */
+	PCOM_GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */
+	PCOM_GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */
+	PCOM_GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */
+	PCOM_GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */
+	PCOM_GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */
+	PCOM_GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */
+	PCOM_GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */
+	PCOM_GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */
+	PCOM_GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */
+	PCOM_GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */
+	PCOM_GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */
+	PCOM_GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */
+	PCOM_GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */
+};
+
+static uint32_t camera_off_gpio_12pins_table[] = {
+	/* CAMERA */
+	PCOM_GPIO_CFG(0, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+	PCOM_GPIO_CFG(1, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(2, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(3, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(4, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT4 */
+	PCOM_GPIO_CFG(5, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT5 */
+	PCOM_GPIO_CFG(6, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT6 */
+	PCOM_GPIO_CFG(7, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT7 */
+	PCOM_GPIO_CFG(8, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT8 */
+	PCOM_GPIO_CFG(9, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT9 */
+	PCOM_GPIO_CFG(10, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT10 */
+	PCOM_GPIO_CFG(11, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT11 */
+	PCOM_GPIO_CFG(12, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* PCLK */
+	PCOM_GPIO_CFG(13, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* HSYNC_IN */
+	PCOM_GPIO_CFG(14, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* VSYNC_IN */
+	PCOM_GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_12pins_table[] = {
+	/* CAMERA */
+	PCOM_GPIO_CFG(0, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */
+	PCOM_GPIO_CFG(1, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */
+	PCOM_GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */
+	PCOM_GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */
+	PCOM_GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */
+	PCOM_GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */
+	PCOM_GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */
+	PCOM_GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */
+	PCOM_GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */
+	PCOM_GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */
+	PCOM_GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */
+	PCOM_GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */
+	PCOM_GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */
+	PCOM_GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */
+	PCOM_GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */
+	PCOM_GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */
+};
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for (n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+void config_sapphire_camera_on_gpios(void)
+{
+	/*Add for judage it's 10 pins or 12 pins platform ----->*/
+	if  (is_12pin_camera()) {
+		config_gpio_table(camera_on_gpio_12pins_table,
+				ARRAY_SIZE(camera_on_gpio_12pins_table));
+	} else {
+		config_gpio_table(camera_on_gpio_table,
+				ARRAY_SIZE(camera_on_gpio_table));
+	}
+	/*End Of Add for judage it's 10 pins or 12 pins platform*/
+}
+
+void config_sapphire_camera_off_gpios(void)
+{
+	/*Add for judage it's 10 pins or 12 pins platform ----->*/
+	if (is_12pin_camera()) {
+		config_gpio_table(camera_off_gpio_12pins_table,
+		ARRAY_SIZE(camera_off_gpio_12pins_table));
+	} else {
+		config_gpio_table(camera_off_gpio_table,
+		ARRAY_SIZE(camera_off_gpio_table));
+	}
+	/*End Of Add for judage it's 10 pins or 12 pins platform*/
+}
+
+static void __init config_gpios(void)
+{
+	config_gpio_table(gpio_table, ARRAY_SIZE(gpio_table));
+	config_sapphire_camera_off_gpios();
+}
+
+static struct msm_acpu_clock_platform_data sapphire_clock_data = {
+	.acpu_switch_time_us = 20,
+	.max_speed_delta_khz = 256000,
+	.vdd_switch_time_us = 62,
+	.power_collapse_khz = 19200000,
+	.wait_for_irq_khz = 128000000,
+};
+
+#ifdef CONFIG_SERIAL_MSM_HS
+static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = {
+	.rx_wakeup_irq = MSM_GPIO_TO_INT(45),
+	.inject_rx_on_wakeup = 1,
+	.rx_to_inject = 0x32,
+};
+#endif
+
 static void __init sapphire_init(void)
 {
+	int rc;
+	printk("sapphire_init() revision = 0x%X\n", system_rev);
+
+	/*
+	 * Setup common MSM GPIOS
+	 */
+	config_gpios();
+
+	msm_hw_reset_hook = sapphire_reset;
+
+	msm_acpu_clock_init(&sapphire_clock_data);
+
+	/* adjust GPIOs based on bootloader request */
+	printk("sapphire_init: cpld_usb_hw2_sw = %d\n", cpld_usb_h2w_sw);
+	gpio_set_value(SAPPHIRE_GPIO_USB_H2W_SW, cpld_usb_h2w_sw);
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+	if (!opt_disable_uart3)
+		msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3,
+				      &msm_device_uart3.dev, 1,
+				      MSM_GPIO_TO_INT(86));
+#endif
+
+	/* gpio_configure(108, IRQF_TRIGGER_LOW); */
+
+	/* H2W pins <-> UART3, Bluetooth <-> UART1 */
+	gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+	gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1);
+	/* put the AF VCM in powerdown mode to avoid noise */
+	if (sapphire_is_5M_camera())
+		sapphire_gpio_write(NULL, SAPPHIRE_GPIO_VCM_PWDN, 0);
+	else
+		sapphire_gpio_write(NULL, SAPPHIRE_GPIO_VCM_PWDN, 1);
+	mdelay(100);
+
+	printk(KERN_DEBUG "sapphire_is_5M_camera=%d\n",
+	       sapphire_is_5M_camera());
+	printk(KERN_DEBUG "is_12pin_camera=%d\n", is_12pin_camera());
+#ifdef CONFIG_SERIAL_MSM_HS
+	msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+#endif
+	msm_add_usb_devices(sapphire_phy_reset);
+
+	if (32 == smi_sz)
+		msm_add_mem_devices(&pmem_setting_32);
+	else
+		msm_add_mem_devices(&pmem_setting_64);
+
+	rc = sapphire_init_mmc(system_rev);
+	if (rc)
+		printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc);
+
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+	rc = sapphire_init_wifi_mem();
+	if (rc) {
+		printk(KERN_CRIT "%s: WiFi memory init failure (%d)\n",
+		       __func__, rc);
+	}
+#endif
+	msm_init_pmic_vibrator();
+
+	if(system_rev != 0x80)
+		sapphire_search_button_info.keymap = sapphire_search_button_v1;
+
+	if (is_12pin_camera())
+		gpio_tp_ls_en = SAPPHIRE20_TP_LS_EN;
+	gpio_request(gpio_tp_ls_en, "tp_ls_en");
+
+	i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
@@ -77,22 +1202,88 @@
 	}
 };
 
+
+unsigned int sapphire_get_hwid(void)
+{
+	return hwid;
+}
+
+unsigned int sapphire_get_skuid(void)
+{
+	return skuid;
+}
+
+unsigned sapphire_engineerid(void)
+{
+	return engineerid;
+}
+
+int sapphire_is_5M_camera(void)
+{
+	int ret = 0;
+	if (sapphire_get_skuid() == 0x1FF00 && !(sapphire_engineerid() & 0x02))
+		ret = 1;
+	else if (sapphire_get_skuid() == 0x20100 && !(sapphire_engineerid() & 0x02))
+		ret = 1;
+	return ret;
+}
+
+/* it can support 3M and 5M sensor */
+unsigned int is_12pin_camera(void)
+{
+	unsigned int ret = 0;
+
+	if (sapphire_get_skuid() == 0x1FF00 || sapphire_get_skuid() == 0x20100)
+		ret = 1;
+	else
+		ret = 0;
+	return ret;
+}
+
+int sapphire_get_smi_size(void)
+{
+	printk(KERN_DEBUG "get_smi_size=%d\n", smi_sz);
+	return smi_sz;
+}
+
 static void __init sapphire_fixup(struct machine_desc *desc, struct tag *tags,
 				  char **cmdline, struct meminfo *mi)
 {
-	int smi_sz = parse_tag_smi((const struct tag *)tags);
+	smi_sz = parse_tag_smi((const struct tag *)tags);
+	printk("sapphire_fixup:smisize=%d\n", smi_sz);
+	hwid = parse_tag_hwid((const struct tag *)tags);
+	printk("sapphire_fixup:hwid=0x%x\n", hwid);
+	skuid = parse_tag_skuid((const struct tag *)tags);
+	printk("sapphire_fixup:skuid=0x%x\n", skuid);
+	engineerid = parse_tag_engineerid((const struct tag *)tags);
+	printk("sapphire_fixup:engineerid=0x%x\n", engineerid);
 
-	mi->nr_banks = 1;
-	mi->bank[0].start = PHYS_OFFSET;
-	mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
 	if (smi_sz == 32) {
+		mi->nr_banks = 1;
+		mi->bank[0].start = PHYS_OFFSET;
+		mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
 		mi->bank[0].size = (84*1024*1024);
 	} else if (smi_sz == 64) {
-		mi->bank[0].size = (101*1024*1024);
+		mi->nr_banks = 2;
+		mi->bank[0].start = SMI64_MSM_LINUX_BASE_1;
+		mi->bank[0].node = PHYS_TO_NID(SMI64_MSM_LINUX_BASE_1);
+		mi->bank[0].size = (32*1024*1024);
+		mi->bank[1].start = SMI64_MSM_LINUX_BASE_2;
+		mi->bank[1].node = PHYS_TO_NID(SMI64_MSM_LINUX_BASE_2);
+		mi->bank[1].size = (84*1024*1024);
 	} else {
-		/* Give a default value when not get smi size */
+		printk(KERN_ERR "can not get smi size\n");
+
+		/*Give a default value when not get smi size*/
 		smi_sz = 64;
-		mi->bank[0].size = (101*1024*1024);
+		mi->nr_banks = 2;
+		mi->bank[0].start = SMI64_MSM_LINUX_BASE_1;
+		mi->bank[0].node = PHYS_TO_NID(SMI64_MSM_LINUX_BASE_1);
+		mi->bank[0].size = (32*1024*1024);
+		mi->bank[1].start = SMI64_MSM_LINUX_BASE_2;
+		mi->bank[1].node = PHYS_TO_NID(SMI64_MSM_LINUX_BASE_2);
+		mi->bank[1].size = (84*1024*1024);
+		printk(KERN_ERR "use default  :  smisize=%d\n", smi_sz);
 	}
 }
 
@@ -100,7 +1291,7 @@
 {
 	msm_map_common_io();
 	iotable_init(sapphire_io_desc, ARRAY_SIZE(sapphire_io_desc));
-	msm_clock_init();
+	msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a);
 }
 
 MACHINE_START(SAPPHIRE, "sapphire")
@@ -109,7 +1300,7 @@
 	.phys_io        = MSM_DEBUG_UART_PHYS,
 	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
-	.boot_params    = PHYS_OFFSET + 0x100,
+	.boot_params    = 0x02000100,
 	.fixup          = sapphire_fixup,
 	.map_io         = sapphire_map_io,
 	.init_irq       = sapphire_init_irq,
diff --git a/arch/arm/mach-msm/board-sapphire.h b/arch/arm/mach-msm/board-sapphire.h
new file mode 100644
index 0000000..d96760a
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire.h
@@ -0,0 +1,224 @@
+/* linux/arch/arm/mach-msm/board-sapphire.h
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_SAPPHIRE_H
+#define __ARCH_ARM_MACH_MSM_BOARD_SAPPHIRE_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE		0x00000000
+#define MSM_SMI_SIZE		0x00800000
+
+#define MSM_EBI_BASE		0x10000000
+#define MSM_EBI_SIZE		0x07100000
+
+#define MSM_PMEM_GPU0_BASE	0x00000000
+#define MSM_PMEM_GPU0_SIZE	0x00700000
+
+#define SMI64_MSM_PMEM_MDP_BASE	0x15900000
+#define SMI64_MSM_PMEM_MDP_SIZE	0x00800000
+
+#define SMI64_MSM_PMEM_ADSP_BASE	0x16100000
+#define SMI64_MSM_PMEM_ADSP_SIZE	0x00800000
+
+#define SMI64_MSM_PMEM_CAMERA_BASE	0x15400000
+#define SMI64_MSM_PMEM_CAMERA_SIZE	0x00500000
+
+#define SMI64_MSM_FB_BASE		0x00700000
+#define SMI64_MSM_FB_SIZE		0x00100000
+
+#define SMI64_MSM_LINUX_BASE		MSM_EBI_BASE
+#define SMI64_MSM_LINUX_SIZE		0x068e0000
+
+#define SMI64_MSM_LINUX_BASE_1		0x02000000
+#define SMI64_MSM_LINUX_SIZE_1		0x02000000
+
+#define SMI64_MSM_LINUX_BASE_2		MSM_EBI_BASE
+#define SMI64_MSM_LINUX_SIZE_2		0x05400000
+
+#define SMI32_MSM_LINUX_BASE		MSM_EBI_BASE
+#define SMI32_MSM_LINUX_SIZE		0x5400000
+
+#define SMI32_MSM_PMEM_MDP_BASE	SMI32_MSM_LINUX_BASE + SMI32_MSM_LINUX_SIZE
+#define SMI32_MSM_PMEM_MDP_SIZE	0x800000
+
+#define SMI32_MSM_PMEM_ADSP_BASE	SMI32_MSM_PMEM_MDP_BASE + SMI32_MSM_PMEM_MDP_SIZE
+#define SMI32_MSM_PMEM_ADSP_SIZE	0x800000
+
+#define SMI32_MSM_FB_BASE		SMI32_MSM_PMEM_ADSP_BASE + SMI32_MSM_PMEM_ADSP_SIZE
+#define SMI32_MSM_FB_SIZE		0x9b000
+
+
+#define MSM_PMEM_GPU1_SIZE	0x800000
+#define MSM_PMEM_GPU1_BASE     (MSM_RAM_CONSOLE_BASE + MSM_RAM_CONSOLE_SIZE)
+
+#define MSM_RAM_CONSOLE_BASE	0x169E0000
+#define MSM_RAM_CONSOLE_SIZE	128 * SZ_1K
+
+#if (SMI32_MSM_FB_BASE + SMI32_MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#if (SMI64_MSM_FB_BASE + SMI64_MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#define DECLARE_MSM_IOMAP
+#include <mach/msm_iomap.h>
+
+/*
+** SOC GPIO
+*/
+#define SAPPHIRE_BALL_UP_0     94
+#define SAPPHIRE_BALL_LEFT_0   18
+#define SAPPHIRE_BALL_DOWN_0   49
+#define SAPPHIRE_BALL_RIGHT_0  19
+
+#define SAPPHIRE_POWER_KEY     20
+#define SAPPHIRE_VOLUME_UP     36
+#define SAPPHIRE_VOLUME_DOWN   39
+
+#define SAPPHIRE_GPIO_PS_HOLD   (25)
+#define SAPPHIRE_MDDI_1V5_EN	(28)
+#define SAPPHIRE_BL_PWM			(27)
+#define SAPPHIRE_TP_LS_EN    	(1)
+#define SAPPHIRE20_TP_LS_EN			(88)
+
+/* H2W */
+#define SAPPHIRE_GPIO_CABLE_IN1		(83)
+#define SAPPHIRE_GPIO_CABLE_IN2		(37)
+#define SAPPHIRE_GPIO_UART3_RX		(86)
+#define SAPPHIRE_GPIO_UART3_TX		(87)
+#define SAPPHIRE_GPIO_H2W_DATA		(86)
+#define SAPPHIRE_GPIO_H2W_CLK		(87)
+
+#define SAPPHIRE_GPIO_UART1_RTS		(43)
+#define SAPPHIRE_GPIO_UART1_CTS		(44)
+
+/*
+** CPLD GPIO
+**
+** Sapphire Altera CPLD can keep the registers value and
+** doesn't need a shadow to backup.
+**/
+#define SAPPHIRE_CPLD_BASE   0xFA000000	/* VA */
+#define SAPPHIRE_CPLD_START  0x98000000	/* PA */
+#define SAPPHIRE_CPLD_SIZE   SZ_4K
+
+#define SAPPHIRE_GPIO_START (128)				/* Pseudo GPIO number */
+
+/* Sapphire has one INT BANK only. */
+#define SAPPHIRE_GPIO_INT_B0_MASK_REG           (0x0c)	/*INT3 MASK*/
+#define SAPPHIRE_GPIO_INT_B0_STAT_REG           (0x0e)	/*INT1 STATUS*/
+
+/* LED control register */
+#define SAPPHIRE_CPLD_LED_BASE									(SAPPHIRE_CPLD_BASE + 0x10)		/* VA */
+#define SAPPHIRE_CPLD_LED_START									(SAPPHIRE_CPLD_START + 0x10)	/* PA */
+#define SAPPHIRE_CPLD_LED_SIZE									0x08
+
+/* MISCn: GPO pin to Enable/Disable some functions. */
+#define SAPPHIRE_GPIO_MISC1_BASE               	(SAPPHIRE_GPIO_START + 0x00)
+#define SAPPHIRE_GPIO_MISC2_BASE               	(SAPPHIRE_GPIO_START + 0x08)
+#define SAPPHIRE_GPIO_MISC3_BASE               	(SAPPHIRE_GPIO_START + 0x10)
+#define SAPPHIRE_GPIO_MISC4_BASE               	(SAPPHIRE_GPIO_START + 0x18)
+#define SAPPHIRE_GPIO_MISC5_BASE               	(SAPPHIRE_GPIO_START + 0x20)
+
+/* INT BANK0: INT1: int status, INT2: int level, INT3: int Mask */
+#define SAPPHIRE_GPIO_INT_B0_BASE              	(SAPPHIRE_GPIO_START + 0x28)
+
+/* MISCn GPIO: */
+#define SAPPHIRE_GPIO_CPLD128_VER_0            	(SAPPHIRE_GPIO_MISC1_BASE + 4)
+#define SAPPHIRE_GPIO_CPLD128_VER_1            	(SAPPHIRE_GPIO_MISC1_BASE + 5)
+#define SAPPHIRE_GPIO_CPLD128_VER_2            	(SAPPHIRE_GPIO_MISC1_BASE + 6)
+#define SAPPHIRE_GPIO_CPLD128_VER_3            	(SAPPHIRE_GPIO_MISC1_BASE + 7)
+
+#define SAPPHIRE_GPIO_H2W_DAT_DIR              	(SAPPHIRE_GPIO_MISC2_BASE + 2)
+#define SAPPHIRE_GPIO_H2W_CLK_DIR              	(SAPPHIRE_GPIO_MISC2_BASE + 3)
+#define SAPPHIRE_GPIO_H2W_SEL0                 	(SAPPHIRE_GPIO_MISC2_BASE + 6)
+#define SAPPHIRE_GPIO_H2W_SEL1                 	(SAPPHIRE_GPIO_MISC2_BASE + 7)
+
+#define SAPPHIRE_GPIO_I2C_PULL                 	(SAPPHIRE_GPIO_MISC3_BASE + 2)
+#define SAPPHIRE_GPIO_TP_EN                    	(SAPPHIRE_GPIO_MISC3_BASE + 4)
+#define SAPPHIRE_GPIO_JOG_EN                   	(SAPPHIRE_GPIO_MISC3_BASE + 5)
+#define SAPPHIRE_GPIO_JOG_LED_EN               	(SAPPHIRE_GPIO_MISC3_BASE + 6)
+#define SAPPHIRE_GPIO_APKEY_LED_EN             	(SAPPHIRE_GPIO_MISC3_BASE + 7)
+
+#define SAPPHIRE_GPIO_VCM_PWDN                 	(SAPPHIRE_GPIO_MISC4_BASE + 0)
+#define SAPPHIRE_GPIO_USB_H2W_SW               	(SAPPHIRE_GPIO_MISC4_BASE + 1)
+#define SAPPHIRE_GPIO_COMPASS_RST_N            	(SAPPHIRE_GPIO_MISC4_BASE + 2)
+#define SAPPHIRE_GPIO_USB_PHY_RST_N            	(SAPPHIRE_GPIO_MISC4_BASE + 5)
+#define SAPPHIRE_GPIO_WIFI_PA_RESETX           	(SAPPHIRE_GPIO_MISC4_BASE + 6)
+#define SAPPHIRE_GPIO_WIFI_EN                  	(SAPPHIRE_GPIO_MISC4_BASE + 7)
+
+#define SAPPHIRE_GPIO_BT_32K_EN                	(SAPPHIRE_GPIO_MISC5_BASE + 0)
+#define SAPPHIRE_GPIO_MAC_32K_EN               	(SAPPHIRE_GPIO_MISC5_BASE + 1)
+#define SAPPHIRE_GPIO_MDDI_32K_EN              	(SAPPHIRE_GPIO_MISC5_BASE + 2)
+#define SAPPHIRE_GPIO_COMPASS_32K_EN           	(SAPPHIRE_GPIO_MISC5_BASE + 3)
+
+/* INT STATUS/LEVEL/MASK : INT GPIO should be the last. */
+#define SAPPHIRE_GPIO_NAVI_ACT_N           		(SAPPHIRE_GPIO_INT_B0_BASE + 0)
+#define SAPPHIRE_GPIO_COMPASS_IRQ         		(SAPPHIRE_GPIO_INT_B0_BASE + 1)
+#define SAPPHIRE_GPIO_SEARCH_ACT_N			(SAPPHIRE_GPIO_INT_B0_BASE + 2)
+#define SAPPHIRE_GPIO_AUD_HSMIC_DET_N      		(SAPPHIRE_GPIO_INT_B0_BASE + 3)
+#define SAPPHIRE_GPIO_SDMC_CD_N      			(SAPPHIRE_GPIO_INT_B0_BASE + 4)
+#define SAPPHIRE_GPIO_CAM_BTN_STEP1_N          	(SAPPHIRE_GPIO_INT_B0_BASE + 5)
+#define SAPPHIRE_GPIO_CAM_BTN_STEP2_N          	(SAPPHIRE_GPIO_INT_B0_BASE + 6)
+#define SAPPHIRE_GPIO_TP_ATT_N            		(SAPPHIRE_GPIO_INT_B0_BASE + 7)
+
+#define	SAPPHIRE_GPIO_END						SAPPHIRE_GPIO_TP_ATT_N
+#define	SAPPHIRE_GPIO_LAST_INT					(SAPPHIRE_GPIO_TP_ATT_N)
+
+/* Bit position in the CPLD MISCn by the CPLD GPIOn: only bit0-7 is used. */
+#define	CPLD_GPIO_BIT_POS_MASK(n)		(1U << ((n) & 7))
+#define	CPLD_GPIO_REG_OFFSET(n)			_g_CPLD_MISCn_Offset[((n)-SAPPHIRE_GPIO_START) >> 3]
+#define	CPLD_GPIO_REG(n)				(CPLD_GPIO_REG_OFFSET(n) + SAPPHIRE_CPLD_BASE)
+
+/*
+** CPLD INT Start
+*/
+#define SAPPHIRE_INT_START 					(NR_MSM_IRQS + NR_GPIO_IRQS)	/* pseudo number for CPLD INT */
+/* Using INT status/Bank0 for GPIO to INT */
+#define	SAPPHIRE_GPIO_TO_INT(n)				((n-SAPPHIRE_GPIO_INT_B0_BASE) + SAPPHIRE_INT_START)
+#define SAPPHIRE_INT_END 					(SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_END))
+
+/* get the INT reg by GPIO number */
+#define	CPLD_INT_GPIO_TO_BANK(n)			(((n)-SAPPHIRE_GPIO_INT_B0_BASE) >> 3)
+#define	CPLD_INT_STATUS_REG_OFFSET_G(n)		_g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][0]
+#define	CPLD_INT_LEVEL_REG_OFFSET_G(n)		_g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][1]
+#define	CPLD_INT_MASK_REG_OFFSET_G(n)		_g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][2]
+#define	CPLD_INT_STATUS_REG_G(n)			(SAPPHIRE_CPLD_BASE + CPLD_INT_STATUS_REG_OFFSET_G(n))
+#define	CPLD_INT_LEVEL_REG_G(n)				(SAPPHIRE_CPLD_BASE + CPLD_INT_LEVEL_REG_OFFSET_G(n))
+#define	CPLD_INT_MASK_REG_G(n)				(SAPPHIRE_CPLD_BASE + CPLD_INT_MASK_REG_OFFSET_G(n))
+
+/* get the INT reg by INT number */
+#define	CPLD_INT_TO_BANK(i)					((i-SAPPHIRE_INT_START) >> 3)
+#define	CPLD_INT_STATUS_REG_OFFSET(i)		_g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][0]
+#define	CPLD_INT_LEVEL_REG_OFFSET(i)		_g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][1]
+#define	CPLD_INT_MASK_REG_OFFSET(i)			_g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][2]
+#define	CPLD_INT_STATUS_REG(i)				(SAPPHIRE_CPLD_BASE + CPLD_INT_STATUS_REG_OFFSET(i))
+#define	CPLD_INT_LEVEL_REG(i)				(SAPPHIRE_CPLD_BASE + CPLD_INT_LEVEL_REG_OFFSET(i))
+#define	CPLD_INT_MASK_REG(i)				(SAPPHIRE_CPLD_BASE + CPLD_INT_MASK_REG_OFFSET(i) )
+
+/* return the bit mask by INT number */
+#define SAPPHIRE_INT_BIT_MASK(i) 			(1U << ((i - SAPPHIRE_INT_START) & 7))
+
+void config_sapphire_camera_on_gpios(void);
+void config_sapphire_camera_off_gpios(void);
+int sapphire_get_smi_size(void);
+unsigned int sapphire_get_hwid(void);
+unsigned int sapphire_get_skuid(void);
+unsigned int is_12pin_camera(void);
+int sapphire_is_5M_camera(void);
+int sapphire_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on);
+
+#endif /* GUARD */
diff --git a/arch/arm/mach-msm/board-surf7x30.c b/arch/arm/mach-msm/board-surf7x30.c
new file mode 100644
index 0000000..fe52633
--- /dev/null
+++ b/arch/arm/mach-msm/board-surf7x30.c
@@ -0,0 +1,486 @@
+/* linux/arch/arm/mach-msm/board-surf7x30.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Dima Zavin <dima@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio_event.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/pm8058.h>
+#include <linux/platform_device.h>
+#include <linux/usb/android_composite.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/setup.h>
+
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/msm_hsusb.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_ssbi.h>
+
+#include "devices.h"
+#include "proc_comm.h"
+
+#define SURF7X30_PM8058_GPIO_BASE	FIRST_BOARD_GPIO
+#define SURF7X30_PM8058_GPIO(x)		(SURF7X30_PM8058_GPIO_BASE + (x))
+#define SURF7X30_PM8058_IRQ_BASE	FIRST_BOARD_IRQ
+
+#define SURF7X30_GPIO_PMIC_INT_N	27
+
+#define SURF7X30_USE_PMIC_KEYPAD	1
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start	= 0x8A000300,
+		.end	= 0x8A0003ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= MSM_GPIO_TO_INT(156),
+		.end	= MSM_GPIO_TO_INT(156),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+static int surf7x30_phy_init_seq[] = {
+	0x0C, 0x31,
+	0x31, 0x32,
+	0x1D, 0x0D,
+	0x1D, 0x10,
+	-1 };
+
+static void surf7x30_usb_phy_reset(void)
+{
+	u32 id;
+	int ret;
+
+	id = PCOM_CLKRGM_APPS_RESET_USB_PHY;
+	ret = msm_proc_comm(PCOM_CLK_REGIME_SEC_RESET_ASSERT, &id, NULL);
+	if (ret) {
+		pr_err("%s: Cannot assert (%d)\n", __func__, ret);
+		return;
+	}
+
+	msleep(1);
+
+	id = PCOM_CLKRGM_APPS_RESET_USB_PHY;
+	ret = msm_proc_comm(PCOM_CLK_REGIME_SEC_RESET_DEASSERT, &id, NULL);
+	if (ret) {
+		pr_err("%s: Cannot assert (%d)\n", __func__, ret);
+		return;
+	}
+}
+
+static void surf7x30_usb_hw_reset(bool enable)
+{
+	u32 id;
+	int ret;
+	u32 func;
+
+	id = PCOM_CLKRGM_APPS_RESET_USBH;
+	if (enable)
+		func = PCOM_CLK_REGIME_SEC_RESET_ASSERT;
+	else
+		func = PCOM_CLK_REGIME_SEC_RESET_DEASSERT;
+	ret = msm_proc_comm(func, &id, NULL);
+	if (ret)
+		pr_err("%s: Cannot set reset to %d (%d)\n", __func__, enable,
+		       ret);
+}
+
+static struct msm_hsusb_platform_data msm_hsusb_pdata = {
+	.phy_init_seq		= surf7x30_phy_init_seq,
+	.phy_reset		= surf7x30_usb_phy_reset,
+	.hw_reset		= surf7x30_usb_hw_reset,
+};
+
+static char *usb_functions[] = {
+	"usb_mass_storage",
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	"rndis",
+#endif
+#ifdef CONFIG_USB_ANDROID_ACM
+	"acm",
+#endif
+};
+
+static char *usb_functions_adb[] = {
+	"usb_mass_storage",
+	"adb",
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	"rndis",
+#endif
+#ifdef CONFIG_USB_ANDROID_ACM
+	"acm",
+#endif
+};
+
+#ifdef CONFIG_USB_ANDROID_DIAG
+static char *usb_functions_adb_diag[] = {
+	"usb_mass_storage",
+	"adb",
+	"diag",
+};
+#endif
+
+static char *usb_functions_all[] = {
+	"usb_mass_storage",
+	"adb",
+#ifdef CONFIG_USB_ANDROID_ACM
+	"acm",
+#endif
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	"rndis",
+#endif
+#ifdef CONFIG_USB_ANDROID_DIAG
+	"diag",
+#endif
+};
+
+static struct android_usb_product usb_products[] = {
+	{
+#ifdef CONFIG_USB_ANDROID_ACM
+		.product_id	= 0x4e21,
+#else
+		.product_id	= 0x4e11,
+#endif
+		.num_functions	= ARRAY_SIZE(usb_functions),
+		.functions	= usb_functions,
+	},
+	{
+#ifdef CONFIG_USB_ANDROID_ACM
+		.product_id	= 0x4e22,
+#else
+		.product_id	= 0x4e12,
+#endif
+		.num_functions	= ARRAY_SIZE(usb_functions_adb),
+		.functions	= usb_functions_adb,
+	},
+#ifdef CONFIG_USB_ANDROID_DIAG
+	{
+		.product_id	= 0x4e17,
+		.num_functions	= ARRAY_SIZE(usb_functions_adb_diag),
+		.functions	= usb_functions_adb_diag,
+	},
+#endif
+};
+
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+	.nluns		= 1,
+	.vendor		= "Qualcomm, Inc.",
+	.product	= "Surf7x30",
+	.release	= 0x0100,
+};
+
+static struct platform_device usb_mass_storage_device = {
+	.name	= "usb_mass_storage",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mass_storage_pdata,
+	},
+};
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.vendor_id	= 0x18d1,
+	.product_id	= 0x4e11,
+	.version	= 0x0100,
+	.product_name		= "Surf7x30",
+	.manufacturer_name	= "Qualcomm, Inc.",
+	.num_products = ARRAY_SIZE(usb_products),
+	.products = usb_products,
+	.num_functions = ARRAY_SIZE(usb_functions_all),
+	.functions = usb_functions_all,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+#if SURF7X30_USE_PMIC_KEYPAD
+static struct pm8058_pin_config surf7x30_kpd_input_gpio_cfg = {
+	.vin_src	= PM8058_GPIO_VIN_SRC_VREG_S3,
+	.dir		= PM8058_GPIO_INPUT,
+	.pull_up	= PM8058_GPIO_PULL_UP_31P5,
+	.strength	= PM8058_GPIO_STRENGTH_OFF,
+	.func		= PM8058_GPIO_FUNC_NORMAL,
+	.flags		= PM8058_GPIO_INV_IRQ_POL
+};
+
+static struct pm8058_pin_config surf7x30_kpd_output_gpio_cfg = {
+	.vin_src	= PM8058_GPIO_VIN_SRC_VREG_S3,
+	.dir		= PM8058_GPIO_OUTPUT,
+	.pull_up	= PM8058_GPIO_PULL_NONE,
+	.strength	= PM8058_GPIO_STRENGTH_LOW,
+	.func		= PM8058_GPIO_FUNC_1,
+	.flags		= (PM8058_GPIO_OPEN_DRAIN |
+			   PM8058_GPIO_INV_IRQ_POL),
+};
+
+#else
+
+static struct pm8058_pin_config surf7x30_kpd_input_gpio_cfg = {
+	.vin_src	= PM8058_GPIO_VIN_SRC_VREG_S3,
+	.dir		= PM8058_GPIO_INPUT,
+	.pull_up	= PM8058_GPIO_PULL_UP_31P5,
+	.strength	= PM8058_GPIO_STRENGTH_OFF,
+	.func		= PM8058_GPIO_FUNC_NORMAL,
+	.flags		= PM8058_GPIO_INV_IRQ_POL
+};
+
+static struct pm8058_pin_config surf7x30_kpd_output_gpio_cfg = {
+	.vin_src	= PM8058_GPIO_VIN_SRC_VREG_S3,
+	.dir		= PM8058_GPIO_OUTPUT,
+	.pull_up	= PM8058_GPIO_PULL_NONE,
+	.strength	= PM8058_GPIO_STRENGTH_LOW,
+	.func		= PM8058_GPIO_FUNC_NORMAL,
+	.flags		= (PM8058_GPIO_OPEN_DRAIN |
+			   PM8058_GPIO_INV_IRQ_POL),
+};
+#endif
+
+static unsigned int surf7x30_pmic_col_gpios[] = {
+	SURF7X30_PM8058_GPIO(0), SURF7X30_PM8058_GPIO(1),
+	SURF7X30_PM8058_GPIO(2), SURF7X30_PM8058_GPIO(3),
+	SURF7X30_PM8058_GPIO(4), SURF7X30_PM8058_GPIO(5),
+	SURF7X30_PM8058_GPIO(6), SURF7X30_PM8058_GPIO(7),
+};
+static unsigned int surf7x30_pmic_row_gpios[] = {
+	SURF7X30_PM8058_GPIO(8), SURF7X30_PM8058_GPIO(9),
+	SURF7X30_PM8058_GPIO(10), SURF7X30_PM8058_GPIO(11),
+	SURF7X30_PM8058_GPIO(12), SURF7X30_PM8058_GPIO(13),
+	SURF7X30_PM8058_GPIO(14), SURF7X30_PM8058_GPIO(15),
+	SURF7X30_PM8058_GPIO(16), SURF7X30_PM8058_GPIO(17),
+	SURF7X30_PM8058_GPIO(18), SURF7X30_PM8058_GPIO(19),
+};
+
+#define KEYMAP_NUM_ROWS		ARRAY_SIZE(surf7x30_pmic_row_gpios)
+#define KEYMAP_NUM_COLS		ARRAY_SIZE(surf7x30_pmic_col_gpios)
+#define KEYMAP_INDEX(row, col)	(((row) * KEYMAP_NUM_COLS) + (col))
+#define KEYMAP_SIZE		(KEYMAP_NUM_ROWS * KEYMAP_NUM_COLS)
+
+static int mux_keypad_gpios(struct device *dev)
+{
+	int i;
+
+	for (i = 0; i < KEYMAP_NUM_COLS; ++i)
+		pm8058_gpio_mux_cfg(dev, surf7x30_pmic_col_gpios[i],
+				    &surf7x30_kpd_input_gpio_cfg);
+	for (i = 0; i < KEYMAP_NUM_ROWS; ++i)
+		pm8058_gpio_mux_cfg(dev, surf7x30_pmic_row_gpios[i],
+				    &surf7x30_kpd_output_gpio_cfg);
+	return 0;
+}
+
+/* if we are using the pmic matrix h/w, we need to do the muxing inside the
+ * keypad probe function once the keypad has been setup. */
+static int surf7x30_pmic_keypad_init(struct device *dev)
+{
+	return mux_keypad_gpios(dev->parent);
+}
+
+static const unsigned short surf7x30_pmic_keymap[KEYMAP_SIZE] = {
+	[KEYMAP_INDEX(0, 6)] = KEY_BACK,
+};
+
+static struct pm8058_keypad_platform_data surf7x30_pmic_keypad_pdata = {
+	.name			= "surf7x30-keypad",
+	.num_drv		= KEYMAP_NUM_ROWS,
+	.num_sns		= KEYMAP_NUM_COLS,
+	.scan_delay_shift	= 5,
+	.drv_hold_clks		= 4,
+	.debounce_ms		= 10,
+	.keymap			= surf7x30_pmic_keymap,
+	.init			= surf7x30_pmic_keypad_init,
+};
+
+static struct gpio_event_matrix_info surf7x30_keypad_matrix_info = {
+	.info.func = gpio_event_matrix_func,
+	.keymap = surf7x30_pmic_keymap,
+	.output_gpios = surf7x30_pmic_row_gpios,
+	.input_gpios = surf7x30_pmic_col_gpios,
+	.noutputs = KEYMAP_NUM_ROWS,
+	.ninputs = KEYMAP_NUM_COLS,
+	.settle_time.tv.nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_REMOVE_PHANTOM_KEYS |GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+static struct gpio_event_info *surf7x30_keypad_info[] = {
+	&surf7x30_keypad_matrix_info.info,
+};
+
+static struct gpio_event_platform_data surf7x30_keypad_data = {
+	.name = "surf7x30-keypad",
+	.info = surf7x30_keypad_info,
+	.info_count = ARRAY_SIZE(surf7x30_keypad_info)
+};
+
+static struct platform_device surf7x30_keypad_device = {
+	.name = GPIO_EVENT_DEV_NAME,
+	.id = 0,
+	.dev	= {
+		.platform_data  = &surf7x30_keypad_data,
+	},
+};
+
+static int surf7x30_pmic_init(struct device *dev)
+{
+	int ret = 0;
+
+#if !SURF7X30_USE_PMIC_KEYPAD
+	/* if we are not using the keypad matrix h/w, but are using the
+	 * gpio_matrix, do the pimuxing here, which is called from pmic's
+	 * probe */
+	ret = mux_keypad_gpios(dev);
+#endif
+	return ret;
+}
+
+static struct pm8058_platform_data surf7x30_pm8058_pdata = {
+	.irq_base	= SURF7X30_PM8058_IRQ_BASE,
+	.gpio_base	= SURF7X30_PM8058_GPIO_BASE,
+	.init		= surf7x30_pmic_init,
+
+#if SURF7X30_USE_PMIC_KEYPAD
+	.keypad_pdata	= &surf7x30_pmic_keypad_pdata,
+#endif
+};
+
+static struct msm_ssbi_platform_data surf7x30_ssbi_pmic_pdata = {
+	.slave		= {
+		.name		= "pm8058-core",
+		.irq		= MSM_GPIO_TO_INT(SURF7X30_GPIO_PMIC_INT_N),
+		.platform_data	= &surf7x30_pm8058_pdata,
+	},
+	.rspinlock_name	= "D:PMIC_SSBI",
+};
+
+static int __init surf7x30_ssbi_pmic_init(void)
+{
+	int ret;
+	u32 id;
+
+	pr_info("%s()\n", __func__);
+	id = PCOM_GPIO_CFG(SURF7X30_GPIO_PMIC_INT_N, 1, GPIO_INPUT,
+			   GPIO_NO_PULL, GPIO_2MA);
+	ret = msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	if (ret)
+		pr_err("%s: gpio %d cfg failed\n", __func__,
+		       SURF7X30_GPIO_PMIC_INT_N);
+
+	ret = gpiochip_reserve(surf7x30_pm8058_pdata.gpio_base,
+			       PM8058_NUM_GPIOS);
+	WARN(ret, "can't reserve pm8058 gpios. badness will ensue...\n");
+	msm_device_ssbi_pmic.dev.platform_data = &surf7x30_ssbi_pmic_pdata;
+	return platform_device_register(&msm_device_ssbi_pmic);
+}
+
+
+static struct i2c_board_info surf_i2c_devices[] = {
+	/* marimba master is implied at 0x0c */
+	{
+		I2C_BOARD_INFO("marimba-codec",	0x77),
+	},
+};
+
+extern struct sys_timer msm_timer;
+
+void msm_serial_debug_init(unsigned int base, int irq,
+			   struct device *clk_device, int signal_irq);
+
+static struct platform_device *devices[] __initdata = {
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER)
+	&msm_device_uart1,
+#endif
+	&msm_device_smd,
+	&msm_device_nand,
+	&msm_device_hsusb,
+	&usb_mass_storage_device,
+	&android_usb_device,
+	&smc91x_device,
+	&msm_device_i2c2,
+#if !SURF7X30_USE_PMIC_KEYPAD
+	&surf7x30_keypad_device,
+#endif
+};
+
+static void __init surf7x30_init(void)
+{
+	printk("%s()\n", __func__);
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+	msm_serial_debug_init(MSM_UART1_PHYS, INT_UART1,
+			      &msm_device_uart1.dev, 1);
+#endif
+	/* do this as early as possible to use pmic gpio/mux facilities */
+	surf7x30_ssbi_pmic_init();
+
+	msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata;
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+	i2c_register_board_info(1, surf_i2c_devices,
+				ARRAY_SIZE(surf_i2c_devices));
+	msm_hsusb_set_vbus_state(1);
+	msm_hsusb_set_vbus_state(0);
+	msm_hsusb_set_vbus_state(1);
+}
+
+static void __init surf7x30_fixup(struct machine_desc *desc, struct tag *tags,
+				 char **cmdline, struct meminfo *mi)
+{
+	mi->nr_banks = 1;
+	mi->bank[0].start = PHYS_OFFSET;
+	mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
+	mi->bank[0].size = (51*1024*1024);
+}
+
+static void __init surf7x30_map_io(void)
+{
+	msm_map_msm7x30_io();
+	msm_clock_init(msm_clocks_7x30, msm_num_clocks_7x30);
+}
+
+MACHINE_START(MSM7X30_SURF, "QCT SURF7X30 Development Board")
+#ifdef CONFIG_MSM_DEBUG_UART
+	.phys_io	= MSM_DEBUG_UART_PHYS,
+	.io_pg_offst	= ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+	.boot_params	= 0x00200100,
+	.fixup		= surf7x30_fixup,
+	.map_io		= surf7x30_map_io,
+	.init_irq	= msm_init_irq,
+	.init_machine	= surf7x30_init,
+	.timer		= &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-swordfish-keypad.c b/arch/arm/mach-msm/board-swordfish-keypad.c
new file mode 100644
index 0000000..f2c2f39
--- /dev/null
+++ b/arch/arm/mach-msm/board-swordfish-keypad.c
@@ -0,0 +1,177 @@
+/* linux/arch/arm/mach-msm/board-swordfish-keypad.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <asm/mach-types.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_event.h>
+
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_swordfish."
+static int swordfish_ffa;
+module_param_named(ffa, swordfish_ffa, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SCAN_FUNCTION_KEYS 0 /* don't turn this on without updating the ffa support */
+
+static unsigned int swordfish_row_gpios[] = {
+	31, 32, 33, 34, 35, 41
+#if SCAN_FUNCTION_KEYS
+	, 42
+#endif
+};
+
+static unsigned int swordfish_col_gpios[] = { 36, 37, 38, 39, 40 };
+
+/* FFA:
+ 36: KEYSENSE_N(0)
+ 37: KEYSENSE_N(1)
+ 38: KEYSENSE_N(2)
+ 39: KEYSENSE_N(3)
+ 40: KEYSENSE_N(4)
+
+ 31: KYPD_17
+ 32: KYPD_15
+ 33: KYPD_13
+ 34: KYPD_11
+ 35: KYPD_9
+ 41: KYPD_MEMO
+*/
+
+#define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(swordfish_col_gpios) + (col))
+
+static const unsigned short swordfish_keymap[ARRAY_SIZE(swordfish_col_gpios) * ARRAY_SIZE(swordfish_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_5,
+	[KEYMAP_INDEX(0, 1)] = KEY_9,
+	[KEYMAP_INDEX(0, 2)] = 229,            /* SOFT1 */
+	[KEYMAP_INDEX(0, 3)] = KEY_6,
+	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_0,
+	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 2)] = KEY_1,
+	[KEYMAP_INDEX(1, 3)] = 228,           /* KEY_SHARP */
+	[KEYMAP_INDEX(1, 4)] = KEY_SEND,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(2, 1)] = KEY_HOME,      /* FA   */
+	[KEYMAP_INDEX(2, 2)] = KEY_F8,        /* QCHT */
+	[KEYMAP_INDEX(2, 3)] = KEY_F6,        /* R+   */
+	[KEYMAP_INDEX(2, 4)] = KEY_F7,        /* R-   */
+
+	[KEYMAP_INDEX(3, 0)] = KEY_UP,
+	[KEYMAP_INDEX(3, 1)] = KEY_CLEAR,
+	[KEYMAP_INDEX(3, 2)] = KEY_4,
+	[KEYMAP_INDEX(3, 3)] = KEY_MUTE,      /* SPKR */
+	[KEYMAP_INDEX(3, 4)] = KEY_2,
+
+	[KEYMAP_INDEX(4, 0)] = 230,           /* SOFT2 */
+	[KEYMAP_INDEX(4, 1)] = 232,           /* KEY_CENTER */
+	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+	[KEYMAP_INDEX(4, 3)] = KEY_BACK,      /* FB */
+	[KEYMAP_INDEX(4, 4)] = KEY_8,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[KEYMAP_INDEX(5, 2)] = KEY_MAIL,      /* MESG */
+	[KEYMAP_INDEX(5, 3)] = KEY_3,
+	[KEYMAP_INDEX(5, 4)] = KEY_7,
+
+#if SCAN_FUNCTION_KEYS
+	[KEYMAP_INDEX(6, 0)] = KEY_F5,
+	[KEYMAP_INDEX(6, 1)] = KEY_F4,
+	[KEYMAP_INDEX(6, 2)] = KEY_F3,
+	[KEYMAP_INDEX(6, 3)] = KEY_F2,
+	[KEYMAP_INDEX(6, 4)] = KEY_F1
+#endif
+};
+
+static const unsigned short swordfish_keymap_ffa[ARRAY_SIZE(swordfish_col_gpios) * ARRAY_SIZE(swordfish_row_gpios)] = {
+	/*[KEYMAP_INDEX(0, 0)] = ,*/
+	/*[KEYMAP_INDEX(0, 1)] = ,*/
+	[KEYMAP_INDEX(0, 2)] = KEY_1,
+	[KEYMAP_INDEX(0, 3)] = KEY_SEND,
+	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_3,
+	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 2)] = KEY_VOLUMEUP,
+	/*[KEYMAP_INDEX(1, 3)] = ,*/
+	[KEYMAP_INDEX(1, 4)] = KEY_6,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_HOME,      /* A */
+	[KEYMAP_INDEX(2, 1)] = KEY_BACK,      /* B */
+	[KEYMAP_INDEX(2, 2)] = KEY_0,
+	[KEYMAP_INDEX(2, 3)] = 228,           /* KEY_SHARP */
+	[KEYMAP_INDEX(2, 4)] = KEY_9,
+
+	[KEYMAP_INDEX(3, 0)] = KEY_UP,
+	[KEYMAP_INDEX(3, 1)] = 232, /* KEY_CENTER */ /* i */
+	[KEYMAP_INDEX(3, 2)] = KEY_4,
+	/*[KEYMAP_INDEX(3, 3)] = ,*/
+	[KEYMAP_INDEX(3, 4)] = KEY_2,
+
+	[KEYMAP_INDEX(4, 0)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(4, 1)] = KEY_SOUND,
+	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+	[KEYMAP_INDEX(4, 3)] = KEY_8,
+	[KEYMAP_INDEX(4, 4)] = KEY_5,
+
+	/*[KEYMAP_INDEX(5, 0)] = ,*/
+	[KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */
+	[KEYMAP_INDEX(5, 3)] = KEY_MENU,      /* 1 */
+	[KEYMAP_INDEX(5, 4)] = KEY_7,
+};
+
+static struct gpio_event_matrix_info swordfish_matrix_info = {
+	.info.func	= gpio_event_matrix_func,
+	.keymap		= swordfish_keymap,
+	.output_gpios	= swordfish_row_gpios,
+	.input_gpios	= swordfish_col_gpios,
+	.noutputs	= ARRAY_SIZE(swordfish_row_gpios),
+	.ninputs	= ARRAY_SIZE(swordfish_col_gpios),
+	.settle_time.tv.nsec = 0,
+	.poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.flags		= GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE | GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+struct gpio_event_info *swordfish_keypad_info[] = {
+	&swordfish_matrix_info.info
+};
+
+static struct gpio_event_platform_data swordfish_keypad_data = {
+	.name		= "swordfish_keypad",
+	.info		= swordfish_keypad_info,
+	.info_count	= ARRAY_SIZE(swordfish_keypad_info)
+};
+
+static struct platform_device swordfish_keypad_device = {
+	.name	= GPIO_EVENT_DEV_NAME,
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &swordfish_keypad_data,
+	},
+};
+
+static int __init swordfish_init_keypad(void)
+{
+	if (!machine_is_swordfish())
+		return 0;
+	if (swordfish_ffa)
+		swordfish_matrix_info.keymap = swordfish_keymap_ffa;
+	return platform_device_register(&swordfish_keypad_device);
+}
+
+device_initcall(swordfish_init_keypad);
diff --git a/arch/arm/mach-msm/board-swordfish-mmc.c b/arch/arm/mach-msm/board-swordfish-mmc.c
new file mode 100644
index 0000000..bb0b173
--- /dev/null
+++ b/arch/arm/mach-msm/board-swordfish-mmc.c
@@ -0,0 +1,263 @@
+/* linux/arch/arm/mach-msm/board-swordfish-mmc.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/platform_device.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/mach/mmc.h>
+
+#include <mach/vreg.h>
+
+#include "proc_comm.h"
+#include "devices.h"
+
+#define FPGA_BASE		0x70000000
+#define FPGA_SDIO_STATUS	0x280
+
+static void __iomem *fpga_base;
+
+#define DEBUG_SWORDFISH_MMC 1
+
+extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+			unsigned int stat_irq, unsigned long stat_irq_flags);
+
+static int config_gpio_table(unsigned *table, int len, int enable)
+{
+	int n;
+	int rc = 0;
+
+	for (n = 0; n < len; n++) {
+		unsigned dis = !enable;
+		unsigned id = table[n];
+
+		if (msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, &dis)) {
+			pr_err("%s: id=0x%08x dis=%d\n", __func__, table[n],
+			       dis);
+			rc = -1;
+		}
+	}
+
+	return rc;
+}
+
+static unsigned sdc1_gpio_table[] = {
+	PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
+};
+
+static unsigned sdc2_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
+	PCOM_GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA),
+};
+
+static unsigned sdc3_gpio_table[] = {
+	PCOM_GPIO_CFG(88, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
+	PCOM_GPIO_CFG(89, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(90, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(91, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(92, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(93, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+};
+
+static unsigned sdc4_gpio_table[] = {
+	PCOM_GPIO_CFG(142, 3, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
+	PCOM_GPIO_CFG(143, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(144, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(145, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(146, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(147, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+};
+
+struct sdc_info {
+	unsigned *table;
+	unsigned len;
+};
+
+static struct sdc_info sdcc_gpio_tables[] = {
+	[0] = {
+		.table	= sdc1_gpio_table,
+		.len	= ARRAY_SIZE(sdc1_gpio_table),
+	},
+	[1] = {
+		.table	= sdc2_gpio_table,
+		.len	= ARRAY_SIZE(sdc2_gpio_table),
+	},
+	[2] = {
+		.table	= sdc3_gpio_table,
+		.len	= ARRAY_SIZE(sdc3_gpio_table),
+	},
+	[3] = {
+		.table	= sdc4_gpio_table,
+		.len	= ARRAY_SIZE(sdc4_gpio_table),
+	},
+};
+
+static int swordfish_sdcc_setup_gpio(int dev_id, unsigned enable)
+{
+	struct sdc_info *info;
+
+	if (dev_id < 1 || dev_id > 4)
+		return -1;
+
+	info = &sdcc_gpio_tables[dev_id - 1];
+	return config_gpio_table(info->table, info->len, enable);
+}
+
+struct mmc_vdd_xlat {
+	int mask;
+	int level;
+};
+
+static struct mmc_vdd_xlat mmc_vdd_table[] = {
+	{ MMC_VDD_165_195,	1800 },
+	{ MMC_VDD_20_21,	2050 },
+	{ MMC_VDD_21_22,	2150 },
+	{ MMC_VDD_22_23,	2250 },
+	{ MMC_VDD_23_24,	2350 },
+	{ MMC_VDD_24_25,	2450 },
+	{ MMC_VDD_25_26,	2550 },
+	{ MMC_VDD_26_27,	2650 },
+	{ MMC_VDD_27_28,	2750 },
+	{ MMC_VDD_28_29,	2850 },
+	{ MMC_VDD_29_30,	2950 },
+};
+
+static struct vreg *vreg_sdcc;
+static unsigned int vreg_sdcc_enabled;
+static unsigned int sdcc_vdd = 0xffffffff;
+
+static uint32_t sdcc_translate_vdd(struct device *dev, unsigned int vdd)
+{
+	int i;
+	int rc = 0;
+	struct platform_device *pdev;
+
+	pdev = container_of(dev, struct platform_device, dev);
+	BUG_ON(!vreg_sdcc);
+
+	if (vdd == sdcc_vdd)
+		return 0;
+
+	sdcc_vdd = vdd;
+
+	/* enable/disable the signals to the slot */
+	swordfish_sdcc_setup_gpio(pdev->id, !!vdd);
+
+	/* power down */
+	if (vdd == 0) {
+#if DEBUG_SWORDFISH_MMC
+		pr_info("%s: disable sdcc power\n", __func__);
+#endif
+		vreg_disable(vreg_sdcc);
+		vreg_sdcc_enabled = 0;
+		return 0;
+	}
+
+	if (!vreg_sdcc_enabled) {
+		rc = vreg_enable(vreg_sdcc);
+		if (rc)
+			pr_err("%s: Error enabling vreg (%d)\n", __func__, rc);
+		vreg_sdcc_enabled = 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+		if (mmc_vdd_table[i].mask != (1 << vdd))
+			continue;
+#if DEBUG_SWORDFISH_MMC
+		pr_info("%s: Setting level to %u\n", __func__,
+			mmc_vdd_table[i].level);
+#endif
+		rc = vreg_set_level(vreg_sdcc, mmc_vdd_table[i].level);
+		if (rc)
+			pr_err("%s: Error setting vreg level (%d)\n", __func__, 				rc);
+		return 0;
+	}
+
+	pr_err("%s: Invalid VDD %d specified\n", __func__, vdd);
+	return 0;
+}
+
+static unsigned int swordfish_sdcc_slot_status (struct device *dev)
+{
+	struct platform_device *pdev;
+	uint32_t sdcc_stat;
+
+	pdev = container_of(dev, struct platform_device, dev);
+
+	sdcc_stat = readl(fpga_base + FPGA_SDIO_STATUS);
+
+	/* bit 0 - sdcc1 crd_det
+	 * bit 1 - sdcc1 wr_prt
+	 * bit 2 - sdcc2 crd_det
+	 * bit 3 - sdcc2 wr_prt
+	 * etc...
+	 */
+
+	/* crd_det is active low */
+	return !(sdcc_stat & (1 << ((pdev->id - 1) << 1)));
+}
+
+#define SWORDFISH_MMC_VDD (MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \
+			| MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \
+			| MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
+			| MMC_VDD_28_29 | MMC_VDD_29_30)
+
+static struct mmc_platform_data swordfish_sdcc_data = {
+	.ocr_mask	= SWORDFISH_MMC_VDD/*MMC_VDD_27_28 | MMC_VDD_28_29*/,
+	.status		= swordfish_sdcc_slot_status,
+	.translate_vdd	= sdcc_translate_vdd,
+};
+
+int __init swordfish_init_mmc(void)
+{
+	vreg_sdcc_enabled = 0;
+	vreg_sdcc = vreg_get(NULL, "gp5");
+	if (IS_ERR(vreg_sdcc)) {
+		pr_err("%s: vreg get failed (%ld)\n",
+		       __func__, PTR_ERR(vreg_sdcc));
+		return PTR_ERR(vreg_sdcc);
+	}
+
+	fpga_base = ioremap(FPGA_BASE, SZ_4K);
+	if (!fpga_base) {
+		pr_err("%s: Can't ioremap FPGA base address (0x%08x)\n",
+		       __func__, FPGA_BASE);
+		vreg_put(vreg_sdcc);
+		return -EIO;
+	}
+
+	msm_add_sdcc(1, &swordfish_sdcc_data, 0, 0);
+	msm_add_sdcc(4, &swordfish_sdcc_data, 0, 0);
+
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/board-swordfish-panel.c b/arch/arm/mach-msm/board-swordfish-panel.c
new file mode 100644
index 0000000..cf5f3f6
--- /dev/null
+++ b/arch/arm/mach-msm/board-swordfish-panel.c
@@ -0,0 +1,116 @@
+/* linux/arch/arm/mach-msm/board-swordfish-panel.c
+ *
+ * Copyright (c) 2009 Google Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Author: Dima Zavin <dima@android.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+
+#include "board-swordfish.h"
+#include "devices.h"
+
+#define CLK_NS_TO_RATE(ns)			(1000000000UL / (ns))
+
+int swordfish_panel_blank(struct msm_lcdc_panel_ops *ops)
+{
+	/* TODO: Turn backlight off? */
+	return 0;
+}
+
+int swordfish_panel_unblank(struct msm_lcdc_panel_ops *ops)
+{
+	/* TODO: Turn backlight on? */
+	return 0;
+}
+
+int swordfish_panel_init(struct msm_lcdc_panel_ops *ops)
+{
+	return 0;
+}
+
+static struct resource resources_msm_fb[] = {
+	{
+		.start = MSM_FB_BASE,
+		.end = MSM_FB_BASE + MSM_FB_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_lcdc_timing swordfish_lcdc_timing = {
+	.clk_rate		= CLK_NS_TO_RATE(26),
+	.hsync_pulse_width	= 60,
+	.hsync_back_porch	= 81,
+	.hsync_front_porch	= 81,
+	.hsync_skew		= 0,
+	.vsync_pulse_width	= 2,
+	.vsync_back_porch	= 20,
+	.vsync_front_porch	= 27,
+	.vsync_act_low		= 0,
+	.hsync_act_low		= 0,
+	.den_act_low		= 0,
+};
+
+static struct msm_fb_data swordfish_lcdc_fb_data = {
+	.xres		= 800,
+	.yres		= 480,
+	.width		= 94,
+	.height		= 57,
+	.output_format	= 0,
+};
+
+static struct msm_lcdc_panel_ops swordfish_lcdc_panel_ops = {
+	.init		= swordfish_panel_init,
+	.blank		= swordfish_panel_blank,
+	.unblank	= swordfish_panel_unblank,
+};
+
+static struct msm_lcdc_platform_data swordfish_lcdc_platform_data = {
+	.panel_ops	= &swordfish_lcdc_panel_ops,
+	.timing		= &swordfish_lcdc_timing,
+	.fb_id		= 0,
+	.fb_data	= &swordfish_lcdc_fb_data,
+	.fb_resource = &resources_msm_fb[0],
+};
+
+static struct platform_device swordfish_lcdc_device = {
+	.name	= "msm_mdp_lcdc",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &swordfish_lcdc_platform_data,
+	},
+};
+
+int __init swordfish_init_panel(void)
+{
+	int rc;
+	if (!machine_is_swordfish())
+		return 0;
+
+	if ((rc = platform_device_register(&msm_device_mdp)) != 0)
+		return rc;
+
+	if ((rc = platform_device_register(&swordfish_lcdc_device)) != 0)
+		return rc;
+
+	return 0;
+}
+
+device_initcall(swordfish_init_panel);
diff --git a/arch/arm/mach-msm/board-swordfish.c b/arch/arm/mach-msm/board-swordfish.c
new file mode 100644
index 0000000..70fac49
--- /dev/null
+++ b/arch/arm/mach-msm/board-swordfish.c
@@ -0,0 +1,365 @@
+/* linux/arch/arm/mach-msm/board-swordfish.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/android_pmem.h>
+#include <linux/msm_kgsl.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/setup.h>
+
+#include <mach/board.h>
+#include <mach/irqs.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_hsusb.h>
+#include <mach/msm_ts.h>
+#include <linux/usb/android_composite.h>
+
+#include "board-swordfish.h"
+#include "devices.h"
+#include "proc_comm.h"
+
+extern int swordfish_init_mmc(void);
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start	= 0x70000300,
+		.end	= 0x70000400,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= MSM_GPIO_TO_INT(156),
+		.end	= MSM_GPIO_TO_INT(156),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+static int swordfish_phy_init_seq[] = {
+	0x0C, 0x31,
+	0x1D, 0x0D,
+	0x1D, 0x10,
+	-1
+};
+
+static void swordfish_usb_phy_reset(void)
+{
+	u32 id;
+	int ret;
+
+	id = PCOM_CLKRGM_APPS_RESET_USB_PHY;
+	ret = msm_proc_comm(PCOM_CLK_REGIME_SEC_RESET_ASSERT, &id, NULL);
+	if (ret) {
+		pr_err("%s: Cannot assert (%d)\n", __func__, ret);
+		return;
+	}
+
+	msleep(1);
+
+	id = PCOM_CLKRGM_APPS_RESET_USB_PHY;
+	ret = msm_proc_comm(PCOM_CLK_REGIME_SEC_RESET_DEASSERT, &id, NULL);
+	if (ret) {
+		pr_err("%s: Cannot assert (%d)\n", __func__, ret);
+		return;
+	}
+}
+
+static void swordfish_usb_hw_reset(bool enable)
+{
+	u32 id;
+	int ret;
+	u32 func;
+
+	id = PCOM_CLKRGM_APPS_RESET_USBH;
+	if (enable)
+		func = PCOM_CLK_REGIME_SEC_RESET_ASSERT;
+	else
+		func = PCOM_CLK_REGIME_SEC_RESET_DEASSERT;
+	ret = msm_proc_comm(func, &id, NULL);
+	if (ret)
+		pr_err("%s: Cannot set reset to %d (%d)\n", __func__, enable,
+		       ret);
+}
+
+
+static struct msm_hsusb_platform_data msm_hsusb_pdata = {
+	.phy_init_seq		= swordfish_phy_init_seq,
+	.phy_reset		= swordfish_usb_phy_reset,
+	.hw_reset		= swordfish_usb_hw_reset,
+};
+
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+	.nluns		= 1,
+	.vendor		= "Qualcomm",
+	.product	= "Swordfish",
+	.release	= 0x0100,
+};
+
+static struct platform_device usb_mass_storage_device = {
+	.name	= "usb_mass_storage",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mass_storage_pdata,
+	},
+};
+
+static struct resource msm_kgsl_resources[] = {
+        {
+                .name   = "kgsl_reg_memory",
+                .start  = MSM_GPU_REG_PHYS,
+                .end    = MSM_GPU_REG_PHYS + MSM_GPU_REG_SIZE - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+        {
+                .name   = "kgsl_phys_memory",
+                .start  = MSM_GPU_MEM_BASE,
+                .end    = MSM_GPU_MEM_BASE + MSM_GPU_MEM_SIZE - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+        {
+                .start  = INT_GRAPHICS,
+                .end    = INT_GRAPHICS,
+                .flags  = IORESOURCE_IRQ,
+        },
+};
+
+static struct platform_device msm_kgsl_device = {
+        .name           = "kgsl",
+        .id             = -1,
+        .resource       = msm_kgsl_resources,
+        .num_resources  = ARRAY_SIZE(msm_kgsl_resources),
+};
+
+static struct android_pmem_platform_data mdp_pmem_pdata = {
+        .name           = "pmem",
+        .start          = MSM_PMEM_MDP_BASE,
+        .size           = MSM_PMEM_MDP_SIZE,
+        .no_allocator   = 0,
+        .cached         = 1,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu0_pdata = {
+        .name           = "pmem_gpu0",
+        .start          = MSM_PMEM_GPU0_BASE,
+        .size           = MSM_PMEM_GPU0_SIZE,
+        .no_allocator   = 0,
+        .cached         = 0,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu1_pdata = {
+        .name           = "pmem_gpu1",
+        .start          = MSM_PMEM_GPU1_BASE,
+        .size           = MSM_PMEM_GPU1_SIZE,
+        .no_allocator   = 0,
+        .cached         = 0,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+        .name           = "pmem_adsp",
+        .start          = MSM_PMEM_ADSP_BASE,
+        .size           = MSM_PMEM_ADSP_SIZE,
+        .no_allocator   = 0,
+        .cached         = 0,
+};
+
+static struct platform_device android_pmem_mdp_device = {
+        .name           = "android_pmem",
+        .id             = 0,
+        .dev            = {
+                .platform_data = &mdp_pmem_pdata
+        },
+};
+
+static struct platform_device android_pmem_adsp_device = {
+        .name           = "android_pmem",
+        .id             = 1,
+        .dev            = {
+                .platform_data = &android_pmem_adsp_pdata,
+        },
+};
+
+static struct platform_device android_pmem_gpu0_device = {
+        .name           = "android_pmem",
+        .id             = 2,
+        .dev            = {
+                .platform_data = &android_pmem_gpu0_pdata,
+        },
+};
+
+static struct platform_device android_pmem_gpu1_device = {
+        .name           = "android_pmem",
+        .id             = 3,
+        .dev            = {
+                .platform_data = &android_pmem_gpu1_pdata,
+        },
+};
+
+static char *usb_functions[] = { "usb_mass_storage" };
+static char *usb_functions_adb[] = { "usb_mass_storage", "adb" };
+
+static struct android_usb_product usb_products[] = {
+	{
+		.product_id	= 0x0c01,
+		.num_functions	= ARRAY_SIZE(usb_functions),
+		.functions	= usb_functions,
+	},
+	{
+		.product_id	= 0x0c02,
+		.num_functions	= ARRAY_SIZE(usb_functions_adb),
+		.functions	= usb_functions_adb,
+	},
+};
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.vendor_id		= 0x18d1,
+	.product_id		= 0x0d01,
+	.version		= 0x0100,
+	.serial_number		= "42",
+	.product_name		= "Swordfishdroid",
+	.manufacturer_name	= "Qualcomm",
+	.num_products = ARRAY_SIZE(usb_products),
+	.products = usb_products,
+	.num_functions = ARRAY_SIZE(usb_functions_adb),
+	.functions = usb_functions_adb,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+static struct platform_device fish_battery_device = {
+	.name = "fish_battery",
+};
+
+static struct msm_ts_platform_data swordfish_ts_pdata = {
+	.min_x		= 296,
+	.max_x		= 3800,
+	.min_y		= 296,
+	.max_y		= 3800,
+	.min_press	= 0,
+	.max_press	= 256,
+	.inv_x		= 4096,
+	.inv_y		= 4096,
+};
+
+static struct platform_device *devices[] __initdata = {
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER)
+	&msm_device_uart3,
+#endif
+	&msm_device_smd,
+	&msm_device_nand,
+	&msm_device_hsusb,
+	&usb_mass_storage_device,
+	&android_usb_device,
+	&fish_battery_device,
+	&smc91x_device,
+	&msm_device_touchscreen,
+	&android_pmem_mdp_device,
+	&android_pmem_adsp_device,
+	&android_pmem_gpu0_device,
+	&android_pmem_gpu1_device,
+	&msm_kgsl_device,
+};
+
+extern struct sys_timer msm_timer;
+
+static struct msm_acpu_clock_platform_data swordfish_clock_data = {
+	.acpu_switch_time_us	= 20,
+	.max_speed_delta_khz	= 256000,
+	.vdd_switch_time_us	= 62,
+	.power_collapse_khz	= 128000000,
+	.wait_for_irq_khz	= 128000000,
+};
+
+void msm_serial_debug_init(unsigned int base, int irq,
+			   struct device *clk_device, int signal_irq);
+
+static void __init swordfish_init(void)
+{
+	int rc;
+
+	msm_acpu_clock_init(&swordfish_clock_data);
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+	msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3,
+			      &msm_device_uart3.dev, 1);
+#endif
+	msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata;
+	msm_device_touchscreen.dev.platform_data = &swordfish_ts_pdata;
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+	msm_hsusb_set_vbus_state(1);
+	rc = swordfish_init_mmc();
+	if (rc)
+		pr_crit("%s: MMC init failure (%d)\n", __func__, rc);
+}
+
+static void __init swordfish_fixup(struct machine_desc *desc, struct tag *tags,
+				 char **cmdline, struct meminfo *mi)
+{
+	mi->nr_banks = 1;
+	mi->bank[0].start = PHYS_OFFSET;
+	mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
+	mi->bank[0].size = (101*1024*1024);
+}
+
+static void __init swordfish_map_io(void)
+{
+	msm_map_qsd8x50_io();
+	msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50);
+}
+
+MACHINE_START(SWORDFISH, "Swordfish Board (QCT SURF8250)")
+#ifdef CONFIG_MSM_DEBUG_UART
+	.phys_io        = MSM_DEBUG_UART_PHYS,
+	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+	.boot_params	= 0x20000100,
+	.fixup		= swordfish_fixup,
+	.map_io		= swordfish_map_io,
+	.init_irq	= msm_init_irq,
+	.init_machine	= swordfish_init,
+	.timer		= &msm_timer,
+MACHINE_END
+
+MACHINE_START(QSD8X50_FFA, "qsd8x50 FFA Board (QCT FFA8250)")
+#ifdef CONFIG_MSM_DEBUG_UART
+	.phys_io	= MSM_DEBUG_UART_PHYS,
+	.io_pg_offst	= ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+	.boot_params	= 0x20000100,
+	.fixup		= swordfish_fixup,
+	.map_io		= swordfish_map_io,
+	.init_irq	= msm_init_irq,
+	.init_machine	= swordfish_init,
+	.timer		= &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-swordfish.h b/arch/arm/mach-msm/board-swordfish.h
new file mode 100644
index 0000000..b9ea54f
--- /dev/null
+++ b/arch/arm/mach-msm/board-swordfish.h
@@ -0,0 +1,48 @@
+/* arch/arm/mach-msm/board-swordfish.h
+ *
+ * Copyright (C) 2009 Google Inc.
+ * Author: Dima Zavin <dima@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_SWORDFISH_H
+#define __ARCH_ARM_MACH_MSM_BOARD_SWORDFISH_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE		0x02B00000
+#define MSM_SMI_SIZE		0x01500000
+
+#define MSM_PMEM_MDP_BASE	0x03000000
+#define MSM_PMEM_MDP_SIZE	0x01000000
+
+#define MSM_EBI1_BASE		0x20000000
+#define MSM_EBI1_SIZE		0x0E000000
+
+#define MSM_PMEM_ADSP_BASE      0x2A300000
+#define MSM_PMEM_ADSP_SIZE      0x02000000
+
+#define MSM_PMEM_GPU1_BASE	0x2C300000
+#define MSM_PMEM_GPU1_SIZE	0x01400000
+
+#define MSM_PMEM_GPU0_BASE	0x2D700000
+#define MSM_PMEM_GPU0_SIZE	0x00400000
+
+#define MSM_GPU_MEM_BASE	0x2DB00000
+#define MSM_GPU_MEM_SIZE	0x00200000
+
+#define MSM_RAM_CONSOLE_BASE	0x2DD00000
+#define MSM_RAM_CONSOLE_SIZE	0x00040000
+
+#define MSM_FB_BASE		0x2DE00000
+#define MSM_FB_SIZE		0x00200000
+
+#endif /* __ARCH_ARM_MACH_MSM_BOARD_SWORDFISH_H */
diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c
new file mode 100644
index 0000000..527379e
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-gpio.c
@@ -0,0 +1,305 @@
+/* arch/arm/mach-msm/board-trout-gpio.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/sysdev.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+
+#include <mach/htc_pwrsink.h>
+
+#include "board-trout.h"
+#include "gpio_chip.h"
+
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_trout."
+
+static uint cpld_usb_h2w_sw;
+module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0);
+
+static uint8_t trout_cpld_shadow[4] = {
+#if defined(CONFIG_MSM_DEBUG_UART1)
+	/* H2W pins <-> UART1 */
+        [0] = 0x40, // for serial debug, low current
+#else
+	/* H2W pins <-> UART3, Bluetooth <-> UART1 */
+        [0] = 0x80, // for serial debug, low current
+#endif
+        [1] = 0x04, // I2C_PULL
+        [3] = 0x04, // mmdi 32k en
+};
+static uint8_t trout_int_mask[2] = {
+        [0] = 0xff, /* mask all interrupts */
+        [1] = 0xff,
+};
+static uint8_t trout_sleep_int_mask[] = {
+        [0] = 0xff,
+        [1] = 0xff,
+};
+static int trout_suspended;
+
+static int trout_gpio_read(struct gpio_chip *chip, unsigned n)
+{
+	uint8_t b;
+	int reg;
+	if (n >= TROUT_GPIO_VIRTUAL_BASE)
+		n += TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET;
+	b = 1U << (n & 7);
+	reg = (n & 0x78) >> 2; // assumes base is 128
+	return !!(readb(TROUT_CPLD_BASE + reg) & b);
+}
+
+static void update_pwrsink(unsigned gpio, unsigned on)
+{
+	switch(gpio) {
+	case TROUT_GPIO_UI_LED_EN:
+		htc_pwrsink_set(PWRSINK_LED_BUTTON, on ? 100 : 0);
+		break;
+	case TROUT_GPIO_QTKEY_LED_EN:
+		htc_pwrsink_set(PWRSINK_LED_KEYBOARD, on ? 100 : 0);
+		break;
+	}
+}
+
+static uint8_t trout_gpio_write_shadow(unsigned n, unsigned on)
+{
+	uint8_t b = 1U << (n & 7);
+	int reg = (n & 0x78) >> 2; // assumes base is 128
+
+	if(on)
+		return trout_cpld_shadow[reg >> 1] |= b;
+	else
+		return trout_cpld_shadow[reg >> 1] &= ~b;
+}
+
+static int trout_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
+{
+	int reg = (n & 0x78) >> 2; // assumes base is 128
+	unsigned long flags;
+	uint8_t reg_val;
+
+	if ((reg >> 1) >= ARRAY_SIZE(trout_cpld_shadow)) {
+		printk(KERN_ERR "trout_gpio_write called on input %d\n", n);
+		return -ENOTSUPP;
+	}
+
+	local_irq_save(flags);
+	update_pwrsink(n, on);
+	reg_val = trout_gpio_write_shadow(n, on);
+	writeb(reg_val, TROUT_CPLD_BASE + reg);
+	local_irq_restore(flags);
+	return 0;
+}
+
+static int trout_gpio_configure(struct gpio_chip *chip, unsigned int gpio, unsigned long flags)
+{
+	if(flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH))
+		trout_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH);
+	return 0;
+}
+
+static int trout_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp)
+{
+	if ((gpio < TROUT_GPIO_BANK0_FIRST_INT_SOURCE ||
+	     gpio > TROUT_GPIO_BANK0_LAST_INT_SOURCE) &&
+	    (gpio < TROUT_GPIO_BANK1_FIRST_INT_SOURCE ||
+	     gpio > TROUT_GPIO_BANK1_LAST_INT_SOURCE))
+		return -ENOENT;
+	*irqp = TROUT_GPIO_TO_INT(gpio);
+	if(irqnumflagsp)
+		*irqnumflagsp = 0;
+	return 0;
+}
+
+static void trout_gpio_irq_ack(unsigned int irq)
+{
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_STAT_REG(bank);
+	/*printk(KERN_INFO "trout_gpio_irq_ack irq %d\n", irq);*/
+	writeb(mask, TROUT_CPLD_BASE + reg);
+}
+
+static void trout_gpio_irq_mask(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_MASK_REG(bank);
+
+	local_irq_save(flags);
+	reg_val = trout_int_mask[bank] |= mask;
+	/*printk(KERN_INFO "trout_gpio_irq_mask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	if (!trout_suspended)
+		writeb(reg_val, TROUT_CPLD_BASE + reg);
+	local_irq_restore(flags);
+}
+
+static void trout_gpio_irq_unmask(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_MASK_REG(bank);
+
+	local_irq_save(flags);
+	reg_val = trout_int_mask[bank] &= ~mask;
+	/*printk(KERN_INFO "trout_gpio_irq_unmask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	if (!trout_suspended)
+		writeb(reg_val, TROUT_CPLD_BASE + reg);
+	local_irq_restore(flags);
+}
+
+int trout_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	unsigned long flags;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+
+	local_irq_save(flags);
+	if(on)
+		trout_sleep_int_mask[bank] &= ~mask;
+	else
+		trout_sleep_int_mask[bank] |= mask;
+	local_irq_restore(flags);
+	return 0;
+}
+
+static void trout_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int j, m;
+	unsigned v;
+	int bank;
+	int stat_reg;
+	int int_base = TROUT_INT_START;
+	uint8_t int_mask;
+
+	for (bank = 0; bank < 2; bank++) {
+		stat_reg = TROUT_BANK_TO_STAT_REG(bank);
+		v = readb(TROUT_CPLD_BASE + stat_reg);
+		int_mask = trout_int_mask[bank];
+		if (v & int_mask) {
+			writeb(v & int_mask, TROUT_CPLD_BASE + stat_reg);
+			printk(KERN_ERR "trout_gpio_irq_handler: got masked "
+			       "interrupt: %d:%02x\n", bank, v & int_mask);
+		}
+		v &= ~int_mask;
+		while (v) {
+			m = v & -v;
+			j = fls(m) - 1;
+			/*printk(KERN_INFO "msm_gpio_irq_handler %d:%02x %02x b"
+			       "it %d irq %d\n", bank, v, m, j, int_base + j);*/
+			v &= ~m;
+			generic_handle_irq(int_base + j);
+		}
+		int_base += TROUT_INT_BANK0_COUNT;
+	}
+	desc->chip->ack(irq);
+}
+
+static int trout_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+{
+	trout_suspended = 1;
+	writeb(trout_sleep_int_mask[0],
+	       TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK0_REG);
+	writeb(trout_sleep_int_mask[1],
+	       TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK1_REG);
+	writeb(trout_sleep_int_mask[0],
+	       TROUT_CPLD_BASE + TROUT_GPIO_INT_STAT0_REG);
+	writeb(trout_sleep_int_mask[1],
+	       TROUT_CPLD_BASE + TROUT_GPIO_INT_STAT1_REG);
+	return 0;
+}
+
+int trout_sysdev_resume(struct sys_device *dev)
+{
+	writeb(trout_int_mask[0], TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK0_REG);
+	writeb(trout_int_mask[1], TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK1_REG);
+	trout_suspended = 0;
+	return 0;
+}
+
+static struct irq_chip trout_gpio_irq_chip = {
+	.name      = "troutgpio",
+	.ack       = trout_gpio_irq_ack,
+	.mask      = trout_gpio_irq_mask,
+	.unmask    = trout_gpio_irq_unmask,
+	.set_wake  = trout_gpio_irq_set_wake,
+	//.set_type  = trout_gpio_irq_set_type,
+};
+
+static struct gpio_chip trout_gpio_chip = {
+	.start = TROUT_GPIO_START,
+	.end = TROUT_GPIO_END,
+	.configure = trout_gpio_configure,
+	.get_irq_num = trout_gpio_get_irq_num,
+	.read = trout_gpio_read,
+	.write = trout_gpio_write,
+//	.read_detect_status = trout_gpio_read_detect_status,
+//	.clear_detect_status = trout_gpio_clear_detect_status
+};
+
+struct sysdev_class trout_sysdev_class = {
+	.name = "troutgpio_irq",
+	.suspend = trout_sysdev_suspend,
+	.resume = trout_sysdev_resume,
+};
+
+static struct sys_device trout_irq_device = {
+	.cls    = &trout_sysdev_class,
+};
+
+static int __init trout_init_gpio(void)
+{
+	int i;
+
+	if (!machine_is_trout())
+		return 0;
+
+	/* adjust GPIOs based on bootloader request */
+	pr_info("trout_init_gpio: cpld_usb_hw2_sw = %d\n", cpld_usb_h2w_sw);
+	trout_gpio_write_shadow(TROUT_GPIO_USB_H2W_SW, cpld_usb_h2w_sw);
+
+	for(i = 0; i < ARRAY_SIZE(trout_cpld_shadow); i++)
+		writeb(trout_cpld_shadow[i], TROUT_CPLD_BASE + i * 2);
+
+	for(i = TROUT_INT_START; i <= TROUT_INT_END; i++) {
+		set_irq_chip(i, &trout_gpio_irq_chip);
+		set_irq_handler(i, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	register_gpio_chip(&trout_gpio_chip);
+
+	set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);
+	set_irq_chained_handler(MSM_GPIO_TO_INT(17), trout_gpio_irq_handler);
+	set_irq_wake(MSM_GPIO_TO_INT(17), 1);
+
+	if(sysdev_class_register(&trout_sysdev_class) == 0)
+		sysdev_register(&trout_irq_device);
+
+	return 0;
+}
+
+postcore_initcall(trout_init_gpio);
diff --git a/arch/arm/mach-msm/board-trout-keypad.c b/arch/arm/mach-msm/board-trout-keypad.c
new file mode 100644
index 0000000..0299d06
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-keypad.c
@@ -0,0 +1,345 @@
+/* arch/arm/mach-msm/board-trout-keypad.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/gpio_event.h>
+#include <asm/mach-types.h>
+
+#include "board-trout.h"
+
+static char *keycaps = "--qwerty";
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_trout."
+module_param_named(keycaps, keycaps, charp, 0);
+
+
+static unsigned int trout_col_gpios[] = { 35, 34, 33, 32, 31, 23, 30, 78 };
+static unsigned int trout_row_gpios[] = { 42, 41, 40, 39, 38, 37, 36 };
+
+#define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(trout_row_gpios) + (row))
+
+static const unsigned short trout_keymap[ARRAY_SIZE(trout_col_gpios) * ARRAY_SIZE(trout_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_BACK,
+	[KEYMAP_INDEX(0, 1)] = KEY_HOME,
+//	[KEYMAP_INDEX(0, 2)] = KEY_,
+	[KEYMAP_INDEX(0, 3)] = KEY_BACKSPACE,
+	[KEYMAP_INDEX(0, 4)] = KEY_ENTER,
+	[KEYMAP_INDEX(0, 5)] = KEY_RIGHTALT,
+	[KEYMAP_INDEX(0, 6)] = KEY_P,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_MENU,
+//	[KEYMAP_INDEX(1, 0)] = 229, // SOFT1
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+	[KEYMAP_INDEX(1, 2)] = KEY_END,
+	[KEYMAP_INDEX(1, 3)] = KEY_LEFTALT,
+	[KEYMAP_INDEX(1, 4)] = KEY_A,
+	[KEYMAP_INDEX(1, 5)] = KEY_LEFTSHIFT,
+	[KEYMAP_INDEX(1, 6)] = KEY_Q,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_U,
+	[KEYMAP_INDEX(2, 1)] = KEY_7,
+	[KEYMAP_INDEX(2, 2)] = KEY_K,
+	[KEYMAP_INDEX(2, 3)] = KEY_J,
+	[KEYMAP_INDEX(2, 4)] = KEY_M,
+	[KEYMAP_INDEX(2, 5)] = KEY_SLASH,
+	[KEYMAP_INDEX(2, 6)] = KEY_8,
+
+	[KEYMAP_INDEX(3, 0)] = KEY_5,
+	[KEYMAP_INDEX(3, 1)] = KEY_6,
+	[KEYMAP_INDEX(3, 2)] = KEY_B,
+	[KEYMAP_INDEX(3, 3)] = KEY_H,
+	[KEYMAP_INDEX(3, 4)] = KEY_N,
+	[KEYMAP_INDEX(3, 5)] = KEY_SPACE,
+	[KEYMAP_INDEX(3, 6)] = KEY_Y,
+
+	[KEYMAP_INDEX(4, 0)] = KEY_4,
+	[KEYMAP_INDEX(4, 1)] = KEY_R,
+	[KEYMAP_INDEX(4, 2)] = KEY_V,
+	[KEYMAP_INDEX(4, 3)] = KEY_G,
+	[KEYMAP_INDEX(4, 4)] = KEY_C,
+	//[KEYMAP_INDEX(4, 5)] = KEY_,
+	[KEYMAP_INDEX(4, 6)] = KEY_T,
+