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,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_2,
+	[KEYMAP_INDEX(5, 1)] = KEY_W,
+	[KEYMAP_INDEX(5, 2)] = KEY_COMPOSE,
+	[KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(5, 4)] = KEY_S,
+	[KEYMAP_INDEX(5, 5)] = KEY_Z,
+	[KEYMAP_INDEX(5, 6)] = KEY_1,
+
+	[KEYMAP_INDEX(6, 0)] = KEY_I,
+	[KEYMAP_INDEX(6, 1)] = KEY_0,
+	[KEYMAP_INDEX(6, 2)] = KEY_O,
+	[KEYMAP_INDEX(6, 3)] = KEY_L,
+	[KEYMAP_INDEX(6, 4)] = KEY_DOT,
+	[KEYMAP_INDEX(6, 5)] = KEY_COMMA,
+	[KEYMAP_INDEX(6, 6)] = KEY_9,
+
+	[KEYMAP_INDEX(7, 0)] = KEY_3,
+	[KEYMAP_INDEX(7, 1)] = KEY_E,
+	[KEYMAP_INDEX(7, 2)] = KEY_EMAIL, // @
+	[KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(7, 4)] = KEY_X,
+	[KEYMAP_INDEX(7, 5)] = KEY_F,
+	[KEYMAP_INDEX(7, 6)] = KEY_D
+};
+
+static unsigned int trout_col_gpios_evt2[] = { 35, 34, 33, 32, 31, 23, 30, 109 };
+static unsigned int trout_row_gpios_evt2[] = { 42, 41, 40, 39, 38, 37, 36 };
+
+static const unsigned short trout_keymap_evt2_1[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_RIGHTSHIFT,
+	[KEYMAP_INDEX(0, 6)] = KEY_P,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_MENU,
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+//	[KEYMAP_INDEX(1, 2)] = KEY_,
+	[KEYMAP_INDEX(1, 3)] = KEY_LEFTSHIFT,
+	[KEYMAP_INDEX(1, 4)] = KEY_A,
+	[KEYMAP_INDEX(1, 5)] = KEY_COMPOSE,
+	[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,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_2,
+	[KEYMAP_INDEX(5, 1)] = KEY_W,
+	[KEYMAP_INDEX(5, 2)] = KEY_LEFTALT,
+	[KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(5, 4)] = KEY_S,
+	[KEYMAP_INDEX(5, 5)] = KEY_Z,
+	[KEYMAP_INDEX(5, 6)] = KEY_1,
+
+	[KEYMAP_INDEX(6, 0)] = KEY_I,
+	[KEYMAP_INDEX(6, 1)] = KEY_0,
+	[KEYMAP_INDEX(6, 2)] = KEY_O,
+	[KEYMAP_INDEX(6, 3)] = KEY_L,
+	[KEYMAP_INDEX(6, 4)] = KEY_COMMA,
+	[KEYMAP_INDEX(6, 5)] = KEY_DOT,
+	[KEYMAP_INDEX(6, 6)] = KEY_9,
+
+	[KEYMAP_INDEX(7, 0)] = KEY_3,
+	[KEYMAP_INDEX(7, 1)] = KEY_E,
+	[KEYMAP_INDEX(7, 2)] = KEY_EMAIL, // @
+	[KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(7, 4)] = KEY_X,
+	[KEYMAP_INDEX(7, 5)] = KEY_F,
+	[KEYMAP_INDEX(7, 6)] = KEY_D
+};
+
+static const unsigned short trout_keymap_evt2_2[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_RIGHTSHIFT,
+	[KEYMAP_INDEX(0, 6)] = KEY_P,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_MENU, /* external menu key */
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+//	[KEYMAP_INDEX(1, 2)] = KEY_,
+	[KEYMAP_INDEX(1, 3)] = KEY_LEFTSHIFT,
+	[KEYMAP_INDEX(1, 4)] = KEY_A,
+	[KEYMAP_INDEX(1, 5)] = KEY_F1, /* qwerty menu key */
+	[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_DOT,
+	[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_EMAIL, // @
+	[KEYMAP_INDEX(4, 6)] = KEY_T,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_2,
+	[KEYMAP_INDEX(5, 1)] = KEY_W,
+	[KEYMAP_INDEX(5, 2)] = KEY_LEFTALT,
+	[KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(5, 4)] = KEY_S,
+	[KEYMAP_INDEX(5, 5)] = KEY_Z,
+	[KEYMAP_INDEX(5, 6)] = KEY_1,
+
+	[KEYMAP_INDEX(6, 0)] = KEY_I,
+	[KEYMAP_INDEX(6, 1)] = KEY_0,
+	[KEYMAP_INDEX(6, 2)] = KEY_O,
+	[KEYMAP_INDEX(6, 3)] = KEY_L,
+	[KEYMAP_INDEX(6, 4)] = KEY_COMMA,
+	[KEYMAP_INDEX(6, 5)] = KEY_RIGHTALT,
+	[KEYMAP_INDEX(6, 6)] = KEY_9,
+
+	[KEYMAP_INDEX(7, 0)] = KEY_3,
+	[KEYMAP_INDEX(7, 1)] = KEY_E,
+	[KEYMAP_INDEX(7, 2)] = KEY_COMPOSE,
+	[KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(7, 4)] = KEY_X,
+	[KEYMAP_INDEX(7, 5)] = KEY_F,
+	[KEYMAP_INDEX(7, 6)] = KEY_D
+};
+
+static struct gpio_event_matrix_info trout_keypad_matrix_info = {
+	.info.func = gpio_event_matrix_func,
+	.keymap = trout_keymap,
+	.output_gpios = trout_col_gpios,
+	.input_gpios = trout_row_gpios,
+	.noutputs = ARRAY_SIZE(trout_col_gpios),
+	.ninputs = ARRAY_SIZE(trout_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 /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+static struct gpio_event_direct_entry trout_keypad_nav_map[] = {
+	{ TROUT_POWER_KEY,              KEY_POWER    },
+	{ TROUT_GPIO_CAM_BTN_STEP1_N,   KEY_CAMERA-1 }, //steal KEY_HP
+	{ TROUT_GPIO_CAM_BTN_STEP2_N,   KEY_CAMERA   },
+};
+
+static struct gpio_event_direct_entry trout_keypad_nav_map_evt2[] = {
+	{ TROUT_POWER_KEY,              KEY_END      },
+	{ TROUT_GPIO_CAM_BTN_STEP1_N,   KEY_CAMERA-1 }, //steal KEY_HP
+	{ TROUT_GPIO_CAM_BTN_STEP2_N,   KEY_CAMERA   },
+};
+
+static struct gpio_event_input_info trout_keypad_nav_info = {
+	.info.func = gpio_event_input_func,
+	.flags = 0,
+	.type = EV_KEY,
+	.keymap = trout_keypad_nav_map,
+	.keymap_size = ARRAY_SIZE(trout_keypad_nav_map)
+};
+
+static struct gpio_event_direct_entry trout_keypad_switch_map[] = {
+	{ TROUT_GPIO_SLIDING_DET,       SW_LID       }
+};
+
+static struct gpio_event_input_info trout_keypad_switch_info = {
+	.info.func = gpio_event_input_func,
+	.flags = 0,
+	.type = EV_SW,
+	.keymap = trout_keypad_switch_map,
+	.keymap_size = ARRAY_SIZE(trout_keypad_switch_map)
+};
+
+static struct gpio_event_info *trout_keypad_info[] = {
+	&trout_keypad_matrix_info.info,
+	&trout_keypad_nav_info.info,
+	&trout_keypad_switch_info.info,
+};
+
+static struct gpio_event_platform_data trout_keypad_data = {
+	.name = "trout-keypad",
+	.info = trout_keypad_info,
+	.info_count = ARRAY_SIZE(trout_keypad_info)
+};
+
+static struct platform_device trout_keypad_device = {
+	.name = GPIO_EVENT_DEV_NAME,
+	.id = 0,
+	.dev		= {
+		.platform_data	= &trout_keypad_data,
+	},
+};
+
+static int __init trout_init_keypad(void)
+{
+	if (!machine_is_trout())
+		return 0;
+
+	switch (system_rev) {
+	case 0:
+		/* legacy default keylayout */
+		break;
+	case 1:
+		/* v1 has a new keyboard layout */
+		trout_keypad_matrix_info.keymap = trout_keymap_evt2_1;
+		trout_keypad_matrix_info.output_gpios = trout_col_gpios_evt2;
+		trout_keypad_matrix_info.input_gpios = trout_row_gpios_evt2;
+		
+		/* v1 has new direct keys */
+		trout_keypad_nav_info.keymap = trout_keypad_nav_map_evt2;
+		trout_keypad_nav_info.keymap_size = ARRAY_SIZE(trout_keypad_nav_map_evt2);
+
+		/* userspace needs to know about these changes as well */
+		trout_keypad_data.name = "trout-keypad-v2";
+		break;
+	default: /* 2, 3, 4 currently */
+		/* v2 has a new keyboard layout */
+		trout_keypad_matrix_info.keymap = trout_keymap_evt2_2;
+		trout_keypad_matrix_info.output_gpios = trout_col_gpios_evt2;
+		trout_keypad_matrix_info.input_gpios = trout_row_gpios_evt2;
+		
+		/* v2 has new direct keys */
+		trout_keypad_nav_info.keymap = trout_keypad_nav_map_evt2;
+		trout_keypad_nav_info.keymap_size = ARRAY_SIZE(trout_keypad_nav_map_evt2);
+
+		/* userspace needs to know about these changes as well */
+		if (!strcmp(keycaps, "qwertz")) {
+			trout_keypad_data.name = "trout-keypad-qwertz";
+		} else {
+			trout_keypad_data.name = "trout-keypad-v3";
+		}
+		break;
+	}
+	return platform_device_register(&trout_keypad_device);
+}
+
+device_initcall(trout_init_keypad);
+
diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c
new file mode 100644
index 0000000..13755f5
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-mmc.c
@@ -0,0 +1,438 @@
+/* linux/arch/arm/mach-msm/board-trout-mmc.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/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#include <mach/vreg.h>
+#include <mach/htc_pwrsink.h>
+
+#include <asm/mach/mmc.h>
+
+#include "devices.h"
+
+#include "board-trout.h"
+
+#include "proc_comm.h"
+
+#define DEBUG_SDSLOT_VDD 1
+
+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 trout_disablesdcard_setup(char *str)
+{
+	int cal = simple_strtol(str, NULL, 0);
+	
+	opt_disable_sdcard = cal;
+	return 1;
+}
+
+__setup("board_trout.disable_sdcard=", trout_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 trout_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("%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("%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 trout_sdslot_status(struct device *dev)
+{
+	unsigned int status;
+
+	status = (unsigned int) gpio_get_value(TROUT_GPIO_SDMC_CD_N);
+	return (!status);
+}
+
+#define TROUT_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 trout_sdslot_data = {
+	.ocr_mask	= TROUT_MMC_VDD,
+	.status		= trout_sdslot_status,
+	.translate_vdd	= trout_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 trout_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 trout_wifi_emb_data = {
+	.cis	= {
+		.vendor		= 0x104c,
+		.device		= 0x9066,
+		.blksize	= 512,
+		/*.max_dtr	= 24000000,  Max of chip - no worky on Trout */
+		.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 trout_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 trout_wifi_status(struct device *dev)
+{
+	return trout_wifi_cd;
+}
+
+int trout_wifi_set_carddetect(int val)
+{
+	printk("%s: %d\n", __func__, val);
+	trout_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(trout_wifi_set_carddetect);
+#endif
+
+static int trout_wifi_power_state;
+
+int trout_wifi_power(int on)
+{
+	int rc;
+
+	printk("%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( TROUT_GPIO_MAC_32K_EN, on);
+	mdelay(100);
+	gpio_set_value( TROUT_GPIO_WIFI_EN, on);
+	mdelay(100);
+	if (!on) {
+		vreg_disable(vreg_wifi_osc);
+	}
+	trout_wifi_power_state = on;
+	return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(trout_wifi_power);
+#endif
+
+static int trout_wifi_reset_state;
+int trout_wifi_reset(int on)
+{
+	printk("%s: %d\n", __func__, on);
+	gpio_set_value( TROUT_GPIO_WIFI_PA_RESETX, !on );
+	trout_wifi_reset_state = on;
+	mdelay(50);
+	return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(trout_wifi_reset);
+#endif
+
+static struct mmc_platform_data trout_wifi_data = {
+	.ocr_mask		= MMC_VDD_28_29,
+	.status			= trout_wifi_status,
+	.register_status_notify	= trout_wifi_status_register,
+	.embedded_sdio		= &trout_wifi_emb_data,
+};
+
+int __init trout_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(TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 1);
+
+	msm_add_sdcc(1, &trout_wifi_data, 0, 0);
+
+	if (!opt_disable_sdcard)
+		msm_add_sdcc(2, &trout_sdslot_data,
+			     TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 0);
+	else
+		printk(KERN_INFO "trout: SD-Card interface disabled\n");
+	return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int troutmmc_dbg_wifi_reset_set(void *data, u64 val)
+{
+	trout_wifi_reset((int) val);
+	return 0;
+}
+
+static int troutmmc_dbg_wifi_reset_get(void *data, u64 *val)
+{
+	*val = trout_wifi_reset_state;
+	return 0;
+}
+
+static int troutmmc_dbg_wifi_cd_set(void *data, u64 val)
+{
+	trout_wifi_set_carddetect((int) val);
+	return 0;
+}
+
+static int troutmmc_dbg_wifi_cd_get(void *data, u64 *val)
+{
+	*val = trout_wifi_cd;
+	return 0;
+}
+
+static int troutmmc_dbg_wifi_pwr_set(void *data, u64 val)
+{
+	trout_wifi_power((int) val);
+	return 0;
+}
+
+static int troutmmc_dbg_wifi_pwr_get(void *data, u64 *val)
+{
+	
+	*val = trout_wifi_power_state;
+	return 0;
+}
+
+static int troutmmc_dbg_sd_pwr_set(void *data, u64 val)
+{
+	trout_sdslot_switchvdd(NULL, (unsigned int) val);
+	return 0;
+}
+
+static int troutmmc_dbg_sd_pwr_get(void *data, u64 *val)
+{
+	*val = sdslot_vdd;
+	return 0;
+}
+
+static int troutmmc_dbg_sd_cd_set(void *data, u64 val)
+{
+	return -ENOSYS;
+}
+
+static int troutmmc_dbg_sd_cd_get(void *data, u64 *val)
+{
+	*val = trout_sdslot_status(NULL);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_wifi_reset_fops,
+			troutmmc_dbg_wifi_reset_get,
+			troutmmc_dbg_wifi_reset_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_wifi_cd_fops,
+			troutmmc_dbg_wifi_cd_get,
+			troutmmc_dbg_wifi_cd_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_wifi_pwr_fops,
+			troutmmc_dbg_wifi_pwr_get,
+			troutmmc_dbg_wifi_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_sd_pwr_fops,
+			troutmmc_dbg_sd_pwr_get,
+			troutmmc_dbg_sd_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_sd_cd_fops,
+			troutmmc_dbg_sd_cd_get,
+			troutmmc_dbg_sd_cd_set, "%llu\n");
+
+static int __init troutmmc_dbg_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("troutmmc_dbg", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("wifi_reset", 0644, dent, NULL,
+			    &troutmmc_dbg_wifi_reset_fops);
+	debugfs_create_file("wifi_cd", 0644, dent, NULL,
+			    &troutmmc_dbg_wifi_cd_fops);
+	debugfs_create_file("wifi_pwr", 0644, dent, NULL,
+			    &troutmmc_dbg_wifi_pwr_fops);
+
+	debugfs_create_file("sd_pwr", 0644, dent, NULL,
+			    &troutmmc_dbg_sd_pwr_fops);
+	debugfs_create_file("sd_cd", 0644, dent, NULL,
+			    &troutmmc_dbg_sd_cd_fops);
+
+	return 0;
+}
+
+device_initcall(troutmmc_dbg_init);
+
+#endif
diff --git a/arch/arm/mach-msm/board-trout-panel.c b/arch/arm/mach-msm/board-trout-panel.c
new file mode 100644
index 0000000..7e978b8
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-panel.c
@@ -0,0 +1,650 @@
+/* linux/arch/arm/mach-msm/board-trout-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 <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+#include <mach/vreg.h>
+#include <mach/htc_pwrsink.h>
+
+#include "board-trout.h"
+#include "proc_comm.h"
+#include "devices.h"
+
+#define TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS 255
+#define VSYNC_GPIO 97
+
+static struct clk *gp_clk;
+static int trout_backlight_off;
+static int trout_backlight_brightness = TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS;
+static int trout_new_backlight = 1;
+static uint8_t trout_backlight_last_level = 33;
+static DEFINE_MUTEX(trout_backlight_lock);
+
+static void trout_set_backlight_level(uint8_t level)
+{
+	unsigned percent = ((int)level * 100) / 255;
+
+	if (trout_new_backlight) {
+		unsigned long flags;
+		int i = 0;
+		level = (int)level * 34 / 256;
+
+		if (trout_backlight_last_level == level)
+			return;
+
+		if (level == 0) {
+			gpio_set_value(27, 0);
+			msleep(2);
+		} else {
+			local_irq_save(flags);
+			if (trout_backlight_last_level == 0) {
+				gpio_set_value(27, 1);
+				udelay(40);
+				trout_backlight_last_level = 33;
+			}
+			i = (trout_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);
+		}
+		trout_backlight_last_level = level;
+	}
+	else {
+		if(level) {
+			clk_enable(gp_clk);
+			writel((1U << 16) | (~level & 0xffff),
+			       MSM_CLK_CTL_BASE + 0x58);
+			/* Going directly to a 100% duty cycle does not
+			 *  seem to work */
+			if(level == 255) {
+				writel((~127 << 16) | 0xb20,
+				       MSM_CLK_CTL_BASE + 0x5c);
+				udelay(1);
+			}
+			writel((~127 << 16) | 0xb58, MSM_CLK_CTL_BASE + 0x5c);
+		}
+		else {
+			writel(0x0, MSM_CLK_CTL_BASE + 0x5c);
+			clk_disable(gp_clk);
+		}
+	}
+	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 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 trout_process_mddi_table(struct msm_mddi_client_data *client_data,
+				     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_mddi_1v5;
+static struct vreg *vreg_lcm_2v85;
+
+static void trout_mddi_power_client(struct msm_mddi_client_data *client_data,
+				    int on)
+{
+    unsigned id, on_off;
+	if(on) {
+		on_off = 0;
+		id = PM_VREG_PDOWN_MDDI_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+		vreg_enable(vreg_mddi_1v5);
+		mdelay(5); // delay time >5ms and <10ms
+		gpio_set_value(V_VDDE2E_VDD2_GPIO, 1);
+		gpio_set_value(TROUT_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);
+		gpio_set_value(MDDI_RST_N, 1);
+		msleep(10);
+	} else {
+		gpio_set_value(TROUT_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);
+		gpio_set_value(V_VDDE2E_VDD2_GPIO, 0);
+		msleep(200);
+		vreg_disable(vreg_mddi_1v5);
+		id = PM_VREG_PDOWN_MDDI_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+	}
+}
+
+static int trout_mddi_toshiba_client_init(
+	struct msm_mddi_bridge_platform_data *bridge_data,
+	struct msm_mddi_client_data *client_data)
+{
+	int panel_id;
+
+	client_data->auto_hibernate(client_data, 0);
+	trout_process_mddi_table(client_data, mddi_toshiba_init_table,
+				 ARRAY_SIZE(mddi_toshiba_init_table));
+	client_data->auto_hibernate(client_data, 1);
+	panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
+	if (panel_id > 1) {
+		printk("unknown panel id at mddi_enable\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int trout_mddi_toshiba_client_uninit(
+	struct msm_mddi_bridge_platform_data *bridge_data,
+	struct msm_mddi_client_data *client_data)
+{
+	return 0;
+}
+
+static int trout_mddi_panel_unblank(
+	struct msm_mddi_bridge_platform_data *bridge_data,
+	struct msm_mddi_client_data *client_data)
+{
+
+	int panel_id, ret = 0;
+	
+	trout_set_backlight_level(0);
+	client_data->auto_hibernate(client_data, 0);
+	trout_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:
+		printk("init sharp panel\n");
+		trout_process_mddi_table(client_data,
+					 mddi_sharp_init_table,
+					 ARRAY_SIZE(mddi_sharp_init_table));
+		break;
+	case 1:
+		printk("init tpo panel\n");
+		trout_process_mddi_table(client_data,
+					 mddi_tpo_init_table,
+					 ARRAY_SIZE(mddi_tpo_init_table));
+		break;
+	default:
+		printk("unknown panel_id: %d\n", panel_id);
+		ret = -1;
+	};
+	mutex_lock(&trout_backlight_lock);
+	trout_set_backlight_level(trout_backlight_brightness);
+	trout_backlight_off = 0;
+	mutex_unlock(&trout_backlight_lock);
+	client_data->auto_hibernate(client_data, 1);
+	client_data->remote_write(client_data, GPIOSEL_VWAKEINT, GPIOSEL);
+	client_data->remote_write(client_data, INTMASK_VWAKEOUT, INTMASK);
+	return ret;
+
+}
+
+static int trout_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("deinit sharp panel\n");
+		trout_process_mddi_table(client_data,
+					 mddi_sharp_deinit_table,
+					 ARRAY_SIZE(mddi_sharp_deinit_table));
+		break;
+	case 1:
+		printk("deinit tpo panel\n");
+		trout_process_mddi_table(client_data,
+					 mddi_tpo_deinit_table,
+					 ARRAY_SIZE(mddi_tpo_deinit_table));
+		break;
+	default:
+		printk("unknown panel_id: %d\n", panel_id);
+		ret = -1;
+	};
+	client_data->auto_hibernate(client_data, 1);
+	mutex_lock(&trout_backlight_lock);
+	trout_set_backlight_level(0);
+	trout_backlight_off = 1;
+	mutex_unlock(&trout_backlight_lock);
+	client_data->remote_write(client_data, 0, SYSCLKENA);
+	client_data->remote_write(client_data, 1, DPSUS);
+	return ret;
+}
+
+static void trout_brightness_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	mutex_lock(&trout_backlight_lock);
+	trout_backlight_brightness = value;
+	if(!trout_backlight_off)
+		trout_set_backlight_level(trout_backlight_brightness);
+	mutex_unlock(&trout_backlight_lock);
+}
+
+static struct led_classdev trout_backlight_led = {
+	.name			= "lcd-backlight",
+	.brightness = TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS,
+	.brightness_set = trout_brightness_set,
+};
+
+static int trout_backlight_probe(struct platform_device *pdev)
+{
+	led_classdev_register(&pdev->dev, &trout_backlight_led);
+	return 0;
+}
+
+static int trout_backlight_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&trout_backlight_led);
+	return 0;
+}
+
+static struct platform_driver trout_backlight_driver = {
+	.probe		= trout_backlight_probe,
+	.remove		= trout_backlight_remove,
+	.driver		= {
+		.name		= "trout-backlight",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static struct resource resources_msm_fb[] = {
+	{
+		.start = MSM_FB_BASE,
+		.end = MSM_FB_BASE + MSM_FB_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct msm_mddi_bridge_platform_data toshiba_client_data = {
+	.init = trout_mddi_toshiba_client_init,
+	.uninit = trout_mddi_toshiba_client_uninit,
+	.blank = trout_mddi_panel_blank,
+	.unblank = trout_mddi_panel_unblank,
+	.fb_data = {
+		.xres = 320,
+		.yres = 480,
+		.width = 45,
+		.height = 67,
+		.output_format = 0,
+	},
+};
+
+static struct msm_mddi_platform_data mddi_pdata = {
+	.clk_rate = 122880000,
+	.power_client = trout_mddi_power_client,
+	.vsync_irq = MSM_GPIO_TO_INT(VSYNC_GPIO),
+	.fb_resource = resources_msm_fb,
+	.num_clients = 1,
+	.client_platform_data = {
+		{
+			.product_id = (0xd263 << 16 | 0),
+			.name = "mddi_c_d263_0000",
+			//.name = "mddi_c_dummy",
+			.id = 0,
+			.client_data = &toshiba_client_data,
+			//.client_data = &toshiba_client_data.fb_data,
+			.clk_rate = 0,
+		},
+	},
+};
+
+static struct platform_device trout_backlight = {
+	.name = "trout-backlight",
+};
+
+int __init trout_init_panel(void)
+{
+	int rc;
+
+        if (!machine_is_trout())
+                return 0;
+	vreg_mddi_1v5 = vreg_get(0, "gp2");
+	if (IS_ERR(vreg_mddi_1v5))
+		return PTR_ERR(vreg_mddi_1v5);
+	vreg_lcm_2v85 = vreg_get(0, "gp4");
+	if (IS_ERR(vreg_lcm_2v85))
+		return PTR_ERR(vreg_lcm_2v85);
+
+	trout_new_backlight = system_rev >= 5;
+	if (trout_new_backlight) {
+		uint32_t config = PCOM_GPIO_CFG(27, 0, GPIO_OUTPUT,
+						GPIO_NO_PULL, GPIO_8MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0);
+	}
+	else {
+		uint32_t config = PCOM_GPIO_CFG(27, 1, GPIO_OUTPUT,
+						GPIO_NO_PULL, GPIO_8MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0);
+
+		gp_clk = clk_get(NULL, "gp_clk");
+		if (IS_ERR(gp_clk)) {
+			printk(KERN_ERR "trout_init_panel: could not get gp"
+			       "clock\n");
+			gp_clk = NULL;
+		}
+		rc = clk_set_rate(gp_clk, 19200000);
+		if (rc)
+			printk(KERN_ERR "trout_init_panel: set clock rate "
+			       "failed\n");
+	}
+
+	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(&trout_backlight);
+	return platform_driver_register(&trout_backlight_driver);
+}
+
+device_initcall(trout_init_panel);
diff --git a/arch/arm/mach-msm/board-trout-rfkill.c b/arch/arm/mach-msm/board-trout-rfkill.c
new file mode 100644
index 0000000..e68eb2a
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-rfkill.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Author: 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.
+ *
+ */
+
+/* Control bluetooth power for trout platform */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/rfkill.h>
+#include <linux/delay.h>
+#include <asm/gpio.h>
+
+#include "board-trout.h"
+
+static struct rfkill *bt_rfk;
+static const char bt_name[] = "brf6300";
+
+static int bluetooth_set_power(void *data, bool blocked)
+{
+	if (!blocked) {
+		gpio_set_value(TROUT_GPIO_BT_32K_EN, 1);
+		udelay(10);
+		gpio_direction_output(101, 1);
+	} else {
+		gpio_direction_output(101, 0);
+		gpio_set_value(TROUT_GPIO_BT_32K_EN, 0);
+	}
+	return 0;
+}
+
+static struct rfkill_ops trout_rfkill_ops = {
+	.set_block = bluetooth_set_power,
+};
+
+static int trout_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,
+				&trout_rfkill_ops, NULL);
+	if (!bt_rfk)
+		return -ENOMEM;
+
+	rfkill_set_states(bt_rfk, default_state, false);
+
+	/* userspace cannot take exclusive control */
+
+	rc = rfkill_register(bt_rfk);
+
+	if (rc)
+		rfkill_destroy(bt_rfk);
+	return rc;
+}
+
+static int trout_rfkill_remove(struct platform_device *dev)
+{
+	rfkill_unregister(bt_rfk);
+	rfkill_destroy(bt_rfk);
+
+	return 0;
+}
+
+static struct platform_driver trout_rfkill_driver = {
+	.probe = trout_rfkill_probe,
+	.remove = trout_rfkill_remove,
+	.driver = {
+		.name = "trout_rfkill",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init trout_rfkill_init(void)
+{
+	return platform_driver_register(&trout_rfkill_driver);
+}
+
+static void __exit trout_rfkill_exit(void)
+{
+	platform_driver_unregister(&trout_rfkill_driver);
+}
+
+module_init(trout_rfkill_init);
+module_exit(trout_rfkill_exit);
+MODULE_DESCRIPTION("trout rfkill");
+MODULE_AUTHOR("Nick Pelly <npelly@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-trout-wifi.c b/arch/arm/mach-msm/board-trout-wifi.c
new file mode 100644
index 0000000..51b26a4
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-wifi.c
@@ -0,0 +1,74 @@
+/* arch/arm/mach-msm/board-trout-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 trout_wifi_set_carddetect(int val);
+extern int trout_wifi_power(int on);
+extern int trout_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 *trout_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 trout_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 trout_wifi_control = {
+	.set_power		= trout_wifi_power,
+	.set_reset		= trout_wifi_reset,
+	.set_carddetect		= trout_wifi_set_carddetect,
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+	.mem_prealloc		= trout_wifi_mem_prealloc,
+#else
+	.mem_prealloc		= NULL,
+#endif	
+};
+
+#endif
diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c
index dca5a5f..1ce43e1 100644
--- a/arch/arm/mach-msm/board-trout.c
+++ b/arch/arm/mach-msm/board-trout.c
@@ -1,7 +1,6 @@
-/* linux/arch/arm/mach-msm/board-trout.c
+/* arch/arm/mach-msm/board-trout.c
  *
- * Copyright (C) 2009 Google, Inc.
- * Author: Brian Swetland <swetland@google.com>
+ * 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
@@ -17,46 +16,817 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #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 <../../../drivers/staging/android/timed_gpio.h>
+#include <linux/synaptics_i2c_rmi.h>
+#include <linux/akm8976.h>
+#include <linux/sysdev.h>
+#include <linux/android_pmem.h>
 
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+#include <asm/system.h>
+#include <mach/system.h>
+#include <mach/vreg.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
 #include <asm/setup.h>
 
-#include <mach/board.h>
-#include <mach/hardware.h>
-#include <mach/msm_iomap.h>
+#include <linux/gpio_event.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
 
-#include "devices.h"
+#include <asm/mach/mmc.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/msm_audio.h>
+
 #include "board-trout.h"
 
+#include "gpio_chip.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_HTC_HEADSET
+#include <mach/htc_headset.h>
+#endif
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#include <linux/wifi_tiwlan.h>
+#endif
+
+#include "proc_comm.h"
+#include "devices.h"
+
+void msm_init_irq(void);
+void msm_init_gpio(void);
+
+extern int trout_init_mmc(unsigned int);
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+extern int trout_init_wifi_mem(void);
+#endif
+extern struct wifi_platform_data trout_wifi_control;
+#endif
+
+struct trout_axis_info {
+	struct gpio_event_axis_info info;
+	uint16_t in_state;
+	uint16_t out_state;
+};
+static bool nav_just_on;
+static int nav_on_jiffies;
+
+uint16_t trout_axis_map(struct gpio_event_axis_info *info, uint16_t in)
+{
+	struct trout_axis_info *ai = container_of(info, struct trout_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;
+	return out;
+}
+
+int trout_nav_power(const struct gpio_event_platform_data *pdata, bool on)
+{
+	gpio_set_value(TROUT_GPIO_JOG_EN, on);
+	if (on) {
+		nav_just_on = 1;
+		nav_on_jiffies = jiffies;
+	}
+	return 0;
+}
+
+static uint32_t trout_4_x_axis_gpios[] = {
+	TROUT_4_BALL_LEFT_0, TROUT_4_BALL_RIGHT_0
+};
+static uint32_t trout_5_x_axis_gpios[] = {
+	TROUT_5_BALL_LEFT_0, TROUT_5_BALL_RIGHT_0
+};
+
+static struct trout_axis_info trout_x_axis = {
+	.info = {
+		.info.func = gpio_event_axis_func,
+		.count = ARRAY_SIZE(trout_5_x_axis_gpios),
+		.type = EV_REL,
+		.code = REL_X,
+		.decoded_size = 1U << ARRAY_SIZE(trout_5_x_axis_gpios),
+		.map = trout_axis_map,
+		.gpio = trout_5_x_axis_gpios,
+		.flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */
+	}
+};
+
+static uint32_t trout_4_y_axis_gpios[] = {
+	TROUT_4_BALL_UP_0, TROUT_4_BALL_DOWN_0
+};
+static uint32_t trout_5_y_axis_gpios[] = {
+	TROUT_5_BALL_UP_0, TROUT_5_BALL_DOWN_0
+};
+
+static struct trout_axis_info trout_y_axis = {
+	.info = {
+		.info.func = gpio_event_axis_func,
+		.count = ARRAY_SIZE(trout_5_y_axis_gpios),
+		.type = EV_REL,
+		.code = REL_Y,
+		.decoded_size = 1U << ARRAY_SIZE(trout_5_y_axis_gpios),
+		.map = trout_axis_map,
+		.gpio = trout_5_y_axis_gpios,
+		.flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */
+	}
+};
+
+static struct gpio_event_direct_entry trout_nav_buttons[] = {
+	{ TROUT_GPIO_NAVI_ACT_N, BTN_MOUSE }
+};
+
+static struct gpio_event_input_info trout_nav_button_info = {
+	.info.func = gpio_event_input_func,
+	.flags = 0,
+	.type = EV_KEY,
+	.keymap = trout_nav_buttons,
+	.keymap_size = ARRAY_SIZE(trout_nav_buttons)
+};
+
+static struct gpio_event_info *trout_nav_info[] = {
+	&trout_x_axis.info.info,
+	&trout_y_axis.info.info,
+	&trout_nav_button_info.info
+};
+
+static struct gpio_event_platform_data trout_nav_data = {
+	.name = "trout-nav",
+	.info = trout_nav_info,
+	.info_count = ARRAY_SIZE(trout_nav_info),
+	.power = trout_nav_power,
+};
+
+static struct platform_device trout_nav_device = {
+	.name = GPIO_EVENT_DEV_NAME,
+	.id = 2,
+	.dev = {
+		.platform_data = &trout_nav_data,
+	},
+};
+
+static int trout_reset_keys_up[] = {
+	BTN_MOUSE,
+	0
+};
+
+static struct keyreset_platform_data trout_reset_keys_pdata = {
+	.keys_up = trout_reset_keys_up,
+	.keys_down = {
+		KEY_SEND,
+		KEY_MENU,
+		KEY_END,
+		0
+	},
+};
+
+struct platform_device trout_reset_keys_device = {
+	.name = KEYRESET_NAME,
+	.dev.platform_data = &trout_reset_keys_pdata,
+};
+
+static int trout_ts_power(int on)
+{
+	int tp_ls_gpio = system_rev < 5 ? TROUT_4_TP_LS_EN : TROUT_5_TP_LS_EN;
+	if (on) {
+		gpio_set_value(TROUT_GPIO_TP_I2C_PULL, 1);
+		gpio_set_value(TROUT_GPIO_TP_EN, 1);
+		/* touchscreen must be powered before we enable i2c pullup */
+		msleep(2);
+		/* enable touch panel level shift */
+		gpio_set_value(tp_ls_gpio, 1);
+		msleep(2);
+	}
+	else {
+		gpio_set_value(tp_ls_gpio, 0);
+		udelay(50);
+		gpio_set_value(TROUT_GPIO_TP_EN, 0);
+		gpio_set_value(TROUT_GPIO_TP_I2C_PULL, 0);
+	}
+	return 0;
+}
+
+static struct synaptics_i2c_rmi_platform_data trout_ts_data[] = {
+	{
+		.version = 0x010c,
+		.power = trout_ts_power,
+		.flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE,
+		.inactive_left = -100 * 0x10000 / 4334,
+		.inactive_right = -100 * 0x10000 / 4334,
+		.inactive_top = -40 * 0x10000 / 6696,
+		.inactive_bottom = -40 * 0x10000 / 6696,
+		.snap_left_on = 300 * 0x10000 / 4334,
+		.snap_left_off = 310 * 0x10000 / 4334,
+		.snap_right_on = 300 * 0x10000 / 4334,
+		.snap_right_off = 310 * 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 = TROUT_GPIO_COMPASS_RST_N,
+	.clk_on = TROUT_GPIO_COMPASS_32K_EN,
+	.intr = TROUT_GPIO_COMPASS_IRQ,
+};
+
+static struct i2c_board_info i2c_devices[] = {
+	{
+		I2C_BOARD_INFO(SYNAPTICS_I2C_RMI_NAME, 0x20),
+		.platform_data = trout_ts_data,
+		.irq = TROUT_GPIO_TO_INT(TROUT_GPIO_TP_ATT_N)
+	},
+	{
+		I2C_BOARD_INFO("elan-touch", 0x10),
+		.irq = TROUT_GPIO_TO_INT(TROUT_GPIO_TP_ATT_N),
+	},
+	{
+		I2C_BOARD_INFO("akm8976", 0x1C),
+		.platform_data = &compass_platform_data,
+		.irq = TROUT_GPIO_TO_INT(TROUT_GPIO_COMPASS_IRQ),
+	},
+	{
+		I2C_BOARD_INFO("pca963x", 0x62),
+	},
+#if defined(CONFIG_MSM_CAMERA) && defined(CONFIG_MT9T013)
+	{
+		I2C_BOARD_INFO("mt9t013", 0x6C),
+	},
+#endif
+#ifdef CONFIG_SENSORS_MT9T013
+	{
+		I2C_BOARD_INFO("mt9t013", 0x6C >> 1),
+	},
+#endif
+};
+
+static struct timed_gpio timed_gpios[] = {
+	{
+		.name = "vibrator",
+		.gpio = TROUT_GPIO_HAPTIC_PWM,
+		.max_timeout = 15000,
+	},
+	{
+		.name = "flash",
+		.gpio = TROUT_GPIO_FLASH_EN,
+		.max_timeout = 400,
+	},
+};
+
+static struct timed_gpio_platform_data timed_gpio_data = {
+	.num_gpios	= ARRAY_SIZE(timed_gpios),
+	.gpios		= timed_gpios,
+};
+
+static struct platform_device android_timed_gpios = {
+	.name		= "timed-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &timed_gpio_data,
+	},
+};
+
+static struct gpio_led android_led_list[] = {
+	{
+		.name = "spotlight",
+		.gpio = TROUT_GPIO_SPOTLIGHT_EN,
+	},
+	{
+		.name = "keyboard-backlight",
+		.gpio = TROUT_GPIO_QTKEY_LED_EN,
+	},
+	{
+		.name = "button-backlight",
+		.gpio = TROUT_GPIO_UI_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,
+	},
+};
+
+static struct gpio_switch_platform_data sd_door_switch_data = {
+	.name		= "sd-door",
+	.gpio		= TROUT_GPIO_SD_DOOR_N,
+	.state_on	= "open",
+	.state_off	= "closed",
+};
+
+static struct platform_device sd_door_switch = {
+	.name		= "switch-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &sd_door_switch_data,
+	},
+};
+
+#ifdef CONFIG_HTC_HEADSET
+static void h2w_config_cpld(int route)
+{
+	switch (route) {
+	case H2W_UART3:
+		gpio_set_value(TROUT_GPIO_H2W_SEL0, 0);
+		gpio_set_value(TROUT_GPIO_H2W_SEL1, 1);
+		break;
+	case H2W_GPIO:
+		gpio_set_value(TROUT_GPIO_H2W_SEL0, 0);
+		gpio_set_value(TROUT_GPIO_H2W_SEL1, 0);
+		break;
+	}
+}
+
+static void h2w_init_cpld(void)
+{
+	h2w_config_cpld(H2W_UART3);
+	gpio_set_value(TROUT_GPIO_H2W_CLK_DIR, 0);
+	gpio_set_value(TROUT_GPIO_H2W_DAT_DIR, 0);
+}
+
+static struct h2w_platform_data trout_h2w_data = {
+	.cable_in1		= TROUT_GPIO_CABLE_IN1,
+	.cable_in2		= TROUT_GPIO_CABLE_IN2,
+	.h2w_clk		= TROUT_GPIO_H2W_CLK_GPI,
+	.h2w_data		= TROUT_GPIO_H2W_DAT_GPI,
+	.debug_uart 		= H2W_UART3,
+	.config_cpld 		= h2w_config_cpld,
+	.init_cpld 		= h2w_init_cpld,
+};
+
+static struct platform_device trout_h2w = {
+	.name		= "h2w",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &trout_h2w_data,
+	},
+};
+#endif
+
+static void trout_phy_reset(void)
+{
+	gpio_set_value(TROUT_GPIO_USB_PHY_RST_N, 0);
+	mdelay(10);
+	gpio_set_value(TROUT_GPIO_USB_PHY_RST_N, 1);
+	mdelay(10);
+}
+
+static void config_camera_on_gpios(void);
+static void config_camera_off_gpios(void);
+
+#ifdef CONFIG_MSM_CAMERA
+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_MT9T013
+static struct msm_camera_sensor_info msm_camera_sensor_mt9t013_data = {
+	.sensor_name    = "mt9t013",
+	.sensor_reset   = 108,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = TROUT_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
+#endif
+
+#ifdef CONFIG_SENSORS_MT9T013
+static struct msm_camera_legacy_device_platform_data msm_camera_device_mt9t013 = {
+	.sensor_reset	= 108,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= TROUT_GPIO_VCM_PWDN,
+	.config_gpio_on = config_camera_on_gpios,
+	.config_gpio_off = config_camera_off_gpios,
+};
+
+static struct platform_device trout_camera = {
+	.name           = "camera",
+	.dev            = {
+		.platform_data = &msm_camera_device_mt9t013,
+	},
+};
+#endif
+
+static struct pwr_sink trout_pwrsink_table[] = {
+	{
+		.id	= PWRSINK_AUDIO,
+		.ua_max	= 90000,
+	},
+	{
+		.id	= PWRSINK_BACKLIGHT,
+		.ua_max	= 128000,
+	},
+	{
+		.id	= PWRSINK_LED_BUTTON,
+		.ua_max	= 17000,
+	},
+	{
+		.id	= PWRSINK_LED_KEYBOARD,
+		.ua_max	= 22000,
+	},
+	{
+		.id	= PWRSINK_GP_CLK,
+		.ua_max	= 30000,
+	},
+	{
+		.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 struct pwr_sink_platform_data trout_pwrsink_data = {
+	.num_sinks	= ARRAY_SIZE(trout_pwrsink_table),
+	.sinks		= trout_pwrsink_table,
+	.suspend_late	= NULL,
+	.resume_early	= NULL,
+	.suspend_early	= NULL,
+	.resume_late	= NULL,
+};
+
+static struct platform_device trout_pwr_sink = {
+	.name = "htc_pwrsink",
+	.id = -1,
+	.dev	= {
+		.platform_data = &trout_pwrsink_data,
+	},
+};
+
+static struct platform_device trout_rfkill = {
+	.name = "trout_rfkill",
+	.id = -1,
+};
+
+static struct msm_pmem_setting pmem_setting = {
+	.pmem_start = MSM_PMEM_MDP_BASE,
+	.pmem_size = MSM_PMEM_MDP_SIZE,
+	.pmem_adsp_start = MSM_PMEM_ADSP_BASE,
+	.pmem_adsp_size = 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 = MSM_PMEM_CAMERA_BASE,
+	.pmem_camera_size = 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 trout_wifi = {
+	.name		= "msm_wifi",
+	.id		= 1,
+	.num_resources	= 0,
+	.resource	= NULL,
+	.dev		= {
+		.platform_data = &trout_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 trout_snd_endpoints = {
+	.endpoints = snd_endpoints_list,
+	.num = ARRAY_SIZE(snd_endpoints_list),
+};
+
+static struct platform_device trout_snd = {
+	.name = "msm_snd",
+	.id = -1,
+	.dev	= {
+		.platform_data = &trout_snd_endpoints,
+	},
+};
+
 static struct platform_device *devices[] __initdata = {
-	&msm_device_uart3,
 	&msm_device_smd,
 	&msm_device_nand,
-	&msm_device_hsusb,
 	&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
+	&trout_nav_device,
+	&trout_reset_keys_device,
+	&android_leds,
+	&sd_door_switch,
+	&android_timed_gpios,
+#ifdef CONFIG_MT9T013
+	&msm_camera_sensor_mt9t013,
+#endif
+#ifdef CONFIG_SENSORS_MT9T013
+	&trout_camera,
+#endif
+	&trout_rfkill,
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+	&trout_wifi,
+#endif
+#ifdef CONFIG_HTC_HEADSET
+	&trout_h2w,
+#endif
+#ifdef CONFIG_HTC_PWRSINK
+	&trout_pwr_sink,
+#endif
+	&trout_snd,
 };
 
 extern struct sys_timer msm_timer;
 
 static void __init trout_init_irq(void)
 {
+	printk("trout_init_irq()\n");
 	msm_init_irq();
 }
 
-static void __init trout_fixup(struct machine_desc *desc, struct tag *tags,
-				char **cmdline, struct meminfo *mi)
+static uint opt_disable_uart3;
+
+module_param_named(disable_uart3, opt_disable_uart3, uint, 0);
+
+static void trout_reset(void)
 {
-	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);
+	gpio_set_value(TROUT_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 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 void __init config_gpios(void)
+{
+	config_gpio_table(gpio_table, ARRAY_SIZE(gpio_table));
+	config_camera_off_gpios();
+}
+
+static struct msm_acpu_clock_platform_data trout_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 trout_init(void)
 {
+	int rc;
+
+	printk("trout_init() revision=%d\n", system_rev);
+
+	/*
+	 * Setup common MSM GPIOS
+	 */
+	config_gpios();
+
+	msm_hw_reset_hook = trout_reset;
+
+	gpio_direction_output(system_rev < 5 ?
+			TROUT_4_TP_LS_EN : TROUT_5_TP_LS_EN, 0);
+
+	msm_acpu_clock_init(&trout_clock_data);
+
+#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); */
+
+	/* put the AF VCM in powerdown mode to avoid noise */
+	gpio_set_value(TROUT_GPIO_VCM_PWDN, 1);
+	mdelay(100);
+
+	if (system_rev < 5) {
+		trout_x_axis.info.gpio = trout_4_x_axis_gpios;
+		trout_y_axis.info.gpio = trout_4_y_axis_gpios;
+	}
+
+#ifdef CONFIG_SERIAL_MSM_HS
+	msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+#endif
+	msm_add_usb_devices(trout_phy_reset);
+
+	msm_add_mem_devices(&pmem_setting);
+
+	rc = trout_init_mmc(system_rev);
+	if (rc)
+		printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc);
+
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+	rc = trout_init_wifi_mem();
+	if (rc)
+		printk(KERN_CRIT "%s: WiFi Memory init failure (%d)\n", __func__, rc);
+#endif
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
+	i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
+
+	/* SD card door should wake the device */
+	set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SD_DOOR_N), 1);
 }
 
 static struct map_desc trout_io_desc[] __initdata = {
@@ -68,28 +838,32 @@
 	}
 };
 
+static void __init trout_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 trout_map_io(void)
 {
 	msm_map_common_io();
 	iotable_init(trout_io_desc, ARRAY_SIZE(trout_io_desc));
-
-#ifdef CONFIG_MSM_DEBUG_UART3
-	/* route UART3 to the "H2W" extended usb connector */
-	writeb(0x80, TROUT_CPLD_BASE + 0x00);
-#endif
-
 	msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a);
 }
 
-MACHINE_START(TROUT, "HTC Dream")
+MACHINE_START(TROUT, "trout")
+/* Maintainer: Brian Swetland <swetland@google.com> */
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io	= MSM_DEBUG_UART_PHYS,
-	.io_pg_offst	= ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+	.phys_io        = MSM_DEBUG_UART_PHYS,
+	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
-	.boot_params	= 0x10000100,
-	.fixup		= trout_fixup,
-	.map_io		= trout_map_io,
-	.init_irq	= trout_init_irq,
-	.init_machine	= trout_init,
-	.timer		= &msm_timer,
+	.boot_params    = 0x10000100,
+	.fixup          = trout_fixup,
+	.map_io         = trout_map_io,
+	.init_irq       = trout_init_irq,
+	.init_machine   = trout_init,
+	.timer          = &msm_timer,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-trout.h b/arch/arm/mach-msm/board-trout.h
index 4f345a5..0a7d274 100644
--- a/arch/arm/mach-msm/board-trout.h
+++ b/arch/arm/mach-msm/board-trout.h
@@ -1,5 +1,162 @@
+/* linux/arch/arm/mach-msm/board-trout.h
+** Author: Brian Swetland <swetland@google.com>
+*/
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
+#define __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
 
-#define TROUT_CPLD_BASE   0xE8100000
+#include <mach/board.h>
+
+#define MSM_SMI_BASE		0x00000000
+#define MSM_SMI_SIZE		0x00800000
+
+#define MSM_EBI_BASE		0x10000000
+#define MSM_EBI_SIZE		0x06e00000
+
+#define MSM_PMEM_GPU0_BASE	0x00000000
+#define MSM_PMEM_GPU0_SIZE	0x00700000
+
+#define MSM_PMEM_MDP_BASE	0x02000000
+#define MSM_PMEM_MDP_SIZE	0x00800000
+
+#define MSM_PMEM_ADSP_BASE      0x02800000
+#define MSM_PMEM_ADSP_SIZE	0x00800000
+
+#define MSM_PMEM_CAMERA_BASE	0x03000000
+#define MSM_PMEM_CAMERA_SIZE	0x00800000
+
+#define MSM_FB_BASE		0x03800000
+#define MSM_FB_SIZE		0x00100000
+
+#define MSM_LINUX_BASE		MSM_EBI_BASE
+#define MSM_LINUX_SIZE		0x06500000
+
+#define MSM_PMEM_GPU1_SIZE	0x800000
+#define MSM_PMEM_GPU1_BASE	MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE
+
+#define MSM_RAM_CONSOLE_BASE	MSM_EBI_BASE + 0x6d00000
+#define MSM_RAM_CONSOLE_SIZE	128 * SZ_1K
+
+#if (MSM_FB_BASE + MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#define DECLARE_MSM_IOMAP
+#include <mach/msm_iomap.h>
+
+#define TROUT_4_BALL_UP_0     1
+#define TROUT_4_BALL_LEFT_0   18
+#define TROUT_4_BALL_DOWN_0   57
+#define TROUT_4_BALL_RIGHT_0  91
+
+#define TROUT_5_BALL_UP_0     94
+#define TROUT_5_BALL_LEFT_0   18
+#define TROUT_5_BALL_DOWN_0   90
+#define TROUT_5_BALL_RIGHT_0  19
+
+#define TROUT_POWER_KEY     20
+
+#define TROUT_4_TP_LS_EN    19
+#define TROUT_5_TP_LS_EN    1
+
+#define TROUT_CPLD_BASE   0xFA000000
 #define TROUT_CPLD_START  0x98000000
 #define TROUT_CPLD_SIZE   SZ_4K
 
+#define TROUT_GPIO_CABLE_IN1		(83)
+#define TROUT_GPIO_CABLE_IN2		(49)
+
+#define TROUT_GPIO_START (128)
+
+#define TROUT_GPIO_INT_MASK0_REG            (0x0c)
+#define TROUT_GPIO_INT_STAT0_REG            (0x0e)
+#define TROUT_GPIO_INT_MASK1_REG            (0x14)
+#define TROUT_GPIO_INT_STAT1_REG            (0x10)
+
+#define TROUT_GPIO_HAPTIC_PWM               (28)
+#define TROUT_GPIO_PS_HOLD                  (25)
+
+#define TROUT_GPIO_MISC2_BASE               (TROUT_GPIO_START + 0x00)
+#define TROUT_GPIO_MISC3_BASE               (TROUT_GPIO_START + 0x08)
+#define TROUT_GPIO_MISC4_BASE               (TROUT_GPIO_START + 0x10)
+#define TROUT_GPIO_MISC5_BASE               (TROUT_GPIO_START + 0x18)
+#define TROUT_GPIO_INT2_BASE                (TROUT_GPIO_START + 0x20)
+#define TROUT_GPIO_MISC1_BASE               (TROUT_GPIO_START + 0x28)
+#define TROUT_GPIO_VIRTUAL_BASE             (TROUT_GPIO_START + 0x30)
+#define TROUT_GPIO_INT5_BASE                (TROUT_GPIO_START + 0x48)
+
+#define TROUT_GPIO_CHARGER_EN               (TROUT_GPIO_MISC2_BASE + 0)
+#define TROUT_GPIO_ISET                     (TROUT_GPIO_MISC2_BASE + 1)
+#define TROUT_GPIO_H2W_DAT_DIR              (TROUT_GPIO_MISC2_BASE + 2)
+#define TROUT_GPIO_H2W_CLK_DIR              (TROUT_GPIO_MISC2_BASE + 3)
+#define TROUT_GPIO_H2W_DAT_GPO              (TROUT_GPIO_MISC2_BASE + 4)
+#define TROUT_GPIO_H2W_CLK_GPO              (TROUT_GPIO_MISC2_BASE + 5)
+#define TROUT_GPIO_H2W_SEL0                 (TROUT_GPIO_MISC2_BASE + 6)
+#define TROUT_GPIO_H2W_SEL1                 (TROUT_GPIO_MISC2_BASE + 7)
+
+#define TROUT_GPIO_SPOTLIGHT_EN             (TROUT_GPIO_MISC3_BASE + 0)
+#define TROUT_GPIO_FLASH_EN                 (TROUT_GPIO_MISC3_BASE + 1)
+#define TROUT_GPIO_I2C_PULL                 (TROUT_GPIO_MISC3_BASE + 2)
+#define TROUT_GPIO_TP_I2C_PULL              (TROUT_GPIO_MISC3_BASE + 3)
+#define TROUT_GPIO_TP_EN                    (TROUT_GPIO_MISC3_BASE + 4)
+#define TROUT_GPIO_JOG_EN                   (TROUT_GPIO_MISC3_BASE + 5)
+#define TROUT_GPIO_UI_LED_EN                (TROUT_GPIO_MISC3_BASE + 6)
+#define TROUT_GPIO_QTKEY_LED_EN             (TROUT_GPIO_MISC3_BASE + 7)
+
+#define TROUT_GPIO_VCM_PWDN                 (TROUT_GPIO_MISC4_BASE + 0)
+#define TROUT_GPIO_USB_H2W_SW               (TROUT_GPIO_MISC4_BASE + 1)
+#define TROUT_GPIO_COMPASS_RST_N            (TROUT_GPIO_MISC4_BASE + 2)
+#define TROUT_GPIO_HAPTIC_EN_UP             (TROUT_GPIO_MISC4_BASE + 3)
+#define TROUT_GPIO_HAPTIC_EN_MAIN           (TROUT_GPIO_MISC4_BASE + 4)
+#define TROUT_GPIO_USB_PHY_RST_N            (TROUT_GPIO_MISC4_BASE + 5)
+#define TROUT_GPIO_WIFI_PA_RESETX           (TROUT_GPIO_MISC4_BASE + 6)
+#define TROUT_GPIO_WIFI_EN                  (TROUT_GPIO_MISC4_BASE + 7)
+
+#define TROUT_GPIO_BT_32K_EN                (TROUT_GPIO_MISC5_BASE + 0)
+#define TROUT_GPIO_MAC_32K_EN               (TROUT_GPIO_MISC5_BASE + 1)
+#define TROUT_GPIO_MDDI_32K_EN              (TROUT_GPIO_MISC5_BASE + 2)
+#define TROUT_GPIO_COMPASS_32K_EN           (TROUT_GPIO_MISC5_BASE + 3)
+
+#define TROUT_GPIO_NAVI_ACT_N               (TROUT_GPIO_INT2_BASE + 0)
+#define TROUT_GPIO_COMPASS_IRQ              (TROUT_GPIO_INT2_BASE + 1)
+#define TROUT_GPIO_SLIDING_DET              (TROUT_GPIO_INT2_BASE + 2)
+#define TROUT_GPIO_AUD_HSMIC_DET_N          (TROUT_GPIO_INT2_BASE + 3)
+#define TROUT_GPIO_SD_DOOR_N                (TROUT_GPIO_INT2_BASE + 4)
+#define TROUT_GPIO_CAM_BTN_STEP1_N          (TROUT_GPIO_INT2_BASE + 5)
+#define TROUT_GPIO_CAM_BTN_STEP2_N          (TROUT_GPIO_INT2_BASE + 6)
+#define TROUT_GPIO_TP_ATT_N                 (TROUT_GPIO_INT2_BASE + 7)
+#define TROUT_GPIO_BANK0_FIRST_INT_SOURCE   (TROUT_GPIO_NAVI_ACT_N)
+#define TROUT_GPIO_BANK0_LAST_INT_SOURCE    (TROUT_GPIO_TP_ATT_N)
+
+#define TROUT_GPIO_H2W_DAT_GPI              (TROUT_GPIO_MISC1_BASE + 0)
+#define TROUT_GPIO_H2W_CLK_GPI              (TROUT_GPIO_MISC1_BASE + 1)
+#define TROUT_GPIO_CPLD128_VER_0            (TROUT_GPIO_MISC1_BASE + 4)
+#define TROUT_GPIO_CPLD128_VER_1            (TROUT_GPIO_MISC1_BASE + 5)
+#define TROUT_GPIO_CPLD128_VER_2            (TROUT_GPIO_MISC1_BASE + 6)
+#define TROUT_GPIO_CPLD128_VER_3            (TROUT_GPIO_MISC1_BASE + 7)
+
+#define TROUT_GPIO_SDMC_CD_N                (TROUT_GPIO_VIRTUAL_BASE + 0)
+#define TROUT_GPIO_END                      (TROUT_GPIO_SDMC_CD_N)
+#define TROUT_GPIO_BANK1_FIRST_INT_SOURCE   (TROUT_GPIO_SDMC_CD_N)
+#define TROUT_GPIO_BANK1_LAST_INT_SOURCE    (TROUT_GPIO_SDMC_CD_N)
+
+#define TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET \
+	(TROUT_GPIO_INT5_BASE - TROUT_GPIO_VIRTUAL_BASE)
+
+#define TROUT_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS)
+#define TROUT_INT_BANK0_COUNT (8)
+#define TROUT_INT_BANK1_START (TROUT_INT_START + TROUT_INT_BANK0_COUNT)
+#define TROUT_INT_BANK1_COUNT (1)
+#define TROUT_INT_END (TROUT_INT_START + TROUT_INT_BANK0_COUNT + \
+			TROUT_INT_BANK1_COUNT - 1)
+#define TROUT_GPIO_TO_INT(n) (((n) <= TROUT_GPIO_BANK0_LAST_INT_SOURCE) ? \
+	(TROUT_INT_START - TROUT_GPIO_BANK0_FIRST_INT_SOURCE + (n)) : \
+	(TROUT_INT_BANK1_START - TROUT_GPIO_BANK1_FIRST_INT_SOURCE + (n)))
+
+#define TROUT_INT_TO_BANK(n) ((n - TROUT_INT_START) / TROUT_INT_BANK0_COUNT)
+#define TROUT_INT_TO_MASK(n) (1U << ((n - TROUT_INT_START) & 7))
+#define TROUT_BANK_TO_MASK_REG(bank) \
+	(bank ? TROUT_GPIO_INT_MASK1_REG : TROUT_GPIO_INT_MASK0_REG)
+#define TROUT_BANK_TO_STAT_REG(bank) \
+	(bank ? TROUT_GPIO_INT_STAT1_REG : TROUT_GPIO_INT_STAT0_REG)
+
+#endif /* GUARD */
diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h
index 17d027b..04f7332 100644
--- a/arch/arm/mach-msm/clock-pcom.h
+++ b/arch/arm/mach-msm/clock-pcom.h
@@ -72,8 +72,13 @@
 #define P_USB_HS_P_CLK	37  /* High speed USB pbus clock */
 #define P_USB_OTG_CLK	38  /* Full speed USB clock */
 #define P_VDC_CLK	39  /* Video controller clock */
-#define P_VFE_MDC_CLK	40  /* Camera / Video Front End clock */
-#define P_VFE_CLK	41  /* VFE MDDI client clock */
+#if !defined(CONFIG_MSM_LEGACY_7X00A_AMSS)
+#define P_VFE_MDC_CLK	40  /* VFE MDDI client clock */
+#define P_VFE_CLK	41  /* Camera / Video Front End clock */
+#else/* For radio code base others */
+#define P_VFE_MDC_CLK	41  /* VFE MDDI client clock */
+#define P_VFE_CLK	40  /* Camera / Video Front End clock */
+#endif
 #define P_MDP_LCDC_PCLK_CLK	42
 #define P_MDP_LCDC_PAD_PCLK_CLK 43
 #define P_MDP_VSYNC_CLK	44
@@ -89,7 +94,7 @@
 #define P_USB_HS2_CORE_CLK	54  /* High speed USB 2 core clock */
 #define P_USB_HS3_CORE_CLK	55  /* High speed USB 3 core clock */
 #define P_CAM_M_CLK		56
-#define P_CAMIF_PAD_P_CLK	57
+#define P_QUP_I2C_P_CLK		57
 #define P_GRP_2D_CLK		58
 #define P_GRP_2D_P_CLK		59
 #define P_I2S_CLK		60
@@ -137,6 +142,7 @@
 
 struct clk_ops;
 extern struct clk_ops clk_ops_pcom;
+enum clk_reset_action;
 
 int pc_clk_reset(unsigned id, enum clk_reset_action action);
 
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 9cb1276..9d09658 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -21,10 +21,13 @@
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/debugfs.h>
 #include <linux/ctype.h>
 #include <linux/pm_qos_params.h>
+#include <linux/device.h>
+#include <linux/seq_file.h>
 #include <mach/clk.h>
 
 #include "clock.h"
@@ -33,7 +36,7 @@
 
 static DEFINE_MUTEX(clocks_mutex);
 static DEFINE_SPINLOCK(clocks_lock);
-static LIST_HEAD(clocks);
+static HLIST_HEAD(clocks);
 struct clk *msm_clocks;
 unsigned msm_num_clocks;
 
@@ -44,25 +47,54 @@
 static DECLARE_BITMAP(clock_map_enabled, NR_CLKS);
 static DEFINE_SPINLOCK(clock_map_lock);
 
+static struct clk *clk_allocate_handle(struct clk *sclk)
+{
+	unsigned long flags;
+	struct clk_handle *clkh = kzalloc(sizeof(*clkh), GFP_KERNEL);
+	if (!clkh)
+		return ERR_PTR(ENOMEM);
+	clkh->clk.flags = CLKFLAG_HANDLE;
+	clkh->source = sclk;
+
+	spin_lock_irqsave(&clocks_lock, flags);
+	hlist_add_head(&clkh->clk.list, &sclk->handles);
+	spin_unlock_irqrestore(&clocks_lock, flags);
+	return &clkh->clk;
+}
+
+static struct clk *source_clk(struct clk *clk)
+{
+	struct clk_handle *clkh;
+
+	if (clk->flags & CLKFLAG_HANDLE) {
+		clkh = container_of(clk, struct clk_handle, clk);
+		clk = clkh->source;
+	}
+	return clk;
+}
+
 /*
  * Standard clock functions defined in include/linux/clk.h
  */
 struct clk *clk_get(struct device *dev, const char *id)
 {
 	struct clk *clk;
+	struct hlist_node *pos;
 
 	mutex_lock(&clocks_mutex);
 
-	list_for_each_entry(clk, &clocks, list)
+	hlist_for_each_entry(clk, pos, &clocks, list)
 		if (!strcmp(id, clk->name) && clk->dev == dev)
 			goto found_it;
 
-	list_for_each_entry(clk, &clocks, list)
+	hlist_for_each_entry(clk, pos, &clocks, list)
 		if (!strcmp(id, clk->name) && clk->dev == NULL)
 			goto found_it;
 
 	clk = ERR_PTR(-ENOENT);
 found_it:
+	if (!IS_ERR(clk) && (clk->flags & CLKFLAG_SHARED))
+		clk = clk_allocate_handle(clk);
 	mutex_unlock(&clocks_mutex);
 	return clk;
 }
@@ -70,6 +102,22 @@
 
 void clk_put(struct clk *clk)
 {
+	struct clk_handle *clkh;
+	unsigned long flags;
+
+	if (WARN_ON(IS_ERR(clk)))
+		return;
+
+	if (!(clk->flags & CLKFLAG_HANDLE))
+		return;
+
+	clk_set_rate(clk, 0);
+
+	spin_lock_irqsave(&clocks_lock, flags);
+	clkh = container_of(clk, struct clk_handle, clk);
+	hlist_del(&clk->list);
+	kfree(clkh);
+	spin_unlock_irqrestore(&clocks_lock, flags);
 }
 EXPORT_SYMBOL(clk_put);
 
@@ -77,6 +125,7 @@
 {
 	unsigned long flags;
 	spin_lock_irqsave(&clocks_lock, flags);
+	clk = source_clk(clk);
 	clk->count++;
 	if (clk->count == 1) {
 		clk->ops->enable(clk->id);
@@ -93,6 +142,7 @@
 {
 	unsigned long flags;
 	spin_lock_irqsave(&clocks_lock, flags);
+	clk = source_clk(clk);
 	BUG_ON(clk->count == 0);
 	clk->count--;
 	if (clk->count == 0) {
@@ -115,13 +165,53 @@
 
 unsigned long clk_get_rate(struct clk *clk)
 {
+	clk = source_clk(clk);
 	return clk->ops->get_rate(clk->id);
 }
 EXPORT_SYMBOL(clk_get_rate);
 
+static unsigned long clk_find_min_rate_locked(struct clk *clk)
+{
+	unsigned long rate = 0;
+	struct clk_handle *clkh;
+	struct hlist_node *pos;
+
+	hlist_for_each_entry(clkh, pos, &clk->handles, clk.list)
+		if (clkh->rate > rate)
+			rate = clkh->rate;
+	return rate;
+}
+
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
-	return clk->ops->set_rate(clk->id, rate);
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&clocks_lock, flags);
+	if (clk->flags & CLKFLAG_HANDLE) {
+		struct clk_handle *clkh;
+		clkh = container_of(clk, struct clk_handle, clk);
+		clkh->rate = rate;
+		clk = clkh->source;
+		rate = clk_find_min_rate_locked(clk);
+	}
+
+	if (clk->flags & CLKFLAG_MAX) {
+		ret = clk->ops->set_max_rate(clk->id, rate);
+		if (ret)
+			goto err;
+	}
+	if (clk->flags & CLKFLAG_MIN) {
+		ret = clk->ops->set_min_rate(clk->id, rate);
+		if (ret)
+			goto err;
+	}
+
+	if (!(clk->flags & (CLKFLAG_MAX | CLKFLAG_MIN)))
+		ret = clk->ops->set_rate(clk->id, rate);
+err:
+	spin_unlock_irqrestore(&clocks_lock, flags);
+	return ret;
 }
 EXPORT_SYMBOL(clk_set_rate);
 
@@ -159,16 +249,49 @@
 {
 	if (clk == NULL || IS_ERR(clk))
 		return -EINVAL;
+	clk = source_clk(clk);
 	return clk->ops->set_flags(clk->id, flags);
 }
 EXPORT_SYMBOL(clk_set_flags);
 
-/* EBI1 is the only shared clock that several clients want to vote on as of
- * this commit. If this changes in the future, then it might be better to
- * make clk_min_rate handle the voting or make ebi1_clk_set_min_rate more
- * generic to support different clocks.
- */
-static struct clk *ebi1_clk;
+void clk_enter_sleep(int from_idle)
+{
+}
+
+void clk_exit_sleep(void)
+{
+}
+
+int clks_print_running(void)
+{
+	struct clk *clk;
+	int clk_on_count = 0;
+	struct hlist_node *pos;
+	char buf[100];
+	char *pbuf = buf;
+	int size = sizeof(buf);
+	int wr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&clocks_lock, flags);
+
+	hlist_for_each_entry(clk, pos, &clocks, list) {
+		if (clk->count) {
+			clk_on_count++;
+			wr = snprintf(pbuf, size, " %s", clk->name);
+			if (wr >= size)
+				break;
+			pbuf += wr;
+			size -= wr;
+		}
+	}
+	if (clk_on_count)
+		pr_info("clocks on:%s\n", buf);
+
+	spin_unlock_irqrestore(&clocks_lock, flags);
+	return !clk_on_count;
+}
+EXPORT_SYMBOL(clks_print_running);
 
 static void __init set_clock_ops(struct clk *clk)
 {
@@ -188,13 +311,9 @@
 	msm_num_clocks = num_clocks;
 	for (n = 0; n < msm_num_clocks; n++) {
 		set_clock_ops(&msm_clocks[n]);
-		list_add_tail(&msm_clocks[n].list, &clocks);
+		hlist_add_head(&msm_clocks[n].list, &clocks);
 	}
 	mutex_unlock(&clocks_mutex);
-
-	ebi1_clk = clk_get(NULL, "ebi1_clk");
-	BUG_ON(ebi1_clk == NULL);
-
 }
 
 #if defined(CONFIG_DEBUG_FS)
@@ -263,6 +382,75 @@
 	return 0;
 }
 
+static void *clk_info_seq_start(struct seq_file *seq, loff_t *ppos)
+{
+	struct hlist_node *pos;
+	int i = *ppos;
+	mutex_lock(&clocks_mutex);
+	hlist_for_each(pos, &clocks)
+		if (i-- == 0)
+			return hlist_entry(pos, struct clk, list);
+	return NULL;
+}
+
+static void *clk_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct clk *clk = v;
+	++*pos;
+	return hlist_entry(clk->list.next, struct clk, list);
+}
+
+static void clk_info_seq_stop(struct seq_file *seq, void *v)
+{
+	mutex_unlock(&clocks_mutex);
+}
+
+static int clk_info_seq_show(struct seq_file *seq, void *v)
+{
+	struct clk *clk = v;
+	unsigned long flags;
+	struct clk_handle *clkh;
+	struct hlist_node *pos;
+
+	seq_printf(seq, "Clock %s\n", clk->name);
+	seq_printf(seq, "  Id          %d\n", clk->id);
+	seq_printf(seq, "  Count       %d\n", clk->count);
+	seq_printf(seq, "  Flags       %x\n", clk->flags);
+	seq_printf(seq, "  Dev         %p %s\n",
+			clk->dev, clk->dev ? dev_name(clk->dev) : "");
+	seq_printf(seq, "  Handles     %p\n", clk->handles.first);
+	spin_lock_irqsave(&clocks_lock, flags);
+	hlist_for_each_entry(clkh, pos, &clk->handles, clk.list)
+		seq_printf(seq, "    Requested rate    %ld\n", clkh->rate);
+	spin_unlock_irqrestore(&clocks_lock, flags);
+
+	seq_printf(seq, "  Enabled     %d\n", clk->ops->is_enabled(clk->id));
+	seq_printf(seq, "  Rate        %ld\n", clk_get_rate(clk));
+
+	seq_printf(seq, "\n");
+	return 0;
+}
+
+static struct seq_operations clk_info_seqops = {
+	.start = clk_info_seq_start,
+	.next = clk_info_seq_next,
+	.stop = clk_info_seq_stop,
+	.show = clk_info_seq_show,
+};
+
+static int clk_info_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &clk_info_seqops);
+}
+
+static const struct file_operations clk_info_fops = {
+	.owner = THIS_MODULE,
+	.open = clk_info_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
 DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get,
 			clock_debug_rate_set, "%llu\n");
 DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get,
@@ -274,7 +462,7 @@
 {
 	struct dentry *dent_rate, *dent_enable, *dent_local;
 	struct clk *clock;
-	unsigned n = 0;
+	struct hlist_node *pos;
 	char temp[50], *ptr;
 
 	dent_rate = debugfs_create_dir("clk_rate", 0);
@@ -289,7 +477,10 @@
 	if (IS_ERR(dent_local))
 		return PTR_ERR(dent_local);
 
-	while ((clock = msm_clock_get_nth(n++)) != 0) {
+	debugfs_create_file("clk_info", 0x444, 0, NULL, &clk_info_fops);
+
+	mutex_lock(&clocks_mutex);
+	hlist_for_each_entry(clock, pos, &clocks, list) {
 		strncpy(temp, clock->dbg_name, ARRAY_SIZE(temp)-1);
 		for (ptr = temp; *ptr; ptr++)
 			*ptr = tolower(*ptr);
@@ -300,10 +491,11 @@
 		debugfs_create_file(temp, S_IRUGO, dent_local,
 				    clock, &clock_local_fops);
 	}
+	mutex_unlock(&clocks_mutex);
 	return 0;
 }
 
-device_initcall(clock_debug_init);
+late_initcall(clock_debug_init);
 #endif
 
 /* The bootloader and/or AMSS may have left various clocks enabled.
@@ -314,10 +506,11 @@
 {
 	unsigned long flags;
 	struct clk *clk;
+	struct hlist_node *pos;
 	unsigned count = 0;
 
 	mutex_lock(&clocks_mutex);
-	list_for_each_entry(clk, &clocks, list) {
+	hlist_for_each_entry(clk, pos, &clocks, list) {
 		if (clk->flags & CLKFLAG_AUTO_OFF) {
 			spin_lock_irqsave(&clocks_lock, flags);
 			if (!clk->count) {
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index c270b55..10d9458 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -27,11 +27,13 @@
 #define CLKFLAG_NOINVERT		0x00000002
 #define CLKFLAG_NONEST			0x00000004
 #define CLKFLAG_NORESET			0x00000008
+#define CLKFLAG_HANDLE			0x00000010
 
 #define CLK_FIRST_AVAILABLE_FLAG	0x00000100
 #define CLKFLAG_AUTO_OFF		0x00000200
 #define CLKFLAG_MIN			0x00000400
 #define CLKFLAG_MAX			0x00000800
+#define CLKFLAG_SHARED			0x00001000
 
 struct clk_ops {
 	int (*enable)(unsigned id);
@@ -55,8 +57,15 @@
 	const char *name;
 	struct clk_ops *ops;
 	const char *dbg_name;
-	struct list_head list;
+	struct hlist_node list;
 	struct device *dev;
+	struct hlist_head handles;
+};
+
+struct clk_handle {
+	struct clk clk;
+	struct clk *source;
+	unsigned long rate;
 };
 
 #define A11S_CLK_CNTL_ADDR		(MSM_CSR_BASE + 0x100)
@@ -105,5 +114,8 @@
 int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate);
 unsigned long clk_get_max_axi_khz(void);
 
+void clk_enter_sleep(int from_idle);
+void clk_exit_sleep(void);
+
 #endif
 
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
new file mode 100644
index 0000000..aaa30bb
--- /dev/null
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -0,0 +1,119 @@
+/* arch/arm/mach-msm/cpufreq.c
+ *
+ * MSM architecture cpufreq driver
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007 QUALCOMM Incorporated
+ * Author: Mike A. Chan <mikechan@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/cpufreq.h>
+#include <linux/earlysuspend.h>
+#include <linux/init.h>
+#include "acpuclock.h"
+
+#ifdef CONFIG_MSM_CPU_FREQ_SCREEN
+static void msm_early_suspend(struct early_suspend *handler) {
+	acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_OFF * 1000, 0);
+}
+
+static void msm_late_resume(struct early_suspend *handler) {
+	acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_ON * 1000, 0);
+}
+
+static struct early_suspend msm_power_suspend = {
+	.suspend = msm_early_suspend,
+	.resume = msm_late_resume,
+};
+
+static int __init clock_late_init(void)
+{
+	register_early_suspend(&msm_power_suspend);
+	return 0;
+}
+
+late_initcall(clock_late_init);
+#else
+
+static int msm_cpufreq_target(struct cpufreq_policy *policy,
+				unsigned int target_freq,
+				unsigned int relation)
+{
+	int index;
+	struct cpufreq_freqs freqs;
+	struct cpufreq_frequency_table *table =
+		cpufreq_frequency_get_table(policy->cpu);
+
+	if (cpufreq_frequency_table_target(policy, table, target_freq, relation,
+			&index)) {
+		pr_err("cpufreq: invalid target_freq: %d\n", target_freq);
+		return -EINVAL;
+	}
+
+	if (policy->cur == table[index].frequency)
+		return 0;
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+	printk("msm_cpufreq_target %d r %d (%d-%d) selected %d\n", target_freq,
+		relation, policy->min, policy->max, table[index].frequency);
+#endif
+	freqs.old = policy->cur;
+	freqs.new = table[index].frequency;
+	freqs.cpu = policy->cpu;
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	acpuclk_set_rate(table[index].frequency * 1000, 0);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	return 0;
+}
+
+static int msm_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+			policy->cpuinfo.max_freq);
+	return 0;
+}
+
+static int msm_cpufreq_init(struct cpufreq_policy *policy)
+{
+	struct cpufreq_frequency_table *table =
+		cpufreq_frequency_get_table(policy->cpu);
+
+	BUG_ON(cpufreq_frequency_table_cpuinfo(policy, table));
+	policy->cur = acpuclk_get_rate();
+	policy->cpuinfo.transition_latency =
+		acpuclk_get_switch_time() * NSEC_PER_USEC;
+	return 0;
+}
+
+static struct freq_attr *msm_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver msm_cpufreq_driver = {
+	/* lps calculations are handled here. */
+	.flags		= CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS,
+	.init		= msm_cpufreq_init,
+	.verify		= msm_cpufreq_verify,
+	.target		= msm_cpufreq_target,
+	.name		= "msm",
+	.attr		= msm_cpufreq_attr,
+};
+
+static int __init msm_cpufreq_register(void)
+{
+	return cpufreq_register_driver(&msm_cpufreq_driver);
+}
+
+device_initcall(msm_cpufreq_register);
+#endif
diff --git a/arch/arm/mach-msm/dal.c b/arch/arm/mach-msm/dal.c
new file mode 100644
index 0000000..7d37efc
--- /dev/null
+++ b/arch/arm/mach-msm/dal.c
@@ -0,0 +1,603 @@
+/* arch/arm/mach-msm/qdsp6/dal.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/slab.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+
+#include <linux/delay.h>
+
+#include <mach/msm_smd.h>
+#include <mach/msm_qdsp6_audio.h>
+
+#include "dal.h"
+
+#define DAL_TRACE 0
+
+struct dal_hdr {
+	uint32_t length:16;	/* message length (header inclusive) */
+	uint32_t version:8;	/* DAL protocol version */
+	uint32_t priority:7;
+	uint32_t async:1;
+	uint32_t ddi:16;	/* DDI method number */
+	uint32_t prototype:8;	/* DDI serialization format */
+	uint32_t msgid:8;	/* message id (DDI, ATTACH, DETACH, ...) */
+	void *from;
+	void *to;
+} __attribute__((packed));
+
+#define TRACE_DATA_MAX	128
+#define TRACE_LOG_MAX	32
+#define TRACE_LOG_MASK	(TRACE_LOG_MAX - 1)
+
+struct dal_trace {
+	unsigned timestamp;
+	struct dal_hdr hdr;
+	uint32_t data[TRACE_DATA_MAX];
+};
+
+#define DAL_HDR_SIZE		(sizeof(struct dal_hdr))
+#define DAL_DATA_MAX		512
+#define DAL_MSG_MAX		(DAL_HDR_SIZE + DAL_DATA_MAX)
+
+#define DAL_VERSION		0x11
+
+#define DAL_MSGID_DDI		0x00
+#define DAL_MSGID_ATTACH	0x01
+#define DAL_MSGID_DETACH	0x02
+#define DAL_MSGID_ASYNCH	0xC0
+#define DAL_MSGID_REPLY		0x80
+
+struct dal_channel {
+	struct list_head list;
+	struct list_head clients;
+
+	/* synchronization for changing channel state,
+	 * adding/removing clients, smd callbacks, etc
+	 */
+	spinlock_t lock;
+
+	struct smd_channel *sch;
+	char *name;
+
+	/* events are delivered at IRQ context immediately, so
+	 * we only need one assembly buffer for the entire channel
+	 */
+	struct dal_hdr hdr;
+	unsigned char data[DAL_DATA_MAX];
+
+	unsigned count;
+	void *ptr;
+
+	/* client which the current inbound message is for */
+	struct dal_client *active;
+};
+
+struct dal_client {
+	struct list_head list;
+	struct dal_channel *dch;
+	void *cookie;
+	dal_event_func_t event;
+
+	/* opaque handle for the far side */
+	void *remote;
+
+	/* dal rpc calls are fully synchronous -- only one call may be
+	 * active per client at a time
+	 */
+	struct mutex write_lock;
+	wait_queue_head_t wait;
+
+	unsigned char data[DAL_DATA_MAX];
+
+	void *reply;
+	int reply_max;
+	int status;
+	unsigned msgid; /* msgid of expected reply */
+
+	spinlock_t tr_lock;
+	unsigned tr_head;
+	unsigned tr_tail;
+	struct dal_trace *tr_log;
+};
+
+static unsigned now(void)
+{
+	struct timespec ts;
+	ktime_get_ts(&ts);
+	return (ts.tv_nsec / 1000000) + (ts.tv_sec * 1000);
+}
+
+void dal_trace(struct dal_client *c)
+{
+	if (c->tr_log)
+		return;
+	c->tr_log = kzalloc(sizeof(struct dal_trace) * TRACE_LOG_MAX,
+			    GFP_KERNEL);
+}
+
+void dal_trace_print(struct dal_hdr *hdr, unsigned *data, int len, unsigned when)
+{
+	int i;
+	printk("DAL %08x -> %08x L=%03x A=%d D=%04x P=%02x M=%02x T=%d",
+	       (unsigned) hdr->from, (unsigned) hdr->to,
+	       hdr->length, hdr->async,
+	       hdr->ddi, hdr->prototype, hdr->msgid,
+	       when);
+	len /= 4;
+	for (i = 0; i < len; i++) {
+		if (!(i & 7))
+			printk("\n%03x", i * 4);
+		printk(" %08x", data[i]);
+	}
+	printk("\n");
+}
+
+void dal_trace_dump(struct dal_client *c)
+{
+	struct dal_trace *dt;
+	unsigned n, len;
+
+	if (!c->tr_log)
+		return;
+
+	for (n = c->tr_tail; n != c->tr_head; n = (n + 1) & TRACE_LOG_MASK) {
+		dt = c->tr_log + n;
+		len = dt->hdr.length - sizeof(dt->hdr);
+		if (len > TRACE_DATA_MAX)
+			len = TRACE_DATA_MAX;
+		dal_trace_print(&dt->hdr, dt->data, len, dt->timestamp);
+	}
+}
+
+static void dal_trace_log(struct dal_client *c,
+			  struct dal_hdr *hdr, void *data, unsigned len)
+{
+	unsigned long flags;
+	unsigned t, n;
+	struct dal_trace *dt;
+
+	t = now();
+	if (len > TRACE_DATA_MAX)
+		len = TRACE_DATA_MAX;
+
+	spin_lock_irqsave(&c->tr_lock, flags);
+	n = (c->tr_head + 1) & TRACE_LOG_MASK;
+	if (c->tr_tail == n)
+		c->tr_tail = (c->tr_tail + 1) & TRACE_LOG_MASK;
+	dt = c->tr_log + n;
+	dt->timestamp = t;
+	memcpy(&dt->hdr, hdr, sizeof(struct dal_hdr));
+	memcpy(dt->data, data, len);
+	c->tr_head = n;
+
+	spin_unlock_irqrestore(&c->tr_lock, flags);
+}
+
+
+static void dal_channel_notify(void *priv, unsigned event)
+{
+	struct dal_channel *dch = priv;
+	struct dal_hdr *hdr = &dch->hdr;
+	struct dal_client *client;
+	unsigned long flags;
+	int len;
+	int r;
+
+	spin_lock_irqsave(&dch->lock, flags);
+
+again:
+	if (dch->count == 0) {
+		if (smd_read_avail(dch->sch) < DAL_HDR_SIZE)
+			goto done;
+
+		smd_read(dch->sch, hdr, DAL_HDR_SIZE);
+
+		if (hdr->length < DAL_HDR_SIZE)
+			goto done;
+
+		if (hdr->length > DAL_MSG_MAX)
+			panic("oversize message");
+
+		dch->count = hdr->length - DAL_HDR_SIZE;
+
+		/* locate the client this message is targeted to */
+		list_for_each_entry(client, &dch->clients, list) {
+			if (dch->hdr.to == client) {
+				dch->active = client;
+				dch->ptr = client->data;
+				goto check_data;
+			}
+		}
+		pr_err("$$$ receiving unknown message len = %d $$$\n",
+		       dch->count);
+		dch->active = 0;
+		dch->ptr = dch->data;
+	}
+
+check_data:
+	len = dch->count;
+	if (len > 0) {
+		if (smd_read_avail(dch->sch) < len)
+			goto done;
+
+		r = smd_read(dch->sch, dch->ptr, len);
+		if (r != len)
+			panic("invalid read");
+
+#if DAL_TRACE
+		pr_info("dal recv %p <- %p %02x:%04x:%02x %d\n",
+			hdr->to, hdr->from, hdr->msgid, hdr->ddi,
+			hdr->prototype, hdr->length - sizeof(*hdr));
+		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, dch->ptr, len);
+#endif
+		dch->count = 0;
+
+		client = dch->active;
+		if (!client) {
+			pr_err("dal: message to %p discarded\n", dch->hdr.to);
+			goto again;
+		}
+
+		if (client->tr_log)
+			dal_trace_log(client, hdr, dch->ptr, len);
+
+		if (hdr->msgid == DAL_MSGID_ASYNCH) {
+			if (client->event)
+				client->event(dch->ptr, len, client->cookie);
+			else
+				pr_err("dal: client %p has no event handler\n",
+				       client);
+			goto again;
+		}
+
+		if (hdr->msgid == client->msgid) {
+			if (!client->remote)
+				client->remote = hdr->from;
+			if (len > client->reply_max)
+				len = client->reply_max;
+			memcpy(client->reply, client->data, len);
+			client->status = len;
+			wake_up(&client->wait);
+			goto again;
+		}
+
+		pr_err("dal: cannot find client %p\n", dch->hdr.to);
+		goto again;
+	}
+
+done:
+	spin_unlock_irqrestore(&dch->lock, flags);
+}
+
+static LIST_HEAD(dal_channel_list);
+static DEFINE_MUTEX(dal_channel_list_lock);
+
+static struct dal_channel *dal_open_channel(const char *name)
+{
+	struct dal_channel *dch;
+
+	/* quick sanity check to avoid trying to talk to
+	 * some non-DAL channel...
+	 */
+	if (strncmp(name, "DSP_DAL", 7) && strncmp(name, "SMD_DAL", 7))
+		return 0;
+
+	mutex_lock(&dal_channel_list_lock);
+
+	list_for_each_entry(dch, &dal_channel_list, list) {
+		if (!strcmp(dch->name, name))
+			goto found_it;
+	}
+
+	dch = kzalloc(sizeof(*dch) + strlen(name) + 1, GFP_KERNEL);
+	if (!dch)
+		goto fail;
+
+	dch->name = (char *) (dch + 1);
+	strcpy(dch->name, name);
+	spin_lock_init(&dch->lock);
+	INIT_LIST_HEAD(&dch->clients);
+
+	list_add(&dch->list, &dal_channel_list);
+
+found_it:
+	if (!dch->sch) {
+		if (smd_open(name, &dch->sch, dch, dal_channel_notify))
+			dch = NULL;
+		/* FIXME: wait for channel to open before returning */
+		msleep(100);
+	}
+
+fail:
+	mutex_unlock(&dal_channel_list_lock);
+
+	return dch;
+}
+
+int dal_call_raw(struct dal_client *client,
+		 struct dal_hdr *hdr,
+		 void *data, int data_len,
+		 void *reply, int reply_max)
+{
+	struct dal_channel *dch = client->dch;
+	unsigned long flags;
+
+	client->reply = reply;
+	client->reply_max = reply_max;
+	client->msgid = hdr->msgid | DAL_MSGID_REPLY;
+	client->status = -EBUSY;
+
+#if DAL_TRACE
+	pr_info("dal send %p -> %p %02x:%04x:%02x %d\n",
+		hdr->from, hdr->to, hdr->msgid, hdr->ddi,
+		hdr->prototype, hdr->length - sizeof(*hdr));
+	print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data, data_len);
+#endif
+
+	if (client->tr_log)
+		dal_trace_log(client, hdr, data, data_len);
+
+	spin_lock_irqsave(&dch->lock, flags);
+	/* FIXME: ensure entire message is written or none. */
+	smd_write(dch->sch, hdr, sizeof(*hdr));
+	smd_write(dch->sch, data, data_len);
+	spin_unlock_irqrestore(&dch->lock, flags);
+
+	if (!wait_event_timeout(client->wait, (client->status != -EBUSY), 5*HZ)) {
+		dal_trace_dump(client);
+		pr_err("dal: call timed out. dsp is probably dead.\n");
+		dal_trace_print(hdr, data, data_len, 0);
+#if defined(CONFIG_MSM_QDSP6)
+		q6audio_dsp_not_responding();
+#endif
+	}
+
+	return client->status;
+}
+
+int dal_call(struct dal_client *client,
+	     unsigned ddi, unsigned prototype,
+	     void *data, int data_len,
+	     void *reply, int reply_max)
+{
+	struct dal_hdr hdr;
+	int r;
+
+	memset(&hdr, 0, sizeof(hdr));
+
+	hdr.length = data_len + sizeof(hdr);
+	hdr.version = DAL_VERSION;
+	hdr.msgid = DAL_MSGID_DDI;
+	hdr.ddi = ddi;
+	hdr.prototype = prototype;
+	hdr.from = client;
+	hdr.to = client->remote;
+
+	if (hdr.length > DAL_MSG_MAX)
+		return -EINVAL;
+
+	mutex_lock(&client->write_lock);
+	r = dal_call_raw(client, &hdr, data, data_len, reply, reply_max);
+	mutex_unlock(&client->write_lock);
+#if 0
+	if ((r > 3) && (((uint32_t*) reply)[0] == 0)) {
+		pr_info("dal call OK\n");
+	} else {
+		pr_info("dal call ERROR\n");
+	}
+#endif
+	return r;
+}
+
+struct dal_msg_attach {
+	uint32_t device_id;
+	char attach[64];
+	char service_name[32];
+} __attribute__((packed));
+
+struct dal_reply_attach {
+	uint32_t status;
+	char name[64];
+};
+
+struct dal_client *dal_attach(uint32_t device_id, const char *name,
+			      dal_event_func_t func, void *cookie)
+{
+	struct dal_hdr hdr;
+	struct dal_msg_attach msg;
+	struct dal_reply_attach reply;
+	struct dal_channel *dch;
+	struct dal_client *client;
+	unsigned long flags;
+	int r;
+
+	dch = dal_open_channel(name);
+	if (!dch)
+		return 0;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return 0;
+
+	client->dch = dch;
+	client->event = func;
+	client->cookie = cookie;
+	mutex_init(&client->write_lock);
+	spin_lock_init(&client->tr_lock);
+	init_waitqueue_head(&client->wait);
+
+	spin_lock_irqsave(&dch->lock, flags);
+	list_add(&client->list, &dch->clients);
+	spin_unlock_irqrestore(&dch->lock, flags);
+
+	memset(&hdr, 0, sizeof(hdr));
+	memset(&msg, 0, sizeof(msg));
+
+	hdr.length = sizeof(hdr) + sizeof(msg);
+	hdr.version = DAL_VERSION;
+	hdr.msgid = DAL_MSGID_ATTACH;
+	hdr.from = client;
+	msg.device_id = device_id;
+
+	r = dal_call_raw(client, &hdr, &msg, sizeof(msg),
+			 &reply, sizeof(reply));
+
+	if ((r == sizeof(reply)) && (reply.status == 0)) {
+		reply.name[63] = 0;
+		pr_info("dal_attach: status = %d, name = '%s'\n",
+			reply.status, reply.name);
+		return client;
+	}
+
+	pr_err("dal_attach: failure\n");
+
+	dal_detach(client);
+	return 0;
+}
+
+int dal_detach(struct dal_client *client)
+{
+	struct dal_channel *dch;
+	unsigned long flags;
+
+	mutex_lock(&client->write_lock);
+	if (client->remote) {
+		struct dal_hdr hdr;
+		uint32_t data;
+
+		memset(&hdr, 0, sizeof(hdr));
+		hdr.length = sizeof(hdr) + sizeof(data);
+		hdr.version = DAL_VERSION;
+		hdr.msgid = DAL_MSGID_DETACH;
+		hdr.from = client;
+		hdr.to = client->remote;
+		data = (uint32_t) client;
+
+		dal_call_raw(client, &hdr, &data, sizeof(data),
+			     &data, sizeof(data));
+	}
+
+	dch = client->dch;
+	spin_lock_irqsave(&dch->lock, flags);
+	if (dch->active == client) {
+		/* We have received a message header for this client
+		 * but not the body of the message.  Ensure that when
+		 * the body arrives we don't write it into the now-closed
+		 * client.  In *theory* this should never happen.
+		 */
+		dch->active = 0;
+		dch->ptr = dch->data;
+	}
+	list_del(&client->list);
+	spin_unlock_irqrestore(&dch->lock, flags);
+
+	mutex_unlock(&client->write_lock);
+
+	kfree(client);
+	return 0;
+}
+
+void *dal_get_remote_handle(struct dal_client *client)
+{
+	return client->remote;
+}
+
+/* convenience wrappers */
+
+int dal_call_f0(struct dal_client *client, uint32_t ddi, uint32_t arg1)
+{
+	uint32_t tmp = arg1;
+	int res;
+	res = dal_call(client, ddi, 0, &tmp, sizeof(tmp), &tmp, sizeof(tmp));
+	if (res >= 4)
+		return (int) tmp;
+	return res;
+}
+
+int dal_call_f1(struct dal_client *client, uint32_t ddi, uint32_t arg1, uint32_t arg2)
+{
+	uint32_t tmp[2];
+	int res;
+	tmp[0] = arg1;
+	tmp[1] = arg2;
+	res = dal_call(client, ddi, 1, tmp, sizeof(tmp), tmp, sizeof(uint32_t));
+	if (res >= 4)
+		return (int) tmp[0];
+	return res;
+}
+
+int dal_call_f5(struct dal_client *client, uint32_t ddi, void *ibuf, uint32_t ilen)
+{
+	uint32_t tmp[128];
+	int res;
+	int param_idx = 0;
+
+	if (ilen + 4 > DAL_DATA_MAX)
+		return -EINVAL;
+
+	tmp[param_idx] = ilen;
+	param_idx++;
+
+	memcpy(&tmp[param_idx], ibuf, ilen);
+	param_idx += DIV_ROUND_UP(ilen, 4);
+
+	res = dal_call(client, ddi, 5, tmp, param_idx * 4, tmp, sizeof(tmp));
+
+	if (res >= 4)
+		return (int) tmp[0];
+	return res;
+}
+
+int dal_call_f13(struct dal_client *client, uint32_t ddi, void *ibuf1,
+		 uint32_t ilen1, void *ibuf2, uint32_t ilen2, void *obuf,
+		 uint32_t olen)
+{
+	uint32_t tmp[128];
+	int res;
+	int param_idx = 0;
+
+	if (ilen1 + ilen2 + 8 > DAL_DATA_MAX)
+		return -EINVAL;
+
+	tmp[param_idx] = ilen1;
+	param_idx++;
+
+	memcpy(&tmp[param_idx], ibuf1, ilen1);
+	param_idx += DIV_ROUND_UP(ilen1, 4);
+
+	tmp[param_idx++] = ilen2;
+	memcpy(&tmp[param_idx], ibuf2, ilen2);
+	param_idx += DIV_ROUND_UP(ilen2, 4);
+
+	tmp[param_idx++] = olen;
+	res = dal_call(client, ddi, 13, tmp, param_idx * 4, tmp, sizeof(tmp));
+
+	if (res >= 4)
+		res = (int)tmp[0];
+
+	if (!res) {
+		if (tmp[1] > olen)
+			return -EIO;
+		memcpy(obuf, &tmp[2], tmp[1]);
+	}
+	return res;
+}
diff --git a/arch/arm/mach-msm/dal.h b/arch/arm/mach-msm/dal.h
new file mode 100644
index 0000000..c02f5c7
--- /dev/null
+++ b/arch/arm/mach-msm/dal.h
@@ -0,0 +1,65 @@
+/* arch/arm/mach-msm/qdsp6/dal.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MACH_MSM_DAL_
+#define _MACH_MSM_DAL_
+
+struct dal_client;
+
+typedef void (*dal_event_func_t)(void *data, int len, void *cookie);
+
+struct dal_client *dal_attach(uint32_t device_id, const char *name,
+			      dal_event_func_t func, void *cookie);
+
+int dal_detach(struct dal_client *client);
+
+int dal_call(struct dal_client *client,
+	     unsigned ddi, unsigned prototype,
+	     void *data, int data_len,
+	     void *reply, int reply_max);
+
+void dal_trace(struct dal_client *client);
+void dal_trace_dump(struct dal_client *client);
+
+/* function to call before panic on stalled dal calls */
+void dal_set_oops(struct dal_client *client, void (*oops)(void));
+
+/* convenience wrappers */
+int dal_call_f0(struct dal_client *client, uint32_t ddi,
+		uint32_t arg1);
+int dal_call_f1(struct dal_client *client, uint32_t ddi,
+		uint32_t arg1, uint32_t arg2);
+int dal_call_f5(struct dal_client *client, uint32_t ddi,
+		void *ibuf, uint32_t ilen);
+int dal_call_f13(struct dal_client *client, uint32_t ddi, void *ibuf1,
+		 uint32_t ilen1, void *ibuf2, uint32_t ilen2, void *obuf,
+		 uint32_t olen);
+
+/* common DAL operations */
+enum {
+	DAL_OP_ATTACH = 0,
+	DAL_OP_DETACH,
+	DAL_OP_INIT,
+	DAL_OP_DEINIT,
+	DAL_OP_OPEN,
+	DAL_OP_CLOSE,
+	DAL_OP_INFO,
+	DAL_OP_POWEREVENT,
+	DAL_OP_SYSREQUEST,
+	DAL_OP_FIRST_DEVICE_API,
+};
+
+#endif
diff --git a/arch/arm/mach-msm/devices-msm7x00.c b/arch/arm/mach-msm/devices-msm7x00.c
index fde9d8f..a49c3ff 100644
--- a/arch/arm/mach-msm/devices-msm7x00.c
+++ b/arch/arm/mach-msm/devices-msm7x00.c
@@ -15,10 +15,14 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
 
 #include <mach/irqs.h>
 #include <mach/msm_iomap.h>
+#include <mach/dma.h>
 #include "devices.h"
+#include "proc_comm.h"
 
 #include <asm/mach/flash.h>
 #include <linux/mtd/nand.h>
@@ -88,6 +92,92 @@
 	.resource	= resources_uart3,
 };
 
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start = MSM_UART1DM_PHYS,
+		.end   = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART1DM_IRQ,
+		.end   = INT_UART1DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART1DM_RX,
+		.end   = INT_UART1DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CHAN,
+		.end   = DMOV_HSUART1_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CRCI,
+		.end   = DMOV_HSUART1_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm1 = {
+	.name = "msm_serial_hs",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource = msm_uart1_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm_uart2_dm_resources[] = {
+	{
+		.start = MSM_UART2DM_PHYS,
+		.end   = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART2DM_IRQ,
+		.end   = INT_UART2DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART2DM_RX,
+		.end   = INT_UART2DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CHAN,
+		.end   = DMOV_HSUART2_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CRCI,
+		.end   = DMOV_HSUART2_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm2_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm2 = {
+	.name = "msm_serial_hs",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(msm_uart2_dm_resources),
+	.resource = msm_uart2_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm2_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
 static struct resource resources_i2c[] = {
 	{
 		.start	= MSM_I2C_PHYS,
@@ -108,6 +198,30 @@
 	.resource	= resources_i2c,
 };
 
+#define GPIO_I2C_CLK 60
+#define GPIO_I2C_DAT 61
+void msm_set_i2c_mux(bool gpio, int *gpio_clk, int *gpio_dat)
+{
+	unsigned id;
+	if (gpio) {
+		id = PCOM_GPIO_CFG(GPIO_I2C_CLK, 0, GPIO_OUTPUT,
+				   GPIO_NO_PULL, GPIO_2MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		id = PCOM_GPIO_CFG(GPIO_I2C_DAT, 0, GPIO_OUTPUT,
+				   GPIO_NO_PULL, GPIO_2MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		*gpio_clk = GPIO_I2C_CLK;
+		*gpio_dat = GPIO_I2C_DAT;
+	} else {
+		id = PCOM_GPIO_CFG(GPIO_I2C_CLK, 1, GPIO_INPUT,
+				   GPIO_NO_PULL, GPIO_8MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		id = PCOM_GPIO_CFG(GPIO_I2C_DAT , 1, GPIO_INPUT,
+				   GPIO_NO_PULL, GPIO_8MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
 static struct resource resources_hsusb[] = {
 	{
 		.start	= MSM_HSUSB_PHYS,
@@ -346,24 +460,119 @@
 	return platform_device_register(pdev);
 }
 
+static struct resource resources_mddi0[] = {
+	{
+		.start	= MSM_PMDH_PHYS,
+		.end	= MSM_PMDH_PHYS + MSM_PMDH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_MDDI_PRI,
+		.end	= INT_MDDI_PRI,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource resources_mddi1[] = {
+	{
+		.start	= MSM_EMDH_PHYS,
+		.end	= MSM_EMDH_PHYS + MSM_EMDH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_MDDI_EXT,
+		.end	= INT_MDDI_EXT,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_mddi0 = {
+	.name = "msm_mddi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_mddi0),
+	.resource = resources_mddi0,
+	.dev = {
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_mddi1 = {
+	.name = "msm_mddi",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(resources_mddi1),
+	.resource = resources_mddi1,
+	.dev = {
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+static struct resource resources_mdp[] = {
+	{
+		.start	= MSM_MDP_PHYS,
+		.end	= MSM_MDP_PHYS + MSM_MDP_SIZE - 1,
+		.name	= "mdp",
+		.flags	= IORESOURCE_MEM
+	},
+	{
+		.start	= INT_MDP,
+		.end	= INT_MDP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_mdp = {
+	.name = "msm_mdp",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_mdp),
+	.resource = resources_mdp,
+};
+
+static struct resource resources_tssc[] = {
+	{
+		.start	= MSM_TSSC_PHYS,
+		.end	= MSM_TSSC_PHYS + MSM_TSSC_SIZE - 1,
+		.name	= "tssc",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_TCHSCRN1,
+		.end	= INT_TCHSCRN1,
+		.name	= "tssc1",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+	{
+		.start	= INT_TCHSCRN2,
+		.end	= INT_TCHSCRN2,
+		.name	= "tssc2",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+};
+
+struct platform_device msm_device_touchscreen = {
+	.name = "msm_touchscreen",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_tssc),
+	.resource = resources_tssc,
+};
+
 struct clk msm_clocks_7x01a[] = {
 	CLK_PCOM("adm_clk",	ADM_CLK,	NULL, 0),
 	CLK_PCOM("adsp_clk",	ADSP_CLK,	NULL, 0),
-	CLK_PCOM("ebi1_clk",	EBI1_CLK,	NULL, 0),
+	CLK_PCOM("ebi1_clk",	EBI1_CLK,	NULL, CLK_MIN),
 	CLK_PCOM("ebi2_clk",	EBI2_CLK,	NULL, 0),
 	CLK_PCOM("ecodec_clk",	ECODEC_CLK,	NULL, 0),
-	CLK_PCOM("emdh_clk",	EMDH_CLK,	NULL, OFF),
-	CLK_PCOM("gp_clk",		GP_CLK,		NULL, 0),
+	CLK_PCOM("mddi_clk",	EMDH_CLK,	&msm_device_mddi1.dev, OFF),
+	CLK_PCOM("gp_clk",	GP_CLK,		NULL, 0),
 	CLK_PCOM("grp_clk",	GRP_3D_CLK,	NULL, OFF),
 	CLK_PCOM("i2c_clk",	I2C_CLK,	&msm_device_i2c.dev, 0),
 	CLK_PCOM("icodec_rx_clk",	ICODEC_RX_CLK,	NULL, 0),
 	CLK_PCOM("icodec_tx_clk",	ICODEC_TX_CLK,	NULL, 0),
 	CLK_PCOM("imem_clk",	IMEM_CLK,	NULL, OFF),
 	CLK_PCOM("mdc_clk",	MDC_CLK,	NULL, 0),
-	CLK_PCOM("mdp_clk",	MDP_CLK,	NULL, OFF),
+	CLK_PCOM("mdp_clk",	MDP_CLK,	&msm_device_mdp.dev, OFF),
 	CLK_PCOM("pbus_clk",	PBUS_CLK,	NULL, 0),
 	CLK_PCOM("pcm_clk",	PCM_CLK,	NULL, 0),
-	CLK_PCOM("pmdh_clk",	PMDH_CLK,	NULL, OFF ),
+	CLK_PCOM("mddi_clk",	PMDH_CLK,	&msm_device_mddi0.dev, OFF | CLK_MINMAX),
 	CLK_PCOM("sdac_clk",	SDAC_CLK,	NULL, OFF),
 	CLK_PCOM("sdc_clk",	SDC1_CLK,	&msm_device_sdc1.dev, OFF),
 	CLK_PCOM("sdc_pclk",	SDC1_P_CLK,	&msm_device_sdc1.dev, OFF),
@@ -378,14 +587,14 @@
 	CLK_PCOM("tv_dac_clk",	TV_DAC_CLK,	NULL, 0),
 	CLK_PCOM("tv_enc_clk",	TV_ENC_CLK,	NULL, 0),
 	CLK_PCOM("uart_clk",	UART1_CLK,	&msm_device_uart1.dev, OFF),
-	CLK_PCOM("uart_clk",	UART2_CLK,	&msm_device_uart2.dev, 0),
+	CLK_PCOM("uart_clk",	UART2_CLK,	&msm_device_uart2.dev, OFF),
 	CLK_PCOM("uart_clk",	UART3_CLK,	&msm_device_uart3.dev, OFF),
-	CLK_PCOM("uart1dm_clk",	UART1DM_CLK,	NULL, OFF),
-	CLK_PCOM("uart2dm_clk",	UART2DM_CLK,	NULL, 0),
+	CLK_PCOM("uartdm_clk",	UART1DM_CLK,	&msm_device_uart_dm1.dev, OFF),
+	CLK_PCOM("uartdm_clk",	UART2DM_CLK,	&msm_device_uart_dm2.dev, OFF),
 	CLK_PCOM("usb_hs_clk",	USB_HS_CLK,	&msm_device_hsusb.dev, OFF),
 	CLK_PCOM("usb_hs_pclk",	USB_HS_P_CLK,	&msm_device_hsusb.dev, OFF),
 	CLK_PCOM("usb_otg_clk",	USB_OTG_CLK,	NULL, 0),
-	CLK_PCOM("vdc_clk",	VDC_CLK,	NULL, OFF ),
+	CLK_PCOM("vdc_clk",	VDC_CLK,	NULL, OFF | CLK_MINMAX),
 	CLK_PCOM("vfe_clk",	VFE_CLK,	NULL, OFF),
 	CLK_PCOM("vfe_mdc_clk",	VFE_MDC_CLK,	NULL, OFF),
 };
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index b449e8a..995d966 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -23,6 +23,7 @@
 #include <mach/board.h>
 
 #include "devices.h"
+#include "proc_comm.h"
 #include "smd_private.h"
 
 #include <asm/mach/flash.h>
@@ -31,6 +32,19 @@
 
 #include <mach/mmc.h>
 
+static struct resource resources_uart1[] = {
+	{
+		.start	= INT_UART1,
+		.end	= INT_UART1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART1_PHYS,
+		.end	= MSM_UART1_PHYS + MSM_UART1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
 static struct resource resources_uart2[] = {
 	{
 		.start	= INT_UART2,
@@ -44,6 +58,26 @@
 	},
 };
 
+static struct resource resources_uart3[] = {
+	{
+		.start	= INT_UART3,
+		.end	= INT_UART3,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART3_PHYS,
+		.end	= MSM_UART3_PHYS + MSM_UART3_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_uart1 = {
+	.name	= "msm_serial",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart1),
+	.resource	= resources_uart1,
+};
+
 struct platform_device msm_device_uart2 = {
 	.name	= "msm_serial",
 	.id	= 1,
@@ -51,15 +85,585 @@
 	.resource	= resources_uart2,
 };
 
+struct platform_device msm_device_uart3 = {
+	.name	= "msm_serial",
+	.id	= 2,
+	.num_resources	= ARRAY_SIZE(resources_uart3),
+	.resource	= resources_uart3,
+};
+
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start = MSM_UART1DM_PHYS,
+		.end   = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART1DM_IRQ,
+		.end   = INT_UART1DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART1DM_RX,
+		.end   = INT_UART1DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CHAN,
+		.end   = DMOV_HSUART1_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CRCI,
+		.end   = DMOV_HSUART1_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm1 = {
+	.name = "msm_serial_hs",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource = msm_uart1_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm_uart2_dm_resources[] = {
+	{
+		.start = MSM_UART2DM_PHYS,
+		.end   = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART2DM_IRQ,
+		.end   = INT_UART2DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART2DM_RX,
+		.end   = INT_UART2DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CHAN,
+		.end   = DMOV_HSUART2_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CRCI,
+		.end   = DMOV_HSUART2_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm2_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm2 = {
+	.name = "msm_serial_hs",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(msm_uart2_dm_resources),
+	.resource = msm_uart2_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm2_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource resources_i2c[] = {
+	{
+		.start	= MSM_I2C_PHYS,
+		.end	= MSM_I2C_PHYS + MSM_I2C_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_PWB_I2C,
+		.end	= INT_PWB_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_i2c = {
+	.name		= "msm_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_i2c),
+	.resource	= resources_i2c,
+};
+
+#define GPIO_I2C_CLK 70
+#define GPIO_I2C_DAT 71
+void msm_set_i2c_mux(bool gpio, int *gpio_clk, int *gpio_dat)
+{
+	unsigned id;
+	if (gpio) {
+		id = PCOM_GPIO_CFG(GPIO_I2C_CLK, 0, GPIO_OUTPUT,
+				   GPIO_NO_PULL, GPIO_2MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		id = PCOM_GPIO_CFG(GPIO_I2C_DAT, 0, GPIO_OUTPUT,
+				   GPIO_NO_PULL, GPIO_2MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		*gpio_clk = GPIO_I2C_CLK;
+		*gpio_dat = GPIO_I2C_DAT;
+	} else {
+		id = PCOM_GPIO_CFG(GPIO_I2C_CLK, 1, GPIO_INPUT,
+				   GPIO_NO_PULL, GPIO_8MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		id = PCOM_GPIO_CFG(GPIO_I2C_DAT , 1, GPIO_INPUT,
+				   GPIO_NO_PULL, GPIO_8MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+static struct resource resources_i2c2[] = {
+	{
+		.start	= MSM_I2C_2_PHYS,
+		.end	= MSM_I2C_2_PHYS + MSM_I2C_2_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_PWB_I2C_2,
+		.end	= INT_PWB_I2C_2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_i2c2 = {
+	.name		= "msm_i2c",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_i2c2),
+	.resource	= resources_i2c2,
+};
+
+static struct resource resources_qup[] = {
+	{
+		.name   = "qup_phys_addr",
+		.start	= MSM_QUP_PHYS,
+		.end	= MSM_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI_QUP_I2C_PHYS,
+		.end	= MSM_GSBI_QUP_I2C_PHYS + MSM_GSBI_QUP_I2C_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "qup_in_intr",
+		.start	= INT_PWB_QUP_IN,
+		.end	= INT_PWB_QUP_IN,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "qup_out_intr",
+		.start	= INT_PWB_QUP_OUT,
+		.end	= INT_PWB_QUP_OUT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "qup_err_intr",
+		.start	= INT_PWB_QUP_ERR,
+		.end	= INT_PWB_QUP_ERR,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_qup_i2c = {
+	.name		= "qup_i2c",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_qup),
+	.resource	= resources_qup,
+};
+
+static struct resource resources_hsusb[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb),
+	.resource	= resources_hsusb,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct flash_platform_data msm_nand_data = {
+	.parts		= NULL,
+	.nr_parts	= 0,
+};
+
+static struct resource resources_nand[] = {
+	[0] = {
+		.start	= 7,
+		.end	= 7,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_nand = {
+	.name		= "msm_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_nand),
+	.resource	= resources_nand,
+	.dev		= {
+		.platform_data	= &msm_nand_data,
+	},
+};
+
+struct platform_device msm_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+};
+
+static struct resource resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_PHYS,
+		.end	= MSM_SDC1_PHYS + MSM_SDC1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC1_0,
+		.end	= INT_SDC1_0,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "cmd_irq",
+	},
+	{
+		.start	= INT_SDC1_1,
+		.end	= INT_SDC1_1,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "pio_irq",
+	},
+	{
+		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
+		.name	= "status_irq"
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.start	= MSM_SDC2_PHYS,
+		.end	= MSM_SDC2_PHYS + MSM_SDC2_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC2_0,
+		.end	= INT_SDC2_0,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "cmd_irq",
+	},
+		{
+		.start	= INT_SDC2_1,
+		.end	= INT_SDC2_1,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "pio_irq",
+	},
+	{
+		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
+		.name	= "status_irq"
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc3[] = {
+	{
+		.start	= MSM_SDC3_PHYS,
+		.end	= MSM_SDC3_PHYS + MSM_SDC3_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC3_0,
+		.end	= INT_SDC3_0,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "cmd_irq",
+	},
+		{
+		.start	= INT_SDC3_1,
+		.end	= INT_SDC3_1,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "pio_irq",
+	},
+	{
+		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
+		.name	= "status_irq"
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc4[] = {
+	{
+		.start	= MSM_SDC4_PHYS,
+		.end	= MSM_SDC4_PHYS + MSM_SDC4_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC4_0,
+		.end	= INT_SDC4_0,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "cmd_irq",
+	},
+		{
+		.start	= INT_SDC4_1,
+		.end	= INT_SDC4_1,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "pio_irq",
+	},
+	{
+		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
+		.name	= "status_irq"
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_sdc2),
+	.resource	= resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_sdc3),
+	.resource	= resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_sdc4),
+	.resource	= resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+	&msm_device_sdc2,
+	&msm_device_sdc3,
+	&msm_device_sdc4,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+			unsigned int stat_irq, unsigned long stat_irq_flags)
+{
+	struct platform_device	*pdev;
+	struct resource *res;
+
+	if (controller < 1 || controller > 4)
+		return -EINVAL;
+
+	pdev = msm_sdcc_devices[controller-1];
+	pdev->dev.platform_data = plat;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq");
+	if (!res)
+		return -EINVAL;
+	else if (stat_irq) {
+		res->start = res->end = stat_irq;
+		res->flags &= ~IORESOURCE_DISABLED;
+		res->flags |= stat_irq_flags;
+	}
+
+	return platform_device_register(pdev);
+}
+
+static struct resource resources_mddi0[] = {
+	{
+		.start	= MSM_PMDH_PHYS,
+		.end	= MSM_PMDH_PHYS + MSM_PMDH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_MDDI_PRI,
+		.end	= INT_MDDI_PRI,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource resources_mddi1[] = {
+	{
+		.start	= MSM_EMDH_PHYS,
+		.end	= MSM_EMDH_PHYS + MSM_EMDH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_MDDI_EXT,
+		.end	= INT_MDDI_EXT,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_mddi0 = {
+	.name = "msm_mddi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_mddi0),
+	.resource = resources_mddi0,
+	.dev = {
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_mddi1 = {
+	.name = "msm_mddi",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(resources_mddi1),
+	.resource = resources_mddi1,
+	.dev = {
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+static struct resource resources_mdp[] = {
+	{
+		.start	= MSM_MDP_PHYS,
+		.end	= MSM_MDP_PHYS + MSM_MDP_SIZE - 1,
+		.name	= "mdp",
+		.flags	= IORESOURCE_MEM
+	},
+	{
+		.start	= INT_MDP,
+		.end	= INT_MDP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_mdp = {
+	.name = "msm_mdp",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_mdp),
+	.resource = resources_mdp,
+};
+
+
+static struct resource resources_ssbi_pmic[] = {
+	{
+		.start	= MSM_PMIC_SSBI_PHYS,
+		.end	= MSM_PMIC_SSBI_PHYS + MSM_PMIC_SSBI_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_ssbi_pmic = {
+	.name		= "msm_ssbi",
+	.id		= -1,
+	.resource	= resources_ssbi_pmic,
+	.num_resources	= ARRAY_SIZE(resources_ssbi_pmic),
+};
+
+static struct resource resources_spi[] = {
+	{
+		.start	= MSM_SPI_PHYS,
+		.end	= MSM_SPI_PHYS + MSM_SPI_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SPI_INPUT,
+		.end	= INT_SPI_INPUT,
+		.name	= "irq_in",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= INT_SPI_OUTPUT,
+		.end	= INT_SPI_OUTPUT,
+		.name	= "irq_out",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= INT_SPI_ERROR,
+		.end	= INT_SPI_ERROR,
+		.name	= "irq_err",
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_spi = {
+	.name		= "msm_spi",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_spi),
+	.resource	= resources_spi,
+};
+
+static struct resource msm_vidc_720p_resources[] = {
+	{
+		.start	= 0xA3B00000,
+		.end	= 0xA3B00000 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_MFC720,
+		.end	= INT_MFC720,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_vidc_720p = {
+	.name = "msm_vidc_720p",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_vidc_720p_resources),
+	.resource = msm_vidc_720p_resources,
+};
+
 struct clk msm_clocks_7x30[] = {
 	CLK_PCOM("adm_clk",	ADM_CLK,	NULL, 0),
 	CLK_PCOM("adsp_clk",	ADSP_CLK,	NULL, 0),
 	CLK_PCOM("cam_m_clk",	CAM_M_CLK,	NULL, 0),
-	CLK_PCOM("camif_pad_pclk",	CAMIF_PAD_P_CLK,	NULL, OFF),
-	CLK_PCOM("ebi1_clk",	EBI1_CLK,	NULL, CLK_MIN),
+	CLK_PCOM("ebi1_clk",	EBI1_CLK,	NULL, CLK_MIN | CLKFLAG_SHARED),
 	CLK_PCOM("ecodec_clk",	ECODEC_CLK,	NULL, 0),
-	CLK_PCOM("emdh_clk",	EMDH_CLK,	NULL, OFF | CLK_MINMAX),
-	CLK_PCOM("emdh_pclk",	EMDH_P_CLK,	NULL, OFF),
+	CLK_PCOM("emdh_clk",	EMDH_CLK,	&msm_device_mddi1.dev, OFF | CLK_MINMAX),
+	CLK_PCOM("emdh_pclk",	EMDH_P_CLK,	&msm_device_mddi1.dev, OFF),
 	CLK_PCOM("gp_clk",	GP_CLK,		NULL, 0),
 	CLK_PCOM("grp_2d_clk",	GRP_2D_CLK,	NULL, 0),
 	CLK_PCOM("grp_2d_pclk",	GRP_2D_P_CLK,	NULL, 0),
@@ -68,43 +672,57 @@
 	CLK_7X30S("grp_src_clk", GRP_3D_SRC_CLK, GRP_3D_CLK,	NULL, 0),
 	CLK_PCOM("hdmi_clk",	HDMI_CLK,	NULL, 0),
 	CLK_PCOM("imem_clk",	IMEM_CLK,	NULL, OFF),
+	CLK_PCOM("i2c_clk",	I2C_CLK,	&msm_device_i2c.dev, OFF),
+	CLK_PCOM("i2c_clk",	I2C_2_CLK,	&msm_device_i2c2.dev, OFF),
 	CLK_PCOM("jpeg_clk",	JPEG_CLK,	NULL, OFF),
 	CLK_PCOM("jpeg_pclk",	JPEG_P_CLK,	NULL, OFF),
 	CLK_PCOM("lpa_codec_clk",	LPA_CODEC_CLK,		NULL, 0),
 	CLK_PCOM("lpa_core_clk",	LPA_CORE_CLK,		NULL, 0),
 	CLK_PCOM("lpa_pclk",		LPA_P_CLK,		NULL, 0),
 	CLK_PCOM("mdc_clk",	MDC_CLK,	NULL, 0),
-	CLK_PCOM("mddi_clk",	PMDH_CLK,	NULL, OFF | CLK_MINMAX),
-	CLK_PCOM("mddi_pclk",	PMDH_P_CLK,	NULL, 0),
-	CLK_PCOM("mdp_clk",	MDP_CLK,	NULL, OFF),
-	CLK_PCOM("mdp_pclk",	MDP_P_CLK,	NULL, 0),
-	CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0),
-	CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0),
-	CLK_PCOM("mdp_vsync_clk",	MDP_VSYNC_CLK,  NULL, 0),
+	CLK_PCOM("mddi_clk",	PMDH_CLK,	&msm_device_mddi0.dev, OFF | CLK_MINMAX),
+	CLK_PCOM("mddi_pclk",	PMDH_P_CLK,	&msm_device_mddi0.dev, OFF | CLK_MINMAX),
+	CLK_PCOM("mdp_clk",	MDP_CLK,	&msm_device_mdp.dev, OFF),
+	CLK_PCOM("mdp_pclk",	MDP_P_CLK,	&msm_device_mdp.dev, OFF),
+	CLK_PCOM("lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, &msm_device_mdp.dev, 0),
+	CLK_PCOM("lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, &msm_device_mdp.dev, 0),
+	CLK_PCOM("mdp_vsync_clk",	MDP_VSYNC_CLK,  &msm_device_mdp.dev, 0),
 	CLK_PCOM("mfc_clk",		MFC_CLK,		NULL, 0),
 	CLK_PCOM("mfc_div2_clk",	MFC_DIV2_CLK,		NULL, 0),
 	CLK_PCOM("mfc_pclk",		MFC_P_CLK,		NULL, 0),
 	CLK_PCOM("mi2s_m_clk",		MI2S_M_CLK,  		NULL, 0),
 	CLK_PCOM("mi2s_s_clk",		MI2S_S_CLK,  		NULL, 0),
-	CLK_PCOM("mi2s_codec_rx_m_clk",	MI2S_CODEC_RX_M_CLK,  NULL, 0),
-	CLK_PCOM("mi2s_codec_rx_s_clk",	MI2S_CODEC_RX_S_CLK,  NULL, 0),
-	CLK_PCOM("mi2s_codec_tx_m_clk",	MI2S_CODEC_TX_M_CLK,  NULL, 0),
-	CLK_PCOM("mi2s_codec_tx_s_clk",	MI2S_CODEC_TX_S_CLK,  NULL, 0),
+	CLK_PCOM("mi2s_codec_rx_mclk",	MI2S_CODEC_RX_M_CLK,  NULL, 0),
+	CLK_PCOM("mi2s_codec_rx_sclk",	MI2S_CODEC_RX_S_CLK,  NULL, 0),
+	CLK_PCOM("mi2s_codec_tx_mclk",	MI2S_CODEC_TX_M_CLK,  NULL, 0),
+	CLK_PCOM("mi2s_codec_tx_sclk",	MI2S_CODEC_TX_S_CLK,  NULL, 0),
 	CLK_PCOM("pbus_clk",	PBUS_CLK,	NULL, CLK_MIN),
 	CLK_PCOM("pcm_clk",	PCM_CLK,	NULL, 0),
 	CLK_PCOM("rotator_clk",	AXI_ROTATOR_CLK,		NULL, 0),
 	CLK_PCOM("rotator_imem_clk",	ROTATOR_IMEM_CLK,	NULL, OFF),
 	CLK_PCOM("rotator_pclk",	ROTATOR_P_CLK,		NULL, OFF),
 	CLK_PCOM("sdac_clk",	SDAC_CLK,	NULL, OFF),
-	CLK_PCOM("spi_clk",	SPI_CLK,	NULL, 0),
-	CLK_PCOM("spi_pclk",	SPI_P_CLK,	NULL, 0),
+	CLK_PCOM("sdc_clk",	SDC1_CLK,	&msm_device_sdc1.dev, OFF),
+	CLK_PCOM("sdc_pclk",	SDC1_P_CLK,	&msm_device_sdc1.dev, OFF),
+	CLK_PCOM("sdc_clk",	SDC2_CLK,	&msm_device_sdc2.dev, OFF),
+	CLK_PCOM("sdc_pclk",	SDC2_P_CLK,	&msm_device_sdc2.dev, OFF),
+	CLK_PCOM("sdc_clk",	SDC3_CLK,	&msm_device_sdc3.dev, OFF),
+	CLK_PCOM("sdc_pclk",	SDC3_P_CLK,	&msm_device_sdc3.dev, OFF),
+	CLK_PCOM("sdc_clk",	SDC4_CLK,	&msm_device_sdc4.dev, OFF),
+	CLK_PCOM("sdc_pclk",	SDC4_P_CLK,	&msm_device_sdc4.dev, OFF),
+	CLK_PCOM("spi_clk",	SPI_CLK,	&msm_device_spi.dev, 0),
+	CLK_PCOM("spi_pclk",	SPI_P_CLK,	&msm_device_spi.dev, 0),
 	CLK_7X30S("tv_src_clk",	TV_CLK, 	TV_ENC_CLK,	NULL, 0),
 	CLK_PCOM("tv_dac_clk",	TV_DAC_CLK,	NULL, 0),
 	CLK_PCOM("tv_enc_clk",	TV_ENC_CLK,	NULL, 0),
-	CLK_PCOM("uart_clk",	UART2_CLK,	&msm_device_uart2.dev, 0),
+	CLK_PCOM("uart_clk",	UART1_CLK,	&msm_device_uart1.dev, OFF),
+	CLK_PCOM("uart_clk",	UART2_CLK,	&msm_device_uart2.dev, OFF),
+	CLK_PCOM("uart_clk",	UART3_CLK,	&msm_device_uart3.dev, OFF),
+	CLK_PCOM("uartdm_clk",	UART1DM_CLK,	&msm_device_uart_dm1.dev, OFF),
+	CLK_PCOM("uartdm_clk",	UART2DM_CLK,	&msm_device_uart_dm2.dev, OFF),
 	CLK_PCOM("usb_hs_clk",		USB_HS_CLK,		NULL, OFF),
 	CLK_PCOM("usb_hs_pclk",		USB_HS_P_CLK,		NULL, OFF),
-	CLK_PCOM("usb_hs_core_clk",	USB_HS_CORE_CLK,	NULL, OFF),
+	CLK_PCOM("usb_hs_core_clk",	USB_HS_CORE_CLK,	&msm_device_hsusb.dev, OFF),
 	CLK_PCOM("usb_hs2_clk",		USB_HS2_CLK,		NULL, OFF),
 	CLK_PCOM("usb_hs2_pclk",	USB_HS2_P_CLK,		NULL, OFF),
 	CLK_PCOM("usb_hs2_core_clk",	USB_HS2_CORE_CLK,	NULL, OFF),
@@ -117,6 +735,8 @@
 	CLK_PCOM("vfe_mdc_clk",	VFE_MDC_CLK,	NULL, 0),
 	CLK_PCOM("vfe_pclk",	VFE_P_CLK,	NULL, OFF),
 	CLK_PCOM("vpe_clk",	VPE_CLK,	NULL, 0),
+	CLK_PCOM("qup_clk",	QUP_I2C_CLK,	&msm_device_qup_i2c.dev, OFF),
+	CLK_PCOM("qup_pclk",	QUP_I2C_P_CLK,	&msm_device_qup_i2c.dev, OFF),
 
 	/* 7x30 v2 hardware only. */
 	CLK_PCOM("csi_clk",	CSI0_CLK,	NULL, 0),
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index 4d4a507..0cb7e8d 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -13,8 +13,10 @@
  *
  */
 
+#include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
 
 #include <linux/dma-mapping.h>
 #include <mach/irqs.h>
@@ -23,11 +25,40 @@
 #include <mach/board.h>
 
 #include "devices.h"
+#include "proc_comm.h"
 
 #include <asm/mach/flash.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
 
 #include <mach/mmc.h>
 
+static struct resource resources_uart1[] = {
+	{
+		.start	= INT_UART1,
+		.end	= INT_UART1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART1_PHYS,
+		.end	= MSM_UART1_PHYS + MSM_UART1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_uart2[] = {
+	{
+		.start	= INT_UART2,
+		.end	= INT_UART2,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART2_PHYS,
+		.end	= MSM_UART2_PHYS + MSM_UART2_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
 static struct resource resources_uart3[] = {
 	{
 		.start	= INT_UART3,
@@ -41,6 +72,20 @@
 	},
 };
 
+struct platform_device msm_device_uart1 = {
+	.name	= "msm_serial",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart1),
+	.resource	= resources_uart1,
+};
+
+struct platform_device msm_device_uart2 = {
+	.name	= "msm_serial",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(resources_uart2),
+	.resource	= resources_uart2,
+};
+
 struct platform_device msm_device_uart3 = {
 	.name	= "msm_serial",
 	.id	= 2,
@@ -48,34 +93,555 @@
 	.resource	= resources_uart3,
 };
 
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start = MSM_UART1DM_PHYS,
+		.end   = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART1DM_IRQ,
+		.end   = INT_UART1DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART1DM_RX,
+		.end   = INT_UART1DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CHAN,
+		.end   = DMOV_HSUART1_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CRCI,
+		.end   = DMOV_HSUART1_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm1 = {
+	.name = "msm_serial_hs",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource = msm_uart1_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm_uart2_dm_resources[] = {
+	{
+		.start = MSM_UART2DM_PHYS,
+		.end   = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART2DM_IRQ,
+		.end   = INT_UART2DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART2DM_RX,
+		.end   = INT_UART2DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CHAN,
+		.end   = DMOV_HSUART2_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CRCI,
+		.end   = DMOV_HSUART2_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm2_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm2 = {
+	.name = "msm_serial_hs",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(msm_uart2_dm_resources),
+	.resource = msm_uart2_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm2_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource resources_i2c[] = {
+	{
+		.start	= MSM_I2C_PHYS,
+		.end	= MSM_I2C_PHYS + MSM_I2C_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_PWB_I2C,
+		.end	= INT_PWB_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_i2c = {
+	.name		= "msm_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_i2c),
+	.resource	= resources_i2c,
+};
+
+#define GPIO_I2C_CLK 95
+#define GPIO_I2C_DAT 96
+static int gpio_i2c_clk = -1;
+static int gpio_i2c_dat = -1;
+void msm_set_i2c_mux(bool gpio, int *gpio_clk, int *gpio_dat)
+{
+	unsigned id;
+
+	if (gpio_i2c_clk < 0) {
+		gpio_request(GPIO_I2C_CLK, "i2c-clk");
+		gpio_i2c_clk = GPIO_I2C_CLK;
+	}
+	if (gpio_i2c_dat < 0) {
+		gpio_request(GPIO_I2C_DAT, "i2c-dat");
+		gpio_i2c_dat = GPIO_I2C_DAT;
+	}
+
+	if (gpio) {
+		id = PCOM_GPIO_CFG(GPIO_I2C_CLK, 0, GPIO_OUTPUT,
+				   GPIO_NO_PULL, GPIO_2MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		id = PCOM_GPIO_CFG(GPIO_I2C_DAT, 0, GPIO_OUTPUT,
+				   GPIO_NO_PULL, GPIO_2MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		*gpio_clk = GPIO_I2C_CLK;
+		*gpio_dat = GPIO_I2C_DAT;
+	} else {
+		id = PCOM_GPIO_CFG(GPIO_I2C_CLK, 1, GPIO_INPUT,
+				   GPIO_NO_PULL, GPIO_8MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		id = PCOM_GPIO_CFG(GPIO_I2C_DAT , 1, GPIO_INPUT,
+				   GPIO_NO_PULL, GPIO_8MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+static struct resource resources_hsusb[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb),
+	.resource	= resources_hsusb,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct flash_platform_data msm_nand_data = {
+	.parts		= NULL,
+	.nr_parts	= 0,
+};
+
+static struct resource resources_nand[] = {
+	[0] = {
+		.start	= 7,
+		.end	= 7,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_nand = {
+	.name		= "msm_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_nand),
+	.resource	= resources_nand,
+	.dev		= {
+		.platform_data	= &msm_nand_data,
+	},
+};
+
+struct platform_device msm_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+};
+
+static struct resource resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_PHYS,
+		.end	= MSM_SDC1_PHYS + MSM_SDC1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC1_0,
+		.end	= INT_SDC1_0,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "cmd_irq",
+	},
+	{
+		.start	= INT_SDC1_1,
+		.end	= INT_SDC1_1,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "pio_irq",
+	},
+	{
+		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
+		.name	= "status_irq"
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.start	= MSM_SDC2_PHYS,
+		.end	= MSM_SDC2_PHYS + MSM_SDC2_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC2_0,
+		.end	= INT_SDC2_0,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "cmd_irq",
+	},
+		{
+		.start	= INT_SDC2_1,
+		.end	= INT_SDC2_1,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "pio_irq",
+	},
+	{
+		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
+		.name	= "status_irq"
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc3[] = {
+	{
+		.start	= MSM_SDC3_PHYS,
+		.end	= MSM_SDC3_PHYS + MSM_SDC3_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC3_0,
+		.end	= INT_SDC3_0,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "cmd_irq",
+	},
+		{
+		.start	= INT_SDC3_1,
+		.end	= INT_SDC3_1,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "pio_irq",
+	},
+	{
+		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
+		.name	= "status_irq"
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc4[] = {
+	{
+		.start	= MSM_SDC4_PHYS,
+		.end	= MSM_SDC4_PHYS + MSM_SDC4_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC4_0,
+		.end	= INT_SDC4_0,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "cmd_irq",
+	},
+		{
+		.start	= INT_SDC4_1,
+		.end	= INT_SDC4_1,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "pio_irq",
+	},
+	{
+		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
+		.name	= "status_irq"
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_sdc2),
+	.resource	= resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_sdc3),
+	.resource	= resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_sdc4),
+	.resource	= resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+	&msm_device_sdc2,
+	&msm_device_sdc3,
+	&msm_device_sdc4,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+			unsigned int stat_irq, unsigned long stat_irq_flags)
+{
+	struct platform_device	*pdev;
+	struct resource *res;
+
+	if (controller < 1 || controller > 4)
+		return -EINVAL;
+
+	pdev = msm_sdcc_devices[controller-1];
+	pdev->dev.platform_data = plat;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq");
+	if (!res)
+		return -EINVAL;
+	else if (stat_irq) {
+		res->start = res->end = stat_irq;
+		res->flags &= ~IORESOURCE_DISABLED;
+		res->flags |= stat_irq_flags;
+	}
+
+	return platform_device_register(pdev);
+}
+
+static struct resource resources_mddi0[] = {
+	{
+		.start	= MSM_PMDH_PHYS,
+		.end	= MSM_PMDH_PHYS + MSM_PMDH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_MDDI_PRI,
+		.end	= INT_MDDI_PRI,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource resources_mddi1[] = {
+	{
+		.start	= MSM_EMDH_PHYS,
+		.end	= MSM_EMDH_PHYS + MSM_EMDH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_MDDI_EXT,
+		.end	= INT_MDDI_EXT,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_mddi0 = {
+	.name = "msm_mddi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_mddi0),
+	.resource = resources_mddi0,
+	.dev = {
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_mddi1 = {
+	.name = "msm_mddi",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(resources_mddi1),
+	.resource = resources_mddi1,
+	.dev = {
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+static struct resource resources_mdp[] = {
+	{
+		.start	= MSM_MDP_PHYS,
+		.end	= MSM_MDP_PHYS + MSM_MDP_SIZE - 1,
+		.name	= "mdp",
+		.flags	= IORESOURCE_MEM
+	},
+	{
+		.start	= INT_MDP,
+		.end	= INT_MDP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_mdp = {
+	.name = "msm_mdp",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_mdp),
+	.resource = resources_mdp,
+};
+
+static struct resource resources_tssc[] = {
+	{
+		.start	= MSM_TSSC_PHYS,
+		.end	= MSM_TSSC_PHYS + MSM_TSSC_SIZE - 1,
+		.name	= "tssc",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_TCHSCRN1,
+		.end	= INT_TCHSCRN1,
+		.name	= "tssc1",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+	{
+		.start	= INT_TCHSCRN2,
+		.end	= INT_TCHSCRN2,
+		.name	= "tssc2",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+};
+
+struct platform_device msm_device_touchscreen = {
+	.name = "msm_touchscreen",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_tssc),
+	.resource = resources_tssc,
+};
+
+static struct resource resources_spi[] = {
+	{
+		.start	= MSM_SPI_PHYS,
+		.end	= MSM_SPI_PHYS + MSM_SPI_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SPI_INPUT,
+		.end	= INT_SPI_INPUT,
+		.name	= "irq_in",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= INT_SPI_OUTPUT,
+		.end	= INT_SPI_OUTPUT,
+		.name	= "irq_out",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= INT_SPI_ERROR,
+		.end	= INT_SPI_ERROR,
+		.name	= "irq_err",
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_spi = {
+	.name		= "msm_spi",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_spi),
+	.resource	= resources_spi,
+};
+
 struct clk msm_clocks_8x50[] = {
 	CLK_PCOM("adm_clk",	ADM_CLK,	NULL, 0),
-	CLK_PCOM("ebi1_clk",	EBI1_CLK,	NULL, CLK_MIN),
+	CLK_PCOM("ebi1_clk",	EBI1_CLK,	NULL, CLK_MIN | CLKFLAG_SHARED),
 	CLK_PCOM("ebi2_clk",	EBI2_CLK,	NULL, 0),
 	CLK_PCOM("ecodec_clk",	ECODEC_CLK,	NULL, 0),
-	CLK_PCOM("emdh_clk",	EMDH_CLK,	NULL, OFF | CLK_MINMAX),
+	CLK_PCOM("mddi_clk",	EMDH_CLK,	&msm_device_mddi1.dev, OFF | CLK_MINMAX),
 	CLK_PCOM("gp_clk",	GP_CLK,		NULL, 0),
 	CLK_PCOM("grp_clk",	GRP_3D_CLK,	NULL, 0),
+	CLK_PCOM("i2c_clk",	I2C_CLK,	&msm_device_i2c.dev, 0),
 	CLK_PCOM("icodec_rx_clk",	ICODEC_RX_CLK,	NULL, 0),
 	CLK_PCOM("icodec_tx_clk",	ICODEC_TX_CLK,	NULL, 0),
 	CLK_PCOM("imem_clk",	IMEM_CLK,	NULL, OFF),
 	CLK_PCOM("mdc_clk",	MDC_CLK,	NULL, 0),
-	CLK_PCOM("mddi_clk",	PMDH_CLK,	NULL, OFF | CLK_MINMAX),
-	CLK_PCOM("mdp_clk",	MDP_CLK,	NULL, OFF),
-	CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0),
-	CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0),
-	CLK_PCOM("mdp_vsync_clk",	MDP_VSYNC_CLK,	NULL, 0),
+	CLK_PCOM("mddi_clk",	PMDH_CLK,	&msm_device_mddi0.dev, OFF | CLK_MINMAX),
+	CLK_PCOM("mdp_clk",	MDP_CLK,	&msm_device_mdp.dev, OFF),
+	CLK_PCOM("lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, &msm_device_mdp.dev, 0),
+	CLK_PCOM("lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, &msm_device_mdp.dev, 0),
+	CLK_PCOM("mdp_vsync_clk",	MDP_VSYNC_CLK,	&msm_device_mdp.dev, 0),
 	CLK_PCOM("pbus_clk",	PBUS_CLK,	NULL, CLK_MIN),
 	CLK_PCOM("pcm_clk",	PCM_CLK,	NULL, 0),
 	CLK_PCOM("sdac_clk",	SDAC_CLK,	NULL, OFF),
-	CLK_PCOM("spi_clk",	SPI_CLK,	NULL, 0),
+	CLK_PCOM("spi_clk",	SPI_CLK,	&msm_device_spi.dev, 0),
+	CLK_PCOM("sdc_clk",	SDC1_CLK,	&msm_device_sdc1.dev, OFF),
+	CLK_PCOM("sdc_pclk",	SDC1_P_CLK,	&msm_device_sdc1.dev, OFF),
+	CLK_PCOM("sdc_clk",	SDC2_CLK,	&msm_device_sdc2.dev, OFF),
+	CLK_PCOM("sdc_pclk",	SDC2_P_CLK,	&msm_device_sdc2.dev, OFF),
+	CLK_PCOM("sdc_clk",	SDC3_CLK,	&msm_device_sdc3.dev, OFF),
+	CLK_PCOM("sdc_pclk",	SDC3_P_CLK,	&msm_device_sdc3.dev, OFF),
+	CLK_PCOM("sdc_clk",	SDC4_CLK,	&msm_device_sdc4.dev, OFF),
+	CLK_PCOM("sdc_pclk",	SDC4_P_CLK,	&msm_device_sdc4.dev, OFF),
 	CLK_PCOM("tsif_clk",	TSIF_CLK,	NULL, 0),
 	CLK_PCOM("tsif_ref_clk",	TSIF_REF_CLK,	NULL, 0),
 	CLK_PCOM("tv_dac_clk",	TV_DAC_CLK,	NULL, 0),
 	CLK_PCOM("tv_enc_clk",	TV_ENC_CLK,	NULL, 0),
+	CLK_PCOM("uart_clk",	UART1_CLK,	&msm_device_uart1.dev, OFF),
+	CLK_PCOM("uart_clk",	UART2_CLK,	&msm_device_uart2.dev, OFF),
 	CLK_PCOM("uart_clk",	UART3_CLK,	&msm_device_uart3.dev, OFF),
-	CLK_PCOM("usb_hs_clk",	USB_HS_CLK,	NULL, OFF),
-	CLK_PCOM("usb_hs_pclk",	USB_HS_P_CLK,	NULL, OFF),
+	CLK_PCOM("uartdm_clk",	UART1DM_CLK,	&msm_device_uart_dm1.dev, OFF),
+	CLK_PCOM("uartdm_clk",	UART2DM_CLK,	&msm_device_uart_dm2.dev, OFF),
+	CLK_PCOM("usb_hs_clk",	USB_HS_CLK,	&msm_device_hsusb.dev, OFF),
+	CLK_PCOM("usb_hs_pclk",	USB_HS_P_CLK,	&msm_device_hsusb.dev, OFF),
 	CLK_PCOM("usb_otg_clk",	USB_OTG_CLK,	NULL, 0),
 	CLK_PCOM("vdc_clk",	VDC_CLK,	NULL, OFF | CLK_MIN),
 	CLK_PCOM("vfe_clk",	VFE_CLK,	NULL, OFF),
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 568443e..e86be3ad 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -22,6 +22,9 @@
 extern struct platform_device msm_device_uart2;
 extern struct platform_device msm_device_uart3;
 
+extern struct platform_device msm_device_uart_dm1;
+extern struct platform_device msm_device_uart_dm2;
+
 extern struct platform_device msm_device_sdc1;
 extern struct platform_device msm_device_sdc2;
 extern struct platform_device msm_device_sdc3;
@@ -30,10 +33,19 @@
 extern struct platform_device msm_device_hsusb;
 
 extern struct platform_device msm_device_i2c;
+extern struct platform_device msm_device_i2c2;
+
+extern struct platform_device msm_device_qup_i2c;
 
 extern struct platform_device msm_device_smd;
 
 extern struct platform_device msm_device_nand;
+extern struct platform_device msm_device_mddi0;
+extern struct platform_device msm_device_mddi1;
+extern struct platform_device msm_device_mdp;
+extern struct platform_device msm_device_touchscreen;
+extern struct platform_device msm_device_spi;
+extern struct platform_device msm_device_ssbi_pmic;
 
 extern struct clk msm_clocks_7x01a[];
 extern unsigned msm_num_clocks_7x01a;
@@ -43,5 +55,6 @@
 
 extern struct clk msm_clocks_8x50[];
 extern unsigned msm_num_clocks_8x50;
+extern struct platform_device msm_device_vidc_720p;
 
 #endif
diff --git a/arch/arm/mach-msm/devices_htc.c b/arch/arm/mach-msm/devices_htc.c
new file mode 100644
index 0000000..e5f65e7
--- /dev/null
+++ b/arch/arm/mach-msm/devices_htc.c
@@ -0,0 +1,500 @@
+/* linux/arch/arm/mach-msm/devices.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * 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/platform_device.h>
+
+#include <linux/dma-mapping.h>
+#include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include "gpio_chip.h"
+#include "devices.h"
+#include <mach/board.h>
+#include <mach/board_htc.h>
+#include <mach/msm_hsusb.h>
+#include <linux/usb/android_composite.h>
+
+#include <asm/mach/flash.h>
+#include <asm/setup.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+#include <linux/android_pmem.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_iomap.h>
+#include <asm/mach/mmc.h>
+
+static char *df_serialno = "000000000000";
+
+#if 0
+struct platform_device *devices[] __initdata = {
+	&msm_device_nand,
+	&msm_device_smd,
+	&msm_device_i2c,
+};
+
+void __init msm_add_devices(void)
+{
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+#endif
+
+#define HSUSB_API_INIT_PHY_PROC	2
+#define HSUSB_API_PROG		0x30000064
+#define HSUSB_API_VERS MSM_RPC_VERS(1,1)
+
+static void internal_phy_reset(void)
+{
+	struct msm_rpc_endpoint *usb_ep;
+	int rc;
+	struct hsusb_phy_start_req {
+		struct rpc_request_hdr hdr;
+	} req;
+
+	printk(KERN_INFO "msm_hsusb_phy_reset\n");
+
+	usb_ep = msm_rpc_connect(HSUSB_API_PROG, HSUSB_API_VERS, 0);
+	if (IS_ERR(usb_ep)) {
+		printk(KERN_ERR "%s: init rpc failed! error: %ld\n",
+				__func__, PTR_ERR(usb_ep));
+		goto close;
+	}
+	rc = msm_rpc_call(usb_ep, HSUSB_API_INIT_PHY_PROC,
+			&req, sizeof(req), 5 * HZ);
+	if (rc < 0)
+		printk(KERN_ERR "%s: rpc call failed! (%d)\n", __func__, rc);
+
+close:
+	msm_rpc_close(usb_ep);
+}
+
+/* adjust eye diagram, disable vbusvalid interrupts */
+static int hsusb_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 };
+
+struct msm_hsusb_platform_data msm_hsusb_pdata = {
+	.phy_reset = internal_phy_reset,
+	.phy_init_seq = hsusb_phy_init_seq,
+	.usb_connected = notify_usb_connected,
+};
+
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+	.nluns = 1,
+	.vendor = "HTC     ",
+	.product = "Android Phone   ",
+	.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	= 0x0bb4,
+	.vendorDescr	= "HTC",
+};
+
+static struct platform_device rndis_device = {
+	.name	= "rndis",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &rndis_pdata,
+	},
+};
+#endif
+
+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",
+};
+
+static char *usb_functions_all[] = {
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	"rndis",
+#endif
+	"usb_mass_storage",
+	"adb",
+#ifdef CONFIG_USB_ANDROID_ACM
+	"acm",
+#endif
+};
+
+static struct android_usb_product usb_products[] = {
+	{
+		.product_id	= 0x0c01,
+		.num_functions	= ARRAY_SIZE(usb_functions_ums),
+		.functions	= usb_functions_ums,
+	},
+	{
+		.product_id	= 0x0c02,
+		.num_functions	= ARRAY_SIZE(usb_functions_ums_adb),
+		.functions	= usb_functions_ums_adb,
+	},
+	{
+		.product_id	= 0x0ffe,
+		.num_functions	= ARRAY_SIZE(usb_functions_rndis),
+		.functions	= usb_functions_rndis,
+	},
+	{
+		.product_id	= 0x0ffc,
+		.num_functions	= ARRAY_SIZE(usb_functions_rndis_adb),
+		.functions	= usb_functions_rndis_adb,
+	},
+};
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.vendor_id	= 0x0bb4,
+	.product_id	= 0x0c01,
+	.version	= 0x0100,
+	.product_name	= "Android Phone",
+	.manufacturer_name = "HTC",
+	.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,
+	},
+};
+
+void __init msm_add_usb_devices(void (*phy_reset) (void))
+{
+	/* setup */
+	if (phy_reset)
+		msm_hsusb_pdata.phy_reset = phy_reset;
+	msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata;
+	platform_device_register(&msm_device_hsusb);
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	platform_device_register(&rndis_device);
+#endif
+	platform_device_register(&usb_mass_storage_device);
+	platform_device_register(&android_usb_device);
+}
+
+static struct android_pmem_platform_data pmem_pdata = {
+	.name = "pmem",
+	.no_allocator = 1,
+	.cached = 1,
+};
+
+static struct android_pmem_platform_data pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.no_allocator = 0,
+	.cached = 0,
+};
+
+static struct android_pmem_platform_data pmem_camera_pdata = {
+	.name = "pmem_camera",
+	.no_allocator = 1,
+	.cached = 0,
+};
+
+static struct platform_device pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = { .platform_data = &pmem_pdata },
+};
+
+static struct platform_device pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 1,
+	.dev = { .platform_data = &pmem_adsp_pdata },
+};
+
+static struct platform_device pmem_camera_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &pmem_camera_pdata },
+};
+
+static struct resource ram_console_resource[] = {
+	{
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device ram_console_device = {
+	.name = "ram_console",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(ram_console_resource),
+	.resource       = ram_console_resource,
+};
+
+static struct resource resources_hw3d[] = {
+	{
+		.start	= 0xA0000000,
+		.end	= 0xA00fffff,
+		.flags	= IORESOURCE_MEM,
+		.name	= "regs",
+	},
+	{
+		.flags	= IORESOURCE_MEM,
+		.name	= "smi",
+	},
+	{
+		.flags	= IORESOURCE_MEM,
+		.name	= "ebi",
+	},
+	{
+		.start	= INT_GRAPHICS,
+		.end	= INT_GRAPHICS,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "gfx",
+	},
+};
+
+static struct platform_device hw3d_device = {
+	.name		= "msm_hw3d",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_hw3d),
+	.resource	= resources_hw3d,
+};
+
+void __init msm_add_mem_devices(struct msm_pmem_setting *setting)
+{
+	if (setting->pmem_size) {
+		pmem_pdata.start = setting->pmem_start;
+		pmem_pdata.size = setting->pmem_size;
+		platform_device_register(&pmem_device);
+	}
+
+	if (setting->pmem_adsp_size) {
+		pmem_adsp_pdata.start = setting->pmem_adsp_start;
+		pmem_adsp_pdata.size = setting->pmem_adsp_size;
+		platform_device_register(&pmem_adsp_device);
+	}
+
+	if (setting->pmem_gpu0_size && setting->pmem_gpu1_size) {
+		struct resource *res;
+
+		res = platform_get_resource_byname(&hw3d_device, IORESOURCE_MEM,
+						   "smi");
+		res->start = setting->pmem_gpu0_start;
+		res->end = res->start + setting->pmem_gpu0_size - 1;
+
+		res = platform_get_resource_byname(&hw3d_device, IORESOURCE_MEM,
+						   "ebi");
+		res->start = setting->pmem_gpu1_start;
+		res->end = res->start + setting->pmem_gpu1_size - 1;
+		platform_device_register(&hw3d_device);
+	}
+
+	if (setting->pmem_camera_size) {
+		pmem_camera_pdata.start = setting->pmem_camera_start;
+		pmem_camera_pdata.size = setting->pmem_camera_size;
+		platform_device_register(&pmem_camera_device);
+	}
+
+	if (setting->ram_console_size) {
+		ram_console_resource[0].start = setting->ram_console_start;
+		ram_console_resource[0].end = setting->ram_console_start
+			+ setting->ram_console_size - 1;
+		platform_device_register(&ram_console_device);
+	}
+}
+
+#define PM_LIBPROG      0x30000061
+#if (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225)
+#define PM_LIBVERS      0xfb837d0b
+#else
+#define PM_LIBVERS      0x10001
+#endif
+
+#if 0
+static struct platform_device *msm_serial_devices[] __initdata = {
+	&msm_device_uart1,
+	&msm_device_uart2,
+	&msm_device_uart3,
+	#ifdef CONFIG_SERIAL_MSM_HS
+	&msm_device_uart_dm1,
+	&msm_device_uart_dm2,
+	#endif
+};
+
+int __init msm_add_serial_devices(unsigned num)
+{
+	if (num > MSM_SERIAL_NUM)
+		return -EINVAL;
+
+	return platform_device_register(msm_serial_devices[num]);
+}
+#endif
+
+#define ATAG_SMI 0x4d534D71
+/* setup calls mach->fixup, then parse_tags, parse_cmdline
+ * We need to setup meminfo in mach->fixup, so this function
+ * will need to traverse each tag to find smi tag.
+ */
+int __init parse_tag_smi(const struct tag *tags)
+{
+	int smi_sz = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_SMI) {
+			printk(KERN_DEBUG "find the smi tag\n");
+			find = 1;
+			break;
+		}
+	}
+	if (!find)
+		return -1;
+
+	printk(KERN_DEBUG "parse_tag_smi: smi size = %d\n", t->u.mem.size);
+	smi_sz = t->u.mem.size;
+	return smi_sz;
+}
+__tagtable(ATAG_SMI, parse_tag_smi);
+
+
+#define ATAG_HWID 0x4d534D72
+int __init parse_tag_hwid(const struct tag *tags)
+{
+	int hwid = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_HWID) {
+			printk(KERN_DEBUG "find the hwid tag\n");
+			find = 1;
+			break;
+		}
+	}
+
+	if (find)
+		hwid = t->u.revision.rev;
+	printk(KERN_DEBUG "parse_tag_hwid: hwid = 0x%x\n", hwid);
+	return hwid;
+}
+__tagtable(ATAG_HWID, parse_tag_hwid);
+
+#define ATAG_SKUID 0x4d534D73
+int __init parse_tag_skuid(const struct tag *tags)
+{
+	int skuid = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_SKUID) {
+			printk(KERN_DEBUG "find the skuid tag\n");
+			find = 1;
+			break;
+		}
+	}
+
+	if (find)
+		skuid = t->u.revision.rev;
+	printk(KERN_DEBUG "parse_tag_skuid: hwid = 0x%x\n", skuid);
+	return skuid;
+}
+__tagtable(ATAG_SKUID, parse_tag_skuid);
+
+#define ATAG_ENGINEERID 0x4d534D75
+int __init parse_tag_engineerid(const struct tag *tags)
+{
+	int engineerid = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_ENGINEERID) {
+			printk(KERN_DEBUG "find the engineer tag\n");
+			find = 1;
+			break;
+		}
+	}
+
+	if (find)
+		engineerid = t->u.revision.rev;
+	printk(KERN_DEBUG "parse_tag_engineerid: hwid = 0x%x\n", engineerid);
+	return engineerid;
+}
+__tagtable(ATAG_ENGINEERID, parse_tag_engineerid);
+
+static int mfg_mode;
+int __init board_mfg_mode_init(char *s)
+{
+	if (!strcmp(s, "normal"))
+		mfg_mode = 0;
+	else if (!strcmp(s, "factory2"))
+		mfg_mode = 1;
+	else if (!strcmp(s, "recovery"))
+		mfg_mode = 2;
+	else if (!strcmp(s, "charge"))
+		mfg_mode = 3;
+
+	return 1;
+}
+__setup("androidboot.mode=", board_mfg_mode_init);
+
+
+int board_mfg_mode(void)
+{
+	return mfg_mode;
+}
+
+static int __init board_serialno_setup(char *serialno)
+{
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	int i;
+	char *src;
+#endif
+	char *str;
+
+	/* use default serial number when mode is factory2 */
+	if (mfg_mode == 1 || !strlen(serialno))
+		str = df_serialno;
+	else
+		str = serialno;
+
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	/* create a fake MAC address from our serial number.
+	 * first byte is 0x02 to signify locally administered.
+	 */
+	rndis_pdata.ethaddr[0] = 0x02;
+	src = str;
+	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 = str;
+	return 1;
+}
+
+__setup("androidboot.serialno=", board_serialno_setup);
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index 02cae5e..cfb78c4 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -1,6 +1,8 @@
 /* linux/arch/arm/mach-msm/dma.c
  *
  * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008 QUALCOMM Incorporated.
+ * Copyright (c) 2008 QUALCOMM USA, INC.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -18,6 +20,7 @@
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/completion.h>
+#include <linux/module.h>
 #include <mach/dma.h>
 
 #define MSM_DMOV_CHANNEL_COUNT 16
@@ -51,6 +54,7 @@
 {
 	writel((graceful << 31), DMOV_FLUSH0(id));
 }
+EXPORT_SYMBOL(msm_dmov_stop_cmd);
 
 void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
 {
@@ -89,6 +93,20 @@
 	}
 	spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
 }
+EXPORT_SYMBOL(msm_dmov_enqueue_cmd);
+
+void msm_dmov_flush(unsigned int id)
+{
+	unsigned long irq_flags;
+	spin_lock_irqsave(&msm_dmov_lock, irq_flags);
+	/* XXX not checking if flush cmd sent already */
+	if (!list_empty(&active_commands[id])) {
+		PRINT_IO("msm_dmov_flush(%d), send flush cmd\n", id);
+		writel(DMOV_FLUSH_TYPE, DMOV_FLUSH0(id));
+	}
+	spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
+}
+EXPORT_SYMBOL(msm_dmov_flush);
 
 struct msm_dmov_exec_cmdptr_cmd {
 	struct msm_dmov_cmd dmov_cmd;
@@ -268,4 +286,3 @@
 }
 
 arch_initcall(msm_init_datamover);
-
diff --git a/arch/arm/mach-msm/fiq_glue.S b/arch/arm/mach-msm/fiq_glue.S
new file mode 100644
index 0000000..df1c708
--- /dev/null
+++ b/arch/arm/mach-msm/fiq_glue.S
@@ -0,0 +1,112 @@
+/* arch/arm/mach-msm/fiq_glue.S
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+
+		.text
+
+		.global fiq_glue_end
+
+		/* fiq stack: r0-r15,cpsr,spsr of interrupted mode */
+
+ENTRY(fiq_glue)
+		/* store pc, cpsr from previous mode */
+		mrs	r12, spsr
+		sub	r11, lr, #4
+		subs	r10, #1
+		bne	nested_fiq
+
+		stmfd	sp!, {r11-r12, lr}
+
+		/* store r8-r14 from previous mode */
+		sub	sp, sp, #(7 * 4)
+		stmia	sp, {r8-r14}^
+		nop
+
+		/* store r0-r7 from previous mode */
+		stmfd	sp!, {r0-r7}
+
+		/* setup func(data,regs) arguments */
+		mov	r0, r9
+		mov	r1, sp
+		mov	r3, r8
+
+		mov	r7, sp
+
+		/* Get sp and lr from non-user modes */
+		and	r4, r12, #MODE_MASK
+		cmp	r4, #USR_MODE
+		beq	fiq_from_usr_mode
+
+		mov	r7, sp
+		orr	r4, r4, #(PSR_I_BIT | PSR_F_BIT)
+		msr	cpsr_c, r4
+		str	sp, [r7, #(4 * 13)]
+		str	lr, [r7, #(4 * 14)]
+		mrs	r5, spsr
+		str	r5, [r7, #(4 * 17)]
+
+		cmp	r4, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT)
+		/* use fiq stack if we reenter this mode */
+		subne	sp, r7, #(4 * 3)
+
+fiq_from_usr_mode:
+		msr	cpsr_c, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT)
+		mov	r2, sp
+		sub	sp, r7, #12
+		stmfd	sp!, {r2, ip, lr}
+		/* call func(data,regs) */
+		blx	r3
+		ldmfd	sp, {r2, ip, lr}
+		mov	sp, r2
+
+		/* restore/discard saved state */
+		cmp	r4, #USR_MODE
+		beq	fiq_from_usr_mode_exit
+
+		msr	cpsr_c, r4
+		ldr	sp, [r7, #(4 * 13)]
+		ldr	lr, [r7, #(4 * 14)]
+		msr	spsr_cxsf, r5
+
+fiq_from_usr_mode_exit:
+		msr	cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
+
+		ldmfd	sp!, {r0-r7}
+		add	sp, sp, #(7 * 4)
+		ldmfd	sp!, {r11-r12, lr}
+exit_fiq:
+		msr	spsr_cxsf, r12
+		add	r10, #1
+		movs	pc, r11
+
+nested_fiq:
+		orr	r12, r12, #(PSR_F_BIT)
+		b	exit_fiq
+
+fiq_glue_end:
+
+ENTRY(fiq_glue_setup) /* func, data, sp */
+		mrs		r3, cpsr
+		msr		cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
+		movs		r8, r0
+		mov		r9, r1
+		mov		sp, r2
+		moveq		r10, #0
+		movne		r10, #1
+		msr		cpsr_c, r3
+		bx		lr
+
diff --git a/arch/arm/mach-msm/fish_battery.c b/arch/arm/mach-msm/fish_battery.c
new file mode 100644
index 0000000..19fbb91
--- /dev/null
+++ b/arch/arm/mach-msm/fish_battery.c
@@ -0,0 +1,145 @@
+/* arch/arm/mach-msm/fish_battery.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.
+ *
+ * based on: arch/arm/mach-msm/htc_battery.c
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+
+static enum power_supply_property fish_battery_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static enum power_supply_property fish_power_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static char *supply_list[] = {
+	"battery",
+};
+
+static int fish_power_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val);
+
+static int fish_battery_get_property(struct power_supply *psy,
+				     enum power_supply_property psp,
+				     union power_supply_propval *val);
+
+static struct power_supply fish_power_supplies[] = {
+	{
+		.name = "battery",
+		.type = POWER_SUPPLY_TYPE_BATTERY,
+		.properties = fish_battery_properties,
+		.num_properties = ARRAY_SIZE(fish_battery_properties),
+		.get_property = fish_battery_get_property,
+	},
+	{
+		.name = "ac",
+		.type = POWER_SUPPLY_TYPE_MAINS,
+		.supplied_to = supply_list,
+		.num_supplicants = ARRAY_SIZE(supply_list),
+		.properties = fish_power_properties,
+		.num_properties = ARRAY_SIZE(fish_power_properties),
+		.get_property = fish_power_get_property,
+	},
+};
+
+static int fish_power_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+			val->intval = 1;
+		else
+			val->intval = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fish_battery_get_property(struct power_supply *psy,
+				     enum power_supply_property psp,
+				     union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = 1;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = 100;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fish_battery_probe(struct platform_device *pdev)
+{
+	int i;
+	int rc;
+
+	/* init power supplier framework */
+	for (i = 0; i < ARRAY_SIZE(fish_power_supplies); i++) {
+		rc = power_supply_register(&pdev->dev, &fish_power_supplies[i]);
+		if (rc)
+			pr_err("%s: Failed to register power supply (%d)\n",
+			       __func__, rc);
+	}
+
+	return 0;
+}
+
+static struct platform_driver fish_battery_driver = {
+	.probe	= fish_battery_probe,
+	.driver	= {
+		.name	= "fish_battery",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init fish_battery_init(void)
+{
+	platform_driver_register(&fish_battery_driver);
+	return 0;
+}
+
+module_init(fish_battery_init);
+MODULE_DESCRIPTION("Qualcomm fish battery driver");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/generic_gpio.c b/arch/arm/mach-msm/generic_gpio.c
new file mode 100644
index 0000000..46630a2
--- /dev/null
+++ b/arch/arm/mach-msm/generic_gpio.c
@@ -0,0 +1,113 @@
+/* arch/arm/mach-msm/generic_gpio.c
+ *
+ * Copyright (C) 2007 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/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/gpio.h>
+#include "gpio_chip.h"
+
+#undef gpio_chip
+static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct old_gpio_chip *old_chip;
+	unsigned long irq_flags;
+	int ret = -ENOTSUPP;
+
+	old_chip = container_of(chip, struct old_gpio_chip, gpio_chip);
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	ret = old_chip->configure(old_chip, chip->base + offset, GPIOF_INPUT);
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+	return ret;
+}
+
+static int gpio_chip_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct old_gpio_chip *old_chip;
+	unsigned long irq_flags;
+	int ret = -ENOTSUPP;
+
+	old_chip = container_of(chip, struct old_gpio_chip, gpio_chip);
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	if (old_chip->read)
+		ret = old_chip->read(old_chip, chip->base + offset);
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+	return ret;
+}
+
+static int
+gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct old_gpio_chip *old_chip;
+	unsigned long irq_flags;
+	int ret = -ENOTSUPP;
+
+	old_chip = container_of(chip, struct old_gpio_chip, gpio_chip);
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	if (old_chip->write)
+		old_chip->write(old_chip, chip->base + offset, value);
+	ret = old_chip->configure(old_chip, chip->base + offset,
+				  GPIOF_DRIVE_OUTPUT);
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+	return ret;
+}
+
+static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct old_gpio_chip *old_chip;
+	unsigned long irq_flags;
+
+	old_chip = container_of(chip, struct old_gpio_chip, gpio_chip);
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	if (old_chip->write)
+		old_chip->write(old_chip, chip->base + offset, value);
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+}
+
+static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct old_gpio_chip *old_chip;
+	unsigned long irq_flags;
+	int ret = -ENOTSUPP;
+	int irq;
+
+	old_chip = container_of(chip, struct old_gpio_chip, gpio_chip);
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	if (old_chip->get_irq_num)
+		ret = old_chip->get_irq_num(old_chip, chip->base + offset,
+					    &irq, NULL);
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+	if (ret)
+		return ret;
+	return irq;
+}
+
+int register_gpio_chip(struct old_gpio_chip *new_gpio_chip)
+{
+	spin_lock_init(&new_gpio_chip->lock);
+	new_gpio_chip->gpio_chip.direction_input = gpio_chip_direction_input;
+	new_gpio_chip->gpio_chip.get = gpio_chip_get;
+	new_gpio_chip->gpio_chip.direction_output = gpio_chip_direction_output;
+	new_gpio_chip->gpio_chip.set = gpio_chip_set;
+	new_gpio_chip->gpio_chip.to_irq = gpio_chip_to_irq;
+	new_gpio_chip->gpio_chip.base = new_gpio_chip->start;
+	new_gpio_chip->gpio_chip.ngpio =
+		new_gpio_chip->end - new_gpio_chip->start + 1;
+
+	return gpiochip_add(&new_gpio_chip->gpio_chip);
+}
+
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
index bc32c84..41b7e4d 100644
--- a/arch/arm/mach-msm/gpio.c
+++ b/arch/arm/mach-msm/gpio.c
@@ -14,9 +14,655 @@
  *
  */
 
+#include <linux/io.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <mach/gpio.h>
+#include "gpio_chip.h"
+#include "gpio_hw.h"
 #include "proc_comm.h"
+#include "smd_private.h"
+
+enum {
+	GPIO_DEBUG_SLEEP = 1U << 0,
+};
+static int msm_gpio_debug_mask;
+module_param_named(debug_mask, msm_gpio_debug_mask, int,
+		   S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define MSM_GPIO_BROKEN_INT_CLEAR 1
+
+/* private gpio_configure flags */
+#define MSM_GPIOF_ENABLE_INTERRUPT      0x10000000
+#define MSM_GPIOF_DISABLE_INTERRUPT     0x20000000
+#define MSM_GPIOF_ENABLE_WAKE           0x40000000
+#define MSM_GPIOF_DISABLE_WAKE          0x80000000
+
+static int msm_gpio_configure(struct gpio_chip *chip, unsigned int gpio,
+			      unsigned long flags);
+static int msm_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio,
+				unsigned int *irqp,
+				unsigned long *irqnumflagsp);
+static int msm_gpio_read(struct gpio_chip *chip, unsigned n);
+static int msm_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on);
+static int msm_gpio_read_detect_status(struct gpio_chip *chip,
+				       unsigned int gpio);
+static int msm_gpio_clear_detect_status(struct gpio_chip *chip,
+					unsigned int gpio);
+
+struct msm_gpio_regs {
+	void __iomem *out;
+	void __iomem *in;
+	void __iomem *int_status;
+	void __iomem *int_clear;
+	void __iomem *int_en;
+	void __iomem *int_edge;
+	void __iomem *int_pos;
+	void __iomem *oe;
+};
+
+struct msm_gpio_chip {
+	struct gpio_chip        chip;
+	struct msm_gpio_regs    regs;
+#if MSM_GPIO_BROKEN_INT_CLEAR
+	unsigned                int_status_copy;
+#endif
+	unsigned int            both_edge_detect;
+	unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
+};
+
+struct msm_gpio_chip msm_gpio_chips[] = {
+	{
+		.regs = {
+			.out =         GPIO_OUT_0,
+			.in =          GPIO_IN_0,
+			.int_status =  GPIO_INT_STATUS_0,
+			.int_clear =   GPIO_INT_CLEAR_0,
+			.int_en =      GPIO_INT_EN_0,
+			.int_edge =    GPIO_INT_EDGE_0,
+			.int_pos =     GPIO_INT_POS_0,
+			.oe =          GPIO_OE_0,
+		},
+		.chip = {
+			.start = 0,
+			.end = 15,
+			.configure = msm_gpio_configure,
+			.get_irq_num = msm_gpio_get_irq_num,
+			.read = msm_gpio_read,
+			.write = msm_gpio_write,
+			.read_detect_status = msm_gpio_read_detect_status,
+			.clear_detect_status = msm_gpio_clear_detect_status
+		}
+	},
+	{
+		.regs = {
+			.out =         GPIO_OUT_1,
+			.in =          GPIO_IN_1,
+			.int_status =  GPIO_INT_STATUS_1,
+			.int_clear =   GPIO_INT_CLEAR_1,
+			.int_en =      GPIO_INT_EN_1,
+			.int_edge =    GPIO_INT_EDGE_1,
+			.int_pos =     GPIO_INT_POS_1,
+			.oe =          GPIO_OE_1,
+		},
+		.chip = {
+			.start = 16,
+#if defined(CONFIG_ARCH_MSM7X30)
+			.end = 43,
+#else
+			.end = 42,
+#endif
+			.configure = msm_gpio_configure,
+			.get_irq_num = msm_gpio_get_irq_num,
+			.read = msm_gpio_read,
+			.write = msm_gpio_write,
+			.read_detect_status = msm_gpio_read_detect_status,
+			.clear_detect_status = msm_gpio_clear_detect_status
+		}
+	},
+	{
+		.regs = {
+			.out =         GPIO_OUT_2,
+			.in =          GPIO_IN_2,
+			.int_status =  GPIO_INT_STATUS_2,
+			.int_clear =   GPIO_INT_CLEAR_2,
+			.int_en =      GPIO_INT_EN_2,
+			.int_edge =    GPIO_INT_EDGE_2,
+			.int_pos =     GPIO_INT_POS_2,
+			.oe =          GPIO_OE_2,
+		},
+		.chip = {
+#if defined(CONFIG_ARCH_MSM7X30)
+			.start = 44,
+#else
+			.start = 43,
+#endif
+			.end = 67,
+			.configure = msm_gpio_configure,
+			.get_irq_num = msm_gpio_get_irq_num,
+			.read = msm_gpio_read,
+			.write = msm_gpio_write,
+			.read_detect_status = msm_gpio_read_detect_status,
+			.clear_detect_status = msm_gpio_clear_detect_status
+		}
+	},
+	{
+		.regs = {
+			.out =         GPIO_OUT_3,
+			.in =          GPIO_IN_3,
+			.int_status =  GPIO_INT_STATUS_3,
+			.int_clear =   GPIO_INT_CLEAR_3,
+			.int_en =      GPIO_INT_EN_3,
+			.int_edge =    GPIO_INT_EDGE_3,
+			.int_pos =     GPIO_INT_POS_3,
+			.oe =          GPIO_OE_3,
+		},
+		.chip = {
+			.start = 68,
+			.end = 94,
+			.configure = msm_gpio_configure,
+			.get_irq_num = msm_gpio_get_irq_num,
+			.read = msm_gpio_read,
+			.write = msm_gpio_write,
+			.read_detect_status = msm_gpio_read_detect_status,
+			.clear_detect_status = msm_gpio_clear_detect_status
+		}
+	},
+	{
+		.regs = {
+			.out =         GPIO_OUT_4,
+			.in =          GPIO_IN_4,
+			.int_status =  GPIO_INT_STATUS_4,
+			.int_clear =   GPIO_INT_CLEAR_4,
+			.int_en =      GPIO_INT_EN_4,
+			.int_edge =    GPIO_INT_EDGE_4,
+			.int_pos =     GPIO_INT_POS_4,
+			.oe =          GPIO_OE_4,
+		},
+		.chip = {
+			.start = 95,
+#if defined(CONFIG_ARCH_QSD8X50)
+			.end = 103,
+#else
+			.end = 106,
+#endif
+			.configure = msm_gpio_configure,
+			.get_irq_num = msm_gpio_get_irq_num,
+			.read = msm_gpio_read,
+			.write = msm_gpio_write,
+			.read_detect_status = msm_gpio_read_detect_status,
+			.clear_detect_status = msm_gpio_clear_detect_status
+		}
+	},
+	{
+		.regs = {
+			.out =         GPIO_OUT_5,
+			.in =          GPIO_IN_5,
+			.int_status =  GPIO_INT_STATUS_5,
+			.int_clear =   GPIO_INT_CLEAR_5,
+			.int_en =      GPIO_INT_EN_5,
+			.int_edge =    GPIO_INT_EDGE_5,
+			.int_pos =     GPIO_INT_POS_5,
+			.oe =          GPIO_OE_5,
+		},
+		.chip = {
+#if defined(CONFIG_ARCH_QSD8X50)
+			.start = 104,
+			.end = 121,
+#elif defined(CONFIG_ARCH_MSM7X30)
+			.start = 107,
+			.end = 133,
+#else
+			.start = 107,
+			.end = 121,
+#endif
+			.configure = msm_gpio_configure,
+			.get_irq_num = msm_gpio_get_irq_num,
+			.read = msm_gpio_read,
+			.write = msm_gpio_write,
+			.read_detect_status = msm_gpio_read_detect_status,
+			.clear_detect_status = msm_gpio_clear_detect_status
+		}
+	},
+#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM7X30)
+	{
+		.regs = {
+			.out =         GPIO_OUT_6,
+			.in =          GPIO_IN_6,
+			.int_status =  GPIO_INT_STATUS_6,
+			.int_clear =   GPIO_INT_CLEAR_6,
+			.int_en =      GPIO_INT_EN_6,
+			.int_edge =    GPIO_INT_EDGE_6,
+			.int_pos =     GPIO_INT_POS_6,
+			.oe =          GPIO_OE_6,
+		},
+		.chip = {
+#if defined(CONFIG_ARCH_MSM7X30)
+			.start = 134,
+			.end = 150,
+#else
+			.start = 122,
+			.end = 152,
+#endif
+			.configure = msm_gpio_configure,
+			.get_irq_num = msm_gpio_get_irq_num,
+			.read = msm_gpio_read,
+			.write = msm_gpio_write,
+			.read_detect_status = msm_gpio_read_detect_status,
+			.clear_detect_status = msm_gpio_clear_detect_status
+		}
+	},
+	{
+		.regs = {
+			.out =         GPIO_OUT_7,
+			.in =          GPIO_IN_7,
+			.int_status =  GPIO_INT_STATUS_7,
+			.int_clear =   GPIO_INT_CLEAR_7,
+			.int_en =      GPIO_INT_EN_7,
+			.int_edge =    GPIO_INT_EDGE_7,
+			.int_pos =     GPIO_INT_POS_7,
+			.oe =          GPIO_OE_7,
+		},
+		.chip = {
+#if defined(CONFIG_ARCH_MSM7X30)
+			.start = 151,
+			.end = 181,
+#else
+			.start = 153,
+			.end = 164,
+#endif
+			.configure = msm_gpio_configure,
+			.get_irq_num = msm_gpio_get_irq_num,
+			.read = msm_gpio_read,
+			.write = msm_gpio_write,
+			.read_detect_status = msm_gpio_read_detect_status,
+			.clear_detect_status = msm_gpio_clear_detect_status
+		}
+	},
+#endif
+};
+
+static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
+{
+	int loop_limit = 100;
+	unsigned pol, val, val2, intstat;
+	do {
+		val = readl(msm_chip->regs.in);
+		pol = readl(msm_chip->regs.int_pos);
+		pol = (pol & ~msm_chip->both_edge_detect) |
+		      (~val & msm_chip->both_edge_detect);
+		writel(pol, msm_chip->regs.int_pos);
+		intstat = readl(msm_chip->regs.int_status);
+		val2 = readl(msm_chip->regs.in);
+		if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
+			return;
+	} while (loop_limit-- > 0);
+	printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
+	       "failed to reach stable state %x != %x\n", val, val2);
+}
+
+static int msm_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
+{
+	struct msm_gpio_chip *msm_chip =
+		container_of(chip, struct msm_gpio_chip, chip);
+	unsigned b = 1U << (n - chip->start);
+	unsigned v;
+
+	v = readl(msm_chip->regs.out);
+	if (on)
+		writel(v | b, msm_chip->regs.out);
+	else
+		writel(v & (~b), msm_chip->regs.out);
+	return 0;
+}
+
+static int msm_gpio_read(struct gpio_chip *chip, unsigned n)
+{
+	struct msm_gpio_chip *msm_chip =
+		container_of(chip, struct msm_gpio_chip, chip);
+	unsigned b = 1U << (n - chip->start);
+
+	return (readl(msm_chip->regs.in) & b) ? 1 : 0;
+}
+
+static int msm_gpio_read_detect_status(struct gpio_chip *chip,
+				       unsigned int gpio)
+{
+	struct msm_gpio_chip *msm_chip =
+		container_of(chip, struct msm_gpio_chip, chip);
+	unsigned b = 1U << (gpio - chip->start);
+	unsigned v;
+
+	v = readl(msm_chip->regs.int_status);
+#if MSM_GPIO_BROKEN_INT_CLEAR
+	v |= msm_chip->int_status_copy;
+#endif
+	return (v & b) ? 1 : 0;
+}
+
+static int msm_gpio_clear_detect_status(struct gpio_chip *chip,
+					unsigned int gpio)
+{
+	struct msm_gpio_chip *msm_chip =
+		container_of(chip, struct msm_gpio_chip, chip);
+	unsigned b = 1U << (gpio - chip->start);
+
+#if MSM_GPIO_BROKEN_INT_CLEAR
+	/* Save interrupts that already triggered before we loose them. */
+	/* Any interrupt that triggers between the read of int_status */
+	/* and the write to int_clear will still be lost though. */
+	msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+	msm_chip->int_status_copy &= ~b;
+#endif
+	writel(b, msm_chip->regs.int_clear);
+	msm_gpio_update_both_edge_detect(msm_chip);
+	return 0;
+}
+
+int msm_gpio_configure(struct gpio_chip *chip, unsigned int gpio,
+		       unsigned long flags)
+{
+	struct msm_gpio_chip *msm_chip =
+		container_of(chip, struct msm_gpio_chip, chip);
+	unsigned b = 1U << (gpio - chip->start);
+	unsigned v;
+
+	if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH))
+		msm_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH);
+
+	if (flags & (GPIOF_INPUT | GPIOF_DRIVE_OUTPUT)) {
+		v = readl(msm_chip->regs.oe);
+		if (flags & GPIOF_DRIVE_OUTPUT)
+			writel(v | b, msm_chip->regs.oe);
+		else
+			writel(v & (~b), msm_chip->regs.oe);
+	}
+
+	if (flags & (IRQF_TRIGGER_MASK | GPIOF_IRQF_TRIGGER_NONE)) {
+		v = readl(msm_chip->regs.int_edge);
+		if (flags & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
+			writel(v | b, msm_chip->regs.int_edge);
+			irq_desc[MSM_GPIO_TO_INT(gpio)].handle_irq =
+				handle_edge_irq;
+		} else {
+			writel(v & (~b), msm_chip->regs.int_edge);
+			irq_desc[MSM_GPIO_TO_INT(gpio)].handle_irq =
+				handle_level_irq;
+		}
+		if ((flags & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) ==
+			(IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
+			msm_chip->both_edge_detect |= b;
+			msm_gpio_update_both_edge_detect(msm_chip);
+		} else {
+			msm_chip->both_edge_detect &= ~b;
+			v = readl(msm_chip->regs.int_pos);
+			if (flags &
+				(IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH)) {
+				writel(v | b, msm_chip->regs.int_pos);
+			} else {
+				writel(v & (~b), msm_chip->regs.int_pos);
+			}
+		}
+	}
+
+	/* used by msm_gpio_irq_mask and msm_gpio_irq_unmask */
+	if (flags &
+		(MSM_GPIOF_ENABLE_INTERRUPT | MSM_GPIOF_DISABLE_INTERRUPT)) {
+		v = readl(msm_chip->regs.int_edge);
+		/* level triggered interrupts are also latched */
+		if (!(v & b))
+			msm_gpio_clear_detect_status(chip, gpio);
+		if (flags & MSM_GPIOF_ENABLE_INTERRUPT)
+			msm_chip->int_enable[0] |= b;
+		else
+			msm_chip->int_enable[0] &= ~b;
+		writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+	}
+
+	if (flags & (MSM_GPIOF_ENABLE_WAKE | MSM_GPIOF_DISABLE_WAKE)) {
+		if (flags & MSM_GPIOF_ENABLE_WAKE)
+			msm_chip->int_enable[1] |= b;
+		else
+			msm_chip->int_enable[1] &= ~b;
+	}
+
+	return 0;
+}
+
+static int msm_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio,
+				unsigned int *irqp, unsigned long *irqnumflagsp)
+{
+	*irqp = MSM_GPIO_TO_INT(gpio);
+	if (irqnumflagsp)
+		*irqnumflagsp = 0;
+	return 0;
+}
+
+
+static void msm_gpio_irq_ack(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	spin_lock_irqsave(&msm_chip->chip.lock, irq_flags);
+	msm_gpio_clear_detect_status(&msm_chip->chip, irq - FIRST_GPIO_IRQ);
+	spin_unlock_irqrestore(&msm_chip->chip.lock, irq_flags);
+}
+
+static void msm_gpio_irq_mask(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	spin_lock_irqsave(&msm_chip->chip.lock, irq_flags);
+	msm_gpio_configure(&msm_chip->chip,
+			   irq - FIRST_GPIO_IRQ, MSM_GPIOF_DISABLE_INTERRUPT);
+	spin_unlock_irqrestore(&msm_chip->chip.lock, irq_flags);
+}
+
+static void msm_gpio_irq_unmask(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	spin_lock_irqsave(&msm_chip->chip.lock, irq_flags);
+	msm_gpio_configure(&msm_chip->chip,
+			   irq - FIRST_GPIO_IRQ, MSM_GPIOF_ENABLE_INTERRUPT);
+	spin_unlock_irqrestore(&msm_chip->chip.lock, irq_flags);
+}
+
+static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	int ret;
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	spin_lock_irqsave(&msm_chip->chip.lock, irq_flags);
+	ret = msm_gpio_configure(&msm_chip->chip, irq - FIRST_GPIO_IRQ,
+		on ? MSM_GPIOF_ENABLE_WAKE : MSM_GPIOF_DISABLE_WAKE);
+	spin_unlock_irqrestore(&msm_chip->chip.lock, irq_flags);
+	return ret;
+}
+
+
+static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+	int ret;
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	spin_lock_irqsave(&msm_chip->chip.lock, irq_flags);
+	ret = msm_gpio_configure(&msm_chip->chip, irq - FIRST_GPIO_IRQ,
+				 flow_type);
+	spin_unlock_irqrestore(&msm_chip->chip.lock, irq_flags);
+	return ret;
+}
+
+static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int i, j, m;
+	unsigned v;
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
+		v = readl(msm_chip->regs.int_status);
+		v &= msm_chip->int_enable[0];
+		while (v) {
+			m = v & -v;
+			j = fls(m) - 1;
+			/* printk("%s %08x %08x bit %d gpio %d irq %d\n",
+				__func__, v, m, j, msm_chip->chip.start + j,
+				FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
+			v &= ~m;
+			generic_handle_irq(FIRST_GPIO_IRQ +
+					   msm_chip->chip.start + j);
+		}
+	}
+	desc->chip->ack(irq);
+}
+
+static struct irq_chip msm_gpio_irq_chip = {
+	.name      = "msmgpio",
+	.ack       = msm_gpio_irq_ack,
+	.mask      = msm_gpio_irq_mask,
+	.unmask    = msm_gpio_irq_unmask,
+	.set_wake  = msm_gpio_irq_set_wake,
+	.set_type  = msm_gpio_irq_set_type,
+};
+
+#define NUM_GPIO_SMEM_BANKS 6
+#define GPIO_SMEM_NUM_GROUPS 2
+#define GPIO_SMEM_MAX_PC_INTERRUPTS 8
+struct tramp_gpio_smem {
+	uint16_t num_fired[GPIO_SMEM_NUM_GROUPS];
+	uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS];
+	uint32_t enabled[NUM_GPIO_SMEM_BANKS];
+	uint32_t detection[NUM_GPIO_SMEM_BANKS];
+	uint32_t polarity[NUM_GPIO_SMEM_BANKS];
+};
+
+static void msm_gpio_sleep_int(unsigned long arg)
+{
+	int i, j;
+	struct tramp_gpio_smem *smem_gpio;
+
+	BUILD_BUG_ON(NR_GPIO_IRQS > NUM_GPIO_SMEM_BANKS * 32);
+
+	smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
+	if (smem_gpio == NULL)
+		return;
+
+	local_irq_disable();
+	for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) {
+		int count = smem_gpio->num_fired[i];
+		for (j = 0; j < count; j++) {
+			/* TODO: Check mask */
+			generic_handle_irq(
+				MSM_GPIO_TO_INT(smem_gpio->fired[i][j]));
+		}
+	}
+	local_irq_enable();
+}
+
+static DECLARE_TASKLET(msm_gpio_sleep_int_tasklet, msm_gpio_sleep_int, 0);
+
+void msm_gpio_enter_sleep(int from_idle)
+{
+	int i;
+	struct tramp_gpio_smem *smem_gpio;
+
+	smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
+
+	if (smem_gpio) {
+		for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) {
+			smem_gpio->enabled[i] = 0;
+			smem_gpio->detection[i] = 0;
+			smem_gpio->polarity[i] = 0;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		writel(msm_gpio_chips[i].int_enable[!from_idle],
+		       msm_gpio_chips[i].regs.int_en);
+		if (smem_gpio) {
+			uint32_t tmp;
+			int start, index, shiftl, shiftr;
+			start = msm_gpio_chips[i].chip.start;
+			index = start / 32;
+			shiftl = start % 32;
+			shiftr = 32 - shiftl;
+			tmp = msm_gpio_chips[i].int_enable[!from_idle];
+			smem_gpio->enabled[index] |= tmp << shiftl;
+			smem_gpio->enabled[index+1] |= tmp >> shiftr;
+			smem_gpio->detection[index] |=
+				readl(msm_gpio_chips[i].regs.int_edge) <<
+				shiftl;
+			smem_gpio->detection[index+1] |=
+				readl(msm_gpio_chips[i].regs.int_edge) >>
+				shiftr;
+			smem_gpio->polarity[index] |=
+				readl(msm_gpio_chips[i].regs.int_pos) << shiftl;
+			smem_gpio->polarity[index+1] |=
+				readl(msm_gpio_chips[i].regs.int_pos) >> shiftr;
+		}
+	}
+
+	if (smem_gpio) {
+		if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP)
+			for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) {
+				printk("msm_gpio_enter_sleep gpio %d-%d: enable"
+				       " %08x, edge %08x, polarity %08x\n",
+				       i * 32, i * 32 + 31,
+				       smem_gpio->enabled[i],
+				       smem_gpio->detection[i],
+				       smem_gpio->polarity[i]);
+			}
+		for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++)
+			smem_gpio->num_fired[i] = 0;
+	}
+}
+
+void msm_gpio_exit_sleep(void)
+{
+	int i;
+	struct tramp_gpio_smem *smem_gpio;
+
+	smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		writel(msm_gpio_chips[i].int_enable[0],
+		       msm_gpio_chips[i].regs.int_en);
+	}
+
+	if (smem_gpio && (smem_gpio->num_fired[0] || smem_gpio->num_fired[1])) {
+		if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP)
+			printk(KERN_INFO "gpio: fired %x %x\n",
+			      smem_gpio->num_fired[0], smem_gpio->num_fired[1]);
+		tasklet_schedule(&msm_gpio_sleep_int_tasklet);
+	}
+}
+
+static int __init msm_init_gpio(void)
+{
+	int i, j = 0;
+
+	for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
+		if (i - FIRST_GPIO_IRQ > msm_gpio_chips[j].chip.end)
+			j++;
+		set_irq_chip_data(i, &msm_gpio_chips[j]);
+		set_irq_chip(i, &msm_gpio_irq_chip);
+		set_irq_handler(i, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		writel(0, msm_gpio_chips[i].regs.int_en);
+		register_gpio_chip(&msm_gpio_chips[i].chip);
+	}
+
+	set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
+	set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
+	set_irq_wake(INT_GPIO_GROUP1, 1);
+	set_irq_wake(INT_GPIO_GROUP2, 2);
+	return 0;
+}
+
+postcore_initcall(msm_init_gpio);
 
 int gpio_tlmm_config(unsigned config, unsigned disable)
 {
diff --git a/arch/arm/mach-msm/gpio_chip.h b/arch/arm/mach-msm/gpio_chip.h
new file mode 100644
index 0000000..b5165c3
--- /dev/null
+++ b/arch/arm/mach-msm/gpio_chip.h
@@ -0,0 +1,51 @@
+/* arch/arm/mach-msm/gpio_chip.h
+ *
+ * Copyright (C) 2007 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.
+ *
+ */
+
+#ifndef _LINUX_GPIO_CHIP_H
+#define _LINUX_GPIO_CHIP_H
+
+#include <linux/list.h>
+#include <linux/gpio.h>
+
+/* use to specify edge detection without */
+#define GPIOF_IRQF_MASK         0x0000ffff
+/* IRQF_TRIGGER_NONE is 0 which also means "as already configured" */
+#define GPIOF_IRQF_TRIGGER_NONE 0x00010000
+#define GPIOF_INPUT             0x00020000
+#define GPIOF_DRIVE_OUTPUT      0x00040000
+#define GPIOF_OUTPUT_LOW        0x00080000
+#define GPIOF_OUTPUT_HIGH       0x00100000
+
+struct old_gpio_chip {
+	struct gpio_chip gpio_chip;
+#define gpio_chip old_gpio_chip
+
+	spinlock_t lock;
+	unsigned int start;
+	unsigned int end;
+
+	int (*configure)(struct gpio_chip *chip, unsigned int gpio,
+			 unsigned long flags);
+	int (*get_irq_num)(struct gpio_chip *chip, unsigned int gpio,
+			   unsigned int *irqp, unsigned long *irqnumflagsp);
+	int (*read)(struct gpio_chip *chip, unsigned int gpio);
+	int (*write)(struct gpio_chip *chip, unsigned int gpio, unsigned on);
+	int (*read_detect_status)(struct gpio_chip *chip, unsigned int gpio);
+	int (*clear_detect_status)(struct gpio_chip *chip, unsigned int gpio);
+};
+
+int register_gpio_chip(struct gpio_chip *gpio_chip);
+
+#endif
diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
new file mode 100644
index 0000000..4634463
--- /dev/null
+++ b/arch/arm/mach-msm/gpio_hw.h
@@ -0,0 +1,276 @@
+/* arch/arm/mach-msm/gpio_hw.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
+#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
+
+#include <mach/msm_iomap.h>
+
+/* see 80-VA736-2 Rev C pp 695-751
+**
+** These are actually the *shadow* gpio registers, since the
+** real ones (which allow full access) are only available to the
+** ARM9 side of the world.
+**
+** Since the _BASE need to be page-aligned when we're mapping them
+** to virtual addresses, adjust for the additional offset in these
+** macros.
+*/
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define GPIO1_REG(off) (MSM_GPIO1_BASE + (off))
+#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off))
+#else
+#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
+#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X00A)
+
+/* output value */
+#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0  */
+#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16 */
+#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43 */
+#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68 */
+#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 106-95 */
+#define GPIO_OUT_5         GPIO1_REG(0x50)  /* gpio 107-121 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0          GPIO1_REG(0x10)
+#define GPIO_OE_1          GPIO2_REG(0x08)
+#define GPIO_OE_2          GPIO1_REG(0x14)
+#define GPIO_OE_3          GPIO1_REG(0x18)
+#define GPIO_OE_4          GPIO1_REG(0x1C)
+#define GPIO_OE_5          GPIO1_REG(0x54)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0          GPIO1_REG(0x34)
+#define GPIO_IN_1          GPIO2_REG(0x20)
+#define GPIO_IN_2          GPIO1_REG(0x38)
+#define GPIO_IN_3          GPIO1_REG(0x3C)
+#define GPIO_IN_4          GPIO1_REG(0x40)
+#define GPIO_IN_5          GPIO1_REG(0x44)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0    GPIO1_REG(0x60)
+#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2    GPIO1_REG(0x64)
+#define GPIO_INT_EDGE_3    GPIO1_REG(0x68)
+#define GPIO_INT_EDGE_4    GPIO1_REG(0x6C)
+#define GPIO_INT_EDGE_5    GPIO1_REG(0xC0)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0     GPIO1_REG(0x70)
+#define GPIO_INT_POS_1     GPIO2_REG(0x58)
+#define GPIO_INT_POS_2     GPIO1_REG(0x74)
+#define GPIO_INT_POS_3     GPIO1_REG(0x78)
+#define GPIO_INT_POS_4     GPIO1_REG(0x7C)
+#define GPIO_INT_POS_5     GPIO1_REG(0xBC)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0      GPIO1_REG(0x80)
+#define GPIO_INT_EN_1      GPIO2_REG(0x60)
+#define GPIO_INT_EN_2      GPIO1_REG(0x84)
+#define GPIO_INT_EN_3      GPIO1_REG(0x88)
+#define GPIO_INT_EN_4      GPIO1_REG(0x8C)
+#define GPIO_INT_EN_5      GPIO1_REG(0xB8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0   GPIO1_REG(0x90)
+#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2   GPIO1_REG(0x94)
+#define GPIO_INT_CLEAR_3   GPIO1_REG(0x98)
+#define GPIO_INT_CLEAR_4   GPIO1_REG(0x9C)
+#define GPIO_INT_CLEAR_5   GPIO1_REG(0xB4)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0  GPIO1_REG(0xA0)
+#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2  GPIO1_REG(0xA4)
+#define GPIO_INT_STATUS_3  GPIO1_REG(0xA8)
+#define GPIO_INT_STATUS_4  GPIO1_REG(0xAC)
+#define GPIO_INT_STATUS_5  GPIO1_REG(0xB0)
+
+#endif
+
+#if defined(CONFIG_ARCH_QSD8X50)
+/* output value */
+#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0   */
+#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16  */
+#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43  */
+#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68  */
+#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 103-95  */
+#define GPIO_OUT_5         GPIO1_REG(0x10)  /* gpio 121-104 */
+#define GPIO_OUT_6         GPIO1_REG(0x14)  /* gpio 152-122 */
+#define GPIO_OUT_7         GPIO1_REG(0x18)  /* gpio 164-153 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0          GPIO1_REG(0x20)
+#define GPIO_OE_1          GPIO2_REG(0x08)
+#define GPIO_OE_2          GPIO1_REG(0x24)
+#define GPIO_OE_3          GPIO1_REG(0x28)
+#define GPIO_OE_4          GPIO1_REG(0x2C)
+#define GPIO_OE_5          GPIO1_REG(0x30)
+#define GPIO_OE_6          GPIO1_REG(0x34)
+#define GPIO_OE_7          GPIO1_REG(0x38)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0          GPIO1_REG(0x50)
+#define GPIO_IN_1          GPIO2_REG(0x20)
+#define GPIO_IN_2          GPIO1_REG(0x54)
+#define GPIO_IN_3          GPIO1_REG(0x58)
+#define GPIO_IN_4          GPIO1_REG(0x5C)
+#define GPIO_IN_5          GPIO1_REG(0x60)
+#define GPIO_IN_6          GPIO1_REG(0x64)
+#define GPIO_IN_7          GPIO1_REG(0x68)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0    GPIO1_REG(0x70)
+#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2    GPIO1_REG(0x74)
+#define GPIO_INT_EDGE_3    GPIO1_REG(0x78)
+#define GPIO_INT_EDGE_4    GPIO1_REG(0x7C)
+#define GPIO_INT_EDGE_5    GPIO1_REG(0x80)
+#define GPIO_INT_EDGE_6    GPIO1_REG(0x84)
+#define GPIO_INT_EDGE_7    GPIO1_REG(0x88)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0     GPIO1_REG(0x90)
+#define GPIO_INT_POS_1     GPIO2_REG(0x58)
+#define GPIO_INT_POS_2     GPIO1_REG(0x94)
+#define GPIO_INT_POS_3     GPIO1_REG(0x98)
+#define GPIO_INT_POS_4     GPIO1_REG(0x9C)
+#define GPIO_INT_POS_5     GPIO1_REG(0xA0)
+#define GPIO_INT_POS_6     GPIO1_REG(0xA4)
+#define GPIO_INT_POS_7     GPIO1_REG(0xA8)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0      GPIO1_REG(0xB0)
+#define GPIO_INT_EN_1      GPIO2_REG(0x60)
+#define GPIO_INT_EN_2      GPIO1_REG(0xB4)
+#define GPIO_INT_EN_3      GPIO1_REG(0xB8)
+#define GPIO_INT_EN_4      GPIO1_REG(0xBC)
+#define GPIO_INT_EN_5      GPIO1_REG(0xC0)
+#define GPIO_INT_EN_6      GPIO1_REG(0xC4)
+#define GPIO_INT_EN_7      GPIO1_REG(0xC8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0   GPIO1_REG(0xD0)
+#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2   GPIO1_REG(0xD4)
+#define GPIO_INT_CLEAR_3   GPIO1_REG(0xD8)
+#define GPIO_INT_CLEAR_4   GPIO1_REG(0xDC)
+#define GPIO_INT_CLEAR_5   GPIO1_REG(0xE0)
+#define GPIO_INT_CLEAR_6   GPIO1_REG(0xE4)
+#define GPIO_INT_CLEAR_7   GPIO1_REG(0xE8)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0  GPIO1_REG(0xF0)
+#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2  GPIO1_REG(0xF4)
+#define GPIO_INT_STATUS_3  GPIO1_REG(0xF8)
+#define GPIO_INT_STATUS_4  GPIO1_REG(0xFC)
+#define GPIO_INT_STATUS_5  GPIO1_REG(0x100)
+#define GPIO_INT_STATUS_6  GPIO1_REG(0x104)
+#define GPIO_INT_STATUS_7  GPIO1_REG(0x108)
+
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X30)
+
+/* output value */
+#define GPIO_OUT_0         GPIO1_REG(0x00)   /* gpio  15-0   */
+#define GPIO_OUT_1         GPIO2_REG(0x00)   /* gpio  43-16  */
+#define GPIO_OUT_2         GPIO1_REG(0x04)   /* gpio  67-44  */
+#define GPIO_OUT_3         GPIO1_REG(0x08)   /* gpio  94-68  */
+#define GPIO_OUT_4         GPIO1_REG(0x0C)   /* gpio 106-95  */
+#define GPIO_OUT_5         GPIO1_REG(0x50)   /* gpio 133-107 */
+#define GPIO_OUT_6         GPIO1_REG(0xC4)   /* gpio 150-134 */
+#define GPIO_OUT_7         GPIO1_REG(0x214)  /* gpio 181-151 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0          GPIO1_REG(0x10)
+#define GPIO_OE_1          GPIO2_REG(0x08)
+#define GPIO_OE_2          GPIO1_REG(0x14)
+#define GPIO_OE_3          GPIO1_REG(0x18)
+#define GPIO_OE_4          GPIO1_REG(0x1C)
+#define GPIO_OE_5          GPIO1_REG(0x54)
+#define GPIO_OE_6          GPIO1_REG(0xC8)
+#define GPIO_OE_7          GPIO1_REG(0x218)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0          GPIO1_REG(0x34)
+#define GPIO_IN_1          GPIO2_REG(0x20)
+#define GPIO_IN_2          GPIO1_REG(0x38)
+#define GPIO_IN_3          GPIO1_REG(0x3C)
+#define GPIO_IN_4          GPIO1_REG(0x40)
+#define GPIO_IN_5          GPIO1_REG(0x44)
+#define GPIO_IN_6          GPIO1_REG(0xCC)
+#define GPIO_IN_7          GPIO1_REG(0x21C)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0    GPIO1_REG(0x60)
+#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2    GPIO1_REG(0x64)
+#define GPIO_INT_EDGE_3    GPIO1_REG(0x68)
+#define GPIO_INT_EDGE_4    GPIO1_REG(0x6C)
+#define GPIO_INT_EDGE_5    GPIO1_REG(0xC0)
+#define GPIO_INT_EDGE_6    GPIO1_REG(0xD0)
+#define GPIO_INT_EDGE_7    GPIO1_REG(0x240)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0     GPIO1_REG(0x70)
+#define GPIO_INT_POS_1     GPIO2_REG(0x58)
+#define GPIO_INT_POS_2     GPIO1_REG(0x74)
+#define GPIO_INT_POS_3     GPIO1_REG(0x78)
+#define GPIO_INT_POS_4     GPIO1_REG(0x7C)
+#define GPIO_INT_POS_5     GPIO1_REG(0xBC)
+#define GPIO_INT_POS_6     GPIO1_REG(0xD4)
+#define GPIO_INT_POS_7     GPIO1_REG(0x228)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0      GPIO1_REG(0x80)
+#define GPIO_INT_EN_1      GPIO2_REG(0x60)
+#define GPIO_INT_EN_2      GPIO1_REG(0x84)
+#define GPIO_INT_EN_3      GPIO1_REG(0x88)
+#define GPIO_INT_EN_4      GPIO1_REG(0x8C)
+#define GPIO_INT_EN_5      GPIO1_REG(0xB8)
+#define GPIO_INT_EN_6      GPIO1_REG(0xD8)
+#define GPIO_INT_EN_7      GPIO1_REG(0x22C)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0   GPIO1_REG(0x90)
+#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2   GPIO1_REG(0x94)
+#define GPIO_INT_CLEAR_3   GPIO1_REG(0x98)
+#define GPIO_INT_CLEAR_4   GPIO1_REG(0x9C)
+#define GPIO_INT_CLEAR_5   GPIO1_REG(0xB4)
+#define GPIO_INT_CLEAR_6   GPIO1_REG(0xDC)
+#define GPIO_INT_CLEAR_7   GPIO1_REG(0x230)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0  GPIO1_REG(0xA0)
+#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2  GPIO1_REG(0xA4)
+#define GPIO_INT_STATUS_3  GPIO1_REG(0xA8)
+#define GPIO_INT_STATUS_4  GPIO1_REG(0xAC)
+#define GPIO_INT_STATUS_5  GPIO1_REG(0xB0)
+#define GPIO_INT_STATUS_6  GPIO1_REG(0xE0)
+#define GPIO_INT_STATUS_7  GPIO1_REG(0x234)
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/htc_35mm_jack.c b/arch/arm/mach-msm/htc_35mm_jack.c
new file mode 100644
index 0000000..a956472
--- /dev/null
+++ b/arch/arm/mach-msm/htc_35mm_jack.c
@@ -0,0 +1,398 @@
+/* arch/arm/mach-msm/htc_35mm_jack.c
+ *
+ * Copyright (C) 2009 HTC, Inc.
+ * Author: Arec Kao <Arec_Kao@htc.com>
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Eric Olsen <eolsen@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/module.h>
+#include <linux/slab.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/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/debugfs.h>
+#include <linux/jiffies.h>
+#include <linux/switch.h>
+#include <linux/input.h>
+#include <linux/wakelock.h>
+#include <asm/gpio.h>
+#include <asm/atomic.h>
+#include <mach/board.h>
+#include <mach/vreg.h>
+#include <asm/mach-types.h>
+#include <mach/htc_acoustic_qsd.h>
+#include <mach/htc_35mm_jack.h>
+#include <mach/htc_headset.h>
+
+#ifdef CONFIG_HTC_AUDIOJACK
+#include <mach/audio_jack.h>
+#endif
+
+/* #define CONFIG_DEBUG_H2W */
+
+#define H2WI(fmt, arg...) \
+	printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
+#define H2WE(fmt, arg...) \
+	printk(KERN_ERR "[H2W] %s " fmt "\r\n", __func__, ## arg)
+
+#ifdef CONFIG_DEBUG_H2W
+#define H2W_DBG(fmt, arg...) \
+	printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
+#else
+#define H2W_DBG(fmt, arg...) do {} while (0)
+#endif
+
+void detect_h2w_do_work(struct work_struct *w);
+
+static struct workqueue_struct *detect_wq;
+static struct workqueue_struct *button_wq;
+
+static DECLARE_DELAYED_WORK(detect_h2w_work, detect_h2w_do_work);
+
+static void insert_35mm_do_work(struct work_struct *work);
+static DECLARE_WORK(insert_35mm_work, insert_35mm_do_work);
+static void remove_35mm_do_work(struct work_struct *work);
+static DECLARE_WORK(remove_35mm_work, remove_35mm_do_work);
+static void button_35mm_do_work(struct work_struct *work);
+static DECLARE_WORK(button_35mm_work, button_35mm_do_work);
+
+struct h35_info {
+	struct mutex mutex_lock;
+	struct switch_dev hs_change;
+	unsigned long insert_jiffies;
+	int ext_35mm_status;
+	int is_ext_insert;
+	int key_code;
+	int mic_bias_state;
+	int *is_hpin_stable;
+	struct input_dev *input;
+
+	struct wake_lock headset_wake_lock;
+};
+
+static struct h35mm_platform_data *pd;
+static struct h35_info *hi;
+
+static ssize_t h35mm_print_name(struct switch_dev *sdev, char *buf)
+{
+	return sprintf(buf, "Headset\n");
+}
+
+static void button_35mm_do_work(struct work_struct *work)
+{
+	int key = 0;
+	int pressed = 0;
+
+	if (!hi->is_ext_insert) {
+		/* no headset ignor key event */
+		H2WI("3.5mm headset is plugged out, skip report key event");
+		return;
+	}
+
+	switch (hi->key_code) {
+	case 0x1: /* Play/Pause */
+		H2WI("3.5mm RC: Play Pressed");
+		key = KEY_MEDIA;
+		pressed = 1;
+		break;
+	case 0x2:
+		H2WI("3.5mm RC: BACKWARD Pressed");
+		key = KEY_PREVIOUSSONG;
+		pressed = 1;
+		break;
+	case 0x3:
+		H2WI("3.5mm RC: FORWARD Pressed");
+		key = KEY_NEXTSONG;
+		pressed = 1;
+		break;
+	case 0x81: /* Play/Pause */
+		H2WI("3.5mm RC: Play Released");
+		key = KEY_MEDIA;
+		pressed = 0;
+		break;
+	case 0x82:
+		H2WI("3.5mm RC: BACKWARD Released");
+		key = KEY_PREVIOUSSONG;
+		pressed = 0;
+		break;
+	case 0x83:
+		H2WI("3.5mm RC: FORWARD Released");
+		key = KEY_NEXTSONG;
+		pressed = 0;
+		break;
+	default:
+		H2WI("3.5mm RC: Unknown Button (0x%x) Pressed", hi->key_code);
+		return;
+	}
+	input_report_key(hi->input, key, pressed);
+	input_sync(hi->input);
+
+	wake_lock_timeout(&hi->headset_wake_lock, 1.5*HZ);
+}
+
+static void remove_35mm_do_work(struct work_struct *work)
+{
+	wake_lock_timeout(&hi->headset_wake_lock, 2.5*HZ);
+
+	H2W_DBG("");
+	/*To solve the insert, remove, insert headset problem*/
+	if (time_before_eq(jiffies, hi->insert_jiffies))
+		msleep(800);
+
+	if (hi->is_ext_insert) {
+		H2WI("Skip 3.5mm headset plug out!!!");
+		if (hi->is_hpin_stable)
+			*(hi->is_hpin_stable) = 1;
+		return;
+	}
+
+	pr_info("3.5mm_headset plug out\n");
+
+	if (pd->key_event_disable != NULL)
+		pd->key_event_disable();
+
+	if (hi->mic_bias_state) {
+		turn_mic_bias_on(0);
+		hi->mic_bias_state = 0;
+	}
+	hi->ext_35mm_status = 0;
+	if (hi->is_hpin_stable)
+		*(hi->is_hpin_stable) = 0;
+
+	/* Notify framework via switch class */
+	mutex_lock(&hi->mutex_lock);
+	switch_set_state(&hi->hs_change, hi->ext_35mm_status);
+	mutex_unlock(&hi->mutex_lock);
+}
+
+static void insert_35mm_do_work(struct work_struct *work)
+{
+	H2W_DBG("");
+	hi->insert_jiffies = jiffies + 1*HZ;
+
+	wake_lock_timeout(&hi->headset_wake_lock, 1.5*HZ);
+
+	if (hi->is_ext_insert) {
+		pr_info("3.5mm_headset plug in\n");
+
+	if (pd->key_event_enable != NULL)
+		pd->key_event_enable();
+
+		/* Turn On Mic Bias */
+		if (!hi->mic_bias_state) {
+			turn_mic_bias_on(1);
+			hi->mic_bias_state = 1;
+			/* Wait for pin stable */
+			msleep(300);
+		}
+
+		/* Detect headset with or without microphone */
+		if(pd->headset_has_mic) {
+			if (pd->headset_has_mic() == 0) {
+				/* without microphone */
+				pr_info("3.5mm without microphone\n");
+				hi->ext_35mm_status = BIT_HEADSET_NO_MIC;
+			} else { /* with microphone */
+				pr_info("3.5mm with microphone\n");
+				hi->ext_35mm_status = BIT_HEADSET;
+			}
+		} else {
+			/* Assume no mic */
+			pr_info("3.5mm without microphone\n");
+			hi->ext_35mm_status = BIT_HEADSET_NO_MIC;
+		}
+		hi->ext_35mm_status |= BIT_35MM_HEADSET;
+
+		/* Notify framework via switch class */
+		mutex_lock(&hi->mutex_lock);
+		switch_set_state(&hi->hs_change, hi->ext_35mm_status);
+		mutex_unlock(&hi->mutex_lock);
+
+		if (hi->is_hpin_stable)
+			*(hi->is_hpin_stable) = 1;
+	}
+}
+
+int htc_35mm_key_event(int keycode, int *hpin_stable)
+{
+	hi->key_code = keycode;
+	hi->is_hpin_stable = hpin_stable;
+
+	if ((hi->ext_35mm_status & BIT_HEADSET) == 0) {
+		*(hi->is_hpin_stable) = 0;
+
+		pr_info("Key press with no mic.  Retrying detection\n");
+		queue_work(detect_wq, &insert_35mm_work);
+	} else
+		queue_work(button_wq, &button_35mm_work);
+
+	return 0;
+}
+
+int htc_35mm_jack_plug_event(int insert, int *hpin_stable)
+{
+	if (!hi) {
+		pr_err("Plug event before driver init\n");
+		return -1;
+	}
+
+	mutex_lock(&hi->mutex_lock);
+	hi->is_ext_insert = insert;
+	hi->is_hpin_stable = hpin_stable;
+	mutex_unlock(&hi->mutex_lock);
+
+	H2WI(" %d", hi->is_ext_insert);
+	if (!hi->is_ext_insert)
+		queue_work(detect_wq, &remove_35mm_work);
+	else
+		queue_work(detect_wq, &insert_35mm_work);
+	return 1;
+}
+
+static int htc_35mm_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	pd = pdev->dev.platform_data;
+
+	pr_info("H2W: htc_35mm_jack driver register\n");
+
+	hi = kzalloc(sizeof(struct h35_info), GFP_KERNEL);
+	if (!hi)
+		return -ENOMEM;
+
+	hi->ext_35mm_status = 0;
+	hi->is_ext_insert = 0;
+	hi->mic_bias_state = 0;
+
+	mutex_init(&hi->mutex_lock);
+
+	wake_lock_init(&hi->headset_wake_lock, WAKE_LOCK_SUSPEND, "headset");
+
+	hi->hs_change.name = "h2w";
+	hi->hs_change.print_name = h35mm_print_name;
+	ret = switch_dev_register(&hi->hs_change);
+	if (ret < 0)
+		goto err_switch_dev_register;
+
+	detect_wq = create_workqueue("detection");
+	if (detect_wq  == NULL) {
+		ret = -ENOMEM;
+		goto err_create_detect_work_queue;
+	}
+
+	button_wq = create_workqueue("button");
+	if (button_wq  == NULL) {
+			ret = -ENOMEM;
+			goto err_create_button_work_queue;
+	}
+
+	hi->input = input_allocate_device();
+	if (!hi->input) {
+		ret = -ENOMEM;
+		goto err_request_input_dev;
+	}
+
+	hi->input->name = "h2w headset";
+	set_bit(EV_SYN, hi->input->evbit);
+	set_bit(EV_KEY, hi->input->evbit);
+	set_bit(KEY_MEDIA, hi->input->keybit);
+	set_bit(KEY_NEXTSONG, hi->input->keybit);
+	set_bit(KEY_PLAYPAUSE, hi->input->keybit);
+	set_bit(KEY_PREVIOUSSONG, hi->input->keybit);
+	set_bit(KEY_MUTE, hi->input->keybit);
+	set_bit(KEY_VOLUMEUP, hi->input->keybit);
+	set_bit(KEY_VOLUMEDOWN, hi->input->keybit);
+	set_bit(KEY_END, hi->input->keybit);
+	set_bit(KEY_SEND, hi->input->keybit);
+
+	ret = input_register_device(hi->input);
+	if (ret < 0)
+	goto err_register_input_dev;
+
+	/* Enable plug events*/
+	if (pd->plug_event_enable == NULL) {
+		ret = -ENOMEM;
+		goto err_enable_plug_event;
+	}
+	if (pd->plug_event_enable() != 1)  {
+		ret = -ENOMEM;
+		goto err_enable_plug_event;
+	}
+
+	return 0;
+
+err_enable_plug_event:
+err_register_input_dev:
+	input_free_device(hi->input);
+err_request_input_dev:
+	destroy_workqueue(button_wq);
+err_create_button_work_queue:
+	destroy_workqueue(detect_wq);
+err_create_detect_work_queue:
+	switch_dev_unregister(&hi->hs_change);
+err_switch_dev_register:
+	kzfree(hi);
+	pr_err("H2W: Failed to register driver\n");
+
+	return ret;
+}
+
+static int htc_35mm_remove(struct platform_device *pdev)
+{
+	H2W_DBG("");
+	switch_dev_unregister(&hi->hs_change);
+	kzfree(hi);
+
+#if 0 /* Add keys later */
+	input_unregister_device(hi->input);
+#endif
+	return 0;
+}
+
+static struct platform_driver htc_35mm_driver = {
+	.probe		= htc_35mm_probe,
+	.remove		= htc_35mm_remove,
+	.driver		= {
+		.name		= "htc_headset",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init htc_35mm_init(void)
+{
+	H2W_DBG("");
+	return platform_driver_register(&htc_35mm_driver);
+}
+
+static void __exit htc_35mm_exit(void)
+{
+	platform_driver_unregister(&htc_35mm_driver);
+}
+
+module_init(htc_35mm_init);
+module_exit(htc_35mm_exit);
+
+MODULE_AUTHOR("Eric Olsen <eolsen@android.com>");
+MODULE_DESCRIPTION("HTC 3.5MM Driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/htc_acoustic.c b/arch/arm/mach-msm/htc_acoustic.c
new file mode 100644
index 0000000..2360b37
--- /dev/null
+++ b/arch/arm/mach-msm/htc_acoustic.c
@@ -0,0 +1,266 @@
+/* arch/arm/mach-msm/htc_acoustic.c
+ *
+ * Copyright (C) 2007-2008 HTC Corporation
+ * Author: Laurence Chen <Laurence_Chen@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/device.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+
+#include <mach/msm_smd.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_iomap.h>
+
+#include "smd_private.h"
+
+#define ACOUSTIC_IOCTL_MAGIC 'p'
+#define ACOUSTIC_ARM11_DONE	_IOW(ACOUSTIC_IOCTL_MAGIC, 22, unsigned int)
+
+#define HTCRPOG 0x30100002
+#define HTCVERS MSM_RPC_VERS(0,0)
+#define ONCRPC_SET_MIC_BIAS_PROC       (1)
+#define ONCRPC_ACOUSTIC_INIT_PROC      (5)
+#define ONCRPC_ALLOC_ACOUSTIC_MEM_PROC (6)
+
+#define HTC_ACOUSTIC_TABLE_SIZE        (0x10000)
+
+#define D(fmt, args...) printk(KERN_INFO "htc-acoustic: "fmt, ##args)
+#define E(fmt, args...) printk(KERN_ERR "htc-acoustic: "fmt, ##args)
+
+struct set_smem_req {
+	struct rpc_request_hdr hdr;
+	uint32_t size;
+};
+
+struct set_smem_rep {
+	struct rpc_reply_hdr hdr;
+	int n;
+};
+
+struct set_acoustic_req {
+	struct rpc_request_hdr hdr;
+};
+
+struct set_acoustic_rep {
+	struct rpc_reply_hdr hdr;
+	int n;
+};
+
+static uint32_t htc_acoustic_vir_addr;
+static struct msm_rpc_endpoint *endpoint;
+static struct mutex api_lock;
+static struct mutex rpc_connect_mutex;
+
+static int is_rpc_connect(void)
+{
+	mutex_lock(&rpc_connect_mutex);
+	if (endpoint == NULL) {
+		endpoint = msm_rpc_connect(HTCRPOG, HTCVERS, 0);
+		if (IS_ERR(endpoint)) {
+			pr_err("%s: init rpc failed! rc = %ld\n",
+				__func__, PTR_ERR(endpoint));
+			mutex_unlock(&rpc_connect_mutex);
+			return 0;
+		}
+	}
+	mutex_unlock(&rpc_connect_mutex);
+	return 1;
+}
+
+int turn_mic_bias_on(int on)
+{
+	struct mic_bias_req {
+		struct rpc_request_hdr hdr;
+		uint32_t on;
+	} req;
+
+	if (!is_rpc_connect())
+		return -1;
+
+	req.on = cpu_to_be32(on);
+	return msm_rpc_call(endpoint, ONCRPC_SET_MIC_BIAS_PROC,
+			    &req, sizeof(req), 5 * HZ);
+}
+EXPORT_SYMBOL(turn_mic_bias_on);
+
+static int acoustic_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long pgoff, delta;
+	int rc = -EINVAL;
+	size_t size;
+
+	D("mmap\n");
+
+	mutex_lock(&api_lock);
+
+	size = vma->vm_end - vma->vm_start;
+
+	if (vma->vm_pgoff != 0) {
+		E("mmap failed: page offset %lx\n", vma->vm_pgoff);
+		goto done;
+	}
+
+	if (!htc_acoustic_vir_addr) {
+		E("mmap failed: smem region not allocated\n");
+		rc = -EIO;
+		goto done;
+	}
+
+	pgoff = MSM_SHARED_RAM_PHYS +
+		(htc_acoustic_vir_addr - (uint32_t)MSM_SHARED_RAM_BASE);
+	delta = PAGE_ALIGN(pgoff) - pgoff;
+
+	if (size + delta > HTC_ACOUSTIC_TABLE_SIZE) {
+		E("mmap failed: size %d\n", size);
+		goto done;
+	}
+
+	pgoff += delta;
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+
+	rc = io_remap_pfn_range(vma, vma->vm_start, pgoff >> PAGE_SHIFT,
+		      size, vma->vm_page_prot);
+
+	if (rc < 0)
+		E("mmap failed: remap error %d\n", rc);
+
+done:	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static int acoustic_open(struct inode *inode, struct file *file)
+{
+	int rc = -EIO;
+	struct set_smem_req req_smem;
+	struct set_smem_rep rep_smem;
+
+	D("open\n");
+
+	mutex_lock(&api_lock);
+
+	if (!htc_acoustic_vir_addr) {
+		if (!is_rpc_connect())
+			goto done;
+
+		req_smem.size = cpu_to_be32(HTC_ACOUSTIC_TABLE_SIZE);
+		rc = msm_rpc_call_reply(endpoint,
+					ONCRPC_ALLOC_ACOUSTIC_MEM_PROC,
+					&req_smem, sizeof(req_smem),
+					&rep_smem, sizeof(rep_smem),
+					5 * HZ);
+
+		if (rep_smem.n != 0 || rc < 0) {
+			E("open failed: ALLOC_ACOUSTIC_MEM_PROC error %d.\n",
+				rc);
+			goto done;
+		}
+		htc_acoustic_vir_addr =
+			(uint32_t)smem_alloc(SMEM_ID_VENDOR1,
+					HTC_ACOUSTIC_TABLE_SIZE);
+		if (!htc_acoustic_vir_addr) {
+			E("open failed: smem_alloc error\n");
+			goto done;
+		}
+	}
+
+	rc = 0;
+done:
+	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static int acoustic_release(struct inode *inode, struct file *file)
+{
+	D("release\n");
+	return 0;
+}
+
+static long acoustic_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	int rc, reply_value;
+	struct set_acoustic_req req;
+	struct set_acoustic_rep rep;
+
+	D("ioctl\n");
+
+	mutex_lock(&api_lock);
+
+	switch (cmd) {
+	case ACOUSTIC_ARM11_DONE:
+		D("ioctl: ACOUSTIC_ARM11_DONE called %d.\n", current->pid);
+		rc = msm_rpc_call_reply(endpoint,
+					ONCRPC_ACOUSTIC_INIT_PROC, &req,
+					sizeof(req), &rep, sizeof(rep),
+					5 * HZ);
+
+		reply_value = be32_to_cpu(rep.n);
+		if (reply_value != 0 || rc < 0) {
+			E("ioctl failed: ONCRPC_ACOUSTIC_INIT_PROC "\
+				"error %d.\n", rc);
+			if (rc >= 0)
+				rc = -EIO;
+			break;
+		}
+		D("ioctl: ONCRPC_ACOUSTIC_INIT_PROC success.\n");
+		break;
+	default:
+		E("ioctl: invalid command\n");
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&api_lock);
+	return 0;
+}
+
+
+static struct file_operations acoustic_fops = {
+	.owner = THIS_MODULE,
+	.open = acoustic_open,
+	.release = acoustic_release,
+	.mmap = acoustic_mmap,
+	.unlocked_ioctl = acoustic_ioctl,
+};
+
+static struct miscdevice acoustic_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "htc-acoustic",
+	.fops = &acoustic_fops,
+};
+
+static int __init acoustic_init(void)
+{
+	mutex_init(&api_lock);
+	mutex_init(&rpc_connect_mutex);
+	return misc_register(&acoustic_misc);
+}
+
+static void __exit acoustic_exit(void)
+{
+	misc_deregister(&acoustic_misc);
+}
+
+module_init(acoustic_init);
+module_exit(acoustic_exit);
+
+MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>");
+MODULE_DESCRIPTION("HTC acoustic driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/htc_acoustic_qsd.c b/arch/arm/mach-msm/htc_acoustic_qsd.c
new file mode 100644
index 0000000..ce3c3a0
--- /dev/null
+++ b/arch/arm/mach-msm/htc_acoustic_qsd.c
@@ -0,0 +1,315 @@
+/* arch/arm/mach-msm/htc_acoustic_qsd.c
+ *
+ * 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/device.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+
+#include <mach/msm_smd.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_iomap.h>
+#include <mach/htc_acoustic_qsd.h>
+#include <mach/msm_qdsp6_audio.h>
+
+#include "smd_private.h"
+
+#define ACOUSTIC_IOCTL_MAGIC 'p'
+#define ACOUSTIC_UPDATE_ADIE \
+	_IOW(ACOUSTIC_IOCTL_MAGIC, 24, unsigned int)
+
+#define HTCACOUSTICPROG 0x30100003
+#define HTCACOUSTICVERS 0
+#define ONCRPC_ALLOC_ACOUSTIC_MEM_PROC		(1)
+#define ONCRPC_UPDATE_ADIE_PROC			(2)
+#define ONCRPC_ENABLE_AUX_PGA_LOOPBACK_PROC	(3)
+#define ONCRPC_FORCE_HEADSET_SPEAKER_PROC	(4)
+
+#define HTC_ACOUSTIC_TABLE_SIZE        (0x20000)
+
+#define D(fmt, args...) printk(KERN_INFO "htc-acoustic: "fmt, ##args)
+#define E(fmt, args...) printk(KERN_ERR "htc-acoustic: "fmt, ##args)
+
+static uint32_t htc_acoustic_vir_addr;
+static struct msm_rpc_endpoint *endpoint;
+static struct mutex api_lock;
+static struct mutex rpc_connect_lock;
+static struct qsd_acoustic_ops *the_ops;
+
+void acoustic_register_ops(struct qsd_acoustic_ops *ops)
+{
+	the_ops = ops;
+}
+
+static int is_rpc_connect(void)
+{
+	mutex_lock(&rpc_connect_lock);
+	if (endpoint == NULL) {
+		endpoint = msm_rpc_connect(HTCACOUSTICPROG,
+				HTCACOUSTICVERS, 0);
+		if (IS_ERR(endpoint)) {
+			pr_err("%s: init rpc failed! rc = %ld\n",
+				__func__, PTR_ERR(endpoint));
+			mutex_unlock(&rpc_connect_lock);
+			return -1;
+		}
+	}
+	mutex_unlock(&rpc_connect_lock);
+	return 0;
+}
+
+int turn_mic_bias_on(int on)
+{
+	D("%s called %d\n", __func__, on);
+	if (the_ops->enable_mic_bias)
+		the_ops->enable_mic_bias(on);
+
+	return 0;
+}
+EXPORT_SYMBOL(turn_mic_bias_on);
+
+int force_headset_speaker_on(int enable)
+{
+	struct speaker_headset_req {
+		struct rpc_request_hdr hdr;
+		uint32_t enable;
+	} spkr_req;
+
+	D("%s called %d\n", __func__, enable);
+
+	if (is_rpc_connect() == -1)
+		return -1;
+
+	spkr_req.enable = cpu_to_be32(enable);
+	return  msm_rpc_call(endpoint,
+		ONCRPC_FORCE_HEADSET_SPEAKER_PROC,
+		&spkr_req, sizeof(spkr_req), 5 * HZ);
+}
+EXPORT_SYMBOL(force_headset_speaker_on);
+
+int enable_aux_loopback(uint32_t enable)
+{
+	struct aux_loopback_req {
+		struct rpc_request_hdr hdr;
+		uint32_t enable;
+	} aux_req;
+
+	D("%s called %d\n", __func__, enable);
+
+	if (is_rpc_connect() == -1)
+		return -1;
+
+	aux_req.enable = cpu_to_be32(enable);
+	return  msm_rpc_call(endpoint,
+		ONCRPC_ENABLE_AUX_PGA_LOOPBACK_PROC,
+		&aux_req, sizeof(aux_req), 5 * HZ);
+}
+EXPORT_SYMBOL(enable_aux_loopback);
+
+static int acoustic_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long pgoff;
+	int rc = -EINVAL;
+	size_t size;
+
+	D("mmap\n");
+
+	mutex_lock(&api_lock);
+
+	size = vma->vm_end - vma->vm_start;
+
+	if (vma->vm_pgoff != 0) {
+		E("mmap failed: page offset %lx\n", vma->vm_pgoff);
+		goto done;
+	}
+
+	if (!htc_acoustic_vir_addr) {
+		E("mmap failed: smem region not allocated\n");
+		rc = -EIO;
+		goto done;
+	}
+
+	pgoff = MSM_SHARED_RAM_PHYS +
+		(htc_acoustic_vir_addr - (uint32_t)MSM_SHARED_RAM_BASE);
+	pgoff = ((pgoff + 4095) & ~4095);
+	htc_acoustic_vir_addr = ((htc_acoustic_vir_addr + 4095) & ~4095);
+
+	if (pgoff <= 0) {
+		E("pgoff wrong. %ld\n", pgoff);
+		goto done;
+	}
+
+	if (size <= HTC_ACOUSTIC_TABLE_SIZE) {
+		pgoff = pgoff >> PAGE_SHIFT;
+	} else {
+		E("size > HTC_ACOUSTIC_TABLE_SIZE  %d\n", size);
+		goto done;
+	}
+
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+	rc = io_remap_pfn_range(vma, vma->vm_start, pgoff,
+				size, vma->vm_page_prot);
+
+	if (rc < 0)
+		E("mmap failed: remap error %d\n", rc);
+
+done:	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static int acoustic_open(struct inode *inode, struct file *file)
+{
+	int reply_value;
+	int rc = -EIO;
+	struct set_smem_req {
+		struct rpc_request_hdr hdr;
+		uint32_t size;
+	} req_smem;
+
+	struct set_smem_rep {
+		struct rpc_reply_hdr hdr;
+		int n;
+	} rep_smem;
+
+	D("open\n");
+
+	mutex_lock(&api_lock);
+
+	if (!htc_acoustic_vir_addr) {
+		if (is_rpc_connect() == -1)
+			goto done;
+
+		req_smem.size = cpu_to_be32(HTC_ACOUSTIC_TABLE_SIZE);
+		rc = msm_rpc_call_reply(endpoint,
+					ONCRPC_ALLOC_ACOUSTIC_MEM_PROC,
+					&req_smem, sizeof(req_smem),
+					&rep_smem, sizeof(rep_smem),
+					5 * HZ);
+
+		reply_value = be32_to_cpu(rep_smem.n);
+		if (reply_value != 0 || rc < 0) {
+			E("open failed: ALLOC_ACOUSTIC_MEM_PROC error %d.\n",
+			rc);
+			goto done;
+		}
+		htc_acoustic_vir_addr =
+			(uint32_t)smem_alloc(SMEM_ID_VENDOR1,
+					HTC_ACOUSTIC_TABLE_SIZE);
+		if (!htc_acoustic_vir_addr) {
+			E("open failed: smem_alloc error\n");
+			goto done;
+		}
+	}
+
+	rc = 0;
+done:
+	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static int acoustic_release(struct inode *inode, struct file *file)
+{
+	D("release\n");
+	return 0;
+}
+
+static long acoustic_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	int rc, reply_value;
+
+	D("ioctl\n");
+
+	mutex_lock(&api_lock);
+
+	switch (cmd) {
+	case ACOUSTIC_UPDATE_ADIE: {
+		struct update_adie_req {
+			struct rpc_request_hdr hdr;
+			int id;
+		} adie_req;
+
+		struct update_adie_rep {
+			struct rpc_reply_hdr hdr;
+			int ret;
+		} adie_rep;
+
+		D("ioctl: ACOUSTIC_UPDATE_ADIE called %d.\n", current->pid);
+
+		adie_req.id = cpu_to_be32(-1); /* update all codecs */
+		rc = msm_rpc_call_reply(endpoint,
+					ONCRPC_UPDATE_ADIE_PROC, &adie_req,
+					sizeof(adie_req), &adie_rep,
+					sizeof(adie_rep), 5 * HZ);
+
+		reply_value = be32_to_cpu(adie_rep.ret);
+		if (reply_value != 0 || rc < 0) {
+			E("ioctl failed: ONCRPC_UPDATE_ADIE_PROC "\
+				"error %d.\n", rc);
+			if (rc >= 0)
+				rc = -EIO;
+			break;
+		}
+		D("ioctl: ONCRPC_UPDATE_ADIE_PROC success.\n");
+		break;
+	}
+	default:
+		E("ioctl: invalid command\n");
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&api_lock);
+	return rc;
+}
+
+struct rpc_set_uplink_mute_args {
+	int mute;
+};
+
+static struct file_operations acoustic_fops = {
+	.owner = THIS_MODULE,
+	.open = acoustic_open,
+	.release = acoustic_release,
+	.mmap = acoustic_mmap,
+	.unlocked_ioctl = acoustic_ioctl,
+};
+
+static struct miscdevice acoustic_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "htc-acoustic",
+	.fops = &acoustic_fops,
+};
+
+static int __init acoustic_init(void)
+{
+	mutex_init(&api_lock);
+	mutex_init(&rpc_connect_lock);
+	return misc_register(&acoustic_misc);
+}
+
+static void __exit acoustic_exit(void)
+{
+	misc_deregister(&acoustic_misc);
+}
+
+module_init(acoustic_init);
+module_exit(acoustic_exit);
+
diff --git a/arch/arm/mach-msm/htc_akm_cal.c b/arch/arm/mach-msm/htc_akm_cal.c
new file mode 100644
index 0000000..943083f
--- /dev/null
+++ b/arch/arm/mach-msm/htc_akm_cal.c
@@ -0,0 +1,64 @@
+/* arch/arm/mach-msm/htc_akm_cal.c
+ *
+ * Code to extract compass calibration information from ATAG set up 
+ * by the bootloader.
+ *
+ * Copyright (C) 2007-2008 HTC Corporation
+ * Author: Farmer Tseng <farmer_tseng@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 <asm/setup.h>
+
+/* configuration tags specific to AKM8976 */
+#define ATAG_AKM8976	0x89768976 /* AKM8976 */
+
+#define MAX_CALI_SIZE	0x1000U
+
+static char akm_cal_ram[MAX_CALI_SIZE];
+
+char *get_akm_cal_ram(void)
+{
+	return(akm_cal_ram);
+}
+EXPORT_SYMBOL(get_akm_cal_ram);
+
+static int __init parse_tag_akm(const struct tag *tag)
+{
+	unsigned char *dptr = (unsigned char *)(&tag->u);
+	unsigned size;
+
+	size = min((tag->hdr.size - 2) * sizeof(__u32), MAX_CALI_SIZE);
+
+	printk(KERN_INFO "AKM Data size = %d , 0x%x, size = %d\n",
+			tag->hdr.size, tag->hdr.tag, size);
+
+#ifdef ATAG_COMPASS_DEBUG
+	unsigned i;
+	unsigned char *ptr;
+
+	ptr = dptr;
+	printk(KERN_INFO
+	       "AKM Data size = %d , 0x%x\n",
+	       tag->hdr.size, tag->hdr.tag);
+	for (i = 0; i < size; i++)
+		printk(KERN_INFO "%02x ", *ptr++);
+#endif
+	memcpy((void *)akm_cal_ram, (void *)dptr, size);
+	return 0;
+}
+
+__tagtable(ATAG_AKM8976, parse_tag_akm);
diff --git a/arch/arm/mach-msm/htc_battery.c b/arch/arm/mach-msm/htc_battery.c
new file mode 100644
index 0000000..e1dbbf5
--- /dev/null
+++ b/arch/arm/mach-msm/htc_battery.c
@@ -0,0 +1,796 @@
+/* arch/arm/mach-msm/htc_battery.c
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/wakelock.h>
+#include <asm/gpio.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/board.h>
+#include <asm/mach-types.h>
+#include <mach/board_htc.h>
+
+static struct wake_lock vbus_wake_lock;
+
+#define TRACE_BATT 0
+
+#if TRACE_BATT
+#include <linux/rtc.h>
+
+#define BATT(x...) do { \
+struct timespec ts; \
+struct rtc_time tm; \
+getnstimeofday(&ts); \
+rtc_time_to_tm(ts.tv_sec, &tm); \
+printk(KERN_INFO "[BATT] " x); \
+printk(" at %lld (%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", \
+ktime_to_ns(ktime_get()), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, \
+tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); \
+} while (0)
+#else
+#define BATT(x...) do {} while (0)
+#endif
+
+/* rpc related */
+#define APP_BATT_PDEV_NAME		"rs30100001:00000000"
+#define APP_BATT_PROG			0x30100001
+#define APP_BATT_VER			MSM_RPC_VERS(0,0)
+#define HTC_PROCEDURE_BATTERY_NULL	0
+#define HTC_PROCEDURE_GET_BATT_LEVEL	1
+#define HTC_PROCEDURE_GET_BATT_INFO	2
+#define HTC_PROCEDURE_GET_CABLE_STATUS	3
+#define HTC_PROCEDURE_SET_BATT_DELTA	4
+
+/* module debugger */
+#define HTC_BATTERY_DEBUG		1
+#define BATTERY_PREVENTION		1
+
+/* Enable this will shut down if no battery */
+#define ENABLE_BATTERY_DETECTION	0
+/* Sapphire pin changes:
+ *  USB_ID (GPIO 90) is renamed to AC_IN (GPIO 30)
+ *  CHARGER_EN (CPLD MISC2 bit[0]) is move to PMIC (MPP_14).
+ *  ISET (CPLD MISC2 bit[1]) is move to PMIC (MPP_13). */
+#define GPIO_SAPPHIRE_USB_ID	30
+
+#define GPIO_BATTERY_DETECTION		21
+#define GPIO_BATTERY_CHARGER_EN		128
+
+/* Charge current selection */
+#define GPIO_BATTERY_CHARGER_CURRENT	129
+
+typedef enum {
+	DISABLE = 0,
+	ENABLE_SLOW_CHG,
+	ENABLE_FAST_CHG
+} batt_ctl_t;
+
+/* This order is the same as htc_power_supplies[]
+ * And it's also the same as htc_cable_status_update()
+ */
+typedef enum {
+	CHARGER_BATTERY = 0,
+	CHARGER_USB,
+	CHARGER_AC
+} charger_type_t;
+
+const char *charger_tags[] = {"none", "USB", "AC"};
+
+struct battery_info_reply {
+	u32 batt_id;		/* Battery ID from ADC */
+	u32 batt_vol;		/* Battery voltage from ADC */
+	u32 batt_temp;		/* Battery Temperature (C) from formula and ADC */
+	u32 batt_current;	/* Battery current from ADC */
+	u32 level;		/* formula */
+	u32 charging_source;	/* 0: no cable, 1:usb, 2:AC */
+	u32 charging_enabled;	/* 0: Disable, 1: Enable */
+	u32 full_bat;		/* Full capacity of battery (mAh) */
+};
+
+struct htc_battery_info {
+	int present;
+	unsigned long update_time;
+
+	/* lock to protect the battery info */
+	struct mutex lock;
+
+	/* lock held while calling the arm9 to query the battery info */
+	struct mutex rpc_lock;
+	struct battery_info_reply rep;
+};
+
+static struct msm_rpc_endpoint *endpoint;
+
+static struct htc_battery_info htc_batt_info;
+
+static unsigned int cache_time = 1000;
+
+static int htc_battery_initial = 0;
+
+static enum power_supply_property htc_battery_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static enum power_supply_property htc_power_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static char *supply_list[] = {
+	"battery",
+};
+
+/* HTC dedicated attributes */
+static ssize_t htc_battery_show_property(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf);
+
+static int htc_power_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val);
+
+static int htc_battery_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val);
+
+static struct power_supply htc_power_supplies[] = {
+	{
+		.name = "battery",
+		.type = POWER_SUPPLY_TYPE_BATTERY,
+		.properties = htc_battery_properties,
+		.num_properties = ARRAY_SIZE(htc_battery_properties),
+		.get_property = htc_battery_get_property,
+	},
+	{
+		.name = "usb",
+		.type = POWER_SUPPLY_TYPE_USB,
+		.supplied_to = supply_list,
+		.num_supplicants = ARRAY_SIZE(supply_list),
+		.properties = htc_power_properties,
+		.num_properties = ARRAY_SIZE(htc_power_properties),
+		.get_property = htc_power_get_property,
+	},
+	{
+		.name = "ac",
+		.type = POWER_SUPPLY_TYPE_MAINS,
+		.supplied_to = supply_list,
+		.num_supplicants = ARRAY_SIZE(supply_list),
+		.properties = htc_power_properties,
+		.num_properties = ARRAY_SIZE(htc_power_properties),
+		.get_property = htc_power_get_property,
+	},
+};
+
+static int g_usb_online;
+
+/* -------------------------------------------------------------------------- */
+
+#if defined(CONFIG_DEBUG_FS)
+int htc_battery_set_charging(batt_ctl_t ctl);
+static int batt_debug_set(void *data, u64 val)
+{
+	return htc_battery_set_charging((batt_ctl_t) val);
+}
+
+static int batt_debug_get(void *data, u64 *val)
+{
+	return -ENOSYS;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(batt_debug_fops, batt_debug_get, batt_debug_set, "%llu\n");
+static int __init batt_debug_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("htc_battery", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("charger_state", 0644, dent, NULL, &batt_debug_fops);
+
+	return 0;
+}
+
+device_initcall(batt_debug_init);
+#endif
+
+static int init_batt_gpio(void)
+{
+	if (!machine_is_trout())
+		return 0;
+
+	if (gpio_request(GPIO_BATTERY_DETECTION, "batt_detect") < 0)
+		goto gpio_failed;
+	if (gpio_request(GPIO_BATTERY_CHARGER_EN, "charger_en") < 0)
+		goto gpio_failed;
+	if (gpio_request(GPIO_BATTERY_CHARGER_CURRENT, "charge_current") < 0)
+		goto gpio_failed;
+
+	return 0;
+
+gpio_failed:	
+	return -EINVAL;
+	
+}
+
+/* 
+ *	battery_charging_ctrl - battery charing control.
+ * 	@ctl:			battery control command
+ *
+ */
+static int battery_charging_ctrl(batt_ctl_t ctl)
+{
+	int result = 0;
+
+	/* The charing operations are move to A9 in Sapphire. */
+	if (!machine_is_trout())
+		return result;
+
+	switch (ctl) {
+	case DISABLE:
+		BATT("charger OFF");
+		/* 0 for enable; 1 disable */
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 1);
+		break;
+	case ENABLE_SLOW_CHG:
+		BATT("charger ON (SLOW)");
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 0);
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0);
+		break;
+	case ENABLE_FAST_CHG:
+		BATT("charger ON (FAST)");
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 1);
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0);
+		break;
+	default:
+		printk(KERN_ERR "Not supported battery ctr called.!\n");
+		result = -EINVAL;
+		break;
+	}
+	
+	return result;
+}
+
+int htc_battery_set_charging(batt_ctl_t ctl)
+{
+	int rc;
+	
+	if ((rc = battery_charging_ctrl(ctl)) < 0)
+		goto result;
+	
+	if (!htc_battery_initial) {
+		htc_batt_info.rep.charging_enabled = ctl & 0x3;
+	} else {
+		mutex_lock(&htc_batt_info.lock);
+		htc_batt_info.rep.charging_enabled = ctl & 0x3;
+		mutex_unlock(&htc_batt_info.lock);
+	}
+result:	
+	return rc;
+}
+
+int htc_battery_status_update(u32 curr_level)
+{
+	int notify;
+	if (!htc_battery_initial)
+		return 0;
+
+	mutex_lock(&htc_batt_info.lock);
+	notify = (htc_batt_info.rep.level != curr_level);
+	htc_batt_info.rep.level = curr_level;
+	mutex_unlock(&htc_batt_info.lock);
+
+	if (notify)
+		power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
+	return 0;
+}
+
+int htc_cable_status_update(int status)
+{
+	int rc = 0;
+	unsigned last_source;
+
+	if (!htc_battery_initial)
+		return 0;
+	
+	if (status < CHARGER_BATTERY || status > CHARGER_AC) {
+		BATT("%s: Not supported cable status received!", __func__);
+		return -EINVAL;
+	}
+	mutex_lock(&htc_batt_info.lock);
+	/* A9 reports USB charging when helf AC cable in and China AC charger. */
+	/* Work arround: notify userspace AC charging first,
+	and notify USB charging again when receiving usb connected notificaiton from usb driver. */
+	last_source = htc_batt_info.rep.charging_source;
+	if (status == CHARGER_USB && g_usb_online == 0)
+		htc_batt_info.rep.charging_source = CHARGER_AC;
+	else {
+		htc_batt_info.rep.charging_source  = status;
+		/* usb driver will not notify usb offline. */
+		if (status == CHARGER_BATTERY && g_usb_online == 1)
+			g_usb_online = 0;
+	}
+
+	/* TODO: Don't call usb driver again with the same cable status. */
+	msm_hsusb_set_vbus_state(status == CHARGER_USB);
+
+	if (htc_batt_info.rep.charging_source != last_source) {
+		if (htc_batt_info.rep.charging_source == CHARGER_USB ||
+			htc_batt_info.rep.charging_source == CHARGER_AC) {
+		wake_lock(&vbus_wake_lock);
+	} else {
+		/* give userspace some time to see the uevent and update
+		 * LED state or whatnot...
+		 */
+		wake_lock_timeout(&vbus_wake_lock, HZ / 2);
+	}
+		if (htc_batt_info.rep.charging_source == CHARGER_BATTERY || last_source == CHARGER_BATTERY)
+	power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
+		if (htc_batt_info.rep.charging_source == CHARGER_USB || last_source == CHARGER_USB)
+	power_supply_changed(&htc_power_supplies[CHARGER_USB]);
+		if (htc_batt_info.rep.charging_source == CHARGER_AC || last_source == CHARGER_AC)
+	power_supply_changed(&htc_power_supplies[CHARGER_AC]);
+	}
+	mutex_unlock(&htc_batt_info.lock);
+
+	return rc;
+}
+
+/* A9 reports USB charging when helf AC cable in and China AC charger. */
+/* Work arround: notify userspace AC charging first,
+and notify USB charging again when receiving usb connected notification from usb driver. */
+void notify_usb_connected(int online)
+{
+	mutex_lock(&htc_batt_info.lock);
+
+	BATT("%s: online=%d, g_usb_online=%d", __func__, online, g_usb_online);
+
+	if (g_usb_online != online) {
+		g_usb_online = online;
+		if (online && htc_batt_info.rep.charging_source == CHARGER_AC) {
+			mutex_unlock(&htc_batt_info.lock);
+			htc_cable_status_update(CHARGER_USB);
+			mutex_lock(&htc_batt_info.lock);
+		} else if (online) {
+			BATT("warning: usb connected but charging source=%d", htc_batt_info.rep.charging_source);
+		}
+	}
+	mutex_unlock(&htc_batt_info.lock);
+}
+
+static int htc_get_batt_info(struct battery_info_reply *buffer)
+{
+	struct rpc_request_hdr req;
+	
+	struct htc_get_batt_info_rep {
+		struct rpc_reply_hdr hdr;
+		struct battery_info_reply info;
+	} rep;
+	
+	int rc;
+
+	if (buffer == NULL) 
+		return -EINVAL;
+
+	rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_BATT_INFO,
+				&req, sizeof(req),
+				&rep, sizeof(rep),
+				5 * HZ);
+	if ( rc < 0 ) 
+		return rc;
+	
+	mutex_lock(&htc_batt_info.lock);
+	buffer->batt_id 		= be32_to_cpu(rep.info.batt_id);
+	buffer->batt_vol 		= be32_to_cpu(rep.info.batt_vol);
+	buffer->batt_temp 		= be32_to_cpu(rep.info.batt_temp);
+	buffer->batt_current 		= be32_to_cpu(rep.info.batt_current);
+	buffer->level 			= be32_to_cpu(rep.info.level);
+	/* Move the rules of charging_source to cable_status_update. */
+	/* buffer->charging_source 	= be32_to_cpu(rep.info.charging_source); */
+	buffer->charging_enabled 	= be32_to_cpu(rep.info.charging_enabled);
+	buffer->full_bat 		= be32_to_cpu(rep.info.full_bat);
+	mutex_unlock(&htc_batt_info.lock);
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+static int htc_power_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val)
+{
+	charger_type_t charger;
+	
+	mutex_lock(&htc_batt_info.lock);
+	charger = htc_batt_info.rep.charging_source;
+	mutex_unlock(&htc_batt_info.lock);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+			val->intval = (charger ==  CHARGER_AC ? 1 : 0);
+		else if (psy->type == POWER_SUPPLY_TYPE_USB)
+			val->intval = (charger ==  CHARGER_USB ? 1 : 0);
+		else
+			val->intval = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+	return 0;
+}
+
+static int htc_battery_get_charging_status(void)
+{
+	u32 level;
+	charger_type_t charger;	
+	int ret;
+	
+	mutex_lock(&htc_batt_info.lock);
+	charger = htc_batt_info.rep.charging_source;
+	
+	switch (charger) {
+	case CHARGER_BATTERY:
+		ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		break;
+	case CHARGER_USB:
+	case CHARGER_AC:
+		level = htc_batt_info.rep.level;
+		if (level == 100)
+			ret = POWER_SUPPLY_STATUS_FULL;
+		else
+			ret = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	default:
+		ret = POWER_SUPPLY_STATUS_UNKNOWN;
+	}
+	mutex_unlock(&htc_batt_info.lock);
+	return ret;
+}
+
+static int htc_battery_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = htc_battery_get_charging_status();
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = htc_batt_info.present;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		mutex_lock(&htc_batt_info.lock);
+		val->intval = htc_batt_info.rep.level;
+		mutex_unlock(&htc_batt_info.lock);
+		break;
+	default:		
+		return -EINVAL;
+	}
+	
+	return 0;
+}
+
+#define HTC_BATTERY_ATTR(_name)							\
+{										\
+	.attr = { .name = #_name, .mode = S_IRUGO, .owner = THIS_MODULE },	\
+	.show = htc_battery_show_property,					\
+	.store = NULL,								\
+}
+
+static struct device_attribute htc_battery_attrs[] = {
+	HTC_BATTERY_ATTR(batt_id),
+	HTC_BATTERY_ATTR(batt_vol),
+	HTC_BATTERY_ATTR(batt_temp),
+	HTC_BATTERY_ATTR(batt_current),
+	HTC_BATTERY_ATTR(charging_source),
+	HTC_BATTERY_ATTR(charging_enabled),
+	HTC_BATTERY_ATTR(full_bat),
+};
+
+enum {
+	BATT_ID = 0,
+	BATT_VOL,
+	BATT_TEMP,
+	BATT_CURRENT,
+	CHARGING_SOURCE,
+	CHARGING_ENABLED,
+	FULL_BAT,
+};
+
+static int htc_rpc_set_delta(unsigned delta)
+{
+	struct set_batt_delta_req {
+		struct rpc_request_hdr hdr;
+		uint32_t data;
+	} req;
+
+	req.data = cpu_to_be32(delta);
+	return msm_rpc_call(endpoint, HTC_PROCEDURE_SET_BATT_DELTA,
+			    &req, sizeof(req), 5 * HZ);
+}
+
+
+static ssize_t htc_battery_set_delta(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	int rc;
+	unsigned long delta = 0;
+	
+	delta = simple_strtoul(buf, NULL, 10);
+
+	if (delta > 100)
+		return -EINVAL;
+
+	mutex_lock(&htc_batt_info.rpc_lock);
+	rc = htc_rpc_set_delta(delta);
+	mutex_unlock(&htc_batt_info.rpc_lock);
+	if (rc < 0)
+		return rc;
+	return count;
+}
+
+static struct device_attribute htc_set_delta_attrs[] = {
+	__ATTR(delta, S_IWUSR | S_IWGRP, NULL, htc_battery_set_delta),
+};
+
+static int htc_battery_create_attrs(struct device * dev)
+{
+	int i, j, rc;
+	
+	for (i = 0; i < ARRAY_SIZE(htc_battery_attrs); i++) {
+		rc = device_create_file(dev, &htc_battery_attrs[i]);
+		if (rc)
+			goto htc_attrs_failed;
+	}
+
+	for (j = 0; j < ARRAY_SIZE(htc_set_delta_attrs); j++) {
+		rc = device_create_file(dev, &htc_set_delta_attrs[j]);
+		if (rc)
+			goto htc_delta_attrs_failed;
+	}
+	
+	goto succeed;
+	
+htc_attrs_failed:
+	while (i--)
+		device_remove_file(dev, &htc_battery_attrs[i]);
+htc_delta_attrs_failed:
+	while (j--)
+		device_remove_file(dev, &htc_set_delta_attrs[i]);
+succeed:	
+	return rc;
+}
+
+static ssize_t htc_battery_show_property(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	int i = 0;
+	const ptrdiff_t off = attr - htc_battery_attrs;
+	
+	/* rpc lock is used to prevent two threads from calling
+	 * into the get info rpc at the same time
+	 */
+
+	mutex_lock(&htc_batt_info.rpc_lock);
+	/* check cache time to decide if we need to update */
+	if (htc_batt_info.update_time &&
+            time_before(jiffies, htc_batt_info.update_time +
+                                msecs_to_jiffies(cache_time)))
+                goto dont_need_update;
+	
+	if (htc_get_batt_info(&htc_batt_info.rep) < 0) {
+		printk(KERN_ERR "%s: rpc failed!!!\n", __FUNCTION__);
+	} else {
+		htc_batt_info.update_time = jiffies;
+	}
+dont_need_update:
+	mutex_unlock(&htc_batt_info.rpc_lock);
+
+	mutex_lock(&htc_batt_info.lock);
+	switch (off) {
+	case BATT_ID:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_id);
+		break;
+	case BATT_VOL:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_vol);
+		break;
+	case BATT_TEMP:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_temp);
+		break;
+	case BATT_CURRENT:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_current);
+		break;
+	case CHARGING_SOURCE:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.charging_source);
+		break;
+	case CHARGING_ENABLED:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.charging_enabled);
+		break;		
+	case FULL_BAT:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.full_bat);
+		break;
+	default:
+		i = -EINVAL;
+	}	
+	mutex_unlock(&htc_batt_info.lock);
+	
+	return i;
+}
+
+static int htc_battery_probe(struct platform_device *pdev)
+{
+	int i, rc;
+
+	/* init battery gpio */
+	if ((rc = init_batt_gpio()) < 0) {
+		printk(KERN_ERR "%s: init battery gpio failed!\n", __FUNCTION__);
+		return rc;
+	}
+
+	/* init structure data member */
+	htc_batt_info.update_time 	= jiffies;
+	/* A9 will shutdown the phone if battery is pluged out, so this value is always 1.
+	htc_batt_info.present 		= gpio_get_value(GPIO_TROUT_MBAT_IN);
+	*/
+	htc_batt_info.present 		= 1;
+
+	/* init rpc */
+	endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0);
+	if (IS_ERR(endpoint)) {
+		printk(KERN_ERR "%s: init rpc failed! rc = %ld\n",
+		       __FUNCTION__, PTR_ERR(endpoint));
+		return rc;
+	}
+
+	/* init power supplier framework */
+	for (i = 0; i < ARRAY_SIZE(htc_power_supplies); i++) {
+		rc = power_supply_register(&pdev->dev, &htc_power_supplies[i]);
+		if (rc)
+			printk(KERN_ERR "Failed to register power supply (%d)\n", rc);	
+	}
+
+	/* create htc detail attributes */
+	htc_battery_create_attrs(htc_power_supplies[CHARGER_BATTERY].dev);
+
+	/* After battery driver gets initialized, send rpc request to inquiry
+	 * the battery status in case of we lost some info
+	 */
+	htc_battery_initial = 1;
+
+	mutex_lock(&htc_batt_info.rpc_lock);
+	htc_batt_info.rep.charging_source = CHARGER_BATTERY;
+	if (htc_get_batt_info(&htc_batt_info.rep) < 0)
+		printk(KERN_ERR "%s: get info failed\n", __FUNCTION__);
+
+	if (htc_rpc_set_delta(1) < 0)
+		printk(KERN_ERR "%s: set delta failed\n", __FUNCTION__);
+	htc_batt_info.update_time = jiffies;
+	mutex_unlock(&htc_batt_info.rpc_lock);
+
+	return 0;
+}
+
+static struct platform_driver htc_battery_driver = {
+	.probe	= htc_battery_probe,
+	.driver	= {
+		.name	= APP_BATT_PDEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+/* batt_mtoa server definitions */
+#define BATT_MTOA_PROG				0x30100000
+#define BATT_MTOA_VERS				0
+#define RPC_BATT_MTOA_NULL			0
+#define RPC_BATT_MTOA_SET_CHARGING_PROC		1
+#define RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC	2
+#define RPC_BATT_MTOA_LEVEL_UPDATE_PROC		3
+
+struct rpc_batt_mtoa_set_charging_args {
+	int enable;
+};
+
+struct rpc_batt_mtoa_cable_status_update_args {
+	int status;
+};
+
+struct rpc_dem_battery_update_args {
+	uint32_t level;
+};
+
+static int handle_battery_call(struct msm_rpc_server *server,
+			       struct rpc_request_hdr *req, unsigned len)
+{	
+	switch (req->procedure) {
+	case RPC_BATT_MTOA_NULL:
+		return 0;
+
+	case RPC_BATT_MTOA_SET_CHARGING_PROC: {
+		struct rpc_batt_mtoa_set_charging_args *args;
+		args = (struct rpc_batt_mtoa_set_charging_args *)(req + 1);
+		args->enable = be32_to_cpu(args->enable);
+		BATT("set_charging: enable=%d",args->enable);
+		htc_battery_set_charging(args->enable);
+		return 0;
+	}
+	case RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC: {
+		struct rpc_batt_mtoa_cable_status_update_args *args;
+		args = (struct rpc_batt_mtoa_cable_status_update_args *)(req + 1);
+		args->status = be32_to_cpu(args->status);
+		BATT("cable_status_update: status=%d",args->status);
+		htc_cable_status_update(args->status);
+		return 0;
+	}
+	case RPC_BATT_MTOA_LEVEL_UPDATE_PROC: {
+		struct rpc_dem_battery_update_args *args;
+		args = (struct rpc_dem_battery_update_args *)(req + 1);
+		args->level = be32_to_cpu(args->level);
+		BATT("dem_battery_update: level=%d",args->level);
+		htc_battery_status_update(args->level);
+		return 0;
+	}
+	default:
+		printk(KERN_ERR "%s: program 0x%08x:%d: unknown procedure %d\n",
+		       __FUNCTION__, req->prog, req->vers, req->procedure);
+		return -ENODEV;
+	}
+}
+
+static struct msm_rpc_server battery_server = {
+	.prog = BATT_MTOA_PROG,
+	.vers = BATT_MTOA_VERS,
+	.rpc_call = handle_battery_call,
+};
+
+static int __init htc_battery_init(void)
+{
+	wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
+	mutex_init(&htc_batt_info.lock);
+	mutex_init(&htc_batt_info.rpc_lock);
+	msm_rpc_create_server(&battery_server);
+	platform_driver_register(&htc_battery_driver);
+	return 0;
+}
+
+module_init(htc_battery_init);
+MODULE_DESCRIPTION("HTC Battery Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/htc_headset.c b/arch/arm/mach-msm/htc_headset.c
new file mode 100644
index 0000000..f9a00b7
--- /dev/null
+++ b/arch/arm/mach-msm/htc_headset.c
@@ -0,0 +1,1332 @@
+/*
+ *  H2W device detection driver.
+ *
+ *  Copyright (C) 2008 Google, Inc.
+ *  Copyright (C) 2008 HTC, Inc.
+ *
+ *  Authors:
+ *      Laurence Chen <Laurence_Chen@htc.com>
+ *      Nick Pelly <npelly@google.com>
+ *      Thomas Tsai <thomas_tsai@htc.com>
+ *      Farmer Tseng <farmer_tseng@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.
+ */
+
+/*  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 trout.
+
+    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/slab.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 <asm/gpio.h>
+#include <asm/atomic.h>
+#include <mach/board.h>
+#include <mach/vreg.h>
+#include <asm/mach-types.h>
+
+#include <mach/htc_headset.h>
+
+#define H2WI(fmt, arg...) \
+	printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
+#define H2WE(fmt, arg...) \
+	printk(KERN_ERR "[H2W] %s " fmt "\r\n", __func__, ## arg)
+
+#ifdef CONFIG_DEBUG_H2W
+#define H2W_DBG(fmt, arg...) printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## 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);
+
+struct h2w_info {
+	struct switch_dev sdev;
+	struct input_dev *input;
+	struct mutex mutex_lock;
+
+	atomic_t btn_state;
+	int ignore_btn;
+
+	unsigned int irq;
+	unsigned int irq_btn;
+	unsigned int irq_btn_35mm;
+
+	int cable_in1;
+	int cable_in2;
+	int h2w_clk;
+	int h2w_data;
+	int debug_uart;
+	int headset_mic_35mm;
+
+	void (*config_cpld) (int);
+	void (*init_cpld) (void);
+	/* for h2w */
+	void (*set_dat)(int);
+	void (*set_clk)(int);
+	void (*set_dat_dir)(int);
+	void (*set_clk_dir)(int);
+	int (*get_dat)(void);
+	int (*get_clk)(void);
+
+	int htc_headset_flag;
+	int btn_11pin_35mm_flag;
+
+	struct hrtimer timer;
+	ktime_t debounce_time;
+
+	struct hrtimer btn_timer;
+	ktime_t btn_debounce_time;
+
+	struct hrtimer btn35mm_timer;
+	ktime_t btn35mm_debounce_time;
+
+	H2W_INFO h2w_info;
+	H2W_SPEED speed;
+	struct vreg *vreg_h2w;
+};
+static struct h2w_info *hi;
+
+static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf)
+{
+	switch (switch_get_state(&hi->sdev)) {
+	case H2W_NO_DEVICE:
+		return sprintf(buf, "No Device\n");
+	case H2W_HTC_HEADSET:
+		return sprintf(buf, "Headset\n");
+	}
+	return -EINVAL;
+}
+
+static void button_pressed(void)
+{
+	printk(KERN_INFO "[H2W] button_pressed\n");
+	atomic_set(&hi->btn_state, 1);
+	input_report_key(hi->input, KEY_MEDIA, 1);
+	input_sync(hi->input);
+}
+
+static void button_released(void)
+{
+	printk(KERN_INFO "[H2W] button_released\n");
+	atomic_set(&hi->btn_state, 0);
+	input_report_key(hi->input, KEY_MEDIA, 0);
+	input_sync(hi->input);
+}
+
+/*****************
+ * H2W proctocol *
+ *****************/
+static inline void h2w_begin_command(void)
+{
+	/* Disable H2W interrupt */
+	set_irq_type(hi->irq_btn, IRQF_TRIGGER_HIGH);
+	disable_irq(hi->irq);
+	disable_irq(hi->irq_btn);
+
+	/* Set H2W_CLK as output low */
+	hi->set_clk(0);
+	hi->set_clk_dir(1);
+}
+
+static inline void h2w_end_command(void)
+{
+	/* Set H2W_CLK as input */
+	hi->set_clk_dir(0);
+
+	/* Enable H2W interrupt */
+	enable_irq(hi->irq);
+	enable_irq(hi->irq_btn);
+	set_irq_type(hi->irq_btn, IRQF_TRIGGER_RISING);
+}
+
+static inline void one_clock_write(unsigned short flag)
+{
+	if (flag)
+		hi->set_dat(1);
+	else
+		hi->set_dat(0);
+
+	udelay(hi->speed);
+	hi->set_clk(1);
+	udelay(hi->speed);
+	hi->set_clk(0);
+}
+
+static inline void one_clock_write_RWbit(unsigned short flag)
+{
+	if (flag)
+		hi->set_dat(1);
+	else
+		hi->set_dat(0);
+
+	udelay(hi->speed);
+	hi->set_clk(1);
+	udelay(hi->speed);
+	hi->set_clk(0);
+	hi->set_dat_dir(0);
+	udelay(hi->speed);
+}
+
+static inline void h2w_reset(void)
+{
+	/* Set H2W_DAT as output low */
+	hi->set_dat(0);
+	hi->set_dat_dir(1);
+
+	udelay(hi->speed);
+	hi->set_clk(1);
+	udelay(4 * hi->speed);
+	hi->set_dat(1);
+	udelay(hi->speed);
+	hi->set_dat(0);
+	udelay(hi->speed);
+	hi->set_clk(0);
+	udelay(hi->speed);
+}
+
+static inline void h2w_start(void)
+{
+	udelay(hi->speed);
+	hi->set_clk(1);
+	udelay(2 * hi->speed);
+	hi->set_clk(0);
+	udelay(hi->speed);
+}
+
+static inline int h2w_ack(void)
+{
+	int retry_times = 0;
+
+ack_resend:
+	if (retry_times == MAX_ACK_RESEND_TIMES)
+		return -1;
+
+	udelay(hi->speed);
+	hi->set_clk(1);
+	udelay(2 * hi->speed);
+
+	if (!hi->get_dat()) {
+		retry_times++;
+		hi->set_clk(0);
+		udelay(hi->speed);
+		goto ack_resend;
+	}
+
+	hi->set_clk(0);
+	udelay(hi->speed);
+	return 0;
+}
+
+static unsigned char h2w_readc(void)
+{
+	unsigned char h2w_read_data = 0x0;
+	int index;
+
+	for (index = 0; index < 8; index++) {
+		hi->set_clk(0);
+		udelay(hi->speed);
+		hi->set_clk(1);
+		udelay(hi->speed);
+		if (hi->get_dat())
+			h2w_read_data |= (1 << (7 - index));
+	}
+	hi->set_clk(0);
+	udelay(hi->speed);
+
+	return h2w_read_data;
+}
+
+static int h2w_readc_cmd(H2W_ADDR address)
+{
+	int ret = -1, retry_times = 0;
+	unsigned char read_data;
+
+read_resend:
+	if (retry_times == MAX_HOST_RESEND_TIMES)
+		goto err_read;
+
+	h2w_reset();
+	h2w_start();
+	/* Write address */
+	one_clock_write(address & 0x1000);
+	one_clock_write(address & 0x0800);
+	one_clock_write(address & 0x0400);
+	one_clock_write(address & 0x0200);
+	one_clock_write(address & 0x0100);
+	one_clock_write(address & 0x0080);
+	one_clock_write(address & 0x0040);
+	one_clock_write(address & 0x0020);
+	one_clock_write(address & 0x0010);
+	one_clock_write(address & 0x0008);
+	one_clock_write(address & 0x0004);
+	one_clock_write(address & 0x0002);
+	one_clock_write(address & 0x0001);
+	one_clock_write_RWbit(1);
+	if (h2w_ack() < 0) {
+		H2W_DBG("Addr NO ACK(%d).\n", retry_times);
+		retry_times++;
+		hi->set_clk(0);
+		mdelay(RESEND_DELAY);
+		goto read_resend;
+	}
+
+	read_data = h2w_readc();
+
+	if (h2w_ack() < 0) {
+		H2W_DBG("Data NO ACK(%d).\n", retry_times);
+		retry_times++;
+		hi->set_clk(0);
+		mdelay(RESEND_DELAY);
+		goto read_resend;
+	}
+	ret = (int)read_data;
+
+err_read:
+	if (ret < 0)
+		H2WE("NO ACK.\n");
+
+	return ret;
+}
+
+static int h2w_writec_cmd(H2W_ADDR address, unsigned char data)
+{
+	int ret = -1;
+	int retry_times = 0;
+
+write_resend:
+	if (retry_times == MAX_HOST_RESEND_TIMES)
+		goto err_write;
+
+	h2w_reset();
+	h2w_start();
+
+	/* Write address */
+	one_clock_write(address & 0x1000);
+	one_clock_write(address & 0x0800);
+	one_clock_write(address & 0x0400);
+	one_clock_write(address & 0x0200);
+	one_clock_write(address & 0x0100);
+	one_clock_write(address & 0x0080);
+	one_clock_write(address & 0x0040);
+	one_clock_write(address & 0x0020);
+	one_clock_write(address & 0x0010);
+	one_clock_write(address & 0x0008);
+	one_clock_write(address & 0x0004);
+	one_clock_write(address & 0x0002);
+	one_clock_write(address & 0x0001);
+	one_clock_write_RWbit(0);
+	if (h2w_ack() < 0) {
+		H2W_DBG("Addr NO ACK(%d).\n", retry_times);
+		retry_times++;
+		hi->set_clk(0);
+		mdelay(RESEND_DELAY);
+		goto write_resend;
+	}
+
+	/* Write data */
+	hi->set_dat_dir(1);
+	one_clock_write(data & 0x0080);
+	one_clock_write(data & 0x0040);
+	one_clock_write(data & 0x0020);
+	one_clock_write(data & 0x0010);
+	one_clock_write(data & 0x0008);
+	one_clock_write(data & 0x0004);
+	one_clock_write(data & 0x0002);
+	one_clock_write_RWbit(data & 0x0001);
+	if (h2w_ack() < 0) {
+		H2W_DBG("Data NO ACK(%d).\n", retry_times);
+		retry_times++;
+		hi->set_clk(0);
+		mdelay(RESEND_DELAY);
+		goto write_resend;
+	}
+	ret = 0;
+
+err_write:
+	if (ret < 0)
+		H2WE("NO ACK.\n");
+
+	return ret;
+}
+
+static int h2w_get_fnkey(void)
+{
+	int ret;
+	h2w_begin_command();
+	ret = h2w_readc_cmd(H2W_FNKEY_UPDOWN);
+	h2w_end_command();
+	return ret;
+}
+
+static int h2w_dev_init(H2W_INFO *ph2w_info)
+{
+	int ret = -1;
+	unsigned char ascr0 = 0;
+	int h2w_sys = 0, maxgpadd = 0, maxadd = 0, key = 0;
+
+	hi->speed = H2W_50KHz;
+	h2w_begin_command();
+
+	/* read H2W_SYSTEM */
+	h2w_sys = h2w_readc_cmd(H2W_SYSTEM);
+	if (h2w_sys == -1) {
+		H2WE("read H2W_SYSTEM(0x0000) failed.\n");
+		goto err_plugin;
+	}
+	ph2w_info->ACC_CLASS = (h2w_sys & 0x03);
+	ph2w_info->AUDIO_DEVICE  = (h2w_sys & 0x04) > 0 ? 1 : 0;
+	ph2w_info->HW_REV = (h2w_sys & 0x18) >> 3;
+	ph2w_info->SLEEP_PR  = (h2w_sys & 0x20) >> 5;
+	ph2w_info->CLK_SP = (h2w_sys & 0xC0) >> 6;
+
+	/* enter init mode */
+	if (h2w_writec_cmd(H2W_ASCR0, H2W_ASCR_DEVICE_INI) < 0) {
+		H2WE("write H2W_ASCR0(0x0002) failed.\n");
+		goto err_plugin;
+	}
+	udelay(10);
+
+	/* read H2W_MAX_GP_ADD */
+	maxgpadd = h2w_readc_cmd(H2W_MAX_GP_ADD);
+	if (maxgpadd == -1) {
+		H2WE("write H2W_MAX_GP_ADD(0x0001) failed.\n");
+		goto err_plugin;
+	}
+	ph2w_info->CLK_SP += (maxgpadd & 0x60) >> 3;
+	ph2w_info->MAX_GP_ADD = (maxgpadd & 0x1F);
+
+	/* read key group */
+	if (ph2w_info->MAX_GP_ADD >= 1) {
+		ph2w_info->KEY_MAXADD = h2w_readc_cmd(H2W_KEY_MAXADD);
+		if (ph2w_info->KEY_MAXADD == -1)
+			goto err_plugin;
+		if (ph2w_info->KEY_MAXADD >= 1) {
+			key = h2w_readc_cmd(H2W_ASCII_DOWN);
+			if (key < 0)
+				goto err_plugin;
+			ph2w_info->ASCII_DOWN = (key == 0xFF) ? 1 : 0;
+		}
+		if (ph2w_info->KEY_MAXADD >= 2) {
+			key = h2w_readc_cmd(H2W_ASCII_UP);
+			if (key == -1)
+				goto err_plugin;
+			ph2w_info->ASCII_UP = (key == 0xFF) ? 1 : 0;
+		}
+		if (ph2w_info->KEY_MAXADD >= 3) {
+			key = h2w_readc_cmd(H2W_FNKEY_UPDOWN);
+			if (key == -1)
+				goto err_plugin;
+			ph2w_info->FNKEY_UPDOWN = (key == 0xFF) ? 1 : 0;
+		}
+		if (ph2w_info->KEY_MAXADD >= 4) {
+			key = h2w_readc_cmd(H2W_KD_STATUS);
+			if (key == -1)
+				goto err_plugin;
+			ph2w_info->KD_STATUS = (key == 0x01) ? 1 : 0;
+		}
+	}
+
+	/* read led group */
+	if (ph2w_info->MAX_GP_ADD >= 2) {
+		ph2w_info->LED_MAXADD = h2w_readc_cmd(H2W_LED_MAXADD);
+		if (ph2w_info->LED_MAXADD == -1)
+			goto err_plugin;
+		if (ph2w_info->LED_MAXADD >= 1) {
+			key = h2w_readc_cmd(H2W_LEDCT0);
+			if (key == -1)
+				goto err_plugin;
+			ph2w_info->LEDCT0 = (key == 0x02) ? 1 : 0;
+		}
+	}
+
+	/* read group 3, 4, 5 */
+	if (ph2w_info->MAX_GP_ADD >= 3) {
+		maxadd = h2w_readc_cmd(H2W_CRDL_MAXADD);
+		if (maxadd == -1)
+			goto err_plugin;
+	}
+	if (ph2w_info->MAX_GP_ADD >= 4) {
+		maxadd = h2w_readc_cmd(H2W_CARKIT_MAXADD);
+		if (maxadd == -1)
+			goto err_plugin;
+	}
+	if (ph2w_info->MAX_GP_ADD >= 5) {
+		maxadd = h2w_readc_cmd(H2W_USBHOST_MAXADD);
+		if (maxadd == -1)
+			goto err_plugin;
+	}
+
+	/* read medical group */
+	if (ph2w_info->MAX_GP_ADD >= 6) {
+		ph2w_info->MED_MAXADD = h2w_readc_cmd(H2W_MED_MAXADD);
+		if (ph2w_info->MED_MAXADD == -1)
+			goto err_plugin;
+		if (ph2w_info->MED_MAXADD >= 1) {
+			key = h2w_readc_cmd(H2W_MED_CONTROL);
+			if (key == -1)
+				goto err_plugin;
+		ph2w_info->DATA_EN = (key & 0x01);
+		ph2w_info->AP_EN = (key & 0x02) >> 1;
+		ph2w_info->AP_ID = (key & 0x1c) >> 2;
+		}
+		if (ph2w_info->MED_MAXADD >= 2) {
+			key = h2w_readc_cmd(H2W_MED_IN_DATA);
+			if (key == -1)
+				goto err_plugin;
+		}
+	}
+
+	if (ph2w_info->AUDIO_DEVICE)
+		ascr0 = H2W_ASCR_AUDIO_IN | H2W_ASCR_ACT_EN;
+	else
+		ascr0 = H2W_ASCR_ACT_EN;
+
+	if (h2w_writec_cmd(H2W_ASCR0, ascr0) < 0)
+		goto err_plugin;
+	udelay(10);
+
+	ret = 0;
+
+	/* adjust speed */
+	if (ph2w_info->MAX_GP_ADD == 2) {
+		/* Remote control */
+		hi->speed = H2W_250KHz;
+	} else if (ph2w_info->MAX_GP_ADD == 6) {
+		if (ph2w_info->MED_MAXADD >= 1) {
+			key = h2w_readc_cmd(H2W_MED_CONTROL);
+			if (key == -1)
+				goto err_plugin;
+			ph2w_info->DATA_EN   = (key & 0x01);
+			ph2w_info->AP_EN = (key & 0x02) >> 1;
+			ph2w_info->AP_ID = (key & 0x1c) >> 2;
+		}
+	}
+
+err_plugin:
+	h2w_end_command();
+
+	return ret;
+}
+
+static inline void h2w_dev_power_on(int on)
+{
+	if (!hi->vreg_h2w)
+		return;
+
+	if (on)
+		vreg_enable(hi->vreg_h2w);
+	else
+		vreg_disable(hi->vreg_h2w);
+}
+
+static int h2w_dev_detect(void)
+{
+	int ret = -1;
+	int retry_times;
+
+	for (retry_times = 5; retry_times; retry_times--) {
+		/* Enable H2W Power */
+		h2w_dev_power_on(1);
+		msleep(100);
+		memset(&hi->h2w_info, 0, sizeof(H2W_INFO));
+		if (h2w_dev_init(&hi->h2w_info) < 0) {
+			h2w_dev_power_on(0);
+			msleep(100);
+		} else if (hi->h2w_info.MAX_GP_ADD == 2) {
+			ret = 0;
+			break;
+		} else {
+			printk(KERN_INFO "h2w_detect: detect error(%d)\n"
+				, hi->h2w_info.MAX_GP_ADD);
+			h2w_dev_power_on(0);
+			msleep(100);
+		}
+		printk(KERN_INFO "h2w_detect(%d)\n"
+				, hi->h2w_info.MAX_GP_ADD);
+	}
+	H2W_DBG("h2w_detect:(%d)\n", retry_times);
+	return ret;
+}
+
+static void remove_headset(void)
+{
+	unsigned long irq_flags;
+
+	H2W_DBG("");
+
+	mutex_lock(&hi->mutex_lock);
+	switch_set_state(&hi->sdev, switch_get_state(&hi->sdev) &
+			~(BIT_HEADSET | BIT_HEADSET_NO_MIC));
+	mutex_unlock(&hi->mutex_lock);
+	hi->init_cpld();
+
+	/* Disable button */
+	switch (hi->htc_headset_flag) {
+	case H2W_HTC_HEADSET:
+		local_irq_save(irq_flags);
+		disable_irq(hi->irq_btn);
+		local_irq_restore(irq_flags);
+
+		if (atomic_read(&hi->btn_state))
+			button_released();
+		printk(KERN_INFO "remove htc headset\n");
+		break;
+	case NORMAL_HEARPHONE:
+		if (hi->btn_11pin_35mm_flag) {
+			disable_irq(hi->irq_btn_35mm);
+			turn_mic_bias_on(0);
+			hi->btn_11pin_35mm_flag = 0;
+			if (atomic_read(&hi->btn_state))
+				button_released();
+		}
+		printk(KERN_INFO "remove 11pin 3.5mm headset\n");
+		break;
+	case H2W_DEVICE:
+		h2w_dev_power_on(0);
+		set_irq_type(hi->irq_btn, IRQF_TRIGGER_LOW);
+		disable_irq(hi->irq_btn);
+		/* 10ms (5-15 with 10ms tick) */
+		hi->btn_debounce_time = ktime_set(0, 10000000);
+		hi->set_clk_dir(0);
+		hi->set_dat_dir(0);
+		printk(KERN_INFO "remove h2w device\n");
+		break;
+	}
+
+	hi->htc_headset_flag = 0;
+	hi->debounce_time = ktime_set(0, 100000000);  /* 100 ms */
+
+}
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+extern void msm_serial_debug_enable(int);
+#endif
+
+static void insert_headset(int type)
+{
+	unsigned long irq_flags;
+	int state;
+
+	H2W_DBG("");
+
+	hi->htc_headset_flag = type;
+	state = BIT_HEADSET | BIT_HEADSET_NO_MIC;
+
+	state = switch_get_state(&hi->sdev);
+	state &= ~(BIT_HEADSET_NO_MIC | BIT_HEADSET);
+	switch (type) {
+	case H2W_HTC_HEADSET:
+		printk(KERN_INFO "insert_headset H2W_HTC_HEADSET\n");
+		state |= BIT_HEADSET;
+		hi->ignore_btn = !gpio_get_value(hi->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, 200000000); /* 20 ms */
+		break;
+	case NORMAL_HEARPHONE:
+		if (hi->headset_mic_35mm) {
+			/* support 3.5mm earphone with mic */
+			printk(KERN_INFO "11pin_3.5mm_headset plug in\n");
+			/* Turn On Mic Bias */
+			turn_mic_bias_on(1);
+			/* Wait pin be stable */
+			msleep(200);
+			/* Detect headset with or without microphone */
+			if (gpio_get_value(hi->headset_mic_35mm)) {
+				/* without microphone */
+				turn_mic_bias_on(0);
+				state |= BIT_HEADSET_NO_MIC;
+				printk(KERN_INFO
+				       "11pin_3.5mm without microphone\n");
+			} else { /* with microphone */
+				state |= BIT_HEADSET;
+				/* Enable button irq */
+				if (!hi->btn_11pin_35mm_flag) {
+					set_irq_type(hi->irq_btn_35mm,
+						     IRQF_TRIGGER_HIGH);
+					enable_irq(hi->irq_btn_35mm);
+					hi->btn_11pin_35mm_flag = 1;
+				}
+				printk(KERN_INFO
+				       "11pin_3.5mm with microphone\n");
+			}
+		} else /* not support 3.5mm earphone with mic */
+			state |= BIT_HEADSET_NO_MIC;
+		hi->debounce_time = ktime_set(0, 500000000);  /* 500 ms */
+		break;
+	case H2W_DEVICE:
+		printk(KERN_INFO "insert_headset H2W_DEVICE\n");
+		if (!hi->set_dat) {
+			printk(KERN_INFO "Don't support H2W_DEVICE\n");
+			hi->htc_headset_flag = 0;
+			return;
+		}
+		if (h2w_dev_detect() < 0) {
+			printk(KERN_INFO "H2W_DEVICE -- Non detect\n");
+			remove_headset();
+		} else {
+			printk(KERN_INFO "H2W_DEVICE -- detect\n");
+			hi->btn_debounce_time = ktime_set(0, 0);
+			local_irq_save(irq_flags);
+			enable_irq(hi->irq_btn);
+			set_irq_type(hi->irq_btn, IRQF_TRIGGER_RISING);
+			local_irq_restore(irq_flags);
+			state |= BIT_HEADSET;
+		}
+		break;
+	case H2W_USB_CRADLE:
+		printk(KERN_INFO "insert_headset USB_CRADLE\n");
+		state |= BIT_HEADSET_NO_MIC;
+		break;
+	case H2W_UART_DEBUG:
+		printk(KERN_INFO "switch to H2W_UART_DEBUG\n");
+		hi->config_cpld(hi->debug_uart);
+	default:
+		return;
+	}
+	mutex_lock(&hi->mutex_lock);
+	switch_set_state(&hi->sdev, state);
+	mutex_unlock(&hi->mutex_lock);
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+	msm_serial_debug_enable(false);
+#endif
+
+}
+#if 0
+static void remove_headset(void)
+{
+	unsigned long irq_flags;
+
+	H2W_DBG("");
+
+	switch_set_state(&hi->sdev, H2W_NO_DEVICE);
+
+	hi->init_cpld();
+
+	/* 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 */
+}
+#endif
+static int is_accessary_pluged_in(void)
+{
+	int type = 0;
+	int clk1 = 0, dat1 = 0, clk2 = 0, dat2 = 0, clk3 = 0, dat3 = 0;
+
+	/* Step1: save H2W_CLK and H2W_DAT */
+	/* Delay 10ms for pin stable. */
+	msleep(10);
+	clk1 = gpio_get_value(hi->h2w_clk);
+	dat1 = gpio_get_value(hi->h2w_data);
+
+	/*
+	 * Step2: set GPIO_CABLE_IN1 as output high and GPIO_CABLE_IN2 as
+	 * input
+	 */
+	gpio_direction_output(hi->cable_in1, 1);
+	gpio_direction_input(hi->cable_in2);
+	/* Delay 10ms for pin stable. */
+	msleep(10);
+	/* Step 3: save H2W_CLK and H2W_DAT */
+	clk2 = gpio_get_value(hi->h2w_clk);
+	dat2 = gpio_get_value(hi->h2w_data);
+
+	/*
+	 * Step 4: set GPIO_CABLE_IN1 as input and GPIO_CABLE_IN2 as output
+	 * high
+	 */
+	gpio_direction_input(hi->cable_in1);
+	gpio_direction_output(hi->cable_in2, 1);
+	/* Delay 10ms for pin stable. */
+	msleep(10);
+	/* Step 5: save H2W_CLK and H2W_DAT */
+	clk3 = gpio_get_value(hi->h2w_clk);
+	dat3 = gpio_get_value(hi->h2w_data);
+
+	/* Step 6: set both GPIO_CABLE_IN1 and GPIO_CABLE_IN2 as input */
+	gpio_direction_input(hi->cable_in1);
+	gpio_direction_input(hi->cable_in2);
+
+	H2WI("(%d,%d) (%d,%d) (%d,%d)",
+		clk1, dat1, clk2, dat2, clk3, dat3);
+
+	if ((clk1 == 0) && (dat1 == 1) &&
+	    (clk2 == 0) && (dat2 == 1) &&
+	    (clk3 == 0) && (dat3 == 1))
+		type = H2W_HTC_HEADSET;
+	else if ((clk1 == 0) && (dat1 == 0) &&
+		 (clk2 == 0) && (dat2 == 0) &&
+		 (clk3 == 0) &&  (dat3 == 0))
+		type = NORMAL_HEARPHONE;
+	else if ((clk1 == 0) && (dat1 == 0) &&
+		 (clk2 == 1) && (dat2 == 0) &&
+		 (clk3 == 0) && (dat3 == 1))
+		type = H2W_DEVICE;
+	else if ((clk1 == 0) && (dat1 == 0) &&
+		 (clk2 == 1) && (dat2 == 1) &&
+		 (clk3 == 1) && (dat3 == 1))
+		type = H2W_USB_CRADLE;
+	else if ((clk1 == 0) && (dat1 == 1) &&
+		 (clk2 == 1) && (dat2 == 1) &&
+		 (clk3 == 0) && (dat3 == 1))
+		type = H2W_UART_DEBUG;
+	else
+		type = H2W_NO_DEVICE;
+
+	return type;
+}
+
+
+static void detection_work(struct work_struct *work)
+{
+	unsigned long irq_flags;
+	int type;
+
+	H2W_DBG("");
+
+	if (gpio_get_value(hi->cable_in1) != 0) {
+		/* Headset not plugged in */
+		if (switch_get_state(&hi->sdev) != H2W_NO_DEVICE)
+			remove_headset();
+		return;
+	}
+
+	/* Something plugged in, lets make sure its a headset */
+
+	/* Switch CPLD to GPIO to do detection */
+	hi->config_cpld(H2W_GPIO);
+
+	/* Disable headset interrupt while detecting.*/
+	local_irq_save(irq_flags);
+	disable_irq(hi->irq);
+	local_irq_restore(irq_flags);
+
+	/* Something plugged in, lets make sure its a headset */
+	type = is_accessary_pluged_in();
+
+	/* Restore IRQs */
+	local_irq_save(irq_flags);
+	enable_irq(hi->irq);
+	local_irq_restore(irq_flags);
+
+	insert_headset(type);
+}
+
+void headset_button_event(int is_press)
+{
+	if (!is_press) {
+		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();
+	}
+}
+
+static enum hrtimer_restart button_35mm_event_timer_func(struct hrtimer *data)
+{
+	if (gpio_get_value(hi->headset_mic_35mm)) {
+		headset_button_event(1);
+		/* 10 ms */
+		hi->btn35mm_debounce_time = ktime_set(0, 10000000);
+	} else {
+		headset_button_event(0);
+		/* 100 ms */
+		hi->btn35mm_debounce_time = ktime_set(0, 100000000);
+	}
+
+	return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart button_event_timer_func(struct hrtimer *data)
+{
+	int key, press, keyname, h2w_key = 1;
+
+	H2W_DBG("");
+
+	if (switch_get_state(&hi->sdev) & BIT_HEADSET) {
+		switch (hi->htc_headset_flag) {
+		case H2W_HTC_HEADSET:
+			if (!gpio_get_value(hi->cable_in2))
+				headset_button_event(1); /* press */
+			else
+				headset_button_event(0);
+			break;
+		case H2W_DEVICE:
+			if ((hi->get_dat() == 1) && (hi->get_clk() == 1)) {
+				/* Don't do anything because H2W pull out. */
+				H2WE("Remote Control pull out.\n");
+			} else {
+				key = h2w_get_fnkey();
+				press = (key > 0x7F) ? 0 : 1;
+				keyname = key & 0x7F;
+				 /* H2WI("key = %d, press = %d,
+					 keyname = %d \n",
+					 key, press, keyname); */
+				switch (keyname) {
+				case H2W_KEY_PLAY:
+					H2WI("H2W_KEY_PLAY");
+					key = KEY_PLAYPAUSE;
+					break;
+				case H2W_KEY_FORWARD:
+					H2WI("H2W_KEY_FORWARD");
+					key = KEY_NEXTSONG;
+					break;
+				case H2W_KEY_BACKWARD:
+					H2WI("H2W_KEY_BACKWARD");
+					key = KEY_PREVIOUSSONG;
+					break;
+				case H2W_KEY_VOLUP:
+					H2WI("H2W_KEY_VOLUP");
+					key = KEY_VOLUMEUP;
+					break;
+				case H2W_KEY_VOLDOWN:
+					H2WI("H2W_KEY_VOLDOWN");
+					key = KEY_VOLUMEDOWN;
+					break;
+				case H2W_KEY_PICKUP:
+					H2WI("H2W_KEY_PICKUP");
+					key = KEY_SEND;
+					break;
+				case H2W_KEY_HANGUP:
+					H2WI("H2W_KEY_HANGUP");
+					key = KEY_END;
+					break;
+				case H2W_KEY_MUTE:
+					H2WI("H2W_KEY_MUTE");
+					key = KEY_MUTE;
+					break;
+				case H2W_KEY_HOLD:
+					H2WI("H2W_KEY_HOLD");
+					break;
+				default:
+				H2WI("default");
+					h2w_key = 0;
+				}
+				if (h2w_key) {
+					if (press)
+						H2WI("Press\n");
+					else
+						H2WI("Release\n");
+					input_report_key(hi->input, key, press);
+				}
+			}
+			break;
+		} /* end switch */
+	}
+
+	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("");
+	set_irq_type(hi->irq_btn, IRQF_TRIGGER_LOW);
+	do {
+		value1 = gpio_get_value(hi->cable_in1);
+		set_irq_type(hi->irq, value1 ?
+				IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+		value2 = gpio_get_value(hi->cable_in1);
+	} while (value1 != value2 && retry_limit-- > 0);
+
+	H2W_DBG("value2 = %d (%d retries), device=%d",
+		value2, (10-retry_limit), switch_get_state(&hi->sdev));
+
+	if ((switch_get_state(&hi->sdev) == H2W_NO_DEVICE) ^ value2) {
+		if (switch_get_state(&hi->sdev) & BIT_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(hi->cable_in2);
+		if (hi->htc_headset_flag != H2W_DEVICE)
+		set_irq_type(hi->irq_btn, value1 ?
+				IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+		value2 = gpio_get_value(hi->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;
+}
+
+static irqreturn_t button_35mm_irq_handler(int irq, void *dev_id)
+{
+	int value1, value2;
+	int retry_limit = 10;
+
+	H2W_DBG("");
+	do {
+		value1 = gpio_get_value(hi->headset_mic_35mm);
+		set_irq_type(hi->irq_btn_35mm, value1 ?
+				IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+		value2 = gpio_get_value(hi->headset_mic_35mm);
+	} while (value1 != value2 && retry_limit-- > 0);
+
+	H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit));
+
+	hrtimer_start(&hi->btn35mm_timer,
+		      hi->btn35mm_debounce_time,
+		      HRTIMER_MODE_REL);
+
+	return IRQ_HANDLED;
+
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int h2w_debug_set(void *data, u64 val)
+{
+	mutex_lock(&hi->mutex_lock);
+	switch_set_state(&hi->sdev, (int)val);
+	mutex_unlock(&hi->mutex_lock);
+	return 0;
+}
+
+static int h2w_debug_get(void *data, u64 *val)
+{
+	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 h2w_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct h2w_platform_data *pdata = pdev->dev.platform_data;
+
+	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->btn35mm_debounce_time = ktime_set(0, 50000000);  /* 50 ms */
+
+	hi->htc_headset_flag = 0;
+	hi->btn_11pin_35mm_flag = 0;
+	hi->cable_in1 = pdata->cable_in1;
+	hi->cable_in2 = pdata->cable_in2;
+	hi->h2w_clk = pdata->h2w_clk;
+	hi->h2w_data = pdata->h2w_data;
+	hi->debug_uart = pdata->debug_uart;
+	hi->headset_mic_35mm = pdata->headset_mic_35mm;
+	hi->config_cpld = pdata->config_cpld;
+	hi->init_cpld = pdata->init_cpld;
+	hi->set_dat = pdata->set_dat;
+	hi->set_clk = pdata->set_clk;
+	hi->set_dat_dir	= pdata->set_dat_dir;
+	hi->set_clk_dir	= pdata->set_clk_dir;
+	hi->get_dat = pdata->get_dat;
+	hi->get_clk = pdata->get_clk;
+	hi->speed = H2W_50KHz;
+	/* obtain needed VREGs */
+	if (pdata->power_name)
+		hi->vreg_h2w = vreg_get(0, pdata->power_name);
+
+	mutex_init(&hi->mutex_lock);
+
+	hi->sdev.name = "h2w";
+	hi->sdev.print_name = 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;
+	}
+
+	if (hi->headset_mic_35mm) {
+		ret = gpio_request(hi->headset_mic_35mm, "3.5mm_mic_detect");
+		if (ret < 0)
+			goto err_request_35mm_mic_detect_gpio;
+
+		ret = gpio_direction_input(hi->headset_mic_35mm);
+		if (ret < 0)
+			goto err_set_35mm_mic_detect_gpio;
+
+		hi->irq_btn_35mm = gpio_to_irq(hi->headset_mic_35mm);
+		if (hi->irq_btn_35mm < 0) {
+			ret = hi->irq_btn_35mm;
+			goto err_request_btn_35mm_irq;
+		}
+		set_irq_flags(hi->irq_btn_35mm, IRQF_VALID | IRQF_NOAUTOEN);
+		ret = request_irq(hi->irq_btn_35mm,
+				  button_35mm_irq_handler,
+				  IRQF_TRIGGER_HIGH, "35mm_button", NULL);
+		if (ret < 0)
+			goto err_request_btn_35mm_irq;
+	}
+
+	ret = gpio_request(hi->cable_in1, "h2w_detect");
+	if (ret < 0)
+		goto err_request_detect_gpio;
+
+	ret = gpio_request(hi->cable_in2, "h2w_button");
+	if (ret < 0)
+		goto err_request_button_gpio;
+
+	ret = gpio_direction_input(hi->cable_in1);
+	if (ret < 0)
+		goto err_set_detect_gpio;
+
+	ret = gpio_direction_input(hi->cable_in2);
+	if (ret < 0)
+		goto err_set_button_gpio;
+
+	hi->irq = gpio_to_irq(hi->cable_in1);
+	if (hi->irq < 0) {
+		ret = hi->irq;
+		goto err_get_h2w_detect_irq_num_failed;
+	}
+
+	hi->irq_btn = gpio_to_irq(hi->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 */
+	hi->init_cpld();
+
+	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;
+	hrtimer_init(&hi->btn35mm_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hi->btn35mm_timer.function = button_35mm_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";
+	set_bit(EV_SYN, hi->input->evbit);
+	set_bit(EV_KEY, hi->input->evbit);
+	set_bit(KEY_MEDIA, hi->input->keybit);
+	set_bit(KEY_NEXTSONG, hi->input->keybit);
+	set_bit(KEY_PLAYPAUSE, hi->input->keybit);
+	set_bit(KEY_PREVIOUSSONG, hi->input->keybit);
+	set_bit(KEY_MUTE, hi->input->keybit);
+	set_bit(KEY_VOLUMEUP, hi->input->keybit);
+	set_bit(KEY_VOLUMEDOWN, hi->input->keybit);
+	set_bit(KEY_END, hi->input->keybit);
+	set_bit(KEY_SEND, hi->input->keybit);
+
+	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(hi->cable_in2);
+err_request_button_gpio:
+	gpio_free(hi->cable_in1);
+err_request_detect_gpio:
+	if (hi->headset_mic_35mm)
+		free_irq(hi->irq_btn_35mm, 0);
+err_request_btn_35mm_irq:
+err_set_35mm_mic_detect_gpio:
+	if (hi->headset_mic_35mm)
+		gpio_free(hi->headset_mic_35mm);
+err_request_35mm_mic_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 h2w_remove(struct platform_device *pdev)
+{
+	H2W_DBG("");
+	if (switch_get_state(&hi->sdev))
+		remove_headset();
+	input_unregister_device(hi->input);
+	gpio_free(hi->cable_in2);
+	gpio_free(hi->cable_in1);
+	free_irq(hi->irq_btn, 0);
+	free_irq(hi->irq, 0);
+	if (hi->headset_mic_35mm) {
+		gpio_free(hi->headset_mic_35mm);
+		free_irq(hi->irq_btn_35mm, 0);
+	}
+	destroy_workqueue(g_detection_work_queue);
+	switch_dev_unregister(&hi->sdev);
+
+	return 0;
+}
+
+
+static struct platform_driver h2w_driver = {
+	.probe		= h2w_probe,
+	.remove		= h2w_remove,
+	.driver		= {
+		.name		= "h2w",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init h2w_init(void)
+{
+	H2W_DBG("");
+	return platform_driver_register(&h2w_driver);
+}
+
+static void __exit h2w_exit(void)
+{
+	platform_driver_unregister(&h2w_driver);
+}
+
+module_init(h2w_init);
+module_exit(h2w_exit);
+
+MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>");
+MODULE_DESCRIPTION("HTC 2 Wire detection driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/htc_power_supply.c b/arch/arm/mach-msm/htc_power_supply.c
new file mode 100644
index 0000000..9cfe2cc
--- /dev/null
+++ b/arch/arm/mach-msm/htc_power_supply.c
@@ -0,0 +1,618 @@
+/* arch/arm/mach-msm/htc_battery.c
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <mach/msm_fast_timer.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/board.h>
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/switch.h>
+#include <linux/wakelock.h>
+
+#include "board-mahimahi.h"
+
+extern void notify_usb_connected(int);
+
+static char *supply_list[] = {
+	"battery",
+};
+
+static struct switch_dev dock_switch = {
+	.name = "dock",
+};
+
+static int vbus_present;
+static int usb_status;
+static bool dock_mains;
+
+struct dock_state {
+	struct mutex lock;
+	u32 t;
+	u32 last_edge_t[2];
+	u32 last_edge_i[2];
+	bool level;
+	bool dock_connected_unknown;
+};
+
+static struct workqueue_struct *dock_wq;
+static struct work_struct dock_work;
+static struct wake_lock dock_work_wake_lock;
+static struct dock_state ds = {
+	.lock = __MUTEX_INITIALIZER(ds.lock),
+};
+
+#define _GPIO_DOCK MAHIMAHI_GPIO_DOCK
+
+#define dock_out(n) gpio_direction_output(_GPIO_DOCK, n)
+#define dock_out2(n) gpio_set_value(_GPIO_DOCK, n)
+#define dock_in() gpio_direction_input(_GPIO_DOCK)
+#define dock_read() gpio_get_value(_GPIO_DOCK)
+
+#define MFM_DELAY_NS 10000
+
+static int dock_get_edge(struct dock_state *s, u32 timeout, u32 tmin, u32 tmax)
+{
+	bool lin;
+	bool in = s->level;
+	u32 t;
+	do {
+		lin = in;
+		in = dock_read();
+		t = msm_read_fast_timer();
+		if (in != lin) {
+			s->last_edge_t[in] = t;
+			s->last_edge_i[in] = 0;
+			s->level = in;
+			if ((s32)(t - tmin) < 0 || (s32)(t - tmax) > 0)
+				return -1;
+			return 1;
+		}
+	} while((s32)(t - timeout) < 0);
+	return 0;
+}
+
+static bool dock_sync(struct dock_state *s, u32 timeout)
+{
+	u32 t;
+
+	s->level = dock_read();
+	t = msm_read_fast_timer();
+
+	if (!dock_get_edge(s, t + timeout, 0, 0))
+		return false;
+	s->last_edge_i[s->level] = 2;
+	return !!dock_get_edge(s,
+			s->last_edge_t[s->level] + MFM_DELAY_NS * 4, 0, 0);
+}
+
+static int dock_get_next_bit(struct dock_state *s)
+{
+	u32 i = s->last_edge_i[!s->level] + ++s->last_edge_i[s->level];
+	u32 target = s->last_edge_t[!s->level] + MFM_DELAY_NS * i;
+	u32 timeout = target + MFM_DELAY_NS / 2;
+	u32 tmin = target - MFM_DELAY_NS / 4;
+	u32 tmax = target + MFM_DELAY_NS / 4;
+	return dock_get_edge(s, timeout, tmin, tmax);
+}
+
+static u32 dock_get_bits(struct dock_state *s, int count, int *errp)
+{
+	u32 data = 0;
+	u32 m = 1;
+	int ret;
+	int err = 0;
+	while (count--) {
+		ret = dock_get_next_bit(s);
+		if (ret)
+			data |= m;
+		if (ret < 0)
+			err++;
+		m <<= 1;
+	}
+	if (errp)
+		*errp = err;
+	return data;
+}
+
+static void dock_delay(u32 timeout)
+{
+	timeout += msm_read_fast_timer();
+	while (((s32)(msm_read_fast_timer() - timeout)) < 0)
+		;
+}
+
+static int dock_send_bits(struct dock_state *s, u32 data, int count, int period)
+{
+	u32 t, t0, to;
+
+	dock_out2(s->level);
+	t = to = 0;
+	t0 = msm_read_fast_timer();
+
+	while (count--) {
+		if (data & 1)
+			dock_out2((s->level = !s->level));
+
+		t = msm_read_fast_timer() - t0;
+		if (t - to > period / 2) {
+			pr_info("dock: to = %d, t = %d\n", to, t);
+			return -EIO;
+		}
+
+		to += MFM_DELAY_NS;
+		do {
+			t = msm_read_fast_timer() - t0;
+		} while (t < to);
+		if (t - to > period / 4) {
+			pr_info("dock: to = %d, t = %d\n", to, t);
+			return -EIO;
+		}
+		data >>= 1;
+	}
+	return 0;
+}
+
+static u32 mfm_encode(u16 data, int count, bool p)
+{
+	u32 mask;
+	u32 mfm = 0;
+	u32 clock = ~data & ~(data << 1 | !!p);
+	for (mask = 1UL << (count - 1); mask; mask >>= 1) {
+		mfm |= (data & mask);
+		mfm <<= 1;
+		mfm |= (clock & mask);
+	}
+	return mfm;
+}
+
+static u32 mfm_decode(u32 mfm)
+{
+	u32 data = 0;
+	u32 clock = 0;
+	u32 mask = 1;
+	while (mfm) {
+		if (mfm & 1)
+			clock |= mask;
+		mfm >>= 1;
+		if (mfm & 1)
+			data |= mask;
+		mfm >>= 1;
+		mask <<= 1;
+	}
+	return data;
+}
+
+static int dock_command(struct dock_state *s, u16 cmd, int len, int retlen)
+{
+	u32 mfm;
+	int count;
+	u32 data = cmd;
+	int ret;
+	int err = -1;
+	unsigned long flags;
+
+	data = data << 2 | 3; /* add 0101 mfm data*/
+	mfm = mfm_encode(data, len, false);
+	count = len * 2 + 2;
+
+	msm_enable_fast_timer();
+	local_irq_save(flags);
+	ret = dock_send_bits(s, mfm, count, MFM_DELAY_NS);
+	if (!ret) {
+		dock_in();
+		if (dock_sync(s, MFM_DELAY_NS * 5))
+			ret = dock_get_bits(s, retlen * 2, &err);
+		else
+			ret = -1;
+		dock_out(s->level);
+	}
+	local_irq_restore(flags);
+
+	dock_delay((ret < 0) ? MFM_DELAY_NS * 6 : MFM_DELAY_NS * 2);
+	msm_disable_fast_timer();
+	if (ret < 0) {
+		pr_warning("dock_command: %x: no response\n", cmd);
+		return ret;
+	}
+	data = mfm_decode(ret);
+	mfm = mfm_encode(data, retlen, true);
+	if (mfm != ret || err) {
+		pr_warning("dock_command: %x: bad response, "
+			   "data %x, mfm %x %x, err %d\n",
+			   cmd, data, mfm, ret, err);
+		return -EIO;
+	}
+	return data;
+}
+
+static int dock_command_retry(struct dock_state *s, u16 cmd, size_t len, size_t retlen)
+{
+	int retry = 20;
+	int ret;
+	while (retry--) {
+		ret = dock_command(s, cmd, len, retlen);
+		if (ret >= 0)
+			return ret;
+		if (retry != 19)
+			msleep(10);
+	}
+	s->dock_connected_unknown = true;
+	return -EIO;
+}
+
+static int dock_read_single(struct dock_state *s, int addr)
+{
+	int ret = -1, last;
+	int retry = 20;
+	while (retry--) {
+		last = ret;
+		ret = dock_command_retry(s, addr << 1, 6, 8);
+		if (ret < 0 || ret == last)
+			return ret;
+	}
+	return -EIO;
+}
+
+static int dock_read_multi(struct dock_state *s, int addr, u8 *data, size_t len)
+{
+	int ret;
+	int i;
+	u8 suml, sumr = -1;
+	int retry = 20;
+	while (retry--) {
+		suml = 0;
+		for (i = 0; i <= len; i++) {
+			ret = dock_command_retry(s, (addr + i) << 1, 6, 8);
+			if (ret < 0)
+				return ret;
+			if (i < len) {
+				data[i] = ret;
+				suml += ret;
+			} else
+				sumr = ret;
+		}
+		if (sumr == suml)
+			return 0;
+
+		pr_warning("dock_read_multi(%x): bad checksum, %x != %x\n",
+			   addr, sumr, suml);
+	}
+	return -EIO;
+}
+
+static int dock_write_byte(struct dock_state *s, int addr, u8 data)
+{
+	return dock_command_retry(s, 1 | addr << 1 | data << 4, 6 + 8, 1);
+}
+
+static int dock_write_multi(struct dock_state *s, int addr, u8 *data, size_t len)
+{
+	int ret;
+	int i;
+	u8 sum;
+	int retry = 2;
+	while (retry--) {
+		sum = 0;
+		for (i = 0; i < len; i++) {
+			sum += data[i];
+			ret = dock_write_byte(s, addr + i, data[i]);
+			if (ret < 0)
+				return ret;
+		}
+		ret = dock_write_byte(s, addr + len, sum);
+		if (ret <= 0)
+			return ret;
+	}
+	return -EIO;
+}
+
+static int dock_acquire(struct dock_state *s)
+{
+	mutex_lock(&s->lock);
+	dock_in();
+	if (dock_read()) {
+		/* Allow some time for the dock pull-down resistor to discharge
+		 * the capasitor.
+		 */
+		msleep(20);
+		if (dock_read()) {
+			mutex_unlock(&s->lock);
+			return -ENOENT;
+		}
+	}
+	dock_out(0);
+	s->level = false;
+	return 0;
+}
+
+static void dock_release(struct dock_state *s)
+{
+	dock_in();
+	mutex_unlock(&s->lock);
+}
+
+enum {
+	DOCK_TYPE = 0x0,
+	DOCK_BT_ADDR = 0x1, /* - 0x7 */
+
+	DOCK_PIN_CODE = 0x0,
+};
+
+static ssize_t bt_addr_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int ret;
+	u8 bt_addr[6];
+
+	ret = dock_acquire(&ds);
+	if (ret < 0)
+		return ret;
+	ret = dock_read_multi(&ds, DOCK_BT_ADDR, bt_addr, 6);
+	dock_release(&ds);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		bt_addr[0], bt_addr[1], bt_addr[2],
+		bt_addr[3], bt_addr[4], bt_addr[5]);
+}
+static DEVICE_ATTR(bt_addr, S_IRUGO | S_IWUSR, bt_addr_show, NULL);
+
+static ssize_t bt_pin_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t size)
+{
+	int ret, i;
+	u8 pin[4];
+
+	if (size < 4)
+		return -EINVAL;
+
+	for (i = 0; i < sizeof(pin); i++) {
+		if ((pin[i] = buf[i] - '0') > 10)
+			return -EINVAL;
+	}
+
+	ret = dock_acquire(&ds);
+	if (ret < 0)
+		return ret;
+	ret = dock_write_multi(&ds, DOCK_PIN_CODE, pin, 4);
+	dock_release(&ds);
+	if (ret < 0)
+		return ret;
+
+	return size;
+}
+static DEVICE_ATTR(bt_pin, S_IRUGO | S_IWUSR, NULL, bt_pin_store);
+
+
+static int power_get_property(struct power_supply *psy,
+			      enum power_supply_property psp,
+			      union power_supply_propval *val)
+{
+	if (psp != POWER_SUPPLY_PROP_ONLINE)
+		return -EINVAL;
+
+	if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
+		val->intval = (vbus_present && (usb_status == 2 || dock_mains));
+	} else {
+		val->intval = vbus_present;
+	}
+	return 0;
+}
+
+static enum power_supply_property power_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static struct power_supply ac_supply = {
+	.name = "ac",
+	.type = POWER_SUPPLY_TYPE_MAINS,
+	.supplied_to = supply_list,
+	.num_supplicants = ARRAY_SIZE(supply_list),
+	.properties = power_properties,
+	.num_properties = ARRAY_SIZE(power_properties),
+	.get_property = power_get_property,
+};
+
+static struct power_supply usb_supply = {
+	.name = "usb",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.supplied_to = supply_list,
+	.num_supplicants = ARRAY_SIZE(supply_list),
+	.properties = power_properties,
+	.num_properties = ARRAY_SIZE(power_properties),
+	.get_property = power_get_property,
+};
+
+/* rpc related */
+#define APP_BATT_PDEV_NAME		"rs30100001:00000000"
+#define APP_BATT_PROG			0x30100001
+#define APP_BATT_VER			MSM_RPC_VERS(0,0)
+#define HTC_PROCEDURE_BATTERY_NULL	0
+#define HTC_PROCEDURE_GET_BATT_LEVEL	1
+#define HTC_PROCEDURE_GET_BATT_INFO	2
+#define HTC_PROCEDURE_GET_CABLE_STATUS	3
+#define HTC_PROCEDURE_SET_BATT_DELTA	4
+
+static struct msm_rpc_endpoint *endpoint;
+
+struct battery_info_reply {
+	u32 batt_id;		/* Battery ID from ADC */
+	u32 batt_vol;		/* Battery voltage from ADC */
+	u32 batt_temp;		/* Battery Temperature (C) from formula and ADC */
+	u32 batt_current;	/* Battery current from ADC */
+	u32 level;		/* formula */
+	u32 charging_source;	/* 0: no cable, 1:usb, 2:AC */
+	u32 charging_enabled;	/* 0: Disable, 1: Enable */
+	u32 full_bat;		/* Full capacity of battery (mAh) */
+};
+
+static void dock_work_proc(struct work_struct *work)
+{
+	int dockid;
+
+	if (!vbus_present || dock_acquire(&ds))
+		goto no_dock;
+
+	if (ds.dock_connected_unknown) {
+		/* force a new dock notification if a command failed */
+		switch_set_state(&dock_switch, 0);
+		ds.dock_connected_unknown = false;
+	}
+
+	dockid = dock_read_single(&ds, DOCK_TYPE);
+	dock_release(&ds);
+
+	pr_info("Detected dock with ID %02x\n", dockid);
+	if (dockid >= 0) {
+		msm_hsusb_set_vbus_state(0);
+		dock_mains = !!(dockid & 0x80);
+		switch_set_state(&dock_switch, (dockid & 1) ? 2 : 1);
+		goto done;
+	}
+no_dock:
+	dock_mains = false;
+	switch_set_state(&dock_switch, 0);
+	msm_hsusb_set_vbus_state(vbus_present);
+done:
+	power_supply_changed(&ac_supply);
+	power_supply_changed(&usb_supply);
+	wake_unlock(&dock_work_wake_lock);
+}
+
+static int htc_battery_probe(struct platform_device *pdev)
+{
+	struct rpc_request_hdr req;	
+	struct htc_get_batt_info_rep {
+		struct rpc_reply_hdr hdr;
+		struct battery_info_reply info;
+	} rep;
+
+	int rc;
+
+	endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0);
+	if (IS_ERR(endpoint)) {
+		printk(KERN_ERR "%s: init rpc failed! rc = %ld\n",
+		       __FUNCTION__, PTR_ERR(endpoint));
+		return PTR_ERR(endpoint);
+	}
+
+	/* must do this or we won't get cable status updates */
+	rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_BATT_INFO,
+				&req, sizeof(req),
+				&rep, sizeof(rep),
+				5 * HZ);
+	if (rc < 0)
+		printk(KERN_ERR "%s: get info failed\n", __FUNCTION__);
+
+	power_supply_register(&pdev->dev, &ac_supply);
+	power_supply_register(&pdev->dev, &usb_supply);
+
+	INIT_WORK(&dock_work, dock_work_proc);
+	dock_wq = create_singlethread_workqueue("dock");
+
+	return 0;
+}
+
+static struct platform_driver htc_battery_driver = {
+	.probe	= htc_battery_probe,
+	.driver	= {
+		.name	= APP_BATT_PDEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+/* batt_mtoa server definitions */
+#define BATT_MTOA_PROG				0x30100000
+#define BATT_MTOA_VERS				0
+#define RPC_BATT_MTOA_NULL			0
+#define RPC_BATT_MTOA_SET_CHARGING_PROC		1
+#define RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC	2
+#define RPC_BATT_MTOA_LEVEL_UPDATE_PROC		3
+
+struct rpc_batt_mtoa_cable_status_update_args {
+	int status;
+};
+
+static int handle_battery_call(struct msm_rpc_server *server,
+			       struct rpc_request_hdr *req, unsigned len)
+{	
+	struct rpc_batt_mtoa_cable_status_update_args *args;
+
+	if (req->procedure != RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC)
+		return 0;
+
+	args = (struct rpc_batt_mtoa_cable_status_update_args *)(req + 1);
+	args->status = be32_to_cpu(args->status);
+	pr_info("cable_status_update: status=%d\n",args->status);
+
+	args->status = !!args->status;
+
+	vbus_present = args->status;
+	wake_lock(&dock_work_wake_lock);
+	queue_work(dock_wq, &dock_work);
+	return 0;
+}
+
+void notify_usb_connected(int status)
+{
+	printk("### notify_usb_connected(%d) ###\n", status);
+	usb_status = status;
+	power_supply_changed(&ac_supply);
+	power_supply_changed(&usb_supply);
+}
+
+int is_ac_power_supplied(void)
+{
+	return vbus_present && (usb_status == 2 || dock_mains);
+}
+
+static struct msm_rpc_server battery_server = {
+	.prog = BATT_MTOA_PROG,
+	.vers = BATT_MTOA_VERS,
+	.rpc_call = handle_battery_call,
+};
+
+static int __init htc_battery_init(void)
+{
+	int ret;
+	gpio_request(_GPIO_DOCK, "dock");
+	dock_in();
+	wake_lock_init(&dock_work_wake_lock, WAKE_LOCK_SUSPEND, "dock");
+	platform_driver_register(&htc_battery_driver);
+	msm_rpc_create_server(&battery_server);
+	if (switch_dev_register(&dock_switch) == 0) {
+		ret = device_create_file(dock_switch.dev, &dev_attr_bt_addr);
+		WARN_ON(ret);
+		ret = device_create_file(dock_switch.dev, &dev_attr_bt_pin);
+		WARN_ON(ret);
+	}
+
+	return 0;
+}
+
+module_init(htc_battery_init);
+MODULE_DESCRIPTION("HTC Battery Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/htc_pwrsink.c b/arch/arm/mach-msm/htc_pwrsink.c
new file mode 100644
index 0000000..12d6182
--- /dev/null
+++ b/arch/arm/mach-msm/htc_pwrsink.c
@@ -0,0 +1,289 @@
+/* arch/arm/mach-msm/htc_pwrsink.c
+ *
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (C) 2008 Google, Inc.
+ * Author: San Mehat <san@google.com>
+ *         Kant Kang <kant_kang@htc.com>
+ *         Eiven Peng <eiven_peng@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/module.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/earlysuspend.h>
+#include <mach/msm_smd.h>
+#include <mach/htc_pwrsink.h>
+
+#include "smd_private.h"
+
+enum {
+	PWRSINK_DEBUG_CURR_CHANGE = 1U << 0,
+	PWRSINK_DEBUG_CURR_CHANGE_AUDIO = 1U << 1,
+};
+static int pwrsink_debug_mask;
+module_param_named(debug_mask, pwrsink_debug_mask, int,
+		S_IRUGO | S_IWUSR | S_IWGRP);
+
+static int initialized;
+static unsigned audio_path = 1;	/* HTC_SND_DEVICE_SPEAKER = 1 */
+static struct pwr_sink_audio audio_sink_array[PWRSINK_AUDIO_LAST + 1];
+static struct pwr_sink *sink_array[PWRSINK_LAST + 1];
+static DEFINE_SPINLOCK(sink_lock);
+static DEFINE_SPINLOCK(audio_sink_lock);
+static unsigned long total_sink;
+static uint32_t *smem_total_sink;
+
+int htc_pwrsink_set(pwrsink_id_type id, unsigned percent_utilized)
+{
+	unsigned long flags;
+
+	if (!smem_total_sink)
+		smem_total_sink = smem_alloc(SMEM_ID_VENDOR0, sizeof(uint32_t));
+
+	if (!initialized)
+		return -EAGAIN;
+
+	if (id < 0 || id > PWRSINK_LAST)
+		return -EINVAL;
+
+	spin_lock_irqsave(&sink_lock, flags);
+
+	if (!sink_array[id]) {
+		spin_unlock_irqrestore(&sink_lock, flags);
+		return -ENOENT;
+	}
+
+	if (sink_array[id]->percent_util == percent_utilized) {
+		spin_unlock_irqrestore(&sink_lock, flags);
+		return 0;
+	}
+
+	total_sink -= (sink_array[id]->ua_max *
+		       sink_array[id]->percent_util / 100);
+	sink_array[id]->percent_util = percent_utilized;
+	total_sink += (sink_array[id]->ua_max *
+		       sink_array[id]->percent_util / 100);
+
+	if (smem_total_sink)
+		*smem_total_sink = total_sink / 1000;
+
+	pr_debug("htc_pwrsink: ID %d, Util %d%%, Total %lu uA %s\n",
+		 id, percent_utilized, total_sink,
+		 smem_total_sink ? "SET" : "");
+
+	spin_unlock_irqrestore(&sink_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_set);
+
+static void compute_audio_current(void)
+{
+	/* unsigned long flags; */
+	unsigned max_percent = 0;
+	int i, active_audio_sinks = 0;
+	pwrsink_audio_id_type last_active_audio_sink = 0;
+
+	/* Make sure this segment will be spinlocked
+	before computing by calling function. */
+	/* spin_lock_irqsave(&audio_sink_lock, flags); */
+	for (i = 0; i <= PWRSINK_AUDIO_LAST; ++i) {
+		max_percent = (audio_sink_array[i].percent > max_percent) ?
+				audio_sink_array[i].percent : max_percent;
+		if (audio_sink_array[i].percent > 0) {
+			active_audio_sinks++;
+			last_active_audio_sink = i;
+		}
+	}
+	if (active_audio_sinks == 0)
+		htc_pwrsink_set(PWRSINK_AUDIO, 0);
+	else if (active_audio_sinks == 1) {
+		pwrsink_audio_id_type laas =  last_active_audio_sink;
+		/* TODO: add volume and routing path current. */
+		if (audio_path == 1)	/* Speaker */
+			htc_pwrsink_set(PWRSINK_AUDIO,
+				audio_sink_array[laas].percent);
+		else
+			htc_pwrsink_set(PWRSINK_AUDIO,
+				audio_sink_array[laas].percent * 9 / 10);
+	} else if (active_audio_sinks > 1) {
+		/* TODO: add volume and routing path current. */
+		if (audio_path == 1)	/* Speaker */
+			htc_pwrsink_set(PWRSINK_AUDIO, max_percent);
+		else
+			htc_pwrsink_set(PWRSINK_AUDIO, max_percent * 9 / 10);
+	}
+	/* spin_unlock_irqrestore(&audio_sink_lock, flags); */
+
+	if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+		pr_info("%s: active_audio_sinks=%d, audio_path=%d\n", __func__,
+				active_audio_sinks, audio_path);
+}
+
+int htc_pwrsink_audio_set(pwrsink_audio_id_type id, unsigned percent_utilized)
+{
+	unsigned long flags;
+
+	if (id < 0 || id > PWRSINK_AUDIO_LAST)
+		return -EINVAL;
+
+	if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+		pr_info("%s: id=%d, percent=%d, percent_old=%d\n", __func__,
+			id, percent_utilized, audio_sink_array[id].percent);
+
+	spin_lock_irqsave(&audio_sink_lock, flags);
+	if (audio_sink_array[id].percent == percent_utilized) {
+		spin_unlock_irqrestore(&audio_sink_lock, flags);
+		return 0;
+	}
+	audio_sink_array[id].percent = percent_utilized;
+	spin_unlock_irqrestore(&audio_sink_lock, flags);
+	compute_audio_current();
+	return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_audio_set);
+
+int htc_pwrsink_audio_volume_set(pwrsink_audio_id_type id, unsigned volume)
+{
+	unsigned long flags;
+
+	if (id < 0 || id > PWRSINK_AUDIO_LAST)
+		return -EINVAL;
+
+	if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+		pr_info("%s: id=%d, volume=%d, volume_old=%d\n", __func__,
+			id, volume, audio_sink_array[id].volume);
+
+	spin_lock_irqsave(&audio_sink_lock, flags);
+	if (audio_sink_array[id].volume == volume) {
+		spin_unlock_irqrestore(&audio_sink_lock, flags);
+		return 0;
+	}
+	audio_sink_array[id].volume = volume;
+	spin_unlock_irqrestore(&audio_sink_lock, flags);
+	compute_audio_current();
+	return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_audio_volume_set);
+
+int htc_pwrsink_audio_path_set(unsigned path)
+{
+	unsigned long flags;
+
+	if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+		pr_info("%s: path=%d, path_old=%d\n",
+			__func__, path, audio_path);
+
+	spin_lock_irqsave(&audio_sink_lock, flags);
+	if (audio_path == path) {
+		spin_unlock_irqrestore(&audio_sink_lock, flags);
+		return 0;
+	}
+	audio_path = path;
+	spin_unlock_irqrestore(&audio_sink_lock, flags);
+	compute_audio_current();
+	return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_audio_path_set);
+
+void htc_pwrsink_suspend_early(struct early_suspend *h)
+{
+	htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 7);
+}
+
+int htc_pwrsink_suspend_late(struct device *dev)
+{
+	struct pwr_sink_platform_data *pdata = dev_get_platdata(dev);
+
+	if (pdata && pdata->suspend_late)
+		pdata->suspend_late(to_platform_device(dev), PMSG_SUSPEND);
+	else
+		htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 1);
+	return 0;
+}
+
+int htc_pwrsink_resume_early(struct device *dev)
+{
+	struct pwr_sink_platform_data *pdata = dev_get_platdata(dev);;
+
+	if (pdata && pdata->resume_early)
+		pdata->resume_early(to_platform_device(dev));
+	else
+		htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 7);
+	return 0;
+}
+
+void htc_pwrsink_resume_late(struct early_suspend *h)
+{
+	htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 38);
+}
+
+#ifdef CONFIG_WAKELOCK
+struct early_suspend htc_pwrsink_early_suspend = {
+	.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1,
+	.suspend = htc_pwrsink_suspend_early,
+	.resume = htc_pwrsink_resume_late,
+};
+#endif
+
+static int __init htc_pwrsink_probe(struct platform_device *pdev)
+{
+	struct pwr_sink_platform_data *pdata = pdev->dev.platform_data;
+	int i;
+
+	if (!pdata)
+		return -EINVAL;
+
+	total_sink = 0;
+	for (i = 0; i < pdata->num_sinks; i++) {
+		sink_array[pdata->sinks[i].id] = &pdata->sinks[i];
+		total_sink += (pdata->sinks[i].ua_max *
+			       pdata->sinks[i].percent_util / 100);
+	}
+
+	initialized = 1;
+
+#ifdef CONFIG_WAKELOCK
+	if (pdata->suspend_early)
+		htc_pwrsink_early_suspend.suspend = pdata->suspend_early;
+	if (pdata->resume_late)
+		htc_pwrsink_early_suspend.resume = pdata->resume_late;
+#endif
+	register_early_suspend(&htc_pwrsink_early_suspend);
+
+	return 0;
+}
+
+static struct dev_pm_ops htc_pwrsink_pm_ops = {
+	.suspend_noirq = htc_pwrsink_suspend_late,
+	.resume_noirq = htc_pwrsink_resume_early,
+};
+
+static struct platform_driver htc_pwrsink_driver = {
+	.probe = htc_pwrsink_probe,
+	.driver = {
+		.name = "htc_pwrsink",
+		.owner = THIS_MODULE,
+		.pm = &htc_pwrsink_pm_ops,
+	},
+};
+
+static int __init htc_pwrsink_init(void)
+{
+	initialized = 0;
+	memset(sink_array, 0, sizeof(sink_array));
+	return platform_driver_register(&htc_pwrsink_driver);
+}
+
+module_init(htc_pwrsink_init);
diff --git a/arch/arm/mach-msm/htc_wifi_nvs.c b/arch/arm/mach-msm/htc_wifi_nvs.c
new file mode 100644
index 0000000..1753595
--- /dev/null
+++ b/arch/arm/mach-msm/htc_wifi_nvs.c
@@ -0,0 +1,106 @@
+/* arch/arm/mach-msm/htc_wifi_nvs.c
+ *
+ * Code to extract WiFi calibration information from ATAG set up 
+ * by the bootloader.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+
+#include <asm/setup.h>
+
+/* configuration tags specific to msm */
+#define ATAG_MSM_WIFI	0x57494649 /* MSM WiFi */
+
+#define NVS_MAX_SIZE	0x800U
+#define NVS_LEN_OFFSET	0x0C
+#define NVS_DATA_OFFSET	0x40
+
+static unsigned char wifi_nvs_ram[NVS_MAX_SIZE];
+static struct proc_dir_entry *wifi_calibration;
+
+unsigned char *get_wifi_nvs_ram( void )
+{
+	return wifi_nvs_ram;
+}
+EXPORT_SYMBOL(get_wifi_nvs_ram);
+
+static int __init parse_tag_msm_wifi(const struct tag *tag)
+{
+	unsigned char *dptr = (unsigned char *)(&tag->u);
+	unsigned size;
+#ifdef ATAG_MSM_WIFI_DEBUG
+	unsigned i;
+#endif
+
+	size = min((tag->hdr.size - 2) * sizeof(__u32), NVS_MAX_SIZE);
+#ifdef ATAG_MSM_WIFI_DEBUG
+	printk("WiFi Data size = %d , 0x%x\n", tag->hdr.size, tag->hdr.tag);
+	for(i=0;( i < size );i++) {
+		printk("%02x ", *dptr++);
+	}
+#endif	
+	memcpy(wifi_nvs_ram, dptr, size);
+	return 0;
+}
+
+__tagtable(ATAG_MSM_WIFI, parse_tag_msm_wifi);
+
+static unsigned wifi_get_nvs_size( void )
+{
+	unsigned char *ptr;
+	unsigned len;
+
+	ptr = get_wifi_nvs_ram();
+	/* Size in format LE assumed */
+	memcpy(&len, ptr + NVS_LEN_OFFSET, sizeof(len));
+	len = min(len, (NVS_MAX_SIZE - NVS_DATA_OFFSET));
+	return len;
+}
+
+int wifi_calibration_size_set(void)
+{
+	if (wifi_calibration != NULL)
+		wifi_calibration->size = wifi_get_nvs_size();
+	return 0;
+}
+
+static int wifi_calibration_read_proc(char *page, char **start, off_t off,
+					int count, int *eof, void *data)
+{
+	unsigned char *ptr;
+	unsigned len;
+
+	ptr = get_wifi_nvs_ram();
+	len = min(wifi_get_nvs_size(), (unsigned)count);
+	memcpy(page, ptr + NVS_DATA_OFFSET, len);
+	return len;
+}
+
+static int __init wifi_nvs_init(void)
+{
+	wifi_calibration = create_proc_entry("calibration", 0444, NULL);
+	if (wifi_calibration != NULL) {
+		wifi_calibration->size = wifi_get_nvs_size();
+		wifi_calibration->read_proc = wifi_calibration_read_proc;
+		wifi_calibration->write_proc = NULL;
+	}
+	return 0;
+}
+
+device_initcall(wifi_nvs_init);
diff --git a/arch/arm/mach-msm/hw3d.c b/arch/arm/mach-msm/hw3d.c
new file mode 100644
index 0000000..aef7f37
--- /dev/null
+++ b/arch/arm/mach-msm/hw3d.c
@@ -0,0 +1,889 @@
+/* arch/arm/mach-msm/hw3d.c
+ *
+ * Register/Interrupt access for userspace 3D library.
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ * Heavily modified: 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.
+ *
+ */
+
+/* #define DEBUG */
+/* #define VERBOSE */
+
+#include <linux/clk.h>
+#include <linux/earlysuspend.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/cdev.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/msm_hw3d.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <asm/io.h>
+
+#include <mach/board.h>
+
+#if defined(VERBOSE)
+#define VDBG(x...)	pr_debug(x)
+#else
+#define VDBG(x...)	do {} while(0)
+#endif
+
+struct mem_region {
+	unsigned long		pbase;
+	unsigned long		size;
+	void __iomem		*vbase;
+};
+
+/* Device minor numbers for master and client */
+#define MINOR_MASTER 0
+#define MINOR_CLIENT 1
+
+struct hw3d_info {
+	dev_t devno;
+	struct cdev	master_cdev;
+	struct cdev	client_cdev;
+
+	struct clk		*grp_clk;
+	struct clk		*imem_clk;
+	int			irq;
+
+	struct mem_region	regions[HW3D_NUM_REGIONS];
+
+	wait_queue_head_t	irq_wq;
+	bool			irq_pending;
+	bool			irq_en;
+	bool			suspending;
+	bool			revoking;
+	bool			enabled;
+
+	struct timer_list	revoke_timer;
+	wait_queue_head_t	revoke_wq;
+	wait_queue_head_t	revoke_done_wq;
+	unsigned int		waiter_cnt;
+
+	spinlock_t		lock;
+
+	struct file		*client_file;
+	struct task_struct	*client_task;
+
+	struct early_suspend	early_suspend;
+	struct wake_lock	wake_lock;
+};
+static struct hw3d_info *hw3d_info;
+
+struct hw3d_data {
+	struct vm_area_struct	*vmas[HW3D_NUM_REGIONS];
+	struct mutex		mutex;
+	bool			closing;
+};
+
+#define REGION_PAGE_ID(addr)		\
+	((((uint32_t)(addr)) >> (28 - PAGE_SHIFT)) & 0xf)
+#define REGION_PAGE_OFFS(addr)		\
+	((((uint32_t)(addr)) & ~(0xf << (28 - PAGE_SHIFT))))
+
+static int hw3d_open(struct inode *, struct file *);
+static int hw3d_release(struct inode *, struct file *);
+static int hw3d_mmap(struct file *, struct vm_area_struct *);
+static int hw3d_flush(struct file *, fl_owner_t);
+static long hw3d_ioctl(struct file *, unsigned int, unsigned long);
+
+static void hw3d_vma_open(struct vm_area_struct *);
+static void hw3d_vma_close(struct vm_area_struct *);
+
+static struct file_operations hw3d_fops = {
+	.open		= hw3d_open,
+	.release	= hw3d_release,
+	.mmap		= hw3d_mmap,
+	.flush		= hw3d_flush,
+	.unlocked_ioctl	= hw3d_ioctl,
+};
+
+static struct vm_operations_struct hw3d_vm_ops = {
+	.open = hw3d_vma_open,
+	.close = hw3d_vma_close,
+};
+
+static bool is_master(struct hw3d_info *info, struct file *file)
+{
+	int fmin = MINOR(file->f_dentry->d_inode->i_rdev);
+	return fmin == MINOR(info->master_cdev.dev);
+}
+
+static bool is_client(struct hw3d_info *info, struct file *file)
+{
+	int fmin = MINOR(file->f_dentry->d_inode->i_rdev);
+	return fmin == MINOR(info->client_cdev.dev);
+}
+
+inline static void locked_hw3d_irq_disable(struct hw3d_info *info)
+{
+	if (info->irq_en) {
+		disable_irq_nosync(info->irq);
+		info->irq_en = 0;
+	}
+}
+
+inline static void locked_hw3d_irq_enable(struct hw3d_info *info)
+{
+	if (!info->irq_en) {
+		enable_irq(info->irq);
+		info->irq_en = 1;
+	}
+}
+
+static void hw3d_disable_interrupt(struct hw3d_info *info)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock, flags);
+	locked_hw3d_irq_disable(info);
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static irqreturn_t hw3d_irq_handler(int irq, void *data)
+{
+	struct hw3d_info *info = data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock, flags);
+	locked_hw3d_irq_disable(info);
+	info->irq_pending = 1;
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	wake_up(&info->irq_wq);
+
+	return IRQ_HANDLED;
+}
+
+static long hw3d_wait_for_interrupt(struct hw3d_info *info, struct file *filp)
+{
+	struct hw3d_data *data = filp->private_data;
+	unsigned long flags;
+	int ret;
+
+	if (is_master(info, filp)) {
+		pr_err("%s: cannot wait for irqs on master node\n", __func__);
+		return -EPERM;
+	}
+
+	for (;;) {
+		spin_lock_irqsave(&info->lock, flags);
+		if (info->irq_pending) {
+			info->irq_pending = 0;
+			spin_unlock_irqrestore(&info->lock, flags);
+			return 0;
+		}
+		locked_hw3d_irq_enable(info);
+		spin_unlock_irqrestore(&info->lock, flags);
+
+		ret = wait_event_interruptible(info->irq_wq,
+					       info->irq_pending ||
+					       info->revoking ||
+					       data->closing);
+		/* always make sure the irq gets disabled */
+		if (ret == 0 && !info->irq_pending)
+			ret = -EPIPE;
+		if (ret < 0) {
+			hw3d_disable_interrupt(info);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static long hw3d_wait_for_revoke(struct hw3d_info *info, struct file *filp)
+{
+	struct hw3d_data *data = filp->private_data;
+	int ret;
+
+	if (is_master(info, filp)) {
+		pr_err("%s: cannot revoke on master node\n", __func__);
+		return -EPERM;
+	}
+
+	ret = wait_event_interruptible(info->revoke_wq,
+				       info->revoking ||
+				       data->closing);
+	if (ret == 0 && data->closing)
+		ret = -EPIPE;
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static void locked_hw3d_client_done(struct hw3d_info *info, int had_timer)
+{
+	if (info->enabled) {
+		pr_debug("hw3d: was enabled\n");
+		info->enabled = 0;
+		clk_disable(info->grp_clk);
+		clk_disable(info->imem_clk);
+	}
+	info->revoking = 0;
+
+	/* double check that the irqs are disabled */
+	locked_hw3d_irq_disable(info);
+
+	if (had_timer)
+		wake_unlock(&info->wake_lock);
+	wake_up(&info->revoke_done_wq);
+}
+
+static void do_force_revoke(struct hw3d_info *info)
+{
+	unsigned long flags;
+
+	/* at this point, the task had a chance to relinquish the gpu, but
+	 * it hasn't. So, we kill it */
+	spin_lock_irqsave(&info->lock, flags);
+	pr_debug("hw3d: forcing revoke\n");
+	locked_hw3d_irq_disable(info);
+	if (info->client_task) {
+		pr_info("hw3d: force revoke from pid=%d\n",
+			info->client_task->pid);
+		force_sig(SIGKILL, info->client_task);
+		put_task_struct(info->client_task);
+		info->client_task = NULL;
+	}
+	locked_hw3d_client_done(info, 1);
+	pr_debug("hw3d: done forcing revoke\n");
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+#define REVOKE_TIMEOUT		(2 * HZ)
+static void locked_hw3d_revoke(struct hw3d_info *info)
+{
+	/* force us to wait to suspend until the revoke is done. If the
+	 * user doesn't release the gpu, the timer will turn off the gpu,
+	 * and force kill the process. */
+	wake_lock(&info->wake_lock);
+	info->revoking = 1;
+	wake_up(&info->revoke_wq);
+	mod_timer(&info->revoke_timer, jiffies + REVOKE_TIMEOUT);
+}
+
+bool is_msm_hw3d_file(struct file *file)
+{
+	struct hw3d_info *info = hw3d_info;
+	if (MAJOR(file->f_dentry->d_inode->i_rdev) == MAJOR(info->devno) &&
+	    (is_master(info, file) || is_client(info, file)))
+		return 1;
+	return 0;
+}
+
+void put_msm_hw3d_file(struct file *file)
+{
+	if (!is_msm_hw3d_file(file))
+		return;
+	fput(file);
+}
+
+int get_msm_hw3d_file(int fd, uint32_t *offs, unsigned long *pbase,
+		      unsigned long *len, struct file **filp)
+{
+	struct hw3d_info *info = hw3d_info;
+	struct file *file;
+	struct hw3d_data *data;
+	uint32_t offset = HW3D_OFFSET_IN_REGION(*offs);
+	int region = HW3D_REGION_ID(*offs);
+	int ret = 0;
+
+	if (unlikely(region >= HW3D_NUM_REGIONS)) {
+		VDBG("hw3d: invalid region %d requested\n", region);
+		return -EINVAL;
+	} else if (unlikely(offset >= info->regions[region].size)) {
+		VDBG("hw3d: offset %08x outside of the requested region %d\n",
+		     offset, region);
+		return -EINVAL;
+	}
+
+	file = fget(fd);
+	if (unlikely(file == NULL)) {
+		pr_info("%s: requested data from file descriptor that doesn't "
+			"exist.", __func__);
+		return -EINVAL;
+	} else if (!is_msm_hw3d_file(file)) {
+		ret = -1;
+		goto err;
+	}
+
+	data = file->private_data;
+	if (unlikely(!data)) {
+		VDBG("hw3d: invalid file\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	mutex_lock(&data->mutex);
+	if (unlikely(!data->vmas[region])) {
+		mutex_unlock(&data->mutex);
+		VDBG("hw3d: requested hw3d region is not mapped\n");
+		ret = -ENOENT;
+		goto err;
+	}
+
+	*offs = offset;
+	*pbase = info->regions[region].pbase;
+	*filp = file;
+	*len = data->vmas[region]->vm_end - data->vmas[region]->vm_start;
+	mutex_unlock(&data->mutex);
+	return 0;
+
+err:
+	fput(file);
+	return ret;
+}
+
+static int hw3d_flush(struct file *filp, fl_owner_t id)
+{
+	struct hw3d_info *info = hw3d_info;
+	struct hw3d_data *data = filp->private_data;
+
+	if (!data) {
+		pr_err("%s: no private data\n", __func__);
+		return -EINVAL;
+	}
+
+	if (is_master(info, filp))
+		return 0;
+	pr_debug("hw3d: closing\n");
+	/* releases any blocked ioctls */
+	data->closing = 1;
+	wake_up(&info->revoke_wq);
+	wake_up(&info->irq_wq);
+	return 0;
+}
+
+static int should_wakeup(struct hw3d_info *info, unsigned int cnt)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&info->lock, flags);
+	ret = (cnt != info->waiter_cnt) ||
+		(!info->suspending && !info->client_file);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	return ret;
+}
+
+static int locked_open_wait_for_gpu(struct hw3d_info *info,
+				    unsigned long *flags)
+{
+	unsigned int my_cnt;
+	int ret;
+
+	my_cnt = ++info->waiter_cnt;
+	pr_debug("%s: wait_for_open %d\n", __func__, my_cnt);
+
+	/* in case there are other waiters, wake and release them. */
+	wake_up(&info->revoke_done_wq);
+
+	if (info->suspending)
+		pr_info("%s: suspended, waiting (%d %d)\n", __func__,
+			current->group_leader->pid, current->pid);
+	if (info->client_file)
+		pr_info("%s: has client, waiting (%d %d)\n", __func__,
+			current->group_leader->pid, current->pid);
+	spin_unlock_irqrestore(&info->lock, *flags);
+
+	ret = wait_event_interruptible(info->revoke_done_wq,
+				       should_wakeup(info, my_cnt));
+
+	spin_lock_irqsave(&info->lock, *flags);
+	pr_debug("%s: woke up (%d %d %p)\n", __func__,
+		 info->waiter_cnt, info->suspending, info->client_file);
+
+	if (ret >= 0) {
+		if (my_cnt != info->waiter_cnt) {
+			pr_info("%s: someone else asked for gpu after us %d:%d"
+				"(%d %d)\n", __func__,
+				current->group_leader->pid, current->pid,
+				my_cnt, info->waiter_cnt);
+			ret = -EBUSY;
+		} else if (info->suspending || info->client_file) {
+			pr_err("%s: couldn't get the gpu for %d:%d (%d %p)\n",
+			       __func__, current->group_leader->pid,
+			       current->pid, info->suspending,
+			       info->client_file);
+			ret = -EBUSY;
+		} else
+			ret = 0;
+	}
+	return ret;
+}
+
+static int hw3d_open(struct inode *inode, struct file *file)
+{
+	struct hw3d_info *info = hw3d_info;
+	struct hw3d_data *data;
+	unsigned long flags;
+	int ret = 0;
+
+	pr_info("%s: pid %d tid %d opening %s node\n", __func__,
+		current->group_leader->pid, current->pid,
+		is_master(info, file) ? "master" : "client");
+
+	if (file->private_data != NULL)
+		return -EINVAL;
+
+	data = kzalloc(sizeof(struct hw3d_data), GFP_KERNEL);
+	if (!data) {
+		pr_err("%s: unable to allocate memory for hw3d_data.\n",
+		       __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&data->mutex);
+	file->private_data = data;
+
+	/* master always succeeds, so we are done */
+	if (is_master(info, file))
+		return 0;
+
+	spin_lock_irqsave(&info->lock, flags);
+	if (info->client_file) {
+		pr_debug("hw3d: have client_file, need revoke\n");
+		locked_hw3d_revoke(info);
+	}
+
+	ret = locked_open_wait_for_gpu(info, &flags);
+	if (ret < 0) {
+		spin_unlock_irqrestore(&info->lock, flags);
+		goto err;
+	}
+	pr_info("%s: pid %d tid %d got gpu\n", __func__,
+		current->group_leader->pid, current->pid);
+
+	info->client_file = file;
+	get_task_struct(current->group_leader);
+	info->client_task = current->group_leader;
+
+	/* XXX: we enable these clocks if the client connects..
+	 * probably not right? Should only turn the clocks on when the user
+	 * tries to map the registers? */
+	clk_enable(info->imem_clk);
+	clk_enable(info->grp_clk);
+	info->enabled = 1;
+
+	spin_unlock_irqrestore(&info->lock, flags);
+	return 0;
+
+err:
+	file->private_data = NULL;
+	kfree(data);
+	return ret;
+
+}
+
+static int hw3d_release(struct inode *inode, struct file *file)
+{
+	struct hw3d_info *info = hw3d_info;
+	struct hw3d_data *data = file->private_data;
+	unsigned long flags;
+
+	BUG_ON(!data);
+
+	file->private_data = NULL;
+
+	if (is_master(info, file))
+		goto done;
+
+	pr_info("%s: in release for pid=%d tid=%d\n", __func__,
+		current->group_leader->pid, current->pid);
+	spin_lock_irqsave(&info->lock, flags);
+
+	if (info->client_task && info->client_task == current->group_leader) {
+		pr_debug("hw3d: releasing %d\n", info->client_task->pid);
+		put_task_struct(info->client_task);
+		info->client_task = NULL;
+	}
+
+	if (info->client_file && info->client_file == file) {
+		int pending;
+		/* this will be true if we are still the "owner" of the gpu */
+		pr_debug("hw3d: had file\n");
+		pending = del_timer(&info->revoke_timer);
+		locked_hw3d_client_done(info, pending);
+		info->client_file = NULL;
+	} else
+		pr_warning("hw3d: release without client_file.\n");
+	spin_unlock_irqrestore(&info->lock, flags);
+
+done:
+	kfree(data);
+	return 0;
+}
+
+static void hw3d_vma_open(struct vm_area_struct *vma)
+{
+	/* XXX: should the master be allowed to fork and keep the mappings? */
+
+	/* TODO: remap garbage page into here.
+	 *
+	 * For now, just pull the mapping. The user shouldn't be forking
+	 * and using it anyway. */
+	zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, NULL);
+}
+
+static void hw3d_vma_close(struct vm_area_struct *vma)
+{
+	struct file *file = vma->vm_file;
+	struct hw3d_data *data = file->private_data;
+	int i;
+
+	pr_debug("hw3d: current %u ppid %u file %p count %ld\n",
+		 current->pid, current->parent->pid, file, file_count(file));
+
+	BUG_ON(!data);
+
+	mutex_lock(&data->mutex);
+	for (i = 0; i < HW3D_NUM_REGIONS; ++i) {
+		if (data->vmas[i] == vma) {
+			data->vmas[i] = NULL;
+			goto done;
+		}
+	}
+	pr_warning("%s: vma %p not of ours during vma_close\n", __func__, vma);
+done:
+	mutex_unlock(&data->mutex);
+}
+
+static int hw3d_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct hw3d_info *info = hw3d_info;
+	struct hw3d_data *data = file->private_data;
+	unsigned long vma_size = vma->vm_end - vma->vm_start;
+	int ret = 0;
+	int region = REGION_PAGE_ID(vma->vm_pgoff);
+
+	if (region >= HW3D_NUM_REGIONS) {
+		pr_err("%s: Trying to mmap unknown region %d\n", __func__,
+		       region);
+		return -EINVAL;
+	} else if (vma_size > info->regions[region].size) {
+		pr_err("%s: VMA size %ld exceeds region %d size %ld\n",
+			__func__, vma_size, region,
+			info->regions[region].size);
+		return -EINVAL;
+	} else if (REGION_PAGE_OFFS(vma->vm_pgoff) != 0 ||
+		   (vma_size & ~PAGE_MASK)) {
+		pr_err("%s: Can't remap part of the region %d\n", __func__,
+		       region);
+		return -EINVAL;
+	} else if (!is_master(info, file) &&
+		   current->group_leader != info->client_task) {
+		pr_err("%s: current(%d) != client_task(%d)\n", __func__,
+		       current->group_leader->pid, info->client_task->pid);
+		return -EPERM;
+	} else if (!is_master(info, file) &&
+		   (info->revoking || info->suspending)) {
+		pr_err("%s: cannot mmap while revoking(%d) or suspending(%d)\n",
+		       __func__, info->revoking, info->suspending);
+		return -EPERM;
+	}
+
+	mutex_lock(&data->mutex);
+	if (data->vmas[region] != NULL) {
+		pr_err("%s: Region %d already mapped (pid=%d tid=%d)\n",
+		       __func__, region, current->group_leader->pid,
+		       current->pid);
+		ret = -EBUSY;
+		goto done;
+	}
+
+	/* our mappings are always noncached */
+#ifdef pgprot_noncached
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
+
+	ret = io_remap_pfn_range(vma, vma->vm_start,
+				 info->regions[region].pbase >> PAGE_SHIFT,
+				 vma_size, vma->vm_page_prot);
+	if (ret) {
+		pr_err("%s: Cannot remap page range for region %d!\n", __func__,
+		       region);
+		ret = -EAGAIN;
+		goto done;
+	}
+
+	/* Prevent a malicious client from stealing another client's data
+	 * by forcing a revoke on it and then mmapping the GPU buffers.
+	 */
+	if (region != HW3D_REGS)
+		memset(info->regions[region].vbase, 0,
+		       info->regions[region].size);
+
+	vma->vm_ops = &hw3d_vm_ops;
+
+	/* mark this region as mapped */
+	data->vmas[region] = vma;
+
+done:
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+
+static long hw3d_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct hw3d_info *info = hw3d_info;
+	struct hw3d_region regions[HW3D_NUM_REGIONS];
+	int i;
+
+	if (!file->private_data)
+		return -EINVAL;
+
+	switch (cmd) {
+	case HW3D_WAIT_FOR_REVOKE:
+		return hw3d_wait_for_revoke(info, file);
+
+	case HW3D_WAIT_FOR_INTERRUPT:
+		return hw3d_wait_for_interrupt(info, file);
+
+	case HW3D_GET_REGIONS:
+		for (i = 0; i < HW3D_NUM_REGIONS; ++i) {
+			regions[i].phys = info->regions[i].pbase;
+			regions[i].map_offset = HW3D_REGION_OFFSET(i);
+			regions[i].len = info->regions[i].size;
+		}
+		if (copy_to_user((void __user *)arg, regions, sizeof(regions)))
+			return -EFAULT;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void hw3d_early_suspend(struct early_suspend *h)
+{
+	unsigned long flags;
+	struct hw3d_info *info;
+	info = container_of(h, struct hw3d_info, early_suspend);
+
+	spin_lock_irqsave(&info->lock, flags);
+	info->suspending = 1;
+	if (info->client_file) {
+		pr_info("hw3d: Requesting revoke for suspend\n");
+		locked_hw3d_revoke(info);
+	}
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static void hw3d_late_resume(struct early_suspend *h)
+{
+	unsigned long flags;
+	struct hw3d_info *info;
+	info = container_of(h, struct hw3d_info, early_suspend);
+
+	spin_lock_irqsave(&info->lock, flags);
+	if (info->suspending)
+		pr_info("%s: resuming\n", __func__);
+	info->suspending = 0;
+	wake_up(&info->revoke_done_wq);
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static int hw3d_resume(struct platform_device *pdev)
+{
+	struct hw3d_info *info = platform_get_drvdata(pdev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock, flags);
+	if (info->suspending)
+		pr_info("%s: resuming\n", __func__);
+	info->suspending = 0;
+	spin_unlock_irqrestore(&info->lock, flags);
+	return 0;
+}
+
+static int __init hw3d_probe(struct platform_device *pdev)
+{
+	struct hw3d_info *info;
+#define DEV_MASTER MKDEV(MAJOR(info->devno), MINOR_MASTER)
+#define DEV_CLIENT MKDEV(MAJOR(info->devno), MINOR_CLIENT)
+	struct class *hw3d_class;
+	struct device *master_dev;
+	struct device *client_dev;
+	struct resource *res[HW3D_NUM_REGIONS];
+	int i;
+	int irq;
+	int ret = 0;
+
+	res[HW3D_REGS] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						      "regs");
+	res[HW3D_SMI] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						     "smi");
+	res[HW3D_EBI] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						     "ebi");
+	irq = platform_get_irq(pdev, 0);
+	if (!res[HW3D_REGS] || !res[HW3D_SMI] || !res[HW3D_EBI] || irq < 0) {
+		pr_err("%s: incomplete resources\n", __func__);
+		return -EINVAL;
+	}
+
+	info = kzalloc(sizeof(struct hw3d_info), GFP_KERNEL);
+	if (info == NULL) {
+		pr_err("%s: Cannot allocate memory for hw3d_info\n", __func__);
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	info->irq = irq;
+	wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND, "hw3d_revoke_lock");
+	spin_lock_init(&info->lock);
+	init_waitqueue_head(&info->irq_wq);
+	init_waitqueue_head(&info->revoke_wq);
+	init_waitqueue_head(&info->revoke_done_wq);
+	setup_timer(&info->revoke_timer,
+		    (void (*)(unsigned long))do_force_revoke,
+		    (unsigned long)info);
+
+	platform_set_drvdata(pdev, info);
+
+	info->grp_clk = clk_get(NULL, "grp_clk");
+	if (IS_ERR(info->grp_clk)) {
+		pr_err("%s: Cannot get grp_clk\n", __func__);
+		ret = PTR_ERR(info->grp_clk);
+		goto err_get_grp_clk;
+	}
+
+	info->imem_clk = clk_get(NULL, "imem_clk");
+	if (IS_ERR(info->imem_clk)) {
+		pr_err("%s: Cannot get imem_clk\n", __func__);
+		ret = PTR_ERR(info->imem_clk);
+		goto err_get_imem_clk;
+	}
+
+	for (i = 0; i < HW3D_NUM_REGIONS; ++i) {
+		info->regions[i].pbase = res[i]->start;
+		info->regions[i].size = res[i]->end - res[i]->start + 1;
+		info->regions[i].vbase = ioremap(info->regions[i].pbase,
+						 info->regions[i].size);
+		if (info->regions[i].vbase == 0) {
+			pr_err("%s: Cannot remap region %d\n", __func__, i);
+			goto err_remap_region;
+		}
+	}
+
+	hw3d_class = class_create(THIS_MODULE, "msm_hw3d");
+	if (IS_ERR(hw3d_class))
+		goto err_fail_create_class;
+
+	ret = alloc_chrdev_region(&info->devno, 0, 2, "msm_hw3d");
+	if (ret < 0)
+		goto err_fail_alloc_region;
+
+	/* register the master/client devices */
+	master_dev = device_create(hw3d_class, &pdev->dev,
+			DEV_MASTER, "%s", "msm_hw3dm");
+	if (IS_ERR(master_dev))
+		goto err_dev_master;
+	cdev_init(&info->master_cdev, &hw3d_fops);
+	info->master_cdev.owner = THIS_MODULE;
+	ret = cdev_add(&info->master_cdev, DEV_MASTER, 1);
+	if (ret < 0) {
+		pr_err("%s: Cannot register master device node\n", __func__);
+		goto err_reg_master;
+	}
+
+	client_dev = device_create(hw3d_class, &pdev->dev,
+			DEV_CLIENT, "%s", "msm_hw3dc");
+	if (IS_ERR(client_dev))
+		goto err_dev_client;
+	cdev_init(&info->client_cdev, &hw3d_fops);
+	info->client_cdev.owner = THIS_MODULE;
+	ret = cdev_add(&info->client_cdev, DEV_CLIENT, 1);
+	if (ret < 0) {
+		pr_err("%s: Cannot register client device node\n", __func__);
+		goto err_reg_client;
+	}
+
+	info->early_suspend.suspend = hw3d_early_suspend;
+	info->early_suspend.resume = hw3d_late_resume;
+	info->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	register_early_suspend(&info->early_suspend);
+
+	info->irq_en = 1;
+	ret = request_irq(info->irq, hw3d_irq_handler, IRQF_TRIGGER_HIGH,
+			  "hw3d", info);
+	if (ret != 0) {
+		pr_err("%s: Cannot request irq\n", __func__);
+		goto err_req_irq;
+	}
+	hw3d_disable_interrupt(info);
+
+	hw3d_info = info;
+
+	return 0;
+
+err_req_irq:
+	unregister_early_suspend(&info->early_suspend);
+	cdev_del(&info->client_cdev);
+err_reg_client:
+	device_destroy(hw3d_class, DEV_CLIENT);
+err_dev_client:
+	cdev_del(&info->master_cdev);
+err_reg_master:
+	device_destroy(hw3d_class, DEV_MASTER);
+err_dev_master:
+	unregister_chrdev_region(info->devno, 2);
+err_fail_alloc_region:
+	class_unregister(hw3d_class);
+err_fail_create_class:
+err_remap_region:
+	for (i = 0; i < HW3D_NUM_REGIONS; ++i)
+		if (info->regions[i].vbase != 0)
+			iounmap(info->regions[i].vbase);
+	clk_put(info->imem_clk);
+err_get_imem_clk:
+	clk_put(info->grp_clk);
+err_get_grp_clk:
+	wake_lock_destroy(&info->wake_lock);
+	kfree(info);
+	platform_set_drvdata(pdev, NULL);
+err_alloc:
+	hw3d_info = NULL;
+	return ret;
+}
+
+static struct platform_driver msm_hw3d_driver = {
+	.probe		= hw3d_probe,
+	.resume		= hw3d_resume,
+	.driver		= {
+		.name = "msm_hw3d",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init hw3d_init(void)
+{
+	return platform_driver_register(&msm_hw3d_driver);
+}
+
+device_initcall(hw3d_init);
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
new file mode 100644
index 0000000..967db0b
--- /dev/null
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -0,0 +1,199 @@
+/*
+ * Idle processing for ARMv7-based Qualcomm SoCs.
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+#include <asm/vfpmacros.h>
+
+ENTRY(msm_arch_idle)
+	wfi
+	bx      lr
+
+ENTRY(msm_pm_collapse)
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+	cpsid   f
+#endif
+
+	ldr     r0, =saved_state
+	stmia   r0!, {r4-r14}
+	mrc     p15, 0, r1, c1, c0, 0 /* MMU control */
+	mrc     p15, 0, r2, c2, c0, 0 /* TTBR0 */
+	mrc     p15, 0, r3, c3, c0, 0 /* dacr */
+	mrc     p15, 3, r4, c15, c0, 3 /* L2CR1 is the L2 cache control reg 1 */
+	mrc     p15, 0, r5, c10, c2, 0 /* PRRR */
+	mrc     p15, 0, r6, c10, c2, 1 /* NMRR */
+	mrc     p15, 0, r7, c1, c0, 1 /* ACTLR */
+	mrc     p15, 0, r8, c2, c0, 1 /* TTBR1 */
+	mrc     p15, 0, r9, c13, c0, 3 /* TPIDRURO */
+	mrc     p15, 0, ip, c13, c0, 1 /* context ID */
+	stmia   r0!, {r1-r9, ip}
+
+#ifdef CONFIG_VFP
+	VFPFSTMIA r0, r1              /* Save VFP working registers */
+	fmrx    r1, fpexc
+	fmrx    r2, fpscr
+	stmia   r0!, {r1, r2}         /* Save VFP state registers */
+#endif
+	bl      v7_flush_dcache_all
+
+	mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */
+	bic     r0, r1, #(1 << 2)        /* clear dcache bit   */
+	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
+	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
+
+	dsb
+	wfi
+
+	mcr     p15, 0, r1, c1, c0, 0    /* restore d/i cache  */
+	isb
+
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+	cpsie   f
+#endif
+
+	ldr     r0, =saved_state         /* restore registers */
+	ldmfd   r0, {r4-r14}
+	mov     r0, #0                   /* return power collapse failed */
+	bx      lr
+
+ENTRY(msm_pm_collapse_exit)
+#if 0 /* serial debug */
+	mov     r0, #0x80000016
+	mcr     p15, 0, r0, c15, c2, 4
+	mov     r0, #0xA9000000
+	add     r0, r0, #0x00A00000 /* UART1 */
+	/*add     r0, r0, #0x00C00000*/ /* UART3 */
+	mov     r1, #'A'
+	str     r1, [r0, #0x00C]
+#endif
+
+#if 0
+        //; 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
+#endif
+
+#if 0 /* allow jtag reconnect */
+1:
+	b	1b
+#endif
+
+	bl	__cpu_early_init
+
+	ldr     r1, =saved_state_end
+	ldr     r2, =msm_pm_collapse_exit
+	adr     r3, msm_pm_collapse_exit
+	add     r1, r1, r3
+	sub     r1, r1, r2
+#ifdef CONFIG_VFP
+	mrc     p15, 0, r2, c1, c0, 2 /* Read CP Access Control Register */
+	orr     r2, r2, #0x00F00000   /* Enable full access for p10,11 */
+	mcr     p15, 0, r2, c1, c0, 2 /* Write CPACR */
+	isb
+	mov     r2, #0x40000000       /* Enable VFP */
+	fmxr    fpexc, r2
+	isb
+	ldmdb   r1!, {r2, r3}         /* Read saved VFP state registers */
+	sub     r1, r1, #32*8         /* Jump to start of vfp regs area */
+	VFPFLDMIA r1, r4              /* Restore VFP working registers,
+				       * r1 incremented to end of vfp
+				       * regs area */
+	sub     r1, r1, #32*8         /* Jump back to start of vfp regs area */
+	fmxr    fpscr, r3             /* Restore FPSCR */
+	fmxr    fpexc, r2             /* Restore FPEXC last */
+#endif
+	ldmdb   r1!, {r2-r11}
+	mcr     p15, 0, r4, c3, c0, 0 /* dacr */
+	mcr     p15, 0, r3, c2, c0, 0 /* TTBR0 */
+	mcr     p15, 3, r5, c15, c0, 3 /* L2CR1 */
+	mcr     p15, 0, r6, c10, c2, 0 /* PRRR */
+	mcr     p15, 0, r7, c10, c2, 1 /* NMRR */
+	mcr     p15, 0, r8, c1, c0, 1 /* ACTLR */
+	mcr     p15, 0, r9, c2, c0, 1 /* TTBR1 */
+	mcr     p15, 0, r10, c13, c0, 3 /* TPIDRURO */
+	mcr     p15, 0, r11, c13, c0, 1 /* context ID */
+	isb
+	ldmdb   r1!, {r4-r14}
+	/* Add 1:1 map in the PMD to allow smooth switch when turning on MMU */
+	and     r3, r3, #~0x7F  /* mask off lower 7 bits of TTB */
+	adr     r0, msm_pm_mapped_pa /* get address of the mapped instr */
+	lsr     r1, r0, #20     /* get the addr range of addr in MB */
+	lsl     r1, r1, #2      /* multiply by 4 to get to the pg index */
+	add     r3, r3, r1      /* pgd + pgd_index(addr) */
+	ldr     r1, [r3]        /* save current entry to r1 */
+	lsr     r0, #20         /* align current addr to 1MB boundary */
+	lsl     r0, #20
+	/* Create new entry for this 1MB page */
+	orr     r0, r0, #0x4     /* PMD_SECT_BUFFERED */
+	orr     r0, r0, #0x400   /* PMD_SECT_AP_WRITE */
+	orr     r0, r0, #0x2     /* PMD_TYPE_SECT|PMD_DOMAIN(DOMAIN_KERNEL) */
+	str     r0, [r3]         /* put new entry into the MMU table */
+	mcr     p15, 0, r3, c7, c10, 1  /* flush_pmd */
+	dsb
+	isb
+	mcr     p15, 0, r2, c1, c0, 0   /* MMU control */
+	isb
+msm_pm_mapped_pa:
+	/* Switch to virtual */
+	adr     r2, msm_pm_pa_to_va
+	ldr     r0, =msm_pm_pa_to_va
+	mov     pc, r0
+msm_pm_pa_to_va:
+	sub     r0, r0, r2
+	/* Restore r1 in MMU table */
+	add     r3, r3, r0
+	str     r1, [r3]
+	mcr     p15, 0, r3, c7, c10, 1  /* flush_pmd */
+	dsb
+	isb
+	mcr     p15, 0, r3, c8, c7, 0   /* UTLBIALL */
+	mcr     p15, 0, r3, c7, c5, 6   /* BPIALL */
+	dsb
+	isb
+	stmfd   sp!, {lr}
+	bl      v7_flush_kern_cache_all
+	ldmfd   sp!, {lr}
+	mov     r0, #1
+	bx      lr
+	nop
+	nop
+	nop
+	nop
+	nop
+1:	b       1b
+
+
+	.data
+
+saved_state:
+	.space  4 * 11 /* r4-14 */
+	.space  4 * 10  /* cp15 */
+#ifdef CONFIG_VFP
+	.space  8 * 32 /* VFP working registers */
+	.space  4 * 2  /* VFP state registers */
+#endif
+saved_state_end:
+
diff --git a/arch/arm/mach-msm/idle.S b/arch/arm/mach-msm/idle.S
index 6a94f05..d4c3e81 100644
--- a/arch/arm/mach-msm/idle.S
+++ b/arch/arm/mach-msm/idle.S
@@ -1,9 +1,9 @@
-/* arch/arm/mach-msm/include/mach/idle.S
+/* arch/arm/mach-msm/idle.S
  *
- * Idle processing for MSM7K - work around bugs with SWFI.
+ * Idle processing for MSM7X00A - work around bugs with SWFI.
  *
  * Copyright (c) 2007 QUALCOMM Incorporated.
- * Copyright (C) 2007 Google, Inc. 
+ * Copyright (C) 2007 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
@@ -14,23 +14,93 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- */ 
-		
+ */
+
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
-ENTRY(arch_idle)
-#ifdef CONFIG_MSM7X00A_IDLE
-	mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */
+ENTRY(msm_pm_collapse)
+	ldr     r0, =saved_state
+	stmia   r0!, {r4-r14}
+	mrc     p15, 0, r1, c1, c0, 0 /* MMU control */
+	mrc     p15, 0, r2, c2, c0, 0 /* ttb */
+	mrc     p15, 0, r3, c3, c0, 0 /* dacr */
+	mrc     p15, 0, ip, c13, c0, 1 /* context ID */
+	stmia   r0!, {r1-r3, ip}
+#if defined(CONFIG_OPROFILE)
+	mrc     p15, 0, r1, c15, c12, 0 /* pmnc */
+	mrc     p15, 0, r2, c15, c12, 1 /* ccnt */
+	mrc     p15, 0, r3, c15, c12, 2 /* pmn0 */
+	mrc     p15, 0, ip, c15, c12, 3 /* pmn1 */
+	stmia   r0!, {r1-r3, ip}
+#endif
+	/* fall though */
+ENTRY(msm_arch_idle)
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+	cpsid	f
+#endif
+	mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */ 
 	bic     r0, r1, #(1 << 2)        /* clear dcache bit   */
 	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
 	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
 
-	mov     r0, #0                   /* prepare wfi value  */
+	mov     r0, #0                   /* prepare wfi value  */ /* also used as return value from msm_pm_collapse */
 	mcr     p15, 0, r0, c7, c10, 0   /* flush the cache    */
 	mcr     p15, 0, r0, c7, c10, 4   /* memory barrier     */
 	mcr     p15, 0, r0, c7, c0, 4    /* wait for interrupt */
 
 	mcr     p15, 0, r1, c1, c0, 0    /* restore d/i cache  */
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+	cpsie	f
 #endif
 	mov     pc, lr
+
+ENTRY(msm_pm_collapse_exit)
+#if 0 /* serial debug */
+	mov     r0, #0x80000016
+	mcr     p15, 0, r0, c15, c2, 4
+	mov     r0, #0xA9000000
+	add     r0, r0, #0x00A00000 /* UART1 */
+	/*add     r0, r0, #0x00C00000*/ /* UART3 */
+	mov     r1, #'A'
+	str     r1, [r0, #0x00C]
+#endif
+	ldr     r1, =saved_state_end
+	ldr     r2, =msm_pm_collapse_exit
+	adr     r3, msm_pm_collapse_exit
+	add     r1, r1, r3
+	sub     r1, r1, r2
+#if defined(CONFIG_OPROFILE)
+	ldmdb   r1!, {r2-r5}
+	mcr     p15, 0, r3, c15, c12, 1 /* ccnt */
+	mcr     p15, 0, r4, c15, c12, 2 /* pmn0 */
+	mcr     p15, 0, r5, c15, c12, 3 /* pmn1 */
+	mcr     p15, 0, r2, c15, c12, 0 /* pmnc */
+#endif
+	ldmdb   r1!, {r2-r5}
+	mcr     p15, 0, r4, c3, c0, 0 /* dacr */
+	mcr     p15, 0, r3, c2, c0, 0 /* ttb */
+	mcr	p15, 0, r5, c13, c0, 1	/* context ID */
+	ldmdb   r1!, {r4-r14}
+	mov     r0, #1
+
+	mcr     p15, 0, r2, c1, c0, 0 /* MMU control */
+	mov     pc, lr
+	nop
+	nop
+	nop
+	nop
+	nop
+1:	b       1b
+
+
+	.data
+
+saved_state:
+	.space  4 * 11 /* r4-14 */
+	.space  4 * 4  /* cp15 - MMU control, ttb, dacr, context ID */
+#if defined(CONFIG_OPROFILE)
+	.space  4 * 4  /* more cp15 - pmnc, ccnt, pmn0, pmn1 */
+#endif
+saved_state_end:
+
diff --git a/arch/arm/mach-msm/include/mach/bcm_bt_lpm.h b/arch/arm/mach-msm/include/mach/bcm_bt_lpm.h
new file mode 100644
index 0000000..c224297
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/bcm_bt_lpm.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_BCM_BT_LPM_H
+#define __ASM_ARCH_BCM_BT_LPM_H
+
+#include <linux/serial_core.h>
+
+/* Uart driver must call this every time it beings TX, to ensure
+ * this driver keeps WAKE asserted during TX. Called with uart
+ * spinlock held. */
+extern void bcm_bt_lpm_exit_lpm_locked(struct uart_port *uport);
+
+struct bcm_bt_lpm_platform_data {
+	unsigned int gpio_wake;   /* CPU -> BCM wakeup gpio */
+	unsigned int gpio_host_wake;  /* BCM -> CPU wakeup gpio */
+
+	/* Callback to request the uart driver to clock off.
+         * Called with uart spinlock held. */
+	void (*request_clock_off_locked)(struct uart_port *uport);
+	/* Callback to request the uart driver to clock on.
+         * Called with uart spinlock held. */
+	void (*request_clock_on_locked)(struct uart_port *uport);
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index e302fbd..6f84d5a 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -26,10 +26,58 @@
 	uint32_t acpu_switch_time_us;
 	uint32_t max_speed_delta_khz;
 	uint32_t vdd_switch_time_us;
+	unsigned long mpll_khz;
 	unsigned long power_collapse_khz;
 	unsigned long wait_for_irq_khz;
 };
 
+struct msm_camera_io_ext {
+	uint32_t mdcphy;
+	uint32_t mdcsz;
+	uint32_t appphy;
+	uint32_t appsz;
+	unsigned long camifpadphy;
+	unsigned long camifpadsz;
+};
+
+struct msm_camera_device_platform_data {
+	void (*camera_gpio_on) (void);
+	void (*camera_gpio_off)(void);
+	struct msm_camera_io_ext ioext;
+};
+
+struct msm_camera_legacy_device_platform_data {
+	int sensor_reset;
+	int sensor_pwd;
+	int vcm_pwd;
+	void (*config_gpio_on) (void);
+	void (*config_gpio_off)(void);
+};
+
+struct msm_camera_sensor_info {
+	const char *sensor_name;
+	int sensor_reset;
+	int sensor_pwd;
+	int vcm_pwd;
+	int mclk;
+	int num_flash_levels;
+	int (*camera_flash)(int level);
+	int need_suspend;
+	struct msm_camera_device_platform_data *pdata;
+	struct resource *resource;
+	uint8_t num_resources;
+};
+
+struct snd_endpoint {
+	int id;
+	const char *name;
+};
+
+struct msm_snd_endpoints {
+	struct snd_endpoint *endpoints;
+	unsigned num;
+};
+
 struct clk;
 
 /* common init routines for use by arch/arm/mach-msm/board-*.c */
@@ -37,8 +85,13 @@
 void __init msm_add_devices(void);
 void __init msm_map_common_io(void);
 void __init msm_init_irq(void);
-void __init msm_init_gpio(void);
 void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks);
 void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *);
 
+#ifdef CONFIG_USB_MSM_72K
+void msm_hsusb_set_vbus_state(int online);
+#else
+static inline void msm_hsusb_set_vbus_state(int online) {}
+#endif
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/board_htc.h b/arch/arm/mach-msm/include/mach/board_htc.h
new file mode 100644
index 0000000..994accd
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/board_htc.h
@@ -0,0 +1,68 @@
+/* arch/arm/mach-msm/include/mach/BOARD_HTC.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 __ASM_ARCH_MSM_BOARD_HTC_H
+#define __ASM_ARCH_MSM_BOARD_HTC_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/setup.h>
+
+struct msm_pmem_setting{
+	resource_size_t pmem_start;
+	resource_size_t pmem_size;
+	resource_size_t pmem_adsp_start;
+	resource_size_t pmem_adsp_size;
+	resource_size_t pmem_gpu0_start;
+	resource_size_t pmem_gpu0_size;
+	resource_size_t pmem_gpu1_start;
+	resource_size_t pmem_gpu1_size;
+	resource_size_t pmem_camera_start;
+	resource_size_t pmem_camera_size;
+	resource_size_t ram_console_start;
+	resource_size_t ram_console_size;
+};
+
+enum {
+	MSM_SERIAL_UART1	= 0,
+	MSM_SERIAL_UART2,
+	MSM_SERIAL_UART3,
+#ifdef CONFIG_SERIAL_MSM_HS
+	MSM_SERIAL_UART1DM,
+	MSM_SERIAL_UART2DM,
+#endif
+	MSM_SERIAL_NUM,
+};
+
+
+/* common init routines for use by arch/arm/mach-msm/board-*.c */
+
+void __init msm_add_usb_devices(void (*phy_reset) (void));
+void __init msm_add_mem_devices(struct msm_pmem_setting *setting);
+void __init msm_init_pmic_vibrator(void);
+
+struct mmc_platform_data;
+int __init msm_add_sdcc_devices(unsigned int controller, struct mmc_platform_data *plat);
+int __init msm_add_serial_devices(unsigned uart);
+
+int __init board_mfg_mode(void);
+int __init parse_tag_smi(const struct tag *tags);
+int __init parse_tag_hwid(const struct tag * tags);
+int __init parse_tag_skuid(const struct tag * tags);
+int parse_tag_engineerid(const struct tag * tags);
+
+void notify_usb_connected(int online);
+
+char *board_serialno(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
new file mode 100644
index 0000000..1da814f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -0,0 +1,326 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __ASM__ARCH_CAMERA_H
+#define __ASM__ARCH_CAMERA_H
+
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/wakelock.h>
+#include "linux/types.h"
+
+#include <mach/board.h>
+#include <media/msm_camera.h>
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define CDBG(fmt, args...) printk(KERN_INFO "msm_camera: " fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#endif
+
+#define MSM_CAMERA_MSG 0
+#define MSM_CAMERA_EVT 1
+#define NUM_WB_EXP_NEUTRAL_REGION_LINES 4
+#define NUM_WB_EXP_STAT_OUTPUT_BUFFERS  3
+#define NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS 16
+#define NUM_STAT_OUTPUT_BUFFERS      3
+#define NUM_AF_STAT_OUTPUT_BUFFERS      3
+
+enum msm_queue {
+	MSM_CAM_Q_CTRL,     /* control command or control command status */
+	MSM_CAM_Q_VFE_EVT,  /* adsp event */
+	MSM_CAM_Q_VFE_MSG,  /* adsp message */
+	MSM_CAM_Q_V4L2_REQ, /* v4l2 request */
+};
+
+enum vfe_resp_msg {
+	VFE_EVENT,
+	VFE_MSG_GENERAL,
+	VFE_MSG_SNAPSHOT,
+	VFE_MSG_OUTPUT1,
+	VFE_MSG_OUTPUT2,
+	VFE_MSG_STATS_AF,
+	VFE_MSG_STATS_WE, /* AEC + AWB */
+	VFE_MSG_OUTPUT_P,   /* preview (continuous mode ) */
+	VFE_MSG_OUTPUT_T,   /* thumbnail (snapshot mode )*/
+	VFE_MSG_OUTPUT_S,   /* main image (snapshot mode )*/
+	VFE_MSG_OUTPUT_V,   /* video   (continuous mode ) */
+	VFE_MSG_STATS_AEC,
+	VFE_MSG_STATS_AWB,
+	VFE_MSG_STATS_RS,
+	VFE_MSG_STATS_CS,
+	VFE_MSG_STATS_IHIST,
+	VFE_MSG_STATS_SKIN,
+};
+
+struct msm_vfe_phy_info {
+	uint32_t sbuf_phy;
+	uint32_t y_phy;
+	uint32_t cbcr_phy;
+	uint8_t  output_id; /* OUTPUT_MODE_P/T/S/V */
+};
+
+struct msm_vfe_resp {
+	enum vfe_resp_msg type;
+	struct msm_vfe_evt_msg evt_msg;
+	struct msm_vfe_phy_info phy;
+	void    *extdata;
+	int32_t extlen;
+};
+
+struct msm_vfe_callback {
+	void (*vfe_resp)(struct msm_vfe_resp *,
+		enum msm_queue, void *syncdata,
+		gfp_t gfp);
+	void* (*vfe_alloc)(int, void *syncdata, gfp_t gfp);
+	void (*vfe_free)(void *ptr);
+	int (*flash_ctrl)(void *syncdata, int level);
+};
+
+struct msm_camvfe_fn {
+	int (*vfe_init)(struct msm_vfe_callback *, struct platform_device *);
+	int (*vfe_enable)(struct camera_enable_cmd *);
+	int (*vfe_config)(struct msm_vfe_cfg_cmd *, void *);
+	int (*vfe_disable)(struct camera_enable_cmd *,
+		struct platform_device *dev);
+	void (*vfe_release)(struct platform_device *);
+};
+
+struct msm_sensor_ctrl {
+	int (*s_init)(const struct msm_camera_sensor_info *);
+	int (*s_release)(void);
+	int (*s_config)(void __user *);
+};
+
+/* this structure is used in kernel */
+struct msm_queue_cmd {
+	struct list_head list_config;
+	struct list_head list_control;
+	struct list_head list_frame;
+	struct list_head list_pict;
+	enum msm_queue type;
+	void *command;
+	int on_heap;
+};
+
+struct msm_device_queue {
+	struct list_head list;
+	spinlock_t lock;
+	wait_queue_head_t wait;
+	int max;
+	int len;
+	const char *name;
+};
+
+struct msm_sync {
+	/* These two queues are accessed from a process context only.  They contain
+	 * pmem descriptors for the preview frames and the stats coming from the
+	 * camera sensor.
+	 */
+	struct hlist_head pmem_frames;
+	struct hlist_head pmem_stats;
+
+	/* The message queue is used by the control thread to send commands
+	 * to the config thread, and also by the DSP to send messages to the
+	 * config thread.  Thus it is the only queue that is accessed from
+	 * both interrupt and process context.
+	 */
+	struct msm_device_queue event_q;
+
+	/* This queue contains preview frames. It is accessed by the DSP (in
+	 * in interrupt context, and by the frame thread.
+	 */
+	struct msm_device_queue frame_q;
+	int unblock_poll_frame;
+
+	/* This queue contains snapshot frames.  It is accessed by the DSP (in
+	 * interrupt context, and by the control thread.
+	 */
+	struct msm_device_queue pict_q;
+
+	struct msm_camera_sensor_info *sdata;
+	struct msm_camvfe_fn vfefn;
+	struct msm_sensor_ctrl sctrl;
+	struct wake_lock wake_lock;
+	struct platform_device *pdev;
+	uint8_t opencnt;
+	void *cropinfo;
+	int  croplen;
+
+	uint32_t pp_mask;
+	struct msm_queue_cmd *pp_prev;
+	struct msm_queue_cmd *pp_snap;
+
+	/* When this flag is set, we send preview-frame notifications to config
+	 * as well as to the frame queue.  By default, the flag is cleared.
+	 */
+	uint32_t report_preview_to_config;
+
+	const char *apps_id;
+
+	struct mutex lock;
+	struct list_head list;
+	int get_pic_abort;
+};
+
+#define MSM_APPS_ID_V4L2 "msm_v4l2"
+#define MSM_APPS_ID_PROP "msm_qct"
+
+struct msm_device {
+	struct msm_sync *sync; /* most-frequently accessed */
+	struct device *device;
+	struct cdev cdev;
+	/* opened is meaningful only for the config and frame nodes,
+	 * which may be opened only once.
+	 */
+	atomic_t opened;
+};
+
+struct msm_control_device {
+	struct msm_device *pmsm;
+
+	/* Used for MSM_CAM_IOCTL_CTRL_CMD_DONE responses */
+	uint8_t ctrl_data[50];
+	struct msm_ctrl_cmd ctrl;
+	struct msm_queue_cmd qcmd;
+
+	/* This queue used by the config thread to send responses back to the
+	 * control thread.  It is accessed only from a process context.
+	 */
+	struct msm_device_queue ctrl_q;
+};
+
+struct register_address_value_pair {
+	uint16_t register_address;
+	uint16_t register_value;
+};
+
+struct msm_pmem_region {
+	struct hlist_node list;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	struct file *file;
+	struct msm_pmem_info info;
+};
+
+struct axidata {
+	uint32_t bufnum1;
+	uint32_t bufnum2;
+	struct msm_pmem_region *region;
+	uint32_t bufnum3;
+};
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+/* Below functions are added for V4L2 kernel APIs */
+struct msm_v4l2_driver {
+	struct msm_sync *sync;
+	int (*open)(struct msm_sync *, const char *apps_id);
+	int (*release)(struct msm_sync *);
+	int (*ctrl)(struct msm_sync *, struct msm_ctrl_cmd *);
+	int (*reg_pmem)(struct msm_sync *, struct msm_pmem_info *);
+	int (*get_frame) (struct msm_sync *, struct msm_frame *);
+	int (*put_frame) (struct msm_sync *, struct msm_frame *);
+	int (*get_pict) (struct msm_sync *, struct msm_ctrl_cmd *);
+	unsigned int (*drv_poll) (struct msm_sync *, struct file *,
+				struct poll_table_struct *);
+};
+
+int msm_v4l2_register(struct msm_v4l2_driver *);
+int msm_v4l2_unregister(struct msm_v4l2_driver *);
+#endif
+
+void msm_camvfe_init(void);
+int msm_camvfe_check(void *);
+void msm_camvfe_fn_init(struct msm_camvfe_fn *, void *);
+int msm_camera_drv_start(struct platform_device *dev,
+		int (*sensor_probe)(const struct msm_camera_sensor_info *,
+					struct msm_sensor_ctrl *));
+
+enum msm_camio_clk_type {
+	CAMIO_VFE_MDC_CLK,
+	CAMIO_MDC_CLK,
+	CAMIO_VFE_CLK,
+	CAMIO_VFE_AXI_CLK,
+
+	CAMIO_VFE_CAMIF_CLK,
+	CAMIO_VFE_PBDG_CLK,
+	CAMIO_CAM_MCLK_CLK,
+	CAMIO_CAMIF_PAD_PBDG_CLK,
+	CAMIO_CSI_CLK,
+	CAMIO_CSI_VFE_CLK,
+	CAMIO_CSI_PCLK,
+	CAMIO_MAX_CLK
+};
+
+enum msm_camio_clk_src_type {
+	MSM_CAMIO_CLK_SRC_INTERNAL,
+	MSM_CAMIO_CLK_SRC_EXTERNAL,
+	MSM_CAMIO_CLK_SRC_MAX
+};
+
+enum msm_s_test_mode {
+	S_TEST_OFF,
+	S_TEST_1,
+	S_TEST_2,
+	S_TEST_3
+};
+
+enum msm_s_resolution {
+	S_QTR_SIZE,
+	S_FULL_SIZE,
+	S_INVALID_SIZE
+};
+
+enum msm_s_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	S_REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	S_UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	S_UPDATE_ALL,
+	/* Not valid update */
+	S_UPDATE_INVALID
+};
+
+enum msm_s_setting {
+	S_RES_PREVIEW,
+	S_RES_CAPTURE
+};
+
+int msm_camio_enable(struct platform_device *dev);
+
+int  msm_camio_clk_enable(enum msm_camio_clk_type clk);
+int  msm_camio_clk_disable(enum msm_camio_clk_type clk);
+int  msm_camio_clk_config(uint32_t freq);
+void msm_camio_clk_rate_set(int rate);
+void msm_camio_clk_axi_rate_set(int rate);
+void msm_disable_io_gpio_clk(struct platform_device *);
+
+void msm_camio_camif_pad_reg_reset(void);
+void msm_camio_camif_pad_reg_reset_2(void);
+
+void msm_camio_vfe_blk_reset(void);
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type);
+void msm_camio_disable(struct platform_device *);
+int msm_camio_probe_on(struct platform_device *);
+int msm_camio_probe_off(struct platform_device *);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 00f9bbf..9a62569 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -1,6 +1,8 @@
 /* linux/include/asm-arm/arch-msm/dma.h
  *
  * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008 QUALCOMM Incorporated.
+ * Copyright (c) 2008 QUALCOMM USA, INC.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -34,6 +36,7 @@
 
 void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd);
 void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful);
+void msm_dmov_flush(unsigned int id);
 int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr);
 
 
@@ -69,6 +72,7 @@
 #define DMOV_FLUSH3(ch)       DMOV_SD_AARM(0x140, ch)
 #define DMOV_FLUSH4(ch)       DMOV_SD_AARM(0x180, ch)
 #define DMOV_FLUSH5(ch)       DMOV_SD_AARM(0x1C0, ch)
+#define DMOV_FLUSH_TYPE       (1 << 31)
 
 #define DMOV_STATUS(ch)       DMOV_SD_AARM(0x200, ch)
 #define DMOV_STATUS_RSLT_COUNT(n)    (((n) >> 29))
@@ -100,6 +104,19 @@
 
 #define DMOV_USB_CHAN         11
 
+#define DMOV_HSUART1_TX_CHAN   4
+#define DMOV_HSUART1_TX_CRCI   8
+
+#define DMOV_HSUART1_RX_CHAN   9
+#define DMOV_HSUART1_RX_CRCI   9
+
+#define DMOV_HSUART2_TX_CHAN   4
+#define DMOV_HSUART2_TX_CRCI   14
+
+#define DMOV_HSUART2_RX_CHAN   11
+#define DMOV_HSUART2_RX_CRCI   15
+
+
 /* no client rate control ifc (eg, ram) */
 #define DMOV_NONE_CRCI        0
 
diff --git a/arch/arm/mach-msm/include/mach/fiq.h b/arch/arm/mach-msm/include/mach/fiq.h
new file mode 100644
index 0000000..64a0ea9
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/fiq.h
@@ -0,0 +1,34 @@
+/* linux/include/asm-arm/arch-msm/irqs.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_FIQ_H
+#define __ASM_ARCH_MSM_FIQ_H
+
+/* cause an interrupt to be an FIQ instead of a regular IRQ */
+void msm_fiq_select(int number);
+void msm_fiq_unselect(int number);
+
+/* enable/disable an interrupt that is an FIQ (not safe from FIQ context) */
+void msm_fiq_enable(int number);
+void msm_fiq_disable(int number);
+
+/* install an FIQ handler */
+int msm_fiq_set_handler(void (*func)(void *data, void *regs, void *svc_sp),
+			void *data);
+
+/* cause an edge triggered interrupt to fire (safe from FIQ context */
+void msm_trigger_irq(int number);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index 262b441..154e536 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -16,6 +16,32 @@
 #ifndef __ASM_ARCH_MSM_GPIO_H
 #define __ASM_ARCH_MSM_GPIO_H
 
+#include <linux/interrupt.h>
+#include <asm-generic/gpio.h>
+#include <mach/irqs.h>
+
+#define FIRST_BOARD_GPIO	NR_GPIO_IRQS
+
+static inline int gpio_get_value(unsigned gpio)
+{
+	return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+	__gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+	return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+	return __gpio_to_irq(gpio);
+}
+
 /**
  * struct msm_gpio - GPIO pin description
  * @gpio_cfg - configuration bitmap, as per gpio_tlmm_config()
@@ -92,33 +118,33 @@
 
 /* GPIO TLMM: Direction */
 enum {
-	GPIO_INPUT,
-	GPIO_OUTPUT,
+	GPIO_CFG_INPUT,
+	GPIO_CFG_OUTPUT,
 };
 
 /* GPIO TLMM: Pullup/Pulldown */
 enum {
-	GPIO_NO_PULL,
-	GPIO_PULL_DOWN,
-	GPIO_KEEPER,
-	GPIO_PULL_UP,
+	GPIO_CFG_NO_PULL,
+	GPIO_CFG_PULL_DOWN,
+	GPIO_CFG_KEEPER,
+	GPIO_CFG_PULL_UP,
 };
 
 /* GPIO TLMM: Drive Strength */
 enum {
-	GPIO_2MA,
-	GPIO_4MA,
-	GPIO_6MA,
-	GPIO_8MA,
-	GPIO_10MA,
-	GPIO_12MA,
-	GPIO_14MA,
-	GPIO_16MA,
+	GPIO_CFG_2MA,
+	GPIO_CFG_4MA,
+	GPIO_CFG_6MA,
+	GPIO_CFG_8MA,
+	GPIO_CFG_10MA,
+	GPIO_CFG_12MA,
+	GPIO_CFG_14MA,
+	GPIO_CFG_16MA,
 };
 
 enum {
-	GPIO_ENABLE,
-	GPIO_DISABLE,
+	GPIO_CFG_ENABLE,
+	GPIO_CFG_DISABLE,
 };
 
 #define GPIO_CFG(gpio, func, dir, pull, drvstr) \
diff --git a/arch/arm/mach-msm/include/mach/htc_35mm_jack.h b/arch/arm/mach-msm/include/mach/htc_35mm_jack.h
new file mode 100644
index 0000000..5ce1e2a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/htc_35mm_jack.h
@@ -0,0 +1,31 @@
+/* arch/arm/mach-msm/include/mach/htc_35mm_jack.h
+ *
+ * Copyright (C) 2009 HTC, Inc.
+ * Author: Arec Kao <Arec_Kao@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 HTC_35MM_REMOTE_H
+#define HTC_35MM_REMOTE_H
+
+/* Driver interfaces */
+int htc_35mm_jack_plug_event(int insert, int *hpin_stable);
+int htc_35mm_key_event(int key, int *hpin_stable);
+
+/* Platform Specific Callbacks */
+struct h35mm_platform_data {
+	int (*plug_event_enable)(void);
+	int (*headset_has_mic)(void);
+	int (*key_event_enable)(void);
+	int (*key_event_disable)(void);
+};
+#endif
diff --git a/arch/arm/mach-msm/include/mach/htc_acoustic_qsd.h b/arch/arm/mach-msm/include/mach/htc_acoustic_qsd.h
new file mode 100644
index 0000000..2139bf9
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/htc_acoustic_qsd.h
@@ -0,0 +1,29 @@
+/* include/asm/mach-msm/htc_acoustic_qsd.h
+ *
+ * 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 _ARCH_ARM_MACH_MSM_HTC_ACOUSTIC_QSD_H_
+#define _ARCH_ARM_MACH_MSM_HTC_ACOUSTIC_QSD_H_
+
+struct qsd_acoustic_ops {
+	void (*enable_mic_bias)(int en);
+};
+
+void acoustic_register_ops(struct qsd_acoustic_ops *ops);
+
+int turn_mic_bias_on(int on);
+int force_headset_speaker_on(int enable);
+int enable_aux_loopback(uint32_t enable);
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/htc_headset.h b/arch/arm/mach-msm/include/mach/htc_headset.h
new file mode 100644
index 0000000..5bea7a2
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/htc_headset.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2008 HTC, Inc.
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_HTC_HEADSET_H
+#define __ASM_ARCH_HTC_HEADSET_H
+
+struct h2w_platform_data {
+	char *power_name;
+	int cable_in1;
+	int cable_in2;
+	int h2w_clk;
+	int h2w_data;
+	int debug_uart;
+	int headset_mic_35mm;
+	void (*config_cpld)(int);
+	void (*init_cpld)(void);
+	void (*set_dat)(int);
+	void (*set_clk)(int);
+	void (*set_dat_dir)(int);
+	void (*set_clk_dir)(int);
+	int (*get_dat)(void);
+	int (*get_clk)(void);
+};
+
+#define BIT_HEADSET		(1 << 0)
+#define BIT_HEADSET_NO_MIC	(1 << 1)
+#define BIT_TTY			(1 << 2)
+#define BIT_FM_HEADSET 		(1 << 3)
+#define BIT_FM_SPEAKER		(1 << 4)
+#define BIT_TTY_VCO             (1 << 5)
+#define BIT_TTY_HCO             (1 << 6)
+#define BIT_35MM_HEADSET        (1 << 7)
+
+enum {
+	H2W_NO_DEVICE	= 0,
+	H2W_HTC_HEADSET	= 1,
+	NORMAL_HEARPHONE= 2,
+	H2W_DEVICE	= 3,
+	H2W_USB_CRADLE	= 4,
+	H2W_UART_DEBUG	= 5,
+};
+
+enum {
+	H2W_GPIO	= 0,
+	H2W_UART1	= 1,
+	H2W_UART3	= 2,
+	H2W_BT		= 3
+};
+
+#define RESEND_DELAY		(3)	/* ms */
+#define MAX_ACK_RESEND_TIMES	(6)	/* follow spec */
+#define MAX_HOST_RESEND_TIMES	(3)	/* follow spec */
+#define MAX_HYGEIA_RESEND_TIMES	(5)
+
+#define H2W_ASCR_DEVICE_INI	(0x01)
+#define H2W_ASCR_ACT_EN		(0x02)
+#define H2W_ASCR_PHONE_IN	(0x04)
+#define H2W_ASCR_RESET		(0x08)
+#define H2W_ASCR_AUDIO_IN	(0x10)
+
+#define H2W_LED_OFF		(0x0)
+#define H2W_LED_BKL		(0x1)
+#define H2W_LED_MTL		(0x2)
+
+typedef enum {
+	/* === system group 0x0000~0x00FF === */
+	/* (R) Accessory type register */
+	H2W_SYSTEM		= 0x0000,
+	/* (R) Maximum group address */
+	H2W_MAX_GP_ADD		= 0x0001,
+	/* (R/W) Accessory system control register0 */
+	H2W_ASCR0		= 0x0002,
+
+	/* === key group 0x0100~0x01FF === */
+	/* (R) Key group maximum sub address */
+	H2W_KEY_MAXADD		= 0x0100,
+	/* (R) ASCII key press down flag */
+	H2W_ASCII_DOWN		= 0x0101,
+	/* (R) ASCII key release up flag */
+	H2W_ASCII_UP		= 0x0102,
+	/* (R) Function key status flag */
+	H2W_FNKEY_UPDOWN	= 0x0103,
+	/* (R/W) Key device status */
+	H2W_KD_STATUS		= 0x0104,
+
+	/* === led group 0x0200~0x02FF === */
+	/* (R) LED group maximum sub address */
+	H2W_LED_MAXADD		= 0x0200,
+	/* (R/W) LED control register0 */
+	H2W_LEDCT0		= 0x0201,
+
+	/* === crdl group 0x0300~0x03FF === */
+	/* (R) Cardle group maximum sub address */
+	H2W_CRDL_MAXADD		= 0x0300,
+	/* (R/W) Cardle group function control register0 */
+	H2W_CRDLCT0		= 0x0301,
+
+	/* === car kit group 0x0400~0x04FF === */
+	H2W_CARKIT_MAXADD	= 0x0400,
+
+	/* === usb host group 0x0500~0x05FF === */
+	H2W_USBHOST_MAXADD	= 0x0500,
+
+	/* === medical group 0x0600~0x06FF === */
+	H2W_MED_MAXADD		= 0x0600,
+	H2W_MED_CONTROL		= 0x0601,
+	H2W_MED_IN_DATA		= 0x0602,
+} H2W_ADDR;
+
+
+typedef struct H2W_INFO {
+	/* system group */
+	unsigned char CLK_SP;
+	int SLEEP_PR;
+	unsigned char HW_REV;
+	int AUDIO_DEVICE;
+	unsigned char ACC_CLASS;
+	unsigned char MAX_GP_ADD;
+
+	/* key group */
+	int KEY_MAXADD;
+	int ASCII_DOWN;
+	int ASCII_UP;
+	int FNKEY_UPDOWN;
+	int KD_STATUS;
+
+	/* led group */
+	int LED_MAXADD;
+	int LEDCT0;
+
+	/* medical group */
+	int MED_MAXADD;
+	unsigned char AP_ID;
+	unsigned char AP_EN;
+	unsigned char DATA_EN;
+} H2W_INFO;
+
+typedef enum {
+	H2W_500KHz	= 1,
+	H2W_250KHz	= 2,
+	H2W_166KHz	= 3,
+	H2W_125KHz	= 4,
+	H2W_100KHz	= 5,
+	H2W_83KHz	= 6,
+	H2W_71KHz	= 7,
+	H2W_62KHz	= 8,
+	H2W_55KHz	= 9,
+	H2W_50KHz	= 10,
+} H2W_SPEED;
+
+typedef enum {
+	H2W_KEY_INVALID	 = -1,
+	H2W_KEY_PLAY	 = 0,
+	H2W_KEY_FORWARD  = 1,
+	H2W_KEY_BACKWARD = 2,
+	H2W_KEY_VOLUP	 = 3,
+	H2W_KEY_VOLDOWN	 = 4,
+	H2W_KEY_PICKUP	 = 5,
+	H2W_KEY_HANGUP	 = 6,
+	H2W_KEY_MUTE	 = 7,
+	H2W_KEY_HOLD	 = 8,
+	H2W_NUM_KEYFUNC	 = 9,
+} KEYFUNC;
+
+extern int turn_mic_bias_on(int on);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/htc_pwrsink.h b/arch/arm/mach-msm/include/mach/htc_pwrsink.h
new file mode 100644
index 0000000..c7a91f1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/htc_pwrsink.h
@@ -0,0 +1,87 @@
+/* include/asm/mach-msm/htc_pwrsink.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2008 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 _ARCH_ARM_MACH_MSM_HTC_PWRSINK_H_
+#define _ARCH_ARM_MACH_MSM_HTC_PWRSINK_H_
+
+#include <linux/platform_device.h>
+#include <linux/earlysuspend.h>
+
+typedef enum {
+	PWRSINK_AUDIO_PCM = 0,
+	PWRSINK_AUDIO_MP3,
+	PWRSINK_AUDIO_AAC,
+
+	PWRSINK_AUDIO_LAST = PWRSINK_AUDIO_AAC,
+	PWRSINK_AUDIO_INVALID
+} pwrsink_audio_id_type;
+
+struct pwr_sink_audio {
+	unsigned volume;
+	unsigned percent;
+};
+
+typedef enum {
+	PWRSINK_SYSTEM_LOAD = 0,
+	PWRSINK_AUDIO,
+	PWRSINK_BACKLIGHT,
+	PWRSINK_LED_BUTTON,
+	PWRSINK_LED_KEYBOARD,
+	PWRSINK_GP_CLK,
+	PWRSINK_BLUETOOTH,
+	PWRSINK_CAMERA,
+	PWRSINK_SDCARD,
+	PWRSINK_VIDEO,
+	PWRSINK_WIFI,
+
+	PWRSINK_LAST = PWRSINK_WIFI,
+	PWRSINK_INVALID
+} pwrsink_id_type;
+
+struct pwr_sink {
+	pwrsink_id_type	id;
+	unsigned	ua_max;
+	unsigned	percent_util;
+};
+
+struct pwr_sink_platform_data {
+	unsigned	num_sinks;
+	struct pwr_sink	*sinks;
+	int (*suspend_late)(struct platform_device *, pm_message_t state);
+	int (*resume_early)(struct platform_device *);
+	void (*suspend_early)(struct early_suspend *);
+	void (*resume_late)(struct early_suspend *);
+};
+
+#ifndef CONFIG_HTC_PWRSINK
+static inline int htc_pwrsink_set(pwrsink_id_type id, unsigned percent)
+{
+	return 0;
+}
+static inline int htc_pwrsink_audio_set(pwrsink_audio_id_type id,
+	unsigned percent_utilized) { return 0; }
+static inline int htc_pwrsink_audio_volume_set(
+	pwrsink_audio_id_type id, unsigned volume) { return 0; }
+static inline int htc_pwrsink_audio_path_set(unsigned path) { return 0; }
+#else
+extern int htc_pwrsink_set(pwrsink_id_type id, unsigned percent);
+extern int htc_pwrsink_audio_set(pwrsink_audio_id_type id,
+	unsigned percent_utilized);
+extern int htc_pwrsink_audio_volume_set(pwrsink_audio_id_type id,
+	unsigned volume);
+extern int htc_pwrsink_audio_path_set(unsigned path);
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-7x00.h b/arch/arm/mach-msm/include/mach/irqs-7x00.h
index f1fe706..65e18d3 100644
--- a/arch/arm/mach-msm/include/mach/irqs-7x00.h
+++ b/arch/arm/mach-msm/include/mach/irqs-7x00.h
@@ -71,5 +71,6 @@
 #define NR_MSM_IRQS 64
 #define NR_GPIO_IRQS 122
 #define NR_BOARD_IRQS 64
+#define NR_SIRC_IRQS 0
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-7x30.h b/arch/arm/mach-msm/include/mach/irqs-7x30.h
index 67c5396..c564576 100644
--- a/arch/arm/mach-msm/include/mach/irqs-7x30.h
+++ b/arch/arm/mach-msm/include/mach/irqs-7x30.h
@@ -155,16 +155,11 @@
 #define INT_MDDI_CLIENT		INT_MDC
 #define INT_NAND_WR_ER_DONE	INT_EBI2_WR_ER_DONE
 #define INT_NAND_OP_DONE	INT_EBI2_OP_DONE
+#define INT_GRAPHICS		INT_GRP_3D
 
 #define NR_MSM_IRQS		128
+#define NR_SIRC_IRQS		0
 #define NR_GPIO_IRQS		182
-#define PMIC8058_IRQ_BASE	(NR_MSM_IRQS + NR_GPIO_IRQS)
-#define NR_PMIC8058_GPIO_IRQS	40
-#define NR_PMIC8058_MPP_IRQS	12
-#define NR_PMIC8058_MISC_IRQS	8
-#define NR_PMIC8058_IRQS	(NR_PMIC8058_GPIO_IRQS +\
-				NR_PMIC8058_MPP_IRQS +\
-				NR_PMIC8058_MISC_IRQS)
-#define NR_BOARD_IRQS		NR_PMIC8058_IRQS
+#define NR_BOARD_IRQS		64
 
 #endif /* __ASM_ARCH_MSM_IRQS_7X30_H */
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 164d355..75d3b98 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -19,6 +19,10 @@
 
 #define MSM_IRQ_BIT(irq)     (1 << ((irq) & 31))
 
+#define FIRST_SIRC_IRQ (NR_MSM_IRQS)
+#define FIRST_GPIO_IRQ (NR_MSM_IRQS + NR_SIRC_IRQS)
+#define FIRST_BOARD_IRQ (NR_MSM_IRQS + NR_SIRC_IRQS + NR_GPIO_IRQS)
+
 #if defined(CONFIG_ARCH_MSM7X30)
 #include "irqs-7x30.h"
 #elif defined(CONFIG_ARCH_QSD8X50)
@@ -30,8 +34,8 @@
 #error "Unknown architecture specification"
 #endif
 
-#define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS)
-#define MSM_GPIO_TO_INT(n) (NR_MSM_IRQS + (n))
+#define NR_IRQS (NR_MSM_IRQS + NR_SIRC_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS)
+#define MSM_GPIO_TO_INT(n) (FIRST_GPIO_IRQ + (n))
 #define MSM_INT_TO_REG(base, irq) (base + irq / 32)
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index 50c7847..4bdc4d3 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -21,10 +21,25 @@
 #define PHYS_OFFSET		UL(0x00000000)
 #elif defined(CONFIG_ARCH_QSD8X50)
 #define PHYS_OFFSET		UL(0x20000000)
+#define RESET_VECTOR		UL(0x00000000)
 #elif defined(CONFIG_ARCH_MSM7X30)
 #define PHYS_OFFSET		UL(0x00200000)
+#define RESET_VECTOR		UL(0x00000000)
+#else
+#ifdef CONFIG_MACH_SAPPHIRE
+#define PHYS_OFFSET		UL(0x02000000)
 #else
 #define PHYS_OFFSET		UL(0x10000000)
+#define RESET_VECTOR		UL(0x00000000)
+#endif
+#endif
+
+#define HAS_ARCH_IO_REMAP_PFN_RANGE
+
+#define CONSISTENT_DMA_SIZE (4*SZ_1M)
+
+#ifdef CONFIG_ARCH_MSM_SCORPION
+#define arch_has_speculative_dfetch()  1
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/mmc.h b/arch/arm/mach-msm/include/mach/mmc.h
index 0ecf254..4292517 100644
--- a/arch/arm/mach-msm/include/mach/mmc.h
+++ b/arch/arm/mach-msm/include/mach/mmc.h
@@ -17,6 +17,7 @@
 
 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;
diff --git a/arch/arm/mach-msm/include/mach/msm_adsp.h b/arch/arm/mach-msm/include/mach/msm_adsp.h
new file mode 100644
index 0000000..a081683
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_adsp.h
@@ -0,0 +1,112 @@
+/* include/asm-arm/arch-msm/msm_adsp.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM__ARCH_MSM_ADSP_H
+#define __ASM__ARCH_MSM_ADSP_H
+
+struct msm_adsp_module;
+
+struct msm_adsp_ops {
+	/* event is called from interrupt context when a message
+	 * arrives from the DSP.  Use the provided function pointer
+	 * to copy the message into a local buffer.  Do NOT call
+	 * it multiple times.
+	 */
+	void (*event)(void *driver_data, unsigned id, size_t len,
+		      void (*getevent)(void *ptr, size_t len));
+};
+
+/* Get, Put, Enable, and Disable are synchronous and must only
+ * be called from thread context.  Enable and Disable will block
+ * up to one second in the event of a fatal DSP error but are
+ * much faster otherwise.
+ */
+int msm_adsp_get(const char *name, struct msm_adsp_module **module,
+		 struct msm_adsp_ops *ops, void *driver_data);
+void msm_adsp_put(struct msm_adsp_module *module);
+int msm_adsp_enable(struct msm_adsp_module *module);
+int msm_adsp_disable(struct msm_adsp_module *module);
+int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate);
+
+/* Write is safe to call from interrupt context.
+ */
+int msm_adsp_write(struct msm_adsp_module *module,
+		   unsigned queue_id,
+		   void *data, size_t len);
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+/* Command Queue Indexes */
+#define QDSP_lpmCommandQueue              0
+#define QDSP_mpuAfeQueue                  1
+#define QDSP_mpuGraphicsCmdQueue          2
+#define QDSP_mpuModmathCmdQueue           3
+#define QDSP_mpuVDecCmdQueue              4
+#define QDSP_mpuVDecPktQueue              5
+#define QDSP_mpuVEncCmdQueue              6
+#define QDSP_rxMpuDecCmdQueue             7
+#define QDSP_rxMpuDecPktQueue             8
+#define QDSP_txMpuEncQueue                9
+#define QDSP_uPAudPPCmd1Queue             10
+#define QDSP_uPAudPPCmd2Queue             11
+#define QDSP_uPAudPPCmd3Queue             12
+#define QDSP_uPAudPlay0BitStreamCtrlQueue 13
+#define QDSP_uPAudPlay1BitStreamCtrlQueue 14
+#define QDSP_uPAudPlay2BitStreamCtrlQueue 15
+#define QDSP_uPAudPlay3BitStreamCtrlQueue 16
+#define QDSP_uPAudPlay4BitStreamCtrlQueue 17
+#define QDSP_uPAudPreProcCmdQueue         18
+#define QDSP_uPAudRecBitStreamQueue       19
+#define QDSP_uPAudRecCmdQueue             20
+#define QDSP_uPDiagQueue                  21
+#define QDSP_uPJpegActionCmdQueue         22
+#define QDSP_uPJpegCfgCmdQueue            23
+#define QDSP_uPVocProcQueue               24
+#define QDSP_vfeCommandQueue              25
+#define QDSP_vfeCommandScaleQueue         26
+#define QDSP_vfeCommandTableQueue         27
+#define QDSP_MAX_NUM_QUEUES               28
+#else
+/* Command Queue Indexes */
+#define QDSP_lpmCommandQueue              0
+#define QDSP_mpuAfeQueue                  1
+#define QDSP_mpuGraphicsCmdQueue          2
+#define QDSP_mpuModmathCmdQueue           3
+#define QDSP_mpuVDecCmdQueue              4
+#define QDSP_mpuVDecPktQueue              5
+#define QDSP_mpuVEncCmdQueue              6
+#define QDSP_rxMpuDecCmdQueue             7
+#define QDSP_rxMpuDecPktQueue             8
+#define QDSP_txMpuEncQueue                9
+#define QDSP_uPAudPPCmd1Queue             10
+#define QDSP_uPAudPPCmd2Queue             11
+#define QDSP_uPAudPPCmd3Queue             12
+#define QDSP_uPAudPlay0BitStreamCtrlQueue 13
+#define QDSP_uPAudPlay1BitStreamCtrlQueue 14
+#define QDSP_uPAudPlay2BitStreamCtrlQueue 15
+#define QDSP_uPAudPlay3BitStreamCtrlQueue 16
+#define QDSP_uPAudPlay4BitStreamCtrlQueue 17
+#define QDSP_uPAudPreProcCmdQueue         18
+#define QDSP_uPAudRecBitStreamQueue       19
+#define QDSP_uPAudRecCmdQueue             20
+#define QDSP_uPJpegActionCmdQueue         21
+#define QDSP_uPJpegCfgCmdQueue            22
+#define QDSP_uPVocProcQueue               23
+#define QDSP_vfeCommandQueue              24
+#define QDSP_vfeCommandScaleQueue         25
+#define QDSP_vfeCommandTableQueue         26
+#define QDSP_QUEUE_MAX                    26
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_audio_aac.h b/arch/arm/mach-msm/include/mach/msm_audio_aac.h
new file mode 100644
index 0000000..1aea0fa
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_audio_aac.h
@@ -0,0 +1,75 @@
+/* arch/arm/mach-msm/include/mach/msm_audio_aac.h
+ *
+ * Copyright (c) 2009 QUALCOMM USA, 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ *
+ */
+
+#ifndef __MSM_AUDIO_AAC_H
+#define __MSM_AUDIO_AAC_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_SET_AAC_CONFIG  _IOW(AUDIO_IOCTL_MAGIC, \
+  (AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned)
+#define AUDIO_GET_AAC_CONFIG  _IOR(AUDIO_IOCTL_MAGIC, \
+  (AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned)
+
+#define AUDIO_AAC_FORMAT_ADTS		-1
+#define	AUDIO_AAC_FORMAT_RAW		0x0000
+#define	AUDIO_AAC_FORMAT_PSUEDO_RAW	0x0001
+#define AUDIO_AAC_FORMAT_LOAS		0x0002
+
+#define AUDIO_AAC_OBJECT_LC            	0x0002
+#define AUDIO_AAC_OBJECT_LTP		0x0004
+#define AUDIO_AAC_OBJECT_ERLC  		0x0011
+
+#define AUDIO_AAC_SEC_DATA_RES_ON       0x0001
+#define AUDIO_AAC_SEC_DATA_RES_OFF      0x0000
+
+#define AUDIO_AAC_SCA_DATA_RES_ON       0x0001
+#define AUDIO_AAC_SCA_DATA_RES_OFF      0x0000
+
+#define AUDIO_AAC_SPEC_DATA_RES_ON      0x0001
+#define AUDIO_AAC_SPEC_DATA_RES_OFF     0x0000
+
+#define AUDIO_AAC_SBR_ON_FLAG_ON	0x0001
+#define AUDIO_AAC_SBR_ON_FLAG_OFF	0x0000
+
+#define AUDIO_AAC_SBR_PS_ON_FLAG_ON	0x0001
+#define AUDIO_AAC_SBR_PS_ON_FLAG_OFF	0x0000
+
+/* Primary channel on both left and right channels */
+#define AUDIO_AAC_DUAL_MONO_PL_PR  0
+/* Secondary channel on both left and right channels */
+#define AUDIO_AAC_DUAL_MONO_SL_SR  1
+/* Primary channel on right channel and 2nd on left channel */
+#define AUDIO_AAC_DUAL_MONO_SL_PR  2
+/* 2nd channel on right channel and primary on left channel */
+#define AUDIO_AAC_DUAL_MONO_PL_SR  3
+
+struct msm_audio_aac_config {
+	signed short format;
+	unsigned short audio_object;
+	unsigned short ep_config;	/* 0 ~ 3 useful only obj = ERLC */
+	unsigned short aac_section_data_resilience_flag;
+	unsigned short aac_scalefactor_data_resilience_flag;
+	unsigned short aac_spectral_data_resilience_flag;
+	unsigned short sbr_on_flag;
+	unsigned short sbr_ps_on_flag;
+	unsigned short dual_mono_mode;
+	unsigned short channel_configuration;
+};
+
+#endif /* __MSM_AUDIO_AAC_H */
diff --git a/arch/arm/mach-msm/include/mach/msm_fast_timer.h b/arch/arm/mach-msm/include/mach/msm_fast_timer.h
new file mode 100644
index 0000000..e1660c1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_fast_timer.h
@@ -0,0 +1,19 @@
+/* arch/arm/mach-msm/include/mach/msm_fast_timer.h
+ *
+ * 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.
+ *
+ */
+
+void msm_enable_fast_timer(void);
+void msm_disable_fast_timer(void);
+u32 msm_read_fast_timer(void);
+
diff --git a/arch/arm/mach-msm/include/mach/msm_fb.h b/arch/arm/mach-msm/include/mach/msm_fb.h
index 1f4fc81..339fa46 100644
--- a/arch/arm/mach-msm/include/mach/msm_fb.h
+++ b/arch/arm/mach-msm/include/mach/msm_fb.h
@@ -21,6 +21,10 @@
 
 struct mddi_info;
 
+/* output interface format */
+#define MSM_MDP_OUT_IF_FMT_RGB565 0
+#define MSM_MDP_OUT_IF_FMT_RGB666 1
+
 struct msm_fb_data {
 	int xres;	/* x resolution in pixels */
 	int yres;	/* y resolution in pixels */
@@ -34,9 +38,12 @@
 };
 
 enum {
-	MSM_MDDI_PMDH_INTERFACE,
+	MSM_MDDI_PMDH_INTERFACE = 0,
 	MSM_MDDI_EMDH_INTERFACE,
 	MSM_EBI2_INTERFACE,
+	MSM_LCDC_INTERFACE,
+
+	MSM_MDP_NUM_INTERFACES = MSM_LCDC_INTERFACE + 1,
 };
 
 #define MSMFB_CAP_PARTIAL_UPDATES	(1 << 0)
@@ -85,6 +92,8 @@
 	/* fixup the mfr name, product id */
 	void (*fixup)(uint16_t *mfr_name, uint16_t *product_id);
 
+	int vsync_irq;
+
 	struct resource *fb_resource; /*optional*/
 	/* number of clients in the list that follows */
 	int num_clients;
@@ -110,17 +119,50 @@
 	} client_platform_data[];
 };
 
+struct msm_lcdc_timing {
+	unsigned int clk_rate;		/* dclk freq */
+	unsigned int hsync_pulse_width;	/* in dclks */
+	unsigned int hsync_back_porch;	/* in dclks */
+	unsigned int hsync_front_porch;	/* in dclks */
+	unsigned int hsync_skew;	/* in dclks */
+	unsigned int vsync_pulse_width;	/* in lines */
+	unsigned int vsync_back_porch;	/* in lines */
+	unsigned int vsync_front_porch;	/* in lines */
+
+	/* control signal polarity */
+	unsigned int vsync_act_low:1;
+	unsigned int hsync_act_low:1;
+	unsigned int den_act_low:1;
+};
+
+struct msm_lcdc_panel_ops {
+	int	(*init)(struct msm_lcdc_panel_ops *);
+	int	(*uninit)(struct msm_lcdc_panel_ops *);
+	int	(*blank)(struct msm_lcdc_panel_ops *);
+	int	(*unblank)(struct msm_lcdc_panel_ops *);
+};
+
+struct msm_lcdc_platform_data {
+	struct msm_lcdc_panel_ops	*panel_ops;
+	struct msm_lcdc_timing		*timing;
+	int				fb_id;
+	struct msm_fb_data		*fb_data;
+	struct resource			*fb_resource;
+};
+
 struct mdp_blit_req;
 struct fb_info;
 struct mdp_device {
 	struct device dev;
-	void (*dma)(struct mdp_device *mpd, uint32_t addr,
+	void (*dma)(struct mdp_device *mdp, uint32_t addr,
 		    uint32_t stride, uint32_t w, uint32_t h, uint32_t x,
 		    uint32_t y, struct msmfb_callback *callback, int interface);
-	void (*dma_wait)(struct mdp_device *mdp);
+	void (*dma_wait)(struct mdp_device *mdp, int interface);
 	int (*blit)(struct mdp_device *mdp, struct fb_info *fb,
 		    struct mdp_blit_req *req);
 	void (*set_grp_disp)(struct mdp_device *mdp, uint32_t disp_id);
+	int (*check_output_format)(struct mdp_device *mdp, int bpp);
+	int (*set_output_format)(struct mdp_device *mdp, int bpp);
 };
 
 struct class_interface;
@@ -140,6 +182,9 @@
 	int (*unblank)(struct msm_mddi_bridge_platform_data *,
 		       struct msm_mddi_client_data *);
 	struct msm_fb_data fb_data;
+
+	/* board file will identify what capabilities the panel supports */
+	uint32_t panel_caps;
 };
 
 
diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb.h b/arch/arm/mach-msm/include/mach/msm_hsusb.h
new file mode 100644
index 0000000..93fb9a4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h
@@ -0,0 +1,38 @@
+/* linux/include/asm-arm/arch-msm/hsusb.h
+ *
+ * Copyright (C) 2008 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_HSUSB_H
+#define __ASM_ARCH_MSM_HSUSB_H
+
+#include <linux/types.h>
+
+/* platform device data for msm_hsusb driver */
+
+struct msm_hsusb_platform_data {
+	/* hard reset the ULPI PHY */
+	void (*phy_reset)(void);
+
+	/* (de)assert the reset to the usb core */
+	void (*hw_reset)(bool enable);
+
+	/* for notification when USB is connected or disconnected */
+	void (*usb_connected)(int);
+
+	/* val, reg pairs terminated by -1 */
+	int *phy_init_seq;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h b/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h
new file mode 100644
index 0000000..a2035d9
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_USB_GADGET_MSM72K_UDC_H__
+#define __LINUX_USB_GADGET_MSM72K_UDC_H__
+
+/*-------------------------------------------------------------------------*/
+
+#define xprintk(level, fmt, args...) \
+	printk(level "%s: " fmt , driver_name , ## args)
+
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(fmt, args...) \
+	xprintk(KERN_DEBUG , fmt , ## args)
+#else
+#define DEBUG(fmt,args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDEBUG DEBUG
+#else
+#define VDEBUG(fmt,args...) \
+	do { } while (0)
+#endif	/* VERBOSE */
+
+#define ERROR(fmt,args...) \
+	xprintk(KERN_ERR , fmt , ## args)
+#define INFO(fmt,args...) \
+	xprintk(KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+
+#define USB_ID               (MSM_USB_BASE + 0x0000)
+#define USB_HWGENERAL        (MSM_USB_BASE + 0x0004)
+#define USB_HWHOST           (MSM_USB_BASE + 0x0008)
+#define USB_HWDEVICE         (MSM_USB_BASE + 0x000C)
+#define USB_HWTXBUF          (MSM_USB_BASE + 0x0010)
+#define USB_HWRXBUF          (MSM_USB_BASE + 0x0014)
+
+#ifdef CONFIG_ARCH_MSM7X00A
+#define USB_SBUSCFG          (MSM_USB_BASE + 0x0090)
+#else
+#define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
+#define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
+#endif
+
+#define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
+#define USB_HCIVERSION       (MSM_USB_BASE + 0x0102) /* 16 bit */
+#define USB_HCSPARAMS        (MSM_USB_BASE + 0x0104)
+#define USB_HCCPARAMS        (MSM_USB_BASE + 0x0108)
+#define USB_DCIVERSION       (MSM_USB_BASE + 0x0120) /* 16 bit */
+#define USB_USBCMD           (MSM_USB_BASE + 0x0140)
+#define USB_USBSTS           (MSM_USB_BASE + 0x0144)
+#define USB_USBINTR          (MSM_USB_BASE + 0x0148)
+#define USB_FRINDEX          (MSM_USB_BASE + 0x014C)
+#define USB_DEVICEADDR       (MSM_USB_BASE + 0x0154)
+#define USB_ENDPOINTLISTADDR (MSM_USB_BASE + 0x0158)
+#define USB_BURSTSIZE        (MSM_USB_BASE + 0x0160)
+#define USB_TXFILLTUNING     (MSM_USB_BASE + 0x0164)
+#define USB_ULPI_VIEWPORT    (MSM_USB_BASE + 0x0170)
+#define USB_ENDPTNAK         (MSM_USB_BASE + 0x0178)
+#define USB_ENDPTNAKEN       (MSM_USB_BASE + 0x017C)
+#define USB_PORTSC           (MSM_USB_BASE + 0x0184)
+#define USB_OTGSC            (MSM_USB_BASE + 0x01A4)
+#define USB_USBMODE          (MSM_USB_BASE + 0x01A8)
+#define USB_ENDPTSETUPSTAT   (MSM_USB_BASE + 0x01AC)
+#define USB_ENDPTPRIME       (MSM_USB_BASE + 0x01B0)
+#define USB_ENDPTFLUSH       (MSM_USB_BASE + 0x01B4)
+#define USB_ENDPTSTAT        (MSM_USB_BASE + 0x01B8)
+#define USB_ENDPTCOMPLETE    (MSM_USB_BASE + 0x01BC)
+#define USB_ENDPTCTRL(n)     (MSM_USB_BASE + 0x01C0 + (4 * (n)))
+
+
+#define USBCMD_RESET   2
+#define USBCMD_ATTACH  1
+#define USBCMD_ATDTW   (1 << 14)
+
+#define USBMODE_DEVICE 2
+#define USBMODE_HOST   3
+
+struct ept_queue_head {
+    unsigned config;
+    unsigned active; /* read-only */
+
+    unsigned next;
+    unsigned info;
+    unsigned page0;
+    unsigned page1;
+    unsigned page2;
+    unsigned page3;
+    unsigned page4;
+    unsigned reserved_0;
+
+    unsigned char setup_data[8];
+
+    unsigned reserved_1;
+    unsigned reserved_2;
+    unsigned reserved_3;
+    unsigned reserved_4;
+};
+
+#define CONFIG_MAX_PKT(n)     ((n) << 16)
+#define CONFIG_ZLT            (1 << 29)    /* stop on zero-len xfer */
+#define CONFIG_IOS            (1 << 15)    /* IRQ on setup */
+
+struct ept_queue_item {
+    unsigned next;
+    unsigned info;
+    unsigned page0;
+    unsigned page1;
+    unsigned page2;
+    unsigned page3;
+    unsigned page4;
+    unsigned reserved;
+};
+
+#define TERMINATE 1
+
+#define INFO_BYTES(n)         ((n) << 16)
+#define INFO_IOC              (1 << 15)
+#define INFO_ACTIVE           (1 << 7)
+#define INFO_HALTED           (1 << 6)
+#define INFO_BUFFER_ERROR     (1 << 5)
+#define INFO_TXN_ERROR        (1 << 3)
+
+
+#define STS_NAKI              (1 << 16)  /* */
+#define STS_SLI               (1 << 8)   /* R/WC - suspend state entered */
+#define STS_SRI               (1 << 7)   /* R/WC - SOF recv'd */
+#define STS_URI               (1 << 6)   /* R/WC - RESET recv'd - write to clear */
+#define STS_FRI               (1 << 3)   /* R/WC - Frame List Rollover */
+#define STS_PCI               (1 << 2)   /* R/WC - Port Change Detect */
+#define STS_UEI               (1 << 1)   /* R/WC - USB Error */
+#define STS_UI                (1 << 0)   /* R/WC - USB Transaction Complete */
+
+
+/* bits used in all the endpoint status registers */
+#define EPT_TX(n) (1 << ((n) + 16))
+#define EPT_RX(n) (1 << (n))
+
+
+#define CTRL_TXE              (1 << 23)
+#define CTRL_TXR              (1 << 22)
+#define CTRL_TXI              (1 << 21)
+#define CTRL_TXD              (1 << 17)
+#define CTRL_TXS              (1 << 16)
+#define CTRL_RXE              (1 << 7)
+#define CTRL_RXR              (1 << 6)
+#define CTRL_RXI              (1 << 5)
+#define CTRL_RXD              (1 << 1)
+#define CTRL_RXS              (1 << 0)
+
+#define CTRL_TXT_MASK         (3 << 18)
+#define CTRL_TXT_CTRL         (0 << 18)
+#define CTRL_TXT_ISOCH        (1 << 18)
+#define CTRL_TXT_BULK         (2 << 18)
+#define CTRL_TXT_INT          (3 << 18)
+#define CTRL_TXT_EP_TYPE_SHIFT 18
+
+#define CTRL_RXT_MASK         (3 << 2)
+#define CTRL_RXT_CTRL         (0 << 2)
+#define CTRL_RXT_ISOCH        (1 << 2)
+#define CTRL_RXT_BULK         (2 << 2)
+#define CTRL_RXT_INT          (3 << 2)
+#define CTRL_RXT_EP_TYPE_SHIFT 2
+
+#define ULPI_WAKEUP           (1 << 31)
+#define ULPI_RUN              (1 << 30)
+#define ULPI_WRITE            (1 << 29)
+#define ULPI_READ             (0 << 29)
+#define ULPI_STATE_NORMAL     (1 << 27)
+#define ULPI_ADDR(n)          (((n) & 255) << 16)
+#define ULPI_DATA(n)          ((n) & 255)
+#define ULPI_DATA_READ(n)     (((n) >> 8) & 255)
+
+#define ULPI_DEBUG_REG        (0x15)
+#define ULPI_SCRATCH_REG      (0x16)
+
+#define ULPI_FUNC_CTRL_CLR    (0x06)
+#define   ULPI_FUNC_SUSPENDM  (1 << 6)
+
+
+/* USB_PORTSC bits for determining port speed */
+#define PORTSC_PSPD_FS        (0 << 26)
+#define PORTSC_PSPD_LS        (1 << 26)
+#define PORTSC_PSPD_HS        (2 << 26)
+#define PORTSC_PSPD_MASK      (3 << 26)
+/* suspend and remote wakeup */
+#define PORTSC_FPR             (1 << 6)
+#define PORTSC_SUSP            (1 << 7)
+
+/* test mode support */
+#define J_TEST			(0x0100)
+#define K_TEST			(0x0200)
+#define SE0_NAK_TEST		(0x0300)
+#define TST_PKT_TEST		(0x0400)
+#define PORTSC_PTC		(0xf << 16)
+#define PORTSC_PTC_J_STATE	(0x01 << 16)
+#define PORTSC_PTC_K_STATE	(0x02 << 16)
+#define PORTSC_PTC_SE0_NAK	(0x03 << 16)
+#define PORTSC_PTC_TST_PKT	(0x04 << 16)
+
+#define PORTSC_PTS_MASK       (3 << 30)
+#define PORTSC_PTS_ULPI       (2 << 30)
+#define PORTSC_PTS_SERIAL     (3 << 30)
+
+#define PORTSC_CCS             (1 << 0)  /* current connect status */
+#define PORTSC_FPR             (1 << 6)  /* R/W - State normal => suspend */
+#define PORTSC_SUSP            (1 << 7)  /* Read - Port in suspend state */
+#define PORTSC_PORT_RESET      (1 << 8)
+#define PORTSC_LS              (3 << 10) /* Read - Port's Line status */
+#define PORTSC_PHCD            (1 << 23) /* phy suspend mode */
+
+#endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
index cfff0e7..571391b 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
@@ -43,35 +43,38 @@
 #define IOMEM(x)	((void __force __iomem *)(x))
 #endif
 
-#define MSM_VIC_BASE          IOMEM(0xE0000000)
+#define MSM_VIC_BASE          IOMEM(0xF8000000)
 #define MSM_VIC_PHYS          0xC0000000
 #define MSM_VIC_SIZE          SZ_4K
 
-#define MSM_CSR_BASE          IOMEM(0xE0001000)
+#define MSM_CSR_BASE          IOMEM(0xF8001000)
 #define MSM_CSR_PHYS          0xC0100000
 #define MSM_CSR_SIZE          SZ_4K
 
-#define MSM_GPT_PHYS          MSM_CSR_PHYS
-#define MSM_GPT_BASE          MSM_CSR_BASE
-#define MSM_GPT_SIZE          SZ_4K
+#define MSM_TMR_PHYS          MSM_CSR_PHYS
+#define MSM_TMR_BASE          MSM_CSR_BASE
+#define MSM_TMR_SIZE          SZ_4K
 
-#define MSM_DMOV_BASE         IOMEM(0xE0002000)
+#define MSM_GPT_BASE          MSM_TMR_BASE
+#define MSM_DGT_BASE          (MSM_TMR_BASE + 0x10)
+
+#define MSM_DMOV_BASE         IOMEM(0xF8002000)
 #define MSM_DMOV_PHYS         0xA9700000
 #define MSM_DMOV_SIZE         SZ_4K
 
-#define MSM_GPIO1_BASE        IOMEM(0xE0003000)
+#define MSM_GPIO1_BASE        IOMEM(0xF8003000)
 #define MSM_GPIO1_PHYS        0xA9200000
 #define MSM_GPIO1_SIZE        SZ_4K
 
-#define MSM_GPIO2_BASE        IOMEM(0xE0004000)
+#define MSM_GPIO2_BASE        IOMEM(0xF8004000)
 #define MSM_GPIO2_PHYS        0xA9300000
 #define MSM_GPIO2_SIZE        SZ_4K
 
-#define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
+#define MSM_CLK_CTL_BASE      IOMEM(0xF8005000)
 #define MSM_CLK_CTL_PHYS      0xA8600000
 #define MSM_CLK_CTL_SIZE      SZ_4K
 
-#define MSM_SHARED_RAM_BASE   IOMEM(0xE0100000)
+#define MSM_SHARED_RAM_BASE   IOMEM(0xF8100000)
 #define MSM_SHARED_RAM_PHYS   0x01F00000
 #define MSM_SHARED_RAM_SIZE   SZ_1M
 
@@ -85,7 +88,7 @@
 #define MSM_UART3_SIZE        SZ_4K
 
 #ifdef CONFIG_MSM_DEBUG_UART
-#define MSM_DEBUG_UART_BASE   0xE1000000
+#define MSM_DEBUG_UART_BASE   0xF9000000
 #if CONFIG_MSM_DEBUG_UART == 1
 #define MSM_DEBUG_UART_PHYS   MSM_UART1_PHYS
 #elif CONFIG_MSM_DEBUG_UART == 2
@@ -108,6 +111,9 @@
 #define MSM_SDC4_PHYS         0xA0700000
 #define MSM_SDC4_SIZE         SZ_4K
 
+#define MSM_NAND_PHYS         0xA0A00000
+#define MSM_NAND_SIZE         SZ_4K
+
 #define MSM_I2C_PHYS          0xA9900000
 #define MSM_I2C_SIZE          SZ_4K
 
@@ -123,12 +129,25 @@
 #define MSM_MDP_PHYS          0xAA200000
 #define MSM_MDP_SIZE          0x000F0000
 
+#define MSM_MDC_BASE	      IOMEM(0xF8200000)
 #define MSM_MDC_PHYS	      0xAA500000
 #define MSM_MDC_SIZE	      SZ_1M
 
+#define MSM_AD5_BASE          IOMEM(0xF8300000)
 #define MSM_AD5_PHYS          0xAC000000
 #define MSM_AD5_SIZE          (SZ_1M*13)
 
+#define MSM_VFE_PHYS          0xA0F00000
+#define MSM_VFE_SIZE          SZ_1M
+
+#define MSM_UART1DM_PHYS      0xA0200000
+#define MSM_UART2DM_PHYS      0xA0300000
+
+#define MSM_SSBI_PHYS         0xA8100000
+#define MSM_SSBI_SIZE         SZ_4K
+
+#define MSM_TSSC_PHYS         0xAA300000
+#define MSM_TSSC_SIZE         SZ_4K
 
 #if defined(CONFIG_ARCH_MSM7X30)
 #define MSM_GCC_BASE          IOMEM(0xF8009000)
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
index 8a00c2d..1c24b39 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
@@ -35,11 +35,11 @@
  *
  */
 
-#define MSM_VIC_BASE          IOMEM(0xE0000000)
+#define MSM_VIC_BASE          IOMEM(0xF8000000)
 #define MSM_VIC_PHYS          0xC0080000
 #define MSM_VIC_SIZE          SZ_4K
 
-#define MSM_CSR_BASE          IOMEM(0xE0001000)
+#define MSM_CSR_BASE          IOMEM(0xF8001000)
 #define MSM_CSR_PHYS          0xC0100000
 #define MSM_CSR_SIZE          SZ_4K
 
@@ -50,43 +50,43 @@
 #define MSM_GPT_BASE 	      (MSM_TMR_BASE + 0x4)
 #define MSM_DGT_BASE 	      (MSM_TMR_BASE + 0x24)
 
-#define MSM_DMOV_BASE         IOMEM(0xE0002000)
+#define MSM_DMOV_BASE         IOMEM(0xF8002000)
 #define MSM_DMOV_PHYS         0xAC400000
 #define MSM_DMOV_SIZE         SZ_4K
 
-#define MSM_GPIO1_BASE        IOMEM(0xE0003000)
+#define MSM_GPIO1_BASE        IOMEM(0xF8003000)
 #define MSM_GPIO1_PHYS        0xAC001000
 #define MSM_GPIO1_SIZE        SZ_4K
 
-#define MSM_GPIO2_BASE        IOMEM(0xE0004000)
+#define MSM_GPIO2_BASE        IOMEM(0xF8004000)
 #define MSM_GPIO2_PHYS        0xAC101000
 #define MSM_GPIO2_SIZE        SZ_4K
 
-#define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
+#define MSM_CLK_CTL_BASE      IOMEM(0xF8005000)
 #define MSM_CLK_CTL_PHYS      0xAB800000
 #define MSM_CLK_CTL_SIZE      SZ_4K
 
-#define MSM_CLK_CTL_SH2_BASE  IOMEM(0xE0006000)
+#define MSM_CLK_CTL_SH2_BASE  IOMEM(0xF8006000)
 #define MSM_CLK_CTL_SH2_PHYS  0xABA01000
 #define MSM_CLK_CTL_SH2_SIZE  SZ_4K
 
-#define MSM_ACC_BASE          IOMEM(0xE0007000)
+#define MSM_ACC_BASE          IOMEM(0xF8007000)
 #define MSM_ACC_PHYS          0xC0101000
 #define MSM_ACC_SIZE          SZ_4K
 
-#define MSM_SAW_BASE          IOMEM(0xE0008000)
+#define MSM_SAW_BASE          IOMEM(0xF8008000)
 #define MSM_SAW_PHYS          0xC0102000
 #define MSM_SAW_SIZE          SZ_4K
 
-#define MSM_GCC_BASE	      IOMEM(0xE0009000)
+#define MSM_GCC_BASE	      IOMEM(0xF8009000)
 #define MSM_GCC_PHYS	      0xC0182000
 #define MSM_GCC_SIZE	      SZ_4K
 
-#define MSM_TCSR_BASE	      IOMEM(0xE000A000)
+#define MSM_TCSR_BASE	      IOMEM(0xF800A000)
 #define MSM_TCSR_PHYS	      0xAB600000
 #define MSM_TCSR_SIZE	      SZ_4K
 
-#define MSM_SHARED_RAM_BASE   IOMEM(0xE0100000)
+#define MSM_SHARED_RAM_BASE   IOMEM(0xF8100000)
 #define MSM_SHARED_RAM_PHYS   0x00100000
 #define MSM_SHARED_RAM_SIZE   SZ_1M
 
@@ -100,7 +100,7 @@
 #define MSM_UART3_SIZE        SZ_4K
 
 #ifdef CONFIG_MSM_DEBUG_UART
-#define MSM_DEBUG_UART_BASE   0xE1000000
+#define MSM_DEBUG_UART_BASE   0xF9000000
 #if CONFIG_MSM_DEBUG_UART == 1
 #define MSM_DEBUG_UART_PHYS   MSM_UART1_PHYS
 #elif CONFIG_MSM_DEBUG_UART == 2
@@ -111,12 +111,69 @@
 #define MSM_DEBUG_UART_SIZE   SZ_4K
 #endif
 
-#define MSM_MDC_BASE	      IOMEM(0xE0200000)
+#define MSM_MDC_BASE	      IOMEM(0xF8200000)
 #define MSM_MDC_PHYS	      0xAA500000
 #define MSM_MDC_SIZE	      SZ_1M
 
-#define MSM_AD5_BASE          IOMEM(0xE0300000)
+#define MSM_AD5_BASE          IOMEM(0xF8300000)
 #define MSM_AD5_PHYS          0xA7000000
 #define MSM_AD5_SIZE          (SZ_1M*13)
 
+#define MSM_VFE_PHYS          0xA0F00000
+#define MSM_VFE_SIZE          SZ_1M
+
+#define MSM_I2C_SIZE          SZ_4K
+#define MSM_I2C_PHYS          0xACD00000
+
+#define MSM_I2C_2_PHYS	      0xACF00000
+#define MSM_I2C_2_SIZE	      SZ_4K
+
+#define MSM_QUP_PHYS          0xA8301000
+#define MSM_QUP_SIZE          SZ_4K
+
+#define MSM_GSBI_QUP_I2C_PHYS 0xA8300000
+#define MSM_GSBI_QUP_I2C_SIZE 4
+
+#define MSM_HSUSB_PHYS        0xA3600000
+#define MSM_HSUSB_SIZE        SZ_1K
+
+#define MSM_PMDH_PHYS         0xAD600000
+#define MSM_PMDH_SIZE         SZ_4K
+
+#define MSM_EMDH_PHYS         0xAD700000
+#define MSM_EMDH_SIZE         SZ_4K
+
+#define MSM_MDP_PHYS          0xA3F00000
+#define MSM_MDP_SIZE          0x000F0000
+
+#define MSM_UART1DM_PHYS      0xA0200000
+#define MSM_UART2DM_PHYS      0xA0300000
+
+#define MSM_TSSC_PHYS         0xAA300000
+#define MSM_TSSC_SIZE         SZ_4K
+
+#define MSM_SDC1_PHYS         0xA0400000
+#define MSM_SDC1_SIZE         SZ_4K
+
+#define MSM_SDC2_PHYS         0xA0500000
+#define MSM_SDC2_SIZE         SZ_4K
+
+#define MSM_SDC3_PHYS         0xA3000000
+#define MSM_SDC3_SIZE         SZ_4K
+
+#define MSM_SDC4_PHYS         0xA3100000
+#define MSM_SDC4_SIZE         SZ_4K
+
+#define MSM_NAND_PHYS         0xA0200000
+#define MSM_NAND_SIZE         SZ_4K
+
+#define MSM_PMIC_SSBI_PHYS    0xAD900000
+#define MSM_PMIC_SSBI_SIZE    SZ_4K
+
+#define MSM_GPU_REG_PHYS      0xA3500000
+#define MSM_GPU_REG_SIZE      SZ_128K
+
+#define MSM_SPI_PHYS          0xA8000000
+#define MSM_SPI_SIZE          SZ_4K
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
index acc819e..eed8606 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
@@ -35,11 +35,11 @@
  *
  */
 
-#define MSM_VIC_BASE          IOMEM(0xE0000000)
+#define MSM_VIC_BASE          IOMEM(0xF8000000)
 #define MSM_VIC_PHYS          0xAC000000
 #define MSM_VIC_SIZE          SZ_4K
 
-#define MSM_CSR_BASE          IOMEM(0xE0001000)
+#define MSM_CSR_BASE          IOMEM(0xF8001000)
 #define MSM_CSR_PHYS          0xAC100000
 #define MSM_CSR_SIZE          SZ_4K
 
@@ -50,38 +50,42 @@
 #define MSM_GPT_BASE          MSM_TMR_BASE
 #define MSM_DGT_BASE          (MSM_TMR_BASE + 0x10)
 
-#define MSM_DMOV_BASE         IOMEM(0xE0002000)
+#define MSM_DMOV_BASE         IOMEM(0xF8002000)
 #define MSM_DMOV_PHYS         0xA9700000
 #define MSM_DMOV_SIZE         SZ_4K
 
-#define MSM_GPIO1_BASE        IOMEM(0xE0003000)
+#define MSM_GPIO1_BASE        IOMEM(0xF8003000)
 #define MSM_GPIO1_PHYS        0xA9000000
 #define MSM_GPIO1_SIZE        SZ_4K
 
-#define MSM_GPIO2_BASE        IOMEM(0xE0004000)
+#define MSM_GPIO2_BASE        IOMEM(0xF8004000)
 #define MSM_GPIO2_PHYS        0xA9100000
 #define MSM_GPIO2_SIZE        SZ_4K
 
-#define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
+#define MSM_CLK_CTL_BASE      IOMEM(0xF8005000)
 #define MSM_CLK_CTL_PHYS      0xA8600000
 #define MSM_CLK_CTL_SIZE      SZ_4K
 
-#define MSM_SIRC_BASE         IOMEM(0xE1006000)
+#define MSM_SIRC_BASE         IOMEM(0xF8006000)
 #define MSM_SIRC_PHYS         0xAC200000
 #define MSM_SIRC_SIZE         SZ_4K
 
-#define MSM_SCPLL_BASE        IOMEM(0xE1007000)
+#define MSM_SCPLL_BASE        IOMEM(0xF8007000)
 #define MSM_SCPLL_PHYS        0xA8800000
 #define MSM_SCPLL_SIZE        SZ_4K
 
+#define MSM_TCSR_BASE         IOMEM(0xF8008000)
+#define MSM_TCSR_PHYS         0xA8700000
+#define MSM_TCSR_SIZE         SZ_4K
+
 #ifdef CONFIG_MSM_SOC_REV_A
-#define MSM_SMI_BASE 0xE0000000
+#define MSM_8K_SMI_BASE 0xE0000000
 #else
-#define MSM_SMI_BASE 0x00000000
+#define MSM_8K_SMI_BASE 0x00000000
 #endif
 
-#define MSM_SHARED_RAM_BASE   IOMEM(0xE0100000)
-#define MSM_SHARED_RAM_PHYS (MSM_SMI_BASE + 0x00100000)
+#define MSM_SHARED_RAM_BASE   IOMEM(0xF8100000)
+#define MSM_SHARED_RAM_PHYS   (MSM_8K_SMI_BASE + 0x00100000)
 #define MSM_SHARED_RAM_SIZE   SZ_1M
 
 #define MSM_UART1_PHYS        0xA9A00000
@@ -94,7 +98,7 @@
 #define MSM_UART3_SIZE        SZ_4K
 
 #ifdef CONFIG_MSM_DEBUG_UART
-#define MSM_DEBUG_UART_BASE   0xE1000000
+#define MSM_DEBUG_UART_BASE   0xF9000000
 #if CONFIG_MSM_DEBUG_UART == 1
 #define MSM_DEBUG_UART_PHYS   MSM_UART1_PHYS
 #elif CONFIG_MSM_DEBUG_UART == 2
@@ -105,14 +109,16 @@
 #define MSM_DEBUG_UART_SIZE   SZ_4K
 #endif
 
-#define MSM_MDC_BASE	      IOMEM(0xE0200000)
+#define MSM_MDC_BASE	      IOMEM(0xF8200000)
 #define MSM_MDC_PHYS	      0xAA500000
 #define MSM_MDC_SIZE	      SZ_1M
 
-#define MSM_AD5_BASE          IOMEM(0xE0300000)
+#define MSM_AD5_BASE          IOMEM(0xF8300000)
 #define MSM_AD5_PHYS          0xAC000000
 #define MSM_AD5_SIZE          (SZ_1M*13)
 
+#define MSM_VFE_PHYS          0xA0F00000
+#define MSM_VFE_SIZE          SZ_1M
 
 #define MSM_I2C_SIZE          SZ_4K
 #define MSM_I2C_PHYS          0xA9900000
@@ -120,8 +126,17 @@
 #define MSM_HSUSB_PHYS        0xA0800000
 #define MSM_HSUSB_SIZE        SZ_1K
 
-#define MSM_NAND_PHYS           0xA0A00000
+#define MSM_PMDH_PHYS         0xAA600000
+#define MSM_PMDH_SIZE         SZ_4K
 
+#define MSM_EMDH_PHYS         0xAA700000
+#define MSM_EMDH_SIZE         SZ_4K
+
+#define MSM_MDP_PHYS          0xAA200000
+#define MSM_MDP_SIZE          0x000F0000
+
+#define MSM_NAND_PHYS         0xA0A00000
+#define MSM_NAND_SIZE         SZ_4K
 
 #define MSM_TSIF_PHYS        (0xa0100000)
 #define MSM_TSIF_SIZE        (0x200)
@@ -131,17 +146,25 @@
 #define MSM_UART1DM_PHYS      0xA0200000
 #define MSM_UART2DM_PHYS      0xA0900000
 
+#define MSM_TSSC_PHYS         0xAA300000
+#define MSM_TSSC_SIZE         SZ_4K
 
-#define MSM_SDC1_PHYS          0xA0400000
+#define MSM_SDC1_PHYS          0xA0300000
 #define MSM_SDC1_SIZE          SZ_4K
 
-#define MSM_SDC2_PHYS          0xA0500000
+#define MSM_SDC2_PHYS          0xA0400000
 #define MSM_SDC2_SIZE          SZ_4K
 
-#define MSM_SDC3_PHYS          0xA0600000
+#define MSM_SDC3_PHYS          0xA0500000
 #define MSM_SDC3_SIZE           SZ_4K
 
-#define MSM_SDC4_PHYS          0xA0700000
+#define MSM_SDC4_PHYS          0xA0600000
 #define MSM_SDC4_SIZE          SZ_4K
 
+#define MSM_GPU_REG_PHYS      0xA0000000
+#define MSM_GPU_REG_SIZE      0x00020000
+
+#define MSM_SPI_PHYS          0xA1200000
+#define MSM_SPI_SIZE          SZ_4K
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h b/arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h
new file mode 100644
index 0000000..54614a9
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h
@@ -0,0 +1,107 @@
+/* arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MACH_MSM_QDSP6_Q6AUDIO_
+#define _MACH_MSM_QDSP6_Q6AUDIO_
+
+#define AUDIO_FLAG_READ		0
+#define AUDIO_FLAG_WRITE	1
+
+struct audio_buffer {
+	dma_addr_t phys;
+	void *data;
+	uint32_t size;
+	uint32_t used;	/* 1 = CPU is waiting for DSP to consume this buf */
+};
+
+struct audio_client {
+	struct audio_buffer buf[2];
+	int cpu_buf;	/* next buffer the CPU will touch */
+	int dsp_buf;	/* next buffer the DSP will touch */
+	int running;
+	int session;
+
+	wait_queue_head_t wait;
+	struct dal_client *client;
+
+	int cb_status;
+	uint32_t flags;
+};
+
+#define Q6_HW_HANDSET	0
+#define Q6_HW_HEADSET	1
+#define Q6_HW_SPEAKER	2
+#define Q6_HW_TTY	3
+#define Q6_HW_BT_SCO	4
+#define Q6_HW_BT_A2DP	5
+
+#define Q6_HW_COUNT	6
+
+struct q6_hw_info {
+	int min_gain;
+	int max_gain;
+};
+
+/* Obtain a 16bit signed, interleaved audio channel of the specified
+ * rate (Hz) and channels (1 or 2), with two buffers of bufsz bytes.
+ */
+struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate,
+				      uint32_t channels, uint32_t flags,
+				      uint32_t acdb_id);
+
+struct audio_client *q6voice_open(uint32_t flags, uint32_t acdb_id);
+
+struct audio_client *q6audio_open_mp3(uint32_t bufsz, uint32_t rate,
+				      uint32_t channels, uint32_t acdb_id);
+
+int q6audio_close(struct audio_client *ac);
+int q6voice_close(struct audio_client *ac);
+int q6audio_mp3_close(struct audio_client *ac);
+
+int q6audio_read(struct audio_client *ac, struct audio_buffer *ab);
+int q6audio_write(struct audio_client *ac, struct audio_buffer *ab);
+int q6audio_async(struct audio_client *ac);
+
+int q6audio_do_routing(uint32_t route, uint32_t acdb_id);
+int q6audio_set_tx_mute(int mute);
+int q6audio_reinit_acdb(char* filename);
+int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst);
+int q6audio_set_rx_volume(int level);
+int q6audio_set_stream_volume(struct audio_client *ac, int vol);
+
+struct q6audio_analog_ops {
+	void (*init)(void);
+	void (*speaker_enable)(int en);
+	void (*headset_enable)(int en);
+	void (*receiver_enable)(int en);
+	void (*bt_sco_enable)(int en);
+	void (*int_mic_enable)(int en);
+	void (*ext_mic_enable)(int en);
+	int (*get_rx_vol)(uint8_t hw, int level);
+};
+
+#ifdef CONFIG_MSM_QDSP6
+void q6audio_register_analog_ops(struct q6audio_analog_ops *ops);
+void q6audio_set_acdb_file(char* filename);
+#else
+static inline void q6audio_register_analog_ops(struct q6audio_analog_ops *ops) {}
+static inline void q6audio_set_acdb_file(char* filename) {}
+#endif
+
+/* signal non-recoverable DSP error so we can log and/or panic */
+void q6audio_dsp_not_responding(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_qup.h b/arch/arm/mach-msm/include/mach/msm_qup.h
new file mode 100644
index 0000000..e95b5d6
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_qup.h
@@ -0,0 +1,16 @@
+#ifndef _MACH_MSM_QUP_H
+#define _MACH_MSM_QUP_H
+
+struct msm_qup_i2c_platform_data {
+        int clk_freq;
+        uint32_t rmutex;
+        const char *rsl_id;
+        uint32_t pm_lat;
+        int pri_clk;
+        int pri_dat;
+        int aux_clk;
+        int aux_dat;
+        void (*msm_i2c_config_gpio)(int iface, int config_type);
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h
new file mode 100644
index 0000000..b2f8e3e
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h
@@ -0,0 +1,180 @@
+/** include/asm-arm/arch-msm/msm_rpcrouter.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009 QUALCOMM Incorporated
+ * Author: San Mehat <san@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 __ASM__ARCH_MSM_RPCROUTER_H
+#define __ASM__ARCH_MSM_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+
+#if !defined(CONFIG_MSM_LEGACY_7X00A_AMSS)
+/* RPC API version structure
+ * Version bit 31 : 1->hashkey versioning,
+ *                  0->major-minor (backward compatible) versioning
+ * hashkey versioning:
+ *   Version bits 31-0 hashkey
+ * major-minor (backward compatible) versioning
+ *   Version bits 30-28 reserved (no match)
+ *   Version bits 27-16 major (must match)
+ *   Version bits 15-0  minor (greater or equal)
+ */
+#define RPC_VERSION_MODE_MASK  0x80000000
+#define RPC_VERSION_MAJOR_MASK 0x0fff0000
+#define RPC_VERSION_MAJOR_OFFSET 16
+#define RPC_VERSION_MINOR_MASK 0x0000ffff
+
+#define MSM_RPC_VERS(major, minor)					\
+	((uint32_t)((((major) << RPC_VERSION_MAJOR_OFFSET) &		\
+		RPC_VERSION_MAJOR_MASK) |				\
+	((minor) & RPC_VERSION_MINOR_MASK)))
+#define MSM_RPC_GET_MAJOR(vers) (((vers) & RPC_VERSION_MAJOR_MASK) >>	\
+					RPC_VERSION_MAJOR_OFFSET)
+#define MSM_RPC_GET_MINOR(vers) ((vers) & RPC_VERSION_MINOR_MASK)
+#else
+#define MSM_RPC_VERS(major, minor) (major)
+#define MSM_RPC_GET_MAJOR(vers) (vers)
+#define MSM_RPC_GET_MINOR(vers) 0
+#endif
+
+struct msm_rpc_endpoint;
+
+struct rpcsvr_platform_device
+{
+	struct platform_device base;
+	uint32_t prog;
+	uint32_t vers;
+};
+
+#define RPC_DATA_IN	0
+/*
+ * Structures for sending / receiving direct RPC requests
+ * XXX: Any cred/verif lengths > 0 not supported
+ */
+
+struct rpc_request_hdr
+{
+	uint32_t xid;
+	uint32_t type;	/* 0 */
+	uint32_t rpc_vers; /* 2 */
+	uint32_t prog;
+	uint32_t vers;
+	uint32_t procedure;
+	uint32_t cred_flavor;
+	uint32_t cred_length;
+	uint32_t verf_flavor;
+	uint32_t verf_length;
+};
+
+typedef struct
+{
+	uint32_t low;
+	uint32_t high;
+} rpc_reply_progmismatch_data;
+
+typedef struct
+{
+} rpc_denied_reply_hdr;
+
+typedef struct
+{
+	uint32_t verf_flavor;
+	uint32_t verf_length;
+	uint32_t accept_stat;
+#define RPC_ACCEPTSTAT_SUCCESS 0
+#define RPC_ACCEPTSTAT_PROG_UNAVAIL 1
+#define RPC_ACCEPTSTAT_PROG_MISMATCH 2
+#define RPC_ACCEPTSTAT_PROC_UNAVAIL 3
+#define RPC_ACCEPTSTAT_GARBAGE_ARGS 4
+#define RPC_ACCEPTSTAT_SYSTEM_ERR 5
+#define RPC_ACCEPTSTAT_PROG_LOCKED 6
+	/*
+	 * Following data is dependant on accept_stat
+	 * If ACCEPTSTAT == PROG_MISMATCH then there is a
+	 * 'rpc_reply_progmismatch_data' structure following the header.
+	 * Otherwise the data is procedure specific
+	 */
+} rpc_accepted_reply_hdr;
+
+struct rpc_reply_hdr
+{
+	uint32_t xid;
+	uint32_t type;
+	uint32_t reply_stat;
+#define RPCMSG_REPLYSTAT_ACCEPTED 0
+#define RPCMSG_REPLYSTAT_DENIED 1
+	union {
+		rpc_accepted_reply_hdr acc_hdr;
+		rpc_denied_reply_hdr dny_hdr;
+	} data;
+};
+
+/* flags for msm_rpc_connect() */
+#define MSM_RPC_UNINTERRUPTIBLE 0x0001
+#define MSM_RPC_ENABLE_RECEIVE (0x10000)
+
+/* use IS_ERR() to check for failure */
+struct msm_rpc_endpoint *msm_rpc_open(void);
+/* Connect with the specified server version */
+struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags);
+uint32_t msm_rpc_get_vers(struct msm_rpc_endpoint *ept);
+/* check if server version can handle client requested version */
+int msm_rpc_is_compatible_version(uint32_t server_version,
+				  uint32_t client_version);
+
+int msm_rpc_close(struct msm_rpc_endpoint *ept);
+int msm_rpc_write(struct msm_rpc_endpoint *ept,
+		  void *data, int len);
+int msm_rpc_read(struct msm_rpc_endpoint *ept,
+		 void **data, unsigned len, long timeout);
+void msm_rpc_setup_req(struct rpc_request_hdr *hdr,
+		       uint32_t prog, uint32_t vers, uint32_t proc);
+int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
+			    uint32_t prog, uint32_t vers);
+int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
+			      uint32_t prog, uint32_t vers);
+
+/* simple blocking rpc call
+ *
+ * request is mandatory and must have a rpc_request_hdr
+ * at the start.  The header will be filled out for you.
+ *
+ * reply provides a buffer for replies of reply_max_size
+ */
+int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
+		       void *request, int request_size,
+		       void *reply, int reply_max_size,
+		       long timeout);
+int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
+		 void *request, int request_size,
+		 long timeout);
+
+struct msm_rpc_server
+{
+	struct list_head list;
+	uint32_t flags;
+
+	uint32_t prog;
+	uint32_t vers;
+
+	int (*rpc_call)(struct msm_rpc_server *server,
+			struct rpc_request_hdr *req, unsigned len);
+};
+
+int msm_rpc_create_server(struct msm_rpc_server *server);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_debugger.h b/arch/arm/mach-msm/include/mach/msm_serial_debugger.h
new file mode 100644
index 0000000..f490b1b
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_serial_debugger.h
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_SERIAL_DEBUGGER_H
+#define __ASM_ARCH_MSM_SERIAL_DEBUGGER_H
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+void msm_serial_debug_init(unsigned int base, int irq,
+		struct device *clk_device, int signal_irq, int wakeup_irq);
+#else
+static inline void msm_serial_debug_init(unsigned int base, int irq,
+		struct device *clk_device, int signal_irq, int wakeup_irq) {}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs.h b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
new file mode 100644
index 0000000..fe54b02
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Author: 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.
+ */
+
+#ifndef __ASM_ARCH_MSM_SERIAL_HS_H
+#define __ASM_ARCH_MSM_SERIAL_HS_H
+
+#include <linux/serial_core.h>
+
+/* API to request the uart clock off or on for low power management
+ * Clients should call request_clock_off() when no uart data is expected,
+ * and must call request_clock_on() before any further uart data can be
+ * received. */
+extern void msm_hs_request_clock_off(struct uart_port *uport);
+extern void msm_hs_request_clock_on(struct uart_port *uport);
+/* uport->lock must be held when calling _locked() */
+extern void msm_hs_request_clock_off_locked(struct uart_port *uport);
+extern void msm_hs_request_clock_on_locked(struct uart_port *uport);
+
+/* Optional platform device data for msm_serial_hs driver.
+ * Used to configure low power rx wakeup */
+struct msm_serial_hs_platform_data {
+	int rx_wakeup_irq;  /* wakeup irq */
+	/* bool: inject char into rx tty on wakeup */
+	unsigned char inject_rx_on_wakeup;
+	char rx_to_inject;
+
+	void (*exit_lpm_cb)(struct uart_port *);
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 029463e..7ed2939 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -106,4 +106,11 @@
 	SMD_NUM_PORTS,
 } smd_port_id_type;
 
+struct smd_tty_channel_desc {
+	int id;
+	const char *name;
+};
+
+int smd_set_channel_list(const struct smd_tty_channel_desc *, int len);
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_spi.h b/arch/arm/mach-msm/include/mach/msm_spi.h
new file mode 100644
index 0000000..433b2bd
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_spi.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT 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.
+ *
+ */
+/*
+ * SPI driver for Qualcomm QSD platforms.
+ */
+
+struct msm_spi_platform_data {
+	u32 max_clock_speed;
+	int (*gpio_config)(void);
+	void (*gpio_release)(void);
+	int (*dma_config)(void);
+};
diff --git a/arch/arm/mach-msm/include/mach/msm_ssbi.h b/arch/arm/mach-msm/include/mach/msm_ssbi.h
new file mode 100644
index 0000000..4d79078
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_ssbi.h
@@ -0,0 +1,35 @@
+/* arch/arm/mach-msm/include/mach/msm_ssbi.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_SSBI_H
+#define __ASM_ARCH_MSM_SSBI_H
+
+#include <linux/types.h>
+
+struct msm_ssbi_slave_info {
+	const char	*name;
+	int		irq;
+	void		*platform_data;
+};
+
+struct msm_ssbi_platform_data {
+	struct msm_ssbi_slave_info	slave;
+	const char			*rspinlock_name;
+};
+
+int msm_ssbi_write(struct device *dev, u16 addr, u8 *buf, int len);
+int msm_ssbi_read(struct device *dev, u16 addr, u8 *buf, int len);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_ts.h b/arch/arm/mach-msm/include/mach/msm_ts.h
new file mode 100644
index 0000000..cb41aed
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_ts.h
@@ -0,0 +1,51 @@
+/* arch/arm/mach-msm/include/mach/msm_ts.h
+ *
+ * Internal platform definitions for msm/qsd touchscreen devices
+ *
+ * Copyright (C) 2008 Google 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.
+ */
+
+#ifndef __ASM_ARCH_MSM_TS_H
+#define __ASM_ARCH_MSM_TS_H
+
+#include <linux/input.h>
+
+/* The dimensions for the virtual key are for the other axis, i.e. if
+ * virtual keys are in the Y dimension then min/max is the range in the X
+ * dimension where that key would be activated */
+struct ts_virt_key {
+	int key;
+	int min;
+	int max;
+};
+
+struct msm_ts_virtual_keys {
+	struct ts_virt_key	*keys;
+	int			num_keys;
+};
+
+struct msm_ts_platform_data {
+	uint32_t			min_x;
+	uint32_t			max_x;
+	uint32_t			min_y;
+	uint32_t			max_y;
+	uint32_t			min_press;
+	uint32_t			max_press;
+	struct msm_ts_virtual_keys	*vkeys_x;
+	uint32_t			virt_x_start;
+	struct msm_ts_virtual_keys	*vkeys_y;
+	uint32_t			virt_y_start;
+	uint32_t			inv_x;
+	uint32_t			inv_y;
+};
+
+#endif /* __ASM_ARCH_MSM_TS_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaycmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaycmdi.h
new file mode 100644
index 0000000..ece4bc7
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaycmdi.h
@@ -0,0 +1,94 @@
+#ifndef QDSP5AUDPLAYCMDI_H
+#define QDSP5AUDPLAYCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+       Q D S P 5  A U D I O   P L A Y  T A S K   C O M M A N D S
+
+GENERAL DESCRIPTION
+  Command Interface for AUDPLAYTASK on QDSP5
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+
+  audplay_cmd_dec_data_avail
+    Send buffer to AUDPLAY task
+	
+  
+Copyright(c) 1992 - 2009 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audplaycmdi.h#2 $
+  
+===========================================================================*/
+
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL		0x0000
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_LEN	\
+	sizeof(audplay_cmd_bitstream_data_avail)
+
+/* Type specification of dec_data_avail message sent to AUDPLAYTASK
+*/
+typedef struct {
+	/*command ID*/
+	unsigned int cmd_id;
+
+	/* Decoder ID for which message is being sent */
+	unsigned int decoder_id;
+
+	/* Start address of data in ARM global memory */
+	unsigned int buf_ptr;
+
+	/* Number of 16-bit words of bit-stream data contiguously available at the
+	 * above-mentioned address. */
+	unsigned int buf_size;
+
+	/* Partition number used by audPlayTask to communicate with DSP's RTOS
+	 * kernel */
+	unsigned int partition_number;
+} __attribute__((packed)) audplay_cmd_bitstream_data_avail;
+
+#define AUDPLAY_CMD_HPCM_BUF_CFG 0x0003
+#define AUDPLAY_CMD_HPCM_BUF_CFG_LEN \
+	sizeof(struct audplay_cmd_hpcm_buf_cfg)
+
+struct audplay_cmd_hpcm_buf_cfg {
+	unsigned int cmd_id;
+	unsigned int hostpcm_config;
+	unsigned int feedback_frequency;
+	unsigned int byte_swap;
+	unsigned int max_buffers;
+	unsigned int partition_number;
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_BUFFER_REFRESH 0x0004
+#define AUDPLAY_CMD_BUFFER_REFRESH_LEN \
+	sizeof(struct audplay_cmd_buffer_update)
+
+struct audplay_cmd_buffer_refresh {
+	unsigned int cmd_id;
+	unsigned int num_buffers;
+	unsigned int buf_read_count;
+	unsigned int buf0_address;
+	unsigned int buf0_length;
+	unsigned int buf1_address;
+	unsigned int buf1_length;
+} __attribute__((packed));
+#endif /* QDSP5AUDPLAYCMD_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaymsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaymsg.h
new file mode 100644
index 0000000..c63034b
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaymsg.h
@@ -0,0 +1,70 @@
+#ifndef QDSP5AUDPLAYMSG_H
+#define QDSP5AUDPLAYMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+       Q D S P 5  A U D I O   P L A Y  T A S K   M S G
+
+GENERAL DESCRIPTION
+  Message sent by AUDPLAY task
+
+REFERENCES
+  None
+
+
+Copyright(c) 1992 - 2009 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audplaymsg.h#3 $
+
+===========================================================================*/
+#define AUDPLAY_MSG_DEC_NEEDS_DATA		0x0001
+#define AUDPLAY_MSG_DEC_NEEDS_DATA_MSG_LEN	\
+	sizeof(audplay_msg_dec_needs_data)
+
+typedef struct{
+	/* reserved*/
+	unsigned int dec_id;
+
+	/* The read pointer offset of external memory until which the
+	 * bitstream has been DMAed in. */
+	unsigned int adecDataReadPtrOffset;
+
+	/* The buffer size of external memory. */
+	unsigned int adecDataBufSize;
+
+	unsigned int bitstream_free_len;
+	unsigned int bitstream_write_ptr;
+	unsigned int bitstarem_buf_start;
+	unsigned int bitstream_buf_len;
+} __attribute__((packed)) audplay_msg_dec_needs_data;
+
+#define AUDPLAY_MSG_BUFFER_UPDATE 0x0004
+#define AUDPLAY_MSG_BUFFER_UPDATE_LEN \
+	sizeof(struct audplay_msg_buffer_update)
+
+struct audplay_msg_buffer_update {
+	unsigned int buffer_write_count;
+	unsigned int num_of_buffer;
+	unsigned int buf0_address;
+	unsigned int buf0_length;
+	unsigned int buf1_address;
+	unsigned int buf1_length;
+} __attribute__((packed));
+#endif /* QDSP5AUDPLAYMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
new file mode 100644
index 0000000..8bee9c6
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
@@ -0,0 +1,914 @@
+#ifndef QDSP5AUDPPCMDI_H
+#define QDSP5AUDPPCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    A U D I O   P O S T   P R O C E S S I N G  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by AUDPP Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audppcmdi.h#2 $
+
+===========================================================================*/
+
+/*
+ * ARM to AUDPPTASK Commands
+ *
+ * ARM uses three command queues to communicate with AUDPPTASK
+ * 1)uPAudPPCmd1Queue : Used for more frequent and shorter length commands
+ * 	Location : MEMA
+ * 	Buffer Size : 6 words
+ * 	No of buffers in a queue : 20 for gaming audio and 5 for other images
+ * 2)uPAudPPCmd2Queue : Used for commands which are not much lengthier
+ * 	Location : MEMA
+ * 	Buffer Size : 23
+ * 	No of buffers in a queue : 2
+ * 3)uPAudOOCmd3Queue : Used for lengthier and more frequent commands
+ * 	Location : MEMA
+ * 	Buffer Size : 145
+ * 	No of buffers in a queue : 3
+ */
+
+/*
+ * Commands Related to uPAudPPCmd1Queue
+ */
+
+/*
+ * Command Structure to enable or disable the active decoders
+ */
+
+#define AUDPP_CMD_CFG_DEC_TYPE 		0x0001
+#define AUDPP_CMD_CFG_DEC_TYPE_LEN 	sizeof(audpp_cmd_cfg_dec_type)
+
+/* Enable the decoder */
+#define AUDPP_CMD_DEC_TYPE_M           	0x000F
+
+#define AUDPP_CMD_ENA_DEC_V         	0x4000
+#define AUDPP_CMD_DIS_DEC_V        	0x0000
+#define AUDPP_CMD_DEC_STATE_M          	0x4000
+
+#define AUDPP_CMD_UPDATDE_CFG_DEC	0x8000
+#define AUDPP_CMD_DONT_UPDATE_CFG_DEC	0x0000
+
+
+/* Type specification of cmd_cfg_dec */
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short dec0_cfg;
+	unsigned short dec1_cfg;
+	unsigned short dec2_cfg;
+	unsigned short dec3_cfg;
+	unsigned short dec4_cfg;
+} __attribute__((packed)) audpp_cmd_cfg_dec_type;
+
+/*
+ * Command Structure to Pause , Resume and flushes the selected audio decoders
+ */
+
+#define AUDPP_CMD_DEC_CTRL		0x0002
+#define AUDPP_CMD_DEC_CTRL_LEN		sizeof(audpp_cmd_dec_ctrl)
+
+/* Decoder control commands for pause, resume and flush */
+#define AUDPP_CMD_FLUSH_V         		0x2000
+
+#define AUDPP_CMD_PAUSE_V		        0x4000
+#define AUDPP_CMD_RESUME_V		        0x0000
+
+#define AUDPP_CMD_UPDATE_V		        0x8000
+#define AUDPP_CMD_IGNORE_V		        0x0000
+
+
+/* Type Spec for decoder control command*/
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short dec0_ctrl;
+	unsigned short dec1_ctrl;
+	unsigned short dec2_ctrl;
+	unsigned short dec3_ctrl;
+	unsigned short dec4_ctrl;
+} __attribute__((packed)) audpp_cmd_dec_ctrl;
+
+/*
+ * Command Structure to Configure the AVSync FeedBack Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC	0x0003
+#define AUDPP_CMD_AVSYNC_LEN	sizeof(audpp_cmd_avsync)
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short object_number;
+	unsigned short interrupt_interval_lsw;
+	unsigned short interrupt_interval_msw;
+} __attribute__((packed)) audpp_cmd_avsync;
+
+/*
+ * Command Structure to enable or disable(sleep) the   AUDPPTASK
+ */
+
+#define AUDPP_CMD_CFG	0x0004
+#define AUDPP_CMD_CFG_LEN	sizeof(audpp_cmd_cfg)
+
+#define AUDPP_CMD_CFG_SLEEP   				0x0000
+#define AUDPP_CMD_CFG_ENABLE  				0xFFFF
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short cfg;
+} __attribute__((packed)) audpp_cmd_cfg;
+
+/*
+ * Command Structure to Inject or drop the specified no of samples
+ */
+
+#define AUDPP_CMD_ADJUST_SAMP		0x0005
+#define AUDPP_CMD_ADJUST_SAMP_LEN	sizeof(audpp_cmd_adjust_samp)
+
+#define AUDPP_CMD_SAMP_DROP		-1
+#define AUDPP_CMD_SAMP_INSERT		0x0001
+
+#define AUDPP_CMD_NUM_SAMPLES		0x0001
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short object_no;
+	signed short sample_insert_or_drop;
+	unsigned short num_samples;
+} __attribute__((packed)) audpp_cmd_adjust_samp;
+
+/*
+ * Command Structure to Configure AVSync Feedback Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC_CMD_2		0x0006
+#define AUDPP_CMD_AVSYNC_CMD_2_LEN	sizeof(audpp_cmd_avsync_cmd_2)
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short object_number;
+	unsigned short interrupt_interval_lsw;
+	unsigned short interrupt_interval_msw;
+	unsigned short sample_counter_dlsw;
+	unsigned short sample_counter_dmsw;
+	unsigned short sample_counter_msw;
+	unsigned short byte_counter_dlsw;
+	unsigned short byte_counter_dmsw;
+	unsigned short byte_counter_msw;
+} __attribute__((packed)) audpp_cmd_avsync_cmd_2;
+
+/*
+ * Command Structure to Configure AVSync Feedback Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC_CMD_3		0x0007
+#define AUDPP_CMD_AVSYNC_CMD_3_LEN	sizeof(audpp_cmd_avsync_cmd_3)
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short object_number;
+	unsigned short interrupt_interval_lsw;
+	unsigned short interrupt_interval_msw;
+	unsigned short sample_counter_dlsw;
+	unsigned short sample_counter_dmsw;
+	unsigned short sample_counter_msw;
+	unsigned short byte_counter_dlsw;
+	unsigned short byte_counter_dmsw;
+	unsigned short byte_counter_msw;
+} __attribute__((packed)) audpp_cmd_avsync_cmd_3;
+
+#define AUDPP_CMD_ROUTING_MODE      0x0008
+#define AUDPP_CMD_ROUTING_MODE_LEN  \
+sizeof(struct audpp_cmd_routing_mode)
+
+struct audpp_cmd_routing_mode {
+	unsigned short cmd_id;
+	unsigned short object_number;
+	unsigned short routing_mode;
+} __attribute__((packed));
+
+/*
+ * Commands Related to uPAudPPCmd2Queue
+ */
+
+/*
+ * Command Structure to configure Per decoder Parameters (Common)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS 		0x0000
+#define AUDPP_CMD_CFG_ADEC_PARAMS_COMMON_LEN	\
+	sizeof(audpp_cmd_cfg_adec_params_common)
+
+#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_FCM	0x4000
+#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_FCM	0x0000
+
+#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_DCM	0x8000
+#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_DCM	0x0000
+
+/* Sampling frequency*/
+#define  AUDPP_CMD_SAMP_RATE_96000 	0x0000
+#define  AUDPP_CMD_SAMP_RATE_88200 	0x0001
+#define  AUDPP_CMD_SAMP_RATE_64000 	0x0002
+#define  AUDPP_CMD_SAMP_RATE_48000 	0x0003
+#define  AUDPP_CMD_SAMP_RATE_44100 	0x0004
+#define  AUDPP_CMD_SAMP_RATE_32000 	0x0005
+#define  AUDPP_CMD_SAMP_RATE_24000 	0x0006
+#define  AUDPP_CMD_SAMP_RATE_22050 	0x0007
+#define  AUDPP_CMD_SAMP_RATE_16000 	0x0008
+#define  AUDPP_CMD_SAMP_RATE_12000 	0x0009
+#define  AUDPP_CMD_SAMP_RATE_11025 	0x000A
+#define  AUDPP_CMD_SAMP_RATE_8000  	0x000B
+
+
+/*
+ * Type specification of cmd_adec_cfg sent to all decoder
+ */
+
+typedef struct {
+  unsigned short cmd_id;
+  unsigned short  length;
+  unsigned short  dec_id;
+  unsigned short  status_msg_flag;
+  unsigned short  decoder_frame_counter_msg_period;
+  unsigned short  input_sampling_frequency;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_common;
+
+/*
+ * Command Structure to configure Per decoder Parameters (Wav)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN	\
+	sizeof(audpp_cmd_cfg_adec_params_wav)
+
+
+#define AUDPP_CMD_WAV_STEREO_CFG_MONO	0x0001
+#define AUDPP_CMD_WAV_STEREO_CFG_STEREO	0x0002
+
+#define AUDPP_CMD_WAV_PCM_WIDTH_8	0x0000
+#define AUDPP_CMD_WAV_PCM_WIDTH_16	0x0001
+#define AUDPP_CMD_WAV_PCM_WIDTH_32	0x0002
+
+typedef struct {
+	audpp_cmd_cfg_adec_params_common		common;
+	unsigned short					stereo_cfg;
+	unsigned short					pcm_width;
+	unsigned short 					sign;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_wav;
+
+/*
+ * Command Structure to configure Per decoder Parameters (ADPCM)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_ADPCM_LEN	\
+	sizeof(audpp_cmd_cfg_adec_params_adpcm)
+
+
+#define	AUDPP_CMD_ADPCM_STEREO_CFG_MONO		0x0001
+#define AUDPP_CMD_ADPCM_STEREO_CFG_STEREO	0x0002
+
+typedef struct {
+	audpp_cmd_cfg_adec_params_common		common;
+	unsigned short					stereo_cfg;
+	unsigned short 					block_size;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_adpcm;
+
+/*
+ * Command Structure to configure Per decoder Parameters (MP3)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN	\
+	sizeof(audpp_cmd_cfg_adec_params_mp3)
+
+typedef struct {
+   audpp_cmd_cfg_adec_params_common    common;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_mp3;
+
+
+/*
+ * Command Structure to configure Per decoder Parameters (AAC)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AAC_LEN	\
+	sizeof(audpp_cmd_cfg_adec_params_aac)
+
+
+#define AUDPP_CMD_AAC_FORMAT_ADTS		-1
+#define	AUDPP_CMD_AAC_FORMAT_RAW		0x0000
+#define	AUDPP_CMD_AAC_FORMAT_PSUEDO_RAW		0x0001
+#define	AUDPP_CMD_AAC_FORMAT_LOAS		0x0002
+
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_LC		0x0002
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_LTP		0x0004
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_ERLC	0x0011
+
+#define AUDPP_CMD_AAC_SBR_ON_FLAG_ON		0x0001
+#define AUDPP_CMD_AAC_SBR_ON_FLAG_OFF		0x0000
+
+#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_ON		0x0001
+#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_OFF	0x0000
+
+typedef struct {
+  audpp_cmd_cfg_adec_params_common	common;
+  signed short				format;
+  unsigned short			audio_object;
+  unsigned short			ep_config;
+  unsigned short                        aac_section_data_resilience_flag;
+  unsigned short                        aac_scalefactor_data_resilience_flag;
+  unsigned short                        aac_spectral_data_resilience_flag;
+  unsigned short                        sbr_on_flag;
+  unsigned short                        sbr_ps_on_flag;
+  unsigned short                        dual_mono_mode;
+  unsigned short                        channel_configuration;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_aac;
+
+/*
+ * Command Structure to configure Per decoder Parameters (V13K)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_v13k)
+
+
+#define AUDPP_CMD_STEREO_CFG_MONO		0x0001
+#define AUDPP_CMD_STEREO_CFG_STEREO		0x0002
+
+struct audpp_cmd_cfg_adec_params_v13k {
+   audpp_cmd_cfg_adec_params_common    	common;
+   unsigned short			stereo_cfg;
+} __attribute__((packed));
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_EVRC_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_evrc)
+
+struct audpp_cmd_cfg_adec_params_evrc {
+	audpp_cmd_cfg_adec_params_common common;
+	unsigned short stereo_cfg;
+} __attribute__ ((packed));
+
+/*
+ * Command Structure to configure the  HOST PCM interface
+ */
+
+#define AUDPP_CMD_PCM_INTF	0x0001
+#define AUDPP_CMD_PCM_INTF_2	0x0002
+#define AUDPP_CMD_PCM_INTF_LEN	sizeof(audpp_cmd_pcm_intf)
+
+#define AUDPP_CMD_PCM_INTF_MONO_V		        0x0001
+#define AUDPP_CMD_PCM_INTF_STEREO_V         	0x0002
+
+/* These two values differentiate the two types of commands that could be issued
+ * Interface configuration command and Buffer update command */
+
+#define AUDPP_CMD_PCM_INTF_CONFIG_CMD_V	       	0x0000
+#define AUDPP_CMD_PCM_INTF_BUFFER_CMD_V	        -1
+
+#define AUDPP_CMD_PCM_INTF_RX_ENA_M              0x000F
+#define AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V     0x0008
+#define AUDPP_CMD_PCM_INTF_RX_ENA_DSPTOARM_V     0x0004
+
+/* These flags control the enabling and disabling of the interface together
+ *  with host interface bit mask. */
+
+#define AUDPP_CMD_PCM_INTF_ENA_V            -1
+#define AUDPP_CMD_PCM_INTF_DIS_V            0x0000
+
+
+#define  AUDPP_CMD_PCM_INTF_FULL_DUPLEX           0x0
+#define  AUDPP_CMD_PCM_INTF_HALF_DUPLEX_TODSP     0x1
+
+
+#define  AUDPP_CMD_PCM_INTF_OBJECT_NUM           0x5
+#define  AUDPP_CMD_PCM_INTF_COMMON_OBJECT_NUM    0x6
+
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short  object_num;
+	signed short  config;
+	unsigned short  intf_type;
+
+	/* DSP -> ARM Configuration */
+	unsigned short  read_buf1LSW;
+	unsigned short  read_buf1MSW;
+	unsigned short  read_buf1_len;
+
+	unsigned short  read_buf2LSW;
+	unsigned short  read_buf2MSW;
+	unsigned short  read_buf2_len;
+	/*   0:HOST_PCM_INTF disable
+	**  0xFFFF: HOST_PCM_INTF enable
+	*/
+	signed short  dsp_to_arm_flag;
+	unsigned short  partition_number;
+
+	/* ARM -> DSP Configuration */
+	unsigned short  write_buf1LSW;
+	unsigned short  write_buf1MSW;
+	unsigned short  write_buf1_len;
+
+	unsigned short  write_buf2LSW;
+	unsigned short  write_buf2MSW;
+	unsigned short  write_buf2_len;
+
+	/*   0:HOST_PCM_INTF disable
+	**  0xFFFF: HOST_PCM_INTF enable
+	*/
+	signed short  arm_to_rx_flag;
+	unsigned short  weight_decoder_to_rx;
+	unsigned short  weight_arm_to_rx;
+
+	unsigned short  partition_number_arm_to_dsp;
+	unsigned short  sample_rate;
+	unsigned short  channel_mode;
+} __attribute__((packed)) audpp_cmd_pcm_intf;
+
+/*
+ **  BUFFER UPDATE COMMAND
+ */
+#define AUDPP_CMD_PCM_INTF_SEND_BUF_PARAMS_LEN	\
+	sizeof(audpp_cmd_pcm_intf_send_buffer)
+
+typedef struct {
+  unsigned short  cmd_id;
+  unsigned short  host_pcm_object;
+  /* set config = 0xFFFF for configuration*/
+  signed short  config;
+  unsigned short  intf_type;
+  unsigned short  dsp_to_arm_buf_id;
+  unsigned short  arm_to_dsp_buf_id;
+  unsigned short  arm_to_dsp_buf_len;
+} __attribute__((packed)) audpp_cmd_pcm_intf_send_buffer;
+
+
+/*
+ * Commands Related to uPAudPPCmd3Queue
+ */
+
+/*
+ * Command Structure to configure post processing params (Commmon)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS		0x0000
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_common)
+
+#define AUDPP_CMD_OBJ0_UPDATE		0x8000
+#define AUDPP_CMD_OBJ0_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ1_UPDATE		0x8000
+#define AUDPP_CMD_OBJ1_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ2_UPDATE		0x8000
+#define AUDPP_CMD_OBJ2_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ3_UPDATE		0x8000
+#define AUDPP_CMD_OBJ3_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ4_UPDATE		0x8000
+#define AUDPP_CMD_OBJ4_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_HPCM_UPDATE		0x8000
+#define AUDPP_CMD_HPCM_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_COMMON_CFG_UPDATE		0x8000
+#define AUDPP_CMD_COMMON_CFG_DONT_UPDATE	0x0000
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short	obj0_cfg;
+	unsigned short	obj1_cfg;
+	unsigned short	obj2_cfg;
+	unsigned short	obj3_cfg;
+	unsigned short	obj4_cfg;
+	unsigned short	host_pcm_obj_cfg;
+	unsigned short	comman_cfg;
+	unsigned short  command_type;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_common;
+
+/*
+ * Command Structure to configure post processing params (Volume)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_VOLUME_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_volume)
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	unsigned short					volume;
+	unsigned short					pan;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_volume;
+
+/*
+ * Command Structure to configure post processing params (PCM Filter) --DOUBT
+ */
+
+typedef struct {
+	unsigned short			numerator_b0_filter_lsw;
+	unsigned short			numerator_b0_filter_msw;
+	unsigned short			numerator_b1_filter_lsw;
+	unsigned short			numerator_b1_filter_msw;
+	unsigned short			numerator_b2_filter_lsw;
+	unsigned short			numerator_b2_filter_msw;
+} __attribute__((packed)) numerator;
+
+typedef struct {
+	unsigned short			denominator_a0_filter_lsw;
+	unsigned short			denominator_a0_filter_msw;
+	unsigned short			denominator_a1_filter_lsw;
+	unsigned short			denominator_a1_filter_msw;
+} __attribute__((packed)) denominator;
+
+typedef struct {
+	unsigned short			shift_factor_0;
+} __attribute__((packed)) shift_factor;
+
+typedef struct {
+	unsigned short			pan_filter_0;
+} __attribute__((packed)) pan;
+
+typedef struct {
+		numerator		numerator_filter;
+		denominator		denominator_filter;
+		shift_factor		shift_factor_filter;
+		pan			pan_filter;
+} __attribute__((packed)) filter_1;
+
+typedef struct {
+		numerator		numerator_filter[2];
+		denominator		denominator_filter[2];
+		shift_factor		shift_factor_filter[2];
+		pan			pan_filter[2];
+} __attribute__((packed)) filter_2;
+
+typedef struct {
+		numerator		numerator_filter[3];
+		denominator		denominator_filter[3];
+		shift_factor		shift_factor_filter[3];
+		pan			pan_filter[3];
+} __attribute__((packed)) filter_3;
+
+typedef struct {
+		numerator		numerator_filter[4];
+		denominator		denominator_filter[4];
+		shift_factor		shift_factor_filter[4];
+		pan			pan_filter[4];
+} __attribute__((packed)) filter_4;
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_PCM_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_pcm)
+
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	unsigned short				active_flag;
+	unsigned short 				num_bands;
+	union {
+		filter_1			filter_1_params;
+		filter_2			filter_2_params;
+		filter_3			filter_3_params;
+		filter_4			filter_4_params;
+	} __attribute__((packed)) params_filter;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_pcm;
+
+
+/*
+ * Command Structure to configure post processing parameters (equalizer)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_EQALIZER_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_eqalizer)
+
+typedef struct {
+	unsigned short			numerator_coeff_0_lsw;
+	unsigned short			numerator_coeff_0_msw;
+	unsigned short			numerator_coeff_1_lsw;
+	unsigned short			numerator_coeff_1_msw;
+	unsigned short			numerator_coeff_2_lsw;
+	unsigned short			numerator_coeff_2_msw;
+} __attribute__((packed)) eq_numerator;
+
+typedef struct {
+	unsigned short			denominator_coeff_0_lsw;
+	unsigned short			denominator_coeff_0_msw;
+	unsigned short			denominator_coeff_1_lsw;
+	unsigned short			denominator_coeff_1_msw;
+} __attribute__((packed)) eq_denominator;
+
+typedef struct {
+	unsigned short			shift_factor;
+} __attribute__((packed)) eq_shiftfactor;
+
+typedef struct {
+	eq_numerator	numerator;
+	eq_denominator	denominator;
+	eq_shiftfactor	shiftfactor;
+} __attribute__((packed)) eq_coeff_1;
+
+typedef struct {
+	eq_numerator	numerator[2];
+	eq_denominator	denominator[2];
+	eq_shiftfactor	shiftfactor[2];
+} __attribute__((packed)) eq_coeff_2;
+
+typedef struct {
+	eq_numerator	numerator[3];
+	eq_denominator	denominator[3];
+	eq_shiftfactor	shiftfactor[3];
+} __attribute__((packed)) eq_coeff_3;
+
+typedef struct {
+	eq_numerator	numerator[4];
+	eq_denominator	denominator[4];
+	eq_shiftfactor	shiftfactor[4];
+} __attribute__((packed)) eq_coeff_4;
+
+typedef struct {
+	eq_numerator	numerator[5];
+	eq_denominator	denominator[5];
+	eq_shiftfactor	shiftfactor[5];
+} __attribute__((packed)) eq_coeff_5;
+
+typedef struct {
+	eq_numerator	numerator[6];
+	eq_denominator	denominator[6];
+	eq_shiftfactor	shiftfactor[6];
+} __attribute__((packed)) eq_coeff_6;
+
+typedef struct {
+	eq_numerator	numerator[7];
+	eq_denominator	denominator[7];
+	eq_shiftfactor	shiftfactor[7];
+} __attribute__((packed)) eq_coeff_7;
+
+typedef struct {
+	eq_numerator	numerator[8];
+	eq_denominator	denominator[8];
+	eq_shiftfactor	shiftfactor[8];
+} __attribute__((packed)) eq_coeff_8;
+
+typedef struct {
+	eq_numerator	numerator[9];
+	eq_denominator	denominator[9];
+	eq_shiftfactor	shiftfactor[9];
+} __attribute__((packed)) eq_coeff_9;
+
+typedef struct {
+	eq_numerator	numerator[10];
+	eq_denominator	denominator[10];
+	eq_shiftfactor	shiftfactor[10];
+} __attribute__((packed)) eq_coeff_10;
+
+typedef struct {
+	eq_numerator	numerator[11];
+	eq_denominator	denominator[11];
+	eq_shiftfactor	shiftfactor[11];
+} __attribute__((packed)) eq_coeff_11;
+
+typedef struct {
+	eq_numerator	numerator[12];
+	eq_denominator	denominator[12];
+	eq_shiftfactor	shiftfactor[12];
+} __attribute__((packed)) eq_coeff_12;
+
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	unsigned short				eq_flag;
+	unsigned short				num_bands;
+	union {
+		eq_coeff_1	eq_coeffs_1;
+		eq_coeff_2	eq_coeffs_2;
+		eq_coeff_3	eq_coeffs_3;
+		eq_coeff_4	eq_coeffs_4;
+		eq_coeff_5	eq_coeffs_5;
+		eq_coeff_6	eq_coeffs_6;
+		eq_coeff_7	eq_coeffs_7;
+		eq_coeff_8	eq_coeffs_8;
+		eq_coeff_9	eq_coeffs_9;
+		eq_coeff_10	eq_coeffs_10;
+		eq_coeff_11	eq_coeffs_11;
+		eq_coeff_12	eq_coeffs_12;
+	} __attribute__((packed)) eq_coeff;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_eqalizer;
+
+
+/*
+ * Command Structure to configure post processing parameters (ADRC)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_ADRC_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_adrc)
+
+
+#define AUDPP_CMD_ADRC_FLAG_DIS		0x0000
+#define AUDPP_CMD_ADRC_FLAG_ENA		-1
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	signed short				adrc_flag;
+	unsigned short				compression_th;
+	unsigned short				compression_slope;
+	unsigned short				rms_time;
+	unsigned short				attack_const_lsw;
+	unsigned short				attack_const_msw;
+	unsigned short				release_const_lsw;
+	unsigned short				release_const_msw;
+	unsigned short				adrc_system_delay;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_adrc;
+
+/*
+ * Command Structure to configure post processing parameters(Spectrum Analizer)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_SPECTRAM_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_spectram)
+
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	unsigned short				sample_interval;
+	unsigned short				num_coeff;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_spectram;
+
+/*
+ * Command Structure to configure post processing parameters (QConcert)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_QCONCERT_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_qconcert)
+
+
+#define AUDPP_CMD_QCON_ENA_FLAG_ENA		-1
+#define AUDPP_CMD_QCON_ENA_FLAG_DIS		0x0000
+
+#define AUDPP_CMD_QCON_OP_MODE_HEADPHONE	-1
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_FRONT	0x0000
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_SIDE	0x0001
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_DESKTOP	0x0002
+
+#define AUDPP_CMD_QCON_GAIN_UNIT			0x7FFF
+#define AUDPP_CMD_QCON_GAIN_SIX_DB			0x4027
+
+
+#define AUDPP_CMD_QCON_EXPANSION_MAX		0x7FFF
+
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	signed short				enable_flag;
+	signed short				output_mode;
+	signed short				gain;
+	signed short				expansion;
+	signed short				delay;
+	unsigned short				stages_per_mode;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_qconcert;
+
+/*
+ * Command Structure to configure post processing parameters (Side Chain)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_SIDECHAIN_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_sidechain)
+
+
+#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_DIS	0x0000
+#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_ENA	-1
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	signed short				active_flag;
+	unsigned short				num_bands;
+	union {
+		filter_1			filter_1_params;
+		filter_2			filter_2_params;
+		filter_3			filter_3_params;
+		filter_4			filter_4_params;
+	} __attribute__((packed)) params_filter;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_sidechain;
+
+
+/*
+ * Command Structure to configure post processing parameters (QAFX)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_QAFX_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_qafx)
+
+#define AUDPP_CMD_QAFX_ENA_DISA		0x0000
+#define AUDPP_CMD_QAFX_ENA_ENA_CFG	-1
+#define AUDPP_CMD_QAFX_ENA_DIS_CFG	0x0001
+
+#define AUDPP_CMD_QAFX_CMD_TYPE_ENV	0x0100
+#define AUDPP_CMD_QAFX_CMD_TYPE_OBJ	0x0010
+#define AUDPP_CMD_QAFX_CMD_TYPE_QUERY	0x1000
+
+#define AUDPP_CMD_QAFX_CMDS_ENV_OP_MODE	0x0100
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_POS	0x0101
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_ORI	0x0102
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_VEL	0X0103
+#define AUDPP_CMD_QAFX_CMDS_ENV_ENV_RES	0x0107
+
+#define AUDPP_CMD_QAFX_CMDS_OBJ_SAMP_FREQ	0x0010
+#define AUDPP_CMD_QAFX_CMDS_OBJ_VOL		0x0011
+#define AUDPP_CMD_QAFX_CMDS_OBJ_DIST		0x0012
+#define AUDPP_CMD_QAFX_CMDS_OBJ_POS		0x0013
+#define AUDPP_CMD_QAFX_CMDS_OBJ_VEL		0x0014
+
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	signed short				enable;
+	unsigned short				command_type;
+	unsigned short				num_commands;
+	unsigned short				commands;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_qafx;
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (Common)
+ */
+
+#define AUDPP_CMD_REVERB_CONFIG		0x0001
+#define	AUDPP_CMD_REVERB_CONFIG_COMMON_LEN	\
+	sizeof(audpp_cmd_reverb_config_common)
+
+#define AUDPP_CMD_ENA_ENA	0xFFFF
+#define AUDPP_CMD_ENA_DIS	0x0000
+#define AUDPP_CMD_ENA_CFG	0x0001
+
+#define AUDPP_CMD_CMD_TYPE_ENV		0x0104
+#define AUDPP_CMD_CMD_TYPE_OBJ		0x0015
+#define AUDPP_CMD_CMD_TYPE_QUERY	0x1000
+
+
+typedef struct {
+	unsigned short			cmd_id;
+	unsigned short			enable;
+	unsigned short			cmd_type;
+} __attribute__((packed)) audpp_cmd_reverb_config_common;
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (ENV-0x0104)
+ */
+
+#define	AUDPP_CMD_REVERB_CONFIG_ENV_104_LEN	\
+	sizeof(audpp_cmd_reverb_config_env_104)
+
+typedef struct {
+	audpp_cmd_reverb_config_common	common;
+	unsigned short			env_gain;
+	unsigned short			decay_msw;
+	unsigned short			decay_lsw;
+	unsigned short			decay_timeratio_msw;
+	unsigned short			decay_timeratio_lsw;
+	unsigned short			delay_time;
+	unsigned short			reverb_gain;
+	unsigned short			reverb_delay;
+} __attribute__((packed)) audpp_cmd_reverb_config_env_104;
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (ENV-0x0015)
+ */
+
+#define	AUDPP_CMD_REVERB_CONFIG_ENV_15_LEN	\
+	sizeof(audpp_cmd_reverb_config_env_15)
+
+typedef struct {
+	audpp_cmd_reverb_config_common	common;
+	unsigned short			object_num;
+	unsigned short			absolute_gain;
+} __attribute__((packed)) audpp_cmd_reverb_config_env_15;
+
+
+#endif /* QDSP5AUDPPCMDI_H */
+
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h
new file mode 100644
index 0000000..e229df3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h
@@ -0,0 +1,318 @@
+#ifndef QDSP5AUDPPMSG_H
+#define QDSP5AUDPPMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+       Q D S P 5  A U D I O   P O S T   P R O C E S S I N G   M S G
+
+GENERAL DESCRIPTION
+  Messages sent by AUDPPTASK to ARM
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2009 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audppmsg.h#4 $
+
+===========================================================================*/
+
+/*
+ * AUDPPTASK uses audPPuPRlist to send messages to the ARM
+ * Location : MEMA
+ * Buffer Size : 45
+ * No of Buffers in a queue : 5 for gaming audio and 1 for other images
+ */
+
+/*
+ * MSG to Informs the ARM os Success/Failure of bringing up the decoder
+ */
+
+#define AUDPP_MSG_STATUS_MSG		0x0001
+#define AUDPP_MSG_STATUS_MSG_LEN	\
+	sizeof(audpp_msg_status_msg)
+
+#define AUDPP_MSG_STATUS_SLEEP		0x0000
+#define AUDPP_MSG__STATUS_INIT		0x0001
+#define AUDPP_MSG_MSG_STATUS_CFG	0x0002
+#define AUDPP_MSG_STATUS_PLAY		0x0003
+
+#define AUDPP_MSG_REASON_MIPS	0x0000
+#define AUDPP_MSG_REASON_MEM	0x0001
+
+typedef struct{
+	unsigned short dec_id;
+	unsigned short status;
+	unsigned short reason;
+} __attribute__((packed)) audpp_msg_status_msg;
+
+/*
+ * MSG to communicate the spectrum analyzer output bands to the ARM
+ */
+#define AUDPP_MSG_SPA_BANDS		0x0002
+#define AUDPP_MSG_SPA_BANDS_LEN	\
+	sizeof(audpp_msg_spa_bands)
+
+typedef struct {
+	unsigned short			current_object;
+	unsigned short			spa_band_1;
+	unsigned short			spa_band_2;
+	unsigned short			spa_band_3;
+	unsigned short			spa_band_4;
+	unsigned short			spa_band_5;
+	unsigned short			spa_band_6;
+	unsigned short			spa_band_7;
+	unsigned short			spa_band_8;
+	unsigned short			spa_band_9;
+	unsigned short			spa_band_10;
+	unsigned short			spa_band_11;
+	unsigned short			spa_band_12;
+	unsigned short			spa_band_13;
+	unsigned short			spa_band_14;
+	unsigned short			spa_band_15;
+	unsigned short			spa_band_16;
+	unsigned short			spa_band_17;
+	unsigned short			spa_band_18;
+	unsigned short			spa_band_19;
+	unsigned short			spa_band_20;
+	unsigned short			spa_band_21;
+	unsigned short			spa_band_22;
+	unsigned short			spa_band_23;
+	unsigned short			spa_band_24;
+	unsigned short			spa_band_25;
+	unsigned short			spa_band_26;
+	unsigned short			spa_band_27;
+	unsigned short			spa_band_28;
+	unsigned short			spa_band_29;
+	unsigned short			spa_band_30;
+	unsigned short			spa_band_31;
+	unsigned short			spa_band_32;
+} __attribute__((packed)) audpp_msg_spa_bands;
+
+/*
+ * MSG to communicate the PCM I/O buffer status to ARM
+ */
+#define  AUDPP_MSG_HOST_PCM_INTF_MSG		0x0003
+#define  AUDPP_MSG_HOST_PCM_INTF_MSG_LEN	\
+	sizeof(audpp_msg_host_pcm_intf_msg)
+
+#define AUDPP_MSG_HOSTPCM_ID_TX_ARM	0x0000
+#define AUDPP_MSG_HOSTPCM_ID_ARM_TX	0x0001
+#define AUDPP_MSG_HOSTPCM_ID_RX_ARM	0x0002
+#define AUDPP_MSG_HOSTPCM_ID_ARM_RX	0x0003
+
+#define AUDPP_MSG_SAMP_FREQ_INDX_96000	0x0000
+#define AUDPP_MSG_SAMP_FREQ_INDX_88200	0x0001
+#define AUDPP_MSG_SAMP_FREQ_INDX_64000	0x0002
+#define AUDPP_MSG_SAMP_FREQ_INDX_48000	0x0003
+#define AUDPP_MSG_SAMP_FREQ_INDX_44100	0x0004
+#define AUDPP_MSG_SAMP_FREQ_INDX_32000	0x0005
+#define AUDPP_MSG_SAMP_FREQ_INDX_24000	0x0006
+#define AUDPP_MSG_SAMP_FREQ_INDX_22050	0x0007
+#define AUDPP_MSG_SAMP_FREQ_INDX_16000	0x0008
+#define AUDPP_MSG_SAMP_FREQ_INDX_12000	0x0009
+#define AUDPP_MSG_SAMP_FREQ_INDX_11025	0x000A
+#define AUDPP_MSG_SAMP_FREQ_INDX_8000	0x000B
+
+#define AUDPP_MSG_CHANNEL_MODE_MONO		0x0001
+#define AUDPP_MSG_CHANNEL_MODE_STEREO	0x0002
+
+typedef struct{
+	unsigned short obj_num;
+	unsigned short numbers_of_samples;
+	unsigned short host_pcm_id;
+	unsigned short buf_indx;
+	unsigned short samp_freq_indx;
+	unsigned short channel_mode;
+} __attribute__((packed)) audpp_msg_host_pcm_intf_msg;
+
+
+/*
+ * MSG to communicate 3D position of the source and listener , source volume
+ * source rolloff, source orientation
+ */
+
+#define AUDPP_MSG_QAFX_POS		0x0004
+#define AUDPP_MSG_QAFX_POS_LEN		\
+	sizeof(audpp_msg_qafx_pos)
+
+typedef struct {
+	unsigned short	current_object;
+	unsigned short	x_pos_lis_msw;
+	unsigned short	x_pos_lis_lsw;
+	unsigned short	y_pos_lis_msw;
+	unsigned short	y_pos_lis_lsw;
+	unsigned short	z_pos_lis_msw;
+	unsigned short	z_pos_lis_lsw;
+	unsigned short	x_fwd_msw;
+	unsigned short	x_fwd_lsw;
+	unsigned short	y_fwd_msw;
+	unsigned short	y_fwd_lsw;
+	unsigned short	z_fwd_msw;
+	unsigned short	z_fwd_lsw;
+	unsigned short 	x_up_msw;
+	unsigned short	x_up_lsw;
+	unsigned short 	y_up_msw;
+	unsigned short	y_up_lsw;
+	unsigned short 	z_up_msw;
+	unsigned short	z_up_lsw;
+	unsigned short 	x_vel_lis_msw;
+	unsigned short 	x_vel_lis_lsw;
+	unsigned short 	y_vel_lis_msw;
+	unsigned short 	y_vel_lis_lsw;
+	unsigned short 	z_vel_lis_msw;
+	unsigned short 	z_vel_lis_lsw;
+	unsigned short	threed_enable_flag;
+	unsigned short 	volume;
+	unsigned short	x_pos_source_msw;
+	unsigned short	x_pos_source_lsw;
+	unsigned short	y_pos_source_msw;
+	unsigned short	y_pos_source_lsw;
+	unsigned short	z_pos_source_msw;
+	unsigned short	z_pos_source_lsw;
+	unsigned short	max_dist_0_msw;
+	unsigned short	max_dist_0_lsw;
+	unsigned short	min_dist_0_msw;
+	unsigned short	min_dist_0_lsw;
+	unsigned short	roll_off_factor;
+	unsigned short	mute_after_max_flag;
+	unsigned short	x_vel_source_msw;
+	unsigned short	x_vel_source_lsw;
+	unsigned short	y_vel_source_msw;
+	unsigned short	y_vel_source_lsw;
+	unsigned short	z_vel_source_msw;
+	unsigned short	z_vel_source_lsw;
+} __attribute__((packed)) audpp_msg_qafx_pos;
+
+/*
+ * MSG to provide AVSYNC feedback from DSP to ARM
+ */
+
+#define AUDPP_MSG_AVSYNC_MSG		0x0005
+#define AUDPP_MSG_AVSYNC_MSG_LEN	\
+	sizeof(audpp_msg_avsync_msg)
+
+typedef struct {
+	unsigned short	active_flag;
+	unsigned short	num_samples_counter0_HSW;
+	unsigned short	num_samples_counter0_MSW;
+	unsigned short	num_samples_counter0_LSW;
+	unsigned short	num_bytes_counter0_HSW;
+	unsigned short	num_bytes_counter0_MSW;
+	unsigned short	num_bytes_counter0_LSW;
+	unsigned short	samp_freq_obj_0;
+	unsigned short	samp_freq_obj_1;
+	unsigned short	samp_freq_obj_2;
+	unsigned short	samp_freq_obj_3;
+	unsigned short	samp_freq_obj_4;
+	unsigned short	samp_freq_obj_5;
+	unsigned short	samp_freq_obj_6;
+	unsigned short	samp_freq_obj_7;
+	unsigned short	samp_freq_obj_8;
+	unsigned short	samp_freq_obj_9;
+	unsigned short	samp_freq_obj_10;
+	unsigned short	samp_freq_obj_11;
+	unsigned short	samp_freq_obj_12;
+	unsigned short	samp_freq_obj_13;
+	unsigned short	samp_freq_obj_14;
+	unsigned short	samp_freq_obj_15;
+	unsigned short	num_samples_counter4_HSW;
+	unsigned short	num_samples_counter4_MSW;
+	unsigned short	num_samples_counter4_LSW;
+	unsigned short	num_bytes_counter4_HSW;
+	unsigned short	num_bytes_counter4_MSW;
+	unsigned short	num_bytes_counter4_LSW;
+} __attribute__((packed)) audpp_msg_avsync_msg;
+
+/*
+ * MSG to provide PCM DMA Missed feedback from the DSP to ARM
+ */
+
+#define  AUDPP_MSG_PCMDMAMISSED	0x0006
+#define  AUDPP_MSG_PCMDMAMISSED_LEN	\
+	sizeof(audpp_msg_pcmdmamissed);
+
+typedef struct{
+	/*
+	** Bit 0	0 = PCM DMA not missed for object 0
+	**        1 = PCM DMA missed for object0
+	** Bit 1	0 = PCM DMA not missed for object 1
+	**        1 = PCM DMA missed for object1
+	** Bit 2	0 = PCM DMA not missed for object 2
+	**        1 = PCM DMA missed for object2
+	** Bit 3	0 = PCM DMA not missed for object 3
+	**        1 = PCM DMA missed for object3
+	** Bit 4	0 = PCM DMA not missed for object 4
+	**        1 = PCM DMA missed for object4
+	*/
+	unsigned short pcmdmamissed;
+} __attribute__((packed)) audpp_msg_pcmdmamissed;
+
+/*
+ * MSG to AUDPP enable or disable feedback form DSP to ARM
+ */
+
+#define AUDPP_MSG_CFG_MSG	0x0007  
+#define AUDPP_MSG_CFG_MSG_LEN	\
+    sizeof(audpp_msg_cfg_msg)
+
+#define AUDPP_MSG_ENA_ENA	0xFFFF
+#define AUDPP_MSG_ENA_DIS	0x0000
+
+typedef struct{
+	/*   Enabled  - 0xffff 
+	**  Disabled - 0
+	*/
+	unsigned short enabled;
+} __attribute__((packed)) audpp_msg_cfg_msg;
+
+/*
+ * MSG to communicate the reverb  per object volume
+ */
+
+#define AUDPP_MSG_QREVERB_VOLUME	0x0008
+#define AUDPP_MSG_QREVERB_VOLUME_LEN	\
+	sizeof(audpp_msg_qreverb_volume)
+
+
+typedef struct {
+	unsigned short	obj_0_gain;
+	unsigned short	obj_1_gain;
+	unsigned short	obj_2_gain;
+	unsigned short	obj_3_gain;
+	unsigned short	obj_4_gain;
+	unsigned short	hpcm_obj_volume;
+} __attribute__((packed)) audpp_msg_qreverb_volume;
+
+#define AUDPP_MSG_ROUTING_ACK 0x0009
+#define AUDPP_MSG_ROUTING_ACK_LEN \
+  sizeof(struct audpp_msg_routing_ack)
+
+struct audpp_msg_routing_ack {
+	unsigned short dec_id;
+	unsigned short routing_mode;
+} __attribute__((packed));
+
+#define AUDPP_MSG_FLUSH_ACK 0x000A
+
+#endif /* QDSP5AUDPPMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h
new file mode 100644
index 0000000..cd9d5906
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h
@@ -0,0 +1,256 @@
+#ifndef QDSP5AUDPREPROCCMDI_H
+#define QDSP5AUDPREPROCCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    A U D I O   P R E   P R O C E S S I N G  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by AUDPREPROC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audpreproccmdi.h#2 $
+  
+===========================================================================*/
+
+/*
+ * AUDIOPREPROC COMMANDS:
+ * ARM uses uPAudPreProcCmdQueue to communicate with AUDPREPROCTASK
+ * Location : MEMB
+ * Buffer size : 51
+ * Number of buffers in a queue : 3
+ */
+
+/*
+ * Command to configure the parameters of AGC
+ */
+
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS	0x0000
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS_LEN	\
+	sizeof(audpreproc_cmd_cfg_agc_params)
+
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_SLOPE	0x0009
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_TH	0x000A
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_SLOPE	0x000B
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_TH		0x000C
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_AIG_FLAG		0x000D
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_STATIC_GAIN	0x000E
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG	0x000F
+
+#define	AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA	-1
+#define	AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS	0x0000
+
+#define	AUDPREPROC_CMD_ADP_GAIN_FLAG_ENA_ADP_GAIN	-1
+#define	AUDPREPROC_CMD_ADP_GAIN_FLAG_ENA_STATIC_GAIN	0x0000
+
+#define	AUDPREPROC_CMD_PARAM_MASK_RMS_TAY	0x0004
+#define	AUDPREPROC_CMD_PARAM_MASK_RELEASEK	0x0005
+#define	AUDPREPROC_CMD_PARAM_MASK_DELAY		0x0006
+#define	AUDPREPROC_CMD_PARAM_MASK_ATTACKK	0x0007
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_SLOW	0x0008
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_FAST	0x0009
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_RELEASEK 	0x000A
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_MIN	0x000B
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_MAX	0x000C
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAK_UP	0x000D
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAK_DOWN	0x000E
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_ATTACKK	0x000F
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	tx_agc_param_mask;
+	unsigned short	tx_agc_enable_flag;
+	unsigned short	static_gain;
+	signed short	adaptive_gain_flag;
+	unsigned short	expander_th;
+	unsigned short	expander_slope;
+	unsigned short	compressor_th;
+	unsigned short	compressor_slope;
+	unsigned short	param_mask;
+	unsigned short	aig_attackk;
+	unsigned short	aig_leak_down;
+	unsigned short	aig_leak_up;
+	unsigned short	aig_max;
+	unsigned short	aig_min;
+	unsigned short	aig_releasek;
+	unsigned short	aig_leakrate_fast;
+	unsigned short	aig_leakrate_slow;
+	unsigned short	attackk_msw;
+	unsigned short	attackk_lsw;
+	unsigned short	delay;
+	unsigned short	releasek_msw;
+	unsigned short	releasek_lsw;
+	unsigned short	rms_tav;
+} __attribute__((packed)) audpreproc_cmd_cfg_agc_params;
+
+
+/*
+ * Command to configure the params of Advanved AGC
+ */
+
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS_2		0x0001
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS_2_LEN		\
+	sizeof(audpreproc_cmd_cfg_agc_params_2)
+
+#define	AUDPREPROC_CMD_2_TX_AGC_ENA_FLAG_ENA	-1;
+#define	AUDPREPROC_CMD_2_TX_AGC_ENA_FLAG_DIS	0x0000;
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	agc_param_mask;
+	signed short	tx_agc_enable_flag;
+	unsigned short	comp_static_gain;
+	unsigned short	exp_th;
+	unsigned short	exp_slope;
+	unsigned short	comp_th;
+	unsigned short	comp_slope;
+	unsigned short	comp_rms_tav;
+	unsigned short	comp_samp_mask;
+	unsigned short	comp_attackk_msw;
+	unsigned short	comp_attackk_lsw;
+	unsigned short	comp_releasek_msw;
+	unsigned short	comp_releasek_lsw;
+	unsigned short	comp_delay;
+	unsigned short	comp_makeup_gain;
+} __attribute__((packed)) audpreproc_cmd_cfg_agc_params_2;
+
+/*
+ * Command to configure params for ns
+ */
+
+#define	AUDPREPROC_CMD_CFG_NS_PARAMS		0x0002
+#define	AUDPREPROC_CMD_CFG_NS_PARAMS_LEN	\
+	sizeof(audpreproc_cmd_cfg_ns_params)
+
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLMS_ENA	0x0001
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLMS_DIS 	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_DES_ENA	0x0002
+#define	AUDPREPROC_CMD_EC_MODE_NEW_DES_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NS_ENA	0x0004
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NS_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_CNI_ENA	0x0008
+#define	AUDPREPROC_CMD_EC_MODE_NEW_CNI_DIS	0x0000
+
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLES_ENA	0x0010
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLES_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_HB_ENA	0x0020
+#define	AUDPREPROC_CMD_EC_MODE_NEW_HB_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_VA_ENA	0x0040
+#define	AUDPREPROC_CMD_EC_MODE_NEW_VA_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_PCD_ENA	0x0080
+#define	AUDPREPROC_CMD_EC_MODE_NEW_PCD_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_FEHI_ENA	0x0100
+#define	AUDPREPROC_CMD_EC_MODE_NEW_FEHI_DIS 	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NEHI_ENA	0x0200
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NEHI_DIS 	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLPP_ENA	0x0400
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLPP_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_FNE_ENA	0x0800
+#define	AUDPREPROC_CMD_EC_MODE_NEW_FNE_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_ENA 	0x1000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_DIS 	0x0000
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	ec_mode_new;
+	unsigned short	dens_gamma_n;
+	unsigned short	dens_nfe_block_size;
+	unsigned short	dens_limit_ns;
+	unsigned short	dens_limit_ns_d;
+	unsigned short	wb_gamma_e;
+	unsigned short	wb_gamma_n;
+} __attribute__((packed)) audpreproc_cmd_cfg_ns_params;
+
+/*
+ * Command to configure parameters for IIR tuning filter
+ */
+
+#define	AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS		0x0003
+#define	AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS_LEN	\
+	sizeof(audpreproc_cmd_cfg_iir_tuning_filter_params)
+
+#define	AUDPREPROC_CMD_IIR_ACTIVE_FLAG_DIS	0x0000
+#define	AUDPREPROC_CMD_IIR_ACTIVE_FLAG_ENA	0x0001
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	active_flag;
+	unsigned short	num_bands;
+	unsigned short	numerator_coeff_b0_filter0_lsw;
+	unsigned short	numerator_coeff_b0_filter0_msw;
+	unsigned short	numerator_coeff_b1_filter0_lsw;
+	unsigned short	numerator_coeff_b1_filter0_msw;
+	unsigned short	numerator_coeff_b2_filter0_lsw;
+	unsigned short	numerator_coeff_b2_filter0_msw;
+	unsigned short	numerator_coeff_b0_filter1_lsw;
+	unsigned short	numerator_coeff_b0_filter1_msw;
+	unsigned short	numerator_coeff_b1_filter1_lsw;
+	unsigned short	numerator_coeff_b1_filter1_msw;
+	unsigned short	numerator_coeff_b2_filter1_lsw;
+	unsigned short	numerator_coeff_b2_filter1_msw;
+	unsigned short	numerator_coeff_b0_filter2_lsw;
+	unsigned short	numerator_coeff_b0_filter2_msw;
+	unsigned short	numerator_coeff_b1_filter2_lsw;
+	unsigned short	numerator_coeff_b1_filter2_msw;
+	unsigned short	numerator_coeff_b2_filter2_lsw;
+	unsigned short	numerator_coeff_b2_filter2_msw;
+	unsigned short	numerator_coeff_b0_filter3_lsw;
+	unsigned short	numerator_coeff_b0_filter3_msw;
+	unsigned short	numerator_coeff_b1_filter3_lsw;
+	unsigned short	numerator_coeff_b1_filter3_msw;
+	unsigned short	numerator_coeff_b2_filter3_lsw;
+	unsigned short	numerator_coeff_b2_filter3_msw;
+	unsigned short 	denominator_coeff_a0_filter0_lsw;
+	unsigned short 	denominator_coeff_a0_filter0_msw;
+	unsigned short 	denominator_coeff_a1_filter0_lsw;
+	unsigned short 	denominator_coeff_a1_filter0_msw; 
+	unsigned short 	denominator_coeff_a0_filter1_lsw;
+	unsigned short 	denominator_coeff_a0_filter1_msw;
+	unsigned short 	denominator_coeff_a1_filter1_lsw;
+	unsigned short 	denominator_coeff_a1_filter1_msw;
+  unsigned short 	denominator_coeff_a0_filter2_lsw;
+	unsigned short 	denominator_coeff_a0_filter2_msw;
+	unsigned short 	denominator_coeff_a1_filter2_lsw;
+	unsigned short 	denominator_coeff_a1_filter2_msw;
+  unsigned short 	denominator_coeff_a0_filter3_lsw;
+	unsigned short 	denominator_coeff_a0_filter3_msw;
+	unsigned short 	denominator_coeff_a1_filter3_lsw;
+	unsigned short 	denominator_coeff_a1_filter3_msw;
+
+	unsigned short	shift_factor_filter0;
+	unsigned short	shift_factor_filter1;
+	unsigned short	shift_factor_filter2;
+	unsigned short	shift_factor_filter3;
+
+	unsigned short	channel_selected0;
+	unsigned short	channel_selected1;
+	unsigned short	channel_selected2;
+	unsigned short	channel_selected3;
+} __attribute__((packed))audpreproc_cmd_cfg_iir_tuning_filter_params;
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h
new file mode 100644
index 0000000..9187f45
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h
@@ -0,0 +1,85 @@
+#ifndef QDSP5AUDPREPROCMSG_H
+#define QDSP5AUDPREPROCMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    A U D I O   P R E   P R O C E S S I N G  M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of messages
+  that are rcvd by AUDPREPROC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audpreprocmsg.h#3 $
+  
+===========================================================================*/
+
+/*
+ * ADSPREPROCTASK Messages
+ * AUDPREPROCTASK uses audPreProcUpRlist to communicate with ARM
+ * Location	: MEMA
+ * Message Length  : 2
+ */
+
+/*
+ * Message to indicate particular feature has been enabled or disabled
+ */
+
+
+#define	AUDPREPROC_MSG_CMD_CFG_DONE_MSG	0x0000
+#define	AUDPREPROC_MSG_CMD_CFG_DONE_MSG_LEN	\
+	sizeof(audpreproc_msg_cmd_cfg_done_msg)
+
+#define	AUDPREPROC_MSG_TYPE_AGC			0x0000
+#define	AUDPREPROC_MSG_TYPE_NOISE_REDUCTION	0x0001
+#define	AUDPREPROC_MSG_TYPE_IIR_FILTER		0x0002
+
+
+#define	AUDPREPROC_MSG_STATUS_FLAG_ENA		-1
+#define	AUDPREPROC_MSG_STATUS_FLAG_DIS		0x0000
+
+typedef struct {
+	unsigned short	type;
+	signed short	status_flag;
+} __attribute__((packed)) audpreproc_msg_cmd_cfg_done_msg;
+
+
+/*
+ * Message to indicate particular feature has selected for wrong samp freq
+ */
+
+#define	AUDPREPROC_MSG_ERROR_MSG_ID		0x0001
+#define	AUDPREPROC_MSG_ERROR_MSG_ID_LEN	\
+	sizeof(audpreproc_msg_error_msg_id)
+
+#define	AUDPREPROC_MSG_ERR_INDEX_NS		0x0000
+
+typedef struct {
+	 unsigned short	err_index;
+} __attribute__((packed)) audpreproc_msg_error_msg_id;
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audreccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audreccmdi.h
new file mode 100644
index 0000000..e88bd5d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audreccmdi.h
@@ -0,0 +1,176 @@
+#ifndef QDSP5AUDRECCMDI_H
+#define QDSP5AUDRECCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    A U D I O   R E C O R D  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by AUDREC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audreccmdi.h#3 $
+
+============================================================================*/
+
+/*
+ * AUDRECTASK COMMANDS
+ * ARM uses 2 queues to communicate with the AUDRECTASK
+ * 1.uPAudRecCmdQueue
+ * Location :MEMC
+ * Buffer Size : 8
+ * No of Buffers in a queue : 3
+ * 2.audRecUpBitStreamQueue
+ * Location : MEMC
+ * Buffer Size : 4
+ * No of buffers in a queue : 2
+ */
+
+/*
+ * Commands on uPAudRecCmdQueue
+ */
+
+/*
+ * Command to initiate and terminate the audio recording section
+ */
+
+#define AUDREC_CMD_CFG		0x0000
+#define	AUDREC_CMD_CFG_LEN	sizeof(audrec_cmd_cfg)
+
+#define	AUDREC_CMD_TYPE_0_INDEX_WAV	0x0000
+#define	AUDREC_CMD_TYPE_0_INDEX_AAC	0x0001
+
+#define AUDREC_CMD_TYPE_0_ENA		0x4000
+#define AUDREC_CMD_TYPE_0_DIS		0x0000
+
+#define AUDREC_CMD_TYPE_0_NOUPDATE	0x0000
+#define AUDREC_CMD_TYPE_0_UPDATE	0x8000
+
+#define	AUDREC_CMD_TYPE_1_INDEX_SBC	0x0002
+
+#define AUDREC_CMD_TYPE_1_ENA		0x4000
+#define AUDREC_CMD_TYPE_1_DIS		0x0000
+
+#define AUDREC_CMD_TYPE_1_NOUPDATE	0x0000
+#define AUDREC_CMD_TYPE_1_UPDATE	0x8000
+
+typedef struct {
+	unsigned short 	cmd_id;
+	unsigned short	type_0;
+	unsigned short	type_1;
+} __attribute__((packed)) audrec_cmd_cfg;
+
+
+/*
+ * Command to configure the recording parameters for RecType0(AAC/WAV) encoder
+ */
+
+#define	AUDREC_CMD_AREC0PARAM_CFG	0x0001
+#define	AUDREC_CMD_AREC0PARAM_CFG_LEN	\
+	sizeof(audrec_cmd_arec0param_cfg)
+
+#define	AUDREC_CMD_SAMP_RATE_INDX_8000		0x000B
+#define	AUDREC_CMD_SAMP_RATE_INDX_11025		0x000A
+#define	AUDREC_CMD_SAMP_RATE_INDX_12000		0x0009
+#define	AUDREC_CMD_SAMP_RATE_INDX_16000		0x0008
+#define	AUDREC_CMD_SAMP_RATE_INDX_22050		0x0007
+#define	AUDREC_CMD_SAMP_RATE_INDX_24000		0x0006
+#define	AUDREC_CMD_SAMP_RATE_INDX_32000		0x0005
+#define	AUDREC_CMD_SAMP_RATE_INDX_44100		0x0004
+#define	AUDREC_CMD_SAMP_RATE_INDX_48000		0x0003
+
+#define AUDREC_CMD_STEREO_MODE_MONO		0x0000
+#define AUDREC_CMD_STEREO_MODE_STEREO		0x0001
+
+typedef struct {
+	unsigned short 	cmd_id;
+	unsigned short	ptr_to_extpkt_buffer_msw;
+	unsigned short	ptr_to_extpkt_buffer_lsw;
+	unsigned short	buf_len;
+	unsigned short	samp_rate_index;
+	unsigned short	stereo_mode;
+	unsigned short 	rec_quality;
+} __attribute__((packed)) audrec_cmd_arec0param_cfg;
+
+/*
+ * Command to configure the recording parameters for RecType1(SBC) encoder
+ */
+
+#define AUDREC_CMD_AREC1PARAM_CFG	0x0002
+#define AUDREC_CMD_AREC1PARAM_CFG_LEN	\
+	sizeof(audrec_cmd_arec1param_cfg)
+
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_4	0x0000
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_8	0x0001
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_12	0x0002
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_16	0x0003
+
+#define AUDREC_CMD_PARAM_BUF_SUB_BANDS_8	0x0010
+#define AUDREC_CMD_PARAM_BUF_MODE_MONO		0x0000
+#define AUDREC_CMD_PARAM_BUF_MODE_DUAL		0x0040
+#define AUDREC_CMD_PARAM_BUF_MODE_STEREO	0x0050
+#define AUDREC_CMD_PARAM_BUF_MODE_JSTEREO	0x0060
+#define AUDREC_CMD_PARAM_BUF_LOUDNESS		0x0000
+#define AUDREC_CMD_PARAM_BUF_SNR		0x0100
+#define AUDREC_CMD_PARAM_BUF_BASIC_VER		0x0000
+
+typedef struct {
+	unsigned short 	cmd_id;
+	unsigned short	ptr_to_extpkt_buffer_msw;
+	unsigned short	ptr_to_extpkt_buffer_lsw;
+	unsigned short	buf_len;
+	unsigned short	param_buf;
+	unsigned short	bit_rate_0;
+	unsigned short	bit_rate_1;
+} __attribute__((packed)) audrec_cmd_arec1param_cfg;
+
+
+/*
+ * Commands on audRecUpBitStreamQueue 
+ */
+
+/*
+ * Command to indicate the current packet read count
+ */
+
+#define AUDREC_CMD_PACKET_EXT_PTR		0x0000
+#define AUDREC_CMD_PACKET_EXT_PTR_LEN	\
+	sizeof(audrec_cmd_packet_ext_ptr)
+
+#define AUDREC_CMD_TYPE_0	0x0000
+#define AUDREC_CMD_TYPE_1	0x0001
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short	type;
+	unsigned short 	curr_rec_count_msw;
+	unsigned short 	curr_rec_count_lsw;
+} __attribute__((packed)) audrec_cmd_packet_ext_ptr;
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audrecmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audrecmsg.h
new file mode 100644
index 0000000..bb6eb50
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audrecmsg.h
@@ -0,0 +1,127 @@
+#ifndef QDSP5AUDRECMSGI_H
+#define QDSP5AUDRECMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    A U D I O   R E C O R D  M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of messages
+  that are sent by AUDREC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audrecmsg.h#3 $
+
+============================================================================*/
+
+/*
+ * AUDRECTASK MESSAGES
+ * AUDRECTASK uses audRecUpRlist to communicate with ARM
+ * Location : MEMC
+ * Buffer size : 4
+ * No of buffers in a queue : 2
+ */
+
+/*
+ * Message to notify that config command is done
+ */
+
+#define AUDREC_MSG_CMD_CFG_DONE_MSG	0x0002
+#define AUDREC_MSG_CMD_CFG_DONE_MSG_LEN	\
+	sizeof(audrec_msg_cmd_cfg_done_msg)
+
+
+#define AUDREC_MSG_CFG_DONE_TYPE_0_ENA		0x4000
+#define AUDREC_MSG_CFG_DONE_TYPE_0_DIS		0x0000
+
+#define AUDREC_MSG_CFG_DONE_TYPE_0_NO_UPDATE	0x0000
+#define AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE	0x8000
+
+#define AUDREC_MSG_CFG_DONE_TYPE_1_ENA		0x4000
+#define AUDREC_MSG_CFG_DONE_TYPE_1_DIS		0x0000
+
+#define AUDREC_MSG_CFG_DONE_TYPE_1_NO_UPDATE	0x0000
+#define AUDREC_MSG_CFG_DONE_TYPE_1_UPDATE	0x8000
+
+typedef struct {
+	unsigned short	type_0;
+	unsigned short	type_1;
+} __attribute__((packed))audrec_msg_cmd_cfg_done_msg;
+
+
+/*
+ * Message to notify arec0/1 cfg done and recording params revd by task
+ */
+
+#define	AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG		0x0003
+#define	AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG_LEN	\
+	sizeof(audrec_msg_cmd_arec_param_cfg_done_msg)
+
+#define	AUDREC_MSG_AREC_PARAM_TYPE_0	0x0000
+#define	AUDREC_MSG_AREC_PARAM_TYPE_1	0x0001
+
+typedef struct {
+	unsigned short	type;
+} __attribute__((packed))audrec_msg_cmd_arec_param_cfg_done_msg;
+
+
+/*
+ * Message to notify no more buffers are available in ext mem to DME
+ */
+
+#define AUDREC_MSG_FATAL_ERR_MSG		0x0004
+#define AUDREC_MSG_FATAL_ERR_MSG_LEN	\
+	sizeof(audrec_msg_fatal_err_msg)
+
+#define AUDREC_MSG_FATAL_ERR_TYPE_0	0x0000
+#define AUDREC_MSG_FATAL_ERR_TYPE_1	0x0001
+
+typedef struct {
+	unsigned short	type;
+} __attribute__((packed))audrec_msg_fatal_err_msg;
+
+/*
+ * Message to notify DME deliverd the encoded pkt to ext pkt buffer
+ */
+
+#define AUDREC_MSG_PACKET_READY_MSG		0x0005
+#define AUDREC_MSG_PACKET_READY_MSG_LEN	\
+	sizeof(audrec_msg_packet_ready_msg)
+
+#define AUDREC_MSG_PACKET_READY_TYPE_0	0x0000
+#define AUDREC_MSG_PACKET_READY_TYPE_1	0x0001
+
+typedef struct {
+	unsigned short	type;
+	unsigned short	pkt_counter_msw;
+	unsigned short	pkt_counter_lsw;
+	unsigned short	pkt_read_cnt_msw;
+	unsigned short	pkt_read_cnt_lsw;
+} __attribute__((packed))audrec_msg_packet_ready_msg;
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegcmdi.h
new file mode 100644
index 0000000..d8170f0
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegcmdi.h
@@ -0,0 +1,376 @@
+#ifndef QDSP5VIDJPEGCMDI_H
+#define QDSP5VIDJPEGCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    J P E G  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by JPEG Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5jpegcmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+06/09/08   sv      initial version
+===========================================================================*/
+
+/*
+ * ARM to JPEG configuration commands are passed through the
+ * uPJpegCfgCmdQueue
+ */
+
+/*
+ * Command to configure JPEG Encoder
+ */
+
+#define	JPEG_CMD_ENC_CFG		0x0000
+#define	JPEG_CMD_ENC_CFG_LEN	sizeof(jpeg_cmd_enc_cfg)
+
+#define	JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_0		0x0000
+#define	JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_90		0x0100
+#define	JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_180	0x0200
+#define	JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_270	0x0300
+#define	JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_M	0x0003
+#define	JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V2	0x0000
+#define	JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V1	0x0001
+#define	JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H1V2	0x0002
+
+#define	JPEG_CMD_IP_SIZE_CFG_LUMA_HEIGHT_M		0x0000FFFF
+#define	JPEG_CMD_IP_SIZE_CFG_LUMA_WIDTH_M		0xFFFF0000
+#define	JPEG_CMD_ENC_UPSAMP_IP_SIZE_CFG_ENA		0x0001
+#define	JPEG_CMD_ENC_UPSAMP_IP_SIZE_CFG_DIS		0x0000
+
+#define	JPEG_CMD_FRAG_SIZE_LUMA_HEIGHT_M		0xFFFF
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	process_cfg;
+	unsigned int	ip_size_cfg;
+	unsigned int	op_size_cfg;
+	unsigned int	frag_cfg;
+	unsigned int	frag_cfg_part[16];
+
+	unsigned int    part_num;
+
+	unsigned int	op_buf_0_cfg_part1;
+	unsigned int	op_buf_0_cfg_part2;
+	unsigned int	op_buf_1_cfg_part1;
+	unsigned int	op_buf_1_cfg_part2;
+
+	unsigned int	luma_qunt_table[32];
+	unsigned int	chroma_qunt_table[32];
+
+	unsigned int	upsamp_ip_size_cfg;
+	unsigned int	upsamp_ip_frame_off;
+	unsigned int	upsamp_pp_filter_coeff[64];
+} __attribute__((packed)) jpeg_cmd_enc_cfg;
+
+/*
+ * Command to configure JPEG Decoder
+ */
+
+#define	JPEG_CMD_DEC_CFG		0x0001
+#define	JPEG_CMD_DEC_CFG_LEN		sizeof(jpeg_cmd_dec_cfg)
+
+#define	JPEG_CMD_DEC_OP_DATA_FORMAT_M		0x0001
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_H2V2	0x0000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_H2V1	0x0001
+
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_8	0x000000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_4	0x010000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_2	0x020000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_1	0x030000
+
+#define	JPEG_CMD_DEC_IP_STREAM_BUF_CFG_PART3_NOT_FINAL	0x0000
+#define	JPEG_CMD_DEC_IP_STREAM_BUF_CFG_PART3_FINAL	0x0001
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	img_dimension_cfg;
+	unsigned int	op_data_format;
+	unsigned int	restart_interval;
+	unsigned int	ip_buf_partition_num;
+	unsigned int	ip_stream_buf_cfg_part1;
+	unsigned int	ip_stream_buf_cfg_part2;
+	unsigned int	ip_stream_buf_cfg_part3;
+	unsigned int	op_stream_buf_0_cfg_part1;
+	unsigned int	op_stream_buf_0_cfg_part2;
+	unsigned int	op_stream_buf_0_cfg_part3;
+	unsigned int	op_stream_buf_1_cfg_part1;
+	unsigned int	op_stream_buf_1_cfg_part2;
+	unsigned int	op_stream_buf_1_cfg_part3;
+	unsigned int	luma_qunt_table_0_3;
+	unsigned int	luma_qunt_table_4_7;
+	unsigned int	luma_qunt_table_8_11;
+	unsigned int	luma_qunt_table_12_15;
+	unsigned int	luma_qunt_table_16_19;
+	unsigned int	luma_qunt_table_20_23;
+	unsigned int	luma_qunt_table_24_27;
+	unsigned int	luma_qunt_table_28_31;
+	unsigned int	luma_qunt_table_32_35;
+	unsigned int	luma_qunt_table_36_39;
+	unsigned int	luma_qunt_table_40_43;
+	unsigned int	luma_qunt_table_44_47;
+	unsigned int	luma_qunt_table_48_51;
+	unsigned int	luma_qunt_table_52_55;
+	unsigned int	luma_qunt_table_56_59;
+	unsigned int	luma_qunt_table_60_63;
+	unsigned int	chroma_qunt_table_0_3;
+	unsigned int	chroma_qunt_table_4_7;
+	unsigned int	chroma_qunt_table_8_11;
+	unsigned int	chroma_qunt_table_12_15;
+	unsigned int	chroma_qunt_table_16_19;
+	unsigned int	chroma_qunt_table_20_23;
+	unsigned int	chroma_qunt_table_24_27;
+	unsigned int	chroma_qunt_table_28_31;
+	unsigned int	chroma_qunt_table_32_35;
+	unsigned int	chroma_qunt_table_36_39;
+	unsigned int	chroma_qunt_table_40_43;
+	unsigned int	chroma_qunt_table_44_47;
+	unsigned int	chroma_qunt_table_48_51;
+	unsigned int	chroma_qunt_table_52_55;
+	unsigned int	chroma_qunt_table_56_59;
+	unsigned int	chroma_qunt_table_60_63;
+	unsigned int	luma_dc_hm_code_cnt_table_0_3;
+	unsigned int	luma_dc_hm_code_cnt_table_4_7;
+	unsigned int	luma_dc_hm_code_cnt_table_8_11;
+	unsigned int	luma_dc_hm_code_cnt_table_12_15;
+	unsigned int	luma_dc_hm_code_val_table_0_3;
+	unsigned int	luma_dc_hm_code_val_table_4_7;
+	unsigned int	luma_dc_hm_code_val_table_8_11;
+	unsigned int	chroma_dc_hm_code_cnt_table_0_3;
+	unsigned int	chroma_dc_hm_code_cnt_table_4_7;
+	unsigned int	chroma_dc_hm_code_cnt_table_8_11;
+	unsigned int	chroma_dc_hm_code_cnt_table_12_15;
+	unsigned int	chroma_dc_hm_code_val_table_0_3;
+	unsigned int	chroma_dc_hm_code_val_table_4_7;
+	unsigned int	chroma_dc_hm_code_val_table_8_11;
+	unsigned int	luma_ac_hm_code_cnt_table_0_3;
+	unsigned int	luma_ac_hm_code_cnt_table_4_7;
+	unsigned int	luma_ac_hm_code_cnt_table_8_11;
+	unsigned int	luma_ac_hm_code_cnt_table_12_15;
+	unsigned int	luma_ac_hm_code_val_table_0_3;
+	unsigned int	luma_ac_hm_code_val_table_4_7;
+	unsigned int	luma_ac_hm_code_val_table_8_11;
+	unsigned int	luma_ac_hm_code_val_table_12_15;
+	unsigned int	luma_ac_hm_code_val_table_16_19;
+	unsigned int	luma_ac_hm_code_val_table_20_23;
+	unsigned int	luma_ac_hm_code_val_table_24_27;
+	unsigned int	luma_ac_hm_code_val_table_28_31;
+	unsigned int	luma_ac_hm_code_val_table_32_35;
+	unsigned int	luma_ac_hm_code_val_table_36_39;
+	unsigned int	luma_ac_hm_code_val_table_40_43;
+	unsigned int	luma_ac_hm_code_val_table_44_47;
+	unsigned int	luma_ac_hm_code_val_table_48_51;
+	unsigned int	luma_ac_hm_code_val_table_52_55;
+	unsigned int	luma_ac_hm_code_val_table_56_59;
+	unsigned int	luma_ac_hm_code_val_table_60_63;
+	unsigned int	luma_ac_hm_code_val_table_64_67;
+	unsigned int	luma_ac_hm_code_val_table_68_71;
+	unsigned int	luma_ac_hm_code_val_table_72_75;
+	unsigned int	luma_ac_hm_code_val_table_76_79;
+	unsigned int	luma_ac_hm_code_val_table_80_83;
+	unsigned int	luma_ac_hm_code_val_table_84_87;
+	unsigned int	luma_ac_hm_code_val_table_88_91;
+	unsigned int	luma_ac_hm_code_val_table_92_95;
+	unsigned int	luma_ac_hm_code_val_table_96_99;
+	unsigned int	luma_ac_hm_code_val_table_100_103;
+	unsigned int	luma_ac_hm_code_val_table_104_107;
+	unsigned int	luma_ac_hm_code_val_table_108_111;
+	unsigned int	luma_ac_hm_code_val_table_112_115;
+	unsigned int	luma_ac_hm_code_val_table_116_119;
+	unsigned int	luma_ac_hm_code_val_table_120_123;
+	unsigned int	luma_ac_hm_code_val_table_124_127;
+	unsigned int	luma_ac_hm_code_val_table_128_131;
+	unsigned int	luma_ac_hm_code_val_table_132_135;
+	unsigned int	luma_ac_hm_code_val_table_136_139;
+	unsigned int	luma_ac_hm_code_val_table_140_143;
+	unsigned int	luma_ac_hm_code_val_table_144_147;
+	unsigned int	luma_ac_hm_code_val_table_148_151;
+	unsigned int	luma_ac_hm_code_val_table_152_155;
+	unsigned int	luma_ac_hm_code_val_table_156_159;
+	unsigned int	luma_ac_hm_code_val_table_160_161;
+	unsigned int	chroma_ac_hm_code_cnt_table_0_3;
+	unsigned int	chroma_ac_hm_code_cnt_table_4_7;
+	unsigned int	chroma_ac_hm_code_cnt_table_8_11;
+	unsigned int	chroma_ac_hm_code_cnt_table_12_15;
+	unsigned int	chroma_ac_hm_code_val_table_0_3;
+	unsigned int	chroma_ac_hm_code_val_table_4_7;
+	unsigned int	chroma_ac_hm_code_val_table_8_11;
+	unsigned int	chroma_ac_hm_code_val_table_12_15;
+	unsigned int	chroma_ac_hm_code_val_table_16_19;
+	unsigned int	chroma_ac_hm_code_val_table_20_23;
+	unsigned int	chroma_ac_hm_code_val_table_24_27;
+	unsigned int	chroma_ac_hm_code_val_table_28_31;
+	unsigned int	chroma_ac_hm_code_val_table_32_35;
+	unsigned int	chroma_ac_hm_code_val_table_36_39;
+	unsigned int	chroma_ac_hm_code_val_table_40_43;
+	unsigned int	chroma_ac_hm_code_val_table_44_47;
+	unsigned int	chroma_ac_hm_code_val_table_48_51;
+	unsigned int	chroma_ac_hm_code_val_table_52_55;
+	unsigned int	chroma_ac_hm_code_val_table_56_59;
+	unsigned int	chroma_ac_hm_code_val_table_60_63;
+	unsigned int	chroma_ac_hm_code_val_table_64_67;
+	unsigned int	chroma_ac_hm_code_val_table_68_71;
+	unsigned int	chroma_ac_hm_code_val_table_72_75;
+	unsigned int	chroma_ac_hm_code_val_table_76_79;
+	unsigned int	chroma_ac_hm_code_val_table_80_83;
+	unsigned int	chroma_ac_hm_code_val_table_84_87;
+	unsigned int	chroma_ac_hm_code_val_table_88_91;
+	unsigned int	chroma_ac_hm_code_val_table_92_95;
+	unsigned int	chroma_ac_hm_code_val_table_96_99;
+	unsigned int	chroma_ac_hm_code_val_table_100_103;
+	unsigned int	chroma_ac_hm_code_val_table_104_107;
+	unsigned int	chroma_ac_hm_code_val_table_108_111;
+	unsigned int	chroma_ac_hm_code_val_table_112_115;
+	unsigned int	chroma_ac_hm_code_val_table_116_119;
+	unsigned int	chroma_ac_hm_code_val_table_120_123;
+	unsigned int	chroma_ac_hm_code_val_table_124_127;
+	unsigned int	chroma_ac_hm_code_val_table_128_131;
+	unsigned int	chroma_ac_hm_code_val_table_132_135;
+	unsigned int	chroma_ac_hm_code_val_table_136_139;
+	unsigned int	chroma_ac_hm_code_val_table_140_143;
+	unsigned int	chroma_ac_hm_code_val_table_144_147;
+	unsigned int	chroma_ac_hm_code_val_table_148_151;
+	unsigned int	chroma_ac_hm_code_val_table_152_155;
+	unsigned int	chroma_ac_hm_code_val_table_156_159;
+	unsigned int	chroma_ac_hm_code_val_table_160_161;
+} __attribute__((packed)) jpeg_cmd_dec_cfg;
+
+
+/*
+ * ARM to JPEG configuration commands are passed through the
+ * uPJpegActionCmdQueue
+ */
+
+/*
+ * Command to start the encode process
+ */
+
+#define	JPEG_CMD_ENC_ENCODE		0x0000
+#define	JPEG_CMD_ENC_ENCODE_LEN		sizeof(jpeg_cmd_enc_encode)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) jpeg_cmd_enc_encode;
+
+
+/*
+ * Command to transition from current state of encoder to IDLE state
+ */
+
+#define	JPEG_CMD_ENC_IDLE		0x0001
+#define	JPEG_CMD_ENC_IDLE_LEN		sizeof(jpeg_cmd_enc_idle)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) jpeg_cmd_enc_idle;
+
+
+/*
+ * Command to inform the encoder that another buffer is ready
+ */
+
+#define	JPEG_CMD_ENC_OP_CONSUMED	0x0002
+#define	JPEG_CMD_ENC_OP_CONSUMED_LEN	sizeof(jpeg_cmd_enc_op_consumed)
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	op_buf_addr;
+	unsigned int	op_buf_size;
+} __attribute__((packed)) jpeg_cmd_enc_op_consumed; 
+
+
+/*
+ * Command to start the decoding process
+ */
+
+#define	JPEG_CMD_DEC_DECODE		0x0003
+#define	JPEG_CMD_DEC_DECODE_LEN	sizeof(jpeg_cmd_dec_decode)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) jpeg_cmd_dec_decode;
+
+
+/*
+ * Command to transition from the current state of decoder to IDLE
+ */
+
+#define	JPEG_CMD_DEC_IDLE	0x0004
+#define	JPEG_CMD_DEC_IDLE_LEN	sizeof(jpeg_cmd_dec_idle)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) jpeg_cmd_dec_idle;
+
+
+/*
+ * Command to inform that an op buffer is ready for use
+ */
+
+#define	JPEG_CMD_DEC_OP_CONSUMED	0x0005
+#define	JPEG_CMD_DEC_OP_CONSUMED_LEN	sizeof(jpeg_cmd_dec_op_consumed)
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	luma_op_buf_addr;
+	unsigned int	luma_op_buf_size;
+	unsigned int	chroma_op_buf_addr;
+} __attribute__((packed)) jpeg_cmd_dec_op_consumed;
+
+
+/*
+ * Command to pass a new ip buffer to the jpeg decoder
+ */
+
+#define	JPEG_CMD_DEC_IP	0x0006
+#define	JPEG_CMD_DEC_IP_LEN	sizeof(jpeg_cmd_dec_ip_len)
+
+#define	JPEG_CMD_EOI_INDICATOR_NOT_END	0x0000
+#define	JPEG_CMD_EOI_INDICATOR_END	0x0001
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	ip_buf_addr;
+	unsigned int	ip_buf_size;
+	unsigned int	eoi_indicator;
+} __attribute__((packed)) jpeg_cmd_dec_ip;
+
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegmsg.h
new file mode 100644
index 0000000..d11aa3f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegmsg.h
@@ -0,0 +1,177 @@
+#ifndef QDSP5VIDJPEGMSGI_H
+#define QDSP5VIDJPEGMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+   J P E G  I N T E R N A L  M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of messages
+  that are sent by JPEG Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5jpegmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+05/10/08   sv      initial version
+===========================================================================*/
+
+/*
+ * Messages from JPEG task to ARM through jpeguPMsgQueue
+ */
+
+/*
+ * Message is ACK for CMD_JPEGE_ENCODE cmd
+ */
+
+#define	JPEG_MSG_ENC_ENCODE_ACK	0x0000
+#define	JPEG_MSG_ENC_ENCODE_ACK_LEN	\
+	sizeof(jpeg_msg_enc_encode_ack)
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_enc_encode_ack;
+
+
+/*
+ * Message informs the up when op buffer is ready for consumption and
+ * when encoding is complete or errors
+ */
+
+#define	JPEG_MSG_ENC_OP_PRODUCED	0x0001
+#define	JPEG_MSG_ENC_OP_PRODUCED_LEN	\
+	sizeof(jpeg_msg_enc_op_produced)
+
+#define	JPEG_MSGOP_OP_BUF_STATUS_ENC_DONE_PROGRESS	0x0000
+#define	JPEG_MSGOP_OP_BUF_STATUS_ENC_DONE_COMPLETE	0x0001
+#define	JPEG_MSGOP_OP_BUF_STATUS_ENC_ERR		0x10000
+
+typedef struct {
+	unsigned int	op_buf_addr;
+	unsigned int	op_buf_size;
+	unsigned int	op_buf_status;
+} __attribute__((packed)) jpeg_msg_enc_op_produced;
+
+
+/*
+ * Message to ack CMD_JPEGE_IDLE
+ */
+
+#define	JPEG_MSG_ENC_IDLE_ACK	0x0002
+#define	JPEG_MSG_ENC_IDLE_ACK_LEN	sizeof(jpeg_msg_enc_idle_ack)
+
+
+typedef struct {
+} __attribute__ ((packed)) jpeg_msg_enc_idle_ack;
+
+
+/*
+ * Message to indicate the illegal command
+ */
+
+#define	JPEG_MSG_ENC_ILLEGAL_COMMAND	0x0003
+#define	JPEG_MSG_ENC_ILLEGAL_COMMAND_LEN	\
+	sizeof(jpeg_msg_enc_illegal_command)
+
+typedef struct {
+	unsigned int	status;
+} __attribute__((packed)) jpeg_msg_enc_illegal_command;
+
+
+/*
+ * Message to ACK CMD_JPEGD_DECODE
+ */
+
+#define	JPEG_MSG_DEC_DECODE_ACK		0x0004
+#define	JPEG_MSG_DEC_DECODE_ACK_LEN	\
+	sizeof(jpeg_msg_dec_decode_ack)
+
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_dec_decode_ack;
+
+
+/*
+ * Message to inform up that an op buffer is ready for consumption and when
+ * decoding is complete or an error occurs
+ */
+
+#define	JPEG_MSG_DEC_OP_PRODUCED		0x0005
+#define	JPEG_MSG_DEC_OP_PRODUCED_LEN	\
+	sizeof(jpeg_msg_dec_op_produced)
+
+#define	JPEG_MSG_DEC_OP_BUF_STATUS_PROGRESS	0x0000
+#define	JPEG_MSG_DEC_OP_BUF_STATUS_DONE		0x0001
+
+typedef struct {
+	unsigned int	luma_op_buf_addr;
+	unsigned int	chroma_op_buf_addr;
+	unsigned int	num_mcus;
+	unsigned int	op_buf_status;
+} __attribute__((packed)) jpeg_msg_dec_op_produced;
+
+/*
+ * Message to ack CMD_JPEGD_IDLE cmd
+ */
+
+#define	JPEG_MSG_DEC_IDLE_ACK	0x0006
+#define	JPEG_MSG_DEC_IDLE_ACK_LEN	sizeof(jpeg_msg_dec_idle_ack)
+
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_dec_idle_ack;
+
+
+/*
+ * Message to indicate illegal cmd was received
+ */
+
+#define	JPEG_MSG_DEC_ILLEGAL_COMMAND	0x0007
+#define	JPEG_MSG_DEC_ILLEGAL_COMMAND_LEN	\
+	sizeof(jpeg_msg_dec_illegal_command)
+
+
+typedef struct {
+	unsigned int	status;
+} __attribute__((packed)) jpeg_msg_dec_illegal_command;
+
+/*
+ * Message to request up for the next segment of ip bit stream
+ */
+
+#define	JPEG_MSG_DEC_IP_REQUEST		0x0008
+#define	JPEG_MSG_DEC_IP_REQUEST_LEN	\
+	sizeof(jpeg_msg_dec_ip_request)
+
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_dec_ip_request;
+
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmcmdi.h
new file mode 100644
index 0000000..6c76e2c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmcmdi.h
@@ -0,0 +1,82 @@
+#ifndef QDSP5LPMCMDI_H
+#define QDSP5LPMCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    L P M   I N T E R N A L   C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by LPM Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5lpmcmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+06/12/08   sv      initial version
+===========================================================================*/
+
+
+/*
+ * Command to start LPM processing based on the config params
+ */
+
+#define	LPM_CMD_START		0x0000
+#define	LPM_CMD_START_LEN	sizeof(lpm_cmd_start)
+
+#define	LPM_CMD_SPATIAL_FILTER_PART_OPMODE_0	0x00000000
+#define	LPM_CMD_SPATIAL_FILTER_PART_OPMODE_1	0x00010000
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	ip_data_cfg_part1;
+	unsigned int	ip_data_cfg_part2;
+	unsigned int	ip_data_cfg_part3;
+	unsigned int	ip_data_cfg_part4;
+	unsigned int	op_data_cfg_part1;
+	unsigned int	op_data_cfg_part2;
+	unsigned int	op_data_cfg_part3;
+	unsigned int	spatial_filter_part[32];
+} __attribute__((packed)) lpm_cmd_start;
+
+
+
+/*
+ * Command to stop LPM processing
+ */
+
+#define	LPM_CMD_IDLE		0x0001
+#define	LPM_CMD_IDLE_LEN	sizeof(lpm_cmd_idle)
+
+typedef struct {
+	unsigned int	cmd_id;
+} __attribute__((packed)) lpm_cmd_idle;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmmsg.h
new file mode 100644
index 0000000..3d1039d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmmsg.h
@@ -0,0 +1,80 @@
+#ifndef QDSP5LPMMSGI_H
+#define QDSP5LPMMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    L P M   I N T E R N A L   M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by LPM Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5lpmmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+06/12/08   sv      initial version
+===========================================================================*/
+
+/*
+ * Message to acknowledge CMD_LPM_IDLE command
+ */
+
+#define	LPM_MSG_IDLE_ACK	0x0000
+#define	LPM_MSG_IDLE_ACK_LEN	sizeof(lpm_msg_idle_ack)
+
+typedef struct {
+} __attribute__((packed)) lpm_msg_idle_ack;
+
+
+/*
+ * Message to acknowledge CMD_LPM_START command
+ */
+
+
+#define	LPM_MSG_START_ACK	0x0001
+#define	LPM_MSG_START_ACK_LEN	sizeof(lpm_msg_start_ack)
+
+
+typedef struct {
+} __attribute__((packed)) lpm_msg_start_ack;
+
+
+/*
+ * Message to notify the ARM that LPM processing is complete
+ */
+
+#define	LPM_MSG_DONE		0x0002
+#define	LPM_MSG_DONE_LEN	sizeof(lpm_msg_done)
+
+typedef struct {
+} __attribute__((packed)) lpm_msg_done;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdeccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdeccmdi.h
new file mode 100644
index 0000000..3a32ee9
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdeccmdi.h
@@ -0,0 +1,235 @@
+#ifndef QDSP5VIDDECCMDI_H
+#define QDSP5VIDDECCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    V I D E O  D E C O D E R  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by VIDDEC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vdeccmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+05/10/08   ac      initial version
+===========================================================================*/
+
+
+/*
+ * Command to inform VIDDEC that new subframe packet is ready
+ */
+
+#define	VIDDEC_CMD_SUBFRAME_PKT		0x0000
+#define	VIDDEC_CMD_SUBFRAME_PKT_LEN \
+	sizeof(viddec_cmd_subframe_pkt)
+
+#define	VIDDEC_CMD_SF_INFO_1_DM_DMA_STATS_EXCHANGE_FLAG_DM		0x0000
+#define	VIDDEC_CMD_SF_INFO_1_DM_DMA_STATS_EXCHANGE_FLAG_DMA 	0x0001
+
+#define	VIDDEC_CMD_SF_INFO_0_SUBFRAME_CONTI		0x0000
+#define	VIDDEC_CMD_SF_INFO_0_SUBFRAME_FIRST		0x0001
+#define	VIDDEC_CMD_SF_INFO_0_SUBFRAME_LAST		0x0002
+#define	VIDDEC_CMD_SF_INFO_0_SUBFRAME_FIRST_AND_LAST 	0x0003
+
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_MPEG_4		0x0000
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_H_263_P0	0x0001
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_H_264		0x0002
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_H_263_p3	0x0003
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_RV9		0x0004
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_WMV9		0x0005
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_SMCDB		0x0006
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_QFRE		0x0007
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_VLD		0x0008
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	packet_seq_number;
+	unsigned short	codec_instance_id;
+	unsigned short	subframe_packet_size_high;
+	unsigned short	subframe_packet_size_low;
+	unsigned short	subframe_packet_high;
+	unsigned short	subframe_packet_low;
+	unsigned short	subframe_packet_partition;
+	unsigned short	statistics_packet_size_high;
+	unsigned short	statistics_packet_size_low;
+	unsigned short	statistics_packet_high;
+	unsigned short	statistics_packet_low;
+	unsigned short	statistics_partition;
+	unsigned short	subframe_info_1;
+	unsigned short	subframe_info_0;
+	unsigned short	codec_selection_word;
+	unsigned short	num_mbs;
+} __attribute__((packed)) viddec_cmd_subframe_pkt;
+
+
+/*
+ * Command to inform VIDDEC task that post processing is required for the frame
+ */
+
+#define	VIDDEC_CMD_PP_ENABLE		0x0001
+#define	VIDDEC_CMD_PP_ENABLE_LEN \
+	sizeof(viddec_cmd_pp_enable)
+
+#define	VIDDEC_CMD_PP_INFO_0_DM_DMA_LS_EXCHANGE_FLAG_DM		0x0000
+#define	VIDDEC_CMD_PP_INFO_0_DM_DMA_LS_EXCHANGE_FLAG_DMA	0x0001
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	packet_seq_num;
+	unsigned short	codec_instance_id;
+	unsigned short	postproc_info_0;
+	unsigned short	codec_selection_word;
+	unsigned short	pp_output_addr_high;
+	unsigned short	pp_output_addr_low;
+	unsigned short	postproc_info_1;
+	unsigned short	load_sharing_packet_size_high;
+	unsigned short	load_sharing_packet_size_low;
+	unsigned short	load_sharing_packet_high;
+	unsigned short	load_sharing_packet_low;
+	unsigned short	load_sharing_partition;
+	unsigned short	pp_param_0;
+	unsigned short	pp_param_1;
+	unsigned short	pp_param_2;
+	unsigned short	pp_param_3;
+} __attribute__((packed)) viddec_cmd_pp_enable;
+
+
+/*
+ * FRAME Header Packet : It is at the start of new frame
+ */
+
+#define	VIDDEC_CMD_FRAME_HEADER_PACKET	0x0002
+#define	VIDDEC_CMD_FRAME_HEADER_PACKET_LEN	\
+	sizeof(viddec_cmd_frame_header_packet)
+
+#define	VIDDEC_CMD_FRAME_INFO_0_ERROR_SKIP	0x0000
+#define	VIDDEC_CMD_FRAME_INFO_0_ERROR_BLACK	0x0800
+
+typedef struct {
+	unsigned short	packet_id;
+	unsigned short	x_dimension;
+	unsigned short	y_dimension;
+	unsigned short	line_width;
+	unsigned short	frame_info_0;
+	unsigned short	frame_buffer_0_high;
+	unsigned short	frame_buffer_0_low;
+	unsigned short	frame_buffer_1_high;
+	unsigned short	frame_buffer_1_low;
+	unsigned short	frame_buffer_2_high;
+	unsigned short	frame_buffer_2_low;
+	unsigned short	frame_buffer_3_high;
+	unsigned short	frame_buffer_3_low;
+	unsigned short	frame_buffer_4_high;
+	unsigned short	frame_buffer_4_low;
+	unsigned short	frame_buffer_5_high;
+	unsigned short	frame_buffer_5_low;
+	unsigned short	frame_buffer_6_high;
+	unsigned short	frame_buffer_6_low;
+	unsigned short	frame_buffer_7_high;
+	unsigned short	frame_buffer_7_low;
+	unsigned short	frame_buffer_8_high;
+	unsigned short	frame_buffer_8_low;
+	unsigned short	frame_buffer_9_high;
+	unsigned short	frame_buffer_9_low;
+	unsigned short	frame_buffer_10_high;
+	unsigned short	frame_buffer_10_low;
+	unsigned short	frame_buffer_11_high;
+	unsigned short	frame_buffer_11_low;
+	unsigned short	frame_buffer_12_high;
+	unsigned short	frame_buffer_12_low;
+	unsigned short	frame_buffer_13_high;
+	unsigned short	frame_buffer_13_low;
+	unsigned short	frame_buffer_14_high;
+	unsigned short	frame_buffer_14_low;
+	unsigned short	frame_buffer_15_high;
+	unsigned short	frame_buffer_15_low;
+	unsigned short	output_frame_buffer_high;
+	unsigned short	output_frame_buffer_low;
+	unsigned short	end_of_packet_marker;
+} __attribute__((packed)) viddec_cmd_frame_header_packet;
+
+
+/*
+ * SLICE HEADER PACKET
+ * I-Slice and P-Slice
+ */
+
+#define	VIDDEC_CMD_SLICE_HEADER_PKT_ISLICE		0x0003
+#define	VIDDEC_CMD_SLICE_HEADER_PKT_ISLICE_LEN	\
+	sizeof(viddec_cmd_slice_header_pkt_islice)
+
+#define	VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_PSLICE	0x0000
+#define	VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_BSLICE	0x0100
+#define	VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_ISLICE	0x0200
+#define	VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_SPSLICE	0x0300
+#define	VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_SISLICE	0x0400
+#define	VIDDEC_CMD_ISLICE_INFO_1_NOPADDING	0x0000
+#define	VIDDEC_CMD_ISLICE_INFO_1_PADDING	0x0800
+
+#define	VIDDEC_CMD_ISLICE_EOP_MARKER		0x7FFF
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	packet_id;
+	unsigned short	slice_info_0;
+	unsigned short	slice_info_1;
+	unsigned short	slice_info_2;
+	unsigned short	num_bytes_in_rbsp_high;
+	unsigned short	num_bytes_in_rbsp_low;
+	unsigned short	num_bytes_in_rbsp_consumed;
+	unsigned short	end_of_packet_marker;
+} __attribute__((packed)) viddec_cmd_slice_header_pkt_islice;
+
+
+#define	VIDDEC_CMD_SLICE_HEADER_PKT_PSLICE		0x0003
+#define	VIDDEC_CMD_SLICE_HEADER_PKT_PSLICE_LEN	\
+	sizeof(viddec_cmd_slice_header_pkt_pslice)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	packet_id;
+	unsigned short	slice_info_0;
+	unsigned short	slice_info_1;
+	unsigned short	slice_info_2;
+	unsigned short	slice_info_3;
+	unsigned short	refidx_l0_map_tab_info_0;
+	unsigned short	refidx_l0_map_tab_info_1;
+	unsigned short	refidx_l0_map_tab_info_2;
+	unsigned short	refidx_l0_map_tab_info_3;
+	unsigned short	num_bytes_in_rbsp_high;
+	unsigned short	num_bytes_in_rbsp_low;
+	unsigned short	num_bytes_in_rbsp_consumed;
+	unsigned short	end_of_packet_marker;
+} __attribute__((packed)) viddec_cmd_slice_header_pkt_pslice;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdecmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdecmsg.h
new file mode 100644
index 0000000..c1744c1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdecmsg.h
@@ -0,0 +1,107 @@
+#ifndef QDSP5VIDDECMSGI_H
+#define QDSP5VIDDECMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    V I D E O  D E C O D E R   I N T E R N A L  M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of messages
+  that are sent by VIDDEC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vdecmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+05/10/08   ac      initial version
+===========================================================================*/
+
+/*
+ * Message to inform ARM which VDEC_SUBFRAME_PKT_CMD processed by VIDDEC TASK
+ */
+
+#define	VIDDEC_MSG_SUBF_DONE	0x0000
+#define	VIDDEC_MSG_SUBF_DONE_LEN	\
+	sizeof(viddec_msg_subf_done)
+
+typedef struct {
+	unsigned short	packet_seq_number;
+	unsigned short	codec_instance_id;
+} __attribute__((packed)) viddec_msg_subf_done;
+
+
+/*
+ * Message to inform ARM one frame has been decoded
+ */
+
+#define	VIDDEC_MSG_FRAME_DONE	0x0001
+#define	VIDDEC_MSG_FRAME_DONE_LEN	\
+	sizeof(viddec_msg_frame_done)
+
+typedef struct {
+	unsigned short	packet_seq_number;
+	unsigned short	codec_instance_id;
+} __attribute__((packed)) viddec_msg_frame_done;
+
+
+/*
+ * Message to inform ARM that post processing frame has been decoded
+ */
+
+#define	VIDDEC_MSG_PP_ENABLE_CMD_DONE	0x0002
+#define	VIDDEC_MSG_PP_ENABLE_CMD_DONE_LEN	\
+	sizeof(viddec_msg_pp_enable_cmd_done)
+
+typedef struct {
+	unsigned short	packet_seq_number;
+	unsigned short	codec_instance_id;
+} __attribute__((packed)) viddec_msg_pp_enable_cmd_done;
+
+
+/*
+ * Message to inform ARM that one post processing frame has been decoded
+ */
+
+
+#define	VIDDEC_MSG_PP_FRAME_DONE		0x0003
+#define	VIDDEC_MSG_PP_FRAME_DONE_LEN	\
+	sizeof(viddec_msg_pp_frame_done)
+
+#define	VIDDEC_MSG_DISP_WORTHY_DISP		0x0000
+#define	VIDDEC_MSG_DISP_WORTHY_DISP_NONE	0xFFFF
+
+
+typedef struct {
+	unsigned short	packet_seq_number;
+	unsigned short	codec_instance_id;
+	unsigned short	display_worthy;
+} __attribute__((packed)) viddec_msg_pp_frame_done;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5venccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5venccmdi.h
new file mode 100755
index 0000000..819544d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5venccmdi.h
@@ -0,0 +1,212 @@
+#ifndef QDSP5VIDENCCMDI_H
+#define QDSP5VIDENCCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    V I D E O  E N C O D E R  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by VIDENC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 2008 by QUALCOMM, Incorporated.
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+			EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+Revision History:
+
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+09/25/08   umeshp      initial version
+===========================================================================*/
+
+  #define VIDENC_CMD_CFG           0x0000
+  #define VIDENC_CMD_ACTIVE        0x0001
+  #define VIDENC_CMD_IDLE          0x0002
+  #define VIDENC_CMD_FRAME_START   0x0003
+  #define VIDENC_CMD_STATUS_QUERY  0x0004
+  #define VIDENC_CMD_RC_CFG        0x0005
+  #define VIDENC_CMD_DIS_CFG       0x0006
+  #define VIDENC_CMD_DIS           0x0007
+  #define VIDENC_CMD_INTRA_REFRESH 0x0008
+  #define VIDENC_CMD_DIGITAL_ZOOM  0x0009
+
+
+/*
+ * Command to pass the frame message information to VIDENC
+ */
+
+
+#define VIDENC_CMD_FRAME_START_LEN \
+	sizeof(videnc_cmd_frame_start)
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short  frame_info;
+	unsigned short  frame_rho_budget_word_high;
+	unsigned short  frame_rho_budget_word_low;
+	unsigned short  input_luma_addr_high;
+	unsigned short  input_luma_addr_low;
+	unsigned short  input_chroma_addr_high;
+	unsigned short  input_chroma_addr_low;
+	unsigned short  ref_vop_buf_ptr_high;
+	unsigned short  ref_vop_buf_ptr_low;
+	unsigned short  enc_pkt_buf_ptr_high;
+	unsigned short  enc_pkt_buf_ptr_low;
+	unsigned short  enc_pkt_buf_size_high;
+	unsigned short  enc_pkt_buf_size_low;
+	unsigned short  unfilt_recon_vop_buf_ptr_high;
+	unsigned short  unfilt_recon_vop_buf_ptr_low;
+	unsigned short  filt_recon_vop_buf_ptr_high;
+	unsigned short  filt_recon_vop_buf_ptr_low;
+} __attribute__((packed)) videnc_cmd_frame_start;
+
+/*
+ * Command to pass the frame-level digital stabilization parameters to VIDENC
+ */
+
+
+#define VIDENC_CMD_DIS_LEN \
+    sizeof(videnc_cmd_dis)
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short  vfe_out_prev_luma_addr_high;
+	unsigned short  vfe_out_prev_luma_addr_low;
+	unsigned short  stabilization_info;
+} __attribute__((packed)) videnc_cmd_dis;
+
+/*
+ * Command to pass the codec related parameters to VIDENC
+ */
+
+
+#define VIDENC_CMD_CFG_LEN \
+    sizeof(videnc_cmd_cfg)
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short  cfg_info_0;
+	unsigned short  cfg_info_1;
+	unsigned short  four_mv_threshold;
+	unsigned short  ise_fse_mv_cost_fac;
+	unsigned short  venc_frame_dim;
+	unsigned short  venc_DM_partition;
+} __attribute__((packed)) videnc_cmd_cfg;
+
+/*
+ * Command to start the video encoding
+ */
+
+
+#define VIDENC_CMD_ACTIVE_LEN \
+    sizeof(videnc_cmd_active)
+
+typedef struct {
+    unsigned short  cmd_id;
+} __attribute__((packed)) videnc_cmd_active;
+
+/*
+ * Command to stop the video encoding
+ */
+
+
+#define VIDENC_CMD_IDLE_LEN \
+    sizeof(videnc_cmd_idle)
+
+typedef struct {
+	unsigned short  cmd_id;
+} __attribute__((packed)) videnc_cmd_idle;
+
+/*
+ * Command to query staus of VIDENC
+ */
+
+
+#define VIDENC_CMD_STATUS_QUERY_LEN \
+    sizeof(videnc_cmd_status_query)
+
+typedef struct {
+	unsigned short  cmd_id;
+} __attribute__((packed)) videnc_cmd_status_query;
+
+/*
+ * Command to set rate control for a frame
+ */
+
+
+#define VIDENC_CMD_RC_CFG_LEN \
+    sizeof(videnc_cmd_rc_cfg)
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short  max_frame_qp_delta;
+	unsigned short  max_min_frame_qp;
+} __attribute__((packed)) videnc_cmd_rc_cfg;
+
+/*
+ * Command to set intra-refreshing
+ */
+
+
+#define VIDENC_CMD_INTRA_REFRESH_LEN \
+    sizeof(videnc_cmd_intra_refresh)
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short  num_mb_refresh;
+	unsigned short  mb_index[15];
+} __attribute__((packed)) videnc_cmd_intra_refresh;
+
+/*
+ * Command to pass digital zoom information to the VIDENC
+ */
+#define VIDENC_CMD_DIGITAL_ZOOM_LEN \
+    sizeof(videnc_cmd_digital_zoom)
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short  digital_zoom_en;
+	unsigned short  luma_frame_shift_X;
+	unsigned short  luma_frame_shift_Y;
+	unsigned short  up_ip_luma_rows;
+	unsigned short  up_ip_luma_cols;
+	unsigned short  up_ip_chroma_rows;
+	unsigned short  up_ip_chroma_cols;
+	unsigned short  luma_ph_incr_V_low;
+	unsigned short  luma_ph_incr_V_high;
+	unsigned short  luma_ph_incr_H_low;
+	unsigned short  luma_ph_incr_H_high;
+	unsigned short  chroma_ph_incr_V_low;
+	unsigned short  chroma_ph_incr_V_high;
+	unsigned short  chroma_ph_incr_H_low;
+	unsigned short  chroma_ph_incr_H_high;
+} __attribute__((packed)) videnc_cmd_digital_zoom;
+
+/*
+ * Command to configure digital stabilization parameters
+ */
+
+#define VIDENC_CMD_DIS_CFG_LEN \
+    sizeof(videnc_cmd_dis_cfg)
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short  image_stab_subf_start_row_col;
+	unsigned short  image_stab_subf_dim;
+	unsigned short  image_stab_info_0;
+} __attribute__((packed)) videnc_cmd_dis_cfg;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfecmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfecmdi.h
new file mode 100644
index 0000000..f76d4e4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfecmdi.h
@@ -0,0 +1,910 @@
+#ifndef QDSP5VFECMDI_H
+#define QDSP5VFECMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    V F E   I N T E R N A L   C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by VFE Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vfecmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+06/12/08   sv      initial version
+===========================================================================*/
+
+/******************************************************************************
+ * Commands through vfeCommandScaleQueue
+ *****************************************************************************/
+
+/*
+ * Command to program scaler for op1 . max op of scaler is VGA
+ */
+
+
+#define	VFE_CMD_SCALE_OP1_CFG		0x0000
+#define	VFE_CMD_SCALE_OP1_CFG_LEN	\
+	sizeof(vfe_cmd_scale_op1_cfg)
+
+#define	VFE_CMD_SCALE_OP1_SEL_IP_SEL_Y_STANDARD	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_IP_SEL_Y_CASCADED	0x0001
+#define	VFE_CMD_SCALE_OP1_SEL_H_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_H_Y_SCALER_ENA	0x0002
+#define	VFE_CMD_SCALE_OP1_SEL_H_PP_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_H_PP_Y_SCALER_ENA	0x0004
+#define	VFE_CMD_SCALE_OP1_SEL_V_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_V_Y_SCALER_ENA	0x0008
+#define	VFE_CMD_SCALE_OP1_SEL_V_PP_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_V_PP_Y_SCALER_ENA	0x0010
+#define	VFE_CMD_SCALE_OP1_SEL_IP_SEL_CBCR_STANDARD	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_IP_SEL_CBCR_CASCADED	0x0020
+#define	VFE_CMD_SCALE_OP1_SEL_H_CBCR_SCALER_DIS		0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_H_CBCR_SCALER_ENA		0x0040
+#define	VFE_CMD_SCALE_OP1_SEL_V_CBCR_SCALER_DIS		0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_V_CBCR_SCALER_ENA		0x0080
+
+#define	VFE_CMD_OP1_PP_Y_SCALER_CFG_PART1_DONT_LOAD_COEFFS	0x80000000
+#define	VFE_CMD_OP1_PP_Y_SCALER_CFG_PART1_LOAD_COEFFS	0x80000000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	scale_op1_sel;
+	unsigned int	y_scaler_cfg_part1;
+	unsigned int	y_scaler_cfg_part2;
+	unsigned int	cbcr_scaler_cfg_part1;
+	unsigned int	cbcr_scaler_cfg_part2;
+	unsigned int	cbcr_scaler_cfg_part3;
+	unsigned int	pp_y_scaler_cfg_part1;
+	unsigned int	pp_y_scaler_cfg_part2;
+	unsigned int	y_scaler_v_coeff_bank_part1[16];
+	unsigned int	y_scaler_v_coeff_bank_part2[16];
+	unsigned int	y_scaler_h_coeff_bank_part1[16];
+	unsigned int	y_scaler_h_coeff_bank_part2[16];
+} __attribute__((packed)) vfe_cmd_scale_op1_cfg;
+
+
+/*
+ * Command to program scaler for op2
+ */
+
+#define	VFE_CMD_SCALE_OP2_CFG		0x0001
+#define	VFE_CMD_SCALE_OP2_CFG_LEN	\
+	sizeof(vfe_cmd_scale_op2_cfg)
+
+#define	VFE_CMD_SCALE_OP2_SEL_IP_SEL_Y_STANDARD	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_IP_SEL_Y_CASCADED	0x0001
+#define	VFE_CMD_SCALE_OP2_SEL_H_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_H_Y_SCALER_ENA	0x0002
+#define	VFE_CMD_SCALE_OP2_SEL_H_PP_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_H_PP_Y_SCALER_ENA	0x0004
+#define	VFE_CMD_SCALE_OP2_SEL_V_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_V_Y_SCALER_ENA	0x0008
+#define	VFE_CMD_SCALE_OP2_SEL_V_PP_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_V_PP_Y_SCALER_ENA	0x0010
+#define	VFE_CMD_SCALE_OP2_SEL_IP_SEL_CBCR_STANDARD	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_IP_SEL_CBCR_CASCADED	0x0020
+#define	VFE_CMD_SCALE_OP2_SEL_H_CBCR_SCALER_DIS		0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_H_CBCR_SCALER_ENA		0x0040
+#define	VFE_CMD_SCALE_OP2_SEL_V_CBCR_SCALER_DIS		0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_V_CBCR_SCALER_ENA		0x0080
+
+#define	VFE_CMD_OP2_PP_Y_SCALER_CFG_PART1_DONT_LOAD_COEFFS	0x80000000
+#define	VFE_CMD_OP2_PP_Y_SCALER_CFG_PART1_LOAD_COEFFS		0x80000000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	scale_op2_sel;
+	unsigned int	y_scaler_cfg_part1;
+	unsigned int	y_scaler_cfg_part2;
+	unsigned int	cbcr_scaler_cfg_part1;
+	unsigned int	cbcr_scaler_cfg_part2;
+	unsigned int	cbcr_scaler_cfg_part3;
+	unsigned int	pp_y_scaler_cfg_part1;
+	unsigned int	pp_y_scaler_cfg_part2;
+	unsigned int	y_scaler_v_coeff_bank_part1[16];
+	unsigned int	y_scaler_v_coeff_bank_part2[16];
+	unsigned int	y_scaler_h_coeff_bank_part1[16];
+	unsigned int	y_scaler_h_coeff_bank_part2[16];
+} __attribute__((packed)) vfe_cmd_scale_op2_cfg;
+
+
+/******************************************************************************
+ * Commands through vfeCommandTableQueue
+ *****************************************************************************/
+
+/*
+ * Command to program the AXI ip paths
+ */
+
+#define	VFE_CMD_AXI_IP_CFG		0x0000
+#define	VFE_CMD_AXI_IP_CFG_LEN		sizeof(vfe_cmd_axi_ip_cfg)
+
+#define	VFE_CMD_IP_SEL_IP_FORMAT_8	0x0000
+#define	VFE_CMD_IP_SEL_IP_FORMAT_10	0x0001
+#define	VFE_CMD_IP_SEL_IP_FORMAT_12	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	ip_sel;
+	unsigned int	ip_cfg_part1;
+	unsigned int	ip_cfg_part2;
+	unsigned int	ip_unpack_cfg_part[6];
+	unsigned int	ip_buf_addr[8];
+} __attribute__ ((packed)) vfe_cmd_axi_ip_cfg;
+
+
+/*
+ * Command to program axi op paths
+ */
+
+#define	VFE_CMD_AXI_OP_CFG	0x0001
+#define	VFE_CMD_AXI_OP_CFG_LEN	sizeof(vfe_cmd_axi_op_cfg)
+
+#define	VFE_CMD_OP_SEL_OP1		0x0000
+#define	VFE_CMD_OP_SEL_OP2		0x0001
+#define	VFE_CMD_OP_SEL_OP1_OP2		0x0002
+#define	VFE_CMD_OP_SEL_CTOA		0x0003
+#define	VFE_CMD_OP_SEL_CTOA_OP1		0x0004
+#define	VFE_CMD_OP_SEL_CTOA_OP2		0x0005
+#define	VFE_CMD_OP_SEL_OP_FORMAT_8	0x0000
+#define	VFE_CMD_OP_SEL_OP_FORMAT_10	0x0008
+#define	VFE_CMD_OP_SEL_OP_FORMAT_12	0x0010
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	op_sel;
+	unsigned int	op1_y_cfg_part1;
+	unsigned int	op1_y_cfg_part2;
+	unsigned int	op1_cbcr_cfg_part1;
+	unsigned int	op1_cbcr_cfg_part2;
+	unsigned int	op2_y_cfg_part1;
+	unsigned int	op2_y_cfg_part2;
+	unsigned int	op2_cbcr_cfg_part1;
+	unsigned int	op2_cbcr_cfg_part2;
+	unsigned int	op1_buf1_addr[16];
+	unsigned int	op2_buf1_addr[16];
+} __attribute__((packed)) vfe_cmd_axi_op_cfg;
+
+
+
+
+/*
+ * Command to program the roll off correction module
+ */
+
+#define	VFE_CMD_ROLLOFF_CFG	0x0002
+#define	VFE_CMD_ROLLOFF_CFG_LEN	\
+	sizeof(vfe_cmd_rolloff_cfg)
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	correction_opt_center_pos;
+	unsigned int	radius_square_entry[32];
+	unsigned int	red_table_entry[32];
+	unsigned int	green_table_entry[32];
+	unsigned int	blue_table_entry[32];
+} __attribute__((packed)) vfe_cmd_rolloff_cfg;
+
+/*
+ * Command to program RGB gamma table
+ */
+
+#define	VFE_CMD_RGB_GAMMA_CFG		0x0003
+#define	VFE_CMD_RGB_GAMMA_CFG_LEN	\
+	sizeof(vfe_cmd_rgb_gamma_cfg)
+
+#define	VFE_CMD_RGB_GAMMA_SEL_LINEAR		0x0000
+#define	VFE_CMD_RGB_GAMMA_SEL_PW_LINEAR		0x0001
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	rgb_gamma_sel;
+	unsigned int	rgb_gamma_entry[256];
+} __attribute__((packed)) vfe_cmd_rgb_gamma_cfg;
+
+
+/*
+ * Command to program luma gamma table for the noise reduction path
+ */
+
+#define	VFE_CMD_Y_GAMMA_CFG		0x0004
+#define	VFE_CMD_Y_GAMMA_CFG_LEN		\
+	sizeof(vfe_cmd_y_gamma_cfg)
+
+#define	VFE_CMD_Y_GAMMA_SEL_LINEAR	0x0000
+#define	VFE_CMD_Y_GAMMA_SEL_PW_LINEAR	0x0001
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	y_gamma_sel;
+	unsigned int	y_gamma_entry[256];	
+} __attribute__((packed)) vfe_cmd_y_gamma_cfg;
+
+
+
+/******************************************************************************
+ * Commands through vfeCommandQueue
+ *****************************************************************************/
+
+/*
+ * Command to reset the VFE to a known good state.All previously programmed 
+ * Params will be lost
+ */
+
+
+#define	VFE_CMD_RESET		0x0000
+#define	VFE_CMD_RESET_LEN	sizeof(vfe_cmd_reset)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) vfe_cmd_reset;
+
+
+/*
+ * Command to start VFE processing based on the config params
+ */
+
+
+#define	VFE_CMD_START		0x0001
+#define	VFE_CMD_START_LEN	sizeof(vfe_cmd_start)
+
+#define	VFE_CMD_STARTUP_PARAMS_SRC_CAMIF	0x0000
+#define	VFE_CMD_STARTUP_PARAMS_SRC_AXI		0x0001
+#define	VFE_CMD_STARTUP_PARAMS_MODE_CONTINUOUS	0x0000
+#define	VFE_CMD_STARTUP_PARAMS_MODE_SNAPSHOT	0x0002
+
+#define	VFE_CMD_IMAGE_PL_BLACK_LVL_CORR_DIS	0x0000
+#define	VFE_CMD_IMAGE_PL_BLACK_LVL_CORR_ENA	0x0001
+#define	VFE_CMD_IMAGE_PL_ROLLOFF_CORR_DIS	0x0000
+#define	VFE_CMD_IMAGE_PL_ROLLOFF_CORR_ENA	0x0002
+#define	VFE_CMD_IMAGE_PL_WHITE_BAL_DIS		0x0000
+#define	VFE_CMD_IMAGE_PL_WHITE_BAL_ENA		0x0004
+#define	VFE_CMD_IMAGE_PL_RGB_GAMMA_DIS		0x0000
+#define	VFE_CMD_IMAGE_PL_RGB_GAMMA_ENA		0x0008
+#define	VFE_CMD_IMAGE_PL_LUMA_NOISE_RED_PATH_DIS	0x0000
+#define	VFE_CMD_IMAGE_PL_LUMA_NOISE_RED_PATH_ENA	0x0010
+#define	VFE_CMD_IMAGE_PL_ADP_FILTER_DIS		0x0000
+#define	VFE_CMD_IMAGE_PL_ADP_FILTER_ENA		0x0020
+#define	VFE_CMD_IMAGE_PL_CHROMA_SAMP_DIS	0x0000
+#define	VFE_CMD_IMAGE_PL_CHROMA_SAMP_ENA	0x0040
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	startup_params;
+	unsigned int	image_pipeline;
+	unsigned int	frame_dimension;
+} __attribute__((packed)) vfe_cmd_start;
+
+
+/*
+ * Command to halt all processing
+ */
+
+#define	VFE_CMD_STOP		0x0002
+#define	VFE_CMD_STOP_LEN	sizeof(vfe_cmd_stop)
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) vfe_cmd_stop;
+
+
+/*
+ * Command to commit the params that have been programmed to take
+ * effect on the next frame
+ */
+
+#define	VFE_CMD_UPDATE		0x0003
+#define	VFE_CMD_UPDATE_LEN	sizeof(vfe_cmd_update)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) vfe_cmd_update;
+
+
+/*
+ * Command to program CAMIF module
+ */
+
+#define	VFE_CMD_CAMIF_CFG	0x0004
+#define	VFE_CMD_CAMIF_CFG_LEN	sizeof(vfe_cmd_camif_cfg)
+
+#define	VFE_CMD_CFG_VSYNC_SYNC_EDGE_HIGH	0x0000
+#define	VFE_CMD_CFG_VSYNC_SYNC_EDGE_LOW		0x0002
+#define	VFE_CMD_CFG_HSYNC_SYNC_EDGE_HIGH	0x0000
+#define	VFE_CMD_CFG_HSYNC_SYNC_EDGE_LOW		0x0004
+#define	VFE_CMD_CFG_SYNC_MODE_APS		0x0000
+#define	VFE_CMD_CFG_SYNC_MODE_EFS		0X0008
+#define	VFE_CMD_CFG_SYNC_MODE_ELS		0x0010
+#define	VFE_CMD_CFG_SYNC_MODE_RVD		0x0018
+#define	VFE_CMD_CFG_VFE_SUBSAMP_EN_DIS		0x0000
+#define	VFE_CMD_CFG_VFE_SUBSAMP_EN_ENA		0x0020
+#define	VFE_CMD_CFG_BUS_SUBSAMP_EN_DIS		0x0000
+#define	VFE_CMD_CFG_BUS_SUBSAMP_EN_ENA		0x0080
+#define	VFE_CMD_CFG_IRQ_SUBSAMP_EN_DIS		0x0000
+#define	VFE_CMD_CFG_IRQ_SUBSAMP_EN_ENA		0x0800
+
+#define	VFE_CMD_SUBSAMP2_CFG_PIXEL_SKIP_16	0x0000
+#define	VFE_CMD_SUBSAMP2_CFG_PIXEL_SKIP_12	0x0010
+
+#define	VFE_CMD_EPOCH_IRQ_1_DIS			0x0000
+#define	VFE_CMD_EPOCH_IRQ_1_ENA			0x4000
+#define	VFE_CMD_EPOCH_IRQ_2_DIS			0x0000
+#define	VFE_CMD_EPOCH_IRQ_2_ENA			0x8000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	cfg;
+	unsigned int	efs_cfg;
+	unsigned int	frame_cfg;
+	unsigned int	window_width_cfg;
+	unsigned int	window_height_cfg;
+	unsigned int	subsamp1_cfg;
+	unsigned int	subsamp2_cfg;
+	unsigned int	epoch_irq;
+} __attribute__((packed)) vfe_cmd_camif_cfg;
+
+
+
+/*
+ * Command to program the black level module
+ */
+
+#define	VFE_CMD_BLACK_LVL_CFG		0x0005
+#define	VFE_CMD_BLACK_LVL_CFG_LEN	sizeof(vfe_cmd_black_lvl_cfg)
+
+#define	VFE_CMD_BL_SEL_MANUAL		0x0000
+#define	VFE_CMD_BL_SEL_AUTO		0x0001
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	black_lvl_sel;
+	unsigned int	cfg_part[3];
+} __attribute__((packed)) vfe_cmd_black_lvl_cfg;
+
+
+/*
+ * Command to program the active region by cropping the region of interest
+ */
+
+#define	VFE_CMD_ACTIVE_REGION_CFG	0x0006
+#define	VFE_CMD_ACTIVE_REGION_CFG_LEN	\
+	sizeof(vfe_cmd_active_region_cfg)
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	cfg_part1;
+	unsigned int	cfg_part2;
+} __attribute__((packed)) vfe_cmd_active_region_cfg;
+
+
+
+/*
+ * Command to program the defective pixel correction(DPC) ,
+ * adaptive bayer filter (ABF) and demosaic modules
+ */
+
+#define	VFE_CMD_DEMOSAIC_CFG		0x0007
+#define	VFE_CMD_DEMOSAIC_CFG_LEN	sizeof(vfe_cmd_demosaic_cfg)
+
+#define	VFE_CMD_DEMOSAIC_PART1_ABF_EN_DIS	0x0000
+#define	VFE_CMD_DEMOSAIC_PART1_ABF_EN_ENA	0x0001
+#define	VFE_CMD_DEMOSAIC_PART1_DPC_EN_DIS	0x0000
+#define	VFE_CMD_DEMOSAIC_PART1_DPC_EN_ENA	0x0002
+#define	VFE_CMD_DEMOSAIC_PART1_FORCE_ABF_OFF	0x0000
+#define	VFE_CMD_DEMOSAIC_PART1_FORCE_ABF_ON	0x0004
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1	0x00000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_2	0x10000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_4	0x20000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_8	0x30000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_2	0x50000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_4	0x60000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_8	0x70000000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	demosaic_part1;
+	unsigned int	demosaic_part2;
+	unsigned int	demosaic_part3;
+	unsigned int	demosaic_part4;
+	unsigned int	demosaic_part5;
+} __attribute__((packed)) vfe_cmd_demosaic_cfg;
+
+
+/*
+ * Command to program the ip format
+ */
+
+#define	VFE_CMD_IP_FORMAT_CFG		0x0008
+#define	VFE_CMD_IP_FORMAT_CFG_LEN	\
+	sizeof(vfe_cmd_ip_format_cfg)
+
+#define	VFE_CMD_IP_FORMAT_SEL_RGRG	0x0000
+#define	VFE_CMD_IP_FORMAT_SEL_GRGR	0x0001
+#define	VFE_CMD_IP_FORMAT_SEL_BGBG	0x0002
+#define	VFE_CMD_IP_FORMAT_SEL_GBGB	0x0003
+#define	VFE_CMD_IP_FORMAT_SEL_YCBYCR	0x0004
+#define	VFE_CMD_IP_FORMAT_SEL_YCRYCB	0x0005
+#define	VFE_CMD_IP_FORMAT_SEL_CBYCRY	0x0006
+#define	VFE_CMD_IP_FORMAT_SEL_CRYCBY	0x0007
+#define	VFE_CMD_IP_FORMAT_SEL_NO_CHROMA	0x0000
+#define	VFE_CMD_IP_FORMAT_SEL_CHROMA	0x0008
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	ip_format_sel;
+	unsigned int	balance_gains_part1;
+	unsigned int	balance_gains_part2;
+} __attribute__((packed)) vfe_cmd_ip_format_cfg;
+
+
+
+/*
+ * Command to program max and min allowed op values
+ */
+
+#define	VFE_CMD_OP_CLAMP_CFG		0x0009
+#define	VFE_CMD_OP_CLAMP_CFG_LEN	\
+	sizeof(vfe_cmd_op_clamp_cfg)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	op_clamp_max;
+	unsigned int	op_clamp_min;
+} __attribute__((packed)) vfe_cmd_op_clamp_cfg;
+
+
+/*
+ * Command to program chroma sub sample module
+ */
+
+#define	VFE_CMD_CHROMA_SUBSAMPLE_CFG		0x000A
+#define	VFE_CMD_CHROMA_SUBSAMPLE_CFG_LEN	\
+	sizeof(vfe_cmd_chroma_subsample_cfg)
+
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_H_INTERESTIAL_SAMPS	0x0000
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_H_COSITED_SAMPS	0x0001
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_V_INTERESTIAL_SAMPS	0x0000
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_V_COSITED_SAMPS	0x0002
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_H_SUBSAMP_DIS	0x0000
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_H_SUBSAMP_ENA	0x0004
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_V_SUBSAMP_DIS	0x0000
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_V_SUBSAMP_ENA	0x0008
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	chroma_subsamp_sel;
+} __attribute__((packed)) vfe_cmd_chroma_subsample_cfg;
+
+
+/*
+ * Command to program the white balance module
+ */
+
+#define	VFE_CMD_WHITE_BALANCE_CFG	0x000B
+#define	VFE_CMD_WHITE_BALANCE_CFG_LEN	\
+	sizeof(vfe_cmd_white_balance_cfg)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	white_balance_gains;
+} __attribute__((packed)) vfe_cmd_white_balance_cfg;
+
+
+/*
+ * Command to program the color processing module
+ */
+
+#define	VFE_CMD_COLOR_PROCESS_CFG	0x000C
+#define	VFE_CMD_COLOR_PROCESS_CFG_LEN	\
+	sizeof(vfe_cmd_color_process_cfg)
+
+#define	VFE_CMD_COLOR_CORRE_PART7_Q7_FACTORS	0x0000
+#define	VFE_CMD_COLOR_CORRE_PART7_Q8_FACTORS	0x0001
+#define	VFE_CMD_COLOR_CORRE_PART7_Q9_FACTORS	0x0002
+#define	VFE_CMD_COLOR_CORRE_PART7_Q10_FACTORS	0x0003
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	color_correction_part1;
+	unsigned int	color_correction_part2;
+	unsigned int	color_correction_part3;
+	unsigned int	color_correction_part4;
+	unsigned int	color_correction_part5;
+	unsigned int	color_correction_part6;
+	unsigned int	color_correction_part7;
+	unsigned int	chroma_enhance_part1;
+	unsigned int	chroma_enhance_part2;
+	unsigned int	chroma_enhance_part3;
+	unsigned int	chroma_enhance_part4;
+	unsigned int	chroma_enhance_part5;
+	unsigned int	luma_calc_part1;
+	unsigned int	luma_calc_part2;
+} __attribute__((packed)) vfe_cmd_color_process_cfg;
+
+
+/*
+ * Command to program adaptive filter module
+ */
+
+#define	VFE_CMD_ADP_FILTER_CFG		0x000D
+#define	VFE_CMD_ADP_FILTER_CFG_LEN	\
+	sizeof(vfe_cmd_adp_filter_cfg)
+
+#define	VFE_CMD_ASF_CFG_PART_SMOOTH_FILTER_DIS		0x0000
+#define	VFE_CMD_ASF_CFG_PART_SMOOTH_FILTER_ENA		0x0001
+#define	VFE_CMD_ASF_CFG_PART_NO_SHARP_MODE		0x0000
+#define	VFE_CMD_ASF_CFG_PART_SINGLE_FILTER		0x0002
+#define	VFE_CMD_ASF_CFG_PART_DUAL_FILTER		0x0004
+#define	VFE_CMD_ASF_CFG_PART_SHARP_MODE			0x0007
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	asf_cfg_part[7];
+} __attribute__((packed)) vfe_cmd_adp_filter_cfg;
+
+
+/*
+ * Command to program for frame skip pattern for op1 and op2
+ */
+
+#define	VFE_CMD_FRAME_SKIP_CFG		0x000E
+#define	VFE_CMD_FRAME_SKIP_CFG_LEN	\
+	sizeof(vfe_cmd_frame_skip_cfg)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	frame_skip_pattern_op1;
+	unsigned int	frame_skip_pattern_op2;
+} __attribute__((packed)) vfe_cmd_frame_skip_cfg;
+
+
+/*
+ * Command to program field-of-view crop for digital zoom
+ */
+
+#define	VFE_CMD_FOV_CROP	0x000F
+#define	VFE_CMD_FOV_CROP_LEN	sizeof(vfe_cmd_fov_crop)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	fov_crop_part1;
+	unsigned int	fov_crop_part2;
+} __attribute__((packed)) vfe_cmd_fov_crop; 
+
+
+
+/*
+ * Command to program auto focus(AF) statistics module
+ */
+
+#define	VFE_CMD_STATS_AUTOFOCUS_CFG	0x0010
+#define	VFE_CMD_STATS_AUTOFOCUS_CFG_LEN	\
+	sizeof(vfe_cmd_stats_autofocus_cfg)
+
+#define	VFE_CMD_AF_STATS_SEL_STATS_DIS	0x0000
+#define	VFE_CMD_AF_STATS_SEL_STATS_ENA	0x0001
+#define	VFE_CMD_AF_STATS_SEL_PRI_FIXED	0x0000
+#define	VFE_CMD_AF_STATS_SEL_PRI_VAR	0x0002
+#define	VFE_CMD_AF_STATS_CFG_PART_METRIC_SUM	0x00000000
+#define	VFE_CMD_AF_STATS_CFG_PART_METRIC_MAX	0x00200000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	af_stats_sel;
+	unsigned int	af_stats_cfg_part[8];
+	unsigned int	af_stats_op_buf_hdr;
+	unsigned int	af_stats_op_buf[3];
+} __attribute__((packed)) vfe_cmd_stats_autofocus_cfg;
+
+
+/*
+ * Command to program White balance(wb) and exposure (exp)
+ * statistics module
+ */
+
+#define	VFE_CMD_STATS_WB_EXP_CFG	0x0011
+#define	VFE_CMD_STATS_WB_EXP_CFG_LEN	\
+	sizeof(vfe_cmd_stats_wb_exp_cfg)
+
+#define	VFE_CMD_WB_EXP_STATS_SEL_STATS_DIS	0x0000
+#define	VFE_CMD_WB_EXP_STATS_SEL_STATS_ENA	0x0001
+#define	VFE_CMD_WB_EXP_STATS_SEL_PRI_FIXED	0x0000
+#define	VFE_CMD_WB_EXP_STATS_SEL_PRI_VAR	0x0002
+
+#define	VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_REG_8_8	0x0000
+#define	VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_REG_16_16	0x0001
+#define	VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_SREG_8_8	0x0000
+#define	VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_SREG_4_4	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	wb_exp_stats_sel;
+	unsigned int	wb_exp_stats_cfg_part1;
+	unsigned int	wb_exp_stats_cfg_part2;
+	unsigned int	wb_exp_stats_cfg_part3;
+	unsigned int	wb_exp_stats_cfg_part4;
+	unsigned int	wb_exp_stats_op_buf_hdr;
+	unsigned int	wb_exp_stats_op_buf[3];
+} __attribute__((packed)) vfe_cmd_stats_wb_exp_cfg;
+
+
+/*
+ * Command to program histogram(hg) stats module
+ */
+
+#define	VFE_CMD_STATS_HG_CFG		0x0012
+#define	VFE_CMD_STATS_HG_CFG_LEN	\
+	sizeof(vfe_cmd_stats_hg_cfg)
+
+#define	VFE_CMD_HG_STATS_SEL_PRI_FIXED	0x0000
+#define	VFE_CMD_HG_STATS_SEL_PRI_VAR	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	hg_stats_sel;
+	unsigned int	hg_stats_cfg_part1;
+	unsigned int	hg_stats_cfg_part2;
+	unsigned int	hg_stats_op_buf_hdr;
+	unsigned int	hg_stats_op_buf;
+} __attribute__((packed)) vfe_cmd_stats_hg_cfg;
+
+
+/*
+ * Command to acknowledge last MSG_VFE_OP1 message
+ */
+
+#define	VFE_CMD_OP1_ACK		0x0013
+#define	VFE_CMD_OP1_ACK_LEN	sizeof(vfe_cmd_op1_ack)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	op1_buf_y_addr;
+	unsigned int	op1_buf_cbcr_addr;
+} __attribute__((packed)) vfe_cmd_op1_ack;
+
+
+
+/*
+ * Command to acknowledge last MSG_VFE_OP2 message
+ */
+
+#define	VFE_CMD_OP2_ACK		0x0014
+#define	VFE_CMD_OP2_ACK_LEN	sizeof(vfe_cmd_op2_ack)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	op2_buf_y_addr;
+	unsigned int	op2_buf_cbcr_addr;
+} __attribute__((packed)) vfe_cmd_op2_ack;
+
+
+
+/*
+ * Command to acknowledge MSG_VFE_STATS_AUTOFOCUS msg
+ */
+
+#define	VFE_CMD_STATS_AF_ACK		0x0015
+#define	VFE_CMD_STATS_AF_ACK_LEN	sizeof(vfe_cmd_stats_af_ack)
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	af_stats_op_buf;
+} __attribute__((packed)) vfe_cmd_stats_af_ack;
+
+
+/*
+ * Command to acknowledge MSG_VFE_STATS_WB_EXP msg
+ */
+
+#define	VFE_CMD_STATS_WB_EXP_ACK	0x0016
+#define	VFE_CMD_STATS_WB_EXP_ACK_LEN	sizeof(vfe_cmd_stats_wb_exp_ack)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	wb_exp_stats_op_buf;
+} __attribute__((packed)) vfe_cmd_stats_wb_exp_ack;
+
+
+/*
+ * Command to acknowledge MSG_VFE_EPOCH1 message
+ */
+
+#define	VFE_CMD_EPOCH1_ACK	0x0017
+#define	VFE_CMD_EPOCH1_ACK_LEN	sizeof(vfe_cmd_epoch1_ack)
+
+typedef struct {
+	unsigned short cmd_id;
+} __attribute__((packed)) vfe_cmd_epoch1_ack;
+
+
+/*
+ * Command to acknowledge MSG_VFE_EPOCH2 message
+ */
+
+#define	VFE_CMD_EPOCH2_ACK	0x0018
+#define	VFE_CMD_EPOCH2_ACK_LEN	sizeof(vfe_cmd_epoch2_ack)
+
+typedef struct {
+	unsigned short cmd_id;
+} __attribute__((packed)) vfe_cmd_epoch2_ack;
+
+
+
+/*
+ * Command to configure, enable or disable synchronous timer1
+ */
+
+#define	VFE_CMD_SYNC_TIMER1_CFG		0x0019
+#define	VFE_CMD_SYNC_TIMER1_CFG_LEN	\
+	sizeof(vfe_cmd_sync_timer1_cfg)
+
+#define	VFE_CMD_SYNC_T1_CFG_PART1_TIMER_DIS	0x0000
+#define	VFE_CMD_SYNC_T1_CFG_PART1_TIMER_ENA	0x0001
+#define	VFE_CMD_SYNC_T1_CFG_PART1_POL_HIGH	0x0000
+#define	VFE_CMD_SYNC_T1_CFG_PART1_POL_LOW	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	sync_t1_cfg_part1;
+	unsigned int	sync_t1_h_sync_countdown;
+	unsigned int	sync_t1_pclk_countdown;
+	unsigned int	sync_t1_duration;
+} __attribute__((packed)) vfe_cmd_sync_timer1_cfg;
+
+
+/*
+ * Command to configure, enable or disable synchronous timer1
+ */
+
+#define	VFE_CMD_SYNC_TIMER2_CFG		0x001A
+#define	VFE_CMD_SYNC_TIMER2_CFG_LEN	\
+	sizeof(vfe_cmd_sync_timer2_cfg)
+
+#define	VFE_CMD_SYNC_T2_CFG_PART1_TIMER_DIS	0x0000
+#define	VFE_CMD_SYNC_T2_CFG_PART1_TIMER_ENA	0x0001
+#define	VFE_CMD_SYNC_T2_CFG_PART1_POL_HIGH	0x0000
+#define	VFE_CMD_SYNC_T2_CFG_PART1_POL_LOW	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	sync_t2_cfg_part1;
+	unsigned int	sync_t2_h_sync_countdown;
+	unsigned int	sync_t2_pclk_countdown;
+	unsigned int	sync_t2_duration;
+} __attribute__((packed)) vfe_cmd_sync_timer2_cfg;
+
+
+/*
+ * Command to configure and start asynchronous timer1
+ */
+
+#define	VFE_CMD_ASYNC_TIMER1_START	0x001B
+#define	VFE_CMD_ASYNC_TIMER1_START_LEN	\
+	sizeof(vfe_cmd_async_timer1_start)
+
+#define	VFE_CMD_ASYNC_T1_POLARITY_A_HIGH	0x0000
+#define	VFE_CMD_ASYNC_T1_POLARITY_A_LOW		0x0001
+#define	VFE_CMD_ASYNC_T1_POLARITY_B_HIGH	0x0000
+#define	VFE_CMD_ASYNC_T1_POLARITY_B_LOW		0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	async_t1a_cfg;
+	unsigned int	async_t1b_cfg;
+	unsigned int	async_t1_polarity;
+} __attribute__((packed)) vfe_cmd_async_timer1_start;
+
+
+/*
+ * Command to configure and start asynchronous timer2
+ */
+
+#define	VFE_CMD_ASYNC_TIMER2_START	0x001C
+#define	VFE_CMD_ASYNC_TIMER2_START_LEN	\
+	sizeof(vfe_cmd_async_timer2_start)
+
+#define	VFE_CMD_ASYNC_T2_POLARITY_A_HIGH	0x0000
+#define	VFE_CMD_ASYNC_T2_POLARITY_A_LOW		0x0001
+#define	VFE_CMD_ASYNC_T2_POLARITY_B_HIGH	0x0000
+#define	VFE_CMD_ASYNC_T2_POLARITY_B_LOW		0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	async_t2a_cfg;
+	unsigned int	async_t2b_cfg;
+	unsigned int	async_t2_polarity;
+} __attribute__((packed)) vfe_cmd_async_timer2_start;
+
+
+/*
+ * Command to program partial configurations of auto focus(af)
+ */
+
+#define	VFE_CMD_STATS_AF_UPDATE		0x001D
+#define	VFE_CMD_STATS_AF_UPDATE_LEN	\
+	sizeof(vfe_cmd_stats_af_update)
+
+#define	VFE_CMD_AF_UPDATE_PART1_WINDOW_ONE	0x00000000
+#define	VFE_CMD_AF_UPDATE_PART1_WINDOW_MULTI	0x80000000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	af_update_part1;
+	unsigned int	af_update_part2;
+} __attribute__((packed)) vfe_cmd_stats_af_update;
+
+
+/*
+ * Command to program partial cfg of wb and exp
+ */
+
+#define	VFE_CMD_STATS_WB_EXP_UPDATE	0x001E
+#define	VFE_CMD_STATS_WB_EXP_UPDATE_LEN	\
+	sizeof(vfe_cmd_stats_wb_exp_update)
+
+#define	VFE_CMD_WB_EXP_UPDATE_PART1_REGIONS_8_8		0x0000
+#define	VFE_CMD_WB_EXP_UPDATE_PART1_REGIONS_16_16	0x0001
+#define	VFE_CMD_WB_EXP_UPDATE_PART1_SREGIONS_8_8	0x0000
+#define	VFE_CMD_WB_EXP_UPDATE_PART1_SREGIONS_4_4	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	wb_exp_update_part1;
+	unsigned int	wb_exp_update_part2;
+	unsigned int	wb_exp_update_part3;
+	unsigned int	wb_exp_update_part4;
+} __attribute__((packed)) vfe_cmd_stats_wb_exp_update;
+
+
+
+/*
+ * Command to re program the CAMIF FRAME CONFIG settings
+ */
+
+#define	VFE_CMD_UPDATE_CAMIF_FRAME_CFG		0x001F
+#define	VFE_CMD_UPDATE_CAMIF_FRAME_CFG_LEN	\
+	sizeof(vfe_cmd_update_camif_frame_cfg)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	camif_frame_cfg;
+} __attribute__((packed)) vfe_cmd_update_camif_frame_cfg;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfemsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfemsg.h
new file mode 100644
index 0000000..0053cfb
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfemsg.h
@@ -0,0 +1,290 @@
+#ifndef QDSP5VFEMSGI_H
+#define QDSP5VFEMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    V F E   I N T E R N A L   M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are sent by VFE Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992 - 2008 by 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vfemsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+06/12/08   sv      initial version
+===========================================================================*/
+
+
+/*
+ * Message to acknowledge CMD_VFE_REST command
+ */
+
+#define	VFE_MSG_RESET_ACK	0x0000
+#define	VFE_MSG_RESET_ACK_LEN	sizeof(vfe_msg_reset_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_reset_ack;
+
+
+/*
+ * Message to acknowledge CMD_VFE_START command
+ */
+
+#define	VFE_MSG_START_ACK	0x0001
+#define	VFE_MSG_START_ACK_LEN	sizeof(vfe_msg_start_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_start_ack;
+
+/*
+ * Message to acknowledge CMD_VFE_STOP	command
+ */
+
+#define	VFE_MSG_STOP_ACK	0x0002
+#define	VFE_MSG_STOP_ACK_LEN	sizeof(vfe_msg_stop_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_stop_ack;
+
+
+/*
+ * Message to acknowledge CMD_VFE_UPDATE command
+ */
+
+#define	VFE_MSG_UPDATE_ACK	0x0003
+#define	VFE_MSG_UPDATE_ACK_LEN	sizeof(vfe_msg_update_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_update_ack;
+
+
+/*
+ * Message to notify the ARM that snapshot processing is complete
+ * and that the VFE is now STATE_VFE_IDLE
+ */
+
+#define	VFE_MSG_SNAPSHOT_DONE		0x0004
+#define	VFE_MSG_SNAPSHOT_DONE_LEN	\
+	sizeof(vfe_msg_snapshot_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_snapshot_done;
+
+
+
+/*
+ * Message to notify ARM that illegal cmd was received and
+ * system is in the IDLE state
+ */
+
+#define	VFE_MSG_ILLEGAL_CMD	0x0005
+#define	VFE_MSG_ILLEGAL_CMD_LEN	\
+	sizeof(vfe_msg_illegal_cmd)
+
+typedef struct {
+	unsigned int	status;
+} __attribute__((packed)) vfe_msg_illegal_cmd;
+
+
+/*
+ * Message to notify ARM that op1 buf is full and ready
+ */
+
+#define	VFE_MSG_OP1		0x0006
+#define	VFE_MSG_OP1_LEN		sizeof(vfe_msg_op1)
+
+typedef struct {
+	unsigned int	op1_buf_y_addr;
+	unsigned int	op1_buf_cbcr_addr;
+	unsigned int	black_level_even_col;
+	unsigned int	black_level_odd_col;
+	unsigned int	defect_pixels_detected;
+	unsigned int	asf_max_edge;
+} __attribute__((packed)) vfe_msg_op1;
+
+
+/*
+ * Message to notify ARM that op2 buf is full and ready
+ */
+
+#define	VFE_MSG_OP2		0x0007
+#define	VFE_MSG_OP2_LEN		sizeof(vfe_msg_op2)
+
+typedef struct {
+	unsigned int	op2_buf_y_addr;
+	unsigned int	op2_buf_cbcr_addr;
+	unsigned int	black_level_even_col;
+	unsigned int	black_level_odd_col;
+	unsigned int	defect_pixels_detected;
+	unsigned int	asf_max_edge;
+} __attribute__((packed)) vfe_msg_op2;
+
+
+/*
+ * Message to notify ARM that autofocus(af) stats are ready
+ */
+
+#define	VFE_MSG_STATS_AF	0x0008
+#define	VFE_MSG_STATS_AF_LEN	sizeof(vfe_msg_stats_af)
+
+typedef struct {
+	unsigned int	af_stats_op_buffer;
+} __attribute__((packed)) vfe_msg_stats_af;
+
+
+/*
+ * Message to notify ARM that white balance(wb) and exposure (exp)
+ * stats are ready
+ */
+
+#define	VFE_MSG_STATS_WB_EXP		0x0009
+#define	VFE_MSG_STATS_WB_EXP_LEN	\
+	sizeof(vfe_msg_stats_wb_exp)
+
+typedef struct {
+	unsigned int	wb_exp_stats_op_buf;
+} __attribute__((packed)) vfe_msg_stats_wb_exp;
+
+
+/*
+ * Message to notify the ARM that histogram(hg) stats are ready
+ */
+
+#define	VFE_MSG_STATS_HG	0x000A
+#define	VFE_MSG_STATS_HG_LEN	sizeof(vfe_msg_stats_hg)
+
+typedef struct {
+	unsigned int	hg_stats_op_buf;
+} __attribute__((packed)) vfe_msg_stats_hg;
+
+
+/*
+ * Message to notify the ARM that epoch1 event occurred in the CAMIF
+ */
+
+#define	VFE_MSG_EPOCH1		0x000B
+#define	VFE_MSG_EPOCH1_LEN	sizeof(vfe_msg_epoch1)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_epoch1;
+
+
+/*
+ * Message to notify the ARM that epoch2 event occurred in the CAMIF
+ */
+
+#define	VFE_MSG_EPOCH2		0x000C
+#define	VFE_MSG_EPOCH2_LEN	sizeof(vfe_msg_epoch2)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_epoch2;
+
+
+/*
+ * Message to notify the ARM that sync timer1 op is completed
+ */
+
+#define	VFE_MSG_SYNC_T1_DONE		0x000D
+#define	VFE_MSG_SYNC_T1_DONE_LEN	sizeof(vfe_msg_sync_t1_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_sync_t1_done;
+
+
+/*
+ * Message to notify the ARM that sync timer2 op is completed
+ */
+
+#define	VFE_MSG_SYNC_T2_DONE		0x000E
+#define	VFE_MSG_SYNC_T2_DONE_LEN	sizeof(vfe_msg_sync_t2_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_sync_t2_done;
+
+
+/*
+ * Message to notify the ARM that async t1 operation completed
+ */
+
+#define	VFE_MSG_ASYNC_T1_DONE		0x000F
+#define	VFE_MSG_ASYNC_T1_DONE_LEN	sizeof(vfe_msg_async_t1_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_async_t1_done;
+
+
+
+/*
+ * Message to notify the ARM that async t2 operation completed
+ */
+
+#define	VFE_MSG_ASYNC_T2_DONE		0x0010
+#define	VFE_MSG_ASYNC_T2_DONE_LEN	sizeof(vfe_msg_async_t2_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_async_t2_done;
+
+
+
+/*
+ * Message to notify the ARM that an error has occurred
+ */
+
+#define	VFE_MSG_ERROR		0x0011
+#define	VFE_MSG_ERROR_LEN	sizeof(vfe_msg_error)
+
+#define	VFE_MSG_ERR_COND_NO_CAMIF_ERR		0x0000
+#define	VFE_MSG_ERR_COND_CAMIF_ERR		0x0001
+#define	VFE_MSG_ERR_COND_OP1_Y_NO_BUS_OF	0x0000
+#define	VFE_MSG_ERR_COND_OP1_Y_BUS_OF		0x0002
+#define	VFE_MSG_ERR_COND_OP1_CBCR_NO_BUS_OF	0x0000
+#define	VFE_MSG_ERR_COND_OP1_CBCR_BUS_OF	0x0004
+#define	VFE_MSG_ERR_COND_OP2_Y_NO_BUS_OF	0x0000
+#define	VFE_MSG_ERR_COND_OP2_Y_BUS_OF		0x0008
+#define	VFE_MSG_ERR_COND_OP2_CBCR_NO_BUS_OF	0x0000
+#define	VFE_MSG_ERR_COND_OP2_CBCR_BUS_OF	0x0010
+#define	VFE_MSG_ERR_COND_AF_NO_BUS_OF		0x0000
+#define	VFE_MSG_ERR_COND_AF_BUS_OF		0x0020
+#define	VFE_MSG_ERR_COND_WB_EXP_NO_BUS_OF	0x0000
+#define	VFE_MSG_ERR_COND_WB_EXP_BUS_OF		0x0040
+#define	VFE_MSG_ERR_COND_NO_AXI_ERR		0x0000
+#define	VFE_MSG_ERR_COND_AXI_ERR		0x0080
+
+#define	VFE_MSG_CAMIF_STS_IDLE			0x0000
+#define	VFE_MSG_CAMIF_STS_CAPTURE_DATA		0x0001
+
+typedef struct {
+	unsigned int	err_cond;
+	unsigned int	camif_sts;
+} __attribute__((packed)) vfe_msg_error;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/remote_spinlock.h b/arch/arm/mach-msm/include/mach/remote_spinlock.h
new file mode 100644
index 0000000..6b25ec2
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/remote_spinlock.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ */
+
+#ifndef __ASM__ARCH_MSM_REMOTE_SPINLOCK_H
+#define __ASM__ARCH_MSM_REMOTE_SPINLOCK_H
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/* Remote spinlock type definitions. */
+struct raw_remote_spinlock;
+typedef struct {
+	spinlock_t			local;
+#if defined(CONFIG_MSM_REMOTE_SPINLOCK)
+	struct raw_remote_spinlock	*remote;
+#endif
+} remote_spinlock_t;
+
+#if defined(CONFIG_MSM_REMOTE_SPINLOCK)
+int _remote_spin_lock_init(remote_spinlock_t *lock, const char *name);
+void _remote_spin_lock(remote_spinlock_t *lock);
+void _remote_spin_unlock(remote_spinlock_t *lock);
+#else
+static inline int _remote_spin_lock_init(remote_spinlock_t *lock,
+					 const char *name) { return 0; }
+static inline void _remote_spin_lock(remote_spinlock_t *lock) { }
+static inline void _remote_spin_unlock(remote_spinlock_t *lock) { }
+#endif
+
+/* Note: only the below functions constitute the supported interface */
+static inline int remote_spin_lock_init(remote_spinlock_t *lock,
+					const char *name)
+{
+	spin_lock_init(&lock->local);
+	return _remote_spin_lock_init(lock, name);
+}
+
+#define remote_spin_lock(lock)				\
+	do {						\
+		typecheck(remote_spinlock_t *, lock);	\
+		spin_lock(&((lock)->local));		\
+		_remote_spin_lock(lock);		\
+	} while (0)
+
+#define remote_spin_unlock(lock)			\
+	do {						\
+		typecheck(remote_spinlock_t *, lock);	\
+		_remote_spin_unlock(lock);		\
+		spin_unlock(&((lock)->local));		\
+	} while (0)
+
+
+#define remote_spin_lock_irqsave(lock,flags)			\
+	do {							\
+		typecheck(remote_spinlock_t *, lock);		\
+		spin_lock_irqsave(&((lock)->local), (flags));	\
+		_remote_spin_lock(lock);			\
+	} while (0)
+
+#define remote_spin_unlock_irqrestore(lock,flags)			\
+	do {								\
+		typecheck(remote_spinlock_t *, lock);			\
+		_remote_spin_unlock(lock);				\
+		spin_unlock_irqrestore(&((lock)->local), (flags));	\
+	} while (0)
+
+#endif /* __ASM__ARCH_MSM_REMOTE_SPINLOCK_H */
diff --git a/arch/arm/mach-msm/include/mach/sirc.h b/arch/arm/mach-msm/include/mach/sirc.h
index 7281337..c23d429 100644
--- a/arch/arm/mach-msm/include/mach/sirc.h
+++ b/arch/arm/mach-msm/include/mach/sirc.h
@@ -42,6 +42,7 @@
 struct sirc_cascade_regs {
 	void    *int_status;
 	unsigned int    cascade_irq;
+	unsigned int    cascade_fiq;
 };
 
 void msm_init_sirc(void);
@@ -56,8 +57,6 @@
  * Secondary interrupt controller interrupts
  */
 
-#define FIRST_SIRC_IRQ (NR_MSM_IRQS + NR_GPIO_IRQS)
-
 #define INT_UART1                     (FIRST_SIRC_IRQ + 0)
 #define INT_UART2                     (FIRST_SIRC_IRQ + 1)
 #define INT_UART3                     (FIRST_SIRC_IRQ + 2)
diff --git a/arch/arm/mach-msm/include/mach/system.h b/arch/arm/mach-msm/include/mach/system.h
index d2e83f4..cdb049d 100644
--- a/arch/arm/mach-msm/include/mach/system.h
+++ b/arch/arm/mach-msm/include/mach/system.h
@@ -26,3 +26,6 @@
  * PSHOLD line on the PMIC to hard reset the system
  */
 extern void (*msm_hw_reset_hook)(void);
+
+void msm_set_i2c_mux(bool gpio, int *gpio_clk, int *gpio_dat);
+
diff --git a/arch/arm/mach-msm/include/mach/vmalloc.h b/arch/arm/mach-msm/include/mach/vmalloc.h
index 05f81fd..c915172 100644
--- a/arch/arm/mach-msm/include/mach/vmalloc.h
+++ b/arch/arm/mach-msm/include/mach/vmalloc.h
@@ -16,7 +16,9 @@
 #ifndef __ASM_ARCH_MSM_VMALLOC_H
 #define __ASM_ARCH_MSM_VMALLOC_H
 
-#define VMALLOC_END	  (PAGE_OFFSET + 0x10000000)
+/* IO devices are mapped at 0xF8000000 and above */
+
+#define VMALLOC_END	  0xF8000000
 
 #endif
 
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 1c05060..cc474e8 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -20,6 +20,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/module.h>
 
 #include <mach/hardware.h>
 #include <asm/page.h>
@@ -40,11 +41,13 @@
 static struct map_desc msm_io_desc[] __initdata = {
 	MSM_DEVICE(VIC),
 	MSM_DEVICE(CSR),
-	MSM_DEVICE(GPT),
+	MSM_DEVICE(TMR),
 	MSM_DEVICE(DMOV),
 	MSM_DEVICE(GPIO1),
 	MSM_DEVICE(GPIO2),
 	MSM_DEVICE(CLK_CTL),
+	MSM_DEVICE(AD5),
+	MSM_DEVICE(MDC),
 #ifdef CONFIG_MSM_DEBUG_UART
 	MSM_DEVICE(DEBUG_UART),
 #endif
@@ -83,6 +86,7 @@
 	MSM_DEVICE(SCPLL),
 	MSM_DEVICE(AD5),
 	MSM_DEVICE(MDC),
+	MSM_DEVICE(TCSR),
 #ifdef CONFIG_MSM_DEBUG_UART
 	MSM_DEVICE(DEBUG_UART),
 #endif
@@ -96,6 +100,19 @@
 
 void __init msm_map_qsd8x50_io(void)
 {
+	unsigned int unused;
+
+	/* The bootloader may not have done it, so disable predecode repair
+	 * cache for thumb2 (DPRC, set bit 4 in PVR0F2) due to a bug.
+	 */
+	asm volatile ("mrc p15, 0, %0, c15, c15, 2\n\t"
+		      "orr %0, %0, #0x10\n\t"
+		      "mcr p15, 0, %0, c15, c15, 2"
+		      : "=&r" (unused));
+	/* clear out EFSR and ADFSR on boot */
+	asm volatile ("mcr p15, 7, %0, c15, c0, 1\n\t"
+		      "mcr p15, 0, %0, c5, c1, 0"
+		      : : "r" (0));
 	iotable_init(qsd8x50_io_desc, ARRAY_SIZE(qsd8x50_io_desc));
 }
 #endif /* CONFIG_ARCH_QSD8X50 */
@@ -129,6 +146,10 @@
 
 void __init msm_map_msm7x30_io(void)
 {
+	/* clear out EFSR and ADFSR on boot */
+	asm volatile ("mcr p15, 7, %0, c15, c0, 1\n\t"
+		      "mcr p15, 0, %0, c5, c1, 0"
+		      : : "r" (0));
 	iotable_init(msm7x30_io_desc, ARRAY_SIZE(msm7x30_io_desc));
 }
 #endif /* CONFIG_ARCH_MSM7X30 */
@@ -136,6 +157,7 @@
 void __iomem *
 __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
 {
+#ifdef CONFIG_ARCH_MSM_ARM11
 	if (mtype == MT_DEVICE) {
 		/* The peripherals in the 88000000 - D0000000 range
 		 * are only accessable by type MT_DEVICE_NONSHARED.
@@ -144,7 +166,9 @@
 		if ((phys_addr >= 0x88000000) && (phys_addr < 0xD0000000))
 			mtype = MT_DEVICE_NONSHARED;
 	}
-
+#endif
 	return __arm_ioremap_caller(phys_addr, size, mtype,
 		__builtin_return_address(0));
 }
+
+EXPORT_SYMBOL(__msm_ioremap);
diff --git a/arch/arm/mach-msm/irq-vic.c b/arch/arm/mach-msm/irq-vic.c
deleted file mode 100644
index 99f2c34..0000000
--- a/arch/arm/mach-msm/irq-vic.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 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/init.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/timer.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <asm/cacheflush.h>
-
-#include <mach/hardware.h>
-
-#include <mach/msm_iomap.h>
-
-#include "smd_private.h"
-
-enum {
-	IRQ_DEBUG_SLEEP_INT_TRIGGER = 1U << 0,
-	IRQ_DEBUG_SLEEP_INT = 1U << 1,
-	IRQ_DEBUG_SLEEP_ABORT = 1U << 2,
-	IRQ_DEBUG_SLEEP = 1U << 3,
-	IRQ_DEBUG_SLEEP_REQUEST = 1U << 4,
-};
-static int msm_irq_debug_mask;
-module_param_named(debug_mask, msm_irq_debug_mask, int,
-		   S_IRUGO | S_IWUSR | S_IWGRP);
-
-#define VIC_REG(off) (MSM_VIC_BASE + (off))
-#define VIC_INT_TO_REG_ADDR(base, irq) (base + (irq / 32) * 4)
-#define VIC_INT_TO_REG_INDEX(irq) ((irq >> 5) & 3)
-
-#define VIC_INT_SELECT0     VIC_REG(0x0000)  /* 1: FIQ, 0: IRQ */
-#define VIC_INT_SELECT1     VIC_REG(0x0004)  /* 1: FIQ, 0: IRQ */
-#define VIC_INT_SELECT2     VIC_REG(0x0008)  /* 1: FIQ, 0: IRQ */
-#define VIC_INT_SELECT3     VIC_REG(0x000C)  /* 1: FIQ, 0: IRQ */
-#define VIC_INT_EN0         VIC_REG(0x0010)
-#define VIC_INT_EN1         VIC_REG(0x0014)
-#define VIC_INT_EN2         VIC_REG(0x0018)
-#define VIC_INT_EN3         VIC_REG(0x001C)
-#define VIC_INT_ENCLEAR0    VIC_REG(0x0020)
-#define VIC_INT_ENCLEAR1    VIC_REG(0x0024)
-#define VIC_INT_ENCLEAR2    VIC_REG(0x0028)
-#define VIC_INT_ENCLEAR3    VIC_REG(0x002C)
-#define VIC_INT_ENSET0      VIC_REG(0x0030)
-#define VIC_INT_ENSET1      VIC_REG(0x0034)
-#define VIC_INT_ENSET2      VIC_REG(0x0038)
-#define VIC_INT_ENSET3      VIC_REG(0x003C)
-#define VIC_INT_TYPE0       VIC_REG(0x0040)  /* 1: EDGE, 0: LEVEL  */
-#define VIC_INT_TYPE1       VIC_REG(0x0044)  /* 1: EDGE, 0: LEVEL  */
-#define VIC_INT_TYPE2       VIC_REG(0x0048)  /* 1: EDGE, 0: LEVEL  */
-#define VIC_INT_TYPE3       VIC_REG(0x004C)  /* 1: EDGE, 0: LEVEL  */
-#define VIC_INT_POLARITY0   VIC_REG(0x0050)  /* 1: NEG, 0: POS */
-#define VIC_INT_POLARITY1   VIC_REG(0x0054)  /* 1: NEG, 0: POS */
-#define VIC_INT_POLARITY2   VIC_REG(0x0058)  /* 1: NEG, 0: POS */
-#define VIC_INT_POLARITY3   VIC_REG(0x005C)  /* 1: NEG, 0: POS */
-#define VIC_NO_PEND_VAL     VIC_REG(0x0060)
-
-#if defined(CONFIG_ARCH_MSM_SCORPION)
-#define VIC_NO_PEND_VAL_FIQ VIC_REG(0x0064)
-#define VIC_INT_MASTEREN    VIC_REG(0x0068)  /* 1: IRQ, 2: FIQ     */
-#define VIC_CONFIG          VIC_REG(0x006C)  /* 1: USE SC VIC */
-#else
-#define VIC_INT_MASTEREN    VIC_REG(0x0064)  /* 1: IRQ, 2: FIQ     */
-#define VIC_PROTECTION      VIC_REG(0x006C)  /* 1: ENABLE          */
-#define VIC_CONFIG          VIC_REG(0x0068)  /* 1: USE ARM1136 VIC */
-#endif
-
-#define VIC_IRQ_STATUS0     VIC_REG(0x0080)
-#define VIC_IRQ_STATUS1     VIC_REG(0x0084)
-#define VIC_IRQ_STATUS2     VIC_REG(0x0088)
-#define VIC_IRQ_STATUS3     VIC_REG(0x008C)
-#define VIC_FIQ_STATUS0     VIC_REG(0x0090)
-#define VIC_FIQ_STATUS1     VIC_REG(0x0094)
-#define VIC_FIQ_STATUS2     VIC_REG(0x0098)
-#define VIC_FIQ_STATUS3     VIC_REG(0x009C)
-#define VIC_RAW_STATUS0     VIC_REG(0x00A0)
-#define VIC_RAW_STATUS1     VIC_REG(0x00A4)
-#define VIC_RAW_STATUS2     VIC_REG(0x00A8)
-#define VIC_RAW_STATUS3     VIC_REG(0x00AC)
-#define VIC_INT_CLEAR0      VIC_REG(0x00B0)
-#define VIC_INT_CLEAR1      VIC_REG(0x00B4)
-#define VIC_INT_CLEAR2      VIC_REG(0x00B8)
-#define VIC_INT_CLEAR3      VIC_REG(0x00BC)
-#define VIC_SOFTINT0        VIC_REG(0x00C0)
-#define VIC_SOFTINT1        VIC_REG(0x00C4)
-#define VIC_SOFTINT2        VIC_REG(0x00C8)
-#define VIC_SOFTINT3        VIC_REG(0x00CC)
-#define VIC_IRQ_VEC_RD      VIC_REG(0x00D0)  /* pending int # */
-#define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4)  /* pending vector addr */
-#define VIC_IRQ_VEC_WR      VIC_REG(0x00D8)
-
-#if defined(CONFIG_ARCH_MSM_SCORPION)
-#define VIC_FIQ_VEC_RD      VIC_REG(0x00DC)
-#define VIC_FIQ_VEC_PEND_RD VIC_REG(0x00E0)
-#define VIC_FIQ_VEC_WR      VIC_REG(0x00E4)
-#define VIC_IRQ_IN_SERVICE  VIC_REG(0x00E8)
-#define VIC_IRQ_IN_STACK    VIC_REG(0x00EC)
-#define VIC_FIQ_IN_SERVICE  VIC_REG(0x00F0)
-#define VIC_FIQ_IN_STACK    VIC_REG(0x00F4)
-#define VIC_TEST_BUS_SEL    VIC_REG(0x00F8)
-#define VIC_IRQ_CTRL_CONFIG VIC_REG(0x00FC)
-#else
-#define VIC_IRQ_IN_SERVICE  VIC_REG(0x00E0)
-#define VIC_IRQ_IN_STACK    VIC_REG(0x00E4)
-#define VIC_TEST_BUS_SEL    VIC_REG(0x00E8)
-#endif
-
-#define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
-#define VIC_VECTADDR(n)     VIC_REG(0x0400+((n) * 4))
-
-#if defined(CONFIG_ARCH_MSM7X30)
-#define VIC_NUM_REGS	    4
-#else
-#define VIC_NUM_REGS	    2
-#endif
-
-#if VIC_NUM_REGS == 2
-#define DPRINT_REGS(base_reg, format, ...)	      			\
-	printk(KERN_INFO format " %x %x\n", ##__VA_ARGS__,		\
-			readl(base_reg ## 0), readl(base_reg ## 1))
-#define DPRINT_ARRAY(array, format, ...)				\
-	printk(KERN_INFO format " %x %x\n", ##__VA_ARGS__,		\
-			array[0], array[1])
-#elif VIC_NUM_REGS == 4
-#define DPRINT_REGS(base_reg, format, ...) \
-	printk(KERN_INFO format " %x %x %x %x\n", ##__VA_ARGS__,	\
-			readl(base_reg ## 0), readl(base_reg ## 1),	\
-			readl(base_reg ## 2), readl(base_reg ## 3))
-#define DPRINT_ARRAY(array, format, ...)				\
-	printk(KERN_INFO format " %x %x %x %x\n", ##__VA_ARGS__,	\
-			array[0], array[1],				\
-			array[2], array[3])
-#else
-#error "VIC_NUM_REGS set to illegal value"
-#endif
-
-static uint32_t msm_irq_smsm_wake_enable[2];
-static struct {
-	uint32_t int_en[2];
-	uint32_t int_type;
-	uint32_t int_polarity;
-	uint32_t int_select;
-} msm_irq_shadow_reg[VIC_NUM_REGS];
-static uint32_t msm_irq_idle_disable[VIC_NUM_REGS];
-
-#define SMSM_FAKE_IRQ (0xff)
-static uint8_t msm_irq_to_smsm[NR_IRQS] = {
-	[INT_MDDI_EXT] = 1,
-	[INT_MDDI_PRI] = 2,
-	[INT_MDDI_CLIENT] = 3,
-	[INT_USB_OTG] = 4,
-
-	[INT_PWB_I2C] = 5,
-	[INT_SDC1_0] = 6,
-	[INT_SDC1_1] = 7,
-	[INT_SDC2_0] = 8,
-
-	[INT_SDC2_1] = 9,
-	[INT_ADSP_A9_A11] = 10,
-	[INT_UART1] = 11,
-	[INT_UART2] = 12,
-
-	[INT_UART3] = 13,
-	[INT_UART1_RX] = 14,
-	[INT_UART2_RX] = 15,
-	[INT_UART3_RX] = 16,
-
-	[INT_UART1DM_IRQ] = 17,
-	[INT_UART1DM_RX] = 18,
-	[INT_KEYSENSE] = 19,
-#if !defined(CONFIG_ARCH_MSM7X30)
-	[INT_AD_HSSD] = 20,
-#endif
-
-	[INT_NAND_WR_ER_DONE] = 21,
-	[INT_NAND_OP_DONE] = 22,
-	[INT_TCHSCRN1] = 23,
-	[INT_TCHSCRN2] = 24,
-
-	[INT_TCHSCRN_SSBI] = 25,
-	[INT_USB_HS] = 26,
-	[INT_UART2DM_RX] = 27,
-	[INT_UART2DM_IRQ] = 28,
-
-	[INT_SDC4_1] = 29,
-	[INT_SDC4_0] = 30,
-	[INT_SDC3_1] = 31,
-	[INT_SDC3_0] = 32,
-
-	/* fake wakeup interrupts */
-	[INT_GPIO_GROUP1] = SMSM_FAKE_IRQ,
-	[INT_GPIO_GROUP2] = SMSM_FAKE_IRQ,
-	[INT_A9_M2A_0] = SMSM_FAKE_IRQ,
-	[INT_A9_M2A_1] = SMSM_FAKE_IRQ,
-	[INT_A9_M2A_5] = SMSM_FAKE_IRQ,
-	[INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ,
-	[INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ,
-	[INT_ADSP_A11] = SMSM_FAKE_IRQ,
-#ifdef CONFIG_ARCH_QSD8X50
-	[INT_SIRC_0] = SMSM_FAKE_IRQ,
-	[INT_SIRC_1] = SMSM_FAKE_IRQ,
-#endif
-};
-
-static inline void msm_irq_write_all_regs(void __iomem *base, unsigned int val)
-{
-	int i;
-
-	for (i = 0; i < VIC_NUM_REGS; i++)
-		writel(val, base + (i * 4));
-}
-
-static void msm_irq_ack(unsigned int irq)
-{
-	void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_CLEAR0, irq);
-	irq = 1 << (irq & 31);
-	writel(irq, reg);
-}
-
-static void msm_irq_mask(unsigned int irq)
-{
-	void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENCLEAR0, irq);
-	unsigned index = VIC_INT_TO_REG_INDEX(irq);
-	uint32_t mask = 1UL << (irq & 31);
-	int smsm_irq = msm_irq_to_smsm[irq];
-
-	msm_irq_shadow_reg[index].int_en[0] &= ~mask;
-	writel(mask, reg);
-	if (smsm_irq == 0)
-		msm_irq_idle_disable[index] &= ~mask;
-	else {
-		mask = 1UL << (smsm_irq - 1);
-		msm_irq_smsm_wake_enable[0] &= ~mask;
-	}
-}
-
-static void msm_irq_unmask(unsigned int irq)
-{
-	void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENSET0, irq);
-	unsigned index = VIC_INT_TO_REG_INDEX(irq);
-	uint32_t mask = 1UL << (irq & 31);
-	int smsm_irq = msm_irq_to_smsm[irq];
-
-	msm_irq_shadow_reg[index].int_en[0] |= mask;
-	writel(mask, reg);
-
-	if (smsm_irq == 0)
-		msm_irq_idle_disable[index] |= mask;
-	else {
-		mask = 1UL << (smsm_irq - 1);
-		msm_irq_smsm_wake_enable[0] |= mask;
-	}
-}
-
-static int msm_irq_set_wake(unsigned int irq, unsigned int on)
-{
-	unsigned index = VIC_INT_TO_REG_INDEX(irq);
-	uint32_t mask = 1UL << (irq & 31);
-	int smsm_irq = msm_irq_to_smsm[irq];
-
-	if (smsm_irq == 0) {
-		printk(KERN_ERR "msm_irq_set_wake: bad wakeup irq %d\n", irq);
-		return -EINVAL;
-	}
-	if (on)
-		msm_irq_shadow_reg[index].int_en[1] |= mask;
-	else
-		msm_irq_shadow_reg[index].int_en[1] &= ~mask;
-
-	if (smsm_irq == SMSM_FAKE_IRQ)
-		return 0;
-
-	mask = 1UL << (smsm_irq - 1);
-	if (on)
-		msm_irq_smsm_wake_enable[1] |= mask;
-	else
-		msm_irq_smsm_wake_enable[1] &= ~mask;
-	return 0;
-}
-
-static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
-{
-	void __iomem *treg = VIC_INT_TO_REG_ADDR(VIC_INT_TYPE0, irq);
-	void __iomem *preg = VIC_INT_TO_REG_ADDR(VIC_INT_POLARITY0, irq);
-	unsigned index = VIC_INT_TO_REG_INDEX(irq);
-	int b = 1 << (irq & 31);
-	uint32_t polarity;
-	uint32_t type;
-
-	polarity = msm_irq_shadow_reg[index].int_polarity;
-	if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
-		polarity |= b;
-	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
-		polarity &= ~b;
-	writel(polarity, preg);
-	msm_irq_shadow_reg[index].int_polarity = polarity;
-
-	type = msm_irq_shadow_reg[index].int_type;
-	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
-		type |= b;
-		irq_desc[irq].handle_irq = handle_edge_irq;
-	}
-	if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
-		type &= ~b;
-		irq_desc[irq].handle_irq = handle_level_irq;
-	}
-	writel(type, treg);
-	msm_irq_shadow_reg[index].int_type = type;
-	return 0;
-}
-
-static struct irq_chip msm_irq_chip = {
-	.name      = "msm",
-	.disable   = msm_irq_mask,
-	.ack       = msm_irq_ack,
-	.mask      = msm_irq_mask,
-	.unmask    = msm_irq_unmask,
-	.set_wake  = msm_irq_set_wake,
-	.set_type  = msm_irq_set_type,
-};
-
-void __init msm_init_irq(void)
-{
-	unsigned n;
-
-	/* select level interrupts */
-	msm_irq_write_all_regs(VIC_INT_TYPE0, 0);
-
-	/* select highlevel interrupts */
-	msm_irq_write_all_regs(VIC_INT_POLARITY0, 0);
-
-	/* select IRQ for all INTs */
-	msm_irq_write_all_regs(VIC_INT_SELECT0, 0);
-
-	/* disable all INTs */
-	msm_irq_write_all_regs(VIC_INT_EN0, 0);
-
-	/* don't use vic */
-	writel(0, VIC_CONFIG);
-
-	/* enable interrupt controller */
-	writel(3, VIC_INT_MASTEREN);
-
-	for (n = 0; n < NR_MSM_IRQS; n++) {
-		set_irq_chip(n, &msm_irq_chip);
-		set_irq_handler(n, handle_level_irq);
-		set_irq_flags(n, IRQF_VALID);
-	}
-}
diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c
index 6c8d5f8..a29c1e6d 100644
--- a/arch/arm/mach-msm/irq.c
+++ b/arch/arm/mach-msm/irq.c
@@ -16,102 +16,473 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
 #include <linux/timer.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 
+#include <asm/cacheflush.h>
+
 #include <mach/hardware.h>
 
 #include <mach/msm_iomap.h>
+#include <mach/fiq.h>
+
+#include "sirc.h"
+#include "smd_private.h"
+
+enum {
+	IRQ_DEBUG_SLEEP_INT_TRIGGER = 1U << 0,
+	IRQ_DEBUG_SLEEP_INT = 1U << 1,
+	IRQ_DEBUG_SLEEP_ABORT = 1U << 2,
+	IRQ_DEBUG_SLEEP = 1U << 3,
+	IRQ_DEBUG_SLEEP_REQUEST = 1U << 4,
+};
+static int msm_irq_debug_mask;
+module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 #define VIC_REG(off) (MSM_VIC_BASE + (off))
+#define __bank(irq) (((irq) / 32) & 0x3)
 
-#define VIC_INT_SELECT0     VIC_REG(0x0000)  /* 1: FIQ, 0: IRQ */
-#define VIC_INT_SELECT1     VIC_REG(0x0004)  /* 1: FIQ, 0: IRQ */
-#define VIC_INT_EN0         VIC_REG(0x0010)
-#define VIC_INT_EN1         VIC_REG(0x0014)
-#define VIC_INT_ENCLEAR0    VIC_REG(0x0020)
-#define VIC_INT_ENCLEAR1    VIC_REG(0x0024)
-#define VIC_INT_ENSET0      VIC_REG(0x0030)
-#define VIC_INT_ENSET1      VIC_REG(0x0034)
-#define VIC_INT_TYPE0       VIC_REG(0x0040)  /* 1: EDGE, 0: LEVEL  */
-#define VIC_INT_TYPE1       VIC_REG(0x0044)  /* 1: EDGE, 0: LEVEL  */
-#define VIC_INT_POLARITY0   VIC_REG(0x0050)  /* 1: NEG, 0: POS */
-#define VIC_INT_POLARITY1   VIC_REG(0x0054)  /* 1: NEG, 0: POS */
+#define VIC_INT_SELECT(n)   VIC_REG(0x0000+((n) * 4)) /* 1: FIQ, 0: IRQ */
+#define VIC_INT_EN(n)       VIC_REG(0x0010+((n) * 4))
+#define VIC_INT_ENCLEAR(n)  VIC_REG(0x0020+((n) * 4))
+#define VIC_INT_ENSET(n)    VIC_REG(0x0030+((n) * 4))
+#define VIC_INT_TYPE(n)     VIC_REG(0x0040+((n) * 4)) /* 1: EDGE, 0: LEVEL */
+#define VIC_INT_POLARITY(n) VIC_REG(0x0050+((n) * 4)) /* 1: NEG, 0: POS */
 #define VIC_NO_PEND_VAL     VIC_REG(0x0060)
+
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+#define VIC_NO_PEND_VAL_FIQ VIC_REG(0x0064)
+#define VIC_INT_MASTEREN    VIC_REG(0x0068)  /* 1: IRQ, 2: FIQ     */
+#define VIC_CONFIG          VIC_REG(0x006C)  /* 1: USE SC VIC */
+#else
 #define VIC_INT_MASTEREN    VIC_REG(0x0064)  /* 1: IRQ, 2: FIQ     */
-#define VIC_PROTECTION      VIC_REG(0x006C)  /* 1: ENABLE          */
 #define VIC_CONFIG          VIC_REG(0x0068)  /* 1: USE ARM1136 VIC */
-#define VIC_IRQ_STATUS0     VIC_REG(0x0080)
-#define VIC_IRQ_STATUS1     VIC_REG(0x0084)
-#define VIC_FIQ_STATUS0     VIC_REG(0x0090)
-#define VIC_FIQ_STATUS1     VIC_REG(0x0094)
-#define VIC_RAW_STATUS0     VIC_REG(0x00A0)
-#define VIC_RAW_STATUS1     VIC_REG(0x00A4)
-#define VIC_INT_CLEAR0      VIC_REG(0x00B0)
-#define VIC_INT_CLEAR1      VIC_REG(0x00B4)
-#define VIC_SOFTINT0        VIC_REG(0x00C0)
-#define VIC_SOFTINT1        VIC_REG(0x00C4)
+#define VIC_PROTECTION      VIC_REG(0x006C)  /* 1: ENABLE          */
+#endif
+#define VIC_IRQ_STATUS(n)   VIC_REG(0x0080+((n) * 4))
+#define VIC_FIQ_STATUS(n)   VIC_REG(0x0090+((n) * 4))
+#define VIC_RAW_STATUS(n)   VIC_REG(0x00A0+((n) * 4))
+#define VIC_INT_CLEAR(n)    VIC_REG(0x00B0+((n) * 4))
+#define VIC_SOFTINT(n)      VIC_REG(0x00C0+((n) * 4))
 #define VIC_IRQ_VEC_RD      VIC_REG(0x00D0)  /* pending int # */
 #define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4)  /* pending vector addr */
 #define VIC_IRQ_VEC_WR      VIC_REG(0x00D8)
+
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+#define VIC_FIQ_VEC_RD      VIC_REG(0x00DC)
+#define VIC_FIQ_VEC_PEND_RD VIC_REG(0x00E0)
+#define VIC_FIQ_VEC_WR      VIC_REG(0x00E4)
+#define VIC_IRQ_IN_SERVICE  VIC_REG(0x00E8)
+#define VIC_IRQ_IN_STACK    VIC_REG(0x00EC)
+#define VIC_FIQ_IN_SERVICE  VIC_REG(0x00F0)
+#define VIC_FIQ_IN_STACK    VIC_REG(0x00F4)
+#define VIC_TEST_BUS_SEL    VIC_REG(0x00F8)
+#define VIC_IRQ_CTRL_CONFIG VIC_REG(0x00FC)
+#else
 #define VIC_IRQ_IN_SERVICE  VIC_REG(0x00E0)
 #define VIC_IRQ_IN_STACK    VIC_REG(0x00E4)
 #define VIC_TEST_BUS_SEL    VIC_REG(0x00E8)
+#endif
 
 #define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
 #define VIC_VECTADDR(n)     VIC_REG(0x0400+((n) * 4))
 
+#if defined(CONFIG_ARCH_MSM7X30)
+#define VIC_NUM_BANKS       4
+#else
+#define VIC_NUM_BANKS       2
+#endif
+
+static uint32_t msm_irq_smsm_wake_enable[2];
+static struct {
+	uint32_t int_en[2];
+	uint32_t int_type;
+	uint32_t int_polarity;
+	uint32_t int_select;
+} msm_irq_shadow_reg[VIC_NUM_BANKS];
+static uint32_t msm_irq_idle_disable[VIC_NUM_BANKS];
+
+#ifndef CONFIG_ARCH_MSM_SCORPION
+#define INT_INFO_SMSM_ID SMEM_SMSM_INT_INFO
+struct smsm_interrupt_info *smsm_int_info;
+#else
+#define INT_INFO_SMSM_ID SMEM_APPS_DEM_SLAVE_DATA
+struct msm_dem_slave_data *smsm_int_info;
+#endif
+
+
+#define SMSM_FAKE_IRQ (0xff)
+static uint8_t msm_irq_to_smsm[NR_MSM_IRQS + NR_SIRC_IRQS] = {
+	[INT_MDDI_EXT] = 1,
+	[INT_MDDI_PRI] = 2,
+	[INT_MDDI_CLIENT] = 3,
+	[INT_USB_OTG] = 4,
+
+	/* [INT_PWB_I2C] = 5 -- not usable */
+	[INT_SDC1_0] = 6,
+	[INT_SDC1_1] = 7,
+	[INT_SDC2_0] = 8,
+
+	[INT_SDC2_1] = 9,
+	[INT_ADSP_A9_A11] = 10,
+	[INT_UART1] = 11,
+	[INT_UART2] = 12,
+
+	[INT_UART3] = 13,
+	[INT_UART1_RX] = 14,
+	[INT_UART2_RX] = 15,
+	[INT_UART3_RX] = 16,
+
+	[INT_UART1DM_IRQ] = 17,
+	[INT_UART1DM_RX] = 18,
+	[INT_KEYSENSE] = 19,
+#if !defined(CONFIG_ARCH_MSM7X30)
+	[INT_AD_HSSD] = 20,
+#endif
+
+	[INT_NAND_WR_ER_DONE] = 21,
+	[INT_NAND_OP_DONE] = 22,
+	[INT_TCHSCRN1] = 23,
+	[INT_TCHSCRN2] = 24,
+
+	[INT_TCHSCRN_SSBI] = 25,
+	[INT_USB_HS] = 26,
+	[INT_UART2DM_RX] = 27,
+	[INT_UART2DM_IRQ] = 28,
+
+	[INT_SDC4_1] = 29,
+	[INT_SDC4_0] = 30,
+	[INT_SDC3_1] = 31,
+	[INT_SDC3_0] = 32,
+
+	/* fake wakeup interrupts */
+	[INT_GPIO_GROUP1] = SMSM_FAKE_IRQ,
+	[INT_GPIO_GROUP2] = SMSM_FAKE_IRQ,
+	[INT_A9_M2A_0] = SMSM_FAKE_IRQ,
+	[INT_A9_M2A_1] = SMSM_FAKE_IRQ,
+	[INT_A9_M2A_5] = SMSM_FAKE_IRQ,
+	[INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ,
+	[INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ,
+	[INT_ADSP_A11] = SMSM_FAKE_IRQ,
+
+#if defined(CONFIG_ARCH_QSD8X50)
+	[INT_SIRC_0] = SMSM_FAKE_IRQ,
+	[INT_SIRC_1] = SMSM_FAKE_IRQ,
+#endif
+};
+
 static void msm_irq_ack(unsigned int irq)
 {
-	void __iomem *reg = VIC_INT_CLEAR0 + ((irq & 32) ? 4 : 0);
+	void __iomem *reg = VIC_INT_CLEAR(__bank(irq));
 	irq = 1 << (irq & 31);
 	writel(irq, reg);
 }
 
 static void msm_irq_mask(unsigned int irq)
 {
-	void __iomem *reg = VIC_INT_ENCLEAR0 + ((irq & 32) ? 4 : 0);
-	writel(1 << (irq & 31), reg);
+	void __iomem *reg = VIC_INT_ENCLEAR(__bank(irq));
+	unsigned index = __bank(irq);
+	uint32_t mask = 1UL << (irq & 31);
+	int smsm_irq = msm_irq_to_smsm[irq];
+
+	msm_irq_shadow_reg[index].int_en[0] &= ~mask;
+	writel(mask, reg);
+	if (smsm_irq == 0)
+		msm_irq_idle_disable[index] &= ~mask;
+	else {
+		mask = 1UL << (smsm_irq - 1);
+		msm_irq_smsm_wake_enable[0] &= ~mask;
+	}
 }
 
 static void msm_irq_unmask(unsigned int irq)
 {
-	void __iomem *reg = VIC_INT_ENSET0 + ((irq & 32) ? 4 : 0);
-	writel(1 << (irq & 31), reg);
+	void __iomem *reg = VIC_INT_ENSET(__bank(irq));
+	unsigned index = __bank(irq);
+	uint32_t mask = 1UL << (irq & 31);
+	int smsm_irq = msm_irq_to_smsm[irq];
+
+	msm_irq_shadow_reg[index].int_en[0] |= mask;
+	writel(mask, reg);
+
+	if (smsm_irq == 0)
+		msm_irq_idle_disable[index] |= mask;
+	else {
+		mask = 1UL << (smsm_irq - 1);
+		msm_irq_smsm_wake_enable[0] |= mask;
+	}
 }
 
 static int msm_irq_set_wake(unsigned int irq, unsigned int on)
 {
-	return -EINVAL;
+	unsigned index = __bank(irq);
+	uint32_t mask = 1UL << (irq & 31);
+	int smsm_irq = msm_irq_to_smsm[irq];
+
+	if (smsm_irq == 0) {
+		printk(KERN_ERR "msm_irq_set_wake: bad wakeup irq %d\n", irq);
+		return -EINVAL;
+	}
+	if (on)
+		msm_irq_shadow_reg[index].int_en[1] |= mask;
+	else
+		msm_irq_shadow_reg[index].int_en[1] &= ~mask;
+
+	if (smsm_irq == SMSM_FAKE_IRQ)
+		return 0;
+
+	mask = 1UL << (smsm_irq - 1);
+	if (on)
+		msm_irq_smsm_wake_enable[1] |= mask;
+	else
+		msm_irq_smsm_wake_enable[1] &= ~mask;
+	return 0;
 }
 
 static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
 {
-	void __iomem *treg = VIC_INT_TYPE0 + ((irq & 32) ? 4 : 0);
-	void __iomem *preg = VIC_INT_POLARITY0 + ((irq & 32) ? 4 : 0);
+	void __iomem *treg = VIC_INT_TYPE(__bank(irq));
+	void __iomem *preg = VIC_INT_POLARITY(__bank(irq));
+	unsigned index = __bank(irq);
 	int b = 1 << (irq & 31);
+	uint32_t polarity;
+	uint32_t type;
 
+	polarity = msm_irq_shadow_reg[index].int_polarity;
 	if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
-		writel(readl(preg) | b, preg);
+		polarity |= b;
 	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
-		writel(readl(preg) & (~b), preg);
+		polarity &= ~b;
+	writel(polarity, preg);
+	msm_irq_shadow_reg[index].int_polarity = polarity;
 
+	type = msm_irq_shadow_reg[index].int_type;
 	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
-		writel(readl(treg) | b, treg);
+		type |= b;
 		irq_desc[irq].handle_irq = handle_edge_irq;
 	}
 	if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
-		writel(readl(treg) & (~b), treg);
+		type &= ~b;
 		irq_desc[irq].handle_irq = handle_level_irq;
 	}
+	writel(type, treg);
+	msm_irq_shadow_reg[index].int_type = type;
 	return 0;
 }
 
+int msm_irq_pending(void)
+{
+	int i;
+
+	for (i = 0; i < VIC_NUM_BANKS; ++i)
+		if (readl(VIC_IRQ_STATUS(i)))
+			return 1;
+	return 0;
+}
+
+static void print_vic_irq_stat(void)
+{
+	int i;
+
+	for (i = 0; i < VIC_NUM_BANKS; i++)
+		printk(" %x", readl(VIC_IRQ_STATUS(i)));
+	printk("\n");
+}
+
+static void print_irq_array(uint32_t *arr, int cnt)
+{
+	int i;
+
+	for (i = 0; i < cnt; i++)
+		printk(" %x", arr[i]);
+	printk("\n");
+}
+
+int msm_irq_idle_sleep_allowed(void)
+{
+	int i;
+
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_REQUEST) {
+		printk(KERN_INFO "%s: disable", __func__);
+		print_irq_array(msm_irq_idle_disable, VIC_NUM_BANKS);
+	}
+
+	for (i = 0; i < VIC_NUM_BANKS; ++i)
+		if (msm_irq_idle_disable[i])
+			return 0;
+	return !!smsm_int_info;
+}
+
+/* If arm9_wake is set: pass control to the other core.
+ * If from_idle is not set: disable non-wakeup interrupts.
+ */
+void msm_irq_enter_sleep1(bool arm9_wake, int from_idle)
+{
+	if (!arm9_wake || !smsm_int_info)
+		return;
+	smsm_int_info->interrupt_mask = msm_irq_smsm_wake_enable[!from_idle];
+	smsm_int_info->pending_interrupts = 0;
+}
+
+int msm_irq_enter_sleep2(bool arm9_wake, int from_idle)
+{
+	int limit = 10;
+	uint32_t pending[VIC_NUM_BANKS];
+	int i;
+	uint32_t any = 0;
+
+	if (from_idle && !arm9_wake)
+		return 0;
+
+	/* edge triggered interrupt may get lost if this mode is used */
+	WARN_ON_ONCE(!arm9_wake && !from_idle);
+
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) {
+		printk(KERN_INFO "%s: change irq, pend", __func__);
+		print_vic_irq_stat();
+	}
+
+	for (i = 0; i < VIC_NUM_BANKS; ++i) {
+		pending[i] = readl(VIC_IRQ_STATUS(i));
+		pending[i] &= msm_irq_shadow_reg[i].int_en[!from_idle];
+		/* Clear INT_A9_M2A_5 since requesting sleep triggers it */
+		if (i == (INT_A9_M2A_5 / 32))
+			pending[i] &= ~(1U << (INT_A9_M2A_5 % 32));
+		any |= pending[i];
+	}
+
+	if (any) {
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT) {
+			printk(KERN_INFO "%s abort", __func__);
+			print_irq_array(pending, VIC_NUM_BANKS);
+		}
+		return -EAGAIN;
+	}
+
+	for (i = 0; i < VIC_NUM_BANKS; ++i)
+		writel(0, VIC_INT_EN(i));
+
+	while (limit-- > 0) {
+		int pend_irq;
+		int irq = readl(VIC_IRQ_VEC_RD);
+		if (irq == -1)
+			break;
+		pend_irq = readl(VIC_IRQ_VEC_PEND_RD);
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
+			printk(KERN_INFO "msm_irq_enter_sleep cleared "
+			       "int %d (%d)\n", irq, pend_irq);
+	}
+
+	if (arm9_wake) {
+		msm_irq_set_type(INT_A9_M2A_6, IRQF_TRIGGER_RISING);
+		msm_irq_ack(INT_A9_M2A_6);
+		writel(1U << INT_A9_M2A_6, VIC_INT_ENSET(0));
+	} else {
+		for (i = 0; i < VIC_NUM_BANKS; ++i)
+			writel(msm_irq_shadow_reg[i].int_en[1],
+			       VIC_INT_ENSET(i));
+	}
+
+	return 0;
+}
+
+void msm_irq_exit_sleep1(void)
+{
+	int i;
+
+	msm_irq_ack(INT_A9_M2A_6);
+	msm_irq_ack(INT_PWB_I2C);
+	for (i = 0; i < VIC_NUM_BANKS; i++) {
+		writel(msm_irq_shadow_reg[i].int_type, VIC_INT_TYPE(i));
+		writel(msm_irq_shadow_reg[i].int_polarity, VIC_INT_POLARITY(i));
+		writel(msm_irq_shadow_reg[i].int_en[0], VIC_INT_EN(i));
+		writel(msm_irq_shadow_reg[i].int_select, VIC_INT_SELECT(i));
+	}
+	writel(3, VIC_INT_MASTEREN);
+	if (!smsm_int_info) {
+		printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n");
+		return;
+	}
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) {
+		printk(KERN_INFO "%s %x %x %x now", __func__,
+			smsm_int_info->interrupt_mask,
+			smsm_int_info->pending_interrupts,
+			smsm_int_info->wakeup_reason);
+		print_vic_irq_stat();
+	}
+}
+
+void msm_irq_exit_sleep2(void)
+{
+	int i;
+	uint32_t pending;
+
+	if (!smsm_int_info) {
+		printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n");
+		return;
+	}
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) {
+		printk(KERN_INFO "%s %x %x %x now", __func__,
+		       smsm_int_info->interrupt_mask,
+		       smsm_int_info->pending_interrupts,
+		       smsm_int_info->wakeup_reason);
+		print_vic_irq_stat();
+	}
+	pending = smsm_int_info->pending_interrupts;
+	for (i = 0; pending && i < ARRAY_SIZE(msm_irq_to_smsm); i++) {
+		unsigned bank = __bank(i);
+		uint32_t reg_mask = 1UL << (i & 31);
+		int smsm_irq = msm_irq_to_smsm[i];
+		uint32_t smsm_mask;
+		if (smsm_irq == 0)
+			continue;
+		smsm_mask = 1U << (smsm_irq - 1);
+		if (!(pending & smsm_mask))
+			continue;
+		pending &= ~smsm_mask;
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT) {
+			printk(KERN_INFO "%s: irq %d still pending %x now",
+			       __func__, i, pending);
+			print_vic_irq_stat();
+		}
+#if 0 /* debug intetrrupt trigger */
+		if (readl(VIC_IRQ_STATUS(bank)) & reg_mask)
+			writel(reg_mask, VIC_INT_CLEAR(bank));
+#endif
+		if (readl(VIC_IRQ_STATUS(bank)) & reg_mask)
+			continue;
+		writel(reg_mask, VIC_SOFTINT(bank));
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT_TRIGGER) {
+			printk(KERN_INFO "%s: irq %d need trigger, now",
+			       __func__, i);
+			print_vic_irq_stat();
+		}
+	}
+}
+
+void msm_irq_exit_sleep3(void)
+{
+	if (!smsm_int_info) {
+		printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n");
+		return;
+	}
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) {
+		printk(KERN_INFO "%s %x %x %x state %x now", __func__,
+		       smsm_int_info->interrupt_mask,
+		       smsm_int_info->pending_interrupts,
+		       smsm_int_info->wakeup_reason,
+		       smsm_get_state(SMSM_STATE_MODEM));
+		print_vic_irq_stat();
+	}
+}
+
 static struct irq_chip msm_irq_chip = {
 	.name      = "msm",
+	.disable   = msm_irq_mask,
 	.ack       = msm_irq_ack,
 	.mask      = msm_irq_mask,
 	.unmask    = msm_irq_unmask,
@@ -123,31 +494,157 @@
 {
 	unsigned n;
 
-	/* select level interrupts */
-	writel(0, VIC_INT_TYPE0);
-	writel(0, VIC_INT_TYPE1);
+	for (n = 0; n < VIC_NUM_BANKS; ++n) {
+		/* select level interrupts */
+		writel(0, VIC_INT_TYPE(n));
 
-	/* select highlevel interrupts */
-	writel(0, VIC_INT_POLARITY0);
-	writel(0, VIC_INT_POLARITY1);
+		/* select highlevel interrupts */
+		writel(0, VIC_INT_POLARITY(n));
 
-	/* select IRQ for all INTs */
-	writel(0, VIC_INT_SELECT0);
-	writel(0, VIC_INT_SELECT1);
+		/* select IRQ for all INTs */
+		writel(0, VIC_INT_SELECT(n));
 
-	/* disable all INTs */
-	writel(0, VIC_INT_EN0);
-	writel(0, VIC_INT_EN1);
+		/* disable all INTs */
+		writel(0, VIC_INT_EN(n));
+	}
 
 	/* don't use 1136 vic */
 	writel(0, VIC_CONFIG);
 
 	/* enable interrupt controller */
-	writel(1, VIC_INT_MASTEREN);
+	writel(3, VIC_INT_MASTEREN);
 
 	for (n = 0; n < NR_MSM_IRQS; n++) {
 		set_irq_chip(n, &msm_irq_chip);
 		set_irq_handler(n, handle_level_irq);
 		set_irq_flags(n, IRQF_VALID);
 	}
+
+	msm_init_sirc();
 }
+
+static int __init msm_init_irq_late(void)
+{
+	smsm_int_info = smem_alloc(INT_INFO_SMSM_ID, sizeof(*smsm_int_info));
+	if (!smsm_int_info)
+		pr_err("set_wakeup_mask NO INT_INFO (%d)\n", INT_INFO_SMSM_ID);
+	return 0;
+}
+late_initcall(msm_init_irq_late);
+
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+void msm_trigger_irq(int irq)
+{
+	void __iomem *reg = VIC_SOFTINT(__bank(irq));
+	uint32_t mask = 1UL << (irq & 31);
+	writel(mask, reg);
+}
+
+void msm_fiq_enable(int irq)
+{
+	unsigned long flags;
+	local_irq_save(flags);
+	irq_desc[irq].chip->unmask(irq);
+	local_irq_restore(flags);
+}
+
+void msm_fiq_disable(int irq)
+{
+	unsigned long flags;
+	local_irq_save(flags);
+	irq_desc[irq].chip->mask(irq);
+	local_irq_restore(flags);
+}
+
+static void _msm_fiq_select(int irq)
+{
+	void __iomem *reg = VIC_INT_SELECT(__bank(irq));
+	unsigned index = __bank(irq);
+	uint32_t mask = 1UL << (irq & 31);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	msm_irq_shadow_reg[index].int_select |= mask;
+	writel(msm_irq_shadow_reg[index].int_select, reg);
+	local_irq_restore(flags);
+}
+
+static void _msm_fiq_unselect(int irq)
+{
+	void __iomem *reg = VIC_INT_SELECT(__bank(irq));
+	unsigned index = __bank(irq);
+	uint32_t mask = 1UL << (irq & 31);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	msm_irq_shadow_reg[index].int_select &= (!mask);
+	writel(msm_irq_shadow_reg[index].int_select, reg);
+	local_irq_restore(flags);
+}
+
+void msm_fiq_select(int irq)
+{
+	if (irq < FIRST_SIRC_IRQ)
+		_msm_fiq_select(irq);
+	else if (irq < FIRST_GPIO_IRQ)
+		sirc_fiq_select(irq, true);
+	else
+		pr_err("unsupported fiq %d", irq);
+}
+
+void msm_fiq_unselect(int irq)
+{
+	if (irq < FIRST_SIRC_IRQ)
+		_msm_fiq_unselect(irq);
+	else if (irq < FIRST_GPIO_IRQ)
+		sirc_fiq_select(irq, false);
+	else
+		pr_err("unsupported fiq %d", irq);
+}
+
+/* set_fiq_handler originally from arch/arm/kernel/fiq.c */
+static void set_fiq_handler(void *start, unsigned int length)
+{
+	memcpy((void *)0xffff001c, start, length);
+	flush_icache_range(0xffff001c, 0xffff001c + length);
+	if (!vectors_high())
+		flush_icache_range(0x1c, 0x1c + length);
+}
+
+extern unsigned char fiq_glue, fiq_glue_end;
+
+static void (*fiq_func)(void *data, void *regs, void *svc_sp);
+static void *fiq_data;
+static void *fiq_stack;
+
+void fiq_glue_setup(void *func, void *data, void *sp);
+
+int msm_fiq_set_handler(void (*func)(void *data, void *regs, void *svc_sp),
+			void *data)
+{
+	unsigned long flags;
+	int ret = -ENOMEM;
+
+	if (!fiq_stack)
+		fiq_stack = kzalloc(THREAD_SIZE, GFP_KERNEL);
+	if (!fiq_stack)
+		return -ENOMEM;
+
+	local_irq_save(flags);
+	if (fiq_func == 0) {
+		fiq_func = func;
+		fiq_data = data;
+		fiq_glue_setup(func, data, fiq_stack + THREAD_START_SP);
+		set_fiq_handler(&fiq_glue, (&fiq_glue_end - &fiq_glue));
+		ret = 0;
+	}
+	local_irq_restore(flags);
+	return ret;
+}
+
+void msm_fiq_exit_sleep(void)
+{
+	if (fiq_stack)
+		fiq_glue_setup(fiq_func, fiq_data, fiq_stack + THREAD_START_SP);
+}
+#endif
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
new file mode 100644
index 0000000..3be79d8
--- /dev/null
+++ b/arch/arm/mach-msm/memory.c
@@ -0,0 +1,29 @@
+/* arch/arm/mach-msm/memory.c
+ *
+ * Copyright (C) 2007 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/mm.h>
+#include <linux/mm_types.h>
+#include <asm/pgtable.h>
+
+int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
+			    unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+	unsigned long pfn_addr = pfn << PAGE_SHIFT;
+	if ((pfn_addr >= 0x88000000) && (pfn_addr < 0xD0000000)) {
+		prot = pgprot_device(prot);
+		printk("remapping device %lx\n", prot);
+	}
+	return remap_pfn_range(vma, addr, pfn, size, prot);
+}
diff --git a/arch/arm/mach-msm/msm_vibrator.c b/arch/arm/mach-msm/msm_vibrator.c
new file mode 100644
index 0000000..8b81741
--- /dev/null
+++ b/arch/arm/mach-msm/msm_vibrator.c
@@ -0,0 +1,134 @@
+/* include/asm/mach-msm/htc_pwrsink.h
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * Copyright (C) 2007 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/platform_device.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <../../../drivers/staging/android/timed_output.h>
+#include <linux/sched.h>
+
+#include <mach/msm_rpcrouter.h>
+
+#define PM_LIBPROG	  0x30000061
+#if defined(CONFIG_ARCH_MSM7X30)
+#define PM_LIBVERS        0x00030001
+#elif defined(CONFIG_MSM_LEGACY_7X00A_AMSS)
+#define PM_LIBVERS	  0xfb837d0b
+#else
+#define PM_LIBVERS	  MSM_RPC_VERS(1,1)
+#endif
+
+#if defined(CONFIG_ARCH_QSD8X50)  || defined(CONFIG_ARCH_MSM7X30)
+#define HTC_PROCEDURE_SET_VIB_ON_OFF	22
+#else
+#define HTC_PROCEDURE_SET_VIB_ON_OFF	21
+#endif
+#define PMIC_VIBRATOR_LEVEL	(3000)
+
+static struct work_struct vibrator_work;
+static struct hrtimer vibe_timer;
+static spinlock_t vibe_lock;
+static int vibe_state;
+
+static void set_pmic_vibrator(int on)
+{
+	static struct msm_rpc_endpoint *vib_endpoint;
+	struct set_vib_on_off_req {
+		struct rpc_request_hdr hdr;
+		uint32_t data;
+	} req;
+
+	if (!vib_endpoint) {
+		vib_endpoint = msm_rpc_connect(PM_LIBPROG, PM_LIBVERS, 0);
+		if (IS_ERR(vib_endpoint)) {
+			printk(KERN_ERR "init vib rpc failed!\n");
+			vib_endpoint = 0;
+			return;
+		}
+	}
+
+	if (on)
+		req.data = cpu_to_be32(PMIC_VIBRATOR_LEVEL);
+	else
+		req.data = cpu_to_be32(0);
+
+	msm_rpc_call(vib_endpoint, HTC_PROCEDURE_SET_VIB_ON_OFF, &req,
+		sizeof(req), 5 * HZ);
+}
+
+static void update_vibrator(struct work_struct *work)
+{
+	set_pmic_vibrator(vibe_state);
+}
+
+static void vibrator_enable(struct timed_output_dev *dev, int value)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave(&vibe_lock, flags);
+	hrtimer_cancel(&vibe_timer);
+
+	if (value == 0)
+		vibe_state = 0;
+	else {
+		value = (value > 15000 ? 15000 : value);
+		vibe_state = 1;
+		hrtimer_start(&vibe_timer,
+			ktime_set(value / 1000, (value % 1000) * 1000000),
+			HRTIMER_MODE_REL);
+	}
+	spin_unlock_irqrestore(&vibe_lock, flags);
+
+	schedule_work(&vibrator_work);
+}
+
+static int vibrator_get_time(struct timed_output_dev *dev)
+{
+	if (hrtimer_active(&vibe_timer)) {
+		ktime_t r = hrtimer_get_remaining(&vibe_timer);
+		return r.tv.sec * 1000 + r.tv.nsec / 1000000;
+	} else
+		return 0;
+}
+
+static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer)
+{
+	vibe_state = 0;
+	schedule_work(&vibrator_work);
+	return HRTIMER_NORESTART;
+}
+
+static struct timed_output_dev pmic_vibrator = {
+	.name = "vibrator",
+	.get_time = vibrator_get_time,
+	.enable = vibrator_enable,
+};
+
+void __init msm_init_pmic_vibrator(void)
+{
+	INIT_WORK(&vibrator_work, update_vibrator);
+
+	spin_lock_init(&vibe_lock);
+	vibe_state = 0;
+	hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	vibe_timer.function = vibrator_timer_func;
+
+	timed_output_dev_register(&pmic_vibrator);
+}
+
+MODULE_DESCRIPTION("timed output pmic vibrator device");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/nand_partitions.c b/arch/arm/mach-msm/nand_partitions.c
new file mode 100644
index 0000000..4361e49
--- /dev/null
+++ b/arch/arm/mach-msm/nand_partitions.c
@@ -0,0 +1,128 @@
+/* arch/arm/mach-msm/nand_partitions.c
+ *
+ * Code to extract partition information from ATAG set up by the
+ * bootloader.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/flash.h>
+#include <asm/io.h>
+
+#include <asm/setup.h>
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <mach/msm_iomap.h>
+
+#include <mach/board.h>
+
+
+/* configuration tags specific to msm */
+
+#define ATAG_MSM_PARTITION 0x4d534D70 /* MSMp */
+
+struct msm_ptbl_entry
+{
+	char name[16];
+	__u32 offset;
+	__u32 size;
+	__u32 flags;
+};
+
+#define MSM_MAX_PARTITIONS 8
+
+static struct mtd_partition msm_nand_partitions[MSM_MAX_PARTITIONS];
+static char msm_nand_names[MSM_MAX_PARTITIONS * 16];
+
+extern struct flash_platform_data msm_nand_data;
+
+static int __init parse_tag_msm_partition(const struct tag *tag)
+{
+	struct mtd_partition *ptn = msm_nand_partitions;
+	char *name = msm_nand_names;
+	struct msm_ptbl_entry *entry = (void *) &tag->u;
+	unsigned count, n;
+	unsigned have_kpanic = 0;
+
+	count = (tag->hdr.size - 2) /
+		(sizeof(struct msm_ptbl_entry) / sizeof(__u32));
+
+	if (count > MSM_MAX_PARTITIONS)
+		count = MSM_MAX_PARTITIONS;
+
+	for (n = 0; n < count; n++) {
+		memcpy(name, entry->name, 15);
+		name[15] = 0;
+
+		if (!strcmp(name, "kpanic"))
+			have_kpanic = 1;
+
+		ptn->name = name;
+		ptn->offset = entry->offset;
+		ptn->size = entry->size;
+
+		name += 16;
+		entry++;
+		ptn++;
+	}
+
+#ifdef CONFIG_VIRTUAL_KPANIC_PARTITION
+	if (!have_kpanic) {
+		int i;
+		uint64_t kpanic_off = 0;
+
+		if (count == MSM_MAX_PARTITIONS) {
+			printk("Cannot create virtual 'kpanic' partition\n");
+			goto out;
+		}
+
+		for (i = 0; i < count; i++) {
+			ptn = &msm_nand_partitions[i];
+			if (!strcmp(ptn->name, CONFIG_VIRTUAL_KPANIC_SRC)) {
+				ptn->size -= CONFIG_VIRTUAL_KPANIC_PSIZE;
+				kpanic_off = ptn->offset + ptn->size;
+				break;
+			}
+		}
+		if (i == count) {
+			printk(KERN_ERR "Partition %s not found\n",
+			       CONFIG_VIRTUAL_KPANIC_SRC);
+			goto out;
+		}
+
+		ptn = &msm_nand_partitions[count];
+		ptn->name ="kpanic";
+		ptn->offset = kpanic_off;
+		ptn->size = CONFIG_VIRTUAL_KPANIC_PSIZE;
+
+		printk("Virtual mtd partition '%s' created @%llx (%llu)\n",
+		       ptn->name, ptn->offset, ptn->size);
+
+		count++;
+	}
+out:
+#endif /* CONFIG_VIRTUAL_KPANIC_SRC */
+	msm_nand_data.nr_parts = count;
+	msm_nand_data.parts = msm_nand_partitions;
+
+	return 0;
+}
+
+__tagtable(ATAG_MSM_PARTITION, parse_tag_msm_partition);
diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c
new file mode 100644
index 0000000..8fd3689
--- /dev/null
+++ b/arch/arm/mach-msm/pm.c
@@ -0,0 +1,794 @@
+/* arch/arm/mach-msm/pm.c
+ *
+ * MSM Power Management Routines
+ *
+ * Copyright (C) 2007 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/module.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/proc_fs.h>
+#include <linux/suspend.h>
+#include <linux/reboot.h>
+#include <linux/earlysuspend.h>
+#include <mach/msm_iomap.h>
+#include <mach/system.h>
+#include <asm/io.h>
+
+#include "smd_private.h"
+#include "acpuclock.h"
+#include "proc_comm.h"
+#include "clock.h"
+#ifdef CONFIG_HAS_WAKELOCK
+#include <linux/wakelock.h>
+#endif
+
+enum {
+	MSM_PM_DEBUG_SUSPEND = 1U << 0,
+	MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1,
+	MSM_PM_DEBUG_STATE = 1U << 2,
+	MSM_PM_DEBUG_CLOCK = 1U << 3,
+	MSM_PM_DEBUG_RESET_VECTOR = 1U << 4,
+	MSM_PM_DEBUG_SMSM_STATE = 1U << 5,
+	MSM_PM_DEBUG_IDLE = 1U << 6,
+	MSM_PM_DEBUG_CLOCK_VOTE = 1U << 7
+};
+static int msm_pm_debug_mask = MSM_PM_DEBUG_CLOCK_VOTE;
+module_param_named(debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+enum {
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+	MSM_PM_SLEEP_MODE_APPS_SLEEP,
+	MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT,
+	MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+};
+static int msm_pm_sleep_mode = CONFIG_MSM7X00A_SLEEP_MODE;
+module_param_named(sleep_mode, msm_pm_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int msm_pm_idle_sleep_mode = CONFIG_MSM7X00A_IDLE_SLEEP_MODE;
+module_param_named(idle_sleep_mode, msm_pm_idle_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME;
+module_param_named(idle_sleep_min_time, msm_pm_idle_sleep_min_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int msm_pm_idle_spin_time = CONFIG_MSM7X00A_IDLE_SPIN_TIME;
+module_param_named(idle_spin_time, msm_pm_idle_spin_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define A11S_CLK_SLEEP_EN (MSM_GCC_BASE + 0x020)
+#define A11S_PWRDOWN      (MSM_ACC_BASE + 0x01c)
+#define A11S_SECOP        (MSM_TCSR_BASE + 0x038)
+#else
+#define A11S_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
+#define A11S_PWRDOWN (MSM_CSR_BASE + 0x440)
+#define A11S_STANDBY_CTL (MSM_CSR_BASE + 0x108)
+#define A11RAMBACKBIAS (MSM_CSR_BASE + 0x508)
+#endif
+
+
+#define DEM_MASTER_BITS_PER_CPU             6
+
+/* Power Master State Bits - Per CPU */
+#define DEM_MASTER_SMSM_RUN \
+        (0x01UL << (DEM_MASTER_BITS_PER_CPU * SMSM_STATE_APPS))
+#define DEM_MASTER_SMSM_RSA \
+        (0x02UL << (DEM_MASTER_BITS_PER_CPU * SMSM_STATE_APPS))
+#define DEM_MASTER_SMSM_PWRC_EARLY_EXIT \
+        (0x04UL << (DEM_MASTER_BITS_PER_CPU * SMSM_STATE_APPS))
+#define DEM_MASTER_SMSM_SLEEP_EXIT \
+        (0x08UL << (DEM_MASTER_BITS_PER_CPU * SMSM_STATE_APPS))
+#define DEM_MASTER_SMSM_READY \
+        (0x10UL << (DEM_MASTER_BITS_PER_CPU * SMSM_STATE_APPS))
+#define DEM_MASTER_SMSM_SLEEP \
+        (0x20UL << (DEM_MASTER_BITS_PER_CPU * SMSM_STATE_APPS))
+
+/* Power Slave State Bits */
+#define DEM_SLAVE_SMSM_RUN                  (0x0001)
+#define DEM_SLAVE_SMSM_PWRC                 (0x0002)
+#define DEM_SLAVE_SMSM_PWRC_DELAY           (0x0004)
+#define DEM_SLAVE_SMSM_PWRC_EARLY_EXIT      (0x0008)
+#define DEM_SLAVE_SMSM_WFPI                 (0x0010)
+#define DEM_SLAVE_SMSM_SLEEP                (0x0020)
+#define DEM_SLAVE_SMSM_SLEEP_EXIT           (0x0040)
+#define DEM_SLAVE_SMSM_MSGS_REDUCED         (0x0080)
+#define DEM_SLAVE_SMSM_RESET                (0x0100)
+#define DEM_SLAVE_SMSM_PWRC_SUSPEND         (0x0200)
+
+#ifndef CONFIG_ARCH_MSM_SCORPION
+#define PM_SMSM_WRITE_STATE	SMSM_STATE_APPS
+#define PM_SMSM_READ_STATE	SMSM_STATE_MODEM
+
+#define PM_SMSM_WRITE_RUN	SMSM_RUN
+#define PM_SMSM_READ_RUN	SMSM_RUN
+#else
+#define PM_SMSM_WRITE_STATE	SMSM_STATE_APPS_DEM
+#define PM_SMSM_READ_STATE	SMSM_STATE_POWER_MASTER_DEM
+
+#define PM_SMSM_WRITE_RUN	DEM_SLAVE_SMSM_RUN
+#define PM_SMSM_READ_RUN	DEM_MASTER_SMSM_RUN
+#endif
+
+int msm_pm_collapse(void);
+int msm_arch_idle(void);
+void msm_pm_collapse_exit(void);
+
+int64_t msm_timer_enter_idle(void);
+void msm_timer_exit_idle(int low_power);
+int msm_irq_idle_sleep_allowed(void);
+int msm_irq_pending(void);
+int clks_print_running(void);
+
+static int axi_rate;
+static int sleep_axi_rate;
+static struct clk *axi_clk;
+static uint32_t *msm_pm_reset_vector;
+
+static uint32_t msm_pm_max_sleep_time;
+
+#ifdef CONFIG_MSM_IDLE_STATS
+enum msm_pm_time_stats_id {
+	MSM_PM_STAT_REQUESTED_IDLE,
+	MSM_PM_STAT_IDLE_SPIN,
+	MSM_PM_STAT_IDLE_WFI,
+	MSM_PM_STAT_IDLE_SLEEP,
+	MSM_PM_STAT_IDLE_FAILED_SLEEP,
+	MSM_PM_STAT_NOT_IDLE,
+	MSM_PM_STAT_COUNT
+};
+
+static struct msm_pm_time_stats {
+	const char *name;
+	int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int count;
+	int64_t total_time;
+} msm_pm_stats[MSM_PM_STAT_COUNT] = {
+	[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request",
+	[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin",
+	[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi",
+	[MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep",
+	[MSM_PM_STAT_IDLE_FAILED_SLEEP].name = "idle-failed-sleep",
+	[MSM_PM_STAT_NOT_IDLE].name = "not-idle",
+};
+
+static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+	int i;
+	int64_t bt;
+	msm_pm_stats[id].total_time += t;
+	msm_pm_stats[id].count++;
+	bt = t;
+	do_div(bt, CONFIG_MSM_IDLE_STATS_FIRST_BUCKET);
+	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
+				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+		i = DIV_ROUND_UP(fls((uint32_t)bt),
+					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+	else
+		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+	msm_pm_stats[id].bucket[i]++;
+	if (t < msm_pm_stats[id].min_time[i] || !msm_pm_stats[id].max_time[i])
+		msm_pm_stats[id].min_time[i] = t;
+	if (t > msm_pm_stats[id].max_time[i])
+		msm_pm_stats[id].max_time[i] = t;
+}
+#endif
+
+static int
+msm_pm_wait_state(uint32_t wait_all_set, uint32_t wait_all_clear,
+                  uint32_t wait_any_set, uint32_t wait_any_clear)
+{
+	int i;
+	uint32_t state;
+
+	for (i = 0; i < 100000; i++) {
+		state = smsm_get_state(PM_SMSM_READ_STATE);
+		if (((wait_all_set || wait_all_clear) && 
+		     !(~state & wait_all_set) && !(state & wait_all_clear)) ||
+		    (state & wait_any_set) || (~state & wait_any_clear))
+			return 0;
+		udelay(1);
+	}
+	pr_err("msm_pm_wait_state(%x, %x, %x, %x) failed %x\n",	wait_all_set,
+		wait_all_clear, wait_any_set, wait_any_clear, state);
+	return -ETIMEDOUT;
+}
+
+static void
+msm_pm_enter_prep_hw(void)
+{
+#if defined(CONFIG_ARCH_MSM7X30)
+	writel(1, A11S_PWRDOWN);
+	writel(4, A11S_SECOP);
+#else
+#if defined(CONFIG_ARCH_QSD8X50)
+	writel(0x1b, A11S_CLK_SLEEP_EN);
+#else
+	writel(0x1f, A11S_CLK_SLEEP_EN);
+#endif
+	writel(1, A11S_PWRDOWN);
+	writel(0, A11S_STANDBY_CTL);
+
+#if defined(CONFIG_ARCH_MSM_ARM11)
+	writel(0, A11RAMBACKBIAS);
+#endif
+#endif
+}
+
+static void
+msm_pm_exit_restore_hw(void)
+{
+#if defined(CONFIG_ARCH_MSM7X30)
+	writel(0, A11S_SECOP);
+	writel(0, A11S_PWRDOWN);
+#else
+	writel(0x00, A11S_CLK_SLEEP_EN);
+	writel(0, A11S_PWRDOWN);
+#endif
+}
+
+#ifdef CONFIG_MSM_FIQ_SUPPORT
+void msm_fiq_exit_sleep(void);
+#else
+static inline void msm_fiq_exit_sleep(void) { }
+#endif
+
+static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle)
+{
+	uint32_t saved_vector[2];
+	int collapsed;
+	void msm_irq_enter_sleep1(bool arm9_wake, int from_idle);
+	int msm_irq_enter_sleep2(bool arm9_wake, int from_idle);
+	void msm_irq_exit_sleep1(void);
+	void msm_irq_exit_sleep2(void);
+	void msm_irq_exit_sleep3(void);
+	void msm_gpio_enter_sleep(int from_idle);
+	void msm_gpio_exit_sleep(void);
+	void smd_sleep_exit(void);
+	uint32_t enter_state;
+	uint32_t enter_wait_set = 0;
+	uint32_t enter_wait_clear = 0;
+	uint32_t exit_state;
+	uint32_t exit_wait_clear = 0;
+	uint32_t exit_wait_any_set = 0;
+	unsigned long pm_saved_acpu_clk_rate = 0;
+	int ret;
+	int rv = -EINTR;
+	bool invalid_inital_state = false;
+
+	if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
+		printk(KERN_INFO "msm_sleep(): mode %d delay %u idle %d\n",
+		       sleep_mode, sleep_delay, from_idle);
+
+#ifndef CONFIG_ARCH_MSM_SCORPION
+	switch (sleep_mode) {
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		enter_state = SMSM_PWRC;
+		enter_wait_set = SMSM_RSA;
+		exit_state = SMSM_WFPI;
+		exit_wait_clear = SMSM_RSA;
+		break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
+		enter_state = SMSM_PWRC_SUSPEND;
+		enter_wait_set = SMSM_RSA;
+		exit_state = SMSM_WFPI;
+		exit_wait_clear = SMSM_RSA;
+		break;
+	case MSM_PM_SLEEP_MODE_APPS_SLEEP:
+		enter_state = SMSM_SLEEP;
+		exit_state = SMSM_SLEEPEXIT;
+		exit_wait_any_set = SMSM_SLEEPEXIT;
+		break;
+	default:
+		enter_state = 0;
+		exit_state = 0;
+	}
+#else
+	switch (sleep_mode) {
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		enter_state = DEM_SLAVE_SMSM_PWRC;
+		enter_wait_set = DEM_MASTER_SMSM_RSA;
+		exit_state = DEM_SLAVE_SMSM_WFPI;
+		exit_wait_any_set =
+			DEM_MASTER_SMSM_RUN | DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
+		break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
+		enter_state = DEM_SLAVE_SMSM_PWRC_SUSPEND;
+		enter_wait_set = DEM_MASTER_SMSM_RSA;
+		exit_state = DEM_SLAVE_SMSM_WFPI;
+		exit_wait_any_set =
+			DEM_MASTER_SMSM_RUN | DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
+		break;
+	case MSM_PM_SLEEP_MODE_APPS_SLEEP:
+		enter_state = DEM_SLAVE_SMSM_SLEEP;
+		enter_wait_set = DEM_MASTER_SMSM_SLEEP;
+		exit_state = DEM_SLAVE_SMSM_SLEEP_EXIT;
+		exit_wait_any_set = DEM_MASTER_SMSM_SLEEP_EXIT;
+		break;
+	default:
+		enter_state = 0;
+		exit_state = 0;
+	}
+#endif
+
+	clk_enter_sleep(from_idle);
+	msm_irq_enter_sleep1(!!enter_state, from_idle);
+	msm_gpio_enter_sleep(from_idle);
+
+	if (enter_state) {
+		/* Make sure last sleep request did not end with a timeout */
+		ret = msm_pm_wait_state(PM_SMSM_READ_RUN, 0, 0, 0);
+		if (ret) {
+			printk(KERN_ERR "msm_sleep(): invalid inital state\n");
+			invalid_inital_state = true;
+		}
+
+		if (sleep_delay == 0 && sleep_mode >= MSM_PM_SLEEP_MODE_APPS_SLEEP)
+			sleep_delay = 192000*5; /* APPS_SLEEP does not allow infinite timeout */
+		ret = smsm_set_sleep_duration(sleep_delay);
+		if (ret) {
+			printk(KERN_ERR "msm_sleep(): smsm_set_sleep_duration %x failed\n", enter_state);
+			enter_state = 0;
+			exit_state = 0;
+		}
+		if ((!from_idle && (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK_VOTE)) ||
+			(from_idle && (msm_pm_debug_mask & MSM_PM_DEBUG_IDLE)))
+			clks_print_running();
+
+		ret = smsm_change_state(PM_SMSM_WRITE_STATE, PM_SMSM_WRITE_RUN, enter_state);
+		if (ret) {
+			printk(KERN_ERR "msm_sleep(): smsm_change_state %x failed\n", enter_state);
+			enter_state = 0;
+			exit_state = 0;
+		}
+		ret = msm_pm_wait_state(enter_wait_set, enter_wait_clear, 0, 0);
+		if (ret || invalid_inital_state) {
+			printk(KERN_INFO "msm_sleep(): msm_pm_wait_state failed, %x\n", smsm_get_state(PM_SMSM_READ_STATE));
+			goto enter_failed;
+		}
+	}
+	if (msm_irq_enter_sleep2(!!enter_state, from_idle))
+		goto enter_failed;
+
+	if (enter_state) {
+		msm_pm_enter_prep_hw();
+
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
+			printk(KERN_INFO "msm_sleep(): enter "
+			       "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
+			       "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN),
+			       readl(A11S_PWRDOWN), smsm_get_state(PM_SMSM_READ_STATE));
+	}
+
+	if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) {
+		pm_saved_acpu_clk_rate = acpuclk_power_collapse();
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
+			printk(KERN_INFO "msm_sleep(): %ld enter power collapse"
+			       "\n", pm_saved_acpu_clk_rate);
+		if (pm_saved_acpu_clk_rate == 0)
+			goto ramp_down_failed;
+
+		/* Drop AXI request when the screen is on */
+		if (axi_rate)
+			clk_set_rate(axi_clk, sleep_axi_rate);
+	}
+	if (sleep_mode < MSM_PM_SLEEP_MODE_APPS_SLEEP) {
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
+			smsm_print_sleep_info();
+		saved_vector[0] = msm_pm_reset_vector[0];
+		saved_vector[1] = msm_pm_reset_vector[1];
+		msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
+		msm_pm_reset_vector[1] = virt_to_phys(msm_pm_collapse_exit);
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_RESET_VECTOR)
+			printk(KERN_INFO "msm_sleep(): vector %x %x -> "
+			       "%x %x\n", saved_vector[0], saved_vector[1],
+			       msm_pm_reset_vector[0], msm_pm_reset_vector[1]);
+		collapsed = msm_pm_collapse();
+		msm_pm_reset_vector[0] = saved_vector[0];
+		msm_pm_reset_vector[1] = saved_vector[1];
+		if (collapsed) {
+			cpu_init();
+			__asm__("cpsie   a");
+			msm_fiq_exit_sleep();
+			local_fiq_enable();
+			rv = 0;
+		}
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_POWER_COLLAPSE)
+			printk(KERN_INFO "msm_pm_collapse(): returned %d\n",
+			       collapsed);
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
+			smsm_print_sleep_info();
+	} else {
+		msm_arch_idle();
+		rv = 0;
+	}
+
+	if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) {
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
+			printk(KERN_INFO "msm_sleep(): exit power collapse %ld"
+			       "\n", pm_saved_acpu_clk_rate);
+		if (acpuclk_set_rate(pm_saved_acpu_clk_rate, 1) < 0)
+			printk(KERN_ERR "msm_sleep(): clk_set_rate %ld "
+			       "failed\n", pm_saved_acpu_clk_rate);
+
+		/* Restore axi rate if needed */
+		if (axi_rate)
+			clk_set_rate(axi_clk, axi_rate);
+	}
+	if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
+		printk(KERN_INFO "msm_sleep(): exit A11S_CLK_SLEEP_EN %x, "
+		       "A11S_PWRDOWN %x, smsm_get_state %x\n",
+		       readl(A11S_CLK_SLEEP_EN), readl(A11S_PWRDOWN),
+		       smsm_get_state(PM_SMSM_READ_STATE));
+ramp_down_failed:
+	msm_irq_exit_sleep1();
+enter_failed:
+	if (enter_state) {
+		msm_pm_exit_restore_hw();
+
+		smsm_change_state(PM_SMSM_WRITE_STATE, enter_state, exit_state);
+		msm_pm_wait_state(0, exit_wait_clear, exit_wait_any_set, 0);
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
+			printk(KERN_INFO "msm_sleep(): sleep exit "
+			       "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
+			       "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN),
+			       readl(A11S_PWRDOWN), smsm_get_state(PM_SMSM_READ_STATE));
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
+			smsm_print_sleep_info();
+	}
+	msm_irq_exit_sleep2();
+	if (enter_state) {
+		smsm_change_state(PM_SMSM_WRITE_STATE, exit_state, PM_SMSM_WRITE_RUN);
+		msm_pm_wait_state(PM_SMSM_READ_RUN, 0, 0, 0);
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
+			printk(KERN_INFO "msm_sleep(): sleep exit "
+			       "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
+			       "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN),
+			       readl(A11S_PWRDOWN), smsm_get_state(PM_SMSM_READ_STATE));
+	}
+	msm_irq_exit_sleep3();
+	msm_gpio_exit_sleep();
+	smd_sleep_exit();
+	clk_exit_sleep();
+	return rv;
+}
+
+static int msm_pm_idle_spin(void)
+{
+	int spin;
+	spin = msm_pm_idle_spin_time >> 10;
+	while (spin-- > 0) {
+		if (msm_irq_pending()) {
+			return -1;
+		}
+		udelay(1);
+	}
+	return 0;
+}
+
+void arch_idle(void)
+{
+	int ret;
+	int64_t sleep_time;
+	int low_power = 0;
+#ifdef CONFIG_MSM_IDLE_STATS
+	int64_t t1;
+	static int64_t t2;
+	int exit_stat;
+#endif
+	int allow_sleep =
+		msm_pm_idle_sleep_mode < MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT &&
+#ifdef CONFIG_HAS_WAKELOCK
+		!has_wake_lock(WAKE_LOCK_IDLE) &&
+#endif
+		msm_irq_idle_sleep_allowed();
+	if (msm_pm_reset_vector == NULL)
+		return;
+
+	sleep_time = msm_timer_enter_idle();
+#ifdef CONFIG_MSM_IDLE_STATS
+	t1 = ktime_to_ns(ktime_get());
+	msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2);
+	msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, sleep_time);
+#endif
+	if (msm_pm_debug_mask & MSM_PM_DEBUG_IDLE)
+		printk(KERN_INFO "arch_idle: sleep time %llu, allow_sleep %d\n",
+		       sleep_time, allow_sleep);
+	if (sleep_time < msm_pm_idle_sleep_min_time || !allow_sleep) {
+		unsigned long saved_rate;
+		if (acpuclk_get_wfi_rate() && msm_pm_idle_spin() < 0) {
+#ifdef CONFIG_MSM_IDLE_STATS
+			exit_stat = MSM_PM_STAT_IDLE_SPIN;
+#endif
+			goto abort_idle;
+		}
+		saved_rate = acpuclk_wait_for_irq();
+
+
+		if (saved_rate && msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
+			printk(KERN_DEBUG "arch_idle: clk %ld -> swfi\n",
+				saved_rate);
+
+		/*
+		 * If there is a wfi speed specified and we failed to ramp, do not
+		 * go into wfi.
+		 */
+		if (acpuclk_get_wfi_rate() && !saved_rate)
+			while (!msm_irq_pending())
+				udelay(1);
+		else
+			msm_arch_idle();
+
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
+			printk(KERN_DEBUG "msm_sleep: clk swfi -> %ld\n",
+				saved_rate);
+		if (acpuclk_set_rate(saved_rate, 1) < 0)
+			printk(KERN_ERR "msm_sleep(): clk_set_rate %ld "
+			       "failed\n", saved_rate);
+#ifdef CONFIG_MSM_IDLE_STATS
+		exit_stat = MSM_PM_STAT_IDLE_WFI;
+#endif
+	} else {
+		if (msm_pm_idle_spin() < 0) {
+#ifdef CONFIG_MSM_IDLE_STATS
+			exit_stat = MSM_PM_STAT_IDLE_SPIN;
+#endif
+			goto abort_idle;
+		}
+
+		low_power = 1;
+		do_div(sleep_time, NSEC_PER_SEC / 32768);
+		if (sleep_time > 0x6DDD000) {
+			printk("sleep_time too big %lld\n", sleep_time);
+			sleep_time = 0x6DDD000;
+		}
+		ret = msm_sleep(msm_pm_idle_sleep_mode, sleep_time, 1);
+#ifdef CONFIG_MSM_IDLE_STATS
+		if (ret)
+			exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
+		else
+			exit_stat = MSM_PM_STAT_IDLE_SLEEP;
+#endif
+	}
+abort_idle:
+	msm_timer_exit_idle(low_power);
+#ifdef CONFIG_MSM_IDLE_STATS
+	t2 = ktime_to_ns(ktime_get());
+	msm_pm_add_stat(exit_stat, t2 - t1);
+#endif
+}
+
+static int msm_pm_enter(suspend_state_t state)
+{
+	msm_sleep(msm_pm_sleep_mode, msm_pm_max_sleep_time, 0);
+	return 0;
+}
+
+static struct platform_suspend_ops msm_pm_ops = {
+	.enter		= msm_pm_enter,
+	.valid		= suspend_valid_only_mem,
+};
+
+#if defined(CONFIG_ARCH_MSM7X00A)
+static uint32_t restart_reason = 0x776655AA;
+#else
+static uint32_t restart_reason = 0;
+#endif
+
+static void msm_pm_power_off(void)
+{
+	msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
+	for (;;) ;
+}
+
+static bool console_flushed;
+
+void msm_pm_flush_console(void)
+{
+	if (console_flushed)
+		return;
+	console_flushed = true;
+
+	printk("\n");
+	printk(KERN_EMERG "Restarting %s\n", linux_banner);
+	if (!try_acquire_console_sem()) {
+		release_console_sem();
+		return;
+	}
+
+	mdelay(50);
+
+	local_irq_disable();
+	if (try_acquire_console_sem())
+		printk(KERN_EMERG "msm_restart: Console was locked! Busting\n");
+	else
+		printk(KERN_EMERG "msm_restart: Console was locked!\n");
+	release_console_sem();
+}
+
+static void msm_pm_restart(char str)
+{
+	msm_pm_flush_console();
+
+	/* If there's a hard reset hook and the restart_reason
+	 * is the default, prefer that to the (slower) proc_comm
+	 * reset command.
+	 */
+	if ((restart_reason == 0x776655AA) && msm_hw_reset_hook) {
+		msm_hw_reset_hook();
+	} else {
+		msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
+	}
+	for (;;) ;
+}
+
+static int msm_reboot_call(struct notifier_block *this, unsigned long code, void *_cmd)
+{
+	if((code == SYS_RESTART) && _cmd) {
+		char *cmd = _cmd;
+		if (!strcmp(cmd, "bootloader")) {
+			restart_reason = 0x77665500;
+		} else if (!strcmp(cmd, "recovery")) {
+			restart_reason = 0x77665502;
+		} else if (!strcmp(cmd, "eraseflash")) {
+			restart_reason = 0x776655EF;
+		} else if (!strncmp(cmd, "oem-", 4)) {
+			unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
+			restart_reason = 0x6f656d00 | code;
+		} else if (!strcmp(cmd, "force-hard")) {
+			restart_reason = 0x776655AA;
+		} else {
+			restart_reason = 0x77665501;
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block msm_reboot_notifier =
+{
+	.notifier_call = msm_reboot_call,
+};
+
+#ifdef CONFIG_MSM_IDLE_STATS
+static int msm_pm_read_proc(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+	int len = 0;
+	int i, j;
+	char *p = page;
+
+	for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) {
+		int64_t bucket_time;
+		int64_t s;
+		uint32_t ns;
+		s = msm_pm_stats[i].total_time;
+		ns = do_div(s, NSEC_PER_SEC);
+		p += sprintf(p,
+			"%s:\n"
+			"  count: %7d\n"
+			"  total_time: %lld.%09u\n",
+			msm_pm_stats[i].name,
+			msm_pm_stats[i].count,
+			s, ns);
+		bucket_time = CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+		for (j = 0; j < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; j++) {
+			s = bucket_time;
+			ns = do_div(s, NSEC_PER_SEC);
+			p += sprintf(p, "   <%2lld.%09u: %7d (%lld-%lld)\n",
+				s, ns, msm_pm_stats[i].bucket[j],
+				msm_pm_stats[i].min_time[j],
+				msm_pm_stats[i].max_time[j]);
+			bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
+		}
+		p += sprintf(p, "  >=%2lld.%09u: %7d (%lld-%lld)\n",
+			s, ns, msm_pm_stats[i].bucket[j],
+			msm_pm_stats[i].min_time[j],
+			msm_pm_stats[i].max_time[j]);
+	}
+	*start = page + off;
+
+	len = p - page;
+	if (len > off)
+		len -= off;
+	else
+		len = 0;
+
+	return len < count ? len  : count;
+}
+#endif
+
+void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
+{
+	int64_t max_sleep_time_bs = max_sleep_time_ns;
+
+	/* Convert from ns -> BS units */
+	do_div(max_sleep_time_bs, NSEC_PER_SEC / 32768);
+
+	if (max_sleep_time_bs > 0x6DDD000)
+		msm_pm_max_sleep_time = (uint32_t) 0x6DDD000;
+	else
+		msm_pm_max_sleep_time = (uint32_t) max_sleep_time_bs;
+
+	if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
+		printk("%s: Requested %lldns (%lldbs), Giving %ubs\n",
+		       __func__, max_sleep_time_ns, 
+		       max_sleep_time_bs, 
+		       msm_pm_max_sleep_time);
+}
+EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
+
+#if defined(CONFIG_EARLYSUSPEND) && defined(CONFIG_ARCH_MSM_SCORPION)
+/* axi 128 screen on, 61mhz screen off */
+static void axi_early_suspend(struct early_suspend *handler) {
+	axi_rate = 0;
+	clk_set_rate(axi_clk, axi_rate);
+}
+
+static void axi_late_resume(struct early_suspend *handler) {
+	axi_rate = 128000000;
+	sleep_axi_rate = 120000000;
+	clk_set_rate(axi_clk, axi_rate);
+}
+
+static struct early_suspend axi_screen_suspend = {
+	.suspend = axi_early_suspend,
+	.resume = axi_late_resume,
+};
+#endif
+
+static void __init msm_pm_axi_init(void)
+{
+#if defined(CONFIG_EARLYSUSPEND) && defined(CONFIG_ARCH_MSM_SCORPION)
+	axi_clk = clk_get(NULL, "ebi1_clk");
+	if (IS_ERR(axi_clk)) {
+		int result = PTR_ERR(axi_clk);
+		pr_err("clk_get(ebi1_clk) returned %d\n", result);
+		return;
+	}
+	axi_rate = 128000000;
+	sleep_axi_rate = 120000000;
+	clk_set_rate(axi_clk, axi_rate);
+	register_early_suspend(&axi_screen_suspend);
+#else
+	axi_rate = 0;
+#endif
+}
+
+static int __init msm_pm_init(void)
+{
+	pm_power_off = msm_pm_power_off;
+	arm_pm_restart = msm_pm_restart;
+	msm_pm_max_sleep_time = 0;
+	msm_pm_axi_init();
+
+	register_reboot_notifier(&msm_reboot_notifier);
+
+	msm_pm_reset_vector = ioremap(RESET_VECTOR, PAGE_SIZE);
+	if (msm_pm_reset_vector == NULL) {
+		printk(KERN_ERR "msm_pm_init: failed to map reset vector\n");
+		return -ENODEV;
+	}
+
+	suspend_set_ops(&msm_pm_ops);
+
+#ifdef CONFIG_MSM_IDLE_STATS
+	create_proc_read_entry("msm_pm_stats", S_IRUGO,
+				NULL, msm_pm_read_proc, NULL);
+#endif
+	return 0;
+}
+
+__initcall(msm_pm_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
new file mode 100644
index 0000000..159a7a6
--- /dev/null
+++ b/arch/arm/mach-msm/pm.h
@@ -0,0 +1,31 @@
+/* arch/arm/mach-msm/pm.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: San Mehat <san@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_PM_H
+#define __ARCH_ARM_MACH_MSM_PM_H
+
+#include <asm/arch/msm_iomap.h>
+
+#define A11S_CLK_SLEEP_EN_ADDR MSM_CSR_BASE + 0x11c
+
+#define CLK_SLEEP_EN_ARM11_CORE	0x01
+#define CLK_SLEEP_EN_ARM11_AHB	0x02
+#define CLK_SLEEP_EN_ID_BRIDGE	0x04
+#define CLK_SLEEP_EN_DMA_BRIDGE	0x08
+#define CLK_SLEEP_EN_PBUS	0x10
+#define CLK_SLEEP_EN_DEBUG_TIME	0x20
+#define CLK_SLEEP_EN_GP_TIMER	0x40
+#endif
diff --git a/arch/arm/mach-msm/pmic.c b/arch/arm/mach-msm/pmic.c
new file mode 100644
index 0000000..e6dc9fe
--- /dev/null
+++ b/arch/arm/mach-msm/pmic.c
@@ -0,0 +1,530 @@
+/* arch/arm/mach-msm/qdsp6/pmic.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/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+
+#include "pmic.h"
+
+#include <mach/msm_rpcrouter.h>
+
+#define LIB_NULL_PROC 0
+#define LIB_RPC_GLUE_CODE_INFO_REMOTE_PROC 1
+#define LP_MODE_CONTROL_PROC 2
+#define VREG_SET_LEVEL_PROC 3
+#define VREG_PULL_DOWN_SWITCH_PROC 4
+#define SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC 5
+#define SECURE_MPP_CONFIG_I_SINK_PROC 6
+#define RTC_START_PROC 7
+#define RTC_STOP_PROC 8
+#define RTC_GET_TIME_PROC 9
+#define RTC_ENABLE_ALARM_PROC 10
+#define RTC_DISABLE_ALARM_PROC 11
+#define RTC_GET_ALARM_TIME_PROC 12
+#define RTC_GET_ALARM_STATUS_PROC 13
+#define RTC_SET_TIME_ADJUST_PROC 14
+#define RTC_GET_TIME_ADJUST_PROC 15
+#define SET_LED_INTENSITY_PROC 16
+#define FLASH_LED_SET_CURRENT_PROC 17
+#define FLASH_LED_SET_MODE_PROC 18
+#define FLASH_LED_SET_POLARITY_PROC 19
+#define SPEAKER_CMD_PROC 20
+#define SET_SPEAKER_GAIN_PROC 21
+#define VIB_MOT_SET_VOLT_PROC 22
+#define VIB_MOT_SET_MODE_PROC 23
+#define VIB_MOT_SET_POLARITY_PROC 24
+#define VID_EN_PROC 25
+#define VID_IS_EN_PROC 26
+#define VID_LOAD_DETECT_EN_PROC 27
+#define MIC_EN_PROC 28
+#define MIC_IS_EN_PROC 29
+#define MIC_SET_VOLT_PROC 30
+#define MIC_GET_VOLT_PROC 31
+#define SPKR_EN_RIGHT_CHAN_PROC 32
+#define SPKR_IS_RIGHT_CHAN_EN_PROC 33
+#define SPKR_EN_LEFT_CHAN_PROC 34
+#define SPKR_IS_LEFT_CHAN_EN_PROC 35
+#define SET_SPKR_CONFIGURATION_PROC 36
+#define GET_SPKR_CONFIGURATION_PROC 37
+#define SPKR_GET_GAIN_PROC 38
+#define SPKR_IS_EN_PROC 39
+#define SPKR_EN_MUTE_PROC 40
+#define SPKR_IS_MUTE_EN_PROC 41
+#define SPKR_SET_DELAY_PROC 42
+#define SPKR_GET_DELAY_PROC 43
+#define SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC 44
+#define SET_SPEAKER_DELAY_PROC 45
+#define SPEAKER_1K6_ZIN_ENABLE_PROC 46
+#define SPKR_SET_MUX_HPF_CORNER_FREQ_PROC 47
+#define SPKR_GET_MUX_HPF_CORNER_FREQ_PROC 48
+#define SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC 49
+#define SPKR_EN_STEREO_PROC 50
+#define SPKR_IS_STEREO_EN_PROC 51
+#define SPKR_SELECT_USB_WITH_HPF_20HZ_PROC 52
+#define SPKR_IS_USB_WITH_HPF_20HZ_PROC 53
+#define SPKR_BYPASS_MUX_PROC 54
+#define SPKR_IS_MUX_BYPASSED_PROC 55
+#define SPKR_EN_HPF_PROC 56
+#define SPKR_IS_HPF_EN_PROC 57
+#define SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC 58
+#define SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC 59
+#define SPKR_ADD_RIGHT_LEFT_CHAN_PROC 60
+#define SPKR_SET_GAIN_PROC 61
+#define SPKR_EN_PROC 62
+
+
+/* rpc related */
+#define PMIC_RPC_TIMEOUT (5*HZ)
+
+#define PMIC_RPC_PROG	0x30000061
+#define PMIC_RPC_VER	0x00010001
+
+/* error bit flags defined by modem side */
+#define PM_ERR_FLAG__PAR1_OUT_OF_RANGE		(0x0001)
+#define PM_ERR_FLAG__PAR2_OUT_OF_RANGE		(0x0002)
+#define PM_ERR_FLAG__PAR3_OUT_OF_RANGE		(0x0004)
+#define PM_ERR_FLAG__PAR4_OUT_OF_RANGE		(0x0008)
+#define PM_ERR_FLAG__PAR5_OUT_OF_RANGE		(0x0010)
+
+#define PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE   	(0x001F)
+
+#define PM_ERR_FLAG__SBI_OPT_ERR		(0x0080)
+#define PM_ERR_FLAG__FEATURE_NOT_SUPPORTED	(0x0100)
+
+#define	PMIC_BUFF_SIZE		256
+
+static DEFINE_MUTEX(pmic_mutex);
+static struct msm_rpc_endpoint *pmic_ept;
+
+
+static int modem_to_linux_err(uint err)
+{
+	if (err == 0)
+		return 0;
+
+	if (err & PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE)
+		return -EINVAL;
+
+	if (err & PM_ERR_FLAG__SBI_OPT_ERR)
+		return -EIO;
+
+	if (err & PM_ERR_FLAG__FEATURE_NOT_SUPPORTED)
+		return -ENOSYS;
+
+	return -EPERM;
+}
+
+
+/*
+ * 1) network byte order
+ * 2) RPC request header(40 bytes) and RPC reply header (24 bytes)
+ * 3) each transaction consists of a request and reply
+ * 3) PROC (comamnd) layer has its own sub-protocol defined
+ * 4) sub-protocol can be grouped to follwoing 7 cases:
+ *  	a) set one argument, no get
+ * 	b) set two argument, no get
+ * 	c) set three argument, no get
+ * 	d) set a struct, no get
+ * 	e) set a argument followed by a struct, no get
+ * 	f) set a argument, get a argument
+ * 	g) no set, get either a argument or a struct
+ */
+
+/* Returns number of reply bytes (minus reply header size) or
+ * negative value on error.
+ */
+static int pmic_rpc(int proc, void *msg, int msglen, void *rep, int replen)
+{
+	int r;
+	mutex_lock(&pmic_mutex);
+
+	if (!pmic_ept) {
+		pmic_ept = msm_rpc_connect(PMIC_RPC_PROG, PMIC_RPC_VER, 0);
+		if (!pmic_ept) {
+			pr_err("pmic: cannot connect to rpc server\n");
+			r = -ENODEV;
+			goto done;
+		}
+	}
+	r = msm_rpc_call_reply(pmic_ept, proc, msg, msglen, 
+			       rep, replen, PMIC_RPC_TIMEOUT);
+	if (r >= 0) {
+		if (r < sizeof(struct rpc_reply_hdr)) {
+			r = -EIO;
+			goto done;
+		}
+		r -= sizeof(struct rpc_reply_hdr);
+	}
+done:
+	mutex_unlock(&pmic_mutex);
+	return r;
+}
+
+struct pmic_reply {
+	struct rpc_reply_hdr hdr;
+	uint32_t status;
+	uint32_t data;
+};
+	
+/**
+ * pmic_rpc_set_only() - set arguments and no get
+ * @data0:	first argumrnt
+ * @data1:	second argument
+ * @data2:	third argument
+ * @data3:	fourth argument
+ * @num:	number of argument
+ * @proc:	command/request id
+ *
+ * This function covers case a, b, and c
+ */
+static int pmic_rpc_set_only(uint data0, uint data1, uint data2, uint data3,
+			     int num, int proc)
+{
+	struct {
+		struct rpc_request_hdr hdr;
+		uint32_t data[4];
+	} msg;
+	struct pmic_reply rep;
+	int r;
+
+	if (num > 4)
+		return -EINVAL;
+
+	msg.data[0] = cpu_to_be32(data0);
+	msg.data[1] = cpu_to_be32(data1);
+	msg.data[2] = cpu_to_be32(data2);
+	msg.data[3] = cpu_to_be32(data3);
+
+	r = pmic_rpc(proc, &msg,
+		     sizeof(struct rpc_request_hdr) + num * sizeof(uint32_t),
+		     &rep, sizeof(rep));
+	if (r < 0)
+		return r;
+	if (r < sizeof(uint32_t))
+		return -EIO;
+
+	return modem_to_linux_err(be32_to_cpu(rep.status));
+}
+
+/**
+ * pmic_rpc_set_struct() - set the whole struct
+ * @xflag:	indicates an extra argument
+ * @xdata:	the extra argument
+ * @*data:	starting address of struct
+ * @size:	size of struct
+ * @proc:	command/request id
+ *
+ * This fucntion covers case d and e
+ */
+static int pmic_rpc_set_struct(int xflag, uint xdata, uint *data, uint size,
+			       int proc)
+{
+	struct {
+		struct rpc_request_hdr hdr;
+		uint32_t data[32+2];
+	} msg;
+	struct pmic_reply rep;
+	int n = 0;
+
+	size = (size + 3) & (~3);
+	if (size > (32 * sizeof(uint32_t)))
+		return -EINVAL;
+
+	if (xflag)
+		msg.data[n++] = cpu_to_be32(xdata);
+
+	msg.data[n++] = cpu_to_be32(1);
+	while (size > 0) {
+		size -= 4;
+		msg.data[n++] = cpu_to_be32(*data++);
+	}
+		
+	n = pmic_rpc(proc, &msg,
+		     sizeof(struct rpc_request_hdr) + n * sizeof(uint32_t),
+		     &rep, sizeof(rep));
+	if (n < 0)
+		return n;
+	if (n < sizeof(uint32_t))
+		return -EIO;
+
+	return modem_to_linux_err(be32_to_cpu(rep.status));
+}
+
+int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id)
+{
+	return pmic_rpc_set_only(cmd, id, 0, 0, 2, LP_MODE_CONTROL_PROC);
+}
+EXPORT_SYMBOL(pmic_lp_mode_control);
+
+int pmic_secure_mpp_control_digital_output(enum mpp_which which,
+	enum mpp_dlogic_level level,
+	enum mpp_dlogic_out_ctrl out)
+{
+	return pmic_rpc_set_only(which, level, out, 0, 3,
+				SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_control_digital_output);
+
+int pmic_secure_mpp_config_i_sink(enum mpp_which which,
+				enum mpp_i_sink_level level,
+				enum mpp_i_sink_switch onoff)
+{
+	return pmic_rpc_set_only(which, level, onoff, 0, 3,
+				SECURE_MPP_CONFIG_I_SINK_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_config_i_sink);
+
+int pmic_secure_mpp_config_digital_input(enum mpp_which which,
+	enum mpp_dlogic_level level,
+	enum mpp_dlogic_in_dbus dbus)
+{
+	return pmic_rpc_set_only(which, level, dbus, 0, 3,
+				SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_config_digital_input);
+
+int pmic_rtc_start(struct rtc_time *time)
+{
+	return pmic_rpc_set_struct(0, 0, (uint *)time, sizeof(*time),
+				RTC_START_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_start);
+
+int pmic_rtc_stop(void)
+{
+	return pmic_rpc_set_only(0, 0, 0, 0, 0, RTC_STOP_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_stop);
+
+int pmic_rtc_enable_alarm(enum rtc_alarm alarm,
+	struct rtc_time *time)
+{
+	return pmic_rpc_set_struct(1, alarm, (uint *)time, sizeof(*time),
+				RTC_ENABLE_ALARM_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_enable_alarm);
+
+int pmic_rtc_disable_alarm(enum rtc_alarm alarm)
+{
+	return pmic_rpc_set_only(alarm, 0, 0, 0, 1, RTC_DISABLE_ALARM_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_disable_alarm);
+
+int pmic_rtc_set_time_adjust(uint adjust)
+{
+	return pmic_rpc_set_only(adjust, 0, 0, 0, 1,
+				RTC_SET_TIME_ADJUST_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_set_time_adjust);
+
+/*
+ * generic speaker
+ */
+int pmic_speaker_cmd(const enum spkr_cmd cmd)
+{
+	return pmic_rpc_set_only(cmd, 0, 0, 0, 1, SPEAKER_CMD_PROC);
+}
+EXPORT_SYMBOL(pmic_speaker_cmd);
+
+int pmic_set_spkr_configuration(struct spkr_config_mode	*cfg)
+{
+	return pmic_rpc_set_struct(0, 0, (uint *)cfg, sizeof(*cfg),
+				SET_SPKR_CONFIGURATION_PROC);
+}
+EXPORT_SYMBOL(pmic_set_spkr_configuration);
+
+int pmic_spkr_en_right_chan(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_RIGHT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_right_chan);
+
+int pmic_spkr_en_left_chan(uint	enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_LEFT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_left_chan);
+
+int pmic_set_speaker_gain(enum spkr_gain gain)
+{
+	return pmic_rpc_set_only(gain, 0, 0, 0, 1, SET_SPEAKER_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_set_speaker_gain);
+
+int pmic_set_speaker_delay(enum spkr_dly delay)
+{
+	return pmic_rpc_set_only(delay, 0, 0, 0, 1, SET_SPEAKER_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_set_speaker_delay);
+
+int pmic_speaker_1k6_zin_enable(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+				SPEAKER_1K6_ZIN_ENABLE_PROC);
+}
+EXPORT_SYMBOL(pmic_speaker_1k6_zin_enable);
+
+int pmic_spkr_set_mux_hpf_corner_freq(enum spkr_hpf_corner_freq	freq)
+{
+	return pmic_rpc_set_only(freq, 0, 0, 0, 1,
+				SPKR_SET_MUX_HPF_CORNER_FREQ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_mux_hpf_corner_freq);
+
+int pmic_spkr_select_usb_with_hpf_20hz(uint	enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+				SPKR_SELECT_USB_WITH_HPF_20HZ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_select_usb_with_hpf_20hz);
+
+int pmic_spkr_bypass_mux(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_BYPASS_MUX_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_bypass_mux);
+
+int pmic_spkr_en_hpf(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_HPF_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_hpf);
+
+int pmic_spkr_en_sink_curr_from_ref_volt_cir(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+				SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_sink_curr_from_ref_volt_cir);
+
+/*
+ * 	speaker indexed by left_right
+ */
+int pmic_spkr_en(enum spkr_left_right left_right, uint enable)
+{
+	return pmic_rpc_set_only(left_right, enable, 0, 0, 2, SPKR_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en);
+
+int pmic_spkr_set_gain(enum spkr_left_right left_right, enum spkr_gain gain)
+{
+	return pmic_rpc_set_only(left_right, gain, 0, 0, 2, SPKR_SET_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_gain);
+
+int pmic_spkr_set_delay(enum spkr_left_right left_right, enum spkr_dly delay)
+{
+	return pmic_rpc_set_only(left_right, delay, 0, 0, 2,
+				SPKR_SET_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_delay);
+
+int pmic_spkr_en_mute(enum spkr_left_right left_right, uint enabled)
+{
+	return pmic_rpc_set_only(left_right, enabled, 0, 0, 2,
+				SPKR_EN_MUTE_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_mute);
+
+/*
+ * 	mic
+ */
+int pmic_mic_en(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, MIC_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_en);
+
+int pmic_mic_set_volt(enum mic_volt vol)
+{
+	return pmic_rpc_set_only(vol, 0, 0, 0, 1, MIC_SET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_set_volt);
+
+int pmic_vib_mot_set_volt(uint vol)
+{
+	return pmic_rpc_set_only(vol, 0, 0, 0, 1, VIB_MOT_SET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_volt);
+
+int pmic_vib_mot_set_mode(enum pm_vib_mot_mode mode)
+{
+	return pmic_rpc_set_only(mode, 0, 0, 0, 1, VIB_MOT_SET_MODE_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_mode);
+
+int pmic_vib_mot_set_polarity(enum pm_vib_mot_pol pol)
+{
+	return pmic_rpc_set_only(pol, 0, 0, 0, 1, VIB_MOT_SET_POLARITY_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_polarity);
+
+int pmic_vid_en(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, VID_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_en);
+
+int pmic_vid_load_detect_en(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, VID_LOAD_DETECT_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_load_detect_en);
+
+int pmic_set_led_intensity(enum ledtype type, int level)
+{
+	return pmic_rpc_set_only(type, level, 0, 0, 2, SET_LED_INTENSITY_PROC);
+}
+EXPORT_SYMBOL(pmic_set_led_intensity);
+
+int pmic_flash_led_set_current(const uint16_t milliamps)
+{
+	return pmic_rpc_set_only(milliamps, 0, 0, 0, 1,
+				FLASH_LED_SET_CURRENT_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_current);
+
+int pmic_flash_led_set_mode(enum flash_led_mode mode)
+{
+	return pmic_rpc_set_only((int)mode, 0, 0, 0, 1,
+				FLASH_LED_SET_MODE_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_mode);
+
+int pmic_flash_led_set_polarity(enum flash_led_pol pol)
+{
+	return pmic_rpc_set_only((int)pol, 0, 0, 0, 1,
+				FLASH_LED_SET_POLARITY_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_polarity);
+
+int pmic_spkr_add_right_left_chan(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+				SPKR_ADD_RIGHT_LEFT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_add_right_left_chan);
+
+int pmic_spkr_en_stereo(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_STEREO_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_stereo);
+
diff --git a/arch/arm/mach-msm/pmic.h b/arch/arm/mach-msm/pmic.h
new file mode 100644
index 0000000..14ad789
--- /dev/null
+++ b/arch/arm/mach-msm/pmic.h
@@ -0,0 +1,310 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora Forum 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_PMIC_H
+#define __ARCH_ARM_MACH_PMIC_H
+
+#include "proc_comm.h"
+
+enum spkr_left_right {
+	LEFT_SPKR,
+	RIGHT_SPKR,
+};
+
+enum spkr_gain {
+	SPKR_GAIN_MINUS16DB,      /* -16 db */
+	SPKR_GAIN_MINUS12DB,      /* -12 db */
+	SPKR_GAIN_MINUS08DB,      /* -08 db */
+	SPKR_GAIN_MINUS04DB,      /* -04 db */
+	SPKR_GAIN_00DB,           /*  00 db */
+	SPKR_GAIN_PLUS04DB,       /* +04 db */
+	SPKR_GAIN_PLUS08DB,       /* +08 db */
+	SPKR_GAIN_PLUS12DB,       /* +12 db */
+};
+
+enum spkr_dly {
+	SPKR_DLY_10MS,            /* ~10  ms delay */
+	SPKR_DLY_100MS,           /* ~100 ms delay */
+};
+
+enum spkr_hpf_corner_freq {
+	SPKR_FREQ_1_39KHZ,         /* 1.39 kHz */
+	SPKR_FREQ_0_64KHZ,         /* 0.64 kHz */
+	SPKR_FREQ_0_86KHZ,         /* 0.86 kHz */
+	SPKR_FREQ_0_51KHZ,         /* 0.51 kHz */
+	SPKR_FREQ_1_06KHZ,         /* 1.06 kHz */
+	SPKR_FREQ_0_57KHZ,         /* 0.57 kHz */
+	SPKR_FREQ_0_73KHZ,         /* 0.73 kHz */
+	SPKR_FREQ_0_47KHZ,         /* 0.47 kHz */
+	SPKR_FREQ_1_20KHZ,         /* 1.20 kHz */
+	SPKR_FREQ_0_60KHZ,         /* 0.60 kHz */
+	SPKR_FREQ_0_76KHZ,         /* 0.76 kHz */
+	SPKR_FREQ_0_49KHZ,         /* 0.49 kHz */
+	SPKR_FREQ_0_95KHZ,         /* 0.95 kHz */
+	SPKR_FREQ_0_54KHZ,         /* 0.54 kHz */
+	SPKR_FREQ_0_68KHZ,         /* 0.68 kHz */
+	SPKR_FREQ_0_45KHZ,         /* 0.45 kHz */
+};
+
+/* Turn the speaker on or off and enables or disables mute.*/
+enum spkr_cmd {
+	SPKR_DISABLE,  /* Enable Speaker */
+	SPKR_ENABLE,   /* Disable Speaker */
+	SPKR_MUTE_OFF, /* turn speaker mute off, SOUND ON */
+	SPKR_MUTE_ON,  /* turn speaker mute on, SOUND OFF */
+	SPKR_OFF,      /* turn speaker OFF (speaker disable and mute on) */
+	SPKR_ON,        /* turn speaker ON (speaker enable and mute off)  */
+	SPKR_SET_FREQ_CMD,    /* set speaker frequency */
+	SPKR_GET_FREQ_CMD,    /* get speaker frequency */
+	SPKR_SET_GAIN_CMD,    /* set speaker gain */
+	SPKR_GET_GAIN_CMD,    /* get speaker gain */
+	SPKR_SET_DELAY_CMD,   /* set speaker delay */
+	SPKR_GET_DELAY_CMD,   /* get speaker delay */
+	SPKR_SET_PDM_MODE,
+	SPKR_SET_PWM_MODE,
+};
+
+struct spkr_config_mode {
+	uint32_t is_right_chan_en;
+	uint32_t is_left_chan_en;
+	uint32_t is_right_left_chan_added;
+	uint32_t is_stereo_en;
+	uint32_t is_usb_with_hpf_20hz;
+	uint32_t is_mux_bypassed;
+	uint32_t is_hpf_en;
+	uint32_t is_sink_curr_from_ref_volt_cir_en;
+};
+
+enum mic_volt {
+	MIC_VOLT_2_00V,            /*  2.00 V  */
+	MIC_VOLT_1_93V,            /*  1.93 V  */
+	MIC_VOLT_1_80V,            /*  1.80 V  */
+	MIC_VOLT_1_73V,            /*  1.73 V  */
+};
+
+enum ledtype {
+	LED_LCD,
+	LED_KEYPAD,
+};
+
+enum flash_led_mode {
+	FLASH_LED_MODE__MANUAL,
+	FLASH_LED_MODE__DBUS1,
+	FLASH_LED_MODE__DBUS2,
+	FLASH_LED_MODE__DBUS3,
+};
+
+enum flash_led_pol {
+	FLASH_LED_POL__ACTIVE_HIGH,
+	FLASH_LED_POL__ACTIVE_LOW,
+};
+
+enum switch_cmd {
+	OFF_CMD,
+	ON_CMD
+};
+
+enum vreg_lp_id {
+	PM_VREG_LP_MSMA_ID,
+	PM_VREG_LP_MSMP_ID,
+	PM_VREG_LP_MSME1_ID,
+	PM_VREG_LP_GP3_ID,
+	PM_VREG_LP_MSMC_ID,
+	PM_VREG_LP_MSME2_ID,
+	PM_VREG_LP_GP4_ID,
+	PM_VREG_LP_GP1_ID,
+	PM_VREG_LP_RFTX_ID,
+	PM_VREG_LP_RFRX1_ID,
+	PM_VREG_LP_RFRX2_ID,
+	PM_VREG_LP_WLAN_ID,
+	PM_VREG_LP_MMC_ID,
+	PM_VREG_LP_RUIM_ID,
+	PM_VREG_LP_MSMC0_ID,
+	PM_VREG_LP_GP2_ID,
+	PM_VREG_LP_GP5_ID,
+	PM_VREG_LP_GP6_ID,
+	PM_VREG_LP_MPLL_ID,
+	PM_VREG_LP_RFUBM_ID,
+	PM_VREG_LP_RFA_ID,
+	PM_VREG_LP_CDC2_ID,
+	PM_VREG_LP_RFTX2_ID,
+	PM_VREG_LP_USIM_ID,
+	PM_VREG_LP_USB2P6_ID,
+	PM_VREG_LP_TCXO_ID,
+	PM_VREG_LP_USB3P3_ID,
+
+	PM_VREG_LP_MSME_ID = PM_VREG_LP_MSME1_ID,
+	/* backward compatible enums only */
+	PM_VREG_LP_CAM_ID = PM_VREG_LP_GP1_ID,
+	PM_VREG_LP_MDDI_ID = PM_VREG_LP_GP2_ID,
+	PM_VREG_LP_RUIM2_ID = PM_VREG_LP_GP3_ID,
+	PM_VREG_LP_AUX_ID = PM_VREG_LP_GP4_ID,
+	PM_VREG_LP_AUX2_ID = PM_VREG_LP_GP5_ID,
+	PM_VREG_LP_BT_ID = PM_VREG_LP_GP6_ID,
+	PM_VREG_LP_MSMC_LDO_ID = PM_VREG_LP_MSMC_ID,
+	PM_VREG_LP_MSME1_LDO_ID = PM_VREG_LP_MSME1_ID,
+	PM_VREG_LP_MSME2_LDO_ID = PM_VREG_LP_MSME2_ID,
+	PM_VREG_LP_RFA1_ID = PM_VREG_LP_RFRX2_ID,
+	PM_VREG_LP_RFA2_ID = PM_VREG_LP_RFTX2_ID,
+	PM_VREG_LP_XO_ID = PM_VREG_LP_TCXO_ID
+};
+
+enum mpp_which {
+	PM_MPP_1,
+	PM_MPP_2,
+	PM_MPP_3,
+	PM_MPP_4,
+	PM_MPP_5,
+	PM_MPP_6,
+	PM_MPP_7,
+	PM_MPP_8,
+	PM_MPP_9,
+	PM_MPP_10,
+	PM_MPP_11,
+	PM_MPP_12,
+	PM_MPP_13,
+	PM_MPP_14,
+	PM_MPP_15,
+	PM_MPP_16,
+	PM_MPP_17,
+	PM_MPP_18,
+	PM_MPP_19,
+	PM_MPP_20,
+	PM_MPP_21,
+	PM_MPP_22,
+
+	PM_NUM_MPP_HAN = PM_MPP_4 + 1,
+	PM_NUM_MPP_KIP = PM_MPP_4 + 1,
+	PM_NUM_MPP_EPIC = PM_MPP_4 + 1,
+	PM_NUM_MPP_PM7500 = PM_MPP_22 + 1,
+	PM_NUM_MPP_PM6650 = PM_MPP_12 + 1,
+	PM_NUM_MPP_PM6658 = PM_MPP_12 + 1,
+	PM_NUM_MPP_PANORAMIX = PM_MPP_2 + 1,
+	PM_NUM_MPP_PM6640 = PM_NUM_MPP_PANORAMIX,
+	PM_NUM_MPP_PM6620 = PM_NUM_MPP_PANORAMIX
+};
+
+enum mpp_dlogic_level {
+	PM_MPP__DLOGIC__LVL_MSME,
+	PM_MPP__DLOGIC__LVL_MSMP,
+	PM_MPP__DLOGIC__LVL_RUIM,
+	PM_MPP__DLOGIC__LVL_MMC,
+	PM_MPP__DLOGIC__LVL_VDD,
+};
+
+enum mpp_dlogic_in_dbus {
+	PM_MPP__DLOGIC_IN__DBUS_NONE,
+	PM_MPP__DLOGIC_IN__DBUS1,
+	PM_MPP__DLOGIC_IN__DBUS2,
+	PM_MPP__DLOGIC_IN__DBUS3,
+};
+
+enum mpp_dlogic_out_ctrl {
+	PM_MPP__DLOGIC_OUT__CTRL_LOW,
+	PM_MPP__DLOGIC_OUT__CTRL_HIGH,
+	PM_MPP__DLOGIC_OUT__CTRL_MPP,
+	PM_MPP__DLOGIC_OUT__CTRL_NOT_MPP,
+};
+
+enum mpp_i_sink_level {
+	PM_MPP__I_SINK__LEVEL_5mA,
+	PM_MPP__I_SINK__LEVEL_10mA,
+	PM_MPP__I_SINK__LEVEL_15mA,
+	PM_MPP__I_SINK__LEVEL_20mA,
+	PM_MPP__I_SINK__LEVEL_25mA,
+	PM_MPP__I_SINK__LEVEL_30mA,
+	PM_MPP__I_SINK__LEVEL_35mA,
+	PM_MPP__I_SINK__LEVEL_40mA,
+};
+
+enum mpp_i_sink_switch {
+	PM_MPP__I_SINK__SWITCH_DIS,
+	PM_MPP__I_SINK__SWITCH_ENA,
+	PM_MPP__I_SINK__SWITCH_ENA_IF_MPP_HIGH,
+	PM_MPP__I_SINK__SWITCH_ENA_IF_MPP_LOW,
+};
+
+enum pm_vib_mot_mode {
+	PM_VIB_MOT_MODE__MANUAL,
+	PM_VIB_MOT_MODE__DBUS1,
+	PM_VIB_MOT_MODE__DBUS2,
+	PM_VIB_MOT_MODE__DBUS3,
+};
+
+enum pm_vib_mot_pol {
+	PM_VIB_MOT_POL__ACTIVE_HIGH,
+	PM_VIB_MOT_POL__ACTIVE_LOW,
+};
+
+struct rtc_time {
+	uint  sec;
+};
+
+enum rtc_alarm {
+	PM_RTC_ALARM_1,
+};
+
+
+int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id);
+int pmic_secure_mpp_control_digital_output(enum mpp_which which,
+		enum mpp_dlogic_level level, enum mpp_dlogic_out_ctrl out);
+int pmic_secure_mpp_config_i_sink(enum mpp_which which,
+		enum mpp_i_sink_level level, enum mpp_i_sink_switch onoff);
+int pmic_secure_mpp_config_digital_input(enum mpp_which	which,
+		enum mpp_dlogic_level level, enum mpp_dlogic_in_dbus dbus);
+int pmic_speaker_cmd(const enum spkr_cmd cmd);
+int pmic_set_spkr_configuration(struct spkr_config_mode	*cfg);
+int pmic_spkr_en_right_chan(uint enable);
+int pmic_spkr_en_left_chan(uint enable);
+int pmic_spkr_en(enum spkr_left_right left_right, uint enabled);
+int pmic_spkr_set_gain(enum spkr_left_right left_right, enum spkr_gain gain);
+int pmic_set_speaker_gain(enum spkr_gain gain);
+int pmic_set_speaker_delay(enum spkr_dly delay);
+int pmic_speaker_1k6_zin_enable(uint enable);
+int pmic_spkr_set_mux_hpf_corner_freq(enum spkr_hpf_corner_freq	freq);
+int pmic_spkr_select_usb_with_hpf_20hz(uint enable);
+int pmic_spkr_bypass_mux(uint enable);
+int pmic_spkr_en_hpf(uint enable);
+int pmic_spkr_en_sink_curr_from_ref_volt_cir(uint enable);
+int pmic_spkr_set_delay(enum spkr_left_right left_right, enum spkr_dly delay);
+int pmic_spkr_en_mute(enum spkr_left_right left_right, uint enabled);
+int pmic_mic_en(uint enable);
+int pmic_mic_set_volt(enum mic_volt vol);
+int pmic_set_led_intensity(enum ledtype type, int level);
+int pmic_flash_led_set_current(uint16_t milliamps);
+int pmic_flash_led_set_mode(enum flash_led_mode mode);
+int pmic_flash_led_set_polarity(enum flash_led_pol pol);
+int pmic_spkr_add_right_left_chan(uint enable);
+int pmic_spkr_en_stereo(uint enable);
+int pmic_vib_mot_set_volt(uint vol);
+int pmic_vib_mot_set_mode(enum pm_vib_mot_mode mode);
+int pmic_vib_mot_set_polarity(enum pm_vib_mot_pol pol);
+int pmic_vid_en(uint enable);
+int pmic_vid_load_detect_en(uint enable);
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5/Makefile b/arch/arm/mach-msm/qdsp5/Makefile
new file mode 100644
index 0000000..991d4a7
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/Makefile
@@ -0,0 +1,17 @@
+obj-y += adsp.o
+ifeq ($(CONFIG_MSM_AMSS_VERSION_6350),y)
+obj-y += adsp_info.o
+obj-y += audio_evrc.o audio_qcelp.o audio_amrnb.o audio_aac.o
+else
+obj-y += adsp_6225.o
+endif
+
+obj-y += adsp_driver.o
+obj-y += adsp_video_verify_cmd.o
+obj-y += adsp_videoenc_verify_cmd.o
+obj-y += adsp_jpeg_verify_cmd.o adsp_jpeg_patch_event.o
+obj-y += adsp_vfe_verify_cmd.o adsp_vfe_patch_event.o
+obj-y += adsp_lpm_verify_cmd.o
+obj-y += audio_out.o audio_in.o audio_mp3.o audmgr.o audpp.o
+obj-y += snd.o
+
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
new file mode 100644
index 0000000..9dc8945
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -0,0 +1,1183 @@
+/* arch/arm/mach-msm/qdsp5/adsp.c
+ *
+ * Register/Interrupt access for userspace aDSP library.
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Iliyan Malchev <ibm@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.
+ *
+ */
+
+/* TODO:
+ * - move shareable rpc code outside of adsp.c
+ * - general solution for virt->phys patchup
+ * - queue IDs should be relative to modules
+ * - disallow access to non-associated queues
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+
+static struct wake_lock adsp_wake_lock;
+static inline void prevent_suspend(void)
+{
+	wake_lock(&adsp_wake_lock);
+}
+static inline void allow_suspend(void)
+{
+	wake_unlock(&adsp_wake_lock);
+}
+
+#include <linux/io.h>
+#include <mach/msm_iomap.h>
+#include "adsp.h"
+
+#define INT_ADSP INT_ADSP_A9_A11
+
+static struct adsp_info adsp_info;
+static struct msm_rpc_endpoint *rpc_cb_server_client;
+static struct msm_adsp_module *adsp_modules;
+static int adsp_open_count;
+static DEFINE_MUTEX(adsp_open_lock);
+
+/* protect interactions with the ADSP command/message queue */
+static spinlock_t adsp_cmd_lock;
+
+static uint32_t current_image = -1;
+
+void adsp_set_image(struct adsp_info *info, uint32_t image)
+{
+	current_image = image;
+}
+
+/*
+ * Checks whether the module_id is available in the
+ * module_entries table.If module_id is available returns `0`.
+ * If module_id is not available returns `-ENXIO`.
+ */
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+static int32_t adsp_validate_module(uint32_t module_id)
+{
+	uint32_t	*ptr;
+	uint32_t	module_index;
+	uint32_t	num_mod_entries;
+
+	ptr = adsp_info.init_info_ptr->module_entries;
+	num_mod_entries = adsp_info.init_info_ptr->module_table_size;
+
+	for (module_index = 0; module_index < num_mod_entries; module_index++)
+		if (module_id == ptr[module_index])
+			return 0;
+
+	return -ENXIO;
+}
+#else
+static inline int32_t adsp_validate_module(uint32_t module_id) { return 0; }
+#endif
+
+uint32_t adsp_get_module(struct adsp_info *info, uint32_t task)
+{
+	BUG_ON(current_image == -1UL);
+	return info->task_to_module[current_image][task];
+}
+
+uint32_t adsp_get_queue_offset(struct adsp_info *info, uint32_t queue_id)
+{
+	BUG_ON(current_image == -1UL);
+	return info->queue_offset[current_image][queue_id];
+}
+
+static int rpc_adsp_rtos_app_to_modem(uint32_t cmd, uint32_t module,
+				      struct msm_adsp_module *adsp_module)
+{
+	int rc;
+	struct rpc_adsp_rtos_app_to_modem_args_t rpc_req;
+	struct rpc_reply_hdr *rpc_rsp;
+
+	msm_rpc_setup_req(&rpc_req.hdr,
+			  RPC_ADSP_RTOS_ATOM_PROG,
+			  msm_rpc_get_vers(adsp_module->rpc_client),
+			  RPC_ADSP_RTOS_APP_TO_MODEM_PROC);
+
+	rpc_req.gotit = cpu_to_be32(1);
+	rpc_req.cmd = cpu_to_be32(cmd);
+	rpc_req.proc_id = cpu_to_be32(RPC_ADSP_RTOS_PROC_APPS);
+	rpc_req.module = cpu_to_be32(module);
+	rc = msm_rpc_write(adsp_module->rpc_client, &rpc_req, sizeof(rpc_req));
+	if (rc < 0) {
+		pr_err("adsp: could not send RPC request: %d\n", rc);
+		return rc;
+	}
+
+	rc = msm_rpc_read(adsp_module->rpc_client,
+			  (void **)&rpc_rsp, -1, (5*HZ));
+	if (rc < 0) {
+		pr_err("adsp: error receiving RPC reply: %d (%d)\n",
+		       rc, -ERESTARTSYS);
+		return rc;
+	}
+
+	if (be32_to_cpu(rpc_rsp->reply_stat) != RPCMSG_REPLYSTAT_ACCEPTED) {
+		pr_err("adsp: RPC call was denied!\n");
+		kfree(rpc_rsp);
+		return -EPERM;
+	}
+
+	if (be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat) !=
+	    RPC_ACCEPTSTAT_SUCCESS) {
+		pr_err("adsp error: RPC call was not successful (%d)\n",
+		       be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat));
+		kfree(rpc_rsp);
+		return -EINVAL;
+	}
+
+	kfree(rpc_rsp);
+	return 0;
+}
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+static int get_module_index(uint32_t id)
+{
+	int mod_idx;
+	for (mod_idx = 0; mod_idx < adsp_info.module_count; mod_idx++)
+		if (adsp_info.module[mod_idx].id == id)
+			return mod_idx;
+
+	return -ENXIO;
+}
+#endif
+
+static struct msm_adsp_module *find_adsp_module_by_id(
+	struct adsp_info *info, uint32_t id)
+{
+	if (id > info->max_module_id) {
+		return NULL;
+	} else {
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+		id = get_module_index(id);
+		if (id < 0)
+			return NULL;
+#endif
+		return info->id_to_module[id];
+	}
+}
+
+static struct msm_adsp_module *find_adsp_module_by_name(
+	struct adsp_info *info, const char *name)
+{
+	unsigned n;
+	for (n = 0; n < info->module_count; n++)
+		if (!strcmp(name, adsp_modules[n].name))
+			return adsp_modules + n;
+	return NULL;
+}
+
+static int adsp_rpc_init(struct msm_adsp_module *adsp_module)
+{
+	/* remove the original connect once compatible support is complete */
+	adsp_module->rpc_client = msm_rpc_connect(
+			RPC_ADSP_RTOS_ATOM_PROG,
+			RPC_ADSP_RTOS_ATOM_VERS,
+			MSM_RPC_UNINTERRUPTIBLE | MSM_RPC_ENABLE_RECEIVE);
+
+	if (IS_ERR(adsp_module->rpc_client)) {
+		int rc = PTR_ERR(adsp_module->rpc_client);
+		adsp_module->rpc_client = 0;
+		pr_err("adsp: could not open rpc client: %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+/*
+ * Send RPC_ADSP_RTOS_CMD_GET_INIT_INFO cmd to ARM9 and get
+ * queue offsets and module entries (init info) as part of the event.
+ */
+static void  msm_get_init_info(void)
+{
+	int rc;
+	struct rpc_adsp_rtos_app_to_modem_args_t rpc_req;
+
+	adsp_info.init_info_rpc_client = msm_rpc_connect(
+			RPC_ADSP_RTOS_ATOM_PROG,
+			RPC_ADSP_RTOS_ATOM_VERS,
+			MSM_RPC_UNINTERRUPTIBLE | MSM_RPC_ENABLE_RECEIVE);
+	if (IS_ERR(adsp_info.init_info_rpc_client)) {
+		rc = PTR_ERR(adsp_info.init_info_rpc_client);
+		adsp_info.init_info_rpc_client = 0;
+		pr_err("adsp: could not open rpc client: %d\n", rc);
+		return;
+	}
+
+	msm_rpc_setup_req(&rpc_req.hdr,
+			RPC_ADSP_RTOS_ATOM_PROG,
+			msm_rpc_get_vers(adsp_info.init_info_rpc_client),
+			RPC_ADSP_RTOS_APP_TO_MODEM_PROC);
+
+	rpc_req.gotit = cpu_to_be32(1);
+	rpc_req.cmd = cpu_to_be32(RPC_ADSP_RTOS_CMD_GET_INIT_INFO);
+	rpc_req.proc_id = cpu_to_be32(RPC_ADSP_RTOS_PROC_APPS);
+	rpc_req.module = 0;
+
+	rc = msm_rpc_write(adsp_info.init_info_rpc_client,
+				&rpc_req, sizeof(rpc_req));
+	if (rc < 0)
+		pr_err("adsp: could not send RPC request: %d\n", rc);
+}
+#endif
+
+int msm_adsp_get(const char *name, struct msm_adsp_module **out,
+		 struct msm_adsp_ops *ops, void *driver_data)
+{
+	struct msm_adsp_module *module;
+	int rc = 0;
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	static uint32_t init_info_cmd_sent;
+	if (!init_info_cmd_sent) {
+		msm_get_init_info();
+		init_waitqueue_head(&adsp_info.init_info_wait);
+		rc = wait_event_timeout(adsp_info.init_info_wait,
+			adsp_info.init_info_state == ADSP_STATE_INIT_INFO,
+			5 * HZ);
+		if (!rc) {
+			pr_info("adsp: INIT_INFO failed\n");
+			return -ETIMEDOUT;
+		}
+		init_info_cmd_sent++;
+	}
+#endif
+
+	module = find_adsp_module_by_name(&adsp_info, name);
+	if (!module)
+		return -ENODEV;
+
+	mutex_lock(&module->lock);
+	pr_info("adsp: opening module %s\n", module->name);
+	if (module->open_count++ == 0 && module->clk)
+		clk_enable(module->clk);
+
+	mutex_lock(&adsp_open_lock);
+	if (adsp_open_count++ == 0) {
+		enable_irq(INT_ADSP);
+		prevent_suspend();
+	}
+	mutex_unlock(&adsp_open_lock);
+
+	if (module->ops) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	rc = adsp_rpc_init(module);
+	if (rc)
+		goto done;
+
+	module->ops = ops;
+	module->driver_data = driver_data;
+	*out = module;
+	rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_REGISTER_APP,
+					module->id, module);
+	if (rc) {
+		module->ops = NULL;
+		module->driver_data = NULL;
+		*out = NULL;
+		pr_err("adsp: REGISTER_APP failed\n");
+		goto done;
+	}
+
+	pr_info("adsp: module %s has been registered\n", module->name);
+
+done:
+	mutex_lock(&adsp_open_lock);
+	if (rc && --adsp_open_count == 0) {
+		disable_irq(INT_ADSP);
+		allow_suspend();
+	}
+	if (rc && --module->open_count == 0 && module->clk)
+		clk_disable(module->clk);
+	mutex_unlock(&adsp_open_lock);
+	mutex_unlock(&module->lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_get);
+
+static int msm_adsp_disable_locked(struct msm_adsp_module *module);
+
+void msm_adsp_put(struct msm_adsp_module *module)
+{
+	unsigned long flags;
+
+	mutex_lock(&module->lock);
+	if (--module->open_count == 0 && module->clk)
+		clk_disable(module->clk);
+	if (module->ops) {
+		pr_info("adsp: closing module %s\n", module->name);
+
+		/* lock to ensure a dsp event cannot be delivered
+		 * during or after removal of the ops and driver_data
+		 */
+		spin_lock_irqsave(&adsp_cmd_lock, flags);
+		module->ops = NULL;
+		module->driver_data = NULL;
+		spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+
+		if (module->state != ADSP_STATE_DISABLED) {
+			pr_info("adsp: disabling module %s\n", module->name);
+			msm_adsp_disable_locked(module);
+		}
+
+		msm_rpc_close(module->rpc_client);
+		module->rpc_client = 0;
+		if (--adsp_open_count == 0) {
+			disable_irq(INT_ADSP);
+			allow_suspend();
+			pr_info("adsp: disable interrupt\n");
+		}
+	} else {
+		pr_info("adsp: module %s is already closed\n", module->name);
+	}
+	mutex_unlock(&module->lock);
+}
+EXPORT_SYMBOL(msm_adsp_put);
+
+/* this should be common code with rpc_servers.c */
+static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client,
+					uint32_t xid, uint32_t accept_status)
+{
+	int rc = 0;
+	uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
+	struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
+
+	reply->xid = cpu_to_be32(xid);
+	reply->type = cpu_to_be32(1); /* reply */
+	reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+	reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+	reply->data.acc_hdr.verf_flavor = 0;
+	reply->data.acc_hdr.verf_length = 0;
+
+	rc = msm_rpc_write(rpc_cb_server_client, reply_buf, sizeof(reply_buf));
+	if (rc < 0)
+		pr_err("adsp: could not write RPC response: %d\n", rc);
+	return rc;
+}
+
+int __msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr,
+		   void *cmd_buf, size_t cmd_size)
+{
+	uint32_t ctrl_word;
+	uint32_t dsp_q_addr;
+	uint32_t dsp_addr;
+	uint32_t cmd_id = 0;
+	int cnt = 0;
+	int ret_status = 0;
+	unsigned long flags;
+	struct adsp_info *info = module->info;
+
+	spin_lock_irqsave(&adsp_cmd_lock, flags);
+
+	if (module->state != ADSP_STATE_ENABLED) {
+		spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+		pr_err("adsp: module %s not enabled before write\n",
+		       module->name);
+		return -ENODEV;
+	}
+	if (adsp_validate_module(module->id)) {
+		spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+		pr_info("adsp: module id validation failed %s  %d\n",
+			module->name, module->id);
+		return -ENXIO;
+	}
+	dsp_q_addr = adsp_get_queue_offset(info, dsp_queue_addr);
+	dsp_q_addr &= ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M;
+
+	/* Poll until the ADSP is ready to accept a command.
+	 * Wait for 100us, return error if it's not responding.
+	 * If this returns an error, we need to disable ALL modules and
+	 * then retry.
+	 */
+	while (((ctrl_word = readl(info->write_ctrl)) &
+		ADSP_RTOS_WRITE_CTRL_WORD_READY_M) !=
+		ADSP_RTOS_WRITE_CTRL_WORD_READY_V) {
+		if (cnt > 100) {
+			pr_err("adsp: timeout waiting for DSP write ready\n");
+			ret_status = -EIO;
+			goto fail;
+		}
+		pr_warning("adsp: waiting for DSP write ready\n");
+		udelay(1);
+		cnt++;
+	}
+
+	/* Set the mutex bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
+	ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;
+
+	/* Clear the command bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);
+
+	/* Set the queue address bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
+	ctrl_word |= dsp_q_addr;
+
+	writel(ctrl_word, info->write_ctrl);
+
+	/* Generate an interrupt to the DSP.  This notifies the DSP that
+	 * we are about to send a command on this particular queue.  The
+	 * DSP will in response change its state.
+	 */
+	writel(1, info->send_irq);
+
+	/* Poll until the adsp responds to the interrupt; this does not
+	 * generate an interrupt from the adsp.  This should happen within
+	 * 5ms.
+	 */
+	cnt = 0;
+	while ((readl(info->write_ctrl) &
+		ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M) ==
+		ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V) {
+		if (cnt > 5000) {
+			pr_err("adsp: timeout waiting for adsp ack\n");
+			ret_status = -EIO;
+			goto fail;
+		}
+		udelay(1);
+		cnt++;
+	}
+
+	/* Read the ctrl word */
+	ctrl_word = readl(info->write_ctrl);
+
+	if ((ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M) !=
+			 ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V) {
+		ret_status = -EAGAIN;
+		goto fail;
+	}
+
+	/* Ctrl word status bits were 00, no error in the ctrl word */
+
+	/* Get the DSP buffer address */
+	dsp_addr = (ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M) +
+		   (uint32_t)MSM_AD5_BASE;
+
+	if (dsp_addr < (uint32_t)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
+		uint16_t *buf_ptr = (uint16_t *) cmd_buf;
+		uint16_t *dsp_addr16 = (uint16_t *)dsp_addr;
+		cmd_size /= sizeof(uint16_t);
+
+		/* Save the command ID */
+		cmd_id = (uint32_t) buf_ptr[0];
+
+		/* Copy the command to DSP memory */
+		cmd_size++;
+		while (--cmd_size)
+			*dsp_addr16++ = *buf_ptr++;
+	} else {
+		uint32_t *buf_ptr = (uint32_t *) cmd_buf;
+		uint32_t *dsp_addr32 = (uint32_t *)dsp_addr;
+		cmd_size /= sizeof(uint32_t);
+
+		/* Save the command ID */
+		cmd_id = buf_ptr[0];
+
+		cmd_size++;
+		while (--cmd_size)
+			*dsp_addr32++ = *buf_ptr++;
+	}
+
+	/* Set the mutex bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
+	ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;
+
+	/* Set the command bits to write done */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);
+	ctrl_word |= ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V;
+
+	/* Set the queue address bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
+	ctrl_word |= dsp_q_addr;
+
+	writel(ctrl_word, info->write_ctrl);
+
+	/* Generate an interrupt to the DSP.  It does not respond with
+	 * an interrupt, and we do not need to wait for it to
+	 * acknowledge, because it will hold the mutex lock until it's
+	 * ready to receive more commands again.
+	 */
+	writel(1, info->send_irq);
+
+	module->num_commands++;
+
+fail:
+	spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+	return ret_status;
+}
+EXPORT_SYMBOL(msm_adsp_write);
+
+int msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr,
+		   void *cmd_buf, size_t cmd_size)
+{
+	int rc, retries = 0;
+	do {
+		rc = __msm_adsp_write(module, dsp_queue_addr, cmd_buf, cmd_size);
+		if (rc == -EAGAIN)
+			udelay(10);
+	} while(rc == -EAGAIN && retries++ < 100);
+	if (retries > 50)
+		pr_warning("adsp: %s command took %d attempts: rc %d\n",
+				module->name, retries, rc);
+	return rc;
+}
+
+#ifdef CONFIG_MSM_ADSP_REPORT_EVENTS
+static void *modem_event_addr;
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+static void read_modem_event(void *buf, size_t size)
+{
+	uint32_t *dptr = buf;
+	struct rpc_adsp_rtos_modem_to_app_args_t *sptr;
+	struct adsp_rtos_mp_mtoa_type *pkt_ptr;
+	size_t len = size / 4;
+
+	if (len < 3) {
+		pr_err("%s: invalid length %d\n", __func__, len);
+		return;
+	}
+
+	sptr = modem_event_addr;
+	pkt_ptr = &sptr->mtoa_pkt.adsp_rtos_mp_mtoa_data.mp_mtoa_packet;
+
+	dptr[0] = be32_to_cpu(sptr->mtoa_pkt.mp_mtoa_header.event);
+	dptr[1] = be32_to_cpu(pkt_ptr->module);
+	dptr[2] = be32_to_cpu(pkt_ptr->image);
+}
+#else
+static void read_modem_event(void *buf, size_t size)
+{
+	uint32_t *dptr = buf;
+	struct rpc_adsp_rtos_modem_to_app_args_t *sptr =
+		modem_event_addr;
+	size_t len = size / 4;
+	if (len < 3) {
+		pr_err("%s: invalid length %d\n", __func__, len);
+		return;
+	}
+	dptr[0] = be32_to_cpu(sptr->event);
+	dptr[1] = be32_to_cpu(sptr->module);
+	dptr[2] = be32_to_cpu(sptr->image);
+}
+#endif /* CONFIG_MSM_AMSS_VERSION >= 6350 */
+#endif /* CONFIG_MSM_ADSP_REPORT_EVENTS */
+
+static void handle_adsp_rtos_mtoa_app(struct rpc_request_hdr *req)
+{
+	struct rpc_adsp_rtos_modem_to_app_args_t *args =
+		(struct rpc_adsp_rtos_modem_to_app_args_t *)req;
+	uint32_t event;
+	uint32_t proc_id;
+	uint32_t module_id;
+	uint32_t image;
+	struct msm_adsp_module *module;
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	struct adsp_rtos_mp_mtoa_type *pkt_ptr =
+		&args->mtoa_pkt.adsp_rtos_mp_mtoa_data.mp_mtoa_packet;
+
+	event = be32_to_cpu(args->mtoa_pkt.mp_mtoa_header.event);
+	proc_id = be32_to_cpu(args->mtoa_pkt.mp_mtoa_header.proc_id);
+	module_id = be32_to_cpu(pkt_ptr->module);
+	image = be32_to_cpu(pkt_ptr->image);
+
+	if (be32_to_cpu(args->mtoa_pkt.desc_field) == RPC_ADSP_RTOS_INIT_INFO) {
+		struct queue_to_offset_type *qptr;
+		struct queue_to_offset_type *qtbl;
+		uint32_t *mptr;
+		uint32_t *mtbl;
+		uint32_t q_idx;
+		uint32_t num_entries;
+		uint32_t entries_per_image;
+		struct adsp_rtos_mp_mtoa_init_info_type *iptr;
+		struct adsp_rtos_mp_mtoa_init_info_type *sptr;
+		int32_t i_no, e_idx;
+
+		pr_info("adsp:INIT_INFO Event\n");
+		sptr = &args->mtoa_pkt.adsp_rtos_mp_mtoa_data.
+				mp_mtoa_init_packet;
+
+		iptr = adsp_info.init_info_ptr;
+		iptr->image_count = be32_to_cpu(sptr->image_count);
+		iptr->num_queue_offsets = be32_to_cpu(sptr->num_queue_offsets);
+		num_entries = iptr->num_queue_offsets;
+		qptr = &sptr->queue_offsets_tbl[0][0];
+		for (i_no = 0; i_no < iptr->image_count; i_no++) {
+			qtbl = &iptr->queue_offsets_tbl[i_no][0];
+			for (e_idx = 0; e_idx < num_entries; e_idx++) {
+				qtbl[e_idx].offset = be32_to_cpu(qptr->offset);
+				qtbl[e_idx].queue = be32_to_cpu(qptr->queue);
+				q_idx = be32_to_cpu(qptr->queue);
+				iptr->queue_offsets[i_no][q_idx] =
+						qtbl[e_idx].offset;
+				qptr++;
+			}
+		}
+
+		num_entries = be32_to_cpu(sptr->num_task_module_entries);
+		iptr->num_task_module_entries = num_entries;
+		entries_per_image = num_entries / iptr->image_count;
+		mptr = &sptr->task_to_module_tbl[0][0];
+		for (i_no = 0; i_no < iptr->image_count; i_no++) {
+			mtbl = &iptr->task_to_module_tbl[i_no][0];
+			for (e_idx = 0; e_idx < entries_per_image; e_idx++) {
+				mtbl[e_idx] = be32_to_cpu(*mptr);
+				mptr++;
+			}
+		}
+
+		iptr->module_table_size = be32_to_cpu(sptr->module_table_size);
+		mptr = &sptr->module_entries[0];
+		for (i_no = 0; i_no < iptr->module_table_size; i_no++)
+			iptr->module_entries[i_no] = be32_to_cpu(mptr[i_no]);
+		adsp_info.init_info_state = ADSP_STATE_INIT_INFO;
+		rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid,
+						RPC_ACCEPTSTAT_SUCCESS);
+		wake_up(&adsp_info.init_info_wait);
+
+		return;
+	}
+#else
+	event = be32_to_cpu(args->event);
+	proc_id = be32_to_cpu(args->proc_id);
+	module_id = be32_to_cpu(args->module);
+	image = be32_to_cpu(args->image);
+#endif
+
+	pr_info("adsp: rpc event=%d, proc_id=%d, module=%d, image=%d\n",
+		event, proc_id, module_id, image);
+
+	module = find_adsp_module_by_id(&adsp_info, module_id);
+	if (!module) {
+		pr_err("adsp: module %d is not supported!\n", module_id);
+		rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid,
+				RPC_ACCEPTSTAT_GARBAGE_ARGS);
+		return;
+	}
+
+	mutex_lock(&module->lock);
+	switch (event) {
+	case RPC_ADSP_RTOS_MOD_READY:
+		pr_info("adsp: module %s: READY\n", module->name);
+		module->state = ADSP_STATE_ENABLED;
+		wake_up(&module->state_wait);
+		adsp_set_image(module->info, image);
+		break;
+	case RPC_ADSP_RTOS_MOD_DISABLE:
+		pr_info("adsp: module %s: DISABLED\n", module->name);
+		module->state = ADSP_STATE_DISABLED;
+		wake_up(&module->state_wait);
+		break;
+	case RPC_ADSP_RTOS_SERVICE_RESET:
+		pr_info("adsp: module %s: SERVICE_RESET\n", module->name);
+		module->state = ADSP_STATE_DISABLED;
+		wake_up(&module->state_wait);
+		break;
+	case RPC_ADSP_RTOS_CMD_SUCCESS:
+		pr_info("adsp: module %s: CMD_SUCCESS\n", module->name);
+		break;
+	case RPC_ADSP_RTOS_CMD_FAIL:
+		pr_info("adsp: module %s: CMD_FAIL\n", module->name);
+		break;
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	case RPC_ADSP_RTOS_DISABLE_FAIL:
+		pr_info("adsp: module %s: DISABLE_FAIL\n", module->name);
+		break;
+#endif
+	default:
+		pr_info("adsp: unknown event %d\n", event);
+		rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid,
+					     RPC_ACCEPTSTAT_GARBAGE_ARGS);
+		mutex_unlock(&module->lock);
+		return;
+	}
+	rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid,
+				     RPC_ACCEPTSTAT_SUCCESS);
+	mutex_unlock(&module->lock);
+#ifdef CONFIG_MSM_ADSP_REPORT_EVENTS
+	if (module->ops != NULL && module->ops->event != NULL) {
+		modem_event_addr = (uint32_t *)req;
+		module->ops->event(module->driver_data, EVENT_MSG_ID,
+					EVENT_LEN, read_modem_event);
+	}
+#endif
+}
+
+static int handle_adsp_rtos_mtoa(struct rpc_request_hdr *req)
+{
+	switch (req->procedure) {
+	case RPC_ADSP_RTOS_MTOA_NULL_PROC:
+		rpc_send_accepted_void_reply(rpc_cb_server_client,
+					     req->xid,
+					     RPC_ACCEPTSTAT_SUCCESS);
+		break;
+	case RPC_ADSP_RTOS_MODEM_TO_APP_PROC:
+		handle_adsp_rtos_mtoa_app(req);
+		break;
+	default:
+		pr_err("adsp: unknowned proc %d\n", req->procedure);
+		rpc_send_accepted_void_reply(
+			rpc_cb_server_client, req->xid,
+			RPC_ACCEPTSTAT_PROC_UNAVAIL);
+		break;
+	}
+	return 0;
+}
+
+/* this should be common code with rpc_servers.c */
+static int adsp_rpc_thread(void *data)
+{
+	void *buffer;
+	struct rpc_request_hdr *req;
+	int rc;
+
+	do {
+		rc = msm_rpc_read(rpc_cb_server_client, &buffer, -1, -1);
+		if (rc < 0) {
+			pr_err("adsp: could not read rpc: %d\n", rc);
+			break;
+		}
+		req = (struct rpc_request_hdr *)buffer;
+
+		req->type = be32_to_cpu(req->type);
+		req->xid = be32_to_cpu(req->xid);
+		req->rpc_vers = be32_to_cpu(req->rpc_vers);
+		req->prog = be32_to_cpu(req->prog);
+		req->vers = be32_to_cpu(req->vers);
+		req->procedure = be32_to_cpu(req->procedure);
+
+		if (req->type != 0)
+			goto bad_rpc;
+		if (req->rpc_vers != 2)
+			goto bad_rpc;
+		if (req->prog != RPC_ADSP_RTOS_MTOA_PROG)
+			goto bad_rpc;
+		if (req->vers != RPC_ADSP_RTOS_MTOA_VERS)
+			goto bad_rpc;
+
+		handle_adsp_rtos_mtoa(req);
+		kfree(buffer);
+		continue;
+
+bad_rpc:
+		pr_err("adsp: bogus rpc from modem\n");
+		kfree(buffer);
+	} while (1);
+
+	do_exit(0);
+}
+
+static size_t read_event_len;
+static void *read_event_addr;
+
+static void read_event_16(void *buf, size_t size)
+{
+	uint16_t *dst = buf;
+	uint16_t *src = read_event_addr;
+	size_t len = size / 2;
+	if (len > read_event_len)
+		len = read_event_len;
+	else if (len < read_event_len)
+		pr_warning("%s: event bufer length too small (%d < %d)\n",
+			__func__, len, read_event_len);
+	while (len--)
+		*dst++ = *src++;
+}
+
+static void read_event_32(void *buf, size_t size)
+{
+	uint32_t *dst = buf;
+	uint32_t *src = read_event_addr;
+	size_t len = size / 4;
+	if (len > read_event_len)
+		len = read_event_len;
+	else if (len < read_event_len)
+		pr_warning("%s: event bufer length too small (%d < %d)\n",
+			__func__, len, read_event_len);
+	while (len--)
+		*dst++ = *src++;
+}
+
+static int adsp_rtos_read_ctrl_word_cmd_tast_to_h_v(
+	struct adsp_info *info, void *dsp_addr)
+{
+	struct msm_adsp_module *module;
+	unsigned rtos_task_id;
+	unsigned msg_id;
+	unsigned msg_length;
+	void (*func)(void *, size_t);
+
+	if (dsp_addr >= (void *)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
+		uint32_t *dsp_addr32 = dsp_addr;
+		uint32_t tmp = *dsp_addr32++;
+		rtos_task_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M) >> 8;
+		msg_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M);
+		read_event_len = tmp >> 16;
+		read_event_addr = dsp_addr32;
+		msg_length = read_event_len * sizeof(uint32_t);
+		func = read_event_32;
+	} else {
+		uint16_t *dsp_addr16 = dsp_addr;
+		uint16_t tmp = *dsp_addr16++;
+		rtos_task_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M) >> 8;
+		msg_id = tmp & ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M;
+		read_event_len = *dsp_addr16++;
+		read_event_addr = dsp_addr16;
+		msg_length = read_event_len * sizeof(uint16_t);
+		func = read_event_16;
+	}
+
+	if (rtos_task_id > info->max_task_id) {
+		pr_err("adsp: bogus task id %d\n", rtos_task_id);
+		return 0;
+	}
+	module = find_adsp_module_by_id(info,
+					adsp_get_module(info, rtos_task_id));
+
+	if (!module) {
+		pr_err("adsp: no module for task id %d\n", rtos_task_id);
+		return 0;
+	}
+
+	module->num_events++;
+
+	if (!module->ops) {
+		pr_err("adsp: module %s is not open\n", module->name);
+		return 0;
+	}
+
+	module->ops->event(module->driver_data, msg_id, msg_length, func);
+	return 0;
+}
+
+static int adsp_get_event(struct adsp_info *info)
+{
+	uint32_t ctrl_word;
+	uint32_t ready;
+	void *dsp_addr;
+	uint32_t cmd_type;
+	int cnt;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&adsp_cmd_lock, flags);
+
+	/* Whenever the DSP has a message, it updates this control word
+	 * and generates an interrupt.  When we receive the interrupt, we
+	 * read this register to find out what ADSP task the command is
+	 * comming from.
+	 *
+	 * The ADSP should *always* be ready on the first call, but the
+	 * irq handler calls us in a loop (to handle back-to-back command
+	 * processing), so we give the DSP some time to return to the
+	 * ready state.  The DSP will not issue another IRQ for events
+	 * pending between the first IRQ and the event queue being drained,
+	 * unfortunately.
+	 */
+
+	for (cnt = 0; cnt < 10; cnt++) {
+		ctrl_word = readl(info->read_ctrl);
+
+		if ((ctrl_word & ADSP_RTOS_READ_CTRL_WORD_FLAG_M) ==
+		    ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_CONT_V)
+			goto ready;
+
+		udelay(10);
+	}
+	pr_warning("adsp: not ready after 100uS\n");
+	rc = -EBUSY;
+	goto done;
+
+ready:
+	/* Here we check to see if there are pending messages. If there are
+	 * none, we siply return -EAGAIN to indicate that there are no more
+	 * messages pending.
+	 */
+	ready = ctrl_word & ADSP_RTOS_READ_CTRL_WORD_READY_M;
+	if ((ready != ADSP_RTOS_READ_CTRL_WORD_READY_V) &&
+	    (ready != ADSP_RTOS_READ_CTRL_WORD_CONT_V)) {
+		rc = -EAGAIN;
+		goto done;
+	}
+
+	/* DSP says that there are messages waiting for the host to read */
+
+	/* Get the Command Type */
+	cmd_type = ctrl_word & ADSP_RTOS_READ_CTRL_WORD_CMD_TYPE_M;
+
+	/* Get the DSP buffer address */
+	dsp_addr = (void *)((ctrl_word &
+			     ADSP_RTOS_READ_CTRL_WORD_DSP_ADDR_M) +
+			    (uint32_t)MSM_AD5_BASE);
+
+	/* We can only handle Task-to-Host messages */
+	if (cmd_type != ADSP_RTOS_READ_CTRL_WORD_CMD_TASK_TO_H_V) {
+		pr_err("adsp: unknown dsp cmd_type %d\n", cmd_type);
+		rc = -EIO;
+		goto done;
+	}
+
+	adsp_rtos_read_ctrl_word_cmd_tast_to_h_v(info, dsp_addr);
+
+	ctrl_word = readl(info->read_ctrl);
+	ctrl_word &= ~ADSP_RTOS_READ_CTRL_WORD_READY_M;
+
+	/* Write ctrl word to the DSP */
+	writel(ctrl_word, info->read_ctrl);
+
+	/* Generate an interrupt to the DSP */
+	writel(1, info->send_irq);
+
+done:
+	spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+	return rc;
+}
+
+static irqreturn_t adsp_irq_handler(int irq, void *data)
+{
+	struct adsp_info *info = &adsp_info;
+	int cnt = 0;
+	for (cnt = 0; cnt < 10; cnt++)
+		if (adsp_get_event(info) < 0)
+			break;
+	if (cnt > info->event_backlog_max)
+		info->event_backlog_max = cnt;
+	info->events_received += cnt;
+	if (cnt == 10)
+		pr_err("adsp: too many (%d) events for single irq!\n", cnt);
+	return IRQ_HANDLED;
+}
+
+int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate)
+{
+	if (module->clk && clk_rate)
+		return clk_set_rate(module->clk, clk_rate);
+
+	return -EINVAL;
+}
+
+int msm_adsp_enable(struct msm_adsp_module *module)
+{
+	int rc = 0;
+
+	pr_info("msm_adsp_enable() '%s'state[%d] id[%d]\n",
+		module->name, module->state, module->id);
+
+	mutex_lock(&module->lock);
+	switch (module->state) {
+	case ADSP_STATE_DISABLED:
+		rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_ENABLE,
+						module->id, module);
+		if (rc)
+			break;
+		module->state = ADSP_STATE_ENABLING;
+		mutex_unlock(&module->lock);
+		rc = wait_event_timeout(module->state_wait,
+					module->state != ADSP_STATE_ENABLING,
+					1 * HZ);
+		mutex_lock(&module->lock);
+		if (module->state == ADSP_STATE_ENABLED) {
+			rc = 0;
+		} else {
+			pr_err("adsp: module '%s' enable timed out\n",
+			       module->name);
+			rc = -ETIMEDOUT;
+		}
+		break;
+	case ADSP_STATE_ENABLING:
+		pr_warning("adsp: module '%s' enable in progress\n",
+			   module->name);
+		break;
+	case ADSP_STATE_ENABLED:
+		pr_warning("adsp: module '%s' already enabled\n",
+			   module->name);
+		break;
+	case ADSP_STATE_DISABLING:
+		pr_err("adsp: module '%s' disable in progress\n",
+		       module->name);
+		rc = -EBUSY;
+		break;
+	}
+	mutex_unlock(&module->lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_enable);
+
+static int msm_adsp_disable_locked(struct msm_adsp_module *module)
+{
+	int rc = 0;
+
+	switch (module->state) {
+	case ADSP_STATE_DISABLED:
+		pr_warning("adsp: module '%s' already disabled\n",
+			   module->name);
+		break;
+	case ADSP_STATE_ENABLING:
+	case ADSP_STATE_ENABLED:
+		rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_DISABLE,
+						module->id, module);
+		module->state = ADSP_STATE_DISABLED;
+	}
+	return rc;
+}
+
+int msm_adsp_disable(struct msm_adsp_module *module)
+{
+	int rc;
+	pr_info("msm_adsp_disable() '%s'\n", module->name);
+	mutex_lock(&module->lock);
+	rc = msm_adsp_disable_locked(module);
+	mutex_unlock(&module->lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_disable);
+
+static int msm_adsp_probe(struct platform_device *pdev)
+{
+	unsigned count;
+	int rc, i;
+	int max_module_id;
+
+	pr_info("adsp: probe\n");
+
+	wake_lock_init(&adsp_wake_lock, WAKE_LOCK_SUSPEND, "adsp");
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	adsp_info.init_info_ptr = kzalloc(
+		(sizeof(struct adsp_rtos_mp_mtoa_init_info_type)), GFP_KERNEL);
+	if (!adsp_info.init_info_ptr)
+		return -ENOMEM;
+#endif
+
+	rc = adsp_init_info(&adsp_info);
+	if (rc)
+		return rc;
+	adsp_info.send_irq += (uint32_t) MSM_AD5_BASE;
+	adsp_info.read_ctrl += (uint32_t) MSM_AD5_BASE;
+	adsp_info.write_ctrl += (uint32_t) MSM_AD5_BASE;
+	count = adsp_info.module_count;
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	max_module_id = count;
+#else
+	max_module_id = adsp_info.max_module_id + 1;
+#endif
+
+	adsp_modules = kzalloc(
+		sizeof(struct msm_adsp_module) * count +
+		sizeof(void *) * max_module_id, GFP_KERNEL);
+	if (!adsp_modules)
+		return -ENOMEM;
+
+	adsp_info.id_to_module = (void *) (adsp_modules + count);
+
+	spin_lock_init(&adsp_cmd_lock);
+
+	rc = request_irq(INT_ADSP, adsp_irq_handler, IRQF_TRIGGER_RISING,
+			 "adsp", 0);
+	if (rc < 0)
+		goto fail_request_irq;
+	disable_irq(INT_ADSP);
+
+	rpc_cb_server_client = msm_rpc_open();
+	if (IS_ERR(rpc_cb_server_client)) {
+		rpc_cb_server_client = NULL;
+		rc = PTR_ERR(rpc_cb_server_client);
+		pr_err("adsp: could not create rpc server (%d)\n", rc);
+		goto fail_rpc_open;
+	}
+
+	rc = msm_rpc_register_server(rpc_cb_server_client,
+				     RPC_ADSP_RTOS_MTOA_PROG,
+				     RPC_ADSP_RTOS_MTOA_VERS);
+	if (rc) {
+		pr_err("adsp: could not register callback server (%d)\n", rc);
+		goto fail_rpc_register;
+	}
+
+	/* start the kernel thread to process the callbacks */
+	kthread_run(adsp_rpc_thread, NULL, "kadspd");
+
+	for (i = 0; i < count; i++) {
+		struct msm_adsp_module *mod = adsp_modules + i;
+		mutex_init(&mod->lock);
+		init_waitqueue_head(&mod->state_wait);
+		mod->info = &adsp_info;
+		mod->name = adsp_info.module[i].name;
+		mod->id = adsp_info.module[i].id;
+		if (adsp_info.module[i].clk_name)
+			mod->clk = clk_get(NULL, adsp_info.module[i].clk_name);
+		else
+			mod->clk = NULL;
+		if (mod->clk && adsp_info.module[i].clk_rate)
+			clk_set_rate(mod->clk, adsp_info.module[i].clk_rate);
+		mod->verify_cmd = adsp_info.module[i].verify_cmd;
+		mod->patch_event = adsp_info.module[i].patch_event;
+		INIT_HLIST_HEAD(&mod->pmem_regions);
+		mod->pdev.name = adsp_info.module[i].pdev_name;
+		mod->pdev.id = -1;
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+		adsp_info.id_to_module[i] = mod;
+#else
+		adsp_info.id_to_module[mod->id] = mod;
+#endif
+		platform_device_register(&mod->pdev);
+	}
+
+	msm_adsp_publish_cdevs(adsp_modules, count);
+
+	return 0;
+
+fail_rpc_register:
+	msm_rpc_close(rpc_cb_server_client);
+	rpc_cb_server_client = NULL;
+fail_rpc_open:
+	enable_irq(INT_ADSP);
+	free_irq(INT_ADSP, 0);
+fail_request_irq:
+	kfree(adsp_modules);
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	kfree(adsp_info.init_info_ptr);
+#endif
+	return rc;
+}
+
+static struct platform_driver msm_adsp_driver = {
+	.probe = msm_adsp_probe,
+	.driver = {
+		.name = MSM_ADSP_DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init adsp_init(void)
+{
+	return platform_driver_register(&msm_adsp_driver);
+}
+
+device_initcall(adsp_init);
diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h
new file mode 100644
index 0000000..0e5c9abd
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp.h
@@ -0,0 +1,369 @@
+/* arch/arm/mach-msm/qdsp5/adsp.h
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Iliyan Malchev <ibm@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_ADSP_H
+#define _ARCH_ARM_MACH_MSM_ADSP_H
+
+#include <linux/types.h>
+#include <linux/msm_adsp.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_adsp.h>
+
+int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr,
+		    unsigned long len);
+int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
+			   unsigned long *kvaddr, unsigned long len);
+int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr);
+
+int adsp_vfe_verify_cmd(struct msm_adsp_module *module,
+			unsigned int queue_id, void *cmd_data,
+			size_t cmd_size);
+int adsp_jpeg_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size);
+int adsp_lpm_verify_cmd(struct msm_adsp_module *module,
+			unsigned int queue_id, void *cmd_data,
+			size_t cmd_size);
+int adsp_video_verify_cmd(struct msm_adsp_module *module,
+			  unsigned int queue_id, void *cmd_data,
+			  size_t cmd_size);
+int adsp_videoenc_verify_cmd(struct msm_adsp_module *module,
+			  unsigned int queue_id, void *cmd_data,
+			  size_t cmd_size);
+
+
+struct adsp_event;
+
+int adsp_vfe_patch_event(struct msm_adsp_module *module,
+			struct adsp_event *event);
+
+int adsp_jpeg_patch_event(struct msm_adsp_module *module,
+			struct adsp_event *event);
+
+
+struct adsp_module_info {
+	const char *name;
+	const char *pdev_name;
+	uint32_t id;
+	const char *clk_name;
+	unsigned long clk_rate;
+	int (*verify_cmd) (struct msm_adsp_module*, unsigned int, void *,
+			   size_t);
+	int (*patch_event) (struct msm_adsp_module*, struct adsp_event *);
+};
+
+#define ADSP_EVENT_MAX_SIZE 496
+#define EVENT_LEN	12
+#define EVENT_MSG_ID	((uint16_t)~0)
+
+struct adsp_event {
+	struct list_head list;
+	uint32_t size; /* always in bytes */
+	uint16_t msg_id;
+	uint16_t type; /* 0 for msgs (from aDSP), -1 for events (from ARM9) */
+	int is16; /* always 0 (msg is 32-bit) when the event type is 1(ARM9) */
+	union {
+		uint16_t msg16[ADSP_EVENT_MAX_SIZE / 2];
+		uint32_t msg32[ADSP_EVENT_MAX_SIZE / 4];
+	} data;
+};
+
+struct adsp_info {
+	uint32_t send_irq;
+	uint32_t read_ctrl;
+	uint32_t write_ctrl;
+
+	uint32_t max_msg16_size;
+	uint32_t max_msg32_size;
+
+	uint32_t max_task_id;
+	uint32_t max_module_id;
+	uint32_t max_queue_id;
+	uint32_t max_image_id;
+
+	/* for each image id, a map of queue id to offset */
+	uint32_t **queue_offset;
+
+	/* for each image id, a map of task id to module id */
+	uint32_t **task_to_module;
+
+	/* for each module id, map of module id to module */
+	struct msm_adsp_module **id_to_module;
+
+	uint32_t module_count;
+	struct adsp_module_info *module;
+
+	/* stats */
+	uint32_t events_received;
+	uint32_t event_backlog_max;
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	/* rpc_client for init_info */
+	struct msm_rpc_endpoint *init_info_rpc_client;
+	struct adsp_rtos_mp_mtoa_init_info_type *init_info_ptr;
+	wait_queue_head_t init_info_wait;
+	unsigned init_info_state;
+#endif
+};
+
+#define RPC_ADSP_RTOS_ATOM_PROG 0x3000000a
+#define RPC_ADSP_RTOS_MTOA_PROG 0x3000000b
+#define RPC_ADSP_RTOS_ATOM_NULL_PROC 0
+#define RPC_ADSP_RTOS_MTOA_NULL_PROC 0
+#define RPC_ADSP_RTOS_APP_TO_MODEM_PROC 2
+#define RPC_ADSP_RTOS_MODEM_TO_APP_PROC 2
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+#define RPC_ADSP_RTOS_ATOM_VERS MSM_RPC_VERS(1,0)
+#define RPC_ADSP_RTOS_MTOA_VERS MSM_RPC_VERS(2,1) /* must be actual vers */
+#define MSM_ADSP_DRIVER_NAME "rs3000000a:00010000"
+#elif (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225)
+#define RPC_ADSP_RTOS_ATOM_VERS MSM_RPC_VERS(0x71d1094b, 0)
+#define RPC_ADSP_RTOS_MTOA_VERS MSM_RPC_VERS(0xee3a9966, 0)
+#define MSM_ADSP_DRIVER_NAME "rs3000000a:71d1094b"
+#elif CONFIG_MSM_AMSS_VERSION == 6210
+#define RPC_ADSP_RTOS_ATOM_VERS MSM_RPC_VERS(0x20f17fd3, 0)
+#define RPC_ADSP_RTOS_MTOA_VERS MSM_RPC_VERS(0x75babbd6, 0)
+#define MSM_ADSP_DRIVER_NAME "rs3000000a:20f17fd3"
+#else
+#error "Unknown AMSS version"
+#endif
+
+enum rpc_adsp_rtos_proc_type {
+	RPC_ADSP_RTOS_PROC_NONE = 0,
+	RPC_ADSP_RTOS_PROC_MODEM = 1,
+	RPC_ADSP_RTOS_PROC_APPS = 2,
+};
+
+enum {
+	RPC_ADSP_RTOS_CMD_REGISTER_APP,
+	RPC_ADSP_RTOS_CMD_ENABLE,
+	RPC_ADSP_RTOS_CMD_DISABLE,
+	RPC_ADSP_RTOS_CMD_KERNEL_COMMAND,
+	RPC_ADSP_RTOS_CMD_16_COMMAND,
+	RPC_ADSP_RTOS_CMD_32_COMMAND,
+	RPC_ADSP_RTOS_CMD_DISABLE_EVENT_RSP,
+	RPC_ADSP_RTOS_CMD_REMOTE_EVENT,
+	RPC_ADSP_RTOS_CMD_SET_STATE,
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	RPC_ADSP_RTOS_CMD_REMOTE_INIT_INFO_EVENT,
+	RPC_ADSP_RTOS_CMD_GET_INIT_INFO,
+#endif
+};
+
+enum rpc_adsp_rtos_mod_status_type {
+	RPC_ADSP_RTOS_MOD_READY,
+	RPC_ADSP_RTOS_MOD_DISABLE,
+	RPC_ADSP_RTOS_SERVICE_RESET,
+	RPC_ADSP_RTOS_CMD_FAIL,
+	RPC_ADSP_RTOS_CMD_SUCCESS,
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	RPC_ADSP_RTOS_INIT_INFO,
+	RPC_ADSP_RTOS_DISABLE_FAIL,
+#endif
+};
+
+struct rpc_adsp_rtos_app_to_modem_args_t {
+	struct rpc_request_hdr hdr;
+	uint32_t gotit; /* if 1, the next elements are present */
+	uint32_t cmd; /* e.g., RPC_ADSP_RTOS_CMD_REGISTER_APP */
+	uint32_t proc_id; /* e.g., RPC_ADSP_RTOS_PROC_APPS */
+	uint32_t module; /* e.g., QDSP_MODULE_AUDPPTASK */
+};
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+enum qdsp_image_type {
+	QDSP_IMAGE_COMBO,
+	QDSP_IMAGE_GAUDIO,
+	QDSP_IMAGE_QTV_LP,
+	QDSP_IMAGE_MAX,
+	/* DO NOT USE: Force this enum to be a 32bit type to improve speed */
+	QDSP_IMAGE_32BIT_DUMMY = 0x10000
+};
+
+struct adsp_rtos_mp_mtoa_header_type {
+	enum rpc_adsp_rtos_mod_status_type  event;
+	enum rpc_adsp_rtos_proc_type        proc_id;
+};
+
+/* ADSP RTOS MP Communications - Modem to APP's  Event Info*/
+struct adsp_rtos_mp_mtoa_type {
+	uint32_t	module;
+	uint32_t	image;
+	uint32_t	apps_okts;
+};
+
+/* ADSP RTOS MP Communications - Modem to APP's Init Info  */
+#define IMG_MAX         8
+#define ENTRIES_MAX     64
+
+struct queue_to_offset_type {
+	uint32_t	queue;
+	uint32_t	offset;
+};
+
+struct adsp_rtos_mp_mtoa_init_info_type {
+	uint32_t	image_count;
+	uint32_t	num_queue_offsets;
+	struct queue_to_offset_type	queue_offsets_tbl[IMG_MAX][ENTRIES_MAX];
+	uint32_t	num_task_module_entries;
+	uint32_t	task_to_module_tbl[IMG_MAX][ENTRIES_MAX];
+
+	uint32_t	module_table_size;
+	uint32_t	module_entries[ENTRIES_MAX];
+	/*
+	 * queue_offsets[] is to store only queue_offsets
+	 */
+	uint32_t	queue_offsets[IMG_MAX][ENTRIES_MAX];
+};
+
+struct adsp_rtos_mp_mtoa_s_type {
+	struct adsp_rtos_mp_mtoa_header_type mp_mtoa_header;
+
+	uint32_t desc_field;
+	union {
+		struct adsp_rtos_mp_mtoa_init_info_type mp_mtoa_init_packet;
+		struct adsp_rtos_mp_mtoa_type mp_mtoa_packet;
+	} adsp_rtos_mp_mtoa_data;
+};
+
+struct rpc_adsp_rtos_modem_to_app_args_t {
+	struct rpc_request_hdr hdr;
+	uint32_t gotit; /* if 1, the next elements are present */
+	struct adsp_rtos_mp_mtoa_s_type mtoa_pkt;
+};
+#else
+struct rpc_adsp_rtos_modem_to_app_args_t {
+	struct rpc_request_hdr hdr;
+	uint32_t gotit; /* if 1, the next elements are present */
+	uint32_t event; /* e.g., RPC_ADSP_RTOS_CMD_REGISTER_APP */
+	uint32_t proc_id; /* e.g., RPC_ADSP_RTOS_PROC_APPS */
+	uint32_t module; /* e.g., QDSP_MODULE_AUDPPTASK */
+	uint32_t image; /* RPC_QDSP_IMAGE_GAUDIO */
+};
+#endif /* CONFIG_MSM_AMSS_VERSION >= 6350 */
+
+#define ADSP_STATE_DISABLED   0
+#define ADSP_STATE_ENABLING   1
+#define ADSP_STATE_ENABLED    2
+#define ADSP_STATE_DISABLING  3
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+#define ADSP_STATE_INIT_INFO  4
+#endif
+
+struct msm_adsp_module {
+	struct mutex lock;
+	const char *name;
+	unsigned id;
+	struct adsp_info *info;
+
+	struct msm_rpc_endpoint *rpc_client;
+	struct msm_adsp_ops *ops;
+	void *driver_data;
+
+	/* statistics */
+	unsigned num_commands;
+	unsigned num_events;
+
+	wait_queue_head_t state_wait;
+	unsigned state;
+
+	struct platform_device pdev;
+	struct clk *clk;
+	int open_count;
+
+	struct mutex pmem_regions_lock;
+	struct hlist_head pmem_regions;
+	int (*verify_cmd) (struct msm_adsp_module*, unsigned int, void *,
+			   size_t);
+	int (*patch_event) (struct msm_adsp_module*, struct adsp_event *);
+};
+
+extern void msm_adsp_publish_cdevs(struct msm_adsp_module *, unsigned);
+extern int adsp_init_info(struct adsp_info *info);
+
+/* Value to indicate that a queue is not defined for a particular image */
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+#define QDSP_RTOS_NO_QUEUE  0xfffffffe
+#else
+#define QDSP_RTOS_NO_QUEUE  0xffffffff
+#endif
+
+/*
+ * Constants used to communicate with the ADSP RTOS
+ */
+#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M            0x80000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V     0x80000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_AVAIL_V      0x00000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_M              0x70000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_REQ_V    0x00000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V   0x10000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_NO_CMD_V       0x70000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M           0x0E000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V           0x00000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_NO_FREE_BUF_V      0x02000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_KERNEL_FLG_M       0x01000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_MSG_WRITE_V   0x00000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_CMD_V         0x01000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M         0x00FFFFFFU
+#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_CMD_ID_M      0x00FFFFFFU
+
+/* Combination of MUTEX and CMD bits to check if the DSP is busy */
+#define ADSP_RTOS_WRITE_CTRL_WORD_READY_M            0xF0000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_READY_V            0x70000000U
+
+/* RTOS to Host processor command mask values */
+#define ADSP_RTOS_READ_CTRL_WORD_FLAG_M              0x80000000U
+#define ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_WAIT_V      0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_CONT_V      0x80000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_M               0x60000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READ_DONE_V         0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READ_REQ_V          0x20000000U
+#define ADSP_RTOS_READ_CTRL_WORD_NO_CMD_V            0x60000000U
+
+/* Combination of FLAG and COMMAND bits to check if MSG ready */
+#define ADSP_RTOS_READ_CTRL_WORD_READY_M             0xE0000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READY_V             0xA0000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CONT_V              0xC0000000U
+#define ADSP_RTOS_READ_CTRL_WORD_DONE_V              0xE0000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_STATUS_M            0x18000000U
+#define ADSP_RTOS_READ_CTRL_WORD_NO_ERR_V            0x00000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_IN_PROG_M           0x04000000U
+#define ADSP_RTOS_READ_CTRL_WORD_NO_READ_IN_PROG_V   0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READ_IN_PROG_V      0x04000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_TYPE_M          0x03000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_TASK_TO_H_V     0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_KRNL_TO_H_V     0x01000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_H_TO_KRNL_CFM_V 0x02000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_DSP_ADDR_M          0x00FFFFFFU
+
+#define ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M            0x000000FFU
+#define ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M           0x0000FF00U
+
+/* Base address of DSP and DSP hardware registers */
+#define QDSP_RAMC_OFFSET  0x400000
+
+#endif /* _ARCH_ARM_MACH_MSM_ADSP_H */
diff --git a/arch/arm/mach-msm/qdsp5/adsp_6210.c b/arch/arm/mach-msm/qdsp5/adsp_6210.c
new file mode 100644
index 0000000..628c247
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_6210.c
@@ -0,0 +1,283 @@
+/* arch/arm/mach-msm/qdsp5/adsp_6210.h
+ *
+ * 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 "adsp.h"
+
+/* Firmware modules */
+typedef enum { 
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEO_AAC_VOC,
+	QDSP_MODULE_PCM_DEC,
+	QDSP_MODULE_AUDIO_DEC_MP3,
+	QDSP_MODULE_AUDIO_DEC_AAC,
+	QDSP_MODULE_AUDIO_DEC_WMA,
+	QDSP_MODULE_HOSTPCM,
+	QDSP_MODULE_DTMF,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_SBC_ENC,
+	QDSP_MODULE_VOC,
+	QDSP_MODULE_VOC_PCM,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_WAV_ENC,
+	QDSP_MODULE_AACLC_ENC,
+	QDSP_MODULE_VIDEO_AMR,
+	QDSP_MODULE_VOC_AMR,
+	QDSP_MODULE_VOC_EVRC,
+	QDSP_MODULE_VOC_13K,
+	QDSP_MODULE_VOC_FGV,
+	QDSP_MODULE_DIAGTASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_QCAMTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MIDI,
+	QDSP_MODULE_GAUDIO,
+	QDSP_MODULE_VDEC_LP_MODE,
+	QDSP_MODULE_MAX,
+} qdsp_module_type;
+
+#define QDSP_RTOS_MAX_TASK_ID  19U
+
+/* Table of modules indexed by task ID for the GAUDIO image */
+static qdsp_module_type qdsp_gaudio_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the GAUDIO image */
+static uint32_t qdsp_gaudio_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x3be,               /* QDSP_mpuAfeQueue                  */
+	0x3ee,               /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x3c2,               /* QDSP_uPAudPPCmd1Queue             */
+	0x3c6,               /* QDSP_uPAudPPCmd2Queue             */
+	0x3ca,               /* QDSP_uPAudPPCmd3Queue             */
+	0x3da,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	0x3de,               /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	0x3e2,               /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	0x3e6,               /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	0x3ea,               /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x3ce,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x3d6,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x3d2,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE   /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Table of modules indexed by task ID for the COMBO image */
+static qdsp_module_type qdsp_combo_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the COMBO image */
+static uint32_t qdsp_combo_queue_offset_table[] = {
+	0x585,               /* QDSP_lpmCommandQueue              */
+	0x52d,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	0x541,               /* QDSP_mpuModmathCmdQueue           */
+	0x555,               /* QDSP_mpuVDecCmdQueue              */
+	0x559,               /* QDSP_mpuVDecPktQueue              */
+	0x551,               /* QDSP_mpuVEncCmdQueue              */
+	0x535,               /* QDSP_rxMpuDecCmdQueue             */
+	0x539,               /* QDSP_rxMpuDecPktQueue             */
+	0x53d,               /* QDSP_txMpuEncQueue                */
+	0x55d,               /* QDSP_uPAudPPCmd1Queue             */
+	0x561,               /* QDSP_uPAudPPCmd2Queue             */
+	0x565,               /* QDSP_uPAudPPCmd3Queue             */
+	0x575,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	0x579,               /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x569,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x571,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x56d,               /* QDSP_uPAudRecCmdQueue             */
+	0x581,               /* QDSP_uPJpegActionCmdQueue         */
+	0x57d,               /* QDSP_uPJpegCfgCmdQueue            */
+	0x531,               /* QDSP_uPVocProcQueue               */
+	0x545,               /* QDSP_vfeCommandQueue              */
+	0x54d,               /* QDSP_vfeCommandScaleQueue         */
+	0x549                /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Table of modules indexed by task ID for the QTV_LP image */
+static qdsp_module_type qdsp_qtv_lp_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the QTV_LP image */
+static uint32_t qdsp_qtv_lp_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x40c,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	0x410,               /* QDSP_mpuVDecCmdQueue              */
+	0x414,               /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x41c,               /* QDSP_uPAudPPCmd1Queue             */
+	0x420,               /* QDSP_uPAudPPCmd2Queue             */
+	0x424,               /* QDSP_uPAudPPCmd3Queue             */
+	0x430,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x418,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x42c,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x428,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE   /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Tables to convert tasks to modules */
+static uint32_t *qdsp_task_to_module[] = {
+	qdsp_combo_task_to_module_table,
+	qdsp_gaudio_task_to_module_table,
+	qdsp_qtv_lp_task_to_module_table,
+};
+
+/* Tables to retrieve queue offsets */
+static uint32_t *qdsp_queue_offset_table[] = {
+	qdsp_combo_queue_offset_table,
+	qdsp_gaudio_queue_offset_table,
+	qdsp_qtv_lp_queue_offset_table,
+};
+
+#define QDSP_MODULE(n) \
+	{ .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n }
+
+static struct adsp_module_info module_info[] = {
+	QDSP_MODULE(AUDPPTASK),
+	QDSP_MODULE(AUDRECTASK),
+	QDSP_MODULE(AUDPREPROCTASK),
+	QDSP_MODULE(VFETASK),
+	QDSP_MODULE(QCAMTASK),
+	QDSP_MODULE(LPMTASK),
+	QDSP_MODULE(JPEGTASK),
+	QDSP_MODULE(VIDEOTASK),
+	QDSP_MODULE(VDEC_LP_MODE),
+};
+
+int adsp_init_info(struct adsp_info *info)
+{
+	info->send_irq =   0x00c00200;
+	info->read_ctrl =  0x00400038;
+	info->write_ctrl = 0x00400034;
+
+	info->max_msg16_size = 193;
+	info->max_msg32_size = 8;
+
+	info->max_task_id = 16;
+	info->max_module_id = QDSP_MODULE_MAX - 1;
+	info->max_queue_id = QDSP_QUEUE_MAX;
+	info->max_image_id = 2;
+	info->queue_offset = qdsp_queue_offset_table;
+	info->task_to_module = qdsp_task_to_module;
+
+	info->module_count = ARRAY_SIZE(module_info);
+	info->module = module_info;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_6220.c b/arch/arm/mach-msm/qdsp5/adsp_6220.c
new file mode 100644
index 0000000..c4c5a55
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_6220.c
@@ -0,0 +1,284 @@
+/* arch/arm/mach-msm/qdsp5/adsp_6220.h
+ *
+ * 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 "adsp.h"
+
+/* Firmware modules */
+typedef enum { 
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEO_AAC_VOC,
+	QDSP_MODULE_PCM_DEC,
+	QDSP_MODULE_AUDIO_DEC_MP3,
+	QDSP_MODULE_AUDIO_DEC_AAC,
+	QDSP_MODULE_AUDIO_DEC_WMA,
+	QDSP_MODULE_HOSTPCM,
+	QDSP_MODULE_DTMF,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_SBC_ENC,
+	QDSP_MODULE_VOC,
+	QDSP_MODULE_VOC_PCM,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_WAV_ENC,
+	QDSP_MODULE_AACLC_ENC,
+	QDSP_MODULE_VIDEO_AMR,
+	QDSP_MODULE_VOC_AMR,
+	QDSP_MODULE_VOC_EVRC,
+	QDSP_MODULE_VOC_13K,
+	QDSP_MODULE_VOC_FGV,
+	QDSP_MODULE_DIAGTASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_QCAMTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MIDI,
+	QDSP_MODULE_GAUDIO,
+	QDSP_MODULE_VDEC_LP_MODE,
+	QDSP_MODULE_MAX,
+} qdsp_module_type;
+
+#define QDSP_RTOS_MAX_TASK_ID  19U
+
+/* Table of modules indexed by task ID for the GAUDIO image */
+static qdsp_module_type qdsp_gaudio_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the GAUDIO image */
+static uint32_t qdsp_gaudio_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x3f0,               /* QDSP_mpuAfeQueue                  */
+	0x420,               /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x3f4,               /* QDSP_uPAudPPCmd1Queue             */
+	0x3f8,               /* QDSP_uPAudPPCmd2Queue             */
+	0x3fc,               /* QDSP_uPAudPPCmd3Queue             */
+	0x40c,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	0x410,               /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	0x414,               /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	0x418,               /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	0x41c,               /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x400,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x408,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x404,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE   /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Table of modules indexed by task ID for the COMBO image */
+static qdsp_module_type qdsp_combo_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the COMBO image */
+static uint32_t qdsp_combo_queue_offset_table[] = {
+	0x6f2,               /* QDSP_lpmCommandQueue              */
+	0x69e,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	0x6b2,               /* QDSP_mpuModmathCmdQueue           */
+	0x6c6,               /* QDSP_mpuVDecCmdQueue              */
+	0x6ca,               /* QDSP_mpuVDecPktQueue              */
+	0x6c2,               /* QDSP_mpuVEncCmdQueue              */
+	0x6a6,               /* QDSP_rxMpuDecCmdQueue             */
+	0x6aa,               /* QDSP_rxMpuDecPktQueue             */
+	0x6ae,               /* QDSP_txMpuEncQueue                */
+	0x6ce,               /* QDSP_uPAudPPCmd1Queue             */
+	0x6d2,               /* QDSP_uPAudPPCmd2Queue             */
+	0x6d6,               /* QDSP_uPAudPPCmd3Queue             */
+	0x6e6,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x6da,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x6e2,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x6de,               /* QDSP_uPAudRecCmdQueue             */
+	0x6ee,               /* QDSP_uPJpegActionCmdQueue         */
+	0x6ea,               /* QDSP_uPJpegCfgCmdQueue            */
+	0x6a2,               /* QDSP_uPVocProcQueue               */
+	0x6b6,               /* QDSP_vfeCommandQueue              */
+	0x6be,               /* QDSP_vfeCommandScaleQueue         */
+	0x6ba                /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Table of modules indexed by task ID for the QTV_LP image */
+static qdsp_module_type qdsp_qtv_lp_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the QTV_LP image */
+static uint32_t qdsp_qtv_lp_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x430,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	0x434,               /* QDSP_mpuVDecCmdQueue              */
+	0x438,               /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x440,               /* QDSP_uPAudPPCmd1Queue             */
+	0x444,               /* QDSP_uPAudPPCmd2Queue             */
+	0x448,               /* QDSP_uPAudPPCmd3Queue             */
+	0x454,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x43c,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x450,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x44c,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE   /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Tables to convert tasks to modules */
+static qdsp_module_type *qdsp_task_to_module[] = {
+	qdsp_combo_task_to_module_table,
+	qdsp_gaudio_task_to_module_table,
+	qdsp_qtv_lp_task_to_module_table,
+};
+
+/* Tables to retrieve queue offsets */
+static uint32_t *qdsp_queue_offset_table[] = {
+	qdsp_combo_queue_offset_table,
+	qdsp_gaudio_queue_offset_table,
+	qdsp_qtv_lp_queue_offset_table,
+};
+
+#define QDSP_MODULE(n) \
+	{ .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n }
+
+static struct adsp_module_info module_info[] = {
+	QDSP_MODULE(AUDPLAY0TASK),
+	QDSP_MODULE(AUDPPTASK),
+	QDSP_MODULE(AUDPREPROCTASK),
+	QDSP_MODULE(AUDRECTASK),
+	QDSP_MODULE(VFETASK),
+	QDSP_MODULE(QCAMTASK),
+	QDSP_MODULE(LPMTASK),
+	QDSP_MODULE(JPEGTASK),
+	QDSP_MODULE(VIDEOTASK),
+	QDSP_MODULE(VDEC_LP_MODE),
+};
+
+int adsp_init_info(struct adsp_info *info)
+{
+	info->send_irq =   0x00c00200;
+	info->read_ctrl =  0x00400038;
+	info->write_ctrl = 0x00400034;
+
+	info->max_msg16_size = 193;
+	info->max_msg32_size = 8;
+
+	info->max_task_id = 16;
+	info->max_module_id = QDSP_MODULE_MAX - 1;
+	info->max_queue_id = QDSP_QUEUE_MAX;
+	info->max_image_id = 2;
+	info->queue_offset = qdsp_queue_offset_table;
+	info->task_to_module = qdsp_task_to_module;
+
+	info->module_count = ARRAY_SIZE(module_info);
+	info->module = module_info;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_6225.c b/arch/arm/mach-msm/qdsp5/adsp_6225.c
new file mode 100644
index 0000000..5078afb
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_6225.c
@@ -0,0 +1,328 @@
+/* arch/arm/mach-msm/qdsp5/adsp_6225.h
+ *
+ * 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 "adsp.h"
+
+/* Firmware modules */
+typedef enum {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEO_AAC_VOC,
+	QDSP_MODULE_PCM_DEC,
+	QDSP_MODULE_AUDIO_DEC_MP3,
+	QDSP_MODULE_AUDIO_DEC_AAC,
+	QDSP_MODULE_AUDIO_DEC_WMA,
+	QDSP_MODULE_HOSTPCM,
+	QDSP_MODULE_DTMF,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_SBC_ENC,
+	QDSP_MODULE_VOC_UMTS,
+	QDSP_MODULE_VOC_CDMA,
+	QDSP_MODULE_VOC_PCM,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_WAV_ENC,
+	QDSP_MODULE_AACLC_ENC,
+	QDSP_MODULE_VIDEO_AMR,
+	QDSP_MODULE_VOC_AMR,
+	QDSP_MODULE_VOC_EVRC,
+	QDSP_MODULE_VOC_13K,
+	QDSP_MODULE_VOC_FGV,
+	QDSP_MODULE_DIAGTASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_QCAMTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MIDI,
+	QDSP_MODULE_GAUDIO,
+	QDSP_MODULE_VDEC_LP_MODE,
+	QDSP_MODULE_MAX,
+} qdsp_module_type;
+
+#define QDSP_RTOS_MAX_TASK_ID  30U
+
+/* Table of modules indexed by task ID for the GAUDIO image */
+static qdsp_module_type qdsp_gaudio_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+};
+
+/* Queue offset table indexed by queue ID for the GAUDIO image */
+static uint32_t qdsp_gaudio_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x3f0,               /* QDSP_mpuAfeQueue                  */
+	0x420,               /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x3f4,               /* QDSP_uPAudPPCmd1Queue             */
+	0x3f8,               /* QDSP_uPAudPPCmd2Queue             */
+	0x3fc,               /* QDSP_uPAudPPCmd3Queue             */
+	0x40c,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	0x410,               /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	0x414,               /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	0x418,               /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	0x41c,               /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x400,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x408,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x404,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandTableQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPDiagQueue                  */
+};
+
+/* Table of modules indexed by task ID for the COMBO image */
+static qdsp_module_type qdsp_combo_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_DIAGTASK,
+	QDSP_MODULE_MAX,
+};
+
+/* Queue offset table indexed by queue ID for the COMBO image */
+static uint32_t qdsp_combo_queue_offset_table[] = {
+	0x714,               /* QDSP_lpmCommandQueue              */
+	0x6bc,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	0x6d0,               /* QDSP_mpuModmathCmdQueue           */
+	0x6e8,               /* QDSP_mpuVDecCmdQueue              */
+	0x6ec,               /* QDSP_mpuVDecPktQueue              */
+	0x6e4,               /* QDSP_mpuVEncCmdQueue              */
+	0x6c4,               /* QDSP_rxMpuDecCmdQueue             */
+	0x6c8,               /* QDSP_rxMpuDecPktQueue             */
+	0x6cc,               /* QDSP_txMpuEncQueue                */
+	0x6f0,               /* QDSP_uPAudPPCmd1Queue             */
+	0x6f4,               /* QDSP_uPAudPPCmd2Queue             */
+	0x6f8,               /* QDSP_uPAudPPCmd3Queue             */
+	0x708,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x6fc,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x704,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x700,               /* QDSP_uPAudRecCmdQueue             */
+	0x710,               /* QDSP_uPJpegActionCmdQueue         */
+	0x70c,               /* QDSP_uPJpegCfgCmdQueue            */
+	0x6c0,               /* QDSP_uPVocProcQueue               */
+	0x6d8,               /* QDSP_vfeCommandQueue              */
+	0x6e0,               /* QDSP_vfeCommandScaleQueue         */
+	0x6dc,               /* QDSP_vfeCommandTableQueue         */
+	0x6d4,               /* QDSP_uPDiagQueue                  */
+};
+
+/* Table of modules indexed by task ID for the QTV_LP image */
+static qdsp_module_type qdsp_qtv_lp_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+};
+
+/* Queue offset table indexed by queue ID for the QTV_LP image */
+static uint32_t qdsp_qtv_lp_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x3fe,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	0x402,               /* QDSP_mpuVDecCmdQueue              */
+	0x406,               /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x40e,               /* QDSP_uPAudPPCmd1Queue             */
+	0x412,               /* QDSP_uPAudPPCmd2Queue             */
+	0x416,               /* QDSP_uPAudPPCmd3Queue             */
+	0x422,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x40a,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x41e,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x41a,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandTableQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPDiagQueue                  */
+};
+
+/* Tables to convert tasks to modules */
+static qdsp_module_type *qdsp_task_to_module[] = {
+	qdsp_combo_task_to_module_table,
+	qdsp_gaudio_task_to_module_table,
+	qdsp_qtv_lp_task_to_module_table,
+};
+
+/* Tables to retrieve queue offsets */
+static uint32_t *qdsp_queue_offset_table[] = {
+	qdsp_combo_queue_offset_table,
+	qdsp_gaudio_queue_offset_table,
+	qdsp_qtv_lp_queue_offset_table,
+};
+
+#define QDSP_MODULE(n, clkname, clkrate, verify_cmd_func, patch_event_func) \
+	{ .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n, \
+	  .clk_name = clkname, .clk_rate = clkrate, \
+	  .verify_cmd = verify_cmd_func, .patch_event = patch_event_func }
+
+static struct adsp_module_info module_info[] = {
+	QDSP_MODULE(AUDPLAY0TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPPTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDRECTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPREPROCTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(VFETASK, "vfe_clk", 0, adsp_vfe_verify_cmd,
+		adsp_vfe_patch_event),
+	QDSP_MODULE(QCAMTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(LPMTASK, NULL, 0, adsp_lpm_verify_cmd, NULL),
+	QDSP_MODULE(JPEGTASK, "vdc_clk", 0, adsp_jpeg_verify_cmd,
+		adsp_jpeg_patch_event),
+	QDSP_MODULE(VIDEOTASK, "vdc_clk", 96000000,
+		adsp_video_verify_cmd, NULL),
+	QDSP_MODULE(VDEC_LP_MODE, NULL, 0, NULL, NULL),
+	QDSP_MODULE(VIDEOENCTASK, "vdc_clk", 96000000,
+		adsp_videoenc_verify_cmd, NULL),
+};
+
+int adsp_init_info(struct adsp_info *info)
+{
+	info->send_irq =   0x00c00200;
+	info->read_ctrl =  0x00400038;
+	info->write_ctrl = 0x00400034;
+
+	info->max_msg16_size = 193;
+	info->max_msg32_size = 8;
+
+	info->max_task_id = 16;
+	info->max_module_id = QDSP_MODULE_MAX - 1;
+	info->max_queue_id = QDSP_QUEUE_MAX;
+	info->max_image_id = 2;
+	info->queue_offset = qdsp_queue_offset_table;
+	info->task_to_module = qdsp_task_to_module;
+
+	info->module_count = ARRAY_SIZE(module_info);
+	info->module = module_info;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_driver.c b/arch/arm/mach-msm/qdsp5/adsp_driver.c
new file mode 100644
index 0000000..8197765
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_driver.c
@@ -0,0 +1,642 @@
+/* arch/arm/mach-msm/qdsp5/adsp_driver.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Iliyan Malchev <ibm@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/cdev.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "adsp.h"
+
+#include <linux/msm_adsp.h>
+#include <linux/android_pmem.h>
+
+struct adsp_pmem_region {
+	struct hlist_node list;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	struct file *file;
+};
+
+struct adsp_device {
+	struct msm_adsp_module *module;
+
+	spinlock_t event_queue_lock;
+	wait_queue_head_t event_wait;
+	struct list_head event_queue;
+	int abort;
+
+	const char *name;
+	struct device *device;
+	struct cdev cdev;
+};
+
+static struct adsp_device *inode_to_device(struct inode *inode);
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = __v >= __r->vaddr && 				\
+		__e <= __r->vaddr + __r->len;			\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+static int adsp_pmem_check(struct msm_adsp_module *module,
+		void *vaddr, unsigned long len)
+{
+	struct adsp_pmem_region *region_elt;
+	struct hlist_node *node;
+	struct adsp_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			printk(KERN_ERR "adsp: module %s:"
+				" region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				module->name,
+				vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr,
+				region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int adsp_pmem_add(struct msm_adsp_module *module,
+			 struct adsp_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct adsp_pmem_region *region;
+	int rc = -EINVAL;
+
+	mutex_lock(&module->pmem_regions_lock);
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+	INIT_HLIST_NODE(&region->list);
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = adsp_pmem_check(module, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+
+	hlist_add_head(&region->list, &module->pmem_regions);
+end:
+	mutex_unlock(&module->pmem_regions_lock);
+	return rc;
+}
+
+static int adsp_pmem_lookup_vaddr(struct msm_adsp_module *module, void **addr,
+		     unsigned long len, struct adsp_pmem_region **region)
+{
+	struct hlist_node *node;
+	void *vaddr = *addr;
+	struct adsp_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+		if (vaddr >= region_elt->vaddr &&
+		    vaddr < region_elt->vaddr + region_elt->len &&
+		    vaddr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		printk(KERN_ERR "adsp: module %s: "
+			"multiple hits for vaddr %p, len %ld\n",
+			module->name, vaddr, len);
+		hlist_for_each_entry(region_elt, node,
+				&module->pmem_regions, list) {
+			if (vaddr >= region_elt->vaddr &&
+			    vaddr < region_elt->vaddr + region_elt->len &&
+			    vaddr + len <= region_elt->vaddr + region_elt->len)
+				printk(KERN_ERR "\t%p, %ld --> %p\n",
+					region_elt->vaddr,
+					region_elt->len,
+					(void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
+			   unsigned long *kvaddr, unsigned long len)
+{
+	struct adsp_pmem_region *region;
+	void *vaddr = *addr;
+	unsigned long *paddr = (unsigned long *)addr;
+	int ret;
+
+	ret = adsp_pmem_lookup_vaddr(module, addr, len, &region);
+	if (ret) {
+		printk(KERN_ERR "adsp: not patching %s (paddr & kvaddr),"
+			" lookup (%p, %ld) failed\n",
+			module->name, vaddr, len);
+		return ret;
+	}
+	*paddr = region->paddr + (vaddr - region->vaddr);
+	*kvaddr = region->kvaddr + (vaddr - region->vaddr);
+	return 0;
+}
+
+int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr,
+		    unsigned long len)
+{
+	struct adsp_pmem_region *region;
+	void *vaddr = *addr;
+	unsigned long *paddr = (unsigned long *)addr;
+	int ret;
+
+	ret = adsp_pmem_lookup_vaddr(module, addr, len, &region);
+	if (ret) {
+		printk(KERN_ERR "adsp: not patching %s, lookup (%p, %ld) failed\n",
+			module->name, vaddr, len);
+		return ret;
+	}
+
+	*paddr = region->paddr + (vaddr - region->vaddr);
+	return 0;
+}
+
+static int adsp_verify_cmd(struct msm_adsp_module *module,
+			   unsigned int queue_id, void *cmd_data,
+			   size_t cmd_size)
+{
+	/* call the per module verifier */
+	if (module->verify_cmd)
+		return module->verify_cmd(module, queue_id, cmd_data,
+					     cmd_size);
+	else
+		printk(KERN_INFO "adsp: no packet verifying function "
+				 "for task %s\n", module->name);
+	return 0;
+}
+
+static long adsp_write_cmd(struct adsp_device *adev, void __user *arg)
+{
+	struct adsp_command_t cmd;
+	unsigned char buf[256];
+	void *cmd_data;
+	long rc;
+
+	if (copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)))
+		return -EFAULT;
+
+	if (cmd.len > 256) {
+		cmd_data = kmalloc(cmd.len, GFP_USER);
+		if (!cmd_data)
+			return -ENOMEM;
+	} else {
+		cmd_data = buf;
+	}
+
+	if (copy_from_user(cmd_data, (void __user *)(cmd.data), cmd.len)) {
+		rc = -EFAULT;
+		goto end;
+	}
+
+	mutex_lock(&adev->module->pmem_regions_lock);
+	if (adsp_verify_cmd(adev->module, cmd.queue, cmd_data, cmd.len)) {
+		printk(KERN_ERR "module %s: verify failed.\n",
+			adev->module->name);
+		rc = -EINVAL;
+		goto end;
+	}
+	rc = msm_adsp_write(adev->module, cmd.queue, cmd_data, cmd.len);
+end:
+	mutex_unlock(&adev->module->pmem_regions_lock);
+
+	if (cmd.len > 256)
+		kfree(cmd_data);
+
+	return rc;
+}
+
+static int adsp_events_pending(struct adsp_device *adev)
+{
+	unsigned long flags;
+	int yes;
+	spin_lock_irqsave(&adev->event_queue_lock, flags);
+	yes = !list_empty(&adev->event_queue);
+	spin_unlock_irqrestore(&adev->event_queue_lock, flags);
+	return yes || adev->abort;
+}
+
+static int adsp_pmem_lookup_paddr(struct msm_adsp_module *module, void **addr,
+		     struct adsp_pmem_region **region)
+{
+	struct hlist_node *node;
+	unsigned long paddr = (unsigned long)(*addr);
+	struct adsp_pmem_region *region_elt;
+
+	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+		if (paddr >= region_elt->paddr &&
+		    paddr < region_elt->paddr + region_elt->len) {
+			*region = region_elt;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr)
+{
+	struct adsp_pmem_region *region;
+	unsigned long paddr = (unsigned long)(*addr);
+	unsigned long *vaddr = (unsigned long *)addr;
+	int ret;
+
+	ret = adsp_pmem_lookup_paddr(module, addr, &region);
+	if (ret) {
+		printk(KERN_ERR "adsp: not patching %s, paddr %p lookup failed\n",
+			module->name, vaddr);
+		return ret;
+	}
+
+	*vaddr = (unsigned long)region->vaddr + (paddr - region->paddr);
+	return 0;
+}
+
+static int adsp_patch_event(struct msm_adsp_module *module,
+				struct adsp_event *event)
+{
+	/* call the per-module msg verifier */
+	if (module->patch_event)
+		return module->patch_event(module, event);
+	return 0;
+}
+
+static long adsp_get_event(struct adsp_device *adev, void __user *arg)
+{
+	unsigned long flags;
+	struct adsp_event *data = NULL;
+	struct adsp_event_t evt;
+	int timeout;
+	long rc = 0;
+
+	if (copy_from_user(&evt, arg, sizeof(struct adsp_event_t)))
+		return -EFAULT;
+
+	timeout = (int)evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			adev->event_wait, adsp_events_pending(adev),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			adev->event_wait, adsp_events_pending(adev));
+	}
+	if (rc < 0)
+		return rc;
+
+	if (adev->abort)
+		return -ENODEV;
+
+	spin_lock_irqsave(&adev->event_queue_lock, flags);
+	if (!list_empty(&adev->event_queue)) {
+		data = list_first_entry(&adev->event_queue,
+					struct adsp_event, list);
+		list_del(&data->list);
+	}
+	spin_unlock_irqrestore(&adev->event_queue_lock, flags);
+
+	if (!data)
+		return -EAGAIN;
+
+	/* DSP messages are type 0; they may contain physical addresses */
+	if (data->type == 0)
+		adsp_patch_event(adev->module, data);
+
+	/* map adsp_event --> adsp_event_t */
+	if (evt.len < data->size) {
+		rc = -ETOOSMALL;
+		goto end;
+	}
+	if (data->msg_id != EVENT_MSG_ID) {
+		if (copy_to_user((void *)(evt.data), data->data.msg16,
+					data->size)) {
+			rc = -EFAULT;
+			goto end;
+	}
+	} else {
+		if (copy_to_user((void *)(evt.data), data->data.msg32,
+					data->size)) {
+			rc = -EFAULT;
+			goto end;
+		}
+	}
+
+	evt.type = data->type; /* 0 --> from aDSP, 1 --> from ARM9 */
+	evt.msg_id = data->msg_id;
+	evt.flags = data->is16;
+	evt.len = data->size;
+	if (copy_to_user(arg, &evt, sizeof(evt)))
+		rc = -EFAULT;
+end:
+	kfree(data);
+	return rc;
+}
+
+static long adsp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct adsp_device *adev = filp->private_data;
+
+	switch (cmd) {
+	case ADSP_IOCTL_ENABLE:
+		return msm_adsp_enable(adev->module);
+
+	case ADSP_IOCTL_DISABLE:
+		return msm_adsp_disable(adev->module);
+
+	case ADSP_IOCTL_DISABLE_EVENT_RSP:
+		return 0;
+
+	case ADSP_IOCTL_DISABLE_ACK:
+		pr_err("adsp: ADSP_IOCTL_DISABLE_ACK is not implemented.\n");
+		break;
+
+	case ADSP_IOCTL_WRITE_COMMAND:
+		return adsp_write_cmd(adev, (void __user *) arg);
+
+	case ADSP_IOCTL_GET_EVENT:
+		return adsp_get_event(adev, (void __user *) arg);
+
+	case ADSP_IOCTL_SET_CLKRATE: {
+#if CONFIG_MSM_AMSS_VERSION==6350
+		unsigned long clk_rate;
+		if (copy_from_user(&clk_rate, (void *) arg, sizeof(clk_rate)))
+			return -EFAULT;
+		return adsp_set_clkrate(adev->module, clk_rate);
+#endif
+	}
+
+	case ADSP_IOCTL_REGISTER_PMEM: {
+		struct adsp_pmem_info info;
+		if (copy_from_user(&info, (void *) arg, sizeof(info)))
+			return -EFAULT;
+		return adsp_pmem_add(adev->module, &info);
+	}
+
+	case ADSP_IOCTL_ABORT_EVENT_READ:
+		adev->abort = 1;
+		wake_up(&adev->event_wait);
+		break;
+
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int adsp_release(struct inode *inode, struct file *filp)
+{
+	struct adsp_device *adev = filp->private_data;
+	struct msm_adsp_module *module = adev->module;
+	struct hlist_node *node, *tmp;
+	struct adsp_pmem_region *region;
+
+	pr_info("adsp_release() '%s'\n", adev->name);
+
+	/* clear module before putting it to avoid race with open() */
+	adev->module = NULL;
+
+	mutex_lock(&module->pmem_regions_lock);
+	hlist_for_each_safe(node, tmp, &module->pmem_regions) {
+		region = hlist_entry(node, struct adsp_pmem_region, list);
+		hlist_del(node);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+	mutex_unlock(&module->pmem_regions_lock);
+	BUG_ON(!hlist_empty(&module->pmem_regions));
+
+	msm_adsp_put(module);
+	return 0;
+}
+
+static void adsp_event(void *driver_data, unsigned id, size_t len,
+		       void (*getevent)(void *ptr, size_t len))
+{
+	struct adsp_device *adev = driver_data;
+	struct adsp_event *event;
+	unsigned long flags;
+
+	if (len > ADSP_EVENT_MAX_SIZE) {
+		pr_err("adsp_event: event too large (%d bytes)\n", len);
+		return;
+	}
+
+	event = kmalloc(sizeof(*event), GFP_ATOMIC);
+	if (!event) {
+		pr_err("adsp_event: cannot allocate buffer\n");
+		return;
+	}
+
+	if (id != EVENT_MSG_ID) {
+		event->type = 0;
+		event->is16 = 0;
+		event->msg_id = id;
+		event->size = len;
+
+		getevent(event->data.msg16, len);
+	} else {
+		event->type = 1;
+		event->is16 = 1;
+		event->msg_id = id;
+		event->size = len;
+		getevent(event->data.msg32, len);
+	}
+
+	spin_lock_irqsave(&adev->event_queue_lock, flags);
+	list_add_tail(&event->list, &adev->event_queue);
+	spin_unlock_irqrestore(&adev->event_queue_lock, flags);
+	wake_up(&adev->event_wait);
+}
+
+static struct msm_adsp_ops adsp_ops = {
+	.event = adsp_event,
+};
+
+static int adsp_open(struct inode *inode, struct file *filp)
+{
+	struct adsp_device *adev;
+	int rc;
+
+	rc = nonseekable_open(inode, filp);
+	if (rc < 0)
+		return rc;
+
+	adev = inode_to_device(inode);
+	if (!adev)
+		return -ENODEV;
+
+	pr_info("adsp_open() name = '%s'\n", adev->name);
+
+	rc = msm_adsp_get(adev->name, &adev->module, &adsp_ops, adev);
+	if (rc)
+		return rc;
+
+	pr_info("adsp_open() module '%s' adev %p\n", adev->name, adev);
+	filp->private_data = adev;
+	adev->abort = 0;
+	INIT_HLIST_HEAD(&adev->module->pmem_regions);
+	mutex_init(&adev->module->pmem_regions_lock);
+
+	return 0;
+}
+
+static unsigned adsp_device_count;
+static struct adsp_device *adsp_devices;
+
+static struct adsp_device *inode_to_device(struct inode *inode)
+{
+	unsigned n = MINOR(inode->i_rdev);
+	if (n < adsp_device_count) {
+		if (adsp_devices[n].device)
+			return adsp_devices + n;
+	}
+	return NULL;
+}
+
+static dev_t adsp_devno;
+static struct class *adsp_class;
+
+static struct file_operations adsp_fops = {
+	.owner = THIS_MODULE,
+	.open = adsp_open,
+	.unlocked_ioctl = adsp_ioctl,
+	.release = adsp_release,
+};
+
+static void adsp_create(struct adsp_device *adev, const char *name,
+			struct device *parent, dev_t devt)
+{
+	struct device *dev;
+	int rc;
+
+	dev = device_create(adsp_class, parent, devt, "%s", name);
+	if (IS_ERR(dev))
+		return;
+
+	init_waitqueue_head(&adev->event_wait);
+	INIT_LIST_HEAD(&adev->event_queue);
+	spin_lock_init(&adev->event_queue_lock);
+
+	cdev_init(&adev->cdev, &adsp_fops);
+	adev->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&adev->cdev, devt, 1);
+	if (rc < 0) {
+		device_destroy(adsp_class, devt);
+	} else {
+		adev->device = dev;
+		adev->name = name;
+	}
+}
+
+void msm_adsp_publish_cdevs(struct msm_adsp_module *modules, unsigned n)
+{
+	int rc;
+
+	adsp_devices = kzalloc(sizeof(struct adsp_device) * n, GFP_KERNEL);
+	if (!adsp_devices)
+		return;
+
+	adsp_class = class_create(THIS_MODULE, "adsp");
+	if (IS_ERR(adsp_class))
+		goto fail_create_class;
+
+	rc = alloc_chrdev_region(&adsp_devno, 0, n, "adsp");
+	if (rc < 0)
+		goto fail_alloc_region;
+
+	adsp_device_count = n;
+	for (n = 0; n < adsp_device_count; n++) {
+		adsp_create(adsp_devices + n,
+			    modules[n].name, &modules[n].pdev.dev,
+			    MKDEV(MAJOR(adsp_devno), n));
+	}
+
+	return;
+
+fail_alloc_region:
+	class_unregister(adsp_class);
+fail_create_class:
+	kfree(adsp_devices);
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_info.c b/arch/arm/mach-msm/qdsp5/adsp_info.c
new file mode 100644
index 0000000..b9c77d2
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_info.c
@@ -0,0 +1,121 @@
+/* arch/arm/mach-msm/adsp_info.c
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated.
+ * Copyright (c) 2008 QUALCOMM USA, 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 "adsp.h"
+
+/* Firmware modules */
+#define QDSP_MODULE_KERNEL                  0x0106dd4e
+#define QDSP_MODULE_AFETASK                 0x0106dd6f
+#define QDSP_MODULE_AUDPLAY0TASK            0x0106dd70
+#define QDSP_MODULE_AUDPLAY1TASK            0x0106dd71
+#define QDSP_MODULE_AUDPPTASK               0x0106dd72
+#define QDSP_MODULE_VIDEOTASK               0x0106dd73
+#define QDSP_MODULE_VIDEO_AAC_VOC           0x0106dd74
+#define QDSP_MODULE_PCM_DEC                 0x0106dd75
+#define QDSP_MODULE_AUDIO_DEC_MP3           0x0106dd76
+#define QDSP_MODULE_AUDIO_DEC_AAC           0x0106dd77
+#define QDSP_MODULE_AUDIO_DEC_WMA           0x0106dd78
+#define QDSP_MODULE_HOSTPCM                 0x0106dd79
+#define QDSP_MODULE_DTMF                    0x0106dd7a
+#define QDSP_MODULE_AUDRECTASK              0x0106dd7b
+#define QDSP_MODULE_AUDPREPROCTASK          0x0106dd7c
+#define QDSP_MODULE_SBC_ENC                 0x0106dd7d
+#define QDSP_MODULE_VOC_UMTS                0x0106dd9a
+#define QDSP_MODULE_VOC_CDMA                0x0106dd98
+#define QDSP_MODULE_VOC_PCM                 0x0106dd7f
+#define QDSP_MODULE_VOCENCTASK              0x0106dd80
+#define QDSP_MODULE_VOCDECTASK              0x0106dd81
+#define QDSP_MODULE_VOICEPROCTASK           0x0106dd82
+#define QDSP_MODULE_VIDEOENCTASK            0x0106dd83
+#define QDSP_MODULE_VFETASK                 0x0106dd84
+#define QDSP_MODULE_WAV_ENC                 0x0106dd85
+#define QDSP_MODULE_AACLC_ENC               0x0106dd86
+#define QDSP_MODULE_VIDEO_AMR               0x0106dd87
+#define QDSP_MODULE_VOC_AMR                 0x0106dd88
+#define QDSP_MODULE_VOC_EVRC                0x0106dd89
+#define QDSP_MODULE_VOC_13K                 0x0106dd8a
+#define QDSP_MODULE_VOC_FGV                 0x0106dd8b
+#define QDSP_MODULE_DIAGTASK                0x0106dd8c
+#define QDSP_MODULE_JPEGTASK                0x0106dd8d
+#define QDSP_MODULE_LPMTASK                 0x0106dd8e
+#define QDSP_MODULE_QCAMTASK                0x0106dd8f
+#define QDSP_MODULE_MODMATHTASK             0x0106dd90
+#define QDSP_MODULE_AUDPLAY2TASK            0x0106dd91
+#define QDSP_MODULE_AUDPLAY3TASK            0x0106dd92
+#define QDSP_MODULE_AUDPLAY4TASK            0x0106dd93
+#define QDSP_MODULE_GRAPHICSTASK            0x0106dd94
+#define QDSP_MODULE_MIDI                    0x0106dd95
+#define QDSP_MODULE_GAUDIO                  0x0106dd96
+#define QDSP_MODULE_VDEC_LP_MODE            0x0106dd97
+#define QDSP_MODULE_MAX                     0x7fffffff
+
+   /* DO NOT USE: Force this enum to be a 32bit type to improve speed */
+#define QDSP_MODULE_32BIT_DUMMY 0x10000
+
+static uint32_t *qdsp_task_to_module[IMG_MAX];
+static uint32_t	*qdsp_queue_offset_table[IMG_MAX];
+
+#define QDSP_MODULE(n, clkname, clkrate, verify_cmd_func, patch_event_func) \
+	{ .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n, \
+	  .clk_name = clkname, .clk_rate = clkrate, \
+	  .verify_cmd = verify_cmd_func, .patch_event = patch_event_func }
+
+static struct adsp_module_info module_info[] = {
+	QDSP_MODULE(AUDPLAY0TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPPTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDRECTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPREPROCTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(VFETASK, "vfe_clk", 0, adsp_vfe_verify_cmd,
+		adsp_vfe_patch_event),
+	QDSP_MODULE(QCAMTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(LPMTASK, NULL, 0, adsp_lpm_verify_cmd, NULL),
+	QDSP_MODULE(JPEGTASK, "vdc_clk", 96000000, adsp_jpeg_verify_cmd,
+		adsp_jpeg_patch_event),
+	QDSP_MODULE(VIDEOTASK, "vdc_clk", 96000000,
+		adsp_video_verify_cmd, NULL),
+	QDSP_MODULE(VDEC_LP_MODE, NULL, 0, NULL, NULL),
+	QDSP_MODULE(VIDEOENCTASK, "vdc_clk", 96000000,
+		adsp_videoenc_verify_cmd, NULL),
+};
+
+int adsp_init_info(struct adsp_info *info)
+{
+	uint32_t img_num;
+
+	info->send_irq =   0x00c00200;
+	info->read_ctrl =  0x00400038;
+	info->write_ctrl = 0x00400034;
+
+	info->max_msg16_size = 193;
+	info->max_msg32_size = 8;
+	for (img_num = 0; img_num < IMG_MAX; img_num++)
+		qdsp_queue_offset_table[img_num] =
+		&info->init_info_ptr->queue_offsets[img_num][0];
+
+	for (img_num = 0; img_num < IMG_MAX; img_num++)
+		qdsp_task_to_module[img_num] =
+		&info->init_info_ptr->task_to_module_tbl[img_num][0];
+	info->max_task_id = 30;
+	info->max_module_id = QDSP_MODULE_MAX - 1;
+	info->max_queue_id = QDSP_MAX_NUM_QUEUES;
+	info->max_image_id = 2;
+	info->queue_offset = qdsp_queue_offset_table;
+	info->task_to_module = qdsp_task_to_module;
+
+	info->module_count = ARRAY_SIZE(module_info);
+	info->module = module_info;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_jpeg_patch_event.c b/arch/arm/mach-msm/qdsp5/adsp_jpeg_patch_event.c
new file mode 100644
index 0000000..4f493ed
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_jpeg_patch_event.c
@@ -0,0 +1,31 @@
+/* arch/arm/mach-msm/qdsp5/adsp_jpeg_patch_event.c
+ *
+ * Verification code for aDSP JPEG events.
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated
+ * 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 <mach/qdsp5/qdsp5jpegmsg.h>
+#include "adsp.h"
+
+int adsp_jpeg_patch_event(struct msm_adsp_module *module,
+			struct adsp_event *event)
+{
+	if (event->msg_id == JPEG_MSG_ENC_OP_PRODUCED) {
+		jpeg_msg_enc_op_produced *op = (jpeg_msg_enc_op_produced *)event->data.msg16;
+		return adsp_pmem_paddr_fixup(module, (void **)&op->op_buf_addr);
+	}
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_jpeg_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_jpeg_verify_cmd.c
new file mode 100644
index 0000000..b33eba2
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_jpeg_verify_cmd.c
@@ -0,0 +1,182 @@
+/* arch/arm/mach-msm/qdsp5/adsp_jpeg_verify_cmd.c
+ *
+ * Verification code for aDSP JPEG packets from userspace.
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated
+ * 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 <mach/qdsp5/qdsp5jpegcmdi.h>
+#include "adsp.h"
+
+static uint32_t dec_fmt;
+
+static inline void get_sizes(jpeg_cmd_enc_cfg *cmd, uint32_t *luma_size,
+			     uint32_t *chroma_size)
+{
+	uint32_t fmt, luma_width, luma_height;
+
+	fmt = cmd->process_cfg & JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_M;
+	luma_width = (cmd->ip_size_cfg & JPEG_CMD_IP_SIZE_CFG_LUMA_WIDTH_M)
+		      >> 16;
+	luma_height = cmd->frag_cfg & JPEG_CMD_FRAG_SIZE_LUMA_HEIGHT_M;
+	*luma_size = luma_width * luma_height;
+	if (fmt == JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V2)
+		*chroma_size = *luma_size/2;
+	else
+		*chroma_size = *luma_size;
+}
+
+static inline int verify_jpeg_cmd_enc_cfg(struct msm_adsp_module *module,
+                             		  void *cmd_data, size_t cmd_size)
+{
+	jpeg_cmd_enc_cfg *cmd = (jpeg_cmd_enc_cfg *)cmd_data;
+	uint32_t luma_size, chroma_size;
+	int i, num_frags;
+
+	if (cmd_size != sizeof(jpeg_cmd_enc_cfg)) {
+		printk(KERN_ERR "adsp: module %s: JPEG ENC CFG invalid cmd_size %d\n",
+			module->name, cmd_size);
+		return -1;
+	}
+
+	get_sizes(cmd, &luma_size, &chroma_size);
+	num_frags = (cmd->process_cfg >> 10) & 0xf;
+	num_frags = ((num_frags == 1) ? num_frags : num_frags * 2);
+	for (i = 0; i < num_frags; i += 2) {
+		if (adsp_pmem_fixup(module, (void **)(&cmd->frag_cfg_part[i]), luma_size) ||
+		    adsp_pmem_fixup(module, (void **)(&cmd->frag_cfg_part[i+1]), chroma_size))
+			return -1;
+	}
+
+	if (adsp_pmem_fixup(module, (void **)&cmd->op_buf_0_cfg_part1,
+			    cmd->op_buf_0_cfg_part2) ||
+	    adsp_pmem_fixup(module, (void **)&cmd->op_buf_1_cfg_part1,
+			    cmd->op_buf_1_cfg_part2))
+		return -1;
+	return 0;
+}
+
+static inline int verify_jpeg_cmd_dec_cfg(struct msm_adsp_module *module,
+					  void *cmd_data, size_t cmd_size)
+{
+	jpeg_cmd_dec_cfg *cmd = (jpeg_cmd_dec_cfg *)cmd_data;
+	uint32_t div;
+
+	if (cmd_size != sizeof(jpeg_cmd_dec_cfg)) {
+		printk(KERN_ERR "adsp: module %s: JPEG DEC CFG invalid cmd_size %d\n",
+			module->name, cmd_size);
+		return -1;
+	}
+
+	if (adsp_pmem_fixup(module, (void **)&cmd->ip_stream_buf_cfg_part1,
+			    cmd->ip_stream_buf_cfg_part2) ||
+	    adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_0_cfg_part1,
+			    cmd->op_stream_buf_0_cfg_part2) ||
+	    adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_1_cfg_part1,
+			    cmd->op_stream_buf_1_cfg_part2))
+		return -1;
+	dec_fmt = cmd->op_data_format &
+		JPEG_CMD_DEC_OP_DATA_FORMAT_M;
+	div = (dec_fmt == JPEG_CMD_DEC_OP_DATA_FORMAT_H2V2) ? 2 : 1;
+	if (adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_0_cfg_part3,
+			    cmd->op_stream_buf_0_cfg_part2 / div) ||
+	    adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_1_cfg_part3,
+			    cmd->op_stream_buf_1_cfg_part2 / div))
+		return -1;
+	return 0;
+}
+
+static int verify_jpeg_cfg_cmd(struct msm_adsp_module *module,
+			       void *cmd_data, size_t cmd_size)
+{
+	uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
+	switch(cmd_id) {
+	case JPEG_CMD_ENC_CFG:
+		return verify_jpeg_cmd_enc_cfg(module, cmd_data, cmd_size);
+	case JPEG_CMD_DEC_CFG:
+		return verify_jpeg_cmd_dec_cfg(module, cmd_data, cmd_size);
+	default:
+		if (cmd_id > 1) {
+			printk(KERN_ERR "adsp: module %s: invalid JPEG CFG cmd_id %d\n", module->name, cmd_id);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int verify_jpeg_action_cmd(struct msm_adsp_module *module,
+				  void *cmd_data, size_t cmd_size)
+{
+	uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
+	switch (cmd_id) {
+	case JPEG_CMD_ENC_OP_CONSUMED:
+	{
+		jpeg_cmd_enc_op_consumed *cmd =
+			(jpeg_cmd_enc_op_consumed *)cmd_data;
+
+		if (cmd_size != sizeof(jpeg_cmd_enc_op_consumed)) {
+			printk(KERN_ERR "adsp: module %s: JPEG_CMD_ENC_OP_CONSUMED invalid size %d\n",
+				module->name, cmd_size);
+			return -1;
+		}
+
+		if (adsp_pmem_fixup(module, (void **)&cmd->op_buf_addr,
+				    cmd->op_buf_size))
+			return -1;
+	}
+	break;
+	case JPEG_CMD_DEC_OP_CONSUMED:
+	{
+		uint32_t div;
+		jpeg_cmd_dec_op_consumed *cmd =
+			(jpeg_cmd_dec_op_consumed *)cmd_data;
+
+		if (cmd_size != sizeof(jpeg_cmd_enc_op_consumed)) {
+			printk(KERN_ERR "adsp: module %s: JPEG_CMD_DEC_OP_CONSUMED invalid size %d\n",
+				module->name, cmd_size);
+			return -1;
+		}
+
+		div = (dec_fmt == JPEG_CMD_DEC_OP_DATA_FORMAT_H2V2) ?  2 : 1;
+		if (adsp_pmem_fixup(module, (void **)&cmd->luma_op_buf_addr,
+				    cmd->luma_op_buf_size) ||
+		    adsp_pmem_fixup(module, (void **)&cmd->chroma_op_buf_addr,
+				    cmd->luma_op_buf_size / div))
+			return -1;
+	}
+	break;
+	default:
+		if (cmd_id > 7) {
+			printk(KERN_ERR "adsp: module %s: invalid cmd_id %d\n",
+				module->name, cmd_id);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int adsp_jpeg_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size)
+{
+	switch(queue_id) {
+	case QDSP_uPJpegCfgCmdQueue:
+		return verify_jpeg_cfg_cmd(module, cmd_data, cmd_size);
+	case QDSP_uPJpegActionCmdQueue:
+		return verify_jpeg_action_cmd(module, cmd_data, cmd_size);
+	default:
+		return -1;
+	}
+}
+
diff --git a/arch/arm/mach-msm/qdsp5/adsp_lpm_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_lpm_verify_cmd.c
new file mode 100644
index 0000000..1e23ef3
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_lpm_verify_cmd.c
@@ -0,0 +1,65 @@
+/* arch/arm/mach-msm/qdsp5/adsp_lpm_verify_cmd.c
+ *
+ * Verificion code for aDSP LPM packets from userspace.
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated
+ * 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 <mach/qdsp5/qdsp5lpmcmdi.h>
+#include "adsp.h"
+
+int adsp_lpm_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size)
+{
+	uint32_t cmd_id, col_height, input_row_incr, output_row_incr,
+		input_size, output_size;
+	uint32_t size_mask = 0x0fff;
+	lpm_cmd_start *cmd;
+
+	if (queue_id != QDSP_lpmCommandQueue) {
+		printk(KERN_ERR "adsp: module %s: wrong queue id %d\n",
+			module->name, queue_id);
+		return -1;
+	}
+
+	cmd = (lpm_cmd_start *)cmd_data;
+	cmd_id = cmd->cmd_id;
+
+	if (cmd_id == LPM_CMD_START) {
+		if (cmd_size != sizeof(lpm_cmd_start)) {
+			printk(KERN_ERR "adsp: module %s: wrong size %d, expect %d\n",
+				module->name, cmd_size, sizeof(lpm_cmd_start));
+			return -1;
+		}
+		col_height = cmd->ip_data_cfg_part1 & size_mask;
+		input_row_incr = cmd->ip_data_cfg_part2 & size_mask;
+		output_row_incr = cmd->op_data_cfg_part1 & size_mask;
+		input_size = col_height * input_row_incr;
+		output_size = col_height * output_row_incr;
+		if ((cmd->ip_data_cfg_part4 && adsp_pmem_fixup(module,
+				    (void **)(&cmd->ip_data_cfg_part4),
+				    input_size)) ||
+		   (cmd->op_data_cfg_part3 && adsp_pmem_fixup(module,
+				    (void **)(&cmd->op_data_cfg_part3),
+				    output_size)))
+			return -1;
+	} else if (cmd_id > 1) {
+		printk(KERN_ERR "adsp: module %s: invalid cmd_id %d\n",
+			module->name, cmd_id);
+		return -1;
+	}
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/qdsp5/adsp_vfe_patch_event.c b/arch/arm/mach-msm/qdsp5/adsp_vfe_patch_event.c
new file mode 100644
index 0000000..8f09ed2
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_vfe_patch_event.c
@@ -0,0 +1,54 @@
+/* arch/arm/mach-msm/qdsp5/adsp_vfe_patch_event.c
+ *
+ * Verification code for aDSP VFE packets from userspace.
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated
+ * 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 <mach/qdsp5/qdsp5vfemsg.h>
+#include "adsp.h"
+
+static int patch_op_event(struct msm_adsp_module *module,
+				struct adsp_event *event)
+{
+	vfe_msg_op1 *op = (vfe_msg_op1 *)event->data.msg16;
+	if (adsp_pmem_paddr_fixup(module, (void **)&op->op1_buf_y_addr) ||
+	    adsp_pmem_paddr_fixup(module, (void **)&op->op1_buf_cbcr_addr))
+		return -1;
+	return 0;
+}
+
+static int patch_af_wb_event(struct msm_adsp_module *module,
+				struct adsp_event *event)
+{
+	vfe_msg_stats_wb_exp *af = (vfe_msg_stats_wb_exp *)event->data.msg16;
+	return adsp_pmem_paddr_fixup(module, (void **)&af->wb_exp_stats_op_buf);
+}
+
+int adsp_vfe_patch_event(struct msm_adsp_module *module,
+			struct adsp_event *event)
+{
+	switch(event->msg_id) {
+	case VFE_MSG_OP1:
+	case VFE_MSG_OP2:
+		return patch_op_event(module, event);
+	case VFE_MSG_STATS_AF:
+	case VFE_MSG_STATS_WB_EXP:	
+		return patch_af_wb_event(module, event);
+	default:
+		break;
+	}
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_vfe_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_vfe_verify_cmd.c
new file mode 100644
index 0000000..d1f3fa8
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_vfe_verify_cmd.c
@@ -0,0 +1,239 @@
+/* arch/arm/mach-msm/qdsp5/adsp_vfe_verify_cmd.c
+ *
+ * Verification code for aDSP VFE packets from userspace.
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated
+ * 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 <mach/qdsp5/qdsp5vfecmdi.h>
+#include "adsp.h"
+
+static uint32_t size1_y, size2_y, size1_cbcr, size2_cbcr;
+static uint32_t af_size = 4228;
+static uint32_t awb_size = 8196;
+
+static inline int verify_cmd_op_ack(struct msm_adsp_module *module,
+				    void *cmd_data, size_t cmd_size)
+{
+	vfe_cmd_op1_ack *cmd = (vfe_cmd_op1_ack *)cmd_data;
+	void **addr_y = (void **)&cmd->op1_buf_y_addr;
+	void **addr_cbcr = (void **)(&cmd->op1_buf_cbcr_addr);
+
+	if (cmd_size != sizeof(vfe_cmd_op1_ack))
+		return -1;
+	if ((*addr_y && adsp_pmem_fixup(module, addr_y, size1_y)) ||
+	    (*addr_cbcr && adsp_pmem_fixup(module, addr_cbcr, size1_cbcr)))
+		return -1;
+	return 0;
+}
+
+static inline int verify_cmd_stats_autofocus_cfg(struct msm_adsp_module *module,
+						 void *cmd_data, size_t cmd_size)
+{
+	int i;
+	vfe_cmd_stats_autofocus_cfg *cmd =
+		(vfe_cmd_stats_autofocus_cfg *)cmd_data;
+
+	if (cmd_size != sizeof(vfe_cmd_stats_autofocus_cfg))
+		return -1;
+
+	for (i = 0; i < 3; i++) {
+		void **addr = (void **)(&cmd->af_stats_op_buf[i]);
+		if (*addr && adsp_pmem_fixup(module, addr, af_size))
+			return -1;
+	}
+	return 0;
+}
+
+static inline int verify_cmd_stats_wb_exp_cfg(struct msm_adsp_module *module,
+					      void *cmd_data, size_t cmd_size)
+{
+	vfe_cmd_stats_wb_exp_cfg *cmd =
+		(vfe_cmd_stats_wb_exp_cfg *)cmd_data;
+	int i;
+
+	if (cmd_size != sizeof(vfe_cmd_stats_wb_exp_cfg))
+		return -1;
+
+	for (i = 0; i < 3; i++) {
+		void **addr = (void **)(&cmd->wb_exp_stats_op_buf[i]);
+		if (*addr && adsp_pmem_fixup(module, addr, awb_size))
+			return -1;
+	}
+	return 0;
+}
+
+static inline int verify_cmd_stats_af_ack(struct msm_adsp_module *module,
+					  void *cmd_data, size_t cmd_size)
+{
+	vfe_cmd_stats_af_ack *cmd = (vfe_cmd_stats_af_ack *)cmd_data;
+	void **addr = (void **)&cmd->af_stats_op_buf;
+
+	if (cmd_size != sizeof(vfe_cmd_stats_af_ack))
+		return -1;
+
+	if (*addr && adsp_pmem_fixup(module, addr, af_size))
+		return -1;
+	return 0;
+}
+
+static inline int verify_cmd_stats_wb_exp_ack(struct msm_adsp_module *module,
+					      void *cmd_data, size_t cmd_size)
+{
+	vfe_cmd_stats_wb_exp_ack *cmd =
+		(vfe_cmd_stats_wb_exp_ack *)cmd_data;
+	void **addr = (void **)&cmd->wb_exp_stats_op_buf;
+
+	if (cmd_size != sizeof(vfe_cmd_stats_wb_exp_ack))
+		return -1;
+
+	if (*addr && adsp_pmem_fixup(module, addr, awb_size))
+		return -1;
+	return 0;
+}
+
+static int verify_vfe_command(struct msm_adsp_module *module,
+			      void *cmd_data, size_t cmd_size)
+{
+	uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
+	switch (cmd_id) {
+	case VFE_CMD_OP1_ACK:
+		return verify_cmd_op_ack(module, cmd_data, cmd_size);
+	case VFE_CMD_OP2_ACK:
+		return verify_cmd_op_ack(module, cmd_data, cmd_size);
+	case VFE_CMD_STATS_AUTOFOCUS_CFG:
+		return verify_cmd_stats_autofocus_cfg(module, cmd_data,
+						      cmd_size);
+	case VFE_CMD_STATS_WB_EXP_CFG:
+		return verify_cmd_stats_wb_exp_cfg(module, cmd_data, cmd_size);
+	case VFE_CMD_STATS_AF_ACK:
+		return verify_cmd_stats_af_ack(module, cmd_data, cmd_size);
+	case VFE_CMD_STATS_WB_EXP_ACK:
+		return verify_cmd_stats_wb_exp_ack(module, cmd_data, cmd_size);
+	default:
+		if (cmd_id > 29) {
+			printk(KERN_ERR "adsp: module %s: invalid VFE command id %d\n", module->name, cmd_id);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int verify_vfe_command_scale(struct msm_adsp_module *module,
+				    void *cmd_data, size_t cmd_size)
+{
+	uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
+	// FIXME: check the size
+	if (cmd_id > 1) {
+		printk(KERN_ERR "adsp: module %s: invalid VFE SCALE command id %d\n", module->name, cmd_id);
+		return -1;
+	}
+	return 0;
+}
+
+
+static uint32_t get_size(uint32_t hw)
+{
+	uint32_t height, width;
+	uint32_t height_mask = 0x3ffc;
+	uint32_t width_mask = 0x3ffc000;
+
+	height = (hw & height_mask) >> 2;
+	width = (hw & width_mask) >> 14 ;
+	return height * width;
+}
+
+static int verify_vfe_command_table(struct msm_adsp_module *module,
+				    void *cmd_data, size_t cmd_size)
+{
+	uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
+	int i;
+
+	switch (cmd_id) {
+	case VFE_CMD_AXI_IP_CFG:
+	{
+		vfe_cmd_axi_ip_cfg *cmd = (vfe_cmd_axi_ip_cfg *)cmd_data;
+		uint32_t size;
+		if (cmd_size != sizeof(vfe_cmd_axi_ip_cfg)) {
+			printk(KERN_ERR "adsp: module %s: invalid VFE TABLE (VFE_CMD_AXI_IP_CFG) command size %d\n",
+				module->name, cmd_size);
+			return -1;
+		}
+		size = get_size(cmd->ip_cfg_part2);
+
+		for (i = 0; i < 8; i++) {
+			void **addr = (void **)
+				&cmd->ip_buf_addr[i];
+			if (*addr && adsp_pmem_fixup(module, addr, size))
+				return -1;
+		}
+	}
+	case VFE_CMD_AXI_OP_CFG:
+	{
+		vfe_cmd_axi_op_cfg *cmd = (vfe_cmd_axi_op_cfg *)cmd_data;
+		void **addr1_y, **addr2_y, **addr1_cbcr, **addr2_cbcr;
+
+		if (cmd_size != sizeof(vfe_cmd_axi_op_cfg)) { 
+			printk(KERN_ERR "adsp: module %s: invalid VFE TABLE (VFE_CMD_AXI_OP_CFG) command size %d\n",
+				module->name, cmd_size);
+			return -1;
+		}
+		size1_y = get_size(cmd->op1_y_cfg_part2);
+		size1_cbcr = get_size(cmd->op1_cbcr_cfg_part2);
+		size2_y = get_size(cmd->op2_y_cfg_part2);
+		size2_cbcr = get_size(cmd->op2_cbcr_cfg_part2);
+		for (i = 0; i < 8; i++) {
+			addr1_y = (void **)(&cmd->op1_buf1_addr[2*i]);
+			addr1_cbcr = (void **)(&cmd->op1_buf1_addr[2*i+1]);
+			addr2_y = (void **)(&cmd->op2_buf1_addr[2*i]);
+			addr2_cbcr = (void **)(&cmd->op2_buf1_addr[2*i+1]);
+/*
+			printk("module %s: [%d] %p %p %p %p\n",
+				module->name, i,
+				*addr1_y, *addr1_cbcr, *addr2_y, *addr2_cbcr);
+*/
+			if ((*addr1_y && adsp_pmem_fixup(module, addr1_y, size1_y)) ||
+			    (*addr1_cbcr && adsp_pmem_fixup(module, addr1_cbcr, size1_cbcr)) ||
+			    (*addr2_y && adsp_pmem_fixup(module, addr2_y, size2_y)) ||
+			    (*addr2_cbcr && adsp_pmem_fixup(module, addr2_cbcr, size2_cbcr)))
+				return -1;
+		}
+	}
+	default:
+		if (cmd_id > 4) {
+			printk(KERN_ERR "adsp: module %s: invalid VFE TABLE command id %d\n",
+				module->name, cmd_id);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int adsp_vfe_verify_cmd(struct msm_adsp_module *module,
+			unsigned int queue_id, void *cmd_data,
+			size_t cmd_size)
+{
+	switch (queue_id) {
+	case QDSP_vfeCommandQueue:
+		return verify_vfe_command(module, cmd_data, cmd_size);
+	case QDSP_vfeCommandScaleQueue:
+		return verify_vfe_command_scale(module, cmd_data, cmd_size);
+	case QDSP_vfeCommandTableQueue:
+		return verify_vfe_command_table(module, cmd_data, cmd_size);
+	default:
+		printk(KERN_ERR "adsp: module %s: unknown queue id %d\n",
+			module->name, queue_id);
+		return -1;
+	}
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
new file mode 100644
index 0000000..fdad055
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
@@ -0,0 +1,163 @@
+/* arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
+ *
+ * Verificion code for aDSP VDEC packets from userspace.
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated
+ * 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/io.h>
+
+#define ADSP_DEBUG_MSGS 0
+#if ADSP_DEBUG_MSGS
+#define DLOG(fmt,args...) \
+	do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \
+	     ##args); } \
+	while (0)
+#else
+#define DLOG(x...) do {} while (0)
+#endif
+
+
+#include <mach/qdsp5/qdsp5vdeccmdi.h>
+#include "adsp.h"
+
+static inline void *high_low_short_to_ptr(unsigned short high,
+					  unsigned short low)
+{
+	return (void *)((((unsigned long)high) << 16) | ((unsigned long)low));
+}
+
+static inline void ptr_to_high_low_short(void *ptr, unsigned short *high,
+					 unsigned short *low)
+{
+	*high = (unsigned short)((((unsigned long)ptr) >> 16) & 0xffff);
+	*low = (unsigned short)((unsigned long)ptr & 0xffff);
+}
+
+static int pmem_fixup_high_low(unsigned short *high,
+				unsigned short *low,
+				unsigned short size_high,
+				unsigned short size_low,
+				struct msm_adsp_module *module,
+				unsigned long *addr, unsigned long *size)
+{
+	void *phys_addr;
+	unsigned long phys_size;
+	unsigned long kvaddr;
+
+	phys_addr = high_low_short_to_ptr(*high, *low);
+	phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low);
+	DLOG("virt %x %x\n", phys_addr, phys_size);
+	if (adsp_pmem_fixup_kvaddr(module, &phys_addr, &kvaddr, phys_size)) {
+		DLOG("ah%x al%x sh%x sl%x addr %x size %x\n",
+			*high, *low, size_high, size_low, phys_addr, phys_size);
+		return -1;
+	}
+	ptr_to_high_low_short(phys_addr, high, low);
+	DLOG("phys %x %x\n", phys_addr, phys_size);
+	if (addr)
+		*addr = kvaddr;
+	if (size)
+		*size = phys_size;
+	return 0;
+}
+
+static int verify_vdec_pkt_cmd(struct msm_adsp_module *module,
+			       void *cmd_data, size_t cmd_size)
+{
+	unsigned short cmd_id = ((unsigned short *)cmd_data)[0];
+	viddec_cmd_subframe_pkt *pkt;
+	unsigned long subframe_pkt_addr;
+	unsigned long subframe_pkt_size;
+	viddec_cmd_frame_header_packet *frame_header_pkt;
+	int i, num_addr, skip;
+	unsigned short *frame_buffer_high, *frame_buffer_low;
+	unsigned long frame_buffer_size;
+	unsigned short frame_buffer_size_high, frame_buffer_size_low;
+
+	DLOG("cmd_size %d cmd_id %d cmd_data %x\n", cmd_size, cmd_id, cmd_data);
+	if (cmd_id != VIDDEC_CMD_SUBFRAME_PKT) {
+		printk(KERN_INFO "adsp_video: unknown video packet %u\n",
+			cmd_id);
+		return 0;
+	}
+	if (cmd_size < sizeof(viddec_cmd_subframe_pkt))
+		return -1;
+
+	pkt = (viddec_cmd_subframe_pkt *)cmd_data;
+
+	if (pmem_fixup_high_low(&(pkt->subframe_packet_high),
+				&(pkt->subframe_packet_low),
+				pkt->subframe_packet_size_high,
+				pkt->subframe_packet_size_low,
+				module,
+				&subframe_pkt_addr,
+				&subframe_pkt_size))
+		return -1;
+
+	/* deref those ptrs and check if they are a frame header packet */
+	frame_header_pkt = (viddec_cmd_frame_header_packet *)subframe_pkt_addr;
+	
+	switch (frame_header_pkt->packet_id) {
+	case 0xB201: /* h.264 */
+		num_addr = skip = 8;
+		break;
+	case 0x4D01: /* mpeg-4 and h.263 */
+		num_addr = 3;
+		skip = 0;
+		break;
+	default:
+		return 0;
+	}
+
+	frame_buffer_high = &frame_header_pkt->frame_buffer_0_high;
+	frame_buffer_low = &frame_header_pkt->frame_buffer_0_low;
+	frame_buffer_size = (frame_header_pkt->x_dimension *
+			     frame_header_pkt->y_dimension * 3) / 2;
+	ptr_to_high_low_short((void *)frame_buffer_size,
+			      &frame_buffer_size_high,
+			      &frame_buffer_size_low);
+	for (i = 0; i < num_addr; i++) {
+		if (pmem_fixup_high_low(frame_buffer_high, frame_buffer_low,
+					frame_buffer_size_high,
+					frame_buffer_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		frame_buffer_high += 2;
+		frame_buffer_low += 2;
+	}
+	/* Patch the output buffer. */
+	frame_buffer_high += 2*skip;
+	frame_buffer_low += 2*skip;
+	if (pmem_fixup_high_low(frame_buffer_high, frame_buffer_low,
+				frame_buffer_size_high,
+				frame_buffer_size_low, module, NULL, NULL))
+		return -1;
+	return 0;
+}
+
+int adsp_video_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size)
+{
+	switch (queue_id) {
+	case QDSP_mpuVDecPktQueue:
+		DLOG("\n");
+		return verify_vdec_pkt_cmd(module, cmd_data, cmd_size);
+	default:
+		printk(KERN_INFO "unknown video queue %u\n", queue_id);
+		return 0;
+	}
+}
+
diff --git a/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c
new file mode 100644
index 0000000..ee37449
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c
@@ -0,0 +1,235 @@
+/* arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
+ *
+ * Verificion code for aDSP VENC packets from userspace.
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated
+ * 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/io.h>
+
+#define ADSP_DEBUG_MSGS 0
+#if ADSP_DEBUG_MSGS
+#define DLOG(fmt,args...) \
+	do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \
+	     ##args); } \
+	while (0)
+#else
+#define DLOG(x...) do {} while (0)
+#endif
+
+#include <mach/qdsp5/qdsp5venccmdi.h>
+#include "adsp.h"
+
+
+static unsigned short x_dimension, y_dimension;
+
+static inline void *high_low_short_to_ptr(unsigned short high,
+					  unsigned short low)
+{
+	return (void *)((((unsigned long)high) << 16) | ((unsigned long)low));
+}
+
+static inline void ptr_to_high_low_short(void *ptr, unsigned short *high,
+					 unsigned short *low)
+{
+	*high = (unsigned short)((((unsigned long)ptr) >> 16) & 0xffff);
+	*low = (unsigned short)((unsigned long)ptr & 0xffff);
+}
+
+static int pmem_fixup_high_low(unsigned short *high,
+				unsigned short *low,
+				unsigned short size_high,
+				unsigned short size_low,
+				struct msm_adsp_module *module,
+				unsigned long *addr, unsigned long *size)
+{
+	void *phys_addr;
+	unsigned long phys_size;
+	unsigned long kvaddr;
+
+	phys_addr = high_low_short_to_ptr(*high, *low);
+	phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low);
+	DLOG("virt %x %x\n", phys_addr, phys_size);
+	if (adsp_pmem_fixup_kvaddr(module, &phys_addr, &kvaddr, phys_size)) {
+		DLOG("ah%x al%x sh%x sl%x addr %x size %x\n",
+			*high, *low, size_high, size_low, phys_addr, phys_size);
+		return -1;
+	}
+	ptr_to_high_low_short(phys_addr, high, low);
+	DLOG("phys %x %x\n", phys_addr, phys_size);
+	if (addr)
+		*addr = kvaddr;
+	if (size)
+		*size = phys_size;
+	return 0;
+}
+
+static int verify_venc_cmd(struct msm_adsp_module *module,
+			       void *cmd_data, size_t cmd_size)
+{
+	unsigned short cmd_id = ((unsigned short *)cmd_data)[0];
+	unsigned long frame_buf_size, luma_buf_size, chroma_buf_size;
+	unsigned short frame_buf_size_high, frame_buf_size_low;
+	unsigned short luma_buf_size_high, luma_buf_size_low;
+	unsigned short chroma_buf_size_high, chroma_buf_size_low;
+	videnc_cmd_cfg *config_cmd;
+	videnc_cmd_frame_start *frame_cmd;
+	videnc_cmd_dis *dis_cmd;
+
+	DLOG("cmd_size %d cmd_id %d cmd_data %x\n", cmd_size, cmd_id, cmd_data);
+	switch (cmd_id) {
+	case VIDENC_CMD_ACTIVE:
+		if (cmd_size < sizeof(videnc_cmd_active))
+			return -1;
+		break;
+	case VIDENC_CMD_IDLE:
+		if (cmd_size < sizeof(videnc_cmd_idle))
+			return -1;
+		x_dimension = y_dimension = 0;
+		break;
+	case VIDENC_CMD_STATUS_QUERY:
+		if (cmd_size < sizeof(videnc_cmd_status_query))
+			return -1;
+		break;
+	case VIDENC_CMD_RC_CFG:
+		if (cmd_size < sizeof(videnc_cmd_rc_cfg))
+			return -1;
+		break;
+	case VIDENC_CMD_INTRA_REFRESH:
+		if (cmd_size < sizeof(videnc_cmd_intra_refresh))
+			return -1;
+		break;
+	case VIDENC_CMD_DIGITAL_ZOOM:
+		if (cmd_size < sizeof(videnc_cmd_digital_zoom))
+			return -1;
+		break;
+	case VIDENC_CMD_DIS_CFG:
+		if (cmd_size < sizeof(videnc_cmd_dis_cfg))
+			return -1;
+		break;
+	case VIDENC_CMD_CFG:
+		if (cmd_size < sizeof(videnc_cmd_cfg))
+			return -1;
+		config_cmd = (videnc_cmd_cfg *)cmd_data;
+		x_dimension = ((config_cmd->venc_frame_dim) & 0xFF00)>>8;
+		x_dimension = x_dimension*16;
+		y_dimension = (config_cmd->venc_frame_dim) & 0xFF;
+		y_dimension = y_dimension * 16;
+		break;
+	case VIDENC_CMD_FRAME_START:
+		if (cmd_size < sizeof(videnc_cmd_frame_start))
+			return -1;
+		frame_cmd = (videnc_cmd_frame_start *)cmd_data;
+		luma_buf_size = x_dimension * y_dimension;
+		chroma_buf_size = luma_buf_size>>1;
+		frame_buf_size = luma_buf_size + chroma_buf_size;
+		ptr_to_high_low_short((void *)luma_buf_size,
+			      &luma_buf_size_high,
+			      &luma_buf_size_low);
+		ptr_to_high_low_short((void *)chroma_buf_size,
+			      &chroma_buf_size_high,
+			      &chroma_buf_size_low);
+		ptr_to_high_low_short((void *)frame_buf_size,
+			      &frame_buf_size_high,
+			      &frame_buf_size_low);
+		/* Address of raw Y data. */
+		if (pmem_fixup_high_low(&frame_cmd->input_luma_addr_high,
+					&frame_cmd->input_luma_addr_low,
+					luma_buf_size_high,
+					luma_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		/* Address of raw CbCr data */
+		if (pmem_fixup_high_low(&frame_cmd->input_chroma_addr_high,
+					&frame_cmd->input_chroma_addr_low,
+					chroma_buf_size_high,
+					chroma_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		/* Reference VOP */
+		if (pmem_fixup_high_low(&frame_cmd->ref_vop_buf_ptr_high,
+					&frame_cmd->ref_vop_buf_ptr_low,
+					frame_buf_size_high,
+					frame_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		/* Encoded Packet Address */
+		if (pmem_fixup_high_low(&frame_cmd->enc_pkt_buf_ptr_high,
+					&frame_cmd->enc_pkt_buf_ptr_low,
+					frame_cmd->enc_pkt_buf_size_high,
+					frame_cmd->enc_pkt_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		/* Unfiltered VOP Buffer Address */
+		if (pmem_fixup_high_low(
+				&frame_cmd->unfilt_recon_vop_buf_ptr_high,
+				&frame_cmd->unfilt_recon_vop_buf_ptr_low,
+				frame_buf_size_high,
+				frame_buf_size_low,
+				module,
+				NULL, NULL))
+			return -1;
+		/* Filtered VOP Buffer Address */
+		if (pmem_fixup_high_low(&frame_cmd->filt_recon_vop_buf_ptr_high,
+					&frame_cmd->filt_recon_vop_buf_ptr_low,
+					frame_buf_size_high,
+					frame_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		break;
+	case VIDENC_CMD_DIS:
+		if (cmd_size < sizeof(videnc_cmd_dis))
+			return -1;
+		dis_cmd = (videnc_cmd_dis *)cmd_data;
+		luma_buf_size = x_dimension * y_dimension;
+		ptr_to_high_low_short((void *)luma_buf_size,
+			      &luma_buf_size_high,
+			      &luma_buf_size_low);
+		/* Prev VFE Luma Output Address */
+		if (pmem_fixup_high_low(&dis_cmd->vfe_out_prev_luma_addr_high,
+					&dis_cmd->vfe_out_prev_luma_addr_low,
+					luma_buf_size_high,
+					luma_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		break;
+	default:
+		printk(KERN_INFO "adsp_video:unknown encoder video command %u\n",
+			cmd_id);
+		return 0;
+	}
+
+	return 0;
+}
+
+
+int adsp_videoenc_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size)
+{
+	switch (queue_id) {
+	case QDSP_mpuVEncCmdQueue:
+		DLOG("\n");
+		return verify_venc_cmd(module, cmd_data, cmd_size);
+	default:
+		printk(KERN_INFO "unknown video queue %u\n", queue_id);
+		return 0;
+	}
+}
+
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
new file mode 100644
index 0000000..4232b9f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -0,0 +1,1051 @@
+/* arch/arm/mach-msm/qdsp5/audio_aac.c
+ *
+ * aac audio decoder device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009 QUALCOMM USA, 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/delay.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audmgr.h"
+
+#include <mach/msm_adsp.h>
+#include <mach/msm_audio_aac.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+
+/* for queue ids - should be relative to module number*/
+#include "adsp.h"
+
+#ifdef DEBUG
+#define dprintk(format, arg...) \
+printk(KERN_DEBUG format, ## arg)
+#else
+#define dprintk(format, arg...) do {} while (0)
+#endif
+
+#define BUFSZ 32768
+#define DMASZ (BUFSZ * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_AAC 5
+
+#define PCM_BUFSZ_MIN 9600	/* Hold one stereo AAC frame */
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	dma_addr_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	struct msm_audio_aac_config aac_config;
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped;	/* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	unsigned volume;
+
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	dprintk("audio_enable()\n");
+
+	if (audio->enabled)
+		return 0;
+
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+	cfg.codec = RPC_AUD_DEF_CODEC_AAC;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		pr_err("audio: msm_adsp_enable(audplay) failed\n");
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		pr_err("audio: audpp_enable() failed\n");
+    msm_adsp_disable(audio->audplay);
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	dprintk("audio_disable()\n");
+	if (audio->enabled) {
+		audio->enabled = 0;
+		auddec_dsp_config(audio, 0);
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_update_pcm_buf_entry(struct audio *audio, uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			dprintk("audio_update_pcm_buf_entry: in[%d] ready\n",
+				audio->fill_next);
+			audio->in[audio->fill_next].used =
+				payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			pr_err
+			    ("audio_update_pcm_buf_entry: expected=%x ret=%x\n"
+			     , audio->in[audio->fill_next].addr,
+			     payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audplay_buffer_refresh(audio);
+	} else {
+		dprintk("audio_update_pcm_buf_entry: read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	dprintk("audplay_dsp_event: msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audplay_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio_update_pcm_buf_entry(audio, msg);
+		break;
+
+	default:
+		pr_err("unexpected message from decoder \n");
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP:
+				dprintk("decoder status: sleep \n");
+				break;
+
+			case AUDPP_DEC_STATUS_INIT:
+				dprintk("decoder status: init \n");
+				audpp_cmd_cfg_routing_mode(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				dprintk("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				dprintk("decoder status: play \n");
+				if (audio->pcm_feedback) {
+					audplay_config_hostpcm(audio);
+					audplay_buffer_refresh(audio);
+				}
+				break;
+			default:
+				pr_err("unknown decoder status \n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			dprintk("audio_dsp_event: CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_set_volume_and_pan(audio->dec_id, audio->volume,
+						 0);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			dprintk("audio_dsp_event: CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			pr_err("audio_dsp_event: CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		dprintk("audio_dsp_event: ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		dprintk("%s: FLUSH_ACK\n", __func__);
+		audio->wflush = 0;
+		audio->rflush = 0;
+		if (audio->pcm_feedback)
+			audplay_buffer_refresh(audio);
+		break;
+
+	default:
+		pr_err("audio_dsp_event: UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_aac = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, QDSP_uPAudPlay0BitStreamCtrlQueue, \
+		       cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	audpp_cmd_cfg_dec_type cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+		    AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AAC;
+	else
+		cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	audpp_cmd_cfg_adec_params_aac cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_AAC_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+	cmd.format = audio->aac_config.format;
+	cmd.audio_object = audio->aac_config.audio_object;
+	cmd.ep_config = audio->aac_config.ep_config;
+	cmd.aac_section_data_resilience_flag =
+		audio->aac_config.aac_section_data_resilience_flag;
+	cmd.aac_scalefactor_data_resilience_flag =
+		audio->aac_config.aac_scalefactor_data_resilience_flag;
+	cmd.aac_spectral_data_resilience_flag =
+		audio->aac_config.aac_spectral_data_resilience_flag;
+	cmd.sbr_on_flag = audio->aac_config.sbr_on_flag;
+	cmd.sbr_ps_on_flag = audio->aac_config.sbr_ps_on_flag;
+	cmd.channel_configuration = audio->aac_config.channel_configuration;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	dprintk("audpp_cmd_cfg_routing_mode()\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	audplay_cmd_bitstream_data_avail cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+	cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size -
+		(audio->in[audio->fill_next].size % 1024); /* AAC frame size */
+	refresh_cmd.buf_read_count = 0;
+	dprintk("audplay_buffer_fresh: buf0_addr=%x buf0_len=%d\n",
+		refresh_cmd.buf0_address, refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	dprintk("audplay_config_hostpcm()\n");
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			dprintk("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+/*                      printk("frame %d busy\n", audio->out_tail); */
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static int audaac_validate_usr_config(struct msm_audio_aac_config *config)
+{
+	int ret_val = -1;
+
+	if (config->format != AUDIO_AAC_FORMAT_ADTS &&
+		config->format != AUDIO_AAC_FORMAT_RAW &&
+		config->format != AUDIO_AAC_FORMAT_PSUEDO_RAW &&
+		config->format != AUDIO_AAC_FORMAT_LOAS)
+		goto done;
+
+	if (config->audio_object != AUDIO_AAC_OBJECT_LC &&
+		config->audio_object != AUDIO_AAC_OBJECT_LTP &&
+		config->audio_object != AUDIO_AAC_OBJECT_ERLC)
+		goto done;
+
+	if (config->audio_object == AUDIO_AAC_OBJECT_ERLC) {
+		if (config->ep_config > 3)
+			goto done;
+		if (config->aac_scalefactor_data_resilience_flag !=
+			AUDIO_AAC_SCA_DATA_RES_OFF &&
+			config->aac_scalefactor_data_resilience_flag !=
+			AUDIO_AAC_SCA_DATA_RES_ON)
+			goto done;
+		if (config->aac_section_data_resilience_flag !=
+			AUDIO_AAC_SEC_DATA_RES_OFF &&
+			config->aac_section_data_resilience_flag !=
+			AUDIO_AAC_SEC_DATA_RES_ON)
+			goto done;
+		if (config->aac_spectral_data_resilience_flag !=
+			AUDIO_AAC_SPEC_DATA_RES_OFF &&
+			config->aac_spectral_data_resilience_flag !=
+			AUDIO_AAC_SPEC_DATA_RES_ON)
+			goto done;
+	} else {
+		config->aac_section_data_resilience_flag =
+			AUDIO_AAC_SEC_DATA_RES_OFF;
+		config->aac_scalefactor_data_resilience_flag =
+			AUDIO_AAC_SCA_DATA_RES_OFF;
+		config->aac_spectral_data_resilience_flag =
+			AUDIO_AAC_SPEC_DATA_RES_OFF;
+	}
+
+	if (config->sbr_on_flag != AUDIO_AAC_SBR_ON_FLAG_OFF &&
+		config->sbr_on_flag != AUDIO_AAC_SBR_ON_FLAG_ON)
+		goto done;
+
+	if (config->sbr_ps_on_flag != AUDIO_AAC_SBR_PS_ON_FLAG_OFF &&
+		config->sbr_ps_on_flag != AUDIO_AAC_SBR_PS_ON_FLAG_ON)
+		goto done;
+
+	if (config->dual_mono_mode > AUDIO_AAC_DUAL_MONO_PL_SR)
+		goto done;
+
+	if (config->channel_configuration > 2)
+		goto done;
+
+	ret_val = 0;
+ done:
+	return ret_val;
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audio_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audio_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	dprintk("audio_ioctl() cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == AUDIO_SET_VOLUME) {
+		unsigned long flags;
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->volume = arg;
+		if (audio->running)
+			audpp_set_volume_and_pan(audio->dec_id, arg, 0);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+	}
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		rc = audio_enable(audio);
+		break;
+	case AUDIO_STOP:
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		dprintk("%s: AUDIO_FLUSH\n", __func__);
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running)
+			audpp_flush(audio->dec_id);
+		else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+
+			if (config.channel_count == 1) {
+				config.channel_count =
+				    AUDPP_CMD_PCM_INTF_MONO_V;
+			} else if (config.channel_count == 2) {
+				config.channel_count =
+				    AUDPP_CMD_PCM_INTF_STEREO_V;
+			} else {
+				rc = -EINVAL;
+				break;
+			}
+
+			audio->out_sample_rate = config.sample_rate;
+			audio->out_channel_mode = config.channel_count;
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = audio->out_sample_rate;
+			if (audio->out_channel_mode ==
+			    AUDPP_CMD_PCM_INTF_MONO_V) {
+				config.channel_count = 1;
+			} else {
+				config.channel_count = 2;
+			}
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_AAC_CONFIG:{
+			if (copy_to_user((void *)arg, &audio->aac_config,
+				sizeof(audio->aac_config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_AAC_CONFIG:{
+			struct msm_audio_aac_config usr_config;
+
+			if (copy_from_user
+				(&usr_config, (void *)arg,
+					sizeof(usr_config))) {
+				rc = -EFAULT;
+				break;
+			}
+
+			if (audaac_validate_usr_config(&usr_config) == 0) {
+				audio->aac_config = usr_config;
+				rc = 0;
+			} else
+				rc = -EINVAL;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = 0;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				dprintk("ioctl: allocate PCM buffer %d\n",
+					config.buffer_count *
+					config.buffer_size);
+				audio->read_data =
+				    dma_alloc_coherent(NULL,
+						       config.buffer_size *
+						       config.buffer_count,
+						       &audio->read_phys,
+						       GFP_KERNEL);
+				if (!audio->read_data) {
+					pr_err("audio_aac: buf alloc fail\n");
+					rc = -1;
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->pcm_feedback = 1;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		dprintk("%s: AUDIO_PAUSE %ld\n", __func__, arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	dprintk("audio_read() %d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+					      (audio->in[audio->read_next].
+						used > 0) || (audio->stopped)
+						|| (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver
+			   does not know frame size, read count must be greater
+			   or equal to size of PCM samples */
+			dprintk("audio_read: no partial frame done reading\n");
+			break;
+		} else {
+			dprintk("audio_read: read from in[%d]\n",
+				audio->read_next);
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				pr_err("audio_read: invalid addr %x \n",
+				       (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			if (audio->in[audio->read_next].used == 0)
+				break; /* No data ready at this moment
+					* Exit while loop to prevent
+					* output thread sleep too long
+					*/
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		dprintk("audio_read: kick start pcm feedback again\n");
+		audplay_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	dprintk("audio_read: read %d bytes\n", rc);
+	return rc;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0;
+	unsigned dsize;
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->reserved) {
+			dprintk("%s: append reserved byte %x\n",
+				__func__, audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > (frame->size - 1)) ?
+				frame->size - 1 : count;
+			cpy_ptr++;
+			dsize = 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > frame->size) ? frame->size : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			dprintk("%s: odd length buf reserve last byte %x\n",
+				__func__, audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audplay_send_data(audio, 0);
+		}
+	}
+	mutex_unlock(&audio->write_lock);
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	dprintk("audio_release()\n");
+
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	audio_flush(audio);
+	audio_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audio->audplay = NULL;
+	audio->opened = 0;
+	audio->reserved = 0;
+	dma_free_coherent(NULL, DMASZ, audio->data, audio->phys);
+	audio->data = NULL;
+	if (audio->read_data != NULL) {
+		dma_free_coherent(NULL,
+				  audio->in[0].size * audio->pcm_buf_count,
+				  audio->read_data, audio->read_phys);
+		audio->read_data = NULL;
+	}
+	audio->pcm_feedback = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+struct audio the_aac_audio;
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &the_aac_audio;
+	int rc;
+
+	mutex_lock(&audio->lock);
+
+	if (audio->opened) {
+		pr_err("audio: busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (!audio->data) {
+		audio->data = dma_alloc_coherent(NULL, DMASZ,
+						 &audio->phys, GFP_KERNEL);
+		if (!audio->data) {
+			pr_err("audio: could not allocate DMA buffers\n");
+			rc = -ENOMEM;
+			goto done;
+		}
+	}
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto done;
+
+	rc = msm_adsp_get("AUDPLAY0TASK", &audio->audplay,
+			  &audplay_adsp_ops_aac, audio);
+	if (rc) {
+		pr_err("audio: failed to get audplay0 dsp module\n");
+		goto done;
+	}
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->aac_config.format = AUDIO_AAC_FORMAT_ADTS;
+	audio->aac_config.audio_object = AUDIO_AAC_OBJECT_LC;
+	audio->aac_config.ep_config = 0;
+	audio->aac_config.aac_section_data_resilience_flag =
+		AUDIO_AAC_SEC_DATA_RES_OFF;
+	audio->aac_config.aac_scalefactor_data_resilience_flag =
+		AUDIO_AAC_SCA_DATA_RES_OFF;
+	audio->aac_config.aac_spectral_data_resilience_flag =
+		AUDIO_AAC_SPEC_DATA_RES_OFF;
+	audio->aac_config.sbr_on_flag = AUDIO_AAC_SBR_ON_FLAG_ON;
+	audio->aac_config.sbr_ps_on_flag = AUDIO_AAC_SBR_PS_ON_FLAG_ON;
+	audio->aac_config.dual_mono_mode = AUDIO_AAC_DUAL_MONO_PL_SR;
+	audio->aac_config.channel_configuration = 2;
+	audio->dec_id = 0;
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->volume = 0x2000;	/* Q13 1.0 */
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static struct file_operations audio_aac_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_release,
+	.read = audio_read,
+	.write = audio_write,
+	.unlocked_ioctl = audio_ioctl,
+};
+
+struct miscdevice audio_aac_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_aac",
+	.fops = &audio_aac_fops,
+};
+
+static int __init audio_init(void)
+{
+	mutex_init(&the_aac_audio.lock);
+	mutex_init(&the_aac_audio.write_lock);
+	mutex_init(&the_aac_audio.read_lock);
+	spin_lock_init(&the_aac_audio.dsp_lock);
+	init_waitqueue_head(&the_aac_audio.write_wait);
+	init_waitqueue_head(&the_aac_audio.read_wait);
+	the_aac_audio.read_data = NULL;
+	return misc_register(&audio_aac_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
new file mode 100644
index 0000000..63fe2d0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -0,0 +1,872 @@
+/* linux/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+ *
+ * amrnb audio decoder device
+ *
+ * Copyright (c) 2008 QUALCOMM USA, INC.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/delay.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <linux/msm_audio.h>
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+
+/* for queue ids - should be relative to module number*/
+#include "adsp.h"
+
+#define DEBUG
+#ifdef DEBUG
+#define dprintk(format, arg...) \
+printk(KERN_DEBUG format, ## arg)
+#else
+#define dprintk(format, arg...) do {} while (0)
+#endif
+
+#define BUFSZ 1024 /* Hold minimum 700ms voice data */
+#define DMASZ (BUFSZ * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_AMRNB 10
+
+#define PCM_BUFSZ_MIN 1600 /* 100ms worth of data */
+#define AMRNB_DECODED_FRSZ 320 /* AMR-NB 20ms 8KHz mono PCM size */
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	dma_addr_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	uint8_t opened:1;
+	uint8_t enabled:1;
+	uint8_t running:1;
+	uint8_t stopped:1;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback:1;
+	uint8_t buf_refresh:1;
+
+	unsigned volume;
+
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+};
+
+struct audpp_cmd_cfg_adec_params_amrnb {
+   audpp_cmd_cfg_adec_params_common     common;
+   unsigned short                       stereo_cfg;
+} __attribute__((packed)) ;
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audamrnb_send_data(struct audio *audio, unsigned needed);
+static void audamrnb_config_hostpcm(struct audio *audio);
+static void audamrnb_buffer_refresh(struct audio *audio);
+static void audamrnb_dsp_event(void *private, unsigned id, uint16_t *msg);
+
+/* must be called with audio->lock held */
+static int audamrnb_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	dprintk("audamrnb_enable()\n");
+
+	if (audio->enabled)
+		return 0;
+
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+	cfg.codec = RPC_AUD_DEF_CODEC_AMR_NB;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		pr_err("audio: msm_adsp_enable(audplay) failed\n");
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audamrnb_dsp_event, audio)) {
+		pr_err("audio: audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audamrnb_disable(struct audio *audio)
+{
+	dprintk("audamrnb_disable()\n");
+	if (audio->enabled) {
+		audio->enabled = 0;
+		auddec_dsp_config(audio, 0);
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audamrnb_update_pcm_buf_entry(struct audio *audio,
+		uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			dprintk("audamrnb_update_pcm_buf_entry: in[%d] ready\n",
+				audio->fill_next);
+			audio->in[audio->fill_next].used =
+			    payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			pr_err
+			  ("audamrnb_update_pcm_buf_entry: expected=%x ret=%x\n"
+			   , audio->in[audio->fill_next].addr,
+			   payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audamrnb_buffer_refresh(audio);
+	} else {
+		dprintk("audamrnb_update_pcm_buf_entry: read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->read_wait);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	dprintk("audplay_dsp_event: msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audamrnb_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audamrnb_update_pcm_buf_entry(audio, msg);
+		break;
+
+	default:
+		pr_err("unexpected message from decoder \n");
+	}
+}
+
+static void audamrnb_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP:
+				dprintk("decoder status: sleep \n");
+				break;
+
+			case AUDPP_DEC_STATUS_INIT:
+				dprintk("decoder status: init \n");
+				audpp_cmd_cfg_routing_mode(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				dprintk("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				dprintk("decoder status: play \n");
+				if (audio->pcm_feedback) {
+					audamrnb_config_hostpcm(audio);
+					audamrnb_buffer_refresh(audio);
+				}
+				break;
+			default:
+				pr_err("unknown decoder status \n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			dprintk("audamrnb_dsp_event: CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_set_volume_and_pan(audio->dec_id, audio->volume,
+						 0);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			dprintk("audamrnb_dsp_event: CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			pr_err("audamrnb_dsp_event: CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		dprintk("audamrnb_dsp_event: ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	default:
+		pr_err("audamrnb_dsp_event: UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_amrnb = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, QDSP_uPAudPlay0BitStreamCtrlQueue, \
+		       cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	audpp_cmd_cfg_dec_type cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+		    AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AMRNB;
+	else
+		cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_amrnb cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = 8000;
+	cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	dprintk("audpp_cmd_cfg_routing_mode()\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	audplay_cmd_bitstream_data_avail cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+	cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audamrnb_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size -
+	  (audio->in[audio->fill_next].size % AMRNB_DECODED_FRSZ);
+	refresh_cmd.buf_read_count = 0;
+	dprintk("audplay_buffer_fresh: buf0_addr=%x buf0_len=%d\n",
+		refresh_cmd.buf0_address, refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audamrnb_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	dprintk("audamrnb_config_hostpcm()\n");
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audamrnb_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+/*                      printk("frame %d busy\n", audio->out_tail); */
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audamrnb_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->stopped = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audamrnb_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static long audamrnb_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	dprintk("audamrnb_ioctl() cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == AUDIO_SET_VOLUME) {
+		unsigned long flags;
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->volume = arg;
+		if (audio->running)
+			audpp_set_volume_and_pan(audio->dec_id, arg, 0);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+    return 0;
+	}
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		rc = audamrnb_enable(audio);
+		break;
+	case AUDIO_STOP:
+		rc = audamrnb_disable(audio);
+		audio->stopped = 1;
+		break;
+	case AUDIO_FLUSH:
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the write_lock.
+			 * While audio->stopped write threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->write_wait);
+			mutex_lock(&audio->write_lock);
+			audamrnb_flush(audio);
+			mutex_unlock(&audio->write_lock);
+			wake_up(&audio->read_wait);
+			mutex_lock(&audio->read_lock);
+			audamrnb_flush_pcm_buf(audio);
+			mutex_unlock(&audio->read_lock);
+			break;
+		}
+
+  case AUDIO_SET_CONFIG:{
+      dprintk("AUDIO_SET_CONFIG not applicable \n");
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = 8000;
+			config.channel_count = 1;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = 0;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+		struct msm_audio_pcm_config config;
+		if (copy_from_user
+		    (&config, (void *)arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+		    (config.buffer_count == 1))
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+
+		if (config.buffer_size < PCM_BUFSZ_MIN)
+			config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+		if ((config.pcm_feedback) && (!audio->read_data)) {
+			dprintk("audamrnb_ioctl: allocate PCM buf %d\n",
+					config.buffer_count *
+					config.buffer_size);
+			audio->read_data =
+				dma_alloc_coherent(NULL,
+						       config.buffer_size *
+						       config.buffer_count,
+						       &audio->read_phys,
+						       GFP_KERNEL);
+			if (!audio->read_data) {
+				pr_err("audamrnb_ioctl: no mem for pcm buf\n");
+				rc = -1;
+			} else {
+				uint8_t index;
+				uint32_t offset = 0;
+				audio->pcm_feedback = 1;
+				audio->buf_refresh = 0;
+				audio->pcm_buf_count =
+					config.buffer_count;
+				audio->read_next = 0;
+				audio->fill_next = 0;
+
+				for (index = 0;
+				index < config.buffer_count; index++) {
+					audio->in[index].data =
+						audio->read_data + offset;
+					audio->in[index].addr =
+					    audio->read_phys + offset;
+					audio->in[index].size =
+					    config.buffer_size;
+					audio->in[index].used = 0;
+					offset += config.buffer_size;
+				}
+				rc = 0;
+			}
+		} else {
+			rc = 0;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audamrnb_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	dprintk("audamrnb_read() %d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+					      (audio->in[audio->read_next].
+					       used > 0) || (audio->stopped));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not know frame size, read count must be greater or
+			 * equal to size of PCM samples
+			 */
+			dprintk("audamrnb_read:read stop - partial frame\n");
+			break;
+		} else {
+			dprintk("audamrnb_read: read from in[%d]\n",
+				audio->read_next);
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				pr_err("audamrnb_read: invalid addr %x \n",
+				       (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+		}
+	}
+
+	if (audio->buf_refresh) {
+		audio->buf_refresh = 0;
+		dprintk("audamrnb_read: kick start pcm feedback again\n");
+		audamrnb_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	dprintk("audamrnb_read: read %d bytes\n", rc);
+	return rc;
+}
+
+static ssize_t audamrnb_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int rc = 0;
+
+	if (count & 1)
+		return -EINVAL;
+	dprintk("audamrnb_write() \n");
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped));
+		dprintk("audamrnb_write() buffer available\n");
+		if (rc < 0)
+			break;
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		xfer = (count > frame->size) ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		frame->used = xfer;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		audamrnb_send_data(audio, 0);
+
+	}
+	mutex_unlock(&audio->write_lock);
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+
+static int audamrnb_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	dprintk("audamrnb_release()\n");
+
+	mutex_lock(&audio->lock);
+	audamrnb_disable(audio);
+	audamrnb_flush(audio);
+	audamrnb_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audio->audplay = NULL;
+	audio->opened = 0;
+	dma_free_coherent(NULL, DMASZ, audio->data, audio->phys);
+	audio->data = NULL;
+	if (audio->read_data != NULL) {
+		dma_free_coherent(NULL,
+				  audio->in[0].size * audio->pcm_buf_count,
+				  audio->read_data, audio->read_phys);
+		audio->read_data = NULL;
+	}
+	audio->pcm_feedback = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static struct audio the_amrnb_audio;
+
+static int audamrnb_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &the_amrnb_audio;
+	int rc;
+
+	mutex_lock(&audio->lock);
+
+	if (audio->opened) {
+		pr_err("audio: busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (!audio->data) {
+		audio->data = dma_alloc_coherent(NULL, DMASZ,
+						 &audio->phys, GFP_KERNEL);
+		if (!audio->data) {
+			pr_err("audio: could not allocate DMA buffers\n");
+			rc = -ENOMEM;
+			goto done;
+		}
+	}
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto done;
+
+	rc = msm_adsp_get("AUDPLAY0TASK", &audio->audplay,
+		&audplay_adsp_ops_amrnb, audio);
+	if (rc) {
+		pr_err("audio: failed to get audplay0 dsp module\n");
+		audmgr_disable(&audio->audmgr);
+		dma_free_coherent(NULL, DMASZ, audio->data, audio->phys);
+		audio->data = NULL;
+		goto done;
+	}
+
+	audio->dec_id = 0;
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->volume = 0x2000;	/* Q13 1.0 */
+
+	audamrnb_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static struct file_operations audio_amrnb_fops = {
+	.owner = THIS_MODULE,
+	.open = audamrnb_open,
+	.release = audamrnb_release,
+	.read = audamrnb_read,
+	.write = audamrnb_write,
+	.unlocked_ioctl = audamrnb_ioctl,
+};
+
+struct miscdevice audio_amrnb_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_amrnb",
+	.fops = &audio_amrnb_fops,
+};
+
+static int __init audamrnb_init(void)
+{
+	mutex_init(&the_amrnb_audio.lock);
+	mutex_init(&the_amrnb_audio.write_lock);
+	mutex_init(&the_amrnb_audio.read_lock);
+	spin_lock_init(&the_amrnb_audio.dsp_lock);
+	init_waitqueue_head(&the_amrnb_audio.write_wait);
+	init_waitqueue_head(&the_amrnb_audio.read_wait);
+	the_amrnb_audio.read_data = NULL;
+	return misc_register(&audio_amrnb_misc);
+}
+
+static void __exit audamrnb_exit(void)
+{
+	misc_deregister(&audio_amrnb_misc);
+}
+
+module_init(audamrnb_init);
+module_exit(audamrnb_exit);
+
+MODULE_DESCRIPTION("MSM AMR-NB driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("QUALCOMM Inc");
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
new file mode 100644
index 0000000..8ee8d53
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -0,0 +1,844 @@
+/* arch/arm/mach-msm/audio_evrc.c
+ *
+ * Copyright (c) 2008 QUALCOMM USA, INC.
+ *
+ * This code also borrows from audio_aac.c, which is
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <linux/msm_audio.h>
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+
+#include "adsp.h"
+
+#ifdef DEBUG
+#define dprintk(format, arg...) \
+	printk(KERN_DEBUG format, ## arg)
+#else
+#define dprintk(format, arg...) do {} while (0)
+#endif
+
+/* Hold 30 packets of 24 bytes each*/
+#define BUFSZ 			720
+#define DMASZ 			(BUFSZ * 2)
+
+#define AUDDEC_DEC_EVRC 	12
+
+#define PCM_BUFSZ_MIN 		1600	/* 100ms worth of data */
+#define PCM_BUF_MAX_COUNT 	5
+/* DSP only accepts 5 buffers at most
+ * but support 2 buffers currently
+ */
+#define EVRC_DECODED_FRSZ 	320	/* EVRC 20ms 8KHz mono PCM size */
+
+#define ROUTING_MODE_FTRT 	1
+#define ROUTING_MODE_RT 	2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	dma_addr_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	uint8_t opened:1;
+	uint8_t enabled:1;
+	uint8_t running:1;
+	uint8_t stopped:1;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback:1;
+	uint8_t buf_refresh:1;
+
+	unsigned volume;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+};
+static struct audio the_evrc_audio;
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audevrc_send_data(struct audio *audio, unsigned needed);
+static void audevrc_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audevrc_config_hostpcm(struct audio *audio);
+static void audevrc_buffer_refresh(struct audio *audio);
+
+/* must be called with audio->lock held */
+static int audevrc_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (audio->enabled)
+		return 0;
+
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+	cfg.codec = RPC_AUD_DEF_CODEC_EVRC;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		pr_err("audio: msm_adsp_enable(audplay) failed\n");
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audevrc_dsp_event, audio)) {
+		pr_err("audio: audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audevrc_disable(struct audio *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+		auddec_dsp_config(audio, 0);
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+
+static void audevrc_update_pcm_buf_entry(struct audio *audio,
+					 uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr
+				== payload[2 + index * 2]) {
+			dprintk("audevrc_update_pcm_buf_entry: in[%d] ready\n",
+				audio->fill_next);
+			audio->in[audio->fill_next].used =
+				payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			pr_err
+			("audevrc_update_pcm_buf_entry: expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audevrc_buffer_refresh(audio);
+	} else {
+		dprintk("audevrc_update_pcm_buf_entry: read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->read_wait);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	dprintk("audplay_dsp_event: msg_id=%x\n", id);
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audevrc_send_data(audio, 1);
+		break;
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		dprintk("audevrc_update_pcm_buf_entry:======> \n");
+		audevrc_update_pcm_buf_entry(audio, msg);
+		break;
+	default:
+		pr_err("unexpected message from decoder \n");
+	}
+}
+
+static void audevrc_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP:
+				dprintk("decoder status: sleep \n");
+				break;
+
+			case AUDPP_DEC_STATUS_INIT:
+				dprintk("decoder status: init \n");
+				audpp_cmd_cfg_routing_mode(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				dprintk("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				dprintk("decoder status: play \n");
+				if (audio->pcm_feedback) {
+					audevrc_config_hostpcm(audio);
+					audevrc_buffer_refresh(audio);
+				}
+				break;
+			default:
+				pr_err("unknown decoder status \n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			dprintk("audevrc_dsp_event: CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_set_volume_and_pan(audio->dec_id, audio->volume,
+						 0);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			dprintk("audevrc_dsp_event: CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			pr_err("audevrc_dsp_event: CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		dprintk("audevrc_dsp_event: ROUTING_ACK\n");
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	default:
+		pr_err("audevrc_dsp_event: UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_evrc = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, QDSP_uPAudPlay0BitStreamCtrlQueue, \
+		       cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	audpp_cmd_cfg_dec_type cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+		    AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_EVRC;
+	else
+		cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_evrc cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = sizeof(cmd);
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = 8000;
+	cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	dprintk("audpp_cmd_cfg_routing_mode()\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	audplay_cmd_bitstream_data_avail cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+	cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audevrc_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+
+	refresh_cmd.buf_read_count = 0;
+	dprintk("audplay_buffer_fresh: buf0_addr=%x buf0_len=%d\n",
+		refresh_cmd.buf0_address, refresh_cmd.buf0_length);
+	audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audevrc_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	dprintk("audevrc_config_hostpcm()\n");
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = 1;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audevrc_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			dprintk("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			dprintk("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audevrc_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->stopped = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audevrc_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static long audevrc_ioctl(struct file *file, unsigned int cmd,
+			  unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	dprintk("audevrc_ioctl() cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == AUDIO_SET_VOLUME) {
+		unsigned long flags;
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->volume = arg;
+		if (audio->running)
+			audpp_set_volume_and_pan(audio->dec_id, arg, 0);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+	}
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		rc = audevrc_enable(audio);
+		break;
+	case AUDIO_STOP:
+		rc = audevrc_disable(audio);
+		audio->stopped = 1;
+		break;
+	case AUDIO_SET_CONFIG:{
+			dprintk("AUDIO_SET_CONFIG not applicable \n");
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = 8000;
+			config.channel_count = 1;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config, sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = 0;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config, sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				dprintk("audevrc_ioctl: allocate PCM buf %d\n",
+					config.buffer_count *
+					config.buffer_size);
+				audio->read_data =
+				    dma_alloc_coherent(NULL,
+						       config.buffer_size *
+						       config.buffer_count,
+						       &audio->read_phys,
+						       GFP_KERNEL);
+				if (!audio->read_data) {
+					pr_err
+					("audevrc_ioctl: no mem for pcm buf\n");
+					rc = -1;
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->pcm_feedback = 1;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		dprintk("%s: AUDIO_PAUSE %ld\n", __func__, arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audevrc_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+	if (!audio->pcm_feedback) {
+		return 0;
+		/* PCM feedback is not enabled. Nothing to read */
+	}
+	mutex_lock(&audio->read_lock);
+	dprintk("audevrc_read() \n");
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+					      (audio->in[audio->read_next].
+					       used > 0) || (audio->stopped));
+		dprintk("audevrc_read() wait terminated \n");
+		if (rc < 0)
+			break;
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not know frame size, read count must be greater or
+			 * equal to size of PCM samples
+			 */
+			dprintk("audevrc_read:read stop - partial frame\n");
+			break;
+		} else {
+			dprintk("audevrc_read: read from in[%d]\n",
+				audio->read_next);
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				pr_err("audevrc_read: invalid addr %x \n",
+				       (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			if (audio->in[audio->read_next].used == 0)
+				break;	/* No data ready at this moment
+					 * Exit while loop to prevent
+					 * output thread sleep too long
+					 */
+
+		}
+	}
+	if (audio->buf_refresh) {
+		audio->buf_refresh = 0;
+		dprintk("audevrc_read: kick start pcm feedback again\n");
+		audevrc_buffer_refresh(audio);
+	}
+	mutex_unlock(&audio->read_lock);
+	if (buf > start)
+		rc = buf - start;
+	dprintk("audevrc_read: read %d bytes\n", rc);
+	return rc;
+}
+
+static ssize_t audevrc_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int rc = 0;
+
+	if (count & 1)
+		return -EINVAL;
+	mutex_lock(&audio->write_lock);
+	dprintk("audevrc_write() \n");
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped));
+		if (rc < 0)
+			break;
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		xfer = (count > frame->size) ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		frame->used = xfer;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		audevrc_send_data(audio, 0);
+
+	}
+	mutex_unlock(&audio->write_lock);
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+
+static int audevrc_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	dprintk("audevrc_release()\n");
+
+	mutex_lock(&audio->lock);
+	audevrc_disable(audio);
+	audevrc_flush(audio);
+	audevrc_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audio->audplay = NULL;
+	audio->opened = 0;
+	dma_free_coherent(NULL, DMASZ, audio->data, audio->phys);
+	audio->data = NULL;
+	if (audio->read_data != NULL) {
+		dma_free_coherent(NULL,
+				  audio->in[0].size * audio->pcm_buf_count,
+				  audio->read_data, audio->read_phys);
+		audio->read_data = NULL;
+	}
+	audio->pcm_feedback = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static struct audio the_evrc_audio;
+
+static int audevrc_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &the_evrc_audio;
+	int rc;
+
+	if (audio->opened) {
+		pr_err("audio: busy\n");
+		return -EBUSY;
+	}
+
+	/* Acquire Lock */
+	mutex_lock(&audio->lock);
+
+	if (!audio->data) {
+		audio->data = dma_alloc_coherent(NULL, DMASZ,
+						 &audio->phys, GFP_KERNEL);
+		if (!audio->data) {
+			pr_err("audio: could not allocate DMA buffers\n");
+			rc = -ENOMEM;
+			goto dma_fail;
+		}
+	}
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto audmgr_fail;
+
+	rc = msm_adsp_get("AUDPLAY0TASK", &audio->audplay,
+			  &audplay_adsp_ops_evrc, audio);
+	if (rc) {
+		pr_err("audio: failed to get audplay0 dsp module\n");
+		goto adsp_fail;
+	}
+
+	audio->dec_id = 0;
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->volume = 0x3FFF;
+
+	audevrc_flush(audio);
+
+	audio->opened = 1;
+	file->private_data = audio;
+
+	mutex_unlock(&audio->lock);
+	return rc;
+
+adsp_fail:
+	audmgr_close(&audio->audmgr);
+audmgr_fail:
+	dma_free_coherent(NULL, DMASZ, audio->data, audio->phys);
+dma_fail:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static struct file_operations audio_evrc_fops = {
+	.owner = THIS_MODULE,
+	.open = audevrc_open,
+	.release = audevrc_release,
+	.read = audevrc_read,
+	.write = audevrc_write,
+	.unlocked_ioctl = audevrc_ioctl,
+};
+
+struct miscdevice audio_evrc_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_evrc",
+	.fops = &audio_evrc_fops,
+};
+
+static int __init audevrc_init(void)
+{
+	mutex_init(&the_evrc_audio.lock);
+	mutex_init(&the_evrc_audio.write_lock);
+	mutex_init(&the_evrc_audio.read_lock);
+	spin_lock_init(&the_evrc_audio.dsp_lock);
+	init_waitqueue_head(&the_evrc_audio.write_wait);
+	init_waitqueue_head(&the_evrc_audio.read_wait);
+	the_evrc_audio.read_data = NULL;
+	return misc_register(&audio_evrc_misc);
+}
+
+static void __exit audevrc_exit(void)
+{
+	misc_deregister(&audio_evrc_misc);
+}
+
+module_init(audevrc_init);
+module_exit(audevrc_exit);
+
+MODULE_DESCRIPTION("MSM EVRC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("QUALCOMM Inc");
diff --git a/arch/arm/mach-msm/qdsp5/audio_in.c b/arch/arm/mach-msm/qdsp5/audio_in.c
new file mode 100644
index 0000000..2a67209
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_in.c
@@ -0,0 +1,967 @@
+/* arch/arm/mach-msm/qdsp5/audio_in.c
+ *
+ * pcm audio input device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/delay.h>
+
+#include <linux/msm_audio.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <mach/msm_rpcrouter.h>
+
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+
+/* for queue ids - should be relative to module number*/
+#include "adsp.h"
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(8)
+#define FRAME_SIZE		(2052 * 2)
+#define MONO_DATA_SIZE		(2048)
+#define STEREO_DATA_SIZE	(MONO_DATA_SIZE * 2)
+#define DMASZ 			(FRAME_SIZE * FRAME_NUM)
+
+#define AGC_PARAM_SIZE		(20)
+#define NS_PARAM_SIZE		(6)
+#define IIR_PARAM_SIZE		(48)
+#define DEBUG			(0)
+
+#define AGC_ENABLE   0x0001
+#define NS_ENABLE    0x0002
+#define IIR_ENABLE   0x0004
+
+struct tx_agc_config {
+	uint16_t agc_params[AGC_PARAM_SIZE];
+};
+
+struct ns_config {
+	uint16_t ns_params[NS_PARAM_SIZE];
+};
+
+struct tx_iir_filter {
+	uint16_t num_bands;
+	uint16_t iir_params[IIR_PARAM_SIZE];
+};
+
+struct audpre_cmd_iir_config_type {
+	uint16_t cmd_id;
+	uint16_t active_flag;
+	uint16_t num_bands;
+	uint16_t iir_params[IIR_PARAM_SIZE];
+};
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+};
+
+struct audio_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+
+	struct msm_adsp_module *audpre;
+	struct msm_adsp_module *audrec;
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */
+	uint32_t type; /* 0 for PCM ,1 for AAC */
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	unsigned short samp_rate_index;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+
+	/* audpre settings */
+	int agc_enable;
+	struct tx_agc_config agc;
+
+	int ns_enable;
+	struct ns_config ns;
+
+	int iir_enable;
+	struct tx_iir_filter iir;
+};
+
+static int audio_in_dsp_enable(struct audio_in *audio, int enable);
+static int audio_in_encoder_config(struct audio_in *audio);
+static int audio_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt);
+static void audio_flush(struct audio_in *audio);
+static int audio_dsp_set_agc(struct audio_in *audio);
+static int audio_dsp_set_ns(struct audio_in *audio);
+static int audio_dsp_set_tx_iir(struct audio_in *audio);
+
+static unsigned convert_dsp_samp_index(unsigned index)
+{
+	switch (index) {
+	case 48000:	return AUDREC_CMD_SAMP_RATE_INDX_48000;
+	case 44100:	return AUDREC_CMD_SAMP_RATE_INDX_44100;
+	case 32000:	return AUDREC_CMD_SAMP_RATE_INDX_32000;
+	case 24000:	return AUDREC_CMD_SAMP_RATE_INDX_24000;
+	case 22050:	return AUDREC_CMD_SAMP_RATE_INDX_22050;
+	case 16000:	return AUDREC_CMD_SAMP_RATE_INDX_16000;
+	case 12000:	return AUDREC_CMD_SAMP_RATE_INDX_12000;
+	case 11025:	return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	case 8000:	return AUDREC_CMD_SAMP_RATE_INDX_8000;
+	default: 	return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	}
+}
+
+static unsigned convert_samp_rate(unsigned hz)
+{
+	switch (hz) {
+	case 48000: return RPC_AUD_DEF_SAMPLE_RATE_48000;
+	case 44100: return RPC_AUD_DEF_SAMPLE_RATE_44100;
+	case 32000: return RPC_AUD_DEF_SAMPLE_RATE_32000;
+	case 24000: return RPC_AUD_DEF_SAMPLE_RATE_24000;
+	case 22050: return RPC_AUD_DEF_SAMPLE_RATE_22050;
+	case 16000: return RPC_AUD_DEF_SAMPLE_RATE_16000;
+	case 12000: return RPC_AUD_DEF_SAMPLE_RATE_12000;
+	case 11025: return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	case 8000:  return RPC_AUD_DEF_SAMPLE_RATE_8000;
+	default:    return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	}
+}
+
+static unsigned convert_samp_index(unsigned index)
+{
+	switch (index) {
+	case RPC_AUD_DEF_SAMPLE_RATE_48000:	return 48000;
+	case RPC_AUD_DEF_SAMPLE_RATE_44100:	return 44100;
+	case RPC_AUD_DEF_SAMPLE_RATE_32000:	return 32000;
+	case RPC_AUD_DEF_SAMPLE_RATE_24000:	return 24000;
+	case RPC_AUD_DEF_SAMPLE_RATE_22050:	return 22050;
+	case RPC_AUD_DEF_SAMPLE_RATE_16000:	return 16000;
+	case RPC_AUD_DEF_SAMPLE_RATE_12000:	return 12000;
+	case RPC_AUD_DEF_SAMPLE_RATE_11025:	return 11025;
+	case RPC_AUD_DEF_SAMPLE_RATE_8000:	return 8000;
+	default: 				return 11025;
+	}
+}
+
+/* must be called with audio->lock held */
+static int audio_in_enable(struct audio_in *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (audio->enabled)
+		return 0;
+
+	cfg.tx_rate = audio->samp_rate;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+	if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV)
+		cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	else
+		cfg.codec = RPC_AUD_DEF_CODEC_AAC;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audpre)) {
+		pr_err("audrec: msm_adsp_enable(audpre) failed\n");
+		return -ENODEV;
+	}
+	if (msm_adsp_enable(audio->audrec)) {
+		pr_err("audrec: msm_adsp_enable(audrec) failed\n");
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	audio_in_dsp_enable(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_in_disable(struct audio_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+
+		audio_in_dsp_enable(audio, 0);
+
+		wake_up(&audio->wait);
+
+		msm_adsp_disable(audio->audrec);
+		msm_adsp_disable(audio->audpre);
+		audmgr_disable(&audio->audmgr);
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	uint16_t msg[6]; /* may be a 32-bit event, which we ignore */
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		pr_info("audpre: type %d, status_flag %d\n", msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		pr_info("audpre: err_index %d\n", msg[0]);
+		break;
+	default:
+		pr_err("audpre: unknown event %d\n", id);
+	}
+}
+
+struct audio_frame {
+	uint16_t count_low;
+	uint16_t count_high;
+	uint16_t bytes;
+	uint16_t unknown;
+	unsigned char samples[];
+} __attribute__((packed));
+
+static void audio_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+
+	/* XXX check for bogus frame size? */
+
+	frame = (void *) (((char *)audio->in[index].data) - sizeof(*frame));
+		
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = frame->bytes;
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+	else
+		audio->in_count++;
+
+	audio_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_in *audio = data;
+	uint16_t msg[6]; /* may be a 32-bit event, which we ignore */
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG:
+		if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE) {
+			if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_ENA) {
+				pr_info("audpre: CFG ENABLED\n");
+				audio_dsp_set_agc(audio);
+				audio_dsp_set_ns(audio);
+				audio_dsp_set_tx_iir(audio);
+				audio_in_encoder_config(audio);
+			} else {
+				pr_info("audrec: CFG SLEEP\n");
+				audio->running = 0;
+			}
+		} else {
+			pr_info("audrec: CMD_CFG_DONE %x\n", msg[0]);
+		}
+		break;
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
+		pr_info("audrec: PARAM CFG DONE\n");
+		audio->running = 1;
+		break;
+	}
+	case AUDREC_MSG_FATAL_ERR_MSG:
+		pr_err("audrec: ERROR %x\n", msg[0]);
+		break;
+	case AUDREC_MSG_PACKET_READY_MSG:
+/* REC_DBG("type %x, count %d", msg[0], (msg[1] | (msg[2] << 16))); */
+		audio_in_get_dsp_frames(audio);
+		break;
+	default:
+		pr_err("audrec: unknown event %d\n", id);
+	}
+}
+
+struct msm_adsp_ops audpre_adsp_ops = {
+	.event = audpre_dsp_event,
+};
+
+struct msm_adsp_ops audrec_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+
+#define audio_send_queue_pre(audio, cmd, len) \
+	msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
+#define audio_send_queue_recbs(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len)
+#define audio_send_queue_rec(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, \
+	QDSP_uPAudRecCmdQueue, cmd, len)
+
+static int audio_dsp_set_agc(struct audio_in *audio)
+{
+	audpreproc_cmd_cfg_agc_params cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
+
+	if (audio->agc_enable) {
+		/* cmd.tx_agc_param_mask = 0xFE00 from sample code */
+		cmd.tx_agc_param_mask =
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_SLOPE) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_TH) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_SLOPE) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_TH) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_AIG_FLAG) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_STATIC_GAIN) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG);
+		cmd.tx_agc_enable_flag =
+			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA;
+		memcpy(&cmd.static_gain, &audio->agc.agc_params[0],
+			sizeof(uint16_t) * 6);
+		/* cmd.param_mask = 0xFFF0 from sample code */
+		cmd.param_mask =
+			(1 << AUDPREPROC_CMD_PARAM_MASK_RMS_TAY) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_RELEASEK) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_DELAY) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_ATTACKK) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_SLOW) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_FAST) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_RELEASEK) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_MIN) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_MAX) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAK_UP) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAK_DOWN) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_ATTACKK);
+		memcpy(&cmd.aig_attackk, &audio->agc.agc_params[6],
+			sizeof(uint16_t) * 14);
+
+	} else {
+		cmd.tx_agc_param_mask =
+			(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG);
+		cmd.tx_agc_enable_flag =
+			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS;
+	}
+#if DEBUG
+	pr_info("cmd_id = 0x%04x\n", cmd.cmd_id);
+	pr_info("tx_agc_param_mask = 0x%04x\n", cmd.tx_agc_param_mask);
+	pr_info("tx_agc_enable_flag = 0x%04x\n", cmd.tx_agc_enable_flag);
+	pr_info("static_gain = 0x%04x\n", cmd.static_gain);
+	pr_info("adaptive_gain_flag = 0x%04x\n", cmd.adaptive_gain_flag);
+	pr_info("expander_th = 0x%04x\n", cmd.expander_th);
+	pr_info("expander_slope = 0x%04x\n", cmd.expander_slope);
+	pr_info("compressor_th = 0x%04x\n", cmd.compressor_th);
+	pr_info("compressor_slope = 0x%04x\n", cmd.compressor_slope);
+	pr_info("param_mask = 0x%04x\n", cmd.param_mask);
+	pr_info("aig_attackk = 0x%04x\n", cmd.aig_attackk);
+	pr_info("aig_leak_down = 0x%04x\n", cmd.aig_leak_down);
+	pr_info("aig_leak_up = 0x%04x\n", cmd.aig_leak_up);
+	pr_info("aig_max = 0x%04x\n", cmd.aig_max);
+	pr_info("aig_min = 0x%04x\n", cmd.aig_min);
+	pr_info("aig_releasek = 0x%04x\n", cmd.aig_releasek);
+	pr_info("aig_leakrate_fast = 0x%04x\n", cmd.aig_leakrate_fast);
+	pr_info("aig_leakrate_slow = 0x%04x\n", cmd.aig_leakrate_slow);
+	pr_info("attackk_msw = 0x%04x\n", cmd.attackk_msw);
+	pr_info("attackk_lsw = 0x%04x\n", cmd.attackk_lsw);
+	pr_info("delay = 0x%04x\n", cmd.delay);
+	pr_info("releasek_msw = 0x%04x\n", cmd.releasek_msw);
+	pr_info("releasek_lsw = 0x%04x\n", cmd.releasek_lsw);
+	pr_info("rms_tav = 0x%04x\n", cmd.rms_tav);
+#endif
+	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_dsp_set_ns(struct audio_in *audio)
+{
+	audpreproc_cmd_cfg_ns_params cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS;
+
+	if (audio->ns_enable) {
+		/* cmd.ec_mode_new is fixed as 0x0064 when enable from sample code */
+		cmd.ec_mode_new =
+			AUDPREPROC_CMD_EC_MODE_NEW_NS_ENA |
+			AUDPREPROC_CMD_EC_MODE_NEW_HB_ENA |
+			AUDPREPROC_CMD_EC_MODE_NEW_VA_ENA;
+		memcpy(&cmd.dens_gamma_n, &audio->ns.ns_params,
+			sizeof(audio->ns.ns_params));
+	} else {
+		cmd.ec_mode_new =
+			AUDPREPROC_CMD_EC_MODE_NEW_NLMS_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_DES_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NS_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_CNI_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NLES_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_HB_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_VA_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_PCD_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_FEHI_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NEHI_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NLPP_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_FNE_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_DIS;
+	}
+#if DEBUG
+	pr_info("cmd_id = 0x%04x\n", cmd.cmd_id);
+	pr_info("ec_mode_new = 0x%04x\n", cmd.ec_mode_new);
+	pr_info("dens_gamma_n = 0x%04x\n", cmd.dens_gamma_n);
+	pr_info("dens_nfe_block_size = 0x%04x\n", cmd.dens_nfe_block_size);
+	pr_info("dens_limit_ns = 0x%04x\n", cmd.dens_limit_ns);
+	pr_info("dens_limit_ns_d = 0x%04x\n", cmd.dens_limit_ns_d);
+	pr_info("wb_gamma_e = 0x%04x\n", cmd.wb_gamma_e);
+	pr_info("wb_gamma_n = 0x%04x\n", cmd.wb_gamma_n);
+#endif
+	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_dsp_set_tx_iir(struct audio_in *audio)
+{
+	struct audpre_cmd_iir_config_type cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+
+	if (audio->iir_enable) {
+		cmd.active_flag = AUDPREPROC_CMD_IIR_ACTIVE_FLAG_ENA;
+		cmd.num_bands = audio->iir.num_bands;
+		memcpy(&cmd.iir_params, &audio->iir.iir_params,
+			sizeof(audio->iir.iir_params));
+	} else {
+		cmd.active_flag = AUDPREPROC_CMD_IIR_ACTIVE_FLAG_DIS;
+	}
+#if DEBUG
+	pr_info("cmd_id = 0x%04x\n", cmd.cmd_id);
+	pr_info("active_flag = 0x%04x\n", cmd.active_flag);
+#endif
+	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_in_dsp_enable(struct audio_in *audio, int enable)
+{
+	audrec_cmd_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_CFG;
+	cmd.type_0 = enable ? AUDREC_CMD_TYPE_0_ENA : AUDREC_CMD_TYPE_0_DIS;
+	cmd.type_0 |= (AUDREC_CMD_TYPE_0_UPDATE | audio->type);
+	cmd.type_1 = 0;
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_in_encoder_config(struct audio_in *audio)
+{
+	audrec_cmd_arec0param_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	unsigned n;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_AREC0PARAM_CFG;
+	cmd.ptr_to_extpkt_buffer_msw = audio->phys >> 16;
+	cmd.ptr_to_extpkt_buffer_lsw = audio->phys;
+	cmd.buf_len = FRAME_NUM; /* Both WAV and AAC use 8 frames */
+	cmd.samp_rate_index = audio->samp_rate_index;
+	cmd.stereo_mode = audio->channel_mode; /* 0 for mono, 1 for stereo */
+
+	/* FIXME have no idea why cmd.rec_quality is fixed 
+	 * as 0x1C00 from sample code
+	 */
+	cmd.rec_quality = 0x1C00;
+
+	/* prepare buffer pointers:
+	 * Mono: 1024 samples + 4 halfword header
+	 * Stereo: 2048 samples + 4 halfword header
+	 * AAC
+	 * Mono/Stere: 768 + 4 halfword header
+	 */
+	for (n = 0; n < FRAME_NUM; n++) {
+		audio->in[n].data = data + 4;
+		if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV)
+			data += (4 + (audio->channel_mode ? 2048 : 1024));
+		else if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC)
+			data += (4 + 768);
+	}
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt)
+{
+	audrec_cmd_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
+	/* Both WAV and AAC use AUDREC_CMD_TYPE_0 */
+	cmd.type = AUDREC_CMD_TYPE_0;
+	cmd.curr_rec_count_msw = read_cnt >> 16;
+	cmd.curr_rec_count_lsw = read_cnt;
+
+	return audio_send_queue_recbs(audio, &cmd, sizeof(cmd));
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_enable_agc(struct audio_in *audio, int enable)
+{
+	if (audio->agc_enable != enable) {
+		audio->agc_enable = enable;
+		if (audio->running)
+			audio_dsp_set_agc(audio);
+	}
+}
+
+static void audio_enable_ns(struct audio_in *audio, int enable)
+{
+	if (audio->ns_enable != enable) {
+		audio->ns_enable = enable;
+		if (audio->running)
+			audio_dsp_set_ns(audio);
+	}
+}
+
+static void audio_enable_tx_iir(struct audio_in *audio, int enable)
+{
+	if (audio->iir_enable != enable) {
+		audio->iir_enable = enable;
+		if (audio->running)
+			audio_dsp_set_tx_iir(audio);
+	}
+}
+
+static void audio_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	for (i = 0; i < FRAME_NUM; i++) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+}
+
+static long audio_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		rc = audio_in_enable(audio);
+		break;
+	case AUDIO_STOP:
+		rc = audio_in_disable(audio);
+		audio->stopped = 1;
+		break;
+	case AUDIO_FLUSH:
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the read_lock.
+			 * While audio->stopped read threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->wait);
+			mutex_lock(&audio->read_lock);
+			audio_flush(audio);
+			mutex_unlock(&audio->read_lock);
+		}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.channel_count == 1) {
+			cfg.channel_count = AUDREC_CMD_STEREO_MODE_MONO;
+		} else if (cfg.channel_count == 2) {
+			cfg.channel_count = AUDREC_CMD_STEREO_MODE_STEREO;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+
+		if (cfg.type == 0) {
+			cfg.type = AUDREC_CMD_TYPE_0_INDEX_WAV;
+		} else if (cfg.type == 1) {
+			cfg.type = AUDREC_CMD_TYPE_0_INDEX_AAC;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->samp_rate = convert_samp_rate(cfg.sample_rate);
+		audio->samp_rate_index =
+		  convert_dsp_samp_index(cfg.sample_rate);
+		audio->channel_mode = cfg.channel_count;
+		audio->buffer_size =
+				audio->channel_mode ? STEREO_DATA_SIZE
+							: MONO_DATA_SIZE;
+		audio->type = cfg.type;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		cfg.sample_rate = convert_samp_index(audio->samp_rate);
+		if (audio->channel_mode == AUDREC_CMD_STEREO_MODE_MONO)
+			cfg.channel_count = 1;
+		else
+			cfg.channel_count = 2;
+		if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV)
+			cfg.type = 0;
+		else
+			cfg.type = 1;
+		cfg.unused[0] = 0;
+		cfg.unused[1] = 0;
+		cfg.unused[2] = 0;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audio_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped);
+		if (rc < 0)
+			break;
+
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+		if (count >= size) {
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+			/* overrun -- data is invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+			if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC)
+				break;
+		} else {
+			pr_err("audio_in: short read\n");
+			break;
+		}
+		if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC)
+			break; /* AAC only read one frame */
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static ssize_t audio_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static int audio_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	audio_in_disable(audio);
+	audio_flush(audio);
+	msm_adsp_put(audio->audrec);
+	msm_adsp_put(audio->audpre);
+	audio->audrec = NULL;
+	audio->audpre = NULL;
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+struct audio_in the_audio_in;
+
+static int audio_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_in;
+	int rc;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_11025;
+	audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_11025;
+	audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
+	audio->buffer_size = MONO_DATA_SIZE;
+	audio->type = AUDREC_CMD_TYPE_0_INDEX_WAV;
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto done;
+	rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
+				&audpre_adsp_ops, audio);
+	if (rc)
+		goto done;
+	rc = msm_adsp_get("AUDRECTASK", &audio->audrec,
+			   &audrec_adsp_ops, audio);
+	if (rc)
+		goto done;
+
+	audio->dsp_cnt = 0;
+	audio->stopped = 0;
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static long audpre_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0, enable;
+	uint16_t enable_mask;
+#if DEBUG
+	int i;
+#endif
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPRE: {
+		if (copy_from_user(&enable_mask, (void *) arg,
+				sizeof(enable_mask)))
+			goto out_fault;
+
+		enable = (enable_mask & AGC_ENABLE) ? 1 : 0;
+		audio_enable_agc(audio, enable);
+		enable = (enable_mask & NS_ENABLE) ? 1 : 0;
+		audio_enable_ns(audio, enable);
+		enable = (enable_mask & IIR_ENABLE) ? 1 : 0;
+		audio_enable_tx_iir(audio, enable);
+		break;
+	}
+	case AUDIO_SET_AGC: {
+		if (copy_from_user(&audio->agc, (void *) arg,
+				sizeof(audio->agc)))
+			goto out_fault;
+#if DEBUG
+		pr_info("set agc\n");
+		for (i = 0; i < AGC_PARAM_SIZE; i++) \
+			pr_info("agc_params[%d] = 0x%04x\n", i,
+				audio->agc.agc_params[i]);
+#endif
+		break;
+	}
+	case AUDIO_SET_NS: {
+		if (copy_from_user(&audio->ns, (void *) arg,
+				sizeof(audio->ns)))
+			goto out_fault;
+#if DEBUG
+		pr_info("set ns\n");
+		for (i = 0; i < NS_PARAM_SIZE; i++) \
+			pr_info("ns_params[%d] = 0x%04x\n",
+				i, audio->ns.ns_params[i]);
+#endif
+		break;
+	}
+	case AUDIO_SET_TX_IIR: {
+		if (copy_from_user(&audio->iir, (void *) arg,
+				sizeof(audio->iir)))
+			goto out_fault;
+#if DEBUG
+		pr_info("set iir\n");
+		pr_info("iir.num_bands = 0x%04x\n", audio->iir.num_bands);
+		for (i = 0; i < IIR_PARAM_SIZE; i++) \
+			pr_info("iir_params[%d] = 0x%04x\n",
+				i, audio->iir.iir_params[i]);
+#endif
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+
+	goto out;
+
+out_fault:
+	rc = -EFAULT;
+out:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audpre_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_in;
+	file->private_data = audio;
+	return 0;
+}
+
+static struct file_operations audio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+static struct file_operations audpre_fops = {
+	.owner          = THIS_MODULE,
+	.open           = audpre_open,
+	.unlocked_ioctl = audpre_ioctl,
+};
+
+struct miscdevice audio_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &audio_fops,
+};
+
+struct miscdevice audpre_misc = {
+	.minor  = MISC_DYNAMIC_MINOR,
+	.name   = "msm_audpre",
+	.fops   = &audpre_fops,
+};
+
+static int __init audio_in_init(void)
+{
+	int rc;
+	the_audio_in.data = dma_alloc_coherent(NULL, DMASZ,
+					       &the_audio_in.phys, GFP_KERNEL);
+	if (!the_audio_in.data) {
+		printk(KERN_ERR "%s: Unable to allocate DMA buffer\n",
+		       __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&the_audio_in.lock);
+	mutex_init(&the_audio_in.read_lock);
+	spin_lock_init(&the_audio_in.dsp_lock);
+	init_waitqueue_head(&the_audio_in.wait);
+	rc = misc_register(&audio_in_misc);
+	if (!rc) {
+		rc = misc_register(&audpre_misc);
+		if (rc < 0)
+			misc_deregister(&audio_in_misc);
+	}
+	return rc;
+}
+
+device_initcall(audio_in_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
new file mode 100644
index 0000000..f09bdcb
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -0,0 +1,970 @@
+/* arch/arm/mach-msm/qdsp5/audio_mp3.c
+ * 
+ * mp3 audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/delay.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+
+#include <linux/msm_audio.h>
+
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+
+/* for queue ids - should be relative to module number*/
+#include "adsp.h"
+
+#ifdef DEBUG
+#define dprintk(format, arg...) \
+printk(KERN_DEBUG format, ## arg)
+#else
+#define dprintk(format, arg...) do {} while (0)
+#endif
+
+/* Size must be power of 2 */
+#define BUFSZ_MAX 32768
+#define BUFSZ_MIN 4096
+#define DMASZ_MAX (BUFSZ_MAX * 2)
+#define DMASZ_MIN (BUFSZ_MIN * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_MP3 2
+
+#define PCM_BUFSZ_MIN 4800	/* Hold one stereo MP3 frame */
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	dma_addr_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	unsigned volume;
+
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	pr_info("audio_enable()\n");
+
+	if (audio->enabled)
+		return 0;
+
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+	cfg.codec = RPC_AUD_DEF_CODEC_MP3;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		pr_err("audio: msm_adsp_enable(audplay) failed\n");
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		pr_err("audio: audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	pr_info("audio_disable()\n");
+	if (audio->enabled) {
+		audio->enabled = 0;
+		auddec_dsp_config(audio, 0);
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_update_pcm_buf_entry(struct audio *audio, uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush) {
+		audio->buf_refresh = 1;
+		return;
+	}
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			pr_info("audio_update_pcm_buf_entry: in[%d] ready\n",
+				audio->fill_next);
+			audio->in[audio->fill_next].used =
+			  payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			pr_err
+			    ("audio_update_pcm_buf_entry: expected=%x ret=%x\n"
+			     , audio->in[audio->fill_next].addr,
+			     payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audplay_buffer_refresh(audio);
+	} else {
+		pr_info("audio_update_pcm_buf_entry: read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	dprintk("audplay_dsp_event: msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audplay_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio_update_pcm_buf_entry(audio, msg);
+		break;
+
+	default:
+		pr_err("unexpected message from decoder \n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP:
+				pr_info("decoder status: sleep \n");
+				break;
+
+			case AUDPP_DEC_STATUS_INIT:
+				pr_info("decoder status: init \n");
+				audpp_cmd_cfg_routing_mode(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				pr_info("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				pr_info("decoder status: play \n");
+				if (audio->pcm_feedback) {
+					audplay_config_hostpcm(audio);
+					audplay_buffer_refresh(audio);
+				}
+				break;
+			default:
+				pr_err("unknown decoder status \n");
+				break;
+			}
+      break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			pr_info("audio_dsp_event: CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_set_volume_and_pan(audio->dec_id, audio->volume,
+						 0);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			pr_info("audio_dsp_event: CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			pr_err("audio_dsp_event: CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		pr_info("audio_dsp_event: ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		dprintk("%s: FLUSH_ACK\n", __func__);
+		audio->wflush = 0;
+		audio->rflush = 0;
+		if (audio->pcm_feedback)
+			audplay_buffer_refresh(audio);
+		break;
+
+	default:
+		pr_err("audio_dsp_event: UNKNOWN (%d)\n", id);
+	}
+
+}
+
+
+struct msm_adsp_ops audplay_adsp_ops = {
+	.event = audplay_dsp_event,
+};
+
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, QDSP_uPAudPlay0BitStreamCtrlQueue, \
+		       cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	audpp_cmd_cfg_dec_type cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+			       AUDPP_CMD_ENA_DEC_V |
+			       AUDDEC_DEC_MP3;
+	else
+		cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+			       AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	audpp_cmd_cfg_adec_params_mp3 cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	pr_info("audpp_cmd_cfg_routing_mode()\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+					unsigned idx, unsigned len)
+{
+	audplay_cmd_bitstream_data_avail cmd;
+
+	cmd.cmd_id		= AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+	cmd.decoder_id		= audio->dec_id;
+	cmd.buf_ptr		= audio->out[idx].addr;
+	cmd.buf_size		= len/2;
+	cmd.partition_number	= 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size -
+	  (audio->in[audio->fill_next].size % 576);	/* Mp3 frame size */
+	refresh_cmd.buf_read_count = 0;
+	pr_info("audplay_buffer_fresh: buf0_addr=%x buf0_len=%d\n",
+		refresh_cmd.buf0_address, refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	pr_info("audplay_config_hostpcm()\n");
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = 1;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (audio->wflush) {
+		audio->out_needed = 1;
+		goto done;
+	}
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+		  dprintk("frame %d free\n", audio->out_tail);
+		  frame->used = 0;
+		  audio->out_tail ^= 1;
+		  wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+			
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+		  BUG_ON(frame->used == 0xffffffff);
+		  dprintk("frame %d busy\n", audio->out_tail);
+		  audplay_dsp_send_data_avail(audio, audio->out_tail,
+					      frame->used);
+		  frame->used = 0xffffffff;
+		  audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audio_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audio_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	pr_info("audio_ioctl() cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == AUDIO_SET_VOLUME) {
+		unsigned long flags;
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->volume = arg;
+		if (audio->running)
+			audpp_set_volume_and_pan(audio->dec_id, arg, 0);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+	}
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		rc = audio_enable(audio);
+		break;
+	case AUDIO_STOP:
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		dprintk("%s: AUDIO_FLUSH\n", __func__);
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		audio->rflush = 0;
+		audio->wflush = 0;
+
+		if (audio->buf_refresh) {
+			audio->buf_refresh = 0;
+			audplay_buffer_refresh(audio);
+		}
+		break;
+
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = (audio->out_dma_sz >> 1);
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V) {
+			config.channel_count = 1;
+		} else {
+			config.channel_count = 2;
+		}
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		} else {
+			rc = 0;
+		}
+		break;
+	}
+	case AUDIO_GET_PCM_CONFIG:{
+		struct msm_audio_pcm_config config;
+		config.pcm_feedback = 0;
+		config.buffer_count = PCM_BUF_MAX_COUNT;
+		config.buffer_size = PCM_BUFSZ_MIN;
+		if (copy_to_user((void *)arg, &config,
+			 sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				pr_info("ioctl: allocate PCM buffer %d\n",
+					config.buffer_count *
+					config.buffer_size);
+				audio->read_data =
+				    dma_alloc_coherent(NULL,
+						       config.buffer_size *
+						       config.buffer_count,
+						       &audio->read_phys,
+						       GFP_KERNEL);
+				if (!audio->read_data) {
+					pr_err("audio_mp3: malloc pcm \
+					buf failed\n");
+					rc = -1;
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->pcm_feedback = 1;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		dprintk("%s: AUDIO_PAUSE %ld\n", __func__, arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback disabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	pr_info("audio_read() %d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+					      (audio->in[audio->read_next].
+					       used > 0) || (audio->stopped)
+						   || (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since
+			 * driver does not know frame size, read count
+			 * must be greater or equal
+			 * to size of PCM samples
+			 */
+			pr_info("audio_read: no partial frame done reading\n");
+			break;
+		} else {
+			pr_info("audio_read: read from in[%d]\n",
+				audio->read_next);
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				pr_err("audio_read: invalid addr %x \n",
+				       (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			if (audio->in[audio->read_next].used == 0)
+				break; /* No data ready at this moment
+					* Exit while loop to prevent
+					* output thread sleep too long
+					*/
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		pr_info("audio_read: kick start pcm feedback again\n");
+		audplay_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	pr_info("audio_read: read %d bytes\n", rc);
+	return rc;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0;
+	unsigned dsize;
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped)
+						  || (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->reserved) {
+			dprintk("%s: append reserved byte %x\n",
+				__func__, audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > (frame->size - 1)) ?
+				frame->size - 1 : count;
+			cpy_ptr++;
+			dsize = 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > frame->size) ? frame->size : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			dprintk("%s: odd length buf reserve last byte %x\n",
+				__func__, audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audplay_send_data(audio, 0);
+		}
+	}
+	mutex_unlock(&audio->write_lock);
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	dprintk("audio_release()\n");
+
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	audio_flush(audio);
+	audio_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audio->audplay = NULL;
+	audio->opened = 0;
+	audio->reserved = 0;
+	dma_free_coherent(NULL, audio->out_dma_sz, audio->data, audio->phys);
+	audio->data = NULL;
+	if (audio->read_data != NULL) {
+		dma_free_coherent(NULL,
+				  audio->in[0].size * audio->pcm_buf_count,
+				  audio->read_data, audio->read_phys);
+		audio->read_data = NULL;
+	}
+	audio->pcm_feedback = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+struct audio the_mp3_audio;
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &the_mp3_audio;
+	int rc;
+	unsigned pmem_sz;
+
+	mutex_lock(&audio->lock);
+
+	if (audio->opened) {
+		pr_err("audio: busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	pmem_sz = DMASZ_MAX;
+
+	while (pmem_sz >= DMASZ_MIN) {
+		audio->data = dma_alloc_coherent(NULL, pmem_sz,
+						 &audio->phys, GFP_KERNEL);
+		if (audio->data)
+			break;
+		else if (pmem_sz == DMASZ_MIN) {
+			pr_err("audio: could not allocate DMA buffers\n");
+			rc = -ENOMEM;
+			goto done;
+		} else
+			pmem_sz >>= 1;
+	}
+
+	dprintk("%s: allocated %d bytes DMA buffer\n", __func__, pmem_sz);
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc) {
+		dma_free_coherent(NULL, pmem_sz,
+		audio->data, audio->phys);
+		goto done;
+	}
+
+	rc = msm_adsp_get("AUDPLAY0TASK", &audio->audplay, &audplay_adsp_ops,
+			  audio);
+	if (rc) {
+		pr_err("audio: failed to get audplay0 dsp module\n");
+		dma_free_coherent(NULL, pmem_sz,
+		audio->data, audio->phys);
+		audmgr_close(&audio->audmgr);
+		goto done;
+	}
+
+	audio->out_dma_sz = pmem_sz;
+	pmem_sz >>= 1; /* Shift by 1 to get size of ping pong buffer */
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->dec_id = 0;
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = pmem_sz;
+
+	audio->out[1].data = audio->data + pmem_sz;
+	audio->out[1].addr = audio->phys + pmem_sz;
+	audio->out[1].size = pmem_sz;
+
+	audio->volume = 0x2000;	/* equal to Q13 number 1.0 Unit Gain */
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static struct file_operations audio_mp3_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+};
+
+struct miscdevice audio_mp3_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_mp3",
+	.fops	= &audio_mp3_fops,
+};
+
+static int __init audio_init(void)
+{
+	mutex_init(&the_mp3_audio.lock);
+	mutex_init(&the_mp3_audio.write_lock);
+	mutex_init(&the_mp3_audio.read_lock);
+	spin_lock_init(&the_mp3_audio.dsp_lock);
+	init_waitqueue_head(&the_mp3_audio.write_wait);
+	init_waitqueue_head(&the_mp3_audio.read_wait);
+	the_mp3_audio.read_data = NULL;
+	return misc_register(&audio_mp3_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
new file mode 100644
index 0000000..fcb1f13
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -0,0 +1,850 @@
+/* arch/arm/mach-msm/qdsp5/audio_out.c
+ *
+ * pcm audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+
+#include <linux/msm_audio.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+
+#include <mach/htc_pwrsink.h>
+
+#include "evlog.h"
+
+#define LOG_AUDIO_EVENTS 1
+#define LOG_AUDIO_FAULTS 0
+
+enum {
+	EV_NULL,
+	EV_OPEN,
+	EV_WRITE,
+	EV_RETURN,
+	EV_IOCTL,
+	EV_WRITE_WAIT,
+	EV_WAIT_EVENT,
+	EV_FILL_BUFFER,
+	EV_SEND_BUFFER,
+	EV_DSP_EVENT,
+	EV_ENABLE,
+};
+
+#if (LOG_AUDIO_EVENTS != 1)
+static inline void LOG(unsigned id, unsigned arg) {}
+#else
+static const char *pcm_log_strings[] = {
+	"NULL",
+	"OPEN",
+	"WRITE",
+	"RETURN",
+	"IOCTL",
+	"WRITE_WAIT",
+	"WAIT_EVENT",
+	"FILL_BUFFER",
+	"SEND_BUFFER",
+	"DSP_EVENT",
+	"ENABLE",
+};
+
+DECLARE_LOG(pcm_log, 64, pcm_log_strings);
+
+static int __init _pcm_log_init(void)
+{
+	return ev_log_init(&pcm_log);
+}
+module_init(_pcm_log_init);
+
+#define LOG(id,arg) ev_log_write(&pcm_log, id, arg)
+#endif
+
+
+
+
+
+#define BUFSZ (960 * 5)
+#define DMASZ (BUFSZ * 2)
+
+#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
+#define AUDPP_CMD_EQ_FLAG_DIS	0x0000
+#define AUDPP_CMD_EQ_FLAG_ENA	-1
+#define AUDPP_CMD_IIR_FLAG_DIS	  0x0000
+#define AUDPP_CMD_IIR_FLAG_ENA	  -1
+
+#define AUDPP_CMD_IIR_TUNING_FILTER  1
+#define AUDPP_CMD_EQUALIZER	2
+#define AUDPP_CMD_ADRC	3
+
+#define ADRC_ENABLE  0x0001
+#define EQ_ENABLE    0x0002
+#define IIR_ENABLE   0x0004
+
+struct adrc_filter {
+	uint16_t compression_th;
+	uint16_t compression_slope;
+	uint16_t rms_time;
+	uint16_t attack_const_lsw;
+	uint16_t attack_const_msw;
+	uint16_t release_const_lsw;
+	uint16_t release_const_msw;
+	uint16_t adrc_system_delay;
+};
+
+struct eqalizer {
+	uint16_t num_bands;
+	uint16_t eq_params[132];
+};
+
+struct rx_iir_filter {
+	uint16_t num_bands;
+	uint16_t iir_params[48];
+};
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common common;
+	uint16_t eq_flag;
+	uint16_t num_bands;
+	uint16_t eq_params[132];
+} audpp_cmd_cfg_object_params_eq;
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common common;
+	uint16_t active_flag;
+	uint16_t num_bands;
+	uint16_t iir_params[48];
+} audpp_cmd_cfg_object_params_rx_iir;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+	unsigned addr;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t wait;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_weight;
+	uint32_t out_buffer_size;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	unsigned volume;
+
+	struct wake_lock wakelock;
+	struct wake_lock idlelock;
+
+	int adrc_enable;
+	struct adrc_filter adrc;
+
+	int eq_enable;
+	struct eqalizer eq;
+
+	int rx_iir_enable;
+	struct rx_iir_filter iir;
+};
+
+static void audio_prevent_sleep(struct audio *audio)
+{
+	printk(KERN_INFO "++++++++++++++++++++++++++++++\n");
+	wake_lock(&audio->wakelock);
+	wake_lock(&audio->idlelock);
+}
+
+static void audio_allow_sleep(struct audio *audio)
+{
+	wake_unlock(&audio->wakelock);
+	wake_unlock(&audio->idlelock);
+	printk(KERN_INFO "------------------------------\n");
+}
+
+static int audio_dsp_out_enable(struct audio *audio, int yes);
+static int audio_dsp_send_buffer(struct audio *audio, unsigned id, unsigned len);
+static int audio_dsp_set_adrc(struct audio *audio);
+static int audio_dsp_set_eq(struct audio *audio);
+static int audio_dsp_set_rx_iir(struct audio *audio);
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	pr_info("audio_enable()\n");
+
+	if (audio->enabled)
+		return 0;	
+
+	/* refuse to start if we're not ready */
+	if (!audio->out[0].used || !audio->out[1].used)
+		return -EIO;
+
+	/* we start buffers 0 and 1, so buffer 0 will be the
+	 * next one the dsp will want
+	 */
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_HOST_PCM;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	audio_prevent_sleep(audio);	
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0) {
+		audio_allow_sleep(audio);
+		return rc;
+	}
+
+	if (audpp_enable(-1, audio_dsp_event, audio)) {
+		pr_err("audio: audpp_enable() failed\n");
+		audmgr_disable(&audio->audmgr);
+		audio_allow_sleep(audio);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	htc_pwrsink_set(PWRSINK_AUDIO, 100);
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	pr_info("audio_disable()\n");
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio_dsp_out_enable(audio, 0);
+
+		audpp_disable(-1, audio);
+
+		wake_up(&audio->wait);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		audio_allow_sleep(audio);
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+	struct buffer *frame;
+	unsigned long flags;
+
+	LOG(EV_DSP_EVENT, id);
+	switch (id) {
+	case AUDPP_MSG_HOST_PCM_INTF_MSG: {
+		unsigned id = msg[2];
+		unsigned idx = msg[3] - 1;
+
+		/* pr_info("audio_dsp_event: HOST_PCM id %d idx %d\n", id, idx); */
+		if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
+			pr_err("bogus id\n");
+			break;
+		}
+		if (idx > 1) {
+			pr_err("bogus buffer idx\n");
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		if (audio->running) {
+			atomic_add(audio->out[idx].used, &audio->out_bytes);
+			audio->out[idx].used = 0;
+
+			frame = audio->out + audio->out_tail;
+			if (frame->used) {
+				audio_dsp_send_buffer(
+					audio, audio->out_tail, frame->used);
+				audio->out_tail ^= 1;
+			} else {
+				audio->out_needed++;
+			}
+			wake_up(&audio->wait);
+		}
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		break;
+	}
+	case AUDPP_MSG_PCMDMAMISSED:
+		pr_info("audio_dsp_event: PCMDMAMISSED %d\n", msg[0]);
+		break;
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			LOG(EV_ENABLE, 1);
+			pr_info("audio_dsp_event: CFG_MSG ENABLE\n");
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_set_volume_and_pan(5, audio->volume, 0);
+			audio_dsp_set_adrc(audio);
+			audio_dsp_set_eq(audio);
+			audio_dsp_set_rx_iir(audio);
+			audio_dsp_out_enable(audio, 1);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			LOG(EV_ENABLE, 0);
+			pr_info("audio_dsp_event: CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			pr_err("audio_dsp_event: CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	default:
+		pr_err("audio_dsp_event: UNKNOWN (%d)\n", id);
+	}
+}
+
+static int audio_dsp_out_enable(struct audio *audio, int yes)
+{
+	audpp_cmd_pcm_intf cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id	= AUDPP_CMD_PCM_INTF_2; 
+	cmd.object_num	= AUDPP_CMD_PCM_INTF_OBJECT_NUM;
+	cmd.config	= AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
+	cmd.intf_type	= AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+
+	if (yes) {
+		cmd.write_buf1LSW	= audio->out[0].addr;
+		cmd.write_buf1MSW	= audio->out[0].addr >> 16;
+		cmd.write_buf1_len	= audio->out[0].size;
+		cmd.write_buf2LSW	= audio->out[1].addr;
+		cmd.write_buf2MSW	= audio->out[1].addr >> 16;
+		cmd.write_buf2_len	= audio->out[1].size;
+		cmd.arm_to_rx_flag	= AUDPP_CMD_PCM_INTF_ENA_V;
+		cmd.weight_decoder_to_rx = audio->out_weight;
+		cmd.weight_arm_to_rx	= 1;
+		cmd.partition_number_arm_to_dsp = 0;
+		cmd.sample_rate		= audio->out_sample_rate;
+		cmd.channel_mode	= audio->out_channel_mode;
+	}
+	
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static int audio_dsp_send_buffer(struct audio *audio, unsigned idx, unsigned len)
+{
+	audpp_cmd_pcm_intf_send_buffer cmd;
+	
+	cmd.cmd_id		= AUDPP_CMD_PCM_INTF_2;
+	cmd.host_pcm_object	= AUDPP_CMD_PCM_INTF_OBJECT_NUM;
+	cmd.config		= AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
+	cmd.intf_type		= AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+	cmd.dsp_to_arm_buf_id	= 0;
+	cmd.arm_to_dsp_buf_id	= idx + 1;
+	cmd.arm_to_dsp_buf_len	= len;
+
+	LOG(EV_SEND_BUFFER, idx);
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static int audio_dsp_set_adrc(struct audio *audio)
+{
+	audpp_cmd_cfg_object_params_adrc cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_ADRC;
+
+	if (audio->adrc_enable) {
+		cmd.adrc_flag = AUDPP_CMD_ADRC_FLAG_ENA;
+		cmd.compression_th = audio->adrc.compression_th;
+		cmd.compression_slope = audio->adrc.compression_slope;
+		cmd.rms_time = audio->adrc.rms_time;
+		cmd.attack_const_lsw = audio->adrc.attack_const_lsw;
+		cmd.attack_const_msw = audio->adrc.attack_const_msw;
+		cmd.release_const_lsw = audio->adrc.release_const_lsw;
+		cmd.release_const_msw = audio->adrc.release_const_msw;
+		cmd.adrc_system_delay = audio->adrc.adrc_system_delay;
+	} else {
+		cmd.adrc_flag = AUDPP_CMD_ADRC_FLAG_DIS;
+	}
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+
+static int audio_dsp_set_eq(struct audio *audio)
+{
+	audpp_cmd_cfg_object_params_eq cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_EQUALIZER;
+
+	if (audio->eq_enable) {
+		cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
+		cmd.num_bands = audio->eq.num_bands;
+		memcpy(&cmd.eq_params, audio->eq.eq_params,
+		       sizeof(audio->eq.eq_params));
+	} else {
+		cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
+	}
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+
+static int audio_dsp_set_rx_iir(struct audio *audio)
+{
+	audpp_cmd_cfg_object_params_rx_iir cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
+
+	if (audio->rx_iir_enable) {
+		cmd.active_flag = AUDPP_CMD_IIR_FLAG_ENA;
+		cmd.num_bands = audio->iir.num_bands;
+		memcpy(&cmd.iir_params, audio->iir.iir_params,
+		       sizeof(audio->iir.iir_params));
+	} else {
+		cmd.active_flag = AUDPP_CMD_IIR_FLAG_DIS;
+	}
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+
+/* ------------------- device --------------------- */
+
+static int audio_enable_adrc(struct audio *audio, int enable)
+{
+	if (audio->adrc_enable != enable) {
+		audio->adrc_enable = enable;
+		if (audio->running)
+			audio_dsp_set_adrc(audio);
+	}
+	return 0;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable != enable) {
+		audio->eq_enable = enable;
+		if (audio->running)
+			audio_dsp_set_eq(audio);
+	}
+	return 0;
+}
+
+static int audio_enable_rx_iir(struct audio *audio, int enable)
+{
+	if (audio->rx_iir_enable != enable) {
+		audio->rx_iir_enable = enable;
+		if (audio->running)
+			audio_dsp_set_rx_iir(audio);
+	}
+	return 0;
+}
+
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->stopped = 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->out_bytes);
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == AUDIO_SET_VOLUME) {
+		unsigned long flags;
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->volume = arg;
+		if (audio->running)
+			audpp_set_volume_and_pan(6, arg, 0);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+
+	LOG(EV_IOCTL, cmd);
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		rc = audio_enable(audio);
+		break;
+	case AUDIO_STOP:
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		break;
+	case AUDIO_FLUSH:
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the write_lock.
+			 * While audio->stopped write threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->wait);
+			mutex_lock(&audio->write_lock);
+			audio_flush(audio);
+			mutex_unlock(&audio->write_lock);
+		}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count= AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = BUFSZ;
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V) {
+			config.channel_count = 1;
+		} else {
+			config.channel_count = 2;
+		}
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		} else {
+			rc = 0;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static inline int rt_policy(int policy)
+{
+	if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
+		return 1;
+	return 0;
+}
+
+static inline int task_has_rt_policy(struct task_struct *p)
+{
+	return rt_policy(p->policy);
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct sched_param s = { .sched_priority = 1 };
+	struct audio *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int old_prio = current->rt_priority;
+	int old_policy = current->policy;
+	int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
+	int rc = 0;
+
+	LOG(EV_WRITE, count | (audio->running << 28) | (audio->stopped << 24));
+
+	/* just for this write, set us real-time */
+	if (!task_has_rt_policy(current)) {
+		struct cred *new = prepare_creds();
+		cap_raise(new->cap_effective, CAP_SYS_NICE);
+		commit_creds(new);
+		sched_setscheduler(current, SCHED_RR, &s);
+	}
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+
+		LOG(EV_WAIT_EVENT, 0);
+		rc = wait_event_interruptible(audio->wait,
+					      (frame->used == 0) || (audio->stopped));
+		LOG(EV_WAIT_EVENT, 1);
+
+		if (rc < 0)
+			break;
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		xfer = count > frame->size ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		frame->used = xfer;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		LOG(EV_FILL_BUFFER, audio->out_head ^ 1);
+		frame = audio->out + audio->out_tail;
+		if (frame->used && audio->out_needed) {
+			audio_dsp_send_buffer(audio, audio->out_tail, frame->used);
+			audio->out_tail ^= 1;
+			audio->out_needed--;
+		}
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+
+	mutex_unlock(&audio->write_lock);
+
+	/* restore scheduling policy and priority */
+	if (!rt_policy(old_policy)) {
+		struct sched_param v = { .sched_priority = old_prio };
+		sched_setscheduler(current, old_policy, &v);
+		if (likely(!cap_nice)) {
+			struct cred *new = prepare_creds();
+			cap_lower(new->cap_effective, CAP_SYS_NICE);
+			commit_creds(new);
+			sched_setscheduler(current, SCHED_RR, &s);
+		}
+	}
+
+	LOG(EV_RETURN,(buf > start) ? (buf - start) : rc);
+	if (buf > start)
+		return buf - start;
+	return rc;	
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	LOG(EV_OPEN, 0);
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	audio_flush(audio);
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	htc_pwrsink_set(PWRSINK_AUDIO, 0);
+	return 0;
+}
+
+struct audio the_audio;
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &the_audio;
+	int rc;
+
+	mutex_lock(&audio->lock);
+
+	if (audio->opened) {
+		pr_err("audio: busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (!audio->data) {
+		audio->data = dma_alloc_coherent(NULL, DMASZ, 
+						 &audio->phys, GFP_KERNEL);
+		if (!audio->data) {
+			pr_err("audio: could not allocate DMA buffers\n");
+			rc = -ENOMEM;
+			goto done;
+		}
+	}
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto done;
+
+	audio->out_buffer_size = BUFSZ;
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->out_weight = 100;
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+	
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->volume = 0x2000;
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+	LOG(EV_OPEN, 1);
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static long audpp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0, enable;
+	uint16_t enable_mask;
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg, sizeof(enable_mask)))
+			goto out_fault;
+
+		enable = (enable_mask & ADRC_ENABLE)? 1 : 0;
+		audio_enable_adrc(audio, enable);
+		enable = (enable_mask & EQ_ENABLE)? 1 : 0;
+		audio_enable_eq(audio, enable);
+		enable = (enable_mask & IIR_ENABLE)? 1 : 0;
+		audio_enable_rx_iir(audio, enable);
+		break;
+
+	case AUDIO_SET_ADRC:
+		if (copy_from_user(&audio->adrc, (void*) arg, sizeof(audio->adrc)))
+			goto out_fault;
+		break;
+
+	case AUDIO_SET_EQ:
+		if (copy_from_user(&audio->eq, (void*) arg, sizeof(audio->eq)))
+			goto out_fault;
+		break;
+
+	case AUDIO_SET_RX_IIR:
+		if (copy_from_user(&audio->iir, (void*) arg, sizeof(audio->iir)))
+			goto out_fault;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	goto out;
+
+ out_fault:
+	rc = -EFAULT;
+ out:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audpp_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &the_audio;
+
+	file->private_data = audio;
+	return 0;
+}
+
+static struct file_operations audio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+};
+
+static struct file_operations audpp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audpp_open,
+	.unlocked_ioctl	= audpp_ioctl,
+};
+
+struct miscdevice audio_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &audio_fops,
+};
+
+struct miscdevice audpp_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_ctl",
+	.fops	= &audpp_fops,
+};
+
+static int __init audio_init(void)
+{
+	mutex_init(&the_audio.lock);
+	mutex_init(&the_audio.write_lock);
+	spin_lock_init(&the_audio.dsp_lock);
+	init_waitqueue_head(&the_audio.wait);
+	wake_lock_init(&the_audio.wakelock, WAKE_LOCK_SUSPEND, "audio_pcm");
+	wake_lock_init(&the_audio.idlelock, WAKE_LOCK_IDLE, "audio_pcm_idle");
+	return (misc_register(&audio_misc) || misc_register(&audpp_misc));
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
new file mode 100644
index 0000000..9571469
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -0,0 +1,855 @@
+/* arch/arm/mach-msm/qdsp5/audio_qcelp.c
+ *
+ * qcelp 13k audio decoder device
+ *
+ * Copyright (c) 2008 QUALCOMM USA, INC.
+ *
+ * This code is based in part on audio_mp3.c, which is
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <linux/msm_audio.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+
+#include "audmgr.h"
+/* for queue ids - should be relative to module number*/
+#include "adsp.h"
+
+#ifdef DEBUG
+#define dprintk(format, arg...) \
+printk(KERN_DEBUG format, ## arg)
+#else
+#define dprintk(format, arg...) do {} while (0)
+#endif
+
+#define BUFSZ 1080 /* QCELP 13K Hold 600ms packet data = 36 * 30 */
+#define BUF_COUNT 2
+#define DMASZ (BUFSZ * BUF_COUNT)
+
+#define PCM_BUFSZ_MIN 1600 /* 100ms worth of data */
+#define PCM_BUF_MAX_COUNT 5
+
+#define AUDDEC_DEC_QCELP 9
+
+#define	ROUTING_MODE_FTRT	1
+#define	ROUTING_MODE_RT		2
+/* Decoder status received from AUDPPTASK */
+#define	AUDPP_DEC_STATUS_SLEEP	0
+#define	AUDPP_DEC_STATUS_INIT	1
+#define	AUDPP_DEC_STATUS_CFG	2
+#define	AUDPP_DEC_STATUS_PLAY	3
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+struct audio {
+	struct buffer out[BUF_COUNT];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section - START */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;    /* Wait queue for read */
+	char *read_data;        /* pointer to reader buffer */
+	dma_addr_t read_phys;   /* physical address of reader buffer */
+	uint8_t read_next;      /* index to input buffers to be read next */
+	uint8_t fill_next;      /* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;  /* number of pcm buffer allocated */
+	/* Host PCM section - END */
+
+	struct msm_adsp_module *audplay;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	uint8_t opened:1;
+	uint8_t enabled:1;
+	uint8_t running:1;
+	uint8_t stopped:1;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback:1; /* set when non-tunnel mode */
+	uint8_t buf_refresh:1;
+
+	unsigned volume;
+
+	uint16_t dec_id;
+};
+
+static struct audio the_qcelp_audio;
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audqcelp_send_data(struct audio *audio, unsigned needed);
+static void audqcelp_config_hostpcm(struct audio *audio);
+static void audqcelp_buffer_refresh(struct audio *audio);
+static void audqcelp_dsp_event(void *private, unsigned id, uint16_t *msg);
+
+/* must be called with audio->lock held */
+static int audqcelp_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	dprintk("audqcelp_enable()\n");
+
+	if (audio->enabled)
+		return 0;
+
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+	cfg.codec = RPC_AUD_DEF_CODEC_13K;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		pr_err("audio: msm_adsp_enable(audplay) failed\n");
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audqcelp_dsp_event, audio)) {
+		pr_err("audio: audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audqcelp_disable(struct audio *audio)
+{
+	dprintk("audqcelp_disable()\n");
+	if (audio->enabled) {
+		audio->enabled = 0;
+		auddec_dsp_config(audio, 0);
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audqcelp_update_pcm_buf_entry(struct audio *audio,
+	uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+			payload[2 + index * 2]) {
+			dprintk("audqcelp_update_pcm_buf_entry: in[%d] ready\n",
+			audio->fill_next);
+			audio->in[audio->fill_next].used =
+			payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+		} else {
+			pr_err(
+			"audqcelp_update_pcm_buf_entry: expected=%x ret=%x\n",
+			audio->in[audio->fill_next].addr,
+			payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audqcelp_buffer_refresh(audio);
+	} else {
+		dprintk("audqcelp_update_pcm_buf_entry: read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->read_wait);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	dprintk("audplay_dsp_event: msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audqcelp_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audqcelp_update_pcm_buf_entry(audio, msg);
+		break;
+
+	default:
+		pr_err("unexpected message from decoder \n");
+	}
+}
+
+static void audqcelp_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP:
+				dprintk("decoder status: sleep \n");
+				break;
+
+			case AUDPP_DEC_STATUS_INIT:
+				dprintk("decoder status: init \n");
+				audpp_cmd_cfg_routing_mode(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				dprintk("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				dprintk("decoder status: play \n");
+				if (audio->pcm_feedback) {
+					audqcelp_config_hostpcm(audio);
+					audqcelp_buffer_refresh(audio);
+				}
+				break;
+			default:
+				pr_err("unknown decoder status \n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			dprintk("audqcelp_dsp_event: CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_set_volume_and_pan(audio->dec_id, audio->volume,
+						 0);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			dprintk("audqcelp_dsp_event: CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			pr_err("audqcelp_dsp_event: CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		dprintk("audqcelp_dsp_event: ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	default:
+		pr_err("audqcelp_dsp_event: UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_qcelp = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, QDSP_uPAudPlay0BitStreamCtrlQueue, \
+		       cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	audpp_cmd_cfg_dec_type cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+		    AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_QCELP;
+	else
+		cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_v13k cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = 8000;
+	cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	dprintk("audpp_cmd_cfg_routing_mode()\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	audplay_cmd_bitstream_data_avail cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+	cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audqcelp_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+	refresh_cmd.buf_read_count = 0;
+	dprintk("audplay_buffer_fresh: buf0_addr=%x buf0_len=%d\n",
+		refresh_cmd.buf0_address, refresh_cmd.buf0_length);
+
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audqcelp_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	dprintk("audqcelp_config_hostpcm()\n");
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+}
+
+static void audqcelp_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			dprintk("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			dprintk("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audqcelp_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->stopped = 0;
+}
+
+static void audqcelp_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static long audqcelp_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	dprintk("audqcelp_ioctl() cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == AUDIO_SET_VOLUME) {
+		unsigned long flags;
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->volume = arg;
+		if (audio->running)
+			audpp_set_volume_and_pan(audio->dec_id, arg, 0);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+	}
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		rc = audqcelp_enable(audio);
+		break;
+	case AUDIO_STOP:
+		rc = audqcelp_disable(audio);
+		audio->stopped = 1;
+		break;
+	case AUDIO_FLUSH:
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the write_lock.
+			 * While audio->stopped write threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->write_wait);
+			mutex_lock(&audio->write_lock);
+			audqcelp_flush(audio);
+			mutex_unlock(&audio->write_lock);
+			wake_up(&audio->read_wait);
+			mutex_lock(&audio->read_lock);
+			audqcelp_flush_pcm_buf(audio);
+			mutex_unlock(&audio->read_lock);
+			break;
+		}
+		break;
+	case AUDIO_SET_CONFIG:
+		dprintk("AUDIO_SET_CONFIG not applicable \n");
+		break;
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = BUF_COUNT;
+			config.sample_rate = 8000;
+			config.channel_count = 1;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+
+			config.pcm_feedback = 0;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+				sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+
+			if (copy_from_user(&config, (void *)arg,
+				sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+				(config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				dprintk(
+				"audqcelp_ioctl: allocate PCM buf %d\n",
+				config.buffer_count * config.buffer_size);
+				audio->read_data = dma_alloc_coherent(NULL,
+				config.buffer_size * config.buffer_count,
+				&audio->read_phys, GFP_KERNEL);
+				if (!audio->read_data) {
+					pr_err(
+					"audqcelp_ioctl: no mem for pcm buf\n"
+					);
+					rc = -ENOMEM;
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+
+					audio->pcm_feedback = 1;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+						config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					index < config.buffer_count; index++) {
+						audio->in[index].data =
+						audio->read_data + offset;
+						audio->in[index].addr =
+						audio->read_phys + offset;
+						audio->in[index].size =
+						config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		dprintk("%s: AUDIO_PAUSE %ld\n", __func__, arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audqcelp_read(struct file *file, char __user *buf, size_t count,
+			loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	dprintk("audqcelp_read() %d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+				(audio->in[audio->read_next].used > 0) ||
+				(audio->stopped));
+		if (rc < 0)
+			break;
+
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			not know frame size, read count must be greater or equal
+			to size of PCM samples */
+			dprintk("audqcelp_read:read stop - partial frame\n");
+			break;
+		} else {
+			dprintk("audqcelp_read: read from in[%d]\n",
+				audio->read_next);
+			if (copy_to_user(buf,
+				audio->in[audio->read_next].data,
+				audio->in[audio->read_next].used)) {
+				pr_err("audqcelp_read: invalid addr %x \n",
+					(unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+		}
+	}
+
+	if (audio->buf_refresh) {
+		audio->buf_refresh = 0;
+		dprintk("audqcelp_read: kick start pcm feedback again\n");
+		audqcelp_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	dprintk("audqcelp_read: read %d bytes\n", rc);
+	return rc;
+}
+
+static ssize_t audqcelp_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int rc = 0;
+
+	if (count & 1)
+		return -EINVAL;
+	dprintk("audqcelp_write() \n");
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped));
+		dprintk("audqcelp_write() buffer available\n");
+		if (rc < 0)
+			break;
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		xfer = (count > frame->size) ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		frame->used = xfer;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		audqcelp_send_data(audio, 0);
+
+	}
+	mutex_unlock(&audio->write_lock);
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+
+static int audqcelp_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	dprintk("audqcelp_release()\n");
+
+	mutex_lock(&audio->lock);
+	audqcelp_disable(audio);
+	audqcelp_flush(audio);
+	audqcelp_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audio->audplay = NULL;
+	audio->opened = 0;
+	if (audio->data)
+		dma_free_coherent(NULL, DMASZ, audio->data, audio->phys);
+	audio->data = NULL;
+	if (audio->read_data) {
+		dma_free_coherent(NULL,
+				 audio->in[0].size * audio->pcm_buf_count,
+				 audio->read_data, audio->read_phys);
+		audio->read_data = NULL;
+	}
+	audio->pcm_feedback = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static int audqcelp_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &the_qcelp_audio;
+	int rc;
+
+	mutex_lock(&audio->lock);
+
+	if (audio->opened) {
+		pr_err("audio: busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	audio->data = dma_alloc_coherent(NULL, DMASZ,
+					 &audio->phys, GFP_KERNEL);
+	if (!audio->data) {
+		pr_err("audio: could not allocate DMA buffers\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto err;
+
+	rc = msm_adsp_get("AUDPLAY0TASK", &audio->audplay,
+		&audplay_adsp_ops_qcelp, audio);
+	if (rc) {
+		pr_err("audio: failed to get audplay0 dsp module\n");
+		audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	audio->dec_id = 0;
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->volume = 0x2000;	/* Q13 1.0 */
+
+	audqcelp_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+err:
+	dma_free_coherent(NULL, DMASZ, audio->data, audio->phys);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static struct file_operations audio_qcelp_fops = {
+	.owner = THIS_MODULE,
+	.open = audqcelp_open,
+	.release = audqcelp_release,
+	.read = audqcelp_read,
+	.write = audqcelp_write,
+	.unlocked_ioctl = audqcelp_ioctl,
+};
+
+struct miscdevice audio_qcelp_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_qcelp",
+	.fops = &audio_qcelp_fops,
+};
+
+static int __init audqcelp_init(void)
+{
+	mutex_init(&the_qcelp_audio.lock);
+	mutex_init(&the_qcelp_audio.write_lock);
+	mutex_init(&the_qcelp_audio.read_lock);
+	spin_lock_init(&the_qcelp_audio.dsp_lock);
+	init_waitqueue_head(&the_qcelp_audio.write_wait);
+	init_waitqueue_head(&the_qcelp_audio.read_wait);
+	the_qcelp_audio.read_data = NULL;
+	return misc_register(&audio_qcelp_misc);
+}
+
+static void __exit audqcelp_exit(void)
+{
+	misc_deregister(&audio_qcelp_misc);
+}
+
+module_init(audqcelp_init);
+module_exit(audqcelp_exit);
+
+MODULE_DESCRIPTION("MSM QCELP 13K driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("QUALCOMM");
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.c b/arch/arm/mach-msm/qdsp5/audmgr.c
new file mode 100644
index 0000000..b7d8158
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audmgr.c
@@ -0,0 +1,314 @@
+/* arch/arm/mach-msm/qdsp5/audmgr.c
+ *
+ * interface to "audmgr" service on the baseband cpu
+ *
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <asm/atomic.h>
+#include <mach/msm_rpcrouter.h>
+
+#include "audmgr.h"
+
+#define STATE_CLOSED    0
+#define STATE_DISABLED  1
+#define STATE_ENABLING  2
+#define STATE_ENABLED   3
+#define STATE_DISABLING 4
+#define STATE_ERROR	5
+
+static void rpc_ack(struct msm_rpc_endpoint *ept, uint32_t xid)
+{
+	uint32_t rep[6];
+
+	rep[0] = cpu_to_be32(xid);
+	rep[1] = cpu_to_be32(1);
+	rep[2] = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+	rep[3] = cpu_to_be32(RPC_ACCEPTSTAT_SUCCESS);
+	rep[4] = 0;
+	rep[5] = 0;
+
+	msm_rpc_write(ept, rep, sizeof(rep));
+}
+
+static void process_audmgr_callback(struct audmgr *am,
+				   struct rpc_audmgr_cb_func_ptr *args,
+				   int len)
+{
+	if (len < (sizeof(uint32_t) * 3))
+		return;
+	if (be32_to_cpu(args->set_to_one) != 1)
+		return;
+
+	switch (be32_to_cpu(args->status)) {
+	case RPC_AUDMGR_STATUS_READY:
+		if (len < sizeof(uint32_t) * 4)
+			break;
+		am->handle = be32_to_cpu(args->u.handle);
+		pr_info("audmgr: rpc READY handle=0x%08x\n", am->handle);
+		break;
+	case RPC_AUDMGR_STATUS_CODEC_CONFIG: {
+		uint32_t volume;
+		if (len < sizeof(uint32_t) * 4)
+			break;
+		volume = be32_to_cpu(args->u.volume);
+		pr_info("audmgr: rpc CODEC_CONFIG volume=0x%08x\n", volume);
+		am->state = STATE_ENABLED;
+		wake_up(&am->wait);
+		break;
+	}
+	case RPC_AUDMGR_STATUS_PENDING:
+		pr_err("audmgr: PENDING?\n");
+		break;
+	case RPC_AUDMGR_STATUS_SUSPEND:
+		pr_err("audmgr: SUSPEND?\n");
+		break;
+	case RPC_AUDMGR_STATUS_FAILURE:
+		pr_err("audmgr: FAILURE\n");
+		break;
+	case RPC_AUDMGR_STATUS_VOLUME_CHANGE:
+		pr_err("audmgr: VOLUME_CHANGE?\n");
+		break;
+	case RPC_AUDMGR_STATUS_DISABLED:
+		pr_err("audmgr: DISABLED\n");
+		am->state = STATE_DISABLED;
+		wake_up(&am->wait);
+		break;
+	case RPC_AUDMGR_STATUS_ERROR:
+		pr_err("audmgr: ERROR?\n");
+		am->state = STATE_ERROR;
+		wake_up(&am->wait);
+		break;
+	default:
+		break;
+	}
+}
+
+static void process_rpc_request(uint32_t proc, uint32_t xid,
+				void *data, int len, void *private)
+{
+	struct audmgr *am = private;
+	uint32_t *x = data;
+
+	if (0) {
+		int n = len / 4;
+		pr_info("rpc_call proc %d:", proc);
+		while (n--)
+			printk(" %08x", be32_to_cpu(*x++));
+		printk("\n");
+	}
+
+	if (proc == AUDMGR_CB_FUNC_PTR)
+		process_audmgr_callback(am, data, len);
+	else
+		pr_err("audmgr: unknown rpc proc %d\n", proc);
+	rpc_ack(am->ept, xid);
+}
+
+#define RPC_TYPE_REQUEST 0
+#define RPC_TYPE_REPLY 1
+
+#define RPC_VERSION 2
+
+#define RPC_COMMON_HDR_SZ  (sizeof(uint32_t) * 2)
+#define RPC_REQUEST_HDR_SZ (sizeof(struct rpc_request_hdr))
+#define RPC_REPLY_HDR_SZ   (sizeof(uint32_t) * 3)
+#define RPC_REPLY_SZ       (sizeof(uint32_t) * 6)
+
+static int audmgr_rpc_thread(void *data)
+{
+	struct audmgr *am = data;
+	struct rpc_request_hdr *hdr = NULL;
+	uint32_t type;
+	int len;
+
+	pr_info("audmgr_rpc_thread() start\n");
+
+	while (!kthread_should_stop()) {
+		if (hdr) {
+			kfree(hdr);
+			hdr = NULL;
+		}
+		len = msm_rpc_read(am->ept, (void **) &hdr, -1, -1);
+		if (len < 0) {
+			pr_err("audmgr: rpc read failed (%d)\n", len);
+			break;
+		}
+		if (len < RPC_COMMON_HDR_SZ)
+			continue;
+
+		type = be32_to_cpu(hdr->type);
+		if (type == RPC_TYPE_REPLY) {
+			struct rpc_reply_hdr *rep = (void *) hdr;
+			uint32_t status;
+			if (len < RPC_REPLY_HDR_SZ)
+				continue;
+			status = be32_to_cpu(rep->reply_stat);
+			if (status == RPCMSG_REPLYSTAT_ACCEPTED) {
+				status = be32_to_cpu(rep->data.acc_hdr.accept_stat);
+				pr_info("audmgr: rpc_reply status %d\n", status);
+			} else {
+				pr_info("audmgr: rpc_reply denied!\n");
+			}
+			/* process reply */
+			continue;
+		}
+
+		if (len < RPC_REQUEST_HDR_SZ)
+			continue;
+
+		process_rpc_request(be32_to_cpu(hdr->procedure),
+				    be32_to_cpu(hdr->xid),
+				    (void *) (hdr + 1),
+				    len - sizeof(*hdr),
+				    data);
+	}
+	pr_info("audmgr_rpc_thread() exit\n");
+	if (hdr) {
+		kfree(hdr);
+		hdr = NULL;
+	}
+	am->task = NULL;
+	wake_up(&am->wait);
+	return 0;
+}
+
+struct audmgr_enable_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_audmgr_enable_client_args args;
+};
+
+struct audmgr_disable_msg {
+	struct rpc_request_hdr hdr;
+	uint32_t handle;
+};
+
+int audmgr_open(struct audmgr *am)
+{
+	int rc;
+
+	if (am->state != STATE_CLOSED)
+		return 0;
+
+	am->ept = msm_rpc_connect(AUDMGR_PROG,
+				AUDMGR_VERS,
+				MSM_RPC_UNINTERRUPTIBLE | MSM_RPC_ENABLE_RECEIVE);
+
+	init_waitqueue_head(&am->wait);
+
+	if (IS_ERR(am->ept)) {
+		rc = PTR_ERR(am->ept);
+		am->ept = NULL;
+		pr_err("audmgr: failed to connect to audmgr svc\n");
+		return rc;
+	}
+
+	am->task = kthread_run(audmgr_rpc_thread, am, "audmgr_rpc");
+	if (IS_ERR(am->task)) {
+		rc = PTR_ERR(am->task);
+		am->task = NULL;
+		msm_rpc_close(am->ept);
+		am->ept = NULL;
+		return rc;
+	}
+
+	am->state = STATE_DISABLED;
+	return 0;
+}
+EXPORT_SYMBOL(audmgr_open);
+
+int audmgr_close(struct audmgr *am)
+{
+	return -EBUSY;
+}
+EXPORT_SYMBOL(audmgr_close);
+
+int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg)
+{
+	struct audmgr_enable_msg msg;
+	int rc;
+
+	if (am->state == STATE_ENABLED)
+		return 0;
+
+	if (am->state == STATE_DISABLING)
+		pr_err("audmgr: state is DISABLING in enable?\n");
+	am->state = STATE_ENABLING;
+
+	msg.args.set_to_one = cpu_to_be32(1);
+	msg.args.tx_sample_rate = cpu_to_be32(cfg->tx_rate);
+	msg.args.rx_sample_rate = cpu_to_be32(cfg->rx_rate);
+	msg.args.def_method = cpu_to_be32(cfg->def_method);
+	msg.args.codec_type = cpu_to_be32(cfg->codec);
+	msg.args.snd_method = cpu_to_be32(cfg->snd_method);
+	msg.args.cb_func = cpu_to_be32(0x11111111);
+	msg.args.client_data = cpu_to_be32(0x11223344);
+
+	msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, msm_rpc_get_vers(am->ept),
+			  AUDMGR_ENABLE_CLIENT);
+
+	rc = msm_rpc_write(am->ept, &msg, sizeof(msg));
+	if (rc < 0)
+		return rc;
+
+	rc = wait_event_timeout(am->wait, am->state != STATE_ENABLING, 15 * HZ);
+	if (rc == 0) {
+		pr_err("audmgr_enable: ARM9 did not reply to RPC am->state = %d\n", am->state);
+		BUG();
+	}
+	if (am->state == STATE_ENABLED)
+		return 0;
+
+	pr_err("audmgr: unexpected state %d while enabling?!\n", am->state);
+	return -ENODEV;
+}
+EXPORT_SYMBOL(audmgr_enable);
+
+int audmgr_disable(struct audmgr *am)
+{
+	struct audmgr_disable_msg msg;
+	int rc;
+
+	if (am->state == STATE_DISABLED)
+		return 0;
+
+	msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, msm_rpc_get_vers(am->ept),
+			  AUDMGR_DISABLE_CLIENT);
+	msg.handle = cpu_to_be32(am->handle);
+
+	am->state = STATE_DISABLING;
+
+	rc = msm_rpc_write(am->ept, &msg, sizeof(msg));
+	if (rc < 0)
+		return rc;
+
+	rc = wait_event_timeout(am->wait, am->state != STATE_DISABLING, 15 * HZ);
+	if (rc == 0) {
+		pr_err("audmgr_disable: ARM9 did not reply to RPC am->state = %d\n", am->state);
+		BUG();
+	}
+
+	if (am->state == STATE_DISABLED)
+		return 0;
+
+	pr_err("audmgr: unexpected state %d while disabling?!\n", am->state);
+	return -ENODEV;
+}
+EXPORT_SYMBOL(audmgr_disable);
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.h b/arch/arm/mach-msm/qdsp5/audmgr.h
new file mode 100644
index 0000000..cd2d0c6
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audmgr.h
@@ -0,0 +1,215 @@
+/* arch/arm/mach-msm/qdsp5/audmgr.h
+ *
+ * Copyright 2008 (c) QUALCOMM Incorporated. 
+ * 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.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_AUDMGR_H
+#define _ARCH_ARM_MACH_MSM_AUDMGR_H
+
+#if CONFIG_MSM_AMSS_VERSION==6350
+#include "audmgr_new.h"
+#else
+
+enum rpc_aud_def_sample_rate_type {
+	RPC_AUD_DEF_SAMPLE_RATE_NONE,
+	RPC_AUD_DEF_SAMPLE_RATE_8000,
+	RPC_AUD_DEF_SAMPLE_RATE_11025,
+	RPC_AUD_DEF_SAMPLE_RATE_12000,
+	RPC_AUD_DEF_SAMPLE_RATE_16000,
+	RPC_AUD_DEF_SAMPLE_RATE_22050,
+	RPC_AUD_DEF_SAMPLE_RATE_24000,
+	RPC_AUD_DEF_SAMPLE_RATE_32000,
+	RPC_AUD_DEF_SAMPLE_RATE_44100,
+	RPC_AUD_DEF_SAMPLE_RATE_48000,
+	RPC_AUD_DEF_SAMPLE_RATE_MAX,
+};
+
+enum rpc_aud_def_method_type {
+	RPC_AUD_DEF_METHOD_NONE,
+	RPC_AUD_DEF_METHOD_KEY_BEEP,
+	RPC_AUD_DEF_METHOD_PLAYBACK,
+	RPC_AUD_DEF_METHOD_VOICE,
+	RPC_AUD_DEF_METHOD_RECORD,
+	RPC_AUD_DEF_METHOD_HOST_PCM,
+	RPC_AUD_DEF_METHOD_MIDI_OUT,
+	RPC_AUD_DEF_METHOD_RECORD_SBC,
+	RPC_AUD_DEF_METHOD_DTMF_RINGER,
+	RPC_AUD_DEF_METHOD_MAX,
+};
+
+enum rpc_aud_def_codec_type {
+	RPC_AUD_DEF_CODEC_NONE,
+	RPC_AUD_DEF_CODEC_DTMF,
+	RPC_AUD_DEF_CODEC_MIDI,
+	RPC_AUD_DEF_CODEC_MP3,
+	RPC_AUD_DEF_CODEC_PCM,
+	RPC_AUD_DEF_CODEC_AAC,
+	RPC_AUD_DEF_CODEC_WMA,
+	RPC_AUD_DEF_CODEC_RA,
+	RPC_AUD_DEF_CODEC_ADPCM,
+	RPC_AUD_DEF_CODEC_GAUDIO,
+	RPC_AUD_DEF_CODEC_VOC_EVRC,
+	RPC_AUD_DEF_CODEC_VOC_13K,
+	RPC_AUD_DEF_CODEC_VOC_4GV_NB,
+	RPC_AUD_DEF_CODEC_VOC_AMR,
+	RPC_AUD_DEF_CODEC_VOC_EFR,
+	RPC_AUD_DEF_CODEC_VOC_FR,
+	RPC_AUD_DEF_CODEC_VOC_HR,
+	RPC_AUD_DEF_CODEC_VOC,
+	RPC_AUD_DEF_CODEC_SBC,
+	RPC_AUD_DEF_CODEC_VOC_PCM,
+	RPC_AUD_DEF_CODEC_AMR_WB,
+	RPC_AUD_DEF_CODEC_AMR_WB_PLUS,
+	RPC_AUD_DEF_CODEC_MAX,
+};
+
+enum rpc_snd_method_type {
+	RPC_SND_METHOD_VOICE = 0,
+	RPC_SND_METHOD_KEY_BEEP,
+	RPC_SND_METHOD_MESSAGE,
+	RPC_SND_METHOD_RING,
+	RPC_SND_METHOD_MIDI,
+	RPC_SND_METHOD_AUX,
+	RPC_SND_METHOD_MAX,
+};
+
+enum rpc_voc_codec_type {
+	RPC_VOC_CODEC_DEFAULT,
+	RPC_VOC_CODEC_ON_CHIP_0 = RPC_VOC_CODEC_DEFAULT,
+	RPC_VOC_CODEC_ON_CHIP_1,
+	RPC_VOC_CODEC_STEREO_HEADSET,
+	RPC_VOC_CODEC_ON_CHIP_AUX,
+	RPC_VOC_CODEC_BT_OFF_BOARD,
+	RPC_VOC_CODEC_BT_A2DP,
+	RPC_VOC_CODEC_OFF_BOARD,
+	RPC_VOC_CODEC_SDAC,
+	RPC_VOC_CODEC_RX_EXT_SDAC_TX_INTERNAL,
+	RPC_VOC_CODEC_IN_STEREO_SADC_OUT_MONO_HANDSET,
+	RPC_VOC_CODEC_IN_STEREO_SADC_OUT_STEREO_HEADSET,
+	RPC_VOC_CODEC_TX_INT_SADC_RX_EXT_AUXPCM,
+	RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_MONO_HANDSET,
+	RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_STEREO_HEADSET,
+	RPC_VOC_CODEC_TTY_ON_CHIP_1,
+	RPC_VOC_CODEC_TTY_OFF_BOARD,
+	RPC_VOC_CODEC_TTY_VCO,
+	RPC_VOC_CODEC_TTY_HCO,
+	RPC_VOC_CODEC_ON_CHIP_0_DUAL_MIC,
+	RPC_VOC_CODEC_MAX,
+	RPC_VOC_CODEC_NONE,
+};
+
+enum rpc_audmgr_status_type {
+	RPC_AUDMGR_STATUS_READY,
+	RPC_AUDMGR_STATUS_CODEC_CONFIG,
+	RPC_AUDMGR_STATUS_PENDING,
+	RPC_AUDMGR_STATUS_SUSPEND,
+	RPC_AUDMGR_STATUS_FAILURE,
+	RPC_AUDMGR_STATUS_VOLUME_CHANGE,
+	RPC_AUDMGR_STATUS_DISABLED,
+	RPC_AUDMGR_STATUS_ERROR,
+};
+
+struct rpc_audmgr_enable_client_args {
+	uint32_t set_to_one;
+	uint32_t tx_sample_rate;
+	uint32_t rx_sample_rate;
+	uint32_t def_method;
+	uint32_t codec_type;
+	uint32_t snd_method;
+
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+	
+#define AUDMGR_ENABLE_CLIENT			2
+#define AUDMGR_DISABLE_CLIENT			3
+#define AUDMGR_SUSPEND_EVENT_RSP		4
+#define AUDMGR_REGISTER_OPERATION_LISTENER	5
+#define AUDMGR_UNREGISTER_OPERATION_LISTENER	6
+#define AUDMGR_REGISTER_CODEC_LISTENER		7
+#define AUDMGR_GET_RX_SAMPLE_RATE		8
+#define AUDMGR_GET_TX_SAMPLE_RATE		9
+#define AUDMGR_SET_DEVICE_MODE			10
+
+#if CONFIG_MSM_AMSS_VERSION < 6220
+#define AUDMGR_PROG_VERS "rs30000013:46255756"
+#define AUDMGR_PROG 0x30000013
+#define AUDMGR_VERS 0x46255756
+#else
+#define AUDMGR_PROG_VERS "rs30000013:e94e8f0c"
+#define AUDMGR_PROG 0x30000013
+#define AUDMGR_VERS 0xe94e8f0c
+#endif
+
+struct rpc_audmgr_cb_func_ptr {
+	uint32_t cb_id;
+	uint32_t set_to_one;
+	uint32_t status;
+	union {
+		uint32_t handle;
+		uint32_t volume;
+		
+	} u;
+};
+
+#define AUDMGR_CB_FUNC_PTR			1
+#define AUDMGR_OPR_LSTNR_CB_FUNC_PTR		2
+#define AUDMGR_CODEC_LSTR_FUNC_PTR		3
+
+#if CONFIG_MSM_AMSS_VERSION < 6220
+#define AUDMGR_CB_PROG 0x31000013
+#define AUDMGR_CB_VERS 0x5fa922a9
+#else
+#define AUDMGR_CB_PROG 0x31000013
+#define AUDMGR_CB_VERS 0x21570ba7
+#endif
+
+struct audmgr {
+	wait_queue_head_t wait;
+	uint32_t handle;
+	struct msm_rpc_endpoint *ept;
+	struct task_struct *task;
+	int state;
+};
+
+struct audmgr_config {
+	uint32_t tx_rate;
+	uint32_t rx_rate;
+	uint32_t def_method;
+	uint32_t codec;
+	uint32_t snd_method;
+};
+
+int audmgr_open(struct audmgr *am);
+int audmgr_close(struct audmgr *am);
+int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg);
+int audmgr_disable(struct audmgr *am);
+
+typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
+
+int audpp_enable(int id, audpp_event_func func, void *private);
+void audpp_disable(int id, void *private);
+
+int audpp_send_queue1(void *cmd, unsigned len);
+int audpp_send_queue2(void *cmd, unsigned len);
+int audpp_send_queue3(void *cmd, unsigned len);
+
+int audpp_pause(unsigned id, int pause);
+int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan);
+void audpp_avsync(int id, unsigned rate);
+unsigned audpp_avsync_sample_count(int id);
+unsigned audpp_avsync_byte_count(int id);
+
+#endif
+#endif
diff --git a/arch/arm/mach-msm/qdsp5/audmgr_new.h b/arch/arm/mach-msm/qdsp5/audmgr_new.h
new file mode 100644
index 0000000..4381242
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audmgr_new.h
@@ -0,0 +1,213 @@
+/* arch/arm/mach-msm/qdsp5/audmgr.h
+ *
+ * Copyright 2008 (c) QUALCOMM Incorporated. 
+ * 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.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_AUDMGR_NEW_H
+#define _ARCH_ARM_MACH_MSM_AUDMGR_NEW_H
+
+enum rpc_aud_def_sample_rate_type {
+	RPC_AUD_DEF_SAMPLE_RATE_NONE,
+	RPC_AUD_DEF_SAMPLE_RATE_8000,
+	RPC_AUD_DEF_SAMPLE_RATE_11025,
+	RPC_AUD_DEF_SAMPLE_RATE_12000,
+	RPC_AUD_DEF_SAMPLE_RATE_16000,
+	RPC_AUD_DEF_SAMPLE_RATE_22050,
+	RPC_AUD_DEF_SAMPLE_RATE_24000,
+	RPC_AUD_DEF_SAMPLE_RATE_32000,
+	RPC_AUD_DEF_SAMPLE_RATE_44100,
+	RPC_AUD_DEF_SAMPLE_RATE_48000,
+	RPC_AUD_DEF_SAMPLE_RATE_MAX,
+};
+
+enum rpc_aud_def_method_type {
+	RPC_AUD_DEF_METHOD_NONE,
+	RPC_AUD_DEF_METHOD_KEY_BEEP,
+	RPC_AUD_DEF_METHOD_PLAYBACK,
+	RPC_AUD_DEF_METHOD_VOICE,
+	RPC_AUD_DEF_METHOD_RECORD,
+	RPC_AUD_DEF_METHOD_HOST_PCM,
+	RPC_AUD_DEF_METHOD_MIDI_OUT,
+	RPC_AUD_DEF_METHOD_RECORD_SBC,
+	RPC_AUD_DEF_METHOD_DTMF_RINGER,
+	RPC_AUD_DEF_METHOD_MAX,
+};
+
+enum rpc_aud_def_codec_type {
+	RPC_AUD_DEF_CODEC_NONE,
+	RPC_AUD_DEF_CODEC_DTMF,
+	RPC_AUD_DEF_CODEC_MIDI,
+	RPC_AUD_DEF_CODEC_MP3,
+	RPC_AUD_DEF_CODEC_PCM,
+	RPC_AUD_DEF_CODEC_AAC,
+	RPC_AUD_DEF_CODEC_WMA,
+	RPC_AUD_DEF_CODEC_RA,
+	RPC_AUD_DEF_CODEC_ADPCM,
+	RPC_AUD_DEF_CODEC_GAUDIO,
+	RPC_AUD_DEF_CODEC_VOC_EVRC,
+	RPC_AUD_DEF_CODEC_VOC_13K,
+	RPC_AUD_DEF_CODEC_VOC_4GV_NB,
+	RPC_AUD_DEF_CODEC_VOC_AMR,
+	RPC_AUD_DEF_CODEC_VOC_EFR,
+	RPC_AUD_DEF_CODEC_VOC_FR,
+	RPC_AUD_DEF_CODEC_VOC_HR,
+	RPC_AUD_DEF_CODEC_VOC_CDMA,
+	RPC_AUD_DEF_CODEC_VOC_CDMA_WB,
+	RPC_AUD_DEF_CODEC_VOC_UMTS,
+	RPC_AUD_DEF_CODEC_VOC_UMTS_WB,
+	RPC_AUD_DEF_CODEC_SBC,
+	RPC_AUD_DEF_CODEC_VOC_PCM,
+	RPC_AUD_DEF_CODEC_AMR_WB,
+	RPC_AUD_DEF_CODEC_AMR_WB_PLUS,
+	RPC_AUD_DEF_CODEC_AAC_BSAC,
+	RPC_AUD_DEF_CODEC_MAX,
+	RPC_AUD_DEF_CODEC_AMR_NB,
+	RPC_AUD_DEF_CODEC_13K,
+	RPC_AUD_DEF_CODEC_EVRC,
+	RPC_AUD_DEF_CODEC_MAX_002,
+};
+
+enum rpc_snd_method_type {
+	RPC_SND_METHOD_VOICE = 0,
+	RPC_SND_METHOD_KEY_BEEP,
+	RPC_SND_METHOD_MESSAGE,
+	RPC_SND_METHOD_RING,
+	RPC_SND_METHOD_MIDI,
+	RPC_SND_METHOD_AUX,
+	RPC_SND_METHOD_MAX,
+};
+
+enum rpc_voc_codec_type {
+	RPC_VOC_CODEC_DEFAULT,
+	RPC_VOC_CODEC_ON_CHIP_0 = RPC_VOC_CODEC_DEFAULT,
+	RPC_VOC_CODEC_ON_CHIP_1,
+	RPC_VOC_CODEC_STEREO_HEADSET,
+	RPC_VOC_CODEC_ON_CHIP_AUX,
+	RPC_VOC_CODEC_BT_OFF_BOARD,
+	RPC_VOC_CODEC_BT_A2DP,
+	RPC_VOC_CODEC_OFF_BOARD,
+	RPC_VOC_CODEC_SDAC,
+	RPC_VOC_CODEC_RX_EXT_SDAC_TX_INTERNAL,
+	RPC_VOC_CODEC_IN_STEREO_SADC_OUT_MONO_HANDSET,
+	RPC_VOC_CODEC_IN_STEREO_SADC_OUT_STEREO_HEADSET,
+	RPC_VOC_CODEC_TX_INT_SADC_RX_EXT_AUXPCM,
+	RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_MONO_HANDSET,
+	RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_STEREO_HEADSET,
+	RPC_VOC_CODEC_TTY_ON_CHIP_1,
+	RPC_VOC_CODEC_TTY_OFF_BOARD,
+	RPC_VOC_CODEC_TTY_VCO,
+	RPC_VOC_CODEC_TTY_HCO,
+	RPC_VOC_CODEC_ON_CHIP_0_DUAL_MIC,
+	RPC_VOC_CODEC_MAX,
+	RPC_VOC_CODEC_NONE,
+};
+
+enum rpc_audmgr_status_type {
+	RPC_AUDMGR_STATUS_READY,
+	RPC_AUDMGR_STATUS_CODEC_CONFIG,
+	RPC_AUDMGR_STATUS_PENDING,
+	RPC_AUDMGR_STATUS_SUSPEND,
+	RPC_AUDMGR_STATUS_FAILURE,
+	RPC_AUDMGR_STATUS_VOLUME_CHANGE,
+	RPC_AUDMGR_STATUS_DISABLED,
+	RPC_AUDMGR_STATUS_ERROR,
+};
+
+struct rpc_audmgr_enable_client_args {
+	uint32_t set_to_one;
+	uint32_t tx_sample_rate;
+	uint32_t rx_sample_rate;
+	uint32_t def_method;
+	uint32_t codec_type;
+	uint32_t snd_method;
+
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+	
+#define AUDMGR_ENABLE_CLIENT			2
+#define AUDMGR_DISABLE_CLIENT			3
+#define AUDMGR_SUSPEND_EVENT_RSP		4
+#define AUDMGR_REGISTER_OPERATION_LISTENER	5
+#define AUDMGR_UNREGISTER_OPERATION_LISTENER	6
+#define AUDMGR_REGISTER_CODEC_LISTENER		7
+#define AUDMGR_GET_RX_SAMPLE_RATE		8
+#define AUDMGR_GET_TX_SAMPLE_RATE		9
+#define AUDMGR_SET_DEVICE_MODE			10
+
+#define AUDMGR_PROG 0x30000013
+#define AUDMGR_VERS MSM_RPC_VERS(1,0)
+
+struct rpc_audmgr_cb_func_ptr {
+	uint32_t cb_id;
+	uint32_t status; /* Audmgr status */
+	uint32_t set_to_one;  /* Pointer status (1 = valid, 0  = invalid) */
+	uint32_t disc;
+	/* disc = AUDMGR_STATUS_READY => data=handle
+	   disc = AUDMGR_STATUS_CODEC_CONFIG => data = handle
+	   disc = AUDMGR_STATUS_DISABLED => data =status_disabled
+	   disc = AUDMGR_STATUS_VOLUME_CHANGE => data = volume-change */
+	union {
+		uint32_t handle;
+		uint32_t volume;
+		uint32_t status_disabled;
+		uint32_t volume_change;
+	} u;
+};
+
+#define AUDMGR_CB_FUNC_PTR			1
+#define AUDMGR_OPR_LSTNR_CB_FUNC_PTR		2
+#define AUDMGR_CODEC_LSTR_FUNC_PTR		3
+
+#define AUDMGR_CB_PROG 0x31000013
+#define AUDMGR_CB_VERS 0xf8e3e2d9
+
+struct audmgr {
+	wait_queue_head_t wait;
+	uint32_t handle;
+	struct msm_rpc_endpoint *ept;
+	struct task_struct *task;
+	int state;
+};
+
+struct audmgr_config {
+	uint32_t tx_rate;
+	uint32_t rx_rate;
+	uint32_t def_method;
+	uint32_t codec;
+	uint32_t snd_method;
+};
+
+int audmgr_open(struct audmgr *am);
+int audmgr_close(struct audmgr *am);
+int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg);
+int audmgr_disable(struct audmgr *am);
+
+typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
+
+int audpp_enable(int id, audpp_event_func func, void *private);
+void audpp_disable(int id, void *private);
+
+int audpp_send_queue1(void *cmd, unsigned len);
+int audpp_send_queue2(void *cmd, unsigned len);
+int audpp_send_queue3(void *cmd, unsigned len);
+
+int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan);
+int audpp_pause(unsigned id, int pause);
+int audpp_flush(unsigned id);
+void audpp_avsync(int id, unsigned rate);
+unsigned audpp_avsync_sample_count(int id);
+unsigned audpp_avsync_byte_count(int id);
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5/audpp.c b/arch/arm/mach-msm/qdsp5/audpp.c
new file mode 100644
index 0000000..32c2847
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audpp.c
@@ -0,0 +1,429 @@
+
+/* arch/arm/mach-msm/qdsp5/audpp.c
+ *
+ * common code to deal with the AUDPP dsp task (audio postproc)
+ *
+ * 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/module.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+
+/* for queue ids - should be relative to module number*/
+#include "adsp.h"
+
+#include "evlog.h"
+
+
+enum {
+	EV_NULL,
+	EV_ENABLE,
+	EV_DISABLE,
+	EV_EVENT,
+	EV_DATA,
+};
+
+static const char *dsp_log_strings[] = {
+	"NULL",
+	"ENABLE",
+	"DISABLE",
+	"EVENT",
+	"DATA",
+};
+
+DECLARE_LOG(dsp_log, 64, dsp_log_strings);
+
+static int __init _dsp_log_init(void)
+{
+	return ev_log_init(&dsp_log);
+}
+module_init(_dsp_log_init);
+#define LOG(id,arg) ev_log_write(&dsp_log, id, arg)
+
+static DEFINE_MUTEX(audpp_lock);
+
+#define CH_COUNT 5
+#define AUDPP_CLNT_MAX_COUNT 6
+#define AUDPP_AVSYNC_INFO_SIZE 7
+
+struct audpp_state {
+	struct msm_adsp_module *mod;
+	audpp_event_func func[AUDPP_CLNT_MAX_COUNT];
+	void *private[AUDPP_CLNT_MAX_COUNT];
+	struct mutex *lock;
+	unsigned open_count;
+	unsigned enabled;
+
+	/* which channels are actually enabled */
+	unsigned avsync_mask;
+
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
+};
+
+struct audpp_state the_audpp_state = {
+	.lock = &audpp_lock,
+};
+
+int audpp_send_queue1(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpp_state.mod,
+			      QDSP_uPAudPPCmd1Queue, cmd, len);
+}
+EXPORT_SYMBOL(audpp_send_queue1);
+
+int audpp_send_queue2(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpp_state.mod,
+			      QDSP_uPAudPPCmd2Queue, cmd, len);
+}
+EXPORT_SYMBOL(audpp_send_queue2);
+
+int audpp_send_queue3(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpp_state.mod,
+			      QDSP_uPAudPPCmd3Queue, cmd, len);
+}
+EXPORT_SYMBOL(audpp_send_queue3);
+
+static int audpp_dsp_config(int enable)
+{
+	audpp_cmd_cfg cmd;
+
+	cmd.cmd_id = AUDPP_CMD_CFG;
+	cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP;
+
+	return audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audpp_broadcast(struct audpp_state *audpp, unsigned id,
+			    uint16_t *msg)
+{
+	unsigned n;
+	for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) {
+		if (audpp->func[n])
+			audpp->func[n] (audpp->private[n], id, msg);
+	}
+}
+
+static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id,
+			      unsigned id, uint16_t *msg)
+{
+	if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id])
+		audpp->func[clnt_id] (audpp->private[clnt_id], id, msg);
+}
+
+static void audpp_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audpp_state *audpp = data;
+	uint16_t msg[8];
+
+	if (id == AUDPP_MSG_AVSYNC_MSG) {
+		getevent(audpp->avsync, sizeof(audpp->avsync));
+
+		/* mask off any channels we're not watching to avoid
+		 * cases where we might get one last update after
+		 * disabling avsync and end up in an odd state when
+		 * we next read...
+		 */
+		audpp->avsync[0] &= audpp->avsync_mask;
+		return;
+	}
+
+	getevent(msg, sizeof(msg));
+
+	LOG(EV_EVENT, (id << 16) | msg[0]);
+	LOG(EV_DATA, (msg[1] << 16) | msg[2]);
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned cid = msg[0];
+			pr_info("audpp: status %d %d %d\n", cid, msg[1],
+				msg[2]);
+			if ((cid < 5) && audpp->func[cid])
+				audpp->func[cid] (audpp->private[cid], id, msg);
+			break;
+		}
+	case AUDPP_MSG_HOST_PCM_INTF_MSG:
+		if (audpp->func[5])
+			audpp->func[5] (audpp->private[5], id, msg);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		pr_err("audpp: DMA missed obj=%x\n", msg[0]);
+		break;
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			pr_info("audpp: ENABLE\n");
+			audpp->enabled = 1;
+			audpp_broadcast(audpp, id, msg);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			pr_info("audpp: DISABLE\n");
+			audpp->enabled = 0;
+			audpp_broadcast(audpp, id, msg);
+		} else {
+			pr_err("audpp: invalid config msg %d\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		audpp_broadcast(audpp, id, msg);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		audpp_notify_clnt(audpp, msg[0], id, msg);
+		break;
+	default:
+	  pr_info("audpp: unhandled msg id %x\n", id);
+	}
+}
+
+static struct msm_adsp_ops adsp_ops = {
+	.event = audpp_dsp_event,
+};
+
+static void audpp_fake_event(struct audpp_state *audpp, int id,
+			     unsigned event, unsigned arg)
+{
+	uint16_t msg[1];
+	msg[0] = arg;
+	audpp->func[id] (audpp->private[id], event, msg);
+}
+
+int audpp_enable(int id, audpp_event_func func, void *private)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int res = 0;
+
+	if (id < -1 || id > 4)
+		return -EINVAL;
+
+	if (id == -1)
+		id = 5;
+
+	mutex_lock(audpp->lock);
+	if (audpp->func[id]) {
+		res = -EBUSY;
+		goto out;
+	}
+
+	audpp->func[id] = func;
+	audpp->private[id] = private;
+
+	LOG(EV_ENABLE, 1);
+	if (audpp->open_count++ == 0) {
+		pr_info("audpp: enable\n");
+		res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
+		if (res < 0) {
+			pr_err("audpp: cannot open AUDPPTASK\n");
+			audpp->open_count = 0;
+			audpp->func[id] = NULL;
+			audpp->private[id] = NULL;
+			goto out;
+		}
+		LOG(EV_ENABLE, 2);
+		msm_adsp_enable(audpp->mod);
+		audpp_dsp_config(1);
+	} else {
+		unsigned long flags;
+		local_irq_save(flags);
+		if (audpp->enabled)
+			audpp_fake_event(audpp, id,
+					 AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA);
+		local_irq_restore(flags);
+	}
+			
+	res = 0;
+out:
+	mutex_unlock(audpp->lock);
+	return res;
+}
+EXPORT_SYMBOL(audpp_enable);
+
+void audpp_disable(int id, void *private)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	unsigned long flags;
+
+	if (id < -1 || id > 4)
+		return;
+
+	if (id == -1)
+		id = 5;
+
+	mutex_lock(audpp->lock);
+	LOG(EV_DISABLE, 1);
+	if (!audpp->func[id])
+		goto out;
+	if (audpp->private[id] != private)
+		goto out;
+
+	local_irq_save(flags);
+	audpp_fake_event(audpp, id, AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_DIS);
+	audpp->func[id] = NULL;
+	audpp->private[id] = NULL;
+	local_irq_restore(flags);
+
+	if (--audpp->open_count == 0) {
+		pr_info("audpp: disable\n");
+		LOG(EV_DISABLE, 2);
+		audpp_dsp_config(0);
+		msm_adsp_disable(audpp->mod);
+		msm_adsp_put(audpp->mod);
+		audpp->mod = NULL;
+	}
+out:
+	mutex_unlock(audpp->lock);
+}
+EXPORT_SYMBOL(audpp_disable);
+
+#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
+
+void audpp_avsync(int id, unsigned rate)
+{
+	unsigned long flags;
+	audpp_cmd_avsync cmd;
+
+	if (BAD_ID(id))
+		return;
+
+	local_irq_save(flags);
+	if (rate)
+		the_audpp_state.avsync_mask |= (1 << id);
+	else
+		the_audpp_state.avsync_mask &= (~(1 << id));
+	the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
+	local_irq_restore(flags);
+
+	cmd.cmd_id = AUDPP_CMD_AVSYNC;
+	cmd.object_number = id;
+	cmd.interrupt_interval_lsw = rate;
+	cmd.interrupt_interval_msw = rate >> 16;
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_avsync);
+
+unsigned audpp_avsync_sample_count(int id)
+{
+	uint16_t *avsync = the_audpp_state.avsync;
+	unsigned val;
+	unsigned long flags;
+	unsigned mask;
+
+	if (BAD_ID(id))
+		return 0;
+	
+	mask = 1 << id;
+	id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
+	local_irq_save(flags);
+	if (avsync[0] & mask)
+		val = (avsync[id] << 16) | avsync[id + 1];
+	else
+		val = 0;
+	local_irq_restore(flags);
+
+	return val;
+}
+EXPORT_SYMBOL(audpp_avsync_sample_count);
+
+unsigned audpp_avsync_byte_count(int id)
+{
+	uint16_t *avsync = the_audpp_state.avsync;
+	unsigned val;
+	unsigned long flags;
+	unsigned mask;
+
+	if (BAD_ID(id))
+		return 0;
+
+	mask = 1 << id;
+	id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
+	local_irq_save(flags);
+	if (avsync[0] & mask)
+		val = (avsync[id] << 16) | avsync[id + 1];
+	else
+		val = 0;
+	local_irq_restore(flags);
+
+	return val;
+}
+EXPORT_SYMBOL(audpp_avsync_byte_count);
+
+#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
+#define AUDPP_CMD_VOLUME_PAN 0
+
+int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan)
+{
+	/* cmd, obj_cfg[7], cmd_type, volume, pan */
+	uint16_t cmd[11];
+	
+	if (id > 6)
+		return -EINVAL;
+
+	memset(cmd, 0, sizeof(cmd));
+	cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	cmd[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd[8] = AUDPP_CMD_VOLUME_PAN;
+	cmd[9] = volume;
+	cmd[10] = pan;
+
+	return audpp_send_queue3(cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_set_volume_and_pan);
+
+int audpp_pause(unsigned id, int pause)
+{
+	/* pause 1 = pause 0 = resume */
+	u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
+
+	if (id >= CH_COUNT)
+		return -EINVAL;
+
+	memset(pause_cmd, 0, sizeof(pause_cmd));
+
+	pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
+	if (pause == 1)
+		pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
+	else if (pause == 0)
+		pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
+	else
+		return -EINVAL;
+
+	return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
+}
+EXPORT_SYMBOL(audpp_pause);
+
+int audpp_flush(unsigned id)
+{
+	u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
+
+	if (id >= CH_COUNT)
+		return -EINVAL;
+
+	memset(flush_cmd, 0, sizeof(flush_cmd));
+
+	flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
+	flush_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
+
+	return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
+}
+EXPORT_SYMBOL(audpp_flush);
diff --git a/arch/arm/mach-msm/qdsp5/evlog.h b/arch/arm/mach-msm/qdsp5/evlog.h
new file mode 100644
index 0000000..5c0edf1
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/evlog.h
@@ -0,0 +1,133 @@
+/* arch/arm/mach-msm/qdsp5/evlog.h
+ *
+ * simple event log debugging facility
+ *
+ * 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/fs.h>
+#include <linux/hrtimer.h>
+#include <linux/debugfs.h>
+
+#define EV_LOG_ENTRY_NAME(n) n##_entry
+
+#define DECLARE_LOG(_name, _size, _str) \
+static struct ev_entry EV_LOG_ENTRY_NAME(_name)[_size]; \
+static struct ev_log _name = { \
+	.name = #_name, \
+	.strings = _str, \
+	.num_strings = ARRAY_SIZE(_str), \
+	.entry = EV_LOG_ENTRY_NAME(_name), \
+	.max = ARRAY_SIZE(EV_LOG_ENTRY_NAME(_name)), \
+}
+
+struct ev_entry {
+	ktime_t when;
+	uint32_t id;
+	uint32_t arg;
+};
+	
+struct ev_log {
+	struct ev_entry *entry;
+	unsigned max;
+	unsigned next;
+	unsigned fault;
+	const char **strings;
+	unsigned num_strings;
+	const char *name;
+};
+
+static char ev_buf[4096];
+
+static ssize_t ev_log_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *ppos)
+{
+	struct ev_log *log = file->private_data;
+	struct ev_entry *entry;
+	unsigned long flags;
+	int size = 0;
+	unsigned n, id, max;
+	ktime_t now, t;
+	
+	max = log->max;
+	now = ktime_get();
+	local_irq_save(flags);
+	n = (log->next - 1) & (max - 1);
+	entry = log->entry;
+	while (n != log->next) {
+		t = ktime_sub(now, entry[n].when);
+		id = entry[n].id;
+		if (id) {
+			const char *str;
+			if (id < log->num_strings)
+				str = log->strings[id];
+			else
+				str = "UNKNOWN";
+			size += scnprintf(ev_buf + size, 4096 - size,
+					  "%8d.%03d %08x %s\n",
+					  t.tv.sec, t.tv.nsec / 1000000,
+					  entry[n].arg, str);
+		}
+		n = (n - 1) & (max - 1);
+	}
+	log->fault = 0;
+	local_irq_restore(flags);
+	return simple_read_from_buffer(buf, count, ppos, ev_buf, size);
+}
+
+static void ev_log_write(struct ev_log *log, unsigned id, unsigned arg)
+{
+	struct ev_entry *entry;
+	unsigned long flags;
+	local_irq_save(flags);
+
+	if (log->fault) {
+		if (log->fault == 1)
+			goto done;
+		log->fault--;
+	}
+
+	entry = log->entry + log->next;
+	entry->when = ktime_get();
+	entry->id = id;
+	entry->arg = arg;
+	log->next = (log->next + 1) & (log->max - 1);
+done:
+	local_irq_restore(flags);
+}
+
+static void ev_log_freeze(struct ev_log *log, unsigned count)
+{
+	unsigned long flags;
+	local_irq_save(flags);
+	log->fault = count;
+	local_irq_restore(flags);
+}
+
+static int ev_log_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations ev_log_ops = {
+	.read = ev_log_read,
+	.open = ev_log_open,
+};
+
+static int ev_log_init(struct ev_log *log)
+{
+	debugfs_create_file(log->name, 0444, 0, log, &ev_log_ops);
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/qdsp5/snd.c b/arch/arm/mach-msm/qdsp5/snd.c
new file mode 100644
index 0000000..037d7ff
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/snd.c
@@ -0,0 +1,279 @@
+/* arch/arm/mach-msm/qdsp5/snd.c
+ *
+ * interface to "snd" service on the baseband cpu
+ *
+ * Copyright (C) 2008 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/msm_audio.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/board.h>
+#include <mach/msm_rpcrouter.h>
+
+struct snd_ctxt {
+	struct mutex lock;
+	int opened;
+	struct msm_rpc_endpoint *ept;
+	struct msm_snd_endpoints *snd_epts;
+};
+
+static struct snd_ctxt the_snd;
+
+#define RPC_SND_PROG    0x30000002
+#define RPC_SND_CB_PROG 0x31000002
+#if CONFIG_MSM_AMSS_VERSION == 6210
+#define RPC_SND_VERS	0x94756085 /* 2490720389 */
+#elif (CONFIG_MSM_AMSS_VERSION == 6220) || \
+      (CONFIG_MSM_AMSS_VERSION == 6225)
+#define RPC_SND_VERS	0xaa2b1a44 /* 2854951492 */
+#elif CONFIG_MSM_AMSS_VERSION == 6350
+#define RPC_SND_VERS 	MSM_RPC_VERS(1,0)
+#endif
+
+#define SND_SET_DEVICE_PROC 2
+#define SND_SET_VOLUME_PROC 3
+
+struct rpc_snd_set_device_args {
+	uint32_t device;
+	uint32_t ear_mute;
+	uint32_t mic_mute;
+
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+
+struct rpc_snd_set_volume_args {
+	uint32_t device;
+	uint32_t method;
+	uint32_t volume;
+
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+
+struct snd_set_device_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_snd_set_device_args args;
+};
+
+struct snd_set_volume_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_snd_set_volume_args args;
+};
+
+struct snd_endpoint *get_snd_endpoints(int *size);
+
+static inline int check_mute(int mute)
+{
+	return (mute == SND_MUTE_MUTED ||
+		mute == SND_MUTE_UNMUTED) ? 0 : -EINVAL;
+}
+
+static int get_endpoint(struct snd_ctxt *snd, unsigned long arg)
+{
+	int rc = 0, index;
+	struct msm_snd_endpoint ept;
+
+	if (copy_from_user(&ept, (void __user *)arg, sizeof(ept))) {
+		pr_err("snd_ioctl get endpoint: invalid read pointer.\n");
+		return -EFAULT;
+	}
+
+	index = ept.id;
+	if (index < 0 || index >= snd->snd_epts->num) {
+		pr_err("snd_ioctl get endpoint: invalid index!\n");
+		return -EINVAL;
+	}
+
+	ept.id = snd->snd_epts->endpoints[index].id;
+	strncpy(ept.name,
+		snd->snd_epts->endpoints[index].name,
+		sizeof(ept.name));
+
+	if (copy_to_user((void __user *)arg, &ept, sizeof(ept))) {
+		pr_err("snd_ioctl get endpoint: invalid write pointer.\n");
+		rc = -EFAULT;
+	}
+
+	return rc;
+}
+
+static long snd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct snd_set_device_msg dmsg;
+	struct snd_set_volume_msg vmsg;
+	struct msm_snd_device_config dev;
+	struct msm_snd_volume_config vol;
+	struct snd_ctxt *snd = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&snd->lock);
+	switch (cmd) {
+	case SND_SET_DEVICE:
+		if (copy_from_user(&dev, (void __user *) arg, sizeof(dev))) {
+			pr_err("snd_ioctl set device: invalid pointer.\n");
+			rc = -EFAULT;
+			break;
+		}
+
+		dmsg.args.device = cpu_to_be32(dev.device);
+		dmsg.args.ear_mute = cpu_to_be32(dev.ear_mute);
+		dmsg.args.mic_mute = cpu_to_be32(dev.mic_mute);
+		if (check_mute(dev.ear_mute) < 0 ||
+				check_mute(dev.mic_mute) < 0) {
+			pr_err("snd_ioctl set device: invalid mute status.\n");
+			rc = -EINVAL;
+			break;
+		}
+		dmsg.args.cb_func = -1;
+		dmsg.args.client_data = 0;
+
+		pr_info("snd_set_device %d %d %d\n", dev.device,
+						 dev.ear_mute, dev.mic_mute);
+
+		rc = msm_rpc_call(snd->ept,
+			SND_SET_DEVICE_PROC,
+			&dmsg, sizeof(dmsg), 5 * HZ);
+		break;
+
+	case SND_SET_VOLUME:
+		if (copy_from_user(&vol, (void __user *) arg, sizeof(vol))) {
+			pr_err("snd_ioctl set volume: invalid pointer.\n");
+			rc = -EFAULT;
+			break;
+		}
+
+		vmsg.args.device = cpu_to_be32(vol.device);
+		vmsg.args.method = cpu_to_be32(vol.method);
+		if (vol.method != SND_METHOD_VOICE) {
+			pr_err("snd_ioctl set volume: invalid method.\n");
+			rc = -EINVAL;
+			break;
+		}
+
+		vmsg.args.volume = cpu_to_be32(vol.volume);
+		vmsg.args.cb_func = -1;
+		vmsg.args.client_data = 0;
+
+		pr_info("snd_set_volume %d %d %d\n", vol.device,
+						vol.method, vol.volume);
+
+		rc = msm_rpc_call(snd->ept,
+			SND_SET_VOLUME_PROC,
+			&vmsg, sizeof(vmsg), 5 * HZ);
+		break;
+
+	case SND_GET_NUM_ENDPOINTS:
+		if (copy_to_user((void __user *)arg,
+				&snd->snd_epts->num, sizeof(unsigned))) {
+			pr_err("snd_ioctl get endpoint: invalid pointer.\n");
+			rc = -EFAULT;
+		}
+		break;
+
+	case SND_GET_ENDPOINT:
+		rc = get_endpoint(snd, arg);
+		break;
+
+	default:
+		pr_err("snd_ioctl unknown command.\n");
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&snd->lock);
+
+	return rc;
+}
+
+static int snd_release(struct inode *inode, struct file *file)
+{
+	struct snd_ctxt *snd = file->private_data;
+
+	mutex_lock(&snd->lock);
+	snd->opened = 0;
+	mutex_unlock(&snd->lock);
+	return 0;
+}
+
+static int snd_open(struct inode *inode, struct file *file)
+{
+	struct snd_ctxt *snd = &the_snd;
+	int rc = 0;
+
+	mutex_lock(&snd->lock);
+	if (snd->opened == 0) {
+		if (snd->ept == NULL) {
+			snd->ept = msm_rpc_connect(RPC_SND_PROG, RPC_SND_VERS,
+					MSM_RPC_UNINTERRUPTIBLE);
+			if (IS_ERR(snd->ept)) {
+				rc = PTR_ERR(snd->ept);
+				snd->ept = NULL;
+				pr_err("snd: failed to connect snd svc\n");
+				goto err;
+			}
+		}
+		file->private_data = snd;
+		snd->opened = 1;
+	} else {
+		pr_err("snd already opened.\n");
+		rc = -EBUSY;
+	}
+
+err:
+	mutex_unlock(&snd->lock);
+	return rc;
+}
+
+static struct file_operations snd_fops = {
+	.owner		= THIS_MODULE,
+	.open		= snd_open,
+	.release	= snd_release,
+	.unlocked_ioctl	= snd_ioctl,
+};
+
+struct miscdevice snd_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_snd",
+	.fops	= &snd_fops,
+};
+
+static int snd_probe(struct platform_device *pdev)
+{
+	struct snd_ctxt *snd = &the_snd;
+	mutex_init(&snd->lock);
+	snd->snd_epts = (struct msm_snd_endpoints *)pdev->dev.platform_data;
+	return misc_register(&snd_misc);
+}
+
+static struct platform_driver snd_plat_driver = {
+	.probe = snd_probe,
+	.driver = {
+		.name = "msm_snd",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init snd_init(void)
+{
+	return platform_driver_register(&snd_plat_driver);
+}
+
+module_init(snd_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/Makefile b/arch/arm/mach-msm/qdsp5v2/Makefile
new file mode 100644
index 0000000..75016db
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/Makefile
@@ -0,0 +1,5 @@
+obj-y += adsp.o
+obj-y += adsp_audio.o
+obj-y += audio_glue.o
+obj-y += audio_out.o
+obj-y += marimba.o
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp.c b/arch/arm/mach-msm/qdsp5v2/adsp.c
new file mode 100644
index 0000000..8d74241
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp.c
@@ -0,0 +1,692 @@
+/* arch/arm/mach-msm/qdsp5v2/adsp.c
+ *
+ * Copyright (C) 2010 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/fs.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include <mach/msm_iomap.h>
+
+#include "../dal.h"
+
+#include "adsp.h"
+#include "adsp_private.h"
+
+struct msm_adsp_queue {
+	const char *name;
+	uint32_t offset;
+	uint32_t max_size;
+	uint32_t flags;
+};
+	
+struct msm_adsp_module {
+	msm_adsp_callback func;
+	void *cookie;
+	
+	wait_queue_head_t wait;
+	struct msm_adsp *adsp;
+	uint32_t id;
+
+	unsigned active;
+
+	const char *name;
+	struct msm_adsp_module *next;
+	struct msm_adsp_queue queue[ADSP_QUEUES_MAX];
+};
+
+struct msm_adsp {
+	/* DSP "registers" */
+	void *read_ctrl;
+	void *write_ctrl;
+	void *send_irq;
+	void *base;
+
+	/* DAL client handle for DSP control service */
+	struct dal_client *client;
+
+	spinlock_t callback_lock;
+	spinlock_t write_lock;
+	spinlock_t event_lock;
+
+	wait_queue_head_t callback_wq;
+
+	/* list of all existing dsp modules */
+	struct msm_adsp_module *all_modules;
+
+	/* map from dsp rtos task IDs to modules */
+	struct msm_adsp_module *task_to_module[ADSP_TASKS_MAX];
+
+	/* used during initialization */
+	struct adsp_module_info tmpmodule;
+
+};
+
+static struct msm_adsp the_adsp;
+
+static struct msm_adsp_module *id_to_module(struct msm_adsp *adsp, unsigned id)
+{
+	struct msm_adsp_module *module;
+
+	for (module = adsp->all_modules; module; module = module->next)
+		if (module->id == id)
+			return module;
+	return NULL;
+}
+
+int msm_adsp_get(const char *name, struct msm_adsp_module **module,
+		 msm_adsp_callback func, void *cookie)
+{
+	struct msm_adsp *adsp = &the_adsp;
+	unsigned long flags;
+	int ret = -ENODEV;
+	struct msm_adsp_module *m;
+
+	for (m = adsp->all_modules; m; m = m->next) {
+		if (!strcmp(m->name, name)) {
+			spin_lock_irqsave(&m->adsp->callback_lock, flags);
+			if (m->func == 0) {
+				m->func = func;
+				m->cookie = cookie;
+				*module = m;
+				ret = 0;
+			} else {
+				ret = -EBUSY;
+			}
+			spin_unlock_irqrestore(&m->adsp->callback_lock, flags);
+			break;
+		}
+	}
+	return ret;
+}
+
+void msm_adsp_put(struct msm_adsp_module *m)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&m->adsp->callback_lock, flags);
+	m->func = 0;
+	m->cookie = 0;
+	spin_unlock_irqrestore(&m->adsp->callback_lock, flags);
+}
+
+
+int msm_adsp_lookup_queue(struct msm_adsp_module *module, const char *name)
+{
+	int n;
+	for (n = 0; n < ADSP_QUEUES_MAX; n++) {
+		if (!module->queue[n].name)
+			break;
+		if (!strcmp(name, module->queue[n].name))
+			return n;
+	}
+	return -ENODEV;
+}
+
+static int msm_adsp_command(struct msm_adsp_module *module, unsigned cmd_id)
+{
+	struct adsp_dal_cmd cmd;
+	int ret;
+
+	cmd.cmd = cmd_id;
+	cmd.proc_id = ADSP_PROC_APPS;
+	cmd.module = module->id;
+	cmd.cookie = 0;
+
+	ret = dal_call_f5(module->adsp->client, ADSP_DAL_COMMAND,
+			  &cmd, sizeof(cmd));
+	if (ret)
+		return -EIO;
+
+	return 0;
+}
+
+int msm_adsp_enable(struct msm_adsp_module *module)
+{
+	int ret;
+	/* XXX interlock? */
+
+	ret = msm_adsp_command(module, ADSP_CMD_ENABLE);
+	if (ret < 0) {
+		pr_err("msm_adsp_enable: error enabling %s %d\n",
+		       module->name, ret);
+		return -EIO;
+	}
+	ret = wait_event_timeout(module->adsp->callback_wq,
+				 module->active, 5 * HZ);
+	if (!ret) {
+		pr_err("msm_adsp_enable: timeout enabling %s\n",
+		       module->name);
+		return -ETIMEDOUT;
+	}
+
+	printk("msm_adsp_enable: %s enabled.\n", module->name);
+	return 0;
+}
+
+int msm_adsp_disable(struct msm_adsp_module *module)
+{
+	/* XXX interlock? */
+	return msm_adsp_command(module, ADSP_CMD_DISABLE);
+}
+
+int msm_adsp_write(struct msm_adsp_module *module, unsigned queue_idx,
+		   void *cmd_buf, size_t cmd_size)
+{
+	struct msm_adsp *adsp;
+	uint32_t val;
+	uint32_t dsp_q_addr;
+	uint32_t dsp_addr;
+	uint32_t cmd_id = 0;
+	int cnt = 0;
+	int ret = 0;
+	unsigned long flags;
+
+	if (!module || !cmd_size || (queue_idx >= ADSP_QUEUES_MAX))
+		return -EINVAL;
+
+	if (module->queue[queue_idx].name == NULL)
+		return -EINVAL;
+
+	adsp = module->adsp;
+
+	spin_lock_irqsave(&adsp->write_lock, flags);
+
+#if 0
+	if (module->state != ADSP_STATE_ENABLED) {
+		ret = -ENODEV;
+		goto done;
+	}
+#endif
+
+	dsp_q_addr = module->queue[queue_idx].offset;
+	dsp_q_addr &= ADSP_WRITE_CTRL_DSP_ADDR_M;
+
+	/* Poll until the ADSP is ready to accept a command.
+	 * Wait for 100us, return error if it's not responding.
+	 * If this returns an error, we need to disable ALL modules and
+	 * then retry.
+	 */
+	while (((val = readl(adsp->write_ctrl)) &
+		ADSP_WRITE_CTRL_READY_M) !=
+		ADSP_WRITE_CTRL_READY_V) {
+		if (cnt > 50) {
+			pr_err("timeout waiting for DSP write ready\n");
+			ret = -EIO;
+			goto done;
+		}
+		udelay(2);
+		cnt++;
+	}
+
+	/* Set the mutex bits */
+	val &= ~(ADSP_WRITE_CTRL_MUTEX_M);
+	val |=  ADSP_WRITE_CTRL_MUTEX_NAVAIL_V;
+
+	/* Clear the command bits */
+	val &= ~(ADSP_WRITE_CTRL_CMD_M);
+
+	/* Set the queue address bits */
+	val &= ~(ADSP_WRITE_CTRL_DSP_ADDR_M);
+	val |= dsp_q_addr;
+
+	writel(val, adsp->write_ctrl);
+
+	/* Generate an interrupt to the DSP.  This notifies the DSP that
+	 * we are about to send a command on this particular queue.  The
+	 * DSP will in response change its state.
+	 */
+	writel(1, adsp->send_irq);
+
+	/* Poll until the adsp responds to the interrupt; this does not
+	 * generate an interrupt from the adsp.  This should happen within
+	 * 5ms.
+	 */
+	cnt = 0;
+	while ((readl(adsp->write_ctrl) &
+		ADSP_WRITE_CTRL_MUTEX_M) ==
+		ADSP_WRITE_CTRL_MUTEX_NAVAIL_V) {
+		if (cnt > 2500) {
+			pr_err("timeout waiting for adsp ack\n");
+			ret = -EIO;
+			goto done;
+		}
+		udelay(2);
+		cnt++;
+	}
+
+	/* Read the ctrl word */
+	val = readl(adsp->write_ctrl);
+
+	if ((val & ADSP_WRITE_CTRL_STATUS_M) !=
+	    ADSP_WRITE_CTRL_NO_ERR_V) {
+		ret = -EIO;
+		pr_err("failed to write queue %x, retry\n", dsp_q_addr);
+		goto done;
+	}
+
+	/* No error */
+	/* Get the DSP buffer address */
+	dsp_addr = (val & ADSP_WRITE_CTRL_DSP_ADDR_M) +
+		(uint32_t)MSM_AD5_BASE;
+
+	if (dsp_addr < (uint32_t)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
+		uint16_t *buf_ptr = (uint16_t *) cmd_buf;
+		uint16_t *dsp_addr16 = (uint16_t *)dsp_addr;
+		cmd_size /= sizeof(uint16_t);
+		
+		/* Save the command ID */
+		cmd_id = (uint32_t) buf_ptr[0];
+		
+		/* Copy the command to DSP memory */
+		cmd_size++;
+		while (--cmd_size)
+			*dsp_addr16++ = *buf_ptr++;
+	} else {
+		uint32_t *buf_ptr = (uint32_t *) cmd_buf;
+		uint32_t *dsp_addr32 = (uint32_t *)dsp_addr;
+		cmd_size /= sizeof(uint32_t);
+		
+		/* Save the command ID */
+		cmd_id = buf_ptr[0];
+		
+		cmd_size++;
+		while (--cmd_size)
+			*dsp_addr32++ = *buf_ptr++;
+	}
+
+	/* Set the mutex bits */
+	val &= ~(ADSP_WRITE_CTRL_MUTEX_M);
+	val |=  ADSP_WRITE_CTRL_MUTEX_NAVAIL_V;
+	
+	/* Set the command bits to write done */
+	val &= ~(ADSP_WRITE_CTRL_CMD_M);
+	val |= ADSP_WRITE_CTRL_CMD_WRITE_DONE_V;
+	
+	/* Set the queue address bits */
+	val &= ~(ADSP_WRITE_CTRL_DSP_ADDR_M);
+	val |= dsp_q_addr;
+	
+	writel(val, adsp->write_ctrl);
+	
+	/* Generate an interrupt to the DSP.  It does not respond with
+	 * an interrupt, and we do not need to wait for it to
+	 * acknowledge, because it will hold the mutex lock until it's
+	 * ready to receive more commands again.
+	 */
+	writel(1, adsp->send_irq);
+	
+//	module->num_commands++;
+
+done:
+	spin_unlock_irqrestore(&adsp->write_lock, flags);
+	return ret;
+}
+
+static int adsp_read_task_to_host(struct msm_adsp *adsp, void *dsp_addr)
+{
+	struct msm_adsp_module *module;
+	unsigned task_id;
+	unsigned msg_id;
+	unsigned msg_length;
+	unsigned n;
+	unsigned tmp;
+	union {
+		u32 data32[16];
+		u16 data16[32];
+	} u;
+
+	if (dsp_addr >= (void *)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
+		uint32_t *dsp_addr32 = dsp_addr;
+		tmp = *dsp_addr32++;
+		task_id = (tmp & ADSP_READ_CTRL_TASK_ID_M) >> 8;
+		msg_id = (tmp & ADSP_READ_CTRL_MSG_ID_M);
+		tmp >>= 16;
+		if (tmp > 16) {
+			pr_err("adsp: message too large (%d x 32)\n", tmp);
+			tmp = 16;
+		}
+		msg_length = tmp * sizeof(uint32_t);
+		for (n = 0; n < tmp; n++)
+			u.data32[n] = *dsp_addr32++;
+	} else {
+		uint16_t *dsp_addr16 = dsp_addr;
+		tmp = *dsp_addr16++;
+		task_id = (tmp & ADSP_READ_CTRL_TASK_ID_M) >> 8;
+		msg_id = tmp & ADSP_READ_CTRL_MSG_ID_M;
+		tmp = *dsp_addr16++;
+		if (tmp > 32) {
+			pr_err("adsp: message too large (%d x 16)\n", tmp);
+			tmp = 32;
+		}
+		msg_length = tmp * sizeof(uint16_t);
+		for (n = 0; n < tmp; n++)
+			u.data16[n] = *dsp_addr16++;
+	}
+
+#if 0
+	pr_info("ADSP EVENT TASK %d MSG %d SIZE %d\n",
+		task_id, msg_id, msg_length);
+#endif
+	if (task_id > ADSP_TASKS_MAX) {
+		pr_err("adsp: bogus task id %d\n", task_id);
+		return 0;
+	}
+	module = adsp->task_to_module[task_id];
+
+	if (!module) {
+		pr_err("adsp: no module for task id %d\n", task_id);
+		return 0;
+	}
+
+	if (!module->func) {
+		pr_err("module %s is not open\n", module->name);
+		return 0;
+	}
+
+	module->func(msg_id, u.data32, msg_length, module->cookie);
+	return 0;
+}
+
+static int adsp_get_event(struct msm_adsp *adsp)
+{
+	uint32_t val;
+	uint32_t ready;
+	void *dsp_addr;
+	uint32_t cmd_type;
+	int cnt;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&adsp->event_lock, flags);
+
+	/* Whenever the DSP has a message, it updates this control word
+	 * and generates an interrupt.  When we receive the interrupt, we
+	 * read this register to find out what ADSP task the command is
+	 * comming from.
+	 *
+	 * The ADSP should *always* be ready on the first call, but the
+	 * irq handler calls us in a loop (to handle back-to-back command
+	 * processing), so we give the DSP some time to return to the
+	 * ready state.  The DSP will not issue another IRQ for events
+	 * pending between the first IRQ and the event queue being drained,
+	 * unfortunately.
+	 */
+
+	for (cnt = 0; cnt < 50; cnt++) {
+		val = readl(adsp->read_ctrl);
+
+		if ((val & ADSP_READ_CTRL_FLAG_M) ==
+		    ADSP_READ_CTRL_FLAG_UP_CONT_V)
+			goto ready;
+
+		udelay(2);
+	}
+	pr_err("adsp_get_event: not ready after 100uS\n");
+	rc = -EBUSY;
+	goto done;
+
+ready:
+	/* Here we check to see if there are pending messages. If there are
+	 * none, we siply return -EAGAIN to indicate that there are no more
+	 * messages pending.
+	 */
+	ready = val & ADSP_READ_CTRL_READY_M;
+	if ((ready != ADSP_READ_CTRL_READY_V) &&
+	    (ready != ADSP_READ_CTRL_CONT_V)) {
+		rc = -EAGAIN;
+		goto done;
+	}
+
+	/* DSP says that there are messages waiting for the host to read */
+
+	/* Get the Command Type */
+	cmd_type = val & ADSP_READ_CTRL_CMD_TYPE_M;
+
+	/* Get the DSP buffer address */
+	dsp_addr = (void *)((val &
+			     ADSP_READ_CTRL_DSP_ADDR_M) +
+			    (uint32_t)MSM_AD5_BASE);
+
+	/* We can only handle Task-to-Host messages */
+	if (cmd_type != ADSP_READ_CTRL_CMD_TASK_TO_H_V) {
+		rc = -EIO;
+		goto done;
+	}
+
+	adsp_read_task_to_host(adsp, dsp_addr);
+
+	val = readl(adsp->read_ctrl);
+	val &= ~ADSP_READ_CTRL_READY_M;
+
+	/* Write ctrl word to the DSP */
+	writel(val, adsp->read_ctrl);
+
+	/* Generate an interrupt to the DSP */
+	writel(1, adsp->send_irq);
+
+done:
+	spin_unlock_irqrestore(&adsp->event_lock, flags);
+	return rc;
+}
+
+static irqreturn_t adsp_irq_handler(int irq, void *data)
+{
+	struct msm_adsp *adsp = &the_adsp;
+	int count = 0;
+	for (count = 0; count < 15; count++)
+		if (adsp_get_event(adsp) < 0)
+			break;
+#if 0
+	if (count > adsp->event_backlog_max)
+		adsp->event_backlog_max = count;
+	adsp->events_received += count;
+#endif
+	if (count == 15)
+		pr_err("too many (%d) events for single irq!\n", count);
+	return IRQ_HANDLED;
+}
+
+static void adsp_dal_callback(void *data, int len, void *cookie)
+{
+	struct msm_adsp *adsp = cookie;
+	struct adsp_dal_event *e = data;
+	struct msm_adsp_module *m;
+#if 0
+	pr_info("adsp: h %08x c %08x l %08x\n",
+		e->evt_handle, e->evt_cookie, e->evt_length);
+	pr_info("    : e %08x v %08x p %08x\n",
+		e->event, e->version, e->proc_id);
+	pr_info("    : m %08x i %08x a %08x\n",
+		e->u.info.module, e->u.info.image, e->u.info.apps_okts);
+#endif
+
+	switch (e->event) {
+	case ADSP_EVT_INIT_INFO:
+		memcpy(&adsp->tmpmodule, &e->u.module,
+		       sizeof(adsp->tmpmodule));
+		break;
+	case ADSP_EVT_MOD_READY:
+		m = id_to_module(adsp, e->u.info.module);
+		if (m) {
+			pr_info("adsp: %s READY\n", m->name);
+			m->active = 1;
+		}
+		break;
+	case ADSP_EVT_MOD_DISABLE:
+		/* does not actually happen in adsp5v2 */
+		m = id_to_module(adsp, e->u.info.module);
+		if (m)
+			pr_info("adsp: %s DISABLED\n", m->name);
+		break;
+	case ADSP_EVT_DISABLE_FAIL:
+		m = id_to_module(adsp, e->u.info.module);
+		if (m)
+			pr_info("adsp: %s DISABLE FAILED\n", m->name);
+		break;
+	default:
+		pr_err("adsp_dal_callback: unknown event %d\n", e->event);
+	}
+	wake_up(&adsp->callback_wq);
+}
+
+static void adsp_add_module(struct msm_adsp *adsp, struct adsp_module_info *mi)
+{
+	struct msm_adsp_module *module;
+	int n;
+
+	if (mi->task_id >= ADSP_TASKS_MAX) {
+		pr_err("adsp: module '%s' task id %d is invalid\n",
+		       mi->name, mi->task_id);
+		return;
+	}
+	if (mi->q_cnt > ADSP_QUEUES_MAX) {
+		pr_err("adsp: module '%s' q_cnt %d is invalid\n",
+		       mi->name, mi->q_cnt);
+		return;
+	}
+
+	module = kzalloc(sizeof(*module), GFP_KERNEL);
+	if (!module)
+		return;
+
+	module->name = kstrdup(mi->name, GFP_KERNEL);
+	if (!module->name)
+		goto fail_module_name;
+
+	for (n = 0; n < mi->q_cnt; n++) {
+		struct msm_adsp_queue *queue = module->queue + n;
+		queue->name = kstrdup(mi->queue[n].name, GFP_KERNEL);
+		if (!queue->name)
+			goto fail_queue_name;
+		queue->offset = mi->queue[n].offset;
+		queue->max_size = mi->queue[n].max_size;
+		queue->flags = mi->queue[n].flag;
+	}
+
+	init_waitqueue_head(&module->wait);
+	module->id = mi->uuid;
+	module->adsp = adsp;
+
+	module->next = adsp->all_modules;
+	adsp->all_modules = module;
+
+	adsp->task_to_module[mi->task_id] = module;
+#if 0
+	pr_info("adsp: module '%s' id 0x%x task %d\n",
+		module->name, module->id, mi->task_id);
+	for (n = 0; (n < ADSP_TASKS_MAX) && module->queue[n].name; n++)
+		pr_info("       queue '%s' off 0x%x size %d flags %x",
+			module->queue[n].name, module->queue[n].offset,
+			module->queue[n].max_size, module->queue[n].flags);
+#endif
+	return;
+
+fail_queue_name:
+	for (n = 0; n < mi->q_cnt; n++)
+		if (module->queue[n].name)
+			kfree(module->queue[n].name);
+fail_module_name:
+	kfree(module);
+}
+
+static int adsp_probe(struct platform_device *pdev) {
+	struct msm_adsp *adsp = &the_adsp;
+	struct adsp_dal_cmd cmd;
+	int ret, n;
+
+	pr_info("*** adsp_probe() ***\n");
+
+	adsp->base = MSM_AD5_BASE;
+	adsp->read_ctrl = adsp->base + ADSP_READ_CTRL_OFFSET;
+	adsp->write_ctrl = adsp->base + ADSP_WRITE_CTRL_OFFSET;
+	adsp->send_irq = adsp->base + ADSP_SEND_IRQ_OFFSET;
+
+	adsp->client = dal_attach(ADSP_DAL_DEVICE, ADSP_DAL_PORT,
+				  adsp_dal_callback, adsp);
+	if (!adsp->client) {
+		pr_err("adsp_probe: cannot attach to dal device\n");
+		return -ENODEV;
+	}
+
+	cmd.cmd = ADSP_CMD_GET_INIT_INFO;
+	cmd.proc_id = ADSP_PROC_APPS;
+	cmd.module = 0;
+	cmd.cookie = 0;
+
+	for (n = 0; n < 64; n++) {
+		adsp->tmpmodule.uuid = 0xffffffff;
+		ret = dal_call_f5(adsp->client, ADSP_DAL_COMMAND,
+				  &cmd, sizeof(cmd));
+		if (ret) {
+			pr_err("adsp_probe() get info dal call failed\n");
+			break;
+		}
+		ret = wait_event_timeout(adsp->callback_wq, 
+					 (adsp->tmpmodule.uuid != 0xffffffff),
+					 5*HZ);
+		if (ret == 0) {
+			pr_err("adsp_probe() timed out getting module info\n");
+			break;
+		}
+		if (adsp->tmpmodule.uuid == 0x7fffffff)
+			break;
+		if (adsp->tmpmodule.task_id == 0xffff)
+			continue;
+//		adsp_print_module(&adsp->tmpmodule);
+		adsp_add_module(adsp, &adsp->tmpmodule);
+	}
+
+	ret = request_irq(INT_AD5A_MPROC_APPS_0, adsp_irq_handler,
+			  IRQF_TRIGGER_RISING, "adsp", 0);
+	if (ret < 0)
+		return ret;
+
+	pr_info("*** adsp_probe() done ***\n");
+	return 0;
+}
+
+static struct platform_driver adsp_driver = {
+	.probe	= adsp_probe,
+	.driver	= {
+		.name	= "SMD_DAL00",
+		.owner	= THIS_MODULE,
+	},
+};
+
+extern int msm_codec_init(void);
+
+static int __init adsp_init(void)
+{
+	struct msm_adsp *adsp = &the_adsp;
+
+	pr_info("*** adsp_init() ***\n");
+
+	init_waitqueue_head(&adsp->callback_wq);
+	spin_lock_init(&adsp->callback_lock);
+	spin_lock_init(&adsp->write_lock);
+	spin_lock_init(&adsp->event_lock);
+
+	msm_codec_init();
+
+	return platform_driver_register(&adsp_driver);
+}
+
+module_init(adsp_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp.h b/arch/arm/mach-msm/qdsp5v2/adsp.h
new file mode 100644
index 0000000..c37588f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp.h
@@ -0,0 +1,42 @@
+/* arch/arm/mach-msm/qdsp5v2/adsp.h
+ *
+ * Copyright (C) 2010 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.
+ *
+ */
+
+#ifndef _MSM_ADSP_5V2_H_
+#define _MSM_ADSP_5V2_H_
+
+struct msm_adsp_module;
+
+typedef void (*msm_adsp_callback)(unsigned id, void *event,
+				  size_t len, void *cookie);
+
+
+int msm_adsp_get(const char *name, struct msm_adsp_module **module,
+		 msm_adsp_callback callback, void *cookie);
+
+void msm_adsp_put(struct msm_adsp_module *module);
+
+/* find queue index for a named module command queue */
+int msm_adsp_lookup_queue(struct msm_adsp_module *module, const char *name);
+
+int msm_adsp_enable(struct msm_adsp_module *module);
+int msm_adsp_disable(struct msm_adsp_module *module);
+
+/* write is safe to call from atomic context.  All other msm_adsp_*
+ * calls may block.
+ */
+int msm_adsp_write(struct msm_adsp_module *module, unsigned queue_idx,
+		   void *data, size_t len);
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp_audio.c b/arch/arm/mach-msm/qdsp5v2/adsp_audio.c
new file mode 100644
index 0000000..80dde0a1
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp_audio.c
@@ -0,0 +1,460 @@
+/* arch/arm/mach-msm/qdsp5v2/adsp_audio.c
+ *
+ * Copyright (C) 2010 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/module.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include "adsp.h"
+#include "adsp_module_afe.h"
+#include "adsp_module_audpp.h"
+#include "adsp_module_audplay.h"
+
+#include "adsp_audio.h"
+
+
+#define AUDDEC_DEC_PCM 0
+
+/* Decoder status received from AUDPPTASK */
+#define  STATUS_SLEEP	0
+#define  STATUS_INIT	1
+#define  STATUS_CONFIG	2
+#define  STATUS_PLAY	3
+
+
+#define MAX_AUDPLAY_TASKS 5
+
+struct audplay {
+	struct msm_adsp_module *module;
+	wait_queue_head_t wait;
+	int q1;
+	int active;
+	int id;
+	int status;
+	struct audpp *audpp;
+
+	void (*callback)(void *cookie);
+	void *cookie;
+};
+
+struct audpp {
+	struct msm_adsp_module *module;
+	wait_queue_head_t wait;
+	struct mutex lock;
+	int q1, q2, q3;
+	unsigned count;
+	struct audplay audplay[MAX_AUDPLAY_TASKS];
+};
+
+struct afe_info {
+	struct msm_adsp_module *module;
+	wait_queue_head_t wait;
+	struct mutex lock;
+	unsigned count;
+	u8 active[AFE_DEVICE_ID_MAX + 1];
+};
+
+struct afe_info the_afe_info;
+static struct audpp the_audpp;
+
+
+static void afe_callback(unsigned id, void *event, size_t len, void *cookie)
+{
+	struct afe_info *afe = cookie;
+	struct afe_msg_codec_config_ack *msg = event;
+
+	printk("afe_callback id=%d len=%d\n", id, len);
+	
+	if (id != AFE_MSG_CODEC_CONFIG_ACK)
+		return;
+
+	if (msg->device_id > AFE_DEVICE_ID_MAX)
+		return;
+
+	if (msg->device_activity == AFE_MSG_CODEC_CONFIG_ENABLED)
+		afe->active[msg->device_id] = 1;
+	else
+		afe->active[msg->device_id] = 0;
+
+	wake_up(&afe->wait);
+}
+
+int afe_enable(unsigned device, unsigned rate, unsigned channels)
+{
+	struct afe_info *afe = &the_afe_info;
+	struct afe_cmd_codec_config cmd;
+	int ret = 0;
+
+	/* rate must be one of the following:
+	 * 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+	 */
+	cmd.cmd_id = AFE_CMD_CODEC_CONFIG_CMD;
+	cmd.device_id = device;
+	cmd.activity = 1;
+	cmd.sample_rate = rate / 1000;
+	cmd.channel_mode = channels;
+	cmd.volume = AFE_VOLUME_UNITY;
+	cmd.reserved = 0;
+
+	mutex_lock(&afe->lock);
+
+	if (!afe->module) {
+		ret = msm_adsp_get("AFE", &afe->module, afe_callback, afe);
+		if (ret)
+			goto done;
+	}
+
+	if (afe->active[device]) {
+		pr_err("afe_enable: device %d already enabled\n", device);
+		ret = -EBUSY;
+		goto done;
+	}
+
+	if (++afe->count == 1) {
+		pr_info("AFE ENABLE!\n");
+		ret = msm_adsp_enable(afe->module);
+		if (ret < 0) {
+			pr_err("afe_enable: cannot enable module\n");
+			afe->count--;
+			goto done;
+		}
+	}
+
+	ret = msm_adsp_write(afe->module, 0, &cmd, sizeof(cmd));
+	if (ret < 0) {
+		printk("afe_enable: command write failed\n");
+		goto done;
+	}
+
+	ret = wait_event_timeout(afe->wait, afe->active[device], 5 * HZ);
+	if (!ret) {
+		pr_err("afe_enable: command timeout\n");
+		ret = -EIO;
+	} else {
+		printk("afe_enable: device %d active\n", cmd.device_id);
+	}
+done:
+	mutex_unlock(&afe->lock);
+	return ret;
+}
+
+int afe_disable(unsigned device)
+{
+	struct afe_info *afe = &the_afe_info;
+	struct afe_cmd_codec_config cmd;
+	int ret = 0;
+
+	memset(&cmd, sizeof(cmd), 0);
+	cmd.cmd_id = AFE_CMD_CODEC_CONFIG_CMD;
+	cmd.device_id = device;
+	cmd.activity = 0;
+
+	mutex_lock(&afe->lock);
+
+	if (!afe->active[device]) {
+		pr_err("afe_disable: device %d already disabled\n", device);
+		goto done;
+	}
+
+	ret = msm_adsp_write(afe->module, 0, &cmd, sizeof(cmd));
+	if (ret < 0) {
+		printk("afe_disable: command write failed\n");
+		goto done;
+	}
+
+	ret = wait_event_timeout(afe->wait, !afe->active[device], 5 * HZ);
+	if (!ret) {
+		pr_err("afe_disable: command timeout\n");
+		ret = -EIO;
+	} else {
+		printk("afe_disable: device %d inactive\n", cmd.device_id);
+		if (--afe->count == 0) {
+			pr_info("AFE DISABLE!\n");
+			msm_adsp_disable(afe->module);
+		}
+	}
+done:
+	mutex_unlock(&afe->lock);
+	return ret;
+}
+
+static void audpp_callback(unsigned id, void *event, size_t len, void *cookie)
+{
+	struct audpp *audpp = cookie;
+
+	if (id == AUDPP_MSG_STATUS_MSG) {
+		struct audpp_msg_status_msg *msg = event;
+		pr_info("audpp STATUS id=%d status=%d reason=%d\n",
+			msg->dec_id, msg->status, msg->reason);
+		if (msg->dec_id < MAX_AUDPLAY_TASKS) {
+			audpp->audplay[msg->dec_id].status = msg->status;
+			wake_up(&audpp->audplay[msg->dec_id].wait);
+		}
+			
+	} else {
+		pr_info("audpp cb %d %d\n", id, len);
+	}
+}
+
+static int audpp_get(struct audpp *audpp)
+{
+	int ret = 0;
+
+	if (++audpp->count > 1)
+		return 0;
+
+	ret = msm_adsp_get("AUDPP", &audpp->module, audpp_callback, audpp);
+	if (ret < 0) {
+		pr_err("audpp_get: could not get AUDPP\n");
+		goto fail_get_module;
+	}
+
+	audpp->q1 = msm_adsp_lookup_queue(audpp->module, "AudPPCmd1");
+	audpp->q2 = msm_adsp_lookup_queue(audpp->module, "AudPPCmd2");
+	audpp->q3 = msm_adsp_lookup_queue(audpp->module, "AudPPCmd3");
+	if ((audpp->q1 < 0) || (audpp->q2 < 0) || (audpp->q3 < 0)) {
+		pr_err("audpp_get: could not get queues\n");
+		ret = -ENODEV;
+		goto fail_enable_module;
+	}
+
+	ret = msm_adsp_enable(audpp->module);
+	if (ret < 0)
+		goto fail_enable_module;
+
+	return 0;
+
+fail_enable_module:
+	msm_adsp_put(audpp->module);
+	audpp->module = NULL;
+fail_get_module:
+	audpp->count--;
+	return ret;
+}
+
+static void audpp_put(struct audpp *audpp)
+{
+	if (--audpp->count > 0)
+		return;
+
+	msm_adsp_disable(audpp->module);
+	msm_adsp_put(audpp->module);
+	audpp->module = NULL;
+}
+
+
+static void audplay_callback(unsigned id, void *event, size_t len, void *cookie)
+{
+	struct audplay *audplay = cookie;
+	if (id == AUDPLAY_MSG_DEC_NEEDS_DATA) {
+#if 0
+		struct audplay_msg_dec_needs_data *msg = event;
+		pr_info("audplay NEEDDATA id=%d off=%d sz=%d %d %d %d %d\n",
+			msg->dec_id, msg->adecDataReadPtrOffset,
+			msg->adecDataBufSize, msg->bitstream_free_len,
+			msg->bitstream_write_ptr, msg->bitstream_buf_start,
+			msg->bitstream_buf_len);
+#endif
+		audplay->callback(audplay->cookie);
+	} else {
+		pr_info("audplay cb %d %d\n", id, len);
+	}
+}
+
+struct audplay *audplay_get(void (*cb)(void *cookie), void *cookie)
+{
+	struct audpp *audpp = &the_audpp;
+	struct audplay *audplay = 0;
+	char buf[32];
+	unsigned n;
+	int ret;
+
+	mutex_lock(&audpp->lock);
+
+	for (n = 0; n < MAX_AUDPLAY_TASKS; n++)
+		if (audpp->audplay[n].active == 0) break;
+
+	if (n == MAX_AUDPLAY_TASKS)
+		goto done;
+
+	if (audpp_get(audpp))
+		goto done;
+
+	audplay = audpp->audplay + n;
+	sprintf(buf, "AUDPLAY%d", n);
+	ret = msm_adsp_get(buf, &audplay->module, audplay_callback, audplay);
+	if (ret < 0)
+		goto fail_audplay_get;
+
+	sprintf(buf,"AudPlay%dBitStreamCtrl", n);
+	audplay->q1 = msm_adsp_lookup_queue(audplay->module, buf);
+	if (audplay->q1 < 0)
+		goto fail_audplay_enable;
+
+	ret = msm_adsp_enable(audplay->module);
+	if (ret < 0)
+		goto fail_audplay_enable;
+
+	audplay->active = 1;
+	audplay->callback = cb;
+	audplay->cookie = cookie;
+	goto done;
+
+fail_audplay_enable:
+	msm_adsp_put(audplay->module);
+	audplay->module = NULL;
+	audplay->callback = NULL;
+fail_audplay_get:
+	audplay = NULL;
+	audpp_put(audpp);
+done:
+	mutex_unlock(&audpp->lock);
+	return audplay;
+}
+
+void audplay_put(struct audplay *audplay)
+{
+	mutex_lock(&audplay->audpp->lock);
+	audplay->active = 0;
+	msm_adsp_disable(audplay->module);
+	msm_adsp_put(audplay->module);
+	audplay->module = NULL;
+	audplay->callback = NULL;
+	audpp_put(audplay->audpp);
+	mutex_unlock(&audplay->audpp->lock);
+}
+
+static void inline audplay_send_q1(struct audplay *audplay, void *cmd, int len) 
+{
+	msm_adsp_write(audplay->module, audplay->q1, cmd, len);
+}
+
+static void inline audpp_send_q1(struct audpp *audpp, void *cmd, int len) 
+{
+	msm_adsp_write(audpp->module, audpp->q1, cmd, len);
+}
+
+static void inline audpp_send_q2(struct audpp *audpp, void *cmd, int len) 
+{
+	msm_adsp_write(audpp->module, audpp->q2, cmd, len);
+}
+
+static void inline audpp_send_q3(struct audpp *audpp, void *cmd, int len) 
+{
+	msm_adsp_write(audpp->module, audpp->q3, cmd, len);
+}
+
+
+void audplay_config_pcm(struct audplay *audplay,
+			unsigned rate, unsigned width, unsigned channels)
+{
+	struct audpp_cmd_cfg_adec_params_wav cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN >> 1;
+	cmd.common.dec_id = audplay->id;
+	cmd.common.input_sampling_frequency = rate;
+	cmd.stereo_cfg = channels;
+	cmd.pcm_width = 1;
+	cmd.sign = 0; /* really? */
+	audpp_send_q2(audplay->audpp, &cmd, sizeof(cmd)); /* sizeof(cmd)?!*/
+}
+
+void audplay_dsp_config(struct audplay *audplay, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cmd;
+	int next;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC;
+	if (enable) {
+		cmd.dec_cfg |= AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_PCM;
+		next = STATUS_INIT;
+	} else {
+		cmd.dec_cfg |= AUDPP_CMD_DIS_DEC_V;
+		next = STATUS_SLEEP;
+	}
+	cmd.dm_mode = 0;
+	cmd.stream_id = audplay->id;
+
+	mutex_lock(&audplay->audpp->lock);
+	audpp_send_q1(audplay->audpp, &cmd, sizeof(cmd));
+	wait_event_timeout(audplay->wait, audplay->status == next, 5 * HZ);
+	mutex_unlock(&audplay->audpp->lock);
+}
+
+void audplay_send_data(struct audplay *audplay, unsigned phys, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+	cmd.decoder_id = audplay->id;
+	cmd.buf_ptr = phys;
+	cmd.buf_size = len/2;
+	cmd.partition_number = 0;
+
+	mutex_lock(&audplay->audpp->lock);
+	audplay_send_q1(audplay, &cmd, sizeof(cmd));
+	wait_event_timeout(audplay->wait, audplay->status == STATUS_PLAY, 5 * HZ);
+	mutex_unlock(&audplay->audpp->lock);
+}
+
+void audplay_mix_select(struct audplay *audplay, unsigned mix)
+{
+	struct audpp_cmd_cfg_dev_mixer_params cmd;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_CFG_DEV_MIXER;
+	cmd.stream_id = audplay->id;
+	cmd.mixer_cmd = mix;
+	audpp_send_q1(audplay->audpp, &cmd, sizeof(cmd));
+}
+
+void audplay_volume_pan(struct audplay *audplay, unsigned volume, unsigned pan)
+{
+#define AUDPP_CMD_VOLUME_PAN		0
+#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
+	uint16_t cmd[7];
+	cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	cmd[1] = AUDPP_CMD_POPP_STREAM;
+	cmd[2] = audplay->id;
+	cmd[3] = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd[4] = AUDPP_CMD_VOLUME_PAN;
+	cmd[5] = volume;
+	cmd[6] = pan;
+	audpp_send_q3(audplay->audpp, cmd, sizeof(cmd));
+}
+
+
+
+void adsp_audio_init(void)
+{
+	struct afe_info *afe = &the_afe_info;
+	struct audpp *audpp = &the_audpp;
+	int n;
+
+	mutex_init(&audpp->lock);
+	init_waitqueue_head(&audpp->wait);
+	for (n = 0; n < MAX_AUDPLAY_TASKS; n++) {
+		struct audplay *audplay = audpp->audplay + n;
+		audplay->id = n;
+		audplay->audpp = audpp;
+		init_waitqueue_head(&audplay->wait);
+	}
+
+	mutex_init(&afe->lock);
+	init_waitqueue_head(&afe->wait);
+}
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp_audio.h b/arch/arm/mach-msm/qdsp5v2/adsp_audio.h
new file mode 100644
index 0000000..4d52e7c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp_audio.h
@@ -0,0 +1,44 @@
+/* arch/arm/mach-msm/qdsp5v2/adsp_audio.h
+ *
+ * Copyright (C) 2010 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.
+ *
+ */
+
+#ifndef _MSM_ADSP_AUDIO_H_
+#define _MSM_ADSP_AUDIO_H_
+
+struct audplay;
+struct audpp;
+
+struct audplay *audplay_get(void (*cb)(void *cookie), void *cookie);
+void audplay_put(struct audplay *audplay);
+
+void audplay_send_data(struct audplay *audplay, unsigned phys, unsigned len);
+
+void audplay_dsp_config(struct audplay *audplay, int enable);
+void audplay_config_pcm(struct audplay *audplay,
+			unsigned rate, unsigned width, unsigned channels);
+
+
+void audplay_mix_select(struct audplay *audplay, unsigned mix);
+void audplay_volume_pan(struct audplay *audplay, unsigned volume, unsigned pan);
+
+
+int afe_enable(unsigned device, unsigned rate, unsigned channels);
+int afe_disable(unsigned device);
+
+
+int msm_codec_output(int enable);
+
+void adsp_audio_init(void);
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp_module_afe.h b/arch/arm/mach-msm/qdsp5v2/adsp_module_afe.h
new file mode 100644
index 0000000..eaa6139
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp_module_afe.h
@@ -0,0 +1,80 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef __ADSP_MODULE_AFE_H
+#define __ADSP_MODULE_AFE_H
+
+#define AFE_DEVICE_MI2S_CODEC_RX 1     /* internal codec rx path  */
+#define AFE_DEVICE_MI2S_CODEC_TX 2     /* internal codec tx path  */
+#define AFE_DEVICE_AUX_CODEC_RX  3     /* external codec rx path  */
+#define AFE_DEVICE_AUX_CODEC_TX  4     /* external codec tx path  */
+#define AFE_DEVICE_MI2S_HDMI_RX  5     /* HDMI/FM block rx path   */
+#define AFE_DEVICE_MI2S_HDMI_TX  6     /* HDMI/FM block tx path   */
+#define AFE_DEVICE_ID_MAX        7
+
+#define AFE_VOLUME_UNITY 0x4000 /* Q14 format */
+
+#define AFE_CMD_CODEC_CONFIG_CMD     0x1
+#define AFE_CMD_CODEC_CONFIG_LEN sizeof(struct afe_cmd_codec_config)
+
+struct afe_cmd_codec_config{
+	uint16_t cmd_id;
+	uint16_t device_id;
+	uint16_t activity;
+	uint16_t sample_rate;
+	uint16_t channel_mode;
+	uint16_t volume;
+	uint16_t reserved;
+} __attribute__ ((packed));
+
+#define AFE_CMD_AUX_CODEC_CONFIG_CMD 	0x3
+#define AFE_CMD_AUX_CODEC_CONFIG_LEN sizeof(struct afe_cmd_aux_codec_config)
+
+struct afe_cmd_aux_codec_config{
+	uint16_t cmd_id;
+	uint16_t dma_path_ctl;
+	uint16_t pcm_ctl;
+	uint16_t eight_khz_int_mode;
+	uint16_t aux_codec_intf_ctl;
+	uint16_t data_format_padding_info;
+} __attribute__ ((packed));
+
+#define AFE_MSG_CODEC_CONFIG_ACK		0x0001
+#define AFE_MSG_CODEC_CONFIG_ACK_LEN	\
+	sizeof(struct afe_msg_codec_config_ack)
+
+#define AFE_MSG_CODEC_CONFIG_ENABLED 0x1
+#define AFE_MSG_CODEC_CONFIG_DISABLED 0xFFFF
+
+struct afe_msg_codec_config_ack {
+	uint16_t device_id;
+	uint16_t device_activity;
+} __attribute__((packed));
+
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp_module_audplay.h b/arch/arm/mach-msm/qdsp5v2/adsp_module_audplay.h
new file mode 100644
index 0000000..7a67ded
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp_module_audplay.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1992-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.
+ *
+ */
+
+#ifndef __ADSP_MODULE_AUDPLAY
+#define __ADSP_MODULE_AUDPLAY
+
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL		0x0000
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_LEN	\
+	sizeof(struct audplay_cmd_bitstream_data_avail)
+
+/* Type specification of dec_data_avail message sent to AUDPLAYTASK
+*/
+struct audplay_cmd_bitstream_data_avail{
+	/*command ID*/
+	unsigned int cmd_id;
+
+	/* Decoder ID for which message is being sent */
+	unsigned int decoder_id;
+
+	/* Start address of data in ARM global memory */
+	unsigned int buf_ptr;
+
+	/* Number of 16-bit words of bit-stream data contiguously
+	* available at the above-mentioned address
+	*/
+	unsigned int buf_size;
+
+	/* Partition number used by audPlayTask to communicate with DSP's RTOS
+	* kernel
+	*/
+	unsigned int partition_number;
+
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_CHANNEL_INFO 0x0001
+#define AUDPLAY_CMD_CHANNEL_INFO_LEN \
+  sizeof(struct audplay_cmd_channel_info)
+
+struct audplay_cmd_channel_select {
+  unsigned int cmd_id;
+  unsigned int stream_id;
+  unsigned int channel_select;
+} __attribute__((packed));
+
+struct audplay_cmd_threshold_update {
+  unsigned int cmd_id;
+  unsigned int threshold_update;
+  unsigned int threshold_value;
+} __attribute__((packed));
+
+union audplay_cmd_channel_info {
+  struct audplay_cmd_channel_select ch_select;
+  struct audplay_cmd_threshold_update thr_update;
+};
+
+#define AUDPLAY_CMD_HPCM_BUF_CFG 0x0003
+#define AUDPLAY_CMD_HPCM_BUF_CFG_LEN \
+  sizeof(struct audplay_cmd_hpcm_buf_cfg)
+
+struct audplay_cmd_hpcm_buf_cfg {
+	unsigned int cmd_id;
+	unsigned int hostpcm_config;
+	unsigned int feedback_frequency;
+	unsigned int byte_swap;
+	unsigned int max_buffers;
+	unsigned int partition_number;
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_BUFFER_REFRESH 0x0004
+#define AUDPLAY_CMD_BUFFER_REFRESH_LEN \
+  sizeof(struct audplay_cmd_buffer_update)
+
+struct audplay_cmd_buffer_refresh {
+	unsigned int cmd_id;
+	unsigned int num_buffers;
+	unsigned int buf_read_count;
+	unsigned int buf0_address;
+	unsigned int buf0_length;
+	unsigned int buf1_address;
+	unsigned int buf1_length;
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2            0x0005
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2_LEN    \
+	sizeof(struct audplay_cmd_bitstream_data_avail_nt2)
+
+/* Type specification of dec_data_avail message sent to AUDPLAYTASK
+ * for NT2 */
+struct audplay_cmd_bitstream_data_avail_nt2 {
+	/*command ID*/
+	unsigned int cmd_id;
+
+	/* Decoder ID for which message is being sent */
+	unsigned int decoder_id;
+
+	/* Start address of data in ARM global memory */
+	unsigned int buf_ptr;
+
+	/* Number of 16-bit words of bit-stream data contiguously
+	*  available at the above-mentioned address
+	*/
+	unsigned int buf_size;
+
+	/* Partition number used by audPlayTask to communicate with DSP's RTOS
+	* kernel
+	*/
+	unsigned int partition_number;
+
+	/* bitstream write pointer */
+	unsigned int dspBitstreamWritePtr;
+
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_OUTPORT_FLUSH 0x0006
+
+struct audplay_cmd_outport_flush {
+	unsigned int cmd_id;
+} __attribute__((packed));
+
+
+/* messages from dsp to apps */
+
+#define AUDPLAY_MSG_DEC_NEEDS_DATA		0x0001
+#define AUDPLAY_MSG_DEC_NEEDS_DATA_MSG_LEN	\
+	sizeof(audplay_msg_dec_needs_data)
+
+struct audplay_msg_dec_needs_data {
+	/* reserved*/
+	unsigned int dec_id;
+
+	/*The read pointer offset of external memory till which bitstream
+	has been dmed in*/
+	unsigned int adecDataReadPtrOffset;
+
+	/*The buffer size of external memory. */
+	unsigned int adecDataBufSize;
+
+	unsigned int 	bitstream_free_len;
+	unsigned int	bitstream_write_ptr;
+	unsigned int	bitstream_buf_start;
+	unsigned int	bitstream_buf_len;
+} __attribute__((packed));
+
+#define AUDPLAY_UP_STREAM_INFO 0x0003
+#define AUDPLAY_UP_STREAM_INFO_LEN \
+	sizeof(struct audplay_msg_stream_info)
+
+struct audplay_msg_stream_info {
+	unsigned int decoder_id;
+	unsigned int channel_info;
+	unsigned int sample_freq;
+	unsigned int bitstream_info;
+	unsigned int bit_rate;
+} __attribute__((packed));
+
+#define AUDPLAY_MSG_BUFFER_UPDATE 0x0004
+#define AUDPLAY_MSG_BUFFER_UPDATE_LEN \
+	sizeof(struct audplay_msg_buffer_update)
+
+struct audplay_msg_buffer_update {
+	unsigned int buffer_write_count;
+	unsigned int num_of_buffer;
+	unsigned int buf0_address;
+	unsigned int buf0_length;
+	unsigned int buf1_address;
+	unsigned int buf1_length;
+} __attribute__((packed));
+
+#define AUDPLAY_UP_OUTPORT_FLUSH_ACK 0x0005
+
+#define ADSP_MESSAGE_ID 0xFFFF
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp_module_audpp.h b/arch/arm/mach-msm/qdsp5v2/adsp_module_audpp.h
new file mode 100644
index 0000000..8f278cf
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp_module_audpp.h
@@ -0,0 +1,1250 @@
+/*
+ * Copyright (c) 1992-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.
+ *
+ */
+
+#ifndef __ADSP_MODULE_AUDPP
+#define __ADSP_MODULE_AUDPP
+
+/*
+ * ARM to AUDPPTASK Commands
+ *
+ * ARM uses three command queues to communicate with AUDPPTASK
+ * 1)uPAudPPCmd1Queue : Used for more frequent and shorter length commands
+ * 	Location : MEMA
+ * 	Buffer Size : 6 words
+ * 	No of buffers in a queue : 20 for gaming audio and 5 for other images
+ * 2)uPAudPPCmd2Queue : Used for commands which are not much lengthier
+ * 	Location : MEMA
+ * 	Buffer Size : 23
+ * 	No of buffers in a queue : 2
+ * 3)uPAudOOCmd3Queue : Used for lengthier and more frequent commands
+ * 	Location : MEMA
+ * 	Buffer Size : 145
+ * 	No of buffers in a queue : 3
+ */
+
+/*
+ * Commands Related to uPAudPPCmd1Queue
+ */
+
+/*
+ * Command Structure to enable or disable the active decoders
+ */
+
+#define AUDPP_CMD_CFG_DEC_TYPE 		0x0001
+#define AUDPP_CMD_CFG_DEC_TYPE_LEN 	sizeof(struct audpp_cmd_cfg_dec_type)
+
+/* Enable the decoder */
+#define AUDPP_CMD_DEC_TYPE_M           	0x000F
+
+#define AUDPP_CMD_ENA_DEC_V         	0x4000
+#define AUDPP_CMD_DIS_DEC_V        	0x0000
+#define AUDPP_CMD_DEC_STATE_M          	0x4000
+
+#define AUDPP_CMD_UPDATDE_CFG_DEC	0x8000
+#define AUDPP_CMD_DONT_UPDATE_CFG_DEC	0x0000
+
+
+/* Type specification of cmd_cfg_dec */
+
+struct audpp_cmd_cfg_dec_type {
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short dec_cfg;
+	unsigned short dm_mode;
+} __attribute__((packed));
+
+/*
+ * Command Structure to Pause , Resume and flushes the selected audio decoders
+ */
+
+#define AUDPP_CMD_DEC_CTRL		0x0002
+#define AUDPP_CMD_DEC_CTRL_LEN		sizeof(struct audpp_cmd_dec_ctrl)
+
+/* Decoder control commands for pause, resume and flush */
+#define AUDPP_CMD_FLUSH_V         		0x2000
+
+#define AUDPP_CMD_PAUSE_V		        0x4000
+#define AUDPP_CMD_RESUME_V		        0x0000
+
+#define AUDPP_CMD_UPDATE_V		        0x8000
+#define AUDPP_CMD_IGNORE_V		        0x0000
+
+
+/* Type Spec for decoder control command*/
+
+struct audpp_cmd_dec_ctrl{
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short dec_ctrl;
+} __attribute__((packed));
+
+/*
+ * Command Structure to Configure the AVSync FeedBack Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC	0x0003
+#define AUDPP_CMD_AVSYNC_LEN	sizeof(struct audpp_cmd_avsync)
+
+struct audpp_cmd_avsync{
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short interrupt_interval;
+	unsigned short sample_counter_dlsw;
+	unsigned short sample_counter_dmsw;
+	unsigned short sample_counter_msw;
+	unsigned short byte_counter_dlsw;
+	unsigned short byte_counter_dmsw;
+	unsigned short byte_counter_msw;
+} __attribute__((packed));
+
+/*
+ * Command Structure to enable or disable(sleep) the AUDPPTASK
+ */
+
+#define AUDPP_CMD_CFG	0x0004
+#define AUDPP_CMD_CFG_LEN	sizeof(struct audpp_cmd_cfg)
+
+#define AUDPP_CMD_CFG_SLEEP   				0x0000
+#define AUDPP_CMD_CFG_ENABLE  				0xFFFF
+
+struct audpp_cmd_cfg {
+	unsigned short cmd_id;
+	unsigned short cfg;
+} __attribute__((packed));
+
+/*
+ * Command Structure to Inject or drop the specified no of samples
+ */
+
+#define AUDPP_CMD_ADJUST_SAMP		0x0005
+#define AUDPP_CMD_ADJUST_SAMP_LEN	sizeof(struct audpp_cmd_adjust_samp)
+
+#define AUDPP_CMD_SAMP_DROP		-1
+#define AUDPP_CMD_SAMP_INSERT		0x0001
+
+#define AUDPP_CMD_NUM_SAMPLES		0x0001
+
+struct audpp_cmd_adjust_samp {
+	unsigned short cmd_id;
+	unsigned short object_no;
+	signed short sample_insert_or_drop;
+	unsigned short num_samples;
+} __attribute__((packed));
+
+/*
+ * Command Structure to Configure AVSync Feedback Mechanism
+ */
+
+#define AUDPP_CMD_ROUTING_MODE      0x0007
+#define AUDPP_CMD_ROUTING_MODE_LEN  \
+sizeof(struct audpp_cmd_routing_mode)
+
+struct audpp_cmd_routing_mode {
+	unsigned short cmd_id;
+	unsigned short object_number;
+	unsigned short routing_mode;
+} __attribute__((packed));
+
+/*
+ * Commands Related to uPAudPPCmd2Queue
+ */
+
+/*
+ * Command Structure to configure Per decoder Parameters (Common)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS 		0x0000
+#define AUDPP_CMD_CFG_ADEC_PARAMS_COMMON_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_common)
+
+#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_FCM	0x4000
+#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_FCM	0x0000
+
+#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_DCM	0x8000
+#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_DCM	0x0000
+
+/* Sampling frequency*/
+#define  AUDPP_CMD_SAMP_RATE_96000 	0x0000
+#define  AUDPP_CMD_SAMP_RATE_88200 	0x0001
+#define  AUDPP_CMD_SAMP_RATE_64000 	0x0002
+#define  AUDPP_CMD_SAMP_RATE_48000 	0x0003
+#define  AUDPP_CMD_SAMP_RATE_44100 	0x0004
+#define  AUDPP_CMD_SAMP_RATE_32000 	0x0005
+#define  AUDPP_CMD_SAMP_RATE_24000 	0x0006
+#define  AUDPP_CMD_SAMP_RATE_22050 	0x0007
+#define  AUDPP_CMD_SAMP_RATE_16000 	0x0008
+#define  AUDPP_CMD_SAMP_RATE_12000 	0x0009
+#define  AUDPP_CMD_SAMP_RATE_11025 	0x000A
+#define  AUDPP_CMD_SAMP_RATE_8000  	0x000B
+
+
+/*
+ * Type specification of cmd_adec_cfg sent to all decoder
+ */
+
+struct audpp_cmd_cfg_adec_params_common {
+	unsigned short  cmd_id;
+	unsigned short  dec_id;
+	unsigned short  length;
+	unsigned short  reserved;
+	unsigned short  input_sampling_frequency;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (Wav)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_wav)
+
+
+#define	AUDPP_CMD_WAV_STEREO_CFG_MONO	0x0001
+#define AUDPP_CMD_WAV_STEREO_CFG_STEREO	0x0002
+
+#define AUDPP_CMD_WAV_PCM_WIDTH_8	0x0000
+#define AUDPP_CMD_WAV_PCM_WIDTH_16	0x0001
+#define AUDPP_CMD_WAV_PCM_WIDTH_24	0x0002
+
+struct audpp_cmd_cfg_adec_params_wav {
+	struct audpp_cmd_cfg_adec_params_common		common;
+	unsigned short					stereo_cfg;
+	unsigned short					pcm_width;
+	unsigned short 					sign;
+} __attribute__((packed));
+
+/*
+ *  Command Structure for CMD_CFG_DEV_MIXER
+ */
+
+#define AUDPP_CMD_CFG_DEV_MIXER_PARAMS_LEN \
+	sizeof(struct audpp_cmd_cfg_dev_mixer_params)
+
+#define AUDPP_CMD_CFG_DEV_MIXER            0x0008
+
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_NONE   0x0000
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_0      0x0001
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_1      0x0002
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_2      0x0004
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_3      0x0008
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_4      0x0010
+
+struct audpp_cmd_cfg_dev_mixer_params {
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short mixer_cmd;
+} __attribute__((packed));
+
+
+/*
+ * Command Structure to configure Per decoder Parameters (ADPCM)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_ADPCM_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_adpcm)
+
+
+#define	AUDPP_CMD_ADPCM_STEREO_CFG_MONO		0x0001
+#define AUDPP_CMD_ADPCM_STEREO_CFG_STEREO	0x0002
+
+struct audpp_cmd_cfg_adec_params_adpcm {
+	struct audpp_cmd_cfg_adec_params_common		common;
+	unsigned short					stereo_cfg;
+	unsigned short 					block_size;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (WMA)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WMA_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_wma)
+
+struct audpp_cmd_cfg_adec_params_wma {
+	struct audpp_cmd_cfg_adec_params_common    common;
+	unsigned short 	armdatareqthr;
+	unsigned short 	channelsdecoded;
+	unsigned short 	wmabytespersec;
+	unsigned short	wmasamplingfreq;
+	unsigned short	wmaencoderopts;
+} __attribute__((packed));
+
+
+/*
+ * Command Structure to configure Per decoder Parameters (MP3)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_mp3)
+
+struct audpp_cmd_cfg_adec_params_mp3 {
+	struct audpp_cmd_cfg_adec_params_common    common;
+} __attribute__((packed));
+
+
+/*
+ * Command Structure to configure Per decoder Parameters (AAC)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AAC_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_aac)
+
+
+#define AUDPP_CMD_AAC_FORMAT_ADTS		-1
+#define	AUDPP_CMD_AAC_FORMAT_RAW		0x0000
+#define	AUDPP_CMD_AAC_FORMAT_PSUEDO_RAW		0x0001
+#define	AUDPP_CMD_AAC_FORMAT_LOAS		0x0002
+
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_LC		0x0002
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_LTP		0x0004
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_ERLC	0x0011
+
+#define AUDPP_CMD_AAC_SBR_ON_FLAG_ON		0x0001
+#define AUDPP_CMD_AAC_SBR_ON_FLAG_OFF		0x0000
+
+#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_ON		0x0001
+#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_OFF	0x0000
+
+struct audpp_cmd_cfg_adec_params_aac {
+	struct audpp_cmd_cfg_adec_params_common	common;
+	signed short			format;
+	unsigned short			audio_object;
+	unsigned short			ep_config;
+	unsigned short                  aac_section_data_resilience_flag;
+	unsigned short                  aac_scalefactor_data_resilience_flag;
+	unsigned short                  aac_spectral_data_resilience_flag;
+	unsigned short                  sbr_on_flag;
+	unsigned short                  sbr_ps_on_flag;
+	unsigned short                  channel_configuration;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (V13K)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_v13k)
+
+
+#define AUDPP_CMD_STEREO_CFG_MONO		0x0001
+#define AUDPP_CMD_STEREO_CFG_STEREO		0x0002
+
+struct audpp_cmd_cfg_adec_params_v13k {
+	struct audpp_cmd_cfg_adec_params_common    	common;
+	unsigned short			stereo_cfg;
+} __attribute__((packed));
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_EVRC_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_evrc)
+
+struct audpp_cmd_cfg_adec_params_evrc {
+	struct audpp_cmd_cfg_adec_params_common common;
+	unsigned short stereo_cfg;
+} __attribute__ ((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (AMRWB)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AMRWB_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_amrwb)
+
+struct audpp_cmd_cfg_adec_params_amrwb {
+	struct audpp_cmd_cfg_adec_params_common    	common;
+	unsigned short			stereo_cfg;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (WMAPRO)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WMAPRO_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_wmapro)
+
+struct audpp_cmd_cfg_adec_params_wmapro {
+	struct audpp_cmd_cfg_adec_params_common    common;
+	unsigned short 	armdatareqthr;
+	uint8_t         validbitspersample;
+	uint8_t         numchannels;
+	unsigned short  formattag;
+	unsigned short  samplingrate;
+	unsigned short  avgbytespersecond;
+	unsigned short  asfpacketlength;
+	unsigned short 	channelmask;
+	unsigned short 	encodeopt;
+	unsigned short	advancedencodeopt;
+	uint32_t	advancedencodeopt2;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure the  HOST PCM interface
+ */
+
+#define AUDPP_CMD_PCM_INTF	0x0001
+#define AUDPP_CMD_PCM_INTF_2	0x0002
+#define AUDPP_CMD_PCM_INTF_LEN	sizeof(struct audpp_cmd_pcm_intf)
+
+#define AUDPP_CMD_PCM_INTF_MONO_V		        0x0001
+#define AUDPP_CMD_PCM_INTF_STEREO_V         	0x0002
+
+/* These two values differentiate the two types of commands that could be issued
+ * Interface configuration command and Buffer update command */
+
+#define AUDPP_CMD_PCM_INTF_CONFIG_CMD_V	       	0x0000
+#define AUDPP_CMD_PCM_INTF_BUFFER_CMD_V	        -1
+
+#define AUDPP_CMD_PCM_INTF_RX_ENA_M              0x000F
+#define AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V     0x0008
+#define AUDPP_CMD_PCM_INTF_RX_ENA_DSPTOARM_V     0x0004
+
+/* These flags control the enabling and disabling of the interface together
+ *  with host interface bit mask. */
+
+#define AUDPP_CMD_PCM_INTF_ENA_V            -1
+#define AUDPP_CMD_PCM_INTF_DIS_V            0x0000
+
+
+#define  AUDPP_CMD_PCM_INTF_FULL_DUPLEX           0x0
+#define  AUDPP_CMD_PCM_INTF_HALF_DUPLEX_TODSP     0x1
+
+
+#define  AUDPP_CMD_PCM_INTF_OBJECT_NUM           0x5
+#define  AUDPP_CMD_PCM_INTF_COMMON_OBJECT_NUM    0x6
+
+struct audpp_cmd_pcm_intf {
+	unsigned short  cmd_id;
+	unsigned short  stream;
+	unsigned short  stream_id;
+	signed short  config;
+	unsigned short  intf_type;
+
+	/* DSP -> ARM Configuration */
+	unsigned short  read_buf1LSW;
+	unsigned short  read_buf1MSW;
+	unsigned short  read_buf1_len;
+
+	unsigned short  read_buf2LSW;
+	unsigned short  read_buf2MSW;
+	unsigned short  read_buf2_len;
+	/*   0:HOST_PCM_INTF disable
+	**  0xFFFF: HOST_PCM_INTF enable
+	*/
+	signed short  dsp_to_arm_flag;
+	unsigned short  partition_number;
+
+	/* ARM -> DSP Configuration */
+	unsigned short  write_buf1LSW;
+	unsigned short  write_buf1MSW;
+	unsigned short  write_buf1_len;
+
+	unsigned short  write_buf2LSW;
+	unsigned short  write_buf2MSW;
+	unsigned short  write_buf2_len;
+
+	/*   0:HOST_PCM_INTF disable
+	**  0xFFFF: HOST_PCM_INTF enable
+	*/
+	signed short  arm_to_rx_flag;
+	unsigned short  weight_decoder_to_rx;
+	unsigned short  weight_arm_to_rx;
+
+	unsigned short  partition_number_arm_to_dsp;
+	unsigned short  sample_rate;
+	unsigned short  channel_mode;
+} __attribute__((packed));
+
+/*
+ **  BUFFER UPDATE COMMAND
+ */
+#define AUDPP_CMD_PCM_INTF_SEND_BUF_PARAMS_LEN	\
+	sizeof(struct audpp_cmd_pcm_intf_send_buffer)
+
+struct audpp_cmd_pcm_intf_send_buffer {
+	unsigned short  cmd_id;
+	unsigned short  stream;
+	unsigned short  stream_id;
+	/* set config = 0xFFFF for configuration*/
+	signed short  config;
+	unsigned short  intf_type;
+	unsigned short  dsp_to_arm_buf_id;
+	unsigned short  arm_to_dsp_buf_id;
+	unsigned short  arm_to_dsp_buf_len;
+} __attribute__((packed));
+
+
+/*
+ * Commands Related to uPAudPPCmd3Queue
+ */
+
+/*
+ * Command Structure to configure post processing params (Commmon)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS		0x0000
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_common)
+
+#define AUDPP_CMD_OBJ0_UPDATE		0x8000
+#define AUDPP_CMD_OBJ0_DONT_UPDATE	0x0000
+
+
+#define AUDPP_CMD_OBJ2_UPDATE		0x8000
+#define AUDPP_CMD_OBJ2_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ3_UPDATE		0x8000
+#define AUDPP_CMD_OBJ3_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ4_UPDATE		0x8000
+#define AUDPP_CMD_OBJ4_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_HPCM_UPDATE		0x8000
+#define AUDPP_CMD_HPCM_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_COMMON_CFG_UPDATE		0x8000
+#define AUDPP_CMD_COMMON_CFG_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_POPP_STREAM   0xFFFF
+#define AUDPP_CMD_COPP_STREAM   0x0000
+
+struct audpp_cmd_cfg_object_params_common{
+	unsigned short  cmd_id;
+	unsigned short	stream;
+	unsigned short	stream_id;
+	unsigned short	obj_cfg;
+	unsigned short	command_type;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing params (Volume)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_VOLUME_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_volume)
+
+struct audpp_cmd_cfg_object_params_volume {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	unsigned short					volume;
+	unsigned short					pan;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing params (PCM Filter)
+ */
+
+struct numerator {
+	unsigned short			numerator_b0_filter_lsw;
+	unsigned short			numerator_b0_filter_msw;
+	unsigned short			numerator_b1_filter_lsw;
+	unsigned short			numerator_b1_filter_msw;
+	unsigned short			numerator_b2_filter_lsw;
+	unsigned short			numerator_b2_filter_msw;
+} __attribute__((packed));
+
+struct denominator {
+	unsigned short			denominator_a0_filter_lsw;
+	unsigned short			denominator_a0_filter_msw;
+	unsigned short			denominator_a1_filter_lsw;
+	unsigned short			denominator_a1_filter_msw;
+} __attribute__((packed));
+
+struct shift_factor {
+	unsigned short			shift_factor_0;
+} __attribute__((packed));
+
+struct pan {
+	unsigned short			pan_filter_0;
+} __attribute__((packed));
+
+struct filter_1 {
+	struct numerator		numerator_filter;
+	struct denominator		denominator_filter;
+	struct shift_factor		shift_factor_filter;
+	struct pan			pan_filter;
+} __attribute__((packed));
+
+struct filter_2 {
+	struct numerator		numerator_filter[2];
+	struct denominator		denominator_filter[2];
+	struct shift_factor		shift_factor_filter[2];
+	struct pan			pan_filter[2];
+} __attribute__((packed));
+
+struct filter_3 {
+	struct numerator		numerator_filter[3];
+	struct denominator		denominator_filter[3];
+	struct shift_factor		shift_factor_filter[3];
+	struct pan			pan_filter[3];
+} __attribute__((packed));
+
+struct filter_4 {
+	struct numerator		numerator_filter[4];
+	struct denominator		denominator_filter[4];
+	struct shift_factor		shift_factor_filter[4];
+	struct pan			pan_filter[4];
+} __attribute__((packed));
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_PCM_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_pcm)
+
+
+struct audpp_cmd_cfg_object_params_pcm {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short				active_flag;
+	unsigned short 				num_bands;
+	union {
+		struct filter_1			filter_1_params;
+		struct filter_2			filter_2_params;
+		struct filter_3			filter_3_params;
+		struct filter_4			filter_4_params;
+	} __attribute__((packed)) params_filter;
+} __attribute__((packed));
+
+
+/*
+ * Command Structure to configure post processing parameters (equalizer)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_EQALIZER_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_eqalizer)
+
+struct eq_numerator {
+	unsigned short			numerator_coeff_0_lsw;
+	unsigned short			numerator_coeff_0_msw;
+	unsigned short			numerator_coeff_1_lsw;
+	unsigned short			numerator_coeff_1_msw;
+	unsigned short			numerator_coeff_2_lsw;
+	unsigned short			numerator_coeff_2_msw;
+} __attribute__((packed));
+
+struct eq_denominator {
+	unsigned short			denominator_coeff_0_lsw;
+	unsigned short			denominator_coeff_0_msw;
+	unsigned short			denominator_coeff_1_lsw;
+	unsigned short			denominator_coeff_1_msw;
+} __attribute__((packed));
+
+struct eq_shiftfactor {
+	unsigned short			shift_factor;
+} __attribute__((packed));
+
+struct eq_coeff_1 {
+	struct eq_numerator	numerator;
+	struct eq_denominator	denominator;
+	struct eq_shiftfactor	shiftfactor;
+} __attribute__((packed));
+
+struct eq_coeff_2 {
+	struct eq_numerator	numerator[2];
+	struct eq_denominator	denominator[2];
+	struct eq_shiftfactor	shiftfactor[2];
+} __attribute__((packed));
+
+struct eq_coeff_3 {
+	struct eq_numerator	numerator[3];
+	struct eq_denominator	denominator[3];
+	struct eq_shiftfactor	shiftfactor[3];
+} __attribute__((packed));
+
+struct eq_coeff_4 {
+	struct eq_numerator	numerator[4];
+	struct eq_denominator	denominator[4];
+	struct eq_shiftfactor	shiftfactor[4];
+} __attribute__((packed));
+
+struct eq_coeff_5 {
+	struct eq_numerator	numerator[5];
+	struct eq_denominator	denominator[5];
+	struct eq_shiftfactor	shiftfactor[5];
+} __attribute__((packed));
+
+struct eq_coeff_6 {
+	struct eq_numerator	numerator[6];
+	struct eq_denominator	denominator[6];
+	struct eq_shiftfactor	shiftfactor[6];
+} __attribute__((packed));
+
+struct eq_coeff_7 {
+	struct eq_numerator	numerator[7];
+	struct eq_denominator	denominator[7];
+	struct eq_shiftfactor	shiftfactor[7];
+} __attribute__((packed));
+
+struct eq_coeff_8 {
+	struct eq_numerator	numerator[8];
+	struct eq_denominator	denominator[8];
+	struct eq_shiftfactor	shiftfactor[8];
+} __attribute__((packed));
+
+struct eq_coeff_9 {
+	struct eq_numerator	numerator[9];
+	struct eq_denominator	denominator[9];
+	struct eq_shiftfactor	shiftfactor[9];
+} __attribute__((packed));
+
+struct eq_coeff_10 {
+	struct eq_numerator	numerator[10];
+	struct eq_denominator	denominator[10];
+	struct eq_shiftfactor	shiftfactor[10];
+} __attribute__((packed));
+
+struct eq_coeff_11 {
+	struct eq_numerator	numerator[11];
+	struct eq_denominator	denominator[11];
+	struct eq_shiftfactor	shiftfactor[11];
+} __attribute__((packed));
+
+struct eq_coeff_12 {
+	struct eq_numerator	numerator[12];
+	struct eq_denominator	denominator[12];
+	struct eq_shiftfactor	shiftfactor[12];
+} __attribute__((packed));
+
+
+struct audpp_cmd_cfg_object_params_eqalizer {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short				eq_flag;
+	unsigned short				num_bands;
+	union {
+		struct eq_coeff_1	eq_coeffs_1;
+		struct eq_coeff_2	eq_coeffs_2;
+		struct eq_coeff_3	eq_coeffs_3;
+		struct eq_coeff_4	eq_coeffs_4;
+		struct eq_coeff_5	eq_coeffs_5;
+		struct eq_coeff_6	eq_coeffs_6;
+		struct eq_coeff_7	eq_coeffs_7;
+		struct eq_coeff_8	eq_coeffs_8;
+		struct eq_coeff_9	eq_coeffs_9;
+		struct eq_coeff_10	eq_coeffs_10;
+		struct eq_coeff_11	eq_coeffs_11;
+		struct eq_coeff_12	eq_coeffs_12;
+	} __attribute__((packed)) eq_coeff;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing parameters (ADRC)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_ADRC_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_adrc)
+
+
+#define AUDPP_CMD_ADRC_FLAG_DIS		0x0000
+#define AUDPP_CMD_ADRC_FLAG_ENA		-1
+
+struct audpp_cmd_cfg_object_params_adrc {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short		adrc_flag;
+	unsigned short	compression_th;
+	unsigned short	compression_slope;
+	unsigned short	rms_time;
+	unsigned short	attack_const_lsw;
+	unsigned short	attack_const_msw;
+	unsigned short	release_const_lsw;
+	unsigned short	release_const_msw;
+	unsigned short	adrc_delay;
+};
+
+/*
+ * Command Structure to configure post processing parameters (MB - ADRC)
+ */
+
+#define	AUDPP_MAX_MBADRC_BANDS		5
+
+struct adrc_config {
+	uint16_t subband_enable;
+	uint16_t adrc_sub_mute;
+	uint16_t rms_time;
+	uint16_t compression_th;
+	uint16_t compression_slope;
+	uint16_t attack_const_lsw;
+	uint16_t attack_const_msw;
+	uint16_t release_const_lsw;
+	uint16_t release_const_msw;
+	uint16_t makeup_gain;
+};
+
+struct audpp_cmd_cfg_object_params_mbadrc {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	uint16_t enable;
+	uint16_t num_bands;
+	uint16_t down_samp_level;
+	uint16_t adrc_delay;
+	uint16_t ext_buf_size;
+	uint16_t ext_partition;
+	uint16_t ext_buf_msw;
+	uint16_t ext_buf_lsw;
+	struct adrc_config adrc_band[AUDPP_MAX_MBADRC_BANDS];
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing parameters(Spectrum Analizer)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_SPECTRAM_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_spectram)
+
+
+struct audpp_cmd_cfg_object_params_spectram {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	unsigned short				sample_interval;
+	unsigned short				num_coeff;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing parameters (QConcert)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_QCONCERT_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_qconcert)
+
+
+#define AUDPP_CMD_QCON_ENA_FLAG_ENA		-1
+#define AUDPP_CMD_QCON_ENA_FLAG_DIS		0x0000
+
+#define AUDPP_CMD_QCON_OP_MODE_HEADPHONE	-1
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_FRONT	0x0000
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_SIDE	0x0001
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_DESKTOP	0x0002
+
+#define AUDPP_CMD_QCON_GAIN_UNIT			0x7FFF
+#define AUDPP_CMD_QCON_GAIN_SIX_DB			0x4027
+
+
+#define AUDPP_CMD_QCON_EXPANSION_MAX		0x7FFF
+
+
+struct audpp_cmd_cfg_object_params_qconcert {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short				enable_flag;
+	signed short				op_mode;
+	signed short				gain;
+	signed short				expansion;
+	signed short				delay;
+	unsigned short				stages_per_mode;
+	unsigned short				reverb_enable;
+	unsigned short				decay_msw;
+	unsigned short				decay_lsw;
+	unsigned short				decay_time_ratio_msw;
+	unsigned short				decay_time_ratio_lsw;
+	unsigned short				reflection_delay_time;
+	unsigned short				late_reverb_gain;
+	unsigned short				late_reverb_delay;
+	unsigned short                          delay_buff_size_msw;
+	unsigned short                          delay_buff_size_lsw;
+	unsigned short                          partition_num;
+	unsigned short                          delay_buff_start_msw;
+	unsigned short                          delay_buff_start_lsw;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing parameters (Side Chain)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_SIDECHAIN_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_sidechain)
+
+
+#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_DIS	0x0000
+#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_ENA	-1
+
+struct audpp_cmd_cfg_object_params_sidechain {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short				active_flag;
+	unsigned short				num_bands;
+	union {
+		struct filter_1			filter_1_params;
+		struct filter_2			filter_2_params;
+		struct filter_3			filter_3_params;
+		struct filter_4			filter_4_params;
+	} __attribute__((packed)) params_filter;
+} __attribute__((packed));
+
+
+/*
+ * Command Structure to configure post processing parameters (QAFX)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_QAFX_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_qafx)
+
+#define AUDPP_CMD_QAFX_ENA_DISA		0x0000
+#define AUDPP_CMD_QAFX_ENA_ENA_CFG	-1
+#define AUDPP_CMD_QAFX_ENA_DIS_CFG	0x0001
+
+#define AUDPP_CMD_QAFX_CMD_TYPE_ENV	0x0100
+#define AUDPP_CMD_QAFX_CMD_TYPE_OBJ	0x0010
+#define AUDPP_CMD_QAFX_CMD_TYPE_QUERY	0x1000
+
+#define AUDPP_CMD_QAFX_CMDS_ENV_OP_MODE	0x0100
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_POS	0x0101
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_ORI	0x0102
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_VEL	0X0103
+#define AUDPP_CMD_QAFX_CMDS_ENV_ENV_RES	0x0107
+
+#define AUDPP_CMD_QAFX_CMDS_OBJ_SAMP_FREQ	0x0010
+#define AUDPP_CMD_QAFX_CMDS_OBJ_VOL		0x0011
+#define AUDPP_CMD_QAFX_CMDS_OBJ_DIST		0x0012
+#define AUDPP_CMD_QAFX_CMDS_OBJ_POS		0x0013
+#define AUDPP_CMD_QAFX_CMDS_OBJ_VEL		0x0014
+
+
+struct audpp_cmd_cfg_object_params_qafx {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short				enable;
+	unsigned short				command_type;
+	unsigned short				num_commands;
+	unsigned short				commands;
+} __attribute__((packed));
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (REVERB) (Common)
+ */
+
+#define AUDPP_CMD_REVERB_CONFIG		0x0001
+#define	AUDPP_CMD_REVERB_CONFIG_COMMON_LEN	\
+	sizeof(struct audpp_cmd_reverb_config_common)
+
+#define AUDPP_CMD_ENA_ENA	0xFFFF
+#define AUDPP_CMD_ENA_DIS	0x0000
+#define AUDPP_CMD_ENA_CFG	0x0001
+
+#define AUDPP_CMD_CMD_TYPE_ENV		0x0104
+#define AUDPP_CMD_CMD_TYPE_OBJ		0x0015
+#define AUDPP_CMD_CMD_TYPE_QUERY	0x1000
+
+
+struct audpp_cmd_reverb_config_common {
+	unsigned short			cmd_id;
+	unsigned short			enable;
+	unsigned short			cmd_type;
+} __attribute__((packed));
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (ENV-0x0104)
+ */
+
+#define	AUDPP_CMD_REVERB_CONFIG_ENV_104_LEN	\
+	sizeof(struct audpp_cmd_reverb_config_env_104)
+
+struct audpp_cmd_reverb_config_env_104 {
+	struct audpp_cmd_reverb_config_common	common;
+	unsigned short			env_gain;
+	unsigned short			decay_msw;
+	unsigned short			decay_lsw;
+	unsigned short			decay_timeratio_msw;
+	unsigned short			decay_timeratio_lsw;
+	unsigned short			delay_time;
+	unsigned short			reverb_gain;
+	unsigned short			reverb_delay;
+} __attribute__((packed));
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (ENV-0x0015)
+ */
+
+#define	AUDPP_CMD_REVERB_CONFIG_ENV_15_LEN	\
+	sizeof(struct audpp_cmd_reverb_config_env_15)
+
+struct audpp_cmd_reverb_config_env_15 {
+	struct audpp_cmd_reverb_config_common	common;
+	unsigned short			object_num;
+	unsigned short			absolute_gain;
+} __attribute__((packed));
+
+
+/* messages from dsp to apps */
+
+
+/*
+ * AUDPPTASK uses audPPuPRlist to send messages to the ARM
+ * Location : MEMA
+ * Buffer Size : 45
+ * No of Buffers in a queue : 5 for gaming audio and 1 for other images
+ */
+
+/*
+ * MSG to Informs the ARM os Success/Failure of bringing up the decoder
+ */
+
+#define AUDPP_MSG_STATUS_MSG		0x0001
+#define AUDPP_MSG_STATUS_MSG_LEN	\
+	sizeof(struct audpp_msg_status_msg)
+
+#define AUDPP_MSG_STATUS_SLEEP		0x0000
+#define AUDPP_MSG_STATUS_INIT		0x0001
+#define AUDPP_MSG_STATUS_CFG		0x0002
+#define AUDPP_MSG_STATUS_PLAY		0x0003
+
+#define AUDPP_MSG_REASON_NONE	0x0000
+#define AUDPP_MSG_REASON_MEM	0x0001
+#define AUDPP_MSG_REASON_NODECODER 0x0002
+
+struct audpp_msg_status_msg {
+	unsigned short dec_id;
+	unsigned short status;
+	unsigned short reason;
+} __attribute__((packed));
+
+/*
+ * MSG to communicate the spectrum analyzer output bands to the ARM
+ */
+#define AUDPP_MSG_SPA_BANDS		0x0002
+#define AUDPP_MSG_SPA_BANDS_LEN	\
+	sizeof(struct audpp_msg_spa_bands)
+
+struct audpp_msg_spa_bands {
+	unsigned short			current_object;
+	unsigned short			spa_band_1;
+	unsigned short			spa_band_2;
+	unsigned short			spa_band_3;
+	unsigned short			spa_band_4;
+	unsigned short			spa_band_5;
+	unsigned short			spa_band_6;
+	unsigned short			spa_band_7;
+	unsigned short			spa_band_8;
+	unsigned short			spa_band_9;
+	unsigned short			spa_band_10;
+	unsigned short			spa_band_11;
+	unsigned short			spa_band_12;
+	unsigned short			spa_band_13;
+	unsigned short			spa_band_14;
+	unsigned short			spa_band_15;
+	unsigned short			spa_band_16;
+	unsigned short			spa_band_17;
+	unsigned short			spa_band_18;
+	unsigned short			spa_band_19;
+	unsigned short			spa_band_20;
+	unsigned short			spa_band_21;
+	unsigned short			spa_band_22;
+	unsigned short			spa_band_23;
+	unsigned short			spa_band_24;
+	unsigned short			spa_band_25;
+	unsigned short			spa_band_26;
+	unsigned short			spa_band_27;
+	unsigned short			spa_band_28;
+	unsigned short			spa_band_29;
+	unsigned short			spa_band_30;
+	unsigned short			spa_band_31;
+	unsigned short			spa_band_32;
+} __attribute__((packed));
+
+/*
+ * MSG to communicate the PCM I/O buffer status to ARM
+ */
+#define  AUDPP_MSG_HOST_PCM_INTF_MSG		0x0003
+#define  AUDPP_MSG_HOST_PCM_INTF_MSG_LEN	\
+	sizeof(struct audpp_msg_host_pcm_intf_msg)
+
+#define AUDPP_MSG_HOSTPCM_ID_TX_ARM	0x0000
+#define AUDPP_MSG_HOSTPCM_ID_ARM_TX	0x0001
+#define AUDPP_MSG_HOSTPCM_ID_RX_ARM	0x0002
+#define AUDPP_MSG_HOSTPCM_ID_ARM_RX	0x0003
+
+#define AUDPP_MSG_SAMP_FREQ_INDX_96000	0x0000
+#define AUDPP_MSG_SAMP_FREQ_INDX_88200	0x0001
+#define AUDPP_MSG_SAMP_FREQ_INDX_64000	0x0002
+#define AUDPP_MSG_SAMP_FREQ_INDX_48000	0x0003
+#define AUDPP_MSG_SAMP_FREQ_INDX_44100	0x0004
+#define AUDPP_MSG_SAMP_FREQ_INDX_32000	0x0005
+#define AUDPP_MSG_SAMP_FREQ_INDX_24000	0x0006
+#define AUDPP_MSG_SAMP_FREQ_INDX_22050	0x0007
+#define AUDPP_MSG_SAMP_FREQ_INDX_16000	0x0008
+#define AUDPP_MSG_SAMP_FREQ_INDX_12000	0x0009
+#define AUDPP_MSG_SAMP_FREQ_INDX_11025	0x000A
+#define AUDPP_MSG_SAMP_FREQ_INDX_8000	0x000B
+
+#define AUDPP_MSG_CHANNEL_MODE_MONO		0x0001
+#define AUDPP_MSG_CHANNEL_MODE_STEREO	0x0002
+
+struct audpp_msg_host_pcm_intf_msg {
+	unsigned short obj_num;
+	unsigned short numbers_of_samples;
+	unsigned short host_pcm_id;
+	unsigned short buf_indx;
+	unsigned short samp_freq_indx;
+	unsigned short channel_mode;
+} __attribute__((packed));
+
+
+/*
+ * MSG to communicate 3D position of the source and listener , source volume
+ * source rolloff, source orientation
+ */
+
+#define AUDPP_MSG_QAFX_POS		0x0004
+#define AUDPP_MSG_QAFX_POS_LEN		\
+	sizeof(struct audpp_msg_qafx_pos)
+
+struct audpp_msg_qafx_pos {
+	unsigned short	current_object;
+	unsigned short	x_pos_lis_msw;
+	unsigned short	x_pos_lis_lsw;
+	unsigned short	y_pos_lis_msw;
+	unsigned short	y_pos_lis_lsw;
+	unsigned short	z_pos_lis_msw;
+	unsigned short	z_pos_lis_lsw;
+	unsigned short	x_fwd_msw;
+	unsigned short	x_fwd_lsw;
+	unsigned short	y_fwd_msw;
+	unsigned short	y_fwd_lsw;
+	unsigned short	z_fwd_msw;
+	unsigned short	z_fwd_lsw;
+	unsigned short 	x_up_msw;
+	unsigned short	x_up_lsw;
+	unsigned short 	y_up_msw;
+	unsigned short	y_up_lsw;
+	unsigned short 	z_up_msw;
+	unsigned short	z_up_lsw;
+	unsigned short 	x_vel_lis_msw;
+	unsigned short 	x_vel_lis_lsw;
+	unsigned short 	y_vel_lis_msw;
+	unsigned short 	y_vel_lis_lsw;
+	unsigned short 	z_vel_lis_msw;
+	unsigned short 	z_vel_lis_lsw;
+	unsigned short	threed_enable_flag;
+	unsigned short 	volume;
+	unsigned short	x_pos_source_msw;
+	unsigned short	x_pos_source_lsw;
+	unsigned short	y_pos_source_msw;
+	unsigned short	y_pos_source_lsw;
+	unsigned short	z_pos_source_msw;
+	unsigned short	z_pos_source_lsw;
+	unsigned short	max_dist_0_msw;
+	unsigned short	max_dist_0_lsw;
+	unsigned short	min_dist_0_msw;
+	unsigned short	min_dist_0_lsw;
+	unsigned short	roll_off_factor;
+	unsigned short	mute_after_max_flag;
+	unsigned short	x_vel_source_msw;
+	unsigned short	x_vel_source_lsw;
+	unsigned short	y_vel_source_msw;
+	unsigned short	y_vel_source_lsw;
+	unsigned short	z_vel_source_msw;
+	unsigned short	z_vel_source_lsw;
+} __attribute__((packed));
+
+/*
+ * MSG to provide AVSYNC feedback from DSP to ARM
+ */
+
+#define AUDPP_MSG_AVSYNC_MSG		0x0005
+#define AUDPP_MSG_AVSYNC_MSG_LEN	\
+	sizeof(struct audpp_msg_avsync_msg)
+
+struct audpp_msg_avsync_msg {
+	unsigned short	active_flag;
+	unsigned short	num_samples_counter0_HSW;
+	unsigned short	num_samples_counter0_MSW;
+	unsigned short	num_samples_counter0_LSW;
+	unsigned short	num_bytes_counter0_HSW;
+	unsigned short	num_bytes_counter0_MSW;
+	unsigned short	num_bytes_counter0_LSW;
+	unsigned short	samp_freq_obj_0;
+	unsigned short	samp_freq_obj_1;
+	unsigned short	samp_freq_obj_2;
+	unsigned short	samp_freq_obj_3;
+	unsigned short	samp_freq_obj_4;
+	unsigned short	samp_freq_obj_5;
+	unsigned short	samp_freq_obj_6;
+	unsigned short	samp_freq_obj_7;
+	unsigned short	samp_freq_obj_8;
+	unsigned short	samp_freq_obj_9;
+	unsigned short	samp_freq_obj_10;
+	unsigned short	samp_freq_obj_11;
+	unsigned short	samp_freq_obj_12;
+	unsigned short	samp_freq_obj_13;
+	unsigned short	samp_freq_obj_14;
+	unsigned short	samp_freq_obj_15;
+	unsigned short	num_samples_counter4_HSW;
+	unsigned short	num_samples_counter4_MSW;
+	unsigned short	num_samples_counter4_LSW;
+	unsigned short	num_bytes_counter4_HSW;
+	unsigned short	num_bytes_counter4_MSW;
+	unsigned short	num_bytes_counter4_LSW;
+} __attribute__((packed));
+
+/*
+ * MSG to provide PCM DMA Missed feedback from the DSP to ARM
+ */
+
+#define  AUDPP_MSG_PCMDMAMISSED	0x0006
+#define  AUDPP_MSG_PCMDMAMISSED_LEN	\
+	sizeof(struct audpp_msg_pcmdmamissed);
+
+struct audpp_msg_pcmdmamissed {
+	/*
+	** Bit 0	0 = PCM DMA not missed for object 0
+	**        1 = PCM DMA missed for object0
+	** Bit 1	0 = PCM DMA not missed for object 1
+	**        1 = PCM DMA missed for object1
+	** Bit 2	0 = PCM DMA not missed for object 2
+	**        1 = PCM DMA missed for object2
+	** Bit 3	0 = PCM DMA not missed for object 3
+	**        1 = PCM DMA missed for object3
+	** Bit 4	0 = PCM DMA not missed for object 4
+	**        1 = PCM DMA missed for object4
+	*/
+	unsigned short pcmdmamissed;
+} __attribute__((packed));
+
+/*
+ * MSG to AUDPP enable or disable feedback form DSP to ARM
+ */
+
+#define AUDPP_MSG_CFG_MSG	0x0007
+#define AUDPP_MSG_CFG_MSG_LEN	\
+    sizeof(struct audpp_msg_cfg_msg)
+
+#define AUDPP_MSG_ENA_ENA	0xFFFF
+#define AUDPP_MSG_ENA_DIS	0x0000
+
+struct audpp_msg_cfg_msg {
+	/*   Enabled  - 0xffff
+	**  Disabled - 0
+	*/
+	unsigned short enabled;
+} __attribute__((packed));
+
+/*
+ * MSG to communicate the reverb  per object volume
+ */
+
+#define AUDPP_MSG_QREVERB_VOLUME	0x0008
+#define AUDPP_MSG_QREVERB_VOLUME_LEN	\
+	sizeof(struct audpp_msg_qreverb_volume)
+
+
+struct audpp_msg_qreverb_volume {
+	unsigned short	obj_0_gain;
+	unsigned short	obj_1_gain;
+	unsigned short	obj_2_gain;
+	unsigned short	obj_3_gain;
+	unsigned short	obj_4_gain;
+	unsigned short	hpcm_obj_volume;
+} __attribute__((packed));
+
+#define AUDPP_MSG_ROUTING_ACK 0x0009
+#define AUDPP_MSG_ROUTING_ACK_LEN \
+	sizeof(struct audpp_msg_routing_ack)
+
+struct audpp_msg_routing_ack {
+	unsigned short dec_id;
+	unsigned short routing_mode;
+} __attribute__((packed));
+
+#define AUDPP_MSG_FLUSH_ACK 0x000A
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp_private.h b/arch/arm/mach-msm/qdsp5v2/adsp_private.h
new file mode 100644
index 0000000..badfb0d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp_private.h
@@ -0,0 +1,163 @@
+/* arch/arm/mach-msm/qdsp5v2/adsp_private.h
+ *
+ * Copyright (C) 2010 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.
+ *
+ */
+
+#ifndef _MSM_ADSP_5V2_PRIVATE_H_
+#define _MSM_ADSP_5V2_PRIVATE_H_
+
+/* adsp rtos / hardware memory map */
+
+#define QDSP_RAMC_OFFSET			0x00400000
+#define ADSP_READ_CTRL_OFFSET			0x00400038
+#define ADSP_WRITE_CTRL_OFFSET			0x00400034
+#define ADSP_SEND_IRQ_OFFSET			0x00c00200
+
+
+/* adsp rtos hardware / shared memory interface */
+
+#define ADSP_WRITE_CTRL_MUTEX_M			0x80000000U
+#define ADSP_WRITE_CTRL_MUTEX_NAVAIL_V		0x80000000U
+#define ADSP_WRITE_CTRL_MUTEX_AVAIL_V		0x00000000U
+
+#define ADSP_WRITE_CTRL_CMD_M			0x70000000U
+#define ADSP_WRITE_CTRL_CMD_WRITE_REQ_V		0x00000000U
+#define ADSP_WRITE_CTRL_CMD_WRITE_DONE_V	0x10000000U
+#define ADSP_WRITE_CTRL_CMD_NO_CMD_V		0x70000000U
+
+#define ADSP_WRITE_CTRL_STATUS_M		0x0E000000U
+#define ADSP_WRITE_CTRL_NO_ERR_V		0x00000000U
+#define ADSP_WRITE_CTRL_NO_FREE_BUF_V		0x02000000U
+
+#define ADSP_WRITE_CTRL_DSP_ADDR_M		0x00FFFFFFU
+
+#define ADSP_WRITE_CTRL_HTOD_CMD_ID_M		0x00FFFFFFU
+
+/* Combination of MUTEX and CMD bits to check if the DSP is busy */
+#define ADSP_WRITE_CTRL_READY_M			0xF0000000U
+#define ADSP_WRITE_CTRL_READY_V			0x70000000U
+
+/* RTOS to Host processor command mask values */
+#define ADSP_READ_CTRL_FLAG_M			0x80000000U
+#define ADSP_READ_CTRL_FLAG_UP_WAIT_V		0x00000000U
+#define ADSP_READ_CTRL_FLAG_UP_CONT_V		0x80000000U
+
+#define ADSP_READ_CTRL_CMD_M			0x60000000U
+#define ADSP_READ_CTRL_READ_DONE_V		0x00000000U
+#define ADSP_READ_CTRL_READ_REQ_V		0x20000000U
+#define ADSP_READ_CTRL_NO_CMD_V			0x60000000U
+
+/* Combination of FLAG and COMMAND bits to check if MSG ready */
+#define ADSP_READ_CTRL_READY_M			0xE0000000U
+#define ADSP_READ_CTRL_READY_V			0xA0000000U
+#define ADSP_READ_CTRL_CONT_V			0xC0000000U
+#define ADSP_READ_CTRL_DONE_V			0xE0000000U
+
+#define ADSP_READ_CTRL_STATUS_M			0x18000000U
+#define ADSP_READ_CTRL_NO_ERR_V			0x00000000U
+
+#define ADSP_READ_CTRL_IN_PROG_M		0x04000000U
+#define ADSP_READ_CTRL_NO_READ_IN_PROG_V	0x00000000U
+#define ADSP_READ_CTRL_READ_IN_PROG_V		0x04000000U
+
+#define ADSP_READ_CTRL_CMD_TYPE_M		0x03000000U
+#define ADSP_READ_CTRL_CMD_TASK_TO_H_V		0x00000000U
+
+#define ADSP_READ_CTRL_DSP_ADDR_M		0x00FFFFFFU
+
+#define ADSP_READ_CTRL_MSG_ID_M			0x000000FFU
+#define ADSP_READ_CTRL_TASK_ID_M		0x0000FF00U
+
+
+/* modem adsp management DAL service interface */
+
+#define ADSP_DAL_DEVICE		0x0200009A
+#define ADSP_DAL_PORT		"SMD_DAL00"
+#define ADSP_DAL_COMMAND	(DAL_OP_FIRST_DEVICE_API | 0x80000000)
+
+struct adsp_dal_cmd {
+	uint32_t cmd;
+	uint32_t proc_id;
+	uint32_t module;
+	void *cookie;
+};
+
+#define ADSP_PROC_NONE			0
+#define ADSP_PROC_MODEM			1
+#define ADSP_PROC_APPS			2
+
+#define ADSP_CMD_ENABLE			1
+#define ADSP_CMD_DISABLE		2
+#define ADSP_CMD_DISABLE_EVENT_RSP	6
+#define ADSP_CMD_GET_INIT_INFO		11
+
+#define ADSP_EVT_MOD_READY		0
+#define ADSP_EVT_MOD_DISABLE		1
+#define ADSP_EVT_INIT_INFO		6
+#define ADSP_EVT_DISABLE_FAIL		7
+
+#define ADSP_TASKS_MAX	64
+#define ADSP_QUEUES_MAX 4
+
+#define MODULE_NAME_MAX 32
+#define QUEUE_NAME_MAX  32
+
+#define ADSP_QUEUE_FLAG_16BIT 0
+#define ADSP_QUEUE_FLAG_32BIT 1
+
+struct adsp_queue_info {
+	uint8_t  name[QUEUE_NAME_MAX];
+	uint32_t offset; /* Queue Offset in DSP memory */
+	uint16_t idx; /* Global queue identifier */
+	uint16_t max_size; /* Max allowed size in bytes for a queue */
+	uint16_t flag; /* queue is 32bit Vs 16 bits */
+	uint16_t rvd1;
+	uint32_t rvd2;
+};
+
+struct adsp_module_info 
+{
+	uint8_t  name[MODULE_NAME_MAX];
+	uint32_t uuid;
+	uint16_t task_id;
+	uint16_t q_cnt;
+	struct adsp_queue_info queue[ADSP_QUEUES_MAX];
+	uint32_t rvd1;
+	uint32_t rvd2;
+};
+	
+struct adsp_evt_info {
+	uint32_t module;
+	uint32_t image;
+	uint32_t apps_okts; /* wtf is an okts? */
+};
+	
+struct adsp_dal_event {
+	/* DAL common event header */
+	uint32_t evt_handle;
+	uint32_t evt_cookie;
+	uint32_t evt_length;
+
+	/* ADSP event header */
+	uint32_t event;
+	uint32_t version;
+	uint32_t proc_id;
+
+	/* payload */
+	union {
+		struct adsp_module_info module;
+		struct adsp_evt_info info;
+	} u;		
+};
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_glue.c b/arch/arm/mach-msm/qdsp5v2/audio_glue.c
new file mode 100644
index 0000000..49b9841
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_glue.c
@@ -0,0 +1,540 @@
+/* arch/arm/mach-msm/qdsp5v2/audio_glue.c
+ *
+ * Copyright (C) 2010 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/module.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+/* the audio codec control consists of
+ * - mi2s transports (x3)
+ * - lpa (low power audio) frontend for mi2s tx
+ * - various related clocks
+ */
+struct msm_codec {
+	void *tx_base;
+	void *rx_base;
+	void *lpa_base;
+
+	struct clk *rx_mclk;
+	struct clk *rx_sclk;
+	struct clk *tx_mclk;
+	struct clk *tx_sclk;
+
+	struct clk *lpa_codec_clk;
+	struct clk *lpa_core_clk;
+	struct clk *lpa_pclk;
+
+	struct clk *adsp_clk;
+};
+
+#define LPA_MAX_BUF_SIZE 		0x30000
+
+#define LPA_CONTROL			0x00000000
+#define LPA_CODEC			0x00000004
+#define LPA_HLB_MIN_ADDR		0x00000008
+#define LPA_HLB_MAX_ADDR		0x0000000C
+#define LPA_HLB_WPTR			0x00000010
+#define LPA_HLB_VOLUME_CONTROL 		0x00000014
+#define LPA_LLB_MIN_ADDR		0x00000018
+#define LPA_LLB_MAX_ADDR		0x0000001C
+#define LPA_SB_MIN_ADDR			0x00000020
+#define LPA_SB_MAX_ADDR			0x00000024
+#define LPA_INTR_ENABLE			0x00000028
+#define LPA_INTR_STATUS			0x0000002C
+#define LPA_WMARK_ASSIGN		0x00000030
+#define LPA_WMARK_0_LLB			0x00000034
+#define LPA_WMARK_1_LLB			0x00000038
+#define LPA_WMARK_2_LLB			0x0000003C
+#define LPA_WMARK_3_LLB			0x00000040
+#define LPA_WMARK_HLB			0x00000044
+#define LPA_WMARK_SB			0x00000048
+#define LPA_RDPTR_LLB			0x0000004C
+#define LPA_RDPTR_HLB			0x00000050
+#define LPA_WRPTR_SB			0x00000054
+#define LPA_UTC_CONFIG			0x00000058
+#define LPA_UTC_INTR_LOW		0x0000005C
+#define LPA_UTC_INTR_HIGH		0x00000060
+#define LPA_UTC_LOW			0x00000064
+#define LPA_UTC_HIGH			0x00000068
+#define LPA_MISR			0x0000006C
+#define LPA_STATUS			0x00000070
+#define LPA_ACK				0x00000074
+#define LPA_MEMORY_CONTROL		0x00000078
+#define LPA_MEMORY_STATUS		0x0000007C
+#define LPA_MEMORY_TIME_CONTROL		0x00000080
+#define LPA_ACC_LV			0x00000084
+#define LPA_ACC_HV			0x0000008c
+#define LPA_RESETS			0x00000090
+#define LPA_TESTBUS			0x00000094
+
+#define LPA_AICTL			0x00000100
+
+/* OBUF_CODEC */
+#define LPA_CODEC_LOAD			0x200000
+#define LPA_CODEC_INTF_EN		0x100000
+#define LPA_CODEC_CFG_MASK		0x0FC07F
+
+#define LPA_SAMPLE_RATE_8KHZ		0x000000
+#define LPA_SAMPLE_RATE_11P025KHZ	0x010000
+#define LPA_SAMPLE_RATE_16KHZ		0x020000
+#define LPA_SAMPLE_RATE_22P05KHZ	0x030000
+#define LPA_SAMPLE_RATE_32KHZ		0x040000
+#define LPA_SAMPLE_RATE_44P1KHZ		0x050000
+#define LPA_SAMPLE_RATE_48KHZ		0x060000
+#define LPA_SAMPLE_RATE_64KHZ		0x070000
+#define LPA_SAMPLE_RATE_96KHZ		0x080000
+
+#define LPA_BITS_PER_CHAN_16BITS	0x000000
+#define LPA_BITS_PER_CHAN_24BITS	0x004000
+#define LPA_BITS_PER_CHAN_32BITS	0x008000
+#define LPA_BITS_PER_CHAN_RESERVED	0x00C000
+
+#define LPA_INTF_SDAC			0x000010
+#define LPA_INTF_MI2S			0x000020
+#define LPA_INTF_WB_CODEC		0x000030
+
+/* WB_CODEC & SDAC can only support 16bit mono/stereo.
+ * MI2S can bit format and number of channel
+ */
+#define LPA_NUM_CHAN_MONO		0x000000
+#define LPA_NUM_CHAN_STEREO		0x000001
+#define LPA_NUM_CHAN_5P1		0x000002
+#define LPA_NUM_CHAN_7P1		0x000003
+#define LPA_NUM_CHAN_4_CHANNEL		0x000004
+
+/* OBUF_CONTROL */
+#define LPA_CONTROL_TEST_EN		0x100
+#define LPA_CONTROL_LLB_CLR_CMD		0x080
+#define LPA_CONTROL_SB_SAT_EN		0x040
+#define LPA_CONTROL_LLB_SAT_EN		0x020
+#define LPA_CONTROL_LLB_ACC_EN		0x008
+#define LPA_CONTROL_HLB_EN		0x004
+#define LPA_CONTROL_LLB_EN		0x002
+#define LPA_CONTROL_SB_EN		0x001
+
+/* OBUF_RESET definition */
+#define LPA_RESETS_MISR			0x1
+#define LPA_RESETS_OVERALL		0x2
+
+/* OBUF_STATUS definition */
+#define LPA_STATUS_RESET_DONE		0x80000
+#define LPA_STATUS_LLB_CLR		0x40000
+
+/* OBUF_HLB_MIN_ADDR definition */
+#define LPA_HLB_MIN_ADDR_LOAD		0x40000
+#define LPA_HLB_MIN_ADDR_SEG_MASK	0x3e000
+
+/* OBUF_HLB_MAX_ADDR definition */
+#define LPA_HLB_MAX_ADDR_SEG_MASK	0x3fff8
+
+/* OBUF_LLB_MIN_ADDR definition */
+#define LPA_LLB_MIN_ADDR_LOAD		0x40000
+#define LPA_LLB_MIN_ADDR_SEG_BMSK	0x3e000
+
+/* OBUF_LLB_MAX_ADDR definition */
+#define LPA_LLB_MAX_ADDR_SEG_MASK	0x3ff8
+#define LPA_LLB_MAX_ADDR_SEG_SHFT	0x3
+
+/* OBUF_SB_MIN_ADDR definition */
+#define LPA_SB_MIN_ADDR_LOAD		0x4000
+#define LPA_SB_MIN_ADDR_SEG_BMSK	0x3e00
+
+/* OBUF_SB_MAX_ADDR definition */
+#define LPA_SB_MAX_ADDR_SEG_BMSK	0x3ff8
+
+/* OBUF_MEMORY_CONTROL definition */
+#define LPA_MEM_CTL_PWRUP		0xfff
+
+/* OBUF_INTR_ENABLE definition */
+#define LPA_INTR_EN			0x3
+
+/* OBUF_WMARK_ASSIGN definition */
+#define LPA_WMARK_ASSIGN_BMSK		0xF
+#define LPA_WMARK_ASSIGN_DONE		0xF
+
+/* OBUF_WMARK_n_LLB definition */
+#define LPA_WMARK_n_LLB_ADDR(n)  (0x00000034 + 0x4 * (n))
+#define LPA_WMARK_CTRL_MASK		0x0c0000
+#define LPA_WMARK_CTRL_SHFT		0x12
+#define LPA_WMARK_MAP_MASK		0xf00000
+#define LPA_WMARK_MAP_SHFT		0x14
+
+#define LPA_WMARK_CTL_DISABLED		0x0
+#define LPA_WMARK_CTL_NON_BLOCK		0x1
+#define LPA_WMARK_CTL_ZERO_INSERT	0x2
+#define LPA_WMARK_CTL_RESERVED		0x3
+
+/* OBUF_UTC_CONFIG definition */
+#define LPA_UTC_CONFIG_MAP_MASK		0xf0
+#define LPA_UTC_CONFIG_MAP_SHFT		0x4
+#define LPA_UTC_CONFIG_EN		0x1
+#define LPA_UTC_CONFIG_NO_INTR		0xF
+
+/* OBUF_ACK definition */
+#define LPA_ACK_RESET_DONE		0x80000
+
+
+#define LPA_BUF_ID_HLB	0   /* HLB buffer */
+#define LPA_BUF_ID_LLB	1   /* LLB buffer */
+#define LPA_BUF_ID_SB	2   /* SB buffer */
+#define LPA_BUF_ID_UTC	3
+
+
+/* from board file in qct tree */
+
+#define LPA_HLB_SIZE		0x2BFF8
+
+#define LPA_ID_DSP		0
+#define LPA_ID_APP		2
+
+#if 0
+#define CFG_LLB_MIN_ADDR	0x0000
+#define CFG_LLB_MAX_ADDR	0x3ff8
+#define CFG_SB_MIN_ADDR		0
+#define CFG_SB_MAX_ADDR		0
+#else
+#define CFG_LLB_MIN_ADDR	0x0000
+#define CFG_LLB_MAX_ADDR	0x37f8
+#define CFG_SB_MIN_ADDR		0x3800
+#define CFG_SB_MAX_ADDR		0x3ff8
+#endif
+
+#define CFG_HLB_MIN_ADDR	0x00000
+#define CFG_HLB_MAX_ADDR	0x2BFF8
+
+/* 7x30 MI2S Registers */
+
+/* MI2S Registers are named from the MI2S block's point of view:
+ * - TX = transmit from SoC to external codec
+ * - RX = receive from external codec to SoC
+ */
+#define MI2S_RESET		0x00
+#define MI2S_MODE		0x04
+#define MI2S_TX_MODE		0x08
+#define MI2S_RX_MODE		0x0C
+
+#define MI2S_RESET_RESET	1
+
+#define MI2S_MODE_MASTER	0x1000
+#define MI2S_MODE_16BIT		0x0100
+#define MI2S_MODE_24BIT		0x0200
+#define MI2S_MODE_32BIT		0x0300
+#define MI2S_MODE_EN_3		0x0080
+#define MI2S_MODE_EN_2		0x0040
+#define MI2S_MODE_EN_1		0x0020
+#define MI2S_MODE_EN_0		0x0010
+#define MI2S_MODE_TX_3		0x0008
+#define MI2S_MODE_TX_2		0x0004
+#define MI2S_MODE_TX_1		0x0002
+#define MI2S_MODE_TX_0		0x0001
+
+#define MI2S_TX_MODE_2CH	0x0000
+#define MI2S_TX_MODE_4CH	0x0008
+#define MI2S_TX_MODE_6CH	0x0010
+#define MI2S_TX_MODE_8CH	0x0018
+#define MI2S_TX_MODE_STEREO	0x0004
+#define MI2S_TX_MODE_MONO_PACK	0x0002 /* 2 mono samples packed together */
+#define MI2S_TX_MODE_DMA_SYNC	0x0001 /* sync dma ack clocks */
+
+#define MI2S_RX_MODE_2CH	0x0000
+#define MI2S_RX_MODE_4CH	0x0008
+#define MI2S_RX_MODE_6CH	0x0010
+#define MI2S_RX_MODE_8CH	0x0018
+#define MI2S_RX_MODE_STEREO	0x0004
+#define MI2S_RX_MODE_MONO_PACK	0x0002 /* 2 mono samples packed together */
+#define MI2S_RX_MODE_DMA_SYNC	0x0001 /* sync dma ack clocks */
+
+static int mi2s_set_output(struct msm_codec *mc,
+			   unsigned channels, unsigned bitdepth)
+{
+	unsigned mode = 0;
+	unsigned tx_mode = 0;
+
+	if (channels != 2 || bitdepth != 16)
+		return -EINVAL;
+
+	/* TODO: support non stereo-16 (does the DSP even do that?) */
+
+	mode |= MI2S_MODE_MASTER;
+	mode |= MI2S_MODE_16BIT;
+	mode |= MI2S_MODE_EN_0;
+	mode |= MI2S_MODE_TX_0;
+
+	tx_mode |= MI2S_TX_MODE_STEREO;
+	tx_mode |= MI2S_TX_MODE_2CH;
+	tx_mode |= MI2S_RX_MODE_DMA_SYNC;
+	
+	writel(1, mc->tx_base + MI2S_RESET);
+	writel(mode, mc->tx_base + MI2S_MODE);
+	writel(tx_mode, mc->tx_base + MI2S_TX_MODE);
+	writel(0, mc->tx_base + MI2S_RESET);
+
+	return 0;
+}
+
+static int mi2s_set_input(struct msm_codec *mc,
+			  unsigned channels, unsigned bitdepth)
+{
+	unsigned mode = 0;
+	unsigned rx_mode = 0;
+
+	if (channels != 2 || bitdepth != 16)
+		return -EINVAL;
+
+	/* TODO: support non stereo-16 */
+	/* TODO: packed mono mode? */
+
+	mode |= MI2S_MODE_MASTER;
+	mode |= MI2S_MODE_16BIT;
+	mode |= MI2S_MODE_EN_0;
+
+	rx_mode |= MI2S_RX_MODE_STEREO;
+	rx_mode |= MI2S_RX_MODE_2CH;
+	rx_mode |= MI2S_RX_MODE_DMA_SYNC;
+	
+	writel(1, mc->rx_base + MI2S_RESET);
+	writel(mode, mc->rx_base + MI2S_MODE);
+	writel(rx_mode, mc->rx_base + MI2S_RX_MODE);
+	writel(0, mc->rx_base + MI2S_RESET);
+
+	return 0;
+}
+
+void lpa_enable(struct msm_codec *mc)
+{
+	unsigned val;
+
+	/* for "hardware reasons" we must ensure the
+	 * adsp clock is on during this reset sequence.
+	 */
+	clk_enable(mc->adsp_clk);
+
+	/* disable codec */
+	writel(LPA_CODEC_LOAD, mc->lpa_base + LPA_CODEC);
+
+	writel(LPA_RESETS_MISR | LPA_RESETS_OVERALL,
+	       mc->lpa_base + LPA_RESETS);
+
+	while (!(readl(mc->lpa_base + LPA_STATUS) & LPA_STATUS_RESET_DONE))
+		;
+
+	writel(LPA_ACK_RESET_DONE, mc->lpa_base + LPA_ACK);
+
+	clk_disable(mc->adsp_clk);
+
+	/* configure memory buffers */
+	writel(CFG_LLB_MIN_ADDR | LPA_LLB_MIN_ADDR_LOAD,
+	       mc->lpa_base + LPA_LLB_MIN_ADDR);
+	writel(CFG_LLB_MAX_ADDR, mc->lpa_base + LPA_LLB_MAX_ADDR);
+
+	writel(CFG_SB_MIN_ADDR | LPA_SB_MIN_ADDR_LOAD,
+	       mc->lpa_base + LPA_SB_MIN_ADDR);
+	writel(CFG_SB_MAX_ADDR, mc->lpa_base + LPA_SB_MAX_ADDR);
+
+	writel(CFG_HLB_MIN_ADDR | LPA_HLB_MIN_ADDR_LOAD,
+	       mc->lpa_base + LPA_HLB_MIN_ADDR);
+	writel(CFG_HLB_MAX_ADDR, mc->lpa_base + LPA_HLB_MAX_ADDR);
+
+	writel(LPA_MEM_CTL_PWRUP, mc->lpa_base + LPA_MEMORY_CONTROL);
+
+
+	while (readl(mc->lpa_base + LPA_WMARK_ASSIGN) != LPA_WMARK_ASSIGN_DONE)
+		;
+
+	/* setup watermark ownership */
+	writel(LPA_ID_DSP << LPA_WMARK_MAP_SHFT,
+	       mc->lpa_base + LPA_WMARK_0_LLB);
+	writel(LPA_ID_DSP << LPA_WMARK_MAP_SHFT,
+	       mc->lpa_base + LPA_WMARK_1_LLB);
+	writel(LPA_ID_APP << LPA_WMARK_MAP_SHFT,
+	       mc->lpa_base + LPA_WMARK_2_LLB);
+	writel(LPA_ID_APP << LPA_WMARK_MAP_SHFT,
+	       mc->lpa_base + LPA_WMARK_3_LLB);
+	writel(LPA_ID_DSP << LPA_WMARK_MAP_SHFT,
+	       mc->lpa_base + LPA_WMARK_HLB);
+	writel(LPA_ID_DSP << LPA_WMARK_MAP_SHFT,
+	       mc->lpa_base + LPA_WMARK_SB);
+	writel(0, mc->lpa_base + LPA_UTC_CONFIG);
+
+
+	val = readl(mc->lpa_base + LPA_CONTROL);
+	val |= LPA_CONTROL_LLB_EN;
+	val |= LPA_CONTROL_LLB_SAT_EN;
+	val |= LPA_CONTROL_SB_EN;
+	val |= LPA_CONTROL_SB_SAT_EN;
+	writel(val, mc->lpa_base + LPA_CONTROL);
+
+	writel(1 << LPA_ID_DSP, mc->lpa_base + LPA_INTR_ENABLE);
+}
+
+void lpa_start(struct msm_codec *mc)
+{
+	unsigned val, codec;
+
+	codec = LPA_CODEC_LOAD;
+	codec |= LPA_NUM_CHAN_STEREO;
+	codec |= LPA_SAMPLE_RATE_48KHZ;
+	codec |= LPA_BITS_PER_CHAN_16BITS;
+	codec |= LPA_INTF_WB_CODEC;
+	writel(codec, mc->lpa_base + LPA_CODEC);
+
+	/* clear LLB */
+	val = readl(mc->lpa_base + LPA_CONTROL);
+	writel(val | LPA_CONTROL_LLB_CLR_CMD, mc->lpa_base + LPA_CONTROL);
+
+	while (!(readl(mc->lpa_base + LPA_STATUS) & LPA_STATUS_LLB_CLR))
+		udelay(100);
+
+	/* enable codec */
+	codec |= LPA_CODEC_INTF_EN;
+	writel(codec, mc->lpa_base + LPA_CODEC);
+}
+
+void lpa_disable(struct msm_codec *mc)
+{
+	writel(LPA_CODEC_LOAD, mc->lpa_base + LPA_CODEC);
+}
+
+int msm_codec_output_enable(struct msm_codec *mc)
+{
+	unsigned rate, val;
+
+	pr_info("msm_codec_output_enable()\n");
+
+	/* yes rx clks for tx codec -- the clocks
+	 * are named from the opposite POV of the
+	 * codec for some reason...
+	 */
+
+
+	/* bitrate * bits * channels * 8 */
+	rate = 48000 * 16 * 2 * 8;
+	clk_set_rate(mc->rx_mclk, rate);
+
+	printk("RATE %d\n", clk_get_rate(mc->rx_mclk));
+
+	clk_enable(mc->rx_mclk);
+	clk_enable(mc->rx_sclk);
+
+ 	clk_enable(mc->lpa_pclk);
+	clk_enable(mc->lpa_codec_clk);
+	clk_enable(mc->lpa_core_clk);
+	/* LPA init */
+
+	lpa_enable(mc);
+
+	/* interconnect reg -> LPA */
+	val = readl(mc->lpa_base + LPA_AICTL);
+	writel(val | 4, mc->lpa_base + LPA_AICTL);
+
+	/* fire up mi2s transport */
+	mi2s_set_output(mc, 2, 16);
+
+	lpa_start(mc);
+
+	/* AFE enable */
+
+	/* ADIE enable */
+
+	/* AMP enable */
+
+	return 0;
+}
+
+int msm_codec_output_disable(struct msm_codec *mc)
+{
+	pr_info("msm_codec_output_disable()\n");
+	/* AMP disable */
+	/* ADIE disable */
+	/* AFE disable */
+	/* LPA disable */
+
+	clk_disable(mc->lpa_core_clk);
+	clk_disable(mc->lpa_codec_clk);
+	clk_disable(mc->lpa_pclk);
+
+	clk_disable(mc->rx_sclk);
+	clk_disable(mc->rx_mclk);
+
+	return 0;
+}
+
+
+static struct msm_codec the_msm_codec;
+
+int msm_codec_output(int enable)
+{
+	struct msm_codec *mc = &the_msm_codec;
+	if (enable)
+		return msm_codec_output_enable(mc);
+	else
+		return msm_codec_output_disable(mc);
+}
+
+/* 7x30 memory map */
+
+#define PHYS_ADDR_LPA		0xA5000000
+#define PHYS_SIZE_LPA		0x00000800
+
+#define PHYS_ADDR_MI2S_HDMI	0xAC900000
+#define PHYS_ADDR_MI2S_CODEC_RX	0xAC940040
+#define PHYS_ADDR_MI2S_CODEC_TX 0xAC980080
+#define PHYS_SIZE_MI2S          0x00000040
+
+int msm_codec_init(void)
+{
+	struct msm_codec *mc = &the_msm_codec;
+
+	printk("msm_codec_init()\n");
+
+	mc->rx_mclk = clk_get(NULL, "mi2s_codec_rx_mclk");
+	if (IS_ERR(mc->rx_mclk))
+		return -ENODEV;
+	mc->rx_sclk = clk_get(NULL, "mi2s_codec_rx_sclk");
+	if (IS_ERR(mc->rx_sclk))
+		return -ENODEV;
+	mc->tx_mclk = clk_get(NULL, "mi2s_codec_tx_mclk");
+	if (IS_ERR(mc->tx_mclk))
+		return -ENODEV;
+	mc->tx_sclk = clk_get(NULL, "mi2s_codec_tx_sclk");
+	if (IS_ERR(mc->tx_sclk))
+		return -ENODEV;
+	mc->lpa_codec_clk = clk_get(NULL, "lpa_codec_clk");
+	if (IS_ERR(mc->lpa_codec_clk))
+		return -ENODEV;
+	mc->lpa_core_clk = clk_get(NULL, "lpa_core_clk");
+	if (IS_ERR(mc->lpa_core_clk))
+		return -ENODEV;
+	mc->lpa_pclk = clk_get(NULL, "lpa_pclk");
+	if (IS_ERR(mc->lpa_pclk))
+		return -ENODEV;
+	mc->adsp_clk = clk_get(NULL, "adsp_clk");
+	if (IS_ERR(mc->adsp_clk))
+		return -ENODEV;
+
+	mc->lpa_base = ioremap(PHYS_ADDR_LPA, PHYS_SIZE_LPA);
+	if (!mc->lpa_base)
+		return -ENODEV;
+	mc->rx_base = ioremap(PHYS_ADDR_MI2S_CODEC_RX, PHYS_SIZE_MI2S);
+	if (!mc->rx_base)
+		return -ENODEV;
+	mc->tx_base = ioremap(PHYS_ADDR_MI2S_CODEC_TX, PHYS_SIZE_MI2S);
+	if (!mc->tx_base)
+		return -ENODEV;
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_out.c b/arch/arm/mach-msm/qdsp5v2/audio_out.c
new file mode 100644
index 0000000..4e63e60
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_out.c
@@ -0,0 +1,242 @@
+/* arch/arm/mach-msm/qdsp5v2/audio_out.c
+ *
+ * Copyright (C) 2010 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/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/delay.h>
+
+#include <linux/msm_audio.h>
+
+#include "adsp.h"
+#include "adsp_audio.h"
+
+#include "adsp_module_afe.h"
+
+
+void adie_enable(void);
+
+struct audio_buffer {
+	dma_addr_t phys;
+	void *data;
+	uint32_t size;
+	uint32_t used;
+};
+	
+struct audio {
+	struct audio_buffer buf[2];
+
+	int cpu_buf;
+	int dsp_buf;
+	int running;
+	int session;
+
+	wait_queue_head_t wait;
+	struct audplay *audplay;
+	void *data;
+	dma_addr_t phys;
+};
+
+static void audio_send_data(void *cookie)
+{
+	struct audio *audio = cookie;
+	struct audio_buffer *ab = audio->buf + audio->dsp_buf;
+
+	if (ab->used) {
+		ab->used = 0;
+		audio->dsp_buf ^= 1;
+		wake_up(&audio->wait);
+	}
+}
+
+
+static int need_init = 1;
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	int ret;
+	struct audio *audio;
+
+	if (need_init) {
+		msm_codec_output(1);
+		afe_enable(AFE_DEVICE_MI2S_CODEC_RX, 48000, 2);
+		adie_enable();
+		need_init = 0;
+	}
+
+#if 0
+	msleep(5000);
+	afe_disable(AFE_DEVICE_MI2S_CODEC_RX);
+	msm_codec_output(0);
+
+	msleep(5000);
+	msm_codec_output(1);
+	afe_enable(AFE_DEVICE_MI2S_CODEC_RX, 48000, 2);
+	return 0;
+#endif
+
+	audio = kzalloc(sizeof(*audio), GFP_KERNEL);
+	if (!audio)
+		return -ENOMEM;
+
+	audio->data = dma_alloc_coherent(NULL, 8192, &audio->phys, GFP_KERNEL);
+	if (!audio->data) {
+		pr_err("audio: could not allocate DMA buffers\n");
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	init_waitqueue_head(&audio->wait);
+
+	audio->buf[0].phys = audio->phys;
+	audio->buf[0].data = audio->data;
+	audio->buf[0].size = 4096;
+	audio->buf[0].used = 0;
+	audio->buf[1].phys = audio->phys + 4096;
+	audio->buf[1].data = audio->data + 4096;
+	audio->buf[1].size = 4096;
+	audio->buf[1].used = 0;
+
+	audio->audplay = audplay_get(audio_send_data, audio);
+	if (!audio->audplay) {
+		kfree(audio);
+		return -ENODEV;
+	}
+
+	audplay_dsp_config(audio->audplay, 1);
+
+	audplay_config_pcm(audio->audplay, 44100, 16, 2);
+
+	audplay_mix_select(audio->audplay, 1);
+	audplay_volume_pan(audio->audplay, 0x2000, 0);
+
+	file->private_data = audio;
+	return 0;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	while (count > 0) {
+		ab = audio->buf + audio->cpu_buf;
+
+		if (ab->used)
+			if (!wait_event_timeout(audio->wait,
+						(ab->used == 0), 5*HZ)) {
+				pr_err("audio_write: timeout. dsp dead?\n");
+				return -EIO;
+			}
+
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer)) 
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = xfer;
+		audplay_send_data(audio->audplay, ab->phys, ab->used);
+		audio->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+	pr_info("audio_release()\n");
+	audplay_dsp_config(audio->audplay, 0);
+	audplay_put(audio->audplay);
+	kfree(audio);
+	return 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_SET_VOLUME: {
+		int vol;
+		if (copy_from_user(&vol, (void*) arg, sizeof(vol))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_info("audio_out: volume %d\n", vol);
+		break;
+	}
+	case AUDIO_GET_STATS:
+	case AUDIO_START:
+	case AUDIO_STOP:
+	case AUDIO_FLUSH:
+	case AUDIO_SET_CONFIG:
+		/* implement me! */
+		break;
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = 4096;
+		config.buffer_count = 2;
+		config.sample_rate = 44100;
+		config.channel_count = 2;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	}
+	return rc;
+}
+
+
+static const struct file_operations audio_out_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+};
+
+struct miscdevice audio_out_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &audio_out_fops,
+};
+
+static int __init audio_init(void)
+{
+	adsp_audio_init();
+	return misc_register(&audio_out_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/marimba.c b/arch/arm/mach-msm/qdsp5v2/marimba.c
new file mode 100644
index 0000000..fb1e18a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/marimba.c
@@ -0,0 +1,322 @@
+/* arch/arm/mach-msm/qdsp5v2/marimba.c
+ *
+ * Copyright (C) 2010 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.
+ *
+ */
+
+struct codec_reg {
+	unsigned char addr, mask, val;
+};
+
+static struct codec_reg init_rx[] = {
+	{ 0x23, 0xF8, 0x00 },
+	{ 0x24, 0x6F, 0x00 },
+	{ 0x25, 0x7F, 0x00 },
+	{ 0x26, 0xFC, 0x00 },
+	{ 0x28, 0xFE, 0x00 },
+	{ 0x29, 0xFE, 0x00 },
+	{ 0x33, 0xFF, 0x00 },
+	{ 0x34, 0xFF, 0x00 },
+	{ 0x35, 0xFC, 0x00 },
+	{ 0x36, 0xFE, 0x00 },
+	{ 0x37, 0xFE, 0x00 },
+	{ 0x38, 0xFE, 0x00 },
+	{ 0x39, 0xF0, 0x00 },
+	{ 0x3A, 0xFF, 0x0A },
+	{ 0x3B, 0xFC, 0xAC },
+	{ 0x3C, 0xFC, 0xAC },
+	{ 0x3D, 0xFF, 0x55 },
+	{ 0x3E, 0xFF, 0x55 },
+	{ 0x3F, 0xCF, 0x00 },
+	{ 0x40, 0x3F, 0x00 },
+	{ 0x41, 0x3F, 0x00 },
+	{ 0x42, 0xFF, 0x00 },
+	{ 0x43, 0xF7, 0x00 },
+	{ 0x43, 0xF7, 0x00 },
+	{ 0x43, 0xF7, 0x00 },
+	{ 0x43, 0xF7, 0x00 },
+	{ 0x44, 0xF7, 0x00 },
+	{ 0x45, 0xFF, 0x00 },
+	{ 0x46, 0xFF, 0x00 },
+	{ 0x47, 0xF7, 0x00 },
+	{ 0x48, 0xF7, 0x00 },
+	{ 0x49, 0xFF, 0x00 },
+	{ 0x4A, 0xFF, 0x00 },
+	{ 0x80, 0x02, 0x00 },
+	{ 0x81, 0xFF, 0x4C },
+	{ 0x83, 0x23, 0x00 },
+	{ 0x84, 0xFF, 0xAC },
+	{ 0x85, 0xFF, 0xAC },
+	{ 0x88, 0xFF, 0xFF },
+	{ 0x8A, 0x0F, 0x03 },
+	{ 0x8B, 0xFF, 0xAC },
+	{ 0x8C, 0x03, 0x01 },
+	{ 0x8D, 0xFF, 0x00 },
+	{ 0x8E, 0xFF, 0x00 },
+
+/* lb regs */
+	{ 0x2B, 0x8F, 0x02 },
+	{ 0x2C, 0x8F, 0x02 },
+
+	{ 0xFF, 0x00, 0x00 },
+};
+
+static struct codec_reg init_handset_48k_256_mono[] = {
+	{ 0x80, 0x02, 0x02 },
+	{ 0x80, 0x02, 0x00 },
+
+	{ 0x24, 0x6F, 0x44 },
+	{ 0x04, 0xFF, 0x8C },
+	{ 0x81, 0xFF, 0x4e },
+	{ 0x25, 0x0F, 0x0b },
+	{ 0x26, 0xfc, 0xfc },
+	{ 0x36, 0xc0, 0x80 },
+	{ 0x3A, 0xFF, 0x2B },
+	{ 0x23, 0xff, 0x20 },
+	{ 0x3d, 0xFF, 0x55 },
+	{ 0x83, 0x21, 0x21 },
+	{ 0x33, 0x80, 0x80 },
+
+	{ 0xFF, 0x00, 10 },
+
+	{ 0x33, 0x40, 0x40 },
+	{ 0x84, 0xff, 0x00 },
+	{ 0x8A, 0x05, 0x04 },
+
+	{ 0xFF, 0x00, 0x00 },
+};
+	
+static struct codec_reg init_speaker_48k_256_stereo[] = {
+	{ 0x80, 0x02, 0x02 },
+	{ 0x80, 0x02, 0x00 },
+
+	{ 0x24, 0x6F, 0x64 },
+	{ 0x25, 0x0F, 0x0B },
+	{ 0x26, 0xfc, 0xfc },
+	{ 0x37, 0xe6, 0x80 },
+	{ 0x3A, 0xFF, 0x2B },
+	{ 0x3d, 0xFF, 0x55 },
+	{ 0x83, 0x23, 0x23 },
+	{ 0x23, 0xff, 0x20 },
+	{ 0x33, 0x8a, 0x8a },
+	{ 0x33, 0x05, 0x05 },
+
+	{ 0xFF, 0x00, 30 },
+
+	{ 0x84, 0xff, 0x03 },
+	{ 0x85, 0xff, 0x03 },
+	{ 0x8A, 0x0f, 0x0c },
+
+	{ 0xFF, 0x00, 0x00 },
+};
+
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include <mach/vreg.h>
+
+static struct vreg *vreg_marimba1;
+static struct vreg *vreg_marimba2;
+static struct vreg *vreg_marimba3;
+
+static int marimba_vreg_init(void)
+{
+	vreg_marimba1 = vreg_get(NULL, "s2");
+	if (IS_ERR(vreg_marimba1))
+		return PTR_ERR(vreg_marimba1);
+	vreg_marimba2 = vreg_get(NULL, "gp16");
+	if (IS_ERR(vreg_marimba2))
+		return PTR_ERR(vreg_marimba2);
+	/* codec vreg */
+	vreg_marimba3 = vreg_get(NULL, "s4");
+	if (IS_ERR(vreg_marimba3))
+		return PTR_ERR(vreg_marimba3);
+	return 0;
+}
+
+static void marimba_vreg_enable(void)
+{
+	vreg_enable(vreg_marimba1);
+	vreg_enable(vreg_marimba2);
+	vreg_enable(vreg_marimba3);
+}
+
+#define MARIMBA_ADDR_MARIMBA	0x0C
+#define MARIMBA_ADDR_FM		0x2A
+#define MARIMBA_ADDR_CDC	0x77
+#define MARIMBA_ADDR_QMEMBIST	0X66
+
+#define MARIMBA_REG_ID_FM	0x01
+#define MARIMBA_REG_ID_CDC	0x02
+#define MARIMBA_REG_ID_QMEMBIST	0x03
+#define MARIMBA_REG_ID_TSADC	0x04
+
+static int marimba_raw_write(struct i2c_client *client,
+			     u8 addr, u8 reg, u8 value)
+{
+	struct i2c_msg msg;
+	u8 data[2];
+	int ret;
+
+	msg.addr = addr;
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = data;
+	data[0] = reg;
+	data[1] = value;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+
+	if (ret != 1)
+		pr_err("marimba_write: fail %d\n", ret);
+
+	return ret;
+}
+
+static int marimba_raw_read(struct i2c_client *client, u8 addr, u8 reg)
+{
+	struct i2c_msg msg[2];
+	u8 value;
+	int ret;
+
+	msg[0].addr = addr;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	msg[0].buf = &reg;
+
+	msg[1].addr = addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = 1;
+	msg[1].buf = &value;
+
+	ret = i2c_transfer(client->adapter, msg, 2);
+
+	if (ret != 2)
+		pr_err("marimba_read: fail %d\n", ret);
+
+	if (ret == 2)
+		return value;
+	return ret;
+}
+
+static u8 marimba_shadow[256];
+
+static int marimba_write(struct i2c_client *client, u8 reg, u8 value)
+{
+	marimba_shadow[reg] = value;
+	return marimba_raw_write(client, client->addr, reg, value);
+}
+
+static int marimba_write_mask(struct i2c_client *client, u8 reg, u8 mask, u8 value)
+{
+	value = (marimba_shadow[reg] & (~mask)) | (value & mask);
+	marimba_shadow[reg] = value;
+	return marimba_raw_write(client, client->addr, reg, value);
+}
+
+static int marimba_read(struct i2c_client *client, u8 reg)
+{
+	return marimba_raw_read(client, client->addr, reg);
+}
+
+
+static struct i2c_client *marimba_client;
+
+void adie_load(struct i2c_client *client, struct codec_reg *regs)
+{
+	int n;
+	for (n = 0;; n++) {
+		if (regs[n].addr == 0xff) {
+			if (regs[n].val == 0)
+				return;
+			msleep(regs[n].val);
+			continue;
+		}
+		marimba_write_mask(client, regs[n].addr,
+				   regs[n].mask, regs[n].val);
+	}
+}
+
+void adie_enable(void)
+{
+	struct i2c_client *client = marimba_client;
+
+	marimba_vreg_enable();
+
+	marimba_write(client, 0xff, 0x08); /* bring up codec */
+	marimba_write(client, 0xff, 0x0a); /* GDFS_EN_FEW=1 */
+	marimba_write(client, 0xff, 0x0e); /* GDFS_EN_REST=1 */
+	marimba_write(client, 0xff, 0x07); /* RESET_N=1 */
+	marimba_write(client, 0xff, 0x17); /* clock enable */
+	marimba_write(client, 0x03, 0x04); /* enable band gap */
+	marimba_write(client, 0x8F, 0x44); /* dither delay select, dmic gain bypass */
+
+	msleep(100);
+
+	adie_load(client, init_rx);
+	adie_load(client, init_speaker_48k_256_stereo);
+}
+
+static int marimba_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	int ret;
+
+	marimba_client = client;
+
+	printk("*** marimba probe %p '%s' @ 0x%x ** *\n",
+	       client, client->name, client->addr);
+
+	/* 0x10 -> MARIMBA_MODE ?! */
+	marimba_raw_write(client, MARIMBA_ADDR_MARIMBA, 0x00, 0x10);
+
+	/* program address into marimba master device */
+	ret = marimba_raw_write(client, MARIMBA_ADDR_MARIMBA,
+				MARIMBA_REG_ID_CDC, client->addr);
+
+	if (ret != 1) {
+		pr_err("marimba_probe() cannot set address\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+
+static const struct i2c_device_id marimba_id[] = {
+	{ "marimba-codec", 0 },
+	{ }
+};
+
+static struct i2c_driver marimba_driver = {
+	.probe		= marimba_probe,
+	.id_table	= marimba_id,
+	.driver		= {
+		.name = "marimba",
+	},
+};
+
+
+static int marimba_init(void)
+{
+	int ret;	
+	ret = marimba_vreg_init();
+	if (ret)
+		return ret;
+	return i2c_add_driver(&marimba_driver);
+}
+
+module_init(marimba_init);
diff --git a/arch/arm/mach-msm/qdsp6/Makefile b/arch/arm/mach-msm/qdsp6/Makefile
new file mode 100644
index 0000000..05cb351
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/Makefile
@@ -0,0 +1,9 @@
+obj-y += q6audio.o
+obj-y += pcm_out.o
+obj-y += pcm_in.o
+obj-y += mp3.o
+obj-y += routing.o
+obj-y += audio_ctl.o
+obj-y += msm_q6vdec.o
+obj-y += msm_q6venc.o
+obj-y += dsp_debug.o
\ No newline at end of file
diff --git a/arch/arm/mach-msm/qdsp6/analog_audio.c b/arch/arm/mach-msm/qdsp6/analog_audio.c
new file mode 100644
index 0000000..3ec80d4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/analog_audio.c
@@ -0,0 +1,67 @@
+
+#include <linux/gpio.h>
+#include "../pmic.h"
+#include <mach/msm_qdsp6_audio.h>
+
+#define GPIO_HEADSET_AMP 157
+
+void analog_init(void)
+{
+	/* stereo pmic init */
+	pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_mic_set_volt(MIC_VOLT_1_80V);
+
+	gpio_direction_output(GPIO_HEADSET_AMP, 1);
+	gpio_set_value(GPIO_HEADSET_AMP, 0);
+}
+
+void analog_headset_enable(int en)
+{
+	/* enable audio amp */
+	gpio_set_value(GPIO_HEADSET_AMP, !!en);
+}
+
+void analog_speaker_enable(int en)
+{
+	struct spkr_config_mode scm;
+	memset(&scm, 0, sizeof(scm));
+
+	if (en) {
+		scm.is_right_chan_en = 1;
+		scm.is_left_chan_en = 1;
+		scm.is_stereo_en = 1;
+		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, 1);
+		
+		/* unmute */
+		pmic_spkr_en_mute(LEFT_SPKR, 1);
+		pmic_spkr_en_mute(RIGHT_SPKR, 1);
+	} else {
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+
+		pmic_spkr_en(LEFT_SPKR, 0);
+		pmic_spkr_en(RIGHT_SPKR, 0);
+
+		pmic_set_spkr_configuration(&scm);
+	}
+}
+
+static struct q6audio_analog_ops ops = {
+	.init = analog_init,
+	.speaker_enable = analog_speaker_enable,
+	.headset_enable = analog_headset_enable,
+};
+
+static int __init init(void)
+{
+	q6audio_register_analog_ops(&ops);
+	return 0;
+}
+
+device_initcall(init);
diff --git a/arch/arm/mach-msm/qdsp6/audio_ctl.c b/arch/arm/mach-msm/qdsp6/audio_ctl.c
new file mode 100644
index 0000000..170b3eb
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audio_ctl.c
@@ -0,0 +1,176 @@
+/* arch/arm/mach-msm/qdsp6/audio_ctrl.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/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+
+#define BUFSZ (0)
+
+static DEFINE_MUTEX(voice_lock);
+static int voice_started;
+
+static struct audio_client *voc_tx_clnt;
+static struct audio_client *voc_rx_clnt;
+
+static int q6_voice_start(uint32_t rx_acdb_id, uint32_t tx_acdb_id)
+{
+	int rc = 0;
+
+	mutex_lock(&voice_lock);
+
+	if (voice_started) {
+		pr_err("voice: busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	voc_rx_clnt = q6voice_open(AUDIO_FLAG_WRITE, rx_acdb_id);
+	if (!voc_rx_clnt) {
+		pr_err("voice: open voice rx failed.\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	voc_tx_clnt = q6voice_open(AUDIO_FLAG_READ, tx_acdb_id);
+	if (!voc_tx_clnt) {
+		pr_err("voice: open voice tx failed.\n");
+		q6voice_close(voc_rx_clnt);
+		rc = -ENOMEM;
+	}
+
+	voice_started = 1;
+done:
+	mutex_unlock(&voice_lock);
+	return rc;
+}
+
+static int q6_voice_stop(void)
+{
+	mutex_lock(&voice_lock);
+	if (voice_started) {
+		q6voice_close(voc_tx_clnt);
+		q6voice_close(voc_rx_clnt);
+		voice_started = 0;
+	}
+	mutex_unlock(&voice_lock);
+	return 0;
+}
+
+static int q6_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int q6_ioctl(struct inode *inode, struct file *file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int rc;
+	uint32_t n;
+	uint32_t id[2];
+	char filename[64];
+
+	switch (cmd) {
+	case AUDIO_SWITCH_DEVICE:
+		rc = copy_from_user(&id, (void *)arg, sizeof(id));
+		if (rc) {
+			pr_err("%s: bad user address\n", __func__);
+			rc = -EFAULT;
+		} else
+			rc = q6audio_do_routing(id[0], id[1]);
+		break;
+	case AUDIO_SET_VOLUME:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		if (rc) {
+			pr_err("%s: bad user address\n", __func__);
+			rc = -EFAULT;
+		} else
+			rc = q6audio_set_rx_volume(n);
+		break;
+	case AUDIO_SET_MUTE:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		if (rc) {
+			pr_err("%s: bad user address\n", __func__);
+			rc = -EFAULT;
+		} else
+			rc = q6audio_set_tx_mute(n);
+		break;
+	case AUDIO_UPDATE_ACDB:
+		rc = copy_from_user(&id, (void *)arg, sizeof(id));
+		if (rc) {
+			pr_err("%s: bad user address\n", __func__);
+			rc = -EFAULT;
+		} else
+			rc = q6audio_update_acdb(id[0], id[1]);
+		break;
+	case AUDIO_START_VOICE:
+		if (arg == 0)
+			id[0] = id[1] = 0;
+		else if (copy_from_user(&id, (void *)arg, sizeof(id))) {
+			pr_info("voice: copy acdb_id from user failed\n");
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6_voice_start(id[0], id[1]);
+		break;
+	case AUDIO_STOP_VOICE:
+		rc = q6_voice_stop();
+		break;
+	case AUDIO_REINIT_ACDB:
+		rc = copy_from_user(&filename, (void *)arg, sizeof(filename));
+		if (rc) {
+			pr_err("%s: bad user address\n", __func__);
+			rc = -EFAULT;
+		} else
+			rc = q6audio_reinit_acdb(filename);
+		break;
+	default:
+		pr_info("%s: unknown %d\n", __func__, cmd);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+
+static int q6_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static struct file_operations q6_dev_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_open,
+	.ioctl		= q6_ioctl,
+	.release	= q6_release,
+};
+
+struct miscdevice q6_control_device = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_ctl",
+	.fops	= &q6_dev_fops,
+};
+
+
+static int __init q6_audio_ctl_init(void) {
+	return misc_register(&q6_control_device);
+}
+
+device_initcall(q6_audio_ctl_init);
diff --git a/arch/arm/mach-msm/qdsp6/dal_acdb.h b/arch/arm/mach-msm/qdsp6/dal_acdb.h
new file mode 100644
index 0000000..0e95b3b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_acdb.h
@@ -0,0 +1,84 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora Forum 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.
+ *
+ */
+
+#define ACDB_DAL_DEVICE		0x02000069
+#define ACDB_DAL_PORT		"SMD_DAL_AM_AUD"
+
+#define ACDB_OP_IOCTL		DAL_OP_FIRST_DEVICE_API
+
+/* ioctls */
+#define ACDB_GET_DEVICE		0x0108bb92
+#define ACDB_SET_DEVICE		0x0108bb93
+#define ACDB_GET_STREAM		0x0108bb95
+#define ACDB_SET_STREAM		0x0108bb96
+#define ACDB_GET_DEVICE_TABLE	0x0108bb97
+#define ACDB_GET_STREAM_TABLE	0x0108bb98
+
+#define ACDB_RES_SUCCESS	0
+#define ACDB_RES_FAILURE	-1
+#define ACDB_RES_BADPARM	-2
+#define ACDB_RES_BADSTATE	-3
+
+struct acdb_cmd_device {
+	uint32_t size;
+
+	uint32_t command_id;
+	uint32_t device_id;
+	uint32_t network_id;
+	uint32_t sample_rate_id;
+	uint32_t interface_id;
+	uint32_t algorithm_block_id;
+
+	/* physical page aligned buffer */
+	uint32_t total_bytes;
+	uint32_t unmapped_buf;
+} __attribute__((packed));
+
+struct acdb_cmd_device_table {
+	uint32_t size;
+
+	uint32_t command_id;
+	uint32_t device_id;
+	uint32_t network_id;
+	uint32_t sample_rate_id;
+
+	/* physical page aligned buffer */
+	uint32_t total_bytes;
+	uint32_t unmapped_buf;
+
+	uint32_t res_size;
+} __attribute__((packed));
+
+struct acdb_result {
+	uint32_t dal_status;
+	uint32_t size;
+
+	uint32_t unmapped_buf;
+	uint32_t used_bytes;
+	uint32_t result;
+} __attribute__((packed));
diff --git a/arch/arm/mach-msm/qdsp6/dal_adie.h b/arch/arm/mach-msm/qdsp6/dal_adie.h
new file mode 100644
index 0000000..99e3c63
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_adie.h
@@ -0,0 +1,108 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora Forum 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.
+ *
+ */
+
+#ifndef _MACH_MSM_QDSP6_ADIE_
+#define _MACH_MSM_QDSP6_ADIE_
+
+#include "../dal.h"
+
+#define ADIE_DAL_DEVICE		0x02000029
+#define ADIE_DAL_PORT		"SMD_DAL_AM_AUD"
+
+enum {
+	ADIE_OP_GET_NUM_PATHS = DAL_OP_FIRST_DEVICE_API,
+	ADIE_OP_GET_ALL_PATH_IDS,
+	ADIE_OP_SET_PATH,
+	ADIE_OP_GET_NUM_PATH_FREQUENCY_PLANS,
+	ADIE_OP_GET_PATH_FREQUENCY_PLANS,
+	ADIE_OP_SET_PATH_FREQUENCY_PLAN,
+	ADIE_OP_PROCEED_TO_STAGE,
+	ADIE_OP_MUTE_PATH
+};
+
+/* Path IDs for normal operation. */
+#define ADIE_PATH_HANDSET_TX			0x010740f6
+#define ADIE_PATH_HANDSET_RX			0x010740f7
+#define ADIE_PATH_HEADSET_MONO_TX		0x010740f8
+#define ADIE_PATH_HEADSET_STEREO_TX		0x010740f9
+#define ADIE_PATH_HEADSET_MONO_RX		0x010740fa
+#define ADIE_PATH_HEADSET_STEREO_RX		0x010740fb
+#define ADIE_PATH_SPEAKER_TX			0x010740fc
+#define ADIE_PATH_SPEAKER_RX			0x010740fd
+#define ADIE_PATH_SPEAKER_STEREO_RX		0x01074101
+
+/* Path IDs used for TTY */
+#define ADIE_PATH_TTY_HEADSET_TX		0x010740fe
+#define ADIE_PATH_TTY_HEADSET_RX		0x010740ff
+
+/* Path IDs used by Factory Test Mode. */
+#define ADIE_PATH_FTM_MIC1_TX			0x01074108
+#define ADIE_PATH_FTM_MIC2_TX			0x01074107
+#define ADIE_PATH_FTM_HPH_L_RX			0x01074106
+#define ADIE_PATH_FTM_HPH_R_RX			0x01074104
+#define ADIE_PATH_FTM_EAR_RX			0x01074103
+#define ADIE_PATH_FTM_SPKR_RX			0x01074102
+
+/* Path IDs for Loopback */
+/* Path IDs used for Line in -> AuxPGA -> Line Out Stereo Mode*/
+#define ADIE_PATH_AUXPGA_LINEOUT_STEREO_LB	0x01074100
+/* Line in -> AuxPGA -> LineOut Mono */
+#define ADIE_PATH_AUXPGA_LINEOUT_MONO_LB	0x01073d82
+/* Line in -> AuxPGA -> Stereo Headphone */
+#define ADIE_PATH_AUXPGA_HDPH_STEREO_LB		0x01074109
+/* Line in -> AuxPGA -> Mono Headphone */
+#define ADIE_PATH_AUXPGA_HDPH_MONO_LB		0x01073d85
+/* Line in -> AuxPGA -> Earpiece */
+#define ADIE_PATH_AUXPGA_EAP_LB			0x01073d81
+/* Line in -> AuxPGA -> AuxOut */
+#define ADIE_PATH_AUXPGA_AUXOUT_LB		0x01073d86
+
+/* Concurrency Profiles */
+#define ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX	0x01073d83
+#define ADIE_PATH_SPKR_MONO_HDPH_MONO_RX	0x01073d84
+#define ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX	0x01073d88
+#define ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX	0x01073d89
+
+/* stages */
+#define ADIE_STAGE_PATH_OFF			0x0050
+#define ADIE_STAGE_DIGITAL_READY		0x0100
+#define ADIE_STAGE_DIGITAL_ANALOG_READY		0x1000
+#define ADIE_STAGE_ANALOG_OFF			0x0750
+#define ADIE_STAGE_DIGITAL_OFF			0x0600
+
+/* path types */
+#define ADIE_PATH_RX		0
+#define ADIE_PATH_TX		1
+#define ADIE_PATH_LOOPBACK	2
+
+/* mute states */
+#define ADIE_MUTE_OFF		0
+#define ADIE_MUTE_ON		1
+
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/dal_audio.h b/arch/arm/mach-msm/qdsp6/dal_audio.h
new file mode 100644
index 0000000..b1ad07d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_audio.h
@@ -0,0 +1,565 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora Forum 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.
+ *
+ */
+
+#ifndef __DAL_AUDIO_H__
+#define __DAL_AUDIO_H__
+
+#include "dal_audio_format.h"
+
+#define AUDIO_DAL_DEVICE 0x02000028
+#define AUDIO_DAL_PORT "DSP_DAL_AQ_AUD"
+
+enum {
+	AUDIO_OP_CONTROL = DAL_OP_FIRST_DEVICE_API,
+	AUDIO_OP_DATA,
+	AUDIO_OP_INIT,
+};	
+
+/* ---- common audio structures ---- */
+
+/* This flag, if set, indicates that the beginning of the data in the*/
+/* buffer is a synchronization point or key frame, meaning no data */
+/* before it in the stream is required in order to render the stream */
+/* from this point onward. */
+#define ADSP_AUDIO_BUFFER_FLAG_SYNC_POINT        0x01
+
+/* This flag, if set, indicates that the buffer object is using valid */
+/* physical address used to store the media data */
+#define ADSP_AUDIO_BUFFER_FLAG_PHYS_ADDR         0x04
+
+/* This flag, if set, indicates that a media start timestamp has been */
+/* set for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_START_SET         0x08
+
+/* This flag, if set, indicates that a media stop timestamp has been set */
+/* for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_STOP_SET          0x10
+
+/* This flag, if set, indicates that a preroll timestamp has been set */
+/* for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_PREROLL_SET       0x20
+
+/* This flag, if set, indicates that the data in the buffer is a fragment of */
+/* a larger block of data, and will be continued by the data in the next */
+/* buffer to be delivered. */
+#define ADSP_AUDIO_BUFFER_FLAG_CONTINUATION      0x40
+
+struct adsp_audio_buffer {
+	u32 addr;		/* Physical Address of buffer */
+	u32 max_size;		/* Maximum size of buffer */
+	u32 actual_size;	/* Actual size of valid data in the buffer */
+	u32 offset;		/* Offset to the first valid byte */
+	u32 flags;		/* ADSP_AUDIO_BUFFER_FLAGs that has been set */
+	s64 start;		/* Start timestamp, if any */
+	s64 stop;		/* Stop timestamp, if any */
+	s64 preroll;		/* Preroll timestamp, if any */
+} __attribute__ ((packed));
+
+
+
+/* ---- audio commands ---- */
+
+/* Command/event response types */
+#define ADSP_AUDIO_RESPONSE_COMMAND   0
+#define ADSP_AUDIO_RESPONSE_ASYNC     1
+
+struct adsp_command_hdr {
+	u32 size;		/* sizeof(cmd) - sizeof(u32) */
+
+	u32 dst;
+	u32 src;
+
+	u32 opcode;
+	u32 response_type;
+	u32 seq_number;
+
+	u32 context;		/* opaque to DSP */
+	u32 data;
+
+	u32 padding;
+} __attribute__ ((packed));
+
+
+#define AUDIO_DOMAIN_APP	0
+#define AUDIO_DOMAIN_MODEM	1
+#define AUDIO_DOMAIN_DSP	2
+
+#define AUDIO_SERVICE_AUDIO	0
+#define AUDIO_SERVICE_VIDEO	1 /* really? */
+
+/* adsp audio addresses are (byte order) domain, service, major, minor */
+//#define AUDIO_ADDR(maj,min) ( (((maj) & 0xff) << 16) | (((min) & 0xff) << 24) | (1) )
+
+#define AUDIO_ADDR(maj,min,dom) ( (((min) & 0xff) << 24) | (((maj) & 0xff) << 16) | ((AUDIO_SERVICE_AUDIO) << 8) | (dom) )
+
+
+/* AAC Encoder modes */
+#define ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE		0
+#define ADSP_AUDIO_ENC_AAC_PLUS_MODE		1
+#define ADSP_AUDIO_ENC_ENHANCED_AAC_PLUS_MODE	2
+
+struct adsp_audio_aac_enc_cfg {
+	u32 bit_rate;		/* bits per second */
+	u32 encoder_mode;	/* ADSP_AUDIO_ENC_* */
+} __attribute__ ((packed));
+
+#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_LOUNDNESS     0
+#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_SNR           1
+
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_MONO                1
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_STEREO              2
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_DUAL                8
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_JOINT_STEREO        9
+
+struct adsp_audio_sbc_encoder_cfg {
+	u32 num_subbands;
+	u32 block_len;
+	u32 channel_mode;
+	u32 allocation_method;
+	u32 bit_rate;
+} __attribute__ ((packed));
+
+/* AMR NB encoder modes */
+#define ADSP_AUDIO_AMR_MR475	0
+#define ADSP_AUDIO_AMR_MR515	1
+#define ADSP_AUDIO_AMR_MMR59	2
+#define ADSP_AUDIO_AMR_MMR67	3
+#define ADSP_AUDIO_AMR_MMR74	4
+#define ADSP_AUDIO_AMR_MMR795	5
+#define ADSP_AUDIO_AMR_MMR102	6
+#define ADSP_AUDIO_AMR_MMR122	7
+
+/* The following are valid AMR NB DTX modes */
+#define ADSP_AUDIO_AMR_DTX_MODE_OFF		0
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD1		1
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD2		2
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_AUTO		3
+
+/* AMR Encoder configuration */
+struct adsp_audio_amr_enc_cfg {
+	u32	mode;		/* ADSP_AUDIO_AMR_MR* */
+	u32	dtx_mode;	/* ADSP_AUDIO_AMR_DTX_MODE* */
+	u32	enable;		/* 1 = enable, 0 = disable */
+} __attribute__ ((packed));
+
+struct adsp_audio_qcelp13k_enc_cfg {
+	u16	min_rate;
+	u16	max_rate;
+} __attribute__ ((packed));
+
+struct adsp_audio_evrc_enc_cfg {
+	u16	min_rate;
+	u16	max_rate;
+} __attribute__ ((packed));
+
+union adsp_audio_codec_config {
+	struct adsp_audio_amr_enc_cfg amr;
+	struct adsp_audio_aac_enc_cfg aac;
+	struct adsp_audio_qcelp13k_enc_cfg qcelp13k;
+	struct adsp_audio_evrc_enc_cfg evrc;
+	struct adsp_audio_sbc_encoder_cfg sbc;
+} __attribute__ ((packed));
+
+
+/* This is the default value. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_NONE		0x0000
+
+/* This bit, if set, indicates that the AVSync mode is activated. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_AVSYNC		0x0001
+
+/* This bit, if set, indicates that the Sample Rate/Channel Mode */
+/* Change Notification mode is activated. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_SR_CM_NOTIFY	0x0002
+
+/* This bit, if set, indicates that the sync clock is enabled */
+#define  ADSP_AUDIO_OPEN_STREAM_MODE_ENABLE_SYNC_CLOCK	0x0004
+
+struct adsp_open_command {
+	struct adsp_command_hdr hdr;
+
+	u32 device;
+	u32 endpoint; /* address */
+
+	u32 stream_context;
+	u32 mode;
+
+	u32 buf_max_size;
+
+	union adsp_audio_format format;
+	union adsp_audio_codec_config config;
+} __attribute__ ((packed));
+
+
+/* --- audio control and stream session ioctls ---- */
+
+/* Opcode to open a device stream session to capture audio */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_READ			0x0108dd79
+
+/* Opcode to open a device stream session to render audio */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE			0x0108dd7a
+
+/* Opcode to open a device session, must open a device */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE		0x0108dd7b
+
+/* Close an existing stream or device */
+#define ADSP_AUDIO_IOCTL_CMD_CLOSE			0x0108d8bc
+
+
+
+/* A device switch requires three IOCTL */
+/* commands in the following sequence: PREPARE, STANDBY, COMMIT */
+
+/* adsp_audio_device_switch_command structure is needed for */
+/* DEVICE_SWITCH_PREPARE */
+
+/* Device switch protocol step #1. Pause old device and */
+/* generate silence for the old device. */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE	0x010815c4
+
+/* Device switch protocol step #2. Release old device, */
+/* create new device and generate silence for the new device. */
+
+/* When client receives ack for this IOCTL, the client can */
+/* start sending IOCTL commands to configure, calibrate and */
+/* change filter settings on the new device. */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY	0x010815c5
+
+/* Device switch protocol step #3. Start normal operations on new device */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT	0x01075ee7
+
+struct adsp_device_switch_command {
+	struct adsp_command_hdr hdr;
+	u32 old_device;
+	u32 new_device;
+	u8 device_class; /* 0 = i.rx, 1 = i.tx, 2 = e.rx, 3 = e.tx */
+	u8 device_type; /* 0 = rx, 1 = tx, 2 = both */
+} __attribute__ ((packed));
+
+
+
+/* --- audio control session ioctls ---- */
+
+#define ADSP_PATH_RX	0
+#define ADSP_PATH_TX	1
+#define ADSP_PATH_BOTH	2
+
+/* These commands will affect a logical device and all its associated */
+/* streams. */
+
+
+/* Set device volume. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL		0x0107605c
+
+struct adsp_set_dev_volume_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 path; /* 0 = rx, 1 = tx, 2 = both */
+	s32 volume;
+} __attribute__ ((packed));
+
+/* Set Device stereo volume. This command has data payload, */
+/* struct adsp_audio_set_dev_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_STEREO_VOL		0x0108df3e
+
+/* Set L, R cross channel gain for a Device. This command has */
+/* data payload, struct adsp_audio_set_dev_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_XCHAN_GAIN		0x0108df40
+
+/* Set device mute state. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE		0x0107605f
+
+struct adsp_set_dev_mute_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 path; /* 0 = rx, 1 = tx, 2 = both */
+	u32 mute; /* 1 = mute */
+} __attribute__ ((packed));
+
+/* Configure Equalizer for a device. */
+/* This command has payload struct adsp_audio_set_dev_equalizer_command. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_EQ_CONFIG	0x0108b10e
+
+/* Set configuration data for an algorithm aspect of a device. */
+/* This command has payload struct adsp_audio_set_dev_cfg_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG		0x0108b6cb
+
+struct adsp_set_dev_cfg_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 block_id;
+	u32 interface_id;
+	u32 phys_addr;
+	u32 phys_size;
+	u32 phys_used;
+} __attribute__ ((packed));
+
+/* Set configuration data for all interfaces of a device. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE	0x0108b6bf
+
+struct adsp_set_dev_cfg_table_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 phys_addr;
+	u32 phys_size;
+	u32 phys_used;
+} __attribute__ ((packed));
+
+/* ---- audio stream data commands ---- */
+
+#define ADSP_AUDIO_IOCTL_CMD_DATA_TX			0x0108dd7f
+#define ADSP_AUDIO_IOCTL_CMD_DATA_RX			0x0108dd80
+
+struct adsp_buffer_command {
+	struct adsp_command_hdr hdr;
+	struct adsp_audio_buffer buffer;
+} __attribute__ ((packed));
+
+
+
+/* ---- audio stream ioctls (only affect a single stream in a session) ---- */
+
+/* Stop stream for audio device. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_STOP		0x01075c54
+
+/* End of stream reached. Client will not send any more data. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_EOS			0x0108b150
+
+/* Do sample slipping/stuffing on AAC outputs. The payload of */
+/* this command is struct adsp_audio_slip_sample_command. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_SLIPSAMPLE		0x0108d40e
+
+/* Set stream volume. */
+/* This command has data payload, struct adsp_audio_set_volume_command. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL		0x0108c0de
+
+/* Set stream stereo volume. This command has data payload, */
+/* struct adsp_audio_set_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_STEREO_VOL		0x0108dd7c
+
+/* Set L, R cross channel gain for a Stream. This command has */
+/* data payload, struct adsp_audio_set_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_XCHAN_GAIN		0x0108dd7d
+
+/* Set stream mute state. */
+/* This command has data payload, struct adsp_audio_set_stream_mute. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE		0x0108c0df
+
+/* Reconfigure bit rate information. This command has data */
+/* payload, struct adsp_audio_set_bit_rate_command */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_BITRATE		0x0108ccf1
+
+/* Set Channel Mapping. This command has data payload, struct */
+/* This command has data payload struct adsp_audio_set_channel_map_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_CHANNELMAP		0x0108d32a
+
+/* Enable/disable AACPlus SBR. */
+/* This command has data payload struct adsp_audio_set_sbr_command */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_SBR			0x0108d416
+
+/* Enable/disable WMA Pro Chex and Fex. This command has data payload */
+/* struct adsp_audio_stream_set_wma_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_WMAPRO		0x0108d417
+
+
+/* ---- audio session ioctls (affect all streams in a session) --- */
+
+/* Start stream for audio device. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_START		0x010815c6
+
+/* Stop all stream(s) for audio session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_STOP		0x0108dd7e
+
+/* Pause the data flow for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_PAUSE		0x01075ee8
+
+/* Resume the data flow for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_RESUME		0x01075ee9
+
+/* Drop any unprocessed data buffers for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_FLUSH		0x01075eea
+
+/* Start Stream DTMF tone */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_START		0x0108c0dd
+
+/* Stop Stream DTMF tone */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_STOP		0x01087554
+
+/* Set Session volume. */
+/* This command has data payload, struct adsp_audio_set_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_VOL		0x0108d8bd
+
+/* Set session stereo volume. This command has data payload, */
+/* struct adsp_audio_set_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_STEREO_VOL		0x0108df3d
+
+/* Set L, R cross channel gain for a session. This command has */
+/* data payload, struct adsp_audio_set_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_XCHAN_GAIN		0x0108df3f
+
+/* Set Session mute state. */
+/* This command has data payload, struct adsp_audio_set_mute_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_MUTE		0x0108d8be
+
+/* Configure Equalizer for a stream. */
+/* This command has payload struct adsp_audio_set_equalizer_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_EQ_CONFIG		0x0108c0e0
+
+/* Set Audio Video sync information. */
+/* This command has data payload, struct adsp_audio_set_av_sync_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_AVSYNC		0x0108d1e2
+
+/* Get Audio Media Session time. */
+/* This command returns the audioTime in adsp_audio_unsigned64_event */
+#define ADSP_AUDIO_IOCTL_CMD_GET_AUDIO_TIME		0x0108c26c
+
+
+/* these command structures are used for both STREAM and SESSION ioctls */
+
+struct adsp_set_volume_command {
+	struct adsp_command_hdr hdr;
+	s32 volume;
+} __attribute__ ((packed));
+	
+struct adsp_set_mute_command {
+	struct adsp_command_hdr hdr;
+	u32 mute; /* 1 == mute */
+} __attribute__ ((packed));
+
+
+
+/* ---- audio events ---- */
+
+/* All IOCTL commands generate an event with the IOCTL opcode as the */
+/* event id after the IOCTL command has been executed. */
+
+/* This event is generated after a media stream session is opened. */
+#define ADSP_AUDIO_EVT_STATUS_OPEN				0x0108c0d6
+
+/* This event is generated after a media stream  session is closed. */
+#define ADSP_AUDIO_EVT_STATUS_CLOSE				0x0108c0d7
+
+/* Asyncronous buffer consumption. This event is generated after a */
+/* recived  buffer is consumed during rendering or filled during */
+/* capture opeartion. */
+#define ADSP_AUDIO_EVT_STATUS_BUF_DONE				0x0108c0d8
+
+/* This event is generated when rendering operation is starving for */
+/* data. In order to avoid audio loss at the end of a plauback, the */
+/* client should wait for this event before issuing the close command. */
+#define ADSP_AUDIO_EVT_STATUS_BUF_UNDERRUN			0x0108c0d9
+
+/* This event is generated during capture operation when there are no */
+/* buffers available to copy the captured audio data */
+#define ADSP_AUDIO_EVT_STATUS_BUF_OVERFLOW			0x0108c0da
+
+/* This asynchronous event is generated as a result of an input */
+/* sample rate change and/or channel mode change detected by the */
+/* decoder. The event payload data is an array of 2 uint32 */
+/* values containing the sample rate in Hz and channel mode. */
+#define ADSP_AUDIO_EVT_SR_CM_CHANGE				0x0108d329
+
+struct adsp_event_hdr {
+	u32 evt_handle;		/* DAL common header */
+	u32 evt_cookie;
+	u32 evt_length;
+
+	u32 src;		/* "source" audio address */
+	u32 dst;		/* "destination" audio address */
+
+	u32 event_id;
+	u32 response_type;
+	u32 seq_number;
+
+	u32 context;		/* opaque to DSP */
+	u32 data;
+
+	u32 status;
+} __attribute__ ((packed));
+
+struct adsp_buffer_event {
+	struct adsp_event_hdr hdr;
+	struct adsp_audio_buffer buffer;
+} __attribute__ ((packed));
+
+
+/* ---- audio device IDs ---- */
+
+/* Device direction Rx/Tx flag */
+#define ADSP_AUDIO_RX_DEVICE		0x00
+#define ADSP_AUDIO_TX_DEVICE		0x01
+
+/* Default RX or TX device */
+#define ADSP_AUDIO_DEVICE_ID_DEFAULT		0x1081679
+
+/* Source (TX) devices */
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_MIC	0x107ac8d
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_MIC	0x1081510
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC	0x1081512
+#define ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC		0x1081518
+#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC	0x108151b
+#define ADSP_AUDIO_DEVICE_ID_I2S_MIC		0x1089bf3
+
+/* Special loopback pseudo device to be paired with an RX device */
+/* with usage ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK */
+#define ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX	0x1089bf2
+
+/* Sink (RX) devices */
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR			0x107ac88
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO			0x1081511
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO		0x107ac8a
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO			0x1081513
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET     0x108c508
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET   0x108c894
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO			0x1081514
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET   0x108c895
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET	0x108c509
+#define ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR			0x1081519
+#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR			0x108151c
+#define ADSP_AUDIO_DEVICE_ID_I2S_SPKR				0x1089bf4
+#define ADSP_AUDIO_DEVICE_ID_NULL_SINK				0x108e512
+
+/* BT A2DP playback device. */
+/* This device must be paired with */
+/* ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX using  */
+/* ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK mode */
+#define ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR	0x108151a
+
+/* Voice Destination identifier - specifically used for */
+/* controlling Voice module from the Device Control Session */
+#define ADSP_AUDIO_DEVICE_ID_VOICE		0x0108df3c
+
+/*  Audio device usage types. */
+/*  This is a bit mask to determine which topology to use in the */
+/* device session */
+#define ADSP_AUDIO_DEVICE_CONTEXT_VOICE			0x01
+#define ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK		0x02
+#define ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD		0x10
+#define ADSP_AUDIO_DEVICE_CONTEXT_RECORD		0x20
+#define ADSP_AUDIO_DEVICE_CONTEXT_PCM_LOOPBACK		0x40
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/dal_audio_format.h b/arch/arm/mach-msm/qdsp6/dal_audio_format.h
new file mode 100644
index 0000000..cdb2e1a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_audio_format.h
@@ -0,0 +1,285 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT 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.
+ *
+ */
+
+#ifndef __ADSP_AUDIO_MEDIA_FORMAT_H
+#define __ADSP_AUDIO_MEDIA_FORMAT_H
+
+
+
+/* Supported audio media formats */
+
+/* format block in shmem */
+#define ADSP_AUDIO_FORMAT_SHAREDMEMORY	0x01091a78
+/* adsp_audio_format_raw_pcm type */
+#define ADSP_AUDIO_FORMAT_PCM		0x0103d2fd
+/* adsp_audio_format_raw_pcm type */
+#define ADSP_AUDIO_FORMAT_DTMF		0x01087725
+/* adsp_audio_format_adpcm type */
+#define ADSP_AUDIO_FORMAT_ADPCM		0x0103d2ff
+/* Yamaha PCM format */
+#define ADSP_AUDIO_FORMAT_YADPCM	0x0108dc07
+/* ISO/IEC 11172 */
+#define ADSP_AUDIO_FORMAT_MP3		0x0103d308
+/* ISO/IEC 14496 */
+#define ADSP_AUDIO_FORMAT_MPEG4_AAC	0x010422f1
+/* AMR-NB audio in FS format */
+#define ADSP_AUDIO_FORMAT_AMRNB_FS	0x0105c16c
+/* AMR-WB audio in FS format */
+#define ADSP_AUDIO_FORMAT_AMRWB_FS	0x0105c16e
+/* QCELP 13k, IS733 */
+#define ADSP_AUDIO_FORMAT_V13K_FS	0x01080b8a
+/* EVRC   8k, IS127 */
+#define ADSP_AUDIO_FORMAT_EVRC_FS	0x01080b89
+/* EVRC-B   8k, 4GV */
+#define ADSP_AUDIO_FORMAT_EVRCB_FS	0x0108f2a3
+/* MIDI command stream */
+#define ADSP_AUDIO_FORMAT_MIDI		0x0103d300
+/* A2DP SBC stream */
+#define ADSP_AUDIO_FORMAT_SBC		0x0108c4d8
+/* Version 10 Professional */
+#define ADSP_AUDIO_FORMAT_WMA_V10PRO	0x0108aa92
+/* Version 9 Starndard */
+#define ADSP_AUDIO_FORMAT_WMA_V9	0x0108d430
+/* AMR WideBand Plus */
+#define ADSP_AUDIO_FORMAT_AMR_WB_PLUS	0x0108f3da
+/* AC3 Decoder */
+#define ADSP_AUDIO_FORMAT_AC3_DECODER	0x0108d5f9
+
+
+/* Not yet supported audio media formats */
+
+
+
+/* ISO/IEC 13818 */
+#define ADSP_AUDIO_FORMAT_MPEG2_AAC	0x0103d309
+/* 3GPP TS 26.101 Sec 4.0 */
+#define ADSP_AUDIO_FORMAT_AMRNB_IF1	0x0103d305
+/* 3GPP TS 26.101 Annex A */
+#define ADSP_AUDIO_FORMAT_AMRNB_IF2	0x01057b31
+/* 3GPP TS 26.201 */
+#define ADSP_AUDIO_FORMAT_AMRWB_IF1	0x0103d306
+/* 3GPP TS 26.201 */
+#define ADSP_AUDIO_FORMAT_AMRWB_IF2	0x0105c16d
+/* G.711 */
+#define ADSP_AUDIO_FORMAT_G711		0x0106201d
+/* QCELP  8k, IS96A */
+#define ADSP_AUDIO_FORMAT_V8K_FS	0x01081d29
+/* Version 1 codec */
+#define ADSP_AUDIO_FORMAT_WMA_V1	0x01055b2b
+/* Version 2, 7 & 8 codec */
+#define ADSP_AUDIO_FORMAT_WMA_V8	0x01055b2c
+/* Version 9 Professional codec */
+#define ADSP_AUDIO_FORMAT_WMA_V9PRO	0x01055b2d
+/* Version 9 Voice codec */
+#define ADSP_AUDIO_FORMAT_WMA_SP1	0x01055b2e
+/* Version 9 Lossless codec */
+#define ADSP_AUDIO_FORMAT_WMA_LOSSLESS	0x01055b2f
+/* Real Media content, low-bitrate */
+#define ADSP_AUDIO_FORMAT_RA_SIPR	0x01042a0f
+/* Real Media content */
+#define ADSP_AUDIO_FORMAT_RA_COOK	0x01042a0e
+
+
+/* For all of the audio formats, unless specified otherwise, */
+/* the following apply: */
+/* Format block bits are arranged in bytes and words in little-endian */
+/* order, i.e., least-significant bit first and least-significant */
+/* byte first. */
+
+
+
+/* AAC Format Block. */
+
+/* AAC format block consist of a format identifier followed by */
+/* AudioSpecificConfig formatted according to ISO/IEC 14496-3 */
+
+/* The following AAC format identifiers are supported */
+#define ADSP_AUDIO_AAC_ADTS		0x010619cf
+#define ADSP_AUDIO_AAC_MPEG4_ADTS	0x010619d0
+#define ADSP_AUDIO_AAC_LOAS		0x010619d1
+#define ADSP_AUDIO_AAC_ADIF		0x010619d2
+#define ADSP_AUDIO_AAC_RAW		0x010619d3
+#define ADSP_AUDIO_AAC_FRAMED_RAW	0x0108c1fb
+
+
+#define ADSP_AUDIO_COMPANDING_ALAW	0x10619cd
+#define ADSP_AUDIO_COMPANDING_MLAW	0x10619ce
+
+/* Maxmum number of bytes allowed in a format block */
+#define ADSP_AUDIO_FORMAT_DATA_MAX 16
+
+
+struct adsp_audio_no_payload_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* no payload for this format type */
+} __attribute__ ((packed));
+
+
+/* For convenience, to be used as a standard format block */
+/* for various media types that don't need a unique format block */
+/* ie. PCM, DTMF, etc. */
+struct adsp_audio_standard_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u16		channels;
+	u16		bits_per_sample;
+	u32		sampling_rate;
+	u8		is_signed;
+	u8		is_interleaved;
+} __attribute__ ((packed));
+
+
+
+/* ADPCM format block */
+struct adsp_audio_adpcm_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u16		channels;
+	u16		bits_per_sample;
+	u32		sampling_rate;
+	u8		is_signed;
+	u8		is_interleaved;
+	u32		block_size;
+} __attribute__ ((packed));
+
+
+/* MIDI format block */
+struct adsp_audio_midi_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		sampling_rate;
+	u16		channels;
+	u16		mode;
+} __attribute__ ((packed));
+
+
+/* G711 format block */
+struct adsp_audio_g711_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		companding;
+} __attribute__ ((packed));
+
+
+struct adsp_audio_wma_pro_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u16		format_tag;
+	u16		channels;
+	u32		samples_per_sec;
+	u32		avg_bytes_per_sec;
+	u16		block_align;
+	u16		valid_bits_per_sample;
+	u32		channel_mask;
+	u16		encode_opt;
+	u16		advanced_encode_opt;
+	u32		advanced_encode_opt2;
+	u32		drc_peak_reference;
+	u32		drc_peak_target;
+	u32		drc_average_reference;
+	u32		drc_average_target;
+} __attribute__ ((packed));
+
+
+struct adsp_audio_amrwb_plus_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		size;
+	u32		version;
+	u32		channels;
+	u32		amr_band_mode;
+	u32		amr_dtx_mode;
+	u32		amr_frame_format;
+	u32		amr_isf_index;
+} __attribute__ ((packed));
+
+
+/* Binary Byte Stream Format */
+/* Binary format type that defines a byte stream, */
+/* can be used to specify any format (ie. AAC) */
+struct adsp_audio_binary_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	/* number of bytes set in byte stream */
+	u32		num_bytes;
+	/* Byte stream binary data */
+	u8		data[ADSP_AUDIO_FORMAT_DATA_MAX];
+} __attribute__ ((packed));
+
+
+struct adsp_audio_shared_memory_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* Number of bytes in shared memory */
+	u32		len;
+	/* Phyisical address to data in shared memory */
+	u32		address;
+} __attribute__ ((packed));
+
+
+/* Union of all format types */
+union adsp_audio_format {
+	/* Basic format block with no payload */
+	struct adsp_audio_no_payload_format	no_payload;
+	/* Generic format block PCM, DTMF */
+	struct adsp_audio_standard_format	standard;
+	/* ADPCM format block */
+	struct adsp_audio_adpcm_format		adpcm;
+	/* MIDI format block */
+	struct adsp_audio_midi_format		midi;
+	/* G711 format block */
+	struct adsp_audio_g711_format		g711;
+	/* WmaPro format block */
+	struct adsp_audio_wma_pro_format	wma_pro;
+	/* WmaPro format block */
+	struct adsp_audio_amrwb_plus_format	amrwb_plus;
+	/* binary (byte stream) format block, used for AAC */
+	struct adsp_audio_binary_format		binary;
+	/* format block in shared memory */
+	struct adsp_audio_shared_memory_format	shared_mem;
+};
+
+#endif
+
diff --git a/arch/arm/mach-msm/qdsp6/dsp_debug.c b/arch/arm/mach-msm/qdsp6/dsp_debug.c
new file mode 100644
index 0000000..71c10eb
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dsp_debug.c
@@ -0,0 +1,175 @@
+/* arch/arm/mach-msm/qdsp6/dsp_dump.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/io.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <asm/atomic.h>
+
+#include "../proc_comm.h"
+
+static wait_queue_head_t dsp_wait;
+static int dsp_has_crashed;
+static int dsp_wait_count;
+
+static atomic_t dsp_crash_count = ATOMIC_INIT(0);
+
+void q6audio_dsp_not_responding(void)
+{
+
+	if (atomic_add_return(1, &dsp_crash_count) != 1) {
+		pr_err("q6audio_dsp_not_responding() - parking additional crasher...\n");
+		for (;;)
+			msleep(1000);
+	}
+	if (dsp_wait_count) {
+		dsp_has_crashed = 1;
+		wake_up(&dsp_wait);
+
+		while (dsp_has_crashed != 2)
+			wait_event(dsp_wait, dsp_has_crashed == 2);
+	} else {
+		pr_err("q6audio_dsp_not_responding() - no waiter?\n");
+	}
+	BUG();
+}
+
+static int dsp_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t dsp_write(struct file *file, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	char cmd[32];
+
+	if (count >= sizeof(cmd))
+		return -EINVAL;
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	if (!strcmp(cmd, "wait-for-crash")) {
+		while (!dsp_has_crashed) {
+			int res;
+			dsp_wait_count++;
+			res = wait_event_interruptible(dsp_wait, dsp_has_crashed);
+			if (res < 0) {
+				dsp_wait_count--;
+				return res;
+			}
+		}
+#if defined(CONFIG_MACH_MAHIMAHI)
+		/* assert DSP NMI */
+		msm_proc_comm(PCOM_CUSTOMER_CMD1, 0, 0);
+		msleep(250);
+#endif
+	} else if (!strcmp(cmd, "boom")) {
+		q6audio_dsp_not_responding();
+	} else if (!strcmp(cmd, "continue-crash")) {
+		dsp_has_crashed = 2;
+		wake_up(&dsp_wait);
+	} else {
+		pr_err("unknown dsp_debug command: %s\n", cmd);
+	}
+
+	return count;
+}
+
+#define DSP_RAM_BASE 0x2E800000
+#define DSP_RAM_SIZE 0x01800000
+
+static unsigned copy_ok_count;
+
+static ssize_t dsp_read(struct file *file, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	size_t actual = 0;
+	size_t mapsize = PAGE_SIZE;
+	unsigned addr;
+	void __iomem *ptr;
+
+	if (*pos >= DSP_RAM_SIZE)
+		return 0;
+
+	if (*pos & (PAGE_SIZE - 1))
+		return -EINVAL;
+
+	addr = (*pos + DSP_RAM_BASE);
+
+	/* don't blow up if we're unaligned */
+	if (addr & (PAGE_SIZE - 1))
+		mapsize *= 2;
+
+	while (count >= PAGE_SIZE) {
+		ptr = ioremap(addr, mapsize);
+		if (!ptr) {
+			pr_err("dsp: map error @ %x\n", addr);
+			return -EFAULT;
+		}
+		if (copy_to_user(buf, ptr, PAGE_SIZE)) {
+			iounmap(ptr);
+			pr_err("dsp: copy error @ %p\n", buf);
+			return -EFAULT;
+		}
+		copy_ok_count += PAGE_SIZE;
+		iounmap(ptr);
+		addr += PAGE_SIZE;
+		buf += PAGE_SIZE;
+		actual += PAGE_SIZE;
+		count -= PAGE_SIZE;
+	}
+
+	*pos += actual;
+	return actual;
+}
+
+static int dsp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations dsp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= dsp_open,
+	.read		= dsp_read,
+	.write		= dsp_write,
+	.release	= dsp_release,
+};
+
+static struct miscdevice dsp_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "dsp_debug",
+	.fops	= &dsp_fops,
+};
+
+
+static int __init dsp_init(void)
+{
+	init_waitqueue_head(&dsp_wait);
+	return misc_register(&dsp_misc);
+}
+
+device_initcall(dsp_init);
diff --git a/arch/arm/mach-msm/qdsp6/mp3.c b/arch/arm/mach-msm/qdsp6/mp3.c
new file mode 100644
index 0000000..759afb1
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/mp3.c
@@ -0,0 +1,220 @@
+/* arch/arm/mach-msm/qdsp6/mp3.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/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+
+#define BUFSZ (8192)
+#define DMASZ (BUFSZ * 2)
+
+struct mp3 {
+	struct mutex lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+};
+
+static long mp3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct mp3 *mp3 = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&mp3->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME: {
+		int vol;
+		if (copy_from_user(&vol, (void*) arg, sizeof(vol))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6audio_set_stream_volume(mp3->ac, vol);
+		break;
+	}
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void*) arg, sizeof(acdb_id))) {
+			pr_info("pcm_out: copy acdb_id from user failed\n");
+			rc = -EFAULT;
+			break;
+		}
+		if (mp3->ac) {
+			rc = -EBUSY;
+		} else {
+			mp3->ac = q6audio_open_mp3(BUFSZ,
+				mp3->sample_rate, mp3->channel_count, acdb_id);
+			if (!mp3->ac)
+				rc = -ENOMEM;
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (mp3->ac) {
+			rc = -EBUSY;
+			break;
+		}
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count < 1 || config.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+		mp3->sample_rate = config.sample_rate;
+		mp3->channel_count = config.channel_count;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = BUFSZ;
+		config.buffer_count = 2;
+		config.sample_rate = mp3->sample_rate;
+		config.channel_count = mp3->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&mp3->lock);
+	return rc;
+}
+
+static int mp3_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	struct mp3 *mp3;
+	mp3 = kzalloc(sizeof(struct mp3), GFP_KERNEL);
+
+	if (!mp3)
+		return -ENOMEM;
+
+	mutex_init(&mp3->lock);
+	mp3->channel_count = 2;
+	mp3->sample_rate = 44100;
+
+	file->private_data = mp3;
+	return rc;
+}
+
+static ssize_t mp3_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct mp3 *mp3 = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	if (!mp3->ac)
+		mp3_ioctl(file, AUDIO_START, 0);
+
+	ac = mp3->ac;
+	if (!ac)
+		return -ENODEV;
+
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer))
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = xfer;
+		q6audio_write(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int mp3_fsync(struct file *f, struct dentry *dentry, int datasync)
+{
+	struct mp3 *mp3 = f->private_data;
+	if (mp3->ac)
+		return q6audio_async(mp3->ac);
+	return -ENODEV;
+}
+
+static int mp3_release(struct inode *inode, struct file *file)
+{
+	struct mp3 *mp3 = file->private_data;
+	if (mp3->ac)
+		q6audio_mp3_close(mp3->ac);
+	kfree(mp3);
+	return 0;
+}
+
+static struct file_operations mp3_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mp3_open,
+	.write		= mp3_write,
+	.fsync		= mp3_fsync,
+	.release	= mp3_release,
+	.unlocked_ioctl	= mp3_ioctl,
+};
+
+struct miscdevice mp3_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_mp3",
+	.fops	= &mp3_fops,
+};
+
+static int __init mp3_init(void) {
+	return misc_register(&mp3_misc);
+}
+
+device_initcall(mp3_init);
diff --git a/arch/arm/mach-msm/qdsp6/msm_q6vdec.c b/arch/arm/mach-msm/qdsp6/msm_q6vdec.c
new file mode 100644
index 0000000..a719dbd
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/msm_q6vdec.c
@@ -0,0 +1,941 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. 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 Code Aurora Forum 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.
+ *
+ */
+
+/*
+#define DEBUG_TRACE_VDEC
+#define DEBUG
+*/
+
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/wakelock.h>
+
+#include <linux/android_pmem.h>
+#include <linux/msm_q6vdec.h>
+
+#include "../dal.h"
+
+#define DALDEVICEID_VDEC_DEVICE		0x02000026
+#define DALDEVICEID_VDEC_PORTNAME	"DSP_DAL_AQ_VID"
+
+#define VDEC_INTERFACE_VERSION		0x00020000
+
+#define MAJOR_MASK			0xFFFF0000
+#define MINOR_MASK			0x0000FFFF
+
+#define VDEC_GET_MAJOR_VERSION(version)	(((version)&MAJOR_MASK)>>16)
+
+#define VDEC_GET_MINOR_VERSION(version)	((version)&MINOR_MASK)
+
+#ifdef DEBUG_TRACE_VDEC
+#define TRACE(fmt,x...)			\
+	do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0)
+#else
+#define TRACE(fmt,x...)		do { } while (0)
+#endif
+
+
+static DEFINE_MUTEX(idlecount_lock);
+static int idlecount;
+static struct wake_lock wakelock;
+static struct wake_lock idlelock;
+
+static void prevent_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (++idlecount == 1) {
+		wake_lock(&idlelock);
+		wake_lock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static void allow_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (--idlecount == 0) {
+		wake_unlock(&idlelock);
+		wake_unlock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+
+enum {
+	VDEC_DALRPC_INITIALIZE = DAL_OP_FIRST_DEVICE_API,
+	VDEC_DALRPC_SETBUFFERS,
+	VDEC_DALRPC_FREEBUFFERS,
+	VDEC_DALRPC_QUEUE,
+	VDEC_DALRPC_SIGEOFSTREAM,
+	VDEC_DALRPC_FLUSH,
+	VDEC_DALRPC_REUSEFRAMEBUFFER,
+	VDEC_DALRPC_GETDECATTRIBUTES,
+};
+
+enum {
+	VDEC_ASYNCMSG_DECODE_DONE = 0xdec0de00,
+	VDEC_ASYNCMSG_REUSE_FRAME,
+};
+
+struct vdec_init_cfg {
+	u32			decode_done_evt;
+	u32			reuse_frame_evt;
+	struct vdec_config	cfg;
+};
+
+struct vdec_buffer_status {
+	u32			data;
+	u32			status;
+};
+
+#define VDEC_MSG_MAX		128
+
+struct vdec_msg_list {
+	struct list_head	list;
+	struct vdec_msg		vdec_msg;
+};
+
+struct vdec_mem_info {
+	u32			buf_type;
+	u32			id;
+	unsigned long		phys_addr;
+	unsigned long		len;
+	struct file		*file;
+};
+
+struct vdec_mem_list {
+	struct list_head	list;
+	struct vdec_mem_info	mem;
+};
+
+struct vdec_data {
+	struct dal_client	*vdec_handle;
+	struct list_head	vdec_msg_list_head;
+	struct list_head	vdec_msg_list_free;
+	wait_queue_head_t	vdec_msg_evt;
+	spinlock_t		vdec_list_lock;
+	struct list_head	vdec_mem_list_head;
+	spinlock_t		vdec_mem_list_lock;
+	int			mem_initialized;
+	int			running;
+	int			close_decode;
+};
+
+static struct class *driver_class;
+static dev_t vdec_device_no;
+static struct cdev vdec_cdev;
+static int ref_cnt;
+static DEFINE_MUTEX(vdec_ref_lock);
+
+static inline int vdec_check_version(u32 client, u32 server)
+{
+	int ret = -EINVAL;
+	if ((VDEC_GET_MAJOR_VERSION(client) == VDEC_GET_MAJOR_VERSION(server))
+	    && (VDEC_GET_MINOR_VERSION(client) <=
+		VDEC_GET_MINOR_VERSION(server)))
+		ret = 0;
+	return ret;
+}
+
+static int vdec_get_msg(struct vdec_data *vd, void *msg)
+{
+	struct vdec_msg_list *l;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!vd->running)
+		return -EPERM;
+
+	spin_lock_irqsave(&vd->vdec_list_lock, flags);
+	list_for_each_entry_reverse(l, &vd->vdec_msg_list_head, list) {
+		if (copy_to_user(msg, &l->vdec_msg, sizeof(struct vdec_msg)))
+			pr_err("vdec_get_msg failed to copy_to_user!\n");
+		if (l->vdec_msg.id == VDEC_MSG_REUSEINPUTBUFFER)
+			TRACE("reuse_input_buffer %d\n", l->vdec_msg.buf_id);
+		else if (l->vdec_msg.id == VDEC_MSG_FRAMEDONE)
+			TRACE("frame_done (stat=%d)\n",
+			      l->vdec_msg.vfr_info.status);
+		else
+			TRACE("unknown msg (msgid=%d)\n", l->vdec_msg.id);
+		list_del(&l->list);
+		list_add(&l->list, &vd->vdec_msg_list_free);
+		ret = 1;
+		break;
+	}
+	spin_unlock_irqrestore(&vd->vdec_list_lock, flags);
+
+	if (vd->close_decode)
+		ret = 1;
+
+	return ret;
+}
+
+static void vdec_put_msg(struct vdec_data *vd, struct vdec_msg *msg)
+{
+	struct vdec_msg_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	spin_lock_irqsave(&vd->vdec_list_lock, flags);
+	list_for_each_entry(l, &vd->vdec_msg_list_free, list) {
+		memcpy(&l->vdec_msg, msg, sizeof(struct vdec_msg));
+		list_del(&l->list);
+		list_add(&l->list, &vd->vdec_msg_list_head);
+		found = 1;
+		break;
+	}
+	spin_unlock_irqrestore(&vd->vdec_list_lock, flags);
+
+	if (found)
+		wake_up(&vd->vdec_msg_evt);
+	else
+		pr_err("vdec_put_msg can't find free list!\n");
+}
+
+static struct vdec_mem_list *vdec_get_mem_from_list(struct vdec_data *vd,
+						    u32 pmem_id, u32 buf_type)
+{
+	struct vdec_mem_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
+	list_for_each_entry(l, &vd->vdec_mem_list_head, list) {
+		if (l->mem.buf_type == buf_type && l->mem.id == pmem_id) {
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
+
+	if (found)
+		return l;
+	else
+		return NULL;
+
+}
+
+static int vdec_initialize(struct vdec_data *vd, void *argp)
+{
+	struct vdec_config_sps vdec_cfg_sps;
+	struct vdec_init_cfg vi_cfg;
+	struct vdec_buf_req vdec_buf_req;
+	struct u8 *header;
+	int ret = 0;
+
+	ret = copy_from_user(&vdec_cfg_sps,
+			     &((struct vdec_init *)argp)->sps_cfg,
+			     sizeof(vdec_cfg_sps));
+
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	vi_cfg.decode_done_evt = VDEC_ASYNCMSG_DECODE_DONE;
+	vi_cfg.reuse_frame_evt = VDEC_ASYNCMSG_REUSE_FRAME;
+	memcpy(&vi_cfg.cfg, &vdec_cfg_sps.cfg, sizeof(struct vdec_config));
+
+	header = kmalloc(vdec_cfg_sps.seq.len, GFP_KERNEL);
+	if (!header) {
+		pr_err("%s: kmalloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = copy_from_user(header,
+			     ((struct vdec_init *)argp)->sps_cfg.seq.header,
+			     vdec_cfg_sps.seq.len);
+
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		kfree(header);
+		return ret;
+	}
+
+	TRACE("vi_cfg: handle=%p fourcc=0x%x w=%d h=%d order=%d notify_en=%d "
+	      "vc1_rb=%d h264_sd=%d h264_nls=%d pp_flag=%d fruc_en=%d\n",
+	      vd->vdec_handle, vi_cfg.cfg.fourcc, vi_cfg.cfg.width,
+	      vi_cfg.cfg.height, vi_cfg.cfg.order, vi_cfg.cfg.notify_enable,
+	      vi_cfg.cfg.vc1_rowbase, vi_cfg.cfg.h264_startcode_detect,
+	      vi_cfg.cfg.h264_nal_len_size, vi_cfg.cfg.postproc_flag,
+	      vi_cfg.cfg.fruc_enable);
+	ret = dal_call_f13(vd->vdec_handle, VDEC_DALRPC_INITIALIZE,
+			   &vi_cfg, sizeof(vi_cfg),
+			   header, vdec_cfg_sps.seq.len,
+			   &vdec_buf_req, sizeof(vdec_buf_req));
+
+	kfree(header);
+
+	if (ret)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	else
+		ret = copy_to_user(((struct vdec_init *)argp)->buf_req,
+				   &vdec_buf_req, sizeof(vdec_buf_req));
+
+	vd->close_decode = 0;
+	return ret;
+}
+
+static int vdec_setbuffers(struct vdec_data *vd, void *argp)
+{
+	struct vdec_buffer vmem;
+	struct vdec_mem_list *l;
+	unsigned long vstart;
+	unsigned long flags;
+	struct {
+		uint32_t size;
+		struct vdec_buf_info buf;
+	} rpc;
+	uint32_t res;
+
+	int ret = 0;
+
+	vd->mem_initialized = 0;
+
+	ret = copy_from_user(&vmem, argp, sizeof(vmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	l = kzalloc(sizeof(struct vdec_mem_list), GFP_KERNEL);
+	if (!l) {
+		pr_err("%s: kzalloc failed!\n", __func__);
+		return -ENOMEM;
+	}
+
+	l->mem.id = vmem.pmem_id;
+	l->mem.buf_type = vmem.buf.buf_type;
+
+	ret = get_pmem_file(l->mem.id, &l->mem.phys_addr, &vstart,
+			    &l->mem.len, &l->mem.file);
+	if (ret) {
+		pr_err("%s: get_pmem_fd failed\n", __func__);
+		goto err_get_pmem_file;
+	}
+
+	TRACE("pmem_id=%d (phys=0x%08lx len=0x%lx) buftype=%d num_buf=%d "
+	      "islast=%d src_id=%d offset=0x%08x size=0x%x\n",
+	      vmem.pmem_id, l->mem.phys_addr, l->mem.len,
+	      vmem.buf.buf_type, vmem.buf.num_buf, vmem.buf.islast,
+	      vmem.buf.region.src_id, vmem.buf.region.offset,
+	      vmem.buf.region.size);
+
+	/* input buffers */
+	if ((vmem.buf.region.offset + vmem.buf.region.size) > l->mem.len) {
+		pr_err("%s: invalid input buffer offset!\n", __func__);
+		ret = -EINVAL;
+		goto err_bad_offset;
+
+	}
+	vmem.buf.region.offset += l->mem.phys_addr;
+
+	rpc.size = sizeof(vmem.buf);
+	memcpy(&rpc.buf, &vmem.buf, sizeof(struct vdec_buf_info));
+
+
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_SETBUFFERS, 5,
+		       &rpc, sizeof(rpc), &res, sizeof(res));
+
+	if (ret < 4) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		ret = -EIO;
+		goto err_dal_call;
+	}
+
+	spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
+	list_add(&l->list, &vd->vdec_mem_list_head);
+	spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
+
+	vd->mem_initialized = 1;
+	return ret;
+
+err_dal_call:
+err_bad_offset:
+	put_pmem_file(l->mem.file);
+err_get_pmem_file:
+	kfree(l);
+	return ret;
+}
+
+static int vdec_queue(struct vdec_data *vd, void *argp)
+{
+	struct {
+		uint32_t size;
+		struct vdec_input_buf_info buf_info;
+		uint32_t osize;
+	} rpc;
+	struct vdec_mem_list *l;
+	struct {
+		uint32_t result;
+		uint32_t size;
+		struct vdec_queue_status status;
+	} rpc_res;
+
+	u32 pmem_id;
+	int ret = 0;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s: memory is not being initialized!\n", __func__);
+		return -EPERM;
+	}
+
+	ret = copy_from_user(&rpc.buf_info,
+			     &((struct vdec_input_buf *)argp)->buffer,
+			     sizeof(rpc.buf_info));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	ret = copy_from_user(&pmem_id,
+			     &((struct vdec_input_buf *)argp)->pmem_id,
+			     sizeof(u32));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	l = vdec_get_mem_from_list(vd, pmem_id, VDEC_BUFFER_TYPE_INPUT);
+
+	if (NULL == l) {
+		pr_err("%s: not able to find the buffer from list\n", __func__);
+		return -EPERM;
+	}
+
+	if ((rpc.buf_info.size + rpc.buf_info.offset) >= l->mem.len) {
+		pr_err("%s: invalid queue buffer offset!\n", __func__);
+		return -EINVAL;
+	}
+
+	rpc.buf_info.offset += l->mem.phys_addr;
+	rpc.size = sizeof(struct vdec_input_buf_info);
+	rpc.osize = sizeof(struct vdec_queue_status);
+
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_QUEUE, 8,
+		       &rpc, sizeof(rpc), &rpc_res, sizeof(rpc_res));
+	if (ret < 4) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		ret = -EIO;
+	}
+	return ret;
+}
+
+static int vdec_reuse_framebuffer(struct vdec_data *vd, void *argp)
+{
+	u32 buf_id;
+	int ret = 0;
+
+	ret = copy_from_user(&buf_id, argp, sizeof(buf_id));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_REUSEFRAMEBUFFER,
+			  buf_id);
+	if (ret)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static int vdec_flush(struct vdec_data *vd, void *argp)
+{
+	u32 flush_type;
+	int ret = 0;
+
+	ret = copy_from_user(&flush_type, argp, sizeof(flush_type));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	TRACE("flush_type=%d\n", flush_type);
+	ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_FLUSH, flush_type);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int vdec_close(struct vdec_data *vd, void *argp)
+{
+	struct vdec_mem_list *l;
+	int ret = 0;
+
+	pr_info("q6vdec_close()\n");
+	vd->close_decode = 1;
+	wake_up(&vd->vdec_msg_evt);
+	ret = dal_call_f0(vd->vdec_handle, DAL_OP_CLOSE, 0);
+	if (ret)
+		pr_err("%s: failed to close daldevice (%d)\n", __func__, ret);
+
+	if (vd->mem_initialized) {
+		list_for_each_entry(l, &vd->vdec_mem_list_head, list)
+		    put_pmem_file(l->mem.file);
+	}
+
+	return ret;
+}
+static int vdec_getdecattributes(struct vdec_data *vd, void *argp)
+{
+	struct {
+		uint32_t status;
+		uint32_t size;
+		struct vdec_dec_attributes dec_attr;
+	} rpc;
+	uint32_t inp;
+	int ret = 0;
+	inp = sizeof(struct vdec_dec_attributes);
+
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_GETDECATTRIBUTES, 9,
+		       &inp, sizeof(inp), &rpc, sizeof(rpc));
+	if (ret < 4 || rpc.size != sizeof(struct vdec_dec_attributes)) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		ret = -EIO;
+	} else
+		ret =
+		    copy_to_user(((struct vdec_dec_attributes *)argp),
+				 &rpc.dec_attr, sizeof(rpc.dec_attr));
+	return ret;
+}
+
+static int vdec_freebuffers(struct vdec_data *vd, void *argp)
+{
+	struct vdec_buffer vmem;
+	struct vdec_mem_list *l;
+	struct {
+		uint32_t size;
+		struct vdec_buf_info buf;
+	} rpc;
+	uint32_t res;
+
+	int ret = 0;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s: memory is not being initialized!\n", __func__);
+		return -EPERM;
+	}
+
+	ret = copy_from_user(&vmem, argp, sizeof(vmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	l = vdec_get_mem_from_list(vd, vmem.pmem_id, vmem.buf.buf_type);
+
+	if (NULL == l) {
+		pr_err("%s: not able to find the buffer from list\n", __func__);
+		return -EPERM;
+	}
+
+	/* input buffers */
+	if ((vmem.buf.region.offset + vmem.buf.region.size) > l->mem.len) {
+		pr_err("%s: invalid input buffer offset!\n", __func__);
+		return -EINVAL;
+
+	}
+	vmem.buf.region.offset += l->mem.phys_addr;
+
+	rpc.size = sizeof(vmem.buf);
+	memcpy(&rpc.buf, &vmem.buf, sizeof(struct vdec_buf_info));
+
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_FREEBUFFERS, 5,
+		       &rpc, sizeof(rpc), &res, sizeof(res));
+	if (ret < 4) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	}
+
+	return ret;
+}
+static long vdec_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct vdec_data *vd = file->private_data;
+	void __user *argp = (void __user *)arg;
+	int ret = 0;
+
+	if (!vd->running)
+		return -EPERM;
+
+	switch (cmd) {
+	case VDEC_IOCTL_INITIALIZE:
+		ret = vdec_initialize(vd, argp);
+		break;
+
+	case VDEC_IOCTL_SETBUFFERS:
+		ret = vdec_setbuffers(vd, argp);
+		break;
+
+	case VDEC_IOCTL_QUEUE:
+		TRACE("VDEC_IOCTL_QUEUE (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_queue(vd, argp);
+		break;
+
+	case VDEC_IOCTL_REUSEFRAMEBUFFER:
+		TRACE("VDEC_IOCTL_REUSEFRAMEBUFFER (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_reuse_framebuffer(vd, argp);
+		break;
+
+	case VDEC_IOCTL_FLUSH:
+		ret = vdec_flush(vd, argp);
+		break;
+
+	case VDEC_IOCTL_EOS:
+		TRACE("VDEC_IOCTL_EOS (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_SIGEOFSTREAM, 0);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+			       __func__, ret);
+		break;
+
+	case VDEC_IOCTL_GETMSG:
+		TRACE("VDEC_IOCTL_GETMSG (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		wait_event_interruptible(vd->vdec_msg_evt,
+					 vdec_get_msg(vd, argp));
+
+		if (vd->close_decode)
+			ret = -EINTR;
+		break;
+
+	case VDEC_IOCTL_CLOSE:
+		ret = vdec_close(vd, argp);
+		break;
+
+	case VDEC_IOCTL_GETDECATTRIBUTES:
+		TRACE("VDEC_IOCTL_GETDECATTRIBUTES (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_getdecattributes(vd, argp);
+
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+			       __func__, ret);
+		break;
+
+	case VDEC_IOCTL_FREEBUFFERS:
+		TRACE("VDEC_IOCTL_FREEBUFFERS (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_freebuffers(vd, argp);
+
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+			       __func__, ret);
+		break;
+
+	default:
+		pr_err("%s: invalid ioctl!\n", __func__);
+		ret = -EINVAL;
+		break;
+	}
+
+	TRACE("ioctl done (pid=%d tid=%d)\n",
+	      current->group_leader->pid, current->pid);
+
+	return ret;
+}
+
+static void vdec_dcdone_handler(struct vdec_data *vd, void *frame,
+				uint32_t frame_size)
+{
+	struct vdec_msg msg;
+	struct vdec_mem_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	if (frame_size < sizeof(struct vdec_frame_info)) {
+		pr_warning("%s: msg size mismatch %d != %d\n", __func__,
+			   frame_size, sizeof(struct vdec_frame_info));
+		return;
+	}
+
+	memcpy(&msg.vfr_info, (struct vdec_frame_info *)frame,
+	       sizeof(struct vdec_frame_info));
+
+	if (msg.vfr_info.status == VDEC_FRAME_DECODE_OK) {
+		spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
+		list_for_each_entry(l, &vd->vdec_mem_list_head, list) {
+			if ((l->mem.buf_type == VDEC_BUFFER_TYPE_OUTPUT) &&
+			    (msg.vfr_info.offset >= l->mem.phys_addr) &&
+			    (msg.vfr_info.offset <
+			     (l->mem.phys_addr + l->mem.len))) {
+				found = 1;
+				msg.vfr_info.offset -= l->mem.phys_addr;
+				msg.vfr_info.data2 = l->mem.id;
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
+	}
+
+	if (found || (msg.vfr_info.status != VDEC_FRAME_DECODE_OK)) {
+		msg.id = VDEC_MSG_FRAMEDONE;
+		vdec_put_msg(vd, &msg);
+	} else {
+		pr_err("%s: invalid phys addr = 0x%x\n",
+		       __func__, msg.vfr_info.offset);
+	}
+
+}
+
+static void vdec_reuseibuf_handler(struct vdec_data *vd, void *bufstat,
+				   uint32_t bufstat_size)
+{
+	struct vdec_buffer_status *vdec_bufstat;
+	struct vdec_msg msg;
+
+	/* TODO: how do we signal the client? If they are waiting on a
+	 * message in an ioctl, they may block forever */
+	if (bufstat_size != sizeof(struct vdec_buffer_status)) {
+		pr_warning("%s: msg size mismatch %d != %d\n", __func__,
+			   bufstat_size, sizeof(struct vdec_buffer_status));
+		return;
+	}
+	vdec_bufstat = (struct vdec_buffer_status *)bufstat;
+	msg.id = VDEC_MSG_REUSEINPUTBUFFER;
+	msg.buf_id = vdec_bufstat->data;
+	vdec_put_msg(vd, &msg);
+}
+
+static void callback(void *data, int len, void *cookie)
+{
+	struct vdec_data *vd = (struct vdec_data *)cookie;
+	uint32_t *tmp = (uint32_t *) data;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s:memory not initialize but callback called!\n",
+		       __func__);
+		return;
+	}
+
+	TRACE("vdec_async: tmp=0x%08x 0x%08x 0x%08x\n", tmp[0], tmp[1], tmp[2]);
+	switch (tmp[0]) {
+	case VDEC_ASYNCMSG_DECODE_DONE:
+		vdec_dcdone_handler(vd, &tmp[3], tmp[2]);
+		break;
+	case VDEC_ASYNCMSG_REUSE_FRAME:
+		vdec_reuseibuf_handler(vd, &tmp[3], tmp[2]);
+		break;
+	default:
+		pr_err("%s: Unknown async message from DSP id=0x%08x sz=%u\n",
+		       __func__, tmp[0], tmp[2]);
+	}
+}
+static int vdec_open(struct inode *inode, struct file *file)
+{
+	int ret;
+	int i;
+	struct vdec_msg_list *l;
+	struct vdec_data *vd;
+
+	pr_info("q6vdec_open()\n");
+	mutex_lock(&vdec_ref_lock);
+	if (ref_cnt > 0) {
+		pr_err("%s: Instance alredy running\n", __func__);
+		mutex_unlock(&vdec_ref_lock);
+		return -ENOMEM;
+	}
+	ref_cnt++;
+	mutex_unlock(&vdec_ref_lock);
+	vd = kmalloc(sizeof(struct vdec_data), GFP_KERNEL);
+	if (!vd) {
+		pr_err("%s: kmalloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto vdec_open_err_handle_vd;
+	}
+	file->private_data = vd;
+
+	vd->mem_initialized = 0;
+	INIT_LIST_HEAD(&vd->vdec_msg_list_head);
+	INIT_LIST_HEAD(&vd->vdec_msg_list_free);
+	INIT_LIST_HEAD(&vd->vdec_mem_list_head);
+	init_waitqueue_head(&vd->vdec_msg_evt);
+
+	spin_lock_init(&vd->vdec_list_lock);
+	spin_lock_init(&vd->vdec_mem_list_lock);
+	for (i = 0; i < VDEC_MSG_MAX; i++) {
+		l = kzalloc(sizeof(struct vdec_msg_list), GFP_KERNEL);
+		if (!l) {
+			pr_err("%s: kzalloc failed!\n", __func__);
+			ret = -ENOMEM;
+			goto vdec_open_err_handle_list;
+		}
+		list_add(&l->list, &vd->vdec_msg_list_free);
+	}
+
+	vd->vdec_handle = dal_attach(DALDEVICEID_VDEC_DEVICE,
+				     DALDEVICEID_VDEC_PORTNAME,
+				     callback, vd);
+
+	if (!vd->vdec_handle) {
+		pr_err("%s: failed to attach \n", __func__);
+		ret = -EIO;
+		goto vdec_open_err_handle_list;
+	}
+
+	vd->running = 1;
+	prevent_sleep();
+	return 0;
+
+vdec_open_err_handle_list:
+	{
+		struct vdec_msg_list *l, *n;
+		list_for_each_entry_safe(l, n, &vd->vdec_msg_list_free, list) {
+			list_del(&l->list);
+			kfree(l);
+		}
+	}
+vdec_open_err_handle_vd:
+	kfree(vd);
+	return ret;
+}
+
+static int vdec_release(struct inode *inode, struct file *file)
+{
+	int ret;
+	struct vdec_msg_list *l, *n;
+	struct vdec_mem_list *m, *k;
+	struct vdec_data *vd = file->private_data;
+
+	vd->running = 0;
+	wake_up_all(&vd->vdec_msg_evt);
+
+	if (!vd->close_decode)
+		vdec_close(vd, NULL);
+
+	ret = dal_detach(vd->vdec_handle);
+	if (ret)
+		printk(KERN_INFO "%s: failed to detach (%d)\n", __func__, ret);
+
+	list_for_each_entry_safe(l, n, &vd->vdec_msg_list_free, list) {
+		list_del(&l->list);
+		kfree(l);
+	}
+
+	list_for_each_entry_safe(l, n, &vd->vdec_msg_list_head, list) {
+		list_del(&l->list);
+		kfree(l);
+	}
+
+	list_for_each_entry_safe(m, k, &vd->vdec_mem_list_head, list) {
+		list_del(&m->list);
+		kfree(m);
+	}
+	mutex_lock(&vdec_ref_lock);
+	BUG_ON(ref_cnt <= 0);
+	ref_cnt--;
+	mutex_unlock(&vdec_ref_lock);
+	kfree(vd);
+	allow_sleep();
+	return 0;
+}
+
+static const struct file_operations vdec_fops = {
+	.owner = THIS_MODULE,
+	.open = vdec_open,
+	.release = vdec_release,
+	.unlocked_ioctl = vdec_ioctl,
+};
+
+static int __init vdec_init(void)
+{
+	struct device *class_dev;
+	int rc = 0;
+
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "vdec_idle");
+	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "vdec_suspend");
+
+	rc = alloc_chrdev_region(&vdec_device_no, 0, 1, "vdec");
+	if (rc < 0) {
+		pr_err("%s: alloc_chrdev_region failed %d\n", __func__, rc);
+		return rc;
+	}
+
+	driver_class = class_create(THIS_MODULE, "vdec");
+	if (IS_ERR(driver_class)) {
+		rc = -ENOMEM;
+		pr_err("%s: class_create failed %d\n", __func__, rc);
+		goto vdec_init_err_unregister_chrdev_region;
+	}
+	class_dev = device_create(driver_class, NULL,
+				  vdec_device_no, NULL, "vdec");
+	if (!class_dev) {
+		pr_err("%s: class_device_create failed %d\n", __func__, rc);
+		rc = -ENOMEM;
+		goto vdec_init_err_class_destroy;
+	}
+
+	cdev_init(&vdec_cdev, &vdec_fops);
+	vdec_cdev.owner = THIS_MODULE;
+	rc = cdev_add(&vdec_cdev, MKDEV(MAJOR(vdec_device_no), 0), 1);
+
+	if (rc < 0) {
+		pr_err("%s: cdev_add failed %d\n", __func__, rc);
+		goto vdec_init_err_class_device_destroy;
+	}
+
+	return 0;
+
+vdec_init_err_class_device_destroy:
+	device_destroy(driver_class, vdec_device_no);
+vdec_init_err_class_destroy:
+	class_destroy(driver_class);
+vdec_init_err_unregister_chrdev_region:
+	unregister_chrdev_region(vdec_device_no, 1);
+	return rc;
+}
+
+static void __exit vdec_exit(void)
+{
+	device_destroy(driver_class, vdec_device_no);
+	class_destroy(driver_class);
+	unregister_chrdev_region(vdec_device_no, 1);
+}
+
+MODULE_DESCRIPTION("video decoder driver for QSD platform");
+MODULE_VERSION("2.00");
+
+module_init(vdec_init);
+module_exit(vdec_exit);
diff --git a/arch/arm/mach-msm/qdsp6/msm_q6venc.c b/arch/arm/mach-msm/qdsp6/msm_q6venc.c
new file mode 100644
index 0000000..7b4eb85
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/msm_q6venc.c
@@ -0,0 +1,1121 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Original driver and v2 protocol changes from Code Aurora.
+ * Heavily modified by Dima Zavin <dima@android.com>
+ * Further cleanup by Brian Swetland <swetland@google.com>
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/file.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/android_pmem.h>
+#include <linux/msm_q6venc.h>
+#include <linux/wakelock.h>
+
+//#include <asm/cacheflush.h>
+#include "../dal.h"
+
+#define DALDEVICEID_VENC_DEVICE		0x0200002D
+#define DALDEVICEID_VENC_PORTNAME	"DSP_DAL_AQ_VID"
+
+#define VENC_NAME			"q6venc"
+#define VENC_MSG_MAX			128
+
+#define VENC_INTERFACE_VERSION		0x00020000
+#define MAJOR_MASK			0xFFFF0000
+#define MINOR_MASK			0x0000FFFF
+#define VENC_GET_MAJOR_VERSION(version)	((version & MAJOR_MASK)>>16)
+#define VENC_GET_MINOR_VERSION(version)	(version & MINOR_MASK)
+
+#define VERSION_CHECK 0
+
+static DEFINE_MUTEX(idlecount_lock);
+static int idlecount;
+static struct wake_lock wakelock;
+static struct wake_lock idlelock;
+
+static void prevent_sleep(void)
+{
+        mutex_lock(&idlecount_lock);
+        if (++idlecount == 1) {
+                wake_lock(&idlelock);
+                wake_lock(&wakelock);
+	}
+        mutex_unlock(&idlecount_lock);
+}
+
+static void allow_sleep(void)
+{
+        mutex_lock(&idlecount_lock);
+        if (--idlecount == 0) {
+                wake_unlock(&idlelock);
+                wake_unlock(&wakelock);
+	}
+        mutex_unlock(&idlecount_lock);
+}
+
+enum {
+	VENC_BUFFER_TYPE_INPUT,
+	VENC_BUFFER_TYPE_OUTPUT,
+	VENC_BUFFER_TYPE_QDSP6,
+	VENC_BUFFER_TYPE_HDR
+};
+enum {
+	VENC_DALRPC_GET_SYNTAX_HEADER = DAL_OP_FIRST_DEVICE_API,
+	VENC_DALRPC_UPDATE_INTRA_REFRESH,
+	VENC_DALRPC_UPDATE_FRAME_RATE,
+	VENC_DALRPC_UPDATE_BITRATE,
+	VENC_DALRPC_UPDATE_QP_RANGE,
+	VENC_DALRPC_UPDATE_INTRA_PERIOD,
+	VENC_DALRPC_REQUEST_IFRAME,
+	VENC_DALRPC_START,
+	VENC_DALRPC_STOP,
+	VENC_DALRPC_SUSPEND,
+	VENC_DALRPC_RESUME,
+	VENC_DALRPC_FLUSH,
+	VENC_DALRPC_QUEUE_INPUT,
+	VENC_DALRPC_QUEUE_OUTPUT
+};
+struct venc_input_payload {
+	u32 data;
+};
+struct venc_output_payload {
+	u32 size;
+	long long time_stamp;
+	u32 flags;
+	u32 data;
+	u32 client_data_from_input;
+};
+union venc_payload {
+	struct venc_input_payload input_payload;
+	struct venc_output_payload output_payload;
+};
+struct venc_msg_type {
+	u32 event;
+	u32 status;
+	union venc_payload payload;
+};
+struct venc_input_buf {
+	struct venc_buf_type yuv_buf;
+	u32 data_size;
+	long long time_stamp;
+	u32 flags;
+	u32 dvs_offsetx;
+	u32 dvs_offsety;
+	u32 client_data;
+	u32 op_client_data;
+};
+struct venc_output_buf {
+	struct venc_buf_type bit_stream_buf;
+	u32 client_data;
+};
+struct venc_buf {
+	int fd;
+	u32 offset;
+	u32 size;
+	u32 btype;
+	unsigned long paddr;
+	struct file *file;
+};
+struct venc_pmem_list {
+	struct list_head list;
+	struct venc_buf buf;
+};
+struct venc_qmsg {
+	struct list_head list;
+	struct venc_msg msg;
+};
+struct venc_dev {
+	bool stop_called;
+	enum venc_state_type state;
+
+	struct list_head msg_pool;
+	struct list_head msg_queue;
+	spinlock_t msg_lock;
+
+	struct list_head venc_pmem_list_head;
+	spinlock_t venc_pmem_list_lock;
+	struct dal_client *q6_handle;
+	wait_queue_head_t venc_msg_evt;
+	struct device *class_devp;
+};
+
+#define DEBUG_VENC 0
+#if DEBUG_VENC
+#define TRACE(fmt, x...)     \
+	do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0)
+#else
+#define TRACE(fmt, x...)         do { } while (0)
+#endif
+
+static struct cdev cdev;
+static dev_t venc_dev_num;
+static struct class *venc_class;
+static struct venc_dev *venc_device_p;
+static int venc_ref;
+
+static inline int venc_check_version(u32 client, u32 server)
+{
+	int ret = -EINVAL;
+
+	if ((VENC_GET_MAJOR_VERSION(client) == VENC_GET_MAJOR_VERSION(server))
+	     && (VENC_GET_MINOR_VERSION(client) <=
+		 VENC_GET_MINOR_VERSION(server)))
+		ret = 0;
+
+	return ret;
+}
+
+static struct venc_qmsg *__dequeue(spinlock_t *lock, struct list_head *queue)
+{
+	unsigned long flags;
+	struct venc_qmsg *msg;
+	spin_lock_irqsave(lock, flags);
+	if (list_empty(queue)) {
+		msg = NULL;
+	} else {
+		msg = list_first_entry(queue, struct venc_qmsg, list);
+		list_del(&msg->list);
+	}
+	spin_unlock_irqrestore(lock, flags);
+	return msg;
+}
+
+static inline struct venc_qmsg *venc_alloc_msg(struct venc_dev *dvenc)
+{
+	return __dequeue(&dvenc->msg_lock, &dvenc->msg_pool);
+}
+static inline struct venc_qmsg *venc_recv_msg(struct venc_dev *dvenc)
+{
+	return __dequeue(&dvenc->msg_lock, &dvenc->msg_queue);
+}
+
+static void venc_free_msg(struct venc_dev *dvenc, struct venc_qmsg *msg)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dvenc->msg_lock, flags);
+	list_add_tail(&msg->list, &dvenc->msg_pool);
+	spin_unlock_irqrestore(&dvenc->msg_lock, flags);
+}
+
+static void venc_post(struct venc_dev *dvenc,
+		      unsigned code, unsigned status,
+		      union venc_msg_data *data)
+{
+	unsigned long flags;
+	struct venc_qmsg *msg;
+	msg = venc_alloc_msg(dvenc);
+	if (msg == NULL) {
+		pr_err("%s cannot alloc message\n", __func__);
+		return;
+	}
+	msg->msg.msg_code = code;
+	msg->msg.status_code = status;
+	if (data) {
+		msg->msg.msg_data_size = sizeof(union venc_msg_data);
+		memcpy(&msg->msg.msg_data, data, sizeof(union venc_msg_data));
+	} else {
+		msg->msg.msg_data_size = 0;
+	}
+
+	spin_lock_irqsave(&dvenc->msg_lock, flags);
+	list_add_tail(&msg->list, &dvenc->msg_queue);
+	spin_unlock_irqrestore(&dvenc->msg_lock, flags);
+	wake_up(&dvenc->venc_msg_evt);
+}
+
+static struct venc_pmem_list *venc_add_pmem_to_list(struct venc_dev *dvenc,
+						      struct venc_pmem *mptr,
+						      u32 btype)
+{
+	int ret = 0;
+	unsigned long flags;
+	unsigned long len;
+	unsigned long vaddr;
+	struct venc_pmem_list *plist = NULL;
+
+	plist = kzalloc(sizeof(struct venc_pmem_list), GFP_KERNEL);
+	if (!plist) {
+		pr_err("%s: kzalloc failed\n", __func__);
+		return NULL;
+	}
+
+	ret = get_pmem_file(mptr->fd, &(plist->buf.paddr),
+		&vaddr, &len, &(plist->buf.file));
+
+	/* xxx bounds checking insufficient here */
+	if (ret) {
+		pr_err("%s: get_pmem_file failed for fd=%d offset=%d\n",
+			__func__, mptr->fd, mptr->offset);
+		goto err_venc_add_pmem;
+	} else if (mptr->offset >= len) {
+		pr_err("%s: invalid offset (%d > %ld) for fd=%d\n",
+		       __func__, mptr->offset, len, mptr->fd);
+		ret = -EINVAL;
+		goto err_venc_get_pmem;
+	}
+
+	plist->buf.fd = mptr->fd;
+	plist->buf.paddr += mptr->offset;
+	plist->buf.size = mptr->size;
+	plist->buf.btype = btype;
+	plist->buf.offset = mptr->offset;
+
+	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
+	list_add(&plist->list, &dvenc->venc_pmem_list_head);
+	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
+	return plist;
+
+err_venc_get_pmem:
+	put_pmem_file(plist->buf.file);
+err_venc_add_pmem:
+	kfree(plist);
+	return NULL;
+}
+
+static struct venc_pmem_list *venc_get_pmem_from_list(
+		struct venc_dev *dvenc, u32 pmem_fd,
+		u32 offset, u32 btype)
+{
+	struct venc_pmem_list *plist;
+	unsigned long flags;
+	struct file *file;
+	int found = 0;
+
+	file = fget(pmem_fd);
+	if (!file) {
+		pr_err("%s: invalid encoder buffer fd(%d)\n", __func__,
+			pmem_fd);
+		return NULL;
+	}
+	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
+	list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list) {
+		if (plist->buf.btype == btype && plist->buf.file == file &&
+			plist->buf.offset == offset) {
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
+	fput(file);
+	if (found)
+		return plist;
+
+	else
+		return NULL;
+}
+
+static int venc_set_buffer(struct venc_dev *dvenc, void *argp,
+			     u32 btype)
+{
+	struct venc_pmem pmem;
+	struct venc_pmem_list *plist;
+	int ret = 0;
+
+	ret = copy_from_user(&pmem, argp, sizeof(pmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	plist = venc_add_pmem_to_list(dvenc, &pmem, btype);
+	if (plist == NULL) {
+		pr_err("%s: buffer add_to_pmem_list failed\n",
+			__func__);
+		return -EPERM;
+	}
+	return ret;
+}
+
+static int venc_assign_q6_buffers(struct venc_dev *dvenc,
+				    struct venc_buffers *pbufs,
+				    struct venc_nonio_buf_config *pcfg)
+{
+	int ret = 0;
+	struct venc_pmem_list *plist;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[0]),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: recon_buf0 failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->recon_buf1.region = 0;
+	pcfg->recon_buf1.phys = plist->buf.paddr;
+	pcfg->recon_buf1.size = plist->buf.size;
+	pcfg->recon_buf1.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[1]),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: recons_buf1 failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->recon_buf2.region = 0;
+	pcfg->recon_buf2.phys = plist->buf.paddr;
+	pcfg->recon_buf2.size = plist->buf.size;
+	pcfg->recon_buf2.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->wb_buf),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: wb_buf failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->wb_buf.region = 0;
+	pcfg->wb_buf.phys = plist->buf.paddr;
+	pcfg->wb_buf.size = plist->buf.size;
+	pcfg->wb_buf.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->cmd_buf),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: cmd_buf failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->cmd_buf.region = 0;
+	pcfg->cmd_buf.phys = plist->buf.paddr;
+	pcfg->cmd_buf.size = plist->buf.size;
+	pcfg->cmd_buf.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->vlc_buf),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: vlc_buf failed to add_to_pmem_list"
+		" failed\n", __func__);
+		return -EPERM;
+	}
+	pcfg->vlc_buf.region = 0;
+	pcfg->vlc_buf.phys = plist->buf.paddr;
+	pcfg->vlc_buf.size = plist->buf.size;
+	pcfg->vlc_buf.offset = 0;
+
+	return ret;
+}
+
+static int venc_start(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_q6_config q6_config;
+	struct venc_init_config vconfig;
+
+	dvenc->state = VENC_STATE_START;
+	ret = copy_from_user(&vconfig, argp, sizeof(struct venc_init_config));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	memcpy(&q6_config, &(vconfig.q6_config), sizeof(q6_config));
+	ret = venc_assign_q6_buffers(dvenc, &(vconfig.q6_bufs),
+		&(q6_config.buf_params));
+	if (ret != 0) {
+		pr_err("%s: assign_q6_buffers failed\n", __func__);
+		return -EPERM;
+	}
+
+	q6_config.callback_event = dvenc->q6_handle;
+	TRACE("%s: parameters: handle:%p, config:%p, callback:%p \n", __func__,
+		dvenc->q6_handle, &q6_config, q6_config.callback_event);
+	TRACE("%s: parameters:recon1:0x%x, recon2:0x%x,"
+		" wb_buf:0x%x, cmd:0x%x, vlc:0x%x\n", __func__,
+		q6_config.buf_params.recon_buf1.phys,
+		q6_config.buf_params.recon_buf2.phys,
+		q6_config.buf_params.wb_buf.phys,
+		q6_config.buf_params.cmd_buf.phys,
+		q6_config.buf_params.vlc_buf.phys);
+	TRACE("%s: size of param:%d \n", __func__, sizeof(q6_config));
+	ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_START, &q6_config,
+		sizeof(q6_config));
+	if (ret != 0) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		return ret;
+	}
+	return ret;
+}
+
+static int venc_encode_frame(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_pmem buf;
+	struct venc_input_buf q6_input;
+	struct venc_pmem_list *plist;
+	struct venc_buffer input;
+
+	ret = copy_from_user(&input, argp, sizeof(struct venc_buffer));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	ret = copy_from_user(&buf,
+			       ((struct venc_buffer *)argp)->ptr_buffer,
+			       sizeof(struct venc_pmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	plist = venc_get_pmem_from_list(dvenc, buf.fd, buf.offset,
+			VENC_BUFFER_TYPE_INPUT);
+	if (NULL == plist) {
+		plist = venc_add_pmem_to_list(dvenc, &buf,
+			VENC_BUFFER_TYPE_INPUT);
+		if (plist == NULL) {
+			pr_err("%s: buffer add_to_pmem_list failed\n",
+				__func__);
+			return -EPERM;
+		}
+	}
+
+	q6_input.flags = 0;
+	if (input.flags & VENC_FLAG_EOS)
+		q6_input.flags |= 0x00000001;
+	q6_input.yuv_buf.region = 0;
+	q6_input.yuv_buf.phys = plist->buf.paddr;
+	q6_input.yuv_buf.size = plist->buf.size;
+	q6_input.yuv_buf.offset = 0;
+	q6_input.data_size = plist->buf.size;
+	q6_input.client_data = (u32)input.client_data;
+	q6_input.time_stamp = input.time_stamp;
+	q6_input.dvs_offsetx = 0;
+	q6_input.dvs_offsety = 0;
+
+	TRACE("Pushing down input phys=0x%x fd= %d, client_data: 0x%x,"
+		" time_stamp:%lld \n", q6_input.yuv_buf.phys, plist->buf.fd,
+		input.client_data, input.time_stamp);
+	ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_INPUT,
+		&q6_input, sizeof(q6_input));
+
+	if (ret != 0)
+		pr_err("%s: Q6 queue_input failed (%d)\n", __func__,
+		(int)ret);
+	return ret;
+}
+
+static int venc_fill_output(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_pmem buf;
+	struct venc_output_buf q6_output;
+	struct venc_pmem_list *plist;
+	struct venc_buffer output;
+
+	ret = copy_from_user(&output, argp, sizeof(struct venc_buffer));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	ret = copy_from_user(&buf,
+			       ((struct venc_buffer *)argp)->ptr_buffer,
+			       sizeof(struct venc_pmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	plist =	venc_get_pmem_from_list(dvenc, buf.fd, buf.offset,
+			VENC_BUFFER_TYPE_OUTPUT);
+	if (NULL == plist) {
+		plist = venc_add_pmem_to_list(dvenc, &buf,
+				VENC_BUFFER_TYPE_OUTPUT);
+		if (NULL == plist) {
+			pr_err("%s: output buffer failed to add_to_pmem_list"
+				"\n", __func__);
+			return -EPERM;
+		}
+	}
+	q6_output.bit_stream_buf.region = 0;
+	q6_output.bit_stream_buf.phys = (u32)plist->buf.paddr;
+	q6_output.bit_stream_buf.size = plist->buf.size;
+	q6_output.bit_stream_buf.offset = 0;
+	q6_output.client_data = (u32)output.client_data;
+	ret =
+	    dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_OUTPUT, &q6_output,
+			sizeof(q6_output));
+	if (ret != 0)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	return ret;
+}
+
+static int venc_stop(struct venc_dev *dvenc)
+{
+	int ret = 0;
+
+	dvenc->stop_called = 1;
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1);
+	if (ret) {
+		pr_err("%s: remote runction failed (%d)\n", __func__, ret);
+		venc_post(dvenc, VENC_MSG_STOP, VENC_S_EFAIL, NULL);
+	}
+	return ret;
+}
+
+static int venc_pause(struct venc_dev *dvenc)
+{
+	int ret = 0;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_SUSPEND, 1);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		venc_post(dvenc, VENC_MSG_PAUSE, VENC_S_EFAIL, NULL);
+	}
+	return ret;
+}
+
+static int venc_resume(struct venc_dev *dvenc)
+{
+	int ret = 0;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_RESUME, 1);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		venc_post(dvenc, VENC_MSG_RESUME, VENC_S_EFAIL, NULL);
+	}
+	return ret;
+}
+
+static int venc_flush(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	int status = VENC_S_SUCCESS;
+	union venc_msg_data data;
+
+	if (copy_from_user(&data.flush_ret, argp, sizeof(struct venc_buffer_flush)))
+		return -EFAULT;
+
+	if (data.flush_ret.flush_mode == VENC_FLUSH_ALL) {
+		ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_FLUSH, 1);
+		if (ret)
+			status = VENC_S_EFAIL;
+	} else
+		status = VENC_S_ENOTSUPP;
+
+	if (status == VENC_S_SUCCESS)
+		return ret;
+
+	venc_post(dvenc, VENC_MSG_FLUSH, status, &data);
+	return -EIO;
+}
+
+static int venc_get_sequence_hdr(struct venc_dev *dvenc, void *argp)
+{
+	pr_err("%s not supported\n", __func__);
+	return -EIO;
+}
+
+static int venc_set_qp_range(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_qp_range qp;
+
+	ret = copy_from_user(&qp, argp, sizeof(struct venc_qp_range));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret =
+		    dal_call_f5(dvenc->q6_handle, VENC_DALRPC_UPDATE_QP_RANGE,
+				&qp, sizeof(struct venc_qp_range));
+		if (ret) {
+			pr_err("%s: remote function failed (%d) \n", __func__,
+				ret);
+			return ret;
+		}
+	}
+	return ret;
+}
+
+static int venc_set_intra_period(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	u32 pnum = 0;
+
+	ret = copy_from_user(&pnum, argp, sizeof(int));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f0(dvenc->q6_handle,
+			VENC_DALRPC_UPDATE_INTRA_PERIOD, pnum);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_set_intra_refresh(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	u32 mb_num = 0;
+
+	ret = copy_from_user(&mb_num, argp, sizeof(int));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f0(dvenc->q6_handle,
+			VENC_DALRPC_UPDATE_INTRA_REFRESH, mb_num);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_set_frame_rate(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_frame_rate pdata;
+	ret = copy_from_user(&pdata, argp, sizeof(struct venc_frame_rate));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f5(dvenc->q6_handle,
+				VENC_DALRPC_UPDATE_FRAME_RATE,
+				(void *)&(pdata),
+				sizeof(struct venc_frame_rate));
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_set_target_bitrate(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	u32 pdata = 0;
+
+	ret = copy_from_user(&pdata, argp, sizeof(int));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f0(dvenc->q6_handle,
+			VENC_DALRPC_UPDATE_BITRATE, pdata);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_request_iframe(struct venc_dev *dvenc)
+{
+	int ret = 0;
+
+	if (dvenc->state != VENC_STATE_START)
+		return -EINVAL;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_REQUEST_IFRAME, 1);
+	if (ret)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	return ret;
+}
+
+static int venc_stop_read_msg(struct venc_dev *dvenc)
+{
+	venc_post(dvenc, VENC_MSG_STOP_READING_MSG, 0, NULL);
+	return 0;
+}
+
+static int venc_translate_error(enum venc_status_code q6_status)
+{
+	switch (q6_status) {
+	case VENC_STATUS_SUCCESS:
+		return VENC_S_SUCCESS;
+	case VENC_STATUS_ERROR:
+		return VENC_S_EFAIL;
+	case VENC_STATUS_INVALID_STATE:
+		return VENC_S_EINVALSTATE;
+	case VENC_STATUS_FLUSHING:
+		return VENC_S_EFLUSHED;
+	case VENC_STATUS_INVALID_PARAM:
+		return VENC_S_EBADPARAM;
+	case VENC_STATUS_CMD_QUEUE_FULL:
+		return VENC_S_ECMDQFULL;
+	case VENC_STATUS_CRITICAL:
+		return VENC_S_EFATAL;
+	case VENC_STATUS_INSUFFICIENT_RESOURCES:
+		return VENC_S_ENOHWRES;
+	case VENC_STATUS_TIMEOUT:
+		return VENC_S_ETIMEOUT;
+	default:
+		/* xxx probably shouldn't assume success */
+		return 0;
+	}
+}
+
+static void venc_q6_callback(void *_data, int len, void *cookie)
+{
+	int status = 0;
+	struct venc_dev *dvenc = (struct venc_dev *)cookie;
+	struct venc_msg_type *q6_msg = NULL;
+	struct venc_input_payload *pload1;
+	struct venc_output_payload *pload2;
+	union venc_msg_data data;
+	uint32_t *tmp = (uint32_t *) _data;
+
+	if (dvenc == NULL) {
+		pr_err("%s: empty driver parameter\n", __func__);
+		return;
+	}
+	if (tmp[2] == sizeof(struct venc_msg_type)) {
+		q6_msg = (struct venc_msg_type *)&tmp[3];
+	} else {
+		pr_err("%s: callback with empty message (%d, %d)\n",
+			__func__, tmp[2], sizeof(struct venc_msg_type));
+		return;
+	}
+
+	status = venc_translate_error(q6_msg->status);
+	if (status != VENC_STATUS_SUCCESS)
+		pr_err("%s: Q6 failed (%d)", __func__, (int)status);
+
+	switch ((enum venc_event_type_enum)q6_msg->event) {
+	case VENC_EVENT_START_STATUS:
+		dvenc->state = VENC_STATE_START;
+		venc_post(dvenc, VENC_MSG_START, status, NULL);
+		break;
+	case VENC_EVENT_STOP_STATUS:
+		dvenc->state = VENC_STATE_STOP;
+		venc_post(dvenc, VENC_MSG_STOP, status, NULL);
+		break;
+	case VENC_EVENT_SUSPEND_STATUS:
+		dvenc->state = VENC_STATE_PAUSE;
+		venc_post(dvenc, VENC_MSG_PAUSE, status, NULL);
+		break;
+	case VENC_EVENT_RESUME_STATUS:
+		dvenc->state = VENC_STATE_START;
+		venc_post(dvenc, VENC_MSG_RESUME, status, NULL);
+		break;
+	case VENC_EVENT_FLUSH_STATUS:
+		data.flush_ret.flush_mode = VENC_FLUSH_INPUT;
+		venc_post(dvenc, VENC_MSG_FLUSH, status, &data);
+		data.flush_ret.flush_mode = VENC_FLUSH_OUTPUT;
+		venc_post(dvenc, VENC_MSG_FLUSH, status, &data);		
+		break;
+	case VENC_EVENT_RELEASE_INPUT:
+		pload1 = &((q6_msg->payload).input_payload);
+		TRACE("Release_input: data: 0x%x \n", pload1->data);
+		if (pload1 != NULL) {
+			/* xxx should we zero? */
+			data.buf.client_data = pload1->data;
+			venc_post(dvenc, VENC_MSG_INPUT_BUFFER_DONE, status, &data);
+		} else {
+			pr_err("%s no payload on buffer done?\n", __func__);
+		}
+		break;
+	case VENC_EVENT_DELIVER_OUTPUT:
+		pload2 = &((q6_msg->payload).output_payload);
+		data.buf.flags = 0;
+		if (pload2->flags & VENC_FLAG_SYNC_FRAME)
+			data.buf.flags |= VENC_FLAG_SYNC_FRAME;
+		if (pload2->flags & VENC_FLAG_CODEC_CONFIG)
+			data.buf.flags |= VENC_FLAG_CODEC_CONFIG;
+		if (pload2->flags & VENC_FLAG_END_OF_FRAME)
+			data.buf.flags |= VENC_FLAG_END_OF_FRAME;
+		if (pload2->flags & VENC_FLAG_EOS)
+			data.buf.flags |= VENC_FLAG_EOS;
+		data.buf.len = pload2->size;
+		data.buf.offset = 0;
+		data.buf.time_stamp = pload2->time_stamp;
+		data.buf.client_data = pload2->data;
+		venc_post(dvenc, VENC_MSG_OUTPUT_BUFFER_DONE, status, &data);
+		break;
+	default:
+		pr_err("%s: invalid response from Q6 (%d)\n", __func__,
+			(int)q6_msg->event);
+		break;
+	}
+}
+
+static int venc_read_next_msg(struct venc_dev *dvenc, void __user *argp)
+{
+	int res;
+	struct venc_qmsg *msg;
+
+	res = wait_event_interruptible(dvenc->venc_msg_evt,
+				       (msg = venc_recv_msg(dvenc)) != NULL);
+	if (res < 0)
+		return res;
+	res = copy_to_user(argp, &msg->msg, sizeof(struct venc_msg));
+	venc_free_msg(dvenc, msg);
+	if (res)
+		return -EFAULT;
+	return 0;
+}
+
+static long q6venc_ioctl(struct file *file, u32 cmd,
+			   unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	struct venc_dev *dvenc = file->private_data;
+
+	switch (cmd) {
+	case VENC_IOCTL_SET_INPUT_BUFFER:
+		return venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_INPUT);
+	case VENC_IOCTL_SET_OUTPUT_BUFFER:
+		return venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_OUTPUT);
+	case VENC_IOCTL_GET_SEQUENCE_HDR:
+		return venc_get_sequence_hdr(dvenc, argp);
+	case VENC_IOCTL_SET_QP_RANGE:
+		return venc_set_qp_range(dvenc, argp);
+	case VENC_IOCTL_SET_INTRA_PERIOD:
+		return venc_set_intra_period(dvenc, argp);
+	case VENC_IOCTL_SET_INTRA_REFRESH:
+		return venc_set_intra_refresh(dvenc, argp);
+	case VENC_IOCTL_SET_FRAME_RATE:
+		return venc_set_frame_rate(dvenc, argp);
+	case VENC_IOCTL_SET_TARGET_BITRATE:
+		return venc_set_target_bitrate(dvenc, argp);
+	case VENC_IOCTL_CMD_REQUEST_IFRAME:
+		if (dvenc->state == VENC_STATE_START)
+			return venc_request_iframe(dvenc);
+		else
+			return 0;
+	case VENC_IOCTL_CMD_START:
+		return venc_start(dvenc, argp);
+	case VENC_IOCTL_CMD_STOP:
+		return venc_stop(dvenc);
+	case VENC_IOCTL_CMD_PAUSE:
+		return venc_pause(dvenc);
+	case VENC_IOCTL_CMD_RESUME:
+		return venc_resume(dvenc);
+	case VENC_IOCTL_CMD_ENCODE_FRAME:
+		return venc_encode_frame(dvenc, argp);
+	case VENC_IOCTL_CMD_FILL_OUTPUT_BUFFER:
+		return venc_fill_output(dvenc, argp);
+	case VENC_IOCTL_CMD_FLUSH:
+		return venc_flush(dvenc, argp);
+	case VENC_IOCTL_CMD_READ_NEXT_MSG:
+		return venc_read_next_msg(dvenc, argp);
+	case VENC_IOCTL_CMD_STOP_READ_MSG:
+		return venc_stop_read_msg(dvenc);
+	default:
+		pr_err("%s: invalid ioctl code (%d)\n", __func__, cmd);
+		return -EINVAL;
+	}
+}
+
+static int q6venc_open(struct inode *inode, struct file *file)
+{
+	int i;
+	int ret = 0;
+	struct venc_dev *dvenc;
+	struct venc_qmsg *msg;
+#if VERSION_CHECK
+	struct dal_info version_info;
+#endif
+
+	dvenc = kzalloc(sizeof(struct venc_dev), GFP_KERNEL);
+	if (!dvenc)
+		return -ENOMEM;
+
+	file->private_data = dvenc;
+	INIT_LIST_HEAD(&dvenc->msg_pool);
+	INIT_LIST_HEAD(&dvenc->msg_queue);
+	INIT_LIST_HEAD(&dvenc->venc_pmem_list_head);
+	init_waitqueue_head(&dvenc->venc_msg_evt);
+	spin_lock_init(&dvenc->msg_lock);
+	spin_lock_init(&dvenc->venc_pmem_list_lock);
+	venc_ref++;
+
+	for (i = 0; i < VENC_MSG_MAX; i++) {
+		msg = kzalloc(sizeof(struct venc_qmsg), GFP_KERNEL);
+		if (msg == NULL) {
+			ret = -ENOMEM;
+			goto fail_list_alloc;
+		}
+		venc_free_msg(dvenc, msg);
+	}
+
+	dvenc->q6_handle = dal_attach(DALDEVICEID_VENC_DEVICE,
+				      DALDEVICEID_VENC_PORTNAME,
+				      venc_q6_callback, (void *)dvenc);
+
+	if (!(dvenc->q6_handle)) {
+		pr_err("%s: daldevice_attach failed (%d)\n", __func__, ret);
+		goto fail_list_alloc;
+	}
+
+#if VERSION_CHECK
+	ret = dal_call_f9(dvenc->q6_handle, DAL_OP_INFO, &version_info,
+		sizeof(struct dal_info));
+	if (ret) {
+		pr_err("%s: failed to get version\n", __func__);
+		ret = -EINVAL;
+		goto fail_open;
+	}
+	if (venc_check_version(VENC_INTERFACE_VERSION, version_info.version)) {
+		pr_err("%s: driver version mismatch\n", __func__);
+		ret = -EINVAL;
+		goto fail_open;
+	}
+#endif
+	ret = dal_call_f0(dvenc->q6_handle, DAL_OP_OPEN, 1);
+	if (ret) {
+		pr_err("%s: dal_call_open failed (%d)\n", __func__, ret);
+		goto fail_open;
+	}
+	dvenc->state = VENC_STATE_STOP;
+	prevent_sleep();
+	return ret;
+
+fail_open:
+	dal_detach(dvenc->q6_handle);
+
+fail_list_alloc:
+	while ((msg = venc_alloc_msg(dvenc)))
+		kfree(msg);
+
+	kfree(dvenc);
+	venc_ref--;
+	return ret;
+}
+
+static int q6venc_release(struct inode *inode, struct file *file)
+{
+	int ret = 0;
+	struct venc_pmem_list *plist, *m;
+	struct venc_dev *dvenc;
+	struct venc_qmsg *msg;
+
+	venc_ref--;
+
+	dvenc = file->private_data;
+	wake_up_all(&dvenc->venc_msg_evt);
+	if (!dvenc->stop_called)
+		dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1);
+	dal_call_f0(dvenc->q6_handle, DAL_OP_CLOSE, 1);
+	dal_detach(dvenc->q6_handle);
+
+
+	/* free all messages in the pool */
+	while ((msg = venc_alloc_msg(dvenc)))
+		kfree(msg);
+
+	/* free all messages sitting in the queue */
+	while ((msg = venc_recv_msg(dvenc)))
+		kfree(msg);
+
+	list_for_each_entry_safe(plist, m, &dvenc->venc_pmem_list_head, list) {
+		put_pmem_file(plist->buf.file);
+		list_del(&plist->list);
+		kfree(plist);
+	}
+	kfree(dvenc);
+	allow_sleep();
+	return ret;
+}
+
+const struct file_operations q6venc_fops = {
+	.owner = THIS_MODULE,
+	.open = q6venc_open,
+	.release = q6venc_release,
+	.unlocked_ioctl = q6venc_ioctl,
+};
+
+static int __init q6venc_init(void)
+{
+	int ret = 0;
+
+	venc_device_p = kzalloc(sizeof(struct venc_dev), GFP_KERNEL);
+	if (!venc_device_p) {
+		pr_err("%s: unable to allocate memory for venc_device_p\n",
+			__func__);
+		return -ENOMEM;
+	}
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "venc_idle");
+	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "venc_suspend");
+
+	ret = alloc_chrdev_region(&venc_dev_num, 0, 1, VENC_NAME);
+	if (ret < 0) {
+		pr_err("%s: alloc_chrdev_region failed (%d)\n", __func__,
+			ret);
+		return ret;
+	}
+	venc_class = class_create(THIS_MODULE, VENC_NAME);
+	if (IS_ERR(venc_class)) {
+		ret = PTR_ERR(venc_class);
+		pr_err("%s: failed to create venc_class (%d)\n",
+			__func__, ret);
+		goto err_venc_class_create;
+	}
+	venc_device_p->class_devp =
+	    device_create(venc_class, NULL, venc_dev_num, NULL,
+			  VENC_NAME);
+	if (IS_ERR(venc_device_p->class_devp)) {
+		ret = PTR_ERR(venc_device_p->class_devp);
+		pr_err("%s: failed to create class_device (%d)\n", __func__,
+			ret);
+		goto err_venc_class_device_create;
+	}
+	cdev_init(&cdev, &q6venc_fops);
+	cdev.owner = THIS_MODULE;
+	ret = cdev_add(&cdev, venc_dev_num, 1);
+	if (ret < 0) {
+		pr_err("%s: cdev_add failed (%d)\n", __func__, ret);
+		goto err_venc_cdev_add;
+	}
+	init_waitqueue_head(&venc_device_p->venc_msg_evt);
+	return ret;
+
+err_venc_cdev_add:
+	device_destroy(venc_class, venc_dev_num);
+err_venc_class_device_create:
+	class_destroy(venc_class);
+err_venc_class_create:
+	unregister_chrdev_region(venc_dev_num, 1);
+	return ret;
+}
+
+static void __exit q6venc_exit(void)
+{
+	cdev_del(&(cdev));
+	device_destroy(venc_class, venc_dev_num);
+	class_destroy(venc_class);
+	unregister_chrdev_region(venc_dev_num, 1);
+}
+
+MODULE_DESCRIPTION("Video encoder driver for QDSP6");
+MODULE_VERSION("2.0");
+module_init(q6venc_init);
+module_exit(q6venc_exit);
diff --git a/arch/arm/mach-msm/qdsp6/pcm_in.c b/arch/arm/mach-msm/qdsp6/pcm_in.c
new file mode 100644
index 0000000..d5a8f77
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/pcm_in.c
@@ -0,0 +1,219 @@
+/* arch/arm/mach-msm/qdsp6/pcm_in.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/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+
+#define BUFSZ (256)
+
+static DEFINE_MUTEX(pcm_in_lock);
+static uint32_t sample_rate = 8000;
+static uint32_t channel_count = 1;
+static uint32_t buffer_size = BUFSZ;
+static int pcm_in_opened = 0;
+
+void audio_client_dump(struct audio_client *ac);
+
+static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STATS: {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		rc = 0;
+
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void*) arg, sizeof(acdb_id))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		mutex_lock(&pcm_in_lock);
+		if (file->private_data) {
+			rc = -EBUSY;
+		} else {
+			file->private_data = q6audio_open_pcm(
+				buffer_size, sample_rate, channel_count,
+				AUDIO_FLAG_READ, acdb_id);
+			if (!file->private_data)
+				rc = -ENOMEM;
+		}
+		mutex_unlock(&pcm_in_lock);
+		break;
+	}
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (!config.channel_count || config.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.sample_rate < 8000 || config.sample_rate > 48000) {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.buffer_size < 128 || config.buffer_size > 8192) {
+			rc = -EINVAL;
+			break;
+		}
+		sample_rate = config.sample_rate;
+		channel_count = config.channel_count;
+		buffer_size = config.buffer_size;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = buffer_size;
+		config.buffer_count = 2;
+		config.sample_rate = sample_rate;
+		config.channel_count = channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int q6_in_open(struct inode *inode, struct file *file)
+{
+	int rc;
+
+	pr_info("pcm_in: open\n");
+	mutex_lock(&pcm_in_lock);
+	if (pcm_in_opened) {
+		pr_err("pcm_in: busy\n");
+		rc = -EBUSY;
+	} else {
+		pcm_in_opened = 1;
+		rc = 0;
+	}
+	mutex_unlock(&pcm_in_lock);
+	return rc;
+}
+
+static ssize_t q6_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+	int res;
+
+	mutex_lock(&pcm_in_lock);
+	ac = file->private_data;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) {
+				audio_client_dump(ac);
+				pr_err("pcm_read: timeout. dsp dead?\n");
+				q6audio_dsp_not_responding();
+			}
+
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+fail:
+	res = buf - start;
+	mutex_unlock(&pcm_in_lock);
+
+	return res;
+}
+
+static int q6_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	mutex_lock(&pcm_in_lock);
+	if (file->private_data)
+		rc = q6audio_close(file->private_data);
+	pcm_in_opened = 0;
+	mutex_unlock(&pcm_in_lock);
+	pr_info("pcm_in: release\n");
+	return rc;
+}
+
+static struct file_operations q6_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_in_open,
+	.read		= q6_in_read,
+	.release	= q6_in_release,
+	.unlocked_ioctl	= q6_in_ioctl,
+};
+
+struct miscdevice q6_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &q6_in_fops,
+};
+
+static int __init q6_in_init(void) {
+	return misc_register(&q6_in_misc);
+}
+
+device_initcall(q6_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/pcm_out.c b/arch/arm/mach-msm/qdsp6/pcm_out.c
new file mode 100644
index 0000000..6d041d8
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/pcm_out.c
@@ -0,0 +1,235 @@
+/* arch/arm/mach-msm/qdsp6/pcm_out.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/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+
+void audio_client_dump(struct audio_client *ac);
+
+#define BUFSZ (3072)
+
+struct pcm {
+	struct mutex lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	size_t buffer_size;
+};
+
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME: {
+		int vol;
+		if (!pcm->ac) {
+			pr_err("%s: cannot set volume before AUDIO_START!\n",
+				__func__);
+			rc = -EINVAL;
+			break;
+		}
+		if (copy_from_user(&vol, (void*) arg, sizeof(vol))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6audio_set_stream_volume(pcm->ac, vol);
+		break;
+	}
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void*) arg, sizeof(acdb_id))) {
+			pr_info("pcm_out: copy acdb_id from user failed\n");
+			rc = -EFAULT;
+			break;
+		}
+		if (pcm->ac) {
+			rc = -EBUSY;
+		} else {
+			pcm->ac = q6audio_open_pcm(pcm->buffer_size, pcm->sample_rate,
+						   pcm->channel_count,
+						   AUDIO_FLAG_WRITE, acdb_id);
+			if (!pcm->ac)
+				rc = -ENOMEM;
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (pcm->ac) {
+			rc = -EBUSY;
+			break;
+		}
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count < 1 || config.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.sample_rate < 8000 || config.sample_rate > 48000) {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.buffer_size < 128 || config.buffer_size > 8192) {
+			rc = -EINVAL;
+			break;
+		}
+		pcm->sample_rate = config.sample_rate;
+		pcm->channel_count = config.channel_count;
+		pcm->buffer_size = config.buffer_size;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = pcm->buffer_size;
+		config.buffer_count = 2;
+		config.sample_rate = pcm->sample_rate;
+		config.channel_count = pcm->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+		mutex_unlock(&pcm->lock);
+	return rc;
+}
+
+static int pcm_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+
+	pr_info("pcm_out: open\n");
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+
+	if (!pcm)
+		return -ENOMEM;
+
+	mutex_init(&pcm->lock);
+	pcm->channel_count = 2;
+	pcm->sample_rate = 44100;
+	pcm->buffer_size = BUFSZ;
+
+	file->private_data = pcm;
+	return 0;
+}
+
+static ssize_t pcm_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	if (!pcm->ac)
+		pcm_ioctl(file, AUDIO_START, 0);
+
+	ac = pcm->ac;
+	if (!ac)
+		return -ENODEV;
+
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) {
+				audio_client_dump(ac);
+				pr_err("pcm_write: timeout. dsp dead?\n");
+				q6audio_dsp_not_responding();
+			}
+
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer)) 
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = xfer;
+		q6audio_write(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int pcm_release(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm = file->private_data;
+	if (pcm->ac)
+		q6audio_close(pcm->ac);
+	kfree(pcm);
+	pr_info("pcm_out: release\n");
+	return 0;
+}
+
+static struct file_operations pcm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pcm_open,
+	.write		= pcm_write,
+	.release	= pcm_release,
+	.unlocked_ioctl	= pcm_ioctl,
+};
+
+struct miscdevice pcm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &pcm_fops,
+};
+
+static int __init pcm_init(void) {
+	return misc_register(&pcm_misc);
+}
+
+device_initcall(pcm_init);
diff --git a/arch/arm/mach-msm/qdsp6/q6audio.c b/arch/arm/mach-msm/qdsp6/q6audio.c
new file mode 100644
index 0000000..1b053e7
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/q6audio.c
@@ -0,0 +1,1574 @@
+/* arch/arm/mach-msm/qdsp6/q6audio.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/mutex.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/firmware.h>
+#include <linux/miscdevice.h>
+
+#include "../dal.h"
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include "dal_acdb.h"
+#include "dal_adie.h"
+#include <mach/msm_qdsp6_audio.h>
+
+#include <linux/gpio.h>
+
+#include "q6audio_devices.h"
+
+#if 0
+#define TRACE(x...) pr_info("Q6: "x)
+#else
+#define TRACE(x...) do{}while(0)
+#endif
+
+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,
+	},
+};
+
+static struct wake_lock wakelock;
+static struct wake_lock idlelock;
+static int idlecount;
+static DEFINE_MUTEX(idlecount_lock);
+
+void audio_prevent_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (++idlecount == 1) {
+		wake_lock(&wakelock);
+		wake_lock(&idlelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+void audio_allow_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (--idlecount == 0) {
+		wake_unlock(&idlelock);
+		wake_unlock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static struct clk *icodec_rx_clk;
+static struct clk *icodec_tx_clk;
+static struct clk *ecodec_clk;
+static struct clk *sdac_clk;
+
+static struct q6audio_analog_ops default_analog_ops;
+static struct q6audio_analog_ops *analog_ops = &default_analog_ops;
+static uint32_t tx_clk_freq = 8000;
+static int tx_mute_status = 0;
+static int rx_vol_level = 100;
+static char acdb_file[64] = "default.acdb";
+static uint32_t tx_acdb = 0;
+static uint32_t rx_acdb = 0;
+
+void q6audio_register_analog_ops(struct q6audio_analog_ops *ops)
+{
+	analog_ops = ops;
+}
+
+void q6audio_set_acdb_file(char* filename)
+{
+	if (filename)
+		strncpy(acdb_file, filename, sizeof(acdb_file)-1);
+}
+
+static struct q6_device_info *q6_lookup_device(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_audio_devices;
+	for (;;) {
+		if (di->id == device_id)
+			return di;
+		if (di->id == 0) {
+			pr_err("q6_lookup_device: bogus id 0x%08x\n",
+			       device_id);
+			return di;
+		}
+		di++;
+	}
+}
+
+static uint32_t q6_device_to_codec(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->codec;
+}
+
+static uint32_t q6_device_to_dir(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->dir;
+}
+
+static uint32_t q6_device_to_cad_id(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->cad_id;
+}
+
+static uint32_t q6_device_to_path(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->path;
+}
+
+static uint32_t q6_device_to_rate(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->rate;
+}
+
+int q6_device_volume(uint32_t device_id, int level)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	if (analog_ops->get_rx_vol)
+		return analog_ops->get_rx_vol(di->hw, level);
+	else {
+		struct q6_hw_info *hw;
+		hw = &q6_audio_hw[di->hw];
+		return hw->min_gain + ((hw->max_gain - hw->min_gain) * level) / 100;
+	}
+}
+
+static inline int adie_open(struct dal_client *client) 
+{
+	return dal_call_f0(client, DAL_OP_OPEN, 0);
+}
+
+static inline int adie_close(struct dal_client *client) 
+{
+	return dal_call_f0(client, DAL_OP_CLOSE, 0);
+}
+
+static inline int adie_set_path(struct dal_client *client,
+				uint32_t id, uint32_t path_type)
+{
+	return dal_call_f1(client, ADIE_OP_SET_PATH, id, path_type);
+}
+
+static inline int adie_set_path_freq_plan(struct dal_client *client,
+                                         uint32_t path_type, uint32_t plan)
+{
+	return dal_call_f1(client, ADIE_OP_SET_PATH_FREQUENCY_PLAN,
+			   path_type, plan);
+}
+
+static inline int adie_proceed_to_stage(struct dal_client *client,
+					uint32_t path_type, uint32_t stage)
+{
+	return dal_call_f1(client, ADIE_OP_PROCEED_TO_STAGE,
+			   path_type, stage);
+}
+
+static inline int adie_mute_path(struct dal_client *client,
+				 uint32_t path_type, uint32_t mute_state)
+{
+	return dal_call_f1(client, ADIE_OP_MUTE_PATH, path_type, mute_state);
+}
+
+static int adie_refcount;
+
+static struct dal_client *adie;
+static struct dal_client *adsp;
+static struct dal_client *acdb;
+
+static int adie_enable(void)
+{
+	adie_refcount++;
+	if (adie_refcount == 1)
+		adie_open(adie);
+	return 0;
+}
+
+static int adie_disable(void)
+{
+	adie_refcount--;
+	if (adie_refcount == 0)
+		adie_close(adie);
+	return 0;
+}
+
+/* 4k DMA scratch page used for exchanging acdb device config tables
+ * and stream format descriptions with the DSP.
+ */
+static void *audio_data;
+static dma_addr_t audio_phys;
+
+#define SESSION_MIN 0
+#define SESSION_MAX 64
+
+static DEFINE_MUTEX(session_lock);
+static DEFINE_MUTEX(audio_lock);
+
+static struct audio_client *session[SESSION_MAX];
+
+static int session_alloc(struct audio_client *ac)
+{
+	int n;
+
+	mutex_lock(&session_lock);
+	for (n = SESSION_MIN; n < SESSION_MAX; n++) {
+		if (!session[n]) {
+			session[n] = ac;
+			mutex_unlock(&session_lock);
+			return n;
+		}
+	}
+	mutex_unlock(&session_lock);
+	return -ENOMEM;
+}
+
+static void session_free(int n, struct audio_client *ac)
+{
+	mutex_lock(&session_lock);
+	if (session[n] == ac)
+		session[n] = 0;
+	mutex_unlock(&session_lock);
+}
+
+static void audio_client_free(struct audio_client *ac)
+{
+	session_free(ac->session, ac);
+
+	if (ac->buf[0].data)
+		dma_free_coherent(NULL, ac->buf[0].size,
+				  ac->buf[0].data, ac->buf[0].phys);
+	if (ac->buf[1].data)
+		dma_free_coherent(NULL, ac->buf[1].size,
+				  ac->buf[1].data, ac->buf[1].phys);
+	kfree(ac);
+}
+
+static struct audio_client *audio_client_alloc(unsigned bufsz)
+{
+	struct audio_client *ac;
+	int n;
+
+	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+	if (!ac)
+		return 0;
+
+	n = session_alloc(ac);
+	if (n < 0)
+		goto fail_session;
+	ac->session = n;
+
+	if (bufsz > 0) {
+		ac->buf[0].data = dma_alloc_coherent(NULL, bufsz,
+						&ac->buf[0].phys, GFP_KERNEL);
+		if (!ac->buf[0].data)
+			goto fail;
+		ac->buf[1].data = dma_alloc_coherent(NULL, bufsz,
+						&ac->buf[1].phys, GFP_KERNEL);
+		if (!ac->buf[1].data)
+			goto fail;
+
+		ac->buf[0].size = bufsz;
+		ac->buf[1].size = bufsz;
+	}
+
+	init_waitqueue_head(&ac->wait);
+	ac->client = adsp;
+
+	return ac;
+
+fail:
+	session_free(n, ac);
+fail_session:
+	audio_client_free(ac);
+	return 0;
+}
+
+void audio_client_dump(struct audio_client *ac)
+{
+	dal_trace_dump(ac->client);
+}
+
+static int audio_ioctl(struct audio_client *ac, void *ptr, uint32_t len)
+{
+	struct adsp_command_hdr *hdr = ptr;
+	uint32_t tmp;
+	int r;
+
+	hdr->size = len - sizeof(u32);
+	hdr->dst = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_DSP);
+	hdr->src = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_MODEM);
+	hdr->context = ac->session;
+	ac->cb_status = -EBUSY;
+	r = dal_call(ac->client, AUDIO_OP_CONTROL, 5, ptr, len, &tmp, sizeof(tmp));
+	if (r != 4)
+		return -EIO;
+	if (!wait_event_timeout(ac->wait, (ac->cb_status != -EBUSY), 5*HZ)) {
+		dal_trace_dump(ac->client);
+		pr_err("audio_ioctl: timeout. dsp dead?\n");
+		q6audio_dsp_not_responding();
+	}
+	return ac->cb_status;
+}
+
+static int audio_command(struct audio_client *ac, uint32_t cmd)
+{
+	struct adsp_command_hdr rpc;
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.opcode = cmd;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_open_control(struct audio_client *ac)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_out_open(struct audio_client *ac, uint32_t bufsz,
+			  uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_PCM;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 1;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+	rpc.buf_max_size = bufsz;
+
+	TRACE("open out %p\n", ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_in_open(struct audio_client *ac, uint32_t bufsz,
+			 uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_PCM;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 1;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+	rpc.buf_max_size = bufsz;
+
+	TRACE("%p: open in\n", ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_mp3_open(struct audio_client *ac, uint32_t bufsz,
+			  uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_MP3;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 0;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+	rpc.buf_max_size = bufsz;
+
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_close(struct audio_client *ac)
+{
+	TRACE("%p: close\n", ac);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_STREAM_STOP);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_CLOSE);
+	return 0;
+}
+
+static int audio_set_table(struct audio_client *ac,
+			   uint32_t device_id, int size)
+{
+	struct adsp_set_dev_cfg_table_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE;
+	if (q6_device_to_dir(device_id) == Q6_TX)
+		rpc.hdr.data = tx_clk_freq;
+	rpc.device_id = device_id;
+	rpc.phys_addr = audio_phys;
+	rpc.phys_size = size;
+	rpc.phys_used = size;
+
+	TRACE("control: set table %x\n", device_id);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+int q6audio_read(struct audio_client *ac, struct audio_buffer *ab)
+{
+	struct adsp_buffer_command rpc;
+	uint32_t res;
+	int r;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.size = sizeof(rpc) - sizeof(u32);
+	rpc.hdr.dst = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_DSP);
+	rpc.hdr.src = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_MODEM);
+	rpc.hdr.context = ac->session;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DATA_TX;
+	rpc.buffer.addr = ab->phys;
+	rpc.buffer.max_size = ab->size;
+	rpc.buffer.actual_size = ab->used;
+
+	TRACE("%p: read\n", ac);
+	r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+	return 0;
+}
+
+int q6audio_write(struct audio_client *ac, struct audio_buffer *ab)
+{
+	struct adsp_buffer_command rpc;
+	uint32_t res;
+	int r;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.size = sizeof(rpc) - sizeof(u32);
+	rpc.hdr.dst = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_DSP);
+	rpc.hdr.src = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_MODEM);
+	rpc.hdr.context = ac->session;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DATA_RX;
+	rpc.buffer.addr = ab->phys;
+	rpc.buffer.max_size = ab->size;
+	rpc.buffer.actual_size = ab->used;
+
+	TRACE("%p: write\n", ac);
+	r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+	return 0;
+}
+
+static int audio_rx_volume(struct audio_client *ac, uint32_t dev_id, int32_t volume)
+{
+	struct adsp_set_dev_volume_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_RX;
+	rpc.volume = volume;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_rx_mute(struct audio_client *ac, uint32_t dev_id, int mute)
+{
+	struct adsp_set_dev_mute_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_RX;
+	rpc.mute = !!mute;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_tx_volume(struct audio_client *ac, uint32_t dev_id, int32_t volume)
+{
+	struct adsp_set_dev_volume_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_TX;
+	rpc.volume = volume;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_tx_mute(struct audio_client *ac, uint32_t dev_id, int mute)
+{
+	struct adsp_set_dev_mute_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_TX;
+	rpc.mute = !!mute;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_stream_volume(struct audio_client *ac, int volume)
+{
+	struct adsp_set_volume_command rpc;
+	int rc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL;
+	rpc.volume = volume;
+	rc = audio_ioctl(ac, &rpc, sizeof(rpc));
+	return rc;
+}
+
+static int audio_stream_mute(struct audio_client *ac, int mute)
+{
+	struct adsp_set_mute_command rpc;
+	int rc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE;
+	rpc.mute = mute;
+	rc = audio_ioctl(ac, &rpc, sizeof(rpc));
+	return rc;
+}
+
+static void callback(void *data, int len, void *cookie)
+{
+	struct adsp_event_hdr *e = data;
+	struct audio_client *ac;
+
+
+	if (e->context >= SESSION_MAX) {
+		pr_err("audio callback: bogus session %d\n",
+		       e->context);
+		return;
+	}
+	ac = session[e->context];
+	if (!ac) {
+		pr_err("audio callback: unknown session %d\n",
+		       e->context);
+		return;
+	}
+
+	if (e->event_id == ADSP_AUDIO_IOCTL_CMD_STREAM_EOS) {
+		TRACE("%p: CB stream eos\n", ac);
+		if (e->status)
+			pr_err("playback status %d\n", e->status);
+		if (ac->cb_status == -EBUSY) {
+			ac->cb_status = e->status;
+			wake_up(&ac->wait);
+		}
+		return;
+	}
+
+	if (e->event_id == ADSP_AUDIO_EVT_STATUS_BUF_DONE) {
+		TRACE("%p: CB done (%d)\n", ac, e->status);
+		if (e->status)
+			pr_err("buffer status %d\n", e->status);
+		ac->buf[ac->dsp_buf].used = 0;
+		ac->dsp_buf ^= 1;
+		wake_up(&ac->wait);
+		return;
+	}
+
+	TRACE("%p: CB %08x status %d\n", ac, e->event_id, e->status);
+	if (e->status)
+		pr_warning("audio_cb: s=%d e=%08x status=%d\n",
+			   e->context, e->event_id, e->status);
+	if (ac->cb_status == -EBUSY) {
+		ac->cb_status = e->status;
+		wake_up(&ac->wait);
+	}
+}
+
+static void audio_init(struct dal_client *client)
+{
+	u32 tmp[3];
+
+	tmp[0] = 2 * sizeof(u32);
+	tmp[1] = 1;
+	tmp[2] = 0;
+	dal_call(client, AUDIO_OP_INIT, 5, tmp, sizeof(tmp),
+		 tmp, sizeof(u32));
+}
+
+static struct audio_client *ac_control;
+
+static int q6audio_init(void)
+{
+	struct audio_client *ac = 0;
+	int res;
+
+	mutex_lock(&audio_lock);
+	if (ac_control) {
+		res = 0;
+		goto done;
+	}
+
+	pr_info("audio: init: codecs\n");
+	icodec_rx_clk = clk_get(0, "icodec_rx_clk");
+	icodec_tx_clk = clk_get(0, "icodec_tx_clk");
+	ecodec_clk = clk_get(0, "ecodec_clk");
+	sdac_clk = clk_get(0, "sdac_clk");
+	audio_data = dma_alloc_coherent(NULL, 4096, &audio_phys, GFP_KERNEL);
+
+	adsp = dal_attach(AUDIO_DAL_DEVICE, AUDIO_DAL_PORT,
+			  callback, 0);
+	if (!adsp) {
+		pr_err("audio_init: cannot attach to adsp\n");
+		res = -ENODEV;
+		goto done;
+	}
+	pr_info("audio: init: INIT\n");
+	audio_init(adsp);
+	dal_trace(adsp);
+
+	ac = audio_client_alloc(0);
+	if (!ac) {
+		pr_err("audio_init: cannot allocate client\n");
+		res = -ENOMEM;
+		goto done;
+	}
+
+	pr_info("audio: init: OPEN control\n");
+	if (audio_open_control(ac)) {
+		pr_err("audio_init: cannot open control channel\n");
+		res = -ENODEV;
+		goto done;
+	}
+
+	pr_info("audio: init: attach ACDB\n");
+	acdb = dal_attach(ACDB_DAL_DEVICE, ACDB_DAL_PORT, 0, 0);
+	if (!acdb) {
+		pr_err("audio_init: cannot attach to acdb channel\n");
+		res = -ENODEV;
+		goto done;
+	}
+
+	pr_info("audio: init: attach ADIE\n");
+	adie = dal_attach(ADIE_DAL_DEVICE, ADIE_DAL_PORT, 0, 0);
+	if (!adie) {
+		pr_err("audio_init: cannot attach to adie\n");
+		res = -ENODEV;
+		goto done;
+	}
+	if (analog_ops->init)
+		analog_ops->init();
+
+	res = 0;
+	ac_control = ac;
+
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "audio_pcm_idle");
+	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "audio_pcm_suspend");
+done:
+	if ((res < 0) && ac)
+		audio_client_free(ac);
+	mutex_unlock(&audio_lock);
+
+	return res;
+}
+
+struct audio_config_data {
+	uint32_t device_id;
+	uint32_t sample_rate;
+	uint32_t offset;
+	uint32_t length;
+};
+
+struct audio_config_database {
+	uint8_t magic[8];
+	uint32_t entry_count;
+	uint32_t unused;
+	struct audio_config_data entry[0];
+};
+
+void *acdb_data;
+const struct firmware *acdb_fw;
+extern struct miscdevice q6_control_device;
+
+static int acdb_init(char *filename)
+{
+	const struct audio_config_database *db;
+	const struct firmware *fw;
+	int n;
+
+	pr_info("acdb: load '%s'\n", filename);
+	if (request_firmware(&fw, filename, q6_control_device.this_device) < 0) {
+		pr_err("acdb: load 'default.acdb' failed...\n");
+		return -ENODEV;
+	}
+	db = (void*) fw->data;
+
+	if (fw->size < sizeof(struct audio_config_database)) {
+		pr_err("acdb: undersized database\n");
+		goto fail;
+	}
+	if (strcmp(db->magic, "ACDB1.0")) {
+		pr_err("acdb: invalid magic\n");
+		goto fail;
+	}
+	if (db->entry_count > 1024) {
+		pr_err("acdb: too many entries\n");
+		goto fail;
+	}
+	if (fw->size < (sizeof(struct audio_config_database) +
+			db->entry_count * sizeof(struct audio_config_data))) {
+		pr_err("acdb: undersized TOC\n");
+		goto fail;
+	}
+	for (n = 0; n < db->entry_count; n++) {
+		if (db->entry[n].length > 4096) {
+			pr_err("acdb: entry %d too large (%d)\n",
+			       n, db->entry[n].length);
+			goto fail;
+		}
+		if ((db->entry[n].offset + db->entry[n].length) > fw->size) {
+			pr_err("acdb: entry %d outside of data\n", n);
+			goto fail;
+		}
+	}
+	if (acdb_data)
+		release_firmware(acdb_fw);
+	acdb_data = (void*) fw->data;
+	acdb_fw = fw;
+	return 0;
+fail:
+	release_firmware(fw);
+	return -ENODEV;
+}
+
+static int acdb_get_config_table(uint32_t device_id, uint32_t sample_rate)
+{
+	struct audio_config_database *db;
+	int n, res;
+
+	if (q6audio_init())
+		return 0;
+
+	if (!acdb_data) {
+		res = acdb_init(acdb_file);
+		if (res)
+			return res;
+	}
+
+	db = acdb_data;
+	for (n = 0; n < db->entry_count; n++) {
+		if (db->entry[n].device_id != device_id)
+			continue;
+		if (db->entry[n].sample_rate != sample_rate)
+			continue;
+		break;
+	}
+
+	if (n == db->entry_count) {
+		pr_err("acdb: no entry for device %d, rate %d.\n",
+		       device_id, sample_rate);
+		return 0;
+	}
+
+	pr_info("acdb: %d bytes for device %d, rate %d.\n",
+		db->entry[n].length, device_id, sample_rate);
+
+	memcpy(audio_data, acdb_data + db->entry[n].offset, db->entry[n].length);
+	return db->entry[n].length;
+}
+
+static uint32_t audio_rx_path_id = ADIE_PATH_HANDSET_RX;
+static uint32_t audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR;
+static uint32_t audio_rx_device_group = -1;
+static uint32_t audio_tx_path_id = ADIE_PATH_HANDSET_TX;
+static uint32_t audio_tx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_MIC;
+static uint32_t audio_tx_device_group = -1;
+
+static int qdsp6_devchg_notify(struct audio_client *ac,
+			       uint32_t dev_type, uint32_t dev_id)
+{
+	struct adsp_device_switch_command rpc;
+
+	if (dev_type != ADSP_AUDIO_RX_DEVICE &&
+	    dev_type != ADSP_AUDIO_TX_DEVICE)
+		return -EINVAL;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE;
+	if (dev_type == ADSP_AUDIO_RX_DEVICE) {
+		rpc.old_device = audio_rx_device_id;
+		rpc.new_device = dev_id;
+	} else {
+		rpc.old_device = audio_tx_device_id;
+		rpc.new_device = dev_id;
+	}
+	rpc.device_class = 0;
+	rpc.device_type = dev_type;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int qdsp6_standby(struct audio_client *ac)
+{
+	return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY);
+}
+
+static int qdsp6_start(struct audio_client *ac)
+{
+	return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT);
+}
+
+static void audio_rx_analog_enable(int en)
+{
+	switch (audio_rx_device_id) {
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO:
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO:
+	case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR:
+		if (analog_ops->headset_enable)
+			analog_ops->headset_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET:
+		if (analog_ops->headset_enable)
+			analog_ops->headset_enable(en);
+		if (analog_ops->speaker_enable)
+			analog_ops->speaker_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO:
+		if (analog_ops->speaker_enable)
+			analog_ops->speaker_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR:
+		if (analog_ops->bt_sco_enable)
+			analog_ops->bt_sco_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR:
+		if (analog_ops->receiver_enable)
+			analog_ops->receiver_enable(en);
+		break;
+	}
+}
+
+static void audio_tx_analog_enable(int en)
+{
+	switch (audio_tx_device_id) {
+	case ADSP_AUDIO_DEVICE_ID_HANDSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC:
+		if (analog_ops->int_mic_enable)
+			analog_ops->int_mic_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC:
+		if (analog_ops->ext_mic_enable)
+			analog_ops->ext_mic_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC:
+		if (analog_ops->bt_sco_enable)
+			analog_ops->bt_sco_enable(en);
+		break;
+	}
+}
+
+static int audio_update_acdb(uint32_t adev, uint32_t acdb_id)
+{
+	uint32_t sample_rate;
+	int sz = -1;
+
+	sample_rate = q6_device_to_rate(adev);
+
+	if (q6_device_to_dir(adev) == Q6_RX)
+		rx_acdb = acdb_id;
+	else
+		tx_acdb = acdb_id;
+
+	if (acdb_id != 0)
+		sz = acdb_get_config_table(acdb_id, sample_rate);
+
+	if (sz <= 0) {
+		acdb_id = q6_device_to_cad_id(adev);
+		sz = acdb_get_config_table(acdb_id, sample_rate);
+		if (sz <= 0)
+			return -EINVAL;
+	}
+
+	audio_set_table(ac_control, adev, sz);
+	return 0;
+}
+
+static void _audio_rx_path_enable(int reconf, uint32_t acdb_id)
+{
+	adie_enable();
+	adie_set_path(adie, audio_rx_path_id, ADIE_PATH_RX);
+	adie_set_path_freq_plan(adie, ADIE_PATH_RX, 48000);
+
+	adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_READY);
+	adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_ANALOG_READY);
+
+	audio_update_acdb(audio_rx_device_id, acdb_id);
+	if (!reconf)
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, audio_rx_device_id);
+	qdsp6_standby(ac_control);
+	qdsp6_start(ac_control);
+
+	audio_rx_analog_enable(1);
+}
+
+static void _audio_tx_path_enable(int reconf, uint32_t acdb_id)
+{
+	audio_tx_analog_enable(1);
+
+	adie_enable();
+	adie_set_path(adie, audio_tx_path_id, ADIE_PATH_TX);
+
+	if (tx_clk_freq > 8000)
+		adie_set_path_freq_plan(adie, ADIE_PATH_TX, 48000);
+	else
+		adie_set_path_freq_plan(adie, ADIE_PATH_TX, 8000);
+
+	adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_DIGITAL_READY);
+	adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_DIGITAL_ANALOG_READY);
+
+	audio_update_acdb(audio_tx_device_id, acdb_id);
+
+	if (!reconf)
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, audio_tx_device_id);
+	qdsp6_standby(ac_control);
+	qdsp6_start(ac_control);
+
+	audio_tx_mute(ac_control, audio_tx_device_id, tx_mute_status);
+}
+
+static void _audio_rx_path_disable(void)
+{
+	audio_rx_analog_enable(0);
+
+	adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_ANALOG_OFF);
+	adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_OFF);
+	adie_disable();
+}
+
+static void _audio_tx_path_disable(void)
+{
+	audio_tx_analog_enable(0);
+
+	adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_ANALOG_OFF);
+	adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_DIGITAL_OFF);
+	adie_disable();
+}
+
+static int icodec_rx_clk_refcount;
+static int icodec_tx_clk_refcount;
+static int ecodec_clk_refcount;
+static int sdac_clk_refcount;
+
+static void _audio_rx_clk_enable(void)
+{
+	uint32_t device_group = q6_device_to_codec(audio_rx_device_id);
+
+	switch(device_group) {
+	case Q6_ICODEC_RX:
+		icodec_rx_clk_refcount++;
+		if (icodec_rx_clk_refcount == 1) {
+			clk_set_rate(icodec_rx_clk, 12288000);
+			clk_enable(icodec_rx_clk);
+		}
+		break;
+	case Q6_ECODEC_RX:
+		ecodec_clk_refcount++;
+		if (ecodec_clk_refcount == 1) {
+			clk_set_rate(ecodec_clk, 2048000);
+			clk_enable(ecodec_clk);
+		}
+		break;
+	case Q6_SDAC_RX:
+		sdac_clk_refcount++;
+		if (sdac_clk_refcount == 1) {
+			clk_set_rate(sdac_clk, 12288000);
+			clk_enable(sdac_clk);
+		}
+		break;
+	default:
+		return;
+	}
+	audio_rx_device_group = device_group;
+}
+
+static void _audio_tx_clk_enable(void)
+{
+	uint32_t device_group = q6_device_to_codec(audio_tx_device_id);
+
+	switch (device_group) {
+	case Q6_ICODEC_TX:
+		icodec_tx_clk_refcount++;
+		if (icodec_tx_clk_refcount == 1) {
+			clk_set_rate(icodec_tx_clk, tx_clk_freq * 256);
+			clk_enable(icodec_tx_clk);
+		}
+		break;
+	case Q6_ECODEC_TX:
+		ecodec_clk_refcount++;
+		if (ecodec_clk_refcount == 1) {
+			clk_set_rate(ecodec_clk, 2048000);
+			clk_enable(ecodec_clk);
+		}
+		break;
+	case Q6_SDAC_TX:
+		/* TODO: In QCT BSP, clk rate was set to 20480000 */
+		sdac_clk_refcount++;
+		if (sdac_clk_refcount == 1) {
+			clk_set_rate(sdac_clk, 12288000);
+			clk_enable(sdac_clk);
+		}
+		break;
+	default:
+		return;
+	}
+	audio_tx_device_group = device_group;
+}
+
+static void _audio_rx_clk_disable(void)
+{
+	switch (audio_rx_device_group) {
+	case Q6_ICODEC_RX:
+		icodec_rx_clk_refcount--;
+		if (icodec_rx_clk_refcount == 0) {
+			clk_disable(icodec_rx_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	case Q6_ECODEC_RX:
+		ecodec_clk_refcount--;
+		if (ecodec_clk_refcount == 0) {
+			clk_disable(ecodec_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	case Q6_SDAC_RX:
+		sdac_clk_refcount--;
+		if (sdac_clk_refcount == 0) {
+			clk_disable(sdac_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	default:
+		pr_err("audiolib: invalid rx device group %d\n",
+			audio_rx_device_group);
+		break;
+	}
+}
+
+static void _audio_tx_clk_disable(void)
+{
+	switch (audio_tx_device_group) {
+	case Q6_ICODEC_TX:
+		icodec_tx_clk_refcount--;
+		if (icodec_tx_clk_refcount == 0) {
+			clk_disable(icodec_tx_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	case Q6_ECODEC_TX:
+		ecodec_clk_refcount--;
+		if (ecodec_clk_refcount == 0) {
+			clk_disable(ecodec_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	case Q6_SDAC_TX:
+		sdac_clk_refcount--;
+		if (sdac_clk_refcount == 0) {
+			clk_disable(sdac_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	default:
+		pr_err("audiolib: invalid tx device group %d\n",
+			audio_tx_device_group);
+		break;
+	}
+}
+
+static void _audio_rx_clk_reinit(uint32_t rx_device)
+{
+	uint32_t device_group = q6_device_to_codec(rx_device);
+
+	if (device_group != audio_rx_device_group)
+		_audio_rx_clk_disable();
+
+	audio_rx_device_id = rx_device;
+	audio_rx_path_id = q6_device_to_path(rx_device);
+
+	if (device_group != audio_rx_device_group)
+		_audio_rx_clk_enable();
+
+}
+
+static void _audio_tx_clk_reinit(uint32_t tx_device)
+{
+	uint32_t device_group = q6_device_to_codec(tx_device);
+
+	if (device_group != audio_tx_device_group)
+		_audio_tx_clk_disable();
+
+	audio_tx_device_id = tx_device;
+	audio_tx_path_id = q6_device_to_path(tx_device);
+
+	if (device_group != audio_tx_device_group)
+		_audio_tx_clk_enable();
+}
+
+static DEFINE_MUTEX(audio_path_lock);
+static int audio_rx_path_refcount;
+static int audio_tx_path_refcount;
+
+static int audio_rx_path_enable(int en, uint32_t acdb_id)
+{
+	mutex_lock(&audio_path_lock);
+	if (en) {
+		audio_rx_path_refcount++;
+		if (audio_rx_path_refcount == 1) {
+			_audio_rx_clk_enable();
+			_audio_rx_path_enable(0, acdb_id);
+		}
+	} else {
+		audio_rx_path_refcount--;
+		if (audio_rx_path_refcount == 0) {
+			_audio_rx_path_disable();
+			_audio_rx_clk_disable();
+		}
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static int audio_tx_path_enable(int en, uint32_t acdb_id)
+{
+	mutex_lock(&audio_path_lock);
+	if (en) {
+		audio_tx_path_refcount++;
+		if (audio_tx_path_refcount == 1) {
+			_audio_tx_clk_enable();
+			_audio_tx_path_enable(0, acdb_id);
+		}
+	} else {
+		audio_tx_path_refcount--;
+		if (audio_tx_path_refcount == 0) {
+			_audio_tx_path_disable();
+			_audio_tx_clk_disable();
+		}
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_reinit_acdb(char* filename) {
+	int res;
+
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+	if (strlen(filename) < 0 || !strcmp(filename, acdb_file)) {
+		res = -EINVAL;
+		goto done;
+	}
+	res = acdb_init(filename);
+	if (!res)
+		strcpy(acdb_file, filename);
+done:
+	mutex_unlock(&audio_path_lock);
+	return res;
+
+}
+
+int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst)
+{
+	int res;
+
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+	res = audio_update_acdb(id_dst, id_src);
+	if (res)
+		goto done;
+
+	if (q6_device_to_dir(id_dst) == Q6_RX)
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, id_dst);
+	else
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, id_dst);
+	qdsp6_standby(ac_control);
+	qdsp6_start(ac_control);
+done:
+	mutex_unlock(&audio_path_lock);
+	return res;
+}
+
+int q6audio_set_tx_mute(int mute)
+{
+	uint32_t adev;
+
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	if (mute == tx_mute_status) {
+		mutex_unlock(&audio_path_lock);
+		return 0;
+	}
+
+	adev = audio_tx_device_id;
+	audio_tx_mute(ac_control, adev, mute);
+	tx_mute_status = mute;
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_stream_volume(struct audio_client *ac, int vol)
+{
+	if (vol > 1200 || vol < -4000) {
+		pr_err("unsupported volume level %d\n", vol);
+		return -EINVAL;
+	}
+	mutex_lock(&audio_path_lock);
+	audio_stream_mute(ac, 0);
+	audio_stream_volume(ac, vol);
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_rx_volume(int level)
+{
+	uint32_t adev;
+	int vol;
+
+	if (q6audio_init())
+		return 0;
+
+	if (level < 0 || level > 100)
+		return -EINVAL;
+
+	mutex_lock(&audio_path_lock);
+	adev = ADSP_AUDIO_DEVICE_ID_VOICE;
+	vol = q6_device_volume(audio_rx_device_id, level);
+	audio_rx_mute(ac_control, adev, 0);
+	audio_rx_volume(ac_control, adev, vol);
+	rx_vol_level = level;
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static void do_rx_routing(uint32_t device_id, uint32_t acdb_id)
+{
+	if (device_id == audio_rx_device_id) {
+		if (acdb_id != rx_acdb) {
+			audio_update_acdb(device_id, acdb_id);
+			qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, device_id);
+			qdsp6_standby(ac_control);
+			qdsp6_start(ac_control);
+		}
+		return;
+	}
+
+	if (audio_rx_path_refcount > 0) {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, device_id);
+		_audio_rx_path_disable();
+		_audio_rx_clk_reinit(device_id);
+		_audio_rx_path_enable(1, acdb_id);
+	} else {
+		audio_rx_device_id = device_id;
+		audio_rx_path_id = q6_device_to_path(device_id);
+	}
+}
+
+static void do_tx_routing(uint32_t device_id, uint32_t acdb_id)
+{
+	if (device_id == audio_tx_device_id) {
+		if (acdb_id != tx_acdb) {
+			audio_update_acdb(device_id, acdb_id);
+			qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, device_id);
+			qdsp6_standby(ac_control);
+			qdsp6_start(ac_control);
+		}
+		return;
+	}
+
+	if (audio_tx_path_refcount > 0) {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, device_id);
+		_audio_tx_path_disable();
+		_audio_tx_clk_reinit(device_id);
+		_audio_tx_path_enable(1, acdb_id);
+	} else {
+		audio_tx_device_id = device_id;
+		audio_tx_path_id = q6_device_to_path(device_id);
+	}
+}
+
+int q6audio_do_routing(uint32_t device_id, uint32_t acdb_id)
+{
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	switch(q6_device_to_dir(device_id)) {
+	case Q6_RX:
+		do_rx_routing(device_id, acdb_id);
+		break;
+	case Q6_TX:
+		do_tx_routing(device_id, acdb_id);
+		break;
+	}
+
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_route(const char *name)
+{
+	uint32_t route;
+	if (!strcmp(name, "speaker")) {
+		route = ADIE_PATH_SPEAKER_STEREO_RX;
+	} else if (!strcmp(name, "headphones")) {
+		route = ADIE_PATH_HEADSET_STEREO_RX;
+	} else if (!strcmp(name, "handset")) {
+		route = ADIE_PATH_HANDSET_RX;
+	} else {
+		return -EINVAL;
+	}
+
+	mutex_lock(&audio_path_lock);
+	if (route == audio_rx_path_id)
+		goto done;
+
+	audio_rx_path_id = route;
+
+	if (audio_rx_path_refcount > 0) {
+		_audio_rx_path_disable();
+		_audio_rx_path_enable(1, 0);
+	}
+	if (audio_tx_path_refcount > 0) {
+		_audio_tx_path_disable();
+		_audio_tx_path_enable(1, 0);
+	}
+done:
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate,
+				      uint32_t channels, uint32_t flags, uint32_t acdb_id)
+{
+	int rc, retry = 5;
+	struct audio_client *ac;
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+
+	mutex_lock(&audio_path_lock);
+
+	if (ac->flags & AUDIO_FLAG_WRITE) {
+		audio_rx_path_refcount++;
+		if (audio_rx_path_refcount == 1) {
+			_audio_rx_clk_enable();
+			audio_update_acdb(audio_rx_device_id, acdb_id);
+			qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, audio_rx_device_id);
+			qdsp6_standby(ac_control);
+			qdsp6_start(ac_control);
+		}
+	} else {
+		/* TODO: consider concurrency with voice call */
+		tx_clk_freq = rate;
+		audio_tx_path_refcount++;
+		if (audio_tx_path_refcount == 1) {
+			_audio_tx_clk_enable();
+			_audio_tx_path_enable(0, acdb_id);
+		}
+	}
+
+	for (retry = 5;;retry--) {
+		if (ac->flags & AUDIO_FLAG_WRITE)
+			rc = audio_out_open(ac, bufsz, rate, channels);
+		else
+			rc = audio_in_open(ac, bufsz, rate, channels);
+		if (rc == 0)
+			break;
+		if (retry == 0)
+			q6audio_dsp_not_responding();
+		pr_err("q6audio: open pcm error %d, retrying\n", rc);
+		msleep(1);
+	}
+
+	if (ac->flags & AUDIO_FLAG_WRITE) {
+		if (audio_rx_path_refcount == 1) {
+			adie_enable();
+			adie_set_path(adie, audio_rx_path_id, ADIE_PATH_RX);
+			adie_set_path_freq_plan(adie, ADIE_PATH_RX, 48000);
+
+			adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_READY);
+			adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_ANALOG_READY);
+
+			audio_rx_analog_enable(1);
+		}
+	}
+
+	mutex_unlock(&audio_path_lock);
+
+	for (retry = 5;;retry--) {
+		rc = audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+		if (rc == 0)
+			break;
+		if (retry == 0)
+			q6audio_dsp_not_responding();
+		pr_err("q6audio: stream start error %d, retrying\n", rc);
+	}
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+
+	audio_prevent_sleep();
+	return ac;
+}
+
+int q6audio_close(struct audio_client *ac)
+{
+	audio_close(ac);
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(0, 0);
+	else
+		audio_tx_path_enable(0, 0);
+
+	audio_client_free(ac);
+	audio_allow_sleep();
+	return 0;
+}
+
+struct audio_client *q6voice_open(uint32_t flags, uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(0);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1, acdb_id);
+	else {
+		tx_clk_freq = 8000;
+		audio_tx_path_enable(1, acdb_id);
+	}
+
+	return ac;
+}
+
+int q6voice_close(struct audio_client *ac)
+{
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(0, 0);
+	else
+		audio_tx_path_enable(0, 0);
+
+	audio_client_free(ac);
+	return 0;
+}
+
+struct audio_client *q6audio_open_mp3(uint32_t bufsz, uint32_t rate,
+				      uint32_t channels, uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	printk("q6audio_open_mp3()\n");
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = AUDIO_FLAG_WRITE;
+	audio_rx_path_enable(1, acdb_id);
+
+	audio_mp3_open(ac, bufsz, rate, channels);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	return ac;
+}
+
+int q6audio_mp3_close(struct audio_client *ac)
+{
+	audio_close(ac);
+	audio_rx_path_enable(0, 0);
+	audio_client_free(ac);
+	return 0;
+}
+
+int q6audio_async(struct audio_client *ac)
+{
+	struct adsp_command_hdr rpc;
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.opcode = ADSP_AUDIO_IOCTL_CMD_STREAM_EOS;
+	rpc.response_type = ADSP_AUDIO_RESPONSE_ASYNC;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
diff --git a/arch/arm/mach-msm/qdsp6/q6audio_devices.h b/arch/arm/mach-msm/qdsp6/q6audio_devices.h
new file mode 100644
index 0000000..d4d30b5
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/q6audio_devices.h
@@ -0,0 +1,265 @@
+/* arch/arm/mach-msm/qdsp6/q6audio_devices.h
+ *
+ * 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.
+ *
+ */
+
+struct q6_device_info {
+	uint32_t id;
+	uint32_t cad_id;
+	uint32_t path;
+	uint32_t rate;
+	uint8_t dir;
+	uint8_t codec;
+	uint8_t hw;
+};
+
+#define Q6_ICODEC_RX		0
+#define Q6_ICODEC_TX		1
+#define Q6_ECODEC_RX		2
+#define Q6_ECODEC_TX		3
+#define Q6_SDAC_RX		6
+#define Q6_SDAC_TX		7
+#define Q6_CODEC_NONE		255
+
+#define Q6_TX		1
+#define Q6_RX		2
+#define Q6_TX_RX	3
+
+#define CAD_HW_DEVICE_ID_HANDSET_MIC		0x01
+#define CAD_HW_DEVICE_ID_HANDSET_SPKR		0x02
+#define CAD_HW_DEVICE_ID_HEADSET_MIC		0x03
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO	0x04
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO	0x05
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_MIC		0x06
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_MONO	0x07
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO	0x08
+#define CAD_HW_DEVICE_ID_BT_SCO_MIC		0x09
+#define CAD_HW_DEVICE_ID_BT_SCO_SPKR		0x0A
+#define CAD_HW_DEVICE_ID_BT_A2DP_SPKR		0x0B
+#define CAD_HW_DEVICE_ID_TTY_HEADSET_MIC	0x0C
+#define CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR	0x0D
+
+#define CAD_HW_DEVICE_ID_DEFAULT_TX		0x0E
+#define CAD_HW_DEVICE_ID_DEFAULT_RX		0x0F
+
+/* Logical Device to indicate A2DP routing */
+#define CAD_HW_DEVICE_ID_BT_A2DP_TX             0x10
+#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX		0x11
+#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX	0x12
+#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX	0x13
+#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX	0x14
+
+#define CAD_HW_DEVICE_ID_VOICE			0x15
+
+#define CAD_HW_DEVICE_ID_I2S_RX                 0x20
+#define CAD_HW_DEVICE_ID_I2S_TX                 0x21
+
+/* AUXPGA */
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO_LB 0x22
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO_LB   0x23
+#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_STEREO_LB 0x24
+#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_MONO_LB   0x25
+
+#define CAD_HW_DEVICE_ID_NULL_RX		0x2A
+
+#define CAD_HW_DEVICE_ID_MAX_NUM                0x2F
+
+#define CAD_HW_DEVICE_ID_INVALID                0xFF
+
+#define CAD_RX_DEVICE  0x00
+#define CAD_TX_DEVICE  0x01
+
+static struct q6_device_info q6_audio_devices[] = {
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_SPKR,
+		.path	= ADIE_PATH_HANDSET_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO,
+		.path	= ADIE_PATH_HEADSET_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO,
+		.path	= ADIE_PATH_HEADSET_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_MONO,
+		.path	= ADIE_PATH_SPEAKER_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO,
+		.path	= ADIE_PATH_SPEAKER_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX,
+		.path	= ADIE_PATH_SPKR_MONO_HDPH_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX,
+		.path	= ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX,
+		.path	= ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX,
+		.path	= ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR,
+		.path	= ADIE_PATH_TTY_HEADSET_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_TTY,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_MIC,
+		.path	= ADIE_PATH_HANDSET_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MIC,
+		.path	= ADIE_PATH_HEADSET_MONO_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_MIC,
+		.path	= ADIE_PATH_SPEAKER_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_TTY_HEADSET_MIC,
+		.path	= ADIE_PATH_TTY_HEADSET_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_A2DP_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_A2DP,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_MIC,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ECODEC_TX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_I2S_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_I2S_RX,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_SDAC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_I2S_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_I2S_TX,
+		.path	= 0, /* XXX */
+		.rate   = 16000,
+		.dir	= Q6_TX,
+		.codec	= Q6_SDAC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= 0,
+		.cad_id	= 0,
+		.path	= 0,
+		.rate   = 8000,
+		.dir	= 0,
+		.codec	= Q6_CODEC_NONE,
+		.hw	= 0,
+	},
+};
+
diff --git a/arch/arm/mach-msm/qdsp6/routing.c b/arch/arm/mach-msm/qdsp6/routing.c
new file mode 100644
index 0000000..a851896
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/routing.c
@@ -0,0 +1,71 @@
+/* arch/arm/mach-msm/qdsp6/routing.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/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+extern int q6audio_set_route(const char *name);
+
+static int q6_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t q6_write(struct file *file, const char __user *buf,
+			size_t count, loff_t *pos)
+{
+	char cmd[32];
+
+	if (count >= sizeof(cmd))
+		return -EINVAL;
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	q6audio_set_route(cmd);
+
+	return count;
+}
+
+static int q6_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static struct file_operations q6_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_open,
+	.write		= q6_write,
+	.release	= q6_release,
+};
+
+static struct miscdevice q6_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_route",
+	.fops	= &q6_fops,
+};
+
+
+static int __init q6_init(void) {
+	return misc_register(&q6_misc);
+}
+
+device_initcall(q6_init);
diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c
new file mode 100644
index 0000000..75f6140
--- /dev/null
+++ b/arch/arm/mach-msm/remote_spinlock.c
@@ -0,0 +1,226 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <mach/remote_spinlock.h>
+#include "smd_private.h"
+
+#define SMEM_SPINLOCK_COUNT 8
+#define SMEM_SPINLOCK_ARRAY_SIZE (SMEM_SPINLOCK_COUNT * sizeof(uint32_t))
+
+struct raw_remote_spinlock {
+	union {
+		volatile u32 lock;
+		struct {
+			volatile u8 self_lock;
+			volatile u8 other_lock;
+			volatile u8 next_yield;
+			u8 pad;
+		} dek;
+	};
+};
+
+static inline void __raw_remote_ex_spin_lock(struct raw_remote_spinlock *lock)
+{
+	unsigned long tmp;
+
+	asm volatile (
+		"1:	ldrex	%0, [%1]\n"
+		"	teq	%0, #0\n"
+		"	strexeq	%0, %2, [%1]\n"
+		"	teqeq	%0, #0\n"
+		"	bne	1b"
+		: "=&r" (tmp)
+		: "r" (&lock->lock), "r" (1)
+		: "cc");
+
+	smp_mb();
+}
+
+static inline void __raw_remote_ex_spin_unlock(struct raw_remote_spinlock *lock)
+{
+	smp_mb();
+
+	asm volatile (
+		"	str	%1, [%0]\n"
+		:
+		: "r" (&lock->lock), "r" (0)
+		: "cc");
+}
+
+static inline void __raw_remote_swp_spin_lock(struct raw_remote_spinlock *lock)
+{
+	unsigned long tmp;
+
+	asm volatile (
+		"1:	swp	%0, %2, [%1]\n"
+		"	teq	%0, #0\n"
+		"	bne	1b"
+		: "=&r" (tmp)
+		: "r" (&lock->lock), "r" (1)
+		: "cc");
+
+	smp_mb();
+}
+
+static inline void __raw_remote_swp_spin_unlock(struct raw_remote_spinlock *lock)
+{
+	smp_mb();
+
+	asm volatile (
+		"	str	%1, [%0]"
+		:
+		: "r" (&lock->lock), "r" (0)
+		: "cc");
+}
+
+#define DEK_LOCK_REQUEST		1
+#define DEK_LOCK_YIELD			(!DEK_LOCK_REQUEST)
+#define DEK_YIELD_TURN_SELF		0
+static void __raw_remote_dek_spin_lock(struct raw_remote_spinlock *lock)
+{
+	lock->dek.self_lock = DEK_LOCK_REQUEST;
+
+	while (lock->dek.other_lock) {
+
+		if (lock->dek.next_yield == DEK_YIELD_TURN_SELF)
+			lock->dek.self_lock = DEK_LOCK_YIELD;
+
+		while (lock->dek.other_lock)
+			;
+
+		lock->dek.self_lock = DEK_LOCK_REQUEST;
+	}
+	lock->dek.next_yield = DEK_YIELD_TURN_SELF;
+
+	smp_mb();
+}
+
+static void __raw_remote_dek_spin_unlock(struct raw_remote_spinlock *lock)
+{
+	smp_mb();
+
+	lock->dek.self_lock = DEK_LOCK_YIELD;
+}
+
+#if defined(CONFIG_MSM_REMOTE_SPINLOCK_DEKKERS)
+/* Use Dekker's algorithm when LDREX/STREX and SWP are unavailable for
+ * shared memory */
+#define _raw_remote_spin_lock(lock)	__raw_remote_dek_spin_lock(lock)
+#define _raw_remote_spin_unlock(lock)	__raw_remote_dek_spin_unlock(lock)
+#elif defined(CONFIG_MSM_REMOTE_SPINLOCK_SWP)
+/* Use SWP-based locks when LDREX/STREX are unavailable for shared memory. */
+#define _raw_remote_spin_lock(lock)	__raw_remote_swp_spin_lock(lock)
+#define _raw_remote_spin_unlock(lock)	__raw_remote_swp_spin_unlock(lock)
+#else
+/* Use LDREX/STREX for shared memory locking, when available */
+#define _raw_remote_spin_lock(lock)	__raw_remote_ex_spin_lock(lock)
+#define _raw_remote_spin_unlock(lock)	__raw_remote_ex_spin_unlock(lock)
+#endif
+
+void _remote_spin_lock(remote_spinlock_t *lock)
+{
+	_raw_remote_spin_lock(lock->remote);
+}
+EXPORT_SYMBOL(_remote_spin_lock);
+
+void _remote_spin_unlock(remote_spinlock_t *lock)
+{
+	_raw_remote_spin_unlock(lock->remote);
+}
+EXPORT_SYMBOL(_remote_spin_unlock);
+
+static int remote_spin_lock_smem_init(remote_spinlock_t *lock, int id)
+{
+	void *start;
+
+	if (id >= SMEM_SPINLOCK_COUNT)
+		return -EINVAL;
+
+	start = smem_alloc(SMEM_SPINLOCK_ARRAY, SMEM_SPINLOCK_ARRAY_SIZE);
+	if (start == NULL)
+		return -ENXIO;
+
+	lock->remote =
+		(struct raw_remote_spinlock *)(start + id * sizeof(uint32_t));
+	return 0;
+}
+
+#define DAL_CHUNK_NAME_LENGTH 12
+struct dal_chunk_header {
+	uint32_t size;
+	char name[DAL_CHUNK_NAME_LENGTH];
+	uint32_t lock;
+	uint32_t reserved;
+	uint32_t type;
+	uint32_t version;
+};
+
+static int remote_spin_lock_dal_init(remote_spinlock_t *lock, const char *name)
+{
+	unsigned long start;
+	unsigned long end;
+	unsigned size;
+	struct dal_chunk_header *cur_hdr;
+
+	if (!name)
+		return -EINVAL;
+
+	start = (unsigned long)smem_item(SMEM_DAL_AREA, &size);
+	if (!start)
+		return -ENXIO;
+
+	end = start + size;
+
+	/* Find first chunk header */
+	cur_hdr = (struct dal_chunk_header *)ALIGN(start, 4096);
+	lock->remote = NULL;
+	while (((unsigned long)(cur_hdr + 1) <= end) && (cur_hdr->size != 0)) {
+		if (!strncmp(cur_hdr->name, name, DAL_CHUNK_NAME_LENGTH)) {
+			lock->remote =
+				(struct raw_remote_spinlock *)&cur_hdr->lock;
+			return 0;
+		}
+		cur_hdr = (void *)cur_hdr + cur_hdr->size;
+	}
+
+	pr_err("%s: DAL remote spin lock '%s' not found.\n", __func__, name);
+	return -EINVAL;
+}
+
+int _remote_spin_lock_init(remote_spinlock_t *lock, const char *name)
+{
+	BUG_ON(name == NULL);
+
+	/* remote spinlocks can be one of two formats:
+	 * D:<dal chunk name>
+	 * S:<single digit smem lock id>
+	 */
+	if (!strncmp(name, "D:", 2)) {
+		return remote_spin_lock_dal_init(lock, &name[2]);
+	} else if (!strncmp(name, "S:", 2)) {
+		BUG_ON(name[3] != '\0');
+		return remote_spin_lock_smem_init(lock, (uint8_t)(name[2]-'0'));
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(_remote_spin_lock_init);
diff --git a/arch/arm/mach-msm/rpc_server_dog_keepalive.c b/arch/arm/mach-msm/rpc_server_dog_keepalive.c
new file mode 100644
index 0000000..b23fccf
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_server_dog_keepalive.c
@@ -0,0 +1,68 @@
+/* arch/arm/mach-msm/rpc_server_dog_keepalive.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Iliyan Malchev <ibm@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/module.h>
+#include <linux/kernel.h>
+#include <mach/msm_rpcrouter.h>
+
+/* dog_keepalive server definitions */
+
+#define DOG_KEEPALIVE_PROG 0x30000015
+#if CONFIG_MSM_AMSS_VERSION==6210
+#define DOG_KEEPALIVE_VERS 0
+#define RPC_DOG_KEEPALIVE_BEACON 1
+#elif (CONFIG_MSM_AMSS_VERSION==6220) || (CONFIG_MSM_AMSS_VERSION==6225)
+#define DOG_KEEPALIVE_VERS 0x731fa727
+#define RPC_DOG_KEEPALIVE_BEACON 2
+#elif CONFIG_MSM_AMSS_VERSION==6350
+#define DOG_KEEPALIVE_VERS 0x00010000
+#define RPC_DOG_KEEPALIVE_BEACON 2
+#else
+#error "Unsupported AMSS version"
+#endif
+#define RPC_DOG_KEEPALIVE_NULL 0
+
+
+/* TODO: Remove server registration with _VERS when modem is upated with _COMP*/
+
+static int handle_rpc_call(struct msm_rpc_server *server,
+			   struct rpc_request_hdr *req, unsigned len)
+{
+	switch (req->procedure) {
+	case RPC_DOG_KEEPALIVE_NULL:
+		return 0;
+	case RPC_DOG_KEEPALIVE_BEACON:
+		printk(KERN_INFO "DOG KEEPALIVE PING\n");
+		return 0;
+	default:
+		return -ENODEV;
+	}
+}
+
+static struct msm_rpc_server rpc_server = {
+	.prog = DOG_KEEPALIVE_PROG,
+	.vers = DOG_KEEPALIVE_VERS,
+	.rpc_call = handle_rpc_call,
+};
+
+static int __init rpc_server_init(void)
+{
+	/* Dual server registration to support backwards compatibility vers */
+	return msm_rpc_create_server(&rpc_server);
+}
+
+
+module_init(rpc_server_init);
diff --git a/arch/arm/mach-msm/rpc_server_time_remote.c b/arch/arm/mach-msm/rpc_server_time_remote.c
new file mode 100644
index 0000000..2f90fc88
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_server_time_remote.c
@@ -0,0 +1,77 @@
+/* arch/arm/mach-msm/rpc_server_time_remote.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Iliyan Malchev <ibm@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/module.h>
+#include <linux/kernel.h>
+#include <mach/msm_rpcrouter.h>
+
+/* time_remote_mtoa server definitions. */
+
+#define TIME_REMOTE_MTOA_PROG 0x3000005d
+#if CONFIG_MSM_AMSS_VERSION==6210
+#define TIME_REMOTE_MTOA_VERS 0
+#elif (CONFIG_MSM_AMSS_VERSION==6220) || (CONFIG_MSM_AMSS_VERSION==6225)
+#define TIME_REMOTE_MTOA_VERS 0x9202a8e4
+#elif CONFIG_MSM_AMSS_VERSION==6350
+#define TIME_REMOTE_MTOA_VERS 0x00010000
+#else
+#error "Unknown AMSS version"
+#endif
+#define RPC_TIME_REMOTE_MTOA_NULL   0
+#define RPC_TIME_TOD_SET_APPS_BASES 2
+
+struct rpc_time_tod_set_apps_bases_args {
+	uint32_t tick;
+	uint64_t stamp;
+};
+
+static int handle_rpc_call(struct msm_rpc_server *server,
+			   struct rpc_request_hdr *req, unsigned len)
+{
+	switch (req->procedure) {
+	case RPC_TIME_REMOTE_MTOA_NULL:
+		return 0;
+
+	case RPC_TIME_TOD_SET_APPS_BASES: {
+		struct rpc_time_tod_set_apps_bases_args *args;
+		args = (struct rpc_time_tod_set_apps_bases_args *)(req + 1);
+		args->tick = be32_to_cpu(args->tick);
+		args->stamp = be64_to_cpu(args->stamp);
+		printk(KERN_INFO "RPC_TIME_TOD_SET_APPS_BASES:\n"
+		       "\ttick = %d\n"
+		       "\tstamp = %lld\n",
+		       args->tick, args->stamp);
+		return 0;
+	}
+	default:
+		return -ENODEV;
+	}
+}
+
+static struct msm_rpc_server rpc_server = {
+	.prog = TIME_REMOTE_MTOA_PROG,
+	.vers = TIME_REMOTE_MTOA_VERS,
+	.rpc_call = handle_rpc_call,
+};
+
+static int __init rpc_server_init(void)
+{
+	/* Dual server registration to support backwards compatibility vers */
+	return msm_rpc_create_server(&rpc_server);
+}
+
+
+module_init(rpc_server_init);
diff --git a/arch/arm/mach-msm/sirc.c b/arch/arm/mach-msm/sirc.c
index b079452..74e0686 100644
--- a/arch/arm/mach-msm/sirc.c
+++ b/arch/arm/mach-msm/sirc.c
@@ -1,25 +1,27 @@
-/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+/* linux/arch/arm/mach-msm/irq.c
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
+ * Copyright (c) 2009 QUALCOMM Incorporated.
+ * 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.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
  */
 
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <asm/irq.h>
+#include <mach/fiq.h>
+#include <mach/msm_iomap.h>
+
+#include "sirc.h"
 
 static unsigned int int_enable;
 static unsigned int wake_enable;
@@ -37,6 +39,7 @@
 	{
 		.int_status  = SPSS_SIRC_IRQ_STATUS,
 		.cascade_irq = INT_SIRC_0,
+		.cascade_fiq = INT_SIRC_1,
 	}
 };
 
@@ -120,6 +123,24 @@
 	return 0;
 }
 
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+void sirc_fiq_select(int irq, bool enable)
+{
+	uint32_t mask = 1 << (irq - FIRST_SIRC_IRQ);
+	uint32_t val;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	val = readl(SPSS_SIRC_INT_SELECT);
+	if (enable)
+		val |= mask;
+	else
+		val &= ~mask;
+	writel(val, SPSS_SIRC_INT_SELECT);
+	local_irq_restore(flags);
+}
+#endif
+
 /* Finds the pending interrupt on the passed cascade irq and redrives it */
 static void sirc_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
@@ -145,6 +166,22 @@
 	desc->chip->ack(irq);
 }
 
+void msm_sirc_enter_sleep(void)
+{
+	save_type     = readl(sirc_regs.int_type);
+	save_polarity = readl(sirc_regs.int_polarity);
+	writel(wake_enable, sirc_regs.int_enable);
+	return;
+}
+
+void msm_sirc_exit_sleep(void)
+{
+	writel(save_type, sirc_regs.int_type);
+	writel(save_polarity, sirc_regs.int_polarity);
+	writel(int_enable, sirc_regs.int_enable);
+	return;
+}
+
 static struct irq_chip sirc_irq_chip = {
 	.name      = "sirc",
 	.ack       = sirc_irq_ack,
@@ -161,7 +198,7 @@
 	int_enable = 0;
 	wake_enable = 0;
 
-	for (i = FIRST_SIRC_IRQ; i < LAST_SIRC_IRQ; i++) {
+	for (i = FIRST_SIRC_IRQ; i < FIRST_SIRC_IRQ + NR_SIRC_IRQS; i++) {
 		set_irq_chip(i, &sirc_irq_chip);
 		set_irq_handler(i, handle_edge_irq);
 		set_irq_flags(i, IRQF_VALID);
@@ -171,6 +208,10 @@
 		set_irq_chained_handler(sirc_reg_table[i].cascade_irq,
 					sirc_irq_handler);
 		set_irq_wake(sirc_reg_table[i].cascade_irq, 1);
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+		msm_fiq_select(sirc_reg_table[i].cascade_fiq);
+		msm_fiq_enable(sirc_reg_table[i].cascade_fiq);
+#endif
 	}
 	return;
 }
diff --git a/arch/arm/mach-msm/sirc.h b/arch/arm/mach-msm/sirc.h
new file mode 100644
index 0000000..8e1399f
--- /dev/null
+++ b/arch/arm/mach-msm/sirc.h
@@ -0,0 +1,27 @@
+/* arch/arm/mach-msm/pm.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_SIRC_H
+#define _ARCH_ARM_MACH_MSM_SIRC_H
+
+#ifdef CONFIG_ARCH_QSD8X50
+void sirc_fiq_select(int irq, bool enable);
+void __init msm_init_sirc(void);
+#else
+static inline void sirc_fiq_select(int irq, bool enable) {}
+static inline void __init msm_init_sirc(void) {}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index cf11d41..d613d5c 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -26,8 +26,10 @@
 #include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
 #include <mach/msm_smd.h>
+#include <mach/msm_iomap.h>
 #include <mach/system.h>
 
 #include "smd_private.h"
@@ -62,8 +64,21 @@
 module_param_named(debug_mask, msm_smd_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+void *smem_item(unsigned id, unsigned *size);
+static void smd_diag(void);
+
 static unsigned last_heap_free = 0xffffffff;
 
+static inline void msm_a2m_int(uint32_t irq)
+{
+#if defined(CONFIG_ARCH_MSM7X30)
+	writel(1 << irq, MSM_GCC_BASE + 0x8);
+#else
+	writel(1, MSM_CSR_BASE + 0x400 + (irq * 4));
+#endif
+}
+
+
 static inline void notify_other_smsm(void)
 {
 	msm_a2m_int(5);
@@ -93,11 +108,14 @@
 	}
 }
 
+void msm_pm_flush_console(void);
+
 /* call when SMSM_RESET flag is set in the A9's smsm_state */
 static void handle_modem_crash(void)
 {
 	pr_err("ARM9 has CRASHED\n");
 	smd_diag();
+	msm_pm_flush_console();
 
 	/* hard reboot if possible */
 	if (msm_hw_reset_hook)
@@ -108,6 +126,8 @@
 		;
 }
 
+extern int (*msm_check_for_modem_crash)(void);
+
 uint32_t raw_smsm_get_state(enum smsm_state_item item)
 {
 	return readl(smd_info.state + item * 4);
@@ -144,6 +164,44 @@
 static unsigned char smd_ch_allocated[64];
 static struct work_struct probe_work;
 
+static int smd_alloc_channel(const char *name, uint32_t cid, uint32_t type);
+
+static void smd_channel_probe_worker(struct work_struct *work)
+{
+	struct smd_alloc_elm *shared;
+	unsigned ctype;
+	unsigned type;
+	unsigned n;
+
+	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
+	if (!shared) {
+		pr_err("smd: cannot find allocation table\n");
+		return;
+	}
+	for (n = 0; n < 64; n++) {
+		if (smd_ch_allocated[n])
+			continue;
+		if (!shared[n].ref_count)
+			continue;
+		if (!shared[n].name[0])
+			continue;
+		ctype = shared[n].ctype;
+		type = ctype & SMD_TYPE_MASK;
+
+		/* DAL channels are stream but neither the modem,
+		 * nor the DSP correctly indicate this.  Fixup manually.
+		 */
+		if (!memcmp(shared[n].name, "DAL", 3))
+			ctype = (ctype & (~SMD_KIND_MASK)) | SMD_KIND_STREAM;
+
+		type = shared[n].ctype & SMD_TYPE_MASK;
+		if ((type == SMD_TYPE_APPS_MODEM) ||
+		    (type == SMD_TYPE_APPS_DSP))
+			if (!smd_alloc_channel(shared[n].name, shared[n].cid, ctype))
+				smd_ch_allocated[n] = 1;
+	}
+}
+
 /* how many bytes are available for reading */
 static int smd_stream_read_avail(struct smd_channel *ch)
 {
@@ -378,13 +436,11 @@
 	return IRQ_HANDLED;
 }
 
-#if defined(CONFIG_QDSP6)
 static irqreturn_t smd_dsp_irq_handler(int irq, void *data)
 {
 	handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd);
 	return IRQ_HANDLED;
 }
-#endif
 
 static void smd_fake_irq_handler(unsigned long arg)
 {
@@ -554,6 +610,48 @@
 	return r;
 }
 
+static int smd_alloc_v2(struct smd_channel *ch)
+{
+	struct smd_shared_v2 *shared2;
+	void *buffer;
+	unsigned buffer_sz;
+
+	shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n, sizeof(*shared2));
+	buffer = smem_item(SMEM_SMD_FIFO_BASE_ID + ch->n, &buffer_sz);
+
+	if (!buffer)
+		return -1;
+
+	/* buffer must be a power-of-two size */
+	if (buffer_sz & (buffer_sz - 1))
+		return -1;
+
+	buffer_sz /= 2;
+	ch->send = &shared2->ch0;
+	ch->recv = &shared2->ch1;
+	ch->send_data = buffer;
+	ch->recv_data = buffer + buffer_sz;
+	ch->fifo_size = buffer_sz;
+	return 0;
+}
+
+static int smd_alloc_v1(struct smd_channel *ch)
+{
+	struct smd_shared_v1 *shared1;
+	shared1 = smem_alloc(ID_SMD_CHANNELS + ch->n, sizeof(*shared1));
+	if (!shared1) {
+		pr_err("smd_alloc_channel() cid %d does not exist\n", ch->n);
+		return -1;
+	}
+	ch->send = &shared1->ch0;
+	ch->recv = &shared1->ch1;
+	ch->send_data = shared1->data0;
+	ch->recv_data = shared1->data1;
+	ch->fifo_size = SMD_BUF_SIZE;
+	return 0;
+}
+
+
 static int smd_alloc_channel(const char *name, uint32_t cid, uint32_t type)
 {
 	struct smd_channel *ch;
@@ -565,7 +663,7 @@
 	}
 	ch->n = cid;
 
-	if (_smd_alloc_channel(ch)) {
+	if (smd_alloc_v2(ch) && smd_alloc_v1(ch)) {
 		kfree(ch);
 		return -1;
 	}
@@ -612,42 +710,6 @@
 	return 0;
 }
 
-static void smd_channel_probe_worker(struct work_struct *work)
-{
-	struct smd_alloc_elm *shared;
-	unsigned ctype;
-	unsigned type;
-	unsigned n;
-
-	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
-	if (!shared) {
-		pr_err("smd: cannot find allocation table\n");
-		return;
-	}
-	for (n = 0; n < 64; n++) {
-		if (smd_ch_allocated[n])
-			continue;
-		if (!shared[n].ref_count)
-			continue;
-		if (!shared[n].name[0])
-			continue;
-		ctype = shared[n].ctype;
-		type = ctype & SMD_TYPE_MASK;
-
-		/* DAL channels are stream but neither the modem,
-		 * nor the DSP correctly indicate this.  Fixup manually.
-		 */
-		if (!memcmp(shared[n].name, "DAL", 3))
-			ctype = (ctype & (~SMD_KIND_MASK)) | SMD_KIND_STREAM;
-
-		type = shared[n].ctype & SMD_TYPE_MASK;
-		if ((type == SMD_TYPE_APPS_MODEM) ||
-		    (type == SMD_TYPE_APPS_DSP))
-			if (!smd_alloc_channel(shared[n].name, shared[n].cid, ctype))
-				smd_ch_allocated[n] = 1;
-	}
-}
-
 static void do_nothing_notify(void *priv, unsigned flags)
 {
 }
@@ -845,9 +907,9 @@
 
 	if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
 		pr_info("<SM %08x %08x>\n", apps, modm);
-	if (modm & SMSM_RESET)
+	if (modm & SMSM_RESET) {
 		handle_modem_crash();
-
+	}
 	do_smd_probe();
 
 	spin_unlock_irqrestore(&smem_lock, flags);
@@ -857,9 +919,9 @@
 int smsm_change_state(enum smsm_state_item item,
 		      uint32_t clear_mask, uint32_t set_mask)
 {
-	unsigned long addr = smd_info.state + item * 4;
 	unsigned long flags;
 	unsigned state;
+	unsigned addr = smd_info.state + item * 4;
 
 	if (!smd_info.ready)
 		return -EIO;
@@ -997,17 +1059,12 @@
 	return 0;
 }
 
-static int __init msm_smd_probe(struct platform_device *pdev)
+extern void msm_init_last_radio_log(struct module *);
+
+static int msm_smd_probe(struct platform_device *pdev)
 {
 	pr_info("smd_init()\n");
 
-	/*
-	 * If we haven't waited for the ARM9 to boot up till now,
-	 * then we need to wait here. Otherwise this should just
-	 * return immediately.
-	 */
-	proc_comm_boot_wait();
-
 	INIT_WORK(&probe_work, smd_channel_probe_worker);
 
 	if (smd_core_init()) {
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index 3b2dd71..6951cc7 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -154,20 +154,31 @@
 	return sprintf(buf, "%d.%d\n", version >> 16, version & 0xffff);
 }
 
+struct smem_msm_id {
+	uint32_t	format;
+	uint32_t	msm_id;
+	uint32_t	msm_ver;
+	char		build_id[32];
+};
+
 static int debug_read_build_id(char *buf, int max)
 {
 	unsigned size;
 	void *data;
+	struct smem_msm_id *msm_id;
 
-	data = smem_item(SMEM_HW_SW_BUILD_ID, &size);
-	if (!data)
+	msm_id = smem_item(SMEM_HW_SW_BUILD_ID, &size);
+	if (!msm_id || (size < sizeof(struct smem_msm_id)))
 		return 0;
 
 	if (size >= max)
 		size = max;
-	memcpy(buf, data, size);
 
-	return size;
+	return scnprintf(buf, size, "fmt=%d id=%d vers=%d.%d build_id='%s'\n",
+			 msm_id->format,msm_id->msm_id,
+			 (msm_id->msm_ver >> 16) & 0xffff,
+			 msm_id->msm_ver & 0xffff,
+			 msm_id->build_id);
 }
 
 static int debug_read_alloc_tbl(char *buf, int max)
@@ -227,7 +238,7 @@
 
 	dent = debugfs_create_dir("smd", 0);
 	if (IS_ERR(dent))
-		return 1;
+		return PTR_ERR(dent);
 
 	debug_create("ch", 0444, dent, debug_read_ch);
 	debug_create("stat", 0444, dent, debug_read_stat);
@@ -269,9 +280,10 @@
 {
 	unsigned long flags;
 	uint32_t *ptr;
+#ifndef CONFIG_ARCH_MSM_SCORPION
 	struct tramp_gpio_smem *gpio;
 	struct smsm_interrupt_info *int_info;
-
+#endif
 
 	spin_lock_irqsave(&smem_lock, flags);
 
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 727bfe6..2da758e 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -19,25 +19,25 @@
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
-#include <linux/io.h>
 
-#include <mach/msm_iomap.h>
-
-struct smem_heap_info {
+struct smem_heap_info
+{
 	unsigned initialized;
 	unsigned free_offset;
 	unsigned heap_remaining;
 	unsigned reserved;
 };
 
-struct smem_heap_entry {
+struct smem_heap_entry
+{
 	unsigned allocated;
 	unsigned offset;
 	unsigned size;
 	unsigned reserved;
 };
 
-struct smem_proc_comm {
+struct smem_proc_comm
+{
 	unsigned command;
 	unsigned status;
 	unsigned data1;
@@ -54,7 +54,8 @@
 #define VERSION_APPS      8
 #define VERSION_MODEM     9
 
-struct smem_shared {
+struct smem_shared
+{
 	struct smem_proc_comm proc_comm[4];
 	unsigned version[32];
 	struct smem_heap_info heap_info;
@@ -64,8 +65,9 @@
 #define SMSM_V1_SIZE		(sizeof(unsigned) * 8)
 #define SMSM_V2_SIZE		(sizeof(unsigned) * 4)
 
-#ifdef CONFIG_MSM_SMD_PKG3
-struct smsm_interrupt_info {
+#ifndef CONFIG_ARCH_MSM_SCORPION
+struct smsm_interrupt_info
+{
 	uint32_t interrupt_mask;
 	uint32_t pending_interrupts;
 	uint32_t wakeup_reason;
@@ -126,7 +128,7 @@
 #define SMSM_WKUP_REASON_ALARM	0x00000010
 #define SMSM_WKUP_REASON_RESET	0x00000020
 
-#ifdef CONFIG_ARCH_MSM7X00A
+#ifndef CONFIG_ARCH_MSM_SCORPION
 enum smsm_state_item {
 	SMSM_STATE_APPS = 1,
 	SMSM_STATE_MODEM = 3,
@@ -154,7 +156,8 @@
 
 #define SMEM_NUM_SMD_CHANNELS        64
 
-typedef enum {
+typedef enum
+{
 	/* fixed items */
 	SMEM_PROC_COMM = 0,
 	SMEM_HEAP_INFO,
@@ -229,7 +232,7 @@
 	SMEM_SMEM_LOG_POWER_WRAP,
 	SMEM_SMEM_LOG_POWER_EVENTS,
 	SMEM_ERR_CRASH_LOG,
-	SMEM_ERR_F3_TRACE_LOG,
+	SMEM_ERR_F3_TRACE_LOG,	
 	SMEM_NUM_ITEMS,
 } smem_mem_type;
 
@@ -268,7 +271,6 @@
 	unsigned head;
 } __attribute__(( aligned(4), packed ));
 
-/* Only used on SMD package v3 on msm7201a */
 struct smd_shared_v1 {
 	struct smd_half_channel ch0;
 	unsigned char data0[SMD_BUF_SIZE];
@@ -276,11 +278,10 @@
 	unsigned char data1[SMD_BUF_SIZE];
 };
 
-/* Used on SMD package v4 */
 struct smd_shared_v2 {
 	struct smd_half_channel ch0;
 	struct smd_half_channel ch1;
-};
+};	
 
 struct smd_channel {
 	volatile struct smd_half_channel *send;
@@ -333,71 +334,4 @@
 void *smem_item(unsigned id, unsigned *size);
 uint32_t raw_smsm_get_state(enum smsm_state_item item);
 
-extern void msm_init_last_radio_log(struct module *);
-
-#ifdef CONFIG_MSM_SMD_PKG3
-/*
- * This allocator assumes an SMD Package v3 which only exists on
- * MSM7x00 SoC's.
- */
-static inline int _smd_alloc_channel(struct smd_channel *ch)
-{
-	struct smd_shared_v1 *shared1;
-
-	shared1 = smem_alloc(ID_SMD_CHANNELS + ch->n, sizeof(*shared1));
-	if (!shared1) {
-		pr_err("smd_alloc_channel() cid %d does not exist\n", ch->n);
-		return -1;
-	}
-	ch->send = &shared1->ch0;
-	ch->recv = &shared1->ch1;
-	ch->send_data = shared1->data0;
-	ch->recv_data = shared1->data1;
-	ch->fifo_size = SMD_BUF_SIZE;
-	return 0;
-}
-#else
-/*
- * This allocator assumes an SMD Package v4, the most common
- * and the default.
- */
-static inline int _smd_alloc_channel(struct smd_channel *ch)
-{
-	struct smd_shared_v2 *shared2;
-	void *buffer;
-	unsigned buffer_sz;
-
-	shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n, sizeof(*shared2));
-	buffer = smem_item(SMEM_SMD_FIFO_BASE_ID + ch->n, &buffer_sz);
-
-	if (!buffer)
-		return -1;
-
-	/* buffer must be a power-of-two size */
-	if (buffer_sz & (buffer_sz - 1))
-		return -1;
-
-	buffer_sz /= 2;
-	ch->send = &shared2->ch0;
-	ch->recv = &shared2->ch1;
-	ch->send_data = buffer;
-	ch->recv_data = buffer + buffer_sz;
-	ch->fifo_size = buffer_sz;
-	return 0;
-}
-#endif /* CONFIG_MSM_SMD_PKG3 */
-
-#if defined(CONFIG_ARCH_MSM7X30)
-static inline void msm_a2m_int(uint32_t irq)
-{
-	writel(1 << irq, MSM_GCC_BASE + 0x8);
-}
-#else
-static inline void msm_a2m_int(uint32_t irq)
-{
-	writel(1, MSM_CSR_BASE + 0x400 + (irq * 4));
-}
-#endif /* CONFIG_ARCH_MSM7X30 */
-
-
 #endif
diff --git a/arch/arm/mach-msm/smd_qmi.c b/arch/arm/mach-msm/smd_qmi.c
new file mode 100644
index 0000000..50411df
--- /dev/null
+++ b/arch/arm/mach-msm/smd_qmi.c
@@ -0,0 +1,860 @@
+/* arch/arm/mach-msm/smd_qmi.c
+ *
+ * QMI Control Driver -- Manages network data connections.
+ *
+ * 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 <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/workqueue.h>
+#include <linux/wakelock.h>
+
+#include <asm/uaccess.h>
+#include <mach/msm_smd.h>
+
+#define QMI_CTL 0x00
+#define QMI_WDS 0x01
+#define QMI_DMS 0x02
+#define QMI_NAS 0x03
+
+#define QMI_RESULT_SUCCESS 0x0000
+#define QMI_RESULT_FAILURE 0x0001
+
+struct qmi_msg {
+	unsigned char service;
+	unsigned char client_id;
+	unsigned short txn_id;
+	unsigned short type;
+	unsigned short size;
+	unsigned char *tlv;
+};
+
+#define qmi_ctl_client_id 0
+
+#define STATE_OFFLINE    0
+#define STATE_QUERYING   1
+#define STATE_ONLINE     2
+
+struct qmi_ctxt {
+	struct miscdevice misc;
+
+	struct mutex lock;
+
+	unsigned char ctl_txn_id;
+	unsigned char wds_client_id;
+	unsigned short wds_txn_id;
+
+	unsigned wds_busy;
+	unsigned wds_handle;
+	unsigned state_dirty;
+	unsigned state;
+
+	unsigned char addr[4];
+	unsigned char mask[4];
+	unsigned char gateway[4];
+	unsigned char dns1[4];
+	unsigned char dns2[4];
+
+	smd_channel_t *ch;
+	const char *ch_name;
+	struct wake_lock wake_lock;
+
+	struct work_struct open_work;
+	struct work_struct read_work;
+};
+
+static struct qmi_ctxt *qmi_minor_to_ctxt(unsigned n);
+
+static void qmi_read_work(struct work_struct *ws);
+static void qmi_open_work(struct work_struct *work);
+
+void qmi_ctxt_init(struct qmi_ctxt *ctxt, unsigned n)
+{
+	mutex_init(&ctxt->lock);
+	INIT_WORK(&ctxt->read_work, qmi_read_work);
+	INIT_WORK(&ctxt->open_work, qmi_open_work);
+	wake_lock_init(&ctxt->wake_lock, WAKE_LOCK_SUSPEND, ctxt->misc.name);
+	ctxt->ctl_txn_id = 1;
+	ctxt->wds_txn_id = 1;
+	ctxt->wds_busy = 1;
+	ctxt->state = STATE_OFFLINE;
+
+}
+
+static struct workqueue_struct *qmi_wq;
+
+static int verbose = 0;
+
+/* anyone waiting for a state change waits here */
+static DECLARE_WAIT_QUEUE_HEAD(qmi_wait_queue);
+
+
+static void qmi_dump_msg(struct qmi_msg *msg, const char *prefix)
+{
+	unsigned sz, n;
+	unsigned char *x;
+
+	if (!verbose)
+		return;
+
+	printk(KERN_INFO
+	       "qmi: %s: svc=%02x cid=%02x tid=%04x type=%04x size=%04x\n",
+	       prefix, msg->service, msg->client_id,
+	       msg->txn_id, msg->type, msg->size);
+
+	x = msg->tlv;
+	sz = msg->size;
+
+	while (sz >= 3) {
+		sz -= 3;
+
+		n = x[1] | (x[2] << 8);
+		if (n > sz)
+			break;
+
+		printk(KERN_INFO "qmi: %s: tlv: %02x %04x { ",
+		       prefix, x[0], n);
+		x += 3;
+		sz -= n;
+		while (n-- > 0)
+			printk("%02x ", *x++);
+		printk("}\n");
+	}
+}
+
+int qmi_add_tlv(struct qmi_msg *msg,
+		unsigned type, unsigned size, const void *data)
+{
+	unsigned char *x = msg->tlv + msg->size;
+
+	x[0] = type;
+	x[1] = size;
+	x[2] = size >> 8;
+
+	memcpy(x + 3, data, size);
+
+	msg->size += (size + 3);
+
+	return 0;
+}
+
+/* Extract a tagged item from a qmi message buffer,
+** taking care not to overrun the buffer.
+*/
+static int qmi_get_tlv(struct qmi_msg *msg,
+		       unsigned type, unsigned size, void *data)
+{
+	unsigned char *x = msg->tlv;
+	unsigned len = msg->size;
+	unsigned n;
+
+	while (len >= 3) {
+		len -= 3;
+
+		/* size of this item */
+		n = x[1] | (x[2] << 8);
+		if (n > len)
+			break;
+
+		if (x[0] == type) {
+			if (n != size)
+				return -1;
+			memcpy(data, x + 3, size);
+			return 0;
+		}
+
+		x += (n + 3);
+		len -= n;
+	}
+
+	return -1;
+}
+
+static unsigned qmi_get_status(struct qmi_msg *msg, unsigned *error)
+{
+	unsigned short status[2];
+	if (qmi_get_tlv(msg, 0x02, sizeof(status), status)) {
+		*error = 0;
+		return QMI_RESULT_FAILURE;
+	} else {
+		*error = status[1];
+		return status[0];
+	}
+}
+
+/* 0x01 <qmux-header> <payload> */
+#define QMUX_HEADER    13
+
+/* should be >= HEADER + FOOTER */
+#define QMUX_OVERHEAD  16
+
+static int qmi_send(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
+{
+	unsigned char *data;
+	unsigned hlen;
+	unsigned len;
+	int r;
+
+	qmi_dump_msg(msg, "send");
+
+	if (msg->service == QMI_CTL) {
+		hlen = QMUX_HEADER - 1;
+	} else {
+		hlen = QMUX_HEADER;
+	}
+
+	/* QMUX length is total header + total payload - IFC selector */
+	len = hlen + msg->size - 1;
+	if (len > 0xffff)
+		return -1;
+
+	data = msg->tlv - hlen;
+
+	/* prepend encap and qmux header */
+	*data++ = 0x01; /* ifc selector */
+
+	/* qmux header */
+	*data++ = len;
+	*data++ = len >> 8;
+	*data++ = 0x00; /* flags: client */
+	*data++ = msg->service;
+	*data++ = msg->client_id;
+
+	/* qmi header */
+	*data++ = 0x00; /* flags: send */
+	*data++ = msg->txn_id;
+	if (msg->service != QMI_CTL)
+		*data++ = msg->txn_id >> 8;
+
+	*data++ = msg->type;
+	*data++ = msg->type >> 8;
+	*data++ = msg->size;
+	*data++ = msg->size >> 8;
+
+	/* len + 1 takes the interface selector into account */
+	r = smd_write(ctxt->ch, msg->tlv - hlen, len + 1);
+
+	if (r != len) {
+		return -1;
+	} else {
+		return 0;
+	}
+}
+
+static void qmi_process_ctl_msg(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
+{
+	unsigned err;
+	if (msg->type == 0x0022) {
+		unsigned char n[2];
+		if (qmi_get_status(msg, &err))
+			return;
+		if (qmi_get_tlv(msg, 0x01, sizeof(n), n))
+			return;
+		if (n[0] == QMI_WDS) {
+			printk(KERN_INFO
+			       "qmi: ctl: wds use client_id 0x%02x\n", n[1]);
+			ctxt->wds_client_id = n[1];
+			ctxt->wds_busy = 0;
+		}
+	}
+}
+
+static int qmi_network_get_profile(struct qmi_ctxt *ctxt);
+
+static void swapaddr(unsigned char *src, unsigned char *dst)
+{
+	dst[0] = src[3];
+	dst[1] = src[2];
+	dst[2] = src[1];
+	dst[3] = src[0];
+}
+
+static unsigned char zero[4];
+static void qmi_read_runtime_profile(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
+{
+	unsigned char tmp[4];
+	unsigned r;
+
+	r = qmi_get_tlv(msg, 0x1e, 4, tmp);
+	swapaddr(r ? zero : tmp, ctxt->addr);
+	r = qmi_get_tlv(msg, 0x21, 4, tmp);
+	swapaddr(r ? zero : tmp, ctxt->mask);
+	r = qmi_get_tlv(msg, 0x20, 4, tmp);
+	swapaddr(r ? zero : tmp, ctxt->gateway);
+	r = qmi_get_tlv(msg, 0x15, 4, tmp);
+	swapaddr(r ? zero : tmp, ctxt->dns1);
+	r = qmi_get_tlv(msg, 0x16, 4, tmp);
+	swapaddr(r ? zero : tmp, ctxt->dns2);
+}
+
+static void qmi_process_unicast_wds_msg(struct qmi_ctxt *ctxt,
+					struct qmi_msg *msg)
+{
+	unsigned err;
+	switch (msg->type) {
+	case 0x0021:
+		if (qmi_get_status(msg, &err)) {
+			printk(KERN_ERR
+			       "qmi: wds: network stop failed (%04x)\n", err);
+		} else {
+			printk(KERN_INFO
+			       "qmi: wds: network stopped\n");
+			ctxt->state = STATE_OFFLINE;
+			ctxt->state_dirty = 1;
+		}
+		break;
+	case 0x0020:
+		if (qmi_get_status(msg, &err)) {
+			printk(KERN_ERR
+			       "qmi: wds: network start failed (%04x)\n", err);
+		} else if (qmi_get_tlv(msg, 0x01, sizeof(ctxt->wds_handle), &ctxt->wds_handle)) {
+			printk(KERN_INFO
+			       "qmi: wds no handle?\n");
+		} else {
+			printk(KERN_INFO
+			       "qmi: wds: got handle 0x%08x\n",
+			       ctxt->wds_handle);
+		}
+		break;
+	case 0x002D:
+		printk("qmi: got network profile\n");
+		if (ctxt->state == STATE_QUERYING) {
+			qmi_read_runtime_profile(ctxt, msg);
+			ctxt->state = STATE_ONLINE;
+			ctxt->state_dirty = 1;
+		}
+		break;
+	default:
+		printk(KERN_ERR "qmi: unknown msg type 0x%04x\n", msg->type);
+	}
+	ctxt->wds_busy = 0;
+}
+
+static void qmi_process_broadcast_wds_msg(struct qmi_ctxt *ctxt,
+					  struct qmi_msg *msg)
+{
+	if (msg->type == 0x0022) {
+		unsigned char n[2];
+		if (qmi_get_tlv(msg, 0x01, sizeof(n), n))
+			return;
+		switch (n[0]) {
+		case 1:
+			printk(KERN_INFO "qmi: wds: DISCONNECTED\n");
+			ctxt->state = STATE_OFFLINE;
+			ctxt->state_dirty = 1;
+			break;
+		case 2:
+			printk(KERN_INFO "qmi: wds: CONNECTED\n");
+			ctxt->state = STATE_QUERYING;
+			ctxt->state_dirty = 1;
+			qmi_network_get_profile(ctxt);
+			break;
+		case 3:
+			printk(KERN_INFO "qmi: wds: SUSPENDED\n");
+			ctxt->state = STATE_OFFLINE;
+			ctxt->state_dirty = 1;
+		}
+	} else {
+		printk(KERN_ERR "qmi: unknown bcast msg type 0x%04x\n", msg->type);
+	}
+}
+
+static void qmi_process_wds_msg(struct qmi_ctxt *ctxt,
+				struct qmi_msg *msg)
+{
+	printk("wds: %04x @ %02x\n", msg->type, msg->client_id);
+	if (msg->client_id == ctxt->wds_client_id) {
+		qmi_process_unicast_wds_msg(ctxt, msg);
+	} else if (msg->client_id == 0xff) {
+		qmi_process_broadcast_wds_msg(ctxt, msg);
+	} else {
+		printk(KERN_ERR
+		       "qmi_process_wds_msg client id 0x%02x unknown\n",
+		       msg->client_id);
+	}
+}
+
+static void qmi_process_qmux(struct qmi_ctxt *ctxt,
+			     unsigned char *buf, unsigned sz)
+{
+	struct qmi_msg msg;
+
+	/* require a full header */
+	if (sz < 5)
+		return;
+
+	/* require a size that matches the buffer size */
+	if (sz != (buf[0] | (buf[1] << 8)))
+		return;
+
+	/* only messages from a service (bit7=1) are allowed */
+	if (buf[2] != 0x80)
+		return;
+
+	msg.service = buf[3];
+	msg.client_id = buf[4];
+
+	/* annoyingly, CTL messages have a shorter TID */
+	if (buf[3] == 0) {
+		if (sz < 7)
+			return;
+		msg.txn_id = buf[6];
+		buf += 7;
+		sz -= 7;
+	} else {
+		if (sz < 8)
+			return;
+		msg.txn_id = buf[6] | (buf[7] << 8);
+		buf += 8;
+		sz -= 8;
+	}
+
+	/* no type and size!? */
+	if (sz < 4)
+		return;
+	sz -= 4;
+
+	msg.type = buf[0] | (buf[1] << 8);
+	msg.size = buf[2] | (buf[3] << 8);
+	msg.tlv = buf + 4;
+
+	if (sz != msg.size)
+		return;
+
+	qmi_dump_msg(&msg, "recv");
+
+	mutex_lock(&ctxt->lock);
+	switch (msg.service) {
+	case QMI_CTL:
+		qmi_process_ctl_msg(ctxt, &msg);
+		break;
+	case QMI_WDS:
+		qmi_process_wds_msg(ctxt, &msg);
+		break;
+	default:
+		printk(KERN_ERR "qmi: msg from unknown svc 0x%02x\n",
+		       msg.service);
+		break;
+	}
+	mutex_unlock(&ctxt->lock);
+
+	wake_up(&qmi_wait_queue);
+}
+
+#define QMI_MAX_PACKET (256 + QMUX_OVERHEAD)
+
+static void qmi_read_work(struct work_struct *ws)
+{
+	struct qmi_ctxt *ctxt = container_of(ws, struct qmi_ctxt, read_work);
+	struct smd_channel *ch = ctxt->ch;
+	unsigned char buf[QMI_MAX_PACKET];
+	int sz;
+
+	for (;;) {
+		sz = smd_cur_packet_size(ch);
+		if (sz == 0)
+			break;
+		if (sz < smd_read_avail(ch))
+			break;
+		if (sz > QMI_MAX_PACKET) {
+			smd_read(ch, 0, sz);
+			continue;
+		}
+		if (smd_read(ch, buf, sz) != sz) {
+			printk(KERN_ERR "qmi: not enough data?!\n");
+			continue;
+		}
+
+		/* interface selector must be 1 */
+		if (buf[0] != 0x01)
+			continue;
+
+		qmi_process_qmux(ctxt, buf + 1, sz - 1);
+	}
+}
+
+static int qmi_request_wds_cid(struct qmi_ctxt *ctxt);
+
+static void qmi_open_work(struct work_struct *ws)
+{
+	struct qmi_ctxt *ctxt = container_of(ws, struct qmi_ctxt, open_work);
+	mutex_lock(&ctxt->lock);
+	qmi_request_wds_cid(ctxt);
+	mutex_unlock(&ctxt->lock);
+}
+
+static void qmi_notify(void *priv, unsigned event)
+{
+	struct qmi_ctxt *ctxt = priv;
+	
+	switch (event) {
+	case SMD_EVENT_DATA: {
+		int sz;
+		sz = smd_cur_packet_size(ctxt->ch);
+		if ((sz > 0) && (sz <= smd_read_avail(ctxt->ch))) {
+			wake_lock_timeout(&ctxt->wake_lock, HZ / 2);
+			queue_work(qmi_wq, &ctxt->read_work);
+		}
+		break;
+	}
+	case SMD_EVENT_OPEN:
+		printk(KERN_INFO "qmi: smd opened\n");
+		queue_work(qmi_wq, &ctxt->open_work);
+		break;
+	case SMD_EVENT_CLOSE:
+		printk(KERN_INFO "qmi: smd closed\n");
+		break;
+	}
+}
+
+static int qmi_request_wds_cid(struct qmi_ctxt *ctxt)
+{
+	unsigned char data[64 + QMUX_OVERHEAD];
+	struct qmi_msg msg;
+	unsigned char n;
+
+	msg.service = QMI_CTL;
+	msg.client_id = qmi_ctl_client_id;
+	msg.txn_id = ctxt->ctl_txn_id;
+	msg.type = 0x0022;
+	msg.size = 0;
+	msg.tlv = data + QMUX_HEADER;
+
+	ctxt->ctl_txn_id += 2;
+
+	n = QMI_WDS;
+	qmi_add_tlv(&msg, 0x01, 0x01, &n);
+
+	return qmi_send(ctxt, &msg);
+}
+
+static int qmi_network_get_profile(struct qmi_ctxt *ctxt)
+{
+	unsigned char data[96 + QMUX_OVERHEAD];
+	struct qmi_msg msg;
+
+	msg.service = QMI_WDS;
+	msg.client_id = ctxt->wds_client_id;
+	msg.txn_id = ctxt->wds_txn_id;
+	msg.type = 0x002D;
+	msg.size = 0;
+	msg.tlv = data + QMUX_HEADER;
+
+	ctxt->wds_txn_id += 2;
+
+	return qmi_send(ctxt, &msg);
+}
+
+static int qmi_network_up(struct qmi_ctxt *ctxt, char *apn)
+{
+	unsigned char data[96 + QMUX_OVERHEAD];
+	struct qmi_msg msg;
+	char *auth_type;
+	char *user;
+	char *pass;
+
+	for (user = apn; *user; user++) {
+		if (*user == ' ') {
+			*user++ = 0;
+			break;
+		}
+	}
+	for (pass = user; *pass; pass++) {
+		if (*pass == ' ') {
+			*pass++ = 0;
+			break;
+		}
+	}
+
+	for (auth_type = pass; *auth_type; auth_type++) {
+		if (*auth_type == ' ') {
+			*auth_type++ = 0;
+			break;
+		}
+	}
+
+	msg.service = QMI_WDS;
+	msg.client_id = ctxt->wds_client_id;
+	msg.txn_id = ctxt->wds_txn_id;
+	msg.type = 0x0020;
+	msg.size = 0;
+	msg.tlv = data + QMUX_HEADER;
+
+	ctxt->wds_txn_id += 2;
+
+	qmi_add_tlv(&msg, 0x14, strlen(apn), apn);
+	if (*auth_type)
+		qmi_add_tlv(&msg, 0x16, strlen(auth_type), auth_type);
+	if (*user) {
+		if (!*auth_type) {
+			unsigned char x;
+			x = 3;
+			qmi_add_tlv(&msg, 0x16, 1, &x);
+		}
+		qmi_add_tlv(&msg, 0x17, strlen(user), user);
+		if (*pass)
+			qmi_add_tlv(&msg, 0x18, strlen(pass), pass);
+	}
+	return qmi_send(ctxt, &msg);
+}
+
+static int qmi_network_down(struct qmi_ctxt *ctxt)
+{
+	unsigned char data[16 + QMUX_OVERHEAD];
+	struct qmi_msg msg;
+
+	msg.service = QMI_WDS;
+	msg.client_id = ctxt->wds_client_id;
+	msg.txn_id = ctxt->wds_txn_id;
+	msg.type = 0x0021;
+	msg.size = 0;
+	msg.tlv = data + QMUX_HEADER;
+
+	ctxt->wds_txn_id += 2;
+
+	qmi_add_tlv(&msg, 0x01, sizeof(ctxt->wds_handle), &ctxt->wds_handle);
+
+	return qmi_send(ctxt, &msg);
+}
+
+static int qmi_print_state(struct qmi_ctxt *ctxt, char *buf, int max)
+{
+	int i;
+	char *statename;
+
+	if (ctxt->state == STATE_ONLINE) {
+		statename = "up";
+	} else if (ctxt->state == STATE_OFFLINE) {
+		statename = "down";
+	} else {
+		statename = "busy";
+	}
+
+	i = scnprintf(buf, max, "STATE=%s\n", statename);
+	i += scnprintf(buf + i, max - i, "CID=%d\n",ctxt->wds_client_id);
+
+	if (ctxt->state != STATE_ONLINE){
+		return i;
+	}
+
+	i += scnprintf(buf + i, max - i, "ADDR=%d.%d.%d.%d\n",
+		ctxt->addr[0], ctxt->addr[1], ctxt->addr[2], ctxt->addr[3]);
+	i += scnprintf(buf + i, max - i, "MASK=%d.%d.%d.%d\n",
+		ctxt->mask[0], ctxt->mask[1], ctxt->mask[2], ctxt->mask[3]);
+	i += scnprintf(buf + i, max - i, "GATEWAY=%d.%d.%d.%d\n",
+		ctxt->gateway[0], ctxt->gateway[1], ctxt->gateway[2],
+		ctxt->gateway[3]);
+	i += scnprintf(buf + i, max - i, "DNS1=%d.%d.%d.%d\n",
+		ctxt->dns1[0], ctxt->dns1[1], ctxt->dns1[2], ctxt->dns1[3]);
+	i += scnprintf(buf + i, max - i, "DNS2=%d.%d.%d.%d\n",
+		ctxt->dns2[0], ctxt->dns2[1], ctxt->dns2[2], ctxt->dns2[3]);
+
+	return i;
+}
+
+static ssize_t qmi_read(struct file *fp, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	struct qmi_ctxt *ctxt = fp->private_data;
+	char msg[256];
+	int len;
+	int r;
+
+	mutex_lock(&ctxt->lock);
+	for (;;) {
+		if (ctxt->state_dirty) {
+			ctxt->state_dirty = 0;
+			len = qmi_print_state(ctxt, msg, 256);
+			break;
+		}
+		mutex_unlock(&ctxt->lock);
+		r = wait_event_interruptible(qmi_wait_queue, ctxt->state_dirty);
+		if (r < 0)
+			return r;
+		mutex_lock(&ctxt->lock);
+	}
+	mutex_unlock(&ctxt->lock);
+
+	if (len > count)
+		len = count;
+
+	if (copy_to_user(buf, msg, len))
+		return -EFAULT;
+
+	return len;
+}
+
+
+static ssize_t qmi_write(struct file *fp, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	struct qmi_ctxt *ctxt = fp->private_data;
+	unsigned char cmd[64];
+	int len;
+	int r;
+
+	if (count < 1)
+		return 0;
+
+	len = count > 63 ? 63 : count;
+
+	if (copy_from_user(cmd, buf, len))
+		return -EFAULT;
+
+	cmd[len] = 0;
+
+	/* lazy */
+	if (cmd[len-1] == '\n') {
+		cmd[len-1] = 0;
+		len--;
+	}
+
+	if (!strncmp(cmd, "verbose", 7)) {
+		verbose = 1;
+	} else if (!strncmp(cmd, "terse", 5)) {
+		verbose = 0;
+	} else if (!strncmp(cmd, "poll", 4)) {
+		ctxt->state_dirty = 1;
+		wake_up(&qmi_wait_queue);
+	} else if (!strncmp(cmd, "down", 4)) {
+retry_down:
+		mutex_lock(&ctxt->lock);
+		if (ctxt->wds_busy) {
+			mutex_unlock(&ctxt->lock);
+			r = wait_event_interruptible(qmi_wait_queue, !ctxt->wds_busy);
+			if (r < 0)
+				return r;
+			goto retry_down;
+		}
+		ctxt->wds_busy = 1;
+		qmi_network_down(ctxt);
+		mutex_unlock(&ctxt->lock);
+	} else if (!strncmp(cmd, "up:", 3)) {
+retry_up:
+		mutex_lock(&ctxt->lock);
+		if (ctxt->wds_busy) {
+			mutex_unlock(&ctxt->lock);
+			r = wait_event_interruptible(qmi_wait_queue, !ctxt->wds_busy);
+			if (r < 0)
+				return r;
+			goto retry_up;
+		}
+		ctxt->wds_busy = 1;
+		qmi_network_up(ctxt, cmd+3);
+		mutex_unlock(&ctxt->lock);
+	} else {
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static int qmi_open(struct inode *ip, struct file *fp)
+{
+	struct qmi_ctxt *ctxt = qmi_minor_to_ctxt(MINOR(ip->i_rdev));
+	int r = 0;
+
+	if (!ctxt) {
+		printk(KERN_ERR "unknown qmi misc %d\n", MINOR(ip->i_rdev));
+		return -ENODEV;
+	}
+
+	fp->private_data = ctxt;
+
+	mutex_lock(&ctxt->lock);
+	if (ctxt->ch == 0)
+		r = smd_open(ctxt->ch_name, &ctxt->ch, ctxt, qmi_notify);
+	if (r == 0)
+		wake_up(&qmi_wait_queue);
+	mutex_unlock(&ctxt->lock);
+
+	return r;
+}
+
+static int qmi_release(struct inode *ip, struct file *fp)
+{
+	return 0;
+}
+
+static struct file_operations qmi_fops = {
+	.owner = THIS_MODULE,
+	.read = qmi_read,
+	.write = qmi_write,
+	.open = qmi_open,
+	.release = qmi_release,
+};
+
+static struct qmi_ctxt qmi_device0 = {
+	.ch_name = "SMD_DATA5_CNTL",
+	.misc = {
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = "qmi0",
+		.fops = &qmi_fops,
+	}
+};
+static struct qmi_ctxt qmi_device1 = {
+	.ch_name = "SMD_DATA6_CNTL",
+	.misc = {
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = "qmi1",
+		.fops = &qmi_fops,
+	}
+};
+static struct qmi_ctxt qmi_device2 = {
+	.ch_name = "SMD_DATA7_CNTL",
+	.misc = {
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = "qmi2",
+		.fops = &qmi_fops,
+	}
+};
+
+static struct qmi_ctxt *qmi_minor_to_ctxt(unsigned n)
+{
+	if (n == qmi_device0.misc.minor)
+		return &qmi_device0;
+	if (n == qmi_device1.misc.minor)
+		return &qmi_device1;
+	if (n == qmi_device2.misc.minor)
+		return &qmi_device2;
+	return 0;
+}
+
+static int __init qmi_init(void)
+{
+	int ret;
+
+	qmi_wq = create_singlethread_workqueue("qmi");
+	if (qmi_wq == 0)
+		return -ENOMEM;
+
+	qmi_ctxt_init(&qmi_device0, 0);
+	qmi_ctxt_init(&qmi_device1, 1);
+	qmi_ctxt_init(&qmi_device2, 2);
+
+	ret = misc_register(&qmi_device0.misc);
+	if (ret == 0)
+		ret = misc_register(&qmi_device1.misc);
+	if (ret == 0)
+		ret = misc_register(&qmi_device2.misc);
+	return ret;
+}
+
+module_init(qmi_init);
diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c
new file mode 100644
index 0000000..ed9745a
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter.c
@@ -0,0 +1,1344 @@
+/* arch/arm/mach-msm/smd_rpcrouter.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009 QUALCOMM Incorporated.
+ * Author: San Mehat <san@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.
+ *
+ */
+
+/* TODO: handle cases where smd_write() will tempfail due to full fifo */
+/* TODO: thread priority? schedule a work to bump it? */
+/* TODO: maybe make server_list_lock a mutex */
+/* TODO: pool fragments to avoid kmalloc/kfree churn */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/wakelock.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+
+#include <asm/byteorder.h>
+
+#include <mach/msm_smd.h>
+#include "smd_rpcrouter.h"
+
+#define TRACE_R2R_MSG 0
+#define TRACE_R2R_RAW 0
+#define TRACE_RPC_MSG 0
+#define TRACE_NOTIFY_MSG 0
+
+#define MSM_RPCROUTER_DEBUG 0
+#define MSM_RPCROUTER_DEBUG_PKT 0
+#define MSM_RPCROUTER_R2R_DEBUG 0
+#define DUMP_ALL_RECEIVED_HEADERS 0
+
+#define DIAG(x...) printk("[RR] ERROR " x)
+
+#if MSM_RPCROUTER_DEBUG
+#define D(x...) printk(x)
+#else
+#define D(x...) do {} while (0)
+#endif
+
+#if TRACE_R2R_MSG
+#define RR(x...) printk("[RR] "x)
+#else
+#define RR(x...) do {} while (0)
+#endif
+
+#if TRACE_RPC_MSG
+#define IO(x...) printk("[RPC] "x)
+#else
+#define IO(x...) do {} while (0)
+#endif
+
+#if TRACE_NOTIFY_MSG
+#define NTFY(x...) printk(KERN_ERR "[NOTIFY] "x)
+#else
+#define NTFY(x...) do {} while (0)
+#endif
+
+static LIST_HEAD(local_endpoints);
+static LIST_HEAD(remote_endpoints);
+
+static LIST_HEAD(server_list);
+
+static smd_channel_t *smd_channel;
+static int initialized;
+static wait_queue_head_t newserver_wait;
+static wait_queue_head_t smd_wait;
+static int smd_wait_count; /* odd while waiting */
+
+static DEFINE_SPINLOCK(local_endpoints_lock);
+static DEFINE_SPINLOCK(remote_endpoints_lock);
+static DEFINE_SPINLOCK(server_list_lock);
+static DEFINE_SPINLOCK(smd_lock);
+
+static struct workqueue_struct *rpcrouter_workqueue;
+static struct wake_lock rpcrouter_wake_lock;
+static int rpcrouter_need_len;
+
+static atomic_t next_xid = ATOMIC_INIT(1);
+static atomic_t next_mid = ATOMIC_INIT(0);
+
+static void do_read_data(struct work_struct *work);
+static void do_create_pdevs(struct work_struct *work);
+static void do_create_rpcrouter_pdev(struct work_struct *work);
+
+static DECLARE_WORK(work_read_data, do_read_data);
+static DECLARE_WORK(work_create_pdevs, do_create_pdevs);
+static DECLARE_WORK(work_create_rpcrouter_pdev, do_create_rpcrouter_pdev);
+static atomic_t rpcrouter_pdev_created = ATOMIC_INIT(0);
+
+#define RR_STATE_IDLE    0
+#define RR_STATE_HEADER  1
+#define RR_STATE_BODY    2
+#define RR_STATE_ERROR   3
+
+struct rr_context {
+	struct rr_packet *pkt;
+	uint8_t *ptr;
+	uint32_t state; /* current assembly state */
+	uint32_t count; /* bytes needed in this state */
+};
+
+struct rr_context the_rr_context;
+
+static struct platform_device rpcrouter_pdev = {
+	.name		= "oncrpc_router",
+	.id		= -1,
+};
+
+
+static int rpcrouter_send_control_msg(union rr_control_msg *msg)
+{
+	struct rr_header hdr;
+	unsigned long flags;
+	int need;
+
+	if (!(msg->cmd == RPCROUTER_CTRL_CMD_HELLO) && !initialized) {
+		printk(KERN_ERR "rpcrouter_send_control_msg(): Warning, "
+		       "router not initialized\n");
+		return -EINVAL;
+	}
+
+	hdr.version = RPCROUTER_VERSION;
+	hdr.type = msg->cmd;
+	hdr.src_pid = RPCROUTER_PID_LOCAL;
+	hdr.src_cid = RPCROUTER_ROUTER_ADDRESS;
+	hdr.confirm_rx = 0;
+	hdr.size = sizeof(*msg);
+	hdr.dst_pid = 0;
+	hdr.dst_cid = RPCROUTER_ROUTER_ADDRESS;
+
+	/* TODO: what if channel is full? */
+
+	need = sizeof(hdr) + hdr.size;
+	spin_lock_irqsave(&smd_lock, flags);
+	while (smd_write_avail(smd_channel) < need) {
+		spin_unlock_irqrestore(&smd_lock, flags);
+		msleep(250);
+		spin_lock_irqsave(&smd_lock, flags);
+	}
+	smd_write(smd_channel, &hdr, sizeof(hdr));
+	smd_write(smd_channel, msg, hdr.size);
+	spin_unlock_irqrestore(&smd_lock, flags);
+	return 0;
+}
+
+static struct rr_server *rpcrouter_create_server(uint32_t pid,
+							uint32_t cid,
+							uint32_t prog,
+							uint32_t ver)
+{
+	struct rr_server *server;
+	unsigned long flags;
+	int rc;
+
+	server = kmalloc(sizeof(struct rr_server), GFP_KERNEL);
+	if (!server)
+		return ERR_PTR(-ENOMEM);
+
+	memset(server, 0, sizeof(struct rr_server));
+	server->pid = pid;
+	server->cid = cid;
+	server->prog = prog;
+	server->vers = ver;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_add_tail(&server->list, &server_list);
+	spin_unlock_irqrestore(&server_list_lock, flags);
+
+	if (pid == RPCROUTER_PID_REMOTE) {
+		rc = msm_rpcrouter_create_server_cdev(server);
+		if (rc < 0)
+			goto out_fail;
+	}
+	return server;
+out_fail:
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_del(&server->list);
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	kfree(server);
+	return ERR_PTR(rc);
+}
+
+static void rpcrouter_destroy_server(struct rr_server *server)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_del(&server->list);
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	device_destroy(msm_rpcrouter_class, server->device_number);
+	kfree(server);
+}
+
+static struct rr_server *rpcrouter_lookup_server(uint32_t prog, uint32_t ver)
+{
+	struct rr_server *server;
+	unsigned long flags;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if (server->prog == prog
+		 && server->vers == ver) {
+			spin_unlock_irqrestore(&server_list_lock, flags);
+			return server;
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	return NULL;
+}
+
+static struct rr_server *rpcrouter_lookup_server_by_dev(dev_t dev)
+{
+	struct rr_server *server;
+	unsigned long flags;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if (server->device_number == dev) {
+			spin_unlock_irqrestore(&server_list_lock, flags);
+			return server;
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	return NULL;
+}
+
+struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev)
+{
+	struct msm_rpc_endpoint *ept;
+	unsigned long flags;
+	int i;
+
+	ept = kmalloc(sizeof(struct msm_rpc_endpoint), GFP_KERNEL);
+	if (!ept)
+		return NULL;
+	memset(ept, 0, sizeof(struct msm_rpc_endpoint));
+
+	/* mark no reply outstanding */
+	ept->next_rroute = 0;
+	for (i = 0; i < MAX_REPLY_ROUTE; i++)
+		ept->rroute[i].pid = 0xffffffff;
+
+	ept->cid = (uint32_t) ept;
+	ept->pid = RPCROUTER_PID_LOCAL;
+	ept->dev = dev;
+
+	if ((dev != msm_rpcrouter_devno) && (dev != MKDEV(0, 0))) {
+		struct rr_server *srv;
+		/*
+		 * This is a userspace client which opened
+		 * a program/ver devicenode. Bind the client
+		 * to that destination
+		 */
+		srv = rpcrouter_lookup_server_by_dev(dev);
+		/* TODO: bug? really? */
+		BUG_ON(!srv);
+
+		ept->dst_pid = srv->pid;
+		ept->dst_cid = srv->cid;
+		ept->dst_prog = cpu_to_be32(srv->prog);
+		ept->dst_vers = cpu_to_be32(srv->vers);
+		ept->flags |= MSM_RPC_ENABLE_RECEIVE;
+
+		D("Creating local ept %p @ %08x:%08x\n", ept, srv->prog, srv->vers);
+	} else {
+		/* mark not connected */
+		ept->dst_pid = 0xffffffff;
+		D("Creating a master local ept %p\n", ept);
+	}
+
+	init_waitqueue_head(&ept->wait_q);
+	INIT_LIST_HEAD(&ept->read_q);
+	spin_lock_init(&ept->read_q_lock);
+	wake_lock_init(&ept->read_q_wake_lock, WAKE_LOCK_SUSPEND, "rpc_read");
+	INIT_LIST_HEAD(&ept->incomplete);
+
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	list_add_tail(&ept->list, &local_endpoints);
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+	return ept;
+}
+
+int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept)
+{
+	int rc;
+	union rr_control_msg msg;
+
+	msg.cmd = RPCROUTER_CTRL_CMD_REMOVE_CLIENT;
+	msg.cli.pid = ept->pid;
+	msg.cli.cid = ept->cid;
+
+	RR("x REMOVE_CLIENT id=%d:%08x\n", ept->pid, ept->cid);
+	rc = rpcrouter_send_control_msg(&msg);
+	if (rc < 0)
+		return rc;
+
+	wake_lock_destroy(&ept->read_q_wake_lock);
+	list_del(&ept->list);
+	kfree(ept);
+	return 0;
+}
+
+static int rpcrouter_create_remote_endpoint(uint32_t cid)
+{
+	struct rr_remote_endpoint *new_c;
+	unsigned long flags;
+
+	new_c = kmalloc(sizeof(struct rr_remote_endpoint), GFP_KERNEL);
+	if (!new_c)
+		return -ENOMEM;
+	memset(new_c, 0, sizeof(struct rr_remote_endpoint));
+
+	new_c->cid = cid;
+	new_c->pid = RPCROUTER_PID_REMOTE;
+	init_waitqueue_head(&new_c->quota_wait);
+	spin_lock_init(&new_c->quota_lock);
+
+	spin_lock_irqsave(&remote_endpoints_lock, flags);
+	list_add_tail(&new_c->list, &remote_endpoints);
+	spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+	return 0;
+}
+
+static struct msm_rpc_endpoint *rpcrouter_lookup_local_endpoint(uint32_t cid)
+{
+	struct msm_rpc_endpoint *ept;
+	unsigned long flags;
+
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	list_for_each_entry(ept, &local_endpoints, list) {
+		if (ept->cid == cid) {
+			spin_unlock_irqrestore(&local_endpoints_lock, flags);
+			return ept;
+		}
+	}
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+	return NULL;
+}
+
+static struct rr_remote_endpoint *rpcrouter_lookup_remote_endpoint(uint32_t cid)
+{
+	struct rr_remote_endpoint *ept;
+	unsigned long flags;
+
+	spin_lock_irqsave(&remote_endpoints_lock, flags);
+	list_for_each_entry(ept, &remote_endpoints, list) {
+		if (ept->cid == cid) {
+			spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+			return ept;
+		}
+	}
+	spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+	return NULL;
+}
+
+static int process_control_msg(union rr_control_msg *msg, int len)
+{
+	union rr_control_msg ctl;
+	struct rr_server *server;
+	struct rr_remote_endpoint *r_ept;
+	int rc = 0;
+	unsigned long flags;
+
+	if (len != sizeof(*msg)) {
+		printk(KERN_ERR "rpcrouter: r2r msg size %d != %d\n",
+		       len, sizeof(*msg));
+		return -EINVAL;
+	}
+
+	switch (msg->cmd) {
+	case RPCROUTER_CTRL_CMD_HELLO:
+		RR("o HELLO\n");
+
+		RR("x HELLO\n");
+		memset(&ctl, 0, sizeof(ctl));
+		ctl.cmd = RPCROUTER_CTRL_CMD_HELLO;
+		rpcrouter_send_control_msg(&ctl);
+
+		initialized = 1;
+
+		/* Send list of servers one at a time */
+		ctl.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
+
+		/* TODO: long time to hold a spinlock... */
+		spin_lock_irqsave(&server_list_lock, flags);
+		list_for_each_entry(server, &server_list, list) {
+			ctl.srv.pid = server->pid;
+			ctl.srv.cid = server->cid;
+			ctl.srv.prog = server->prog;
+			ctl.srv.vers = server->vers;
+
+			RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+			   server->pid, server->cid,
+			   server->prog, server->vers);
+
+			rpcrouter_send_control_msg(&ctl);
+		}
+		spin_unlock_irqrestore(&server_list_lock, flags);
+
+		queue_work(rpcrouter_workqueue, &work_create_rpcrouter_pdev);
+		break;
+
+	case RPCROUTER_CTRL_CMD_RESUME_TX:
+		RR("o RESUME_TX id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
+
+		r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.cid);
+		if (!r_ept) {
+			printk(KERN_ERR
+			       "rpcrouter: Unable to resume client\n");
+			break;
+		}
+		spin_lock_irqsave(&r_ept->quota_lock, flags);
+		r_ept->tx_quota_cntr = 0;
+		spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+		wake_up(&r_ept->quota_wait);
+		break;
+
+	case RPCROUTER_CTRL_CMD_NEW_SERVER:
+		RR("o NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+		   msg->srv.pid, msg->srv.cid, msg->srv.prog, msg->srv.vers);
+
+		server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
+
+		if (!server) {
+			server = rpcrouter_create_server(
+				msg->srv.pid, msg->srv.cid,
+				msg->srv.prog, msg->srv.vers);
+			if (!server)
+				return -ENOMEM;
+			/*
+			 * XXX: Verify that its okay to add the
+			 * client to our remote client list
+			 * if we get a NEW_SERVER notification
+			 */
+			if (!rpcrouter_lookup_remote_endpoint(msg->srv.cid)) {
+				rc = rpcrouter_create_remote_endpoint(
+					msg->srv.cid);
+				if (rc < 0)
+					printk(KERN_ERR
+						"rpcrouter:Client create"
+						"error (%d)\n", rc);
+			}
+			schedule_work(&work_create_pdevs);
+			wake_up(&newserver_wait);
+		} else {
+			if ((server->pid == msg->srv.pid) &&
+			    (server->cid == msg->srv.cid)) {
+				printk(KERN_ERR "rpcrouter: Duplicate svr\n");
+			} else {
+				server->pid = msg->srv.pid;
+				server->cid = msg->srv.cid;
+			}
+		}
+		break;
+
+	case RPCROUTER_CTRL_CMD_REMOVE_SERVER:
+		RR("o REMOVE_SERVER prog=%08x:%d\n",
+		   msg->srv.prog, msg->srv.vers);
+		server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
+		if (server)
+			rpcrouter_destroy_server(server);
+		break;
+
+	case RPCROUTER_CTRL_CMD_REMOVE_CLIENT:
+		RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
+		if (msg->cli.pid != RPCROUTER_PID_REMOTE) {
+			printk(KERN_ERR
+			       "rpcrouter: Denying remote removal of "
+			       "local client\n");
+			break;
+		}
+		r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.cid);
+		if (r_ept) {
+			spin_lock_irqsave(&remote_endpoints_lock, flags);
+			list_del(&r_ept->list);
+			spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+			kfree(r_ept);
+		}
+
+		/* Notify local clients of this event */
+		printk(KERN_ERR "rpcrouter: LOCAL NOTIFICATION NOT IMP\n");
+		rc = -ENOSYS;
+
+		break;
+	default:
+		RR("o UNKNOWN(%08x)\n", msg->cmd);
+		rc = -ENOSYS;
+	}
+
+	return rc;
+}
+
+static void do_create_rpcrouter_pdev(struct work_struct *work)
+{
+	if (atomic_cmpxchg(&rpcrouter_pdev_created, 0, 1) == 0)
+		platform_device_register(&rpcrouter_pdev);
+}
+
+static void do_create_pdevs(struct work_struct *work)
+{
+	unsigned long flags;
+	struct rr_server *server;
+
+	/* TODO: race if destroyed while being registered */
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if (server->pid == RPCROUTER_PID_REMOTE) {
+			if (server->pdev_name[0] == 0) {
+				spin_unlock_irqrestore(&server_list_lock,
+						       flags);
+				msm_rpcrouter_create_server_pdev(server);
+				schedule_work(&work_create_pdevs);
+				return;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+}
+
+static void rpcrouter_smdnotify(void *_dev, unsigned event)
+{
+	if (event != SMD_EVENT_DATA)
+		return;
+
+	if (smd_read_avail(smd_channel) >= rpcrouter_need_len)
+		wake_lock(&rpcrouter_wake_lock);
+	wake_up(&smd_wait);
+}
+
+static void *rr_malloc(unsigned sz)
+{
+	void *ptr = kmalloc(sz, GFP_KERNEL);
+	if (ptr)
+		return ptr;
+
+	printk(KERN_ERR "rpcrouter: kmalloc of %d failed, retrying...\n", sz);
+	do {
+		ptr = kmalloc(sz, GFP_KERNEL);
+	} while (!ptr);
+
+	return ptr;
+}
+
+/* TODO: deal with channel teardown / restore */
+static int rr_read(void *data, int len)
+{
+	int rc;
+	unsigned long flags;
+//	printk("rr_read() %d\n", len);
+	for(;;) {
+		spin_lock_irqsave(&smd_lock, flags);
+		if (smd_read_avail(smd_channel) >= len) {
+			rc = smd_read(smd_channel, data, len);
+			spin_unlock_irqrestore(&smd_lock, flags);
+			if (rc == len)
+				return 0;
+			else
+				return -EIO;
+		}
+		rpcrouter_need_len = len;
+		wake_unlock(&rpcrouter_wake_lock);
+		spin_unlock_irqrestore(&smd_lock, flags);
+
+//		printk("rr_read: waiting (%d)\n", len);
+		smd_wait_count++;
+		wake_up(&smd_wait);
+		wait_event(smd_wait, smd_read_avail(smd_channel) >= len);
+		smd_wait_count++;
+	}
+	return 0;
+}
+
+static uint32_t r2r_buf[RPCROUTER_MSGSIZE_MAX];
+
+static void do_read_data(struct work_struct *work)
+{
+	struct rr_header hdr;
+	struct rr_packet *pkt;
+	struct rr_fragment *frag;
+	struct msm_rpc_endpoint *ept;
+	uint32_t pm, mid;
+	unsigned long flags;
+
+	if (rr_read(&hdr, sizeof(hdr)))
+		goto fail_io;
+
+#if TRACE_R2R_RAW
+	RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
+	   hdr.version, hdr.type, hdr.src_pid, hdr.src_cid,
+	   hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid);
+#endif
+
+	if (hdr.version != RPCROUTER_VERSION) {
+		DIAG("version %d != %d\n", hdr.version, RPCROUTER_VERSION);
+		goto fail_data;
+	}
+	if (hdr.size > RPCROUTER_MSGSIZE_MAX) {
+		DIAG("msg size %d > max %d\n", hdr.size, RPCROUTER_MSGSIZE_MAX);
+		goto fail_data;
+	}
+
+	if (hdr.dst_cid == RPCROUTER_ROUTER_ADDRESS) {
+		if (rr_read(r2r_buf, hdr.size))
+			goto fail_io;
+		process_control_msg((void*) r2r_buf, hdr.size);
+		goto done;
+	}
+
+	if (hdr.size < sizeof(pm)) {
+		DIAG("runt packet (no pacmark)\n");
+		goto fail_data;
+	}
+	if (rr_read(&pm, sizeof(pm)))
+		goto fail_io;
+
+	hdr.size -= sizeof(pm);
+
+	frag = rr_malloc(hdr.size + sizeof(*frag));
+	frag->next = NULL;
+	frag->length = hdr.size;
+	if (rr_read(frag->data, hdr.size))
+		goto fail_io;
+
+	ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid);
+	if (!ept) {
+		DIAG("no local ept for cid %08x\n", hdr.dst_cid);
+		kfree(frag);
+		goto done;
+	}
+
+	/* See if there is already a partial packet that matches our mid
+	 * and if so, append this fragment to that packet.
+	 */
+	mid = PACMARK_MID(pm);
+	list_for_each_entry(pkt, &ept->incomplete, list) {
+		if (pkt->mid == mid) {
+			pkt->last->next = frag;
+			pkt->last = frag;
+			pkt->length += frag->length;
+			if (PACMARK_LAST(pm)) {
+				list_del(&pkt->list);
+				goto packet_complete;
+			}
+			goto done;
+		}
+	}
+	/* This mid is new -- create a packet for it, and put it on
+	 * the incomplete list if this fragment is not a last fragment,
+	 * otherwise put it on the read queue.
+	 */
+	pkt = rr_malloc(sizeof(struct rr_packet));
+	pkt->first = frag;
+	pkt->last = frag;
+	memcpy(&pkt->hdr, &hdr, sizeof(hdr));
+	pkt->mid = mid;
+	pkt->length = frag->length;
+	if (!PACMARK_LAST(pm)) {
+		list_add_tail(&pkt->list, &ept->incomplete);
+		goto done;
+	}
+
+packet_complete:
+	spin_lock_irqsave(&ept->read_q_lock, flags);
+	if (ept->flags & MSM_RPC_ENABLE_RECEIVE) {
+		wake_lock(&ept->read_q_wake_lock);
+		list_add_tail(&pkt->list, &ept->read_q);
+		wake_up(&ept->wait_q);
+	} else {
+		pr_warning("smd_rpcrouter: Unexpected incoming data on %08x:%08x\n",
+				be32_to_cpu(ept->dst_prog),
+				be32_to_cpu(ept->dst_vers));
+	}
+	spin_unlock_irqrestore(&ept->read_q_lock, flags);
+done:
+
+	if (hdr.confirm_rx) {
+		union rr_control_msg msg;
+
+		msg.cmd = RPCROUTER_CTRL_CMD_RESUME_TX;
+		msg.cli.pid = hdr.dst_pid;
+		msg.cli.cid = hdr.dst_cid;
+
+		RR("x RESUME_TX id=%d:%08x\n", msg.cli.pid, msg.cli.cid);
+		rpcrouter_send_control_msg(&msg);
+	}
+
+	queue_work(rpcrouter_workqueue, &work_read_data);
+	return;
+
+fail_io:
+fail_data:
+	printk(KERN_ERR "rpc_router has died\n");
+	wake_unlock(&rpcrouter_wake_lock);
+}
+
+void msm_rpc_setup_req(struct rpc_request_hdr *hdr, uint32_t prog,
+		       uint32_t vers, uint32_t proc)
+{
+	memset(hdr, 0, sizeof(struct rpc_request_hdr));
+	hdr->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
+	hdr->rpc_vers = cpu_to_be32(2);
+	hdr->prog = cpu_to_be32(prog);
+	hdr->vers = cpu_to_be32(vers);
+	hdr->procedure = cpu_to_be32(proc);
+}
+
+struct msm_rpc_endpoint *msm_rpc_open(void)
+{
+	struct msm_rpc_endpoint *ept;
+
+	ept = msm_rpcrouter_create_local_endpoint(MKDEV(0, 0));
+	if (ept == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	return ept;
+}
+
+int msm_rpc_close(struct msm_rpc_endpoint *ept)
+{
+	return msm_rpcrouter_destroy_local_endpoint(ept);
+}
+EXPORT_SYMBOL(msm_rpc_close);
+
+static int msm_rpc_write_pkt(struct msm_rpc_endpoint *ept,
+			     struct rr_remote_endpoint *r_ept,
+			     struct rr_header *hdr,
+			     uint32_t pacmark,
+			     void *buffer, int count)
+{
+	DEFINE_WAIT(__wait);
+	unsigned long flags;
+	int needed;
+
+	for (;;) {
+		prepare_to_wait(&r_ept->quota_wait, &__wait,
+				TASK_INTERRUPTIBLE);
+		spin_lock_irqsave(&r_ept->quota_lock, flags);
+		if (r_ept->tx_quota_cntr < RPCROUTER_DEFAULT_RX_QUOTA)
+			break;
+		if (signal_pending(current) &&
+		    (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE)))
+			break;
+		spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+		schedule();
+	}
+	finish_wait(&r_ept->quota_wait, &__wait);
+
+	if (signal_pending(current) &&
+	    (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) {
+		spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+		return -ERESTARTSYS;
+	}
+	r_ept->tx_quota_cntr++;
+	if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA)
+		hdr->confirm_rx = 1;
+
+	spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+
+	spin_lock_irqsave(&smd_lock, flags);
+
+	needed = sizeof(*hdr) + hdr->size;
+	while (smd_write_avail(smd_channel) < needed) {
+		spin_unlock_irqrestore(&smd_lock, flags);
+		msleep(250);
+		spin_lock_irqsave(&smd_lock, flags);
+	}
+
+	/* TODO: deal with full fifo */
+	smd_write(smd_channel, hdr, sizeof(*hdr));
+	smd_write(smd_channel, &pacmark, sizeof(pacmark));
+	smd_write(smd_channel, buffer, count);
+
+	spin_unlock_irqrestore(&smd_lock, flags);
+
+	return 0;
+}
+
+int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count)
+{
+	struct rr_header hdr;
+	uint32_t pacmark;
+	uint32_t mid;
+	struct rpc_request_hdr *rq = buffer;
+	struct rr_remote_endpoint *r_ept;
+	int ret;
+	int total;
+
+	/* snoop the RPC packet and enforce permissions */
+
+	/* has to have at least the xid and type fields */
+	if (count < (sizeof(uint32_t) * 2)) {
+		printk(KERN_ERR "rr_write: rejecting runt packet\n");
+		return -EINVAL;
+	}
+
+	if (rq->type == 0) {
+		/* RPC CALL */
+		if (count < (sizeof(uint32_t) * 6)) {
+			printk(KERN_ERR
+			       "rr_write: rejecting runt call packet\n");
+			return -EINVAL;
+		}
+		if (ept->dst_pid == 0xffffffff) {
+			printk(KERN_ERR "rr_write: not connected\n");
+			return -ENOTCONN;
+		}
+
+#if !defined(CONFIG_MSM_LEGACY_7X00A_AMSS)
+		if ((ept->dst_prog != rq->prog) ||
+			!msm_rpc_is_compatible_version(
+					be32_to_cpu(ept->dst_vers),
+					be32_to_cpu(rq->vers))) {
+#else
+		if (ept->dst_prog != rq->prog || ept->dst_vers != rq->vers) {
+#endif
+			printk(KERN_ERR
+			       "rr_write: cannot write to %08x:%d "
+			       "(bound to %08x:%d)\n",
+			       be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
+			       be32_to_cpu(ept->dst_prog),
+			       be32_to_cpu(ept->dst_vers));
+			return -EINVAL;
+		}
+		hdr.dst_pid = ept->dst_pid;
+		hdr.dst_cid = ept->dst_cid;
+		IO("CALL on ept %p to %08x:%08x @ %d:%08x (%d bytes) (xid %x proc %x)\n",
+		   ept,
+		   be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
+		   ept->dst_pid, ept->dst_cid, count,
+		   be32_to_cpu(rq->xid), be32_to_cpu(rq->procedure));
+	} else {
+		/* RPC REPLY */
+		/* TODO: locking */
+		for (ret = 0; ret < MAX_REPLY_ROUTE; ret++)
+			if (ept->rroute[ret].xid == rq->xid) {
+				if (ept->rroute[ret].pid == 0xffffffff)
+					continue;
+				hdr.dst_pid = ept->rroute[ret].pid;
+				hdr.dst_cid = ept->rroute[ret].cid;
+				/* consume this reply */
+				ept->rroute[ret].pid = 0xffffffff;
+				goto found_rroute;
+			}
+
+		printk(KERN_ERR "rr_write: rejecting packet w/ bad xid\n");
+		return -EINVAL;
+
+found_rroute:
+		IO("REPLY on ept %p to xid=%d @ %d:%08x (%d bytes)\n",
+		   ept,
+		   be32_to_cpu(rq->xid), hdr.dst_pid, hdr.dst_cid, count);
+	}
+
+	r_ept = rpcrouter_lookup_remote_endpoint(hdr.dst_cid);
+
+	if (!r_ept) {
+		printk(KERN_ERR
+			"msm_rpc_write(): No route to ept "
+			"[PID %x CID %x]\n", hdr.dst_pid, hdr.dst_cid);
+		return -EHOSTUNREACH;
+	}
+
+	/* Create routing header */
+	hdr.type = RPCROUTER_CTRL_CMD_DATA;
+	hdr.version = RPCROUTER_VERSION;
+	hdr.src_pid = ept->pid;
+	hdr.src_cid = ept->cid;
+
+	total = count;
+
+	mid = atomic_add_return(1, &next_mid) & 0xFF;
+
+	while (count > 0) {
+		unsigned xfer;
+
+		if (count > RPCROUTER_DATASIZE_MAX)
+			xfer = RPCROUTER_DATASIZE_MAX;
+		else
+			xfer = count;
+
+		hdr.confirm_rx = 0;
+		hdr.size = xfer + sizeof(uint32_t);
+
+		/* total == count -> must be first packet 
+		 * xfer == count -> must be last packet
+		 */
+		pacmark = PACMARK(xfer, mid, (total == count), (xfer == count));
+
+		ret = msm_rpc_write_pkt(ept, r_ept, &hdr, pacmark, buffer, xfer);
+		if (ret < 0)
+			return ret;
+
+		buffer += xfer;
+		count -= xfer;
+	}
+
+	return total;
+}
+EXPORT_SYMBOL(msm_rpc_write);
+
+/*
+ * NOTE: It is the responsibility of the caller to kfree buffer
+ */
+int msm_rpc_read(struct msm_rpc_endpoint *ept, void **buffer,
+		 unsigned user_len, long timeout)
+{
+	struct rr_fragment *frag, *next;
+	char *buf;
+	int rc;
+
+	rc = __msm_rpc_read(ept, &frag, user_len, timeout);
+	if (rc <= 0)
+		return rc;
+
+	/* single-fragment messages conveniently can be
+	 * returned as-is (the buffer is at the front)
+	 */
+	if (frag->next == 0) {
+		*buffer = (void*) frag;
+		return rc;
+	}
+
+	/* multi-fragment messages, we have to do it the
+	 * hard way, which is rather disgusting right now
+	 */
+	buf = rr_malloc(rc);
+	*buffer = buf;
+
+	while (frag != NULL) {
+		memcpy(buf, frag->data, frag->length);
+		next = frag->next;
+		buf += frag->length;
+		kfree(frag);
+		frag = next;
+	}
+
+	return rc;
+}
+
+int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
+		 void *_request, int request_size,
+		 long timeout)
+{
+	return msm_rpc_call_reply(ept, proc,
+				  _request, request_size,
+				  NULL, 0, timeout);
+}
+EXPORT_SYMBOL(msm_rpc_call);
+
+int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
+		       void *_request, int request_size,
+		       void *_reply, int reply_size,
+		       long timeout)
+{
+	struct rpc_request_hdr *req = _request;
+	struct rpc_reply_hdr *reply;
+	int rc;
+
+	if (request_size < sizeof(*req))
+		return -ETOOSMALL;
+
+	if (ept->dst_pid == 0xffffffff)
+		return -ENOTCONN;
+
+	/* We can't use msm_rpc_setup_req() here, because dst_prog and
+	 * dst_vers here are already in BE.
+	 */
+	memset(req, 0, sizeof(*req));
+	req->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
+	req->rpc_vers = cpu_to_be32(2);
+	req->prog = ept->dst_prog;
+	req->vers = ept->dst_vers;
+	req->procedure = cpu_to_be32(proc);
+
+	/* Allow replys to be added to the queue */
+	ept->flags |= MSM_RPC_ENABLE_RECEIVE;
+
+	rc = msm_rpc_write(ept, req, request_size);
+	if (rc < 0)
+		goto error;
+
+	for (;;) {
+		rc = msm_rpc_read(ept, (void*) &reply, -1, timeout);
+		if (rc < 0)
+			goto error;
+		if (rc < (3 * sizeof(uint32_t))) {
+			rc = -EIO;
+			break;
+		}
+		/* we should not get CALL packets -- ignore them */
+		if (reply->type == 0) {
+			kfree(reply);
+			continue;
+		}
+		/* If an earlier call timed out, we could get the (no
+		 * longer wanted) reply for it.  Ignore replies that
+		 * we don't expect.
+		 */
+		if (reply->xid != req->xid) {
+			kfree(reply);
+			continue;
+		}
+		if (reply->reply_stat != 0) {
+			rc = -EPERM;
+			break;
+		}
+		if (reply->data.acc_hdr.accept_stat != 0) {
+			rc = -EINVAL;
+			break;
+		}
+		if (_reply == NULL) {
+			rc = 0;
+			break;
+		}
+		if (rc > reply_size) {
+			rc = -ENOMEM;
+		} else {
+			memcpy(_reply, reply, rc);
+		}
+		break;
+	}
+	kfree(reply);
+error:
+	ept->flags &= ~MSM_RPC_ENABLE_RECEIVE;
+	wake_unlock(&ept->read_q_wake_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_call_reply);
+
+
+static inline int ept_packet_available(struct msm_rpc_endpoint *ept)
+{
+	unsigned long flags;
+	int ret;
+	spin_lock_irqsave(&ept->read_q_lock, flags);
+	ret = !list_empty(&ept->read_q);
+	spin_unlock_irqrestore(&ept->read_q_lock, flags);
+	return ret;
+}
+
+int __msm_rpc_read(struct msm_rpc_endpoint *ept,
+		   struct rr_fragment **frag_ret,
+		   unsigned len, long timeout)
+{
+	struct rr_packet *pkt;
+	struct rpc_request_hdr *rq;
+	DEFINE_WAIT(__wait);
+	unsigned long flags;
+	int rc;
+
+	IO("READ on ept %p\n", ept);
+
+	if (ept->flags & MSM_RPC_UNINTERRUPTIBLE) {
+		if (timeout < 0) {
+			wait_event(ept->wait_q, ept_packet_available(ept));
+		} else {
+			rc = wait_event_timeout(
+				ept->wait_q, ept_packet_available(ept),
+				timeout);
+			if (rc == 0)
+				return -ETIMEDOUT;
+		}
+	} else {
+		if (timeout < 0) {
+			rc = wait_event_interruptible(
+				ept->wait_q, ept_packet_available(ept));
+			if (rc < 0)
+				return rc;
+		} else {
+			rc = wait_event_interruptible_timeout(
+				ept->wait_q, ept_packet_available(ept),
+				timeout);
+			if (rc == 0)
+				return -ETIMEDOUT;
+		}
+	}
+
+	spin_lock_irqsave(&ept->read_q_lock, flags);
+	if (list_empty(&ept->read_q)) {
+		spin_unlock_irqrestore(&ept->read_q_lock, flags);
+		return -EAGAIN;
+	}
+	pkt = list_first_entry(&ept->read_q, struct rr_packet, list);
+	if (pkt->length > len) {
+		spin_unlock_irqrestore(&ept->read_q_lock, flags);
+		return -ETOOSMALL;
+	}
+	list_del(&pkt->list);
+	if (list_empty(&ept->read_q))
+		wake_unlock(&ept->read_q_wake_lock);
+	spin_unlock_irqrestore(&ept->read_q_lock, flags);
+
+	rc = pkt->length;
+
+	*frag_ret = pkt->first;
+	rq = (void*) pkt->first->data;
+	if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 0)) {
+		IO("READ on ept %p is a CALL on %08x:%08x proc %d xid %d\n",
+			ept, be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
+			be32_to_cpu(rq->procedure),
+			be32_to_cpu(rq->xid));
+		/* RPC CALL */
+		if (ept->rroute[ept->next_rroute].pid != 0xffffffff) {
+			printk(KERN_WARNING
+			       "rr_read: lost previous reply xid...\n");
+		}
+		/* TODO: locking? */
+		ept->rroute[ept->next_rroute].pid = pkt->hdr.src_pid;
+		ept->rroute[ept->next_rroute].cid = pkt->hdr.src_cid;
+		ept->rroute[ept->next_rroute].xid = rq->xid;
+		ept->next_rroute = (ept->next_rroute + 1) & (MAX_REPLY_ROUTE - 1);
+	}
+#if TRACE_RPC_MSG
+	else if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 1))
+		IO("READ on ept %p is a REPLY\n", ept);
+	else IO("READ on ept %p (%d bytes)\n", ept, rc);
+#endif
+
+	kfree(pkt);
+	return rc;
+}
+
+#if !defined(CONFIG_MSM_LEGACY_7X00A_AMSS)
+int msm_rpc_is_compatible_version(uint32_t server_version,
+				  uint32_t client_version)
+{
+	if ((server_version & RPC_VERSION_MODE_MASK) !=
+	    (client_version & RPC_VERSION_MODE_MASK))
+		return 0;
+
+	if (server_version & RPC_VERSION_MODE_MASK)
+		return server_version == client_version;
+
+	return ((server_version & RPC_VERSION_MAJOR_MASK) ==
+		(client_version & RPC_VERSION_MAJOR_MASK)) &&
+		((server_version & RPC_VERSION_MINOR_MASK) >=
+		(client_version & RPC_VERSION_MINOR_MASK));
+}
+EXPORT_SYMBOL(msm_rpc_is_compatible_version);
+
+static int msm_rpc_get_compatible_server(uint32_t prog,
+					uint32_t ver,
+					uint32_t *found_vers)
+{
+	struct rr_server *server;
+	unsigned long     flags;
+	if (found_vers == NULL)
+		return 0;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if ((server->prog == prog) &&
+		    msm_rpc_is_compatible_version(server->vers, ver)) {
+			*found_vers = server->vers;
+			spin_unlock_irqrestore(&server_list_lock, flags);
+			return 0;
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	return -1;
+}
+#endif
+
+struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags)
+{
+	struct msm_rpc_endpoint *ept;
+	struct rr_server *server;
+
+#if !defined(CONFIG_MSM_LEGACY_7X00A_AMSS)
+	if (!(vers & RPC_VERSION_MODE_MASK)) {
+		uint32_t found_vers;
+		if (msm_rpc_get_compatible_server(prog, vers, &found_vers) < 0)
+			return ERR_PTR(-EHOSTUNREACH);
+		if (found_vers != vers) {
+			D("RPC using new version %08x:{%08x --> %08x}\n",
+			 	prog, vers, found_vers);
+			vers = found_vers;
+		}
+	}
+#endif
+
+	server = rpcrouter_lookup_server(prog, vers);
+	if (!server)
+		return ERR_PTR(-EHOSTUNREACH);
+
+	ept = msm_rpc_open();
+	if (IS_ERR(ept))
+		return ept;
+
+	ept->flags = flags;
+	ept->dst_pid = server->pid;
+	ept->dst_cid = server->cid;
+	ept->dst_prog = cpu_to_be32(prog);
+	ept->dst_vers = cpu_to_be32(vers);
+
+	return ept;
+}
+EXPORT_SYMBOL(msm_rpc_connect);
+
+uint32_t msm_rpc_get_vers(struct msm_rpc_endpoint *ept)
+{
+	return be32_to_cpu(ept->dst_vers);
+}
+EXPORT_SYMBOL(msm_rpc_get_vers);
+
+/* TODO: permission check? */
+int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
+			    uint32_t prog, uint32_t vers)
+{
+	int rc;
+	union rr_control_msg msg;
+	struct rr_server *server;
+
+	server = rpcrouter_create_server(ept->pid, ept->cid,
+					 prog, vers);
+	if (!server)
+		return -ENODEV;
+
+	msg.srv.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
+	msg.srv.pid = ept->pid;
+	msg.srv.cid = ept->cid;
+	msg.srv.prog = prog;
+	msg.srv.vers = vers;
+
+	RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+	   ept->pid, ept->cid, prog, vers);
+
+	rc = rpcrouter_send_control_msg(&msg);
+	if (rc < 0)
+		return rc;
+
+	ept->flags |= MSM_RPC_ENABLE_RECEIVE;
+	return 0;
+}
+
+/* TODO: permission check -- disallow unreg of somebody else's server */
+int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
+			      uint32_t prog, uint32_t vers)
+{
+	struct rr_server *server;
+	server = rpcrouter_lookup_server(prog, vers);
+
+	if (!server)
+		return -ENOENT;
+
+	ept->flags &= ~MSM_RPC_ENABLE_RECEIVE;
+	wake_unlock(&ept->read_q_wake_lock);
+	rpcrouter_destroy_server(server);
+	return 0;
+}
+
+static int msm_rpcrouter_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	/* Initialize what we need to start processing */
+	INIT_LIST_HEAD(&local_endpoints);
+	INIT_LIST_HEAD(&remote_endpoints);
+
+	init_waitqueue_head(&newserver_wait);
+	init_waitqueue_head(&smd_wait);
+	wake_lock_init(&rpcrouter_wake_lock, WAKE_LOCK_SUSPEND, "SMD_RPCCALL");
+
+	rpcrouter_workqueue = create_singlethread_workqueue("rpcrouter");
+	if (!rpcrouter_workqueue)
+		return -ENOMEM;
+
+	rc = msm_rpcrouter_init_devices();
+	if (rc < 0)
+		goto fail_destroy_workqueue;
+
+	/* Open up SMD channel 2 */
+	initialized = 0;
+	rc = smd_open("SMD_RPCCALL", &smd_channel, NULL, rpcrouter_smdnotify);
+	if (rc < 0)
+		goto fail_remove_devices;
+
+	queue_work(rpcrouter_workqueue, &work_read_data);
+	return 0;
+
+ fail_remove_devices:
+	msm_rpcrouter_exit_devices();
+ fail_destroy_workqueue:
+	destroy_workqueue(rpcrouter_workqueue);
+	return rc;
+}
+
+static int msm_rpcrouter_suspend(struct platform_device *pdev,
+					pm_message_t state)
+{
+	/* Wait until the worker thread has waited at least once so that it
+	 * gets a chance to release its wakelock.
+	 */
+	int wait_count = smd_wait_count;
+	if (!(smd_wait_count & 1))
+		wait_event(smd_wait, smd_wait_count != wait_count);
+	return 0;
+}
+
+static struct platform_driver msm_smd_channel2_driver = {
+	.probe		= msm_rpcrouter_probe,
+	.driver		= {
+			.name	= "SMD_RPCCALL",
+			.owner	= THIS_MODULE,
+	},
+	.suspend	= msm_rpcrouter_suspend,
+};
+
+static int __init rpcrouter_init(void)
+{
+	return platform_driver_register(&msm_smd_channel2_driver);
+}
+
+module_init(rpcrouter_init);
+MODULE_DESCRIPTION("MSM RPC Router");
+MODULE_AUTHOR("San Mehat <san@android.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h
new file mode 100644
index 0000000..2bf541a
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter.h
@@ -0,0 +1,202 @@
+/** arch/arm/mach-msm/smd_rpcrouter.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2008 QUALCOMM Incorporated.
+ * Author: San Mehat <san@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_SMD_RPCROUTER_H
+#define _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/wakelock.h>
+
+#include <mach/msm_smd.h>
+#include <mach/msm_rpcrouter.h>
+
+/* definitions for the R2R wire protcol */
+
+#define RPCROUTER_VERSION			1
+#define RPCROUTER_PROCESSORS_MAX		4
+#define RPCROUTER_MSGSIZE_MAX			512
+#define RPCROUTER_DATASIZE_MAX			500
+
+#define RPCROUTER_CLIENT_BCAST_ID		0xffffffff
+#define RPCROUTER_ROUTER_ADDRESS		0xfffffffe
+
+#define RPCROUTER_PID_LOCAL			1
+#define RPCROUTER_PID_REMOTE			0
+
+#define RPCROUTER_CTRL_CMD_DATA			1
+#define RPCROUTER_CTRL_CMD_HELLO		2
+#define RPCROUTER_CTRL_CMD_BYE			3
+#define RPCROUTER_CTRL_CMD_NEW_SERVER		4
+#define RPCROUTER_CTRL_CMD_REMOVE_SERVER	5
+#define RPCROUTER_CTRL_CMD_REMOVE_CLIENT	6
+#define RPCROUTER_CTRL_CMD_RESUME_TX		7
+#define RPCROUTER_CTRL_CMD_EXIT			8
+
+#define RPCROUTER_DEFAULT_RX_QUOTA	5
+
+union rr_control_msg {
+	uint32_t cmd;
+	struct {
+		uint32_t cmd;
+		uint32_t prog;
+		uint32_t vers;
+		uint32_t pid;
+		uint32_t cid;
+	} srv;
+	struct {
+		uint32_t cmd;
+		uint32_t pid;
+		uint32_t cid;
+	} cli;
+};
+
+struct rr_header {
+	uint32_t version;
+	uint32_t type;
+	uint32_t src_pid;
+	uint32_t src_cid;
+	uint32_t confirm_rx;
+	uint32_t size;
+	uint32_t dst_pid;
+	uint32_t dst_cid;
+};
+
+/* internals */
+
+#define RPCROUTER_MAX_REMOTE_SERVERS		100
+
+struct rr_fragment {
+	unsigned char data[RPCROUTER_MSGSIZE_MAX];
+	uint32_t length;
+	struct rr_fragment *next;
+};
+
+struct rr_packet {
+	struct list_head list;
+	struct rr_fragment *first;
+	struct rr_fragment *last;
+	struct rr_header hdr;
+	uint32_t mid;
+	uint32_t length;
+};
+
+#define PACMARK_LAST(n) ((n) & 0x80000000)
+#define PACMARK_MID(n)  (((n) >> 16) & 0xFF)
+#define PACMARK_LEN(n)  ((n) & 0xFFFF)
+
+static inline uint32_t PACMARK(uint32_t len, uint32_t mid, uint32_t first,
+			       uint32_t last)
+{
+	return (len & 0xFFFF) |
+	  ((mid & 0xFF) << 16) |
+	  ((!!first) << 30) |
+	  ((!!last) << 31);
+}
+
+struct rr_server {
+	struct list_head list;
+
+	uint32_t pid;
+	uint32_t cid;
+	uint32_t prog;
+	uint32_t vers;
+
+	dev_t device_number;
+	struct cdev cdev;
+	struct device *device;
+	struct rpcsvr_platform_device p_device;
+	char pdev_name[32];
+};
+
+struct rr_remote_endpoint {
+	uint32_t pid;
+	uint32_t cid;
+
+	int tx_quota_cntr;
+	spinlock_t quota_lock;
+	wait_queue_head_t quota_wait;
+
+	struct list_head list;
+};
+
+struct msm_reply_route {
+	uint32_t xid;
+	uint32_t pid;
+	uint32_t cid;
+	uint32_t unused;
+};
+
+#define MAX_REPLY_ROUTE 4
+
+struct msm_rpc_endpoint {
+	struct list_head list;
+
+	/* incomplete packets waiting for assembly */
+	struct list_head incomplete;
+
+	/* complete packets waiting to be read */
+	struct list_head read_q;
+	spinlock_t read_q_lock;
+	struct wake_lock read_q_wake_lock;
+	wait_queue_head_t wait_q;
+	unsigned flags;
+
+	/* endpoint address */
+	uint32_t pid;
+	uint32_t cid;
+
+	/* bound remote address
+	 * if not connected (dst_pid == 0xffffffff) RPC_CALL writes fail
+	 * RPC_CALLs must be to the prog/vers below or they will fail
+	 */
+	uint32_t dst_pid;
+	uint32_t dst_cid;
+	uint32_t dst_prog; /* be32 */
+	uint32_t dst_vers; /* be32 */
+
+	/* RPC_REPLY writes must be routed to the pid/cid of the
+	 * RPC_CALL they are in reply to.  Keep a cache of valid
+	 * xid/pid/cid groups.  pid 0xffffffff -> not valid.
+	 */
+	unsigned next_rroute;
+	struct msm_reply_route rroute[MAX_REPLY_ROUTE];
+
+	/* device node if this endpoint is accessed via userspace */
+	dev_t dev;
+};
+
+/* shared between smd_rpcrouter*.c */
+
+int __msm_rpc_read(struct msm_rpc_endpoint *ept,
+		   struct rr_fragment **frag,
+		   unsigned len, long timeout);
+
+struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev);
+int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept);
+
+int msm_rpcrouter_create_server_cdev(struct rr_server *server);
+int msm_rpcrouter_create_server_pdev(struct rr_server *server);
+
+int msm_rpcrouter_init_devices(void);
+void msm_rpcrouter_exit_devices(void);
+
+extern dev_t msm_rpcrouter_devno;
+extern struct class *msm_rpcrouter_class;
+#endif
diff --git a/arch/arm/mach-msm/smd_rpcrouter_device.c b/arch/arm/mach-msm/smd_rpcrouter_device.c
new file mode 100644
index 0000000..1ae83b5
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_device.c
@@ -0,0 +1,377 @@
+/* arch/arm/mach-msm/smd_rpcrouter_device.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009 QUALCOMM Incorporated.
+ * Author: San Mehat <san@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/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/msm_rpcrouter.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+#include "smd_rpcrouter.h"
+
+#define SAFETY_MEM_SIZE 65536
+
+/* Next minor # available for a remote server */
+static int next_minor = 1;
+
+struct class *msm_rpcrouter_class;
+dev_t msm_rpcrouter_devno;
+
+static struct cdev rpcrouter_cdev;
+static struct device *rpcrouter_device;
+
+static int rpcrouter_open(struct inode *inode, struct file *filp)
+{
+	int rc;
+	struct msm_rpc_endpoint *ept;
+
+	rc = nonseekable_open(inode, filp);
+	if (rc < 0)
+		return rc;
+
+	ept = msm_rpcrouter_create_local_endpoint(inode->i_rdev);
+	if (!ept)
+		return -ENOMEM;
+
+	filp->private_data = ept;
+	return 0;
+}
+
+static int rpcrouter_release(struct inode *inode, struct file *filp)
+{
+	struct msm_rpc_endpoint *ept;
+	ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+	return msm_rpcrouter_destroy_local_endpoint(ept);
+}
+
+static ssize_t rpcrouter_read(struct file *filp, char __user *buf,
+			      size_t count, loff_t *ppos)
+{
+	struct msm_rpc_endpoint *ept;
+	struct rr_fragment *frag, *next;
+	int rc;
+
+	ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+	rc = __msm_rpc_read(ept, &frag, count, -1);
+	if (rc < 0)
+		return rc;
+
+	count = rc;
+
+	while (frag != NULL) {		
+		if (copy_to_user(buf, frag->data, frag->length)) {
+			printk(KERN_ERR
+			       "rpcrouter: could not copy all read data to user!\n");
+			rc = -EFAULT;
+		}
+		buf += frag->length;
+		next = frag->next;
+		kfree(frag);
+		frag = next;
+	}
+
+	return rc;
+}
+
+static ssize_t rpcrouter_write(struct file *filp, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	struct msm_rpc_endpoint	*ept;
+	int rc = 0;
+	void *k_buffer;
+
+	ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+	/* A check for safety, this seems non-standard */
+	if (count > SAFETY_MEM_SIZE)
+		return -EINVAL;
+
+	k_buffer = kmalloc(count, GFP_KERNEL);
+	if (!k_buffer)
+		return -ENOMEM;
+
+	if (copy_from_user(k_buffer, buf, count)) {
+		rc = -EFAULT;
+		goto write_out_free;
+	}
+
+	rc = msm_rpc_write(ept, k_buffer, count);
+	if (rc < 0)
+		goto write_out_free;
+
+	rc = count;
+write_out_free:
+	kfree(k_buffer);
+	return rc;
+}
+
+static unsigned int rpcrouter_poll(struct file *filp,
+				   struct poll_table_struct *wait)
+{
+	struct msm_rpc_endpoint *ept;
+	unsigned mask = 0;
+	ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+	/* If there's data already in the read queue, return POLLIN.
+	 * Else, wait for the requested amount of time, and check again.
+	 */
+
+	if (!list_empty(&ept->read_q))
+		mask |= POLLIN;
+
+	if (!mask) {
+		poll_wait(filp, &ept->wait_q, wait);
+		if (!list_empty(&ept->read_q))
+			mask |= POLLIN;
+	}
+
+	return mask;
+}
+
+static long rpcrouter_ioctl(struct file *filp, unsigned int cmd,
+			    unsigned long arg)
+{
+	struct msm_rpc_endpoint *ept;
+	struct rpcrouter_ioctl_server_args server_args;
+	int rc = 0;
+	uint32_t n;
+
+	ept = (struct msm_rpc_endpoint *) filp->private_data;
+	switch (cmd) {
+
+	case RPC_ROUTER_IOCTL_GET_VERSION:
+		n = RPC_ROUTER_VERSION_V1;
+		rc = put_user(n, (unsigned int *) arg);
+		break;
+
+	case RPC_ROUTER_IOCTL_GET_MTU:
+		/* the pacmark word reduces the actual payload
+		 * possible per message
+		 */
+		n = RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t);
+		rc = put_user(n, (unsigned int *) arg);
+		break;
+
+	case RPC_ROUTER_IOCTL_REGISTER_SERVER:
+		rc = copy_from_user(&server_args, (void *) arg,
+				    sizeof(server_args));
+		if (rc < 0)
+			break;
+		msm_rpc_register_server(ept,
+					server_args.prog,
+					server_args.vers);
+		break;
+
+	case RPC_ROUTER_IOCTL_UNREGISTER_SERVER:
+		rc = copy_from_user(&server_args, (void *) arg,
+				    sizeof(server_args));
+		if (rc < 0)
+			break;
+
+		msm_rpc_unregister_server(ept,
+					  server_args.prog,
+					  server_args.vers);
+		break;
+
+	case RPC_ROUTER_IOCTL_GET_MINOR_VERSION:
+		n = MSM_RPC_GET_MINOR(msm_rpc_get_vers(ept));
+		rc = put_user(n, (unsigned int *)arg);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static struct file_operations rpcrouter_server_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = rpcrouter_open,
+	.release = rpcrouter_release,
+	.read	 = rpcrouter_read,
+	.write	 = rpcrouter_write,
+	.poll    = rpcrouter_poll,
+	.unlocked_ioctl	 = rpcrouter_ioctl,
+};
+
+static struct file_operations rpcrouter_router_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = rpcrouter_open,
+	.release = rpcrouter_release,
+	.read	 = rpcrouter_read,
+	.write	 = rpcrouter_write,
+	.poll    = rpcrouter_poll,
+	.unlocked_ioctl = rpcrouter_ioctl,
+};
+
+int msm_rpcrouter_create_server_cdev(struct rr_server *server)
+{
+	int rc;
+	uint32_t dev_vers;
+
+	if (next_minor == RPCROUTER_MAX_REMOTE_SERVERS) {
+		printk(KERN_ERR
+		       "rpcrouter: Minor numbers exhausted - Increase "
+		       "RPCROUTER_MAX_REMOTE_SERVERS\n");
+		return -ENOBUFS;
+	}
+
+#if !defined(CONFIG_MSM_LEGACY_7X00A_AMSS)
+	/* Servers with bit 31 set are remote msm servers with hashkey version.
+	 * Servers with bit 31 not set are remote msm servers with
+	 * backwards compatible version type in which case the minor number
+	 * (lower 16 bits) is set to zero.
+	 *
+	 */
+	if ((server->vers & RPC_VERSION_MODE_MASK))
+		dev_vers = server->vers;
+	else
+		dev_vers = server->vers & RPC_VERSION_MAJOR_MASK;
+#else
+	dev_vers = server->vers;
+#endif
+
+	server->device_number =
+		MKDEV(MAJOR(msm_rpcrouter_devno), next_minor++);
+
+	server->device =
+		device_create(msm_rpcrouter_class, rpcrouter_device,
+			      server->device_number, NULL, "%.8x:%.8x",
+			      server->prog, dev_vers);
+	if (IS_ERR(server->device)) {
+		printk(KERN_ERR
+		       "rpcrouter: Unable to create device (%ld)\n",
+		       PTR_ERR(server->device));
+		return PTR_ERR(server->device);;
+	}
+
+	cdev_init(&server->cdev, &rpcrouter_server_fops);
+	server->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&server->cdev, server->device_number, 1);
+	if (rc < 0) {
+		printk(KERN_ERR
+		       "rpcrouter: Unable to add chrdev (%d)\n", rc);
+		device_destroy(msm_rpcrouter_class, server->device_number);
+		return rc;
+	}
+	return 0;
+}
+
+/* for backward compatible version type (31st bit cleared)
+ * clearing minor number (lower 16 bits) in device name
+ * is neccessary for driver binding
+ */
+int msm_rpcrouter_create_server_pdev(struct rr_server *server)
+{
+	sprintf(server->pdev_name, "rs%.8x:%.8x",
+		server->prog,
+#if !defined(CONFIG_MSM_LEGACY_7X00A_AMSS)
+		(server->vers & RPC_VERSION_MODE_MASK) ? server->vers :
+		(server->vers & RPC_VERSION_MAJOR_MASK));
+#else
+		server->vers);
+#endif
+
+	server->p_device.base.id = -1;
+	server->p_device.base.name = server->pdev_name;
+
+	server->p_device.prog = server->prog;
+	server->p_device.vers = server->vers;
+
+	platform_device_register(&server->p_device.base);
+	return 0;
+}
+
+int msm_rpcrouter_init_devices(void)
+{
+	int rc;
+	int major;
+
+	/* Create the device nodes */
+	msm_rpcrouter_class = class_create(THIS_MODULE, "oncrpc");
+	if (IS_ERR(msm_rpcrouter_class)) {
+		rc = -ENOMEM;
+		printk(KERN_ERR
+		       "rpcrouter: failed to create oncrpc class\n");
+		goto fail;
+	}
+
+	rc = alloc_chrdev_region(&msm_rpcrouter_devno, 0,
+				 RPCROUTER_MAX_REMOTE_SERVERS + 1,
+				 "oncrpc");
+	if (rc < 0) {
+		printk(KERN_ERR
+		       "rpcrouter: Failed to alloc chardev region (%d)\n", rc);
+		goto fail_destroy_class;
+	}
+
+	major = MAJOR(msm_rpcrouter_devno);
+	rpcrouter_device = device_create(msm_rpcrouter_class, NULL,
+					 msm_rpcrouter_devno, NULL, "%.8x:%d",
+					 0, 0);
+	if (IS_ERR(rpcrouter_device)) {
+		rc = -ENOMEM;
+		goto fail_unregister_cdev_region;
+	}
+
+	cdev_init(&rpcrouter_cdev, &rpcrouter_router_fops);
+	rpcrouter_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&rpcrouter_cdev, msm_rpcrouter_devno, 1);
+	if (rc < 0)
+		goto fail_destroy_device;
+
+	return 0;
+
+fail_destroy_device:
+	device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
+fail_unregister_cdev_region:
+	unregister_chrdev_region(msm_rpcrouter_devno,
+				 RPCROUTER_MAX_REMOTE_SERVERS + 1);
+fail_destroy_class:
+	class_destroy(msm_rpcrouter_class);
+fail:
+	return rc;
+}
+
+void msm_rpcrouter_exit_devices(void)
+{
+	cdev_del(&rpcrouter_cdev);
+	device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
+	unregister_chrdev_region(msm_rpcrouter_devno,
+				 RPCROUTER_MAX_REMOTE_SERVERS + 1);
+	class_destroy(msm_rpcrouter_class);
+}
+
diff --git a/arch/arm/mach-msm/smd_rpcrouter_servers.c b/arch/arm/mach-msm/smd_rpcrouter_servers.c
new file mode 100644
index 0000000..8396002
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_servers.c
@@ -0,0 +1,230 @@
+/* arch/arm/mach-msm/rpc_servers.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Iliyan Malchev <ibm@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/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/wakelock.h>
+
+#include <linux/msm_rpcrouter.h>
+#include <linux/uaccess.h>
+
+#include <mach/msm_rpcrouter.h>
+#include "smd_rpcrouter.h"
+
+static struct msm_rpc_endpoint *endpoint;
+
+#define FLAG_REGISTERED 0x0001
+
+static LIST_HEAD(rpc_server_list);
+static DEFINE_MUTEX(rpc_server_list_lock);
+static int rpc_servers_active;
+static struct wake_lock rpc_servers_wake_lock;
+
+static void rpc_server_register(struct msm_rpc_server *server)
+{
+	int rc;
+	rc = msm_rpc_register_server(endpoint, server->prog, server->vers);
+	if (rc < 0)
+		printk(KERN_ERR "[rpcserver] error registering %p @ %08x:%d\n",
+		       server, server->prog, server->vers);
+}
+
+static struct msm_rpc_server *rpc_server_find(uint32_t prog, uint32_t vers)
+{
+	struct msm_rpc_server *server;
+
+	mutex_lock(&rpc_server_list_lock);
+	list_for_each_entry(server, &rpc_server_list, list) {
+		if ((server->prog == prog) &&
+#if !defined(CONFIG_MSM_LEGACY_7X00A_AMSS)
+		    msm_rpc_is_compatible_version(server->vers, vers)) {
+#else
+		    server->vers == vers) {
+#endif
+			mutex_unlock(&rpc_server_list_lock);
+			return server;
+		}
+	}
+	mutex_unlock(&rpc_server_list_lock);
+	return NULL;
+}
+
+static void rpc_server_register_all(void)
+{
+	struct msm_rpc_server *server;
+
+	mutex_lock(&rpc_server_list_lock);
+	list_for_each_entry(server, &rpc_server_list, list) {
+		if (!(server->flags & FLAG_REGISTERED)) {
+			rpc_server_register(server);
+			server->flags |= FLAG_REGISTERED;
+		}
+	}
+	mutex_unlock(&rpc_server_list_lock);
+}
+
+int msm_rpc_create_server(struct msm_rpc_server *server)
+{
+	/* make sure we're in a sane state first */
+	server->flags = 0;
+	INIT_LIST_HEAD(&server->list);
+
+	mutex_lock(&rpc_server_list_lock);
+	list_add(&server->list, &rpc_server_list);
+	if (rpc_servers_active) {
+		rpc_server_register(server);
+		server->flags |= FLAG_REGISTERED;
+	}
+	mutex_unlock(&rpc_server_list_lock);
+
+	return 0;
+}
+
+static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client,
+					uint32_t xid, uint32_t accept_status)
+{
+	int rc = 0;
+	uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
+	struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
+
+	reply->xid = cpu_to_be32(xid);
+	reply->type = cpu_to_be32(1); /* reply */
+	reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+	reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+	reply->data.acc_hdr.verf_flavor = 0;
+	reply->data.acc_hdr.verf_length = 0;
+
+	rc = msm_rpc_write(client, reply_buf, sizeof(reply_buf));
+	if (rc < 0)
+		printk(KERN_ERR
+		       "%s: could not write response: %d\n",
+		       __FUNCTION__, rc);
+
+	return rc;
+}
+
+static int rpc_servers_thread(void *data)
+{
+	void *buffer;
+	struct rpc_request_hdr *req;
+	struct msm_rpc_server *server;
+	int rc;
+
+	for (;;) {
+		wake_unlock(&rpc_servers_wake_lock);
+		rc = wait_event_interruptible(endpoint->wait_q,
+						!list_empty(&endpoint->read_q));
+		wake_lock(&rpc_servers_wake_lock);
+		rc = msm_rpc_read(endpoint, &buffer, -1, -1);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: could not read: %d\n",
+			       __FUNCTION__, rc);
+			break;
+		}
+		req = (struct rpc_request_hdr *)buffer;
+
+		req->type = be32_to_cpu(req->type);
+		req->xid = be32_to_cpu(req->xid);
+		req->rpc_vers = be32_to_cpu(req->rpc_vers);
+		req->prog = be32_to_cpu(req->prog);
+		req->vers = be32_to_cpu(req->vers);
+		req->procedure = be32_to_cpu(req->procedure);
+
+		server = rpc_server_find(req->prog, req->vers);
+
+		if (req->rpc_vers != 2)
+			continue;
+		if (req->type != 0)
+			continue;
+		if (!server) {
+			rpc_send_accepted_void_reply(
+				endpoint, req->xid,
+				RPC_ACCEPTSTAT_PROG_UNAVAIL);
+			continue;
+		}
+
+		rc = server->rpc_call(server, req, rc);
+
+		switch (rc) {
+		case 0:
+			rpc_send_accepted_void_reply(
+				endpoint, req->xid,
+				RPC_ACCEPTSTAT_SUCCESS);
+			break;
+		default:
+			rpc_send_accepted_void_reply(
+				endpoint, req->xid,
+				RPC_ACCEPTSTAT_PROG_UNAVAIL);
+			break;
+		}
+
+		kfree(buffer);
+	}
+
+	do_exit(0);
+}
+
+static int rpcservers_probe(struct platform_device *pdev)
+{
+	struct task_struct *server_thread;
+
+	endpoint = msm_rpc_open();
+	if (IS_ERR(endpoint))
+		return PTR_ERR(endpoint);
+
+	/* we're online -- register any servers installed beforehand */
+	rpc_servers_active = 1;
+	rpc_server_register_all();
+
+	/* start the kernel thread */
+	server_thread = kthread_run(rpc_servers_thread, NULL, "krpcserversd");
+	if (IS_ERR(server_thread))
+		return PTR_ERR(server_thread);
+
+	return 0;
+}
+
+static struct platform_driver rpcservers_driver = {
+	.probe	= rpcservers_probe,
+	.driver	= {
+		.name	= "oncrpc_router",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init rpc_servers_init(void)
+{
+	wake_lock_init(&rpc_servers_wake_lock, WAKE_LOCK_SUSPEND, "rpc_server");
+	return platform_driver_register(&rpcservers_driver);
+}
+
+module_init(rpc_servers_init);
+
+MODULE_DESCRIPTION("MSM RPC Servers");
+MODULE_AUTHOR("Iliyan Malchev <ibm@android.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
new file mode 100644
index 0000000..8715544
--- /dev/null
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -0,0 +1,229 @@
+/* arch/arm/mach-msm/smd_tty.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 <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
+#include <mach/msm_smd.h>
+
+#define MAX_SMD_TTYS 32
+
+static DEFINE_MUTEX(smd_tty_lock);
+
+struct smd_tty_info {
+	smd_channel_t *ch;
+	struct tty_struct *tty;
+	struct wake_lock wake_lock;
+	int open_count;
+};
+
+static struct smd_tty_info smd_tty[MAX_SMD_TTYS];
+
+static const struct smd_tty_channel_desc smd_default_tty_channels[] = {
+	{ .id = 0, .name = "SMD_DS" },
+	{ .id = 27, .name = "SMD_GPSNMEA" },
+};
+
+static const struct smd_tty_channel_desc *smd_tty_channels =
+		smd_default_tty_channels;
+static int smd_tty_channels_len = ARRAY_SIZE(smd_default_tty_channels);
+
+int smd_set_channel_list(const struct smd_tty_channel_desc *channels, int len)
+{
+	smd_tty_channels = channels;
+	smd_tty_channels_len = len;
+	return 0;
+}
+
+static void smd_tty_notify(void *priv, unsigned event)
+{
+	unsigned char *ptr;
+	int avail;
+	struct smd_tty_info *info = priv;
+	struct tty_struct *tty = info->tty;
+
+	if (!tty)
+		return;
+
+	if (event != SMD_EVENT_DATA)
+		return;
+
+	for (;;) {
+		if (test_bit(TTY_THROTTLED, &tty->flags)) break;
+		avail = smd_read_avail(info->ch);
+		if (avail == 0) break;
+
+		avail = tty_prepare_flip_string(tty, &ptr, avail);
+
+		if (smd_read(info->ch, ptr, avail) != avail) {
+			/* shouldn't be possible since we're in interrupt
+			** context here and nobody else could 'steal' our
+			** characters.
+			*/
+			printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!");
+		}
+
+		wake_lock_timeout(&info->wake_lock, HZ / 2);
+		tty_flip_buffer_push(tty);
+	}
+
+	/* XXX only when writable and necessary */
+	tty_wakeup(tty);
+}
+
+static int smd_tty_open(struct tty_struct *tty, struct file *f)
+{
+	int res = 0;
+	int n = tty->index;
+	struct smd_tty_info *info;
+	const char *name = NULL;
+	int i;
+
+	for (i = 0; i < smd_tty_channels_len; i++) {
+		if (smd_tty_channels[i].id == n) {
+			name = smd_tty_channels[i].name;
+			break;
+		}
+	}
+	if (!name)
+		return -ENODEV;
+
+	info = smd_tty + n;
+
+	mutex_lock(&smd_tty_lock);
+	wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND, name);
+	tty->driver_data = info;
+
+	if (info->open_count++ == 0) {
+		info->tty = tty;
+		if (info->ch) {
+			smd_kick(info->ch);
+		} else {
+			res = smd_open(name, &info->ch, info, smd_tty_notify);
+		}
+	}
+	mutex_unlock(&smd_tty_lock);
+
+	return res;
+}
+
+static void smd_tty_close(struct tty_struct *tty, struct file *f)
+{
+	struct smd_tty_info *info = tty->driver_data;
+
+	if (info == 0)
+		return;
+
+	mutex_lock(&smd_tty_lock);
+	if (--info->open_count == 0) {
+		info->tty = 0;
+		tty->driver_data = 0;
+		wake_lock_destroy(&info->wake_lock);
+		if (info->ch) {
+			smd_close(info->ch);
+			info->ch = 0;
+		}
+	}
+	mutex_unlock(&smd_tty_lock);
+}
+
+static int smd_tty_write(struct tty_struct *tty, const unsigned char *buf, int len)
+{
+	struct smd_tty_info *info = tty->driver_data;
+	int avail;
+
+	/* if we're writing to a packet channel we will
+	** never be able to write more data than there
+	** is currently space for
+	*/
+	avail = smd_write_avail(info->ch);
+	if (len > avail)
+		len = avail;
+
+	return smd_write(info->ch, buf, len);
+}
+
+static int smd_tty_write_room(struct tty_struct *tty)
+{
+	struct smd_tty_info *info = tty->driver_data;
+	return smd_write_avail(info->ch);
+}
+
+static int smd_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct smd_tty_info *info = tty->driver_data;
+	return smd_read_avail(info->ch);
+}
+
+static void smd_tty_unthrottle(struct tty_struct *tty)
+{
+	struct smd_tty_info *info = tty->driver_data;
+	smd_kick(info->ch);
+}
+
+static struct tty_operations smd_tty_ops = {
+	.open = smd_tty_open,
+	.close = smd_tty_close,
+	.write = smd_tty_write,
+	.write_room = smd_tty_write_room,
+	.chars_in_buffer = smd_tty_chars_in_buffer,
+	.unthrottle = smd_tty_unthrottle,
+};
+
+static struct tty_driver *smd_tty_driver;
+
+static int __init smd_tty_init(void)
+{
+	int ret, i;
+
+	smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
+	if (smd_tty_driver == 0)
+		return -ENOMEM;
+
+	smd_tty_driver->owner = THIS_MODULE;
+	smd_tty_driver->driver_name = "smd_tty_driver";
+	smd_tty_driver->name = "smd";
+	smd_tty_driver->major = 0;
+	smd_tty_driver->minor_start = 0;
+	smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	smd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+	smd_tty_driver->init_termios = tty_std_termios;
+	smd_tty_driver->init_termios.c_iflag = 0;
+	smd_tty_driver->init_termios.c_oflag = 0;
+	smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+	smd_tty_driver->init_termios.c_lflag = 0;
+	smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(smd_tty_driver, &smd_tty_ops);
+
+	ret = tty_register_driver(smd_tty_driver);
+	if (ret) return ret;
+
+	for (i = 0; i < smd_tty_channels_len; i++)
+		tty_register_device(smd_tty_driver, smd_tty_channels[i].id, 0);
+
+	return 0;
+}
+
+module_init(smd_tty_init);
diff --git a/arch/arm/mach-msm/ssbi.c b/arch/arm/mach-msm/ssbi.c
new file mode 100644
index 0000000..b9cefa2
--- /dev/null
+++ b/arch/arm/mach-msm/ssbi.c
@@ -0,0 +1,304 @@
+/* arch/arm/mach-msm/ssbi.c
+ *
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010, Google Inc.
+ *
+ * Original authors: Code Aurura Forum
+ *
+ * Author: Dima Zavin <dima@android.com>
+ *  - Largely rewritten from original to not be an i2c driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <mach/msm_ssbi.h>
+#include <mach/remote_spinlock.h>
+
+/* SSBI 2.0 controller registers */
+#define SSBI2_CTL			0x0000
+#define SSBI2_RESET			0x0004
+#define SSBI2_CMD			0x0008
+#define SSBI2_RD			0x0010
+#define SSBI2_STATUS			0x0014
+#define SSBI2_PRIORITIES		0x0018
+#define SSBI2_MODE2			0x001C
+
+/* SSBI_CMD fields */
+#define SSBI_CMD_SEND_TERM_SYM		(1 << 27)
+#define SSBI_CMD_WAKEUP_SLAVE		(1 << 26)
+#define SSBI_CMD_USE_ENABLE		(1 << 25)
+#define SSBI_CMD_RDWRN			(1 << 24)
+
+/* SSBI_STATUS fields */
+#define SSBI_STATUS_DATA_IN		(1 << 4)
+#define SSBI_STATUS_RD_CLOBBERED	(1 << 3)
+#define SSBI_STATUS_RD_READY		(1 << 2)
+#define SSBI_STATUS_READY		(1 << 1)
+#define SSBI_STATUS_MCHN_BUSY		(1 << 0)
+
+/* SSBI_RD fields */
+#define SSBI_RD_USE_ENABLE		(1 << 25)
+#define SSBI_RD_RDWRN			(1 << 24)
+
+/* SSBI_MODE2 fields */
+#define SSBI_MODE2_SSBI2_MODE		(1 << 0)
+
+#define SSBI_TIMEOUT_US			100
+
+struct msm_ssbi {
+	struct device		*dev;
+	struct device		*slave;
+	void __iomem		*base;
+	remote_spinlock_t	rspin_lock;
+};
+
+#define to_msm_ssbi(dev)	platform_get_drvdata(to_platform_device(dev))
+
+static inline u32 ssbi_readl(struct msm_ssbi *ssbi, unsigned long reg)
+{
+	return readl(ssbi->base + reg);
+}
+
+static inline void ssbi_writel(struct msm_ssbi *ssbi, u32 val,
+			       unsigned long reg)
+{
+	writel(val, ssbi->base + reg);
+}
+
+//poll_for_device_ready === SSBI_STATUS_READY
+//poll_for_transfer_completed === SSBI_STATUS_MCHN_BUSY
+//poll_for_read_completed === SSBI_STATUS_RD_READY
+static int ssbi_wait_mask(struct msm_ssbi *ssbi, u32 set_mask, u32 clr_mask)
+{
+	u32 timeout = SSBI_TIMEOUT_US;
+	u32 val;
+
+	while (timeout--) {
+		val = ssbi_readl(ssbi, SSBI2_STATUS);
+		if (((val & set_mask) == set_mask) && ((val & clr_mask) == 0))
+			return 0;
+		udelay(1);
+	}
+
+	dev_err(ssbi->dev, "%s: timeout (status %x set_mask %x clr_mask %x)\n",
+		__func__, ssbi_readl(ssbi, SSBI2_STATUS), set_mask, clr_mask);
+	return -ETIMEDOUT;
+}
+
+int msm_ssbi_read(struct device *dev, u16 addr, u8 *buf, int len)
+{
+	struct msm_ssbi *ssbi = to_msm_ssbi(dev);
+	unsigned long flags;
+	u32 read_cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16);
+	u32 mode2;
+	int ret = 0;
+
+	BUG_ON(ssbi->dev != dev);
+
+	remote_spin_lock_irqsave(&ssbi->rspin_lock, flags);
+
+	mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
+	if (mode2 & SSBI_MODE2_SSBI2_MODE) {
+		mode2 = (mode2 & 0xf) | (((addr >> 8) & 0x7f) << 4);
+		ssbi_writel(ssbi, mode2, SSBI2_MODE2);
+	}
+
+	while (len) {
+		ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0);
+		if (ret)
+			goto err;
+
+		ssbi_writel(ssbi, read_cmd, SSBI2_CMD);
+		ret = ssbi_wait_mask(ssbi, SSBI_STATUS_RD_READY, 0);
+		if (ret)
+			goto err;
+		*buf++ = ssbi_readl(ssbi, SSBI2_RD) & 0xff;
+		len--;
+	}
+
+err:
+	remote_spin_unlock_irqrestore(&ssbi->rspin_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(msm_ssbi_read);
+
+int msm_ssbi_write(struct device *dev, u16 addr, u8 *buf, int len)
+{
+	struct msm_ssbi *ssbi = to_msm_ssbi(dev);
+	unsigned long flags;
+	u32 mode2;
+	int ret = 0;
+
+	BUG_ON(ssbi->dev != dev);
+
+	remote_spin_lock_irqsave(&ssbi->rspin_lock, flags);
+
+	mode2 = readl(ssbi->base + SSBI2_MODE2);
+	if (mode2 & SSBI_MODE2_SSBI2_MODE) {
+		mode2 = (mode2 & 0xf) | (((addr >> 8) & 0x7f) << 4);
+		ssbi_writel(ssbi, mode2, SSBI2_MODE2);
+	}
+
+	while (len) {
+		ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0);
+		if (ret)
+			goto err;
+
+		ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf, SSBI2_CMD);
+		ret = ssbi_wait_mask(ssbi, 0, SSBI_STATUS_MCHN_BUSY);
+		if (ret)
+			goto err;
+		buf++;
+		len--;
+	}
+
+err:
+	remote_spin_unlock_irqrestore(&ssbi->rspin_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(msm_ssbi_write);
+
+static int __init msm_ssbi_add_slave(struct msm_ssbi *ssbi,
+				     struct msm_ssbi_slave_info *slave)
+{
+	struct platform_device *slave_pdev;
+	struct resource slave_irq_res;
+	int ret;
+
+	if (ssbi->slave) {
+		pr_err("%s: slave already attached??\n", __func__);
+		return -EBUSY;
+	}
+
+	slave_pdev = platform_device_alloc(slave->name, -1);
+	if (!slave_pdev) {
+		pr_err("%s: cannot allocate pdev for slave '%s'", __func__,
+		       slave->name);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	slave_pdev->dev.parent = ssbi->dev;
+	slave_pdev->dev.platform_data = slave->platform_data;
+
+	memset(&slave_irq_res, 0, sizeof(struct resource));
+	slave_irq_res.start = slave->irq;
+	slave_irq_res.end = slave->irq;
+	slave_irq_res.flags = IORESOURCE_IRQ;
+	ret = platform_device_add_resources(slave_pdev, &slave_irq_res, 1);
+	if (ret) {
+		pr_err("%s: can't add irq resource for '%s'\n", __func__,
+		       slave->name);
+		goto err;
+	}
+
+	ret = platform_device_add(slave_pdev);
+	if (ret) {
+		pr_err("%s: cannot add slave platform device for '%s'\n",
+		       __func__, slave->name);
+		goto err;
+	}
+
+	ssbi->slave = &slave_pdev->dev;
+	return 0;
+
+err:
+	if (slave_pdev)
+		platform_device_put(slave_pdev);
+	return ret;
+}
+
+static int __init msm_ssbi_probe(struct platform_device *pdev)
+{
+	struct msm_ssbi_platform_data *pdata = pdev->dev.platform_data;
+	struct resource *mem_res;
+	struct msm_ssbi *ssbi;
+	int ret = 0;
+
+	if (!pdata) {
+		pr_err("%s: missing platform data\n", __func__);
+		return -EINVAL;
+	}
+
+	ssbi = kzalloc(sizeof(struct msm_ssbi), GFP_KERNEL);
+	if (!ssbi) {
+		pr_err("%s: cannot allocate ssbi_data\n", __func__);
+		return -ENOMEM;
+	}
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem_res) {
+		pr_err("%s: missing mem resource\n", __func__);
+		ret = -EINVAL;
+		goto err_get_mem_res;
+	}
+
+	ssbi->base = ioremap(mem_res->start, resource_size(mem_res));
+	if (!ssbi->base) {
+		pr_err("%s: ioremap of 0x%p failed\n", __func__,
+		       (void *)mem_res->start);
+		ret = -EINVAL;
+		goto err_ioremap;
+	}
+	ssbi->dev = &pdev->dev;
+	platform_set_drvdata(pdev, ssbi);
+
+	ret = remote_spin_lock_init(&ssbi->rspin_lock, pdata->rspinlock_name);
+	if (ret) {
+		pr_err("%s: cannot init remote spinlock '%s'\n", __func__,
+		       pdata->rspinlock_name);
+		goto err_remote_spinlock_init;
+	}
+
+	ret = msm_ssbi_add_slave(ssbi, &pdata->slave);
+	if (ret)
+		goto err_ssbi_add_slave;
+
+	pr_info("msm_ssbi: io=%08x rsl='%s'\n", mem_res->start,
+		pdata->rspinlock_name);
+
+	return 0;
+
+err_remote_spinlock_init:
+	platform_set_drvdata(pdev, NULL);
+err_ssbi_add_slave:
+	iounmap(ssbi->base);
+err_ioremap:
+err_get_mem_res:
+	kfree(ssbi);
+	return ret;
+}
+
+static struct platform_driver msm_ssbi_driver = {
+	.probe		= msm_ssbi_probe,
+	.driver		= {
+		.name	= "msm_ssbi",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init msm_ssbi_init(void)
+{
+	return platform_driver_register(&msm_ssbi_driver);
+}
+
+postcore_initcall(msm_ssbi_init);
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index dec5ca6..07d456f 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -25,10 +25,15 @@
 #include <asm/mach/time.h>
 #include <mach/msm_iomap.h>
 
-#ifndef MSM_DGT_BASE
-#define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
-#endif
-#define MSM_DGT_SHIFT (5)
+#include "smd_private.h"
+
+enum {
+	MSM_TIMER_DEBUG_SYNC_STATE = 1U << 0,
+	MSM_TIMER_DEBUG_SYNC_UPDATE = 1U << 1,
+	MSM_TIMER_DEBUG_SYNC = 1U << 2,
+};
+static int msm_timer_debug_mask;
+module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 #define TIMER_MATCH_VAL         0x0000
 #define TIMER_COUNT_VAL         0x0004
@@ -41,7 +46,23 @@
 #define CSR_PROTECTION_EN               1
 
 #define GPT_HZ 32768
+
+#if defined(CONFIG_ARCH_QSD8X50)
+#define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */
+#define MSM_DGT_SHIFT (0)
+#elif defined(CONFIG_ARCH_MSM7X30)
+#define DGT_HZ (24576000 / 4) /* 24.576 MHz (LPXO) / 4 by default */
+#define MSM_DGT_SHIFT (0)
+#else
 #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
+#define MSM_DGT_SHIFT (5)
+#endif
+
+enum {
+	MSM_CLOCK_FLAGS_UNSTABLE_COUNT = 1U << 0,
+	MSM_CLOCK_FLAGS_ODD_MATCH_WRITE = 1U << 1,
+	MSM_CLOCK_FLAGS_DELAYED_WRITE_POST = 1U << 2,
+};
 
 struct msm_clock {
 	struct clock_event_device   clockevent;
@@ -50,40 +71,108 @@
 	void __iomem                *regbase;
 	uint32_t                    freq;
 	uint32_t                    shift;
+	uint32_t                    flags;
+	uint32_t                    write_delay;
+	uint32_t                    last_set;
+	uint32_t                    offset;
+	uint32_t                    alarm_vtime;
+	uint32_t                    smem_offset;
+	uint32_t                    smem_in_sync;
+	cycle_t                     stopped_tick;
+	int                         stopped;
 };
+enum {
+	MSM_CLOCK_GPT,
+	MSM_CLOCK_DGT,
+};
+static struct msm_clock msm_clocks[];
+static struct msm_clock *msm_active_clock;
+static DEFINE_SPINLOCK(msm_fast_timer_lock);
+static int msm_fast_timer_enabled;
 
 static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
 {
 	struct clock_event_device *evt = dev_id;
-	evt->event_handler(evt);
+	if (evt->event_handler)
+		evt->event_handler(evt);
 	return IRQ_HANDLED;
 }
 
+static uint32_t msm_read_timer_count(struct msm_clock *clock)
+{
+	uint32_t t1, t2;
+	int loop_count = 0;
+
+	t1 = readl(clock->regbase + TIMER_COUNT_VAL);
+	if (!(clock->flags & MSM_CLOCK_FLAGS_UNSTABLE_COUNT))
+		return t1;
+	while (1) {
+		t2 = readl(clock->regbase + TIMER_COUNT_VAL);
+		if (t1 == t2)
+			return t1;
+		if (loop_count++ > 10) {
+			printk(KERN_ERR "msm_read_timer_count timer %s did not"
+			       "stabilize %u != %u\n", clock->clockevent.name,
+			       t2, t1);
+			return t2;
+		}
+		t1 = t2;
+	}
+}
+
 static cycle_t msm_gpt_read(struct clocksource *cs)
 {
-	return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
+	struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT];
+	if (clock->stopped)
+		return clock->stopped_tick;
+	else
+		return msm_read_timer_count(clock) + clock->offset;
 }
 
 static cycle_t msm_dgt_read(struct clocksource *cs)
 {
-	return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
+	struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT];
+	if (clock->stopped)
+		return clock->stopped_tick;
+	return (msm_read_timer_count(clock) + clock->offset) >> MSM_DGT_SHIFT;
 }
 
 static int msm_timer_set_next_event(unsigned long cycles,
 				    struct clock_event_device *evt)
 {
-	struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
-	uint32_t now = readl(clock->regbase + TIMER_COUNT_VAL);
-	uint32_t alarm = now + (cycles << clock->shift);
+	int i;
+	struct msm_clock *clock;
+	uint32_t now;
+	uint32_t alarm;
 	int late;
 
+	clock = container_of(evt, struct msm_clock, clockevent);
+	now = msm_read_timer_count(clock);
+	alarm = now + (cycles << clock->shift);
+	if (clock->flags & MSM_CLOCK_FLAGS_ODD_MATCH_WRITE)
+		while (now == clock->last_set)
+			now = msm_read_timer_count(clock);
 	writel(alarm, clock->regbase + TIMER_MATCH_VAL);
-	now = readl(clock->regbase + TIMER_COUNT_VAL);
+	if (clock->flags & MSM_CLOCK_FLAGS_DELAYED_WRITE_POST) {
+		/* read the counter four extra times to make sure write posts
+		   before reading the time */
+		for (i = 0; i < 4; i++)
+			readl(clock->regbase + TIMER_COUNT_VAL);
+	}
+	now = msm_read_timer_count(clock);
+	clock->last_set = now;
+	clock->alarm_vtime = alarm + clock->offset;
 	late = now - alarm;
-	if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
-		printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
-		       "alarm already expired, now %x, alarm %x, late %d\n",
-		       cycles, clock->clockevent.name, now, alarm, late);
+	if (late >= (int)(-clock->write_delay << clock->shift) && late < DGT_HZ*5) {
+		static int print_limit = 10;
+		if (print_limit > 0) {
+			print_limit--;
+			printk(KERN_NOTICE "msm_timer_set_next_event(%lu) "
+			       "clock %s, alarm already expired, now %x, "
+			       "alarm %x, late %d%s\n",
+			       cycles, clock->clockevent.name, now, alarm, late,
+			       print_limit ? "" : " stop printing");
+		}
 		return -ETIME;
 	}
 	return 0;
@@ -92,23 +181,370 @@
 static void msm_timer_set_mode(enum clock_event_mode mode,
 			      struct clock_event_device *evt)
 {
-	struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
+	struct msm_clock *clock;
+	unsigned long irq_flags;
+
+	clock = container_of(evt, struct msm_clock, clockevent);
+	local_irq_save(irq_flags);
+
 	switch (mode) {
 	case CLOCK_EVT_MODE_RESUME:
 	case CLOCK_EVT_MODE_PERIODIC:
 		break;
 	case CLOCK_EVT_MODE_ONESHOT:
+		clock->stopped = 0;
+		clock->offset = -msm_read_timer_count(clock) + clock->stopped_tick;
+		msm_active_clock = clock;
 		writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
+		msm_active_clock = NULL;
+		clock->smem_in_sync = 0;
+		clock->stopped = 1;
+		clock->stopped_tick = (msm_read_timer_count(clock) +
+					clock->offset) >> clock->shift;
 		writel(0, clock->regbase + TIMER_ENABLE);
 		break;
 	}
+	local_irq_restore(irq_flags);
 }
 
+static inline int check_timeout(struct msm_clock *clock, uint32_t timeout)
+{
+	return (int32_t)(msm_read_timer_count(clock) - timeout) <= 0;
+}
+
+#ifndef CONFIG_ARCH_MSM_SCORPION
+
+static uint32_t msm_timer_sync_smem_clock(int exit_sleep)
+{
+	struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT];
+	uint32_t *smem_clock;
+	uint32_t smem_clock_val;
+	uint32_t timeout;
+	uint32_t entry_time;
+	uint32_t timeout_delta;
+	uint32_t last_state;
+	uint32_t state;
+	uint32_t new_offset;
+
+	smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE,
+				sizeof(uint32_t));
+
+	if (smem_clock == NULL) {
+		printk(KERN_ERR "no smem clock\n");
+		return 0;
+	}
+
+	if (!exit_sleep && clock->smem_in_sync)
+		return 0;
+
+	timeout_delta = (clock->freq >> (7 - clock->shift)); /* 7.8ms */
+
+	last_state = state = smsm_get_state(SMSM_STATE_MODEM);
+	if (*smem_clock) {
+		printk(KERN_INFO "get_smem_clock: invalid start state %x "
+		       "clock %u\n", state, *smem_clock);
+		smsm_change_state(SMSM_STATE_APPS, SMSM_TIMEWAIT, SMSM_TIMEINIT);
+		entry_time = msm_read_timer_count(clock);
+		timeout = entry_time + timeout_delta;
+		while (*smem_clock != 0 && check_timeout(clock, timeout))
+			;
+		if (*smem_clock) {
+			printk(KERN_INFO "get_smem_clock: timeout still "
+			       "invalid state %x clock %u in %d ticks\n",
+			       state, *smem_clock,
+			       msm_read_timer_count(clock) - entry_time);
+			return 0;
+		}
+	}
+	entry_time = msm_read_timer_count(clock);
+	timeout = entry_time + timeout_delta;
+	smsm_change_state(SMSM_STATE_APPS, SMSM_TIMEINIT, SMSM_TIMEWAIT);
+	do {
+		smem_clock_val = *smem_clock;
+		state = smsm_get_state(SMSM_STATE_MODEM);
+		if (state != last_state) {
+			last_state = state;
+			if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC_STATE)
+				pr_info("get_smem_clock: state %x clock %u\n",
+					state, smem_clock_val);
+		}
+	} while (smem_clock_val == 0 && check_timeout(clock, timeout));
+	if (smem_clock_val) {
+		new_offset = smem_clock_val - msm_read_timer_count(clock);
+		if (clock->offset + clock->smem_offset != new_offset) {
+			if (exit_sleep)
+				clock->offset = new_offset - clock->smem_offset;
+			else
+				clock->smem_offset = new_offset - clock->offset;
+			clock->smem_in_sync = 1;
+			if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC_UPDATE)
+				printk(KERN_INFO "get_smem_clock: state %x "
+				       "clock %u new offset %u+%u\n",
+				       state, smem_clock_val,
+				       clock->offset, clock->smem_offset);
+		} else if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) {
+			printk(KERN_INFO "get_smem_clock: state %x "
+			       "clock %u offset %u+%u\n",
+			       state, smem_clock_val,
+			       clock->offset, clock->smem_offset);
+		}
+	} else {
+		printk(KERN_INFO "get_smem_clock: timeout state %x clock %u "
+		       "in %d ticks\n", state, *smem_clock,
+		       msm_read_timer_count(clock) - entry_time);
+	}
+	smsm_change_state(SMSM_STATE_APPS, SMSM_TIMEWAIT, SMSM_TIMEINIT);
+	entry_time = msm_read_timer_count(clock);
+	timeout = entry_time + timeout_delta;
+	while (*smem_clock != 0 && check_timeout(clock, timeout)) {
+		uint32_t astate = smsm_get_state(SMSM_STATE_APPS);
+		if ((astate & SMSM_TIMEWAIT) || !(astate & SMSM_TIMEINIT)) {
+			if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC_STATE)
+				pr_info("get_smem_clock: modem overwrote "
+					"apps state %x\n", astate);
+			smsm_change_state(SMSM_STATE_APPS,
+					  SMSM_TIMEWAIT, SMSM_TIMEINIT);
+		}
+	}
+	if (*smem_clock)
+		printk(KERN_INFO "get_smem_clock: exit timeout state %x "
+		       "clock %u in %d ticks\n", state, *smem_clock,
+		       msm_read_timer_count(clock) - entry_time);
+	return smem_clock_val;
+}
+
+#else
+
+/* Time Master State Bits */
+#define DEM_TIME_MASTER_TIME_PENDING_APPS	BIT(0)
+
+/* Time Slave State Bits */
+#define DEM_TIME_SLAVE_TIME_REQUEST         0x0400
+#define DEM_TIME_SLAVE_TIME_POLL            0x0800
+#define DEM_TIME_SLAVE_TIME_INIT            0x1000
+
+static uint32_t msm_timer_sync_smem_clock(int exit_sleep)
+{
+	struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT];
+	uint32_t *smem_clock;
+	uint32_t smem_clock_val;
+	uint32_t bad_clock = 0;
+	uint32_t timeout;
+	uint32_t entry_time;
+	uint32_t timeout_delta;
+	uint32_t last_state;
+	uint32_t state;
+	uint32_t new_offset;
+
+	smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE,
+				sizeof(uint32_t));
+
+	if (smem_clock == NULL) {
+		printk(KERN_ERR "no smem clock\n");
+		return 0;
+	}
+
+	if (!exit_sleep && clock->smem_in_sync)
+		return 0;
+
+	timeout_delta = (clock->freq >> (7 - clock->shift)); /* 7.8ms */
+
+	entry_time = msm_read_timer_count(clock);
+	last_state = state = smsm_get_state(SMSM_STATE_TIME_MASTER_DEM);
+	timeout = entry_time + timeout_delta;
+	while ((smsm_get_state(SMSM_STATE_TIME_MASTER_DEM)
+		& DEM_TIME_MASTER_TIME_PENDING_APPS)
+		&& check_timeout(clock, timeout))
+		;
+	if ((smsm_get_state(SMSM_STATE_TIME_MASTER_DEM) &
+				DEM_TIME_MASTER_TIME_PENDING_APPS)) {
+		printk(KERN_INFO "get_smem_clock: invalid start state %x "
+		       "clock %u in %d ticks\n",
+		       state, *smem_clock,
+		       msm_read_timer_count(clock) - entry_time);
+		bad_clock = *smem_clock;
+	}
+	entry_time = msm_read_timer_count(clock);
+	timeout = entry_time + timeout_delta;
+	smsm_change_state(SMSM_STATE_APPS_DEM,
+			DEM_TIME_SLAVE_TIME_INIT, DEM_TIME_SLAVE_TIME_REQUEST);
+	while (!(smsm_get_state(SMSM_STATE_TIME_MASTER_DEM)
+		& DEM_TIME_MASTER_TIME_PENDING_APPS)
+		&& check_timeout(clock, timeout))
+		;
+	if (!(smsm_get_state(SMSM_STATE_TIME_MASTER_DEM) &
+					DEM_TIME_MASTER_TIME_PENDING_APPS)) {
+		printk(KERN_INFO "get_smem_clock: invalid start state %x "
+		       "clock %u in %d ticks\n",
+		       state, *smem_clock,
+		       msm_read_timer_count(clock) - entry_time);
+		bad_clock = *smem_clock;
+	}
+	smsm_change_state(SMSM_STATE_APPS_DEM,
+		DEM_TIME_SLAVE_TIME_REQUEST, DEM_TIME_SLAVE_TIME_POLL);
+	do {
+		smem_clock_val = *smem_clock;
+		state = smsm_get_state(SMSM_STATE_TIME_MASTER_DEM);
+		if (state != last_state) {
+			last_state = state;
+			if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC_STATE)
+				pr_info("get_smem_clock: state %x clock %u\n",
+					state, smem_clock_val);
+		}
+	} while ((!smem_clock_val || smem_clock_val == bad_clock)
+		 && check_timeout(clock, timeout));
+	if (smem_clock_val && smem_clock_val != bad_clock) {
+		new_offset = smem_clock_val - msm_read_timer_count(clock);
+		if (clock->offset + clock->smem_offset != new_offset) {
+			if (exit_sleep)
+				clock->offset = new_offset - clock->smem_offset;
+			else
+				clock->smem_offset = new_offset - clock->offset;
+			clock->smem_in_sync = 1;
+			if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC_UPDATE)
+				printk(KERN_INFO "get_smem_clock: state %x "
+				       "clock %u new offset %u+%u\n",
+				       state, smem_clock_val,
+				       clock->offset, clock->smem_offset);
+		} else if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) {
+			printk(KERN_INFO "get_smem_clock: state %x "
+			       "clock %u offset %u+%u\n",
+			       state, smem_clock_val,
+			       clock->offset, clock->smem_offset);
+		}
+	} else {
+		printk(KERN_INFO "get_smem_clock: timeout state %x clock %u "
+		       "in %d ticks\n", state, *smem_clock,
+		       msm_read_timer_count(clock) - entry_time);
+	}
+	smsm_change_state(SMSM_STATE_APPS_DEM,
+		DEM_TIME_SLAVE_TIME_POLL, DEM_TIME_SLAVE_TIME_INIT);
+#if 1 /* debug */
+	entry_time = msm_read_timer_count(clock);
+	timeout = entry_time + timeout_delta;
+	while ((smsm_get_state(SMSM_STATE_TIME_MASTER_DEM)
+		& DEM_TIME_MASTER_TIME_PENDING_APPS)
+		&& check_timeout(clock, timeout))
+		;
+	if (smsm_get_state(SMSM_STATE_TIME_MASTER_DEM) &
+					DEM_TIME_MASTER_TIME_PENDING_APPS)
+		printk(KERN_INFO "get_smem_clock: exit timeout state %x "
+		       "clock %u in %d ticks\n", state, *smem_clock,
+		       msm_read_timer_count(clock) - entry_time);
+#endif
+	return smem_clock_val;
+}
+
+#endif
+
+static void msm_timer_reactivate_alarm(struct msm_clock *clock)
+{
+	long alarm_delta = clock->alarm_vtime - clock->offset -
+		msm_read_timer_count(clock);
+	if (alarm_delta < (long)clock->write_delay + 4)
+		alarm_delta = clock->write_delay + 4;
+	while (msm_timer_set_next_event(alarm_delta, &clock->clockevent))
+		;
+}
+
+int64_t msm_timer_enter_idle(void)
+{
+	struct msm_clock *clock = msm_active_clock;
+	uint32_t alarm;
+	uint32_t count;
+	int32_t delta;
+
+	if (clock != &msm_clocks[MSM_CLOCK_GPT] || msm_fast_timer_enabled)
+		return 0;
+
+	msm_timer_sync_smem_clock(0);
+
+	count = msm_read_timer_count(clock);
+	if (clock->stopped++ == 0)
+		clock->stopped_tick = (count + clock->offset) >> clock->shift;
+	alarm = clock->alarm_vtime - clock->offset;
+	delta = alarm - count;
+	if (delta <= -(int32_t)((clock->freq << clock->shift) >> 10)) {
+		/* timer should have triggered 1ms ago */
+		printk(KERN_ERR "msm_timer_enter_idle: timer late %d, "
+			"reprogram it\n", delta);
+		msm_timer_reactivate_alarm(clock);
+	}
+	if (delta <= 0)
+		return 0;
+	return clocksource_cyc2ns((alarm - count) >> clock->shift,
+			clock->clocksource.mult, clock->clocksource.shift);
+}
+
+void msm_timer_exit_idle(int low_power)
+{
+	struct msm_clock *clock = msm_active_clock;
+	uint32_t smem_clock;
+
+	if (clock != &msm_clocks[MSM_CLOCK_GPT])
+		return;
+
+	if (low_power) {
+		if (!(readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN)) {
+			writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
+			smem_clock = msm_timer_sync_smem_clock(1);
+		}
+		msm_timer_reactivate_alarm(clock);
+	}
+	clock->stopped--;
+}
+
+unsigned long long sched_clock(void)
+{
+	static cycle_t saved_ticks;
+	static int saved_ticks_valid;
+	static unsigned long long base;
+	static unsigned long long last_result;
+
+	unsigned long irq_flags;
+	static cycle_t last_ticks;
+	cycle_t ticks;
+	static unsigned long long result;
+	struct clocksource *cs;
+	struct msm_clock *clock = msm_active_clock;
+
+	local_irq_save(irq_flags);
+	if (clock) {
+		cs = &clock->clocksource;
+
+		last_ticks = saved_ticks;
+		saved_ticks = ticks = cs->read(cs);
+		if (!saved_ticks_valid) {
+			saved_ticks_valid = 1;
+			last_ticks = ticks;
+			base -= clocksource_cyc2ns(ticks, cs->mult, cs->shift);
+		}
+		if (ticks < last_ticks) {
+			base += clocksource_cyc2ns(cs->mask,
+						   cs->mult, cs->shift);
+			base += clocksource_cyc2ns(1, cs->mult, cs->shift);
+		}
+		last_result = result =
+			clocksource_cyc2ns(ticks, cs->mult, cs->shift) + base;
+	} else {
+		base = result = last_result;
+		saved_ticks_valid = 0;
+	}
+	local_irq_restore(irq_flags);
+	return result; 
+}
+
+#ifdef CONFIG_MSM7X00A_USE_GP_TIMER
+	#define DG_TIMER_RATING 100
+#else
+	#define DG_TIMER_RATING 300
+#endif
+
 static struct msm_clock msm_clocks[] = {
-	{
+	[MSM_CLOCK_GPT] = {
 		.clockevent = {
 			.name           = "gp_timer",
 			.features       = CLOCK_EVT_FEAT_ONESHOT,
@@ -122,49 +558,116 @@
 			.rating         = 200,
 			.read           = msm_gpt_read,
 			.mask           = CLOCKSOURCE_MASK(32),
-			.shift          = 24,
+			.shift          = 17,
 			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 		},
 		.irq = {
 			.name    = "gp_timer",
-			.flags   = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
+			.flags   = IRQF_DISABLED | IRQF_TIMER |
+				   IRQF_TRIGGER_RISING,
 			.handler = msm_timer_interrupt,
 			.dev_id  = &msm_clocks[0].clockevent,
 			.irq     = INT_GP_TIMER_EXP
 		},
 		.regbase = MSM_GPT_BASE,
-		.freq = GPT_HZ
+		.freq = GPT_HZ,
+		.flags   =
+			MSM_CLOCK_FLAGS_UNSTABLE_COUNT |
+			MSM_CLOCK_FLAGS_ODD_MATCH_WRITE |
+			MSM_CLOCK_FLAGS_DELAYED_WRITE_POST,
+		.write_delay = 9,
 	},
-	{
+	[MSM_CLOCK_DGT] = {
 		.clockevent = {
 			.name           = "dg_timer",
 			.features       = CLOCK_EVT_FEAT_ONESHOT,
 			.shift          = 32 + MSM_DGT_SHIFT,
-			.rating         = 300,
+			.rating         = DG_TIMER_RATING,
 			.set_next_event = msm_timer_set_next_event,
 			.set_mode       = msm_timer_set_mode,
 		},
 		.clocksource = {
 			.name           = "dg_timer",
-			.rating         = 300,
+			.rating         = DG_TIMER_RATING,
 			.read           = msm_dgt_read,
-			.mask           = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
+			.mask           = CLOCKSOURCE_MASK((32-MSM_DGT_SHIFT)),
 			.shift          = 24 - MSM_DGT_SHIFT,
 			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 		},
 		.irq = {
 			.name    = "dg_timer",
-			.flags   = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
+			.flags   = IRQF_DISABLED | IRQF_TIMER |
+				   IRQF_TRIGGER_RISING,
 			.handler = msm_timer_interrupt,
 			.dev_id  = &msm_clocks[1].clockevent,
 			.irq     = INT_DEBUG_TIMER_EXP
 		},
 		.regbase = MSM_DGT_BASE,
 		.freq = DGT_HZ >> MSM_DGT_SHIFT,
-		.shift = MSM_DGT_SHIFT
+		.shift = MSM_DGT_SHIFT,
+		.write_delay = 2,
 	}
 };
 
+/**
+ * msm_enable_fast_timer - Enable fast timer
+ *
+ * Prevents low power idle, but the caller must call msm_disable_fast_timer
+ * before suspend completes.
+ * Reference counted.
+ */
+void msm_enable_fast_timer(void)
+{
+	u32 max;
+	unsigned long irq_flags;
+	struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT];
+
+	spin_lock_irqsave(&msm_fast_timer_lock, irq_flags);
+	if (msm_fast_timer_enabled++)
+		goto done;
+	if (msm_active_clock == &msm_clocks[MSM_CLOCK_DGT]) {
+		pr_warning("msm_enable_fast_timer: timer already in use, "
+			"returned time will jump when hardware timer wraps\n");
+		goto done;
+	}
+	max = (clock->clockevent.mult >> (clock->clockevent.shift - 32)) - 1;
+	writel(max, clock->regbase + TIMER_MATCH_VAL);
+	writel(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN,
+		clock->regbase + TIMER_ENABLE);
+done:
+	spin_unlock_irqrestore(&msm_fast_timer_lock, irq_flags);
+}
+
+/**
+ * msm_enable_fast_timer - Disable fast timer
+ */
+void msm_disable_fast_timer(void)
+{
+	unsigned long irq_flags;
+	struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT];
+
+	spin_lock_irqsave(&msm_fast_timer_lock, irq_flags);
+	if (!WARN(!msm_fast_timer_enabled, "msm_disable_fast_timer undeflow")
+	    && !--msm_fast_timer_enabled
+	    && msm_active_clock != &msm_clocks[MSM_CLOCK_DGT])
+		writel(0, clock->regbase + TIMER_ENABLE);
+	spin_unlock_irqrestore(&msm_fast_timer_lock, irq_flags);
+}
+
+/**
+ * msm_enable_fast_timer - Read fast timer
+ *
+ * Returns 32bit nanosecond time value.
+ */
+u32 msm_read_fast_timer(void)
+{
+	cycle_t ticks;
+	struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT];
+	ticks = msm_read_timer_count(clock) >> MSM_DGT_SHIFT;
+	return clocksource_cyc2ns(ticks, clock->clocksource.mult,
+					clock->clocksource.shift);
+}
+
 static void __init msm_timer_init(void)
 {
 	int i;
@@ -177,13 +680,15 @@
 		writel(0, clock->regbase + TIMER_ENABLE);
 		writel(0, clock->regbase + TIMER_CLEAR);
 		writel(~0, clock->regbase + TIMER_MATCH_VAL);
+		while (msm_read_timer_count(clock)) ; /* wait for clock to clear */
 
 		ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift);
 		/* allow at least 10 seconds to notice that the timer wrapped */
 		ce->max_delta_ns =
 			clockevent_delta2ns(0xf0000000 >> clock->shift, ce);
-		/* 4 gets rounded down to 3 */
-		ce->min_delta_ns = clockevent_delta2ns(4, ce);
+		/* ticks gets rounded down by one */
+		ce->min_delta_ns =
+			clockevent_delta2ns(clock->write_delay + 4, ce);
 		ce->cpumask = cpumask_of(0);
 
 		cs->mult = clocksource_hz2mult(clock->freq, cs->shift);
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index cbfb2ed..79c864a 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -23,6 +23,10 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
+#ifdef CONFIG_ARCH_MSM_SCORPION
+#include <asm/io.h>
+#include <mach/msm_iomap.h>
+#endif
 
 #include "fault.h"
 
@@ -452,6 +456,49 @@
 	return 1;
 }
 
+#ifdef CONFIG_ARCH_MSM_SCORPION
+#define __str(x) #x
+#define MRC(x, v1, v2, v4, v5, v6) do {					\
+	unsigned int __##x;						\
+	asm("mrc " __str(v1) ", " __str(v2) ", %0, " __str(v4) ", "	\
+		__str(v5) ", " __str(v6) "\n" \
+		: "=r" (__##x));					\
+	pr_info("%s: %s = 0x%.8x\n", __func__, #x, __##x);		\
+} while(0)
+
+#define MSM_TCSR_SPARE2 (MSM_TCSR_BASE + 0x60)
+
+#endif
+
+static int
+do_imprecise_ext(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+#ifdef CONFIG_ARCH_MSM_SCORPION
+	MRC(ADFSR,    p15, 0,  c5, c1, 0);
+	MRC(DFSR,     p15, 0,  c5, c0, 0);
+	MRC(ACTLR,    p15, 0,  c1, c0, 1);
+	MRC(EFSR,     p15, 7, c15, c0, 1);
+	MRC(L2SR,     p15, 3, c15, c1, 0);
+	MRC(L2CR0,    p15, 3, c15, c0, 1);
+	MRC(L2CPUESR, p15, 3, c15, c1, 1);
+	MRC(L2CPUCR,  p15, 3, c15, c0, 2);
+	MRC(SPESR,    p15, 1,  c9, c7, 0);
+	MRC(SPCR,     p15, 0,  c9, c7, 0);
+	MRC(DMACHSR,  p15, 1, c11, c0, 0);
+	MRC(DMACHESR, p15, 1, c11, c0, 1);
+	MRC(DMACHCR,  p15, 0, c11, c0, 2);
+
+	/* clear out EFSR and ADFSR after fault */
+	asm volatile ("mcr p15, 7, %0, c15, c0, 1\n\t"
+		      "mcr p15, 0, %0, c5, c1, 0"
+		      : : "r" (0));
+#endif
+#ifdef CONFIG_ARCH_MSM_SCORPION
+	pr_info("%s: TCSR_SPARE2 = 0x%.8x\n", __func__, readl(MSM_TCSR_SPARE2));
+#endif
+	return 1;
+}
+
 static struct fsr_info {
 	int	(*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
 	int	sig;
@@ -494,7 +541,7 @@
 	{ do_bad,		SIGBUS,  0,		"unknown 19"			   },
 	{ do_bad,		SIGBUS,  0,		"lock abort"			   }, /* xscale */
 	{ do_bad,		SIGBUS,  0,		"unknown 21"			   },
-	{ do_bad,		SIGBUS,  BUS_OBJERR,	"imprecise external abort"	   }, /* xscale */
+	{ do_imprecise_ext,	SIGBUS,  BUS_OBJERR,	"imprecise external abort"	   }, /* xscale */
 	{ do_bad,		SIGBUS,  0,		"unknown 23"			   },
 	{ do_bad,		SIGBUS,  0,		"dcache parity error"		   }, /* xscale */
 	{ do_bad,		SIGBUS,  0,		"unknown 25"			   },
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 2858941..b01f7cd 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -668,7 +668,7 @@
 		create_mapping(io_desc + i);
 }
 
-static unsigned long __initdata vmalloc_reserve = SZ_128M;
+static unsigned long __initdata vmalloc_reserve = CONFIG_VMALLOC_RESERVE;
 
 /*
  * vmalloc=size forces the vmalloc area to be exactly 'size'
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 7aaf88a..df74916 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -240,8 +240,6 @@
 	mcr	p15, 0, r10, c2, c0, 2		@ TTB control register
 	orr	r4, r4, #TTB_FLAGS
 	mcr	p15, 0, r4, c2, c0, 1		@ load TTB1
-	mov	r10, #0x1f			@ domains 0, 1 = manager
-	mcr	p15, 0, r10, c3, c0, 0		@ load domain access register
 	/*
 	 * Memory region attributes with SCTLR.TRE=1
 	 *
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index fb8445c..7635e42 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -45,6 +45,7 @@
 #include <linux/signal.h>
 #include <linux/ioctl.h>
 #include <linux/skbuff.h>
+#include <linux/serial_core.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -86,6 +87,28 @@
 	struct sk_buff_head tx_wait_q;	/* HCILL wait queue	*/
 };
 
+#ifdef CONFIG_SERIAL_MSM_HS
+void msm_hs_request_clock_off(struct uart_port *uport);
+void msm_hs_request_clock_on(struct uart_port *uport);
+
+static void __ll_msm_serial_clock_on(struct tty_struct *tty) {
+	struct uart_state *state = tty->driver_data;
+	struct uart_port *port = state->uart_port;
+
+	msm_hs_request_clock_on(port);
+}
+
+static void __ll_msm_serial_clock_request_off(struct tty_struct *tty) {
+	struct uart_state *state = tty->driver_data;
+	struct uart_port *port = state->uart_port;
+
+	msm_hs_request_clock_off(port);
+}
+#else
+static inline void __ll_msm_serial_clock_on(struct tty_struct *tty) {}
+static inline void __ll_msm_serial_clock_request_off(struct tty_struct *tty) {}
+#endif
+
 /*
  * Builds and sends an HCILL command packet.
  * These are very simple packets with only 1 cmd byte
@@ -217,6 +240,10 @@
 		BT_DBG("dual wake-up-indication");
 		/* deliberate fall-through - do not add break */
 	case HCILL_ASLEEP:
+		/* Make sure clock is on - we may have turned clock off since
+		 * receiving the wake up indicator
+		 */
+		__ll_msm_serial_clock_on(hu->tty);
 		/* acknowledge device wake up */
 		if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) {
 			BT_ERR("cannot acknowledge device wake up");
@@ -270,6 +297,11 @@
 
 	/* actually send the sleep ack packet */
 	hci_uart_tx_wakeup(hu);
+
+	spin_lock_irqsave(&ll->hcill_lock, flags);
+	if (ll->hcill_state == HCILL_ASLEEP)
+		__ll_msm_serial_clock_request_off(hu->tty);
+	spin_unlock_irqrestore(&ll->hcill_lock, flags);
 }
 
 /*
@@ -321,6 +353,7 @@
 		break;
 	case HCILL_ASLEEP:
 		BT_DBG("device asleep, waking up and queueing packet");
+		__ll_msm_serial_clock_on(hu->tty);
 		/* save packet for later */
 		skb_queue_tail(&ll->tx_wait_q, skb);
 		/* awake device */
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 91091b0..ae08b38 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -329,7 +329,7 @@
 	vma->vm_ops = &mmap_mem_ops;
 
 	/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
-	if (remap_pfn_range(vma,
+	if (io_remap_pfn_range(vma,
 			    vma->vm_start,
 			    vma->vm_pgoff,
 			    size,
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index cd650ca..92ab03d 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -144,7 +144,6 @@
 	old_fops = file->f_op;
 	file->f_op = new_fops;
 	if (file->f_op->open) {
-		file->private_data = c;
 		err=file->f_op->open(inode,file);
 		if (err) {
 			fops_put(file->f_op);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index bceafbf..42a396a 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -431,6 +431,22 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-mpc.
 
+config I2C_MSM
+	tristate "MSM"
+	depends on I2C && ARCH_MSM
+	default y
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in I2C interface on the MSM7X00A family processors.
+
+config I2C_QUP
+	tristate "I2C_QUP"
+	depends on I2C && ARCH_MSM7X30
+	default y
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in I2C interface on the MSM family processors.
+
 config I2C_MV64XXX
 	tristate "Marvell mv64xxx I2C Controller"
 	depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 936880b..d8d2931 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -41,6 +41,8 @@
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
+obj-$(CONFIG_I2C_MSM)		+= i2c-msm.o
+obj-$(CONFIG_I2C_QUP)		+= i2c-qup.o
 obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
 obj-$(CONFIG_I2C_NOMADIK)	+= i2c-nomadik.o
 obj-$(CONFIG_I2C_OCORES)	+= i2c-ocores.o
diff --git a/drivers/i2c/busses/i2c-msm.c b/drivers/i2c/busses/i2c-msm.c
new file mode 100644
index 0000000..0322262
--- /dev/null
+++ b/drivers/i2c/busses/i2c-msm.c
@@ -0,0 +1,607 @@
+/* drivers/i2c/busses/i2c-msm.c
+ *
+ * Copyright (C) 2007 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/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/wakelock.h>
+#include <mach/system.h>
+
+#define DEBUG 0
+
+enum {
+	I2C_WRITE_DATA          = 0x00,
+	I2C_CLK_CTL             = 0x04,
+	I2C_STATUS              = 0x08,
+	I2C_READ_DATA           = 0x0c,
+	I2C_INTERFACE_SELECT    = 0x10,
+
+	I2C_WRITE_DATA_DATA_BYTE            = 0xff,
+	I2C_WRITE_DATA_ADDR_BYTE            = 1U << 8,
+	I2C_WRITE_DATA_LAST_BYTE            = 1U << 9,
+
+	I2C_CLK_CTL_FS_DIVIDER_VALUE        = 0xff,
+	I2C_CLK_CTL_HS_DIVIDER_VALUE        = 7U << 8,
+
+	I2C_STATUS_WR_BUFFER_FULL           = 1U << 0,
+	I2C_STATUS_RD_BUFFER_FULL           = 1U << 1,
+	I2C_STATUS_BUS_ERROR                = 1U << 2,
+	I2C_STATUS_PACKET_NACKED            = 1U << 3,
+	I2C_STATUS_ARB_LOST                 = 1U << 4,
+	I2C_STATUS_INVALID_WRITE            = 1U << 5,
+	I2C_STATUS_FAILED                   = 3U << 6,
+	I2C_STATUS_BUS_ACTIVE               = 1U << 8,
+	I2C_STATUS_BUS_MASTER               = 1U << 9,
+	I2C_STATUS_ERROR_MASK               = 0xfc,
+
+	I2C_INTERFACE_SELECT_INTF_SELECT    = 1U << 0,
+	I2C_INTERFACE_SELECT_SCL            = 1U << 8,
+	I2C_INTERFACE_SELECT_SDA            = 1U << 9,
+};
+
+struct msm_i2c_dev {
+	struct device      *dev;
+	void __iomem       *base;		/* virtual */
+	int                 irq;
+	struct clk         *clk;
+	struct i2c_adapter  adapter;
+
+	spinlock_t          lock;
+
+	struct i2c_msg      *msg;
+	int                 rem;
+	int                 pos;
+	int                 cnt;
+	int                 ret;
+	bool                need_flush;
+	int                 flush_cnt;
+	void                *complete;
+	struct wake_lock    wakelock;
+	bool                is_suspended;
+};
+
+#if DEBUG
+static void
+dump_status(uint32_t status)
+{
+	printk("STATUS (0x%.8x): ", status);
+	if (status & I2C_STATUS_BUS_MASTER)
+		printk("MST ");
+	if (status & I2C_STATUS_BUS_ACTIVE)
+		printk("ACT ");
+	if (status & I2C_STATUS_INVALID_WRITE)
+		printk("INV_WR ");
+	if (status & I2C_STATUS_ARB_LOST)
+		printk("ARB_LST ");
+	if (status & I2C_STATUS_PACKET_NACKED)
+		printk("NAK ");
+	if (status & I2C_STATUS_BUS_ERROR)
+		printk("BUS_ERR ");
+	if (status & I2C_STATUS_RD_BUFFER_FULL)
+		printk("RD_FULL ");
+	if (status & I2C_STATUS_WR_BUFFER_FULL)
+		printk("WR_FULL ");
+	if (status & I2C_STATUS_FAILED)
+		printk("FAIL 0x%x", (status & I2C_STATUS_FAILED));
+	printk("\n");
+}
+#endif
+
+static void msm_i2c_write_delay(struct msm_i2c_dev *dev)
+{
+	/* If scl is still high we have >4us (for 100kbps) to write the data
+	 * register before we risk hitting a bug where the controller releases
+	 * scl to soon after driving sda low. Writing the data after the
+	 * scheduled release time for scl also avoids the bug.
+	 */
+	if (readl(dev->base + I2C_INTERFACE_SELECT) & I2C_INTERFACE_SELECT_SCL)
+		return;
+	udelay(6);
+}
+
+static bool msm_i2c_fill_write_buffer(struct msm_i2c_dev *dev)
+{
+	uint16_t val;
+	if (dev->pos < 0) {
+		val = I2C_WRITE_DATA_ADDR_BYTE | dev->msg->addr << 1;
+		if (dev->msg->flags & I2C_M_RD)
+			val |= 1;
+		if (dev->rem == 1 && dev->msg->len == 0)
+			val |= I2C_WRITE_DATA_LAST_BYTE;
+		msm_i2c_write_delay(dev);
+		writel(val, dev->base + I2C_WRITE_DATA);
+		dev->pos++;
+		return true;
+	}
+
+	if (dev->msg->flags & I2C_M_RD)
+		return false;
+
+	if (!dev->cnt)
+		return false;
+
+	/* Ready to take a byte */
+	val = dev->msg->buf[dev->pos];
+	if (dev->cnt == 1 && dev->rem == 1)
+		val |= I2C_WRITE_DATA_LAST_BYTE;
+
+	msm_i2c_write_delay(dev);
+	writel(val, dev->base + I2C_WRITE_DATA);
+	dev->pos++;
+	dev->cnt--;
+	return true;
+}
+
+static void msm_i2c_read_buffer(struct msm_i2c_dev *dev)
+{
+	/*
+	 * Theres something in the FIFO.
+	 * Are we expecting data or flush crap?
+	 */
+	if ((dev->msg->flags & I2C_M_RD) && dev->pos >= 0 && dev->cnt) {
+		switch (dev->cnt) {
+		case 1:
+			if (dev->pos != 0)
+				break;
+			dev->need_flush = true;
+			/* fall-trough */
+		case 2:
+			writel(I2C_WRITE_DATA_LAST_BYTE,
+			       dev->base + I2C_WRITE_DATA);
+		}
+		dev->msg->buf[dev->pos] = readl(dev->base + I2C_READ_DATA);
+		dev->cnt--;
+		dev->pos++;
+	} else { /* FLUSH */
+		if (dev->flush_cnt & 1) {
+			/*
+			* Stop requests are sometimes ignored, but writing
+			* more than one request generates a write error.
+			*/
+			writel(I2C_WRITE_DATA_LAST_BYTE,
+				dev->base + I2C_WRITE_DATA);
+		}
+		readl(dev->base + I2C_READ_DATA);
+		if (dev->need_flush)
+			dev->need_flush = false;
+		else
+			dev->flush_cnt++;
+	}
+}
+
+static void msm_i2c_interrupt_locked(struct msm_i2c_dev *dev)
+{
+	uint32_t status	= readl(dev->base + I2C_STATUS);
+	bool not_done = true;
+
+#if DEBUG
+	dump_status(status);
+#endif
+	if (!dev->msg) {
+		dev_err(dev->dev,
+			"IRQ but nothing to do!, status %x\n", status);
+		return;
+	}
+	if (status & I2C_STATUS_ERROR_MASK)
+		goto out_err;
+
+	if (!(status & I2C_STATUS_WR_BUFFER_FULL))
+		not_done = msm_i2c_fill_write_buffer(dev);
+	if (status & I2C_STATUS_RD_BUFFER_FULL)
+		msm_i2c_read_buffer(dev);
+
+	if (dev->pos >= 0 && dev->cnt == 0) {
+		if (dev->rem > 1) {
+			dev->rem--;
+			dev->msg++;
+			dev->pos = -1;
+			dev->cnt = dev->msg->len;
+		} else if (!not_done && !dev->need_flush)
+			goto out_complete;
+	}
+	return;
+
+out_err:
+	dev_err(dev->dev, "error, status %x\n", status);
+	dev->ret = -EIO;
+out_complete:
+	complete(dev->complete);
+}
+
+static irqreturn_t
+msm_i2c_interrupt(int irq, void *devid)
+{
+	struct msm_i2c_dev *dev = devid;
+
+	spin_lock(&dev->lock);
+	msm_i2c_interrupt_locked(dev);
+	spin_unlock(&dev->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int
+msm_i2c_poll_notbusy(struct msm_i2c_dev *dev, int warn)
+{
+	uint32_t retries = 0;
+
+	while (retries != 200) {
+		uint32_t status = readl(dev->base + I2C_STATUS);
+
+		if (!(status & I2C_STATUS_BUS_ACTIVE)) {
+			if (retries && warn)
+				dev_warn(dev->dev,
+					"Warning bus was busy (%d)\n", retries);
+			return 0;
+		}
+		if (retries++ > 100)
+			msleep(10);
+	}
+	dev_err(dev->dev, "Error waiting for notbusy (%d)\n", warn);
+	return -ETIMEDOUT;
+}
+
+static int
+msm_i2c_recover_bus_busy(struct msm_i2c_dev *dev)
+{
+	int i;
+	uint32_t status = readl(dev->base + I2C_STATUS);
+	int gpio_clk, gpio_dat;
+	bool gpio_clk_status = false;
+
+	if (!(status & (I2C_STATUS_BUS_ACTIVE | I2C_STATUS_WR_BUFFER_FULL)))
+		return 0;
+
+	msm_set_i2c_mux(true, &gpio_clk, &gpio_dat);
+
+	if (status & I2C_STATUS_RD_BUFFER_FULL) {
+		dev_warn(dev->dev, "Read buffer full, status %x, intf %x\n",
+			 status, readl(dev->base + I2C_INTERFACE_SELECT));
+		writel(I2C_WRITE_DATA_LAST_BYTE, dev->base + I2C_WRITE_DATA);
+		readl(dev->base + I2C_READ_DATA);
+	}
+	else if (status & I2C_STATUS_BUS_MASTER) {
+		dev_warn(dev->dev, "Still the bus master, status %x, intf %x\n",
+			 status, readl(dev->base + I2C_INTERFACE_SELECT));
+		writel(I2C_WRITE_DATA_LAST_BYTE | 0xff,
+		       dev->base + I2C_WRITE_DATA);
+	}
+
+	dev_warn(dev->dev, "i2c_scl: %d, i2c_sda: %d\n",
+		 gpio_get_value(gpio_clk), gpio_get_value(gpio_dat));
+
+	for (i = 0; i < 9; i++) {
+		if (gpio_get_value(gpio_dat) && gpio_clk_status)
+			break;
+		gpio_direction_output(gpio_clk, 0);
+		udelay(5);
+		gpio_direction_output(gpio_dat, 0);
+		udelay(5);
+		gpio_direction_input(gpio_clk);
+		udelay(5);
+		if (!gpio_get_value(gpio_clk))
+			udelay(20);
+		if (!gpio_get_value(gpio_clk))
+			msleep(10);
+		gpio_clk_status = gpio_get_value(gpio_clk);
+		gpio_direction_input(gpio_dat);
+		udelay(5);
+	}
+	msm_set_i2c_mux(false, NULL, NULL);
+	udelay(10);
+
+	status = readl(dev->base + I2C_STATUS);
+	if (!(status & I2C_STATUS_BUS_ACTIVE)) {
+		dev_info(dev->dev, "Bus busy cleared after %d clock cycles, "
+			 "status %x, intf %x\n",
+			 i, status, readl(dev->base + I2C_INTERFACE_SELECT));
+		return 0;
+	}
+
+	dev_warn(dev->dev, "Bus still busy, status %x, intf %x\n",
+		 status, readl(dev->base + I2C_INTERFACE_SELECT));
+	return -EBUSY;
+}
+
+
+static int
+msm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	DECLARE_COMPLETION_ONSTACK(complete);
+	struct msm_i2c_dev *dev = i2c_get_adapdata(adap);
+	int ret;
+	long timeout;
+	unsigned long flags;
+
+	if (WARN_ON(!num))
+		return -EINVAL;
+
+	/*
+	 * If there is an i2c_xfer after driver has been suspended,
+	 * grab wakelock to abort suspend.
+	 */
+	if (dev->is_suspended)
+		wake_lock(&dev->wakelock);
+	clk_enable(dev->clk);
+	enable_irq(dev->irq);
+
+	ret = msm_i2c_poll_notbusy(dev, 1);
+	if (ret) {
+		ret = msm_i2c_recover_bus_busy(dev);
+		if (ret)
+			goto err;
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->flush_cnt) {
+		dev_warn(dev->dev, "%d unrequested bytes read\n",
+			 dev->flush_cnt);
+	}
+	dev->msg = msgs;
+	dev->rem = num;
+	dev->pos = -1;
+	dev->ret = num;
+	dev->need_flush = false;
+	dev->flush_cnt = 0;
+	dev->cnt = msgs->len;
+	dev->complete = &complete;
+
+	msm_i2c_interrupt_locked(dev);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	/*
+	 * Now that we've setup the xfer, the ISR will transfer the data
+	 * and wake us up with dev->err set if there was an error
+	 */
+
+	timeout = wait_for_completion_timeout(&complete, HZ);
+	msm_i2c_poll_notbusy(dev, 0); /* Read may not have stopped in time */
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->flush_cnt) {
+		dev_warn(dev->dev, "%d unrequested bytes read\n",
+			 dev->flush_cnt);
+	}
+	ret = dev->ret;
+	dev->complete = NULL;
+	dev->msg = NULL;
+	dev->rem = 0;
+	dev->pos = 0;
+	dev->ret = 0;
+	dev->flush_cnt = 0;
+	dev->cnt = 0;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (!timeout) {
+		dev_err(dev->dev, "Transaction timed out\n");
+		ret = -ETIMEDOUT;
+	}
+
+	if (ret < 0) {
+		dev_err(dev->dev, "Error during data xfer %x (%d)\n",
+			msgs[0].addr, ret);
+		msm_i2c_recover_bus_busy(dev);
+	}
+err:
+	disable_irq(dev->irq);
+	clk_disable(dev->clk);
+	if (dev->is_suspended)
+		wake_unlock(&dev->wakelock);
+
+	return ret;
+}
+
+static u32
+msm_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm msm_i2c_algo = {
+	.master_xfer	= msm_i2c_xfer,
+	.functionality	= msm_i2c_func,
+};
+
+static int
+msm_i2c_probe(struct platform_device *pdev)
+{
+	struct msm_i2c_dev	*dev;
+	struct resource		*mem, *irq, *ioarea;
+	int ret;
+	int fs_div;
+	int hs_div;
+	int i2c_clk;
+	int clk_ctl;
+	int target_clk;
+	struct clk *clk;
+
+	printk(KERN_INFO "msm_i2c_probe\n");
+
+	/* NOTE: driver uses the static register mapping */
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "no mem resource?\n");
+		return -ENODEV;
+	}
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!irq) {
+		dev_err(&pdev->dev, "no irq resource?\n");
+		return -ENODEV;
+	}
+
+	ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+			pdev->name);
+	if (!ioarea) {
+		dev_err(&pdev->dev, "I2C region already claimed\n");
+		return -EBUSY;
+	}
+	clk = clk_get(&pdev->dev, "i2c_clk");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Could not get clock\n");
+		ret = PTR_ERR(clk);
+		goto err_clk_get_failed;
+	}
+
+	dev = kzalloc(sizeof(struct msm_i2c_dev), GFP_KERNEL);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err_alloc_dev_failed;
+	}
+
+	dev->dev = &pdev->dev;
+	dev->irq = irq->start;
+	dev->clk = clk;
+	dev->base = ioremap(mem->start, (mem->end - mem->start) + 1);
+	if (!dev->base) {
+		ret = -ENOMEM;
+		goto err_ioremap_failed;
+	}
+
+	spin_lock_init(&dev->lock);
+	wake_lock_init(&dev->wakelock, WAKE_LOCK_SUSPEND, "i2c");
+	platform_set_drvdata(pdev, dev);
+
+	msm_set_i2c_mux(false, NULL, NULL);
+
+	clk_enable(clk);
+
+	/* I2C_HS_CLK = I2C_CLK/(3*(HS_DIVIDER_VALUE+1) */
+	/* I2C_FS_CLK = I2C_CLK/(2*(FS_DIVIDER_VALUE+3) */
+	/* FS_DIVIDER_VALUE = ((I2C_CLK / I2C_FS_CLK) / 2) - 3 */
+	i2c_clk = 19200000; /* input clock */
+	target_clk = 100000;
+	/* target_clk = 200000; */
+	fs_div = ((i2c_clk / target_clk) / 2) - 3;
+	hs_div = 3;
+	clk_ctl = ((hs_div & 0x7) << 8) | (fs_div & 0xff);
+	writel(clk_ctl, dev->base + I2C_CLK_CTL);
+	printk(KERN_INFO "msm_i2c_probe: clk_ctl %x, %d Hz\n",
+	       clk_ctl, i2c_clk / (2 * ((clk_ctl & 0xff) + 3)));
+	clk_disable(clk);
+
+	i2c_set_adapdata(&dev->adapter, dev);
+	dev->adapter.algo = &msm_i2c_algo;
+	strncpy(dev->adapter.name,
+		"MSM I2C adapter",
+		sizeof(dev->adapter.name));
+
+	dev->adapter.nr = pdev->id;
+	ret = i2c_add_numbered_adapter(&dev->adapter);
+	if (ret) {
+		dev_err(&pdev->dev, "i2c_add_adapter failed\n");
+		goto err_i2c_add_adapter_failed;
+	}
+
+	ret = request_irq(dev->irq, msm_i2c_interrupt,
+			IRQF_DISABLED | IRQF_TRIGGER_RISING, pdev->name, dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request_irq failed\n");
+		goto err_request_irq_failed;
+	}
+	disable_irq(dev->irq);
+	return 0;
+
+/*	free_irq(dev->irq, dev); */
+err_request_irq_failed:
+	i2c_del_adapter(&dev->adapter);
+err_i2c_add_adapter_failed:
+	iounmap(dev->base);
+err_ioremap_failed:
+	kfree(dev);
+err_alloc_dev_failed:
+	clk_put(clk);
+err_clk_get_failed:
+	release_mem_region(mem->start, (mem->end - mem->start) + 1);
+	return ret;
+}
+
+static int
+msm_i2c_remove(struct platform_device *pdev)
+{
+	struct msm_i2c_dev	*dev = platform_get_drvdata(pdev);
+	struct resource		*mem;
+
+	platform_set_drvdata(pdev, NULL);
+	enable_irq(dev->irq);
+	free_irq(dev->irq, dev);
+	i2c_del_adapter(&dev->adapter);
+	wake_lock_destroy(&dev->wakelock);
+	clk_put(dev->clk);
+	iounmap(dev->base);
+	kfree(dev);
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, (mem->end - mem->start) + 1);
+	return 0;
+}
+
+static int msm_i2c_suspend_noirq(struct device *device)
+{
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_i2c_dev *dev = platform_get_drvdata(pdev);
+
+	/* Block to allow any i2c_xfers to finish */
+	i2c_lock_adapter(&dev->adapter);
+	dev->is_suspended = true;
+	i2c_unlock_adapter(&dev->adapter);
+	return 0;
+}
+
+static int msm_i2c_resume_noirq(struct device *device) {
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_i2c_dev *dev = platform_get_drvdata(pdev);
+
+	/* Block to allow any i2c_xfers to finish */
+	i2c_lock_adapter(&dev->adapter);
+	dev->is_suspended = false;
+	i2c_unlock_adapter(&dev->adapter);
+	return 0;
+}
+
+static struct dev_pm_ops msm_i2c_pm_ops = {
+	.suspend_noirq	= msm_i2c_suspend_noirq,
+	.resume_noirq	= msm_i2c_resume_noirq,
+};
+
+static struct platform_driver msm_i2c_driver = {
+	.probe		= msm_i2c_probe,
+	.remove		= msm_i2c_remove,
+	.driver		= {
+		.name	= "msm_i2c",
+		.owner	= THIS_MODULE,
+		.pm = &msm_i2c_pm_ops,
+	},
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init
+msm_i2c_init_driver(void)
+{
+	return platform_driver_register(&msm_i2c_driver);
+}
+subsys_initcall(msm_i2c_init_driver);
+
+static void __exit msm_i2c_exit_driver(void)
+{
+	platform_driver_unregister(&msm_i2c_driver);
+}
+module_exit(msm_i2c_exit_driver);
+
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
new file mode 100644
index 0000000..9983dd8
--- /dev/null
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -0,0 +1,930 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora Forum nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above.  If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL".  Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms.  In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 and only version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * END
+ *
+ * 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.
+ *
+ */
+/*
+ * QUP driver for Qualcomm MSM platforms
+ *
+ */
+
+/* #define DEBUG */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <mach/msm_qup.h>
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION("0.2");
+MODULE_ALIAS("platform:i2c_qup");
+
+/* QUP Registers */
+enum {
+	QUP_CONFIG              = 0x0,
+	QUP_STATE               = 0x4,
+	QUP_IO_MODE             = 0x8,
+	QUP_SW_RESET            = 0xC,
+	QUP_OPERATIONAL         = 0x18,
+	QUP_ERROR_FLAGS         = 0x1C,
+	QUP_ERROR_FLAGS_EN      = 0x20,
+	QUP_MX_READ_CNT         = 0x208,
+	QUP_MX_INPUT_CNT        = 0x200,
+	QUP_OUT_DEBUG           = 0x108,
+	QUP_OUT_FIFO_CNT        = 0x10C,
+	QUP_OUT_FIFO_BASE       = 0x110,
+	QUP_IN_READ_CUR         = 0x20C,
+	QUP_IN_DEBUG            = 0x210,
+	QUP_IN_FIFO_CNT         = 0x214,
+	QUP_IN_FIFO_BASE        = 0x218,
+	QUP_I2C_CLK_CTL         = 0x400,
+	QUP_I2C_STATUS          = 0x404,
+};
+
+/* QUP States and reset values */
+enum {
+	QUP_RESET_STATE         = 0,
+	QUP_RUN_STATE           = 1U,
+	QUP_STATE_MASK          = 3U,
+	QUP_PAUSE_STATE         = 3U,
+	QUP_STATE_VALID         = 1U << 2,
+	QUP_I2C_MAST_GEN        = 1U << 4,
+	QUP_OPERATIONAL_RESET   = 0xFF0,
+	QUP_I2C_STATUS_RESET    = 0xFFFFFC,
+};
+
+/* I2C mini core related values */
+enum {
+	I2C_MINI_CORE           = 2U << 8,
+	I2C_N_VAL               = 0xF,
+
+};
+
+/* Packing Unpacking words in FIFOs */
+enum {
+	QUP_UNPACK_EN = 1U << 14,
+	QUP_PACK_EN = 1U << 15,
+};
+
+/* QUP tags */
+enum {
+	QUP_OUT_NOP   = 0,
+	QUP_OUT_START = 1U << 8,
+	QUP_OUT_DATA  = 2U << 8,
+	QUP_OUT_STOP  = 3U << 8,
+	QUP_OUT_REC   = 4U << 8,
+	QUP_IN_DATA   = 5U << 8,
+	QUP_IN_STOP   = 6U << 8,
+	QUP_IN_NACK   = 7U << 8,
+};
+
+/* Status, Error flags */
+enum {
+	I2C_STATUS_WR_BUFFER_FULL  = 1U << 0,
+	I2C_STATUS_ERROR_MASK      = 0xfc,
+	QUP_IN_NOT_EMPTY           = 1U << 5,
+	QUP_STATUS_ERROR_MASK      = 0x7F,
+	QUP_STATUS_ERROR_FLAGS     = 0x7C,
+};
+
+struct qup_i2c_dev {
+	struct device                *dev;
+	void __iomem                 *base;		/* virtual */
+	void __iomem                 *gsbi;		/* virtual */
+	int                          in_irq;
+	int                          out_irq;
+	int                          err_irq;
+	struct clk                   *clk;
+	struct clk                   *pclk;
+	struct i2c_adapter           adapter;
+
+	struct i2c_msg               *msg;
+	int                          pos;
+	int                          cnt;
+	int                          err;
+	int                          mode;
+	int                          clk_ctl;
+	int                          out_fifo_sz;
+	int                          in_fifo_sz;
+	int                          out_blk_sz;
+	int                          in_blk_sz;
+	struct msm_qup_i2c_platform_data *pdata;
+	void                         *complete;
+};
+
+#ifdef DEBUG
+static void
+qup_print_status(struct qup_i2c_dev *dev)
+{
+	uint32_t val;
+	val = readl(dev->base+QUP_CONFIG);
+	dev_dbg(dev->dev, "Qup config is :0x%x\n", val);
+	val = readl(dev->base+QUP_STATE);
+	dev_dbg(dev->dev, "Qup state is :0x%x\n", val);
+	val = readl(dev->base+QUP_IO_MODE);
+	dev_dbg(dev->dev, "Qup mode is :0x%x\n", val);
+}
+#else
+static inline void qup_print_status(struct qup_i2c_dev *dev)
+{
+}
+#endif
+
+static irqreturn_t
+qup_i2c_interrupt(int irq, void *devid)
+{
+	struct qup_i2c_dev *dev = devid;
+	uint32_t status = readl(dev->base + QUP_I2C_STATUS);
+	uint32_t status1 = readl(dev->base + QUP_ERROR_FLAGS);
+	int err = 0;
+
+	if (status & I2C_STATUS_ERROR_MASK) {
+		dev_err(dev->dev, "QUP: Got i2c error :0x%x\n", status);
+		err = -status;
+		goto intr_done;
+	}
+
+	if (status1 & 0x7F) {
+		dev_err(dev->dev, "QUP: Got QUP error :0x%x\n", status1);
+		err = -status1;
+		goto intr_done;
+	}
+
+	/* Ignore output buffer empty interrupt for READ transaction */
+	if (dev->msg && dev->msg->flags == I2C_M_RD && irq == dev->out_irq)
+		return IRQ_HANDLED;
+	else if (!dev->msg)
+		return IRQ_HANDLED;
+
+intr_done:
+	dev_dbg(dev->dev, "QUP intr= %d, i2c status=0x%x, qup status = 0x%x\n",
+			irq, status, status1);
+	qup_print_status(dev);
+	dev->err = err;
+	complete(dev->complete);
+	return IRQ_HANDLED;
+}
+
+static int
+qup_i2c_poll_writeready(struct qup_i2c_dev *dev)
+{
+	uint32_t retries = 0;
+
+	while (retries != 2000) {
+		uint32_t status = readl(dev->base + QUP_I2C_STATUS);
+
+		if (!(status & I2C_STATUS_WR_BUFFER_FULL))
+			return 0;
+		if (retries++ == 1000)
+			udelay(100);
+	}
+	qup_print_status(dev);
+	return -ETIMEDOUT;
+}
+
+static int
+qup_i2c_poll_state(struct qup_i2c_dev *dev, uint32_t state)
+{
+	uint32_t retries = 0;
+
+	dev_dbg(dev->dev, "Polling Status for state:0x%x\n", state);
+
+	while (retries != 2000) {
+		uint32_t status = readl(dev->base + QUP_STATE);
+
+		if ((status & (QUP_STATE_VALID | state)) ==
+				(QUP_STATE_VALID | state))
+			return 0;
+		else if (retries++ == 1000)
+			udelay(100);
+	}
+	return -ETIMEDOUT;
+}
+
+#ifdef DEBUG
+static void qup_verify_fifo(struct qup_i2c_dev *dev, uint32_t val,
+				uint32_t addr, int rdwr)
+{
+	if (rdwr)
+		dev_dbg(dev->dev, "RD:Wrote 0x%x to out_ff:0x%x\n", val, addr);
+	else
+		dev_dbg(dev->dev, "WR:Wrote 0x%x to out_ff:0x%x\n", val, addr);
+}
+#else
+static inline void qup_verify_fifo(struct qup_i2c_dev *dev, uint32_t val,
+				uint32_t addr, int rdwr)
+{
+}
+#endif
+
+static void
+qup_issue_read(struct qup_i2c_dev *dev, struct i2c_msg *msg, int *idx,
+		uint32_t carry_over)
+{
+	uint16_t addr = (msg->addr << 1) | 1;
+
+	/* QUP limit 256 bytes per read */
+	if (*idx % 4) {
+		writel(carry_over | ((QUP_OUT_START | addr) << 16),
+		dev->base + QUP_OUT_FIFO_BASE);/* + (*idx-2)); */
+
+		qup_verify_fifo(dev, carry_over |
+			((QUP_OUT_START | addr) << 16), (uint32_t)dev->base
+			+ QUP_OUT_FIFO_BASE + (*idx - 2), 1);
+		writel((QUP_OUT_REC | dev->cnt),
+			dev->base + QUP_OUT_FIFO_BASE);/* + (*idx+2)); */
+
+		qup_verify_fifo(dev, (QUP_OUT_REC | dev->cnt),
+		(uint32_t)dev->base + QUP_OUT_FIFO_BASE + (*idx + 2), 1);
+	} else {
+		writel(((QUP_OUT_REC | dev->cnt) << 16) | QUP_OUT_START | addr,
+			dev->base + QUP_OUT_FIFO_BASE);/* + (*idx)); */
+
+		qup_verify_fifo(dev, QUP_OUT_REC << 16 | dev->cnt << 16 |
+		QUP_OUT_START | addr,
+		(uint32_t)dev->base + QUP_OUT_FIFO_BASE + (*idx), 1);
+	}
+	*idx += 4;
+}
+
+static void
+qup_issue_write(struct qup_i2c_dev *dev, struct i2c_msg *msg, int rem,
+			int *idx, uint32_t *carry_over)
+{
+	int entries = dev->cnt;
+	int i = 0;
+	uint32_t val = 0;
+	uint32_t last_entry = 0;
+	uint16_t addr = msg->addr << 1;
+	if (dev->pos == 0)
+		entries++;
+
+	if (dev->pos == 0) {
+		if (*idx % 4) {
+			writel(*carry_over | ((QUP_OUT_START | addr) << 16),
+					dev->base + QUP_OUT_FIFO_BASE);
+
+			qup_verify_fifo(dev, *carry_over | QUP_OUT_DATA << 16 |
+				addr << 16, (uint32_t)dev->base +
+				QUP_OUT_FIFO_BASE + (*idx) - 2, 0);
+		} else
+			val = QUP_OUT_START | addr;
+		*idx += 2;
+		i++;
+	} else if (*idx % 4) {
+		val = (QUP_OUT_NOP | 1);
+		i++;
+	}
+
+	for (; i < (entries - 1); i++) {
+		if (*idx % 4) {
+			writel(val | ((QUP_OUT_DATA |
+				msg->buf[dev->pos]) << 16),
+				dev->base + QUP_OUT_FIFO_BASE);
+
+			qup_verify_fifo(dev, val | QUP_OUT_DATA << 16 |
+				msg->buf[dev->pos] << 16, (uint32_t)dev->base +
+				QUP_OUT_FIFO_BASE + (*idx) - 2, 0);
+		} else
+			val = QUP_OUT_DATA | msg->buf[dev->pos];
+		(*idx) += 2;
+		dev->pos++;
+	}
+	if (dev->pos < (dev->cnt - 1))
+		last_entry = QUP_OUT_DATA;
+	else if (rem > 1) /* not last array entry */
+		last_entry = QUP_OUT_DATA;
+	else
+		last_entry = QUP_OUT_STOP;
+	if ((*idx % 4) == 0) {
+		/*
+		 * If read-start and read-command end up in different fifos, it
+		 * may result in extra-byte being read due to extra-read cycle.
+		 * Avoid that by inserting NOP as the last entry of fifo only
+		 * if write command(s) leave 1 space in fifo.
+		 */
+		if (rem > 1) {
+			struct i2c_msg *next = msg + 1;
+			if (next->addr == msg->addr && (next->flags | I2C_M_RD)
+				&& *idx == ((dev->out_fifo_sz*2) - 4)) {
+				writel(((last_entry | msg->buf[dev->pos]) |
+					((1 | QUP_OUT_NOP) << 16)), dev->base +
+					QUP_OUT_FIFO_BASE);/* + (*idx) - 2); */
+				*idx += 2;
+			} else
+				*carry_over = (last_entry | msg->buf[dev->pos]);
+		} else {
+			writel((last_entry | msg->buf[dev->pos]),
+			dev->base + QUP_OUT_FIFO_BASE);/* + (*idx) - 2); */
+
+			qup_verify_fifo(dev, last_entry | msg->buf[dev->pos],
+			(uint32_t)dev->base + QUP_OUT_FIFO_BASE +
+			(*idx), 0);
+		}
+	} else {
+		writel(val | ((last_entry | msg->buf[dev->pos]) << 16),
+		dev->base + QUP_OUT_FIFO_BASE);/* + (*idx) - 2); */
+
+		qup_verify_fifo(dev, val | (last_entry << 16) |
+		(msg->buf[dev->pos] << 16), (uint32_t)dev->base +
+		QUP_OUT_FIFO_BASE + (*idx) - 2, 0);
+	}
+
+	*idx += 2;
+	dev->pos++;
+	dev->cnt = msg->len - dev->pos;
+}
+
+static int
+qup_update_state(struct qup_i2c_dev *dev, uint32_t state)
+{
+	if (qup_i2c_poll_state(dev, 0) != 0)
+		return -EIO;
+	writel(state, dev->base + QUP_STATE);
+	if (qup_i2c_poll_state(dev, state) != 0)
+		return -EIO;
+	return 0;
+}
+
+static int
+qup_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	DECLARE_COMPLETION_ONSTACK(complete);
+	struct qup_i2c_dev *dev = i2c_get_adapdata(adap);
+	int ret;
+	int rem = num;
+	long timeout;
+	int err;
+
+	/* Initialize QUP registers during first transfer */
+	if (dev->clk_ctl == 0) {
+		int fs_div;
+		int hs_div;
+		int i2c_clk;
+		uint32_t fifo_reg;
+		writel(0x2 << 4, dev->gsbi);
+
+		i2c_clk = 19200000; /* input clock */
+		fs_div = ((i2c_clk / dev->pdata->clk_freq) / 2) - 3;
+		hs_div = 3;
+		dev->clk_ctl = ((hs_div & 0x7) << 8) | (fs_div & 0xff);
+		fifo_reg = readl(dev->base + QUP_IO_MODE);
+		if (fifo_reg & 0x3)
+			dev->out_blk_sz = (fifo_reg & 0x3) * 16;
+		else
+			dev->out_blk_sz = 16;
+		if (fifo_reg & 0x60)
+			dev->in_blk_sz = ((fifo_reg & 0x60) >> 5) * 16;
+		else
+			dev->in_blk_sz = 16;
+		/*
+		 * The block/fifo size w.r.t. 'actual data' is 1/2 due to 'tag'
+		 * associated with each byte written/received
+		 */
+		dev->out_blk_sz /= 2;
+		dev->in_blk_sz /= 2;
+		dev->out_fifo_sz = dev->out_blk_sz *
+					(2 << ((fifo_reg & 0x1C) >> 2));
+		dev->in_fifo_sz = dev->in_blk_sz *
+					(2 << ((fifo_reg & 0x380) >> 7));
+		dev_dbg(dev->dev, "QUP IN:bl:%d, ff:%d, OUT:bl:%d, ff:%d\n",
+				dev->in_blk_sz, dev->in_fifo_sz,
+				dev->out_blk_sz, dev->out_fifo_sz);
+	}
+
+	enable_irq(dev->in_irq);
+	enable_irq(dev->out_irq);
+	enable_irq(dev->err_irq);
+	writel(QUP_RESET_STATE, dev->base + QUP_STATE);
+	ret = qup_i2c_poll_state(dev, QUP_RESET_STATE);
+	if (ret) {
+		dev_err(dev->dev, "QUP Busy:Trying to recover\n");
+		goto out_err;
+	}
+
+	/* Initialize QUP registers */
+	writel(1, dev->base + QUP_SW_RESET);
+	writel(0, dev->base + QUP_CONFIG);
+	writel(QUP_OPERATIONAL_RESET, dev->base + QUP_OPERATIONAL);
+	writel(QUP_STATUS_ERROR_FLAGS, dev->base + QUP_ERROR_FLAGS_EN);
+
+	writel(QUP_PACK_EN | QUP_UNPACK_EN, dev->base + QUP_IO_MODE);
+	writel(I2C_MINI_CORE | I2C_N_VAL, dev->base + QUP_CONFIG);
+
+	/* Initialize I2C mini core registers */
+	writel(0, dev->base + QUP_I2C_CLK_CTL);
+	writel(QUP_I2C_STATUS_RESET, dev->base + QUP_I2C_STATUS);
+
+	dev->cnt = msgs->len;
+	dev->pos = 0;
+	dev->msg = msgs;
+	while (rem) {
+		bool filled = false;
+
+		/* Wait for WR buffer not full */
+		ret = qup_i2c_poll_writeready(dev);
+		if (ret) {
+			dev_err(dev->dev,
+				"Error waiting for write ready before addr\n");
+			goto out_err;
+		}
+
+		dev->err = 0;
+		dev->complete = &complete;
+
+		if (qup_i2c_poll_state(dev, QUP_I2C_MAST_GEN) != 0) {
+			ret = -EIO;
+			goto out_err;
+		}
+
+		qup_print_status(dev);
+		/* HW limits Read upto 256 bytes in 1 read without stop
+		 * only FIFO mode supported right now, so read size of
+		 * in_fifo supported in 1 read
+		 */
+		if (dev->msg->flags == I2C_M_RD) {
+			if (dev->cnt > dev->in_fifo_sz) {
+				dev_err(dev->dev, "No Block mode support\n");
+				ret = -EPROTONOSUPPORT;
+				goto out_err;
+			}
+			writel(dev->cnt, dev->base + QUP_MX_READ_CNT);
+		} else {
+			if (dev->cnt > dev->out_fifo_sz) {
+				dev_err(dev->dev, "No Block mode support\n");
+				ret = -EPROTONOSUPPORT;
+				goto out_err;
+			} else if (rem > 1) {
+				struct i2c_msg *next = msgs + 1;
+				if (next->addr == msgs->addr &&
+					next->flags == I2C_M_RD) {
+					if (next->len > dev->in_fifo_sz) {
+						dev_err(dev->dev,
+						"No Block mode support\n");
+						ret = -EPROTONOSUPPORT;
+						goto out_err;
+					}
+					writel(next->len, dev->base +
+							QUP_MX_READ_CNT);
+				}
+			}
+		}
+
+		err = qup_update_state(dev, QUP_RUN_STATE);
+		if (err < 0) {
+			ret = err;
+			goto out_err;
+		}
+
+		qup_print_status(dev);
+		writel(dev->clk_ctl, dev->base + QUP_I2C_CLK_CTL);
+
+		do {
+			int idx = 0;
+			uint32_t carry_over = 0;
+
+			/* Transition to PAUSE state only possible from RUN */
+			err = qup_update_state(dev, QUP_PAUSE_STATE);
+			if (err < 0) {
+				ret = err;
+				goto out_err;
+			}
+
+			qup_print_status(dev);
+			/* This operation is Write, check the next operation
+			 * and decide mode
+			 */
+			while (filled == false) {
+				if (msgs->flags & I2C_M_RD)
+					qup_issue_read(dev, msgs, &idx,
+							carry_over);
+				else
+					qup_issue_write(dev, msgs, rem, &idx,
+							&carry_over);
+				if (idx >= dev->out_fifo_sz)
+					filled = true;
+				/* Start new message */
+				if (filled == false) {
+					if (msgs->flags & I2C_M_RD)
+							filled = true;
+					else if (rem > 1) {
+						/* Only combine operations with
+						 * same address
+						 */
+						struct i2c_msg *next = msgs + 1;
+						if (next->addr != msgs->addr)
+							filled = true;
+						else {
+							rem--;
+							msgs++;
+							dev->msg = msgs;
+							dev->pos = 0;
+							dev->cnt = msgs->len;
+						}
+					} else
+						filled = true;
+				}
+			}
+			err = qup_update_state(dev, QUP_RUN_STATE);
+			if (err < 0) {
+				ret = err;
+				goto out_err;
+			}
+			dev_dbg(dev->dev, "idx:%d, rem:%d, num:%d, mode:%d\n",
+				idx, rem, num, dev->mode);
+
+			qup_print_status(dev);
+			timeout = wait_for_completion_timeout(&complete,
+					msecs_to_jiffies(dev->out_fifo_sz));
+			if (!timeout) {
+				dev_err(dev->dev, "Transaction timed out\n");
+				writel(1, dev->base + QUP_SW_RESET);
+				msleep(10);
+				ret = -ETIMEDOUT;
+				goto out_err;
+			}
+			if (dev->err) {
+				dev_err(dev->dev,
+					"Error during data xfer (%d)\n",
+					dev->err);
+				ret = dev->err;
+				goto out_err;
+			}
+			if (dev->msg->flags & I2C_M_RD) {
+				int i;
+				uint32_t dval = 0;
+				for (i = 0; dev->pos < dev->msg->len; i++,
+						dev->pos++) {
+					uint32_t rd_status = readl(dev->base +
+							QUP_OPERATIONAL);
+					if (i % 2 == 0) {
+						if ((rd_status &
+							QUP_IN_NOT_EMPTY) == 0)
+							break;
+						dval = readl(dev->base +
+							QUP_IN_FIFO_BASE);
+						dev->msg->buf[dev->pos] =
+							dval & 0xFF;
+					} else
+						dev->msg->buf[dev->pos] =
+							((dval & 0xFF0000) >>
+							 16);
+				}
+				dev->cnt -= i;
+			} else
+				filled = false; /* refill output FIFO */
+		} while (dev->cnt > 0);
+		if (dev->cnt == 0) {
+			rem--;
+			msgs++;
+			if (rem) {
+				dev->pos = 0;
+				dev->cnt = msgs->len;
+				dev->msg = msgs;
+			}
+		}
+	}
+
+	ret = num;
+ out_err:
+	dev->complete = NULL;
+	dev->msg = NULL;
+	dev->pos = 0;
+	dev->err = 0;
+	dev->cnt = 0;
+	disable_irq(dev->err_irq);
+	disable_irq(dev->in_irq);
+	disable_irq(dev->out_irq);
+	return ret;
+}
+
+static u32
+qup_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm qup_i2c_algo = {
+	.master_xfer	= qup_i2c_xfer,
+	.functionality	= qup_i2c_func,
+};
+
+static int __devinit
+qup_i2c_probe(struct platform_device *pdev)
+{
+	struct qup_i2c_dev	*dev;
+	struct resource         *qup_mem, *gsbi_mem, *qup_io, *gsbi_io;
+	struct resource		*in_irq, *out_irq, *err_irq;
+	struct clk         *clk, *pclk;
+	int ret = 0;
+	struct msm_qup_i2c_platform_data *pdata;
+
+	dev_dbg(&pdev->dev, "qup_i2c_probe\n");
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform data not initialized\n");
+		return -ENOSYS;
+	}
+	qup_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"qup_phys_addr");
+	if (!qup_mem) {
+		dev_err(&pdev->dev, "no qup mem resource?\n");
+		return -ENODEV;
+	}
+	gsbi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"gsbi_qup_i2c_addr");
+	if (!gsbi_mem) {
+		dev_err(&pdev->dev, "no gsbi mem resource?\n");
+		return -ENODEV;
+	}
+
+	in_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+						"qup_in_intr");
+	if (!in_irq) {
+		dev_err(&pdev->dev, "no input irq resource?\n");
+		return -ENODEV;
+	}
+	out_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+						"qup_out_intr");
+	if (!out_irq) {
+		dev_err(&pdev->dev, "no output irq resource?\n");
+		return -ENODEV;
+	}
+	err_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+						"qup_err_intr");
+	if (!err_irq) {
+		dev_err(&pdev->dev, "no error irq resource?\n");
+		return -ENODEV;
+	}
+
+	qup_io = request_mem_region(qup_mem->start, resource_size(qup_mem),
+					pdev->name);
+	if (!qup_io) {
+		dev_err(&pdev->dev, "QUP region already claimed\n");
+		return -EBUSY;
+	}
+	gsbi_io = request_mem_region(gsbi_mem->start, resource_size(gsbi_mem),
+					pdev->name);
+	if (!gsbi_io) {
+		dev_err(&pdev->dev, "GSBI region already claimed\n");
+		return -EBUSY;
+	}
+
+	clk = clk_get(&pdev->dev, "qup_clk");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Could not get clock\n");
+		ret = PTR_ERR(clk);
+		goto err_clk_get_failed;
+	}
+
+	pclk = clk_get(&pdev->dev, "qup_pclk");
+	if (IS_ERR(clk))
+		pclk = NULL;
+
+	if (!(pdata->msm_i2c_config_gpio)) {
+		dev_err(&pdev->dev, "config_gpio function not initialized\n");
+		ret = -ENOSYS;
+		goto err_config_failed;
+	}
+
+	/* We support frequencies upto FAST Mode(400KHz) */
+	if (pdata->clk_freq <= 0 ||
+			pdata->clk_freq > 400000) {
+		dev_err(&pdev->dev, "clock frequency not supported\n");
+		ret = -EIO;
+		goto err_config_failed;
+	}
+
+	dev = kzalloc(sizeof(struct qup_i2c_dev), GFP_KERNEL);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err_alloc_dev_failed;
+	}
+
+	dev->dev = &pdev->dev;
+	dev->in_irq = in_irq->start;
+	dev->out_irq = out_irq->start;
+	dev->err_irq = err_irq->start;
+	dev->clk = clk;
+	dev->pclk = pclk;
+	dev->base = ioremap(qup_mem->start, resource_size(qup_mem));
+	if (!dev->base) {
+		ret = -ENOMEM;
+		goto err_ioremap_failed;
+	}
+
+	/* Configure GSBI block to use I2C functionality */
+	dev->gsbi = ioremap(gsbi_mem->start, resource_size(gsbi_mem));
+	if (!dev->gsbi) {
+		ret = -ENOMEM;
+		goto err_gsbi_failed;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	clk_enable(clk);
+	if (pclk)
+		clk_enable(pclk);
+	dev->pdata = pdata;
+	dev->clk_ctl = 0;
+
+	i2c_set_adapdata(&dev->adapter, dev);
+	dev->adapter.algo = &qup_i2c_algo;
+	strlcpy(dev->adapter.name,
+		"QUP I2C adapter",
+		sizeof(dev->adapter.name));
+
+	dev->adapter.nr = pdev->id;
+	ret = i2c_add_numbered_adapter(&dev->adapter);
+	if (ret) {
+		dev_err(&pdev->dev, "i2c_add_adapter failed\n");
+		goto err_i2c_add_adapter_failed;
+	}
+
+	ret = request_irq(dev->in_irq, qup_i2c_interrupt,
+			IRQF_TRIGGER_RISING, "qup_in_intr", dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request_out_irq failed\n");
+		goto err_request_irq_failed;
+	}
+	ret = request_irq(dev->out_irq, qup_i2c_interrupt,
+			IRQF_TRIGGER_RISING, "qup_out_intr", dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request_in_irq failed\n");
+		free_irq(dev->in_irq, dev);
+		goto err_request_irq_failed;
+	}
+	ret = request_irq(dev->err_irq, qup_i2c_interrupt,
+			IRQF_TRIGGER_RISING, "qup_err_intr", dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request_err_irq failed\n");
+		free_irq(dev->out_irq, dev);
+		free_irq(dev->in_irq, dev);
+		goto err_request_irq_failed;
+	}
+	disable_irq(dev->err_irq);
+	disable_irq(dev->in_irq);
+	disable_irq(dev->out_irq);
+	pdata->msm_i2c_config_gpio(dev->adapter.nr, 1);
+
+	return 0;
+
+err_request_irq_failed:
+	i2c_del_adapter(&dev->adapter);
+err_i2c_add_adapter_failed:
+	clk_disable(clk);
+	if (pclk)
+		clk_disable(pclk);
+	iounmap(dev->gsbi);
+err_gsbi_failed:
+	iounmap(dev->base);
+err_ioremap_failed:
+	kfree(dev);
+err_alloc_dev_failed:
+err_config_failed:
+	clk_put(clk);
+	if (pclk)
+		clk_put(pclk);
+err_clk_get_failed:
+	release_mem_region(gsbi_mem->start, resource_size(gsbi_mem));
+	release_mem_region(qup_mem->start, resource_size(qup_mem));
+	return ret;
+}
+
+static int __devexit
+qup_i2c_remove(struct platform_device *pdev)
+{
+	struct qup_i2c_dev	*dev = platform_get_drvdata(pdev);
+	struct resource		*qup_mem, *gsbi_mem;
+
+	platform_set_drvdata(pdev, NULL);
+	free_irq(dev->out_irq, dev);
+	free_irq(dev->in_irq, dev);
+	free_irq(dev->err_irq, dev);
+	i2c_del_adapter(&dev->adapter);
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+	if (dev->pclk) {
+		clk_disable(dev->pclk);
+		clk_put(dev->pclk);
+	}
+	iounmap(dev->gsbi);
+	iounmap(dev->base);
+	kfree(dev);
+	gsbi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"gsbi_qup_i2c_addr");
+	release_mem_region(gsbi_mem->start, resource_size(gsbi_mem));
+	qup_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"qup_phys_addr");
+	release_mem_region(qup_mem->start, resource_size(qup_mem));
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int qup_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
+
+	clk_disable(dev->clk);
+	if (dev->pclk)
+		clk_disable(dev->pclk);
+	return 0;
+}
+
+static int qup_i2c_resume(struct platform_device *pdev)
+{
+	struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
+
+	clk_enable(dev->clk);
+	if (dev->pclk)
+		clk_enable(dev->pclk);
+	return 0;
+}
+#else
+#define qup_i2c_suspend NULL
+#define qup_i2c_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver qup_i2c_driver = {
+	.probe		= qup_i2c_probe,
+	.remove		= __devexit_p(qup_i2c_remove),
+	.suspend	= qup_i2c_suspend,
+	.resume		= qup_i2c_resume,
+	.driver		= {
+		.name	= "qup_i2c",
+		.owner	= THIS_MODULE,
+	},
+};
+
+/* QUP may be needed to bring up other drivers */
+static int __init
+qup_i2c_init_driver(void)
+{
+	return platform_driver_register(&qup_i2c_driver);
+}
+subsys_initcall(qup_i2c_init_driver);
+
+static void __exit qup_i2c_exit_driver(void)
+{
+	platform_driver_unregister(&qup_i2c_driver);
+}
+module_exit(qup_i2c_exit_driver);
+
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
new file mode 100644
index 0000000..f58e49a
--- /dev/null
+++ b/drivers/i2c/chips/Kconfig
@@ -0,0 +1,16 @@
+#
+# Miscellaneous I2C chip drivers configuration
+#
+# *** DEPRECATED! Do not add new entries! See Makefile ***
+#
+
+menu "Miscellaneous I2C Chip support"
+
+config SENSORS_MT9T013
+	tristate "MT9T013 Camera Driver"
+	depends on I2C
+	default y
+	help
+	 MT9T013 Camera Driver implemented by HTC.
+
+endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
new file mode 100644
index 0000000..23b7b7b
--- /dev/null
+++ b/drivers/i2c/chips/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for miscellaneous I2C chip drivers.
+#
+# Do not add new drivers to this directory! It is DEPRECATED.
+#
+# Device drivers are better grouped according to the functionality they
+# implement rather than to the bus they are connected to. In particular:
+# * Hardware monitoring chip drivers go to drivers/hwmon
+# * RTC chip drivers go to drivers/rtc
+# * I/O expander drivers go to drivers/gpio
+#
+
+obj-$(CONFIG_SENSORS_MT9T013)	+= mt9t013.o
+
+ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/i2c/chips/mt9t013.c b/drivers/i2c/chips/mt9t013.c
new file mode 100755
index 0000000..200a9f8
--- /dev/null
+++ b/drivers/i2c/chips/mt9t013.c
@@ -0,0 +1,1351 @@
+/*
+ * Copyright (C) 2007-2008 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/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/clk.h>
+#include <linux/wakelock.h>
+#include <net/sock.h>
+#include <asm/gpio.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/vreg.h>
+#include <mach/board.h>
+#include <linux/mt9t013.h> /* define ioctls */
+
+
+#define ALLOW_USPACE_RW		0
+
+static const uint32_t fps_divider = 1;
+
+#define AF_I2C_ID	0x18  /* actuator's slave address */
+
+static struct i2c_client *pclient;
+
+/* we need this to set the clock rate */
+static struct clk *vfe_clk;
+
+/* camif clocks */
+static struct clk *vfe_mdc_clk;
+static struct clk *mdc_clk;
+
+static int mdc_clk_enabled;
+static int vfe_mdc_clk_enabled;
+static int vfe_clk_enabled;
+static int opened;
+static int pclk_set;
+
+static const struct mt9t013_reg_pat mt9t013_reg_pattern = { .reg = {
+	{ /* preview 2x2 binning 20fps, pclk MHz, MCLK 24MHz */
+		10,	/*vt_pix_clk_div        REG=0x0300*/
+			/*update get_snapshot_fps if this change*/
+		1,	/*vt_sys_clk_div        REG=0x0302*/
+			/*update get_snapshot_fps if this change*/
+		3,	/*2,  pre_pll_clk_div   REG=0x0304*/
+			/*update get_snapshot_fps if this change*/
+		80,	/*40, pll_multiplier   REG=0x0306*/
+			/*60 for 30fps preview, 40 for 20fps preview*/
+		10,	/*op_pix_clk_div        REG=0x0308*/
+		1,	/*op_sys_clk_div        REG=0x030A*/
+		16,	/*scale_m       REG=0x0404*/
+		0x0111,	/*row_speed     REG=0x3016*/
+		8,	/*x_addr_start  REG=0x3004*/
+		2053,	/*x_addr_end    REG=0x3008*/
+		8,	/*y_addr_start  REG=0x3002*/
+		1541,	/*y_addr_end    REG=0x3006*/
+		0x046C,	/*read_mode     REG=0x3040*/
+		1024,	/*x_output_size REG=0x034C*/
+		768,	/*y_output_size REG=0x034E*/
+		3540,	/*2616,        line_length_pck       REG=0x300C*/
+		861,	/*916, frame_length_lines     REG=0x300A*/
+		16,	/*coarse_integration_time     REG=0x3012*/
+		1461	/*fine_integration_time REG=0x3014*/
+	},
+	{ /* snapshot */
+		10,	/*vt_pix_clk_div        REG=0x0300*/
+			/*update get_snapshot_fps if this change*/
+		1,	/*vt_sys_clk_div        REG=0x0302*/
+			/*update get_snapshot_fps if this change*/
+		3,	/*2,  pre_pll_clk_div   REG=0x0304*/
+			/*update get_snapshot_fps if this change*/
+		80,	/*40, pll_multiplier   REG=0x0306*/
+			/*50 for 15fps snapshot, 40 for 10fps snapshot*/
+		10,	/*op_pix_clk_div        REG=0x0308*/
+		1,	/*op_sys_clk_div        REG=0x030A*/
+		16,	/*scale_m       REG=0x0404*/
+		0x0111,	/*row_speed     REG=0x3016*/
+		8,	/*0,     x_addr_start  REG=0x3004*/
+		2063,	/*2061,       x_addr_end    REG=0x3008*/
+		8,	/*2,     y_addr_start  REG=0x3002*/
+		1551,	/*1545,       y_addr_end    REG=0x3006*/
+		0x0024,	/*read_mode     REG=0x3040*/
+		2063,	/*output_size REG=0x034C*/
+		1544,	/*y_output_size REG=0x034E*/
+		4800,	/*2952,        line_length_pck       REG=0x300C*/
+		1629,	/*frame_length_lines    REG=0x300A*/
+		16,	/*coarse_integration_time       REG=0x3012*/
+		733	/*fine_integration_time REG=0x3014*/
+	}
+}};
+
+#define MT9T013_MU3M0VC_REG_MODEL_ID		0x0000
+#define MT9T013_MU3M0VC_MODEL_ID		0x2600
+#define REG_GROUPED_PARAMETER_HOLD		0x0104
+#define GROUPED_PARAMETER_HOLD			0x0100
+#define GROUPED_PARAMETER_UPDATE		0x0000
+#define REG_COARSE_INTEGRATION_TIME		0x3012
+#define REG_VT_PIX_CLK_DIV			0x0300
+#define REG_VT_SYS_CLK_DIV			0x0302
+#define REG_PRE_PLL_CLK_DIV			0x0304
+#define REG_PLL_MULTIPLIER			0x0306
+#define REG_OP_PIX_CLK_DIV			0x0308
+#define REG_OP_SYS_CLK_DIV			0x030A
+#define REG_SCALE_M				0x0404
+#define REG_FRAME_LENGTH_LINES			0x300A
+#define REG_LINE_LENGTH_PCK			0x300C
+#define REG_X_ADDR_START			0x3004
+#define REG_Y_ADDR_START			0x3002
+#define REG_X_ADDR_END				0x3008
+#define REG_Y_ADDR_END				0x3006
+#define REG_X_OUTPUT_SIZE			0x034C
+#define REG_Y_OUTPUT_SIZE			0x034E
+#define REG_FINE_INTEGRATION_TIME		0x3014
+#define REG_ROW_SPEED				0x3016
+#define MT9T013_REG_RESET_REGISTER		0x301A
+#define MT9T013_RESET_REGISTER_PWON		0x10CC   /*enable paralled and start streaming*/
+#define MT9T013_RESET_REGISTER_PWOFF		0x1008 //0x10C8   /*stop streaming*/
+#define REG_READ_MODE				0x3040
+#define REG_GLOBAL_GAIN				0x305E
+#define REG_TEST_PATTERN_MODE			0x3070
+
+static struct wake_lock mt9t013_wake_lock;
+
+static inline void init_suspend(void)
+{
+	wake_lock_init(&mt9t013_wake_lock, WAKE_LOCK_IDLE, "mt9t013");
+}
+
+static inline void deinit_suspend(void)
+{
+	wake_lock_destroy(&mt9t013_wake_lock);
+}
+
+static inline void prevent_suspend(void)
+{
+	wake_lock(&mt9t013_wake_lock);
+}
+
+static inline void allow_suspend(void)
+{
+	wake_unlock(&mt9t013_wake_lock);
+}
+
+#define CLK_GET(clk) do {						\
+	if (!clk) {							\
+		clk = clk_get(NULL, #clk);				\
+		printk(KERN_INFO 					\
+			"mt9t013: clk_get(%s): %p\n", #clk, clk);	\
+	}								\
+} while(0)
+
+DECLARE_MUTEX(sem);
+
+static struct msm_camera_legacy_device_platform_data  *cam;
+
+#define out_dword(addr, val) \
+	(*((volatile unsigned long  *)(addr)) = ((unsigned long)(val)))
+
+#define out_dword_masked_ns(io, mask, val, current_reg_content)	    \
+  (void) out_dword(io, ((current_reg_content & (uint32_t)(~(mask))) | \
+			 ((uint32_t)((val) & (mask)))))
+
+#define __inpdw(port) (*((volatile uint32_t *) (port)))
+#define in_dword_masked(addr, mask) (__inpdw(addr) & (uint32_t)mask )
+
+#define HWIO_MDDI_CAMIF_CFG_ADDR MSM_MDC_BASE
+#define HWIO_MDDI_CAMIF_CFG_RMSK 0x1fffff
+#define HWIO_MDDI_CAMIF_CFG_IN \
+  in_dword_masked(HWIO_MDDI_CAMIF_CFG_ADDR, HWIO_MDDI_CAMIF_CFG_RMSK)
+
+#define HWIO_MDDI_CAMIF_CFG_OUTM(m,v) \
+  out_dword_masked_ns(HWIO_MDDI_CAMIF_CFG_ADDR,m,v,HWIO_MDDI_CAMIF_CFG_IN);
+#define __msmhwio_outm(hwiosym, mask, val) HWIO_##hwiosym##_OUTM(mask, val)
+#define HWIO_OUTM(hwiosym, mask, val) __msmhwio_outm(hwiosym, mask, val)
+
+#define HWIO_MDDI_CAMIF_CFG_CAM_SEL_BMSK 0x2
+#define HWIO_MDDI_CAMIF_CFG_CAM_PCLK_SRC_SEL_BMSK 0x60000
+#define HWIO_MDDI_CAMIF_CFG_CAM_PCLK_INVERT_BMSK 0x80000
+#define HWIO_MDDI_CAMIF_CFG_CAM_PAD_REG_SW_RESET_BMSK 0x100000
+
+#define HWIO_MDDI_CAMIF_CFG_CAM_SEL_SHFT 0x1
+#define HWIO_MDDI_CAMIF_CFG_CAM_PCLK_SRC_SEL_SHFT 0x11
+#define HWIO_MDDI_CAMIF_CFG_CAM_PCLK_INVERT_SHFT 0x13
+#define HWIO_MDDI_CAMIF_CFG_CAM_PAD_REG_SW_RESET_SHFT 0x14
+
+#define __msmhwio_shft(hwio_regsym, hwio_fldsym) HWIO_##hwio_regsym##_##hwio_fldsym##_SHFT
+#define HWIO_SHFT(hwio_regsym, hwio_fldsym) __msmhwio_shft(hwio_regsym, hwio_fldsym)
+
+#define __msmhwio_fmsk(hwio_regsym, hwio_fldsym) HWIO_##hwio_regsym##_##hwio_fldsym##_BMSK
+#define HWIO_FMSK(hwio_regsym, hwio_fldsym) __msmhwio_fmsk(hwio_regsym, hwio_fldsym)
+
+#define HWIO_APPS_RESET_ADDR (MSM_CLK_CTL_BASE + 0x00000210)
+#define HWIO_APPS_RESET_RMSK 0x1fff
+#define HWIO_APPS_RESET_VFE_BMSK 1
+#define HWIO_APPS_RESET_VFE_SHFT 0 
+#define HWIO_APPS_RESET_IN in_dword_masked(HWIO_APPS_RESET_ADDR, HWIO_APPS_RESET_RMSK)
+#define HWIO_APPS_RESET_OUTM(m,v) out_dword_masked_ns(HWIO_APPS_RESET_ADDR,m,v,HWIO_APPS_RESET_IN)
+
+struct mt9t013_data {
+	struct work_struct work;
+};
+
+static DECLARE_WAIT_QUEUE_HEAD(g_data_ready_wait_queue);
+
+static int mt9t013_i2c_sensor_init(struct mt9t013_init *init);
+static int mt9t013_i2c_sensor_setting(unsigned long arg);
+static int mt9t013_i2c_exposure_gain(uint32_t mode, uint16_t line,
+					uint16_t gain);
+static int mt9t013_i2c_move_focus(uint16_t position);
+static int mt9t013_i2c_set_default_focus(uint8_t step);
+static int mt9t013_i2c_power_up(void);
+static int mt9t013_i2c_power_down(void);
+static int mt9t013_camif_pad_reg_reset(void);
+static int mt9t013_lens_power(int on);
+
+int mt_i2c_lens_tx_data(unsigned char slave_addr, char* txData, int length)
+{
+	int rc;
+	struct i2c_msg msg[] = {
+		{
+			.addr = slave_addr,
+			.flags = 0,
+			.len = length,
+			.buf = txData,		
+		},
+	};
+
+#if 0
+	{
+		int i;
+		/* printk(KERN_INFO "mt_i2c_lens_tx_data: af i2c client addr = %x,"
+		   " register addr = 0x%02x%02x:\n", slave_addr, txData[0], txData[1]); 
+		*/
+		for (i = 0; i < length - 2; i++)
+			printk(KERN_INFO "\tdata[%d]: 0x%02x\n", i, txData[i+2]);
+	}
+#endif
+    
+	rc = i2c_transfer(pclient->adapter, msg, 1);
+	if (rc < 0) {
+		printk(KERN_ERR "mt_i2c_lens_tx_data: i2c_transfer error %d\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
+static int mt9t013_i2c_lens_write(unsigned char slave_addr, unsigned char u_addr, unsigned char u_data)
+{
+	unsigned char buf[2] = { u_addr, u_data };
+	return mt_i2c_lens_tx_data(slave_addr, buf, sizeof(buf));
+}
+
+static int mt_i2c_rx_data(char* rxData, int length)
+{
+	int rc;
+	struct i2c_msg msgs[] = {
+		{
+			.addr = pclient->addr,
+			.flags = 0,      
+			.len = 2,
+			.buf = rxData,
+		},
+		{
+			.addr = pclient->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = rxData,
+		},
+	};
+
+	rc = i2c_transfer(pclient->adapter, msgs, 2);
+	if (rc < 0) {
+		printk(KERN_ERR "mt9t013: mt_i2c_rx_data error %d\n", rc);
+		return rc;
+	}
+#if 0
+	else {
+		int i;
+		for (i = 0; i < length; i++)
+			printk(KERN_INFO "\tdata[%d]: 0x%02x\n", i, rxData[i]);
+	}
+#endif
+
+	return 0;
+}
+
+int mt_i2c_tx_data(char* txData, int length)
+{
+	int rc; 
+
+	struct i2c_msg msg[] = {
+		{
+			.addr = pclient->addr,
+			.flags = 0,
+			.len = length,
+			.buf = txData,		
+		},
+	};
+    
+	rc = i2c_transfer(pclient->adapter, msg, 1);
+	if (rc < 0) {
+		printk(KERN_ERR "mt9t013: mt_i2c_tx_data error %d\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
+static int mt9t013_i2c_write(unsigned short u_addr, unsigned short u_data)
+{
+	int rc;
+	unsigned char buf[4];
+
+	buf[0] = (u_addr & 0xFF00) >> 8;
+	buf[1] = u_addr & 0x00FF;
+	buf[2] = (u_data & 0xFF00) >> 8;
+	buf[3] = u_data & 0x00FF;
+
+	rc = mt_i2c_tx_data(buf, sizeof(buf));
+	if(rc < 0)
+		printk(KERN_ERR "mt9t013: txdata error %d add:0x%02x data:0x%02x\n",
+			rc, u_addr, u_data);
+	return rc;	
+}
+
+static int mt9t013_i2c_read(unsigned short u_addr, unsigned short *pu_data)
+{
+	int rc;
+	unsigned char buf[2];
+
+	buf[0] = (u_addr & 0xFF00)>>8;
+	buf[1] = (u_addr & 0x00FF);
+	rc = mt_i2c_rx_data(buf, 2);
+	if (!rc)
+		*pu_data = buf[0]<<8 | buf[1];
+	else printk(KERN_ERR "mt9t013: i2c read failed\n");
+	return rc;	
+}
+
+static int msm_camio_clk_enable (int clk_type)
+{
+	struct clk *clk = NULL;
+	int *enabled = NULL;
+
+	switch (clk_type) {
+	case CAMIO_VFE_MDC_CLK:
+		CLK_GET(vfe_mdc_clk);
+		clk = vfe_mdc_clk;
+		enabled = &vfe_mdc_clk_enabled;
+		break;
+	case CAMIO_MDC_CLK:
+		CLK_GET(mdc_clk);
+		clk = mdc_clk;
+		enabled = &mdc_clk_enabled;
+		break;
+	default:
+		break;
+	}
+
+	if (clk != NULL && !*enabled) {
+		int rc = clk_enable(clk);
+		*enabled = !rc;	
+		return rc;
+	}
+
+	return -EINVAL; 
+}
+
+static int msm_camio_clk_disable(int clk_type)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+	int *enabled = NULL;
+
+	switch (clk_type) {
+	case CAMIO_VFE_MDC_CLK:
+		clk = vfe_mdc_clk;
+		enabled = &vfe_mdc_clk_enabled;
+		break;
+	case CAMIO_MDC_CLK:
+		clk = mdc_clk;
+		enabled = &mdc_clk_enabled;
+		break;
+	default:
+		rc = -1;
+		break;
+	}
+
+	if (clk != NULL && *enabled) {
+		clk_disable(clk);
+		*enabled = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int msm_camio_vfe_clk_enable(void)
+{
+	CLK_GET(vfe_clk);
+	if (vfe_clk && !vfe_clk_enabled) {
+		vfe_clk_enabled = !clk_enable(vfe_clk);
+		printk(KERN_INFO "mt9t013: enable vfe_clk\n");
+	}
+	return vfe_clk_enabled ? 0 : -EIO;
+}
+
+static int msm_camio_clk_rate_set(int rate)
+{
+	int rc = msm_camio_vfe_clk_enable();
+	if (!rc && vfe_clk_enabled)
+		rc = clk_set_rate(vfe_clk, rate);
+	return rc;
+}
+
+static int clk_select(int internal)
+{
+	int rc = -EIO;
+	printk(KERN_INFO "mt9t013: clk select %d\n", internal);
+	CLK_GET(vfe_clk);
+	if (vfe_clk != NULL) {
+		extern int clk_set_flags(struct clk *clk, unsigned long flags);
+		rc = clk_set_flags(vfe_clk, 0x00000100 << internal);
+		if (!rc && internal) rc = msm_camio_vfe_clk_enable();
+	}
+	return rc;
+}
+
+static void mt9t013_sensor_init(void)
+{
+	int ret;
+	printk(KERN_INFO "mt9t013: init\n");
+	if (!pclient)
+		return;
+
+	/*pull hi reset*/
+	printk(KERN_INFO "mt9t013: mt9t013_register_init\n");
+	ret = gpio_request(cam->sensor_reset, "mt9t013");
+	if (!ret) {
+		gpio_direction_output(cam->sensor_reset, 1);
+		printk(KERN_INFO "mt9t013: camera sensor_reset set as 1\n");
+	} else
+		printk(KERN_ERR "mt9t013 error: request gpio %d failed: "
+				"%d\n", cam->sensor_reset, ret);
+	mdelay(2);
+
+	/* pull down power down */
+	ret = gpio_request(cam->sensor_pwd, "mt9t013");
+	if (!ret || ret == -EBUSY)
+		gpio_direction_output(cam->sensor_pwd, 0);
+	else printk(KERN_ERR "mt913t013 error: request gpio %d failed: "
+			"%d\n", cam->sensor_pwd, ret);
+	gpio_free(cam->sensor_pwd);
+
+	/* enable clk */
+	msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
+	msm_camio_clk_enable(CAMIO_MDC_CLK);
+
+	/* reset CAMIF */
+	mt9t013_camif_pad_reg_reset();
+
+	/* set mclk */
+	ret = msm_camio_clk_rate_set(24000000);
+	if(ret < 0)
+		printk(KERN_ERR "camio clk rate select error\n");
+	mdelay(2);
+
+	/* enable gpio */
+	cam->config_gpio_on();
+	/* delay 2 ms */
+	mdelay(2);
+
+	/* reset sensor sequency */
+	gpio_direction_output(cam->sensor_reset, 0);
+	mdelay(2);
+	gpio_direction_output(cam->sensor_reset, 1);
+	gpio_free(cam->sensor_reset);
+	mdelay(2);
+
+	printk(KERN_INFO "mt9t013: camera sensor init sequence done\n");
+}
+
+#define CLK_DISABLE_AND_PUT(clk) do {					\
+	if (clk) {							\
+		if (clk##_enabled) {					\
+			printk(KERN_INFO "mt9t013: disabling "#clk"\n");\
+			clk_disable(clk);				\
+			clk##_enabled = 0;				\
+		}							\
+		printk(KERN_INFO 					\
+			"mt9t013: clk_put(%s): %p\n", #clk, clk);	\
+		clk_put(clk);						\
+		clk = NULL; 						\
+	}								\
+} while(0)
+
+static void mt9t013_sensor_suspend(void)
+{
+	printk(KERN_INFO "mt9t013: camera sensor suspend sequence\n");
+	if (!pclient) {
+		return;
+	}
+	/*disable clk*/
+	msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
+	msm_camio_clk_disable(CAMIO_MDC_CLK);
+	CLK_DISABLE_AND_PUT(vfe_clk); /* this matches clk_select(1) */
+	/* disable gpios */
+	cam->config_gpio_off();
+	printk(KERN_INFO "mt9t013: camera sensor suspend sequence done\n");
+}
+
+static int mt9t013_open(struct inode *ip, struct file *fp)
+{
+	int rc = -EBUSY;
+	down(&sem);
+	printk(KERN_INFO "mt9t013: open\n");
+	if (!opened) {
+		printk(KERN_INFO "mt9t013: prevent collapse on idle\n");
+		prevent_suspend();
+		cam->config_gpio_on();
+		opened = 1;
+		rc = 0;
+	}
+	up(&sem);
+	return rc;
+}
+
+static int mt9t013_release(struct inode *ip, struct file *fp)
+{
+	int rc = -EBADF;
+	printk(KERN_INFO "mt9t013: release\n");
+	down(&sem);
+	if (opened) {
+		printk(KERN_INFO "mt9t013: release clocks\n");
+
+
+		/* mt9t013_i2c_power_down() should be called before closing MCLK */
+		/* otherwise I2C_WRITE will always fail                          */
+		mt9t013_i2c_power_down();
+
+		CLK_DISABLE_AND_PUT(mdc_clk);
+		CLK_DISABLE_AND_PUT(vfe_mdc_clk);
+		CLK_DISABLE_AND_PUT(vfe_clk);
+		mt9t013_lens_power(0);
+
+		cam->config_gpio_off();
+
+		printk(KERN_INFO "mt9t013: allow collapse on idle\n");
+		allow_suspend();
+		rc = pclk_set = opened = 0;
+	}
+	up(&sem);
+	return rc;
+}
+
+#undef CLK_DISABLE_AND_PUT
+
+#define CHECK() ({ 							\
+	if (!mdc_clk_enabled || !vfe_mdc_clk_enabled) { 		\
+		printk(KERN_ERR "mt9t013 error: one or more clocks"	\
+			" are NULL.\n"); 				\
+		rc = -EIO; 						\
+	} 								\
+	!rc; })
+
+static int mt9t013_camif_pad_reg_reset(void)
+{
+	int rc = clk_select(1);
+	if(rc < 0) {
+		printk(KERN_ERR "mt9t013 error switching to internal clock\n");
+		return rc;
+	}
+	HWIO_OUTM (MDDI_CAMIF_CFG,
+		HWIO_FMSK (MDDI_CAMIF_CFG, CAM_SEL) |
+		HWIO_FMSK (MDDI_CAMIF_CFG, CAM_PCLK_SRC_SEL) |
+		HWIO_FMSK (MDDI_CAMIF_CFG, CAM_PCLK_INVERT),
+		1 << HWIO_SHFT (MDDI_CAMIF_CFG, CAM_SEL) |
+		3 << HWIO_SHFT (MDDI_CAMIF_CFG, CAM_PCLK_SRC_SEL) |
+		0 << HWIO_SHFT (MDDI_CAMIF_CFG, CAM_PCLK_INVERT));
+	msleep(10);
+	HWIO_OUTM (MDDI_CAMIF_CFG,
+		HWIO_FMSK (MDDI_CAMIF_CFG, CAM_PAD_REG_SW_RESET),
+		1 << HWIO_SHFT (MDDI_CAMIF_CFG,
+		CAM_PAD_REG_SW_RESET));
+	msleep(10);
+	HWIO_OUTM (MDDI_CAMIF_CFG,
+		HWIO_FMSK (MDDI_CAMIF_CFG, CAM_PAD_REG_SW_RESET),
+		0 << HWIO_SHFT (MDDI_CAMIF_CFG,
+		CAM_PAD_REG_SW_RESET));
+	msleep(10);
+	rc = clk_select(0); /* external */
+	if(rc < 0) {
+		printk(KERN_ERR "mt9t013 error switching to external clock\n");
+		return rc;
+	}
+
+	return rc;
+}
+
+#if ALLOW_USPACE_RW
+#define COPY_FROM_USER(size) ({                                         \
+        if (copy_from_user(rwbuf, argp, size)) rc = -EFAULT;            \
+        !rc; })
+#endif
+
+static long mt9t013_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int rc = 0;
+	
+#if ALLOW_USPACE_RW
+	unsigned short addr = 0;
+	unsigned short data = 0;
+	char rwbuf[4];
+#endif
+
+	down(&sem);
+
+	switch(cmd) {
+#if ALLOW_USPACE_RW
+	case MT9T013_I2C_IOCTL_W:
+		if (/* CHECK() && */ COPY_FROM_USER(4)) {
+			addr = *((unsigned short *)rwbuf);
+			data = *((unsigned short *)(rwbuf+2));
+			rc = mt9t013_i2c_write(addr, data);
+		} else
+			printk(KERN_ERR "mt9t013: write: err %d\n", rc);
+		break;
+
+	case MT9T013_I2C_IOCTL_R:
+		if (/* CHECK() && */ COPY_FROM_USER(4)) {
+			addr = *((unsigned short*) rwbuf);
+			rc = mt9t013_i2c_read(addr, (unsigned short *)(rwbuf+2));
+			if (!rc) {
+				if (copy_to_user(argp, rwbuf, 4)) {
+					printk(KERN_ERR "mt9t013: read: err " \
+							"writeback -EFAULT\n");
+					rc = -EFAULT;
+				}
+			}
+		} else
+			printk(KERN_ERR "mt9t013: read: err %d\n", rc);
+		break;
+
+	case MT9T013_I2C_IOCTL_AF_W:
+		if (/* CHECK() && */ COPY_FROM_USER(3))
+			rc = mt9t013_i2c_lens_write(*rwbuf, *(rwbuf + 1), *(rwbuf + 2));
+		else
+			printk(KERN_ERR "mt9t013: af write: err %d\n", rc);
+		break;
+#endif /* ALLOW_USPACE_RW */
+
+	case MT9T013_I2C_IOCTL_CAMIF_PAD_REG_RESET:
+		printk(KERN_INFO "mt9t013: CAMIF_PAD_REG_RESET\n"); 
+		if (CHECK())
+			rc = mt9t013_camif_pad_reg_reset();
+		break;
+
+	case MT9T013_I2C_IOCTL_CAMIF_PAD_REG_RESET_2:
+		printk(KERN_INFO "mt9t013: CAMIF_PAD_REG_RESET_2 (pclk_set %d)\n",
+				pclk_set);
+		if (!pclk_set)
+			rc = -EIO;
+		else if (CHECK()) {
+			HWIO_OUTM (MDDI_CAMIF_CFG,
+				HWIO_FMSK (MDDI_CAMIF_CFG, CAM_PAD_REG_SW_RESET),
+					1 << HWIO_SHFT (MDDI_CAMIF_CFG,
+					CAM_PAD_REG_SW_RESET));
+			msleep(10);
+			HWIO_OUTM (MDDI_CAMIF_CFG,
+				HWIO_FMSK (MDDI_CAMIF_CFG, CAM_PAD_REG_SW_RESET),
+				0 << HWIO_SHFT (MDDI_CAMIF_CFG,
+				CAM_PAD_REG_SW_RESET));
+			msleep(10);
+		}
+		break;
+
+	case MT9T013_I2C_IOCTL_CAMIF_APPS_RESET:
+		printk(KERN_INFO "mt9t013: CAMIF_APPS_RESET\n"); 
+		if (CHECK()) {
+			rc = clk_select(1);
+			if(rc < 0) {
+				printk(KERN_ERR "mt9t013 error switching to internal clock\n");
+				break;	
+			}
+			HWIO_OUTM (APPS_RESET,
+				HWIO_FMSK(APPS_RESET,VFE),
+				1 << HWIO_SHFT(APPS_RESET,VFE));
+			udelay(10);
+			HWIO_OUTM (APPS_RESET,
+				HWIO_FMSK(APPS_RESET,VFE),
+				0 << HWIO_SHFT(APPS_RESET,VFE));
+			udelay(10);
+			rc = clk_select(0); /* external */
+			if(rc < 0) {
+				printk(KERN_ERR "mt9t013 error switching to external clock\n");
+				break;
+			}
+		}
+		break;
+
+	case CAMERA_LENS_POWER_ON:
+		rc = mt9t013_lens_power(1);
+		break;
+
+	case CAMERA_LENS_POWER_OFF:
+		rc = mt9t013_lens_power(0);
+		break;
+
+	case MT9T013_I2C_IOCTL_CLK_ENABLE:
+		printk(KERN_INFO "mt9t013: clk enable %ld\n", arg);
+		rc = msm_camio_clk_enable(arg);
+		break;
+
+	case MT9T013_I2C_IOCTL_CLK_DISABLE:
+		printk(KERN_INFO "mt9t013: clk disable %ld\n", arg);
+		rc = msm_camio_clk_disable(arg);
+		break;
+
+	case MT9T013_I2C_IOCTL_CLK_SELECT:
+		printk(KERN_INFO "mt9t013: clk select %ld\n", arg);
+		rc = clk_select(!!arg);
+		break;
+  
+	case MT9T013_I2C_IOCTL_CLK_FREQ_PROG:
+		printk(KERN_INFO "mt9t013: clk rate select %ld\n", arg);
+		rc = msm_camio_clk_rate_set(arg);
+		break;
+
+	case MT9T013_I2C_IOCTL_GET_REGISTERS:
+		printk(KERN_INFO "mt9t013: get registers\n");
+		if (copy_to_user(argp, &mt9t013_reg_pattern.reg, sizeof(mt9t013_reg_pattern.reg)))
+			rc = -EFAULT;
+		break;
+
+	case MT9T013_I2C_IOCTL_SENSOR_SETTING:
+		printk(KERN_INFO "mt9t013: sensor setting 0x%lx\n", arg);
+		rc = mt9t013_i2c_sensor_setting(arg);
+		break;
+
+	case MT9T013_I2C_IOCTL_EXPOSURE_GAIN: {
+		struct mt9t013_exposure_gain exp;
+		if (copy_from_user(&exp, argp, sizeof(exp))) {
+			printk(KERN_ERR "mt9t013: (exposure gain) invalid user pointer\n");
+			rc = -EFAULT;
+			break;
+		}
+		rc = mt9t013_i2c_exposure_gain(exp.mode, exp.line, exp.gain); 
+	}
+		break;
+
+	case MT9T013_I2C_IOCTL_MOVE_FOCUS:
+		printk(KERN_INFO "mt9t013: move focus %ld\n", arg);
+		rc = mt9t013_i2c_move_focus((uint16_t)arg);
+		break;
+
+	case MT9T013_I2C_IOCTL_SET_DEFAULT_FOCUS:
+		printk(KERN_INFO "mt9t013: set default focus %ld\n", arg);
+		rc = mt9t013_i2c_set_default_focus((uint8_t)arg);
+		break;
+
+	case MT9T013_I2C_IOCTL_POWER_DOWN:
+		rc = mt9t013_i2c_power_down();
+		break;
+
+	case MT9T013_I2C_IOCTL_INIT: {
+		struct mt9t013_init init;
+		printk(KERN_INFO "mt9t013: init\n");
+		if (copy_from_user(&init, argp, sizeof(init))) {
+			printk(KERN_ERR "mt9t013: (init) invalid user pointer\n");
+			rc = -EFAULT;
+			break;
+		}
+		rc = mt9t013_i2c_sensor_init(&init);
+		if (copy_to_user(argp, &init, sizeof(init)))
+			rc = -EFAULT;
+	}
+		break;
+
+	case CAMERA_CONFIGURE_GPIOS:
+	case CAMERA_UNCONFIGURE_GPIOS: 
+		break;
+
+	default:
+		printk(KERN_INFO "mt9t013: unknown ioctl %d\n", cmd);
+		break;
+	}
+
+	up(&sem);
+
+	return rc;
+}
+
+#undef CHECK
+
+static int mt9t013_lens_power(int on)
+{
+	int rc;
+	printk(KERN_INFO "mt9t013: lens power %d\n", on);
+	rc = gpio_request(cam->vcm_pwd, "mt9t013");
+	if (!rc)
+		gpio_direction_output(cam->vcm_pwd, !on);
+	else printk(KERN_ERR "mt9t013 error: request gpio %d failed:"
+		" %d\n", cam->vcm_pwd, rc);
+	gpio_free(cam->vcm_pwd);
+	return rc;
+}
+
+#define I2C_WRITE(reg,data) if (!mt9t013_i2c_write(reg, data) < 0) return -EIO
+#define MT9T013_MU3M0VC_RESET_DELAY_MSECS    66
+
+static int mt9t013_i2c_sensor_init(struct mt9t013_init *init)
+{
+	int rc;
+	
+	/* RESET the sensor via I2C register */
+	I2C_WRITE(MT9T013_REG_RESET_REGISTER, 0x10cc & 0xfffe);
+	msleep(MT9T013_MU3M0VC_RESET_DELAY_MSECS);
+
+	if ((rc = mt9t013_i2c_read(MT9T013_MU3M0VC_REG_MODEL_ID, &init->chipid)) < 0) {
+		printk(KERN_ERR "mt9t013: could not read chip id: %d\n", rc);
+		return rc;
+	}
+	printk(KERN_INFO "mt9t013: chip id: %d\n", init->chipid);
+
+	if (init->chipid != MT9T013_MU3M0VC_MODEL_ID) {
+		printk(KERN_INFO "mt9t013: chip id %d is invalid\n",
+			init->chipid);
+		return -EINVAL;
+	}
+
+	I2C_WRITE(0x306E, 0x9080);
+	I2C_WRITE(0x301A, 0x10CC);
+	I2C_WRITE(0x3064, 0x0805);
+	msleep(MT9T013_MU3M0VC_RESET_DELAY_MSECS);
+
+	if ((rc = mt9t013_i2c_sensor_setting(CAMSENSOR_REG_INIT |
+					((init->preview ? 0 : 1) << 1))) < 0) {
+		printk(KERN_INFO "mt9t013: failed to configure the sensor\n");
+		return rc;
+	}
+
+	mt9t013_i2c_power_up();
+
+	return 0;
+}
+
+static int mt9t013_mu3m0vc_set_lc(void)
+{
+	/* lens shading 85% TL84 */
+	I2C_WRITE(0x360A, 0x0290); // P_RD_P0Q0
+	I2C_WRITE(0x360C, 0xC92D); // P_RD_P0Q1
+	I2C_WRITE(0x360E, 0x0771); // P_RD_P0Q2
+	I2C_WRITE(0x3610, 0xE38C); // P_RD_P0Q3
+	I2C_WRITE(0x3612, 0xD74F); // P_RD_P0Q4
+	I2C_WRITE(0x364A, 0x168C); // P_RD_P1Q0
+	I2C_WRITE(0x364C, 0xCACB); // P_RD_P1Q1
+	I2C_WRITE(0x364E, 0x8C4C); // P_RD_P1Q2
+	I2C_WRITE(0x3650, 0x0BEA); // P_RD_P1Q3
+	I2C_WRITE(0x3652, 0xDC0F); // P_RD_P1Q4
+	I2C_WRITE(0x368A, 0x70B0); // P_RD_P2Q0
+	I2C_WRITE(0x368C, 0x200B); // P_RD_P2Q1
+	I2C_WRITE(0x368E, 0x30B2); // P_RD_P2Q2
+	I2C_WRITE(0x3690, 0xD04F); // P_RD_P2Q3
+	I2C_WRITE(0x3692, 0xACF5); // P_RD_P2Q4
+	I2C_WRITE(0x36CA, 0xF7C9); // P_RD_P3Q0
+	I2C_WRITE(0x36CC, 0x2AED); // P_RD_P3Q1
+	I2C_WRITE(0x36CE, 0xA652); // P_RD_P3Q2
+	I2C_WRITE(0x36D0, 0x8192); // P_RD_P3Q3
+	I2C_WRITE(0x36D2, 0x3A15); // P_RD_P3Q4
+	I2C_WRITE(0x370A, 0xDA30); // P_RD_P4Q0
+	I2C_WRITE(0x370C, 0x2E2F); // P_RD_P4Q1
+	I2C_WRITE(0x370E, 0xBB56); // P_RD_P4Q2
+	I2C_WRITE(0x3710, 0x8195); // P_RD_P4Q3
+	I2C_WRITE(0x3712, 0x02F9); // P_RD_P4Q4
+	I2C_WRITE(0x3600, 0x0230); // P_GR_P0Q0
+	I2C_WRITE(0x3602, 0x58AD); // P_GR_P0Q1
+	I2C_WRITE(0x3604, 0x18D1); // P_GR_P0Q2
+	I2C_WRITE(0x3606, 0x260D); // P_GR_P0Q3
+	I2C_WRITE(0x3608, 0xF530); // P_GR_P0Q4
+	I2C_WRITE(0x3640, 0x17EB); // P_GR_P1Q0
+	I2C_WRITE(0x3642, 0x3CAB); // P_GR_P1Q1
+	I2C_WRITE(0x3644, 0x87CE); // P_GR_P1Q2
+	I2C_WRITE(0x3646, 0xC02E); // P_GR_P1Q3
+	I2C_WRITE(0x3648, 0xF48F); // P_GR_P1Q4
+	I2C_WRITE(0x3680, 0x5350); // P_GR_P2Q0
+	I2C_WRITE(0x3682, 0x7EAF); // P_GR_P2Q1
+	I2C_WRITE(0x3684, 0x4312); // P_GR_P2Q2
+	I2C_WRITE(0x3686, 0xC652); // P_GR_P2Q3
+	I2C_WRITE(0x3688, 0xBC15); // P_GR_P2Q4
+	I2C_WRITE(0x36C0, 0xB8AD); // P_GR_P3Q0
+	I2C_WRITE(0x36C2, 0xBDCD); // P_GR_P3Q1
+	I2C_WRITE(0x36C4, 0xE4B2); // P_GR_P3Q2
+	I2C_WRITE(0x36C6, 0xB50F); // P_GR_P3Q3
+	I2C_WRITE(0x36C8, 0x5B95); // P_GR_P3Q4
+	I2C_WRITE(0x3700, 0xFC90); // P_GR_P4Q0
+	I2C_WRITE(0x3702, 0x8C51); // P_GR_P4Q1
+	I2C_WRITE(0x3704, 0xCED6); // P_GR_P4Q2
+	I2C_WRITE(0x3706, 0xB594); // P_GR_P4Q3
+	I2C_WRITE(0x3708, 0x0A39); // P_GR_P4Q4
+	I2C_WRITE(0x3614, 0x0230); // P_BL_P0Q0
+	I2C_WRITE(0x3616, 0x160D); // P_BL_P0Q1
+	I2C_WRITE(0x3618, 0x08D1); // P_BL_P0Q2
+	I2C_WRITE(0x361A, 0x98AB); // P_BL_P0Q3
+	I2C_WRITE(0x361C, 0xEA50); // P_BL_P0Q4
+	I2C_WRITE(0x3654, 0xB4EA); // P_BL_P1Q0
+	I2C_WRITE(0x3656, 0xEA6C); // P_BL_P1Q1
+	I2C_WRITE(0x3658, 0xFE08); // P_BL_P1Q2
+	I2C_WRITE(0x365A, 0x2C6E); // P_BL_P1Q3
+	I2C_WRITE(0x365C, 0xEB0E); // P_BL_P1Q4
+	I2C_WRITE(0x3694, 0x6DF0); // P_BL_P2Q0
+	I2C_WRITE(0x3696, 0x3ACF); // P_BL_P2Q1
+	I2C_WRITE(0x3698, 0x3E0F); // P_BL_P2Q2
+	I2C_WRITE(0x369A, 0xB2B1); // P_BL_P2Q3
+	I2C_WRITE(0x369C, 0xC374); // P_BL_P2Q4
+	I2C_WRITE(0x36D4, 0xF2AA); // P_BL_P3Q0
+	I2C_WRITE(0x36D6, 0x8CCC); // P_BL_P3Q1
+	I2C_WRITE(0x36D8, 0xDEF2); // P_BL_P3Q2
+	I2C_WRITE(0x36DA, 0xFA11); // P_BL_P3Q3
+	I2C_WRITE(0x36DC, 0x42F5); // P_BL_P3Q4
+	I2C_WRITE(0x3714, 0xF4F1); // P_BL_P4Q0
+	I2C_WRITE(0x3716, 0xF6F0); // P_BL_P4Q1
+	I2C_WRITE(0x3718, 0x8FD6); // P_BL_P4Q2
+	I2C_WRITE(0x371A, 0xEA14); // P_BL_P4Q3
+	I2C_WRITE(0x371C, 0x6338); // P_BL_P4Q4
+	I2C_WRITE(0x361E, 0x0350); // P_GB_P0Q0
+	I2C_WRITE(0x3620, 0x91AE); // P_GB_P0Q1
+	I2C_WRITE(0x3622, 0x0571); // P_GB_P0Q2
+	I2C_WRITE(0x3624, 0x100D); // P_GB_P0Q3
+	I2C_WRITE(0x3626, 0xCA70); // P_GB_P0Q4
+	I2C_WRITE(0x365E, 0xE6CB); // P_GB_P1Q0
+	I2C_WRITE(0x3660, 0x50ED); // P_GB_P1Q1
+	I2C_WRITE(0x3662, 0x3DAE); // P_GB_P1Q2
+	I2C_WRITE(0x3664, 0xAA4F); // P_GB_P1Q3
+	I2C_WRITE(0x3666, 0xDC50); // P_GB_P1Q4
+	I2C_WRITE(0x369E, 0x5470); // P_GB_P2Q0
+	I2C_WRITE(0x36A0, 0x1F6E); // P_GB_P2Q1
+	I2C_WRITE(0x36A2, 0x6671); // P_GB_P2Q2
+	I2C_WRITE(0x36A4, 0xC010); // P_GB_P2Q3
+	I2C_WRITE(0x36A6, 0x8DF5); // P_GB_P2Q4
+	I2C_WRITE(0x36DE, 0x0B0C); // P_GB_P3Q0
+	I2C_WRITE(0x36E0, 0x84CE); // P_GB_P3Q1
+	I2C_WRITE(0x36E2, 0x8493); // P_GB_P3Q2
+	I2C_WRITE(0x36E4, 0xA610); // P_GB_P3Q3
+	I2C_WRITE(0x36E6, 0x50B5); // P_GB_P3Q4
+	I2C_WRITE(0x371E, 0x9651); // P_GB_P4Q0
+	I2C_WRITE(0x3720, 0x1EAB); // P_GB_P4Q1
+	I2C_WRITE(0x3722, 0xAF76); // P_GB_P4Q2
+	I2C_WRITE(0x3724, 0xE4F4); // P_GB_P4Q3
+	I2C_WRITE(0x3726, 0x79F8); // P_GB_P4Q4
+	I2C_WRITE(0x3782, 0x0410); // Original LC 2 // POLY_ORIGIN_C
+	I2C_WRITE(0x3784, 0x0320); // POLY_ORIGIN_R
+	I2C_WRITE(0x3780, 0x8000); // POLY_SC_ENABLE
+
+	return 0;
+}
+
+static int mt9t013_set_pclk(int rt, int div_adj)
+{
+	int rc;
+	if ((rc = mt9t013_i2c_power_down()) < 0) return rc; 
+	I2C_WRITE(REG_VT_PIX_CLK_DIV, mt9t013_reg_pattern.reg[rt].vt_pix_clk_div);
+	I2C_WRITE(REG_VT_SYS_CLK_DIV, mt9t013_reg_pattern.reg[rt].vt_sys_clk_div);
+	I2C_WRITE(REG_PRE_PLL_CLK_DIV, mt9t013_reg_pattern.reg[rt].pre_pll_clk_div * div_adj);
+	I2C_WRITE(REG_PLL_MULTIPLIER, mt9t013_reg_pattern.reg[rt].pll_multiplier);
+	I2C_WRITE(REG_OP_PIX_CLK_DIV, mt9t013_reg_pattern.reg[rt].op_pix_clk_div);
+	I2C_WRITE(REG_OP_SYS_CLK_DIV, mt9t013_reg_pattern.reg[rt].op_sys_clk_div);
+	if ((rc = mt9t013_i2c_power_up()) < 0) return rc; 
+	pclk_set = 1;
+	return 0;
+}
+
+static int mt9t013_i2c_sensor_setting(unsigned long arg) 
+{
+	uint32_t update = arg & 1;
+	uint32_t rt = (arg & 2) >> 1;
+
+	if (rt > 1 || update > 1) {
+		printk(KERN_ERR "mt9t013: invalid values %d of rt or %d of update\n",
+			rt, update);
+		return -EINVAL;
+	}
+
+	switch (update) {
+	case CAMSENSOR_REG_UPDATE_PERIODIC: {
+		uint16_t pclk_div_adj = arg >> 16;
+
+		printk(KERN_INFO "CAMSENSOR_REG_UPDATE_PERIODIC (rt %d)\n", rt);
+		
+		if (!pclk_div_adj || pclk_div_adj > 2) {
+			printk(KERN_ERR "mt9t013: invalid value %d of pclk_div_adj\n",
+					pclk_div_adj); 
+			return -EINVAL;
+		}
+		
+		if (mt9t013_set_pclk(rt, pclk_div_adj) < 0)
+			return -EIO;
+
+		I2C_WRITE(REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD);
+		I2C_WRITE(REG_ROW_SPEED, mt9t013_reg_pattern.reg[rt].row_speed);
+		I2C_WRITE(REG_X_ADDR_START, mt9t013_reg_pattern.reg[rt].x_addr_start);
+		I2C_WRITE(REG_X_ADDR_END, mt9t013_reg_pattern.reg[rt].x_addr_end);
+		I2C_WRITE(REG_Y_ADDR_START, mt9t013_reg_pattern.reg[rt].y_addr_start);
+		I2C_WRITE(REG_Y_ADDR_END, mt9t013_reg_pattern.reg[rt].y_addr_end);
+
+		if (machine_is_sapphire()) {
+			if (rt == 0) {
+				I2C_WRITE(REG_READ_MODE, 0x046F);
+			} else {
+				I2C_WRITE(REG_READ_MODE, 0x0027);
+			}
+		} else {
+			I2C_WRITE(REG_READ_MODE,
+				mt9t013_reg_pattern.reg[rt].read_mode);
+		}
+
+		I2C_WRITE(REG_SCALE_M, mt9t013_reg_pattern.reg[rt].scale_m);
+		I2C_WRITE(REG_X_OUTPUT_SIZE, mt9t013_reg_pattern.reg[rt].x_output_size);
+		I2C_WRITE(REG_Y_OUTPUT_SIZE, mt9t013_reg_pattern.reg[rt].y_output_size);
+		I2C_WRITE(REG_LINE_LENGTH_PCK, mt9t013_reg_pattern.reg[rt].line_length_pck);
+		I2C_WRITE(REG_FRAME_LENGTH_LINES, (uint16_t) (mt9t013_reg_pattern.reg[rt].frame_length_lines * fps_divider));
+		I2C_WRITE(REG_COARSE_INTEGRATION_TIME, mt9t013_reg_pattern.reg[rt].coarse_integration_time);
+		I2C_WRITE(REG_FINE_INTEGRATION_TIME, mt9t013_reg_pattern.reg[rt].fine_integration_time);
+		I2C_WRITE(REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE);
+	}
+		break;
+		
+	case CAMSENSOR_REG_INIT:
+		printk(KERN_INFO "CAMSENSOR_REG_INIT (rt %d)\n", rt);
+
+		if (mt9t013_set_pclk(rt, 1) < 0) return -EIO;
+
+		I2C_WRITE(REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD);
+		
+		/* additional power saving mode ok around 38.2MHz */
+		I2C_WRITE(0x3084, 0x2409);
+		I2C_WRITE(0x3092, 0x0A49);
+		I2C_WRITE(0x3094, 0x4949);
+		I2C_WRITE(0x3096, 0x4949);
+
+		/* set preview or snapshot mode */
+		I2C_WRITE(REG_ROW_SPEED,
+			mt9t013_reg_pattern.reg[rt].row_speed);
+		I2C_WRITE(REG_X_ADDR_START,
+			mt9t013_reg_pattern.reg[rt].x_addr_start);
+		I2C_WRITE(REG_X_ADDR_END,
+			mt9t013_reg_pattern.reg[rt].x_addr_end);
+		I2C_WRITE(REG_Y_ADDR_START,
+			mt9t013_reg_pattern.reg[rt].y_addr_start);
+		I2C_WRITE(REG_Y_ADDR_END,
+			mt9t013_reg_pattern.reg[rt].y_addr_end);
+
+		if (machine_is_sapphire()) {
+			if (rt == 0) {
+				I2C_WRITE(REG_READ_MODE, 0x046F);
+			} else {
+				I2C_WRITE(REG_READ_MODE, 0x0027);
+			}
+		} else {
+			I2C_WRITE(REG_READ_MODE,
+				mt9t013_reg_pattern.reg[rt].read_mode);
+		}
+
+		I2C_WRITE(REG_SCALE_M, mt9t013_reg_pattern.reg[rt].scale_m);
+		I2C_WRITE(REG_X_OUTPUT_SIZE, mt9t013_reg_pattern.reg[rt].x_output_size);
+		I2C_WRITE(REG_Y_OUTPUT_SIZE, mt9t013_reg_pattern.reg[rt].y_output_size);
+		I2C_WRITE(REG_LINE_LENGTH_PCK, mt9t013_reg_pattern.reg[rt].line_length_pck);
+		I2C_WRITE(REG_FRAME_LENGTH_LINES, mt9t013_reg_pattern.reg[rt].frame_length_lines);
+		I2C_WRITE(REG_COARSE_INTEGRATION_TIME, mt9t013_reg_pattern.reg[rt].coarse_integration_time);
+		I2C_WRITE(REG_FINE_INTEGRATION_TIME, mt9t013_reg_pattern.reg[rt].fine_integration_time);
+
+		I2C_WRITE(REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE);
+
+		/* load lens shading */
+		I2C_WRITE(REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD);
+		if(mt9t013_mu3m0vc_set_lc() < 0) return -EIO;
+		I2C_WRITE(REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE);
+		break;
+		
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mt9t013_i2c_exposure_gain(uint32_t mode, uint16_t line,
+					uint16_t gain)
+{
+	static const uint16_t max_legal_gain  = 0x01FF;
+	
+	if (gain > max_legal_gain) gain = max_legal_gain;
+
+	gain |= 0x200; /* set digital gain */
+
+	/*I2C_WRITE(REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD);*/
+	I2C_WRITE(REG_GLOBAL_GAIN, gain);
+	I2C_WRITE(REG_COARSE_INTEGRATION_TIME, line);
+	/*I2C_WRITE(REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE);*/
+	if (mode == 1) {
+		/* RESET REGISTER RESTART */
+		I2C_WRITE(MT9T013_REG_RESET_REGISTER, 0x10cc|0x0002);
+	}
+	return 0;
+}
+
+#define I2C_AF_WRITE(command, data) if (mt9t013_i2c_lens_write(AF_I2C_ID >> 1, command, data) < 0) return -EIO;
+
+static int mt9t013_i2c_move_focus(uint16_t position)
+{
+	uint8_t code_val_msb = (position >> 2) | ((position << 4) >> 6);
+	uint8_t code_val_lsb = (position & 0x03) << 6;
+
+	I2C_AF_WRITE(code_val_msb, code_val_lsb);
+	return 0;
+}
+
+static int mt9t013_i2c_set_default_focus(uint8_t step)
+{
+	I2C_AF_WRITE(0x01, step);
+    	return 0; 
+}
+
+static int powered;
+
+static int mt9t013_i2c_power_up(void)
+{
+	printk(KERN_INFO "mt9t013: power up\n");
+	if (powered) {
+		printk(KERN_INFO "mt9t013: already powered up\n");
+		return 0;
+	}
+	I2C_WRITE(MT9T013_REG_RESET_REGISTER, MT9T013_RESET_REGISTER_PWON);
+	mdelay(5);
+	powered = 1;
+	return 0;
+}
+
+static int mt9t013_i2c_power_down(void)
+{
+	int i = 0, try_more = 100;
+
+	printk(KERN_INFO "mt9t013: power down\n");
+	if (!powered) {
+		printk(KERN_INFO "mt9t013: already powered down\n");
+		return 0;
+	}
+
+	/* I2C_WRITE(MT9T013_REG_RESET_REGISTER, MT9T013_RESET_REGISTER_PWOFF); */
+	/* Modified by Horng for more tries while I2C write fail                */
+	/* -------------------------------------------------------------------- */
+	while(mt9t013_i2c_write(MT9T013_REG_RESET_REGISTER, MT9T013_RESET_REGISTER_PWOFF) < 0)
+	{
+		if (i >= try_more)
+			return -EIO;
+		else {
+			i++;
+			printk(KERN_INFO "mt9p012: in mt9p012_i2c_power_down() call mt9p012_i2c_write() failed !!!  (try %d times)\n", i);
+			mdelay(i+5);
+		}
+	}
+	/* -------------------------------------------------------------------- */
+	mdelay(5);
+	powered = pclk_set = 0;
+	return 0;
+}
+
+#undef I2C_WRITE
+#undef I2C_AF_WRITE
+
+static int mt9t013_init_client(struct i2c_client *client)
+{
+	/* Initialize the MT9T013 Chip */
+	init_waitqueue_head(&g_data_ready_wait_queue);
+	return 0;
+}   
+
+static struct file_operations mt9t013_fops = {
+        .owner 	= THIS_MODULE,
+        .open 	= mt9t013_open,
+        .release = mt9t013_release,
+        .unlocked_ioctl = mt9t013_ioctl,
+};
+
+static struct miscdevice mt9t013_device = {
+        .minor 	= MISC_DYNAMIC_MINOR,
+        .name 	= "mt9t013",
+        .fops 	= &mt9t013_fops,
+};
+
+static const char *MT9T013Vendor = "micron";
+static const char *MT9T013NAME = "mt9t013";
+static const char *MT9T013Size = "3M";
+
+
+
+static ssize_t sensor_vendor_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+
+	sprintf(buf, "%s %s %s\n", MT9T013Vendor, MT9T013NAME, MT9T013Size);
+	ret = strlen(buf) + 1;
+
+	return ret;
+}
+
+static DEVICE_ATTR(sensor, 0444, sensor_vendor_show, NULL);
+
+
+static struct kobject *android_mt9t013 = NULL;
+
+static int mt9t013_sysfs_init(void)
+{
+	int ret ;
+	printk(KERN_INFO "mt9t013:kobject creat and add\n");
+	android_mt9t013 = kobject_create_and_add("android_camera", NULL);
+	if (android_mt9t013 == NULL) {
+		printk(KERN_INFO "mt9t013_sysfs_init: subsystem_register " \
+		"failed\n");
+		ret = -ENOMEM;
+		return ret ;
+	}
+	printk(KERN_INFO "mt9t013:sysfs_create_file\n");
+	ret = sysfs_create_file(android_mt9t013, &dev_attr_sensor.attr);
+	if (ret) {
+		printk(KERN_INFO "mt9t013_sysfs_init: sysfs_create_file " \
+		"failed\n");
+		kobject_del(android_mt9t013);
+	}
+	return 0 ;
+}
+
+
+
+static int mt9t013_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct mt9t013_data *mt;
+	int err = 0;
+	printk(KERN_INFO "mt9t013: probe\n");
+
+	if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		goto exit_check_functionality_failed;		
+
+	if(!(mt = kzalloc( sizeof(struct mt9t013_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit_alloc_data_failed;
+	}
+
+	i2c_set_clientdata(client, mt);
+	mt9t013_init_client(client);
+	pclient = client;
+	mt9t013_sensor_init();
+	mt9t013_sensor_suspend();
+	
+	/* Register a misc device */
+	err = misc_register(&mt9t013_device);
+	if(err) {
+		printk(KERN_ERR "mt9t013_probe: misc_register failed \n");
+		goto exit_misc_device_register_failed;
+	}
+	init_suspend();
+	mt9t013_sysfs_init();
+	return 0;
+	
+exit_misc_device_register_failed:
+exit_alloc_data_failed:
+exit_check_functionality_failed:
+	
+	return err;
+}
+
+	
+static int mt9t013_remove(struct i2c_client *client)
+{
+	struct mt9t013_data *mt = i2c_get_clientdata(client);
+	free_irq(client->irq, mt);
+	deinit_suspend();
+	pclient = NULL;
+	misc_deregister(&mt9t013_device);
+	kfree(mt);
+	return 0;
+}
+
+static const struct i2c_device_id mt9t013_id[] = {
+	{ "mt9t013", 0 },
+	{ }
+};
+
+static struct i2c_driver mt9t013_driver = {
+	.probe = mt9t013_probe,
+	.remove = mt9t013_remove,
+	.id_table = mt9t013_id,
+	.driver = {		
+		.name   = "mt9t013",
+	},
+};
+
+static int mt9t013_plat_probe(struct platform_device *pdev __attribute__((unused)))
+{
+       int rc = -EFAULT;
+
+       if(pdev->dev.platform_data)
+       {
+               printk(KERN_INFO "pdev->dev.platform_data is not NULL\n");
+               cam = pdev->dev.platform_data;
+               rc = i2c_add_driver(&mt9t013_driver);
+       }
+       return rc;
+}
+
+static struct platform_driver mt9t013_plat_driver = {
+        .probe = mt9t013_plat_probe,
+        .driver = {
+                .name = "camera",
+                .owner = THIS_MODULE,
+        },
+};
+
+static int __init mt9t013_init(void)
+{
+       return platform_driver_register(&mt9t013_plat_driver);
+}
+
+module_init(mt9t013_init);
+
+MODULE_AUTHOR("Kidd Chen");
+MODULE_DESCRIPTION("MT9T013 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 1ba2514..1985cbf 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -324,6 +324,13 @@
 	  To compile this driver as a module, choose M here; the
 	  module will be called opencores-kbd.
 
+config KEYBOARD_PM8058
+	bool "Qualcomm PM8058 Matrix Keypad support"
+	depends on PM8058
+	help
+	  Say Y here to enable the driver for the keypad matrix interface
+	  on the Qualcomm PM8058 power management I/C device.
+
 config KEYBOARD_PXA27x
 	tristate "PXA27x/PXA3xx keypad support"
 	depends on PXA27x || PXA3xx
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 4596d0c..8aeec81 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -29,6 +29,7 @@
 obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)	+= opencores-kbd.o
+obj-$(CONFIG_KEYBOARD_PM8058)		+= pm8058-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)	+= pxa930_rotary.o
 obj-$(CONFIG_KEYBOARD_QT2160)		+= qt2160.o
diff --git a/drivers/input/keyboard/pm8058-keypad.c b/drivers/input/keyboard/pm8058-keypad.c
new file mode 100644
index 0000000..f1aefd4
--- /dev/null
+++ b/drivers/input/keyboard/pm8058-keypad.c
@@ -0,0 +1,417 @@
+/* drivers/input/keyboard/pm8058-keypad.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2009 Code Aurora Forum
+ *
+ * Author: Dima Zavin <dima@android.com>
+ *    - Heavily based on the driver from the Code Aurora Forum.
+ *
+ * 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/err.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/pm8058.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+enum {
+	DEBUG_IRQ = 1U << 0,
+	DEBUG_KEYS = 1U << 1,
+};
+static int debug_mask = 0;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define REG_KEYP_CTRL		0x148
+#define REG_KEYP_SCAN		0x149
+#define REG_KEYP_TEST		0x14a
+#define REG_KEYP_NEW_DATA	0x14b
+#define REG_KEYP_OLD_DATA	0x14c
+
+#define KP_SNS_MIN		5
+#define KP_SNS_MAX		8
+#define KP_DRV_MIN		5
+#define KP_DRV_MAX		18
+
+#define KP_CLOCK_FREQ		32768
+
+#define KPF_HAS_SYNC_READ	0x00000001
+
+struct pm8058_keypad {
+	struct device		*dev;
+	struct input_dev	*input_dev;
+	int			sense_irq;
+	int			stuck_irq;
+
+	int			num_sns;
+	int			num_drv;
+	const unsigned short	*keymap;
+
+	u8			key_state[KP_DRV_MAX];
+	u8			stuck_state[KP_DRV_MAX];
+
+	u32			flags;
+};
+
+/* convenience wrapers */
+static inline int kp_writeb(struct pm8058_keypad *kp, u16 addr, u8 val)
+{
+	return pm8058_writeb(kp->dev->parent, addr, val);
+}
+
+static inline int kp_readb(struct pm8058_keypad *kp, u16 addr, u8 *val)
+{
+	return pm8058_readb(kp->dev->parent, addr, val);
+}
+
+static inline int kp_read_buf(struct pm8058_keypad *kp, u16 addr,
+				     u8 *buf, int cnt)
+{
+	return pm8058_read_buf(kp->dev->parent, addr, buf, cnt);
+}
+
+static int kp_hw_init(struct pm8058_keypad *kp,
+		      struct pm8058_keypad_platform_data *pdata)
+{
+	int ret;
+	u8 val;
+	u8 drv_bits[] = {
+		0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7,
+	};
+	u8 sns_bits[] = {
+		0, 0, 0, 0, 0, 0, 1, 2, 3,
+	};
+
+	val = ((drv_bits[pdata->num_drv] << 2) |
+	       (sns_bits[pdata->num_sns] << 5));
+	ret = kp_writeb(kp, REG_KEYP_CTRL, val);
+	if (ret) {
+		pr_err("%s: can't write kp ctrl\n", __func__);
+		goto out;
+	}
+
+	val = ((((pdata->drv_hold_clks - 1) & 0x3) << 6) |
+	       ((pdata->scan_delay_shift & 0x7) << 3) |
+	       ((((pdata->debounce_ms / 5) & 0x3)) << 1));
+	ret = kp_writeb(kp, REG_KEYP_SCAN, val);
+	if (ret) {
+		pr_err("%s: can't write kp scan\n", __func__);
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+static int kp_get_scan_data(struct pm8058_keypad *kp, u8 *old, u8 *new)
+{
+	int ret;
+	u8 val;
+
+	/* XXX: B0 only? */
+	if (kp->flags & KPF_HAS_SYNC_READ) {
+		ret = kp_readb(kp, REG_KEYP_SCAN, &val);
+		if (ret)
+			goto err;
+		ret = kp_writeb(kp, REG_KEYP_SCAN, val | 1);
+		if (ret)
+			goto err;
+		/* 2 * 32KHz clocks */
+		udelay((2 * USEC_PER_SEC / KP_CLOCK_FREQ) + 1);
+	}
+
+	if (old) {
+		ret = kp_read_buf(kp, REG_KEYP_OLD_DATA, old, kp->num_drv);
+		if (ret)
+			goto done;
+	}
+
+	ret = kp_read_buf(kp, REG_KEYP_NEW_DATA, new, kp->num_drv);
+	if (ret)
+		goto done;
+
+done:
+	if (kp->flags & KPF_HAS_SYNC_READ) {
+		/* 4 * 32KHz clocks */
+		udelay((4 * USEC_PER_SEC / KP_CLOCK_FREQ) + 1);
+		ret = kp_readb(kp, REG_KEYP_SCAN, &val);
+		if (ret)
+			goto err;
+		ret = kp_writeb(kp, REG_KEYP_SCAN, val & (~0x1));
+		if (ret)
+			goto err;
+	}
+
+err:
+	if (ret)
+		pr_err("%s: can't get scan data\n", __func__);
+	return ret;
+}
+
+static int kp_process_scan_data(struct pm8058_keypad *kp, u8 *old, u8 *new)
+{
+	int drv;
+	int sns;
+
+	for (drv = 0; drv < kp->num_drv; ++drv) {
+		unsigned long bits_changed = (new[drv] ^ old[drv]) & 0xff;
+
+		for_each_set_bit(sns, &bits_changed, kp->num_sns) {
+			int key_idx = drv * kp->num_sns + sns;
+			unsigned int code = kp->keymap[key_idx] ?: KEY_UNKNOWN;
+			int down = !(new[drv] & (1 << sns));
+
+			if (debug_mask & DEBUG_KEYS)
+				pr_info("%s: key [%d:%d] %s\n", __func__,
+					drv, sns, down ? "down" : "up");
+			input_event(kp->input_dev, EV_MSC, MSC_SCAN, key_idx);
+			input_report_key(kp->input_dev, code, down);
+			input_sync(kp->input_dev);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * NOTE: We are reading recent and old data registers blindly
+ * whenever key-stuck interrupt happens, because events counter doesn't
+ * get updated when this interrupt happens due to key stuck doesn't get
+ * considered as key state change.
+ *
+ * We are not using old data register contents after they are being read
+ * because it might report the key which was pressed before the key being stuck
+ * as stuck key because it's pressed status is stored in the old data
+ * register.
+ */
+static irqreturn_t kp_stuck_irq_handler(int irq, void *dev_id)
+{
+	struct pm8058_keypad *kp = dev_id;
+	u8 old[KP_DRV_MAX];
+	u8 new[KP_DRV_MAX];
+	int ret;
+
+	if (debug_mask & DEBUG_IRQ)
+		pr_info("%s: key stuck!\n", __func__);
+
+	ret = kp_get_scan_data(kp, old, new);
+	if (ret) {
+		pr_err("%s: couldn't get scan data\n", __func__);
+		goto out;
+	}
+	kp_process_scan_data(kp, kp->stuck_state, new);
+
+out:
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t kp_sense_irq_handler(int irq, void *dev_id)
+{
+	struct pm8058_keypad *kp = dev_id;
+	int ret;
+	u8 old[KP_DRV_MAX];
+	u8 new[KP_DRV_MAX];
+	u8 val;
+
+	if (debug_mask & DEBUG_IRQ)
+		pr_info("%s: key event!!\n", __func__);
+	ret = kp_readb(kp, REG_KEYP_CTRL, &val);
+	if (ret) {
+		pr_err("%s: can't read events\n", __func__);
+		goto out;
+	}
+
+	/* events counter is gray coded */
+	switch(val & 0x3) {
+	case 0x1:
+		ret = kp_get_scan_data(kp, NULL, new);
+		if (ret)
+			goto out;
+		kp_process_scan_data(kp, kp->key_state, new);
+		memcpy(kp->key_state, new, sizeof(new));
+		break;
+
+	case 0x2:
+		pr_debug("%s: some key events were missed\n", __func__);
+	case 0x3:
+		ret = kp_get_scan_data(kp, old, new);
+		if (ret)
+			goto out;
+		/* first process scan data in relation to last known
+		 * key state */
+		kp_process_scan_data(kp, kp->key_state, old);
+		kp_process_scan_data(kp, old, new);
+		memcpy(kp->key_state, new, sizeof(new));
+		break;
+		
+	case 0x0:
+		pr_warning("%s: interrupt without any events?!\n", __func__);
+		break;
+	}
+
+out:
+	if (ret)
+		pr_err("%s: couldn't get scan data\n", __func__);
+
+	return IRQ_HANDLED;
+}
+
+static int pm8058_keypad_probe(struct platform_device *pdev)
+{
+	struct pm8058_keypad_platform_data *pdata = pdev->dev.platform_data;
+	struct pm8058_keypad *kp;
+	int sense_irq;
+	int stuck_irq;
+	int ret;
+	int i;
+	u8 val;
+
+	sense_irq = platform_get_irq_byname(pdev, "kp_sense");
+	stuck_irq = platform_get_irq_byname(pdev, "kp_stuck");
+
+	if (!pdata || sense_irq < 0 || stuck_irq < 0) {
+		pr_err("%s: missing platform data/resources\n", __func__);
+		return -EINVAL;
+	}
+
+	if (pdata->num_sns > KP_SNS_MAX || pdata->num_drv > KP_DRV_MAX ||
+	    (pdata->drv_hold_clks == 0) || !pdata->keymap) {
+		pr_err("%s: invalid plaform data\n", __func__);
+		return -EINVAL;
+	}
+
+	kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+	if (!kp) {
+		pr_err("%s: can't allocate memory for kp struct\n", __func__);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, kp);
+	kp->dev = &pdev->dev;
+	kp->num_sns = pdata->num_sns;
+	kp->num_drv = pdata->num_drv;
+	kp->keymap = pdata->keymap;
+	kp->sense_irq = sense_irq;
+	kp->stuck_irq = stuck_irq;
+
+	memset(kp->key_state, 0xff, sizeof(kp->key_state));
+	memset(kp->stuck_state, 0xff, sizeof(kp->stuck_state));
+
+	/* b0 and up have sync_read support */
+	kp->flags = KPF_HAS_SYNC_READ;
+
+	kp->input_dev = input_allocate_device();
+	if (!kp->input_dev) {
+		ret = -ENOMEM;
+		pr_err("%s: Failed to allocate input device\n", __func__);
+		goto err_input_dev_alloc;
+	}
+
+	kp->input_dev->name = pdata->name;
+	input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN);
+	input_set_drvdata(kp->input_dev, kp);
+
+	for (i = 0; i < kp->num_drv * kp->num_sns; ++i) {
+		unsigned short keycode = kp->keymap[i];
+		BUG_ON(keycode && keycode > KEY_MAX);
+		if (keycode)
+			input_set_capability(kp->input_dev, EV_KEY, keycode);
+	}
+
+	ret = input_register_device(kp->input_dev);
+	if (ret) {
+		pr_err("%s: can't register input device '%s'\n", __func__,
+		       pdata->name);
+		goto err_input_dev_reg;
+	}
+
+	ret = kp_hw_init(kp, pdata);
+	if (ret) {
+		pr_err("%s: can't initialize keypad hardware\n", __func__);
+		goto err_kp_hw_init;
+	}
+
+	if (pdata->init) {
+		ret = pdata->init(kp->dev);
+		if (ret) {
+			pr_err("%s: can't call board's init\n", __func__);
+			goto err_pdata_init;
+		}
+	}
+
+	ret = request_threaded_irq(kp->sense_irq, NULL, kp_sense_irq_handler,
+			  IRQF_TRIGGER_RISING, "pm8058-keypad-sense", kp);
+	if (ret) {
+		pr_err("%s: can't request sense_irq\n", __func__);
+		goto err_req_sense_irq;
+	}
+	ret = request_threaded_irq(kp->stuck_irq, NULL, kp_stuck_irq_handler,
+			  IRQF_TRIGGER_RISING, "pm8058-keypad-stuck", kp);
+	if (ret) {
+		pr_err("%s: can't request stuck\n", __func__);
+		goto err_req_stuck_irq;
+	}
+
+	enable_irq_wake(kp->sense_irq);
+
+	ret = kp_readb(kp, REG_KEYP_CTRL, &val);
+	if (ret) {
+		pr_err("%s: can't read kp ctrl\n", __func__);
+		goto err_read_kp_ctrl;
+	}
+	val |= 1 << 7;
+	ret = kp_writeb(kp, REG_KEYP_CTRL, val);
+	if (ret) {
+		pr_err("%s: can't enable kp\n", __func__);
+		goto err_kp_enable;
+	}
+
+	pr_info("%s: %dx%d matrix keypad '%s' registered\n", __func__,
+		kp->num_drv, kp->num_sns, pdata->name);
+
+	return 0;
+
+err_kp_enable:
+err_read_kp_ctrl:
+	disable_irq_wake(kp->sense_irq);
+	free_irq(kp->stuck_irq, kp);
+err_req_stuck_irq:
+	free_irq(kp->sense_irq, kp);
+err_req_sense_irq:
+err_pdata_init:
+err_kp_hw_init:
+	input_unregister_device(kp->input_dev);
+err_input_dev_reg:
+	input_free_device(kp->input_dev);
+err_input_dev_alloc:
+	platform_set_drvdata(pdev, NULL);
+	kfree(kp);
+	return ret;
+}
+
+static struct platform_driver pm8058_keypad_driver = {
+	.probe		= pm8058_keypad_probe,
+	.driver		= {
+		.name	= "pm8058-keypad",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init pm8058_keypad_init(void)
+{
+	return platform_driver_register(&pm8058_keypad_driver);
+}
+device_initcall(pm8058_keypad_init);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7861016..e4dc20a 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -406,4 +406,10 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called pcap_keys.
 
+config INPUT_CAPELLA_CM3602
+	tristate "Capella CM3602 proximity and light sensor"
+	help
+	  Say Y here to enable the Capella CM3602 Short Distance Proximity
+	  Sensor with Ambient Light Sensor.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index d234834..6d323e4 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
 obj-$(CONFIG_INPUT_BFIN_ROTARY)		+= bfin_rotary.o
+obj-$(CONFIG_INPUT_CAPELLA_CM3602)	+= capella_cm3602.o
 obj-$(CONFIG_INPUT_CM109)		+= cm109.o
 obj-$(CONFIG_INPUT_COBALT_BTNS)		+= cobalt_btns.o
 obj-$(CONFIG_INPUT_DM355EVM)		+= dm355evm_keys.o
diff --git a/drivers/input/misc/capella_cm3602.c b/drivers/input/misc/capella_cm3602.c
new file mode 100644
index 0000000..b03eb62
--- /dev/null
+++ b/drivers/input/misc/capella_cm3602.c
@@ -0,0 +1,268 @@
+/* drivers/input/misc/capella_cm3602.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Iliyan Malchev <malchev@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/module.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/capella_cm3602.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+
+#define D(x...) pr_info(x)
+
+static struct capella_cm3602_data {
+	struct input_dev *input_dev;
+	struct capella_cm3602_platform_data *pdata;
+	int enabled;
+} the_data;
+
+static int misc_opened;
+
+static int capella_cm3602_report(struct capella_cm3602_data *data)
+{
+	int val = gpio_get_value(data->pdata->p_out);
+	if (val < 0) {
+		pr_err("%s: gpio_get_value error %d\n", __func__, val);
+		return val;
+	}
+
+	D("proximity %d\n", val);
+
+	/* 0 is close, 1 is far */
+	input_report_abs(data->input_dev, ABS_DISTANCE, val);
+	input_sync(data->input_dev);
+	return val;
+}
+
+static irqreturn_t capella_cm3602_irq_handler(int irq, void *data)
+{
+	struct capella_cm3602_data *ip = data;
+	int val = capella_cm3602_report(ip);
+	return IRQ_HANDLED;
+}
+
+static int capella_cm3602_enable(struct capella_cm3602_data *data)
+{
+	D("%s\n", __func__);
+	if (data->enabled) {
+		D("%s: already enabled\n", __func__);
+	} else {
+		data->pdata->power(1);
+		data->enabled = 1;
+		capella_cm3602_report(data);
+	}
+	return 0;
+}
+
+static int capella_cm3602_disable(struct capella_cm3602_data *data)
+{
+	D("%s\n", __func__);
+	if (data->enabled) {
+		data->pdata->power(0);
+		data->enabled = 0;
+	} else {
+		D("%s: already disabled\n", __func__);
+	}
+	return 0;
+}
+
+static int capella_cm3602_setup(struct capella_cm3602_data *ip)
+{
+	int rc = -EIO;
+	struct capella_cm3602_platform_data *pdata = ip->pdata;
+	int irq = gpio_to_irq(pdata->p_out);
+
+	D("%s\n", __func__);
+
+	rc = gpio_request(pdata->p_out, "gpio_proximity_out");
+	if (rc < 0) {
+		pr_err("%s: gpio %d request failed (%d)\n",
+			__func__, pdata->p_out, rc);
+		goto done;
+	}
+
+	rc = gpio_direction_input(pdata->p_out);
+	if (rc < 0) {
+		pr_err("%s: failed to set gpio %d as input (%d)\n",
+			__func__, pdata->p_out, rc);
+		goto fail_free_p_out;
+	}
+
+	rc = request_irq(irq,
+			capella_cm3602_irq_handler,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			"capella_cm3602",
+			ip);
+	if (rc < 0) {
+		pr_err("%s: request_irq(%d) failed for gpio %d (%d)\n",
+			__func__, irq,
+			pdata->p_out, rc);
+		goto fail_free_p_out;
+	}
+
+	rc = set_irq_wake(irq, 1);
+	if (rc < 0) {
+		pr_err("%s: failed to set irq %d as a wake interrupt\n",
+			__func__, irq);
+		goto fail_free_irq;
+
+	}
+
+	goto done;
+
+fail_free_irq:
+	free_irq(irq, 0);
+fail_free_p_out:
+	gpio_free(pdata->p_out);
+done:
+	return rc;
+}
+
+static int capella_cm3602_open(struct inode *inode, struct file *file)
+{
+	D("%s\n", __func__);
+	if (misc_opened)
+		return -EBUSY;
+	misc_opened = 1;
+	return 0;
+}
+
+static int capella_cm3602_release(struct inode *inode, struct file *file)
+{
+	D("%s\n", __func__);
+	misc_opened = 0;
+	return capella_cm3602_disable(&the_data);
+}
+
+static long capella_cm3602_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int val;
+	D("%s cmd %d\n", __func__, _IOC_NR(cmd));
+	switch (cmd) {
+	case CAPELLA_CM3602_IOCTL_ENABLE:
+		if (get_user(val, (unsigned long __user *)arg))
+			return -EFAULT;
+		if (val)
+			return capella_cm3602_enable(&the_data);
+		else
+			return capella_cm3602_disable(&the_data);
+		break;
+	case CAPELLA_CM3602_IOCTL_GET_ENABLED:
+		return put_user(the_data.enabled, (unsigned long __user *)arg);
+		break;
+	default:
+		pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd));
+		return -EINVAL;
+	}
+}
+
+static struct file_operations capella_cm3602_fops = {
+	.owner = THIS_MODULE,
+	.open = capella_cm3602_open,
+	.release = capella_cm3602_release,
+	.unlocked_ioctl = capella_cm3602_ioctl
+};
+
+struct miscdevice capella_cm3602_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "cm3602",
+	.fops = &capella_cm3602_fops
+};
+
+static int capella_cm3602_probe(struct platform_device *pdev)
+{
+	int rc = -EIO;
+	struct input_dev *input_dev;
+	struct capella_cm3602_data *ip;
+	struct capella_cm3602_platform_data *pdata;
+
+	D("%s: probe\n", __func__);
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		pr_err("%s: missing pdata!\n", __func__);
+		goto done;
+	}
+	if (!pdata->power) {
+		pr_err("%s: incomplete pdata!\n", __func__);
+		goto done;
+	}
+
+	ip = &the_data;
+	platform_set_drvdata(pdev, ip);
+
+	D("%s: allocating input device\n", __func__);
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		pr_err("%s: could not allocate input device\n", __func__);
+		rc = -ENOMEM;
+		goto done;
+	}
+	ip->input_dev = input_dev;
+	ip->pdata = pdata;
+	input_set_drvdata(input_dev, ip);
+
+	input_dev->name = "proximity";
+
+	set_bit(EV_ABS, input_dev->evbit);
+	input_set_abs_params(input_dev, ABS_DISTANCE, 0, 1, 0, 0);
+
+	D("%s: registering input device\n", __func__);
+	rc = input_register_device(input_dev);
+	if (rc < 0) {
+		pr_err("%s: could not register input device\n", __func__);
+		goto err_free_input_device;
+	}
+
+	D("%s: registering misc device\n", __func__);
+	rc = misc_register(&capella_cm3602_misc);
+	if (rc < 0) {
+		pr_err("%s: could not register misc device\n", __func__);
+		goto err_unregister_input_device;
+	}
+
+	rc = capella_cm3602_setup(ip);
+	if (!rc)
+		goto done;
+
+	misc_deregister(&capella_cm3602_misc);
+err_unregister_input_device:
+	input_unregister_device(input_dev);
+	goto done;
+err_free_input_device:
+	input_free_device(input_dev);
+done:
+	return rc;
+}
+
+static struct platform_driver capella_cm3602_driver = {
+	.probe = capella_cm3602_probe,
+	.driver = {
+		.name = CAPELLA_CM3602,
+		.owner = THIS_MODULE
+	},
+};
+
+static int __init capella_cm3602_init(void)
+{
+	return platform_driver_register(&capella_cm3602_driver);
+}
+
+device_initcall(capella_cm3602_init);
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index c4e276a..55edb04 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -99,6 +99,17 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called h3600_ts_input.
 
+config TOUCHSCREEN_CYPRESS_TMG
+	tristate "Support for Cypress TMC i2c touchscreen"
+	depends on I2C
+	help
+	  Say Y here to enable support for cy8ctmg touchcreens.
+
+	  If unsure, say N
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called h3600_ts_input.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
@@ -177,6 +188,10 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called gunze.
 
+config TOUCHSCREEN_ELAN_I2C_8232
+	tristate "Elan 8232 I2C touchscreen"
+	depends on I2C
+
 config TOUCHSCREEN_ELO
 	tristate "Elo serial touchscreens"
 	select SERIO
@@ -292,6 +307,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called penmount.
 
+config TOUCHSCREEN_MSM
+	bool "Qualcomm MSM touchscreen controller"
+	depends on ARCH_MSM
+	default n
+	help
+	  Say Y here if you have a 4-wire resistive touchscreen panel
+	  connected to the TSSC touchscreen controller on a
+	  Qualcomm MSM/QSD based SoC.
+
 config TOUCHSCREEN_MIGOR
 	tristate "Renesas MIGO-R touchscreen"
 	depends on SH_MIGOR && I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 0559522..ff3cb78 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -12,10 +12,12 @@
 obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_CYPRESS_TMG)	+= cy8c_tmg_ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)		+= gunze.o
 obj-$(CONFIG_TOUCHSCREEN_EETI)		+= eeti_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ELAN_I2C_8232) += elan8232_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
@@ -24,6 +26,7 @@
 obj-$(CONFIG_TOUCHSCREEN_MIGOR)		+= migor_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MTOUCH)	+= mtouch.o
 obj-$(CONFIG_TOUCHSCREEN_MK712)		+= mk712.o
+obj-$(CONFIG_TOUCHSCREEN_MSM)		+= msm_ts.o
 obj-$(CONFIG_TOUCHSCREEN_HP600)		+= hp680_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_HP7XX)		+= jornada720_ts.o
 obj-$(CONFIG_TOUCHSCREEN_HTCPEN)	+= htcpen.o
diff --git a/drivers/input/touchscreen/cy8c_tmg_ts.c b/drivers/input/touchscreen/cy8c_tmg_ts.c
new file mode 100644
index 0000000..f48374e
--- /dev/null
+++ b/drivers/input/touchscreen/cy8c_tmg_ts.c
@@ -0,0 +1,467 @@
+/* drivers/input/touchscreen/cy8c_tmg_ts.c
+ *
+ * Copyright (C) 2007-2008 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/cy8c_tmg_ts.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define CY8C_REG_START_NEW_SCAN 0x0F
+#define CY8C_REG_INTR_STATUS    0x3C
+#define CY8C_REG_VERSION        0x3E
+
+struct cy8c_ts_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	int use_irq;
+	struct hrtimer timer;
+	struct work_struct work;
+	uint16_t version;
+	int (*power) (int on);
+	struct early_suspend early_suspend;
+};
+
+struct workqueue_struct *cypress_touch_wq;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void cy8c_ts_early_suspend(struct early_suspend *h);
+static void cy8c_ts_late_resume(struct early_suspend *h);
+#endif
+
+uint16_t sample_count, X_mean, Y_mean, first_touch;
+
+static s32 cy8c_read_word_data(struct i2c_client *client,
+			       u8 command, uint16_t * data)
+{
+	s32 ret = i2c_smbus_read_word_data(client, command);
+	if (ret != -1) {
+		*data = (u16) ((ret << 8) | (ret >> 8));
+	}
+	return ret;
+}
+
+static int cy8c_init_panel(struct cy8c_ts_data *ts)
+{
+	int ret;
+	sample_count = X_mean = Y_mean = first_touch = 0;
+
+	/* clean intr busy */
+	ret = i2c_smbus_write_byte_data(ts->client, CY8C_REG_INTR_STATUS,
+					0x00);
+	if (ret < 0) {
+		dev_err(&ts->client->dev,
+			"cy8c_init_panel failed for clean intr busy\n");
+		goto exit;
+	}
+
+	/* start new scan */
+	ret = i2c_smbus_write_byte_data(ts->client, CY8C_REG_START_NEW_SCAN,
+					0x01);
+	if (ret < 0) {
+		dev_err(&ts->client->dev,
+			"cy8c_init_panel failed for start new scan\n");
+		goto exit;
+	}
+
+exit:
+	return ret;
+}
+
+static void cy8c_ts_reset(struct i2c_client *client)
+{
+	struct cy8c_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts->power) {
+		ts->power(0);
+		msleep(10);
+		ts->power(1);
+		msleep(10);
+	}
+
+	cy8c_init_panel(ts);
+}
+
+static void cy8c_ts_work_func(struct work_struct *work)
+{
+	struct cy8c_ts_data *ts = container_of(work, struct cy8c_ts_data, work);
+	uint16_t x1, y1, x2, y2;
+	uint8_t is_touch, start_reg, force, area, finger2_pressed;
+	uint8_t buf[11];
+	struct i2c_msg msg[2];
+	int ret = 0;
+
+	x2 = y2 = 0;
+
+	/*printk("%s: enter\n",__func__);*/
+	is_touch = i2c_smbus_read_byte_data(ts->client, 0x20);
+	dev_dbg(&ts->client->dev, "fIsTouch %d,\n", is_touch);
+	if (is_touch < 0 || is_touch > 3) {
+		pr_err("%s: invalid is_touch = %d\n", __func__, is_touch);
+		cy8c_ts_reset(ts->client);
+		msleep(10);
+		goto done;
+	}
+
+	msg[0].addr = ts->client->addr;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	start_reg = 0x16;
+	msg[0].buf = &start_reg;
+
+	msg[1].addr = ts->client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = sizeof(buf);
+	msg[1].buf = buf;
+
+	ret = i2c_transfer(ts->client->adapter, msg, 2);
+	if (ret < 0)
+		goto done;
+
+	/* parse data */
+	force = buf[0];
+	area = buf[1];
+	x1 = (buf[2] << 8) | buf[3];
+	y1 = (buf[6] << 8) | buf[7];
+	is_touch = buf[10];
+
+	if (is_touch == 2) {
+		x2 = (buf[4] << 8) | buf[5];
+		y2 = (buf[8] << 8) | buf[9];
+		finger2_pressed = 1;
+	}
+
+	dev_dbg(&ts->client->dev,
+		"bFingerForce %d, bFingerArea %d \n", force, area);
+	dev_dbg(&ts->client->dev, "x1: %d, y1: %d \n", x1, y1);
+	if (finger2_pressed)
+		dev_dbg(&ts->client->dev, "x2: %d, y2: %d \n", x2, y2);
+
+	/* drop the first one? */
+	if ((is_touch == 1) && (first_touch == 0)) {
+		first_touch = 1;
+		goto done;
+	}
+
+	if (!first_touch)
+		goto done;
+
+	if (is_touch == 2)
+		finger2_pressed = 1;
+
+	input_report_abs(ts->input_dev, ABS_X, x1);
+	input_report_abs(ts->input_dev, ABS_Y, y1);
+	input_report_abs(ts->input_dev, ABS_PRESSURE, force);
+	input_report_abs(ts->input_dev, ABS_TOOL_WIDTH, area);
+	input_report_key(ts->input_dev, BTN_TOUCH, is_touch);
+	input_report_key(ts->input_dev, BTN_2, finger2_pressed);
+
+	if (finger2_pressed) {
+		input_report_abs(ts->input_dev, ABS_HAT0X, x2);
+		input_report_abs(ts->input_dev, ABS_HAT0Y, y2);
+	}
+	input_sync(ts->input_dev);
+
+done:
+	if (is_touch == 0)
+		first_touch = sample_count = 0;
+
+	/* prepare for next intr */
+	i2c_smbus_write_byte_data(ts->client, CY8C_REG_INTR_STATUS, 0x00);
+	if (!ts->use_irq)
+		hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL);
+	else
+		enable_irq(ts->client->irq);
+}
+
+static enum hrtimer_restart cy8c_ts_timer_func(struct hrtimer *timer)
+{
+	struct cy8c_ts_data *ts;
+
+	ts = container_of(timer, struct cy8c_ts_data, timer);
+	queue_work(cypress_touch_wq, &ts->work);
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t cy8c_ts_irq_handler(int irq, void *dev_id)
+{
+	struct cy8c_ts_data *ts = dev_id;
+
+	disable_irq_nosync(ts->client->irq);
+	queue_work(cypress_touch_wq, &ts->work);
+	return IRQ_HANDLED;
+}
+
+static int cy8c_ts_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct cy8c_ts_data *ts;
+	struct cy8c_i2c_platform_data *pdata;
+	uint16_t panel_version;
+	int ret = 0;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "need I2C_FUNC_I2C\n");
+		ret = -ENODEV;
+		goto err_check_functionality_failed;
+	}
+
+	ts = kzalloc(sizeof(struct cy8c_ts_data), GFP_KERNEL);
+	if (ts == NULL) {
+		dev_err(&client->dev, "allocate cy8c_ts_data failed\n");
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	INIT_WORK(&ts->work, cy8c_ts_work_func);
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+
+	pdata = client->dev.platform_data;
+	if (pdata) {
+		ts->version = pdata->version;
+		ts->power = pdata->power;
+	}
+
+	if (ts->power) {
+		ret = ts->power(1);
+		msleep(10);
+		if (ret < 0) {
+			dev_err(&client->dev, "power on failed\n");
+			goto err_power_failed;
+		}
+	}
+
+	ret = cy8c_read_word_data(ts->client, CY8C_REG_VERSION, &panel_version);
+	if (ret < 0) {
+		dev_err(&client->dev, "init panel failed\n");
+		goto err_detect_failed;
+	}
+	dev_info(&client->dev, "Panel Version %04X\n", panel_version);
+	if (pdata) {
+		while (pdata->version > panel_version) {
+			dev_info(&client->dev, "old tp detected, "
+				 "panel version = %x\n", panel_version);
+			pdata++;
+		}
+	}
+
+	ret = cy8c_init_panel(ts);
+	if (ret < 0) {
+		dev_err(&client->dev, "init panel failed\n");
+		goto err_detect_failed;
+	}
+
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) {
+		ret = -ENOMEM;
+		dev_err(&client->dev, "Failed to allocate input device\n");
+		goto err_input_dev_alloc_failed;
+	}
+	ts->input_dev->name = "cy8c-touchscreen";
+
+	set_bit(EV_SYN, ts->input_dev->evbit);
+	set_bit(EV_ABS, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+	input_set_capability(ts->input_dev, EV_KEY, BTN_TOUCH);
+	input_set_capability(ts->input_dev, EV_KEY, BTN_2);
+
+	input_set_abs_params(ts->input_dev, ABS_X,
+			     pdata->abs_x_min, pdata->abs_x_max, 5, 0);
+	input_set_abs_params(ts->input_dev, ABS_Y,
+			     pdata->abs_y_min, pdata->abs_y_max, 5, 0);
+	input_set_abs_params(ts->input_dev, ABS_HAT0X,
+			     pdata->abs_x_min, pdata->abs_x_max, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_HAT0Y,
+			     pdata->abs_y_min, pdata->abs_y_max, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_PRESSURE,
+			     pdata->abs_pressure_min, pdata->abs_pressure_max,
+			     0, 0);
+	input_set_abs_params(ts->input_dev, ABS_TOOL_WIDTH,
+			     pdata->abs_width_min, pdata->abs_width_max, 0, 0);
+
+	ret = input_register_device(ts->input_dev);
+	if (ret) {
+		dev_err(&client->dev,
+			"cy8c_ts_probe: Unable to register %s input device\n",
+			ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+
+	if (client->irq) {
+		ret = request_irq(client->irq, cy8c_ts_irq_handler,
+				  IRQF_TRIGGER_LOW, CYPRESS_TMG_NAME, ts);
+		if (ret == 0)
+			ts->use_irq = 1;
+		else
+			dev_err(&client->dev, "request_irq failed\n");
+	}
+
+	if (!ts->use_irq) {
+		hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		ts->timer.function = cy8c_ts_timer_func;
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = cy8c_ts_early_suspend;
+	ts->early_suspend.resume = cy8c_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+
+	dev_info(&client->dev, "Start touchscreen %s in %s mode\n",
+		 ts->input_dev->name, (ts->use_irq ? "interrupt" : "polling"));
+
+	return 0;
+
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+
+err_input_dev_alloc_failed:
+	if (ts->power)
+		ts->power(0);
+
+err_detect_failed:
+err_power_failed:
+	kfree(ts);
+
+err_alloc_data_failed:
+err_check_functionality_failed:
+	return ret;
+}
+
+static int cy8c_ts_remove(struct i2c_client *client)
+{
+	struct cy8c_ts_data *ts = i2c_get_clientdata(client);
+
+	unregister_early_suspend(&ts->early_suspend);
+
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+
+	return 0;
+}
+
+static int cy8c_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct cy8c_ts_data *ts = i2c_get_clientdata(client);
+	int ret;
+
+	if (ts->use_irq)
+		disable_irq_nosync(client->irq);
+	else
+		hrtimer_cancel(&ts->timer);
+
+	ret = cancel_work_sync(&ts->work);
+	if (ret && ts->use_irq)
+		enable_irq(client->irq);
+
+	if (ts->power)
+		ts->power(0);
+
+	return 0;
+}
+
+static int cy8c_ts_resume(struct i2c_client *client)
+{
+	int ret;
+	struct cy8c_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts->power) {
+		ret = ts->power(1);
+		if (ret < 0)
+			dev_err(&client->dev,
+				"cy8c_ts_resume power on failed\n");
+		msleep(10);
+
+		cy8c_init_panel(ts);
+	}
+
+	if (ts->use_irq)
+		enable_irq(client->irq);
+	else
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void cy8c_ts_early_suspend(struct early_suspend *h)
+{
+	struct cy8c_ts_data *ts;
+	ts = container_of(h, struct cy8c_ts_data, early_suspend);
+	cy8c_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void cy8c_ts_late_resume(struct early_suspend *h)
+{
+	struct cy8c_ts_data *ts;
+	ts = container_of(h, struct cy8c_ts_data, early_suspend);
+	cy8c_ts_resume(ts->client);
+}
+#endif
+
+static const struct i2c_device_id cy8c_ts_i2c_id[] = {
+	{CYPRESS_TMG_NAME, 0},
+	{}
+};
+
+static struct i2c_driver cy8c_ts_driver = {
+	.id_table = cy8c_ts_i2c_id,
+	.probe = cy8c_ts_probe,
+	.remove = cy8c_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend = cy8c_ts_suspend,
+	.resume = cy8c_ts_resume,
+#endif
+	.driver = {
+		.name = CYPRESS_TMG_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __devinit cy8c_ts_init(void)
+{
+	cypress_touch_wq = create_singlethread_workqueue("cypress_touch_wq");
+	if (!cypress_touch_wq)
+		return -ENOMEM;
+
+	return i2c_add_driver(&cy8c_ts_driver);
+}
+
+static void __exit cy8c_ts_exit(void)
+{
+	if (cypress_touch_wq)
+		destroy_workqueue(cypress_touch_wq);
+
+	i2c_del_driver(&cy8c_ts_driver);
+}
+
+module_init(cy8c_ts_init);
+module_exit(cy8c_ts_exit);
+
+MODULE_DESCRIPTION("Cypress TMG Touchscreen Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/touchscreen/elan8232_i2c.c b/drivers/input/touchscreen/elan8232_i2c.c
new file mode 100644
index 0000000..4870b22
--- /dev/null
+++ b/drivers/input/touchscreen/elan8232_i2c.c
@@ -0,0 +1,829 @@
+/*
+ * Copyright (C) 2007-2008 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/input.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/hrtimer.h>
+#include <linux/elan_i2c.h>
+#include <linux/earlysuspend.h>
+#include <linux/gpio.h>
+
+
+static const char EKT8232NAME[]	= "elan-touch";
+
+#define ELAN_TS_FUZZ 		0
+#define ELAN_TS_FLAT 		0
+#define IDX_PACKET_SIZE		9
+
+enum {
+	STATE_DEEP_SLEEP	= 0,
+	STATE_NORMAL		= 1U,
+	STATE_MASK		= 0x08,
+	cmd_reponse_packet	= 0x52,
+	read_cmd_packet		= 0x53,
+	write_cmd_packet	= 0x54,
+	hello_packet 		= 0x55,
+	enable_int		= 0xa6,
+	disable_int		= 0x56,
+	idx_coordinate_packet 	= 0x5a,
+};
+
+enum {
+	idx_finger_width = 7,
+	idx_finger_state = 8,
+};
+
+static struct workqueue_struct *elan_wq;
+
+static struct ekt8232_data {
+	int intr_gpio;
+	int use_irq;
+	/* delete when finish migration */
+	int fw_ver;
+	struct hrtimer timer;
+	struct work_struct work;
+	struct i2c_client *client;
+	struct input_dev *input;
+	wait_queue_head_t wait;
+	int (*power)(int on);
+	struct early_suspend early_suspend;
+} ekt_data;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void elan_ts_early_suspend(struct early_suspend *h);
+static void elan_ts_late_resume(struct early_suspend *h);
+#endif
+
+static ssize_t touch_vendor_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+
+	sprintf(buf, "%s_%#x\n", EKT8232NAME, ekt_data.fw_ver);
+	ret = strlen(buf) + 1;
+
+	return ret;
+}
+
+static DEVICE_ATTR(vendor, 0444, touch_vendor_show, NULL);
+
+static struct kobject *android_touch_kobj;
+
+static int touch_sysfs_init(void)
+{
+	int ret ;
+
+	android_touch_kobj = kobject_create_and_add("android_touch", NULL) ;
+	if (android_touch_kobj == NULL) {
+		printk(KERN_INFO
+		       "touch_sysfs_init: subsystem_register failed\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = sysfs_create_file(android_touch_kobj, &dev_attr_vendor.attr);
+	if (ret) {
+		printk(KERN_INFO
+		       "touch_sysfs_init: sysfs_create_group failed\n");
+		goto err4;
+	}
+
+	return 0 ;
+err4:
+	kobject_del(android_touch_kobj);
+err:
+	return ret ;
+}
+
+static int ekt8232_detect_int_level(void)
+{
+	unsigned v;
+	v = gpio_get_value(ekt_data.intr_gpio);
+	/* printk("ekt8232_detect_int_level: v = %0x\n", v); */
+	return v;
+}
+
+static int __ekt8232_poll(struct i2c_client *client)
+{
+	int status = 0, retry = 10;
+
+	do {
+		status = ekt8232_detect_int_level();
+		dev_dbg(&client->dev, "%s: status = %d\n", __func__, status);
+		retry--;
+		mdelay(20);
+	} while (status == 1 && retry > 0);
+
+	dev_dbg(&client->dev, "%s: poll interrupt status %s\n",
+			__func__, status == 1 ? "high" : "low");
+	return (status == 0 ? 0 : -ETIMEDOUT);
+}
+
+static int ekt8232_poll(struct i2c_client *client)
+{
+	return __ekt8232_poll(client);
+}
+
+static int ekt8232_get_data(struct i2c_client *client, uint8_t *cmd,
+			    uint8_t *buf, size_t size, int sleep)
+{
+	int rc;
+	unsigned time_out = msecs_to_jiffies(10);
+
+	dev_dbg(&client->dev, "%s: enter.\n", __func__);
+
+	if (buf == NULL)
+		return -EINVAL;
+
+	if ((i2c_master_send(client, cmd, 4)) != 4) {
+		dev_err(&client->dev,
+			"%s: i2c_master_send failed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (sleep == 1) {
+		rc = wait_event_timeout(ekt_data.wait,
+				i2c_master_recv(client, buf, size) == size &&
+				buf[0] == cmd_reponse_packet, time_out);
+		if (rc == 0) {
+			dev_err(&client->dev,
+				"%s: i2c_master_recv failed\n", __func__);
+			return -ETIMEDOUT;
+		}
+	} else {
+		rc = ekt8232_poll(client);
+		if (rc < 0)
+			return -EINVAL;
+		else {
+			if (i2c_master_recv(client, buf, size) != size ||
+			    buf[0] != cmd_reponse_packet)
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int __hello_packet_handler(struct i2c_client *client)
+{
+	int rc;
+	uint8_t buf_recv[4] = { 0 };
+
+	rc = ekt8232_poll(client);
+	if (rc < 0) {
+		dev_err(&client->dev, "%s: failed!\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = i2c_master_recv(client, buf_recv, 4);
+	if (rc != 4) {
+		dev_err(&client->dev,
+			"%s: get hello packet failed!, rc = %d\n",
+			__func__, rc);
+		return rc;
+	} else {
+		int i;
+		dev_dbg(&client->dev,
+			"dump hello packet: %0x, %0x, %0x, %0x\n",
+			buf_recv[0], buf_recv[1], buf_recv[2], buf_recv[3]);
+
+		for (i = 0; i < 4; i++)
+			if (buf_recv[i] != hello_packet)
+				return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __fw_packet_handler(struct i2c_client *client)
+{
+	int rc;
+	int major, minor;
+	uint8_t cmd[] = { read_cmd_packet, 0x00, 0x00, 0x01 };
+	uint8_t buf_recv[4] = { 0 };
+
+	rc = ekt8232_get_data(client, cmd, buf_recv, 4, 0);
+	if (rc < 0)
+		return rc;
+
+	major = ((buf_recv[1] & 0x0f) << 4) | ((buf_recv[2] & 0xf0) >> 4);
+	minor = ((buf_recv[2] & 0x0f) << 4) | ((buf_recv[3] & 0xf0) >> 4);
+
+	/* delete after migration */
+	ekt_data.fw_ver = major << 8 | minor;
+
+	printk(KERN_INFO "%s: firmware version: 0x%x\n",
+			__func__, ekt_data.fw_ver);
+	return 0;
+}
+
+static int __set_report_type(struct i2c_client *client)
+{
+	return 0;
+}
+
+static inline int ekt8232_parse_xy(uint8_t *data, uint16_t *x, uint16_t *y)
+{
+	*x = (data[0] & 0xf0);
+	*x <<= 4;
+	*x |= data[1];
+
+	*y = (data[0] & 0x0f);
+	*y <<= 8;
+	*y |= data[2];
+
+	return 0;
+}
+
+/*	ekt8232_ts_init -- hand shaking with touch panel
+ *
+ *	1. recv hello packet
+ *	2. check its' firmware version
+ *	3. set up sensitivity, report rate, ...
+ */
+static int ekt8232_ts_init(struct i2c_client *client)
+{
+	int rc;
+
+	rc = __hello_packet_handler(client);
+	if (rc < 0)
+		goto hand_shake_failed;
+	dev_dbg(&client->dev, "%s: hello packet got.\n", __func__);
+
+	rc = __fw_packet_handler(client);
+	if (rc < 0)
+		goto hand_shake_failed;
+	dev_dbg(&client->dev, "%s: firmware checking done.\n", __func__);
+
+	rc = __set_report_type(client);
+	if (rc < 0)
+		goto hand_shake_failed;
+	dev_dbg(&client->dev,
+		"%s: channging operating mode done.\n", __func__);
+
+	if (ekt_data.fw_ver == 0x103) {
+		uint8_t cmd[4] = {0x5c, 0x10, 0x00, 0x01};
+		if ((i2c_master_send(client, cmd, 4)) != 4) {
+			dev_err(&client->dev,
+				"%s: set adc failed\n", __func__);
+		}
+		cmd[0] = 0x54;
+		cmd[0] = 0x43;
+		cmd[0] = 0x00;
+		cmd[0] = 0x01;
+		if ((i2c_master_send(client, cmd, 4)) != 4) {
+			dev_err(&client->dev,
+				"%s: set gain failed\n", __func__);
+		}
+	}
+
+hand_shake_failed:
+	return rc;
+}
+
+static int ekt8232_set_power_state(struct i2c_client *client, int state)
+{
+	uint8_t cmd[] = {write_cmd_packet, 0x50, 0x00, 0x01};
+
+	dev_dbg(&client->dev, "%s: enter.\n", __func__);
+
+	cmd[1] |= (state << 3);
+
+	dev_dbg(&client->dev,
+		"dump cmd: %02x, %02x, %02x, %02x\n",
+		cmd[0], cmd[1], cmd[2], cmd[3]);
+
+	if ((i2c_master_send(client, cmd, sizeof(cmd))) != sizeof(cmd)) {
+		dev_err(&client->dev,
+			"%s: i2c_master_send failed\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ekt8232_get_power_state(struct i2c_client *client)
+{
+	int rc = 0;
+	uint8_t cmd[] = { read_cmd_packet, 0x50, 0x00, 0x01 };
+	uint8_t buf[4], power_state;
+
+	rc = ekt8232_get_data(client, cmd, buf, 4, 0);
+	if (rc)
+		return rc;
+	else {
+		power_state = buf[1];
+		dev_dbg(&client->dev, "dump repsponse: %0x\n", power_state);
+
+		power_state = (power_state & STATE_MASK) >> 3;
+		dev_dbg(&client->dev, "power state = %s\n",
+			power_state == STATE_DEEP_SLEEP ?
+			"Deep Sleep" : "Normal/Idle");
+		return power_state;
+	}
+}
+
+static int ekt8232_recv_data(struct i2c_client *client, uint8_t *buf)
+{
+	int rc, bytes_to_recv = IDX_PACKET_SIZE;
+	int retry = 5;
+
+	if (ekt_data.fw_ver == 0x101)
+		bytes_to_recv = 8;
+
+	if (buf == NULL)
+		return -EINVAL;
+
+	memset(buf, 0, bytes_to_recv);
+	rc = i2c_master_recv(client, buf, bytes_to_recv);
+
+	if (rc != bytes_to_recv) {
+		dev_err(&client->dev,
+			"%s: i2c_master_recv error?! \n", __func__);
+		/* power off level shift */
+		ekt_data.power(0);
+		msleep(5);
+		/* power on level shift */
+		ekt_data.power(1);
+		/* re-initial */
+		if (ekt_data.fw_ver > 0x101) {
+			msleep(100);
+			rc = ekt8232_ts_init(client);
+		} else {
+			do {
+				rc = ekt8232_set_power_state(client,
+							     STATE_NORMAL);
+
+				rc = ekt8232_get_power_state(client);
+				if (rc != STATE_NORMAL)
+					dev_err(&client->dev,
+						"%s: wake up tp failed! \
+						err = %d\n",
+						__func__, rc);
+				else
+					break;
+			} while (--retry);
+		}
+		if (ekt8232_detect_int_level() == 0)
+			queue_work(elan_wq, &ekt_data.work);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static inline void ekt8232_parse_width(uint8_t data, uint8_t *w1, uint8_t *w2)
+{
+	*w1 = *w2 = 0;
+	*w1 = (data & 0xf0) >> 4;
+	*w2 = data & 0x0f;
+}
+
+static void ekt8232_report_data(struct i2c_client *client, uint8_t *buf)
+{
+	static unsigned report_time;
+	unsigned report_time2;
+
+	switch (buf[0]) {
+	case idx_coordinate_packet: {
+		uint16_t x1, x2, y1, y2;
+		uint8_t finger_stat, w1 = 1, w2 = 1;
+
+		ekt8232_parse_xy(&buf[1], &x1, &y1);
+		if (ekt_data.fw_ver == 0x101) {
+			finger_stat = buf[7] >> 1;
+		} else {
+			ekt8232_parse_width(buf[idx_finger_width], &w1, &w2);
+			finger_stat = buf[idx_finger_state] >> 1;
+		}
+
+		if (finger_stat != 0) {
+			input_report_abs(ekt_data.input, ABS_X, x1);
+			if (ekt_data.fw_ver == 0x101)
+				input_report_abs(ekt_data.input, ABS_Y,
+						 (544 - 1) - y1);
+			else
+				input_report_abs(ekt_data.input, ABS_Y, y1);
+			/* only report finger width at y */
+			input_report_abs(ekt_data.input, ABS_TOOL_WIDTH, w2);
+		}
+
+		dev_dbg(&client->dev,
+			"x1 = %d, y1 = %d, \
+			 w1 = %d, w2 = %d, finger status = %d\n",
+			x1, y1, w1, w2, finger_stat);
+
+		input_report_abs(ekt_data.input, ABS_PRESSURE, 100);
+		input_report_key(ekt_data.input, BTN_TOUCH, finger_stat);
+		input_report_key(ekt_data.input, BTN_2, finger_stat == 2);
+
+		if (finger_stat > 1) {
+			ekt8232_parse_xy(&buf[4], &x2, &y2);
+			dev_dbg(&client->dev, "x2 = %d, y2 = %d\n", x2, y2);
+			input_report_abs(ekt_data.input, ABS_HAT0X, x2);
+			input_report_abs(ekt_data.input, ABS_HAT0Y, y2);
+		}
+		input_sync(ekt_data.input);
+		break;
+	}
+	default:
+		dev_err(&client->dev,
+			"%s: Unknown packet type: %0x\n", __func__, buf[0]);
+		break;
+	}
+
+	report_time2 = jiffies;
+	dev_dbg(&client->dev,
+		"report time = %d\n",
+		jiffies_to_msecs(report_time2 - report_time));
+
+	report_time = report_time2;
+
+}
+
+static void ekt8232_work_func(struct work_struct *work)
+{
+	int rc;
+	uint8_t buf[IDX_PACKET_SIZE] = { 0 };
+	struct i2c_client *client = ekt_data.client;
+
+	/* dev_dbg(&client->dev, "%s: enter. \n", __func__); */
+
+	/* this means that we have already serviced it */
+	if (ekt8232_detect_int_level())
+		return;
+
+	rc = ekt8232_recv_data(client, buf);
+	if (rc < 0)
+		return;
+
+	ekt8232_report_data(client, buf);
+}
+
+static irqreturn_t ekt8232_ts_interrupt(int irq, void *dev_id)
+{
+	/* the queue_work has spin_lock protection */
+	/* disable_irq(irq); */
+	queue_work(elan_wq, &ekt_data.work);
+
+	return IRQ_HANDLED;
+}
+
+static enum hrtimer_restart ekt8232_ts_timer_func(struct hrtimer *timer)
+{
+	queue_work(elan_wq, &ekt_data.work);
+	hrtimer_start(&ekt_data.timer,
+		      ktime_set(0, 12500000),
+		      HRTIMER_MODE_REL);
+
+	return HRTIMER_NORESTART;
+}
+
+static int ekt8232_register_interrupt(struct i2c_client *client)
+{
+	int err = 0;
+
+	if (client->irq) {
+		ekt_data.use_irq = 1;
+
+		err = request_irq(client->irq, ekt8232_ts_interrupt, 0,
+				  EKT8232NAME, &ekt_data);
+		if (err < 0) {
+			dev_err(&client->dev,
+				"%s(%s): Can't allocate irq %d\n",
+				__FILE__, __func__, client->irq);
+			ekt_data.use_irq = 0;
+		}
+	}
+
+	if (!ekt_data.use_irq) {
+		hrtimer_init(&ekt_data.timer,
+			     CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		ekt_data.timer.function = ekt8232_ts_timer_func;
+		hrtimer_start(&ekt_data.timer, ktime_set(1, 0),
+			      HRTIMER_MODE_REL);
+	}
+
+	dev_dbg(&client->dev,
+		"elan starts in %s mode.\n",
+		ekt_data.use_irq == 1 ? "interrupt":"polling");
+	return 0;
+}
+
+static int ekt8232_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int err = 0;
+	struct elan_i2c_platform_data *pdata;
+	int x_max, y_max;
+	uint8_t x_resolution_cmd[] = { read_cmd_packet, 0x60, 0x00, 0x01 };
+	uint8_t y_resolution_cmd[] = { read_cmd_packet, 0x63, 0x00, 0x01 };
+	uint8_t buf_recv[4] = { 0 };
+
+	elan_wq = create_singlethread_workqueue("elan_wq");
+	if (!elan_wq) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	printk(KERN_INFO "ekt8232_probe enter.\n");
+	dev_dbg(&client->dev, "ekt8232_probe enter.\n");
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev,
+			"No supported i2c func what we need?!!\n");
+		err = -ENOTSUPP;
+		goto fail;
+	}
+
+	ekt_data.client = client;
+	strlcpy(client->name, EKT8232NAME, I2C_NAME_SIZE);
+	i2c_set_clientdata(client, &ekt_data);
+	INIT_WORK(&ekt_data.work, ekt8232_work_func);
+	init_waitqueue_head(&ekt_data.wait);
+
+	ekt_data.input = input_allocate_device();
+	if (ekt_data.input == NULL) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	pdata = client->dev.platform_data;
+	if (likely(pdata != NULL)) {
+		ekt_data.intr_gpio =
+			((struct elan_i2c_platform_data *)pdata)->intr_gpio;
+		ekt_data.power =
+			((struct elan_i2c_platform_data *)pdata)->power;
+		ekt_data.power(1);
+		dev_info(&client->dev, "touch panel is powered on. \n");
+		mdelay(500);	/* elan will be ready after about 500 ms */
+	} else {
+		dev_err(&client->dev, "without platform data??!!\n");
+	}
+
+	err = ekt8232_ts_init(client);
+	if (err < 0) {
+		printk(KERN_INFO "looks like it's not Elan, so..i'll quit\n");
+		err = -ENODEV;
+		goto fail;
+	}
+
+	if (pdata) {
+		while (pdata->version > ekt_data.fw_ver) {
+			printk(KERN_INFO "ekt8232_probe: old tp detected, "
+					"panel version = 0x%x\n",
+					ekt_data.fw_ver);
+			pdata++;
+		}
+	}
+	printk(KERN_INFO "ekt8232_register_input\n");
+
+	ekt_data.input->name = EKT8232NAME;
+	ekt_data.input->id.bustype = BUS_I2C;
+	set_bit(EV_SYN, ekt_data.input->evbit);
+	set_bit(EV_KEY, ekt_data.input->evbit);
+	set_bit(BTN_TOUCH, ekt_data.input->keybit);
+	set_bit(BTN_2, ekt_data.input->keybit);
+	set_bit(EV_ABS, ekt_data.input->evbit);
+
+	if (ekt_data.fw_ver >= 0x104) {
+		err = ekt8232_get_data(ekt_data.client, x_resolution_cmd,
+				       buf_recv, 4, 0);
+		if (err < 0) {
+			dev_err(&client->dev,
+				"%s: get x resolution failed, err = %d\n",
+				__func__, err);
+			goto fail;
+		}
+
+		x_max = ((buf_recv[3] & 0xf0) << 4) | ((buf_recv[2] & 0xff));
+		printk(KERN_INFO "ekt8232_probe: x_max: %d\n", x_max);
+
+		err = ekt8232_get_data(ekt_data.client, y_resolution_cmd,
+				      buf_recv, 4, 0);
+		if (err < 0) {
+			dev_err(&client->dev,
+				"%s: get y resolution failed, err = %d\n",
+				__func__, err);
+			goto fail;
+		}
+
+		y_max = ((buf_recv[3] & 0xf0) << 4) | ((buf_recv[2] & 0xff));
+		printk(KERN_INFO "ekt8232_probe: y_max: %d\n", y_max);
+		input_set_abs_params(ekt_data.input, ABS_X,
+				     pdata->abs_x_min, x_max,
+				     ELAN_TS_FUZZ, ELAN_TS_FLAT);
+		input_set_abs_params(ekt_data.input, ABS_Y,
+				     pdata->abs_y_min, y_max,
+				     ELAN_TS_FUZZ, ELAN_TS_FLAT);
+		input_set_abs_params(ekt_data.input, ABS_HAT0X,
+				     pdata->abs_x_min, x_max,
+				     ELAN_TS_FUZZ, ELAN_TS_FLAT);
+		input_set_abs_params(ekt_data.input, ABS_HAT0Y,
+				     pdata->abs_y_min, y_max,
+				     ELAN_TS_FUZZ, ELAN_TS_FLAT);
+	} else {
+		input_set_abs_params(ekt_data.input, ABS_X,
+				     pdata->abs_x_min,  pdata->abs_x_max,
+				     ELAN_TS_FUZZ, ELAN_TS_FLAT);
+		input_set_abs_params(ekt_data.input, ABS_Y,
+				     pdata->abs_y_min,  pdata->abs_y_max,
+				     ELAN_TS_FUZZ, ELAN_TS_FLAT);
+		input_set_abs_params(ekt_data.input, ABS_HAT0X,
+				     pdata->abs_x_min,  pdata->abs_x_max,
+				     ELAN_TS_FUZZ, ELAN_TS_FLAT);
+		input_set_abs_params(ekt_data.input, ABS_HAT0Y,
+				     pdata->abs_y_min,  pdata->abs_y_max,
+				     ELAN_TS_FUZZ, ELAN_TS_FLAT);
+		input_set_abs_params(ekt_data.input, ABS_PRESSURE, 0, 255,
+				     ELAN_TS_FUZZ, ELAN_TS_FLAT);
+		input_set_abs_params(ekt_data.input, ABS_TOOL_WIDTH, 1, 8,
+				     1, ELAN_TS_FLAT);
+	}
+
+	err = input_register_device(ekt_data.input);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"%s: input_register_device failed, err = %d\n",
+			__func__, err);
+		goto fail;
+	}
+
+	ekt8232_register_interrupt(ekt_data.client);
+
+	/* checking the interrupt to avoid missing any interrupt */
+	if (ekt8232_detect_int_level() == 0)
+		ekt8232_ts_interrupt(client->irq, NULL);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ekt_data.early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ekt_data.early_suspend.suspend = elan_ts_early_suspend;
+	ekt_data.early_suspend.resume = elan_ts_late_resume;
+	register_early_suspend(&ekt_data.early_suspend);
+#endif
+	touch_sysfs_init();
+	return 0;
+
+fail:
+	input_free_device(ekt_data.input);
+	if (elan_wq)
+		destroy_workqueue(elan_wq);
+	return err;
+}
+
+static int ekt8232_remove(struct i2c_client *client)
+{
+	struct ekt8232_data *tp = i2c_get_clientdata(client);
+
+	if (elan_wq)
+		destroy_workqueue(elan_wq);
+
+	dev_dbg(&client->dev, "%s: enter.\n", __func__);
+
+	input_unregister_device(tp->input);
+
+	if (ekt_data.use_irq)
+		free_irq(client->irq, tp);
+	else
+		hrtimer_cancel(&ekt_data.timer);
+	return 0;
+}
+
+static int ekt8232_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	uint8_t cmd[4];
+	int rc = 0;
+
+	dev_dbg(&client->dev, "%s: enter. irq = %d\n", __func__, client->irq);
+
+	cancel_work_sync(&ekt_data.work);
+
+	rc = ekt8232_set_power_state(client, STATE_DEEP_SLEEP);
+/*
+	rc = ekt8232_get_power_state(client);
+	if (rc < 0 || rc != STATE_DEEP_SLEEP)
+		dev_err(&client->dev,
+			"%s: put tp into sleep failed, err = %d!\n",
+			__func__, rc);
+*/
+	/* disable tp interrupt */
+	if (ekt_data.fw_ver > 0x101) {
+		memset(cmd, disable_int, 4);
+		if ((i2c_master_send(client, cmd, sizeof(cmd))) != sizeof(cmd))
+			dev_err(&client->dev,
+				"%s: tp disable interrupt failed\n", __func__);
+	}
+
+	/* power off level shift */
+	ekt_data.power(0);
+
+	return 0;
+}
+
+static int ekt8232_resume(struct i2c_client *client)
+{
+	int rc = 0, retry = 5;
+
+	dev_dbg(&client->dev,
+		"%s: enter. irq = %d\n", __func__, client->irq);
+
+	disable_irq(client->irq);
+
+	/* power on level shift */
+	ekt_data.power(1);
+
+	/* re-initial */
+	if (ekt_data.fw_ver > 0x101) {
+		msleep(500);
+		rc = ekt8232_ts_init(client);
+	} else {
+		do {
+			rc = ekt8232_set_power_state(client, STATE_NORMAL);
+			rc = ekt8232_get_power_state(client);
+			if (rc != STATE_NORMAL)
+				dev_err(&client->dev,
+					"%s: wake up tp failed! err = %d\n",
+					__func__, rc);
+			else
+				break;
+		} while (--retry);
+	}
+
+	enable_irq(client->irq);
+
+	if (ekt8232_detect_int_level() == 0)
+		ekt8232_ts_interrupt(client->irq, NULL);
+
+	return 0;
+}
+
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void elan_ts_early_suspend(struct early_suspend *h)
+{
+	struct i2c_client *client = ekt_data.client;
+
+	dev_dbg(&client->dev, "%s enter.\n", __func__);
+	ekt8232_suspend(client, PMSG_SUSPEND);
+}
+
+static void elan_ts_late_resume(struct early_suspend *h)
+{
+	struct i2c_client *client = ekt_data.client;
+
+	dev_dbg(&client->dev, "%s enter.\n", __func__);
+	ekt8232_resume(client);
+}
+#endif
+
+/* -------------------------------------------------------------------- */
+static const struct i2c_device_id ekt8232_ts_id[] = {
+	{ ELAN_8232_I2C_NAME, 0 },
+	{ }
+};
+
+static struct i2c_driver ekt8232_driver = {
+	.probe		= ekt8232_probe,
+	.remove		= ekt8232_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend	= ekt8232_suspend,
+	.resume		= ekt8232_resume,
+#endif
+	.id_table	= ekt8232_ts_id,
+	.driver		= {
+		.name = ELAN_8232_I2C_NAME,
+	},
+};
+
+static int __init ekt8232_init(void)
+{
+	return i2c_add_driver(&ekt8232_driver);
+}
+
+static void __exit ekt8232_exit(void)
+{
+	i2c_del_driver(&ekt8232_driver);
+}
+
+module_init(ekt8232_init);
+module_exit(ekt8232_exit);
+
+MODULE_AUTHOR("Shan-Fu Chiou <sfchiou@gmail.com>, "
+	      "Jay Tu <jay_tu@htc.com>");
+MODULE_DESCRIPTION("ELAN ekt8232 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/msm_ts.c b/drivers/input/touchscreen/msm_ts.c
new file mode 100644
index 0000000..dff730a
--- /dev/null
+++ b/drivers/input/touchscreen/msm_ts.c
@@ -0,0 +1,344 @@
+/* drivers/input/touchscreen/msm_ts.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.
+ *
+ * TODO:
+ *      - Add a timer to simulate a pen_up in case there's a timeout.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <mach/msm_ts.h>
+
+#define TSSC_CTL			0x100
+#define 	TSSC_CTL_PENUP_IRQ	(1 << 12)
+#define 	TSSC_CTL_DATA_FLAG	(1 << 11)
+#define 	TSSC_CTL_DEBOUNCE_EN	(1 << 6)
+#define 	TSSC_CTL_EN_AVERAGE	(1 << 5)
+#define 	TSSC_CTL_MODE_MASTER	(3 << 3)
+#define 	TSSC_CTL_ENABLE		(1 << 0)
+#define TSSC_OPN			0x104
+#define 	TSSC_OPN_NOOP		0x00
+#define 	TSSC_OPN_4WIRE_X	0x01
+#define 	TSSC_OPN_4WIRE_Y	0x02
+#define 	TSSC_OPN_4WIRE_Z1	0x03
+#define 	TSSC_OPN_4WIRE_Z2	0x04
+#define TSSC_SAMPLING_INT		0x108
+#define TSSC_STATUS			0x10c
+#define TSSC_AVG_12			0x110
+#define TSSC_AVG_34			0x114
+#define TSSC_SAMPLE(op,samp)		((0x118 + ((op & 0x3) * 0x20)) + \
+					 ((samp & 0x7) * 0x4))
+#define TSSC_TEST_1			0x198
+#define TSSC_TEST_2			0x19c
+
+struct msm_ts {
+	struct msm_ts_platform_data	*pdata;
+	struct input_dev		*input_dev;
+	void __iomem			*tssc_base;
+	uint32_t			ts_down:1;
+	struct ts_virt_key		*vkey_down;
+};
+
+static uint32_t msm_tsdebug;
+module_param_named(tsdebug, msm_tsdebug, uint, 0664);
+
+#define tssc_readl(t, a)	(readl(((t)->tssc_base) + (a)))
+#define tssc_writel(t, v, a)	do {writel(v, ((t)->tssc_base) + (a));} while(0)
+
+static void setup_next_sample(struct msm_ts *ts)
+{
+	uint32_t tmp;
+
+	/* 1.2ms debounce time */
+	tmp = ((2 << 7) | TSSC_CTL_DEBOUNCE_EN | TSSC_CTL_EN_AVERAGE |
+	       TSSC_CTL_MODE_MASTER | TSSC_CTL_ENABLE);
+	tssc_writel(ts, tmp, TSSC_CTL);
+}
+
+static struct ts_virt_key *find_virt_key(struct msm_ts *ts,
+					 struct msm_ts_virtual_keys *vkeys,
+					 uint32_t val)
+{
+	int i;
+
+	if (!vkeys)
+		return NULL;
+
+	for (i = 0; i < vkeys->num_keys; ++i)
+		if ((val >= vkeys->keys[i].min) && (val <= vkeys->keys[i].max))
+			return &vkeys->keys[i];
+	return NULL;
+}
+
+
+static irqreturn_t msm_ts_irq(int irq, void *dev_id)
+{
+	struct msm_ts *ts = dev_id;
+	struct msm_ts_platform_data *pdata = ts->pdata;
+
+	uint32_t tssc_avg12, tssc_avg34, tssc_status, tssc_ctl;
+	int x, y, z1, z2;
+	int was_down;
+	int down;
+
+	tssc_ctl = tssc_readl(ts, TSSC_CTL);
+	tssc_status = tssc_readl(ts, TSSC_STATUS);
+	tssc_avg12 = tssc_readl(ts, TSSC_AVG_12);
+	tssc_avg34 = tssc_readl(ts, TSSC_AVG_34);
+
+	setup_next_sample(ts);
+
+	x = tssc_avg12 & 0xffff;
+	y = tssc_avg12 >> 16;
+	z1 = tssc_avg34 & 0xffff;
+	z2 = tssc_avg34 >> 16;
+
+	/* invert the inputs if necessary */
+	if (pdata->inv_x) x = pdata->inv_x - x;
+	if (pdata->inv_y) y = pdata->inv_y - y;
+	if (x < 0) x = 0;
+	if (y < 0) y = 0;
+
+	down = !(tssc_ctl & TSSC_CTL_PENUP_IRQ);
+	was_down = ts->ts_down;
+	ts->ts_down = down;
+
+	/* no valid data */
+	if (down && !(tssc_ctl & TSSC_CTL_DATA_FLAG))
+		return IRQ_HANDLED;
+
+	if (msm_tsdebug & 2)
+		printk("%s: down=%d, x=%d, y=%d, z1=%d, z2=%d, status %x\n",
+		       __func__, down, x, y, z1, z2, tssc_status);
+
+	if (!was_down && down) {
+		struct ts_virt_key *vkey = NULL;
+
+		if (pdata->vkeys_y && (y > pdata->virt_y_start))
+			vkey = find_virt_key(ts, pdata->vkeys_y, x);
+		if (!vkey && ts->pdata->vkeys_x && (x > pdata->virt_x_start))
+			vkey = find_virt_key(ts, pdata->vkeys_x, y);
+
+		if (vkey) {
+			WARN_ON(ts->vkey_down != NULL);
+			if(msm_tsdebug)
+				printk("%s: virtual key down %d\n", __func__,
+				       vkey->key);
+			ts->vkey_down = vkey;
+			input_report_key(ts->input_dev, vkey->key, 1);
+			input_sync(ts->input_dev);
+			return IRQ_HANDLED;
+		}
+	} else if (ts->vkey_down != NULL) {
+		if (!down) {
+			if(msm_tsdebug)
+				printk("%s: virtual key up %d\n", __func__,
+				       ts->vkey_down->key);
+			input_report_key(ts->input_dev, ts->vkey_down->key, 0);
+			input_sync(ts->input_dev);
+			ts->vkey_down = NULL;
+		}
+		return IRQ_HANDLED;
+	}
+
+	if (down) {
+		input_report_abs(ts->input_dev, ABS_X, x);
+		input_report_abs(ts->input_dev, ABS_Y, y);
+		input_report_abs(ts->input_dev, ABS_PRESSURE, z1);
+	}
+	input_report_key(ts->input_dev, BTN_TOUCH, down);
+	input_sync(ts->input_dev);
+
+	return IRQ_HANDLED;
+}
+
+static void dump_tssc_regs(struct msm_ts *ts)
+{
+#define __dump_tssc_reg(r) \
+		do { printk(#r " %x\n", tssc_readl(ts, (r))); } while(0)
+
+	__dump_tssc_reg(TSSC_CTL);
+	__dump_tssc_reg(TSSC_OPN);
+	__dump_tssc_reg(TSSC_SAMPLING_INT);
+	__dump_tssc_reg(TSSC_STATUS);
+	__dump_tssc_reg(TSSC_AVG_12);
+	__dump_tssc_reg(TSSC_AVG_34);
+#undef __dump_tssc_reg
+}
+
+static int __devinit msm_ts_hw_init(struct msm_ts *ts)
+{
+	uint32_t tmp;
+
+	/* Enable the register clock to tssc so we can configure it. */
+	tssc_writel(ts, TSSC_CTL_ENABLE, TSSC_CTL);
+
+	/* op1 - measure X, 1 sample, 12bit resolution */
+	tmp = (TSSC_OPN_4WIRE_X << 16) | (2 << 8) | (2 << 0);
+	/* op2 - measure Y, 1 sample, 12bit resolution */
+	tmp |= (TSSC_OPN_4WIRE_Y << 20) | (2 << 10) | (2 << 2);
+	/* op3 - measure Z1, 1 sample, 8bit resolution */
+	tmp |= (TSSC_OPN_4WIRE_Z1 << 24) | (2 << 12) | (0 << 4);
+
+	/* XXX: we don't actually need to measure Z2 (thus 0 samples) when
+	 * doing voltage-driven measurement */
+	/* op4 - measure Z2, 0 samples, 8bit resolution */
+	tmp |= (TSSC_OPN_4WIRE_Z2 << 28) | (0 << 14) | (0 << 6);
+	tssc_writel(ts, tmp, TSSC_OPN);
+
+	/* 16ms sampling interval */
+	tssc_writel(ts, 16, TSSC_SAMPLING_INT);
+
+	setup_next_sample(ts);
+
+	return 0;
+}
+
+static int __devinit msm_ts_probe(struct platform_device *pdev)
+{
+	struct msm_ts_platform_data *pdata = pdev->dev.platform_data;
+	struct msm_ts *ts;
+	struct resource *tssc_res;
+	struct resource *irq1_res;
+	struct resource *irq2_res;
+	int err = 0;
+	int i;
+
+	tssc_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tssc");
+	irq1_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tssc1");
+	irq2_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tssc2");
+
+	if (!tssc_res || !irq1_res || !irq2_res) {
+		pr_err("%s: required resources not defined\n", __func__);
+		return -ENODEV;
+	}
+
+	if (pdata == NULL) {
+		pr_err("%s: missing platform_data\n", __func__);
+		return -ENODEV;
+	}
+
+	ts = kzalloc(sizeof(struct msm_ts), GFP_KERNEL);
+	if (ts == NULL) {
+		pr_err("%s: No memory for struct msm_ts\n", __func__);
+		return -ENOMEM;
+	}
+	ts->pdata = pdata;
+
+	ts->tssc_base = ioremap(tssc_res->start, resource_size(tssc_res));
+	if (ts->tssc_base == NULL) {
+		pr_err("%s: Can't ioremap region (0x%08x - 0x%08x)\n", __func__,
+		       (uint32_t)tssc_res->start, (uint32_t)tssc_res->end);
+		err = -ENOMEM;
+		goto err_ioremap_tssc;
+	}
+
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) {
+		pr_err("failed to allocate touchscreen input device\n");
+		err = -ENOMEM;
+		goto err_alloc_input_dev;
+	}
+	ts->input_dev->name = "msm-touchscreen";
+	input_set_drvdata(ts->input_dev, ts);
+
+	input_set_capability(ts->input_dev, EV_KEY, BTN_TOUCH);
+	set_bit(EV_ABS, ts->input_dev->evbit);
+
+	input_set_abs_params(ts->input_dev, ABS_X, pdata->min_x, pdata->max_x,
+			     0, 0);
+	input_set_abs_params(ts->input_dev, ABS_Y, pdata->min_y, pdata->max_y,
+			     0, 0);
+	input_set_abs_params(ts->input_dev, ABS_PRESSURE, pdata->min_press,
+			     pdata->max_press, 0, 0);
+
+	for (i = 0; pdata->vkeys_x && (i < pdata->vkeys_x->num_keys); ++i)
+		input_set_capability(ts->input_dev, EV_KEY,
+				     pdata->vkeys_x->keys[i].key);
+	for (i = 0; pdata->vkeys_y && (i < pdata->vkeys_y->num_keys); ++i)
+		input_set_capability(ts->input_dev, EV_KEY,
+				     pdata->vkeys_y->keys[i].key);
+
+	err = input_register_device(ts->input_dev);
+	if (err != 0) {
+		pr_err("%s: failed to register input device\n", __func__);
+		goto err_input_dev_reg;
+	}
+
+	msm_ts_hw_init(ts);
+
+	err = request_irq(irq1_res->start, msm_ts_irq,
+			  (irq1_res->flags & ~IORESOURCE_IRQ) | IRQF_DISABLED,
+			  "msm_touchscreen", ts);
+	if (err != 0) {
+		pr_err("%s: Cannot register irq1 (%d)\n", __func__, err);
+		goto err_request_irq1;
+	}
+
+	err = request_irq(irq2_res->start, msm_ts_irq,
+			  (irq2_res->flags & ~IORESOURCE_IRQ) | IRQF_DISABLED,
+			  "msm_touchscreen", ts);
+	if (err != 0) {
+		pr_err("%s: Cannot register irq2 (%d)\n", __func__, err);
+		goto err_request_irq2;
+	}
+
+	platform_set_drvdata(pdev, ts);
+
+	pr_info("%s: tssc_base=%p irq1=%d irq2=%d\n", __func__,
+		ts->tssc_base, (int)irq1_res->start, (int)irq2_res->start);
+	return 0;
+
+err_request_irq2:
+	free_irq(irq1_res->start, ts);
+
+err_request_irq1:
+	/* disable the tssc */
+	tssc_writel(ts, TSSC_CTL_ENABLE, TSSC_CTL);
+
+err_input_dev_reg:
+	input_set_drvdata(ts->input_dev, NULL);
+	input_free_device(ts->input_dev);
+
+err_alloc_input_dev:
+	iounmap(ts->tssc_base);
+
+err_ioremap_tssc:
+	kfree(ts);
+	return err;
+}
+
+static struct platform_driver msm_touchscreen_driver = {
+	.driver = {
+		.name = "msm_touchscreen",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_ts_probe,
+};
+
+static int __init msm_ts_init(void)
+{
+	return platform_driver_register(&msm_touchscreen_driver);
+}
+device_initcall(msm_ts_init);
+
+MODULE_DESCRIPTION("Qualcomm MSM/QSD Touchscreen controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 65dd750..115b099 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -176,6 +176,13 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called leds-lp3944.
 
+config LEDS_CPLD
+	tristate "LED Support for CPLD connected LEDs"
+	default y
+	depends on LEDS_CLASS
+	help
+	  This option enables support for the LEDs connected to CPLD
+
 config LEDS_CLEVO_MAIL
 	tristate "Mail LED on Clevo notebook"
 	depends on X86 && SERIO_I8042 && DMI
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index b68fcf6..f88e24a 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -23,6 +23,7 @@
 obj-$(CONFIG_LEDS_PCA9532)		+= leds-pca9532.o
 obj-$(CONFIG_LEDS_GPIO)			+= leds-gpio.o
 obj-$(CONFIG_LEDS_LP3944)		+= leds-lp3944.o
+obj-$(CONFIG_LEDS_CPLD)			+= leds-cpld.o
 obj-$(CONFIG_LEDS_CLEVO_MAIL)		+= leds-clevo-mail.o
 obj-$(CONFIG_LEDS_HP6XX)		+= leds-hp6xx.o
 obj-$(CONFIG_LEDS_FSG)			+= leds-fsg.o
diff --git a/drivers/leds/leds-cpld.c b/drivers/leds/leds-cpld.c
new file mode 100644
index 0000000..eab004c
--- /dev/null
+++ b/drivers/leds/leds-cpld.c
@@ -0,0 +1,405 @@
+/* include/asm/mach-msm/leds-cpld.c
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ *
+ * Author: Farmer Tseng
+ *
+ * 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/device.h>
+#include <linux/leds.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <asm/mach-types.h>
+
+#define DEBUG_LED_CHANGE 0
+
+static int _g_cpld_led_addr;
+
+struct CPLD_LED_data {
+	spinlock_t data_lock;
+	struct led_classdev leds[4];	/* blue, green, red */
+};
+
+static ssize_t led_blink_solid_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct CPLD_LED_data *CPLD_LED;
+	int idx = 2;
+	uint8_t reg_val;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret = 0;
+
+	if (!strcmp(led_cdev->name, "red"))
+		idx = 0;
+	else if (!strcmp(led_cdev->name, "green"))
+		idx = 1;
+	else
+		idx = 2;
+
+	CPLD_LED = container_of(led_cdev, struct CPLD_LED_data, leds[idx]);
+
+	spin_lock(&CPLD_LED->data_lock);
+	reg_val = readb(_g_cpld_led_addr);
+	reg_val = reg_val >> (2 * idx + 1);
+	reg_val &= 0x1;
+	spin_unlock(&CPLD_LED->data_lock);
+
+	/* no lock needed for this */
+	sprintf(buf, "%u\n", reg_val);
+	ret = strlen(buf) + 1;
+
+	return ret;
+}
+
+static ssize_t led_blink_solid_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t size)
+{
+	struct CPLD_LED_data *CPLD_LED;
+	int idx = 2;
+	uint8_t reg_val;
+	char *after;
+	unsigned long state;
+	ssize_t ret = -EINVAL;
+	size_t count;
+
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+	if (!strcmp(led_cdev->name, "red"))
+		idx = 0;
+	else if (!strcmp(led_cdev->name, "green"))
+		idx = 1;
+	else
+		idx = 2;
+
+	CPLD_LED = container_of(led_cdev, struct CPLD_LED_data, leds[idx]);
+
+	state = simple_strtoul(buf, &after, 10);
+
+	count = after - buf;
+
+	if (*after && isspace(*after))
+		count++;
+
+	if (count == size) {
+		ret = count;
+		spin_lock(&CPLD_LED->data_lock);
+		reg_val = readb(_g_cpld_led_addr);
+		if (state)
+			reg_val |= 1 << (2 * idx + 1);
+		else
+			reg_val &= ~(1 << (2 * idx + 1));
+
+		writeb(reg_val, _g_cpld_led_addr);
+		spin_unlock(&CPLD_LED->data_lock);
+	}
+
+	return ret;
+}
+
+static DEVICE_ATTR(blink, 0644, led_blink_solid_show, led_blink_solid_store);
+
+static ssize_t cpldled_blink_all_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	uint8_t reg_val;
+	struct CPLD_LED_data *CPLD_LED = dev_get_drvdata(dev);
+	ssize_t ret = 0;
+
+	spin_lock(&CPLD_LED->data_lock);
+	reg_val = readb(_g_cpld_led_addr);
+	reg_val &= 0x2A;
+	if (reg_val == 0x2A)
+		reg_val = 1;
+	else
+		reg_val = 0;
+	spin_unlock(&CPLD_LED->data_lock);
+
+	/* no lock needed for this */
+	sprintf(buf, "%u\n", reg_val);
+	ret = strlen(buf) + 1;
+
+	return ret;
+}
+
+static ssize_t cpldled_blink_all_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t size)
+{
+	uint8_t reg_val;
+	char *after;
+	unsigned long state;
+	ssize_t ret = -EINVAL;
+	size_t count;
+	struct CPLD_LED_data *CPLD_LED = dev_get_drvdata(dev);
+
+	state = simple_strtoul(buf, &after, 10);
+
+	count = after - buf;
+
+	if (*after && isspace(*after))
+		count++;
+
+	if (count == size) {
+		ret = count;
+		spin_lock(&CPLD_LED->data_lock);
+		reg_val = readb(_g_cpld_led_addr);
+		if (state)
+			reg_val |= 0x2A;
+		else
+			reg_val &= ~0x2A;
+
+		writeb(reg_val, _g_cpld_led_addr);
+		spin_unlock(&CPLD_LED->data_lock);
+	}
+
+	return ret;
+}
+
+static struct device_attribute dev_attr_blink_all = {
+	.attr = {
+		 .name = "blink",
+		 .mode = 0644,
+		 },
+	.show = cpldled_blink_all_show,
+	.store = cpldled_blink_all_store,
+};
+
+static void led_brightness_set(struct led_classdev *led_cdev,
+			       enum led_brightness brightness)
+{
+	struct CPLD_LED_data *CPLD_LED;
+	int idx = 2;
+	struct led_classdev *led;
+	uint8_t reg_val;
+
+	if (!strcmp(led_cdev->name, "jogball-backlight")) {
+		if (brightness > 7)
+			reg_val = 1;
+		else
+			reg_val = brightness;
+		writeb(0, _g_cpld_led_addr + 0x8);
+		writeb(reg_val, _g_cpld_led_addr + 0x8);
+#if DEBUG_LED_CHANGE
+		printk(KERN_INFO "LED change: jogball backlight = %d \n",
+		       reg_val);
+#endif
+		return;
+	} else if (!strcmp(led_cdev->name, "red")) {
+		idx = 0;
+	} else if (!strcmp(led_cdev->name, "green")) {
+		idx = 1;
+	} else {
+		idx = 2;
+	}
+
+	CPLD_LED = container_of(led_cdev, struct CPLD_LED_data, leds[idx]);
+	spin_lock(&CPLD_LED->data_lock);
+	reg_val = readb(_g_cpld_led_addr);
+	led = &CPLD_LED->leds[idx];
+
+	if (led->brightness > LED_OFF)
+		reg_val |= 1 << (2 * idx);
+	else
+		reg_val &= ~(1 << (2 * idx));
+
+	writeb(reg_val, _g_cpld_led_addr);
+#if DEBUG_LED_CHANGE
+	printk(KERN_INFO "LED change: %s = %d \n", led_cdev->name, led->brightness);
+#endif
+	spin_unlock(&CPLD_LED->data_lock);
+}
+
+static ssize_t cpldled_grpfreq_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%u\n", 0);
+}
+
+static ssize_t cpldled_grpfreq_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	return 0;
+}
+
+static DEVICE_ATTR(grpfreq, 0644, cpldled_grpfreq_show, cpldled_grpfreq_store);
+
+static ssize_t cpldled_grppwm_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%u\n", 0);
+}
+
+static ssize_t cpldled_grppwm_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	return 0;
+}
+
+static DEVICE_ATTR(grppwm, 0644, cpldled_grppwm_show, cpldled_grppwm_store);
+
+static int CPLD_LED_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	int i, j;
+	struct resource *res;
+	struct CPLD_LED_data *CPLD_LED;
+
+	CPLD_LED = kzalloc(sizeof(struct CPLD_LED_data), GFP_KERNEL);
+	if (CPLD_LED == NULL) {
+		printk(KERN_ERR "CPLD_LED_probe: no memory for device\n");
+		ret = -ENOMEM;
+		goto err_alloc_failed;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENOMEM;
+		goto err_alloc_failed;
+	}
+
+	_g_cpld_led_addr = res->start;
+	if (!_g_cpld_led_addr) {
+		ret = -ENOMEM;
+		goto err_alloc_failed;
+	}
+
+	memset(CPLD_LED, 0, sizeof(struct CPLD_LED_data));
+	writeb(0x00, _g_cpld_led_addr);
+
+	CPLD_LED->leds[0].name = "red";
+	CPLD_LED->leds[0].brightness_set = led_brightness_set;
+
+	CPLD_LED->leds[1].name = "green";
+	CPLD_LED->leds[1].brightness_set = led_brightness_set;
+
+	CPLD_LED->leds[2].name = "blue";
+	CPLD_LED->leds[2].brightness_set = led_brightness_set;
+
+	CPLD_LED->leds[3].name = "jogball-backlight";
+	CPLD_LED->leds[3].brightness_set = led_brightness_set;
+
+	spin_lock_init(&CPLD_LED->data_lock);
+
+	for (i = 0; i < 4; i++) {	/* red, green, blue jogball */
+		ret = led_classdev_register(&pdev->dev, &CPLD_LED->leds[i]);
+		if (ret) {
+			printk(KERN_ERR
+			       "CPLD_LED: led_classdev_register failed\n");
+			goto err_led_classdev_register_failed;
+		}
+	}
+
+	for (i = 0; i < 3; i++) {
+		ret =
+		    device_create_file(CPLD_LED->leds[i].dev, &dev_attr_blink);
+		if (ret) {
+			printk(KERN_ERR
+			       "CPLD_LED: device_create_file failed\n");
+			goto err_out_attr_blink;
+		}
+	}
+
+	dev_set_drvdata(&pdev->dev, CPLD_LED);
+	ret = device_create_file(&pdev->dev, &dev_attr_blink_all);
+	if (ret) {
+		printk(KERN_ERR
+		       "CPLD_LED: create dev_attr_blink_all failed\n");
+		goto err_out_attr_blink;
+	}
+	ret = device_create_file(&pdev->dev, &dev_attr_grppwm);
+	if (ret) {
+		printk(KERN_ERR
+		       "CPLD_LED: create dev_attr_grppwm failed\n");
+		goto err_out_attr_grppwm;
+	}
+	ret = device_create_file(&pdev->dev, &dev_attr_grpfreq);
+	if (ret) {
+		printk(KERN_ERR
+		       "CPLD_LED: create dev_attr_grpfreq failed\n");
+		goto err_out_attr_grpfreq;
+	}
+
+	return 0;
+
+err_out_attr_grpfreq:
+	device_remove_file(&pdev->dev, &dev_attr_grppwm);
+err_out_attr_grppwm:
+	device_remove_file(&pdev->dev, &dev_attr_blink_all);
+err_out_attr_blink:
+	for (j = 0; j < i; j++)
+		device_remove_file(CPLD_LED->leds[j].dev, &dev_attr_blink);
+	i = 3;
+
+err_led_classdev_register_failed:
+	for (j = 0; j < i; j++)
+		led_classdev_unregister(&CPLD_LED->leds[j]);
+
+err_alloc_failed:
+	kfree(CPLD_LED);
+
+	return ret;
+}
+
+static int __devexit CPLD_LED_remove(struct platform_device *pdev)
+{
+	struct CPLD_LED_data *CPLD_LED;
+	int i;
+
+	CPLD_LED = platform_get_drvdata(pdev);
+
+	for (i = 0; i < 3; i++) {
+		device_remove_file(CPLD_LED->leds[i].dev, &dev_attr_blink);
+		led_classdev_unregister(&CPLD_LED->leds[i]);
+	}
+
+	device_remove_file(&pdev->dev, &dev_attr_blink_all);
+	device_remove_file(&pdev->dev, &dev_attr_grppwm);
+	device_remove_file(&pdev->dev, &dev_attr_grpfreq);
+
+	kfree(CPLD_LED);
+	return 0;
+}
+
+static struct platform_driver CPLD_LED_driver = {
+	.probe = CPLD_LED_probe,
+	.remove = __devexit_p(CPLD_LED_remove),
+	.driver = {
+		   .name = "leds-cpld",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __init CPLD_LED_init(void)
+{
+	return platform_driver_register(&CPLD_LED_driver);
+}
+
+static void __exit CPLD_LED_exit(void)
+{
+	platform_driver_unregister(&CPLD_LED_driver);
+}
+
+MODULE_AUTHOR("Farmer Tseng");
+MODULE_DESCRIPTION("CPLD_LED driver");
+MODULE_LICENSE("GPL");
+
+module_init(CPLD_LED_init);
+module_exit(CPLD_LED_exit);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index bdbc9d3..13e7409 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1126,8 +1126,12 @@
 	  This driver can be compiled as a module, called s2255drv.
 
 endif # V4L_USB_DRIVERS
+
 endif # VIDEO_CAPTURE_DRIVERS
 
+# MSM camera does not require V4L2
+source "drivers/media/video/msm/Kconfig"
+
 menuconfig V4L_MEM2MEM_DRIVERS
 	bool "Memory-to-memory multimedia devices"
 	depends on VIDEO_V4L2
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index cc93859..fbd3486 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -179,6 +179,8 @@
 
 obj-$(CONFIG_ARCH_DAVINCI)	+= davinci/
 
+obj-$(CONFIG_MSM_CAMERA) += msm/
+
 obj-$(CONFIG_ARCH_OMAP)	+= omap/
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
new file mode 100644
index 0000000..b4796d3
--- /dev/null
+++ b/drivers/media/video/msm/Kconfig
@@ -0,0 +1,48 @@
+comment "Qualcomm MSM Camera And Video"
+
+menuconfig MSM_CAMERA
+	bool "Qualcomm MSM camera and video capture support"
+	depends on ARCH_MSM
+	help
+	  Say Y here to enable selecting the video adapters for
+	  Qualcomm msm camera and video encoding
+
+config MSM_CAMERA_V4L2
+	bool "Video For Linux interface to MSM camera"
+	depends on MSM_CAMERA && VIDEO_V4L2 && EXPERIMENTAL
+	default y
+	help
+	  Say Y here to enable the V4L2 interface for the MSM camera.
+	  Not everything works through this interface and it has not
+	  been thoroughly tested.
+
+config MSM_CAMERA_DEBUG
+	bool "Qualcomm MSM camera debugging with printk"
+	depends on MSM_CAMERA
+	help
+	  Enable printk() debug for msm camera
+
+comment "Camera Sensor Selection"
+config MT9T013
+	bool "Sensor mt9t013 (BAYER 3M)"
+	depends on MSM_CAMERA
+	---help---
+	  MICRON 3M Bayer Sensor with AutoFocus
+
+config MT9D112
+	bool "Sensor mt9d112 (YUV 2M)"
+	depends on MSM_CAMERA
+	---help---
+	  MICRON 2M YUV Sensor
+
+config MT9P012
+	bool "Sensor mt9p012 (BAYER 5M)"
+	depends on MSM_CAMERA
+	---help---
+	  MICRON 5M Bayer Sensor with Autofocus
+
+config S5K3E2FX
+	bool "Sensor s5k3e2fx (Samsung 5M)"
+	depends on MSM_CAMERA
+	---help---
+	  Samsung 5M with Autofocus
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
new file mode 100755
index 0000000..61e370c
--- /dev/null
+++ b/drivers/media/video/msm/Makefile
@@ -0,0 +1,9 @@
+obj-$(CONFIG_MT9T013) += mt9t013.o mt9t013_reg.o
+obj-$(CONFIG_MT9D112) += mt9d112.o mt9d112_reg.o
+obj-$(CONFIG_MT9P012) += mt9p012_fox.o mt9p012_reg.o
+obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
+obj-$(CONFIG_MSM_CAMERA_V4L2) += msm_v4l2.o
+obj-$(CONFIG_S5K3E2FX) += s5k3e2fx.o
+obj-$(CONFIG_ARCH_MSM7X00A) += msm_vfe7x.o msm_io7x.o
+obj-$(CONFIG_ARCH_QSD8X50) += msm_vfe8x.o msm_vfe8x_proc.o msm_io8x.o
+obj-$(CONFIG_ARCH_MSM7X30) += msm_vfe31.o msm_io_vfe31.o
diff --git a/drivers/media/video/msm/msm_camera.c b/drivers/media/video/msm/msm_camera.c
new file mode 100644
index 0000000..42cd3ad
--- /dev/null
+++ b/drivers/media/video/msm/msm_camera.c
@@ -0,0 +1,2718 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+/* FIXME: management of mutexes */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <mach/board.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/android_pmem.h>
+#include <linux/poll.h>
+#include <linux/time.h>
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+
+#include <asm/cacheflush.h>
+
+#define MSM_MAX_CAMERA_SENSORS 5
+#define CAMERA_STOP_SNAPSHOT 42
+
+#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \
+				__func__, __LINE__, ((to) ? "to" : "from"))
+#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
+#define ERR_COPY_TO_USER() ERR_USER_COPY(1)
+
+static struct class *msm_class;
+static dev_t msm_devno;
+static LIST_HEAD(msm_sensors);
+
+#define __CONTAINS(r, v, l, field) ({				\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = __v >= __r->field &&				\
+		__e <= __r->field + __r->len;			\
+	res;							\
+})
+
+#define CONTAINS(r1, r2, field) ({				\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->field, __r2->len, field);		\
+})
+
+#define IN_RANGE(r, v, field) ({				\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->field) &&			\
+		(__vv < (__r->field + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2, field) ({				\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->field) __v = __r2->field;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v, field) ||		\
+		   IN_RANGE(__r1, __e, field));                 \
+	res;							\
+})
+
+static inline void free_qcmd(struct msm_queue_cmd *qcmd)
+{
+	if (!qcmd || !qcmd->on_heap)
+		return;
+	if (!--qcmd->on_heap)
+		kfree(qcmd);
+}
+
+static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+{
+	spin_lock_init(&queue->lock);
+	queue->len = 0;
+	queue->max = 0;
+	queue->name = name;
+	INIT_LIST_HEAD(&queue->list);
+	init_waitqueue_head(&queue->wait);
+}
+
+static void msm_enqueue(struct msm_device_queue *queue,
+		struct list_head *entry)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&queue->lock, flags);
+	queue->len++;
+	if (queue->len > queue->max) {
+		queue->max = queue->len;
+		pr_info("%s: queue %s new max is %d\n", __func__,
+			queue->name, queue->max);
+	}
+	list_add_tail(entry, &queue->list);
+	wake_up(&queue->wait);
+	CDBG("%s: woke up %s\n", __func__, queue->name);
+	spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+#define msm_dequeue(queue, member) ({				\
+	unsigned long flags;					\
+	struct msm_device_queue *__q = (queue);			\
+	struct msm_queue_cmd *qcmd = 0;				\
+	spin_lock_irqsave(&__q->lock, flags);			\
+	if (!list_empty(&__q->list)) {				\
+		__q->len--;					\
+		qcmd = list_first_entry(&__q->list,		\
+				struct msm_queue_cmd, member);	\
+		list_del_init(&qcmd->member);			\
+	}							\
+	spin_unlock_irqrestore(&__q->lock, flags);		\
+	qcmd;							\
+})
+
+#define msm_queue_drain(queue, member) do {			\
+	unsigned long flags;					\
+	struct msm_device_queue *__q = (queue);			\
+	struct msm_queue_cmd *qcmd;				\
+	spin_lock_irqsave(&__q->lock, flags);			\
+	CDBG("%s: draining queue %s\n", __func__, __q->name);	\
+	while (!list_empty(&__q->list)) {			\
+		qcmd = list_first_entry(&__q->list,		\
+			struct msm_queue_cmd, member);		\
+		list_del_init(&qcmd->member);			\
+		free_qcmd(qcmd);				\
+	};							\
+	__q->len = 0;						\
+	spin_unlock_irqrestore(&__q->lock, flags);		\
+} while(0)
+
+static int check_overlap(struct hlist_head *ptype,
+			unsigned long paddr,
+			unsigned long len)
+{
+	struct msm_pmem_region *region;
+	struct msm_pmem_region t = { .paddr = paddr, .len = len };
+	struct hlist_node *node;
+
+	hlist_for_each_entry(region, node, ptype, list) {
+		if (CONTAINS(region, &t, paddr) ||
+				CONTAINS(&t, region, paddr) ||
+				OVERLAPS(region, &t, paddr)) {
+			printk(KERN_ERR
+				" region (PHYS %p len %ld)"
+				" clashes with registered region"
+				" (paddr %p len %ld)\n",
+				(void *)t.paddr, t.len,
+				(void *)region->paddr, region->len);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int check_pmem_info(struct msm_pmem_info *info, int len)
+{
+	if (info->offset & (PAGE_SIZE - 1)) {
+		pr_err("%s: pmem offset is not page-aligned\n", __func__);
+		goto error;
+	}
+
+	if (info->offset < len &&
+	    info->offset + info->len <= len &&
+	    info->y_off < len &&
+	    info->cbcr_off < len)
+		return 0;
+
+error:
+	pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
+		__func__,
+		info->offset,
+		info->len,
+		info->y_off,
+		info->cbcr_off,
+		len);
+	return -EINVAL;
+}
+
+static int msm_pmem_table_add(struct hlist_head *ptype,
+	struct msm_pmem_info *info)
+{
+	struct file *file;
+	unsigned long paddr;
+	unsigned long kvstart;
+	unsigned long len;
+	int rc;
+	struct msm_pmem_region *region;
+
+	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
+	if (rc < 0) {
+		pr_err("%s: get_pmem_file fd %d error %d\n",
+			__func__,
+			info->fd, rc);
+		return rc;
+	}
+
+	if (!info->len)
+		info->len = len;
+
+	rc = check_pmem_info(info, len);
+	if (rc < 0)
+		return rc;
+
+	paddr += info->offset;
+	kvstart += info->offset;
+	len = info->len;
+
+	if (check_overlap(ptype, paddr, len) < 0)
+		return -EINVAL;
+
+	CDBG("%s: type %d, paddr 0x%lx, vaddr 0x%lx\n",
+		__func__,
+		info->type, paddr, (unsigned long)info->vaddr);
+
+	region = kmalloc(sizeof(struct msm_pmem_region), GFP_KERNEL);
+	if (!region)
+		return -ENOMEM;
+
+	INIT_HLIST_NODE(&region->list);
+
+	region->paddr = paddr;
+	region->kvaddr = kvstart;
+	region->len = len;
+	region->file = file;
+	memcpy(&region->info, info, sizeof(region->info));
+
+	if (info->vfe_can_write) {
+		dmac_map_area((void*)region->kvaddr, region->len, DMA_FROM_DEVICE);
+	}
+
+	hlist_add_head(&(region->list), ptype);
+
+	return 0;
+}
+
+/* return of 0 means failure */
+static uint8_t msm_pmem_region_lookup(struct hlist_head *ptype,
+	int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount)
+{
+	struct msm_pmem_region *region;
+	struct msm_pmem_region *regptr;
+	struct hlist_node *node, *n;
+
+	uint8_t rc = 0;
+
+	regptr = reg;
+
+	hlist_for_each_entry_safe(region, node, n, ptype, list) {
+		if (region->info.type == pmem_type &&
+			region->info.vfe_can_write) {
+				*regptr = *region;
+				rc += 1;
+				if (rc >= maxcount)
+					break;
+				regptr++;
+		}
+	}
+
+	return rc;
+}
+
+static int msm_pmem_frame_ptov_lookup(struct msm_sync *sync,
+		unsigned long pyaddr, unsigned long pcbcraddr,
+		struct msm_pmem_region **pmem_region,
+		int take_from_vfe)
+{
+	struct hlist_node *node, *n;
+	struct msm_pmem_region *region;
+
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) {
+		if (pyaddr == (region->paddr + region->info.y_off) &&
+				pcbcraddr == (region->paddr +
+						region->info.cbcr_off) &&
+				region->info.vfe_can_write) {
+			*pmem_region = region;
+			dmac_unmap_area((void*)region->kvaddr, region->len,
+					DMA_FROM_DEVICE);
+			region->info.vfe_can_write = !take_from_vfe;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync,
+		unsigned long addr, int *fd)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) {
+		if (addr == region->paddr && region->info.vfe_can_write) {
+			/* offset since we could pass vaddr inside a
+			 * registered pmem buffer */
+			*fd = region->info.fd;
+			dmac_unmap_area((void*)region->kvaddr, region->len,
+					DMA_FROM_DEVICE);
+			region->info.vfe_can_write = 0;
+			return (unsigned long)(region->info.vaddr);
+		}
+	}
+
+	return 0;
+}
+
+static unsigned long msm_pmem_frame_vtop_lookup(struct msm_sync *sync,
+		unsigned long buffer,
+		uint32_t yoff, uint32_t cbcroff, int fd)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+
+	hlist_for_each_entry_safe(region,
+		node, n, &sync->pmem_frames, list) {
+		if (((unsigned long)(region->info.vaddr) == buffer) &&
+				(region->info.y_off == yoff) &&
+				(region->info.cbcr_off == cbcroff) &&
+				(region->info.fd == fd) &&
+				(region->info.vfe_can_write == 0)) {
+			dmac_map_area((void*)region->kvaddr, region->len, DMA_FROM_DEVICE);
+			region->info.vfe_can_write = 1;
+			return region->paddr;
+		}
+	}
+
+	return 0;
+}
+
+static unsigned long msm_pmem_stats_vtop_lookup(
+		struct msm_sync *sync,
+		unsigned long buffer,
+		int fd)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) {
+		if (((unsigned long)(region->info.vaddr) == buffer) &&
+				(region->info.fd == fd) &&
+				region->info.vfe_can_write == 0) {
+			dmac_map_area((void*)region->kvaddr, region->len, DMA_FROM_DEVICE);
+			region->info.vfe_can_write = 1;
+			return region->paddr;
+		}
+	}
+
+	return 0;
+}
+
+static int __msm_pmem_table_del(struct msm_sync *sync,
+		struct msm_pmem_info *pinfo)
+{
+	int rc = 0;
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+
+	switch (pinfo->type) {
+	case MSM_PMEM_OUTPUT1:
+	case MSM_PMEM_OUTPUT2:
+	case MSM_PMEM_VIDEO:
+	case MSM_PMEM_PREVIEW:
+	case MSM_PMEM_THUMBNAIL:
+	case MSM_PMEM_MAINIMG:
+	case MSM_PMEM_RAW_MAINIMG:
+		hlist_for_each_entry_safe(region, node, n,
+			&sync->pmem_frames, list) {
+
+			if (pinfo->type == region->info.type &&
+					pinfo->vaddr == region->info.vaddr &&
+					pinfo->fd == region->info.fd) {
+				hlist_del(node);
+				put_pmem_file(region->file);
+				if (region->info.vfe_can_write) {
+					dmac_unmap_area((void*)region->kvaddr, region->len,
+							DMA_FROM_DEVICE);
+				}
+				kfree(region);
+			}
+		}
+		break;
+
+	case MSM_PMEM_AEC_AWB:
+	case MSM_PMEM_AF:
+		hlist_for_each_entry_safe(region, node, n,
+			&sync->pmem_stats, list) {
+
+			if (pinfo->type == region->info.type &&
+					pinfo->vaddr == region->info.vaddr &&
+					pinfo->fd == region->info.fd) {
+				hlist_del(node);
+				put_pmem_file(region->file);
+				if (region->info.vfe_can_write) {
+					dmac_unmap_area((void*)region->kvaddr, region->len,
+							DMA_FROM_DEVICE);
+				}
+				kfree(region);
+			}
+		}
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static int msm_pmem_table_del(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_pmem_info info;
+
+	if (copy_from_user(&info, arg, sizeof(info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	return __msm_pmem_table_del(sync, &info);
+}
+
+static int __msm_get_frame(struct msm_sync *sync,
+		struct msm_frame *frame)
+{
+	int rc = 0;
+
+	struct msm_pmem_region *region;
+	struct msm_queue_cmd *qcmd = NULL;
+	struct msm_vfe_resp *vdata;
+	struct msm_vfe_phy_info *pphy;
+
+	qcmd = msm_dequeue(&sync->frame_q, list_frame);
+
+	if (!qcmd) {
+		pr_err("%s: no preview frame.\n", __func__);
+		return -EAGAIN;
+	}
+
+	vdata = (struct msm_vfe_resp *)(qcmd->command);
+	pphy = &vdata->phy;
+
+	rc = msm_pmem_frame_ptov_lookup(sync,
+			pphy->y_phy,
+			pphy->cbcr_phy,
+			&region,
+			1); /* give frame to user space */
+
+	if (rc < 0) {
+		pr_err("%s: cannot get frame, invalid lookup address "
+			"y %x cbcr %x\n",
+			__func__,
+			pphy->y_phy,
+			pphy->cbcr_phy);
+		goto err;
+	}
+
+	frame->buffer = (unsigned long)region->info.vaddr;
+	frame->y_off = region->info.y_off;
+	frame->cbcr_off = region->info.cbcr_off;
+	frame->fd = region->info.fd;
+	frame->path = vdata->phy.output_id;
+
+	CDBG("%s: y %x, cbcr %x, qcmd %x, virt_addr %x\n",
+		__func__,
+		pphy->y_phy, pphy->cbcr_phy, (int) qcmd, (int) frame->buffer);
+
+err:
+	free_qcmd(qcmd);
+	return rc;
+}
+
+static int msm_get_frame(struct msm_sync *sync, void __user *arg)
+{
+	int rc = 0;
+	struct msm_frame frame;
+
+	if (copy_from_user(&frame,
+				arg,
+				sizeof(struct msm_frame))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	rc = __msm_get_frame(sync, &frame);
+	if (rc < 0)
+		return rc;
+
+	if (sync->croplen) {
+		if (frame.croplen != sync->croplen) {
+			pr_err("%s: invalid frame croplen %d,"
+				"expecting %d\n",
+				__func__,
+				frame.croplen,
+				sync->croplen);
+			return -EINVAL;
+		}
+
+		if (copy_to_user((void *)frame.cropinfo,
+				sync->cropinfo,
+				sync->croplen)) {
+			ERR_COPY_TO_USER();
+			return -EFAULT;
+		}
+	}
+
+	if (copy_to_user((void *)arg,
+				&frame, sizeof(struct msm_frame))) {
+		ERR_COPY_TO_USER();
+		rc = -EFAULT;
+	}
+
+	CDBG("%s: got frame\n", __func__);
+
+	return rc;
+}
+
+static int msm_enable_vfe(struct msm_sync *sync, void __user *arg)
+{
+	int rc = -EIO;
+	struct camera_enable_cmd cfg;
+
+	if (copy_from_user(&cfg,
+			arg,
+			sizeof(struct camera_enable_cmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	if (sync->vfefn.vfe_enable)
+		rc = sync->vfefn.vfe_enable(&cfg);
+
+	CDBG("%s: rc %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_disable_vfe(struct msm_sync *sync, void __user *arg)
+{
+	int rc = -EIO;
+	struct camera_enable_cmd cfg;
+
+	if (copy_from_user(&cfg,
+			arg,
+			sizeof(struct camera_enable_cmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	if (sync->vfefn.vfe_disable)
+		rc = sync->vfefn.vfe_disable(&cfg, NULL);
+
+	CDBG("%s: rc %d\n", __func__, rc);
+	return rc;
+}
+
+static struct msm_queue_cmd *__msm_control(struct msm_sync *sync,
+		struct msm_device_queue *queue,
+		struct msm_queue_cmd *qcmd,
+		int timeout)
+{
+	int rc;
+
+	msm_enqueue(&sync->event_q, &qcmd->list_config);
+
+	if (!queue)
+		return NULL;
+
+	/* wait for config status */
+	rc = wait_event_interruptible_timeout(
+			queue->wait,
+			!list_empty_careful(&queue->list),
+			timeout);
+	if (list_empty_careful(&queue->list)) {
+		if (!rc)
+			rc = -ETIMEDOUT;
+		if (rc < 0) {
+			pr_err("%s: wait_event error %d\n", __func__, rc);
+			/* qcmd may be still on the event_q, in which case we
+			 * need to remove it.  Alternatively, qcmd may have
+			 * been dequeued and processed already, in which case
+			 * the list removal will be a no-op.
+			 */
+			list_del_init(&qcmd->list_config);
+			return ERR_PTR(rc);
+		}
+	}
+
+	qcmd = msm_dequeue(queue, list_control);
+	BUG_ON(!qcmd);
+
+	return qcmd;
+}
+
+static struct msm_queue_cmd *__msm_control_nb(struct msm_sync *sync,
+					struct msm_queue_cmd *qcmd_to_copy)
+{
+	/* Since this is a non-blocking command, we cannot use qcmd_to_copy and
+	 * its data, since they are on the stack.  We replicate them on the heap
+	 * and mark them on_heap so that they get freed when the config thread
+	 * dequeues them.
+	 */
+
+	struct msm_ctrl_cmd *udata;
+	struct msm_ctrl_cmd *udata_to_copy = qcmd_to_copy->command;
+
+	struct msm_queue_cmd *qcmd =
+			kmalloc(sizeof(*qcmd_to_copy) +
+				sizeof(*udata_to_copy) +
+				udata_to_copy->length,
+				GFP_KERNEL);
+	if (!qcmd) {
+		pr_err("%s: out of memory\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	*qcmd = *qcmd_to_copy;
+	udata = qcmd->command = qcmd + 1;
+	memcpy(udata, udata_to_copy, sizeof(*udata));
+	udata->value = udata + 1;
+	memcpy(udata->value, udata_to_copy->value, udata_to_copy->length);
+
+	qcmd->on_heap = 1;
+
+	/* qcmd_resp will be set to NULL */
+	return __msm_control(sync, NULL, qcmd, 0);
+}
+
+static int msm_control(struct msm_control_device *ctrl_pmsm,
+			int block,
+			void __user *arg)
+{
+	int rc = 0;
+
+	struct msm_sync *sync = ctrl_pmsm->pmsm->sync;
+	void __user *uptr;
+	struct msm_ctrl_cmd udata;
+	struct msm_queue_cmd qcmd;
+	struct msm_queue_cmd *qcmd_resp = NULL;
+	uint8_t data[50];
+
+	if (copy_from_user(&udata, arg, sizeof(struct msm_ctrl_cmd))) {
+		ERR_COPY_FROM_USER();
+		rc = -EFAULT;
+		goto end;
+	}
+
+	uptr = udata.value;
+	udata.value = data;
+	if (udata.type == CAMERA_STOP_SNAPSHOT)
+		sync->get_pic_abort = 1;
+	qcmd.on_heap = 0;
+	qcmd.type = MSM_CAM_Q_CTRL;
+	qcmd.command = &udata;
+
+	if (udata.length) {
+		if (udata.length > sizeof(data)) {
+			pr_err("%s: user data too large (%d, max is %d)\n",
+					__func__,
+					udata.length,
+					sizeof(data));
+			rc = -EIO;
+			goto end;
+		}
+		if (copy_from_user(udata.value, uptr, udata.length)) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+			goto end;
+		}
+	}
+
+	if (unlikely(!block)) {
+		qcmd_resp = __msm_control_nb(sync, &qcmd);
+		goto end;
+	}
+
+	qcmd_resp = __msm_control(sync,
+				  &ctrl_pmsm->ctrl_q,
+				  &qcmd, MAX_SCHEDULE_TIMEOUT);
+
+	if (!qcmd_resp || IS_ERR(qcmd_resp)) {
+		/* Do not free qcmd_resp here.  If the config thread read it,
+		 * then it has already been freed, and we timed out because
+		 * we did not receive a MSM_CAM_IOCTL_CTRL_CMD_DONE.  If the
+		 * config thread itself is blocked and not dequeueing commands,
+		 * then it will either eventually unblock and process them,
+		 * or when it is killed, qcmd will be freed in
+		 * msm_release_config.
+		 */
+		rc = PTR_ERR(qcmd_resp);
+		qcmd_resp = NULL;
+		goto end;
+	}
+
+	if (qcmd_resp->command) {
+		udata = *(struct msm_ctrl_cmd *)qcmd_resp->command;
+		if (udata.length > 0) {
+			if (copy_to_user(uptr,
+					 udata.value,
+					 udata.length)) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto end;
+			}
+		}
+		udata.value = uptr;
+
+		if (copy_to_user((void *)arg, &udata,
+				sizeof(struct msm_ctrl_cmd))) {
+			ERR_COPY_TO_USER();
+			rc = -EFAULT;
+			goto end;
+		}
+	}
+
+end:
+	free_qcmd(qcmd_resp);
+	CDBG("%s: rc %d\n", __func__, rc);
+	return rc;
+}
+
+/* Divert frames for post-processing by delivering them to the config thread;
+ * when post-processing is done, it will return the frame to the frame thread.
+ */
+static int msm_divert_frame(struct msm_sync *sync,
+		struct msm_vfe_resp *data,
+		struct msm_stats_event_ctrl *se)
+{
+	struct msm_pmem_region *region;
+	struct msm_postproc buf;
+	int rc;
+
+	pr_info("%s: preview PP sync->pp_mask %d\n", __func__, sync->pp_mask);
+
+	if (!(sync->pp_mask & PP_PREV)) {
+		pr_err("%s: diverting preview frame but not in PP_PREV!\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	rc = msm_pmem_frame_ptov_lookup(sync,
+			data->phy.y_phy,
+			data->phy.cbcr_phy,
+			&region,
+			0);  /* vfe can still write to frame */
+	if (rc < 0) {
+		CDBG("%s: msm_pmem_frame_ptov_lookup failed\n", __func__);
+		return rc;
+	}
+
+	buf.fmain.buffer = (unsigned long)region->info.vaddr;
+	buf.fmain.y_off = region->info.y_off;
+	buf.fmain.cbcr_off = region->info.cbcr_off;
+	buf.fmain.fd = region->info.fd;
+
+	CDBG("%s: buf %ld fd %d\n",
+		__func__, buf.fmain.buffer,
+		buf.fmain.fd);
+	if (copy_to_user((void *)(se->stats_event.data),
+			&(buf.fmain),
+			sizeof(struct msm_frame))) {
+		ERR_COPY_TO_USER();
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int msm_divert_snapshot(struct msm_sync *sync,
+		struct msm_vfe_resp *data,
+		struct msm_stats_event_ctrl *se)
+{
+	struct msm_postproc buf;
+	struct msm_pmem_region region;
+
+	CDBG("%s: preview PP sync->pp_mask %d\n", __func__, sync->pp_mask);
+
+	if (!(sync->pp_mask & (PP_SNAP|PP_RAW_SNAP))) {
+		pr_err("%s: diverting snapshot but not in PP_SNAP!\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	memset(&region, 0, sizeof(region));
+	buf.fmnum = msm_pmem_region_lookup(&sync->pmem_frames,
+					MSM_PMEM_MAINIMG,
+					&region, 1);
+	if (buf.fmnum == 1) {
+		buf.fmain.buffer = (uint32_t)region.info.vaddr;
+		buf.fmain.y_off  = region.info.y_off;
+		buf.fmain.cbcr_off = region.info.cbcr_off;
+		buf.fmain.fd = region.info.fd;
+	} else {
+		if (buf.fmnum > 1)
+			pr_err("%s: MSM_PMEM_MAINIMG lookup found %d\n",
+				__func__, buf.fmnum);
+		buf.fmnum = msm_pmem_region_lookup(&sync->pmem_frames,
+					MSM_PMEM_RAW_MAINIMG,
+					&region, 1);
+		if (buf.fmnum == 1) {
+			buf.fmain.path = MSM_FRAME_PREV_2;
+			buf.fmain.buffer = (uint32_t)region.info.vaddr;
+			buf.fmain.fd = region.info.fd;
+		} else {
+			pr_err("%s: pmem lookup fail (found %d)\n",
+				__func__, buf.fmnum);
+			return -EIO;
+		}
+	}
+
+	CDBG("%s: snapshot copy_to_user!\n", __func__);
+	if (copy_to_user((void *)(se->stats_event.data), &buf, sizeof(buf))) {
+		ERR_COPY_TO_USER();
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int msm_get_stats(struct msm_sync *sync, void __user *arg)
+{
+	int timeout;
+	int rc = 0;
+
+	struct msm_stats_event_ctrl se;
+
+	struct msm_queue_cmd *qcmd = NULL;
+	struct msm_ctrl_cmd  *ctrl = NULL;
+	struct msm_vfe_resp  *data = NULL;
+	struct msm_stats_buf stats;
+
+	if (copy_from_user(&se, arg,
+			sizeof(struct msm_stats_event_ctrl))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	timeout = (int)se.timeout_ms;
+
+	CDBG("%s: timeout %d\n", __func__, timeout);
+	rc = wait_event_interruptible_timeout(
+			sync->event_q.wait,
+			!list_empty_careful(&sync->event_q.list),
+			msecs_to_jiffies(timeout));
+	if (list_empty_careful(&sync->event_q.list)) {
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		if (rc < 0) {
+			pr_err("%s: error %d\n", __func__, rc);
+			return rc;
+		}
+	}
+	CDBG("%s: returned from wait: %d\n", __func__, rc);
+
+	rc = 0;
+
+	qcmd = msm_dequeue(&sync->event_q, list_config);
+	BUG_ON(!qcmd);
+
+	CDBG("%s: received from DSP %d\n", __func__, qcmd->type);
+
+	switch (qcmd->type) {
+	case MSM_CAM_Q_VFE_EVT:
+	case MSM_CAM_Q_VFE_MSG:
+		data = (struct msm_vfe_resp *)(qcmd->command);
+
+		/* adsp event and message */
+		se.resptype = MSM_CAM_RESP_STAT_EVT_MSG;
+
+		/* 0 - msg from aDSP, 1 - event from mARM */
+		se.stats_event.type   = data->evt_msg.type;
+		se.stats_event.msg_id = data->evt_msg.msg_id;
+		se.stats_event.len    = data->evt_msg.len;
+
+		CDBG("%s: qcmd->type %d length %d msd_id %d\n", __func__,
+			qcmd->type,
+			se.stats_event.len,
+			se.stats_event.msg_id);
+
+		if (data->type == VFE_MSG_STATS_AF ||
+		    data->type ==  VFE_MSG_STATS_WE ||
+			(data->type >=  VFE_MSG_STATS_AEC &&
+			 data->type <= VFE_MSG_STATS_SKIN)) {
+			/* the check above includes all stats type. */
+			stats.buffer =
+			msm_pmem_stats_ptov_lookup(sync,
+					data->phy.sbuf_phy,
+					&(stats.fd));
+			if (!stats.buffer) {
+				pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
+					__func__);
+				rc = -EINVAL;
+				goto failure;
+			}
+
+			if (copy_to_user((void *)(se.stats_event.data),
+					&stats,
+					sizeof(struct msm_stats_buf))) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto failure;
+			}
+		} else if ((data->evt_msg.len > 0) &&
+				(data->type == VFE_MSG_GENERAL)) {
+			if (copy_to_user((void *)(se.stats_event.data),
+					data->evt_msg.data,
+					data->evt_msg.len)) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto failure;
+			}
+		} else {
+			if ((sync->pp_mask & PP_PREV) &&
+				(data->type == VFE_MSG_OUTPUT1 ||
+				 data->type == VFE_MSG_OUTPUT2 ||
+				 data->type == VFE_MSG_OUTPUT_P))
+					rc = msm_divert_frame(sync, data, &se);
+			else if ((sync->pp_mask & (PP_SNAP|PP_RAW_SNAP)) &&
+				  (data->type == VFE_MSG_SNAPSHOT ||
+				   data->type == VFE_MSG_OUTPUT_S))
+					rc = msm_divert_snapshot(sync,
+								data, &se);
+		}
+		break;
+
+	case MSM_CAM_Q_CTRL:
+		/* control command from control thread */
+		ctrl = (struct msm_ctrl_cmd *)(qcmd->command);
+
+		CDBG("%s: qcmd->type %d length %d\n", __func__,
+			qcmd->type, ctrl->length);
+
+		if (ctrl->length > 0) {
+			if (copy_to_user((void *)(se.ctrl_cmd.value),
+						ctrl->value,
+						ctrl->length)) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto failure;
+			}
+		}
+
+		se.resptype = MSM_CAM_RESP_CTRL;
+
+		/* what to control */
+		se.ctrl_cmd.type = ctrl->type;
+		se.ctrl_cmd.length = ctrl->length;
+		se.ctrl_cmd.resp_fd = ctrl->resp_fd;
+		break;
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	case MSM_CAM_Q_V4L2_REQ:
+		/* control command from v4l2 client */
+		ctrl = (struct msm_ctrl_cmd *)(qcmd->command);
+
+		CDBG("%s: qcmd->type %d len %d\n", __func__, qcmd->type, ctrl->length);
+
+		if (ctrl->length > 0) {
+			if (copy_to_user((void *)(se.ctrl_cmd.value),
+					ctrl->value, ctrl->length)) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto failure;
+			}
+		}
+
+		/* 2 tells config thread this is v4l2 request */
+		se.resptype = MSM_CAM_RESP_V4L2;
+
+		/* what to control */
+		se.ctrl_cmd.type   = ctrl->type;
+		se.ctrl_cmd.length = ctrl->length;
+		break;
+#endif
+
+	default:
+		rc = -EFAULT;
+		goto failure;
+	} /* switch qcmd->type */
+
+	if (copy_to_user((void *)arg, &se, sizeof(se))) {
+		ERR_COPY_TO_USER();
+		rc = -EFAULT;
+		goto failure;
+	}
+
+failure:
+	free_qcmd(qcmd);
+
+	CDBG("%s: %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_ctrl_cmd_done(struct msm_control_device *ctrl_pmsm,
+		void __user *arg)
+{
+	void __user *uptr;
+	struct msm_queue_cmd *qcmd = &ctrl_pmsm->qcmd;
+	struct msm_ctrl_cmd *command = &ctrl_pmsm->ctrl;
+
+	if (copy_from_user(command, arg, sizeof(*command))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	qcmd->on_heap = 0;
+	qcmd->command = command;
+	uptr = command->value;
+
+	if (command->length > 0) {
+		command->value = ctrl_pmsm->ctrl_data;
+		if (command->length > sizeof(ctrl_pmsm->ctrl_data)) {
+			pr_err("%s: user data %d is too big (max %d)\n",
+				__func__, command->length,
+				sizeof(ctrl_pmsm->ctrl_data));
+			return -EINVAL;
+		}
+		if (copy_from_user(command->value,
+					uptr,
+					command->length)) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	} else
+		command->value = NULL;
+
+	CDBG("%s: end\n", __func__);
+
+	/* wake up control thread */
+	msm_enqueue(&ctrl_pmsm->ctrl_q, &qcmd->list_control);
+
+	return 0;
+}
+
+static int msm_config_vfe(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+	struct msm_pmem_region region[8];
+	struct axidata axi_data;
+
+	if (!sync->vfefn.vfe_config) {
+		pr_err("%s: no vfe_config!\n", __func__);
+		return -EIO;
+	}
+
+	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	memset(&axi_data, 0, sizeof(axi_data));
+
+	CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type);
+
+	switch (cfgcmd.cmd_type) {
+	case CMD_STATS_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+					MSM_PMEM_AEC_AWB, &region[0],
+					NUM_STAT_OUTPUT_BUFFERS);
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+					MSM_PMEM_AF, &region[axi_data.bufnum1],
+					NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1 || !axi_data.bufnum2) {
+			pr_err("%s: pmem region lookup error\n", __func__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+	case CMD_STATS_AF_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+					MSM_PMEM_AF, &region[0],
+					NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+	case CMD_STATS_AEC_AWB_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+					MSM_PMEM_AEC_AWB, &region[0],
+					NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+	case CMD_STATS_AEC_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_AEC, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+	case CMD_STATS_AWB_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_AWB, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+
+
+	case CMD_STATS_IHIST_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_IHIST, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+
+	case CMD_STATS_RS_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_RS, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+
+	case CMD_STATS_CS_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_CS, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+
+	case CMD_GENERAL:
+	case CMD_STATS_DISABLE:
+		return sync->vfefn.vfe_config(&cfgcmd, NULL);
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd.cmd_type);
+	}
+
+	return -EINVAL;
+}
+
+static int msm_frame_axi_cfg(struct msm_sync *sync,
+		struct msm_vfe_cfg_cmd *cfgcmd)
+{
+	int rc = -EIO;
+	struct axidata axi_data;
+	void *data = &axi_data;
+	struct msm_pmem_region region[8];
+	int pmem_type;
+
+	memset(&axi_data, 0, sizeof(axi_data));
+
+	switch (cfgcmd->cmd_type) {
+	case CMD_AXI_CFG_OUT1:
+		pmem_type = MSM_PMEM_OUTPUT1;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], 8);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_AXI_CFG_OUT2:
+		pmem_type = MSM_PMEM_OUTPUT2;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], 8);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error (empty %d)\n",
+				__func__, __LINE__,
+				hlist_empty(&sync->pmem_frames));
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_AXI_CFG_PREVIEW:
+		pmem_type = MSM_PMEM_PREVIEW;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], 8);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error (empty %d)\n",
+				__func__, __LINE__,
+				hlist_empty(&sync->pmem_frames));
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_AXI_CFG_VIDEO:
+		pmem_type = MSM_PMEM_PREVIEW;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], 8);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+
+		pmem_type = MSM_PMEM_VIDEO;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[axi_data.bufnum1],
+				(8-(axi_data.bufnum1)));
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_AXI_CFG_O1_AND_O2:
+		pmem_type = MSM_PMEM_OUTPUT1;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], 8);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+
+		pmem_type = MSM_PMEM_OUTPUT2;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[axi_data.bufnum1],
+				(8-(axi_data.bufnum1)));
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_AXI_CFG_SNAP:
+	case CMD_AXI_CFG_SNAP_O1_AND_O2:
+		pmem_type = MSM_PMEM_THUMBNAIL;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], 8);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+
+		pmem_type = MSM_PMEM_MAINIMG;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[axi_data.bufnum1],
+				(8-(axi_data.bufnum1)));
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_RAW_PICT_AXI_CFG:
+		pmem_type = MSM_PMEM_RAW_MAINIMG;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], 8);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_GENERAL:
+		data = NULL;
+		break;
+
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd->cmd_type);
+		return -EINVAL;
+	}
+
+	axi_data.region = &region[0];
+
+	/* send the AXI configuration command to driver */
+	if (sync->vfefn.vfe_config)
+		rc = sync->vfefn.vfe_config(cfgcmd, data);
+
+	return rc;
+}
+
+static int msm_get_sensor_info(struct msm_sync *sync, void __user *arg)
+{
+	int rc = 0;
+	struct msm_camsensor_info info;
+	struct msm_camera_sensor_info *sdata;
+
+	if (copy_from_user(&info,
+			arg,
+			sizeof(struct msm_camsensor_info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	sdata = sync->pdev->dev.platform_data;
+	CDBG("%s: sensor_name %s\n", __func__, sdata->sensor_name);
+
+	memcpy(&info.name[0],
+		sdata->sensor_name,
+		MAX_SENSOR_NAME);
+	info.flash_enabled = !!sdata->camera_flash;
+
+	/* copy back to user space */
+	if (copy_to_user((void *)arg,
+			&info,
+			sizeof(struct msm_camsensor_info))) {
+		ERR_COPY_TO_USER();
+		rc = -EFAULT;
+	}
+
+	return rc;
+}
+
+static int __msm_put_frame_buf(struct msm_sync *sync,
+		struct msm_frame *pb)
+{
+	unsigned long pphy;
+	struct msm_vfe_cfg_cmd cfgcmd;
+
+	int rc = -EIO;
+
+	pphy = msm_pmem_frame_vtop_lookup(sync,
+		pb->buffer,
+		pb->y_off, pb->cbcr_off, pb->fd);
+
+	if (pphy != 0) {
+		CDBG("%s: rel: vaddr %lx, paddr %lx\n",
+			__func__,
+			pb->buffer, pphy);
+		cfgcmd.cmd_type = CMD_FRAME_BUF_RELEASE;
+		cfgcmd.value    = (void *)pb;
+		if (sync->vfefn.vfe_config)
+			rc = sync->vfefn.vfe_config(&cfgcmd, &pphy);
+	} else {
+		pr_err("%s: msm_pmem_frame_vtop_lookup failed. "
+			"buffer=0x%lx, y_off=%d, cbcr_off=%d, fd=%d\n",
+			__func__, pb->buffer, pb->y_off, pb->cbcr_off, pb->fd);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int msm_put_frame_buffer(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_frame buf;
+
+	if (copy_from_user(&buf,
+				arg,
+				sizeof(struct msm_frame))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	return __msm_put_frame_buf(sync, &buf);
+}
+
+static int __msm_register_pmem(struct msm_sync *sync,
+		struct msm_pmem_info *pinfo)
+{
+	int rc = 0;
+
+	switch (pinfo->type) {
+	case MSM_PMEM_OUTPUT1:
+	case MSM_PMEM_OUTPUT2:
+	case MSM_PMEM_VIDEO:
+	case MSM_PMEM_PREVIEW:
+	case MSM_PMEM_THUMBNAIL:
+	case MSM_PMEM_MAINIMG:
+	case MSM_PMEM_RAW_MAINIMG:
+		rc = msm_pmem_table_add(&sync->pmem_frames, pinfo);
+		break;
+
+	case MSM_PMEM_AEC_AWB:
+	case MSM_PMEM_AF:
+	case MSM_PMEM_AEC:
+	case MSM_PMEM_AWB:
+	case MSM_PMEM_RS:
+	case MSM_PMEM_CS:
+	case MSM_PMEM_IHIST:
+	case MSM_PMEM_SKIN:
+
+		rc = msm_pmem_table_add(&sync->pmem_stats, pinfo);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static int msm_register_pmem(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_pmem_info info;
+
+	if (copy_from_user(&info, arg, sizeof(info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	return __msm_register_pmem(sync, &info);
+}
+
+static int msm_stats_axi_cfg(struct msm_sync *sync,
+		struct msm_vfe_cfg_cmd *cfgcmd)
+{
+	int rc = -EIO;
+	struct axidata axi_data;
+	void *data = &axi_data;
+
+	struct msm_pmem_region region[3];
+	int pmem_type = MSM_PMEM_MAX;
+
+	memset(&axi_data, 0, sizeof(axi_data));
+
+	switch (cfgcmd->cmd_type) {
+	case CMD_STATS_AXI_CFG:
+		pmem_type = MSM_PMEM_AEC_AWB;
+		break;
+	case CMD_STATS_AF_AXI_CFG:
+		pmem_type = MSM_PMEM_AF;
+		break;
+	case CMD_GENERAL:
+		data = NULL;
+		break;
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd->cmd_type);
+		return -EINVAL;
+	}
+
+	if (cfgcmd->cmd_type != CMD_GENERAL) {
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats, pmem_type,
+				&region[0], NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+	}
+
+	/* send the AEC/AWB STATS configuration command to driver */
+	if (sync->vfefn.vfe_config)
+		rc = sync->vfefn.vfe_config(cfgcmd, &axi_data);
+
+	return rc;
+}
+
+static int msm_put_stats_buffer(struct msm_sync *sync, void __user *arg)
+{
+	int rc = -EIO;
+
+	struct msm_stats_buf buf;
+	unsigned long pphy;
+	struct msm_vfe_cfg_cmd cfgcmd;
+
+	if (copy_from_user(&buf, arg,
+				sizeof(struct msm_stats_buf))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	CDBG("%s\n", __func__);
+	pphy = msm_pmem_stats_vtop_lookup(sync, buf.buffer, buf.fd);
+
+	if (pphy != 0) {
+		if (buf.type == STAT_AEAW)
+			cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE;
+		else if (buf.type == STAT_AF)
+			cfgcmd.cmd_type = CMD_STATS_AF_BUF_RELEASE;
+		else if (buf.type == STAT_AEC)
+			cfgcmd.cmd_type = CMD_STATS_AEC_BUF_RELEASE;
+		else if (buf.type == STAT_AWB)
+			cfgcmd.cmd_type = CMD_STATS_AWB_BUF_RELEASE;
+		else if (buf.type == STAT_IHIST)
+			cfgcmd.cmd_type = CMD_STATS_IHIST_BUF_RELEASE;
+		else if (buf.type == STAT_RS)
+			cfgcmd.cmd_type = CMD_STATS_RS_BUF_RELEASE;
+		else if (buf.type == STAT_CS)
+			cfgcmd.cmd_type = CMD_STATS_CS_BUF_RELEASE;
+
+		else {
+			pr_err("%s: invalid buf type %d\n",
+				__func__,
+				buf.type);
+			rc = -EINVAL;
+			goto put_done;
+		}
+
+		cfgcmd.value = (void *)&buf;
+
+		if (sync->vfefn.vfe_config) {
+			rc = sync->vfefn.vfe_config(&cfgcmd, &pphy);
+			if (rc < 0)
+				pr_err("%s: vfe_config error %d\n",
+					__func__, rc);
+		} else
+			pr_err("%s: vfe_config is NULL\n", __func__);
+	} else {
+		pr_err("%s: NULL physical address\n", __func__);
+		rc = -EINVAL;
+	}
+
+put_done:
+	return rc;
+}
+
+static int msm_axi_config(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+
+	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	switch (cfgcmd.cmd_type) {
+	case CMD_AXI_CFG_OUT1:
+	case CMD_AXI_CFG_OUT2:
+	case CMD_AXI_CFG_O1_AND_O2:
+	case CMD_AXI_CFG_SNAP_O1_AND_O2:
+	case CMD_AXI_CFG_VIDEO:
+	case CMD_AXI_CFG_PREVIEW:
+	case CMD_AXI_CFG_SNAP:
+	case CMD_RAW_PICT_AXI_CFG:
+		return msm_frame_axi_cfg(sync, &cfgcmd);
+
+	case CMD_STATS_AXI_CFG:
+	case CMD_STATS_AF_AXI_CFG:
+		return msm_stats_axi_cfg(sync, &cfgcmd);
+
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__,
+			cfgcmd.cmd_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __msm_get_pic(struct msm_sync *sync, struct msm_ctrl_cmd *ctrl)
+{
+	int rc = 0;
+	int tm;
+
+	struct msm_queue_cmd *qcmd = NULL;
+
+	tm = (int)ctrl->timeout_ms;
+
+	rc = wait_event_interruptible_timeout(
+			sync->pict_q.wait,
+			!list_empty_careful(
+				&sync->pict_q.list) || sync->get_pic_abort,
+			msecs_to_jiffies(tm));
+
+	if (sync->get_pic_abort == 1) {
+		sync->get_pic_abort = 0;
+		return -ENODATA;
+	}
+	if (list_empty_careful(&sync->pict_q.list)) {
+		if (rc == 0)
+			return -ETIMEDOUT;
+		if (rc < 0) {
+			pr_err("%s: rc %d\n", __func__, rc);
+			return rc;
+		}
+	}
+
+	rc = 0;
+
+	qcmd = msm_dequeue(&sync->pict_q, list_pict);
+	BUG_ON(!qcmd);
+
+	if (qcmd->command != NULL) {
+		struct msm_ctrl_cmd *q =
+			(struct msm_ctrl_cmd *)qcmd->command;
+		ctrl->type = q->type;
+		ctrl->status = q->status;
+	} else {
+		ctrl->type = -1;
+		ctrl->status = -1;
+	}
+
+	free_qcmd(qcmd);
+
+	return rc;
+}
+
+static int msm_get_pic(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_ctrl_cmd ctrlcmd;
+	struct msm_pmem_region *pic_pmem_region = NULL, *region;
+	struct hlist_node *node, *n;
+	int rc;
+	unsigned long end;
+	int cline_mask;
+
+	if (copy_from_user(&ctrlcmd,
+				arg,
+				sizeof(struct msm_ctrl_cmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	rc = __msm_get_pic(sync, &ctrlcmd);
+	if (rc < 0)
+		return rc;
+
+	if (sync->croplen) {
+		if (ctrlcmd.length != sync->croplen) {
+			pr_err("%s: invalid len %d < %d\n",
+				__func__,
+				ctrlcmd.length,
+				sync->croplen);
+			return -EINVAL;
+		}
+		if (copy_to_user(ctrlcmd.value,
+				sync->cropinfo,
+				sync->croplen)) {
+			ERR_COPY_TO_USER();
+			return -EFAULT;
+		}
+	}
+
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) {
+		if (region->info.vfe_can_write &&
+				(region->info.type == MSM_PMEM_MAINIMG ||
+				region->info.type == MSM_PMEM_RAW_MAINIMG)) {
+			pic_pmem_region = region;
+			break;
+		}
+	}
+
+	if (!pic_pmem_region) {
+		pr_err("%s pmem region lookup error\n", __func__);
+		return -EIO;
+	}
+	cline_mask = cache_line_size() - 1;
+	end = pic_pmem_region->kvaddr + pic_pmem_region->len;
+	end = (end + cline_mask) & ~cline_mask;
+
+	pr_info("%s: flushing cache for [%08lx, %08lx)\n",
+		__func__,
+		pic_pmem_region->kvaddr, end);
+
+	/* HACK: Invalidate buffer */
+	dmac_unmap_area((void*)pic_pmem_region->kvaddr, pic_pmem_region->len,
+			DMA_FROM_DEVICE);
+	pic_pmem_region->info.vfe_can_write = 0;
+
+	CDBG("%s: copy snapshot frame to user\n", __func__);
+	if (copy_to_user((void *)arg,
+		&ctrlcmd,
+		sizeof(struct msm_ctrl_cmd))) {
+		ERR_COPY_TO_USER();
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static int msm_set_crop(struct msm_sync *sync, void __user *arg)
+{
+	struct crop_info crop;
+
+	if (copy_from_user(&crop,
+				arg,
+				sizeof(struct crop_info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	if (!sync->croplen) {
+		sync->cropinfo = kmalloc(crop.len, GFP_KERNEL);
+		if (!sync->cropinfo)
+			return -ENOMEM;
+	} else if (sync->croplen < crop.len)
+		return -EINVAL;
+
+	if (copy_from_user(sync->cropinfo,
+				crop.info,
+				crop.len)) {
+		ERR_COPY_FROM_USER();
+		kfree(sync->cropinfo);
+		return -EFAULT;
+	}
+
+	sync->croplen = crop.len;
+
+	return 0;
+}
+
+static int msm_pp_grab(struct msm_sync *sync, void __user *arg)
+{
+	uint32_t enable;
+	if (copy_from_user(&enable, arg, sizeof(enable))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	} else {
+		enable &= PP_MASK;
+		if (enable & (enable - 1)) {
+			pr_err("%s: error: more than one PP request!\n",
+				__func__);
+			return -EINVAL;
+		}
+		if (sync->pp_mask) {
+			pr_err("%s: postproc %x is already enabled\n",
+				__func__, sync->pp_mask & enable);
+			return -EINVAL;
+		}
+
+		CDBG("%s: sync->pp_mask %d enable %d\n", __func__,
+			sync->pp_mask, enable);
+		sync->pp_mask |= enable;
+	}
+
+	return 0;
+}
+
+static int msm_pp_release(struct msm_sync *sync, void __user *arg)
+{
+	uint32_t mask;
+	if (copy_from_user(&mask, arg, sizeof(uint32_t))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	mask &= PP_MASK;
+	if (!(sync->pp_mask & mask)) {
+		pr_warning("%s: pp not in progress for %x\n", __func__,
+			mask);
+		return -EINVAL;
+	}
+
+	if ((mask & PP_PREV) && (sync->pp_mask & PP_PREV)) {
+		if (!sync->pp_prev) {
+			pr_err("%s: no preview frame to deliver!\n", __func__);
+			return -EINVAL;
+		}
+		pr_info("%s: delivering pp_prev\n", __func__);
+
+		msm_enqueue(&sync->frame_q, &sync->pp_prev->list_frame);
+		sync->pp_prev = NULL;
+		goto done;
+	}
+
+	if (((mask & PP_SNAP) && (sync->pp_mask & PP_SNAP)) ||
+			((mask & PP_RAW_SNAP) &&
+			 (sync->pp_mask & PP_RAW_SNAP))) {
+		if (!sync->pp_snap) {
+			pr_err("%s: no snapshot to deliver!\n", __func__);
+			return -EINVAL;
+		}
+		pr_info("%s: delivering pp_snap\n", __func__);
+		msm_enqueue(&sync->pict_q, &sync->pp_snap->list_pict);
+		sync->pp_snap = NULL;
+	}
+
+done:
+	sync->pp_mask = 0;
+	return 0;
+}
+
+static long msm_ioctl_common(struct msm_device *pmsm,
+		unsigned int cmd,
+		void __user *argp)
+{
+	CDBG("%s\n", __func__);
+	switch (cmd) {
+	case MSM_CAM_IOCTL_REGISTER_PMEM:
+		return msm_register_pmem(pmsm->sync, argp);
+	case MSM_CAM_IOCTL_UNREGISTER_PMEM:
+		return msm_pmem_table_del(pmsm->sync, argp);
+	default:
+		return -EINVAL;
+	}
+}
+
+int msm_camera_flash(struct msm_sync *sync, int level)
+{
+	int flash_level;
+
+	if (!sync->sdata->camera_flash) {
+		pr_err("%s: camera flash is not supported.\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!sync->sdata->num_flash_levels) {
+		pr_err("%s: no flash levels.\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (level) {
+	case MSM_CAMERA_LED_HIGH:
+		flash_level = sync->sdata->num_flash_levels - 1;
+		break;
+	case MSM_CAMERA_LED_LOW:
+		flash_level = sync->sdata->num_flash_levels / 2;
+		break;
+	case MSM_CAMERA_LED_OFF:
+		flash_level = 0;
+		break;
+	default:
+		pr_err("%s: invalid flash level %d.\n", __func__, level);
+		return -EINVAL;
+	}
+
+	return sync->sdata->camera_flash(level);
+}
+
+static long msm_ioctl_config(struct file *filep, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc = -EINVAL;
+	void __user *argp = (void __user *)arg;
+	struct msm_device *pmsm = filep->private_data;
+
+	CDBG("%s: cmd %d\n", __func__, _IOC_NR(cmd));
+
+	switch (cmd) {
+	case MSM_CAM_IOCTL_GET_SENSOR_INFO:
+		rc = msm_get_sensor_info(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_CONFIG_VFE:
+		/* Coming from config thread for update */
+		rc = msm_config_vfe(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_GET_STATS:
+		/* Coming from config thread wait
+		 * for vfe statistics and control requests */
+		rc = msm_get_stats(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_ENABLE_VFE:
+		/* This request comes from control thread:
+		 * enable either QCAMTASK or VFETASK */
+		rc = msm_enable_vfe(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_DISABLE_VFE:
+		/* This request comes from control thread:
+		 * disable either QCAMTASK or VFETASK */
+		rc = msm_disable_vfe(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_VFE_APPS_RESET:
+		msm_camio_vfe_blk_reset();
+		rc = 0;
+		break;
+
+	case MSM_CAM_IOCTL_RELEASE_STATS_BUFFER:
+		rc = msm_put_stats_buffer(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_AXI_CONFIG:
+		rc = msm_axi_config(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_SET_CROP:
+		rc = msm_set_crop(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_PP:
+		/* Grab one preview frame or one snapshot
+		 * frame.
+		 */
+		rc = msm_pp_grab(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_PP_DONE:
+		/* Release the preview of snapshot frame
+		 * that was grabbed.
+		 */
+		rc = msm_pp_release(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_SENSOR_IO_CFG:
+		rc = pmsm->sync->sctrl.s_config(argp);
+		break;
+
+	case MSM_CAM_IOCTL_FLASH_LED_CFG: {
+		uint32_t led_state;
+		if (copy_from_user(&led_state, argp, sizeof(led_state))) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+		} else
+			rc = msm_camera_flash(pmsm->sync, led_state);
+		break;
+	}
+
+	case MSM_CAM_IOCTL_ENABLE_OUTPUT_IND: {
+		uint32_t enable;
+		if (copy_from_user(&enable, argp, sizeof(enable))) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+			break;
+		}
+		pr_info("%s: copying all preview frames to config: %d\n",
+			__func__, enable);
+		pmsm->sync->report_preview_to_config = enable;
+		rc = 0;
+		break;
+	}
+
+	default:
+		rc = msm_ioctl_common(pmsm, cmd, argp);
+		break;
+	}
+
+	CDBG("%s: cmd %d DONE\n", __func__, _IOC_NR(cmd));
+	return rc;
+}
+
+static int msm_unblock_poll_frame(struct msm_sync *);
+
+static long msm_ioctl_frame(struct file *filep, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc = -EINVAL;
+	void __user *argp = (void __user *)arg;
+	struct msm_device *pmsm = filep->private_data;
+
+
+	switch (cmd) {
+	case MSM_CAM_IOCTL_GETFRAME:
+		/* Coming from frame thread to get frame
+		 * after SELECT is done */
+		rc = msm_get_frame(pmsm->sync, argp);
+		break;
+	case MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER:
+		rc = msm_put_frame_buffer(pmsm->sync, argp);
+		break;
+	case MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME:
+		rc = msm_unblock_poll_frame(pmsm->sync);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+
+static long msm_ioctl_control(struct file *filep, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc = -EINVAL;
+	void __user *argp = (void __user *)arg;
+	struct msm_control_device *ctrl_pmsm = filep->private_data;
+	struct msm_device *pmsm = ctrl_pmsm->pmsm;
+
+	switch (cmd) {
+	case MSM_CAM_IOCTL_CTRL_COMMAND:
+		/* Coming from control thread, may need to wait for
+		 * command status */
+		rc = msm_control(ctrl_pmsm, 1, argp);
+		break;
+	case MSM_CAM_IOCTL_CTRL_COMMAND_2:
+		/* Sends a message, returns immediately */
+		rc = msm_control(ctrl_pmsm, 0, argp);
+		break;
+	case MSM_CAM_IOCTL_CTRL_CMD_DONE:
+		/* Config thread calls the control thread to notify it
+		 * of the result of a MSM_CAM_IOCTL_CTRL_COMMAND.
+		 */
+		rc = msm_ctrl_cmd_done(ctrl_pmsm, argp);
+		break;
+	case MSM_CAM_IOCTL_GET_PICTURE:
+		rc = msm_get_pic(pmsm->sync, argp);
+		break;
+	case MSM_CAM_IOCTL_GET_SENSOR_INFO:
+		rc = msm_get_sensor_info(pmsm->sync, argp);
+		break;
+	default:
+		rc = msm_ioctl_common(pmsm, cmd, argp);
+		break;
+	}
+
+	return rc;
+}
+
+static int __msm_release(struct msm_sync *sync)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *hnode;
+	struct hlist_node *n;
+
+	mutex_lock(&sync->lock);
+	if (sync->opencnt)
+		sync->opencnt--;
+
+	if (!sync->opencnt) {
+		/* need to clean up system resource */
+		if (sync->vfefn.vfe_release)
+			sync->vfefn.vfe_release(sync->pdev);
+
+		kfree(sync->cropinfo);
+		sync->cropinfo = NULL;
+		sync->croplen = 0;
+
+		hlist_for_each_entry_safe(region, hnode, n,
+				&sync->pmem_frames, list) {
+			hlist_del(hnode);
+			put_pmem_file(region->file);
+			kfree(region);
+		}
+
+		hlist_for_each_entry_safe(region, hnode, n,
+				&sync->pmem_stats, list) {
+			hlist_del(hnode);
+			put_pmem_file(region->file);
+			kfree(region);
+		}
+		msm_queue_drain(&sync->pict_q, list_pict);
+
+		wake_unlock(&sync->wake_lock);
+
+		sync->apps_id = NULL;
+		CDBG("%s: completed\n", __func__);
+	}
+	mutex_unlock(&sync->lock);
+
+	return 0;
+}
+
+static int msm_release_config(struct inode *node, struct file *filep)
+{
+	int rc;
+	struct msm_device *pmsm = filep->private_data;
+	CDBG("%s: %s\n", __func__, filep->f_path.dentry->d_name.name);
+	rc = __msm_release(pmsm->sync);
+	if (!rc) {
+		msm_queue_drain(&pmsm->sync->event_q, list_config);
+		atomic_set(&pmsm->opened, 0);
+	}
+	return rc;
+}
+
+static int msm_release_control(struct inode *node, struct file *filep)
+{
+	int rc;
+	struct msm_control_device *ctrl_pmsm = filep->private_data;
+	struct msm_device *pmsm = ctrl_pmsm->pmsm;
+	CDBG("%s: %s\n", __func__, filep->f_path.dentry->d_name.name);
+	rc = __msm_release(pmsm->sync);
+	if (!rc) {
+		msm_queue_drain(&ctrl_pmsm->ctrl_q, list_control);
+		kfree(ctrl_pmsm);
+	}
+	return rc;
+}
+
+static int msm_release_frame(struct inode *node, struct file *filep)
+{
+	int rc;
+	struct msm_device *pmsm = filep->private_data;
+	CDBG("%s: %s\n", __func__, filep->f_path.dentry->d_name.name);
+	rc = __msm_release(pmsm->sync);
+	if (!rc) {
+		msm_queue_drain(&pmsm->sync->frame_q, list_frame);
+		atomic_set(&pmsm->opened, 0);
+	}
+	return rc;
+}
+
+static int msm_unblock_poll_frame(struct msm_sync *sync)
+{
+	unsigned long flags;
+	CDBG("%s\n", __func__);
+	spin_lock_irqsave(&sync->frame_q.lock, flags);
+	sync->unblock_poll_frame = 1;
+	wake_up(&sync->frame_q.wait);
+	spin_unlock_irqrestore(&sync->frame_q.lock, flags);
+	return 0;
+}
+
+static unsigned int __msm_poll_frame(struct msm_sync *sync,
+		struct file *filep,
+		struct poll_table_struct *pll_table)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	poll_wait(filep, &sync->frame_q.wait, pll_table);
+
+	spin_lock_irqsave(&sync->frame_q.lock, flags);
+	if (!list_empty_careful(&sync->frame_q.list))
+		/* frame ready */
+		rc = POLLIN | POLLRDNORM;
+	if (sync->unblock_poll_frame) {
+		CDBG("%s: sync->unblock_poll_frame is true\n", __func__);
+		rc |= POLLPRI;
+		sync->unblock_poll_frame = 0;
+	}
+	spin_unlock_irqrestore(&sync->frame_q.lock, flags);
+
+	return rc;
+}
+
+static unsigned int msm_poll_frame(struct file *filep,
+	struct poll_table_struct *pll_table)
+{
+	struct msm_device *pmsm = filep->private_data;
+	return __msm_poll_frame(pmsm->sync, filep, pll_table);
+}
+
+/*
+ * This function executes in interrupt context.
+ */
+
+static void *msm_vfe_sync_alloc(int size,
+			void *syncdata __attribute__((unused)),
+			gfp_t gfp)
+{
+	struct msm_queue_cmd *qcmd =
+		kmalloc(sizeof(struct msm_queue_cmd) + size, gfp);
+	if (qcmd) {
+		qcmd->on_heap = 1;
+		return qcmd + 1;
+	}
+	return NULL;
+}
+
+static void msm_vfe_sync_free(void *ptr)
+{
+	if (ptr) {
+		struct msm_queue_cmd *qcmd =
+			(struct msm_queue_cmd *)ptr;
+		qcmd--;
+		if (qcmd->on_heap)
+			kfree(qcmd);
+	}
+}
+
+/*
+ * This function may execute in interrupt context.
+ */
+
+static void msm_vfe_sync(struct msm_vfe_resp *vdata,
+		enum msm_queue qtype, void *syncdata,
+		gfp_t gfp)
+{
+	struct msm_queue_cmd *qcmd = NULL;
+	struct msm_sync *sync = (struct msm_sync *)syncdata;
+
+	if (!sync) {
+		pr_err("%s: no context in dsp callback.\n", __func__);
+		return;
+	}
+
+	if (!sync->opencnt) {
+		pr_err("%s: SPURIOUS INTERRUPT\n", __func__);
+		return;
+	}
+
+	qcmd = ((struct msm_queue_cmd *)vdata) - 1;
+	qcmd->type = qtype;
+	qcmd->command = vdata;
+
+	if (qtype != MSM_CAM_Q_VFE_MSG)
+		goto for_config;
+
+	CDBG("%s: vdata->type %d\n", __func__, vdata->type);
+	switch (vdata->type) {
+	case VFE_MSG_OUTPUT1:
+	case VFE_MSG_OUTPUT2:
+	case VFE_MSG_OUTPUT_P:
+		if (sync->pp_mask & PP_PREV) {
+			CDBG("%s: PP_PREV in progress: phy_y %x phy_cbcr %x\n",
+				__func__,
+				vdata->phy.y_phy,
+				vdata->phy.cbcr_phy);
+			if (sync->pp_prev)
+				pr_warning("%s: overwriting pp_prev!\n",
+					__func__);
+			pr_info("%s: sending preview to config\n", __func__);
+			sync->pp_prev = qcmd;
+			break;
+		}
+
+		if (sync->report_preview_to_config) {
+			if (qcmd->on_heap)
+				qcmd->on_heap++;
+			msm_enqueue(&sync->frame_q, &qcmd->list_frame);
+			break;
+		}
+		msm_enqueue(&sync->frame_q, &qcmd->list_frame);
+		return;
+
+	case VFE_MSG_OUTPUT_V:
+		CDBG("%s: msm_enqueue video frame_q\n", __func__);
+		if (qcmd->on_heap)
+			qcmd->on_heap++;
+		msm_enqueue(&sync->frame_q, &qcmd->list_frame);
+		break;
+
+	case VFE_MSG_SNAPSHOT:
+		if (sync->pp_mask & (PP_SNAP | PP_RAW_SNAP)) {
+			CDBG("%s: PP_SNAP in progress: pp_mask %x\n",
+				__func__, sync->pp_mask);
+			if (sync->pp_snap)
+				pr_warning("%s: overwriting pp_snap!\n",
+					__func__);
+			pr_info("%s: sending snapshot to config\n", __func__);
+			sync->pp_snap = qcmd;
+			break;
+		}
+
+		if (qcmd->on_heap)
+			qcmd->on_heap++;
+		msm_enqueue(&sync->pict_q, &qcmd->list_pict);
+		break;
+
+	case VFE_MSG_STATS_AWB:
+		CDBG("%s: qtype %d, AWB stats, enqueue event_q.\n",
+		     __func__, vdata->type);
+		break;
+
+	case VFE_MSG_STATS_AEC:
+		CDBG("%s: qtype %d, AEC stats, enqueue event_q.\n",
+		     __func__, vdata->type);
+		break;
+
+	case VFE_MSG_STATS_IHIST:
+		CDBG("%s: qtype %d, ihist stats, enqueue event_q.\n",
+		     __func__, vdata->type);
+		break;
+
+	case VFE_MSG_STATS_RS:
+		CDBG("%s: qtype %d, rs stats, enqueue event_q.\n",
+		     __func__, vdata->type);
+		break;
+
+	case VFE_MSG_STATS_CS:
+		CDBG("%s: qtype %d, cs stats, enqueue event_q.\n",
+		     __func__, vdata->type);
+		break;
+
+
+	case VFE_MSG_GENERAL:
+		CDBG("%s: qtype %d, general msg, enqueue event_q.\n",
+		    __func__, vdata->type);
+		break;
+
+	default:
+		CDBG("%s: qtype %d not handled\n", __func__, vdata->type);
+		/* fall through, send to config. */
+	}
+
+for_config:
+	msm_enqueue(&sync->event_q, &qcmd->list_config);
+}
+
+static struct msm_vfe_callback msm_vfe_s = {
+	.vfe_resp = msm_vfe_sync,
+	.vfe_alloc = msm_vfe_sync_alloc,
+	.vfe_free = msm_vfe_sync_free,
+	.flash_ctrl = msm_camera_flash,
+};
+
+static int __msm_open(struct msm_sync *sync, const char *const apps_id)
+{
+	int rc = 0;
+
+	mutex_lock(&sync->lock);
+	if (sync->apps_id && strcmp(sync->apps_id, apps_id)) {
+		pr_err("%s(%s): sensor %s is already opened for %s\n",
+			__func__,
+			apps_id,
+			sync->sdata->sensor_name,
+			sync->apps_id);
+		rc = -EBUSY;
+		goto msm_open_done;
+	}
+
+	sync->apps_id = apps_id;
+
+	if (!sync->opencnt) {
+		wake_lock(&sync->wake_lock);
+
+		msm_camvfe_fn_init(&sync->vfefn, sync);
+		if (sync->vfefn.vfe_init) {
+			sync->get_pic_abort = 0;
+			rc = sync->vfefn.vfe_init(&msm_vfe_s,
+				sync->pdev);
+			if (rc < 0) {
+				pr_err("%s: vfe_init failed at %d\n",
+					__func__, rc);
+				goto msm_open_done;
+			}
+			rc = sync->sctrl.s_init(sync->sdata);
+			if (rc < 0) {
+				pr_err("%s: sensor init failed: %d\n",
+					__func__, rc);
+				goto msm_open_done;
+			}
+		} else {
+			pr_err("%s: no sensor init func\n", __func__);
+			rc = -ENODEV;
+			goto msm_open_done;
+		}
+
+		if (rc >= 0) {
+			INIT_HLIST_HEAD(&sync->pmem_frames);
+			INIT_HLIST_HEAD(&sync->pmem_stats);
+			sync->unblock_poll_frame = 0;
+		}
+	}
+	sync->opencnt++;
+
+msm_open_done:
+	mutex_unlock(&sync->lock);
+	return rc;
+}
+
+static int msm_open_common(struct inode *inode, struct file *filep,
+			   int once)
+{
+	int rc;
+	struct msm_device *pmsm =
+		container_of(inode->i_cdev, struct msm_device, cdev);
+
+	CDBG("%s: open %s\n", __func__, filep->f_path.dentry->d_name.name);
+
+	if (atomic_cmpxchg(&pmsm->opened, 0, 1) && once) {
+		pr_err("%s: %s is already opened.\n",
+			__func__,
+			filep->f_path.dentry->d_name.name);
+		return -EBUSY;
+	}
+
+	rc = nonseekable_open(inode, filep);
+	if (rc < 0) {
+		pr_err("%s: nonseekable_open error %d\n", __func__, rc);
+		return rc;
+	}
+
+	rc = __msm_open(pmsm->sync, MSM_APPS_ID_PROP);
+	if (rc < 0)
+		return rc;
+
+	filep->private_data = pmsm;
+
+	CDBG("%s: rc %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_open(struct inode *inode, struct file *filep)
+{
+	return msm_open_common(inode, filep, 1);
+}
+
+static int msm_open_control(struct inode *inode, struct file *filep)
+{
+	int rc;
+
+	struct msm_control_device *ctrl_pmsm =
+		kmalloc(sizeof(struct msm_control_device), GFP_KERNEL);
+	if (!ctrl_pmsm)
+		return -ENOMEM;
+
+	rc = msm_open_common(inode, filep, 0);
+	if (rc < 0) {
+		kfree(ctrl_pmsm);
+		return rc;
+	}
+
+	ctrl_pmsm->pmsm = filep->private_data;
+	filep->private_data = ctrl_pmsm;
+
+	msm_queue_init(&ctrl_pmsm->ctrl_q, "control");
+
+	CDBG("%s: rc %d\n", __func__, rc);
+	return rc;
+}
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static int __msm_v4l2_control(struct msm_sync *sync,
+		struct msm_ctrl_cmd *out)
+{
+	int rc = 0;
+
+	struct msm_queue_cmd *qcmd = NULL, *rcmd = NULL;
+	struct msm_ctrl_cmd *ctrl;
+	struct msm_device_queue FIXME;
+
+	/* wake up config thread, 4 is for V4L2 application */
+	qcmd = kmalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	if (!qcmd) {
+		pr_err("%s: cannot allocate buffer\n", __func__);
+		rc = -ENOMEM;
+		goto end;
+	}
+	qcmd->type = MSM_CAM_Q_V4L2_REQ;
+	qcmd->command = out;
+	qcmd->on_heap = 1;
+
+	rcmd = __msm_control(sync, &FIXME, qcmd, out->timeout_ms);
+	if (IS_ERR(rcmd)) {
+		rc = PTR_ERR(rcmd);
+		goto end;
+	}
+
+	ctrl = (struct msm_ctrl_cmd *)(rcmd->command);
+	/* FIXME: we should just set out->length = ctrl->length; */
+	BUG_ON(out->length < ctrl->length);
+	memcpy(out->value, ctrl->value, ctrl->length);
+
+end:
+	free_qcmd(rcmd);
+	CDBG("%s: rc %d\n", __func__, rc);
+	return rc;
+}
+#endif
+
+static const struct file_operations msm_fops_config = {
+	.owner = THIS_MODULE,
+	.open = msm_open,
+	.unlocked_ioctl = msm_ioctl_config,
+	.release = msm_release_config,
+};
+
+static const struct file_operations msm_fops_control = {
+	.owner = THIS_MODULE,
+	.open = msm_open_control,
+	.unlocked_ioctl = msm_ioctl_control,
+	.release = msm_release_control,
+};
+
+static const struct file_operations msm_fops_frame = {
+	.owner = THIS_MODULE,
+	.open = msm_open,
+	.unlocked_ioctl = msm_ioctl_frame,
+	.release = msm_release_frame,
+	.poll = msm_poll_frame,
+};
+
+static int msm_setup_cdev(struct msm_device *msm,
+			int node,
+			dev_t devno,
+			const char *suffix,
+			const struct file_operations *fops)
+{
+	int rc = -ENODEV;
+
+	struct device *device =
+		device_create(msm_class, NULL,
+			devno, NULL,
+			"%s%d", suffix, node);
+
+	if (IS_ERR(device)) {
+		rc = PTR_ERR(device);
+		pr_err("%s: error creating device: %d\n", __func__, rc);
+		return rc;
+	}
+
+	cdev_init(&msm->cdev, fops);
+	msm->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&msm->cdev, devno, 1);
+	if (rc < 0) {
+		pr_err("%s: error adding cdev: %d\n", __func__, rc);
+		device_destroy(msm_class, devno);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_tear_down_cdev(struct msm_device *msm, dev_t devno)
+{
+	cdev_del(&msm->cdev);
+	device_destroy(msm_class, devno);
+	return 0;
+}
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+int msm_v4l2_register(struct msm_v4l2_driver *drv)
+{
+	/* FIXME: support multiple sensors */
+	if (list_empty(&msm_sensors))
+		return -ENODEV;
+
+	drv->sync = list_first_entry(&msm_sensors, struct msm_sync, list);
+	drv->open      = __msm_open;
+	drv->release   = __msm_release;
+	drv->ctrl      = __msm_v4l2_control;
+	drv->reg_pmem  = __msm_register_pmem;
+	drv->get_frame = __msm_get_frame;
+	drv->put_frame = __msm_put_frame_buf;
+	drv->get_pict  = __msm_get_pic;
+	drv->drv_poll  = __msm_poll_frame;
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_v4l2_register);
+
+int msm_v4l2_unregister(struct msm_v4l2_driver *drv)
+{
+	drv->sync = NULL;
+	return 0;
+}
+EXPORT_SYMBOL(msm_v4l2_unregister);
+#endif
+
+static int msm_sync_init(struct msm_sync *sync,
+		struct platform_device *pdev,
+		int (*sensor_probe)(const struct msm_camera_sensor_info *,
+				struct msm_sensor_ctrl *))
+{
+	int rc = 0;
+	struct msm_sensor_ctrl sctrl;
+	sync->sdata = pdev->dev.platform_data;
+
+	msm_queue_init(&sync->event_q, "event");
+	msm_queue_init(&sync->frame_q, "frame");
+	msm_queue_init(&sync->pict_q, "pict");
+
+	wake_lock_init(&sync->wake_lock, WAKE_LOCK_SUSPEND, "msm_camera");
+
+	rc = msm_camio_probe_on(pdev);
+	if (rc < 0)
+		return rc;
+	rc = sensor_probe(sync->sdata, &sctrl);
+	if (rc >= 0) {
+		sync->pdev = pdev;
+		sync->sctrl = sctrl;
+	}
+	msm_camio_probe_off(pdev);
+	if (rc < 0) {
+		pr_err("%s: failed to initialize %s\n",
+			__func__,
+			sync->sdata->sensor_name);
+		wake_lock_destroy(&sync->wake_lock);
+		return rc;
+	}
+
+	sync->opencnt = 0;
+	mutex_init(&sync->lock);
+	CDBG("%s: initialized %s\n", __func__, sync->sdata->sensor_name);
+	return rc;
+}
+
+static int msm_sync_destroy(struct msm_sync *sync)
+{
+	wake_lock_destroy(&sync->wake_lock);
+	return 0;
+}
+
+static int msm_device_init(struct msm_device *pmsm,
+		struct msm_sync *sync,
+		int node)
+{
+	int dev_num = 3 * node;
+	int rc = msm_setup_cdev(pmsm, node,
+		MKDEV(MAJOR(msm_devno), dev_num),
+		"control", &msm_fops_control);
+	if (rc < 0) {
+		pr_err("%s: error creating control node: %d\n", __func__, rc);
+		return rc;
+	}
+
+	rc = msm_setup_cdev(pmsm + 1, node,
+		MKDEV(MAJOR(msm_devno), dev_num + 1),
+		"config", &msm_fops_config);
+	if (rc < 0) {
+		pr_err("%s: error creating config node: %d\n", __func__, rc);
+		msm_tear_down_cdev(pmsm, MKDEV(MAJOR(msm_devno),
+				dev_num));
+		return rc;
+	}
+
+	rc = msm_setup_cdev(pmsm + 2, node,
+		MKDEV(MAJOR(msm_devno), dev_num + 2),
+		"frame", &msm_fops_frame);
+	if (rc < 0) {
+		pr_err("%s: error creating frame node: %d\n", __func__, rc);
+		msm_tear_down_cdev(pmsm,
+			MKDEV(MAJOR(msm_devno), dev_num));
+		msm_tear_down_cdev(pmsm + 1,
+			MKDEV(MAJOR(msm_devno), dev_num + 1));
+		return rc;
+	}
+
+	atomic_set(&pmsm[0].opened, 0);
+	atomic_set(&pmsm[1].opened, 0);
+	atomic_set(&pmsm[2].opened, 0);
+
+	pmsm[0].sync = sync;
+	pmsm[1].sync = sync;
+	pmsm[2].sync = sync;
+
+	return rc;
+}
+
+int msm_camera_drv_start(struct platform_device *dev,
+		int (*sensor_probe)(const struct msm_camera_sensor_info *,
+			struct msm_sensor_ctrl *))
+{
+	struct msm_device *pmsm = NULL;
+	struct msm_sync *sync;
+	int rc = -ENODEV;
+	static int camera_node;
+
+	if (camera_node >= MSM_MAX_CAMERA_SENSORS) {
+		pr_err("%s: too many camera sensors\n", __func__);
+		return rc;
+	}
+
+	if (!msm_class) {
+		/* There are three device nodes per sensor */
+		rc = alloc_chrdev_region(&msm_devno, 0,
+				3 * MSM_MAX_CAMERA_SENSORS,
+				"msm_camera");
+		if (rc < 0) {
+			pr_err("%s: failed to allocate chrdev: %d\n", __func__,
+				rc);
+			return rc;
+		}
+
+		msm_class = class_create(THIS_MODULE, "msm_camera");
+		if (IS_ERR(msm_class)) {
+			rc = PTR_ERR(msm_class);
+			pr_err("%s: create device class failed: %d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	pmsm = kzalloc(sizeof(struct msm_device) * 3 +
+			sizeof(struct msm_sync), GFP_ATOMIC);
+	if (!pmsm)
+		return -ENOMEM;
+	sync = (struct msm_sync *)(pmsm + 3);
+
+	rc = msm_sync_init(sync, dev, sensor_probe);
+	if (rc < 0) {
+		kfree(pmsm);
+		return rc;
+	}
+
+	CDBG("%s: setting camera node %d\n", __func__, camera_node);
+	rc = msm_device_init(pmsm, sync, camera_node);
+	if (rc < 0) {
+		msm_sync_destroy(sync);
+		kfree(pmsm);
+		return rc;
+	}
+
+	camera_node++;
+	list_add(&sync->list, &msm_sensors);
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_drv_start);
diff --git a/drivers/media/video/msm/msm_io7x.c b/drivers/media/video/msm/msm_io7x.c
new file mode 100644
index 0000000..63c9b64
--- /dev/null
+++ b/drivers/media/video/msm/msm_io7x.c
@@ -0,0 +1,311 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+
+#define CAMIF_CFG_RMSK 0x1fffff
+#define CAM_SEL_BMSK 0x2
+#define CAM_PCLK_SRC_SEL_BMSK 0x60000
+#define CAM_PCLK_INVERT_BMSK 0x80000
+#define CAM_PAD_REG_SW_RESET_BMSK 0x100000
+
+#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
+#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
+#define MDDI_CLK_CHICKEN_BIT_BMSK  0x80
+
+#define CAM_SEL_SHFT 0x1
+#define CAM_PCLK_SRC_SEL_SHFT 0x11
+#define CAM_PCLK_INVERT_SHFT 0x13
+#define CAM_PAD_REG_SW_RESET_SHFT 0x14
+
+#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
+#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
+#define MDDI_CLK_CHICKEN_BIT_SHFT  0x7
+#define APPS_RESET_OFFSET 0x00000210
+
+static struct clk *camio_vfe_mdc_clk;
+static struct clk *camio_mdc_clk;
+static struct clk *camio_vfe_clk;
+
+static struct msm_camera_io_ext camio_ext;
+static struct resource *appio, *mdcio;
+void __iomem *appbase, *mdcbase;
+
+static struct msm_camera_io_ext camio_ext;
+static struct resource *appio, *mdcio;
+void __iomem *appbase, *mdcbase;
+
+int clk_set_flags(struct clk *clk, unsigned long flags);
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+	int rc = -1;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		clk = camio_vfe_mdc_clk = clk_get(NULL, "vfe_mdc_clk");
+		break;
+
+	case CAMIO_MDC_CLK:
+		clk = camio_mdc_clk = clk_get(NULL, "mdc_clk");
+		break;
+
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk = clk_get(NULL, "vfe_clk");
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_enable(clk);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+	int rc = -1;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		clk = camio_vfe_mdc_clk;
+		break;
+
+	case CAMIO_MDC_CLK:
+		clk = camio_mdc_clk;
+		break;
+
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk;
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_disable(clk);
+		clk_put(clk);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_vfe_clk;
+
+	if (clk != ERR_PTR(-ENOENT))
+		clk_set_rate(clk, rate);
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camio_ext = camdev->ioext;
+
+	appio = request_mem_region(camio_ext.appphy,
+				   camio_ext.appsz, pdev->name);
+	if (!appio) {
+		rc = -EBUSY;
+		goto enable_fail;
+	}
+
+	appbase = ioremap(camio_ext.appphy, camio_ext.appsz);
+	if (!appbase) {
+		rc = -ENOMEM;
+		goto apps_no_mem;
+	}
+
+	mdcio = request_mem_region(camio_ext.mdcphy,
+				   camio_ext.mdcsz, pdev->name);
+	if (!mdcio) {
+		rc = -EBUSY;
+		goto mdc_busy;
+	}
+
+	mdcbase = ioremap(camio_ext.mdcphy, camio_ext.mdcsz);
+	if (!mdcbase) {
+		rc = -ENOMEM;
+		goto mdc_no_mem;
+	}
+
+	camdev->camera_gpio_on();
+
+	msm_camio_clk_enable(CAMIO_VFE_CLK);
+	msm_camio_clk_enable(CAMIO_MDC_CLK);
+	msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
+	return 0;
+
+mdc_no_mem:
+	release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+mdc_busy:
+	iounmap(appbase);
+apps_no_mem:
+	release_mem_region(camio_ext.appphy, camio_ext.appsz);
+enable_fail:
+	return rc;
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	iounmap(mdcbase);
+	release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+	iounmap(appbase);
+	release_mem_region(camio_ext.appphy, camio_ext.appsz);
+
+	camdev->camera_gpio_off();
+
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_MDC_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
+}
+
+void msm_camio_camif_pad_reg_reset(void)
+{
+	uint32_t reg;
+	uint32_t mask, value;
+
+	/* select CLKRGM_VFE_SRC_CAM_VFE_SRC:  internal source */
+	msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+
+	mask = CAM_SEL_BMSK | CAM_PCLK_SRC_SEL_BMSK | CAM_PCLK_INVERT_BMSK;
+
+	value = 1 << CAM_SEL_SHFT |
+	    3 << CAM_PCLK_SRC_SEL_SHFT | 0 << CAM_PCLK_INVERT_SHFT;
+
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+
+	msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL);
+	mdelay(10);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+	uint32_t val;
+
+	val = readl(appbase + 0x00000210);
+	val |= 0x1;
+	writel(val, appbase + 0x00000210);
+	mdelay(10);
+
+	val = readl(appbase + 0x00000210);
+	val &= ~0x1;
+	writel(val, appbase + 0x00000210);
+	mdelay(10);
+
+	/* do axi reset */
+	val = readl(appbase + 0x00000208);
+	val |= 0x1;
+	writel(val, appbase + 0x00000208);
+	mdelay(10);
+
+	val = readl(appbase + 0x00000208);
+	val &= ~0x1;
+	writel(val, appbase + 0x00000208);
+	mdelay(10);
+}
+
+void msm_camio_camif_pad_reg_reset_2(void)
+{
+	uint32_t reg;
+	uint32_t mask, value;
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+}
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
+{
+	struct clk *clk = NULL;
+
+	clk = camio_vfe_clk;
+
+	if (clk != NULL && clk != ERR_PTR(-ENOENT)) {
+		switch (srctype) {
+		case MSM_CAMIO_CLK_SRC_INTERNAL:
+			clk_set_flags(clk, 0x00000100 << 1);
+			break;
+
+		case MSM_CAMIO_CLK_SRC_EXTERNAL:
+			clk_set_flags(clk, 0x00000100);
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_on();
+	return msm_camio_clk_enable(CAMIO_VFE_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_VFE_CLK);
+}
diff --git a/drivers/media/video/msm/msm_io8x.c b/drivers/media/video/msm/msm_io8x.c
new file mode 100644
index 0000000..ae4fe44
--- /dev/null
+++ b/drivers/media/video/msm/msm_io8x.c
@@ -0,0 +1,332 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+
+#define CAMIF_CFG_RMSK 0x1fffff
+#define CAM_SEL_BMSK 0x2
+#define CAM_PCLK_SRC_SEL_BMSK 0x60000
+#define CAM_PCLK_INVERT_BMSK 0x80000
+#define CAM_PAD_REG_SW_RESET_BMSK 0x100000
+
+#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
+#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
+#define MDDI_CLK_CHICKEN_BIT_BMSK  0x80
+
+#define CAM_SEL_SHFT 0x1
+#define CAM_PCLK_SRC_SEL_SHFT 0x11
+#define CAM_PCLK_INVERT_SHFT 0x13
+#define CAM_PAD_REG_SW_RESET_SHFT 0x14
+
+#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
+#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
+#define MDDI_CLK_CHICKEN_BIT_SHFT  0x7
+#define APPS_RESET_OFFSET 0x00000210
+
+static struct clk *camio_vfe_mdc_clk;
+static struct clk *camio_mdc_clk;
+static struct clk *camio_vfe_clk;
+static struct clk *camio_vfe_axi_clk;
+static struct msm_camera_io_ext camio_ext;
+static struct resource *appio, *mdcio;
+void __iomem *appbase, *mdcbase;
+
+int clk_set_flags(struct clk *clk, unsigned long flags);
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		camio_vfe_mdc_clk = clk = clk_get(NULL, "vfe_mdc_clk");
+		break;
+
+	case CAMIO_MDC_CLK:
+		camio_mdc_clk = clk = clk_get(NULL, "mdc_clk");
+		break;
+
+	case CAMIO_VFE_CLK:
+		camio_vfe_clk = clk = clk_get(NULL, "vfe_clk");
+		break;
+
+	case CAMIO_VFE_AXI_CLK:
+		camio_vfe_axi_clk = clk = clk_get(NULL, "vfe_axi_clk");
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		/* Set rate here *before* enabling the block to prevent
+		 * unstable clock from source.
+		 */
+		if (clktype == CAMIO_VFE_CLK && camio_vfe_clk) {
+			clk_set_rate(camio_vfe_clk, 96000000);
+		}
+		clk_enable(clk);
+	}
+	else
+		rc = -1;
+
+	return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		clk = camio_vfe_mdc_clk;
+		break;
+
+	case CAMIO_MDC_CLK:
+		clk = camio_mdc_clk;
+		break;
+
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk;
+		break;
+
+	case CAMIO_VFE_AXI_CLK:
+		clk = camio_vfe_axi_clk;
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_disable(clk);
+		clk_put(clk);
+	} else
+		rc = -1;
+
+	return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_vfe_mdc_clk;
+
+	/* TODO: check return */
+	clk_set_rate(clk, rate);
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camio_ext = camdev->ioext;
+
+	appio = request_mem_region(camio_ext.appphy,
+				   camio_ext.appsz, pdev->name);
+	if (!appio) {
+		rc = -EBUSY;
+		goto enable_fail;
+	}
+
+	appbase = ioremap(camio_ext.appphy, camio_ext.appsz);
+	if (!appbase) {
+		rc = -ENOMEM;
+		goto apps_no_mem;
+	}
+
+	mdcio = request_mem_region(camio_ext.mdcphy,
+				   camio_ext.mdcsz, pdev->name);
+	if (!mdcio) {
+		rc = -EBUSY;
+		goto mdc_busy;
+	}
+
+	mdcbase = ioremap(camio_ext.mdcphy, camio_ext.mdcsz);
+	if (!mdcbase) {
+		rc = -ENOMEM;
+		goto mdc_no_mem;
+	}
+
+	camdev->camera_gpio_on();
+
+	msm_camio_clk_enable(CAMIO_VFE_CLK);
+	msm_camio_clk_enable(CAMIO_MDC_CLK);
+	msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
+	msm_camio_clk_enable(CAMIO_VFE_AXI_CLK);
+
+	return 0;
+
+mdc_no_mem:
+	release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+mdc_busy:
+	iounmap(appbase);
+apps_no_mem:
+	release_mem_region(camio_ext.appphy, camio_ext.appsz);
+enable_fail:
+	return rc;
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	iounmap(mdcbase);
+	release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+	iounmap(appbase);
+	release_mem_region(camio_ext.appphy, camio_ext.appsz);
+
+	camdev->camera_gpio_off();
+
+	msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
+	msm_camio_clk_disable(CAMIO_MDC_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_AXI_CLK);
+}
+
+void msm_camio_camif_pad_reg_reset(void)
+{
+	uint32_t reg;
+	uint32_t mask, value;
+
+	/* select CLKRGM_VFE_SRC_CAM_VFE_SRC:  internal source */
+	msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+
+	mask = CAM_SEL_BMSK |
+	    CAM_PCLK_SRC_SEL_BMSK |
+	    CAM_PCLK_INVERT_BMSK |
+	    EXT_CAM_HSYNC_POL_SEL_BMSK |
+	    EXT_CAM_VSYNC_POL_SEL_BMSK | MDDI_CLK_CHICKEN_BIT_BMSK;
+
+	value = 1 << CAM_SEL_SHFT |
+	    3 << CAM_PCLK_SRC_SEL_SHFT |
+	    0 << CAM_PCLK_INVERT_SHFT |
+	    0 << EXT_CAM_HSYNC_POL_SEL_SHFT |
+	    0 << EXT_CAM_VSYNC_POL_SEL_SHFT | 0 << MDDI_CLK_CHICKEN_BIT_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+
+	msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL);
+
+	mdelay(10);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+#if 0
+	uint32_t val;
+
+	val = readl(appbase + 0x00000210);
+	val |= 0x1;
+	writel(val, appbase + 0x00000210);
+	mdelay(10);
+
+	val = readl(appbase + 0x00000210);
+	val &= ~0x1;
+	writel(val, appbase + 0x00000210);
+	mdelay(10);
+#endif
+}
+
+void msm_camio_camif_pad_reg_reset_2(void)
+{
+	uint32_t reg;
+	uint32_t mask, value;
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+}
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
+{
+	struct clk *clk = NULL;
+
+	clk = camio_vfe_clk;
+
+	if (clk != NULL) {
+		switch (srctype) {
+		case MSM_CAMIO_CLK_SRC_INTERNAL:
+			clk_set_flags(clk, 0x00000100 << 1);
+			break;
+
+		case MSM_CAMIO_CLK_SRC_EXTERNAL:
+			clk_set_flags(clk, 0x00000100);
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+void msm_camio_clk_axi_rate_set(int rate)
+{
+	struct clk *clk = camio_vfe_axi_clk;
+	/* todo: check return */
+	clk_set_rate(clk, rate);
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camdev->camera_gpio_on();
+	return msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
+}
diff --git a/drivers/media/video/msm/msm_io_vfe31.c b/drivers/media/video/msm/msm_io_vfe31.c
new file mode 100644
index 0000000..523c7f1
--- /dev/null
+++ b/drivers/media/video/msm/msm_io_vfe31.c
@@ -0,0 +1,285 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+
+#define CAMIF_CFG_RMSK             0x1fffff
+#define CAM_SEL_BMSK               0x2
+#define CAM_PCLK_SRC_SEL_BMSK      0x60000
+#define CAM_PCLK_INVERT_BMSK       0x80000
+#define CAM_PAD_REG_SW_RESET_BMSK  0x100000
+
+#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
+#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
+#define MDDI_CLK_CHICKEN_BIT_BMSK  0x80
+
+#define CAM_SEL_SHFT               0x1
+#define CAM_PCLK_SRC_SEL_SHFT      0x11
+#define CAM_PCLK_INVERT_SHFT       0x13
+#define CAM_PAD_REG_SW_RESET_SHFT  0x14
+
+#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
+#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
+#define MDDI_CLK_CHICKEN_BIT_SHFT  0x7
+
+static struct clk *camio_vfe_mdc_clk;
+static struct clk *camio_mdc_clk;
+static struct clk *camio_vfe_clk;
+static struct clk *camio_vfe_camif_clk;
+static struct clk *camio_vfe_pbdg_clk;
+static struct clk *camio_cam_m_clk;
+static struct clk *camio_camif_pad_pbdg_clk;
+static struct msm_camera_io_ext camio_ext;
+static struct resource *camifpadio;
+void __iomem *camifpadbase;
+
+static void camif_io_w(u32 data)
+{
+	writel(data, camifpadbase);
+	wmb();
+}
+
+static u32 camif_io_r(void)
+{
+	uint32_t data = readl(camifpadbase);
+	rmb();
+	return data;
+}
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		camio_vfe_mdc_clk = clk = clk_get(NULL, "vfe_mdc_clk");
+		break;
+
+	case CAMIO_MDC_CLK:
+		camio_mdc_clk = clk = clk_get(NULL, "mdc_clk");
+		break;
+
+	case CAMIO_VFE_CLK:
+		camio_vfe_clk = clk = clk_get(NULL, "vfe_clk");
+		clk_set_rate(clk, 122880000);
+		break;
+
+	case CAMIO_VFE_CAMIF_CLK:
+		camio_vfe_camif_clk = clk = clk_get(NULL, "vfe_camif_clk");
+		break;
+
+	case CAMIO_VFE_PBDG_CLK:
+		camio_vfe_pbdg_clk = clk = clk_get(NULL, "vfe_pclk");
+		break;
+
+	case CAMIO_CAM_MCLK_CLK:
+		camio_cam_m_clk = clk = clk_get(NULL, "cam_m_clk");
+		clk_set_rate(clk, 24000000);
+		break;
+
+	case CAMIO_CAMIF_PAD_PBDG_CLK:
+		camio_camif_pad_pbdg_clk = clk = clk_get(NULL, "camif_pad_pclk");
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk))
+		clk_enable(clk);
+	else
+		rc = -1;
+	return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		clk = camio_vfe_mdc_clk;
+		break;
+
+	case CAMIO_MDC_CLK:
+		clk = camio_mdc_clk;
+		break;
+
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk;
+		break;
+
+	case CAMIO_VFE_CAMIF_CLK:
+		clk = camio_vfe_camif_clk;
+		break;
+
+	case CAMIO_VFE_PBDG_CLK:
+		clk = camio_vfe_pbdg_clk;
+		break;
+
+	case CAMIO_CAM_MCLK_CLK:
+		clk = camio_cam_m_clk;
+		break;
+
+	case CAMIO_CAMIF_PAD_PBDG_CLK:
+		clk = camio_camif_pad_pbdg_clk;
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_disable(clk);
+		clk_put(clk);
+	} else
+		rc = -1;
+
+	return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_cam_m_clk;
+	clk_set_rate(clk, rate);
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camio_ext = camdev->ioext;
+
+	camdev->camera_gpio_on();
+	msm_camio_clk_enable(CAMIO_VFE_PBDG_CLK);
+	msm_camio_clk_enable(CAMIO_CAMIF_PAD_PBDG_CLK);
+	msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+	msm_camio_clk_enable(CAMIO_VFE_CLK);
+	camifpadio = request_mem_region(camio_ext.camifpadphy,
+		camio_ext.camifpadsz, pdev->name);
+	if (!camifpadio) {
+		rc = -EBUSY;
+		goto common_fail;
+	}
+	camifpadbase = ioremap(camio_ext.camifpadphy, camio_ext.camifpadsz);
+	if (!camifpadbase) {
+		rc = -ENOMEM;
+		goto parallel_busy;
+	}
+	msm_camio_clk_enable(CAMIO_VFE_CAMIF_CLK);
+	return 0;
+
+parallel_busy:
+	release_mem_region(camio_ext.camifpadphy, camio_ext.camifpadsz);
+common_fail:
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+	msm_camio_clk_disable(CAMIO_CAMIF_PAD_PBDG_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_PBDG_CLK);
+	camdev->camera_gpio_off();
+	return rc;
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	msm_camio_clk_disable(CAMIO_VFE_CAMIF_CLK);
+	iounmap(camifpadbase);
+	release_mem_region(camio_ext.camifpadphy, camio_ext.camifpadsz);
+	CDBG("disable clocks\n");
+
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+	msm_camio_clk_disable(CAMIO_CAMIF_PAD_PBDG_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_PBDG_CLK);
+	camdev->camera_gpio_off();
+}
+
+void msm_camio_camif_pad_reg_reset(void)
+{
+	uint32_t reg;
+
+	msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
+	msleep(10);
+
+	reg = camif_io_r() & CAMIF_CFG_RMSK;
+	reg |= 0x3;
+	camif_io_w(reg);
+	msleep(10);
+
+	reg = camif_io_r() & CAMIF_CFG_RMSK;
+	reg |= 0x10;
+	camif_io_w(reg);
+	msleep(10);
+
+	reg = camif_io_r() & CAMIF_CFG_RMSK;
+	/* Need to be uninverted*/
+	reg &= 0x03;
+	camif_io_w(reg);
+	msleep(10);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+	return;
+}
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
+{
+	if (camio_vfe_clk != NULL) {
+		switch (srctype) {
+		case MSM_CAMIO_CLK_SRC_INTERNAL:
+			clk_set_flags(camio_vfe_clk, 0x00000100 << 1);
+			break;
+
+		case MSM_CAMIO_CLK_SRC_EXTERNAL:
+			clk_set_flags(camio_vfe_clk, 0x00000100);
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_on();
+	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+}
diff --git a/drivers/media/video/msm/msm_v4l2.c b/drivers/media/video/msm/msm_v4l2.c
new file mode 100644
index 0000000..6abbdb9
--- /dev/null
+++ b/drivers/media/video/msm/msm_v4l2.c
@@ -0,0 +1,790 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <media/v4l2-dev.h>
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+#include <media/v4l2-ioctl.h>
+/*#include <linux/platform_device.h>*/
+
+#define MSM_V4L2_START_SNAPSHOT _IOWR('V', BASE_VIDIOC_PRIVATE+1, \
+      struct v4l2_buffer)
+
+#define MSM_V4L2_GET_PICTURE    _IOWR('V', BASE_VIDIOC_PRIVATE+2, \
+      struct v4l2_buffer)
+
+#define MSM_V4L2_DEVICE_NAME       "msm_v4l2"
+
+#define MSM_V4L2_PROC_NAME         "msm_v4l2"
+
+#define MSM_V4L2_DEVNUM_MPEG2       0
+#define MSM_V4L2_DEVNUM_YUV         20
+
+/* HVGA-P (portrait) and HVGA-L (landscape) */
+#define MSM_V4L2_WIDTH              480
+#define MSM_V4L2_HEIGHT             320
+
+#if 1
+#define D(fmt, args...) printk(KERN_INFO "msm_v4l2: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+#define PREVIEW_FRAMES_NUM 4
+
+struct msm_v4l2_device {
+	struct list_head read_queue;
+	struct v4l2_format current_cap_format;
+	struct v4l2_format current_pix_format;
+	struct video_device *pvdev;
+	struct msm_v4l2_driver *drv;
+	uint8_t opencnt;
+
+	spinlock_t read_queue_lock;
+};
+
+static struct msm_v4l2_device *g_pmsm_v4l2_dev;
+
+static DEFINE_MUTEX(msm_v4l2_opencnt_lock);
+
+static int msm_v4l2_open(struct file *f)
+{
+	int rc = 0;
+	D("%s\n", __func__);
+	mutex_lock(&msm_v4l2_opencnt_lock);
+	if (!g_pmsm_v4l2_dev->opencnt) {
+		rc = g_pmsm_v4l2_dev->drv->open(g_pmsm_v4l2_dev->drv->sync,
+						MSM_APPS_ID_V4L2);
+	}
+	g_pmsm_v4l2_dev->opencnt++;
+	mutex_unlock(&msm_v4l2_opencnt_lock);
+	return rc;
+}
+
+static int msm_v4l2_release(struct file *f)
+{
+	int rc = 0;
+	D("%s\n", __func__);
+	mutex_lock(&msm_v4l2_opencnt_lock);
+	if (!g_pmsm_v4l2_dev->opencnt) {
+		g_pmsm_v4l2_dev->opencnt--;
+		if (!g_pmsm_v4l2_dev->opencnt) {
+			rc = g_pmsm_v4l2_dev->drv->release(g_pmsm_v4l2_dev->
+							   drv->sync);
+		}
+	}
+	mutex_unlock(&msm_v4l2_opencnt_lock);
+	return rc;
+}
+
+static unsigned int msm_v4l2_poll(struct file *f, struct poll_table_struct *w)
+{
+	return g_pmsm_v4l2_dev->drv->drv_poll(g_pmsm_v4l2_dev->drv->sync, f, w);
+}
+
+static long msm_v4l2_ioctl(struct file *filep,
+			   unsigned int cmd, unsigned long arg)
+{
+	struct msm_ctrl_cmd *ctrlcmd;
+
+	D("msm_v4l2_ioctl, cmd = %d, %d\n", cmd, __LINE__);
+
+	switch (cmd) {
+	case MSM_V4L2_START_SNAPSHOT:
+
+		ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+		if (!ctrlcmd) {
+			CDBG("msm_v4l2_ioctl: cannot allocate buffer\n");
+			return -ENOMEM;
+		}
+
+		ctrlcmd->length = 0;
+		ctrlcmd->value = NULL;
+		ctrlcmd->timeout_ms = 10000;
+
+		D("msm_v4l2_ioctl,  MSM_V4L2_START_SNAPSHOT v4l2 ioctl %d\n",
+		  cmd);
+		ctrlcmd->type = MSM_V4L2_SNAPSHOT;
+		return g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync,
+						  ctrlcmd);
+
+	case MSM_V4L2_GET_PICTURE:
+		D("msm_v4l2_ioctl,  MSM_V4L2_GET_PICTURE v4l2 ioctl %d\n", cmd);
+		ctrlcmd = (struct msm_ctrl_cmd *)arg;
+		return g_pmsm_v4l2_dev->drv->get_pict(g_pmsm_v4l2_dev->drv->
+						      sync, ctrlcmd);
+
+	default:
+		D("msm_v4l2_ioctl, standard v4l2 ioctl %d\n", cmd);
+		return video_ioctl2(filep, cmd, arg);
+	}
+}
+
+static void msm_v4l2_release_dev(struct video_device *d)
+{
+	D("%s\n", __func__);
+}
+
+static int msm_v4l2_querycap(struct file *f,
+			     void *pctx, struct v4l2_capability *pcaps)
+{
+	D("%s\n", __func__);
+	strncpy(pcaps->driver, MSM_APPS_ID_V4L2, sizeof(pcaps->driver));
+	strncpy(pcaps->card, MSM_V4L2_DEVICE_NAME, sizeof(pcaps->card));
+	pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int msm_v4l2_s_std(struct file *f, void *pctx, v4l2_std_id * pnorm)
+{
+	D("%s\n", __func__);
+	return 0;
+}
+
+static int msm_v4l2_queryctrl(struct file *f,
+			      void *pctx, struct v4l2_queryctrl *pqctrl)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd *ctrlcmd;
+
+	D("%s\n", __func__);
+
+	ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+	if (!ctrlcmd) {
+		CDBG("msm_v4l2_queryctrl: cannot allocate buffer\n");
+		return -ENOMEM;
+	}
+
+	ctrlcmd->type = MSM_V4L2_QUERY_CTRL;
+	ctrlcmd->length = sizeof(struct v4l2_queryctrl);
+	ctrlcmd->value = pqctrl;
+	ctrlcmd->timeout_ms = 10000;
+
+	rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+	if (rc < 0)
+		return -1;
+
+	return ctrlcmd->status;
+}
+
+static int msm_v4l2_g_ctrl(struct file *f, void *pctx, struct v4l2_control *c)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd *ctrlcmd;
+
+	D("%s\n", __func__);
+
+	ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+	if (!ctrlcmd) {
+		CDBG("msm_v4l2_g_ctrl: cannot allocate buffer\n");
+		return -ENOMEM;
+	}
+
+	ctrlcmd->type = MSM_V4L2_GET_CTRL;
+	ctrlcmd->length = sizeof(struct v4l2_control);
+	ctrlcmd->value = c;
+	ctrlcmd->timeout_ms = 10000;
+
+	rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+	if (rc < 0)
+		return -1;
+
+	return ctrlcmd->status;
+}
+
+static int msm_v4l2_s_ctrl(struct file *f, void *pctx, struct v4l2_control *c)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd *ctrlcmd;
+
+	ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+	if (!ctrlcmd) {
+		CDBG("msm_v4l2_s_ctrl: cannot allocate buffer\n");
+		return -ENOMEM;
+	}
+
+	ctrlcmd->type = MSM_V4L2_SET_CTRL;
+	ctrlcmd->length = sizeof(struct v4l2_control);
+	ctrlcmd->value = c;
+	ctrlcmd->timeout_ms = 10000;
+
+	D("%s\n", __func__);
+
+	rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+	if (rc < 0)
+		return -1;
+
+	return ctrlcmd->status;
+}
+
+static int msm_v4l2_reqbufs(struct file *f,
+			    void *pctx, struct v4l2_requestbuffers *b)
+{
+	D("%s\n", __func__);
+	return 0;
+}
+
+static int msm_v4l2_querybuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
+{
+	struct msm_pmem_info pmem_buf;
+#if 0
+	__u32 width = 0;
+	__u32 height = 0;
+	__u32 y_size = 0;
+	__u32 y_pad = 0;
+
+	/* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.width; */
+	width = 640;
+	/* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.height; */
+	height = 480;
+
+	D("%s: width = %d, height = %d\n", __func__, width, height);
+
+	y_size = width * height;
+	y_pad = y_size % 4;
+#endif
+
+	__u32 y_pad = pb->bytesused % 4;
+
+	/* V4L2 videodev will do the copy_from_user. */
+
+	memset(&pmem_buf, 0, sizeof(struct msm_pmem_info));
+	pmem_buf.type = MSM_PMEM_OUTPUT2;
+	pmem_buf.vaddr = (void *)pb->m.userptr;
+	pmem_buf.y_off = 0;
+	pmem_buf.fd = (int)pb->reserved;
+	/* pmem_buf.cbcr_off = (y_size + y_pad); */
+	pmem_buf.cbcr_off = (pb->bytesused + y_pad);
+
+	g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync, &pmem_buf);
+
+	return 0;
+}
+
+static int msm_v4l2_qbuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
+{
+	/*
+	   __u32 y_size = 0;
+	   __u32 y_pad = 0;
+	   __u32 width = 0;
+	   __u32 height = 0;
+	 */
+
+	__u32 y_pad = 0;
+
+	struct msm_pmem_info meminfo;
+	struct msm_frame frame;
+	static int cnt;
+
+	if ((pb->flags >> 16) & 0x0001) {
+		/* this is for previwe */
+#if 0
+		width = 640;
+		height = 480;
+
+		/* V4L2 videodev will do the copy_from_user. */
+		D("%s: width = %d, height = %d\n", __func__, width, height);
+		y_size = width * height;
+		y_pad = y_size % 4;
+#endif
+
+		y_pad = pb->bytesused % 4;
+
+		if (pb->type == V4L2_BUF_TYPE_PRIVATE) {
+			/* this qbuf is actually for releasing */
+
+			frame.buffer = pb->m.userptr;
+			frame.y_off = 0;
+			/* frame.cbcr_off = (y_size + y_pad); */
+			frame.cbcr_off = (pb->bytesused + y_pad);
+			frame.fd = pb->reserved;
+
+			D("V4L2_BUF_TYPE_PRIVATE: pb->bytesused = %d \n",
+			  pb->bytesused);
+
+			g_pmsm_v4l2_dev->drv->put_frame(g_pmsm_v4l2_dev->drv->
+							sync, &frame);
+
+			return 0;
+		}
+
+		D("V4L2_BUF_TYPE_VIDEO_CAPTURE: pb->bytesused = %d \n",
+		  pb->bytesused);
+
+		meminfo.type = MSM_PMEM_OUTPUT2;
+		meminfo.fd = (int)pb->reserved;
+		meminfo.vaddr = (void *)pb->m.userptr;
+		meminfo.y_off = 0;
+		/* meminfo.cbcr_off = (y_size + y_pad); */
+		meminfo.cbcr_off = (pb->bytesused + y_pad);
+		meminfo.vfe_can_write =
+			cnt != PREVIEW_FRAMES_NUM - 1;
+		cnt++;
+		g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync,
+					       &meminfo);
+	} else if ((pb->flags) & 0x0001) {
+		/* this is for snapshot */
+
+		__u32 y_size = 0;
+
+		if ((pb->flags >> 8) & 0x01) {
+
+			y_size = pb->bytesused;
+
+			meminfo.type = MSM_PMEM_THUMBNAIL;
+		} else if ((pb->flags >> 9) & 0x01) {
+
+			y_size = pb->bytesused;
+
+			meminfo.type = MSM_PMEM_MAINIMG;
+		}
+
+		y_pad = y_size % 4;
+
+		meminfo.fd = (int)pb->reserved;
+		meminfo.vaddr = (void *)pb->m.userptr;
+		meminfo.y_off = 0;
+		/* meminfo.cbcr_off = (y_size + y_pad); */
+		meminfo.cbcr_off = (y_size + y_pad);
+		meminfo.vfe_can_write = 1;
+		g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync,
+					       &meminfo);
+	}
+
+	return 0;
+}
+
+static int msm_v4l2_dqbuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
+{
+	struct msm_frame frame;
+	D("%s\n", __func__);
+
+	/* V4L2 videodev will do the copy_to_user. */
+	if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+
+		D("%s, %d\n", __func__, __LINE__);
+
+		g_pmsm_v4l2_dev->drv->get_frame(g_pmsm_v4l2_dev->drv->sync,
+						&frame);
+
+		pb->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		pb->m.userptr = (unsigned long)frame.buffer;	/* FIXME */
+		pb->reserved = (int)frame.fd;
+		/* pb->length     = (int)frame.cbcr_off; */
+
+		pb->bytesused = frame.cbcr_off;
+
+	} else if (pb->type == V4L2_BUF_TYPE_PRIVATE) {
+		__u32 y_pad = pb->bytesused % 4;
+
+		frame.buffer = pb->m.userptr;
+		frame.y_off = 0;
+		/* frame.cbcr_off = (y_size + y_pad); */
+		frame.cbcr_off = (pb->bytesused + y_pad);
+		frame.fd = pb->reserved;
+
+		g_pmsm_v4l2_dev->drv->put_frame(g_pmsm_v4l2_dev->drv->sync,
+						&frame);
+	}
+
+	return 0;
+}
+
+static int msm_v4l2_streamon(struct file *f, void *pctx, enum v4l2_buf_type i)
+{
+	struct msm_ctrl_cmd *ctrlcmd;
+
+	ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+	if (!ctrlcmd) {
+		CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
+		return -ENOMEM;
+	}
+
+	ctrlcmd->type = MSM_V4L2_STREAM_ON;
+	ctrlcmd->timeout_ms = 10000;
+	ctrlcmd->length = 0;
+	ctrlcmd->value = NULL;
+
+	D("%s\n", __func__);
+
+	g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+
+	D("%s after drv->ctrl \n", __func__);
+
+	return 0;
+}
+
+static int msm_v4l2_streamoff(struct file *f, void *pctx, enum v4l2_buf_type i)
+{
+	struct msm_ctrl_cmd *ctrlcmd;
+
+	ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+	if (!ctrlcmd) {
+		CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
+		return -ENOMEM;
+	}
+
+	ctrlcmd->type = MSM_V4L2_STREAM_OFF;
+	ctrlcmd->timeout_ms = 10000;
+	ctrlcmd->length = 0;
+	ctrlcmd->value = NULL;
+
+	D("%s\n", __func__);
+
+	g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+
+	return 0;
+}
+
+static int msm_v4l2_enum_fmt_overlay(struct file *f,
+				     void *pctx, struct v4l2_fmtdesc *pfmtdesc)
+{
+	D("%s\n", __func__);
+	return 0;
+}
+
+static int msm_v4l2_enum_fmt_cap(struct file *f,
+				 void *pctx, struct v4l2_fmtdesc *pfmtdesc)
+{
+	D("%s\n", __func__);
+
+	switch (pfmtdesc->index) {
+	case 0:
+		pfmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		pfmtdesc->flags = 0;
+		strncpy(pfmtdesc->description, "YUV 4:2:0",
+			sizeof(pfmtdesc->description));
+		pfmtdesc->pixelformat = V4L2_PIX_FMT_YVU420;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_v4l2_g_fmt_cap(struct file *f,
+			      void *pctx, struct v4l2_format *pfmt)
+{
+	D("%s\n", __func__);
+	pfmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	pfmt->fmt.pix.width = MSM_V4L2_WIDTH;
+	pfmt->fmt.pix.height = MSM_V4L2_HEIGHT;
+	pfmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420;
+	pfmt->fmt.pix.field = V4L2_FIELD_ANY;
+	pfmt->fmt.pix.bytesperline = 0;
+	pfmt->fmt.pix.sizeimage = 0;
+	pfmt->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+	pfmt->fmt.pix.priv = 0;
+	return 0;
+}
+
+static int msm_v4l2_s_fmt_cap(struct file *f,
+			      void *pctx, struct v4l2_format *pfmt)
+{
+	struct msm_ctrl_cmd *ctrlcmd;
+
+	D("%s\n", __func__);
+
+	ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+	if (!ctrlcmd) {
+		CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
+		return -ENOMEM;
+	}
+
+	ctrlcmd->type = MSM_V4L2_VID_CAP_TYPE;
+	ctrlcmd->length = sizeof(struct v4l2_format);
+	ctrlcmd->value = pfmt;
+	ctrlcmd->timeout_ms = 10000;
+
+	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -1;
+
+#if 0
+	/* FIXEME */
+	if (pfmt->fmt.pix.pixelformat != V4L2_PIX_FMT_YVU420)
+		return -EINVAL;
+#endif
+
+	/* Ok, but check other params, too. */
+
+#if 0
+	memcpy(&g_pmsm_v4l2_dev->current_pix_format.fmt.pix, pfmt,
+	       sizeof(struct v4l2_format));
+#endif
+
+	g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+
+	return 0;
+}
+
+static int msm_v4l2_g_fmt_overlay(struct file *f,
+				  void *pctx, struct v4l2_format *pfmt)
+{
+	D("%s\n", __func__);
+	pfmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+	pfmt->fmt.pix.width = MSM_V4L2_WIDTH;
+	pfmt->fmt.pix.height = MSM_V4L2_HEIGHT;
+	pfmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420;
+	pfmt->fmt.pix.field = V4L2_FIELD_ANY;
+	pfmt->fmt.pix.bytesperline = 0;
+	pfmt->fmt.pix.sizeimage = 0;
+	pfmt->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+	pfmt->fmt.pix.priv = 0;
+	return 0;
+}
+
+static int msm_v4l2_s_fmt_overlay(struct file *f,
+				  void *pctx, struct v4l2_format *pfmt)
+{
+	D("%s\n", __func__);
+	return 0;
+}
+
+static int msm_v4l2_overlay(struct file *f, void *pctx, unsigned int i)
+{
+	D("%s\n", __func__);
+	return 0;
+}
+
+static int msm_v4l2_g_jpegcomp(struct file *f,
+			       void *pctx, struct v4l2_jpegcompression *pcomp)
+{
+	D("%s\n", __func__);
+	return 0;
+}
+
+static int msm_v4l2_s_jpegcomp(struct file *f,
+			       void *pctx, struct v4l2_jpegcompression *pcomp)
+{
+	D("%s\n", __func__);
+	return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+int msm_v4l2_read_proc(char *pbuf, char **start, off_t offset,
+		       int count, int *eof, void *data)
+{
+	int len = 0;
+	len += snprintf(pbuf, strlen("stats\n") + 1, "stats\n");
+
+	if (g_pmsm_v4l2_dev) {
+		len += snprintf(pbuf, strlen("mode: ") + 1, "mode: ");
+
+		if (g_pmsm_v4l2_dev->current_cap_format.type
+		    == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			len += snprintf(pbuf, strlen("capture\n") + 1,
+					"capture\n");
+		else
+			len += snprintf(pbuf, strlen("unknown\n") + 1,
+					"unknown\n");
+
+		len += snprintf(pbuf, 21, "resolution: %dx%d\n",
+				g_pmsm_v4l2_dev->current_cap_format.fmt.pix.
+				width,
+				g_pmsm_v4l2_dev->current_cap_format.fmt.pix.
+				height);
+
+		len += snprintf(pbuf,
+				strlen("pixel format: ") + 1, "pixel format: ");
+		if (g_pmsm_v4l2_dev->current_cap_format.fmt.pix.pixelformat
+		    == V4L2_PIX_FMT_YVU420)
+			len += snprintf(pbuf, strlen("yvu420\n") + 1,
+					"yvu420\n");
+		else
+			len += snprintf(pbuf, strlen("unknown\n") + 1,
+					"unknown\n");
+
+		len += snprintf(pbuf, strlen("colorspace: ") + 1,
+				"colorspace: ");
+		if (g_pmsm_v4l2_dev->current_cap_format.fmt.pix.colorspace
+		    == V4L2_COLORSPACE_JPEG)
+			len += snprintf(pbuf, strlen("jpeg\n") + 1, "jpeg\n");
+		else
+			len += snprintf(pbuf, strlen("unknown\n") + 1,
+					"unknown\n");
+	}
+
+	*eof = 1;
+	return len;
+}
+#endif
+
+static const struct v4l2_file_operations msm_v4l2_fops = {
+	.owner = THIS_MODULE,
+	.open = msm_v4l2_open,
+	.poll = msm_v4l2_poll,
+	.release = msm_v4l2_release,
+	.ioctl = msm_v4l2_ioctl,
+};
+
+static void msm_v4l2_dev_init(struct msm_v4l2_device *pmsm_v4l2_dev)
+{
+	pmsm_v4l2_dev->read_queue_lock =
+	    __SPIN_LOCK_UNLOCKED(pmsm_v4l2_dev->read_queue_lock);
+	INIT_LIST_HEAD(&pmsm_v4l2_dev->read_queue);
+}
+
+static int msm_v4l2_try_fmt_cap(struct file *file,
+				void *fh, struct v4l2_format *f)
+{
+	/* FIXME */
+	return 0;
+}
+
+static int mm_v4l2_try_fmt_type_private(struct file *file,
+					void *fh, struct v4l2_format *f)
+{
+	/* FIXME */
+	return 0;
+}
+
+/*
+ * should the following structure be used instead of the code in the function?
+ * static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
+ *     .vidioc_querycap = ....
+ * }
+ */
+static const struct v4l2_ioctl_ops msm_ioctl_ops = {
+	.vidioc_querycap = msm_v4l2_querycap,
+	.vidioc_s_std = msm_v4l2_s_std,
+
+	.vidioc_queryctrl = msm_v4l2_queryctrl,
+	.vidioc_g_ctrl = msm_v4l2_g_ctrl,
+	.vidioc_s_ctrl = msm_v4l2_s_ctrl,
+
+	.vidioc_reqbufs = msm_v4l2_reqbufs,
+	.vidioc_querybuf = msm_v4l2_querybuf,
+	.vidioc_qbuf = msm_v4l2_qbuf,
+	.vidioc_dqbuf = msm_v4l2_dqbuf,
+
+	.vidioc_streamon = msm_v4l2_streamon,
+	.vidioc_streamoff = msm_v4l2_streamoff,
+
+	.vidioc_enum_fmt_vid_overlay = msm_v4l2_enum_fmt_overlay,
+	.vidioc_enum_fmt_vid_cap = msm_v4l2_enum_fmt_cap,
+
+	.vidioc_try_fmt_vid_cap = msm_v4l2_try_fmt_cap,
+	.vidioc_try_fmt_type_private = mm_v4l2_try_fmt_type_private,
+
+	.vidioc_g_fmt_vid_cap = msm_v4l2_g_fmt_cap,
+	.vidioc_s_fmt_vid_cap = msm_v4l2_s_fmt_cap,
+	.vidioc_g_fmt_vid_overlay = msm_v4l2_g_fmt_overlay,
+	.vidioc_s_fmt_vid_overlay = msm_v4l2_s_fmt_overlay,
+	.vidioc_overlay = msm_v4l2_overlay,
+
+	.vidioc_g_jpegcomp = msm_v4l2_g_jpegcomp,
+	.vidioc_s_jpegcomp = msm_v4l2_s_jpegcomp,
+};
+
+static int msm_v4l2_video_dev_init(struct video_device *pvd)
+{
+	strncpy(pvd->name, MSM_APPS_ID_V4L2, sizeof(pvd->name));
+	pvd->fops = &msm_v4l2_fops;
+	pvd->release = msm_v4l2_release_dev;
+	pvd->minor = -1;
+	pvd->ioctl_ops = &msm_ioctl_ops;
+	return msm_v4l2_register(g_pmsm_v4l2_dev->drv);
+}
+
+static int __init msm_v4l2_init(void)
+{
+	int rc = -ENOMEM;
+	struct video_device *pvdev = NULL;
+	struct msm_v4l2_device *pmsm_v4l2_dev = NULL;
+	D("%s\n", __func__);
+
+	pvdev = video_device_alloc();
+	if (pvdev == NULL)
+		return rc;
+
+	pmsm_v4l2_dev = kzalloc(sizeof(struct msm_v4l2_device), GFP_KERNEL);
+	if (pmsm_v4l2_dev == NULL) {
+		video_device_release(pvdev);
+		return rc;
+	}
+
+	msm_v4l2_dev_init(pmsm_v4l2_dev);
+
+	g_pmsm_v4l2_dev = pmsm_v4l2_dev;
+	g_pmsm_v4l2_dev->pvdev = pvdev;
+
+	g_pmsm_v4l2_dev->drv =
+	    kzalloc(sizeof(struct msm_v4l2_driver), GFP_KERNEL);
+	if (!g_pmsm_v4l2_dev->drv) {
+		video_device_release(pvdev);
+		kfree(pmsm_v4l2_dev);
+		return rc;
+	}
+
+	rc = msm_v4l2_video_dev_init(pvdev);
+	if (rc < 0) {
+		video_device_release(pvdev);
+		kfree(g_pmsm_v4l2_dev->drv);
+		kfree(pmsm_v4l2_dev);
+		return rc;
+	}
+
+	if (video_register_device(pvdev,
+			VFL_TYPE_GRABBER, MSM_V4L2_DEVNUM_YUV)) {
+		D("failed to register device\n");
+		video_device_release(pvdev);
+		kfree(g_pmsm_v4l2_dev);
+		g_pmsm_v4l2_dev = NULL;
+		return -ENOENT;
+	}
+#ifdef CONFIG_PROC_FS
+	create_proc_read_entry(MSM_V4L2_PROC_NAME,
+			       0, NULL, msm_v4l2_read_proc, NULL);
+#endif
+
+	return 0;
+}
+
+static void __exit msm_v4l2_exit(void)
+{
+	struct video_device *pvdev = g_pmsm_v4l2_dev->pvdev;
+	D("%s\n", __func__);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry(MSM_V4L2_PROC_NAME, NULL);
+#endif
+	video_unregister_device(pvdev);
+	video_device_release(pvdev);
+
+	msm_v4l2_unregister(g_pmsm_v4l2_dev->drv);
+
+	kfree(g_pmsm_v4l2_dev->drv);
+	g_pmsm_v4l2_dev->drv = NULL;
+
+	kfree(g_pmsm_v4l2_dev);
+	g_pmsm_v4l2_dev = NULL;
+}
+
+module_init(msm_v4l2_init);
+module_exit(msm_v4l2_exit);
+
+MODULE_DESCRIPTION("MSM V4L2 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_vfe31.c b/drivers/media/video/msm/msm_vfe31.c
new file mode 100644
index 0000000..7160229
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe31.c
@@ -0,0 +1,2314 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <mach/irqs.h>
+#include "msm_vfe31.h"
+#include <mach/camera.h>
+#include <linux/io.h>
+
+#define CHECKED_COPY_FROM_USER(in) {					\
+	if (copy_from_user((in), (void __user *)cmd->value,		\
+			cmd->length)) {					\
+		rc = -EFAULT;						\
+		break;							\
+	}								\
+}
+
+#define vfe31_get_ch_ping_addr(chn) \
+	(vfe_io_r(VFE_AXI_OFFSET + 0x18 * (chn)))
+#define vfe31_get_ch_pong_addr(chn) \
+	(vfe_io_r(VFE_AXI_OFFSET + 0x18 * (chn) + 4))
+#define vfe31_get_ch_addr(ping_pong, chn) \
+	(((ping_pong) & (1 << (chn))) == 0 ? \
+	vfe31_get_ch_pong_addr(chn) : vfe31_get_ch_ping_addr(chn))
+
+#define vfe31_put_ch_ping_addr(chn, addr) \
+	(vfe_io_w((addr), VFE_AXI_OFFSET + 0x18 * (chn)))
+#define vfe31_put_ch_pong_addr(chn, addr) \
+	(vfe_io_w((addr), VFE_AXI_OFFSET + 0x18 * (chn) + 4))
+#define vfe31_put_ch_addr(ping_pong, chn, addr) \
+	(((ping_pong) & (1 << (chn))) == 0 ?   \
+	vfe31_put_ch_pong_addr((chn), (addr)) : \
+	vfe31_put_ch_ping_addr((chn), (addr)))
+
+static struct vfe31_ctrl_type *vfe31_ctrl;
+static void *vfe_syncdata;
+
+struct vfe31_isr_queue_cmd {
+	struct list_head list;
+	uint32_t                           vfeInterruptStatus0;
+	uint32_t                           vfeInterruptStatus1;
+	struct vfe_frame_asf_info          vfeAsfFrameInfo;
+	struct vfe_frame_bpc_info          vfeBpcFrameInfo;
+	struct vfe_msg_camif_status        vfeCamifStatusLocal;
+};
+
+static struct vfe31_cmd_type vfe31_cmd[] = {
+/* 0*/	{V31_DUMMY_0},
+		{V31_SET_CLK},
+		{V31_RESET},
+		{V31_START},
+		{V31_TEST_GEN_START},
+/* 5*/	{V31_OPERATION_CFG, V31_OPERATION_CFG_LEN},
+		{V31_AXI_OUT_CFG, V31_AXI_OUT_LEN, V31_AXI_OUT_OFF, 0xFF},
+		{V31_CAMIF_CFG, V31_CAMIF_LEN, V31_CAMIF_OFF, 0xFF},
+		{V31_AXI_INPUT_CFG},
+		{V31_BLACK_LEVEL_CFG, V31_BLACK_LEVEL_LEN, V31_BLACK_LEVEL_OFF,
+		0xFF},
+/*10*/  {V31_ROLL_OFF_CFG, V31_ROLL_OFF_CFG_LEN, V31_ROLL_OFF_CFG_OFF,
+		0xFF},
+		{V31_DEMUX_CFG, V31_DEMUX_LEN, V31_DEMUX_OFF, 0xFF},
+		{V31_DEMOSAIC_0_CFG, V31_DEMOSAIC_0_LEN, V31_DEMOSAIC_0_OFF,
+		0xFF},
+		{V31_DEMOSAIC_1_CFG, V31_DEMOSAIC_1_LEN, V31_DEMOSAIC_1_OFF,
+		0xFF},
+		{V31_DEMOSAIC_2_CFG, V31_DEMOSAIC_2_LEN, V31_DEMOSAIC_2_OFF,
+		0xFF},
+/*15*/	{V31_FOV_CFG, V31_FOV_LEN, V31_FOV_OFF, 0xFF},
+		{V31_MAIN_SCALER_CFG, V31_MAIN_SCALER_LEN, V31_MAIN_SCALER_OFF,
+		0xFF},
+		{V31_WB_CFG, V31_WB_LEN, V31_WB_OFF, 0xFF},
+		{V31_COLOR_COR_CFG, V31_COLOR_COR_LEN, V31_COLOR_COR_OFF, 0xFF},
+		{V31_RGB_G_CFG, V31_RGB_G_LEN, V31_RGB_G_OFF, 0xFF},
+/*20*/	{V31_LA_CFG, V31_LA_LEN, V31_LA_OFF, 0xFF },
+		{V31_CHROMA_EN_CFG, V31_CHROMA_EN_LEN, V31_CHROMA_EN_OFF, 0xFF},
+		{V31_CHROMA_SUP_CFG, V31_CHROMA_SUP_LEN, V31_CHROMA_SUP_OFF,
+		0xFF},
+		{V31_MCE_CFG, V31_MCE_LEN, V31_MCE_OFF, 0xFF},
+		{V31_SK_ENHAN_CFG},
+/*25*/	{V31_ASF_CFG, V31_ASF_LEN, V31_ASF_OFF, 0xFF},
+		{V31_S2Y_CFG, V31_S2Y_LEN, V31_S2Y_OFF, 0xFF},
+		{V31_S2CbCr_CFG, V31_S2CbCr_LEN, V31_S2CbCr_OFF, 0xFF},
+		{V31_CHROMA_SUBS_CFG, V31_CHROMA_SUBS_LEN, V31_CHROMA_SUBS_OFF,
+			0xFF},
+		{V31_OUT_CLAMP_CFG, V31_OUT_CLAMP_LEN, V31_OUT_CLAMP_OFF, 0xFF},
+/*30*/	{V31_FRAME_SKIP_CFG, V31_FRAME_SKIP_LEN, V31_FRAME_SKIP_OFF, 0xFF},
+		{V31_DUMMY_1},
+		{V31_DUMMY_2},
+		{V31_DUMMY_3},
+		{V31_UPDATE},
+/*35*/	{V31_BL_LVL_UPDATE, V31_BLACK_LEVEL_LEN, V31_BLACK_LEVEL_OFF,
+		0xFF},
+		{V31_DEMUX_UPDATE, V31_DEMUX_LEN, V31_DEMUX_OFF, 0xFF},
+		{V31_DEMOSAIC_1_UPDATE, V31_DEMOSAIC_1_LEN, V31_DEMOSAIC_1_OFF,
+		0xFF},
+		{V31_DEMOSAIC_2_UPDATE, V31_DEMOSAIC_2_LEN, V31_DEMOSAIC_2_OFF,
+		0xFF},
+		{V31_FOV_UPDATE, V31_FOV_LEN, V31_FOV_OFF, 0xFF},
+/*40*/	{V31_MAIN_SCALER_UPDATE, V31_MAIN_SCALER_LEN, V31_MAIN_SCALER_OFF,
+		0xFF},
+		{V31_WB_UPDATE, V31_WB_LEN, V31_WB_OFF, 0xFF},
+		{V31_COLOR_COR_UPDATE, V31_COLOR_COR_LEN, V31_COLOR_COR_OFF,
+		0xFF},
+		{V31_RGB_G_UPDATE, V31_RGB_G_LEN, V31_CHROMA_EN_OFF, 0xFF},
+		{V31_LA_UPDATE, V31_LA_LEN, V31_LA_OFF, 0xFF },
+/*45*/	{V31_CHROMA_EN_UPDATE, V31_CHROMA_EN_LEN, V31_CHROMA_EN_OFF, 0xFF},
+		{V31_CHROMA_SUP_UPDATE, V31_CHROMA_SUP_LEN, V31_CHROMA_SUP_OFF,
+		0xFF},
+		{V31_MCE_UPDATE, V31_MCE_LEN, V31_MCE_OFF, 0xFF},
+		{V31_SK_ENHAN_UPDATE},
+		{V31_S2CbCr_UPDATE, V31_S2CbCr_LEN, V31_S2CbCr_OFF, 0xFF},
+/*50*/	{V31_S2Y_UPDATE, V31_S2Y_LEN, V31_S2Y_OFF, 0xFF},
+		{V31_ASF_UPDATE, V31_ASF_UPDATE_LEN, V31_ASF_OFF, 0xFF},
+		{V31_FRAME_SKIP_UPDATE},
+		{V31_CAMIF_FRAME_UPDATE},
+		{V31_STATS_AF_UPDATE, V31_STATS_AF_LEN, V31_STATS_AF_OFF},
+/*55*/	{V31_STATS_AE_UPDATE, V31_STATS_AE_LEN, V31_STATS_AE_OFF},
+		{V31_STATS_AWB_UPDATE, V31_STATS_AWB_LEN, V31_STATS_AWB_OFF},
+		{V31_STATS_RS_UPDATE, V31_STATS_RS_LEN, V31_STATS_RS_OFF},
+		{V31_STATS_CS_UPDATE, V31_STATS_CS_LEN, V31_STATS_CS_OFF},
+		{V31_STATS_SKIN_UPDATE},
+/*60*/	{V31_STATS_IHIST_UPDATE, V31_STATS_IHIST_LEN, V31_STATS_IHIST_OFF},
+		{V31_DUMMY_4},
+		{V31_EPOCH1_ACK},
+		{V31_EPOCH2_ACK},
+		{V31_START_RECORDING},
+/*65*/	{V31_STOP_RECORDING},
+		{V31_DUMMY_5},
+		{V31_DUMMY_6},
+		{V31_CAPTURE, V31_CAPTURE_LEN, 0xFF},
+		{V31_DUMMY_7},
+/*70*/	{V31_STOP},
+		{V31_GET_HW_VERSION},
+		{V31_GET_FRAME_SKIP_COUNTS},
+		{V31_OUTPUT1_BUFFER_ENQ},
+		{V31_OUTPUT2_BUFFER_ENQ},
+/*75*/	{V31_OUTPUT3_BUFFER_ENQ},
+		{V31_JPEG_OUT_BUF_ENQ},
+		{V31_RAW_OUT_BUF_ENQ},
+		{V31_RAW_IN_BUF_ENQ},
+		{V31_STATS_AF_ENQ},
+/*80*/	{V31_STATS_AE_ENQ},
+		{V31_STATS_AWB_ENQ},
+		{V31_STATS_RS_ENQ},
+		{V31_STATS_CS_ENQ},
+		{V31_STATS_SKIN_ENQ},
+/*85*/	{V31_STATS_IHIST_ENQ},
+		{V31_DUMMY_8},
+		{V31_JPEG_ENC_CFG},
+		{V31_DUMMY_9},
+		{V31_STATS_AF_START, V31_STATS_AF_LEN, V31_STATS_AF_OFF},
+/*90*/	{V31_STATS_AF_STOP},
+		{V31_STATS_AE_START, V31_STATS_AE_LEN, V31_STATS_AE_OFF},
+		{V31_STATS_AE_STOP},
+		{V31_STATS_AWB_START, V31_STATS_AWB_LEN, V31_STATS_AWB_OFF},
+		{V31_STATS_AWB_STOP},
+/*95*/	{V31_STATS_RS_START, V31_STATS_RS_LEN, V31_STATS_RS_OFF},
+		{V31_STATS_RS_STOP},
+		{V31_STATS_CS_START, V31_STATS_CS_LEN, V31_STATS_CS_OFF},
+		{V31_STATS_CS_STOP},
+		{V31_STATS_SKIN_START, V31_STATS_IHIST_LEN,
+			V31_STATS_IHIST_OFF},
+/*100*/	{V31_STATS_SKIN_STOP},
+		{V31_STATS_IHIST_START},
+		{V31_STATS_IHIST_STOP},
+		{V31_DUMMY_10},
+		{V31_SYNC_TIMER_SETTING},
+/*105*/	{V31_ASYNC_TIMER_SETTING},
+};
+
+static void vfe_io_w(u32 data, unsigned long offset)
+{
+	writel(data, vfe31_ctrl->vfebase + offset);
+	wmb();
+}
+
+static u32 vfe_io_r(unsigned long offset)
+{
+	uint32_t data = readl(vfe31_ctrl->vfebase + offset);
+	rmb();
+	return data;
+}
+
+static void msm_io_memcpy(void __iomem *dest_addr,
+	void __iomem *src_addr, u32 len)
+{
+	int i;
+	u32 *d = (u32 *) dest_addr;
+	u32 *s = (u32 *) src_addr;
+	/* memcpy_toio does not work. Use writel for now */
+	for (i = 0; i < len / 4; i++) {
+		writel(*s++, d++);
+		wmb();
+	}
+}
+
+static void vfe_io_w_axi_out_chan(u32 data, int8_t chan)
+{
+	uint32_t temp;
+	vfe_io_w(data, V31_AXI_OUT_OFF + 20 + 24 * chan);
+	temp = vfe_io_r(V31_AXI_OUT_OFF + 20 + 24 * chan);
+}
+
+static void vfe_msg_get_phy_addr(struct msm_vfe_phy_info *pinfo,
+	struct vfe_message *data)
+{
+	pinfo->y_phy = data->_u.msgOut.yBuffer;
+	pinfo->cbcr_phy = data->_u.msgOut.cbcrBuffer;
+}
+
+static void vfe31_proc_ops(enum VFE31_MESSAGE_ID id, void *msg, size_t len)
+{
+	struct msm_vfe_resp *rp;
+	struct vfe_message *vfe_msg_data = NULL;
+
+	rp = vfe31_ctrl->resp->vfe_alloc(sizeof(struct msm_vfe_resp),
+		vfe31_ctrl->syncdata, GFP_ATOMIC);
+	if (!rp) {
+		pr_err("rp: cannot allocate buffer\n");
+		return;
+	}
+	CDBG("vfe31_proc_ops, msgId = %d\n", id);
+	rp->evt_msg.type   = MSM_CAMERA_MSG;
+	rp->evt_msg.msg_id = id;
+	rp->evt_msg.len    = len;
+	rp->evt_msg.data   = msg;
+	vfe_msg_data = (struct vfe_message *)rp->evt_msg.data;
+
+	switch (rp->evt_msg.msg_id) {
+	case MSG_ID_SNAPSHOT_DONE:
+		rp->type = VFE_MSG_SNAPSHOT;
+		break;
+
+	case MSG_ID_OUTPUT_P:
+		rp->type = VFE_MSG_OUTPUT_P;
+		rp->phy.output_id = OUTPUT_TYPE_P;
+		vfe_msg_get_phy_addr(&rp->phy, vfe_msg_data);
+		break;
+
+	case MSG_ID_OUTPUT_T:
+		rp->type = VFE_MSG_OUTPUT_T;
+		rp->phy.output_id = OUTPUT_TYPE_T;
+		vfe_msg_get_phy_addr(&rp->phy, vfe_msg_data);
+		break;
+
+	case MSG_ID_OUTPUT_S:
+		rp->type = VFE_MSG_OUTPUT_S;
+		rp->phy.output_id = OUTPUT_TYPE_S;
+		vfe_msg_get_phy_addr(&rp->phy, vfe_msg_data);
+		break;
+
+	case MSG_ID_OUTPUT_V:
+		rp->type = VFE_MSG_OUTPUT_V;
+		rp->phy.output_id = OUTPUT_TYPE_V;
+		vfe_msg_get_phy_addr(&rp->phy, vfe_msg_data);
+		break;
+
+	case MSG_ID_STATS_AF:
+		rp->type = VFE_MSG_STATS_AF;
+		rp->phy.sbuf_phy = vfe_msg_data->_u.msgStats.buffer;
+		break;
+
+	case MSG_ID_STATS_AWB:
+		rp->type = VFE_MSG_STATS_AWB;
+		rp->phy.sbuf_phy = vfe_msg_data->_u.msgStats.buffer;
+		break;
+
+	case MSG_ID_STATS_AEC:
+		rp->type = VFE_MSG_STATS_AEC;
+		rp->phy.sbuf_phy = vfe_msg_data->_u.msgStats.buffer;
+		break;
+
+	default:
+		rp->type = VFE_MSG_GENERAL;
+		break;
+	}
+	vfe31_ctrl->resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe31_ctrl->syncdata,
+		GFP_ATOMIC);
+}
+
+static void vfe_send_outmsg(uint8_t msgid, uint32_t pyaddr, uint32_t pcbcraddr)
+{
+	struct vfe_message msg;
+	msg._d = msgid;
+	msg._u.msgOut.yBuffer     = pyaddr;
+	msg._u.msgOut.cbcrBuffer  = pcbcraddr;
+	vfe31_proc_ops(msgid, &msg, sizeof(struct vfe_message));
+}
+
+static int vfe31_enable(struct camera_enable_cmd *enable)
+{
+	return 0;
+}
+
+void vfe_stop(void)
+{
+	uint8_t axiBusyFlag = true;
+	unsigned long flags;
+
+	/* for reset hw modules, and send msg when reset_irq comes. */
+	spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+	vfe31_ctrl->stop_ack_pending = TRUE;
+	spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+
+	/* disable all interrupts.  */
+	vfe_io_w(VFE_DISABLE_ALL_IRQS, VFE_IRQ_MASK_0);
+	vfe_io_w(VFE_DISABLE_ALL_IRQS, VFE_IRQ_MASK_1);
+
+	/* clear all pending interrupts*/
+	vfe_io_w(VFE_CLEAR_ALL_IRQS, VFE_IRQ_CLEAR_0);
+	vfe_io_w(VFE_CLEAR_ALL_IRQS, VFE_IRQ_CLEAR_1);
+	vfe_io_w(1, VFE_IRQ_CMD);
+
+	/* in either continuous or snapshot mode, stop command can be issued
+	 * at any time. stop camif immediately. */
+	vfe_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY, VFE_CAMIF_COMMAND);
+
+	/* axi halt command. */
+	vfe_io_w(AXI_HALT, VFE_AXI_CMD);
+
+	while (axiBusyFlag) {
+		if (vfe_io_r(VFE_AXI_STATUS) & 0x1) {
+			axiBusyFlag = false;
+		}
+	}
+	vfe_io_w(AXI_HALT_CLEAR, VFE_AXI_CMD);
+
+	/* after axi halt, then ok to apply global reset. */
+	/* enable reset_ack and async timer interrupt only while
+	stopping the pipeline.*/
+	vfe_io_w(0xf0000000, VFE_IRQ_MASK_0);
+	vfe_io_w(VFE_IMASK_WHILE_STOPPING_1, VFE_IRQ_MASK_1);
+	vfe_io_w(VFE_RESET_UPON_STOP_CMD, VFE_GLOBAL_RESET);
+}
+
+static int vfe31_disable(struct camera_enable_cmd *enable,
+	struct platform_device *dev)
+{
+	vfe_stop();
+	msm_camio_disable(dev);
+	return 0;
+}
+
+static void vfe31_release(struct platform_device *pdev)
+{
+	struct msm_sensor_ctrl *sctrl =
+		&((struct msm_sync *)vfe_syncdata)->sctrl;
+	struct resource *vfemem, *vfeio;
+
+	if (sctrl)
+		sctrl->s_release();
+
+	vfemem = vfe31_ctrl->vfemem;
+	vfeio  = vfe31_ctrl->vfeio;
+
+	kfree(vfe31_ctrl->extdata);
+	free_irq(vfe31_ctrl->vfeirq, 0);
+	iounmap(vfe31_ctrl->vfebase);
+	kfree(vfe31_ctrl);
+	vfe31_ctrl = NULL;
+	release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	msm_camio_disable(pdev);
+	vfe_syncdata = NULL;
+}
+
+static int vfe31_config_axi(int mode, struct axidata *ad, uint32_t *ao)
+{
+	int i;
+	uint32_t *p, *p1, *p2;
+	struct vfe31_output_ch *outp1 = NULL, *outp2 = NULL;
+	struct msm_pmem_region *regp1 = NULL, *regp2 = NULL;
+
+	p = ao + 2;
+
+	CDBG("vfe31_config_axi: mode = %d, bufnum1 = %d, bufnum2 = %d\n",
+		mode, ad->bufnum1, ad->bufnum2);
+
+	switch (mode) {
+	case OUTPUT_2:
+		if (ad->bufnum2 != 3)
+			return -EINVAL;
+		*p = 0x200;    /* preview with wm0 & wm1 */
+
+		vfe31_ctrl->outpath.out0.ch0 = 0; /* luma   */
+		vfe31_ctrl->outpath.out0.ch1 = 1; /* chroma */
+		regp1 = &(ad->region[ad->bufnum1]);
+		outp1 = &(vfe31_ctrl->outpath.out0);
+		vfe31_ctrl->outpath.output_mode |= VFE31_OUTPUT_MODE_PT;
+
+		for (i = 0; i < 2; i++) {
+			p1 = ao + 6 + i;    /* wm0 for y  */
+			*p1 = (regp1->paddr + regp1->info.y_off);
+
+			p1 = ao + 12 + i;  /* wm1 for cbcr */
+			*p1 = (regp1->paddr + regp1->info.cbcr_off);
+			regp1++;
+		}
+		outp1->free_buf.available = 1;
+		outp1->free_buf.paddr = regp1->paddr;
+		outp1->free_buf.y_off = regp1->info.y_off;
+		outp1->free_buf.cbcr_off = regp1->info.cbcr_off;
+
+		CDBG("vfe31_config_axi: free_buf paddr = 0x%x, y_off = %d,"
+			" cbcr_off = %d\n",
+			outp1->free_buf.paddr, outp1->free_buf.y_off,
+			outp1->free_buf.cbcr_off);
+		break;
+
+	case OUTPUT_1_AND_2:
+		/* use wm0& 4 for thumbnail, wm1&5 for main image.*/
+		if ((ad->bufnum1 < 1) || (ad->bufnum2 < 1))
+			return -EINVAL;
+		/* at least one frame for snapshot.  */
+		*p++ = 0x1;    /* xbar cfg0 */
+		*p = 0x203;    /* xbar cfg1 */
+		vfe31_ctrl->outpath.out0.ch0 = 0; /* thumbnail luma   */
+		vfe31_ctrl->outpath.out0.ch1 = 4; /* thumbnail chroma */
+		vfe31_ctrl->outpath.out1.ch0 = 1; /* main image luma   */
+		vfe31_ctrl->outpath.out1.ch1 = 5; /* main image chroma */
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_S;  /* main image.*/
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_PT;  /* thumbnail. */
+
+		regp1 = &(ad->region[0]); /* this is thumbnail buffer. */
+		/* this is main image buffer. */
+		regp2 = &(ad->region[ad->bufnum1]);
+		outp1 = &(vfe31_ctrl->outpath.out0);
+		outp2 = &(vfe31_ctrl->outpath.out1); /* snapshot */
+
+		p1 = ao + 6;   /* wm0 ping */
+		*p1++ = (regp1->paddr + regp1->info.y_off);
+		/* this is to duplicate ping address to pong.*/
+		*p1 = (regp1->paddr + regp1->info.y_off);
+		p1 = ao + 30;  /* wm4 ping */
+		*p1++ = (regp1->paddr + regp1->info.cbcr_off);
+		/* this is to duplicate ping address to pong.*/
+		*p1 = (regp1->paddr + regp1->info.cbcr_off);
+		p1 = ao + 12;   /* wm1 ping */
+		*p1++ = (regp2->paddr + regp2->info.y_off);
+		/* pong = ping,*/
+		*p1 = (regp2->paddr + regp2->info.y_off);
+		p1 = ao + 36;  /* wm5 */
+		*p1++ = (regp2->paddr + regp2->info.cbcr_off);
+		*p1 = (regp2->paddr + regp2->info.cbcr_off);
+		break;
+
+	case OUTPUT_1_AND_3:
+		/* use wm0& 4 for preview, wm1&5 for video.*/
+		if ((ad->bufnum1 < 2) || (ad->bufnum2 < 2))
+			return -EINVAL;
+		*p++ = 0x1;    /* xbar cfg0 */
+		*p = 0x1a03;    /* xbar cfg1 */
+		vfe31_ctrl->outpath.out0.ch0 = 0; /* preview luma   */
+		vfe31_ctrl->outpath.out0.ch1 = 4; /* preview chroma */
+		vfe31_ctrl->outpath.out2.ch0 = 1; /* video luma     */
+		vfe31_ctrl->outpath.out2.ch1 = 5; /* video chroma   */
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_V;  /* video*/
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_PT;  /* preview */
+
+		regp1 = &(ad->region[0]); /* this is preview buffer. */
+		regp2 = &(ad->region[ad->bufnum1]);/* this is video buffer. */
+		outp1 = &(vfe31_ctrl->outpath.out0); /* preview */
+		outp2 = &(vfe31_ctrl->outpath.out2); /* video */
+
+
+		for (i = 0; i < 2; i++) {
+			p1 = ao + 6 + i;    /* wm0 for y  */
+			*p1 = (regp1->paddr + regp1->info.y_off);
+
+			p1 = ao + 30 + i;  /* wm1 for cbcr */
+			*p1 = (regp1->paddr + regp1->info.cbcr_off);
+			regp1++;
+		}
+
+		for (i = 0; i < 2; i++) {
+			p2 = ao + 12 + i;    /* wm0 for y  */
+			*p2 = (regp2->paddr + regp2->info.y_off);
+
+			p2 = ao + 36 + i;  /* wm1 for cbcr */
+			*p2 = (regp2->paddr + regp2->info.cbcr_off);
+			regp2++;
+		}
+		outp1->free_buf.available = 1;
+		outp1->free_buf.paddr = regp1->paddr;
+		outp1->free_buf.y_off = regp1->info.y_off;
+		outp1->free_buf.cbcr_off = regp1->info.cbcr_off;
+
+		outp2->free_buf.available = 1;
+		outp2->free_buf.paddr = regp2->paddr;
+		outp2->free_buf.y_off = regp2->info.y_off;
+		outp2->free_buf.cbcr_off = regp2->info.cbcr_off;
+		CDBG("vfe31_config_axi: preview free_buf"
+			"paddr = 0x%x, y_off = %d, cbcr_off = %d\n",
+			outp1->free_buf.paddr, outp1->free_buf.y_off,
+			outp1->free_buf.cbcr_off);
+		CDBG("vfe31_config_axi: video free_buf"
+			"paddr = 0x%x,y_off = %d, cbcr_off = %d\n",
+			outp2->free_buf.paddr, outp2->free_buf.y_off,
+			outp2->free_buf.cbcr_off);
+		break;
+
+	case CAMIF_TO_AXI_VIA_OUTPUT_2:  /* use wm0 only */
+		if (ad->bufnum2 < 1)
+			return -EINVAL;
+		CDBG("config axi for raw snapshot.\n");
+		*p = 0x60;    /* raw snapshot with wm0 */
+		vfe31_ctrl->outpath.out1.ch0 = 0; /* raw */
+		regp1 = &(ad->region[ad->bufnum1]);
+		vfe31_ctrl->outpath.output_mode |= VFE31_OUTPUT_MODE_S;
+		p1 = ao + 6;    /* wm0 for y  */
+		*p1 = (regp1->paddr + regp1->info.y_off);
+		break;
+
+	default:
+		break;
+	}
+	msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[V31_AXI_OUT_CFG].offset,
+		ao, vfe31_cmd[V31_AXI_OUT_CFG].length);
+	return 0;
+}
+
+static void vfe31_reset_internal_variables(void)
+{
+	unsigned long flags;
+
+	vfe31_ctrl->vfeImaskCompositePacked = 0;
+	/* state control variables */
+	vfe31_ctrl->start_ack_pending = FALSE;
+
+	spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+	vfe31_ctrl->stop_ack_pending = FALSE;
+	spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+
+	vfe31_ctrl->reset_ack_pending = FALSE;
+
+	spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+	vfe31_ctrl->update_ack_pending = FALSE;
+	spin_unlock_irqrestore(&vfe31_ctrl->update_ack_lock, flags);
+
+	vfe31_ctrl->req_stop_video_rec = FALSE;
+	vfe31_ctrl->req_start_video_rec = FALSE;
+
+	spin_lock_irqsave(&vfe31_ctrl->state_lock, flags);
+	vfe31_ctrl->vstate = VFE_STATE_IDLE;
+	spin_unlock_irqrestore(&vfe31_ctrl->state_lock, flags);
+
+	/* 0 for continuous mode, 1 for snapshot mode */
+	vfe31_ctrl->operation_mode = 0;
+	vfe31_ctrl->outpath.output_mode = 0;
+	vfe31_ctrl->vfe_capture_count = 0;
+
+	/* this is unsigned 32 bit integer. */
+	vfe31_ctrl->vfeFrameId = 0;
+	vfe31_ctrl->output1Pattern = 0xffffffff;
+	vfe31_ctrl->output1Period  = 31;
+	vfe31_ctrl->output2Pattern = 0xffffffff;
+	vfe31_ctrl->output2Period  = 31;
+	vfe31_ctrl->vfeFrameSkipCount   = 0;
+	vfe31_ctrl->vfeFrameSkipPeriod  = 31;
+
+	/* Stats control variables. */
+	memset(&vfe31_ctrl->afStatsControl, 0,
+		sizeof(struct vfe_stats_control));
+	memset(&vfe31_ctrl->awbStatsControl, 0,
+		sizeof(struct vfe_stats_control));
+	memset(&vfe31_ctrl->aecStatsControl, 0,
+		sizeof(struct vfe_stats_control));
+	memset(&vfe31_ctrl->ihistStatsControl, 0,
+		sizeof(struct vfe_stats_control));
+	memset(&vfe31_ctrl->rsStatsControl, 0,
+		sizeof(struct vfe_stats_control));
+	memset(&vfe31_ctrl->csStatsControl, 0,
+		sizeof(struct vfe_stats_control));
+}
+
+static void vfe31_reset(void)
+{
+	uint32_t vfe_version;
+
+	vfe31_reset_internal_variables();
+	vfe_version = vfe_io_r(VFE_VERSION);
+	CDBG("vfe_version = 0x%x\n", vfe_version);
+	/* disable all interrupts.  vfeImaskLocal is also reset to 0
+	* to begin with. */
+	vfe_io_w(VFE_DISABLE_ALL_IRQS, VFE_IRQ_MASK_0);
+	vfe_io_w(VFE_DISABLE_ALL_IRQS, VFE_IRQ_MASK_1);
+
+	/* clear all pending interrupts*/
+	vfe_io_w(VFE_CLEAR_ALL_IRQS, VFE_IRQ_CLEAR_0);
+	vfe_io_w(VFE_CLEAR_ALL_IRQS, VFE_IRQ_CLEAR_1);
+	vfe_io_w(1, VFE_IRQ_CMD);
+
+	/* enable reset_ack interrupt.  */
+	vfe_io_w(VFE_IMASK_WHILE_STOPPING_1, VFE_IRQ_MASK_1);
+
+	/* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
+	 * is done, hardware interrupt will be generated.  VFE ist processes
+	 * the interrupt to complete the function call.  Note that the reset
+	 * function is synchronous. */
+	vfe_io_w(VFE_RESET_UPON_RESET_CMD, VFE_GLOBAL_RESET);
+}
+
+static int vfe31_operation_config(uint32_t *cmd)
+{
+	uint32_t *p = cmd;
+
+	vfe31_ctrl->operation_mode = *p;
+	vfe31_ctrl->stats_comp = *(++p);
+
+	vfe_io_w(*(++p), VFE_CFG_OFF);
+	vfe_io_w(*(++p), VFE_MODULE_CFG);
+	vfe_io_w(*(++p), VFE_REALIGN_BUF);
+	vfe_io_w(*(++p), VFE_CHROMA_UP);
+	vfe_io_w(*(++p), VFE_STATS_CFG);
+	return 0;
+}
+
+static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	vfe_io_w(addr, VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	addr = ptr[1];
+	vfe_io_w(addr, VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+	vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	vfe_io_w(addr, VFE_BUS_STATS_AEC_WR_PING_ADDR);
+	addr = ptr[1];
+	vfe_io_w(addr, VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+	vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	vfe_io_w(addr, VFE_BUS_STATS_AF_WR_PING_ADDR);
+	addr = ptr[1];
+	vfe_io_w(addr, VFE_BUS_STATS_AF_WR_PONG_ADDR);
+	vfe31_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	vfe_io_w(addr, VFE_BUS_STATS_HIST_WR_PING_ADDR);
+	addr = ptr[1];
+	vfe_io_w(addr, VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+	vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	vfe_io_w(addr, VFE_BUS_STATS_RS_WR_PING_ADDR);
+	addr = ptr[1];
+	vfe_io_w(addr, VFE_BUS_STATS_RS_WR_PONG_ADDR);
+	vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	vfe_io_w(addr, VFE_BUS_STATS_CS_WR_PING_ADDR);
+	addr = ptr[1];
+	vfe_io_w(addr, VFE_BUS_STATS_CS_WR_PONG_ADDR);
+	vfe31_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static void vfe31_start_common(void)
+{
+	unsigned long flags;
+
+	vfe31_ctrl->start_ack_pending = TRUE;
+	CDBG("VFE opertaion mode = 0x%x.\n", vfe31_ctrl->operation_mode);
+	CDBG("VFE output path out mode = 0x%x.\n",
+		vfe31_ctrl->outpath.output_mode);
+	vfe_io_w(0x00EFE021, VFE_IRQ_MASK_0);
+	vfe_io_w(VFE_IMASK_WHILE_STOPPING_1, VFE_IRQ_MASK_1);
+
+	vfe_io_w(1, VFE_REG_UPDATE_CMD);
+	vfe_io_w(1, VFE_CAMIF_COMMAND);
+
+	spin_lock_irqsave(&vfe31_ctrl->state_lock, flags);
+	vfe31_ctrl->vstate = VFE_STATE_ACTIVE;
+	spin_unlock_irqrestore(&vfe31_ctrl->state_lock, flags);
+}
+
+static int vfe31_start_recording(void)
+{
+	vfe31_ctrl->req_start_video_rec = TRUE;
+	return 0;
+}
+
+static int vfe31_stop_recording(void)
+{
+	vfe31_ctrl->req_stop_video_rec = TRUE;
+	return 0;
+}
+
+static int vfe31_capture(uint32_t num_frames_capture)
+{
+	uint32_t irq_comp_mask = 0;
+
+	/* capture command is valid for both idle and active state. */
+	vfe31_ctrl->outpath.out1.capture_cnt = num_frames_capture;
+	if (vfe31_ctrl->operation_mode == 1) {
+		vfe31_ctrl->outpath.out0.capture_cnt = num_frames_capture;
+	}
+	vfe31_ctrl->vfe_capture_count = num_frames_capture;
+	irq_comp_mask = vfe_io_r(VFE_IRQ_COMP_MASK);
+
+	if (vfe31_ctrl->operation_mode == 1) {
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) {
+			irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+					0x1 << vfe31_ctrl->outpath.out0.ch1);
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) {
+			irq_comp_mask |=
+				(0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8) |
+				0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8));
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) {
+			vfe_io_w_axi_out_chan(1, vfe31_ctrl->outpath.out0.ch0);
+			vfe_io_w_axi_out_chan(1, vfe31_ctrl->outpath.out0.ch1);
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) {
+			vfe_io_w_axi_out_chan(1, vfe31_ctrl->outpath.out1.ch0);
+			vfe_io_w_axi_out_chan(1, vfe31_ctrl->outpath.out1.ch1);
+		}
+	} else {  /* this is raw snapshot mode. */
+		CDBG("config the comp imask for raw snapshot mode.\n");
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) {
+			irq_comp_mask |=
+				(0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8));
+			vfe_io_w_axi_out_chan(1, vfe31_ctrl->outpath.out1.ch0);
+		}
+	}
+	vfe_io_w(irq_comp_mask, VFE_IRQ_COMP_MASK);
+	vfe_io_r(VFE_IRQ_COMP_MASK);
+	vfe31_start_common();
+	vfe_io_r(VFE_IRQ_COMP_MASK);
+	/* for debug */
+	vfe_io_w(1, 0x18C);
+	vfe_io_w(1, 0x188);
+	return 0;
+}
+
+static int vfe31_start(void)
+{
+	uint32_t irq_comp_mask = 0;
+
+	/* start command now is only good for continuous mode. */
+	if (vfe31_ctrl->operation_mode & 1)
+		return 0;
+	irq_comp_mask = vfe_io_r(VFE_IRQ_COMP_MASK);
+
+	if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) {
+		irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+			0x1 << vfe31_ctrl->outpath.out0.ch1);
+	}
+
+	if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_V) {
+		irq_comp_mask |= (0x1 << (vfe31_ctrl->outpath.out2.ch0 + 16) |
+			0x1 << (vfe31_ctrl->outpath.out2.ch1 + 16));
+	}
+
+	vfe_io_w(irq_comp_mask, VFE_IRQ_COMP_MASK);
+
+	if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) {
+		vfe_io_w_axi_out_chan(1, vfe31_ctrl->outpath.out0.ch0);
+		vfe_io_w_axi_out_chan(1, vfe31_ctrl->outpath.out0.ch1);
+	}
+	vfe31_start_common();
+	return 0;
+}
+
+static void vfe31_update(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+	vfe31_ctrl->update_ack_pending = TRUE;
+	spin_unlock_irqrestore(&vfe31_ctrl->update_ack_lock, flags);
+	vfe_io_w(1, VFE_REG_UPDATE_CMD);
+}
+
+void vfe31_program_dmi_cfg(enum VFE31_DMI_RAM_SEL bankSel)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = VFE_DMI_CFG_DEFAULT;
+	value += (uint32_t)bankSel;
+
+	vfe_io_w(value, VFE_DMI_CFG);
+	/* by default, always starts with offset 0. */
+	vfe_io_w(0, VFE_DMI_ADDR);
+}
+
+void vfe31_write_gamma_cfg(enum VFE31_DMI_RAM_SEL channel_sel,
+						const uint32_t *tbl)
+{
+	int i;
+	uint32_t value, value1, value2;
+
+	vfe31_program_dmi_cfg(channel_sel);
+	/* for loop for extracting init table. */
+	for (i = 0 ; i < (VFE31_GAMMA_NUM_ENTRIES/2) ; i++) {
+		value = *tbl++;
+		value1 = value & 0x0000FFFF;
+		value2 = (value & 0xFFFF0000)>>16;
+		vfe_io_w(value1, VFE_DMI_DATA_LO);
+		vfe_io_w(value2, VFE_DMI_DATA_LO);
+	}
+	vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static int vfe31_proc_general(struct msm_vfe31_cmd *cmd)
+{
+	int i, rc = 0;
+	uint32_t old_val = 0, new_val = 0;
+	uint32_t *cmdp = NULL;
+	uint32_t *cmdp_local = NULL;
+
+	CDBG("vfe31_proc_general: cmdID = %d, length = %d\n",
+		cmd->id, cmd->length);
+	switch (cmd->id) {
+	case V31_RESET:
+		vfe31_reset();
+		break;
+	case V31_START:
+		rc = vfe31_start();
+		break;
+	case V31_UPDATE:
+		vfe31_update();
+		break;
+	case V31_CAPTURE:
+		rc = vfe31_capture(1);
+		break;
+	case V31_START_RECORDING:
+		rc = vfe31_start_recording();
+		break;
+	case V31_STOP_RECORDING:
+		rc = vfe31_stop_recording();
+		break;
+	case V31_OPERATION_CFG:
+		if (cmd->length != V31_OPERATION_CFG_LEN) {
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(V31_OPERATION_CFG_LEN, GFP_KERNEL);
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				V31_OPERATION_CFG_LEN)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe31_operation_config(cmdp);
+		break;
+
+	case V31_STATS_AE_START:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val |= AE_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, vfe31_cmd[cmd->id].length);
+		break;
+
+	case V31_STATS_AF_START:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val |= AF_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, vfe31_cmd[cmd->id].length);
+		break;
+
+	case V31_STATS_AWB_START:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val |= AWB_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, vfe31_cmd[cmd->id].length);
+		break;
+
+	case V31_STATS_IHIST_START:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val |= IHIST_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, vfe31_cmd[cmd->id].length);
+		break;
+
+
+	case V31_STATS_RS_START:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val |= RS_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, vfe31_cmd[cmd->id].length);
+		break;
+
+	case V31_STATS_CS_START:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val |= CS_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, vfe31_cmd[cmd->id].length);
+		break;
+
+	case V31_MCE_UPDATE:
+	case V31_MCE_CFG:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		/* Incrementing with 4 so as to point to the 2nd Register as
+		the 2nd register has the mce_enable bit */
+		old_val = vfe_io_r(V31_CHROMA_EN_OFF + 4);
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+		old_val &= MCE_EN_MASK;
+		new_val = new_val | old_val;
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_EN_OFF + 4,
+			      &new_val, 4);
+		cmdp_local += 1;
+
+		old_val = vfe_io_r(V31_CHROMA_EN_OFF + 8);
+		new_val = *cmdp_local;
+		old_val &= MCE_Q_K_MASK;
+		new_val = new_val | old_val;
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_EN_OFF + 8,
+			      &new_val, 4);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp_local, vfe31_cmd[cmd->id].length);
+		break;
+
+	case V31_DEMOSAIC_2_UPDATE: /* 38 BPC update   */
+	case V31_DEMOSAIC_2_CFG:  /* 14 BPC config   */
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = vfe_io_r(V31_DEMOSAIC_0_OFF);
+		old_val &= BPC_MASK;
+
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAIC_0_OFF,
+			      cmdp_local, 4);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp_local, vfe31_cmd[cmd->id].length);
+		break;
+
+	case V31_DEMOSAIC_1_UPDATE:/* 37 ABF update  */
+	case V31_DEMOSAIC_1_CFG: /* 13 ABF config  */
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = vfe_io_r(V31_DEMOSAIC_0_OFF);
+		old_val &= ABF_MASK;
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAIC_0_OFF,
+			      cmdp_local, 4);
+
+		cmdp_local += 1;
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp_local, vfe31_cmd[cmd->id].length);
+		break;
+
+	case V31_ROLL_OFF_CFG:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp_local, 16);
+		cmdp_local += 4;
+		vfe31_program_dmi_cfg(ROLLOFF_RAM);
+		/* for loop for extrcting init table. */
+		for (i = 0 ; i < (VFE31_ROLL_OFF_INIT_TABLE_SIZE * 2) ; i++) {
+			vfe_io_w(*cmdp_local, VFE_DMI_DATA_LO);
+			cmdp_local++;
+		}
+		CDBG("done writing init table\n");
+		/* by default, always starts with offset 0. */
+		vfe_io_w(LENS_ROLL_OFF_DELTA_TABLE_OFFSET, VFE_DMI_ADDR);
+		/* for loop for extracting delta table. */
+		for (i = 0 ; i < (VFE31_ROLL_OFF_DELTA_TABLE_SIZE * 2) ; i++) {
+			vfe_io_w(*cmdp_local, VFE_DMI_DATA_LO);
+			cmdp_local++;
+		}
+		vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+		break;
+
+	case V31_LA_CFG:
+	case V31_LA_UPDATE:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, vfe31_cmd[cmd->id].length);
+
+		/* If the value is 0x00 then write in to LUT bank0
+		if the value is 0x01 then write in to LUT bank1 */
+		if (*cmdp == 0x0)
+			vfe31_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK0);
+		else
+			vfe31_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK1);
+		cmdp += 1;
+		/* for loop for extracting init table. */
+		for (i = 0 ; i < VFE31_LA_TABLE_LENGTH ; i++) {
+			vfe_io_w(*cmdp, VFE_DMI_DATA_LO);
+			cmdp++;
+		}
+		vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+		cmdp -= 1;
+		break;
+
+	case V31_RGB_G_CFG:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_RGB_G_OFF, cmdp, 4);
+		cmdp += 1;
+		vfe31_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0 , cmdp);
+		vfe31_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0 , cmdp);
+		vfe31_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0 , cmdp);
+		cmdp -= 1;
+		break;
+
+	case V31_RGB_G_UPDATE:
+		cmdp = kmalloc(cmd->length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_RGB_G_OFF, cmdp, 4);
+		old_val = *cmdp;
+		cmdp += 1;
+
+		if (old_val) {
+			vfe31_write_gamma_cfg(RGBLUT_RAM_CH0_BANK1, cmdp);
+			vfe31_write_gamma_cfg(RGBLUT_RAM_CH1_BANK1, cmdp);
+			vfe31_write_gamma_cfg(RGBLUT_RAM_CH2_BANK1, cmdp);
+		} else {
+			vfe31_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp);
+			vfe31_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp);
+			vfe31_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp);
+		}
+		cmdp -= 1;
+		break;
+
+	case V31_STATS_AWB_STOP:
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val &= ~AWB_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		break;
+
+	case V31_STATS_AE_STOP:
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val &= ~AE_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		break;
+
+	case V31_STATS_AF_STOP:
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val &= ~AF_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		break;
+
+	case V31_STATS_IHIST_STOP:
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val &= ~IHIST_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		break;
+
+	case V31_STATS_RS_STOP:
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val &= ~RS_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		break;
+
+	case V31_STATS_CS_STOP:
+		old_val = vfe_io_r(VFE_MODULE_CFG);
+		old_val &= ~CS_ENABLE_MASK;
+		vfe_io_w(old_val, VFE_MODULE_CFG);
+		break;
+
+	case V31_STOP:
+		vfe_stop();
+		break;
+
+	default:
+		if (cmd->length != vfe31_cmd[cmd->id].length)
+			return -EINVAL;
+
+		cmdp = kmalloc(vfe31_cmd[cmd->id].length, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+
+		CHECKED_COPY_FROM_USER(cmdp);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, vfe31_cmd[cmd->id].length);
+		break;
+	}
+
+proc_general_done:
+	kfree(cmdp);
+
+	return rc;
+}
+
+static void vfe31_stats_af_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
+	vfe31_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->afStatsControl.ackPending = FALSE;
+	spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+}
+
+static void vfe31_stats_awb_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
+	vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->awbStatsControl.ackPending = FALSE;
+	spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+}
+
+static void vfe31_stats_aec_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
+	vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->aecStatsControl.ackPending = FALSE;
+	spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+}
+
+static void vfe31_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe31_ctrl->ihist_ack_lock, flags);
+	vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->ihistStatsControl.ackPending = FALSE;
+	spin_unlock_irqrestore(&vfe31_ctrl->ihist_ack_lock, flags);
+}
+
+static void vfe31_stats_rs_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe31_ctrl->rs_ack_lock, flags);
+	vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->rsStatsControl.ackPending = FALSE;
+	spin_unlock_irqrestore(&vfe31_ctrl->rs_ack_lock, flags);
+}
+
+static void vfe31_stats_cs_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe31_ctrl->cs_ack_lock, flags);
+	vfe31_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->csStatsControl.ackPending = FALSE;
+	spin_unlock_irqrestore(&vfe31_ctrl->cs_ack_lock, flags);
+}
+
+static int vfe31_config(struct msm_vfe_cfg_cmd *cmd, void *data)
+{
+	struct msm_vfe31_cmd vfecmd;
+	long rc = 0;
+	uint32_t i = 0;
+	struct vfe_cmd_stats_buf *scfg = NULL;
+	struct msm_pmem_region *regptr = NULL;
+	struct vfe_cmd_stats_ack *sack = NULL;
+
+	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+		if (copy_from_user(&vfecmd, (void __user *)cmd->value,
+				sizeof(vfecmd))) {
+			pr_err("%s %d: copy_from_user failed\n", __func__,
+				__LINE__);
+			return -EFAULT;
+		}
+	} else if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE) {
+		/* This must be stats release. */
+		if (!data)
+			return -EFAULT;
+		sack = kmalloc(sizeof(struct vfe_cmd_stats_ack), GFP_KERNEL);
+		if (!sack)
+			return -ENOMEM;
+		sack->nextStatsBuf = *(uint32_t *)data;
+	}
+
+	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+	switch (cmd->cmd_type) {
+	case CMD_GENERAL:
+		rc = vfe31_proc_general(&vfecmd);
+		break;
+	case CMD_FRAME_BUF_RELEASE: {
+		struct msm_frame *b;
+		unsigned long p;
+		struct vfe31_free_buf *fbuf = NULL;
+		if (!data)
+			return -EFAULT;
+
+		b = (struct msm_frame *)(cmd->value);
+		p = *(unsigned long *)data;
+
+		CDBG("CMD_FRAME_BUF_RELEASE b->path = %d\n", b->path);
+
+		if (b->path & OUTPUT_TYPE_P) {
+			CDBG("CMD_FRAME_BUF_RELEASE got free buffer\n");
+			fbuf = &vfe31_ctrl->outpath.out0.free_buf;
+		} else if (b->path & OUTPUT_TYPE_S) {
+			fbuf = &vfe31_ctrl->outpath.out1.free_buf;
+		} else if (b->path & OUTPUT_TYPE_V) {
+			fbuf = &vfe31_ctrl->outpath.out2.free_buf;
+		} else
+			return -EFAULT;
+
+		fbuf->paddr = p;
+		fbuf->y_off = b->y_off;
+		fbuf->cbcr_off = b->cbcr_off;
+		fbuf->available = 1;
+		}
+		break;
+
+	case CMD_SNAP_BUF_RELEASE:
+		break;
+	case CMD_STATS_AEC_BUF_RELEASE:
+		vfe31_stats_aec_ack(sack);
+		break;
+	case CMD_STATS_AF_BUF_RELEASE:
+		vfe31_stats_af_ack(sack);
+		break;
+	case CMD_STATS_AWB_BUF_RELEASE:
+		vfe31_stats_awb_ack(sack);
+		break;
+	case CMD_STATS_IHIST_BUF_RELEASE:
+		vfe31_stats_ihist_ack(sack);
+		break;
+	case CMD_STATS_RS_BUF_RELEASE:
+		vfe31_stats_rs_ack(sack);
+		break;
+	case CMD_STATS_CS_BUF_RELEASE:
+		vfe31_stats_cs_ack(sack);
+		break;
+
+	case CMD_AXI_CFG_PREVIEW: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid)
+			return -EFAULT;
+		axio = kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length, GFP_KERNEL);
+		if (!axio)
+			return -ENOMEM;
+
+		if (copy_from_user(axio, (void __user *)vfecmd.value,
+				vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			return -EFAULT;
+		}
+		vfe31_config_axi(OUTPUT_2, axid, axio);
+		kfree(axio);
+	}
+		break;
+
+	case CMD_RAW_PICT_AXI_CFG: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid)
+			return -EFAULT;
+		axio = kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length, GFP_KERNEL);
+		if (!axio)
+			return -ENOMEM;
+
+		if (copy_from_user(axio, (void __user *)vfecmd.value,
+				vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			return -EFAULT;
+		}
+		vfe31_config_axi(CAMIF_TO_AXI_VIA_OUTPUT_2, axid, axio);
+		kfree(axio);
+	}
+		break;
+
+	case CMD_AXI_CFG_SNAP: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid)
+			return -EFAULT;
+		axio = kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length, GFP_KERNEL);
+		if (!axio)
+			return -ENOMEM;
+
+		if (copy_from_user(axio, (void __user *)vfecmd.value,
+				vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			return -EFAULT;
+		}
+		vfe31_config_axi(OUTPUT_1_AND_2, axid, axio);
+		kfree(axio);
+	}
+		break;
+
+	case CMD_AXI_CFG_VIDEO: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid)
+			return -EFAULT;
+		axio = kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length, GFP_KERNEL);
+		if (!axio)
+			return -ENOMEM;
+
+		if (copy_from_user(axio, (void __user *)vfecmd.value,
+				vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			return -EFAULT;
+		}
+		vfe31_config_axi(OUTPUT_1_AND_3, axid, axio);
+		kfree(axio);
+	}
+		break;
+
+	case CMD_STATS_AF_ENABLE:
+	case CMD_STATS_AWB_ENABLE:
+	case CMD_STATS_IHIST_ENABLE:
+	case CMD_STATS_RS_ENABLE:
+	case CMD_STATS_CS_ENABLE:
+	case CMD_STATS_AEC_ENABLE: {
+		struct axidata *axid;
+		axid = (struct axidata *)data;
+		if (!axid)
+			return -EFAULT;
+
+		scfg = kmalloc(sizeof(struct vfe_cmd_stats_buf), GFP_KERNEL);
+		if (!scfg)
+			return -ENOMEM;
+		regptr = axid->region;
+		if (axid->bufnum1 > 0) {
+			for (i = 0; i < axid->bufnum1; i++) {
+				scfg->statsBuf[i] = (uint32_t)(regptr->paddr);
+				regptr++;
+			}
+		}
+		/* individual */
+		switch (cmd->cmd_type) {
+		case CMD_STATS_AEC_ENABLE:
+			rc = vfe_stats_aec_buf_init(scfg);
+			break;
+		case CMD_STATS_AF_ENABLE:
+			rc = vfe_stats_af_buf_init(scfg);
+			break;
+		case CMD_STATS_AWB_ENABLE:
+			rc = vfe_stats_awb_buf_init(scfg);
+			break;
+		case CMD_STATS_IHIST_ENABLE:
+			rc = vfe_stats_ihist_buf_init(scfg);
+			break;
+		case CMD_STATS_RS_ENABLE:
+			rc = vfe_stats_rs_buf_init(scfg);
+			break;
+		case CMD_STATS_CS_ENABLE:
+			rc = vfe_stats_cs_buf_init(scfg);
+			break;
+		}
+	}
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	kfree(scfg);
+	kfree(sack);
+	CDBG("%s done: rc = %d\n", __func__, (int) rc);
+	return rc;
+}
+
+static inline void vfe31_read_irq_status(struct vfe31_irq_status *out)
+{
+	memset(out, 0, sizeof(struct vfe31_irq_status));
+	out->vfeIrqStatus0 = vfe_io_r(VFE_IRQ_STATUS_0);
+	out->vfeIrqStatus1 = vfe_io_r(VFE_IRQ_STATUS_1);
+	out->camifStatus = vfe_io_r(VFE_CAMIF_STATUS);
+	CDBG("camifStatus  = 0x%x\n", out->camifStatus);
+}
+
+static void vfe31_send_msg_no_payload(enum VFE31_MESSAGE_ID id)
+{
+	struct vfe_message msg;
+
+	CDBG("vfe31_send_msg_no_payload\n");
+	msg._d = id;
+	vfe31_proc_ops(id, &msg, 0);
+}
+
+static void vfe31_process_reg_update_irq(void)
+{
+	unsigned long flags;
+	uint32_t temp;
+
+	if (vfe31_ctrl->req_start_video_rec) {
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_V) {
+			vfe_io_w_axi_out_chan(1, vfe31_ctrl->outpath.out2.ch0);
+			vfe_io_w_axi_out_chan(1, vfe31_ctrl->outpath.out2.ch1);
+		}
+		vfe31_ctrl->req_start_video_rec =  FALSE;
+		CDBG("start video triggered .\n");
+	} else if (vfe31_ctrl->req_stop_video_rec) {
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_V) {
+			vfe_io_w_axi_out_chan(0, vfe31_ctrl->outpath.out2.ch0);
+			vfe_io_w_axi_out_chan(0, vfe31_ctrl->outpath.out2.ch1);
+		}
+		vfe31_ctrl->req_stop_video_rec =  FALSE;
+		CDBG("stop video triggered .\n");
+	}
+	if (vfe31_ctrl->start_ack_pending == TRUE) {
+		vfe31_send_msg_no_payload(MSG_ID_START_ACK);
+		vfe31_ctrl->start_ack_pending = FALSE;
+	} else {
+		spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+		if (vfe31_ctrl->update_ack_pending == TRUE) {
+			spin_unlock_irqrestore(
+				&vfe31_ctrl->update_ack_lock, flags);
+			vfe31_send_msg_no_payload(MSG_ID_UPDATE_ACK);
+			spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+			vfe31_ctrl->update_ack_pending = FALSE;
+			spin_unlock_irqrestore(
+				&vfe31_ctrl->update_ack_lock, flags);
+		} else {
+			spin_unlock_irqrestore(
+				&vfe31_ctrl->update_ack_lock, flags);
+		}
+	}
+	if (vfe31_ctrl->operation_mode & 1) {  /* in snapshot mode */
+		/* later we need to add check for live snapshot mode. */
+		vfe31_ctrl->vfe_capture_count--;
+		/* if last frame to be captured: */
+		if (vfe31_ctrl->vfe_capture_count == 0) {
+			/* stop the bus output:  write master enable = 0*/
+			if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) {
+				vfe_io_w_axi_out_chan(0,
+					vfe31_ctrl->outpath.out0.ch0);
+				vfe_io_w_axi_out_chan(0,
+					vfe31_ctrl->outpath.out0.ch1);
+			}
+			if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) {
+				vfe_io_w_axi_out_chan(0,
+					vfe31_ctrl->outpath.out1.ch0);
+				vfe_io_w_axi_out_chan(0,
+					vfe31_ctrl->outpath.out1.ch1);
+			}
+			vfe_io_w(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+				VFE_CAMIF_COMMAND);
+
+			temp = vfe_io_r(VFE_CAMIF_COMMAND);
+			/* then do reg_update. */
+			vfe_io_w(1, VFE_REG_UPDATE_CMD);
+		}
+	} /* if snapshot mode. */
+}
+
+static void vfe31_set_default_reg_values(void)
+{
+	vfe_io_w(0x800080, VFE_DEMUX_GAIN_0);
+	vfe_io_w(0x800080, VFE_DEMUX_GAIN_1);
+	vfe_io_w(0xFFFFF, VFE_CGC_OVERRIDE);
+
+	/* default frame drop period and pattern */
+	vfe_io_w(0x1f, VFE_FRAMEDROP_ENC_Y_CFG);
+	vfe_io_w(0x1f, VFE_FRAMEDROP_ENC_CBCR_CFG);
+	vfe_io_w(0xFFFFFFFF, VFE_FRAMEDROP_ENC_Y_PATTERN);
+	vfe_io_w(0xFFFFFFFF, VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+	vfe_io_w(0x1f, VFE_FRAMEDROP_VIEW_Y);
+	vfe_io_w(0x1f, VFE_FRAMEDROP_VIEW_CBCR);
+	vfe_io_w(0xFFFFFFFF, VFE_FRAMEDROP_VIEW_Y_PATTERN);
+	vfe_io_w(0xFFFFFFFF, VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+	vfe_io_w(0, VFE_CLAMP_MIN);
+	vfe_io_w(0xFFFFFF, VFE_CLAMP_MAX);
+
+	/* stats UB config */
+	vfe_io_w(0x3900007, VFE_BUS_STATS_AEC_UB_CFG);
+	vfe_io_w(0x3980007, VFE_BUS_STATS_AF_UB_CFG);
+	vfe_io_w(0x3A0000F, VFE_BUS_STATS_AWB_UB_CFG);
+	vfe_io_w(0x3B00007, VFE_BUS_STATS_RS_UB_CFG);
+	vfe_io_w(0x3B8001F, VFE_BUS_STATS_CS_UB_CFG);
+	vfe_io_w(0x3D8001F, VFE_BUS_STATS_HIST_UB_CFG);
+	vfe_io_w(0x3F80007, VFE_BUS_STATS_SKIN_UB_CFG);
+}
+
+static void vfe31_process_reset_irq(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->state_lock, flags);
+	vfe31_ctrl->vstate = VFE_STATE_IDLE;
+	spin_unlock_irqrestore(&vfe31_ctrl->state_lock, flags);
+
+	spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+	if (vfe31_ctrl->stop_ack_pending) {
+		vfe31_ctrl->stop_ack_pending = FALSE;
+		spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+		vfe31_send_msg_no_payload(MSG_ID_STOP_ACK);
+	} else {
+		spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+		/* this is from reset command. */
+		vfe31_set_default_reg_values();
+
+		/* reload all write masters. (frame & line)*/
+		vfe_io_w(0x7FFF, VFE_BUS_CMD);
+		vfe31_send_msg_no_payload(MSG_ID_RESET_ACK);
+	}
+}
+
+static void vfe31_process_camif_sof_irq(void)
+{
+	uint32_t temp;
+
+	if (vfe31_ctrl->operation_mode == 3) {  /* in raw snapshot mode */
+		if (vfe31_ctrl->start_ack_pending) {
+			vfe31_send_msg_no_payload(MSG_ID_START_ACK);
+			vfe31_ctrl->start_ack_pending = FALSE;
+		}
+		vfe31_ctrl->vfe_capture_count--;
+		/* if last frame to be captured: */
+		if (vfe31_ctrl->vfe_capture_count == 0) {
+			vfe_io_w(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY, VFE_CAMIF_COMMAND);
+			temp = vfe_io_r(VFE_CAMIF_COMMAND);
+		}
+	} /* if raw snapshot mode. */
+
+	vfe31_ctrl->vfeFrameId++;
+	CDBG("camif_sof_irq, frameId = %d\n", vfe31_ctrl->vfeFrameId);
+}
+
+static void vfe31_process_output_path_irq_0(void)
+{
+	uint32_t ping_pong;
+	uint32_t pyaddr, pcbcraddr;
+	uint8_t out_bool = 0;
+
+	/* we render frames in the following conditions:
+	1. Continuous mode and the free buffer is avaialable.
+	2. In snapshot shot mode, free buffer is not always available.
+	when pending snapshot count is <=1,  then no need to use
+	free buffer.
+	*/
+	out_bool =
+		((vfe31_ctrl->operation_mode & 1) &&
+		(vfe31_ctrl->vfe_capture_count <= 1)) ||
+		(vfe31_ctrl->outpath.out0.free_buf.available);
+	if (out_bool) {
+		ping_pong = vfe_io_r(VFE_BUS_PING_PONG_STATUS);
+
+		/* Y channel */
+		pyaddr = vfe31_get_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out0.ch0);
+		/* Chroma channel */
+		pcbcraddr = vfe31_get_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out0.ch1);
+
+		CDBG("output path 0, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+			pyaddr, pcbcraddr);
+		if (vfe31_ctrl->outpath.out0.free_buf.available) {
+			/* Y channel */
+			vfe31_put_ch_addr(ping_pong,
+				vfe31_ctrl->outpath.out0.ch0,
+				vfe31_ctrl->outpath.out0.free_buf.paddr +
+				vfe31_ctrl->outpath.out0.free_buf.y_off);
+			/* Chroma channel */
+			vfe31_put_ch_addr(ping_pong,
+				vfe31_ctrl->outpath.out0.ch1,
+				vfe31_ctrl->outpath.out0.free_buf.paddr +
+				vfe31_ctrl->outpath.out0.free_buf.cbcr_off);
+			vfe31_ctrl->outpath.out0.free_buf.available = 0;
+		}
+		if (vfe31_ctrl->operation_mode & 1) {
+			/* will add message for multi-shot. */
+			vfe31_ctrl->outpath.out0.capture_cnt--;
+		} else {
+			/* always send message for continous mode. */
+			/* if continuous mode, this is for display. (preview) */
+			vfe_send_outmsg(MSG_ID_OUTPUT_P, pyaddr, pcbcraddr);
+		}
+	} else {
+		vfe31_ctrl->outpath.out0.frame_drop_cnt++;
+		CDBG("path_irq_0 - no free buffer!\n");
+	}
+}
+
+static void vfe31_process_output_path_irq_1(void)
+{
+	uint32_t ping_pong;
+	uint32_t pyaddr, pcbcraddr;
+	/* this must be snapshot main image output. */
+	uint8_t out_bool;
+
+	/* we render frames in the following conditions:
+	1. Continuous mode and the free buffer is avaialable.
+	2. In snapshot shot mode, free buffer is not always available.
+	-- when pending snapshot count is <=1,  then no need to use
+	free buffer.
+	*/
+	out_bool =
+		((vfe31_ctrl->operation_mode & 1) &&
+		 (vfe31_ctrl->vfe_capture_count <= 1)) ||
+		(vfe31_ctrl->outpath.out1.free_buf.available);
+	if (out_bool) {
+		ping_pong = vfe_io_r(VFE_BUS_PING_PONG_STATUS);
+
+		/* Y channel */
+		pyaddr = vfe31_get_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out1.ch0);
+		/* Chroma channel */
+		pcbcraddr = vfe31_get_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out1.ch1);
+
+		CDBG("snapshot main, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+			pyaddr, pcbcraddr);
+		if (vfe31_ctrl->outpath.out1.free_buf.available) {
+			/* Y channel */
+			vfe31_put_ch_addr(ping_pong,
+				vfe31_ctrl->outpath.out1.ch0,
+				vfe31_ctrl->outpath.out1.free_buf.paddr +
+				vfe31_ctrl->outpath.out1.free_buf.y_off);
+			/* Chroma channel */
+			vfe31_put_ch_addr(ping_pong,
+				vfe31_ctrl->outpath.out1.ch1,
+				vfe31_ctrl->outpath.out1.free_buf.paddr +
+				vfe31_ctrl->outpath.out1.free_buf.cbcr_off);
+			vfe31_ctrl->outpath.out1.free_buf.available = 0;
+		}
+
+		vfe31_ctrl->outpath.out1.capture_cnt--;
+	} else {
+		vfe31_ctrl->outpath.out1.frame_drop_cnt++;
+		CDBG("path_irq_1 - no free buffer!\n");
+	}
+}
+
+static void vfe31_process_output_path_irq_2(void)
+{
+	uint32_t ping_pong;
+	uint32_t pyaddr, pcbcraddr;
+	uint8_t out_bool;
+
+	/* we render frames in the following conditions:
+	1. Continuous mode and the free buffer is avaialable.
+	2. In snapshot shot mode, free buffer is not always available.
+	-- when pending snapshot count is <=1,  then no need to use
+	free buffer.
+	*/
+	out_bool =
+		((vfe31_ctrl->operation_mode & 1) &&
+		(vfe31_ctrl->vfe_capture_count <= 1)) ||
+		(vfe31_ctrl->outpath.out2.free_buf.available);
+	if (out_bool) {
+		ping_pong = vfe_io_r(VFE_BUS_PING_PONG_STATUS);
+
+		/* Y channel */
+		pyaddr = vfe31_get_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out2.ch0);
+		/* Chroma channel */
+		pcbcraddr = vfe31_get_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out2.ch1);
+
+		CDBG("video output, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+			pyaddr, pcbcraddr);
+
+		if (vfe31_ctrl->outpath.out2.free_buf.available) {
+			/* Y channel */
+			vfe31_put_ch_addr(ping_pong,
+				vfe31_ctrl->outpath.out2.ch0,
+				vfe31_ctrl->outpath.out2.free_buf.paddr +
+				vfe31_ctrl->outpath.out2.free_buf.y_off);
+			/* Chroma channel */
+			vfe31_put_ch_addr(ping_pong,
+				vfe31_ctrl->outpath.out2.ch1,
+				vfe31_ctrl->outpath.out2.free_buf.paddr +
+				vfe31_ctrl->outpath.out2.free_buf.cbcr_off);
+			vfe31_ctrl->outpath.out2.free_buf.available = 0;
+		}
+		vfe_send_outmsg(MSG_ID_OUTPUT_V, pyaddr, pcbcraddr);
+	} else {
+		vfe31_ctrl->outpath.out2.frame_drop_cnt++;
+		CDBG("path_irq_2 - no free buffer!\n");
+	}
+}
+
+static void vfe31_process_stats_comb_irq(uint32_t *irqstatus)
+{
+	return;
+}
+
+static uint32_t vfe31_process_stats_irq_common(uint32_t statsNum,
+						uint32_t newAddr) {
+	uint32_t pingpongStatus;
+	uint32_t returnAddr;
+	uint32_t pingpongAddrOffset;
+
+	/* must be 0=ping, 1=pong */
+	pingpongStatus =
+		(vfe_io_r(VFE_BUS_PING_PONG_STATUS)
+		& ((uint32_t)(1<<(statsNum + 7)))) >> (statsNum + 7);
+	/* stats bits starts at 7 */
+	CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus);
+	pingpongAddrOffset =
+		((uint32_t)(VFE_BUS_STATS_PING_PONG_BASE)) +
+				(3*statsNum)*4 + (1-pingpongStatus)*4;
+	returnAddr = vfe_io_r(pingpongAddrOffset);
+	vfe_io_w(newAddr, pingpongAddrOffset);
+	return returnAddr;
+}
+
+static void vfe_send_stats_msg(uint32_t bufAddress, uint32_t statsNum)
+{
+	struct vfe_message msg;
+
+	/* fill message with right content. */
+	msg._u.msgStats.frameCounter = vfe31_ctrl->vfeFrameId;
+	msg._u.msgStats.buffer = bufAddress;
+
+	switch (statsNum) {
+	case statsAeNum:
+		msg._d = MSG_ID_STATS_AEC;
+		break;
+	case statsAfNum:
+		msg._d = MSG_ID_STATS_AF;
+		break;
+	case statsAwbNum:
+		msg._d = MSG_ID_STATS_AWB;
+		break;
+	case statsIhistNum:
+		msg._d = MSG_ID_STATS_IHIST;
+		break;
+	case statsRsNum:
+		msg._d = MSG_ID_STATS_RS;
+		break;
+	case statsCsNum:
+		msg._d = MSG_ID_STATS_CS;
+		break;
+	default:
+		goto stats_done;
+	}
+
+	vfe31_proc_ops(msg._d, &msg, sizeof(struct vfe_message));
+stats_done:
+	return;
+}
+
+static void vfe31_process_stats_ae_irq(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
+	if (!vfe31_ctrl->aecStatsControl.ackPending) {
+		vfe31_ctrl->aecStatsControl.ackPending = TRUE;
+		spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+		vfe31_ctrl->aecStatsControl.bufToRender =
+			vfe31_process_stats_irq_common(statsAeNum,
+			vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe31_ctrl->aecStatsControl.bufToRender,
+						statsAeNum);
+	} else {
+		spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+		vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++;
+	}
+
+}
+
+static void vfe31_process_stats_af_irq(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
+	if (!vfe31_ctrl->afStatsControl.ackPending) {
+		vfe31_ctrl->afStatsControl.ackPending = TRUE;
+		spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+		vfe31_ctrl->afStatsControl.bufToRender =
+			vfe31_process_stats_irq_common(statsAfNum,
+			vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe31_ctrl->afStatsControl.bufToRender,
+						statsAfNum);
+	} else {
+		spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+		vfe31_ctrl->afStatsControl.droppedStatsFrameCount++;
+	}
+
+}
+
+static void vfe31_process_stats_awb_irq(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
+	if (!vfe31_ctrl->awbStatsControl.ackPending) {
+		vfe31_ctrl->awbStatsControl.ackPending = TRUE;
+		spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+		vfe31_ctrl->awbStatsControl.bufToRender =
+			vfe31_process_stats_irq_common(statsAwbNum,
+			vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe31_ctrl->awbStatsControl.bufToRender,
+						statsAwbNum);
+	} else {
+		spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+		vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
+	}
+
+}
+
+static void vfe31_process_stats_ihist_irq(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->ihist_ack_lock, flags);
+	if (!vfe31_ctrl->ihistStatsControl.ackPending) {
+		vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
+		spin_unlock_irqrestore(&vfe31_ctrl->ihist_ack_lock, flags);
+		vfe31_ctrl->ihistStatsControl.bufToRender =
+			vfe31_process_stats_irq_common(statsIhistNum,
+			vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe31_ctrl->ihistStatsControl.bufToRender,
+						statsIhistNum);
+	} else {
+		spin_unlock_irqrestore(&vfe31_ctrl->ihist_ack_lock, flags);
+		vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+	}
+}
+
+
+static void vfe31_process_stats_rs_irq(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->rs_ack_lock, flags);
+	if (!vfe31_ctrl->rsStatsControl.ackPending) {
+		vfe31_ctrl->rsStatsControl.ackPending = TRUE;
+		spin_unlock_irqrestore(&vfe31_ctrl->rs_ack_lock, flags);
+		vfe31_ctrl->rsStatsControl.bufToRender =
+			vfe31_process_stats_irq_common(statsRsNum,
+			vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe31_ctrl->rsStatsControl.bufToRender,
+						statsRsNum);
+	} else {
+		spin_unlock_irqrestore(&vfe31_ctrl->rs_ack_lock, flags);
+		vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++;
+	}
+}
+
+static void vfe31_process_stats_cs_irq(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->cs_ack_lock, flags);
+	if (!vfe31_ctrl->csStatsControl.ackPending) {
+		vfe31_ctrl->csStatsControl.ackPending = TRUE;
+		spin_unlock_irqrestore(&vfe31_ctrl->cs_ack_lock, flags);
+		vfe31_ctrl->csStatsControl.bufToRender =
+			vfe31_process_stats_irq_common(statsCsNum,
+			vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe31_ctrl->csStatsControl.bufToRender,
+						statsCsNum);
+	} else {
+		spin_unlock_irqrestore(&vfe31_ctrl->cs_ack_lock, flags);
+		vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
+	}
+}
+
+static void vfe31_do_tasklet(unsigned long data)
+{
+	unsigned long flags;
+	struct vfe31_isr_queue_cmd *qcmd = NULL;
+
+	CDBG("=== vfe31_do_tasklet start ===\n");
+
+	spin_lock_irqsave(&vfe31_ctrl->tasklet_lock, flags);
+	qcmd = list_first_entry(&vfe31_ctrl->tasklet_q,
+		struct vfe31_isr_queue_cmd, list);
+
+	if (!qcmd) {
+		spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock, flags);
+		return;
+	}
+
+	list_del(&qcmd->list);
+	spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock, flags);
+
+	/* interrupt to be processed,  *qcmd has the payload.  */
+	if (qcmd->vfeInterruptStatus0 & VFE_IRQ_STATUS0_REG_UPDATE_MASK) {
+		CDBG("irq regUpdateIrq\n");
+		vfe31_process_reg_update_irq();
+	}
+
+	if (qcmd->vfeInterruptStatus1 & VFE_IMASK_WHILE_STOPPING_1) {
+		CDBG("irq resetAckIrq\n");
+		vfe31_process_reset_irq();
+	}
+
+	spin_lock_irqsave(&vfe31_ctrl->state_lock, flags);
+	if (vfe31_ctrl->vstate == VFE_STATE_ACTIVE) {
+		/* irqs below are only valid when in active state. */
+		spin_unlock_irqrestore(&vfe31_ctrl->state_lock, flags);
+		/* next, check output path related interrupts. */
+		if (qcmd->vfeInterruptStatus0 &
+			VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
+			vfe31_process_output_path_irq_0();
+		}
+		if (qcmd->vfeInterruptStatus0 &
+			VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
+			vfe31_process_output_path_irq_1();
+		}
+		if (qcmd->vfeInterruptStatus0 &
+			VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK) {
+			vfe31_process_output_path_irq_2();
+		}
+		/* in snapshot mode if done then send snapshot done message */
+		if (vfe31_ctrl->operation_mode & 1) {
+			if ((vfe31_ctrl->outpath.out0.capture_cnt == 0) &&
+				(vfe31_ctrl->outpath.out1.capture_cnt == 0)) {
+				vfe31_send_msg_no_payload(MSG_ID_SNAPSHOT_DONE);
+				vfe_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY, VFE_CAMIF_COMMAND);
+			}
+		}
+		/* then process stats irq. */
+		if (vfe31_ctrl->stats_comp) {
+			/* process stats comb interrupt. */
+			if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
+				CDBG("Stats composite irq occured.\n");
+				vfe31_process_stats_comb_irq(
+					&qcmd->vfeInterruptStatus0);
+			}
+		} else {
+			/* process individual stats interrupt. */
+			if (qcmd->vfeInterruptStatus0 & VFE_IRQ_STATUS0_STATS_AEC) {
+				CDBG("Stats AEC irq occured.\n");
+				vfe31_process_stats_ae_irq();
+			}
+			if (qcmd->vfeInterruptStatus0 & VFE_IRQ_STATUS0_STATS_AWB) {
+				CDBG("Stats AWB irq occured.\n");
+				vfe31_process_stats_awb_irq();
+			}
+			if (qcmd->vfeInterruptStatus0 & VFE_IRQ_STATUS0_STATS_AF) {
+				CDBG("Stats AF irq occured.\n");
+				vfe31_process_stats_af_irq();
+			}
+			if (qcmd->vfeInterruptStatus0 & VFE_IRQ_STATUS0_STATS_IHIST) {
+				CDBG("Stats IHIST irq occured.\n");
+				vfe31_process_stats_ihist_irq();
+			}
+			if (qcmd->vfeInterruptStatus0 & VFE_IRQ_STATUS0_STATS_RS) {
+				CDBG("Stats RS irq occured.\n");
+				vfe31_process_stats_rs_irq();
+			}
+			if (qcmd->vfeInterruptStatus0 & VFE_IRQ_STATUS0_STATS_CS) {
+				CDBG("Stats CS irq occured.\n");
+				vfe31_process_stats_cs_irq();
+			}
+		}
+	} else {
+		/* do we really need spin lock for state? */
+		spin_unlock_irqrestore(&vfe31_ctrl->state_lock, flags);
+	}
+	if (qcmd->vfeInterruptStatus0 & VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
+		vfe31_process_camif_sof_irq();
+	}
+	kfree(qcmd);
+	CDBG("=== vfe31_do_tasklet end ===\n");
+}
+
+DECLARE_TASKLET(vfe31_tasklet, vfe31_do_tasklet, 0);
+
+static irqreturn_t vfe31_parse_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	struct vfe31_irq_status irq;
+	struct vfe31_isr_queue_cmd *qcmd;
+
+	CDBG("vfe_parse_irq\n");
+	vfe31_read_irq_status(&irq);
+
+	if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) {
+		CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n");
+		return IRQ_HANDLED;
+	}
+
+	qcmd = kzalloc(sizeof(struct vfe31_isr_queue_cmd), GFP_ATOMIC);
+	if (!qcmd) {
+		pr_err("vfe_parse_irq: qcmd malloc failed!\n");
+		return IRQ_HANDLED;
+	}
+
+	spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+	if (vfe31_ctrl->stop_ack_pending) {
+		irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0;
+		irq.vfeIrqStatus1 &= VFE_IMASK_WHILE_STOPPING_1;
+	}
+	spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+
+	CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n",
+		irq.vfeIrqStatus0, irq.vfeIrqStatus1);
+
+	qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0;
+	qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1;
+
+	spin_lock_irqsave(&vfe31_ctrl->tasklet_lock, flags);
+	list_add_tail(&qcmd->list, &vfe31_ctrl->tasklet_q);
+	spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock, flags);
+	tasklet_schedule(&vfe31_tasklet);
+
+	/* clear the pending interrupt of the same kind.*/
+	vfe_io_w(irq.vfeIrqStatus0, VFE_IRQ_CLEAR_0);
+	vfe_io_w(irq.vfeIrqStatus1, VFE_IRQ_CLEAR_1);
+
+	vfe_io_w(1, VFE_IRQ_CMD);
+
+	return IRQ_HANDLED;
+}
+
+static int vfe31_resource_init(struct msm_vfe_callback *presp,
+	struct platform_device *pdev, void *sdata)
+{
+	struct resource	*vfemem, *vfeirq, *vfeio;
+	int rc;
+	struct msm_camera_sensor_info *s_info;
+	s_info = pdev->dev.platform_data;
+
+	pdev->resource = s_info->resource;
+	pdev->num_resources = s_info->num_resources;
+
+	vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!vfemem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!vfeirq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	vfeio = request_mem_region(vfemem->start,
+		resource_size(vfemem), pdev->name);
+	if (!vfeio) {
+		pr_err("%s: VFE region already claimed\n", __func__);
+		return -EBUSY;
+	}
+
+	vfe31_ctrl = kzalloc(sizeof(struct vfe31_ctrl_type), GFP_KERNEL);
+	if (!vfe31_ctrl) {
+		rc = -ENOMEM;
+		goto cmd_init_failed1;
+	}
+
+	vfe31_ctrl->vfeirq = vfeirq->start;
+
+	vfe31_ctrl->vfebase =
+		ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	if (!vfe31_ctrl->vfebase) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto cmd_init_failed2;
+	}
+
+	rc = request_irq(vfe31_ctrl->vfeirq, vfe31_parse_irq,
+		IRQF_TRIGGER_RISING, "vfe", 0);
+	if (rc < 0)
+		goto cmd_init_failed2;
+
+	if (presp && presp->vfe_resp)
+		vfe31_ctrl->resp = presp;
+	else {
+		rc = -EINVAL;
+		goto cmd_init_failed3;
+	}
+
+	vfe31_ctrl->extdata = kmalloc(sizeof(struct vfe31_frame_extra),
+				      GFP_KERNEL);
+	if (!vfe31_ctrl->extdata) {
+		rc = -ENOMEM;
+		goto cmd_init_failed3;
+	}
+
+	vfe31_ctrl->extlen = sizeof(struct vfe31_frame_extra);
+
+	spin_lock_init(&vfe31_ctrl->stop_flag_lock);
+	spin_lock_init(&vfe31_ctrl->state_lock);
+	spin_lock_init(&vfe31_ctrl->update_ack_lock);
+	spin_lock_init(&vfe31_ctrl->tasklet_lock);
+
+	spin_lock_init(&vfe31_ctrl->aec_ack_lock);
+	spin_lock_init(&vfe31_ctrl->awb_ack_lock);
+	spin_lock_init(&vfe31_ctrl->af_ack_lock);
+	spin_lock_init(&vfe31_ctrl->ihist_ack_lock);
+	spin_lock_init(&vfe31_ctrl->rs_ack_lock);
+	spin_lock_init(&vfe31_ctrl->cs_ack_lock);
+	INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
+
+	vfe31_ctrl->syncdata = sdata;
+	vfe31_ctrl->vfemem = vfemem;
+	vfe31_ctrl->vfeio = vfeio;
+	return 0;
+
+cmd_init_failed3:
+	free_irq(vfe31_ctrl->vfeirq, 0);
+	iounmap(vfe31_ctrl->vfebase);
+cmd_init_failed2:
+	kfree(vfe31_ctrl);
+cmd_init_failed1:
+	release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	return rc;
+}
+
+static int vfe31_init(struct msm_vfe_callback *presp,
+	struct platform_device *dev)
+{
+	int rc = 0;
+	rc = vfe31_resource_init(presp, dev, vfe_syncdata);
+	if (rc < 0)
+		return rc;
+
+	/* Bring up all the required GPIOs and Clocks */
+	rc = msm_camio_enable(dev);
+	return rc;
+}
+
+void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
+{
+	fptr->vfe_init    = vfe31_init;
+	fptr->vfe_enable  = vfe31_enable;
+	fptr->vfe_config  = vfe31_config;
+	fptr->vfe_disable = vfe31_disable;
+	fptr->vfe_release = vfe31_release;
+	vfe_syncdata = data;
+}
diff --git a/drivers/media/video/msm/msm_vfe31.h b/drivers/media/video/msm/msm_vfe31.h
new file mode 100644
index 0000000..2a12ac4
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe31.h
@@ -0,0 +1,1052 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+
+#ifndef __MSM_VFE31_H__
+#define __MSM_VFE31_H__
+
+#define TRUE  1
+#define FALSE 0
+
+/* at start of camif,  bit 1:0 = 0x01:enable
+ * image data capture at frame boundary. */
+#define CAMIF_COMMAND_START  0x00000005
+
+/* bit 2= 0x1:clear the CAMIF_STATUS register
+ * value. */
+#define CAMIF_COMMAND_CLEAR  0x00000004
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x10:
+ * disable image data capture immediately. */
+#define CAMIF_COMMAND_STOP_IMMEDIATELY  0x00000002
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x00:
+ * disable image data capture at frame boundary */
+#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY  0x00000000
+
+/* to halt axi bridge */
+#define AXI_HALT  0x00000001
+
+/* clear the halt bit. */
+#define AXI_HALT_CLEAR  0x00000000
+
+/* reset the pipeline when stop command is issued.
+ * (without reset the register.) bit 26-31 = 0,
+ * domain reset, bit 0-9 = 1 for module reset, except
+ * register module. */
+#define VFE_RESET_UPON_STOP_CMD  0x000003ef
+
+/* reset the pipeline when reset command.
+ * bit 26-31 = 0, domain reset, bit 0-9 = 1 for module reset. */
+#define VFE_RESET_UPON_RESET_CMD  0x000003ff
+
+/* bit 5 is for axi status idle or busy.
+ * 1 =  halted,  0 = busy */
+#define AXI_STATUS_BUSY_MASK 0x00000020
+
+/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present
+ * for frame done interrupt */
+#define VFE_COMP_IRQ_BOTH_Y_CBCR 3
+
+/* bit 1 = 1, only cbcr irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_CBCR_ONLY 2
+
+/* bit 0 = 1, only y irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_Y_ONLY 1
+
+/* bit 0 = 1, PM go;   bit1 = 1, PM stop */
+#define VFE_PERFORMANCE_MONITOR_GO   0x00000001
+#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002
+
+/* bit 0 = 1, test gen go;   bit1 = 1, test gen stop */
+#define VFE_TEST_GEN_GO   0x00000001
+#define VFE_TEST_GEN_STOP 0x00000002
+
+/* the chroma is assumed to be interpolated between
+ * the luma samples.  JPEG 4:2:2 */
+#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0
+
+/* constants for irq registers */
+#define VFE_DISABLE_ALL_IRQS 0
+/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS.  */
+#define VFE_CLEAR_ALL_IRQS   0xffffffff
+
+#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK            0x00000001
+#define VFE_IRQ_STATUS0_REG_UPDATE_MASK           0x00000020
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK 0x00200000
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK 0x00400000
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK 0x00800000
+#define VFE_IRQ_STATUS1_RESET_AXI_HALT_ACK_MASK   0x00800000
+#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK       0x01000000
+
+#define VFE_IRQ_STATUS0_STATS_AEC     0x2000  /* bit 13 */
+#define VFE_IRQ_STATUS0_STATS_AF      0x4000  /* bit 14 */
+#define VFE_IRQ_STATUS0_STATS_AWB     0x8000  /* bit 15 */
+#define VFE_IRQ_STATUS0_STATS_RS      0x10000  /* bit 16 */
+#define VFE_IRQ_STATUS0_STATS_CS      0x20000  /* bit 17 */
+#define VFE_IRQ_STATUS0_STATS_IHIST   0x40000  /* bit 18 */
+
+/* imask for while waiting for stop ack,  driver has already
+ * requested stop, waiting for reset irq, and async timer irq.
+ * For irq_status_0, bit 28-31 are for async timer. For
+ * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack
+   irq */
+#define VFE_IMASK_WHILE_STOPPING_0  0xF0000000
+#define VFE_IMASK_WHILE_STOPPING_1  0x00400000
+
+/* no error irq in mask 0 */
+#define VFE_IMASK_ERROR_ONLY_0  0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE_IMASK_ERROR_ONLY_1  0x003fffff
+
+/* For BPC bit 0,bit 12-17 and bit 26 -20 are set to zero and other's 1 */
+#define BPC_MASK 0xF80C0FFE
+
+/* For BPC bit 1 and 2 are set to zero and other's 1 */
+#define ABF_MASK 0xFFFFFFF9
+
+/* For MCE enable bit 28 set to zero and other's 1 */
+#define MCE_EN_MASK 0xEFFFFFFF
+
+/* For MCE Q_K bit 28 to 31 set to zero and other's 1 */
+#define MCE_Q_K_MASK 0x0FFFFFFF
+
+#define AWB_ENABLE_MASK 0x00000080     /* bit 7 */
+#define AF_ENABLE_MASK 0x00000040      /* bit 6 */
+#define AE_ENABLE_MASK 0x00000020      /* bit 5 */
+#define IHIST_ENABLE_MASK 0x00008000   /* bit 15 */
+#define RS_ENABLE_MASK 0x00000100      /* bit 8  */
+#define CS_ENABLE_MASK 0x00000200      /* bit 9  */
+
+
+#define VFE_REG_UPDATE_TRIGGER           1
+#define VFE_PM_BUF_MAX_CNT_MASK          0xFF
+#define VFE_DMI_CFG_DEFAULT              0x00000100
+#define LENS_ROLL_OFF_DELTA_TABLE_OFFSET 32
+#define VFE_AE_PINGPONG_STATUS_BIT       0x80
+#define VFE_AF_PINGPONG_STATUS_BIT       0x100
+#define VFE_AWB_PINGPONG_STATUS_BIT      0x200
+
+
+enum VFE31_DMI_RAM_SEL {
+	 NO_MEM_SELECTED          = 0,
+	 ROLLOFF_RAM              = 0x1,
+	 RGBLUT_RAM_CH0_BANK0     = 0x2,
+	 RGBLUT_RAM_CH0_BANK1     = 0x3,
+	 RGBLUT_RAM_CH1_BANK0     = 0x4,
+	 RGBLUT_RAM_CH1_BANK1     = 0x5,
+	 RGBLUT_RAM_CH2_BANK0     = 0x6,
+	 RGBLUT_RAM_CH2_BANK1     = 0x7,
+	 STATS_HIST_CB_EVEN_RAM   = 0x8,
+	 STATS_HIST_CB_ODD_RAM    = 0x9,
+	 STATS_HIST_CR_EVEN_RAM   = 0xa,
+	 STATS_HIST_CR_ODD_RAM    = 0xb,
+	 RGBLUT_CHX_BANK0         = 0xc,
+	 RGBLUT_CHX_BANK1         = 0xd,
+	 LUMA_ADAPT_LUT_RAM_BANK0 = 0xe,
+	 LUMA_ADAPT_LUT_RAM_BANK1 = 0xf
+
+};
+
+enum  VFE_STATE {
+	VFE_STATE_IDLE,
+	VFE_STATE_ACTIVE
+};
+
+#define V31_DUMMY_0               0
+#define V31_SET_CLK               1
+#define V31_RESET                 2
+#define V31_START                 3
+#define V31_TEST_GEN_START        4
+#define V31_OPERATION_CFG         5
+#define V31_AXI_OUT_CFG           6
+#define V31_CAMIF_CFG             7
+#define V31_AXI_INPUT_CFG         8
+#define V31_BLACK_LEVEL_CFG       9
+#define V31_ROLL_OFF_CFG          10
+#define V31_DEMUX_CFG             11
+#define V31_DEMOSAIC_0_CFG        12 /* general */
+#define V31_DEMOSAIC_1_CFG        13 /* ABF     */
+#define V31_DEMOSAIC_2_CFG        14 /* BPC     */
+#define V31_FOV_CFG               15
+#define V31_MAIN_SCALER_CFG       16
+#define V31_WB_CFG                17
+#define V31_COLOR_COR_CFG         18
+#define V31_RGB_G_CFG             19
+#define V31_LA_CFG                20
+#define V31_CHROMA_EN_CFG         21
+#define V31_CHROMA_SUP_CFG        22
+#define V31_MCE_CFG               23
+#define V31_SK_ENHAN_CFG          24
+#define V31_ASF_CFG               25
+#define V31_S2Y_CFG               26
+#define V31_S2CbCr_CFG            27
+#define V31_CHROMA_SUBS_CFG       28
+#define V31_OUT_CLAMP_CFG         29
+#define V31_FRAME_SKIP_CFG        30
+#define V31_DUMMY_1               31
+#define V31_DUMMY_2               32
+#define V31_DUMMY_3               33
+#define V31_UPDATE                34
+#define V31_BL_LVL_UPDATE         35
+#define V31_DEMUX_UPDATE          36
+#define V31_DEMOSAIC_1_UPDATE     37 /* BPC */
+#define V31_DEMOSAIC_2_UPDATE     38 /* ABF */
+#define V31_FOV_UPDATE            39
+#define V31_MAIN_SCALER_UPDATE    40
+#define V31_WB_UPDATE             41
+#define V31_COLOR_COR_UPDATE      42
+#define V31_RGB_G_UPDATE          43
+#define V31_LA_UPDATE             44
+#define V31_CHROMA_EN_UPDATE      45
+#define V31_CHROMA_SUP_UPDATE     46
+#define V31_MCE_UPDATE            47
+#define V31_SK_ENHAN_UPDATE       48
+#define V31_S2CbCr_UPDATE         49
+#define V31_S2Y_UPDATE            50
+#define V31_ASF_UPDATE            51
+#define V31_FRAME_SKIP_UPDATE     52
+#define V31_CAMIF_FRAME_UPDATE    53
+#define V31_STATS_AF_UPDATE       54
+#define V31_STATS_AE_UPDATE       55
+#define V31_STATS_AWB_UPDATE      56
+#define V31_STATS_RS_UPDATE       57
+#define V31_STATS_CS_UPDATE       58
+#define V31_STATS_SKIN_UPDATE     59
+#define V31_STATS_IHIST_UPDATE    60
+#define V31_DUMMY_4               61
+#define V31_EPOCH1_ACK            62
+#define V31_EPOCH2_ACK            63
+#define V31_START_RECORDING       64
+#define V31_STOP_RECORDING        65
+#define V31_DUMMY_5               66
+#define V31_DUMMY_6               67
+#define V31_CAPTURE               68
+#define V31_DUMMY_7               69
+#define V31_STOP                  70
+#define V31_GET_HW_VERSION        71
+#define V31_GET_FRAME_SKIP_COUNTS 72
+#define V31_OUTPUT1_BUFFER_ENQ    73
+#define V31_OUTPUT2_BUFFER_ENQ    74
+#define V31_OUTPUT3_BUFFER_ENQ    75
+#define V31_JPEG_OUT_BUF_ENQ      76
+#define V31_RAW_OUT_BUF_ENQ       77
+#define V31_RAW_IN_BUF_ENQ        78
+#define V31_STATS_AF_ENQ          79
+#define V31_STATS_AE_ENQ          80
+#define V31_STATS_AWB_ENQ         81
+#define V31_STATS_RS_ENQ          82
+#define V31_STATS_CS_ENQ          83
+#define V31_STATS_SKIN_ENQ        84
+#define V31_STATS_IHIST_ENQ       85
+#define V31_DUMMY_8               86
+#define V31_JPEG_ENC_CFG          87
+#define V31_DUMMY_9               88
+#define V31_STATS_AF_START        89
+#define V31_STATS_AF_STOP         90
+#define V31_STATS_AE_START        91
+#define V31_STATS_AE_STOP         92
+#define V31_STATS_AWB_START       93
+#define V31_STATS_AWB_STOP        94
+#define V31_STATS_RS_START        95
+#define V31_STATS_RS_STOP         96
+#define V31_STATS_CS_START        97
+#define V31_STATS_CS_STOP         98
+#define V31_STATS_SKIN_START      99
+#define V31_STATS_SKIN_STOP       100
+#define V31_STATS_IHIST_START     101
+#define V31_STATS_IHIST_STOP      102
+#define V31_DUMMY_10              103
+#define V31_SYNC_TIMER_SETTING    104
+#define V31_ASYNC_TIMER_SETTING   105
+#define V31_CAMIF_OFF             0x000001E4
+#define V31_CAMIF_LEN             32
+
+#define V31_DEMUX_OFF             0x00000284
+#define V31_DEMUX_LEN             20
+
+#define V31_DEMOSAIC_0_OFF        0x00000298
+#define V31_DEMOSAIC_0_LEN        4
+/* ABF     */
+#define V31_DEMOSAIC_1_OFF        0x000002A4
+#define V31_DEMOSAIC_1_LEN        180
+/* BPC     */
+#define V31_DEMOSAIC_2_OFF        0x0000029C
+#define V31_DEMOSAIC_2_LEN        8
+
+#define V31_OUT_CLAMP_OFF         0x00000524
+#define V31_OUT_CLAMP_LEN         8
+
+#define V31_OPERATION_CFG_LEN     28
+
+#define V31_AXI_OUT_OFF           0x00000038
+#define V31_AXI_OUT_LEN           188
+
+#define V31_FRAME_SKIP_OFF        0x00000504
+#define V31_FRAME_SKIP_LEN        32
+
+#define V31_CHROMA_SUBS_OFF       0x000004F8
+#define V31_CHROMA_SUBS_LEN       12
+
+#define V31_FOV_OFF           0x00000360
+#define V31_FOV_LEN           8
+
+#define V31_MAIN_SCALER_OFF 0x00000368
+#define V31_MAIN_SCALER_LEN 28
+
+#define V31_S2Y_OFF 0x000004D0
+#define V31_S2Y_LEN 20
+
+#define V31_S2CbCr_OFF 0x000004E4
+#define V31_S2CbCr_LEN 20
+
+#define V31_CHROMA_EN_OFF 0x000003C4
+#define V31_CHROMA_EN_LEN 36
+
+#define V31_BLACK_LEVEL_OFF 0x00000264
+#define V31_BLACK_LEVEL_LEN 16
+
+#define V31_ROLL_OFF_CFG_OFF 0x00000274
+#define V31_ROLL_OFF_CFG_LEN 16
+
+#define V31_COLOR_COR_OFF 0x00000388
+#define V31_COLOR_COR_LEN 52
+
+#define V31_WB_OFF 0x00000384
+#define V31_WB_LEN 4
+
+#define V31_RGB_G_OFF 0x000003BC
+#define V31_RGB_G_LEN 4
+
+#define V31_LA_OFF 0x000003C0
+#define V31_LA_LEN 4
+
+#define V31_CHROMA_SUP_OFF 0x000003E8
+#define V31_CHROMA_SUP_LEN 12
+
+#define V31_MCE_OFF 0x000003E8
+#define V31_MCE_LEN 36
+#define V31_STATS_AF_OFF 0x0000053c
+#define V31_STATS_AF_LEN 16
+
+#define V31_STATS_AE_OFF 0x00000534
+#define V31_STATS_AE_LEN 8
+
+#define V31_STATS_AWB_OFF 0x0000054c
+#define V31_STATS_AWB_LEN 32
+
+#define V31_STATS_IHIST_OFF 0x0000057c
+#define V31_STATS_IHIST_LEN 8
+
+#define V31_STATS_RS_OFF 0x0000056c
+#define V31_STATS_RS_LEN 8
+
+#define V31_STATS_CS_OFF 0x00000574
+#define V31_STATS_CS_LEN 8
+
+
+#define V31_ASF_OFF 0x000004A0
+#define V31_ASF_LEN 48
+#define V31_ASF_UPDATE_LEN 36
+
+#define V31_CAPTURE_LEN 4
+
+struct vfe_cmd_hw_version {
+	uint32_t minorVersion;
+	uint32_t majorVersion;
+	uint32_t coreVersion;
+};
+
+enum VFE_AXI_OUTPUT_MODE {
+	VFE_AXI_OUTPUT_MODE_Output1,
+	VFE_AXI_OUTPUT_MODE_Output2,
+	VFE_AXI_OUTPUT_MODE_Output1AndOutput2,
+	VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2,
+	VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1,
+	VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2,
+	VFE_AXI_LAST_OUTPUT_MODE_ENUM
+};
+
+enum VFE_RAW_WR_PATH_SEL {
+	VFE_RAW_OUTPUT_DISABLED,
+	VFE_RAW_OUTPUT_ENC_CBCR_PATH,
+	VFE_RAW_OUTPUT_VIEW_CBCR_PATH,
+	VFE_RAW_OUTPUT_PATH_INVALID
+};
+
+
+#define VFE_AXI_OUTPUT_BURST_LENGTH     4
+#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4
+#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT  3
+
+struct vfe_cmds_per_write_master {
+	uint16_t imageWidth;
+	uint16_t imageHeight;
+	uint16_t outRowCount;
+	uint16_t outRowIncrement;
+	uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT]
+		[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+struct vfe_cmds_axi_per_output_path {
+	uint8_t fragmentCount;
+	struct vfe_cmds_per_write_master firstWM;
+	struct vfe_cmds_per_write_master secondWM;
+};
+
+enum VFE_AXI_BURST_LENGTH {
+	VFE_AXI_BURST_LENGTH_IS_2  = 2,
+	VFE_AXI_BURST_LENGTH_IS_4  = 4,
+	VFE_AXI_BURST_LENGTH_IS_8  = 8,
+	VFE_AXI_BURST_LENGTH_IS_16 = 16
+};
+
+
+struct vfe_cmd_fov_crop_config {
+	uint8_t enable;
+	uint16_t firstPixel;
+	uint16_t lastPixel;
+	uint16_t firstLine;
+	uint16_t lastLine;
+};
+
+struct vfe_cmds_main_scaler_stripe_init {
+	uint16_t MNCounterInit;
+	uint16_t phaseInit;
+};
+
+struct vfe_cmds_scaler_one_dimension {
+	uint8_t  enable;
+	uint16_t inputSize;
+	uint16_t outputSize;
+	uint32_t phaseMultiplicationFactor;
+	uint8_t  interpolationResolution;
+};
+
+struct vfe_cmd_main_scaler_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension    hconfig;
+	struct vfe_cmds_scaler_one_dimension    vconfig;
+	struct vfe_cmds_main_scaler_stripe_init MNInitH;
+	struct vfe_cmds_main_scaler_stripe_init MNInitV;
+};
+
+struct vfe_cmd_scaler2_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension hconfig;
+	struct vfe_cmds_scaler_one_dimension vconfig;
+};
+
+
+struct vfe_cmd_frame_skip_update {
+	uint32_t output1Pattern;
+	uint32_t output2Pattern;
+};
+
+struct vfe_cmd_output_clamp_config {
+	uint8_t minCh0;
+	uint8_t minCh1;
+	uint8_t minCh2;
+	uint8_t maxCh0;
+	uint8_t maxCh1;
+	uint8_t maxCh2;
+};
+
+struct vfe_cmd_chroma_subsample_config {
+	uint8_t enable;
+	uint8_t cropEnable;
+	uint8_t vsubSampleEnable;
+	uint8_t hsubSampleEnable;
+	uint8_t vCosited;
+	uint8_t hCosited;
+	uint8_t vCositedPhase;
+	uint8_t hCositedPhase;
+	uint16_t cropWidthFirstPixel;
+	uint16_t cropWidthLastPixel;
+	uint16_t cropHeightFirstLine;
+	uint16_t cropHeightLastLine;
+};
+
+enum VFE_START_INPUT_SOURCE {
+	VFE_START_INPUT_SOURCE_CAMIF,
+	VFE_START_INPUT_SOURCE_TESTGEN,
+	VFE_START_INPUT_SOURCE_AXI,
+	VFE_START_INPUT_SOURCE_INVALID
+};
+
+enum VFE_START_OPERATION_MODE {
+	VFE_START_OPERATION_MODE_CONTINUOUS,
+	VFE_START_OPERATION_MODE_SNAPSHOT
+};
+
+enum VFE_START_PIXEL_PATTERN {
+	VFE_BAYER_RGRGRG,
+	VFE_BAYER_GRGRGR,
+	VFE_BAYER_BGBGBG,
+	VFE_BAYER_GBGBGB,
+	VFE_YUV_YCbYCr,
+	VFE_YUV_YCrYCb,
+	VFE_YUV_CbYCrY,
+	VFE_YUV_CrYCbY
+};
+
+enum VFE_BUS_RD_INPUT_PIXEL_PATTERN {
+	VFE_BAYER_RAW,
+	VFE_YUV_INTERLEAVED,
+	VFE_YUV_PSEUDO_PLANAR_Y,
+	VFE_YUV_PSEUDO_PLANAR_CBCR
+};
+
+enum VFE_YUV_INPUT_COSITING_MODE {
+	VFE_YUV_COSITED,
+	VFE_YUV_INTERPOLATED
+};
+
+
+/* 13*1  */
+#define VFE31_ROLL_OFF_INIT_TABLE_SIZE  13
+/* 13*16 */
+#define VFE31_ROLL_OFF_DELTA_TABLE_SIZE 208
+
+#define VFE31_GAMMA_NUM_ENTRIES  64
+
+#define VFE31_LA_TABLE_LENGTH    64
+
+struct vfe_cmds_demosaic_abf {
+	uint8_t   enable;
+	uint8_t   forceOn;
+	uint8_t   shift;
+	uint16_t  lpThreshold;
+	uint16_t  max;
+	uint16_t  min;
+	uint8_t   ratio;
+};
+
+struct vfe_cmds_demosaic_bpc {
+	uint8_t   enable;
+	uint16_t  fmaxThreshold;
+	uint16_t  fminThreshold;
+	uint16_t  redDiffThreshold;
+	uint16_t  blueDiffThreshold;
+	uint16_t  greenDiffThreshold;
+};
+
+struct vfe_cmd_demosaic_config {
+	uint8_t   enable;
+	uint8_t   slopeShift;
+	struct vfe_cmds_demosaic_abf abfConfig;
+	struct vfe_cmds_demosaic_bpc bpcConfig;
+};
+
+struct vfe_cmd_demosaic_bpc_update {
+	struct vfe_cmds_demosaic_bpc bpcUpdate;
+};
+
+struct vfe_cmd_demosaic_abf_update {
+	struct vfe_cmds_demosaic_abf abfUpdate;
+};
+
+struct vfe_cmd_white_balance_config {
+	uint8_t  enable;
+	uint16_t ch2Gain;
+	uint16_t ch1Gain;
+	uint16_t ch0Gain;
+};
+
+enum VFE_COLOR_CORRECTION_COEF_QFACTOR {
+	COEF_IS_Q7_SIGNED,
+	COEF_IS_Q8_SIGNED,
+	COEF_IS_Q9_SIGNED,
+	COEF_IS_Q10_SIGNED
+};
+
+struct vfe_cmd_color_correction_config {
+	uint8_t     enable;
+	enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor;
+	int16_t  C0;
+	int16_t  C1;
+	int16_t  C2;
+	int16_t  C3;
+	int16_t  C4;
+	int16_t  C5;
+	int16_t  C6;
+	int16_t  C7;
+	int16_t  C8;
+	int16_t  K0;
+	int16_t  K1;
+	int16_t  K2;
+};
+
+#define VFE_LA_TABLE_LENGTH 256
+struct vfe_cmd_la_config {
+	uint8_t enable;
+	int16_t table[VFE_LA_TABLE_LENGTH];
+};
+
+#define VFE_GAMMA_TABLE_LENGTH 256
+enum VFE_RGB_GAMMA_TABLE_SELECT {
+	RGB_GAMMA_CH0_SELECTED,
+	RGB_GAMMA_CH1_SELECTED,
+	RGB_GAMMA_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_SELECTED,
+	RGB_GAMMA_CH0_CH2_SELECTED,
+	RGB_GAMMA_CH1_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_CH2_SELECTED
+};
+
+struct vfe_cmd_rgb_gamma_config {
+	uint8_t enable;
+	enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect;
+	int16_t table[VFE_GAMMA_TABLE_LENGTH];
+};
+
+struct vfe_cmd_chroma_enhan_config {
+	uint8_t  enable;
+	int16_t am;
+	int16_t ap;
+	int16_t bm;
+	int16_t bp;
+	int16_t cm;
+	int16_t cp;
+	int16_t dm;
+	int16_t dp;
+	int16_t kcr;
+	int16_t kcb;
+	int16_t RGBtoYConversionV0;
+	int16_t RGBtoYConversionV1;
+	int16_t RGBtoYConversionV2;
+	uint8_t RGBtoYConversionOffset;
+};
+
+struct vfe_cmd_chroma_suppression_config {
+	uint8_t enable;
+	uint8_t m1;
+	uint8_t m3;
+	uint8_t n1;
+	uint8_t n3;
+	uint8_t nn1;
+	uint8_t mm1;
+};
+
+struct vfe_cmd_asf_config {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t sharpThreshE2;
+	int8_t sharpThreshE3;
+	int8_t sharpThreshE4;
+	int8_t sharpThreshE5;
+	int8_t filter1Coefficients[9];
+	int8_t filter2Coefficients[9];
+	uint8_t  cropEnable;
+	uint16_t cropFirstPixel;
+	uint16_t cropLastPixel;
+	uint16_t cropFirstLine;
+	uint16_t cropLastLine;
+};
+
+struct vfe_cmd_asf_update {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t  sharpThreshE2;
+	int8_t  sharpThreshE3;
+	int8_t  sharpThreshE4;
+	int8_t  sharpThreshE5;
+	int8_t  filter1Coefficients[9];
+	int8_t  filter2Coefficients[9];
+	uint8_t cropEnable;
+};
+
+enum VFE_TEST_GEN_SYNC_EDGE {
+	VFE_TEST_GEN_SYNC_EDGE_ActiveHigh,
+	VFE_TEST_GEN_SYNC_EDGE_ActiveLow
+};
+
+
+struct vfe_cmd_bus_pm_start {
+	uint8_t output2YWrPmEnable;
+	uint8_t output2CbcrWrPmEnable;
+	uint8_t output1YWrPmEnable;
+	uint8_t output1CbcrWrPmEnable;
+};
+
+struct vfe_cmd_sync_timer_setting {
+	uint8_t  whichSyncTimer;
+	uint8_t  operation;
+	uint8_t  polarity;
+	uint16_t repeatCount;
+	uint16_t hsyncCount;
+	uint32_t pclkCount;
+	uint32_t outputDuration;
+};
+
+struct vfe_cmd_async_timer_setting {
+	uint8_t  whichAsyncTimer;
+	uint8_t  operation;
+	uint8_t  polarity;
+	uint16_t repeatCount;
+	uint16_t inactiveCount;
+	uint32_t activeCount;
+};
+
+struct  vfe_frame_skip_counts {
+	uint32_t  totalFrameCount;
+	uint32_t  output1Count;
+	uint32_t  output2Count;
+};
+
+enum VFE_AXI_RD_UNPACK_HBI_SEL {
+	VFE_AXI_RD_HBI_32_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_64_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_128_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_256_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_512_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_1024_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_2048_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_4096_CLOCK_CYCLES
+};
+
+enum VFE31_MESSAGE_ID {
+	MSG_ID_RESET_ACK,
+	MSG_ID_START_ACK,
+	MSG_ID_STOP_ACK,
+	MSG_ID_UPDATE_ACK,
+	MSG_ID_OUTPUT_P,
+	MSG_ID_OUTPUT_T,
+	MSG_ID_OUTPUT_S,
+	MSG_ID_OUTPUT_V,
+	MSG_ID_SNAPSHOT_DONE,
+	MSG_ID_STATS_AEC,
+	MSG_ID_STATS_AF,
+	MSG_ID_STATS_AWB, /* 8 */
+	MSG_ID_STATS_RS,
+	MSG_ID_STATS_CS,
+	MSG_ID_STATS_IHIST,
+	MSG_ID_STATS_SKIN,
+	MSG_ID_EPOCH1,
+	MSG_ID_EPOCH2,
+	MSG_ID_SYNC_TIMER0_DONE,
+	MSG_ID_SYNC_TIMER1_DONE,
+	MSG_ID_SYNC_TIMER2_DONE,
+	MSG_ID_ASYNC_TIMER0_DONE,
+	MSG_ID_ASYNC_TIMER1_DONE,
+	MSG_ID_ASYNC_TIMER2_DONE,
+	MSG_ID_ASYNC_TIMER3_DONE,
+	MSG_ID_AE_OVERFLOW,
+	MSG_ID_AF_OVERFLOW,
+	MSG_ID_AWB_OVERFLOW,
+	MSG_ID_RS_OVERFLOW,
+	MSG_ID_CS_OVERFLOW,
+	MSG_ID_IHIST_OVERFLOW,
+	MSG_ID_SKIN_OVERFLOW,
+	MSG_ID_AXI_ERROR,
+	MSG_ID_CAMIF_OVERFLOW,
+	MSG_ID_VIOLATION,
+	MSG_ID_CAMIF_ERROR,
+	MSG_ID_BUS_OVERFLOW,
+};
+
+struct vfe_msg_stats{
+	uint32_t    buffer;
+	uint32_t    frameCounter;
+};
+
+
+struct vfe_frame_bpc_info {
+	uint32_t greenDefectPixelCount;
+	uint32_t redBlueDefectPixelCount;
+};
+
+struct vfe_frame_asf_info {
+	uint32_t  asfMaxEdge;
+	uint32_t  asfHbiCount;
+};
+
+struct vfe_msg_camif_status {
+	uint8_t  camifState;
+	uint32_t pixelCount;
+	uint32_t lineCount;
+};
+
+
+struct vfe31_irq_status {
+	uint32_t vfeIrqStatus0;
+	uint32_t vfeIrqStatus1;
+	uint32_t camifStatus;
+	uint32_t demosaicStatus;
+	uint32_t asfMaxEdge;
+};
+
+struct vfe_msg_output {
+	uint8_t   output_id;
+	uint32_t  yBuffer;
+	uint32_t  cbcrBuffer;
+	struct vfe_frame_bpc_info bpcInfo;
+	struct vfe_frame_asf_info asfInfo;
+	uint32_t  frameCounter;
+};
+
+struct vfe_message {
+	enum VFE31_MESSAGE_ID _d;
+	union {
+		struct vfe_msg_output              msgOut;
+		struct vfe_msg_stats               msgStats;
+		struct vfe_msg_camif_status        msgCamifError;
+   } _u;
+};
+
+/* New one for 7x30 */
+struct msm_vfe31_cmd {
+	int32_t  id;
+	uint16_t length;
+	void     *value;
+};
+
+#define V31_PREVIEW_AXI_FLAG  0x00000001
+#define V31_SNAPSHOT_AXI_FLAG (0x00000001<<1)
+
+struct vfe31_cmd_type {
+	uint16_t id;
+	uint32_t length;
+	uint32_t offset;
+	uint32_t flag;
+};
+
+struct vfe31_free_buf {
+	spinlock_t f_lock;
+	uint8_t available;
+	uint32_t paddr;
+	uint32_t y_off;
+	uint32_t cbcr_off;
+};
+
+struct vfe31_output_ch {
+	struct vfe31_free_buf free_buf;
+	uint16_t output_fmt;
+	int8_t ch0;
+	int8_t ch1;
+	int8_t ch2;
+	uint32_t  capture_cnt;
+	uint32_t  frame_drop_cnt;
+};
+
+/* no error irq in mask 0 */
+#define VFE31_IMASK_ERROR_ONLY_0  0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE31_IMASK_ERROR_ONLY_1  0x003fffff
+
+struct vfe31_output_path {
+	uint16_t output_mode;     /* bitmask  */
+
+	struct vfe31_output_ch out0; /* preview and thumbnail */
+	struct vfe31_output_ch out1; /* snapshot */
+	struct vfe31_output_ch out2; /* video    */
+};
+
+struct vfe31_frame_extra {
+	uint32_t greenDefectPixelCount;
+	uint32_t redBlueDefectPixelCount;
+
+	uint32_t  asfMaxEdge;
+	uint32_t  asfHbiCount;
+
+	uint32_t yWrPmStats0;
+	uint32_t yWrPmStats1;
+	uint32_t cbcrWrPmStats0;
+	uint32_t cbcrWrPmStats1;
+
+	uint32_t  frameCounter;
+};
+
+#define VFE_DISABLE_ALL_IRQS              0
+#define VFE_CLEAR_ALL_IRQS                0xffffffff
+
+#define VFE_VERSION                       0x00000000
+#define VFE_GLOBAL_RESET                  0x00000004
+#define VFE_CGC_OVERRIDE                  0x0000000C
+#define VFE_MODULE_CFG                    0x00000010
+#define VFE_CFG_OFF                       0x00000014
+#define VFE_IRQ_CMD                       0x00000018
+#define VFE_IRQ_MASK_0                    0x0000001C
+#define VFE_IRQ_MASK_1                    0x00000020
+#define VFE_IRQ_CLEAR_0                   0x00000024
+#define VFE_IRQ_CLEAR_1                   0x00000028
+#define VFE_IRQ_STATUS_0                  0x0000002C
+#define VFE_IRQ_STATUS_1                  0x00000030
+#define VFE_IRQ_COMP_MASK                 0x00000034
+#define VFE_BUS_CMD                       0x00000038
+#define VFE_AXI_OFFSET                    0x00000050
+#define VFE_BUS_STATS_PING_PONG_BASE      0x000000F4
+#define VFE_BUS_STATS_AEC_WR_PING_ADDR    0x000000F4
+#define VFE_BUS_STATS_AEC_WR_PONG_ADDR    0x000000F8
+#define VFE_BUS_STATS_AEC_UB_CFG          0x000000FC
+#define VFE_BUS_STATS_AF_WR_PING_ADDR     0x00000100
+#define VFE_BUS_STATS_AF_WR_PONG_ADDR     0x00000104
+#define VFE_BUS_STATS_AF_UB_CFG           0x00000108
+#define VFE_BUS_STATS_AWB_WR_PING_ADDR    0x0000010C
+#define VFE_BUS_STATS_AWB_WR_PONG_ADDR    0x00000110
+#define VFE_BUS_STATS_AWB_UB_CFG          0x00000114
+#define VFE_BUS_STATS_RS_WR_PING_ADDR     0x00000118
+#define VFE_BUS_STATS_RS_WR_PONG_ADDR     0x0000011C
+#define VFE_BUS_STATS_RS_UB_CFG           0x00000120
+#define VFE_BUS_STATS_CS_WR_PING_ADDR     0x00000124
+#define VFE_BUS_STATS_CS_WR_PONG_ADDR     0x00000128
+#define VFE_BUS_STATS_CS_UB_CFG           0x0000012C
+#define VFE_BUS_STATS_HIST_WR_PING_ADDR   0x00000130
+#define VFE_BUS_STATS_HIST_WR_PONG_ADDR   0x00000134
+#define VFE_BUS_STATS_HIST_UB_CFG         0x00000138
+#define VFE_BUS_STATS_SKIN_WR_PING_ADDR   0x0000013C
+#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR   0x00000140
+#define VFE_BUS_STATS_SKIN_UB_CFG         0x00000144
+#define VFE_BUS_PING_PONG_STATUS          0x00000180
+#define VFE_AXI_CMD                       0x000001D8
+#define VFE_AXI_STATUS                    0x000001DC
+#define VFE_CAMIF_COMMAND                 0x000001E0
+#define VFE_CAMIF_STATUS                  0x00000204
+#define VFE_REG_UPDATE_CMD                0x00000260
+#define VFE_DEMUX_GAIN_0                  0x00000288
+#define VFE_DEMUX_GAIN_1                  0x0000028C
+#define VFE_CHROMA_UP                     0x0000035C
+#define VFE_FRAMEDROP_ENC_Y_CFG           0x00000504
+#define VFE_FRAMEDROP_ENC_CBCR_CFG        0x00000508
+#define VFE_FRAMEDROP_ENC_Y_PATTERN       0x0000050C
+#define VFE_FRAMEDROP_ENC_CBCR_PATTERN    0x00000510
+#define VFE_FRAMEDROP_VIEW_Y              0x00000514
+#define VFE_FRAMEDROP_VIEW_CBCR           0x00000518
+#define VFE_FRAMEDROP_VIEW_Y_PATTERN      0x0000051C
+#define VFE_FRAMEDROP_VIEW_CBCR_PATTERN   0x00000520
+#define VFE_CLAMP_MAX                     0x00000524
+#define VFE_CLAMP_MIN                     0x00000528
+#define VFE_REALIGN_BUF                   0x0000052C
+#define VFE_STATS_CFG                     0x00000530
+#define VFE_DMI_CFG                       0x00000598
+#define VFE_DMI_ADDR                      0x0000059C
+#define VFE_DMI_DATA_LO                   0x000005A4
+
+struct vfe_stats_control {
+	uint8_t  ackPending;
+	uint32_t nextFrameAddrBuf;
+	uint32_t droppedStatsFrameCount;
+	uint32_t bufToRender;
+};
+
+struct vfe31_ctrl_type {
+	uint16_t operation_mode;     /* streaming or snapshot */
+	struct vfe31_output_path outpath;
+
+	uint32_t vfeImaskCompositePacked;
+
+	spinlock_t  stop_flag_lock;  /* protects stop_ack_pending */
+	spinlock_t  update_ack_lock; /* protects update_ack_pending */
+	spinlock_t  state_lock;      /* protects vstate */
+	spinlock_t  aec_ack_lock;    /* protects aecStatsControl.ackPending */
+	spinlock_t  awb_ack_lock;    /* protects awbStatsControl.ackPending */
+	spinlock_t  af_ack_lock;     /* protects afStatsControl.ackPending */
+	spinlock_t  ihist_ack_lock;  /* protects ihistStatsControl.ackPending */
+	spinlock_t  rs_ack_lock;     /* protects rsStatsControl.ackPending */
+	spinlock_t  cs_ack_lock;     /* protects csStatsControl.ackPending */
+
+	struct msm_vfe_callback *resp;
+	uint32_t extlen;
+	void *extdata;
+
+	int8_t start_ack_pending;
+	int8_t stop_ack_pending;
+	int8_t reset_ack_pending;
+	int8_t update_ack_pending;
+	int8_t req_start_video_rec;
+	int8_t req_stop_video_rec;
+
+	spinlock_t tasklet_lock;
+	struct list_head tasklet_q;
+	int vfeirq;
+	void __iomem *vfebase;
+	void *syncdata;
+
+	struct resource	*vfemem;
+	struct resource *vfeio;
+
+	uint32_t stats_comp;
+	uint8_t vstate;
+	uint32_t vfe_capture_count;
+
+	uint32_t vfeFrameId;
+	uint32_t output1Pattern;
+	uint32_t output1Period;
+	uint32_t output2Pattern;
+	uint32_t output2Period;
+	uint32_t vfeFrameSkipCount;
+	uint32_t vfeFrameSkipPeriod;
+	struct vfe_stats_control afStatsControl;
+	struct vfe_stats_control awbStatsControl;
+	struct vfe_stats_control aecStatsControl;
+	struct vfe_stats_control ihistStatsControl;
+	struct vfe_stats_control rsStatsControl;
+	struct vfe_stats_control csStatsControl;
+};
+
+#define statsAeNum      0
+#define statsAfNum      1
+#define statsAwbNum     2
+#define statsRsNum      3
+#define statsCsNum      4
+#define statsIhistNum   5
+#define statsSkinNum    6
+
+struct vfe_cmd_stats_ack{
+	uint32_t nextStatsBuf;
+};
+
+#define VFE_STATS_BUFFER_COUNT            3
+
+struct vfe_cmd_stats_buf{
+	uint32_t statsBuf[VFE_STATS_BUFFER_COUNT];
+};
+
+#define VFE31_OUTPUT_MODE_PT (0x1 << 0)
+#define VFE31_OUTPUT_MODE_S (0x1 << 1)
+#define VFE31_OUTPUT_MODE_V (0x1 << 2)
+
+#endif /* __MSM_VFE31_H__ */
diff --git a/drivers/media/video/msm/msm_vfe7x.c b/drivers/media/video/msm/msm_vfe7x.c
new file mode 100644
index 0000000..0812bf5
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe7x.c
@@ -0,0 +1,712 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/msm_adsp.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/android_pmem.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/clk.h>
+#include <mach/msm_adsp.h>
+#include "msm_vfe7x.h"
+
+#define QDSP_CMDQUEUE QDSP_vfeCommandQueue
+
+#define VFE_RESET_CMD 0
+#define VFE_START_CMD 1
+#define VFE_STOP_CMD  2
+#define VFE_FRAME_ACK 20
+#define STATS_AF_ACK  21
+#define STATS_WE_ACK  22
+
+#define MSG_STOP_ACK  1
+#define MSG_SNAPSHOT  2
+#define MSG_OUTPUT1   6
+#define MSG_OUTPUT2   7
+#define MSG_STATS_AF  8
+#define MSG_STATS_WE  9
+
+static struct msm_adsp_module *qcam_mod;
+static struct msm_adsp_module *vfe_mod;
+static struct msm_vfe_callback *resp;
+static struct vfe_frame_extra *extdata;
+
+struct mutex vfe_lock;
+static void *vfe_syncdata;
+static uint8_t vfestopped;
+
+static struct stop_event stopevent;
+
+static struct clk *ebi1_clk;
+static const char *const ebi1_clk_name = "ebi1_clk";
+
+static void vfe_7x_convert(struct msm_vfe_phy_info *pinfo,
+			   enum vfe_resp_msg type,
+			   void *data, void **ext, int *elen)
+{
+	switch (type) {
+	case VFE_MSG_OUTPUT1:
+	case VFE_MSG_OUTPUT2:{
+			pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
+			pinfo->cbcr_phy =
+			    ((struct vfe_endframe *)data)->cbcr_address;
+
+			CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
+			     pinfo->y_phy, pinfo->cbcr_phy);
+
+			((struct vfe_frame_extra *)extdata)->bl_evencol =
+			    ((struct vfe_endframe *)data)->blacklevelevencolumn;
+
+			((struct vfe_frame_extra *)extdata)->bl_oddcol =
+			    ((struct vfe_endframe *)data)->blackleveloddcolumn;
+
+			((struct vfe_frame_extra *)extdata)->g_def_p_cnt =
+			    ((struct vfe_endframe *)data)->
+			    greendefectpixelcount;
+
+			((struct vfe_frame_extra *)extdata)->r_b_def_p_cnt =
+			    ((struct vfe_endframe *)data)->
+			    redbluedefectpixelcount;
+
+			*ext = extdata;
+			*elen = sizeof(*extdata);
+		}
+		break;
+
+	case VFE_MSG_STATS_AF:
+	case VFE_MSG_STATS_WE:
+		pinfo->sbuf_phy = *(uint32_t *) data;
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
+		       void (*getevent) (void *ptr, size_t len))
+{
+	uint32_t evt_buf[3];
+	struct msm_vfe_resp *rp;
+	void *data;
+
+	len = (id == (uint16_t)-1) ? 0 : len;
+	data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len,
+			vfe_syncdata,
+			GFP_ATOMIC);
+
+	if (!data) {
+		pr_err("rp: cannot allocate buffer\n");
+		return;
+	}
+	rp = (struct msm_vfe_resp *)data;
+	rp->evt_msg.len = len;
+
+	if (id == ((uint16_t)-1)) {
+		/* event */
+		rp->type = VFE_EVENT;
+		rp->evt_msg.type = MSM_CAMERA_EVT;
+		getevent(evt_buf, sizeof(evt_buf));
+		rp->evt_msg.msg_id = evt_buf[0];
+		resp->vfe_resp(rp, MSM_CAM_Q_VFE_EVT,
+				vfe_syncdata,
+				GFP_ATOMIC);
+	} else {
+		/* messages */
+		rp->evt_msg.type = MSM_CAMERA_MSG;
+		rp->evt_msg.msg_id = id;
+		rp->evt_msg.data = rp + 1;
+		getevent(rp->evt_msg.data, len);
+
+		switch (rp->evt_msg.msg_id) {
+		case MSG_SNAPSHOT:
+			rp->type = VFE_MSG_SNAPSHOT;
+			break;
+
+		case MSG_OUTPUT1:
+			rp->type = VFE_MSG_OUTPUT1;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT1,
+				       rp->evt_msg.data, &(rp->extdata),
+				       &(rp->extlen));
+			break;
+
+		case MSG_OUTPUT2:
+			rp->type = VFE_MSG_OUTPUT2;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT2,
+				       rp->evt_msg.data, &(rp->extdata),
+				       &(rp->extlen));
+			break;
+
+		case MSG_STATS_AF:
+			rp->type = VFE_MSG_STATS_AF;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF,
+				       rp->evt_msg.data, NULL, NULL);
+			break;
+
+		case MSG_STATS_WE:
+			rp->type = VFE_MSG_STATS_WE;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE,
+				       rp->evt_msg.data, NULL, NULL);
+
+			CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy);
+			break;
+
+		case MSG_STOP_ACK:
+			rp->type = VFE_MSG_GENERAL;
+			stopevent.state = 1;
+			wake_up(&stopevent.wait);
+			break;
+
+		default:
+			rp->type = VFE_MSG_GENERAL;
+			break;
+		}
+		resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata, GFP_ATOMIC);
+	}
+}
+
+static struct msm_adsp_ops vfe_7x_sync = {
+	.event = vfe_7x_ops,
+};
+
+static int vfe_7x_enable(struct camera_enable_cmd *enable)
+{
+	int rc = -EFAULT;
+
+	if (!strcmp(enable->name, "QCAMTASK"))
+		rc = msm_adsp_enable(qcam_mod);
+	else if (!strcmp(enable->name, "VFETASK"))
+		rc = msm_adsp_enable(vfe_mod);
+
+	return rc;
+}
+
+static int vfe_7x_disable(struct camera_enable_cmd *enable,
+			  struct platform_device *dev __attribute__ ((unused)))
+{
+	int rc = -EFAULT;
+
+	if (!strcmp(enable->name, "QCAMTASK"))
+		rc = msm_adsp_disable(qcam_mod);
+	else if (!strcmp(enable->name, "VFETASK"))
+		rc = msm_adsp_disable(vfe_mod);
+
+	return rc;
+}
+
+static int vfe_7x_stop(void)
+{
+	int rc = 0;
+	uint32_t stopcmd = VFE_STOP_CMD;
+	rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE, &stopcmd, sizeof(uint32_t));
+	if (rc < 0) {
+		CDBG("%s:%d: failed rc = %d \n", __func__, __LINE__, rc);
+		return rc;
+	}
+
+	stopevent.state = 0;
+	rc = wait_event_timeout(stopevent.wait,
+				stopevent.state != 0,
+				msecs_to_jiffies(stopevent.timeout));
+
+	return rc;
+}
+
+static void vfe_7x_release(struct platform_device *pdev)
+{
+	struct msm_sensor_ctrl *sctrl =
+		&((struct msm_sync *)vfe_syncdata)->sctrl;
+
+	mutex_lock(&vfe_lock);
+	vfe_syncdata = NULL;
+	mutex_unlock(&vfe_lock);
+
+	if (!vfestopped) {
+		CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__);
+		vfe_7x_stop();
+	} else
+		vfestopped = 0;
+
+	msm_adsp_disable(qcam_mod);
+	msm_adsp_disable(vfe_mod);
+
+	if (sctrl)
+		sctrl->s_release();
+
+	msm_adsp_put(qcam_mod);
+	msm_adsp_put(vfe_mod);
+
+	msm_camio_disable(pdev);
+
+	if (ebi1_clk) {
+		clk_set_rate(ebi1_clk, 0);
+		clk_put(ebi1_clk);
+		ebi1_clk = 0;
+	}
+
+	kfree(extdata);
+	extdata = 0;
+}
+
+static int vfe_7x_init(struct msm_vfe_callback *presp,
+		       struct platform_device *dev)
+{
+	int rc = 0;
+
+	init_waitqueue_head(&stopevent.wait);
+	stopevent.timeout = 200;
+	stopevent.state = 0;
+
+	if (presp && presp->vfe_resp)
+		resp = presp;
+	else
+		return -EIO;
+
+	ebi1_clk = clk_get(NULL, ebi1_clk_name);
+	if (!ebi1_clk) {
+		pr_err("%s: could not get %s\n", __func__, ebi1_clk_name);
+		return -EIO;
+	}
+
+	rc = clk_set_rate(ebi1_clk, 128000000);
+	if (rc < 0) {
+		pr_err("%s: clk_set_rate(%s) failed: %d\n", __func__,
+			ebi1_clk_name, rc);
+		return rc;
+	}
+
+	/* Bring up all the required GPIOs and Clocks */
+	rc = msm_camio_enable(dev);
+	if (rc < 0)
+		return rc;
+
+	msm_camio_camif_pad_reg_reset();
+
+	extdata = kmalloc(sizeof(struct vfe_frame_extra), GFP_ATOMIC);
+	if (!extdata) {
+		rc = -ENOMEM;
+		goto init_fail;
+	}
+
+	rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
+	if (rc) {
+		rc = -EBUSY;
+		goto get_qcam_fail;
+	}
+
+	rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
+	if (rc) {
+		rc = -EBUSY;
+		goto get_vfe_fail;
+	}
+
+	return 0;
+
+get_vfe_fail:
+	msm_adsp_put(qcam_mod);
+get_qcam_fail:
+	kfree(extdata);
+init_fail:
+	return rc;
+}
+
+static int vfe_7x_config_axi(int mode, struct axidata *ad, struct axiout *ao)
+{
+	struct msm_pmem_region *regptr;
+	unsigned long *bptr;
+	int cnt;
+
+	int rc = 0;
+
+	if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
+		regptr = ad->region;
+
+		CDBG("bufnum1 = %d\n", ad->bufnum1);
+		CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
+		     regptr->paddr, regptr->info.y_off, regptr->info.cbcr_off);
+
+		bptr = &ao->output1buffer1_y_phy;
+		for (cnt = 0; cnt < ad->bufnum1; cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+
+			bptr++;
+			regptr++;
+		}
+
+		regptr--;
+		for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+			bptr++;
+		}
+	}
+	/* if OUTPUT1 or Both */
+	if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
+		regptr = &(ad->region[ad->bufnum1]);
+
+		CDBG("bufnum2 = %d\n", ad->bufnum2);
+		CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
+		     regptr->paddr, regptr->info.y_off, regptr->info.cbcr_off);
+
+		bptr = &ao->output2buffer1_y_phy;
+		for (cnt = 0; cnt < ad->bufnum2; cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+
+			bptr++;
+			regptr++;
+		}
+
+		regptr--;
+		for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+			bptr++;
+		}
+	}
+
+	return rc;
+}
+
+static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data)
+{
+	int rc = 0;
+	int i;
+
+	struct msm_pmem_region *regptr = NULL;
+
+	struct vfe_stats_ack sack;
+	struct axidata *axid = NULL;
+
+	struct axiout axio;
+	void *cmd_data_alloc = NULL;
+	struct msm_vfe_command_7k vfecmd;
+
+	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+	    cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+	    cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+		if (copy_from_user(&vfecmd,
+				   (void __user *)(cmd->value),
+				   sizeof(struct msm_vfe_command_7k))) {
+			rc = -EFAULT;
+			goto config_error;
+		}
+	}
+
+	switch (cmd->cmd_type) {
+	case CMD_STATS_AEC_AWB_ENABLE:
+	case CMD_STATS_AXI_CFG:{
+			struct vfe_stats_we_cfg scfg;
+			axid = data;
+			if (!axid) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			if (vfecmd.length != sizeof(typeof(scfg))) {
+				rc = -EIO;
+				pr_err
+				    ("msm_camera: %s: cmd %d: "\
+				     "user-space data size %d "\
+				     "!= kernel data size %d\n", __func__,
+				     cmd->cmd_type, vfecmd.length,
+				     sizeof(typeof(scfg)));
+				goto config_error;
+			}
+
+			if (copy_from_user(&scfg,
+					   (void __user *)(vfecmd.value),
+					   vfecmd.length)) {
+
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n",
+			     axid->bufnum1, scfg.wb_expstatsenable);
+
+			if (axid->bufnum1 > 0) {
+				regptr = axid->region;
+
+				for (i = 0; i < axid->bufnum1; i++) {
+
+					CDBG("STATS_ENABLE, phy = 0x%lx\n",
+					     regptr->paddr);
+
+					scfg.wb_expstatoutputbuffer[i] =
+					    (void *)regptr->paddr;
+					regptr++;
+				}
+
+				vfecmd.value = &scfg;
+
+			} else {
+				rc = -EINVAL;
+				goto config_error;
+			}
+		}
+		break;
+
+	case CMD_STATS_AF_ENABLE:
+	case CMD_STATS_AF_AXI_CFG:{
+			struct vfe_stats_af_cfg sfcfg;
+			axid = data;
+			if (!axid) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			if (vfecmd.length > sizeof(typeof(sfcfg))) {
+				pr_err
+				    ("msm_camera: %s: cmd %d: user-space "\
+				     "data %d exceeds kernel buffer %d\n",
+				     __func__, cmd->cmd_type, vfecmd.length,
+				     sizeof(typeof(sfcfg)));
+				rc = -EIO;
+				goto config_error;
+			}
+
+			if (copy_from_user(&sfcfg,
+					   (void __user *)(vfecmd.value),
+					   vfecmd.length)) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
+			     axid->bufnum1, sfcfg.af_enable);
+
+			if (axid->bufnum1 > 0) {
+				regptr = axid->region;
+
+				for (i = 0; i < axid->bufnum1; i++) {
+
+					CDBG("STATS_ENABLE, phy = 0x%lx\n",
+					     regptr->paddr);
+
+					sfcfg.af_outbuf[i] =
+					    (void *)regptr->paddr;
+
+					regptr++;
+				}
+
+				vfecmd.value = &sfcfg;
+
+			} else {
+				rc = -EINVAL;
+				goto config_error;
+			}
+		}
+		break;
+
+	case CMD_FRAME_BUF_RELEASE:{
+			struct msm_frame *b;
+			unsigned long p;
+			struct vfe_outputack fack;
+			if (!data) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			b = (struct msm_frame *)(cmd->value);
+			p = *(unsigned long *)data;
+
+			fack.header = VFE_FRAME_ACK;
+
+			fack.output2newybufferaddress = (void *)(p + b->y_off);
+
+			fack.output2newcbcrbufferaddress =
+			    (void *)(p + b->cbcr_off);
+
+			vfecmd.queue = QDSP_CMDQUEUE;
+			vfecmd.length = sizeof(struct vfe_outputack);
+			vfecmd.value = &fack;
+		}
+		break;
+
+	case CMD_SNAP_BUF_RELEASE:
+		break;
+
+	case CMD_STATS_BUF_RELEASE:{
+			CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n");
+			if (!data) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			sack.header = STATS_WE_ACK;
+			sack.bufaddr = (void *)*(uint32_t *) data;
+
+			vfecmd.queue = QDSP_CMDQUEUE;
+			vfecmd.length = sizeof(struct vfe_stats_ack);
+			vfecmd.value = &sack;
+		}
+		break;
+
+	case CMD_STATS_AF_BUF_RELEASE:{
+			CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n");
+			if (!data) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			sack.header = STATS_AF_ACK;
+			sack.bufaddr = (void *)*(uint32_t *) data;
+
+			vfecmd.queue = QDSP_CMDQUEUE;
+			vfecmd.length = sizeof(struct vfe_stats_ack);
+			vfecmd.value = &sack;
+		}
+		break;
+
+	case CMD_GENERAL:
+	case CMD_STATS_DISABLE:{
+			uint8_t buf[256];
+			void *tmp = buf;
+			if (vfecmd.length > sizeof(buf)) {
+				cmd_data_alloc = tmp =
+				    kmalloc(vfecmd.length, GFP_ATOMIC);
+				if (!cmd_data_alloc) {
+					rc = -ENOMEM;
+					goto config_error;
+				}
+			}
+
+			if (copy_from_user(tmp,
+					   (void __user *)(vfecmd.value),
+					   vfecmd.length)) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+			vfecmd.value = tmp;
+
+			if (vfecmd.queue == QDSP_CMDQUEUE) {
+				switch (*(uint32_t *) vfecmd.value) {
+				case VFE_RESET_CMD:
+					msm_camio_vfe_blk_reset();
+					msm_camio_camif_pad_reg_reset_2();
+					vfestopped = 0;
+					break;
+
+				case VFE_START_CMD:
+					msm_camio_camif_pad_reg_reset_2();
+					vfestopped = 0;
+					break;
+
+				case VFE_STOP_CMD:
+					vfestopped = 1;
+					goto config_send;
+
+				default:
+					break;
+				}
+			}	/* QDSP_CMDQUEUE */
+		}
+		break;
+
+	case CMD_AXI_CFG_OUT1:{
+			axid = data;
+			if (!axid) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			if (copy_from_user(&axio, (void *)(vfecmd.value),
+					   sizeof(axio))) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			vfe_7x_config_axi(OUTPUT_1, axid, &axio);
+
+			vfecmd.value = &axio;
+		}
+		break;
+
+	case CMD_AXI_CFG_OUT2:
+	case CMD_RAW_PICT_AXI_CFG:{
+			axid = data;
+			if (!axid) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			if (copy_from_user(&axio, (void __user *)(vfecmd.value),
+					   sizeof(axio))) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			vfe_7x_config_axi(OUTPUT_2, axid, &axio);
+			vfecmd.value = &axio;
+		}
+		break;
+
+	case CMD_AXI_CFG_SNAP_O1_AND_O2:{
+			axid = data;
+			if (!axid) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			if (copy_from_user(&axio, (void __user *)(vfecmd.value),
+					   sizeof(axio))) {
+				rc = -EFAULT;
+				goto config_error;
+			}
+
+			vfe_7x_config_axi(OUTPUT_1_AND_2, axid, &axio);
+
+			vfecmd.value = &axio;
+		}
+		break;
+
+	default:
+		break;
+	}			/* switch */
+
+	if (vfestopped)
+		goto config_error;
+
+config_send:
+	CDBG("send adsp command = %d\n", *(uint32_t *)vfecmd.value);
+	rc = msm_adsp_write(vfe_mod, vfecmd.queue, vfecmd.value, vfecmd.length);
+
+config_error:
+	kfree(cmd_data_alloc);
+	return rc;
+}
+
+void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
+{
+	mutex_init(&vfe_lock);
+	fptr->vfe_init = vfe_7x_init;
+	fptr->vfe_enable = vfe_7x_enable;
+	fptr->vfe_config = vfe_7x_config;
+	fptr->vfe_disable = vfe_7x_disable;
+	fptr->vfe_release = vfe_7x_release;
+	vfe_syncdata = data;
+}
diff --git a/drivers/media/video/msm/msm_vfe7x.h b/drivers/media/video/msm/msm_vfe7x.h
new file mode 100644
index 0000000..5e86ce0
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe7x.h
@@ -0,0 +1,269 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __MSM_VFE7X_H__
+#define __MSM_VFE7X_H__
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+
+struct vfe_frame_extra {
+	uint32_t bl_evencol;
+	uint32_t bl_oddcol;
+	uint16_t g_def_p_cnt;
+	uint16_t r_b_def_p_cnt;
+};
+
+struct vfe_endframe {
+	uint32_t y_address;
+	uint32_t cbcr_address;
+
+	unsigned int blacklevelevencolumn:23;
+	uint16_t reserved1:9;
+	unsigned int blackleveloddcolumn:23;
+	uint16_t reserved2:9;
+
+	uint16_t greendefectpixelcount:8;
+	uint16_t reserved3:8;
+	uint16_t redbluedefectpixelcount:8;
+	uint16_t reserved4:8;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_outputack {
+	uint32_t header;
+	void *output2newybufferaddress;
+	void *output2newcbcrbufferaddress;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_stats_ack {
+	uint32_t header;
+	/* MUST BE 64 bit ALIGNED */
+	void *bufaddr;
+} __attribute__ ((packed, aligned(4)));
+
+/* AXI Output Config Command sent to DSP */
+struct axiout {
+	uint32_t cmdheader:32;
+	int outputmode:3;
+	uint8_t format:2;
+	 uint32_t /* reserved */ : 27;
+
+	/* AXI Output 1 Y Configuration, Part 1 */
+	uint32_t out1yimageheight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out1yimagewidthin64bitwords:10;
+	 uint32_t /* reserved */ : 6;
+
+	/* AXI Output 1 Y Configuration, Part 2 */
+	uint8_t out1yburstlen:2;
+	uint32_t out1ynumrows:12;
+	uint32_t out1yrowincin64bitincs:12;
+	 uint32_t /* reserved */ : 6;
+
+	/* AXI Output 1 CbCr Configuration, Part 1 */
+	uint32_t out1cbcrimageheight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out1cbcrimagewidthin64bitwords:10;
+	 uint32_t /* reserved */ : 6;
+
+	/* AXI Output 1 CbCr Configuration, Part 2 */
+	uint8_t out1cbcrburstlen:2;
+	uint32_t out1cbcrnumrows:12;
+	uint32_t out1cbcrrowincin64bitincs:12;
+	 uint32_t /* reserved */ : 6;
+
+	/* AXI Output 2 Y Configuration, Part 1 */
+	uint32_t out2yimageheight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out2yimagewidthin64bitwords:10;
+	 uint32_t /* reserved */ : 6;
+
+	/* AXI Output 2 Y Configuration, Part 2 */
+	uint8_t out2yburstlen:2;
+	uint32_t out2ynumrows:12;
+	uint32_t out2yrowincin64bitincs:12;
+	 uint32_t /* reserved */ : 6;
+
+	/* AXI Output 2 CbCr Configuration, Part 1 */
+	uint32_t out2cbcrimageheight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out2cbcrimagewidtein64bitwords:10;
+	 uint32_t /* reserved */ : 6;
+
+	/* AXI Output 2 CbCr Configuration, Part 2 */
+	uint8_t out2cbcrburstlen:2;
+	uint32_t out2cbcrnumrows:12;
+	uint32_t out2cbcrrowincin64bitincs:12;
+	 uint32_t /* reserved */ : 6;
+
+	/* Address configuration:
+	 * output1 phisycal address */
+	unsigned long output1buffer1_y_phy;
+	unsigned long output1buffer1_cbcr_phy;
+	unsigned long output1buffer2_y_phy;
+	unsigned long output1buffer2_cbcr_phy;
+	unsigned long output1buffer3_y_phy;
+	unsigned long output1buffer3_cbcr_phy;
+	unsigned long output1buffer4_y_phy;
+	unsigned long output1buffer4_cbcr_phy;
+	unsigned long output1buffer5_y_phy;
+	unsigned long output1buffer5_cbcr_phy;
+	unsigned long output1buffer6_y_phy;
+	unsigned long output1buffer6_cbcr_phy;
+	unsigned long output1buffer7_y_phy;
+	unsigned long output1buffer7_cbcr_phy;
+	unsigned long output1buffer8_y_phy;
+	unsigned long output1buffer8_cbcr_phy;
+
+	/* output2 phisycal address */
+	unsigned long output2buffer1_y_phy;
+	unsigned long output2buffer1_cbcr_phy;
+	unsigned long output2buffer2_y_phy;
+	unsigned long output2buffer2_cbcr_phy;
+	unsigned long output2buffer3_y_phy;
+	unsigned long output2buffer3_cbcr_phy;
+	unsigned long output2buffer4_y_phy;
+	unsigned long output2buffer4_cbcr_phy;
+	unsigned long output2buffer5_y_phy;
+	unsigned long output2buffer5_cbcr_phy;
+	unsigned long output2buffer6_y_phy;
+	unsigned long output2buffer6_cbcr_phy;
+	unsigned long output2buffer7_y_phy;
+	unsigned long output2buffer7_cbcr_phy;
+	unsigned long output2buffer8_y_phy;
+	unsigned long output2buffer8_cbcr_phy;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_stats_we_cfg {
+	uint32_t header;
+
+	/* White Balance/Exposure Statistic Selection */
+	uint8_t wb_expstatsenable:1;
+	uint8_t wb_expstatbuspriorityselection:1;
+	unsigned int wb_expstatbuspriorityvalue:4;
+	unsigned int /* reserved */ : 26;
+
+	/* White Balance/Exposure Statistic Configuration, Part 1 */
+	uint8_t exposurestatregions:1;
+	uint8_t exposurestatsubregions:1;
+	unsigned int /* reserved */ : 14;
+
+	unsigned int whitebalanceminimumy:8;
+	unsigned int whitebalancemaximumy:8;
+
+	/* White Balance/Exposure Statistic Configuration, Part 2 */
+	 uint8_t
+	    wb_expstatslopeofneutralregionline[NUM_WB_EXP_NEUTRAL_REGION_LINES];
+
+	/* White Balance/Exposure Statistic Configuration, Part 3 */
+	unsigned int wb_expstatcrinterceptofneutralregionline2:12;
+	unsigned int /* reserved */ : 4;
+	unsigned int wb_expstatcbinterceptofneutralreginnline1:12;
+	unsigned int /* reserved */ : 4;
+
+	/* White Balance/Exposure Statistic Configuration, Part 4 */
+	unsigned int wb_expstatcrinterceptofneutralregionline4:12;
+	unsigned int /* reserved */ : 4;
+	unsigned int wb_expstatcbinterceptofneutralregionline3:12;
+	unsigned int /* reserved */ : 4;
+
+	/* White Balance/Exposure Statistic Output Buffer Header */
+	unsigned int wb_expmetricheaderpattern:8;
+	unsigned int /* reserved */ : 24;
+
+	/* White Balance/Exposure Statistic Output Buffers-MUST
+	 * BE 64 bit ALIGNED */
+	void *wb_expstatoutputbuffer[NUM_WB_EXP_STAT_OUTPUT_BUFFERS];
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_stats_af_cfg {
+	uint32_t header;
+
+	/* Autofocus Statistic Selection */
+	uint8_t af_enable:1;
+	uint8_t af_busprioritysel:1;
+	unsigned int af_buspriorityval:4;
+	unsigned int /* reserved */ : 26;
+
+	/* Autofocus Statistic Configuration, Part 1 */
+	unsigned int af_singlewinvoffset:12;
+	unsigned int /* reserved */ : 4;
+	unsigned int af_singlewinhoffset:12;
+	unsigned int /* reserved */ : 3;
+	uint8_t af_winmode:1;
+
+	/* Autofocus Statistic Configuration, Part 2 */
+	unsigned int af_singglewinvh:11;
+	unsigned int /* reserved */ : 5;
+	unsigned int af_singlewinhw:11;
+	unsigned int /* reserved */ : 5;
+
+	/* Autofocus Statistic Configuration, Parts 3-6 */
+	uint8_t af_multiwingrid[NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS];
+
+	/* Autofocus Statistic Configuration, Part 7 */
+	signed int af_metrichpfcoefa00:5;
+	signed int af_metrichpfcoefa04:5;
+	unsigned int af_metricmaxval:11;
+	uint8_t af_metricsel:1;
+	unsigned int /* reserved */ : 10;
+
+	/* Autofocus Statistic Configuration, Part 8 */
+	signed int af_metrichpfcoefa20:5;
+	signed int af_metrichpfcoefa21:5;
+	signed int af_metrichpfcoefa22:5;
+	signed int af_metrichpfcoefa23:5;
+	signed int af_metrichpfcoefa24:5;
+	unsigned int /* reserved */ : 7;
+
+	/* Autofocus Statistic Output Buffer Header */
+	unsigned int af_metrichp:8;
+	unsigned int /* reserved */ : 24;
+
+	/* Autofocus Statistic Output Buffers - MUST BE 64 bit ALIGNED!!! */
+	void *af_outbuf[NUM_AF_STAT_OUTPUT_BUFFERS];
+} __attribute__ ((packed, aligned(4)));	/* VFE_StatsAutofocusConfigCmdType */
+
+struct msm_camera_frame_msg {
+	unsigned long output_y_address;
+	unsigned long output_cbcr_address;
+
+	unsigned int blacklevelevenColumn:23;
+	uint16_t reserved1:9;
+	unsigned int blackleveloddColumn:23;
+	uint16_t reserved2:9;
+
+	uint16_t greendefectpixelcount:8;
+	uint16_t reserved3:8;
+	uint16_t redbluedefectpixelcount:8;
+	uint16_t reserved4:8;
+} __attribute__ ((packed, aligned(4)));
+
+/* New one for 7k */
+struct msm_vfe_command_7k {
+	uint16_t queue;
+	uint16_t length;
+	void *value;
+};
+
+struct stop_event {
+	wait_queue_head_t wait;
+	int state;
+	int timeout;
+};
+
+#endif /* __MSM_VFE7X_H__ */
diff --git a/drivers/media/video/msm/msm_vfe8x.c b/drivers/media/video/msm/msm_vfe8x.c
new file mode 100644
index 0000000..b4943be
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe8x.c
@@ -0,0 +1,727 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <mach/irqs.h>
+#include <linux/clk.h>
+#include "msm_vfe8x_proc.h"
+
+#define ON  1
+#define OFF 0
+
+static void *vfe_syncdata;
+static struct clk *ebi1_clk;
+static const char *const clk_name = "ebi1_clk";
+
+static int vfe_enable(struct camera_enable_cmd *enable)
+{
+	return 0;
+}
+
+static int vfe_disable(struct camera_enable_cmd *enable,
+		       struct platform_device *dev)
+{
+	vfe_stop();
+	msm_camio_disable(dev);
+	return 0;
+}
+
+static int vfe_init(struct msm_vfe_callback *presp, struct platform_device *dev)
+{
+	int rc = 0;
+
+	ebi1_clk = clk_get(NULL, clk_name);
+	if (!ebi1_clk) {
+		pr_err("%s: could not get %s\n", __func__, clk_name);
+		return -EIO;
+	}
+
+	rc = clk_set_rate(ebi1_clk, 128000000);
+	if (rc < 0) {
+		pr_err("%s: clk_set_rate(%s) failed: %d\n", __func__,
+			clk_name, rc);
+		return rc;
+	}
+
+	rc = vfe_cmd_init(presp, dev, vfe_syncdata);
+	if (rc < 0)
+		return rc;
+
+	/* Bring up all the required GPIOs and Clocks */
+	return msm_camio_enable(dev);
+}
+
+static void vfe_release(struct platform_device *dev)
+{
+	struct msm_sensor_ctrl *sctrl =
+		&((struct msm_sync *)vfe_syncdata)->sctrl;
+
+	if (ebi1_clk) {
+		clk_set_rate(ebi1_clk, 0);
+		clk_put(ebi1_clk);
+		ebi1_clk = 0;
+	}
+
+	if (sctrl)
+		sctrl->s_release();
+
+	msm_camio_disable(dev);
+	vfe_cmd_release(dev);
+	vfe_syncdata = NULL;
+}
+
+static void vfe_config_axi(int mode,
+			   struct axidata *ad,
+			   struct vfe_cmd_axi_output_config *ao)
+{
+	struct msm_pmem_region *regptr;
+	int i, j;
+	uint32_t *p1, *p2;
+
+	if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
+		regptr = ad->region;
+		for (i = 0; i < ad->bufnum1; i++) {
+
+			p1 = &(ao->output1.outputY.outFragments[i][0]);
+			p2 = &(ao->output1.outputCbcr.outFragments[i][0]);
+
+			for (j = 0; j < ao->output1.fragmentCount; j++) {
+
+				*p1 = regptr->paddr + regptr->info.y_off;
+				p1++;
+
+				*p2 = regptr->paddr + regptr->info.cbcr_off;
+				p2++;
+			}
+			regptr++;
+		}
+	}
+	/* if OUTPUT1 or Both */
+	if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
+
+		regptr = &(ad->region[ad->bufnum1]);
+		CDBG("bufnum2 = %d\n", ad->bufnum2);
+
+		for (i = 0; i < ad->bufnum2; i++) {
+
+			p1 = &(ao->output2.outputY.outFragments[i][0]);
+			p2 = &(ao->output2.outputCbcr.outFragments[i][0]);
+
+			CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, "\
+			     "cbcr_off = %d\n", regptr->paddr,
+			     regptr->info.y_off, regptr->info.cbcr_off);
+
+			for (j = 0; j < ao->output2.fragmentCount; j++) {
+
+				*p1 = regptr->paddr + regptr->info.y_off;
+				CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
+				p1++;
+
+				*p2 = regptr->paddr + regptr->info.cbcr_off;
+				CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
+				p2++;
+			}
+			regptr++;
+		}
+	}
+}
+
+#define ERR_COPY_FROM_USER() \
+	pr_err("%s(%d): copy from user\n", __func__, __LINE__)
+
+#define CHECKED_COPY_FROM_USER(in) {					\
+	if (cmd->length != sizeof(*(in))) {				\
+		pr_err("msm_camera: %s:%d cmd %d: user data size %d "	\
+			"!= kernel data size %d\n",			\
+			__func__, __LINE__,				\
+			cmd->id, cmd->length, sizeof(*(in)));		\
+		rc = -EIO;						\
+		break;							\
+	}								\
+	if (copy_from_user((in), (void __user *)cmd->value,		\
+			sizeof(*(in)))) {				\
+		ERR_COPY_FROM_USER();					\
+		rc = -EFAULT;						\
+		break;							\
+	}								\
+}
+
+static int vfe_proc_general(struct msm_vfe_command_8k *cmd)
+{
+	int rc = 0;
+
+	CDBG("%s: cmdID = %d\n", __func__, cmd->id);
+
+	switch (cmd->id) {
+	case VFE_CMD_ID_RESET:
+		msm_camio_vfe_blk_reset();
+		msm_camio_camif_pad_reg_reset_2();
+		vfe_reset();
+		break;
+
+	case VFE_CMD_ID_START:{
+			struct vfe_cmd_start start;
+			CHECKED_COPY_FROM_USER(&start);
+
+			/* msm_camio_camif_pad_reg_reset_2(); */
+			msm_camio_camif_pad_reg_reset();
+			vfe_start(&start);
+		}
+		break;
+
+	case VFE_CMD_ID_CAMIF_CONFIG:{
+			struct vfe_cmd_camif_config camif;
+			CHECKED_COPY_FROM_USER(&camif);
+
+			vfe_camif_config(&camif);
+		}
+		break;
+
+	case VFE_CMD_ID_BLACK_LEVEL_CONFIG:{
+			struct vfe_cmd_black_level_config bl;
+			CHECKED_COPY_FROM_USER(&bl);
+
+			vfe_black_level_config(&bl);
+		}
+		break;
+
+	case VFE_CMD_ID_ROLL_OFF_CONFIG:{
+			/* rolloff is too big to be on the stack */
+			struct vfe_cmd_roll_off_config *rolloff =
+			    kmalloc(sizeof(struct vfe_cmd_roll_off_config),
+				    GFP_KERNEL);
+			if (!rolloff) {
+				pr_err("%s: out of memory\n", __func__);
+				rc = -ENOMEM;
+				break;
+			}
+			/* Wrap CHECKED_COPY_FROM_USER() in a do-while(0) loop
+			 * to make sure we free rolloff when copy_from_user()
+			 * fails.
+			 */
+			do {
+				CHECKED_COPY_FROM_USER(rolloff);
+				vfe_roll_off_config(rolloff);
+			} while (0);
+			kfree(rolloff);
+		}
+		break;
+
+	case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG:{
+			struct vfe_cmd_demux_channel_gain_config demuxc;
+			CHECKED_COPY_FROM_USER(&demuxc);
+
+			/* demux is always enabled.  */
+			vfe_demux_channel_gain_config(&demuxc);
+		}
+		break;
+
+	case VFE_CMD_ID_DEMOSAIC_CONFIG:{
+			struct vfe_cmd_demosaic_config demosaic;
+			CHECKED_COPY_FROM_USER(&demosaic);
+
+			vfe_demosaic_config(&demosaic);
+		}
+		break;
+
+	case VFE_CMD_ID_FOV_CROP_CONFIG:
+	case VFE_CMD_ID_FOV_CROP_UPDATE:{
+			struct vfe_cmd_fov_crop_config fov;
+			CHECKED_COPY_FROM_USER(&fov);
+
+			vfe_fov_crop_config(&fov);
+		}
+		break;
+
+	case VFE_CMD_ID_MAIN_SCALER_CONFIG:
+	case VFE_CMD_ID_MAIN_SCALER_UPDATE:{
+			struct vfe_cmd_main_scaler_config mainds;
+			CHECKED_COPY_FROM_USER(&mainds);
+
+			vfe_main_scaler_config(&mainds);
+		}
+		break;
+
+	case VFE_CMD_ID_WHITE_BALANCE_CONFIG:
+	case VFE_CMD_ID_WHITE_BALANCE_UPDATE:{
+			struct vfe_cmd_white_balance_config wb;
+			CHECKED_COPY_FROM_USER(&wb);
+
+			vfe_white_balance_config(&wb);
+		}
+		break;
+
+	case VFE_CMD_ID_COLOR_CORRECTION_CONFIG:
+	case VFE_CMD_ID_COLOR_CORRECTION_UPDATE:{
+			struct vfe_cmd_color_correction_config cc;
+			CHECKED_COPY_FROM_USER(&cc);
+
+			vfe_color_correction_config(&cc);
+		}
+		break;
+
+	case VFE_CMD_ID_LA_CONFIG:{
+			struct vfe_cmd_la_config la;
+			CHECKED_COPY_FROM_USER(&la);
+
+			vfe_la_config(&la);
+		}
+		break;
+
+	case VFE_CMD_ID_RGB_GAMMA_CONFIG:{
+			struct vfe_cmd_rgb_gamma_config rgb;
+			CHECKED_COPY_FROM_USER(&rgb);
+
+			rc = vfe_rgb_gamma_config(&rgb);
+		}
+		break;
+
+	case VFE_CMD_ID_CHROMA_ENHAN_CONFIG:
+	case VFE_CMD_ID_CHROMA_ENHAN_UPDATE:{
+			struct vfe_cmd_chroma_enhan_config chrom;
+			CHECKED_COPY_FROM_USER(&chrom);
+
+			vfe_chroma_enhan_config(&chrom);
+		}
+		break;
+
+	case VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG:
+	case VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE:{
+			struct vfe_cmd_chroma_suppression_config chromsup;
+			CHECKED_COPY_FROM_USER(&chromsup);
+
+			vfe_chroma_sup_config(&chromsup);
+		}
+		break;
+
+	case VFE_CMD_ID_ASF_CONFIG:{
+			struct vfe_cmd_asf_config asf;
+			CHECKED_COPY_FROM_USER(&asf);
+
+			vfe_asf_config(&asf);
+		}
+		break;
+
+	case VFE_CMD_ID_SCALER2Y_CONFIG:
+	case VFE_CMD_ID_SCALER2Y_UPDATE:{
+			struct vfe_cmd_scaler2_config ds2y;
+			CHECKED_COPY_FROM_USER(&ds2y);
+
+			vfe_scaler2y_config(&ds2y);
+		}
+		break;
+
+	case VFE_CMD_ID_SCALER2CbCr_CONFIG:
+	case VFE_CMD_ID_SCALER2CbCr_UPDATE:{
+			struct vfe_cmd_scaler2_config ds2cbcr;
+			CHECKED_COPY_FROM_USER(&ds2cbcr);
+
+			vfe_scaler2cbcr_config(&ds2cbcr);
+		}
+		break;
+
+	case VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG:{
+			struct vfe_cmd_chroma_subsample_config sub;
+			CHECKED_COPY_FROM_USER(&sub);
+
+			vfe_chroma_subsample_config(&sub);
+		}
+		break;
+
+	case VFE_CMD_ID_FRAME_SKIP_CONFIG:{
+			struct vfe_cmd_frame_skip_config fskip;
+			CHECKED_COPY_FROM_USER(&fskip);
+
+			vfe_frame_skip_config(&fskip);
+		}
+		break;
+
+	case VFE_CMD_ID_OUTPUT_CLAMP_CONFIG:{
+			struct vfe_cmd_output_clamp_config clamp;
+			CHECKED_COPY_FROM_USER(&clamp);
+
+			vfe_output_clamp_config(&clamp);
+		}
+		break;
+
+		/* module update commands */
+	case VFE_CMD_ID_BLACK_LEVEL_UPDATE:{
+			struct vfe_cmd_black_level_config blk;
+			CHECKED_COPY_FROM_USER(&blk);
+
+			vfe_black_level_update(&blk);
+		}
+		break;
+
+	case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE:{
+			struct vfe_cmd_demux_channel_gain_config dmu;
+			CHECKED_COPY_FROM_USER(&dmu);
+
+			vfe_demux_channel_gain_update(&dmu);
+		}
+		break;
+
+	case VFE_CMD_ID_DEMOSAIC_BPC_UPDATE:{
+			struct vfe_cmd_demosaic_bpc_update demo_bpc;
+			CHECKED_COPY_FROM_USER(&demo_bpc);
+
+			vfe_demosaic_bpc_update(&demo_bpc);
+		}
+		break;
+
+	case VFE_CMD_ID_DEMOSAIC_ABF_UPDATE:{
+			struct vfe_cmd_demosaic_abf_update demo_abf;
+			CHECKED_COPY_FROM_USER(&demo_abf);
+
+			vfe_demosaic_abf_update(&demo_abf);
+		}
+		break;
+
+	case VFE_CMD_ID_LA_UPDATE:{
+			struct vfe_cmd_la_config la;
+			CHECKED_COPY_FROM_USER(&la);
+
+			vfe_la_update(&la);
+		}
+		break;
+
+	case VFE_CMD_ID_RGB_GAMMA_UPDATE:{
+			struct vfe_cmd_rgb_gamma_config rgb;
+			CHECKED_COPY_FROM_USER(&rgb);
+
+			rc = vfe_rgb_gamma_update(&rgb);
+		}
+		break;
+
+	case VFE_CMD_ID_ASF_UPDATE:{
+			struct vfe_cmd_asf_update asf;
+			CHECKED_COPY_FROM_USER(&asf);
+
+			vfe_asf_update(&asf);
+		}
+		break;
+
+	case VFE_CMD_ID_FRAME_SKIP_UPDATE:{
+			struct vfe_cmd_frame_skip_update fskip;
+			CHECKED_COPY_FROM_USER(&fskip);
+
+			vfe_frame_skip_update(&fskip);
+		}
+		break;
+
+	case VFE_CMD_ID_CAMIF_FRAME_UPDATE:{
+			struct vfe_cmds_camif_frame fup;
+			CHECKED_COPY_FROM_USER(&fup);
+
+			vfe_camif_frame_update(&fup);
+		}
+		break;
+
+		/* stats update commands */
+	case VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE:{
+			struct vfe_cmd_stats_af_update afup;
+			CHECKED_COPY_FROM_USER(&afup);
+
+			vfe_stats_update_af(&afup);
+		}
+		break;
+
+	case VFE_CMD_ID_STATS_WB_EXP_UPDATE:{
+			struct vfe_cmd_stats_wb_exp_update wbexp;
+			CHECKED_COPY_FROM_USER(&wbexp);
+
+			vfe_stats_update_wb_exp(&wbexp);
+		}
+		break;
+
+		/* control of start, stop, update, etc... */
+	case VFE_CMD_ID_STOP:
+		vfe_stop();
+		break;
+
+	case VFE_CMD_ID_GET_HW_VERSION:
+		break;
+
+		/* stats */
+	case VFE_CMD_ID_STATS_SETTING:{
+			struct vfe_cmd_stats_setting stats;
+			CHECKED_COPY_FROM_USER(&stats);
+
+			vfe_stats_setting(&stats);
+		}
+		break;
+
+	case VFE_CMD_ID_STATS_AUTOFOCUS_START:{
+			struct vfe_cmd_stats_af_start af;
+			CHECKED_COPY_FROM_USER(&af);
+
+			vfe_stats_start_af(&af);
+		}
+		break;
+
+	case VFE_CMD_ID_STATS_AUTOFOCUS_STOP:
+		vfe_stats_af_stop();
+		break;
+
+	case VFE_CMD_ID_STATS_WB_EXP_START:{
+			struct vfe_cmd_stats_wb_exp_start awexp;
+			CHECKED_COPY_FROM_USER(&awexp);
+
+			vfe_stats_start_wb_exp(&awexp);
+		}
+		break;
+
+	case VFE_CMD_ID_STATS_WB_EXP_STOP:
+		vfe_stats_wb_exp_stop();
+		break;
+
+	case VFE_CMD_ID_ASYNC_TIMER_SETTING:
+		break;
+
+	case VFE_CMD_ID_UPDATE:
+		vfe_update();
+		break;
+
+		/* test gen */
+	case VFE_CMD_ID_TEST_GEN_START:
+		break;
+
+	case VFE_CMD_ID_EPOCH1_CONFIG:{
+			struct vfe_cmds_camif_epoch epoch1;
+			CHECKED_COPY_FROM_USER(&epoch1);
+			vfe_epoch1_config(&epoch1);
+		}
+		break;
+
+/*
+  acknowledge from upper layer
+	these are not in general command.
+
+	case VFE_CMD_ID_OUTPUT1_ACK:
+		break;
+	case VFE_CMD_ID_OUTPUT2_ACK:
+		break;
+	case VFE_CMD_ID_EPOCH1_ACK:
+		break;
+	case VFE_CMD_ID_EPOCH2_ACK:
+		break;
+	case VFE_CMD_ID_STATS_AUTOFOCUS_ACK:
+		break;
+	case VFE_CMD_ID_STATS_WB_EXP_ACK:
+		break;
+*/
+
+	default:
+		pr_err("%s: invalid cmd id %d\n", __func__, cmd->id);
+		rc = -EINVAL;
+		break;
+	}			/* switch */
+
+	return rc;
+}
+
+static int vfe_config(struct msm_vfe_cfg_cmd *cmd, void *data)
+{
+	struct msm_pmem_region *regptr;
+	struct msm_vfe_command_8k vfecmd;
+	struct vfe_cmd_axi_output_config axio;
+	struct axidata *axid = data;
+
+	int rc = 0;
+
+	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+	    cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+	    cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+		if (copy_from_user(&vfecmd,
+				   (void __user *)(cmd->value), sizeof(vfecmd))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	}
+
+	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+	switch (cmd->cmd_type) {
+	case CMD_GENERAL:
+		rc = vfe_proc_general(&vfecmd);
+		break;
+
+	case CMD_STATS_ENABLE:
+	case CMD_STATS_AXI_CFG: {
+			int i;
+			struct vfe_cmd_stats_setting scfg;
+
+			BUG_ON(!axid);
+
+			if (vfecmd.length != sizeof(scfg)) {
+				pr_err
+				    ("msm_camera: %s: cmd %d: user-space "\
+				     "data size %d != kernel data size %d\n",
+				     __func__,
+				     cmd->cmd_type, vfecmd.length,
+				     sizeof(scfg));
+				return -EIO;
+			}
+
+			if (copy_from_user(&scfg,
+					   (void __user *)(vfecmd.value),
+					   sizeof(scfg))) {
+				ERR_COPY_FROM_USER();
+				return -EFAULT;
+			}
+
+			regptr = axid->region;
+			if (axid->bufnum1 > 0) {
+				for (i = 0; i < axid->bufnum1; i++) {
+					scfg.awbBuffer[i] =
+					    (uint32_t) (regptr->paddr);
+					regptr++;
+				}
+			}
+
+			if (axid->bufnum2 > 0) {
+				for (i = 0; i < axid->bufnum2; i++) {
+					scfg.afBuffer[i] =
+					    (uint32_t) (regptr->paddr);
+					regptr++;
+				}
+			}
+
+			vfe_stats_setting(&scfg);
+		}
+		break;
+
+	case CMD_STATS_AF_AXI_CFG:
+		break;
+
+	case CMD_FRAME_BUF_RELEASE: {
+			/* preview buffer release */
+			struct msm_frame *b;
+			unsigned long p;
+			struct vfe_cmd_output_ack fack;
+
+			BUG_ON(!data);
+
+			b = (struct msm_frame *)(cmd->value);
+			p = *(unsigned long *)data;
+
+			fack.ybufaddr[0] = (uint32_t) (p + b->y_off);
+
+			fack.chromabufaddr[0] = (uint32_t) (p + b->cbcr_off);
+
+			if (b->path == MSM_FRAME_PREV_1)
+				vfe_output1_ack(&fack);
+
+			if (b->path == MSM_FRAME_ENC ||
+			    b->path == MSM_FRAME_PREV_2)
+				vfe_output2_ack(&fack);
+
+
+		}
+		break;
+
+	case CMD_SNAP_BUF_RELEASE:
+		break;
+
+	case CMD_STATS_BUF_RELEASE: {
+			struct vfe_cmd_stats_wb_exp_ack sack;
+
+			BUG_ON(!data);
+
+			sack.nextWbExpOutputBufferAddr = *(uint32_t *) data;
+			vfe_stats_wb_exp_ack(&sack);
+		}
+		break;
+
+	case CMD_STATS_AF_BUF_RELEASE: {
+			struct vfe_cmd_stats_af_ack ack;
+
+			BUG_ON(!data);
+
+			ack.nextAFOutputBufferAddr = *(uint32_t *) data;
+			vfe_stats_af_ack(&ack);
+		}
+		break;
+
+	case CMD_AXI_CFG_OUT1: {
+
+			BUG_ON(!axid);
+
+			if (copy_from_user(&axio, (void __user *)(vfecmd.value),
+					   sizeof(axio))) {
+				ERR_COPY_FROM_USER();
+				return -EFAULT;
+			}
+
+			vfe_config_axi(OUTPUT_1, axid, &axio);
+			vfe_axi_output_config(&axio);
+		}
+		break;
+
+	case CMD_AXI_CFG_OUT2:
+	case CMD_RAW_PICT_AXI_CFG: {
+
+			BUG_ON(!axid);
+
+			if (copy_from_user(&axio, (void __user *)(vfecmd.value),
+					   sizeof(axio))) {
+				ERR_COPY_FROM_USER();
+				return -EFAULT;
+			}
+
+			vfe_config_axi(OUTPUT_2, axid, &axio);
+
+			axio.outputDataSize = 0;
+			vfe_axi_output_config(&axio);
+		}
+		break;
+
+	case CMD_AXI_CFG_O1_AND_O2:
+	case CMD_AXI_CFG_SNAP_O1_AND_O2: {
+
+			BUG_ON(!axid);
+
+			if (copy_from_user(&axio, (void __user *)(vfecmd.value),
+					   sizeof(axio))) {
+				ERR_COPY_FROM_USER();
+				return -EFAULT;
+			}
+
+			vfe_config_axi(OUTPUT_1_AND_2, axid, &axio);
+			vfe_axi_output_config(&axio);
+		}
+		break;
+
+	default:
+		break;
+	}			/* switch */
+
+	return rc;
+}
+
+void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
+{
+	fptr->vfe_init = vfe_init;
+	fptr->vfe_enable = vfe_enable;
+	fptr->vfe_config = vfe_config;
+	fptr->vfe_disable = vfe_disable;
+	fptr->vfe_release = vfe_release;
+	vfe_syncdata = data;
+}
diff --git a/drivers/media/video/msm/msm_vfe8x.h b/drivers/media/video/msm/msm_vfe8x.h
new file mode 100644
index 0000000..09d5875
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe8x.h
@@ -0,0 +1,913 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __MSM_VFE8X_H__
+#define __MSM_VFE8X_H__
+
+#define TRUE  1
+#define FALSE 0
+#define boolean uint8_t
+
+enum VFE_STATE {
+	VFE_STATE_IDLE,
+	VFE_STATE_ACTIVE
+};
+
+enum vfe_cmd_id {
+	/*
+	 *Important! Command_ID are arranged in order.
+	 *Don't change!*/
+	VFE_CMD_ID_START,
+	VFE_CMD_ID_RESET,
+
+	/* bus and camif config */
+	VFE_CMD_ID_AXI_INPUT_CONFIG,
+	VFE_CMD_ID_CAMIF_CONFIG,
+	VFE_CMD_ID_AXI_OUTPUT_CONFIG,
+
+	/* module config  */
+	VFE_CMD_ID_BLACK_LEVEL_CONFIG,
+	VFE_CMD_ID_ROLL_OFF_CONFIG,
+	VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG,
+	VFE_CMD_ID_DEMOSAIC_CONFIG,
+	VFE_CMD_ID_FOV_CROP_CONFIG,
+	VFE_CMD_ID_MAIN_SCALER_CONFIG,
+	VFE_CMD_ID_WHITE_BALANCE_CONFIG,
+	VFE_CMD_ID_COLOR_CORRECTION_CONFIG,
+	VFE_CMD_ID_LA_CONFIG,
+	VFE_CMD_ID_RGB_GAMMA_CONFIG,
+	VFE_CMD_ID_CHROMA_ENHAN_CONFIG,
+	VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG,
+	VFE_CMD_ID_ASF_CONFIG,
+	VFE_CMD_ID_SCALER2Y_CONFIG,
+	VFE_CMD_ID_SCALER2CbCr_CONFIG,
+	VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG,
+	VFE_CMD_ID_FRAME_SKIP_CONFIG,
+	VFE_CMD_ID_OUTPUT_CLAMP_CONFIG,
+
+	/* test gen */
+	VFE_CMD_ID_TEST_GEN_START,
+
+	VFE_CMD_ID_UPDATE,
+
+	/* ackownledge from upper layer */
+	VFE_CMD_ID_OUTPUT1_ACK,
+	VFE_CMD_ID_OUTPUT2_ACK,
+	VFE_CMD_ID_EPOCH1_ACK,
+	VFE_CMD_ID_EPOCH2_ACK,
+	VFE_CMD_ID_STATS_AUTOFOCUS_ACK,
+	VFE_CMD_ID_STATS_WB_EXP_ACK,
+
+	/* module update commands */
+	VFE_CMD_ID_BLACK_LEVEL_UPDATE,
+	VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE,
+	VFE_CMD_ID_DEMOSAIC_BPC_UPDATE,
+	VFE_CMD_ID_DEMOSAIC_ABF_UPDATE,
+	VFE_CMD_ID_FOV_CROP_UPDATE,
+	VFE_CMD_ID_WHITE_BALANCE_UPDATE,
+	VFE_CMD_ID_COLOR_CORRECTION_UPDATE,
+	VFE_CMD_ID_LA_UPDATE,
+	VFE_CMD_ID_RGB_GAMMA_UPDATE,
+	VFE_CMD_ID_CHROMA_ENHAN_UPDATE,
+	VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE,
+	VFE_CMD_ID_MAIN_SCALER_UPDATE,
+	VFE_CMD_ID_SCALER2CbCr_UPDATE,
+	VFE_CMD_ID_SCALER2Y_UPDATE,
+	VFE_CMD_ID_ASF_UPDATE,
+	VFE_CMD_ID_FRAME_SKIP_UPDATE,
+	VFE_CMD_ID_CAMIF_FRAME_UPDATE,
+
+	/* stats update commands */
+	VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE,
+	VFE_CMD_ID_STATS_WB_EXP_UPDATE,
+
+	/* control of start, stop, update, etc... */
+	VFE_CMD_ID_STOP,
+	VFE_CMD_ID_GET_HW_VERSION,
+
+	/* stats */
+	VFE_CMD_ID_STATS_SETTING,
+	VFE_CMD_ID_STATS_AUTOFOCUS_START,
+	VFE_CMD_ID_STATS_AUTOFOCUS_STOP,
+	VFE_CMD_ID_STATS_WB_EXP_START,
+	VFE_CMD_ID_STATS_WB_EXP_STOP,
+
+	VFE_CMD_ID_ASYNC_TIMER_SETTING,
+
+	/* epoch1 */
+	VFE_CMD_ID_EPOCH1_CONFIG,
+
+	/* max id  */
+	VFE_CMD_ID_MAX
+};
+
+struct vfe_cmd_hw_version {
+	uint32_t minorVersion;
+	uint32_t majorVersion;
+	uint32_t coreVersion;
+};
+
+enum VFE_CAMIF_SYNC_EDGE {
+	VFE_CAMIF_SYNC_EDGE_ActiveHigh,
+	VFE_CAMIF_SYNC_EDGE_ActiveLow
+};
+
+enum VFE_CAMIF_SYNC_MODE {
+	VFE_CAMIF_SYNC_MODE_APS,
+	VFE_CAMIF_SYNC_MODE_EFS,
+	VFE_CAMIF_SYNC_MODE_ELS,
+	VFE_CAMIF_SYNC_MODE_ILLEGAL
+};
+
+struct vfe_cmds_camif_efs {
+	uint8_t efsendofline;
+	uint8_t efsstartofline;
+	uint8_t efsendofframe;
+	uint8_t efsstartofframe;
+};
+
+struct vfe_cmds_camif_frame {
+	uint16_t pixelsPerLine;
+	uint16_t linesPerFrame;
+};
+
+struct vfe_cmds_camif_window {
+	uint16_t firstpixel;
+	uint16_t lastpixel;
+	uint16_t firstline;
+	uint16_t lastline;
+};
+
+enum CAMIF_SUBSAMPLE_FRAME_SKIP {
+	CAMIF_SUBSAMPLE_FRAME_SKIP_0,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_AllFrames,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_2Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_3Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_4Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_5Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_6Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_7Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_8Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_9Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_10Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_11Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_12Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_13Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_14Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_15Frame
+};
+
+struct vfe_cmds_camif_subsample {
+	uint16_t pixelskipmask;
+	uint16_t lineskipmask;
+	enum CAMIF_SUBSAMPLE_FRAME_SKIP frameskip;
+	uint8_t frameskipmode;
+	uint8_t pixelskipwrap;
+};
+
+struct vfe_cmds_camif_epoch {
+	uint8_t enable;
+	uint16_t lineindex;
+};
+
+struct vfe_cmds_camif_cfg {
+	enum VFE_CAMIF_SYNC_EDGE vSyncEdge;
+	enum VFE_CAMIF_SYNC_EDGE hSyncEdge;
+	enum VFE_CAMIF_SYNC_MODE syncMode;
+	uint8_t vfeSubSampleEnable;
+	uint8_t busSubSampleEnable;
+	uint8_t irqSubSampleEnable;
+	uint8_t binningEnable;
+	uint8_t misrEnable;
+};
+
+struct vfe_cmd_camif_config {
+	struct vfe_cmds_camif_cfg camifConfig;
+	struct vfe_cmds_camif_efs EFS;
+	struct vfe_cmds_camif_frame frame;
+	struct vfe_cmds_camif_window window;
+	struct vfe_cmds_camif_subsample subsample;
+	struct vfe_cmds_camif_epoch epoch1;
+	struct vfe_cmds_camif_epoch epoch2;
+};
+
+enum VFE_AXI_OUTPUT_MODE {
+	VFE_AXI_OUTPUT_MODE_Output1,
+	VFE_AXI_OUTPUT_MODE_Output2,
+	VFE_AXI_OUTPUT_MODE_Output1AndOutput2,
+	VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2,
+	VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1,
+	VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2,
+	VFE_AXI_LAST_OUTPUT_MODE_ENUM
+};
+
+enum VFE_RAW_WR_PATH_SEL {
+	VFE_RAW_OUTPUT_DISABLED,
+	VFE_RAW_OUTPUT_ENC_CBCR_PATH,
+	VFE_RAW_OUTPUT_VIEW_CBCR_PATH,
+	VFE_RAW_OUTPUT_PATH_INVALID
+};
+
+enum VFE_RAW_PIXEL_DATA_SIZE {
+	VFE_RAW_PIXEL_DATA_SIZE_8BIT,
+	VFE_RAW_PIXEL_DATA_SIZE_10BIT,
+	VFE_RAW_PIXEL_DATA_SIZE_12BIT,
+};
+
+#define VFE_AXI_OUTPUT_BURST_LENGTH     4
+#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4
+#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT  3
+
+struct vfe_cmds_axi_out_per_component {
+	uint16_t imageWidth;
+	uint16_t imageHeight;
+	uint16_t outRowCount;
+	uint16_t outRowIncrement;
+	uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT]
+	    [VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+struct vfe_cmds_axi_per_output_path {
+	uint8_t fragmentCount;
+	struct vfe_cmds_axi_out_per_component outputY;
+	struct vfe_cmds_axi_out_per_component outputCbcr;
+};
+
+enum VFE_AXI_BURST_LENGTH {
+	VFE_AXI_BURST_LENGTH_IS_2 = 2,
+	VFE_AXI_BURST_LENGTH_IS_4 = 4,
+	VFE_AXI_BURST_LENGTH_IS_8 = 8,
+	VFE_AXI_BURST_LENGTH_IS_16 = 16
+};
+
+struct vfe_cmd_axi_output_config {
+	enum VFE_AXI_BURST_LENGTH burstLength;
+	enum VFE_AXI_OUTPUT_MODE outputMode;
+	enum VFE_RAW_PIXEL_DATA_SIZE outputDataSize;
+	struct vfe_cmds_axi_per_output_path output1;
+	struct vfe_cmds_axi_per_output_path output2;
+};
+
+struct vfe_cmd_fov_crop_config {
+	uint8_t enable;
+	uint16_t firstPixel;
+	uint16_t lastPixel;
+	uint16_t firstLine;
+	uint16_t lastLine;
+};
+
+struct vfe_cmds_main_scaler_stripe_init {
+	uint16_t MNCounterInit;
+	uint16_t phaseInit;
+};
+
+struct vfe_cmds_scaler_one_dimension {
+	uint8_t enable;
+	uint16_t inputSize;
+	uint16_t outputSize;
+	uint32_t phaseMultiplicationFactor;
+	uint8_t interpolationResolution;
+};
+
+struct vfe_cmd_main_scaler_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension hconfig;
+	struct vfe_cmds_scaler_one_dimension vconfig;
+	struct vfe_cmds_main_scaler_stripe_init MNInitH;
+	struct vfe_cmds_main_scaler_stripe_init MNInitV;
+};
+
+struct vfe_cmd_scaler2_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension hconfig;
+	struct vfe_cmds_scaler_one_dimension vconfig;
+};
+
+struct vfe_cmd_frame_skip_config {
+	uint8_t output1Period;
+	uint32_t output1Pattern;
+	uint8_t output2Period;
+	uint32_t output2Pattern;
+};
+
+struct vfe_cmd_frame_skip_update {
+	uint32_t output1Pattern;
+	uint32_t output2Pattern;
+};
+
+struct vfe_cmd_output_clamp_config {
+	uint8_t minCh0;
+	uint8_t minCh1;
+	uint8_t minCh2;
+	uint8_t maxCh0;
+	uint8_t maxCh1;
+	uint8_t maxCh2;
+};
+
+struct vfe_cmd_chroma_subsample_config {
+	uint8_t enable;
+	uint8_t cropEnable;
+	uint8_t vsubSampleEnable;
+	uint8_t hsubSampleEnable;
+	uint8_t vCosited;
+	uint8_t hCosited;
+	uint8_t vCositedPhase;
+	uint8_t hCositedPhase;
+	uint16_t cropWidthFirstPixel;
+	uint16_t cropWidthLastPixel;
+	uint16_t cropHeightFirstLine;
+	uint16_t cropHeightLastLine;
+};
+
+enum VFE_START_INPUT_SOURCE {
+	VFE_START_INPUT_SOURCE_CAMIF,
+	VFE_START_INPUT_SOURCE_TESTGEN,
+	VFE_START_INPUT_SOURCE_AXI,
+	VFE_START_INPUT_SOURCE_INVALID
+};
+
+enum VFE_START_OPERATION_MODE {
+	VFE_START_OPERATION_MODE_CONTINUOUS,
+	VFE_START_OPERATION_MODE_SNAPSHOT
+};
+
+enum VFE_START_PIXEL_PATTERN {
+	VFE_BAYER_RGRGRG,
+	VFE_BAYER_GRGRGR,
+	VFE_BAYER_BGBGBG,
+	VFE_BAYER_GBGBGB,
+	VFE_YUV_YCbYCr,
+	VFE_YUV_YCrYCb,
+	VFE_YUV_CbYCrY,
+	VFE_YUV_CrYCbY
+};
+
+enum VFE_BUS_RD_INPUT_PIXEL_PATTERN {
+	VFE_BAYER_RAW,
+	VFE_YUV_INTERLEAVED,
+	VFE_YUV_PSEUDO_PLANAR_Y,
+	VFE_YUV_PSEUDO_PLANAR_CBCR
+};
+
+enum VFE_YUV_INPUT_COSITING_MODE {
+	VFE_YUV_COSITED,
+	VFE_YUV_INTERPOLATED
+};
+
+struct vfe_cmd_start {
+	enum VFE_START_INPUT_SOURCE inputSource;
+	enum VFE_START_OPERATION_MODE operationMode;
+	uint8_t snapshotCount;
+	enum VFE_START_PIXEL_PATTERN pixel;
+	enum VFE_YUV_INPUT_COSITING_MODE yuvInputCositingMode;
+};
+
+struct vfe_cmd_output_ack {
+	uint32_t ybufaddr[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+	uint32_t chromabufaddr[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+#define VFE_STATS_BUFFER_COUNT 3
+
+struct vfe_cmd_stats_setting {
+	uint16_t frameHDimension;
+	uint16_t frameVDimension;
+	uint8_t afBusPrioritySelection;
+	uint8_t afBusPriority;
+	uint8_t awbBusPrioritySelection;
+	uint8_t awbBusPriority;
+	uint8_t histBusPrioritySelection;
+	uint8_t histBusPriority;
+	uint32_t afBuffer[VFE_STATS_BUFFER_COUNT];
+	uint32_t awbBuffer[VFE_STATS_BUFFER_COUNT];
+	uint32_t histBuffer[VFE_STATS_BUFFER_COUNT];
+};
+
+struct vfe_cmd_stats_af_start {
+	uint8_t enable;
+	uint8_t windowMode;
+	uint16_t windowHOffset;
+	uint16_t windowVOffset;
+	uint16_t windowWidth;
+	uint16_t windowHeight;
+	uint8_t gridForMultiWindows[16];
+	uint8_t metricSelection;
+	int16_t metricMax;
+	int8_t highPassCoef[7];
+	int8_t bufferHeader;
+};
+
+struct vfe_cmd_stats_af_update {
+	uint8_t windowMode;
+	uint16_t windowHOffset;
+	uint16_t windowVOffset;
+	uint16_t windowWidth;
+	uint16_t windowHeight;
+};
+
+struct vfe_cmd_stats_wb_exp_start {
+	uint8_t enable;
+	uint8_t wbExpRegions;
+	uint8_t wbExpSubRegion;
+	uint8_t awbYMin;
+	uint8_t awbYMax;
+	int8_t awbMCFG[4];
+	int16_t awbCCFG[4];
+	int8_t axwHeader;
+};
+
+struct vfe_cmd_stats_wb_exp_update {
+	uint8_t wbExpRegions;
+	uint8_t wbExpSubRegion;
+	int8_t awbYMin;
+	int8_t awbYMax;
+	int8_t awbMCFG[4];
+	int16_t awbCCFG[4];
+};
+
+struct vfe_cmd_stats_af_ack {
+	uint32_t nextAFOutputBufferAddr;
+};
+
+struct vfe_cmd_stats_wb_exp_ack {
+	uint32_t nextWbExpOutputBufferAddr;
+};
+
+struct vfe_cmd_black_level_config {
+	uint8_t enable;
+	uint16_t evenEvenAdjustment;
+	uint16_t evenOddAdjustment;
+	uint16_t oddEvenAdjustment;
+	uint16_t oddOddAdjustment;
+};
+
+/* 13*1  */
+#define  VFE_ROLL_OFF_INIT_TABLE_SIZE  13
+/* 13*16 */
+#define  VFE_ROLL_OFF_DELTA_TABLE_SIZE 208
+
+struct vfe_cmd_roll_off_config {
+	uint8_t enable;
+	uint16_t gridWidth;
+	uint16_t gridHeight;
+	uint16_t yDelta;
+	uint8_t gridXIndex;
+	uint8_t gridYIndex;
+	uint16_t gridPixelXIndex;
+	uint16_t gridPixelYIndex;
+	uint16_t yDeltaAccum;
+	uint16_t initTableR[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+	uint16_t initTableGr[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+	uint16_t initTableB[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+	uint16_t initTableGb[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+	int16_t deltaTableR[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+	int16_t deltaTableGr[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+	int16_t deltaTableB[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+	int16_t deltaTableGb[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+};
+
+struct vfe_cmd_demux_channel_gain_config {
+	uint16_t ch0EvenGain;
+	uint16_t ch0OddGain;
+	uint16_t ch1Gain;
+	uint16_t ch2Gain;
+};
+
+struct vfe_cmds_demosaic_abf {
+	uint8_t enable;
+	uint8_t forceOn;
+	uint8_t shift;
+	uint16_t lpThreshold;
+	uint16_t max;
+	uint16_t min;
+	uint8_t ratio;
+};
+
+struct vfe_cmds_demosaic_bpc {
+	uint8_t enable;
+	uint16_t fmaxThreshold;
+	uint16_t fminThreshold;
+	uint16_t redDiffThreshold;
+	uint16_t blueDiffThreshold;
+	uint16_t greenDiffThreshold;
+};
+
+struct vfe_cmd_demosaic_config {
+	uint8_t enable;
+	uint8_t slopeShift;
+	struct vfe_cmds_demosaic_abf abfConfig;
+	struct vfe_cmds_demosaic_bpc bpcConfig;
+};
+
+struct vfe_cmd_demosaic_bpc_update {
+	struct vfe_cmds_demosaic_bpc bpcUpdate;
+};
+
+struct vfe_cmd_demosaic_abf_update {
+	struct vfe_cmds_demosaic_abf abfUpdate;
+};
+
+struct vfe_cmd_white_balance_config {
+	uint8_t enable;
+	uint16_t ch2Gain;
+	uint16_t ch1Gain;
+	uint16_t ch0Gain;
+};
+
+enum VFE_COLOR_CORRECTION_COEF_QFACTOR {
+	COEF_IS_Q7_SIGNED,
+	COEF_IS_Q8_SIGNED,
+	COEF_IS_Q9_SIGNED,
+	COEF_IS_Q10_SIGNED
+};
+
+struct vfe_cmd_color_correction_config {
+	uint8_t enable;
+	enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor;
+	int16_t C0;
+	int16_t C1;
+	int16_t C2;
+	int16_t C3;
+	int16_t C4;
+	int16_t C5;
+	int16_t C6;
+	int16_t C7;
+	int16_t C8;
+	int16_t K0;
+	int16_t K1;
+	int16_t K2;
+};
+
+#define VFE_LA_TABLE_LENGTH 256
+struct vfe_cmd_la_config {
+	uint8_t enable;
+	int16_t table[VFE_LA_TABLE_LENGTH];
+};
+
+#define VFE_GAMMA_TABLE_LENGTH 256
+enum VFE_RGB_GAMMA_TABLE_SELECT {
+	RGB_GAMMA_CH0_SELECTED,
+	RGB_GAMMA_CH1_SELECTED,
+	RGB_GAMMA_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_SELECTED,
+	RGB_GAMMA_CH0_CH2_SELECTED,
+	RGB_GAMMA_CH1_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_CH2_SELECTED
+};
+
+struct vfe_cmd_rgb_gamma_config {
+	uint8_t enable;
+	enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect;
+	int16_t table[VFE_GAMMA_TABLE_LENGTH];
+};
+
+struct vfe_cmd_chroma_enhan_config {
+	uint8_t enable;
+	int16_t am;
+	int16_t ap;
+	int16_t bm;
+	int16_t bp;
+	int16_t cm;
+	int16_t cp;
+	int16_t dm;
+	int16_t dp;
+	int16_t kcr;
+	int16_t kcb;
+	int16_t RGBtoYConversionV0;
+	int16_t RGBtoYConversionV1;
+	int16_t RGBtoYConversionV2;
+	uint8_t RGBtoYConversionOffset;
+};
+
+struct vfe_cmd_chroma_suppression_config {
+	uint8_t enable;
+	uint8_t m1;
+	uint8_t m3;
+	uint8_t n1;
+	uint8_t n3;
+	uint8_t nn1;
+	uint8_t mm1;
+};
+
+struct vfe_cmd_asf_config {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t sharpThreshE2;
+	int8_t sharpThreshE3;
+	int8_t sharpThreshE4;
+	int8_t sharpThreshE5;
+	int8_t filter1Coefficients[9];
+	int8_t filter2Coefficients[9];
+	uint8_t cropEnable;
+	uint16_t cropFirstPixel;
+	uint16_t cropLastPixel;
+	uint16_t cropFirstLine;
+	uint16_t cropLastLine;
+};
+
+struct vfe_cmd_asf_update {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t sharpThreshE2;
+	int8_t sharpThreshE3;
+	int8_t sharpThreshE4;
+	int8_t sharpThreshE5;
+	int8_t filter1Coefficients[9];
+	int8_t filter2Coefficients[9];
+	uint8_t cropEnable;
+};
+
+enum VFE_TEST_GEN_SYNC_EDGE {
+	VFE_TEST_GEN_SYNC_EDGE_ActiveHigh,
+	VFE_TEST_GEN_SYNC_EDGE_ActiveLow
+};
+
+struct vfe_cmd_test_gen_start {
+	uint8_t pixelDataSelect;
+	uint8_t systematicDataSelect;
+	enum VFE_TEST_GEN_SYNC_EDGE hsyncEdge;
+	enum VFE_TEST_GEN_SYNC_EDGE vsyncEdge;
+	uint16_t numFrame;
+	enum VFE_RAW_PIXEL_DATA_SIZE pixelDataSize;
+	uint16_t imageWidth;
+	uint16_t imageHeight;
+	uint32_t startOfFrameOffset;
+	uint32_t endOfFrameNOffset;
+	uint16_t startOfLineOffset;
+	uint16_t endOfLineNOffset;
+	uint16_t hbi;
+	uint8_t vblEnable;
+	uint16_t vbl;
+	uint8_t startOfFrameDummyLine;
+	uint8_t endOfFrameDummyLine;
+	uint8_t unicolorBarEnable;
+	uint8_t colorBarsSplitEnable;
+	uint8_t unicolorBarSelect;
+	enum VFE_START_PIXEL_PATTERN colorBarsPixelPattern;
+	uint8_t colorBarsRotatePeriod;
+	uint16_t testGenRandomSeed;
+};
+
+struct vfe_cmd_bus_pm_start {
+	uint8_t output2YWrPmEnable;
+	uint8_t output2CbcrWrPmEnable;
+	uint8_t output1YWrPmEnable;
+	uint8_t output1CbcrWrPmEnable;
+};
+
+struct vfe_cmd_camif_frame_update {
+	struct vfe_cmds_camif_frame camifFrame;
+};
+
+struct vfe_cmd_sync_timer_setting {
+	uint8_t whichSyncTimer;
+	uint8_t operation;
+	uint8_t polarity;
+	uint16_t repeatCount;
+	uint16_t hsyncCount;
+	uint32_t pclkCount;
+	uint32_t outputDuration;
+};
+
+struct vfe_cmd_async_timer_setting {
+	uint8_t whichAsyncTimer;
+	uint8_t operation;
+	uint8_t polarity;
+	uint16_t repeatCount;
+	uint16_t inactiveCount;
+	uint32_t activeCount;
+};
+
+struct vfe_frame_skip_counts {
+	uint32_t totalFrameCount;
+	uint32_t output1Count;
+	uint32_t output2Count;
+};
+
+enum VFE_AXI_RD_UNPACK_HBI_SEL {
+	VFE_AXI_RD_HBI_32_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_64_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_128_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_256_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_512_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_1024_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_2048_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_4096_CLOCK_CYCLES
+};
+
+struct vfe_cmd_axi_input_config {
+	uint32_t fragAddr[4];
+	uint8_t totalFragmentCount;
+	uint16_t ySize;
+	uint16_t xOffset;
+	uint16_t xSize;
+	uint16_t rowIncrement;
+	uint16_t numOfRows;
+	enum VFE_AXI_BURST_LENGTH burstLength;
+	uint8_t unpackPhase;
+	enum VFE_AXI_RD_UNPACK_HBI_SEL unpackHbi;
+	enum VFE_RAW_PIXEL_DATA_SIZE pixelSize;
+	uint8_t padRepeatCountLeft;
+	uint8_t padRepeatCountRight;
+	uint8_t padRepeatCountTop;
+	uint8_t padRepeatCountBottom;
+	uint8_t padLeftComponentSelectCycle0;
+	uint8_t padLeftComponentSelectCycle1;
+	uint8_t padLeftComponentSelectCycle2;
+	uint8_t padLeftComponentSelectCycle3;
+	uint8_t padLeftStopCycle0;
+	uint8_t padLeftStopCycle1;
+	uint8_t padLeftStopCycle2;
+	uint8_t padLeftStopCycle3;
+	uint8_t padRightComponentSelectCycle0;
+	uint8_t padRightComponentSelectCycle1;
+	uint8_t padRightComponentSelectCycle2;
+	uint8_t padRightComponentSelectCycle3;
+	uint8_t padRightStopCycle0;
+	uint8_t padRightStopCycle1;
+	uint8_t padRightStopCycle2;
+	uint8_t padRightStopCycle3;
+	uint8_t padTopLineCount;
+	uint8_t padBottomLineCount;
+};
+
+struct vfe_interrupt_status {
+	uint8_t camifErrorIrq;
+	uint8_t camifSofIrq;
+	uint8_t camifEolIrq;
+	uint8_t camifEofIrq;
+	uint8_t camifEpoch1Irq;
+	uint8_t camifEpoch2Irq;
+	uint8_t camifOverflowIrq;
+	uint8_t ceIrq;
+	uint8_t regUpdateIrq;
+	uint8_t resetAckIrq;
+	uint8_t encYPingpongIrq;
+	uint8_t encCbcrPingpongIrq;
+	uint8_t viewYPingpongIrq;
+	uint8_t viewCbcrPingpongIrq;
+	uint8_t rdPingpongIrq;
+	uint8_t afPingpongIrq;
+	uint8_t awbPingpongIrq;
+	uint8_t histPingpongIrq;
+	uint8_t encIrq;
+	uint8_t viewIrq;
+	uint8_t busOverflowIrq;
+	uint8_t afOverflowIrq;
+	uint8_t awbOverflowIrq;
+	uint8_t syncTimer0Irq;
+	uint8_t syncTimer1Irq;
+	uint8_t syncTimer2Irq;
+	uint8_t asyncTimer0Irq;
+	uint8_t asyncTimer1Irq;
+	uint8_t asyncTimer2Irq;
+	uint8_t asyncTimer3Irq;
+	uint8_t axiErrorIrq;
+	uint8_t violationIrq;
+	uint8_t anyErrorIrqs;
+	uint8_t anyOutput1PathIrqs;
+	uint8_t anyOutput2PathIrqs;
+	uint8_t anyOutputPathIrqs;
+	uint8_t anyAsyncTimerIrqs;
+	uint8_t anySyncTimerIrqs;
+	uint8_t anyIrqForActiveStatesOnly;
+};
+
+enum VFE_MESSAGE_ID {
+	VFE_MSG_ID_RESET_ACK,
+	VFE_MSG_ID_START_ACK,
+	VFE_MSG_ID_STOP_ACK,
+	VFE_MSG_ID_UPDATE_ACK,
+	VFE_MSG_ID_OUTPUT1,
+	VFE_MSG_ID_OUTPUT2,
+	VFE_MSG_ID_SNAPSHOT_DONE,
+	VFE_MSG_ID_STATS_AUTOFOCUS,
+	VFE_MSG_ID_STATS_WB_EXP,
+	VFE_MSG_ID_EPOCH1,
+	VFE_MSG_ID_EPOCH2,
+	VFE_MSG_ID_SYNC_TIMER0_DONE,
+	VFE_MSG_ID_SYNC_TIMER1_DONE,
+	VFE_MSG_ID_SYNC_TIMER2_DONE,
+	VFE_MSG_ID_ASYNC_TIMER0_DONE,
+	VFE_MSG_ID_ASYNC_TIMER1_DONE,
+	VFE_MSG_ID_ASYNC_TIMER2_DONE,
+	VFE_MSG_ID_ASYNC_TIMER3_DONE,
+	VFE_MSG_ID_AF_OVERFLOW,
+	VFE_MSG_ID_AWB_OVERFLOW,
+	VFE_MSG_ID_AXI_ERROR,
+	VFE_MSG_ID_CAMIF_OVERFLOW,
+	VFE_MSG_ID_VIOLATION,
+	VFE_MSG_ID_CAMIF_ERROR,
+	VFE_MSG_ID_BUS_OVERFLOW,
+};
+
+struct vfe_msg_stats_autofocus {
+	uint32_t afBuffer;
+	uint32_t frameCounter;
+};
+
+struct vfe_msg_stats_wb_exp {
+	uint32_t awbBuffer;
+	uint32_t frameCounter;
+};
+
+struct vfe_frame_bpc_info {
+	uint32_t greenDefectPixelCount;
+	uint32_t redBlueDefectPixelCount;
+};
+
+struct vfe_frame_asf_info {
+	uint32_t asfMaxEdge;
+	uint32_t asfHbiCount;
+};
+
+struct vfe_msg_camif_status {
+	uint8_t camifState;
+	uint32_t pixelCount;
+	uint32_t lineCount;
+};
+
+struct vfe_bus_pm_per_path {
+	uint32_t yWrPmStats0;
+	uint32_t yWrPmStats1;
+	uint32_t cbcrWrPmStats0;
+	uint32_t cbcrWrPmStats1;
+};
+
+struct vfe_bus_performance_monitor {
+	struct vfe_bus_pm_per_path encPathPmInfo;
+	struct vfe_bus_pm_per_path viewPathPmInfo;
+};
+
+struct vfe_irq_thread_msg {
+	uint32_t vfeIrqStatus;
+	uint32_t camifStatus;
+	uint32_t demosaicStatus;
+	uint32_t asfMaxEdge;
+	struct vfe_bus_performance_monitor pmInfo;
+};
+
+struct vfe_msg_output {
+	uint32_t yBuffer;
+	uint32_t cbcrBuffer;
+	struct vfe_frame_bpc_info bpcInfo;
+	struct vfe_frame_asf_info asfInfo;
+	uint32_t frameCounter;
+	struct vfe_bus_pm_per_path pmData;
+};
+
+struct vfe_message {
+	enum VFE_MESSAGE_ID _d;
+	union {
+		struct vfe_msg_output msgOutput1;
+		struct vfe_msg_output msgOutput2;
+		struct vfe_msg_stats_autofocus msgStatsAf;
+		struct vfe_msg_stats_wb_exp msgStatsWbExp;
+		struct vfe_msg_camif_status msgCamifError;
+		struct vfe_bus_performance_monitor msgBusOverflow;
+	} _u;
+};
+
+/* New one for 8k */
+struct msm_vfe_command_8k {
+	int id;
+	uint16_t length;
+	void *value;
+};
+
+struct vfe_frame_extra {
+	struct vfe_frame_bpc_info bpcInfo;
+	struct vfe_frame_asf_info asfInfo;
+	uint32_t frameCounter;
+	struct vfe_bus_pm_per_path pmData;
+};
+#endif /* __MSM_VFE8X_H__ */
diff --git a/drivers/media/video/msm/msm_vfe8x_proc.c b/drivers/media/video/msm/msm_vfe8x_proc.c
new file mode 100644
index 0000000..23ea197
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe8x_proc.c
@@ -0,0 +1,3827 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include "msm_vfe8x_proc.h"
+#include <media/msm_camera.h>
+#include <mach/board.h>
+
+struct isr_queue_cmd {
+	struct list_head list;
+	struct vfe_interrupt_status vfeInterruptStatus;
+	struct vfe_frame_asf_info vfeAsfFrameInfo;
+	struct vfe_frame_bpc_info vfeBpcFrameInfo;
+	struct vfe_msg_camif_status vfeCamifStatusLocal;
+	struct vfe_bus_performance_monitor vfePmData;
+};
+
+struct msm_vfe8x_ctrl {
+	/* bit 1:0 ENC_IRQ_MASK = 0x11:
+	 * generate IRQ when both y and cbcr frame is ready. */
+
+	/* bit 1:0 VIEW_IRQ_MASK= 0x11:
+	 * generate IRQ when both y and cbcr frame is ready. */
+	struct vfe_irq_composite_mask_config vfeIrqCompositeMaskLocal;
+	struct vfe_module_enable vfeModuleEnableLocal;
+	struct vfe_camif_cfg_data vfeCamifConfigLocal;
+	struct vfe_cmds_camif_epoch vfeCamifEpoch1Local;
+	struct vfe_interrupt_mask vfeImaskLocal;
+	struct vfe_stats_cmd_data vfeStatsCmdLocal;
+	struct vfe_bus_cfg_data vfeBusConfigLocal;
+	struct vfe_cmd_bus_pm_start vfeBusPmConfigLocal;
+	struct vfe_bus_cmd_data vfeBusCmdLocal;
+	enum vfe_interrupt_name vfeInterruptNameLocal;
+	uint32_t vfeLaBankSel;
+	struct vfe_gamma_lut_sel vfeGammaLutSel;
+
+	boolean vfeStartAckPendingFlag;
+	boolean vfeStopAckPending;
+	boolean vfeResetAckPending;
+	boolean vfeUpdateAckPending;
+
+	enum VFE_AXI_OUTPUT_MODE axiOutputMode;
+	enum VFE_START_OPERATION_MODE vfeOperationMode;
+
+	uint32_t vfeSnapShotCount;
+	uint32_t vfeRequestedSnapShotCount;
+	boolean vfeStatsPingPongReloadFlag;
+	uint32_t vfeFrameId;
+
+	struct vfe_cmd_frame_skip_config vfeFrameSkip;
+	uint32_t vfeFrameSkipPattern;
+	uint8_t vfeFrameSkipCount;
+	uint8_t vfeFrameSkipPeriod;
+
+	boolean vfeTestGenStartFlag;
+	uint32_t vfeImaskPacked;
+	uint32_t vfeImaskCompositePacked;
+	enum VFE_RAW_PIXEL_DATA_SIZE axiInputDataSize;
+	struct vfe_irq_thread_msg vfeIrqThreadMsgLocal;
+
+	struct vfe_output_path_combo viewPath;
+	struct vfe_output_path_combo encPath;
+	struct vfe_frame_skip_counts vfeDroppedFrameCounts;
+	struct vfe_stats_control afStatsControl;
+	struct vfe_stats_control awbStatsControl;
+
+	enum VFE_STATE vstate;
+
+	struct msm_vfe_callback *resp;
+	struct vfe_frame_extra extdata;
+
+	struct isr_queue_cmd irqs[5];
+	spinlock_t irqs_lock;
+	int irq_get;
+	int irq_put;
+
+	int vfeirq;
+	void __iomem *vfebase;
+
+	void *syncdata;
+};
+
+static struct msm_vfe8x_ctrl *ctrl;
+
+static void vfe_prog_hw(uint8_t *hwreg, uint32_t *inptr, uint32_t regcnt)
+{
+	/* unsigned long flags; */
+	uint32_t i;
+	uint32_t *p;
+
+	p = (uint32_t *) (hwreg);
+	for (i = 0; i < (regcnt >> 2); i++)
+		writel(*inptr++, p++);
+	/* *p++ = *inptr++; */
+}
+
+static void
+vfe_set_bus_pipo_addr(struct vfe_output_path_combo *vpath,
+		      struct vfe_output_path_combo *epath)
+{
+	vpath->yPath.hwRegPingAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PING_ADDR);
+	vpath->yPath.hwRegPongAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PONG_ADDR);
+	vpath->cbcrPath.hwRegPingAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PING_ADDR);
+	vpath->cbcrPath.hwRegPongAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PONG_ADDR);
+
+	epath->yPath.hwRegPingAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR);
+	epath->yPath.hwRegPongAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_ENC_Y_WR_PONG_ADDR);
+	epath->cbcrPath.hwRegPingAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PING_ADDR);
+	epath->cbcrPath.hwRegPongAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PONG_ADDR);
+}
+
+static void vfe_axi_output(struct vfe_cmd_axi_output_config *in,
+			   struct vfe_output_path_combo *out1,
+			   struct vfe_output_path_combo *out2, uint16_t out)
+{
+	struct vfe_axi_out_cfg cmd;
+
+	uint16_t temp;
+	uint32_t burstLength;
+
+	memset(&cmd, 0, sizeof(cmd));
+	/* force it to burst length 4, hardware does not support it. */
+	burstLength = 1;
+
+	/* AXI Output 2 Y Configuration */
+	/* VFE_BUS_ENC_Y_WR_PING_ADDR  */
+	cmd.out2YPingAddr = out2->yPath.addressBuffer[0];
+
+	/* VFE_BUS_ENC_Y_WR_PONG_ADDR  */
+	cmd.out2YPongAddr = out2->yPath.addressBuffer[1];
+
+	/* VFE_BUS_ENC_Y_WR_IMAGE_SIZE */
+	cmd.out2YImageHeight = in->output2.outputY.imageHeight;
+	/* convert the image width and row increment to be in
+	 * unit of 64bit (8 bytes) */
+	temp = (in->output2.outputY.imageWidth + (out - 1)) / out;
+	cmd.out2YImageWidthin64bit = temp;
+
+	/* VFE_BUS_ENC_Y_WR_BUFFER_CFG */
+	cmd.out2YBurstLength = burstLength;
+	cmd.out2YNumRows = in->output2.outputY.outRowCount;
+	temp = (in->output2.outputY.outRowIncrement + (out - 1)) / out;
+	cmd.out2YRowIncrementIn64bit = temp;
+
+	/* AXI Output 2 Cbcr Configuration */
+	/* VFE_BUS_ENC_Cbcr_WR_PING_ADDR  */
+	cmd.out2CbcrPingAddr = out2->cbcrPath.addressBuffer[0];
+
+	/* VFE_BUS_ENC_Cbcr_WR_PONG_ADDR  */
+	cmd.out2CbcrPongAddr = out2->cbcrPath.addressBuffer[1];
+
+	/* VFE_BUS_ENC_Cbcr_WR_IMAGE_SIZE */
+	cmd.out2CbcrImageHeight = in->output2.outputCbcr.imageHeight;
+	temp = (in->output2.outputCbcr.imageWidth + (out - 1)) / out;
+	cmd.out2CbcrImageWidthIn64bit = temp;
+
+	/* VFE_BUS_ENC_Cbcr_WR_BUFFER_CFG */
+	cmd.out2CbcrBurstLength = burstLength;
+	cmd.out2CbcrNumRows = in->output2.outputCbcr.outRowCount;
+	temp = (in->output2.outputCbcr.outRowIncrement + (out - 1)) / out;
+	cmd.out2CbcrRowIncrementIn64bit = temp;
+
+	/* AXI Output 1 Y Configuration */
+	/* VFE_BUS_VIEW_Y_WR_PING_ADDR  */
+	cmd.out1YPingAddr = out1->yPath.addressBuffer[0];
+
+	/* VFE_BUS_VIEW_Y_WR_PONG_ADDR */
+	cmd.out1YPongAddr = out1->yPath.addressBuffer[1];
+
+	/* VFE_BUS_VIEW_Y_WR_IMAGE_SIZE */
+	cmd.out1YImageHeight = in->output1.outputY.imageHeight;
+	temp = (in->output1.outputY.imageWidth + (out - 1)) / out;
+	cmd.out1YImageWidthin64bit = temp;
+
+	/* VFE_BUS_VIEW_Y_WR_BUFFER_CFG     */
+	cmd.out1YBurstLength = burstLength;
+	cmd.out1YNumRows = in->output1.outputY.outRowCount;
+
+	temp = (in->output1.outputY.outRowIncrement + (out - 1)) / out;
+	cmd.out1YRowIncrementIn64bit = temp;
+
+	/* AXI Output 1 Cbcr Configuration */
+	cmd.out1CbcrPingAddr = out1->cbcrPath.addressBuffer[0];
+
+	/* VFE_BUS_VIEW_Cbcr_WR_PONG_ADDR  */
+	cmd.out1CbcrPongAddr = out1->cbcrPath.addressBuffer[1];
+
+	/* VFE_BUS_VIEW_Cbcr_WR_IMAGE_SIZE */
+	cmd.out1CbcrImageHeight = in->output1.outputCbcr.imageHeight;
+	temp = (in->output1.outputCbcr.imageWidth + (out - 1)) / out;
+	cmd.out1CbcrImageWidthIn64bit = temp;
+
+	cmd.out1CbcrBurstLength = burstLength;
+	cmd.out1CbcrNumRows = in->output1.outputCbcr.outRowCount;
+	temp = (in->output1.outputCbcr.outRowIncrement + (out - 1)) / out;
+
+	cmd.out1CbcrRowIncrementIn64bit = temp;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_reg_bus_cfg(struct vfe_bus_cfg_data *in)
+{
+	struct vfe_axi_bus_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.stripeRdPathEn = in->stripeRdPathEn;
+	cmd.encYWrPathEn = in->encYWrPathEn;
+	cmd.encCbcrWrPathEn = in->encCbcrWrPathEn;
+	cmd.viewYWrPathEn = in->viewYWrPathEn;
+	cmd.viewCbcrWrPathEn = in->viewCbcrWrPathEn;
+	cmd.rawPixelDataSize = (uint32_t) in->rawPixelDataSize;
+	cmd.rawWritePathSelect = (uint32_t) in->rawWritePathSelect;
+
+	/*  program vfe_bus_cfg */
+	writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CFG);
+}
+
+static void vfe_reg_camif_config(struct vfe_camif_cfg_data *in)
+{
+	struct VFE_CAMIFConfigType cfg;
+
+	memset(&cfg, 0, sizeof(cfg));
+
+	cfg.VSyncEdge = in->camifCfgFromCmd.vSyncEdge;
+
+	cfg.HSyncEdge = in->camifCfgFromCmd.hSyncEdge;
+
+	cfg.syncMode = in->camifCfgFromCmd.syncMode;
+
+	cfg.vfeSubsampleEnable = in->camifCfgFromCmd.vfeSubSampleEnable;
+
+	cfg.busSubsampleEnable = in->camifCfgFromCmd.busSubSampleEnable;
+
+	cfg.camif2vfeEnable = in->camif2OutputEnable;
+
+	cfg.camif2busEnable = in->camif2BusEnable;
+
+	cfg.irqSubsampleEnable = in->camifCfgFromCmd.irqSubSampleEnable;
+
+	cfg.binningEnable = in->camifCfgFromCmd.binningEnable;
+
+	cfg.misrEnable = in->camifCfgFromCmd.misrEnable;
+
+	/*  program camif_config */
+	writel(*((uint32_t *)&cfg), ctrl->vfebase + CAMIF_CONFIG);
+}
+
+static void vfe_reg_bus_cmd(struct vfe_bus_cmd_data *in)
+{
+	struct vfe_buscmd cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.stripeReload = in->stripeReload;
+	cmd.busPingpongReload = in->busPingpongReload;
+	cmd.statsPingpongReload = in->statsPingpongReload;
+
+	writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CMD);
+
+	CDBG("bus command = 0x%x\n", (*((uint32_t *)&cmd)));
+
+	/* this is needed, as the control bits are pulse based.
+	 * Don't want to reload bus pingpong again. */
+	in->busPingpongReload = 0;
+	in->statsPingpongReload = 0;
+	in->stripeReload = 0;
+}
+
+static void vfe_reg_module_cfg(struct vfe_module_enable *in)
+{
+	struct vfe_mod_enable ena;
+
+	memset(&ena, 0, sizeof(ena));
+
+	ena.blackLevelCorrectionEnable = in->blackLevelCorrectionEnable;
+	ena.lensRollOffEnable = in->lensRollOffEnable;
+	ena.demuxEnable = in->demuxEnable;
+	ena.chromaUpsampleEnable = in->chromaUpsampleEnable;
+	ena.demosaicEnable = in->demosaicEnable;
+	ena.statsEnable = in->statsEnable;
+	ena.cropEnable = in->cropEnable;
+	ena.mainScalerEnable = in->mainScalerEnable;
+	ena.whiteBalanceEnable = in->whiteBalanceEnable;
+	ena.colorCorrectionEnable = in->colorCorrectionEnable;
+	ena.yHistEnable = in->yHistEnable;
+	ena.skinToneEnable = in->skinToneEnable;
+	ena.lumaAdaptationEnable = in->lumaAdaptationEnable;
+	ena.rgbLUTEnable = in->rgbLUTEnable;
+	ena.chromaEnhanEnable = in->chromaEnhanEnable;
+	ena.asfEnable = in->asfEnable;
+	ena.chromaSuppressionEnable = in->chromaSuppressionEnable;
+	ena.chromaSubsampleEnable = in->chromaSubsampleEnable;
+	ena.scaler2YEnable = in->scaler2YEnable;
+	ena.scaler2CbcrEnable = in->scaler2CbcrEnable;
+
+	writel(*((uint32_t *)&ena), ctrl->vfebase + VFE_MODULE_CFG);
+}
+
+static void vfe_program_dmi_cfg(enum VFE_DMI_RAM_SEL bankSel)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = (uint32_t) ctrl->vfebase + VFE_DMI_CFG_DEFAULT;
+
+	value += (uint32_t) bankSel;
+	/* CDBG("dmi cfg input bank is  0x%x\n", bankSel); */
+
+	writel(value, ctrl->vfebase + VFE_DMI_CFG);
+	writel(0, ctrl->vfebase + VFE_DMI_ADDR);
+}
+
+static void vfe_write_lens_roll_off_table(struct vfe_cmd_roll_off_config *in)
+{
+	uint16_t i;
+	uint32_t data;
+
+	uint16_t *initGr = in->initTableGr;
+	uint16_t *initGb = in->initTableGb;
+	uint16_t *initB = in->initTableB;
+	uint16_t *initR = in->initTableR;
+
+	int16_t *pDeltaGr = in->deltaTableGr;
+	int16_t *pDeltaGb = in->deltaTableGb;
+	int16_t *pDeltaB = in->deltaTableB;
+	int16_t *pDeltaR = in->deltaTableR;
+
+	vfe_program_dmi_cfg(ROLLOFF_RAM);
+
+	/* first pack and write init table */
+	for (i = 0; i < VFE_ROLL_OFF_INIT_TABLE_SIZE; i++) {
+		data = (((uint32_t) (*initR)) & 0x0000FFFF) |
+		    (((uint32_t) (*initGr)) << 16);
+		initR++;
+		initGr++;
+
+		writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+
+		data = (((uint32_t) (*initB)) & 0x0000FFFF) |
+		    (((uint32_t) (*initGr)) << 16);
+		initB++;
+		initGb++;
+
+		writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+	}
+
+	/* there are gaps between the init table and delta table,
+	 * set the offset for delta table. */
+	writel(LENS_ROLL_OFF_DELTA_TABLE_OFFSET, ctrl->vfebase + VFE_DMI_ADDR);
+
+	/* pack and write delta table */
+	for (i = 0; i < VFE_ROLL_OFF_DELTA_TABLE_SIZE; i++) {
+		data = *pDeltaR | (*pDeltaGr << 16);
+		pDeltaR++;
+		pDeltaGr++;
+
+		writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+
+		data = *pDeltaB | (*pDeltaGb << 16);
+		pDeltaB++;
+		pDeltaGb++;
+
+		writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+	}
+
+	/* After DMI transfer, to make it safe, need to set the
+	 * DMI_CFG to unselect any SRAM
+	 */
+	/* unselect the SRAM Bank. */
+	writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+}
+
+static void vfe_set_default_reg_values(void)
+{
+	writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_0);
+	writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_1);
+	writel(0xFFFFF, ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+	/* default frame drop period and pattern */
+	writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+	writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+	writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+	writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+	writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_CFG);
+	writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_CFG);
+	writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+	writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+	writel(0, ctrl->vfebase + VFE_CLAMP_MIN_CFG);
+	writel(0xFFFFFF, ctrl->vfebase + VFE_CLAMP_MAX_CFG);
+}
+
+static void vfe_config_demux(uint32_t period, uint32_t even, uint32_t odd)
+{
+	writel(period, ctrl->vfebase + VFE_DEMUX_CFG);
+	writel(even, ctrl->vfebase + VFE_DEMUX_EVEN_CFG);
+	writel(odd, ctrl->vfebase + VFE_DEMUX_ODD_CFG);
+}
+
+static void vfe_pm_stop(void)
+{
+	writel(VFE_PERFORMANCE_MONITOR_STOP, ctrl->vfebase + VFE_BUS_PM_CMD);
+}
+
+static void vfe_camif_stop_immediately(void)
+{
+	writel(CAMIF_COMMAND_STOP_IMMEDIATELY, ctrl->vfebase + CAMIF_COMMAND);
+	writel(0, ctrl->vfebase + VFE_CGC_OVERRIDE);
+}
+
+static void vfe_program_reg_update_cmd(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static void vfe_program_global_reset_cmd(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_GLOBAL_RESET_CMD);
+}
+
+static void vfe_program_axi_cmd(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_AXI_CMD);
+}
+
+static void vfe_program_irq_composite_mask(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK);
+}
+
+static inline void vfe_program_irq_mask(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_IRQ_MASK);
+}
+
+static uint32_t vfe_read_axi_status(void)
+{
+	return readl(ctrl->vfebase + VFE_AXI_STATUS);
+}
+
+static void
+vfe_set_stats_pingpong_address(struct vfe_stats_control *afControl,
+			       struct vfe_stats_control *awbControl)
+{
+	afControl->hwRegPingAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	afControl->hwRegPongAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+
+	awbControl->hwRegPingAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	awbControl->hwRegPongAddress = (uint8_t *)
+	    (ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static void vfe_program_lut_bank_sel(struct vfe_gamma_lut_sel *in)
+{
+	struct VFE_GammaLutSelect_ConfigCmdType cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.ch0BankSelect = in->ch0BankSelect;
+	cmd.ch1BankSelect = in->ch1BankSelect;
+	cmd.ch2BankSelect = in->ch2BankSelect;
+	CDBG("VFE gamma lut bank selection is 0x%x\n", *((uint32_t *)&cmd));
+	vfe_prog_hw(ctrl->vfebase + VFE_LUT_BANK_SEL,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_program_stats_cmd(struct vfe_stats_cmd_data *in)
+{
+	struct VFE_StatsCmdType stats;
+	memset(&stats, 0, sizeof(stats));
+
+	stats.autoFocusEnable = in->autoFocusEnable;
+	stats.axwEnable = in->axwEnable;
+	stats.histEnable = in->histEnable;
+	stats.clearHistEnable = in->clearHistEnable;
+	stats.histAutoClearEnable = in->histAutoClearEnable;
+	stats.colorConversionEnable = in->colorConversionEnable;
+
+	writel(*((uint32_t *)&stats), ctrl->vfebase + VFE_STATS_CMD);
+}
+
+static void vfe_pm_start(struct vfe_cmd_bus_pm_start *in)
+{
+	struct VFE_Bus_Pm_ConfigCmdType cmd;
+	memset(&cmd, 0, sizeof(struct VFE_Bus_Pm_ConfigCmdType));
+
+	cmd.output2YWrPmEnable = in->output2YWrPmEnable;
+	cmd.output2CbcrWrPmEnable = in->output2CbcrWrPmEnable;
+	cmd.output1YWrPmEnable = in->output1YWrPmEnable;
+	cmd.output1CbcrWrPmEnable = in->output1CbcrWrPmEnable;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_BUS_PM_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_8k_pm_start(struct vfe_cmd_bus_pm_start *in)
+{
+	in->output1CbcrWrPmEnable = ctrl->vfeBusConfigLocal.viewCbcrWrPathEn;
+	in->output1YWrPmEnable = ctrl->vfeBusConfigLocal.viewYWrPathEn;
+	in->output2CbcrWrPmEnable = ctrl->vfeBusConfigLocal.encCbcrWrPathEn;
+	in->output2YWrPmEnable = ctrl->vfeBusConfigLocal.encYWrPathEn;
+
+	if (in->output1CbcrWrPmEnable || in->output1YWrPmEnable)
+		ctrl->viewPath.pmEnabled = TRUE;
+
+	if (in->output2CbcrWrPmEnable || in->output2YWrPmEnable)
+		ctrl->encPath.pmEnabled = TRUE;
+
+	vfe_pm_start(in);
+
+	writel(VFE_PERFORMANCE_MONITOR_GO, ctrl->vfebase + VFE_BUS_PM_CMD);
+}
+
+static uint32_t vfe_irq_pack(struct vfe_interrupt_mask data)
+{
+	struct vfe_irqenable packedData;
+
+	memset(&packedData, 0, sizeof(packedData));
+
+	packedData.camifErrorIrq = data.camifErrorIrq;
+	packedData.camifSofIrq = data.camifSofIrq;
+	packedData.camifEolIrq = data.camifEolIrq;
+	packedData.camifEofIrq = data.camifEofIrq;
+	packedData.camifEpoch1Irq = data.camifEpoch1Irq;
+	packedData.camifEpoch2Irq = data.camifEpoch2Irq;
+	packedData.camifOverflowIrq = data.camifOverflowIrq;
+	packedData.ceIrq = data.ceIrq;
+	packedData.regUpdateIrq = data.regUpdateIrq;
+	packedData.resetAckIrq = data.resetAckIrq;
+	packedData.encYPingpongIrq = data.encYPingpongIrq;
+	packedData.encCbcrPingpongIrq = data.encCbcrPingpongIrq;
+	packedData.viewYPingpongIrq = data.viewYPingpongIrq;
+	packedData.viewCbcrPingpongIrq = data.viewCbcrPingpongIrq;
+	packedData.rdPingpongIrq = data.rdPingpongIrq;
+	packedData.afPingpongIrq = data.afPingpongIrq;
+	packedData.awbPingpongIrq = data.awbPingpongIrq;
+	packedData.histPingpongIrq = data.histPingpongIrq;
+	packedData.encIrq = data.encIrq;
+	packedData.viewIrq = data.viewIrq;
+	packedData.busOverflowIrq = data.busOverflowIrq;
+	packedData.afOverflowIrq = data.afOverflowIrq;
+	packedData.awbOverflowIrq = data.awbOverflowIrq;
+	packedData.syncTimer0Irq = data.syncTimer0Irq;
+	packedData.syncTimer1Irq = data.syncTimer1Irq;
+	packedData.syncTimer2Irq = data.syncTimer2Irq;
+	packedData.asyncTimer0Irq = data.asyncTimer0Irq;
+	packedData.asyncTimer1Irq = data.asyncTimer1Irq;
+	packedData.asyncTimer2Irq = data.asyncTimer2Irq;
+	packedData.asyncTimer3Irq = data.asyncTimer3Irq;
+	packedData.axiErrorIrq = data.axiErrorIrq;
+	packedData.violationIrq = data.violationIrq;
+
+	return *((uint32_t *)&packedData);
+}
+
+static uint32_t
+vfe_irq_composite_pack(struct vfe_irq_composite_mask_config data)
+{
+	struct VFE_Irq_Composite_MaskType packedData;
+
+	memset(&packedData, 0, sizeof(packedData));
+
+	packedData.encIrqComMaskBits = data.encIrqComMask;
+	packedData.viewIrqComMaskBits = data.viewIrqComMask;
+	packedData.ceDoneSelBits = data.ceDoneSel;
+
+	return *((uint32_t *)&packedData);
+}
+
+static void vfe_addr_convert(struct msm_vfe_phy_info *pinfo,
+			     enum vfe_resp_msg type, void *data, void **ext,
+			     int *elen)
+{
+	switch (type) {
+	case VFE_MSG_OUTPUT1:{
+			pinfo->y_phy =
+			    ((struct vfe_message *)data)->_u.msgOutput1.yBuffer;
+			pinfo->cbcr_phy =
+			    ((struct vfe_message *)data)->_u.msgOutput1.
+			    cbcrBuffer;
+
+			ctrl->extdata.bpcInfo =
+			    ((struct vfe_message *)data)->_u.msgOutput1.bpcInfo;
+
+			ctrl->extdata.asfInfo =
+			    ((struct vfe_message *)data)->_u.msgOutput1.asfInfo;
+
+			ctrl->extdata.frameCounter =
+			    ((struct vfe_message *)data)->_u.msgOutput1.
+			    frameCounter;
+
+			ctrl->extdata.pmData =
+			    ((struct vfe_message *)data)->_u.msgOutput1.pmData;
+
+			*ext = &ctrl->extdata;
+			*elen = sizeof(ctrl->extdata);
+		}
+		break;
+
+	case VFE_MSG_OUTPUT2:{
+			pinfo->y_phy =
+			    ((struct vfe_message *)data)->_u.msgOutput2.yBuffer;
+			pinfo->cbcr_phy =
+			    ((struct vfe_message *)data)->_u.msgOutput2.
+			    cbcrBuffer;
+
+			CDBG("vfe_addr_convert, pinfo->y_phy = 0x%x\n",
+			     pinfo->y_phy);
+			CDBG("vfe_addr_convert, pinfo->cbcr_phy = 0x%x\n",
+			     pinfo->cbcr_phy);
+
+			ctrl->extdata.bpcInfo =
+			    ((struct vfe_message *)data)->_u.msgOutput2.bpcInfo;
+
+			ctrl->extdata.asfInfo =
+			    ((struct vfe_message *)data)->_u.msgOutput2.asfInfo;
+
+			ctrl->extdata.frameCounter =
+			    ((struct vfe_message *)data)->_u.msgOutput2.
+			    frameCounter;
+
+			ctrl->extdata.pmData =
+			    ((struct vfe_message *)data)->_u.msgOutput2.pmData;
+
+			*ext = &ctrl->extdata;
+			*elen = sizeof(ctrl->extdata);
+		}
+		break;
+
+	case VFE_MSG_STATS_AF:
+		pinfo->sbuf_phy =
+		    ((struct vfe_message *)data)->_u.msgStatsAf.afBuffer;
+		break;
+
+	case VFE_MSG_STATS_WE:
+		pinfo->sbuf_phy =
+		    ((struct vfe_message *)data)->_u.msgStatsWbExp.awbBuffer;
+		break;
+
+	default:
+		break;
+	}			/* switch */
+}
+
+static boolean vfe_send_output1_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_output2_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_af_stats_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_awb_stats_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_camif_error_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_bus_overflow_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+
+static boolean invalid(struct msm_vfe_resp *rp,
+		struct vfe_message *_m, void *_d)
+{
+	BUG_ON(1); /* this function should not be called. */
+	return FALSE;
+}
+
+static struct {
+	boolean (*fn)(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data);
+	enum vfe_resp_msg rt; /* reponse type */
+} vfe_funcs[] = {
+	[VFE_MSG_ID_RESET_ACK] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_START_ACK] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_STOP_ACK] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_UPDATE_ACK] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_OUTPUT1] = { vfe_send_output1_msg, VFE_MSG_OUTPUT1 },
+	[VFE_MSG_ID_OUTPUT2] = { vfe_send_output2_msg, VFE_MSG_OUTPUT2 },
+	[VFE_MSG_ID_SNAPSHOT_DONE] = { NULL, VFE_MSG_SNAPSHOT },
+	[VFE_MSG_ID_STATS_AUTOFOCUS] = { vfe_send_af_stats_msg, VFE_MSG_STATS_AF },
+	[VFE_MSG_ID_STATS_WB_EXP] = { vfe_send_awb_stats_msg, VFE_MSG_STATS_WE },
+	[VFE_MSG_ID_EPOCH1] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_EPOCH2] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_SYNC_TIMER0_DONE] = { invalid },
+	[VFE_MSG_ID_SYNC_TIMER1_DONE] = { invalid },
+	[VFE_MSG_ID_SYNC_TIMER2_DONE] = { invalid },
+	[VFE_MSG_ID_ASYNC_TIMER0_DONE] = { invalid },
+	[VFE_MSG_ID_ASYNC_TIMER1_DONE] = { invalid },
+	[VFE_MSG_ID_ASYNC_TIMER2_DONE] = { invalid },
+	[VFE_MSG_ID_ASYNC_TIMER3_DONE] = { invalid },
+	[VFE_MSG_ID_AF_OVERFLOW] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_AWB_OVERFLOW] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_AXI_ERROR] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_CAMIF_OVERFLOW] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_VIOLATION] = { invalid },
+	[VFE_MSG_ID_CAMIF_ERROR] = { vfe_send_camif_error_msg, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_BUS_OVERFLOW] = { vfe_send_bus_overflow_msg, VFE_MSG_GENERAL },
+};
+
+static void vfe_proc_ops(enum VFE_MESSAGE_ID id, void *data)
+{
+	struct msm_vfe_resp *rp;
+	struct vfe_message *msg;
+	struct msm_sync *sync = (struct msm_sync *)ctrl->syncdata;
+
+	CDBG("ctrl->vfeOperationMode = %d, msgId = %d\n",
+	     ctrl->vfeOperationMode, id);
+
+	if (id >= ARRAY_SIZE(vfe_funcs) || vfe_funcs[id].fn == invalid) {
+		pr_err("%s: invalid VFE message id %d\n", __func__, id);
+		return;
+	}
+
+	/* In 8k, OUTPUT1 & OUTPUT2 messages arrive before SNAPSHOT_DONE.
+	 * We don't send such messages to the user.  Note that we can do
+	 * this in the vfe_func[] callback, but that would cause us to
+	 * allocate and then immediately free the msm_vfe_resp structure,
+	 * which is wasteful.
+	 */
+	if ((ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) &&
+			(id == VFE_MSG_ID_OUTPUT1 ||
+			 id == VFE_MSG_ID_OUTPUT2))
+		return;
+
+	rp = ctrl->resp->vfe_alloc(sizeof(*rp) +
+					(vfe_funcs[id].fn ? sizeof(*msg) : 0),
+					ctrl->syncdata,
+					GFP_ATOMIC);
+	if (!rp) {
+		pr_err("%s: out of memory\n", __func__);
+		return;
+	}
+
+	rp->type = vfe_funcs[id].rt;
+	rp->evt_msg.type = MSM_CAMERA_MSG;
+	rp->evt_msg.msg_id = id;
+
+	/* Turn off the flash if epoch1 is enabled and snapshot is done. */
+	if (ctrl->vfeCamifEpoch1Local.enable &&
+			ctrl->vfeOperationMode ==
+				VFE_START_OPERATION_MODE_SNAPSHOT &&
+			id == VFE_MSG_ID_SNAPSHOT_DONE) {
+		ctrl->resp->flash_ctrl(sync, MSM_CAMERA_LED_OFF);
+		ctrl->vfeCamifEpoch1Local.enable = 0;
+	}
+
+	if (!vfe_funcs[id].fn) {
+		rp->evt_msg.len = 0;
+		rp->evt_msg.data = 0;
+	} else {
+		/* populate the message accordingly */
+		if (vfe_funcs[id].fn)
+			rp->evt_msg.data = msg =
+				(struct vfe_message *)(rp + 1);
+		else
+			rp->evt_msg.data = msg = 0;
+		rp->evt_msg.len = sizeof(*msg);
+		msg->_d = id;
+		if (vfe_funcs[id].fn(rp, msg, data) == FALSE) {
+			pr_info("%s: freeing memory: handler for %d "
+				"returned false\n", __func__, id);
+			ctrl->resp->vfe_free(rp);
+			return;
+		}
+	}
+
+	ctrl->resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, ctrl->syncdata, GFP_ATOMIC);
+}
+
+static boolean vfe_send_bus_overflow_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg,
+			void *data)
+{
+	struct isr_queue_cmd *qcmd = data;
+	memcpy(&(msg->_u.msgBusOverflow),
+	       &qcmd->vfePmData, sizeof(qcmd->vfePmData));
+	return TRUE;
+}
+
+static boolean vfe_send_camif_error_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg,
+			void *data)
+{
+	struct isr_queue_cmd *qcmd = data;
+	memcpy(&(msg->_u.msgCamifError),
+	       &qcmd->vfeCamifStatusLocal, sizeof(qcmd->vfeCamifStatusLocal));
+	return TRUE;
+}
+
+static void vfe_process_error_irq(struct isr_queue_cmd *qcmd)
+{
+	struct vfe_interrupt_status *irqstatus = &qcmd->vfeInterruptStatus;
+
+	/* all possible error irq.  Note error irqs are not enabled, it is
+	 * checked only when other interrupts are present. */
+	if (irqstatus->afOverflowIrq)
+		vfe_proc_ops(VFE_MSG_ID_AF_OVERFLOW, qcmd);
+
+	if (irqstatus->awbOverflowIrq)
+		vfe_proc_ops(VFE_MSG_ID_AWB_OVERFLOW, qcmd);
+
+	if (irqstatus->axiErrorIrq)
+		vfe_proc_ops(VFE_MSG_ID_AXI_ERROR, qcmd);
+
+	if (irqstatus->busOverflowIrq)
+		vfe_proc_ops(VFE_MSG_ID_BUS_OVERFLOW, qcmd);
+
+	if (irqstatus->camifErrorIrq)
+		vfe_proc_ops(VFE_MSG_ID_CAMIF_ERROR, qcmd);
+
+	if (irqstatus->camifOverflowIrq)
+		vfe_proc_ops(VFE_MSG_ID_CAMIF_OVERFLOW, qcmd);
+
+	if (irqstatus->violationIrq)
+		pr_err("%s: violation irq\n", __func__);
+}
+
+/* We use epoch1 interrupt to control flash timing. The purpose is to reduce the
+ * flash duration as much as possible. Userspace driver has no way to control
+ * the exactly timing like VFE. Currently we skip a frame during snapshot.
+ * We want to fire the flash in the middle of the first frame. Epoch1 interrupt
+ * allows us to set a line index and we will get an interrupt when VFE reaches
+ * the line. Userspace driver sets the line index in camif configuration. VFE
+ * will fire the flash in high mode when it gets the epoch1 interrupt. Flash
+ * will be turned off after snapshot is done.
+ */
+static void vfe_process_camif_epoch1_irq(void)
+{
+	/* Turn on the flash. */
+	struct msm_sync *sync = (struct msm_sync *)ctrl->syncdata;
+	ctrl->resp->flash_ctrl(sync, MSM_CAMERA_LED_HIGH);
+
+	/* Disable the epoch1 interrupt. */
+	ctrl->vfeImaskLocal.camifEpoch1Irq = FALSE;
+	ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+	vfe_program_irq_mask(ctrl->vfeImaskPacked);
+}
+
+static void vfe_process_camif_sof_irq(void)
+{
+	/* increment the frame id number. */
+	ctrl->vfeFrameId++;
+
+	CDBG("camif_sof_irq, frameId = %d\n", ctrl->vfeFrameId);
+
+	/* In snapshot mode, if frame skip is programmed,
+	 * need to check it accordingly to stop camif at
+	 * correct frame boundary. For the dropped frames,
+	 * there won't be any output path irqs, but there is
+	 * still SOF irq, which can help us determine when
+	 * to stop the camif.
+	 */
+	if (ctrl->vfeOperationMode) {
+		if ((1 << ctrl->vfeFrameSkipCount)&ctrl->vfeFrameSkipPattern) {
+
+			ctrl->vfeSnapShotCount--;
+			if (ctrl->vfeSnapShotCount == 0)
+				/* terminate vfe pipeline at frame boundary. */
+				writel(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+				       ctrl->vfebase + CAMIF_COMMAND);
+		}
+
+		/* update frame skip counter for bit checking. */
+		ctrl->vfeFrameSkipCount++;
+		if (ctrl->vfeFrameSkipCount == (ctrl->vfeFrameSkipPeriod + 1))
+			ctrl->vfeFrameSkipCount = 0;
+	}
+}
+
+static boolean vfe_get_af_pingpong_status(void)
+{
+	uint32_t busPingPongStatus =
+		readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+	return !!(busPingPongStatus & VFE_AF_PINGPONG_STATUS_BIT);
+}
+
+static uint32_t vfe_read_af_buf_addr(boolean pipo)
+{
+	if (pipo == FALSE)
+		return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	else
+		return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+}
+
+static void vfe_update_af_buf_addr(boolean pipo, uint32_t addr)
+{
+	if (pipo == FALSE)
+		writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	else
+		writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+}
+
+static boolean vfe_send_af_stats_msg(struct msm_vfe_resp *rp,
+		struct vfe_message *msg, void *data)
+{
+	uint32_t afBufAddress = (uint32_t)data;
+
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return FALSE;
+
+	msg->_u.msgStatsAf.afBuffer = afBufAddress;
+	msg->_u.msgStatsAf.frameCounter = ctrl->vfeFrameId;
+
+	ctrl->afStatsControl.ackPending = TRUE;
+
+	vfe_addr_convert(&(rp->phy), rp->type, msg, NULL, NULL);
+
+	return TRUE;
+}
+
+static void vfe_process_stats_af_irq(void)
+{
+	boolean bufferAvailable;
+
+	if (!(ctrl->afStatsControl.ackPending)) {
+
+		/* read hardware status. */
+		ctrl->afStatsControl.pingPongStatus =
+		    vfe_get_af_pingpong_status();
+
+		bufferAvailable = (ctrl->afStatsControl.pingPongStatus) ^ 1;
+
+		ctrl->afStatsControl.bufToRender =
+		    vfe_read_af_buf_addr(bufferAvailable);
+
+		/* update the same buffer address (ping or pong) */
+		vfe_update_af_buf_addr(bufferAvailable,
+				       ctrl->afStatsControl.nextFrameAddrBuf);
+
+		vfe_proc_ops(VFE_MSG_ID_STATS_AUTOFOCUS,
+			(void *)ctrl->afStatsControl.bufToRender);
+	} else
+		ctrl->afStatsControl.droppedStatsFrameCount++;
+}
+
+static boolean vfe_get_awb_pingpong_status(void)
+{
+	uint32_t busPingPongStatus =
+		readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+	return !!(busPingPongStatus & VFE_AWB_PINGPONG_STATUS_BIT);
+}
+
+static uint32_t vfe_read_awb_buf_addr(boolean pingpong)
+{
+	if (pingpong == FALSE)
+		return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	else
+		return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static void vfe_update_awb_buf_addr(boolean pingpong, uint32_t addr)
+{
+	if (pingpong == FALSE)
+		writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	else
+		writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static boolean vfe_send_awb_stats_msg(struct msm_vfe_resp *rp,
+		struct vfe_message *msg, void *data)
+{
+	uint32_t awbBufAddress = (uint32_t)data;
+
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return FALSE;
+
+	msg->_u.msgStatsWbExp.awbBuffer = awbBufAddress;
+	msg->_u.msgStatsWbExp.frameCounter = ctrl->vfeFrameId;
+
+	ctrl->awbStatsControl.ackPending = TRUE;
+
+	vfe_addr_convert(&(rp->phy),
+			rp->type, msg,
+			NULL, NULL);
+
+	return TRUE;
+}
+
+static void vfe_process_stats_awb_irq(void)
+{
+	boolean bufferAvailable;
+
+	if (!(ctrl->awbStatsControl.ackPending)) {
+
+		ctrl->awbStatsControl.pingPongStatus =
+		    vfe_get_awb_pingpong_status();
+
+		bufferAvailable = (ctrl->awbStatsControl.pingPongStatus) ^ 1;
+
+		ctrl->awbStatsControl.bufToRender =
+		    vfe_read_awb_buf_addr(bufferAvailable);
+
+		vfe_update_awb_buf_addr(bufferAvailable,
+			ctrl->awbStatsControl.nextFrameAddrBuf);
+
+		vfe_proc_ops(VFE_MSG_ID_STATS_WB_EXP,
+			(void *)ctrl->awbStatsControl.bufToRender);
+
+	} else
+		ctrl->awbStatsControl.droppedStatsFrameCount++;
+}
+
+static void vfe_write_gamma_table(uint8_t channel,
+				  boolean bank, int16_t *pTable)
+{
+	uint16_t i;
+
+	enum VFE_DMI_RAM_SEL dmiRamSel = NO_MEM_SELECTED;
+
+	switch (channel) {
+	case 0:
+		if (bank == 0)
+			dmiRamSel = RGBLUT_RAM_CH0_BANK0;
+		else
+			dmiRamSel = RGBLUT_RAM_CH0_BANK1;
+		break;
+
+	case 1:
+		if (bank == 0)
+			dmiRamSel = RGBLUT_RAM_CH1_BANK0;
+		else
+			dmiRamSel = RGBLUT_RAM_CH1_BANK1;
+		break;
+
+	case 2:
+		if (bank == 0)
+			dmiRamSel = RGBLUT_RAM_CH2_BANK0;
+		else
+			dmiRamSel = RGBLUT_RAM_CH2_BANK1;
+		break;
+
+	default:
+		break;
+	}
+
+	vfe_program_dmi_cfg(dmiRamSel);
+
+	for (i = 0; i < VFE_GAMMA_TABLE_LENGTH; i++) {
+		writel((uint32_t) (*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+		pTable++;
+	}
+
+	/* After DMI transfer, need to set the DMI_CFG to unselect any SRAM
+	   unselect the SRAM Bank. */
+	writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+}
+
+static void vfe_prog_hw_testgen_cmd(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_HW_TESTGEN_CMD);
+}
+
+static inline void vfe_read_irq_status(struct vfe_irq_thread_msg *out)
+{
+	uint32_t *temp;
+
+	memset(out, 0, sizeof(struct vfe_irq_thread_msg));
+
+	temp = (uint32_t *) (ctrl->vfebase + VFE_IRQ_STATUS);
+	out->vfeIrqStatus = readl(temp);
+
+	temp = (uint32_t *) (ctrl->vfebase + CAMIF_STATUS);
+	out->camifStatus = readl(temp);
+#if 0				/*this for YUV performance tuning */
+	writel(0x7, ctrl->vfebase + CAMIF_COMMAND);
+	writel(0x3, ctrl->vfebase + CAMIF_COMMAND);
+	CDBG("camifStatus  = 0x%x\n", out->camifStatus);
+#endif
+/*
+	temp = (uint32_t *)(ctrl->vfebase + VFE_DEMOSAIC_STATUS);
+	out->demosaicStatus = readl(temp);
+
+	temp = (uint32_t *)(ctrl->vfebase + VFE_ASF_MAX_EDGE);
+	out->asfMaxEdge = readl(temp);
+
+	temp = (uint32_t *)(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PM_STATS_0);
+*/
+
+#if 0
+	out->pmInfo.encPathPmInfo.yWrPmStats0 = readl(temp++);
+	out->pmInfo.encPathPmInfo.yWrPmStats1 = readl(temp++);
+	out->pmInfo.encPathPmInfo.cbcrWrPmStats0 = readl(temp++);
+	out->pmInfo.encPathPmInfo.cbcrWrPmStats1 = readl(temp++);
+	out->pmInfo.viewPathPmInfo.yWrPmStats0 = readl(temp++);
+	out->pmInfo.viewPathPmInfo.yWrPmStats1 = readl(temp++);
+	out->pmInfo.viewPathPmInfo.cbcrWrPmStats0 = readl(temp++);
+	out->pmInfo.viewPathPmInfo.cbcrWrPmStats1 = readl(temp);
+#endif /* if 0 Jeff */
+}
+
+static void
+vfe_parse_interrupt_status(struct vfe_interrupt_status *ret, uint32_t irqStatusIn)
+{
+	struct vfe_irqenable hwstat;
+	boolean temp;
+
+	memset(&hwstat, 0, sizeof(hwstat));
+	memset(ret, 0, sizeof(*ret));
+
+	hwstat = *((struct vfe_irqenable *)(&irqStatusIn));
+
+	ret->camifErrorIrq = hwstat.camifErrorIrq;
+	ret->camifSofIrq = hwstat.camifSofIrq;
+	ret->camifEolIrq = hwstat.camifEolIrq;
+	ret->camifEofIrq = hwstat.camifEofIrq;
+	ret->camifEpoch1Irq = hwstat.camifEpoch1Irq;
+	ret->camifEpoch2Irq = hwstat.camifEpoch2Irq;
+	ret->camifOverflowIrq = hwstat.camifOverflowIrq;
+	ret->ceIrq = hwstat.ceIrq;
+	ret->regUpdateIrq = hwstat.regUpdateIrq;
+	ret->resetAckIrq = hwstat.resetAckIrq;
+	ret->encYPingpongIrq = hwstat.encYPingpongIrq;
+	ret->encCbcrPingpongIrq = hwstat.encCbcrPingpongIrq;
+	ret->viewYPingpongIrq = hwstat.viewYPingpongIrq;
+	ret->viewCbcrPingpongIrq = hwstat.viewCbcrPingpongIrq;
+	ret->rdPingpongIrq = hwstat.rdPingpongIrq;
+	ret->afPingpongIrq = hwstat.afPingpongIrq;
+	ret->awbPingpongIrq = hwstat.awbPingpongIrq;
+	ret->histPingpongIrq = hwstat.histPingpongIrq;
+	ret->encIrq = hwstat.encIrq;
+	ret->viewIrq = hwstat.viewIrq;
+	ret->busOverflowIrq = hwstat.busOverflowIrq;
+	ret->afOverflowIrq = hwstat.afOverflowIrq;
+	ret->awbOverflowIrq = hwstat.awbOverflowIrq;
+	ret->syncTimer0Irq = hwstat.syncTimer0Irq;
+	ret->syncTimer1Irq = hwstat.syncTimer1Irq;
+	ret->syncTimer2Irq = hwstat.syncTimer2Irq;
+	ret->asyncTimer0Irq = hwstat.asyncTimer0Irq;
+	ret->asyncTimer1Irq = hwstat.asyncTimer1Irq;
+	ret->asyncTimer2Irq = hwstat.asyncTimer2Irq;
+	ret->asyncTimer3Irq = hwstat.asyncTimer3Irq;
+	ret->axiErrorIrq = hwstat.axiErrorIrq;
+	ret->violationIrq = hwstat.violationIrq;
+
+	/* logic OR of any error bits
+	 * although each irq corresponds to a bit, the data type here is a
+	 * boolean already. hence use logic operation.
+	 */
+	temp =
+	    ret->camifErrorIrq ||
+	    ret->camifOverflowIrq ||
+	    ret->afOverflowIrq ||
+	    ret->awbOverflowIrq ||
+	    ret->awbPingpongIrq ||
+	    ret->afPingpongIrq ||
+	    ret->busOverflowIrq || ret->axiErrorIrq || ret->violationIrq;
+
+	ret->anyErrorIrqs = temp;
+
+	/* logic OR of any output path bits */
+	temp = ret->encYPingpongIrq || ret->encCbcrPingpongIrq || ret->encIrq;
+
+	ret->anyOutput2PathIrqs = temp;
+
+	temp = ret->viewYPingpongIrq || ret->viewCbcrPingpongIrq || ret->viewIrq;
+
+	ret->anyOutput1PathIrqs = temp;
+
+	ret->anyOutputPathIrqs =
+	    ret->anyOutput1PathIrqs || ret->anyOutput2PathIrqs;
+
+	/* logic OR of any sync timer bits */
+	temp = ret->syncTimer0Irq || ret->syncTimer1Irq || ret->syncTimer2Irq;
+
+	ret->anySyncTimerIrqs = temp;
+
+	/* logic OR of any async timer bits */
+	temp =
+	    ret->asyncTimer0Irq ||
+	    ret->asyncTimer1Irq || ret->asyncTimer2Irq || ret->asyncTimer3Irq;
+
+	ret->anyAsyncTimerIrqs = temp;
+
+	/* bool for all interrupts that are not allowed in idle state */
+	temp =
+	    ret->anyErrorIrqs ||
+	    ret->anyOutputPathIrqs ||
+	    ret->anySyncTimerIrqs ||
+	    ret->regUpdateIrq ||
+	    ret->awbPingpongIrq ||
+	    ret->afPingpongIrq ||
+	    ret->camifSofIrq || ret->camifEpoch2Irq || ret->camifEpoch1Irq;
+
+	ret->anyIrqForActiveStatesOnly = temp;
+}
+
+static void
+vfe_get_asf_frame_info(struct vfe_frame_asf_info *rc, struct vfe_irq_thread_msg *in)
+{
+	struct vfe_asf_info asfInfoTemp;
+
+	memset(rc, 0, sizeof(*rc));
+	memset(&asfInfoTemp, 0, sizeof(asfInfoTemp));
+
+	asfInfoTemp = *((struct vfe_asf_info *)(&(in->asfMaxEdge)));
+
+	rc->asfHbiCount = asfInfoTemp.HBICount;
+	rc->asfMaxEdge = asfInfoTemp.maxEdge;
+}
+
+static void
+vfe_get_demosaic_frame_info(struct vfe_frame_bpc_info *rc, struct vfe_irq_thread_msg *in)
+{
+	struct vfe_bps_info bpcInfoTemp;
+
+	memset(rc, 0, sizeof(*rc));
+	memset(&bpcInfoTemp, 0, sizeof(bpcInfoTemp));
+
+	bpcInfoTemp = *((struct vfe_bps_info *)(&(in->demosaicStatus)));
+
+	rc->greenDefectPixelCount = bpcInfoTemp.greenBadPixelCount;
+
+	rc->redBlueDefectPixelCount = bpcInfoTemp.RedBlueBadPixelCount;
+}
+
+static void
+vfe_get_camif_status(struct vfe_msg_camif_status *rc, struct vfe_irq_thread_msg *in)
+{
+	struct vfe_camif_stats camifStatusTemp;
+
+	memset(rc, 0, sizeof(*rc));
+	memset(&camifStatusTemp, 0, sizeof(camifStatusTemp));
+
+	camifStatusTemp = *((struct vfe_camif_stats *)(&(in->camifStatus)));
+
+	rc->camifState = (boolean) camifStatusTemp.camifHalt;
+	rc->lineCount = camifStatusTemp.lineCount;
+	rc->pixelCount = camifStatusTemp.pixelCount;
+}
+
+static void
+vfe_get_performance_monitor_data(struct vfe_bus_performance_monitor *rc,
+		struct vfe_irq_thread_msg *in)
+{
+	memset(rc, 0, sizeof(*rc));
+
+	rc->encPathPmInfo.yWrPmStats0 = in->pmInfo.encPathPmInfo.yWrPmStats0;
+	rc->encPathPmInfo.yWrPmStats1 = in->pmInfo.encPathPmInfo.yWrPmStats1;
+	rc->encPathPmInfo.cbcrWrPmStats0 =
+	    in->pmInfo.encPathPmInfo.cbcrWrPmStats0;
+	rc->encPathPmInfo.cbcrWrPmStats1 =
+	    in->pmInfo.encPathPmInfo.cbcrWrPmStats1;
+	rc->viewPathPmInfo.yWrPmStats0 = in->pmInfo.viewPathPmInfo.yWrPmStats0;
+	rc->viewPathPmInfo.yWrPmStats1 = in->pmInfo.viewPathPmInfo.yWrPmStats1;
+	rc->viewPathPmInfo.cbcrWrPmStats0 =
+	    in->pmInfo.viewPathPmInfo.cbcrWrPmStats0;
+	rc->viewPathPmInfo.cbcrWrPmStats1 =
+	    in->pmInfo.viewPathPmInfo.cbcrWrPmStats1;
+}
+
+static void vfe_process_reg_update_irq(void)
+{
+	CDBG("vfe_process_reg_update_irq: ackPendingFlag is %d\n",
+	     ctrl->vfeStartAckPendingFlag);
+	if (ctrl->vfeStartAckPendingFlag == TRUE) {
+		vfe_proc_ops(VFE_MSG_ID_START_ACK, NULL);
+		ctrl->vfeStartAckPendingFlag = FALSE;
+	} else
+		vfe_proc_ops(VFE_MSG_ID_UPDATE_ACK, NULL);
+}
+
+static void vfe_process_reset_irq(void)
+{
+	/* unsigned long flags; */
+
+	ctrl->vstate = VFE_STATE_IDLE;
+
+	if (ctrl->vfeStopAckPending == TRUE) {
+		ctrl->vfeStopAckPending = FALSE;
+		/* disable all irqs when got stop ack from VFE */
+		vfe_program_irq_mask(VFE_DISABLE_ALL_IRQS);
+		vfe_proc_ops(VFE_MSG_ID_STOP_ACK, NULL);
+	} else {
+		vfe_set_default_reg_values();
+		vfe_proc_ops(VFE_MSG_ID_RESET_ACK, NULL);
+	}
+}
+
+static void vfe_process_pingpong_irq(struct vfe_output_path *in,
+				     uint8_t fragmentCount)
+{
+	uint16_t circularIndex;
+	uint32_t nextFragmentAddr;
+
+	/* get next fragment address from circular buffer */
+	circularIndex = (in->fragIndex) % (2 * fragmentCount);
+	nextFragmentAddr = in->addressBuffer[circularIndex];
+
+	in->fragIndex = circularIndex + 1;
+
+	/* use next fragment to program hardware ping/pong address. */
+	if (in->hwCurrentFlag == ping) {
+		writel(nextFragmentAddr, in->hwRegPingAddress);
+		in->hwCurrentFlag = pong;
+
+	} else {
+		writel(nextFragmentAddr, in->hwRegPongAddress);
+		in->hwCurrentFlag = ping;
+	}
+}
+
+static boolean vfe_send_output2_msg(struct msm_vfe_resp *rp,
+		struct vfe_message *msg, void *data)
+{
+	struct vfe_msg_output *pPayload = data;
+
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return FALSE;
+
+	memcpy(&(msg->_u.msgOutput2),
+	       (void *)pPayload, sizeof(struct vfe_msg_output));
+
+	ctrl->encPath.ackPending = TRUE;
+	rp->phy.output_id = MSM_FRAME_PREV_2;
+
+	if (!(ctrl->vfeRequestedSnapShotCount <= 3) &&
+	    (ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT))
+		ctrl->encPath.ackPending = TRUE;
+
+	vfe_addr_convert(&(rp->phy),
+			rp->type, msg,
+			&(rp->extdata), &(rp->extlen));
+	return TRUE;
+}
+
+static boolean vfe_send_output1_msg(struct msm_vfe_resp *rp,
+		struct vfe_message *msg, void *data)
+{
+	struct vfe_msg_output *pPayload = data;
+
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return FALSE;
+
+	memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output));
+
+	ctrl->viewPath.ackPending = TRUE;
+	rp->phy.output_id = MSM_FRAME_PREV_1;
+	if (!(ctrl->vfeRequestedSnapShotCount <= 3) &&
+	    (ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT))
+		ctrl->viewPath.ackPending = TRUE;
+
+	vfe_addr_convert(&(rp->phy),
+			rp->type, msg,
+			&(rp->extdata), &(rp->extlen));
+
+	return TRUE;
+}
+
+static void vfe_send_output_msg(boolean whichOutputPath,
+				uint32_t yPathAddr, uint32_t cbcrPathAddr)
+{
+	struct vfe_msg_output msgPayload;
+
+	msgPayload.yBuffer = yPathAddr;
+	msgPayload.cbcrBuffer = cbcrPathAddr;
+
+	/* asf info is common for both output1 and output2 */
+#if 0
+	msgPayload.asfInfo.asfHbiCount = ctrl->vfeAsfFrameInfo.asfHbiCount;
+	msgPayload.asfInfo.asfMaxEdge = ctrl->vfeAsfFrameInfo.asfMaxEdge;
+
+	/* demosaic info is common for both output1 and output2 */
+	msgPayload.bpcInfo.greenDefectPixelCount =
+	    ctrl->vfeBpcFrameInfo.greenDefectPixelCount;
+	msgPayload.bpcInfo.redBlueDefectPixelCount =
+	    ctrl->vfeBpcFrameInfo.redBlueDefectPixelCount;
+#endif /* if 0 */
+
+	/* frame ID is common for both paths. */
+	msgPayload.frameCounter = ctrl->vfeFrameId;
+
+	if (whichOutputPath) {
+		/* msgPayload.pmData = ctrl->vfePmData.encPathPmInfo; */
+		vfe_proc_ops(VFE_MSG_ID_OUTPUT2, &msgPayload);
+	} else {
+		/* msgPayload.pmData = ctrl->vfePmData.viewPathPmInfo; */
+		vfe_proc_ops(VFE_MSG_ID_OUTPUT1, &msgPayload);
+	}
+}
+
+static void vfe_process_frame_done_irq_multi_frag(struct vfe_output_path_combo
+						  *in)
+{
+	uint32_t yAddress, cbcrAddress;
+	uint16_t idx;
+	uint32_t *ptrY;
+	uint32_t *ptrCbcr;
+	const uint32_t *ptrSrc;
+	uint8_t i;
+
+	if (!in->ackPending) {
+
+		idx = (in->currentFrame) * (in->fragCount);
+
+		/* Send output message. */
+		yAddress = in->yPath.addressBuffer[idx];
+		cbcrAddress = in->cbcrPath.addressBuffer[idx];
+
+		/* copy next frame to current frame. */
+		ptrSrc = in->nextFrameAddrBuf;
+		ptrY = (uint32_t *)&in->yPath.addressBuffer[idx];
+		ptrCbcr = (uint32_t *)&in->cbcrPath.addressBuffer[idx];
+
+		/* Copy Y address */
+		for (i = 0; i < in->fragCount; i++)
+			*ptrY++ = *ptrSrc++;
+
+		/* Copy Cbcr address */
+		for (i = 0; i < in->fragCount; i++)
+			*ptrCbcr++ = *ptrSrc++;
+
+		vfe_send_output_msg(in->whichOutputPath, yAddress, cbcrAddress);
+
+	} else {
+		if (in->whichOutputPath == 0)
+			ctrl->vfeDroppedFrameCounts.output1Count++;
+
+		if (in->whichOutputPath == 1)
+			ctrl->vfeDroppedFrameCounts.output2Count++;
+	}
+
+	/* toggle current frame. */
+	in->currentFrame = in->currentFrame ^ 1;
+
+	if (ctrl->vfeOperationMode)
+		in->snapshotPendingCount--;
+}
+
+static void vfe_process_frame_done_irq_no_frag_io(
+		struct vfe_output_path_combo *in,
+		uint32_t *pNextAddr,
+		uint32_t *pdestRenderAddr)
+{
+	uint32_t busPingPongStatus;
+	uint32_t tempAddress;
+
+	/* 1. read hw status register. */
+	busPingPongStatus = readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+
+	CDBG("hardware status is 0x%x\n", busPingPongStatus);
+
+	/* 2. determine ping or pong */
+	/* use cbcr status */
+	busPingPongStatus = busPingPongStatus & (1 << (in->cbcrStatusBit));
+
+	/* 3. read out address and update address */
+	if (busPingPongStatus == 0) {
+		/* hw is working on ping, render pong buffer */
+		/* a. read out pong address */
+		/* read out y address. */
+		tempAddress = readl(in->yPath.hwRegPongAddress);
+
+		CDBG("pong 1 addr = 0x%x\n", tempAddress);
+		*pdestRenderAddr++ = tempAddress;
+		/* read out cbcr address. */
+		tempAddress = readl(in->cbcrPath.hwRegPongAddress);
+
+		CDBG("pong 2 addr = 0x%x\n", tempAddress);
+		*pdestRenderAddr = tempAddress;
+
+		/* b. update pong address */
+		writel(*pNextAddr++, in->yPath.hwRegPongAddress);
+		writel(*pNextAddr, in->cbcrPath.hwRegPongAddress);
+	} else {
+		/* hw is working on pong, render ping buffer */
+
+		/* a. read out ping address */
+		tempAddress = readl(in->yPath.hwRegPingAddress);
+		CDBG("ping 1 addr = 0x%x\n", tempAddress);
+		*pdestRenderAddr++ = tempAddress;
+		tempAddress = readl(in->cbcrPath.hwRegPingAddress);
+
+		CDBG("ping 2 addr = 0x%x\n", tempAddress);
+		*pdestRenderAddr = tempAddress;
+
+		/* b. update ping address */
+		writel(*pNextAddr++, in->yPath.hwRegPingAddress);
+		CDBG("NextAddress = 0x%x\n", *pNextAddr);
+		writel(*pNextAddr, in->cbcrPath.hwRegPingAddress);
+	}
+}
+
+static void vfe_process_frame_done_irq_no_frag(struct vfe_output_path_combo *in)
+{
+	uint32_t addressToRender[2];
+
+	if (!in->ackPending) {
+		vfe_process_frame_done_irq_no_frag_io(in,
+						      in->nextFrameAddrBuf,
+						      addressToRender);
+
+		/* use addressToRender to send out message. */
+		vfe_send_output_msg(in->whichOutputPath,
+				    addressToRender[0], addressToRender[1]);
+
+	} else {
+		/* ackPending is still there, accumulate dropped frame count.
+		 * These count can be read through ioctrl command. */
+		CDBG("waiting frame ACK\n");
+
+		if (in->whichOutputPath == 0)
+			ctrl->vfeDroppedFrameCounts.output1Count++;
+
+		if (in->whichOutputPath == 1)
+			ctrl->vfeDroppedFrameCounts.output2Count++;
+	}
+
+	/* in case of multishot when upper layer did not ack, there will still
+	 * be a snapshot done msg sent out, even though the number of frames
+	 * sent out may be less than the desired number of frames.  snapshot
+	 * done msg would be helpful to indicate that vfe pipeline has stop,
+	 * and in good known state.
+	 */
+	if (ctrl->vfeOperationMode)
+		in->snapshotPendingCount--;
+}
+
+static void vfe_process_output_path_irq(struct vfe_interrupt_status *irqstatus)
+{
+	/* unsigned long flags; */
+
+	/* process the view path interrupts */
+	if (irqstatus->anyOutput1PathIrqs) {
+		if (ctrl->viewPath.multiFrag) {
+
+			if (irqstatus->viewCbcrPingpongIrq)
+				vfe_process_pingpong_irq(&
+							 (ctrl->viewPath.
+							  cbcrPath),
+							 ctrl->viewPath.
+							 fragCount);
+
+			if (irqstatus->viewYPingpongIrq)
+				vfe_process_pingpong_irq(&
+							 (ctrl->viewPath.yPath),
+							 ctrl->viewPath.
+							 fragCount);
+
+			if (irqstatus->viewIrq)
+				vfe_process_frame_done_irq_multi_frag(&ctrl->
+								      viewPath);
+
+		} else {
+			/* typical case for no fragment,
+			   only frame done irq is enabled. */
+			if (irqstatus->viewIrq)
+				vfe_process_frame_done_irq_no_frag(&ctrl->
+								   viewPath);
+		}
+	}
+
+	/* process the encoder path interrupts */
+	if (irqstatus->anyOutput2PathIrqs) {
+		if (ctrl->encPath.multiFrag) {
+			if (irqstatus->encCbcrPingpongIrq)
+				vfe_process_pingpong_irq(&
+							 (ctrl->encPath.
+							  cbcrPath),
+							 ctrl->encPath.
+							 fragCount);
+
+			if (irqstatus->encYPingpongIrq)
+				vfe_process_pingpong_irq(&(ctrl->encPath.yPath),
+							 ctrl->encPath.
+							 fragCount);
+
+			if (irqstatus->encIrq)
+				vfe_process_frame_done_irq_multi_frag(&ctrl->
+								      encPath);
+
+		} else {
+			if (irqstatus->encIrq)
+				vfe_process_frame_done_irq_no_frag(&ctrl->
+								   encPath);
+		}
+	}
+
+	if (ctrl->vfeOperationMode) {
+		if ((ctrl->encPath.snapshotPendingCount == 0) &&
+		    (ctrl->viewPath.snapshotPendingCount == 0)) {
+
+			ctrl->vstate = VFE_STATE_IDLE;
+
+			vfe_proc_ops(VFE_MSG_ID_SNAPSHOT_DONE, NULL);
+			vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP);
+			vfe_pm_stop();
+		}
+	}
+}
+
+static void __vfe_do_tasklet(struct isr_queue_cmd *qcmd)
+{
+	if (qcmd->vfeInterruptStatus.regUpdateIrq) {
+		CDBG("irq regUpdateIrq\n");
+		vfe_process_reg_update_irq();
+	}
+
+	if (qcmd->vfeInterruptStatus.resetAckIrq) {
+		CDBG("%s: process resetAckIrq\n", __func__);
+		vfe_process_reset_irq();
+	}
+
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return;
+
+	if (qcmd->vfeInterruptStatus.camifEpoch1Irq) {
+		vfe_process_camif_epoch1_irq();
+	}
+
+#if 0
+	if (qcmd->vfeInterruptStatus.camifEpoch2Irq)
+		vfe_proc_ops(VFE_MSG_ID_EPOCH2);
+#endif
+
+	/* next, check output path related interrupts. */
+	if (qcmd->vfeInterruptStatus.anyOutputPathIrqs) {
+		CDBG("irq: anyOutputPathIrqs\n");
+		vfe_process_output_path_irq(&qcmd->vfeInterruptStatus);
+	}
+
+	if (qcmd->vfeInterruptStatus.afPingpongIrq)
+		vfe_process_stats_af_irq();
+
+	if (qcmd->vfeInterruptStatus.awbPingpongIrq)
+		vfe_process_stats_awb_irq();
+
+	/* any error irqs */
+	if (qcmd->vfeInterruptStatus.anyErrorIrqs)
+		vfe_process_error_irq(qcmd);
+
+#if 0
+	if (qcmd->vfeInterruptStatus.anySyncTimerIrqs)
+		vfe_process_sync_timer_irq();
+
+	if (qcmd->vfeInterruptStatus.anyAsyncTimerIrqs)
+		vfe_process_async_timer_irq();
+#endif
+
+	if (qcmd->vfeInterruptStatus.camifSofIrq) {
+		CDBG("irq: camifSofIrq\n");
+		vfe_process_camif_sof_irq();
+	}
+}
+
+static struct isr_queue_cmd *get_irq_cmd_nosync(void)
+{
+	int old_get = ctrl->irq_get++;
+	ctrl->irq_get = ctrl->irq_get % ARRAY_SIZE(ctrl->irqs);
+	if (ctrl->irq_get == ctrl->irq_put) {
+		pr_err("%s: out of irq command packets\n", __func__);
+		ctrl->irq_get = old_get;
+		return NULL;
+	}
+
+	return ctrl->irqs + old_get;
+}
+
+static struct isr_queue_cmd *next_irq_cmd(void)
+{
+	unsigned long flags;
+	struct isr_queue_cmd *cmd;
+	spin_lock_irqsave(&ctrl->irqs_lock, flags);
+	if (ctrl->irq_get == ctrl->irq_put) {
+		spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+		return NULL; /* already empty */
+	}
+	cmd = ctrl->irqs + ctrl->irq_put;
+	spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+	return cmd;
+}
+
+static void put_irq_cmd(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&ctrl->irqs_lock, flags);
+	if (ctrl->irq_get == ctrl->irq_put) {
+		spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+		return; /* already empty */
+	}
+	ctrl->irq_put++;
+	ctrl->irq_put %= ARRAY_SIZE(ctrl->irqs);
+	spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+}
+
+static void vfe_do_tasklet(unsigned long data)
+{
+	int cnt = 0;
+	struct isr_queue_cmd *qcmd = NULL;
+
+	CDBG("%s\n", __func__);
+
+	while ((qcmd = next_irq_cmd())) {
+		__vfe_do_tasklet(qcmd);
+		put_irq_cmd();
+		cnt++;
+	}
+
+	if (cnt > 1)
+		pr_info("%s: serviced %d vfe interrupts\n", __func__, cnt);
+}
+
+DECLARE_TASKLET(vfe_tasklet, vfe_do_tasklet, 0);
+
+static irqreturn_t vfe_parse_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	uint32_t irqStatusLocal;
+	struct vfe_irq_thread_msg irq;
+	struct isr_queue_cmd *qcmd;
+
+	CDBG("vfe_parse_irq\n");
+
+	vfe_read_irq_status(&irq);
+
+	if (irq.vfeIrqStatus == 0) {
+		CDBG("vfe_parse_irq: irq.vfeIrqStatus is 0\n");
+		return IRQ_HANDLED;
+	}
+
+	if (ctrl->vfeStopAckPending)
+		irqStatusLocal = (VFE_IMASK_WHILE_STOPPING & irq.vfeIrqStatus);
+	else
+		irqStatusLocal =
+		    ((ctrl->vfeImaskPacked | VFE_IMASK_ERROR_ONLY) &
+		     irq.vfeIrqStatus);
+
+	spin_lock_irqsave(&ctrl->irqs_lock, flags);
+	qcmd = get_irq_cmd_nosync();
+	if (!qcmd) {
+		spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+		goto done;
+	}
+	/* parse the interrupt status to local data structures. */
+	vfe_parse_interrupt_status(&qcmd->vfeInterruptStatus, irqStatusLocal);
+	vfe_get_asf_frame_info(&qcmd->vfeAsfFrameInfo, &irq);
+	vfe_get_demosaic_frame_info(&qcmd->vfeBpcFrameInfo, &irq);
+	vfe_get_camif_status(&qcmd->vfeCamifStatusLocal, &irq);
+	vfe_get_performance_monitor_data(&qcmd->vfePmData, &irq);
+	spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+	tasklet_schedule(&vfe_tasklet);
+
+done:
+	/* clear the pending interrupt of the same kind. */
+	writel(irq.vfeIrqStatus, ctrl->vfebase + VFE_IRQ_CLEAR);
+	return IRQ_HANDLED;
+}
+
+int vfe_cmd_init(struct msm_vfe_callback *presp,
+		 struct platform_device *pdev, void *sdata)
+{
+	struct resource *vfemem, *vfeirq, *vfeio;
+	int rc;
+	struct msm_camera_sensor_info *s_info;
+	s_info = pdev->dev.platform_data;
+
+	pdev->resource = s_info->resource;
+	pdev->num_resources = s_info->num_resources;
+
+	vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!vfemem) {
+		pr_err("%s: no mem resource\n", __func__);
+		return -ENODEV;
+	}
+
+	vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!vfeirq) {
+		pr_err("%s: no irq resource\n", __func__);
+		return -ENODEV;
+	}
+
+	vfeio = request_mem_region(vfemem->start,
+				   resource_size(vfemem), pdev->name);
+	if (!vfeio) {
+		pr_err("%s: VFE region already claimed\n", __func__);
+		return -EBUSY;
+	}
+
+	ctrl = kzalloc(sizeof(struct msm_vfe8x_ctrl), GFP_KERNEL);
+	if (!ctrl) {
+		pr_err("%s: out of memory\n", __func__);
+		rc = -ENOMEM;
+		goto cmd_init_failed1;
+	}
+
+	spin_lock_init(&ctrl->irqs_lock);
+
+	ctrl->vfeirq = vfeirq->start;
+
+	ctrl->vfebase =
+	    ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	if (!ctrl->vfebase) {
+		pr_err("%s: ioremap failed\n", __func__);
+		rc = -ENOMEM;
+		goto cmd_init_failed2;
+	}
+
+	rc = request_irq(ctrl->vfeirq, vfe_parse_irq,
+			 IRQF_TRIGGER_RISING, "vfe", 0);
+	if (rc < 0) {
+		pr_err("%s: request_irq(%d) failed\n", __func__, ctrl->vfeirq);
+		goto cmd_init_failed2;
+	}
+
+	if (presp && presp->vfe_resp)
+		ctrl->resp = presp;
+	else {
+		pr_err("%s: no vfe_resp function\n", __func__);
+		rc = -EIO;
+		goto cmd_init_failed3;
+	}
+
+	ctrl->syncdata = sdata;
+	return 0;
+
+cmd_init_failed3:
+	disable_irq(ctrl->vfeirq);
+	free_irq(ctrl->vfeirq, 0);
+	iounmap(ctrl->vfebase);
+cmd_init_failed2:
+	kfree(ctrl);
+cmd_init_failed1:
+	release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	return rc;
+}
+
+void vfe_cmd_release(struct platform_device *dev)
+{
+	struct resource *mem;
+
+	disable_irq(ctrl->vfeirq);
+	free_irq(ctrl->vfeirq, 0);
+
+	iounmap(ctrl->vfebase);
+	mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+	kfree(ctrl);
+	ctrl = 0;
+}
+
+void vfe_stats_af_stop(void)
+{
+	ctrl->vfeStatsCmdLocal.autoFocusEnable = FALSE;
+	ctrl->vfeImaskLocal.afPingpongIrq = FALSE;
+}
+
+void vfe_stop(void)
+{
+	int spin_cnt = 0;
+	uint32_t vfeAxiStauts;
+
+	/* for reset hw modules, and send msg when reset_irq comes. */
+	ctrl->vfeStopAckPending = TRUE;
+
+	ctrl->vfeStatsPingPongReloadFlag = FALSE;
+	vfe_pm_stop();
+
+	/* disable all interrupts.  */
+	vfe_program_irq_mask(VFE_DISABLE_ALL_IRQS);
+
+	/* in either continuous or snapshot mode, stop command can be issued
+	 * at any time.
+	 */
+	vfe_camif_stop_immediately();
+	vfe_program_axi_cmd(AXI_HALT);
+	vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP);
+
+	do {
+		vfeAxiStauts = vfe_read_axi_status();
+		spin_cnt++;
+	} while (!(vfeAxiStauts & AXI_STATUS_BUSY_MASK));
+	if (spin_cnt > 1)
+		pr_warning("%s: spin_cnt %d\n", __func__, spin_cnt);
+
+	vfe_program_axi_cmd(AXI_HALT_CLEAR);
+
+	/* clear all pending interrupts */
+	writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+	/* enable reset_ack and async timer interrupt only while stopping
+	 * the pipeline.
+	 */
+	vfe_program_irq_mask(VFE_IMASK_WHILE_STOPPING);
+
+	vfe_program_global_reset_cmd(VFE_RESET_UPON_STOP_CMD);
+}
+
+void vfe_update(void)
+{
+	ctrl->vfeModuleEnableLocal.statsEnable =
+	    ctrl->vfeStatsCmdLocal.autoFocusEnable |
+	    ctrl->vfeStatsCmdLocal.axwEnable;
+
+	vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal);
+
+	vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal);
+
+	ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+	vfe_program_irq_mask(ctrl->vfeImaskPacked);
+
+	if ((ctrl->vfeModuleEnableLocal.statsEnable == TRUE) &&
+	    (ctrl->vfeStatsPingPongReloadFlag == FALSE)) {
+		ctrl->vfeStatsPingPongReloadFlag = TRUE;
+
+		ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE;
+		vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal);
+	}
+
+	vfe_program_reg_update_cmd(VFE_REG_UPDATE_TRIGGER);
+}
+
+int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *in)
+{
+	int rc = 0;
+
+	ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable;
+
+	switch (in->channelSelect) {
+	case RGB_GAMMA_CH0_SELECTED:
+		ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+		vfe_write_gamma_table(0,
+				      ctrl->vfeGammaLutSel.ch0BankSelect,
+				      in->table);
+		break;
+
+	case RGB_GAMMA_CH1_SELECTED:
+		ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+		vfe_write_gamma_table(1,
+				      ctrl->vfeGammaLutSel.ch1BankSelect,
+				      in->table);
+		break;
+
+	case RGB_GAMMA_CH2_SELECTED:
+		ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+		vfe_write_gamma_table(2,
+				      ctrl->vfeGammaLutSel.ch2BankSelect,
+				      in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH1_SELECTED:
+		ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+		ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+		vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+				      in->table);
+		vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+				      in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH2_SELECTED:
+		ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+		ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+		vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+				      in->table);
+		vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+				      in->table);
+		break;
+
+	case RGB_GAMMA_CH1_CH2_SELECTED:
+		ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+		ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+		vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+				      in->table);
+		vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+				      in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH1_CH2_SELECTED:
+		ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+		ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+		ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+		vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+				      in->table);
+		vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+				      in->table);
+		vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+				      in->table);
+		break;
+
+	default:
+		pr_err("%s: invalid gamma channel %d\n", __func__, in->channelSelect);
+		return -EINVAL;
+	}			/* switch */
+
+	/* update the gammaLutSel register. */
+	vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel);
+
+	return rc;
+}
+
+int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *in)
+{
+	int rc = 0;
+
+	ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable;
+
+	switch (in->channelSelect) {
+	case RGB_GAMMA_CH0_SELECTED:
+		vfe_write_gamma_table(0, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH1_SELECTED:
+		vfe_write_gamma_table(1, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH2_SELECTED:
+		vfe_write_gamma_table(2, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH1_SELECTED:
+		vfe_write_gamma_table(0, 0, in->table);
+		vfe_write_gamma_table(1, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH2_SELECTED:
+		vfe_write_gamma_table(0, 0, in->table);
+		vfe_write_gamma_table(2, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH1_CH2_SELECTED:
+		vfe_write_gamma_table(1, 0, in->table);
+		vfe_write_gamma_table(2, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH1_CH2_SELECTED:
+		vfe_write_gamma_table(0, 0, in->table);
+		vfe_write_gamma_table(1, 0, in->table);
+		vfe_write_gamma_table(2, 0, in->table);
+		break;
+
+	default:
+		pr_err("%s: invalid gamma channel %d\n", __func__, in->channelSelect);
+		rc = -EINVAL;
+		break;
+	}			/* switch */
+
+	return rc;
+}
+
+void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *in)
+{
+	ctrl->afStatsControl.nextFrameAddrBuf = in->nextAFOutputBufferAddr;
+	ctrl->afStatsControl.ackPending = FALSE;
+}
+
+void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *in)
+{
+	ctrl->awbStatsControl.nextFrameAddrBuf = in->nextWbExpOutputBufferAddr;
+	ctrl->awbStatsControl.ackPending = FALSE;
+}
+
+void vfe_output2_ack(struct vfe_cmd_output_ack *in)
+{
+	const uint32_t *psrc;
+	uint32_t *pdest;
+	uint8_t i;
+
+	pdest = ctrl->encPath.nextFrameAddrBuf;
+
+	CDBG("output2_ack: ack addr = 0x%x\n", in->ybufaddr[0]);
+
+	psrc = in->ybufaddr;
+	for (i = 0; i < ctrl->encPath.fragCount; i++)
+		*pdest++ = *psrc++;
+
+	psrc = in->chromabufaddr;
+	for (i = 0; i < ctrl->encPath.fragCount; i++)
+		*pdest++ = *psrc++;
+
+	ctrl->encPath.ackPending = FALSE;
+}
+
+void vfe_output1_ack(struct vfe_cmd_output_ack *in)
+{
+	const uint32_t *psrc;
+	uint32_t *pdest;
+	uint8_t i;
+
+	pdest = ctrl->viewPath.nextFrameAddrBuf;
+
+	psrc = in->ybufaddr;
+	for (i = 0; i < ctrl->viewPath.fragCount; i++)
+		*pdest++ = *psrc++;
+
+	psrc = in->chromabufaddr;
+	for (i = 0; i < ctrl->viewPath.fragCount; i++)
+		*pdest++ = *psrc++;
+
+	ctrl->viewPath.ackPending = FALSE;
+}
+
+void vfe_start(struct vfe_cmd_start *in)
+{
+	uint32_t pmstatus = 0;
+	boolean rawmode;
+	uint32_t demperiod = 0;
+	uint32_t demeven = 0;
+	uint32_t demodd = 0;
+
+	/* derived from other commands.  (camif config, axi output config,
+	 * etc)
+	 */
+	struct vfe_cfg hwcfg;
+	struct vfe_upsample_cfg chromupcfg;
+
+	CDBG("vfe_start operationMode = %d\n", in->operationMode);
+
+	memset(&hwcfg, 0, sizeof(hwcfg));
+	memset(&chromupcfg, 0, sizeof(chromupcfg));
+
+	switch (in->pixel) {
+	case VFE_BAYER_RGRGRG:
+		demperiod = 1;
+		demeven = 0xC9;
+		demodd = 0xAC;
+		break;
+
+	case VFE_BAYER_GRGRGR:
+		demperiod = 1;
+		demeven = 0x9C;
+		demodd = 0xCA;
+		break;
+
+	case VFE_BAYER_BGBGBG:
+		demperiod = 1;
+		demeven = 0xCA;
+		demodd = 0x9C;
+		break;
+
+	case VFE_BAYER_GBGBGB:
+		demperiod = 1;
+		demeven = 0xAC;
+		demodd = 0xC9;
+		break;
+
+	case VFE_YUV_YCbYCr:
+		demperiod = 3;
+		demeven = 0x9CAC;
+		demodd = 0x9CAC;
+		break;
+
+	case VFE_YUV_YCrYCb:
+		demperiod = 3;
+		demeven = 0xAC9C;
+		demodd = 0xAC9C;
+		break;
+
+	case VFE_YUV_CbYCrY:
+		demperiod = 3;
+		demeven = 0xC9CA;
+		demodd = 0xC9CA;
+		break;
+
+	case VFE_YUV_CrYCbY:
+		demperiod = 3;
+		demeven = 0xCAC9;
+		demodd = 0xCAC9;
+		break;
+
+	default:
+		return;
+	}
+
+	vfe_config_demux(demperiod, demeven, demodd);
+
+	vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel);
+
+	/* save variables to local. */
+	ctrl->vfeOperationMode = in->operationMode;
+	if (ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) {
+		/* in snapshot mode, initialize snapshot count */
+		ctrl->vfeSnapShotCount = in->snapshotCount;
+
+		/* save the requested count, this is temporarily done, to
+		   help with HJR / multishot. */
+		ctrl->vfeRequestedSnapShotCount = ctrl->vfeSnapShotCount;
+
+		CDBG("requested snapshot count = %d\n", ctrl->vfeSnapShotCount);
+
+		/* Assumption is to have the same pattern and period for both
+		   paths, if both paths are used. */
+		if (ctrl->viewPath.pathEnabled) {
+			ctrl->viewPath.snapshotPendingCount = in->snapshotCount;
+
+			ctrl->vfeFrameSkipPattern =
+			    ctrl->vfeFrameSkip.output1Pattern;
+			ctrl->vfeFrameSkipPeriod =
+			    ctrl->vfeFrameSkip.output1Period;
+		}
+
+		if (ctrl->encPath.pathEnabled) {
+			ctrl->encPath.snapshotPendingCount = in->snapshotCount;
+
+			ctrl->vfeFrameSkipPattern =
+			    ctrl->vfeFrameSkip.output2Pattern;
+			ctrl->vfeFrameSkipPeriod =
+			    ctrl->vfeFrameSkip.output2Period;
+		}
+	}
+
+	/* enable color conversion for bayer sensor
+	   if stats enabled, need to do color conversion. */
+	if (in->pixel <= VFE_BAYER_GBGBGB)
+		ctrl->vfeStatsCmdLocal.colorConversionEnable = TRUE;
+
+	vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal);
+
+	if (in->pixel >= VFE_YUV_YCbYCr)
+		ctrl->vfeModuleEnableLocal.chromaUpsampleEnable = TRUE;
+
+	ctrl->vfeModuleEnableLocal.demuxEnable = TRUE;
+
+	/* if any stats module is enabled, the main bit is enabled. */
+	ctrl->vfeModuleEnableLocal.statsEnable =
+	    ctrl->vfeStatsCmdLocal.autoFocusEnable |
+	    ctrl->vfeStatsCmdLocal.axwEnable;
+
+	vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal);
+
+	/* in case of offline processing, do not need to config camif. Having
+	 * bus output enabled in camif_config register might confuse the
+	 * hardware?
+	 */
+	if (in->inputSource != VFE_START_INPUT_SOURCE_AXI) {
+		vfe_reg_camif_config(&ctrl->vfeCamifConfigLocal);
+	} else {
+		/* offline processing, enable axi read */
+		ctrl->vfeBusConfigLocal.stripeRdPathEn = TRUE;
+		ctrl->vfeBusCmdLocal.stripeReload = TRUE;
+		ctrl->vfeBusConfigLocal.rawPixelDataSize =
+		    ctrl->axiInputDataSize;
+	}
+
+	vfe_reg_bus_cfg(&ctrl->vfeBusConfigLocal);
+
+	/* directly from start command */
+	hwcfg.pixelPattern = in->pixel;
+	hwcfg.inputSource = in->inputSource;
+	writel(*(uint32_t *)&hwcfg, ctrl->vfebase + VFE_CFG);
+
+	/* regardless module enabled or not, it does not hurt
+	 * to program the cositing mode. */
+	chromupcfg.chromaCositingForYCbCrInputs = in->yuvInputCositingMode;
+
+	writel(*(uint32_t *)&chromupcfg,
+	       ctrl->vfebase + VFE_CHROMA_UPSAMPLE_CFG);
+
+	/* MISR to monitor the axi read. */
+	writel(0xd8, ctrl->vfebase + VFE_BUS_MISR_MAST_CFG_0);
+
+	/* clear all pending interrupts. */
+	writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+	/*  define how composite interrupt work.  */
+	ctrl->vfeImaskCompositePacked =
+	    vfe_irq_composite_pack(ctrl->vfeIrqCompositeMaskLocal);
+
+	vfe_program_irq_composite_mask(ctrl->vfeImaskCompositePacked);
+
+	/*  enable all necessary interrupts.      */
+	ctrl->vfeImaskLocal.camifSofIrq = TRUE;
+	ctrl->vfeImaskLocal.regUpdateIrq = TRUE;
+	ctrl->vfeImaskLocal.resetAckIrq = TRUE;
+
+	ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+	vfe_program_irq_mask(ctrl->vfeImaskPacked);
+
+	/* enable bus performance monitor */
+	vfe_8k_pm_start(&ctrl->vfeBusPmConfigLocal);
+
+	/* trigger vfe reg update */
+	ctrl->vfeStartAckPendingFlag = TRUE;
+
+	/* write bus command to trigger reload of ping pong buffer. */
+	ctrl->vfeBusCmdLocal.busPingpongReload = TRUE;
+
+	if (ctrl->vfeModuleEnableLocal.statsEnable == TRUE) {
+		ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE;
+		ctrl->vfeStatsPingPongReloadFlag = TRUE;
+	}
+
+	writel(VFE_REG_UPDATE_TRIGGER, ctrl->vfebase + VFE_REG_UPDATE_CMD);
+
+	/* program later than the reg update. */
+	vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal);
+
+	if ((in->inputSource ==
+	     VFE_START_INPUT_SOURCE_CAMIF) ||
+	    (in->inputSource == VFE_START_INPUT_SOURCE_TESTGEN))
+		writel(CAMIF_COMMAND_START, ctrl->vfebase + CAMIF_COMMAND);
+
+	/* start test gen if it is enabled */
+	if (ctrl->vfeTestGenStartFlag == TRUE) {
+		ctrl->vfeTestGenStartFlag = FALSE;
+		vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_GO);
+	}
+
+	CDBG("ctrl->axiOutputMode = %d\n", ctrl->axiOutputMode);
+	if (ctrl->axiOutputMode == VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2) {
+		/* raw dump mode */
+		rawmode = TRUE;
+
+		while (rawmode) {
+			pmstatus =
+			    readl(ctrl->vfebase +
+				  VFE_BUS_ENC_CBCR_WR_PM_STATS_1);
+
+			if ((pmstatus & VFE_PM_BUF_MAX_CNT_MASK) != 0)
+				rawmode = FALSE;
+		}
+
+		vfe_proc_ops(VFE_MSG_ID_START_ACK, NULL);
+		ctrl->vfeStartAckPendingFlag = FALSE;
+	}
+
+	ctrl->vstate = VFE_STATE_ACTIVE;
+}
+
+void vfe_la_update(struct vfe_cmd_la_config *in)
+{
+	int16_t *pTable;
+	enum VFE_DMI_RAM_SEL dmiRamSel;
+	int i;
+
+	pTable = in->table;
+	ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable;
+
+	/* toggle the bank to be used. */
+	ctrl->vfeLaBankSel ^= 1;
+
+	if (ctrl->vfeLaBankSel == 0)
+		dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0;
+	else
+		dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1;
+
+	/* configure the DMI_CFG to select right sram */
+	vfe_program_dmi_cfg(dmiRamSel);
+
+	for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) {
+		writel((uint32_t) (*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+		pTable++;
+	}
+
+	/* After DMI transfer, to make it safe, need to set
+	 * the DMI_CFG to unselect any SRAM */
+	writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+	writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG);
+}
+
+void vfe_la_config(struct vfe_cmd_la_config *in)
+{
+	uint16_t i;
+	int16_t *pTable;
+	enum VFE_DMI_RAM_SEL dmiRamSel;
+
+	pTable = in->table;
+	ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable;
+
+	if (ctrl->vfeLaBankSel == 0)
+		dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0;
+	else
+		dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1;
+
+	/* configure the DMI_CFG to select right sram */
+	vfe_program_dmi_cfg(dmiRamSel);
+
+	for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) {
+		writel((uint32_t) (*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+		pTable++;
+	}
+
+	/* After DMI transfer, to make it safe, need to set the
+	 * DMI_CFG to unselect any SRAM */
+	writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+
+	/* can only be bank 0 or bank 1 for now. */
+	writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG);
+	CDBG("VFE Luma adaptation bank selection is 0x%x\n",
+	     *(uint32_t *)&ctrl->vfeLaBankSel);
+}
+
+void vfe_test_gen_start(struct vfe_cmd_test_gen_start *in)
+{
+	struct VFE_TestGen_ConfigCmdType cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.numFrame = in->numFrame;
+	cmd.pixelDataSelect = in->pixelDataSelect;
+	cmd.systematicDataSelect = in->systematicDataSelect;
+	cmd.pixelDataSize = (uint32_t) in->pixelDataSize;
+	cmd.hsyncEdge = (uint32_t) in->hsyncEdge;
+	cmd.vsyncEdge = (uint32_t) in->vsyncEdge;
+	cmd.imageWidth = in->imageWidth;
+	cmd.imageHeight = in->imageHeight;
+	cmd.sofOffset = in->startOfFrameOffset;
+	cmd.eofNOffset = in->endOfFrameNOffset;
+	cmd.solOffset = in->startOfLineOffset;
+	cmd.eolNOffset = in->endOfLineNOffset;
+	cmd.hBlankInterval = in->hbi;
+	cmd.vBlankInterval = in->vbl;
+	cmd.vBlankIntervalEnable = in->vblEnable;
+	cmd.sofDummy = in->startOfFrameDummyLine;
+	cmd.eofDummy = in->endOfFrameDummyLine;
+	cmd.unicolorBarSelect = in->unicolorBarSelect;
+	cmd.unicolorBarEnable = in->unicolorBarEnable;
+	cmd.splitEnable = in->colorBarsSplitEnable;
+	cmd.pixelPattern = (uint32_t) in->colorBarsPixelPattern;
+	cmd.rotatePeriod = in->colorBarsRotatePeriod;
+	cmd.randomSeed = in->testGenRandomSeed;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_HW_TESTGEN_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *in)
+{
+	struct VFE_FRAME_SKIP_UpdateCmdType cmd;
+
+	cmd.yPattern = in->output1Pattern;
+	cmd.cbcrPattern = in->output1Pattern;
+	vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	cmd.yPattern = in->output2Pattern;
+	cmd.cbcrPattern = in->output2Pattern;
+	vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *in)
+{
+	struct vfe_frame_skip_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeFrameSkip = *in;
+
+	cmd.output2YPeriod = in->output2Period;
+	cmd.output2CbCrPeriod = in->output2Period;
+	cmd.output2YPattern = in->output2Pattern;
+	cmd.output2CbCrPattern = in->output2Pattern;
+	cmd.output1YPeriod = in->output1Period;
+	cmd.output1CbCrPeriod = in->output1Period;
+	cmd.output1YPattern = in->output1Pattern;
+	cmd.output1CbCrPattern = in->output1Pattern;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *in)
+{
+	struct vfe_output_clamp_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.yChanMax = in->maxCh0;
+	cmd.cbChanMax = in->maxCh1;
+	cmd.crChanMax = in->maxCh2;
+
+	cmd.yChanMin = in->minCh0;
+	cmd.cbChanMin = in->minCh1;
+	cmd.crChanMin = in->minCh2;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_CLAMP_MAX_CFG, (uint32_t *)&cmd,
+		    sizeof(cmd));
+}
+
+void vfe_camif_frame_update(struct vfe_cmds_camif_frame *in)
+{
+	struct vfe_camifframe_update cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.pixelsPerLine = in->pixelsPerLine;
+	cmd.linesPerFrame = in->linesPerFrame;
+
+	vfe_prog_hw(ctrl->vfebase + CAMIF_FRAME_CONFIG, (uint32_t *)&cmd,
+		    sizeof(cmd));
+}
+
+void vfe_color_correction_config(struct vfe_cmd_color_correction_config *in)
+{
+	struct vfe_color_correction_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	ctrl->vfeModuleEnableLocal.colorCorrectionEnable = in->enable;
+
+	cmd.c0 = in->C0;
+	cmd.c1 = in->C1;
+	cmd.c2 = in->C2;
+	cmd.c3 = in->C3;
+	cmd.c4 = in->C4;
+	cmd.c5 = in->C5;
+	cmd.c6 = in->C6;
+	cmd.c7 = in->C7;
+	cmd.c8 = in->C8;
+
+	cmd.k0 = in->K0;
+	cmd.k1 = in->K1;
+	cmd.k2 = in->K2;
+
+	cmd.coefQFactor = in->coefQFactor;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CORRECT_COEFF_0,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *in)
+{
+	struct vfe_demosaic_cfg cmd;
+	struct vfe_demosaic_abf_cfg cmdabf;
+	uint32_t temp;
+
+	memset(&cmd, 0, sizeof(cmd));
+	temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG);
+
+	cmd = *((struct vfe_demosaic_cfg *)(&temp));
+	cmd.abfEnable = in->abfUpdate.enable;
+	cmd.forceAbfOn = in->abfUpdate.forceOn;
+	cmd.abfShift = in->abfUpdate.shift;
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	cmdabf.lpThreshold = in->abfUpdate.lpThreshold;
+	cmdabf.ratio = in->abfUpdate.ratio;
+	cmdabf.minValue = in->abfUpdate.min;
+	cmdabf.maxValue = in->abfUpdate.max;
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0,
+		    (uint32_t *)&cmdabf, sizeof(cmdabf));
+}
+
+void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *in)
+{
+	struct vfe_demosaic_cfg cmd;
+	struct vfe_demosaic_bpc_cfg cmdbpc;
+	uint32_t temp;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG);
+
+	cmd = *((struct vfe_demosaic_cfg *)(&temp));
+	cmd.badPixelCorrEnable = in->bpcUpdate.enable;
+	cmd.fminThreshold = in->bpcUpdate.fminThreshold;
+	cmd.fmaxThreshold = in->bpcUpdate.fmaxThreshold;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	cmdbpc.blueDiffThreshold = in->bpcUpdate.blueDiffThreshold;
+	cmdbpc.redDiffThreshold = in->bpcUpdate.redDiffThreshold;
+	cmdbpc.greenDiffThreshold = in->bpcUpdate.greenDiffThreshold;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0,
+		    (uint32_t *)&cmdbpc, sizeof(cmdbpc));
+}
+
+void vfe_demosaic_config(struct vfe_cmd_demosaic_config *in)
+{
+	struct vfe_demosaic_cfg cmd;
+	struct vfe_demosaic_bpc_cfg cmd_bpc;
+	struct vfe_demosaic_abf_cfg cmd_abf;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd_bpc, 0, sizeof(cmd_bpc));
+	memset(&cmd_abf, 0, sizeof(cmd_abf));
+
+	ctrl->vfeModuleEnableLocal.demosaicEnable = in->enable;
+
+	cmd.abfEnable = in->abfConfig.enable;
+	cmd.badPixelCorrEnable = in->bpcConfig.enable;
+	cmd.forceAbfOn = in->abfConfig.forceOn;
+	cmd.abfShift = in->abfConfig.shift;
+	cmd.fminThreshold = in->bpcConfig.fminThreshold;
+	cmd.fmaxThreshold = in->bpcConfig.fmaxThreshold;
+	cmd.slopeShift = in->slopeShift;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	cmd_abf.lpThreshold = in->abfConfig.lpThreshold;
+	cmd_abf.ratio = in->abfConfig.ratio;
+	cmd_abf.minValue = in->abfConfig.min;
+	cmd_abf.maxValue = in->abfConfig.max;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0,
+		    (uint32_t *)&cmd_abf, sizeof(cmd_abf));
+
+	cmd_bpc.blueDiffThreshold = in->bpcConfig.blueDiffThreshold;
+	cmd_bpc.redDiffThreshold = in->bpcConfig.redDiffThreshold;
+	cmd_bpc.greenDiffThreshold = in->bpcConfig.greenDiffThreshold;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0,
+		    (uint32_t *)&cmd_bpc, sizeof(cmd_bpc));
+}
+
+void vfe_demux_channel_gain_update(struct vfe_cmd_demux_channel_gain_config *in)
+{
+	struct vfe_demux_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.ch0EvenGain = in->ch0EvenGain;
+	cmd.ch0OddGain = in->ch0OddGain;
+	cmd.ch1Gain = in->ch1Gain;
+	cmd.ch2Gain = in->ch2Gain;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_demux_channel_gain_config(struct vfe_cmd_demux_channel_gain_config *in)
+{
+	struct vfe_demux_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.ch0EvenGain = in->ch0EvenGain;
+	cmd.ch0OddGain = in->ch0OddGain;
+	cmd.ch1Gain = in->ch1Gain;
+	cmd.ch2Gain = in->ch2Gain;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_black_level_update(struct vfe_cmd_black_level_config *in)
+{
+	struct vfe_blacklevel_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable;
+
+	cmd.evenEvenAdjustment = in->evenEvenAdjustment;
+	cmd.evenOddAdjustment = in->evenOddAdjustment;
+	cmd.oddEvenAdjustment = in->oddEvenAdjustment;
+	cmd.oddOddAdjustment = in->oddOddAdjustment;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_black_level_config(struct vfe_cmd_black_level_config *in)
+{
+	struct vfe_blacklevel_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable;
+
+	cmd.evenEvenAdjustment = in->evenEvenAdjustment;
+	cmd.evenOddAdjustment = in->evenOddAdjustment;
+	cmd.oddEvenAdjustment = in->oddEvenAdjustment;
+	cmd.oddOddAdjustment = in->oddOddAdjustment;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_asf_update(struct vfe_cmd_asf_update *in)
+{
+	struct vfe_asf_update cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.asfEnable = in->enable;
+
+	cmd.smoothEnable = in->smoothFilterEnabled;
+	cmd.sharpMode = in->sharpMode;
+	cmd.smoothCoeff0 = in->smoothCoefCenter;
+	cmd.smoothCoeff1 = in->smoothCoefSurr;
+	cmd.cropEnable = in->cropEnable;
+	cmd.sharpThresholdE1 = in->sharpThreshE1;
+	cmd.sharpDegreeK1 = in->sharpK1;
+	cmd.sharpDegreeK2 = in->sharpK2;
+	cmd.normalizeFactor = in->normalizeFactor;
+	cmd.sharpThresholdE2 = in->sharpThreshE2;
+	cmd.sharpThresholdE3 = in->sharpThreshE3;
+	cmd.sharpThresholdE4 = in->sharpThreshE4;
+	cmd.sharpThresholdE5 = in->sharpThreshE5;
+	cmd.F1Coeff0 = in->filter1Coefficients[0];
+	cmd.F1Coeff1 = in->filter1Coefficients[1];
+	cmd.F1Coeff2 = in->filter1Coefficients[2];
+	cmd.F1Coeff3 = in->filter1Coefficients[3];
+	cmd.F1Coeff4 = in->filter1Coefficients[4];
+	cmd.F1Coeff5 = in->filter1Coefficients[5];
+	cmd.F1Coeff6 = in->filter1Coefficients[6];
+	cmd.F1Coeff7 = in->filter1Coefficients[7];
+	cmd.F1Coeff8 = in->filter1Coefficients[8];
+	cmd.F2Coeff0 = in->filter2Coefficients[0];
+	cmd.F2Coeff1 = in->filter2Coefficients[1];
+	cmd.F2Coeff2 = in->filter2Coefficients[2];
+	cmd.F2Coeff3 = in->filter2Coefficients[3];
+	cmd.F2Coeff4 = in->filter2Coefficients[4];
+	cmd.F2Coeff5 = in->filter2Coefficients[5];
+	cmd.F2Coeff6 = in->filter2Coefficients[6];
+	cmd.F2Coeff7 = in->filter2Coefficients[7];
+	cmd.F2Coeff8 = in->filter2Coefficients[8];
+
+	vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_asf_config(struct vfe_cmd_asf_config *in)
+{
+	struct vfe_asf_update cmd;
+	struct vfe_asfcrop_cfg cmd2;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd2, 0, sizeof(cmd2));
+
+	ctrl->vfeModuleEnableLocal.asfEnable = in->enable;
+
+	cmd.smoothEnable = in->smoothFilterEnabled;
+	cmd.sharpMode = in->sharpMode;
+	cmd.smoothCoeff0 = in->smoothCoefCenter;
+	cmd.smoothCoeff1 = in->smoothCoefSurr;
+	cmd.cropEnable = in->cropEnable;
+	cmd.sharpThresholdE1 = in->sharpThreshE1;
+	cmd.sharpDegreeK1 = in->sharpK1;
+	cmd.sharpDegreeK2 = in->sharpK2;
+	cmd.normalizeFactor = in->normalizeFactor;
+	cmd.sharpThresholdE2 = in->sharpThreshE2;
+	cmd.sharpThresholdE3 = in->sharpThreshE3;
+	cmd.sharpThresholdE4 = in->sharpThreshE4;
+	cmd.sharpThresholdE5 = in->sharpThreshE5;
+	cmd.F1Coeff0 = in->filter1Coefficients[0];
+	cmd.F1Coeff1 = in->filter1Coefficients[1];
+	cmd.F1Coeff2 = in->filter1Coefficients[2];
+	cmd.F1Coeff3 = in->filter1Coefficients[3];
+	cmd.F1Coeff4 = in->filter1Coefficients[4];
+	cmd.F1Coeff5 = in->filter1Coefficients[5];
+	cmd.F1Coeff6 = in->filter1Coefficients[6];
+	cmd.F1Coeff7 = in->filter1Coefficients[7];
+	cmd.F1Coeff8 = in->filter1Coefficients[8];
+	cmd.F2Coeff0 = in->filter2Coefficients[0];
+	cmd.F2Coeff1 = in->filter2Coefficients[1];
+	cmd.F2Coeff2 = in->filter2Coefficients[2];
+	cmd.F2Coeff3 = in->filter2Coefficients[3];
+	cmd.F2Coeff4 = in->filter2Coefficients[4];
+	cmd.F2Coeff5 = in->filter2Coefficients[5];
+	cmd.F2Coeff6 = in->filter2Coefficients[6];
+	cmd.F2Coeff7 = in->filter2Coefficients[7];
+	cmd.F2Coeff8 = in->filter2Coefficients[8];
+
+	vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	cmd2.firstLine = in->cropFirstLine;
+	cmd2.lastLine = in->cropLastLine;
+	cmd2.firstPixel = in->cropFirstPixel;
+	cmd2.lastPixel = in->cropLastPixel;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_ASF_CROP_WIDTH_CFG,
+		    (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_white_balance_config(struct vfe_cmd_white_balance_config *in)
+{
+	struct vfe_wb_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.whiteBalanceEnable = in->enable;
+
+	cmd.ch0Gain = in->ch0Gain;
+	cmd.ch1Gain = in->ch1Gain;
+	cmd.ch2Gain = in->ch2Gain;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_WB_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *in)
+{
+	struct vfe_chroma_suppress_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.chromaSuppressionEnable = in->enable;
+
+	cmd.m1 = in->m1;
+	cmd.m3 = in->m3;
+	cmd.n1 = in->n1;
+	cmd.n3 = in->n3;
+	cmd.mm1 = in->mm1;
+	cmd.nn1 = in->nn1;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUPPRESS_CFG_0,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_roll_off_config(struct vfe_cmd_roll_off_config *in)
+{
+	struct vfe_rolloff_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.lensRollOffEnable = in->enable;
+
+	cmd.gridWidth = in->gridWidth;
+	cmd.gridHeight = in->gridHeight;
+	cmd.yDelta = in->yDelta;
+	cmd.gridX = in->gridXIndex;
+	cmd.gridY = in->gridYIndex;
+	cmd.pixelX = in->gridPixelXIndex;
+	cmd.pixelY = in->gridPixelYIndex;
+	cmd.yDeltaAccum = in->yDeltaAccum;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_ROLLOFF_CFG_0,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	vfe_write_lens_roll_off_table(in);
+}
+
+void vfe_chroma_subsample_config(struct vfe_cmd_chroma_subsample_config *in)
+{
+	struct vfe_chromasubsample_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.chromaSubsampleEnable = in->enable;
+
+	cmd.hCositedPhase = in->hCositedPhase;
+	cmd.vCositedPhase = in->vCositedPhase;
+	cmd.hCosited = in->hCosited;
+	cmd.vCosited = in->vCosited;
+	cmd.hsubSampleEnable = in->hsubSampleEnable;
+	cmd.vsubSampleEnable = in->vsubSampleEnable;
+	cmd.cropEnable = in->cropEnable;
+	cmd.cropWidthLastPixel = in->cropWidthLastPixel;
+	cmd.cropWidthFirstPixel = in->cropWidthFirstPixel;
+	cmd.cropHeightLastLine = in->cropHeightLastLine;
+	cmd.cropHeightFirstLine = in->cropHeightFirstLine;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUBSAMPLE_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *in)
+{
+	struct vfe_chroma_enhance_cfg cmd;
+	struct vfe_color_convert_cfg cmd2;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd2, 0, sizeof(cmd2));
+
+	ctrl->vfeModuleEnableLocal.chromaEnhanEnable = in->enable;
+
+	cmd.ap = in->ap;
+	cmd.am = in->am;
+	cmd.bp = in->bp;
+	cmd.bm = in->bm;
+	cmd.cp = in->cp;
+	cmd.cm = in->cm;
+	cmd.dp = in->dp;
+	cmd.dm = in->dm;
+	cmd.kcb = in->kcb;
+	cmd.kcr = in->kcr;
+
+	cmd2.v0 = in->RGBtoYConversionV0;
+	cmd2.v1 = in->RGBtoYConversionV1;
+	cmd2.v2 = in->RGBtoYConversionV2;
+	cmd2.ConvertOffset = in->RGBtoYConversionOffset;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_ENHAN_A,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CONVERT_COEFF_0,
+		    (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *in)
+{
+	struct vfe_scaler2_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.scaler2CbcrEnable = in->enable;
+
+	cmd.hEnable = in->hconfig.enable;
+	cmd.vEnable = in->vconfig.enable;
+	cmd.inWidth = in->hconfig.inputSize;
+	cmd.outWidth = in->hconfig.outputSize;
+	cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor;
+	cmd.horizInterResolution = in->hconfig.interpolationResolution;
+	cmd.inHeight = in->vconfig.inputSize;
+	cmd.outHeight = in->vconfig.outputSize;
+	cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor;
+	cmd.vertInterResolution = in->vconfig.interpolationResolution;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CBCR_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *in)
+{
+	struct vfe_scaler2_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.scaler2YEnable = in->enable;
+
+	cmd.hEnable = in->hconfig.enable;
+	cmd.vEnable = in->vconfig.enable;
+	cmd.inWidth = in->hconfig.inputSize;
+	cmd.outWidth = in->hconfig.outputSize;
+	cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor;
+	cmd.horizInterResolution = in->hconfig.interpolationResolution;
+	cmd.inHeight = in->vconfig.inputSize;
+	cmd.outHeight = in->vconfig.outputSize;
+	cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor;
+	cmd.vertInterResolution = in->vconfig.interpolationResolution;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_SCALE_Y_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *in)
+{
+	struct vfe_main_scaler_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.mainScalerEnable = in->enable;
+
+	cmd.hEnable = in->hconfig.enable;
+	cmd.vEnable = in->vconfig.enable;
+	cmd.inWidth = in->hconfig.inputSize;
+	cmd.outWidth = in->hconfig.outputSize;
+	cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor;
+	cmd.horizInterResolution = in->hconfig.interpolationResolution;
+	cmd.horizMNInit = in->MNInitH.MNCounterInit;
+	cmd.horizPhaseInit = in->MNInitH.phaseInit;
+	cmd.inHeight = in->vconfig.inputSize;
+	cmd.outHeight = in->vconfig.outputSize;
+	cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor;
+	cmd.vertInterResolution = in->vconfig.interpolationResolution;
+	cmd.vertMNInit = in->MNInitV.MNCounterInit;
+	cmd.vertPhaseInit = in->MNInitV.phaseInit;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_stats_wb_exp_stop(void)
+{
+	ctrl->vfeStatsCmdLocal.axwEnable = FALSE;
+	ctrl->vfeImaskLocal.awbPingpongIrq = FALSE;
+}
+
+void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *in)
+{
+	struct vfe_statsawb_update cmd;
+	struct vfe_statsawbae_update cmd2;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd2, 0, sizeof(cmd2));
+
+	cmd.m1 = in->awbMCFG[0];
+	cmd.m2 = in->awbMCFG[1];
+	cmd.m3 = in->awbMCFG[2];
+	cmd.m4 = in->awbMCFG[3];
+	cmd.c1 = in->awbCCFG[0];
+	cmd.c2 = in->awbCCFG[1];
+	cmd.c3 = in->awbCCFG[2];
+	cmd.c4 = in->awbCCFG[3];
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	cmd2.aeRegionCfg = in->wbExpRegions;
+	cmd2.aeSubregionCfg = in->wbExpSubRegion;
+	cmd2.awbYMin = in->awbYMin;
+	cmd2.awbYMax = in->awbYMax;
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG,
+		    (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_stats_update_af(struct vfe_cmd_stats_af_update *in)
+{
+	struct vfe_statsaf_update cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.windowVOffset = in->windowVOffset;
+	cmd.windowHOffset = in->windowHOffset;
+	cmd.windowMode = in->windowMode;
+	cmd.windowHeight = in->windowHeight;
+	cmd.windowWidth = in->windowWidth;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *in)
+{
+	struct vfe_statsawb_update cmd;
+	struct vfe_statsawbae_update cmd2;
+	struct vfe_statsaxw_hdr_cfg cmd3;
+
+	ctrl->vfeStatsCmdLocal.axwEnable = in->enable;
+	ctrl->vfeImaskLocal.awbPingpongIrq = TRUE;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd2, 0, sizeof(cmd2));
+	memset(&cmd3, 0, sizeof(cmd3));
+
+	cmd.m1 = in->awbMCFG[0];
+	cmd.m2 = in->awbMCFG[1];
+	cmd.m3 = in->awbMCFG[2];
+	cmd.m4 = in->awbMCFG[3];
+	cmd.c1 = in->awbCCFG[0];
+	cmd.c2 = in->awbCCFG[1];
+	cmd.c3 = in->awbCCFG[2];
+	cmd.c4 = in->awbCCFG[3];
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	cmd2.aeRegionCfg = in->wbExpRegions;
+	cmd2.aeSubregionCfg = in->wbExpSubRegion;
+	cmd2.awbYMin = in->awbYMin;
+	cmd2.awbYMax = in->awbYMax;
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG,
+		    (uint32_t *)&cmd2, sizeof(cmd2));
+
+	cmd3.axwHeader = in->axwHeader;
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AXW_HEADER,
+		    (uint32_t *)&cmd3, sizeof(cmd3));
+}
+
+void vfe_stats_start_af(struct vfe_cmd_stats_af_start *in)
+{
+	struct vfe_statsaf_update cmd;
+	struct vfe_statsaf_cfg cmd2;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd2, 0, sizeof(cmd2));
+
+	ctrl->vfeStatsCmdLocal.autoFocusEnable = in->enable;
+	ctrl->vfeImaskLocal.afPingpongIrq = TRUE;
+
+	cmd.windowVOffset = in->windowVOffset;
+	cmd.windowHOffset = in->windowHOffset;
+	cmd.windowMode = in->windowMode;
+	cmd.windowHeight = in->windowHeight;
+	cmd.windowWidth = in->windowWidth;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	cmd2.a00 = in->highPassCoef[0];
+	cmd2.a04 = in->highPassCoef[1];
+	cmd2.a20 = in->highPassCoef[2];
+	cmd2.a21 = in->highPassCoef[3];
+	cmd2.a22 = in->highPassCoef[4];
+	cmd2.a23 = in->highPassCoef[5];
+	cmd2.a24 = in->highPassCoef[6];
+	cmd2.fvMax = in->metricMax;
+	cmd2.fvMetric = in->metricSelection;
+	cmd2.afHeader = in->bufferHeader;
+	cmd2.entry00 = in->gridForMultiWindows[0];
+	cmd2.entry01 = in->gridForMultiWindows[1];
+	cmd2.entry02 = in->gridForMultiWindows[2];
+	cmd2.entry03 = in->gridForMultiWindows[3];
+	cmd2.entry10 = in->gridForMultiWindows[4];
+	cmd2.entry11 = in->gridForMultiWindows[5];
+	cmd2.entry12 = in->gridForMultiWindows[6];
+	cmd2.entry13 = in->gridForMultiWindows[7];
+	cmd2.entry20 = in->gridForMultiWindows[8];
+	cmd2.entry21 = in->gridForMultiWindows[9];
+	cmd2.entry22 = in->gridForMultiWindows[10];
+	cmd2.entry23 = in->gridForMultiWindows[11];
+	cmd2.entry30 = in->gridForMultiWindows[12];
+	cmd2.entry31 = in->gridForMultiWindows[13];
+	cmd2.entry32 = in->gridForMultiWindows[14];
+	cmd2.entry33 = in->gridForMultiWindows[15];
+
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_GRID_0,
+		    (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_stats_setting(struct vfe_cmd_stats_setting *in)
+{
+	struct vfe_statsframe cmd1;
+	struct vfe_busstats_wrprio cmd2;
+
+	memset(&cmd1, 0, sizeof(cmd1));
+	memset(&cmd2, 0, sizeof(cmd2));
+
+	ctrl->afStatsControl.addressBuffer[0] = in->afBuffer[0];
+	ctrl->afStatsControl.addressBuffer[1] = in->afBuffer[1];
+	ctrl->afStatsControl.nextFrameAddrBuf = in->afBuffer[2];
+
+	ctrl->awbStatsControl.addressBuffer[0] = in->awbBuffer[0];
+	ctrl->awbStatsControl.addressBuffer[1] = in->awbBuffer[1];
+	ctrl->awbStatsControl.nextFrameAddrBuf = in->awbBuffer[2];
+
+	cmd1.lastPixel = in->frameHDimension;
+	cmd1.lastLine = in->frameVDimension;
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_FRAME_SIZE,
+		    (uint32_t *)&cmd1, sizeof(cmd1));
+
+	cmd2.afBusPriority = in->afBusPriority;
+	cmd2.awbBusPriority = in->awbBusPriority;
+	cmd2.histBusPriority = in->histBusPriority;
+	cmd2.afBusPriorityEn = in->afBusPrioritySelection;
+	cmd2.awbBusPriorityEn = in->awbBusPrioritySelection;
+	cmd2.histBusPriorityEn = in->histBusPrioritySelection;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_BUS_STATS_WR_PRIORITY,
+		    (uint32_t *)&cmd2, sizeof(cmd2));
+
+	/* Program the bus ping pong address for statistics modules. */
+	writel(in->afBuffer[0], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	writel(in->afBuffer[1], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+	writel(in->awbBuffer[0],
+	       ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	writel(in->awbBuffer[1],
+	       ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+	writel(in->histBuffer[0],
+	       ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+	writel(in->histBuffer[1],
+	       ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+}
+
+void vfe_axi_input_config(struct vfe_cmd_axi_input_config *in)
+{
+	struct VFE_AxiInputCmdType cmd;
+	uint32_t xSizeWord, axiRdUnpackPattern;
+	uint8_t axiInputPpw;
+	uint32_t busPingpongRdIrqEnable;
+
+	ctrl->vfeImaskLocal.rdPingpongIrq = TRUE;
+
+	switch (in->pixelSize) {
+	case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+		ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_10BIT;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+		ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_12BIT;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+	default:
+		ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_8BIT;
+		break;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	switch (in->pixelSize) {
+	case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+		axiInputPpw = 6;
+		axiRdUnpackPattern = 0xD43210;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+		axiInputPpw = 5;
+		axiRdUnpackPattern = 0xC3210;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+	default:
+		axiInputPpw = 8;
+		axiRdUnpackPattern = 0xF6543210;
+		break;
+	}
+
+	xSizeWord =
+	    ((((in->xOffset % axiInputPpw) + in->xSize) +
+	      (axiInputPpw - 1)) / axiInputPpw) - 1;
+
+	cmd.stripeStartAddr0 = in->fragAddr[0];
+	cmd.stripeStartAddr1 = in->fragAddr[1];
+	cmd.stripeStartAddr2 = in->fragAddr[2];
+	cmd.stripeStartAddr3 = in->fragAddr[3];
+	cmd.ySize = in->ySize;
+	cmd.yOffsetDelta = 0;
+	cmd.xSizeWord = xSizeWord;
+	cmd.burstLength = 1;
+	cmd.NumOfRows = in->numOfRows;
+	cmd.RowIncrement = (in->rowIncrement + (axiInputPpw - 1)) / axiInputPpw;
+	cmd.mainUnpackHeight = in->ySize;
+	cmd.mainUnpackWidth = in->xSize - 1;
+	cmd.mainUnpackHbiSel = (uint32_t) in->unpackHbi;
+	cmd.mainUnpackPhase = in->unpackPhase;
+	cmd.unpackPattern = axiRdUnpackPattern;
+	cmd.padLeft = in->padRepeatCountLeft;
+	cmd.padRight = in->padRepeatCountRight;
+	cmd.padTop = in->padRepeatCountTop;
+	cmd.padBottom = in->padRepeatCountBottom;
+	cmd.leftUnpackPattern0 = in->padLeftComponentSelectCycle0;
+	cmd.leftUnpackPattern1 = in->padLeftComponentSelectCycle1;
+	cmd.leftUnpackPattern2 = in->padLeftComponentSelectCycle2;
+	cmd.leftUnpackPattern3 = in->padLeftComponentSelectCycle3;
+	cmd.leftUnpackStop0 = in->padLeftStopCycle0;
+	cmd.leftUnpackStop1 = in->padLeftStopCycle1;
+	cmd.leftUnpackStop2 = in->padLeftStopCycle2;
+	cmd.leftUnpackStop3 = in->padLeftStopCycle3;
+	cmd.rightUnpackPattern0 = in->padRightComponentSelectCycle0;
+	cmd.rightUnpackPattern1 = in->padRightComponentSelectCycle1;
+	cmd.rightUnpackPattern2 = in->padRightComponentSelectCycle2;
+	cmd.rightUnpackPattern3 = in->padRightComponentSelectCycle3;
+	cmd.rightUnpackStop0 = in->padRightStopCycle0;
+	cmd.rightUnpackStop1 = in->padRightStopCycle1;
+	cmd.rightUnpackStop2 = in->padRightStopCycle2;
+	cmd.rightUnpackStop3 = in->padRightStopCycle3;
+	cmd.topUnapckPattern = in->padTopLineCount;
+	cmd.bottomUnapckPattern = in->padBottomLineCount;
+
+	/*  program vfe_bus_cfg */
+	vfe_prog_hw(ctrl->vfebase + VFE_BUS_STRIPE_RD_ADDR_0,
+		    (uint32_t *)&cmd, sizeof(cmd));
+
+	/* hacking code, put it to default value */
+	busPingpongRdIrqEnable = 0xf;
+
+	writel(busPingpongRdIrqEnable, ctrl->vfebase + VFE_BUS_PINGPONG_IRQ_EN);
+}
+
+void vfe_axi_output_config(struct vfe_cmd_axi_output_config *in)
+{
+	/* local variable  */
+	uint32_t *pcircle;
+	uint32_t *pdest;
+	uint32_t *psrc;
+	uint8_t i;
+	uint8_t fcnt;
+	uint16_t axioutpw = 8;
+
+	/* parameters check, condition and usage mode check */
+	ctrl->encPath.fragCount = in->output2.fragmentCount;
+	if (ctrl->encPath.fragCount > 1)
+		ctrl->encPath.multiFrag = TRUE;
+
+	ctrl->viewPath.fragCount = in->output1.fragmentCount;
+	if (ctrl->viewPath.fragCount > 1)
+		ctrl->viewPath.multiFrag = TRUE;
+
+	/* VFE_BUS_CFG.  raw data size */
+	ctrl->vfeBusConfigLocal.rawPixelDataSize = in->outputDataSize;
+
+	switch (in->outputDataSize) {
+	case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+		axioutpw = 8;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+		axioutpw = 6;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+		axioutpw = 5;
+		break;
+	}
+
+	ctrl->axiOutputMode = in->outputMode;
+
+	CDBG("axiOutputMode = %d\n", ctrl->axiOutputMode);
+
+	switch (ctrl->axiOutputMode) {
+	case VFE_AXI_OUTPUT_MODE_Output1:{
+			ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE;
+			ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+			ctrl->vfeBusConfigLocal.rawWritePathSelect =
+			    VFE_RAW_OUTPUT_DISABLED;
+
+			ctrl->encPath.pathEnabled = FALSE;
+			ctrl->vfeImaskLocal.encIrq = FALSE;
+			ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			    VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+			ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE;
+			ctrl->vfeBusConfigLocal.encCbcrWrPathEn = FALSE;
+			ctrl->viewPath.pathEnabled = TRUE;
+			ctrl->vfeImaskLocal.viewIrq = TRUE;
+			ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			    VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+			ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE;
+			ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+		}		/* VFE_AXI_OUTPUT_MODE_Output1 */
+		break;
+
+	case VFE_AXI_OUTPUT_MODE_Output2:{
+			ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE;
+			ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+			ctrl->vfeBusConfigLocal.rawWritePathSelect =
+			    VFE_RAW_OUTPUT_DISABLED;
+
+			ctrl->encPath.pathEnabled = TRUE;
+			ctrl->vfeImaskLocal.encIrq = TRUE;
+			ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			    VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+			ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE;
+			ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE;
+
+			ctrl->viewPath.pathEnabled = FALSE;
+			ctrl->vfeImaskLocal.viewIrq = FALSE;
+			ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			    VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+			ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE;
+			ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = FALSE;
+
+			if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+		}		/* VFE_AXI_OUTPUT_MODE_Output2 */
+		break;
+
+	case VFE_AXI_OUTPUT_MODE_Output1AndOutput2:{
+			ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE;
+			ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+			ctrl->vfeBusConfigLocal.rawWritePathSelect =
+			    VFE_RAW_OUTPUT_DISABLED;
+
+			ctrl->encPath.pathEnabled = TRUE;
+			ctrl->vfeImaskLocal.encIrq = TRUE;
+			ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			    VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+			ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE;
+			ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE;
+			ctrl->viewPath.pathEnabled = TRUE;
+			ctrl->vfeImaskLocal.viewIrq = TRUE;
+			ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			    VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+			ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE;
+			ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+		}		/* VFE_AXI_OUTPUT_MODE_Output1AndOutput2 */
+		break;
+
+	case VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2:{
+			/* For raw snapshot, we need both ping and pong buffer
+			 * initialized to the same address. Otherwise, if we
+			 * leave the pong buffer to NULL, there will be
+			 * axi_error.
+			 * Note that ideally we should deal with this at upper
+			 * layer, which is in msm_vfe8x.c */
+			if (!in->output2.outputCbcr.outFragments[1][0]) {
+				in->output2.outputCbcr.outFragments[1][0] =
+				    in->output2.outputCbcr.outFragments[0][0];
+			}
+
+			ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE;
+			ctrl->vfeCamifConfigLocal.camif2OutputEnable = FALSE;
+			ctrl->vfeBusConfigLocal.rawWritePathSelect =
+			    VFE_RAW_OUTPUT_ENC_CBCR_PATH;
+
+			ctrl->encPath.pathEnabled = TRUE;
+			ctrl->vfeImaskLocal.encIrq = TRUE;
+			ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			    VFE_COMP_IRQ_CBCR_ONLY;
+
+			ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE;
+			ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE;
+
+			ctrl->viewPath.pathEnabled = FALSE;
+			ctrl->vfeImaskLocal.viewIrq = FALSE;
+			ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			    VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+			ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE;
+			ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = FALSE;
+
+			if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+		}		/* VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2 */
+		break;
+
+	case VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1:{
+			ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE;
+			ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+			ctrl->vfeBusConfigLocal.rawWritePathSelect =
+			    VFE_RAW_OUTPUT_VIEW_CBCR_PATH;
+
+			ctrl->encPath.pathEnabled = TRUE;
+			ctrl->vfeImaskLocal.encIrq = TRUE;
+			ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			    VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+			ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE;
+			ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE;
+
+			ctrl->viewPath.pathEnabled = TRUE;
+			ctrl->vfeImaskLocal.viewIrq = TRUE;
+			ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			    VFE_COMP_IRQ_CBCR_ONLY;
+
+			ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE;
+			ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+		} /* VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1 */
+		break;
+
+	case VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2:{
+			ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE;
+			ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+			ctrl->vfeBusConfigLocal.rawWritePathSelect =
+			    VFE_RAW_OUTPUT_ENC_CBCR_PATH;
+
+			ctrl->encPath.pathEnabled = TRUE;
+			ctrl->vfeImaskLocal.encIrq = TRUE;
+			ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			    VFE_COMP_IRQ_CBCR_ONLY;
+
+			ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE;
+			ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE;
+
+			ctrl->viewPath.pathEnabled = TRUE;
+			ctrl->vfeImaskLocal.viewIrq = TRUE;
+
+			ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			    VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+			ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE;
+			ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+			    ctrl->encPath.multiFrag)
+				ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+			if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+			    ctrl->viewPath.multiFrag)
+				ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+		} /* VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2 */
+		break;
+
+	case VFE_AXI_LAST_OUTPUT_MODE_ENUM:
+		break;
+	}			/* switch */
+
+	/* Save the addresses for each path. */
+	/* output2 path */
+	fcnt = ctrl->encPath.fragCount;
+
+	pcircle = ctrl->encPath.yPath.addressBuffer;
+	pdest = ctrl->encPath.nextFrameAddrBuf;
+
+	psrc = &(in->output2.outputY.outFragments[0][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output2.outputY.outFragments[1][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output2.outputY.outFragments[2][0]);
+	for (i = 0; i < fcnt; i++)
+		*pdest++ = *psrc++;
+
+	pcircle = ctrl->encPath.cbcrPath.addressBuffer;
+
+	psrc = &(in->output2.outputCbcr.outFragments[0][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output2.outputCbcr.outFragments[1][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output2.outputCbcr.outFragments[2][0]);
+	for (i = 0; i < fcnt; i++)
+		*pdest++ = *psrc++;
+
+	vfe_set_bus_pipo_addr(&ctrl->viewPath, &ctrl->encPath);
+
+	ctrl->encPath.ackPending = FALSE;
+	ctrl->encPath.currentFrame = ping;
+	ctrl->encPath.whichOutputPath = 1;
+	ctrl->encPath.yPath.fragIndex = 2;
+	ctrl->encPath.cbcrPath.fragIndex = 2;
+	ctrl->encPath.yPath.hwCurrentFlag = ping;
+	ctrl->encPath.cbcrPath.hwCurrentFlag = ping;
+
+	/* output1 path */
+	pcircle = ctrl->viewPath.yPath.addressBuffer;
+	pdest = ctrl->viewPath.nextFrameAddrBuf;
+	fcnt = ctrl->viewPath.fragCount;
+
+	psrc = &(in->output1.outputY.outFragments[0][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output1.outputY.outFragments[1][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output1.outputY.outFragments[2][0]);
+	for (i = 0; i < fcnt; i++)
+		*pdest++ = *psrc++;
+
+	pcircle = ctrl->viewPath.cbcrPath.addressBuffer;
+
+	psrc = &(in->output1.outputCbcr.outFragments[0][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output1.outputCbcr.outFragments[1][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output1.outputCbcr.outFragments[2][0]);
+	for (i = 0; i < fcnt; i++)
+		*pdest++ = *psrc++;
+
+	ctrl->viewPath.ackPending = FALSE;
+	ctrl->viewPath.currentFrame = ping;
+	ctrl->viewPath.whichOutputPath = 0;
+	ctrl->viewPath.yPath.fragIndex = 2;
+	ctrl->viewPath.cbcrPath.fragIndex = 2;
+	ctrl->viewPath.yPath.hwCurrentFlag = ping;
+	ctrl->viewPath.cbcrPath.hwCurrentFlag = ping;
+
+	/* call to program the registers. */
+	vfe_axi_output(in, &ctrl->viewPath, &ctrl->encPath, axioutpw);
+}
+
+void vfe_epoch1_config(struct vfe_cmds_camif_epoch *in)
+{
+	struct vfe_epoch1cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+	/* determine if epoch interrupt needs to be enabled. */
+	if (in->enable == TRUE) {
+		cmd.epoch1Line = in->lineindex;
+		vfe_prog_hw(ctrl->vfebase + CAMIF_EPOCH_IRQ, (uint32_t *)&cmd,
+					sizeof(cmd));
+	}
+
+	/* Set the epoch1 interrupt mask. */
+	ctrl->vfeImaskLocal.camifEpoch1Irq = in->enable;
+	ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+	vfe_program_irq_mask(ctrl->vfeImaskPacked);
+
+	/* Store the epoch1 data. */
+	ctrl->vfeCamifEpoch1Local.enable = in->enable;
+	ctrl->vfeCamifEpoch1Local.lineindex = in->lineindex;
+}
+
+void vfe_camif_config(struct vfe_cmd_camif_config *in)
+{
+	struct vfe_camifcfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	CDBG("camif.frame pixelsPerLine = %d\n", in->frame.pixelsPerLine);
+	CDBG("camif.frame linesPerFrame = %d\n", in->frame.linesPerFrame);
+	CDBG("camif.window firstpixel = %d\n", in->window.firstpixel);
+	CDBG("camif.window lastpixel = %d\n", in->window.lastpixel);
+	CDBG("camif.window firstline = %d\n", in->window.firstline);
+	CDBG("camif.window lastline = %d\n", in->window.lastline);
+
+	/* determine if epoch interrupt needs to be enabled.  */
+	if ((in->epoch1.enable == TRUE) &&
+	    (in->epoch1.lineindex <= in->frame.linesPerFrame))
+		ctrl->vfeImaskLocal.camifEpoch1Irq = 1;
+
+	if ((in->epoch2.enable == TRUE) &&
+	    (in->epoch2.lineindex <= in->frame.linesPerFrame)) {
+		ctrl->vfeImaskLocal.camifEpoch2Irq = 1;
+	}
+
+	/*  save the content to program CAMIF_CONFIG seperately. */
+	ctrl->vfeCamifConfigLocal.camifCfgFromCmd = in->camifConfig;
+
+	/* EFS_Config */
+	cmd.efsEndOfLine = in->EFS.efsendofline;
+	cmd.efsStartOfLine = in->EFS.efsstartofline;
+	cmd.efsEndOfFrame = in->EFS.efsendofframe;
+	cmd.efsStartOfFrame = in->EFS.efsstartofframe;
+
+	/* Frame Config */
+	cmd.frameConfigPixelsPerLine = in->frame.pixelsPerLine;
+	cmd.frameConfigLinesPerFrame = in->frame.linesPerFrame;
+
+	/* Window Width Config */
+	cmd.windowWidthCfgLastPixel = in->window.lastpixel;
+	cmd.windowWidthCfgFirstPixel = in->window.firstpixel;
+
+	/* Window Height Config */
+	cmd.windowHeightCfglastLine = in->window.lastline;
+	cmd.windowHeightCfgfirstLine = in->window.firstline;
+
+	/* Subsample 1 Config */
+	cmd.subsample1CfgPixelSkip = in->subsample.pixelskipmask;
+	cmd.subsample1CfgLineSkip = in->subsample.lineskipmask;
+
+	/* Subsample 2 Config */
+	cmd.subsample2CfgFrameSkip = in->subsample.frameskip;
+	cmd.subsample2CfgFrameSkipMode = in->subsample.frameskipmode;
+	cmd.subsample2CfgPixelSkipWrap = in->subsample.pixelskipwrap;
+
+	/* Epoch Interrupt */
+	cmd.epoch1Line = in->epoch1.lineindex;
+	cmd.epoch2Line = in->epoch2.lineindex;
+
+	vfe_prog_hw(ctrl->vfebase + CAMIF_EFS_CONFIG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *in)
+{
+	struct vfe_fov_crop_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.cropEnable = in->enable;
+
+	/* FOV Corp, Part 1 */
+	cmd.lastPixel = in->lastPixel;
+	cmd.firstPixel = in->firstPixel;
+
+	/* FOV Corp, Part 2 */
+	cmd.lastLine = in->lastLine;
+	cmd.firstLine = in->firstLine;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_CROP_WIDTH_CFG,
+		    (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_get_hw_version(struct vfe_cmd_hw_version *out)
+{
+	uint32_t vfeHwVersionPacked;
+	struct vfe_hw_ver ver;
+
+	vfeHwVersionPacked = readl(ctrl->vfebase + VFE_HW_VERSION);
+
+	ver = *((struct vfe_hw_ver *)&vfeHwVersionPacked);
+
+	out->coreVersion = ver.coreVersion;
+	out->minorVersion = ver.minorVersion;
+	out->majorVersion = ver.majorVersion;
+}
+
+static void vfe_reset_internal_variables(void)
+{
+	/* local variables to program the hardware. */
+	ctrl->vfeImaskPacked = 0;
+	ctrl->vfeImaskCompositePacked = 0;
+
+	/* FALSE = disable,  1 = enable. */
+	memset(&ctrl->vfeModuleEnableLocal, 0,
+	       sizeof(ctrl->vfeModuleEnableLocal));
+
+	/* 0 = disable, 1 = enable */
+	memset(&ctrl->vfeCamifConfigLocal, 0,
+	       sizeof(ctrl->vfeCamifConfigLocal));
+	/* 0 = disable, 1 = enable */
+	memset(&ctrl->vfeImaskLocal, 0, sizeof(ctrl->vfeImaskLocal));
+	memset(&ctrl->vfeStatsCmdLocal, 0, sizeof(ctrl->vfeStatsCmdLocal));
+	memset(&ctrl->vfeBusConfigLocal, 0, sizeof(ctrl->vfeBusConfigLocal));
+	memset(&ctrl->vfeBusPmConfigLocal, 0,
+	       sizeof(ctrl->vfeBusPmConfigLocal));
+	memset(&ctrl->vfeBusCmdLocal, 0, sizeof(ctrl->vfeBusCmdLocal));
+	memset(&ctrl->vfeInterruptNameLocal, 0,
+	       sizeof(ctrl->vfeInterruptNameLocal));
+	memset(&ctrl->vfeDroppedFrameCounts, 0,
+	       sizeof(ctrl->vfeDroppedFrameCounts));
+	memset(&ctrl->vfeIrqThreadMsgLocal, 0,
+	       sizeof(ctrl->vfeIrqThreadMsgLocal));
+
+	/* state control variables */
+	ctrl->vfeStartAckPendingFlag = FALSE;
+	ctrl->vfeStopAckPending = FALSE;
+	ctrl->vfeIrqCompositeMaskLocal.ceDoneSel = 0;
+	ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = VFE_COMP_IRQ_BOTH_Y_CBCR;
+	ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+	    VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+	ctrl->vstate = VFE_STATE_IDLE;
+
+	ctrl->axiOutputMode = VFE_AXI_LAST_OUTPUT_MODE_ENUM;
+	/* 0 for continuous mode, 1 for snapshot mode */
+	ctrl->vfeOperationMode = VFE_START_OPERATION_MODE_CONTINUOUS;
+	ctrl->vfeSnapShotCount = 0;
+	ctrl->vfeStatsPingPongReloadFlag = FALSE;
+	/* this is unsigned 32 bit integer. */
+	ctrl->vfeFrameId = 0;
+	ctrl->vfeFrameSkip.output1Pattern = 0xffffffff;
+	ctrl->vfeFrameSkip.output1Period = 31;
+	ctrl->vfeFrameSkip.output2Pattern = 0xffffffff;
+	ctrl->vfeFrameSkip.output2Period = 31;
+	ctrl->vfeFrameSkipPattern = 0xffffffff;
+	ctrl->vfeFrameSkipCount = 0;
+	ctrl->vfeFrameSkipPeriod = 31;
+
+	memset((void *)&ctrl->encPath, 0, sizeof(ctrl->encPath));
+	memset((void *)&ctrl->viewPath, 0, sizeof(ctrl->viewPath));
+
+	ctrl->encPath.whichOutputPath = 1;
+	ctrl->encPath.cbcrStatusBit = 5;
+	ctrl->viewPath.whichOutputPath = 0;
+	ctrl->viewPath.cbcrStatusBit = 7;
+
+	ctrl->vfeTestGenStartFlag = FALSE;
+
+	/* default to bank 0. */
+	ctrl->vfeLaBankSel = 0;
+
+	/* default to bank 0 for all channels. */
+	memset(&ctrl->vfeGammaLutSel, 0, sizeof(ctrl->vfeGammaLutSel));
+
+	/* Stats control variables. */
+	memset(&ctrl->afStatsControl, 0, sizeof(ctrl->afStatsControl));
+	memset(&ctrl->awbStatsControl, 0, sizeof(ctrl->awbStatsControl));
+	vfe_set_stats_pingpong_address(&ctrl->afStatsControl,
+				       &ctrl->awbStatsControl);
+}
+
+void vfe_reset(void)
+{
+	vfe_reset_internal_variables();
+
+	ctrl->vfeImaskLocal.resetAckIrq = TRUE;
+	ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+
+	/* disable all interrupts. */
+	writel(VFE_DISABLE_ALL_IRQS, ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK);
+
+	/* clear all pending interrupts */
+	writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+	/* enable reset_ack interrupt.  */
+	writel(ctrl->vfeImaskPacked, ctrl->vfebase + VFE_IRQ_MASK);
+
+	writel(VFE_RESET_UPON_RESET_CMD, ctrl->vfebase + VFE_GLOBAL_RESET_CMD);
+}
diff --git a/drivers/media/video/msm/msm_vfe8x_proc.h b/drivers/media/video/msm/msm_vfe8x_proc.h
new file mode 100644
index 0000000..aef7eca
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe8x_proc.h
@@ -0,0 +1,1570 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __MSM_VFE8X_REG_H__
+#define __MSM_VFE8X_REG_H__
+
+#include <mach/msm_iomap.h>
+#include <mach/camera.h>
+#include "msm_vfe8x.h"
+
+/* at start of camif,  bit 1:0 = 0x01:enable
+ * image data capture at frame boundary. */
+#define CAMIF_COMMAND_START  0x00000005
+
+/* bit 2= 0x1:clear the CAMIF_STATUS register
+ * value. */
+#define CAMIF_COMMAND_CLEAR  0x00000004
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x10:
+ * disable image data capture immediately. */
+#define CAMIF_COMMAND_STOP_IMMEDIATELY  0x00000002
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x00:
+ * disable image data capture at frame boundary */
+#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY  0x00000000
+
+/* to halt axi bridge */
+#define AXI_HALT  0x00000001
+
+/* clear the halt bit. */
+#define AXI_HALT_CLEAR  0x00000000
+
+/* reset the pipeline when stop command is issued.
+ * (without reset the register.) bit 26-31 = 0,
+ * domain reset, bit 0-9 = 1 for module reset, except
+ * register module. */
+#define VFE_RESET_UPON_STOP_CMD  0x000003ef
+
+/* reset the pipeline when reset command.
+ * bit 26-31 = 0, domain reset, bit 0-9 = 1 for module reset. */
+#define VFE_RESET_UPON_RESET_CMD  0x000003ff
+
+/* bit 5 is for axi status idle or busy.
+ * 1 =  halted,  0 = busy */
+#define AXI_STATUS_BUSY_MASK 0x00000020
+
+/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present
+ * for frame done interrupt */
+#define VFE_COMP_IRQ_BOTH_Y_CBCR 3
+
+/* bit 1 = 1, only cbcr irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_CBCR_ONLY 2
+
+/* bit 0 = 1, only y irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_Y_ONLY 1
+
+/* bit 0 = 1, PM go;   bit1 = 1, PM stop */
+#define VFE_PERFORMANCE_MONITOR_GO   0x00000001
+#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002
+
+/* bit 0 = 1, test gen go;   bit1 = 1, test gen stop */
+#define VFE_TEST_GEN_GO   0x00000001
+#define VFE_TEST_GEN_STOP 0x00000002
+
+/* the chroma is assumed to be interpolated between
+ * the luma samples.  JPEG 4:2:2 */
+#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0
+
+/* constants for irq registers */
+#define VFE_DISABLE_ALL_IRQS 0
+/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS.  */
+#define VFE_CLEAR_ALL_IRQS   0xffffffff
+/* imask for while waiting for stop ack,  driver has already
+ * requested stop, waiting for reset irq,
+ * bit 29,28,27,26 for async timer, bit 9 for reset */
+#define VFE_IMASK_WHILE_STOPPING  0x3c000200
+
+/* when normal case, don't want to block error status.
+ * bit 0,6,20,21,22,30,31 */
+#define VFE_IMASK_ERROR_ONLY             0xC0700041
+#define VFE_REG_UPDATE_TRIGGER           1
+#define VFE_PM_BUF_MAX_CNT_MASK          0xFF
+#define VFE_DMI_CFG_DEFAULT              0x00000100
+#define LENS_ROLL_OFF_DELTA_TABLE_OFFSET 32
+#define VFE_AF_PINGPONG_STATUS_BIT       0x100
+#define VFE_AWB_PINGPONG_STATUS_BIT      0x200
+
+/* VFE I/O registers */
+enum {
+	VFE_HW_VERSION = 0x00000000,
+	VFE_GLOBAL_RESET_CMD = 0x00000004,
+	VFE_MODULE_RESET = 0x00000008,
+	VFE_CGC_OVERRIDE = 0x0000000C,
+	VFE_MODULE_CFG = 0x00000010,
+	VFE_CFG = 0x00000014,
+	VFE_IRQ_MASK = 0x00000018,
+	VFE_IRQ_CLEAR = 0x0000001C,
+	VFE_IRQ_STATUS = 0x00000020,
+	VFE_IRQ_COMPOSITE_MASK = 0x00000024,
+	VFE_BUS_CMD = 0x00000028,
+	VFE_BUS_CFG = 0x0000002C,
+	VFE_BUS_ENC_Y_WR_PING_ADDR = 0x00000030,
+	VFE_BUS_ENC_Y_WR_PONG_ADDR = 0x00000034,
+	VFE_BUS_ENC_Y_WR_IMAGE_SIZE = 0x00000038,
+	VFE_BUS_ENC_Y_WR_BUFFER_CFG = 0x0000003C,
+	VFE_BUS_ENC_CBCR_WR_PING_ADDR = 0x00000040,
+	VFE_BUS_ENC_CBCR_WR_PONG_ADDR = 0x00000044,
+	VFE_BUS_ENC_CBCR_WR_IMAGE_SIZE = 0x00000048,
+	VFE_BUS_ENC_CBCR_WR_BUFFER_CFG = 0x0000004C,
+	VFE_BUS_VIEW_Y_WR_PING_ADDR = 0x00000050,
+	VFE_BUS_VIEW_Y_WR_PONG_ADDR = 0x00000054,
+	VFE_BUS_VIEW_Y_WR_IMAGE_SIZE = 0x00000058,
+	VFE_BUS_VIEW_Y_WR_BUFFER_CFG = 0x0000005C,
+	VFE_BUS_VIEW_CBCR_WR_PING_ADDR = 0x00000060,
+	VFE_BUS_VIEW_CBCR_WR_PONG_ADDR = 0x00000064,
+	VFE_BUS_VIEW_CBCR_WR_IMAGE_SIZE = 0x00000068,
+	VFE_BUS_VIEW_CBCR_WR_BUFFER_CFG = 0x0000006C,
+	VFE_BUS_STATS_AF_WR_PING_ADDR = 0x00000070,
+	VFE_BUS_STATS_AF_WR_PONG_ADDR = 0x00000074,
+	VFE_BUS_STATS_AWB_WR_PING_ADDR = 0x00000078,
+	VFE_BUS_STATS_AWB_WR_PONG_ADDR = 0x0000007C,
+	VFE_BUS_STATS_HIST_WR_PING_ADDR = 0x00000080,
+	VFE_BUS_STATS_HIST_WR_PONG_ADDR = 0x00000084,
+	VFE_BUS_STATS_WR_PRIORITY = 0x00000088,
+	VFE_BUS_STRIPE_RD_ADDR_0 = 0x0000008C,
+	VFE_BUS_STRIPE_RD_ADDR_1 = 0x00000090,
+	VFE_BUS_STRIPE_RD_ADDR_2 = 0x00000094,
+	VFE_BUS_STRIPE_RD_ADDR_3 = 0x00000098,
+	VFE_BUS_STRIPE_RD_VSIZE = 0x0000009C,
+	VFE_BUS_STRIPE_RD_HSIZE = 0x000000A0,
+	VFE_BUS_STRIPE_RD_BUFFER_CFG = 0x000000A4,
+	VFE_BUS_STRIPE_RD_UNPACK_CFG = 0x000000A8,
+	VFE_BUS_STRIPE_RD_UNPACK = 0x000000AC,
+	VFE_BUS_STRIPE_RD_PAD_SIZE = 0x000000B0,
+	VFE_BUS_STRIPE_RD_PAD_L_UNPACK = 0x000000B4,
+	VFE_BUS_STRIPE_RD_PAD_R_UNPACK = 0x000000B8,
+	VFE_BUS_STRIPE_RD_PAD_TB_UNPACK = 0x000000BC,
+	VFE_BUS_PINGPONG_IRQ_EN = 0x000000C0,
+	VFE_BUS_PINGPONG_STATUS = 0x000000C4,
+	VFE_BUS_PM_CMD = 0x000000C8,
+	VFE_BUS_PM_CFG = 0x000000CC,
+	VFE_BUS_ENC_Y_WR_PM_STATS_0 = 0x000000D0,
+	VFE_BUS_ENC_Y_WR_PM_STATS_1 = 0x000000D4,
+	VFE_BUS_ENC_CBCR_WR_PM_STATS_0 = 0x000000D8,
+	VFE_BUS_ENC_CBCR_WR_PM_STATS_1 = 0x000000DC,
+	VFE_BUS_VIEW_Y_WR_PM_STATS_0 = 0x000000E0,
+	VFE_BUS_VIEW_Y_WR_PM_STATS_1 = 0x000000E4,
+	VFE_BUS_VIEW_CBCR_WR_PM_STATS_0 = 0x000000E8,
+	VFE_BUS_VIEW_CBCR_WR_PM_STATS_1 = 0x000000EC,
+	VFE_BUS_MISR_CFG = 0x000000F4,
+	VFE_BUS_MISR_MAST_CFG_0 = 0x000000F8,
+	VFE_BUS_MISR_MAST_CFG_1 = 0x000000FC,
+	VFE_BUS_MISR_RD_VAL = 0x00000100,
+	VFE_AXI_CMD = 0x00000104,
+	VFE_AXI_CFG = 0x00000108,
+	VFE_AXI_STATUS = 0x0000010C,
+	CAMIF_COMMAND = 0x00000110,
+	CAMIF_CONFIG = 0x00000114,
+	CAMIF_EFS_CONFIG = 0x00000118,
+	CAMIF_FRAME_CONFIG = 0x0000011C,
+	CAMIF_WINDOW_WIDTH_CONFIG = 0x00000120,
+	CAMIF_WINDOW_HEIGHT_CONFIG = 0x00000124,
+	CAMIF_SUBSAMPLE1_CONFIG = 0x00000128,
+	CAMIF_SUBSAMPLE2_CONFIG = 0x0000012C,
+	CAMIF_EPOCH_IRQ = 0x00000130,
+	CAMIF_STATUS = 0x00000134,
+	CAMIF_MISR = 0x00000138,
+	VFE_SYNC_TIMER_CMD = 0x0000013C,
+	VFE_SYNC_TIMER0_LINE_START = 0x00000140,
+	VFE_SYNC_TIMER0_PIXEL_START = 0x00000144,
+	VFE_SYNC_TIMER0_PIXEL_DURATION = 0x00000148,
+	VFE_SYNC_TIMER1_LINE_START = 0x0000014C,
+	VFE_SYNC_TIMER1_PIXEL_START = 0x00000150,
+	VFE_SYNC_TIMER1_PIXEL_DURATION = 0x00000154,
+	VFE_SYNC_TIMER2_LINE_START = 0x00000158,
+	VFE_SYNC_TIMER2_PIXEL_START = 0x0000015C,
+	VFE_SYNC_TIMER2_PIXEL_DURATION = 0x00000160,
+	VFE_SYNC_TIMER_POLARITY = 0x00000164,
+	VFE_ASYNC_TIMER_CMD = 0x00000168,
+	VFE_ASYNC_TIMER0_CFG_0 = 0x0000016C,
+	VFE_ASYNC_TIMER0_CFG_1 = 0x00000170,
+	VFE_ASYNC_TIMER1_CFG_0 = 0x00000174,
+	VFE_ASYNC_TIMER1_CFG_1 = 0x00000178,
+	VFE_ASYNC_TIMER2_CFG_0 = 0x0000017C,
+	VFE_ASYNC_TIMER2_CFG_1 = 0x00000180,
+	VFE_ASYNC_TIMER3_CFG_0 = 0x00000184,
+	VFE_ASYNC_TIMER3_CFG_1 = 0x00000188,
+	VFE_TIMER_SEL = 0x0000018C,
+	VFE_REG_UPDATE_CMD = 0x00000190,
+	VFE_BLACK_EVEN_EVEN_VALUE = 0x00000194,
+	VFE_BLACK_EVEN_ODD_VALUE = 0x00000198,
+	VFE_BLACK_ODD_EVEN_VALUE = 0x0000019C,
+	VFE_BLACK_ODD_ODD_VALUE = 0x000001A0,
+	VFE_ROLLOFF_CFG_0 = 0x000001A4,
+	VFE_ROLLOFF_CFG_1 = 0x000001A8,
+	VFE_ROLLOFF_CFG_2 = 0x000001AC,
+	VFE_DEMUX_CFG = 0x000001B0,
+	VFE_DEMUX_GAIN_0 = 0x000001B4,
+	VFE_DEMUX_GAIN_1 = 0x000001B8,
+	VFE_DEMUX_EVEN_CFG = 0x000001BC,
+	VFE_DEMUX_ODD_CFG = 0x000001C0,
+	VFE_DEMOSAIC_CFG = 0x000001C4,
+	VFE_DEMOSAIC_ABF_CFG_0 = 0x000001C8,
+	VFE_DEMOSAIC_ABF_CFG_1 = 0x000001CC,
+	VFE_DEMOSAIC_BPC_CFG_0 = 0x000001D0,
+	VFE_DEMOSAIC_BPC_CFG_1 = 0x000001D4,
+	VFE_DEMOSAIC_STATUS = 0x000001D8,
+	VFE_CHROMA_UPSAMPLE_CFG = 0x000001DC,
+	VFE_CROP_WIDTH_CFG = 0x000001E0,
+	VFE_CROP_HEIGHT_CFG = 0x000001E4,
+	VFE_COLOR_CORRECT_COEFF_0 = 0x000001E8,
+	VFE_COLOR_CORRECT_COEFF_1 = 0x000001EC,
+	VFE_COLOR_CORRECT_COEFF_2 = 0x000001F0,
+	VFE_COLOR_CORRECT_COEFF_3 = 0x000001F4,
+	VFE_COLOR_CORRECT_COEFF_4 = 0x000001F8,
+	VFE_COLOR_CORRECT_COEFF_5 = 0x000001FC,
+	VFE_COLOR_CORRECT_COEFF_6 = 0x00000200,
+	VFE_COLOR_CORRECT_COEFF_7 = 0x00000204,
+	VFE_COLOR_CORRECT_COEFF_8 = 0x00000208,
+	VFE_COLOR_CORRECT_OFFSET_0 = 0x0000020C,
+	VFE_COLOR_CORRECT_OFFSET_1 = 0x00000210,
+	VFE_COLOR_CORRECT_OFFSET_2 = 0x00000214,
+	VFE_COLOR_CORRECT_COEFF_Q = 0x00000218,
+	VFE_LA_CFG = 0x0000021C,
+	VFE_LUT_BANK_SEL = 0x00000220,
+	VFE_CHROMA_ENHAN_A = 0x00000224,
+	VFE_CHROMA_ENHAN_B = 0x00000228,
+	VFE_CHROMA_ENHAN_C = 0x0000022C,
+	VFE_CHROMA_ENHAN_D = 0x00000230,
+	VFE_CHROMA_ENHAN_K = 0x00000234,
+	VFE_COLOR_CONVERT_COEFF_0 = 0x00000238,
+	VFE_COLOR_CONVERT_COEFF_1 = 0x0000023C,
+	VFE_COLOR_CONVERT_COEFF_2 = 0x00000240,
+	VFE_COLOR_CONVERT_OFFSET = 0x00000244,
+	VFE_ASF_CFG = 0x00000248,
+	VFE_ASF_SHARP_CFG_0 = 0x0000024C,
+	VFE_ASF_SHARP_CFG_1 = 0x00000250,
+	VFE_ASF_SHARP_COEFF_0 = 0x00000254,
+	VFE_ASF_SHARP_COEFF_1 = 0x00000258,
+	VFE_ASF_SHARP_COEFF_2 = 0x0000025C,
+	VFE_ASF_SHARP_COEFF_3 = 0x00000260,
+	VFE_ASF_MAX_EDGE = 0x00000264,
+	VFE_ASF_CROP_WIDTH_CFG = 0x00000268,
+	VFE_ASF_CROP_HEIGHT_CFG = 0x0000026C,
+	VFE_SCALE_CFG = 0x00000270,
+	VFE_SCALE_H_IMAGE_SIZE_CFG = 0x00000274,
+	VFE_SCALE_H_PHASE_CFG = 0x00000278,
+	VFE_SCALE_H_STRIPE_CFG = 0x0000027C,
+	VFE_SCALE_V_IMAGE_SIZE_CFG = 0x00000280,
+	VFE_SCALE_V_PHASE_CFG = 0x00000284,
+	VFE_SCALE_V_STRIPE_CFG = 0x00000288,
+	VFE_SCALE_Y_CFG = 0x0000028C,
+	VFE_SCALE_Y_H_IMAGE_SIZE_CFG = 0x00000290,
+	VFE_SCALE_Y_H_PHASE_CFG = 0x00000294,
+	VFE_SCALE_Y_V_IMAGE_SIZE_CFG = 0x00000298,
+	VFE_SCALE_Y_V_PHASE_CFG = 0x0000029C,
+	VFE_SCALE_CBCR_CFG = 0x000002A0,
+	VFE_SCALE_CBCR_H_IMAGE_SIZE_CFG = 0x000002A4,
+	VFE_SCALE_CBCR_H_PHASE_CFG = 0x000002A8,
+	VFE_SCALE_CBCR_V_IMAGE_SIZE_CFG = 0x000002AC,
+	VFE_SCALE_CBCR_V_PHASE_CFG = 0x000002B0,
+	VFE_WB_CFG = 0x000002B4,
+	VFE_CHROMA_SUPPRESS_CFG_0 = 0x000002B8,
+	VFE_CHROMA_SUPPRESS_CFG_1 = 0x000002BC,
+	VFE_CHROMA_SUBSAMPLE_CFG = 0x000002C0,
+	VFE_CHROMA_SUB_CROP_WIDTH_CFG = 0x000002C4,
+	VFE_CHROMA_SUB_CROP_HEIGHT_CFG = 0x000002C8,
+	VFE_FRAMEDROP_ENC_Y_CFG = 0x000002CC,
+	VFE_FRAMEDROP_ENC_CBCR_CFG = 0x000002D0,
+	VFE_FRAMEDROP_ENC_Y_PATTERN = 0x000002D4,
+	VFE_FRAMEDROP_ENC_CBCR_PATTERN = 0x000002D8,
+	VFE_FRAMEDROP_VIEW_Y_CFG = 0x000002DC,
+	VFE_FRAMEDROP_VIEW_CBCR_CFG = 0x000002E0,
+	VFE_FRAMEDROP_VIEW_Y_PATTERN = 0x000002E4,
+	VFE_FRAMEDROP_VIEW_CBCR_PATTERN = 0x000002E8,
+	VFE_CLAMP_MAX_CFG = 0x000002EC,
+	VFE_CLAMP_MIN_CFG = 0x000002F0,
+	VFE_STATS_CMD = 0x000002F4,
+	VFE_STATS_AF_CFG = 0x000002F8,
+	VFE_STATS_AF_DIM = 0x000002FC,
+	VFE_STATS_AF_GRID_0 = 0x00000300,
+	VFE_STATS_AF_GRID_1 = 0x00000304,
+	VFE_STATS_AF_GRID_2 = 0x00000308,
+	VFE_STATS_AF_GRID_3 = 0x0000030C,
+	VFE_STATS_AF_HEADER = 0x00000310,
+	VFE_STATS_AF_COEF0 = 0x00000314,
+	VFE_STATS_AF_COEF1 = 0x00000318,
+	VFE_STATS_AWBAE_CFG = 0x0000031C,
+	VFE_STATS_AXW_HEADER = 0x00000320,
+	VFE_STATS_AWB_MCFG = 0x00000324,
+	VFE_STATS_AWB_CCFG1 = 0x00000328,
+	VFE_STATS_AWB_CCFG2 = 0x0000032C,
+	VFE_STATS_HIST_HEADER = 0x00000330,
+	VFE_STATS_HIST_INNER_OFFSET = 0x00000334,
+	VFE_STATS_HIST_INNER_DIM = 0x00000338,
+	VFE_STATS_FRAME_SIZE = 0x0000033C,
+	VFE_DMI_CFG = 0x00000340,
+	VFE_DMI_ADDR = 0x00000344,
+	VFE_DMI_DATA_HI = 0x00000348,
+	VFE_DMI_DATA_LO = 0x0000034C,
+	VFE_DMI_RAM_AUTO_LOAD_CMD = 0x00000350,
+	VFE_DMI_RAM_AUTO_LOAD_STATUS = 0x00000354,
+	VFE_DMI_RAM_AUTO_LOAD_CFG = 0x00000358,
+	VFE_DMI_RAM_AUTO_LOAD_SEED = 0x0000035C,
+	VFE_TESTBUS_SEL = 0x00000360,
+	VFE_TESTGEN_CFG = 0x00000364,
+	VFE_SW_TESTGEN_CMD = 0x00000368,
+	VFE_HW_TESTGEN_CMD = 0x0000036C,
+	VFE_HW_TESTGEN_CFG = 0x00000370,
+	VFE_HW_TESTGEN_IMAGE_CFG = 0x00000374,
+	VFE_HW_TESTGEN_SOF_OFFSET_CFG = 0x00000378,
+	VFE_HW_TESTGEN_EOF_NOFFSET_CFG = 0x0000037C,
+	VFE_HW_TESTGEN_SOL_OFFSET_CFG = 0x00000380,
+	VFE_HW_TESTGEN_EOL_NOFFSET_CFG = 0x00000384,
+	VFE_HW_TESTGEN_HBI_CFG = 0x00000388,
+	VFE_HW_TESTGEN_VBL_CFG = 0x0000038C,
+	VFE_HW_TESTGEN_SOF_DUMMY_LINE_CFG2 = 0x00000390,
+	VFE_HW_TESTGEN_EOF_DUMMY_LINE_CFG2 = 0x00000394,
+	VFE_HW_TESTGEN_COLOR_BARS_CFG = 0x00000398,
+	VFE_HW_TESTGEN_RANDOM_CFG = 0x0000039C,
+	VFE_SPARE = 0x000003A0,
+};
+
+#define ping 0x0
+#define pong 0x1
+
+struct vfe_bus_cfg_data {
+	boolean stripeRdPathEn;
+	boolean encYWrPathEn;
+	boolean encCbcrWrPathEn;
+	boolean viewYWrPathEn;
+	boolean viewCbcrWrPathEn;
+	enum VFE_RAW_PIXEL_DATA_SIZE rawPixelDataSize;
+	enum VFE_RAW_WR_PATH_SEL rawWritePathSelect;
+};
+
+struct vfe_camif_cfg_data {
+	boolean camif2OutputEnable;
+	boolean camif2BusEnable;
+	struct vfe_cmds_camif_cfg camifCfgFromCmd;
+};
+
+struct vfe_irq_composite_mask_config {
+	uint8_t encIrqComMask;
+	uint8_t viewIrqComMask;
+	uint8_t ceDoneSel;
+};
+
+/* define a structure for each output path.*/
+struct vfe_output_path {
+	uint32_t addressBuffer[8];
+	uint16_t fragIndex;
+	boolean hwCurrentFlag;
+	uint8_t *hwRegPingAddress;
+	uint8_t *hwRegPongAddress;
+};
+
+struct vfe_output_path_combo {
+	boolean whichOutputPath;
+	boolean pathEnabled;
+	boolean multiFrag;
+	uint8_t fragCount;
+	boolean ackPending;
+	uint8_t currentFrame;
+	uint32_t nextFrameAddrBuf[8];
+	struct vfe_output_path yPath;
+	struct vfe_output_path cbcrPath;
+	uint8_t snapshotPendingCount;
+	boolean pmEnabled;
+	uint8_t cbcrStatusBit;
+};
+
+struct vfe_stats_control {
+	boolean ackPending;
+	uint32_t addressBuffer[2];
+	uint32_t nextFrameAddrBuf;
+	boolean pingPongStatus;
+	uint8_t *hwRegPingAddress;
+	uint8_t *hwRegPongAddress;
+	uint32_t droppedStatsFrameCount;
+	uint32_t bufToRender;
+};
+
+struct vfe_gamma_lut_sel {
+	boolean ch0BankSelect;
+	boolean ch1BankSelect;
+	boolean ch2BankSelect;
+};
+
+struct vfe_interrupt_mask {
+	boolean camifErrorIrq;
+	boolean camifSofIrq;
+	boolean camifEolIrq;
+	boolean camifEofIrq;
+	boolean camifEpoch1Irq;
+	boolean camifEpoch2Irq;
+	boolean camifOverflowIrq;
+	boolean ceIrq;
+	boolean regUpdateIrq;
+	boolean resetAckIrq;
+	boolean encYPingpongIrq;
+	boolean encCbcrPingpongIrq;
+	boolean viewYPingpongIrq;
+	boolean viewCbcrPingpongIrq;
+	boolean rdPingpongIrq;
+	boolean afPingpongIrq;
+	boolean awbPingpongIrq;
+	boolean histPingpongIrq;
+	boolean encIrq;
+	boolean viewIrq;
+	boolean busOverflowIrq;
+	boolean afOverflowIrq;
+	boolean awbOverflowIrq;
+	boolean syncTimer0Irq;
+	boolean syncTimer1Irq;
+	boolean syncTimer2Irq;
+	boolean asyncTimer0Irq;
+	boolean asyncTimer1Irq;
+	boolean asyncTimer2Irq;
+	boolean asyncTimer3Irq;
+	boolean axiErrorIrq;
+	boolean violationIrq;
+};
+
+enum vfe_interrupt_name {
+	CAMIF_ERROR_IRQ,
+	CAMIF_SOF_IRQ,
+	CAMIF_EOL_IRQ,
+	CAMIF_EOF_IRQ,
+	CAMIF_EPOCH1_IRQ,
+	CAMIF_EPOCH2_IRQ,
+	CAMIF_OVERFLOW_IRQ,
+	CE_IRQ,
+	REG_UPDATE_IRQ,
+	RESET_ACK_IRQ,
+	ENC_Y_PINGPONG_IRQ,
+	ENC_CBCR_PINGPONG_IRQ,
+	VIEW_Y_PINGPONG_IRQ,
+	VIEW_CBCR_PINGPONG_IRQ,
+	RD_PINGPONG_IRQ,
+	AF_PINGPONG_IRQ,
+	AWB_PINGPONG_IRQ,
+	HIST_PINGPONG_IRQ,
+	ENC_IRQ,
+	VIEW_IRQ,
+	BUS_OVERFLOW_IRQ,
+	AF_OVERFLOW_IRQ,
+	AWB_OVERFLOW_IRQ,
+	SYNC_TIMER0_IRQ,
+	SYNC_TIMER1_IRQ,
+	SYNC_TIMER2_IRQ,
+	ASYNC_TIMER0_IRQ,
+	ASYNC_TIMER1_IRQ,
+	ASYNC_TIMER2_IRQ,
+	ASYNC_TIMER3_IRQ,
+	AXI_ERROR_IRQ,
+	VIOLATION_IRQ
+};
+
+enum VFE_DMI_RAM_SEL {
+	NO_MEM_SELECTED = 0,
+	ROLLOFF_RAM = 0x1,
+	RGBLUT_RAM_CH0_BANK0 = 0x2,
+	RGBLUT_RAM_CH0_BANK1 = 0x3,
+	RGBLUT_RAM_CH1_BANK0 = 0x4,
+	RGBLUT_RAM_CH1_BANK1 = 0x5,
+	RGBLUT_RAM_CH2_BANK0 = 0x6,
+	RGBLUT_RAM_CH2_BANK1 = 0x7,
+	STATS_HIST_CB_EVEN_RAM = 0x8,
+	STATS_HIST_CB_ODD_RAM = 0x9,
+	STATS_HIST_CR_EVEN_RAM = 0xa,
+	STATS_HIST_CR_ODD_RAM = 0xb,
+	RGBLUT_CHX_BANK0 = 0xc,
+	RGBLUT_CHX_BANK1 = 0xd,
+	LUMA_ADAPT_LUT_RAM_BANK0 = 0xe,
+	LUMA_ADAPT_LUT_RAM_BANK1 = 0xf
+};
+
+struct vfe_module_enable {
+	boolean blackLevelCorrectionEnable;
+	boolean lensRollOffEnable;
+	boolean demuxEnable;
+	boolean chromaUpsampleEnable;
+	boolean demosaicEnable;
+	boolean statsEnable;
+	boolean cropEnable;
+	boolean mainScalerEnable;
+	boolean whiteBalanceEnable;
+	boolean colorCorrectionEnable;
+	boolean yHistEnable;
+	boolean skinToneEnable;
+	boolean lumaAdaptationEnable;
+	boolean rgbLUTEnable;
+	boolean chromaEnhanEnable;
+	boolean asfEnable;
+	boolean chromaSuppressionEnable;
+	boolean chromaSubsampleEnable;
+	boolean scaler2YEnable;
+	boolean scaler2CbcrEnable;
+};
+
+struct vfe_bus_cmd_data {
+	boolean stripeReload;
+	boolean busPingpongReload;
+	boolean statsPingpongReload;
+};
+
+struct vfe_stats_cmd_data {
+	boolean autoFocusEnable;
+	boolean axwEnable;
+	boolean histEnable;
+	boolean clearHistEnable;
+	boolean histAutoClearEnable;
+	boolean colorConversionEnable;
+};
+
+struct vfe_hw_ver {
+	uint32_t minorVersion:8;
+	uint32_t majorVersion:8;
+	uint32_t coreVersion:4;
+	 uint32_t /* reserved */ : 12;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_cfg {
+	uint32_t pixelPattern:3;
+	 uint32_t /* reserved */ : 13;
+	uint32_t inputSource:2;
+	 uint32_t /* reserved */ : 14;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_buscmd {
+	uint32_t stripeReload:1;
+	 uint32_t /* reserved */ : 3;
+	uint32_t busPingpongReload:1;
+	uint32_t statsPingpongReload:1;
+	 uint32_t /* reserved */ : 26;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_Irq_Composite_MaskType {
+	uint32_t encIrqComMaskBits:2;
+	uint32_t viewIrqComMaskBits:2;
+	uint32_t ceDoneSelBits:5;
+	 uint32_t /* reserved */ : 23;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_mod_enable {
+	uint32_t blackLevelCorrectionEnable:1;
+	uint32_t lensRollOffEnable:1;
+	uint32_t demuxEnable:1;
+	uint32_t chromaUpsampleEnable:1;
+	uint32_t demosaicEnable:1;
+	uint32_t statsEnable:1;
+	uint32_t cropEnable:1;
+	uint32_t mainScalerEnable:1;
+	uint32_t whiteBalanceEnable:1;
+	uint32_t colorCorrectionEnable:1;
+	uint32_t yHistEnable:1;
+	uint32_t skinToneEnable:1;
+	uint32_t lumaAdaptationEnable:1;
+	uint32_t rgbLUTEnable:1;
+	uint32_t chromaEnhanEnable:1;
+	uint32_t asfEnable:1;
+	uint32_t chromaSuppressionEnable:1;
+	uint32_t chromaSubsampleEnable:1;
+	uint32_t scaler2YEnable:1;
+	uint32_t scaler2CbcrEnable:1;
+	 uint32_t /* reserved */ : 14;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_irqenable {
+	uint32_t camifErrorIrq:1;
+	uint32_t camifSofIrq:1;
+	uint32_t camifEolIrq:1;
+	uint32_t camifEofIrq:1;
+	uint32_t camifEpoch1Irq:1;
+	uint32_t camifEpoch2Irq:1;
+	uint32_t camifOverflowIrq:1;
+	uint32_t ceIrq:1;
+	uint32_t regUpdateIrq:1;
+	uint32_t resetAckIrq:1;
+	uint32_t encYPingpongIrq:1;
+	uint32_t encCbcrPingpongIrq:1;
+	uint32_t viewYPingpongIrq:1;
+	uint32_t viewCbcrPingpongIrq:1;
+	uint32_t rdPingpongIrq:1;
+	uint32_t afPingpongIrq:1;
+	uint32_t awbPingpongIrq:1;
+	uint32_t histPingpongIrq:1;
+	uint32_t encIrq:1;
+	uint32_t viewIrq:1;
+	uint32_t busOverflowIrq:1;
+	uint32_t afOverflowIrq:1;
+	uint32_t awbOverflowIrq:1;
+	uint32_t syncTimer0Irq:1;
+	uint32_t syncTimer1Irq:1;
+	uint32_t syncTimer2Irq:1;
+	uint32_t asyncTimer0Irq:1;
+	uint32_t asyncTimer1Irq:1;
+	uint32_t asyncTimer2Irq:1;
+	uint32_t asyncTimer3Irq:1;
+	uint32_t axiErrorIrq:1;
+	uint32_t violationIrq:1;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_upsample_cfg {
+	uint32_t chromaCositingForYCbCrInputs:1;
+	 uint32_t /* reserved */ : 31;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_CAMIFConfigType {
+	/* CAMIF Config */
+	uint32_t /* reserved */ : 1;
+	uint32_t VSyncEdge:1;
+	uint32_t HSyncEdge:1;
+	uint32_t syncMode:2;
+	uint32_t vfeSubsampleEnable:1;
+	 uint32_t /* reserved */ : 1;
+	uint32_t busSubsampleEnable:1;
+	uint32_t camif2vfeEnable:1;
+	 uint32_t /* reserved */ : 1;
+	uint32_t camif2busEnable:1;
+	uint32_t irqSubsampleEnable:1;
+	uint32_t binningEnable:1;
+	 uint32_t /* reserved */ : 18;
+	uint32_t misrEnable:1;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_camifcfg {
+	/* EFS_Config */
+	uint32_t efsEndOfLine:8;
+	uint32_t efsStartOfLine:8;
+	uint32_t efsEndOfFrame:8;
+	uint32_t efsStartOfFrame:8;
+	/* Frame Config */
+	uint32_t frameConfigPixelsPerLine:14;
+	 uint32_t /* reserved */ : 2;
+	uint32_t frameConfigLinesPerFrame:14;
+	 uint32_t /* reserved */ : 2;
+	/* Window Width Config */
+	uint32_t windowWidthCfgLastPixel:14;
+	 uint32_t /* reserved */ : 2;
+	uint32_t windowWidthCfgFirstPixel:14;
+	 uint32_t /* reserved */ : 2;
+	/* Window Height Config */
+	uint32_t windowHeightCfglastLine:14;
+	 uint32_t /* reserved */ : 2;
+	uint32_t windowHeightCfgfirstLine:14;
+	 uint32_t /* reserved */ : 2;
+	/* Subsample 1 Config */
+	uint32_t subsample1CfgPixelSkip:16;
+	uint32_t subsample1CfgLineSkip:16;
+	/* Subsample 2 Config */
+	uint32_t subsample2CfgFrameSkip:4;
+	uint32_t subsample2CfgFrameSkipMode:1;
+	uint32_t subsample2CfgPixelSkipWrap:1;
+	 uint32_t /* reserved */ : 26;
+	/* Epoch Interrupt */
+	uint32_t epoch1Line:14;
+	 uint32_t /* reserved */ : 2;
+	uint32_t epoch2Line:14;
+	 uint32_t /* reserved */ : 2;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_epoch1cfg {
+	/* Epoch Interrupt */
+	uint32_t epoch1Line:14;
+	uint32_t /* reserved */ : 2;
+} __attribute__ ((packed, aligned(4)));
+
+
+struct vfe_camifframe_update {
+	uint32_t pixelsPerLine:14;
+	 uint32_t /* reserved */ : 2;
+	uint32_t linesPerFrame:14;
+	 uint32_t /* reserved */ : 2;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_axi_bus_cfg {
+	uint32_t stripeRdPathEn:1;
+	 uint32_t /* reserved */ : 3;
+	uint32_t encYWrPathEn:1;
+	uint32_t encCbcrWrPathEn:1;
+	uint32_t viewYWrPathEn:1;
+	uint32_t viewCbcrWrPathEn:1;
+	uint32_t rawPixelDataSize:2;
+	uint32_t rawWritePathSelect:2;
+	 uint32_t /* reserved */ : 20;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_axi_out_cfg {
+	uint32_t out2YPingAddr:32;
+	uint32_t out2YPongAddr:32;
+	uint32_t out2YImageHeight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out2YImageWidthin64bit:10;
+	 uint32_t /* reserved */ : 6;
+	uint32_t out2YBurstLength:2;
+	 uint32_t /* reserved */ : 2;
+	uint32_t out2YNumRows:12;
+	uint32_t out2YRowIncrementIn64bit:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out2CbcrPingAddr:32;
+	uint32_t out2CbcrPongAddr:32;
+	uint32_t out2CbcrImageHeight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out2CbcrImageWidthIn64bit:10;
+	 uint32_t /* reserved */ : 6;
+	uint32_t out2CbcrBurstLength:2;
+	 uint32_t /* reserved */ : 2;
+	uint32_t out2CbcrNumRows:12;
+	uint32_t out2CbcrRowIncrementIn64bit:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out1YPingAddr:32;
+	uint32_t out1YPongAddr:32;
+	uint32_t out1YImageHeight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out1YImageWidthin64bit:10;
+	 uint32_t /* reserved */ : 6;
+	uint32_t out1YBurstLength:2;
+	 uint32_t /* reserved */ : 2;
+	uint32_t out1YNumRows:12;
+	uint32_t out1YRowIncrementIn64bit:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out1CbcrPingAddr:32;
+	uint32_t out1CbcrPongAddr:32;
+	uint32_t out1CbcrImageHeight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t out1CbcrImageWidthIn64bit:10;
+	 uint32_t /* reserved */ : 6;
+	uint32_t out1CbcrBurstLength:2;
+	 uint32_t /* reserved */ : 2;
+	uint32_t out1CbcrNumRows:12;
+	uint32_t out1CbcrRowIncrementIn64bit:12;
+	 uint32_t /* reserved */ : 4;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_output_clamp_cfg {
+	/* Output Clamp Maximums */
+	uint32_t yChanMax:8;
+	uint32_t cbChanMax:8;
+	uint32_t crChanMax:8;
+	 uint32_t /* reserved */ : 8;
+	/* Output Clamp Minimums */
+	uint32_t yChanMin:8;
+	uint32_t cbChanMin:8;
+	uint32_t crChanMin:8;
+	 uint32_t /* reserved */ : 8;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_fov_crop_cfg {
+	uint32_t lastPixel:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t firstPixel:12;
+	 uint32_t /* reserved */ : 4;
+
+	/* FOV Corp, Part 2 */
+	uint32_t lastLine:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t firstLine:12;
+	 uint32_t /* reserved */ : 4;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_FRAME_SKIP_UpdateCmdType {
+	uint32_t yPattern:32;
+	uint32_t cbcrPattern:32;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_frame_skip_cfg {
+	/* Frame Drop Enc (output2) */
+	uint32_t output2YPeriod:5;
+	 uint32_t /* reserved */ : 27;
+	uint32_t output2CbCrPeriod:5;
+	 uint32_t /* reserved */ : 27;
+	uint32_t output2YPattern:32;
+	uint32_t output2CbCrPattern:32;
+	/* Frame Drop View (output1) */
+	uint32_t output1YPeriod:5;
+	 uint32_t /* reserved */ : 27;
+	uint32_t output1CbCrPeriod:5;
+	 uint32_t /* reserved */ : 27;
+	uint32_t output1YPattern:32;
+	uint32_t output1CbCrPattern:32;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_main_scaler_cfg {
+	/* Scaler Enable Config */
+	uint32_t hEnable:1;
+	uint32_t vEnable:1;
+	 uint32_t /* reserved */ : 30;
+	/* Scale H Image Size Config */
+	uint32_t inWidth:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t outWidth:12;
+	 uint32_t /* reserved */ : 4;
+	/* Scale H Phase Config */
+	uint32_t horizPhaseMult:18;
+	 uint32_t /* reserved */ : 2;
+	uint32_t horizInterResolution:2;
+	 uint32_t /* reserved */ : 10;
+	/* Scale H Stripe Config */
+	uint32_t horizMNInit:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t horizPhaseInit:15;
+	 uint32_t /* reserved */ : 1;
+	/* Scale V Image Size Config */
+	uint32_t inHeight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t outHeight:12;
+	 uint32_t /* reserved */ : 4;
+	/* Scale V Phase Config */
+	uint32_t vertPhaseMult:18;
+	 uint32_t /* reserved */ : 2;
+	uint32_t vertInterResolution:2;
+	 uint32_t /* reserved */ : 10;
+	/* Scale V Stripe Config */
+	uint32_t vertMNInit:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t vertPhaseInit:15;
+	 uint32_t /* reserved */ : 1;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_scaler2_cfg {
+	/* Scaler   Enable Config */
+	uint32_t hEnable:1;
+	uint32_t vEnable:1;
+	 uint32_t /* reserved */ : 30;
+	/* Scaler   H Image Size Config */
+	uint32_t inWidth:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t outWidth:12;
+	 uint32_t /* reserved */ : 4;
+	/* Scaler   H Phase Config */
+	uint32_t horizPhaseMult:18;
+	 uint32_t /* reserved */ : 2;
+	uint32_t horizInterResolution:2;
+	 uint32_t /* reserved */ : 10;
+	/* Scaler   V Image Size Config */
+	uint32_t inHeight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t outHeight:12;
+	 uint32_t /* reserved */ : 4;
+	/* Scaler   V Phase Config */
+	uint32_t vertPhaseMult:18;
+	 uint32_t /* reserved */ : 2;
+	uint32_t vertInterResolution:2;
+	 uint32_t /* reserved */ : 10;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_rolloff_cfg {
+	/* Rolloff 0 Config */
+	uint32_t gridWidth:9;
+	uint32_t gridHeight:9;
+	uint32_t yDelta:9;
+	 uint32_t /* reserved */ : 5;
+	/* Rolloff 1 Config */
+	uint32_t gridX:4;
+	uint32_t gridY:4;
+	uint32_t pixelX:9;
+	 uint32_t /* reserved */ : 3;
+	uint32_t pixelY:9;
+	 uint32_t /* reserved */ : 3;
+	/* Rolloff 2 Config */
+	uint32_t yDeltaAccum:12;
+	 uint32_t /* reserved */ : 20;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_asf_update {
+	/* ASF Config Command */
+	uint32_t smoothEnable:1;
+	uint32_t sharpMode:2;
+	 uint32_t /* reserved */ : 1;
+	uint32_t smoothCoeff1:4;
+	uint32_t smoothCoeff0:8;
+	uint32_t pipeFlushCount:12;
+	uint32_t pipeFlushOvd:1;
+	uint32_t flushHaltOvd:1;
+	uint32_t cropEnable:1;
+	 uint32_t /* reserved */ : 1;
+	/* Sharpening Config 0 */
+	uint32_t sharpThresholdE1:7;
+	 uint32_t /* reserved */ : 1;
+	uint32_t sharpDegreeK1:5;
+	 uint32_t /* reserved */ : 3;
+	uint32_t sharpDegreeK2:5;
+	 uint32_t /* reserved */ : 3;
+	uint32_t normalizeFactor:7;
+	 uint32_t /* reserved */ : 1;
+	/* Sharpening Config 1 */
+	uint32_t sharpThresholdE2:8;
+	uint32_t sharpThresholdE3:8;
+	uint32_t sharpThresholdE4:8;
+	uint32_t sharpThresholdE5:8;
+	/* Sharpening Coefficients 0 */
+	uint32_t F1Coeff0:6;
+	uint32_t F1Coeff1:6;
+	uint32_t F1Coeff2:6;
+	uint32_t F1Coeff3:6;
+	uint32_t F1Coeff4:6;
+	 uint32_t /* reserved */ : 2;
+	/* Sharpening Coefficients 1 */
+	uint32_t F1Coeff5:6;
+	uint32_t F1Coeff6:6;
+	uint32_t F1Coeff7:6;
+	uint32_t F1Coeff8:7;
+	 uint32_t /* reserved */ : 7;
+	/* Sharpening Coefficients 2 */
+	uint32_t F2Coeff0:6;
+	uint32_t F2Coeff1:6;
+	uint32_t F2Coeff2:6;
+	uint32_t F2Coeff3:6;
+	uint32_t F2Coeff4:6;
+	 uint32_t /* reserved */ : 2;
+	/* Sharpening Coefficients 3 */
+	uint32_t F2Coeff5:6;
+	uint32_t F2Coeff6:6;
+	uint32_t F2Coeff7:6;
+	uint32_t F2Coeff8:7;
+	 uint32_t /* reserved */ : 7;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_asfcrop_cfg {
+	/* ASF Crop Width Config */
+	uint32_t lastPixel:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t firstPixel:12;
+	 uint32_t /* reserved */ : 4;
+	/* ASP Crop Height Config */
+	uint32_t lastLine:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t firstLine:12;
+	 uint32_t /* reserved */ : 4;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_chroma_suppress_cfg {
+	/* Chroma Suppress 0 Config */
+	uint32_t m1:8;
+	uint32_t m3:8;
+	uint32_t n1:3;
+	 uint32_t /* reserved */ : 1;
+	uint32_t n3:3;
+	 uint32_t /* reserved */ : 9;
+	/* Chroma Suppress 1 Config */
+	uint32_t mm1:8;
+	uint32_t nn1:3;
+	 uint32_t /* reserved */ : 21;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_chromasubsample_cfg {
+	/* Chroma Subsample Selection */
+	uint32_t hCositedPhase:1;
+	uint32_t vCositedPhase:1;
+	uint32_t hCosited:1;
+	uint32_t vCosited:1;
+	uint32_t hsubSampleEnable:1;
+	uint32_t vsubSampleEnable:1;
+	uint32_t cropEnable:1;
+	 uint32_t /* reserved */ : 25;
+	uint32_t cropWidthLastPixel:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t cropWidthFirstPixel:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t cropHeightLastLine:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t cropHeightFirstLine:12;
+	 uint32_t /* reserved */ : 4;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_blacklevel_cfg {
+	/* Black Even-Even Value Config */
+	uint32_t evenEvenAdjustment:9;
+	 uint32_t /* reserved */ : 23;
+	/* Black Even-Odd Value Config */
+	uint32_t evenOddAdjustment:9;
+	 uint32_t /* reserved */ : 23;
+	/* Black Odd-Even Value Config */
+	uint32_t oddEvenAdjustment:9;
+	 uint32_t /* reserved */ : 23;
+	/* Black Odd-Odd Value Config */
+	uint32_t oddOddAdjustment:9;
+	 uint32_t /* reserved */ : 23;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_demux_cfg {
+	/* Demux Gain 0 Config */
+	uint32_t ch0EvenGain:10;
+	 uint32_t /* reserved */ : 6;
+	uint32_t ch0OddGain:10;
+	 uint32_t /* reserved */ : 6;
+	/* Demux Gain 1 Config */
+	uint32_t ch1Gain:10;
+	 uint32_t /* reserved */ : 6;
+	uint32_t ch2Gain:10;
+	 uint32_t /* reserved */ : 6;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_bps_info {
+	uint32_t greenBadPixelCount:8;
+	 uint32_t /* reserved */ : 8;
+	uint32_t RedBlueBadPixelCount:8;
+	 uint32_t /* reserved */ : 8;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_demosaic_cfg {
+	/* Demosaic Config */
+	uint32_t abfEnable:1;
+	uint32_t badPixelCorrEnable:1;
+	uint32_t forceAbfOn:1;
+	 uint32_t /* reserved */ : 1;
+	uint32_t abfShift:4;
+	uint32_t fminThreshold:7;
+	 uint32_t /* reserved */ : 1;
+	uint32_t fmaxThreshold:7;
+	 uint32_t /* reserved */ : 5;
+	uint32_t slopeShift:3;
+	 uint32_t /* reserved */ : 1;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_demosaic_bpc_cfg {
+	/* Demosaic BPC Config 0 */
+	uint32_t blueDiffThreshold:12;
+	uint32_t redDiffThreshold:12;
+	 uint32_t /* reserved */ : 8;
+	/* Demosaic BPC Config 1 */
+	uint32_t greenDiffThreshold:12;
+	 uint32_t /* reserved */ : 20;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_demosaic_abf_cfg {
+	/* Demosaic ABF Config 0 */
+	uint32_t lpThreshold:10;
+	 uint32_t /* reserved */ : 22;
+	/* Demosaic ABF Config 1 */
+	uint32_t ratio:4;
+	uint32_t minValue:10;
+	 uint32_t /* reserved */ : 2;
+	uint32_t maxValue:10;
+	 uint32_t /* reserved */ : 6;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_color_correction_cfg {
+	/* Color Corr. Coefficient 0 Config */
+	uint32_t c0:12;
+	 uint32_t /* reserved */ : 20;
+	/* Color Corr. Coefficient 1 Config */
+	uint32_t c1:12;
+	 uint32_t /* reserved */ : 20;
+	/* Color Corr. Coefficient 2 Config */
+	uint32_t c2:12;
+	 uint32_t /* reserved */ : 20;
+	/* Color Corr. Coefficient 3 Config */
+	uint32_t c3:12;
+	 uint32_t /* reserved */ : 20;
+	/* Color Corr. Coefficient 4 Config */
+	uint32_t c4:12;
+	 uint32_t /* reserved */ : 20;
+	/* Color Corr. Coefficient 5 Config */
+	uint32_t c5:12;
+	 uint32_t /* reserved */ : 20;
+	/* Color Corr. Coefficient 6 Config */
+	uint32_t c6:12;
+	 uint32_t /* reserved */ : 20;
+	/* Color Corr. Coefficient 7 Config */
+	uint32_t c7:12;
+	 uint32_t /* reserved */ : 20;
+	/* Color Corr. Coefficient 8 Config */
+	uint32_t c8:12;
+	 uint32_t /* reserved */ : 20;
+	/* Color Corr. Offset 0 Config */
+	uint32_t k0:11;
+	 uint32_t /* reserved */ : 21;
+	/* Color Corr. Offset 1 Config */
+	uint32_t k1:11;
+	 uint32_t /* reserved */ : 21;
+	/* Color Corr. Offset 2 Config */
+	uint32_t k2:11;
+	 uint32_t /* reserved */ : 21;
+	/* Color Corr. Coefficient Q Config */
+	uint32_t coefQFactor:2;
+	 uint32_t /* reserved */ : 30;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_LumaAdaptation_ConfigCmdType {
+	/* LA Config */
+	uint32_t lutBankSelect:1;
+	 uint32_t /* reserved */ : 31;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_wb_cfg {
+	/* WB Config */
+	uint32_t ch0Gain:9;
+	uint32_t ch1Gain:9;
+	uint32_t ch2Gain:9;
+	 uint32_t /* reserved */ : 5;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_GammaLutSelect_ConfigCmdType {
+	/* LUT Bank Select Config */
+	uint32_t ch0BankSelect:1;
+	uint32_t ch1BankSelect:1;
+	uint32_t ch2BankSelect:1;
+	 uint32_t /* reserved */ : 29;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_chroma_enhance_cfg {
+	/* Chroma Enhance A Config */
+	uint32_t ap:11;
+	 uint32_t /* reserved */ : 5;
+	uint32_t am:11;
+	 uint32_t /* reserved */ : 5;
+	/* Chroma Enhance B Config */
+	uint32_t bp:11;
+	 uint32_t /* reserved */ : 5;
+	uint32_t bm:11;
+	 uint32_t /* reserved */ : 5;
+	/* Chroma Enhance C Config */
+	uint32_t cp:11;
+	 uint32_t /* reserved */ : 5;
+	uint32_t cm:11;
+	 uint32_t /* reserved */ : 5;
+	/* Chroma Enhance D Config */
+	uint32_t dp:11;
+	 uint32_t /* reserved */ : 5;
+	uint32_t dm:11;
+	 uint32_t /* reserved */ : 5;
+	/* Chroma Enhance K Config */
+	uint32_t kcb:11;
+	 uint32_t /* reserved */ : 5;
+	uint32_t kcr:11;
+	 uint32_t /* reserved */ : 5;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_color_convert_cfg {
+	/* Conversion Coefficient 0 */
+	uint32_t v0:12;
+	 uint32_t /* reserved */ : 20;
+	/* Conversion Coefficient 1 */
+	uint32_t v1:12;
+	 uint32_t /* reserved */ : 20;
+	/* Conversion Coefficient 2 */
+	uint32_t v2:12;
+	 uint32_t /* reserved */ : 20;
+	/* Conversion Offset */
+	uint32_t ConvertOffset:8;
+	 uint32_t /* reserved */ : 24;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_SyncTimer_ConfigCmdType {
+	/* Timer Line Start Config */
+	uint32_t timerLineStart:12;
+	 uint32_t /* reserved */ : 20;
+	/* Timer Pixel Start Config */
+	uint32_t timerPixelStart:18;
+	 uint32_t /* reserved */ : 14;
+	/* Timer Pixel Duration Config */
+	uint32_t timerPixelDuration:28;
+	 uint32_t /* reserved */ : 4;
+	/* Sync Timer Polarity Config */
+	uint32_t timer0Polarity:1;
+	uint32_t timer1Polarity:1;
+	uint32_t timer2Polarity:1;
+	 uint32_t /* reserved */ : 29;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_AsyncTimer_ConfigCmdType {
+	/* Async Timer Config 0 */
+	uint32_t inactiveLength:20;
+	uint32_t numRepetition:10;
+	 uint32_t /* reserved */ : 1;
+	uint32_t polarity:1;
+	/* Async Timer Config 1 */
+	uint32_t activeLength:20;
+	 uint32_t /* reserved */ : 12;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_AWBAEStatistics_ConfigCmdType {
+	/* AWB autoexposure Config */
+	uint32_t aeRegionConfig:1;
+	uint32_t aeSubregionConfig:1;
+	 uint32_t /* reserved */ : 14;
+	uint32_t awbYMin:8;
+	uint32_t awbYMax:8;
+	/* AXW Header */
+	uint32_t axwHeader:8;
+	 uint32_t /* reserved */ : 24;
+	/* AWB Mconfig */
+	uint32_t m4:8;
+	uint32_t m3:8;
+	uint32_t m2:8;
+	uint32_t m1:8;
+	/* AWB Cconfig */
+	uint32_t c2:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t c1:12;
+	 uint32_t /* reserved */ : 4;
+	/* AWB Cconfig 2 */
+	uint32_t c4:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t c3:12;
+	 uint32_t /* reserved */ : 4;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_TestGen_ConfigCmdType {
+	/* HW Test Gen Config */
+	uint32_t numFrame:10;
+	 uint32_t /* reserved */ : 2;
+	uint32_t pixelDataSelect:1;
+	uint32_t systematicDataSelect:1;
+	 uint32_t /* reserved */ : 2;
+	uint32_t pixelDataSize:2;
+	uint32_t hsyncEdge:1;
+	uint32_t vsyncEdge:1;
+	 uint32_t /* reserved */ : 12;
+	/* HW Test Gen Image Config */
+	uint32_t imageWidth:14;
+	 uint32_t /* reserved */ : 2;
+	uint32_t imageHeight:14;
+	 uint32_t /* reserved */ : 2;
+	/* SOF Offset Config */
+	uint32_t sofOffset:24;
+	 uint32_t /* reserved */ : 8;
+	/* EOF NOffset Config */
+	uint32_t eofNOffset:24;
+	 uint32_t /* reserved */ : 8;
+	/* SOL Offset Config */
+	uint32_t solOffset:9;
+	 uint32_t /* reserved */ : 23;
+	/* EOL NOffset Config */
+	uint32_t eolNOffset:9;
+	 uint32_t /* reserved */ : 23;
+	/* HBI Config */
+	uint32_t hBlankInterval:14;
+	 uint32_t /* reserved */ : 18;
+	/* VBL Config */
+	uint32_t vBlankInterval:14;
+	 uint32_t /* reserved */ : 2;
+	uint32_t vBlankIntervalEnable:1;
+	 uint32_t /* reserved */ : 15;
+	/* SOF Dummy Line Config */
+	uint32_t sofDummy:8;
+	 uint32_t /* reserved */ : 24;
+	/* EOF Dummy Line Config */
+	uint32_t eofDummy:8;
+	 uint32_t /* reserved */ : 24;
+	/* Color Bars Config */
+	uint32_t unicolorBarSelect:3;
+	 uint32_t /* reserved */ : 1;
+	uint32_t unicolorBarEnable:1;
+	uint32_t splitEnable:1;
+	uint32_t pixelPattern:2;
+	uint32_t rotatePeriod:6;
+	 uint32_t /* reserved */ : 18;
+	/* Random Config */
+	uint32_t randomSeed:16;
+	 uint32_t /* reserved */ : 16;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_Bus_Pm_ConfigCmdType {
+	/* VFE Bus Performance Monitor Config */
+	uint32_t output2YWrPmEnable:1;
+	uint32_t output2CbcrWrPmEnable:1;
+	uint32_t output1YWrPmEnable:1;
+	uint32_t output1CbcrWrPmEnable:1;
+	 uint32_t /* reserved */ : 28;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_asf_info {
+	/* asf max edge  */
+	uint32_t maxEdge:13;
+	 uint32_t /* reserved */ : 3;
+	/* HBi count  */
+	uint32_t HBICount:12;
+	 uint32_t /* reserved */ : 4;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_camif_stats {
+	uint32_t pixelCount:14;
+	 uint32_t /* reserved */ : 2;
+	uint32_t lineCount:14;
+	 uint32_t /* reserved */ : 1;
+	uint32_t camifHalt:1;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_StatsCmdType {
+	uint32_t autoFocusEnable:1;
+	uint32_t axwEnable:1;
+	uint32_t histEnable:1;
+	uint32_t clearHistEnable:1;
+	uint32_t histAutoClearEnable:1;
+	uint32_t colorConversionEnable:1;
+	 uint32_t /* reserved */ : 26;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_statsframe {
+	uint32_t lastPixel:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t lastLine:12;
+	 uint32_t /* reserved */ : 4;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_busstats_wrprio {
+	uint32_t afBusPriority:4;
+	uint32_t awbBusPriority:4;
+	uint32_t histBusPriority:4;
+	uint32_t afBusPriorityEn:1;
+	uint32_t awbBusPriorityEn:1;
+	uint32_t histBusPriorityEn:1;
+	 uint32_t /* reserved */ : 17;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_statsaf_update {
+	/* VFE_STATS_AF_CFG */
+	uint32_t windowVOffset:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t windowHOffset:12;
+	 uint32_t /* reserved */ : 3;
+	uint32_t windowMode:1;
+
+	/* VFE_STATS_AF_DIM */
+	uint32_t windowHeight:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t windowWidth:12;
+	 uint32_t /* reserved */ : 4;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_statsaf_cfg {
+	/* VFE_STATS_AF_GRID_0 */
+	uint32_t entry00:8;
+	uint32_t entry01:8;
+	uint32_t entry02:8;
+	uint32_t entry03:8;
+
+	/* VFE_STATS_AF_GRID_1 */
+	uint32_t entry10:8;
+	uint32_t entry11:8;
+	uint32_t entry12:8;
+	uint32_t entry13:8;
+
+	/* VFE_STATS_AF_GRID_2 */
+	uint32_t entry20:8;
+	uint32_t entry21:8;
+	uint32_t entry22:8;
+	uint32_t entry23:8;
+
+	/* VFE_STATS_AF_GRID_3 */
+	uint32_t entry30:8;
+	uint32_t entry31:8;
+	uint32_t entry32:8;
+	uint32_t entry33:8;
+
+	/* VFE_STATS_AF_HEADER */
+	uint32_t afHeader:8;
+	 uint32_t /* reserved */ : 24;
+	/*  VFE_STATS_AF_COEF0 */
+	uint32_t a00:5;
+	uint32_t a04:5;
+	uint32_t fvMax:11;
+	uint32_t fvMetric:1;
+	 uint32_t /* reserved */ : 10;
+
+	/* VFE_STATS_AF_COEF1 */
+	uint32_t a20:5;
+	uint32_t a21:5;
+	uint32_t a22:5;
+	uint32_t a23:5;
+	uint32_t a24:5;
+	 uint32_t /* reserved */ : 7;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_statsawbae_update {
+	uint32_t aeRegionCfg:1;
+	uint32_t aeSubregionCfg:1;
+	 uint32_t /* reserved */ : 14;
+	uint32_t awbYMin:8;
+	uint32_t awbYMax:8;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_statsaxw_hdr_cfg {
+	/* Stats AXW Header Config */
+	uint32_t axwHeader:8;
+	 uint32_t /* reserved */ : 24;
+} __attribute__ ((packed, aligned(4)));
+
+struct vfe_statsawb_update {
+	/* AWB MConfig */
+	uint32_t m4:8;
+	uint32_t m3:8;
+	uint32_t m2:8;
+	uint32_t m1:8;
+
+	/* AWB CConfig1 */
+	uint32_t c2:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t c1:12;
+	 uint32_t /* reserved */ : 4;
+
+	/* AWB CConfig2 */
+	uint32_t c4:12;
+	 uint32_t /* reserved */ : 4;
+	uint32_t c3:12;
+	 uint32_t /* reserved */ : 4;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_SyncTimerCmdType {
+	uint32_t hsyncCount:12;
+	 uint32_t /* reserved */ : 20;
+	uint32_t pclkCount:18;
+	 uint32_t /* reserved */ : 14;
+	uint32_t outputDuration:28;
+	 uint32_t /* reserved */ : 4;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_AsyncTimerCmdType {
+	/*  config 0 */
+	uint32_t inactiveCount:20;
+	uint32_t repeatCount:10;
+	 uint32_t /* reserved */ : 1;
+	uint32_t polarity:1;
+	/*  config 1 */
+	uint32_t activeCount:20;
+	 uint32_t /* reserved */ : 12;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_AxiInputCmdType {
+	uint32_t stripeStartAddr0:32;
+	uint32_t stripeStartAddr1:32;
+	uint32_t stripeStartAddr2:32;
+	uint32_t stripeStartAddr3:32;
+
+	uint32_t ySize:12;
+	uint32_t yOffsetDelta:12;
+	 uint32_t /* reserved */ : 8;
+
+	/* bus_stripe_rd_hSize */
+	 uint32_t /* reserved */ : 16;
+	uint32_t xSizeWord:10;
+	 uint32_t /* reserved */ : 6;
+
+	/* bus_stripe_rd_buffer_cfg */
+	uint32_t burstLength:2;
+	 uint32_t /* reserved */ : 2;
+	uint32_t NumOfRows:12;
+	uint32_t RowIncrement:12;
+	 uint32_t /* reserved */ : 4;
+
+	/* bus_stripe_rd_unpack_cfg */
+	uint32_t mainUnpackHeight:12;
+	uint32_t mainUnpackWidth:13;
+	uint32_t mainUnpackHbiSel:3;
+	uint32_t mainUnpackPhase:3;
+	 uint32_t /* reserved */ : 1;
+
+	/* bus_stripe_rd_unpack */
+	uint32_t unpackPattern:32;
+
+	/* bus_stripe_rd_pad_size */
+	uint32_t padLeft:7;
+	 uint32_t /* reserved */ : 1;
+	uint32_t padRight:7;
+	 uint32_t /* reserved */ : 1;
+	uint32_t padTop:7;
+	 uint32_t /* reserved */ : 1;
+	uint32_t padBottom:7;
+	 uint32_t /* reserved */ : 1;
+
+	/* bus_stripe_rd_pad_L_unpack */
+	uint32_t leftUnpackPattern0:4;
+	uint32_t leftUnpackPattern1:4;
+	uint32_t leftUnpackPattern2:4;
+	uint32_t leftUnpackPattern3:4;
+	uint32_t leftUnpackStop0:1;
+	uint32_t leftUnpackStop1:1;
+	uint32_t leftUnpackStop2:1;
+	uint32_t leftUnpackStop3:1;
+	 uint32_t /* reserved */ : 12;
+
+	/* bus_stripe_rd_pad_R_unpack */
+	uint32_t rightUnpackPattern0:4;
+	uint32_t rightUnpackPattern1:4;
+	uint32_t rightUnpackPattern2:4;
+	uint32_t rightUnpackPattern3:4;
+	uint32_t rightUnpackStop0:1;
+	uint32_t rightUnpackStop1:1;
+	uint32_t rightUnpackStop2:1;
+	uint32_t rightUnpackStop3:1;
+	 uint32_t /* reserved */ : 12;
+
+	/* bus_stripe_rd_pad_tb_unpack */
+	uint32_t topUnapckPattern:4;
+	 uint32_t /* reserved */ : 12;
+	uint32_t bottomUnapckPattern:4;
+	 uint32_t /* reserved */ : 12;
+} __attribute__ ((packed, aligned(4)));
+
+struct VFE_AxiRdFragIrqEnable {
+	uint32_t stripeRdFragirq0Enable:1;
+	uint32_t stripeRdFragirq1Enable:1;
+	uint32_t stripeRdFragirq2Enable:1;
+	uint32_t stripeRdFragirq3Enable:1;
+	 uint32_t /* reserved */ : 28;
+} __attribute__ ((packed, aligned(4)));
+
+int vfe_cmd_init(struct msm_vfe_callback *, struct platform_device *, void *);
+void vfe_stats_af_stop(void);
+void vfe_stop(void);
+void vfe_update(void);
+int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *);
+int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *);
+void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *);
+void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *);
+void vfe_start(struct vfe_cmd_start *);
+void vfe_la_update(struct vfe_cmd_la_config *);
+void vfe_la_config(struct vfe_cmd_la_config *);
+void vfe_test_gen_start(struct vfe_cmd_test_gen_start *);
+void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *);
+void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *);
+void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *);
+void vfe_camif_frame_update(struct vfe_cmds_camif_frame *);
+void vfe_color_correction_config(struct vfe_cmd_color_correction_config *);
+void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *);
+void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *);
+void vfe_demosaic_config(struct vfe_cmd_demosaic_config *);
+void vfe_demux_channel_gain_update(struct vfe_cmd_demux_channel_gain_config *);
+void vfe_demux_channel_gain_config(struct vfe_cmd_demux_channel_gain_config *);
+void vfe_black_level_update(struct vfe_cmd_black_level_config *);
+void vfe_black_level_config(struct vfe_cmd_black_level_config *);
+void vfe_asf_update(struct vfe_cmd_asf_update *);
+void vfe_asf_config(struct vfe_cmd_asf_config *);
+void vfe_white_balance_config(struct vfe_cmd_white_balance_config *);
+void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *);
+void vfe_roll_off_config(struct vfe_cmd_roll_off_config *);
+void vfe_chroma_subsample_config(struct vfe_cmd_chroma_subsample_config *);
+void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *);
+void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *);
+void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *);
+void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *);
+void vfe_stats_wb_exp_stop(void);
+void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *);
+void vfe_stats_update_af(struct vfe_cmd_stats_af_update *);
+void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *);
+void vfe_stats_start_af(struct vfe_cmd_stats_af_start *);
+void vfe_stats_setting(struct vfe_cmd_stats_setting *);
+void vfe_axi_input_config(struct vfe_cmd_axi_input_config *);
+void vfe_stats_config(struct vfe_cmd_stats_setting *);
+void vfe_axi_output_config(struct vfe_cmd_axi_output_config *);
+void vfe_camif_config(struct vfe_cmd_camif_config *);
+void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *);
+void vfe_get_hw_version(struct vfe_cmd_hw_version *);
+void vfe_reset(void);
+void vfe_cmd_release(struct platform_device *);
+void vfe_output1_ack(struct vfe_cmd_output_ack *);
+void vfe_output2_ack(struct vfe_cmd_output_ack *);
+void vfe_epoch1_config(struct vfe_cmds_camif_epoch *);
+#endif /* __MSM_VFE8X_REG_H__ */
diff --git a/drivers/media/video/msm/mt9d112.c b/drivers/media/video/msm/mt9d112.c
new file mode 100644
index 0000000..5a6a8db
--- /dev/null
+++ b/drivers/media/video/msm/mt9d112.c
@@ -0,0 +1,736 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include "mt9d112.h"
+
+/* Micron MT9D112 Registers and their values */
+/* Sensor Core Registers */
+#define  REG_MT9D112_MODEL_ID 0x3000
+#define  MT9D112_MODEL_ID     0x1580
+
+/*  SOC Registers Page 1  */
+#define  REG_MT9D112_SENSOR_RESET     0x301A
+#define  REG_MT9D112_STANDBY_CONTROL  0x3202
+#define  REG_MT9D112_MCU_BOOT         0x3386
+
+struct mt9d112_work {
+	struct work_struct work;
+};
+
+static struct mt9d112_work *mt9d112_sensorw;
+static struct i2c_client *mt9d112_client;
+
+struct mt9d112_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+};
+
+static struct mt9d112_ctrl *mt9d112_ctrl;
+
+static DECLARE_WAIT_QUEUE_HEAD(mt9d112_wait_queue);
+
+static int mt9d112_reset(const struct msm_camera_sensor_info *dev)
+{
+	int rc = 0;
+
+	rc = gpio_request(dev->sensor_reset, "mt9d112");
+
+	if (!rc) {
+		rc = gpio_direction_output(dev->sensor_reset, 0);
+		mdelay(20);
+		rc = gpio_direction_output(dev->sensor_reset, 1);
+	}
+
+	gpio_free(dev->sensor_reset);
+	return rc;
+}
+
+static int mt9d112_i2c_txdata(unsigned short saddr,
+				  unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+		 .addr = saddr,
+		 .flags = 0,
+		 .len = length,
+		 .buf = txdata,
+		 },
+	};
+
+	if (i2c_transfer(mt9d112_client->adapter, msg, 1) < 0) {
+		CDBG("mt9d112_i2c_txdata failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mt9d112_i2c_write(unsigned short saddr,
+				 unsigned short waddr, unsigned short wdata,
+				 enum mt9d112_width width)
+{
+	int rc = -EIO;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	switch (width) {
+	case WORD_LEN:{
+			buf[0] = (waddr & 0xFF00) >> 8;
+			buf[1] = (waddr & 0x00FF);
+			buf[2] = (wdata & 0xFF00) >> 8;
+			buf[3] = (wdata & 0x00FF);
+
+			rc = mt9d112_i2c_txdata(saddr, buf, 4);
+		}
+		break;
+
+	case BYTE_LEN:{
+			buf[0] = waddr;
+			buf[1] = wdata;
+			rc = mt9d112_i2c_txdata(saddr, buf, 2);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	if (rc < 0)
+		CDBG("i2c_write failed, addr = 0x%x, val = 0x%x!\n",
+		     waddr, wdata);
+
+	return rc;
+}
+
+static int mt9d112_i2c_write_table(struct mt9d112_i2c_reg_conf const
+				       *reg_conf_tbl, int num_of_items_in_table)
+{
+	int i;
+	int rc = -EIO;
+
+	for (i = 0; i < num_of_items_in_table; i++) {
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       reg_conf_tbl->waddr, reg_conf_tbl->wdata,
+				       reg_conf_tbl->width);
+		if (rc < 0)
+			break;
+		if (reg_conf_tbl->mdelay_time != 0)
+			mdelay(reg_conf_tbl->mdelay_time);
+		reg_conf_tbl++;
+	}
+
+	return rc;
+}
+
+static int mt9d112_i2c_rxdata(unsigned short saddr,
+			      unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+		 .addr = saddr,
+		 .flags = 0,
+		 .len = 2,
+		 .buf = rxdata,
+		 },
+		{
+		 .addr = saddr,
+		 .flags = I2C_M_RD,
+		 .len = length,
+		 .buf = rxdata,
+		 },
+	};
+
+	if (i2c_transfer(mt9d112_client->adapter, msgs, 2) < 0) {
+		CDBG("mt9d112_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mt9d112_i2c_read(unsigned short saddr,
+				unsigned short raddr, unsigned short *rdata,
+				enum mt9d112_width width)
+{
+	int rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	switch (width) {
+	case WORD_LEN:{
+			buf[0] = (raddr & 0xFF00) >> 8;
+			buf[1] = (raddr & 0x00FF);
+
+			rc = mt9d112_i2c_rxdata(saddr, buf, 2);
+			if (rc < 0)
+				return rc;
+
+			*rdata = buf[0] << 8 | buf[1];
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	if (rc < 0)
+		CDBG("mt9d112_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int mt9d112_set_lens_roll_off(void)
+{
+	int rc = 0;
+	rc = mt9d112_i2c_write_table(&mt9d112_regs.rftbl[0],
+				     mt9d112_regs.rftbl_size);
+	return rc;
+}
+
+static int mt9d112_reg_init(void)
+{
+	int array_length;
+	int i;
+	int rc;
+
+	/* PLL Setup Start */
+	rc = mt9d112_i2c_write_table(&mt9d112_regs.plltbl[0],
+				     mt9d112_regs.plltbl_size);
+
+	if (rc < 0)
+		return rc;
+	/* PLL Setup End */
+
+	array_length = mt9d112_regs.prev_snap_reg_settings_size;
+
+	/* Configure sensor for Preview mode and Snapshot mode */
+	for (i = 0; i < array_length; i++) {
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       mt9d112_regs.prev_snap_reg_settings[i].
+				       register_address,
+				       mt9d112_regs.prev_snap_reg_settings[i].
+				       register_value, WORD_LEN);
+
+		if (rc < 0)
+			return rc;
+	}
+
+	/* Configure for Noise Reduction, Saturation and Aperture Correction */
+	array_length = mt9d112_regs.noise_reduction_reg_settings_size;
+
+	for (i = 0; i < array_length; i++) {
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       mt9d112_regs.
+				       noise_reduction_reg_settings[i].
+				       register_address,
+				       mt9d112_regs.
+				       noise_reduction_reg_settings[i].
+				       register_value, WORD_LEN);
+
+		if (rc < 0)
+			return rc;
+	}
+
+	/* Set Color Kill Saturation point to optimum value */
+	rc = mt9d112_i2c_write(mt9d112_client->addr, 0x35A4, 0x0593, WORD_LEN);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9d112_i2c_write_table(&mt9d112_regs.stbl[0],
+				     mt9d112_regs.stbl_size);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9d112_set_lens_roll_off();
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static int mt9d112_set_sensor_mode(int mode)
+{
+	uint16_t clock;
+	int rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x338C, 0xA20C, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x3390, 0x0004, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x338C, 0xA215, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x3390, 0x0004, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x338C, 0xA20B, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x3390, 0x0000, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		clock = 0x0250;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x341C, clock, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x338C, 0xA103, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x3390, 0x0001, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		mdelay(5);
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		/* Switch to lower fps for Snapshot */
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x341C, 0x0120, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x338C, 0xA120, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x3390, 0x0002, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		mdelay(5);
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x338C, 0xA103, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+				       0x3390, 0x0002, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mt9d112_set_effect(int mode, int effect)
+{
+	uint16_t reg_addr;
+	uint16_t reg_val;
+	int rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		/* Context A Special Effects */
+		reg_addr = 0x2799;
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		/* Context B Special Effects */
+		reg_addr = 0x279B;
+		break;
+
+	default:
+		reg_addr = 0x2799;
+		break;
+	}
+
+	switch (effect) {
+	case CAMERA_EFFECT_OFF:{
+			reg_val = 0x6440;
+
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x338C, reg_addr, WORD_LEN);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x3390, reg_val, WORD_LEN);
+			if (rc < 0)
+				return rc;
+		}
+		break;
+
+	case CAMERA_EFFECT_MONO:{
+			reg_val = 0x6441;
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x338C, reg_addr, WORD_LEN);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x3390, reg_val, WORD_LEN);
+			if (rc < 0)
+				return rc;
+		}
+		break;
+
+	case CAMERA_EFFECT_NEGATIVE:{
+			reg_val = 0x6443;
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x338C, reg_addr, WORD_LEN);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x3390, reg_val, WORD_LEN);
+			if (rc < 0)
+				return rc;
+		}
+		break;
+
+	case CAMERA_EFFECT_SOLARIZE:{
+			reg_val = 0x6445;
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x338C, reg_addr, WORD_LEN);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x3390, reg_val, WORD_LEN);
+			if (rc < 0)
+				return rc;
+		}
+		break;
+
+	case CAMERA_EFFECT_SEPIA:{
+			reg_val = 0x6442;
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x338C, reg_addr, WORD_LEN);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x3390, reg_val, WORD_LEN);
+			if (rc < 0)
+				return rc;
+		}
+		break;
+
+	case CAMERA_EFFECT_PASTEL:
+	case CAMERA_EFFECT_MOSAIC:
+	case CAMERA_EFFECT_RESIZE:
+		return -EINVAL;
+
+	default:{
+			reg_val = 0x6440;
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x338C, reg_addr, WORD_LEN);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9d112_i2c_write(mt9d112_client->addr,
+					       0x3390, reg_val, WORD_LEN);
+			if (rc < 0)
+				return rc;
+
+			return -EINVAL;
+		}
+	}
+
+	/* Refresh Sequencer */
+	rc = mt9d112_i2c_write(mt9d112_client->addr, 0x338C, 0xA103, WORD_LEN);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9d112_i2c_write(mt9d112_client->addr, 0x3390, 0x0005, WORD_LEN);
+
+	return rc;
+}
+
+static int mt9d112_sensor_init_probe(const struct msm_camera_sensor_info *data)
+{
+	uint16_t model_id = 0;
+	int rc = 0;
+
+	CDBG("init entry \n");
+	rc = mt9d112_reset(data);
+	if (rc < 0) {
+		CDBG("reset failed!\n");
+		goto init_probe_fail;
+	}
+
+	mdelay(5);
+
+	/* Micron suggested Power up block Start:
+	 * Put MCU into Reset - Stop MCU */
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+			       REG_MT9D112_MCU_BOOT, 0x0501, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	/* Pull MCU from Reset - Start MCU */
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+			       REG_MT9D112_MCU_BOOT, 0x0500, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	mdelay(5);
+
+	/* Micron Suggested - Power up block */
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+			       REG_MT9D112_SENSOR_RESET, 0x0ACC, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+			       REG_MT9D112_STANDBY_CONTROL, 0x0008, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	/* FUSED_DEFECT_CORRECTION */
+	rc = mt9d112_i2c_write(mt9d112_client->addr, 0x33F4, 0x031D, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	mdelay(5);
+
+	/* Micron suggested Power up block End */
+	/* Read the Model ID of the sensor */
+	rc = mt9d112_i2c_read(mt9d112_client->addr,
+			      REG_MT9D112_MODEL_ID, &model_id, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	CDBG("mt9d112 model_id = 0x%x\n", model_id);
+
+	/* Check if it matches it with the value in Datasheet */
+	if (model_id != MT9D112_MODEL_ID) {
+		rc = -EINVAL;
+		goto init_probe_fail;
+	}
+
+	rc = mt9d112_reg_init();
+	if (rc < 0)
+		goto init_probe_fail;
+
+	return rc;
+
+init_probe_fail:
+	return rc;
+}
+
+int mt9d112_sensor_init(const struct msm_camera_sensor_info *data)
+{
+	int rc = 0;
+
+	mt9d112_ctrl = kzalloc(sizeof(struct mt9d112_ctrl), GFP_KERNEL);
+	if (!mt9d112_ctrl) {
+		CDBG("mt9d112_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+
+	if (data)
+		mt9d112_ctrl->sensordata = data;
+
+	/* Input MCLK = 24MHz */
+	msm_camio_clk_rate_set(24000000);
+	mdelay(5);
+
+	msm_camio_camif_pad_reg_reset();
+
+	rc = mt9d112_sensor_init_probe(data);
+	if (rc < 0) {
+		CDBG("mt9d112_sensor_init failed!\n");
+		goto init_fail;
+	}
+
+init_done:
+	return rc;
+
+init_fail:
+	kfree(mt9d112_ctrl);
+	return rc;
+}
+
+static int mt9d112_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&mt9d112_wait_queue);
+	return 0;
+}
+
+int mt9d112_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cfg_data;
+	long rc = 0;
+
+	if (copy_from_user(&cfg_data,
+			   (void *)argp, sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	CDBG("mt9d112_ioctl, cfgtype = %d, mode = %d\n",
+	     cfg_data.cfgtype, cfg_data.mode);
+
+	switch (cfg_data.cfgtype) {
+	case CFG_SET_MODE:
+		rc = mt9d112_set_sensor_mode(cfg_data.mode);
+		break;
+
+	case CFG_SET_EFFECT:
+		rc = mt9d112_set_effect(cfg_data.mode, cfg_data.cfg.effect);
+		break;
+
+	case CFG_GET_AF_MAX_STEPS:
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+int mt9d112_sensor_release(void)
+{
+	int rc = 0;
+
+	kfree(mt9d112_ctrl);
+
+	return rc;
+}
+
+static int mt9d112_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	int rc = 0;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		rc = -ENOTSUPP;
+		goto probe_failure;
+	}
+
+	mt9d112_sensorw = kzalloc(sizeof(struct mt9d112_work), GFP_KERNEL);
+
+	if (!mt9d112_sensorw) {
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, mt9d112_sensorw);
+	mt9d112_init_client(client);
+	mt9d112_client = client;
+
+	CDBG("mt9d112_probe succeeded!\n");
+
+	return 0;
+
+probe_failure:
+	kfree(mt9d112_sensorw);
+	mt9d112_sensorw = NULL;
+	CDBG("mt9d112_probe failed!\n");
+	return rc;
+}
+
+static const struct i2c_device_id mt9d112_i2c_id[] = {
+	{"mt9d112", 0},
+	{},
+};
+
+static struct i2c_driver mt9d112_i2c_driver = {
+	.id_table = mt9d112_i2c_id,
+	.probe = mt9d112_i2c_probe,
+	.remove = __exit_p(mt9d112_i2c_remove),
+	.driver = {
+		   .name = "mt9d112",
+		   },
+};
+
+static int mt9d112_sensor_probe(const struct msm_camera_sensor_info *info,
+				struct msm_sensor_ctrl *s)
+{
+	int rc = i2c_add_driver(&mt9d112_i2c_driver);
+	if (rc < 0 || mt9d112_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_done;
+	}
+
+	/* Input MCLK = 24MHz */
+	msm_camio_clk_rate_set(24000000);
+	mdelay(5);
+
+	rc = mt9d112_sensor_init_probe(info);
+	if (rc < 0)
+		goto probe_done;
+
+	s->s_init = mt9d112_sensor_init;
+	s->s_release = mt9d112_sensor_release;
+	s->s_config = mt9d112_sensor_config;
+
+probe_done:
+	CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
+	return rc;
+}
+
+static int __mt9d112_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, mt9d112_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __mt9d112_probe,
+	.driver = {
+		   .name = "msm_camera_mt9d112",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __init mt9d112_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9d112_init);
diff --git a/drivers/media/video/msm/mt9d112.h b/drivers/media/video/msm/mt9d112.h
new file mode 100644
index 0000000..39777c7
--- /dev/null
+++ b/drivers/media/video/msm/mt9d112.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef MT9D112_H
+#define MT9D112_H
+
+#include <linux/types.h>
+#include <mach/camera.h>
+
+enum mt9d112_width {
+	WORD_LEN,
+	BYTE_LEN
+};
+
+struct mt9d112_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+	enum mt9d112_width width;
+	unsigned short mdelay_time;
+};
+
+struct mt9d112_reg {
+	const struct register_address_value_pair *prev_snap_reg_settings;
+	uint16_t prev_snap_reg_settings_size;
+	const struct register_address_value_pair *noise_reduction_reg_settings;
+	uint16_t noise_reduction_reg_settings_size;
+	const struct mt9d112_i2c_reg_conf *plltbl;
+	uint16_t plltbl_size;
+	const struct mt9d112_i2c_reg_conf *stbl;
+	uint16_t stbl_size;
+	const struct mt9d112_i2c_reg_conf *rftbl;
+	uint16_t rftbl_size;
+};
+
+extern struct mt9d112_reg mt9d112_regs;
+
+#endif /* MT9D112_H */
diff --git a/drivers/media/video/msm/mt9d112_reg.c b/drivers/media/video/msm/mt9d112_reg.c
new file mode 100644
index 0000000..f2ae0c7
--- /dev/null
+++ b/drivers/media/video/msm/mt9d112_reg.c
@@ -0,0 +1,320 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "mt9d112.h"
+
+struct register_address_value_pair
+ preview_snapshot_mode_reg_settings_array[] = {
+	{0x338C, 0x2703},
+	{0x3390, 800},		/* Output Width (P) = 640 */
+	{0x338C, 0x2705},
+	{0x3390, 600},		/* Output Height (P) = 480 */
+	{0x338C, 0x2707},
+	{0x3390, 0x0640},	/* Output Width (S) = 1600 */
+	{0x338C, 0x2709},
+	{0x3390, 0x04B0},	/* Output Height (S) = 1200 */
+	{0x338C, 0x270D},
+	{0x3390, 0x0000},	/* Row Start (P) = 0 */
+	{0x338C, 0x270F},
+	{0x3390, 0x0000},	/* Column Start (P) = 0 */
+	{0x338C, 0x2711},
+	{0x3390, 0x04BD},	/* Row End (P) = 1213 */
+	{0x338C, 0x2713},
+	{0x3390, 0x064D},	/* Column End (P) = 1613 */
+	{0x338C, 0x2715},
+	{0x3390, 0x0000},	/* Extra Delay (P) = 0 */
+	{0x338C, 0x2717},
+	{0x3390, 0x2111},	/* Row Speed (P) = 8465 */
+	{0x338C, 0x2719},
+	{0x3390, 0x046C},	/* Read Mode (P) = 1132 */
+	{0x338C, 0x271B},
+	{0x3390, 0x024F},	/* Sensor_Sample_Time_pck(P) = 591 */
+	{0x338C, 0x271D},
+	{0x3390, 0x0102},	/* Sensor_Fine_Correction(P) = 258 */
+	{0x338C, 0x271F},
+	{0x3390, 0x0279},	/* Sensor_Fine_IT_min(P) = 633 */
+	{0x338C, 0x2721},
+	{0x3390, 0x0155},	/* Sensor_Fine_IT_max_margin(P) = 341 */
+	{0x338C, 0x2723},
+	{0x3390, 659},		/* Frame Lines (P) = 679 */
+	{0x338C, 0x2725},
+	{0x3390, 0x0824},	/* Line Length (P) = 2084 */
+	{0x338C, 0x2727},
+	{0x3390, 0x2020},
+	{0x338C, 0x2729},
+	{0x3390, 0x2020},
+	{0x338C, 0x272B},
+	{0x3390, 0x1020},
+	{0x338C, 0x272D},
+	{0x3390, 0x2007},
+	{0x338C, 0x272F},
+	{0x3390, 0x0004},	/* Row Start(S) = 4 */
+	{0x338C, 0x2731},
+	{0x3390, 0x0004},	/* Column Start(S) = 4 */
+	{0x338C, 0x2733},
+	{0x3390, 0x04BB},	/* Row End(S) = 1211 */
+	{0x338C, 0x2735},
+	{0x3390, 0x064B},	/* Column End(S) = 1611 */
+	{0x338C, 0x2737},
+	{0x3390, 0x04CE},	/* Extra Delay(S) = 1230 */
+	{0x338C, 0x2739},
+	{0x3390, 0x2111},	/* Row Speed(S) = 8465 */
+	{0x338C, 0x273B},
+	{0x3390, 0x0024},	/* Read Mode(S) = 36 */
+	{0x338C, 0x273D},
+	{0x3390, 0x0120},	/* Sensor sample time pck(S) = 288 */
+	{0x338C, 0x2741},
+	{0x3390, 0x0169},	/* Sensor_Fine_IT_min(P) = 361 */
+	{0x338C, 0x2745},
+	{0x3390, 0x04FF},	/* Frame Lines(S) = 1279 */
+	{0x338C, 0x2747},
+	{0x3390, 0x0824},	/* Line Length(S) = 2084 */
+	{0x338C, 0x2751},
+	{0x3390, 0x0000},	/* Crop_X0(P) = 0 */
+	{0x338C, 0x2753},
+	{0x3390, 0x0320},	/* Crop_X1(P) = 800 */
+	{0x338C, 0x2755},
+	{0x3390, 0x0000},	/* Crop_Y0(P) = 0 */
+	{0x338C, 0x2757},
+	{0x3390, 0x0258},	/* Crop_Y1(P) = 600 */
+	{0x338C, 0x275F},
+	{0x3390, 0x0000},	/* Crop_X0(S) = 0 */
+	{0x338C, 0x2761},
+	{0x3390, 0x0640},	/* Crop_X1(S) = 1600 */
+	{0x338C, 0x2763},
+	{0x3390, 0x0000},	/* Crop_Y0(S) = 0 */
+	{0x338C, 0x2765},
+	{0x3390, 0x04B0},	/* Crop_Y1(S) = 1200 */
+	{0x338C, 0x222E},
+	{0x3390, 0x00A0},	/* R9 Step = 160 */
+	{0x338C, 0xA408},
+	{0x3390, 0x001F},
+	{0x338C, 0xA409},
+	{0x3390, 0x0021},
+	{0x338C, 0xA40A},
+	{0x3390, 0x0025},
+	{0x338C, 0xA40B},
+	{0x3390, 0x0027},
+	{0x338C, 0x2411},
+	{0x3390, 0x00A0},
+	{0x338C, 0x2413},
+	{0x3390, 0x00C0},
+	{0x338C, 0x2415},
+	{0x3390, 0x00A0},
+	{0x338C, 0x2417},
+	{0x3390, 0x00C0},
+	{0x338C, 0x2799},
+	{0x3390, 0x6408},	/* MODE_SPEC_EFFECTS(P) */
+	{0x338C, 0x279B},
+	{0x3390, 0x6408},	/* MODE_SPEC_EFFECTS(S) */
+};
+
+static struct register_address_value_pair
+ noise_reduction_reg_settings_array[] = {
+	{0x338C, 0xA76D},
+	{0x3390, 0x0003},
+	{0x338C, 0xA76E},
+	{0x3390, 0x0003},
+	{0x338C, 0xA76F},
+	{0x3390, 0},
+	{0x338C, 0xA770},
+	{0x3390, 21},
+	{0x338C, 0xA771},
+	{0x3390, 37},
+	{0x338C, 0xA772},
+	{0x3390, 63},
+	{0x338C, 0xA773},
+	{0x3390, 100},
+	{0x338C, 0xA774},
+	{0x3390, 128},
+	{0x338C, 0xA775},
+	{0x3390, 151},
+	{0x338C, 0xA776},
+	{0x3390, 169},
+	{0x338C, 0xA777},
+	{0x3390, 186},
+	{0x338C, 0xA778},
+	{0x3390, 199},
+	{0x338C, 0xA779},
+	{0x3390, 210},
+	{0x338C, 0xA77A},
+	{0x3390, 220},
+	{0x338C, 0xA77B},
+	{0x3390, 228},
+	{0x338C, 0xA77C},
+	{0x3390, 234},
+	{0x338C, 0xA77D},
+	{0x3390, 240},
+	{0x338C, 0xA77E},
+	{0x3390, 244},
+	{0x338C, 0xA77F},
+	{0x3390, 248},
+	{0x338C, 0xA780},
+	{0x3390, 252},
+	{0x338C, 0xA781},
+	{0x3390, 255},
+	{0x338C, 0xA782},
+	{0x3390, 0},
+	{0x338C, 0xA783},
+	{0x3390, 21},
+	{0x338C, 0xA784},
+	{0x3390, 37},
+	{0x338C, 0xA785},
+	{0x3390, 63},
+	{0x338C, 0xA786},
+	{0x3390, 100},
+	{0x338C, 0xA787},
+	{0x3390, 128},
+	{0x338C, 0xA788},
+	{0x3390, 151},
+	{0x338C, 0xA789},
+	{0x3390, 169},
+	{0x338C, 0xA78A},
+	{0x3390, 186},
+	{0x338C, 0xA78B},
+	{0x3390, 199},
+	{0x338C, 0xA78C},
+	{0x3390, 210},
+	{0x338C, 0xA78D},
+	{0x3390, 220},
+	{0x338C, 0xA78E},
+	{0x3390, 228},
+	{0x338C, 0xA78F},
+	{0x3390, 234},
+	{0x338C, 0xA790},
+	{0x3390, 240},
+	{0x338C, 0xA791},
+	{0x3390, 244},
+	{0x338C, 0xA793},
+	{0x3390, 252},
+	{0x338C, 0xA794},
+	{0x3390, 255},
+	{0x338C, 0xA103},
+	{0x3390, 6},
+};
+
+static const struct mt9d112_i2c_reg_conf const lens_roll_off_tbl[] = {
+	{0x34CE, 0x81A0, WORD_LEN, 0},
+	{0x34D0, 0x6331, WORD_LEN, 0},
+	{0x34D2, 0x3394, WORD_LEN, 0},
+	{0x34D4, 0x9966, WORD_LEN, 0},
+	{0x34D6, 0x4B25, WORD_LEN, 0},
+	{0x34D8, 0x2670, WORD_LEN, 0},
+	{0x34DA, 0x724C, WORD_LEN, 0},
+	{0x34DC, 0xFFFD, WORD_LEN, 0},
+	{0x34DE, 0x00CA, WORD_LEN, 0},
+	{0x34E6, 0x00AC, WORD_LEN, 0},
+	{0x34EE, 0x0EE1, WORD_LEN, 0},
+	{0x34F6, 0x0D87, WORD_LEN, 0},
+	{0x3500, 0xE1F7, WORD_LEN, 0},
+	{0x3508, 0x1CF4, WORD_LEN, 0},
+	{0x3510, 0x1D28, WORD_LEN, 0},
+	{0x3518, 0x1F26, WORD_LEN, 0},
+	{0x3520, 0x2220, WORD_LEN, 0},
+	{0x3528, 0x333D, WORD_LEN, 0},
+	{0x3530, 0x15D9, WORD_LEN, 0},
+	{0x3538, 0xCFB8, WORD_LEN, 0},
+	{0x354C, 0x05FE, WORD_LEN, 0},
+	{0x3544, 0x05F8, WORD_LEN, 0},
+	{0x355C, 0x0596, WORD_LEN, 0},
+	{0x3554, 0x0611, WORD_LEN, 0},
+	{0x34E0, 0x00F2, WORD_LEN, 0},
+	{0x34E8, 0x00A8, WORD_LEN, 0},
+	{0x34F0, 0x0F7B, WORD_LEN, 0},
+	{0x34F8, 0x0CD7, WORD_LEN, 0},
+	{0x3502, 0xFEDB, WORD_LEN, 0},
+	{0x350A, 0x13E4, WORD_LEN, 0},
+	{0x3512, 0x1F2C, WORD_LEN, 0},
+	{0x351A, 0x1D20, WORD_LEN, 0},
+	{0x3522, 0x2422, WORD_LEN, 0},
+	{0x352A, 0x2925, WORD_LEN, 0},
+	{0x3532, 0x1D04, WORD_LEN, 0},
+	{0x353A, 0xFBF2, WORD_LEN, 0},
+	{0x354E, 0x0616, WORD_LEN, 0},
+	{0x3546, 0x0597, WORD_LEN, 0},
+	{0x355E, 0x05CD, WORD_LEN, 0},
+	{0x3556, 0x0529, WORD_LEN, 0},
+	{0x34E4, 0x00B2, WORD_LEN, 0},
+	{0x34EC, 0x005E, WORD_LEN, 0},
+	{0x34F4, 0x0F43, WORD_LEN, 0},
+	{0x34FC, 0x0E2F, WORD_LEN, 0},
+	{0x3506, 0xF9FC, WORD_LEN, 0},
+	{0x350E, 0x0CE4, WORD_LEN, 0},
+	{0x3516, 0x1E1E, WORD_LEN, 0},
+	{0x351E, 0x1B19, WORD_LEN, 0},
+	{0x3526, 0x151B, WORD_LEN, 0},
+	{0x352E, 0x1416, WORD_LEN, 0},
+	{0x3536, 0x10FC, WORD_LEN, 0},
+	{0x353E, 0xC018, WORD_LEN, 0},
+	{0x3552, 0x06B4, WORD_LEN, 0},
+	{0x354A, 0x0506, WORD_LEN, 0},
+	{0x3562, 0x06AB, WORD_LEN, 0},
+	{0x355A, 0x063A, WORD_LEN, 0},
+	{0x34E2, 0x00E5, WORD_LEN, 0},
+	{0x34EA, 0x008B, WORD_LEN, 0},
+	{0x34F2, 0x0E4C, WORD_LEN, 0},
+	{0x34FA, 0x0CA3, WORD_LEN, 0},
+	{0x3504, 0x0907, WORD_LEN, 0},
+	{0x350C, 0x1DFD, WORD_LEN, 0},
+	{0x3514, 0x1E24, WORD_LEN, 0},
+	{0x351C, 0x2529, WORD_LEN, 0},
+	{0x3524, 0x1D20, WORD_LEN, 0},
+	{0x352C, 0x2332, WORD_LEN, 0},
+	{0x3534, 0x10E9, WORD_LEN, 0},
+	{0x353C, 0x0BCB, WORD_LEN, 0},
+	{0x3550, 0x04EF, WORD_LEN, 0},
+	{0x3548, 0x0609, WORD_LEN, 0},
+	{0x3560, 0x0580, WORD_LEN, 0},
+	{0x3558, 0x05DD, WORD_LEN, 0},
+	{0x3540, 0x0000, WORD_LEN, 0},
+	{0x3542, 0x0000, WORD_LEN, 0}
+};
+
+static const struct mt9d112_i2c_reg_conf const pll_setup_tbl[] = {
+	{0x341E, 0x8F09, WORD_LEN, 0},
+	{0x341C, 0x0250, WORD_LEN, 0},
+	{0x341E, 0x8F09, WORD_LEN, 5},
+	{0x341E, 0x8F08, WORD_LEN, 0}
+};
+
+/* Refresh Sequencer */
+static const struct mt9d112_i2c_reg_conf const sequencer_tbl[] = {
+	{0x338C, 0x2799, WORD_LEN, 0},
+	{0x3390, 0x6440, WORD_LEN, 5},
+	{0x338C, 0x279B, WORD_LEN, 0},
+	{0x3390, 0x6440, WORD_LEN, 5},
+	{0x338C, 0xA103, WORD_LEN, 0},
+	{0x3390, 0x0005, WORD_LEN, 5},
+	{0x338C, 0xA103, WORD_LEN, 0},
+	{0x3390, 0x0006, WORD_LEN, 5}
+};
+
+struct mt9d112_reg mt9d112_regs = {
+	.prev_snap_reg_settings = &preview_snapshot_mode_reg_settings_array[0],
+	.prev_snap_reg_settings_size =
+	    ARRAY_SIZE(preview_snapshot_mode_reg_settings_array),
+	.noise_reduction_reg_settings = &noise_reduction_reg_settings_array[0],
+	.noise_reduction_reg_settings_size =
+	    ARRAY_SIZE(noise_reduction_reg_settings_array),
+	.plltbl = pll_setup_tbl,
+	.plltbl_size = ARRAY_SIZE(pll_setup_tbl),
+	.stbl = sequencer_tbl,
+	.stbl_size = ARRAY_SIZE(sequencer_tbl),
+	.rftbl = lens_roll_off_tbl,
+	.rftbl_size = ARRAY_SIZE(lens_roll_off_tbl)
+};
diff --git a/drivers/media/video/msm/mt9p012.h b/drivers/media/video/msm/mt9p012.h
new file mode 100644
index 0000000..4c05f79
--- /dev/null
+++ b/drivers/media/video/msm/mt9p012.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef MT9T012_H
+#define MT9T012_H
+
+#include <linux/types.h>
+
+struct reg_struct {
+	uint16_t vt_pix_clk_div;	/* 0x0300 */
+	uint16_t vt_sys_clk_div;	/* 0x0302 */
+	uint16_t pre_pll_clk_div;	/* 0x0304 */
+	uint16_t pll_multiplier;	/* 0x0306 */
+	uint16_t op_pix_clk_div;	/* 0x0308 */
+	uint16_t op_sys_clk_div;	/* 0x030A */
+	uint16_t scale_m;	/* 0x0404 */
+	uint16_t row_speed;	/* 0x3016 */
+	uint16_t x_addr_start;	/* 0x3004 */
+	uint16_t x_addr_end;	/* 0x3008 */
+	uint16_t y_addr_start;	/* 0x3002 */
+	uint16_t y_addr_end;	/* 0x3006 */
+	uint16_t read_mode;	/* 0x3040 */
+	uint16_t x_output_size;	/* 0x034C */
+	uint16_t y_output_size;	/* 0x034E */
+	uint16_t line_length_pck;	/* 0x300C */
+	uint16_t frame_length_lines;	/* 0x300A */
+	uint16_t coarse_int_time;	/* 0x3012 */
+	uint16_t fine_int_time;	/* 0x3014 */
+};
+
+struct mt9p012_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+struct mt9p012_reg {
+	struct reg_struct *reg_pat;
+	uint16_t reg_pat_size;
+	struct mt9p012_i2c_reg_conf *ttbl;
+	uint16_t ttbl_size;
+	struct mt9p012_i2c_reg_conf *lctbl;
+	uint16_t lctbl_size;
+	struct mt9p012_i2c_reg_conf *rftbl;
+	uint16_t rftbl_size;
+};
+
+extern struct mt9p012_reg mt9p012_regs;
+
+#endif /* MT9T012_H */
diff --git a/drivers/media/video/msm/mt9p012_fox.c b/drivers/media/video/msm/mt9p012_fox.c
new file mode 100644
index 0000000..f2ff40a
--- /dev/null
+++ b/drivers/media/video/msm/mt9p012_fox.c
@@ -0,0 +1,1328 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "mt9p012.h"
+
+/*=============================================================
+    SENSOR REGISTER DEFINES
+==============================================================*/
+#define MT9P012_REG_MODEL_ID         0x0000
+#define MT9P012_MODEL_ID             0x2801
+#define REG_GROUPED_PARAMETER_HOLD   0x0104
+#define GROUPED_PARAMETER_HOLD       0x0100
+#define GROUPED_PARAMETER_UPDATE     0x0000
+#define REG_COARSE_INT_TIME          0x3012
+#define REG_VT_PIX_CLK_DIV           0x0300
+#define REG_VT_SYS_CLK_DIV           0x0302
+#define REG_PRE_PLL_CLK_DIV          0x0304
+#define REG_PLL_MULTIPLIER           0x0306
+#define REG_OP_PIX_CLK_DIV           0x0308
+#define REG_OP_SYS_CLK_DIV           0x030A
+#define REG_SCALE_M                  0x0404
+#define REG_FRAME_LENGTH_LINES       0x300A
+#define REG_LINE_LENGTH_PCK          0x300C
+#define REG_X_ADDR_START             0x3004
+#define REG_Y_ADDR_START             0x3002
+#define REG_X_ADDR_END               0x3008
+#define REG_Y_ADDR_END               0x3006
+#define REG_X_OUTPUT_SIZE            0x034C
+#define REG_Y_OUTPUT_SIZE            0x034E
+#define REG_FINE_INTEGRATION_TIME    0x3014
+#define REG_ROW_SPEED                0x3016
+#define MT9P012_REG_RESET_REGISTER   0x301A
+#define MT9P012_RESET_REGISTER_PWON  0x10CC
+#define MT9P012_RESET_REGISTER_PWOFF 0x10C8
+#define REG_READ_MODE                0x3040
+#define REG_GLOBAL_GAIN              0x305E
+#define REG_TEST_PATTERN_MODE        0x3070
+
+#define MT9P012_REV_7
+
+enum mt9p012_test_mode {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum mt9p012_resolution {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+
+enum mt9p012_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+enum mt9p012_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+
+/* actuator's Slave Address */
+#define MT9P012_AF_I2C_ADDR   0x18
+
+/* AF Total steps parameters */
+#define MT9P012_STEPS_NEAR_TO_CLOSEST_INF  32
+#define MT9P012_TOTAL_STEPS_NEAR_TO_FAR    32
+
+#define MT9P012_MU5M0_PREVIEW_DUMMY_PIXELS 0
+#define MT9P012_MU5M0_PREVIEW_DUMMY_LINES  0
+
+/* Time in milisecs for waiting for the sensor to reset.*/
+#define MT9P012_RESET_DELAY_MSECS   66
+
+/* for 20 fps preview */
+#define MT9P012_DEFAULT_CLOCK_RATE  24000000
+#define MT9P012_DEFAULT_MAX_FPS     26	/* ???? */
+
+struct mt9p012_work {
+	struct work_struct work;
+};
+static struct mt9p012_work *mt9p012_sensorw;
+static struct i2c_client *mt9p012_client;
+
+struct mt9p012_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+
+	int sensormode;
+	uint32_t fps_divider;	/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;	/* init to 1 * 0x00000400 */
+
+	uint16_t curr_lens_pos;
+	uint16_t init_curr_lens_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+
+	enum mt9p012_resolution prev_res;
+	enum mt9p012_resolution pict_res;
+	enum mt9p012_resolution curr_res;
+	enum mt9p012_test_mode set_test;
+};
+
+static struct mt9p012_ctrl *mt9p012_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(mt9p012_wait_queue);
+
+static int mt9p012_i2c_rxdata(unsigned short saddr, unsigned char *rxdata,
+			      int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+		 .addr = saddr,
+		 .flags = 0,
+		 .len = 2,
+		 .buf = rxdata,
+		 },
+		{
+		 .addr = saddr,
+		 .flags = I2C_M_RD,
+		 .len = length,
+		 .buf = rxdata,
+		 },
+	};
+
+	if (i2c_transfer(mt9p012_client->adapter, msgs, 2) < 0) {
+		CDBG("mt9p012_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mt9p012_i2c_read_w(unsigned short saddr, unsigned short raddr,
+				  unsigned short *rdata)
+{
+	int rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = mt9p012_i2c_rxdata(saddr, buf, 2);
+	if (rc < 0)
+		return rc;
+
+	*rdata = buf[0] << 8 | buf[1];
+
+	if (rc < 0)
+		CDBG("mt9p012_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int mt9p012_i2c_txdata(unsigned short saddr, unsigned char *txdata,
+				  int length)
+{
+	struct i2c_msg msg[] = {
+		{
+		 .addr = saddr,
+		 .flags = 0,
+		 .len = length,
+		 .buf = txdata,
+		 },
+	};
+
+	if (i2c_transfer(mt9p012_client->adapter, msg, 1) < 0) {
+		CDBG("mt9p012_i2c_txdata failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mt9p012_i2c_write_b(unsigned short saddr, unsigned short baddr,
+				   unsigned short bdata)
+{
+	int rc = -EIO;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = baddr;
+	buf[1] = bdata;
+	rc = mt9p012_i2c_txdata(saddr, buf, 2);
+
+	if (rc < 0)
+		CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!\n",
+		     saddr, baddr, bdata);
+
+	return rc;
+}
+
+static int mt9p012_i2c_write_w(unsigned short saddr, unsigned short waddr,
+				   unsigned short wdata)
+{
+	int rc = -EIO;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+
+	rc = mt9p012_i2c_txdata(saddr, buf, 4);
+
+	if (rc < 0)
+		CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+		     waddr, wdata);
+
+	return rc;
+}
+
+static int mt9p012_i2c_write_w_table(struct mt9p012_i2c_reg_conf
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int rc = -EIO;
+
+	for (i = 0; i < num; i++) {
+		rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+					 reg_conf_tbl->waddr,
+					 reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+
+	return rc;
+}
+
+static int mt9p012_test(enum mt9p012_test_mode mo)
+{
+	int rc = 0;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	if (mo == TEST_OFF)
+		return 0;
+	else {
+		rc = mt9p012_i2c_write_w_table(mt9p012_regs.ttbl,
+					       mt9p012_regs.ttbl_size);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+					 REG_TEST_PATTERN_MODE, (uint16_t) mo);
+		if (rc < 0)
+			return rc;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int mt9p012_lens_shading_enable(uint8_t is_enable)
+{
+	int rc = 0;
+
+	CDBG("%s: entered. enable = %d\n", __func__, is_enable);
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3780,
+				 ((uint16_t) is_enable) << 15);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+
+	CDBG("%s: exiting. rc = %d\n", __func__, rc);
+	return rc;
+}
+
+static int mt9p012_set_lc(void)
+{
+	int rc;
+
+	rc = mt9p012_i2c_write_w_table(mt9p012_regs.lctbl,
+				       mt9p012_regs.lctbl_size);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_w_table(mt9p012_regs.rftbl,
+				       mt9p012_regs.rftbl_size);
+
+	return rc;
+}
+
+static void mt9p012_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider;	/*Q10 */
+	uint32_t pclk_mult;	/*Q10 */
+
+	if (mt9p012_ctrl->prev_res == QTR_SIZE) {
+		divider = (uint32_t)
+		    (((mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines *
+		       mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck) *
+		      0x00000400) /
+		     (mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines *
+		      mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck));
+
+		pclk_mult =
+		    (uint32_t) ((mt9p012_regs.reg_pat[RES_CAPTURE].
+				 pll_multiplier * 0x00000400) /
+				(mt9p012_regs.reg_pat[RES_PREVIEW].
+				 pll_multiplier));
+	} else {
+		/* full size resolution used for preview. */
+		divider = 0x00000400;	/*1.0 */
+		pclk_mult = 0x00000400;	/*1.0 */
+	}
+
+	/* Verify PCLK settings and frame sizes. */
+	*pfps = (uint16_t) (fps * divider * pclk_mult / 0x00000400 /
+			    0x00000400);
+}
+
+static uint16_t mt9p012_get_prev_lines_pf(void)
+{
+	if (mt9p012_ctrl->prev_res == QTR_SIZE)
+		return mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines;
+	else
+		return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9p012_get_prev_pixels_pl(void)
+{
+	if (mt9p012_ctrl->prev_res == QTR_SIZE)
+		return mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck;
+	else
+		return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint16_t mt9p012_get_pict_lines_pf(void)
+{
+	return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9p012_get_pict_pixels_pl(void)
+{
+	return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint32_t mt9p012_get_pict_max_exp_lc(void)
+{
+	uint16_t snapshot_lines_per_frame;
+
+	if (mt9p012_ctrl->pict_res == QTR_SIZE)
+		snapshot_lines_per_frame =
+		    mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1;
+	else
+		snapshot_lines_per_frame =
+		    mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1;
+
+	return snapshot_lines_per_frame * 24;
+}
+
+static int mt9p012_set_fps(struct fps_cfg *fps)
+{
+	/* input is new fps in Q10 format */
+	int rc = 0;
+
+	mt9p012_ctrl->fps_divider = fps->fps_div;
+	mt9p012_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return -EBUSY;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_LINE_LENGTH_PCK,
+				 (mt9p012_regs.reg_pat[RES_PREVIEW].
+				  line_length_pck * fps->f_mult / 0x00000400));
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+
+	return rc;
+}
+
+static int mt9p012_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint16_t max_legal_gain = 0x01FF;
+	uint32_t line_length_ratio = 0x00000400;
+	enum mt9p012_setting setting;
+	int rc = 0;
+
+	CDBG("Line:%d mt9p012_write_exp_gain \n", __LINE__);
+
+	if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		mt9p012_ctrl->my_reg_gain = gain;
+		mt9p012_ctrl->my_reg_line_count = (uint16_t) line;
+	}
+
+	if (gain > max_legal_gain) {
+		CDBG("Max legal gain Line:%d \n", __LINE__);
+		gain = max_legal_gain;
+	}
+
+	/* Verify no overflow */
+	if (mt9p012_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
+		line = (uint32_t) (line * mt9p012_ctrl->fps_divider /
+				   0x00000400);
+		setting = RES_PREVIEW;
+	} else {
+		line = (uint32_t) (line * mt9p012_ctrl->pict_fps_divider /
+				   0x00000400);
+		setting = RES_CAPTURE;
+	}
+
+	/* Set digital gain to 1 */
+#ifdef MT9P012_REV_7
+	gain |= 0x1000;
+#else
+	gain |= 0x0200;
+#endif
+
+	if ((mt9p012_regs.reg_pat[setting].frame_length_lines - 1) < line) {
+		line_length_ratio = (uint32_t) (line * 0x00000400) /
+		    (mt9p012_regs.reg_pat[setting].frame_length_lines - 1);
+	} else
+		line_length_ratio = 0x00000400;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0) {
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, REG_GLOBAL_GAIN, gain);
+	if (rc < 0) {
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_COARSE_INT_TIME, line);
+	if (rc < 0) {
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	CDBG("mt9p012_write_exp_gain: gain = %d, line = %d\n", gain, line);
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+	if (rc < 0)
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+
+	return rc;
+}
+
+static int mt9p012_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int rc = 0;
+
+	CDBG("Line:%d mt9p012_set_pict_exp_gain \n", __LINE__);
+
+	rc = mt9p012_write_exp_gain(gain, line);
+	if (rc < 0) {
+		CDBG("Line:%d mt9p012_set_pict_exp_gain failed... \n",
+		     __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER, 0x10CC | 0x0002);
+	if (rc < 0) {
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	mdelay(5);
+
+	/* camera_timed_wait(snapshot_wait*exposure_ratio); */
+	return rc;
+}
+
+static int mt9p012_setting(enum mt9p012_reg_update rupdate,
+			       enum mt9p012_setting rt)
+{
+	int rc = 0;
+
+	switch (rupdate) {
+	case UPDATE_PERIODIC:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+
+			struct mt9p012_i2c_reg_conf ppc_tbl[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD},
+				{REG_ROW_SPEED,
+				 mt9p012_regs.reg_pat[rt].row_speed},
+				{REG_X_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].x_addr_start},
+				{REG_X_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].x_addr_end},
+				{REG_Y_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].y_addr_start},
+				{REG_Y_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].y_addr_end},
+				{REG_READ_MODE,
+				 mt9p012_regs.reg_pat[rt].read_mode},
+				{REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m},
+				{REG_X_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].x_output_size},
+				{REG_Y_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].y_output_size},
+
+				{REG_LINE_LENGTH_PCK,
+				 mt9p012_regs.reg_pat[rt].line_length_pck},
+				{REG_FRAME_LENGTH_LINES,
+				 (mt9p012_regs.reg_pat[rt].frame_length_lines *
+				  mt9p012_ctrl->fps_divider / 0x00000400)},
+				{REG_COARSE_INT_TIME,
+				 mt9p012_regs.reg_pat[rt].coarse_int_time},
+				{REG_FINE_INTEGRATION_TIME,
+				 mt9p012_regs.reg_pat[rt].fine_int_time},
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE},
+			};
+
+			rc = mt9p012_i2c_write_w_table(&ppc_tbl[0],
+						       ARRAY_SIZE(ppc_tbl));
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_test(mt9p012_ctrl->set_test);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+						 MT9P012_REG_RESET_REGISTER,
+						 MT9P012_RESET_REGISTER_PWON |
+						 0x0002);
+			if (rc < 0)
+				return rc;
+
+			mdelay(5);	/* 15? wait for sensor to transition */
+
+			return rc;
+		}
+		break;		/* UPDATE_PERIODIC */
+
+	case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct mt9p012_i2c_reg_conf ipc_tbl1[] = {
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWOFF},
+				{REG_VT_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_pix_clk_div},
+				{REG_VT_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_sys_clk_div},
+				{REG_PRE_PLL_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].pre_pll_clk_div},
+				{REG_PLL_MULTIPLIER,
+				 mt9p012_regs.reg_pat[rt].pll_multiplier},
+				{REG_OP_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_pix_clk_div},
+				{REG_OP_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_sys_clk_div},
+#ifdef MT9P012_REV_7
+				{0x30B0, 0x0001},
+				{0x308E, 0xE060},
+				{0x3092, 0x0A52},
+				{0x3094, 0x4656},
+				{0x3096, 0x5652},
+				{0x30CA, 0x8006},
+				{0x312A, 0xDD02},
+				{0x312C, 0x00E4},
+				{0x3170, 0x299A},
+#endif
+				/* optimized settings for noise */
+				{0x3088, 0x6FF6},
+				{0x3154, 0x0282},
+				{0x3156, 0x0381},
+				{0x3162, 0x04CE},
+				{0x0204, 0x0010},
+				{0x0206, 0x0010},
+				{0x0208, 0x0010},
+				{0x020A, 0x0010},
+				{0x020C, 0x0010},
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWON},
+			};
+
+			struct mt9p012_i2c_reg_conf ipc_tbl2[] = {
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWOFF},
+				{REG_VT_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_pix_clk_div},
+				{REG_VT_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_sys_clk_div},
+				{REG_PRE_PLL_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].pre_pll_clk_div},
+				{REG_PLL_MULTIPLIER,
+				 mt9p012_regs.reg_pat[rt].pll_multiplier},
+				{REG_OP_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_pix_clk_div},
+				{REG_OP_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_sys_clk_div},
+#ifdef MT9P012_REV_7
+				{0x30B0, 0x0001},
+				{0x308E, 0xE060},
+				{0x3092, 0x0A52},
+				{0x3094, 0x4656},
+				{0x3096, 0x5652},
+				{0x30CA, 0x8006},
+				{0x312A, 0xDD02},
+				{0x312C, 0x00E4},
+				{0x3170, 0x299A},
+#endif
+				/* optimized settings for noise */
+				{0x3088, 0x6FF6},
+				{0x3154, 0x0282},
+				{0x3156, 0x0381},
+				{0x3162, 0x04CE},
+				{0x0204, 0x0010},
+				{0x0206, 0x0010},
+				{0x0208, 0x0010},
+				{0x020A, 0x0010},
+				{0x020C, 0x0010},
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWON},
+			};
+
+			struct mt9p012_i2c_reg_conf ipc_tbl3[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD},
+				/* Set preview or snapshot mode */
+				{REG_ROW_SPEED,
+				 mt9p012_regs.reg_pat[rt].row_speed},
+				{REG_X_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].x_addr_start},
+				{REG_X_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].x_addr_end},
+				{REG_Y_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].y_addr_start},
+				{REG_Y_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].y_addr_end},
+				{REG_READ_MODE,
+				 mt9p012_regs.reg_pat[rt].read_mode},
+				{REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m},
+				{REG_X_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].x_output_size},
+				{REG_Y_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].y_output_size},
+				{REG_LINE_LENGTH_PCK,
+				 mt9p012_regs.reg_pat[rt].line_length_pck},
+				{REG_FRAME_LENGTH_LINES,
+				 mt9p012_regs.reg_pat[rt].frame_length_lines},
+				{REG_COARSE_INT_TIME,
+				 mt9p012_regs.reg_pat[rt].coarse_int_time},
+				{REG_FINE_INTEGRATION_TIME,
+				 mt9p012_regs.reg_pat[rt].fine_int_time},
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE},
+			};
+
+			/* reset fps_divider */
+			mt9p012_ctrl->fps_divider = 1 * 0x0400;
+
+			rc = mt9p012_i2c_write_w_table(&ipc_tbl1[0],
+						       ARRAY_SIZE(ipc_tbl1));
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_i2c_write_w_table(&ipc_tbl2[0],
+						       ARRAY_SIZE(ipc_tbl2));
+			if (rc < 0)
+				return rc;
+
+			mdelay(5);
+
+			rc = mt9p012_i2c_write_w_table(&ipc_tbl3[0],
+						       ARRAY_SIZE(ipc_tbl3));
+			if (rc < 0)
+				return rc;
+
+			/* load lens shading */
+			rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+						 REG_GROUPED_PARAMETER_HOLD,
+						 GROUPED_PARAMETER_HOLD);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_set_lc();
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+						 REG_GROUPED_PARAMETER_HOLD,
+						 GROUPED_PARAMETER_UPDATE);
+
+			if (rc < 0)
+				return rc;
+		}
+		break;		/* case REG_INIT: */
+
+	default:
+		rc = -EINVAL;
+		break;
+	}			/* switch (rupdate) */
+
+	return rc;
+}
+
+static int mt9p012_video_config(int mode, int res)
+{
+	int rc;
+
+	switch (res) {
+	case QTR_SIZE:
+		rc = mt9p012_setting(UPDATE_PERIODIC, RES_PREVIEW);
+		if (rc < 0)
+			return rc;
+
+		CDBG("mt9p012 sensor configuration done!\n");
+		break;
+
+	case FULL_SIZE:
+		rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+		if (rc < 0)
+			return rc;
+
+		break;
+
+	default:
+		return 0;
+	}			/* switch */
+
+	mt9p012_ctrl->prev_res = res;
+	mt9p012_ctrl->curr_res = res;
+	mt9p012_ctrl->sensormode = mode;
+
+	rc = mt9p012_write_exp_gain(mt9p012_ctrl->my_reg_gain,
+				    mt9p012_ctrl->my_reg_line_count);
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER, 0x10cc | 0x0002);
+
+	return rc;
+}
+
+static int mt9p012_snapshot_config(int mode)
+{
+	int rc = 0;
+
+	rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res;
+
+	mt9p012_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int mt9p012_raw_snapshot_config(int mode)
+{
+	int rc = 0;
+
+	rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res;
+
+	mt9p012_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int mt9p012_power_down(void)
+{
+	int rc = 0;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWOFF);
+
+	mdelay(5);
+	return rc;
+}
+
+static int mt9p012_move_focus(int direction, int num_steps)
+{
+	int16_t step_direction;
+	int16_t actual_step;
+	int16_t next_position;
+	uint8_t code_val_msb, code_val_lsb;
+
+	if (num_steps > MT9P012_TOTAL_STEPS_NEAR_TO_FAR)
+		num_steps = MT9P012_TOTAL_STEPS_NEAR_TO_FAR;
+	else if (num_steps == 0) {
+		CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+		return -EINVAL;
+	}
+
+	if (direction == MOVE_NEAR)
+		step_direction = 16;	/* 10bit */
+	else if (direction == MOVE_FAR)
+		step_direction = -16;	/* 10 bit */
+	else {
+		CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+		return -EINVAL;
+	}
+
+	if (mt9p012_ctrl->curr_lens_pos < mt9p012_ctrl->init_curr_lens_pos)
+		mt9p012_ctrl->curr_lens_pos = mt9p012_ctrl->init_curr_lens_pos;
+
+	actual_step = (int16_t) (step_direction * (int16_t) num_steps);
+	next_position = (int16_t) (mt9p012_ctrl->curr_lens_pos + actual_step);
+
+	if (next_position > 1023)
+		next_position = 1023;
+	else if (next_position < 0)
+		next_position = 0;
+
+	code_val_msb = next_position >> 4;
+	code_val_lsb = (next_position & 0x000F) << 4;
+	/* code_val_lsb |= mode_mask; */
+
+	/* Writing the digital code for current to the actuator */
+	if (mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1,
+				code_val_msb, code_val_lsb) < 0) {
+		CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+		return -EBUSY;
+	}
+
+	/* Storing the current lens Position */
+	mt9p012_ctrl->curr_lens_pos = next_position;
+
+	return 0;
+}
+
+static int mt9p012_set_default_focus(void)
+{
+	int rc = 0;
+	uint8_t code_val_msb, code_val_lsb;
+
+	code_val_msb = 0x00;
+	code_val_lsb = 0x00;
+
+	/* Write the digital code for current to the actuator */
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1,
+				 code_val_msb, code_val_lsb);
+
+	mt9p012_ctrl->curr_lens_pos = 0;
+	mt9p012_ctrl->init_curr_lens_pos = 0;
+
+	return rc;
+}
+
+static int mt9p012_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int mt9p012_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int rc;
+	uint16_t chipid;
+
+	rc = gpio_request(data->sensor_reset, "mt9p012");
+	if (!rc)
+		gpio_direction_output(data->sensor_reset, 1);
+	else
+		goto init_probe_done;
+
+	mdelay(20);
+
+	/* RESET the sensor image part via I2C command */
+	CDBG("mt9p012_sensor_init(): reseting sensor.\n");
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER, 0x10CC | 0x0001);
+	if (rc < 0) {
+		CDBG("sensor reset failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	mdelay(MT9P012_RESET_DELAY_MSECS);
+
+	/* 3. Read sensor Model ID: */
+	rc = mt9p012_i2c_read_w(mt9p012_client->addr,
+				MT9P012_REG_MODEL_ID, &chipid);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	/* 4. Compare sensor ID to MT9T012VC ID: */
+	if (chipid != MT9P012_MODEL_ID) {
+		CDBG("mt9p012 wrong model_id = 0x%x\n", chipid);
+		rc = -ENODEV;
+		goto init_probe_fail;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x306E, 0x9000);
+	if (rc < 0) {
+		CDBG("REV_7 write failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	/* RESET_REGISTER, enable parallel interface and disable serialiser */
+	CDBG("mt9p012_sensor_init(): enabling parallel interface.\n");
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x301A, 0x10CC);
+	if (rc < 0) {
+		CDBG("enable parallel interface failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	/* To disable the 2 extra lines */
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3064, 0x0805);
+
+	if (rc < 0) {
+		CDBG("disable the 2 extra lines failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	mdelay(MT9P012_RESET_DELAY_MSECS);
+	goto init_probe_done;
+
+init_probe_fail:
+	mt9p012_probe_init_done(data);
+init_probe_done:
+	return rc;
+}
+
+static int mt9p012_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int rc;
+
+	mt9p012_ctrl = kzalloc(sizeof(struct mt9p012_ctrl), GFP_KERNEL);
+	if (!mt9p012_ctrl) {
+		CDBG("mt9p012_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+
+	mt9p012_ctrl->fps_divider = 1 * 0x00000400;
+	mt9p012_ctrl->pict_fps_divider = 1 * 0x00000400;
+	mt9p012_ctrl->set_test = TEST_OFF;
+	mt9p012_ctrl->prev_res = QTR_SIZE;
+	mt9p012_ctrl->pict_res = FULL_SIZE;
+
+	if (data)
+		mt9p012_ctrl->sensordata = data;
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(MT9P012_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	msm_camio_camif_pad_reg_reset();
+	mdelay(20);
+
+	rc = mt9p012_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail1;
+
+	if (mt9p012_ctrl->prev_res == QTR_SIZE)
+		rc = mt9p012_setting(REG_INIT, RES_PREVIEW);
+	else
+		rc = mt9p012_setting(REG_INIT, RES_CAPTURE);
+
+	if (rc < 0) {
+		CDBG("mt9p012_setting failed. rc = %d\n", rc);
+		goto init_fail1;
+	}
+
+	/* sensor : output enable */
+	CDBG("mt9p012_sensor_open_init(): enabling output.\n");
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWON);
+	if (rc < 0) {
+		CDBG("sensor output enable failed. rc = %d\n", rc);
+		goto init_fail1;
+	}
+
+	/* TODO: enable AF actuator */
+#if 0
+	CDBG("enable AF actuator, gpio = %d\n",
+	     mt9p012_ctrl->sensordata->vcm_pwd);
+	rc = gpio_request(mt9p012_ctrl->sensordata->vcm_pwd, "mt9p012");
+	if (!rc)
+		gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 1);
+	else {
+		CDBG("mt9p012_ctrl gpio request failed!\n");
+		goto init_fail1;
+	}
+	mdelay(20);
+
+	rc = mt9p012_set_default_focus();
+#endif
+	if (rc >= 0)
+		goto init_done;
+
+	/* TODO:
+	 * gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 0);
+	 * gpio_free(mt9p012_ctrl->sensordata->vcm_pwd); */
+init_fail1:
+	mt9p012_probe_init_done(data);
+	kfree(mt9p012_ctrl);
+init_done:
+	return rc;
+}
+
+static int mt9p012_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&mt9p012_wait_queue);
+	return 0;
+}
+
+static int mt9p012_set_sensor_mode(int mode, int res)
+{
+	int rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = mt9p012_video_config(mode, res);
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		rc = mt9p012_snapshot_config(mode);
+		break;
+
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = mt9p012_raw_snapshot_config(mode);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+int mt9p012_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	int rc = 0;
+
+	if (copy_from_user(&cdata,
+			   (void *)argp, sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		mt9p012_get_pict_fps(cdata.cfg.gfps.prevfps,
+				     &(cdata.cfg.gfps.pictfps));
+
+		if (copy_to_user((void *)argp, &cdata,
+				 sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf = mt9p012_get_prev_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl = mt9p012_get_prev_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf = mt9p012_get_pict_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl = mt9p012_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc = mt9p012_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = mt9p012_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc = mt9p012_write_exp_gain(cdata.cfg.exp_gain.gain,
+					    cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_PICT_EXP_GAIN:
+		CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__);
+		rc = mt9p012_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+					       cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_MODE:
+		rc = mt9p012_set_sensor_mode(cdata.mode, cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = mt9p012_power_down();
+		break;
+
+	case CFG_MOVE_FOCUS:
+		CDBG("mt9p012_ioctl: CFG_MOVE_FOCUS: cdata.cfg.focus.dir=%d "
+		     "cdata.cfg.focus.steps=%d\n",
+		     cdata.cfg.focus.dir, cdata.cfg.focus.steps);
+		rc = mt9p012_move_focus(cdata.cfg.focus.dir,
+					cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = mt9p012_set_default_focus();
+		break;
+
+	case CFG_SET_LENS_SHADING:
+		CDBG("%s: CFG_SET_LENS_SHADING\n", __func__);
+		rc = mt9p012_lens_shading_enable(cdata.cfg.lens_shading);
+		break;
+
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = MT9P012_STEPS_NEAR_TO_CLOSEST_INF;
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_EFFECT:
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+int mt9p012_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	mt9p012_power_down();
+
+	gpio_direction_output(mt9p012_ctrl->sensordata->sensor_reset, 0);
+	gpio_free(mt9p012_ctrl->sensordata->sensor_reset);
+
+	gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 0);
+	gpio_free(mt9p012_ctrl->sensordata->vcm_pwd);
+
+	kfree(mt9p012_ctrl);
+	mt9p012_ctrl = NULL;
+
+	CDBG("mt9p012_release completed\n");
+
+	return rc;
+}
+
+static int mt9p012_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("mt9p012_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	mt9p012_sensorw = kzalloc(sizeof(struct mt9p012_work), GFP_KERNEL);
+	if (!mt9p012_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, mt9p012_sensorw);
+	mt9p012_init_client(client);
+	mt9p012_client = client;
+
+	mdelay(50);
+
+	CDBG("mt9p012_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("mt9p012_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static const struct i2c_device_id mt9p012_i2c_id[] = {
+	{"mt9p012", 0},
+	{}
+};
+
+static struct i2c_driver mt9p012_i2c_driver = {
+	.id_table = mt9p012_i2c_id,
+	.probe = mt9p012_i2c_probe,
+	.remove = __exit_p(mt9p012_i2c_remove),
+	.driver = {
+		   .name = "mt9p012",
+		   },
+};
+
+static int mt9p012_sensor_probe(const struct msm_camera_sensor_info *info,
+				struct msm_sensor_ctrl *s)
+{
+	int rc = i2c_add_driver(&mt9p012_i2c_driver);
+	if (rc < 0 || mt9p012_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_done;
+	}
+
+	msm_camio_clk_rate_set(MT9P012_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	rc = mt9p012_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_done;
+
+	s->s_init = mt9p012_sensor_open_init;
+	s->s_release = mt9p012_sensor_release;
+	s->s_config = mt9p012_sensor_config;
+	mt9p012_probe_init_done(info);
+
+probe_done:
+	CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
+	return rc;
+}
+
+static int __mt9p012_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, mt9p012_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __mt9p012_probe,
+	.driver = {
+		   .name = "msm_camera_mt9p012",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __init mt9p012_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9p012_init);
diff --git a/drivers/media/video/msm/mt9p012_reg.c b/drivers/media/video/msm/mt9p012_reg.c
new file mode 100644
index 0000000..713a061
--- /dev/null
+++ b/drivers/media/video/msm/mt9p012_reg.c
@@ -0,0 +1,580 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "mt9p012.h"
+#include <linux/kernel.h>
+
+/*Micron settings from Applications for lower power consumption.*/
+struct reg_struct mt9p012_reg_pat[2] = {
+	{			/* Preview */
+	 /* vt_pix_clk_div          REG=0x0300 */
+	 6,			/* 5 */
+
+	 /* vt_sys_clk_div          REG=0x0302 */
+	 1,
+
+	 /* pre_pll_clk_div         REG=0x0304 */
+	 2,
+
+	 /* pll_multiplier          REG=0x0306 */
+	 60,
+
+	 /* op_pix_clk_div          REG=0x0308 */
+	 8,			/* 10 */
+
+	 /* op_sys_clk_div          REG=0x030A */
+	 1,
+
+	 /* scale_m                 REG=0x0404 */
+	 16,
+
+	 /* row_speed               REG=0x3016 */
+	 0x0111,
+
+	 /* x_addr_start            REG=0x3004 */
+	 8,
+
+	 /* x_addr_end              REG=0x3008 */
+	 2597,
+
+	 /* y_addr_start            REG=0x3002 */
+	 8,
+
+	 /* y_addr_end              REG=0x3006 */
+	 1949,
+
+	 /* read_mode               REG=0x3040
+	  * Preview 2x2 skipping */
+	 0x00C3,
+
+	 /* x_output_size           REG=0x034C */
+	 1296,
+
+	 /* y_output_size           REG=0x034E */
+	 972,
+
+	 /* line_length_pck         REG=0x300C */
+	 3784,
+
+	 /* frame_length_lines      REG=0x300A */
+	 1057,
+
+	 /* coarse_integration_time REG=0x3012 */
+	 16,
+
+	 /* fine_integration_time   REG=0x3014 */
+	 1764},
+	{			/*Snapshot */
+	 /* vt_pix_clk_div          REG=0x0300 */
+	 6,
+
+	 /* vt_sys_clk_div          REG=0x0302 */
+	 1,
+
+	 /* pre_pll_clk_div         REG=0x0304 */
+	 2,
+
+	 /* pll_multiplier          REG=0x0306
+	  * 60 for 10fps snapshot */
+	 60,
+
+	 /* op_pix_clk_div          REG=0x0308 */
+	 8,
+
+	 /* op_sys_clk_div          REG=0x030A */
+	 1,
+
+	 /* scale_m                 REG=0x0404 */
+	 16,
+
+	 /* row_speed               REG=0x3016 */
+	 0x0111,
+
+	 /* x_addr_start            REG=0x3004 */
+	 8,
+
+	 /* x_addr_end              REG=0x3008 */
+	 2615,
+
+	 /* y_addr_start            REG=0x3002 */
+	 8,
+
+	 /* y_addr_end              REG=0x3006 */
+	 1967,
+
+	 /* read_mode               REG=0x3040 */
+	 0x0041,
+
+	 /* x_output_size           REG=0x034C */
+	 2608,
+
+	 /* y_output_size           REG=0x034E */
+	 1960,
+
+	 /* line_length_pck         REG=0x300C */
+	 3911,
+
+	 /* frame_length_lines      REG=0x300A //10 fps snapshot */
+	 2045,
+
+	 /* coarse_integration_time REG=0x3012 */
+	 16,
+
+	 /* fine_integration_time   REG=0x3014 */
+	 882}
+};
+
+struct mt9p012_i2c_reg_conf mt9p012_test_tbl[] = {
+	{0x3044, 0x0544 & 0xFBFF},
+	{0x30CA, 0x0004 | 0x0001},
+	{0x30D4, 0x9020 & 0x7FFF},
+	{0x31E0, 0x0003 & 0xFFFE},
+	{0x3180, 0x91FF & 0x7FFF},
+	{0x301A, (0x10CC | 0x8000) & 0xFFF7},
+	{0x301E, 0x0000},
+	{0x3780, 0x0000},
+};
+
+struct mt9p012_i2c_reg_conf mt9p012_lc_tbl[] = {
+	/* [Lens shading 85 Percent TL84] */
+	/* P_RD_P0Q0 */
+	{0x360A, 0x7FEF},
+	/* P_RD_P0Q1 */
+	{0x360C, 0x232C},
+	/* P_RD_P0Q2 */
+	{0x360E, 0x7050},
+	/* P_RD_P0Q3 */
+	{0x3610, 0xF3CC},
+	/* P_RD_P0Q4 */
+	{0x3612, 0x89D1},
+	/* P_RD_P1Q0 */
+	{0x364A, 0xBE0D},
+	/* P_RD_P1Q1 */
+	{0x364C, 0x9ACB},
+	/* P_RD_P1Q2 */
+	{0x364E, 0x2150},
+	/* P_RD_P1Q3 */
+	{0x3650, 0xB26B},
+	/* P_RD_P1Q4 */
+	{0x3652, 0x9511},
+	/* P_RD_P2Q0 */
+	{0x368A, 0x2151},
+	/* P_RD_P2Q1 */
+	{0x368C, 0x00AD},
+	/* P_RD_P2Q2 */
+	{0x368E, 0x8334},
+	/* P_RD_P2Q3 */
+	{0x3690, 0x478E},
+	/* P_RD_P2Q4 */
+	{0x3692, 0x0515},
+	/* P_RD_P3Q0 */
+	{0x36CA, 0x0710},
+	/* P_RD_P3Q1 */
+	{0x36CC, 0x452D},
+	/* P_RD_P3Q2 */
+	{0x36CE, 0xF352},
+	/* P_RD_P3Q3 */
+	{0x36D0, 0x190F},
+	/* P_RD_P3Q4 */
+	{0x36D2, 0x4413},
+	/* P_RD_P4Q0 */
+	{0x370A, 0xD112},
+	/* P_RD_P4Q1 */
+	{0x370C, 0xF50F},
+	/* P_RD_P4Q2 */
+	{0x370C, 0xF50F},
+	/* P_RD_P4Q3 */
+	{0x3710, 0xDC11},
+	/* P_RD_P4Q4 */
+	{0x3712, 0xD776},
+	/* P_GR_P0Q0 */
+	{0x3600, 0x1750},
+	/* P_GR_P0Q1 */
+	{0x3602, 0xF0AC},
+	/* P_GR_P0Q2 */
+	{0x3604, 0x4711},
+	/* P_GR_P0Q3 */
+	{0x3606, 0x07CE},
+	/* P_GR_P0Q4 */
+	{0x3608, 0x96B2},
+	/* P_GR_P1Q0 */
+	{0x3640, 0xA9AE},
+	/* P_GR_P1Q1 */
+	{0x3642, 0xF9AC},
+	/* P_GR_P1Q2 */
+	{0x3644, 0x39F1},
+	/* P_GR_P1Q3 */
+	{0x3646, 0x016F},
+	/* P_GR_P1Q4 */
+	{0x3648, 0x8AB2},
+	/* P_GR_P2Q0 */
+	{0x3680, 0x1752},
+	/* P_GR_P2Q1 */
+	{0x3682, 0x70F0},
+	/* P_GR_P2Q2 */
+	{0x3684, 0x83F5},
+	/* P_GR_P2Q3 */
+	{0x3686, 0x8392},
+	/* P_GR_P2Q4 */
+	{0x3688, 0x1FD6},
+	/* P_GR_P3Q0 */
+	{0x36C0, 0x1131},
+	/* P_GR_P3Q1 */
+	{0x36C2, 0x3DAF},
+	/* P_GR_P3Q2 */
+	{0x36C4, 0x89B4},
+	/* P_GR_P3Q3 */
+	{0x36C6, 0xA391},
+	/* P_GR_P3Q4 */
+	{0x36C8, 0x1334},
+	/* P_GR_P4Q0 */
+	{0x3700, 0xDC13},
+	/* P_GR_P4Q1 */
+	{0x3702, 0xD052},
+	/* P_GR_P4Q2 */
+	{0x3704, 0x5156},
+	/* P_GR_P4Q3 */
+	{0x3706, 0x1F13},
+	/* P_GR_P4Q4 */
+	{0x3708, 0x8C38},
+	/* P_BL_P0Q0 */
+	{0x3614, 0x0050},
+	/* P_BL_P0Q1 */
+	{0x3616, 0xBD4C},
+	/* P_BL_P0Q2 */
+	{0x3618, 0x41B0},
+	/* P_BL_P0Q3 */
+	{0x361A, 0x660D},
+	/* P_BL_P0Q4 */
+	{0x361C, 0xC590},
+	/* P_BL_P1Q0 */
+	{0x3654, 0x87EC},
+	/* P_BL_P1Q1 */
+	{0x3656, 0xE44C},
+	/* P_BL_P1Q2 */
+	{0x3658, 0x302E},
+	/* P_BL_P1Q3 */
+	{0x365A, 0x106E},
+	/* P_BL_P1Q4 */
+	{0x365C, 0xB58E},
+	/* P_BL_P2Q0 */
+	{0x3694, 0x0DD1},
+	/* P_BL_P2Q1 */
+	{0x3696, 0x2A50},
+	/* P_BL_P2Q2 */
+	{0x3698, 0xC793},
+	/* P_BL_P2Q3 */
+	{0x369A, 0xE8F1},
+	/* P_BL_P2Q4 */
+	{0x369C, 0x4174},
+	/* P_BL_P3Q0 */
+	{0x36D4, 0x01EF},
+	/* P_BL_P3Q1 */
+	{0x36D6, 0x06CF},
+	/* P_BL_P3Q2 */
+	{0x36D8, 0x8D91},
+	/* P_BL_P3Q3 */
+	{0x36DA, 0x91F0},
+	/* P_BL_P3Q4 */
+	{0x36DC, 0x52EF},
+	/* P_BL_P4Q0 */
+	{0x3714, 0xA6D2},
+	/* P_BL_P4Q1 */
+	{0x3716, 0xA312},
+	/* P_BL_P4Q2 */
+	{0x3718, 0x2695},
+	/* P_BL_P4Q3 */
+	{0x371A, 0x3953},
+	/* P_BL_P4Q4 */
+	{0x371C, 0x9356},
+	/* P_GB_P0Q0 */
+	{0x361E, 0x7EAF},
+	/* P_GB_P0Q1 */
+	{0x3620, 0x2A4C},
+	/* P_GB_P0Q2 */
+	{0x3622, 0x49F0},
+	{0x3624, 0xF1EC},
+	/* P_GB_P0Q4 */
+	{0x3626, 0xC670},
+	/* P_GB_P1Q0 */
+	{0x365E, 0x8E0C},
+	/* P_GB_P1Q1 */
+	{0x3660, 0xC2A9},
+	/* P_GB_P1Q2 */
+	{0x3662, 0x274F},
+	/* P_GB_P1Q3 */
+	{0x3664, 0xADAB},
+	/* P_GB_P1Q4 */
+	{0x3666, 0x8EF0},
+	/* P_GB_P2Q0 */
+	{0x369E, 0x09B1},
+	/* P_GB_P2Q1 */
+	{0x36A0, 0xAA2E},
+	/* P_GB_P2Q2 */
+	{0x36A2, 0xC3D3},
+	/* P_GB_P2Q3 */
+	{0x36A4, 0x7FAF},
+	/* P_GB_P2Q4 */
+	{0x36A6, 0x3F34},
+	/* P_GB_P3Q0 */
+	{0x36DE, 0x4C8F},
+	/* P_GB_P3Q1 */
+	{0x36E0, 0x886E},
+	/* P_GB_P3Q2 */
+	{0x36E2, 0xE831},
+	/* P_GB_P3Q3 */
+	{0x36E4, 0x1FD0},
+	/* P_GB_P3Q4 */
+	{0x36E6, 0x1192},
+	/* P_GB_P4Q0 */
+	{0x371E, 0xB952},
+	/* P_GB_P4Q1 */
+	{0x3720, 0x6DCF},
+	/* P_GB_P4Q2 */
+	{0x3722, 0x1B55},
+	/* P_GB_P4Q3 */
+	{0x3724, 0xA112},
+	/* P_GB_P4Q4 */
+	{0x3726, 0x82F6},
+	/* POLY_ORIGIN_C */
+	{0x3782, 0x0510},
+	/* POLY_ORIGIN_R  */
+	{0x3784, 0x0390},
+	/* POLY_SC_ENABLE */
+	{0x3780, 0x8000},
+};
+
+/* rolloff table for illuminant A */
+struct mt9p012_i2c_reg_conf mt9p012_rolloff_tbl[] = {
+	/* P_RD_P0Q0 */
+	{0x360A, 0x7FEF},
+	/* P_RD_P0Q1 */
+	{0x360C, 0x232C},
+	/* P_RD_P0Q2 */
+	{0x360E, 0x7050},
+	/* P_RD_P0Q3 */
+	{0x3610, 0xF3CC},
+	/* P_RD_P0Q4 */
+	{0x3612, 0x89D1},
+	/* P_RD_P1Q0 */
+	{0x364A, 0xBE0D},
+	/* P_RD_P1Q1 */
+	{0x364C, 0x9ACB},
+	/* P_RD_P1Q2 */
+	{0x364E, 0x2150},
+	/* P_RD_P1Q3 */
+	{0x3650, 0xB26B},
+	/* P_RD_P1Q4 */
+	{0x3652, 0x9511},
+	/* P_RD_P2Q0 */
+	{0x368A, 0x2151},
+	/* P_RD_P2Q1 */
+	{0x368C, 0x00AD},
+	/* P_RD_P2Q2 */
+	{0x368E, 0x8334},
+	/* P_RD_P2Q3 */
+	{0x3690, 0x478E},
+	/* P_RD_P2Q4 */
+	{0x3692, 0x0515},
+	/* P_RD_P3Q0 */
+	{0x36CA, 0x0710},
+	/* P_RD_P3Q1 */
+	{0x36CC, 0x452D},
+	/* P_RD_P3Q2 */
+	{0x36CE, 0xF352},
+	/* P_RD_P3Q3 */
+	{0x36D0, 0x190F},
+	/* P_RD_P3Q4 */
+	{0x36D2, 0x4413},
+	/* P_RD_P4Q0 */
+	{0x370A, 0xD112},
+	/* P_RD_P4Q1 */
+	{0x370C, 0xF50F},
+	/* P_RD_P4Q2 */
+	{0x370E, 0x6375},
+	/* P_RD_P4Q3 */
+	{0x3710, 0xDC11},
+	/* P_RD_P4Q4 */
+	{0x3712, 0xD776},
+	/* P_GR_P0Q0 */
+	{0x3600, 0x1750},
+	/* P_GR_P0Q1 */
+	{0x3602, 0xF0AC},
+	/* P_GR_P0Q2 */
+	{0x3604, 0x4711},
+	/* P_GR_P0Q3 */
+	{0x3606, 0x07CE},
+	/* P_GR_P0Q4 */
+	{0x3608, 0x96B2},
+	/* P_GR_P1Q0 */
+	{0x3640, 0xA9AE},
+	/* P_GR_P1Q1 */
+	{0x3642, 0xF9AC},
+	/* P_GR_P1Q2 */
+	{0x3644, 0x39F1},
+	/* P_GR_P1Q3 */
+	{0x3646, 0x016F},
+	/* P_GR_P1Q4 */
+	{0x3648, 0x8AB2},
+	/* P_GR_P2Q0 */
+	{0x3680, 0x1752},
+	/* P_GR_P2Q1 */
+	{0x3682, 0x70F0},
+	/* P_GR_P2Q2 */
+	{0x3684, 0x83F5},
+	/* P_GR_P2Q3 */
+	{0x3686, 0x8392},
+	/* P_GR_P2Q4 */
+	{0x3688, 0x1FD6},
+	/* P_GR_P3Q0 */
+	{0x36C0, 0x1131},
+	/* P_GR_P3Q1 */
+	{0x36C2, 0x3DAF},
+	/* P_GR_P3Q2 */
+	{0x36C4, 0x89B4},
+	/* P_GR_P3Q3 */
+	{0x36C6, 0xA391},
+	/* P_GR_P3Q4 */
+	{0x36C8, 0x1334},
+	/* P_GR_P4Q0 */
+	{0x3700, 0xDC13},
+	/* P_GR_P4Q1 */
+	{0x3702, 0xD052},
+	/* P_GR_P4Q2 */
+	{0x3704, 0x5156},
+	/* P_GR_P4Q3 */
+	{0x3706, 0x1F13},
+	/* P_GR_P4Q4 */
+	{0x3708, 0x8C38},
+	/* P_BL_P0Q0 */
+	{0x3614, 0x0050},
+	/* P_BL_P0Q1 */
+	{0x3616, 0xBD4C},
+	/* P_BL_P0Q2 */
+	{0x3618, 0x41B0},
+	/* P_BL_P0Q3 */
+	{0x361A, 0x660D},
+	/* P_BL_P0Q4 */
+	{0x361C, 0xC590},
+	/* P_BL_P1Q0 */
+	{0x3654, 0x87EC},
+	/* P_BL_P1Q1 */
+	{0x3656, 0xE44C},
+	/* P_BL_P1Q2 */
+	{0x3658, 0x302E},
+	/* P_BL_P1Q3 */
+	{0x365A, 0x106E},
+	/* P_BL_P1Q4 */
+	{0x365C, 0xB58E},
+	/* P_BL_P2Q0 */
+	{0x3694, 0x0DD1},
+	/* P_BL_P2Q1 */
+	{0x3696, 0x2A50},
+	/* P_BL_P2Q2 */
+	{0x3698, 0xC793},
+	/* P_BL_P2Q3 */
+	{0x369A, 0xE8F1},
+	/* P_BL_P2Q4 */
+	{0x369C, 0x4174},
+	/* P_BL_P3Q0 */
+	{0x36D4, 0x01EF},
+	/* P_BL_P3Q1 */
+	{0x36D6, 0x06CF},
+	/* P_BL_P3Q2 */
+	{0x36D8, 0x8D91},
+	/* P_BL_P3Q3 */
+	{0x36DA, 0x91F0},
+	/* P_BL_P3Q4 */
+	{0x36DC, 0x52EF},
+	/* P_BL_P4Q0 */
+	{0x3714, 0xA6D2},
+	/* P_BL_P4Q1 */
+	{0x3716, 0xA312},
+	/* P_BL_P4Q2 */
+	{0x3718, 0x2695},
+	/* P_BL_P4Q3 */
+	{0x371A, 0x3953},
+	/* P_BL_P4Q4 */
+	{0x371C, 0x9356},
+	/* P_GB_P0Q0 */
+	{0x361E, 0x7EAF},
+	/* P_GB_P0Q1 */
+	{0x3620, 0x2A4C},
+	/* P_GB_P0Q2 */
+	{0x3622, 0x49F0},
+	{0x3624, 0xF1EC},
+	/* P_GB_P0Q4 */
+	{0x3626, 0xC670},
+	/* P_GB_P1Q0 */
+	{0x365E, 0x8E0C},
+	/* P_GB_P1Q1 */
+	{0x3660, 0xC2A9},
+	/* P_GB_P1Q2 */
+	{0x3662, 0x274F},
+	/* P_GB_P1Q3 */
+	{0x3664, 0xADAB},
+	/* P_GB_P1Q4 */
+	{0x3666, 0x8EF0},
+	/* P_GB_P2Q0 */
+	{0x369E, 0x09B1},
+	/* P_GB_P2Q1 */
+	{0x36A0, 0xAA2E},
+	/* P_GB_P2Q2 */
+	{0x36A2, 0xC3D3},
+	/* P_GB_P2Q3 */
+	{0x36A4, 0x7FAF},
+	/* P_GB_P2Q4 */
+	{0x36A6, 0x3F34},
+	/* P_GB_P3Q0 */
+	{0x36DE, 0x4C8F},
+	/* P_GB_P3Q1 */
+	{0x36E0, 0x886E},
+	/* P_GB_P3Q2 */
+	{0x36E2, 0xE831},
+	/* P_GB_P3Q3 */
+	{0x36E4, 0x1FD0},
+	/* P_GB_P3Q4 */
+	{0x36E6, 0x1192},
+	/* P_GB_P4Q0 */
+	{0x371E, 0xB952},
+	/* P_GB_P4Q1 */
+	{0x3720, 0x6DCF},
+	/* P_GB_P4Q2 */
+	{0x3722, 0x1B55},
+	/* P_GB_P4Q3 */
+	{0x3724, 0xA112},
+	/* P_GB_P4Q4 */
+	{0x3726, 0x82F6},
+	/* POLY_ORIGIN_C */
+	{0x3782, 0x0510},
+	/* POLY_ORIGIN_R  */
+	{0x3784, 0x0390},
+	/* POLY_SC_ENABLE */
+	{0x3780, 0x8000},
+};
+
+struct mt9p012_reg mt9p012_regs = {
+	.reg_pat = &mt9p012_reg_pat[0],
+	.reg_pat_size = ARRAY_SIZE(mt9p012_reg_pat),
+	.ttbl = &mt9p012_test_tbl[0],
+	.ttbl_size = ARRAY_SIZE(mt9p012_test_tbl),
+	.lctbl = &mt9p012_lc_tbl[0],
+	.lctbl_size = ARRAY_SIZE(mt9p012_lc_tbl),
+	.rftbl = &mt9p012_rolloff_tbl[0],
+	.rftbl_size = ARRAY_SIZE(mt9p012_rolloff_tbl)
+};
diff --git a/drivers/media/video/msm/mt9t013.c b/drivers/media/video/msm/mt9t013.c
new file mode 100644
index 0000000..e77904e
--- /dev/null
+++ b/drivers/media/video/msm/mt9t013.c
@@ -0,0 +1,1506 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include <asm/mach-types.h>
+#include "mt9t013.h"
+
+/*=============================================================
+	SENSOR REGISTER DEFINES
+==============================================================*/
+#define MT9T013_REG_MODEL_ID 		 0x0000
+#define MT9T013_MODEL_ID     		 0x2600
+#define REG_GROUPED_PARAMETER_HOLD   0x0104
+#define GROUPED_PARAMETER_HOLD       0x0100
+#define GROUPED_PARAMETER_UPDATE     0x0000
+#define REG_COARSE_INT_TIME          0x3012
+#define REG_VT_PIX_CLK_DIV           0x0300
+#define REG_VT_SYS_CLK_DIV           0x0302
+#define REG_PRE_PLL_CLK_DIV          0x0304
+#define REG_PLL_MULTIPLIER           0x0306
+#define REG_OP_PIX_CLK_DIV           0x0308
+#define REG_OP_SYS_CLK_DIV           0x030A
+#define REG_SCALE_M                  0x0404
+#define REG_FRAME_LENGTH_LINES       0x300A
+#define REG_LINE_LENGTH_PCK          0x300C
+#define REG_X_ADDR_START             0x3004
+#define REG_Y_ADDR_START             0x3002
+#define REG_X_ADDR_END               0x3008
+#define REG_Y_ADDR_END               0x3006
+#define REG_X_OUTPUT_SIZE            0x034C
+#define REG_Y_OUTPUT_SIZE            0x034E
+#define REG_FINE_INT_TIME            0x3014
+#define REG_ROW_SPEED                0x3016
+#define MT9T013_REG_RESET_REGISTER   0x301A
+#define MT9T013_RESET_REGISTER_PWON  0x10CC
+#define MT9T013_RESET_REGISTER_PWOFF 0x1008	/* 0x10C8 stop streaming */
+#define REG_READ_MODE                0x3040
+#define REG_GLOBAL_GAIN              0x305E
+#define REG_TEST_PATTERN_MODE        0x3070
+
+enum mt9t013_test_mode {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum mt9t013_resolution {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+
+enum mt9t013_reg_update {
+	REG_INIT, /* registers that need to be updated during initialization */
+	UPDATE_PERIODIC, /* registers that needs periodic I2C writes */
+	UPDATE_ALL, /* all registers will be updated */
+	UPDATE_INVALID
+};
+
+enum mt9t013_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+
+/* actuator's Slave Address */
+#define MT9T013_AF_I2C_ADDR   0x18
+
+/*
+* AF Total steps parameters
+*/
+#define MT9T013_TOTAL_STEPS_NEAR_TO_FAR    30
+
+/*
+ * Time in milisecs for waiting for the sensor to reset.
+ */
+#define MT9T013_RESET_DELAY_MSECS   66
+
+/* for 30 fps preview */
+#define MT9T013_DEFAULT_CLOCK_RATE  24000000
+#define MT9T013_DEFAULT_MAX_FPS     26
+
+/* FIXME: Changes from here */
+struct mt9t013_work {
+	struct work_struct work;
+};
+
+static struct mt9t013_work *mt9t013_sensorw;
+static struct i2c_client *mt9t013_client;
+
+struct mt9t013_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+
+	int sensormode;
+	uint32_t fps_divider;	/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;	/* init to 1 * 0x00000400 */
+
+	uint16_t curr_lens_pos;
+	uint16_t init_curr_lens_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+
+	enum mt9t013_resolution prev_res;
+	enum mt9t013_resolution pict_res;
+	enum mt9t013_resolution curr_res;
+	enum mt9t013_test_mode set_test;
+
+	unsigned short imgaddr;
+};
+
+static struct mt9t013_ctrl *mt9t013_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(mt9t013_wait_queue);
+
+static int mt9t013_i2c_rxdata(unsigned short saddr,
+			      unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+		 .addr = saddr,
+		 .flags = 0,
+		 .len = 2,
+		 .buf = rxdata,
+		 },
+		{
+		 .addr = saddr,
+		 .flags = I2C_M_RD,
+		 .len = length,
+		 .buf = rxdata,
+		 },
+	};
+
+	if (i2c_transfer(mt9t013_client->adapter, msgs, 2) < 0) {
+		pr_err("mt9t013_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mt9t013_i2c_read_w(unsigned short saddr,
+				  unsigned short raddr, unsigned short *rdata)
+{
+	int rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = mt9t013_i2c_rxdata(saddr, buf, 2);
+	if (rc < 0)
+		return rc;
+
+	*rdata = buf[0] << 8 | buf[1];
+
+	if (rc < 0)
+		pr_err("mt9t013_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int mt9t013_i2c_txdata(unsigned short saddr,
+				  unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+		 .addr = saddr,
+		 .flags = 0,
+		 .len = length,
+		 .buf = txdata,
+		 },
+	};
+
+	if (i2c_transfer(mt9t013_client->adapter, msg, 1) < 0) {
+		pr_err("mt9t013_i2c_txdata failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mt9t013_i2c_write_b(unsigned short saddr,
+				   unsigned short waddr, unsigned short wdata)
+{
+	int rc = -EIO;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = waddr;
+	buf[1] = wdata;
+	rc = mt9t013_i2c_txdata(saddr, buf, 2);
+
+	if (rc < 0)
+		pr_err("i2c_write failed, addr = 0x%x, val = 0x%x!\n",
+		       waddr, wdata);
+
+	return rc;
+}
+
+static int mt9t013_i2c_write_w(unsigned short saddr,
+				   unsigned short waddr, unsigned short wdata)
+{
+	int rc = -EIO;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+
+	rc = mt9t013_i2c_txdata(saddr, buf, 4);
+
+	if (rc < 0)
+		pr_err("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+		       waddr, wdata);
+
+	return rc;
+}
+
+static int mt9t013_i2c_write_w_table(struct mt9t013_i2c_reg_conf
+					 *reg_conf_tbl,
+					 int num_of_items_in_table)
+{
+	int i;
+	int rc = -EIO;
+
+	for (i = 0; i < num_of_items_in_table; i++) {
+		rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+					 reg_conf_tbl->waddr,
+					 reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+
+	return rc;
+}
+
+static int mt9t013_test(enum mt9t013_test_mode mo)
+{
+	int rc = 0;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	if (mo == TEST_OFF)
+		return 0;
+	else {
+		rc = mt9t013_i2c_write_w_table(mt9t013_regs.ttbl,
+					       mt9t013_regs.ttbl_size);
+		if (rc < 0)
+			return rc;
+		rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+					 REG_TEST_PATTERN_MODE, (uint16_t) mo);
+		if (rc < 0)
+			return rc;
+	}
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int mt9t013_set_lc(void)
+{
+	int rc;
+
+	rc = mt9t013_i2c_write_w_table(mt9t013_regs.lctbl,
+				       mt9t013_regs.lctbl_size);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int mt9t013_set_default_focus(uint8_t af_step)
+{
+	int rc = 0;
+	uint8_t code_val_msb, code_val_lsb;
+	code_val_msb = 0x01;
+	code_val_lsb = af_step;
+
+	/* Write the digital code for current to the actuator */
+	rc = mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR >> 1,
+				 code_val_msb, code_val_lsb);
+
+	mt9t013_ctrl->curr_lens_pos = 0;
+	mt9t013_ctrl->init_curr_lens_pos = 0;
+	return rc;
+}
+
+static void mt9t013_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider;	/*Q10 */
+	uint32_t pclk_mult;	/*Q10 */
+
+	if (mt9t013_ctrl->prev_res == QTR_SIZE) {
+		divider =
+		    (uint32_t) (((mt9t013_regs.reg_pat[RES_PREVIEW].
+				  frame_length_lines *
+				  mt9t013_regs.reg_pat[RES_PREVIEW].
+				  line_length_pck) * 0x00000400) /
+				(mt9t013_regs.reg_pat[RES_CAPTURE].
+				 frame_length_lines *
+				 mt9t013_regs.reg_pat[RES_CAPTURE].
+				 line_length_pck));
+
+		pclk_mult =
+		    (uint32_t) ((mt9t013_regs.reg_pat[RES_CAPTURE].
+				 pll_multiplier * 0x00000400) /
+				(mt9t013_regs.reg_pat[RES_PREVIEW].
+				 pll_multiplier));
+
+	} else {
+		/* full size resolution used for preview. */
+		divider = 0x00000400;	/*1.0 */
+		pclk_mult = 0x00000400;	/*1.0 */
+	}
+
+	/* Verify PCLK settings and frame sizes. */
+	*pfps =
+	    (uint16_t) (fps * divider * pclk_mult / 0x00000400 / 0x00000400);
+}
+
+static uint16_t mt9t013_get_prev_lines_pf(void)
+{
+	if (mt9t013_ctrl->prev_res == QTR_SIZE)
+		return mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines;
+	else
+		return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9t013_get_prev_pixels_pl(void)
+{
+	if (mt9t013_ctrl->prev_res == QTR_SIZE)
+		return mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck;
+	else
+		return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint16_t mt9t013_get_pict_lines_pf(void)
+{
+	return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9t013_get_pict_pixels_pl(void)
+{
+	return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint32_t mt9t013_get_pict_max_exp_lc(void)
+{
+	uint16_t snapshot_lines_per_frame;
+
+	if (mt9t013_ctrl->pict_res == QTR_SIZE) {
+		snapshot_lines_per_frame =
+		    mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1;
+	} else {
+		snapshot_lines_per_frame =
+		    mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1;
+	}
+
+	return snapshot_lines_per_frame * 24;
+}
+
+static int mt9t013_set_fps(struct fps_cfg *fps)
+{
+	/* input is new fps in Q8 format */
+	int rc = 0;
+
+	mt9t013_ctrl->fps_divider = fps->fps_div;
+	mt9t013_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return -EBUSY;
+
+	CDBG("mt9t013_set_fps: fps_div is %d, frame_rate is %d\n",
+	     fps->fps_div,
+	     (uint16_t) (mt9t013_regs.reg_pat[RES_PREVIEW].
+			 frame_length_lines * fps->fps_div / 0x00000400));
+
+	CDBG("mt9t013_set_fps: fps_mult is %d, frame_rate is %d\n",
+	     fps->f_mult,
+	     (uint16_t) (mt9t013_regs.reg_pat[RES_PREVIEW].
+			 line_length_pck * fps->f_mult / 0x00000400));
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 REG_LINE_LENGTH_PCK,
+				 (uint16_t) (mt9t013_regs.reg_pat[RES_PREVIEW].
+					     line_length_pck * fps->f_mult /
+					     0x00000400));
+	if (rc < 0)
+		return rc;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int mt9t013_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	const uint16_t max_legal_gain = 0x01FF;
+	uint32_t line_length_ratio = 0x00000400;
+	enum mt9t013_setting setting;
+	int rc = 0;
+
+	if (mt9t013_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		mt9t013_ctrl->my_reg_gain = gain;
+		mt9t013_ctrl->my_reg_line_count = (uint16_t) line;
+	}
+
+	if (gain > max_legal_gain)
+		gain = max_legal_gain;
+
+	/* Verify no overflow */
+	if (mt9t013_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
+		line = (uint32_t) (line * mt9t013_ctrl->fps_divider /
+				   0x00000400);
+
+		setting = RES_PREVIEW;
+
+	} else {
+		line = (uint32_t) (line * mt9t013_ctrl->pict_fps_divider /
+				   0x00000400);
+
+		setting = RES_CAPTURE;
+	}
+
+	/*Set digital gain to 1 */
+	gain |= 0x0200;
+
+	if ((mt9t013_regs.reg_pat[setting].frame_length_lines - 1) < line) {
+
+		line_length_ratio =
+		    (uint32_t) (line * 0x00000400) /
+		    (mt9t013_regs.reg_pat[setting].frame_length_lines - 1);
+	} else
+		line_length_ratio = 0x00000400;
+
+	/* There used to be PARAMETER_HOLD register write before and
+	 * after REG_GLOBAL_GAIN & REG_COARSE_INIT_TIME. This causes
+	 * aec oscillation. Hence removed. */
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr, REG_GLOBAL_GAIN, gain);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 REG_COARSE_INT_TIME,
+				 (uint16_t) ((uint32_t) line));
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int mt9t013_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int rc = 0;
+
+	rc = mt9t013_write_exp_gain(gain, line);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 MT9T013_REG_RESET_REGISTER, 0x10CC | 0x0002);
+
+	mdelay(5);
+
+	/* camera_timed_wait(snapshot_wait*exposure_ratio); */
+	return rc;
+}
+
+static int mt9t013_setting(enum mt9t013_reg_update rupdate,
+			       enum mt9t013_setting rt)
+{
+	int rc = 0;
+
+	switch (rupdate) {
+	case UPDATE_PERIODIC:{
+
+			if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+#if 0
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+						 MT9T013_REG_RESET_REGISTER,
+						 MT9T013_RESET_REGISTER_PWOFF);
+				if (rc < 0)
+					return rc;
+#endif
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_VT_PIX_CLK_DIV,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 vt_pix_clk_div);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_VT_SYS_CLK_DIV,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 vt_sys_clk_div);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_PRE_PLL_CLK_DIV,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 pre_pll_clk_div);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_PLL_MULTIPLIER,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 pll_multiplier);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_OP_PIX_CLK_DIV,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 op_pix_clk_div);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_OP_SYS_CLK_DIV,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 op_sys_clk_div);
+				if (rc < 0)
+					return rc;
+
+				mdelay(5);
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+						 REG_GROUPED_PARAMETER_HOLD,
+						 GROUPED_PARAMETER_HOLD);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_ROW_SPEED,
+							 mt9t013_regs.
+							 reg_pat[rt].row_speed);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_X_ADDR_START,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 x_addr_start);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_X_ADDR_END,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 x_addr_end);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_Y_ADDR_START,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 y_addr_start);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_Y_ADDR_END,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 y_addr_end);
+				if (rc < 0)
+					return rc;
+
+				if (machine_is_sapphire()) {
+					if (rt == 0)
+						rc = mt9t013_i2c_write_w
+						    (mt9t013_client->addr,
+						     REG_READ_MODE, 0x046F);
+					else
+						rc = mt9t013_i2c_write_w
+						    (mt9t013_client->addr,
+						     REG_READ_MODE, 0x0027);
+				} else
+					rc = mt9t013_i2c_write_w
+					    (mt9t013_client->addr,
+					     REG_READ_MODE,
+					     mt9t013_regs.reg_pat[rt].
+					     read_mode);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_SCALE_M,
+							 mt9t013_regs.
+							 reg_pat[rt].scale_m);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_X_OUTPUT_SIZE,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 x_output_size);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_Y_OUTPUT_SIZE,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 y_output_size);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_LINE_LENGTH_PCK,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 line_length_pck);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_FRAME_LENGTH_LINES,
+							 (mt9t013_regs.
+							  reg_pat[rt].
+							  frame_length_lines *
+							  mt9t013_ctrl->
+							  fps_divider /
+							  0x00000400));
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_COARSE_INT_TIME,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 coarse_int_time);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_FINE_INT_TIME,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 fine_int_time);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+						REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_UPDATE);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_test(mt9t013_ctrl->set_test);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+						MT9T013_REG_RESET_REGISTER,
+						MT9T013_RESET_REGISTER_PWON);
+				if (rc < 0)
+					return rc;
+
+				mdelay(5);
+
+				return rc;
+			}
+		}
+		break;
+
+		/*CAMSENSOR_REG_UPDATE_PERIODIC */
+	case REG_INIT:{
+			if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+						MT9T013_REG_RESET_REGISTER,
+						MT9T013_RESET_REGISTER_PWOFF);
+				if (rc < 0)
+					/* MODE_SELECT, stop streaming */
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_VT_PIX_CLK_DIV,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 vt_pix_clk_div);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_VT_SYS_CLK_DIV,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 vt_sys_clk_div);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_PRE_PLL_CLK_DIV,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 pre_pll_clk_div);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_PLL_MULTIPLIER,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 pll_multiplier);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_OP_PIX_CLK_DIV,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 op_pix_clk_div);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_OP_SYS_CLK_DIV,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 op_sys_clk_div);
+				if (rc < 0)
+					return rc;
+
+				mdelay(5);
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+						REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_HOLD);
+				if (rc < 0)
+					return rc;
+
+				/* additional power saving mode ok around
+				 * 38.2MHz
+				 */
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 0x3084, 0x2409);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 0x3092, 0x0A49);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 0x3094, 0x4949);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 0x3096, 0x4949);
+				if (rc < 0)
+					return rc;
+
+				/* Set preview or snapshot mode */
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_ROW_SPEED,
+							 mt9t013_regs.
+							 reg_pat[rt].row_speed);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_X_ADDR_START,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 x_addr_start);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_X_ADDR_END,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 x_addr_end);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_Y_ADDR_START,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 y_addr_start);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_Y_ADDR_END,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 y_addr_end);
+				if (rc < 0)
+					return rc;
+
+				if (machine_is_sapphire()) {
+					if (rt == 0)
+						rc = mt9t013_i2c_write_w
+						    (mt9t013_client->addr,
+						     REG_READ_MODE, 0x046F);
+					else
+						rc = mt9t013_i2c_write_w
+						    (mt9t013_client->addr,
+						     REG_READ_MODE, 0x0027);
+				} else
+					rc = mt9t013_i2c_write_w
+					    (mt9t013_client->addr,
+					     REG_READ_MODE,
+					     mt9t013_regs.reg_pat[rt].
+					     read_mode);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_SCALE_M,
+							 mt9t013_regs.
+							 reg_pat[rt].scale_m);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_X_OUTPUT_SIZE,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 x_output_size);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_Y_OUTPUT_SIZE,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 y_output_size);
+				if (rc < 0)
+					return 0;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_LINE_LENGTH_PCK,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 line_length_pck);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_FRAME_LENGTH_LINES,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 frame_length_lines);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_COARSE_INT_TIME,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 coarse_int_time);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+							 REG_FINE_INT_TIME,
+							 mt9t013_regs.
+							 reg_pat[rt].
+							 fine_int_time);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+						REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_UPDATE);
+				if (rc < 0)
+					return rc;
+
+				/* load lens shading */
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+						REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_HOLD);
+				if (rc < 0)
+					return rc;
+
+				/* most likely needs to be written only once. */
+				rc = mt9t013_set_lc();
+				if (rc < 0)
+					return -EBUSY;
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+						REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_UPDATE);
+				if (rc < 0)
+					return rc;
+
+				rc = mt9t013_test(mt9t013_ctrl->set_test);
+				if (rc < 0)
+					return rc;
+
+				mdelay(5);
+
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+						MT9T013_REG_RESET_REGISTER,
+						MT9T013_RESET_REGISTER_PWON);
+				if (rc < 0)
+					/* MODE_SELECT, stop streaming */
+					return rc;
+
+				CDBG("!!! mt9t013 !!! PowerOn is done!\n");
+				mdelay(5);
+				return rc;
+			}
+		} /* case CAMSENSOR_REG_INIT: */
+		break;
+
+		/*CAMSENSOR_REG_INIT */
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static int mt9t013_video_config(int mode, int res)
+{
+	int rc;
+
+	switch (res) {
+	case QTR_SIZE:
+		rc = mt9t013_setting(UPDATE_PERIODIC, RES_PREVIEW);
+		if (rc < 0)
+			return rc;
+		CDBG("sensor configuration done!\n");
+		break;
+
+	case FULL_SIZE:
+		rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
+		if (rc < 0)
+			return rc;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	mt9t013_ctrl->prev_res = res;
+	mt9t013_ctrl->curr_res = res;
+	mt9t013_ctrl->sensormode = mode;
+
+	return mt9t013_write_exp_gain(mt9t013_ctrl->my_reg_gain,
+				      mt9t013_ctrl->my_reg_line_count);
+}
+
+static int mt9t013_snapshot_config(int mode)
+{
+	int rc = 0;
+
+	rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res;
+	mt9t013_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int mt9t013_raw_snapshot_config(int mode)
+{
+	int rc = 0;
+
+	rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res;
+	mt9t013_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int mt9t013_power_down(void)
+{
+	int rc = 0;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 MT9T013_REG_RESET_REGISTER,
+				 MT9T013_RESET_REGISTER_PWOFF);
+	if (rc >= 0)
+		mdelay(5);
+	return rc;
+}
+
+static int mt9t013_move_focus(int direction, int num_steps)
+{
+	int16_t step_direction;
+	int16_t actual_step;
+	int16_t next_position;
+	int16_t break_steps[4];
+	uint8_t code_val_msb, code_val_lsb;
+	int16_t i;
+
+	if (num_steps > MT9T013_TOTAL_STEPS_NEAR_TO_FAR)
+		num_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR;
+	else if (num_steps == 0)
+		return -EINVAL;
+
+	if (direction == MOVE_NEAR)
+		step_direction = 4;
+	else if (direction == MOVE_FAR)
+		step_direction = -4;
+	else
+		return -EINVAL;
+
+	if (mt9t013_ctrl->curr_lens_pos < mt9t013_ctrl->init_curr_lens_pos)
+		mt9t013_ctrl->curr_lens_pos = mt9t013_ctrl->init_curr_lens_pos;
+
+	actual_step = (int16_t) (step_direction * (int16_t) num_steps);
+
+	for (i = 0; i < 4; i++)
+		break_steps[i] =
+		    actual_step / 4 * (i + 1) - actual_step / 4 * i;
+
+	for (i = 0; i < 4; i++) {
+		next_position = (int16_t)
+		    (mt9t013_ctrl->curr_lens_pos + break_steps[i]);
+
+		if (next_position > 255)
+			next_position = 255;
+		else if (next_position < 0)
+			next_position = 0;
+
+		code_val_msb =
+		    ((next_position >> 4) << 2) | ((next_position << 4) >> 6);
+
+		code_val_lsb = ((next_position & 0x03) << 6);
+
+		/* Writing the digital code for current to the actuator */
+		if (mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR >> 1,
+					code_val_msb, code_val_lsb) < 0)
+			return -EBUSY;
+
+		/* Storing the current lens Position */
+		mt9t013_ctrl->curr_lens_pos = next_position;
+
+		if (i < 3)
+			mdelay(1);
+	}
+
+	return 0;
+}
+
+static int mt9t013_sensor_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int mt9t013_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int rc;
+	uint16_t chipid;
+
+	rc = gpio_request(data->sensor_reset, "mt9t013");
+	if (!rc)
+		gpio_direction_output(data->sensor_reset, 1);
+	else
+		goto init_probe_done;
+
+	mdelay(20);
+
+	/* RESET the sensor image part via I2C command */
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 MT9T013_REG_RESET_REGISTER, 0x1009);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	/* 3. Read sensor Model ID: */
+	rc = mt9t013_i2c_read_w(mt9t013_client->addr,
+				MT9T013_REG_MODEL_ID, &chipid);
+
+	if (rc < 0)
+		goto init_probe_fail;
+
+	CDBG("mt9t013 model_id = 0x%x\n", chipid);
+
+	/* 4. Compare sensor ID to MT9T012VC ID: */
+	if (chipid != MT9T013_MODEL_ID) {
+		rc = -ENODEV;
+		goto init_probe_fail;
+	}
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr, 0x3064, 0x0805);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	mdelay(MT9T013_RESET_DELAY_MSECS);
+
+	goto init_probe_done;
+
+	/* sensor: output enable */
+#if 0
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 MT9T013_REG_RESET_REGISTER,
+				 MT9T013_RESET_REGISTER_PWON);
+
+	/* if this fails, the sensor is not the MT9T013 */
+	rc = mt9t013_set_default_focus(0);
+#endif
+
+init_probe_fail:
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+init_probe_done:
+	return rc;
+}
+
+static int mt9t013_poweron_af(void)
+{
+	int rc = 0;
+
+	/* enable AF actuator */
+	CDBG("enable AF actuator, gpio = %d\n",
+	     mt9t013_ctrl->sensordata->vcm_pwd);
+	rc = gpio_request(mt9t013_ctrl->sensordata->vcm_pwd, "mt9t013");
+	if (!rc) {
+		gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 0);
+		mdelay(20);
+		rc = mt9t013_set_default_focus(0);
+	} else
+		pr_err("%s, gpio_request failed (%d)!\n", __func__, rc);
+	return rc;
+}
+
+static void mt9t013_poweroff_af(void)
+{
+	gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 1);
+	gpio_free(mt9t013_ctrl->sensordata->vcm_pwd);
+}
+
+int mt9t013_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int rc;
+
+	mt9t013_ctrl = kzalloc(sizeof(struct mt9t013_ctrl), GFP_KERNEL);
+	if (!mt9t013_ctrl) {
+		pr_err("mt9t013_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+
+	mt9t013_ctrl->fps_divider = 1 * 0x00000400;
+	mt9t013_ctrl->pict_fps_divider = 1 * 0x00000400;
+	mt9t013_ctrl->set_test = TEST_OFF;
+	mt9t013_ctrl->prev_res = QTR_SIZE;
+	mt9t013_ctrl->pict_res = FULL_SIZE;
+
+	if (data)
+		mt9t013_ctrl->sensordata = data;
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	msm_camio_camif_pad_reg_reset();
+	mdelay(20);
+
+	rc = mt9t013_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail;
+
+	if (mt9t013_ctrl->prev_res == QTR_SIZE)
+		rc = mt9t013_setting(REG_INIT, RES_PREVIEW);
+	else
+		rc = mt9t013_setting(REG_INIT, RES_CAPTURE);
+
+	if (rc >= 0)
+		rc = mt9t013_poweron_af();
+
+	if (rc < 0)
+		goto init_fail;
+	else
+		goto init_done;
+
+init_fail:
+	kfree(mt9t013_ctrl);
+init_done:
+	return rc;
+}
+
+static int mt9t013_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&mt9t013_wait_queue);
+	return 0;
+}
+
+static int mt9t013_set_sensor_mode(int mode, int res)
+{
+	int rc = 0;
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = mt9t013_video_config(mode, res);
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		rc = mt9t013_snapshot_config(mode);
+		break;
+
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = mt9t013_raw_snapshot_config(mode);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* FIXME: what should we do if rc < 0? */
+	if (rc >= 0)
+		return mt9t013_i2c_write_w(mt9t013_client->addr,
+					   REG_GROUPED_PARAMETER_HOLD,
+					   GROUPED_PARAMETER_UPDATE);
+	return rc;
+}
+
+int mt9t013_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long rc = 0;
+
+	if (copy_from_user(&cdata, (void *)argp,
+			   sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	CDBG("mt9t013_sensor_config: cfgtype = %d\n", cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		mt9t013_get_pict_fps(cdata.cfg.gfps.prevfps,
+				     &(cdata.cfg.gfps.pictfps));
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf = mt9t013_get_prev_lines_pf();
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl = mt9t013_get_prev_pixels_pl();
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf = mt9t013_get_pict_lines_pf();
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl = mt9t013_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc = mt9t013_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = mt9t013_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc = mt9t013_write_exp_gain(cdata.cfg.exp_gain.gain,
+					    cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_PICT_EXP_GAIN:
+		rc = mt9t013_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+					       cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_MODE:
+		rc = mt9t013_set_sensor_mode(cdata.mode, cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = mt9t013_power_down();
+		break;
+
+	case CFG_MOVE_FOCUS:
+		rc = mt9t013_move_focus(cdata.cfg.focus.dir,
+					cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = mt9t013_set_default_focus(cdata.cfg.focus.steps);
+		break;
+
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR;
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_EFFECT:
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+int mt9t013_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	mt9t013_poweroff_af();
+	mt9t013_power_down();
+
+	gpio_direction_output(mt9t013_ctrl->sensordata->sensor_reset, 0);
+	gpio_free(mt9t013_ctrl->sensordata->sensor_reset);
+
+	kfree(mt9t013_ctrl);
+
+	CDBG("mt9t013_release completed!\n");
+	return rc;
+}
+
+static int mt9t013_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	int rc = 0;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		rc = -ENOTSUPP;
+		goto probe_failure;
+	}
+
+	mt9t013_sensorw = kzalloc(sizeof(struct mt9t013_work), GFP_KERNEL);
+
+	if (!mt9t013_sensorw) {
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, mt9t013_sensorw);
+	mt9t013_init_client(client);
+	mt9t013_client = client;
+	mt9t013_client->addr = mt9t013_client->addr >> 1;
+	mdelay(50);
+
+	CDBG("i2c probe ok\n");
+	return 0;
+
+probe_failure:
+	kfree(mt9t013_sensorw);
+	mt9t013_sensorw = NULL;
+	pr_err("i2c probe failure %d\n", rc);
+	return rc;
+}
+
+static const struct i2c_device_id mt9t013_i2c_id[] = {
+	{"mt9t013", 0},
+	{}
+};
+
+static struct i2c_driver mt9t013_i2c_driver = {
+	.id_table = mt9t013_i2c_id,
+	.probe = mt9t013_i2c_probe,
+	.remove = __exit_p(mt9t013_i2c_remove),
+	.driver = {
+		   .name = "mt9t013",
+		   },
+};
+
+static int mt9t013_sensor_probe(const struct msm_camera_sensor_info *info,
+				struct msm_sensor_ctrl *s)
+{
+	/* We expect this driver to match with the i2c device registered
+	 * in the board file immediately. */
+	int rc = i2c_add_driver(&mt9t013_i2c_driver);
+	if (rc < 0 || mt9t013_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_done;
+	}
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	rc = mt9t013_probe_init_sensor(info);
+	if (rc < 0) {
+		i2c_del_driver(&mt9t013_i2c_driver);
+		goto probe_done;
+	}
+
+	s->s_init = mt9t013_sensor_open_init;
+	s->s_release = mt9t013_sensor_release;
+	s->s_config = mt9t013_sensor_config;
+	mt9t013_sensor_init_done(info);
+
+probe_done:
+	return rc;
+}
+
+static int __mt9t013_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, mt9t013_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __mt9t013_probe,
+	.driver = {
+		   .name = "msm_camera_mt9t013",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __init mt9t013_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9t013_init);
diff --git a/drivers/media/video/msm/mt9t013.h b/drivers/media/video/msm/mt9t013.h
new file mode 100644
index 0000000..67c4d9c
--- /dev/null
+++ b/drivers/media/video/msm/mt9t013.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef MT9T013_H
+#define MT9T013_H
+
+#include <linux/types.h>
+
+struct reg_struct {
+	uint16_t vt_pix_clk_div;	/*  0x0300 */
+	uint16_t vt_sys_clk_div;	/*  0x0302 */
+	uint16_t pre_pll_clk_div;	/*  0x0304 */
+	uint16_t pll_multiplier;	/*  0x0306 */
+	uint16_t op_pix_clk_div;	/*  0x0308 */
+	uint16_t op_sys_clk_div;	/*  0x030A */
+	uint16_t scale_m;	/*  0x0404 */
+	uint16_t row_speed;	/*  0x3016 */
+	uint16_t x_addr_start;	/*  0x3004 */
+	uint16_t x_addr_end;	/*  0x3008 */
+	uint16_t y_addr_start;	/*  0x3002 */
+	uint16_t y_addr_end;	/*  0x3006 */
+	uint16_t read_mode;	/*  0x3040 */
+	uint16_t x_output_size;	/*  0x034C */
+	uint16_t y_output_size;	/*  0x034E */
+	uint16_t line_length_pck;	/*  0x300C */
+	uint16_t frame_length_lines;	/*  0x300A */
+	uint16_t coarse_int_time;	/*  0x3012 */
+	uint16_t fine_int_time;	/*  0x3014 */
+};
+
+struct mt9t013_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+struct mt9t013_reg {
+	struct reg_struct *reg_pat;
+	int reg_pat_size;
+	struct mt9t013_i2c_reg_conf *ttbl;
+	int ttbl_size;
+	struct mt9t013_i2c_reg_conf *lctbl;
+	int lctbl_size;
+	struct mt9t013_i2c_reg_conf *rftbl;
+	int rftbl_size;
+};
+
+extern struct mt9t013_reg mt9t013_regs;
+
+#endif /* #define MT9T013_H */
diff --git a/drivers/media/video/msm/mt9t013_reg.c b/drivers/media/video/msm/mt9t013_reg.c
new file mode 100644
index 0000000..aac81c7
--- /dev/null
+++ b/drivers/media/video/msm/mt9t013_reg.c
@@ -0,0 +1,277 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "mt9t013.h"
+#include <linux/kernel.h>
+
+struct reg_struct mt9t013_reg_pat[2] = {
+	{/* Preview 2x2 binning 20fps, pclk MHz, MCLK 24MHz */
+	 /* vt_pix_clk_div:REG=0x0300 update get_snapshot_fps
+	  * if this change */
+	 10,
+
+	 /* vt_sys_clk_div: REG=0x0302  update get_snapshot_fps
+	  * if this change */
+	 1,
+
+	 /* pre_pll_clk_div REG=0x0304  update get_snapshot_fps
+	  * if this change */
+	 3,
+
+	 /* pll_multiplier  REG=0x0306 60 for 30fps preview, 40
+	  * for 20fps preview
+	  * 46 for 30fps preview, try 47/48 to increase further */
+	 80,
+
+	 /* op_pix_clk_div        REG=0x0308 */
+	 10,
+
+	 /* op_sys_clk_div        REG=0x030A */
+	 1,
+
+	 /* scale_m       REG=0x0404 */
+	 16,
+
+	 /* row_speed     REG=0x3016 */
+	 0x0111,
+
+	 /* x_addr_start  REG=0x3004 */
+	 8,
+
+	 /* x_addr_end    REG=0x3008 */
+	 2053,
+
+	 /* y_addr_start  REG=0x3002 */
+	 8,
+
+	 /* y_addr_end    REG=0x3006 */
+	 1541,
+
+	 /* read_mode     REG=0x3040 */
+	 0x046C,
+
+	 /* x_output_size REG=0x034C */
+	 1024,
+
+	 /* y_output_size REG=0x034E */
+	 768,
+
+	 /* line_length_pck    REG=0x300C */
+	 3540,
+
+	 /* frame_length_lines REG=0x300A */
+	 861,
+
+	 /* coarse_int_time REG=0x3012 */
+	 16,
+
+	 /* fine_int_time   REG=0x3014 */
+	 1461},
+
+	{ /*Snapshot */
+	 /* vt_pix_clk_div  REG=0x0300 update get_snapshot_fps
+	  * if this change */
+	 10,
+
+	 /* vt_sys_clk_div  REG=0x0302 update get_snapshot_fps
+	  * if this change */
+	 1,
+
+	 /* pre_pll_clk_div REG=0x0304 update get_snapshot_fps
+	  * if this change */
+	 3,
+
+	 /* pll_multiplier REG=0x0306 50 for 15fps snapshot,
+	  * 40 for 10fps snapshot
+	  * 46 for 30fps snapshot, try 47/48 to increase further */
+	 80,
+
+	 /* op_pix_clk_div        REG=0x0308 */
+	 10,
+
+	 /* op_sys_clk_div        REG=0x030A */
+	 1,
+
+	 /* scale_m       REG=0x0404 */
+	 16,
+
+	 /* row_speed     REG=0x3016 */
+	 0x0111,
+
+	 /* x_addr_start  REG=0x3004 */
+	 8,
+
+	 /* x_addr_end    REG=0x3008 */
+	 2063,
+
+	 /* y_addr_start  REG=0x3002 */
+	 8,
+
+	 /* y_addr_end    REG=0x3006 */
+	 1551,
+
+	 /* read_mode     REG=0x3040 */
+	 0x0024,
+
+	 /* x_output_size REG=0x034C */
+	 2064,
+
+	 /* y_output_size REG=0x034E */
+	 1544,
+
+	 /* line_length_pck REG=0x300C */
+	 4800,
+
+	 /* frame_length_lines    REG=0x300A */
+	 1629,
+
+	 /* coarse_int_time REG=0x3012 */
+	 16,
+
+	 /* fine_int_time REG=0x3014   */
+	 733}
+};
+
+struct mt9t013_i2c_reg_conf mt9t013_test_tbl[] = {
+	{0x3044, 0x0544 & 0xFBFF},
+	{0x30CA, 0x0004 | 0x0001},
+	{0x30D4, 0x9020 & 0x7FFF},
+	{0x31E0, 0x0003 & 0xFFFE},
+	{0x3180, 0x91FF & 0x7FFF},
+	{0x301A, (0x10CC | 0x8000) & 0xFFF7},
+	{0x301E, 0x0000},
+	{0x3780, 0x0000},
+};
+
+/* [Lens shading 85 Percent TL84] */
+struct mt9t013_i2c_reg_conf mt9t013_lc_tbl[] = {
+	{0x360A, 0x0290},	/* P_RD_P0Q0 */
+	{0x360C, 0xC92D},	/* P_RD_P0Q1 */
+	{0x360E, 0x0771},	/* P_RD_P0Q2 */
+	{0x3610, 0xE38C},	/* P_RD_P0Q3 */
+	{0x3612, 0xD74F},	/* P_RD_P0Q4 */
+	{0x364A, 0x168C},	/* P_RD_P1Q0 */
+	{0x364C, 0xCACB},	/* P_RD_P1Q1 */
+	{0x364E, 0x8C4C},	/* P_RD_P1Q2 */
+	{0x3650, 0x0BEA},	/* P_RD_P1Q3 */
+	{0x3652, 0xDC0F},	/* P_RD_P1Q4 */
+	{0x368A, 0x70B0},	/* P_RD_P2Q0 */
+	{0x368C, 0x200B},	/* P_RD_P2Q1 */
+	{0x368E, 0x30B2},	/* P_RD_P2Q2 */
+	{0x3690, 0xD04F},	/* P_RD_P2Q3 */
+	{0x3692, 0xACF5},	/* P_RD_P2Q4 */
+	{0x36CA, 0xF7C9},	/* P_RD_P3Q0 */
+	{0x36CC, 0x2AED},	/* P_RD_P3Q1 */
+	{0x36CE, 0xA652},	/* P_RD_P3Q2 */
+	{0x36D0, 0x8192},	/* P_RD_P3Q3 */
+	{0x36D2, 0x3A15},	/* P_RD_P3Q4 */
+	{0x370A, 0xDA30},	/* P_RD_P4Q0 */
+	{0x370C, 0x2E2F},	/* P_RD_P4Q1 */
+	{0x370E, 0xBB56},	/* P_RD_P4Q2 */
+	{0x3710, 0x8195},	/* P_RD_P4Q3 */
+	{0x3712, 0x02F9},	/* P_RD_P4Q4 */
+	{0x3600, 0x0230},	/* P_GR_P0Q0 */
+	{0x3602, 0x58AD},	/* P_GR_P0Q1 */
+	{0x3604, 0x18D1},	/* P_GR_P0Q2 */
+	{0x3606, 0x260D},	/* P_GR_P0Q3 */
+	{0x3608, 0xF530},	/* P_GR_P0Q4 */
+	{0x3640, 0x17EB},	/* P_GR_P1Q0 */
+	{0x3642, 0x3CAB},	/* P_GR_P1Q1 */
+	{0x3644, 0x87CE},	/* P_GR_P1Q2 */
+	{0x3646, 0xC02E},	/* P_GR_P1Q3 */
+	{0x3648, 0xF48F},	/* P_GR_P1Q4 */
+	{0x3680, 0x5350},	/* P_GR_P2Q0 */
+	{0x3682, 0x7EAF},	/* P_GR_P2Q1 */
+	{0x3684, 0x4312},	/* P_GR_P2Q2 */
+	{0x3686, 0xC652},	/* P_GR_P2Q3 */
+	{0x3688, 0xBC15},	/* P_GR_P2Q4 */
+	{0x36C0, 0xB8AD},	/* P_GR_P3Q0 */
+	{0x36C2, 0xBDCD},	/* P_GR_P3Q1 */
+	{0x36C4, 0xE4B2},	/* P_GR_P3Q2 */
+	{0x36C6, 0xB50F},	/* P_GR_P3Q3 */
+	{0x36C8, 0x5B95},	/* P_GR_P3Q4 */
+	{0x3700, 0xFC90},	/* P_GR_P4Q0 */
+	{0x3702, 0x8C51},	/* P_GR_P4Q1 */
+	{0x3704, 0xCED6},	/* P_GR_P4Q2 */
+	{0x3706, 0xB594},	/* P_GR_P4Q3 */
+	{0x3708, 0x0A39},	/* P_GR_P4Q4 */
+	{0x3614, 0x0230},	/* P_BL_P0Q0 */
+	{0x3616, 0x160D},	/* P_BL_P0Q1 */
+	{0x3618, 0x08D1},	/* P_BL_P0Q2 */
+	{0x361A, 0x98AB},	/* P_BL_P0Q3 */
+	{0x361C, 0xEA50},	/* P_BL_P0Q4 */
+	{0x3654, 0xB4EA},	/* P_BL_P1Q0 */
+	{0x3656, 0xEA6C},	/* P_BL_P1Q1 */
+	{0x3658, 0xFE08},	/* P_BL_P1Q2 */
+	{0x365A, 0x2C6E},	/* P_BL_P1Q3 */
+	{0x365C, 0xEB0E},	/* P_BL_P1Q4 */
+	{0x3694, 0x6DF0},	/* P_BL_P2Q0 */
+	{0x3696, 0x3ACF},	/* P_BL_P2Q1 */
+	{0x3698, 0x3E0F},	/* P_BL_P2Q2 */
+	{0x369A, 0xB2B1},	/* P_BL_P2Q3 */
+	{0x369C, 0xC374},	/* P_BL_P2Q4 */
+	{0x36D4, 0xF2AA},	/* P_BL_P3Q0 */
+	{0x36D6, 0x8CCC},	/* P_BL_P3Q1 */
+	{0x36D8, 0xDEF2},	/* P_BL_P3Q2 */
+	{0x36DA, 0xFA11},	/* P_BL_P3Q3 */
+	{0x36DC, 0x42F5},	/* P_BL_P3Q4 */
+	{0x3714, 0xF4F1},	/* P_BL_P4Q0 */
+	{0x3716, 0xF6F0},	/* P_BL_P4Q1 */
+	{0x3718, 0x8FD6},	/* P_BL_P4Q2 */
+	{0x371A, 0xEA14},	/* P_BL_P4Q3 */
+	{0x371C, 0x6338},	/* P_BL_P4Q4 */
+	{0x361E, 0x0350},	/* P_GB_P0Q0 */
+	{0x3620, 0x91AE},	/* P_GB_P0Q1 */
+	{0x3622, 0x0571},	/* P_GB_P0Q2 */
+	{0x3624, 0x100D},	/* P_GB_P0Q3 */
+	{0x3626, 0xCA70},	/* P_GB_P0Q4 */
+	{0x365E, 0xE6CB},	/* P_GB_P1Q0 */
+	{0x3660, 0x50ED},	/* P_GB_P1Q1 */
+	{0x3662, 0x3DAE},	/* P_GB_P1Q2 */
+	{0x3664, 0xAA4F},	/* P_GB_P1Q3 */
+	{0x3666, 0xDC50},	/* P_GB_P1Q4 */
+	{0x369E, 0x5470},	/* P_GB_P2Q0 */
+	{0x36A0, 0x1F6E},	/* P_GB_P2Q1 */
+	{0x36A2, 0x6671},	/* P_GB_P2Q2 */
+	{0x36A4, 0xC010},	/* P_GB_P2Q3 */
+	{0x36A6, 0x8DF5},	/* P_GB_P2Q4 */
+	{0x36DE, 0x0B0C},	/* P_GB_P3Q0 */
+	{0x36E0, 0x84CE},	/* P_GB_P3Q1 */
+	{0x36E2, 0x8493},	/* P_GB_P3Q2 */
+	{0x36E4, 0xA610},	/* P_GB_P3Q3 */
+	{0x36E6, 0x50B5},	/* P_GB_P3Q4 */
+	{0x371E, 0x9651},	/* P_GB_P4Q0 */
+	{0x3720, 0x1EAB},	/* P_GB_P4Q1 */
+	{0x3722, 0xAF76},	/* P_GB_P4Q2 */
+	{0x3724, 0xE4F4},	/* P_GB_P4Q3 */
+	{0x3726, 0x79F8},	/* P_GB_P4Q4 */
+	{0x3782, 0x0410},	/* POLY_ORIGIN_C */
+	{0x3784, 0x0320},	/* POLY_ORIGIN_R  */
+	{0x3780, 0x8000}	/* POLY_SC_ENABLE */
+};
+
+struct mt9t013_reg mt9t013_regs = {
+	.reg_pat = &mt9t013_reg_pat[0],
+	.reg_pat_size = ARRAY_SIZE(mt9t013_reg_pat),
+	.ttbl = &mt9t013_test_tbl[0],
+	.ttbl_size = ARRAY_SIZE(mt9t013_test_tbl),
+	.lctbl = &mt9t013_lc_tbl[0],
+	.lctbl_size = ARRAY_SIZE(mt9t013_lc_tbl),
+	.rftbl = &mt9t013_lc_tbl[0],
+	.rftbl_size = ARRAY_SIZE(mt9t013_lc_tbl)
+};
diff --git a/drivers/media/video/msm/s5k3e2fx.c b/drivers/media/video/msm/s5k3e2fx.c
new file mode 100644
index 0000000..a2ab9ba
--- /dev/null
+++ b/drivers/media/video/msm/s5k3e2fx.c
@@ -0,0 +1,3104 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <media/msm_camera.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include <linux/clk.h>
+#include <linux/wakelock.h>
+
+static uint16_t g_usModuleVersion;	/*0: rev.4, 1: rev.5 */
+
+/* prepare for modify PCLK*/
+#define REG_PLL_MULTIPLIER_LSB_VALUE	  0x90
+/* 0xA0 for PCLK=80MHz */
+/* 0x90 for PCLK=72MHz */
+
+/* prepare for modify initial gain*/
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB_VALUE	0x80
+
+#define S5K3E2FX_REG_MODEL_ID   0x0000
+#define S5K3E2FX_MODEL_ID       0x3E2F
+
+#define S5K3E2FX_REG_MODULE_VER 0x0002
+
+#define S5K3E2FX_DEF_MCLK		24000000
+
+#define S5K3E2FX_QTR_SIZE_WIDTH		1296
+#define S5K3E2FX_QTR_SIZE_HEIGHT	972
+
+#define S5K3E2FX_FULL_SIZE_WIDTH	2608
+#define S5K3E2FX_FULL_SIZE_HEIGHT	1960
+
+/* AEC_FLASHING */
+#define REG_GROUPED_PARAMETER_HOLD    0x0104
+#define GROUPED_PARAMETER_HOLD        0x01
+#define GROUPED_PARAMETER_UPDATE      0x00
+
+/* Greenish in low light */
+#define REG_MASK_CORRUPTED_FRAMES     0x0105
+#define MASK                          0x01
+#define NO_MASK                       0x00
+
+/* PLL Registers */
+#define REG_PRE_PLL_CLK_DIV           0x0305
+#define REG_PLL_MULTIPLIER_MSB        0x0306
+#define REG_PLL_MULTIPLIER_LSB        0x0307
+#define REG_VT_PIX_CLK_DIV            0x0301
+#define REG_VT_SYS_CLK_DIV            0x0303
+#define REG_OP_PIX_CLK_DIV            0x0309
+#define REG_OP_SYS_CLK_DIV            0x030B
+
+/* Data Format Registers */
+#define REG_CCP_DATA_FORMAT_MSB       0x0112
+#define REG_CCP_DATA_FORMAT_LSB       0x0113
+
+/* Output Size */
+#define REG_X_OUTPUT_SIZE_MSB         0x034C
+#define REG_X_OUTPUT_SIZE_LSB         0x034D
+#define REG_Y_OUTPUT_SIZE_MSB         0x034E
+#define REG_Y_OUTPUT_SIZE_LSB         0x034F
+
+/* Binning */
+#define REG_X_EVEN_INC                0x0381
+#define REG_X_ODD_INC                 0x0383
+#define REG_Y_EVEN_INC                0x0385
+#define REG_Y_ODD_INC                 0x0387
+/*Reserved register */
+#define REG_BINNING_ENABLE            0x3014
+
+/* Frame Fotmat */
+#define REG_FRAME_LENGTH_LINES_MSB    0x0340
+#define REG_FRAME_LENGTH_LINES_LSB    0x0341
+#define REG_LINE_LENGTH_PCK_MSB       0x0342
+#define REG_LINE_LENGTH_PCK_LSB       0x0343
+
+/* MSR setting */
+/* Reserved registers */
+#define REG_SHADE_CLK_ENABLE          0x30AC
+#define REG_SEL_CCP                   0x30C4
+#define REG_VPIX                      0x3024
+#define REG_CLAMP_ON                  0x3015
+#define REG_OFFSET                    0x307E
+
+/* CDS timing settings */
+/* Reserved registers */
+#define REG_LD_START                  0x3000
+#define REG_LD_END                    0x3001
+#define REG_SL_START                  0x3002
+#define REG_SL_END                    0x3003
+#define REG_RX_START                  0x3004
+#define REG_S1_START                  0x3005
+#define REG_S1_END                    0x3006
+#define REG_S1S_START                 0x3007
+#define REG_S1S_END                   0x3008
+#define REG_S3_START                  0x3009
+#define REG_S3_END                    0x300A
+#define REG_CMP_EN_START              0x300B
+#define REG_CLP_SL_START              0x300C
+#define REG_CLP_SL_END                0x300D
+#define REG_OFF_START                 0x300E
+#define REG_RMP_EN_START              0x300F
+#define REG_TX_START                  0x3010
+#define REG_TX_END                    0x3011
+#define REG_STX_WIDTH                 0x3012
+#define REG_TYPE1_AF_ENABLE           0x3130
+#define DRIVER_ENABLED                0x0001
+#define AUTO_START_ENABLED            0x0010
+#define REG_NEW_POSITION              0x3131
+#define REG_3152_RESERVED             0x3152
+#define REG_315A_RESERVED             0x315A
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB 0x0204
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB 0x0205
+#define REG_FINE_INTEGRATION_TIME         0x0200
+#define REG_COARSE_INTEGRATION_TIME       0x0202
+#define REG_COARSE_INTEGRATION_TIME_LSB   0x0203
+
+/* Mode select register */
+#define S5K3E2FX_REG_MODE_SELECT        0x0100
+#define S5K3E2FX_MODE_SELECT_STREAM     0x01	/* start streaming */
+#define S5K3E2FX_MODE_SELECT_SW_STANDBY 0x00	/* software standby */
+#define S5K3E2FX_REG_SOFTWARE_RESET     0x0103
+#define S5K3E2FX_SOFTWARE_RESET         0x01
+#define REG_TEST_PATTERN_MODE           0x0601
+
+/* Samsung other MSR setting*/
+#define REG_301D_RESERVED             0x301D
+#define REG_3028_RESERVED             0x3028
+#define REG_3070_RESERVED             0x3070
+#define REG_3072_RESERVED             0x3072
+#define REG_301B_RESERVED             0x301B
+#define REG_30BD_RESERVED             0x30BD
+#define REG_30C2_RESERVED             0x30C2
+#define REG_3151_RESERVED             0x3151
+#define REG_3029_RESERVED             0x3029
+#define REG_30BF_RESERVED             0x30BF
+#define REG_3022_RESERVED             0x3022
+#define REG_3019_RESERVED             0x3019
+#define REG_3150_RESERVED             0x3150
+#define REG_3157_RESERVED             0x3157
+#define REG_3159_RESERVED             0x3159
+/* LC Preview/Snapshot difference register */
+#define REG_SH4CH_BLK_WIDTH_R         0x309E
+#define REG_SH4CH_BLK_HEIGHT_R        0x309F
+#define REG_SH4CH_STEP_X_R_MSB        0x30A0
+#define REG_SH4CH_STEP_X_R_LSB        0x30A1
+#define REG_SH4CH_STEP_Y_R_MSB        0x30A2
+#define REG_SH4CH_STEP_Y_R_LSB        0x30A3
+#define REG_SH4CH_START_BLK_CNT_X_R   0x30A4
+#define REG_SH4CH_START_BLK_INT_X_R   0x30A5
+#define REG_SH4CH_START_FRAC_X_R_MSB  0x30A6
+#define REG_SH4CH_START_FRAC_X_R_LSB  0x30A7
+#define REG_SH4CH_START_BLK_CNT_Y_R   0x30A8
+#define REG_SH4CH_START_BLK_INT_Y_R   0x30A9
+#define REG_SH4CH_START_FRAC_Y_R_MSB  0x30AA
+#define REG_SH4CH_START_FRAC_Y_R_LSB  0x30AB
+#define REG_X_ADDR_START_MSB          0x0344
+#define REG_X_ADDR_START_LSB          0x0345
+#define REG_Y_ADDR_START_MSB          0x0346
+#define REG_Y_ADDR_START_LSB          0x0347
+#define REG_X_ADDR_END_MSB            0x0348
+#define REG_X_ADDR_END_LSB            0x0349
+#define REG_Y_ADDR_END_MSB            0x034A
+#define REG_Y_ADDR_END_LSB            0x034B
+
+#define NUM_INIT_REG                  94
+#define NUM_LC_REG                    434
+
+struct s5k3e2fx_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned char bdata;
+};
+
+/* Separate the EVT4/EVT5 sensor init and LC setting start */
+struct s5k3e2fx_i2c_reg_conf Init_setting[2][NUM_INIT_REG] = {
+/*EVT4 */
+	{
+	 {REG_PRE_PLL_CLK_DIV, 0x06},	/* PLL setting */
+	 {REG_PLL_MULTIPLIER_MSB, 0x00},
+	 {REG_PLL_MULTIPLIER_LSB, REG_PLL_MULTIPLIER_LSB_VALUE},
+	 {REG_VT_PIX_CLK_DIV, 0x08},
+	 {REG_VT_SYS_CLK_DIV, 0x01},
+	 {REG_OP_PIX_CLK_DIV, 0x08},
+	 {REG_OP_SYS_CLK_DIV, 0x01},
+/* Data Format */
+	 {REG_CCP_DATA_FORMAT_MSB, 0x0a},
+	 {REG_CCP_DATA_FORMAT_LSB, 0x0a},
+/* Preview Output Size */
+	 {REG_X_OUTPUT_SIZE_MSB, 0x05},
+	 {REG_X_OUTPUT_SIZE_LSB, 0x10},
+	 {REG_Y_OUTPUT_SIZE_MSB, 0x03},
+	 {REG_Y_OUTPUT_SIZE_LSB, 0xcc},
+	 {REG_X_ADDR_START_MSB, 0x00},
+	 {REG_X_ADDR_START_LSB, 0x08},
+	 {REG_Y_ADDR_START_MSB, 0x00},
+	 {REG_Y_ADDR_START_LSB, 0x08},
+	 {REG_X_ADDR_END_MSB, 0x0a},
+	 {REG_X_ADDR_END_LSB, 0x27},
+	 {REG_Y_ADDR_END_MSB, 0x07},
+	 {REG_Y_ADDR_END_LSB, 0x9f},
+/* Frame format */
+	 {REG_FRAME_LENGTH_LINES_MSB, 0x03},
+	 {REG_FRAME_LENGTH_LINES_LSB, 0xe2},
+	 {REG_LINE_LENGTH_PCK_MSB, 0x0a},
+	 {REG_LINE_LENGTH_PCK_LSB, 0xac},
+/* Preview Binning */
+	 {REG_X_EVEN_INC, 0x01},
+	 {REG_X_ODD_INC, 0x01},
+	 {REG_Y_EVEN_INC, 0x01},
+	 {REG_Y_ODD_INC, 0x03},
+	 {REG_BINNING_ENABLE, 0x06},
+/* Samsung MSR Setting */
+	 {REG_SEL_CCP, 0x01},
+	 {REG_LD_START, 0x03},
+/* Add EVT5 sensor Samsung MSR setting, Start */
+	 {REG_LD_END, 0x94},
+	 {REG_SL_START, 0x02},
+	 {REG_SL_END, 0x95},
+	 {REG_RX_START, 0x0f},
+	 {REG_S1_START, 0x05},
+	 {REG_S1_END, 0x3c},
+	 {REG_S1S_START, 0x8c},
+	 {REG_S1S_END, 0x93},
+	 {REG_S3_START, 0x05},
+	 {REG_S3_END, 0x3a},
+	 {REG_CMP_EN_START, 0x10},
+	 {REG_CLP_SL_START, 0x02},
+	 {REG_CLP_SL_END, 0x3e},
+	 {REG_OFF_START, 0x02},
+	 {REG_RMP_EN_START, 0x0e},
+	 {REG_TX_START, 0x46},
+	 {REG_TX_END, 0x64},
+	 {REG_STX_WIDTH, 0x1e},
+	 {REG_CLAMP_ON, 0x00},
+	 {REG_301D_RESERVED, 0x3f},
+	 {REG_VPIX, 0x04},
+	 {REG_3028_RESERVED, 0x40},
+	 {REG_3070_RESERVED, 0xdf},
+	 {REG_3072_RESERVED, 0x20},
+	 {REG_301B_RESERVED, 0x73},
+	 {REG_OFFSET, 0x02},
+	 {REG_30BD_RESERVED, 0x06},
+	 {REG_30C2_RESERVED, 0x0b},
+	 {REG_SHADE_CLK_ENABLE, 0x81},
+	 {REG_3151_RESERVED, 0xe6},
+	 {REG_3029_RESERVED, 0x02},
+	 {REG_30BF_RESERVED, 0x00},
+	 {REG_3022_RESERVED, 0x87},
+	 {REG_3019_RESERVED, 0x60},
+	 {REG_3019_RESERVED, 0x60},
+	 {REG_3019_RESERVED, 0x60},
+	 {REG_3019_RESERVED, 0x60},
+	 {REG_3019_RESERVED, 0x60},
+	 {REG_3019_RESERVED, 0x60},
+	 {REG_3152_RESERVED, 0x08},
+	 {REG_3150_RESERVED, 0x50}, /* from 0x40 to 0x50 for PCLK=80MHz */
+/* Inverse PCLK = 0x50 */
+	 {REG_3157_RESERVED, 0x04}, /* from 0x00 to 0x04 for PCLK=80MHz */
+/* PCLK Delay offset; 0x0a will delay around 4ns at 80MHz */
+	 {REG_3159_RESERVED, 0x0f}, /* from 0x00 to 0x0f for PCLK=80MHz */
+/* HS, VS driving strength [3:2]=>VS, [1:0]=>HS 00:2mA, 01:4mA, 10:6mA,
+ * 11:8mA
+ */
+	 {REG_315A_RESERVED, 0xf0}, /* from 0x10 to 0xf0 for PCLK=80MHz */
+/* PCLK, DATA driving strength [7:6]=>data, [5:4]=>PCLK 00:2mA, 01:4mA
+ * 10:6mA, 11:8mA
+ */
+/* AEC Setting */
+	 {REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, 0x00},
+	 {REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB_VALUE},
+	 {REG_FINE_INTEGRATION_TIME, 0x02},
+	 {REG_COARSE_INTEGRATION_TIME, 0x03},
+/* Preview LC config Setting */
+	 {REG_SH4CH_BLK_WIDTH_R, 0x52},
+	 {REG_SH4CH_BLK_HEIGHT_R, 0x3e},
+	 {REG_SH4CH_STEP_X_R_MSB, 0x03},
+	 {REG_SH4CH_STEP_X_R_LSB, 0x1f},
+	 {REG_SH4CH_STEP_Y_R_MSB, 0x04},
+	 {REG_SH4CH_STEP_Y_R_LSB, 0x21},
+	 {REG_SH4CH_START_BLK_CNT_X_R, 0x04},
+	 {REG_SH4CH_START_BLK_INT_X_R, 0x00},
+	 {REG_SH4CH_START_FRAC_X_R_MSB, 0x0c},
+	 {REG_SH4CH_START_FRAC_X_R_LSB, 0x7c},
+	 {REG_SH4CH_START_BLK_CNT_Y_R, 0x04},
+	 {REG_SH4CH_START_BLK_INT_Y_R, 0x00},
+	 {REG_SH4CH_START_FRAC_Y_R_MSB, 0x10},
+	 {REG_SH4CH_START_FRAC_Y_R_LSB, 0x84},
+	 },
+
+/* EVT5 */
+	{
+	 {REG_PRE_PLL_CLK_DIV, 0x06}, /* PLL setting */
+	 {REG_PLL_MULTIPLIER_MSB, 0x00},
+	 {REG_PLL_MULTIPLIER_LSB, REG_PLL_MULTIPLIER_LSB_VALUE},
+	 {REG_VT_PIX_CLK_DIV, 0x08},
+	 {REG_VT_SYS_CLK_DIV, 0x01},
+	 {REG_OP_PIX_CLK_DIV, 0x08},
+	 {REG_OP_SYS_CLK_DIV, 0x01},
+/* Data Format */
+	 {REG_CCP_DATA_FORMAT_MSB, 0x0a},
+	 {REG_CCP_DATA_FORMAT_LSB, 0x0a},
+/* Preview Output Size */
+	 {REG_X_OUTPUT_SIZE_MSB, 0x05},
+	 {REG_X_OUTPUT_SIZE_LSB, 0x10},
+	 {REG_Y_OUTPUT_SIZE_MSB, 0x03},
+	 {REG_Y_OUTPUT_SIZE_LSB, 0xcc},
+	 {REG_X_ADDR_START_MSB, 0x00},
+	 {REG_X_ADDR_START_LSB, 0x08},
+	 {REG_Y_ADDR_START_MSB, 0x00},
+	 {REG_Y_ADDR_START_LSB, 0x08},
+	 {REG_X_ADDR_END_MSB, 0x0a},
+	 {REG_X_ADDR_END_LSB, 0x27},
+	 {REG_Y_ADDR_END_MSB, 0x07},
+	 {REG_Y_ADDR_END_LSB, 0x9f},
+/* Frame format */
+	 {REG_FRAME_LENGTH_LINES_MSB, 0x03},
+	 {REG_FRAME_LENGTH_LINES_LSB, 0xe2},
+	 {REG_LINE_LENGTH_PCK_MSB, 0x0a},
+	 {REG_LINE_LENGTH_PCK_LSB, 0xac},
+/* Preview Binning */
+	 {REG_X_EVEN_INC, 0x01},
+	 {REG_X_ODD_INC, 0x01},
+	 {REG_Y_EVEN_INC, 0x01},
+	 {REG_Y_ODD_INC, 0x03},
+	 {REG_BINNING_ENABLE, 0x06},
+/* Samsung MSR Setting */
+	 {REG_SEL_CCP, 0x01},
+	 {REG_LD_START, 0x03},
+/* EVT5 sensor Samsung MSR setting */
+	 {REG_LD_END, 0x99},
+	 {REG_SL_START, 0x02},
+	 {REG_SL_END, 0x9A},
+	 {REG_RX_START, 0x0f},
+	 {REG_S1_START, 0x05},
+	 {REG_S1_END, 0x3c},
+	 {REG_S1S_START, 0x8c},
+	 {REG_S1S_END, 0x26},
+	 {REG_S3_START, 0x05},
+	 {REG_S3_END, 0x3a},
+	 {REG_CMP_EN_START, 0x10},
+	 {REG_CLP_SL_START, 0x02},
+	 {REG_CLP_SL_END, 0x3e},
+	 {REG_OFF_START, 0x02},
+	 {REG_RMP_EN_START, 0x0e},
+	 {REG_TX_START, 0x46},
+	 {REG_TX_END, 0x64},
+	 {REG_STX_WIDTH, 0x1e},
+	 {REG_CLAMP_ON, 0x00},
+	 {REG_301D_RESERVED, 0x3f},
+	 {REG_VPIX, 0x04},
+	 {REG_3028_RESERVED, 0x40},
+	 {REG_3070_RESERVED, 0xdf},
+	 {REG_3072_RESERVED, 0x20},
+	 {REG_301B_RESERVED, 0x73},
+	 {REG_OFFSET, 0x02},
+	 {REG_30BD_RESERVED, 0x06},
+	 {REG_30C2_RESERVED, 0x0b},
+	 {REG_SHADE_CLK_ENABLE, 0x81},
+	 {REG_3151_RESERVED, 0xe6},
+	 {REG_3029_RESERVED, 0x02},
+	 {REG_30BF_RESERVED, 0x00},
+	 {REG_3022_RESERVED, 0x87},
+	 {REG_3019_RESERVED, 0x60},
+	 {0x3060, 0x03},
+	 {0x3061, 0x6C},
+	 {0x3062, 0x00},
+	 {0x3063, 0xD6},
+	 {0x3023, 0x0C},
+	 {REG_3152_RESERVED, 0x08},
+	 {REG_3150_RESERVED, 0x50}, /* from 0x40 to 0x50 for PCLK=80MHz */
+/* Inverse PCLK = 0x50 */
+	 {REG_3157_RESERVED, 0x04}, /* from 0x00 to 0x04 for PCLK=80MHz */
+/* PCLK Delay offset; 0x0a will delay around 4ns at 80MHz */
+	 {REG_3159_RESERVED, 0x0f}, /* from 0x00 to 0x0f for PCLK=80MHz */
+/* HS, VS driving strength [3:2]=>VS, [1:0]=>HS 00:2mA, 01:4mA, 10:6mA,
+ * 11:8mA
+ */
+	 {REG_315A_RESERVED, 0xf0}, /* from 0x10 to 0xf0 for PCLK=80MHz */
+/* PCLK, DATA driving strength [7:6]=>data, [5:4]=>PCLK 00:2mA, 01:4mA,
+ * 10:6mA, 11:8mA
+ */
+/* AEC Setting */
+	 {REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, 0x00},
+	 {REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB_VALUE},
+	 {REG_FINE_INTEGRATION_TIME, 0x02},
+	 {REG_COARSE_INTEGRATION_TIME, 0x03},
+/* Preview LC config Setting */
+	 {REG_SH4CH_BLK_WIDTH_R, 0x52},
+	 {REG_SH4CH_BLK_HEIGHT_R, 0x3e},
+	 {REG_SH4CH_STEP_X_R_MSB, 0x03},
+	 {REG_SH4CH_STEP_X_R_LSB, 0x1f},
+	 {REG_SH4CH_STEP_Y_R_MSB, 0x04},
+	 {REG_SH4CH_STEP_Y_R_LSB, 0x21},
+	 {REG_SH4CH_START_BLK_CNT_X_R, 0x04},
+	 {REG_SH4CH_START_BLK_INT_X_R, 0x00},
+	 {REG_SH4CH_START_FRAC_X_R_MSB, 0x0c},
+	 {REG_SH4CH_START_FRAC_X_R_LSB, 0x7c},
+	 {REG_SH4CH_START_BLK_CNT_Y_R, 0x04},
+	 {REG_SH4CH_START_BLK_INT_Y_R, 0x00},
+	 {REG_SH4CH_START_FRAC_Y_R_MSB, 0x10},
+	 {REG_SH4CH_START_FRAC_Y_R_LSB, 0x84},
+	 }
+};
+
+struct s5k3e2fx_i2c_reg_conf lc_setting[2][NUM_LC_REG] = {
+/*EVT4 */
+	{
+	/*EVT4 */  /* 100108 Modify LC setting DNP light source t75-r73*/
+	{0x3200, 0x00},
+	{0x3201, 0x99},
+	{0x3202, 0xc1},
+	{0x3203, 0x0f},
+	{0x3204, 0xd0},
+	{0x3205, 0x1b},
+	{0x3206, 0x00},
+	{0x3207, 0x24},
+	{0x3208, 0x8d},
+	{0x3209, 0x0f},
+	{0x320a, 0xee},
+	{0x320b, 0x0f},
+	{0x320c, 0x00},
+	{0x320d, 0x04},
+	{0x320e, 0x5c},
+	{0x320f, 0x00},
+	{0x3210, 0x07},
+	{0x3211, 0x68},
+	{0x3212, 0x0f},
+	{0x3213, 0xc2},
+	{0x3214, 0x82},
+	{0x3215, 0x00},
+	{0x3216, 0x29},
+	{0x3217, 0x3e},
+	{0x3218, 0x0f},
+	{0x3219, 0xd3},
+	{0x321a, 0x63},
+	{0x321b, 0x00},
+	{0x321c, 0x22},
+	{0x321d, 0x6c},
+	{0x321e, 0x0f},
+	{0x321f, 0xf8},
+	{0x3220, 0xce},
+	{0x3221, 0x0f},
+	{0x3222, 0xed},
+	{0x3223, 0x30},
+	{0x3224, 0x00},
+	{0x3225, 0x37},
+	{0x3226, 0x87},
+	{0x3227, 0x0f},
+	{0x3228, 0xc2},
+	{0x3229, 0x87},
+	{0x322a, 0x00},
+	{0x322b, 0x2a},
+	{0x322c, 0xc6},
+	{0x322d, 0x0f},
+	{0x322e, 0xf3},
+	{0x322f, 0xd9},
+	{0x3230, 0x0f},
+	{0x3231, 0xea},
+	{0x3232, 0x1a},
+	{0x3233, 0x00},
+	{0x3234, 0x2d},
+	{0x3235, 0x9f},
+	{0x3236, 0x0f},
+	{0x3237, 0xde},
+	{0x3238, 0x7d},
+	{0x3239, 0x00},
+	{0x323a, 0x37},
+	{0x323b, 0x1e},
+	{0x323c, 0x0f},
+	{0x323d, 0xed},
+	{0x323e, 0x9c},
+	{0x323f, 0x0f},
+	{0x3240, 0xf6},
+	{0x3241, 0xfd},
+	{0x3242, 0x00},
+	{0x3243, 0x15},
+	{0x3244, 0xeb},
+	{0x3245, 0x0f},
+	{0x3246, 0xd3},
+	{0x3247, 0xca},
+	{0x3248, 0x00},
+	{0x3249, 0x08},
+	{0x324a, 0xe6},
+	{0x324b, 0x0f},
+	{0x324c, 0xf4},
+	{0x324d, 0x7a},
+	{0x324e, 0x0f},
+	{0x324f, 0xed},
+	{0x3250, 0x1e},
+	{0x3251, 0x00},
+	{0x3252, 0x0d},
+	{0x3253, 0x46},
+	{0x3254, 0x00},
+	{0x3255, 0x0c},
+	{0x3256, 0x3e},
+	{0x3257, 0x00},
+	{0x3258, 0x09},
+	{0x3259, 0xcf},
+	{0x325a, 0x00},
+	{0x325b, 0x09},
+	{0x325c, 0xb5},
+	{0x325d, 0x0f},
+	{0x325e, 0xec},
+	{0x325f, 0x47},
+	{0x3260, 0x00},
+	{0x3261, 0x1d},
+	{0x3262, 0xd8},
+	{0x3263, 0x0f},
+	{0x3264, 0xf7},
+	{0x3265, 0x11},
+	{0x3266, 0x0f},
+	{0x3267, 0xea},
+	{0x3268, 0x3d},
+	{0x3269, 0x00},
+	{0x326a, 0x09},
+	{0x326b, 0xcc},
+	{0x326c, 0x00},
+	{0x326d, 0x9b},
+	{0x326e, 0x73},
+	{0x326f, 0x0f},
+	{0x3270, 0xd4},
+	{0x3271, 0x9e},
+	{0x3272, 0x00},
+	{0x3273, 0x1a},
+	{0x3274, 0x87},
+	{0x3275, 0x0f},
+	{0x3276, 0xfd},
+	{0x3277, 0xeb},
+	{0x3278, 0x0f},
+	{0x3279, 0xf5},
+	{0x327a, 0xb4},
+	{0x327b, 0x00},
+	{0x327c, 0x0d},
+	{0x327d, 0x8c},
+	{0x327e, 0x0f},
+	{0x327f, 0xc9},
+	{0x3280, 0x4d},
+	{0x3281, 0x00},
+	{0x3282, 0x1d},
+	{0x3283, 0x2d},
+	{0x3284, 0x0f},
+	{0x3285, 0xea},
+	{0x3286, 0x5b},
+	{0x3287, 0x00},
+	{0x3288, 0x04},
+	{0x3289, 0x76},
+	{0x328a, 0x00},
+	{0x328b, 0x10},
+	{0x328c, 0x2d},
+	{0x328d, 0x0f},
+	{0x328e, 0xe6},
+	{0x328f, 0xde},
+	{0x3290, 0x00},
+	{0x3291, 0x26},
+	{0x3292, 0x85},
+	{0x3293, 0x0f},
+	{0x3294, 0xcf},
+	{0x3295, 0x12},
+	{0x3296, 0x00},
+	{0x3297, 0x14},
+	{0x3298, 0x0f},
+	{0x3299, 0x00},
+	{0x329a, 0x0b},
+	{0x329b, 0x36},
+	{0x329c, 0x0f},
+	{0x329d, 0xe4},
+	{0x329e, 0xa4},
+	{0x329f, 0x00},
+	{0x32a0, 0x21},
+	{0x32a1, 0x1f},
+	{0x32a2, 0x0f},
+	{0x32a3, 0xf3},
+	{0x32a4, 0x99},
+	{0x32a5, 0x00},
+	{0x32a6, 0x30},
+	{0x32a7, 0x8f},
+	{0x32a8, 0x0f},
+	{0x32a9, 0xf9},
+	{0x32aa, 0x35},
+	{0x32ab, 0x0f},
+	{0x32ac, 0xee},
+	{0x32ad, 0x6e},
+	{0x32ae, 0x00},
+	{0x32af, 0x09},
+	{0x32b0, 0x19},
+	{0x32b1, 0x0f},
+	{0x32b2, 0xf0},
+	{0x32b3, 0x57},
+	{0x32b4, 0x00},
+	{0x32b5, 0x01},
+	{0x32b6, 0xcc},
+	{0x32b7, 0x0f},
+	{0x32b8, 0xf1},
+	{0x32b9, 0x0b},
+	{0x32ba, 0x0f},
+	{0x32bb, 0xee},
+	{0x32bc, 0x99},
+	{0x32bd, 0x00},
+	{0x32be, 0x11},
+	{0x32bf, 0x3d},
+	{0x32c0, 0x00},
+	{0x32c1, 0x10},
+	{0x32c2, 0x64},
+	{0x32c3, 0x0f},
+	{0x32c4, 0xf6},
+	{0x32c5, 0xab},
+	{0x32c6, 0x00},
+	{0x32c7, 0x03},
+	{0x32c8, 0x19},
+	{0x32c9, 0x0f},
+	{0x32ca, 0xf3},
+	{0x32cb, 0xc9},
+	{0x32cc, 0x00},
+	{0x32cd, 0x17},
+	{0x32ce, 0xb3},
+	{0x32cf, 0x0f},
+	{0x32d0, 0xf2},
+	{0x32d1, 0x3d},
+	{0x32d2, 0x0f},
+	{0x32d3, 0xf4},
+	{0x32d4, 0x7e},
+	{0x32d5, 0x00},
+	{0x32d6, 0x09},
+	{0x32d7, 0x46},
+	{0x32d8, 0x00},
+	{0x32d9, 0x7c},
+	{0x32da, 0x79},
+	{0x32db, 0x0f},
+	{0x32dc, 0xde},
+	{0x32dd, 0x19},
+	{0x32de, 0x00},
+	{0x32df, 0x19},
+	{0x32e0, 0xe8},
+	{0x32e1, 0x0f},
+	{0x32e2, 0xf3},
+	{0x32e3, 0x41},
+	{0x32e4, 0x00},
+	{0x32e5, 0x03},
+	{0x32e6, 0x4c},
+	{0x32e7, 0x00},
+	{0x32e8, 0x05},
+	{0x32e9, 0x73},
+	{0x32ea, 0x0f},
+	{0x32eb, 0xd6},
+	{0x32ec, 0xa5},
+	{0x32ed, 0x00},
+	{0x32ee, 0x1f},
+	{0x32ef, 0x81},
+	{0x32f0, 0x0f},
+	{0x32f1, 0xdc},
+	{0x32f2, 0xe6},
+	{0x32f3, 0x00},
+	{0x32f4, 0x18},
+	{0x32f5, 0x65},
+	{0x32f6, 0x00},
+	{0x32f7, 0x00},
+	{0x32f8, 0x11},
+	{0x32f9, 0x0f},
+	{0x32fa, 0xed},
+	{0x32fb, 0x65},
+	{0x32fc, 0x00},
+	{0x32fd, 0x23},
+	{0x32fe, 0x12},
+	{0x32ff, 0x0f},
+	{0x3300, 0xcf},
+	{0x3301, 0x28},
+	{0x3302, 0x00},
+	{0x3303, 0x2b},
+	{0x3304, 0xda},
+	{0x3305, 0x0f},
+	{0x3306, 0xef},
+	{0x3307, 0xae},
+	{0x3308, 0x0f},
+	{0x3309, 0xeb},
+	{0x330a, 0x13},
+	{0x330b, 0x00},
+	{0x330c, 0x27},
+	{0x330d, 0xb8},
+	{0x330e, 0x0f},
+	{0x330f, 0xec},
+	{0x3310, 0x69},
+	{0x3311, 0x00},
+	{0x3312, 0x2f},
+	{0x3313, 0x5f},
+	{0x3314, 0x0f},
+	{0x3315, 0xdf},
+	{0x3316, 0x4f},
+	{0x3317, 0x00},
+	{0x3318, 0x05},
+	{0x3319, 0x70},
+	{0x331a, 0x00},
+	{0x331b, 0x0f},
+	{0x331c, 0xd2},
+	{0x331d, 0x0f},
+	{0x331e, 0xe1},
+	{0x331f, 0xd8},
+	{0x3320, 0x00},
+	{0x3321, 0x09},
+	{0x3322, 0xcf},
+	{0x3323, 0x0f},
+	{0x3324, 0xf2},
+	{0x3325, 0x6e},
+	{0x3326, 0x0f},
+	{0x3327, 0xf6},
+	{0x3328, 0xb4},
+	{0x3329, 0x00},
+	{0x332a, 0x0d},
+	{0x332b, 0x87},
+	{0x332c, 0x00},
+	{0x332d, 0x08},
+	{0x332e, 0x1e},
+	{0x332f, 0x0f},
+	{0x3330, 0xfa},
+	{0x3331, 0x6e},
+	{0x3332, 0x0f},
+	{0x3333, 0xff},
+	{0x3334, 0xaa},
+	{0x3335, 0x0f},
+	{0x3336, 0xf2},
+	{0x3337, 0xc0},
+	{0x3338, 0x00},
+	{0x3339, 0x1d},
+	{0x333a, 0x18},
+	{0x333b, 0x0f},
+	{0x333c, 0xef},
+	{0x333d, 0xed},
+	{0x333e, 0x0f},
+	{0x333f, 0xec},
+	{0x3340, 0xf6},
+	{0x3341, 0x00},
+	{0x3342, 0x16},
+	{0x3343, 0x8e},
+	{0x3344, 0x00},
+	{0x3345, 0x9c},
+	{0x3346, 0x52},
+	{0x3347, 0x0f},
+	{0x3348, 0xcf},
+	{0x3349, 0xb9},
+	{0x334a, 0x00},
+	{0x334b, 0x29},
+	{0x334c, 0xe9},
+	{0x334d, 0x0f},
+	{0x334e, 0xe2},
+	{0x334f, 0x83},
+	{0x3350, 0x00},
+	{0x3351, 0x11},
+	{0x3352, 0xcc},
+	{0x3353, 0x0f},
+	{0x3354, 0xff},
+	{0x3355, 0xf4},
+	{0x3356, 0x0f},
+	{0x3357, 0xc1},
+	{0x3358, 0xa4},
+	{0x3359, 0x00},
+	{0x335a, 0x2f},
+	{0x335b, 0xce},
+	{0x335c, 0x0f},
+	{0x335d, 0xc5},
+	{0x335e, 0xbb},
+	{0x335f, 0x00},
+	{0x3360, 0x35},
+	{0x3361, 0x2a},
+	{0x3362, 0x0f},
+	{0x3363, 0xe6},
+	{0x3364, 0x2a},
+	{0x3365, 0x0f},
+	{0x3366, 0xf7},
+	{0x3367, 0x44},
+	{0x3368, 0x00},
+	{0x3369, 0x31},
+	{0x336a, 0xfe},
+	{0x336b, 0x0f},
+	{0x336c, 0xb6},
+	{0x336d, 0x84},
+	{0x336e, 0x00},
+	{0x336f, 0x3c},
+	{0x3370, 0x71},
+	{0x3371, 0x0f},
+	{0x3372, 0xe5},
+	{0x3373, 0xfe},
+	{0x3374, 0x0f},
+	{0x3375, 0xf2},
+	{0x3376, 0x87},
+	{0x3377, 0x00},
+	{0x3378, 0x29},
+	{0x3379, 0x2b},
+	{0x337a, 0x0f},
+	{0x337b, 0xe5},
+	{0x337c, 0x3f},
+	{0x337d, 0x00},
+	{0x337e, 0x45},
+	{0x337f, 0xc6},
+	{0x3380, 0x0f},
+	{0x3381, 0xdf},
+	{0x3382, 0xe6},
+	{0x3383, 0x0f},
+	{0x3384, 0xfb},
+	{0x3385, 0x0f},
+	{0x3386, 0x00},
+	{0x3387, 0x0f},
+	{0x3388, 0xf4},
+	{0x3389, 0x0f},
+	{0x338a, 0xdf},
+	{0x338b, 0x72},
+	{0x338c, 0x00},
+	{0x338d, 0x0e},
+	{0x338e, 0xaf},
+	{0x338f, 0x0f},
+	{0x3390, 0xed},
+	{0x3391, 0x7a},
+	{0x3392, 0x0f},
+	{0x3393, 0xe5},
+	{0x3394, 0xab},
+	{0x3395, 0x00},
+	{0x3396, 0x18},
+	{0x3397, 0x43},
+	{0x3398, 0x00},
+	{0x3399, 0x1b},
+	{0x339a, 0x41},
+	{0x339b, 0x0f},
+	{0x339c, 0xea},
+	{0x339d, 0x84},
+	{0x339e, 0x0f},
+	{0x339f, 0xfd},
+	{0x33a0, 0xdb},
+	{0x33a1, 0x0f},
+	{0x33a2, 0xe9},
+	{0x33a3, 0xbd},
+	{0x33a4, 0x00},
+	{0x33a5, 0x30},
+	{0x33a6, 0x77},
+	{0x33a7, 0x0f},
+	{0x33a8, 0xe9},
+	{0x33a9, 0x93},
+	{0x33aa, 0x0f},
+	{0x33ab, 0xd7},
+	{0x33ac, 0xde},
+	{0x33ad, 0x00},
+	{0x33ae, 0x2a},
+	{0x33af, 0x14},
+	{0x309D, 0x62},
+	{0x309d, 0x22},
+
+/* LC setting End */
+	 },
+/*EVT5 */
+	{
+/* LC setting Start */
+	 {0x3200, 0x00}, /* 100108 Modify LC setting DNP light source t75-r73*/
+	 {0x3201, 0x99},
+	 {0x3202, 0xc1},
+	 {0x3203, 0x0f},
+	 {0x3204, 0xd0},
+	 {0x3205, 0x1b},
+	 {0x3206, 0x00},
+	 {0x3207, 0x24},
+	 {0x3208, 0x8d},
+	 {0x3209, 0x0f},
+	 {0x320a, 0xee},
+	 {0x320b, 0x0f},
+	 {0x320c, 0x00},
+	 {0x320d, 0x04},
+	 {0x320e, 0x5c},
+	 {0x320f, 0x00},
+	 {0x3210, 0x07},
+	 {0x3211, 0x68},
+	 {0x3212, 0x0f},
+	 {0x3213, 0xc2},
+	 {0x3214, 0x82},
+	 {0x3215, 0x00},
+	 {0x3216, 0x29},
+	 {0x3217, 0x3e},
+	 {0x3218, 0x0f},
+	 {0x3219, 0xd3},
+	 {0x321a, 0x63},
+	 {0x321b, 0x00},
+	 {0x321c, 0x22},
+	 {0x321d, 0x6c},
+	 {0x321e, 0x0f},
+	 {0x321f, 0xf8},
+	 {0x3220, 0xce},
+	 {0x3221, 0x0f},
+	 {0x3222, 0xed},
+	 {0x3223, 0x30},
+	 {0x3224, 0x00},
+	 {0x3225, 0x37},
+	 {0x3226, 0x87},
+	 {0x3227, 0x0f},
+	 {0x3228, 0xc2},
+	 {0x3229, 0x87},
+	 {0x322a, 0x00},
+	 {0x322b, 0x2a},
+	 {0x322c, 0xc6},
+	 {0x322d, 0x0f},
+	 {0x322e, 0xf3},
+	 {0x322f, 0xd9},
+	 {0x3230, 0x0f},
+	 {0x3231, 0xea},
+	 {0x3232, 0x1a},
+	 {0x3233, 0x00},
+	 {0x3234, 0x2d},
+	 {0x3235, 0x9f},
+	 {0x3236, 0x0f},
+	 {0x3237, 0xde},
+	 {0x3238, 0x7d},
+	 {0x3239, 0x00},
+	 {0x323a, 0x37},
+	 {0x323b, 0x1e},
+	 {0x323c, 0x0f},
+	 {0x323d, 0xed},
+	 {0x323e, 0x9c},
+	 {0x323f, 0x0f},
+	 {0x3240, 0xf6},
+	 {0x3241, 0xfd},
+	 {0x3242, 0x00},
+	 {0x3243, 0x15},
+	 {0x3244, 0xeb},
+	 {0x3245, 0x0f},
+	 {0x3246, 0xd3},
+	 {0x3247, 0xca},
+	 {0x3248, 0x00},
+	 {0x3249, 0x08},
+	 {0x324a, 0xe6},
+	 {0x324b, 0x0f},
+	 {0x324c, 0xf4},
+	 {0x324d, 0x7a},
+	 {0x324e, 0x0f},
+	 {0x324f, 0xed},
+	 {0x3250, 0x1e},
+	 {0x3251, 0x00},
+	 {0x3252, 0x0d},
+	 {0x3253, 0x46},
+	 {0x3254, 0x00},
+	 {0x3255, 0x0c},
+	 {0x3256, 0x3e},
+	 {0x3257, 0x00},
+	 {0x3258, 0x09},
+	 {0x3259, 0xcf},
+	 {0x325a, 0x00},
+	 {0x325b, 0x09},
+	 {0x325c, 0xb5},
+	 {0x325d, 0x0f},
+	 {0x325e, 0xec},
+	 {0x325f, 0x47},
+	 {0x3260, 0x00},
+	 {0x3261, 0x1d},
+	 {0x3262, 0xd8},
+	 {0x3263, 0x0f},
+	 {0x3264, 0xf7},
+	 {0x3265, 0x11},
+	 {0x3266, 0x0f},
+	 {0x3267, 0xea},
+	 {0x3268, 0x3d},
+	 {0x3269, 0x00},
+	 {0x326a, 0x09},
+	 {0x326b, 0xcc},
+	 {0x326c, 0x00},
+	 {0x326d, 0x99},
+	 {0x326e, 0x45},
+	 {0x326f, 0x0f},
+	 {0x3270, 0xd3},
+	 {0x3271, 0x80},
+	 {0x3272, 0x00},
+	 {0x3273, 0x20},
+	 {0x3274, 0xf7},
+	 {0x3275, 0x0f},
+	 {0x3276, 0xef},
+	 {0x3277, 0x0d},
+	 {0x3278, 0x00},
+	 {0x3279, 0x09},
+	 {0x327a, 0x3c},
+	 {0x327b, 0x00},
+	 {0x327c, 0x01},
+	 {0x327d, 0x16},
+	 {0x327e, 0x0f},
+	 {0x327f, 0xc9},
+	 {0x3280, 0x36},
+	 {0x3281, 0x00},
+	 {0x3282, 0x21},
+	 {0x3283, 0xff},
+	 {0x3284, 0x0f},
+	 {0x3285, 0xdc},
+	 {0x3286, 0xc2},
+	 {0x3287, 0x00},
+	 {0x3288, 0x1e},
+	 {0x3289, 0xc0},
+	 {0x328a, 0x0f},
+	 {0x328b, 0xf0},
+	 {0x328c, 0xa7},
+	 {0x328d, 0x0f},
+	 {0x328e, 0xf9},
+	 {0x328f, 0x2a},
+	 {0x3290, 0x00},
+	 {0x3291, 0x29},
+	 {0x3292, 0x5c},
+	 {0x3293, 0x0f},
+	 {0x3294, 0xc9},
+	 {0x3295, 0x2a},
+	 {0x3296, 0x00},
+	 {0x3297, 0x1f},
+	 {0x3298, 0x5c},
+	 {0x3299, 0x0f},
+	 {0x329a, 0xfa},
+	 {0x329b, 0x0c},
+	 {0x329c, 0x0f},
+	 {0x329d, 0xf3},
+	 {0x329e, 0x94},
+	 {0x329f, 0x00},
+	 {0x32a0, 0x1c},
+	 {0x32a1, 0xce},
+	 {0x32a2, 0x0f},
+	 {0x32a3, 0xed},
+	 {0x32a4, 0xb7},
+	 {0x32a5, 0x00},
+	 {0x32a6, 0x34},
+	 {0x32a7, 0x51},
+	 {0x32a8, 0x0f},
+	 {0x32a9, 0xfa},
+	 {0x32aa, 0x7d},
+	 {0x32ab, 0x0f},
+	 {0x32ac, 0xe6},
+	 {0x32ad, 0xbf},
+	 {0x32ae, 0x00},
+	 {0x32af, 0x18},
+	 {0x32b0, 0xc6},
+	 {0x32b1, 0x0f},
+	 {0x32b2, 0xe0},
+	 {0x32b3, 0x72},
+	 {0x32b4, 0x00},
+	 {0x32b5, 0x08},
+	 {0x32b6, 0x23},
+	 {0x32b7, 0x0f},
+	 {0x32b8, 0xf1},
+	 {0x32b9, 0x54},
+	 {0x32ba, 0x0f},
+	 {0x32bb, 0xe1},
+	 {0x32bc, 0x84},
+	 {0x32bd, 0x00},
+	 {0x32be, 0x26},
+	 {0x32bf, 0xb1},
+	 {0x32c0, 0x0f},
+	 {0x32c1, 0xfa},
+	 {0x32c2, 0xc2},
+	 {0x32c3, 0x00},
+	 {0x32c4, 0x05},
+	 {0x32c5, 0x3d},
+	 {0x32c6, 0x0f},
+	 {0x32c7, 0xff},
+	 {0x32c8, 0xaf},
+	 {0x32c9, 0x0f},
+	 {0x32ca, 0xf1},
+	 {0x32cb, 0xe5},
+	 {0x32cc, 0x00},
+	 {0x32cd, 0x21},
+	 {0x32ce, 0xdd},
+	 {0x32cf, 0x0f},
+	 {0x32d0, 0xe8},
+	 {0x32d1, 0x6a},
+	 {0x32d2, 0x0f},
+	 {0x32d3, 0xf4},
+	 {0x32d4, 0xfb},
+	 {0x32d5, 0x00},
+	 {0x32d6, 0x0c},
+	 {0x32d7, 0x89},
+	 {0x32d8, 0x00},
+	 {0x32d9, 0x7c},
+	 {0x32da, 0x79},
+	 {0x32db, 0x0f},
+	 {0x32dc, 0xde},
+	 {0x32dd, 0x19},
+	 {0x32de, 0x00},
+	 {0x32df, 0x19},
+	 {0x32e0, 0xe8},
+	 {0x32e1, 0x0f},
+	 {0x32e2, 0xf3},
+	 {0x32e3, 0x41},
+	 {0x32e4, 0x00},
+	 {0x32e5, 0x03},
+	 {0x32e6, 0x4c},
+	 {0x32e7, 0x00},
+	 {0x32e8, 0x05},
+	 {0x32e9, 0x73},
+	 {0x32ea, 0x0f},
+	 {0x32eb, 0xd6},
+	 {0x32ec, 0xa5},
+	 {0x32ed, 0x00},
+	 {0x32ee, 0x1f},
+	 {0x32ef, 0x81},
+	 {0x32f0, 0x0f},
+	 {0x32f1, 0xdc},
+	 {0x32f2, 0xe6},
+	 {0x32f3, 0x00},
+	 {0x32f4, 0x18},
+	 {0x32f5, 0x65},
+	 {0x32f6, 0x00},
+	 {0x32f7, 0x00},
+	 {0x32f8, 0x11},
+	 {0x32f9, 0x0f},
+	 {0x32fa, 0xed},
+	 {0x32fb, 0x65},
+	 {0x32fc, 0x00},
+	 {0x32fd, 0x23},
+	 {0x32fe, 0x12},
+	 {0x32ff, 0x0f},
+	 {0x3300, 0xcf},
+	 {0x3301, 0x28},
+	 {0x3302, 0x00},
+	 {0x3303, 0x2b},
+	 {0x3304, 0xda},
+	 {0x3305, 0x0f},
+	 {0x3306, 0xef},
+	 {0x3307, 0xae},
+	 {0x3308, 0x0f},
+	 {0x3309, 0xeb},
+	 {0x330a, 0x13},
+	 {0x330b, 0x00},
+	 {0x330c, 0x27},
+	 {0x330d, 0xb8},
+	 {0x330e, 0x0f},
+	 {0x330f, 0xec},
+	 {0x3310, 0x69},
+	 {0x3311, 0x00},
+	 {0x3312, 0x2f},
+	 {0x3313, 0x5f},
+	 {0x3314, 0x0f},
+	 {0x3315, 0xdf},
+	 {0x3316, 0x4f},
+	 {0x3317, 0x00},
+	 {0x3318, 0x05},
+	 {0x3319, 0x70},
+	 {0x331a, 0x00},
+	 {0x331b, 0x0f},
+	 {0x331c, 0xd2},
+	 {0x331d, 0x0f},
+	 {0x331e, 0xe1},
+	 {0x331f, 0xd8},
+	 {0x3320, 0x00},
+	 {0x3321, 0x09},
+	 {0x3322, 0xcf},
+	 {0x3323, 0x0f},
+	 {0x3324, 0xf2},
+	 {0x3325, 0x6e},
+	 {0x3326, 0x0f},
+	 {0x3327, 0xf6},
+	 {0x3328, 0xb4},
+	 {0x3329, 0x00},
+	 {0x332a, 0x0d},
+	 {0x332b, 0x87},
+	 {0x332c, 0x00},
+	 {0x332d, 0x08},
+	 {0x332e, 0x1e},
+	 {0x332f, 0x0f},
+	 {0x3330, 0xfa},
+	 {0x3331, 0x6e},
+	 {0x3332, 0x0f},
+	 {0x3333, 0xff},
+	 {0x3334, 0xaa},
+	 {0x3335, 0x0f},
+	 {0x3336, 0xf2},
+	 {0x3337, 0xc0},
+	 {0x3338, 0x00},
+	 {0x3339, 0x1d},
+	 {0x333a, 0x18},
+	 {0x333b, 0x0f},
+	 {0x333c, 0xef},
+	 {0x333d, 0xed},
+	 {0x333e, 0x0f},
+	 {0x333f, 0xec},
+	 {0x3340, 0xf6},
+	 {0x3341, 0x00},
+	 {0x3342, 0x16},
+	 {0x3343, 0x8e},
+	 {0x3344, 0x00},
+	 {0x3345, 0x9c},
+	 {0x3346, 0x52},
+	 {0x3347, 0x0f},
+	 {0x3348, 0xcf},
+	 {0x3349, 0xb9},
+	 {0x334a, 0x00},
+	 {0x334b, 0x29},
+	 {0x334c, 0xe9},
+	 {0x334d, 0x0f},
+	 {0x334e, 0xe2},
+	 {0x334f, 0x83},
+	 {0x3350, 0x00},
+	 {0x3351, 0x11},
+	 {0x3352, 0xcc},
+	 {0x3353, 0x0f},
+	 {0x3354, 0xff},
+	 {0x3355, 0xf4},
+	 {0x3356, 0x0f},
+	 {0x3357, 0xc1},
+	 {0x3358, 0xa4},
+	 {0x3359, 0x00},
+	 {0x335a, 0x2f},
+	 {0x335b, 0xce},
+	 {0x335c, 0x0f},
+	 {0x335d, 0xc5},
+	 {0x335e, 0xbb},
+	 {0x335f, 0x00},
+	 {0x3360, 0x35},
+	 {0x3361, 0x2a},
+	 {0x3362, 0x0f},
+	 {0x3363, 0xe6},
+	 {0x3364, 0x2a},
+	 {0x3365, 0x0f},
+	 {0x3366, 0xf7},
+	 {0x3367, 0x44},
+	 {0x3368, 0x00},
+	 {0x3369, 0x31},
+	 {0x336a, 0xfe},
+	 {0x336b, 0x0f},
+	 {0x336c, 0xb6},
+	 {0x336d, 0x84},
+	 {0x336e, 0x00},
+	 {0x336f, 0x3c},
+	 {0x3370, 0x71},
+	 {0x3371, 0x0f},
+	 {0x3372, 0xe5},
+	 {0x3373, 0xfe},
+	 {0x3374, 0x0f},
+	 {0x3375, 0xf2},
+	 {0x3376, 0x87},
+	 {0x3377, 0x00},
+	 {0x3378, 0x29},
+	 {0x3379, 0x2b},
+	 {0x337a, 0x0f},
+	 {0x337b, 0xe5},
+	 {0x337c, 0x3f},
+	 {0x337d, 0x00},
+	 {0x337e, 0x45},
+	 {0x337f, 0xc6},
+	 {0x3380, 0x0f},
+	 {0x3381, 0xdf},
+	 {0x3382, 0xe6},
+	 {0x3383, 0x0f},
+	 {0x3384, 0xfb},
+	 {0x3385, 0x0f},
+	 {0x3386, 0x00},
+	 {0x3387, 0x0f},
+	 {0x3388, 0xf4},
+	 {0x3389, 0x0f},
+	 {0x338a, 0xdf},
+	 {0x338b, 0x72},
+	 {0x338c, 0x00},
+	 {0x338d, 0x0e},
+	 {0x338e, 0xaf},
+	 {0x338f, 0x0f},
+	 {0x3390, 0xed},
+	 {0x3391, 0x7a},
+	 {0x3392, 0x0f},
+	 {0x3393, 0xe5},
+	 {0x3394, 0xab},
+	 {0x3395, 0x00},
+	 {0x3396, 0x18},
+	 {0x3397, 0x43},
+	 {0x3398, 0x00},
+	 {0x3399, 0x1b},
+	 {0x339a, 0x41},
+	 {0x339b, 0x0f},
+	 {0x339c, 0xea},
+	 {0x339d, 0x84},
+	 {0x339e, 0x0f},
+	 {0x339f, 0xfd},
+	 {0x33a0, 0xdb},
+	 {0x33a1, 0x0f},
+	 {0x33a2, 0xe9},
+	 {0x33a3, 0xbd},
+	 {0x33a4, 0x00},
+	 {0x33a5, 0x30},
+	 {0x33a6, 0x77},
+	 {0x33a7, 0x0f},
+	 {0x33a8, 0xe9},
+	 {0x33a9, 0x93},
+	 {0x33aa, 0x0f},
+	 {0x33ab, 0xd7},
+	 {0x33ac, 0xde},
+	 {0x33ad, 0x00},
+	 {0x33ae, 0x2a},
+	 {0x33af, 0x14},
+	 {0x309D, 0x62},
+	 {0x309d, 0x22}, /* shading enable */
+	 /*LC setting End */
+	 }
+}; /* lc_setting} */
+
+static struct wake_lock s5k3e2fx_wake_lock;
+
+static inline void init_suspend(void)
+{
+	wake_lock_init(&s5k3e2fx_wake_lock, WAKE_LOCK_IDLE, "s5k3e2fx");
+}
+
+static inline void deinit_suspend(void)
+{
+	wake_lock_destroy(&s5k3e2fx_wake_lock);
+}
+
+static inline void prevent_suspend(void)
+{
+	wake_lock(&s5k3e2fx_wake_lock);
+}
+
+static inline void allow_suspend(void)
+{
+	wake_unlock(&s5k3e2fx_wake_lock);
+}
+
+struct reg_struct {
+/* PLL setting */
+	uint8_t pre_pll_clk_div;	/* 0x0305 */
+	uint8_t pll_multiplier_msb;	/* 0x0306 */
+	uint8_t pll_multiplier_lsb;	/* 0x0307 */
+	uint8_t vt_pix_clk_div;	/* 0x0301 */
+	uint8_t vt_sys_clk_div;	/* 0x0303 */
+	uint8_t op_pix_clk_div;	/* 0x0309 */
+	uint8_t op_sys_clk_div;	/* 0x030B */
+/* Data Format */
+	uint8_t ccp_data_format_msb;	/* 0x0112 */
+	uint8_t ccp_data_format_lsb;	/* 0x0113 */
+/* Preview Output Size */
+	uint8_t x_output_size_msb;	/* 0x034C */
+	uint8_t x_output_size_lsb;	/* 0x034D */
+	uint8_t y_output_size_msb;	/* 0x034E */
+	uint8_t y_output_size_lsb;	/* 0x034F */
+/* add the X-Y addr setting position */
+	uint8_t x_addr_start_MSB;	/* 0x0344 */
+	uint8_t x_addr_start_LSB;	/* 0x0345 */
+	uint8_t y_addr_start_MSB;	/* 0x0346 */
+	uint8_t y_addr_start_LSB;	/* 0x0347 */
+	uint8_t x_addr_end_MSB;	/* 0x0348 */
+	uint8_t x_addr_end_LSB;	/* 0x0349 */
+	uint8_t y_addr_end_MSB;	/* 0x034A */
+	uint8_t y_addr_end_LSB;	/* 0x034B */
+/* change the setting position */
+/* Frame format */
+	uint8_t frame_length_lines_msb;	/* 0x0340 */
+	uint8_t frame_length_lines_lsb;	/* 0x0341 */
+	uint8_t line_length_pck_msb;	/* 0x0342 */
+	uint8_t line_length_pck_lsb;	/* 0x0343 */
+/* binning */
+	uint8_t x_even_inc;	/* 0x0381 */
+	uint8_t x_odd_inc;	/* 0x0383 */
+	uint8_t y_even_inc;	/* 0x0385 */
+	uint8_t y_odd_inc;	/* 0x0387 */
+	uint8_t binning_enable;	/* 0x3014 */
+/* Samsung MSR Setting */
+	uint8_t sel_ccp;	/* 0x30C4 */
+	uint8_t ld_start;	/* 0x3000 */
+	uint8_t ld_end;		/* 0x3001 */
+	uint8_t sl_start;	/* 0x3002 */
+	uint8_t sl_end;		/* 0x3003 */
+	uint8_t rx_start;	/* 0x3004 */
+	uint8_t s1_start;	/* 0x3005 */
+	uint8_t s1_end;		/* 0x3006 */
+	uint8_t s1s_start;	/* 0x3007 */
+	uint8_t s1s_end;	/* 0x3008 */
+	uint8_t s3_start;	/* 0x3009 */
+	uint8_t s3_end;		/* 0x300A */
+	uint8_t cmp_en_start;	/* 0x300B */
+	uint8_t clp_sl_start;	/* 0x300C */
+	uint8_t clp_sl_end;	/* 0x300D */
+	uint8_t off_start;	/* 0x300E */
+	uint8_t rmp_en_start;	/* 0x300F */
+	uint8_t tx_start;	/* 0x3010 */
+	uint8_t tx_end;		/* 0x3011 */
+	uint8_t stx_width;	/* 0x3012 */
+/* Samsung other MSR setting */
+	uint8_t clamp_on;	/* 0x3015 */
+	uint8_t reg_301d_reserved;	/* 0x301D */
+	uint8_t vpix;		/* 0x3024 */
+	uint8_t reg_3028_reserved;	/* 0x3028 */
+	uint8_t reg_3070_reserved;	/* 0x3070 */
+	uint8_t reg_3072_reserved;	/* 0x3072 */
+	uint8_t reg_301b_reserved;	/* 0x301B */
+	uint8_t offset;		/* 0x307E */
+	uint8_t reg_30bd_reserved;	/* 0x30BD */
+	uint8_t reg_30c2_reserved;	/* 0x30C2 */
+	uint8_t shade_clk_enable;	/* 0x30AC */
+	uint8_t reg_3051_reserved;	/* 0x3051 */
+	uint8_t reg_3029_reserved;	/* 0x3029 */
+	uint8_t reg_30bf_reserved;	/* 0x30BF */
+	uint8_t reg_3022_reserved;	/* 0x3022 */
+	uint8_t reg_3019_reserved;	/* 0x3019 */
+/* end: Samsung other MSR setting */
+	uint8_t reg_3152_reserved;	/* 0x3152 */
+/* Samsung signal output setting */
+	uint8_t reg_3150_reserved;	/* 0x3150 */
+	uint8_t reg_3157_reserved;	/* 0x3157 */
+	uint8_t reg_3159_reserved;	/* 0x3159 */
+/* end: Samsung signal output setting */
+	uint8_t reg_315A_reserved;	/* 0x315A */
+/* AEC Setting */
+	uint8_t analogue_gain_code_global_msb;	/* 0x0204 */
+	uint8_t analogue_gain_code_global_lsb;	/* 0x0205 */
+	uint8_t fine_integration_time;	/* 0x0200 */
+	uint8_t coarse_integration_time;	/* 0x0202 */
+/* LC Preview/Snapshot difference register */
+/* Preview LC Setting */
+	uint8_t sh4ch_blk_width_r;	/* 0x309E */
+	uint8_t sh4ch_blk_height_r;	/* 0x309F */
+	uint8_t sh4ch_step_x_r_MSB;	/* 0x30A0 */
+	uint8_t sh4ch_step_x_r_LSB;	/* 0x30A1 */
+	uint8_t sh4ch_step_y_r_MSB;	/* 0x30A2 */
+	uint8_t sh4ch_step_y_r_LSB;	/* 0x30A3 */
+	uint8_t sh4ch_start_blk_cnt_x_r;	/* 0x30A4 */
+	uint8_t sh4ch_start_blk_int_x_r;	/* 0x30A5 */
+	uint8_t sh4ch_start_frac_x_r_MSB;	/* 0x30A6 */
+	uint8_t sh4ch_start_frac_x_r_LSB;	/* 0x30A7 */
+	uint8_t sh4ch_start_blk_cnt_y_r;	/* 0x30A8 */
+	uint8_t sh4ch_start_blk_int_y_r;	/* 0x30A9 */
+	uint8_t sh4ch_start_frac_y_r_MSB;	/* 0x30AA */
+	uint8_t sh4ch_start_frac_y_r_LSB;	/* 0x30AB */
+/* end: LC Preview/Snapshot difference register */
+	uint32_t size_h;
+	uint32_t blk_l;
+	uint32_t size_w;
+	uint32_t blk_p;
+};
+
+struct reg_struct s5k3e2fx_reg_pat[2] = {
+	{			/* Preview */
+/* PLL setting */
+	 0x06,			/* pre_pll_clk_div               REG=0x0305 */
+	 0x00,			/* pll_multiplier_msb            REG=0x0306 */
+	 REG_PLL_MULTIPLIER_LSB_VALUE,
+				/* pll_multiplier_lsb            REG=0x0307 */
+	 0x08,			/* vt_pix_clk_div                REG=0x0301 */
+	 0x01,			/* vt_sys_clk_div                REG=0x0303 */
+	 0x08,			/* op_pix_clk_div                REG=0x0309 */
+	 0x01,			/* op_sys_clk_div                REG=0x030B */
+/* Data Format */
+	 0x0a,			/* ccp_data_format_msb   REG=0x0112 */
+	 0x0a,			/* ccp_data_format_lsb   REG=0x0113 */
+/* Preview Output Size */
+	 0x05,			/* x_output_size_msb     REG=0x034C */
+	 0x10,			/* x_output_size_lsb     REG=0x034D */
+	 0x03,			/* y_output_size_msb     REG=0x034E */
+	 0xcc,			/* y_output_size_lsb     REG=0x034F */
+/* X-Y addr setting position. Start */
+	 0x00,			/* x_addr_start_MSB              REG=0x0344 */
+	 0x08,			/* x_addr_start_LSB              REG=0x0345 */
+	 0x00,			/* y_addr_start_MSB              REG=0x0346 */
+	 0x08,			/* y_addr_start_LSB              REG=0x0347 */
+	 0x0a,			/* x_addr_end_MSB                REG=0x0348 */
+	 0x27,			/* x_addr_end_LSB                REG=0x0349 */
+	 0x07,			/* y_addr_end_MSB                REG=0x034A */
+	 0x9f,			/* y_addr_end_LSB                REG=0x034B */
+/* change the setting position */
+/* Frame format */
+	 0x03,			/* frame_length_lines_msb        REG=0x0340 */
+	 0xe2,			/* frame_length_lines_lsb        REG=0x0341 */
+	 0x0a,			/* line_length_pck_msb           REG=0x0342 */
+	 0xac,			/* line_length_pck_lsb           REG=0x0343 */
+/* enable binning for preview */
+	 0x01,			/* x_even_inc             REG=0x0381 */
+	 0x01,			/* x_odd_inc              REG=0x0383 */
+	 0x01,			/* y_even_inc             REG=0x0385 */
+	 0x03,			/* y_odd_inc              REG=0x0387 */
+	 0x06,			/* binning_enable         REG=0x3014 */
+/* Samsung MSR Setting */
+	 0x01,			/* sel_ccp                       REG=0x30C4 */
+	 0x03,			/* ld_start                      REG=0x3000 */
+	 0x94,			/* ld_end                        REG=0x3001 */
+	 0x02,			/* sl_start                      REG=0x3002 */
+	 0x95,			/* sl_end                        REG=0x3003 */
+	 0x0f,			/* rx_start                      REG=0x3004 */
+	 0x05,			/* s1_start                      REG=0x3005 */
+	 0x3c,			/* s1_end                        REG=0x3006 */
+	 0x8c,			/* s1s_start                     REG=0x3007 */
+	 0x93,			/* s1s_end                       REG=0x3008 */
+	 0x05,			/* s3_start                      REG=0x3009 */
+	 0x3a,			/* s3_end                        REG=0x300A */
+	 0x10,			/* cmp_en_start                  REG=0x300B */
+	 0x02,			/* clp_sl_start                  REG=0x300C */
+	 0x3e,			/* clp_sl_end                    REG=0x300D */
+	 0x02,			/* off_start                     REG=0x300E */
+	 0x0e,			/* rmp_en_start                  REG=0x300F */
+	 0x46,			/* tx_start                      REG=0x3010 */
+	 0x64,			/* tx_end                        REG=0x3011 */
+	 0x1e,			/* stx_width                     REG=0x3012 */
+/* Samsung other MSR setting. */
+	 0x00,			/* clamp_on                      REG=0x3015 */
+	 0x3f,			/* reg_301d_reserved             REG=0x301D */
+	 0x04,			/* vpix                          REG=0x3024 */
+	 0x40,			/* reg_3028_reserved             REG=0x3028 */
+	 0xdf,			/* reg_3070_reserved             REG=0x3070 */
+	 0x20,			/* reg_3072_reserved             REG=0x3072 */
+	 0x73,			/* reg_3073_reserved             REG=0x301B */
+	 0x02,			/* offset                        REG=0x307E */
+	 0x06,			/* reg_30bd_reserved             REG=0x30BD */
+	 0x0b,			/* reg_30c2_reserved             REG=0x30C2 */
+	 0x81,			/* shade_clk_enable              REG=0x30AC */
+	 0xe6,			/* reg_3051_reserved             REG=0x3051 */
+	 0x02,			/* reg_3029_reserved             REG=0x3029 */
+	 0x00,			/* reg_30bf_reserved             REG=0x30BF */
+	 0x87,			/* reg_3022_reserved             REG=0x3022 */
+	 0x60,			/* reg_3019_reserved             REG=0x3019 */
+/* end: Samsung other MSR setting. */
+	 0x08,			/* reg_3152_reserved             REG=0x3152 */
+	 0x50,			/* reg_3150_reserved             REG=0x3150 */
+/* Inverse PCLK */
+	 0x04,			/* reg_3157_reserved             REG=0x3157 */
+/* PCLK Delay offset; 0x0a will delay around 4ns at 80MHz */
+	 0x0f,			/* reg_3159_reserved             REG=0x3159 */
+/* HS, VS driving strength [3:2]=>VS, [1:0]=>HS 00:2mA, 01:4mA, 10:6mA,
+ * 11:8mA
+ */
+	 0xf0,			/* reg_315A_reserved             REG=0x315A */
+/* PCLK, DATA driving strength [7:6]=>data, [5:4]=>PCLK 00:2mA, 01:4mA, 10:6mA,
+ * 11:8mA
+ */
+/* AEC Setting */
+	 0x00,			/* analogue_gain_code_global_msb REG=0x0204 */
+	 REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB_VALUE,
+				/* analogue_gain_code_global_lsb REG=0x0205 */
+	 0x02,			/* fine_integration_time         REG=0x0200 */
+	 0x03,			/* coarse_integration_time       REG=0x0202 */
+/* LC Preview/Snapshot difference register. */
+/* Preview LC config Setting */
+	 0x52,			/* sh4ch_blk_width_r             REG=0x309E */
+	 0x3e,			/* sh4ch_blk_height_r            REG=0x309F */
+	 0x03,			/* sh4ch_step_x_r_MSB            REG=0x30A0 */
+	 0x1f,			/* sh4ch_step_x_r_LSB            REG=0x30A1 */
+	 0x04,			/* sh4ch_step_y_r_MSB            REG=0x30A2 */
+	 0x21,			/* sh4ch_step_y_r_LSB            REG=0x30A3 */
+	 0x04,			/* sh4ch_start_blk_cnt_x_r       REG=0x30A4 */
+	 0x00,			/* sh4ch_start_blk_int_x_r       REG=0x30A5 */
+	 0x0c,			/* sh4ch_start_frac_x_r_MSB      REG=0x30A6 */
+	 0x7c,			/* sh4ch_start_frac_x_r_LSB      REG=0x30A7 */
+	 0x04,			/* sh4ch_start_blk_cnt_y_r       REG=0x30A8 */
+	 0x00,			/* sh4ch_start_blk_int_y_r       REG=0x30A9 */
+	 0x10,			/* sh4ch_start_frac_y_r_MSB      REG=0x30AA */
+	 0x84,			/* sh4ch_start_frac_y_r_LSB      REG=0x30AB */
+/* end: LC Preview/Snapshot difference register. */
+	 S5K3E2FX_QTR_SIZE_HEIGHT,
+	 18,
+	 S5K3E2FX_QTR_SIZE_WIDTH,
+	 1436},
+	{			/* Snapshot */
+/* PLL setting */
+	 0x06,			/* pre_pll_clk_div               REG=0x0305 */
+	 0x00,			/* pll_multiplier_msb            REG=0x0306 */
+	 REG_PLL_MULTIPLIER_LSB_VALUE,
+				/* pll_multiplier_lsb            REG=0x0307 */
+	 0x08,			/* vt_pix_clk_div                REG=0x0301 */
+	 0x01,			/* vt_sys_clk_div                REG=0x0303 */
+	 0x08,			/* op_pix_clk_div                REG=0x0309 */
+	 0x01,			/* op_sys_clk_div                REG=0x030B */
+/* Data Format */
+	 0x0a,			/* ccp_data_format_msb           REG=0x0112 */
+	 0x0a,			/* ccp_data_format_lsb           REG=0x0113 */
+/* Snapshot Output Size */
+	 0x0a,			/* x_output_size_msb             REG=0x034C */
+	 0x30,			/* x_output_size_lsb             REG=0x034D */
+	 0x07,			/* y_output_size_msb             REG=0x034E */
+	 0xa8,			/* y_output_size_lsb             REG=0x034F */
+/* add the X-Y addr setting position. */
+	 0x00,			/* x_addr_start_MSB              REG=0x0344 */
+	 0x00,			/* x_addr_start_LSB              REG=0x0345 */
+	 0x00,			/* y_addr_start_MSB              REG=0x0346 */
+	 0x00,			/* y_addr_start_LSB              REG=0x0347 */
+	 0x0a,			/* x_addr_end_MSB                REG=0x0348 */
+	 0x2F,			/* x_addr_end_LSB                REG=0x0349 */
+	 0x07,			/* y_addr_end_MSB                REG=0x034A */
+	 0xA7,			/* y_addr_end_LSB                REG=0x034B */
+/* Change the setting position. */
+/* Frame format */
+	 0x07,			/* frame_length_lines_msb        REG=0x0340 */
+	 0xb6,			/* frame_length_lines_lsb        REG=0x0341 */
+	 0x0a,			/* line_length_pck_msb           REG=0x0342 */
+	 0xac,			/* line_length_pck_lsb           REG=0x0343 */
+/* disable binning for snapshot */
+	 0x01,			/* x_even_inc                    REG=0x0381 */
+	 0x01,			/* x_odd_inc                     REG=0x0383 */
+	 0x01,			/* y_even_inc                    REG=0x0385 */
+	 0x01,			/* y_odd_inc                     REG=0x0387 */
+	 0x00,			/* binning_enable                REG=0x3014 */
+/* Samsung MSR Setting */
+	 0x01,			/* sel_ccp                       REG=0x30C4 */
+	 0x03,			/* ld_start                      REG=0x3000 */
+	 0x94,			/* ld_end                        REG=0x3001 */
+	 0x02,			/* sl_start                      REG=0x3002 */
+	 0x95,			/* sl_end                        REG=0x3003 */
+	 0x0f,			/* rx_start                      REG=0x3004 */
+	 0x05,			/* s1_start                      REG=0x3005 */
+	 0x3c,			/* s1_end                        REG=0x3006 */
+	 0x8c,			/* s1s_start                     REG=0x3007 */
+	 0x93,			/* s1s_end                       REG=0x3008 */
+	 0x05,			/* s3_start                      REG=0x3009 */
+	 0x3a,			/* s3_end                        REG=0x300A */
+	 0x10,			/* cmp_en_start                  REG=0x300B */
+	 0x02,			/* clp_sl_start                  REG=0x300C */
+	 0x3e,			/* clp_sl_end                    REG=0x300D */
+	 0x02,			/* off_start                     REG=0x300E */
+	 0x0e,			/* rmp_en_start                  REG=0x300F */
+	 0x46,			/* tx_start                      REG=0x3010 */
+	 0x64,			/* tx_end                        REG=0x3011 */
+	 0x1e,			/* stx_width                     REG=0x3012 */
+/* Add Samsung other MSR setting. */
+	 0x00,			/* clamp_on                      REG=0x3015 */
+	 0x3f,			/* reg_301d_reserved             REG=0x301D */
+	 0x04,			/* vpix                          REG=0x3024 */
+	 0x40,			/* reg_3028_reserved             REG=0x3028 */
+	 0xdf,			/* reg_3070_reserved             REG=0x3070 */
+	 0x20,			/* reg_3072_reserved             REG=0x3072 */
+	 0x73,			/* reg_3073_reserved             REG=0x301B */
+	 0x02,			/* offset                        REG=0x307E */
+	 0x06,			/* reg_30bd_reserved             REG=0x30BD */
+	 0x0b,			/* reg_30c2_reserved             REG=0x30C2 */
+	 0x81,			/* shade_clk_enable              REG=0x30AC */
+	 0xe6,			/* reg_3051_reserved             REG=0x3051 */
+	 0x02,			/* reg_3029_reserved             REG=0x3029 */
+	 0x00,			/* reg_30bf_reserved             REG=0x30BF */
+	 0x87,			/* reg_3022_reserved             REG=0x3022 */
+	 0x60,			/* reg_3019_reserved             REG=0x3019 */
+/* end: Add Samsung other MSR setting. */
+	 0x08,			/* reg_3152_reserved             REG=0x3152 */
+/* Add Samsung signal output setting. */
+	 0x50,			/* reg_3150_reserved             REG=0x3150 */
+/* Inverse PCLK = 0x50 */
+	 0x04,			/* reg_3157_reserved             REG=0x3157 */
+/* PCLK Delay offset; 0x0a will delay around 4ns at 80MHz */
+	 0x0f,			/* reg_3159_reserved             REG=0x3159 */
+/* HS, VS driving strength [3:2]=>VS, [1:0]=>HS 00:2mA, 01:4mA, 10:6mA,
+ * 11:8mA
+ */
+	 0xf0,			/* reg_315A_reserved             REG=0x315A */
+/* PCLK, DATA driving strength [7:6]=>data, [5:4]=>PCLK 00:2mA, 01:4mA, 10:6mA,
+ * 11:8mA
+ */
+/* AEC Setting */
+	 0x00,			/* analogue_gain_code_global_msb REG=0x0204 */
+	 REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB_VALUE,
+				/* analogue_gain_code_global_lsb REG=0x0205 */
+	 0x02,			/* fine_integration_time         REG=0x0200 */
+	 0x03,			/* coarse_integration_time       REG=0x0202 */
+/* Add LC Preview/Snapshot diff register. */
+/* Snapshot LC config Setting */
+	 0x52,			/* sh4ch_blk_width_r             REG=0x309E */
+	 0x7b,			/* sh4ch_blk_height_r            REG=0x309F */
+	 0x03,			/* sh4ch_step_x_r_MSB            REG=0x30A0 */
+	 0x1f,			/* sh4ch_step_x_r_LSB            REG=0x30A1 */
+	 0x02,			/* sh4ch_step_y_r_MSB            REG=0x30A2 */
+	 0x15,			/* sh4ch_step_y_r_LSB            REG=0x30A3 */
+	 0x00,			/* sh4ch_start_blk_cnt_x_r       REG=0x30A4 */
+	 0x00,			/* sh4ch_start_blk_int_x_r       REG=0x30A5 */
+	 0x00,			/* sh4ch_start_frac_x_r_MSB      REG=0x30A6 */
+	 0x00,			/* sh4ch_start_frac_x_r_LSB      REG=0x30A7 */
+	 0x00,			/* sh4ch_start_blk_cnt_y_r       REG=0x30A8 */
+	 0x00,			/* sh4ch_start_blk_int_y_r       REG=0x30A9 */
+	 0x00,			/* sh4ch_start_frac_y_r_MSB      REG=0x30AA */
+	 0x00,			/* sh4ch_start_frac_y_r_LSB      REG=0x30AB */
+/* diff: Add LC Preview/Snapshot diff register. */
+	 S5K3E2FX_FULL_SIZE_HEIGHT,
+	 14,
+	 S5K3E2FX_FULL_SIZE_WIDTH,
+	 124}
+};
+
+struct s5k3e2fx_work {
+	struct work_struct work;
+};
+static struct s5k3e2fx_work *s5k3e2fx_sensorw;
+static struct i2c_client *s5k3e2fx_client;
+
+struct s5k3e2fx_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+
+	int sensormode;
+	uint32_t fps_divider;	/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;	/* init to 1 * 0x00000400 */
+
+	uint16_t curr_lens_pos;
+	uint16_t init_curr_lens_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+
+	enum msm_s_resolution prev_res;
+	enum msm_s_resolution pict_res;
+	enum msm_s_resolution curr_res;
+	enum msm_s_test_mode set_test;
+};
+
+static struct s5k3e2fx_ctrl *s5k3e2fx_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(s5k3e2fx_wait_queue);
+
+#define MAX_I2C_RETRIES 20
+static int i2c_transfer_retry(struct i2c_adapter *adap,
+			struct i2c_msg *msgs,
+			int len)
+{
+	int i2c_retry = 0;
+	int ns; /* number sent */
+
+	while (i2c_retry++ < MAX_I2C_RETRIES) {
+		ns = i2c_transfer(adap, msgs, len);
+		if (ns == len)
+			break;
+		pr_err("%s: try %d/%d: i2c_transfer sent: %d, len %d\n",
+			__func__,
+			i2c_retry, MAX_I2C_RETRIES, ns, len);
+		msleep(10);
+	}
+
+	return ns == len ? 0 : -EIO;
+}
+
+static inline int s5k3e2fx_i2c_rxdata(unsigned short saddr, unsigned char *rxdata,
+			       int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = 2,
+			.buf = rxdata,
+		},
+		{
+			.addr = saddr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = rxdata,
+		},
+	};
+
+	return i2c_transfer_retry(s5k3e2fx_client->adapter, msgs, 2);
+}
+
+static inline int s5k3e2fx_i2c_txdata(unsigned short saddr,
+				   unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		},
+	};
+
+	return i2c_transfer_retry(s5k3e2fx_client->adapter, msg, 1);
+}
+
+static int s5k3e2fx_i2c_write_b(unsigned short saddr, unsigned short waddr,
+				    unsigned char bdata)
+{
+	int rc = -EFAULT;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+
+	rc = s5k3e2fx_i2c_txdata(saddr, buf, 3);
+
+	if (rc < 0)
+		pr_err("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+		       waddr, bdata);
+
+	return rc;
+}
+
+static int s5k3e2fx_i2c_write_table(struct s5k3e2fx_i2c_reg_conf
+					*reg_cfg_tbl, int num)
+{
+	int i;
+	int rc = -EFAULT;
+	CDBG("s5k3e2fx_i2c_write_table starts\n");
+	for (i = 0; i < num; i++) {
+		CDBG("%d: waddr = 0x%x, bdata = 0x%x\n", i,
+		     (int)reg_cfg_tbl->waddr, (int)reg_cfg_tbl->bdata);
+		rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+					  reg_cfg_tbl->waddr,
+					  reg_cfg_tbl->bdata);
+		if (rc < 0)
+			break;
+		reg_cfg_tbl++;
+	}
+
+	CDBG("s5k3e2fx_i2c_write_table ends\n");
+	return rc;
+}
+
+static int s5k3e2fx_i2c_read_w(unsigned short saddr, unsigned short raddr,
+				   unsigned short *rdata)
+{
+	int rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = s5k3e2fx_i2c_rxdata(saddr, buf, 2);
+	if (rc < 0)
+		return rc;
+
+	*rdata = buf[0] << 8 | buf[1];
+
+	if (rc < 0)
+		pr_err("s5k3e2fx_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int s5k3e2fx_i2c_read_b(unsigned short saddr, unsigned short raddr,
+				   unsigned short *rdata)
+{
+	int rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = s5k3e2fx_i2c_rxdata(saddr, buf, 1);
+	if (rc < 0)
+		return rc;
+
+	*rdata = buf[0];
+
+	if (rc < 0)
+		pr_err("s5k3e2fx_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int s5k3e2fx_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int rc;
+	uint16_t chipid = 0;
+	uint16_t modulever = 0;
+
+	CDBG("s5k3e2fx: gpio_request: %d\n", data->sensor_reset);
+	rc = gpio_request(data->sensor_reset, "s5k3e2fx");
+	if (!rc)
+		gpio_direction_output(data->sensor_reset, 1);
+	else {
+		pr_err("s5k3e2fx: request GPIO(sensor_reset): %d failed\n",
+			data->sensor_reset);
+		goto init_probe_fail;
+	}
+	CDBG("s5k3e2fx: gpio_free: %d\n", data->sensor_reset);
+
+	gpio_free(data->sensor_reset);
+
+	msleep(20);
+
+	CDBG("s5k3e2fx_sensor_init(): reseting sensor.\n");
+
+	rc = s5k3e2fx_i2c_read_w(s5k3e2fx_client->addr, S5K3E2FX_REG_MODEL_ID,
+				 &chipid);
+	if (rc < 0) {
+		pr_err("s5k3e2fx: read model_id failed: %d\n", rc);
+		goto init_probe_fail;
+	}
+	CDBG("s5k3e2fx_sensor_init(): model_id=0x%X\n", chipid);
+
+	if (chipid != S5K3E2FX_MODEL_ID) {
+		pr_err("S5K3E2FX wrong model_id = 0x%x\n", chipid);
+		rc = -ENODEV;
+		goto init_probe_fail;
+	}
+
+	rc = s5k3e2fx_i2c_read_b(s5k3e2fx_client->addr,
+				 S5K3E2FX_REG_MODULE_VER, &modulever);
+	if (rc < 0) {
+		pr_err("S5K3E2FX read module version failed, line=%d\n",
+		       __LINE__);
+		goto init_probe_fail;
+	}
+	/* modulever = (0xF000 & modulever) >> 8; */
+	modulever = 0x00F0 & modulever;
+	CDBG("s5k3e2fx_sensor_init(): module version=0x%X\n", modulever);
+
+	if (modulever == 0x40)
+		g_usModuleVersion = 0;
+	else if (modulever == 0x50)
+		g_usModuleVersion = 1;
+	goto init_probe_done;
+
+init_probe_fail:
+	pr_err("s5k3e2fx: prob init sensor failed\n");
+init_probe_done:
+	return rc;
+}
+
+static int s5k3e2fx_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&s5k3e2fx_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id s5k3e2fx_i2c_id[] = {
+	{"s5k3e2fx", 0},
+	{}
+};
+
+static int s5k3e2fx_i2c_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("s5k3e2fx_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	s5k3e2fx_sensorw = kzalloc(sizeof(struct s5k3e2fx_work), GFP_KERNEL);
+	if (!s5k3e2fx_sensorw) {
+		pr_err("kzalloc failed\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, s5k3e2fx_sensorw);
+	s5k3e2fx_init_client(client);
+	s5k3e2fx_client = client;
+
+	msleep(50);
+
+	CDBG("s5k3e2fx_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	pr_err("s5k3e2fx_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static struct i2c_driver s5k3e2fx_i2c_driver = {
+	.id_table = s5k3e2fx_i2c_id,
+	.probe = s5k3e2fx_i2c_probe,
+	.driver = {
+		.name = "s5k3e2fx",
+	},
+};
+
+#if 0
+static int s5k3e2fx_test(enum msm_s_test_mode mo)
+{
+	int rc = 0;
+
+	if (mo == S_TEST_OFF)
+		rc = 0;
+	else
+		rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+					  REG_TEST_PATTERN_MODE, (uint16_t) mo);
+
+	return rc;
+}
+#endif
+static int s5k3e2fx_setting(enum msm_s_reg_update rupdate,
+				enum msm_s_setting rt)
+{
+	int rc = 0;
+	uint16_t num_lperf;
+
+	switch (rupdate) {
+	case S_UPDATE_PERIODIC:{
+			if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) {
+				struct s5k3e2fx_i2c_reg_conf tbl_1[] = {
+					{REG_X_OUTPUT_SIZE_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 x_output_size_msb},
+					{REG_X_OUTPUT_SIZE_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 x_output_size_lsb},
+					{REG_Y_OUTPUT_SIZE_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 y_output_size_msb},
+					{REG_Y_OUTPUT_SIZE_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 y_output_size_lsb},
+					/* Start-End address */
+					{REG_X_ADDR_START_MSB,
+					 s5k3e2fx_reg_pat[rt].x_addr_start_MSB},
+					{REG_X_ADDR_START_LSB,
+					 s5k3e2fx_reg_pat[rt].x_addr_start_LSB},
+					{REG_Y_ADDR_START_MSB,
+					 s5k3e2fx_reg_pat[rt].y_addr_start_MSB},
+					{REG_Y_ADDR_START_LSB,
+					 s5k3e2fx_reg_pat[rt].y_addr_start_LSB},
+					{REG_X_ADDR_END_MSB,
+					 s5k3e2fx_reg_pat[rt].x_addr_end_MSB},
+					{REG_X_ADDR_END_LSB,
+					 s5k3e2fx_reg_pat[rt].x_addr_end_LSB},
+					{REG_Y_ADDR_END_MSB,
+					 s5k3e2fx_reg_pat[rt].y_addr_end_MSB},
+					{REG_Y_ADDR_END_LSB,
+					 s5k3e2fx_reg_pat[rt].y_addr_end_LSB},
+					/* Binning */
+					{REG_X_EVEN_INC,
+					 s5k3e2fx_reg_pat[rt].x_even_inc},
+					{REG_X_ODD_INC,
+					 s5k3e2fx_reg_pat[rt].x_odd_inc},
+					{REG_Y_EVEN_INC,
+					 s5k3e2fx_reg_pat[rt].y_even_inc},
+					{REG_Y_ODD_INC,
+					 s5k3e2fx_reg_pat[rt].y_odd_inc},
+					{REG_BINNING_ENABLE,
+					 s5k3e2fx_reg_pat[rt].binning_enable},
+				};
+				struct s5k3e2fx_i2c_reg_conf tbl_2[] = {
+					{REG_FRAME_LENGTH_LINES_MSB, 0},
+					{REG_FRAME_LENGTH_LINES_LSB, 0},
+					{REG_LINE_LENGTH_PCK_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 line_length_pck_msb},
+					{REG_LINE_LENGTH_PCK_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 line_length_pck_lsb},
+					{REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 analogue_gain_code_global_msb},
+					{REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 analogue_gain_code_global_lsb},
+					{REG_FINE_INTEGRATION_TIME,
+					 s5k3e2fx_reg_pat[rt].
+					 fine_integration_time},
+					{REG_COARSE_INTEGRATION_TIME,
+					 s5k3e2fx_reg_pat[rt].
+					 coarse_integration_time},
+					/* LC Preview/Snapshot difference
+					 * register
+					 */
+					{REG_SH4CH_BLK_WIDTH_R,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_blk_width_r},
+					{REG_SH4CH_BLK_HEIGHT_R,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_blk_height_r},
+					{REG_SH4CH_STEP_X_R_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_step_x_r_MSB},
+					{REG_SH4CH_STEP_X_R_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_step_x_r_LSB},
+					{REG_SH4CH_STEP_Y_R_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_step_y_r_MSB},
+					{REG_SH4CH_STEP_Y_R_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_step_y_r_LSB},
+					{REG_SH4CH_START_BLK_CNT_X_R,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_start_blk_cnt_x_r},
+					{REG_SH4CH_START_BLK_INT_X_R,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_start_blk_int_x_r},
+					{REG_SH4CH_START_FRAC_X_R_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_start_frac_x_r_MSB},
+					{REG_SH4CH_START_FRAC_X_R_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_start_frac_x_r_LSB},
+					{REG_SH4CH_START_BLK_CNT_Y_R,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_start_blk_cnt_y_r},
+					{REG_SH4CH_START_BLK_INT_Y_R,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_start_blk_int_y_r},
+					{REG_SH4CH_START_FRAC_Y_R_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_start_frac_y_r_MSB},
+					{REG_SH4CH_START_FRAC_Y_R_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 sh4ch_start_frac_y_r_LSB},
+				};
+
+/* add EVT5 sensor Samsung difference MSR setting between Preview and Capture */
+
+				struct s5k3e2fx_i2c_reg_conf
+				    tbl_only_for_EVT5[2][2] = {
+					{	/* S_RES_PREVIEW */
+					 {0x3062, 0x00},
+					 {0x3063, 0xD6},
+					 },
+					{	/* S_RES_CAPTURE */
+					 {0x3062, 0x01},
+					 {0x3063, 0x16},
+					 }
+				};
+
+				/* Most registers are directly applied at next frame after
+				   writing except shutter and analog gain. Shutter and gain are
+				   applied at 2nd or 1st frame later depending on register
+				   writing time. When the camera is switched from preview to
+				   snapshot, the first frame may have wrong shutter/gain and
+				   should be discarded. The register REG_MASK_CORRUPTED_FRAMES
+				   can discard the frame that has wrong shutter/gain. But in
+				   preview mode, the frames should not be dropped. Otherwise
+				   the preview will not be smooth. */
+				if (rt == S_RES_PREVIEW) {
+					/* Frames will be not discarded after exposure and gain are
+					   written. */
+					s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+						REG_MASK_CORRUPTED_FRAMES, NO_MASK);
+				} else {
+					/* Solve greenish in lowlight. Prevent corrupted frame */
+					s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+						REG_MASK_CORRUPTED_FRAMES, MASK);
+				}
+
+/* solve greenish: hold for both */
+				rc = s5k3e2fx_i2c_write_b(
+					s5k3e2fx_client->addr,
+					REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD);
+				if (rc < 0)
+					return rc;
+
+				CDBG("Binning_enable = 0x %2x"
+				     "[s5k3e2fx.c s5k3e2fx_setting]\r\n",
+				     s5k3e2fx_reg_pat[rt].binning_enable);
+
+				rc = s5k3e2fx_i2c_write_table(&tbl_1[0],
+							ARRAY_SIZE
+							(tbl_1));
+				if (rc < 0) {
+					pr_err("UPDATE_PERIODIC, tb1_1 failed");
+					return rc;
+				}
+
+				num_lperf =
+				    (uint16_t) ((s5k3e2fx_reg_pat[rt].
+						 frame_length_lines_msb
+						 << 8) & 0xFF00) +
+				    s5k3e2fx_reg_pat[rt].
+				    frame_length_lines_lsb;
+
+				num_lperf =
+				    num_lperf *
+				    s5k3e2fx_ctrl->fps_divider / 0x0400;
+
+				tbl_2[0] =
+				    (struct s5k3e2fx_i2c_reg_conf) {
+					REG_FRAME_LENGTH_LINES_MSB,
+					    (num_lperf & 0xFF00) >> 8};
+				tbl_2[1] =
+				    (struct s5k3e2fx_i2c_reg_conf) {
+					REG_FRAME_LENGTH_LINES_LSB,
+					    (num_lperf & 0x00FF)};
+
+				rc = s5k3e2fx_i2c_write_table(&tbl_2[0],
+							ARRAY_SIZE
+							(tbl_2));
+				if (rc < 0) {
+					pr_err("UPDATE_PERIODIC, tb1_2 failed");
+					return rc;
+				}
+
+				/* only for evt5 */
+				if (g_usModuleVersion == 1) {
+					rc = s5k3e2fx_i2c_write_table
+					    (&tbl_only_for_EVT5[rt][0],
+					     2);
+					if (rc < 0)
+						return rc;
+				}
+
+				/* solve greenish: only release for preview */
+				if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE)
+				{
+					rc = s5k3e2fx_i2c_write_b(
+						s5k3e2fx_client->addr,
+						REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_UPDATE);
+					if (rc < 0)
+						return rc;
+				}
+
+				rc = s5k3e2fx_i2c_write_b
+					(s5k3e2fx_client->addr,
+					S5K3E2FX_REG_MODE_SELECT,
+					S5K3E2FX_MODE_SELECT_STREAM);
+				if (rc < 0)
+					return rc;
+			}
+		break; /* UPDATE_PERIODIC */
+		}
+	case S_REG_INIT:{
+			if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) {
+				struct s5k3e2fx_i2c_reg_conf tbl_3[] = {
+/* {S5K3E2FX_REG_SOFTWARE_RESET, S5K3E2FX_SOFTWARE_RESET},*/
+					{S5K3E2FX_REG_MODE_SELECT,
+					 S5K3E2FX_MODE_SELECT_SW_STANDBY},
+					/*Output Size */
+					{REG_X_OUTPUT_SIZE_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 x_output_size_msb},
+					{REG_X_OUTPUT_SIZE_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 x_output_size_lsb},
+					{REG_Y_OUTPUT_SIZE_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 y_output_size_msb},
+					{REG_Y_OUTPUT_SIZE_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 y_output_size_lsb},
+					/* Start-End address */
+					{REG_X_ADDR_START_MSB,
+					 s5k3e2fx_reg_pat[rt].x_addr_start_MSB},
+					{REG_X_ADDR_START_LSB,
+					 s5k3e2fx_reg_pat[rt].x_addr_start_LSB},
+					{REG_Y_ADDR_START_MSB,
+					 s5k3e2fx_reg_pat[rt].y_addr_start_MSB},
+					{REG_Y_ADDR_START_LSB,
+					 s5k3e2fx_reg_pat[rt].y_addr_start_LSB},
+					{REG_X_ADDR_END_MSB,
+					 s5k3e2fx_reg_pat[rt].x_addr_end_MSB},
+					{REG_X_ADDR_END_LSB,
+					 s5k3e2fx_reg_pat[rt].x_addr_end_LSB},
+					{REG_Y_ADDR_END_MSB,
+					 s5k3e2fx_reg_pat[rt].y_addr_end_MSB},
+					{REG_Y_ADDR_END_LSB,
+					 s5k3e2fx_reg_pat[rt].y_addr_end_LSB},
+					/* Binning */
+					{REG_X_EVEN_INC,
+					 s5k3e2fx_reg_pat[rt].x_even_inc},
+					{REG_X_ODD_INC,
+					 s5k3e2fx_reg_pat[rt].x_odd_inc},
+					{REG_Y_EVEN_INC,
+					 s5k3e2fx_reg_pat[rt].y_even_inc},
+					{REG_Y_ODD_INC,
+					 s5k3e2fx_reg_pat[rt].y_odd_inc},
+					{REG_BINNING_ENABLE,
+					 s5k3e2fx_reg_pat[rt].binning_enable},
+					/* Frame format */
+					{REG_FRAME_LENGTH_LINES_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 frame_length_lines_msb},
+					{REG_FRAME_LENGTH_LINES_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 frame_length_lines_lsb},
+					{REG_LINE_LENGTH_PCK_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 line_length_pck_msb},
+					{REG_LINE_LENGTH_PCK_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 line_length_pck_lsb},
+					/* MSR setting */
+					{REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB,
+					 s5k3e2fx_reg_pat[rt].
+					 analogue_gain_code_global_msb},
+					{REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB,
+					 s5k3e2fx_reg_pat[rt].
+					 analogue_gain_code_global_lsb},
+					{REG_FINE_INTEGRATION_TIME,
+					 s5k3e2fx_reg_pat[rt].
+					 fine_integration_time},
+					{REG_COARSE_INTEGRATION_TIME,
+					 s5k3e2fx_reg_pat[rt].
+					 coarse_integration_time},
+					{S5K3E2FX_REG_MODE_SELECT,
+					 S5K3E2FX_MODE_SELECT_STREAM},
+				};
+				unsigned short rData = 0;
+				mdelay(1);
+				s5k3e2fx_i2c_read_b(s5k3e2fx_client->
+						    addr,
+						    REG_3150_RESERVED,
+						    &rData);
+				s5k3e2fx_i2c_write_b(s5k3e2fx_client->
+						     addr,
+						     REG_3150_RESERVED,
+						     (rData & 0xFFFE));
+				mdelay(1);
+				s5k3e2fx_i2c_read_b(s5k3e2fx_client->
+						    addr,
+						    REG_TYPE1_AF_ENABLE,
+						    &rData);
+				s5k3e2fx_i2c_write_b(s5k3e2fx_client->
+						addr,
+						REG_TYPE1_AF_ENABLE,
+						(rData | 0x0001));
+				mdelay(1);
+
+				/* reset fps_divider */
+				s5k3e2fx_ctrl->fps_divider = 1 * 0x0400;
+				/* write REG_INIT registers */
+				rc = s5k3e2fx_i2c_write_table(&tbl_3[0],
+							ARRAY_SIZE
+							(tbl_3));
+				if (rc < 0) {
+					pr_err("REG_INIT failed, rc=%d\n", rc);
+					return rc;
+				}
+			}
+		}
+		break; /* REG_INIT */
+
+	default:
+		rc = -EFAULT;
+		break;
+	} /* switch (rupdate) */
+
+	return rc;
+}
+
+static int s5k3e2fx_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int rc;
+
+	CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
+	s5k3e2fx_ctrl = kzalloc(sizeof(struct s5k3e2fx_ctrl), GFP_KERNEL);
+	if (!s5k3e2fx_ctrl) {
+		pr_err("s5k3e2fx_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	s5k3e2fx_ctrl->fps_divider = 1 * 0x00000400;
+	s5k3e2fx_ctrl->pict_fps_divider = 1 * 0x00000400;
+	s5k3e2fx_ctrl->set_test = S_TEST_OFF;
+	s5k3e2fx_ctrl->prev_res = S_QTR_SIZE;
+	s5k3e2fx_ctrl->pict_res = S_FULL_SIZE;
+
+	if (data)
+		s5k3e2fx_ctrl->sensordata = data;
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(S5K3E2FX_DEF_MCLK);
+
+	msleep(20);
+
+	msm_camio_camif_pad_reg_reset();
+	msleep(20);
+
+	rc = s5k3e2fx_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail1;
+
+	if (s5k3e2fx_ctrl->prev_res == S_QTR_SIZE)
+		rc = s5k3e2fx_setting(S_REG_INIT, S_RES_PREVIEW);
+	else
+		rc = s5k3e2fx_setting(S_REG_INIT, S_RES_CAPTURE);
+
+	if (rc < 0) {
+		pr_err("s5k3e2fx_setting failed. rc = %d\n", rc);
+		goto init_fail1;
+	}
+
+	rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+				0x3130, 0x03);
+	if (rc < 0)
+		goto init_fail1;
+
+	goto init_done;
+
+init_fail1:
+	kfree(s5k3e2fx_ctrl);
+init_done:
+	return rc;
+}
+
+static void s5k3e2fx_suspend_sensor(void)
+{
+	unsigned short rData = 0;
+	 /*AF*/
+	s5k3e2fx_i2c_read_b(s5k3e2fx_client->addr,
+			REG_TYPE1_AF_ENABLE, &rData);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			REG_TYPE1_AF_ENABLE, (rData & 0xFFFE));
+	mdelay(1);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			S5K3E2FX_REG_MODE_SELECT,
+			S5K3E2FX_MODE_SELECT_SW_STANDBY);
+	msleep(210);		/*for 5FPS */
+	/* hi z */
+	s5k3e2fx_i2c_read_b(s5k3e2fx_client->addr, REG_3150_RESERVED, &rData);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			REG_3150_RESERVED, (rData | 0x0001));
+	mdelay(1);
+
+}
+
+static int s5k3e2fx_power_down(void)
+{
+	int rc = -EBADF;
+	s5k3e2fx_suspend_sensor();
+	return rc;
+}
+
+static int s5k3e2fx_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	s5k3e2fx_suspend_sensor();
+
+	kfree(s5k3e2fx_ctrl);
+	s5k3e2fx_ctrl = NULL;
+
+	allow_suspend();
+
+	CDBG("s5k3e2fx_release completed\n");
+
+	return rc;
+}
+
+static int s5k3e2fx_probe_init_lens_correction(
+		const struct msm_camera_sensor_info *data)
+{
+	int rc = 0;
+
+	/* LC setting */
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			     S5K3E2FX_REG_SOFTWARE_RESET,
+			     S5K3E2FX_SOFTWARE_RESET);
+	mdelay(2);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			     S5K3E2FX_REG_MODE_SELECT,
+			     S5K3E2FX_MODE_SELECT_SW_STANDBY);
+	/*20090811  separates the EVT4/EVT5 sensor init and LC setting start */
+	s5k3e2fx_i2c_write_table(&Init_setting[g_usModuleVersion][0],
+				 NUM_INIT_REG);
+
+	/* 090911  Add for Samsung VCM calibration current Start */
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3112, 0x0A);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3112, 0x09);
+	mdelay(5);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3145, 0x04);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3146, 0x80);
+	/* 090911 Add for Samsung VCM calibration current End */
+
+	s5k3e2fx_i2c_write_table(&lc_setting[g_usModuleVersion][0], NUM_LC_REG);
+
+	/*20090811  separates the EVT4/EVT5 sensor init and LC setting end */
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			     S5K3E2FX_REG_MODE_SELECT,
+			     S5K3E2FX_MODE_SELECT_STREAM);
+	msleep(10);
+	s5k3e2fx_suspend_sensor();
+
+	return rc;
+}
+
+static void s5k3e2fx_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider;	/* Q10 */
+
+	divider = (uint32_t)
+	    ((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+	      s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) *
+	     (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
+	      s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p)) * 0x00000400 /
+	    ((s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
+	      s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l) *
+	     (s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
+	      s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p));
+
+	/* Verify PCLK settings and frame sizes. */
+	*pfps = (uint16_t) (fps * divider / 0x00000400);
+}
+
+static uint16_t s5k3e2fx_get_prev_lines_pf(void)
+{
+	return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+		s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l;
+}
+
+static uint16_t s5k3e2fx_get_prev_pixels_pl(void)
+{
+	return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
+		s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p;
+}
+
+static uint16_t s5k3e2fx_get_pict_lines_pf(void)
+{
+	return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
+		s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
+}
+
+static uint16_t s5k3e2fx_get_pict_pixels_pl(void)
+{
+	return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
+		s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
+}
+
+static uint32_t s5k3e2fx_get_pict_max_exp_lc(void)
+{
+	uint32_t snapshot_lines_per_frame;
+
+	if (s5k3e2fx_ctrl->pict_res == S_QTR_SIZE)
+		snapshot_lines_per_frame =
+		    s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+		    s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l;
+	else
+		snapshot_lines_per_frame = 3961 * 3;
+
+	return snapshot_lines_per_frame;
+}
+
+static int s5k3e2fx_set_fps(struct fps_cfg *fps)
+{
+	/* input is new fps in Q10 format */
+	int rc = 0;
+
+	s5k3e2fx_ctrl->fps_divider = fps->fps_div;
+
+	CDBG("s5k3e2fx_ctrl->fps_divider = %d\n",
+		s5k3e2fx_ctrl->fps_divider);
+
+	rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+				  REG_FRAME_LENGTH_LINES_MSB,
+				  (((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+				     s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) *
+				    s5k3e2fx_ctrl->fps_divider /
+				    0x400) & 0xFF00) >> 8);
+	if (rc < 0)
+		goto set_fps_done;
+
+	rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+				  REG_FRAME_LENGTH_LINES_LSB,
+				  (((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+				     s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) *
+				    s5k3e2fx_ctrl->fps_divider /
+				    0x400) & 0xFF00));
+
+set_fps_done:
+	return rc;
+}
+
+static int s5k3e2fx_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	int rc = 0;
+
+	uint16_t max_legal_gain = 0x0200;
+	uint32_t ll_ratio;	/* Q10 */
+	uint32_t ll_pck, fl_lines;
+	uint16_t offset = 4;
+	uint32_t gain_msb, gain_lsb;
+	uint32_t intg_t_msb, intg_t_lsb;
+	uint32_t ll_pck_msb, ll_pck_lsb;
+
+	struct s5k3e2fx_i2c_reg_conf tbl[2];
+
+	CDBG("Line:%d s5k3e2fx_write_exp_gain gain %d line %d\n",
+		__LINE__, gain, line);
+
+	if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+
+		s5k3e2fx_ctrl->my_reg_gain = gain;
+		s5k3e2fx_ctrl->my_reg_line_count = (uint16_t) line;
+
+		fl_lines = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+		    s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l;
+
+		ll_pck = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
+		    s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p;
+
+	} else {
+
+		fl_lines = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
+		    s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
+
+		ll_pck = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
+		    s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
+	}
+
+	if (gain > max_legal_gain)
+		gain = max_legal_gain;
+
+	/* in Q10 */
+	line = (line * s5k3e2fx_ctrl->fps_divider);
+
+	if (fl_lines < (line / 0x400))
+		ll_ratio = (line / (fl_lines - offset));
+	else
+		ll_ratio = 0x400;
+
+/* solve greenish: only release for preview */
+	if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+					  REG_GROUPED_PARAMETER_HOLD,
+					  GROUPED_PARAMETER_HOLD);
+		if (rc < 0) {
+			pr_err("s5k3e2fx_i2c_write_b failed on line %d\n",
+				__LINE__);
+			return rc;
+		}
+	}
+
+	/* update gain registers */
+	gain_msb = (gain & 0xFF00) >> 8;
+	gain_lsb = gain & 0x00FF;
+	tbl[0].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB;
+	tbl[0].bdata = gain_msb;
+	tbl[1].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB;
+	tbl[1].bdata = gain_lsb;
+	rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
+	if (rc < 0)
+		goto write_gain_done;
+#if 1 /* Solve EVT5 greenish in lowlight*/
+	ll_pck = ll_pck * ll_ratio;
+	ll_pck_msb = ((ll_pck / 0x400) & 0xFF00) >> 8;
+	ll_pck_lsb = (ll_pck / 0x400) & 0x00FF;
+	tbl[0].waddr = REG_LINE_LENGTH_PCK_MSB;
+	tbl[0].bdata = ll_pck_msb;
+	tbl[1].waddr = REG_LINE_LENGTH_PCK_LSB;
+	tbl[1].bdata = ll_pck_lsb;
+
+	rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
+	if (rc < 0)
+		goto write_gain_done;
+#else
+	if (line / 0x400 + offset > fl_lines)
+		ll_pck = line / 0x400 + offset;
+	else
+		ll_pck = fl_lines;
+
+	ll_pck_msb = ((ll_pck) & 0xFF00) >> 8;
+	ll_pck_lsb = (ll_pck) & 0x00FF;
+	tbl[0].waddr = REG_FRAME_LENGTH_LINES_MSB;
+	tbl[0].bdata = ll_pck_msb;
+	tbl[1].waddr = REG_FRAME_LENGTH_LINES_LSB;
+	tbl[1].bdata = ll_pck_lsb;
+
+	rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
+	if (rc < 0)
+		goto write_gain_done;
+#endif
+
+	line = line / 0x400;
+	intg_t_msb = (line & 0xFF00) >> 8;
+	intg_t_lsb = (line & 0x00FF);
+	tbl[0].waddr = REG_COARSE_INTEGRATION_TIME;
+	tbl[0].bdata = intg_t_msb;
+	tbl[1].waddr = REG_COARSE_INTEGRATION_TIME_LSB;
+	tbl[1].bdata = intg_t_lsb;
+	rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
+
+/* solve greenish: release for both */
+		rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+					  REG_GROUPED_PARAMETER_HOLD,
+					  GROUPED_PARAMETER_UPDATE);
+		if (rc < 0) {
+			pr_err("s5k3e2fx_i2c_write_b failed on line %d\n",
+				__LINE__);
+			return rc;
+		}
+
+write_gain_done:
+	return rc;
+}
+
+static int s5k3e2fx_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	pr_info("s5k3e2fx_set_pict_exp_gain gain %d line %d\n",
+		gain, line);
+
+	return s5k3e2fx_write_exp_gain(gain, line);
+}
+
+static int s5k3e2fx_video_config(int mode, int res)
+{
+	int rc;
+
+	switch (res) {
+	case S_QTR_SIZE:
+		pr_info("start sensor S_RES_PREVIEW config: %d\n", __LINE__);
+		rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_PREVIEW);
+		if (rc < 0)
+			return rc;
+		/* only apply my_reg for returning preview*/
+		rc = s5k3e2fx_write_exp_gain(s5k3e2fx_ctrl->my_reg_gain,
+				     s5k3e2fx_ctrl->my_reg_line_count);
+		break;
+
+	case S_FULL_SIZE:
+		rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE);
+		if (rc < 0)
+			return rc;
+		break;
+
+	default:
+		return 0;
+	}
+
+	s5k3e2fx_ctrl->prev_res = res;
+	s5k3e2fx_ctrl->curr_res = res;
+	s5k3e2fx_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int s5k3e2fx_set_default_focus(void)
+{
+	int rc = 0;
+
+	rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3131, 0);
+	if (rc < 0)
+		return rc;
+
+	rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3132, 0);
+	if (rc < 0)
+		return rc;
+
+	s5k3e2fx_ctrl->curr_lens_pos = 0;
+
+	return rc;
+}
+
+static int s5k3e2fx_move_focus(int direction, int num_steps)
+{
+	int rc = 0;
+	int i;
+	int16_t step_direction;
+	int16_t actual_step;
+	int16_t next_pos, pos_offset;
+	int16_t init_code = 0;
+	uint8_t next_pos_msb, next_pos_lsb;
+	int16_t s_move[5];
+	uint32_t gain;		/* Q10 format */
+
+	if (direction == MOVE_NEAR)
+		step_direction = 20;
+	else if (direction == MOVE_FAR)
+		step_direction = -20;
+	else {
+		pr_err("s5k3e2fx_move_focus failed at line %d ...\n", __LINE__);
+		return -EINVAL;
+	}
+
+	actual_step = step_direction * (int16_t) num_steps;
+	pos_offset = init_code + s5k3e2fx_ctrl->curr_lens_pos;
+	gain = actual_step * 0x400 / 5;
+
+	for (i = 0; i <= 4; i++) {
+		if (actual_step >= 0)
+			s_move[i] =
+			    ((((i + 1) * gain + 0x200) -
+			      (i * gain + 0x200)) / 0x400);
+		else
+			s_move[i] =
+			    ((((i + 1) * gain - 0x200) -
+			      (i * gain - 0x200)) / 0x400);
+	}
+
+	/* Ring Damping Code */
+	for (i = 0; i <= 4; i++) {
+		next_pos = (int16_t) (pos_offset + s_move[i]);
+
+		if (next_pos > (738 + init_code))
+			next_pos = 738 + init_code;
+		else if (next_pos < 0)
+			next_pos = 0;
+
+		CDBG("next_position in damping mode = %d\n", next_pos);
+		/* Writing the Values to the actuator */
+		if (next_pos == init_code)
+			next_pos = 0x00;
+
+		next_pos_msb = next_pos >> 8;
+		next_pos_lsb = next_pos & 0x00FF;
+
+		rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3131,
+					  next_pos_msb);
+		if (rc < 0)
+			break;
+
+		rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3132,
+					  next_pos_lsb);
+		if (rc < 0)
+			break;
+
+		pos_offset = next_pos;
+		s5k3e2fx_ctrl->curr_lens_pos = pos_offset - init_code;
+		if (num_steps > 1)
+			mdelay(6);
+		else
+			mdelay(4);
+	}
+
+	return rc;
+}
+
+static int s5k3e2fx_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long rc = 0;
+
+	if (copy_from_user(&cdata,
+			   (void *)argp, sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		s5k3e2fx_get_pict_fps(cdata.cfg.gfps.prevfps,
+				      &(cdata.cfg.gfps.pictfps));
+
+		if (copy_to_user((void *)argp, &cdata,
+				 sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf = s5k3e2fx_get_prev_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl = s5k3e2fx_get_prev_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf = s5k3e2fx_get_pict_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl = s5k3e2fx_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc = s5k3e2fx_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = s5k3e2fx_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc = s5k3e2fx_write_exp_gain(cdata.cfg.exp_gain.gain,
+					     cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_PICT_EXP_GAIN:
+		rc = s5k3e2fx_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+						cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_MODE:
+		rc = s5k3e2fx_video_config(cdata.mode, cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = s5k3e2fx_power_down();
+		break;
+
+	case CFG_MOVE_FOCUS:
+		rc = s5k3e2fx_move_focus(cdata.cfg.focus.dir,
+					 cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = s5k3e2fx_set_default_focus();
+		break;
+
+/*	case CFG_GET_AF_MAX_STEPS: */
+	case CFG_SET_EFFECT:
+		rc = s5k3e2fx_set_default_focus();
+		break;
+
+	case CFG_SET_LENS_SHADING:
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	prevent_suspend();
+	return rc;
+}
+
+static int s5k3e2fx_sensor_probe(const struct msm_camera_sensor_info *info,
+				 struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	pr_info("%s\n", __func__);
+
+	rc = i2c_add_driver(&s5k3e2fx_i2c_driver);
+	if (rc < 0 || s5k3e2fx_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_fail;
+	}
+
+	msm_camio_clk_rate_set(S5K3E2FX_DEF_MCLK);
+	msleep(20);
+
+	rc = s5k3e2fx_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+
+	/* lens correction */
+	s5k3e2fx_probe_init_lens_correction(info);
+	init_suspend();
+
+	s->s_init = s5k3e2fx_sensor_open_init;
+	s->s_release = s5k3e2fx_sensor_release;
+	s->s_config = s5k3e2fx_sensor_config;
+
+	return rc;
+
+probe_fail:
+	pr_err("SENSOR PROBE FAILS!\n");
+	return rc;
+}
+
+static int s5k3e2fx_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	int rc;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+
+	if (!sinfo->need_suspend)
+		return 0;
+
+	CDBG("s5k3e2fx: camera suspend\n");
+	rc = gpio_request(sinfo->sensor_reset, "s5k3e2fx");
+	if (!rc)
+		gpio_direction_output(sinfo->sensor_reset, 0);
+	else {
+		pr_err("s5k3e2fx: request GPIO(sensor_reset) :%d faile\n",
+			sinfo->sensor_reset);
+		goto suspend_fail;
+	}
+	CDBG("s5k3e2fx: gpio_free:%d line:%d\n", sinfo->sensor_reset,
+		__LINE__);
+	gpio_free(sinfo->sensor_reset);
+
+suspend_fail:
+	return rc;
+}
+static void s5k3e2fx_sensor_resume_setting(void)
+{
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			     S5K3E2FX_REG_SOFTWARE_RESET,
+			     S5K3E2FX_SOFTWARE_RESET);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0100, 0x00);
+	/*--------------PLL setting for 80Mhz*/
+	/* PLL setting */
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0305, 0x06);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0306, 0x00);
+	/*88 54.4Mhz */
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0307, 0x83);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0301, 0x08);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0303, 0x01);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0309, 0x08);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x030b, 0x01);
+	/*--------------output size*/
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x034c, 0x05);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x034d, 0x10);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x034e, 0x03);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x034f, 0xcc);
+	/*--------------frame format (min blanking)*/
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0340, 0x03);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0341, 0xe2);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0342, 0x0a);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0343, 0xac);
+	/*--------------Binning */
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0381, 0x01);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0383, 0x01);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0385, 0x01);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0387, 0x03);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3014, 0x06);
+	/*--------------MSR setting*/
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x30c4, 0x01);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3000, 0x03);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3001, 0x94);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3002, 0x02);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3003, 0x95);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3004, 0x0f);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3005, 0x05);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3006, 0x3c);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3007, 0x8c);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3008, 0x93);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3009, 0x05);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x300a, 0x3a);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x300c, 0x02);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x300d, 0x3e);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x300f, 0x0e);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3010, 0x46);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3011, 0x64);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3012, 0x1e);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x301d, 0x3f);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3024, 0x04);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3028, 0x40);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3070, 0xdf);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x301b, 0x73);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x307e, 0x02);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x30bd, 0x06);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x30c2, 0x0b);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x30ac, 0x81);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3151, 0xe6);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3029, 0x02);
+	/*--------------EVT4 setting*/
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x30bf, 0x00);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3022, 0x87);
+	/*tune ADC to got batter yield rate in EDS */
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3019, 0x60);
+	/*AF driving strength */
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3146, 0x3c);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3152, 0x08);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x315a, 0xaa);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3159, 0x0a);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0205, 0x80);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0202, 0x03);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0200, 0x02);
+}
+static int s5k3e2fx_resume(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+
+	if (!sinfo->need_suspend)
+		return 0;
+
+	CDBG("s5k3e2fx_resume\n");
+	/*init msm,clk ,GPIO,enable */
+	msm_camio_probe_on(pdev);
+	msm_camio_clk_enable(CAMIO_MDC_CLK);
+
+	CDBG("msm_camio_probe_on\n");
+	/*read sensor ID and pull down reset */
+	msm_camio_clk_rate_set(S5K3E2FX_DEF_MCLK);
+	CDBG("msm_camio_clk_rate_set\n");
+	msleep(20);
+	s5k3e2fx_probe_init_sensor(sinfo);
+	CDBG("s5k3e2fx_probe_init_sensor\n");
+	/*init sensor,streaming on, SW init streaming off */
+	s5k3e2fx_sensor_resume_setting();
+	/*lens sharding */
+	s5k3e2fx_probe_init_lens_correction(sinfo);
+	/*stream on */
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			     S5K3E2FX_REG_MODE_SELECT,
+			     S5K3E2FX_MODE_SELECT_STREAM);
+	/*software standby */
+	msleep(25);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3130, 0x00);
+	mdelay(1);
+	/*stream off */
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			     S5K3E2FX_REG_MODE_SELECT,
+			     S5K3E2FX_MODE_SELECT_SW_STANDBY);
+	mdelay(1);
+	s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3150, 0x51);
+	msleep(240);
+	/*set RST to low */
+	msm_camio_probe_off(pdev);
+	msm_camio_clk_disable(CAMIO_MDC_CLK);
+	CDBG("s5k3e2fx:resume done\n");
+	return rc;
+}
+
+static int __s5k3e2fx_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, s5k3e2fx_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __s5k3e2fx_probe,
+	.driver = {
+		.name = "msm_camera_s5k3e2fx",
+		.owner = THIS_MODULE,
+	},
+	.suspend = s5k3e2fx_suspend,
+	.resume = s5k3e2fx_resume,
+};
+
+static int __init s5k3e2fx_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(s5k3e2fx_init);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 9da0e50..e780a75 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -482,6 +482,14 @@
 	  host many different types of MODULbus daughterboards, including
 	  CAN and GPIO controllers.
 
+config PM8058
+	bool "Qualcomm PM8058 Power Management IC"
+	depends on MSM_SSBI && ARCH_MSM7X30
+	default y if MSM_SSBI && ARCH_MSM7X30
+	help
+	  Say yes here if your board is equipped with the Qualcomm
+	  PM8058 PMIC.
+
 endif # MFD_SUPPORT
 
 menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index fb503e7..6722d31 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -71,3 +71,4 @@
 obj-$(CONFIG_LPC_SCH)		+= lpc_sch.o
 obj-$(CONFIG_MFD_RDC321X)	+= rdc321x-southbridge.o
 obj-$(CONFIG_MFD_JANZ_CMODIO)	+= janz-cmodio.o
+obj-$(CONFIG_PM8058)		+= pm8058-core.o
diff --git a/drivers/mfd/pm8058-core.c b/drivers/mfd/pm8058-core.c
new file mode 100644
index 0000000..24410b5
--- /dev/null
+++ b/drivers/mfd/pm8058-core.c
@@ -0,0 +1,958 @@
+/*
+ * Copyright (c) 2010 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Author: Dima Zavin <dima@android.com>
+ *   - Based on a driver from Code Aurora Forum.
+ *
+ * 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/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/pm8058.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <asm-generic/gpio.h>
+
+#include <mach/msm_ssbi.h>
+
+enum {
+	DEBUG_IRQS = 1U << 0,
+};
+static int debug_mask = 0;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define REG_HWREV		0x0002  /* PMIC4 revision */
+
+#define REG_IRQ_PERM		0x01a6
+#define REG_IRQ_PERM_BLK_SEL	0x01ac
+#define REG_IRQ_ROOT		0x01bb
+#define REG_IRQ_M_STATUS1	0x01bc
+#define REG_IRQ_M_STATUS2	0x01bd
+#define REG_IRQ_M_STATUS3	0x01be
+#define REG_IRQ_M_STATUS4	0x01bf
+#define REG_IRQ_BLK_SEL		0x01c0
+#define REG_IRQ_IT_STATUS	0x01c1
+#define REG_IRQ_CONFIG		0x01c2
+#define REG_IRQ_RT_STATUS	0x01c3
+#define REG_GPIO_CTRL(x)	(0x0150 + (x))
+
+#define IRQ_CFG_CLR		(1 << 3)
+#define IRQ_CFG_MASK_RE		(1 << 2)
+#define IRQ_CFG_MASK_FE		(1 << 1)
+#define IRQ_CFG_LVL_SEL		(1 << 0)
+
+#define NUM_BLOCKS		32
+#define IRQS_PER_BLOCK		8
+#define NUM_PMIRQS		(NUM_BLOCKS * IRQS_PER_BLOCK)
+
+/* XXX: why are mpp's different than gpios? should we just put them into
+ * the gpio space? */
+#define MPP_IRQ_OFFSET		(16 * 8)
+#define GPIO_IRQ_OFFSET		(24 * 8)
+#define KEYPAD_IRQ_OFFSET	(9 * 8 + 2)
+#define CHARGER_IRQ_OFFSET	(1 * 8 + 7)
+
+/* this defines banks of irq space. We want to provide a compact irq space
+ * to the kernel, but there several ranges of irqs in an otherwise sparse
+ * map of available/accessible irqs on the pm8058. So,
+ *
+ * bank 0 - GPIO IRQs start=(24 * 8) cnt=40 (gpios 0-39)
+ * bank 1 - MPP IRQs start=(16 * 8) cnt=12 (mpps 0-11)
+ * bank 2 - keypad irqs start=(9*8 + 1) cnt=2
+ * bank 3 - charger irqs start=(1*8 + 7) cnt=7 (ends at 2*8 + 5)
+ *
+ */
+struct pm8058_irq_bank {
+	unsigned int	start; /* will be added to the chip irq_base */
+	unsigned int	cnt;
+	unsigned int	offset; /* offset into device's real irq map */
+};
+
+static struct pm8058_irq_bank pm8058_irq_banks[] = {
+	{
+		.start	= PM8058_FIRST_GPIO_IRQ,
+		.cnt	= PM8058_NUM_GPIO_IRQS,
+		.offset	= GPIO_IRQ_OFFSET,
+	},
+	{
+		.start	= PM8058_FIRST_MPP_IRQ,
+		.cnt	= PM8058_NUM_MPP_IRQS,
+		.offset	= MPP_IRQ_OFFSET,
+	},
+	{
+		.start	= PM8058_FIRST_KEYPAD_IRQ,
+		.cnt	= PM8058_NUM_KEYPAD_IRQS,
+		.offset	= KEYPAD_IRQ_OFFSET,
+	},
+	{
+		.start	= PM8058_FIRST_CHARGER_IRQ,
+		.cnt	= PM8058_NUM_CHARGER_IRQS,
+		.offset	= CHARGER_IRQ_OFFSET,
+	},
+};
+#define NUM_IRQ_BANKS		ARRAY_SIZE(pm8058_irq_banks)
+
+struct pm8058_irq_group {
+	u16	stat_reg;
+	u8	valid_mask;
+	u8	root_mask;
+	u8	block_offset;
+};
+
+static const struct pm8058_irq_group pm8058_irq_groups[] = {
+	{
+		.stat_reg	= REG_IRQ_M_STATUS1,
+		.valid_mask	= 0x6,
+		.root_mask	= 0x2,
+		.block_offset	= 0,
+	},
+	{
+		.stat_reg	= REG_IRQ_M_STATUS2,
+		.valid_mask	= 0x2,
+		.root_mask	= 0x4,
+		.block_offset	= 8,
+	},
+	{
+		.stat_reg	= REG_IRQ_M_STATUS4,
+		.valid_mask	= 0x1f,
+		.root_mask	= 0x10,
+		.block_offset	= 24,
+	},
+};
+#define NUM_ROOT_GROUPS		ARRAY_SIZE(pm8058_irq_groups)
+
+struct pm8058_irq_info {
+	u8	cfg;
+	u8	cfg_val;
+	u8	mask;
+	u8	blk;
+	u8	blk_bit;
+	u8	wake;
+};
+
+struct pm8058 {
+	struct device			*dev;
+	unsigned int			devirq;
+
+	spinlock_t			lock;
+
+	unsigned int			irq_base;
+	struct pm8058_irq_info		irqs[PM8058_NUM_IRQS];
+	unsigned int			pmirqs[NUM_PMIRQS];
+	int				wake_cnt;
+
+	struct gpio_chip		gpio_chip;
+	u8				gpio_flags[PM8058_NUM_GPIOS];
+
+	struct pm8058_platform_data	*pdata;
+
+	struct platform_device		*kp_pdev;
+	struct platform_device		*charger_pdev;
+};
+
+static struct pm8058 *the_pm8058;
+
+static int read_irq_block_reg(struct pm8058 *pmic, u8 blk, u16 reg, u8 *val);
+static int get_curr_irq_stat(struct pm8058 *pmic, unsigned int irq);
+
+int pm8058_readb(struct device *dev, u16 addr, u8 *val)
+{
+	struct pm8058 *pmic = dev_get_drvdata(dev);
+
+	return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
+}
+EXPORT_SYMBOL(pm8058_readb);
+
+int pm8058_writeb(struct device *dev, u16 addr, u8 val)
+{
+	struct pm8058 *pmic = dev_get_drvdata(dev);
+
+	return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
+}
+EXPORT_SYMBOL(pm8058_writeb);
+
+int pm8058_write_buf(struct device *dev, u16 addr, u8 *buf, int cnt)
+{
+	struct pm8058 *pmic = dev_get_drvdata(dev);
+
+	return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
+}
+EXPORT_SYMBOL(pm8058_write_buf);
+
+int pm8058_read_buf(struct device *dev, u16 addr, u8 *buf, int cnt)
+{
+	struct pm8058 *pmic = dev_get_drvdata(dev);
+
+	return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
+}
+EXPORT_SYMBOL(pm8058_read_buf);
+
+static int _dir_map[] = {
+	[0]				= 0x3,
+	[PM8058_GPIO_INPUT]		= 0x0,
+	[PM8058_GPIO_OUTPUT]		= 0x2,
+	[PM8058_GPIO_OUTPUT_HIGH]	= 0x2,
+};
+
+int pm8058_gpio_mux_cfg(struct device *dev, unsigned int gpio,
+			struct pm8058_pin_config *cfg)
+{
+	struct pm8058 *pmic = dev_get_drvdata(dev);
+	unsigned long flags;
+	int ret;
+	u8 bank[6];
+
+	gpio -= pmic->gpio_chip.base;
+
+	/* bit 7   - write
+	 * bit 6:4 - bank select */
+	bank[0] = ((1 << 7) | (0 << 4) | ((cfg->vin_src & 0x7) << 1) | 0x1);
+	bank[1] = ((1 << 7) | (1 << 4) | (_dir_map[cfg->dir] << 2) |
+		   ((cfg->flags & PM8058_GPIO_OPEN_DRAIN ? 0x1 : 0) << 1) |
+		   ((cfg->dir & PM8058_GPIO_OUTPUT_HIGH ? 0x1 : 0) << 0));
+	bank[2] = ((1 << 7) | (2 << 4) | ((cfg->pull_up & 0x7) << 1));
+	bank[3] = ((1 << 7) | (3 << 4) |
+		   ((cfg->strength & 0x3) << 2) |
+		   ((cfg->flags & PM8058_GPIO_HIGH_Z ? 0x1 : 0x0) << 0));
+	bank[4] = ((1 << 7) | (4 << 4) | ((cfg->func & 0x7) << 1));
+	bank[5] = ((1 << 7) | (5 << 4) |
+		   ((cfg->flags & PM8058_GPIO_INV_IRQ_POL ? 0 : 1) << 3));
+
+	spin_lock_irqsave(&pmic->lock, flags);
+
+	pmic->gpio_flags[gpio] = cfg->flags | PM8058_GPIO_CONFIGURED;
+	ret = pm8058_write_buf(pmic->dev, REG_GPIO_CTRL(gpio),
+			       bank, sizeof(bank));
+
+	spin_unlock_irqrestore(&pmic->lock, flags);
+
+	if (ret)
+		pr_err("%s: failed writing config for gpio %d (%d)\n", __func__,
+		       gpio, ret);
+	return ret;
+}
+EXPORT_SYMBOL(pm8058_gpio_mux_cfg);
+
+int pm8058_gpio_mux(unsigned int gpio, struct pm8058_pin_config *cfg)
+{
+	if (!the_pm8058)
+		return -ENODEV;
+	return pm8058_gpio_mux_cfg(the_pm8058->dev, gpio, cfg);
+}
+EXPORT_SYMBOL(pm8058_gpio_mux);
+
+/* gpio funcs */
+static int read_gpio_bank(struct pm8058 *pmic, unsigned gpio, u8 bank, u8 *val)
+{
+	int ret;
+
+	ret = pm8058_writeb(pmic->dev, REG_GPIO_CTRL(gpio), (bank & 0x7) << 4);
+	if (ret)
+		goto out;
+	ret = pm8058_readb(pmic->dev, REG_GPIO_CTRL(gpio), val);
+	if (ret)
+		goto out;
+out:
+	return ret;
+}
+
+static int pm8058_gpio_request(struct gpio_chip *chip, unsigned gpio)
+{
+	struct pm8058 *pmic = container_of(chip, struct pm8058, gpio_chip);
+	unsigned long flags;
+	int ret;
+	u8 bank1;
+	u8 bank3;
+	u8 bank5;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	if (pmic->gpio_flags[gpio] & PM8058_GPIO_CONFIGURED) {
+		ret = 0;
+		goto out;
+	}
+
+	ret = read_gpio_bank(pmic, gpio, 1, &bank1);
+	if (ret) {
+		pr_err("%s: can't read bank 1\n", __func__);
+		goto out;
+	}
+
+	ret = read_gpio_bank(pmic, gpio, 3, &bank3);
+	if (ret) {
+		pr_err("%s: can't read bank 3\n", __func__);
+		goto out;
+	}
+
+	ret = read_gpio_bank(pmic, gpio, 5, &bank5);
+	if (ret) {
+		pr_err("%s: can't read bank 5\n", __func__);
+		goto out;
+	}
+
+	pmic->gpio_flags[gpio] = bank1 & 0x2 ? PM8058_GPIO_OPEN_DRAIN : 0;
+	pmic->gpio_flags[gpio] |= bank3 & 0x1 ? PM8058_GPIO_HIGH_Z : 0;
+	pmic->gpio_flags[gpio] |= bank5 & 0x8 ? 0 : PM8058_GPIO_INV_IRQ_POL;
+	pmic->gpio_flags[gpio] |= PM8058_GPIO_CONFIGURED;
+
+out:
+	spin_unlock_irqrestore(&pmic->lock, flags);
+	return 0;
+}
+
+static void pm8058_gpio_free(struct gpio_chip *chip, unsigned gpio)
+{
+	struct pm8058 *pmic = container_of(chip, struct pm8058, gpio_chip);
+	unsigned long flags;
+
+	/* XXX: set high Z maybe?? */
+	spin_lock_irqsave(&pmic->lock, flags);
+	pmic->gpio_flags[gpio] = 0;
+	spin_unlock_irqrestore(&pmic->lock, flags);
+}
+
+static int gpio_set_dir(struct pm8058 *pmic, unsigned gpio, int dir)
+{
+	unsigned long flags;
+	int ret;
+	u8 val;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	/* only need to write bank1 */
+	val = (pmic->gpio_flags[gpio] & PM8058_GPIO_OPEN_DRAIN ? 0x1 : 0) << 1;
+	val |= ((1 << 7) | (1 << 4) | (_dir_map[dir] << 2) |
+		(dir & PM8058_GPIO_OUTPUT_HIGH ? 0x1 : 0x0));
+	ret = pm8058_writeb(pmic->dev, REG_GPIO_CTRL(gpio), val);
+	if (ret)
+		pr_err("%s: erorr setting dir %x (%d)\n", __func__, dir, ret);
+
+	spin_unlock_irqrestore(&pmic->lock, flags);
+	return ret;
+}
+
+static int pm8058_gpio_direction_in(struct gpio_chip *chip, unsigned gpio)
+{
+	struct pm8058 *pmic = container_of(chip, struct pm8058, gpio_chip);
+
+	return gpio_set_dir(pmic, gpio, PM8058_GPIO_INPUT);
+}
+
+static int pm8058_gpio_direction_out(struct gpio_chip *chip, unsigned gpio,
+				     int val)
+{
+	struct pm8058 *pmic = container_of(chip, struct pm8058, gpio_chip);
+
+	val = val ? PM8058_GPIO_OUTPUT_HIGH : PM8058_GPIO_OUTPUT;
+	return gpio_set_dir(pmic, gpio, val);
+}
+
+static void pm8058_gpio_set(struct gpio_chip *chip, unsigned gpio, int val)
+{
+	struct pm8058 *pmic = container_of(chip, struct pm8058, gpio_chip);
+
+	/* XXX: for now, let's always force the gpio to be an output when
+	 * the user calls this func. I'm not even sure that it's wrong to
+	 * assume that. */
+	val = val ? PM8058_GPIO_OUTPUT_HIGH : PM8058_GPIO_OUTPUT;
+	gpio_set_dir(pmic, gpio, val);
+}
+
+static int pm8058_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+	struct pm8058 *pmic = container_of(chip, struct pm8058, gpio_chip);
+
+	/* XXX: assumes gpio maps 1:1 to irq @ 0 */
+	return get_curr_irq_stat(pmic, gpio);
+}
+
+static int pm8058_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+	struct pm8058 *pmic = container_of(chip, struct pm8058, gpio_chip);
+	return pmic->irq_base + gpio;
+}
+
+static struct gpio_chip pm8058_base_gpio_chip = {
+	.label			= "pm8058",
+	.owner			= THIS_MODULE,
+	.request		= pm8058_gpio_request,
+	.free			= pm8058_gpio_free,
+	.direction_input	= pm8058_gpio_direction_in,
+	.get			= pm8058_gpio_get,
+	.direction_output	= pm8058_gpio_direction_out,
+	.set			= pm8058_gpio_set,
+	.to_irq			= pm8058_gpio_to_irq,
+};
+
+/* irq funcs */
+static int read_irq_block_reg(struct pm8058 *pmic, u8 blk, u16 reg, u8 *val)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	ret = pm8058_writeb(pmic->dev, REG_IRQ_BLK_SEL, blk);
+	if (ret) {
+		pr_err("%s: error setting block select (%d)\n", __func__, ret);
+		goto done;
+	}
+
+	ret = pm8058_readb(pmic->dev, reg, val);
+	if (ret)
+		pr_err("%s: error setting bit select (%d)\n", __func__, ret);
+
+done:
+	spin_unlock_irqrestore(&pmic->lock, flags);
+	return ret;
+}
+
+static int get_curr_irq_stat(struct pm8058 *pmic, unsigned int irq)
+{
+	int ret;
+	u8 val;
+
+	ret = read_irq_block_reg(pmic, pmic->irqs[irq].blk, REG_IRQ_RT_STATUS,
+				 &val);
+	if (ret) {
+		pr_err("%s: can't read irq %d status\n", __func__, irq);
+		goto done;
+	}
+
+	ret = !!(val & (1 << pmic->irqs[irq].blk_bit));
+
+done:
+	return ret;
+}
+
+int pm8058_irq_get_status(struct device *dev, unsigned int irq)
+{
+	struct pm8058 *pmic = dev_get_drvdata(dev);
+
+	if (irq >= PM8058_NUM_IRQS)
+		return -EINVAL;
+	return get_curr_irq_stat(pmic, irq);
+}
+EXPORT_SYMBOL(pm8058_irq_get_status);
+
+static int cfg_irq_blk_bit_perm(struct pm8058 *pmic, u8 blk, u8 mask)
+{
+	int ret;
+	unsigned long flags;
+	u8 tmp;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	ret = pm8058_writeb(pmic->dev, REG_IRQ_PERM_BLK_SEL, blk);
+	if (ret) {
+		pr_err("%s: error setting block select (%d)\n", __func__, ret);
+		goto done;
+	}
+
+	ret = pm8058_readb(pmic->dev, REG_IRQ_PERM, &tmp);
+	if (ret) {
+		pr_err("%s: error getting (%d)\n", __func__, ret);
+		goto done;
+	}
+
+	ret = pm8058_writeb(pmic->dev, REG_IRQ_PERM, tmp | mask);
+	if (ret)
+		pr_err("%s: error writing %d 0x%x 0x%x (0x%x)\n", __func__,
+		       ret, blk, REG_IRQ_PERM, mask);
+
+done:
+	spin_unlock_irqrestore(&pmic->lock, flags);
+	return ret;
+}
+
+static int _write_irq_blk_bit_cfg(struct pm8058 *pmic, u8 blk, u8 bit, u8 cfg)
+{
+	int ret;
+
+	ret = pm8058_writeb(pmic->dev, REG_IRQ_BLK_SEL, blk);
+	if (ret) {
+		pr_err("%s: error setting block select (%d)\n", __func__, ret);
+		goto done;
+	}
+
+	cfg = (1 << 7) | (cfg & 0xf) | (bit << 4);
+	ret = pm8058_writeb(pmic->dev, REG_IRQ_CONFIG, cfg);
+	if (ret)
+		pr_err("%s: error writing irq cfg (%d)\n", __func__, ret);
+
+done:
+	return ret;
+}
+
+static int write_irq_config_locked(struct pm8058 *pmic, unsigned int irq,
+				   u8 cfg)
+{
+	return _write_irq_blk_bit_cfg(pmic, pmic->irqs[irq].blk,
+				      pmic->irqs[irq].blk_bit, cfg);
+}
+
+static int do_irq_master(struct pm8058 *pmic, int group)
+{
+	int i;
+	int j;
+	int ret;
+	u8 val;
+	unsigned long stat;
+
+	ret = pm8058_readb(pmic->dev, pm8058_irq_groups[group].stat_reg, &val);
+	if (ret) {
+		pr_err("%s: Can't read master status\n", __func__);
+		goto done;
+	}
+
+	if (debug_mask & DEBUG_IRQS)
+		pr_info("%s: master %d %02x\n", __func__, group, val);
+	stat = val & pm8058_irq_groups[group].valid_mask;
+	for_each_set_bit(i, &stat, BITS_PER_BYTE) {
+		u8 blk = pm8058_irq_groups[group].block_offset + i;
+		unsigned long blk_stat;
+
+		ret = read_irq_block_reg(pmic, blk, REG_IRQ_IT_STATUS, &val);
+		if (ret) {
+			pr_err("%s: can't read block status\n", __func__);
+			goto done;
+		}
+
+		blk_stat = val;
+		for_each_set_bit(j, &blk_stat, BITS_PER_BYTE) {
+			u8 irq = blk * 8 + j;
+
+			/* XXX: we should mask these out and count em' */
+			if (pmic->pmirqs[irq] == 0xffffffffU) {
+				pr_warning("Unexpected pmirq %d\n", irq);
+				continue;
+			}
+			generic_handle_irq(pmic->pmirqs[irq] + pmic->irq_base);
+		}
+	}
+
+done:
+	return ret;
+}
+
+static void pm8058_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct pm8058 *pmic = get_irq_data(irq);
+	int ret;
+	int i;
+	u8 root;
+
+	desc->chip->ack(irq);
+	ret = pm8058_readb(pmic->dev, REG_IRQ_ROOT, &root);
+	if (ret) {
+		pr_err("%s: Can't read root status\n", __func__);
+		return;
+	}
+
+	if (debug_mask & DEBUG_IRQS)
+		pr_info("%s: root %02x\n", __func__, root);
+	for (i = 0; i < NUM_ROOT_GROUPS; ++i) {
+		if (root & pm8058_irq_groups[i].root_mask)
+			do_irq_master(pmic, i);
+	}
+}
+
+static void pm8058_irq_ack(unsigned int _irq)
+{
+	struct pm8058 *pmic = get_irq_chip_data(_irq);
+	unsigned int irq = _irq - pmic->irq_base;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	write_irq_config_locked(pmic, irq,
+				pmic->irqs[irq].cfg_val | IRQ_CFG_CLR);
+	spin_unlock_irqrestore(&pmic->lock, flags);
+}
+
+static void pm8058_irq_mask(unsigned int _irq)
+{
+	struct pm8058 *pmic = get_irq_chip_data(_irq);
+	unsigned int irq = _irq - pmic->irq_base;
+	struct pm8058_irq_info *irq_info = &pmic->irqs[irq];
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	irq_info->mask = IRQ_CFG_MASK_FE | IRQ_CFG_MASK_RE;
+	irq_info->cfg_val = irq_info->cfg | irq_info->mask;
+	write_irq_config_locked(pmic, irq, irq_info->cfg_val);
+	spin_unlock_irqrestore(&pmic->lock, flags);
+}
+
+static void pm8058_irq_unmask(unsigned int _irq)
+{
+	struct pm8058 *pmic = get_irq_chip_data(_irq);
+	unsigned int irq = _irq - pmic->irq_base;
+	struct pm8058_irq_info *irq_info = &pmic->irqs[irq];
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	irq_info->mask = 0;
+	irq_info->cfg_val = irq_info->cfg;
+	write_irq_config_locked(pmic, irq, irq_info->cfg_val);
+	spin_unlock_irqrestore(&pmic->lock, flags);
+}
+
+static void pm8058_irq_disable(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	pm8058_irq_mask(irq);
+	desc->status |= IRQ_MASKED;
+}
+
+static void pm8058_irq_enable(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	pm8058_irq_unmask(irq);
+	desc->status &= ~IRQ_MASKED;
+}
+
+static int pm8058_irq_set_type(unsigned int _irq, unsigned int flow_type)
+{
+	struct pm8058 *pmic = get_irq_chip_data(_irq);
+	unsigned int irq = _irq - pmic->irq_base;
+	struct pm8058_irq_info *irq_info = &pmic->irqs[irq];
+	unsigned long flags;
+	int ret;
+	u8 cfg;
+
+	cfg = IRQ_CFG_MASK_RE | IRQ_CFG_MASK_FE;
+	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+		if (flow_type & IRQF_TRIGGER_RISING)
+			cfg &= ~IRQ_CFG_MASK_RE;
+		if (flow_type & IRQF_TRIGGER_FALLING)
+			cfg &= ~IRQ_CFG_MASK_FE;
+		__set_irq_handler_unlocked(_irq, handle_edge_irq);
+	} else {
+		cfg |= IRQ_CFG_LVL_SEL;
+		if (flow_type & IRQF_TRIGGER_HIGH)
+			cfg &= ~IRQ_CFG_MASK_RE;
+		else
+			cfg &= ~IRQ_CFG_MASK_FE;
+		__set_irq_handler_unlocked(_irq, handle_level_irq);
+	}
+
+	/* in case the irq was masked when the type was set, we don't want
+	 * to unmask it */
+	spin_lock_irqsave(&pmic->lock, flags);
+	irq_info->cfg = cfg;
+	irq_info->cfg_val = irq_info->cfg | irq_info->mask;
+	ret = write_irq_config_locked(pmic, irq,
+				      irq_info->cfg_val | IRQ_CFG_CLR);
+	spin_unlock_irqrestore(&pmic->lock, flags);
+
+	return ret;
+}
+
+static int pm8058_irq_set_wake(unsigned int _irq, unsigned int on)
+{
+	struct pm8058 *pmic = get_irq_chip_data(_irq);
+	unsigned int irq = _irq - pmic->irq_base;
+	struct pm8058_irq_info *irq_info = &pmic->irqs[irq];
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	if (on) {
+		if (!irq_info->wake) {
+			irq_info->wake = 1;
+			pmic->wake_cnt++;
+		}
+	} else {
+		if (irq_info->wake) {
+			irq_info->wake = 0;
+			pmic->wake_cnt--;
+		}
+	}
+	spin_unlock_irqrestore(&pmic->lock, flags);
+
+	return 0;
+}
+
+static struct irq_chip pm8058_irq_chip = {
+	.name		= "pm8058",
+	.ack		= pm8058_irq_ack,
+	.mask		= pm8058_irq_mask,
+	.unmask		= pm8058_irq_unmask,
+	.disable	= pm8058_irq_disable,
+	.enable		= pm8058_irq_enable,
+	.set_type	= pm8058_irq_set_type,
+	.set_wake	= pm8058_irq_set_wake,
+};
+
+static int pm8058_irq_init(struct pm8058 *pmic, unsigned int irq_base)
+{
+	int i;
+	int j;
+
+	/* mask/clear all the irqs */
+	for (i = 0; i < NUM_BLOCKS; ++i)
+		for (j = 0; j < IRQS_PER_BLOCK; ++j)
+			_write_irq_blk_bit_cfg(pmic, i, j, (IRQ_CFG_MASK_RE |
+							    IRQ_CFG_MASK_FE |
+							    IRQ_CFG_CLR));
+
+	memset(pmic->pmirqs, 0xff, NUM_PMIRQS * sizeof(pmic->pmirqs[0]));
+	for (i = 0; i < NUM_IRQ_BANKS; ++i) {
+		struct pm8058_irq_bank *bank = &pm8058_irq_banks[i];
+
+		for (j = 0; j < bank->cnt; ++j) {
+			unsigned int irq = bank->start + j;
+			unsigned int pmirq = bank->offset + j;
+
+			BUG_ON(irq >= PM8058_NUM_IRQS);
+
+			/* by default mask the irq */
+			pmic->irqs[irq].cfg = 0;
+			pmic->irqs[irq].mask =
+				IRQ_CFG_MASK_RE | IRQ_CFG_MASK_FE;
+			pmic->irqs[irq].cfg_val = pmic->irqs[irq].mask;
+			pmic->irqs[irq].blk = pmirq / 8;
+			pmic->irqs[irq].blk_bit = pmirq % 8;
+			pmic->pmirqs[pmirq] = irq;
+
+			BUG_ON(pmic->irqs[irq].blk >= NUM_BLOCKS);
+
+			/* XXX: slightly inefficient since we can end up
+			 * doing it 8 times per block per bank, but it's
+			 * the easiet. Optimize if gets too slow. */
+
+			/* ensure we set the permissions for the irqs in
+			 * this bank */
+			cfg_irq_blk_bit_perm(pmic, pmic->irqs[irq].blk,
+					     1 << pmic->irqs[irq].blk_bit);
+
+			set_irq_chip(irq_base + irq, &pm8058_irq_chip);
+			set_irq_chip_data(irq_base + irq, pmic);
+			set_irq_handler(irq_base + irq, handle_edge_irq);
+			set_irq_flags(irq_base + irq, IRQF_VALID);
+		}
+
+	}
+
+	return 0;
+}
+
+static struct platform_device *add_child_device(
+			struct pm8058 *pmic, const char *name, void *pdata,
+			struct resource *res, int num_res)
+{
+	struct platform_device *pdev;
+	int ret;
+
+	pdev = platform_device_alloc(name, -1);
+	if (!pdev) {
+		pr_err("%s: cannot allocate pdev for '%s'\n", __func__, name);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	pdev->dev.parent = pmic->dev;
+	pdev->dev.platform_data = pdata;
+
+	ret = platform_device_add_resources(pdev, res, num_res);
+	if (ret) {
+		pr_err("%s: can't add resources for '%s'\n", __func__, name);
+		goto err;
+	}
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+		pr_err("%s: cannot add child platform device '%s'\n", __func__,
+		       name);
+		goto err;
+	}
+	return pdev;
+
+err:
+	if (pdev)
+		platform_device_put(pdev);
+	return ERR_PTR(ret);
+}
+
+static int add_keypad_device(struct pm8058 *pmic, void *pdata)
+{
+	struct platform_device *pdev;
+	struct resource irq_res[] = {
+		{
+			.start	= pmic->irq_base + PM8058_KEYPAD_IRQ,
+			.end	= pmic->irq_base + PM8058_KEYPAD_IRQ,
+			.flags	= IORESOURCE_IRQ,
+			.name	= "kp_sense",
+		},
+		{
+			.start	= pmic->irq_base + PM8058_KEYPAD_STUCK_IRQ,
+			.end	= pmic->irq_base + PM8058_KEYPAD_STUCK_IRQ,
+			.flags	= IORESOURCE_IRQ,
+			.name	= "kp_stuck",
+		}
+	};
+
+	pdev = add_child_device(pmic, "pm8058-keypad", pdata, irq_res,
+				ARRAY_SIZE(irq_res));
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	pmic->kp_pdev = pdev;
+	return 0;
+}
+
+static int add_charger_device(struct pm8058 *pmic, void *pdata)
+{
+	struct platform_device *pdev;
+	struct resource irq_res[] = {
+		{
+			.start	= pmic->irq_base + PM8058_CHGVAL_IRQ,
+			.end	= pmic->irq_base + PM8058_CHGVAL_IRQ,
+			.flags	= IORESOURCE_IRQ,
+			.name	= "chgval_irq",
+		},
+		{
+			.start	= pmic->irq_base + PM8058_FASTCHG_IRQ,
+			.end	= pmic->irq_base + PM8058_FASTCHG_IRQ,
+			.flags	= IORESOURCE_IRQ,
+			.name	= "fastchg_irq",
+		}
+	};
+
+	pdev = add_child_device(pmic, "pm8058-charger", pdata, irq_res,
+				ARRAY_SIZE(irq_res));
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	pmic->charger_pdev = pdev;
+	return 0;
+}
+
+static int pm8058_probe(struct platform_device *pdev)
+{
+	struct pm8058_platform_data *pdata = pdev->dev.platform_data;
+	struct pm8058 *pmic;
+	int devirq;
+	int ret;
+	u8 val;
+
+	if (!pdata) {
+		pr_err("%s: no platform data\n", __func__);
+		return -EINVAL;
+	}
+
+	devirq = platform_get_irq(pdev, 0);
+	if (devirq < 0) {
+		pr_err("%s: missing devirq\n", __func__);
+		return devirq;
+	}
+
+	pmic = kzalloc(sizeof(struct pm8058), GFP_KERNEL);
+	if (!pmic) {
+		pr_err("%s: Cannot alloc pm8058 struct\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* Read PMIC chip revision */
+	ret = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
+	if (ret)
+		goto err_read_rev;
+	pr_info("%s: PMIC revision: %x\n", __func__, val);
+
+	pmic->dev = &pdev->dev;
+	pmic->irq_base = pdata->irq_base;
+	pmic->devirq = devirq;
+	spin_lock_init(&pmic->lock);
+	pmic->pdata = pdata;
+	platform_set_drvdata(pdev, pmic);
+
+	ret = pm8058_irq_init(pmic, pmic->irq_base);
+	if (ret)
+		goto err_irq_init;
+
+	memcpy(&pmic->gpio_chip, &pm8058_base_gpio_chip,
+	       sizeof(struct gpio_chip));
+	pmic->gpio_chip.dev = pmic->dev;
+	pmic->gpio_chip.base = pdata->gpio_base;
+	pmic->gpio_chip.ngpio = PM8058_NUM_GPIOS;
+
+	ret = gpiochip_add(&pmic->gpio_chip);
+	if (ret) {
+		pr_err("%s: can't register gpio chip\n", __func__);
+		goto err_gpiochip_add;
+	}
+
+	set_irq_type(devirq, IRQ_TYPE_LEVEL_LOW);
+	set_irq_data(devirq, pmic);
+	set_irq_chained_handler(devirq, pm8058_irq_handler);
+	set_irq_wake(devirq, 1);
+
+	the_pm8058 = pmic;
+
+	if (pdata->init) {
+		ret = pdata->init(pmic->dev);
+		if (ret) {
+			pr_err("%s: error in board init\n", __func__);
+			goto err_pdata_init;
+		}
+	}
+
+	if (pdata->keypad_pdata) {
+		ret = add_keypad_device(pmic, pdata->keypad_pdata);
+		if (ret) {
+			pr_err("%s: can't add child keypad device\n", __func__);
+			goto err_add_kp_dev;
+		}
+	}
+
+	if (pdata->charger_pdata) {
+		ret = add_charger_device(pmic, pdata->charger_pdata);
+		if (ret) {
+			pr_err("%s: can't add child charger dev\n", __func__);
+			goto err_add_charger_dev;
+		}
+	}
+
+	return 0;
+
+err_add_charger_dev:
+	if (pmic->kp_pdev)
+		platform_device_put(pmic->kp_pdev);
+err_add_kp_dev:
+err_pdata_init:
+	the_pm8058 = NULL;
+	set_irq_wake(devirq, 0);
+	set_irq_chained_handler(devirq, NULL);
+	WARN_ON(gpiochip_remove(&pmic->gpio_chip));
+err_gpiochip_add:
+err_irq_init:
+	platform_set_drvdata(pdev, NULL);
+err_read_rev:
+	kfree(pmic);
+	return ret;
+}
+
+static struct platform_driver pm8058_driver = {
+	.probe		= pm8058_probe,
+	.driver		= {
+		.name	= "pm8058-core",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init pm8058_init(void)
+{
+	return platform_driver_register(&pm8058_driver);
+}
+postcore_initcall(pm8058_init);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 86f2258..ab4a951 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -323,6 +323,24 @@
 	  If you say yes here you get support for Asahi Kasei's
 	  orientation sensor AK8975.
 
+config SENSORS_AKM8973
+	tristate "AKM8973 Compass Driver"
+	depends on I2C
+	help
+	 AKM8973 Compass Driver implemented by HTC.
+
+config SENSORS_AKM8976
+	tristate "AKM8976 Compass Driver"
+	depends on I2C
+	help
+	  AKM8976 Compass Driver implemented by HTC.
+
+config VP_A1026
+	tristate "A1026 Voice Processor Driver"
+	depends on I2C
+	help
+	  A1026 Voice Processor Driver implemented by HTC.
+
 config EP93XX_PWM
 	tristate "EP93xx PWM support"
 	depends on ARCH_EP93XX
@@ -407,5 +425,6 @@
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
 source "drivers/misc/iwmc3200top/Kconfig"
+source "drivers/misc/video_core/720p/Kconfig"
 
 endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index fe5ad59..48ce8fe 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -38,3 +38,7 @@
 obj-$(CONFIG_WL127X_RFKILL)	+= wl127x-rfkill.o
 obj-$(CONFIG_APANIC)		+= apanic.o
 obj-$(CONFIG_SENSORS_AK8975)	+= akm8975.o
+obj-$(CONFIG_SENSORS_AKM8973)	+= akm8973.o
+obj-$(CONFIG_SENSORS_AKM8976)	+= akm8976.o
+obj-$(CONFIG_VP_A1026)		+= a1026.o
+obj-$(CONFIG_MSM_720P_CORE)	+= video_core/720p/
diff --git a/drivers/misc/a1026.c b/drivers/misc/a1026.c
new file mode 100644
index 0000000..7eaa3e1
--- /dev/null
+++ b/drivers/misc/a1026.c
@@ -0,0 +1,1146 @@
+/* drivers/i2c/chips/a1026.c - a1026 voice processor 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.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <linux/a1026.h>
+
+#define DEBUG			(0)
+#define ENABLE_DIAG_IOCTLS	(0)
+
+static struct i2c_client *this_client;
+static struct a1026_platform_data *pdata;
+
+static int execute_cmdmsg(unsigned int);
+
+static struct mutex a1026_lock;
+static int a1026_opened;
+static int a1026_suspended;
+static int control_a1026_clk;
+static unsigned int a1026_NS_state = A1026_NS_STATE_AUTO;
+static int a1026_current_config = A1026_PATH_SUSPEND;
+static int a1026_param_ID;
+
+struct vp_ctxt {
+	unsigned char *data;
+	unsigned int img_size;
+};
+
+struct vp_ctxt the_vp;
+
+static int a1026_i2c_read(char *rxData, int length)
+{
+	int rc;
+	struct i2c_msg msgs[] = {
+		{
+			.addr = this_client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = rxData,
+		},
+	};
+
+	rc = i2c_transfer(this_client->adapter, msgs, 1);
+	if (rc < 0) {
+		pr_err("%s: transfer error %d\n", __func__, rc);
+		return rc;
+	}
+
+#if DEBUG
+	{
+		int i = 0;
+		for (i = 0; i < length; i++)
+			pr_info("%s: rx[%d] = %2x\n", __func__, i, rxData[i]);
+	}
+#endif
+
+	return 0;
+}
+
+static int a1026_i2c_write(char *txData, int length)
+{
+	int rc;
+	struct i2c_msg msg[] = {
+		{
+			.addr = this_client->addr,
+			.flags = 0,
+			.len = length,
+			.buf = txData,
+		},
+	};
+
+	rc = i2c_transfer(this_client->adapter, msg, 1);
+	if (rc < 0) {
+		pr_err("%s: transfer error %d\n", __func__, rc);
+		return rc;
+	}
+
+#if DEBUG
+	{
+		int i = 0;
+		for (i = 0; i < length; i++)
+			pr_info("%s: tx[%d] = %2x\n", __func__, i, txData[i]);
+	}
+#endif
+
+	return 0;
+}
+
+static int a1026_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct vp_ctxt *vp = &the_vp;
+
+	mutex_lock(&a1026_lock);
+
+	if (a1026_opened) {
+		pr_err("%s: busy\n", __func__);
+		rc = -EBUSY;
+		goto done;
+	}
+
+	file->private_data = vp;
+	vp->img_size = 0;
+	a1026_opened = 1;
+done:
+	mutex_unlock(&a1026_lock);
+	return rc;
+}
+
+static int a1026_release(struct inode *inode, struct file *file)
+{
+	mutex_lock(&a1026_lock);
+	a1026_opened = 0;
+	mutex_unlock(&a1026_lock);
+
+	return 0;
+}
+
+static void a1026_i2c_sw_reset(unsigned int reset_cmd)
+{
+	int rc = 0;
+	unsigned char msgbuf[4];
+
+	msgbuf[0] = (reset_cmd >> 24) & 0xFF;
+	msgbuf[1] = (reset_cmd >> 16) & 0xFF;
+	msgbuf[2] = (reset_cmd >> 8) & 0xFF;
+	msgbuf[3] = reset_cmd & 0xFF;
+
+	pr_info("%s: %08x\n", __func__, reset_cmd);
+
+	rc = a1026_i2c_write(msgbuf, 4);
+	if (!rc)
+		msleep(20);
+}
+
+static ssize_t a1026_bootup_init(struct file *file, struct a1026img *img)
+{
+	struct vp_ctxt *vp = file->private_data;
+	int rc, pass = 0;
+	int remaining;
+	int retry = RETRY_CNT;
+	unsigned char *index;
+	char buf[2];
+
+	if (img->img_size > A1026_MAX_FW_SIZE) {
+		pr_err("%s: invalid a1026 image size %d\n", __func__,
+			img->img_size);
+		return -EINVAL;
+	}
+
+	vp->data = kmalloc(img->img_size, GFP_KERNEL);
+	if (!vp->data) {
+		pr_err("%s: out of memory\n", __func__);
+		return -ENOMEM;
+	}
+	vp->img_size = img->img_size;
+	if (copy_from_user(vp->data, img->buf, img->img_size)) {
+		pr_err("%s: copy from user failed\n", __func__);
+		kfree(vp->data);
+		return -EFAULT;
+	}
+
+	while (retry--) {
+		/* Reset A1026 chip */
+		gpio_set_value(pdata->gpio_a1026_reset, 0);
+
+		/* Enable A1026 clock */
+		if (control_a1026_clk)
+			gpio_set_value(pdata->gpio_a1026_clk, 1);
+		mdelay(1);
+
+		/* Take out of reset */
+		gpio_set_value(pdata->gpio_a1026_reset, 1);
+
+		msleep(50); /* Delay before send I2C command */
+
+		/* Boot Cmd to A1026 */
+		buf[0] = A1026_msg_BOOT >> 8;
+		buf[1] = A1026_msg_BOOT & 0xff;
+
+		rc = a1026_i2c_write(buf, 2);
+		if (rc < 0) {
+			pr_err("%s: set boot mode error (%d retries left)\n",
+				__func__, retry);
+			continue;
+		}
+
+		mdelay(1); /* use polling */
+		rc = a1026_i2c_read(buf, 1);
+		if (rc < 0) {
+			pr_err("%s: boot mode ack error (%d retries left)\n",
+				__func__, retry);
+			continue;
+		}
+
+		if (buf[0] != A1026_msg_BOOT_ACK) {
+			pr_err("%s: not a boot-mode ack (%d retries left)\n",
+				__func__, retry);
+			continue;
+		}
+
+		remaining = vp->img_size / 32;
+		index = vp->data;
+
+		pr_info("%s: starting to load image (%d passes)...\n",
+			__func__,
+			remaining + !!(vp->img_size % 32));
+
+		for (; remaining; remaining--, index += 32) {
+			rc = a1026_i2c_write(index, 32);
+			if (rc < 0)
+				break;
+		}
+
+		if (rc >= 0 && vp->img_size % 32)
+			rc = a1026_i2c_write(index, vp->img_size % 32);
+
+		if (rc < 0) {
+			pr_err("%s: fw load error %d (%d retries left)\n",
+				__func__, rc, retry);
+			continue;
+		}
+
+		msleep(20); /* Delay time before issue a Sync Cmd */
+
+		pr_info("%s: firmware loaded successfully\n", __func__);
+
+		rc = execute_cmdmsg(A100_msg_Sync);
+		if (rc < 0) {
+			pr_err("%s: sync command error %d (%d retries left)\n",
+				__func__, rc, retry);
+			continue;
+		}
+
+		pass = 1;
+		break;
+	}
+
+	/* Put A1026 into sleep mode */
+	rc = execute_cmdmsg(A100_msg_Sleep);
+	if (rc < 0) {
+		pr_err("%s: suspend error\n", __func__);
+		goto set_suspend_err;
+	}
+
+	a1026_suspended = 1;
+	a1026_current_config = A1026_PATH_SUSPEND;
+
+	msleep(120);
+	/* Disable A1026 clock */
+	if (control_a1026_clk)
+		gpio_set_value(pdata->gpio_a1026_clk, 0);
+
+set_suspend_err:
+	if (pass && !rc)
+		pr_info("%s: initialized!\n", __func__);
+	else
+		pr_err("%s: initialization failed\n", __func__);
+
+	kfree(vp->data);
+	return rc;
+}
+
+unsigned char phonecall_receiver[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:2-mic Close Talk (CT) */
+	0x80,0x1C,0x00,0x01, /* VoiceProcessingOn, 0x0001:Yes */
+	0x80,0x17,0x00,0x1A, /* SetAlgorithmParmID, 0x001A:Use ComfortNoise */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x17,0x00,0x04, /* SetAlgorithmParmID, 0x0004:Use AGC */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x17,0x00,0x00, /* SetAlgorithmParmID, 0x0000:Suppression Strength */
+	0x80,0x18,0x00,0x05, /* SetAlgorithmParm, 0x0005:25dB Max Suppression */
+	0x80,0x17,0x00,0x20, /* SetAlgorithmParmID, 0x0020:Tx PostEq Mode */
+	0x80,0x18,0x00,0x02, /* SetAlgorithmParm, 0x0002:On always */
+	0x80,0x1B,0x00,0x0C, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x0C:(12 dB) */
+	0x80,0x1B,0x01,0x0C, /* SetDigitalInputGain, 0x01:Secondary Mic (Tx), 0x0C:(12 dB) */
+	0x80,0x15,0x00,0xFA, /* SetDigitalOutputGain, 0x00:Tx, 0xFA:(-6 dB) */
+};
+
+unsigned char phonecall_headset[] = {
+	0x80,0x26,0x00,0x15, /* SelectRouting, 0x0015:Snk,Pri,Snk,Snk - Csp,Zro,Zro (none) */
+	0x80,0x1C,0x00,0x00, /* VoiceProcessingOn, 0x0000:No */
+	0x80,0x1B,0x00,0x12, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x12:(18 dB) */
+	0x80,0x15,0x00,0xF8, /* SetDigitalOutputGain, 0x00:Tx, 0xF8:(-8 dB) */
+};
+
+unsigned char phonecall_speaker[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x02, /* SetAlgorithmParm, 0x0002:1-mic Desktop/Vehicle (DV) */
+	0x80,0x1C,0x00,0x01, /* VoiceProcessingOn, 0x0001:Yes */
+	0x80,0x17,0x00,0x00, /* SetAlgorithmParmID, 0x0000:Suppression Strength */
+	0x80,0x18,0x00,0x02, /* SetAlgorithmParm, 0x0002 */
+	0x80,0x17,0x00,0x04, /* SetAlgorithmParmID, 0x0004:Use AGC */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x17,0x00,0x1A, /* SetAlgorithmParmID, 0x001A:Use ComfortNoise */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x1B,0x00,0x12, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x12:(18 dB) */
+	0x80,0x15,0x00,0xFD, /* SetDigitalOutputGain, 0x00:Tx, 0xFD:(-3 dB) */
+};
+
+unsigned char phonecall_bt[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x03, /* SetAlgorithmParm, 0x0003:1-mic External (MD) */
+	0x80,0x26,0x00,0x06, /* SelectRouting, 0x0006:Snk,Snk,Fei,Pri - Zro,Csp,Feo (PCM0->PCM1+ADCs) */
+	0x80,0x1C,0x00,0x00, /* VoiceProcessingOn, 0x0000:No */
+	0x80,0x1B,0x00,0x00, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x00:(0 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char phonecall_tty[] = {
+	0x80,0x26,0x00,0x15, /* SelectRouting, 0x0015:Snk,Pri,Snk,Snk - Csp,Zro,Zro (none) */
+	0x80,0x1C,0x00,0x00, /* VoiceProcessingOn, 0x0000:No */
+	0x80,0x1B,0x00,0x00, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x00:(0 dB) */
+	0x80,0x15,0x00,0xFB, /* SetDigitalOutputGain, 0x00:Tx, 0xFB:(-5 dB) */
+};
+
+unsigned char INT_MIC_recording_receiver[] = {
+	0x80,0x26,0x00,0x07, /* SelectRouting, 0x0007:Pri,Snk,Snk,Snk - Csp,Zro,Zro (none) */
+	0x80,0x1C,0x00,0x00, /* VoiceProcessingOn, 0x0000:No */
+	0x80,0x1B,0x00,0x12, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x12:(18 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char EXT_MIC_recording[] = {
+	0x80,0x26,0x00,0x15, /* SelectRouting, 0x0015:Snk,Pri,Snk,Snk - Csp,Zro,Zro (none) */
+	0x80,0x1C,0x00,0x00, /* VoiceProcessingOn, 0x0000:No */
+	0x80,0x1B,0x00,0x12, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x12:(18 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char INT_MIC_recording_speaker[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x02, /* SetAlgorithmParm, 0x0002:1-mic Desktop/Vehicle (DV) */
+	0x80,0x1C,0x00,0x00, /* VoiceProcessingOn, 0x0000:No */
+	0x80,0x1B,0x00,0x12, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x12:(18 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char BACK_MIC_recording[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x02, /* SetAlgorithmParm, 0x0002:1-mic Desktop/Vehicle (DV) */
+	0x80,0x26,0x00,0x15, /* SelectRouting, 0x0015:Snk,Pri,Snk,Snk - Csp,Zro,Zro (none) */
+	0x80,0x1C,0x00,0x01, /* VoiceProcessingOn, 0x0001:Yes */
+	0x80,0x17,0x00,0x04, /* SetAlgorithmParmID, 0x0004:Use AGC */
+	0x80,0x18,0x00,0x01, /* SetAlgorithmParm, 0x0001:Yes */
+	0x80,0x17,0x00,0x1A, /* SetAlgorithmParmID, 0x001A:Use ComfortNoise */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x17,0x00,0x00, /* SetAlgorithmParmID, 0x0000:Suppression Strength */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No Suppression */
+	0x80,0x1B,0x00,0x12, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x12:(18 dB) */
+	0x80,0x15,0x00,0x06, /* SetDigitalOutputGain, 0x00:Tx, 0x06:(6 dB) */
+};
+
+unsigned char vr_no_ns_receiver[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:2-mic Close Talk (CT) */
+	0x80,0x1C,0x00,0x00, /* VoiceProcessingOn, 0x0000:No */
+	0x80,0x1B,0x00,0x0C, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x0C:(12 dB) */
+	0x80,0x1B,0x01,0x0C, /* SetDigitalInputGain, 0x01:Secondary Mic (Tx), 0x09:(12 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char vr_no_ns_headset[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x03, /* SetAlgorithmParm, 0x0003:1M-DG (1-mic digital input) */
+	0x80,0x26,0x00,0x15, /* SelectRouting, 0x0015:Snk,Pri,Snk,Snk - Csp,Zro,Zro (none) */
+	0x80,0x1C,0x00,0x00, /* VoiceProcessingOn, 0x0000:No */
+	0x80,0x1B,0x00,0x12, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x12:(18 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char vr_no_ns_speaker[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x02, /* SetAlgorithmParm, 0x0002:1-mic Desktop/Vehicle (DV) */
+	0x80,0x1C,0x00,0x00, /* VoiceProcessingOn, 0x0000:No */
+	0x80,0x1B,0x00,0x0C, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x0C:(12 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char vr_no_ns_bt[] = {
+	0x80,0x26,0x00,0x06, /* SelectRouting, 0x0006:Snk,Snk,Fei,Pri - Zro,Csp,Feo (PCM0->PCM1+ADCs) */
+	0x80,0x1C,0x00,0x00, /* VoiceProcessingOn, 0x0000:No */
+	0x80,0x1B,0x00,0x00, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x00:(0 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char vr_ns_receiver[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:2-mic Close Talk (CT) */
+	0x80,0x1C,0x00,0x01, /* VoiceProcessingOn, 0x0001:Yes */
+	0x80,0x17,0x00,0x1A, /* SetAlgorithmParmID, 0x001A:Use ComfortNoise */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x17,0x00,0x04, /* SetAlgorithmParmID, 0x0004:Use AGC */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x17,0x00,0x00, /* SetAlgorithmParmID, 0x0000:Suppression Strength */
+	0x80,0x18,0x00,0x04, /* SetAlgorithmParm, 0x0004:20dB Max Suppression */
+	0x80,0x1B,0x00,0x0C, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x0C:(12 dB) */
+	0x80,0x1B,0x01,0x0C, /* SetDigitalInputGain, 0x01:Secondary Mic (Tx), 0x0C:(12 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char vr_ns_headset[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x03, /* SetAlgorithmParm, 0x0003:1-mic External (MD) */
+	0x80,0x26,0x00,0x15, /* SelectRouting, 0x0015:Snk,Pri,Snk,Snk - Csp,Zro,Zro (none) */
+	0x80,0x1C,0x00,0x01, /* VoiceProcessingOn, 0x0001:Yes */
+	0x80,0x17,0x00,0x00, /* SetAlgorithmParmID, 0x0000:Suppression Strength */
+	0x80,0x18,0x00,0x02, /* SetAlgorithmParm, 0x0002:20dB Max Suppression */
+	0x80,0x17,0x00,0x1A, /* SetAlgorithmParmID, 0x001A:Use ComfortNoise */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x17,0x00,0x04, /* SetAlgorithmParmID, 0x0004:Use AGC */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x1B,0x00,0x12, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x12:(18 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char vr_ns_speaker[] = {
+	0x80,0x17,0x00,0x02, /* SetAlgorithmParmID, 0x0002:Microphone Configuration */
+	0x80,0x18,0x00,0x02, /* SetAlgorithmParm, 0x0002:1-mic Desktop/Vehicle (DV) */
+	0x80,0x1C,0x00,0x01, /* VoiceProcessingOn, 0x0001:Yes */
+	0x80,0x17,0x00,0x00, /* SetAlgorithmParmID, 0x0000:Suppression Strength */
+	0x80,0x18,0x00,0x04, /* SetAlgorithmParm, 0x0004:20dB Max Suppression */
+	0x80,0x17,0x00,0x04, /* SetAlgorithmParmID, 0x0004:Use AGC */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x17,0x00,0x1A, /* SetAlgorithmParmID, 0x001A:Use ComfortNoise */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x1B,0x00,0x0C, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x0C:(12 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char vr_ns_bt[] = {
+	0x80,0x26,0x00,0x06, /* SelectRouting, 0x0006:Snk,Snk,Fei,Pri - Zro,Csp,Feo (PCM0->PCM1+ADCs) */
+	0x80,0x1C,0x00,0x01, /* VoiceProcessingOn, 0x0001:Yes */
+	0x80,0x17,0x00,0x00, /* SetAlgorithmParmID, 0x0000:Suppression Strength */
+	0x80,0x18,0x00,0x02, /* SetAlgorithmParm, 0x0002:20dB Max Suppression */
+	0x80,0x17,0x00,0x04, /* SetAlgorithmParmID, 0x0004:Use AGC */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x17,0x00,0x1A, /* SetAlgorithmParmID, 0x001A:Use ComfortNoise */
+	0x80,0x18,0x00,0x00, /* SetAlgorithmParm, 0x0000:No */
+	0x80,0x1B,0x00,0x00, /* SetDigitalInputGain, 0x00:Primay Mic (Tx), 0x00:(0 dB) */
+	0x80,0x15,0x00,0x00, /* SetDigitalOutputGain, 0x00:Tx, 0x00:(0 dB) */
+};
+
+unsigned char suspend_mode[] = {
+	0x80,0x10,0x00,0x01
+};
+
+static ssize_t chk_wakeup_a1026(void)
+{
+	int rc = 0, retry = 3;
+
+	if (a1026_suspended == 1) {
+		/* Enable A1026 clock */
+		if (control_a1026_clk) {
+			gpio_set_value(pdata->gpio_a1026_clk, 1);
+			mdelay(1);
+		}
+
+		gpio_set_value(pdata->gpio_a1026_wakeup, 0);
+		msleep(120);
+
+		do {
+			rc = execute_cmdmsg(A100_msg_Sync);
+		} while ((rc < 0) && --retry);
+
+		gpio_set_value(pdata->gpio_a1026_wakeup, 1);
+		if (rc < 0) {
+			pr_err("%s: failed (%d)\n", __func__, rc);
+			goto wakeup_sync_err;
+		}
+
+		a1026_suspended = 0;
+	}
+wakeup_sync_err:
+	return rc;
+}
+
+/* Filter commands according to noise suppression state forced by
+ * A1026_SET_NS_STATE ioctl.
+ *
+ * For this function to operate properly, all configurations must include
+ * both A100_msg_Bypass and Mic_Config commands even if default values
+ * are selected or if Mic_Config is useless because VP is off
+ */
+int a1026_filter_vp_cmd(int cmd, int mode)
+{
+	int msg = (cmd >> 16) & 0xFFFF;
+	int filtered_cmd = cmd;
+
+	if (a1026_NS_state == A1026_NS_STATE_AUTO)
+		return cmd;
+
+	switch (msg) {
+	case A100_msg_Bypass:
+		if (a1026_NS_state == A1026_NS_STATE_OFF)
+			filtered_cmd = A1026_msg_VP_OFF;
+		else
+			filtered_cmd = A1026_msg_VP_ON;
+		break;
+	case A100_msg_SetAlgorithmParmID:
+		a1026_param_ID = cmd & 0xFFFF;
+		break;
+	case A100_msg_SetAlgorithmParm:
+		if (a1026_param_ID == Mic_Config) {
+			if (a1026_NS_state == A1026_NS_STATE_CT)
+				filtered_cmd = (msg << 16);
+			else if (a1026_NS_state == A1026_NS_STATE_FT)
+				filtered_cmd = (msg << 16) | 0x0002;
+		}
+		break;
+	default:
+		if (mode == A1026_CONFIG_VP)
+			filtered_cmd = -1;
+		break;
+	}
+
+	pr_info("%s: %x filtered = %x, a1026_NS_state %d, mode %d\n", __func__,
+			cmd, filtered_cmd, a1026_NS_state, mode);
+
+	return filtered_cmd;
+}
+
+int a1026_set_config(char newid, int mode)
+{
+	int i = 0, rc = 0, size = 0;
+	int number_of_cmd_sets, rd_retry_cnt;
+	unsigned int sw_reset = 0;
+	unsigned char *i2c_cmds;
+	unsigned char *index = 0;
+	unsigned char ack_buf[A1026_CMD_FIFO_DEPTH * 4];
+	unsigned char rdbuf[4];
+
+	if ((a1026_suspended) && (newid == A1026_PATH_SUSPEND))
+		return rc;
+
+	rc = chk_wakeup_a1026();
+	if (rc < 0)
+		return rc;
+
+	sw_reset = ((A100_msg_Reset << 16) | RESET_IMMEDIATE);
+
+	switch (newid) {
+	case A1026_PATH_INCALL_RECEIVER:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = phonecall_receiver;
+		size = sizeof(phonecall_receiver);
+		break;
+	case A1026_PATH_INCALL_HEADSET:
+		gpio_set_value(pdata->gpio_a1026_micsel, 1);
+		i2c_cmds = phonecall_headset;
+		size = sizeof(phonecall_headset);
+		break;
+	case A1026_PATH_INCALL_SPEAKER:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = phonecall_speaker;
+		size = sizeof(phonecall_speaker);
+		break;
+	case A1026_PATH_INCALL_BT:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = phonecall_bt;
+		size = sizeof(phonecall_bt);
+		break;
+	case A1026_PATH_INCALL_TTY:
+		gpio_set_value(pdata->gpio_a1026_micsel, 1);
+		i2c_cmds = phonecall_tty;
+		size = sizeof(phonecall_tty);
+		break;
+	case A1026_PATH_VR_NO_NS_RECEIVER:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = vr_no_ns_receiver;
+		size = sizeof(vr_no_ns_receiver);
+		break;
+	case A1026_PATH_VR_NO_NS_HEADSET:
+		gpio_set_value(pdata->gpio_a1026_micsel, 1);
+		i2c_cmds = vr_no_ns_headset;
+		size = sizeof(vr_no_ns_headset);
+		break;
+	case A1026_PATH_VR_NO_NS_SPEAKER:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = vr_no_ns_speaker;
+		size = sizeof(vr_no_ns_speaker);
+		break;
+	case A1026_PATH_VR_NO_NS_BT:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = vr_no_ns_bt;
+		size = sizeof(vr_no_ns_bt);
+		break;
+	case A1026_PATH_VR_NS_RECEIVER:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = vr_ns_receiver;
+		size = sizeof(vr_ns_receiver);
+		break;
+	case A1026_PATH_VR_NS_HEADSET:
+		gpio_set_value(pdata->gpio_a1026_micsel, 1);
+		i2c_cmds = vr_ns_headset;
+		size = sizeof(vr_ns_headset);
+		break;
+	case A1026_PATH_VR_NS_SPEAKER:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = vr_ns_speaker;
+		size = sizeof(vr_ns_speaker);
+		break;
+	case A1026_PATH_VR_NS_BT:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = vr_ns_bt;
+		size = sizeof(vr_ns_bt);
+		break;
+	case A1026_PATH_RECORD_RECEIVER:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = INT_MIC_recording_receiver;
+		size = sizeof(INT_MIC_recording_receiver);
+		break;
+	case A1026_PATH_RECORD_HEADSET:
+		gpio_set_value(pdata->gpio_a1026_micsel, 1);
+		i2c_cmds = EXT_MIC_recording;
+		size = sizeof(EXT_MIC_recording);
+		break;
+	case A1026_PATH_RECORD_SPEAKER:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = INT_MIC_recording_speaker;
+		size = sizeof(INT_MIC_recording_speaker);
+		break;
+	case A1026_PATH_RECORD_BT:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = phonecall_bt;
+		size = sizeof(phonecall_bt);
+		break;
+	case A1026_PATH_SUSPEND:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = (unsigned char *)suspend_mode;
+		size = sizeof(suspend_mode);
+		break;
+	case A1026_PATH_CAMCORDER:
+		gpio_set_value(pdata->gpio_a1026_micsel, 0);
+		i2c_cmds = BACK_MIC_recording;
+		size = sizeof(BACK_MIC_recording);
+		break;
+	default:
+		pr_err("%s: invalid cmd %d\n", __func__, newid);
+		rc = -1;
+		goto input_err;
+		break;
+	}
+
+	a1026_current_config = newid;
+	pr_info("%s: change to mode %d\n", __func__, newid);
+
+	pr_info("%s: block write start (size = %d)\n", __func__, size);
+#if DEBUG
+        for (i = 1; i <= size; i++) {
+                pr_info("%x ", *(i2c_cmds + i - 1));
+                if ( !(i % 4))
+                        pr_info("\n");
+        }
+#endif
+
+	rc = a1026_i2c_write(i2c_cmds, size);
+	if (rc < 0) {
+		pr_err("A1026 CMD block write error!\n");
+		a1026_i2c_sw_reset(sw_reset);
+		return rc;
+	}
+	pr_info("%s: block write end\n", __func__);
+
+	/* Don't need to get Ack after sending out a suspend command */
+	if (*i2c_cmds == 0x80 && *(i2c_cmds + 1) == 0x10
+		&& *(i2c_cmds + 2) == 0x00 && *(i2c_cmds + 3) == 0x01) {
+		a1026_suspended = 1;
+		/* Disable A1026 clock */
+		msleep(120);
+		if (control_a1026_clk)
+			gpio_set_value(pdata->gpio_a1026_clk, 0);
+		return rc;
+	}
+
+	memset(ack_buf, 0, sizeof(ack_buf));
+	msleep(20);
+	pr_info("%s: CMD ACK block read start\n", __func__);
+	rc = a1026_i2c_read(ack_buf, size);
+	if (rc < 0) {
+		pr_err("%s: CMD ACK block read error\n", __func__);
+		a1026_i2c_sw_reset(sw_reset);
+		return rc;
+	} else {
+		pr_info("%s: CMD ACK block read end\n", __func__);
+#if DEBUG
+		for (i = 1; i <= size; i++) {
+			pr_info("%x ", ack_buf[i-1]);
+			if ( !(i % 4))
+				pr_info("\n");
+		}
+#endif
+		index = ack_buf;
+		number_of_cmd_sets = size / 4;
+		do {
+			if (*index == 0x00) {
+				rd_retry_cnt = POLLING_RETRY_CNT;
+rd_retry:
+				if (rd_retry_cnt--) {
+					memset(rdbuf, 0, sizeof(rdbuf));
+					rc = a1026_i2c_read(rdbuf, 4);
+					if (rc < 0)
+						return rc;
+#if DEBUG
+					for (i = 0; i < sizeof(rdbuf); i++) {
+						pr_info("0x%x\n", rdbuf[i]);
+					}
+					pr_info("-----------------\n");
+#endif
+					if (rdbuf[0] == 0x00) {
+						msleep(20);
+						goto rd_retry;
+					}
+				} else {
+					pr_err("%s: CMD ACK Not Ready\n",
+						__func__);
+					return -EBUSY;
+				}
+			} else if (*index == 0xff) { /* illegal cmd */
+				return -ENOEXEC;
+			} else if (*index == 0x80) {
+				index += 4;
+			}
+		} while (--number_of_cmd_sets);
+	}
+input_err:
+	return rc;
+}
+
+int execute_cmdmsg(unsigned int msg)
+{
+	int rc = 0;
+	int retries, pass = 0;
+	unsigned char msgbuf[4];
+	unsigned char chkbuf[4];
+	unsigned int sw_reset = 0;
+
+	sw_reset = ((A100_msg_Reset << 16) | RESET_IMMEDIATE);
+
+	msgbuf[0] = (msg >> 24) & 0xFF;
+	msgbuf[1] = (msg >> 16) & 0xFF;
+	msgbuf[2] = (msg >> 8) & 0xFF;
+	msgbuf[3] = msg & 0xFF;
+
+	memcpy(chkbuf, msgbuf, 4);
+
+	rc = a1026_i2c_write(msgbuf, 4);
+	if (rc < 0) {
+		pr_err("%s: error %d\n", __func__, rc);
+		a1026_i2c_sw_reset(sw_reset);
+		return rc;
+	}
+
+	/* We don't need to get Ack after sending out a suspend command */
+	if (msg == A100_msg_Sleep)
+		return rc;
+
+	retries = POLLING_RETRY_CNT;
+	while (retries--) {
+		rc = 0;
+
+		msleep(20); /* use polling */
+		memset(msgbuf, 0, sizeof(msgbuf));
+		rc = a1026_i2c_read(msgbuf, 4);
+		if (rc < 0) {
+			pr_err("%s: ack-read error %d (%d retries)\n", __func__,
+				rc, retries);
+			continue;
+		}
+
+		if (msgbuf[0] == 0x80  && msgbuf[1] == chkbuf[1]) {
+			pass = 1;
+			break;
+		} else if (msgbuf[0] == 0xff && msgbuf[1] == 0xff) {
+			pr_err("%s: illegal cmd %08x\n", __func__, msg);
+			rc = -EINVAL;
+			break;
+		} else if ( msgbuf[0] == 0x00 && msgbuf[1] == 0x00 ) {
+			pr_info("%s: not ready (%d retries)\n", __func__,
+				retries);
+			rc = -EBUSY;
+		} else {
+			pr_info("%s: cmd/ack mismatch: (%d retries left)\n",
+				__func__,
+				retries);
+#if DEBUG
+			pr_info("%s: msgbuf[0] = %x\n", __func__, msgbuf[0]);
+			pr_info("%s: msgbuf[1] = %x\n", __func__, msgbuf[1]);
+			pr_info("%s: msgbuf[2] = %x\n", __func__, msgbuf[2]);
+			pr_info("%s: msgbuf[3] = %x\n", __func__, msgbuf[3]);
+#endif
+			rc = -EBUSY;
+		}
+	}
+
+	if (!pass) {
+		pr_err("%s: failed execute cmd %08x (%d)\n", __func__,
+			msg, rc);
+		a1026_i2c_sw_reset(sw_reset);
+	}
+	return rc;
+}
+
+#if ENABLE_DIAG_IOCTLS
+static int a1026_set_mic_state(char miccase)
+{
+	int rc = 0;
+	unsigned int cmd_msg = 0;
+
+	switch (miccase) {
+	case 1: /* Mic-1 ON / Mic-2 OFF */
+		cmd_msg = 0x80260007;
+		break;
+	case 2: /* Mic-1 OFF / Mic-2 ON */
+		cmd_msg = 0x80260015;
+		break;
+	case 3: /* both ON */
+		cmd_msg = 0x80260001;
+		break;
+	case 4: /* both OFF */
+		cmd_msg = 0x80260006;
+		break;
+	default:
+		pr_info("%s: invalid input %d\n", __func__, miccase);
+		rc = -EINVAL;
+		break;
+	}
+	rc = execute_cmdmsg(cmd_msg);
+	return rc;
+}
+
+static int exe_cmd_in_file(unsigned char *incmd)
+{
+	int rc = 0;
+	int i = 0;
+	unsigned int cmd_msg = 0;
+	unsigned char tmp = 0;
+
+	for (i = 0; i < 4; i++) {
+		tmp = *(incmd + i);
+		cmd_msg |= (unsigned int)tmp;
+		if (i != 3)
+			cmd_msg = cmd_msg << 8;
+	}
+	rc = execute_cmdmsg(cmd_msg);
+	if (rc < 0)
+		pr_err("%s: cmd %08x error %d\n", __func__, cmd_msg, rc);
+	return rc;
+}
+#endif /* ENABLE_DIAG_IOCTLS */
+
+static int
+a1026_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	   unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	struct a1026img img;
+	int rc = 0;
+#if ENABLE_DIAG_IOCTLS
+	char msg[4];
+	int mic_cases = 0;
+	int mic_sel = 0;
+#endif
+	int pathid = 0;
+	unsigned int ns_state;
+
+	switch (cmd) {
+	case A1026_BOOTUP_INIT:
+		img.buf = 0;
+		img.img_size = 0;
+		if (copy_from_user(&img, argp, sizeof(img)))
+			return -EFAULT;
+		rc = a1026_bootup_init(file, &img);
+		break;
+	case A1026_SET_CONFIG:
+		if (copy_from_user(&pathid, argp, sizeof(pathid)))
+			return -EFAULT;
+		rc = a1026_set_config(pathid, A1026_CONFIG_FULL);
+		if (rc < 0)
+			pr_err("%s: A1026_SET_CONFIG (%d) error %d!\n",
+				__func__, pathid, rc);
+		break;
+	case A1026_SET_NS_STATE:
+		if (copy_from_user(&ns_state, argp, sizeof(ns_state)))
+			return -EFAULT;
+		pr_info("%s: set noise suppression %d\n", __func__, ns_state);
+		if (ns_state < 0 || ns_state >= A1026_NS_NUM_STATES)
+			return -EINVAL;
+		a1026_NS_state = ns_state;
+		if (!a1026_suspended)
+			a1026_set_config(a1026_current_config,
+					A1026_CONFIG_VP);
+		break;
+#if ENABLE_DIAG_IOCTLS
+	case A1026_SET_MIC_ONOFF:
+		rc = chk_wakeup_a1026();
+		if (rc < 0)
+			return rc;
+		if (copy_from_user(&mic_cases, argp, sizeof(mic_cases)))
+			return -EFAULT;
+		rc = a1026_set_mic_state(mic_cases);
+		if (rc < 0)
+			pr_err("%s: A1026_SET_MIC_ONOFF %d error %d!\n",
+				__func__, mic_cases, rc);
+		break;
+	case A1026_SET_MICSEL_ONOFF:
+		rc = chk_wakeup_a1026();
+		if (rc < 0)
+			return rc;
+		if (copy_from_user(&mic_sel, argp, sizeof(mic_sel)))
+			return -EFAULT;
+		gpio_set_value(pdata->gpio_a1026_micsel, !!mic_sel);
+		rc = 0;
+		break;
+	case A1026_READ_DATA:
+		rc = chk_wakeup_a1026();
+		if (rc < 0)
+			return rc;
+		rc = a1026_i2c_read(msg, 4);
+		if (copy_to_user(argp, &msg, 4))
+			return -EFAULT;
+		break;
+	case A1026_WRITE_MSG:
+		rc = chk_wakeup_a1026();
+		if (rc < 0)
+			return rc;
+		if (copy_from_user(msg, argp, sizeof(msg)))
+			return -EFAULT;
+		rc = a1026_i2c_write(msg, 4);
+		break;
+	case A1026_SYNC_CMD:
+		rc = chk_wakeup_a1026();
+		if (rc < 0)
+			return rc;
+		msg[0] = 0x80;
+		msg[1] = 0x00;
+		msg[2] = 0x00;
+		msg[3] = 0x00;
+		rc = a1026_i2c_write(msg, 4);
+		break;
+	case A1026_SET_CMD_FILE:
+		rc = chk_wakeup_a1026();
+		if (rc < 0)
+			return rc;
+		if (copy_from_user(msg, argp, sizeof(msg)))
+			return -EFAULT;
+		rc = exe_cmd_in_file(msg);
+		break;
+#endif /* ENABLE_DIAG_IOCTLS */
+	default:
+		pr_err("%s: invalid command %d\n", __func__, _IOC_NR(cmd));
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static const struct file_operations a1026_fops = {
+	.owner = THIS_MODULE,
+	.open = a1026_open,
+	.release = a1026_release,
+	.ioctl = a1026_ioctl,
+};
+
+static struct miscdevice a1026_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "audience_a1026",
+	.fops = &a1026_fops,
+};
+
+static int a1026_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int rc = 0;
+
+	pdata = client->dev.platform_data;
+
+	if (pdata == NULL) {
+		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+		if (pdata == NULL) {
+			rc = -ENOMEM;
+			pr_err("%s: platform data is NULL\n", __func__);
+			goto err_alloc_data_failed;
+		}
+	}
+
+	this_client = client;
+
+	rc = gpio_request(pdata->gpio_a1026_clk, "a1026");
+	if (rc < 0) {
+		control_a1026_clk = 0;
+		goto chk_gpio_micsel;
+	}
+	control_a1026_clk = 1;
+
+	rc = gpio_direction_output(pdata->gpio_a1026_clk, 1);
+	if (rc < 0) {
+		pr_err("%s: request clk gpio direction failed\n", __func__);
+		goto err_free_gpio_clk;
+	}
+
+chk_gpio_micsel:
+	rc = gpio_request(pdata->gpio_a1026_micsel, "a1026");
+	if (rc < 0) {
+		pr_err("%s: gpio request mic_sel pin failed\n", __func__);
+		goto err_free_gpio_micsel;
+	}
+
+	rc = gpio_direction_output(pdata->gpio_a1026_micsel, 1);
+	if (rc < 0) {
+		pr_err("%s: request mic_sel gpio direction failed\n", __func__);
+		goto err_free_gpio_micsel;
+	}
+
+	rc = gpio_request(pdata->gpio_a1026_wakeup, "a1026");
+	if (rc < 0) {
+		pr_err("%s: gpio request wakeup pin failed\n", __func__);
+		goto err_free_gpio;
+	}
+
+	rc = gpio_direction_output(pdata->gpio_a1026_wakeup, 1);
+	if (rc < 0) {
+		pr_err("%s: request wakeup gpio direction failed\n", __func__);
+		goto err_free_gpio;
+	}
+
+	rc = gpio_request(pdata->gpio_a1026_reset, "a1026");
+	if (rc < 0) {
+		pr_err("%s: gpio request reset pin failed\n", __func__);
+		goto err_free_gpio;
+	}
+
+	rc = gpio_direction_output(pdata->gpio_a1026_reset, 1);
+	if (rc < 0) {
+		pr_err("%s: request reset gpio direction failed\n", __func__);
+		goto err_free_gpio_all;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s: i2c check functionality error\n", __func__);
+		rc = -ENODEV;
+		goto err_free_gpio_all;
+	}
+
+	if (control_a1026_clk)
+		gpio_set_value(pdata->gpio_a1026_clk, 1);
+	gpio_set_value(pdata->gpio_a1026_micsel, 0);
+	gpio_set_value(pdata->gpio_a1026_wakeup, 1);
+	gpio_set_value(pdata->gpio_a1026_reset, 1);
+
+	rc = misc_register(&a1026_device);
+	if (rc) {
+		pr_err("%s: a1026_device register failed\n", __func__);
+		goto err_free_gpio_all;
+	}
+
+	return 0;
+
+err_free_gpio_all:
+	gpio_free(pdata->gpio_a1026_reset);
+err_free_gpio:
+	gpio_free(pdata->gpio_a1026_wakeup);
+err_free_gpio_micsel:
+	gpio_free(pdata->gpio_a1026_micsel);
+err_free_gpio_clk:
+	if (control_a1026_clk)
+		gpio_free(pdata->gpio_a1026_clk);
+err_alloc_data_failed:
+	return rc;
+}
+
+static int a1026_remove(struct i2c_client *client)
+{
+	struct a1026_platform_data *p1026data = i2c_get_clientdata(client);
+	kfree(p1026data);
+
+	return 0;
+}
+
+static int a1026_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	return 0;
+}
+
+static int a1026_resume(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id a1026_id[] = {
+	{ "audience_a1026", 0 },
+	{ }
+};
+
+static struct i2c_driver a1026_driver = {
+	.probe = a1026_probe,
+	.remove = a1026_remove,
+	.suspend = a1026_suspend,
+	.resume	= a1026_resume,
+	.id_table = a1026_id,
+	.driver = {
+		.name = "audience_a1026",
+	},
+};
+
+static int __init a1026_init(void)
+{
+	pr_info("%s\n", __func__);
+	mutex_init(&a1026_lock);
+
+	return i2c_add_driver(&a1026_driver);
+}
+
+static void __exit a1026_exit(void)
+{
+	i2c_del_driver(&a1026_driver);
+}
+
+module_init(a1026_init);
+module_exit(a1026_exit);
+
+MODULE_DESCRIPTION("A1026 voice processor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/akm8973.c b/drivers/misc/akm8973.c
new file mode 100644
index 0000000..723eac7
--- /dev/null
+++ b/drivers/misc/akm8973.c
@@ -0,0 +1,753 @@
+/*
+ * drivers/i2c/chips/akm8973.c - akm8973 compass driver
+ *
+ * Copyright (C) 2008-2009 HTC Corporation.
+ * Author: viral wang <viralwang@gmail.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/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <asm/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <linux/akm8973.h>
+
+#define DEBUG 0
+#define MAX_FAILURE_COUNT 3
+
+static struct i2c_client *this_client;
+
+struct akm8973_data {
+	struct input_dev *input_dev;
+	struct work_struct work;
+};
+
+/* Addresses to scan -- protected by sense_data_mutex */
+static char sense_data[RBUFF_SIZE + 1];
+static struct mutex sense_data_mutex;
+#define AKM8973_RETRY_COUNT 10
+static DECLARE_WAIT_QUEUE_HEAD(data_ready_wq);
+static DECLARE_WAIT_QUEUE_HEAD(open_wq);
+
+static atomic_t data_ready;
+static atomic_t open_count;
+static atomic_t open_flag;
+static atomic_t reserve_open_flag;
+
+static atomic_t m_flag;
+static atomic_t a_flag;
+static atomic_t t_flag;
+static atomic_t mv_flag;
+
+static int failure_count = 0;
+
+static short akmd_delay = 0;
+
+static struct akm8973_platform_data *pdata;
+
+static int AKI2C_RxData(char *rxData, int length)
+{
+	uint8_t loop_i;
+	struct i2c_msg msgs[] = {
+		{
+		 .addr = this_client->addr,
+		 .flags = 0,
+		 .len = 1,
+		 .buf = rxData,
+		 },
+		{
+		 .addr = this_client->addr,
+		 .flags = I2C_M_RD,
+		 .len = length,
+		 .buf = rxData,
+		 },
+	};
+
+	for (loop_i = 0; loop_i < AKM8973_RETRY_COUNT; loop_i++) {
+		if (i2c_transfer(this_client->adapter, msgs, 2) > 0) {
+			break;
+		}
+		mdelay(10);
+	}
+
+	if (loop_i >= AKM8973_RETRY_COUNT) {
+		printk(KERN_ERR "%s retry over %d\n", __func__, AKM8973_RETRY_COUNT);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int AKI2C_TxData(char *txData, int length)
+{
+	uint8_t loop_i;
+	struct i2c_msg msg[] = {
+		{
+		 .addr = this_client->addr,
+		 .flags = 0,
+		 .len = length,
+		 .buf = txData,
+		 },
+	};
+
+	for (loop_i = 0; loop_i < AKM8973_RETRY_COUNT; loop_i++) {
+		if (i2c_transfer(this_client->adapter, msg, 1) > 0) {
+			break;
+		}
+		mdelay(10);
+	}
+
+	if (loop_i >= AKM8973_RETRY_COUNT) {
+		printk(KERN_ERR "%s retry over %d\n", __func__, AKM8973_RETRY_COUNT);
+		return -EIO;
+	}
+	return 0;
+}
+
+static void AKECS_Reset(void)
+{
+	gpio_set_value(pdata->reset, 0);
+	udelay(120);
+	gpio_set_value(pdata->reset, 1);
+}
+
+static int AKECS_StartMeasure(void)
+{
+	char buffer[2];
+
+	atomic_set(&data_ready, 0);
+
+	/* Set measure mode */
+	buffer[0] = AKECS_REG_MS1;
+	buffer[1] = AKECS_MODE_MEASURE;
+
+	/* Set data */
+	return AKI2C_TxData(buffer, 2);
+}
+
+static int AKECS_PowerDown(void)
+{
+	char buffer[2];
+	int ret;
+
+	/* Set powerdown mode */
+	buffer[0] = AKECS_REG_MS1;
+	buffer[1] = AKECS_MODE_POWERDOWN;
+	/* Set data */
+	ret = AKI2C_TxData(buffer, 2);
+	if (ret < 0)
+		return ret;
+
+	/* Dummy read for clearing INT pin */
+	buffer[0] = AKECS_REG_TMPS;
+	/* Read data */
+	ret = AKI2C_RxData(buffer, 1);
+	if (ret < 0)
+		return ret;
+	return ret;
+}
+
+static int AKECS_StartE2PRead(void)
+{
+	char buffer[2];
+
+	/* Set measure mode */
+	buffer[0] = AKECS_REG_MS1;
+	buffer[1] = AKECS_MODE_E2P_READ;
+	/* Set data */
+	return AKI2C_TxData(buffer, 2);
+}
+
+static int AKECS_GetData(void)
+{
+	char buffer[RBUFF_SIZE + 1];
+	int ret;
+
+	memset(buffer, 0, RBUFF_SIZE + 1);
+	buffer[0] = AKECS_REG_ST;
+	ret = AKI2C_RxData(buffer, RBUFF_SIZE+1);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&sense_data_mutex);
+	memcpy(sense_data, buffer, sizeof(buffer));
+	atomic_set(&data_ready, 1);
+	wake_up(&data_ready_wq);
+	mutex_unlock(&sense_data_mutex);
+
+	return 0;
+}
+
+static int AKECS_SetMode(char mode)
+{
+	int ret;
+
+	switch (mode) {
+	case AKECS_MODE_MEASURE:
+		ret = AKECS_StartMeasure();
+		break;
+	case AKECS_MODE_E2P_READ:
+		ret = AKECS_StartE2PRead();
+		break;
+	case AKECS_MODE_POWERDOWN:
+		ret = AKECS_PowerDown();
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* wait at least 300us after changing mode */
+	mdelay(1);
+	return ret;
+}
+
+static int AKECS_TransRBuff(char *rbuf, int size)
+{
+	wait_event_interruptible_timeout(data_ready_wq,
+					 atomic_read(&data_ready), 1000);
+	if (!atomic_read(&data_ready)) {
+		/* Ignore data errors if there are no open handles */
+		if (atomic_read(&open_count) > 0) {
+			printk(KERN_ERR
+				"AKM8973 AKECS_TransRBUFF: Data not ready\n");
+			failure_count++;
+			if (failure_count >= MAX_FAILURE_COUNT) {
+				printk(KERN_ERR
+				       "AKM8973 AKECS_TransRBUFF: successive %d failure.\n",
+				       failure_count);
+				atomic_set(&open_flag, -1);
+				wake_up(&open_wq);
+				failure_count = 0;
+			}
+		}
+		return -1;
+	}
+
+	mutex_lock(&sense_data_mutex);
+	memcpy(&rbuf[1], &sense_data[1], size);
+	atomic_set(&data_ready, 0);
+	mutex_unlock(&sense_data_mutex);
+
+	failure_count = 0;
+	return 0;
+}
+
+
+static void AKECS_Report_Value(short *rbuf)
+{
+	struct akm8973_data *data = i2c_get_clientdata(this_client);
+#if DEBUG
+	printk(KERN_INFO"AKECS_Report_Value: yaw = %d, pitch = %d, roll = %d\n", rbuf[0],
+	       rbuf[1], rbuf[2]);
+	printk(KERN_INFO"                    tmp = %d, m_stat= %d, g_stat=%d\n", rbuf[3],
+	       rbuf[4], rbuf[5]);
+	printk(KERN_INFO"          G_Sensor:   x = %d LSB, y = %d LSB, z = %d LSB\n",
+	       rbuf[6], rbuf[7], rbuf[8]);
+#endif
+	/* Report magnetic sensor information */
+	if (atomic_read(&m_flag)) {
+		input_report_abs(data->input_dev, ABS_RX, rbuf[0]);
+		input_report_abs(data->input_dev, ABS_RY, rbuf[1]);
+		input_report_abs(data->input_dev, ABS_RZ, rbuf[2]);
+		input_report_abs(data->input_dev, ABS_RUDDER, rbuf[4]);
+	}
+
+	/* Report acceleration sensor information */
+	if (atomic_read(&a_flag)) {
+		input_report_abs(data->input_dev, ABS_X, rbuf[6]);
+		input_report_abs(data->input_dev, ABS_Y, rbuf[7]);
+		input_report_abs(data->input_dev, ABS_Z, rbuf[8]);
+		input_report_abs(data->input_dev, ABS_WHEEL, rbuf[5]);
+	}
+
+	/* Report temperature information */
+	if (atomic_read(&t_flag))
+		input_report_abs(data->input_dev, ABS_THROTTLE, rbuf[3]);
+
+	if (atomic_read(&mv_flag)) {
+		input_report_abs(data->input_dev, ABS_HAT0X, rbuf[9]);
+		input_report_abs(data->input_dev, ABS_HAT0Y, rbuf[10]);
+		input_report_abs(data->input_dev, ABS_BRAKE, rbuf[11]);
+	}
+
+	input_sync(data->input_dev);
+}
+
+static int AKECS_GetOpenStatus(void)
+{
+	wait_event_interruptible(open_wq, (atomic_read(&open_flag) != 0));
+	return atomic_read(&open_flag);
+}
+
+static int AKECS_GetCloseStatus(void)
+{
+	wait_event_interruptible(open_wq, (atomic_read(&open_flag) <= 0));
+	return atomic_read(&open_flag);
+}
+
+static void AKECS_CloseDone(void)
+{
+	atomic_set(&m_flag, 1);
+	atomic_set(&a_flag, 1);
+	atomic_set(&t_flag, 1);
+	atomic_set(&mv_flag, 1);
+}
+
+static int akm_aot_open(struct inode *inode, struct file *file)
+{
+	int ret = -1;
+	if (atomic_cmpxchg(&open_count, 0, 1) == 0) {
+		if (atomic_cmpxchg(&open_flag, 0, 1) == 0) {
+			atomic_set(&reserve_open_flag, 1);
+			enable_irq(this_client->irq);
+			wake_up(&open_wq);
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+static int akm_aot_release(struct inode *inode, struct file *file)
+{
+	atomic_set(&reserve_open_flag, 0);
+	atomic_set(&open_flag, 0);
+	atomic_set(&open_count, 0);
+	wake_up(&open_wq);
+	disable_irq(this_client->irq);
+	return 0;
+}
+
+static int
+akm_aot_ioctl(struct inode *inode, struct file *file,
+	      unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	short flag;
+
+	switch (cmd) {
+	case ECS_IOCTL_APP_SET_MFLAG:
+	case ECS_IOCTL_APP_SET_AFLAG:
+	case ECS_IOCTL_APP_SET_TFLAG:
+	case ECS_IOCTL_APP_SET_MVFLAG:
+		if (copy_from_user(&flag, argp, sizeof(flag)))
+			return -EFAULT;
+		if (flag < 0 || flag > 1)
+			return -EINVAL;
+		break;
+	case ECS_IOCTL_APP_SET_DELAY:
+		if (copy_from_user(&flag, argp, sizeof(flag)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	switch (cmd) {
+	case ECS_IOCTL_APP_SET_MFLAG:
+		atomic_set(&m_flag, flag);
+		break;
+	case ECS_IOCTL_APP_GET_MFLAG:
+		flag = atomic_read(&m_flag);
+		break;
+	case ECS_IOCTL_APP_SET_AFLAG:
+		atomic_set(&a_flag, flag);
+		break;
+	case ECS_IOCTL_APP_GET_AFLAG:
+		flag = atomic_read(&a_flag);
+		break;
+	case ECS_IOCTL_APP_SET_TFLAG:
+		atomic_set(&t_flag, flag);
+		break;
+	case ECS_IOCTL_APP_GET_TFLAG:
+		flag = atomic_read(&t_flag);
+		break;
+	case ECS_IOCTL_APP_SET_MVFLAG:
+		atomic_set(&mv_flag, flag);
+		break;
+	case ECS_IOCTL_APP_GET_MVFLAG:
+		flag = atomic_read(&mv_flag);
+		break;
+	case ECS_IOCTL_APP_SET_DELAY:
+		akmd_delay = flag;
+		break;
+	case ECS_IOCTL_APP_GET_DELAY:
+		flag = akmd_delay;
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	switch (cmd) {
+	case ECS_IOCTL_APP_GET_MFLAG:
+	case ECS_IOCTL_APP_GET_AFLAG:
+	case ECS_IOCTL_APP_GET_TFLAG:
+	case ECS_IOCTL_APP_GET_MVFLAG:
+	case ECS_IOCTL_APP_GET_DELAY:
+		if (copy_to_user(argp, &flag, sizeof(flag)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int akmd_open(struct inode *inode, struct file *file)
+{
+	return nonseekable_open(inode, file);
+}
+
+static int akmd_release(struct inode *inode, struct file *file)
+{
+	AKECS_CloseDone();
+	return 0;
+}
+
+static int
+akmd_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	   unsigned long arg)
+{
+
+	void __user *argp = (void __user *)arg;
+
+	char msg[RBUFF_SIZE + 1], rwbuf[5];
+	int ret = -1, status;
+	short mode, value[12], delay;
+	char project_name[64];
+	short layouts[4][3][3];
+	int i, j, k;
+
+
+	switch (cmd) {
+	case ECS_IOCTL_WRITE:
+	case ECS_IOCTL_READ:
+		if (copy_from_user(&rwbuf, argp, sizeof(rwbuf)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_SET_MODE:
+		if (copy_from_user(&mode, argp, sizeof(mode)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_SET_YPR:
+		if (copy_from_user(&value, argp, sizeof(value)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	switch (cmd) {
+	case ECS_IOCTL_WRITE:
+		if (rwbuf[0] < 2)
+			return -EINVAL;
+		ret = AKI2C_TxData(&rwbuf[1], rwbuf[0]);
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_READ:
+		if (rwbuf[0] < 1)
+			return -EINVAL;
+		ret = AKI2C_RxData(&rwbuf[1], rwbuf[0]);
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_RESET:
+		AKECS_Reset();
+		break;
+	case ECS_IOCTL_SET_MODE:
+		ret = AKECS_SetMode((char)mode);
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_GETDATA:
+		ret = AKECS_TransRBuff(msg, RBUFF_SIZE);
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_SET_YPR:
+		AKECS_Report_Value(value);
+		break;
+	case ECS_IOCTL_GET_OPEN_STATUS:
+		status = AKECS_GetOpenStatus();
+		break;
+	case ECS_IOCTL_GET_CLOSE_STATUS:
+		status = AKECS_GetCloseStatus();
+		break;
+	case ECS_IOCTL_GET_DELAY:
+		delay = akmd_delay;
+		break;
+	case ECS_IOCTL_GET_PROJECT_NAME:
+		strncpy(project_name, pdata->project_name, 64);
+		break;
+	case ECS_IOCTL_GET_MATRIX:
+		for (i = 0; i < 4; i++)
+			for (j = 0; j < 3; j++)
+				for (k = 0; k < 3; k++) {
+				layouts[i][j][k] = pdata->layouts[i][j][k];
+				}
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	switch (cmd) {
+	case ECS_IOCTL_READ:
+		if (copy_to_user(argp, &rwbuf, sizeof(rwbuf)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_GETDATA:
+		if (copy_to_user(argp, &msg, sizeof(msg)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_GET_OPEN_STATUS:
+	case ECS_IOCTL_GET_CLOSE_STATUS:
+		if (copy_to_user(argp, &status, sizeof(status)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_GET_DELAY:
+		if (copy_to_user(argp, &delay, sizeof(delay)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_GET_PROJECT_NAME:
+		if (copy_to_user(argp, project_name, sizeof(project_name)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_GET_MATRIX:
+		if (copy_to_user(argp, layouts, sizeof(layouts)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void akm_work_func(struct work_struct *work)
+{
+	if (AKECS_GetData() < 0)
+		printk(KERN_ERR "AKM8973 akm_work_func: Get data failed\n");
+	enable_irq(this_client->irq);
+}
+
+static irqreturn_t akm8973_interrupt(int irq, void *dev_id)
+{
+	struct akm8973_data *data = dev_id;
+	disable_irq_nosync(this_client->irq);
+	schedule_work(&data->work);
+	return IRQ_HANDLED;
+}
+
+static struct file_operations akmd_fops = {
+	.owner = THIS_MODULE,
+	.open = akmd_open,
+	.release = akmd_release,
+	.ioctl = akmd_ioctl,
+};
+
+static struct file_operations akm_aot_fops = {
+	.owner = THIS_MODULE,
+	.open = akm_aot_open,
+	.release = akm_aot_release,
+	.ioctl = akm_aot_ioctl,
+};
+
+
+static struct miscdevice akm_aot_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "akm8973_aot",
+	.fops = &akm_aot_fops,
+};
+
+
+static struct miscdevice akmd_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "akm8973_daemon",
+	.fops = &akmd_fops,
+};
+
+int akm8973_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct akm8973_data *akm;
+	int err = 0;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		err = -ENODEV;
+		goto exit_check_functionality_failed;
+	}
+
+	akm = kzalloc(sizeof(struct akm8973_data), GFP_KERNEL);
+	if (!akm) {
+		err = -ENOMEM;
+		goto exit_alloc_data_failed;
+	}
+
+	INIT_WORK(&akm->work, akm_work_func);
+	i2c_set_clientdata(client, akm);
+
+	pdata = client->dev.platform_data;
+	if (pdata == NULL) {
+		printk(KERN_ERR"AKM8973 akm8973_probe: platform data is NULL\n");
+		goto exit_platform_data_null;
+	}
+	this_client = client;
+
+	err = AKECS_PowerDown();
+	if (err < 0) {
+		printk(KERN_ERR"AKM8973 akm8973_probe: set power down mode error\n");
+		goto exit_set_mode_failed;
+	}
+
+	err = request_irq(client->irq, akm8973_interrupt, IRQF_TRIGGER_HIGH,
+			  "akm8973", akm);
+	disable_irq(this_client->irq);
+
+	if (err < 0) {
+		printk(KERN_ERR"AKM8973 akm8973_probe: request irq failed\n");
+		goto exit_irq_request_failed;
+	}
+
+	akm->input_dev = input_allocate_device();
+
+	if (!akm->input_dev) {
+		err = -ENOMEM;
+		printk(KERN_ERR
+		       "AKM8973 akm8973_probe: Failed to allocate input device\n");
+		goto exit_input_dev_alloc_failed;
+	}
+
+	set_bit(EV_ABS, akm->input_dev->evbit);
+	/* yaw */
+	input_set_abs_params(akm->input_dev, ABS_RX, 0, 360, 0, 0);
+	/* pitch */
+	input_set_abs_params(akm->input_dev, ABS_RY, -180, 180, 0, 0);
+	/* roll */
+	input_set_abs_params(akm->input_dev, ABS_RZ, -90, 90, 0, 0);
+	/* x-axis acceleration */
+	input_set_abs_params(akm->input_dev, ABS_X, -1872, 1872, 0, 0);
+	/* y-axis acceleration */
+	input_set_abs_params(akm->input_dev, ABS_Y, -1872, 1872, 0, 0);
+	/* z-axis acceleration */
+	input_set_abs_params(akm->input_dev, ABS_Z, -1872, 1872, 0, 0);
+	/* temparature */
+	input_set_abs_params(akm->input_dev, ABS_THROTTLE, -30, 85, 0, 0);
+	/* status of magnetic sensor */
+	input_set_abs_params(akm->input_dev, ABS_RUDDER, -32768, 3, 0, 0);
+	/* status of acceleration sensor */
+	input_set_abs_params(akm->input_dev, ABS_WHEEL, -32768, 3, 0, 0);
+	/* step count */
+	input_set_abs_params(akm->input_dev, ABS_GAS, 0, 65535, 0, 0);
+	/* x-axis of raw magnetic vector */
+	input_set_abs_params(akm->input_dev, ABS_HAT0X, -2048, 2032, 0, 0);
+	/* y-axis of raw magnetic vector */
+	input_set_abs_params(akm->input_dev, ABS_HAT0Y, -2048, 2032, 0, 0);
+	/* z-axis of raw magnetic vector */
+	input_set_abs_params(akm->input_dev, ABS_BRAKE, -2048, 2032, 0, 0);
+
+	akm->input_dev->name = "compass";
+
+	err = input_register_device(akm->input_dev);
+
+	if (err) {
+		printk(KERN_ERR
+		       "AKM8973 akm8973_probe: Unable to register input device: %s\n",
+		       akm->input_dev->name);
+		goto exit_input_register_device_failed;
+	}
+
+	err = misc_register(&akmd_device);
+	if (err) {
+		printk(KERN_ERR "AKM8973 akm8973_probe: akmd_device register failed\n");
+		goto exit_misc_device_register_failed;
+	}
+
+	err = misc_register(&akm_aot_device);
+	if (err) {
+		printk(KERN_ERR
+		       "AKM8973 akm8973_probe: akm_aot_device register failed\n");
+		goto exit_misc_device_register_failed;
+	}
+
+	mutex_init(&sense_data_mutex);
+
+	init_waitqueue_head(&data_ready_wq);
+	init_waitqueue_head(&open_wq);
+
+	/* As default, report all information */
+	atomic_set(&m_flag, 1);
+	atomic_set(&a_flag, 1);
+	atomic_set(&t_flag, 1);
+	atomic_set(&mv_flag, 1);
+
+	return 0;
+
+exit_misc_device_register_failed:
+exit_input_register_device_failed:
+	input_free_device(akm->input_dev);
+exit_input_dev_alloc_failed:
+	free_irq(client->irq, akm);
+exit_irq_request_failed:
+exit_set_mode_failed:
+exit_platform_data_null:
+	kfree(akm);
+exit_alloc_data_failed:
+exit_check_functionality_failed:
+	return err;
+
+}
+
+static int akm8973_remove(struct i2c_client *client)
+{
+	struct akm8973_data *akm = i2c_get_clientdata(client);
+	free_irq(client->irq, akm);
+	input_unregister_device(akm->input_dev);
+	kfree(akm);
+	return 0;
+}
+static const struct i2c_device_id akm8973_id[] = {
+	{ AKM8973_I2C_NAME, 0 },
+	{ }
+};
+
+static struct i2c_driver akm8973_driver = {
+	.probe 	= akm8973_probe,
+	.remove 	= akm8973_remove,
+	.id_table	= akm8973_id,
+	.driver = {
+		   .name = AKM8973_I2C_NAME,
+		   },
+};
+
+static int __init akm8973_init(void)
+{
+	printk(KERN_INFO "AKM8973 compass driver: init\n");
+	return i2c_add_driver(&akm8973_driver);
+}
+
+static void __exit akm8973_exit(void)
+{
+	i2c_del_driver(&akm8973_driver);
+}
+
+module_init(akm8973_init);
+module_exit(akm8973_exit);
+
+MODULE_AUTHOR("viral wang <viral_wang@htc.com>");
+MODULE_DESCRIPTION("AKM8973 compass driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/akm8976.c b/drivers/misc/akm8976.c
new file mode 100644
index 0000000..ee99ae8
--- /dev/null
+++ b/drivers/misc/akm8976.c
@@ -0,0 +1,1132 @@
+/* drivers/i2c/chips/akm8976.c - akm8976 compass driver
+ *
+ * Copyright (C) 2007-2008 HTC Corporation.
+ * Author: Hou-Kun Chen <houkun.chen@gmail.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/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <linux/akm8976.h>
+
+#define DEBUG 0
+#define MAX_FAILURE_COUNT 10
+
+static struct i2c_client *this_client;
+
+struct akm8976_data {
+	struct input_dev *input_dev;
+	struct work_struct work;
+};
+
+/* Addresses to scan -- protected by sense_data_mutex */
+static char sense_data[RBUFF_SIZE + 1];
+static struct mutex sense_data_mutex;
+
+static DECLARE_WAIT_QUEUE_HEAD(data_ready_wq);
+static DECLARE_WAIT_QUEUE_HEAD(open_wq);
+
+static char cspec_num;
+static atomic_t cspec_frq;
+
+static atomic_t data_ready;
+static atomic_t open_count;
+static atomic_t open_flag;
+static atomic_t reserve_open_flag;
+
+static atomic_t m_flag;
+static atomic_t a_flag;
+static atomic_t t_flag;
+static atomic_t mv_flag;
+
+static int pffd_mode = 0;
+static int failure_count = 0;
+
+static short akmd_delay = 0;
+
+static atomic_t suspend_flag = ATOMIC_INIT(0);
+
+static struct akm8976_platform_data *pdata;
+static int revision = -1;
+/* AKM HW info */
+static ssize_t gsensor_vendor_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+
+	sprintf(buf, "AK8976A_%#x\n", revision);
+	ret = strlen(buf) + 1;
+
+	return ret;
+}
+
+static DEVICE_ATTR(vendor, 0444, gsensor_vendor_show, NULL);
+
+static struct kobject *android_gsensor_kobj;
+
+static int gsensor_sysfs_init(void)
+{
+	int ret ;
+
+	android_gsensor_kobj = kobject_create_and_add("android_gsensor", NULL);
+	if (android_gsensor_kobj == NULL) {
+		printk(KERN_ERR
+		       "AKM8976 gsensor_sysfs_init:"\
+		       "subsystem_register failed\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = sysfs_create_file(android_gsensor_kobj, &dev_attr_vendor.attr);
+	if (ret) {
+		printk(KERN_ERR
+		       "AKM8976 gsensor_sysfs_init:"\
+		       "sysfs_create_group failed\n");
+		goto err4;
+	}
+
+	return 0 ;
+err4:
+	kobject_del(android_gsensor_kobj);
+err:
+	return ret ;
+}
+
+/* following are the sysfs callback functions */
+
+#define config_ctrl_reg(name,address) \
+static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
+			   char *buf) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+        return sprintf(buf, "%u\n", i2c_smbus_read_byte_data(client,address)); \
+} \
+static ssize_t name##_store(struct device *dev, struct device_attribute *attr, \
+			    const char *buf,size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	unsigned long val = simple_strtoul(buf, NULL, 10); \
+	if (val > 0xff) \
+		return -EINVAL; \
+	i2c_smbus_write_byte_data(client,address, val); \
+        return count; \
+} \
+static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, name##_show, name##_store)
+
+config_ctrl_reg(ms1, AKECS_REG_MS1);
+config_ctrl_reg(ms2, AKECS_REG_MS2);
+config_ctrl_reg(ms3, AKECS_REG_MS3);
+
+static int AKI2C_RxData(char *rxData, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+		 .addr = this_client->addr,
+		 .flags = 0,
+		 .len = 1,
+		 .buf = rxData,
+		 },
+		{
+		 .addr = this_client->addr,
+		 .flags = I2C_M_RD,
+		 .len = length,
+		 .buf = rxData,
+		 },
+	};
+
+	if (i2c_transfer(this_client->adapter, msgs, 2) < 0) {
+		printk(KERN_ERR "AKM8976 AKI2C_RxData: transfer error\n");
+		return -EIO;
+	} else
+		return 0;
+}
+
+static int AKI2C_TxData(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) {
+		printk(KERN_ERR "AKM8976 AKI2C_TxData: transfer error\n");
+		return -EIO;
+	} else
+		return 0;
+}
+
+static int AKECS_Init(void)
+{
+	char buffer[4];
+
+	cspec_num = CSPEC_SEQ_NUM;
+	atomic_set(&cspec_frq, CSPEC_SFRQ_32);
+
+	/* Prepare data */
+	buffer[0] = AKECS_REG_MS2;
+	buffer[1] = ((CSPEC_AINT << 7) |
+		     (cspec_num << 5) |
+		     (atomic_read(&cspec_frq) << 4) |
+		     (CSPEC_MCS << 1) | (CSPEC_MKS));
+	buffer[2] = (CSPEC_INTEN << 2);
+
+	return AKI2C_TxData(buffer, 3);
+}
+
+static void AKECS_Reset(void)
+{
+	gpio_set_value(pdata->reset, 0);
+	udelay(120);
+	gpio_set_value(pdata->reset, 1);
+}
+
+static int AKECS_StartMeasure(void)
+{
+	char buffer[2];
+	int ret;
+
+	buffer[0] = AKECS_REG_MS2;
+	buffer[1] = ((CSPEC_AINT << 7) |
+		     (cspec_num << 5) |
+		     (atomic_read(&cspec_frq) << 4) |
+		     (CSPEC_MCS << 1) | (CSPEC_MKS));
+
+	/* Set data */
+	ret = AKI2C_TxData(buffer, 2);
+	if (ret < 0)
+		return ret;
+
+	/* Set measure mode */
+	buffer[0] = AKECS_REG_MS1;
+	buffer[1] = AKECS_MODE_MEASURE;
+
+	/* Set data */
+	return AKI2C_TxData(buffer, 2);
+}
+
+static int AKECS_StartPFFD(void)
+{
+	char buffer[2];
+	int ret;
+
+	/* Set PFFD mode */
+	buffer[0] = AKECS_REG_MS1;
+	buffer[1] = AKECS_MODE_PFFD;
+	/* Set data */
+	ret = AKI2C_TxData(buffer, 2);
+	if (ret < 0)
+		return ret;
+
+	ret = gpio_direction_output(pdata->clk_on, 1);
+	if (ret < 0)
+		return ret;
+
+	pffd_mode = 1;
+	return ret;
+}
+
+static int AKECS_PowerDown(void)
+{
+	char buffer[2];
+	int ret;
+
+	/* Set powerdown mode */
+	buffer[0] = AKECS_REG_MS1;
+	buffer[1] = AKECS_MODE_POWERDOWN;
+	/* Set data */
+	ret = AKI2C_TxData(buffer, 2);
+	if (ret < 0)
+		return ret;
+
+	/* Dummy read for clearing INT pin */
+	buffer[0] = AKECS_REG_TMPS;
+	/* Read data */
+	ret = AKI2C_RxData(buffer, 1);
+	if (ret < 0)
+		return ret;
+
+	if (pffd_mode == 1) {
+		pffd_mode = 0;
+		ret = gpio_direction_output(pdata->clk_on, 0);
+	}
+	return ret;
+}
+
+static int AKECS_StartE2PRead(void)
+{
+	char buffer[2];
+
+	/* Set measure mode */
+	buffer[0] = AKECS_REG_MS1;
+	buffer[1] = AKECS_MODE_E2P_READ;
+	/* Set data */
+	return AKI2C_TxData(buffer, 2);
+}
+
+static int AKECS_GetData(void)
+{
+	char buffer[RBUFF_SIZE + 1];
+	int ret;
+
+	memset(buffer, 0, RBUFF_SIZE + 1);
+	buffer[0] = AKECS_REG_ST;
+	ret = AKI2C_RxData(buffer, 32);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&sense_data_mutex);
+	memcpy(sense_data, buffer, sizeof(buffer));
+	atomic_set(&data_ready, 1);
+	wake_up(&data_ready_wq);
+	mutex_unlock(&sense_data_mutex);
+
+	return 0;
+}
+
+static int AKECS_SetMode(char mode)
+{
+	int ret, status;
+	char buffer[1];
+
+	if (mode == AKECS_MODE_MEASURE_SNG) {
+		/* Check INT pin before mode setting */
+		status = gpio_get_value(pdata->intr);
+		if (status) {
+			printk(KERN_INFO
+			       "AKM8976 AKECS_SetMode:"\
+			       "dummy read to reset INT pin \n");
+			buffer[0] = AKECS_REG_TMPS;
+			ret = AKI2C_RxData(buffer, 1);
+			if (ret < 0)
+				return ret;
+			status = gpio_get_value(pdata->intr);
+			printk(KERN_INFO
+			       "AKM8976 AKECS_SetMode:"\
+			       "after dummy read, status = %d \n",
+			       status);
+		}
+	}
+
+	switch (mode) {
+	case AKECS_MODE_MEASURE_SNG:
+		cspec_num = CSPEC_SNG_NUM;
+		ret = AKECS_StartMeasure();
+		break;
+	case AKECS_MODE_MEASURE_SEQ:
+		cspec_num = CSPEC_SEQ_NUM;
+		ret = AKECS_StartMeasure();
+		break;
+	case AKECS_MODE_PFFD:
+		ret = AKECS_StartPFFD();
+		break;
+	case AKECS_MODE_E2P_READ:
+		ret = AKECS_StartE2PRead();
+		break;
+	case AKECS_MODE_POWERDOWN:
+		ret = AKECS_PowerDown();
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* wait at least 300us after changing mode */
+	msleep(1);
+	return ret;
+}
+
+static int AKECS_TransRBuff(char *rbuf, int size)
+{
+	wait_event_interruptible_timeout(data_ready_wq,
+					 atomic_read(&data_ready), 1000);
+
+	if (!atomic_read(&data_ready)) {
+		if (!atomic_read(&suspend_flag)) {
+			printk(KERN_ERR
+			       "AKM8976 AKECS_TransRBUFF: Data not ready\n");
+			failure_count++;
+			if (failure_count >= MAX_FAILURE_COUNT) {
+				printk(KERN_ERR
+				       "AKM8976 AKECS_TransRBUFF:"\
+				       "successive %d failure.\n",
+				       failure_count);
+				atomic_set(&open_flag, -1);
+				wake_up(&open_wq);
+				failure_count = 0;
+			}
+		}
+		return -1;
+	}
+
+	if ((sense_data[0] & 0x02) == 0x02) {
+		printk(KERN_ERR "AKM8976 AKECS_TransRBUFF: Data error\n");
+		return -1;
+	}
+
+	mutex_lock(&sense_data_mutex);
+	memcpy(&rbuf[1], &sense_data[1], size);
+	atomic_set(&data_ready, 0);
+	mutex_unlock(&sense_data_mutex);
+
+
+	failure_count = 0;
+	return 0;
+}
+
+static int AKECS_Set_PERST(void)
+{
+	char buffer[2];
+
+	buffer[0] = AKECS_REG_MS3;
+	buffer[1] = ((CSPEC_INTEN << 2) | 0x01);
+
+	/* Set data */
+	return AKI2C_TxData(buffer, 2);
+}
+
+static int AKECS_Set_G0RST(void)
+{
+	char buffer[2];
+
+	buffer[0] = AKECS_REG_MS3;
+	buffer[1] = ((CSPEC_INTEN << 2) | 0x02);
+
+	/* Set data */
+	return AKI2C_TxData(buffer, 2);
+}
+
+static void AKECS_Report_Value(short *rbuf)
+{
+	struct akm8976_data *data = i2c_get_clientdata(this_client);
+#if DEBUG
+	printk(KERN_INFO
+	       "AKECS_Report_Value: yaw = %d, pitch = %d, roll = %d\n",
+	       rbuf[0], rbuf[1], rbuf[2]);
+	printk(KERN_INFO
+	       "                    tmp = %d, m_stat= %d, g_stat=%d\n",
+	       rbuf[3], rbuf[4], rbuf[5]);
+	printk(KERN_INFO
+	       "          G_Sensor:   x = %d LSB, y = %d LSB, z = %d LSB\n",
+	       rbuf[6], rbuf[7], rbuf[8]);
+#endif
+	/* Report magnetic sensor information */
+	if (atomic_read(&m_flag)) {
+		input_report_abs(data->input_dev, ABS_RX, rbuf[0]);
+		input_report_abs(data->input_dev, ABS_RY, rbuf[1]);
+		input_report_abs(data->input_dev, ABS_RZ, rbuf[2]);
+		input_report_abs(data->input_dev, ABS_RUDDER, rbuf[4]);
+	}
+
+	/* Report acceleration sensor information */
+	if (atomic_read(&a_flag)) {
+		input_report_abs(data->input_dev, ABS_X, rbuf[6]);
+		input_report_abs(data->input_dev, ABS_Y, rbuf[7]);
+		input_report_abs(data->input_dev, ABS_Z, rbuf[8]);
+		input_report_abs(data->input_dev, ABS_WHEEL, rbuf[5]);
+	}
+
+	/* Report temperature information */
+	if (atomic_read(&t_flag)) {
+		input_report_abs(data->input_dev, ABS_THROTTLE, rbuf[3]);
+	}
+
+	if (atomic_read(&mv_flag)) {
+		input_report_abs(data->input_dev, ABS_HAT0X, rbuf[9]);
+		input_report_abs(data->input_dev, ABS_HAT0Y, rbuf[10]);
+		input_report_abs(data->input_dev, ABS_BRAKE, rbuf[11]);
+	}
+
+	input_sync(data->input_dev);
+}
+
+static void AKECS_Report_StepCount(short count)
+{
+	struct akm8976_data *data = i2c_get_clientdata(this_client);
+#if DEBUG
+	printk(KERN_INFO"AKECS_Report_StepCount: %d \n", count);
+#endif
+
+	/* Report pedometer information */
+	input_report_abs(data->input_dev, ABS_GAS, count);
+	input_sync(data->input_dev);
+}
+
+static int AKECS_GetOpenStatus(void)
+{
+	wait_event_interruptible(open_wq, (atomic_read(&open_flag) != 0));
+	return atomic_read(&open_flag);
+}
+
+static int AKECS_GetCloseStatus(void)
+{
+	wait_event_interruptible(open_wq, (atomic_read(&open_flag) <= 0));
+	return atomic_read(&open_flag);
+}
+
+static void AKECS_CloseDone(void)
+{
+	atomic_set(&m_flag, 1);
+	atomic_set(&a_flag, 1);
+	atomic_set(&t_flag, 1);
+	atomic_set(&mv_flag, 1);
+}
+
+static int akm_aot_open(struct inode *inode, struct file *file)
+{
+	int ret = -1;
+	if (atomic_cmpxchg(&open_count, 0, 1) == 0) {
+		if (atomic_cmpxchg(&open_flag, 0, 1) == 0) {
+			atomic_set(&reserve_open_flag, 1);
+			wake_up(&open_wq);
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+static int akm_aot_release(struct inode *inode, struct file *file)
+{
+	atomic_set(&reserve_open_flag, 0);
+	atomic_set(&open_flag, 0);
+	atomic_set(&open_count, 0);
+	wake_up(&open_wq);
+	return 0;
+}
+
+static int
+akm_aot_ioctl(struct inode *inode, struct file *file,
+	      unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	short flag;
+
+	switch (cmd) {
+	case ECS_IOCTL_APP_SET_MFLAG:
+	case ECS_IOCTL_APP_SET_AFLAG:
+	case ECS_IOCTL_APP_SET_TFLAG:
+	case ECS_IOCTL_APP_SET_MVFLAG:
+		if (copy_from_user(&flag, argp, sizeof(flag)))
+			return -EFAULT;
+		if (flag < 0 || flag > 1)
+			return -EINVAL;
+		break;
+	case ECS_IOCTL_APP_SET_DELAY:
+		if (copy_from_user(&flag, argp, sizeof(flag)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	switch (cmd) {
+	case ECS_IOCTL_APP_SET_MFLAG:
+		atomic_set(&m_flag, flag);
+		break;
+	case ECS_IOCTL_APP_GET_MFLAG:
+		flag = atomic_read(&m_flag);
+		break;
+	case ECS_IOCTL_APP_SET_AFLAG:
+		atomic_set(&a_flag, flag);
+		break;
+	case ECS_IOCTL_APP_GET_AFLAG:
+		flag = atomic_read(&a_flag);
+		break;
+	case ECS_IOCTL_APP_SET_TFLAG:
+		atomic_set(&t_flag, flag);
+		break;
+	case ECS_IOCTL_APP_GET_TFLAG:
+		flag = atomic_read(&t_flag);
+		break;
+	case ECS_IOCTL_APP_SET_MVFLAG:
+		atomic_set(&mv_flag, flag);
+		break;
+	case ECS_IOCTL_APP_GET_MVFLAG:
+		flag = atomic_read(&mv_flag);
+		break;
+	case ECS_IOCTL_APP_SET_DELAY:
+		akmd_delay = flag;
+		break;
+	case ECS_IOCTL_APP_GET_DELAY:
+		flag = akmd_delay;
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	switch (cmd) {
+	case ECS_IOCTL_APP_GET_MFLAG:
+	case ECS_IOCTL_APP_GET_AFLAG:
+	case ECS_IOCTL_APP_GET_TFLAG:
+	case ECS_IOCTL_APP_GET_MVFLAG:
+	case ECS_IOCTL_APP_GET_DELAY:
+		if (copy_to_user(argp, &flag, sizeof(flag)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int akm_pffd_open(struct inode *inode, struct file *file)
+{
+	int ret = -1;
+	if (atomic_cmpxchg(&open_count, 0, 1) == 0) {
+		if (atomic_cmpxchg(&open_flag, 0, 2) == 0) {
+			atomic_set(&reserve_open_flag, 2);
+			wake_up(&open_wq);
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+static int akm_pffd_release(struct inode *inode, struct file *file)
+{
+	atomic_set(&reserve_open_flag, 0);
+	atomic_set(&open_flag, 0);
+	atomic_set(&open_count, 0);
+	wake_up(&open_wq);
+	return 0;
+}
+
+static int
+akm_pffd_ioctl(struct inode *inode, struct file *file,
+	       unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	short flag;
+	int ret;
+
+	switch (cmd) {
+	case ECS_IOCTL_APP_SET_DELAY:
+		if (copy_from_user(&flag, argp, sizeof(flag)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	switch (cmd) {
+	case ECS_IOCTL_APP_RESET_PEDOMETER:
+		ret = AKECS_Set_PERST();
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_APP_SET_DELAY:
+		akmd_delay = flag;
+		break;
+	case ECS_IOCTL_APP_GET_DELAY:
+		flag = akmd_delay;
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	switch (cmd) {
+	case ECS_IOCTL_APP_GET_DELAY:
+		if (copy_to_user(argp, &flag, sizeof(flag)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int akmd_open(struct inode *inode, struct file *file)
+{
+	return nonseekable_open(inode, file);
+}
+
+static int akmd_release(struct inode *inode, struct file *file)
+{
+	AKECS_CloseDone();
+	return 0;
+}
+
+static int
+akmd_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	   unsigned long arg)
+{
+
+	void __user *argp = (void __user *)arg;
+
+	char msg[RBUFF_SIZE + 1], rwbuf[5], numfrq[2];
+	int ret = -1, status;
+	short mode, value[12], step_count, delay;
+	char *pbuffer = 0;
+
+	switch (cmd) {
+	case ECS_IOCTL_READ:
+	case ECS_IOCTL_WRITE:
+		if (copy_from_user(&rwbuf, argp, sizeof(rwbuf)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_SET_MODE:
+		if (copy_from_user(&mode, argp, sizeof(mode)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_SET_YPR:
+		if (copy_from_user(&value, argp, sizeof(value)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_SET_STEP_CNT:
+		if (copy_from_user(&step_count, argp, sizeof(step_count)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	switch (cmd) {
+	case ECS_IOCTL_INIT:
+		ret = AKECS_Init();
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_RESET:
+		AKECS_Reset();
+		break;
+	case ECS_IOCTL_READ:
+		if (rwbuf[0] < 1)
+			return -EINVAL;
+		ret = AKI2C_RxData(&rwbuf[1], rwbuf[0]);
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_WRITE:
+		if (rwbuf[0] < 2)
+			return -EINVAL;
+		ret = AKI2C_TxData(&rwbuf[1], rwbuf[0]);
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_SET_MODE:
+		ret = AKECS_SetMode((char)mode);
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_GETDATA:
+		ret = AKECS_TransRBuff(msg, RBUFF_SIZE);
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_GET_NUMFRQ:
+		numfrq[0] = cspec_num;
+		numfrq[1] = atomic_read(&cspec_frq);
+		break;
+	case ECS_IOCTL_SET_PERST:
+		ret = AKECS_Set_PERST();
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_SET_G0RST:
+		ret = AKECS_Set_G0RST();
+		if (ret < 0)
+			return ret;
+		break;
+	case ECS_IOCTL_SET_YPR:
+		AKECS_Report_Value(value);
+		break;
+	case ECS_IOCTL_GET_OPEN_STATUS:
+		status = AKECS_GetOpenStatus();
+		break;
+	case ECS_IOCTL_GET_CLOSE_STATUS:
+		status = AKECS_GetCloseStatus();
+		break;
+	case ECS_IOCTL_SET_STEP_CNT:
+		AKECS_Report_StepCount(step_count);
+		break;
+	case ECS_IOCTL_GET_CALI_DATA:
+		pbuffer = get_akm_cal_ram();
+		break;
+	case ECS_IOCTL_GET_DELAY:
+		delay = akmd_delay;
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	switch (cmd) {
+	case ECS_IOCTL_READ:
+		if (copy_to_user(argp, &rwbuf, sizeof(rwbuf)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_GETDATA:
+		if (copy_to_user(argp, &msg, sizeof(msg)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_GET_NUMFRQ:
+		if (copy_to_user(argp, &numfrq, sizeof(numfrq)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_GET_OPEN_STATUS:
+	case ECS_IOCTL_GET_CLOSE_STATUS:
+		if (copy_to_user(argp, &status, sizeof(status)))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_GET_CALI_DATA:
+		if (copy_to_user(argp, pbuffer, MAX_CALI_SIZE))
+			return -EFAULT;
+		break;
+	case ECS_IOCTL_GET_DELAY:
+		if (copy_to_user(argp, &delay, sizeof(delay)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void akm_work_func(struct work_struct *work)
+{
+	if (AKECS_GetData() < 0)
+		printk(KERN_ERR "AKM8976 akm_work_func: Get data failed\n");
+	enable_irq(this_client->irq);
+}
+
+static irqreturn_t akm8976_interrupt(int irq, void *dev_id)
+{
+	struct akm8976_data *data = dev_id;
+	disable_irq_nosync(this_client->irq);
+	schedule_work(&data->work);
+	return IRQ_HANDLED;
+}
+
+static int akm8976_init_client(struct i2c_client *client)
+{
+	struct akm8976_data *data;
+	int ret;
+
+	data = i2c_get_clientdata(client);
+
+	mutex_init(&sense_data_mutex);
+
+	ret = request_irq(client->irq, akm8976_interrupt, IRQF_TRIGGER_HIGH,
+			  "akm8976", data);
+
+	if (ret < 0) {
+		printk(KERN_ERR "akm8976_init_client: request irq failed\n");
+		goto err;
+	}
+
+	pdata = client->dev.platform_data;
+	if (pdata == NULL) {
+		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+		if (pdata == NULL) {
+			ret = -ENOMEM;
+			goto err_alloc_data_failed;
+		} else {
+			pdata->reset = ECS_RST;
+			pdata->clk_on = ECS_CLK_ON;
+			pdata->intr = ECS_INTR;
+		}
+	}
+
+	ret = gpio_request(pdata->reset, "akm8976");
+	if (ret < 0) {
+		printk(KERN_ERR
+		       "akm8976_init_client: request reset gpio failed\n");
+		goto err_free_irq;
+	}
+	ret = gpio_direction_output(pdata->reset, 1);
+	if (ret < 0) {
+		printk(KERN_ERR
+		       "akm8976_init_client: request reset gpio failed\n");
+		goto err_free_gpio;
+	}
+
+	ret = gpio_request(pdata->clk_on, "akm8976");
+	if (ret < 0) {
+		printk(KERN_ERR
+		       "akm8976_init_client: request clock gpio failed\n");
+		goto err_free_gpio;
+	}
+
+	ret = gpio_direction_output(pdata->clk_on, 0);
+	if (ret < 0) {
+		printk(KERN_ERR
+		       "akm8976_init_client: request clock gpio failed\n");
+		goto err_free_gpio_2;
+	}
+
+	init_waitqueue_head(&data_ready_wq);
+	init_waitqueue_head(&open_wq);
+
+	/* As default, report all information */
+	atomic_set(&m_flag, 1);
+	atomic_set(&a_flag, 1);
+	atomic_set(&t_flag, 1);
+	atomic_set(&mv_flag, 1);
+
+	return 0;
+
+err_free_gpio_2:
+	gpio_free(pdata->clk_on);
+err_free_gpio:
+	gpio_free(pdata->reset);
+err_free_irq:
+	free_irq(client->irq, 0);
+err_alloc_data_failed:
+err:
+	return ret;
+}
+
+static struct file_operations akmd_fops = {
+	.owner = THIS_MODULE,
+	.open = akmd_open,
+	.release = akmd_release,
+	.ioctl = akmd_ioctl,
+};
+
+static struct file_operations akm_aot_fops = {
+	.owner = THIS_MODULE,
+	.open = akm_aot_open,
+	.release = akm_aot_release,
+	.ioctl = akm_aot_ioctl,
+};
+
+static struct file_operations akm_pffd_fops = {
+	.owner = THIS_MODULE,
+	.open = akm_pffd_open,
+	.release = akm_pffd_release,
+	.ioctl = akm_pffd_ioctl,
+};
+
+static struct miscdevice akm_aot_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "akm8976_aot",
+	.fops = &akm_aot_fops,
+};
+
+static struct miscdevice akm_pffd_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "akm8976_pffd",
+	.fops = &akm_pffd_fops,
+};
+
+static struct miscdevice akmd_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "akm8976_daemon",
+	.fops = &akmd_fops,
+};
+
+static int akm8976_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct akm8976_data *akm;
+	int err;
+	char rxData[2];
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		err = -ENODEV;
+		goto exit_check_functionality_failed;
+	}
+
+	akm = kzalloc(sizeof(struct akm8976_data), GFP_KERNEL);
+	if (!akm) {
+		err = -ENOMEM;
+		goto exit_alloc_data_failed;
+	}
+
+	INIT_WORK(&akm->work, akm_work_func);
+	i2c_set_clientdata(client, akm);
+	akm8976_init_client(client);
+	this_client = client;
+
+	/* Set EEPROM access mode */
+	err = AKECS_StartE2PRead();
+	if (err < 0)
+		goto exit_input_dev_alloc_failed;
+	/* Read ETS from EEPROM */
+	rxData[0] = 0x42;
+	err = AKI2C_RxData(rxData, 1);
+	if (err < 0)
+		goto exit_input_dev_alloc_failed;
+	revision = (0x03 & (rxData[0] >> 6));
+
+	/* Set Power down mode */
+	err = AKECS_PowerDown();
+	if (err < 0)
+		goto exit_input_dev_alloc_failed;
+
+	akm->input_dev = input_allocate_device();
+
+	if (!akm->input_dev) {
+		err = -ENOMEM;
+		printk(KERN_ERR
+		       "akm8976_probe: Failed to allocate input device\n");
+		goto exit_input_dev_alloc_failed;
+	}
+
+	set_bit(EV_ABS, akm->input_dev->evbit);
+	/* yaw */
+	input_set_abs_params(akm->input_dev, ABS_RX, 0, 360, 0, 0);
+	/* pitch */
+	input_set_abs_params(akm->input_dev, ABS_RY, -180, 180, 0, 0);
+	/* roll */
+	input_set_abs_params(akm->input_dev, ABS_RZ, -90, 90, 0, 0);
+	/* x-axis acceleration */
+	input_set_abs_params(akm->input_dev, ABS_X, -1872, 1872, 0, 0);
+	/* y-axis acceleration */
+	input_set_abs_params(akm->input_dev, ABS_Y, -1872, 1872, 0, 0);
+	/* z-axis acceleration */
+	input_set_abs_params(akm->input_dev, ABS_Z, -1872, 1872, 0, 0);
+	/* temparature */
+	input_set_abs_params(akm->input_dev, ABS_THROTTLE, -30, 85, 0, 0);
+	/* status of magnetic sensor */
+	input_set_abs_params(akm->input_dev, ABS_RUDDER, -32768, 3, 0, 0);
+	/* status of acceleration sensor */
+	input_set_abs_params(akm->input_dev, ABS_WHEEL, -32768, 3, 0, 0);
+	/* step count */
+	input_set_abs_params(akm->input_dev, ABS_GAS, 0, 65535, 0, 0);
+	/* x-axis of raw magnetic vector */
+	input_set_abs_params(akm->input_dev, ABS_HAT0X, -2048, 2032, 0, 0);
+	/* y-axis of raw magnetic vector */
+	input_set_abs_params(akm->input_dev, ABS_HAT0Y, -2048, 2032, 0, 0);
+	/* z-axis of raw magnetic vector */
+	input_set_abs_params(akm->input_dev, ABS_BRAKE, -2048, 2032, 0, 0);
+
+	akm->input_dev->name = "compass";
+
+	err = input_register_device(akm->input_dev);
+
+	if (err) {
+		printk(KERN_ERR
+		       "akm8976_probe: Unable to register input device: %s\n",
+		       akm->input_dev->name);
+		goto exit_input_register_device_failed;
+	}
+
+	err = misc_register(&akmd_device);
+	if (err) {
+		printk(KERN_ERR
+		       "akm8976_probe: akmd_device register failed\n");
+		goto exit_misc_device_register_failed;
+	}
+
+	err = misc_register(&akm_aot_device);
+	if (err) {
+		printk(KERN_ERR
+		       "akm8976_probe: akm_aot_device register failed\n");
+		goto exit_misc_device_register_failed;
+	}
+
+	err = misc_register(&akm_pffd_device);
+	if (err) {
+		printk(KERN_ERR
+		       "akm8976_probe: akm_pffd_device register failed\n");
+		goto exit_misc_device_register_failed;
+	}
+
+	err = device_create_file(&client->dev, &dev_attr_ms1);
+	err = device_create_file(&client->dev, &dev_attr_ms2);
+	err = device_create_file(&client->dev, &dev_attr_ms3);
+
+	gsensor_sysfs_init();
+
+	return 0;
+
+exit_misc_device_register_failed:
+exit_input_register_device_failed:
+	input_free_device(akm->input_dev);
+exit_input_dev_alloc_failed:
+	kfree(akm);
+exit_alloc_data_failed:
+exit_check_functionality_failed:
+	return err;
+}
+
+static int akm8976_remove(struct i2c_client *client)
+{
+	struct akm8976_data *akm = i2c_get_clientdata(client);
+	free_irq(client->irq, akm);
+	input_unregister_device(akm->input_dev);
+	kfree(akm);
+	return 0;
+}
+
+static int akm8976_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	atomic_set(&suspend_flag, 1);
+	if (atomic_read(&open_flag) == 2)
+		AKECS_SetMode(AKECS_MODE_POWERDOWN);
+
+	atomic_set(&reserve_open_flag, atomic_read(&open_flag));
+	atomic_set(&open_flag, 0);
+	wake_up(&open_wq);
+	disable_irq(this_client->irq);
+	return 0;
+}
+
+static int akm8976_resume(struct i2c_client *client)
+{
+	enable_irq(this_client->irq);
+	if (atomic_read(&open_flag) == 2)
+		AKECS_SetMode(AKECS_MODE_PFFD);
+	atomic_set(&suspend_flag, 0);
+	atomic_set(&open_flag, atomic_read(&reserve_open_flag));
+	wake_up(&open_wq);
+	return 0;
+}
+
+static const struct i2c_device_id akm8976_id[] = {
+	{ "akm8976", 0 },
+	{ }
+};
+
+static struct i2c_driver akm8976_driver = {
+	.probe = akm8976_probe,
+	.remove = akm8976_remove,
+	.suspend	= akm8976_suspend,
+	.resume		= akm8976_resume,
+	.id_table = akm8976_id,
+	.driver = {
+		   .name = "akm8976",
+		   },
+};
+
+static int __init akm8976_init(void)
+{
+	printk(KERN_INFO "AKM8976A compass driver: init\n");
+	return i2c_add_driver(&akm8976_driver);
+}
+
+static void __exit akm8976_exit(void)
+{
+	i2c_del_driver(&akm8976_driver);
+}
+
+module_init(akm8976_init);
+module_exit(akm8976_exit);
+
+MODULE_AUTHOR("Hou-Kun Chen <hk_chen@htc.com>");
+MODULE_DESCRIPTION("AKM8976A compass driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/video_core/720p/Kconfig b/drivers/misc/video_core/720p/Kconfig
new file mode 100644
index 0000000..53808f9
--- /dev/null
+++ b/drivers/misc/video_core/720p/Kconfig
@@ -0,0 +1,35 @@
+#
+# VIDEO CORE
+#
+menuconfig MSM_720P_CORE
+        bool "720P Core Video Driver"
+	depends on ARCH_MSM7X30
+        default n
+        ---help---
+        Say Y here to see options for video device drivers.
+	If you say N, all options in this submenu will be skipped and disabled.
+
+if MSM_720P_CORE
+
+config MSM_VIDEO_CORE_REG
+	tristate "MSM Video core registration"
+	depends on MSM_720P_CORE
+	default n
+	help
+	  This option enables support for Video core.
+
+config MSM_VIDEO_CORE_VENC
+	tristate "Video encoder"
+	depends on MSM_VIDEO_CORE_REG
+	default n
+	help
+	  This option enables support for Video encoder.
+
+config MSM_VIDEO_CORE_VDEC
+	tristate "Video decoder"
+	depends on MSM_VIDEO_CORE_REG
+	default n
+	help
+	  This option enables support for Video decoder.
+
+endif # MSM_720P_CORE
diff --git a/drivers/misc/video_core/720p/Makefile b/drivers/misc/video_core/720p/Makefile
new file mode 100644
index 0000000..77aa694
--- /dev/null
+++ b/drivers/misc/video_core/720p/Makefile
@@ -0,0 +1,40 @@
+
+EXTRA_CFLAGS  += -Idrivers/misc/video_core/720p
+EXTRA_CFLAGS  += -Idrivers/misc/video_core/720p/ddl
+EXTRA_CFLAGS  += -Idrivers/misc/video_core/720p/dec
+EXTRA_CFLAGS  += -Idrivers/misc/video_core/720p/enc
+EXTRA_CFLAGS  += -Idrivers/misc/video_core/720p/resource_tracker
+EXTRA_CFLAGS  += -Idrivers/misc/video_core/720p/scheduler
+EXTRA_CFLAGS  += -Idrivers/misc/video_core/720p/vcd
+EXTRA_CFLAGS  += -Idrivers/misc/video_core/720p/init
+
+obj-$(CONFIG_MSM_VIDEO_CORE_REG) += video_corereg.o
+video_corereg-objs :=	ddl/vcd_ddl_firmware.o \
+			ddl/vcd_ddl_metadata.o \
+			ddl/video_core_720p.o \
+			ddl/vcd_ddl_utils.o \
+			ddl/vcd_ddl.o \
+			ddl/vcd_ddl_helper.o \
+			ddl/vcd_ddl_interrupt_handler.o \
+			ddl/vcd_ddl_hal.o \
+			ddl/vcd_ddl_properties.o \
+			init/video_core_init.o \
+			resource_tracker/vcd_res_tracker.o \
+			scheduler/vid_frame_scheduler_utils.o \
+			scheduler/vid_frame_scheduler.o \
+			scheduler/vid_frame_scheduler_api.o \
+			vcd/vcd_api.o \
+			vcd/vcd_power_sm.o \
+			vcd/vcd_client_sm.o \
+			vcd/vcd_device_sm.o \
+			vcd/vcd_sub.o \
+			ddl/vcd_ddl_errors.o
+
+obj-$(CONFIG_MSM_VIDEO_CORE_VDEC) += video_decoder.o
+
+video_decoder-objs := dec/vdec.o
+
+obj-$(CONFIG_MSM_VIDEO_CORE_VENC) += video_encoder.o
+
+video_encoder-objs := enc/venc.o \
+                    enc/venc_internal.o
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl.c b/drivers/misc/video_core/720p/ddl/vcd_ddl.c
new file mode 100644
index 0000000..22b7362
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl.c
@@ -0,0 +1,575 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vcd_ddl_utils.h"
+#include "vcd_ddl_metadata.h"
+
+u32 ddl_device_init(struct ddl_init_config *ddl_init_config, void *client_data)
+{
+	struct ddl_context *ddl_ctxt;
+	u32 status = VCD_S_SUCCESS;
+
+	if (!ddl_init_config || !ddl_init_config->ddl_callback ||
+			!ddl_init_config->core_virtual_base_addr) {
+		pr_err("ddl_dev_init:Bad_argument\n");
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+
+	ddl_ctxt = ddl_get_context();
+
+	if (DDL_IS_INITIALIZED(ddl_ctxt)) {
+		pr_err("ddl_dev_init:Multiple_init\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	if (DDL_IS_BUSY(ddl_ctxt)) {
+		pr_err("ddl_dev_init:Ddl_busy\n");
+		return VCD_ERR_BUSY;
+	}
+
+	memset(ddl_ctxt, 0, sizeof(struct ddl_context));
+
+	DDL_BUSY(ddl_ctxt);
+
+	ddl_ctxt->ddl_callback = ddl_init_config->ddl_callback;
+	ddl_ctxt->pf_interrupt_clr = ddl_init_config->pf_interrupt_clr;
+	ddl_ctxt->core_virtual_base_addr =
+		ddl_init_config->core_virtual_base_addr;
+	ddl_ctxt->client_data = client_data;
+
+	ddl_ctxt->intr_status = DDL_INVALID_INTR_STATUS;
+
+	vidc_720p_set_device_virtual_base(ddl_ctxt->core_virtual_base_addr);
+
+	ddl_ctxt->current_ddl = NULL;
+	ddl_move_command_state(ddl_ctxt, DDL_CMD_INVALID);
+
+	ddl_client_transact(DDL_INIT_CLIENTS, NULL);
+
+	if (!ddl_dma_alloc(&ddl_ctxt->context_buf_addr, DDL_CONTEXT_MEMORY, npelly_context)) {
+		pr_err("ddl_dev_init:Context_alloc_fail\n");
+		status = VCD_ERR_ALLOC_FAIL;
+		goto out;
+	}
+	if (!ddl_dma_alloc(&ddl_ctxt->db_line_buffer, DDL_DB_LINE_BUF_SIZE, npelly_dbl)) {
+		pr_err("ddl_dev_init:Line_buf_alloc_fail\n");
+		status = VCD_ERR_ALLOC_FAIL;
+		goto out;
+	}
+	if (!ddl_dma_alloc(&ddl_ctxt->data_partition_tempbuf,
+			DDL_MPEG4_DATA_PARTITION_BUF_SIZE, npelly_mpeg4)) {
+		pr_err("ddl_dev_init:"
+			"Data_partition_buf_alloc_fail\n");
+		status = VCD_ERR_ALLOC_FAIL;
+		goto out;
+	}
+	if (!ddl_dma_alloc(&ddl_ctxt->metadata_shared_input,
+			DDL_METADATA_TOTAL_INPUTBUFSIZE, npelly_meta)) {
+		pr_err("ddl_dev_init:"
+			"metadata_shared_input_alloc_fail\n");
+		status = VCD_ERR_ALLOC_FAIL;
+		goto out;
+	}
+	if (!ddl_dma_alloc(&ddl_ctxt->dbg_core_dump, DDL_DBG_CORE_DUMP_SIZE, npelly_debug)) {
+		pr_err("ddl_dev_init:"
+			"dbg_core_dump_alloc_failed\n");
+		status = VCD_ERR_ALLOC_FAIL;
+		ddl_ctxt->enable_dbg_core_dump = 0;
+		goto out;
+	}
+
+out:
+	if (status) {
+		ddl_release_context_buffers(ddl_ctxt);
+		DDL_IDLE(ddl_ctxt);
+		return status;
+	}
+
+	ddl_move_command_state(ddl_ctxt, DDL_CMD_DMA_INIT);
+
+	ddl_core_init(ddl_ctxt);
+
+	return status;
+}
+
+u32 ddl_device_release(void *client_data)
+{
+	struct ddl_context *ddl_ctxt;
+
+	ddl_ctxt = ddl_get_context();
+
+	if (DDL_IS_BUSY(ddl_ctxt)) {
+		pr_err("ddl_dev_rel:Ddl_busy\n");
+		return VCD_ERR_BUSY;
+	}
+
+	if (!DDL_IS_INITIALIZED(ddl_ctxt)) {
+		pr_err("ddl_dev_rel:Not_inited\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	if (!ddl_client_transact(DDL_ACTIVE_CLIENT, NULL)) {
+		pr_err("ddl_dev_rel:Client_present_err\n");
+		return VCD_ERR_CLIENT_PRESENT;
+	}
+	DDL_BUSY(ddl_ctxt);
+
+	ddl_ctxt->device_state = DDL_DEVICE_NOTINIT;
+	ddl_ctxt->client_data = client_data;
+	ddl_move_command_state(ddl_ctxt, DDL_CMD_INVALID);
+	vidc_720p_stop_fw();
+
+	pr_debug("FW_ENDDONE\n");
+	ddl_release_context_buffers(ddl_ctxt);
+
+	DDL_IDLE(ddl_ctxt);
+
+	return VCD_S_SUCCESS;
+}
+
+u32 ddl_open(u32 **ddl_handle, u32 decoding)
+{
+	struct ddl_context *ddl_context;
+	struct ddl_client_context *ddl;
+	u32 status;
+
+	if (!ddl_handle) {
+		pr_err("ddl_open:Bad_handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	ddl_context = ddl_get_context();
+
+	if (!DDL_IS_INITIALIZED(ddl_context)) {
+		pr_err("ddl_open:Not_inited\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	status = ddl_client_transact(DDL_GET_CLIENT, &ddl);
+
+	if (status) {
+		pr_err("ddl_open:Client_trasac_failed\n");
+		return status;
+	}
+
+	ddl_move_client_state(ddl, DDL_CLIENT_OPEN);
+
+	ddl->codec_data.hdr.decoding = decoding;
+	ddl->decoding = decoding;
+
+	ddl_set_default_meta_data_hdr(ddl);
+
+	ddl_set_initial_default_values(ddl);
+
+	*ddl_handle = (u32 *) ddl;
+	return VCD_S_SUCCESS;
+}
+
+u32 ddl_close(u32 **ddl_handle)
+{
+	struct ddl_context *ddl_context;
+	struct ddl_client_context **pp_ddl = (struct ddl_client_context **)
+		ddl_handle;
+
+	if (!pp_ddl || !*pp_ddl) {
+		pr_err("ddl_close:Bad_handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	ddl_context = ddl_get_context();
+
+	if (!DDL_IS_INITIALIZED(ddl_context)) {
+		pr_err("ddl_close:Not_inited\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	if (!DDLCLIENT_STATE_IS(*pp_ddl, DDL_CLIENT_OPEN)) {
+		pr_err("ddl_close:Not_in_open_state\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	ddl_move_client_state(*pp_ddl, DDL_CLIENT_INVALID);
+
+	ddl_client_transact(DDL_FREE_CLIENT, pp_ddl);
+
+	return VCD_S_SUCCESS;
+}
+
+u32 ddl_encode_start(u32 *ddl_handle, void *client_data)
+{
+	struct ddl_client_context *ddl =
+		(struct ddl_client_context *)ddl_handle;
+	struct ddl_context *ddl_context;
+	struct ddl_encoder_data *enc;
+	u32 dpb_size;
+
+	ddl_context = ddl_get_context();
+
+	if (!DDL_IS_INITIALIZED(ddl_context)) {
+		pr_err("ddl_enc_start:Not_inited\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	if (DDL_IS_BUSY(ddl_context)) {
+		pr_err("ddl_enc_start:Ddl_busy\n");
+		return VCD_ERR_BUSY;
+	}
+	if (!ddl || ddl->decoding) {
+		pr_err("ddl_enc_start:Bad_handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN)) {
+		pr_err("ddl_enc_start:Not_opened\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	if (!ddl_encoder_ready_to_start(ddl)) {
+		pr_err("ddl_enc_start:Err_param_settings\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	enc = &ddl->codec_data.encoder;
+
+	dpb_size = ddl_get_yuv_buffer_size(&enc->frame_size,
+					&enc->re_con_buf_format, false);
+
+	dpb_size *= DDL_ENC_NUM_DPB_BUFFERS;
+	if (!ddl_dma_alloc(&enc->enc_dpb_addr, dpb_size, npelly_enc_dpb)) {
+		pr_err("ddl_enc_start:Dpb_alloc_failed\n");
+		return VCD_ERR_ALLOC_FAIL;
+	}
+
+	if ((enc->codec_type.codec == VCD_CODEC_MPEG4 &&
+			!enc->short_header.short_header) ||
+			enc->codec_type.codec == VCD_CODEC_H264) {
+		if (!ddl_dma_alloc(&enc->seq_header, DDL_ENC_SEQHEADER_SIZE, npelly_enc_seq)) {
+			ddl_dma_free(&enc->enc_dpb_addr);
+			pr_err("ddl_enc_start:Seq_hdr_alloc_failed\n");
+			return VCD_ERR_ALLOC_FAIL;
+		}
+	} else {
+		enc->seq_header.size = 0;
+		enc->seq_header.virt_addr = NULL;
+	}
+
+	DDL_BUSY(ddl_context);
+
+	ddl_context->current_ddl = ddl;
+	ddl_context->client_data = client_data;
+	ddl_channel_set(ddl);
+	return VCD_S_SUCCESS;
+}
+
+u32 ddl_decode_start(u32 *ddl_handle, struct vcd_phys_sequence_hdr *hdr,
+		void *client_data)
+{
+	struct ddl_client_context *ddl = (struct ddl_client_context *)
+		ddl_handle;
+	struct ddl_context *ddl_context;
+	struct ddl_decoder_data *decoder;
+
+	ddl_context = ddl_get_context();
+
+	if (!DDL_IS_INITIALIZED(ddl_context)) {
+		pr_err("ddl_dec_start:Not_inited\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	if (DDL_IS_BUSY(ddl_context)) {
+		pr_err("ddl_dec_start:Ddl_busy\n");
+		return VCD_ERR_BUSY;
+	}
+	if (!ddl || !ddl->decoding) {
+		pr_err("ddl_dec_start:Bad_handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN)) {
+		pr_err("ddl_dec_start:Not_in_opened_state\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	if (hdr && (!hdr->sz || !hdr->addr)) {
+		pr_err("ddl_dec_start:Bad_param_seq_header\n");
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+
+	if (!ddl_decoder_ready_to_start(ddl, hdr)) {
+		pr_err("ddl_dec_start:Err_param_settings\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	DDL_BUSY(ddl_context);
+
+	decoder = &ddl->codec_data.decoder;
+	if (hdr) {
+		decoder->header_in_start = true;
+		decoder->decode_config = *hdr;
+	} else {
+		decoder->header_in_start = false;
+		decoder->decode_config.sz = 0;
+	}
+
+	if (decoder->codec_type.codec == VCD_CODEC_H264) {
+		if (!ddl_dma_alloc(&decoder->h264Vsp_temp_buffer,
+			       DDL_DECODE_H264_VSPTEMP_BUFSIZE,
+				npelly_dec_h264)) {
+			DDL_IDLE(ddl_context);
+			pr_err("ddl_dec_start:H264Sps_alloc_failed\n");
+			return VCD_ERR_ALLOC_FAIL;
+		}
+	}
+
+	ddl_context->current_ddl = ddl;
+	ddl_context->client_data = client_data;
+
+	ddl_channel_set(ddl);
+	return VCD_S_SUCCESS;
+}
+
+u32 ddl_decode_frame(u32 *ddl_handle, struct ddl_frame_data_tag *in_bits,
+		void *client_data)
+{
+	u32 vcd_status = VCD_S_SUCCESS;
+	struct ddl_client_context *ddl = (struct ddl_client_context *)
+		ddl_handle;
+	struct ddl_context *ddl_context = ddl_get_context();
+
+#ifdef CORE_TIMING_INFO
+	ddl_get_core_start_time(0);
+#endif
+
+	if (!DDL_IS_INITIALIZED(ddl_context)) {
+		pr_err("ddl_dec_frame:Not_inited\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	if (DDL_IS_BUSY(ddl_context)) {
+		pr_err("ddl_dec_frame:Ddl_busy\n");
+		return VCD_ERR_BUSY;
+	}
+	if (!ddl || !ddl->decoding) {
+		pr_err("ddl_dec_frame:Bad_handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+	if (!in_bits || ((!in_bits->vcd_frm.phys_addr ||
+			!in_bits->vcd_frm.data_len) &&
+			!(VCD_FRAME_FLAG_EOS & in_bits->vcd_frm.flags))) {
+		pr_err("ddl_dec_frame:Bad_input_param\n");
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+
+	DDL_BUSY(ddl_context);
+
+	ddl_context->current_ddl = ddl;
+	ddl_context->client_data = client_data;
+
+	ddl->input_frame = *in_bits;
+
+	if (DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME)) {
+		ddl_decode_frame_run(ddl);
+	} else {
+		if (!ddl->codec_data.decoder.dp_buf.no_of_dec_pic_buf) {
+			pr_err("ddl_dec_frame:Dpbs_requied\n");
+			vcd_status = VCD_ERR_ILLEGAL_OP;
+		} else if (DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_DPB)) {
+			vcd_status = ddl_decode_set_buffers(ddl);
+		} else if (DDLCLIENT_STATE_IS(ddl,
+				DDL_CLIENT_WAIT_FOR_INITCODEC)) {
+			ddl->codec_data.decoder.decode_config.addr =
+				ddl->input_frame.vcd_frm.phys_addr;
+			ddl->codec_data.decoder.decode_config.sz =
+				ddl->input_frame.vcd_frm.data_len;
+			ddl_decode_init_codec(ddl);
+		} else {
+			pr_err("Dec_frame:Wrong_state\n");
+			vcd_status = VCD_ERR_ILLEGAL_OP;
+		}
+		if (vcd_status)
+			DDL_IDLE(ddl_context);
+	}
+	return vcd_status;
+}
+
+u32 ddl_encode_frame(u32 *ddl_handle, struct ddl_frame_data_tag *input_frame,
+		struct ddl_frame_data_tag *out_bits, void *client_data)
+{
+	struct ddl_client_context *ddl = (struct ddl_client_context *)
+		ddl_handle;
+	struct ddl_context *ddl_context = ddl_get_context();
+
+#ifdef CORE_TIMING_INFO
+	ddl_get_core_start_time(1);
+#endif
+
+	if (!DDL_IS_INITIALIZED(ddl_context)) {
+		pr_err("ddl_encode_frame:Not_inited\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	if (DDL_IS_BUSY(ddl_context)) {
+		pr_err("ddl_encode_frame:Ddl_busy\n");
+		return VCD_ERR_BUSY;
+	}
+	if (!ddl || ddl->decoding) {
+		pr_err("ddl_encode_frame:Bad_handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+	if (!input_frame || !input_frame->vcd_frm.phys_addr ||
+			ddl->codec_data.encoder.input_buf_req.size !=
+			input_frame->vcd_frm.data_len) {
+		pr_err("ddl_encode_frame:Bad_input_params\n");
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+	if ((input_frame->vcd_frm.phys_addr + input_frame->vcd_frm.offset) &
+			DDL_STREAMBUF_ALIGN_GUARD_BYTES) {
+		pr_err("ddl_encode_frame:unaligned_yuv_start_addr\n");
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+	if (!out_bits || !out_bits->vcd_frm.phys_addr ||
+			!out_bits->vcd_frm.alloc_len) {
+		pr_err("ddl_encode_frame:Bad_output_params\n");
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+	if ((ddl->codec_data.encoder.output_buf_req.size +
+			out_bits->vcd_frm.offset) >
+			out_bits->vcd_frm.alloc_len) {
+		pr_err("ddl_encode_frame:offset > min_buf_size\n");
+	}
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME)) {
+		pr_err("ddl_encode_frame:Wrong_state\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	DDL_BUSY(ddl_context);
+
+	ddl_context->current_ddl = ddl;
+	ddl_context->client_data = client_data;
+
+	ddl->input_frame = *input_frame;
+	ddl->output_frame = *out_bits;
+
+	ddl_encode_frame_run(ddl);
+	return VCD_S_SUCCESS;
+}
+
+u32 ddl_decode_end(u32 *ddl_handle, void *client_data)
+{
+	struct ddl_client_context *ddl = (struct ddl_client_context *)
+		ddl_handle;
+	struct ddl_context *ddl_context;
+
+	ddl_context = ddl_get_context();
+
+#ifdef CORE_TIMING_INFO
+	ddl_reset_time_variables(0);
+#endif
+
+	if (!DDL_IS_INITIALIZED(ddl_context)) {
+		pr_err("ddl_dec_end:Not_inited\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	if (DDL_IS_BUSY(ddl_context)) {
+		pr_err("ddl_dec_end:Ddl_busy\n");
+		return VCD_ERR_BUSY;
+	}
+	if (!ddl || !ddl->decoding) {
+		pr_err("ddl_dec_end:Bad_handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME) &&
+			!DDLCLIENT_STATE_IS(ddl,
+			DDL_CLIENT_WAIT_FOR_INITCODEC) &&
+			!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_DPB) &&
+			!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_FATAL_ERROR)) {
+		pr_err("ddl_dec_end:Wrong_state\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	DDL_BUSY(ddl_context);
+
+	ddl_context->current_ddl = ddl;
+	ddl_context->client_data = client_data;
+
+	ddl_channel_end(ddl);
+	return VCD_S_SUCCESS;
+}
+
+u32 ddl_encode_end(u32 *ddl_handle, void *client_data)
+{
+	struct ddl_client_context *ddl = (struct ddl_client_context *)
+		ddl_handle;
+	struct ddl_context *ddl_context;
+
+	ddl_context = ddl_get_context();
+
+#ifdef CORE_TIMING_INFO
+	ddl_reset_time_variables(1);
+#endif
+
+	if (!DDL_IS_INITIALIZED(ddl_context)) {
+		pr_err("ddl_enc_end:Not_inited\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	if (DDL_IS_BUSY(ddl_context)) {
+		pr_err("ddl_enc_end:Ddl_busy\n");
+		return VCD_ERR_BUSY;
+	}
+	if (!ddl || ddl->decoding) {
+		pr_err("ddl_enc_end:Bad_handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME) &&
+		!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_INITCODEC) &&
+		!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_FATAL_ERROR)) {
+		pr_err("ddl_enc_end:Wrong_state\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	DDL_BUSY(ddl_context);
+
+	ddl_context->current_ddl = ddl;
+	ddl_context->client_data = client_data;
+
+	ddl_channel_end(ddl);
+	return VCD_S_SUCCESS;
+}
+
+u32 ddl_reset_hw(u32 mode)
+{
+	struct ddl_context *ddl_context;
+	struct ddl_client_context *ddl;
+	int client_num;
+
+	pr_debug("ddl_reset_hw:called\n");
+	ddl_context = ddl_get_context();
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+	DDL_BUSY(ddl_context);
+
+	if (ddl_context->core_virtual_base_addr)
+		vidc_720p_do_sw_reset();
+
+	ddl_context->device_state = DDL_DEVICE_NOTINIT;
+	for (client_num = 0; client_num < VCD_MAX_NO_CLIENT; ++client_num) {
+		ddl = ddl_context->ddl_clients[client_num];
+		ddl_context->ddl_clients[client_num] = NULL;
+		if (ddl) {
+			ddl_release_client_internal_buffers(ddl);
+			ddl_client_transact(DDL_FREE_CLIENT, &ddl);
+		}
+	}
+
+	ddl_release_context_buffers(ddl_context);
+	memset(ddl_context, 0, sizeof(struct ddl_context));
+
+	return true;
+}
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl.h b/drivers/misc/video_core/720p/ddl/vcd_ddl.h
new file mode 100644
index 0000000..8f4e924
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl.h
@@ -0,0 +1,286 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_DDL_H_
+#define _VCD_DDL_H_
+#include "vcd_ddl_api.h"
+#include "vcd_ddl_utils.h"
+#include "vcd_ddl_firmware.h"
+#include "video_core_720p.h"
+
+#define DDL_BUSY_STATE 1
+#define DDL_IDLE_STATE 0
+#define DDL_ERROR_STATE 2
+#define DDL_IS_BUSY(ddl_context) \
+	(((ddl_context)->ddl_busy != DDL_IDLE_STATE))
+#define DDL_BUSY(ddl_context) \
+	((ddl_context)->ddl_busy = DDL_BUSY_STATE)
+#define DDL_IDLE(ddl_context) \
+	((ddl_context)->ddl_busy = DDL_IDLE_STATE)
+#define DDL_ERROR(ddl_context) \
+	((ddl_context)->ddl_busy = DDL_ERROR_STATE)
+
+#define DDL_DEVICE_NOTINIT  0
+#define DDL_DEVICE_INITED   1
+#define DDL_DEVICE_HWFATAL  2
+#define DDL_IS_INITIALIZED(ddl_context)  \
+	(ddl_context->device_state == DDL_DEVICE_INITED)
+
+#define DDLCOMMAND_STATE_IS(ddl_context, command_state) \
+	(command_state == (ddl_context)->cmd_state)
+
+#define DDLCLIENT_STATE_IS(ddl, cs) \
+	(cs == (ddl)->client_state)
+
+#define DDL_DPB_OP_INIT       1
+#define DDL_DPB_OP_MARK_FREE  2
+#define DDL_DPB_OP_MARK_BUSY  3
+#define DDL_DPB_OP_SET_MASK   4
+#define DDL_DPB_OP_RETRIEVE   5
+
+#define DDL_INIT_CLIENTS     0
+#define DDL_GET_CLIENT       1
+#define DDL_FREE_CLIENT      2
+#define DDL_ACTIVE_CLIENT    3
+
+#define DDL_INVALID_CHANNEL_ID  ((u32)~0)
+#define DDL_INVALID_CODEC_TYPE ((u32)~0)
+#define DDL_INVALID_INTR_STATUS ((u32)~0)
+
+#define DDL_ENC_REQ_IFRAME                      0x1
+#define DDL_ENC_CHANGE_IPERIOD                  0x2
+#define DDL_ENC_CHANGE_BITRATE                  0x4
+#define DDL_ENC_CHANGE_FRAMERATE                0x8
+
+#define DDL_DEC_REQ_OUTPUT_FLUSH                0x1
+
+struct ddl_dma_buffer {
+	void *virt_addr;
+	phys_addr_t phys_addr;
+	size_t size;
+};
+
+enum ddl_cmd_state {
+	DDL_CMD_INVALID = 0x0,
+	DDL_CMD_DMA_INIT = 0x1,
+	DDL_CMD_CPU_RESET = 0x2,
+	DDL_CMD_CHANNEL_SET = 0x3,
+	DDL_CMD_INIT_CODEC = 0x4,
+	DDL_CMD_HEADER_PARSE = 0x5,
+	DDL_CMD_DECODE_SET_DPB = 0x6,
+	DDL_CMD_DECODE_FRAME = 0x7,
+	DDL_CMD_ENCODE_FRAME = 0x8,
+	DDL_CMD_EOS = 0x9,
+	DDL_CMD_CHANNEL_END = 0xA,
+	DDL_CMD_32BIT = 0x7FFFFFFF
+};
+
+enum ddl_client_state {
+	DDL_CLIENT_INVALID = 0x0,
+	DDL_CLIENT_OPEN = 0x1,
+	DDL_CLIENT_WAIT_FOR_CHDONE = 0x2,
+	DDL_CLIENT_WAIT_FOR_INITCODEC = 0x3,
+	DDL_CLIENT_WAIT_FOR_INITCODECDONE = 0x4,
+	DDL_CLIENT_WAIT_FOR_DPB = 0x5,
+	DDL_CLIENT_WAIT_FOR_DPBDONE = 0x6,
+	DDL_CLIENT_WAIT_FOR_FRAME = 0x7,
+	DDL_CLIENT_WAIT_FOR_FRAME_DONE = 0x8,
+	DDL_CLIENT_WAIT_FOR_EOS_DONE = 0x9,
+	DDL_CLIENT_WAIT_FOR_CHEND = 0xA,
+	DDL_CLIENT_FATAL_ERROR = 0xB,
+	DDL_CLIENT_32BIT = 0x7FFFFFFF
+};
+
+struct ddl_mask {
+	u32 client_mask;
+	u32 hw_mask;
+};
+
+struct ddl_context;
+
+struct ddl_client_context;
+
+struct ddl_codec_data_hdr {
+	u32 decoding;
+};
+
+struct ddl_encoder_data {
+	struct ddl_codec_data_hdr hdr;
+	struct vcd_property_codec codec_type;
+	struct vcd_property_frame_size frame_size;
+	struct vcd_property_frame_rate frame_rate;
+	struct vcd_property_target_bitrate target_bit_rate;
+	struct vcd_property_profile profile;
+	struct vcd_property_level level;
+	struct vcd_property_rate_control rc_type;
+	struct vcd_property_multi_slice multi_slice;
+	u32 meta_data_enable_flag;
+	u32 suffix;
+	struct ddl_dma_buffer meta_data_input;
+	phys_addr_t meta_data_offset;
+	struct vcd_property_short_header short_header;
+	struct vcd_property_vop_timing vop_timing;
+	u32 hdr_ext_control;
+	struct vcd_property_db_config db_control;
+	struct vcd_property_entropy_control entropy_control;
+	struct vcd_property_i_period period;
+	struct vcd_property_session_qp session_qp;
+	struct vcd_property_qp_range qp_range;
+	struct vcd_property_rc_level rc_level;
+	u32 r_cframe_skip;
+	u32 vb_vbuffer_size;
+	struct vcd_property_frame_level_rc_params frame_level_rc;
+	struct vcd_property_adaptive_rc_params adaptive_rc;
+	struct vcd_property_intra_refresh_mb_number intra_refresh;
+	struct vcd_property_buffer_format buf_format;
+	struct vcd_property_buffer_format re_con_buf_format;
+	u32 dynamic_prop_change;
+	u32 dynmic_prop_change_req;
+	u32 ext_enc_control_val;
+	struct vidc_720p_enc_frame_info enc_frame_info;
+	struct ddl_dma_buffer enc_dpb_addr;
+	struct ddl_dma_buffer seq_header;
+	struct vcd_buffer_requirement input_buf_req;
+	struct vcd_buffer_requirement output_buf_req;
+	struct vcd_buffer_requirement client_input_buf_req;
+	struct vcd_buffer_requirement client_output_buf_req;
+};
+
+struct ddl_decoder_data {
+	struct ddl_codec_data_hdr hdr;
+	struct vcd_property_codec codec_type;
+	struct vcd_property_buffer_format buf_format;
+	struct vcd_property_frame_size frame_size;
+	struct vcd_property_frame_size client_frame_size;
+	struct vcd_property_profile profile;
+	struct vcd_property_level level;
+	u32 progressive_only;
+	u32 meta_data_enable_flag;
+	u32 suffix;
+	struct ddl_dma_buffer meta_data_input;
+	struct ddl_dma_buffer ref_buffer;
+	size_t meta_data_offset;
+	struct vcd_property_post_filter post_filter;
+	struct vcd_phys_sequence_hdr decode_config;
+	u32 header_in_start;
+	u32 min_dpb_num;
+	size_t y_cb_cr_size;
+	struct ddl_property_dec_pic_buffers dp_buf;
+	struct ddl_mask dpb_mask;
+	u32 dynamic_prop_change;
+	u32 dynmic_prop_change_req;
+	struct vidc_720p_dec_disp_info dec_disp_info;
+	struct ddl_dma_buffer dpb_comv_buffer;
+	struct ddl_dma_buffer h264Vsp_temp_buffer;
+	struct vcd_buffer_requirement actual_input_buf_req;
+	struct vcd_buffer_requirement min_input_buf_req;
+	struct vcd_buffer_requirement client_input_buf_req;
+	struct vcd_buffer_requirement actual_output_buf_req;
+	struct vcd_buffer_requirement min_output_buf_req;
+	struct vcd_buffer_requirement client_output_buf_req;
+};
+
+union ddl_codec_data {
+	struct ddl_codec_data_hdr hdr;
+	struct ddl_decoder_data decoder;
+	struct ddl_encoder_data encoder;
+};
+
+struct ddl_context {
+	u8 *core_virtual_base_addr;
+	void (*ddl_callback) (u32 event, u32 status, void *payload, u32 size,
+			      u32 *ddl_handle, void *const client_data);
+	void *client_data;
+	void (*pf_interrupt_clr) (void);
+	enum ddl_cmd_state cmd_state;
+	struct ddl_client_context *current_ddl;
+	struct ddl_dma_buffer context_buf_addr;
+	struct ddl_dma_buffer db_line_buffer;
+	struct ddl_dma_buffer data_partition_tempbuf;
+	struct ddl_dma_buffer metadata_shared_input;
+	struct ddl_dma_buffer dbg_core_dump;
+	u32 enable_dbg_core_dump;
+	struct ddl_client_context *ddl_clients[VCD_MAX_NO_CLIENT];
+	u32 device_state;
+	u32 ddl_busy;
+	u32  intr_status;
+	u32 cmd_err_status;
+	u32 disp_pic_err_status;
+	u32 op_failed;
+};
+
+struct ddl_client_context {
+	struct ddl_context *ddl_context;
+	enum ddl_client_state client_state;
+	u32 decoding;
+	u32 channel_id;
+	struct ddl_frame_data_tag input_frame;
+	struct ddl_frame_data_tag output_frame;
+	union ddl_codec_data codec_data;
+};
+
+struct ddl_context *ddl_get_context(void);
+void ddl_move_command_state(struct ddl_context *ddl_context,
+	enum ddl_cmd_state command_state);
+void ddl_move_client_state(struct ddl_client_context *ddl,
+	enum ddl_client_state client_state);
+void ddl_core_init(struct ddl_context *);
+void ddl_core_start_cpu(struct ddl_context *);
+void ddl_channel_set(struct ddl_client_context *);
+void ddl_channel_end(struct ddl_client_context *);
+void ddl_encode_init_codec(struct ddl_client_context *);
+void ddl_decode_init_codec(struct ddl_client_context *);
+void ddl_encode_frame_run(struct ddl_client_context *);
+void ddl_decode_frame_run(struct ddl_client_context *);
+void ddl_decode_eos_run(struct ddl_client_context *);
+void ddl_release_context_buffers(struct ddl_context *);
+void ddl_release_client_internal_buffers(struct ddl_client_context *ddl);
+u32 ddl_decode_set_buffers(struct ddl_client_context *);
+u32 ddl_decoder_dpb_transact(struct ddl_decoder_data *dec,
+	struct ddl_frame_data_tag *in_out_frame, u32 operation);
+u32 ddl_client_transact(u32, struct ddl_client_context **);
+void ddl_set_default_decoder_buffer_req(struct ddl_decoder_data *dec,
+	u32 estimate);
+void ddl_set_default_encoder_buffer_req(struct ddl_encoder_data *enc);
+void ddl_set_default_dec_property(struct ddl_client_context *);
+u32 ddl_encoder_ready_to_start(struct ddl_client_context *);
+u32 ddl_decoder_ready_to_start(struct ddl_client_context *,
+	struct vcd_phys_sequence_hdr *);
+size_t ddl_get_yuv_buffer_size(struct vcd_property_frame_size *frame_size,
+	struct vcd_property_buffer_format *buf_format, u32 interlace);
+void ddl_calculate_stride(struct vcd_property_frame_size *frame_size,
+	u32 interlace);
+void ddl_encode_dynamic_property(struct ddl_client_context *ddl, u32 enable);
+void ddl_decode_dynamic_property(struct ddl_client_context *ddl, u32 enable);
+void ddl_set_initial_default_values(struct ddl_client_context *ddl);
+u32 ddl_handle_core_errors(struct ddl_context *ddl_context);
+void ddl_client_fatal_cb(struct ddl_context *ddl_context);
+void ddl_hw_fatal_cb(struct ddl_context *ddl_context);
+u32 ddl_hal_engine_reset(struct ddl_context *ddl_context);
+
+#endif
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_api.h b/drivers/misc/video_core/720p/ddl/vcd_ddl_api.h
new file mode 100644
index 0000000..b3ce6b7
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_api.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_DDL_API_H_
+#define _VCD_DDL_API_H_
+#include "vcd_ddl_internal_property.h"
+
+struct ddl_init_config {
+	u8 *core_virtual_base_addr;
+	void (*pf_interrupt_clr) (void);
+	void (*ddl_callback) (u32 event, u32 status, void *payload, u32 size,
+		u32 *ddl_handle, void *const client_data);
+};
+
+struct ddl_frame_data_tag {
+	struct vcd_frame_data vcd_frm;
+	u32 intrlcd_ip_frm_tag;
+	u32 frm_trans_end;
+	u32 frm_delta;
+};
+
+u32 ddl_device_init(struct ddl_init_config *ddl_init_config, void *client_data);
+u32 ddl_device_release(void *client_data);
+u32 ddl_open(u32 **ddl_handle, u32 decoding);
+u32 ddl_close(u32 **ddl_handle);
+u32 ddl_encode_start(u32 *ddl_handle, void *client_data);
+u32 ddl_encode_frame(u32 *ddl_handle, struct ddl_frame_data_tag *input_frame,
+	struct ddl_frame_data_tag *output_bit, void *client_data);
+u32 ddl_encode_end(u32 *ddl_handle, void *client_data);
+u32 ddl_decode_start(u32 *ddl_handle, struct vcd_phys_sequence_hdr *header,
+	void *client_data);
+u32 ddl_decode_frame(u32 *ddl_handle, struct ddl_frame_data_tag *in_bits,
+	void *client_data);
+u32 ddl_decode_end(u32 *ddl_handle, void *client_data);
+u32 ddl_set_property(u32 *ddl_handle, struct vcd_property_hdr *property_hdr,
+	void *property_value);
+u32 ddl_get_property(u32 *ddl_handle, struct vcd_property_hdr *property_hdr,
+	void *property_value);
+void ddl_read_and_clear_interrupt(void);
+u32 ddl_process_core_response(void);
+u32 ddl_reset_hw(u32 mode);
+
+#endif
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_core.h b/drivers/misc/video_core/720p/ddl/vcd_ddl_core.h
new file mode 100644
index 0000000..8e0cfcd
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_core.h
@@ -0,0 +1,105 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_DDL_CORE_H_
+#define _VCD_DDL_CORE_H_
+
+#define DDL_LINEAR_BUF_ALIGN_MASK   0xFFFFFFF8U
+#define DDL_LINEAR_BUF_ALIGN_GUARD_BYTES 0x7
+#define DDL_LINEAR_BUFFER_ALIGN_BYTES  8
+
+#define DDL_TILE_BUF_ALIGN_MASK   0xFFFFE000U
+#define DDL_TILE_BUF_ALIGN_GUARD_BYTES 0x1FFF
+#define DDL_TILE_BUFFER_ALIGN_BYTES  8192
+
+#define DDL_MAX_FRAME_WIDTH   1280
+#define DDL_MAX_FRAME_HEIGHT  720
+
+#define DDL_MAX_DP_FRAME_WIDTH  352
+#define DDL_MAX_DP_FRAME_HEIGHT 288
+
+#define DDL_SW_RESET_SLEEP 10
+
+#define VCD_MAX_NO_CLIENT  4
+#define VCD_FRAME_COMMAND_DEPTH 1
+#define VCD_GENERAL_COMMAND_DEPTH 1
+#define VCD_COMMAND_EXCLUSIVE true
+
+#define DDL_HW_TIMEOUT_IN_MS  1000
+
+#define DDL_STREAMBUF_ALIGN_GUARD_BYTES 0x7
+
+#define DDL_CONTEXT_MEMORY (1024 * 15 * (VCD_MAX_NO_CLIENT + 1))
+#define DDL_DB_LINE_BUF_SIZE \
+(((((DDL_MAX_FRAME_WIDTH * 4) - 1) / 256) + 1) * 8 * 1024)
+#define DDL_MPEG4_DATA_PARTITION_BUF_SIZE (64 * 1024)
+#define DDL_DECODE_H264_VSPTEMP_BUFSIZE 0x51c00
+#define DDL_ENC_NUM_DPB_BUFFERS 2
+
+#define DDL_DBG_CORE_DUMP_SIZE (10 * 1024)
+
+#define DDL_BUFEND_PAD    256
+#define DDL_ENC_SEQHEADER_SIZE (256+DDL_BUFEND_PAD)
+#define DDL_MAX_BUFFER_COUNT  32
+
+#define DDL_MPEG_REFBUF_COUNT  2
+
+#define DDL_MPEG_COMV_BUF_NO 2
+#define DDL_H263_COMV_BUF_NO 0
+#define DDL_COMV_BUFLINE_NO  128
+#define DDL_VC1_COMV_BUFLINE_NO  32
+#define DDL_MINIMUM_BYTE_PER_SLICE  1920
+
+#define DDL_MAX_H264_QP   51
+#define DDL_MAX_MPEG4_QP  31
+
+//TODO clean this dirty thing
+#define DDL_PADDING_HACK(addr) \
+	(addr) = (u32)((((u32)(addr) + DDL_STREAMBUF_ALIGN_GUARD_BYTES) & \
+	~(DDL_STREAMBUF_ALIGN_GUARD_BYTES)) + DDL_BUFEND_PAD)
+
+#define DDL_FRAMESIZE_DIV_FACTOR   0xF
+#define DDL_ALLOW_DEC_FRAMESIZE(w, h) (\
+	(w) <= DDL_MAX_FRAME_WIDTH && \
+	(h) <= DDL_MAX_FRAME_HEIGHT && \
+	(((w) >= 32 && (h) >= 16) || ((w) >= 16 && (h) >= 32)))
+
+#define DDL_ALLOW_ENC_FRAMESIZE(w, h) (\
+	(w) <= DDL_MAX_FRAME_WIDTH && \
+	(h) <= DDL_MAX_FRAME_HEIGHT && \
+	(w) >= 32 && (h) >= 32 && \
+	!((w) & DDL_FRAMESIZE_DIV_FACTOR) && \
+	!((h) & DDL_FRAMESIZE_DIV_FACTOR))
+
+#define DDL_TILE_ALIGN_WIDTH     128
+#define DDL_TILE_ALIGN_HEIGHT    32
+#define DDL_TILE_MULTIPLY_FACTOR 8192
+#define DDL_TILE_ALIGN(val, grid) \
+	(((val) + (grid) - 1) / (grid) * (grid))
+
+#endif
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_errors.c b/drivers/misc/video_core/720p/ddl/vcd_ddl_errors.c
new file mode 100644
index 0000000..1aad338
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_errors.c
@@ -0,0 +1,509 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vcd_ddl_utils.h"
+#include "vcd_ddl.h"
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+#define ERR(x...) printk(KERN_ERR x)
+
+#define INVALID_CHANNEL_NUMBER  1
+#define INVALID_COMMAND_ID 2
+#define CHANNEL_ALREADY_IN_USE 3
+#define CHANNEL_NOT_SET_BEFORE_CHANNEL_CLOSE 4
+#define CHANNEL_SET_ERROR_INIT_CODEC 5
+#define INIT_CODEC_ALREADY_CALLED 6
+#define CHANNEL_SET_ERROR_INIT_BUFFERS 7
+#define INIT_CODEC_ERROR_INIT_BUFFERS 8
+#define INIT_BUFFER_ALREADY_CALLED  9
+#define CHANNEL_SET_ERROR_FRAME_RUN 10
+#define INIT_CODEC_ERROR_FRAME_RUN 11
+#define INIT_BUFFERS_ERROR_FRAME_RUN 12
+#define CODEC_LIMIT_EXCEEDED 13
+#define FIRMWARE_SIZE_ZERO 14
+#define FIRMWARE_ADDRESS_EXT_ZERO 15
+#define CONTEXT_DMA_IN_ERROR 16
+#define CONTEXT_DMA_OUT_ERROR 17
+#define PROGRAM_DMA_ERROR 18
+#define CONTEXT_STORE_EXT_ADD_ZERO 19
+#define MEM_ALLOCATION_FAILED 20
+
+
+#define UNSUPPORTED_FEATURE_IN_PROFILE 27
+#define RESOLUTION_NOT_SUPPORTED 28
+#define HEADER_NOT_FOUND 52
+#define MB_NUM_INVALID 61
+#define FRAME_RATE_NOT_SUPPORTED 62
+#define INVALID_QP_VALUE 63
+#define INVALID_RC_REACTION_COEFFICIENT 64
+#define INVALID_CPB_SIZE_AT_GIVEN_LEVEL 65
+
+#define ALLOC_DPB_SIZE_NOT_SUFFICIENT 71
+#define ALLOC_DB_SIZE_NOT_SUFFICIENT 72
+#define ALLOC_COMV_SIZE_NOT_SUFFICIENT 73
+#define NUM_BUF_OUT_OF_RANGE 74
+#define NULL_CONTEXT_POINTER 75
+#define NULL_COMAMND_CONTROL_COMM_POINTER 76
+#define NULL_METADATA_INPUT_POINTER 77
+#define NULL_DPB_POINTER 78
+#define NULL_DB_POINTER 79
+#define NULL_COMV_POINTER 80
+
+#define DIVIDE_BY_ZERO 81
+#define BIT_STREAM_BUF_EXHAUST 82
+#define DMA_NOT_STOPPED 83
+#define DMA_TX_NOT_COMPLETE 84
+
+#define MB_HEADER_NOT_DONE  85
+#define MB_COEFF_NOT_DONE 86
+#define CODEC_SLICE_NOT_DONE 87
+#define VME_NOT_READY 88
+#define VC1_BITPLANE_DECODE_ERR 89
+
+
+#define VSP_NOT_READY 90
+#define BUFFER_FULL_STATE 91
+
+#define RESOLUTION_MISMATCH 112
+#define NV_QUANT_ERR 113
+#define SYNC_MARKER_ERR 114
+#define FEATURE_NOT_SUPPORTED 115
+#define MEM_CORRUPTION  116
+#define INVALID_REFERENCE_FRAME  117
+#define PICTURE_CODING_TYPE_ERR  118
+#define MV_RANGE_ERR  119
+#define PICTURE_STRUCTURE_ERR 120
+#define SLICE_ADDR_INVALID  121
+#define NON_PAIRED_FIELD_NOT_SUPPORTED  122
+#define NON_FRAME_DATA_RECEIVED 123
+#define INCOMPLETE_FRAME  124
+#define NO_BUFFER_RELEASED_FROM_HOST  125
+#define PICTURE_MANAGEMENT_ERROR  128
+#define INVALID_MMCO  129
+#define INVALID_PIC_REORDERING 130
+#define INVALID_POC_TYPE 131
+#define ACTIVE_SPS_NOT_PRESENT 132
+#define ACTIVE_PPS_NOT_PRESENT 133
+#define INVALID_SPS_ID 134
+#define INVALID_PPS_ID 135
+
+
+#define METADATA_NO_SPACE_QP 151
+#define METADATA_NO_SAPCE_CONCEAL_MB 152
+#define METADATA_NO_SPACE_VC1_PARAM 153
+#define METADATA_NO_SPACE_SEI 154
+#define METADATA_NO_SPACE_VUI 155
+#define METADATA_NO_SPACE_EXTRA 156
+#define METADATA_NO_SPACE_DATA_NONE 157
+#define FRAME_RATE_UNKNOWN 158
+#define ASPECT_RATIO_UNKOWN 159
+#define COLOR_PRIMARIES_UNKNOWN 160
+#define TRANSFER_CHAR_UNKWON 161
+#define MATRIX_COEFF_UNKNOWN 162
+#define NON_SEQ_SLICE_ADDR 163
+#define BROKEN_LINK 164
+#define FRAME_CONCEALED 165
+#define PROFILE_UNKOWN 166
+#define LEVEL_UNKOWN 167
+#define BIT_RATE_NOT_SUPPORTED 168
+#define COLOR_DIFF_FORMAT_NOT_SUPPORTED 169
+#define NULL_EXTRA_METADATA_POINTER  170
+#define SYNC_POINT_NOT_RECEIVED_STARTED_DECODING  171
+#define NULL_FW_DEBUG_INFO_POINTER  172
+#define ALLOC_DEBUG_INFO_SIZE_INSUFFICIENT  173
+#define MAX_STAGE_COUNTER_EXCEEDED 174
+
+#define METADATA_NO_SPACE_MB_INFO 180
+#define METADATA_NO_SPACE_SLICE_SIZE 181
+#define RESOLUTION_WARNING 182
+
+void ddl_hw_fatal_cb(struct ddl_context *ddl_context)
+{
+	/* Invalidate the command state */
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+	ddl_context->device_state = DDL_DEVICE_HWFATAL;
+
+	/* callback to the client to indicate hw fatal error */
+	ddl_context->ddl_callback(VCD_EVT_IND_HWERRFATAL,
+					VCD_ERR_HW_FATAL, NULL, 0,
+					(void *)ddl_context->current_ddl,
+					ddl_context->client_data);
+
+	DDL_IDLE(ddl_context);
+}
+
+static u32 ddl_handle_hw_fatal_errors(struct ddl_context
+			*ddl_context)
+{
+	u32 status = false;
+
+	switch (ddl_context->cmd_err_status) {
+
+	case INVALID_CHANNEL_NUMBER:
+	case INVALID_COMMAND_ID:
+	case CHANNEL_ALREADY_IN_USE:
+	case CHANNEL_NOT_SET_BEFORE_CHANNEL_CLOSE:
+	case CHANNEL_SET_ERROR_INIT_CODEC:
+	case INIT_CODEC_ALREADY_CALLED:
+	case CHANNEL_SET_ERROR_INIT_BUFFERS:
+	case INIT_CODEC_ERROR_INIT_BUFFERS:
+	case INIT_BUFFER_ALREADY_CALLED:
+	case CHANNEL_SET_ERROR_FRAME_RUN:
+	case INIT_CODEC_ERROR_FRAME_RUN:
+	case INIT_BUFFERS_ERROR_FRAME_RUN:
+	case CODEC_LIMIT_EXCEEDED:
+	case FIRMWARE_SIZE_ZERO:
+	case FIRMWARE_ADDRESS_EXT_ZERO:
+
+	case CONTEXT_DMA_IN_ERROR:
+	case CONTEXT_DMA_OUT_ERROR:
+	case PROGRAM_DMA_ERROR:
+	case CONTEXT_STORE_EXT_ADD_ZERO:
+	case MEM_ALLOCATION_FAILED:
+
+	case DIVIDE_BY_ZERO:
+	case DMA_NOT_STOPPED:
+	case DMA_TX_NOT_COMPLETE:
+
+	case VSP_NOT_READY:
+	case BUFFER_FULL_STATE:
+		ERR("HW FATAL ERROR");
+		ddl_hw_fatal_cb(ddl_context);
+		status = true;
+		break;
+	}
+	return status;
+}
+
+void ddl_client_fatal_cb(struct ddl_context *ddl_context)
+{
+	struct ddl_client_context  *ddl =
+		ddl_context->current_ddl;
+
+	if (ddl_context->cmd_state == DDL_CMD_DECODE_FRAME)
+		ddl_decode_dynamic_property(ddl, false);
+	else if (ddl_context->cmd_state == DDL_CMD_ENCODE_FRAME)
+		ddl_encode_dynamic_property(ddl, false);
+
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+
+	ddl_move_client_state(ddl, DDL_CLIENT_FATAL_ERROR);
+
+	ddl_context->ddl_callback
+	(
+		VCD_EVT_IND_HWERRFATAL,
+		VCD_ERR_CLIENT_FATAL,
+		NULL,
+		0,
+		(void *)ddl,
+		ddl_context->client_data
+	);
+
+	DDL_IDLE(ddl_context);
+}
+
+static u32 ddl_handle_client_fatal_errors(struct ddl_context
+			*ddl_context)
+{
+	u32 status = false;
+
+	switch (ddl_context->cmd_err_status) {
+	case UNSUPPORTED_FEATURE_IN_PROFILE:
+	case RESOLUTION_NOT_SUPPORTED:
+	case HEADER_NOT_FOUND:
+	case INVALID_SPS_ID:
+	case INVALID_PPS_ID:
+
+	case MB_NUM_INVALID:
+	case FRAME_RATE_NOT_SUPPORTED:
+	case INVALID_QP_VALUE:
+	case INVALID_RC_REACTION_COEFFICIENT:
+	case INVALID_CPB_SIZE_AT_GIVEN_LEVEL:
+
+	case ALLOC_DPB_SIZE_NOT_SUFFICIENT:
+	case ALLOC_DB_SIZE_NOT_SUFFICIENT:
+	case ALLOC_COMV_SIZE_NOT_SUFFICIENT:
+	case NUM_BUF_OUT_OF_RANGE:
+	case NULL_CONTEXT_POINTER:
+	case NULL_COMAMND_CONTROL_COMM_POINTER:
+	case NULL_METADATA_INPUT_POINTER:
+	case NULL_DPB_POINTER:
+	case NULL_DB_POINTER:
+	case NULL_COMV_POINTER:
+		{
+			status = true;
+			break;
+		}
+	}
+
+	if (!status)
+		ERR("UNKNOWN-OP-FAILED");
+
+	ddl_client_fatal_cb(ddl_context);
+
+	return true;
+}
+
+static void ddl_input_failed_cb(struct ddl_context *ddl_context,
+			u32 vcd_event, u32 vcd_status)
+{
+	struct ddl_client_context  *ddl = ddl_context->current_ddl;
+
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+
+	if (ddl->decoding)
+		ddl_decode_dynamic_property(ddl, false);
+	else
+		ddl_encode_dynamic_property(ddl, false);
+
+	ddl_context->ddl_callback(vcd_event,
+		vcd_status, &ddl->input_frame,
+		sizeof(struct ddl_frame_data_tag),
+		(void *)ddl, ddl_context->client_data);
+
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME);
+}
+
+static u32 ddl_handle_core_recoverable_errors(struct ddl_context \
+			*ddl_context)
+{
+	struct ddl_client_context  *ddl = ddl_context->current_ddl;
+	u32   vcd_status = VCD_S_SUCCESS;
+	u32   vcd_event = VCD_EVT_RESP_INPUT_DONE;
+	u32   eos = false, pending_display = 0, release_mask = 0;
+
+	if (ddl_context->cmd_state != DDL_CMD_DECODE_FRAME &&
+		ddl_context->cmd_state != DDL_CMD_ENCODE_FRAME) {
+		return false;
+	}
+	switch (ddl_context->cmd_err_status) {
+	case NON_PAIRED_FIELD_NOT_SUPPORTED:
+		{
+		vcd_status = VCD_ERR_INTRLCD_FIELD_DROP;
+		break;
+		}
+	case NO_BUFFER_RELEASED_FROM_HOST:
+		{
+			/* lets check sanity of this error */
+			release_mask =
+				ddl->codec_data.decoder.dpb_mask.hw_mask;
+			while (release_mask > 0) {
+				if ((release_mask & 0x1))
+					pending_display += 1;
+				release_mask >>= 1;
+			}
+
+			if (pending_display >=
+				ddl->codec_data.decoder.min_dpb_num) {
+				DBG("FWISSUE-REQBUF!!");
+				/* callback to client for client fatal error */
+				ddl_client_fatal_cb(ddl_context);
+				return true ;
+			}
+		vcd_event = VCD_EVT_RESP_OUTPUT_REQ;
+		break;
+		}
+	case BIT_STREAM_BUF_EXHAUST:
+	case MB_HEADER_NOT_DONE:
+	case MB_COEFF_NOT_DONE:
+	case CODEC_SLICE_NOT_DONE:
+	case VME_NOT_READY:
+	case VC1_BITPLANE_DECODE_ERR:
+		{
+			u32 reset_core;
+			/* need to reset the internal core hw engine */
+			reset_core = ddl_hal_engine_reset(ddl_context);
+			if (!reset_core)
+				return true;
+			/* fall through to process bitstream error handling */
+		}
+	case RESOLUTION_MISMATCH:
+	case NV_QUANT_ERR:
+	case SYNC_MARKER_ERR:
+	case FEATURE_NOT_SUPPORTED:
+	case MEM_CORRUPTION:
+	case INVALID_REFERENCE_FRAME:
+	case PICTURE_CODING_TYPE_ERR:
+	case MV_RANGE_ERR:
+	case PICTURE_STRUCTURE_ERR:
+	case SLICE_ADDR_INVALID:
+	case NON_FRAME_DATA_RECEIVED:
+	case INCOMPLETE_FRAME:
+	case PICTURE_MANAGEMENT_ERROR:
+	case INVALID_MMCO:
+	case INVALID_PIC_REORDERING:
+	case INVALID_POC_TYPE:
+	case ACTIVE_SPS_NOT_PRESENT:
+	case ACTIVE_PPS_NOT_PRESENT:
+		{
+			vcd_status = VCD_ERR_BITSTREAM_ERR;
+			break;
+		}
+	}
+
+	if (!vcd_status && vcd_event == VCD_EVT_RESP_INPUT_DONE)
+		return false;
+
+	ddl->input_frame.frm_trans_end = true;
+
+	eos = ((vcd_event == VCD_EVT_RESP_INPUT_DONE) &&
+		((VCD_FRAME_FLAG_EOS & ddl->input_frame.
+				vcd_frm.flags)));
+
+	if ((ddl->decoding && eos) ||
+		(!ddl->decoding))
+		ddl->input_frame.frm_trans_end = false;
+
+	if (vcd_event == VCD_EVT_RESP_INPUT_DONE &&
+		ddl->decoding &&
+		!ddl->codec_data.decoder.header_in_start &&
+		!ddl->codec_data.decoder.dec_disp_info.img_size_x &&
+		!ddl->codec_data.decoder.dec_disp_info.img_size_y
+		) {
+		/* this is first frame seq. header only case */
+		vcd_status = VCD_S_SUCCESS;
+		ddl->input_frame.vcd_frm.flags |=
+			VCD_FRAME_FLAG_CODECCONFIG;
+		ddl->input_frame.frm_trans_end = !eos;
+		/* put just some non - zero value */
+		ddl->codec_data.decoder.dec_disp_info.img_size_x = 0xff;
+	}
+	/* inform client about input failed */
+	ddl_input_failed_cb(ddl_context, vcd_event, vcd_status);
+
+	/* for Encoder case, we need to send output done also */
+	if (!ddl->decoding) {
+		/* transaction is complete after this callback */
+		ddl->output_frame.frm_trans_end = !eos;
+		/* error case: NO data present */
+		ddl->output_frame.vcd_frm.data_len = 0;
+		/* call back to client for output frame done */
+		ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
+		VCD_ERR_FAIL, &(ddl->output_frame),
+			sizeof(struct ddl_frame_data_tag),
+			(void *)ddl, ddl_context->client_data);
+
+		if (eos) {
+			DBG("ENC-EOS_DONE");
+			/* send client EOS DONE callback */
+			ddl_context->ddl_callback(VCD_EVT_RESP_EOS_DONE,
+				VCD_S_SUCCESS, NULL, 0, (void *)ddl,
+				ddl_context->client_data);
+		}
+	}
+
+	/* if it is decoder EOS case */
+	if (ddl->decoding && eos)
+		ddl_decode_eos_run(ddl);
+	else
+		DDL_IDLE(ddl_context);
+
+	return true;
+}
+
+static u32 ddl_handle_core_warnings(u32 err_status)
+{
+	u32 status = false;
+
+	switch (err_status) {
+	case FRAME_RATE_UNKNOWN:
+	case ASPECT_RATIO_UNKOWN:
+	case COLOR_PRIMARIES_UNKNOWN:
+	case TRANSFER_CHAR_UNKWON:
+	case MATRIX_COEFF_UNKNOWN:
+	case NON_SEQ_SLICE_ADDR:
+	case BROKEN_LINK:
+	case FRAME_CONCEALED:
+	case PROFILE_UNKOWN:
+	case LEVEL_UNKOWN:
+	case BIT_RATE_NOT_SUPPORTED:
+	case COLOR_DIFF_FORMAT_NOT_SUPPORTED:
+	case NULL_EXTRA_METADATA_POINTER:
+	case SYNC_POINT_NOT_RECEIVED_STARTED_DECODING:
+
+	case NULL_FW_DEBUG_INFO_POINTER:
+	case ALLOC_DEBUG_INFO_SIZE_INSUFFICIENT:
+	case MAX_STAGE_COUNTER_EXCEEDED:
+
+	case METADATA_NO_SPACE_MB_INFO:
+	case METADATA_NO_SPACE_SLICE_SIZE:
+	case RESOLUTION_WARNING:
+
+	/* decoder warnings */
+	case METADATA_NO_SPACE_QP:
+	case METADATA_NO_SAPCE_CONCEAL_MB:
+	case METADATA_NO_SPACE_VC1_PARAM:
+	case METADATA_NO_SPACE_SEI:
+	case METADATA_NO_SPACE_VUI:
+	case METADATA_NO_SPACE_EXTRA:
+	case METADATA_NO_SPACE_DATA_NONE:
+		{
+			status = true;
+			DBG("CMD-WARNING-IGNORED!!");
+			break;
+		}
+	}
+	return status;
+}
+
+u32 ddl_handle_core_errors(struct ddl_context *ddl_context)
+{
+	u32 status = false;
+
+	if (!ddl_context->cmd_err_status &&
+		!ddl_context->disp_pic_err_status)
+		return false;
+
+	if (ddl_context->cmd_state == DDL_CMD_INVALID) {
+		DBG("SPURIOUS_INTERRUPT_ERROR");
+		return true;
+	}
+
+	if (!ddl_context->op_failed) {
+		u32 disp_status;
+		status = ddl_handle_core_warnings(ddl_context->
+			cmd_err_status);
+		disp_status = ddl_handle_core_warnings(
+			ddl_context->disp_pic_err_status);
+		if (!status && !disp_status)
+			DBG("ddl_warning:Unknown");
+
+		return false;
+	}
+
+	ERR("\n %s(): OPFAILED!!", __func__);
+	ERR("\n CMD_ERROR_STATUS = %u, DISP_ERR_STATUS = %u",
+		ddl_context->cmd_err_status,
+		ddl_context->disp_pic_err_status);
+
+	status = ddl_handle_hw_fatal_errors(ddl_context);
+
+	if (!status)
+		status = ddl_handle_core_recoverable_errors(ddl_context);
+
+	if (!status)
+		status = ddl_handle_client_fatal_errors(ddl_context);
+
+	return status;
+}
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_firmware.c b/drivers/misc/video_core/720p/ddl/vcd_ddl_firmware.c
new file mode 100644
index 0000000..d501893
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_firmware.c
@@ -0,0 +1,212 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/firmware.h>
+
+#include "video_core_type.h"
+#include "vcd_ddl_firmware.h"
+
+struct vcd_firmware_table {
+	bool prepared;
+	struct device *dev;
+	struct vcd_firmware fw[6];
+};
+
+//TODO max_sz is kinda sucky, a better way?
+static struct vcd_firmware_table vcd_fw_table = {
+	.prepared = false,
+	.fw[0] = {
+		.filename = "vidc_720p_command_control.fw",
+		.change_endian = false,
+		.max_sz = 12288,
+	},
+	.fw[1] = {
+		.filename = "vidc_720p_mp4_dec_mc.fw",
+		.change_endian = true,
+		.max_sz = 32768,
+	},
+	.fw[2] = {
+		.filename = "vidc_720p_h263_dec_mc.fw",
+		.change_endian = true,
+		.max_sz = 24576,
+	},
+	.fw[3] = {
+		.filename = "vidc_720p_h264_dec_mc.fw",
+		.change_endian = true,
+		.max_sz = 45056,
+	},
+	.fw[4] = {
+		.filename = "vidc_720p_mp4_enc_mc.fw",
+		.change_endian = true,
+		.max_sz = 32768,
+	},
+	.fw[5] = {
+		.filename = "vidc_720p_h264_enc_mc.fw",
+		.change_endian = true,
+		.max_sz = 36864,
+	},
+
+};
+
+static void vcd_fw_change_endian(struct vcd_firmware *vcd_fw)
+{
+	size_t i;
+	u8 tmp;
+	u8 *fw = vcd_fw->virt_addr;
+	for (i = 0; i < vcd_fw->sz; i += 4) {
+		tmp = fw[i];
+		fw[i] = fw[i + 3];
+		fw[i + 3] = tmp;
+
+		tmp = fw[i + 1];
+		fw[i + 1] = fw[i + 2];
+		fw[i + 2] = tmp;
+	}
+}
+
+static int vcd_fw_prepare(struct vcd_firmware *vcd_fw)
+{
+	int rc;
+	const struct firmware *fw;
+
+	rc = request_firmware(&fw, vcd_fw->filename, vcd_fw_table.dev);
+	if (rc) {
+		pr_err("request_firmware(%s) failed %d\n", vcd_fw->filename,
+			rc);
+		return rc;
+	}
+
+	if (fw->size > vcd_fw->max_sz) {
+		pr_err("firmware %s is larger than allocated size (%u > %u)\n",
+			vcd_fw->filename, fw->size, vcd_fw->max_sz);
+		rc = -ENOMEM;
+		goto out;
+	}
+	vcd_fw->sz = fw->size;
+	memcpy(vcd_fw->virt_addr, fw->data, fw->size);
+
+	if (vcd_fw->change_endian)
+		vcd_fw_change_endian(vcd_fw);
+
+	pr_info("prepared firmware %s\n", vcd_fw->filename);
+
+out:
+	release_firmware(fw);
+	return rc;
+}
+
+int vcd_fw_prepare_all()
+{
+	int i;
+	int rc = 0;
+
+	if (vcd_fw_table.prepared)
+		goto out;
+
+	for (i = 0; i < ARRAY_SIZE(vcd_fw_table.fw); i++) {
+		rc = vcd_fw_prepare(&vcd_fw_table.fw[i]);
+		if (rc)
+			goto out;
+	}
+	vcd_fw_table.prepared = true;
+
+out:
+	return rc;
+}
+
+int vcd_fw_init(struct device *dev) {
+	int i;
+	vcd_fw_table.dev = dev;
+	for (i = 0; i < ARRAY_SIZE(vcd_fw_table.fw); i++) {
+		struct vcd_firmware *fw = &vcd_fw_table.fw[i];
+		fw->virt_addr = dma_alloc_coherent(NULL, fw->max_sz,
+			&fw->phys_addr, GFP_KERNEL);
+		if (!fw->virt_addr) {
+			pr_err("failed to allocate %d for %s\n", fw->max_sz,
+				fw->filename);
+			vcd_fw_exit();
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+void vcd_fw_exit(void) {
+	int i;
+	vcd_fw_table.prepared = false;
+	for (i = 0; i < ARRAY_SIZE(vcd_fw_table.fw); i++) {
+		struct vcd_firmware *fw = &vcd_fw_table.fw[i];
+		if (!fw->virt_addr)
+			continue;
+		dma_free_coherent(NULL, fw->max_sz, fw->virt_addr,
+			fw->phys_addr);
+	}
+}
+
+struct vcd_firmware *vcd_fw_get_boot_fw(void)
+{
+	if (!vcd_fw_table.prepared)
+		return NULL;
+	return &vcd_fw_table.fw[0];
+}
+
+struct vcd_firmware *vcd_fw_get_fw(bool is_decode, enum vcd_codec codec)
+{
+	if (!vcd_fw_table.prepared)
+		return NULL;
+
+	if (is_decode) {
+		switch (codec) {
+		case VCD_CODEC_DIVX_4:
+		case VCD_CODEC_DIVX_5:
+		case VCD_CODEC_DIVX_6:
+		case VCD_CODEC_XVID:
+		case VCD_CODEC_MPEG4:
+			return &vcd_fw_table.fw[1];
+		case VCD_CODEC_H264:
+			return &vcd_fw_table.fw[3];
+		case VCD_CODEC_VC1:
+		case VCD_CODEC_VC1_RCV:
+			/* vidc_720p_vc1_dec_mc.fw - untested */
+			break;
+		case VCD_CODEC_MPEG2:
+			/* vidc_720p_mp2_dec_mc.fw - untested */
+			break;
+		case VCD_CODEC_H263:
+			return &vcd_fw_table.fw[2];
+		default:
+			break;
+		}
+	} else {
+		switch (codec) {
+		case VCD_CODEC_H263:
+		case VCD_CODEC_MPEG4:
+			return &vcd_fw_table.fw[4];
+		case VCD_CODEC_H264:
+			return &vcd_fw_table.fw[5];
+		default:
+			break;
+		}
+	}
+	return NULL;
+}
+
+bool vcd_fw_is_codec_supported(bool is_decode, enum vcd_codec codec)
+{
+	return vcd_fw_get_fw(is_decode, codec) != NULL;
+}
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_firmware.h b/drivers/misc/video_core/720p/ddl/vcd_ddl_firmware.h
new file mode 100644
index 0000000..467765a
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_firmware.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_DDL_FIRMWARE_H_
+#define _VCD_DDL_FIRMWARE_H_
+
+#include <linux/device.h>
+
+#include "vcd_property.h"
+
+struct vcd_firmware {
+	const char *filename;
+	bool change_endian;
+	phys_addr_t phys_addr;
+	void *virt_addr;
+	size_t sz;      /* real size of firmware (unknown until load time) */
+	size_t max_sz;  /* size for allocation at init time */
+};
+
+int vcd_fw_init(struct device *dev);
+void vcd_fw_exit(void);
+int vcd_fw_prepare_all(void);
+struct vcd_firmware *vcd_fw_get_boot_fw(void);
+struct vcd_firmware *vcd_fw_get_fw(bool is_decode, enum vcd_codec codec);
+bool vcd_fw_is_codec_supported(bool is_decode, enum vcd_codec codec);
+
+#endif
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_hal.c b/drivers/misc/video_core/720p/ddl/vcd_ddl_hal.c
new file mode 100644
index 0000000..1b1b488
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_hal.c
@@ -0,0 +1,735 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+
+#include "vcd_ddl_utils.h"
+#include "vcd_ddl_metadata.h"
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+void ddl_core_init(struct ddl_context *ddl_context)
+{
+	char *psz_version;
+	enum vidc_720p_endian_type dma_endian;
+	u32 interrupt_off;
+	enum vidc_720p_interrupt_level_selection_type interrupt_sel;
+	u32 intr_mask = 0x0;
+	struct vcd_firmware *vcd_fw;
+
+	vcd_fw = vcd_fw_get_boot_fw();
+	dma_endian = VIDC_720P_BIG_ENDIAN;  /* use default endian */
+
+	interrupt_off = false;
+	interrupt_sel = VIDC_720P_INTERRUPT_LEVEL_SEL;
+
+	intr_mask |= VIDC_720P_INTR_BUFFER_FULL;
+	intr_mask |= VIDC_720P_INTR_FW_DONE;
+	intr_mask |= VIDC_720P_INTR_DMA_DONE;
+	intr_mask |= VIDC_720P_INTR_FRAME_DONE;
+
+	vidc_720p_do_sw_reset();
+
+	vidc_720p_init(&psz_version, vcd_fw->sz, vcd_fw->phys_addr, dma_endian,
+		interrupt_off, interrupt_sel, intr_mask);
+	return;
+}
+
+void ddl_core_start_cpu(struct ddl_context *ddl_context)
+{
+	enum vidc_720p_endian_type dma_endian;
+	u32 dbg_core_dump_buf_size = 0;
+
+	dma_endian = VIDC_720P_LITTLE_ENDIAN;  /* use reverse endian */
+
+	ddl_move_command_state(ddl_context, DDL_CMD_CPU_RESET);
+
+	DBG("VSP_BUF_ADDR_SIZE %d", ddl_context->context_buf_addr.size);
+	if (ddl_context->enable_dbg_core_dump) {
+		dbg_core_dump_buf_size = ddl_context->dbg_core_dump.size;
+	}
+
+	vidc_720p_start_cpu(dma_endian, ddl_context->context_buf_addr.phys_addr,
+		ddl_context->dbg_core_dump.phys_addr, dbg_core_dump_buf_size);
+}
+
+void ddl_channel_set(struct ddl_client_context *ddl)
+{
+	enum vidc_720p_enc_dec_selection_type enc_dec_sel;
+	enum vidc_720p_codec_type codec;
+	enum vcd_codec vcd_codec;
+	struct vcd_firmware *vcd_fw;
+
+	if (ddl->decoding) {
+		enc_dec_sel = VIDC_720P_DECODER;
+		vcd_codec = ddl->codec_data.decoder.codec_type.codec;
+	} else {
+		enc_dec_sel = VIDC_720P_ENCODER;
+		vcd_codec = ddl->codec_data.encoder.codec_type.codec;
+	}
+	switch (vcd_codec) {
+	default:
+	case VCD_CODEC_MPEG4:
+		codec = VIDC_720P_MPEG4;
+		if (ddl->decoding) {
+			vidc_720p_decode_set_mpeg4_data_partitionbuffer(
+			ddl->ddl_context->data_partition_tempbuf.phys_addr);
+		}
+		break;
+	case VCD_CODEC_H264:
+		codec = VIDC_720P_H264;
+		break;
+	case VCD_CODEC_DIVX_4:
+	case VCD_CODEC_DIVX_5:
+	case VCD_CODEC_DIVX_6:
+		codec = VIDC_720P_DIVX;
+		break;
+	case VCD_CODEC_XVID:
+		codec = VIDC_720P_XVID;
+		break;
+	case VCD_CODEC_H263:
+		codec = VIDC_720P_H263;
+		break;
+	case VCD_CODEC_MPEG2:
+		codec = VIDC_720P_MPEG2;
+		break;
+	case VCD_CODEC_VC1:
+	case VCD_CODEC_VC1_RCV:
+		codec = VIDC_720P_VC1;
+		break;
+	}
+
+	vcd_fw = vcd_fw_get_fw(ddl->decoding, vcd_codec);
+
+	ddl_move_command_state(ddl->ddl_context, DDL_CMD_CHANNEL_SET);
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_CHDONE);
+
+	vidc_720p_set_channel(ddl->channel_id, enc_dec_sel, codec,
+		vcd_fw->phys_addr, vcd_fw->sz);
+}
+
+void ddl_decode_init_codec(struct ddl_client_context *ddl)
+{
+	u32 seq_h = 0, seq_e = 0, start_byte_num = 0;
+	struct ddl_decoder_data *decoder = &(ddl->codec_data.decoder);
+	struct vcd_phys_sequence_hdr *seq_hdr = &decoder->decode_config;
+	enum vidc_720p_memory_access_method_type mem_access_method;
+
+	ddl_metadata_enable(ddl);
+
+	vidc_720p_decode_set_error_control(true);
+
+	vidc_720p_decode_set_mpeg4Post_filter(decoder->post_filter.post_filter);
+	if (decoder->codec_type.codec == VCD_CODEC_VC1_RCV) {
+		vidc_720p_set_frame_size(decoder->client_frame_size.width,
+			decoder->client_frame_size.height);
+	} else {
+		vidc_720p_set_frame_size(0x0, 0x0);
+	}
+
+	switch (decoder->buf_format.buffer_format) {
+	default:
+	case VCD_BUFFER_FORMAT_NV12:
+		mem_access_method = VIDC_720P_TILE_LINEAR;
+		break;
+	case VCD_BUFFER_FORMAT_TILE_4x2:
+		mem_access_method = VIDC_720P_TILE_64x32;
+		break;
+	}
+	pr_debug("HEADER-PARSE-START\n");
+
+	seq_h = seq_hdr->addr;
+	start_byte_num = 8 - (seq_h & DDL_STREAMBUF_ALIGN_GUARD_BYTES);
+	seq_e = seq_h + seq_hdr->sz;
+	seq_h &= ~(DDL_STREAMBUF_ALIGN_GUARD_BYTES);
+	DDL_PADDING_HACK(seq_e);
+
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_INITCODECDONE);
+	ddl_move_command_state(ddl->ddl_context, DDL_CMD_HEADER_PARSE);
+
+	vidc_720p_decode_bitstream_header(ddl->channel_id, seq_hdr->sz,
+		   start_byte_num, seq_h, seq_e, mem_access_method);
+}
+
+void ddl_decode_dynamic_property(struct ddl_client_context *ddl, u32 enable)
+{
+	struct ddl_decoder_data *decoder = &ddl->codec_data.decoder;
+	struct vcd_frame_data *bit_stream = &ddl->input_frame.vcd_frm;
+
+	if (!enable) {
+		if (decoder->dynmic_prop_change_req) {
+			decoder->dynmic_prop_change_req = false;
+			vidc_720p_decode_dynamic_req_reset();
+		}
+		return;
+	}
+	if ((decoder->dynamic_prop_change & DDL_DEC_REQ_OUTPUT_FLUSH)) {
+		decoder->dynmic_prop_change_req = true;
+		decoder->dynamic_prop_change &= ~(DDL_DEC_REQ_OUTPUT_FLUSH);
+		decoder->dpb_mask.hw_mask = 0;
+		vidc_720p_decode_dynamic_req_set(VIDC_720P_FLUSH_REQ);
+	}
+	if ((decoder->meta_data_enable_flag & VCD_METADATA_PASSTHROUGH) &&
+			(VCD_FRAME_FLAG_EXTRADATA & bit_stream->flags)) {
+		phys_addr_t extra_datastart = bit_stream->phys_addr +
+			bit_stream->offset + bit_stream->data_len;
+		extra_datastart = (extra_datastart + 3) & ~0x03;
+
+		decoder->dynmic_prop_change_req = true;
+
+		vidc_720p_decode_setpassthrough_start(extra_datastart);
+
+		vidc_720p_decode_dynamic_req_set(VIDC_720P_EXTRADATA);
+	}
+}
+
+void ddl_encode_dynamic_property(struct ddl_client_context *ddl, u32 enable)
+{
+	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+	u32 enc_param_change = 0;
+
+	if (!enable) {
+		if (encoder->dynmic_prop_change_req) {
+			encoder->dynmic_prop_change_req = false;
+			encoder->ext_enc_control_val &=
+				~(VIDC_720P_ENC_IFRAME_REQ);
+			vidc_720p_encode_set_control_param
+			(encoder->ext_enc_control_val);
+			vidc_720p_encoder_set_param_change(enc_param_change);
+		}
+		return;
+	}
+	if ((encoder->dynamic_prop_change & DDL_ENC_REQ_IFRAME)) {
+		encoder->dynamic_prop_change &= ~(DDL_ENC_REQ_IFRAME);
+		encoder->ext_enc_control_val |= VIDC_720P_ENC_IFRAME_REQ;
+		vidc_720p_encode_set_control_param
+		(encoder->ext_enc_control_val);
+	}
+	if ((encoder->dynamic_prop_change & DDL_ENC_CHANGE_BITRATE)) {
+		vidc_720p_encode_set_bit_rate(
+		encoder->target_bit_rate.target_bitrate);
+		enc_param_change |= VIDC_720P_ENC_BITRATE_CHANGE;
+		encoder->dynamic_prop_change &= ~(DDL_ENC_CHANGE_BITRATE);
+	}
+	if ((encoder->dynamic_prop_change & DDL_ENC_CHANGE_IPERIOD)) {
+		vidc_720p_encode_set_i_period(encoder->period.frames);
+		enc_param_change |= VIDC_720P_ENC_IPERIOD_CHANGE;
+		encoder->dynamic_prop_change &= ~(DDL_ENC_CHANGE_IPERIOD);
+	}
+	if ((encoder->dynamic_prop_change &
+				DDL_ENC_CHANGE_FRAMERATE)) {
+		vidc_720p_encode_set_fps
+		    ((encoder->frame_rate.fps_numerator * 1000) /
+		     encoder->frame_rate.fps_denominator);
+		enc_param_change |= VIDC_720P_ENC_FRAMERATE_CHANGE;
+		encoder->dynamic_prop_change &= ~(DDL_ENC_CHANGE_FRAMERATE);
+	}
+	if (enc_param_change)
+		vidc_720p_encoder_set_param_change(enc_param_change);
+}
+
+static void ddl_encode_set_profile_level(struct ddl_client_context *ddl)
+{
+	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+	u32 profile;
+	u32 level;
+
+	switch (encoder->profile.profile) {
+	default:
+	case VCD_PROFILE_MPEG4_SP:
+		profile = VIDC_720P_PROFILE_MPEG4_SP;
+		break;
+	case VCD_PROFILE_MPEG4_ASP:
+		profile = VIDC_720P_PROFILE_MPEG4_ASP;
+		break;
+	case VCD_PROFILE_H264_BASELINE:
+		profile = VIDC_720P_PROFILE_H264_BASELINE;
+		break;
+	case VCD_PROFILE_H264_MAIN:
+		profile = VIDC_720P_PROFILE_H264_MAIN;
+		break;
+	case VCD_PROFILE_H264_HIGH:
+		profile = VIDC_720P_PROFILE_H264_HIGH;
+		break;
+	case VCD_PROFILE_H263_BASELINE:
+		profile = VIDC_720P_PROFILE_H263_BASELINE;
+		break;
+	}
+	switch (encoder->level.level) {
+	default:
+	case VCD_LEVEL_MPEG4_0:
+		level = VIDC_720P_MPEG4_LEVEL0;
+		break;
+	case VCD_LEVEL_MPEG4_0b:
+		level = VIDC_720P_MPEG4_LEVEL0b;
+		break;
+	case VCD_LEVEL_MPEG4_1:
+		level = VIDC_720P_MPEG4_LEVEL1;
+		break;
+	case VCD_LEVEL_MPEG4_2:
+		level = VIDC_720P_MPEG4_LEVEL2;
+		break;
+	case VCD_LEVEL_MPEG4_3:
+		level = VIDC_720P_MPEG4_LEVEL3;
+		break;
+	case VCD_LEVEL_MPEG4_3b:
+		level = VIDC_720P_MPEG4_LEVEL3b;
+		break;
+	case VCD_LEVEL_MPEG4_4:
+	case VCD_LEVEL_MPEG4_4a:
+		level = VIDC_720P_MPEG4_LEVEL4a;
+		break;
+	case VCD_LEVEL_MPEG4_5:
+		level = VIDC_720P_MPEG4_LEVEL5;
+		break;
+	case VCD_LEVEL_MPEG4_6:
+		level = VIDC_720P_MPEG4_LEVEL6;
+		break;
+	case VCD_LEVEL_H264_1:
+		level = VIDC_720P_H264_LEVEL1;
+		break;
+	case VCD_LEVEL_H264_1b:
+		level = VIDC_720P_H264_LEVEL1b;
+		break;
+	case VCD_LEVEL_H264_1p1:
+		level = VIDC_720P_H264_LEVEL1p1;
+		break;
+	case VCD_LEVEL_H264_1p2:
+		level = VIDC_720P_H264_LEVEL1p2;
+		break;
+	case VCD_LEVEL_H264_1p3:
+		level = VIDC_720P_H264_LEVEL1p3;
+		break;
+	case VCD_LEVEL_H264_2:
+		level = VIDC_720P_H264_LEVEL2;
+		break;
+	case VCD_LEVEL_H264_2p1:
+		level = VIDC_720P_H264_LEVEL2p1;
+		break;
+	case VCD_LEVEL_H264_2p2:
+		level = VIDC_720P_H264_LEVEL2p2;
+		break;
+	case VCD_LEVEL_H264_3:
+		level = VIDC_720P_H264_LEVEL3;
+		break;
+	case VCD_LEVEL_H264_3p1:
+		level = VIDC_720P_H264_LEVEL3p1;
+		break;
+	case VCD_LEVEL_H263_10:
+		level = VIDC_720P_H263_LEVEL10;
+		break;
+	case VCD_LEVEL_H263_20:
+		level = VIDC_720P_H263_LEVEL20;
+		break;
+	case VCD_LEVEL_H263_30:
+		level = VIDC_720P_H263_LEVEL30;
+		break;
+	case VCD_LEVEL_H263_40:
+		level = VIDC_720P_H263_LEVEL40;
+		break;
+	case VCD_LEVEL_H263_45:
+		level = VIDC_720P_H263_LEVEL45;
+		break;
+	case VCD_LEVEL_H263_50:
+		level = VIDC_720P_H263_LEVEL50;
+		break;
+	case VCD_LEVEL_H263_60:
+		level = VIDC_720P_H263_LEVEL60;
+		break;
+	case VCD_LEVEL_H263_70:
+		level = VIDC_720P_H263_LEVEL70;
+		break;
+	}
+	vidc_720p_encode_set_profile(profile, level);
+}
+
+void ddl_encode_init_codec(struct ddl_client_context *ddl)
+{
+	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+	enum vidc_720p_memory_access_method_type mem_access_method;
+	enum vidc_720p_DBConfig_type db_config;
+	enum vidc_720p_MSlice_selection_type m_slice_sel;
+
+	ddl_encode_set_profile_level(ddl);
+
+	vidc_720p_set_frame_size
+	    (encoder->frame_size.width, encoder->frame_size.height);
+	vidc_720p_encode_set_qp_params
+	    (encoder->qp_range.max_qp, encoder->qp_range.min_qp);
+	vidc_720p_encode_set_rc_config
+	    (encoder->rc_level.frame_level_rc,
+	     encoder->rc_level.mb_level_rc,
+	     encoder->session_qp.iframe_qp,
+	     encoder->session_qp.frame_qp);
+
+	if (encoder->r_cframe_skip) {
+		if (encoder->vb_vbuffer_size) {
+			encoder->ext_enc_control_val = (0x2 << 0x2) |
+			(encoder->vb_vbuffer_size << 0x10);
+		} else
+			encoder->ext_enc_control_val = (0x1 << 2);
+	} else
+		encoder->ext_enc_control_val = 0;
+
+	vidc_720p_encode_set_fps
+	    ((encoder->frame_rate.fps_numerator * 1000) /
+	     encoder->frame_rate.fps_denominator);
+
+	vidc_720p_encode_set_vop_time(
+			encoder->vop_timing.vop_time_resolution, 0);
+
+	if (encoder->rc_level.frame_level_rc) {
+		vidc_720p_encode_set_bit_rate
+		    (encoder->target_bit_rate.target_bitrate);
+
+		vidc_720p_encode_set_frame_level_rc_params
+		    (encoder->frame_level_rc.reaction_coeff);
+	}
+	if (encoder->rc_level.mb_level_rc) {
+		vidc_720p_encode_set_mb_level_rc_params
+		    (encoder->adaptive_rc.dark_region_as_flag,
+		     encoder->adaptive_rc.smooth_region_as_flag,
+		     encoder->adaptive_rc.static_region_as_flag,
+		     encoder->adaptive_rc.activity_region_flag);
+	}
+	if (encoder->codec_type.codec == VCD_CODEC_MPEG4) {
+		vidc_720p_encode_set_short_header
+		    (encoder->short_header.short_header);
+
+		if (encoder->hdr_ext_control) {
+			vidc_720p_encode_set_hec_period
+			(encoder->hdr_ext_control);
+			encoder->ext_enc_control_val |= (0x1 << 0x1);
+		}
+	}
+	/* set extended encoder control settings */
+	vidc_720p_encode_set_control_param
+	(encoder->ext_enc_control_val);
+
+	if (encoder->codec_type.codec == VCD_CODEC_H264) {
+		enum vidc_720p_entropy_sel_type entropy_sel;
+		enum vidc_720p_cabac_model_type cabac_model_number;
+		switch (encoder->entropy_control.entropy_sel) {
+		default:
+		case VCD_ENTROPY_SEL_CAVLC:
+			entropy_sel = VIDC_720P_ENTROPY_SEL_CAVLC;
+			break;
+		case VCD_ENTROPY_SEL_CABAC:
+			entropy_sel = VIDC_720P_ENTROPY_SEL_CABAC;
+			break;
+		}
+		switch (encoder->entropy_control.cabac_model) {
+		default:
+		case VCD_CABAC_MODEL_NUMBER_0:
+			cabac_model_number = VIDC_720P_CABAC_MODEL_NUMBER_0;
+			break;
+		case VCD_CABAC_MODEL_NUMBER_1:
+			cabac_model_number = VIDC_720P_CABAC_MODEL_NUMBER_1;
+			break;
+		case VCD_CABAC_MODEL_NUMBER_2:
+			cabac_model_number = VIDC_720P_CABAC_MODEL_NUMBER_2;
+			break;
+		}
+		vidc_720p_encode_set_entropy_control
+		    (entropy_sel, cabac_model_number);
+		switch (encoder->db_control.db_config) {
+		default:
+		case VCD_DB_ALL_BLOCKING_BOUNDARY:
+			db_config = VIDC_720P_DB_ALL_BLOCKING_BOUNDARY;
+			break;
+		case VCD_DB_DISABLE:
+			db_config = VIDC_720P_DB_DISABLE;
+			break;
+		case VCD_DB_SKIP_SLICE_BOUNDARY:
+			db_config = VIDC_720P_DB_SKIP_SLICE_BOUNDARY;
+			break;
+		}
+		vidc_720p_encode_set_db_filter_control
+		    (db_config,
+		     encoder->db_control.slice_alpha_offset,
+		     encoder->db_control.slice_beta_offset);
+	}
+
+	vidc_720p_encode_set_intra_refresh_mb_number
+	    (encoder->intra_refresh.cir_mb_number);
+
+	switch (encoder->multi_slice.m_slice_sel) {
+	default:
+	case VCD_MSLICE_OFF:
+		m_slice_sel = VIDC_720P_MSLICE_OFF;
+		break;
+	case VCD_MSLICE_BY_MB_COUNT:
+		m_slice_sel = VIDC_720P_MSLICE_BY_MB_COUNT;
+		break;
+	case VCD_MSLICE_BY_BYTE_COUNT:
+		m_slice_sel = VIDC_720P_MSLICE_BY_BYTE_COUNT;
+		break;
+	case VCD_MSLICE_BY_GOB:
+		m_slice_sel = VIDC_720P_MSLICE_BY_GOB;
+		break;
+	}
+	vidc_720p_encode_set_multi_slice_info(m_slice_sel,
+		encoder->multi_slice.m_slice_size);
+
+	vidc_720p_encode_set_dpb_buffer(encoder->enc_dpb_addr.phys_addr,
+		encoder->enc_dpb_addr.size);
+
+	pr_debug("ENC_DPB_ADDR_SIZE %u\n", encoder->enc_dpb_addr.size);
+
+	vidc_720p_encode_set_i_period(encoder->period.frames);
+
+	ddl_metadata_enable(ddl);
+
+	if (encoder->seq_header.virt_addr) {
+		phys_addr_t ext_buffer_start;
+		phys_addr_t ext_buffer_end;
+		u32 start_byte_num;
+		ext_buffer_start = encoder->seq_header.phys_addr;
+		ext_buffer_end = ext_buffer_start + encoder->seq_header.size;
+		start_byte_num = ext_buffer_start &
+			DDL_STREAMBUF_ALIGN_GUARD_BYTES;
+		ext_buffer_start &= ~DDL_STREAMBUF_ALIGN_GUARD_BYTES;
+		ext_buffer_end &= ~DDL_STREAMBUF_ALIGN_GUARD_BYTES;
+		pr_debug("ENC_SEQHDR_ALLOC_SIZE %u\n",
+			encoder->seq_header.size);
+		vidc_720p_encode_set_seq_header_buffer(ext_buffer_start,
+			ext_buffer_end,	start_byte_num);
+	}
+
+	if (encoder->re_con_buf_format.buffer_format ==
+		VCD_BUFFER_FORMAT_NV12)
+		mem_access_method = VIDC_720P_TILE_LINEAR;
+	else
+		mem_access_method = VIDC_720P_TILE_16x16;
+
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_INITCODECDONE);
+	ddl_move_command_state(ddl->ddl_context, DDL_CMD_INIT_CODEC);
+
+	vidc_720p_encode_init_codec(ddl->channel_id, mem_access_method);
+}
+
+void ddl_channel_end(struct ddl_client_context *ddl)
+{
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_CHEND);
+	ddl_move_command_state(ddl->ddl_context, DDL_CMD_CHANNEL_END);
+
+	vidc_720p_submit_command(ddl->channel_id, VIDC_720P_CMD_CHEND);
+}
+
+void ddl_encode_frame_run(struct ddl_client_context *ddl)
+{
+	phys_addr_t ext_buffer_start;
+	phys_addr_t ext_buffer_end;
+	phys_addr_t y_addr;
+	phys_addr_t c_addr;
+	u32 start_byte_number;
+	struct ddl_encoder_data *encoder = &ddl->codec_data.encoder;
+	struct vcd_frame_data *stream = &ddl->output_frame.vcd_frm;
+
+	ext_buffer_start = stream->phys_addr + stream->offset;
+	ext_buffer_end = ddl_encode_set_metadata_output_buf(ddl);
+	start_byte_number = ext_buffer_start & DDL_STREAMBUF_ALIGN_GUARD_BYTES;
+	if (start_byte_number) {
+		u32 *data;
+		ext_buffer_start &= ~DDL_STREAMBUF_ALIGN_GUARD_BYTES;
+		data = (u32 *)((u32)stream->virt_addr + stream->offset -
+			start_byte_number);
+		vidc_720p_encode_unalign_bitstream(data[0], data[1]);
+	}
+
+	y_addr = ddl->input_frame.vcd_frm.phys_addr +
+		ddl->input_frame.vcd_frm.offset;
+	c_addr = y_addr + encoder->frame_size.height *
+		encoder->frame_size.width;
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE);
+	ddl_move_command_state(ddl->ddl_context, DDL_CMD_ENCODE_FRAME);
+
+	if (encoder->dynamic_prop_change) {
+		encoder->dynmic_prop_change_req = true;
+		ddl_encode_dynamic_property(ddl, true);
+	}
+	vidc_720p_encode_set_vop_time(encoder->vop_timing.vop_time_resolution,
+		ddl->input_frame.frm_delta);
+
+	vidc_720p_encode_frame(ddl->channel_id, ext_buffer_start,
+		ext_buffer_end, start_byte_number, y_addr, c_addr);
+}
+
+u32 ddl_decode_set_buffers(struct ddl_client_context *ddl)
+{
+	struct ddl_decoder_data *decoder = &(ddl->codec_data.decoder);
+	u32 comv_buf_size = DDL_COMV_BUFLINE_NO, comv_buf_no = 0;
+	u32 ref_buf_no = 0;
+
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_DPB)) {
+		pr_debug("STATE-CRITICAL\n");
+		return VCD_ERR_FAIL;
+	}
+
+	switch (decoder->codec_type.codec) {
+	default:
+	case VCD_CODEC_DIVX_4:
+	case VCD_CODEC_DIVX_5:
+	case VCD_CODEC_DIVX_6:
+	case VCD_CODEC_XVID:
+	case VCD_CODEC_MPEG2:
+	case VCD_CODEC_MPEG4:
+		comv_buf_no = DDL_MPEG_COMV_BUF_NO;
+		ref_buf_no = DDL_MPEG_REFBUF_COUNT;
+		break;
+	case VCD_CODEC_H263:
+		comv_buf_no = DDL_H263_COMV_BUF_NO;
+		break;
+	case VCD_CODEC_VC1:
+	case VCD_CODEC_VC1_RCV:
+		comv_buf_no = decoder->client_output_buf_req.actual_count + 1;
+		comv_buf_size = DDL_VC1_COMV_BUFLINE_NO;
+		break;
+	case VCD_CODEC_H264:
+		comv_buf_no = decoder->client_output_buf_req.actual_count;
+		break;
+	}
+
+	if (comv_buf_no) {
+		comv_buf_size *= (comv_buf_no *
+			(((decoder->client_frame_size.width + 15) >> 4)) *
+			(((decoder->client_frame_size.height + 15) >> 4) + 1));
+		if (!ddl_dma_alloc(&decoder->dpb_comv_buffer, comv_buf_size, npelly_dec_dpb)) {
+			pr_err("Dec_set_buf:Comv_buf_alloc_failed\n");
+			return VCD_ERR_ALLOC_FAIL;
+		}
+		vidc_720p_decode_set_comv_buffer(decoder->dpb_comv_buffer.
+			  phys_addr, decoder->dpb_comv_buffer.size);
+	}
+	decoder->ref_buffer.phys_addr = 0;
+	if (ref_buf_no) {
+		u32 size, yuv_size;
+		yuv_size = ddl_get_yuv_buffer_size(&decoder->
+			client_frame_size, &decoder->buf_format,
+			(!decoder->progressive_only));
+		size = yuv_size * ref_buf_no;
+
+		if (!ddl_dma_alloc(&decoder->ref_buffer, size, npelly_dec_ref)) {
+			ddl_dma_free(&decoder->dpb_comv_buffer);
+			pr_err("Dec_set_buf:mpeg_ref_buf_alloc_failed\n");
+			return VCD_ERR_ALLOC_FAIL;
+		}
+	}
+	ddl_decode_set_metadata_output(decoder);
+
+	ddl_decoder_dpb_transact(decoder, NULL, DDL_DPB_OP_INIT);
+
+	if (decoder->codec_type.codec == VCD_CODEC_H264) {
+		vidc_720p_decode_setH264VSPBuffer(
+			decoder->h264Vsp_temp_buffer.phys_addr);
+		pr_debug("VSP_BUF_ADDR_SIZE %u\n",
+			decoder->h264Vsp_temp_buffer.size);
+	}
+
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_DPBDONE);
+	ddl_move_command_state(ddl->ddl_context, DDL_CMD_DECODE_SET_DPB);
+
+	vidc_720p_submit_command(ddl->channel_id,
+		VIDC_720P_CMD_INITBUFFERS);
+	return VCD_S_SUCCESS;
+}
+
+void ddl_decode_frame_run(struct ddl_client_context *ddl)
+{
+	phys_addr_t ext_buffer_start;
+	phys_addr_t ext_buffer_end = 0;
+	u32 start_byte_num;
+	struct ddl_decoder_data *decoder = &ddl->codec_data.decoder;
+	struct vcd_frame_data *bit_stream = &ddl->input_frame.vcd_frm;
+
+	if (!bit_stream->data_len || !bit_stream->phys_addr) {
+		ddl_decode_eos_run(ddl);
+		return;
+	}
+
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE);
+
+	ddl_decode_dynamic_property(ddl, true);
+
+	ddl_decoder_dpb_transact(decoder, NULL, DDL_DPB_OP_SET_MASK);
+
+	ext_buffer_start = bit_stream->phys_addr + bit_stream->offset;
+	start_byte_num = 8 - (ext_buffer_start &
+		DDL_STREAMBUF_ALIGN_GUARD_BYTES);
+	ext_buffer_end = ext_buffer_start + bit_stream->data_len;
+	ext_buffer_start &= ~DDL_STREAMBUF_ALIGN_GUARD_BYTES;
+	DDL_PADDING_HACK(ext_buffer_end);
+
+	ddl_move_command_state(ddl->ddl_context, DDL_CMD_DECODE_FRAME);
+
+	vidc_720p_decode_frame(ddl->channel_id, ext_buffer_start,
+		ext_buffer_end, bit_stream->data_len, start_byte_num,
+		bit_stream->ip_frm_tag);
+}
+
+void  ddl_decode_eos_run(struct ddl_client_context *ddl)
+{
+	struct ddl_decoder_data *decoder = &ddl->codec_data.decoder;
+
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_EOS_DONE);
+
+	ddl_decode_dynamic_property(ddl, true);
+
+	ddl_decoder_dpb_transact(decoder, NULL, DDL_DPB_OP_SET_MASK);
+
+	decoder->dynmic_prop_change_req = true;
+
+	ddl_move_command_state(ddl->ddl_context, DDL_CMD_EOS);
+
+	vidc_720p_issue_eos(ddl->channel_id);
+}
+
+u32 ddl_hal_engine_reset(struct ddl_context *ddl_context)
+{
+	u32 eng_reset;
+	u32 channel_id = 0;
+	enum vidc_720p_endian_type dma_endian;
+	enum vidc_720p_interrupt_level_selection_type interrupt_sel;
+	u32 intr_mask = 0x0;
+
+	if (ddl_context->current_ddl)
+		channel_id = ddl_context->current_ddl->channel_id;
+
+	interrupt_sel = VIDC_720P_INTERRUPT_LEVEL_SEL;
+	/* Enable all the supported interrupt */
+	intr_mask |= VIDC_720P_INTR_BUFFER_FULL;
+	intr_mask |= VIDC_720P_INTR_FW_DONE;
+	intr_mask |= VIDC_720P_INTR_DMA_DONE;
+	intr_mask |= VIDC_720P_INTR_FRAME_DONE;
+
+	/* use reverse endian after boot code download */
+	dma_endian = VIDC_720P_LITTLE_ENDIAN;
+
+	/* Need to reset MFC silently */
+	eng_reset = vidc_720p_engine_reset(channel_id, dma_endian,
+		interrupt_sel, intr_mask);
+	if (!eng_reset) {
+		/* call the hw fatal callback if engine reset fails */
+		ddl_hw_fatal_cb(ddl_context);
+	}
+	return eng_reset ;
+}
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_helper.c b/drivers/misc/video_core/720p/ddl/vcd_ddl_helper.c
new file mode 100644
index 0000000..17bf125
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_helper.c
@@ -0,0 +1,218 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vcd_ddl_utils.h"
+
+struct ddl_context *ddl_get_context(void)
+{
+	static struct ddl_context ddl_context;
+	return &ddl_context;
+}
+
+void ddl_move_client_state(struct ddl_client_context *ddl,
+	enum ddl_client_state client_state)
+{
+	ddl->client_state = client_state;
+}
+
+void ddl_move_command_state(struct ddl_context *ddl_context,
+	enum ddl_cmd_state command_state)
+{
+	ddl_context->cmd_state = command_state;
+}
+
+u32 ddl_client_transact(u32 operation, struct ddl_client_context **pddl_client)
+{
+	u32 ret_status = VCD_ERR_FAIL;
+	u32 i;
+	struct ddl_context *ddl_context;
+
+	ddl_context = ddl_get_context();
+	switch (operation) {
+	case DDL_FREE_CLIENT:
+		if (pddl_client && *pddl_client) {
+			u32 channel_id;
+			channel_id = (*pddl_client)->channel_id;
+			if (channel_id < VCD_MAX_NO_CLIENT)
+				ddl_context->ddl_clients[channel_id] = NULL;
+			else
+				pr_warn("CHID_CORRUPTION\n");
+			kfree(*pddl_client);
+			*pddl_client = NULL;
+			ret_status = VCD_S_SUCCESS;
+		}
+		break;
+	case DDL_GET_CLIENT:
+		ret_status = VCD_ERR_MAX_CLIENT;
+		for (i = 0; i < VCD_MAX_NO_CLIENT && ret_status ==
+				VCD_ERR_MAX_CLIENT; ++i) {
+			if (!ddl_context->ddl_clients[i]) {
+				*pddl_client = (struct ddl_client_context *)
+					kzalloc((sizeof(
+					struct ddl_client_context)),
+					GFP_KERNEL);
+				if (!*pddl_client) {
+					ret_status = VCD_ERR_ALLOC_FAIL;
+					break;
+				}
+				ddl_context->ddl_clients[i] = *pddl_client;
+				(*pddl_client)->channel_id = i;
+				(*pddl_client)->ddl_context = ddl_context;
+				ret_status = VCD_S_SUCCESS;
+			}
+		}
+		break;
+	case DDL_INIT_CLIENTS:
+		for (i = 0; i < VCD_MAX_NO_CLIENT; ++i)
+			ddl_context->ddl_clients[i] = NULL;
+		ret_status = VCD_S_SUCCESS;
+		break;
+	case DDL_ACTIVE_CLIENT:
+		for (i = 0; i < VCD_MAX_NO_CLIENT; ++i) {
+			if (ddl_context->ddl_clients[i]) {
+				ret_status = VCD_S_SUCCESS;
+				break;
+			}
+		}
+		break;
+	default:
+		ret_status = VCD_ERR_ILLEGAL_PARM;
+		break;
+	}
+	return ret_status;
+}
+
+u32 ddl_decoder_dpb_transact(struct ddl_decoder_data *dec,
+	struct ddl_frame_data_tag *in_out_frame, u32 operation)
+{
+	u32 vcd_status = VCD_S_SUCCESS;
+	u32 i;
+	struct ddl_frame_data_tag *found_frame = NULL;
+	struct ddl_mask *dpb_mask = &dec->dpb_mask;
+
+	switch (operation) {
+	case DDL_DPB_OP_MARK_BUSY:
+	case DDL_DPB_OP_MARK_FREE:
+		for (i = 0; i < dec->dp_buf.no_of_dec_pic_buf; ++i) {
+			if (in_out_frame->vcd_frm.phys_addr == dec->dp_buf.
+					dec_pic_buffers[i].vcd_frm.phys_addr) {
+				found_frame = &dec->dp_buf.dec_pic_buffers[i];
+				break;
+			}
+		}
+
+		if (!found_frame) {
+			in_out_frame->vcd_frm.phys_addr = 0;
+			vcd_status = VCD_ERR_BAD_POINTER;
+			pr_debug("BUF_NOT_FOUND\n");
+			break;
+		}
+		if (operation == DDL_DPB_OP_MARK_BUSY) {
+			dpb_mask->hw_mask &= ~(0x1 << i);
+			*in_out_frame = *found_frame;
+		} else if (operation == DDL_DPB_OP_MARK_FREE) {
+			dpb_mask->client_mask |= 0x1 << i;
+			*found_frame = *in_out_frame;
+		}
+
+		break;
+	case DDL_DPB_OP_SET_MASK:
+		dpb_mask->hw_mask |= dpb_mask->client_mask;
+		dpb_mask->client_mask = 0;
+		vidc_720p_decode_set_dpb_release_buffer_mask(dpb_mask->hw_mask);
+		break;
+	case DDL_DPB_OP_INIT:
+	{
+		size_t dpb_size = !dec->meta_data_offset ?
+			dec->dp_buf.dec_pic_buffers[0].vcd_frm.alloc_len :
+			dec->meta_data_offset;
+		vidc_720p_decode_set_dpb_details(dec->dp_buf.no_of_dec_pic_buf,
+			dpb_size, dec->ref_buffer.phys_addr);
+		for (i = 0; i < dec->dp_buf.no_of_dec_pic_buf; ++i) {
+			vidc_720p_decode_set_dpb_buffers(i, dec->dp_buf.
+				dec_pic_buffers[i].vcd_frm.phys_addr);
+			pr_debug("DEC_DPB_BUFn_SIZE %u\n", dec->dp_buf.
+				dec_pic_buffers[i].vcd_frm.alloc_len);
+		}
+		break;
+	}
+	case DDL_DPB_OP_RETRIEVE:
+	{
+		u32 position;
+		u32 *mask;
+		if (dpb_mask->client_mask) {
+			mask = &dpb_mask->client_mask;
+		} else if (dpb_mask->hw_mask) {
+			mask = &dpb_mask->hw_mask;
+		} else {
+			in_out_frame->vcd_frm.phys_addr = 0;
+			break;
+		}
+		position = 0x1;
+		for (i = 0; i < dec->dp_buf.no_of_dec_pic_buf; ++i) {
+			if (*mask & position) {
+				found_frame = &dec->dp_buf.dec_pic_buffers[i];
+				*mask &= ~position;
+				*in_out_frame = *found_frame;
+				break;
+			}
+			position <<= 1;
+		}
+		if (!found_frame)
+			in_out_frame->vcd_frm.phys_addr = 0;
+		break;
+	}
+	}
+	return vcd_status;
+}
+
+void ddl_release_context_buffers(struct ddl_context *ddl_context)
+{
+	ddl_dma_free(&ddl_context->context_buf_addr);
+	ddl_dma_free(&ddl_context->db_line_buffer);
+	ddl_dma_free(&ddl_context->data_partition_tempbuf);
+	ddl_dma_free(&ddl_context->metadata_shared_input);
+	ddl_dma_free(&ddl_context->dbg_core_dump);
+}
+
+void ddl_release_client_internal_buffers(struct ddl_client_context *ddl)
+{
+	if (ddl->decoding) {
+		struct ddl_decoder_data *dec = &(ddl->codec_data.decoder);
+		ddl_dma_free(&dec->h264Vsp_temp_buffer);
+		ddl_dma_free(&dec->dpb_comv_buffer);
+		ddl_dma_free(&dec->ref_buffer);
+		kfree(dec->dp_buf.dec_pic_buffers);
+		dec->dp_buf.dec_pic_buffers = NULL;
+		ddl_decode_dynamic_property(ddl, false);
+		dec->decode_config.sz = 0;
+		dec->decode_config.addr = 0;
+		dec->dpb_mask.client_mask = 0;
+		dec->dpb_mask.hw_mask = 0;
+		dec->dp_buf.no_of_dec_pic_buf = 0;
+		dec->dynamic_prop_change = 0;
+
+	} else {
+		struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+		ddl_dma_free(&encoder->enc_dpb_addr);
+		ddl_dma_free(&encoder->seq_header);
+		ddl_encode_dynamic_property(ddl, false);
+		encoder->dynamic_prop_change = 0;
+	}
+}
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_internal_property.h b/drivers/misc/video_core/720p/ddl/vcd_ddl_internal_property.h
new file mode 100644
index 0000000..3f3c6e2
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_internal_property.h
@@ -0,0 +1,91 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_DDL_INTERNAL_PROPERTY_H_
+#define _VCD_DDL_INTERNAL_PROPERTY_H_
+#include "vcd_api.h"
+
+#define VCD_EVT_RESP_DDL_BASE          0x3000
+#define VCD_EVT_RESP_DEVICE_INIT       (VCD_EVT_RESP_DDL_BASE + 0x1)
+#define VCD_EVT_RESP_OUTPUT_REQ        (VCD_EVT_RESP_DDL_BASE + 0x2)
+#define VCD_EVT_RESP_EOS_DONE          (VCD_EVT_RESP_DDL_BASE + 0x3)
+#define VCD_EVT_RESP_TRANSACTION_PENDING (VCD_EVT_RESP_DDL_BASE + 0x4)
+
+#define VCD_S_DDL_ERR_BASE     0x90000000
+#define VCD_ERR_MAX_NO_CODEC   (VCD_S_DDL_ERR_BASE + 0x1)
+#define VCD_ERR_CLIENT_PRESENT (VCD_S_DDL_ERR_BASE + 0x2)
+#define VCD_ERR_CLIENT_FATAL   (VCD_S_DDL_ERR_BASE + 0x3)
+
+#define VCD_I_CUSTOM_BASE  (VCD_I_RESERVED_BASE)
+#define VCD_I_RC_LEVEL_CONFIG (VCD_I_CUSTOM_BASE + 0x1)
+#define VCD_I_FRAME_LEVEL_RC (VCD_I_CUSTOM_BASE + 0x2)
+#define VCD_I_ADAPTIVE_RC    (VCD_I_CUSTOM_BASE + 0x3)
+#define VCD_I_CUSTOM_DDL_BASE  (VCD_I_RESERVED_BASE + 0x100)
+#define DDL_I_INPUT_BUF_REQ  (VCD_I_CUSTOM_DDL_BASE + 0x1)
+#define DDL_I_OUTPUT_BUF_REQ (VCD_I_CUSTOM_DDL_BASE + 0x2)
+#define DDL_I_DPB       (VCD_I_CUSTOM_DDL_BASE + 0x3)
+#define DDL_I_DPB_RELEASE    (VCD_I_CUSTOM_DDL_BASE + 0x4)
+#define DDL_I_DPB_RETRIEVE  (VCD_I_CUSTOM_DDL_BASE + 0x5)
+#define DDL_I_REQ_OUTPUT_FLUSH   (VCD_I_CUSTOM_DDL_BASE + 0x6)
+#define DDL_I_SEQHDR_ALIGN_BYTES (VCD_I_CUSTOM_DDL_BASE + 0x7)
+#define DDL_I_SEQHDR_PRESENT (VCD_I_CUSTOM_DDL_BASE + 0xb)
+#define DDL_I_CAPABILITY    (VCD_I_CUSTOM_DDL_BASE + 0x8)
+#define DDL_I_FRAME_PROC_UNITS    (VCD_I_CUSTOM_DDL_BASE + 0x9)
+
+struct vcd_property_rc_level {
+	u32 frame_level_rc;
+	u32 mb_level_rc;
+};
+
+struct vcd_property_frame_level_rc_params {
+	u32 reaction_coeff;
+};
+
+struct vcd_property_adaptive_rc_params {
+	u32 dark_region_as_flag;
+	u32 smooth_region_as_flag;
+	u32 static_region_as_flag;
+	u32 activity_region_flag;
+};
+
+struct ddl_frame_data_tag;
+
+struct ddl_property_dec_pic_buffers {
+	struct ddl_frame_data_tag *dec_pic_buffers;
+	u32 no_of_dec_pic_buf;
+};
+
+struct ddl_property_capability {
+	u32 max_num_client;
+	u32 general_command_depth;
+	u32 frame_command_depth;
+	u32 exclusive;
+	u32 ddl_time_out_in_ms;
+};
+
+#endif
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_interrupt_handler.c b/drivers/misc/video_core/720p/ddl/vcd_ddl_interrupt_handler.c
new file mode 100644
index 0000000..6269f05
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_interrupt_handler.c
@@ -0,0 +1,878 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+
+#include "vcd_ddl_utils.h"
+#include "vcd_ddl_metadata.h"
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+static void ddl_decoder_input_done_callback(struct ddl_client_context *ddl,
+		u32 frame_transact_end);
+static void ddl_decoder_ouput_done_callback(struct ddl_client_context *ddl,
+		u32 frame_transact_end);
+
+static u32 ddl_get_frame_type(struct vcd_frame_data *frame, u32 frame_type);
+
+static void ddl_getdec_profilelevel(struct ddl_decoder_data *dec,
+		u32 profile, u32 level);
+
+static void ddl_dma_done_callback(struct ddl_context *ddl_context)
+{
+	if (!DDLCOMMAND_STATE_IS(ddl_context, DDL_CMD_DMA_INIT)) {
+		pr_debug("UNKNOWN_DMADONE\n");
+		return;
+	}
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+	pr_debug("DMA_DONE");
+	ddl_core_start_cpu(ddl_context);
+}
+
+static void ddl_cpu_started_callback(struct ddl_context *ddl_context)
+{
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+	pr_debug("CPU-STARTED");
+
+	if (!vidc_720p_cpu_start()) {
+		ddl_hw_fatal_cb(ddl_context);
+		return;
+	}
+
+	vidc_720p_set_deblock_line_buffer(ddl_context->db_line_buffer.phys_addr,
+			ddl_context->db_line_buffer.size);
+	ddl_context->device_state = DDL_DEVICE_INITED;
+	ddl_context->ddl_callback(VCD_EVT_RESP_DEVICE_INIT, VCD_S_SUCCESS,
+			NULL, 0, NULL, ddl_context->client_data);
+	DDL_IDLE(ddl_context);
+}
+
+
+static void ddl_eos_done_callback(struct ddl_context *ddl_context)
+{
+	struct ddl_client_context *ddl = ddl_context->current_ddl;
+	u32 displaystatus;
+
+	if (!DDLCOMMAND_STATE_IS(ddl_context, DDL_CMD_EOS)) {
+		pr_debug("UNKWN_EOSDONE");
+		ddl_client_fatal_cb(ddl_context);
+		return;
+	}
+
+	if (!ddl || !ddl->decoding || !DDLCLIENT_STATE_IS(ddl,
+			DDL_CLIENT_WAIT_FOR_EOS_DONE)) {
+		pr_debug("STATE-CRITICAL-EOSDONE");
+		ddl_client_fatal_cb(ddl_context);
+		return;
+	}
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+
+	vidc_720p_eos_info(&displaystatus);
+	if ((enum vidc_720p_display_status_type) displaystatus
+		!= VIDC_720P_EMPTY_BUFFER) {
+		pr_debug("EOSDONE-EMPTYBUF-ISSUE");
+	}
+
+	ddl_decode_dynamic_property(ddl, false);
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME);
+	pr_debug("EOS_DONE");
+	ddl_context->ddl_callback(VCD_EVT_RESP_EOS_DONE, VCD_S_SUCCESS, NULL,
+			0, (u32 *) ddl, ddl_context->client_data);
+
+	DDL_IDLE(ddl_context);
+}
+
+static u32 ddl_channel_set_callback(struct ddl_context *ddl_context)
+{
+	struct ddl_client_context *ddl = ddl_context->current_ddl;
+	u32 return_status = false;
+
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+
+	if (!ddl || !DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_CHDONE)) {
+		pr_debug("STATE-CRITICAL-CHSET");
+		DDL_IDLE(ddl_context);
+		return return_status;
+	}
+	pr_debug("Channel-set");
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_INITCODEC);
+
+	if (ddl->decoding) {
+		if (ddl->codec_data.decoder.header_in_start) {
+			ddl_decode_init_codec(ddl);
+		} else {
+			ddl_context->ddl_callback(VCD_EVT_RESP_START,
+					VCD_S_SUCCESS, NULL, 0, (u32 *) ddl,
+					ddl_context->client_data);
+			DDL_IDLE(ddl_context);
+			return_status = true;
+		}
+	} else {
+		ddl_encode_init_codec(ddl);
+	}
+	return return_status;
+}
+
+static void ddl_init_codec_done_callback(struct ddl_context *ddl_context)
+{
+	struct ddl_client_context *ddl = ddl_context->current_ddl;
+	struct ddl_encoder_data *encoder;
+
+	if (!ddl || ddl->decoding || !DDLCLIENT_STATE_IS(ddl,
+			DDL_CLIENT_WAIT_FOR_INITCODECDONE)) {
+		pr_debug("STATE-CRITICAL-INITCODEC");
+		ddl_client_fatal_cb(ddl_context);
+		return;
+	}
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME);
+	pr_debug("INIT_CODEC_DONE");
+
+	encoder = &ddl->codec_data.encoder;
+	if (encoder->seq_header.virt_addr)
+		vidc_720p_encode_get_header(&encoder->seq_header.size);
+
+	ddl_context->ddl_callback(VCD_EVT_RESP_START, VCD_S_SUCCESS, NULL, 0,
+			(u32 *) ddl, ddl_context->client_data);
+
+	DDL_IDLE(ddl_context);
+}
+
+static u32 ddl_header_done_callback(struct ddl_context *ddl_context)
+{
+	struct ddl_client_context *ddl = ddl_context->current_ddl;
+	struct ddl_decoder_data *dec;
+	struct vidc_720p_seq_hdr_info_type seq_hdr_info;
+	u32 vcd_event = VCD_EVT_RESP_START;
+	u32 vcd_status = VCD_S_SUCCESS;
+	u32 req_cb = true, bret = true;
+
+	if (!DDLCOMMAND_STATE_IS(ddl_context, DDL_CMD_HEADER_PARSE)) {
+		pr_debug("UNKWN_HEADERDONE");
+		ddl_client_fatal_cb(ddl_context);
+		return true;
+	}
+
+	if (!ddl || !ddl->decoding || !DDLCLIENT_STATE_IS(ddl,
+			DDL_CLIENT_WAIT_FOR_INITCODECDONE)) {
+		pr_debug("STATE-CRITICAL-HDDONE");
+		ddl_client_fatal_cb(ddl_context);
+		return true;
+	}
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_DPB);
+	pr_debug("HEADER_DONE");
+
+	vidc_720p_decode_get_seq_hdr_info(&seq_hdr_info);
+
+	dec = &(ddl->codec_data.decoder);
+	dec->frame_size.width = seq_hdr_info.img_size_x;
+	dec->frame_size.height = seq_hdr_info.img_size_y;
+	dec->min_dpb_num = seq_hdr_info.min_num_dpb;
+	dec->y_cb_cr_size = seq_hdr_info.min_dpb_size;
+	dec->progressive_only = 1 - seq_hdr_info.progressive;
+	ddl_getdec_profilelevel(dec, seq_hdr_info.profile, seq_hdr_info.level);
+	ddl_calculate_stride(&dec->frame_size, !dec->progressive_only);
+	if (seq_hdr_info.crop_exists) {
+		dec->frame_size.width -= (seq_hdr_info.crop_right_offset +
+				seq_hdr_info.crop_left_offset);
+		dec->frame_size.height -= (seq_hdr_info.crop_top_offset +
+				seq_hdr_info.crop_bottom_offset);
+	}
+	ddl_set_default_decoder_buffer_req(dec, false);
+	if (seq_hdr_info.data_partitioned == 0x1 &&
+			dec->codec_type.codec == VCD_CODEC_MPEG4 &&
+			seq_hdr_info.img_size_x > DDL_MAX_DP_FRAME_WIDTH &&
+			seq_hdr_info.img_size_y > DDL_MAX_DP_FRAME_HEIGHT) {
+		ddl_client_fatal_cb(ddl_context);
+		return true;
+	}
+
+
+	if (dec->header_in_start) {
+		dec->client_frame_size = dec->frame_size;
+		dec->client_output_buf_req = dec->actual_output_buf_req;
+		if ((dec->frame_size.width * dec->frame_size.height) >=
+				(800*480)) {
+			if ((dec->actual_output_buf_req.actual_count + 2) < 10)
+				dec->client_output_buf_req.actual_count = 10;
+			else
+				dec->client_output_buf_req.actual_count += 2;
+		} else
+			dec->client_output_buf_req.actual_count =
+				dec->actual_output_buf_req.actual_count + 5;
+
+		dec->client_input_buf_req = dec->actual_input_buf_req;
+	} else {
+		DBG("%s(): width = %d client_frame_size.width = %d\n",
+			__func__, dec->frame_size.width,
+			dec->client_frame_size.width);
+		DBG("%s(): height = %d client_frame_size.height = %d\n",
+			__func__, dec->frame_size.height,
+			dec->client_frame_size.height);
+		DBG("%s(): size = %d client_frame_size size = %d\n",
+			__func__, dec->actual_output_buf_req.size,
+			dec->client_output_buf_req.size);
+		DBG("%s(): min_dpb_num = %d actual_count = %d\n", __func__,
+			dec->min_dpb_num,
+			dec->client_output_buf_req.actual_count);
+
+		bret = false;
+
+		if (dec->frame_size.width == dec->client_frame_size.width &&
+				dec->frame_size.height ==
+				dec->client_frame_size.height &&
+				dec->actual_output_buf_req.size <=
+				dec->client_output_buf_req.size &&
+				dec->min_dpb_num <=
+				dec->client_output_buf_req.actual_count) {
+			vcd_status = ddl_decode_set_buffers(ddl);
+			if (!vcd_status) {
+				req_cb = false;
+			} else {
+				ddl_client_fatal_cb(ddl_context);
+				req_cb = true;
+			}
+		} else {
+			dec->client_frame_size = dec->frame_size;
+			dec->client_output_buf_req = dec->actual_output_buf_req;
+			dec->client_input_buf_req = dec->actual_input_buf_req;
+			pr_err("%s:Decode_reconfig_not_supported\n", __func__);
+			vcd_event = VCD_EVT_IND_RECONFIG;
+		}
+	}
+
+	if (req_cb) {
+		ddl_context->ddl_callback(vcd_event, vcd_status, NULL, 0,
+				(u32 *) ddl, ddl_context->client_data);
+		DDL_IDLE(ddl_context);
+	}
+	return bret;
+}
+
+static u32 ddl_dpb_buffers_set_done_callback(struct ddl_context
+					      *ddl_context)
+{
+	struct ddl_client_context *ddl = ddl_context->current_ddl;
+
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+	if (!ddl || !DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_DPBDONE)) {
+		pr_debug("STATE-CRITICAL-DPBDONE\n");
+		ddl_client_fatal_cb(ddl_context);
+		return true;
+	}
+	pr_debug("INTR_DPBDONE\n");
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME);
+	ddl_decode_frame_run(ddl);
+	return false;
+}
+
+static void ddl_encoder_frame_run_callback(struct ddl_context *ddl_context)
+{
+	struct ddl_client_context *ddl = ddl_context->current_ddl;
+	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+	u32 eos_present = false;
+
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE)) {
+		pr_debug("STATE-CRITICAL-ENCFRMRUN\n");
+		ddl_client_fatal_cb(ddl_context);
+		return;
+	}
+
+	pr_debug("ENC_FRM_RUN_DONE\n");
+
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+	vidc_720p_enc_frame_info(&encoder->enc_frame_info);
+
+	ddl->output_frame.vcd_frm.ip_frm_tag =
+		ddl->input_frame.vcd_frm.ip_frm_tag;
+	ddl->output_frame.vcd_frm.data_len =
+		encoder->enc_frame_info.enc_size;
+	ddl->output_frame.vcd_frm.flags |= VCD_FRAME_FLAG_ENDOFFRAME;
+	ddl_get_frame_type(&(ddl->output_frame.vcd_frm),
+		encoder->enc_frame_info.frame_type);
+	ddl_process_encoder_metadata(ddl);
+
+	ddl_encode_dynamic_property(ddl, false);
+
+	ddl->input_frame.frm_trans_end = false;
+	ddl_context->ddl_callback(VCD_EVT_RESP_INPUT_DONE, VCD_S_SUCCESS,
+		&(ddl->input_frame), sizeof(struct ddl_frame_data_tag),
+		(u32 *) ddl, ddl_context->client_data);
+
+#ifdef CORE_TIMING_INFO
+	ddl_calc_core_time(1);
+#endif
+	/* check the presence of EOS */
+	eos_present = VCD_FRAME_FLAG_EOS & ddl->input_frame.vcd_frm.flags;
+
+	ddl->output_frame.frm_trans_end = !eos_present;
+	ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE, VCD_S_SUCCESS,
+		&(ddl->output_frame), sizeof(struct ddl_frame_data_tag),
+		(u32 *) ddl, ddl_context->client_data);
+
+	if (eos_present) {
+		pr_debug("ENC-EOS_DONE\n");
+		ddl_context->ddl_callback(VCD_EVT_RESP_EOS_DONE,
+				VCD_S_SUCCESS, NULL, 0,	(u32 *)ddl,
+				ddl_context->client_data);
+	}
+
+	ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME);
+	DDL_IDLE(ddl_context);
+}
+
+static u32 ddl_decoder_frame_run_callback(struct ddl_context
+					   *ddl_context)
+{
+	struct ddl_client_context *ddl = ddl_context->current_ddl;
+	struct ddl_decoder_data *dec = &(ddl->codec_data.decoder);
+	struct vidc_720p_dec_disp_info *dec_disp_info = &(dec->dec_disp_info);
+	u32 callback_end = false;
+	u32 status = true, eos_present = false;;
+
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE)) {
+		pr_debug("STATE-CRITICAL-DECFRMRUN\n");
+		ddl_client_fatal_cb(ddl_context);
+		return true;
+	}
+
+	pr_debug("DEC_FRM_RUN_DONE\n");
+
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+
+	vidc_720p_decode_display_info(dec_disp_info);
+
+	ddl_decode_dynamic_property(ddl, false);
+
+	if (dec_disp_info->resl_change) {
+		pr_err("ddl_dec_frm_done:"
+			"Dec_reconfig_no_tsupported\n");
+	}
+
+	if ((VCD_FRAME_FLAG_EOS & ddl->input_frame.vcd_frm.flags)) {
+		callback_end = false;
+		eos_present = true;
+	}
+
+	if (dec_disp_info->disp_status == VIDC_720P_DECODE_ONLY ||
+			dec_disp_info->disp_status ==
+			VIDC_720P_DECODE_AND_DISPLAY) {
+		if (!eos_present)
+			callback_end = (dec_disp_info->disp_status ==
+				VIDC_720P_DECODE_ONLY);
+
+		ddl_decoder_input_done_callback(ddl, callback_end);
+	}
+
+	if (dec_disp_info->disp_status == VIDC_720P_DECODE_AND_DISPLAY ||
+			dec_disp_info->disp_status == VIDC_720P_DISPLAY_ONLY) {
+		if (!eos_present)
+			callback_end = (dec_disp_info->disp_status ==
+				VIDC_720P_DECODE_AND_DISPLAY);
+
+		ddl_decoder_ouput_done_callback(ddl, callback_end);
+	}
+
+	if (dec_disp_info->disp_status ==  VIDC_720P_DISPLAY_ONLY) {
+		/* send the same input once again for decoding */
+		ddl_decode_frame_run(ddl);
+		/* client need to ignore the interrupt */
+		status = false;
+	} else if (eos_present) {
+		/* send EOS command to HW */
+		ddl_decode_eos_run(ddl);
+		/* client need to ignore the interrupt */
+		status = false;
+	} else {
+		ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME);
+		/* move to Idle */
+		DDL_IDLE(ddl_context);
+	}
+	return status;
+}
+
+static u32 ddl_eos_frame_done_callback(struct ddl_context *ddl_context)
+{
+	struct ddl_client_context *ddl = ddl_context->current_ddl;
+	struct ddl_decoder_data *dec = &(ddl->codec_data.decoder);
+	struct vidc_720p_dec_disp_info *dec_disp_info =
+		&(dec->dec_disp_info);
+
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_EOS_DONE)) {
+		pr_err("STATE-CRITICAL-EOSFRMRUN\n");
+		ddl_client_fatal_cb(ddl_context);
+		return true;
+	}
+	pr_debug("EOS_FRM_RUN_DONE\n");
+
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+
+	vidc_720p_decode_display_info(dec_disp_info);
+
+	ddl_decode_dynamic_property(ddl, false);
+
+	if (ddl_context->op_failed == 0x1)
+		pr_err("ddl_eos_frm_done:OPFAILED!!\n");
+	else if (dec_disp_info->resl_change)
+		pr_err("ddl_eos_frm_done:Dec_reconfig!!\n");
+
+	if (dec_disp_info->disp_status == VIDC_720P_DISPLAY_ONLY)
+		ddl_decoder_ouput_done_callback(ddl, false);
+	else
+		pr_debug("STATE-CRITICAL-WRONG-DISP-STATUS\n");
+
+	ddl_decoder_dpb_transact(dec, NULL, DDL_DPB_OP_SET_MASK);
+	ddl_move_command_state(ddl_context, DDL_CMD_EOS);
+	vidc_720p_submit_command(ddl->channel_id, VIDC_720P_CMD_FRAMERUN);
+	return false;
+}
+
+static void ddl_channel_end_callback(struct ddl_context *ddl_context)
+{
+	struct ddl_client_context *ddl;
+
+	ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
+	pr_debug("CH_END_DONE\n");
+
+	ddl = ddl_context->current_ddl;
+	if (!ddl || !DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_CHEND)) {
+		pr_debug("STATE-CRITICAL-CHEND\n");
+		DDL_IDLE(ddl_context);
+		return;
+	}
+
+	ddl_release_client_internal_buffers(ddl);
+	ddl_context->ddl_callback(VCD_EVT_RESP_STOP, VCD_S_SUCCESS, NULL, 0,
+		(u32 *) ddl, ddl_context->client_data);
+	ddl_move_client_state(ddl, DDL_CLIENT_OPEN);
+	DDL_IDLE(ddl_context);
+}
+
+static u32 ddl_operation_done_callback(struct ddl_context *ddl_context)
+{
+	u32 return_status = true;
+
+	switch (ddl_context->cmd_state) {
+	case DDL_CMD_DECODE_FRAME:
+		return_status = ddl_decoder_frame_run_callback(ddl_context);
+		break;
+	case DDL_CMD_ENCODE_FRAME:
+		ddl_encoder_frame_run_callback(ddl_context);
+		break;
+	case DDL_CMD_CHANNEL_SET:
+		return_status = ddl_channel_set_callback(ddl_context);
+		break;
+	case DDL_CMD_INIT_CODEC:
+		ddl_init_codec_done_callback(ddl_context);
+		break;
+	case DDL_CMD_HEADER_PARSE:
+		return_status = ddl_header_done_callback(ddl_context);
+		break;
+	case DDL_CMD_DECODE_SET_DPB:
+		return_status = ddl_dpb_buffers_set_done_callback(ddl_context);
+		break;
+	case DDL_CMD_CHANNEL_END:
+		ddl_channel_end_callback(ddl_context);
+		break;
+	case DDL_CMD_EOS:
+		return_status = ddl_eos_frame_done_callback(ddl_context);
+		break;
+	case DDL_CMD_CPU_RESET:
+		ddl_cpu_started_callback(ddl_context);
+		break;
+	default:
+		pr_debug("UNKWN_OPDONE\n");
+		return_status = false;
+		break;
+	}
+	return return_status;
+}
+
+static u32 ddl_process_intr_status(struct ddl_context *ddl_context,
+			u32 int_status)
+{
+	u32 status = true;
+	switch (int_status) {
+	case VIDC_720P_INTR_FRAME_DONE:
+		status = ddl_operation_done_callback(ddl_context);
+		break;
+	case VIDC_720P_INTR_DMA_DONE:
+		ddl_dma_done_callback(ddl_context);
+		status = false;
+		break;
+	case VIDC_720P_INTR_FW_DONE:
+		ddl_eos_done_callback(ddl_context);
+		break;
+	case VIDC_720P_INTR_BUFFER_FULL:
+		pr_err("BUF_FULL_INTR\n");
+		break;
+	default:
+		pr_err("UNKWN_INTR\n");
+		break;
+	}
+	return status;
+}
+
+void ddl_read_and_clear_interrupt(void)
+{
+	struct ddl_context *ddl_context;
+
+	ddl_context = ddl_get_context();
+	if (!ddl_context->core_virtual_base_addr) {
+		pr_err("SPURIOUS_INTERRUPT\n");
+		return;
+	}
+	vidc_720p_get_interrupt_status(&ddl_context->intr_status,
+		&ddl_context->cmd_err_status,
+		&ddl_context->disp_pic_err_status,
+		&ddl_context->op_failed);
+
+	vidc_720p_interrupt_done_clear();
+}
+
+u32 ddl_process_core_response(void)
+{
+	struct ddl_context *ddl_context;
+	u32 return_status = true;
+
+	ddl_context = ddl_get_context();
+	if (!ddl_context->core_virtual_base_addr) {
+		pr_err("UNKWN_INTR\n");
+		return false;
+	}
+	if (ddl_context->intr_status == DDL_INVALID_INTR_STATUS) {
+		pr_err("INTERRUPT_NOT_READ\n");
+		return false;
+	}
+
+	if (!ddl_handle_core_errors(ddl_context)) {
+		return_status = ddl_process_intr_status(ddl_context,
+			ddl_context->intr_status);
+	}
+
+	if (ddl_context->pf_interrupt_clr)
+		(*ddl_context->pf_interrupt_clr)();
+
+	ddl_context->intr_status = DDL_INVALID_INTR_STATUS;
+	return return_status;
+}
+
+static void ddl_decoder_input_done_callback(
+	struct	ddl_client_context *ddl, u32 frame_transact_end)
+{
+	struct vidc_720p_dec_disp_info *dec_disp_info =
+		&(ddl->codec_data.decoder.dec_disp_info);
+	struct vcd_frame_data *input_vcd_frm = &(ddl->input_frame.vcd_frm);
+	ddl_get_frame_type(input_vcd_frm, dec_disp_info->input_frame_type);
+
+	input_vcd_frm->interlaced = (dec_disp_info->input_is_interlace);
+
+	input_vcd_frm->offset += dec_disp_info->input_bytes_consumed;
+	input_vcd_frm->data_len -= dec_disp_info->input_bytes_consumed;
+
+	ddl->input_frame.frm_trans_end = frame_transact_end;
+	ddl->ddl_context->ddl_callback(VCD_EVT_RESP_INPUT_DONE,
+		VCD_S_SUCCESS,
+		&ddl->input_frame,
+		sizeof(struct ddl_frame_data_tag),
+		(void *)ddl,
+		ddl->ddl_context->client_data);
+}
+
+static void ddl_decoder_ouput_done_callback(struct ddl_client_context *ddl,
+	u32 frame_transact_end)
+{
+	struct ddl_decoder_data *dec = &ddl->codec_data.decoder;
+	struct vidc_720p_dec_disp_info *dec_disp_info =	&dec->dec_disp_info;
+	struct ddl_frame_data_tag *output_frame = &ddl->output_frame;
+	struct vcd_frame_data *output_vcd_frm = &output_frame->vcd_frm;
+	u32 vcd_status;
+	phys_addr_t free_luma_dpb = 0;
+
+	output_vcd_frm->phys_addr = dec_disp_info->y_addr;
+
+	if (dec->codec_type.codec == VCD_CODEC_MPEG4 ||
+			dec->codec_type.codec == VCD_CODEC_VC1 ||
+			dec->codec_type.codec == VCD_CODEC_VC1_RCV) {
+		vidc_720p_decode_skip_frm_details(&free_luma_dpb);
+		if (free_luma_dpb)
+			output_vcd_frm->phys_addr = free_luma_dpb;
+	}
+
+	vcd_status = ddl_decoder_dpb_transact(dec, output_frame,
+		DDL_DPB_OP_MARK_BUSY);
+
+	output_vcd_frm->ip_frm_tag =  dec_disp_info->tag_top;
+	if (dec_disp_info->crop_exists == 0x1) {
+		output_vcd_frm->dec_op_prop.disp_frm.left =
+			dec_disp_info->crop_left_offset;
+		output_vcd_frm->dec_op_prop.disp_frm.top =
+			dec_disp_info->crop_top_offset;
+		output_vcd_frm->dec_op_prop.disp_frm.right =
+			dec_disp_info->img_size_x -
+			dec_disp_info->crop_right_offset;
+		output_vcd_frm->dec_op_prop.disp_frm.bottom =
+			dec_disp_info->img_size_y -
+			dec_disp_info->crop_bottom_offset;
+	} else {
+		output_vcd_frm->dec_op_prop.disp_frm.left = 0;
+		output_vcd_frm->dec_op_prop.disp_frm.top = 0;
+		output_vcd_frm->dec_op_prop.disp_frm.right =
+			dec_disp_info->img_size_x;
+		output_vcd_frm->dec_op_prop.disp_frm.bottom =
+			dec_disp_info->img_size_y;
+	}
+	if (!dec_disp_info->disp_is_interlace) {
+		output_vcd_frm->interlaced = false;
+		output_frame->intrlcd_ip_frm_tag = VCD_FRAMETAG_INVALID;
+	} else {
+		output_vcd_frm->interlaced = true;
+		output_frame->intrlcd_ip_frm_tag = dec_disp_info->tag_bottom;
+	}
+
+	output_vcd_frm->offset = 0;
+	output_vcd_frm->data_len = dec->y_cb_cr_size;
+
+	if (free_luma_dpb)
+		output_vcd_frm->data_len = 0;
+
+	output_vcd_frm->flags |= VCD_FRAME_FLAG_ENDOFFRAME;
+
+	if (!vcd_status)
+		ddl_process_decoder_metadata(ddl);
+	output_frame->frm_trans_end = frame_transact_end;
+
+#ifdef CORE_TIMING_INFO
+	ddl_calc_core_time(0);
+#endif
+
+	ddl->ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
+		vcd_status, output_frame, sizeof(struct ddl_frame_data_tag),
+		(void *)ddl, ddl->ddl_context->client_data);
+}
+
+static u32 ddl_get_frame_type(struct vcd_frame_data *frame, u32 frame_type)
+{
+	enum vidc_720p_frame_type e_frame_type =
+		(enum vidc_720p_frame_type)frame_type;
+	u32 status = true;
+
+	switch (e_frame_type) {
+	case VIDC_720P_IFRAME:
+		frame->flags |= VCD_FRAME_FLAG_SYNCFRAME;
+		frame->frame_type = VCD_FRAME_I;
+		break;
+	case VIDC_720P_PFRAME:
+		frame->frame_type = VCD_FRAME_P;
+		break;
+	case VIDC_720P_BFRAME:
+		frame->frame_type = VCD_FRAME_B;
+		break;
+	case VIDC_720P_NOTCODED:
+		frame->data_len = 0;
+		break;
+	default:
+		pr_debug("CRITICAL-FRAMETYPE\n");
+		status = false;
+		break;
+	}
+	return status;
+}
+
+static void ddl_getmpeg4_declevel(enum vcd_codec_level_type *vcd_level,
+	u32 level)
+{
+	switch (level) {
+	case VIDC_720P_MPEG4_LEVEL0:
+		*vcd_level = VCD_LEVEL_MPEG4_0;
+		break;
+	case VIDC_720P_MPEG4_LEVEL0b:
+		*vcd_level = VCD_LEVEL_MPEG4_0b;
+		break;
+	case VIDC_720P_MPEG4_LEVEL1:
+		*vcd_level = VCD_LEVEL_MPEG4_1;
+		break;
+	case VIDC_720P_MPEG4_LEVEL2:
+		*vcd_level = VCD_LEVEL_MPEG4_2;
+		break;
+	case VIDC_720P_MPEG4_LEVEL3:
+		*vcd_level = VCD_LEVEL_MPEG4_3;
+		break;
+	case VIDC_720P_MPEG4_LEVEL3b:
+		*vcd_level = VCD_LEVEL_MPEG4_3b;
+		break;
+	case VIDC_720P_MPEG4_LEVEL4a:
+		*vcd_level = VCD_LEVEL_MPEG4_4a;
+		break;
+	case VIDC_720P_MPEG4_LEVEL5:
+		*vcd_level = VCD_LEVEL_MPEG4_5;
+		break;
+	case VIDC_720P_MPEG4_LEVEL6:
+		*vcd_level = VCD_LEVEL_MPEG4_6;
+		break;
+	}
+}
+
+static void ddl_geth264_declevel(enum vcd_codec_level_type *vcd_level,
+		u32 level)
+{
+	switch (level) {
+	case VIDC_720P_H264_LEVEL1:
+		*vcd_level = VCD_LEVEL_H264_1;
+		break;
+	case VIDC_720P_H264_LEVEL1b:
+		*vcd_level = VCD_LEVEL_H264_1b;
+		break;
+	case VIDC_720P_H264_LEVEL1p1:
+		*vcd_level = VCD_LEVEL_H264_1p1;
+		break;
+	case VIDC_720P_H264_LEVEL1p2:
+		*vcd_level = VCD_LEVEL_H264_1p2;
+		break;
+	case VIDC_720P_H264_LEVEL1p3:
+		*vcd_level = VCD_LEVEL_H264_1p3;
+		break;
+	case VIDC_720P_H264_LEVEL2:
+		*vcd_level = VCD_LEVEL_H264_2;
+		break;
+	case VIDC_720P_H264_LEVEL2p1:
+		*vcd_level = VCD_LEVEL_H264_2p1;
+		break;
+	case VIDC_720P_H264_LEVEL2p2:
+		*vcd_level = VCD_LEVEL_H264_2p2;
+		break;
+	case VIDC_720P_H264_LEVEL3:
+		*vcd_level = VCD_LEVEL_H264_3;
+		break;
+	case VIDC_720P_H264_LEVEL3p1:
+		*vcd_level = VCD_LEVEL_H264_3p1;
+		break;
+	case VIDC_720P_H264_LEVEL3p2:
+		*vcd_level = VCD_LEVEL_H264_3p2;
+		break;
+	}
+}
+
+static void ddl_get_vc1_dec_level(enum vcd_codec_level_type *vcd_level,
+		u32 level, enum vcd_codec_profile_type vc1_profile)
+{
+	if (vc1_profile == VCD_PROFILE_VC1_ADVANCE) {
+		switch (level) {
+		case VIDC_720P_VC1_LEVEL0:
+			*vcd_level = VCD_LEVEL_VC1_0;
+			break;
+		case VIDC_720P_VC1_LEVEL1:
+			*vcd_level = VCD_LEVEL_VC1_1;
+			break;
+		case VIDC_720P_VC1_LEVEL2:
+			*vcd_level = VCD_LEVEL_VC1_2;
+			break;
+		case VIDC_720P_VC1_LEVEL3:
+			*vcd_level = VCD_LEVEL_VC1_3;
+			break;
+		case VIDC_720P_VC1_LEVEL4:
+			*vcd_level = VCD_LEVEL_VC1_4;
+			break;
+		}
+		return;
+	}
+
+	/* now determine the Main and Simple profile level */
+	switch (level) {
+	case VIDC_720P_VC1_LEVEL_LOW:
+		*vcd_level = VCD_LEVEL_VC1_LOW;
+		break;
+	case VIDC_720P_VC1_LEVEL_MED:
+		*vcd_level = VCD_LEVEL_VC1_MEDIUM;
+		break;
+	case VIDC_720P_VC1_LEVEL_HIGH:
+		*vcd_level = VCD_LEVEL_VC1_HIGH;
+		break;
+	}
+}
+
+static void ddl_get_mpeg2_dec_level(enum vcd_codec_level_type *vcd_level,
+		u32 level)
+{
+	switch (level) {
+	case VIDCL_720P_MPEG2_LEVEL_LOW:
+		*vcd_level = VCD_LEVEL_MPEG2_LOW;
+		break;
+	case VIDCL_720P_MPEG2_LEVEL_MAIN:
+		*vcd_level = VCD_LEVEL_MPEG2_MAIN;
+		break;
+	case VIDCL_720P_MPEG2_LEVEL_HIGH14:
+		*vcd_level = VCD_LEVEL_MPEG2_HIGH_14;
+		break;
+	}
+}
+
+static void ddl_getdec_profilelevel(struct ddl_decoder_data *dec,
+		u32 profile, u32 level)
+{
+	enum vcd_codec_profile_type vcd_profile = VCD_PROFILE_UNKNOWN;
+	enum vcd_codec_level_type vcd_level = VCD_LEVEL_UNKNOWN;
+
+	switch (dec->codec_type.codec) {
+	case VCD_CODEC_MPEG4:
+		if (profile == VIDC_720P_PROFILE_MPEG4_SP)
+			vcd_profile = VCD_PROFILE_MPEG4_SP;
+		else if (profile == VIDC_720P_PROFILE_MPEG4_ASP)
+			vcd_profile = VCD_PROFILE_MPEG4_ASP;
+
+		ddl_getmpeg4_declevel(&vcd_level, level);
+		break;
+	case VCD_CODEC_H264:
+		if (profile == VIDC_720P_PROFILE_H264_BASELINE)
+			vcd_profile = VCD_PROFILE_H264_BASELINE;
+		else if (profile == VIDC_720P_PROFILE_H264_MAIN)
+			vcd_profile = VCD_PROFILE_H264_MAIN;
+		else if (profile == VIDC_720P_PROFILE_H264_HIGH)
+			vcd_profile = VCD_PROFILE_H264_HIGH;
+		ddl_geth264_declevel(&vcd_level, level);
+		break;
+	default:
+	case VCD_CODEC_H263:
+		break;
+	case VCD_CODEC_VC1:
+	case VCD_CODEC_VC1_RCV:
+		if (profile == VIDC_720P_PROFILE_VC1_SP)
+			vcd_profile = VCD_PROFILE_VC1_SIMPLE;
+		else if (profile == VIDC_720P_PROFILE_VC1_MAIN)
+			vcd_profile = VCD_PROFILE_VC1_MAIN;
+		else if (profile == VIDC_720P_PROFILE_VC1_ADV)
+			vcd_profile = VCD_PROFILE_VC1_ADVANCE;
+		ddl_get_vc1_dec_level(&vcd_level, level, vcd_profile);
+		break;
+	case VCD_CODEC_MPEG2:
+		if (profile == VIDC_720P_PROFILE_MPEG2_MAIN)
+			vcd_profile = VCD_PROFILE_MPEG2_MAIN;
+		else if (profile == VIDC_720P_PROFILE_MPEG2_SP)
+			vcd_profile = VCD_PROFILE_MPEG2_SIMPLE;
+		ddl_get_mpeg2_dec_level(&vcd_level, level);
+		break;
+	}
+
+	dec->profile.profile = vcd_profile;
+	dec->level.level = vcd_level;
+}
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_metadata.c b/drivers/misc/video_core/720p/ddl/vcd_ddl_metadata.c
new file mode 100644
index 0000000..230e7ec
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_metadata.c
@@ -0,0 +1,545 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vcd_ddl_utils.h"
+#include "vcd_ddl_metadata.h"
+
+static u32 *ddl_metadata_hdr_entry(struct ddl_client_context *ddl,
+	u32 meta_data_type)
+{
+	u32 skip_words;
+	u32 *buffer;
+
+	if (ddl->decoding) {
+		buffer = ddl->codec_data.decoder.meta_data_input.virt_addr;
+		skip_words = 32 + 1;
+		buffer += skip_words;
+
+		switch (meta_data_type) {
+		default:
+		case VCD_METADATA_DATANONE:
+			skip_words = 0;
+			break;
+		case VCD_METADATA_QPARRAY:
+			skip_words = 3;
+			break;
+		case VCD_METADATA_CONCEALMB:
+			skip_words = 6;
+			break;
+		case VCD_METADATA_VC1:
+			skip_words = 9;
+			break;
+		case VCD_METADATA_SEI:
+			skip_words = 12;
+			break;
+		case VCD_METADATA_VUI:
+			skip_words = 15;
+			break;
+		case VCD_METADATA_PASSTHROUGH:
+			skip_words = 18;
+			break;
+		case VCD_METADATA_QCOMFILLER:
+			skip_words = 21;
+			break;
+		}
+	} else {
+		buffer = ddl->codec_data.encoder.meta_data_input.virt_addr;
+		skip_words = 2;
+		buffer += skip_words;
+
+		switch (meta_data_type) {
+		default:
+		case VCD_METADATA_DATANONE:
+			skip_words = 0;
+			break;
+		case VCD_METADATA_ENC_SLICE:
+			skip_words = 3;
+			break;
+		case VCD_METADATA_QCOMFILLER:
+			skip_words = 6;
+			break;
+		}
+	}
+
+	buffer += skip_words;
+	return buffer;
+}
+
+void ddl_set_default_meta_data_hdr(struct ddl_client_context *ddl)
+{
+	struct ddl_dma_buffer *main_buffer =
+		&ddl->ddl_context->metadata_shared_input;
+	struct ddl_dma_buffer *b;
+	u32 *hdr;
+
+	if (ddl->decoding)
+		b = &ddl->codec_data.decoder.meta_data_input;
+	else
+		b = &ddl->codec_data.encoder.meta_data_input;
+
+	b->phys_addr = main_buffer->phys_addr +
+		DDL_METADATA_CLIENT_INPUTBUFSIZE * ddl->channel_id;
+	b->virt_addr = (void *)((u8 *)main_buffer->virt_addr +
+		DDL_METADATA_CLIENT_INPUTBUFSIZE * ddl->channel_id);
+
+	hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_QCOMFILLER);
+	hdr[DDL_METADATA_HDR_VERSION_INDEX] = 1;
+	hdr[DDL_METADATA_HDR_PORT_INDEX] = 1;
+	hdr[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_QCOMFILLER;
+
+	hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_DATANONE);
+	hdr[DDL_METADATA_HDR_VERSION_INDEX] = 2;
+	hdr[DDL_METADATA_HDR_PORT_INDEX] = 2;
+	hdr[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_DATANONE;
+
+	if (ddl->decoding) {
+		hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_QPARRAY);
+		hdr[DDL_METADATA_HDR_VERSION_INDEX] = 3;
+		hdr[DDL_METADATA_HDR_PORT_INDEX] = 3;
+		hdr[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_QPARRAY;
+
+		hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_CONCEALMB);
+		hdr[DDL_METADATA_HDR_VERSION_INDEX] = 4;
+		hdr[DDL_METADATA_HDR_PORT_INDEX] = 4;
+		hdr[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_CONCEALMB;
+
+		hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_SEI);
+		hdr[DDL_METADATA_HDR_VERSION_INDEX] = 5;
+		hdr[DDL_METADATA_HDR_PORT_INDEX] = 5;
+		hdr[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_SEI;
+
+		hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_VUI);
+		hdr[DDL_METADATA_HDR_VERSION_INDEX] = 6;
+		hdr[DDL_METADATA_HDR_PORT_INDEX] = 6;
+		hdr[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_VUI;
+
+		hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_VC1);
+		hdr[DDL_METADATA_HDR_VERSION_INDEX] = 7;
+		hdr[DDL_METADATA_HDR_PORT_INDEX] = 7;
+		hdr[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_VC1;
+
+		hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_PASSTHROUGH);
+		hdr[DDL_METADATA_HDR_VERSION_INDEX] = 8;
+		hdr[DDL_METADATA_HDR_PORT_INDEX] = 8;
+		hdr[DDL_METADATA_HDR_TYPE_INDEX] =
+			VCD_METADATA_PASSTHROUGH;
+
+	} else {
+		hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_ENC_SLICE);
+		hdr[DDL_METADATA_HDR_VERSION_INDEX] = 9;
+		hdr[DDL_METADATA_HDR_PORT_INDEX] = 9;
+		hdr[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_ENC_SLICE;
+	}
+}
+
+static u32 ddl_supported_metadata_flag(struct ddl_client_context *ddl)
+{
+	u32 flag = 0;
+
+	if (ddl->decoding) {
+		enum vcd_codec codec =
+			ddl->codec_data.decoder.codec_type.codec;
+
+		flag |= VCD_METADATA_CONCEALMB | VCD_METADATA_PASSTHROUGH |
+				VCD_METADATA_QPARRAY;
+		if (codec == VCD_CODEC_H264)
+			flag |= VCD_METADATA_SEI | VCD_METADATA_VUI;
+		else if (codec == VCD_CODEC_VC1 || codec == VCD_CODEC_VC1_RCV)
+			flag |= VCD_METADATA_VC1;
+	} else {
+		flag |= VCD_METADATA_ENC_SLICE;
+	}
+
+	return flag;
+}
+
+void ddl_set_default_metadata_flag(struct ddl_client_context *ddl)
+{
+	if (ddl->decoding)
+		ddl->codec_data.decoder.meta_data_enable_flag = 0;
+	else
+		ddl->codec_data.encoder.meta_data_enable_flag = 0;
+}
+
+void ddl_set_default_decoder_metadata_buffer_size(struct ddl_decoder_data *dec,
+	struct vcd_property_frame_size *frame_size,
+	struct vcd_buffer_requirement *output_buf_req)
+{
+	u32 flag = dec->meta_data_enable_flag;
+	u32 suffix = 0;
+	u32 size = 0;
+
+	if (!flag) {
+		dec->suffix = 0;
+		return;
+	}
+
+	if (flag & VCD_METADATA_QPARRAY) {
+		u32 num_of_mb = ((frame_size->width * frame_size->height) >> 8);
+		size = DDL_METADATA_HDR_SIZE;
+		size += num_of_mb;
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += size;
+	}
+	if (flag & VCD_METADATA_CONCEALMB) {
+		u32 num_of_mb = ((frame_size->width * frame_size->height) >> 8);
+		size = DDL_METADATA_HDR_SIZE;
+		size *= (4 * num_of_mb / 2);
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += size;
+	}
+	if (flag & VCD_METADATA_VC1) {
+		size = DDL_METADATA_HDR_SIZE;
+		size += DDL_METADATA_VC1_PAYLOAD_SIZE;
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += size;
+	}
+	if (flag & VCD_METADATA_SEI) {
+		size = DDL_METADATA_HDR_SIZE;
+		size += DDL_METADATA_SEI_PAYLOAD_SIZE;
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += (size * DDL_METADATA_SEI_MAX);
+	}
+	if (flag & VCD_METADATA_VUI) {
+		size = DDL_METADATA_HDR_SIZE;
+		size += DDL_METADATA_VUI_PAYLOAD_SIZE;
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += (size);
+	}
+	if (flag & VCD_METADATA_PASSTHROUGH) {
+		size = DDL_METADATA_HDR_SIZE;
+		size += DDL_METADATA_PASSTHROUGH_PAYLOAD_SIZE;
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += (size);
+	}
+	size = DDL_METADATA_EXTRADATANONE_SIZE;
+	DDL_METADATA_ALIGNSIZE(size);
+	suffix += (size);
+
+	suffix += DDL_METADATA_EXTRAPAD_SIZE;
+	DDL_METADATA_ALIGNSIZE(suffix);
+
+	dec->suffix = suffix;
+	output_buf_req->size += suffix;
+	return;
+}
+
+void ddl_set_default_encoder_metadata_buffer_size(struct ddl_encoder_data *enc)
+{
+	u32 flag = enc->meta_data_enable_flag;
+	u32 suffix = 0;
+	u32 size = 0;
+
+	if (!flag) {
+		enc->suffix = 0;
+		return;
+	}
+
+	if (flag & VCD_METADATA_ENC_SLICE) {
+		u32 num_of_mb = enc->frame_size.width * enc->frame_size.height /
+			16 / 16;
+		size = DDL_METADATA_HDR_SIZE + 4 + 8 * num_of_mb;
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += size;
+	}
+
+	size = DDL_METADATA_EXTRADATANONE_SIZE;
+	DDL_METADATA_ALIGNSIZE(size);
+	suffix += (size);
+
+	suffix += DDL_METADATA_EXTRAPAD_SIZE;
+	DDL_METADATA_ALIGNSIZE(suffix);
+
+	enc->suffix = suffix;
+	enc->output_buf_req.size += suffix;
+}
+
+static u32 ddl_set_metadata_enable_client_open(struct ddl_client_context *ddl,
+	struct vcd_property_meta_data_enable *meta_data_enable,
+	u32 *meta_data_enable_flag)
+{
+	if (!meta_data_enable->meta_data_enable_flag) {
+		*meta_data_enable_flag = 0;
+		if (ddl->decoding) {
+			ddl_set_default_decoder_buffer_req(
+				&ddl->codec_data.decoder, true);
+		} else {
+			ddl_set_default_encoder_buffer_req(
+				&ddl->codec_data.encoder);
+		}
+
+	} else {
+		u32 flag = ddl_supported_metadata_flag(ddl);
+		flag &= meta_data_enable->meta_data_enable_flag;
+		if (flag) {
+			flag |= DDL_METADATA_MANDATORY;
+			if (flag != *meta_data_enable_flag) {
+				*meta_data_enable_flag = flag;
+
+				if (ddl->decoding) {
+					ddl_set_default_decoder_buffer_req(
+						&ddl->codec_data.decoder, true);
+				} else {
+					ddl_set_default_encoder_buffer_req(
+						&ddl->codec_data.encoder);
+				}
+
+			}
+		}
+	}
+	return VCD_S_SUCCESS;
+}
+
+static u32 ddl_set_metadata_header(struct ddl_client_context *ddl,
+	struct vcd_property_hdr *property_hdr,
+	struct vcd_property_metadata_hdr *hdr)
+{
+	u32 flag;
+	if (sizeof(struct vcd_property_metadata_hdr) != property_hdr->sz)
+		return VCD_ERR_ILLEGAL_PARM;
+
+	flag = ddl_supported_metadata_flag(ddl);
+	flag |= DDL_METADATA_MANDATORY;
+	flag &= hdr->meta_data_id_type;
+	if (!(flag & (flag - 1))) {
+		u32 *hdr_entry = ddl_metadata_hdr_entry(ddl, flag);
+		hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = hdr->version;
+		hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = hdr->port_index;
+		hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = hdr->type;
+		return VCD_S_SUCCESS;
+	}
+	return VCD_ERR_ILLEGAL_PARM;
+}
+
+u32 ddl_set_metadata_params(struct ddl_client_context *ddl,
+	struct vcd_property_hdr *prop, void *value)
+{
+	u32 vcd_status = VCD_ERR_ILLEGAL_PARM;
+	if (prop->id == VCD_I_METADATA_ENABLE) {
+		struct vcd_property_meta_data_enable *meta_data_enable =
+			(struct vcd_property_meta_data_enable *)value;
+		u32 *meta_data_enable_flag;
+		enum vcd_codec codec;
+		if (ddl->decoding) {
+			meta_data_enable_flag = &ddl->codec_data.decoder.
+				meta_data_enable_flag;
+			codec = ddl->codec_data.decoder.codec_type.codec;
+		} else {
+			meta_data_enable_flag = &ddl->codec_data.encoder.
+				meta_data_enable_flag;
+			codec = ddl->codec_data.encoder.codec_type.codec;
+		}
+		if (sizeof(struct vcd_property_meta_data_enable) == prop->sz &&
+				DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN) &&
+				codec) {
+			vcd_status = ddl_set_metadata_enable_client_open(ddl,
+				meta_data_enable, meta_data_enable_flag);
+		}
+	} else if (prop->id == VCD_I_METADATA_HEADER) {
+		vcd_status = ddl_set_metadata_header(ddl, prop, value);
+	}
+	return vcd_status;
+}
+
+u32 ddl_get_metadata_params(struct ddl_client_context *ddl,
+	struct vcd_property_hdr *prop, void *value)
+{
+	u32 vcd_status = VCD_ERR_ILLEGAL_PARM;
+	struct vcd_property_meta_data_enable *enable;
+	struct vcd_property_metadata_hdr *hdr;
+
+	if (prop->id == VCD_I_METADATA_ENABLE && prop->sz == sizeof(*enable)) {
+		enable = value;
+		enable->meta_data_enable_flag = ddl->decoding ?
+			ddl->codec_data.decoder.meta_data_enable_flag :
+			ddl->codec_data.encoder.meta_data_enable_flag;
+		vcd_status = VCD_S_SUCCESS;
+	} else if (prop->id == VCD_I_METADATA_HEADER &&
+			sizeof(*hdr) == prop->sz) {
+		u32 flag = ddl_supported_metadata_flag(ddl);
+		hdr = value;
+		flag |= DDL_METADATA_MANDATORY;
+		flag &= hdr->meta_data_id_type;
+		if (!(flag & (flag - 1))) {
+			u32 *hdr_entry = ddl_metadata_hdr_entry(ddl, flag);
+			hdr->version =
+				hdr_entry[DDL_METADATA_HDR_VERSION_INDEX];
+			hdr->port_index =
+				hdr_entry[DDL_METADATA_HDR_PORT_INDEX];
+			hdr->type = hdr_entry[DDL_METADATA_HDR_TYPE_INDEX];
+			vcd_status = VCD_S_SUCCESS;
+		}
+	}
+	return vcd_status;
+}
+
+void ddl_metadata_enable(struct ddl_client_context *ddl)
+{
+	u32 flag, hal_flag = 0;
+	phys_addr_t input;
+	if (ddl->decoding) {
+		flag = ddl->codec_data.decoder.meta_data_enable_flag;
+		input = ddl->codec_data.decoder.meta_data_input.phys_addr;
+	} else {
+		flag = ddl->codec_data.encoder.meta_data_enable_flag;
+		input = ddl->codec_data.encoder.meta_data_input.phys_addr;
+	}
+	if (flag) {
+		if (flag & VCD_METADATA_QPARRAY)
+			hal_flag |= VIDC_720P_METADATA_ENABLE_QP;
+		if (flag & VCD_METADATA_CONCEALMB)
+			hal_flag |= VIDC_720P_METADATA_ENABLE_CONCEALMB;
+		if (flag & VCD_METADATA_VC1)
+			hal_flag |= VIDC_720P_METADATA_ENABLE_VC1;
+		if (flag & VCD_METADATA_SEI)
+			hal_flag |= VIDC_720P_METADATA_ENABLE_SEI;
+		if (flag & VCD_METADATA_VUI)
+			hal_flag |= VIDC_720P_METADATA_ENABLE_VUI;
+		if (flag & VCD_METADATA_ENC_SLICE)
+			hal_flag |= VIDC_720P_METADATA_ENABLE_ENCSLICE;
+		if (flag & VCD_METADATA_PASSTHROUGH)
+			hal_flag |= VIDC_720P_METADATA_ENABLE_PASSTHROUGH;
+	} else {
+		input = 0;
+	}
+	vidc_720p_metadata_enable(hal_flag, input);
+}
+
+phys_addr_t ddl_encode_set_metadata_output_buf(struct ddl_client_context *ddl)
+{
+	struct ddl_encoder_data *encoder = &ddl->codec_data.encoder;
+	u32 *buffer;
+	struct vcd_frame_data *stream = &(ddl->output_frame.vcd_frm);
+	phys_addr_t ext_buffer_end;
+	phys_addr_t hw_metadata_start;
+
+	ext_buffer_end = stream->phys_addr + stream->alloc_len;
+	if (!encoder->meta_data_enable_flag) {
+		ext_buffer_end &= ~DDL_STREAMBUF_ALIGN_GUARD_BYTES;
+		return ext_buffer_end;
+	}
+	hw_metadata_start = (ext_buffer_end - encoder->suffix) &
+		~DDL_STREAMBUF_ALIGN_GUARD_BYTES;
+
+	ext_buffer_end = (hw_metadata_start - 1) &
+		~DDL_STREAMBUF_ALIGN_GUARD_BYTES;
+
+	buffer = encoder->meta_data_input.virt_addr;
+
+	*buffer++ = encoder->suffix;
+
+	*buffer = hw_metadata_start;
+
+	encoder->meta_data_offset = hw_metadata_start - stream->phys_addr;
+
+	return ext_buffer_end;
+}
+
+void ddl_decode_set_metadata_output(struct ddl_decoder_data *dec)
+{
+	int i;
+	u32 *buffer;
+
+	if (!dec->meta_data_enable_flag) {
+		dec->meta_data_offset = 0;
+		return;
+	}
+
+	dec->meta_data_offset = ddl_get_yuv_buffer_size(&dec->client_frame_size,
+		&dec->buf_format, !dec->progressive_only);
+
+	buffer = dec->meta_data_input.virt_addr;
+
+	*buffer++ = dec->suffix;
+
+	for (i = 0; i < dec->dp_buf.no_of_dec_pic_buf; ++i)
+		*buffer++ = dec->dp_buf.dec_pic_buffers[i].vcd_frm.phys_addr +
+			dec->meta_data_offset;
+}
+
+//TOOD consider combining ddl_process_xxx_metadata
+void ddl_process_encoder_metadata(struct ddl_client_context *ddl)
+{
+	struct ddl_encoder_data *enc = &ddl->codec_data.encoder;
+	struct vcd_frame_data *frm = &ddl->output_frame.vcd_frm;
+	u32 *qfill_hdr;
+	u32 *qfill;
+	unsigned long tmp;
+	size_t qfill_sz;
+
+	if (!enc->meta_data_enable_flag) {
+		frm->flags &= ~VCD_FRAME_FLAG_EXTRADATA;
+		return;
+	}
+
+	if (!enc->enc_frame_info.metadata_exists) {
+		frm->flags &= ~VCD_FRAME_FLAG_EXTRADATA;
+		return;
+	}
+	frm->flags |= VCD_FRAME_FLAG_EXTRADATA;
+
+	tmp = (unsigned long)frm->virt_addr + frm->offset + frm->data_len;
+	qfill = (u32 *)ALIGN(tmp, 4);
+
+	qfill_sz = enc->meta_data_offset + (u8 *)frm->virt_addr - (u8 *)qfill;
+
+	qfill_hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_QCOMFILLER);
+
+	*qfill++ = qfill_sz;
+	*qfill++ = qfill_hdr[DDL_METADATA_HDR_VERSION_INDEX];
+	*qfill++ = qfill_hdr[DDL_METADATA_HDR_PORT_INDEX];
+	*qfill++ = qfill_hdr[DDL_METADATA_HDR_TYPE_INDEX];
+	*qfill = qfill_sz - DDL_METADATA_HDR_SIZE;
+}
+
+void ddl_process_decoder_metadata(struct ddl_client_context *ddl)
+{
+	struct ddl_decoder_data *dec = &ddl->codec_data.decoder;
+	struct vcd_frame_data *frm = &ddl->output_frame.vcd_frm;
+	u32 *qfill_hdr;
+	u32 *qfill;
+	size_t qfill_sz;
+	unsigned long tmp;
+
+	if (!dec->meta_data_enable_flag) {
+		frm->flags &= ~VCD_FRAME_FLAG_EXTRADATA;
+		return;
+	}
+	if (!dec->dec_disp_info.metadata_exists) {
+		frm->flags &= ~VCD_FRAME_FLAG_EXTRADATA;
+		return;
+	}
+	frm->flags |= VCD_FRAME_FLAG_EXTRADATA;
+
+	if (frm->data_len == dec->meta_data_offset)
+		return;
+
+	tmp = (unsigned long)frm->virt_addr + frm->offset + frm->data_len;
+	qfill = (u32 *)ALIGN(tmp, 4);
+
+	qfill_sz = dec->meta_data_offset + (u8 *)frm->virt_addr - (u8 *)qfill;
+
+	qfill_hdr = ddl_metadata_hdr_entry(ddl,	VCD_METADATA_QCOMFILLER);
+
+	*qfill++ = qfill_sz;
+	*qfill++ = qfill_hdr[DDL_METADATA_HDR_VERSION_INDEX];
+	*qfill++ = qfill_hdr[DDL_METADATA_HDR_PORT_INDEX];
+	*qfill++ = qfill_hdr[DDL_METADATA_HDR_TYPE_INDEX];
+	*qfill = qfill_sz - DDL_METADATA_HDR_SIZE;
+}
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_metadata.h b/drivers/misc/video_core/720p/ddl/vcd_ddl_metadata.h
new file mode 100644
index 0000000..b0fa84c
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_metadata.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_DDL_METADATA_H_
+#define _VCD_DDL_METADATA_H_
+
+#define DDL_MAX_DEC_METADATATYPE  (8)
+#define DDL_MAX_ENC_METADATATYPE  (3)
+
+#define DDL_METADATA_EXTRAPAD_SIZE (256)
+#define DDL_METADATA_HDR_SIZE (20)
+
+#define DDL_METADATA_EXTRADATANONE_SIZE (24)
+
+#define DDL_METADATA_ALIGNSIZE(x) ((x) = (((x) + 0x7) & ~0x7))
+
+#define DDL_METADATA_MANDATORY (VCD_METADATA_DATANONE | VCD_METADATA_QCOMFILLER)
+
+#define DDL_METADATA_VC1_PAYLOAD_SIZE (38*4)
+
+#define DDL_METADATA_SEI_PAYLOAD_SIZE (100)
+#define DDL_METADATA_SEI_MAX (5)
+
+#define DDL_METADATA_VUI_PAYLOAD_SIZE (256)
+
+#define DDL_METADATA_PASSTHROUGH_PAYLOAD_SIZE  (68)
+
+#define DDL_METADATA_CLIENT_INPUTBUFSIZE  (256)
+#define DDL_METADATA_TOTAL_INPUTBUFSIZE \
+	(DDL_METADATA_CLIENT_INPUTBUFSIZE * VCD_MAX_NO_CLIENT)
+
+#define DDL_METADATA_HDR_VERSION_INDEX 0
+#define DDL_METADATA_HDR_PORT_INDEX    1
+#define DDL_METADATA_HDR_TYPE_INDEX    2
+
+
+void ddl_set_default_meta_data_hdr(struct ddl_client_context *ddl);
+u32 ddl_get_metadata_params(struct ddl_client_context	*ddl,
+	struct vcd_property_hdr *property_hdr, void *property_value);
+u32 ddl_set_metadata_params(struct ddl_client_context *ddl,
+	struct vcd_property_hdr *property_hdr, void *property_value);
+void ddl_set_default_metadata_flag(struct ddl_client_context *ddl);
+void ddl_set_default_decoder_metadata_buffer_size(struct ddl_decoder_data *dec,
+	struct vcd_property_frame_size *frame_size,
+	struct vcd_buffer_requirement *output_buf_req);
+void ddl_set_default_encoder_metadata_buffer_size(struct ddl_encoder_data *enc);
+void ddl_metadata_enable(struct ddl_client_context *ddl);
+phys_addr_t ddl_encode_set_metadata_output_buf(struct ddl_client_context *ddl);
+void ddl_decode_set_metadata_output(struct ddl_decoder_data *decoder);
+void ddl_process_encoder_metadata(struct ddl_client_context *ddl);
+void ddl_process_decoder_metadata(struct ddl_client_context *ddl);
+
+#endif
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_properties.c b/drivers/misc/video_core/720p/ddl/vcd_ddl_properties.c
new file mode 100644
index 0000000..6e4037b
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_properties.c
@@ -0,0 +1,1395 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+
+#include "vcd_ddl_utils.h"
+#include "vcd_ddl_metadata.h"
+
+static u32 ddl_set_dec_property(struct ddl_client_context *pddl,
+	struct vcd_property_hdr *hdr, void *value);
+static u32 ddl_set_enc_property(struct ddl_client_context *pddl,
+	struct vcd_property_hdr *hdr, void *value);
+static u32 ddl_get_dec_property(struct ddl_client_context *pddl,
+	struct vcd_property_hdr *hdr, void *value);
+static u32 ddl_get_enc_property(struct ddl_client_context *pddl,
+	struct vcd_property_hdr *hdr, void *value);
+static u32 ddl_set_enc_dynamic_property(struct ddl_encoder_data *enc,
+	struct vcd_property_hdr *hdr, void *value);
+static void ddl_set_default_enc_property(struct ddl_client_context *ddl);
+static void ddl_set_default_enc_profile(struct ddl_encoder_data *enc);
+static void ddl_set_default_enc_level(struct ddl_encoder_data *enc);
+static void ddl_set_default_enc_vop_timing(struct ddl_encoder_data *enc);
+static void ddl_set_default_enc_intra_period(struct ddl_encoder_data *enc);
+static void ddl_set_default_enc_rc_params(struct ddl_encoder_data *enc);
+static u32 ddl_valid_buffer_requirement(struct vcd_buffer_requirement
+	*orig, struct vcd_buffer_requirement *req);
+static u32 ddl_decoder_min_num_dpb(struct ddl_decoder_data *dec);
+static u32 ddl_set_dec_buffers(struct ddl_decoder_data *dec,
+	struct ddl_property_dec_pic_buffers *dpb);
+
+u32 ddl_set_property(u32 *ddl_handle, struct vcd_property_hdr *hdr,
+	void *value)
+{
+	u32 vcd_status;
+	struct ddl_context *ddl_context;
+	struct ddl_client_context *ddl = (struct ddl_client_context *)
+		ddl_handle;
+
+	if (!hdr || !value) {
+		pr_err("ddl_set_prop:Bad_argument\n");
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+	ddl_context = ddl_get_context();
+
+	if (!DDL_IS_INITIALIZED(ddl_context)) {
+		pr_err("ddl_set_prop:Not_inited\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	if (!ddl) {
+		pr_err("ddl_set_prop:Bad_handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+	if (ddl->decoding)
+		vcd_status = ddl_set_dec_property(ddl, hdr, value);
+	else
+		vcd_status = ddl_set_enc_property(ddl, hdr, value);
+	if (vcd_status)
+		pr_err("ddl_set_prop:FAILED\n");
+
+	return vcd_status;
+}
+
+u32 ddl_get_property(u32 *ddl_handle, struct vcd_property_hdr *hdr, void *value)
+{
+	u32 vcd_status = VCD_ERR_ILLEGAL_PARM;
+	struct ddl_context *ddl_context;
+	struct ddl_client_context *ddl = (struct ddl_client_context *)
+		ddl_handle;
+
+	if (!hdr || !value)
+		return VCD_ERR_ILLEGAL_PARM;
+
+	if (hdr->id == DDL_I_CAPABILITY) {
+		struct ddl_property_capability *cap;
+		if (sizeof(*cap) == hdr->sz) {
+			cap = value;
+			cap->max_num_client = VCD_MAX_NO_CLIENT;
+			cap->exclusive = VCD_COMMAND_EXCLUSIVE;
+			cap->frame_command_depth = VCD_FRAME_COMMAND_DEPTH;
+			cap->general_command_depth = VCD_GENERAL_COMMAND_DEPTH;
+			cap->ddl_time_out_in_ms = DDL_HW_TIMEOUT_IN_MS;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		return vcd_status;
+	}
+	ddl_context = ddl_get_context();
+	if (!DDL_IS_INITIALIZED(ddl_context))
+		return VCD_ERR_ILLEGAL_OP;
+
+	if (!ddl)
+		return VCD_ERR_BAD_HANDLE;
+
+	if (ddl->decoding)
+		vcd_status = ddl_get_dec_property(ddl, hdr, value);
+	else
+		vcd_status = ddl_get_enc_property(ddl, hdr, value);
+	if (vcd_status)
+		pr_err("ddl_get_prop:FAILED\n");
+
+	return vcd_status;
+}
+
+u32 ddl_decoder_ready_to_start(struct ddl_client_context *ddl,
+	struct vcd_phys_sequence_hdr *seq_hdr)
+{
+	struct ddl_decoder_data *dec = &ddl->codec_data.decoder;
+	if (!dec->codec_type.codec) {
+		pr_err("ddl_dec_start_check:Codec_not_set\n");
+		return false;
+	}
+	if (!seq_hdr && (!dec->client_frame_size.height ||
+			!dec->client_frame_size.width)) {
+		pr_err("ddl_dec_start_check:"
+			"Client_height_width_default\n");
+		return false;
+	}
+	return true;
+}
+
+u32 ddl_encoder_ready_to_start(struct ddl_client_context *ddl)
+{
+	struct ddl_encoder_data *enc = &ddl->codec_data.encoder;
+
+	if (!enc->codec_type.codec || !enc->frame_size.height ||
+			!enc->frame_size.width ||
+			!enc->frame_rate.fps_denominator ||
+			!enc->frame_rate.fps_numerator ||
+			!enc->target_bit_rate.target_bitrate) {
+		return false;
+	}
+	return true;
+}
+
+static u32 ddl_set_dec_property(struct ddl_client_context *ddl,
+		struct vcd_property_hdr *hdr, void *value) {
+	u32 vcd_status = VCD_ERR_ILLEGAL_PARM;
+	struct ddl_decoder_data *dec = &ddl->codec_data.decoder;
+	switch (hdr->id) {
+	case DDL_I_DPB_RELEASE:
+		if (sizeof(struct ddl_frame_data_tag) == hdr->sz &&
+				dec->dp_buf.no_of_dec_pic_buf) {
+			vcd_status = ddl_decoder_dpb_transact(dec, value,
+				DDL_DPB_OP_MARK_FREE);
+		}
+		break;
+	case DDL_I_DPB:
+	{
+		struct ddl_property_dec_pic_buffers *dpb = value;
+		if (sizeof(*dpb) == hdr->sz &&
+				(DDLCLIENT_STATE_IS(ddl,
+				DDL_CLIENT_WAIT_FOR_INITCODEC) ||
+				DDLCLIENT_STATE_IS(ddl,
+				DDL_CLIENT_WAIT_FOR_DPB)) &&
+				dpb->no_of_dec_pic_buf >=
+				dec->client_output_buf_req.actual_count) {
+			vcd_status = ddl_set_dec_buffers(dec, dpb);
+		}
+		break;
+	}
+	case DDL_I_REQ_OUTPUT_FLUSH:
+		if (sizeof(u32) == hdr->sz) {
+			dec->dynamic_prop_change |= DDL_DEC_REQ_OUTPUT_FLUSH;
+			dec->dpb_mask.client_mask = 0;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case DDL_I_INPUT_BUF_REQ:
+	{
+		struct vcd_buffer_requirement *buf_req = value;
+		if (sizeof(*buf_req) == hdr->sz &&
+				ddl_valid_buffer_requirement(
+				&dec->min_input_buf_req, buf_req)) {
+			dec->client_input_buf_req = *buf_req;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case DDL_I_OUTPUT_BUF_REQ:
+	{
+		struct vcd_buffer_requirement *buf_req = value;
+		if (sizeof(*buf_req) == hdr->sz &&
+				ddl_valid_buffer_requirement(
+				&dec->min_output_buf_req, buf_req)) {
+			dec->client_output_buf_req = *buf_req;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_CODEC:
+	{
+		struct vcd_property_codec *codec = value;
+		if (sizeof(*codec) == hdr->sz &&
+				DDLCLIENT_STATE_IS(ddl,	DDL_CLIENT_OPEN)) {
+			if (!vcd_fw_is_codec_supported(true, codec->codec)) {
+				vcd_status = VCD_ERR_NOT_SUPPORTED;
+				break;
+			}
+			dec->codec_type = *codec;
+			ddl_set_default_dec_property(ddl);
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_POST_FILTER:
+		if (sizeof(struct vcd_property_post_filter) == hdr->sz &&
+				DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN) &&
+				(dec->codec_type.codec == VCD_CODEC_MPEG4 ||
+				dec->codec_type.codec == VCD_CODEC_MPEG2)) {
+			dec->post_filter = *(struct vcd_property_post_filter *)
+				value;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_FRAME_SIZE:
+	{
+		struct vcd_property_frame_size *frame_size = value;
+		if ((sizeof(*frame_size) == hdr->sz) &&
+				DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN)) {
+			if (dec->client_frame_size.height != frame_size->height
+					|| dec->client_frame_size.width !=
+					frame_size->width) {
+				dec->client_frame_size = *frame_size;
+				ddl_calculate_stride(&dec->client_frame_size,
+					!dec->progressive_only);
+				ddl_set_default_decoder_buffer_req(dec, true);
+			}
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_BUFFER_FORMAT:
+	{
+		struct vcd_property_buffer_format *tile = value;
+		if (sizeof(*tile) == hdr->sz &&
+				DDLCLIENT_STATE_IS(ddl,	DDL_CLIENT_OPEN) &&
+				(tile->buffer_format ==	VCD_BUFFER_FORMAT_NV12
+				|| tile->buffer_format ==
+				VCD_BUFFER_FORMAT_TILE_4x2)) {
+			if (tile->buffer_format !=
+					dec->buf_format.buffer_format) {
+				dec->buf_format = *tile;
+				ddl_set_default_decoder_buffer_req(dec,	true);
+			}
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_METADATA_ENABLE:
+	case VCD_I_METADATA_HEADER:
+		vcd_status = ddl_set_metadata_params(ddl, hdr, value);
+		break;
+	default:
+		vcd_status = VCD_ERR_ILLEGAL_OP;
+		break;
+	}
+	return vcd_status;
+}
+
+static u32 ddl_set_enc_property(struct ddl_client_context *ddl,
+	struct vcd_property_hdr *hdr, void *value)
+{
+	u32 vcd_status = VCD_ERR_ILLEGAL_PARM;
+	struct ddl_encoder_data *enc = &ddl->codec_data.encoder;
+
+	if (DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME)) {
+		vcd_status = ddl_set_enc_dynamic_property(enc, hdr, value);
+		return vcd_status;
+	}
+
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN)) {
+		pr_err("ddl_set_enc_property:"
+				"Fails_as_not_in_open_state\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	switch (hdr->id) {
+	case VCD_I_TARGET_BITRATE:
+	{
+		struct vcd_property_target_bitrate *bitrate = value;
+		if (sizeof(*bitrate) == hdr->sz &&
+				bitrate->target_bitrate) {
+			enc->target_bit_rate = *bitrate;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_FRAME_RATE:
+	{
+		struct vcd_property_frame_rate *framerate = value;
+		if (sizeof(*framerate) == hdr->sz &&
+				framerate->fps_denominator &&
+				framerate->fps_numerator) {
+			enc->frame_rate = *framerate;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_FRAME_SIZE:
+	{
+		struct vcd_property_frame_size *framesize = value;
+		if (sizeof(*framesize) == hdr->sz &&
+				DDL_ALLOW_ENC_FRAMESIZE(framesize->width,
+				framesize->height)) {
+			enc->frame_size = *framesize;
+			ddl_calculate_stride(&enc->frame_size, false);
+			ddl_set_default_encoder_buffer_req(enc);
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_CODEC:
+	{
+		struct vcd_property_codec *codec = value;
+		if (sizeof(*codec) == hdr->sz) {
+			if (!vcd_fw_is_codec_supported(false, codec->codec)) {
+				vcd_status = VCD_ERR_NOT_SUPPORTED;
+				break;
+			}
+			enc->codec_type = *codec;
+			ddl_set_default_enc_property(ddl);
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_REQ_IFRAME:
+		vcd_status = VCD_S_SUCCESS;
+		break;
+	case VCD_I_INTRA_PERIOD:
+	{
+		struct vcd_property_i_period *iperiod = value;
+		if (sizeof(*iperiod) == hdr->sz && !iperiod->bframes) {
+			enc->period = *iperiod;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_PROFILE:
+	{
+		struct vcd_property_profile *profile = value;
+		if (sizeof(*profile) == hdr->sz &&
+				((enc->codec_type.codec == VCD_CODEC_MPEG4 &&
+				(profile->profile == VCD_PROFILE_MPEG4_SP ||
+				profile->profile == VCD_PROFILE_MPEG4_ASP)) ||
+				((enc->codec_type.codec == VCD_CODEC_H264 &&
+				profile->profile >= VCD_PROFILE_H264_BASELINE &&
+				profile->profile <= VCD_PROFILE_H264_HIGH)) ||
+				(enc->codec_type.codec == VCD_CODEC_H263 &&
+				profile->profile == VCD_PROFILE_H263_BASELINE))
+				) {
+			enc->profile = *profile;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_LEVEL:
+	{
+		struct vcd_property_level *level = value;
+		if (sizeof(*level) == hdr->sz &&
+				((enc->codec_type.codec == VCD_CODEC_MPEG4 &&
+				level->level >= VCD_LEVEL_MPEG4_0 &&
+				level->level <= VCD_LEVEL_MPEG4_6) ||
+				(enc->codec_type.codec == VCD_CODEC_H264 &&
+				level->level >= VCD_LEVEL_H264_1 &&
+				level->level <= VCD_LEVEL_H264_3p1) ||
+				(enc->codec_type.codec == VCD_CODEC_H263 &&
+				level->level >= VCD_LEVEL_H263_10 &&
+				level->level <= VCD_LEVEL_H263_70))) {
+			enc->level = *level;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_MULTI_SLICE:
+	{
+		struct vcd_property_multi_slice *multislice = value;
+		switch (multislice->m_slice_sel) {
+		case VCD_MSLICE_OFF:
+			vcd_status = VCD_S_SUCCESS;
+			break;
+		case VCD_MSLICE_BY_GOB:
+			if (enc->codec_type.codec == VCD_CODEC_H263)
+				vcd_status = VCD_S_SUCCESS;
+			 break;
+		case VCD_MSLICE_BY_MB_COUNT:
+			if (multislice->m_slice_size >= 1 &&
+					(multislice->m_slice_size <=
+					(enc->frame_size.height
+					* enc->frame_size.width	/ 16 / 16))) {
+				vcd_status = VCD_S_SUCCESS;
+			}
+			break;
+		case VCD_MSLICE_BY_BYTE_COUNT:
+			if (multislice->m_slice_size <
+					DDL_MINIMUM_BYTE_PER_SLICE) {
+				vcd_status = VCD_S_SUCCESS;
+				break;
+			}
+		default:
+			break;
+		}
+		if (sizeof(struct vcd_property_multi_slice) == hdr->sz &&
+				!vcd_status) {
+			enc->multi_slice = *multislice;
+		}
+		break;
+	}
+	case VCD_I_RATE_CONTROL:
+	{
+		struct vcd_property_rate_control *ratecontrol_type = value;
+		if (sizeof(*ratecontrol_type) == hdr->sz &&
+				ratecontrol_type->rate_control >=
+				VCD_RATE_CONTROL_OFF &&
+				ratecontrol_type->rate_control <=
+				VCD_RATE_CONTROL_CBR_CFR) {
+			enc->rc_type = *ratecontrol_type;
+			ddl_set_default_enc_rc_params(enc);
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_SHORT_HEADER:
+		if (sizeof(struct vcd_property_short_header) ==	hdr->sz &&
+				enc->codec_type.codec == VCD_CODEC_MPEG4) {
+			enc->short_header =
+				*(struct vcd_property_short_header *)value;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_VOP_TIMING:
+	{
+		struct vcd_property_vop_timing *voptime = value;
+		if (sizeof(*voptime) == hdr->sz && enc->frame_rate.fps_numerator
+				<= voptime->vop_time_resolution) {
+			enc->vop_timing = *voptime;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_HEADER_EXTENSION:
+		if (sizeof(u32) == hdr->sz && enc->codec_type.codec ==
+				VCD_CODEC_MPEG4) {
+			enc->hdr_ext_control = *(u32 *)value;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_ENTROPY_CTRL:
+	{
+		struct vcd_property_entropy_control *entropy = value;
+		if (sizeof(*entropy) == hdr->sz &&
+				enc->codec_type.codec == VCD_CODEC_H264 &&
+				entropy->entropy_sel >= VCD_ENTROPY_SEL_CAVLC &&
+				entropy->entropy_sel <= VCD_ENTROPY_SEL_CABAC) {
+			enc->entropy_control = *entropy;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_DEBLOCKING:
+	{
+		struct vcd_property_db_config *db = value;
+		if (sizeof(*db) == hdr->sz &&
+				enc->codec_type.codec == VCD_CODEC_H264	&&
+				db->db_config >= VCD_DB_ALL_BLOCKING_BOUNDARY &&
+				db->db_config <= VCD_DB_SKIP_SLICE_BOUNDARY) {
+			enc->db_control = *db;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_QP_RANGE:
+	{
+		struct vcd_property_qp_range *qp = value;
+		if (sizeof(*qp) == hdr->sz && qp->min_qp <= qp->max_qp &&
+				((enc->codec_type.codec == VCD_CODEC_H264 &&
+				qp->max_qp <= DDL_MAX_H264_QP) ||
+				qp->max_qp <= DDL_MAX_MPEG4_QP)) {
+			enc->qp_range = *qp;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_SESSION_QP:
+	{
+		struct vcd_property_session_qp *qp = value;
+		if ((sizeof(*qp) == hdr->sz) &&
+				qp->iframe_qp >= enc->qp_range.min_qp &&
+				qp->iframe_qp <= enc->qp_range.max_qp &&
+				qp->frame_qp >= enc->qp_range.min_qp &&
+				qp->frame_qp <= enc->qp_range.max_qp) {
+			enc->session_qp = *qp;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_RC_LEVEL_CONFIG:
+	{
+		struct vcd_property_rc_level *rc_level = value;
+		if (sizeof(*rc_level) == hdr->sz &&
+				(enc->rc_type.rate_control >=
+				VCD_RATE_CONTROL_VBR_VFR ||
+				enc->rc_type.rate_control <=
+				VCD_RATE_CONTROL_CBR_VFR) &&
+				(!rc_level->mb_level_rc ||
+				enc->codec_type.codec == VCD_CODEC_H264)) {
+			enc->rc_level = *rc_level;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_FRAME_LEVEL_RC:
+	{
+		struct vcd_property_frame_level_rc_params *rc = value;
+		if (sizeof(*rc) == hdr->sz && rc->reaction_coeff &&
+				enc->rc_level.frame_level_rc) {
+			enc->frame_level_rc = *rc;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_ADAPTIVE_RC:
+	{
+		struct vcd_property_adaptive_rc_params *rc = value;
+		if (sizeof(*rc) == hdr->sz && enc->codec_type.codec ==
+				VCD_CODEC_H264 && enc->rc_level.mb_level_rc) {
+			enc->adaptive_rc = *rc;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_INTRA_REFRESH:
+	{
+		struct vcd_property_intra_refresh_mb_number *mbnum = value;
+		u32 frame_mbnum = (enc->frame_size.width / 16) *
+			(enc->frame_size.height / 16);
+		if (sizeof(*mbnum) == hdr->sz && mbnum->cir_mb_number <=
+				frame_mbnum) {
+			enc->intra_refresh = *mbnum;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_BUFFER_FORMAT:
+	{
+		struct vcd_property_buffer_format *tile = value;
+		if (sizeof(*tile) == hdr->sz && tile->buffer_format ==
+				VCD_BUFFER_FORMAT_NV12) {
+			enc->buf_format = *tile;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case DDL_I_INPUT_BUF_REQ:
+	{
+		struct vcd_buffer_requirement *buf_req = value;
+		if (sizeof(*buf_req) == hdr->sz && ddl_valid_buffer_requirement(
+				&enc->input_buf_req, buf_req)) {
+			enc->client_input_buf_req = *buf_req;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case DDL_I_OUTPUT_BUF_REQ:
+	{
+		struct vcd_buffer_requirement *buf_req = value;
+		if (sizeof(*buf_req) == hdr->sz && ddl_valid_buffer_requirement(
+				&enc->output_buf_req, buf_req)) {
+			enc->client_output_buf_req = *buf_req;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_METADATA_ENABLE:
+	case VCD_I_METADATA_HEADER:
+		vcd_status = ddl_set_metadata_params(ddl, hdr, value);
+		break;
+	default:
+		vcd_status = VCD_ERR_ILLEGAL_OP;
+		break;
+	}
+	return vcd_status;
+}
+
+static u32 ddl_get_dec_property(struct ddl_client_context *ddl,
+		struct vcd_property_hdr *hdr, void *value)
+{
+	u32 vcd_status = VCD_ERR_ILLEGAL_PARM;
+	struct ddl_decoder_data *dec = &ddl->codec_data.decoder;
+
+	switch (hdr->id) {
+	case VCD_I_FRAME_SIZE:
+		if (sizeof(struct vcd_property_frame_size) == hdr->sz) {
+			if (dec->client_frame_size.width) {
+				struct vcd_property_frame_size *size = value;
+				*size = dec->client_frame_size;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+		break;
+	case VCD_I_PROFILE:
+		if (sizeof(struct vcd_property_profile) == hdr->sz) {
+			*(struct vcd_property_profile *)value = dec->profile;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_LEVEL:
+		if (sizeof(struct vcd_property_level) == hdr->sz) {
+			*(struct vcd_property_level *)value = dec->level;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_PROGRESSIVE_ONLY:
+		if (sizeof(u32) == hdr->sz) {
+			*(u32 *)value = dec->progressive_only;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case DDL_I_INPUT_BUF_REQ:
+		if (sizeof(struct vcd_buffer_requirement) == hdr->sz) {
+			if (dec->client_input_buf_req.size) {
+				*(struct vcd_buffer_requirement *)value =
+					dec->client_input_buf_req;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+		break;
+	case DDL_I_OUTPUT_BUF_REQ:
+		if (sizeof(struct vcd_buffer_requirement) == hdr->sz) {
+			if (dec->client_output_buf_req.size) {
+				*(struct vcd_buffer_requirement *)value =
+					dec->client_output_buf_req;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+		break;
+	case VCD_I_CODEC:
+		if (sizeof(struct vcd_property_codec) == hdr->sz) {
+			if (dec->codec_type.codec) {
+				*(struct vcd_property_codec *)value =
+					dec->codec_type;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+		break;
+	case VCD_I_BUFFER_FORMAT:
+		if (sizeof(struct vcd_property_buffer_format) == hdr->sz) {
+			*(struct vcd_property_buffer_format *)value =
+				dec->buf_format;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_POST_FILTER:
+		if (sizeof(struct vcd_property_post_filter) == hdr->sz) {
+			*(struct vcd_property_post_filter *)value =
+				dec->post_filter;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case DDL_I_SEQHDR_ALIGN_BYTES:
+		if (sizeof(u32) == hdr->sz) {
+			*(u32 *)value = DDL_LINEAR_BUFFER_ALIGN_BYTES;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case DDL_I_FRAME_PROC_UNITS:
+		if (sizeof(u32) == hdr->sz && dec->client_frame_size.width &&
+				dec->client_frame_size.height) {
+			*(u32 *)value = ((dec->client_frame_size.width >> 4) *
+				(dec->client_frame_size.height >> 4));
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case DDL_I_DPB_RETRIEVE:
+		if (sizeof(struct ddl_frame_data_tag) == hdr->sz) {
+			vcd_status = ddl_decoder_dpb_transact(dec,
+				(struct ddl_frame_data_tag *)value,
+				DDL_DPB_OP_RETRIEVE);
+		}
+		break;
+	case VCD_I_METADATA_ENABLE:
+	case VCD_I_METADATA_HEADER:
+		vcd_status = ddl_get_metadata_params(ddl, hdr, value);
+		break;
+	default:
+		vcd_status = VCD_ERR_ILLEGAL_OP;
+		break;
+	}
+	return vcd_status;
+}
+
+static u32 ddl_get_enc_property(struct ddl_client_context *ddl,
+		struct vcd_property_hdr *hdr, void *value)
+{
+	u32 vcd_status = VCD_ERR_ILLEGAL_PARM;
+	struct ddl_encoder_data *enc = &ddl->codec_data.encoder;
+
+	struct vcd_property_entropy_control *entropy_control;
+	struct vcd_property_intra_refresh_mb_number *intra_refresh;
+
+	switch (hdr->id) {
+	case VCD_I_CODEC:
+		if (sizeof(struct vcd_property_codec) == hdr->sz) {
+			*(struct vcd_property_codec *)value = enc->codec_type;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_FRAME_SIZE:
+		if (sizeof(struct vcd_property_frame_size) == hdr->sz) {
+			*(struct vcd_property_frame_size *)value =
+				enc->frame_size;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_FRAME_RATE:
+		if (sizeof(struct vcd_property_frame_rate) == hdr->sz) {
+			*(struct vcd_property_frame_rate *)value =
+				enc->frame_rate;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_TARGET_BITRATE:
+		if (sizeof(struct vcd_property_target_bitrate) == hdr->sz) {
+			*(struct vcd_property_target_bitrate *)value =
+				enc->target_bit_rate;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_RATE_CONTROL:
+		if (sizeof(struct vcd_property_rate_control) == hdr->sz) {
+			*(struct vcd_property_rate_control *)value =
+				enc->rc_type;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_PROFILE:
+		if (sizeof(struct vcd_property_profile) == hdr->sz) {
+			*(struct vcd_property_profile *)value = enc->profile;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_LEVEL:
+		if (sizeof(struct vcd_property_level) == hdr->sz) {
+			*(struct vcd_property_level *)value = enc->level;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_MULTI_SLICE:
+		if (sizeof(struct vcd_property_multi_slice) == hdr->sz) {
+			*(struct vcd_property_multi_slice *)value =
+				enc->multi_slice;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_SEQ_HEADER:
+	{
+		struct vcd_sequence_hdr *seq_hdr = value;
+		if (enc->seq_header.size && sizeof(struct vcd_sequence_hdr) ==
+				hdr->sz && enc->seq_header.size <=
+				seq_hdr->sz) {
+			memcpy(seq_hdr->addr, enc->seq_header.virt_addr,
+				enc->seq_header.size);
+			seq_hdr->sz = enc->seq_header.size;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case DDL_I_SEQHDR_PRESENT:
+		if (sizeof(u32) == hdr->sz) {
+			if ((enc->codec_type.codec == VCD_CODEC_MPEG4 &&
+					!enc->short_header.short_header) ||
+					enc->codec_type.codec ==
+					VCD_CODEC_H264)
+				*(u32 *)value = 0x1;
+			else
+				*(u32 *)value = 0x0;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_VOP_TIMING:
+		if (sizeof(struct vcd_property_vop_timing) == hdr->sz) {
+			*(struct vcd_property_vop_timing *)value =
+				enc->vop_timing;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_SHORT_HEADER:
+		if (sizeof(struct vcd_property_short_header) == hdr->sz) {
+			if (enc->codec_type.codec == VCD_CODEC_MPEG4) {
+				*(struct vcd_property_short_header *)value =
+					enc->short_header;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+		break;
+	case VCD_I_ENTROPY_CTRL:
+		entropy_control = value;
+		if (sizeof(struct vcd_property_entropy_control) == hdr->sz) {
+			if (enc->codec_type.codec == VCD_CODEC_H264) {
+				*entropy_control = enc->entropy_control;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+		break;
+	case VCD_I_DEBLOCKING:
+		if (sizeof(struct vcd_property_db_config) == hdr->sz) {
+			if (enc->codec_type.codec == VCD_CODEC_H264) {
+				*(struct vcd_property_db_config *)value =
+					enc->db_control;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+		break;
+	case VCD_I_INTRA_PERIOD:
+		if (sizeof(struct vcd_property_i_period) == hdr->sz) {
+			*(struct vcd_property_i_period *)value = enc->period;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_QP_RANGE:
+		if (sizeof(struct vcd_property_qp_range) == hdr->sz) {
+			*(struct vcd_property_qp_range *)value = enc->qp_range;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_SESSION_QP:
+		if (sizeof(struct vcd_property_session_qp) == hdr->sz) {
+			*(struct vcd_property_session_qp *)value =
+				enc->session_qp;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_RC_LEVEL_CONFIG:
+		if (sizeof(struct vcd_property_rc_level) == hdr->sz) {
+			*(struct vcd_property_rc_level *)value = enc->rc_level;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_FRAME_LEVEL_RC:
+		if (sizeof(struct vcd_property_frame_level_rc_params) ==
+				hdr->sz) {
+			*(struct vcd_property_frame_level_rc_params *)value =
+				enc->frame_level_rc;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_ADAPTIVE_RC:
+		if (sizeof(struct vcd_property_adaptive_rc_params) ==
+				hdr->sz) {
+			*(struct vcd_property_adaptive_rc_params *)value =
+				enc->adaptive_rc;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_INTRA_REFRESH:
+		intra_refresh = value;
+		if (sizeof(struct vcd_property_intra_refresh_mb_number) ==
+				hdr->sz) {
+			*intra_refresh = enc->intra_refresh;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case DDL_I_INPUT_BUF_REQ:
+		if (sizeof(struct vcd_buffer_requirement) == hdr->sz) {
+			if (enc->output_buf_req.size) {
+				*(struct vcd_buffer_requirement *)value =
+					enc->client_input_buf_req;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+		break;
+	case DDL_I_OUTPUT_BUF_REQ:
+		if (sizeof(struct vcd_buffer_requirement) == hdr->sz) {
+			if (enc->output_buf_req.size) {
+				*(struct vcd_buffer_requirement *)value =
+					enc->client_output_buf_req;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+		break;
+	case VCD_I_BUFFER_FORMAT:
+		if (sizeof(struct vcd_property_buffer_format) == hdr->sz) {
+			*(struct vcd_property_buffer_format *)value =
+				enc->buf_format;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case DDL_I_FRAME_PROC_UNITS:
+		if (sizeof(u32) == hdr->sz && enc->frame_size.width &&
+				enc->frame_size.height) {
+			*(u32 *)value = ((enc->frame_size.width >> 4) *
+				(enc->frame_size.height >> 4));
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_HEADER_EXTENSION:
+		if (sizeof(u32) == hdr->sz && enc->codec_type.codec ==
+				VCD_CODEC_MPEG4) {
+			*(u32 *)value = enc->hdr_ext_control;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_METADATA_ENABLE:
+	case VCD_I_METADATA_HEADER:
+		vcd_status = ddl_get_metadata_params(ddl, hdr, value);
+		break;
+	default:
+		vcd_status = VCD_ERR_ILLEGAL_OP;
+		break;
+	}
+	return vcd_status;
+}
+
+static u32 ddl_set_enc_dynamic_property(struct ddl_encoder_data *enc,
+		struct vcd_property_hdr *hdr, void *value)
+{
+	u32 vcd_status = VCD_ERR_ILLEGAL_PARM;
+	switch (hdr->id) {
+	case VCD_I_REQ_IFRAME:
+		if (sizeof(struct vcd_property_req_i_frame) == hdr->sz) {
+			enc->dynamic_prop_change |= DDL_ENC_REQ_IFRAME;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_TARGET_BITRATE:
+		if (sizeof(struct vcd_property_target_bitrate) == hdr->sz) {
+			enc->target_bit_rate =
+				*(struct vcd_property_target_bitrate *)value;
+			enc->dynamic_prop_change |= DDL_ENC_CHANGE_BITRATE;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_I_INTRA_PERIOD:
+	{
+		struct vcd_property_i_period *iperiod = value;
+		if (sizeof(struct vcd_property_i_period) == hdr->sz &&
+				!iperiod->bframes) {
+			enc->period = *iperiod;
+			enc->dynamic_prop_change |= DDL_ENC_CHANGE_IPERIOD;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	case VCD_I_FRAME_RATE:
+	{
+		struct vcd_property_frame_rate *frame_rate = value;
+		if (sizeof(struct vcd_property_frame_rate) == hdr->sz &&
+				frame_rate->fps_denominator &&
+				frame_rate->fps_numerator &&
+				frame_rate->fps_denominator <=
+				frame_rate->fps_numerator) {
+			enc->frame_rate = *frame_rate;
+			enc->dynamic_prop_change |= DDL_ENC_CHANGE_FRAMERATE;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
+	default:
+		vcd_status = VCD_ERR_ILLEGAL_OP;
+		break;
+	}
+	return vcd_status;
+}
+
+void ddl_set_default_dec_property(struct ddl_client_context *ddl)
+{
+	struct ddl_decoder_data *dec = &(ddl->codec_data.decoder);
+
+	if (dec->codec_type.codec == VCD_CODEC_MPEG4 ||
+			dec->codec_type.codec == VCD_CODEC_MPEG2) {
+		dec->post_filter.post_filter = true;
+	} else {
+		dec->post_filter.post_filter = false;
+	}
+	dec->buf_format.buffer_format = VCD_BUFFER_FORMAT_NV12;
+	dec->client_frame_size.height = 144;
+	dec->client_frame_size.width = 176;
+	dec->client_frame_size.stride = 176;
+	dec->client_frame_size.scan_lines = 144;
+	dec->progressive_only = 1;
+	ddl_set_default_metadata_flag(ddl);
+
+	ddl_set_default_decoder_buffer_req(dec, true);
+}
+
+static void ddl_set_default_enc_property(struct ddl_client_context *ddl)
+{
+	struct ddl_encoder_data *enc = &(ddl->codec_data.encoder);
+
+	ddl_set_default_enc_profile(enc);
+	ddl_set_default_enc_level(enc);
+
+	enc->rc_type.rate_control = VCD_RATE_CONTROL_VBR_VFR;
+	ddl_set_default_enc_rc_params(enc);
+
+	ddl_set_default_enc_intra_period(enc);
+
+	enc->intra_refresh.cir_mb_number = 0;
+	ddl_set_default_enc_vop_timing(enc);
+
+	enc->multi_slice.m_slice_size = VCD_MSLICE_OFF;
+	enc->short_header.short_header = false;
+
+	enc->entropy_control.entropy_sel = VCD_ENTROPY_SEL_CAVLC;
+	enc->entropy_control.cabac_model = VCD_CABAC_MODEL_NUMBER_0;
+	enc->db_control.db_config = VCD_DB_ALL_BLOCKING_BOUNDARY;
+	enc->db_control.slice_alpha_offset = 0;
+	enc->db_control.slice_beta_offset = 0;
+
+	enc->re_con_buf_format.buffer_format = VCD_BUFFER_FORMAT_TILE_4x2;
+
+	enc->buf_format.buffer_format = VCD_BUFFER_FORMAT_NV12;
+
+	enc->hdr_ext_control = 0;
+
+	ddl_set_default_metadata_flag(ddl);
+
+	ddl_set_default_encoder_buffer_req(enc);
+}
+
+static void ddl_set_default_enc_profile(struct ddl_encoder_data *enc)
+{
+	enum vcd_codec codec = enc->codec_type.codec;
+	if (codec == VCD_CODEC_MPEG4)
+		enc->profile.profile = VCD_PROFILE_MPEG4_SP;
+	else if (codec == VCD_CODEC_H264)
+		enc->profile.profile = VCD_PROFILE_H264_BASELINE;
+	else
+		enc->profile.profile = VCD_PROFILE_H263_BASELINE;
+}
+
+static void ddl_set_default_enc_level(struct ddl_encoder_data *enc)
+{
+	enum vcd_codec codec = enc->codec_type.codec;
+	if (codec == VCD_CODEC_MPEG4)
+		enc->level.level = VCD_LEVEL_MPEG4_1;
+	else if (codec == VCD_CODEC_H264)
+		enc->level.level = VCD_LEVEL_H264_1;
+	else
+		enc->level.level = VCD_LEVEL_H263_10;
+}
+
+static void ddl_set_default_enc_vop_timing(struct ddl_encoder_data *enc)
+{
+	enc->vop_timing.vop_time_resolution = (2 *
+		enc->frame_rate.fps_numerator) /
+		enc->frame_rate.fps_denominator;
+}
+
+static void ddl_set_default_enc_intra_period(struct ddl_encoder_data *enc)
+{
+	switch (enc->rc_type.rate_control) {
+	default:
+	case VCD_RATE_CONTROL_VBR_VFR:
+	case VCD_RATE_CONTROL_VBR_CFR:
+	case VCD_RATE_CONTROL_CBR_VFR:
+	case VCD_RATE_CONTROL_OFF:
+		enc->period.frames = ((enc->frame_rate.fps_numerator << 1) /
+			enc->frame_rate.fps_denominator) - 1;
+		break;
+	case VCD_RATE_CONTROL_CBR_CFR:
+		enc->period.frames = ((enc->frame_rate.fps_numerator >> 1) /
+			enc->frame_rate.fps_denominator) - 1;
+		break;
+	}
+	enc->period.bframes = 0;
+}
+
+static void ddl_set_default_enc_rc_params(struct ddl_encoder_data *enc)
+{
+	enum vcd_codec codec = enc->codec_type.codec;
+
+	enc->rc_level.frame_level_rc = true;
+	enc->qp_range.min_qp = 0x1;
+
+	if (codec == VCD_CODEC_H264) {
+		enc->qp_range.max_qp = 0x33;
+		enc->session_qp.iframe_qp = 0x19;
+		enc->session_qp.frame_qp = 0x19;
+
+		enc->rc_level.mb_level_rc = true;
+		enc->adaptive_rc.activity_region_flag = true;
+		enc->adaptive_rc.dark_region_as_flag = true;
+		enc->adaptive_rc.smooth_region_as_flag = true;
+		enc->adaptive_rc.static_region_as_flag = true;
+	} else {
+		enc->qp_range.max_qp = 0x1f;
+		enc->session_qp.iframe_qp = 0x14;
+		enc->session_qp.frame_qp = 0x14;
+		enc->rc_level.mb_level_rc = false;
+	}
+
+	switch (enc->rc_type.rate_control) {
+	default:
+	case VCD_RATE_CONTROL_VBR_VFR:
+		enc->r_cframe_skip = 1;
+		enc->frame_level_rc.reaction_coeff = 0x1f4;
+		break;
+	case VCD_RATE_CONTROL_VBR_CFR:
+		enc->r_cframe_skip = 0;
+		enc->frame_level_rc.reaction_coeff = 0x1f4;
+		break;
+	case VCD_RATE_CONTROL_CBR_VFR:
+		enc->r_cframe_skip = 1;
+		if (codec != VCD_CODEC_H264) {
+			enc->session_qp.iframe_qp = 0xf;
+			enc->session_qp.frame_qp = 0xf;
+		}
+
+		enc->frame_level_rc.reaction_coeff = 0x6;
+		break;
+	case VCD_RATE_CONTROL_CBR_CFR:
+		enc->r_cframe_skip = 0;
+		enc->frame_level_rc.reaction_coeff = 0x6;
+		break;
+	case VCD_RATE_CONTROL_OFF:
+		enc->r_cframe_skip = 0;
+		enc->rc_level.frame_level_rc = false;
+		enc->rc_level.mb_level_rc = false;
+		break;
+	}
+}
+
+void ddl_set_default_encoder_buffer_req(struct ddl_encoder_data *enc)
+{
+	u32 y_cb_cr_size;
+
+	y_cb_cr_size = ddl_get_yuv_buffer_size(&enc->frame_size,
+		&enc->buf_format, false);
+
+	memset(&enc->input_buf_req, 0, sizeof(struct vcd_buffer_requirement));
+
+	enc->input_buf_req.min_count = 1;
+	enc->input_buf_req.actual_count = enc->input_buf_req.min_count;
+	enc->input_buf_req.max_count = DDL_MAX_BUFFER_COUNT;
+	enc->input_buf_req.size = y_cb_cr_size;
+	enc->input_buf_req.align = DDL_LINEAR_BUFFER_ALIGN_BYTES;
+
+	enc->client_input_buf_req = enc->input_buf_req;
+
+	memset(&enc->output_buf_req, 0, sizeof(struct vcd_buffer_requirement));
+
+	enc->output_buf_req.min_count = 2;
+	enc->output_buf_req.actual_count = enc->output_buf_req.min_count;
+	enc->output_buf_req.max_count = DDL_MAX_BUFFER_COUNT;
+	enc->output_buf_req.align = DDL_LINEAR_BUFFER_ALIGN_BYTES;
+	enc->output_buf_req.size = y_cb_cr_size;
+	ddl_set_default_encoder_metadata_buffer_size(enc);
+	enc->client_output_buf_req = enc->output_buf_req;
+}
+
+void ddl_set_default_decoder_buffer_req(struct ddl_decoder_data *dec,
+	u32 estimate)
+{
+	size_t y_cb_cr_size;
+	u32 min_dpb;
+	struct vcd_property_frame_size *frame_size;
+	struct vcd_buffer_requirement *output_buf_req, *input_buf_req;
+
+	if (!dec->codec_type.codec)
+		return;
+
+	if (estimate) {
+		frame_size = &dec->client_frame_size;
+		output_buf_req = &dec->client_output_buf_req;
+		input_buf_req = &dec->client_input_buf_req;
+		min_dpb = ddl_decoder_min_num_dpb(dec);
+		y_cb_cr_size = ddl_get_yuv_buffer_size(frame_size,
+			&dec->buf_format, !dec->progressive_only);
+	} else {
+		frame_size = &dec->frame_size;
+		output_buf_req = &dec->actual_output_buf_req;
+		input_buf_req = &dec->actual_input_buf_req;
+		y_cb_cr_size = dec->y_cb_cr_size;
+		min_dpb = dec->min_dpb_num;
+	}
+
+	memset(output_buf_req, 0, sizeof(struct vcd_buffer_requirement));
+
+	output_buf_req->min_count = min_dpb;
+	output_buf_req->actual_count = output_buf_req->min_count;
+	output_buf_req->max_count = DDL_MAX_BUFFER_COUNT;
+	output_buf_req->size = y_cb_cr_size;
+	if (dec->buf_format.buffer_format != VCD_BUFFER_FORMAT_NV12)
+		output_buf_req->align = DDL_TILE_BUFFER_ALIGN_BYTES;
+	else
+		output_buf_req->align = DDL_LINEAR_BUFFER_ALIGN_BYTES;
+
+	ddl_set_default_decoder_metadata_buffer_size(dec, frame_size,
+		output_buf_req);
+
+	dec->min_output_buf_req = *output_buf_req;
+
+	memset(input_buf_req, 0, sizeof(struct vcd_buffer_requirement));
+
+	input_buf_req->min_count = 1;
+	input_buf_req->actual_count = input_buf_req->min_count;
+	input_buf_req->max_count = DDL_MAX_BUFFER_COUNT;
+	input_buf_req->size = y_cb_cr_size;
+
+	if (input_buf_req->size >= (1280 * 720 * 3) >> 1)
+		input_buf_req->size >>= 1;
+
+	input_buf_req->align = DDL_LINEAR_BUFFER_ALIGN_BYTES;
+
+	dec->min_input_buf_req = *input_buf_req;
+}
+
+size_t ddl_get_yuv_buffer_size(struct vcd_property_frame_size *frame_size,
+	struct vcd_property_buffer_format *buf_format, u32 interlace)
+{
+	u32 width = frame_size->stride;
+	u32 height = frame_size->scan_lines;
+	size_t sz;
+
+	if (buf_format->buffer_format != VCD_BUFFER_FORMAT_NV12) {
+		size_t component_sz;
+		u32 width_round_up;
+		u32 height_round_up;
+		u32 height_chroma = (height >> 1);
+
+		width_round_up = DDL_TILE_ALIGN(width, DDL_TILE_ALIGN_WIDTH);
+		height_round_up = DDL_TILE_ALIGN(height, DDL_TILE_ALIGN_HEIGHT);
+
+		component_sz = width_round_up * height_round_up;
+		component_sz = DDL_TILE_ALIGN(component_sz,
+			DDL_TILE_MULTIPLY_FACTOR);
+
+		sz = (component_sz + DDL_TILE_BUF_ALIGN_GUARD_BYTES) &
+			DDL_TILE_BUF_ALIGN_MASK;
+
+		height_round_up = DDL_TILE_ALIGN(height_chroma,
+			DDL_TILE_ALIGN_HEIGHT);
+		component_sz = width_round_up * height_round_up;
+		component_sz = DDL_TILE_ALIGN(component_sz,
+			DDL_TILE_MULTIPLY_FACTOR);
+		sz += component_sz;
+	} else {
+		sz = height * width;
+		sz += sz >> 1;
+	}
+	return sz;
+}
+
+void ddl_calculate_stride(struct vcd_property_frame_size *frame_size,
+	u32 interlace)
+{
+	frame_size->stride = ((frame_size->width + 15) >> 4) << 4;
+
+	if (interlace)
+		frame_size->scan_lines = ((frame_size->height + 31) >> 5) << 5;
+	else
+		frame_size->scan_lines = ((frame_size->height + 15) >> 4) << 4;
+}
+
+static u32 ddl_valid_buffer_requirement(struct vcd_buffer_requirement
+	*orig, struct vcd_buffer_requirement *req)
+{
+	u32 status = false;
+	if (orig->max_count >= req->actual_count &&
+			orig->actual_count <= req->actual_count &&
+			orig->align <= req->align && orig->size <= req->size) {
+		status = true;
+	} else {
+		pr_err("ddl_valid_buf_req:Failed\n");
+	}
+	return status;
+}
+
+static u32 ddl_decoder_min_num_dpb(struct ddl_decoder_data *dec)
+{
+	u32 min_dpb = 0;
+	switch (dec->codec_type.codec) {
+	default:
+	case VCD_CODEC_MPEG4:
+	case VCD_CODEC_MPEG2:
+	case VCD_CODEC_DIVX_4:
+	case VCD_CODEC_DIVX_5:
+	case VCD_CODEC_DIVX_6:
+	case VCD_CODEC_XVID:
+		min_dpb = 3;
+		break;
+	case VCD_CODEC_H263:
+		min_dpb = 2;
+		break;
+	case VCD_CODEC_VC1:
+	case VCD_CODEC_VC1_RCV:
+		min_dpb = 4;
+		break;
+	case VCD_CODEC_H264:
+	{
+		u32 yuv_size = (dec->client_frame_size.height *
+			dec->client_frame_size.width * 3) >> 1;
+		min_dpb = 6912000 / yuv_size;
+		if (min_dpb > 16)
+			min_dpb = 16;
+
+		min_dpb += 2;
+		break;
+	}
+	}
+	return min_dpb;
+}
+
+static u32 ddl_set_dec_buffers(struct ddl_decoder_data *dec,
+	struct ddl_property_dec_pic_buffers *dpb)
+{
+	u32 vcd_status = VCD_S_SUCCESS;
+	u32 i;
+	for (i = 0; !vcd_status && i < dpb->no_of_dec_pic_buf; ++i) {
+		if (!IS_ALIGNED(dpb->dec_pic_buffers[i].vcd_frm.phys_addr,
+				dec->client_output_buf_req.align) ||
+				dpb->dec_pic_buffers[i].vcd_frm.alloc_len <
+				dec->client_output_buf_req.size) {
+			vcd_status = VCD_ERR_ILLEGAL_PARM;
+			pr_err("ddl_set_prop:"
+				"Dpb_align_fail_or_alloc_size_small\n");
+			return vcd_status;
+		}
+	}
+
+	if (dec->dp_buf.no_of_dec_pic_buf) {
+		kfree(dec->dp_buf.dec_pic_buffers);
+		dec->dp_buf.dec_pic_buffers = NULL;
+		dec->dp_buf.no_of_dec_pic_buf = 0;
+	}
+	dec->dp_buf.dec_pic_buffers = kmalloc(dpb->no_of_dec_pic_buf *
+		sizeof(struct ddl_frame_data_tag), GFP_KERNEL);
+
+	if (!dec->dp_buf.dec_pic_buffers) {
+		pr_err("ddl_dec_set_prop:"
+			"Dpb_container_alloc_failed\n");
+		return VCD_ERR_ALLOC_FAIL;
+	}
+	dec->dp_buf.no_of_dec_pic_buf = dpb->no_of_dec_pic_buf;
+	for (i = 0; i < dpb->no_of_dec_pic_buf; ++i)
+		dec->dp_buf.dec_pic_buffers[i] = dpb->dec_pic_buffers[i];
+
+	dec->dpb_mask.client_mask = 0;
+	dec->dpb_mask.hw_mask = 0;
+	dec->dynamic_prop_change = 0;
+	return VCD_S_SUCCESS;
+}
+
+void ddl_set_initial_default_values(struct ddl_client_context *ddl)
+{
+	if (ddl->decoding) {
+		ddl->codec_data.decoder.codec_type.codec = VCD_CODEC_MPEG4;
+		ddl_set_default_dec_property(ddl);
+	} else {
+		struct ddl_encoder_data *enc = &(ddl->codec_data.encoder);
+		enc->codec_type.codec = VCD_CODEC_MPEG4;
+
+		enc->target_bit_rate.target_bitrate = 64000;
+		enc->frame_size.width = 176;
+		enc->frame_size.height = 144;
+		enc->frame_size.stride = 176;
+		enc->frame_size.scan_lines = 144;
+		enc->frame_rate.fps_numerator = 30;
+		enc->frame_rate.fps_denominator = 1;
+		ddl_set_default_enc_property(ddl);
+	}
+}
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_utils.c b/drivers/misc/video_core/720p/ddl/vcd_ddl_utils.c
new file mode 100644
index 0000000..922f071
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_utils.c
@@ -0,0 +1,154 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vcd_ddl_utils.h"
+#include "vcd_ddl_metadata.h"
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+#define ERR(x...) printk(KERN_ERR x)
+
+#ifdef CORE_TIMING_INFO
+static unsigned int g_ddl_dec_t1, g_ddl_enc_t1;
+static unsigned int g_ddl_dec_ttotal, g_ddl_enc_ttotal;
+static unsigned int g_ddl_dec_count, g_ddl_enc_count;
+#endif
+
+size_t npelly_size[] = {
+	0x100000,
+	0x080000,
+	0x51c00,
+	DDL_CONTEXT_MEMORY,
+	DDL_DB_LINE_BUF_SIZE,
+	DDL_MPEG4_DATA_PARTITION_BUF_SIZE,
+	DDL_METADATA_TOTAL_INPUTBUFSIZE,
+	DDL_DBG_CORE_DUMP_SIZE,
+	0x040000,
+	DDL_ENC_SEQHEADER_SIZE,
+};
+
+struct ddl_dma_buffer npelly_b[30];
+
+u32 npelly_init(void) {
+	int i;
+	printk("\nnpelly npelly max_key = %d\n", npelly_max_key);
+	for (i=0; i<npelly_max_key; i++) {
+		struct ddl_dma_buffer *b = &npelly_b[i];
+		b->size = npelly_size[i];
+		b->virt_addr = dma_alloc_coherent(NULL, b->size,
+			&b->phys_addr, GFP_KERNEL);
+		if (!b->virt_addr) {
+			printk("\nnpelly %s: Could not allocate %d for %d\n",
+				__FUNCTION__, b->size, i);
+			return -1;
+		}
+		printk("\nnpelly ALLOC %d for %d\n", b->size, i);
+		memset(b->virt_addr, 0, b->size);
+	}
+	return 0;
+}
+
+void *ddl_dma_alloc(struct ddl_dma_buffer *b, size_t sz, enum npelly_key key)
+{
+	printk("\nnpelly RETRIEVE %d for %d\n", sz, key);
+
+	if (sz > npelly_b[key].size) {
+		printk("\nnpelly OH SHIT, %d > %d for %d\n", sz, npelly_b[key].size, key);
+		BUG_ON(true);
+	}
+	*b = npelly_b[key];
+	b->size = sz;
+	memset(b->virt_addr, 0, sz);
+
+	return b->virt_addr;
+}
+
+void ddl_dma_free(struct ddl_dma_buffer *b)
+{
+	printk("\nnpelly RELEASE %d\n", b->size);
+
+	b->virt_addr = NULL;
+	b->size = 0;
+}
+
+#ifdef CORE_TIMING_INFO
+void ddl_get_core_start_time(u8 codec_type)
+{
+	u32 *ddl_t1 = NULL;
+	if (!codec_type)
+		ddl_t1 = &g_ddl_dec_t1;
+	else if (codec_type == 1)
+		ddl_t1 = &g_ddl_enc_t1;
+
+	if (!*ddl_t1) {
+		struct timeval ddl_tv;
+		do_gettimeofday(&ddl_tv);
+		*ddl_t1 = (ddl_tv.tv_sec * 1000) + (ddl_tv.tv_usec / 1000);
+	}
+}
+
+void ddl_calc_core_time(u8 codec_type)
+{
+	u32 *ddl_t1 = NULL, *ddl_ttotal = NULL,
+		*ddl_count = NULL;
+	if (!codec_type) {
+		DBG("\n720p Core Decode ");
+		ddl_t1 = &g_ddl_dec_t1;
+		ddl_ttotal = &g_ddl_dec_ttotal;
+		ddl_count = &g_ddl_dec_count;
+	} else if (codec_type == 1) {
+		DBG("\n720p Core Encode ");
+		ddl_t1 = &g_ddl_enc_t1;
+		ddl_ttotal = &g_ddl_enc_ttotal;
+		ddl_count = &g_ddl_enc_count;
+	}
+
+	if (*ddl_t1) {
+		int ddl_t2;
+		struct timeval ddl_tv;
+		do_gettimeofday(&ddl_tv);
+		ddl_t2 = (ddl_tv.tv_sec * 1000) + (ddl_tv.tv_usec / 1000);
+		*ddl_ttotal += (ddl_t2 - *ddl_t1);
+		*ddl_count = *ddl_count + 1;
+		DBG("time %u, average time %u, count %u",
+			ddl_t2 - *ddl_t1, (*ddl_ttotal)/(*ddl_count),
+			*ddl_count);
+		*ddl_t1 = 0;
+	}
+}
+
+void ddl_reset_time_variables(u8 codec_type)
+{
+	if (!codec_type) {
+		DBG("\n Reset Decoder time variables");
+		g_ddl_dec_t1 = 0;
+		g_ddl_dec_ttotal = 0;
+		g_ddl_dec_count = 0;
+	} else if (codec_type == 1) {
+		DBG("\n Reset Encoder time variables ");
+		g_ddl_enc_t1 = 0;
+		g_ddl_enc_ttotal = 0;
+		g_ddl_enc_count = 0;
+	}
+}
+#endif
diff --git a/drivers/misc/video_core/720p/ddl/vcd_ddl_utils.h b/drivers/misc/video_core/720p/ddl/vcd_ddl_utils.h
new file mode 100644
index 0000000..bf83a73
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/vcd_ddl_utils.h
@@ -0,0 +1,61 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_DDL_UTILS_H_
+#define _VCD_DDL_UTILS_H_
+
+#include "vcd_ddl_core.h"
+#include "vcd_ddl.h"
+
+//TODO get rid of this hack
+enum npelly_key {
+	npelly_dec_dpb = 0,
+	npelly_dec_ref,
+	npelly_dec_h264,
+	npelly_context,
+	npelly_dbl,
+	npelly_mpeg4,
+	npelly_meta,
+	npelly_debug,
+	npelly_enc_dpb,
+	npelly_enc_seq,
+	npelly_max_key,
+};
+
+void *ddl_dma_alloc(struct ddl_dma_buffer *, size_t, enum npelly_key key);
+void ddl_dma_free(struct ddl_dma_buffer *);
+
+#ifdef CORE_TIMING_INFO
+void ddl_get_core_start_time(u8 codec_type);
+
+void ddl_calc_core_time(u8 codec_type);
+
+void ddl_reset_time_variables(u8 codec_type);
+#endif
+
+#endif
diff --git a/drivers/misc/video_core/720p/ddl/video_core_720p.c b/drivers/misc/video_core/720p/ddl/video_core_720p.c
new file mode 100644
index 0000000..053a3a8
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/video_core_720p.c
@@ -0,0 +1,754 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/unistd.h>
+
+#include "video_core_type.h"
+#include "video_core_720p.h"
+
+#define VIDC_720P_VERSION_STRING "VIDC_V1.0"
+
+unsigned long vid_c_base_addr;
+
+void vidc_720p_set_device_virtual_base(void *virt_addr)
+{
+	vid_c_base_addr = (unsigned long)virt_addr;
+}
+
+static inline void vidc_720p_write(unsigned long offset, unsigned long val)
+{
+	pr_debug("REG 0x%08lx: write 0x%08lx\n", offset, val);
+	mb();
+	iowrite32(val, vid_c_base_addr + offset);
+}
+
+static inline unsigned long vidc_720p_read(unsigned long offset)
+{
+	unsigned long val;
+	mb();
+	val = ioread32(vid_c_base_addr + offset);
+	pr_debug("REG 0x%08lx: read 0x%08lx\n", offset, val);
+	return val;
+}
+
+void vidc_720p_init(char **ppsz_version, size_t sz, phys_addr_t phys_addr,
+	enum vidc_720p_endian_type dma_endian, u32 interrupt_off,
+	enum vidc_720p_interrupt_level_selection_type interrupt_sel,
+	u32 interrupt_mask)
+{
+	if (ppsz_version)
+		*ppsz_version = VIDC_720P_VERSION_STRING;
+
+	if (interrupt_sel == VIDC_720P_INTERRUPT_LEVEL_SEL)
+		vidc_720p_write(0x0504, 0);
+	else
+		vidc_720p_write(0x0504, 1);
+
+	if (interrupt_off)
+		vidc_720p_write(0x0500, 1);
+	else
+		vidc_720p_write(0x0500, 0);
+
+	vidc_720p_write(0x0508, 1);
+
+	vidc_720p_write(0x0518, 0);
+
+	vidc_720p_write(0x0518, interrupt_mask);
+
+	vidc_720p_write(0x0044, dma_endian);
+
+	vidc_720p_write(0x0138, 0);
+
+	vidc_720p_write(0x0110, 1);
+
+	vidc_720p_write(0x000C, sz / 4);  /* word size */
+
+	vidc_720p_write(0x0014, phys_addr);
+
+	vidc_720p_write(0x0020, 0);
+
+	vidc_720p_write(0x0000, 1);
+}
+
+u32 vidc_720p_do_sw_reset(void)
+{
+	u32 fw_start;
+	udelay(5);
+	vidc_720p_write(0x0108, 0);
+	udelay(5);
+	vidc_720p_write(0x0134, 0);
+	udelay(5);
+	vidc_720p_write(0x0130, 1);
+	udelay(15);
+	vidc_720p_write(0x0130, 0);
+	udelay(5);
+	fw_start = vidc_720p_read(0x0134);
+
+	if (!fw_start) {
+		pr_debug("VIDC-SW-RESET-FAILS!\n");
+		return false;
+	}
+	return true;
+}
+
+u32 vidc_720p_reset_is_success()
+{
+	u32 stagecounter;
+	stagecounter = vidc_720p_read(0x0414);
+	stagecounter &= 0xff;
+	if (stagecounter != 0xe5) {
+		pr_debug("VIDC-CPU_RESET-FAILS!\n");
+		vidc_720p_write(0x0108, 0);
+		msleep(10);
+		return false;
+	}
+	return true;
+}
+
+void vidc_720p_start_cpu(enum vidc_720p_endian_type dma_endian,
+	phys_addr_t icontext_bufferstart, phys_addr_t debug_core_dump_addr,
+	size_t debug_buffer_size)
+{
+	u32 dbg_info_input0_reg = 0x1;
+
+	vidc_720p_write(0x0110, 0);
+	vidc_720p_write(0x0230, icontext_bufferstart);
+	vidc_720p_write(0x0044, dma_endian);
+	if (debug_buffer_size) {
+		dbg_info_input0_reg = (debug_buffer_size << 0x10)
+			| (0x2 << 1) | 0x1;
+		vidc_720p_write(0x0D10, debug_core_dump_addr);
+	}
+	vidc_720p_write(0x0D0C, dbg_info_input0_reg);
+	vidc_720p_write(0x0108, 1);
+}
+
+u32 vidc_720p_cpu_start()
+{
+	u32 fw_status;
+
+	fw_status = vidc_720p_read(0x0C14);
+	if (fw_status != 0x02)
+		return false;
+	return true;
+}
+
+
+void vidc_720p_stop_fw(void)
+{
+	vidc_720p_write(0x0134, 0);
+	vidc_720p_write(0x0108, 0);
+}
+
+void vidc_720p_get_interrupt_status(u32 *interrupt_status,
+		u32 *cmd_err_status, u32 *disp_pic_err_status, u32 *op_failed)
+{
+	u32 err_status;
+
+	*interrupt_status = vidc_720p_read(0x0514);
+	err_status = vidc_720p_read(0x0E9C);
+	*cmd_err_status = err_status & 0xffff;
+	*disp_pic_err_status = (err_status & 0xffff0000) >> 16;
+	*op_failed = (vidc_720p_read(0x0EC0) & 0x2) >> 1;
+}
+
+void vidc_720p_interrupt_done_clear(void)
+{
+	vidc_720p_write(0x0508, 1);
+	vidc_720p_write(0x0104, 4);
+}
+
+void vidc_720p_submit_command(u32 ch_id, u32 cmd_id)
+{
+	u32 fw_status;
+
+	vidc_720p_write(0x0104, ch_id);
+	vidc_720p_write(0x0D00, cmd_id);
+
+	fw_status = vidc_720p_read(0x0C14);
+	vidc_720p_write(0x0D1C, fw_status);
+}
+
+u32 vidc_720p_engine_reset(u32 ch_id, enum vidc_720p_endian_type dma_endian,
+	enum vidc_720p_interrupt_level_selection_type interrupt_sel,
+	u32 interrupt_mask)
+{
+	u32 op_done;
+	u32 counter = 0;
+
+	pr_debug("ENG-RESET!!\n");
+	/* issue the engine reset command */
+	vidc_720p_submit_command(ch_id, VIDC_720P_CMD_MFC_ENGINE_RESET);
+
+	do {
+		udelay(20);
+		op_done = vidc_720p_read(0x050C);
+		counter++;
+	} while (!op_done && counter < 10);
+
+	if (!op_done)
+		return false;  /* reset fails */
+
+	/* write invalid channel id */
+	vidc_720p_write(0x0104, 4);
+
+	/* Set INT_PULSE_SEL */
+	if (interrupt_sel == VIDC_720P_INTERRUPT_LEVEL_SEL)
+		vidc_720p_write(0x0504, 0);
+	else
+		vidc_720p_write(0x0504, 1);
+
+	if (!interrupt_mask) {
+		/* Disable interrupt */
+		vidc_720p_write(0x0500, 1);
+	} else {
+	  /* Enable interrupt */
+		vidc_720p_write(0x0500, 0);
+	}
+
+	/* Clear any pending interrupt */
+	vidc_720p_write(0x0508, 1);
+
+	/* Set INT_ENABLE_REG */
+	vidc_720p_write(0x0518, interrupt_mask);
+
+	/* Sets the DMA endianness */
+	vidc_720p_write(0x0044, dma_endian);
+
+	/* return engine reset success */
+	return true ;
+}
+
+void vidc_720p_set_channel(u32 ch_id, enum vidc_720p_enc_dec_selection_type
+	enc_dec_sel, enum vidc_720p_codec_type codec, phys_addr_t pi_fw,
+	size_t firmware_size)
+{
+	u32 std_sel = codec;
+
+	vidc_720p_write(0x012C, 0);
+
+	if (enc_dec_sel)
+		std_sel |= 0x10;
+
+	vidc_720p_write(0x0100, std_sel);
+
+	switch (codec) {
+	default:
+	case VIDC_720P_DIVX:
+	case VIDC_720P_XVID:
+	case VIDC_720P_MPEG4:
+		if (enc_dec_sel == VIDC_720P_ENCODER)
+			vidc_720p_write(0x0200, pi_fw);
+		else
+			vidc_720p_write(0x0204, pi_fw);
+		break;
+	case VIDC_720P_H264:
+		if (enc_dec_sel == VIDC_720P_ENCODER)
+			vidc_720p_write(0x0208, pi_fw);
+		else
+			vidc_720p_write(0x020C, pi_fw);
+		break;
+	case VIDC_720P_H263:
+		if (enc_dec_sel == VIDC_720P_ENCODER)
+			vidc_720p_write(0x0200, pi_fw);
+		else
+			vidc_720p_write(0x0218, pi_fw);
+		break;
+	case VIDC_720P_VC1:
+		vidc_720p_write(0x0210, pi_fw);
+		break;
+	case VIDC_720P_MPEG2:
+		vidc_720p_write(0x40293, pi_fw);
+		break;
+	}
+	vidc_720p_write(0x000C, firmware_size / 4);  /* word size */
+
+	vidc_720p_submit_command(ch_id, VIDC_720P_CMD_CHSET);
+}
+
+void vidc_720p_encode_set_profile(u32 profile, u32 level)
+{
+	u32 profile_level = profile|(level << 0x8);
+
+	vidc_720p_write(0x0300, profile_level);
+}
+
+void vidc_720p_set_frame_size(u32 size_x, u32 size_y)
+{
+	vidc_720p_write(0x0118, size_x);
+
+	vidc_720p_write(0x011C, size_y);
+}
+
+void vidc_720p_encode_set_fps(u32 rc_frame_rate)
+{
+	vidc_720p_write(0x0D14, rc_frame_rate);
+}
+
+void vidc_720p_encode_set_short_header(u32 short_header)
+{
+	vidc_720p_write(0x0318, short_header);
+}
+
+void vidc_720p_encode_set_vop_time(u32 vop_time_resolution,
+		u32 vop_time_increment)
+{
+	u32 enable_vop, vop_timing_reg;
+
+	if (!vop_time_resolution)
+		vidc_720p_write(0x0E00, 0x0);
+	else {
+		enable_vop = 0x1;
+		vop_timing_reg = (enable_vop << 0x1f) |
+		(vop_time_resolution << 0x10) | vop_time_increment;
+		vidc_720p_write(0x0E00, vop_timing_reg);
+	}
+}
+
+void vidc_720p_encode_set_hec_period(u32 hec_period)
+{
+	vidc_720p_write(0x0EB0, hec_period);
+}
+
+void vidc_720p_encode_set_qp_params(u32 max_qp, u32 min_qp)
+{
+	u32 qp = min_qp | (max_qp << 0x8);
+
+	vidc_720p_write(0x0A0C, qp);
+}
+
+void vidc_720p_encode_set_rc_config(u32 enable_frame_level_rc,
+	u32 enable_mb_level_rc_flag, u32 iframe_qp, u32 pframe_qp)
+{
+	u32 rc_config = iframe_qp;
+
+	if (enable_frame_level_rc)
+		rc_config |= (0x1 << 0x9);
+
+	if (enable_mb_level_rc_flag)
+		rc_config |= (0x1 << 0x8);
+
+	vidc_720p_write(0x0A00, rc_config);
+	vidc_720p_write(0x0A04, pframe_qp);
+}
+
+void vidc_720p_encode_set_bit_rate(u32 target_bitrate)
+{
+	vidc_720p_write(0x0A08, target_bitrate);
+}
+
+void vidc_720p_encoder_set_param_change(u32 enc_param_change)
+{
+	vidc_720p_write(0x0E08, enc_param_change);
+}
+
+void vidc_720p_encode_set_control_param(u32 param_val)
+{
+	vidc_720p_write(0x0EC8, param_val);
+}
+
+void vidc_720p_encode_set_frame_level_rc_params(u32 reaction_coeff)
+{
+	vidc_720p_write(0x0A10, reaction_coeff);
+}
+
+void vidc_720p_encode_set_mb_level_rc_params(u32 dark_region_as_flag,
+		u32 smooth_region_as_flag, u32 static_region_as_flag,
+		u32 activity_region_flag)
+{
+	u32 mb_level_rc = 0x0;
+
+	if (activity_region_flag)
+		mb_level_rc |= 0x1;
+	if (static_region_as_flag)
+		mb_level_rc |= (0x1 << 0x1);
+	if (smooth_region_as_flag)
+		mb_level_rc |= (0x1 << 0x2);
+	if (dark_region_as_flag)
+		mb_level_rc |= (0x1 << 0x3);
+	/* Write MB level rate control */
+	vidc_720p_write(0x0A14, mb_level_rc);
+}
+
+void vidc_720p_encode_set_entropy_control(enum vidc_720p_entropy_sel_type
+		entropy_sel, enum vidc_720p_cabac_model_type cabac_model_number)
+{
+	u32 num;
+	u32 entropy_params = entropy_sel;
+
+	/* Set Model Number */
+	if (entropy_sel == VIDC_720P_ENTROPY_SEL_CABAC) {
+		num = (u32)cabac_model_number;
+		entropy_params |= (num << 0x2);
+	}
+	/* Set Entropy parameters */
+	vidc_720p_write(0x0310, entropy_params);
+}
+
+void vidc_720p_encode_set_db_filter_control(enum vidc_720p_DBConfig_type
+		db_config, u32 slice_alpha_offset, u32 slice_beta_offset)
+{
+	u32 deblock_params;
+
+	deblock_params = db_config;
+	deblock_params |=
+		(slice_beta_offset << 0x2) | (slice_alpha_offset << 0x7);
+
+	/* Write deblocking control settings */
+	vidc_720p_write(0x0314, deblock_params);
+}
+
+void vidc_720p_encode_set_intra_refresh_mb_number(u32 cir_mb_number)
+{
+	vidc_720p_write(0x0810, cir_mb_number);
+}
+
+void vidc_720p_encode_set_multi_slice_info(enum vidc_720p_MSlice_selection_type
+		m_slice_sel, u32 multi_slice_size)
+{
+	switch (m_slice_sel) {
+	case VIDC_720P_MSLICE_BY_MB_COUNT:
+		vidc_720p_write(0x0EA8, 0x1);
+		vidc_720p_write(0x1517, m_slice_sel);
+		vidc_720p_write(0x0324, multi_slice_size);
+		break;
+	case VIDC_720P_MSLICE_BY_BYTE_COUNT:
+		vidc_720p_write(0x0EA8, 0x1);
+		vidc_720p_write(0x1517, m_slice_sel);
+		vidc_720p_write(0x0328, multi_slice_size);
+		break;
+	case VIDC_720P_MSLICE_BY_GOB:
+		vidc_720p_write(0x0EA8, 0x1);
+		break;
+	default:
+	case VIDC_720P_MSLICE_OFF:
+		vidc_720p_write(0x0EA8, 0x0);
+		break;
+	}
+}
+
+void vidc_720p_encode_set_dpb_buffer(dma_addr_t pi_enc_dpb_addr,
+	size_t alloc_len)
+{
+	vidc_720p_write(0x080C, pi_enc_dpb_addr);
+	vidc_720p_write(0x0ED4, alloc_len);
+}
+
+void vidc_720p_encode_set_i_period(u32 period)
+{
+	vidc_720p_write(0x0308, period);
+}
+
+void vidc_720p_encode_init_codec(u32 ch_id,
+	enum vidc_720p_memory_access_method_type memory_access_model)
+{
+	vidc_720p_write(0x0600, memory_access_model);
+	vidc_720p_submit_command(ch_id, VIDC_720P_CMD_INITCODEC);
+}
+
+void vidc_720p_encode_unalign_bitstream(u32 upper_unalign_word,
+	u32 lower_unalign_word)
+{
+	vidc_720p_write(0x0EA0, upper_unalign_word);
+	vidc_720p_write(0x0EA4, lower_unalign_word);
+}
+
+void vidc_720p_encode_set_seq_header_buffer(phys_addr_t ext_buffer_start,
+	phys_addr_t ext_buffer_end, u32 start_byte_num)
+{
+	vidc_720p_write(0x0018, ext_buffer_start);
+
+	vidc_720p_write(0x0024, ext_buffer_start);
+
+	vidc_720p_write(0x001C, ext_buffer_end);
+
+	vidc_720p_write(0x005C, start_byte_num);
+}
+
+void vidc_720p_encode_frame(u32 ch_id, phys_addr_t ext_buffer_start,
+	phys_addr_t ext_buffer_end, u32 start_byte_number, phys_addr_t y_addr,
+	phys_addr_t c_addr)
+{
+	vidc_720p_write(0x0018, ext_buffer_start);
+
+	vidc_720p_write(0x001C, ext_buffer_end);
+
+	vidc_720p_write(0x0024, ext_buffer_start);
+
+	vidc_720p_write(0x005C, start_byte_number);
+
+	vidc_720p_write(0x99105, y_addr);
+
+	vidc_720p_write(0x0804, c_addr);
+
+	vidc_720p_submit_command(ch_id, VIDC_720P_CMD_FRAMERUN);
+}
+
+void vidc_720p_encode_get_header(u32 *pi_enc_header_size)
+{
+	*pi_enc_header_size = vidc_720p_read(0x0060);
+}
+
+void vidc_720p_enc_frame_info(struct vidc_720p_enc_frame_info *enc_frame_info)
+{
+	enc_frame_info->enc_size = vidc_720p_read(0x0058);
+
+	enc_frame_info->frame_type = vidc_720p_read(0x0EBC);
+
+	enc_frame_info->frame_type &= 0x03;
+
+	enc_frame_info->metadata_exists = vidc_720p_read(0x0EB8);
+}
+
+void vidc_720p_decode_bitstream_header(u32 ch_id, u32 dec_unit_size,
+		u32 start_byte_num, u32 ext_buffer_start, u32 ext_buffer_end,
+		enum vidc_720p_memory_access_method_type memory_access_model)
+{
+	vidc_720p_write(0x0E04, 0x0);
+
+	vidc_720p_write(0x0018, ext_buffer_start);
+
+	vidc_720p_write(0x001C, ext_buffer_end);
+
+	vidc_720p_write(0x0024, ext_buffer_end);
+
+	vidc_720p_write(0x0054, dec_unit_size);
+
+	vidc_720p_write(0x005C, start_byte_num);
+
+	vidc_720p_write(0x0600, memory_access_model);
+
+	vidc_720p_submit_command(ch_id, VIDC_720P_CMD_INITCODEC);
+}
+
+void vidc_720p_decode_get_seq_hdr_info(struct vidc_720p_seq_hdr_info_type
+		*seq_hdr_info)
+{
+	unsigned long tmp;
+
+	seq_hdr_info->img_size_x = vidc_720p_read(0x0118);
+
+	seq_hdr_info->img_size_y = vidc_720p_read(0x011C);
+
+	seq_hdr_info->min_num_dpb = vidc_720p_read(0x0E10);
+
+	seq_hdr_info->min_dpb_size = vidc_720p_read(0x0C10);
+
+	seq_hdr_info->dec_frm_size = vidc_720p_read(0x0C08);
+
+	tmp = vidc_720p_read(0x0C0C);
+	seq_hdr_info->profile = tmp & 0x1f;
+	seq_hdr_info->level = (tmp & 0xff00) >> 8;
+
+	tmp = vidc_720p_read(0x0408);
+	seq_hdr_info->progressive = (tmp & 0x4) >> 2;
+	/* bit 3 is for crop existence */
+	seq_hdr_info->crop_exists = (tmp & 0x8) >> 3;
+
+	if (seq_hdr_info->crop_exists) {
+		/* read the cropping information */
+		tmp = vidc_720p_read(0x0C00);
+		seq_hdr_info->crop_right_offset = (tmp & 0xffff0000) >> 0x10;
+		seq_hdr_info->crop_left_offset = tmp & 0xffff;
+		tmp = vidc_720p_read(0x0C04);
+		seq_hdr_info->crop_bottom_offset = (tmp & 0xffff0000) >> 0x10;
+		seq_hdr_info->crop_top_offset = tmp & 0xffff;
+	}
+	/* Read the MPEG4 data partitioning indication */
+	seq_hdr_info->data_partitioned = (vidc_720p_read(0x0EBC) & 0x8) >> 3;
+}
+
+void vidc_720p_decode_set_dpb_release_buffer_mask(u32 dpb_release_buffer_mask)
+{
+	vidc_720p_write(0x0E98, dpb_release_buffer_mask);
+}
+
+void vidc_720p_decode_set_dpb_buffers(u32 i, phys_addr_t dpb_buffer)
+{
+	vidc_720p_write(0x0E18 + sizeof(i) * i, dpb_buffer);
+}
+
+void vidc_720p_decode_set_comv_buffer(phys_addr_t pi_dpb_comv_buffer,
+	size_t alloc_len)
+{
+	vidc_720p_write(0x0904, pi_dpb_comv_buffer);
+
+	vidc_720p_write(0x0D08, alloc_len);
+}
+
+void vidc_720p_decode_set_dpb_details(u32 num_dpb, size_t alloc_len,
+	phys_addr_t ref_buffer)
+{
+	vidc_720p_write(0x0900, ref_buffer);
+
+	vidc_720p_write(0x0908, 0);
+
+	vidc_720p_write(0x0E14, num_dpb);
+
+	vidc_720p_write(0x0ED4, alloc_len);
+}
+
+void vidc_720p_decode_set_mpeg4Post_filter(u32 enable_post_filter)
+{
+	if (enable_post_filter)
+		vidc_720p_write(0x0124, 0x1);
+	else
+		vidc_720p_write(0x0124, 0x0);
+}
+
+void vidc_720p_decode_set_error_control(u32 enable_error_control)
+{
+	if (enable_error_control)
+		vidc_720p_write(0x013C, 0);
+	else
+		vidc_720p_write(0x013C, 1);
+}
+
+void vidc_720p_set_deblock_line_buffer(dma_addr_t pi_deblock_line_buffer_start,
+					size_t alloc_len)
+{
+	vidc_720p_write(0x0234, pi_deblock_line_buffer_start);
+
+	vidc_720p_write(0x0D04, alloc_len);
+}
+
+void vidc_720p_decode_set_mpeg4_data_partitionbuffer(dma_addr_t vsp_buf_start)
+{
+	vidc_720p_write(0x0230, vsp_buf_start);
+}
+
+void vidc_720p_decode_setH264VSPBuffer(dma_addr_t pi_vsp_temp_buffer_start)
+{
+	vidc_720p_write(0x0230, pi_vsp_temp_buffer_start);
+}
+
+void vidc_720p_decode_frame(u32 ch_id, phys_addr_t ext_buffer_start,
+	phys_addr_t ext_buffer_end, size_t dec_unit_size, u32 start_byte_num,
+	u32 input_frame_tag)
+{
+	vidc_720p_write(0x0018, ext_buffer_start);
+
+	vidc_720p_write(0x001C, ext_buffer_end);
+
+	vidc_720p_write(0x0024, ext_buffer_end);
+
+	vidc_720p_write(0x005C, start_byte_num);
+
+	vidc_720p_write(0x0EE0, input_frame_tag);
+
+	vidc_720p_write(0x0054, dec_unit_size);
+
+	vidc_720p_submit_command(ch_id, VIDC_720P_CMD_FRAMERUN);
+}
+
+void vidc_720p_issue_eos(u32 ch_id)
+{
+	vidc_720p_write(0x0028, 0x1);
+
+	vidc_720p_write(0x0054, 0);
+
+	vidc_720p_submit_command(ch_id, VIDC_720P_CMD_FRAMERUN);
+}
+
+void vidc_720p_eos_info(u32 *disp_status)
+{
+	*disp_status = vidc_720p_read(0x0408) & 0x3;
+}
+
+void vidc_720p_decode_display_info(struct vidc_720p_dec_disp_info *disp_info)
+{
+	unsigned long tmp;
+
+	tmp = vidc_720p_read(0x0408);
+
+	disp_info->disp_status = (enum vidc_720p_display_status_type)
+		(tmp & 0x3);
+
+	disp_info->disp_is_interlace = (tmp & 0x4) >> 2;
+	disp_info->crop_exists = (tmp & 0x8) >> 3;
+
+	disp_info->resl_change = (tmp & 0x30) >> 4;
+
+	disp_info->reconfig_flush_done = vidc_720p_read(0x0EC0) & 0x1;
+
+	disp_info->img_size_x = vidc_720p_read(0x0118);
+	disp_info->img_size_y = vidc_720p_read(0x011C);
+	disp_info->y_addr = vidc_720p_read(0x0400);
+	disp_info->c_addr = vidc_720p_read(0x0404);
+	disp_info->tag_top = vidc_720p_read(0x0EA8);
+	disp_info->tag_bottom = vidc_720p_read(0x0EE4);
+	disp_info->pic_time_top = vidc_720p_read(0x0ED8);
+	disp_info->pic_time_bottom = vidc_720p_read(0x0EDC);
+
+	if (disp_info->crop_exists) {
+		tmp = vidc_720p_read(0x0C00);
+		disp_info->crop_right_offset = (tmp & 0xffff0000) >> 0x10;
+		disp_info->crop_left_offset = tmp & 0xffff;
+		tmp = vidc_720p_read(0x0C04);
+		disp_info->crop_bottom_offset = (tmp & 0xffff0000) >> 0x10;
+		disp_info->crop_top_offset = tmp & 0xffff;
+	}
+	disp_info->metadata_exists = vidc_720p_read(0x0EB8);
+
+	disp_info->input_bytes_consumed = vidc_720p_read(0x0C08);
+
+	disp_info->input_frame_num = vidc_720p_read(0x0410);
+
+	disp_info->input_frame_type = vidc_720p_read(0x0EBC) & 0x7;
+
+	disp_info->input_is_interlace = (disp_info->input_frame_type & 0x4) >>
+		2;
+
+	disp_info->input_frame_type &= 0x3;
+}
+
+void vidc_720p_decode_skip_frm_details(phys_addr_t *free_luma_dpb)
+{
+	u32 disp_frm_type;
+
+	disp_frm_type = vidc_720p_read(0x0EB4);
+
+	if (disp_frm_type == VIDC_720P_NOTCODED)
+		*free_luma_dpb = vidc_720p_read(0x0C18);
+}
+
+void vidc_720p_metadata_enable(u32 flag, phys_addr_t input_buffer)
+{
+	vidc_720p_write(0x0EC4, flag);
+	vidc_720p_write(0x0ED0, input_buffer);
+}
+
+void vidc_720p_decode_dynamic_req_reset(void)
+{
+	vidc_720p_write(0x0EE8, 0x0);
+	vidc_720p_write(0x0EAC, 0x0);
+	vidc_720p_write(0x0028, 0x0);
+}
+
+void vidc_720p_decode_dynamic_req_set(u32 property)
+{
+	if (property == VIDC_720P_FLUSH_REQ)
+		vidc_720p_write(0x0EE8, 0x1);
+	else if (property == VIDC_720P_EXTRADATA)
+		vidc_720p_write(0x0EAC, 0x1);
+}
+
+void vidc_720p_decode_setpassthrough_start(phys_addr_t pass_startaddr)
+{
+	vidc_720p_write(0x0D18, pass_startaddr);
+}
diff --git a/drivers/misc/video_core/720p/ddl/video_core_720p.h b/drivers/misc/video_core/720p/ddl/video_core_720p.h
new file mode 100644
index 0000000..14853f9
--- /dev/null
+++ b/drivers/misc/video_core/720p/ddl/video_core_720p.h
@@ -0,0 +1,395 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef VID_C_720P_H
+#define VID_C_720P_H
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <asm/system.h>
+
+/** List all the levels and their register values */
+
+#define VIDC_720P_PROFILE_MPEG4_SP      0
+#define VIDC_720P_PROFILE_MPEG4_ASP     1
+#define VIDC_720P_PROFILE_H264_BASELINE 0
+#define VIDC_720P_PROFILE_H264_MAIN     1
+#define VIDC_720P_PROFILE_H264_HIGH     2
+#define VIDC_720P_PROFILE_H263_BASELINE 0
+
+#define VIDC_720P_PROFILE_VC1_SP        0
+#define VIDC_720P_PROFILE_VC1_MAIN      1
+#define VIDC_720P_PROFILE_VC1_ADV       2
+#define VIDC_720P_PROFILE_MPEG2_MAIN    4
+#define VIDC_720P_PROFILE_MPEG2_SP      5
+
+#define VIDC_720P_MPEG4_LEVEL0  0
+#define VIDC_720P_MPEG4_LEVEL0b 9
+#define VIDC_720P_MPEG4_LEVEL1  1
+#define VIDC_720P_MPEG4_LEVEL2  2
+#define VIDC_720P_MPEG4_LEVEL3  3
+#define VIDC_720P_MPEG4_LEVEL3b 7
+#define VIDC_720P_MPEG4_LEVEL4a 4
+#define VIDC_720P_MPEG4_LEVEL5  5
+#define VIDC_720P_MPEG4_LEVEL6  6
+
+#define VIDC_720P_H264_LEVEL1     10
+#define VIDC_720P_H264_LEVEL1b    9
+#define VIDC_720P_H264_LEVEL1p1   11
+#define VIDC_720P_H264_LEVEL1p2   12
+#define VIDC_720P_H264_LEVEL1p3   13
+#define VIDC_720P_H264_LEVEL2     20
+#define VIDC_720P_H264_LEVEL2p1   21
+#define VIDC_720P_H264_LEVEL2p2   22
+#define VIDC_720P_H264_LEVEL3     30
+#define VIDC_720P_H264_LEVEL3p1   31
+#define VIDC_720P_H264_LEVEL3p2   32
+
+#define VIDC_720P_H263_LEVEL10    10
+#define VIDC_720P_H263_LEVEL20    20
+#define VIDC_720P_H263_LEVEL30    30
+#define VIDC_720P_H263_LEVEL40    40
+#define VIDC_720P_H263_LEVEL45    45
+#define VIDC_720P_H263_LEVEL50    50
+#define VIDC_720P_H263_LEVEL60    60
+#define VIDC_720P_H263_LEVEL70    70
+
+#define VIDC_720P_VC1_LEVEL_LOW    0
+#define VIDC_720P_VC1_LEVEL_MED    2
+#define VIDC_720P_VC1_LEVEL_HIGH   4
+#define VIDC_720P_VC1_LEVEL0       0
+#define VIDC_720P_VC1_LEVEL1       1
+#define VIDC_720P_VC1_LEVEL2       2
+#define VIDC_720P_VC1_LEVEL3       3
+#define VIDC_720P_VC1_LEVEL4       4
+
+#define VIDCL_720P_MPEG2_LEVEL_LOW 10
+#define VIDCL_720P_MPEG2_LEVEL_MAIN 8
+#define VIDCL_720P_MPEG2_LEVEL_HIGH14 6
+
+#define VIDC_720P_CMD_CHSET               0x0
+#define VIDC_720P_CMD_CHEND               0x2
+#define VIDC_720P_CMD_INITCODEC           0x3
+#define VIDC_720P_CMD_FRAMERUN            0x4
+#define VIDC_720P_CMD_INITBUFFERS         0x5
+#define VIDC_720P_CMD_FRAMERUN_REALLOCATE 0x6
+#define VIDC_720P_CMD_MFC_ENGINE_RESET 0x7
+
+enum vidc_720p_endian_type {
+	VIDC_720P_BIG_ENDIAN = 0x0,
+	VIDC_720P_LITTLE_ENDIAN = 0x1
+};
+
+enum vidc_720p_memory_access_method_type {
+	VIDC_720P_TILE_LINEAR = 0,
+	VIDC_720P_TILE_16x16 = 2,
+	VIDC_720P_TILE_64x32 = 3
+};
+
+enum vidc_720p_interrupt_control_mode_type {
+	VIDC_720P_INTERRUPT_MODE = 0,
+	VIDC_720P_POLL_MODE = 1
+};
+
+enum vidc_720p_interrupt_level_selection_type {
+	VIDC_720P_INTERRUPT_LEVEL_SEL = 0,
+	VIDC_720P_INTERRUPT_PULSE_SEL = 1
+};
+
+#define VIDC_720P_INTR_BUFFER_FULL             0x002
+#define VIDC_720P_INTR_FW_DONE                 0x020
+#define VIDC_720P_INTR_HEADER_DONE             0x040
+#define VIDC_720P_INTR_DMA_DONE                0x080
+#define VIDC_720P_INTR_FRAME_DONE              0x100
+
+enum vidc_720p_enc_dec_selection_type {
+	VIDC_720P_DECODER = 0,
+	VIDC_720P_ENCODER = 1
+};
+
+enum vidc_720p_codec_type {
+	VIDC_720P_MPEG4 = 0,
+	VIDC_720P_H264 = 1,
+	VIDC_720P_DIVX = 2,
+	VIDC_720P_XVID = 3,
+	VIDC_720P_H263 = 4,
+	VIDC_720P_MPEG2 = 5,
+	VIDC_720P_VC1 = 6
+};
+
+enum vidc_720p_frame_type {
+	VIDC_720P_NOTCODED = 0,
+	VIDC_720P_IFRAME = 1,
+	VIDC_720P_PFRAME = 2,
+	VIDC_720P_BFRAME = 3
+};
+
+enum vidc_720p_entropy_sel_type {
+	VIDC_720P_ENTROPY_SEL_CAVLC = 0,
+	VIDC_720P_ENTROPY_SEL_CABAC = 1
+};
+
+enum vidc_720p_cabac_model_type {
+	VIDC_720P_CABAC_MODEL_NUMBER_0 = 0,
+	VIDC_720P_CABAC_MODEL_NUMBER_1 = 1,
+	VIDC_720P_CABAC_MODEL_NUMBER_2 = 2
+};
+
+enum vidc_720p_DBConfig_type {
+	VIDC_720P_DB_ALL_BLOCKING_BOUNDARY = 0,
+	VIDC_720P_DB_DISABLE = 1,
+	VIDC_720P_DB_SKIP_SLICE_BOUNDARY = 2
+};
+
+enum vidc_720p_MSlice_selection_type {
+	VIDC_720P_MSLICE_BY_MB_COUNT = 0,
+	VIDC_720P_MSLICE_BY_BYTE_COUNT = 1,
+	VIDC_720P_MSLICE_BY_GOB = 2,
+	VIDC_720P_MSLICE_OFF = 3
+};
+
+enum vidc_720p_display_status_type {
+	VIDC_720P_DECODE_ONLY = 0,
+	VIDC_720P_DECODE_AND_DISPLAY = 1,
+	VIDC_720P_DISPLAY_ONLY = 2,
+	VIDC_720P_EMPTY_BUFFER = 3
+};
+
+#define VIDC_720P_ENC_IFRAME_REQ       0x1
+#define VIDC_720P_ENC_IPERIOD_CHANGE   0x1
+#define VIDC_720P_ENC_FRAMERATE_CHANGE 0x2
+#define VIDC_720P_ENC_BITRATE_CHANGE   0x4
+
+#define VIDC_720P_FLUSH_REQ     0x1
+#define VIDC_720P_EXTRADATA     0x2
+
+#define VIDC_720P_METADATA_ENABLE_QP           0x01
+#define VIDC_720P_METADATA_ENABLE_CONCEALMB    0x02
+#define VIDC_720P_METADATA_ENABLE_VC1          0x04
+#define VIDC_720P_METADATA_ENABLE_SEI          0x08
+#define VIDC_720P_METADATA_ENABLE_VUI          0x10
+#define VIDC_720P_METADATA_ENABLE_ENCSLICE     0x20
+#define VIDC_720P_METADATA_ENABLE_PASSTHROUGH  0x40
+
+struct vidc_720p_dec_disp_info {
+	enum vidc_720p_display_status_type disp_status;
+	u32 resl_change;
+	u32 reconfig_flush_done;
+	u32 img_size_x;
+	u32 img_size_y;
+	phys_addr_t y_addr;
+	phys_addr_t c_addr;
+	u32 tag_top;
+	u32 pic_time_top;
+	u32 disp_is_interlace;
+	u32 tag_bottom;
+	u32 pic_time_bottom;
+	u32 metadata_exists;
+	u32 crop_exists;
+	u32 crop_right_offset;
+	u32 crop_left_offset;
+	u32 crop_bottom_offset;
+	u32 crop_top_offset;
+	u32 input_frame_type;
+	u32 input_bytes_consumed;
+	u32 input_is_interlace;
+	u32 input_frame_num;
+};
+
+struct vidc_720p_seq_hdr_info_type {
+	u32 img_size_x;
+	u32 img_size_y;
+	u32 dec_frm_size;
+	u32 min_num_dpb;
+	u32 min_dpb_size;
+	u32 profile;
+	u32 level;
+	u32 progressive;
+	u32 data_partitioned;
+	u32 crop_exists;
+	u32 crop_right_offset;
+	u32 crop_left_offset;
+	u32 crop_bottom_offset;
+	u32 crop_top_offset;
+};
+
+struct vidc_720p_enc_frame_info {
+	u32 enc_size;
+	u32 frame_type;
+	u32 metadata_exists;
+};
+
+void vidc_720p_set_device_virtual_base(void *virt_addr);
+
+void vidc_720p_init(char **ppsz_version, size_t sz, phys_addr_t phys_addr,
+	enum vidc_720p_endian_type dma_endian, u32 interrupt_off,
+	enum vidc_720p_interrupt_level_selection_type interrupt_sel,
+	u32 interrupt_mask);
+
+u32 vidc_720p_do_sw_reset(void);
+
+u32 vidc_720p_reset_is_success(void);
+
+void vidc_720p_start_cpu(enum vidc_720p_endian_type dma_endian,
+	phys_addr_t icontext_bufferstart, phys_addr_t debug_core_dump_addr,
+	size_t debug_buffer_size);
+
+u32 vidc_720p_cpu_start(void);
+
+void vidc_720p_stop_fw(void);
+
+void vidc_720p_get_interrupt_status(u32 *interrupt_status, u32 *cmd_err_status,
+	u32 *disp_pic_err_status, u32 *op_failed);
+
+void vidc_720p_interrupt_done_clear(void);
+
+void vidc_720p_submit_command(u32 ch_id, u32 cmd_id);
+
+
+void vidc_720p_set_channel(u32 ch_id,
+	enum vidc_720p_enc_dec_selection_type enc_dec_sel,
+	enum vidc_720p_codec_type codec, dma_addr_t pi_fw,
+	size_t firmware_size);
+
+u32 vidc_720p_engine_reset(u32 ch_id,
+	enum vidc_720p_endian_type dma_endian,
+	enum vidc_720p_interrupt_level_selection_type interrupt_sel,
+	u32 interrupt_mask
+);
+
+void vidc_720p_encode_set_profile(u32 profile, u32 level);
+
+void vidc_720p_set_frame_size(u32 size_x, u32 size_y);
+
+void vidc_720p_encode_set_fps(u32 rc_frame_rate);
+
+void vidc_720p_encode_set_vop_time(u32 vop_time_resolution,
+	u32 vop_time_increment);
+
+void vidc_720p_encode_set_hec_period(u32 hec_period);
+
+void vidc_720p_encode_set_short_header(u32 short_header);
+
+void vidc_720p_encode_set_qp_params(u32 max_qp, u32 min_qp);
+
+void vidc_720p_encode_set_rc_config(u32 enable_frame_level_rc,
+	u32 enable_mb_level_rc_flag, u32 iframe_qp, u32 pframe_qp);
+
+void vidc_720p_encode_set_bit_rate(u32 target_bitrate);
+
+void vidc_720p_encoder_set_param_change(u32 enc_param_change);
+
+void vidc_720p_encode_set_control_param(u32 param_val);
+
+void vidc_720p_encode_set_frame_level_rc_params(u32 reaction_coeff);
+
+void vidc_720p_encode_set_mb_level_rc_params(u32 dark_region_as_flag,
+	u32 smooth_region_as_flag, u32 static_region_as_flag,
+	u32 activity_region_flag);
+
+void vidc_720p_encode_set_entropy_control(enum vidc_720p_entropy_sel_type
+	entropy_sel, enum vidc_720p_cabac_model_type cabac_model_number);
+
+void vidc_720p_encode_set_db_filter_control(enum vidc_720p_DBConfig_type
+	db_config, u32 slice_alpha_offset, u32 slice_beta_offset);
+
+void vidc_720p_encode_set_intra_refresh_mb_number(u32 cir_mb_number);
+
+void vidc_720p_encode_set_multi_slice_info(enum vidc_720p_MSlice_selection_type
+	m_slice_sel, u32 multi_slice_size);
+
+void vidc_720p_encode_set_dpb_buffer(phys_addr_t pi_enc_dpb_addr,
+	size_t alloc_len);
+
+void vidc_720p_set_deblock_line_buffer(phys_addr_t pi_deblock_line_buffer_start,
+	size_t alloc_len);
+
+void vidc_720p_encode_set_i_period(u32 period);
+
+void vidc_720p_encode_init_codec(u32 ch_id,
+	enum vidc_720p_memory_access_method_type memory_access_model);
+
+void vidc_720p_encode_unalign_bitstream(u32 upper_unalign_word,
+	u32 lower_unalign_word);
+
+void vidc_720p_encode_set_seq_header_buffer(phys_addr_t ext_buffer_start,
+	phys_addr_t ext_buffer_end, u32 start_byte_num);
+
+void vidc_720p_encode_frame(u32 ch_id, phys_addr_t ext_buffer_start,
+	phys_addr_t ext_buffer_end, u32 start_byte_number, phys_addr_t y_addr,
+	phys_addr_t c_addr);
+
+void vidc_720p_encode_get_header(u32 *pi_enc_header_size);
+
+void vidc_720p_enc_frame_info(struct vidc_720p_enc_frame_info *enc_frame_info);
+
+void vidc_720p_decode_bitstream_header(u32 ch_id, u32 dec_unit_size,
+	u32 start_byte_num, u32 ext_buffer_start, u32 ext_buffer_end,
+	enum vidc_720p_memory_access_method_type memory_access_model);
+
+void vidc_720p_decode_get_seq_hdr_info(struct vidc_720p_seq_hdr_info_type
+	*seq_hdr_info);
+
+void vidc_720p_decode_set_dpb_release_buffer_mask(u32 dpb_release_buffer_mask);
+
+void vidc_720p_decode_set_dpb_buffers(u32 buf_index, phys_addr_t pi_dpb_buffer);
+
+void vidc_720p_decode_set_comv_buffer(dma_addr_t pi_dpb_comv_buffer,
+	size_t alloc_len);
+
+void vidc_720p_decode_set_dpb_details(u32 num_dpb, size_t alloc_len,
+	phys_addr_t ref_buffer);
+
+void vidc_720p_decode_set_mpeg4Post_filter(u32 enable_post_filter);
+
+void vidc_720p_decode_set_error_control(u32 enable_error_control);
+
+void vidc_720p_decode_set_mpeg4_data_partitionbuffer(dma_addr_t vsp_buf_start);
+
+void vidc_720p_decode_setH264VSPBuffer(dma_addr_t pi_vsp_temp_buffer_start);
+
+void vidc_720p_decode_frame(u32 ch_id, phys_addr_t ext_buffer_start,
+	phys_addr_t ext_buffer_end, size_t dec_unit_size, u32 start_byte_num,
+	u32 input_frame_tag);
+
+void vidc_720p_issue_eos(u32 ch_id);
+void vidc_720p_eos_info(u32 *disp_status);
+
+void vidc_720p_decode_display_info(struct vidc_720p_dec_disp_info *disp_info);
+
+void vidc_720p_decode_skip_frm_details(phys_addr_t *free_luma_dpb);
+
+void vidc_720p_metadata_enable(u32 flag, phys_addr_t input_buffer);
+
+void vidc_720p_decode_dynamic_req_reset(void);
+
+void vidc_720p_decode_dynamic_req_set(u32 property);
+
+void vidc_720p_decode_setpassthrough_start(phys_addr_t pass_startaddr);
+
+#endif
diff --git a/drivers/misc/video_core/720p/dec/vdec.c b/drivers/misc/video_core/720p/dec/vdec.c
new file mode 100644
index 0000000..36ca556
--- /dev/null
+++ b/drivers/misc/video_core/720p/dec/vdec.c
@@ -0,0 +1,1525 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/android_pmem.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+
+#include "vcd_ddl_firmware.h"
+#include "video_core_type.h"
+#include "vcd_api.h"
+#include "vdec_internal.h"
+#include "video_core_init.h"
+
+
+#define VID_C_HCLK_RATE 170667000
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+#define INFO(x...) printk(KERN_INFO x)
+#define ERR(x...) printk(KERN_ERR x)
+
+#define VID_DEC_NAME "msm_vidc_dec"
+
+static struct vid_dec_dev *vidc_dec_dev;
+static dev_t vidc_dec_dev_num;
+static struct class *vidc_dec_class;
+
+static s32 vid_dec_get_empty_client_index(void)
+{
+	u32 i, found = false;
+
+	for (i = 0; i < VID_DEC_MAX_DECODER_CLIENTS; i++) {
+		if (!vidc_dec_dev->vdec_clients[i].vcd_handle) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		ERR("%s():ERROR No space for new client\n", __func__);
+		return -1;
+	}
+	DBG("%s(): available client index = %u\n", __func__, i);
+	return i;
+}
+
+u32 vid_dec_get_status(u32 status)
+{
+	u32 vdec_status;
+
+	switch (status) {
+	case VCD_ERR_BITSTREAM_ERR:
+	case VCD_S_SUCCESS:
+		vdec_status = VDEC_S_SUCCESS;
+		break;
+	case VCD_ERR_FAIL:
+		vdec_status = VDEC_S_EFAIL;
+		break;
+	case VCD_ERR_ALLOC_FAIL:
+		vdec_status = VDEC_S_ENOSWRES;
+		break;
+	case VCD_ERR_ILLEGAL_OP:
+		vdec_status = VDEC_S_EINVALCMD;
+		break;
+	case VCD_ERR_ILLEGAL_PARM:
+		vdec_status = VDEC_S_EBADPARAM;
+		break;
+	case VCD_ERR_BAD_POINTER:
+	case VCD_ERR_BAD_HANDLE:
+		vdec_status = VDEC_S_EFATAL;
+		break;
+	case VCD_ERR_NOT_SUPPORTED:
+		vdec_status = VDEC_S_ENOTSUPP;
+		break;
+	case VCD_ERR_BAD_STATE:
+		vdec_status = VDEC_S_EINVALSTATE;
+		break;
+	case VCD_ERR_BUSY:
+		vdec_status = VDEC_S_BUSY;
+		break;
+	case VCD_ERR_MAX_CLIENT:
+		vdec_status = VDEC_S_ENOHWRES;
+		break;
+	default:
+		vdec_status = VDEC_S_EFAIL;
+		break;
+	}
+
+	return vdec_status;
+}
+
+static void vid_dec_notify_client(struct video_client_ctx *client_ctx)
+{
+	if (client_ctx)
+		complete(&client_ctx->event);
+}
+
+void vid_dec_vcd_open_done(struct video_client_ctx *client_ctx,
+	struct vcd_handle_container *handle_container)
+{
+	DBG("vid_dec_vcd_open_done\n");
+
+	if (!client_ctx) {
+		ERR("%s(): ERROR. client_ctx is NULL\n", __func__);
+		return;
+	}
+
+	if (handle_container)
+		client_ctx->vcd_handle = handle_container->handle;
+	else
+		ERR("%s(): ERROR. handle_container is NULL\n", __func__);
+
+	vid_dec_notify_client(client_ctx);
+}
+
+static void vid_dec_input_frame_done(struct video_client_ctx *client_ctx,
+	u32 event, u32 status, struct vcd_frame_data *vcd_frame_data)
+{
+	struct vid_dec_msg *vdec_msg;
+
+	if (!client_ctx || !vcd_frame_data) {
+		ERR("vid_dec_input_frame_done() NULL pointer\n");
+		return;
+	}
+
+	vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+	if (!vdec_msg) {
+		ERR("%s: cannot allocate vid_dec_msg buffer\n", __func__);
+		return;
+	}
+
+	vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
+
+	if (event == VCD_EVT_RESP_INPUT_DONE) {
+		vdec_msg->vdec_msg_info.msgcode =
+			VDEC_MSG_RESP_INPUT_BUFFER_DONE;
+		DBG("Send INPUT_DON message to client = %p\n", client_ctx);
+
+	} else if (event == VCD_EVT_RESP_INPUT_FLUSHED) {
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_INPUT_FLUSHED;
+		DBG("Send INPUT_FLUSHED message to client = %p\n", client_ctx);
+	} else {
+		ERR("%s: invalid event type\n", __func__);
+		return;
+	}
+
+	vdec_msg->vdec_msg_info.msgdata.input_frame_clientdata =
+		vcd_frame_data->client_data;
+	vdec_msg->vdec_msg_info.msgdatasize = sizeof(void *);
+
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+static void vid_dec_output_frame_done(struct video_client_ctx *client_ctx,
+	u32 event, u32 status, struct vcd_frame_data *vcd_frame_data)
+{
+	struct vid_dec_msg *vdec_msg;
+
+	void __user *user_addr;
+	void *kern_addr;
+	phys_addr_t phys_addr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	struct vdec_output_frameinfo *frm;
+
+	if (!client_ctx || !vcd_frame_data) {
+		ERR("%s: NULL pointer\n", __func__);
+		return;
+	}
+
+	vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+	if (!vdec_msg) {
+		ERR("%s: cannot allocate vid_dec_msg buffer\n", __func__);
+		return;
+	}
+
+	vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
+
+	if (event == VCD_EVT_RESP_OUTPUT_DONE) {
+		vdec_msg->vdec_msg_info.msgcode =
+			VDEC_MSG_RESP_OUTPUT_BUFFER_DONE;
+	} else if (event == VCD_EVT_RESP_OUTPUT_FLUSHED) {
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_OUTPUT_FLUSHED;
+	} else {
+		ERR("QVD: vid_dec_output_frame_done invalid cmd type\n");
+		return;
+	}
+
+	kern_addr = vcd_frame_data->virt_addr;
+
+	if (!vid_c_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT, false,
+			&user_addr, &kern_addr, &phys_addr, &pmem_fd, &file,
+			&buffer_index)) {
+		ERR("vid_dec_output_frame_done UVA can not be found\n");
+		vdec_msg->vdec_msg_info.status_code = VDEC_S_EFATAL;
+		goto out;
+	}
+
+	frm = &vdec_msg->vdec_msg_info.msgdata.output_frame;
+	/* Buffer address in user space */
+	frm->user_addr = user_addr;
+	frm->phys_addr = vcd_frame_data->phys_addr;
+	/* Data length */
+	frm->len = vcd_frame_data->data_len;
+	frm->flags = vcd_frame_data->flags;
+	/* timestamp pass-through from input frame */
+	frm->time_stamp = vcd_frame_data->time_stamp;
+	/* Output frame client data */
+	frm->client_data = vcd_frame_data->client_data;
+	/* Associated input frame client data */
+	frm->input_frame_clientdata = (void *)vcd_frame_data->ip_frm_tag;
+	/* Decoded picture width and height */
+	frm->framesize.bottom = vcd_frame_data->dec_op_prop.disp_frm.bottom;
+	frm->framesize.left = vcd_frame_data->dec_op_prop.disp_frm.left;
+	frm->framesize.right = vcd_frame_data->dec_op_prop.disp_frm.right;
+	frm->framesize.top = vcd_frame_data->dec_op_prop.disp_frm.top;
+	vdec_msg->vdec_msg_info.msgdatasize = sizeof(*frm);
+
+out:
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+static void vid_dec_lean_event(struct video_client_ctx *client_ctx,
+	u32 event, u32 status)
+{
+	struct vid_dec_msg *vdec_msg;
+
+	if (!client_ctx) {
+		ERR("%s(): !client_ctx pointer\n", __func__);
+		return;
+	}
+
+	vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+	if (!vdec_msg) {
+		ERR("%s(): cannot allocate vid_dec_msg buffer\n", __func__);
+		return;
+	}
+
+	vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
+
+	switch (event) {
+	case VCD_EVT_IND_RECONFIG:
+		INFO("msm_vidc_dec: Sending VDEC_MSG_EVT_CONFIG_CHANGED"
+			 " to client\n");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_CONFIG_CHANGED;
+		break;
+	case VCD_EVT_IND_RESOURCES_LOST:
+		INFO("msm_vidc_dec: Sending VDEC_EVT_RESOURCES_LOST"
+			 " to client\n");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_EVT_RESOURCES_LOST;
+		break;
+	case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+		INFO("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_INPUT_DONE"
+			 " to client\n");
+		vdec_msg->vdec_msg_info.msgcode =
+			VDEC_MSG_RESP_FLUSH_INPUT_DONE;
+		break;
+	case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+		INFO("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_OUTPUT_DONE"
+			 " to client\n");
+		vdec_msg->vdec_msg_info.msgcode =
+			VDEC_MSG_RESP_FLUSH_OUTPUT_DONE;
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+		INFO("msm_vidc_dec: Sending VDEC_MSG_EVT_HW_ERROR to client\n");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_HW_ERROR;
+		break;
+	case VCD_EVT_RESP_START:
+		INFO("msm_vidc_dec: Sending VDEC_MSG_RESP_START_DONE"
+			 " to client\n");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_START_DONE;
+		break;
+	case VCD_EVT_RESP_STOP:
+		INFO("msm_vidc_dec: Sending VDEC_MSG_RESP_STOP_DONE"
+			 " to client\n");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_STOP_DONE;
+		break;
+	case VCD_EVT_RESP_PAUSE:
+		INFO("msm_vidc_dec: Sending VDEC_MSG_RESP_PAUSE_DONE"
+			 " to client\n");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_PAUSE_DONE;
+		break;
+	default:
+		ERR("%s() : unknown event type\n", __func__);
+		break;
+	}
+
+	vdec_msg->vdec_msg_info.msgdatasize = 0;
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+
+void vid_dec_vcd_cb(u32 event, u32 status, void *info, u32 size, void *handle,
+	void *const client_data)
+{
+	struct video_client_ctx *client_ctx = (struct video_client_ctx *)
+		client_data;
+
+	DBG("Entering %s()\n", __func__);
+
+	if (!client_ctx) {
+		ERR("%s(): client_ctx is NULL\n", __func__);
+		return;
+	}
+
+	client_ctx->event_status = status;
+
+	switch (event) {
+	case VCD_EVT_RESP_OPEN:
+		vid_dec_vcd_open_done(client_ctx, info);
+		break;
+	case VCD_EVT_RESP_INPUT_DONE:
+	case VCD_EVT_RESP_INPUT_FLUSHED:
+		vid_dec_input_frame_done(client_ctx, event, status, info);
+		break;
+	case VCD_EVT_RESP_OUTPUT_DONE:
+	case VCD_EVT_RESP_OUTPUT_FLUSHED:
+		vid_dec_output_frame_done(client_ctx, event, status, info);
+		break;
+	case VCD_EVT_RESP_PAUSE:
+	case VCD_EVT_RESP_STOP:
+	case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+	case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+	case VCD_EVT_IND_RECONFIG:
+	case VCD_EVT_IND_HWERRFATAL:
+	case VCD_EVT_IND_RESOURCES_LOST:
+		vid_dec_lean_event(client_ctx, event, status);
+		break;
+	case VCD_EVT_RESP_START:
+		if (!client_ctx->seq_header_set)
+			vid_dec_lean_event(client_ctx, event, status);
+		else
+			vid_dec_notify_client(client_ctx);
+		break;
+	default:
+		ERR("%s():  Error - Invalid event type %u\n", __func__, event);
+		break;
+	}
+}
+
+static u32 vid_dec_set_codec(struct video_client_ctx *client_ctx,
+	enum vdec_codec *vdec_codec_type)
+{
+	u32 result = true;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_codec codec_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !vdec_codec_type)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+	switch (*vdec_codec_type) {
+	case VDEC_CODECTYPE_MPEG4:
+		codec_type.codec = VCD_CODEC_MPEG4;
+		break;
+	case VDEC_CODECTYPE_H264:
+		codec_type.codec = VCD_CODEC_H264;
+		break;
+	case VDEC_CODECTYPE_DIVX_3:
+		codec_type.codec = VCD_CODEC_DIVX_3;
+		break;
+	case VDEC_CODECTYPE_XVID:
+		codec_type.codec = VCD_CODEC_XVID;
+		break;
+	case VDEC_CODECTYPE_H263:
+		codec_type.codec = VCD_CODEC_H263;
+		break;
+	case VDEC_CODECTYPE_MPEG2:
+		codec_type.codec = VCD_CODEC_MPEG2;
+		break;
+	case VDEC_CODECTYPE_VC1:
+		codec_type.codec = VCD_CODEC_VC1;
+		break;
+	default:
+		result = false;
+		break;
+	}
+
+	if (result) {
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &codec_type);
+		if (vcd_status)
+			result = false;
+	}
+	return result;
+}
+
+static u32 vid_dec_set_output_format(struct video_client_ctx *client_ctx,
+	enum vdec_output_format *output_format)
+{
+	u32 result = true;
+	struct vcd_property_hdr prop_hdr;
+	struct vcd_property_buffer_format buffer_format;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !output_format)
+		return false;
+
+	prop_hdr.id = VCD_I_BUFFER_FORMAT;;
+	prop_hdr.sz = sizeof(struct vcd_property_buffer_format);
+
+	switch (*output_format) {
+	case VDEC_YUV_FORMAT_NV12:
+		buffer_format.buffer_format = VCD_BUFFER_FORMAT_NV12;
+		break;
+	case VDEC_YUV_FORMAT_TILE_4x2:
+		buffer_format.buffer_format = VCD_BUFFER_FORMAT_TILE_4x2;
+		break;
+	default:
+		result = false;
+		break;
+	}
+
+	if (!result)
+		return false;
+
+	vcd_status = vcd_set_property(client_ctx->vcd_handle, &prop_hdr,
+		&buffer_format);
+
+	//TODO fix false/true silliness
+	if (vcd_status)
+		return false;
+	else
+		return true;
+}
+
+static u32 vid_dec_set_frame_resolution(struct video_client_ctx *client_ctx,
+	struct vdec_picsize *video_resoultion)
+{
+	struct vcd_property_hdr prop_hdr;
+	struct vcd_property_frame_size res;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !video_resoultion)
+		return false;
+
+	prop_hdr.id = VCD_I_FRAME_SIZE;
+	prop_hdr.sz = sizeof(struct vcd_property_frame_size);
+	res.width = video_resoultion->frame_width;
+	res.height = video_resoultion->frame_height;
+
+	vcd_status = vcd_set_property(client_ctx->vcd_handle, &prop_hdr, &res);
+
+	if (vcd_status)
+		return false;
+	else
+		return true;
+}
+
+static u32 vid_dec_get_frame_resolution(struct video_client_ctx *client_ctx,
+	struct vdec_picsize *video_res)
+{
+	struct vcd_property_hdr prop_hdr;
+	struct vcd_property_frame_size frame_res;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !video_res)
+		return false;
+
+	prop_hdr.id = VCD_I_FRAME_SIZE;
+	prop_hdr.sz = sizeof(struct vcd_property_frame_size);
+
+	vcd_status = vcd_get_property(client_ctx->vcd_handle, &prop_hdr,
+		&frame_res);
+
+	video_res->frame_width = frame_res.width;
+	video_res->frame_height = frame_res.height;
+	video_res->scan_lines = frame_res.scan_lines;
+	video_res->stride = frame_res.stride;
+
+	if (vcd_status)
+		return false;
+	else
+		return true;
+}
+
+static u32 vid_dec_get_buffer_req(struct video_client_ctx *client_ctx,
+	struct vdec_allocatorproperty *vdec_buf_req)
+{
+	u32 vcd_status = VCD_ERR_FAIL;
+	struct vcd_buffer_requirement vcd_buf_req;
+
+	if (!client_ctx || !vdec_buf_req)
+		return false;
+
+	if (vdec_buf_req->buffer_type == VDEC_BUFFER_TYPE_INPUT) {
+		vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+			VCD_BUFFER_INPUT, &vcd_buf_req);
+	} else {
+		vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+			VCD_BUFFER_OUTPUT, &vcd_buf_req);
+	}
+
+	if (vcd_status)
+		return false;
+
+	vdec_buf_req->mincount = vcd_buf_req.min_count;
+	vdec_buf_req->maxcount = vcd_buf_req.max_count;
+	vdec_buf_req->actualcount = vcd_buf_req.actual_count;
+	vdec_buf_req->buffer_size = vcd_buf_req.size;
+	vdec_buf_req->alignment = vcd_buf_req.align;
+	vdec_buf_req->buf_poolid = vcd_buf_req.buf_pool_id;
+
+	return true;
+}
+
+static u32 vid_dec_set_buffer(struct video_client_ctx *client_ctx,
+	struct vdec_setbuffer_cmd *b_info)
+{
+	enum vcd_buffer_type buffer_type;
+	enum buffer_dir dir_buffer = BUFFER_TYPE_INPUT;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	void __user *user_addr;
+	void *kern_addr;
+	phys_addr_t phys_addr;
+	unsigned long len;
+	int pmem_fd;
+	struct file *file;
+	struct buf_addr_table *addr_table;
+	s32 buffer_index = -1;
+
+	if (!client_ctx || !b_info)
+		return false;
+
+	user_addr = b_info->buffer.addr;
+
+	if (b_info->buffer_type == VDEC_BUFFER_TYPE_OUTPUT)
+		dir_buffer = BUFFER_TYPE_OUTPUT;
+
+	/* if buffer already set, ignore */
+	if (vid_c_lookup_addr_table(client_ctx, dir_buffer, true, &user_addr,
+			&kern_addr, &phys_addr, &pmem_fd, &file,
+			&buffer_index)) {
+		DBG("%s: user_addr = %p is already set\n", __func__, user_addr);
+		return true;
+	}
+
+	if (get_pmem_file(b_info->buffer.pmem_fd, (unsigned long *)&phys_addr,
+			(unsigned long *)&kern_addr, &len, &file)) {
+		ERR("%s: get_pmem_file failed\n", __func__);
+		return false;
+	}
+	put_pmem_file(file);
+	if (b_info->buffer_type == VDEC_BUFFER_TYPE_INPUT) {
+		buffer_type = VCD_BUFFER_INPUT;
+		client_ctx->num_of_input_buffers++;
+		if (client_ctx->num_of_input_buffers > MAX_VIDEO_NUM_OF_BUFF) {
+			ERR("%s(): num_of_input_buffers reached max value"
+				" MAX_VIDEO_NUM_OF_BUFF\n", __func__);
+			client_ctx->num_of_input_buffers--;
+			return false;
+		}
+		buffer_index = client_ctx->num_of_input_buffers - 1;
+		addr_table = &client_ctx->input_buf_addr_table[buffer_index];
+		addr_table->user_addr = b_info->buffer.addr;
+		addr_table->kern_addr = kern_addr;
+		addr_table->phys_addr = phys_addr;
+		addr_table->pmem_fd = b_info->buffer.pmem_fd;
+		addr_table->file = file;
+	} else {
+		buffer_type = VCD_BUFFER_OUTPUT;
+		client_ctx->num_of_output_buffers++;
+		if (client_ctx->num_of_output_buffers >	MAX_VIDEO_NUM_OF_BUFF) {
+			ERR("%s(): num_of_outut_buffers reached max value"
+				" MAX_VIDEO_NUM_OF_BUFF\n", __func__);
+			client_ctx->num_of_output_buffers--;
+			return false;
+		}
+		buffer_index = client_ctx->num_of_output_buffers - 1;
+		addr_table = &client_ctx->output_buf_addr_table[buffer_index];
+		kern_addr = (u8 *)kern_addr + b_info->buffer.offset;
+		phys_addr += b_info->buffer.offset;
+		addr_table->user_addr =	b_info->buffer.addr;
+		addr_table->kern_addr = kern_addr;
+		addr_table->phys_addr = phys_addr;
+		addr_table->pmem_fd = b_info->buffer.pmem_fd;
+		addr_table->file = file;
+	}
+
+	vcd_status = vcd_set_buffer(client_ctx->vcd_handle, buffer_type,
+		kern_addr, b_info->buffer.sz);
+
+	if (!vcd_status)
+		return true;
+	else
+		return false;
+}
+
+static u32 vid_dec_free_buffer(struct video_client_ctx *client_ctx,
+	struct vdec_setbuffer_cmd *buffer_info)
+{
+	enum vcd_buffer_type buffer_type;
+	enum buffer_dir dir_buffer = BUFFER_TYPE_INPUT;
+	u32 vcd_status = VCD_ERR_FAIL;
+	void __user *user_addr;
+	void *kern_addr;
+	phys_addr_t phys_addr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+
+	if (!client_ctx || !buffer_info)
+		return false;
+
+	user_addr = buffer_info->buffer.addr;
+
+	if (buffer_info->buffer_type == VDEC_BUFFER_TYPE_OUTPUT)
+		dir_buffer = BUFFER_TYPE_OUTPUT;
+
+	/*If buffer already set, ignore */
+	if (!vid_c_lookup_addr_table(client_ctx, dir_buffer, true, &user_addr,
+			&kern_addr, &phys_addr, &pmem_fd, &file,
+			&buffer_index)) {
+		DBG("%s: user_addr = %p is already set\n", __func__, user_addr);
+		return true;
+	}
+
+	if (buffer_info->buffer_type == VDEC_BUFFER_TYPE_INPUT)
+		buffer_type = VCD_BUFFER_INPUT;
+	else
+		buffer_type = VCD_BUFFER_OUTPUT;
+	vcd_status = vcd_free_buffer(client_ctx->vcd_handle, buffer_type,
+		kern_addr);
+
+	if (!vcd_status)
+		return true;
+	else
+		return false;
+}
+
+static u32 vid_dec_pause_resume(struct video_client_ctx *client_ctx, u32 pause)
+{
+	u32 vcd_status;
+
+	if (!client_ctx) {
+		ERR("%s: Invalid client_ctx\n", __func__);
+		return false;
+	}
+
+	if (pause) {
+		INFO("msm_vidc_dec: PAUSE command from client = %p\n",
+			 client_ctx);
+		vcd_status = vcd_pause(client_ctx->vcd_handle);
+	} else {
+		INFO("msm_vidc_dec: RESUME command from client = %p\n",
+			 client_ctx);
+		vcd_status = vcd_resume(client_ctx->vcd_handle);
+	}
+
+	if (vcd_status)
+		return false;
+
+	return true;
+
+}
+static u32 vid_dec_start(struct video_client_ctx *client_ctx)
+{
+	struct vid_dec_msg *vdec_msg = NULL;
+	u32 vcd_status;
+
+	INFO("msm_vidc_dec: Inside %s\n", __func__);
+	if (!client_ctx) {
+		ERR("\n Invalid client_ctx");
+		return false;
+	}
+
+	if (!client_ctx->seq_header_set) {
+		INFO("%s: Calling decode_start()\n", __func__);
+		vcd_status = vcd_decode_start(client_ctx->vcd_handle, NULL);
+
+		if (vcd_status) {
+			ERR("%s: vcd_decode_start failed vcd_status = %u\n",
+				__func__, vcd_status);
+			return false;
+		}
+		return true;
+	}
+
+	INFO("%s(): Seq Hdr set: Send START_DONE to client\n", __func__);
+	vdec_msg = kzalloc(sizeof(*vdec_msg), GFP_KERNEL);
+	if (!vdec_msg) {
+		ERR("%s: cannot allocate buffer\n", __func__);
+		return false;
+	}
+	vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_START_DONE;
+	vdec_msg->vdec_msg_info.status_code = VDEC_S_SUCCESS;
+	vdec_msg->vdec_msg_info.msgdatasize = 0;
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+
+	wake_up(&client_ctx->msg_wait);
+
+	DBG("Send START_DONE message to client = %p\n",	client_ctx);
+
+	return true;
+}
+
+static u32 vid_dec_stop(struct video_client_ctx *client_ctx)
+{
+	u32 vcd_status;
+
+	INFO("msm_vidc_dec: Inside %s\n", __func__);
+	if (!client_ctx) {
+		ERR("Invalid client_ctx\n");
+		return false;
+	}
+
+	INFO("%s: Calling vcd_stop()\n", __func__);
+	vcd_status = vcd_stop(client_ctx->vcd_handle);
+	if (vcd_status) {
+		ERR("%s: vcd_stop failed %u\n", __func__, vcd_status);
+		return false;
+	}
+	DBG("Send STOP_DONE message to client = %p\n", client_ctx);
+	return true;
+}
+
+static u32 vid_dec_decode_frame(struct video_client_ctx *client_ctx,
+	struct vdec_input_frameinfo *frm_info)
+{
+	struct vcd_frame_data vcd_input_buffer;
+	void *kern_addr;
+	void __user *user_addr;
+	phys_addr_t phys_addr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !frm_info)
+		return false;
+
+	user_addr = frm_info->user_addr;
+
+	if (!vid_c_lookup_addr_table(client_ctx, BUFFER_TYPE_INPUT, true,
+			&user_addr, &kern_addr, &phys_addr, &pmem_fd, &file,
+			&buffer_index)) {
+		ERR("%s: kern_addr not found\n", __func__);
+		return false;
+	}
+
+	/* kernel_vaddr  is found. send the frame to VCD */
+	memset((void *)&vcd_input_buffer, 0, sizeof(vcd_input_buffer));
+	vcd_input_buffer.virt_addr = (u8 *)kern_addr + frm_info->pmem_offset;
+	vcd_input_buffer.offset = frm_info->offset;
+	vcd_input_buffer.client_data = frm_info->client_data;
+	vcd_input_buffer.ip_frm_tag = (u32)frm_info->client_data;
+	vcd_input_buffer.data_len = frm_info->data_len;
+	vcd_input_buffer.time_stamp = frm_info->timestamp;
+	/* Rely on VCD using the same flags as OMX */
+	vcd_input_buffer.flags = frm_info->flags;
+
+	vcd_status = vcd_decode_frame(client_ctx->vcd_handle,
+		&vcd_input_buffer);
+
+	if (vcd_status) {
+		ERR("%s: vcd_decode_frame failed = %u\n", __func__, vcd_status);
+		return false;
+	}
+	return true;
+}
+
+static u32 vid_dec_fill_output_buffer(struct video_client_ctx *client_ctx,
+	struct vdec_fillbuffer_cmd *fill_buffer_cmd)
+{
+	void *kern_addr;
+	void __user *user_addr;
+	phys_addr_t phys_addr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	u32 vcd_status = VCD_ERR_FAIL;
+	struct vcd_frame_data vcd_frame;
+
+	if (!client_ctx || !fill_buffer_cmd)
+		return false;
+
+	user_addr = fill_buffer_cmd->buffer.addr;
+
+	if (!vid_c_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT, true,
+			&user_addr, &kern_addr, &phys_addr, &pmem_fd, &file,
+			&buffer_index)) {
+		ERR("%s: kern_addr not found\n", __func__);
+		return false;
+	}
+
+	memset((void *)&vcd_frame, 0, sizeof(vcd_frame));
+	vcd_frame.virt_addr = kern_addr;
+	vcd_frame.client_data = fill_buffer_cmd->client_data;
+	vcd_frame.alloc_len = fill_buffer_cmd->buffer.sz;
+
+	vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle, &vcd_frame);
+	if (vcd_status) {
+		ERR("%s: vcd_fill_output_buffer failed = %u\n",	__func__,
+			vcd_status);
+		return false;
+	}
+	return true;
+}
+
+static u32 vid_dec_flush(struct video_client_ctx *client_ctx,
+	enum vdec_bufferflush flush_dir)
+{
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	INFO("msm_vidc_dec: %s called with dir = %u\n", __func__, flush_dir);
+	if (!client_ctx) {
+		ERR("Invalid client_ctx\n");
+		return false;
+	}
+
+	switch (flush_dir) {
+	case VDEC_FLUSH_TYPE_INPUT:
+		vcd_status = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_INPUT);
+		break;
+	case VDEC_FLUSH_TYPE_OUTPUT:
+		vcd_status = vcd_flush(client_ctx->vcd_handle,
+			VCD_FLUSH_OUTPUT);
+		break;
+	case VDEC_FLUSH_TYPE_ALL:
+		vcd_status = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_ALL);
+		break;
+	default:
+		ERR("%s: Invalid flush cmd. flush_dir = %u\n", __func__,
+			flush_dir);
+		return false;
+	}
+
+	if (vcd_status) {
+		ERR("%s: vcd_flush failed. vcd_status = %u flush_dir = %u\n",
+			__func__, vcd_status, flush_dir);
+		return false;
+	}
+	return true;
+}
+
+static u32 vid_dec_msg_pending(struct video_client_ctx *client_ctx)
+{
+	u32 islist_empty = 0;
+	mutex_lock(&client_ctx->msg_queue_lock);
+	islist_empty = list_empty(&client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+
+	if (islist_empty) {
+		DBG("%s: vid_dec msg queue empty\n", __func__);
+		if (client_ctx->stop_msg) {
+			DBG("%s: List empty and Stop Msg set\n", __func__);
+			return client_ctx->stop_msg;
+		}
+	} else {
+		DBG("%s: vid_dec msg queue Not empty\n", __func__);
+	}
+
+	return !islist_empty;
+}
+
+static u32 vid_dec_get_next_msg(struct video_client_ctx *client_ctx,
+	struct vdec_msginfo *vdec_msg_info)
+{
+	int rc;
+	struct vid_dec_msg *vid_dec_msg = NULL;
+
+	if (!client_ctx)
+		return false;
+
+	rc = wait_event_interruptible(client_ctx->msg_wait,
+		vid_dec_msg_pending(client_ctx));
+	if (rc < 0 || client_ctx->stop_msg) {
+		DBG("rc = %d, stop_msg = %u\n", rc, client_ctx->stop_msg);
+		return false;
+	}
+
+	mutex_lock(&client_ctx->msg_queue_lock);
+	if (!list_empty(&client_ctx->msg_queue)) {
+		DBG("%s(): After Wait\n", __func__);
+		vid_dec_msg = list_first_entry(&client_ctx->msg_queue,
+			struct vid_dec_msg, list);
+		list_del(&vid_dec_msg->list);
+		memcpy(vdec_msg_info, &vid_dec_msg->vdec_msg_info,
+		       sizeof(struct vdec_msginfo));
+		kfree(vid_dec_msg);
+	}
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	return true;
+}
+
+static int vid_dec_ioctl(struct inode *inode, struct file *file,
+	unsigned cmd, unsigned long arg)
+{
+	struct video_client_ctx *client_ctx = NULL;
+	struct vdec_ioctl_msg vdec_msg;
+	u32 vcd_status;
+	void *kern_addr;
+	phys_addr_t phys_addr;
+	struct file *pmem_file;
+	u32 result = true;
+	void __user *u_arg = (void __user *)arg;
+
+	DBG("%s\n", __func__);
+
+	if (_IOC_TYPE(cmd) != VDEC_IOCTL_MAGIC)
+		return -ENOTTY;
+
+	client_ctx = (struct video_client_ctx *)file->private_data;
+	if (!client_ctx) {
+		ERR("!client_ctx. Cannot attach to device handle\n");
+		return -ENODEV;
+	}
+
+	switch (cmd) {
+	case VDEC_IOCTL_SET_CODEC:
+	{
+		enum vdec_codec codec_type;
+		struct vcd_property_meta_data_enable metdata_disable;
+		struct vcd_property_hdr header_type;
+		DBG("VDEC_IOCTL_SET_CODEC\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_from_user(&codec_type, vdec_msg.in,
+				sizeof(codec_type)))
+			return -EFAULT;
+		DBG("setting code type = %u\n", codec_type);
+		result = vid_dec_set_codec(client_ctx, &codec_type);
+		if (!result)
+			return -EIO;
+		metdata_disable.meta_data_enable_flag = 0;
+		header_type.sz = sizeof(metdata_disable);
+		header_type.id = VCD_I_METADATA_ENABLE;
+
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&header_type, (void *)&metdata_disable);
+
+		if (vcd_status) {
+			ERR("%s: vcd_set_property Failed for Meta Data Disable"
+				"\n", __func__);
+			return -ENODEV;
+		}
+		DBG("Disabled Meta Data\n");
+		break;
+	}
+	case VDEC_IOCTL_SET_OUTPUT_FORMAT:
+	{
+		enum vdec_output_format out_format;
+		DBG("VDEC_IOCTL_SET_OUTPUT_FORMAT\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_from_user(&out_format, vdec_msg.in,
+				sizeof(out_format)))
+			return -EFAULT;
+
+		result = vid_dec_set_output_format(client_ctx, &out_format);
+
+		if (!result)
+			return -EIO;
+		break;
+	}
+	case VDEC_IOCTL_SET_PICRES:
+	{
+		struct vdec_picsize video_res;
+		DBG("VDEC_IOCTL_SET_PICRES\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_from_user(&video_res, vdec_msg.in, sizeof(video_res)))
+			return -EFAULT;
+		result = vid_dec_set_frame_resolution(client_ctx,
+			&video_res);
+		if (!result)
+			return -EIO;
+		break;
+	}
+	case VDEC_IOCTL_GET_PICRES:
+	{
+		struct vdec_picsize video_res;
+		DBG("VDEC_IOCTL_GET_PICRES\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_from_user(&video_res, vdec_msg.out, sizeof(video_res)))
+			return -EFAULT;
+
+		result = vid_dec_get_frame_resolution(client_ctx, &video_res);
+
+		if (!result)
+			return -EIO;
+
+		if (copy_to_user(vdec_msg.out, &video_res,sizeof(video_res)))
+			return -EFAULT;
+		break;
+	}
+	case VDEC_IOCTL_SET_BUFFER_REQ:
+	{
+		//TODO unify these types
+		struct vdec_allocatorproperty vdec_buf_req;
+		struct vcd_buffer_requirement vcd_buf_req;
+
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+
+		if (copy_from_user(&vdec_buf_req, vdec_msg.in,
+				sizeof(vdec_buf_req)))
+			return -EFAULT;
+
+		vcd_buf_req.actual_count = vdec_buf_req.actualcount;
+		vcd_buf_req.align = vdec_buf_req.alignment;
+		vcd_buf_req.max_count = vdec_buf_req.maxcount;
+		vcd_buf_req.min_count = vdec_buf_req.mincount;
+		vcd_buf_req.size = vdec_buf_req.buffer_size;
+
+		switch (vdec_buf_req.buffer_type) {
+		case VDEC_BUFFER_TYPE_INPUT:
+			vcd_status = vcd_set_buffer_requirements(
+				client_ctx->vcd_handle,	VCD_BUFFER_INPUT,
+				&vcd_buf_req);
+			break;
+		case VDEC_BUFFER_TYPE_OUTPUT:
+			vcd_status = vcd_set_buffer_requirements(
+				client_ctx->vcd_handle,	VCD_BUFFER_OUTPUT,
+				&vcd_buf_req);
+			break;
+		default:
+			vcd_status = VCD_ERR_BAD_POINTER;
+			break;
+		}
+
+		if (vcd_status)
+			return -EFAULT;
+		break;
+	}
+	case VDEC_IOCTL_GET_BUFFER_REQ:
+	{
+		struct vdec_allocatorproperty vdec_buf_req;
+		DBG("VDEC_IOCTL_GET_BUFFER_REQ\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_from_user(&vdec_buf_req, vdec_msg.out,
+				sizeof(vdec_buf_req)))
+			return -EFAULT;
+
+		result = vid_dec_get_buffer_req(client_ctx, &vdec_buf_req);
+		if (!result)
+			return -EIO;
+
+		if (copy_to_user(vdec_msg.out, &vdec_buf_req,
+				sizeof(vdec_buf_req)))
+			return -EFAULT;
+		break;
+	}
+	case VDEC_IOCTL_SET_BUFFER:
+	{
+		struct vdec_setbuffer_cmd setbuffer;
+		DBG("VDEC_IOCTL_SET_BUFFER\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_from_user(&setbuffer, vdec_msg.in, sizeof(setbuffer)))
+			return -EFAULT;
+		result = vid_dec_set_buffer(client_ctx, &setbuffer);
+		break;
+	}
+	case VDEC_IOCTL_FREE_BUFFER:
+	{
+		struct vdec_setbuffer_cmd setbuffer;
+		DBG("VDEC_IOCTL_FREE_BUFFER\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_from_user(&setbuffer, vdec_msg.in, sizeof(setbuffer)))
+			return -EFAULT;
+
+		result = vid_dec_free_buffer(client_ctx, &setbuffer);
+
+		if (!result)
+			return -EIO;
+		break;
+	}
+	case VDEC_IOCTL_CMD_START:
+		DBG("VDEC_IOCTL_CMD_START\n");
+		result = vid_dec_start(client_ctx);
+
+		if (!result)
+			return -EIO;
+		break;
+	case VDEC_IOCTL_CMD_STOP:
+		DBG("VDEC_IOCTL_CMD_STOP\n");
+		result = vid_dec_stop(client_ctx);
+
+		if (!result)
+			return -EIO;
+		break;
+	case VDEC_IOCTL_CMD_PAUSE:
+		DBG("VDEC_IOCTL_CMD_PAUSE\n");
+		result = vid_dec_pause_resume(client_ctx, true);
+
+		if (!result)
+			return -EIO;
+		break;
+	case VDEC_IOCTL_CMD_RESUME:
+		DBG("VDEC_IOCTL_CMD_RESUME\n");
+		result = vid_dec_pause_resume(client_ctx, false);
+
+		if (!result)
+			return -EIO;
+		break;
+	case VDEC_IOCTL_DECODE_FRAME:
+	{
+		struct vdec_input_frameinfo frm_info;
+		DBG("VDEC_IOCTL_DECODE_FRAME\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_from_user(&frm_info, vdec_msg.in, sizeof(frm_info)))
+			return -EFAULT;
+
+		result = vid_dec_decode_frame(client_ctx, &frm_info);
+
+		if (!result)
+			return -EIO;
+		break;
+	}
+	case VDEC_IOCTL_FILL_OUTPUT_BUFFER:
+	{
+		struct vdec_fillbuffer_cmd fill_cmd;
+
+		DBG("VDEC_IOCTL_FILL_OUTPUT_BUFFER\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_from_user(&fill_cmd, vdec_msg.in, sizeof(fill_cmd)))
+			return -EFAULT;
+		result = vid_dec_fill_output_buffer(client_ctx, &fill_cmd);
+		if (!result)
+			return -EIO;
+		break;
+	}
+	case VDEC_IOCTL_CMD_FLUSH:
+	{
+		enum vdec_bufferflush flush_dir;
+		DBG("VDEC_IOCTL_CMD_FLUSH\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_from_user(&flush_dir, vdec_msg.in, sizeof(flush_dir)))
+			return -EFAULT;
+
+		result = vid_dec_flush(client_ctx, flush_dir);
+
+		if (!result)
+			return -EIO;
+		break;
+	}
+	case VDEC_IOCTL_GET_NEXT_MSG:
+	{
+		struct vdec_msginfo msg_info;
+		DBG("VDEC_IOCTL_GET_NEXT_MSG\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		result = vid_dec_get_next_msg(client_ctx, &msg_info);
+
+		if (!result)
+			return -EIO;
+		if (copy_to_user(vdec_msg.out, &msg_info, sizeof(msg_info)))
+			return -EFAULT;
+		break;
+	}
+	case VDEC_IOCTL_STOP_NEXT_MSG:
+		DBG("VDEC_IOCTL_STOP_NEXT_MSG\n");
+		client_ctx->stop_msg = 1;
+		wake_up(&client_ctx->msg_wait);
+		break;
+	case VDEC_IOCTL_SET_SEQUENCE_HEADER:
+	{
+		struct vdec_seqheader vdec_seq_hdr;
+		struct vcd_sequence_hdr vcd_seq_hdr;
+		unsigned long sz;
+		DBG("VDEC_IOCTL_SET_SEQUENCE_HEADER\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg))) {
+			ERR("Copy from user vdec_msg failed\n");
+			return -EFAULT;
+		}
+		if (copy_from_user(&vdec_seq_hdr, vdec_msg.in,
+				sizeof(vdec_seq_hdr))) {
+			ERR("Copy from user seq_header failed\n");
+			return -EFAULT;
+		}
+		if (!vdec_seq_hdr.sz) {
+			ERR("Seq len is zero\n");
+			return -EFAULT;
+		}
+
+		if (get_pmem_file(vdec_seq_hdr.pmem_fd,
+				(unsigned long *)&phys_addr,
+				(unsigned long *)&kern_addr, &sz, &pmem_file)) {
+			ERR("%s: get_pmem_file failed\n", __func__);
+			return false;
+		}
+		put_pmem_file(pmem_file);
+
+		vcd_seq_hdr.sz = vdec_seq_hdr.sz;
+		kern_addr = (u8 *)kern_addr + vdec_seq_hdr.pmem_offset;
+		vcd_seq_hdr.addr = kern_addr;
+		if (!vcd_seq_hdr.addr) {
+			ERR("Sequence Header pointer failed\n");
+			return -EFAULT;
+		}
+		client_ctx->seq_header_set = true;
+		if (vcd_decode_start(client_ctx->vcd_handle, &vcd_seq_hdr)) {
+			ERR("Decode start Failed\n");
+			client_ctx->seq_header_set = false;
+			return -EFAULT;
+		}
+		DBG("Wait Client completion Sequence Header\n");
+		wait_for_completion(&client_ctx->event);
+		vcd_seq_hdr.addr = NULL;
+		if (client_ctx->event_status) {
+			ERR("Set Seq Header status is failed");
+			return -EFAULT;
+		}
+		break;
+	}
+	case VDEC_IOCTL_GET_NUMBER_INSTANCES:
+		DBG("VDEC_IOCTL_GET_NUMBER_INSTANCES\n");
+		if (copy_from_user(&vdec_msg, u_arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		if (copy_to_user(vdec_msg.out, &vidc_dec_dev->num_clients,
+				sizeof(vidc_dec_dev->num_clients)))
+			return -EFAULT;
+		break;
+	default:
+		ERR("%s(): Unsupported ioctl\n", __func__);
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+static u32 vid_dec_close_client(struct video_client_ctx *client_ctx)
+{
+	u32 vcd_status;
+	int rc;
+
+	INFO("msm_vidc_dec: Inside %s\n", __func__);
+	if (!client_ctx || !client_ctx->vcd_handle) {
+		ERR("Invalid client_ctx\n");
+		return false;
+	}
+
+	mutex_lock(&vidc_dec_dev->lock);
+	vcd_status = vcd_stop(client_ctx->vcd_handle);
+
+	if (!vcd_status) {
+		rc = wait_for_completion_timeout(&client_ctx->event,
+			(5 * HZ) / 10);
+		if (!rc)
+			DBG("%s:ERROR vcd_stop time out rc = %d\n", __func__,
+				rc);
+
+		if (client_ctx->event_status)
+			ERR("%s:ERROR vcd_stop event_status failure\n",
+				__func__);
+	}
+	vcd_status = vcd_close(client_ctx->vcd_handle);
+
+	if (vcd_status) {
+		mutex_unlock(&vidc_dec_dev->lock);
+		return false;
+	}
+	memset((void *)client_ctx, 0, sizeof(*client_ctx));
+	vidc_dec_dev->num_clients--;
+	mutex_unlock(&vidc_dec_dev->lock);
+	return true;
+}
+
+static int vid_dec_open(struct inode *inode, struct file *file)
+{
+	int rc;
+	s32 client_index;
+	struct video_client_ctx *client_ctx;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	INFO("msm_vidc_dec: Inside %s\n", __func__);
+	mutex_lock(&vidc_dec_dev->lock);
+
+	if (vidc_dec_dev->num_clients == VID_DEC_MAX_DECODER_CLIENTS) {
+		ERR("%s: ERROR: max number of clients limit reached\n",
+			__func__);
+		mutex_unlock(&vidc_dec_dev->lock);
+		return -ENODEV;
+	}
+
+#ifndef USE_RES_TRACKER
+	DBG("Resource Tracker not in use");
+	if (!vid_c_enable_clk(VID_C_HCLK_RATE)) {
+		ERR("%s: ERROR: clock enabled failed\n", __func__);
+		mutex_unlock(&vidc_dec_dev->lock);
+		return -ENODEV;
+	}
+#endif
+
+	DBG("Virtual Address of ioremap is %p\n", vidc_dec_dev->virt_base);
+
+	if (!vidc_dec_dev->num_clients) {
+		rc = vcd_fw_prepare_all();
+		if (rc)
+			return rc;
+	}
+
+	client_index = vid_dec_get_empty_client_index();
+	if (client_index == -1) {
+		ERR("%s: No free clients client_index == -1\n", __func__);
+		return -ENODEV;
+	}
+	client_ctx = &vidc_dec_dev->vdec_clients[client_index];
+	vidc_dec_dev->num_clients++;
+	init_completion(&client_ctx->event);
+	mutex_init(&client_ctx->msg_queue_lock);
+	INIT_LIST_HEAD(&client_ctx->msg_queue);
+	init_waitqueue_head(&client_ctx->msg_wait);
+	client_ctx->stop_msg = 0;
+
+	vcd_status = vcd_open(vidc_dec_dev->device_handle, true,
+		vid_dec_vcd_cb, client_ctx);
+	wait_for_completion(&client_ctx->event);
+	client_ctx->seq_header_set = false;
+	file->private_data = client_ctx;
+	mutex_unlock(&vidc_dec_dev->lock);
+	return 0;
+}
+
+static int vid_dec_release(struct inode *inode, struct file *file)
+{
+	struct video_client_ctx *client_ctx = file->private_data;
+
+	INFO("msm_vidc_dec: Inside %s\n", __func__);
+	vid_dec_close_client(client_ctx);
+#ifndef USE_RES_TRACKER
+	vid_c_disable_clk();
+#endif
+	INFO("msm_vidc_dec: Return from %s\n", __func__);
+	return 0;
+}
+
+static const struct file_operations vid_dec_fops = {
+	.owner = THIS_MODULE,
+	.open = vid_dec_open,
+	.release = vid_dec_release,
+	.ioctl = vid_dec_ioctl,
+};
+
+void vid_dec_interrupt_deregister(void)
+{
+}
+
+void vid_dec_interrupt_register(void *device_name)
+{
+}
+
+void vid_dec_interrupt_clear(void)
+{
+}
+
+void *vid_dec_map_dev_base_addr(void *device_name)
+{
+	return vidc_dec_dev->virt_base;
+}
+
+static int vid_dec_vcd_init(void)
+{
+	int rc;
+	struct vcd_init_config vcd_init_config;
+	u32 i;
+
+	/* init_timer(&hw_timer); */
+	INFO("msm_vidc_dec: Inside %s\n", __func__);
+	vidc_dec_dev->num_clients = 0;
+
+	for (i = 0; i < VID_DEC_MAX_DECODER_CLIENTS; i++) {
+		memset((void *)&vidc_dec_dev->vdec_clients[i], 0,
+			sizeof(vidc_dec_dev->vdec_clients[i]));
+	}
+
+	mutex_init(&vidc_dec_dev->lock);
+	vidc_dec_dev->virt_base = vid_c_get_ioaddr();
+	DBG("%s: base address for VIDC core %p\n", __func__,
+		vidc_dec_dev->virt_base);
+
+	if (!vidc_dec_dev->virt_base) {
+		ERR("%s: ioremap failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	vcd_init_config.device_name = "VID_C";
+	vcd_init_config.pf_map_dev_base_addr = vid_dec_map_dev_base_addr;
+	vcd_init_config.pf_interrupt_clr = vid_dec_interrupt_clear;
+	vcd_init_config.pf_register_isr = vid_dec_interrupt_register;
+	vcd_init_config.pf_deregister_isr = vid_dec_interrupt_deregister;
+	vcd_init_config.pf_timer_create = vid_c_timer_create;
+	vcd_init_config.pf_timer_release = vid_c_timer_release;
+	vcd_init_config.pf_timer_start = vid_c_timer_start;
+	vcd_init_config.pf_timer_stop = vid_c_timer_stop;
+
+	rc = vcd_init(&vcd_init_config, &vidc_dec_dev->device_handle);
+	if (rc) {
+		ERR("%s: vcd_init failed\n", __func__);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int __init vid_dec_init(void)
+{
+	int rc = 0;
+	struct device *class_devp;
+
+	INFO("msm_vidc_dec: Inside %s\n", __func__);
+	vidc_dec_dev = kzalloc(sizeof(*vidc_dec_dev), GFP_KERNEL);
+	if (!vidc_dec_dev) {
+		ERR("%s Unable to allocate memory for vid_dec_dev\n", __func__);
+		return -ENOMEM;
+	}
+
+	rc = alloc_chrdev_region(&vidc_dec_dev_num, 0, 1, VID_DEC_NAME);
+	if (rc < 0) {
+		ERR("%s: alloc_chrdev_region failed rc = %d\n",	__func__, rc);
+		goto error_vid_dec_alloc_chrdev_region;
+	}
+
+	vidc_dec_class = class_create(THIS_MODULE, VID_DEC_NAME);
+	if (IS_ERR(vidc_dec_class)) {
+		rc = PTR_ERR(vidc_dec_class);
+		ERR("%s: couldn't create vid_dec_class %d\n", __func__, rc);
+		goto error_vid_dec_class_create;
+	}
+
+	class_devp = device_create(vidc_dec_class, NULL, vidc_dec_dev_num, NULL,
+		VID_DEC_NAME);
+
+	if (IS_ERR(class_devp)) {
+		rc = PTR_ERR(class_devp);
+		ERR("%s: class device_create failed %d\n", __func__, rc);
+		goto error_vid_dec_class_device_create;
+	}
+
+	vidc_dec_dev->device = class_devp;
+
+	cdev_init(&vidc_dec_dev->cdev, &vid_dec_fops);
+	vidc_dec_dev->cdev.owner = THIS_MODULE;
+	rc = cdev_add(&vidc_dec_dev->cdev, vidc_dec_dev_num, 1);
+
+	if (rc < 0) {
+		ERR("%s: cdev_add failed %d\n", __func__, rc);
+		goto error_vid_dec_cdev_add;
+	}
+
+	return vid_dec_vcd_init();
+
+error_vid_dec_cdev_add:
+	device_destroy(vidc_dec_class, vidc_dec_dev_num);
+error_vid_dec_class_device_create:
+	class_destroy(vidc_dec_class);
+error_vid_dec_class_create:
+	unregister_chrdev_region(vidc_dec_dev_num, 1);
+error_vid_dec_alloc_chrdev_region:
+	kfree(vidc_dec_dev);
+
+	return rc;
+}
+
+static void __exit vid_dec_exit(void)
+{
+	INFO("msm_vidc_dec: Inside %s\n", __func__);
+	cdev_del(&(vidc_dec_dev->cdev));
+	device_destroy(vidc_dec_class, vidc_dec_dev_num);
+	class_destroy(vidc_dec_class);
+	unregister_chrdev_region(vidc_dec_dev_num, 1);
+	kfree(vidc_dec_dev);
+	INFO("msm_vidc_dec: Return from %s\n", __func__);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Video decoder driver");
+MODULE_VERSION("1.0");
+
+module_init(vid_dec_init);
+module_exit(vid_dec_exit);
diff --git a/drivers/misc/video_core/720p/dec/vdec_internal.h b/drivers/misc/video_core/720p/dec/vdec_internal.h
new file mode 100644
index 0000000..f6ce510
--- /dev/null
+++ b/drivers/misc/video_core/720p/dec/vdec_internal.h
@@ -0,0 +1,61 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+
+#ifndef VDEC_INTERNAL_H
+#define VDEC_INTERNAL_H
+
+#include <linux/msm_vidc_dec.h>
+#include <linux/cdev.h>
+#include "video_core_init.h"
+
+#define VID_DEC_MAX_DECODER_CLIENTS 16
+
+struct vid_dec_msg {
+	struct list_head list;
+	struct vdec_msginfo vdec_msg_info;
+};
+
+struct vid_dec_dev {
+	struct cdev cdev;
+	struct device *device;
+	resource_size_t phys_base;
+	void __iomem *virt_base;
+	unsigned int irq;
+	struct clk *hclk;
+	struct clk *hclk_div2;
+	struct clk *pclk;
+	unsigned long hclk_rate;
+	struct mutex lock;
+	s32 device_handle;
+	struct video_client_ctx vdec_clients[VID_DEC_MAX_DECODER_CLIENTS];
+	u32 num_clients;
+	void(*pf_timer_handler)(void *);
+};
+
+#endif
diff --git a/drivers/misc/video_core/720p/enc/venc.c b/drivers/misc/video_core/720p/enc/venc.c
new file mode 100644
index 0000000..6b81018
--- /dev/null
+++ b/drivers/misc/video_core/720p/enc/venc.c
@@ -0,0 +1,1486 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/android_pmem.h>
+#include <linux/clk.h>
+
+#include "vcd_ddl_firmware.h"
+#include "video_core_type.h"
+#include "vcd_api.h"
+#include "venc_internal.h"
+#include "video_core_init.h"
+
+#define VID_ENC_NAME "msm_vidc_enc"
+#define VID_C_HCLK_RATE	170667000
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+#define INFO(x...) printk(KERN_INFO x)
+#define ERR(x...) printk(KERN_ERR x)
+
+static struct vid_enc_dev *vidc_enc_dev;
+static dev_t vidc_enc_dev_num;
+static struct class *vid_enc_class;
+static int vid_enc_ioctl(struct inode *inode, struct file *file, unsigned cmd,
+	unsigned long arg);
+//TOOD stop_cmd wtf
+static int stop_cmd;
+
+static s32 vid_enc_get_empty_client_index(void)
+{
+	u32 i;
+	u32 found = false;
+
+	for (i = 0; i < VID_ENC_MAX_ENCODER_CLIENTS; i++) {
+		if (!vidc_enc_dev->venc_clients[i].vcd_handle) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		ERR("%s: ERROR No space for new client\n", __func__);
+		return -1;
+	}
+	DBG("%s: available client index = %u\n", __func__, i);
+	return i;
+}
+
+//TODO collapse this crap
+u32 vid_enc_get_status(u32 status)
+{
+	u32 venc_status;
+
+	switch (status) {
+	case VCD_S_SUCCESS:
+		venc_status = VEN_S_SUCCESS;
+		break;
+	case VCD_ERR_FAIL:
+		venc_status = VEN_S_EFAIL;
+		break;
+	case VCD_ERR_ALLOC_FAIL:
+		venc_status = VEN_S_ENOSWRES;
+		break;
+	case VCD_ERR_ILLEGAL_OP:
+		venc_status = VEN_S_EINVALCMD;
+		break;
+	case VCD_ERR_ILLEGAL_PARM:
+		venc_status = VEN_S_EBADPARAM;
+		break;
+	case VCD_ERR_BAD_POINTER:
+	case VCD_ERR_BAD_HANDLE:
+		venc_status = VEN_S_EFATAL;
+		break;
+	case VCD_ERR_NOT_SUPPORTED:
+		venc_status = VEN_S_ENOTSUPP;
+		break;
+	case VCD_ERR_BAD_STATE:
+		venc_status = VEN_S_EINVALSTATE;
+		break;
+	case VCD_ERR_MAX_CLIENT:
+		venc_status = VEN_S_ENOHWRES;
+		break;
+	default:
+		venc_status = VEN_S_EFAIL;
+		break;
+	}
+	return venc_status;
+}
+
+static void vid_enc_notify_client(struct video_client_ctx *client_ctx)
+{
+	if (client_ctx)
+		complete(&client_ctx->event);
+}
+
+void vid_enc_vcd_open_done(struct video_client_ctx *client_ctx,
+	struct vcd_handle_container *handle_container)
+{
+	DBG("vid_enc_vcd_open_done\n");
+
+	if (!client_ctx) {
+		ERR("%s(): ERROR. client_ctx is NULL\n", __func__);
+		return;
+	}
+	if (handle_container)
+		client_ctx->vcd_handle = handle_container->handle;
+	else
+		ERR("%s: ERROR. handle_container is NULL\n", __func__);
+	vid_enc_notify_client(client_ctx);
+}
+
+static void vid_enc_input_frame_done(struct video_client_ctx *client_ctx,
+	u32 event, u32 status, struct vcd_frame_data *vcd_frame_data)
+{
+	struct vid_enc_msg *venc_msg;
+
+	if (!client_ctx || !vcd_frame_data) {
+		ERR("%s: NULL pointer\n", __func__);
+		return;
+	}
+
+	venc_msg = kzalloc(sizeof(struct vid_enc_msg), GFP_KERNEL);
+	if (!venc_msg) {
+		ERR("%s: cannot allocate vid_enc_msg buffer\n", __func__);
+		return;
+	}
+
+	venc_msg->venc_msg_info.statuscode = vid_enc_get_status(status);
+
+	if (event == VCD_EVT_RESP_INPUT_DONE) {
+		venc_msg->venc_msg_info.msgcode = VEN_MSG_INPUT_BUFFER_DONE;
+		DBG("Send INPUT_DON message to client = %p\n", client_ctx);
+	} else if (event == VCD_EVT_RESP_INPUT_FLUSHED) {
+		venc_msg->venc_msg_info.msgcode = VEN_MSG_INPUT_BUFFER_DONE;
+		DBG("Send INPUT_FLUSHED message to client = %p\n", client_ctx);
+	} else {
+		ERR("vid_enc_input_frame_done(): invalid event type\n");
+		return;
+	}
+
+	venc_msg->venc_msg_info.buf.clientdata = vcd_frame_data->client_data;
+	venc_msg->venc_msg_info.msgdata_size = sizeof(struct vid_enc_msg);
+
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&venc_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+static void vid_enc_output_frame_done(struct video_client_ctx *client_ctx,
+	u32 event, u32 status, struct vcd_frame_data *frm_data)
+{
+	struct vid_enc_msg *venc_msg;
+	void __user *user_addr;
+	void *kern_addr;
+	phys_addr_t phys_addr;
+	int pmem_fd;
+	struct file *file;
+	s32 buf_index = -1;
+
+	if (!client_ctx || !frm_data) {
+		ERR("%s: NULL pointer\n", __func__);
+		return;
+	}
+
+	venc_msg = kzalloc(sizeof(struct vid_enc_msg), GFP_KERNEL);
+	if (!venc_msg) {
+		ERR("%s: cannot allocate vid_enc_msg buffer\n", __func__);
+		return;
+	}
+
+	venc_msg->venc_msg_info.statuscode = vid_enc_get_status(status);
+
+	if (event == VCD_EVT_RESP_OUTPUT_DONE) {
+		venc_msg->venc_msg_info.msgcode = VEN_MSG_OUTPUT_BUFFER_DONE;
+	} else if (event == VCD_EVT_RESP_OUTPUT_FLUSHED) {
+		venc_msg->venc_msg_info.msgcode = VEN_MSG_OUTPUT_BUFFER_DONE;
+	} else {
+		ERR("QVD: vid_enc_output_frame_done invalid cmd type\n");
+		return;
+	}
+
+	kern_addr = frm_data->virt_addr;
+
+	if (!vid_c_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT, false,
+			&user_addr, &kern_addr, &phys_addr, &pmem_fd, &file,
+			&buf_index)) {
+		ERR("vid_enc_output_frame_done UVA can not be found\n");
+		venc_msg->venc_msg_info.statuscode = VEN_S_EFATAL;
+		goto out;
+	}
+
+
+	/* Buffer address in user space */
+	venc_msg->venc_msg_info.buf.addr = user_addr;
+	venc_msg->venc_msg_info.buf.clientdata = frm_data->client_data;
+	/* Data length */
+	venc_msg->venc_msg_info.buf.len = frm_data->data_len;
+	venc_msg->venc_msg_info.buf.flags = frm_data->flags;
+	/* time-stamp pass-through from input frame */
+	venc_msg->venc_msg_info.buf.timestamp =	frm_data->time_stamp;
+	/* Decoded picture width and height */
+	venc_msg->venc_msg_info.msgdata_size = sizeof(struct venc_buffer);
+
+out:
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&venc_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+static void vid_enc_lean_event(struct video_client_ctx *client_ctx,
+	u32 event, u32 status)
+{
+	struct vid_enc_msg *venc_msg;
+	if (!client_ctx) {
+		ERR("%s(): !client_ctx pointer\n", __func__);
+		return;
+	}
+
+	venc_msg = kzalloc(sizeof(struct vid_enc_msg), GFP_KERNEL);
+	if (!venc_msg) {
+		ERR("%s(): cannot allocate vid_enc_msg buffer\n", __func__);
+		return;
+	}
+
+	venc_msg->venc_msg_info.statuscode = vid_enc_get_status(status);
+
+	switch (event) {
+	case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+		INFO("%s: Sending VCD_EVT_RESP_FLUSH_INPUT_DONE to client\n",
+			__func__);
+		venc_msg->venc_msg_info.msgcode = VEN_MSG_FLUSH_INPUT_DONE;
+		break;
+	case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+		INFO("%s: Sending VCD_EVT_RESP_FLUSH_OUTPUT_DONE to client\n",
+			__func__);
+		venc_msg->venc_msg_info.msgcode = VEN_MSG_FLUSH_OUPUT_DONE;
+		break;
+	case VCD_EVT_RESP_START:
+		INFO("%s: Sending VCD_EVT_RESP_START to client\n", __func__);
+		venc_msg->venc_msg_info.msgcode = VEN_MSG_START;
+		break;
+	case VCD_EVT_RESP_STOP:
+		INFO("%s: Sending VCD_EVT_RESP_STOP to client\n", __func__);
+		venc_msg->venc_msg_info.msgcode = VEN_MSG_STOP;
+		break;
+	case VCD_EVT_RESP_PAUSE:
+		INFO("%s: Sending VCD_EVT_RESP_PAUSE to client\n", __func__);
+		venc_msg->venc_msg_info.msgcode = VEN_MSG_PAUSE;
+		break;
+	default:
+		ERR("%s: unknown event type\n", __func__);
+		break;
+	}
+
+	venc_msg->venc_msg_info.msgdata_size = 0;
+
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&venc_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+
+void vid_enc_vcd_cb(u32 event, u32 status, void *info, u32 size, void *handle,
+	void *const client_data)
+{
+	struct video_client_ctx *client_ctx = client_data;
+
+	DBG("Entering %s\n", __func__);
+
+	if (!client_ctx) {
+		ERR("%s: client_ctx is NULL\n", __func__);
+		return;
+	}
+
+	client_ctx->event_status = status;
+
+	switch (event) {
+	case VCD_EVT_RESP_OPEN:
+		vid_enc_vcd_open_done(client_ctx, info);
+		break;
+	case VCD_EVT_RESP_INPUT_DONE:
+	case VCD_EVT_RESP_INPUT_FLUSHED:
+		vid_enc_input_frame_done(client_ctx, event, status, info);
+		break;
+	case VCD_EVT_RESP_OUTPUT_DONE:
+	case VCD_EVT_RESP_OUTPUT_FLUSHED:
+		vid_enc_output_frame_done(client_ctx, event, status, info);
+		break;
+	case VCD_EVT_RESP_PAUSE:
+	case VCD_EVT_RESP_START:
+	case VCD_EVT_RESP_STOP:
+	case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+	case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+	case VCD_EVT_IND_RECONFIG:
+	case VCD_EVT_IND_HWERRFATAL:
+	case VCD_EVT_IND_RESOURCES_LOST:
+		vid_enc_lean_event(client_ctx, event, status);
+		break;
+	default:
+		ERR("%s: Error invalid event type %u\n", __func__, event);
+		break;
+	}
+}
+
+static u32 vid_enc_msg_pending(struct video_client_ctx *client_ctx)
+{
+	u32 islist_empty = 0;
+
+	mutex_lock(&client_ctx->msg_queue_lock);
+	islist_empty = list_empty(&client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+
+	if (islist_empty) {
+		DBG("%s: vid_enc msg queue empty\n", __func__);
+		if (client_ctx->stop_msg) {
+			DBG("%s: List empty and Stop Msg set\n", __func__);
+			return client_ctx->stop_msg;
+		}
+	} else
+		DBG("%s: vid_enc msg queue Not empty\n", __func__);
+
+	return !islist_empty;
+}
+
+static u32 vid_enc_get_next_msg(struct video_client_ctx *client_ctx,
+	struct venc_msg *venc_msg_info)
+{
+	int rc;
+	struct vid_enc_msg *vid_enc_msg = NULL;
+
+	if (!client_ctx)
+		return false;
+
+	rc = wait_event_interruptible(client_ctx->msg_wait,
+		vid_enc_msg_pending(client_ctx));
+
+	if (rc < 0 || client_ctx->stop_msg) {
+		DBG("rc = %d, stop_msg = %u\n", rc, client_ctx->stop_msg);
+		return false;
+	}
+
+	mutex_lock(&client_ctx->msg_queue_lock);
+
+	if (!list_empty(&client_ctx->msg_queue)) {
+		DBG("%s: After Wait\n", __func__);
+		vid_enc_msg = list_first_entry(&client_ctx->msg_queue,
+			struct vid_enc_msg, list);
+		list_del(&vid_enc_msg->list);
+		memcpy(venc_msg_info, &vid_enc_msg->venc_msg_info,
+			sizeof(struct venc_msg));
+		kfree(vid_enc_msg);
+	}
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	return true;
+}
+
+static u32 vid_enc_close_client(struct video_client_ctx *client_ctx)
+{
+	u32 vcd_status;
+
+	int rc;
+
+	INFO("msm_vidc_enc: Inside %s\n", __func__);
+	if (!client_ctx || !client_ctx->vcd_handle) {
+		ERR("%s: Invalid client_ctx\n", __func__);
+		return false;
+	}
+
+	mutex_lock(&vidc_enc_dev->lock);
+
+	if (!stop_cmd) {
+		vcd_status = vcd_stop(client_ctx->vcd_handle);
+		DBG("Waiting for VCD_STOP: Before Timeout\n");
+		if (!vcd_status) {
+			rc = wait_for_completion_timeout(&client_ctx->event,
+				5 * HZ);
+			if (!rc) {
+				ERR("%s: ERROR vcd_stop time out %d\n",
+					__func__, rc);
+			}
+
+			if (client_ctx->event_status) {
+				ERR("%s :ERROR vcd_stop Not success\n",
+					__func__);
+			}
+		}
+	}
+	DBG("VCD_STOPPED: After Timeout, calling VCD_CLOSE\n");
+	vcd_status = vcd_close(client_ctx->vcd_handle);
+
+	if (vcd_status) {
+		mutex_unlock(&vidc_enc_dev->lock);
+		return false;
+	}
+
+	memset((void *)client_ctx, 0, sizeof(struct video_client_ctx));
+
+	vidc_enc_dev->num_clients--;
+	stop_cmd = 0;
+	mutex_unlock(&vidc_enc_dev->lock);
+	return true;
+}
+
+
+static int vid_enc_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	s32 client_index;
+	struct video_client_ctx *client_ctx;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	INFO("msm_vidc_enc: Inside %s\n", __func__);
+
+	mutex_lock(&vidc_enc_dev->lock);
+
+	stop_cmd = 0;
+	if (vidc_enc_dev->num_clients == VID_ENC_MAX_ENCODER_CLIENTS) {
+		ERR("ERROR: vid_enc_open() max number of clients limit reached"
+			"\n");
+		rc = -ENODEV;
+		goto out;
+	}
+
+#ifndef USE_RES_TRACKER
+	DBG("Resource Tracker not in use");
+	if (!vid_c_enable_clk(VID_C_HCLK_RATE)) {
+		ERR("ERROR: vid_enc_open() clock enabled failed\n");
+		rc = -ENODEV;
+		goto out;
+	}
+#endif
+
+	DBG("Virtual Address of ioremap is %p\n", vidc_enc_dev->virt_base);
+
+	if (!vidc_enc_dev->num_clients) {
+		rc = vcd_fw_prepare_all();
+		if (rc)
+			goto out;
+	}
+
+	client_index = vid_enc_get_empty_client_index();
+
+	if (client_index == -1) {
+		ERR("%s: No free clients client_index == -1\n", __func__);
+		rc = -ENODEV;
+		goto out;
+	}
+
+	client_ctx = &vidc_enc_dev->venc_clients[client_index];
+	vidc_enc_dev->num_clients++;
+
+	init_completion(&client_ctx->event);
+	mutex_init(&client_ctx->msg_queue_lock);
+	INIT_LIST_HEAD(&client_ctx->msg_queue);
+	init_waitqueue_head(&client_ctx->msg_wait);
+	vcd_status = vcd_open(vidc_enc_dev->device_handle, false,
+		vid_enc_vcd_cb, client_ctx);
+	client_ctx->stop_msg = 0;
+
+	wait_for_completion(&client_ctx->event);
+	file->private_data = client_ctx;
+
+out:
+	mutex_unlock(&vidc_enc_dev->lock);
+	return rc;
+}
+
+static int vid_enc_release(struct inode *inode, struct file *file)
+{
+	struct video_client_ctx *client_ctx = file->private_data;
+	INFO("msm_vidc_enc: Inside %s\n", __func__);
+	vid_enc_close_client(client_ctx);
+#ifndef USE_RES_TRACKER
+	vid_c_disable_clk();
+#endif
+	INFO("msm_vidc_enc: Return from %s\n", __func__);
+	return 0;
+}
+
+static const struct file_operations vid_enc_fops = {
+	.owner = THIS_MODULE,
+	.open = vid_enc_open,
+	.release = vid_enc_release,
+	.ioctl = vid_enc_ioctl
+};
+
+void vid_enc_interrupt_deregister(void)
+{
+}
+
+void vid_enc_interrupt_register(void *device_name)
+{
+}
+
+void vid_enc_interrupt_clear(void)
+{
+}
+
+void *vid_enc_map_dev_base_addr(void *device_name)
+{
+	return vidc_enc_dev->virt_base;
+}
+
+static int vid_enc_vcd_init(void)
+{
+	int rc;
+	struct vcd_init_config vcd_init_config;
+	u32 i;
+
+	INFO("msm_vidc_enc: Inside %s\n", __func__);
+	vidc_enc_dev->num_clients = 0;
+
+	for (i = 0; i < VID_ENC_MAX_ENCODER_CLIENTS; i++)
+		memset((void *)&vidc_enc_dev->venc_clients[i], 0,
+			sizeof(vidc_enc_dev->venc_clients[i]));
+
+	mutex_init(&vidc_enc_dev->lock);
+	vidc_enc_dev->virt_base = vid_c_get_ioaddr();
+
+	if (!vidc_enc_dev->virt_base) {
+		ERR("%s: ioremap failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	vcd_init_config.device_name = "VID_C";
+	vcd_init_config.pf_map_dev_base_addr = vid_enc_map_dev_base_addr;
+	vcd_init_config.pf_interrupt_clr = vid_enc_interrupt_clear;
+	vcd_init_config.pf_register_isr = vid_enc_interrupt_register;
+	vcd_init_config.pf_deregister_isr = vid_enc_interrupt_deregister;
+
+	rc = vcd_init(&vcd_init_config, &vidc_enc_dev->device_handle);
+
+	if (rc) {
+		ERR("%s: vcd_init failed\n", __func__);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int __init vid_enc_init(void)
+{
+	int rc = 0;
+	struct device *class_devp;
+
+	INFO("msm_vidc_enc: Inside %s\n", __func__);
+	vidc_enc_dev = kzalloc(sizeof(struct vid_enc_dev), GFP_KERNEL);
+	if (!vidc_enc_dev) {
+		ERR("%s Unable to allocate memory for vid_enc_dev\n", __func__);
+		return -ENOMEM;
+	}
+
+	rc = alloc_chrdev_region(&vidc_enc_dev_num, 0, 1, VID_ENC_NAME);
+	if (rc < 0) {
+		ERR("%s: alloc_chrdev_region Failed rc = %d\n", __func__, rc);
+		goto error_vid_enc_alloc_chrdev_region;
+	}
+
+	vid_enc_class = class_create(THIS_MODULE, VID_ENC_NAME);
+	if (IS_ERR(vid_enc_class)) {
+		rc = PTR_ERR(vid_enc_class);
+		ERR("%s: couldn't create vid_enc_class %d\n", __func__, rc);
+		goto error_vid_enc_class_create;
+	}
+
+	class_devp = device_create(vid_enc_class, NULL, vidc_enc_dev_num, NULL,
+		VID_ENC_NAME);
+	if (IS_ERR(class_devp)) {
+		rc = PTR_ERR(class_devp);
+		ERR("%s: class device_create failed %d\n", __func__, rc);
+		goto error_vid_enc_class_device_create;
+	}
+
+	vidc_enc_dev->device = class_devp;
+
+	cdev_init(&vidc_enc_dev->cdev, &vid_enc_fops);
+	vidc_enc_dev->cdev.owner = THIS_MODULE;
+	rc = cdev_add(&vidc_enc_dev->cdev, vidc_enc_dev_num, 1);
+
+	if (rc < 0) {
+		ERR("%s: cdev_add failed %d\n", __func__, rc);
+		goto error_vid_enc_cdev_add;
+	}
+	vid_enc_vcd_init();
+	return 0;
+
+error_vid_enc_cdev_add:
+	device_destroy(vid_enc_class, vidc_enc_dev_num);
+error_vid_enc_class_device_create:
+	class_destroy(vid_enc_class);
+error_vid_enc_class_create:
+	unregister_chrdev_region(vidc_enc_dev_num, 1);
+error_vid_enc_alloc_chrdev_region:
+	kfree(vidc_enc_dev);
+
+	return rc;
+}
+
+static void __exit vid_enc_exit(void)
+{
+	INFO("msm_vidc_enc: Inside %s\n", __func__);
+	cdev_del(&vidc_enc_dev->cdev);
+	device_destroy(vid_enc_class, vidc_enc_dev_num);
+	class_destroy(vid_enc_class);
+	unregister_chrdev_region(vidc_enc_dev_num, 1);
+	kfree(vidc_enc_dev);
+	INFO("msm_vidc_enc: Return from %s\n", __func__);
+}
+
+static int vid_enc_ioctl(struct inode *inode, struct file *file,
+	unsigned cmd, unsigned long arg)
+{
+	void __user *u_arg = (void __user *)arg;
+	struct video_client_ctx *client_ctx;
+	struct venc_ioctl_msg venc_msg;
+	u32 result = true;
+
+	DBG("%s\n", __func__);
+
+	client_ctx = file->private_data;
+	if (!client_ctx) {
+		ERR("!client_ctx. Cannot attach to device handle\n");
+		return -ENODEV;
+	}
+
+	switch (cmd) {
+	case VEN_IOCTL_CMD_READ_NEXT_MSG:
+	{
+		struct venc_msg cb_msg;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+		DBG("VEN_IOCTL_CMD_READ_NEXT_MSG\n");
+		result = vid_enc_get_next_msg(client_ctx, &cb_msg);
+		if (!result) {
+			ERR("VEN_IOCTL_CMD_READ_NEXT_MSG failed\n");
+			return -EIO;
+		}
+		if (copy_to_user(venc_msg.out, &cb_msg, sizeof(cb_msg)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_CMD_STOP_READ_MSG:
+		DBG("VEN_IOCTL_CMD_STOP_READ_MSG\n");
+		client_ctx->stop_msg = 1;
+		wake_up(&client_ctx->msg_wait);
+		break;
+	case VEN_IOCTL_CMD_ENCODE_FRAME:
+	case VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER:
+	{
+		struct venc_buffer enc_buf;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_CMD_ENCODE_FRAME/"
+			"VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER\n");
+
+		if (copy_from_user(&enc_buf, venc_msg.in, sizeof(enc_buf)))
+			return -EFAULT;
+
+		if (cmd == VEN_IOCTL_CMD_ENCODE_FRAME)
+			result = vid_enc_encode_frame(client_ctx, &enc_buf);
+		else
+			result = vid_enc_fill_output_buffer(client_ctx,
+				&enc_buf);
+
+		if (!result) {
+			DBG("VEN_IOCTL_CMD_ENCODE_FRAME/"
+				"VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_SET_INPUT_BUFFER:
+	case VEN_IOCTL_SET_OUTPUT_BUFFER:
+	{
+		struct venc_bufferpayload buf_info;
+		enum venc_buffer_dir buf_dir;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_INPUT_BUFFER/VEN_IOCTL_SET_OUTPUT_BUFFER\n");
+
+		if (copy_from_user(&buf_info, venc_msg.in, sizeof(buf_info)))
+			return -EFAULT;
+
+		buf_dir = VEN_BUFFER_TYPE_INPUT;
+		if (cmd == VEN_IOCTL_SET_OUTPUT_BUFFER)
+			buf_dir = VEN_BUFFER_TYPE_OUTPUT;
+
+		result = vid_enc_set_buffer(client_ctx, &buf_info, buf_dir);
+		if (!result) {
+			DBG("VEN_IOCTL_SET_INPUT_BUFFER"
+				"/VEN_IOCTL_SET_OUTPUT_BUFFER failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_SET_INPUT_BUFFER_REQ:
+	case VEN_IOCTL_SET_OUTPUT_BUFFER_REQ:
+	{
+		struct venc_allocatorproperty alloc;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_INPUT_BUFFER_REQ"
+			"/VEN_IOCTL_SET_OUTPUT_BUFFER_REQ\n");
+
+		if (copy_from_user(&alloc, venc_msg.in, sizeof(alloc)))
+			return -EFAULT;
+
+		if (cmd == VEN_IOCTL_SET_OUTPUT_BUFFER_REQ)
+			result = vid_enc_set_buffer_req(client_ctx, &alloc,
+				false);
+		else
+			result = vid_enc_set_buffer_req(client_ctx, &alloc,
+				true);
+		if (!result) {
+			DBG("setting VEN_IOCTL_SET_OUTPUT_BUFFER_REQ/"
+				"VEN_IOCTL_SET_INPUT_BUFFER_REQ failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_INPUT_BUFFER_REQ:
+	case VEN_IOCTL_GET_OUTPUT_BUFFER_REQ:
+	{
+		struct venc_allocatorproperty alloc;
+
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_INPUT_BUFFER_REQ/"
+			"VEN_IOCTL_GET_OUTPUT_BUFFER_REQ\n");
+
+		if (cmd == VEN_IOCTL_GET_OUTPUT_BUFFER_REQ)
+			result = vid_enc_get_buffer_req(client_ctx, &alloc,
+				false);
+		else
+			result = vid_enc_get_buffer_req(client_ctx, &alloc,
+				true);
+
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &alloc, sizeof(alloc)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_CMD_FLUSH:
+	{
+		struct venc_bufferflush buf_flush;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_CMD_FLUSH\n");
+
+		if (copy_from_user(&buf_flush, venc_msg.in, sizeof(buf_flush)))
+			return -EFAULT;
+
+		INFO("%s: Calling vid_enc_flush with mode = %lu\n", __func__,
+			buf_flush.flush_mode);
+		result = vid_enc_flush(client_ctx, &buf_flush);
+		if (!result) {
+			ERR("setting VEN_IOCTL_CMD_FLUSH failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_CMD_START:
+		INFO("%s: Executing VEN_IOCTL_CMD_START\n", __func__);
+		result = vid_enc_start(client_ctx);
+		if (!result) {
+			ERR("setting VEN_IOCTL_CMD_START failed\n");
+			return -EIO;
+		}
+		break;
+	case VEN_IOCTL_CMD_STOP:
+		INFO("%s: Executing VEN_IOCTL_CMD_STOP", __func__);
+		result = vid_enc_stop(client_ctx);
+		if (!result) {
+			ERR("setting VEN_IOCTL_CMD_STOP failed\n");
+			return -EIO;
+		}
+		stop_cmd = 1;
+		break;
+	case VEN_IOCTL_CMD_PAUSE:
+		INFO("%s: Executing VEN_IOCTL_CMD_PAUSE\n", __func__);
+		result = vid_enc_pause(client_ctx);
+		if (!result) {
+			ERR("setting VEN_IOCTL_CMD_PAUSE failed\n");
+			return -EIO;
+		}
+		break;
+	case VEN_IOCTL_CMD_RESUME:
+		INFO("%s: Executing VEN_IOCTL_CMD_RESUME\n", __func__);
+		result = vid_enc_resume(client_ctx);
+		if (!result) {
+			ERR("setting VEN_IOCTL_CMD_RESUME failed\n");
+			return -EIO;
+		}
+		break;
+	case VEN_IOCTL_SET_QP_RANGE:
+	{
+		struct venc_qprange qprange;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_QP_RANGE\n");
+
+		if (copy_from_user(&qprange, venc_msg.in, sizeof(qprange)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_qprange(client_ctx, &qprange, true);
+
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_QP_RANGE failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_QP_RANGE:
+	{
+		struct venc_qprange qprange;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_QP_RANGE\n");
+		result = vid_enc_set_get_qprange(client_ctx, &qprange, false);
+
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &qprange, sizeof(qprange)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_HEC:
+	{
+		struct venc_headerextension ext;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_HEC\n");
+
+		if (copy_from_user(&ext, venc_msg.in, sizeof(ext)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_headerextension(client_ctx, &ext,
+			true);
+
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_HEC failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_HEC:
+	{
+		struct venc_headerextension ext;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_HEC\n");
+		result = vid_enc_set_get_headerextension(client_ctx, &ext,
+			false);
+
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &ext, sizeof(ext)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_TARGET_BITRATE:
+	{
+		struct venc_targetbitrate rate;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_TARGET_BITRATE\n");
+
+		if (copy_from_user(&rate, venc_msg.in, sizeof(rate)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_bitrate(client_ctx, &rate, true);
+
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_TARGET_BITRATE failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_TARGET_BITRATE:
+	{
+		struct venc_targetbitrate rate;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_TARGET_BITRATE\n");
+		result = vid_enc_set_get_bitrate(client_ctx, &rate, false);
+
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &rate, sizeof(rate)))
+				return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_FRAME_RATE:
+	{
+		struct venc_framerate frm_rate;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_FRAME_RATE\n");
+
+		if (copy_from_user(&frm_rate, venc_msg.in, sizeof(frm_rate)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_framerate(client_ctx, &frm_rate,
+			true);
+
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_FRAME_RATE failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_FRAME_RATE:
+	{
+		struct venc_framerate frm_rate;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_FRAME_RATE\n");
+		result = vid_enc_set_get_framerate(client_ctx, &frm_rate,
+			false);
+
+		if (result) {
+			if (copy_to_user(venc_msg.out,
+					&frm_rate, sizeof(frm_rate)))
+				return -EFAULT;
+		} else
+			return -EIO;
+		break;
+	}
+	case VEN_IOCTL_SET_VOP_TIMING_CFG:
+	{
+		struct venc_voptimingcfg timing;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_VOP_TIMING_CFG\n");
+
+		if (copy_from_user(&timing, venc_msg.in, sizeof(timing)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_voptimingcfg(client_ctx, &timing,
+			true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_VOP_TIMING_CFG failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_VOP_TIMING_CFG:
+	{
+		struct venc_voptimingcfg timing;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_VOP_TIMING_CFG\n");
+		result = vid_enc_set_get_voptimingcfg(client_ctx, &timing,
+			false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &timing, sizeof(timing)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_RATE_CTRL_CFG:
+	{
+		struct venc_ratectrlcfg rate_ctrl;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_RATE_CTRL_CFG\n");
+
+		if (copy_from_user(&rate_ctrl, venc_msg.in, sizeof(rate_ctrl)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_ratectrlcfg(client_ctx, &rate_ctrl,
+			true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_RATE_CTRL_CFG failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_RATE_CTRL_CFG:
+	{
+		struct venc_ratectrlcfg rate_ctrl;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_RATE_CTRL_CFG\n");
+		result = vid_enc_set_get_ratectrlcfg(client_ctx, &rate_ctrl,
+			false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &rate_ctrl, sizeof(rate_ctrl)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_MULTI_SLICE_CFG:
+	{
+		struct venc_multiclicecfg slice;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_MULTI_SLICE_CFG\n");
+
+		if (copy_from_user(&slice, venc_msg.in, sizeof(slice)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_multiclicecfg(client_ctx, &slice,
+			true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_MULTI_SLICE_CFG failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_MULTI_SLICE_CFG:
+	{
+		struct venc_multiclicecfg slice;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_MULTI_SLICE_CFG\n");
+		result = vid_enc_set_get_multiclicecfg(client_ctx, &slice,
+			false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &slice, sizeof(slice)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_INTRA_REFRESH:
+	{
+		struct venc_intrarefresh refresh;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_INTRA_REFRESH\n");
+
+		if (copy_from_user(&refresh, venc_msg.in, sizeof(refresh)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_intrarefresh(client_ctx, &refresh,
+			true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_INTRA_REFRESH failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_INTRA_REFRESH:
+	{
+		struct venc_intrarefresh refresh;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_DEBLOCKING_CFG\n");
+		result = vid_enc_set_get_intrarefresh(client_ctx, &refresh,
+			false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &refresh, sizeof(refresh)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_DEBLOCKING_CFG:
+	{
+		struct venc_dbcfg dbcfg;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_DEBLOCKING_CFG\n");
+
+		if (copy_from_user(&dbcfg, venc_msg.in, sizeof(dbcfg)))
+			return -EFAULT;
+		result = vid_enc_set_get_dbcfg(client_ctx, &dbcfg, true);
+
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_DEBLOCKING_CFG failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_DEBLOCKING_CFG:
+	{
+		struct venc_dbcfg dbcfg;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_DEBLOCKING_CFG\n");
+		result = vid_enc_set_get_dbcfg(client_ctx, &dbcfg, false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &dbcfg, sizeof(dbcfg)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_ENTROPY_CFG:
+	{
+		struct venc_entropycfg entropy;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_ENTROPY_CFG\n");
+
+		if (copy_from_user(&entropy, venc_msg.in, sizeof(entropy)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_entropy_cfg(client_ctx, &entropy,
+			true);
+
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_ENTROPY_CFG failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_ENTROPY_CFG:
+	{
+		struct venc_entropycfg entropy;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_ENTROPY_CFG\n");
+
+		result = vid_enc_set_get_entropy_cfg(client_ctx, &entropy,
+			false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &entropy, sizeof(entropy)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_GET_SEQUENCE_HDR:
+	{
+		int rc = 0;
+		struct venc_seqheader hdr;
+		struct venc_seqheader hdr_user;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_SEQUENCE_HDR\n");
+
+		if (copy_from_user(&hdr, venc_msg.in, sizeof(hdr)))
+			return -EFAULT;
+		if (copy_from_user(&hdr_user, venc_msg.in, sizeof(hdr_user)))
+			return -EFAULT;
+
+		hdr.buf = NULL;
+		result = vid_enc_get_sequence_header(client_ctx, &hdr);
+		if (!result)
+			rc = -EIO;
+		if (!rc || copy_to_user(hdr_user.buf, hdr.buf, hdr.hdr_len))
+			rc = -EFAULT;
+		if (!rc || copy_to_user(&hdr_user.hdr_len, &hdr.hdr_len,
+				sizeof(hdr.hdr_len)))
+			rc = -EFAULT;
+
+		kfree(hdr.buf);
+		hdr.buf = NULL;
+		if (rc)
+			return rc;
+		break;
+	}
+	case VEN_IOCTL_GET_CAPABILITY:
+		return -EIO;
+	case VEN_IOCTL_CMD_REQUEST_IFRAME:
+		result = vid_enc_request_iframe(client_ctx);
+		if (!result) {
+			ERR("setting VEN_IOCTL_CMD_REQUEST_IFRAME failed\n");
+			return -EIO;
+		}
+		break;
+	case VEN_IOCTL_SET_INTRA_PERIOD:
+	{
+		struct venc_intraperiod period;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_INTRA_PERIOD\n");
+
+		if (copy_from_user(&period, venc_msg.in, sizeof(period)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_intraperiod(client_ctx, &period,
+			true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_INTRA_PERIOD failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_INTRA_PERIOD:
+	{
+		struct venc_intraperiod period;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_SESSION_QP\n");
+
+		result = vid_enc_set_get_intraperiod(client_ctx, &period,
+			false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &period, sizeof(period)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_SESSION_QP:
+	{
+		struct venc_sessionqp qp;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_SESSION_QP\n");
+
+		if (copy_from_user(&qp,	venc_msg.in, sizeof(qp)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_session_qp(client_ctx,	&qp, true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_SESSION_QP failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_SESSION_QP:
+	{
+		struct venc_sessionqp qp;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_SESSION_QP\n");
+
+		result = vid_enc_set_get_session_qp(client_ctx, &qp, false);
+
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &qp, sizeof(qp)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_PROFILE_LEVEL:
+	{
+		struct ven_profilelevel level;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_PROFILE_LEVEL\n");
+
+		if (copy_from_user(&level, venc_msg.in, sizeof(level)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_profile_level(client_ctx, &level,
+			true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_PROFILE_LEVEL failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_PROFILE_LEVEL:
+	{
+		struct ven_profilelevel level;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_CODEC_PROFILE\n");
+
+		result = vid_enc_set_get_profile_level(client_ctx, &level,
+			false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &level, sizeof(level)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_CODEC_PROFILE:
+	{
+		struct venc_profile profile;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_SET_CODEC_PROFILE\n");
+
+		if (copy_from_user(&profile, venc_msg.in, sizeof(profile)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_profile(client_ctx, &profile, true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_CODEC_PROFILE failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_CODEC_PROFILE:
+	{
+		struct venc_profile profile;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_CODEC_PROFILE\n");
+
+		result = vid_enc_set_get_profile(client_ctx, &profile, false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &profile, sizeof(profile)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_SHORT_HDR:
+	{
+		struct venc_switch enc_switch;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("Getting VEN_IOCTL_SET_SHORT_HDR\n");
+
+		if (copy_from_user(&enc_switch, venc_msg.in,
+				sizeof(enc_switch)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_short_header(client_ctx, &enc_switch,
+			true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_SHORT_HDR failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_SHORT_HDR:
+	{
+		struct venc_switch enc_switch;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_LIVE_MODE\n");
+
+		result = vid_enc_set_get_short_header(client_ctx, &enc_switch,
+			false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &enc_switch, sizeof(enc_switch)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_BASE_CFG:
+	{
+		struct venc_basecfg base;
+		DBG("VEN_IOCTL_SET_BASE_CFG\n");
+
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		if (copy_from_user(&base, venc_msg.in, sizeof(base)))
+			return -EFAULT;
+
+		DBG("setting VEN_IOCTL_SET_BASE_CFG\n");
+
+		result = vid_enc_set_get_base_cfg(client_ctx, &base, true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_BASE_CFG failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_BASE_CFG:
+	{
+		struct venc_basecfg base;
+		DBG("VEN_IOCTL_GET_BASE_CFG\n");
+
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("Getting VEN_IOCTL_SET_BASE_CFG\n");
+
+		result = vid_enc_set_get_base_cfg(client_ctx, &base, false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &base, sizeof(base)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_LIVE_MODE:
+	{
+		struct venc_switch enc_switch;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("Getting VEN_IOCTL_SET_LIVE_MODE\n");
+
+		if (copy_from_user(&enc_switch, venc_msg.in, sizeof(enc_switch)))
+			return -EFAULT;
+
+		result = vid_enc_set_get_live_mode(client_ctx, &enc_switch,
+			true);
+		if (!result) {
+			ERR("setting VEN_IOCTL_SET_LIVE_MODE failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_LIVE_MODE:
+	{
+		struct venc_switch enc_switch;
+		if (copy_from_user(&venc_msg, u_arg, sizeof(venc_msg)))
+			return -EFAULT;
+
+		DBG("VEN_IOCTL_GET_LIVE_MODE\n");
+
+		result = vid_enc_set_get_live_mode(client_ctx, &enc_switch,
+			false);
+		if (!result)
+			return -EIO;
+		if (copy_to_user(venc_msg.out, &enc_switch, sizeof(enc_switch)))
+			return -EFAULT;
+		break;
+	}
+	case VEN_IOCTL_SET_AC_PREDICTION:
+	case VEN_IOCTL_GET_AC_PREDICTION:
+	case VEN_IOCTL_SET_RVLC:
+	case VEN_IOCTL_GET_RVLC:
+	case VEN_IOCTL_SET_ROTATION:
+	case VEN_IOCTL_GET_ROTATION:
+	case VEN_IOCTL_SET_DATA_PARTITION:
+	case VEN_IOCTL_GET_DATA_PARTITION:
+	default:
+		ERR("%s: Unsupported ioctl %d\n", __func__, cmd);
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Video encoder driver");
+MODULE_VERSION("1.0");
+
+module_init(vid_enc_init);
+module_exit(vid_enc_exit);
diff --git a/drivers/misc/video_core/720p/enc/venc_internal.c b/drivers/misc/video_core/720p/enc/venc_internal.c
new file mode 100644
index 0000000..11e8d66
--- /dev/null
+++ b/drivers/misc/video_core/720p/enc/venc_internal.c
@@ -0,0 +1,1576 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/android_pmem.h>
+#include <linux/clk.h>
+
+#include "video_core_type.h"
+#include "vcd_api.h"
+#include "venc_internal.h"
+#include "video_core_init.h"
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+#define ERR(x...) printk(KERN_ERR x)
+
+u32 vid_enc_set_get_base_cfg(struct video_client_ctx *client_ctx,
+	struct venc_basecfg *config, u32 set_flag)
+{
+	struct venc_targetbitrate venc_bitrate;
+	struct venc_framerate frame_rate;
+	u32 current_codec_type;
+
+	if (!client_ctx || !config)
+		return false;
+
+	if (!vid_enc_set_get_codec(client_ctx, &current_codec_type, false))
+			return false;
+
+	DBG("%s: Current Codec Type = %u\n", __func__, current_codec_type);
+	if (current_codec_type != config->codectype) {
+		if (!vid_enc_set_get_codec(client_ctx, &config->codectype,
+				set_flag))
+			return false;
+	}
+
+	if (!vid_enc_set_get_inputformat(client_ctx, &config->inputformat,
+			set_flag))
+		return false;
+
+	if (!vid_enc_set_get_framesize(client_ctx, &config->input_height,
+			&config->input_width, set_flag))
+		return false;
+
+	if (set_flag)
+		venc_bitrate.target_bitrate = config->targetbitrate;
+
+	if (!vid_enc_set_get_bitrate(client_ctx, &venc_bitrate, set_flag))
+		return false;
+
+	if (!set_flag)
+		config->targetbitrate = venc_bitrate.target_bitrate;
+
+	if (set_flag) {
+		frame_rate.fps_denominator = config->fps_den;
+		frame_rate.fps_numerator = config->fps_num;
+	}
+
+	if (!vid_enc_set_get_framerate(client_ctx, &frame_rate, set_flag))
+		return false;
+
+	if (!set_flag) {
+		config->fps_den = frame_rate.fps_denominator;
+		config->fps_num = frame_rate.fps_numerator;
+	}
+
+	return true;
+}
+
+u32 vid_enc_set_get_inputformat(struct video_client_ctx *client_ctx,
+	u32 *input_format, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_buffer_format format_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+	u32 status = true;
+
+	if (!client_ctx || !input_format)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_BUFFER_FORMAT;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_format);
+
+	if (set_flag) {
+		switch (*input_format) {
+		case VEN_INPUTFMT_NV12:
+			format_type.buffer_format = VCD_BUFFER_FORMAT_NV12;
+			break;
+		case VEN_INPUTFMT_NV21:
+			format_type.buffer_format = VCD_BUFFER_FORMAT_TILE_4x2;
+			break;
+		default:
+			status = false;
+			break;
+		}
+
+		if (!status)
+			return status;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &format_type);
+		if (vcd_status) {
+			status = false;
+			ERR("%s(): Set VCD_I_BUFFER_FORMAT Failed\n", __func__);
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &format_type);
+
+		if (vcd_status) {
+			status = false;
+			ERR("%s(): Get VCD_I_BUFFER_FORMAT Failed\n", __func__);
+			return status;
+		}
+		switch (format_type.buffer_format) {
+		case VCD_BUFFER_FORMAT_NV12:
+			*input_format = VEN_INPUTFMT_NV12;
+			break;
+		case VCD_BUFFER_FORMAT_TILE_4x2:
+			*input_format = VEN_INPUTFMT_NV21;
+			break;
+		default:
+			status = false;
+			break;
+		}
+	}
+	return status;
+}
+
+u32 vid_enc_set_get_codec(struct video_client_ctx *client_ctx, u32 *codec_type,
+	u32 set_flag)
+{
+	struct vcd_property_codec vcd_property_codec;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+	u32 status = true;
+
+	if (!client_ctx || !codec_type)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+	if (set_flag) {
+		switch (*codec_type) {
+		case VEN_CODEC_MPEG4:
+			vcd_property_codec.codec = VCD_CODEC_MPEG4;
+			break;
+		case VEN_CODEC_H263:
+			vcd_property_codec.codec = VCD_CODEC_H263;
+			break;
+		case VEN_CODEC_H264:
+			vcd_property_codec.codec = VCD_CODEC_H264;
+			break;
+		default:
+			status = false;
+			break;
+		}
+
+		if (!status)
+			return status;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_codec);
+		if (vcd_status) {
+			status = false;
+			ERR("%s: Set VCD_I_CODEC Failed\n", __func__);
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_codec);
+
+		if (vcd_status) {
+			status = false;
+			ERR("%s(): Get VCD_I_CODEC Failed\n", __func__);
+			return status;
+		}
+		switch (vcd_property_codec.codec) {
+		case VCD_CODEC_H263:
+			*codec_type = VEN_CODEC_H263;
+			break;
+		case VCD_CODEC_H264:
+			*codec_type = VEN_CODEC_H264;
+			break;
+		case VCD_CODEC_MPEG4:
+			*codec_type = VEN_CODEC_MPEG4;
+			break;
+		case VCD_CODEC_DIVX_3:
+		case VCD_CODEC_DIVX_4:
+		case VCD_CODEC_DIVX_5:
+		case VCD_CODEC_DIVX_6:
+		case VCD_CODEC_MPEG1:
+		case VCD_CODEC_MPEG2:
+		case VCD_CODEC_VC1:
+		case VCD_CODEC_VC1_RCV:
+		case VCD_CODEC_XVID:
+		default:
+			status = false;
+			break;
+		}
+	}
+	return status;
+}
+
+u32 vid_enc_set_get_framesize(struct video_client_ctx *client_ctx, u32 *height,
+	u32 *width, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_size frame_size;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !height || !width)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_FRAME_SIZE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+
+	if (set_flag) {
+		frame_size.height = *height;
+		frame_size.width = *width;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &frame_size);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_FRAME_SIZE Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &frame_size);
+
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_FRAME_SIZE Failed\n", __func__);
+			return false;
+		}
+		*height = frame_size.height;
+		*width = frame_size.width;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_bitrate(struct video_client_ctx *client_ctx,
+	struct venc_targetbitrate *venc_bitrate, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_target_bitrate bit_rate;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_bitrate)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_TARGET_BITRATE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_target_bitrate);
+	if (set_flag) {
+		bit_rate.target_bitrate = venc_bitrate->target_bitrate;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &bit_rate);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_TARGET_BITRATE Failed\n",
+				__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &bit_rate);
+
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_TARGET_BITRATE Failed\n",
+				__func__);
+			return false;
+		}
+		venc_bitrate->target_bitrate = bit_rate.target_bitrate;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_framerate(struct video_client_ctx *client_ctx,
+	struct venc_framerate *frame_rate, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_rate vcd_frame_rate;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !frame_rate)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_FRAME_RATE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_frame_rate);
+
+	if (set_flag) {
+		vcd_frame_rate.fps_denominator = frame_rate->fps_denominator;
+		vcd_frame_rate.fps_numerator = frame_rate->fps_numerator;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_frame_rate);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_FRAME_RATE Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_frame_rate);
+
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_FRAME_RATE Failed\n", __func__);
+			return false;
+		}
+		frame_rate->fps_denominator = vcd_frame_rate.fps_denominator;
+		frame_rate->fps_numerator = vcd_frame_rate.fps_numerator;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_live_mode(struct video_client_ctx *client_ctx,
+	struct venc_switch *encoder_switch, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_live live_mode;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_LIVE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_live);
+
+	if (set_flag) {
+		live_mode.live = 1;
+		if (!encoder_switch->status)
+			live_mode.live = 0;
+
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &live_mode);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_LIVE Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &live_mode);
+
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_LIVE Failed\n", __func__);
+			return false;
+		}
+		encoder_switch->status = 1;
+		if (!live_mode.live)
+			encoder_switch->status = 0;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_short_header(struct video_client_ctx *client_ctx,
+	struct venc_switch *encoder_switch, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_short_header short_header;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !encoder_switch)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_SHORT_HEADER;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_short_header);
+
+	if (set_flag) {
+		short_header.short_header = (u32) encoder_switch->status;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &short_header);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_SHORT_HEADER Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &short_header);
+
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_SHORT_HEADER Failed\n", __func__);
+			return false;
+		}
+		encoder_switch->status = (u8)short_header.short_header;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_profile(struct video_client_ctx *client_ctx,
+	struct venc_profile *profile, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_profile profile_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+	u32 status = true;
+
+	if (!client_ctx || !profile)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_PROFILE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_profile);
+
+	if (set_flag) {
+		switch (profile->profile) {
+		case VEN_PROFILE_MPEG4_SP:
+			profile_type.profile = VCD_PROFILE_MPEG4_SP;
+			break;
+		case VEN_PROFILE_MPEG4_ASP:
+			profile_type.profile = VCD_PROFILE_MPEG4_ASP;
+			break;
+		case VEN_PROFILE_H264_BASELINE:
+			profile_type.profile = VCD_PROFILE_H264_BASELINE;
+			break;
+		case VEN_PROFILE_H264_MAIN:
+			profile_type.profile = VCD_PROFILE_H264_MAIN;
+			break;
+		case VEN_PROFILE_H264_HIGH:
+			profile_type.profile = VCD_PROFILE_H264_HIGH;
+			break;
+		case VEN_PROFILE_H263_BASELINE:
+			profile_type.profile = VCD_PROFILE_H263_BASELINE;
+			break;
+		default:
+			status = false;
+			break;
+		}
+
+		if (!status)
+			return status;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &profile_type);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_PROFILE Failed\n",	__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &profile_type);
+
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_PROFILE Failed\n", __func__);
+			return false;
+		}
+		switch (profile_type.profile) {
+		case VCD_PROFILE_H263_BASELINE:
+			profile->profile = VEN_PROFILE_H263_BASELINE;
+			break;
+		case VCD_PROFILE_H264_BASELINE:
+			profile->profile = VEN_PROFILE_H264_BASELINE;
+			break;
+		case VCD_PROFILE_H264_HIGH:
+			profile->profile = VEN_PROFILE_H264_HIGH;
+			break;
+		case VCD_PROFILE_H264_MAIN:
+			profile->profile = VEN_PROFILE_H264_MAIN;
+			break;
+		case VCD_PROFILE_MPEG4_ASP:
+			profile->profile = VEN_PROFILE_MPEG4_ASP;
+			break;
+		case VCD_PROFILE_MPEG4_SP:
+			profile->profile = VEN_PROFILE_MPEG4_SP;
+			break;
+		default:
+			status = false;
+			break;
+		}
+	}
+	return status;
+}
+
+u32 vid_enc_set_get_profile_level(struct video_client_ctx *client_ctx,
+	struct ven_profilelevel *profile_level,	u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_level level_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !profile_level)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_LEVEL;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_level);
+
+	if (set_flag) {
+		switch (profile_level->level) {
+		//TODO: collapse this crap
+		case VEN_LEVEL_MPEG4_0:
+			level_type.level = VCD_LEVEL_MPEG4_0;
+			break;
+		case VEN_LEVEL_MPEG4_1:
+			level_type.level = VCD_LEVEL_MPEG4_1;
+			break;
+		case VEN_LEVEL_MPEG4_2:
+			level_type.level = VCD_LEVEL_MPEG4_2;
+			break;
+		case VEN_LEVEL_MPEG4_3:
+			level_type.level = VCD_LEVEL_MPEG4_3;
+			break;
+		case VEN_LEVEL_MPEG4_4:
+			level_type.level = VCD_LEVEL_MPEG4_4;
+			break;
+		case VEN_LEVEL_MPEG4_5:
+			level_type.level = VCD_LEVEL_MPEG4_5;
+			break;
+		case VEN_LEVEL_MPEG4_3b:
+			level_type.level = VCD_LEVEL_MPEG4_3b;
+			break;
+		case VEN_LEVEL_MPEG4_6:
+			level_type.level = VCD_LEVEL_MPEG4_6;
+			break;
+		case VEN_LEVEL_H264_1:
+			level_type.level = VCD_LEVEL_H264_1;
+			break;
+		case VEN_LEVEL_H264_1b:
+			level_type.level = VCD_LEVEL_H264_1b;
+			break;
+		case VEN_LEVEL_H264_1p1:
+			level_type.level = VCD_LEVEL_H264_1p1;
+			break;
+		case VEN_LEVEL_H264_1p2:
+			level_type.level = VCD_LEVEL_H264_1p2;
+			break;
+		case VEN_LEVEL_H264_1p3:
+			level_type.level = VCD_LEVEL_H264_1p3;
+			break;
+		case VEN_LEVEL_H264_2:
+			level_type.level = VCD_LEVEL_H264_2;
+			break;
+		case VEN_LEVEL_H264_2p1:
+			level_type.level = VCD_LEVEL_H264_2p1;
+			break;
+		case VEN_LEVEL_H264_2p2:
+			level_type.level = VCD_LEVEL_H264_2p2;
+			break;
+		case VEN_LEVEL_H264_3:
+			level_type.level = VCD_LEVEL_H264_3;
+			break;
+		case VEN_LEVEL_H264_3p1:
+			level_type.level = VCD_LEVEL_H264_3p1;
+			break;
+		case VEN_LEVEL_H263_10:
+			level_type.level = VCD_LEVEL_H263_10;
+			break;
+		case VEN_LEVEL_H263_20:
+			level_type.level = VCD_LEVEL_H263_20;
+			break;
+		case VEN_LEVEL_H263_30:
+			level_type.level = VCD_LEVEL_H263_30;
+			break;
+		case VEN_LEVEL_H263_40:
+			level_type.level = VCD_LEVEL_H263_40;
+			break;
+		case VEN_LEVEL_H263_45:
+			level_type.level = VCD_LEVEL_H263_45;
+			break;
+		case VEN_LEVEL_H263_50:
+			level_type.level = VCD_LEVEL_H263_50;
+			break;
+		case VEN_LEVEL_H263_60:
+			level_type.level = VCD_LEVEL_H263_60;
+			break;
+		case VEN_LEVEL_H263_70:
+			level_type.level = VCD_LEVEL_H263_70;
+			break;
+		default:
+			return false;
+		}
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &level_type);
+
+		if (vcd_status) {
+			ERR("%s: Set VCD_I_LEVEL Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &level_type);
+
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_LEVEL Failed\n", __func__);
+			return false;
+		}
+		switch (level_type.level) {
+		case VCD_LEVEL_MPEG4_0:
+			profile_level->level = VEN_LEVEL_MPEG4_0;
+			break;
+		case VCD_LEVEL_MPEG4_1:
+			profile_level->level = VEN_LEVEL_MPEG4_1;
+			break;
+		case VCD_LEVEL_MPEG4_2:
+			profile_level->level = VEN_LEVEL_MPEG4_2;
+			break;
+		case VCD_LEVEL_MPEG4_3:
+			profile_level->level = VEN_LEVEL_MPEG4_3;
+			break;
+		case VCD_LEVEL_MPEG4_4:
+			profile_level->level = VEN_LEVEL_MPEG4_4;
+			break;
+		case VCD_LEVEL_MPEG4_5:
+			profile_level->level = VEN_LEVEL_MPEG4_5;
+			break;
+		case VCD_LEVEL_MPEG4_3b:
+			profile_level->level = VEN_LEVEL_MPEG4_3b;
+			break;
+		case VCD_LEVEL_H264_1:
+			profile_level->level = VEN_LEVEL_H264_1;
+			break;
+		case VCD_LEVEL_H264_1b:
+			profile_level->level = VEN_LEVEL_H264_1b;
+			break;
+		case VCD_LEVEL_H264_1p1:
+			profile_level->level = VEN_LEVEL_H264_1p1;
+			break;
+		case VCD_LEVEL_H264_1p2:
+			profile_level->level = VEN_LEVEL_H264_1p2;
+			break;
+		case VCD_LEVEL_H264_1p3:
+			profile_level->level = VEN_LEVEL_H264_1p3;
+			break;
+		case VCD_LEVEL_H264_2:
+			profile_level->level = VEN_LEVEL_H264_2;
+			break;
+		case VCD_LEVEL_H264_2p1:
+			profile_level->level = VEN_LEVEL_H264_2p1;
+			break;
+		case VCD_LEVEL_H264_2p2:
+			profile_level->level = VEN_LEVEL_H264_2p2;
+			break;
+		case VCD_LEVEL_H264_3:
+			profile_level->level = VEN_LEVEL_H264_3;
+			break;
+		case VCD_LEVEL_H264_3p1:
+			profile_level->level = VEN_LEVEL_H264_3p1;
+			break;
+		case VCD_LEVEL_H264_3p2:
+		case VCD_LEVEL_H264_4:
+			return false;
+		case VCD_LEVEL_H263_10:
+			profile_level->level = VEN_LEVEL_H263_10;
+			break;
+		case VCD_LEVEL_H263_20:
+			profile_level->level = VEN_LEVEL_H263_20;
+			break;
+		case VCD_LEVEL_H263_30:
+			profile_level->level = VEN_LEVEL_H263_30;
+			break;
+		case VCD_LEVEL_H263_40:
+			profile_level->level = VEN_LEVEL_H263_40;
+			break;
+		case VCD_LEVEL_H263_45:
+			profile_level->level = VEN_LEVEL_H263_45;
+			break;
+		case VCD_LEVEL_H263_50:
+			profile_level->level = VEN_LEVEL_H263_50;
+			break;
+		case VCD_LEVEL_H263_60:
+			profile_level->level = VEN_LEVEL_H263_60;
+			break;
+		case VCD_LEVEL_H263_70:
+		default:
+			return false;
+		}
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_session_qp(struct video_client_ctx *client_ctx,
+	struct venc_sessionqp *session_qp, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_session_qp qp_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !session_qp)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_SESSION_QP;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_session_qp);
+
+	if (set_flag) {
+		qp_type.iframe_qp = session_qp->iframeqp;
+		qp_type.frame_qp = session_qp->pframqp;
+
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &qp_type);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_SESSION_QP Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &qp_type);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_SESSION_QP Failed\n", __func__);
+			return false;
+		}
+		session_qp->iframeqp = qp_type.iframe_qp;
+		session_qp->pframqp = qp_type.frame_qp;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_intraperiod(struct video_client_ctx *client_ctx,
+	struct venc_intraperiod *intraperiod, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_i_period period_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !intraperiod)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_INTRA_PERIOD;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_i_period);
+
+	if (set_flag) {
+		period_type.frames = intraperiod->num_pframes;
+		period_type.bframes = 0;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &period_type);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_INTRA_PERIOD Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &period_type);
+
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_INTRA_PERIOD Failed\n", __func__);
+			return false;
+		}
+		intraperiod->num_pframes = period_type.frames;
+	}
+	return true;
+}
+
+u32 vid_enc_request_iframe(struct video_client_ctx *client_ctx)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_req_i_frame request;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_REQ_IFRAME;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_req_i_frame);
+	request.req_i_frame = 1;
+
+	vcd_status = vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+		&request);
+
+	if (vcd_status) {
+		ERR("%s(): Set VCD_I_REQ_IFRAME Failed\n", __func__);
+		return false;
+	}
+	return true;
+}
+
+u32 vid_enc_get_sequence_header(struct video_client_ctx *client_ctx,
+	struct venc_seqheader *seq_header)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_sequence_hdr hdr_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !seq_header || !seq_header->buf_sz)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_SEQ_HEADER;
+	vcd_property_hdr.sz = sizeof(struct vcd_sequence_hdr);
+
+	hdr_type.addr = kzalloc(seq_header->buf_sz, GFP_KERNEL);
+	seq_header->buf = hdr_type.addr;
+	if (!hdr_type.addr)
+		return false;
+
+	hdr_type.sz = seq_header->buf_sz;
+	vcd_status = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+		&hdr_type);
+
+	if (vcd_status) {
+		ERR("%s: Get VCD_I_SEQ_HEADER Failed\n", __func__);
+		return false;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_entropy_cfg(struct video_client_ctx *client_ctx,
+	struct venc_entropycfg *entropy_cfg, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_entropy_control control_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !entropy_cfg)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_ENTROPY_CTRL;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_entropy_control);
+
+	if (set_flag) {
+		switch (entropy_cfg->cabacmodel) {
+		case VEN_ENTROPY_MODEL_CAVLC:
+			control_type.entropy_sel = VCD_ENTROPY_SEL_CAVLC;
+			break;
+		case VEN_ENTROPY_MODEL_CABAC:
+			control_type.entropy_sel = VCD_ENTROPY_SEL_CABAC;
+			break;
+		default:
+			return false;
+		}
+
+		if (entropy_cfg->cabacmodel == VCD_ENTROPY_SEL_CABAC) {
+			switch (entropy_cfg->cabacmodel) {
+			case VEN_CABAC_MODEL_0:
+				control_type.cabac_model =
+					VCD_CABAC_MODEL_NUMBER_0;
+				break;
+			case VEN_CABAC_MODEL_1:
+				control_type.cabac_model =
+					VCD_CABAC_MODEL_NUMBER_1;
+				break;
+			case VEN_CABAC_MODEL_2:
+				control_type.cabac_model =
+					VCD_CABAC_MODEL_NUMBER_2;
+				break;
+			default:
+				return false;
+			}
+		}
+
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_ENTROPY_CTRL Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_ENTROPY_CTRL Failed\n", __func__);
+			return false;
+		}
+
+		switch (control_type.entropy_sel) {
+		case VCD_ENTROPY_SEL_CABAC:
+			entropy_cfg->cabacmodel = VEN_ENTROPY_MODEL_CABAC;
+			break;
+		case VCD_ENTROPY_SEL_CAVLC:
+			entropy_cfg->cabacmodel = VEN_ENTROPY_MODEL_CAVLC;
+			break;
+		default:
+			return false;
+		}
+
+		if (control_type.entropy_sel ==	VCD_ENTROPY_SEL_CABAC) {
+			switch (control_type.cabac_model) {
+			case VCD_CABAC_MODEL_NUMBER_0:
+				entropy_cfg->cabacmodel = VEN_CABAC_MODEL_0;
+				break;
+			case VCD_CABAC_MODEL_NUMBER_1:
+				entropy_cfg->cabacmodel = VEN_CABAC_MODEL_1;
+				break;
+			case VCD_CABAC_MODEL_NUMBER_2:
+				entropy_cfg->cabacmodel = VEN_CABAC_MODEL_2;
+				break;
+			default:
+				return false;
+			}
+		}
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_dbcfg(struct video_client_ctx *client_ctx,
+	struct venc_dbcfg *dbcfg, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_db_config control_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !dbcfg)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_DEBLOCKING;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_db_config);
+
+	if (set_flag) {
+		switch (dbcfg->db_mode) {
+		case VEN_DB_DISABLE:
+			control_type.db_config = VCD_DB_DISABLE;
+			break;
+		case VEN_DB_ALL_BLKG_BNDRY:
+			control_type.db_config = VCD_DB_ALL_BLOCKING_BOUNDARY;
+			break;
+		case VEN_DB_SKIP_SLICE_BNDRY:
+			control_type.db_config = VCD_DB_SKIP_SLICE_BOUNDARY;
+			break;
+		default:
+			return false;
+		}
+
+		control_type.slice_alpha_offset = dbcfg->slicealpha_offset;
+		control_type.slice_beta_offset = dbcfg->slicebeta_offset;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+		if (vcd_status) {
+			ERR("%s: Set VCD_I_DEBLOCKING Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+		if (vcd_status) {
+			ERR("%s: Get VCD_I_DEBLOCKING Failed\n", __func__);
+			return false;
+		}
+		switch (control_type.db_config) {
+		case VCD_DB_ALL_BLOCKING_BOUNDARY:
+			dbcfg->db_mode = VEN_DB_ALL_BLKG_BNDRY;
+			break;
+		case VCD_DB_DISABLE:
+			dbcfg->db_mode = VEN_DB_DISABLE;
+			break;
+		case VCD_DB_SKIP_SLICE_BOUNDARY:
+			dbcfg->db_mode = VEN_DB_SKIP_SLICE_BNDRY;
+			break;
+		default:
+			return false;
+		}
+		dbcfg->slicealpha_offset = control_type.slice_alpha_offset;
+		dbcfg->slicebeta_offset = control_type.slice_beta_offset;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_intrarefresh(struct video_client_ctx *client_ctx,
+	struct venc_intrarefresh *intrarefresh, u32 set_flag)
+{
+	struct vcd_property_hdr prop_hdr;
+	struct vcd_property_intra_refresh_mb_number control_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !intrarefresh)
+		return false;
+
+	prop_hdr.id = VCD_I_INTRA_REFRESH;
+	prop_hdr.sz = sizeof(struct vcd_property_intra_refresh_mb_number);
+
+	if (set_flag) {
+		control_type.cir_mb_number = intrarefresh->mbcount;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle, &prop_hdr,
+			&control_type);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_INTRA_REFRESH Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle, &prop_hdr,
+			&control_type);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_INTRA_REFRESH Failed\n", __func__);
+			return false;
+		}
+		intrarefresh->mbcount = control_type.cir_mb_number;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_multiclicecfg(struct video_client_ctx *client_ctx,
+	struct venc_multiclicecfg *multiclicecfg, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_multi_slice control_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !multiclicecfg)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_MULTI_SLICE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_multi_slice);
+
+	if (set_flag) {
+		switch (multiclicecfg->mslice_mode) {
+		case VEN_MSLICE_OFF:
+			control_type.m_slice_sel = VCD_MSLICE_OFF;
+			break;
+		case VEN_MSLICE_CNT_MB:
+			control_type.m_slice_sel = VCD_MSLICE_BY_MB_COUNT;
+			break;
+		case VEN_MSLICE_CNT_BYTE:
+			control_type.m_slice_sel = VCD_MSLICE_BY_BYTE_COUNT;
+			break;
+		case VEN_MSLICE_GOB:
+			control_type.m_slice_sel = VCD_MSLICE_BY_GOB;
+			break;
+		default:
+			return false;
+		}
+
+		control_type.m_slice_size = multiclicecfg->mslice_size;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+
+		if (vcd_status) {
+			ERR("%s: Set VCD_I_MULTI_SLICE Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+
+		if (vcd_status) {
+			ERR("%s: Get VCD_I_MULTI_SLICE Failed\n", __func__);
+			return false;
+		}
+		multiclicecfg->mslice_size = control_type.m_slice_size;
+		switch (control_type.m_slice_sel) {
+		case VCD_MSLICE_OFF:
+			multiclicecfg->mslice_mode = VEN_MSLICE_OFF;
+			break;
+		case VCD_MSLICE_BY_MB_COUNT:
+			multiclicecfg->mslice_mode = VEN_MSLICE_CNT_MB;
+			break;
+		case VCD_MSLICE_BY_BYTE_COUNT:
+			multiclicecfg->mslice_mode = VEN_MSLICE_CNT_BYTE;
+			break;
+		case VCD_MSLICE_BY_GOB:
+			multiclicecfg->mslice_mode = VEN_MSLICE_GOB;
+			break;
+		default:
+			return false;
+		}
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_ratectrlcfg(struct video_client_ctx *client_ctx,
+	struct venc_ratectrlcfg *ratectrlcfg, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_rate_control control_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !ratectrlcfg)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_RATE_CONTROL;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_rate_control);
+
+	if (set_flag) {
+		switch (ratectrlcfg->rcmode) {
+		case VEN_RC_OFF:
+			control_type.rate_control = VCD_RATE_CONTROL_OFF;
+			break;
+		case VEN_RC_CBR_VFR:
+			control_type.rate_control = VCD_RATE_CONTROL_CBR_VFR;
+			break;
+		case VEN_RC_VBR_CFR:
+			control_type.rate_control = VCD_RATE_CONTROL_VBR_CFR;
+			break;
+		case VEN_RC_VBR_VFR:
+			control_type.rate_control = VCD_RATE_CONTROL_VBR_VFR;
+			break;
+		default:
+			return false;
+		}
+
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_RATE_CONTROL Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_RATE_CONTROL Failed\n", __func__);
+			return false;
+		}
+
+		switch (control_type.rate_control) {
+		case VCD_RATE_CONTROL_OFF:
+			ratectrlcfg->rcmode = VEN_RC_OFF;
+			break;
+		case VCD_RATE_CONTROL_CBR_VFR:
+			ratectrlcfg->rcmode = VEN_RC_CBR_VFR;
+			break;
+		case VCD_RATE_CONTROL_VBR_CFR:
+			ratectrlcfg->rcmode = VEN_RC_VBR_CFR;
+			break;
+		case VCD_RATE_CONTROL_VBR_VFR:
+			ratectrlcfg->rcmode = VEN_RC_VBR_VFR;
+			break;
+		default:
+			return false;
+		}
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_voptimingcfg(struct video_client_ctx *client_ctx,
+	struct venc_voptimingcfg *venc_timing, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_vop_timing vcd_timing;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_timing)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_VOP_TIMING;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_vop_timing);
+
+	if (set_flag) {
+		vcd_timing.vop_time_resolution =
+			venc_timing->voptime_resolution;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_timing);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_VOP_TIMING Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_timing);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_VOP_TIMING Failed\n", __func__);
+			return false;
+		}
+		venc_timing->voptime_resolution =
+			vcd_timing.vop_time_resolution;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_headerextension(struct video_client_ctx *client_ctx,
+	struct venc_headerextension *headerextension, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 control_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !headerextension)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_HEADER_EXTENSION;
+	vcd_property_hdr.sz = sizeof(u32);
+
+	if (set_flag) {
+		control_type = headerextension->header_extension;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+		if (vcd_status) {
+			ERR("%s: Set VCD_I_HEADER_EXTENSION Fail\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+		if (vcd_status) {
+			ERR("%s: Get VCD_I_HEADER_EXTENSION Fail\n", __func__);
+			return false;
+		}
+		headerextension->header_extension = control_type;
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_qprange(struct video_client_ctx *client_ctx,
+	struct venc_qprange *qprange, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_qp_range control_type;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !qprange)
+		return false;
+
+	vcd_property_hdr.id = VCD_I_QP_RANGE;
+	vcd_property_hdr.sz =	sizeof(struct vcd_property_qp_range);
+
+	if (set_flag) {
+		control_type.max_qp = qprange->maxqp;
+		control_type.min_qp = qprange->minqp;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_QP_RANGE Failed\n", __func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &control_type);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_QP_RANGE Failed\n", __func__);
+			return false;
+		}
+		qprange->maxqp = control_type.max_qp;
+		qprange->minqp = control_type.min_qp;
+	}
+	return true;
+}
+
+u32 vid_enc_start(struct video_client_ctx *client_ctx)
+{
+	u32 vcd_status;
+
+	if (!client_ctx)
+		return false;
+
+	vcd_status = vcd_encode_start(client_ctx->vcd_handle);
+	if (vcd_status) {
+		ERR("%s: vcd_encode_start failed %u\n",	__func__, vcd_status);
+		return false;
+	}
+	return true;
+}
+
+
+u32 vid_enc_stop(struct video_client_ctx *client_ctx)
+{
+	u32 vcd_status;
+
+	if (!client_ctx)
+		return false;
+	vcd_status = vcd_stop(client_ctx->vcd_handle);
+	if (vcd_status) {
+		ERR("%s: vcd_stop failed %u\n", __func__, vcd_status);
+		return false;
+	}
+	DBG("Send STOP_DONE message to client = %p\n", client_ctx);
+	return true;
+}
+
+u32 vid_enc_pause(struct video_client_ctx *client_ctx)
+{
+	u32 vcd_status;
+
+	if (!client_ctx)
+		return false;
+
+	DBG("PAUSE command from client = %p\n", client_ctx);
+	vcd_status = vcd_pause(client_ctx->vcd_handle);
+	if (vcd_status)
+		return false;
+	return true;
+}
+
+u32 vid_enc_resume(struct video_client_ctx *client_ctx)
+{
+	u32 vcd_status;
+
+	if (!client_ctx)
+		return false;
+
+	DBG("Resume command from client = %p\n", client_ctx);
+	vcd_status = vcd_resume(client_ctx->vcd_handle);
+	if (vcd_status)
+		return false;
+	return true;
+}
+
+u32 vid_enc_flush(struct video_client_ctx *client_ctx,
+	struct venc_bufferflush *bufferflush)
+{
+	u32 mode;
+	u32 vcd_status;
+
+	if (!client_ctx || !bufferflush)
+		return false;
+
+	switch (bufferflush->flush_mode) {
+	case VEN_FLUSH_INPUT:
+		mode = VCD_FLUSH_INPUT;
+		break;
+	case VEN_FLUSH_OUTPUT:
+		mode = VCD_FLUSH_OUTPUT;
+		break;
+	case VEN_FLUSH_ALL:
+		mode = VCD_FLUSH_ALL;
+		break;
+	default:
+		return false;
+		break;
+	}
+	vcd_status = vcd_flush(client_ctx->vcd_handle, mode);
+	if (vcd_status)
+		return false;
+	return true;
+}
+
+u32 vid_enc_get_buffer_req(struct video_client_ctx *client_ctx,
+	struct venc_allocatorproperty *venc_buf_req, u32 input_dir)
+{
+	enum vcd_buffer_type buffer;
+	struct vcd_buffer_requirement buffer_req;
+	u32 vcd_status;
+
+	if (!client_ctx || !venc_buf_req)
+		return false;
+
+	buffer = VCD_BUFFER_OUTPUT;
+	if (input_dir)
+		buffer = VCD_BUFFER_INPUT;
+
+	vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+		buffer, &buffer_req);
+	if (vcd_status)
+		return false;
+
+	venc_buf_req->actualcount = buffer_req.actual_count;
+	venc_buf_req->alignment = buffer_req.align;
+	venc_buf_req->datasize = buffer_req.size;
+	venc_buf_req->mincount = buffer_req.min_count;
+	venc_buf_req->maxcount = buffer_req.max_count;
+	venc_buf_req->alignment = buffer_req.align;
+	venc_buf_req->bufpoolid = buffer_req.buf_pool_id;
+	venc_buf_req->suffixsize = 0;
+
+	return true;
+}
+
+u32 vid_enc_set_buffer_req(struct video_client_ctx *client_ctx,
+	struct venc_allocatorproperty *venc_buf_req, u32 input_dir)
+{
+	enum vcd_buffer_type buffer;
+	struct vcd_buffer_requirement buffer_req;
+	u32 vcd_status;
+
+	if (!client_ctx || !venc_buf_req)
+		return false;
+
+	buffer = VCD_BUFFER_OUTPUT;
+	if (input_dir)
+		buffer = VCD_BUFFER_INPUT;
+
+	buffer_req.actual_count = venc_buf_req->actualcount;
+	buffer_req.align = venc_buf_req->alignment;
+	buffer_req.size = venc_buf_req->datasize;
+	buffer_req.min_count = venc_buf_req->mincount;
+	buffer_req.max_count = venc_buf_req->maxcount;
+	buffer_req.align = venc_buf_req->alignment;
+	buffer_req.buf_pool_id = 0;
+
+	vcd_status = vcd_set_buffer_requirements(client_ctx->vcd_handle,
+		buffer, &buffer_req);
+
+	if (vcd_status)
+		return false;
+	return true;
+}
+
+u32 vid_enc_set_buffer(struct video_client_ctx *client_ctx,
+	struct venc_bufferpayload *buf_info, enum venc_buffer_dir buf_type)
+{
+	u32 vcd_status = VCD_ERR_FAIL;
+	enum vcd_buffer_type buffer_vcd_type;
+	enum buffer_dir dir_buffer = BUFFER_TYPE_INPUT;
+	void __user *user_addr;
+	void *kern_addr;
+	phys_addr_t phys_addr;
+	unsigned long len;
+	int pmem_fd;
+	struct file *file;
+	struct buf_addr_table *buf_addr_table;
+
+	s32 buf_index = -1;
+
+	if (!client_ctx || !buf_info)
+		return false;
+
+	user_addr = buf_info->buffer;
+
+	if (buf_type == VEN_BUFFER_TYPE_OUTPUT)
+		dir_buffer = BUFFER_TYPE_OUTPUT;
+
+	/* if buffer already set, ignore */
+	if (vid_c_lookup_addr_table(client_ctx, dir_buffer, true, &user_addr,
+			&kern_addr, &phys_addr, &pmem_fd, &file,
+			&buf_index)) {
+
+		DBG("%s: user_addr = %p is already set\n", __func__, user_addr);
+		return true;
+	}
+
+	if (get_pmem_file(buf_info->fd, (unsigned long *)&phys_addr,
+			(unsigned long *)&kern_addr,
+			&len, &file)) {
+		ERR("%s: get_pmem_file failed\n", __func__);
+		return false;
+	}
+	put_pmem_file(file);
+	if (buf_type == VEN_BUFFER_TYPE_INPUT) {
+		buffer_vcd_type = VCD_BUFFER_INPUT;
+		client_ctx->num_of_input_buffers++;
+
+		if (client_ctx->num_of_input_buffers > VID_ENC_MAX_NUM_OF_BUFF
+				) {
+			ERR("%s: num_of_input_buffers reached max value"
+				" VID_ENC_MAX_NUM_OF_BUFF\n", __func__);
+			client_ctx->num_of_input_buffers--;
+			return false;
+		}
+
+		buf_index = client_ctx->num_of_input_buffers - 1;
+		buf_addr_table = &client_ctx->input_buf_addr_table[buf_index];
+		buf_addr_table->user_addr = buf_info->buffer;
+		kern_addr = (u8 *)kern_addr + buf_info->offset;
+		phys_addr += buf_info->offset;
+		buf_addr_table->kern_addr = kern_addr;
+		buf_addr_table->phys_addr = phys_addr;
+		buf_addr_table->pmem_fd = buf_info->fd;
+		buf_addr_table->file = file;
+	} else {
+		buffer_vcd_type = VCD_BUFFER_OUTPUT;
+
+		client_ctx->num_of_output_buffers++;
+
+		if (client_ctx->num_of_output_buffers >
+				VID_ENC_MAX_NUM_OF_BUFF) {
+			ERR("%s: num_of_outut_buffers reached max value"
+				" VID_ENC_MAX_NUM_OF_BUFF\n", __func__);
+			client_ctx->num_of_output_buffers--;
+			return false;
+		}
+
+		buf_index = client_ctx->num_of_output_buffers - 1;
+
+		buf_addr_table = &client_ctx->output_buf_addr_table[buf_index];
+		kern_addr = (u8 *)kern_addr + buf_info->offset;
+		phys_addr += buf_info->offset;
+		buf_addr_table->user_addr = buf_info->buffer;
+		buf_addr_table->kern_addr = kern_addr;
+		buf_addr_table->phys_addr = phys_addr;
+		buf_addr_table->pmem_fd = buf_info->fd;
+		buf_addr_table->file = file;
+	}
+
+	vcd_status = vcd_set_buffer(client_ctx->vcd_handle, buffer_vcd_type,
+		kern_addr, buf_info->sz);
+
+	if (!vcd_status)
+		return true;
+	else
+		return false;
+}
+
+u32 vid_enc_encode_frame(struct video_client_ctx *client_ctx,
+	struct venc_buffer *input_frame_info)
+{
+	struct vcd_frame_data vcd_input_buffer;
+	void __user *user_addr;
+	void *kern_addr;
+	phys_addr_t phys_addr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !input_frame_info)
+		return false;
+
+	user_addr = input_frame_info->addr;
+
+	if (!vid_c_lookup_addr_table(client_ctx, BUFFER_TYPE_INPUT, true,
+			&user_addr, &kern_addr, &phys_addr, &pmem_fd, &file,
+			&buffer_index)) {
+		ERR("%s: kernel_vaddr not found\n", __func__);
+		return false;
+	}
+
+	/* kern_addr  is found. send the frame to VCD */
+	memset((void *)&vcd_input_buffer, 0, sizeof(vcd_input_buffer));
+
+	vcd_input_buffer.virt_addr = (u8 *)kern_addr + input_frame_info->offset;
+	vcd_input_buffer.offset = input_frame_info->offset;
+	vcd_input_buffer.client_data = input_frame_info->clientdata;
+	vcd_input_buffer.ip_frm_tag = (u32)input_frame_info->clientdata;
+	vcd_input_buffer.data_len = input_frame_info->len;
+	vcd_input_buffer.time_stamp = input_frame_info->timestamp;
+
+	/* Rely on VCD using the same flags as OMX */
+	vcd_input_buffer.flags = input_frame_info->flags;
+
+	vcd_status = vcd_encode_frame(client_ctx->vcd_handle,
+		&vcd_input_buffer);
+
+	if (vcd_status) {
+		ERR("%s: vcd_encode_frame failed = %u\n", __func__, vcd_status);
+		return false;
+	}
+	return true;
+}
+
+u32 vid_enc_fill_output_buffer(struct video_client_ctx *client_ctx,
+	struct venc_buffer *output_frame_info)
+{
+	void __user *user_addr;
+	void *kern_addr;
+	phys_addr_t phys_addr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	struct vcd_frame_data vcd_frame;
+
+	if (!client_ctx || !output_frame_info)
+		return false;
+
+	user_addr = output_frame_info->addr;
+
+	if (!vid_c_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+			true, &user_addr, &kern_addr, &phys_addr, &pmem_fd,
+			&file, &buffer_index)) {
+		ERR("%s: kernel_vaddr not found\n", __func__);
+		return false;
+	}
+
+	memset((void *)&vcd_frame, 0, sizeof(vcd_frame));
+	vcd_frame.virt_addr = kern_addr;
+	vcd_frame.client_data = output_frame_info->clientdata;
+	vcd_frame.alloc_len = output_frame_info->sz;
+
+	vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle, &vcd_frame);
+	if (vcd_status) {
+		ERR("%s: vcd_fill_output_buffer %u\n", __func__, vcd_status);
+		return false;
+	}
+	return true;
+}
diff --git a/drivers/misc/video_core/720p/enc/venc_internal.h b/drivers/misc/video_core/720p/enc/venc_internal.h
new file mode 100644
index 0000000..517783a
--- /dev/null
+++ b/drivers/misc/video_core/720p/enc/venc_internal.h
@@ -0,0 +1,160 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+
+#ifndef VENC_INTERNAL_H
+#define VENC_INTERNAL_H
+
+#include <linux/msm_vidc_enc.h>
+#include <linux/cdev.h>
+
+#include "video_core_init.h"
+
+#define VID_ENC_MAX_ENCODER_CLIENTS 16
+#define VID_ENC_MAX_NUM_OF_BUFF 100
+
+enum venc_buffer_dir {
+	VEN_BUFFER_TYPE_INPUT,
+	VEN_BUFFER_TYPE_OUTPUT
+};
+
+struct vid_enc_msg {
+	struct list_head list;
+	struct venc_msg venc_msg_info;
+};
+
+struct vid_enc_dev {
+
+	struct cdev cdev;
+	struct device *device;
+	resource_size_t phys_base;
+	void __iomem *virt_base;
+	unsigned int irq;
+	struct clk *hclk;
+	struct clk *hclk_div2;
+	struct clk *pclk;
+	unsigned long hclk_rate;
+	struct mutex lock;
+	s32 device_handle;
+	struct video_client_ctx venc_clients[VID_ENC_MAX_ENCODER_CLIENTS];
+	u32 num_clients;
+};
+
+u32 vid_enc_set_get_base_cfg(struct video_client_ctx *client_ctx,
+	struct venc_basecfg *base_config, u32 set_flag);
+
+u32 vid_enc_set_get_inputformat(struct video_client_ctx *client_ctx,
+	u32 *input_format, u32 set_flag);
+
+u32 vid_enc_set_get_codec(struct video_client_ctx *client_ctx, u32 *codec_type,
+	u32 set_flag);
+
+u32 vid_enc_set_get_framesize(struct video_client_ctx *client_ctx,
+	u32 *height, u32 *width, u32 set_flag);
+
+u32 vid_enc_set_get_bitrate(struct video_client_ctx *client_ctx,
+	struct venc_targetbitrate *venc_bitrate, u32 set_flag);
+
+u32 vid_enc_set_get_framerate(struct video_client_ctx *client_ctx,
+	struct venc_framerate *frame_rate, u32 set_flag);
+
+u32 vid_enc_set_get_live_mode(struct video_client_ctx *client_ctx,
+	struct venc_switch *encoder_switch, u32 set_flag);
+
+u32 vid_enc_set_get_short_header(struct video_client_ctx *client_ctx,
+	struct venc_switch *encoder_switch, u32 set_flag);
+
+u32 vid_enc_set_get_profile(struct video_client_ctx *client_ctx,
+	struct venc_profile *profile, u32 set_flag);
+
+u32 vid_enc_set_get_profile_level(struct video_client_ctx *client_ctx,
+	struct ven_profilelevel *profile_level, u32 set_flag);
+
+u32 vid_enc_set_get_session_qp(struct video_client_ctx *client_ctx,
+	struct venc_sessionqp *session_qp, u32 set_flag);
+
+u32 vid_enc_set_get_intraperiod(struct video_client_ctx *client_ctx,
+	struct venc_intraperiod *intraperiod, u32 set_flag);
+
+u32 vid_enc_request_iframe(struct video_client_ctx *client_ctx);
+
+u32 vid_enc_get_sequence_header(struct video_client_ctx *client_ctx,
+	struct venc_seqheader *seq_header);
+
+u32 vid_enc_set_get_entropy_cfg(struct video_client_ctx *client_ctx,
+	struct venc_entropycfg *entropy_cfg, u32 set_flag);
+
+u32 vid_enc_set_get_dbcfg(struct video_client_ctx *client_ctx,
+	struct venc_dbcfg *dbcfg, u32 set_flag);
+
+u32 vid_enc_set_get_intrarefresh(struct video_client_ctx *client_ctx,
+	struct venc_intrarefresh *intrarefresh,	u32 set_flag);
+
+u32 vid_enc_set_get_multiclicecfg(struct video_client_ctx *client_ctx,
+	struct venc_multiclicecfg *multiclicecfg, u32 set_flag);
+
+u32 vid_enc_set_get_ratectrlcfg(struct video_client_ctx *client_ctx,
+	struct venc_ratectrlcfg *ratectrlcfg, u32 set_flag);
+
+u32 vid_enc_set_get_voptimingcfg(struct video_client_ctx *client_ctx,
+	struct  venc_voptimingcfg *voptimingcfg, u32 set_flag);
+
+u32 vid_enc_set_get_headerextension(struct video_client_ctx *client_ctx,
+	struct venc_headerextension *headerextension, u32 set_flag);
+
+u32 vid_enc_set_get_qprange(struct video_client_ctx *client_ctx,
+	struct venc_qprange *qprange, u32 set_flag);
+
+u32 vid_enc_start(struct video_client_ctx *client_ctx);
+
+u32 vid_enc_stop(struct video_client_ctx *client_ctx);
+
+u32 vid_enc_pause(struct video_client_ctx *client_ctx);
+
+u32 vid_enc_resume(struct video_client_ctx *client_ctx);
+
+u32 vid_enc_flush(struct video_client_ctx *client_ctx,
+	struct venc_bufferflush *bufferflush);
+
+u32 vid_enc_get_buffer_req(struct video_client_ctx *client_ctx,
+	struct venc_allocatorproperty *venc_buf_req, u32 input_dir);
+
+u32 vid_enc_set_buffer_req(struct video_client_ctx *client_ctx,
+	struct venc_allocatorproperty *venc_buf_req, u32 input_dir);
+
+u32 vid_enc_set_buffer(struct video_client_ctx *client_ctx,
+	struct venc_bufferpayload *buffer_info,
+	enum venc_buffer_dir buffer_type);
+
+u32 vid_enc_encode_frame(struct video_client_ctx *client_ctx,
+	struct venc_buffer *input_frame_info);
+
+u32 vid_enc_fill_output_buffer(struct video_client_ctx *client_ctx,
+	struct venc_buffer *output_frame_info);
+
+#endif
diff --git a/drivers/misc/video_core/720p/init/video_core_init.c b/drivers/misc/video_core/720p/init/video_core_init.c
new file mode 100644
index 0000000..9af634c
--- /dev/null
+++ b/drivers/misc/video_core/720p/init/video_core_init.c
@@ -0,0 +1,766 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/android_pmem.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <mach/clk.h>
+
+#include "vcd_ddl_firmware.h"
+#include "vcd_api.h"
+#include "video_core_init_internal.h"
+#include "video_core_init.h"
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+#define VID_C_NAME "msm_vidc_reg"
+
+#define ERR(x...) printk(KERN_ERR x)
+
+static struct vid_c_dev *vidc_dev;
+static dev_t vidc_dev_num;
+static struct class *vidc_class;
+
+static const struct file_operations vid_c_fops = {
+	.owner = THIS_MODULE,
+	.open = NULL,
+	.release = NULL,
+	.ioctl = NULL,
+};
+
+struct workqueue_struct *vid_c_wq;
+struct workqueue_struct *vidc_timer_wq;
+static irqreturn_t vid_c_isr(int irq, void *dev);
+static spinlock_t vidc_spin_lock;
+
+
+static void vid_c_timer_fn(unsigned long data)
+{
+	unsigned long flag;
+	struct vid_c_timer *hw_timer = NULL;
+
+	DBG("%s: Timer expired\n", __func__);
+	spin_lock_irqsave(&vidc_spin_lock, flag);
+	hw_timer = (struct vid_c_timer *)data;
+	list_add_tail(&hw_timer->list, &vidc_dev->vidc_timer_queue);
+	spin_unlock_irqrestore(&vidc_spin_lock, flag);
+	DBG("Queue the work for timer\n");
+	queue_work(vidc_timer_wq, &vidc_dev->vidc_timer_worker);
+}
+
+static void vid_c_timer_handler(struct work_struct *work)
+{
+	unsigned long flag = 0;
+	u32 islist_empty = 0;
+	struct vid_c_timer *hw_timer = NULL;
+
+	DBG("%s: Timer expired\n", __func__);
+	do {
+		spin_lock_irqsave(&vidc_spin_lock, flag);
+		islist_empty = list_empty(&vidc_dev->vidc_timer_queue);
+		if (!islist_empty) {
+			hw_timer = list_first_entry(&vidc_dev->vidc_timer_queue,
+				struct vid_c_timer, list);
+			list_del(&hw_timer->list);
+		}
+		spin_unlock_irqrestore(&vidc_spin_lock, flag);
+		if (!islist_empty && hw_timer && hw_timer->cb_func)
+			hw_timer->cb_func(hw_timer->userdata);
+	} while (!islist_empty);
+}
+
+static void vid_c_work_handler(struct work_struct *work)
+{
+	DBG("vid_c_work_handler()");
+	vcd_read_and_clear_interrupt();
+	vcd_response_handler();
+	enable_irq(vidc_dev->irq);
+	DBG("vid_c_work_handler() done");
+}
+
+static DECLARE_WORK(vid_c_work, vid_c_work_handler);
+
+static int __init vid_c_720p_probe(struct platform_device *pdev)
+{
+	int rc;
+	struct resource *resource;
+	DBG("Enter %s\n", __func__);
+
+	if (pdev->id) {
+		ERR("Invalid platform device ID = %d\n", pdev->id);
+		return -EINVAL;
+	}
+	vidc_dev->irq = platform_get_irq(pdev, 0);
+	if (unlikely(vidc_dev->irq < 0)) {
+		ERR("%s: Invalid irq = %d\n", __func__, vidc_dev->irq);
+		return -ENXIO;
+	}
+
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!resource)) {
+		ERR("%s: Invalid resource\n", __func__);
+		return -ENXIO;
+	}
+
+	vidc_dev->phys_base = resource->start;
+	vidc_dev->virt_base = ioremap(resource->start,
+	resource->end - resource->start + 1);
+
+	if (!vidc_dev->virt_base) {
+		ERR("%s: ioremap failed\n", __func__);
+		return -ENOMEM;
+	}
+	vidc_dev->device = &pdev->dev;
+	mutex_init(&vidc_dev->lock);
+
+	vid_c_wq = create_singlethread_workqueue("vid_c_worker_queue");
+	if (!vid_c_wq) {
+		ERR("%s: create workqueue failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	rc = vcd_fw_init(vidc_dev->device);
+	if (rc)
+		ERR("%s: failed to prepare firmware %d\n", __func__, rc);
+
+	return rc;
+}
+
+static int __devexit vid_c_720p_remove(struct platform_device *pdev)
+{
+	if (pdev->id) {
+		ERR("Invalid plaform device ID = %d\n", pdev->id);
+		return -EINVAL;
+	}
+	vcd_fw_exit();
+	return 0;
+}
+
+static struct platform_driver msm_vid_c_720p_platform_driver = {
+	.probe = vid_c_720p_probe,
+	.remove = vid_c_720p_remove,
+	.driver = {
+		.name = "msm_vidc_720p",
+	},
+};
+
+static void __exit vid_c_exit(void)
+{
+	platform_driver_unregister(&msm_vid_c_720p_platform_driver);
+}
+
+static irqreturn_t vid_c_isr(int irq, void *dev)
+{
+	DBG("vid_c_isr() %d\n", irq);
+	disable_irq_nosync(irq);
+	queue_work(vid_c_wq, &vid_c_work);
+	return IRQ_HANDLED;
+}
+
+static int __init vid_c_init(void)
+{
+	int rc = 0;
+	struct device *class_devp;
+
+	vidc_dev = kzalloc(sizeof(struct vid_c_dev), GFP_KERNEL);
+	if (!vidc_dev) {
+		ERR("%s Unable to allocate memory for vid_c_dev\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	rc = alloc_chrdev_region(&vidc_dev_num, 0, 1, VID_C_NAME);
+	if (rc < 0) {
+		ERR("%s: alloc_chrdev_region failed %d\n", __func__, rc);
+		goto error_vid_c_alloc_chrdev_region;
+	}
+
+	vidc_class = class_create(THIS_MODULE, VID_C_NAME);
+	if (IS_ERR(vidc_class)) {
+		rc = PTR_ERR(vidc_class);
+		ERR("%s: couldn't create vid_c_class %d\n", __func__, rc);
+		goto error_vid_c_class_create;
+	}
+
+	class_devp = device_create(vidc_class, NULL, vidc_dev_num, NULL,
+					VID_C_NAME);
+
+	if (IS_ERR(class_devp)) {
+		rc = PTR_ERR(class_devp);
+		ERR("%s: class device_create failed %d\n", __func__, rc);
+		goto error_vid_c_class_device_create;
+	}
+
+	cdev_init(&vidc_dev->cdev, &vid_c_fops);
+	vidc_dev->cdev.owner = THIS_MODULE;
+	rc = cdev_add(&(vidc_dev->cdev), vidc_dev_num, 1);
+
+	if (rc < 0) {
+		ERR("%s: cdev_add failed %d\n", __func__, rc);
+		goto error_vid_c_cdev_add;
+	}
+
+	rc = platform_driver_register(&msm_vid_c_720p_platform_driver);
+	if (rc) {
+		ERR("%s failed to load\n", __func__);
+		goto error_vid_c_platfom_register;
+	}
+
+	rc = request_irq(vidc_dev->irq, vid_c_isr, IRQF_TRIGGER_HIGH,
+			 "vid_c", vidc_dev->device);
+	if (unlikely(rc)) {
+		ERR("%s:request_irq failed\n", __func__);
+		goto error_vid_c_platfom_register;
+	}
+
+	vidc_timer_wq = create_singlethread_workqueue("vidc_timer_wq");
+	if (!vidc_timer_wq) {
+		ERR("%s: create workqueue failed\n", __func__);
+		rc = -ENOMEM;
+		goto error_vid_c_platfom_register;
+	}
+
+	DBG("Disabling IRQ in %s\n", __func__);
+	disable_irq_nosync(vidc_dev->irq);
+	INIT_WORK(&vidc_dev->vidc_timer_worker, vid_c_timer_handler);
+	spin_lock_init(&vidc_spin_lock);
+	INIT_LIST_HEAD(&vidc_dev->vidc_timer_queue);
+	vidc_dev->clock_enabled = 0;
+	vidc_dev->ref_count = 0;
+	vidc_dev->firmware_refcount = 0;
+	vidc_dev->get_firmware = 0;
+
+	return 0;
+
+error_vid_c_platfom_register:
+	cdev_del(&(vidc_dev->cdev));
+error_vid_c_cdev_add:
+	device_destroy(vidc_class, vidc_dev_num);
+error_vid_c_class_device_create:
+	class_destroy(vidc_class);
+error_vid_c_class_create:
+	unregister_chrdev_region(vidc_dev_num, 1);
+error_vid_c_alloc_chrdev_region:
+	kfree(vidc_dev);
+
+	return rc;
+}
+
+void __iomem *vid_c_get_ioaddr()
+{
+	return vidc_dev->virt_base;
+}
+EXPORT_SYMBOL(vid_c_get_ioaddr);
+#ifdef USE_RES_TRACKER
+
+u32 vid_c_enable_pwr_rail()
+{
+	int rc;
+
+	mutex_lock(&vidc_dev->lock);
+
+	if (vidc_dev->rail_enabled) {
+		mutex_unlock(&vidc_dev->lock);
+		return true;
+	}
+
+	//TODO: internal_pwr_rail_mode(MFC_CLK_ID, MANUAL)
+
+	vidc_dev->pclk = clk_get(vidc_dev->device, "mfc_pclk");
+	if (IS_ERR(vidc_dev->pclk)) {
+		ERR("%s: mfc_pclk get failed\n", __func__);
+		goto err;
+	}
+
+	vidc_dev->hclk = clk_get(vidc_dev->device, "mfc_clk");
+	if (IS_ERR(vidc_dev->hclk)) {
+		ERR("%s: mfc_clk get failed\n", __func__);
+		goto err;
+	}
+
+	vidc_dev->hclk_div2 = clk_get(vidc_dev->device, "mfc_div2_clk");
+	if (IS_ERR(vidc_dev->hclk_div2)) {
+		ERR("%s: mfc_div2_clk get failed\n", __func__);
+		goto err;
+	}
+
+	//TODO: internal_pwr_rail_ctl(MFC_CLK_ID, 1)
+
+	//TODO msleep must die
+	msleep(20);
+
+	rc = clk_reset(vidc_dev->pclk, CLK_RESET_DEASSERT);
+	if (rc) {
+		ERR("clk_reset failed %d\n", rc);
+		goto err;
+	}
+	//TODO msleep must die
+	msleep(20);
+
+	vidc_dev->rail_enabled = 1;
+	mutex_unlock(&vidc_dev->lock);
+	return true;
+
+err:
+	if (!IS_ERR(vidc_dev->pclk))
+		clk_put(vidc_dev->pclk);
+	if (!IS_ERR(vidc_dev->hclk))
+		clk_put(vidc_dev->hclk);
+	if (!IS_ERR(vidc_dev->hclk_div2))
+		clk_put(vidc_dev->hclk_div2);
+	mutex_unlock(&vidc_dev->lock);
+	return false;
+}
+EXPORT_SYMBOL(vid_c_enable_pwr_rail);
+
+u32 vid_c_disable_pwr_rail()
+{
+	int rc = -1;
+	mutex_lock(&vidc_dev->lock);
+
+	if (vidc_dev->clock_enabled) {
+		mutex_unlock(&vidc_dev->lock);
+		DBG("Calling CLK disable in power down\n");
+		vid_c_disable_clk();
+		mutex_lock(&vidc_dev->lock);
+	}
+
+	if (!vidc_dev->rail_enabled) {
+		mutex_unlock(&vidc_dev->lock);
+		return false;
+	}
+
+	vidc_dev->rail_enabled = 0;
+	rc = clk_reset(vidc_dev->pclk, CLK_RESET_ASSERT);
+	if (rc) {
+		ERR("clk_reset failed %d\n", rc);
+		mutex_unlock(&vidc_dev->lock);
+		return false;
+	}
+	msleep(20);
+
+	//TODO: internal_pwr_rail_ctl(MFC_CLK_ID, 0)
+
+	clk_put(vidc_dev->hclk_div2);
+	clk_put(vidc_dev->hclk);
+	clk_put(vidc_dev->pclk);
+
+	mutex_unlock(&vidc_dev->lock);
+
+	return true;
+}
+EXPORT_SYMBOL(vid_c_disable_pwr_rail);
+
+u32 vid_c_enable_clk()
+{
+	mutex_lock(&vidc_dev->lock);
+
+	if (!vidc_dev->rail_enabled) {
+		goto err;
+	}
+	if (vidc_dev->clock_enabled) {
+		mutex_unlock(&vidc_dev->lock);
+		return true;
+	}
+
+	DBG("Enabling IRQ in %s\n", __func__);
+	enable_irq(vidc_dev->irq);
+	DBG("%s: Enabling the clocks ...\n", __func__);
+
+	if (clk_enable(vidc_dev->pclk)) {
+		ERR("vidc pclk enable failed\n");
+		goto err;
+	}
+
+	if (clk_enable(vidc_dev->hclk)) {
+		ERR("vidc hclk enable failed\n");
+		goto err;
+	}
+
+	if (clk_enable(vidc_dev->hclk_div2)) {
+		ERR("vidc hclk_div2 enable failed\n");
+		goto err;
+	}
+
+	vidc_dev->clock_enabled = 1;
+	mutex_unlock(&vidc_dev->lock);
+	return true;
+err:
+	mutex_unlock(&vidc_dev->lock);
+	return false;
+}
+EXPORT_SYMBOL(vid_c_enable_clk);
+
+u32 vid_c_sel_clk_rate(unsigned long hclk_rate)
+{
+	mutex_lock(&vidc_dev->lock);
+	if (clk_set_rate(vidc_dev->hclk, hclk_rate)) {
+		ERR("vidc hclk set rate failed\n");
+		mutex_unlock(&vidc_dev->lock);
+		return false;
+	}
+	vidc_dev->hclk_rate = hclk_rate;
+	mutex_unlock(&vidc_dev->lock);
+	return true;
+}
+EXPORT_SYMBOL(vid_c_sel_clk_rate);
+
+u32 vid_c_get_clk_rate(unsigned long *phclk_rate)
+{
+	if (!phclk_rate) {
+		ERR("vid_c_get_clk_rate(): phclk_rate is NULL\n");
+		return false;
+	}
+	mutex_lock(&vidc_dev->lock);
+	*phclk_rate = clk_get_rate(vidc_dev->hclk);
+	if (!(*phclk_rate)) {
+		ERR("vidc hclk get rate failed\n");
+		mutex_unlock(&vidc_dev->lock);
+		return false;
+	}
+	mutex_unlock(&vidc_dev->lock);
+	return true;
+}
+EXPORT_SYMBOL(vid_c_get_clk_rate);
+
+u32 vid_c_disable_clk(void)
+{
+	mutex_lock(&vidc_dev->lock);
+
+	if (!vidc_dev->clock_enabled) {
+		mutex_unlock(&vidc_dev->lock);
+		return false;
+	}
+
+	DBG("Disabling IRQ in %s\n", __func__);
+	disable_irq_nosync(vidc_dev->irq);
+	DBG("%s: Disabling the clocks ...\n", __func__);
+
+	vidc_dev->clock_enabled = 0;
+	clk_disable(vidc_dev->hclk);
+	clk_disable(vidc_dev->hclk_div2);
+	clk_disable(vidc_dev->pclk);
+
+	mutex_unlock(&vidc_dev->lock);
+
+	return true;
+}
+EXPORT_SYMBOL(vid_c_disable_clk);
+
+//TODO: consider deleting USE_RES_TRACKER
+#else
+
+u32 vid_c_enable_clk(unsigned long hclk_rate)
+{
+	int rc = -1;
+	mutex_lock(&vidc_dev->lock);
+	vidc_dev->ref_count++;
+
+	if (!vidc_dev->clock_enabled) {
+		DBG("Enabling IRQ in %s()\n", __func__);
+		enable_irq(vidc_dev->irq);
+
+		rc = internal_pwr_rail_mode
+			(PWR_RAIL_MFC_CLK, PWR_RAIL_CTL_MANUAL);
+		if (rc) {
+			ERR("%s(): internal_pwr_rail_mode failed %d\n",
+			__func__, rc);
+			return false;
+		}
+		DBG("%s(): internal_pwr_rail_mode Success %d\n",
+		__func__, rc);
+
+		vidc_dev->pclk =
+			clk_get(vidc_dev->device, "mfc_pclk");
+
+		if (IS_ERR(vidc_dev->pclk)) {
+			ERR("%s(): mfc_pclk get failed\n", __func__);
+
+			mutex_unlock(&vidc_dev->lock);
+			return false;
+		}
+
+		vidc_dev->hclk =
+			clk_get(vidc_dev->device, "mfc_clk");
+
+		if (IS_ERR(vidc_dev->hclk)) {
+			ERR("%s(): mfc_clk get failed\n", __func__);
+
+			clk_put(vidc_dev->pclk);
+			mutex_unlock(&vidc_dev->lock);
+			return false;
+		}
+
+		vidc_dev->hclk_div2 =
+			clk_get(vidc_dev->device, "mfc_div2_clk");
+
+		if (IS_ERR(vidc_dev->pclk)) {
+			ERR("%s(): mfc_div2_clk get failed\n", __func__);
+
+			clk_put(vidc_dev->pclk);
+			clk_put(vidc_dev->hclk);
+			mutex_unlock(&vidc_dev->lock);
+			return false;
+		}
+
+		vidc_dev->hclk_rate = hclk_rate;
+
+		if (clk_set_rate(vidc_dev->hclk,
+			vidc_dev->hclk_rate)) {
+			ERR("vid_c hclk set rate failed\n");
+			clk_put(vidc_dev->pclk);
+			clk_put(vidc_dev->hclk);
+			clk_put(vidc_dev->hclk_div2);
+			mutex_unlock(&vidc_dev->lock);
+			return false;
+		}
+
+		if (clk_enable(vidc_dev->pclk)) {
+			ERR("vid_c pclk Enable failed\n");
+
+			clk_put(vidc_dev->hclk);
+			clk_put(vidc_dev->hclk_div2);
+			mutex_unlock(&vidc_dev->lock);
+			return false;
+		}
+
+		if (clk_enable(vidc_dev->hclk)) {
+			ERR("vid_c  hclk Enable failed\n");
+			clk_put(vidc_dev->pclk);
+			clk_put(vidc_dev->hclk_div2);
+			mutex_unlock(&vidc_dev->lock);
+			return false;
+		}
+
+		if (clk_enable(vidc_dev->hclk_div2)) {
+			ERR("vid_c  hclk Enable failed\n");
+			clk_put(vidc_dev->hclk);
+			clk_put(vidc_dev->pclk);
+			mutex_unlock(&vidc_dev->lock);
+			return false;
+		}
+		msleep(20);
+		rc = internal_pwr_rail_ctl(PWR_RAIL_MFC_CLK, 1);
+		if (rc) {
+			ERR("\n internal_pwr_rail_ctl failed %d\n", rc);
+			return false;
+		}
+		DBG("%s(): internal_pwr_rail_ctl Success %d\n",
+			__func__, rc);
+		msleep(20);
+		rc = clk_reset(vidc_dev->pclk, CLK_RESET_DEASSERT);
+		if (rc) {
+			ERR("\n clk_reset failed %d\n", rc);
+			return false;
+		}
+		msleep(20);
+	}
+	vidc_dev->clock_enabled = 1;
+	mutex_unlock(&vidc_dev->lock);
+	return true;
+}
+EXPORT_SYMBOL(vid_c_enable_clk);
+
+u32 vid_c_disable_clk(void)
+{
+	int rc = -1;
+	mutex_lock(&vidc_dev->lock);
+
+	if (!vidc_dev->ref_count ||
+		!vidc_dev->clock_enabled) {
+		return false;
+	}
+
+	if (vidc_dev->ref_count > 0)
+		vidc_dev->ref_count--;
+
+	if (!vidc_dev->ref_count) {
+		DBG("Disabling IRQ in %s()\n", __func__);
+		disable_irq_nosync(vidc_dev->irq);
+		rc = clk_reset(vidc_dev->pclk, CLK_RESET_ASSERT);
+		if (rc) {
+			ERR("\n clk_reset failed %d\n", rc);
+			return false;
+		}
+		msleep(20);
+
+		rc = internal_pwr_rail_ctl(PWR_RAIL_MFC_CLK, 0);
+		if (rc) {
+			ERR("\n internal_pwr_rail_ctl failed %d\n", rc);
+			return false;
+		}
+
+		vidc_dev->clock_enabled = 0;
+		clk_disable(vidc_dev->hclk);
+		clk_disable(vidc_dev->hclk_div2);
+		clk_disable(vidc_dev->pclk);
+
+		clk_put(vidc_dev->hclk_div2);
+		clk_put(vidc_dev->hclk);
+		clk_put(vidc_dev->pclk);
+
+	}
+	mutex_unlock(&vidc_dev->lock);
+	return true;
+}
+EXPORT_SYMBOL(vid_c_disable_clk);
+
+#endif
+
+u32 vid_c_lookup_addr_table(struct video_client_ctx *client_ctx,
+	enum buffer_dir buffer_type, u32 search_with_user_vaddr,
+	void __user **user_addr, void **kern_addr, phys_addr_t *phys_addr,
+	int *pmem_fd, struct file **file, s32 *buffer_index)
+{
+	u32 num_of_buffers;
+	u32 i;
+	struct buf_addr_table *buf_addr_table;
+	u32 found = false;
+
+	if (!client_ctx)
+		return false;
+
+	if (buffer_type == BUFFER_TYPE_INPUT) {
+		buf_addr_table = client_ctx->input_buf_addr_table;
+		num_of_buffers = client_ctx->num_of_input_buffers;
+		DBG("%s: buffer_type = INPUT\n", __func__);
+	} else {
+		buf_addr_table = client_ctx->output_buf_addr_table;
+		num_of_buffers = client_ctx->num_of_output_buffers;
+		DBG("%s: buffer_type = OUTPUT\n", __func__);
+	}
+
+	for (i = 0; i < num_of_buffers; ++i) {
+		if (search_with_user_vaddr) {
+			if (*user_addr == buf_addr_table[i].user_addr) {
+				*kern_addr = buf_addr_table[i].kern_addr;
+				found = true;
+				DBG("%s: client_ctx=%p user_addr=%p is found\n",
+					__func__, client_ctx, *user_addr);
+				break;
+			}
+		} else {
+			if (*kern_addr == buf_addr_table[i].kern_addr) {
+				*user_addr = buf_addr_table[i].user_addr;
+				found = true;
+				DBG("%s: client_ctx=%p kern_addr=%p is found",
+					__func__, client_ctx, *kern_addr);
+				break;
+			}
+		}
+	}
+
+	if (!found) {
+		if (search_with_user_vaddr)
+			DBG("%s: client_ctx=%p user_addr=%p not found\n",
+				__func__, client_ctx, *user_addr);
+		else
+			DBG("%s: client_ctx=%p kern_addr=%p not found\n",
+				__func__, client_ctx, *kern_addr);
+		return false;
+	}
+
+	*phys_addr = buf_addr_table[i].phys_addr;
+	*pmem_fd = buf_addr_table[i].pmem_fd;
+	*file = buf_addr_table[i].file;
+	*buffer_index = i;
+
+	if (search_with_user_vaddr)
+		DBG("kern_addr=%p phys_addr=%X pmem_fd=%d "
+			"struct *file=%p buffer_index=%d\n", *kern_addr,
+			*phys_addr, *pmem_fd, *file, *buffer_index);
+	else
+		DBG("user_addr=%p phys_addr=%X pmem_fd=%d, "
+			"struct *file=%p buffer_index=%d\n", *user_addr,
+			*phys_addr, *pmem_fd, *file, *buffer_index);
+	return true;
+}
+EXPORT_SYMBOL(vid_c_lookup_addr_table);
+
+u32 vid_c_timer_create(void (*pf_timer_handler)(void *), void *user_data,
+	void **pp_timer_handle)
+{
+	struct vid_c_timer *hw_timer = NULL;
+	if (!pf_timer_handler || !pp_timer_handle) {
+		DBG("%s: timer creation failed\n", __func__);
+		return false;
+	}
+	hw_timer = kzalloc(sizeof(struct vid_c_timer), GFP_KERNEL);
+	if (!hw_timer) {
+		DBG("%s: timer creation failed in allocation\n", __func__);
+		return false;
+	}
+	init_timer(&hw_timer->hw_timeout);
+	hw_timer->hw_timeout.data = (unsigned long)hw_timer;
+	hw_timer->hw_timeout.function = vid_c_timer_fn;
+	hw_timer->cb_func = pf_timer_handler;
+	hw_timer->userdata = user_data;
+	*pp_timer_handle = hw_timer;
+	return true;
+}
+EXPORT_SYMBOL(vid_c_timer_create);
+
+void  vid_c_timer_release(void *timer_handle)
+{
+	kfree(timer_handle);
+}
+EXPORT_SYMBOL(vid_c_timer_release);
+
+void  vid_c_timer_start(void *timer_handle, u32 time_out)
+{
+	struct vid_c_timer *hw_timer = timer_handle;
+	DBG("%s: start timer\n ", __func__);
+	if (hw_timer) {
+		hw_timer->hw_timeout.expires = jiffies + 1 * HZ;
+		add_timer(&hw_timer->hw_timeout);
+	}
+}
+EXPORT_SYMBOL(vid_c_timer_start);
+
+void  vid_c_timer_stop(void *timer_handle)
+{
+	struct vid_c_timer *hw_timer = timer_handle;
+	DBG("%s: stop timer\n ", __func__);
+	if (hw_timer)
+		del_timer(&hw_timer->hw_timeout);
+}
+EXPORT_SYMBOL(vid_c_timer_stop);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Video decoder/encoder driver Init Module");
+MODULE_VERSION("1.0");
+module_init(vid_c_init);
+module_exit(vid_c_exit);
diff --git a/drivers/misc/video_core/720p/init/video_core_init.h b/drivers/misc/video_core/720p/init/video_core_init.h
new file mode 100644
index 0000000..d8e40f3
--- /dev/null
+++ b/drivers/misc/video_core/720p/init/video_core_init.h
@@ -0,0 +1,95 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+
+#ifndef VIDEO_CORE_INIT_H
+#define VIDEO_CORE_INIT_H
+
+#include "video_core_type.h"
+
+#define MAX_VIDEO_NUM_OF_BUFF 100
+
+enum buffer_dir {
+	BUFFER_TYPE_INPUT,
+	BUFFER_TYPE_OUTPUT
+};
+
+struct buf_addr_table {
+	void __user *user_addr;
+	void *kern_addr;
+	phys_addr_t phys_addr;
+	int pmem_fd;
+	struct file *file;
+};
+
+struct video_client_ctx {
+	void *vcd_handle;
+	u32 num_of_input_buffers;
+	u32 num_of_output_buffers;
+	struct buf_addr_table input_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
+	struct buf_addr_table output_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
+	struct list_head msg_queue;
+	struct mutex msg_queue_lock;
+	wait_queue_head_t msg_wait;
+	struct completion event;
+	u32 event_status;
+	u32 seq_header_set;
+	u32 stop_msg;
+};
+
+void __iomem *vid_c_get_ioaddr(void);
+
+#ifdef USE_RES_TRACKER
+
+u32 vid_c_sel_clk_rate(unsigned long hclk_rate);
+u32 vid_c_get_clk_rate(unsigned long *phclk_rate);
+u32 vid_c_enable_clk(void);
+u32 vid_c_disable_clk(void);
+u32 vid_c_enable_pwr_rail(void);
+u32 vid_c_disable_pwr_rail(void);
+
+#else
+u32 vid_c_enable_clk(unsigned long hclk_rate);
+u32 vid_c_disable_clk(void);
+#endif
+
+int vid_c_load_firmware(void);
+void vid_c_release_firmware(void);
+u32 vid_c_lookup_addr_table(struct video_client_ctx *client_ctx,
+	enum buffer_dir buffer_type, u32 search_with_user_vaddr,
+	void __user **user_addr, void **kernel_addr, phys_addr_t *phys_addr,
+	int *pmem_fd, struct file **file, s32 *buffer_index);
+
+u32 vid_c_timer_create(void (*pf_timer_handler)(void *),
+	void *user_data, void **pp_timer_handle);
+void  vid_c_timer_release(void *timer_handle);
+void  vid_c_timer_start(void *timer_handle, u32 time_out);
+void  vid_c_timer_stop(void *timer_handle);
+
+
+#endif
diff --git a/drivers/misc/video_core/720p/init/video_core_init_internal.h b/drivers/misc/video_core/720p/init/video_core_init_internal.h
new file mode 100644
index 0000000..b72e9f2
--- /dev/null
+++ b/drivers/misc/video_core/720p/init/video_core_init_internal.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+
+#ifndef VIDEO_CORE_INIT_INTERNAL_H
+#define VIDEO_CORE_INIT_INTERNAL_H
+
+#include <linux/cdev.h>
+
+struct vid_c_timer {
+	struct list_head list;
+	struct timer_list hw_timeout;
+	void (*cb_func)(void *);
+	void *userdata;
+};
+
+struct vid_c_dev {
+	struct cdev cdev;
+	struct device *device;
+	resource_size_t phys_base;
+	void __iomem *virt_base;
+	unsigned int irq;
+	struct clk *hclk;
+	struct clk *hclk_div2;
+	struct clk *pclk;
+	unsigned long hclk_rate;
+	unsigned int clock_enabled;
+	unsigned int rail_enabled;
+	unsigned int ref_count;
+	unsigned int firmware_refcount;
+	unsigned int get_firmware;
+	struct mutex lock;
+	s32 device_handle;
+	struct list_head vidc_timer_queue;
+	struct work_struct vidc_timer_worker;
+};
+
+#endif
diff --git a/drivers/misc/video_core/720p/resource_tracker/vcd_res_tracker.c b/drivers/misc/video_core/720p/resource_tracker/vcd_res_tracker.c
new file mode 100644
index 0000000..7ad199b
--- /dev/null
+++ b/drivers/misc/video_core/720p/resource_tracker/vcd_res_tracker.c
@@ -0,0 +1,275 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vcd_res_tracker.h"
+#include "video_core_init.h"
+
+#include <linux/pm_qos_params.h>
+#ifdef AXI_CLK_SCALING
+#include <mach/msm_reqs.h>
+#endif
+
+#define MSM_AXI_QOS_NAME "msm_vidc_reg"
+
+#define QVGA_PERF_LEVEL (300 * 30)
+#define VGA_PERF_LEVEL (1200 * 30)
+#define WVGA_PERF_LEVEL (1500 * 30)
+
+static unsigned int mfc_clk_freq_table[3] = {
+	61440000, 122880000, 170667000
+};
+
+#ifndef CONFIG_MSM_NPA_SYSTEM_BUS
+static unsigned int axi_clk_freq_table_enc[2] = {
+	122880, 192000
+};
+static unsigned int axi_clk_freq_table_dec[2] = {
+	122880, 192000
+};
+#else
+static unsigned int axi_clk_freq_table_enc[2] = {
+	MSM_AXI_FLOW_VIDEO_RECORDING_720P,
+	MSM_AXI_FLOW_VIDEO_RECORDING_720P
+};
+static unsigned int axi_clk_freq_table_dec[2] = {
+	MSM_AXI_FLOW_VIDEO_PLAYBACK_720P,
+	MSM_AXI_FLOW_VIDEO_PLAYBACK_720P
+};
+#endif
+static u32 res_trk_convert_freq_to_perf_lvl(u64 freq)
+{
+	u64 perf_lvl;
+	u64 temp;
+
+	pr_debug("\n %s():: freq = %u\n", __func__, (u32)freq);
+
+	if (!freq)
+		return 0;
+
+	temp = freq * 1000;
+	do_div(temp, VCD_RESTRK_HZ_PER_1000_PERFLVL);
+	perf_lvl = (u32)temp;
+	pr_debug("\n %s(): perf_lvl = %u\n", __func__, (u32)perf_lvl);
+
+	return (u32)perf_lvl;
+}
+
+static u32 res_trk_convert_perf_lvl_to_freq(u64 perf_lvl)
+{
+	u64 freq, temp;
+
+	pr_debug("\n %s():: perf_lvl = %u\n", __func__,
+		(u32)perf_lvl);
+	temp = (perf_lvl * VCD_RESTRK_HZ_PER_1000_PERFLVL) + 999;
+	do_div(temp, 1000);
+	freq = (u32)temp;
+	pr_debug("\n %s(): freq = %u\n", __func__, (u32)freq);
+
+	return (u32)freq;
+}
+
+u32 res_trk_power_up(void)
+{
+	pr_debug("clk_regime_rail_enable\n");
+	pr_debug("clk_regime_sel_rail_control\n");
+#ifdef AXI_CLK_SCALING
+{
+	int rc;
+	pr_debug("\n res_trk_power_up():: "
+		"Calling AXI add requirement\n");
+	rc = pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ,
+		MSM_AXI_QOS_NAME, PM_QOS_DEFAULT_VALUE);
+	if (rc < 0)	{
+		pr_err("Request AXI bus QOS fails. rc = %d\n", rc);
+		return false;
+	}
+}
+#endif
+
+#ifdef USE_RES_TRACKER
+	pr_debug("\n res_trk_power_up():: Calling "
+		"vid_c_enable_pwr_rail()\n");
+	return vid_c_enable_pwr_rail();
+#endif
+	return true;
+}
+
+u32 res_trk_power_down(void)
+{
+	pr_debug("clk_regime_rail_disable\n");
+#ifdef AXI_CLK_SCALING
+	pr_debug("\n res_trk_power_down()::"
+		"Calling AXI remove requirement\n");
+	pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ,
+		MSM_AXI_QOS_NAME);
+#endif
+
+#ifdef USE_RES_TRACKER
+	pr_debug("\n res_trk_power_down():: Calling "
+		"vid_c_disable_pwr_rail()\n");
+	return vid_c_disable_pwr_rail();
+#endif
+	return true;
+}
+
+u32 res_trk_enable_clocks(void)
+{
+	pr_debug("clk_regime_msm_enable\n");
+#ifdef USE_RES_TRACKER
+	pr_debug("\n res_trk_enable_clocks():: Calling "
+		"vid_c_enable_clk()\n");
+	return vid_c_enable_clk();
+#endif
+	return true;
+}
+
+u32 res_trk_disable_clocks(void)
+{
+	pr_debug("clk_regime_msm_disable\n");
+
+#ifdef USE_RES_TRACKER
+	pr_debug("\n res_trk_disable_clocks():: Calling "
+		"vid_c_disable_clk()\n");
+	return vid_c_disable_clk();
+#endif
+	return true;
+}
+
+u32 res_trk_get_max_perf_level(u32 *pn_max_perf_lvl)
+{
+	if (!pn_max_perf_lvl) {
+		pr_err("%s(): pn_max_perf_lvl is NULL\n", __func__);
+		return false;
+	}
+
+	*pn_max_perf_lvl = VCD_RESTRK_MAX_PERF_LEVEL;
+	return true;
+}
+
+u32 res_trk_set_perf_level(u32 req_perf_lvl, u32 *pn_set_perf_lvl,
+	struct vcd_clnt_ctxt *cctxt)
+{
+	u32 axi_freq = 0, mfc_freq = 0, calc_mfc_freq = 0;
+
+	if (!pn_set_perf_lvl) {
+		pr_err("%s(): pn_perf_lvl is NULL\n", __func__);
+		return false;
+	}
+
+	pr_debug("%s(), req_perf_lvl = %d\n", __func__, req_perf_lvl);
+	if (cctxt) {
+		calc_mfc_freq = res_trk_convert_perf_lvl_to_freq(
+			(u64)req_perf_lvl);
+
+		if (calc_mfc_freq < VCD_RESTRK_MIN_FREQ_POINT)
+			calc_mfc_freq = VCD_RESTRK_MIN_FREQ_POINT;
+		else if (calc_mfc_freq > VCD_RESTRK_MAX_FREQ_POINT)
+			calc_mfc_freq = VCD_RESTRK_MAX_FREQ_POINT;
+
+		if (!cctxt->decoding) {
+			if (req_perf_lvl >= VGA_PERF_LEVEL) {
+				mfc_freq = mfc_clk_freq_table[2];
+				axi_freq = axi_clk_freq_table_enc[1];
+			} else {
+				mfc_freq = mfc_clk_freq_table[0];
+				axi_freq = axi_clk_freq_table_enc[0];
+			}
+			pr_debug("\n ENCODER: axi_freq = %u"
+				", mfc_freq = %u, calc_mfc_freq = %u,"
+				" req_perf_lvl = %u", axi_freq,
+				mfc_freq, calc_mfc_freq,
+				req_perf_lvl);
+		} else {
+			if (req_perf_lvl <= QVGA_PERF_LEVEL) {
+				mfc_freq = mfc_clk_freq_table[0];
+				axi_freq = axi_clk_freq_table_dec[0];
+			} else {
+				axi_freq = axi_clk_freq_table_dec[0];
+				if (req_perf_lvl <= VGA_PERF_LEVEL)
+					mfc_freq = mfc_clk_freq_table[0];
+				else if (req_perf_lvl <= WVGA_PERF_LEVEL)
+					mfc_freq = mfc_clk_freq_table[1];
+				else {
+					mfc_freq = mfc_clk_freq_table[2];
+					axi_freq = axi_clk_freq_table_dec[1];
+				}
+			}
+			pr_debug("\n DECODER: axi_freq = %u"
+				", mfc_freq = %u, calc_mfc_freq = %u,"
+				" req_perf_lvl = %u", axi_freq,
+				mfc_freq, calc_mfc_freq,
+				req_perf_lvl);
+		}
+	} else {
+		pr_debug("%s() WARNING:: cctxt is NULL\n", __func__);
+		return true;
+	}
+
+#ifdef AXI_CLK_SCALING
+	if (req_perf_lvl != VCD_RESTRK_MIN_PERF_LEVEL) {
+		int rc = -1;
+		pr_debug("\n %s(): Setting AXI freq to %u",
+			__func__, axi_freq);
+		rc = pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ,
+			MSM_AXI_QOS_NAME, axi_freq);
+
+		if (rc < 0) {
+			pr_err("\n Update AXI bus QOS fails,rc = %d\n", rc);
+			return false;
+		}
+	}
+#endif
+
+#ifdef USE_RES_TRACKER
+	if (req_perf_lvl != VCD_RESTRK_MIN_PERF_LEVEL) {
+		pr_debug("\n %s(): Setting MFC freq to %u",
+			__func__, mfc_freq);
+		if (!vid_c_sel_clk_rate(mfc_freq)) {
+			pr_err("%s(): vid_c_sel_clk_rate FAILED\n", __func__);
+			*pn_set_perf_lvl = 0;
+			return false;
+		}
+	}
+#endif
+
+	*pn_set_perf_lvl =
+	    res_trk_convert_freq_to_perf_lvl((u64) mfc_freq);
+	return true;
+}
+
+u32 res_trk_get_curr_perf_level(u32 *pn_perf_lvl)
+{
+	unsigned long freq;
+
+	if (!pn_perf_lvl) {
+		pr_err("%s(): pn_perf_lvl is NULL\n", __func__);
+		return false;
+	}
+	pr_debug("clk_regime_msm_get_clk_freq_hz\n");
+	if (!vid_c_get_clk_rate(&freq)) {
+		pr_err("%s(): vid_c_get_clk_rate FAILED\n", __func__);
+		*pn_perf_lvl = 0;
+		return false;
+	}
+
+	*pn_perf_lvl = res_trk_convert_freq_to_perf_lvl((u64) freq);
+	pr_debug("%s(): freq = %lu, *pn_perf_lvl = %u\n", __func__,
+		freq, *pn_perf_lvl);
+	return true;
+}
diff --git a/drivers/misc/video_core/720p/resource_tracker/vcd_res_tracker.h b/drivers/misc/video_core/720p/resource_tracker/vcd_res_tracker.h
new file mode 100644
index 0000000..f937e79
--- /dev/null
+++ b/drivers/misc/video_core/720p/resource_tracker/vcd_res_tracker.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VIDEO_720P_RESOURCE_TRACKER_H_
+#define _VIDEO_720P_RESOURCE_TRACKER_H_
+
+#include "vcd_res_tracker_api.h"
+
+#define VCD_RESTRK_MIN_PERF_LEVEL 37900
+#define VCD_RESTRK_MAX_PERF_LEVEL 108000
+#define VCD_RESTRK_MIN_FREQ_POINT 61440000
+#define VCD_RESTRK_MAX_FREQ_POINT 170667000
+#define VCD_RESTRK_HZ_PER_1000_PERFLVL 1580250
+
+#endif
diff --git a/drivers/misc/video_core/720p/resource_tracker/vcd_res_tracker_api.h b/drivers/misc/video_core/720p/resource_tracker/vcd_res_tracker_api.h
new file mode 100644
index 0000000..b099d09
--- /dev/null
+++ b/drivers/misc/video_core/720p/resource_tracker/vcd_res_tracker_api.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VIDEO_720P_RESOURCE_TRACKER_API_H_
+#define _VIDEO_720P_RESOURCE_TRACKER_API_H_
+
+#include "vcd_core.h"
+
+u32 res_trk_power_up(void);
+u32 res_trk_power_down(void);
+u32 res_trk_enable_clocks(void);
+u32 res_trk_disable_clocks(void);
+u32 res_trk_get_max_perf_level(u32 *pn_max_perf_lvl);
+u32 res_trk_set_perf_level(u32 req_perf_lvl, u32 *pn_set_perf_lvl,
+	struct vcd_clnt_ctxt *cctxt);
+u32 res_trk_get_curr_perf_level(u32 *pn_perf_lvl);
+
+#endif
diff --git a/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler.c b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler.c
new file mode 100644
index 0000000..169f082
--- /dev/null
+++ b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler.c
@@ -0,0 +1,1247 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+
+#include "vid_frame_scheduler_api.h"
+#include "vid_frame_scheduler.h"
+
+static const u32 SCHED_TKNBKT_SIZE_FACTOR = 5;
+static const u32 SCHED_TKNBKT_FILL_NORMLZ_SCALE = 100;
+static const u32 SCHED_TIME_MAX = 0xffffffff;
+
+
+SCHED_INLINE u32 SCHED_SUCCEEDED(enum sched_status status)
+{
+	SCHED_MSG_LOW("SCHED_SUCCEEDED check: status = %d", status);
+
+	if (status == SCHED_S_OK)
+		return true;
+	else
+		return false;
+
+}
+
+SCHED_INLINE u32 SCHED_FAILED(enum sched_status status)
+{
+	SCHED_MSG_LOW("SCHED_FAILED check: status = %d", status);
+
+	if (status >= SCHED_S_EFAIL)
+		return true;
+	else
+		return false;
+
+}
+
+static void sched_clear_clnt_ctx(struct sched_clnt_ctx *ctx)
+{
+	if (ctx->clnt_frm_q)
+		SCHED_FREE(ctx->clnt_frm_q);
+	(void)SCHED_CRITSEC_RELEASE(ctx->clnt_cs);
+}
+
+SCHED_INLINE void sched_free_clnt_node(
+		struct _sched_clnt_list_node *clnt_node)
+{
+	sched_clear_clnt_ctx(&clnt_node->data);
+	SCHED_FREE(clnt_node);
+
+}
+
+enum sched_status sched_clear_clnt_list(
+	struct _sched_clnt_list_node *clnt_lst) {
+	struct _sched_clnt_list_node *clnt_node;
+
+	while (clnt_lst) {
+		(void)SCHED_CRITSEC_ENTER(clnt_lst->data.clnt_cs);
+		clnt_node = clnt_lst;
+		clnt_lst = clnt_lst->next;
+		sched_free_clnt_node(clnt_node);
+	}
+	return SCHED_S_OK;
+}
+
+static SCHED_INLINE enum sched_status sched_alloc_frm_q(
+		struct sched_clnt_ctx *ctx)
+{
+	ctx->clnt_frm_q = (struct sched_clnt_q_elem *)
+		SCHED_MALLOC(sizeof(struct sched_clnt_q_elem) *
+			 ctx->max_queue_len);
+
+	if (!ctx->clnt_frm_q) {
+		SCHED_MSG_ERR("Could not allocate clnt frm Q. Out of memory");
+		return SCHED_S_ENOMEM;
+	}
+
+	SCHED_MEMSET(ctx->clnt_frm_q,
+	0, sizeof(struct sched_clnt_q_elem) * ctx->max_queue_len);
+	ctx->q_head = 0;
+	ctx->q_tail = -1;
+	ctx->q_len = 0;
+	SCHED_MSG_MED("Clnt frm Q allocted & initialized");
+	return SCHED_S_OK;
+
+}
+
+static SCHED_INLINE void sched_de_q_head_frm
+	(struct sched_clnt_ctx *ctx,
+	 struct sched_clnt_q_elem *q_elem) {
+	*q_elem = ctx->clnt_frm_q[ctx->q_head];
+
+	memset(&ctx->clnt_frm_q[ctx->q_head], 0,
+		sizeof(struct sched_clnt_q_elem));
+
+	/*Update the circular queue head index.*/
+	ctx->q_head = (ctx->q_head + 1) % ctx->max_queue_len;
+	ctx->q_len--;
+}
+
+static SCHED_INLINE void sched_tkn_bkt_fill_normalize
+	(struct sched_clnt_ctx *ctx)
+{
+	ctx->bkt_curr_tkns_nmlzd =
+		(ctx->bkt_curr_tkns * SCHED_TKNBKT_FILL_NORMLZ_SCALE) /
+		ctx->tkn_per_frm;
+}
+
+static void sched_tkn_bkt_config(struct sched_clnt_ctx *ctx)
+{
+	ctx->bkt_size = ctx->tkn_per_frm * SCHED_TKNBKT_SIZE_FACTOR;
+	ctx->bkt_quies_cap = ctx->bkt_size;
+	ctx->bkt_curr_tkns =
+	SCHED_MIN(ctx->bkt_curr_tkns, ctx->bkt_size);
+}
+
+static void sched_tkn_bkt_supply(
+	struct sched_clnt_ctx *ctx, u32 curr_time)
+{
+	u32 delta;
+	u32 num_tkns;
+
+	/*Check if there's time wrap-around since last token supply time.*/
+	if (curr_time < ctx->bkt_lst_sup_time) {
+		SCHED_MSG_HIGH("Current time wrap around detected");
+		delta =
+		SCHED_TIME_MAX - ctx->bkt_lst_sup_time + curr_time;
+	} else
+		delta = curr_time - ctx->bkt_lst_sup_time;
+
+	/*Proceed only if there is any time elapsed since our last supply
+	time.*/
+	if (delta > 0) {
+		/*Calculate the number of tokens that we can supply based on
+		time elapsed and the client's token supply rate.*/
+		num_tkns = delta * ctx->curr_p_tkn_rate / 1000;
+
+		if (num_tkns > 0) {
+			ctx->bkt_curr_tkns = SCHED_MIN(ctx->bkt_size,
+					ctx->bkt_curr_tkns + num_tkns);
+
+			if ((delta * ctx->curr_p_tkn_rate % 1000)) {
+				delta = (num_tkns * 1000 +
+						(ctx->curr_p_tkn_rate >> 1))
+						/ ctx->curr_p_tkn_rate;
+				if ((SCHED_TIME_MAX -
+					ctx->bkt_lst_sup_time) < delta) {
+					SCHED_MSG_HIGH
+					("Handling for current time wrap "
+					"around");
+
+					ctx->bkt_lst_sup_time = delta -
+					(SCHED_TIME_MAX -
+					ctx->bkt_lst_sup_time);
+				} else
+					ctx->bkt_lst_sup_time += delta;
+			} else
+				ctx->bkt_lst_sup_time = curr_time;
+
+			if (ctx->bkt_curr_tkns >
+				(s32) ctx->bkt_quies_cap) {
+				SCHED_MSG_HIGH
+				("Client Quiesence detected. Capping "
+				"bkt_curr_tkns");
+				ctx->bkt_curr_tkns = ctx->tkn_per_frm;
+			}
+			sched_tkn_bkt_fill_normalize(ctx);
+		}
+	}
+}
+
+static SCHED_INLINE void sched_tkn_bkt_consume(
+	struct sched_clnt_ctx *ctx) {
+	ctx->bkt_curr_tkns -= ctx->tkn_per_frm;
+}
+
+static SCHED_INLINE u32 sched_clnt_frm_is_cnfmnt
+	(struct sched_clnt_ctx *ctx)
+{
+	if (ctx->bkt_curr_tkns >= (s32) ctx->tkn_per_frm)
+		return true;
+	else
+		return false;
+}				/* end of sched_clnt_frm_is_conformant */
+
+static struct sched_clnt_ctx *sched_elect_cnfmnt
+	(struct sched_clnt_ctx *prov_elect,
+	struct sched_clnt_ctx *new_cand) {
+
+	/*If there is no provisional elect client then the new candidate
+	becomes the first one.*/
+	if (!prov_elect)
+		return new_cand;
+
+
+	/*Here we want to pick the client who has accumulated the most tokens
+	from the time of attaining single frame conformance.
+	Since we are comparing between clients we use the available normalized
+	token bucket occupancy value.*/
+	if (prov_elect->bkt_curr_tkns_nmlzd >=
+	    new_cand->bkt_curr_tkns_nmlzd) {
+		return prov_elect;
+	} else {
+	/*We had held on to this provisional elect conformant
+	client critical section. Since new candidate has won the
+	election leave critical section of earlier provisional
+	elect.
+	*/
+		(void)SCHED_CRITSEC_LEAVE(prov_elect->clnt_cs);
+		return new_cand;
+	}
+}
+
+static struct sched_clnt_ctx *sched_elect_non_cnfmnt
+	(struct sched_clnt_ctx *prov_elect,
+	struct sched_clnt_ctx *new_cand) {
+
+	/*If there is no provisional elect client then the new candidate
+	becomes the first one.*/
+	if (!prov_elect)
+		return new_cand;
+	/*Here we want to pick the client who is closest to attaining a single
+	frame conformance.
+	Since we are comparing between clients we use the available
+	normalized token bucket occupancy value.
+	Also if the provisional elect or the new contender (in that order)
+	have an end of frame marker set we give it priority over deciding
+	by frame conformance method mentiond earlier.*/
+	if (prov_elect->eof_marker > 0) {
+		return prov_elect;
+	} else if (new_cand->eof_marker > 0) {
+		/*We had held on to this provisional elect non conformant client
+		critical section. Since new candidate has won the election
+		leave critical section of earlier provisional elect.
+		*/
+		(void)SCHED_CRITSEC_LEAVE(prov_elect->clnt_cs);
+
+		return new_cand;
+	} else if (prov_elect->bkt_curr_tkns_nmlzd >=
+		   new_cand->bkt_curr_tkns_nmlzd) {
+		return prov_elect;
+	} else {
+	/*Similar to above case leave critical section of earlier
+	provisional elect.*/
+		(void)SCHED_CRITSEC_LEAVE(prov_elect->clnt_cs);
+		return new_cand;
+	}
+
+}
+
+static struct sched_clnt_ctx *sched_elect_non_rt
+	(struct sched_ctx *sched_ctx) {
+	struct _sched_clnt_list_node *node = NULL;
+	struct _sched_clnt_list_node *start_node = NULL;
+	u32 found = false;
+
+	/*For non real time clients we are using a round robin election
+	algorithm.
+	Based on the last scheduled client we find the next to schedule
+	and return its context.
+	We also need to skip the client if certain conditions (mentioned below)
+	are not met*/
+	if (!sched_ctx->non_rt_last_sched)
+		start_node = node = sched_ctx->non_rt_head;
+	else {
+		if (!sched_ctx->non_rt_last_sched->next)
+			start_node = sched_ctx->non_rt_head;
+		else
+			start_node = sched_ctx->non_rt_last_sched->next;
+
+		node = start_node;
+	}
+
+	do {
+
+		(void)SCHED_CRITSEC_ENTER(node->data.clnt_cs);
+
+	/*Check if the client can be considered for this round of scheduling.*/
+		if (sched_consider_clnt_for_sched(&node->data)) {
+			found = true;
+			sched_ctx->non_rt_last_sched = node;
+		}
+
+	/*If this client is not the election winner then leave its critical
+	section.
+	If we have found a winner we want to hold on to its critical
+	section. We would leave its critical section after we are done
+	with dequeueing a frame from the client context.*/
+		if (!found)
+			(void)SCHED_CRITSEC_LEAVE(node->data.clnt_cs);
+
+		if (!node->next)
+			node = sched_ctx->non_rt_head;
+		else
+			node = node->next;
+
+	} while (node != start_node);
+
+	if (found) {
+		SCHED_MSG_LOW("Non real time client selected");
+
+		return &sched_ctx->non_rt_last_sched->data;
+	} else {
+		SCHED_MSG_MED
+		    ("No non-real time client available for scheduling");
+
+		return NULL;
+	}
+
+}
+
+static enum sched_status sched_process_set_p_tkn_rate(
+		struct sched_ctx *sched_ctx,
+	struct sched_clnt_ctx *clnt_ctx,
+	union sched_value_type *param_value) {
+	u32 curr_time = 0;
+
+	if (param_value->un_value == clnt_ctx->curr_p_tkn_rate)
+		return SCHED_S_OK;
+
+
+	if ((sched_ctx->total_clnt_bw - clnt_ctx->curr_p_tkn_rate +
+	     param_value->un_value) > sched_ctx->perf_lvl) {
+		SCHED_MSG_HIGH
+		    ("Perf level insufficient for requested P Tkn rate");
+
+	}
+
+	/*Get current time. We need this for token supply.
+	If we didn't get a valid current time value just return*/
+	if (SCHED_FAILED(SCHED_GET_CURRENT_TIME(&curr_time))) {
+		SCHED_MSG_ERR("Get current time failed");
+
+		return SCHED_S_EFAIL;
+	}
+
+	/*Before we go ahead and update the Current tkn rate, we fill
+	the token bucket upto current time instance.*/
+	sched_tkn_bkt_supply(clnt_ctx, curr_time);
+
+	/*Next, update the current value of total client bandwidth with
+	the new tkn rate of the client.*/
+	sched_ctx->total_clnt_bw = sched_ctx->total_clnt_bw -
+	    clnt_ctx->curr_p_tkn_rate + param_value->un_value;
+	clnt_ctx->curr_p_tkn_rate = param_value->un_value;
+
+	/*Since the current Ptkn rate (i.e. current alloted bandwidth)
+	of the client has changed we need to update client's token
+	bucket configuration*/
+	sched_tkn_bkt_config(clnt_ctx);
+	return SCHED_S_OK;
+}
+
+static enum sched_status sched_process_add_rt_clnt(
+		struct sched_ctx *sched_ctx,
+	struct _sched_clnt_list_node *clnt_node) {
+	enum sched_status status;
+	struct sched_clnt_ctx *clnt_ctx = &clnt_node->data;
+	struct _sched_clnt_list_node *tmp_node;
+
+	/*Validate real time client specific parameters.*/
+	if (!clnt_ctx->curr_p_tkn_rate)
+		SCHED_MSG_HIGH("Allocated token rate is zero");
+
+	/*Check if our performance level setting can sustain the new client*/
+	if (sched_ctx->total_clnt_bw + clnt_ctx->curr_p_tkn_rate >
+	    sched_ctx->perf_lvl) {
+		SCHED_MSG_HIGH("Not enough bandwidth to support client");
+		SCHED_MSG_HIGH
+		    ("curr_perflvl=%d, curr_bw=%d, newclnt_ptknrate=%d",
+		     sched_ctx->perf_lvl, sched_ctx->total_clnt_bw,
+		     clnt_ctx->curr_p_tkn_rate);
+
+	}
+	/*Allocate the client frame queue*/
+	status = sched_alloc_frm_q(clnt_ctx);
+
+	if (SCHED_SUCCEEDED(status)) {
+		/*Allocate the token bucket*/
+		sched_tkn_bkt_config(clnt_ctx);
+		/*We start with empty token bucket*/
+		clnt_ctx->bkt_curr_tkns = 0;
+		clnt_ctx->bkt_curr_tkns_nmlzd = 0;
+		/*Add the client to the real time client list and increase the
+		total client bandwidth.*/
+		tmp_node = sched_ctx->rt_head;
+		sched_ctx->rt_head = clnt_node;
+		sched_ctx->rt_head->next = tmp_node;
+		sched_ctx->rt_clnts++;
+		sched_ctx->total_clnt_bw += clnt_ctx->curr_p_tkn_rate;
+	}
+	return status;
+}
+
+static enum sched_status sched_process_add_non_rt_clnt(
+		struct sched_ctx *sched_ctx,
+	struct _sched_clnt_list_node *clnt_node) {
+	enum sched_status status;
+	struct sched_clnt_ctx *clnt_ctx = &clnt_node->data;
+	struct _sched_clnt_list_node *tmp_node;
+
+	/*Allocate the client frame queue*/
+	status = sched_alloc_frm_q(clnt_ctx);
+	if (SCHED_SUCCEEDED(status)) {
+		/*Add the client to the real time client list and increase the
+		total client bandwidth.*/
+		tmp_node = sched_ctx->non_rt_head;
+		sched_ctx->non_rt_head = clnt_node;
+		sched_ctx->non_rt_head->next = tmp_node;
+		sched_ctx->non_rt_clnts++;
+	}
+	return status;
+}
+
+enum sched_status sched_process_add_clnt(
+	struct sched_ctx *sched_ctx,
+	struct _sched_clnt_list_node *clnt_node,
+	struct sched_client_init_param *init_param) {
+	enum sched_status status = SCHED_S_OK;
+
+	SCHED_MEMSET(clnt_node, 0, sizeof(struct _sched_clnt_list_node));
+
+	/*Validate all initialization parameters*/
+	if (!init_param->tkn_per_frm ||
+	    !init_param->frm_rate.numer ||
+	    !init_param->frm_rate.denom ||
+	    !init_param->max_queue_len ||
+	    !init_param->o_tkn_max ||
+	    !init_param->o_tkn_per_ip_frm ||
+	    init_param->o_tkn_init > init_param->o_tkn_max ||
+	    init_param->o_tkn_per_ip_frm > init_param->o_tkn_max) {
+		SCHED_MSG_ERR("Bad initialization parameters");
+		return SCHED_S_EBADPARM;
+	}
+
+	/*Store all initialization parameters*/
+	clnt_node->data.client_ctgy = init_param->client_ctgy;
+	clnt_node->data.curr_p_tkn_rate = init_param->alloc_p_tkn_rate;
+	clnt_node->data.frm_rate = init_param->frm_rate;
+	clnt_node->data.max_queue_len = init_param->max_queue_len;
+	clnt_node->data.o_tkn_max = init_param->o_tkn_max;
+	clnt_node->data.o_tkn_per_ip_frm = init_param->o_tkn_per_ip_frm;
+	clnt_node->data.curr_o_tkns = init_param->o_tkn_init;
+	clnt_node->data.tkn_per_frm = init_param->tkn_per_frm;
+	clnt_node->data.client_data = init_param->client_data;
+	clnt_node->data.sched_state = true;
+
+	SCHED_MSG_HIGH("Adding new client of category %d",
+		       clnt_node->data.client_ctgy);
+	SCHED_MSG_MED("Allocated P token rate (per sec) = %d",
+		      clnt_node->data.curr_p_tkn_rate);
+	SCHED_MSG_MED("Frame rate = %d / %d",
+		      clnt_node->data.frm_rate.numer,
+		      clnt_node->data.frm_rate.denom);
+	SCHED_MSG_MED("Max_queue_len = %d", clnt_node->data.max_queue_len);
+	SCHED_MSG_MED("Max O tokens = %d", clnt_node->data.o_tkn_max);
+	SCHED_MSG_MED("O tokens threshold = %d",
+		      clnt_node->data.o_tkn_per_ip_frm);
+	SCHED_MSG_MED("P tokens per frame = %d",
+		      clnt_node->data.tkn_per_frm);
+	SCHED_MSG_MED("Client data ptr = %p", clnt_node->data.client_data);
+
+	if (SCHED_FAILED(SCHED_CRITSEC_CREATE(&clnt_node->data.clnt_cs)))
+		return SCHED_S_EFAIL;
+
+	/*Configure the client context based on client category.*/
+	switch (clnt_node->data.client_ctgy) {
+	case SCHED_CLNT_RT_BUFF:
+	case SCHED_CLNT_RT_NOBUFF:
+		{
+			status =
+			    sched_process_add_rt_clnt(sched_ctx, clnt_node);
+			break;
+		}
+
+	case SCHED_CLNT_NONRT:
+		{
+			status =
+			    sched_process_add_non_rt_clnt(sched_ctx,
+							  clnt_node);
+			break;
+		}
+
+	default:
+		{
+			status = SCHED_S_EBADPARM;
+			break;
+		}
+
+	}
+	return status;
+}
+
+enum sched_status sched_process_remove_clnt(
+		struct sched_ctx *sched_ctx,
+	struct _sched_clnt_list_node *clnt_node) {
+
+	(void)SCHED_CRITSEC_ENTER(clnt_node->data.clnt_cs);
+
+	/*Handling if the client frame queue is not empty. Just return
+	and let Codec driver dequeue all frames for this client
+	before calling remove client*/
+	if (clnt_node->data.q_len) {
+		SCHED_MSG_ERR("Cannot remove client. Queue is not empty");
+		return SCHED_S_EINVALST;
+	}
+
+	/*Based on client category, remove the client node from the
+	appropriate scheduler client list*/
+	switch (clnt_node->data.client_ctgy) {
+	case SCHED_CLNT_RT_BUFF:
+	case SCHED_CLNT_RT_NOBUFF:
+		{
+
+			sched_remove_node_from_list(&sched_ctx->rt_head,
+						    clnt_node);
+			sched_ctx->rt_clnts--;
+			sched_ctx->total_clnt_bw -=
+			    clnt_node->data.curr_p_tkn_rate;
+			break;
+		}
+
+	case SCHED_CLNT_NONRT:
+		{
+			sched_remove_node_from_list(&sched_ctx->non_rt_head,
+						    clnt_node);
+			sched_ctx->non_rt_clnts--;
+			break;
+		}
+
+	default:
+		{
+			SCHED_ASSERT(0);
+			break;
+		}
+	}
+
+	/*Now that client node is off the scheduler client list free up
+	resources that its been using.*/
+	SCHED_MSG_HIGH("Removing new client of category %d",
+		       clnt_node->data.client_ctgy);
+	SCHED_MSG_MED("Allocated P token rate (per sec) = %d",
+		      clnt_node->data.curr_p_tkn_rate);
+	SCHED_MSG_MED("Frame rate = %d / %d",
+		      clnt_node->data.frm_rate.numer,
+		      clnt_node->data.frm_rate.denom);
+	SCHED_MSG_MED("Max_queue_len = %d", clnt_node->data.max_queue_len);
+	SCHED_MSG_MED("Max O tokens = %d", clnt_node->data.o_tkn_max);
+	SCHED_MSG_MED("P tokens per frame = %d",
+		      clnt_node->data.tkn_per_frm);
+	SCHED_MSG_MED("Client data ptr = %p", clnt_node->data.client_data);
+	sched_free_clnt_node(clnt_node);
+	return SCHED_S_OK;
+}
+
+enum sched_status sched_process_flush_clnt_buff(
+		struct sched_ctx *sched_ctx,
+	struct _sched_clnt_list_node *clnt_node, void **pp_frm_data) {
+	struct sched_clnt_ctx *clnt_ctx;
+	enum sched_status status = SCHED_S_OK;
+	struct sched_clnt_q_elem q_elem;
+
+	clnt_ctx = &clnt_node->data;
+
+	/*If the client queue is empty just return an QEMPTY status*/
+	if (!clnt_ctx->q_len) {
+		status = SCHED_S_QEMPTY;
+	} else {
+		clnt_ctx->flushing = true;
+
+	/*If the client queue is not empty just remove and return the
+	element at the front of the queue.*/
+		sched_de_q_head_frm(clnt_ctx, &q_elem);
+		*pp_frm_data = q_elem.frm_data;
+	}
+
+	/*If the Queue was orginially empty OR if it got empty after latest
+	De_queue we reset the flushing and First_frame flags.
+	Token bucket contents are also emptied.Queue pointers are reset.
+	o_tkns are restored.*/
+	if (!clnt_ctx->q_len) {
+		clnt_ctx->flushing = false;
+		clnt_ctx->first_frm = false;
+		clnt_ctx->bkt_curr_tkns = 0;
+		clnt_ctx->bkt_curr_tkns_nmlzd = 0;
+		clnt_ctx->bkt_lst_sup_time = 0;
+		clnt_ctx->q_head = 0;
+		clnt_ctx->q_tail = -1;
+		SCHED_MSG_HIGH
+		    ("Client flushed and re-initialized. Client category %d",
+		     clnt_ctx->client_ctgy);
+		SCHED_MSG_MED("Client allocated P token rate (per sec) = %d",
+			      clnt_ctx->curr_p_tkn_rate);
+		SCHED_MSG_MED("Client frame rate = %d / %d",
+			      clnt_ctx->frm_rate.numer,
+			      clnt_ctx->frm_rate.denom);
+		SCHED_MSG_MED("Client P tokens per frame = %d",
+			      clnt_ctx->tkn_per_frm);
+	}
+	return status;
+}
+
+SCHED_INLINE enum sched_status sched_process_mark_clnt_eof(
+		struct sched_ctx *sched_ctx,
+	struct _sched_clnt_list_node *clnt_node) {
+
+	if (!clnt_node->data.q_len)
+		return SCHED_S_QEMPTY;
+
+
+	if (!clnt_node->data.clnt_frm_q[clnt_node->data.q_tail].eof) {
+		/*Just increment the EOF marker count in the client context.*/
+		clnt_node->data.eof_marker++;
+		clnt_node->data.clnt_frm_q[clnt_node->data.q_tail].
+		eof = true;
+	} else
+		SCHED_MSG_HIGH("Current frame is already marked EOF");
+
+	SCHED_MSG_HIGH("Client marked for end of frames. Client category %d",
+		       clnt_node->data.client_ctgy);
+	SCHED_MSG_MED("Client allocated P token rate (per sec) = %d",
+		      clnt_node->data.curr_p_tkn_rate);
+	SCHED_MSG_MED("Client frame rate = %d / %d",
+		      clnt_node->data.frm_rate.numer,
+		      clnt_node->data.frm_rate.denom);
+	SCHED_MSG_MED("Client P tokens per frame = %d",
+		      clnt_node->data.tkn_per_frm);
+	return SCHED_S_OK;
+}
+
+enum sched_status sched_process_update_clnt_o_tkn(
+		struct sched_ctx *sched_ctx,
+	struct _sched_clnt_list_node *clnt_node,
+	u32 type, u32 o_tkn) {
+
+	/*Act based on the type of update.*/
+
+	if (type) {
+		/*Just replenish the output tokens the client currently has with
+		the provided number while not going over the max value.*/
+		clnt_node->data.curr_o_tkns =
+		    SCHED_MIN(clnt_node->data.curr_o_tkns + o_tkn,
+			      clnt_node->data.o_tkn_max);
+	} else {
+	/*Just subtract the give number of output tokens from the count
+	the client currently has while not going less than 0.*/
+		if (o_tkn >= clnt_node->data.curr_o_tkns)
+			clnt_node->data.curr_o_tkns = 0;
+		else
+			clnt_node->data.curr_o_tkns -= o_tkn;
+
+	}
+
+	SCHED_MSG_LOW("%d O tokens restored for client", o_tkn);
+	SCHED_MSG_LOW("Client Curr_o_tkns = %d",
+		      clnt_node->data.curr_o_tkns);
+	SCHED_MSG_LOW("Client category = %d", clnt_node->data.client_ctgy);
+	SCHED_MSG_LOW("Client allocated P token rate (per sec) = %d",
+		      clnt_node->data.curr_p_tkn_rate);
+	SCHED_MSG_LOW("Client frame rate = %d / %d",
+		      clnt_node->data.frm_rate.numer,
+		      clnt_node->data.frm_rate.denom);
+	SCHED_MSG_LOW("Client P tokens per frame = %d",
+		      clnt_node->data.tkn_per_frm);
+	return SCHED_S_OK;
+}
+
+enum sched_status sched_process_en_q_frm(
+		struct sched_ctx *sched_ctx,
+	struct _sched_clnt_list_node *clnt_node, void *frm_data) {
+	struct sched_clnt_ctx *clnt_ctx;
+	u32 curr_time = 0;
+
+	clnt_ctx = &clnt_node->data;
+
+	/*Check if the client queue is full already*/
+	if (clnt_ctx->q_len == clnt_ctx->max_queue_len) {
+		SCHED_MSG_HIGH("Cannot enqueue. Client queue is full");
+
+		return SCHED_S_QFULL;
+	}
+
+	/*Check if the client queue is being flushed.*/
+	if (clnt_ctx->flushing) {
+		SCHED_MSG_ERR("Cannot enqueue. Client queue is being flushed");
+
+		return SCHED_S_EINVALST;
+	}
+
+	/*Reposition tail, increase Q length and add the frame data to Q*/
+	clnt_ctx->q_tail =
+	    (clnt_ctx->q_tail + 1) % clnt_ctx->max_queue_len;
+
+	clnt_ctx->q_len++;
+
+	clnt_ctx->clnt_frm_q[clnt_ctx->q_tail].frm_data = frm_data;
+	clnt_ctx->clnt_frm_q[clnt_ctx->q_tail].eof = false;
+
+	/*If this is the first frame being queued for this client then,
+	get current time. We now start the token supply clock for the client.
+	Supply tokens required for a single frame processing while storing
+	the current time as the last supply time and marking that first
+	frame is received.*/
+	if (!clnt_ctx->first_frm) {
+		SCHED_MSG_HIGH("Client first frame enqueued");
+		if (clnt_ctx->client_ctgy != SCHED_CLNT_NONRT) {
+			if (SCHED_SUCCEEDED
+			(SCHED_GET_CURRENT_TIME(&curr_time))) {
+				clnt_ctx->bkt_curr_tkns =
+					clnt_ctx->tkn_per_frm;
+				clnt_ctx->bkt_lst_sup_time = curr_time;
+				clnt_ctx->first_frm = true;
+			}
+		} else
+			clnt_ctx->first_frm = true;
+	}
+
+	SCHED_MSG_LOW("Client frame enqueued. Queue fill status = %d / %d",
+			clnt_ctx->q_len, clnt_ctx->max_queue_len);
+	SCHED_MSG_LOW("Client category = %d", clnt_ctx->client_ctgy);
+	SCHED_MSG_LOW("Client allocated P token rate (per sec) = %d",
+		clnt_ctx->curr_p_tkn_rate);
+	SCHED_MSG_LOW("Client frame rate = %d / %d",
+		clnt_ctx->frm_rate.numer,
+		clnt_ctx->frm_rate.denom);
+	SCHED_MSG_LOW("Client P tokens per frame = %d",
+		clnt_ctx->tkn_per_frm);
+
+	return SCHED_S_OK;
+
+}
+
+enum sched_status sched_process_re_en_q_frm(
+	struct sched_ctx *sched_ctx,
+	struct _sched_clnt_list_node *clnt_node,
+	void *frm_data)
+{
+	struct sched_clnt_ctx *clnt_ctx;
+	u32 curr_time = 0;
+
+	clnt_ctx = &clnt_node->data;
+
+	if (clnt_ctx->q_len == clnt_ctx->max_queue_len) {
+		SCHED_MSG_ERR("Cannot re-enqueue. Client queue is full");
+		return SCHED_S_QFULL;
+	}
+
+	if (clnt_ctx->flushing) {
+		SCHED_MSG_ERR("Cannot re-enqueue. Client"
+					" queue is being flushed");
+		return SCHED_S_EINVALST;
+	}
+
+	clnt_ctx->q_head =
+		(clnt_ctx->q_head + clnt_ctx->max_queue_len - 1) %
+		clnt_ctx->max_queue_len;
+
+	clnt_ctx->q_len++;
+
+	clnt_ctx->clnt_frm_q[clnt_ctx->q_head].frm_data =
+		frm_data;
+	clnt_ctx->clnt_frm_q[clnt_ctx->q_head].eof =
+		false;
+
+	if (clnt_ctx->client_ctgy != SCHED_CLNT_NONRT) {
+		if (!clnt_ctx->first_frm) {
+			SCHED_MSG_HIGH("Client frame "
+						"re-enqueued as first frame");
+			if (SCHED_SUCCEEDED
+			(SCHED_GET_CURRENT_TIME(&curr_time))) {
+				clnt_ctx->bkt_curr_tkns =
+					clnt_ctx->tkn_per_frm;
+				clnt_ctx->bkt_lst_sup_time =
+					curr_time;
+				clnt_ctx->first_frm =
+					true;
+			}
+		} else
+			clnt_ctx->bkt_curr_tkns +=
+				clnt_ctx->tkn_per_frm;
+	} else
+		clnt_ctx->first_frm = true;
+
+
+	SCHED_MSG_LOW("Client frame re-enqueued. Queue fill status = %d / %d",
+	clnt_ctx->q_len, clnt_ctx->max_queue_len);
+	SCHED_MSG_LOW("Client category = %d", clnt_ctx->client_ctgy);
+	SCHED_MSG_LOW("Client allocated P token rate (per sec) = %d",
+	clnt_ctx->curr_p_tkn_rate);
+	SCHED_MSG_LOW("Client frame rate = %d / %d",
+			clnt_ctx->frm_rate.numer,
+			clnt_ctx->frm_rate.denom);
+	SCHED_MSG_LOW("Client P tokens per frame = %d",
+			clnt_ctx->tkn_per_frm);
+
+	return SCHED_S_OK;
+
+}
+
+enum sched_status sched_process_de_q_frm_rt_clnt(
+		struct sched_ctx *sched_ctx,
+	struct sched_clnt_ctx **pp_conf_elect_ctx,
+	struct sched_clnt_ctx **pp_non_conf_elect_ctx) {
+	u32 curr_time = 0;
+	struct _sched_clnt_list_node *clnt_node;
+	struct sched_clnt_ctx *clnt_ctx;
+
+	*pp_conf_elect_ctx = NULL;
+	*pp_non_conf_elect_ctx = NULL;
+
+	/*Get current time. We need this for token supply.
+	If we didn't get a valid current time value just return*/
+	if (SCHED_FAILED(SCHED_GET_CURRENT_TIME(&curr_time))) {
+		SCHED_MSG_ERR("Get current time failed");
+
+		return SCHED_S_EFAIL;
+	}
+
+	/*Run through the list of real time clients.
+	Consider only the clients that have queued atleast one frame since
+	being admitted into the scheduler.
+	Supply tokens equivalent to elapsed time since last supply.
+	Also in this same pass, check if each client has a conformant
+	frame or not.*/
+	clnt_node = sched_ctx->rt_head;
+	while (clnt_node) {
+		clnt_ctx = &clnt_node->data;
+
+		(void)SCHED_CRITSEC_ENTER(clnt_ctx->clnt_cs);
+
+		if (sched_consider_clnt_for_sched(clnt_ctx)) {
+			sched_tkn_bkt_supply(clnt_ctx, curr_time);
+			if (sched_clnt_frm_is_cnfmnt(clnt_ctx)) {
+				*pp_conf_elect_ctx =
+					sched_elect_cnfmnt(*pp_conf_elect_ctx,
+						clnt_ctx);
+			} else {
+				if (!*pp_conf_elect_ctx) {
+					*pp_non_conf_elect_ctx =
+					    sched_elect_non_cnfmnt
+					    (*pp_non_conf_elect_ctx,
+					     clnt_ctx);
+				} else if (*pp_non_conf_elect_ctx) {
+					(void)
+					    SCHED_CRITSEC_LEAVE(
+					    (*pp_non_conf_elect_ctx)->clnt_cs);
+					*pp_non_conf_elect_ctx = NULL;
+
+				}
+			}
+		}
+		if (clnt_ctx != *pp_conf_elect_ctx
+		    && clnt_ctx != *pp_non_conf_elect_ctx)
+			(void)SCHED_CRITSEC_LEAVE(clnt_ctx->clnt_cs);
+		clnt_node = clnt_node->next;
+	}
+
+	return SCHED_S_OK;
+
+}
+
+enum sched_status sched_process_de_q_frm(
+		struct sched_ctx *sched_ctx,
+	void **pp_frm_data, void **pp_client_data) {
+	enum sched_status status;
+	struct sched_clnt_ctx *sched_clnt_ctx = NULL;
+	struct sched_clnt_ctx *conf_elect_ctx;
+	struct sched_clnt_ctx *non_conf_elect_ctx;
+	struct sched_clnt_q_elem q_elem;
+
+	status = sched_process_de_q_frm_rt_clnt(sched_ctx,
+						&conf_elect_ctx,
+						&non_conf_elect_ctx);
+	if (SCHED_FAILED(status)) {
+		SCHED_MSG_ERR("sched_process_de_q_frm_rt_clnt ret err=%d",
+			      status);
+
+		return status;
+	}
+
+	/*At this point we have looked at all real time clients in the
+	scheduler list and have run their elections.
+	We used the following frame service order to pick the client to
+	schedule:
+	a) client with conformant frame
+	b) client with non-conformant frame
+	c) non real-time client*/
+	if (conf_elect_ctx) {
+		SCHED_MSG_LOW("Conformant frame client selected");
+		sched_tkn_bkt_consume(conf_elect_ctx);
+		sched_clnt_ctx = conf_elect_ctx;
+	} else if (non_conf_elect_ctx) {
+		SCHED_MSG_LOW("Non-Conformant frame client selected");
+		sched_tkn_bkt_consume(non_conf_elect_ctx);
+		sched_clnt_ctx = non_conf_elect_ctx;
+	} else if (sched_ctx->non_rt_clnts)
+		sched_clnt_ctx = sched_elect_non_rt(sched_ctx);
+
+	/*If we have a client that we can schedule, then dequeue the frame
+	at the head of its queue.*/
+	if (sched_clnt_ctx) {
+		*pp_client_data = sched_clnt_ctx->client_data;
+
+		sched_de_q_head_frm(sched_clnt_ctx, &q_elem);
+
+		*pp_frm_data = q_elem.frm_data;
+
+		sched_clnt_ctx->curr_o_tkns -=
+		    sched_clnt_ctx->o_tkn_per_ip_frm;
+
+	/*If the dequeued frame was marked EOF we need to decrement the
+	eof_marker count.*/
+		if (q_elem.eof) {
+			SCHED_MSG_MED
+			    ("Last frame for EOF marked client dequeued");
+
+			sched_clnt_ctx->eof_marker--;
+
+			status = SCHED_S_EOF;
+		}
+
+		SCHED_MSG_LOW
+		    ("Client frame Dequeued. Queue fill status = %d / %d",
+		     sched_clnt_ctx->q_len,
+		     sched_clnt_ctx->max_queue_len);
+		SCHED_MSG_LOW("Client category = %d",
+			      sched_clnt_ctx->client_ctgy);
+		SCHED_MSG_LOW("Client allocated P token rate (per sec) = %d",
+			      sched_clnt_ctx->curr_p_tkn_rate);
+		SCHED_MSG_LOW("Client frame rate = %d / %d",
+			      sched_clnt_ctx->frm_rate.numer,
+			      sched_clnt_ctx->frm_rate.denom);
+		SCHED_MSG_LOW("Client P tokens per frame = %d",
+			      sched_clnt_ctx->tkn_per_frm);
+
+	/*We had held on to the election winning client critical
+	section. Leave client critical section before we exit.*/
+		(void)SCHED_CRITSEC_LEAVE(sched_clnt_ctx->clnt_cs);
+	} else {
+		status = SCHED_S_QEMPTY;
+	}
+
+	return status;
+
+}
+
+enum sched_status sched_process_sched_lvl_get_param(
+		struct sched_ctx *sched_ctx,
+	enum sched_index param_index,
+	union sched_value_type *param_value)
+{
+	enum sched_status status = SCHED_S_OK;
+
+	switch (param_index) {
+	case SCHED_I_PERFLEVEL:
+		{
+			param_value->un_value = sched_ctx->perf_lvl;
+			break;
+		}
+
+	default:
+		{
+			status = SCHED_S_EBADPARM;
+			break;
+		}
+	}
+	return status;
+}
+
+enum sched_status sched_process_sched_lvl_set_param(
+		struct sched_ctx *sched_ctx,
+	enum sched_index param_index,
+	union sched_value_type *param_value)
+{
+	enum sched_status status = SCHED_S_OK;
+
+	SCHED_MSG_HIGH("Set_sched_param index = %u, value = %p",
+		       param_index, (void *)param_value);
+
+	switch (param_index) {
+	case SCHED_I_PERFLEVEL:
+		{
+			if (sched_ctx->total_clnt_bw >
+			    param_value->un_value) {
+				SCHED_MSG_HIGH
+				    ("Perf level being lowered than current "
+				     "bandwidth");
+				SCHED_MSG_HIGH
+				    ("curr_perflvl=%d, new_perflvl=%d, "
+				     "curr_bw=%d",
+				     sched_ctx->perf_lvl,
+				     param_value->un_value,
+				     sched_ctx->total_clnt_bw);
+			}
+
+			sched_ctx->perf_lvl = param_value->un_value;
+
+			break;
+		}
+
+	default:
+		{
+			status = SCHED_S_EBADPARM;
+			break;
+		}
+	}
+	return status;
+}
+
+enum sched_status sched_process_clnt_lvl_get_param(
+		struct sched_ctx *sched_ctx,
+	struct sched_clnt_ctx *clnt_ctx,
+	enum sched_index param_index,
+	union sched_value_type *param_value) {
+	enum sched_status status = SCHED_S_OK;
+
+	switch (param_index) {
+	case SCHED_I_CLNT_CURRQLEN:
+		{
+			param_value->un_value = clnt_ctx->q_len;
+			break;
+		}
+
+	case SCHED_I_CLNT_PTKNRATE:
+		{
+			param_value->un_value = clnt_ctx->curr_p_tkn_rate;
+			break;
+		}
+
+	case SCHED_I_CLNT_PTKNPERFRM:
+		{
+			param_value->un_value = clnt_ctx->tkn_per_frm;
+			break;
+		}
+
+	case SCHED_I_CLNT_FRAMERATE:
+		{
+			param_value->frm_rate = clnt_ctx->frm_rate;
+			break;
+		}
+
+	case SCHED_I_CLNT_OTKNMAX:
+		{
+			param_value->un_value = clnt_ctx->o_tkn_max;
+			break;
+		}
+
+	case SCHED_I_CLNT_OTKNPERIPFRM:
+		{
+			param_value->un_value =
+			    clnt_ctx->o_tkn_per_ip_frm;
+			break;
+		}
+
+	case SCHED_I_CLNT_OTKNCURRENT:
+		{
+			param_value->un_value = clnt_ctx->curr_o_tkns;
+			break;
+		}
+
+	default:
+		{
+			status = SCHED_S_EBADPARM;
+			break;
+		}
+	}
+	return status;
+}
+
+enum sched_status sched_process_clnt_lvl_set_param(
+		struct sched_ctx *sched_ctx,
+	struct sched_clnt_ctx *clnt_ctx,
+	enum sched_index param_index,
+	union sched_value_type *param_value)
+{
+	enum sched_status status = SCHED_S_OK;
+
+	SCHED_MSG_HIGH("Set_clnt_param index = %u, value = %p",
+		       param_index, (void *)param_value);
+
+	switch (param_index) {
+	case SCHED_I_CLNT_CURRQLEN:
+	case SCHED_I_CLNT_OTKNCURRENT:
+		{
+			status = SCHED_S_EINVALOP;
+			break;
+		}
+
+	case SCHED_I_CLNT_PTKNRATE:
+		{
+			status =
+			    sched_process_set_p_tkn_rate(sched_ctx,
+							 clnt_ctx,
+							 param_value);
+			break;
+		}
+
+	case SCHED_I_CLNT_PTKNPERFRM:
+		{
+
+			clnt_ctx->tkn_per_frm = param_value->un_value;
+			sched_tkn_bkt_config(clnt_ctx);
+			break;
+		}
+
+	case SCHED_I_CLNT_FRAMERATE:
+		{
+			clnt_ctx->frm_rate = param_value->frm_rate;
+			break;
+		}
+
+	case SCHED_I_CLNT_OTKNMAX:
+		{
+			if (param_value->un_value <
+			    clnt_ctx->o_tkn_per_ip_frm) {
+				status = SCHED_S_EBADPARM;
+			} else {
+				clnt_ctx->o_tkn_max =
+				    param_value->un_value;
+
+				clnt_ctx->curr_o_tkns =
+				    SCHED_MIN(clnt_ctx->curr_o_tkns,
+					      clnt_ctx->o_tkn_max);
+			}
+			break;
+		}
+
+	case SCHED_I_CLNT_OTKNPERIPFRM:
+		{
+			if (param_value->un_value > clnt_ctx->o_tkn_max) {
+				status = SCHED_S_EBADPARM;
+			} else {
+				clnt_ctx->o_tkn_per_ip_frm =
+				    param_value->un_value;
+			}
+			break;
+		}
+
+	default:
+		{
+			status = SCHED_S_EBADPARM;
+			break;
+		}
+	}
+
+	return status;
+
+}
+
+enum sched_status sched_process_suspend_resume_clnt(
+		struct sched_ctx *sched_ctx,
+	struct _sched_clnt_list_node *clnt_node, u32 state) {
+	u32 curr_time;
+	struct sched_clnt_ctx *clnt_ctx = &clnt_node->data;
+
+	SCHED_MSG_HIGH("Current client sched_state=%d. Requested state=%d",
+		       clnt_ctx->sched_state, state);
+
+	if (clnt_ctx->sched_state == state)
+		return SCHED_S_OK;
+
+
+	clnt_ctx->sched_state = state;
+
+	if (!SCHED_SUCCEEDED(SCHED_GET_CURRENT_TIME(&curr_time))) {
+		SCHED_MSG_ERR("Get current time failed");
+
+		return SCHED_S_OK;
+	}
+
+	/* RESUME */
+	if (state) {
+		clnt_ctx->bkt_lst_sup_time = curr_time;
+	} else {		/* SUSPEND */
+	/*As we are suspending the client we fill the token bucket upto
+	current time instance.*/
+		sched_tkn_bkt_supply(clnt_ctx, curr_time);
+	}
+
+	SCHED_MSG_MED("Client category %d", clnt_ctx->client_ctgy);
+	SCHED_MSG_MED("Client allocated P token rate (per sec) = %d",
+		      clnt_ctx->curr_p_tkn_rate);
+	SCHED_MSG_MED("Client frame rate = %d / %d",
+		      clnt_ctx->frm_rate.numer,
+		      clnt_ctx->frm_rate.denom);
+	SCHED_MSG_MED("Client P tokens per frame = %d",
+		      clnt_ctx->tkn_per_frm);
+
+	return SCHED_S_OK;
+
+}
+
+void sched_remove_node_from_list(
+	struct _sched_clnt_list_node **pp_head,
+	struct _sched_clnt_list_node *node)
+{
+	u32 found = false;
+	struct _sched_clnt_list_node *curr = *pp_head;
+
+	if (!*pp_head || !node) {
+		SCHED_MSG_ERR("Bad params. head %p, node %p", *pp_head,
+			      node);
+		return;
+	}
+
+	if (node == *pp_head) {
+		*pp_head = node->next;
+		return;
+	}
+
+	while (!found && curr) {
+		if (node == curr->next) {
+			curr->next = node->next;
+			found = true;
+		}
+
+		curr = curr->next;
+	}
+
+}
+
+SCHED_INLINE u32 sched_consider_clnt_for_sched(
+		struct sched_clnt_ctx *clnt_ctx)
+{
+	if (clnt_ctx->first_frm &&
+	    clnt_ctx->sched_state &&
+	    !clnt_ctx->flushing &&
+	    clnt_ctx->q_len &&
+	    clnt_ctx->curr_o_tkns >= clnt_ctx->o_tkn_per_ip_frm) {
+		return true;
+	} else {
+		return false;
+	}
+}
diff --git a/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler.h b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler.h
new file mode 100644
index 0000000..e38e9af
--- /dev/null
+++ b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler.h
@@ -0,0 +1,138 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VID_FRAME_SCHEDULER_H_
+#define _VID_FRAME_SCHEDULER_H_
+#include "vid_frame_scheduler_utils.h"
+
+struct sched_clnt_q_elem {
+	void *frm_data;
+	u32 eof;
+
+};
+
+struct sched_clnt_ctx {
+	enum sched_client_ctgy client_ctgy;
+	struct sched_client_frm_rate frm_rate;
+	u32 tkn_per_frm;
+	u32 curr_p_tkn_rate;
+	u32 o_tkn_max;
+	u32 o_tkn_per_ip_frm;
+	u32 curr_o_tkns;
+	u32 bkt_size;
+	u32 bkt_quies_cap;
+	s32 bkt_curr_tkns;
+	s32 bkt_curr_tkns_nmlzd;
+	u32 bkt_lst_sup_time;
+	u32 max_queue_len;
+	struct sched_clnt_q_elem *clnt_frm_q;
+	s32 q_head;
+	s32 q_tail;
+	u32 q_len;
+	u32 first_frm;
+	u32 eof_marker;
+	u32 flushing;
+	u32 sched_state;
+	void *client_data;
+	u32 *clnt_cs;
+};
+
+struct _sched_clnt_list_node {
+	struct sched_clnt_ctx data;
+	struct _sched_clnt_list_node *next;
+
+};
+
+struct _sched_clnt_list_node;
+
+struct sched_ctx {
+	u32 perf_lvl;
+	struct _sched_clnt_list_node *rt_head;
+	u32 rt_clnts;
+	struct _sched_clnt_list_node *non_rt_head;
+	u32 non_rt_clnts;
+	struct _sched_clnt_list_node *non_rt_last_sched;
+	u32 total_clnt_bw;
+	u32 *sched_cs;
+};
+
+SCHED_INLINE u32 SCHED_SUCCEEDED(enum sched_status status);
+SCHED_INLINE u32 SCHED_FAILED(enum sched_status status);
+SCHED_INLINE void sched_free_clnt_node
+    (struct _sched_clnt_list_node *clnt_node);
+enum sched_status sched_clear_clnt_list
+    (struct _sched_clnt_list_node *clnt_lst);
+enum sched_status sched_process_add_clnt
+    (struct sched_ctx *sched_ctx,
+     struct _sched_clnt_list_node *clnt_node,
+     struct sched_client_init_param *init_param);
+enum sched_status sched_process_remove_clnt
+    (struct sched_ctx *sched_ctx,
+     struct _sched_clnt_list_node *clnt_node);
+enum sched_status sched_process_flush_clnt_buff
+    (struct sched_ctx *sched_ctx,
+     struct _sched_clnt_list_node *clnt_node, void **pp_frm_data);
+SCHED_INLINE enum sched_status sched_process_mark_clnt_eof
+    (struct sched_ctx *sched_ctx,
+     struct _sched_clnt_list_node *clnt_node);
+enum sched_status sched_process_update_clnt_o_tkn
+    (struct sched_ctx *sched_ctx,
+     struct _sched_clnt_list_node *clnt_node, u32 type, u32 o_tkn);
+enum sched_status sched_process_en_q_frm
+    (struct sched_ctx *sched_ctx,
+     struct _sched_clnt_list_node *clnt_node, void *frm_data);
+enum sched_status sched_process_re_en_q_frm
+(struct sched_ctx	*sched_ctx,
+  struct _sched_clnt_list_node *clnt_node, void *frm_data);
+enum sched_status sched_process_de_q_frm
+    (struct sched_ctx *sched_ctx,
+     void **pp_frm_data, void **pp_client_data);
+enum sched_status sched_process_sched_lvl_get_param
+    (struct sched_ctx *sched_ctx,
+     enum sched_index param_index, union sched_value_type *param_value);
+enum sched_status sched_process_sched_lvl_set_param
+    (struct sched_ctx *sched_ctx,
+     enum sched_index param_index, union sched_value_type *param_value);
+enum sched_status sched_process_clnt_lvl_get_param
+    (struct sched_ctx *sched_ctx,
+     struct sched_clnt_ctx *clnt_ctx,
+     enum sched_index param_index, union sched_value_type *param_value);
+enum sched_status sched_process_clnt_lvl_set_param
+    (struct sched_ctx *sched_ctx,
+     struct sched_clnt_ctx *clnt_ctx,
+     enum sched_index param_index, union sched_value_type *param_value);
+enum sched_status sched_process_suspend_resume_clnt
+    (struct sched_ctx *sched_ctx,
+     struct _sched_clnt_list_node *clnt_node, u32 state);
+void sched_remove_node_from_list
+    (struct _sched_clnt_list_node **pp_head,
+     struct _sched_clnt_list_node *node);
+SCHED_INLINE u32 sched_consider_clnt_for_sched
+    (struct sched_clnt_ctx *clnt_ctx);
+
+#endif
diff --git a/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_api.c b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_api.c
new file mode 100644
index 0000000..7c55784
--- /dev/null
+++ b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_api.c
@@ -0,0 +1,426 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+
+#include "vid_frame_scheduler_api.h"
+#include "vid_frame_scheduler.h"
+
+enum sched_status sched_create(
+	struct sched_init_param *init_param, void **handle)
+{
+	struct sched_ctx *sched_ctx;
+
+	SCHED_MSG_HIGH("sched_create API");
+
+	if (!handle || !init_param) {
+		SCHED_MSG_ERR
+		("Bad input parameters: handle=%p, init_param=%p",
+		handle, init_param);
+		return SCHED_S_EBADPARM;
+	}
+
+	if (!init_param->perf_lvl) {
+		SCHED_MSG_ERR("Invalid Perf level=%u",
+			init_param->perf_lvl);
+		return SCHED_S_EBADPARM;
+	}
+
+	sched_ctx =
+		(struct sched_ctx *)
+		SCHED_MALLOC(sizeof(struct sched_ctx));
+
+	if (!sched_ctx) {
+		SCHED_MSG_ERR("Could not allocate sched ctx. Out of memory");
+		return SCHED_S_ENOMEM;
+	}
+
+	SCHED_MEMSET(sched_ctx, 0, sizeof(struct sched_ctx));
+	sched_ctx->perf_lvl = init_param->perf_lvl;
+
+	if (SCHED_FAILED(SCHED_CRITSEC_CREATE(&sched_ctx->sched_cs))) {
+		SCHED_FREE(sched_ctx);
+		return SCHED_S_EFAIL;
+	}
+
+	*handle = sched_ctx;
+
+	SCHED_MSG_MED("Sched instance created. All went well");
+
+	return SCHED_S_OK;
+
+}
+
+enum sched_status sched_destroy(void *handle)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+
+	SCHED_MSG_HIGH("sched_destroy API");
+
+	if (!sched_ctx) {
+		SCHED_MSG_ERR("Bad input parameters");
+		return SCHED_S_EBADPARM;
+	}
+	(void)SCHED_CRITSEC_ENTER(sched_ctx->sched_cs);
+	(void)sched_clear_clnt_list(sched_ctx->rt_head);
+	(void)sched_clear_clnt_list(sched_ctx->rt_head);
+	SCHED_MSG_MED("Sched clnt lists are cleared & released");
+	(void)SCHED_CRITSEC_LEAVE(sched_ctx->sched_cs);
+	(void)SCHED_CRITSEC_RELEASE(sched_ctx->sched_cs);
+	SCHED_MEMSET(sched_ctx, 0, sizeof(struct sched_ctx));
+	SCHED_FREE(sched_ctx);
+	SCHED_MSG_MED("Sched instance deleted");
+	return SCHED_S_OK;
+}
+
+enum sched_status sched_get_param(
+	void *handle,
+	enum sched_index param_index,
+	union sched_value_type *param_value)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	enum sched_status status;
+
+	SCHED_MSG_HIGH("sched_get_param API");
+
+	if (!sched_ctx || !param_value) {
+		SCHED_MSG_ERR
+		("Bad input parameters: sched_ctx=%p, param_value=%p",
+		sched_ctx, param_value);
+
+		return SCHED_S_EBADPARM;
+	}
+
+	(void)SCHED_CRITSEC_ENTER(sched_ctx->sched_cs);
+
+	status =
+	sched_process_sched_lvl_get_param(sched_ctx, param_index,
+					param_value);
+
+	(void)SCHED_CRITSEC_LEAVE(sched_ctx->sched_cs);
+	return status;
+}
+
+enum sched_status sched_set_param(
+	void *handle,
+	enum sched_index param_index,
+	union sched_value_type *param_value)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	enum sched_status status;
+
+	SCHED_MSG_HIGH("sched_set_param API");
+
+	if (!sched_ctx || !param_value) {
+		SCHED_MSG_ERR
+		("Bad input parameters: sched_ctx=%p, param_value=%p",
+		sched_ctx, param_value);
+		return SCHED_S_EBADPARM;
+	}
+	(void)SCHED_CRITSEC_ENTER(sched_ctx->sched_cs);
+	status =
+		sched_process_sched_lvl_set_param(sched_ctx, param_index,
+		param_value);
+	(void)SCHED_CRITSEC_LEAVE(sched_ctx->sched_cs);
+	return status;
+}
+
+enum sched_status sched_add_client(
+	void *handle,
+	struct sched_client_init_param *init_param,
+	void **client_hdl)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	enum sched_status status = SCHED_S_OK;
+	struct _sched_clnt_list_node *new_clnt;
+
+	SCHED_MSG_HIGH("sched_add_client API");
+
+	if (!sched_ctx || !init_param ||
+			!client_hdl) {
+		SCHED_MSG_ERR("Bad input parameters");
+
+		return SCHED_S_EBADPARM;
+	}
+
+	new_clnt = (struct _sched_clnt_list_node *)
+	SCHED_MALLOC(sizeof(struct _sched_clnt_list_node));
+	if (!new_clnt) {
+		SCHED_MSG_ERR("Could not allocate client ctx. Out of memory");
+		return SCHED_S_ENOMEM;
+	}
+	(void)SCHED_CRITSEC_ENTER(sched_ctx->sched_cs);
+	status = sched_process_add_clnt(sched_ctx, new_clnt, init_param);
+
+	if (SCHED_FAILED(status)) {
+		SCHED_MSG_ERR("Add_client failed with err=%d", status);
+		sched_free_clnt_node(new_clnt);
+		new_clnt = NULL;
+	}
+
+	(void)SCHED_CRITSEC_LEAVE(sched_ctx->sched_cs);
+	*client_hdl = new_clnt;
+	SCHED_MSG_MED("Sched client instance created. All went well");
+	return status;
+}
+
+enum sched_status sched_remove_client(void *handle, void *client_hdl)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	struct _sched_clnt_list_node *clnt_node =
+	(struct _sched_clnt_list_node *)client_hdl;
+	enum sched_status status = SCHED_S_OK;
+
+	SCHED_MSG_HIGH("sched_remove_client API");
+	if (!sched_ctx || !clnt_node) {
+		SCHED_MSG_ERR
+		("Bad input parameters: sched_ctx=%p, clnt_node=%p",
+		sched_ctx, clnt_node);
+		return SCHED_S_EBADPARM;
+	}
+
+	(void)SCHED_CRITSEC_ENTER(sched_ctx->sched_cs);
+	status = sched_process_remove_clnt(sched_ctx, clnt_node);
+	(void)SCHED_CRITSEC_LEAVE(sched_ctx->sched_cs);
+	return status;
+}
+
+enum sched_status sched_flush_client_buffer(
+	void *handle, void *client_hdl, void **pp_frm_data)
+{
+
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	struct _sched_clnt_list_node *clnt_node =
+	(struct _sched_clnt_list_node *)client_hdl;
+	enum sched_status status = SCHED_S_OK;
+
+	SCHED_MSG_HIGH("sched_flush_client_buffer API");
+	if (!sched_ctx || !clnt_node || !pp_frm_data) {
+		SCHED_MSG_ERR
+		("Bad input parameters: sched_ctx=%p, clnt_node=%p",
+		sched_ctx, clnt_node);
+		return SCHED_S_EBADPARM;
+	}
+
+	(void)SCHED_CRITSEC_ENTER(clnt_node->data.clnt_cs);
+	status =
+	sched_process_flush_clnt_buff(sched_ctx, clnt_node,
+					pp_frm_data);
+	(void)SCHED_CRITSEC_LEAVE(clnt_node->data.clnt_cs);
+	return status;
+}
+
+enum sched_status sched_mark_client_eof(void *handle, void *client_hdl)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	struct _sched_clnt_list_node *clnt_node =
+	(struct _sched_clnt_list_node *)client_hdl;
+	enum sched_status status = SCHED_S_OK;
+
+	SCHED_MSG_HIGH("sched_mark_client_eof API");
+	if (!sched_ctx || !clnt_node) {
+		SCHED_MSG_ERR
+		("Bad input parameters: sched_ctx=%p, clnt_node=%p",
+		sched_ctx, clnt_node);
+		return SCHED_S_EBADPARM;
+	}
+
+	(void)SCHED_CRITSEC_ENTER(clnt_node->data.clnt_cs);
+	status = sched_process_mark_clnt_eof(sched_ctx, clnt_node);
+	(void)SCHED_CRITSEC_LEAVE(clnt_node->data.clnt_cs);
+	return status;
+}
+
+enum sched_status sched_update_client_o_tkn(
+	void *handle, void *client_hdl, u32 type, u32 o_tkn)
+{
+
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	struct _sched_clnt_list_node *clnt_node =
+	(struct _sched_clnt_list_node *)client_hdl;
+	enum sched_status status = SCHED_S_OK;
+
+	SCHED_MSG_HIGH("sched_restore_client_o_tkn API");
+
+	if (!sched_ctx || !clnt_node) {
+		SCHED_MSG_ERR
+		("Bad input parameters: sched_ctx=%p, clnt_node=%p",
+		sched_ctx, clnt_node);
+		return SCHED_S_EBADPARM;
+	}
+
+	(void)SCHED_CRITSEC_ENTER(clnt_node->data.clnt_cs);
+	status =
+	sched_process_update_clnt_o_tkn(sched_ctx, clnt_node, type,
+					o_tkn);
+	(void)SCHED_CRITSEC_LEAVE(clnt_node->data.clnt_cs);
+	return status;
+}
+
+enum sched_status sched_queue_frame(
+	void *handle, void *client_hdl, void *frm_data)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	struct _sched_clnt_list_node *clnt_node =
+	(struct _sched_clnt_list_node *)client_hdl;
+	enum sched_status status = SCHED_S_OK;
+
+	SCHED_MSG_HIGH("sched_queue_frame API");
+	if (!sched_ctx || !clnt_node) {
+		SCHED_MSG_ERR
+		("Bad input parameters: sched_ctx=%p, clnt_node=%p",
+		sched_ctx, clnt_node);
+		return SCHED_S_EBADPARM;
+	}
+
+	(void)SCHED_CRITSEC_ENTER(clnt_node->data.clnt_cs);
+	status = sched_process_en_q_frm(sched_ctx, clnt_node, frm_data);
+	(void)SCHED_CRITSEC_LEAVE(clnt_node->data.clnt_cs);
+	return status;
+}
+
+enum sched_status sched_re_queue_frame(
+void *handle, void *client_hdl, void *frm_data)
+{
+	struct sched_ctx* sched_ctx = (struct sched_ctx *)handle;
+	struct _sched_clnt_list_node *clnt_node =
+	(struct _sched_clnt_list_node *)client_hdl;
+	enum sched_status status = SCHED_S_OK;
+
+	SCHED_MSG_HIGH("\n sched_re_queue_frame API");
+	if (!sched_ctx || !clnt_node) {
+		SCHED_MSG_ERR("Bad input parameters:"
+		"sched_ctx=%p, clnt_node=%p",
+		sched_ctx, clnt_node);
+		return SCHED_S_EBADPARM;
+	}
+	(void)SCHED_CRITSEC_ENTER(clnt_node->data.clnt_cs);
+	status = sched_process_re_en_q_frm(sched_ctx, clnt_node,
+			frm_data);
+	(void)SCHED_CRITSEC_LEAVE(clnt_node->data.clnt_cs);
+	return status;
+}
+
+enum sched_status sched_de_queue_frame(
+	void *handle, void **pp_frm_data, void **pp_client_data)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	enum sched_status status = SCHED_S_OK;
+
+	SCHED_MSG_HIGH("sched_de_queue_frame API");
+
+	if (!sched_ctx || !pp_frm_data
+		|| !pp_client_data) {
+		SCHED_MSG_ERR("Bad input parameters: sched_ctx=%p, "
+				"pp_frm_data=%p, pp_client_data=%p",
+				sched_ctx, pp_frm_data,
+					pp_client_data);
+		return SCHED_S_EBADPARM;
+	}
+	(void)SCHED_CRITSEC_ENTER(sched_ctx->sched_cs);
+	status =
+	sched_process_de_q_frm(sched_ctx, pp_frm_data, pp_client_data);
+	(void)SCHED_CRITSEC_LEAVE(sched_ctx->sched_cs);
+	return status;
+}
+
+enum sched_status sched_get_client_param(
+	void *handle, void *client_hdl,
+	enum sched_index param_index,
+	union sched_value_type *param_value)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	struct _sched_clnt_list_node *clnt_node =
+	(struct _sched_clnt_list_node *)client_hdl;
+	enum sched_status status;
+
+	SCHED_MSG_HIGH("sched_get_client_param API");
+
+	if (!sched_ctx || !clnt_node ||
+			!param_value) {
+		SCHED_MSG_ERR("Bad input parameters: sched_ctx=%p, "
+				"clnt_node=%p, param_value=%p",
+				sched_ctx, clnt_node,
+				param_value);
+
+		return SCHED_S_EBADPARM;
+	}
+	(void)SCHED_CRITSEC_ENTER(clnt_node->data.clnt_cs);
+	status = sched_process_clnt_lvl_get_param(sched_ctx,
+						&clnt_node->data,
+						param_index, param_value);
+	(void)SCHED_CRITSEC_LEAVE(clnt_node->data.clnt_cs);
+	return status;
+}
+
+enum sched_status sched_set_client_param(
+	void *handle, void *client_hdl,
+	enum sched_index param_index,
+	union sched_value_type *param_value)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	struct _sched_clnt_list_node *clnt_node =
+	    (struct _sched_clnt_list_node *)client_hdl;
+	enum sched_status status;
+
+	SCHED_MSG_HIGH("sched_set_client_param API");
+
+	if (!sched_ctx || !clnt_node ||
+			!param_value) {
+		SCHED_MSG_ERR("Bad input parameters: "
+				"sched_ctx=%p, clnt_node=%p, "
+				"param_value=%p", sched_ctx, clnt_node,
+				param_value);
+		return SCHED_S_EBADPARM;
+	}
+
+	(void)SCHED_CRITSEC_ENTER(sched_ctx->sched_cs);
+	(void)SCHED_CRITSEC_ENTER(clnt_node->data.clnt_cs);
+
+	status = sched_process_clnt_lvl_set_param(sched_ctx,
+			&clnt_node->data, param_index, param_value);
+
+	(void)SCHED_CRITSEC_LEAVE(clnt_node->data.clnt_cs);
+	(void)SCHED_CRITSEC_LEAVE(sched_ctx->sched_cs);
+	return status;
+}
+
+enum sched_status sched_suspend_resume_client(
+	void *handle, void *client_hdl, u32 state)
+{
+	struct sched_ctx *sched_ctx = (struct sched_ctx *)handle;
+	struct _sched_clnt_list_node *clnt_node =
+	(struct _sched_clnt_list_node *)client_hdl;
+	enum sched_status status;
+
+	SCHED_MSG_HIGH("sched_client_suspend_resume API");
+
+	if (!sched_ctx || !clnt_node) {
+		SCHED_MSG_ERR
+		("Bad input parameters: sched_ctx=%p, clnt_node=%p",
+		sched_ctx, clnt_node);
+		return SCHED_S_EBADPARM;
+	}
+
+	(void)SCHED_CRITSEC_ENTER(clnt_node->data.clnt_cs);
+	status =
+	sched_process_suspend_resume_clnt(sched_ctx, clnt_node,
+					state);
+	(void)SCHED_CRITSEC_LEAVE(clnt_node->data.clnt_cs);
+	return status;
+}
diff --git a/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_api.h b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_api.h
new file mode 100644
index 0000000..29e0692
--- /dev/null
+++ b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_api.h
@@ -0,0 +1,150 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _SCHEDULER_API_H_
+#define _SCHEDULER_API_H_
+
+enum sched_status {
+	SCHED_S_OK = 0x0,
+	SCHED_S_NOPTKN,
+	SCHED_S_NOOTKN,
+	SCHED_S_SLEEP,
+	SCHED_S_QEMPTY,
+	SCHED_S_QFULL,
+	SCHED_S_EOF,
+	SCHED_S_EFAIL = 0x64,
+	SCHED_S_ENOMEM,
+	SCHED_S_EBADPARM,
+	SCHED_S_EINVALOP,
+	SCHED_S_ENOTIMPL,
+	SCHED_S_ENORES,
+	SCHED_S_EINVALST,
+	SCHED_S_MAX = 0x7fffffff
+};
+
+enum sched_index {
+	SCHED_I_START_UNUSED = 0x0,
+	SCHED_I_PERFLEVEL,
+	SCHED_I_CLNT_START_UNUSED = 0x63,
+	SCHED_I_CLNT_CURRQLEN,
+	SCHED_I_CLNT_PTKNRATE,
+	SCHED_I_CLNT_PTKNPERFRM,
+	SCHED_I_CLNT_FRAMERATE,
+	SCHED_I_CLNT_OTKNMAX,
+	SCHED_I_CLNT_OTKNPERIPFRM,
+	SCHED_I_CLNT_OTKNCURRENT,
+	SCHED_I_MAX = 0x7fffffff
+};
+
+struct sched_client_frm_rate {
+	u32 numer;
+	u32 denom;
+
+};
+
+union sched_value_type {
+	u32 un_value;
+	struct sched_client_frm_rate frm_rate;
+
+};
+
+struct sched_init_param {
+	u32 perf_lvl;
+
+};
+
+enum sched_client_ctgy {
+	SCHED_CLNT_RT_BUFF = 0,
+	SCHED_CLNT_RT_NOBUFF,
+	SCHED_CLNT_NONRT,
+	SCHED_CLNT_MAX = 0x7fffffff
+};
+
+struct sched_client_init_param {
+	enum sched_client_ctgy client_ctgy;
+	u32 max_queue_len;
+	struct sched_client_frm_rate frm_rate;
+	u32 tkn_per_frm;
+	u32 alloc_p_tkn_rate;
+	u32 o_tkn_max;
+	u32 o_tkn_per_ip_frm;
+	u32 o_tkn_init;
+
+	void *client_data;
+
+};
+
+enum sched_status sched_create
+    (struct sched_init_param *init_param, void **handle);
+
+enum sched_status sched_destroy(void *handle);
+
+enum sched_status sched_get_param
+    (void *handle,
+     enum sched_index param_index, union sched_value_type *param_value);
+
+enum sched_status sched_set_param
+    (void *handle,
+     enum sched_index param_index, union sched_value_type *param_value);
+
+enum sched_status sched_add_client
+    (void *handle,
+     struct sched_client_init_param *init_param, void **client_hdl);
+
+enum sched_status sched_remove_client(void *handle, void *client_hdl);
+
+enum sched_status sched_flush_client_buffer
+    (void *handle, void *client_hdl, void **pp_frm_data);
+
+enum sched_status sched_mark_client_eof(void *handle, void *client_hdl);
+
+enum sched_status sched_update_client_o_tkn
+    (void *handle, void *client_hdl, u32 type, u32 o_tkn);
+
+enum sched_status sched_queue_frame
+    (void *handle, void *client_hdl, void *frm_data);
+enum sched_status sched_re_queue_frame
+(void *handle, void *client_hdl, void *frm_data);
+
+enum sched_status sched_de_queue_frame
+    (void *handle, void **pp_frm_data, void **pp_client_data);
+
+enum sched_status sched_get_client_param
+    (void *handle,
+     void *client_hdl,
+     enum sched_index param_index, union sched_value_type *param_value);
+
+enum sched_status sched_set_client_param
+    (void *handle,
+     void *client_hdl,
+     enum sched_index param_index, union sched_value_type *param_value);
+
+enum sched_status sched_suspend_resume_client
+    (void *handle, void *client_hdl, u32 state);
+
+#endif
diff --git a/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_utils.c b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_utils.c
new file mode 100644
index 0000000..f6a7b83
--- /dev/null
+++ b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_utils.c
@@ -0,0 +1,154 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vid_frame_scheduler_utils.h"
+
+/**
+ * SCHED_ASSERT () - This function is a wrapper to underlying ASSERT
+ * @val: value to be checked for
+ * function.
+ * DEPENDENCIES: None
+ * Returns none
+ */
+SCHED_INLINE void SCHED_ASSERT(int val)
+{
+
+}				/* end of SCHED_ASSERT */
+
+/**
+ * SCHED_MIN () - This function will find minimum of two values
+ * @x: value 1
+ * @y: value 2
+ * DEPENDENCIES: None
+ * Returns none
+ */
+SCHED_INLINE int SCHED_MIN(int x, int y)
+{
+	if (x < y)
+		return x;
+	else
+		return y;
+
+}				/* end of SCHED_MIN */
+
+/**
+ * SCHED_MALLOC () - This function is a wrapper to underlying malloc
+ * @size: memory size to be allocated
+ * function
+ * DEPENDENCIES: None
+ * Returns none
+ */
+SCHED_INLINE void *SCHED_MALLOC(int size)
+{
+	return kmalloc(size, GFP_KERNEL);
+}				/* end of SCHED_MALLOC */
+
+/**
+ * SCHED_FREE () - This function is a wrapper to underlying memory free
+ * @ptr: memory to be freed
+ * function
+ * DEPENDENCIES: None
+ * Returns none
+ */
+SCHED_INLINE void SCHED_FREE(void *ptr)
+{
+	kfree(ptr);
+}				/* end of SCHED_FREE */
+
+/**
+ * SCHED_MEMSET () - This function is a wrapper to underlying memory set
+ * @ptr: ptr to memory
+ * @val: value to be set
+ * @size: memory size to be set
+ * function
+ * DEPENDENCIES: None
+ * Returns none
+ */
+SCHED_INLINE void *SCHED_MEMSET(void *ptr, int val, int size)
+{
+	return memset(ptr, val, size);
+}				/* end of SCHED_MEMSET */
+
+/**
+ * SCHED_GET_CURRENT_TIME () - This function is a wrapper to underlying get time
+ * @pn_time: ptr time value in milliseconds
+ * function
+ * DEPENDENCIES: None
+ * Returns SCHED_S_OK on success
+ */
+SCHED_INLINE enum sched_status SCHED_GET_CURRENT_TIME(u32 *pn_time)
+{
+	struct timeval tv;
+	do_gettimeofday(&tv);
+	*pn_time = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+	return SCHED_S_OK;
+
+}				/* end of SCHED_GET_CURRENT_TIME */
+
+/**
+ * SCHED_CRITSEC_CREATE () - This function is a wrapper to creating a critical
+ * @cs: ptr to a critical section type
+ * section
+ * DEPENDENCIES: None
+ * Returns SCHED_S_OK on success
+ */
+SCHED_INLINE enum sched_status SCHED_CRITSEC_CREATE(u32 **cs)
+{
+	return SCHED_S_OK;
+
+}				/* end of SCHED_CRITSEC_CREATE */
+
+/**
+ * SCHED_CRITSEC_RELEASE () - This function is a wrapper to releasing a critical
+ * @cs: critical section handle type
+ * section resource
+ * DEPENDENCIES: None
+ * Returns SCHED_S_OK on success
+ */
+SCHED_INLINE enum sched_status SCHED_CRITSEC_RELEASE(u32 *cs)
+{
+	return SCHED_S_OK;
+
+}				/* end of SCHED_CRITSEC_RELEASE */
+
+/**
+ * SCHED_CRITSEC_ENTER () - This function is a wrapper to enter a critical
+ * @cs: critical section handle type
+ * section
+ * DEPENDENCIES: None
+ * Returns SCHED_S_OK on success
+ */
+SCHED_INLINE enum sched_status SCHED_CRITSEC_ENTER(u32 *cs)
+{
+	return SCHED_S_OK;
+
+}				/* end of SCHED_CRITSEC_ENTER */
+
+/**
+ * SCHED_CRITSEC_LEAVE () - This function is a wrapper to leave a critical
+ * @cs: critical section handle type
+ * section
+ * DEPENDENCIES: None
+ * Returns SCHED_S_OK on success
+ */
+SCHED_INLINE enum sched_status SCHED_CRITSEC_LEAVE(u32 *cs)
+{
+	return SCHED_S_OK;
+
+}				/* end of SCHED_CRITSEC_LEAVE */
diff --git a/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_utils.h b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_utils.h
new file mode 100644
index 0000000..f5e1d7d
--- /dev/null
+++ b/drivers/misc/video_core/720p/scheduler/vid_frame_scheduler_utils.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _SCHEDULER_UTILS_H_
+#define _SCHEDULER_UTILS_H_
+
+#include "vid_frame_scheduler_api.h"
+
+//TODO lots of low hanging fruit in here
+#define SCHED_INLINE
+
+#if DEBUG
+
+#define SCHED_MSG_LOW(xx_fmt, ...)	printk(KERN_INFO "\n " \
+					xx_fmt, ## __VA_ARGS__)
+#define SCHED_MSG_MED(xx_fmt, ...)	printk(KERN_INFO "\n" \
+					xx_fmt, ## __VA_ARGS__)
+#define SCHED_MSG_HIGH(xx_fmt, ...)	printk(KERN_WARNING "\n" \
+					xx_fmt, ## __VA_ARGS__)
+
+#else
+
+#define SCHED_MSG_LOW(xx_fmt...)
+#define SCHED_MSG_MED(xx_fmt...)
+#define SCHED_MSG_HIGH(xx_fmt...)
+
+#endif
+
+#define SCHED_MSG_ERR(xx_fmt, ...)	printk(KERN_ERR "\n err: " \
+					xx_fmt, ## __VA_ARGS__)
+#define SCHED_MSG_FATAL(xx_fmt, ...)	printk(KERN_ERR "\n<FATAL> " \
+					xx_fmt, ## __VA_ARGS__)
+
+SCHED_INLINE void SCHED_ASSERT(int val);
+
+SCHED_INLINE int SCHED_MIN(int x, int y);
+
+SCHED_INLINE enum sched_status SCHED_CRITSEC_CREATE(u32 **cs);
+
+SCHED_INLINE enum sched_status SCHED_CRITSEC_RELEASE(u32 *cs);
+
+SCHED_INLINE enum sched_status SCHED_CRITSEC_ENTER(u32 *cs);
+
+SCHED_INLINE enum sched_status SCHED_CRITSEC_LEAVE(u32 *cs);
+
+SCHED_INLINE void *SCHED_MALLOC(int size);
+
+SCHED_INLINE void SCHED_FREE(void *ptr);
+
+SCHED_INLINE void *SCHED_MEMSET(void *ptr, int val, int size);
+
+SCHED_INLINE enum sched_status SCHED_GET_CURRENT_TIME(u32 *pn_time);
+
+#endif
diff --git a/drivers/misc/video_core/720p/vcd/vcd.h b/drivers/misc/video_core/720p/vcd/vcd.h
new file mode 100644
index 0000000..1367e7d
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd.h
@@ -0,0 +1,320 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_H_
+#define _VCD_H_
+
+#include "vcd_api.h"
+#include "vid_frame_scheduler_api.h"
+#include "vcd_ddl_api.h"
+#include "vcd_res_tracker_api.h"
+#include "vcd_util.h"
+#include "vcd_client_sm.h"
+#include "vcd_core.h"
+#include "vcd_device_sm.h"
+
+void vcd_reset_device_channels(struct vcd_dev_ctxt *dev_ctxt);
+
+u32 vcd_get_command_channel(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc **pp_transc);
+
+u32 vcd_get_command_channel_in_loop(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc **pp_transc);
+
+void vcd_mark_command_channel(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc);
+
+void vcd_release_command_channel(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc);
+
+void vcd_release_multiple_command_channels(struct vcd_dev_ctxt *dev_ctxt,
+	u32 channels);
+
+void vcd_release_interim_command_channels(struct vcd_dev_ctxt *dev_ctxt);
+
+u32 vcd_get_frame_channel(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc **pp_transc);
+
+u32 vcd_get_frame_channel_in_loop(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc **pp_transc);
+
+void vcd_mark_frame_channel(struct vcd_dev_ctxt *dev_ctxt);
+
+void vcd_release_frame_channel(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc);
+
+void vcd_release_multiple_frame_channels(struct vcd_dev_ctxt *dev_ctxt,
+	u32 channels);
+
+void vcd_release_interim_frame_channels(struct vcd_dev_ctxt *dev_ctxt);
+u32 vcd_core_is_busy(struct vcd_dev_ctxt *dev_ctxt);
+
+void vcd_device_timer_start(struct vcd_dev_ctxt *dev_ctxt);
+void vcd_device_timer_stop(struct vcd_dev_ctxt *dev_ctxt);
+
+u32 vcd_init_device_context(struct vcd_drv_ctxt *drv_ctxt, u32 ev_code);
+
+u32 vcd_deinit_device_context(struct vcd_drv_ctxt *drv_ctxt, u32 ev_code);
+
+u32 vcd_init_client_context(struct vcd_clnt_ctxt *cctxt);
+
+void vcd_destroy_client_context(struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_check_for_client_context(struct vcd_dev_ctxt *dev_ctxt, s32 driver_id);
+
+u32 vcd_validate_driver_handle(struct vcd_dev_ctxt *dev_ctxt,
+	s32 driver_handle);
+
+void vcd_handle_for_last_clnt_close(struct vcd_dev_ctxt *dev_ctxt,
+	u32 send_deinit);
+
+u32 vcd_common_allocate_set_buffer(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_buffer_type buffer, size_t sz,
+	struct vcd_buffer_pool **pp_buf_pool);
+
+u32 vcd_set_buffer_internal(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_buffer_pool *buf_pool, void *buf, size_t sz);
+
+u32 vcd_allocate_buffer_internal(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_buffer_pool *buf_pool, size_t buf_size, void **virt_addr,
+	phys_addr_t *phys_addr);
+
+u32 vcd_free_one_buffer_internal(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_buffer_type vcd_buffer_type, u8 *buffer);
+
+u32 vcd_free_buffers_internal(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_buffer_pool *buf_pool);
+
+u32 vcd_alloc_buffer_pool_entries(struct vcd_buffer_pool *buf_pool,
+	struct vcd_buffer_requirement *buf_req);
+
+void vcd_free_buffer_pool_entries(struct vcd_buffer_pool *buf_pool);
+
+void vcd_flush_in_use_buffer_pool_entries(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_buffer_pool *buf_pool, u32 event);
+
+void vcd_reset_buffer_pool_for_reuse(struct vcd_buffer_pool *buf_pool);
+
+struct vcd_buffer_entry *vcd_get_free_buffer_pool_entry(
+	struct vcd_buffer_pool *pool);
+
+struct vcd_buffer_entry *vcd_find_buffer_pool_entry(struct vcd_buffer_pool
+	*pool, void *virt_addr);
+
+struct vcd_buffer_entry *vcd_buffer_pool_entry_de_q(
+	struct vcd_buffer_pool *pool);
+
+u32 vcd_buffer_pool_entry_en_q(struct vcd_buffer_pool *pool,
+	struct vcd_buffer_entry *entry);
+
+u32 vcd_client_cmd_en_q(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_command_type command);
+
+void vcd_client_cmd_flush_and_en_q(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_command_type command);
+
+u32 vcd_client_cmd_de_q(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_command_type *command);
+
+u32 vcd_handle_recvd_eos(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame, u32 * pb_eos_handled);
+
+u32 vcd_handle_first_decode_frame(struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_add_client_to_sched(struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_handle_input_frame(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame);
+
+u32 vcd_store_seq_hdr(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_sequence_hdr *seq_hdr);
+
+u32 vcd_set_frame_size(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_property_frame_size *frm_size);
+
+u32 vcd_set_frame_rate(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_property_frame_rate *fps);
+
+u32 vcd_calculate_frame_delta(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *frame);
+
+struct vcd_buffer_entry *vcd_check_fill_output_buffer(
+	struct vcd_clnt_ctxt *cctxt, struct vcd_frame_data *buffer);
+
+u32 vcd_requeue_input_frame(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_clnt_ctxt *cctxt, struct vcd_buffer_entry *buf_entry);
+
+u32 vcd_schedule_frame(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_clnt_ctxt **pp_cctxt,
+	struct vcd_buffer_entry **pp_ip_buf_entry);
+
+u32 vcd_map_sched_status(enum sched_status sched_status);
+
+u32 vcd_submit_command_in_continue(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc);
+
+u32 vcd_submit_cmd_sess_start(struct vcd_transc *transc);
+
+u32 vcd_submit_cmd_sess_end(struct vcd_transc *transc);
+
+void vcd_submit_cmd_client_close(struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_submit_frame(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc *transc);
+
+u32 vcd_try_submit_frame_in_continue(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc);
+
+u32 vcd_process_cmd_sess_start(struct vcd_clnt_ctxt *cctxt);
+
+void vcd_try_submit_frame(struct vcd_dev_ctxt *dev_ctxt);
+
+u32 vcd_setup_with_ddl_capabilities(struct vcd_dev_ctxt *dev_ctxt);
+void vcd_handle_submit_frame_failed(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc);
+
+struct vcd_transc *vcd_get_free_trans_tbl_entry(struct vcd_dev_ctxt *dev_ctxt);
+
+void vcd_release_trans_tbl_entry(struct vcd_transc *trans_entry);
+
+void vcd_release_all_clnt_frm_transc(struct vcd_clnt_ctxt *cctxt);
+void vcd_release_all_clnt_def_frm_transc(struct vcd_clnt_ctxt *cctxt);
+void vcd_release_all_clnt_transc(struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_handle_input_done(struct vcd_clnt_ctxt *cctxt, void *payload,
+	u32 event, u32 status);
+
+void vcd_handle_input_done_in_eos(struct vcd_clnt_ctxt *cctxt, void *payload,
+	u32 status);
+
+void vcd_handle_input_done_failed(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_transc *transc);
+
+void vcd_handle_input_done_for_interlacing(struct vcd_clnt_ctxt *cctxt);
+
+void vcd_handle_input_done_with_trans_end(struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_handle_frame_done(struct vcd_clnt_ctxt *cctxt, void *payload,
+	u32 event, u32 status);
+
+void vcd_handle_frame_done_for_interlacing(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_transc *transc_ip1, struct ddl_frame_data_tag *op_frm,
+	u32 status);
+
+u32 vcd_handle_first_frame_done(struct vcd_clnt_ctxt *cctxt, void *payload);
+
+void vcd_handle_frame_done_in_eos(struct vcd_clnt_ctxt *cctxt, void *payload,
+	u32 status);
+
+u32 vcd_handle_first_encode_frame_done(struct vcd_clnt_ctxt *cctxt,
+	void *payload);
+
+u32 vcd_handle_output_required(struct vcd_clnt_ctxt *cctxt, void *payload,
+	u32 status);
+
+u32 vcd_handle_output_required_in_flushing(struct vcd_clnt_ctxt *cctxt,
+	void *payload);
+
+u32 vcd_handle_output_req_tran_end_in_eos(struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_validate_io_done_pyld(void *payload, u32 status);
+
+void vcd_handle_eos_trans_end(struct vcd_clnt_ctxt *cctxt);
+
+void vcd_handle_eos_done(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_transc *transc, u32 status);
+
+void vcd_send_frame_done_in_eos(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame, u32 valid_opbuf);
+
+void vcd_send_frame_done_in_eos_for_dec(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame);
+
+void vcd_send_frame_done_in_eos_for_enc(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame);
+
+void vcd_handle_start_done(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_transc *transc, u32 status);
+
+void vcd_handle_stop_done(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_transc *transc, u32 status);
+
+void vcd_handle_stop_done_in_starting(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_transc *transc, u32 status);
+
+void vcd_handle_stop_done_in_invalid(struct vcd_clnt_ctxt *cctxt, u32 status);
+
+void vcd_send_flush_done(struct vcd_clnt_ctxt *cctxt, u32 status);
+
+void vcd_process_pending_flush_in_eos(struct vcd_clnt_ctxt *cctxt);
+
+void vcd_process_pending_stop_in_eos(struct vcd_clnt_ctxt *cctxt);
+
+void vcd_handle_trans_pending(struct vcd_clnt_ctxt *cctxt);
+
+void vcd_flush_output_buffers(struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_flush_buffers(struct vcd_clnt_ctxt *cctxt, u32 mode);
+void vcd_flush_buffers_in_err_fatal(struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_power_event(struct vcd_dev_ctxt *dev_ctxt, struct vcd_clnt_ctxt *cctxt,
+	u32 event);
+
+u32 vcd_device_power_event(struct vcd_dev_ctxt *dev_ctxt, u32 event,
+	struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_client_power_event(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_clnt_ctxt *cctxt, u32 event);
+
+u32 vcd_enable_clock(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_disable_clock(struct vcd_dev_ctxt *dev_ctxt);
+
+u32 vcd_set_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl,
+	struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_update_clnt_perf_lvl(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_property_frame_rate *fps, u32 frm_p_units);
+
+u32 vcd_gate_clock(struct vcd_dev_ctxt *dev_ctxt);
+
+u32 vcd_un_gate_clock(struct vcd_dev_ctxt *dev_ctxt);
+
+void vcd_handle_err_fatal(struct vcd_clnt_ctxt *cctxt, u32 event, u32 status);
+
+void vcd_handle_device_err_fatal(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_clnt_ctxt *cctxt);
+
+void vcd_clnt_handle_device_err_fatal(struct vcd_clnt_ctxt *cctxt, u32 event);
+
+void vcd_handle_err_in_starting(struct vcd_clnt_ctxt *cctxt, u32 status);
+
+void vcd_handle_ind_hw_err_fatal(struct vcd_clnt_ctxt *cctxt, u32 event,
+	u32 status);
+
+#endif
diff --git a/drivers/misc/video_core/720p/vcd/vcd_api.c b/drivers/misc/video_core/720p/vcd/vcd_api.c
new file mode 100644
index 0000000..202f61d
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_api.c
@@ -0,0 +1,882 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vcd.h"
+
+u32 vcd_init(struct vcd_init_config *config, s32 *driver_handle)
+{
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_drv_ctxt *drv_ctxt;
+
+	VCD_MSG_MED("vcd_init:");
+
+	if (!config || !driver_handle || !config->pf_map_dev_base_addr) {
+		VCD_MSG_ERROR("Bad parameters");
+
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	if (!drv_ctxt->dev_mutex) {
+		drv_ctxt->dev_mutex = kmalloc(sizeof(struct mutex), GFP_KERNEL);
+		if (!drv_ctxt->dev_mutex) {
+			VCD_MSG_ERROR("Failed: vcd_critical_section_create");
+			return VCD_ERR_ALLOC_FAIL;
+		}
+		mutex_init(drv_ctxt->dev_mutex);
+	}
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (drv_ctxt->dev_state.state_table->ev_hdlr.pf_init) {
+		rc = drv_ctxt->dev_state.state_table->ev_hdlr.
+		    pf_init(drv_ctxt, config, driver_handle);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in device state %d\n",
+			      drv_ctxt->dev_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_init);
+
+u32 vcd_term(s32 driver_handle)
+{
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_drv_ctxt *drv_ctxt;
+
+	VCD_MSG_MED("vcd_term:");
+
+	drv_ctxt = vcd_get_drv_context();
+
+	if (!drv_ctxt->dev_mutex) {
+		VCD_MSG_ERROR("No critical section object");
+
+		return VCD_ERR_BAD_STATE;
+	}
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (drv_ctxt->dev_state.state_table->ev_hdlr.pf_term) {
+		rc = drv_ctxt->dev_state.state_table->ev_hdlr.
+		    pf_term(drv_ctxt, driver_handle);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in device state %d\n",
+			      drv_ctxt->dev_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	if (drv_ctxt->dev_state.state == VCD_DEVICE_STATE_NULL) {
+		VCD_MSG_HIGH
+		    ("Device in NULL state. Releasing critical section\n");
+
+		mutex_destroy(drv_ctxt->dev_mutex);
+		kfree(drv_ctxt->dev_mutex);
+		drv_ctxt->dev_mutex = NULL;
+	}
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_term);
+
+u32 vcd_open(s32 driver_handle, u32 decoding,
+	void (*callback) (u32 event, u32 status, void *info, u32 size,
+	void *handle, void *const client_data), void *client_data)
+{
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_drv_ctxt *drv_ctxt;
+
+	VCD_MSG_MED("vcd_open:\n");
+
+	if (!callback) {
+		VCD_MSG_ERROR("Bad parameters\n");
+
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	if (!drv_ctxt->dev_mutex) {
+		VCD_MSG_ERROR("No critical section object\n");
+
+		return VCD_ERR_BAD_STATE;
+	}
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (drv_ctxt->dev_state.state_table->ev_hdlr.pf_open) {
+		rc = drv_ctxt->dev_state.state_table->ev_hdlr.
+		    pf_open(drv_ctxt, driver_handle, decoding, callback,
+			    client_data);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in device state %d\n",
+			      drv_ctxt->dev_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_open);
+
+u32 vcd_close(void *handle)
+{
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_close:");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	if (drv_ctxt->dev_state.state_table->ev_hdlr.pf_close) {
+		rc = drv_ctxt->dev_state.state_table->ev_hdlr.
+		    pf_close(drv_ctxt, cctxt);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in device state %d\n",
+			      drv_ctxt->dev_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_close);
+
+u32 vcd_encode_start(void *handle)
+{
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_encode_start:");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_encode_start &&
+			drv_ctxt->dev_ctxt.pwr_state != VCD_PWR_STATE_SLEEP) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+			pf_encode_start(cctxt);
+	} else {
+		VCD_MSG_ERROR
+		    ("Unsupported API dev power state %d OR client state %d\n",
+		     drv_ctxt->dev_ctxt.pwr_state,
+		     cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_encode_start);
+
+u32 vcd_encode_frame(void *handle, struct vcd_frame_data *input_frame)
+{
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_encode_frame:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (!input_frame) {
+		VCD_MSG_ERROR("Bad parameters\n");
+
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_encode_frame) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_encode_frame(cctxt, input_frame);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_encode_frame);
+
+u32 vcd_decode_start(void *handle, struct vcd_sequence_hdr *seq_hdr)
+{
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_decode_start:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_decode_start &&
+	    drv_ctxt->dev_ctxt.pwr_state != VCD_PWR_STATE_SLEEP) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_decode_start(cctxt, seq_hdr);
+	} else {
+		VCD_MSG_ERROR
+		    ("Unsupported API dev power state %d OR client state %d\n",
+		     drv_ctxt->dev_ctxt.pwr_state,
+		     cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_decode_start);
+
+u32 vcd_decode_frame(void *handle, struct vcd_frame_data *input_frame)
+{
+	struct vcd_clnt_ctxt *cctxt =
+	    (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_decode_frame:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (!input_frame) {
+		VCD_MSG_ERROR("Bad parameters\n");
+
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_decode_frame) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_decode_frame(cctxt, input_frame);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_decode_frame);
+
+u32 vcd_pause(void *handle)
+{
+	struct vcd_drv_ctxt *drv_ctxt;
+	struct vcd_clnt_ctxt *cctxt =
+	    (struct vcd_clnt_ctxt *)handle;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_pause:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_pause) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_pause(cctxt);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_pause);
+
+u32 vcd_resume(void *handle)
+{
+	struct vcd_drv_ctxt *drv_ctxt;
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_resume:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (drv_ctxt->dev_state.state_table->ev_hdlr.pf_resume &&
+	    drv_ctxt->dev_ctxt.pwr_state != VCD_PWR_STATE_SLEEP) {
+		rc = drv_ctxt->dev_state.state_table->ev_hdlr.
+		    pf_resume(drv_ctxt, cctxt);
+	} else {
+		VCD_MSG_ERROR
+		    ("Unsupported API dev power state %d OR client state %d\n",
+		     drv_ctxt->dev_ctxt.pwr_state,
+		     cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_resume);
+
+u32 vcd_flush(void *handle, u32 mode)
+{
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_flush:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_flush) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_flush(cctxt, mode);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_flush);
+
+u32 vcd_stop(void *handle)
+{
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_stop:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_stop &&
+	    drv_ctxt->dev_ctxt.pwr_state != VCD_PWR_STATE_SLEEP) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_stop(cctxt);
+	} else {
+		VCD_MSG_ERROR
+		    ("Unsupported API dev power state %d OR client state %d\n",
+		     drv_ctxt->dev_ctxt.pwr_state,
+		     cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_stop);
+
+u32 vcd_set_property(void *handle, struct vcd_property_hdr *prop_hdr,
+	void *prop_val)
+{
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_set_property:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (!prop_hdr || !prop_val) {
+		VCD_MSG_ERROR("Bad parameters\n");
+
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_set_property) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_set_property(cctxt, prop_hdr, prop_val);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_set_property);
+
+u32 vcd_get_property(void *handle, struct vcd_property_hdr *prop_hdr,
+	void *prop_val)
+{
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_get_property:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (!prop_hdr || !prop_val) {
+		VCD_MSG_ERROR("Bad parameters\n");
+
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_get_property) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_get_property(cctxt, prop_hdr, prop_val);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_get_property);
+
+u32 vcd_set_buffer_requirements(void *handle, enum vcd_buffer_type buffer_type,
+	struct vcd_buffer_requirement *buffer_req)
+{
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_set_buffer_requirements:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (!buffer_req) {
+		VCD_MSG_ERROR("Bad parameters\n");
+
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.
+	    pf_set_buffer_requirements) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_set_buffer_requirements(cctxt, buffer_type, buffer_req);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_set_buffer_requirements);
+
+u32 vcd_get_buffer_requirements(void *handle, enum vcd_buffer_type buffer_type,
+	struct vcd_buffer_requirement *buffer_req)
+{
+	struct vcd_clnt_ctxt *cctxt = (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_get_buffer_requirements:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (!buffer_req) {
+		VCD_MSG_ERROR("Bad parameters\n");
+
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.
+	    pf_get_buffer_requirements) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_get_buffer_requirements(cctxt, buffer_type, buffer_req);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_get_buffer_requirements);
+
+u32 vcd_set_buffer(void *handle, enum vcd_buffer_type buffer_type, void *buffer,
+	size_t buf_size)
+{
+	struct vcd_clnt_ctxt *cctxt = handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_set_buffer:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (!buffer || !buf_size) {
+		VCD_MSG_ERROR("Bad parameters\n");
+
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_set_buffer) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_set_buffer(cctxt, buffer_type, buffer, buf_size);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_set_buffer);
+
+u32 vcd_allocate_buffer(void *handle, enum vcd_buffer_type buffer_type,
+	size_t sz, void **virt_addr, phys_addr_t *phys_addr)
+{
+	struct vcd_clnt_ctxt *cctxt = handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_allocate_buffer:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (!virt_addr || !phys_addr || !sz) {
+		VCD_MSG_ERROR("Bad parameters\n");
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_allocate_buffer) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.pf_allocate_buffer(
+			cctxt, buffer_type, sz, virt_addr, phys_addr);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_allocate_buffer);
+
+u32 vcd_free_buffer(void *handle, enum vcd_buffer_type buffer_type, void *buf)
+{
+	struct vcd_clnt_ctxt *cctxt = handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_free_buffer:");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_free_buffer) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_free_buffer(cctxt, buffer_type, buf);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			cctxt->clnt_state.state);
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_free_buffer);
+
+u32 vcd_fill_output_buffer(void *handle, struct vcd_frame_data *buffer)
+{
+	struct vcd_clnt_ctxt *cctxt =
+	    (struct vcd_clnt_ctxt *)handle;
+	struct vcd_drv_ctxt *drv_ctxt;
+	u32 rc;
+
+	VCD_MSG_MED("vcd_fill_output_buffer:\n");
+
+	if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
+		VCD_MSG_ERROR("Bad client handle\n");
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (!buffer) {
+		VCD_MSG_ERROR("Bad parameters\n");
+
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_fill_output_buffer) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+		    pf_fill_output_buffer(cctxt, buffer);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d\n",
+			      cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_fill_output_buffer);
+
+u32 vcd_set_device_power(s32 driver_handle, enum vcd_power_state pwr_state)
+{
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_drv_ctxt *drv_ctxt;
+
+	VCD_MSG_MED("vcd_set_device_power:\n");
+
+	drv_ctxt = vcd_get_drv_context();
+
+	if (!drv_ctxt->dev_mutex) {
+		VCD_MSG_ERROR("No critical section object\n");
+
+		return VCD_ERR_BAD_STATE;
+	}
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (drv_ctxt->dev_state.state_table->ev_hdlr.pf_set_dev_pwr) {
+		rc = drv_ctxt->dev_state.state_table->ev_hdlr.
+		    pf_set_dev_pwr(drv_ctxt, pwr_state);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in device state %d\n",
+			      drv_ctxt->dev_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	mutex_unlock(drv_ctxt->dev_mutex);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(vcd_set_device_power);
+
+void vcd_read_and_clear_interrupt(void)
+{
+	VCD_MSG_LOW("vcd_read_and_clear_interrupt:\n");
+	ddl_read_and_clear_interrupt();
+}
+
+
+void vcd_response_handler(void)
+{
+	struct vcd_drv_ctxt *drv_ctxt;
+
+	VCD_MSG_LOW("vcd_response_handler:\n");
+	drv_ctxt = vcd_get_drv_context();
+
+	mutex_lock(drv_ctxt->dev_mutex);
+
+	if (!ddl_process_core_response()) {
+		VCD_MSG_HIGH("ddl_process_core_response indicated no further"
+			"processing\n");
+		mutex_unlock(drv_ctxt->dev_mutex);
+		return;
+	}
+
+	if (drv_ctxt->dev_ctxt.cont)
+		vcd_continue();
+	mutex_unlock(drv_ctxt->dev_mutex);
+}
+EXPORT_SYMBOL(vcd_response_handler);
+
+
+
+
+
+
diff --git a/drivers/misc/video_core/720p/vcd/vcd_api.h b/drivers/misc/video_core/720p/vcd/vcd_api.h
new file mode 100644
index 0000000..4368331
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_api.h
@@ -0,0 +1,153 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_API_H_
+#define _VCD_API_H_
+#include "vcd_property.h"
+#include "vcd_status.h"
+
+#define VCD_FRAME_FLAG_EOS 0x00000001
+#define VCD_FRAME_FLAG_ENDOFFRAME 0x00000010
+#define VCD_FRAME_FLAG_SYNCFRAME 0x00000020
+#define VCD_FRAME_FLAG_EXTRADATA 0x00000040
+#define VCD_FRAME_FLAG_CODECCONFIG  0x00000080
+
+#define VCD_FLUSH_INPUT   0x0001
+#define VCD_FLUSH_OUTPUT  0x0002
+#define VCD_FLUSH_ALL     0x0003
+
+#define VCD_FRAMETAG_INVALID  0xffffffff
+
+struct vcd_handle_container {
+	void *handle;
+};
+struct vcd_flush_cmd {
+	u32 mode;
+};
+
+enum vcd_frame {
+	VCD_FRAME_YUV = 1,
+	VCD_FRAME_I,
+	VCD_FRAME_P,
+	VCD_FRAME_B,
+	VCD_FRAME_32BIT = 0x7fffffff
+};
+
+enum vcd_power_state {
+	VCD_PWR_STATE_ON = 1,
+	VCD_PWR_STATE_SLEEP,
+};
+
+struct vcd_frame_data {
+	void *virt_addr;
+	phys_addr_t phys_addr;
+	size_t alloc_len;
+	size_t data_len;
+	size_t offset;
+	s64 time_stamp;
+	u32 flags;
+	void *client_data;
+	struct vcd_property_dec_output_buffer dec_op_prop;
+	u32 interlaced;
+	enum vcd_frame frame_type;
+	u32 ip_frm_tag;
+};
+
+struct vcd_phys_sequence_hdr {
+	phys_addr_t addr;
+	size_t sz;
+};
+
+struct vcd_sequence_hdr {
+	void *addr;
+	size_t sz;
+};
+
+enum vcd_buffer_type {
+	VCD_BUFFER_INPUT = 0x1,
+	VCD_BUFFER_OUTPUT = 0x2,
+	VCD_BUFFER_INVALID = 0x3,
+	VCD_BUFFER_32BIT = 0x7FFFFFFF
+};
+
+struct vcd_buffer_requirement {
+	u32 min_count;
+	u32 actual_count;
+	u32 max_count;
+	size_t size;
+	u32 align;
+	u32 buf_pool_id;
+};
+
+struct vcd_init_config {
+	void *device_name;
+	void *(*pf_map_dev_base_addr) (void *device_name);
+	void (*pf_un_map_dev_base_addr) (void);
+	void (*pf_interrupt_clr) (void);
+	void (*pf_register_isr) (void *device_name);
+	void (*pf_deregister_isr) (void);
+	u32  (*pf_timer_create) (void (*pf_timer_handler)(void *),
+		void *user_data, void **pp_timer_handle);
+	void (*pf_timer_release) (void *timer_handle);
+	void (*pf_timer_start) (void *timer_handle, u32 time_out);
+	void (*pf_timer_stop) (void *timer_handle);
+};
+
+u32 vcd_init(struct vcd_init_config *config, s32 *driver_handle);
+u32 vcd_term(s32 driver_handle);
+u32 vcd_open(s32 driver_handle, u32 decoding,
+	void (*callback) (u32 event, u32 status, void *info, u32 size,
+	void *handle, void *const client_data), void *client_data);
+u32 vcd_close(void *handle);
+u32 vcd_encode_start(void *handle);
+u32 vcd_encode_frame(void *handle, struct vcd_frame_data *input_frame);
+u32 vcd_decode_start(void *handle, struct vcd_sequence_hdr *seq_hdr);
+u32 vcd_decode_frame(void *handle, struct vcd_frame_data *input_frame);
+u32 vcd_pause(void *handle);
+u32 vcd_resume(void *handle);
+u32 vcd_flush(void *handle, u32 mode);
+u32 vcd_stop(void *handle);
+u32 vcd_set_property(void *handle, struct vcd_property_hdr *prop_hdr,
+	void *prop_val);
+u32 vcd_get_property(void *handle, struct vcd_property_hdr *prop_hdr,
+	void *prop_val);
+u32 vcd_set_buffer_requirements(void *handle, enum vcd_buffer_type buffer_type,
+	struct vcd_buffer_requirement *buffer_req);
+u32 vcd_get_buffer_requirements(void *handle, enum vcd_buffer_type buffer_type,
+	struct vcd_buffer_requirement *buffer_req);
+u32 vcd_set_buffer(void *handle, enum vcd_buffer_type buffer_type,
+	void *buffer, size_t buf_size);
+u32 vcd_allocate_buffer(void *handle, enum vcd_buffer_type buffer_type,
+	size_t sz, void **virt_addr, phys_addr_t *phys_addr);
+u32 vcd_free_buffer(void *handle, enum vcd_buffer_type buffer_type, void *buf);
+u32 vcd_fill_output_buffer(void *handle, struct vcd_frame_data *buffer);
+u32 vcd_set_device_power(s32 driver_handle, enum vcd_power_state pwr_state);
+void vcd_read_and_clear_interrupt(void);
+void vcd_response_handler(void);
+
+#endif
diff --git a/drivers/misc/video_core/720p/vcd/vcd_client_sm.c b/drivers/misc/video_core/720p/vcd/vcd_client_sm.c
new file mode 100644
index 0000000..4617f80
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_client_sm.c
@@ -0,0 +1,1499 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vcd.h"
+
+static const struct vcd_clnt_state_table *vcd_clnt_state_table[];
+
+void vcd_clnt_handle_device_err_fatal(struct vcd_clnt_ctxt *cctxt, u32 event)
+{
+	if (cctxt->clnt_state.state != VCD_CLIENT_STATE_INVALID) {
+		cctxt->callback(event, VCD_ERR_HW_FATAL, NULL, 0,
+			cctxt, cctxt->client_data);
+		vcd_flush_buffers_in_err_fatal(cctxt);
+		vcd_do_client_state_transition(cctxt,
+			VCD_CLIENT_STATE_INVALID,
+			CLIENT_STATE_EVENT_NUMBER(pf_clnt_cb));
+	}
+}
+
+static u32 vcd_close_in_open(struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_close_in_open:");
+	if (cctxt->in_buf_pool.allocated || cctxt->out_buf_pool.allocated) {
+		VCD_MSG_ERROR("Allocated buffers are not freed yet\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	vcd_destroy_client_context(cctxt);
+	return rc;
+}
+
+static u32  vcd_close_in_invalid(struct vcd_clnt_ctxt *cctxt)
+{
+	VCD_MSG_LOW("vcd_close_in_invalid:\n");
+	if (cctxt->in_buf_pool.allocated || cctxt->out_buf_pool.allocated) {
+		VCD_MSG_ERROR("Allocated buffers are not freed yet\n");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	if (cctxt->status.cleaning_up)
+		cctxt->status.close_pending = true;
+	else
+		vcd_destroy_client_context(cctxt);
+	return VCD_S_SUCCESS;
+}
+
+static u32 vcd_start_in_run_cmn(struct vcd_clnt_ctxt *cctxt)
+{
+	VCD_MSG_LOW("vcd_start_in_run_cmn:\n");
+	cctxt->callback(VCD_EVT_RESP_START, VCD_S_SUCCESS, NULL, 0, cctxt,
+		cctxt->client_data);
+	return VCD_S_SUCCESS;
+}
+
+static u32 vcd_encode_start_in_open(struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_property_hdr prop_hdr;
+	struct vcd_property_vop_timing timing;
+
+	VCD_MSG_LOW("vcd_encode_start_in_open:\n");
+
+	if (cctxt->decoding) {
+		VCD_MSG_ERROR("vcd_encode_init for decoder client\n");
+
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	if (!cctxt->in_buf_pool.entries || !cctxt->out_buf_pool.entries ||
+			cctxt->in_buf_pool.validated !=
+			cctxt->in_buf_pool.count ||
+			cctxt->out_buf_pool.validated !=
+			cctxt->out_buf_pool.count) {
+		VCD_MSG_ERROR("Buffer pool is not completely setup yet\n");
+
+		return VCD_ERR_BAD_STATE;
+	}
+
+	rc = vcd_add_client_to_sched(cctxt);
+
+	VCD_FAILED_RETURN(rc, "Failed: vcd_add_client_to_sched\n");
+
+	prop_hdr.id = VCD_I_VOP_TIMING;
+	prop_hdr.sz = sizeof(struct vcd_property_vop_timing);
+	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &timing);
+
+	VCD_FAILED_RETURN(rc, "Failed: Get VCD_I_VOP_TIMING\n");
+	if (!timing.vop_time_resolution) {
+		VCD_MSG_ERROR("Vop_time_resolution value is zero\n");
+		return VCD_ERR_FAIL;
+	}
+	cctxt->time_resoln = timing.vop_time_resolution;
+
+	rc = vcd_process_cmd_sess_start(cctxt);
+
+	if (!VCD_FAILED(rc)) {
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_STARTING,
+			CLIENT_STATE_EVENT_NUMBER(pf_encode_start));
+	}
+
+	return rc;
+}
+
+static u32  vcd_encode_start_in_run(struct vcd_clnt_ctxt *cctxt)
+{
+	VCD_MSG_LOW("vcd_encode_start_in_run:\n");
+	vcd_start_in_run_cmn(cctxt);
+	return VCD_S_SUCCESS;
+}
+
+
+static u32 vcd_encode_frame_cmn(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame)
+{
+	VCD_MSG_LOW("vcd_encode_frame_cmn in %d:", cctxt->clnt_state.state);
+
+	if (cctxt->decoding) {
+		VCD_MSG_ERROR("vcd_encode_frame for decoder client\n");
+
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	return vcd_handle_input_frame(cctxt, input_frame);
+}
+
+static u32 vcd_decode_start_in_open(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_sequence_hdr *seq_hdr)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_decode_start_in_open:\n");
+
+	if (!cctxt->decoding) {
+		VCD_MSG_ERROR("vcd_decode_init for encoder client\n");
+
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	if (seq_hdr) {
+		VCD_MSG_HIGH("Seq hdr supplied. len = %d\n", seq_hdr->sz);
+		rc = vcd_store_seq_hdr(cctxt, seq_hdr);
+
+	} else {
+		VCD_MSG_HIGH("Seq hdr not supplied\n");
+		cctxt->seq_hdr.sz = 0;
+		cctxt->seq_hdr.addr = NULL;
+	}
+
+	VCD_FAILED_RETURN(rc, "Err processing seq hdr\n");
+
+	rc = vcd_process_cmd_sess_start(cctxt);
+
+	if (!VCD_FAILED(rc)) {
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_STARTING,
+			CLIENT_STATE_EVENT_NUMBER(pf_decode_start));
+	}
+
+	return rc;
+}
+
+static u32 vcd_decode_start_in_run(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_sequence_hdr *seqhdr)
+{
+	VCD_MSG_LOW("vcd_decode_start_in_run:\n");
+	vcd_start_in_run_cmn(cctxt);
+	return VCD_S_SUCCESS;
+}
+
+static u32 vcd_decode_frame_cmn(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame)
+{
+	VCD_MSG_LOW("vcd_decode_frame_cmn in %d:\n", cctxt->clnt_state.state);
+
+	if (!cctxt->decoding) {
+		VCD_MSG_ERROR("Decode_frame api called for Encoder client\n");
+
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	return vcd_handle_input_frame(cctxt, input_frame);
+}
+
+static u32 vcd_pause_in_run(struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_pause_in_run:\n");
+
+	if (cctxt->sched_clnt_valid) {
+		rc = vcd_map_sched_status(sched_suspend_resume_client(
+			cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+			false));
+	}
+
+	VCD_FAILED_RETURN(rc, "Failed: sched_suspend_resume_client\n");
+
+	if (cctxt->status.frame_submitted > 0) {
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_PAUSING,
+			CLIENT_STATE_EVENT_NUMBER(pf_pause));
+
+	} else {
+		VCD_MSG_HIGH("No client frames are currently being processed\n");
+
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_PAUSED,
+			CLIENT_STATE_EVENT_NUMBER(pf_pause));
+
+		cctxt->callback(VCD_EVT_RESP_PAUSE, VCD_S_SUCCESS, NULL, 0,
+			cctxt, cctxt->client_data);
+
+		rc = vcd_power_event(cctxt->dev_ctxt, cctxt,
+			VCD_EVT_PWR_CLNT_PAUSE);
+
+		if (VCD_FAILED(rc))
+			VCD_MSG_ERROR("VCD_EVT_PWR_CLNT_PAUSE_END failed\n");
+
+	}
+
+	return VCD_S_SUCCESS;
+}
+
+static u32 vcd_resume_in_paused(struct vcd_clnt_ctxt *cctxt)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_resume_in_paused:\n");
+
+	if (cctxt->sched_clnt_valid) {
+
+		rc = vcd_power_event(cctxt->dev_ctxt, cctxt,
+			VCD_EVT_PWR_CLNT_RESUME);
+
+		if (VCD_FAILED(rc)) {
+			VCD_MSG_ERROR("VCD_EVT_PWR_CLNT_RESUME failed\n");
+		} else {
+			rc = vcd_map_sched_status(sched_suspend_resume_client(
+				cctxt->dev_ctxt->sched_hdl,
+				cctxt->sched_clnt_hdl, true));
+			if (VCD_FAILED(rc)) {
+				VCD_MSG_ERROR("rc = 0x%x. Failed: "
+				     "sched_suspend_resume_client\n", rc);
+			}
+
+		}
+		if (!VCD_FAILED(rc))
+			vcd_try_submit_frame(dev_ctxt);
+	}
+
+	if (!VCD_FAILED(rc)) {
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_RUN,
+			CLIENT_STATE_EVENT_NUMBER(pf_resume));
+	}
+
+	return rc;
+}
+
+static u32 vcd_flush_cmn(struct vcd_clnt_ctxt *cctxt, u32 mode)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_flush_cmn in %d:\n", cctxt->clnt_state.state);
+
+	rc = vcd_flush_buffers(cctxt, mode);
+
+	VCD_FAILED_RETURN(rc, "Failed: vcd_flush_buffers\n");
+
+	if (cctxt->status.frame_submitted > 0) {
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_FLUSHING,
+			CLIENT_STATE_EVENT_NUMBER(pf_flush));
+	} else {
+		VCD_MSG_HIGH("All buffers are flushed\n");
+		cctxt->status.flush_mode = mode;
+		vcd_send_flush_done(cctxt, VCD_S_SUCCESS);
+	}
+
+	return rc;
+}
+
+static u32  vcd_flush_inopen(struct vcd_clnt_ctxt *cctxt, u32 mode)
+{
+	VCD_MSG_LOW("vcd_flush_inopen:\n");
+	cctxt->status.flush_mode = mode;
+	vcd_send_flush_done(cctxt, VCD_S_SUCCESS);
+	return VCD_S_SUCCESS;
+}
+
+static u32 vcd_flush_in_flushing(struct vcd_clnt_ctxt *cctxt, u32 mode)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_flush_in_flushing:\n");
+
+	rc = vcd_flush_buffers(cctxt, mode);
+
+	return rc;
+}
+
+static u32 vcd_flush_in_eos(struct vcd_clnt_ctxt *cctxt, u32 mode)
+{
+	VCD_MSG_LOW("vcd_flush_in_eos:\n");
+
+	if (mode > VCD_FLUSH_ALL || !mode) {
+		VCD_MSG_ERROR("Invalid flush mode %d\n", mode);
+
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+
+	VCD_MSG_MED("Flush mode requested %d\n", mode);
+
+	cctxt->status.flush_mode |= mode;
+
+	return VCD_S_SUCCESS;
+}
+
+static u32 vcd_flush_in_invalid(struct vcd_clnt_ctxt *cctxt, u32 mode)
+{
+	u32 rc = VCD_S_SUCCESS;
+	VCD_MSG_LOW("vcd_flush_in_invalid:\n");
+	if (!cctxt->status.cleaning_up) {
+		rc = vcd_flush_buffers(cctxt, mode);
+		if (!VCD_FAILED(rc)) {
+			VCD_MSG_HIGH("All buffers are flushed\n");
+			cctxt->status.flush_mode = mode;
+			vcd_send_flush_done(cctxt, VCD_S_SUCCESS);
+		}
+	}
+	return rc;
+}
+
+static u32 vcd_stop_cmn(struct vcd_clnt_ctxt *cctxt)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_transc *transc;
+
+	VCD_MSG_LOW("vcd_stop_cmn in %d:\n", cctxt->clnt_state.state);
+
+	rc = vcd_flush_buffers(cctxt, VCD_FLUSH_ALL);
+
+	VCD_FAILED_RETURN(rc, "Failed: vcd_flush_buffers\n");
+
+	if (!cctxt->status.frame_submitted) {
+
+		if (vcd_get_command_channel(dev_ctxt, &transc)) {
+			rc = vcd_power_event(dev_ctxt, cctxt,
+				VCD_EVT_PWR_CLNT_CMD_BEGIN);
+
+			if (!VCD_FAILED(rc)) {
+				transc->type = VCD_CMD_CODEC_STOP;
+				transc->cctxt = cctxt;
+
+				rc = vcd_submit_cmd_sess_end(transc);
+			} else {
+				VCD_MSG_ERROR("Failed:"
+					" VCD_EVT_PWR_CLNT_CMD_BEGIN\n");
+			}
+
+			if (VCD_FAILED(rc))
+				vcd_release_command_channel(dev_ctxt, transc);
+
+		} else {
+			vcd_client_cmd_flush_and_en_q(cctxt,
+				VCD_CMD_CODEC_STOP);
+		}
+	}
+
+	if (VCD_FAILED(rc)) {
+		vcd_power_event(dev_ctxt, cctxt, VCD_EVT_PWR_CLNT_CMD_FAIL);
+	} else {
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_STOPPING,
+			CLIENT_STATE_EVENT_NUMBER(pf_stop));
+	}
+
+	return rc;
+}
+
+
+static u32  vcd_stop_inopen(struct vcd_clnt_ctxt *cctxt)
+{
+	VCD_MSG_LOW("vcd_stop_inopen:\n");
+
+	cctxt->callback(VCD_EVT_RESP_STOP, VCD_S_SUCCESS, NULL, 0, cctxt,
+		cctxt->client_data);
+
+	return VCD_S_SUCCESS;
+}
+
+static u32 vcd_stop_in_run(struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_stop_in_run:\n");
+
+	rc = vcd_stop_cmn(cctxt);
+
+	if (!VCD_FAILED(rc) && cctxt->status.b1st_frame_recvd) {
+		rc = vcd_power_event(cctxt->dev_ctxt, cctxt,
+			VCD_EVT_PWR_CLNT_LAST_FRAME);
+	}
+
+	return rc;
+}
+
+static u32 vcd_stop_in_eos(struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_stop_in_eos:\n");
+
+	cctxt->status.stop_pending = true;
+
+	return rc;
+}
+
+static u32  vcd_stop_in_invalid(struct vcd_clnt_ctxt *cctxt)
+{
+	VCD_MSG_LOW("vcd_stop_in_invalid:\n");
+	if (cctxt->status.cleaning_up) {
+		cctxt->status.stop_pending = true;
+	} else {
+		vcd_flush_buffers(cctxt, VCD_FLUSH_ALL);
+		cctxt->callback(VCD_EVT_RESP_STOP, VCD_S_SUCCESS, NULL, 0,
+			cctxt, cctxt->client_data);
+	}
+	return VCD_S_SUCCESS;
+}
+
+static u32 vcd_set_property_cmn(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_property_hdr *prop_hdr, void *prop_val)
+{
+	u32 rc;
+
+	VCD_MSG_LOW("vcd_set_property_cmn in %d:\n", cctxt->clnt_state.state);
+	VCD_MSG_LOW("property Id = %d\n", prop_hdr->id);
+
+	if (!prop_hdr->sz || !prop_hdr->id) {
+		VCD_MSG_MED("Bad parameters\n");
+
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+
+	rc = ddl_set_property(cctxt->ddl_handle, prop_hdr, prop_val);
+
+	VCD_FAILED_RETURN(rc, "Failed: ddl_set_property\n");
+
+	switch (prop_hdr->id) {
+	case VCD_I_LIVE:
+	{
+		struct vcd_property_live *live = (struct vcd_property_live *)
+			prop_val;
+		cctxt->live = live->live;
+		break;
+	}
+	case VCD_I_FRAME_RATE:
+		if (cctxt->sched_clnt_valid) {
+			rc = vcd_set_frame_rate(cctxt,
+				(struct vcd_property_frame_rate *)prop_val);
+		}
+		break;
+	case VCD_I_FRAME_SIZE:
+		if (cctxt->sched_clnt_valid) {
+			rc = vcd_set_frame_size(cctxt,
+				(struct vcd_property_frame_size *)prop_val);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+static u32 vcd_get_property_cmn(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_property_hdr *prop_hdr, void *prop_val)
+{
+	VCD_MSG_LOW("vcd_get_property_cmn in %d:\n", cctxt->clnt_state.state);
+	VCD_MSG_LOW("property id = %d\n", prop_hdr->id);
+	if (!prop_hdr->sz || !prop_hdr->id) {
+		VCD_MSG_MED("Bad parameters\n");
+
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+	return ddl_get_property(cctxt->ddl_handle, prop_hdr, prop_val);
+}
+
+static u32 vcd_set_buffer_requirements_cmn(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_buffer_type vcd_buffer_type,
+	struct vcd_buffer_requirement *buffer_req)
+{
+	struct vcd_property_hdr prop_hdr;
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_buffer_pool *buf_pool;
+
+	VCD_MSG_LOW("vcd_set_buffer_requirements_cmn in %d:\n",
+		    cctxt->clnt_state.state);
+
+	if (!cctxt->decoding && cctxt->clnt_state.state !=
+			VCD_CLIENT_STATE_OPEN) {
+		VCD_MSG_ERROR("Bad state (%d) for encoder\n",
+			cctxt->clnt_state.state);
+
+		return VCD_ERR_BAD_STATE;
+	}
+
+	VCD_MSG_MED("Buffer type = %d\n", vcd_buffer_type);
+
+	if (vcd_buffer_type == VCD_BUFFER_INPUT) {
+		prop_hdr.id = DDL_I_INPUT_BUF_REQ;
+		buf_pool = &cctxt->in_buf_pool;
+	} else if (vcd_buffer_type == VCD_BUFFER_OUTPUT) {
+		prop_hdr.id = DDL_I_OUTPUT_BUF_REQ;
+		buf_pool = &cctxt->out_buf_pool;
+	} else {
+		rc = VCD_ERR_ILLEGAL_PARM;
+	}
+
+	VCD_FAILED_RETURN(rc, "Invalid buffer type provided\n");
+
+	if (buf_pool->validated > 0) {
+		VCD_MSG_ERROR("Need to free allocated buffers\n");
+
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	prop_hdr.sz = sizeof(*buffer_req);
+
+	rc = ddl_set_property(cctxt->ddl_handle, &prop_hdr, buffer_req);
+
+	VCD_FAILED_RETURN(rc, "Failed: ddl_set_property\n");
+
+	if (buf_pool->entries) {
+		VCD_MSG_MED("Resetting buffer requirements\n");
+
+		vcd_free_buffer_pool_entries(buf_pool);
+	}
+
+	rc = vcd_alloc_buffer_pool_entries(buf_pool, buffer_req);
+
+	return rc;
+}
+
+static u32 vcd_get_buffer_requirements_cmn(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_buffer_type vcd_buffer_type,
+	struct vcd_buffer_requirement *buffer_req)
+{
+	struct vcd_property_hdr prop_hdr;
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_get_buffer_requirements_cmn in %d:\n",
+		    cctxt->clnt_state.state);
+
+	VCD_MSG_MED("Buffer type = %d\n", vcd_buffer_type);
+
+	if (vcd_buffer_type == VCD_BUFFER_INPUT)
+		prop_hdr.id = DDL_I_INPUT_BUF_REQ;
+	else if (vcd_buffer_type == VCD_BUFFER_OUTPUT)
+		prop_hdr.id = DDL_I_OUTPUT_BUF_REQ;
+	else
+		rc = VCD_ERR_ILLEGAL_PARM;
+
+	VCD_FAILED_RETURN(rc, "Invalid buffer type provided\n");
+
+	prop_hdr.sz = sizeof(*buffer_req);
+
+	return ddl_get_property(cctxt->ddl_handle, &prop_hdr, buffer_req);
+
+}
+
+static u32 vcd_set_buffer_cmn(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_buffer_type vcd_buffer_type, void *buf, size_t sz)
+{
+	u32 rc;
+	struct vcd_buffer_pool *buf_pool;
+
+	VCD_MSG_LOW("vcd_set_buffer_cmn in %d:\n", cctxt->clnt_state.state);
+
+	rc = vcd_common_allocate_set_buffer(cctxt, vcd_buffer_type, sz,
+		&buf_pool);
+
+	if (!VCD_FAILED(rc)) {
+		rc = vcd_set_buffer_internal(cctxt, buf_pool, buf, sz);
+	}
+
+	return rc;
+}
+
+static u32 vcd_allocate_buffer_cmn(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_buffer_type vcd_buffer_type, size_t sz, void **virt_addr,
+	phys_addr_t *phys_addr)
+{
+	u32 rc;
+	struct vcd_buffer_pool *buf_pool;
+
+	VCD_MSG_LOW("vcd_allocate_buffer_cmn in %d:\n",
+		    cctxt->clnt_state.state);
+
+	rc = vcd_common_allocate_set_buffer(cctxt, vcd_buffer_type, sz,
+		&buf_pool);
+
+	if (!VCD_FAILED(rc)) {
+		rc = vcd_allocate_buffer_internal(cctxt, buf_pool, sz,
+			virt_addr, phys_addr);
+	}
+
+	return rc;
+}
+
+static u32 vcd_free_buffer_cmn(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_buffer_type vcd_buffer_type, void *buf)
+{
+	VCD_MSG_LOW("vcd_free_buffer_cmn in %d:\n", cctxt->clnt_state.state);
+
+	return vcd_free_one_buffer_internal(cctxt, vcd_buffer_type, buf);
+}
+
+static u32 vcd_fill_output_buffer_cmn(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *buffer)
+{
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_buffer_entry *buf_entry;
+	struct vcd_frame_data *frm_entry;
+	u32 q_result = true;
+
+	VCD_MSG_LOW("vcd_fill_output_buffer_cmn in %d:\n",
+		    cctxt->clnt_state.state);
+
+	buf_entry = vcd_check_fill_output_buffer(cctxt, buffer);
+	if (!buf_entry)
+		return VCD_ERR_BAD_POINTER;
+
+	q_result = vcd_buffer_pool_entry_en_q(&cctxt->out_buf_pool, buf_entry);
+
+	if (!q_result && !cctxt->decoding) {
+		VCD_MSG_ERROR("Failed: vcd_buffer_pool_entry_en_q\n");
+
+		return VCD_ERR_FAIL;
+	}
+
+	frm_entry = &buf_entry->frame;
+
+	*frm_entry = *buffer;
+	frm_entry->phys_addr = buf_entry->phys_addr;
+	frm_entry->ip_frm_tag = VCD_FRAMETAG_INVALID;
+	frm_entry->data_len = 0;
+
+	if (cctxt->sched_clnt_valid) {
+		if (cctxt->decoding && cctxt->status.b1st_frame_recvd) {
+			struct vcd_property_hdr prop_hdr;
+			struct ddl_frame_data_tag ddl_frm;
+
+			prop_hdr.id = DDL_I_DPB_RELEASE;
+			prop_hdr.sz = sizeof(struct ddl_frame_data_tag);
+
+			memset(&ddl_frm, 0, sizeof(ddl_frm));
+			ddl_frm.vcd_frm = *frm_entry;
+			ddl_frm.intrlcd_ip_frm_tag = VCD_FRAMETAG_INVALID;
+
+			rc = ddl_set_property(cctxt->ddl_handle, &prop_hdr,
+				&ddl_frm);
+
+			if (VCD_FAILED(rc)) {
+				VCD_MSG_ERROR("Error returning output buffer to"
+						" HW. rc = 0x%x\n", rc);
+
+				buf_entry->in_use = false;
+			} else {
+				cctxt->out_buf_pool.in_use++;
+				buf_entry->in_use = true;
+			}
+		}
+
+		if (!VCD_FAILED(rc)) {
+			rc = vcd_map_sched_status(sched_update_client_o_tkn(
+				cctxt->dev_ctxt->sched_hdl,
+				cctxt->sched_clnt_hdl, true,
+				cctxt->sched_o_tkn_per_ip_frm));
+		}
+
+		if (!VCD_FAILED(rc))
+			vcd_try_submit_frame(cctxt->dev_ctxt);
+
+	}
+
+	return rc;
+}
+
+static u32 vcd_fill_output_buffer_in_eos(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *buffer)
+{
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_buffer_entry *buf_entry;
+
+	VCD_MSG_LOW("vcd_fill_output_buffer_in_eos:\n");
+
+	buf_entry = vcd_check_fill_output_buffer(cctxt, buffer);
+	if (!buf_entry)
+		return VCD_ERR_BAD_POINTER;
+
+	if (cctxt->status.eos_wait_for_op_buf) {
+		VCD_MSG_HIGH("Got an output buffer we were waiting for\n");
+
+		buf_entry->frame = *buffer;
+
+		buf_entry->frame.data_len = 0;
+		buf_entry->frame.flags |= VCD_FRAME_FLAG_EOS;
+		buf_entry->frame.ip_frm_tag =
+			cctxt->status.eos_trig_ip_frm.ip_frm_tag;
+		buf_entry->frame.time_stamp =
+			cctxt->status.eos_trig_ip_frm.time_stamp;
+
+		cctxt->callback(VCD_EVT_RESP_OUTPUT_DONE, VCD_S_SUCCESS,
+			&buf_entry->frame, sizeof(struct vcd_frame_data),
+			cctxt, cctxt->client_data);
+
+		cctxt->status.eos_wait_for_op_buf = false;
+
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_RUN,
+			CLIENT_STATE_EVENT_NUMBER(pf_fill_output_buffer));
+
+	} else {
+		rc = vcd_fill_output_buffer_cmn(cctxt, buffer);
+	}
+
+	return rc;
+}
+
+static void vcd_clnt_cb_in_starting(struct vcd_clnt_ctxt *cctxt, u32 event,
+	u32 status, void *payload, u32 size, u32 *ddl_handle,
+	void *const client_data)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	struct vcd_transc *transc = (struct vcd_transc *)client_data;
+	VCD_MSG_LOW("vcd_clnt_cb_in_starting:\n");
+	if (cctxt->ddl_handle != ddl_handle) {
+		VCD_MSG_ERROR("vcd_clnt_cb_in_initing: Wrong DDL handle %p\n",
+			ddl_handle);
+		return;
+	}
+
+	switch (event) {
+	case VCD_EVT_RESP_START:
+		vcd_handle_start_done(cctxt, (struct vcd_transc *)client_data,
+			status);
+		break;
+	case VCD_EVT_RESP_STOP:
+		vcd_handle_stop_done_in_starting(cctxt, (struct vcd_transc *)
+			client_data, status);
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+		cctxt->status.cmd_submitted--;
+		vcd_mark_command_channel(cctxt->dev_ctxt, transc);
+		vcd_handle_err_fatal(cctxt, VCD_EVT_RESP_START,	status);
+		break;
+	default:
+		VCD_MSG_ERROR("Unexpected callback event=%d status=%d "
+			"from DDL\n", event, status);
+		dev_ctxt->cont = false;
+		break;
+	}
+}
+
+static void vcd_clnt_cb_in_run(struct vcd_clnt_ctxt *cctxt, u32 event,
+	u32 status, void *payload, u32 size, u32 *ddl_handle,
+	void *const client_data)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u32 rc = VCD_S_SUCCESS;
+
+	if (cctxt->ddl_handle != ddl_handle) {
+		VCD_MSG_ERROR("ddl_handle mismatch\n");
+
+		return;
+	}
+
+	switch (event) {
+	case VCD_EVT_RESP_INPUT_DONE:
+		rc = vcd_handle_input_done(cctxt, payload, event, status);
+		break;
+	case VCD_EVT_RESP_OUTPUT_DONE:
+		if (!cctxt->status.b1st_op_done_recvd) {
+			if (!VCD_FAILED(status)) {
+				rc = vcd_handle_first_frame_done(cctxt,
+					payload);
+
+				if (VCD_FAILED(rc)) {
+					VCD_MSG_ERROR("rc = 0x%x. Failed: "
+						"vcd_handle_first_frame_"
+						"done\n", rc);
+					status = VCD_ERR_FAIL;
+				} else {
+					cctxt->status.b1st_op_done_recvd = true;
+				}
+			}
+		}
+
+		rc = vcd_handle_frame_done(cctxt, payload, event, status);
+
+		break;
+	case VCD_EVT_RESP_OUTPUT_REQ:
+		rc = vcd_handle_output_required(cctxt, payload, status);
+		break;
+	case VCD_EVT_IND_RECONFIG:
+		break;
+	case VCD_EVT_RESP_TRANSACTION_PENDING:
+		vcd_handle_trans_pending(cctxt);
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+		vcd_handle_ind_hw_err_fatal(cctxt, VCD_EVT_IND_HWERRFATAL,
+			status);
+		break;
+	default:
+		VCD_MSG_ERROR("Unexpected callback event=%d status=%d from DDL\n",
+			event, status);
+		dev_ctxt->cont = false;
+		break;
+	}
+
+	if (!VCD_FAILED(rc) && (event == VCD_EVT_RESP_INPUT_DONE ||
+			event == VCD_EVT_RESP_OUTPUT_DONE ||
+			event == VCD_EVT_RESP_OUTPUT_REQ)) {
+
+		if (((struct ddl_frame_data_tag *)payload)->frm_trans_end)
+			vcd_mark_frame_channel(cctxt->dev_ctxt);
+	}
+}
+
+static void vcd_clnt_cb_in_eos(struct vcd_clnt_ctxt *cctxt, u32 event,
+	u32 status, void *payload, u32 size, u32 *ddl_handle,
+	void *const client_data)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	struct vcd_transc *transc = NULL;
+
+	if (cctxt->ddl_handle != ddl_handle) {
+		VCD_MSG_ERROR("ddl_handle mismatch\n");
+
+		return;
+	}
+
+	switch (event) {
+	case VCD_EVT_RESP_INPUT_DONE:
+		vcd_handle_input_done_in_eos(cctxt, payload, status);
+		break;
+	case VCD_EVT_RESP_OUTPUT_DONE:
+		vcd_handle_frame_done_in_eos(cctxt, payload, status);
+		break;
+	case VCD_EVT_RESP_OUTPUT_REQ:
+		vcd_handle_output_required(cctxt, payload, status);
+		break;
+	case VCD_EVT_RESP_EOS_DONE:
+		transc = (struct vcd_transc *)client_data;
+		vcd_handle_eos_done(cctxt, transc, status);
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+		vcd_handle_ind_hw_err_fatal(cctxt, VCD_EVT_IND_HWERRFATAL,
+			status);
+		break;
+	default:
+		VCD_MSG_ERROR("Unexpected callback event=%d status=%d from DDL\n",
+			event, status);
+
+		dev_ctxt->cont = false;
+		break;
+	}
+
+	if (event == VCD_EVT_RESP_INPUT_DONE ||
+			event == VCD_EVT_RESP_OUTPUT_DONE ||
+			event == VCD_EVT_RESP_OUTPUT_REQ) {
+		if (payload && ((struct ddl_frame_data_tag *)
+				payload)->frm_trans_end) {
+			vcd_mark_frame_channel(cctxt->dev_ctxt);
+			if (!cctxt->status.frame_submitted)
+				vcd_handle_eos_trans_end(cctxt);
+		}
+	}
+}
+
+static void vcd_clnt_cb_in_flushing(struct vcd_clnt_ctxt *cctxt, u32 event,
+	u32 status, void *payload, u32 size, u32 *ddl_handle,
+	void *const client_data)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_clnt_cb_in_flushing:\n");
+
+	if (cctxt->ddl_handle != ddl_handle) {
+		VCD_MSG_ERROR("ddl_handle mismatch\n");
+		return;
+	}
+
+	switch (event) {
+	case VCD_EVT_RESP_INPUT_DONE:
+		rc = vcd_handle_input_done(cctxt, payload,
+			VCD_EVT_RESP_INPUT_FLUSHED, status);
+		break;
+	case VCD_EVT_RESP_OUTPUT_DONE:
+		rc = vcd_handle_frame_done(cctxt, payload,
+			VCD_EVT_RESP_OUTPUT_FLUSHED, status);
+		break;
+	case VCD_EVT_RESP_OUTPUT_REQ:
+		rc = vcd_handle_output_required_in_flushing(cctxt, payload);
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+		vcd_handle_ind_hw_err_fatal(cctxt, VCD_EVT_IND_HWERRFATAL,
+			status);
+		break;
+	default:
+		VCD_MSG_ERROR("Unexpected callback event=%d status=%d from DDL\n",
+			event, status);
+		dev_ctxt->cont = false;
+		break;
+	}
+
+	if (!VCD_FAILED(rc) && (event == VCD_EVT_RESP_INPUT_DONE ||
+			event == VCD_EVT_RESP_OUTPUT_DONE ||
+			event == VCD_EVT_RESP_OUTPUT_REQ) &&
+			((struct ddl_frame_data_tag *)payload)->frm_trans_end) {
+
+		vcd_mark_frame_channel(cctxt->dev_ctxt);
+
+		if (!cctxt->status.frame_submitted) {
+			VCD_MSG_HIGH("All pending frames recvd from DDL\n");
+
+			if (cctxt->status.flush_mode & VCD_FLUSH_OUTPUT) {
+				vcd_flush_output_buffers(cctxt);
+
+				vcd_release_all_clnt_frm_transc(cctxt);
+			}
+
+			vcd_send_flush_done(cctxt, VCD_S_SUCCESS);
+			vcd_release_interim_frame_channels(dev_ctxt);
+			VCD_MSG_HIGH("Flush complete\n");
+			vcd_release_all_clnt_def_frm_transc(cctxt);
+			vcd_do_client_state_transition(cctxt,
+				VCD_CLIENT_STATE_RUN,
+				CLIENT_STATE_EVENT_NUMBER(pf_clnt_cb));
+		}
+	}
+}
+
+static void vcd_clnt_cb_in_stopping(struct vcd_clnt_ctxt *cctxt, u32 event,
+	u32 status, void *payload, u32 size, u32 *ddl_handle,
+	void *const client_data)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_clnt_cb_in_stopping:\n");
+
+	if (cctxt->ddl_handle != ddl_handle) {
+		VCD_MSG_ERROR("ddl_handle mismatch\n");
+		return;
+	}
+
+	switch (event) {
+	case VCD_EVT_RESP_INPUT_DONE:
+		rc = vcd_handle_input_done(cctxt, payload,
+			VCD_EVT_RESP_INPUT_FLUSHED, status);
+
+		break;
+	case VCD_EVT_RESP_OUTPUT_DONE:
+		rc = vcd_handle_frame_done(cctxt, payload,
+			VCD_EVT_RESP_OUTPUT_FLUSHED, status);
+
+		break;
+	case VCD_EVT_RESP_OUTPUT_REQ:
+		rc = vcd_handle_output_required_in_flushing(cctxt, payload);
+		break;
+	case VCD_EVT_RESP_STOP:
+		vcd_handle_stop_done(cctxt, (struct vcd_transc *)client_data,
+			status);
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+		vcd_handle_ind_hw_err_fatal(cctxt, VCD_EVT_RESP_STOP, status);
+		break;
+	default:
+		VCD_MSG_ERROR("Unexpected callback event=%d status=%d from DDL\n",
+			event, status);
+
+		dev_ctxt->cont = false;
+		break;
+	}
+
+	if (!VCD_FAILED(rc) && (event == VCD_EVT_RESP_INPUT_DONE ||
+			event == VCD_EVT_RESP_OUTPUT_DONE ||
+			event == VCD_EVT_RESP_OUTPUT_REQ) &&
+			((struct ddl_frame_data_tag *)payload)->frm_trans_end) {
+
+		vcd_mark_frame_channel(cctxt->dev_ctxt);
+
+		if (!cctxt->status.frame_submitted) {
+			VCD_MSG_HIGH("All pending frames recvd from DDL\n");
+
+			vcd_flush_output_buffers(cctxt);
+
+			cctxt->status.flush_mode = 0;
+
+			vcd_release_all_clnt_frm_transc(cctxt);
+
+			VCD_MSG_HIGH("All buffers flushed. Enqueuing stop cmd\n");
+
+			vcd_client_cmd_flush_and_en_q(cctxt,
+				VCD_CMD_CODEC_STOP);
+		}
+	}
+}
+
+static void vcd_clnt_cb_in_pausing(struct vcd_clnt_ctxt *cctxt, u32 event,
+	u32 status, void *payload, u32 size, u32 *ddl_handle,
+	void *const client_data)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_clnt_cb_in_pausing:\n");
+
+	if (cctxt->ddl_handle != ddl_handle) {
+		VCD_MSG_ERROR("ddl_handle mismatch\n");
+
+		return;
+	}
+
+	switch (event) {
+	case VCD_EVT_RESP_INPUT_DONE:
+		rc = vcd_handle_input_done(cctxt, payload, event, status);
+		break;
+	case VCD_EVT_RESP_OUTPUT_DONE:
+		rc = vcd_handle_frame_done(cctxt, payload, event, status);
+		break;
+	case VCD_EVT_RESP_OUTPUT_REQ:
+		rc = vcd_handle_output_required(cctxt, payload, status);
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+		vcd_handle_ind_hw_err_fatal(cctxt, VCD_EVT_RESP_PAUSE, status);
+		break;
+	default:
+		VCD_MSG_ERROR("Unexpected callback event=%d status=%d from DDL\n",
+			event, status);
+
+		dev_ctxt->cont = false;
+		break;
+	}
+
+	if (!VCD_FAILED(rc) && (event == VCD_EVT_RESP_INPUT_DONE ||
+			event == VCD_EVT_RESP_OUTPUT_DONE ||
+			event == VCD_EVT_RESP_OUTPUT_REQ) &&
+			((struct ddl_frame_data_tag *)payload)->frm_trans_end) {
+
+		vcd_mark_frame_channel(cctxt->dev_ctxt);
+
+		if (!cctxt->status.frame_submitted) {
+			VCD_MSG_HIGH("All pending frames recvd from DDL\n");
+
+			cctxt->callback(VCD_EVT_RESP_PAUSE, VCD_S_SUCCESS, NULL,
+				0, cctxt, cctxt->client_data);
+
+			vcd_do_client_state_transition(cctxt,
+				VCD_CLIENT_STATE_PAUSED,
+				CLIENT_STATE_EVENT_NUMBER(pf_clnt_cb));
+
+			rc = vcd_power_event(cctxt->dev_ctxt, cctxt,
+				VCD_EVT_PWR_CLNT_PAUSE);
+
+			if (VCD_FAILED(rc)) {
+				VCD_MSG_ERROR("VCD_EVT_PWR_CLNT_PAUSE_END "
+					"failed\n");
+			}
+		}
+	}
+}
+
+static void  vcd_clnt_cb_in_invalid(struct vcd_clnt_ctxt *cctxt, u32 event,
+	u32 status, void *payload, u32 size, u32 *ddl_handle,
+	void *const client_data)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	VCD_MSG_LOW("vcd_clnt_cb_in_invalid:\n");
+	if (cctxt->ddl_handle != ddl_handle) {
+		VCD_MSG_ERROR("ddl_handle mismatch\n");
+		return;
+	}
+	switch (event) {
+	case VCD_EVT_RESP_STOP:
+		vcd_handle_stop_done_in_invalid(cctxt, status);
+		break;
+	case VCD_EVT_RESP_INPUT_DONE:
+	case VCD_EVT_RESP_OUTPUT_DONE:
+	case VCD_EVT_RESP_OUTPUT_REQ:
+	case VCD_EVT_RESP_TRANSACTION_PENDING:
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+		if (status == VCD_ERR_HW_FATAL)
+			vcd_handle_stop_done_in_invalid(cctxt, status);
+
+		break;
+	default:
+		VCD_MSG_ERROR("Unexpected callback event=%d status=%d from DDL\n",
+			event, status);
+		dev_ctxt->cont = false;
+		break;
+	}
+}
+
+static void vcd_clnt_enter_open(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering CLIENT_STATE_OPEN on api %d\n", ev_code);
+}
+
+static void vcd_clnt_enter_starting(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering CLIENT_STATE_STARTING on api %d\n",	ev_code);
+}
+
+static void vcd_clnt_enter_run(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering CLIENT_STATE_RUN on api %d\n", ev_code);
+}
+
+static void vcd_clnt_enter_flushing(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering CLIENT_STATE_FLUSHING on api %d\n",	ev_code);
+}
+
+static void vcd_clnt_enter_stopping(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering CLIENT_STATE_STOPPING on api %d\n", ev_code);
+}
+
+static void vcd_clnt_enter_eos(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	u32 rc;
+
+	VCD_MSG_MED("Entering CLIENT_STATE_EOS on api %d\n", ev_code);
+	rc = vcd_map_sched_status(sched_suspend_resume_client(
+		cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl, false));
+	if (VCD_FAILED(rc))
+		VCD_MSG_ERROR("Failed: sched_suspend_resume_client. rc=0x%x\n",
+			rc);
+}
+
+static void vcd_clnt_enter_pausing(struct vcd_clnt_ctxt *cctxt,	s32 ev_code)
+{
+	VCD_MSG_MED("Entering CLIENT_STATE_PAUSING on api %d\n", ev_code);
+}
+
+static void vcd_clnt_enter_paused(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering CLIENT_STATE_PAUSED on api %d\n", ev_code);
+}
+
+static void  vcd_clnt_enter_invalid(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering CLIENT_STATE_INVALID on api %d\n", ev_code);
+	cctxt->ddl_hdl_valid = false;
+}
+
+static void vcd_clnt_exit_open(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting CLIENT_STATE_OPEN on api %d\n", ev_code);
+}
+
+static void vcd_clnt_exit_starting(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting CLIENT_STATE_STARTING on api %d\n", ev_code);
+}
+
+static void vcd_clnt_exit_run(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting CLIENT_STATE_RUN on api %d\n", ev_code);
+}
+
+static void vcd_clnt_exit_flushing(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting CLIENT_STATE_FLUSHING on api %d\n", ev_code);
+}
+
+static void vcd_clnt_exit_stopping(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting CLIENT_STATE_STOPPING on api %d\n", ev_code);
+}
+
+static void vcd_clnt_exit_eos(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	u32 rc;
+	VCD_MSG_MED("Exiting CLIENT_STATE_EOS on api %d\n", ev_code);
+	rc = vcd_map_sched_status(sched_suspend_resume_client(
+		cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl, true));
+	if (VCD_FAILED(rc))
+		VCD_MSG_ERROR("Failed: sched_suspend_resume_client. rc=0x%x\n",
+			rc);
+}
+
+static void vcd_clnt_exit_pausing(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting CLIENT_STATE_PAUSING on api %d\n", ev_code);
+}
+
+static void vcd_clnt_exit_paused(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting CLIENT_STATE_PAUSED on api %d\n", ev_code);
+}
+
+static void  vcd_clnt_exit_invalid(struct vcd_clnt_ctxt *cctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting CLIENT_STATE_INVALID on api %d\n", ev_code);
+}
+
+void vcd_do_client_state_transition(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_clnt_state_enum to_state, u32 ev_code)
+{
+	struct vcd_clnt_state_ctxt *state_ctxt;
+
+	if (!cctxt || to_state >= VCD_CLIENT_STATE_MAX) {
+		VCD_MSG_ERROR("Bad parameters. cctxt=%p, to_state=%d\n", cctxt,
+			to_state);
+	}
+
+	state_ctxt = &cctxt->clnt_state;
+
+	if (state_ctxt->state == to_state) {
+		VCD_MSG_HIGH("Client already in requested to_state=%d\n",
+			to_state);
+		return;
+	}
+
+	VCD_MSG_MED("vcd_do_client_state_transition: C%d -> C%d, for api %d\n",
+		(int)state_ctxt->state, (int)to_state, ev_code);
+
+	if (state_ctxt->state_table->pf_exit)
+		state_ctxt->state_table->pf_exit(cctxt, ev_code);
+
+
+	state_ctxt->state = to_state;
+	state_ctxt->state_table = vcd_clnt_state_table[to_state];
+
+	if (state_ctxt->state_table->pf_entry)
+		state_ctxt->state_table->pf_entry(cctxt, ev_code);
+}
+
+const struct vcd_clnt_state_table *vcd_get_client_state_table(
+	enum vcd_clnt_state_enum state)
+{
+	return vcd_clnt_state_table[state];
+}
+
+static const struct vcd_clnt_state_table vcd_clnt_table_open = {
+	{
+		vcd_close_in_open,
+		vcd_encode_start_in_open,
+		NULL,
+		vcd_decode_start_in_open,
+		NULL,
+		NULL,
+		NULL,
+		vcd_flush_inopen,
+		vcd_stop_inopen,
+		vcd_set_property_cmn,
+		vcd_get_property_cmn,
+		vcd_set_buffer_requirements_cmn,
+		vcd_get_buffer_requirements_cmn,
+		vcd_set_buffer_cmn,
+		vcd_allocate_buffer_cmn,
+		vcd_free_buffer_cmn,
+		vcd_fill_output_buffer_cmn,
+		NULL,
+	},
+	vcd_clnt_enter_open,
+	vcd_clnt_exit_open
+};
+
+static const struct vcd_clnt_state_table vcd_clnt_table_starting = {
+	{
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		vcd_clnt_cb_in_starting,
+	},
+	vcd_clnt_enter_starting,
+	vcd_clnt_exit_starting
+};
+
+static const struct vcd_clnt_state_table vcd_clnt_table_run = {
+	{
+		NULL,
+		vcd_encode_start_in_run,
+		vcd_encode_frame_cmn,
+		vcd_decode_start_in_run,
+		vcd_decode_frame_cmn,
+		vcd_pause_in_run,
+		NULL,
+		vcd_flush_cmn,
+		vcd_stop_in_run,
+		vcd_set_property_cmn,
+		vcd_get_property_cmn,
+		vcd_set_buffer_requirements_cmn,
+		vcd_get_buffer_requirements_cmn,
+		vcd_set_buffer_cmn,
+		vcd_allocate_buffer_cmn,
+		NULL,
+		vcd_fill_output_buffer_cmn,
+		vcd_clnt_cb_in_run,
+	},
+	vcd_clnt_enter_run,
+	vcd_clnt_exit_run
+};
+
+static const struct vcd_clnt_state_table vcd_clnt_table_flushing = {
+	{
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		vcd_flush_in_flushing,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		vcd_clnt_cb_in_flushing,
+	},
+	vcd_clnt_enter_flushing,
+	vcd_clnt_exit_flushing
+};
+
+static const struct vcd_clnt_state_table vcd_clnt_table_stopping = {
+	{
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		vcd_get_property_cmn,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		vcd_clnt_cb_in_stopping,
+	},
+	vcd_clnt_enter_stopping,
+	vcd_clnt_exit_stopping
+};
+
+static const struct vcd_clnt_state_table vcd_clnt_table_eos = {
+	{
+		NULL,
+		NULL,
+		vcd_encode_frame_cmn,
+		NULL,
+		vcd_decode_frame_cmn,
+		NULL,
+		NULL,
+		vcd_flush_in_eos,
+		vcd_stop_in_eos,
+		NULL,
+		vcd_get_property_cmn,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		vcd_fill_output_buffer_in_eos,
+		vcd_clnt_cb_in_eos,
+	},
+	vcd_clnt_enter_eos,
+	vcd_clnt_exit_eos
+};
+
+static const struct vcd_clnt_state_table vcd_clnt_table_pausing = {
+	{
+		NULL,
+		NULL,
+		vcd_encode_frame_cmn,
+		NULL,
+		vcd_decode_frame_cmn,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		vcd_get_property_cmn,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		vcd_fill_output_buffer_cmn,
+		vcd_clnt_cb_in_pausing,
+	},
+	vcd_clnt_enter_pausing,
+	vcd_clnt_exit_pausing
+};
+
+static const struct vcd_clnt_state_table vcd_clnt_table_paused = {
+	{
+		NULL,
+		NULL,
+		vcd_encode_frame_cmn,
+		NULL,
+		vcd_decode_frame_cmn,
+		NULL,
+		vcd_resume_in_paused,
+		vcd_flush_cmn,
+		vcd_stop_cmn,
+		vcd_set_property_cmn,
+		vcd_get_property_cmn,
+		vcd_set_buffer_requirements_cmn,
+		vcd_get_buffer_requirements_cmn,
+		vcd_set_buffer_cmn,
+		vcd_allocate_buffer_cmn,
+		NULL,
+		vcd_fill_output_buffer_cmn,
+		NULL,
+	},
+	vcd_clnt_enter_paused,
+	vcd_clnt_exit_paused
+};
+static const struct vcd_clnt_state_table vcd_clnt_table_invalid = {
+	{
+		vcd_close_in_invalid,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		vcd_flush_in_invalid,
+		vcd_stop_in_invalid,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		vcd_free_buffer_cmn,
+		NULL,
+		vcd_clnt_cb_in_invalid,
+	},
+	vcd_clnt_enter_invalid,
+	vcd_clnt_exit_invalid
+};
+
+static const struct vcd_clnt_state_table *vcd_clnt_state_table[] = {
+	NULL,
+	&vcd_clnt_table_open,
+	&vcd_clnt_table_starting,
+	&vcd_clnt_table_run,
+	&vcd_clnt_table_flushing,
+	&vcd_clnt_table_pausing,
+	&vcd_clnt_table_paused,
+	&vcd_clnt_table_stopping,
+	&vcd_clnt_table_eos,
+	&vcd_clnt_table_invalid
+};
diff --git a/drivers/misc/video_core/720p/vcd/vcd_client_sm.h b/drivers/misc/video_core/720p/vcd/vcd_client_sm.h
new file mode 100644
index 0000000..8f3a975
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_client_sm.h
@@ -0,0 +1,112 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_CLIENT_SM_H_
+#define _VCD_CLIENT_SM_H_
+#include "vcd_api.h"
+#include "vcd_ddl_api.h"
+
+struct vcd_clnt_state_table;
+struct vcd_clnt_state_ctxt;
+struct vcd_clnt_ctxt;
+
+enum vcd_clnt_state_enum {
+	VCD_CLIENT_STATE_NULL = 0,
+	VCD_CLIENT_STATE_OPEN,
+	VCD_CLIENT_STATE_STARTING,
+	VCD_CLIENT_STATE_RUN,
+	VCD_CLIENT_STATE_FLUSHING,
+	VCD_CLIENT_STATE_PAUSING,
+	VCD_CLIENT_STATE_PAUSED,
+	VCD_CLIENT_STATE_STOPPING,
+	VCD_CLIENT_STATE_EOS,
+	VCD_CLIENT_STATE_INVALID,
+	VCD_CLIENT_STATE_MAX,
+	VCD_CLIENT_STATE_32BIT = 0x7FFFFFFF
+};
+
+#define CLIENT_STATE_EVENT_NUMBER(ppf) \
+	((u32 *) (&(((struct vcd_clnt_state_table*)0)->ev_hdlr.ppf)) -  \
+	(u32 *) (&(((struct vcd_clnt_state_table*)0)->ev_hdlr.pf_close)) + 1)
+
+struct vcd_clnt_state_table {
+	struct {
+		u32(*pf_close) (struct vcd_clnt_ctxt *cctxt);
+		u32(*pf_encode_start) (struct vcd_clnt_ctxt *cctxt);
+		u32(*pf_encode_frame) (struct vcd_clnt_ctxt *cctxt,
+			struct vcd_frame_data *input_frame);
+		u32(*pf_decode_start) (struct vcd_clnt_ctxt *cctxt,
+			struct vcd_sequence_hdr *seq_hdr);
+		u32(*pf_decode_frame) (struct vcd_clnt_ctxt *cctxt,
+			struct vcd_frame_data *input_frame);
+		u32(*pf_pause) (struct vcd_clnt_ctxt *cctxt);
+		u32(*pf_resume) (struct vcd_clnt_ctxt *cctxt);
+		u32(*pf_flush) (struct vcd_clnt_ctxt *cctxt, u32 mode);
+		u32(*pf_stop) (struct vcd_clnt_ctxt *cctxt);
+		u32(*pf_set_property) (struct vcd_clnt_ctxt *cctxt,
+			struct vcd_property_hdr *prop_hdr, void *prop);
+		u32(*pf_get_property) (struct vcd_clnt_ctxt *cctxt,
+			struct vcd_property_hdr *prop_hdr,
+			void *prop);
+		u32(*pf_set_buffer_requirements) (struct vcd_clnt_ctxt *cctxt,
+			enum vcd_buffer_type vcd_buffer_type,
+			struct vcd_buffer_requirement *buffer_req);
+		u32(*pf_get_buffer_requirements) (struct vcd_clnt_ctxt *cctxt,
+			  enum vcd_buffer_type vcd_buffer_type,
+			  struct vcd_buffer_requirement *buffer_req);
+		u32(*pf_set_buffer) (struct vcd_clnt_ctxt *cctxt,
+			enum vcd_buffer_type vcd_buffer_type, void *buffer,
+			size_t buf_size);
+		u32(*pf_allocate_buffer) (struct vcd_clnt_ctxt *cctxt,
+			enum vcd_buffer_type vcd_buffer_type, size_t sz,
+			void **virt_addr, phys_addr_t *phys_addr);
+		u32(*pf_free_buffer) (struct vcd_clnt_ctxt *cctxt,
+			enum vcd_buffer_type vcd_buffer_type, void *buf);
+		u32(*pf_fill_output_buffer) (struct vcd_clnt_ctxt *cctxt,
+			struct vcd_frame_data *buffer);
+		void (*pf_clnt_cb) (struct vcd_clnt_ctxt *cctxt, u32 event,
+			u32 status, void *payload, u32 size, u32 *ddl_handle,
+			void *const client_data);
+	} ev_hdlr;
+
+	void (*pf_entry) (struct vcd_clnt_ctxt *cctxt, s32 state_event_type);
+	void (*pf_exit) (struct vcd_clnt_ctxt *cctxt, s32 state_event_type);
+};
+
+struct vcd_clnt_state_ctxt {
+	const struct vcd_clnt_state_table *state_table;
+	enum vcd_clnt_state_enum state;
+};
+
+extern void vcd_do_client_state_transition(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_clnt_state_enum to_state, u32 ev_code);
+
+extern const struct vcd_clnt_state_table *vcd_get_client_state_table(
+	enum vcd_clnt_state_enum state);
+
+#endif
diff --git a/drivers/misc/video_core/720p/vcd/vcd_core.h b/drivers/misc/video_core/720p/vcd/vcd_core.h
new file mode 100644
index 0000000..f855d7bd
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_core.h
@@ -0,0 +1,258 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_CORE_H_
+#define _VCD_CORE_H_
+
+#include "vcd_api.h"
+#include "vid_frame_scheduler_api.h"
+#include "vcd_ddl_api.h"
+
+#include "vcd_util.h"
+#include "vcd_client_sm.h"
+#include "vcd_power_sm.h"
+
+#define VCD_SIGNATURE                        0x75017591U
+
+#define VCD_MIN_PERF_LEVEL                   37900
+
+#define VCD_MAX_SCHEDULER_QUEUE_DURATION     1
+
+#define VCD_MAX_SCHEDULER_QUEUE_SIZE(fps_n, fps_d)          \
+      (fps_n / fps_d * VCD_MAX_SCHEDULER_QUEUE_DURATION)
+
+#define VCD_SCHEDULER_INITIAL_PERF_LEVEL        108000
+
+#define VCD_SCHEDULER_ENC_DFLT_OTKN_PERFRM        1
+
+#define VCD_SCHEDULER_DEC_DFLT_OTKN_PERFRM        1
+
+#define VCD_DRIVER_INSTANCE_MAX              4
+
+#define VCD_MAX_CLIENT_TRANSACTIONS          32
+
+#define VCD_SEQ_HDR_PADDING_BYTES            256
+
+#define VCD_DEC_NUM_INTERLACED_FIELDS        2
+
+#define VCD_TIMESTAMP_RESOLUTION             1000000
+#define VCD_DEC_INITIAL_FRAME_RATE           30
+
+#define VCD_S_SCHED_STAT_BASE  0x20000000
+#define VCD_S_SCHED_EOS        (VCD_S_SCHED_STAT_BASE + 0x1)
+#define VCD_S_SCHED_SLEEP      (VCD_S_SCHED_STAT_BASE + 0x2)
+#define VCD_S_SCHED_QEMPTY     (VCD_S_SCHED_STAT_BASE + 0x3)
+#define VCD_S_SCHED_QFULL      (VCD_S_SCHED_STAT_BASE + 0x4)
+
+enum vcd_command_type {
+	VCD_CMD_NONE,
+	VCD_CMD_DEVICE_INIT,
+	VCD_CMD_DEVICE_TERM,
+	VCD_CMD_DEVICE_RESET,
+	VCD_CMD_CODEC_START,
+	VCD_CMD_CODEC_STOP,
+	VCD_CMD_CODE_FRAME,
+	VCD_CMD_OUTPUT_FLUSH,
+	VCD_CMD_CLIENT_CLOSE
+};
+
+//TODO: remove this
+struct vcd_cmd_q_element {
+	enum vcd_command_type pending_cmd;
+};
+
+struct vcd_dma_buffer {
+	void *virt_addr;
+	phys_addr_t phys_addr;
+	size_t size;
+};
+
+struct vcd_buffer_entry {
+	u32 valid;
+	struct vcd_dma_buffer buffer;
+	void *virt_addr;
+	phys_addr_t phys_addr;
+	size_t size;
+//	u8 *alloc;
+//	u8 *virtual;  // aligned so == alloc
+//	u8 *physical;
+//	u32 size;
+	u32 allocated;  // true when allocated
+	u32 in_use;
+	struct vcd_frame_data frame;
+
+};
+
+struct vcd_buffer_pool {
+	struct vcd_buffer_entry *entries;
+	u32 count;
+	struct vcd_buffer_requirement buf_req;
+	u32 validated;
+	u32 allocated;
+	u32 in_use;
+	struct vcd_buffer_entry **queue;
+	u16 q_len;
+	u16 q_head;
+	u16 q_tail;
+
+};
+
+struct vcd_transc {
+	u32 in_use;
+	enum vcd_command_type type;
+	struct vcd_clnt_ctxt *cctxt;
+
+	struct vcd_buffer_entry *ip_buf_entry;
+
+	s64 time_stamp;
+	u32 ip_frm_tag;
+	enum vcd_frame frame_type;
+
+	struct vcd_buffer_entry *op_buf_entry;
+
+	u32 input_done;
+	u32 frame_done;
+};
+
+struct vcd_dev_ctxt {
+	u32 ddl_cmd_concurrency;
+	u32 ddl_frame_ch_depth;
+	u32 ddl_cmd_ch_depth;
+	u32 ddl_frame_ch_interim;
+	u32 ddl_cmd_ch_interim;
+	u32 ddl_frame_ch_free;
+	u32 ddl_cmd_ch_free;
+
+	void *sched_hdl;
+
+	struct vcd_init_config config;
+
+	u32 driver_ids[VCD_DRIVER_INSTANCE_MAX];
+	u32 refs;
+	u8 *device_base_addr;
+	void *hw_timer_handle;
+	u32               hw_time_out;
+	struct vcd_clnt_ctxt *cctxt_list_head;
+
+	enum vcd_command_type pending_cmd;
+
+	u32 cont;
+
+	struct vcd_transc *trans_tbl;
+	u32 trans_tbl_size;
+
+	enum vcd_power_state pwr_state;
+	enum vcd_pwr_clk_state_type pwr_clk_state;
+	u32 active_clnts;
+	u32 max_perf_lvl;
+	u32 reqd_perf_lvl;
+	u32 curr_perf_lvl;
+	u32 set_perf_lvl_pending;
+
+};
+
+struct vcd_clnt_status {
+	u32 req_perf_lvl;
+
+	u32 b1st_frame_recvd;
+	u32 b1st_ip_done_recvd;
+	u32 b1st_op_done_recvd;
+
+	u32 frame_submitted;
+	u32 frame_delayed;
+	u32 cmd_submitted;
+
+	u32 int_field_cnt;
+
+	s64 first_ts;
+	s64 prev_ts;
+	u32 time_elapsed;
+
+	u32 stop_pending;
+	u32 flush_mode;
+
+	u32 eos_wait_for_op_buf;
+	struct vcd_frame_data eos_trig_ip_frm;
+
+	u32 eos_prev_valid;
+	struct ddl_frame_data_tag eos_prev_op_frm;
+	u32	last_err;
+	u32	last_evt;
+	u32	cleaning_up;
+	u32	close_pending;
+};
+
+struct vcd_clnt_ctxt {
+	u32 signature;
+	struct vcd_clnt_state_ctxt clnt_state;
+
+	s32 driver_id;
+
+	u32 live;
+	u32 decoding;
+
+	struct vcd_property_frame_rate frm_rate;
+	u32 frm_p_units;
+	u32 reqd_perf_lvl;
+	u32 time_resoln;
+
+	struct vcd_buffer_pool in_buf_pool;
+	struct vcd_buffer_pool out_buf_pool;
+
+	void (*callback) (u32 event, u32 status, void *info, u32 size,
+			  void *handle, void *const client_data);
+	void *client_data;
+
+	u32 sched_clnt_valid;
+	void *sched_clnt_hdl;
+	u32 sched_o_tkn_per_ip_frm;
+	u32 ddl_hdl_valid;
+	u32 *ddl_handle;
+	struct vcd_dev_ctxt *dev_ctxt;
+	struct vcd_cmd_q_element cmd_q;
+
+	struct vcd_sequence_hdr seq_hdr;
+	phys_addr_t seq_hdr_phys_addr;
+
+	struct vcd_clnt_status status;
+
+	struct vcd_clnt_ctxt *next;
+};
+
+#define VCD_BUFFERPOOL_INUSE_DECREMENT(val) \
+do { \
+	if ((val) > 0) \
+		val--; \
+	else { \
+		VCD_MSG_ERROR("%s(): Inconsistent val given in " \
+			" VCD_BUFFERPOOL_INUSE_DECREMENT\n", __func__); \
+		vcd_assert(); \
+	} \
+} while (0)
+
+#endif
diff --git a/drivers/misc/video_core/720p/vcd/vcd_device_sm.c b/drivers/misc/video_core/720p/vcd/vcd_device_sm.c
new file mode 100644
index 0000000..9e3a6a7
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_device_sm.c
@@ -0,0 +1,1109 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vcd.h"
+
+static const struct vcd_dev_state_table *vcd_dev_state_table[];
+static const struct vcd_dev_state_table vcd_dev_table_null;
+
+struct vcd_drv_ctxt *vcd_get_drv_context(void)
+{
+	static struct vcd_drv_ctxt drv_context = {
+		{&vcd_dev_table_null, VCD_DEVICE_STATE_NULL},
+		{0},
+		0
+	};
+
+	return &drv_context;
+
+}
+
+void vcd_do_device_state_transition(struct vcd_drv_ctxt *drv_ctxt,
+	enum vcd_dev_state_enum to_state, u32 ev_code)
+{
+	struct vcd_dev_state_ctxt *state_ctxt;
+
+	if (!drv_ctxt || to_state >= VCD_DEVICE_STATE_MAX) {
+		VCD_MSG_ERROR("Bad parameters. drv_ctxt=%p, to_state=%d",
+				  drv_ctxt, to_state);
+	}
+
+	state_ctxt = &drv_ctxt->dev_state;
+
+	if (state_ctxt->state == to_state) {
+		VCD_MSG_HIGH("Device already in requested to_state=%d",
+				 to_state);
+
+		return;
+	}
+
+	VCD_MSG_MED("vcd_do_device_state_transition: D%d -> D%d, for api %d",
+			(int)state_ctxt->state, (int)to_state, ev_code);
+
+	if (state_ctxt->state_table->pf_exit)
+		state_ctxt->state_table->pf_exit(drv_ctxt, ev_code);
+
+
+	state_ctxt->state = to_state;
+	state_ctxt->state_table = vcd_dev_state_table[to_state];
+
+	if (state_ctxt->state_table->pf_entry)
+		state_ctxt->state_table->pf_entry(drv_ctxt, ev_code);
+}
+
+void vcd_hw_timeout_handler(void *user_data)
+{
+	struct vcd_drv_ctxt *drv_ctxt;
+
+	VCD_MSG_HIGH("vcd_hw_timeout_handler:");
+	user_data = NULL;
+	drv_ctxt = vcd_get_drv_context();
+	mutex_lock(drv_ctxt->dev_mutex);
+	if (drv_ctxt->dev_state.state_table->ev_hdlr.pf_timeout)
+		drv_ctxt->dev_state.state_table->ev_hdlr.pf_timeout(drv_ctxt,
+			user_data);
+	else
+		VCD_MSG_ERROR("hw_timeout unsupported in device state %d",
+			drv_ctxt->dev_state.state);
+	mutex_unlock(drv_ctxt->dev_mutex);
+}
+
+void vcd_ddl_callback(u32 event, u32 status, void *payload,
+	u32 size, u32 *ddl_handle, void *const client_data)
+{
+	struct vcd_drv_ctxt *drv_ctxt;
+	struct vcd_dev_ctxt *dev_ctxt;
+	struct vcd_dev_state_ctxt *dev_state;
+	struct vcd_clnt_ctxt *cctxt;
+	struct vcd_transc *transc;
+
+	VCD_MSG_LOW("vcd_ddl_callback:");
+
+	VCD_MSG_LOW("event=0x%x status=0x%x", event, status);
+
+	drv_ctxt = vcd_get_drv_context();
+	dev_ctxt = &drv_ctxt->dev_ctxt;
+	dev_state = &drv_ctxt->dev_state;
+
+	dev_ctxt->cont = true;
+	vcd_device_timer_stop(dev_ctxt);
+
+	switch (dev_state->state) {
+	case VCD_DEVICE_STATE_NULL:
+		VCD_MSG_HIGH("Callback unexpected in NULL state");
+		break;
+	case VCD_DEVICE_STATE_NOT_INIT:
+		VCD_MSG_HIGH("Callback unexpected in NOT_INIT state");
+		break;
+	case VCD_DEVICE_STATE_INITING:
+		if (dev_state->state_table->ev_hdlr.pf_dev_cb) {
+			dev_state->state_table->ev_hdlr.pf_dev_cb(drv_ctxt,
+				event, status, payload, size, ddl_handle,
+				client_data);
+		} else {
+			VCD_MSG_HIGH("No device handler in %d state",
+				dev_state->state);
+		}
+		break;
+	case VCD_DEVICE_STATE_READY:
+		transc = (struct vcd_transc *)client_data;
+
+		if (!transc || !transc->in_use || !transc->cctxt) {
+			VCD_MSG_ERROR("Invalid clientdata received from DDL ");
+		} else {
+			cctxt = transc->cctxt;
+
+			if (cctxt->clnt_state.state_table->ev_hdlr.pf_clnt_cb) {
+				cctxt->clnt_state.state_table->ev_hdlr.
+					pf_clnt_cb(cctxt, event, status,
+					payload, size, ddl_handle, client_data);
+			} else {
+				VCD_MSG_HIGH("No client handler in"
+					" (dsm:READY, csm:%d) state",
+					(int)cctxt->clnt_state.state);
+
+				if (VCD_FAILED(status)) {
+					VCD_MSG_FATAL("DDL callback"
+						" returned failure 0x%x",
+						status);
+				}
+			}
+		}
+		break;
+	default:
+		VCD_MSG_ERROR("Unknown state");
+		break;
+	}
+
+}
+
+u32 vcd_init_device_context(struct vcd_drv_ctxt *drv_ctxt, u32 ev_code)
+{
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+	struct sched_init_param sched_init;
+	u32 rc;
+	struct ddl_init_config ddl_init;
+
+	VCD_MSG_LOW("vcd_init_device_context:");
+
+	dev_ctxt->pending_cmd = VCD_CMD_NONE;
+
+	rc = vcd_power_event(dev_ctxt, NULL, VCD_EVT_PWR_DEV_INIT_BEGIN);
+	VCD_FAILED_RETURN(rc, "VCD_EVT_PWR_DEV_INIT_BEGIN failed");
+
+	VCD_MSG_HIGH("Device powered ON and clocked");
+
+	sched_init.perf_lvl = dev_ctxt->max_perf_lvl;
+	rc = vcd_map_sched_status(sched_create(&sched_init,
+		&dev_ctxt->sched_hdl));
+
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: sched_create", rc);
+
+		vcd_power_event(dev_ctxt, NULL, VCD_EVT_PWR_DEV_INIT_FAIL);
+
+		return rc;
+	}
+
+	VCD_MSG_HIGH("Created scheduler instance.");
+
+	ddl_init.core_virtual_base_addr = dev_ctxt->device_base_addr;
+	ddl_init.pf_interrupt_clr = dev_ctxt->config.pf_interrupt_clr;
+	ddl_init.ddl_callback = vcd_ddl_callback;
+
+	rc = ddl_device_init(&ddl_init, NULL);
+
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: ddl_device_init", rc);
+
+		sched_destroy(dev_ctxt->sched_hdl);
+		dev_ctxt->sched_hdl = NULL;
+
+		vcd_power_event(dev_ctxt, NULL, VCD_EVT_PWR_DEV_INIT_FAIL);
+	} else {
+		vcd_device_timer_start(dev_ctxt);
+		vcd_do_device_state_transition(drv_ctxt,
+			VCD_DEVICE_STATE_INITING, ev_code);
+	}
+
+	return rc;
+}
+
+void vcd_handle_device_init_failed(struct vcd_drv_ctxt *drv_ctxt, u32 status)
+{
+	struct vcd_clnt_ctxt *client;
+	struct vcd_clnt_ctxt *tmp_client;
+
+	VCD_MSG_ERROR("Device init failed. status = %d", status);
+
+	client = drv_ctxt->dev_ctxt.cctxt_list_head;
+	while (client) {
+		client->callback(VCD_EVT_RESP_OPEN, status, NULL, 0, 0,
+			client->client_data);
+
+		tmp_client = client;
+		client = client->next;
+
+		vcd_destroy_client_context(tmp_client);
+	}
+	if (ddl_device_release(NULL))
+		VCD_MSG_ERROR("Failed: ddl_device_release");
+
+	(void)sched_destroy(drv_ctxt->dev_ctxt.sched_hdl);
+	drv_ctxt->dev_ctxt.sched_hdl = NULL;
+
+	if (vcd_power_event(&drv_ctxt->dev_ctxt, NULL,
+			VCD_EVT_PWR_DEV_INIT_FAIL))
+		VCD_MSG_ERROR("VCD_EVT_PWR_DEV_INIT_FAIL failed");
+
+	vcd_do_device_state_transition(drv_ctxt, VCD_DEVICE_STATE_NOT_INIT,
+		DEVICE_STATE_EVENT_NUMBER(pf_dev_cb));
+}
+
+u32 vcd_deinit_device_context(struct vcd_drv_ctxt *drv_ctxt, u32 ev_code)
+{
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_deinit_device_context:");
+
+	rc = vcd_power_event(&drv_ctxt->dev_ctxt, NULL,
+		VCD_EVT_PWR_DEV_TERM_BEGIN);
+
+	VCD_FAILED_RETURN(rc, "VCD_EVT_PWR_DEV_TERM_BEGIN failed");
+
+	rc = ddl_device_release(NULL);
+
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: ddl_device_release", rc);
+
+		vcd_power_event(dev_ctxt, NULL, VCD_EVT_PWR_DEV_TERM_FAIL);
+	} else {
+		sched_destroy(dev_ctxt->sched_hdl);
+		dev_ctxt->sched_hdl = NULL;
+
+		vcd_power_event(dev_ctxt, NULL, VCD_EVT_PWR_DEV_TERM_END);
+
+		vcd_do_device_state_transition(drv_ctxt,
+			VCD_DEVICE_STATE_NOT_INIT, ev_code);
+	}
+	return rc;
+}
+
+void vcd_term_driver_context(struct vcd_drv_ctxt *drv_ctxt)
+{
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+
+	VCD_MSG_HIGH("All driver instances terminated");
+
+	if (dev_ctxt->config.pf_deregister_isr)
+		dev_ctxt->config.pf_deregister_isr();
+
+	if (dev_ctxt->config.pf_un_map_dev_base_addr)
+		dev_ctxt->config.pf_un_map_dev_base_addr();
+
+	if (dev_ctxt->config.pf_timer_release)
+		dev_ctxt->config.pf_timer_release(dev_ctxt->hw_timer_handle);
+
+	kfree(dev_ctxt->trans_tbl);
+
+	memset(dev_ctxt, 0, sizeof(struct vcd_dev_ctxt));
+
+	vcd_do_device_state_transition(drv_ctxt, VCD_DEVICE_STATE_NULL,
+		DEVICE_STATE_EVENT_NUMBER(pf_term));
+
+}
+
+u32 vcd_reset_device_context(struct vcd_drv_ctxt *drv_ctxt, u32 ev_code)
+{
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_reset_device_context:");
+	vcd_reset_device_channels(dev_ctxt);
+	rc = vcd_power_event(&drv_ctxt->dev_ctxt, NULL,
+		VCD_EVT_PWR_DEV_TERM_BEGIN);
+	VCD_FAILED_RETURN(rc, "VCD_EVT_PWR_DEV_TERM_BEGIN failed");
+	if (ddl_reset_hw(0))
+		VCD_MSG_HIGH("HW Reset done");
+	else
+		VCD_MSG_FATAL("HW Reset failed");
+
+	vcd_power_event(dev_ctxt, NULL, VCD_EVT_PWR_DEV_TERM_END);
+
+	return VCD_S_SUCCESS;
+}
+
+void vcd_handle_device_err_fatal(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_clnt_ctxt *trig_clnt)
+{
+	struct vcd_clnt_ctxt *cctxt = dev_ctxt->cctxt_list_head;
+	VCD_MSG_LOW("vcd_handle_device_err_fatal:");
+	while (cctxt) {
+		if (cctxt != trig_clnt) {
+			vcd_clnt_handle_device_err_fatal(cctxt,
+				VCD_EVT_IND_HWERRFATAL);
+		}
+		cctxt = cctxt->next;
+	}
+	dev_ctxt->pending_cmd = VCD_CMD_DEVICE_RESET;
+	vcd_do_device_state_transition(vcd_get_drv_context(),
+		VCD_DEVICE_STATE_INVALID, DEVICE_STATE_EVENT_NUMBER(pf_dev_cb));
+}
+
+void vcd_handle_for_last_clnt_close(
+	struct vcd_dev_ctxt *dev_ctxt, u32 send_deinit)
+{
+	if (!dev_ctxt->cctxt_list_head) {
+		VCD_MSG_HIGH("All clients are closed");
+		if (send_deinit)
+			vcd_deinit_device_context(vcd_get_drv_context(),
+				DEVICE_STATE_EVENT_NUMBER(pf_close));
+		else
+			dev_ctxt->pending_cmd =	VCD_CMD_DEVICE_TERM;
+	}
+}
+void vcd_continue(void)
+{
+	struct vcd_drv_ctxt *drv_ctxt;
+	struct vcd_dev_ctxt *dev_ctxt;
+	u32 cont;
+	struct vcd_transc *transc;
+	u32 rc;
+	VCD_MSG_LOW("vcd_continue:");
+
+	drv_ctxt = vcd_get_drv_context();
+	dev_ctxt = &drv_ctxt->dev_ctxt;
+
+	dev_ctxt->cont = false;
+
+	if (dev_ctxt->pending_cmd == VCD_CMD_DEVICE_INIT) {
+		VCD_MSG_HIGH("VCD_CMD_DEVICE_INIT is pending");
+
+		dev_ctxt->pending_cmd = VCD_CMD_NONE;
+
+		vcd_init_device_context(drv_ctxt,
+			DEVICE_STATE_EVENT_NUMBER(pf_open));
+	} else if (dev_ctxt->pending_cmd == VCD_CMD_DEVICE_TERM) {
+		VCD_MSG_HIGH("VCD_CMD_DEVICE_TERM is pending");
+
+		dev_ctxt->pending_cmd = VCD_CMD_NONE;
+
+		vcd_deinit_device_context(drv_ctxt,
+			DEVICE_STATE_EVENT_NUMBER(pf_close));
+	} else if (dev_ctxt->pending_cmd == VCD_CMD_DEVICE_RESET) {
+		VCD_MSG_HIGH("VCD_CMD_DEVICE_RESET is pending");
+		dev_ctxt->pending_cmd = VCD_CMD_NONE;
+		vcd_reset_device_context(drv_ctxt,
+			DEVICE_STATE_EVENT_NUMBER(pf_dev_cb));
+	} else {
+		if (dev_ctxt->set_perf_lvl_pending) {
+			rc = vcd_power_event(dev_ctxt, NULL,
+				VCD_EVT_PWR_DEV_SET_PERFLVL);
+
+			if (VCD_FAILED(rc)) {
+				VCD_MSG_ERROR
+					("VCD_EVT_PWR_CLNT_SET_PERFLVL failed");
+				VCD_MSG_HIGH("Not running at desired perf "
+					"level.curr=%d, reqd=%d",
+					 dev_ctxt->curr_perf_lvl,
+					 dev_ctxt->reqd_perf_lvl);
+			} else {
+				dev_ctxt->set_perf_lvl_pending = false;
+			}
+		}
+
+		do {
+			cont = false;
+
+			if (vcd_get_command_channel_in_loop(dev_ctxt,
+					&transc)) {
+				if (vcd_submit_command_in_continue(dev_ctxt,
+						transc))
+					cont = true;
+				else {
+					VCD_MSG_MED
+						("No more commands to submit");
+
+					vcd_release_command_channel(dev_ctxt,
+						transc);
+
+					vcd_release_interim_command_channels(
+						dev_ctxt);
+				}
+			}
+		} while (cont);
+
+		do {
+			cont = false;
+
+			if (vcd_get_frame_channel_in_loop(dev_ctxt, &transc)) {
+				if (vcd_try_submit_frame_in_continue(dev_ctxt,
+						transc)) {
+					cont = true;
+				} else {
+					VCD_MSG_MED("No more frames to submit");
+
+					vcd_release_frame_channel(dev_ctxt,
+						transc);
+
+					vcd_release_interim_frame_channels(
+						dev_ctxt);
+				}
+			}
+
+		} while (cont);
+
+		if (!vcd_core_is_busy(dev_ctxt)) {
+			rc = vcd_power_event(dev_ctxt, NULL,
+				VCD_EVT_PWR_CLNT_CMD_END);
+
+			if (VCD_FAILED(rc))
+				VCD_MSG_ERROR("Failed:"
+					"VCD_EVT_PWR_CLNT_CMD_END");
+		}
+	}
+}
+
+static void vcd_pause_all_sessions(struct vcd_dev_ctxt *dev_ctxt)
+{
+	struct vcd_clnt_ctxt *cctxt = dev_ctxt->cctxt_list_head;
+	u32 rc;
+
+	while (cctxt) {
+		if (cctxt->clnt_state.state_table->ev_hdlr.pf_pause) {
+			rc = cctxt->clnt_state.state_table->ev_hdlr.
+				pf_pause(cctxt);
+
+			if (VCD_FAILED(rc))
+				VCD_MSG_ERROR("Client pause failed");
+
+		}
+
+		cctxt = cctxt->next;
+	}
+}
+
+static void vcd_resume_all_sessions(struct vcd_dev_ctxt *dev_ctxt)
+{
+	struct vcd_clnt_ctxt *cctxt = dev_ctxt->cctxt_list_head;
+	u32 rc;
+
+	while (cctxt) {
+		if (cctxt->clnt_state.state_table->ev_hdlr.pf_resume) {
+			rc = cctxt->clnt_state.state_table->ev_hdlr.
+				pf_resume(cctxt);
+
+			if (VCD_FAILED(rc))
+				VCD_MSG_ERROR("Client resume failed");
+
+		}
+
+		cctxt = cctxt->next;
+	}
+}
+
+static u32 vcd_init_cmn(struct vcd_drv_ctxt *drv_ctxt,
+	struct vcd_init_config *config, s32 *driver_handle)
+{
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+	s32 driver_id;
+
+	if (dev_ctxt->config.pf_interrupt_clr != config->pf_interrupt_clr ||
+			dev_ctxt->config.pf_register_isr !=
+			config->pf_register_isr ||
+			dev_ctxt->config.pf_deregister_isr !=
+			config->pf_deregister_isr ||
+			dev_ctxt->config.pf_map_dev_base_addr !=
+			config->pf_map_dev_base_addr ||
+			dev_ctxt->config.pf_un_map_dev_base_addr !=
+			config->pf_un_map_dev_base_addr) {
+		VCD_MSG_ERROR("Device config mismatch");
+		VCD_MSG_HIGH("VCD will be using config from 1st vcd_init");
+	}
+
+	*driver_handle = 0;
+
+	driver_id = 0;
+	while (driver_id < VCD_DRIVER_INSTANCE_MAX &&
+			dev_ctxt->driver_ids[driver_id]) {
+		++driver_id;
+	}
+
+	if (driver_id == VCD_DRIVER_INSTANCE_MAX) {
+		VCD_MSG_ERROR("Max driver instances reached");
+
+		return VCD_ERR_FAIL;
+	}
+
+	++dev_ctxt->refs;
+	dev_ctxt->driver_ids[driver_id] = true;
+	*driver_handle = driver_id + 1;
+
+	VCD_MSG_HIGH("Driver_id = %d. No of driver instances = %d",
+		driver_id, dev_ctxt->refs);
+
+	return VCD_S_SUCCESS;
+
+}
+
+static u32 vcd_init_in_null(struct vcd_drv_ctxt *drv_ctxt,
+		struct vcd_init_config *config, s32 *driver_handle) {
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+	u32 done_create_timer = false;
+	VCD_MSG_LOW("vcd_init_in_dev_null:");
+
+	dev_ctxt->config = *config;
+
+	dev_ctxt->device_base_addr = (u8 *)config->pf_map_dev_base_addr(
+		dev_ctxt->config.device_name);
+
+	if (!dev_ctxt->device_base_addr) {
+		VCD_MSG_ERROR("NULL Device_base_addr");
+
+		return VCD_ERR_FAIL;
+	}
+
+	if (config->pf_register_isr)
+		config->pf_register_isr(dev_ctxt->config.device_name);
+
+	if (config->pf_timer_create) {
+		if (config->pf_timer_create(vcd_hw_timeout_handler, NULL,
+				&dev_ctxt->hw_timer_handle))
+			done_create_timer = true;
+		else {
+			VCD_MSG_ERROR("timercreate failed");
+			return VCD_ERR_FAIL;
+		}
+	}
+
+
+	rc = vcd_init_cmn(drv_ctxt, config, driver_handle);
+
+	if (!VCD_FAILED(rc)) {
+		vcd_do_device_state_transition(drv_ctxt,
+			VCD_DEVICE_STATE_NOT_INIT,
+			DEVICE_STATE_EVENT_NUMBER(pf_init));
+	} else {
+		if (dev_ctxt->config.pf_un_map_dev_base_addr)
+			dev_ctxt->config.pf_un_map_dev_base_addr();
+
+		if (dev_ctxt->config.pf_deregister_isr)
+			dev_ctxt->config.pf_deregister_isr();
+
+		if (done_create_timer && dev_ctxt->config.pf_timer_release)
+			dev_ctxt->config.pf_timer_release(
+				dev_ctxt->hw_timer_handle);
+	}
+
+	return rc;
+
+}
+
+u32 npelly_init(void);
+
+static u32 vcd_init_in_not_init(struct vcd_drv_ctxt *drv_ctxt,
+	struct vcd_init_config *config, s32 *driver_handle)
+{
+	u32 rc;
+	VCD_MSG_LOW("vcd_init_in_dev_not_init:");
+
+	rc = npelly_init();
+
+	if (rc)
+		return rc;
+	return vcd_init_cmn(drv_ctxt, config, driver_handle);
+
+}
+
+static u32 vcd_init_in_initing(struct vcd_drv_ctxt *drv_ctxt,
+		struct vcd_init_config *config, s32 *driver_handle)
+{
+	VCD_MSG_LOW("vcd_init_in_dev_initing:");
+
+	return vcd_init_cmn(drv_ctxt, config, driver_handle);
+
+}
+
+static u32 vcd_init_in_ready(struct vcd_drv_ctxt *drv_ctxt,
+	struct vcd_init_config *config, s32 *driver_handle)
+{
+	VCD_MSG_LOW("vcd_init_in_dev_ready:");
+
+	return vcd_init_cmn(drv_ctxt, config, driver_handle);
+}
+
+static u32 vcd_term_cmn(struct vcd_drv_ctxt *drv_ctxt, s32 driver_handle)
+{
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+
+	if (!vcd_validate_driver_handle(dev_ctxt, driver_handle)) {
+		VCD_MSG_ERROR("Invalid driver handle = %d", driver_handle);
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	if (vcd_check_for_client_context(dev_ctxt, driver_handle - 1)) {
+		VCD_MSG_ERROR("Driver has active client");
+
+		return VCD_ERR_BAD_STATE;
+	}
+
+	--dev_ctxt->refs;
+	dev_ctxt->driver_ids[driver_handle - 1] = false;
+
+	VCD_MSG_HIGH("Driver_id %d terminated. No of driver instances = %d",
+			 driver_handle - 1, dev_ctxt->refs);
+
+	return VCD_S_SUCCESS;
+}
+
+static u32 vcd_term_in_not_init(struct vcd_drv_ctxt *drv_ctxt,
+	s32 driver_handle)
+{
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+	u32 rc;
+
+	VCD_MSG_LOW("vcd_term_in_dev_not_init:");
+
+	rc = vcd_term_cmn(drv_ctxt, driver_handle);
+
+	if (!VCD_FAILED(rc) && !dev_ctxt->refs)
+		vcd_term_driver_context(drv_ctxt);
+
+	return rc;
+}
+
+static u32 vcd_term_in_initing(struct vcd_drv_ctxt *drv_ctxt, s32 driver_handle)
+{
+	VCD_MSG_LOW("vcd_term_in_dev_initing:");
+
+	return vcd_term_cmn(drv_ctxt, driver_handle);
+}
+
+static u32 vcd_term_in_ready(struct vcd_drv_ctxt *drv_ctxt, s32 driver_handle)
+{
+	VCD_MSG_LOW("vcd_term_in_dev_ready:");
+
+	return vcd_term_cmn(drv_ctxt, driver_handle);
+}
+
+static u32  vcd_term_in_invalid(struct vcd_drv_ctxt *drv_ctxt,
+	s32 driver_handle)
+{
+	u32 rc;
+	VCD_MSG_LOW("vcd_term_in_invalid:");
+	rc = vcd_term_cmn(drv_ctxt, driver_handle);
+	if (!VCD_FAILED(rc) && !drv_ctxt->dev_ctxt.refs)
+		vcd_term_driver_context(drv_ctxt);
+
+	return rc;
+}
+
+static u32 vcd_open_cmn(struct vcd_drv_ctxt *drv_ctxt, s32 driver_handle,
+	u32 decoding, void (*callback) (u32 event, u32 status, void *info,
+	u32 size, void *handle, void *const client_data), void *client_data,
+	struct vcd_clnt_ctxt **pp_cctxt)
+{
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+	struct vcd_clnt_ctxt *cctxt;
+	struct vcd_clnt_ctxt *client;
+
+	if (!vcd_validate_driver_handle(dev_ctxt, driver_handle)) {
+		VCD_MSG_ERROR("Invalid driver handle = %d", driver_handle);
+
+		return VCD_ERR_BAD_HANDLE;
+	}
+
+	cctxt =	kzalloc(sizeof(struct vcd_clnt_ctxt), GFP_KERNEL);
+	if (!cctxt) {
+		VCD_MSG_ERROR("No memory for client ctxt");
+		return VCD_ERR_ALLOC_FAIL;
+	}
+
+	cctxt->dev_ctxt = dev_ctxt;
+	cctxt->driver_id = driver_handle - 1;
+	cctxt->decoding = decoding;
+	cctxt->callback = callback;
+	cctxt->client_data = client_data;
+
+	client = dev_ctxt->cctxt_list_head;
+	dev_ctxt->cctxt_list_head = cctxt;
+	cctxt->next = client;
+
+	*pp_cctxt = cctxt;
+
+	return VCD_S_SUCCESS;
+
+}
+
+static u32 vcd_open_in_not_init(struct vcd_drv_ctxt *drv_ctxt,
+	s32 driver_handle, u32 decoding, void (*callback) (u32 event,
+	u32 status, void *info, u32 size, void *handle,
+	void *const client_data), void *client_data)
+{
+	struct vcd_clnt_ctxt *cctxt;
+	u32 rc;
+
+	VCD_MSG_LOW("vcd_open_in_dev_not_init:");
+
+	rc = vcd_open_cmn(drv_ctxt, driver_handle, decoding, callback,
+		client_data, &cctxt);
+
+	VCD_FAILED_RETURN(rc, "Failed: vcd_open_cmn");
+
+	rc = vcd_init_device_context(drv_ctxt,
+		DEVICE_STATE_EVENT_NUMBER(pf_open));
+
+	if (VCD_FAILED(rc))
+		vcd_destroy_client_context(cctxt);
+
+	return rc;
+}
+
+static u32 vcd_open_in_initing(struct vcd_drv_ctxt *drv_ctxt, s32 driver_handle,
+	u32 decoding, void (*callback) (u32 event, u32 status, void *info,
+	u32 size, void *handle, void *const client_data), void *client_data)
+{
+	struct vcd_clnt_ctxt *cctxt;
+
+	VCD_MSG_LOW("vcd_open_in_dev_initing:");
+
+	return vcd_open_cmn(drv_ctxt, driver_handle, decoding, callback,
+				 client_data, &cctxt);
+}
+
+static u32 vcd_open_in_ready(struct vcd_drv_ctxt *drv_ctxt, s32 driver_handle,
+	u32 decoding, void (*callback) (u32 event, u32 status, void *info,
+	u32 size, void *handle, void *const client_data), void *client_data)
+{
+	struct vcd_clnt_ctxt *cctxt;
+	struct vcd_handle_container container;
+	u32 rc;
+
+	VCD_MSG_LOW("vcd_open_in_dev_ready:");
+
+	rc = vcd_open_cmn(drv_ctxt, driver_handle, decoding, callback,
+			  client_data, &cctxt);
+
+	VCD_FAILED_RETURN(rc, "Failed: vcd_open_cmn");
+
+	rc = vcd_init_client_context(cctxt);
+
+	if (!VCD_FAILED(rc)) {
+		container.handle = (void *)cctxt;
+
+		callback(VCD_EVT_RESP_OPEN, VCD_S_SUCCESS, &container,
+			sizeof(container), container.handle, client_data);
+	} else {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: vcd_init_client_context", rc);
+
+		vcd_destroy_client_context(cctxt);
+	}
+
+	return rc;
+}
+
+static u32 vcd_close_in_ready(struct vcd_drv_ctxt *drv_ctxt,
+	struct vcd_clnt_ctxt *cctxt) {
+	u32 rc;
+
+	VCD_MSG_LOW("vcd_close_in_dev_ready:");
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_close) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.
+			pf_close(cctxt);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d",
+				  cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	if (!VCD_FAILED(rc))
+		vcd_handle_for_last_clnt_close(&drv_ctxt->dev_ctxt, true);
+
+	return rc;
+}
+
+static u32  vcd_close_in_dev_invalid(struct vcd_drv_ctxt *drv_ctxt,
+	struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc;
+	VCD_MSG_LOW("vcd_close_in_dev_invalid:");
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_close) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.pf_close(cctxt);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d",
+					  cctxt->clnt_state.state);
+		rc = VCD_ERR_BAD_STATE;
+	}
+	if (!VCD_FAILED(rc) && !drv_ctxt->dev_ctxt.cctxt_list_head) {
+		VCD_MSG_HIGH("All INVALID clients are closed");
+		vcd_do_device_state_transition(drv_ctxt,
+			VCD_DEVICE_STATE_NOT_INIT,
+			DEVICE_STATE_EVENT_NUMBER(pf_close));
+	}
+	return rc;
+}
+
+static u32 vcd_resume_in_ready(struct vcd_drv_ctxt *drv_ctxt,
+	struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_resume_in_ready:");
+
+	if (cctxt->clnt_state.state_table->ev_hdlr.pf_resume) {
+		rc = cctxt->clnt_state.state_table->ev_hdlr.pf_resume(cctxt);
+	} else {
+		VCD_MSG_ERROR("Unsupported API in client state %d",
+			cctxt->clnt_state.state);
+
+		rc = VCD_ERR_BAD_STATE;
+	}
+
+	return rc;
+}
+
+static u32 vcd_set_dev_pwr_in_ready(struct vcd_drv_ctxt *drv_ctxt,
+	 enum vcd_power_state pwr_state)
+{
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+
+	VCD_MSG_LOW("vcd_set_dev_pwr_in_ready:");
+
+	switch (pwr_state) {
+	case VCD_PWR_STATE_SLEEP:
+		vcd_pause_all_sessions(dev_ctxt);
+
+		dev_ctxt->pwr_state = VCD_PWR_STATE_SLEEP;
+
+		break;
+	case VCD_PWR_STATE_ON:
+		if (dev_ctxt->pwr_state == VCD_PWR_STATE_SLEEP)
+			vcd_resume_all_sessions(dev_ctxt);
+
+		dev_ctxt->pwr_state = VCD_PWR_STATE_ON;
+		break;
+	default:
+		VCD_MSG_ERROR("Invalid power state requested %d",
+				  pwr_state);
+		break;
+	}
+	return rc;
+}
+
+static void vcd_dev_cb_in_initing(struct vcd_drv_ctxt *drv_ctxt, u32 event,
+	 u32 status, void *payload, u32 size, u32 *ddl_handle,
+	 void *const client_data)
+{
+	struct vcd_dev_ctxt *dev_ctxt;
+	struct vcd_clnt_ctxt *client;
+	struct vcd_clnt_ctxt *tmp_client;
+	struct vcd_handle_container container;
+	u32 rc = VCD_S_SUCCESS;
+	u32 client_inited = false;
+	u32 fail_all_open = false;
+
+	VCD_MSG_LOW("vcd_dev_cb_in_initing:");
+
+	if (event != VCD_EVT_RESP_DEVICE_INIT) {
+		VCD_MSG_ERROR("vcd_dev_cb_in_initing: Unexpected event %d",
+			(int)event);
+		return;
+	}
+
+	dev_ctxt = &drv_ctxt->dev_ctxt;
+
+	dev_ctxt->cont = false;
+
+	if (VCD_FAILED(status)) {
+		vcd_handle_device_init_failed(drv_ctxt, status);
+
+		return;
+	}
+
+	vcd_do_device_state_transition(drv_ctxt, VCD_DEVICE_STATE_READY,
+		DEVICE_STATE_EVENT_NUMBER(pf_open));
+
+	if (!dev_ctxt->cctxt_list_head) {
+		VCD_MSG_HIGH("All clients are closed");
+
+		dev_ctxt->pending_cmd = VCD_CMD_DEVICE_TERM;
+
+		return;
+	}
+
+	if (!dev_ctxt->ddl_cmd_ch_depth || !dev_ctxt->trans_tbl)
+		rc = vcd_setup_with_ddl_capabilities(dev_ctxt);
+
+
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x: Failed "
+			"vcd_setup_with_ddl_capabilities", rc);
+
+		fail_all_open = true;
+	}
+
+	client = dev_ctxt->cctxt_list_head;
+	while (client) {
+		if (!fail_all_open)
+			rc = vcd_init_client_context(client);
+
+
+		if (!VCD_FAILED(rc)) {
+			container.handle = (void *)client;
+			client->callback(VCD_EVT_RESP_OPEN, VCD_S_SUCCESS,
+				&container, sizeof(container), container.handle,
+				client->client_data);
+
+			client = client->next;
+
+			client_inited = true;
+		} else {
+			VCD_MSG_ERROR("rc = 0x%x, Failed: "
+				"vcd_init_client_context", rc);
+
+			client->callback(VCD_EVT_RESP_OPEN, rc, NULL, 0, 0,
+				client->client_data);
+
+			tmp_client = client;
+			client = client->next;
+
+			vcd_destroy_client_context(tmp_client);
+		}
+	}
+
+	if (!client_inited || fail_all_open) {
+		VCD_MSG_ERROR("All client open requests failed");
+
+		dev_ctxt->pending_cmd = VCD_CMD_DEVICE_TERM;
+	} else if (vcd_power_event(dev_ctxt, NULL, VCD_EVT_PWR_DEV_INIT_END)) {
+		VCD_MSG_ERROR("VCD_EVT_PWR_DEV_INIT_END failed");
+	}
+}
+
+static void  vcd_hw_timeout_cmn(struct vcd_drv_ctxt *drv_ctxt, void *user_data)
+{
+	struct vcd_dev_ctxt *dev_ctxt = &drv_ctxt->dev_ctxt;
+	VCD_MSG_LOW("vcd_hw_timeout_cmn:");
+	vcd_device_timer_stop(dev_ctxt);
+
+	vcd_handle_device_err_fatal(dev_ctxt, NULL);
+
+	/* Reset HW. */
+	vcd_reset_device_context(drv_ctxt, DEVICE_STATE_EVENT_NUMBER(
+		pf_timeout));
+}
+
+static void vcd_dev_enter_null(struct vcd_drv_ctxt *drv_ctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering DEVICE_STATE_NULL on api %d", ev_code);
+}
+
+static void vcd_dev_enter_not_init(struct vcd_drv_ctxt *drv_ctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering DEVICE_STATE_NOT_INIT on api %d", ev_code);
+}
+
+static void vcd_dev_enter_initing(struct vcd_drv_ctxt *drv_ctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering DEVICE_STATE_INITING on api %d", ev_code);
+}
+
+static void vcd_dev_enter_ready(struct vcd_drv_ctxt *drv_ctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering DEVICE_STATE_READY on api %d", ev_code);
+}
+
+static void vcd_dev_enter_invalid(struct vcd_drv_ctxt *drv_ctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Entering DEVICE_STATE_INVALID on api %d", ev_code);
+}
+
+static void vcd_dev_exit_null(struct vcd_drv_ctxt *drv_ctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting DEVICE_STATE_NULL on api %d", ev_code);
+}
+
+static void vcd_dev_exit_not_init(struct vcd_drv_ctxt *drv_ctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting DEVICE_STATE_NOT_INIT on api %d", ev_code);
+}
+
+static void vcd_dev_exit_initing(struct vcd_drv_ctxt *drv_ctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting DEVICE_STATE_INITING on api %d", ev_code);
+}
+
+static void vcd_dev_exit_ready(struct vcd_drv_ctxt *drv_ctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting DEVICE_STATE_READY on api %d", ev_code);
+}
+
+static void vcd_dev_exit_invalid(struct vcd_drv_ctxt *drv_ctxt, s32 ev_code)
+{
+	VCD_MSG_MED("Exiting DEVICE_STATE_INVALID on api %d", ev_code);
+}
+
+static const struct vcd_dev_state_table vcd_dev_table_null = {
+	{
+		vcd_init_in_null,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+	},
+	vcd_dev_enter_null,
+	vcd_dev_exit_null
+};
+
+static const struct vcd_dev_state_table vcd_dev_table_not_init = {
+	{
+		vcd_init_in_not_init,
+		vcd_term_in_not_init,
+		vcd_open_in_not_init,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+	},
+	vcd_dev_enter_not_init,
+	vcd_dev_exit_not_init
+};
+
+static const struct vcd_dev_state_table vcd_dev_table_initing = {
+	{
+		vcd_init_in_initing,
+		vcd_term_in_initing,
+		vcd_open_in_initing,
+		NULL,
+		NULL,
+		NULL,
+		vcd_dev_cb_in_initing,
+		vcd_hw_timeout_cmn,
+	},
+	vcd_dev_enter_initing,
+	vcd_dev_exit_initing
+};
+
+static const struct vcd_dev_state_table vcd_dev_table_ready = {
+	{
+		vcd_init_in_ready,
+		vcd_term_in_ready,
+		vcd_open_in_ready,
+		vcd_close_in_ready,
+		vcd_resume_in_ready,
+		vcd_set_dev_pwr_in_ready,
+		NULL,
+		vcd_hw_timeout_cmn,
+	},
+	vcd_dev_enter_ready,
+	vcd_dev_exit_ready
+};
+
+static const struct vcd_dev_state_table vcd_dev_table_in_invalid = {
+	{
+		NULL,
+		vcd_term_in_invalid,
+		NULL,
+		vcd_close_in_dev_invalid,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+	},
+	vcd_dev_enter_invalid,
+	vcd_dev_exit_invalid
+};
+
+static const struct vcd_dev_state_table *vcd_dev_state_table[] = {
+	&vcd_dev_table_null,
+	&vcd_dev_table_not_init,
+	&vcd_dev_table_initing,
+	&vcd_dev_table_ready,
+	&vcd_dev_table_in_invalid
+};
diff --git a/drivers/misc/video_core/720p/vcd/vcd_device_sm.h b/drivers/misc/video_core/720p/vcd/vcd_device_sm.h
new file mode 100644
index 0000000..0ba70d2
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_device_sm.h
@@ -0,0 +1,106 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_DEVICE_SM_H_
+#define _VCD_DEVICE_SM_H_
+
+#include "vcd_api.h"
+#include "vcd_ddl_api.h"
+#include "vcd_core.h"
+
+struct vcd_dev_state_table;
+struct vcd_dev_state_ctxt;
+struct vcd_drv_ctxt;
+
+enum vcd_dev_state_enum {
+	VCD_DEVICE_STATE_NULL = 0,
+	VCD_DEVICE_STATE_NOT_INIT,
+	VCD_DEVICE_STATE_INITING,
+	VCD_DEVICE_STATE_READY,
+	VCD_DEVICE_STATE_INVALID,
+	VCD_DEVICE_STATE_MAX,
+	VCD_DEVICE_STATE_32BIT = 0x7FFFFFFF
+};
+
+struct vcd_dev_state_table {
+	struct {
+		u32(*pf_init) (struct vcd_drv_ctxt *drv_ctxt,
+			struct vcd_init_config *config,	s32 *driver_handle);
+
+		u32(*pf_term) (struct vcd_drv_ctxt *drv_ctxt,
+			s32 driver_handle);
+
+		u32(*pf_open) (struct vcd_drv_ctxt *drv_ctxt,
+			s32 driver_handle, u32 decoding,
+			void (*callback) (u32 event, u32 status, void *info,
+			u32 size, void *handle,	void *const client_data),
+			void *client_data);
+
+		u32(*pf_close) (struct vcd_drv_ctxt *drv_ctxt,
+			struct vcd_clnt_ctxt *cctxt);
+
+		u32(*pf_resume) (struct vcd_drv_ctxt *drv_ctxt,
+			struct vcd_clnt_ctxt *cctxt);
+
+		u32(*pf_set_dev_pwr) (struct vcd_drv_ctxt *drv_ctxt,
+			enum vcd_power_state pwr_state);
+
+		void (*pf_dev_cb) (struct vcd_drv_ctxt *drv_ctxt,
+			u32 event, u32 status, void *payload, u32 size,
+			u32 *ddl_handle, void *const client_data);
+
+		void (*pf_timeout) (struct vcd_drv_ctxt *drv_ctxt,
+			void *user_data);
+	} ev_hdlr;
+
+	void (*pf_entry) (struct vcd_drv_ctxt *drv_ctxt, s32 state_event_type);
+	void (*pf_exit) (struct vcd_drv_ctxt *drv_ctxt, s32 state_event_type);
+};
+
+#define DEVICE_STATE_EVENT_NUMBER(ppf) \
+	((u32 *) (&(((struct vcd_dev_state_table*)0)->ev_hdlr.ppf)) - \
+	(u32 *) (&(((struct vcd_dev_state_table*)0)->ev_hdlr.pf_init)) \
+	+ 1)
+
+struct vcd_dev_state_ctxt {
+	const struct vcd_dev_state_table *state_table;
+
+	enum vcd_dev_state_enum state;
+};
+
+struct vcd_drv_ctxt {
+	struct vcd_dev_state_ctxt dev_state;
+	struct vcd_dev_ctxt dev_ctxt;
+	struct mutex *dev_mutex;
+};
+
+extern struct vcd_drv_ctxt *vcd_get_drv_context(void);
+
+void vcd_continue(void);
+
+#endif
diff --git a/drivers/misc/video_core/720p/vcd/vcd_power_sm.c b/drivers/misc/video_core/720p/vcd/vcd_power_sm.c
new file mode 100644
index 0000000..5685417
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_power_sm.c
@@ -0,0 +1,316 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "video_core_type.h"
+#include "vcd_power_sm.h"
+#include "vcd_core.h"
+#include "vcd.h"
+
+u32 vcd_power_event(struct vcd_dev_ctxt *dev_ctxt, struct vcd_clnt_ctxt *cctxt,
+	u32 event)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_MED("Device power state = %d\n", dev_ctxt->pwr_clk_state);
+	VCD_MSG_MED("event = 0x%x\n", event);
+	switch (event) {
+	case VCD_EVT_PWR_DEV_INIT_BEGIN:
+	case VCD_EVT_PWR_DEV_INIT_END:
+	case VCD_EVT_PWR_DEV_INIT_FAIL:
+	case VCD_EVT_PWR_DEV_TERM_BEGIN:
+	case VCD_EVT_PWR_DEV_TERM_END:
+	case VCD_EVT_PWR_DEV_TERM_FAIL:
+	case VCD_EVT_PWR_DEV_SLEEP_BEGIN:
+	case VCD_EVT_PWR_DEV_SLEEP_END:
+	case VCD_EVT_PWR_DEV_SET_PERFLVL:
+	case VCD_EVT_PWR_DEV_HWTIMEOUT:
+		rc = vcd_device_power_event(dev_ctxt, event, cctxt);
+		break;
+	case VCD_EVT_PWR_CLNT_CMD_BEGIN:
+	case VCD_EVT_PWR_CLNT_CMD_END:
+	case VCD_EVT_PWR_CLNT_CMD_FAIL:
+	case VCD_EVT_PWR_CLNT_PAUSE:
+	case VCD_EVT_PWR_CLNT_RESUME:
+	case VCD_EVT_PWR_CLNT_FIRST_FRAME:
+	case VCD_EVT_PWR_CLNT_LAST_FRAME:
+	case VCD_EVT_PWR_CLNT_ERRFATAL:
+		rc = vcd_client_power_event(dev_ctxt, cctxt, event);
+		break;
+	}
+
+	if (VCD_FAILED(rc))
+		VCD_MSG_ERROR("vcd_power_event: event 0x%x failed\n", event);
+
+	return rc;
+
+}
+
+u32 vcd_device_power_event(struct vcd_dev_ctxt *dev_ctxt, u32 event,
+	struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_ERR_FAIL;
+	u32 set_perf_lvl;
+
+	switch (event) {
+	case VCD_EVT_PWR_DEV_INIT_BEGIN:
+		if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_OFF &&
+				res_trk_get_max_perf_level(
+				&dev_ctxt->max_perf_lvl) &&
+				res_trk_power_up()) {
+			dev_ctxt->pwr_clk_state =
+				VCD_PWRCLK_STATE_ON_NOTCLOCKED;
+			dev_ctxt->curr_perf_lvl = 0;
+			dev_ctxt->reqd_perf_lvl = 0;
+			dev_ctxt->active_clnts = 0;
+			dev_ctxt->set_perf_lvl_pending = false;
+			rc = vcd_enable_clock(dev_ctxt,	cctxt);
+			if (VCD_FAILED(rc)) {
+				res_trk_power_down();
+				dev_ctxt->pwr_clk_state = VCD_PWRCLK_STATE_OFF;
+			}
+		}
+		break;
+	case VCD_EVT_PWR_DEV_INIT_END:
+	case VCD_EVT_PWR_DEV_TERM_FAIL:
+	case VCD_EVT_PWR_DEV_SLEEP_BEGIN:
+	case VCD_EVT_PWR_DEV_HWTIMEOUT:
+		rc = vcd_gate_clock(dev_ctxt);
+		break;
+	case VCD_EVT_PWR_DEV_INIT_FAIL:
+	case VCD_EVT_PWR_DEV_TERM_END:
+		if (dev_ctxt->pwr_clk_state != VCD_PWRCLK_STATE_OFF) {
+			vcd_disable_clock(dev_ctxt);
+			res_trk_power_down();
+
+			dev_ctxt->pwr_clk_state = VCD_PWRCLK_STATE_OFF;
+			dev_ctxt->curr_perf_lvl = 0;
+			dev_ctxt->reqd_perf_lvl = 0;
+			dev_ctxt->active_clnts = 0;
+			dev_ctxt->set_perf_lvl_pending = false;
+			rc = VCD_S_SUCCESS;
+		}
+		break;
+	case VCD_EVT_PWR_DEV_TERM_BEGIN:
+	case VCD_EVT_PWR_DEV_SLEEP_END:
+		rc = vcd_un_gate_clock(dev_ctxt);
+		break;
+	case VCD_EVT_PWR_DEV_SET_PERFLVL:
+		set_perf_lvl = dev_ctxt->reqd_perf_lvl > 0 ?
+			dev_ctxt->reqd_perf_lvl : VCD_MIN_PERF_LEVEL;
+		rc = vcd_set_perf_level(dev_ctxt, set_perf_lvl, cctxt);
+		break;
+	}
+	return rc;
+}
+
+u32 vcd_client_power_event(struct vcd_dev_ctxt *dev_ctxt, struct vcd_clnt_ctxt
+	*cctxt, u32 event)
+{
+	u32 rc = VCD_ERR_FAIL;
+
+	switch (event) {
+	case VCD_EVT_PWR_CLNT_CMD_BEGIN:
+		rc = vcd_un_gate_clock(dev_ctxt);
+		break;
+	case VCD_EVT_PWR_CLNT_CMD_END:
+		rc = vcd_gate_clock(dev_ctxt);
+		break;
+	case VCD_EVT_PWR_CLNT_CMD_FAIL:
+		if (!vcd_core_is_busy(dev_ctxt))
+			rc = vcd_gate_clock(dev_ctxt);
+		break;
+	case VCD_EVT_PWR_CLNT_PAUSE:
+	case VCD_EVT_PWR_CLNT_LAST_FRAME:
+	case VCD_EVT_PWR_CLNT_ERRFATAL:
+		if (!cctxt)
+			break;
+		rc = VCD_S_SUCCESS;
+		if (cctxt->status.req_perf_lvl) {
+			dev_ctxt->reqd_perf_lvl -= cctxt->reqd_perf_lvl;
+			cctxt->status.req_perf_lvl = false;
+
+			rc = vcd_set_perf_level(dev_ctxt,
+				dev_ctxt->reqd_perf_lvl, cctxt);
+		}
+		break;
+	case VCD_EVT_PWR_CLNT_RESUME:
+	case VCD_EVT_PWR_CLNT_FIRST_FRAME:
+		if (!cctxt)
+			break;
+		rc = VCD_S_SUCCESS;
+		if (!cctxt->status.req_perf_lvl) {
+			dev_ctxt->reqd_perf_lvl += cctxt->reqd_perf_lvl;
+			cctxt->status.req_perf_lvl = true;
+
+			rc = vcd_set_perf_level(dev_ctxt,
+				dev_ctxt->reqd_perf_lvl, cctxt);
+		}
+		break;
+	}
+
+	return rc;
+}
+
+u32 vcd_enable_clock(struct vcd_dev_ctxt *dev_ctxt, struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+	u32 set_perf_lvl;
+
+	if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_OFF) {
+		VCD_MSG_ERROR("vcd_enable_clock(): Already in state "
+			"VCD_PWRCLK_STATE_OFF\n");
+		vcd_assert();
+		rc = VCD_ERR_FAIL;
+	} else if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_NOTCLOCKED) {
+
+		set_perf_lvl = dev_ctxt->reqd_perf_lvl > 0 ?
+			dev_ctxt->reqd_perf_lvl : VCD_MIN_PERF_LEVEL;
+
+		rc = vcd_set_perf_level(dev_ctxt, set_perf_lvl, cctxt);
+
+		if (!VCD_FAILED(rc)) {
+			if (res_trk_enable_clocks()) {
+				dev_ctxt->pwr_clk_state =
+						VCD_PWRCLK_STATE_ON_CLOCKED;
+			}
+		} else {
+			rc = VCD_ERR_FAIL;
+		}
+
+	}
+
+	if (!VCD_FAILED(rc))
+		dev_ctxt->active_clnts++;
+
+	return rc;
+}
+
+u32 vcd_disable_clock(struct vcd_dev_ctxt *dev_ctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_OFF) {
+		VCD_MSG_ERROR("vcd_disable_clock(): Already in state "
+			"VCD_PWRCLK_STATE_OFF\n");
+		vcd_assert();
+		rc = VCD_ERR_FAIL;
+	} else if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_CLOCKED ||
+		dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_CLOCKGATED) {
+		dev_ctxt->active_clnts--;
+
+		if (!dev_ctxt->active_clnts) {
+			if (!res_trk_disable_clocks())
+				rc = VCD_ERR_FAIL;
+
+			dev_ctxt->pwr_clk_state =
+				VCD_PWRCLK_STATE_ON_NOTCLOCKED;
+			dev_ctxt->curr_perf_lvl = 0;
+		}
+	}
+
+	return rc;
+}
+
+u32 vcd_set_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl,
+	struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	if (!vcd_core_is_busy(dev_ctxt)) {
+		if (res_trk_set_perf_level(perf_lvl, &dev_ctxt->curr_perf_lvl,
+				cctxt)) {
+			dev_ctxt->set_perf_lvl_pending = false;
+		} else {
+			rc = VCD_ERR_FAIL;
+			dev_ctxt->set_perf_lvl_pending = true;
+		}
+
+	} else {
+		dev_ctxt->set_perf_lvl_pending = true;
+	}
+
+	return rc;
+}
+
+u32 vcd_update_clnt_perf_lvl(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_property_frame_rate *fps, u32 frm_p_units)
+{
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u32 new_perf_lvl;
+
+	new_perf_lvl = frm_p_units * fps->fps_numerator / fps->fps_denominator;
+
+	if (cctxt->status.req_perf_lvl) {
+		dev_ctxt->reqd_perf_lvl = dev_ctxt->reqd_perf_lvl -
+			cctxt->reqd_perf_lvl + new_perf_lvl;
+
+		rc = vcd_set_perf_level(cctxt->dev_ctxt,
+			dev_ctxt->reqd_perf_lvl, cctxt);
+	}
+
+	cctxt->reqd_perf_lvl = new_perf_lvl;
+
+	return rc;
+}
+
+u32 vcd_gate_clock(struct vcd_dev_ctxt *dev_ctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_OFF ||
+			dev_ctxt->pwr_clk_state ==
+			VCD_PWRCLK_STATE_ON_NOTCLOCKED) {
+		VCD_MSG_ERROR("%s: Clk is Off or Not Clked yet\n", __func__);
+		vcd_assert();
+		return VCD_ERR_FAIL;
+	}
+
+	if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_CLOCKGATED)
+		return rc;
+
+	if (res_trk_disable_clocks())
+		dev_ctxt->pwr_clk_state = VCD_PWRCLK_STATE_ON_CLOCKGATED;
+	else
+		rc = VCD_ERR_FAIL;
+
+	return rc;
+}
+
+u32 vcd_un_gate_clock(struct vcd_dev_ctxt *dev_ctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_OFF ||
+			dev_ctxt->pwr_clk_state ==
+			VCD_PWRCLK_STATE_ON_NOTCLOCKED) {
+		VCD_MSG_ERROR("%s: Clk is Off or Not Clked yet\n", __func__);
+		vcd_assert();
+		return VCD_ERR_FAIL;
+	}
+
+	if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_CLOCKED)
+		return rc;
+
+	if (res_trk_enable_clocks())
+		dev_ctxt->pwr_clk_state = VCD_PWRCLK_STATE_ON_CLOCKED;
+	else
+		rc = VCD_ERR_FAIL;
+
+	return rc;
+}
diff --git a/drivers/misc/video_core/720p/vcd/vcd_power_sm.h b/drivers/misc/video_core/720p/vcd/vcd_power_sm.h
new file mode 100644
index 0000000..b2af5dd
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_power_sm.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_POWERSM_H_
+#define _VCD_POWERSM_H_
+
+#define VCD_EVT_PWR_BASE                0x5000
+#define VCD_EVT_PWR_DEV_INIT_BEGIN      (VCD_EVT_PWR_BASE + 0x1)
+#define VCD_EVT_PWR_DEV_INIT_END        (VCD_EVT_PWR_BASE + 0x2)
+#define VCD_EVT_PWR_DEV_INIT_FAIL       (VCD_EVT_PWR_BASE + 0x3)
+#define VCD_EVT_PWR_DEV_TERM_BEGIN      (VCD_EVT_PWR_BASE + 0x4)
+#define VCD_EVT_PWR_DEV_TERM_END        (VCD_EVT_PWR_BASE + 0x5)
+#define VCD_EVT_PWR_DEV_TERM_FAIL       (VCD_EVT_PWR_BASE + 0x6)
+#define VCD_EVT_PWR_DEV_SLEEP_BEGIN     (VCD_EVT_PWR_BASE + 0x7)
+#define VCD_EVT_PWR_DEV_SLEEP_END       (VCD_EVT_PWR_BASE + 0x8)
+#define VCD_EVT_PWR_DEV_SET_PERFLVL     (VCD_EVT_PWR_BASE + 0x9)
+#define VCD_EVT_PWR_DEV_HWTIMEOUT       (VCD_EVT_PWR_BASE + 0xa)
+#define VCD_EVT_PWR_CLNT_CMD_BEGIN      (VCD_EVT_PWR_BASE + 0xb)
+#define VCD_EVT_PWR_CLNT_CMD_END        (VCD_EVT_PWR_BASE + 0xc)
+#define VCD_EVT_PWR_CLNT_CMD_FAIL       (VCD_EVT_PWR_BASE + 0xd)
+#define VCD_EVT_PWR_CLNT_PAUSE          (VCD_EVT_PWR_BASE + 0xe)
+#define VCD_EVT_PWR_CLNT_RESUME         (VCD_EVT_PWR_BASE + 0xf)
+#define VCD_EVT_PWR_CLNT_FIRST_FRAME    (VCD_EVT_PWR_BASE + 0x10)
+#define VCD_EVT_PWR_CLNT_LAST_FRAME     (VCD_EVT_PWR_BASE + 0x11)
+#define VCD_EVT_PWR_CLNT_ERRFATAL       (VCD_EVT_PWR_BASE + 0x12)
+
+enum vcd_pwr_clk_state_type {
+	VCD_PWRCLK_STATE_OFF = 0,
+	VCD_PWRCLK_STATE_ON_NOTCLOCKED,
+	VCD_PWRCLK_STATE_ON_CLOCKED,
+	VCD_PWRCLK_STATE_ON_CLOCKGATED
+};
+
+#endif
diff --git a/drivers/misc/video_core/720p/vcd/vcd_property.h b/drivers/misc/video_core/720p/vcd/vcd_property.h
new file mode 100644
index 0000000..4df31b6
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_property.h
@@ -0,0 +1,313 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_DRIVER_PROPERTY_H_
+#define _VCD_DRIVER_PROPERTY_H_
+
+#define VCD_START_BASE       0x0
+#define VCD_I_LIVE           (VCD_START_BASE + 0x1)
+#define VCD_I_CODEC          (VCD_START_BASE + 0x2)
+#define VCD_I_FRAME_SIZE     (VCD_START_BASE + 0x3)
+#define VCD_I_METADATA_ENABLE  (VCD_START_BASE + 0x4)
+#define VCD_I_METADATA_HEADER  (VCD_START_BASE + 0x5)
+#define VCD_I_PROFILE        (VCD_START_BASE + 0x6)
+#define VCD_I_LEVEL          (VCD_START_BASE + 0x7)
+#define VCD_I_BUFFER_FORMAT  (VCD_START_BASE + 0x8)
+#define VCD_I_FRAME_RATE  (VCD_START_BASE + 0x9)
+#define VCD_I_TARGET_BITRATE (VCD_START_BASE + 0xA)
+#define VCD_I_MULTI_SLICE    (VCD_START_BASE + 0xB)
+#define VCD_I_ENTROPY_CTRL   (VCD_START_BASE + 0xC)
+#define VCD_I_DEBLOCKING     (VCD_START_BASE + 0xD)
+#define VCD_I_RATE_CONTROL   (VCD_START_BASE + 0xE)
+#define VCD_I_QP_RANGE      (VCD_START_BASE + 0xF)
+#define VCD_I_SESSION_QP    (VCD_START_BASE + 0x10)
+#define VCD_I_INTRA_PERIOD   (VCD_START_BASE + 0x11)
+#define VCD_I_VOP_TIMING     (VCD_START_BASE + 0x12)
+#define VCD_I_SHORT_HEADER   (VCD_START_BASE + 0x13)
+#define VCD_I_SEQ_HEADER    (VCD_START_BASE + 0x14)
+#define VCD_I_HEADER_EXTENSION   (VCD_START_BASE + 0x15)
+#define VCD_I_INTRA_REFRESH  (VCD_START_BASE + 0x16)
+#define VCD_I_POST_FILTER    (VCD_START_BASE + 0x17)
+#define VCD_I_PROGRESSIVE_ONLY (VCD_START_BASE + 0x18)
+
+#define VCD_START_REQ      (VCD_START_BASE + 0x1000)
+#define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
+
+#define VCD_I_RESERVED_BASE  (VCD_START_BASE + 0x10000)
+
+struct vcd_property_hdr {
+	u32 id;
+	size_t sz;
+};
+
+//TODO: Remove?
+struct vcd_property_live {
+	u32             live;
+};
+
+enum vcd_codec {
+	VCD_CODEC_H264      = 0x1,
+	VCD_CODEC_H263      = 0x2,
+	VCD_CODEC_MPEG1     = 0x3,
+	VCD_CODEC_MPEG2     = 0x4,
+	VCD_CODEC_MPEG4     = 0x5,
+	VCD_CODEC_DIVX_3    = 0x6,
+	VCD_CODEC_DIVX_4    = 0x7,
+	VCD_CODEC_DIVX_5    = 0x8,
+	VCD_CODEC_DIVX_6    = 0x9,
+	VCD_CODEC_XVID      = 0xA,
+	VCD_CODEC_VC1       = 0xB,
+	VCD_CODEC_VC1_RCV   = 0xC
+};
+
+struct vcd_property_codec {
+	enum vcd_codec       codec;
+};
+
+struct vcd_property_frame_size {
+	u32              width;
+	u32              height;
+	u32              stride;
+	u32              scan_lines;
+};
+
+
+#define VCD_METADATA_DATANONE       0x001
+#define VCD_METADATA_QCOMFILLER     0x002
+#define VCD_METADATA_QPARRAY        0x004
+#define VCD_METADATA_CONCEALMB      0x008
+#define VCD_METADATA_SEI            0x010
+#define VCD_METADATA_VUI            0x020
+#define VCD_METADATA_VC1            0x040
+#define VCD_METADATA_PASSTHROUGH    0x080
+#define VCD_METADATA_ENC_SLICE      0x100
+
+struct vcd_property_meta_data_enable {
+	u32 meta_data_enable_flag;
+};
+
+struct vcd_property_metadata_hdr {
+	u32 meta_data_id_type;
+	u32 version;
+	u32 port_index;
+	u32 type;
+};
+
+struct vcd_property_frame_rate {
+	u32              fps_denominator;
+	u32              fps_numerator;
+};
+
+struct vcd_property_target_bitrate {
+	u32             target_bitrate;
+};
+
+enum vcd_yuv_buffer_format_type {
+	VCD_BUFFER_FORMAT_NV12      = 0x1,
+	VCD_BUFFER_FORMAT_TILE_4x2    = 0x2,
+	VCD_BUFFER_FORMAT_NV12_16M2KA = 0x3
+};
+
+struct vcd_property_buffer_format {
+	enum vcd_yuv_buffer_format_type  buffer_format;
+};
+
+struct vcd_property_post_filter {
+	u32           post_filter;
+};
+
+enum vcd_codec_profile_type {
+	VCD_PROFILE_UNKNOWN       = 0x0,
+	VCD_PROFILE_MPEG4_SP      = 0x1,
+	VCD_PROFILE_MPEG4_ASP     = 0x2,
+	VCD_PROFILE_H264_BASELINE = 0x3,
+	VCD_PROFILE_H264_MAIN     = 0x4,
+	VCD_PROFILE_H264_HIGH     = 0x5,
+	VCD_PROFILE_H263_BASELINE = 0x6,
+	VCD_PROFILE_VC1_SIMPLE    = 0x7,
+	VCD_PROFILE_VC1_MAIN      = 0x8,
+	VCD_PROFILE_VC1_ADVANCE   = 0x9,
+	VCD_PROFILE_MPEG2_MAIN    = 0xA,
+	VCD_PROFILE_MPEG2_SIMPLE  = 0xB
+};
+
+struct vcd_property_profile {
+	enum vcd_codec_profile_type       profile;
+};
+
+enum vcd_codec_level_type {
+	VCD_LEVEL_UNKNOWN       = 0x0,
+	VCD_LEVEL_MPEG4_0       = 0x1,
+	VCD_LEVEL_MPEG4_0b      = 0x2,
+	VCD_LEVEL_MPEG4_1       = 0x3,
+	VCD_LEVEL_MPEG4_2       = 0x4,
+	VCD_LEVEL_MPEG4_3       = 0x5,
+	VCD_LEVEL_MPEG4_3b      = 0x6,
+	VCD_LEVEL_MPEG4_4       = 0x7,
+	VCD_LEVEL_MPEG4_4a      = 0x8,
+	VCD_LEVEL_MPEG4_5       = 0x9,
+	VCD_LEVEL_MPEG4_6       = 0xA,
+	VCD_LEVEL_MPEG4_7       = 0xB,
+	VCD_LEVEL_MPEG4_X       = 0xC,
+	VCD_LEVEL_H264_1        = 0x10,
+	VCD_LEVEL_H264_1b       = 0x11,
+	VCD_LEVEL_H264_1p1      = 0x12,
+	VCD_LEVEL_H264_1p2      = 0x13,
+	VCD_LEVEL_H264_1p3      = 0x14,
+	VCD_LEVEL_H264_2        = 0x15,
+	VCD_LEVEL_H264_2p1      = 0x16,
+	VCD_LEVEL_H264_2p2      = 0x17,
+	VCD_LEVEL_H264_3        = 0x18,
+	VCD_LEVEL_H264_3p1      = 0x19,
+	VCD_LEVEL_H264_3p2      = 0x1A,
+	VCD_LEVEL_H264_4        = 0x1B,
+	VCD_LEVEL_H264_X        = 0x1C,
+	VCD_LEVEL_H263_10       = 0x20,
+	VCD_LEVEL_H263_20       = 0x21,
+	VCD_LEVEL_H263_30       = 0x22,
+	VCD_LEVEL_H263_40       = 0x23,
+	VCD_LEVEL_H263_45       = 0x24,
+	VCD_LEVEL_H263_50       = 0x25,
+	VCD_LEVEL_H263_60       = 0x26,
+	VCD_LEVEL_H263_70       = 0x27,
+	VCD_LEVEL_H263_X        = 0x28,
+	VCD_LEVEL_MPEG2_LOW     = 0x30,
+	VCD_LEVEL_MPEG2_MAIN    = 0x31,
+	VCD_LEVEL_MPEG2_HIGH_14 = 0x32,
+	VCD_LEVEL_MPEG2_HIGH    = 0x33,
+	VCD_LEVEL_MPEG2_X       = 0x34,
+	VCD_LEVEL_VC1_LOW       = 0x40,
+	VCD_LEVEL_VC1_MEDIUM    = 0x41,
+	VCD_LEVEL_VC1_HIGH      = 0x42,
+	VCD_LEVEL_VC1_0         = 0x43,
+	VCD_LEVEL_VC1_1         = 0x44,
+	VCD_LEVEL_VC1_2         = 0x45,
+	VCD_LEVEL_VC1_3         = 0x46,
+	VCD_LEVEL_VC1_4         = 0x47,
+	VCD_LEVEL_VC1_X         = 0x48
+};
+
+struct vcd_property_level {
+	enum vcd_codec_level_type   level;
+};
+
+enum vcd_m_slice_sel_type {
+	VCD_MSLICE_OFF             = 0x1,
+	VCD_MSLICE_BY_MB_COUNT     = 0x2,
+	VCD_MSLICE_BY_BYTE_COUNT   = 0x3,
+	VCD_MSLICE_BY_GOB          = 0x4
+};
+
+struct vcd_property_multi_slice {
+	enum vcd_m_slice_sel_type m_slice_sel;
+	u32 m_slice_size;
+};
+
+enum vcd_entropy_sel_type {
+	VCD_ENTROPY_SEL_CAVLC = 0x1,
+	VCD_ENTROPY_SEL_CABAC = 0x2
+};
+
+enum vcd_cabac_model_type {
+	VCD_CABAC_MODEL_NUMBER_0 = 0x1,
+	VCD_CABAC_MODEL_NUMBER_1 = 0x2,
+	VCD_CABAC_MODEL_NUMBER_2 = 0x3
+};
+
+struct vcd_property_entropy_control {
+	enum vcd_entropy_sel_type  entropy_sel;
+	enum vcd_cabac_model_type  cabac_model;
+};
+
+enum vcd_db_config_type {
+	VCD_DB_ALL_BLOCKING_BOUNDARY = 0x1,
+	VCD_DB_DISABLE               = 0x2,
+	VCD_DB_SKIP_SLICE_BOUNDARY   = 0x3
+};
+struct vcd_property_db_config {
+	enum vcd_db_config_type    db_config;
+	u32             slice_alpha_offset;
+	u32             slice_beta_offset;
+};
+
+enum vcd_rate_control_type {
+	VCD_RATE_CONTROL_OFF      = 0x1,
+	VCD_RATE_CONTROL_VBR_VFR  = 0x2,
+	VCD_RATE_CONTROL_VBR_CFR  = 0x3,
+	VCD_RATE_CONTROL_CBR_VFR  = 0x4,
+	VCD_RATE_CONTROL_CBR_CFR  = 0x5
+};
+
+struct vcd_property_rate_control {
+	enum vcd_rate_control_type rate_control;
+};
+
+struct vcd_property_qp_range {
+	u32 max_qp;
+	u32 min_qp;
+};
+
+struct vcd_property_session_qp {
+	u32 iframe_qp;
+	u32 frame_qp;
+	u32 bframe_qp;
+};
+
+struct vcd_property_i_period {
+	u32 frames;
+	u32 bframes;
+};
+
+struct vcd_property_vop_timing {
+	u32 vop_time_resolution;
+};
+
+struct vcd_property_short_header {
+	u32 short_header;
+};
+
+struct vcd_property_intra_refresh_mb_number {
+	u32 cir_mb_number;
+};
+
+struct vcd_property_req_i_frame {
+	u32 req_i_frame;
+};
+
+struct vcd_frame_rect {
+	u32 left;
+	u32 top;
+	u32 right;
+	u32 bottom;
+};
+
+struct vcd_property_dec_output_buffer {
+	struct vcd_frame_rect disp_frm;
+};
+
+#endif
diff --git a/drivers/misc/video_core/720p/vcd/vcd_status.h b/drivers/misc/video_core/720p/vcd/vcd_status.h
new file mode 100644
index 0000000..702ed54
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_status.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+
+#ifndef _VCD_ERR_STATUS_H_
+#define _VCD_ERR_STATUS_H_
+
+#define VCD_EVT_RESP_BASE              0x1000
+#define VCD_EVT_RESP_OPEN              (VCD_EVT_RESP_BASE + 0x1)
+#define VCD_EVT_RESP_START             (VCD_EVT_RESP_BASE + 0x2)
+#define VCD_EVT_RESP_STOP              (VCD_EVT_RESP_BASE + 0x3)
+#define VCD_EVT_RESP_PAUSE             (VCD_EVT_RESP_BASE + 0x4)
+#define VCD_EVT_RESP_FLUSH_INPUT_DONE  (VCD_EVT_RESP_BASE + 0x5)
+#define VCD_EVT_RESP_FLUSH_OUTPUT_DONE (VCD_EVT_RESP_BASE + 0x6)
+#define VCD_EVT_RESP_INPUT_FLUSHED     (VCD_EVT_RESP_BASE + 0x7)
+#define VCD_EVT_RESP_OUTPUT_FLUSHED    (VCD_EVT_RESP_BASE + 0x8)
+#define VCD_EVT_RESP_INPUT_DONE        (VCD_EVT_RESP_BASE + 0x9)
+#define VCD_EVT_RESP_OUTPUT_DONE       (VCD_EVT_RESP_BASE + 0xa)
+
+#define VCD_EVT_IND_BASE               0x2000
+#define VCD_EVT_IND_RECONFIG           (VCD_EVT_IND_BASE + 0x1)
+#define VCD_EVT_IND_HWERRFATAL         (VCD_EVT_IND_BASE + 0x2)
+#define VCD_EVT_IND_RESOURCES_LOST     (VCD_EVT_IND_BASE + 0x3)
+
+#define VCD_S_SUCCESS           0x0
+
+#define VCD_S_ERR_BASE              0x80000000
+#define VCD_ERR_FAIL                (VCD_S_ERR_BASE + 0x1)
+#define VCD_ERR_ALLOC_FAIL          (VCD_S_ERR_BASE + 0x2)
+#define VCD_ERR_ILLEGAL_OP          (VCD_S_ERR_BASE + 0x3)
+#define VCD_ERR_ILLEGAL_PARM        (VCD_S_ERR_BASE + 0x4)
+#define VCD_ERR_BAD_POINTER         (VCD_S_ERR_BASE + 0x5)
+#define VCD_ERR_BAD_HANDLE          (VCD_S_ERR_BASE + 0x6)
+#define VCD_ERR_NOT_SUPPORTED       (VCD_S_ERR_BASE + 0x7)
+#define VCD_ERR_BAD_STATE           (VCD_S_ERR_BASE + 0x8)
+#define VCD_ERR_BUSY                (VCD_S_ERR_BASE + 0x9)
+#define VCD_ERR_MAX_CLIENT          (VCD_S_ERR_BASE + 0xa)
+#define VCD_ERR_IFRAME_EXPECTED     (VCD_S_ERR_BASE + 0xb)
+#define VCD_ERR_INTRLCD_FIELD_DROP  (VCD_S_ERR_BASE + 0xc)
+#define VCD_ERR_HW_FATAL            (VCD_S_ERR_BASE + 0xd)
+#define VCD_ERR_BITSTREAM_ERR       (VCD_S_ERR_BASE + 0xe)
+#define VCD_FAILED(rc)   ((rc > VCD_S_ERR_BASE) ? true : false)
+
+#endif
diff --git a/drivers/misc/video_core/720p/vcd/vcd_sub.c b/drivers/misc/video_core/720p/vcd/vcd_sub.c
new file mode 100644
index 0000000..a088cbc
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_sub.c
@@ -0,0 +1,2921 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <asm/div64.h>
+
+#include "video_core_type.h"
+#include "vcd.h"
+#include "vdec_internal.h"
+
+static phys_addr_t vcd_pmem_get_physical(struct video_client_ctx *client_ctx,
+	void *kern_addr)
+{
+	phys_addr_t phys_addr;
+	void __user *user_addr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+
+	if (vid_c_lookup_addr_table(client_ctx, BUFFER_TYPE_INPUT,
+			false, &user_addr, &kern_addr, &phys_addr, &pmem_fd,
+			&file, &buffer_index)) {
+		return phys_addr;
+	}
+	if (vid_c_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+			false, &user_addr, &kern_addr, &phys_addr, &pmem_fd,
+			&file, &buffer_index)) {
+		return phys_addr;
+	}
+	VCD_MSG_ERROR("Couldn't get physical address");
+	return 0;
+}
+
+void vcd_reset_device_channels(struct vcd_dev_ctxt *dev_ctxt)
+{
+	dev_ctxt->ddl_frame_ch_free = dev_ctxt->ddl_frame_ch_depth;
+	dev_ctxt->ddl_cmd_ch_free = dev_ctxt->ddl_cmd_ch_depth;
+	dev_ctxt->ddl_frame_ch_interim = 0;
+	dev_ctxt->ddl_cmd_ch_interim = 0;
+}
+
+u32 vcd_get_command_channel(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc **pp_transc)
+{
+	u32 result = false;
+
+	*pp_transc = NULL;
+
+	if (dev_ctxt->ddl_cmd_ch_free > 0) {
+		if (dev_ctxt->ddl_cmd_concurrency) {
+			--dev_ctxt->ddl_cmd_ch_free;
+			result = true;
+		} else if ((dev_ctxt->ddl_frame_ch_free +
+				dev_ctxt->ddl_frame_ch_interim)	==
+				dev_ctxt->ddl_frame_ch_depth) {
+			--dev_ctxt->ddl_cmd_ch_free;
+			result = true;
+		}
+	}
+
+	if (result) {
+		*pp_transc = vcd_get_free_trans_tbl_entry(dev_ctxt);
+
+		if (!*pp_transc) {
+			result = false;
+
+			vcd_release_command_channel(dev_ctxt, *pp_transc);
+		}
+
+	}
+	return result;
+}
+
+u32 vcd_get_command_channel_in_loop(struct vcd_dev_ctxt *dev_ctxt,
+	 struct vcd_transc **pp_transc)
+{
+	u32 result = false;
+
+	*pp_transc = NULL;
+
+	if (dev_ctxt->ddl_cmd_ch_interim > 0) {
+		if (dev_ctxt->ddl_cmd_concurrency) {
+			--dev_ctxt->ddl_cmd_ch_interim;
+			result = true;
+		} else if ((dev_ctxt->ddl_frame_ch_free +
+				dev_ctxt->ddl_frame_ch_interim)
+				== dev_ctxt->ddl_frame_ch_depth) {
+			--dev_ctxt->ddl_cmd_ch_interim;
+			result = true;
+		}
+	} else {
+		result = vcd_get_command_channel(dev_ctxt, pp_transc);
+	}
+
+	if (result && !*pp_transc) {
+		*pp_transc = vcd_get_free_trans_tbl_entry(dev_ctxt);
+
+		if (!*pp_transc) {
+			result = false;
+
+			++dev_ctxt->ddl_cmd_ch_interim;
+		}
+	}
+
+	return result;
+}
+
+void vcd_mark_command_channel(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc)
+{
+	++dev_ctxt->ddl_cmd_ch_interim;
+
+	vcd_release_trans_tbl_entry(transc);
+	if (dev_ctxt->ddl_cmd_ch_interim + dev_ctxt->ddl_cmd_ch_free >
+			dev_ctxt->ddl_cmd_ch_depth) {
+		VCD_MSG_ERROR("\n Command channel access counters messed up");
+		vcd_assert();
+	}
+}
+
+void vcd_release_command_channel(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc)
+{
+	++dev_ctxt->ddl_cmd_ch_free;
+
+	vcd_release_trans_tbl_entry(transc);
+	if (dev_ctxt->ddl_cmd_ch_interim + dev_ctxt->ddl_cmd_ch_free >
+			dev_ctxt->ddl_cmd_ch_depth) {
+		VCD_MSG_ERROR("\n Command channel access counters messed up");
+		vcd_assert();
+	}
+}
+
+void vcd_release_multiple_command_channels(struct vcd_dev_ctxt *dev_ctxt,
+	u32 channels)
+{
+	dev_ctxt->ddl_cmd_ch_free += channels;
+
+	if (dev_ctxt->ddl_cmd_ch_interim + dev_ctxt->ddl_cmd_ch_free >
+			dev_ctxt->ddl_cmd_ch_depth) {
+		VCD_MSG_ERROR("\n Command channel access counters messed up");
+		vcd_assert();
+	}
+}
+
+void vcd_release_interim_command_channels(struct vcd_dev_ctxt *dev_ctxt)
+{
+	dev_ctxt->ddl_cmd_ch_free += dev_ctxt->ddl_cmd_ch_interim;
+	dev_ctxt->ddl_cmd_ch_interim = 0;
+
+	if (dev_ctxt->ddl_cmd_ch_interim + dev_ctxt->ddl_cmd_ch_free >
+			dev_ctxt->ddl_cmd_ch_depth) {
+		VCD_MSG_ERROR("\n Command channel access counters messed up");
+		vcd_assert();
+	}
+}
+
+u32 vcd_get_frame_channel(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc **pp_transc)
+{
+	u32 result = false;
+
+	if (dev_ctxt->ddl_frame_ch_free > 0) {
+		if (dev_ctxt->ddl_cmd_concurrency) {
+			--dev_ctxt->ddl_frame_ch_free;
+			result = true;
+		} else if ((dev_ctxt->ddl_cmd_ch_free +
+				dev_ctxt->ddl_cmd_ch_interim)
+				== dev_ctxt->ddl_cmd_ch_depth) {
+			--dev_ctxt->ddl_frame_ch_free;
+			result = true;
+		}
+	}
+
+	if (result) {
+		*pp_transc = vcd_get_free_trans_tbl_entry(dev_ctxt);
+
+		if (!*pp_transc) {
+			result = false;
+
+			vcd_release_frame_channel(dev_ctxt, *pp_transc);
+		} else {
+			(*pp_transc)->type = VCD_CMD_CODE_FRAME;
+		}
+
+	}
+
+	return result;
+}
+
+u32 vcd_get_frame_channel_in_loop(struct vcd_dev_ctxt *dev_ctxt,
+	 struct vcd_transc **pp_transc)
+{
+	u32 result = false;
+
+	*pp_transc = NULL;
+
+	if (dev_ctxt->ddl_frame_ch_interim > 0) {
+		if (dev_ctxt->ddl_cmd_concurrency) {
+			--dev_ctxt->ddl_frame_ch_interim;
+			result = true;
+		} else if ((dev_ctxt->ddl_cmd_ch_free +
+				dev_ctxt->ddl_cmd_ch_interim) ==
+				dev_ctxt->ddl_cmd_ch_depth) {
+			--dev_ctxt->ddl_frame_ch_interim;
+			result = true;
+		}
+	} else {
+		result = vcd_get_frame_channel(dev_ctxt, pp_transc);
+	}
+
+	if (result && !*pp_transc) {
+		*pp_transc = vcd_get_free_trans_tbl_entry(dev_ctxt);
+
+		if (!*pp_transc) {
+			result = false;
+			VCD_MSG_FATAL("\n%s: All transactions are busy;"
+				"Couldnt find free one\n", __func__);
+			++dev_ctxt->ddl_frame_ch_interim;
+		}
+
+	}
+
+	return result;
+}
+
+void vcd_mark_frame_channel(struct vcd_dev_ctxt *dev_ctxt)
+{
+	++dev_ctxt->ddl_frame_ch_interim;
+
+	if (dev_ctxt->ddl_frame_ch_interim + dev_ctxt->ddl_frame_ch_free >
+			dev_ctxt->ddl_cmd_ch_depth) {
+		VCD_MSG_FATAL("Frame channel access counters messed up");
+		vcd_assert();
+	}
+}
+
+void vcd_release_frame_channel(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc)
+{
+	++dev_ctxt->ddl_frame_ch_free;
+
+	vcd_release_trans_tbl_entry(transc);
+
+	if (dev_ctxt->ddl_frame_ch_interim + dev_ctxt->ddl_frame_ch_free >
+			dev_ctxt->ddl_cmd_ch_depth) {
+		VCD_MSG_FATAL("Frame channel access counters messed up");
+		vcd_assert();
+	}
+}
+
+void vcd_release_multiple_frame_channels(struct vcd_dev_ctxt
+	*dev_ctxt, u32 channels)
+{
+	dev_ctxt->ddl_frame_ch_free += channels;
+
+	if (dev_ctxt->ddl_frame_ch_interim + dev_ctxt->ddl_frame_ch_free >
+			dev_ctxt->ddl_frame_ch_depth) {
+		VCD_MSG_FATAL("Frame channel access counters messed up");
+		vcd_assert();
+	}
+}
+
+void vcd_release_interim_frame_channels(struct vcd_dev_ctxt
+	*dev_ctxt)
+{
+	dev_ctxt->ddl_frame_ch_free += dev_ctxt->ddl_frame_ch_interim;
+	dev_ctxt->ddl_frame_ch_interim = 0;
+
+	if (dev_ctxt->ddl_frame_ch_free > dev_ctxt->ddl_cmd_ch_depth) {
+		VCD_MSG_FATAL("Frame channel access counters messed up");
+		vcd_assert();
+	}
+}
+
+u32 vcd_core_is_busy(struct vcd_dev_ctxt *dev_ctxt)
+{
+	if (((dev_ctxt->ddl_cmd_ch_free + dev_ctxt->ddl_cmd_ch_interim) !=
+			dev_ctxt->ddl_cmd_ch_depth) ||
+			((dev_ctxt->ddl_frame_ch_free +
+			dev_ctxt->ddl_frame_ch_interim) !=
+			dev_ctxt->ddl_frame_ch_depth)) {
+		return true;
+	} else {
+		return false;
+	}
+}
+
+void vcd_device_timer_start(struct vcd_dev_ctxt *dev_ctxt)
+{
+	if (dev_ctxt->config.pf_timer_start)
+		dev_ctxt->config.pf_timer_start(dev_ctxt->hw_timer_handle,
+			dev_ctxt->hw_time_out);
+}
+
+void vcd_device_timer_stop(struct vcd_dev_ctxt *dev_ctxt)
+{
+	if (dev_ctxt->config.pf_timer_stop)
+		dev_ctxt->config.pf_timer_stop(dev_ctxt->hw_timer_handle);
+}
+
+
+u32 vcd_common_allocate_set_buffer(struct vcd_clnt_ctxt *cctxt,
+	 enum vcd_buffer_type buffer, size_t sz,
+	 struct vcd_buffer_pool **pp_buf_pool)
+{
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_buffer_requirement buf_req;
+	struct vcd_property_hdr prop_hdr;
+	struct vcd_buffer_pool *buf_pool;
+
+	if (buffer == VCD_BUFFER_INPUT) {
+		prop_hdr.id = DDL_I_INPUT_BUF_REQ;
+		buf_pool = &cctxt->in_buf_pool;
+	} else if (buffer == VCD_BUFFER_OUTPUT) {
+		prop_hdr.id = DDL_I_OUTPUT_BUF_REQ;
+		buf_pool = &cctxt->out_buf_pool;
+	} else {
+		rc = VCD_ERR_ILLEGAL_PARM;
+	}
+
+	VCD_FAILED_RETURN(rc, "Invalid buffer type provided");
+
+	*pp_buf_pool = buf_pool;
+
+	if (buf_pool->count > 0 && buf_pool->validated == buf_pool->count) {
+		VCD_MSG_ERROR("Buffer pool is full");
+
+		return VCD_ERR_FAIL;
+	}
+
+	if (!buf_pool->entries) {
+		prop_hdr.sz = sizeof(buf_req);
+		rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &buf_req);
+
+		if (!VCD_FAILED(rc))
+			rc = vcd_alloc_buffer_pool_entries(buf_pool, &buf_req);
+		else
+			VCD_MSG_ERROR("rc = 0x%x. Failed ddl_get_property", rc);
+	}
+
+	if (!VCD_FAILED(rc)) {
+		if (buf_pool->buf_req.size > sz) {
+			VCD_MSG_ERROR("required buffer size %u allocated size "
+				"%u", buf_pool->buf_req.size, sz);
+			rc = VCD_ERR_ILLEGAL_PARM;
+		}
+	}
+
+	return rc;
+}
+
+u32 vcd_set_buffer_internal(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_buffer_pool *buf_pool, void *buf, size_t sz)
+{
+	struct vcd_buffer_entry *buf_entry;
+
+	buf_entry = vcd_find_buffer_pool_entry(buf_pool, buf);
+	if (buf_entry) {
+		VCD_MSG_ERROR("This buffer address already exists");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	if (!IS_ALIGNED((unsigned long)buf, buf_pool->buf_req.align)) {
+		VCD_MSG_ERROR("Provided addr is not aligned");
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	buf_entry = vcd_get_free_buffer_pool_entry(buf_pool);
+	if (!buf_entry) {
+		VCD_MSG_ERROR("Can't allocate buffer pool is full");
+		return VCD_ERR_FAIL;
+	}
+
+	printk("npelly adding %p to buf_pool %p\n", buf, buf_entry);
+	buf_entry->virt_addr = buf;
+
+	buf_entry->phys_addr = vcd_pmem_get_physical(cctxt->client_data, buf);
+
+	if (!buf_entry->phys_addr) {
+		VCD_MSG_ERROR("Couldn't get physical address");
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	if (!IS_ALIGNED((unsigned long)buf_entry->phys_addr,
+			buf_pool->buf_req.align)) {
+		VCD_MSG_ERROR("Physical addr is not aligned");
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	buf_entry->size = sz;
+	buf_entry->frame.alloc_len = sz;
+	buf_entry->allocated = false;
+
+	buf_entry->frame.virt_addr = buf_entry->virt_addr;
+	buf_entry->frame.phys_addr = buf_entry->phys_addr;
+
+	buf_pool->validated++;
+
+	return VCD_S_SUCCESS;
+
+}
+
+u32 vcd_allocate_buffer_internal(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_buffer_pool *buf_pool, size_t buf_size, void **virt_addr,
+	phys_addr_t *phys_addr)
+{
+	struct vcd_buffer_entry *buf_entry;
+	struct vcd_buffer_requirement *buf_req;
+//	u32 addr;
+//	int rc = 0;
+
+	buf_entry = vcd_get_free_buffer_pool_entry(buf_pool);
+	if (!buf_entry) {
+		VCD_MSG_ERROR("Can't allocate buffer pool is full");
+		return VCD_ERR_FAIL;
+	}
+
+	buf_req = &buf_pool->buf_req;
+
+	//TODO strip align crap
+//	buf_size += buf_req->align;
+
+	buf_entry->buffer.virt_addr = dma_alloc_coherent(NULL, buf_size,
+		&buf_entry->buffer.phys_addr, GFP_KERNEL);
+	if (!buf_entry->buffer.virt_addr) {
+		VCD_MSG_ERROR("Buffer allocation failed");
+		return VCD_ERR_ALLOC_FAIL;
+	}
+
+	buf_entry->buffer.size = buf_size;
+	buf_entry->allocated = true;
+
+	buf_entry->frame.alloc_len = buf_entry->buffer.size;
+	buf_entry->frame.virt_addr = buf_entry->buffer.virt_addr;
+	buf_entry->frame.phys_addr = buf_entry->buffer.phys_addr;
+
+	*virt_addr = buf_entry->buffer.virt_addr;
+	*phys_addr = buf_entry->buffer.phys_addr;
+
+	buf_pool->allocated++;
+	buf_pool->validated++;
+
+	return VCD_S_SUCCESS;
+}
+
+u32 vcd_free_one_buffer_internal(struct vcd_clnt_ctxt *cctxt,
+	 enum vcd_buffer_type vcd_buffer_type, u8 *buffer)
+{
+	struct vcd_buffer_pool *buf_pool;
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_buffer_entry *buf_entry;
+
+	if (vcd_buffer_type == VCD_BUFFER_INPUT)
+		buf_pool = &cctxt->in_buf_pool;
+	else if (vcd_buffer_type == VCD_BUFFER_OUTPUT)
+		buf_pool = &cctxt->out_buf_pool;
+	else
+		rc = VCD_ERR_ILLEGAL_PARM;
+
+	VCD_FAILED_RETURN(rc, "Invalid buffer type provided");
+
+	buf_entry = vcd_find_buffer_pool_entry(buf_pool, buffer);
+	if (!buf_entry) {
+		VCD_MSG_ERROR("Buffer addr %p not found. Can't free buffer",
+				  buffer);
+
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+	if (buf_entry->in_use) {
+		VCD_MSG_ERROR("\n Buffer is in use and is not flushed");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+
+	VCD_MSG_LOW("Freeing buffer %p. Allocated %d", buf_entry->virt_addr,
+		buf_entry->allocated);
+
+	if (buf_entry->allocated) {
+		dma_free_coherent(NULL, buf_entry->size, buf_entry->virt_addr,
+			buf_entry->phys_addr);
+		buf_entry->virt_addr = NULL;
+		buf_pool->allocated--;
+
+	}
+
+	memset(buf_entry, 0, sizeof(struct vcd_buffer_entry));
+
+	buf_pool->validated--;
+
+	return VCD_S_SUCCESS;
+}
+
+u32 vcd_free_buffers_internal(struct vcd_clnt_ctxt *cctxt,
+	 struct vcd_buffer_pool *buf_pool)
+{
+	u32 rc = VCD_S_SUCCESS;
+	u32 i;
+
+	VCD_MSG_LOW("vcd_free_buffers_internal:");
+
+	if (!buf_pool->entries)
+		return rc;
+
+	for (i = 1; i <= buf_pool->count; i++) {
+		struct vcd_buffer_entry *b = &buf_pool->entries[i];
+		if (!b->valid || !b->allocated)
+			continue;
+		dma_free_coherent(NULL, b->size, b->virt_addr, b->phys_addr);
+	}
+
+	vcd_reset_buffer_pool_for_reuse(buf_pool);
+
+	return rc;
+}
+
+u32 vcd_alloc_buffer_pool_entries(struct vcd_buffer_pool *buf_pool,
+	struct vcd_buffer_requirement *buf_req)
+{
+
+	VCD_MSG_LOW("vcd_alloc_buffer_pool_entries:");
+
+	buf_pool->buf_req = *buf_req;
+
+	buf_pool->count = buf_req->actual_count;
+	buf_pool->entries = kzalloc(sizeof(struct vcd_buffer_entry) *
+		(buf_pool->count + 1), GFP_KERNEL);
+
+	if (!buf_pool->entries) {
+		VCD_MSG_ERROR("Buf_pool entries alloc failed");
+		return VCD_ERR_ALLOC_FAIL;
+	}
+
+	buf_pool->queue = kzalloc(sizeof(struct vcd_buffer_entry *) *
+		buf_pool->count, GFP_KERNEL);
+
+	if (!buf_pool->queue) {
+		VCD_MSG_ERROR("Buf_pool queue alloc failed");
+		kfree(buf_pool->entries);
+		return VCD_ERR_ALLOC_FAIL;
+	}
+
+	buf_pool->entries[0].valid = true;
+
+	buf_pool->q_head = 0;
+	buf_pool->q_tail = (u16) (buf_pool->count - 1);
+	buf_pool->q_len = 0;
+
+	buf_pool->validated = 0;
+	buf_pool->allocated = 0;
+	buf_pool->in_use = 0;
+
+	return VCD_S_SUCCESS;
+}
+
+void vcd_free_buffer_pool_entries(struct vcd_buffer_pool *buf_pool)
+{
+	VCD_MSG_LOW("vcd_free_buffer_pool_entries:");
+
+	kfree(buf_pool->entries);
+	kfree(buf_pool->queue);
+
+	memset(buf_pool, 0, sizeof(struct vcd_buffer_pool));
+}
+
+void vcd_flush_in_use_buffer_pool_entries(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_buffer_pool *buf_pool, u32 event)
+{
+	u32 i;
+	VCD_MSG_LOW("vcd_flush_buffer_pool_entries: event=0x%x", event);
+
+	if (!buf_pool->entries)
+		return;
+
+	for (i = 0; i <= buf_pool->count; i++) {
+		if (buf_pool->entries[i].virt_addr &&
+				buf_pool->entries[i].in_use) {
+			cctxt->callback(event, VCD_S_SUCCESS,
+				&buf_pool->entries[i].frame,
+				sizeof(struct vcd_frame_data), cctxt,
+				cctxt->client_data);
+			buf_pool->entries[i].in_use = false;
+			VCD_BUFFERPOOL_INUSE_DECREMENT(buf_pool->in_use);
+		}
+	}
+}
+
+
+void vcd_reset_buffer_pool_for_reuse(struct vcd_buffer_pool *buf_pool)
+{
+	VCD_MSG_LOW("vcd_reset_buffer_pool_for_reuse:");
+
+	memset(&buf_pool->entries[1], 0, sizeof(struct vcd_buffer_entry) *
+		buf_pool->count);
+	memset(buf_pool->queue, 0, sizeof(struct vcd_buffer_entry *) *
+		buf_pool->count);
+
+	buf_pool->q_head = 0;
+	buf_pool->q_tail = (u16) (buf_pool->count - 1);
+	buf_pool->q_len = 0;
+
+	buf_pool->validated = 0;
+	buf_pool->allocated = 0;
+	buf_pool->in_use = 0;
+
+}
+
+struct vcd_buffer_entry *vcd_get_free_buffer_pool_entry(struct vcd_buffer_pool
+	*pool)
+{
+	int i;
+	for (i = 1; i <= pool->count; i++) {
+		if (!pool->entries[i].valid) {
+			pool->entries[i].valid = true;
+			return &pool->entries[i];
+		}
+	}
+	return NULL;
+}
+
+struct vcd_buffer_entry *vcd_find_buffer_pool_entry(struct vcd_buffer_pool
+	*pool, void *virt_addr)
+{
+	int i;
+	for (i = 0; i <= pool->count; i++)
+		if (pool->entries[i].virt_addr == virt_addr)
+			return &pool->entries[i];
+	return NULL;
+}
+
+u32 vcd_buffer_pool_entry_en_q(struct vcd_buffer_pool *pool,
+	struct vcd_buffer_entry *entry)
+{
+	u16 i;
+	u16 q_cntr;
+	u32 found = false;
+
+	if (pool->q_len == pool->count)
+		return false;
+
+	for (i = 0, q_cntr = pool->q_head; !found && i < pool->q_len;
+			i++, q_cntr = (q_cntr + 1) % pool->count) {
+		if (pool->queue[q_cntr] == entry)
+			found = true;
+	}
+
+	if (found) {
+		VCD_MSG_HIGH("this output buffer is already present in queue");
+		VCD_MSG_HIGH("virt_addr %p phys_addr %x", entry->virt_addr,
+			entry->phys_addr);
+		return false;
+	}
+
+	pool->q_tail = (pool->q_tail + 1) % pool->count;
+	pool->q_len++;
+	pool->queue[pool->q_tail] = entry;
+
+	return true;
+}
+
+struct vcd_buffer_entry *vcd_buffer_pool_entry_de_q(struct vcd_buffer_pool
+	*pool)
+{
+	struct vcd_buffer_entry *entry;
+
+	if (!pool || !pool->q_len)
+		return NULL;
+
+	entry = pool->queue[pool->q_head];
+	pool->q_head = (pool->q_head + 1) % pool->count;
+	pool->q_len--;
+
+	return entry;
+}
+
+void vcd_flush_output_buffers(struct vcd_clnt_ctxt *cctxt)
+{
+	struct vcd_buffer_pool *buf_pool;
+	struct vcd_buffer_entry *buf_entry;
+	u32 count = 0;
+	struct vcd_property_hdr prop_hdr;
+
+	VCD_MSG_LOW("vcd_flush_output_buffers:");
+
+	buf_pool = &cctxt->out_buf_pool;
+
+	buf_entry = vcd_buffer_pool_entry_de_q(buf_pool);
+	while (buf_entry) {
+		if (!cctxt->decoding || buf_entry->in_use) {
+			buf_entry->frame.data_len = 0;
+
+			cctxt->callback(VCD_EVT_RESP_OUTPUT_FLUSHED,
+				VCD_S_SUCCESS, &buf_entry->frame,
+				sizeof(struct vcd_frame_data),
+				cctxt, cctxt->client_data);
+
+			buf_entry->in_use = false;
+
+			count++;
+		}
+
+		buf_entry = vcd_buffer_pool_entry_de_q(buf_pool);
+	}
+	buf_pool->in_use = 0;
+
+	if (cctxt->sched_clnt_valid && count > 0) {
+		VCD_MSG_LOW("Updating scheduler O tkns = %u", count);
+
+		sched_update_client_o_tkn(cctxt->dev_ctxt->sched_hdl,
+			cctxt->sched_clnt_hdl, false,
+			count * cctxt->sched_o_tkn_per_ip_frm);
+	}
+
+	if (cctxt->ddl_hdl_valid && cctxt->decoding) {
+		prop_hdr.id = DDL_I_REQ_OUTPUT_FLUSH;
+		prop_hdr.sz = sizeof(u32);
+		count = 0x1;
+
+		ddl_set_property(cctxt->ddl_handle, &prop_hdr, &count);
+	}
+}
+
+u32 vcd_flush_buffers(struct vcd_clnt_ctxt *cctxt, u32 mode)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_buffer_entry *buf_entry;
+
+	VCD_MSG_LOW("vcd_flush_buffers:");
+
+	if (mode > VCD_FLUSH_ALL || !(mode & VCD_FLUSH_ALL)) {
+		VCD_MSG_ERROR("Invalid flush mode %d", mode);
+
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+
+	VCD_MSG_MED("Flush mode %d requested", mode);
+
+	if ((mode & VCD_FLUSH_INPUT) && cctxt->sched_clnt_valid) {
+		rc = vcd_map_sched_status(sched_flush_client_buffer(
+			dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+			(void **)&buf_entry));
+
+		while (!VCD_FAILED(rc) && rc != VCD_S_SCHED_QEMPTY &&
+				buf_entry) {
+			if (buf_entry->virt_addr) {
+				cctxt->callback(VCD_EVT_RESP_INPUT_FLUSHED,
+					VCD_S_SUCCESS, &buf_entry->frame,
+					sizeof(struct vcd_frame_data), cctxt,
+					cctxt->client_data);
+			}
+
+			buf_entry->in_use = false;
+			VCD_BUFFERPOOL_INUSE_DECREMENT(
+				cctxt->in_buf_pool.in_use);
+			buf_entry = NULL;
+			rc = vcd_map_sched_status(sched_flush_client_buffer(
+				dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+				(void **)&buf_entry));
+		}
+
+	}
+	VCD_FAILED_RETURN(rc, "Failed: sched_flush_client_buffer");
+
+	if (cctxt->status.frame_submitted > 0) {
+		cctxt->status.flush_mode |= mode;
+	} else {
+		if (mode & VCD_FLUSH_OUTPUT) {
+			vcd_flush_output_buffers(cctxt);
+			vcd_release_all_clnt_frm_transc(cctxt);
+		}
+
+	}
+
+	return VCD_S_SUCCESS;
+}
+
+void vcd_flush_buffers_in_err_fatal(struct vcd_clnt_ctxt *cctxt)
+{
+	VCD_MSG_LOW("\n vcd_flush_buffers_in_err_fatal:");
+	vcd_flush_buffers(cctxt, VCD_FLUSH_ALL);
+	vcd_flush_in_use_buffer_pool_entries(cctxt, &cctxt->in_buf_pool,
+		VCD_EVT_RESP_INPUT_FLUSHED);
+	vcd_flush_in_use_buffer_pool_entries(cctxt, &cctxt->out_buf_pool,
+		VCD_EVT_RESP_OUTPUT_FLUSHED);
+	cctxt->status.flush_mode = VCD_FLUSH_ALL;
+	vcd_send_flush_done(cctxt, VCD_S_SUCCESS);
+}
+
+u32 vcd_init_client_context(struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc;
+
+	VCD_MSG_LOW("vcd_init_client_context:");
+
+	rc = ddl_open(&cctxt->ddl_handle, cctxt->decoding);
+
+	VCD_FAILED_RETURN(rc, "Failed: ddl_open");
+	cctxt->ddl_hdl_valid = true;
+
+	cctxt->clnt_state.state = VCD_CLIENT_STATE_OPEN;
+	cctxt->clnt_state.state_table =	vcd_get_client_state_table(
+		VCD_CLIENT_STATE_OPEN);
+
+	cctxt->signature = VCD_SIGNATURE;
+	cctxt->live = true;
+
+	cctxt->cmd_q.pending_cmd = VCD_CMD_NONE;
+
+	return rc;
+}
+
+void vcd_destroy_client_context(struct vcd_clnt_ctxt *cctxt)
+{
+	struct vcd_dev_ctxt *dev_ctxt;
+	struct vcd_clnt_ctxt *client;
+	u32 rc = VCD_S_SUCCESS;
+	int idx;
+
+	VCD_MSG_LOW("vcd_destroy_client_context:");
+
+	dev_ctxt = cctxt->dev_ctxt;
+
+	if (cctxt == dev_ctxt->cctxt_list_head) {
+		VCD_MSG_MED("Clnt list head clnt being removed");
+
+		dev_ctxt->cctxt_list_head = cctxt->next;
+	} else {
+		client = dev_ctxt->cctxt_list_head;
+		while (client && cctxt != client->next)
+			client = client->next;
+
+		if (client)
+			client->next = cctxt->next;
+
+		if (!client) {
+			rc = VCD_ERR_FAIL;
+
+			VCD_MSG_ERROR("Client not found in client list");
+		}
+	}
+
+	if (VCD_FAILED(rc))
+		return;
+
+	if (cctxt->sched_clnt_valid) {
+		rc = VCD_S_SUCCESS;
+		while (!VCD_FAILED(rc) && rc != VCD_S_SCHED_QEMPTY) {
+
+			rc = vcd_map_sched_status(sched_flush_client_buffer(
+				dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+				(void *)&idx));
+			if (VCD_FAILED(rc))
+				VCD_MSG_ERROR("\n Failed: "
+					"sched_flush_client_buffer");
+		}
+
+		rc = vcd_map_sched_status(sched_remove_client(
+			dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl));
+		if (VCD_FAILED(rc))
+			VCD_MSG_ERROR("\n Failed: sched_remove_client");
+
+		cctxt->sched_clnt_valid = false;
+	}
+
+	if (cctxt->seq_hdr.addr) {
+		dma_free_coherent(NULL, cctxt->seq_hdr.sz, cctxt->seq_hdr.addr,
+			cctxt->seq_hdr_phys_addr);
+		cctxt->seq_hdr.addr = NULL;
+	}
+
+	vcd_free_buffers_internal(cctxt, &cctxt->in_buf_pool);
+	vcd_free_buffers_internal(cctxt, &cctxt->out_buf_pool);
+	vcd_free_buffer_pool_entries(&cctxt->in_buf_pool);
+	vcd_free_buffer_pool_entries(&cctxt->out_buf_pool);
+	vcd_release_all_clnt_transc(cctxt);
+
+	if (cctxt->ddl_hdl_valid) {
+		ddl_close(&cctxt->ddl_handle);
+		cctxt->ddl_hdl_valid = false;
+	}
+	kfree(cctxt);
+}
+
+u32 vcd_check_for_client_context(struct vcd_dev_ctxt *dev_ctxt, s32 driver_id)
+{
+	struct vcd_clnt_ctxt *client;
+
+	client = dev_ctxt->cctxt_list_head;
+	while (client && client->driver_id != driver_id)
+		client = client->next;
+
+	if (!client)
+		return false;
+	else
+		return true;
+}
+
+u32 vcd_validate_driver_handle(struct vcd_dev_ctxt *dev_ctxt, s32 driver_handle)
+{
+	driver_handle--;
+
+	if (driver_handle < 0 || driver_handle >= VCD_DRIVER_INSTANCE_MAX ||
+			!dev_ctxt->driver_ids[driver_handle]) {
+		return false;
+	} else {
+		return true;
+	}
+}
+
+u32 vcd_client_cmd_en_q(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_command_type command)
+{
+	u32 result;
+
+	if (cctxt->cmd_q.pending_cmd == VCD_CMD_NONE) {
+		cctxt->cmd_q.pending_cmd = command;
+		result = true;
+	} else {
+		result = false;
+	}
+
+	return result;
+}
+
+void vcd_client_cmd_flush_and_en_q(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_command_type command)
+{
+	cctxt->cmd_q.pending_cmd = command;
+}
+
+u32 vcd_client_cmd_de_q(struct vcd_clnt_ctxt *cctxt,
+	enum vcd_command_type *command)
+{
+	if (cctxt->cmd_q.pending_cmd == VCD_CMD_NONE)
+		return false;
+
+	*command = cctxt->cmd_q.pending_cmd;
+	cctxt->cmd_q.pending_cmd = VCD_CMD_NONE;
+
+	return true;
+}
+
+u32 vcd_get_next_queued_client_cmd(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_clnt_ctxt **cctxt, enum vcd_command_type *command)
+{
+	struct vcd_clnt_ctxt *client = dev_ctxt->cctxt_list_head;
+	u32 result = false;
+
+	while (client && !result) {
+		*cctxt = client;
+		result = vcd_client_cmd_de_q(client, command);
+		client = client->next;
+	}
+	return result;
+}
+
+u32 vcd_map_sched_status(enum sched_status sched_status)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	switch (sched_status) {
+
+	case SCHED_S_OK:
+		rc = VCD_S_SUCCESS;
+		break;
+
+	case SCHED_S_EOF:
+		rc = VCD_S_SCHED_EOS;
+		break;
+
+	case SCHED_S_QEMPTY:
+		rc = VCD_S_SCHED_QEMPTY;
+		break;
+
+	case SCHED_S_QFULL:
+		rc = VCD_S_SCHED_QFULL;
+		break;
+
+	default:
+		rc = VCD_ERR_FAIL;
+		break;
+	}
+
+	return rc;
+}
+
+u32 vcd_submit_cmd_sess_start(struct vcd_transc *transc)
+{
+	u32 rc;
+	struct vcd_phys_sequence_hdr seq_hdr;
+
+	VCD_MSG_LOW("vcd_submit_cmd_sess_start:");
+
+	if (transc->cctxt->decoding) {
+
+		if (transc->cctxt->seq_hdr.addr) {
+			seq_hdr.sz = transc->cctxt->seq_hdr.sz;
+			seq_hdr.addr = transc->cctxt->seq_hdr_phys_addr;
+
+			rc = ddl_decode_start(transc->cctxt->ddl_handle,
+				&seq_hdr, (void *)transc);
+		} else {
+			rc = ddl_decode_start(transc->cctxt->ddl_handle, NULL,
+				(void *)transc);
+		}
+
+	} else {
+		rc = ddl_encode_start(transc->cctxt->ddl_handle,
+			(void *)transc);
+	}
+	if (!VCD_FAILED(rc)) {
+		transc->cctxt->status.cmd_submitted++;
+		vcd_device_timer_start(transc->cctxt->dev_ctxt);
+	} else
+		VCD_MSG_ERROR("rc = 0x%x. Failed: ddl start", rc);
+
+	return rc;
+}
+
+u32 vcd_submit_cmd_sess_end(struct vcd_transc *transc)
+{
+	u32 rc;
+
+	VCD_MSG_LOW("vcd_submit_cmd_sess_end:");
+
+	if (transc->cctxt->decoding) {
+		rc = ddl_decode_end(transc->cctxt->ddl_handle,
+			(void *)transc);
+	} else {
+		rc = ddl_encode_end(transc->cctxt->ddl_handle,
+			(void *)transc);
+	}
+	if (!VCD_FAILED(rc)) {
+		transc->cctxt->status.cmd_submitted++;
+		vcd_device_timer_start(transc->cctxt->dev_ctxt);
+	} else
+		VCD_MSG_ERROR("rc = 0x%x. Failed: ddl end", rc);
+
+	return rc;
+}
+
+void vcd_submit_cmd_client_close(struct vcd_clnt_ctxt *cctxt)
+{
+	ddl_close(&cctxt->ddl_handle);
+	cctxt->ddl_hdl_valid = false;
+	cctxt->status.cleaning_up = false;
+	if (cctxt->status.close_pending) {
+		vcd_destroy_client_context(cctxt);
+		vcd_handle_for_last_clnt_close(cctxt->dev_ctxt, true);
+	}
+}
+
+u32 vcd_submit_command_in_continue(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc)
+{
+	struct vcd_property_hdr prop_hdr;
+	struct vcd_clnt_ctxt *client = NULL;
+	enum vcd_command_type cmd = VCD_CMD_NONE;
+	u32 rc = VCD_ERR_FAIL;
+	u32 result = false;
+	u32 flush = 0;
+	u32 event = 0;
+
+	VCD_MSG_LOW("\n vcd_submit_command_in_continue:");
+
+	while (1) {
+		result = vcd_get_next_queued_client_cmd(dev_ctxt, &client,
+			&cmd);
+
+		if (!result)
+			break;
+
+		transc->type = cmd;
+		transc->cctxt = client;
+
+		switch (cmd) {
+		case VCD_CMD_CODEC_START:
+			rc = vcd_submit_cmd_sess_start(transc);
+			event = VCD_EVT_RESP_START;
+			break;
+		case VCD_CMD_CODEC_STOP:
+			rc = vcd_submit_cmd_sess_end(transc);
+			event = VCD_EVT_RESP_STOP;
+			break;
+		case VCD_CMD_OUTPUT_FLUSH:
+			prop_hdr.id = DDL_I_REQ_OUTPUT_FLUSH;
+			prop_hdr.sz = sizeof(u32);
+			flush = 0x1;
+			ddl_set_property(client->ddl_handle, &prop_hdr, &flush);
+			vcd_release_command_channel(dev_ctxt, transc);
+			rc = VCD_S_SUCCESS;
+			break;
+		case VCD_CMD_CLIENT_CLOSE:
+			vcd_submit_cmd_client_close(client);
+			vcd_release_command_channel(dev_ctxt, transc);
+			rc = VCD_S_SUCCESS;
+			break;
+		default:
+			VCD_MSG_ERROR("\n vcd_submit_command: Unknown"
+				"command %d", (int)cmd);
+			vcd_assert();
+			break;
+		}
+
+		if (!VCD_FAILED(rc)) {
+			break;
+		} else	{
+			VCD_MSG_ERROR("vcd_submit_command %d: failed 0x%x",
+				cmd, rc);
+			client->callback(event, rc, NULL, 0, client,
+				client->client_data);
+		}
+	}
+	return result;
+}
+
+u32 vcd_schedule_frame(struct vcd_dev_ctxt *dev_ctxt, struct vcd_clnt_ctxt
+	**pp_cctxt, struct vcd_buffer_entry **pp_ip_buf_entry)
+{
+	u32 rc = VCD_S_SUCCESS;
+	VCD_MSG_LOW("vcd_schedule_frame:");
+
+	if (!dev_ctxt->cctxt_list_head) {
+		VCD_MSG_HIGH("Client list empty");
+		return false;
+	}
+
+	rc = vcd_map_sched_status(sched_de_queue_frame(dev_ctxt->sched_hdl,
+		(void **) pp_ip_buf_entry, (void **) pp_cctxt));
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_FATAL("vcd_submit_frame: sched_de_queue_frame"
+			"failed 0x%x", rc);
+	  return false;
+	}
+
+	if (rc == VCD_S_SCHED_QEMPTY) {
+		VCD_MSG_HIGH("No frame available. Sched queues are empty");
+		return false;
+	}
+
+	if (!*pp_cctxt || !*pp_ip_buf_entry) {
+		VCD_MSG_FATAL("Sched returned invalid values. ctxt=%p,"
+			"ipbuf=%p", *pp_cctxt, *pp_ip_buf_entry);
+		return false;
+	}
+
+	if (rc == VCD_S_SCHED_EOS)
+		(*pp_ip_buf_entry)->frame.flags |= VCD_FRAME_FLAG_EOS;
+
+	return true;
+}
+
+void vcd_try_submit_frame(struct vcd_dev_ctxt *dev_ctxt)
+{
+	struct vcd_transc *transc;
+	u32 rc = VCD_S_SUCCESS;
+	struct vcd_clnt_ctxt *cctxt = NULL;
+	struct vcd_buffer_entry *ip_buf_entry = NULL;
+	u32 result = false;
+
+	VCD_MSG_LOW("vcd_try_submit_frame:");
+
+	if (!vcd_get_frame_channel(dev_ctxt, &transc))
+		return;
+
+	if (!vcd_schedule_frame(dev_ctxt, &cctxt, &ip_buf_entry)) {
+		vcd_release_frame_channel(dev_ctxt, transc);
+		return;
+	}
+
+	rc = vcd_power_event(dev_ctxt, cctxt, VCD_EVT_PWR_CLNT_CMD_BEGIN);
+
+	if (!VCD_FAILED(rc)) {
+		transc->cctxt = cctxt;
+		transc->ip_buf_entry = ip_buf_entry;
+
+		result = vcd_submit_frame(dev_ctxt, transc);
+	} else {
+		VCD_MSG_ERROR("Failed: VCD_EVT_PWR_CLNT_CMD_BEGIN");
+
+		vcd_requeue_input_frame(dev_ctxt, cctxt, ip_buf_entry);
+
+		vcd_map_sched_status(sched_update_client_o_tkn(
+			dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+			true, cctxt->sched_o_tkn_per_ip_frm));
+	}
+
+	if (!result) {
+		vcd_release_frame_channel(dev_ctxt, transc);
+		vcd_power_event(dev_ctxt, cctxt, VCD_EVT_PWR_CLNT_CMD_FAIL);
+	}
+}
+
+u32 vcd_submit_frame(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc *transc)
+{
+	struct vcd_clnt_ctxt *cctxt = NULL;
+	struct vcd_frame_data *ip_frm_entry;
+	struct vcd_buffer_entry *op_buf_entry = NULL;
+	u32 rc = VCD_S_SUCCESS;
+	u32 evcode = 0;
+	struct ddl_frame_data_tag ddl_ip_frm;
+	struct ddl_frame_data_tag ddl_op_frm;
+
+	VCD_MSG_LOW("vcd_submit_frame:");
+	cctxt = transc->cctxt;
+	ip_frm_entry = &transc->ip_buf_entry->frame;
+
+	transc->op_buf_entry = op_buf_entry;
+	transc->ip_frm_tag = ip_frm_entry->ip_frm_tag;
+	transc->time_stamp = ip_frm_entry->time_stamp;
+	ip_frm_entry->ip_frm_tag = (u32) transc;
+	memset(&ddl_ip_frm, 0, sizeof(ddl_ip_frm));
+	memset(&ddl_op_frm, 0, sizeof(ddl_op_frm));
+	if (cctxt->decoding) {
+		evcode = CLIENT_STATE_EVENT_NUMBER(pf_decode_frame);
+		ddl_ip_frm.vcd_frm = *ip_frm_entry;
+		rc = ddl_decode_frame(cctxt->ddl_handle, &ddl_ip_frm,
+			(void *) transc);
+	} else {
+		op_buf_entry = vcd_buffer_pool_entry_de_q(&cctxt->out_buf_pool);
+		if (!op_buf_entry) {
+			VCD_MSG_ERROR("Sched provided frame when no"
+				"op buffer was present");
+			rc = VCD_ERR_FAIL;
+		} else {
+			op_buf_entry->in_use = true;
+			cctxt->out_buf_pool.in_use++;
+			ddl_ip_frm.vcd_frm = *ip_frm_entry;
+			ddl_ip_frm.frm_delta = vcd_calculate_frame_delta(cctxt,
+				ip_frm_entry);
+
+			ddl_op_frm.vcd_frm = op_buf_entry->frame;
+
+			evcode = CLIENT_STATE_EVENT_NUMBER(pf_encode_frame);
+
+			rc = ddl_encode_frame(cctxt->ddl_handle, &ddl_ip_frm,
+				&ddl_op_frm, (void *) transc);
+		}
+	}
+	ip_frm_entry->ip_frm_tag = transc->ip_frm_tag;
+	if (!VCD_FAILED(rc)) {
+		vcd_device_timer_start(dev_ctxt);
+		cctxt->status.frame_submitted++;
+		if (ip_frm_entry->flags & VCD_FRAME_FLAG_EOS)
+			vcd_do_client_state_transition(cctxt,
+				VCD_CLIENT_STATE_EOS, evcode);
+	} else {
+		VCD_MSG_ERROR("Frame submission failed. rc = 0x%x", rc);
+		vcd_handle_submit_frame_failed(dev_ctxt, transc);
+	}
+	return true;
+}
+
+u32 vcd_try_submit_frame_in_continue(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc)
+{
+	struct vcd_clnt_ctxt *cctxt = NULL;
+	struct vcd_buffer_entry *ip_buf_entry = NULL;
+
+	VCD_MSG_LOW("vcd_try_submit_frame_in_continue:");
+
+	if (!vcd_schedule_frame(dev_ctxt, &cctxt, &ip_buf_entry))
+		return false;
+
+	transc->cctxt = cctxt;
+	transc->ip_buf_entry = ip_buf_entry;
+
+	return vcd_submit_frame(dev_ctxt, transc);
+}
+
+u32 vcd_process_cmd_sess_start(struct vcd_clnt_ctxt *cctxt)
+{
+	struct vcd_transc *transc;
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_process_cmd_sess_start:");
+	if (vcd_get_command_channel(cctxt->dev_ctxt, &transc)) {
+		rc = vcd_power_event(cctxt->dev_ctxt, cctxt,
+			VCD_EVT_PWR_CLNT_CMD_BEGIN);
+
+		if (!VCD_FAILED(rc)) {
+			transc->type = VCD_CMD_CODEC_START;
+			transc->cctxt = cctxt;
+			rc = vcd_submit_cmd_sess_start(transc);
+		} else {
+			VCD_MSG_ERROR("Failed: VCD_EVT_PWR_CLNT_CMD_BEGIN");
+		}
+
+		if (VCD_FAILED(rc)) {
+			vcd_release_command_channel(cctxt->dev_ctxt,
+							transc);
+		}
+	} else {
+		u32 result;
+
+		result = vcd_client_cmd_en_q(cctxt, VCD_CMD_CODEC_START);
+		if (!result) {
+			rc = VCD_ERR_BUSY;
+			VCD_MSG_ERROR("%s(): vcd_client_cmd_en_q() "
+				"failed\n", __func__);
+			vcd_assert();
+		}
+	}
+
+	if (VCD_FAILED(rc)) {
+		vcd_power_event(cctxt->dev_ctxt, cctxt,
+			VCD_EVT_PWR_CLNT_CMD_FAIL);
+	}
+
+	return rc;
+}
+
+void vcd_send_frame_done_in_eos(struct vcd_clnt_ctxt *cctxt,
+	 struct vcd_frame_data *input_frame, u32 valid_opbuf)
+{
+	VCD_MSG_LOW("vcd_send_frame_done_in_eos:");
+
+	if (!input_frame->virt_addr && !valid_opbuf) {
+		VCD_MSG_MED("Sending NULL output with EOS");
+
+		cctxt->out_buf_pool.entries[0].frame.flags = VCD_FRAME_FLAG_EOS;
+		cctxt->out_buf_pool.entries[0].frame.data_len = 0;
+		cctxt->out_buf_pool.entries[0].frame.time_stamp =
+			input_frame->time_stamp;
+		cctxt->out_buf_pool.entries[0].frame.ip_frm_tag =
+			input_frame->ip_frm_tag;
+
+		cctxt->callback(VCD_EVT_RESP_OUTPUT_DONE, VCD_S_SUCCESS,
+			&cctxt->out_buf_pool.entries[0].frame,
+			sizeof(struct vcd_frame_data), cctxt,
+			cctxt->client_data);
+
+		memset(&cctxt->out_buf_pool.entries[0].frame, 0,
+			sizeof(struct vcd_frame_data));
+	} else if (!input_frame->data_len) {
+		if (cctxt->decoding)
+			vcd_send_frame_done_in_eos_for_dec(cctxt, input_frame);
+		else
+			vcd_send_frame_done_in_eos_for_enc(cctxt, input_frame);
+	}
+}
+
+void vcd_send_frame_done_in_eos_for_dec(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame)
+{
+	struct vcd_buffer_entry *buf_entry;
+	struct vcd_property_hdr prop_hdr;
+	u32 rc;
+	struct ddl_frame_data_tag ddl_frm;
+
+	prop_hdr.id = DDL_I_DPB_RETRIEVE;
+	prop_hdr.sz = sizeof(struct ddl_frame_data_tag);
+	memset(&ddl_frm, 0, sizeof(ddl_frm));
+	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &ddl_frm);
+
+	if (VCD_FAILED(rc) || !ddl_frm.vcd_frm.virt_addr) {
+		cctxt->status.eos_trig_ip_frm = *input_frame;
+		cctxt->status.eos_wait_for_op_buf = true;
+
+		return;
+	}
+
+	buf_entry = vcd_find_buffer_pool_entry(&cctxt->out_buf_pool,
+		ddl_frm.vcd_frm.virt_addr);
+	if (!buf_entry) {
+		VCD_MSG_ERROR("Unrecognized buffer address provided %p",
+				  ddl_frm.vcd_frm.virt_addr);
+		vcd_assert();
+	} else {
+		vcd_map_sched_status(sched_update_client_o_tkn(
+			cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,\
+			false, cctxt->sched_o_tkn_per_ip_frm));
+
+		VCD_MSG_MED("Sending non-NULL output with EOS");
+
+		buf_entry->frame.data_len = 0;
+		buf_entry->frame.offset = 0;
+		buf_entry->frame.flags |= VCD_FRAME_FLAG_EOS;
+		buf_entry->frame.ip_frm_tag = input_frame->ip_frm_tag;
+		buf_entry->frame.time_stamp = input_frame->time_stamp;
+
+		cctxt->callback(VCD_EVT_RESP_OUTPUT_DONE, VCD_S_SUCCESS,
+			&buf_entry->frame, sizeof(struct vcd_frame_data),
+			cctxt, cctxt->client_data);
+
+		buf_entry->in_use = false;
+		VCD_BUFFERPOOL_INUSE_DECREMENT(cctxt->out_buf_pool.in_use);
+	}
+}
+
+void vcd_send_frame_done_in_eos_for_enc(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame)
+{
+	struct vcd_buffer_entry *op_buf_entry;
+
+	if (!cctxt->out_buf_pool.q_len) {
+		cctxt->status.eos_trig_ip_frm = *input_frame;
+
+		cctxt->status.eos_wait_for_op_buf = true;
+
+		return;
+	}
+
+	op_buf_entry = vcd_buffer_pool_entry_de_q(&cctxt->out_buf_pool);
+	if (!op_buf_entry) {
+		VCD_MSG_ERROR("%s(): vcd_buffer_pool_entry_de_q() "
+			"failed\n", __func__);
+		vcd_assert();
+	} else {
+		vcd_map_sched_status(sched_update_client_o_tkn(
+			cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+			false, cctxt->sched_o_tkn_per_ip_frm));
+
+		VCD_MSG_MED("Sending non-NULL output with EOS");
+
+		op_buf_entry->frame.data_len = 0;
+		op_buf_entry->frame.flags |= VCD_FRAME_FLAG_EOS;
+		op_buf_entry->frame.ip_frm_tag = input_frame->ip_frm_tag;
+		op_buf_entry->frame.time_stamp = input_frame->time_stamp;
+
+		cctxt->callback(VCD_EVT_RESP_OUTPUT_DONE, VCD_S_SUCCESS,
+			&op_buf_entry->frame, sizeof(struct vcd_frame_data),
+			cctxt, cctxt->client_data);
+	}
+}
+
+u32 vcd_handle_recvd_eos(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame, u32 *pb_eos_handled)
+{
+	union sched_value_type sched_val;
+	u32 rc;
+
+	VCD_MSG_LOW("vcd_handle_recvd_eos:");
+
+	*pb_eos_handled = false;
+
+	if (input_frame->virt_addr && input_frame->data_len)
+		return VCD_S_SUCCESS;
+
+	input_frame->data_len = 0;
+
+	rc = vcd_map_sched_status(sched_get_client_param(
+		cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+		SCHED_I_CLNT_CURRQLEN, &sched_val));
+
+	VCD_FAILED_RETURN(rc, "Failed: sched_get_client_param");
+
+	if (sched_val.un_value > 0) {
+		rc = vcd_map_sched_status(sched_mark_client_eof(
+			cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl));
+
+		if (!VCD_FAILED(rc)) {
+			*pb_eos_handled = true;
+		} else {
+			VCD_MSG_ERROR("rc = 0x%x. Failed: "
+				"sched_mark_client_eof", rc);
+		}
+
+	} else if (cctxt->decoding && !input_frame->virt_addr) {
+		rc = vcd_map_sched_status(sched_update_client_o_tkn(
+			cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl, true,
+			cctxt->sched_o_tkn_per_ip_frm));
+	} else if (!cctxt->decoding) {
+
+		vcd_send_frame_done_in_eos(cctxt, input_frame, false);
+
+		if (cctxt->status.eos_wait_for_op_buf) {
+			vcd_do_client_state_transition(cctxt,
+				VCD_CLIENT_STATE_EOS,
+				CLIENT_STATE_EVENT_NUMBER(pf_encode_frame));
+		}
+
+		*pb_eos_handled = true;
+
+	}
+
+	if (*pb_eos_handled && input_frame->virt_addr &&
+			!input_frame->data_len) {
+		cctxt->callback(VCD_EVT_RESP_INPUT_DONE, VCD_S_SUCCESS,
+			input_frame, sizeof(struct vcd_frame_data), cctxt,
+			cctxt->client_data);
+	}
+	return rc;
+}
+
+u32 vcd_handle_first_decode_frame(struct vcd_clnt_ctxt *cctxt)
+{
+	struct ddl_property_dec_pic_buffers dpb;
+	struct vcd_property_hdr prop_hdr;
+	u32 rc;
+	u16 i;
+	u16 q_cntr;
+	struct ddl_frame_data_tag *frm_entry;
+	struct ddl_frame_data_tag ddl_frm;
+	struct vcd_buffer_pool *out_buf_pool;
+
+	VCD_MSG_LOW("vcd_handle_first_decode_frame:");
+
+	if (!cctxt->in_buf_pool.entries || !cctxt->out_buf_pool.entries ||
+			cctxt->in_buf_pool.validated !=
+			cctxt->in_buf_pool.count ||
+			cctxt->out_buf_pool.validated !=
+			cctxt->out_buf_pool.count) {
+		VCD_MSG_ERROR("Buffer pool is not completely setup yet");
+
+		return VCD_ERR_BAD_STATE;
+	}
+
+	rc = vcd_add_client_to_sched(cctxt);
+
+	VCD_FAILED_RETURN(rc, "Failed: vcd_add_client_to_sched");
+
+	prop_hdr.id = DDL_I_DPB;
+	prop_hdr.sz = sizeof(dpb);
+
+	out_buf_pool = &cctxt->out_buf_pool;
+
+	frm_entry = kmalloc(sizeof(struct ddl_frame_data_tag) *
+		out_buf_pool->count, GFP_KERNEL);
+	if (!frm_entry) {
+		VCD_MSG_ERROR("Memory allocation failure");
+		return VCD_ERR_ALLOC_FAIL;
+	}
+
+	for (i = 1; i <= out_buf_pool->count; i++)
+		frm_entry[i - 1].vcd_frm = out_buf_pool->entries[i].frame;
+
+	dpb.dec_pic_buffers = frm_entry;
+	dpb.no_of_dec_pic_buf = out_buf_pool->count;
+	rc = ddl_set_property(cctxt->ddl_handle, &prop_hdr, &dpb);
+
+	kfree(frm_entry);
+
+	VCD_FAILED_RETURN(rc, "Failed: DDL set DDL_I_DPB");
+
+	if (out_buf_pool->q_len > 0) {
+		prop_hdr.id = DDL_I_DPB_RELEASE;
+		prop_hdr.sz = sizeof(struct ddl_frame_data_tag);
+
+		for (i = 0, q_cntr = out_buf_pool->q_head; !VCD_FAILED(rc) &&
+				i < out_buf_pool->q_len; i++,
+				q_cntr = (q_cntr + 1) % out_buf_pool->count) {
+
+			ddl_frm.vcd_frm = out_buf_pool->queue[q_cntr]->frame;
+
+			rc = ddl_set_property(cctxt->ddl_handle, &prop_hdr,
+				&ddl_frm);
+
+			if (VCD_FAILED(rc)) {
+				VCD_MSG_ERROR
+					("Error returning output buffer to HW");
+
+				out_buf_pool->queue[q_cntr]->in_use = false;
+			} else {
+				out_buf_pool->queue[q_cntr]->in_use = true;
+				out_buf_pool->in_use++;
+			}
+		}
+
+		if (VCD_FAILED(rc))
+			return rc;
+		rc = vcd_map_sched_status(sched_update_client_o_tkn(
+			cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl, true,
+			cctxt->sched_o_tkn_per_ip_frm * out_buf_pool->q_len));
+	}
+	return rc;
+}
+
+u32 vcd_setup_with_ddl_capabilities(struct vcd_dev_ctxt *dev_ctxt)
+{
+	struct vcd_property_hdr prop_hdr;
+	struct ddl_property_capability capability;
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_LOW("vcd_setup_with_ddl_capabilities:");
+
+	if (dev_ctxt->ddl_cmd_ch_depth)
+		goto out;
+
+	prop_hdr.id = DDL_I_CAPABILITY;
+	prop_hdr.sz = sizeof(capability);
+
+	/*
+	 * Since this is underlying core's property we don't need a
+	 * ddl client handle.
+	 */
+	rc = ddl_get_property(NULL, &prop_hdr, &capability);
+
+	if (VCD_FAILED(rc))
+		goto out;
+
+	/*
+	** Allocate the transaction table.
+	*/
+	dev_ctxt->trans_tbl_size = VCD_MAX_CLIENT_TRANSACTIONS *
+		capability.max_num_client + capability.general_command_depth;
+
+	dev_ctxt->trans_tbl = kzalloc(sizeof(struct vcd_transc) *
+		dev_ctxt->trans_tbl_size, GFP_KERNEL);
+	if (!dev_ctxt->trans_tbl) {
+		VCD_MSG_ERROR("Transaction table alloc failed");
+		rc = VCD_ERR_ALLOC_FAIL;
+		goto out;
+	}
+
+	/*
+	** Set the command/frame depth
+	*/
+	dev_ctxt->ddl_cmd_concurrency =	!capability.exclusive;
+	dev_ctxt->ddl_frame_ch_depth = capability.frame_command_depth;
+	dev_ctxt->ddl_cmd_ch_depth = capability.general_command_depth;
+
+	vcd_reset_device_channels(dev_ctxt);
+
+	dev_ctxt->hw_time_out = capability.ddl_time_out_in_ms;
+
+out:
+	return rc;
+}
+
+struct vcd_transc *vcd_get_free_trans_tbl_entry(struct vcd_dev_ctxt *dev_ctxt)
+{
+	u8 i;
+
+	if (!dev_ctxt->trans_tbl)
+		return NULL;
+
+	i = 0;
+	while (i < dev_ctxt->trans_tbl_size && dev_ctxt->trans_tbl[i].in_use)
+		i++;
+
+	if (i == dev_ctxt->trans_tbl_size) {
+		return NULL;
+	} else {
+		memset(&dev_ctxt->trans_tbl[i], 0, sizeof(struct vcd_transc));
+
+		dev_ctxt->trans_tbl[i].in_use = true;
+
+		return &dev_ctxt->trans_tbl[i];
+	}
+}
+
+void vcd_release_trans_tbl_entry(struct vcd_transc *trans_entry)
+{
+	if (trans_entry)
+		trans_entry->in_use = false;
+}
+
+u32 vcd_add_client_to_sched(struct vcd_clnt_ctxt *cctxt)
+{
+	struct vcd_property_hdr prop_hdr;
+	struct sched_client_init_param sched_input_init;
+	u32 rc, seqhdr_present = 0;;
+
+	if (cctxt->sched_clnt_valid) {
+		VCD_MSG_HIGH("Schedulder client is already added ");
+		return VCD_S_SUCCESS;
+	}
+
+	prop_hdr.id = DDL_I_FRAME_PROC_UNITS;
+	prop_hdr.sz = sizeof(cctxt->frm_p_units);
+	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr,
+		&cctxt->frm_p_units);
+	VCD_FAILED_RETURN(rc, "Failed: Get DDL_I_FRAME_PROC_UNITS");
+
+	if (cctxt->decoding) {
+		cctxt->frm_rate.fps_numerator = VCD_DEC_INITIAL_FRAME_RATE;
+		cctxt->frm_rate.fps_denominator = 1;
+
+		sched_input_init.o_tkn_per_ip_frm =
+			VCD_SCHEDULER_DEC_DFLT_OTKN_PERFRM;
+		cctxt->sched_o_tkn_per_ip_frm =
+			VCD_SCHEDULER_DEC_DFLT_OTKN_PERFRM;
+
+		sched_input_init.o_tkn_max = cctxt->sched_o_tkn_per_ip_frm *
+			cctxt->out_buf_pool.count+1;
+	} else {
+		sched_input_init.o_tkn_per_ip_frm =
+			VCD_SCHEDULER_ENC_DFLT_OTKN_PERFRM;
+		cctxt->sched_o_tkn_per_ip_frm =
+			VCD_SCHEDULER_ENC_DFLT_OTKN_PERFRM;
+		prop_hdr.id = DDL_I_SEQHDR_PRESENT;
+		prop_hdr.sz = sizeof(seqhdr_present);
+		rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr,
+			&seqhdr_present);
+		if (!VCD_FAILED(rc)) {
+			if (seqhdr_present == 0x1) {
+				VCD_MSG_MED("Sequence hdr present");
+				sched_input_init.o_tkn_per_ip_frm++;
+			}
+			sched_input_init.o_tkn_max = cctxt->out_buf_pool.count;
+			prop_hdr.id = VCD_I_FRAME_RATE;
+			prop_hdr.sz = sizeof(cctxt->frm_rate);
+			rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr,
+				&cctxt->frm_rate);
+		}
+	}
+
+	VCD_FAILED_RETURN(rc, "Failed: DDL get VCD_I_FRAME_RATE");
+
+	if (cctxt->live)
+		sched_input_init.client_ctgy = SCHED_CLNT_RT_NOBUFF;
+	else
+		sched_input_init.client_ctgy = SCHED_CLNT_NONRT;
+
+	sched_input_init.max_queue_len = max(cctxt->in_buf_pool.count,
+		VCD_MAX_SCHEDULER_QUEUE_SIZE(cctxt->frm_rate.fps_numerator,
+		cctxt->frm_rate.fps_denominator));
+	cctxt->reqd_perf_lvl = cctxt->frm_p_units *
+		cctxt->frm_rate.fps_numerator /	cctxt->frm_rate.fps_denominator;
+
+	sched_input_init.frm_rate.numer = cctxt->frm_rate.fps_numerator;
+	sched_input_init.frm_rate.denom = cctxt->frm_rate.fps_denominator;
+	sched_input_init.tkn_per_frm = cctxt->frm_p_units;
+	sched_input_init.alloc_p_tkn_rate = cctxt->reqd_perf_lvl;
+
+	sched_input_init.o_tkn_init = 0;
+
+	sched_input_init.client_data = cctxt;
+
+	rc = vcd_map_sched_status(sched_add_client(cctxt->dev_ctxt->sched_hdl,
+		&sched_input_init, &cctxt->sched_clnt_hdl));
+
+	if (!VCD_FAILED(rc))
+		cctxt->sched_clnt_valid = true;
+
+	return rc;
+}
+
+u32 vcd_handle_input_done(struct vcd_clnt_ctxt *cctxt, void *payload, u32 event,
+	u32 status)
+{
+	struct vcd_transc *transc;
+	struct ddl_frame_data_tag *frame = (struct ddl_frame_data_tag *)payload;
+	u32 rc;
+
+	if (!cctxt->status.frame_submitted && !cctxt->status.frame_delayed) {
+		VCD_MSG_ERROR("Input done was not expected");
+		vcd_assert();
+
+		return VCD_ERR_BAD_STATE;
+	}
+
+	rc = vcd_validate_io_done_pyld(payload, status);
+	VCD_FAILED_RETURN(rc, "Bad input done payload");
+
+	transc = (struct vcd_transc *)frame->vcd_frm.ip_frm_tag;
+
+	if (transc->ip_buf_entry->frame.virt_addr != frame->vcd_frm.virt_addr ||
+			!transc->ip_buf_entry->in_use) {
+		VCD_MSG_ERROR("Bad frm transaction state");
+		vcd_assert();
+	}
+
+	frame->vcd_frm.ip_frm_tag = transc->ip_frm_tag;
+
+	cctxt->callback(event, status, &frame->vcd_frm,
+		sizeof(struct vcd_frame_data), cctxt, cctxt->client_data);
+
+	transc->frame_type = frame->vcd_frm.frame_type;
+
+	transc->ip_buf_entry->in_use = false;
+	VCD_BUFFERPOOL_INUSE_DECREMENT(cctxt->in_buf_pool.in_use);
+	transc->ip_buf_entry = NULL;
+	transc->input_done = true;
+
+	if (transc->input_done && transc->frame_done)
+		transc->in_use = false;
+
+	if (VCD_FAILED(status)) {
+		VCD_MSG_ERROR("INPUT_DONE returned err = 0x%x", status);
+		vcd_handle_input_done_failed(cctxt, transc);
+	}
+
+	if (cctxt->status.frame_submitted > 0)
+		cctxt->status.frame_submitted--;
+	else
+		cctxt->status.frame_delayed--;
+
+	if (!VCD_FAILED(status) && cctxt->decoding) {
+		if (frame->vcd_frm.interlaced)
+			vcd_handle_input_done_for_interlacing(cctxt);
+		if (frame->frm_trans_end)
+			vcd_handle_input_done_with_trans_end(cctxt);
+	}
+
+	return VCD_S_SUCCESS;
+}
+
+void vcd_handle_input_done_in_eos(struct vcd_clnt_ctxt *cctxt, void *payload,
+	u32 status)
+{
+	struct vcd_transc *transc;
+	struct ddl_frame_data_tag *frame = (struct ddl_frame_data_tag *)payload;
+
+	if (VCD_FAILED(vcd_validate_io_done_pyld(payload, status)))
+		return;
+
+	transc = (struct vcd_transc *)frame->vcd_frm.ip_frm_tag;
+
+	vcd_handle_input_done(cctxt, payload, VCD_EVT_RESP_INPUT_DONE, status);
+
+	if ((frame->vcd_frm.flags & VCD_FRAME_FLAG_EOS)) {
+		VCD_MSG_HIGH("Got input done for EOS initiator");
+		transc->input_done = false;
+		transc->in_use = true;
+	}
+}
+
+u32 vcd_validate_io_done_pyld(void *payload, u32 status)
+{
+	struct ddl_frame_data_tag *frame = (struct ddl_frame_data_tag *)payload;
+
+	if (!frame) {
+		VCD_MSG_ERROR("Bad payload from DDL");
+		vcd_assert();
+
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	if (!frame->vcd_frm.ip_frm_tag || frame->vcd_frm.ip_frm_tag ==
+			VCD_FRAMETAG_INVALID) {
+		VCD_MSG_ERROR("bad input frame tag");
+		vcd_assert();
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	if (!frame->vcd_frm.virt_addr && status != VCD_ERR_INTRLCD_FIELD_DROP)
+		return VCD_ERR_BAD_POINTER;
+
+	return VCD_S_SUCCESS;
+}
+
+void vcd_handle_input_done_failed(struct vcd_clnt_ctxt *cctxt,
+		struct vcd_transc *transc)
+{
+	if (cctxt->decoding) {
+		vcd_map_sched_status(sched_update_client_o_tkn(
+			cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl, true,
+			cctxt->sched_o_tkn_per_ip_frm));
+
+		transc->in_use = false;
+	}
+}
+
+void vcd_handle_input_done_for_interlacing(struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc;
+
+	cctxt->status.int_field_cnt++;
+
+	if (cctxt->status.int_field_cnt == 1) {
+		rc = vcd_map_sched_status(sched_update_client_o_tkn(
+			cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl, true,
+			cctxt->sched_o_tkn_per_ip_frm));
+
+		if (VCD_FAILED(rc))
+			VCD_MSG_ERROR("sched_update_client_o_tkn failed");
+	} else if (cctxt->status.int_field_cnt == VCD_DEC_NUM_INTERLACED_FIELDS)
+		cctxt->status.int_field_cnt = 0;
+}
+
+void vcd_handle_input_done_with_trans_end(struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc;
+	union sched_value_type sched_val;
+	if (!cctxt->decoding)
+		return;
+
+	if (cctxt->out_buf_pool.in_use < cctxt->out_buf_pool.buf_req.min_count)
+		return;
+
+	rc = vcd_map_sched_status(sched_get_client_param(
+		cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+		SCHED_I_CLNT_OTKNCURRENT, &sched_val));
+
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("sched_get_client_param:OTKNCURRENT failed");
+		return;
+	}
+
+	if (!sched_val.un_value) {
+		VCD_MSG_MED("All output buffers with core are pending display");
+
+		rc = vcd_map_sched_status(sched_update_client_o_tkn(
+			cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl, true,
+			cctxt->sched_o_tkn_per_ip_frm));
+
+		if (VCD_FAILED(rc))
+			VCD_MSG_ERROR("sched_update_client_o_tkn failed");
+	}
+}
+
+u32 vcd_handle_output_required(struct vcd_clnt_ctxt *cctxt, void *payload,
+	u32 status)
+{
+	struct vcd_transc *transc;
+	struct ddl_frame_data_tag *frame = (struct ddl_frame_data_tag *)payload;
+	u32 rc;
+
+	if (!cctxt->status.frame_submitted && !cctxt->status.frame_delayed) {
+		VCD_MSG_ERROR("\n Input done was not expected");
+		return VCD_ERR_BAD_STATE;
+	}
+
+	rc = vcd_validate_io_done_pyld(payload, status);
+	VCD_FAILED_RETURN(rc, "\n Bad input done payload");
+
+	transc = (struct vcd_transc *)frame->vcd_frm.ip_frm_tag;
+
+	if (transc->ip_buf_entry->frame.virt_addr != frame->vcd_frm.virt_addr ||
+			!transc->ip_buf_entry->in_use) {
+		VCD_MSG_ERROR("\n Bad frm transaction state");
+		return VCD_ERR_BAD_STATE;
+	}
+
+	rc = vcd_map_sched_status(sched_re_queue_frame(
+		cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+		(void *) transc->ip_buf_entry));
+
+	VCD_FAILED_RETURN(rc, "Failed: sched_queue_frame");
+
+	if (transc->ip_buf_entry->frame.flags &	VCD_FRAME_FLAG_EOS) {
+		rc = vcd_map_sched_status(sched_mark_client_eof(
+			cctxt->dev_ctxt->sched_hdl,
+			cctxt->sched_clnt_hdl));
+	}
+
+	VCD_FAILED_RETURN(rc, "Failed: sched_mark_client_eof");
+
+	transc->ip_buf_entry = NULL;
+	transc->in_use = false;
+	frame->frm_trans_end = true;
+
+	if (VCD_FAILED(status))
+		VCD_MSG_ERROR("\n OUTPUT_REQ returned err = 0x%x", status);
+
+	if (cctxt->status.frame_submitted > 0)
+		cctxt->status.frame_submitted--;
+	else
+		cctxt->status.frame_delayed--;
+
+	if (!VCD_FAILED(status) && cctxt->decoding &&
+			frame->vcd_frm.interlaced) {
+		if (cctxt->status.int_field_cnt > 0)
+			VCD_MSG_ERROR("\n Not expected: OUTPUT_REQ"
+				"for 2nd interlace field");
+	}
+
+	return VCD_S_SUCCESS;
+}
+
+u32 vcd_handle_output_required_in_flushing(struct vcd_clnt_ctxt *cctxt,
+	void *payload)
+{
+	u32 rc;
+	struct vcd_transc *transc;
+
+	rc = vcd_validate_io_done_pyld(payload, VCD_S_SUCCESS);
+	VCD_FAILED_RETURN(rc, "Bad input done payload");
+
+	transc = (struct vcd_transc *) (((struct ddl_frame_data_tag *)payload)->
+		 vcd_frm.ip_frm_tag);
+
+	((struct ddl_frame_data_tag *)payload)->vcd_frm.interlaced = false;
+
+	rc = vcd_handle_input_done(cctxt, payload, VCD_EVT_RESP_INPUT_FLUSHED,
+		VCD_S_SUCCESS);
+
+	transc->in_use = false;
+	((struct ddl_frame_data_tag *)payload)->frm_trans_end = true;
+
+	return rc;
+}
+
+u32 vcd_handle_frame_done(struct vcd_clnt_ctxt *cctxt, void *payload, u32 event,
+	u32 status)
+{
+	struct vcd_buffer_entry *op_buf_entry;
+	struct ddl_frame_data_tag *op_frm = (struct ddl_frame_data_tag *)
+		payload;
+	struct vcd_transc *transc;
+	u32 rc;
+
+	rc = vcd_validate_io_done_pyld(payload, status);
+	VCD_FAILED_RETURN(rc, "Bad payload recvd");
+
+	transc = (struct vcd_transc *)op_frm->vcd_frm.ip_frm_tag;
+
+	if (op_frm->vcd_frm.virt_addr) {
+
+		if (!transc->op_buf_entry) {
+			op_buf_entry = vcd_find_buffer_pool_entry(
+				&cctxt->out_buf_pool, op_frm->vcd_frm.virt_addr);
+		} else {
+			op_buf_entry = transc->op_buf_entry;
+		}
+
+		if (!op_buf_entry) {
+			VCD_MSG_ERROR("Invalid output buffer returned"
+				"from DDL");
+			vcd_assert();
+			rc = VCD_ERR_BAD_POINTER;
+		} else if (!op_buf_entry->in_use) {
+			VCD_MSG_ERROR("Bad output buffer %p recv from DDL",
+				op_buf_entry->frame.virt_addr);
+			vcd_assert();
+			rc = VCD_ERR_BAD_POINTER;
+		} else {
+			op_buf_entry->in_use = false;
+			VCD_BUFFERPOOL_INUSE_DECREMENT(
+				cctxt->out_buf_pool.in_use);
+			VCD_MSG_LOW("outBufPool.InUse = %d",
+				cctxt->out_buf_pool.in_use);
+		}
+	}
+	VCD_FAILED_RETURN(rc, "Bad output buffer pointer");
+	op_frm->vcd_frm.time_stamp = transc->time_stamp;
+	op_frm->vcd_frm.ip_frm_tag = transc->ip_frm_tag;
+	op_frm->vcd_frm.frame_type = transc->frame_type;
+
+	transc->frame_done = true;
+
+	if (transc->input_done && transc->frame_done)
+		transc->in_use = false;
+
+	if (status == VCD_ERR_INTRLCD_FIELD_DROP ||
+			(op_frm->intrlcd_ip_frm_tag != VCD_FRAMETAG_INVALID &&
+			op_frm->intrlcd_ip_frm_tag)) {
+		vcd_handle_frame_done_for_interlacing(cctxt, transc, op_frm,
+			status);
+	}
+
+	if (status != VCD_ERR_INTRLCD_FIELD_DROP) {
+		cctxt->callback(event, status, &op_frm->vcd_frm,
+			sizeof(struct vcd_frame_data), cctxt,
+			cctxt->client_data);
+	}
+	return VCD_S_SUCCESS;
+}
+
+void vcd_handle_frame_done_in_eos(struct vcd_clnt_ctxt *cctxt, void *payload,
+	u32 status)
+{
+	struct ddl_frame_data_tag *frame = (struct ddl_frame_data_tag *)payload;
+
+	VCD_MSG_LOW("vcd_handle_frame_done_in_eos:");
+
+	if (VCD_FAILED(vcd_validate_io_done_pyld(payload, status)))
+		return;
+
+	if (cctxt->status.eos_prev_valid) {
+		vcd_handle_frame_done(cctxt,
+			(void *)&cctxt->status.eos_prev_op_frm,
+			VCD_EVT_RESP_OUTPUT_DONE, status);
+	}
+
+	cctxt->status.eos_prev_op_frm = *frame;
+	cctxt->status.eos_prev_valid = true;
+}
+
+void vcd_handle_frame_done_for_interlacing(struct vcd_clnt_ctxt *cctxt,
+	 struct vcd_transc *transc_ip1, struct ddl_frame_data_tag *op_frm,
+	 u32 status)
+{
+	struct vcd_transc *transc_ip2 =	(struct vcd_transc *)
+		op_frm->intrlcd_ip_frm_tag;
+
+	if (status == VCD_ERR_INTRLCD_FIELD_DROP) {
+		cctxt->status.int_field_cnt = 0;
+		return;
+	}
+
+	op_frm->intrlcd_ip_frm_tag = transc_ip2->ip_frm_tag;
+
+	transc_ip2->frame_done = true;
+
+	if (transc_ip2->input_done && transc_ip2->frame_done)
+		transc_ip2->in_use = false;
+
+	if (!transc_ip1->frame_type || !transc_ip2->frame_type) {
+		VCD_MSG_ERROR("DDL didn't provided frame type");
+		return;
+	}
+}
+
+u32 vcd_handle_first_frame_done(struct vcd_clnt_ctxt *cctxt, void *payload)
+{
+	if (!cctxt->decoding)
+		return vcd_handle_first_encode_frame_done(cctxt, payload);
+
+	return VCD_S_SUCCESS;
+}
+
+u32 vcd_handle_first_encode_frame_done(struct vcd_clnt_ctxt *cctxt,
+	void *payload)
+{
+	struct vcd_buffer_entry *buf_entry;
+	struct vcd_frame_data *frm_entry;
+	u32 rc, seqhdr_present;
+	struct vcd_property_hdr prop_hdr;
+	struct vcd_sequence_hdr seq_hdr;
+	struct vcd_property_codec codec;
+	union sched_value_type sched_val;
+	struct vcd_transc *transc;
+	struct ddl_frame_data_tag *payload_frm = (struct ddl_frame_data_tag *)
+		payload;
+	VCD_MSG_LOW("vcd_handle_first_encode_frame_done:");
+
+	rc = vcd_validate_io_done_pyld(payload, VCD_S_SUCCESS);
+	VCD_FAILED_RETURN(rc, "Validate frame done payload failed");
+
+	transc = (struct vcd_transc *)payload_frm->vcd_frm.ip_frm_tag;
+
+	prop_hdr.id = DDL_I_SEQHDR_PRESENT;
+	prop_hdr.sz = sizeof(seqhdr_present);
+	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &seqhdr_present);
+	VCD_FAILED_RETURN(rc, "Failed: DDL_I_SEQHDR_PRESENT");
+	if (!seqhdr_present)
+		return VCD_S_SUCCESS;
+
+	buf_entry = vcd_buffer_pool_entry_de_q(&cctxt->out_buf_pool);
+
+	if (!buf_entry) {
+		VCD_MSG_ERROR("Sched provided frame when 2nd op buffer "
+			"was unavailable");
+
+		rc = VCD_ERR_FAIL;
+		vcd_assert();
+		return rc;
+	}
+
+	frm_entry = &buf_entry->frame;
+	prop_hdr.id = VCD_I_CODEC;
+	prop_hdr.sz = sizeof(struct vcd_property_codec);
+
+	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &codec);
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: ddl_get_property:VCD_I_CODEC",
+			rc);
+		goto out;
+	}
+
+	if (codec.codec != VCD_CODEC_H263) {
+		prop_hdr.id = VCD_I_SEQ_HEADER;
+		prop_hdr.sz = sizeof(struct vcd_sequence_hdr);
+
+		seq_hdr.addr = frm_entry->virt_addr;
+		seq_hdr.sz = buf_entry->size;
+
+		rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &seq_hdr);
+		if (VCD_FAILED(rc)) {
+			VCD_MSG_ERROR("rc = 0x%x. Failed: "
+				 "ddl_get_property:VCD_I_SEQ_HEADER", rc);
+			goto out;
+		}
+	} else {
+		VCD_MSG_LOW("Codec Type is H.263\n");
+	}
+
+	sched_val.un_value = VCD_SCHEDULER_ENC_DFLT_OTKN_PERFRM;
+
+	rc = vcd_map_sched_status(sched_set_client_param(
+		cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+		SCHED_I_CLNT_OTKNPERIPFRM, &sched_val));
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x.Failed: sched_set_client_param", rc);
+		goto out;
+	}
+
+	frm_entry->data_len = seq_hdr.sz;
+	frm_entry->time_stamp = transc->time_stamp;
+	frm_entry->ip_frm_tag =	transc->ip_frm_tag;
+	frm_entry->flags |= VCD_FRAME_FLAG_CODECCONFIG;
+
+	cctxt->callback(VCD_EVT_RESP_OUTPUT_DONE, VCD_S_SUCCESS, frm_entry,
+		sizeof(struct vcd_frame_data), cctxt, cctxt->client_data);
+
+out:
+	if (VCD_FAILED(rc))
+		vcd_buffer_pool_entry_en_q(&cctxt->out_buf_pool, buf_entry);
+
+	return rc;
+}
+
+void vcd_handle_eos_trans_end(struct vcd_clnt_ctxt *cctxt)
+{
+	if (cctxt->status.eos_prev_valid) {
+		vcd_handle_frame_done(cctxt,
+			(void *)&cctxt->status.eos_prev_op_frm,
+			VCD_EVT_RESP_OUTPUT_DONE, VCD_S_SUCCESS);
+
+		cctxt->status.eos_prev_valid = false;
+	}
+
+	if (cctxt->status.flush_mode)
+		vcd_process_pending_flush_in_eos(cctxt);
+
+	if (cctxt->status.stop_pending)
+		vcd_process_pending_stop_in_eos(cctxt);
+	else {
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_RUN,
+			CLIENT_STATE_EVENT_NUMBER(pf_clnt_cb));
+	}
+}
+
+void vcd_handle_eos_done(struct vcd_clnt_ctxt *cctxt, struct vcd_transc *transc,
+	u32 status)
+{
+	struct vcd_frame_data  vcd_frm;
+	VCD_MSG_LOW("vcd_handle_eos_done:");
+
+	if (VCD_FAILED(status))
+		VCD_MSG_ERROR("EOS DONE returned error = 0x%x", status);
+
+	if (cctxt->status.eos_prev_valid) {
+		cctxt->status.eos_prev_op_frm.vcd_frm.flags |=
+			VCD_FRAME_FLAG_EOS;
+
+		vcd_handle_frame_done(cctxt,
+			(void *)&cctxt->status.eos_prev_op_frm,
+			VCD_EVT_RESP_OUTPUT_DONE, VCD_S_SUCCESS);
+
+		cctxt->status.eos_prev_valid = false;
+	} else {
+		if (transc->ip_buf_entry) {
+			transc->ip_buf_entry->frame.ip_frm_tag =
+				transc->ip_frm_tag;
+
+			vcd_send_frame_done_in_eos(cctxt,
+				&transc->ip_buf_entry->frame, false);
+		} else {
+			memset(&vcd_frm, 0, sizeof(struct vcd_frame_data));
+			vcd_frm.ip_frm_tag = transc->ip_frm_tag;
+			vcd_frm.time_stamp = transc->time_stamp;
+			vcd_frm.flags = VCD_FRAME_FLAG_EOS;
+			vcd_send_frame_done_in_eos(cctxt, &vcd_frm, true);
+		}
+	}
+	if (transc->ip_buf_entry) {
+		if (transc->ip_buf_entry->frame.virt_addr) {
+			transc->ip_buf_entry->frame.ip_frm_tag =
+				transc->ip_frm_tag;
+
+			cctxt->callback(VCD_EVT_RESP_INPUT_DONE,
+				  VCD_S_SUCCESS, &transc->ip_buf_entry->frame,
+				  sizeof(struct vcd_frame_data), cctxt,
+				  cctxt->client_data);
+		}
+		transc->ip_buf_entry->in_use = false;
+		VCD_BUFFERPOOL_INUSE_DECREMENT(cctxt->in_buf_pool.in_use);
+		transc->ip_buf_entry = NULL;
+		cctxt->status.frame_submitted--;
+	}
+
+	transc->in_use = false;
+	vcd_mark_frame_channel(cctxt->dev_ctxt);
+	if (cctxt->status.flush_mode)
+		vcd_process_pending_flush_in_eos(cctxt);
+
+	if (cctxt->status.stop_pending) {
+		vcd_process_pending_stop_in_eos(cctxt);
+	} else if (!cctxt->status.eos_wait_for_op_buf) {
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_RUN,
+			CLIENT_STATE_EVENT_NUMBER(pf_clnt_cb));
+	}
+}
+
+void vcd_handle_start_done(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_transc *transc, u32 status)
+{
+	cctxt->status.cmd_submitted--;
+	vcd_mark_command_channel(cctxt->dev_ctxt, transc);
+
+	if (!VCD_FAILED(status)) {
+		cctxt->callback(VCD_EVT_RESP_START, status, NULL, 0, cctxt,
+			cctxt->client_data);
+
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_RUN,
+			CLIENT_STATE_EVENT_NUMBER(pf_clnt_cb));
+	} else {
+		VCD_MSG_ERROR("ddl callback returned failure.status = 0x%x",
+			status);
+		vcd_handle_err_in_starting(cctxt, status);
+	}
+}
+
+void vcd_handle_stop_done(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_transc *transc, u32 status)
+{
+	u32 rc = VCD_S_SUCCESS;
+	u32 seq_hdrpresent = 0;
+	union sched_value_type sched_val;
+	struct vcd_property_hdr  prop_hdr;
+	VCD_MSG_LOW("vcd_handle_stop_done:");
+	cctxt->status.cmd_submitted--;
+	vcd_mark_command_channel(cctxt->dev_ctxt, transc);
+
+	if (VCD_FAILED(status)) {
+		VCD_MSG_FATAL("STOP_DONE returned error = 0x%x", status);
+		status = VCD_ERR_HW_FATAL;
+		vcd_handle_device_err_fatal(cctxt->dev_ctxt, cctxt);
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_INVALID,
+			CLIENT_STATE_EVENT_NUMBER(pf_clnt_cb));
+		goto out;
+	}
+
+	if (!cctxt->decoding) {
+		prop_hdr.id = DDL_I_SEQHDR_PRESENT;
+		prop_hdr.sz = sizeof(seq_hdrpresent);
+		rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr,
+			&seq_hdrpresent);
+		if (VCD_FAILED(rc)) {
+			VCD_MSG_ERROR("Failed: DDL Get DDL_I_SEQHDR_PRESENT %d",
+				rc);
+			goto open_out;
+		}
+		if (seq_hdrpresent == 0x1) {
+			sched_val.un_value = VCD_SCHEDULER_ENC_DFLT_OTKN_PERFRM
+				+ 1;
+
+			rc = vcd_map_sched_status(sched_set_client_param(
+				cctxt->dev_ctxt->sched_hdl,
+				cctxt->sched_clnt_hdl,
+				SCHED_I_CLNT_OTKNPERIPFRM, &sched_val));
+			if (VCD_FAILED(rc))
+				VCD_MSG_ERROR("Failed: sched_set_client_param "
+					"%d", rc);
+		}
+	}
+open_out:
+	vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_OPEN,
+		CLIENT_STATE_EVENT_NUMBER(pf_clnt_cb));
+
+out:
+	cctxt->callback(VCD_EVT_RESP_STOP, status, NULL, 0, cctxt,
+					  cctxt->client_data);
+
+	memset(&cctxt->status, 0, sizeof(struct vcd_clnt_status));
+}
+
+void vcd_handle_stop_done_in_starting(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_transc *transc, u32 status)
+{
+	VCD_MSG_LOW("vcd_handle_stop_done_in_starting:");
+	cctxt->status.cmd_submitted--;
+	vcd_mark_command_channel(cctxt->dev_ctxt, transc);
+	if (!VCD_FAILED(status)) {
+		cctxt->callback(VCD_EVT_RESP_START, cctxt->status.last_err,
+			NULL, 0, cctxt, cctxt->client_data);
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_OPEN,
+			   CLIENT_STATE_EVENT_NUMBER(pf_clnt_cb));
+	} else {
+		VCD_MSG_FATAL("VCD Cleanup: STOP_DONE returned error "
+			"= 0x%x", status);
+		vcd_handle_err_fatal(cctxt, VCD_EVT_RESP_START,
+			VCD_ERR_HW_FATAL);
+	}
+}
+
+void vcd_handle_stop_done_in_invalid(struct vcd_clnt_ctxt *cctxt, u32 status)
+{
+	u32 rc;
+	VCD_MSG_LOW("vcd_handle_stop_done_in_invalid:");
+	if (!VCD_FAILED(status)) {
+		vcd_client_cmd_flush_and_en_q(cctxt, VCD_CMD_CLIENT_CLOSE);
+		if (cctxt->status.frame_submitted) {
+			vcd_release_multiple_frame_channels(cctxt->dev_ctxt,
+			cctxt->status.frame_submitted);
+
+			cctxt->status.frame_submitted = 0;
+			cctxt->status.frame_delayed = 0;
+		}
+		if (cctxt->status.cmd_submitted) {
+			vcd_release_multiple_command_channels(cctxt->dev_ctxt,
+				cctxt->status.cmd_submitted);
+			cctxt->status.cmd_submitted = 0;
+		}
+	} else {
+		VCD_MSG_FATAL("VCD Cleanup: STOP_DONE returned error "
+			"= 0x%x", status);
+		vcd_handle_device_err_fatal(cctxt->dev_ctxt, cctxt);
+		cctxt->status.cleaning_up = false;
+	}
+	vcd_flush_buffers_in_err_fatal(cctxt);
+	VCD_MSG_HIGH("VCD cleanup: All buffers are returned");
+	if (cctxt->status.stop_pending) {
+		cctxt->callback(VCD_EVT_RESP_STOP, VCD_S_SUCCESS, NULL, 0,
+			cctxt, cctxt->client_data);
+		cctxt->status.stop_pending = false;
+	}
+	rc = vcd_power_event(cctxt->dev_ctxt, cctxt, VCD_EVT_PWR_CLNT_ERRFATAL);
+	if (VCD_FAILED(rc))
+		VCD_MSG_ERROR("VCD_EVT_PWR_CLNT_ERRFATAL failed");
+	if (!cctxt->status.cleaning_up &&
+		cctxt->status.close_pending) {
+		vcd_destroy_client_context(cctxt);
+		vcd_handle_for_last_clnt_close(cctxt->dev_ctxt, false);
+	}
+}
+
+u32 vcd_handle_input_frame(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *input_frame)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	struct vcd_buffer_entry *buf_entry;
+	struct vcd_frame_data *frm_entry;
+	u32 rc = VCD_S_SUCCESS;
+	u32 eos_handled = false;
+
+	VCD_MSG_LOW("vcd_handle_input_frame:");
+
+	VCD_MSG_LOW("input buffer: addr=(0x%p), size=(%d), len=(%d)",
+		input_frame->virt_addr, input_frame->alloc_len,
+		input_frame->data_len);
+
+	if ((!input_frame->virt_addr || !input_frame->data_len) &&
+			!(input_frame->flags & VCD_FRAME_FLAG_EOS)) {
+		VCD_MSG_ERROR("Bad frame ptr/len/EOS combination");
+
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+
+	if (!cctxt->status.b1st_frame_recvd) {
+		if (cctxt->decoding)
+			rc = vcd_handle_first_decode_frame(cctxt);
+
+		if (!VCD_FAILED(rc)) {
+			cctxt->status.first_ts = input_frame->time_stamp;
+			cctxt->status.prev_ts = cctxt->status.first_ts;
+
+			cctxt->status.b1st_frame_recvd = true;
+
+			vcd_power_event(cctxt->dev_ctxt, cctxt,
+				VCD_EVT_PWR_CLNT_FIRST_FRAME);
+		}
+	}
+	VCD_FAILED_RETURN(rc, "Failed: Frist frame handling");
+
+	buf_entry = vcd_find_buffer_pool_entry(&cctxt->in_buf_pool,
+		input_frame->virt_addr);
+	if (!buf_entry) {
+		VCD_MSG_ERROR("Bad buffer addr: %p", input_frame->virt_addr);
+		return VCD_ERR_FAIL;
+	}
+
+	if (buf_entry->in_use) {
+		VCD_MSG_ERROR("An inuse input frame is being re-queued to "
+			"scheduler");
+		return VCD_ERR_FAIL;
+	}
+
+	if (input_frame->alloc_len > buf_entry->size) {
+		VCD_MSG_ERROR("Bad buffer Alloc_len %d, Actual size=%d",
+			input_frame->alloc_len, buf_entry->size);
+
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+
+	frm_entry = &buf_entry->frame;
+
+	*frm_entry = *input_frame;
+	frm_entry->phys_addr = buf_entry->phys_addr;
+
+	if (input_frame->flags & VCD_FRAME_FLAG_EOS)
+		rc = vcd_handle_recvd_eos(cctxt, input_frame, &eos_handled);
+
+	if (VCD_FAILED(rc) || eos_handled) {
+		VCD_MSG_HIGH("rc = 0x%x, eos_handled = %d", rc, eos_handled);
+
+		return rc;
+	}
+
+	rc = vcd_map_sched_status(sched_queue_frame(dev_ctxt->sched_hdl,
+		cctxt->sched_clnt_hdl, (void *)buf_entry));
+
+	VCD_FAILED_RETURN(rc, "Failed: sched_queue_frame");
+
+	buf_entry->in_use = true;
+	cctxt->in_buf_pool.in_use++;
+	if (input_frame->flags & VCD_FRAME_FLAG_EOS) {
+		rc = vcd_map_sched_status(sched_mark_client_eof(
+			cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl));
+	}
+
+	VCD_FAILED_RETURN(rc, "Failed: sched_mark_client_eof");
+
+	vcd_try_submit_frame(dev_ctxt);
+	return rc;
+}
+
+void vcd_release_all_clnt_frm_transc(struct vcd_clnt_ctxt *cctxt)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u8 i;
+
+	VCD_MSG_LOW("vcd_release_all_clnt_frm_transc:");
+
+	for (i = 0; i < dev_ctxt->trans_tbl_size; i++) {
+		if (dev_ctxt->trans_tbl[i].in_use &&
+				cctxt == dev_ctxt->trans_tbl[i].cctxt &&
+				dev_ctxt->trans_tbl[i].type ==
+				VCD_CMD_CODE_FRAME) {
+			vcd_release_trans_tbl_entry(&dev_ctxt->trans_tbl[i]);
+		}
+	}
+}
+
+void vcd_release_all_clnt_def_frm_transc(struct vcd_clnt_ctxt *cctxt)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u8 i;
+
+	VCD_MSG_LOW("vcd_release_all_clnt_def_frm_transc:");
+
+	for (i = 0; i < dev_ctxt->trans_tbl_size; i++) {
+		if (dev_ctxt->trans_tbl[i].in_use &&
+				cctxt == dev_ctxt->trans_tbl[i].cctxt &&
+				dev_ctxt->trans_tbl[i].type == VCD_CMD_NONE) {
+			vcd_release_trans_tbl_entry(&dev_ctxt->trans_tbl[i]);
+		}
+	}
+}
+
+void vcd_release_all_clnt_transc(struct vcd_clnt_ctxt *cctxt)
+{
+	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+	u8 i;
+
+	VCD_MSG_LOW("vcd_release_all_clnt_def_frm_transc:");
+
+	for (i = 0; i < dev_ctxt->trans_tbl_size; i++) {
+		if (dev_ctxt->trans_tbl[i].in_use &&
+				cctxt == dev_ctxt->trans_tbl[i].cctxt) {
+			vcd_release_trans_tbl_entry(&dev_ctxt->trans_tbl[i]);
+		}
+	}
+}
+
+void vcd_send_flush_done(struct vcd_clnt_ctxt *cctxt, u32 status)
+{
+	VCD_MSG_LOW("vcd_send_flush_done:");
+
+	if (cctxt->status.flush_mode & VCD_FLUSH_INPUT) {
+		cctxt->callback(VCD_EVT_RESP_FLUSH_INPUT_DONE, status, NULL, 0,
+			cctxt, cctxt->client_data);
+		cctxt->status.flush_mode &= ~VCD_FLUSH_INPUT;
+	}
+
+	if (cctxt->status.flush_mode & VCD_FLUSH_OUTPUT) {
+		cctxt->callback(VCD_EVT_RESP_FLUSH_OUTPUT_DONE,	status, NULL, 0,
+			cctxt, cctxt->client_data);
+		cctxt->status.flush_mode &= ~VCD_FLUSH_OUTPUT;
+	}
+}
+
+u32 vcd_store_seq_hdr(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_sequence_hdr *seq_hdr)
+{
+//	u32 rc;
+//	struct vcd_property_hdr prop_hdr;
+//	u32 align;
+//	u32 addr;
+//	int ret = 0;
+
+	if (!seq_hdr->sz || !seq_hdr->addr) {
+		VCD_MSG_ERROR("Bad seq hdr");
+		return VCD_ERR_BAD_POINTER;
+	}
+
+	if (cctxt->seq_hdr.addr) {
+		VCD_MSG_HIGH("Old seq hdr detected");
+
+		dma_free_coherent(NULL, cctxt->seq_hdr.sz +
+			VCD_SEQ_HDR_PADDING_BYTES, cctxt->seq_hdr.addr,
+			cctxt->seq_hdr_phys_addr);
+		cctxt->seq_hdr.addr = NULL;
+	}
+
+	cctxt->seq_hdr.sz = seq_hdr->sz;
+
+	//TODO strip out all this alignment crap?
+#if 0
+	prop_hdr.id = DDL_I_SEQHDR_ALIGN_BYTES;
+	prop_hdr.size = sizeof(u32);
+
+	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &align);
+
+	VCD_FAILED_RETURN(rc,
+		"Failed: ddl_get_property DDL_I_SEQHDR_ALIGN_BYTES");
+
+	VCD_MSG_MED("Seq hdr alignment bytes = %d", align);
+#endif
+
+	cctxt->seq_hdr.addr = dma_alloc_coherent(NULL,
+		cctxt->seq_hdr.sz + VCD_SEQ_HDR_PADDING_BYTES,
+		&cctxt->seq_hdr_phys_addr, GFP_KERNEL);
+	if (!cctxt->seq_hdr.addr) {
+		VCD_MSG_ERROR("Seq hdr allocation failed");
+		return VCD_ERR_ALLOC_FAIL;
+	}
+
+	memset(cctxt->seq_hdr.addr, 0,
+		cctxt->seq_hdr.sz + VCD_SEQ_HDR_PADDING_BYTES);
+	memcpy(cctxt->seq_hdr.addr, seq_hdr->addr, seq_hdr->sz);
+
+	return VCD_S_SUCCESS;
+}
+
+u32 vcd_set_frame_rate(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_property_frame_rate *fps)
+{
+	union sched_value_type sched_val;
+	u32 rc;
+
+	sched_val.frm_rate.numer = fps->fps_numerator;
+	sched_val.frm_rate.denom = fps->fps_denominator;
+	cctxt->frm_rate = *fps;
+
+	rc = vcd_map_sched_status(sched_set_client_param(
+		cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+		SCHED_I_CLNT_FRAMERATE, &sched_val));
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: Set SCHED_I_CLNT_FRAMERATE",
+			rc);
+	}
+
+	rc = vcd_update_clnt_perf_lvl(cctxt, &cctxt->frm_rate,
+		cctxt->frm_p_units);
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: vcd_update_clnt_perf_lvl",
+				  rc);
+	}
+
+	sched_val.un_value = cctxt->reqd_perf_lvl;
+
+	rc = vcd_map_sched_status(sched_set_client_param(
+		cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+		SCHED_I_CLNT_PTKNRATE, &sched_val));
+
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: Set SCHED_I_CLNT_PTKNRATE",
+				  rc);
+	}
+
+	return VCD_S_SUCCESS;
+}
+
+u32 vcd_set_frame_size(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_property_frame_size *frm_size)
+{
+	struct vcd_property_hdr prop_hdr;
+	union sched_value_type sched_val;
+	u32 rc;
+	u32 frm_p_units;
+	frm_size = NULL;
+
+	prop_hdr.id = DDL_I_FRAME_PROC_UNITS;
+	prop_hdr.sz = sizeof(frm_p_units);
+	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &frm_p_units);
+
+	VCD_FAILED_RETURN(rc, "Failed: Get DDL_I_FRAME_PROC_UNITS");
+
+	cctxt->frm_p_units = sched_val.un_value = frm_p_units;
+
+	rc = vcd_map_sched_status(sched_set_client_param(
+		cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+		SCHED_I_CLNT_PTKNPERFRM, &sched_val));
+
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: Set SCHED_I_CLNT_PTKNPERFRM",
+				  rc);
+	}
+
+	rc = vcd_update_clnt_perf_lvl(cctxt, &cctxt->frm_rate, frm_p_units);
+
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: vcd_update_clnt_perf_lvl",
+				  rc);
+	}
+
+	sched_val.un_value = cctxt->reqd_perf_lvl;
+
+	rc = vcd_map_sched_status(sched_set_client_param(
+		cctxt->dev_ctxt->sched_hdl, cctxt->sched_clnt_hdl,
+		SCHED_I_CLNT_PTKNRATE, &sched_val));
+
+	if (VCD_FAILED(rc)) {
+		VCD_MSG_ERROR("rc = 0x%x. Failed: Set SCHED_I_CLNT_PTKNRATE",
+				  rc);
+	}
+
+	return VCD_S_SUCCESS;
+}
+
+void vcd_process_pending_flush_in_eos(struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	VCD_MSG_HIGH("Buffer flush is pending");
+
+	rc = vcd_flush_buffers(cctxt, cctxt->status.flush_mode);
+
+	if (VCD_FAILED(rc))
+		VCD_MSG_ERROR("rc = 0x%x. Failed: vcd_flush_buffers", rc);
+
+	cctxt->status.eos_wait_for_op_buf = false;
+
+	vcd_send_flush_done(cctxt, VCD_S_SUCCESS);
+}
+
+void vcd_process_pending_stop_in_eos(struct vcd_clnt_ctxt *cctxt)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	rc = vcd_flush_buffers(cctxt, VCD_FLUSH_ALL);
+
+	if (VCD_FAILED(rc))
+		VCD_MSG_ERROR("rc = 0x%x. Failed: vcd_flush_buffers", rc);
+
+	VCD_MSG_HIGH("All buffers are returned. Enqueuing stop cmd");
+
+	vcd_client_cmd_flush_and_en_q(cctxt, VCD_CMD_CODEC_STOP);
+	cctxt->status.stop_pending = false;
+
+	vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_STOPPING,
+		CLIENT_STATE_EVENT_NUMBER(pf_stop));
+}
+
+u32 vcd_calculate_frame_delta(struct vcd_clnt_ctxt *cctxt,
+	struct vcd_frame_data *frame)
+{
+	u32 frm_delta;
+	u64 temp, temp1;
+
+	temp = frame->time_stamp - cctxt->status.prev_ts;
+
+	VCD_MSG_LOW("Curr_ts=%lld  Prev_ts=%lld Diff=%llu", frame->time_stamp,
+		cctxt->status.prev_ts, temp);
+
+	temp = temp * cctxt->time_resoln;
+	temp = (temp + (VCD_TIMESTAMP_RESOLUTION >> 1));
+	temp1 = do_div(temp, VCD_TIMESTAMP_RESOLUTION);
+	frm_delta = temp;
+	VCD_MSG_LOW("temp1=%lld  temp=%lld", temp1, temp);
+	cctxt->status.time_elapsed += frm_delta;
+
+	temp = ((u64)cctxt->status.time_elapsed * VCD_TIMESTAMP_RESOLUTION);
+	temp = (temp + (cctxt->time_resoln >> 1));
+	temp1 = do_div(temp, cctxt->time_resoln);
+
+	cctxt->status.prev_ts = cctxt->status.first_ts + temp;
+
+	VCD_MSG_LOW("Time_elapsed=%u, Drift=%llu, new Prev_ts=%lld",
+		cctxt->status.time_elapsed, temp1, cctxt->status.prev_ts);
+
+	return frm_delta;
+}
+
+struct vcd_buffer_entry *vcd_check_fill_output_buffer(struct vcd_clnt_ctxt
+	*cctxt, struct vcd_frame_data *buffer)
+{
+	struct vcd_buffer_pool *buf_pool = &cctxt->out_buf_pool;
+	struct vcd_buffer_entry *buf_entry;
+
+	if (!buf_pool->entries) {
+		VCD_MSG_ERROR("Buffers not set or allocated yet");
+		return NULL;
+	}
+
+	if (!buffer->virt_addr) {
+		VCD_MSG_ERROR("NULL buffer address provided");
+		return NULL;
+	}
+
+	buf_entry = vcd_find_buffer_pool_entry(buf_pool, buffer->virt_addr);
+	if (!buf_entry) {
+		VCD_MSG_ERROR("Unrecognized buffer address provided %p",
+			buffer->virt_addr);
+		return NULL;
+	}
+
+	if (buf_entry->in_use) {
+		VCD_MSG_ERROR("An inuse output frame is being provided for "
+			"reuse");
+		return NULL;
+	}
+
+	if (buffer->alloc_len < buf_pool->buf_req.size ||
+			buffer->alloc_len > buf_entry->size) {
+		VCD_MSG_ERROR("Bad buffer Alloc_len = %d, Actual size = %d, "
+			" Min size = %u", buffer->alloc_len, buf_entry->size,
+			 buf_pool->buf_req.size);
+		return NULL;
+	}
+
+	return buf_entry;
+}
+
+void vcd_handle_ind_hw_err_fatal(struct vcd_clnt_ctxt *cctxt, u32 event,
+	u32 status)
+{
+	if (cctxt->status.frame_submitted) {
+		cctxt->status.frame_submitted--;
+		vcd_mark_frame_channel(cctxt->dev_ctxt);
+	}
+	vcd_handle_err_fatal(cctxt, event, status);
+}
+
+void vcd_handle_err_fatal(struct vcd_clnt_ctxt *cctxt, u32 event, u32 status)
+{
+	u32 rc;
+	VCD_MSG_LOW("vcd_handle_err_fatal: event=%x, err=%x", event, status);
+	if (!VCD_FAILED_FATAL(status))
+		return;
+
+	if (VCD_FAILED_DEVICE_FATAL(status)) {
+		vcd_clnt_handle_device_err_fatal(cctxt, event);
+		vcd_handle_device_err_fatal(cctxt->dev_ctxt, cctxt);
+	} else if (VCD_FAILED_CLIENT_FATAL(status)) {
+		cctxt->status.last_evt = event;
+
+		if (cctxt->sched_clnt_valid) {
+			rc = vcd_map_sched_status(sched_suspend_resume_client(
+				cctxt->dev_ctxt->sched_hdl,
+				cctxt->sched_clnt_hdl, false));
+			if (VCD_FAILED(rc)) {
+				VCD_MSG_ERROR("Failed: sched_suspend_resume_"
+					"client rc=0x%x", rc);
+			}
+		}
+		cctxt->callback(event, VCD_ERR_HW_FATAL, NULL, 0, cctxt,
+						   cctxt->client_data);
+		cctxt->status.cleaning_up = true;
+		vcd_client_cmd_flush_and_en_q(cctxt, VCD_CMD_CODEC_STOP);
+		vcd_do_client_state_transition(cctxt, VCD_CLIENT_STATE_INVALID,
+			CLIENT_STATE_EVENT_NUMBER(pf_clnt_cb));
+	}
+}
+
+void vcd_handle_err_in_starting(struct vcd_clnt_ctxt *cctxt, u32 status)
+{
+	VCD_MSG_LOW("\n vcd_handle_err_in_starting:");
+	if (VCD_FAILED_FATAL(status)) {
+		vcd_handle_err_fatal(cctxt, VCD_EVT_RESP_START, status);
+	} else {
+		cctxt->status.last_err = status;
+		VCD_MSG_HIGH("\n VCD cleanup: Enqueuing stop cmd");
+		vcd_client_cmd_flush_and_en_q(cctxt, VCD_CMD_CODEC_STOP);
+	}
+}
+
+void vcd_handle_trans_pending(struct vcd_clnt_ctxt *cctxt)
+{
+	if (!cctxt->status.frame_submitted) {
+		VCD_MSG_ERROR("Transaction pending response was not expected");
+		vcd_assert();
+		return;
+	}
+	cctxt->status.frame_submitted--;
+	cctxt->status.frame_delayed++;
+	vcd_mark_frame_channel(cctxt->dev_ctxt);
+}
+
+u32 vcd_requeue_input_frame(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_clnt_ctxt *cctxt, struct vcd_buffer_entry *buf_entry)
+{
+	u32 rc;
+	rc = vcd_map_sched_status(sched_re_queue_frame(dev_ctxt->sched_hdl,
+		cctxt->sched_clnt_hdl, (void *) buf_entry));
+
+	VCD_FAILED_RETURN(rc, "Failed: Sched_ReQueueFrame");
+
+	if (buf_entry->frame.flags & VCD_FRAME_FLAG_EOS) {
+		rc = vcd_map_sched_status(sched_mark_client_eof(dev_ctxt->
+			sched_hdl, cctxt->sched_clnt_hdl));
+	}
+
+	if (VCD_FAILED(rc))
+		VCD_MSG_ERROR("rc = 0x%x: Failed: Sched_MarkClientEOF", rc);
+
+	return rc;
+}
+
+void vcd_handle_submit_frame_failed(struct vcd_dev_ctxt *dev_ctxt,
+	struct vcd_transc *transc)
+{
+	struct vcd_clnt_ctxt *cctxt = transc->cctxt;
+	u32 rc;
+
+	vcd_mark_frame_channel(dev_ctxt);
+	transc->in_use = false;
+
+	vcd_handle_err_fatal(cctxt, VCD_EVT_IND_HWERRFATAL,
+		VCD_ERR_CLIENT_FATAL);
+
+	if (vcd_get_command_channel(dev_ctxt, &transc)) {
+		transc->type = VCD_CMD_CODEC_STOP;
+		transc->cctxt = cctxt;
+		rc = vcd_submit_cmd_sess_end(transc);
+		if (VCD_FAILED(rc)) {
+			vcd_release_command_channel(dev_ctxt, transc);
+			VCD_MSG_ERROR("rc = 0x%x. Failed: VCD_SubmitCmdSessEnd",
+				rc);
+		}
+	}
+}
diff --git a/drivers/misc/video_core/720p/vcd/vcd_util.h b/drivers/misc/video_core/720p/vcd/vcd_util.h
new file mode 100644
index 0000000..2d90bf5
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/vcd_util.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _VCD_UTIL_H_
+#define _VCD_UTIL_H_
+
+#include "vcd_api.h"
+
+#if DEBUG
+
+//TODO what a load of crap in here
+#define VCD_MSG_LOW(xx_fmt...) printk(KERN_INFO "\t* " xx_fmt)
+#define VCD_MSG_MED(xx_fmt...) printk(KERN_INFO "  * " xx_fmt)
+#define VCD_MSG_HIGH(xx_fmt...) printk(KERN_WARNING xx_fmt)
+
+#else
+
+#define VCD_MSG_LOW(xx_fmt...)
+#define VCD_MSG_MED(xx_fmt...)
+#define VCD_MSG_HIGH(xx_fmt...)
+
+#endif
+
+#define VCD_MSG_ERROR(xx_fmt...) printk(KERN_ERR "err: " xx_fmt)
+#define VCD_MSG_FATAL(xx_fmt...) printk(KERN_ERR "<FATAL> " xx_fmt)
+
+#define VCD_FAILED_RETURN(rc, xx_fmt...)		\
+	do {						\
+		if (VCD_FAILED(rc)) {			\
+			printk(KERN_ERR  xx_fmt);	\
+			return rc;			\
+		}					\
+	} while	(0)
+
+#define VCD_FAILED_DEVICE_FATAL(rc) \
+	(rc == VCD_ERR_HW_FATAL ? true : false)
+#define VCD_FAILED_CLIENT_FATAL(rc) \
+	(rc == VCD_ERR_CLIENT_FATAL ? true : false)
+
+#define VCD_FAILED_FATAL(rc)  \
+	((VCD_FAILED_DEVICE_FATAL(rc) || VCD_FAILED_CLIENT_FATAL(rc)) \
+	? true : false)
+
+#define vcd_assert() VCD_MSG_FATAL("ASSERT")
+
+#endif
diff --git a/drivers/misc/video_core/720p/vcd/video_core_type.h b/drivers/misc/video_core/720p/vcd/video_core_type.h
new file mode 100644
index 0000000..febd4cf
--- /dev/null
+++ b/drivers/misc/video_core/720p/vcd/video_core_type.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef VIDEO_CORE_TYPE_H
+#define VIDEO_CORE_TYPE_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/time.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+
+#define DEBUG 1
+
+#define USE_RES_TRACKER
+
+#undef CORE_TIMING_INFO
+
+#endif
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index 549a341..d3d0e2e 100755
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -692,11 +692,13 @@
 
 	BUG_ON(!func);
 
+#if 0
 	if ((addr < 0xF0 || addr > 0xFF) && (!mmc_card_lenient_fn0(func->card))) {
 		if (err_ret)
 			*err_ret = -EINVAL;
 		return;
 	}
+#endif
 
 	ret = mmc_io_rw_direct(func->card, 1, 0, addr, b, NULL);
 	if (err_ret)
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index f06d06e..e171e77 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -249,7 +249,7 @@
 
 config MMC_MSM7X00A
 	tristate "Qualcomm MSM 7X00A SDCC Controller Support"
-	depends on MMC && ARCH_MSM && !ARCH_MSM7X30
+	depends on MMC && ARCH_MSM
 	help
 	  This provides support for the SD/MMC cell found in the
           MSM 7X00A controllers from Qualcomm.
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 24e0945..8a149ab 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -52,7 +52,7 @@
 #define BUSCLK_PWRSAVE 1
 #define BUSCLK_TIMEOUT (HZ)
 static unsigned int msmsdcc_fmin = 144000;
-static unsigned int msmsdcc_fmax = 50000000;
+static unsigned int msmsdcc_fmax = 49152000;
 static unsigned int msmsdcc_4bit = 1;
 static unsigned int msmsdcc_pwrsave = 1;
 static unsigned int msmsdcc_piopoll = 1;
@@ -389,6 +389,7 @@
 	host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
 			       DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
 	host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
+	host->dma.hdr.execute_func = NULL;
 
 	n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
 			host->dma.num_ents, host->dma.dir);
@@ -988,7 +989,7 @@
 	if (status ^ host->oldstat) {
 		pr_info("%s: Slot status change detected (%d -> %d)\n",
 			mmc_hostname(host->mmc), host->oldstat, status);
-		if (status)
+		if (status && !host->plat->built_in)
 			mmc_detect_change(host->mmc, (5 * HZ) / 2);
 		else
 			mmc_detect_change(host->mmc, 0);
@@ -1214,6 +1215,10 @@
 	msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0);
 	host->saved_irq0mask = MCI_IRQENABLE;
 
+	mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY;
+	if (plat->built_in)
+		mmc->pm_flags = MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY;
+
 	/*
 	 * Setup card detect change
 	 */
@@ -1326,6 +1331,9 @@
 		if (host->stat_irq)
 			disable_irq(host->stat_irq);
 
+		if (host->plat->built_in)
+			mmc->pm_flags |= MMC_PM_KEEP_POWER;
+
 		if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
 			rc = mmc_suspend_host(mmc);
 		if (!rc)
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 35081ce..03fe3e3d 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -49,6 +49,14 @@
 	  say M here and read <file:Documentation/kbuild/modules.txt>.
 	  The module will be called ms02-nv.
 
+config MTD_MSM_NAND
+	tristate "MSM NAND Device Support"
+	depends on MTD && ARCH_MSM
+	select MTD_NAND_IDS
+	default y
+	help
+	  Support for some NAND chips connected to the MSM NAND controller.
+
 config MTD_DATAFLASH
 	tristate "Support for AT45xxx DataFlash"
 	depends on SPI_MASTER && EXPERIMENTAL
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index f3226b1..fe959e8 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -11,6 +11,7 @@
 obj-$(CONFIG_MTD_PHRAM)		+= phram.o
 obj-$(CONFIG_MTD_PMC551)	+= pmc551.o
 obj-$(CONFIG_MTD_MS02NV)	+= ms02-nv.o
+obj-$(CONFIG_MTD_MSM_NAND)	+= msm_nand.o
 obj-$(CONFIG_MTD_MTDRAM)	+= mtdram.o
 obj-$(CONFIG_MTD_LART)		+= lart.o
 obj-$(CONFIG_MTD_BLOCK2MTD)	+= block2mtd.o
diff --git a/drivers/mtd/devices/msm_nand.c b/drivers/mtd/devices/msm_nand.c
new file mode 100644
index 0000000..a379a35
--- /dev/null
+++ b/drivers/mtd/devices/msm_nand.c
@@ -0,0 +1,1703 @@
+/* drivers/mtd/devices/msm_nand.c
+ *
+ * Copyright (C) 2007 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/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/moduleparam.h>
+#include <linux/stat.h>
+
+#include <asm/dma.h>
+#include <asm/mach/flash.h>
+
+#include <mach/dma.h>
+
+#include "msm_nand.h"
+
+#define MSM_NAND_DMA_BUFFER_SIZE SZ_4K
+#define MSM_NAND_DMA_BUFFER_SLOTS \
+	(MSM_NAND_DMA_BUFFER_SIZE / (sizeof(((atomic_t *)0)->counter) * 8))
+
+#define SUPPORT_WRONG_ECC_CONFIG 1
+
+#define MSM_NAND_CFG0_RAW 0xA80420C0
+#define MSM_NAND_CFG1_RAW 0x5045D
+
+#define VERBOSE 0
+
+struct msm_nand_chip {
+	struct device *dev;
+	wait_queue_head_t wait_queue;
+	atomic_t dma_buffer_busy;
+	unsigned dma_channel;
+	uint8_t *dma_buffer;
+	dma_addr_t dma_addr;
+	unsigned CFG0, CFG1;
+	unsigned page_shift;
+	unsigned last_sector;
+	unsigned last_sectorsz;
+#if SUPPORT_WRONG_ECC_CONFIG
+	uint32_t ecc_buf_cfg;
+	uint32_t saved_ecc_buf_cfg;
+#endif
+};
+
+#define CFG1_WIDE_FLASH (1U << 1)
+
+#ifdef CONFIG_ARCH_MSM7X30
+#define BUF_STAT_UNCORRECTABLE (1U << 8)
+#define BUF_STAT_NUM_ERRS_MASK (0xf)
+#else
+#define BUF_STAT_UNCORRECTABLE (1U << 3)
+#define BUF_STAT_NUM_ERRS_MASK (0x7)
+#endif
+
+
+/* TODO: move datamover code out */
+
+#define SRC_CRCI_NAND_CMD  CMD_SRC_CRCI(DMOV_NAND_CRCI_CMD)
+#define DST_CRCI_NAND_CMD  CMD_DST_CRCI(DMOV_NAND_CRCI_CMD)
+#define SRC_CRCI_NAND_DATA CMD_SRC_CRCI(DMOV_NAND_CRCI_DATA)
+#define DST_CRCI_NAND_DATA CMD_DST_CRCI(DMOV_NAND_CRCI_DATA)
+
+#define msm_virt_to_dma(chip, vaddr) \
+	((void)(*(vaddr)), (chip)->dma_addr + \
+	 ((uint8_t *)(vaddr) - (chip)->dma_buffer))
+
+/**
+ * msm_nand_oob_64 - oob info for large (2KB) page
+ */
+static struct nand_ecclayout msm_nand_oob_64 = {
+	.oobavail	= 16,
+	.oobfree	= {
+		{30, 16},
+	}
+};
+
+/*
+ * msm_nand_oob_128 - oob info for 4KB page
+ */
+static struct nand_ecclayout msm_nand_oob_128 = {
+	.oobavail       = 32,
+	.oobfree        = {
+		{70, 32},
+	}
+};
+
+
+static void *msm_nand_get_dma_buffer(struct msm_nand_chip *chip, size_t size)
+{
+	unsigned int bitmask, free_bitmask, old_bitmask;
+	unsigned int need_mask, current_need_mask;
+	int free_index;
+
+	need_mask = (1UL << DIV_ROUND_UP(size, MSM_NAND_DMA_BUFFER_SLOTS)) - 1;
+	bitmask = atomic_read(&chip->dma_buffer_busy);
+	free_bitmask = ~bitmask;
+	do {
+		free_index = __ffs(free_bitmask);
+		current_need_mask = need_mask << free_index;
+		if ((bitmask & current_need_mask) == 0) {
+			old_bitmask =
+				atomic_cmpxchg(&chip->dma_buffer_busy,
+					       bitmask,
+					       bitmask | current_need_mask);
+			if (old_bitmask == bitmask)
+				return chip->dma_buffer +
+					free_index * MSM_NAND_DMA_BUFFER_SLOTS;
+			free_bitmask = 0; /* force return */
+		}
+		/* current free range was too small, clear all free bits */
+		/* below the top busy bit within current_need_mask */
+		free_bitmask &=
+			~(~0U >> (32 - fls(bitmask & current_need_mask)));
+	} while (free_bitmask);
+
+	return NULL;
+}
+
+static void msm_nand_release_dma_buffer(struct msm_nand_chip *chip,
+					void *buffer, size_t size)
+{
+	int index;
+	unsigned int used_mask;
+
+	used_mask = (1UL << DIV_ROUND_UP(size, MSM_NAND_DMA_BUFFER_SLOTS)) - 1;
+	index = ((uint8_t *)buffer - chip->dma_buffer) /
+		MSM_NAND_DMA_BUFFER_SLOTS;
+	atomic_sub(used_mask << index, &chip->dma_buffer_busy);
+
+	wake_up(&chip->wait_queue);
+}
+
+uint32_t flash_read_id(struct msm_nand_chip *chip)
+{
+	struct {
+		dmov_s cmd[5];
+		unsigned cmdptr;
+		unsigned data[5];
+	} *dma_buffer;
+	uint32_t rv;
+
+	wait_event(chip->wait_queue,
+		   (dma_buffer = msm_nand_get_dma_buffer(
+			    chip, sizeof(*dma_buffer))));
+
+	dma_buffer->data[0] = 0 | 4;
+	dma_buffer->data[1] = MSM_NAND_CMD_FETCH_ID;
+	dma_buffer->data[2] = 1;
+	dma_buffer->data[3] = 0xeeeeeeee;
+	dma_buffer->data[4] = 0xeeeeeeee;
+	BUILD_BUG_ON(4 != ARRAY_SIZE(dma_buffer->data) - 1);
+
+	dma_buffer->cmd[0].cmd = 0 | CMD_OCB;
+	dma_buffer->cmd[0].src = msm_virt_to_dma(chip, &dma_buffer->data[0]);
+	dma_buffer->cmd[0].dst = MSM_NAND_FLASH_CHIP_SELECT;
+	dma_buffer->cmd[0].len = 4;
+
+	dma_buffer->cmd[1].cmd = DST_CRCI_NAND_CMD;
+	dma_buffer->cmd[1].src = msm_virt_to_dma(chip, &dma_buffer->data[1]);
+	dma_buffer->cmd[1].dst = MSM_NAND_FLASH_CMD;
+	dma_buffer->cmd[1].len = 4;
+
+	dma_buffer->cmd[2].cmd = 0;
+	dma_buffer->cmd[2].src = msm_virt_to_dma(chip, &dma_buffer->data[2]);
+	dma_buffer->cmd[2].dst = MSM_NAND_EXEC_CMD;
+	dma_buffer->cmd[2].len = 4;
+
+	dma_buffer->cmd[3].cmd = SRC_CRCI_NAND_DATA;
+	dma_buffer->cmd[3].src = MSM_NAND_FLASH_STATUS;
+	dma_buffer->cmd[3].dst = msm_virt_to_dma(chip, &dma_buffer->data[3]);
+	dma_buffer->cmd[3].len = 4;
+
+	dma_buffer->cmd[4].cmd = CMD_OCU | CMD_LC;
+	dma_buffer->cmd[4].src = MSM_NAND_READ_ID;
+	dma_buffer->cmd[4].dst = msm_virt_to_dma(chip, &dma_buffer->data[4]);
+	dma_buffer->cmd[4].len = 4;
+	BUILD_BUG_ON(4 != ARRAY_SIZE(dma_buffer->cmd) - 1);
+
+	dma_buffer->cmdptr =
+		(msm_virt_to_dma(chip, dma_buffer->cmd) >> 3) | CMD_PTR_LP;
+
+	msm_dmov_exec_cmd(
+		chip->dma_channel, DMOV_CMD_PTR_LIST |
+		DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
+
+	rv = dma_buffer->data[4];
+	pr_info("msn_nand: nandid %x status %x\n", rv, dma_buffer->data[3]);
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+	return rv;
+}
+
+int flash_read_config(struct msm_nand_chip *chip)
+{
+	struct {
+		dmov_s cmd[2];
+		unsigned cmdptr;
+		unsigned cfg0;
+		unsigned cfg1;
+	} *dma_buffer;
+
+	wait_event(chip->wait_queue,
+		   (dma_buffer = msm_nand_get_dma_buffer(
+			    chip, sizeof(*dma_buffer))));
+	dma_buffer->cfg0 = 0;
+	dma_buffer->cfg1 = 0;
+
+	dma_buffer->cmd[0].cmd = CMD_OCB;
+	dma_buffer->cmd[0].src = MSM_NAND_DEV0_CFG0;
+	dma_buffer->cmd[0].dst = msm_virt_to_dma(chip, &dma_buffer->cfg0);
+	dma_buffer->cmd[0].len = 4;
+
+	dma_buffer->cmd[1].cmd = CMD_OCU | CMD_LC;
+	dma_buffer->cmd[1].src = MSM_NAND_DEV0_CFG1;
+	dma_buffer->cmd[1].dst = msm_virt_to_dma(chip, &dma_buffer->cfg1);
+	dma_buffer->cmd[1].len = 4;
+	BUILD_BUG_ON(1 != ARRAY_SIZE(dma_buffer->cmd) - 1);
+
+	dma_buffer->cmdptr =
+		(msm_virt_to_dma(chip, dma_buffer->cmd) >> 3) | CMD_PTR_LP;
+
+	msm_dmov_exec_cmd(
+		chip->dma_channel, DMOV_CMD_PTR_LIST |
+		DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
+
+	chip->CFG0 = dma_buffer->cfg0;
+	chip->CFG1 = dma_buffer->cfg1;
+	pr_info("msm_nand: read CFG0 = %x CFG1 = %x\n", chip->CFG0, chip->CFG1);
+	pr_info("msm_nand: CFG0 cw/page=%d ud_sz=%d ecc_sz=%d spare_sz=%d\n",
+		(chip->CFG0 >> 6) & 7, (chip->CFG0 >> 9) & 0x3ff,
+		(chip->CFG0 >> 19) & 15, (chip->CFG0 >> 23) & 15);
+
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+
+	if ((chip->CFG0 == 0) || (chip->CFG1 == 0))
+		return -1;
+
+	return 0;
+}
+
+unsigned flash_rd_reg(struct msm_nand_chip *chip, unsigned addr)
+{
+	struct {
+		dmov_s cmd;
+		unsigned cmdptr;
+		unsigned data;
+	} *dma_buffer;
+	unsigned rv;
+
+	wait_event(chip->wait_queue,
+		   (dma_buffer = msm_nand_get_dma_buffer(
+			    chip, sizeof(*dma_buffer))));
+
+	dma_buffer->cmd.cmd = CMD_LC;
+	dma_buffer->cmd.src = addr;
+	dma_buffer->cmd.dst = msm_virt_to_dma(chip, &dma_buffer->data);
+	dma_buffer->cmd.len = 4;
+
+	dma_buffer->cmdptr =
+		(msm_virt_to_dma(chip, &dma_buffer->cmd) >> 3) | CMD_PTR_LP;
+	dma_buffer->data = 0xeeeeeeee;
+
+	msm_dmov_exec_cmd(
+		chip->dma_channel, DMOV_CMD_PTR_LIST |
+		DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
+	rv = dma_buffer->data;
+
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+
+	return rv;
+}
+
+void flash_wr_reg(struct msm_nand_chip *chip, unsigned addr, unsigned val)
+{
+	struct {
+		dmov_s cmd;
+		unsigned cmdptr;
+		unsigned data;
+	} *dma_buffer;
+
+	wait_event(chip->wait_queue,
+		   (dma_buffer = msm_nand_get_dma_buffer(
+			    chip, sizeof(*dma_buffer))));
+
+	dma_buffer->cmd.cmd = CMD_LC;
+	dma_buffer->cmd.src = msm_virt_to_dma(chip, &dma_buffer->data);
+	dma_buffer->cmd.dst = addr;
+	dma_buffer->cmd.len = 4;
+
+	dma_buffer->cmdptr =
+		(msm_virt_to_dma(chip, &dma_buffer->cmd) >> 3) | CMD_PTR_LP;
+	dma_buffer->data = val;
+
+	msm_dmov_exec_cmd(
+		chip->dma_channel, DMOV_CMD_PTR_LIST |
+		DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
+
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+}
+
+static dma_addr_t
+msm_nand_dma_map(struct device *dev, void *addr, size_t size,
+		 enum dma_data_direction dir)
+{
+	struct page *page;
+	unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+	if (virt_addr_valid(addr))
+		page = virt_to_page(addr);
+	else {
+		if (WARN_ON(size + offset > PAGE_SIZE))
+			return ~0;
+		page = vmalloc_to_page(addr);
+	}
+	return dma_map_page(dev, page, offset, size, dir);
+}
+
+static int msm_nand_check_empty(struct mtd_info *mtd, struct mtd_oob_ops *ops,
+				unsigned long *uncorrected)
+{
+	unsigned int p, n, end;
+	uint8_t *datbuf = ops->datbuf;
+	uint8_t *oobbuf = ops->oobbuf;
+	size_t oobsize;
+	int page_count;
+
+	if (ops->mode == MTD_OOB_RAW)
+		return false;
+
+	page_count = ops->retlen / mtd->writesize;
+	oobsize = (ops->mode == MTD_OOB_AUTO) ? mtd->oobavail : mtd->oobsize;
+
+	for_each_set_bit(p, uncorrected, page_count) {
+		if (datbuf) {
+			datbuf = ops->datbuf + p * mtd->writesize;
+			for (n = 0; n < mtd->writesize; n++) {
+				/* empty blocks read 0x54 at these offsets */
+				if (datbuf[n] != ((n % 516 == 3) ? 0x54 : 0xff))
+					return false;
+			}
+		}
+		if (oobbuf) {
+			n = p * oobsize;
+			end = min(n + oobsize, ops->oobretlen);
+			for(; n < end; n++)
+				if (oobbuf[n] != 0xff)
+					return false;
+		}
+		if (ops->datbuf)
+			for (n = 3; n < mtd->writesize; n+= 516)
+				datbuf[n] = 0xff;
+	}
+	return true;
+}
+
+static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from,
+			     struct mtd_oob_ops *ops)
+{
+	struct msm_nand_chip *chip = mtd->priv;
+
+	struct {
+		dmov_s cmd[8 * 5 + 3];
+		unsigned cmdptr;
+		struct {
+			uint32_t cmd;
+			uint32_t addr0;
+			uint32_t addr1;
+			uint32_t chipsel;
+			uint32_t cfg0;
+			uint32_t cfg1;
+			uint32_t exec;
+#if SUPPORT_WRONG_ECC_CONFIG
+			uint32_t ecccfg;
+			uint32_t ecccfg_restore;
+#endif
+			struct {
+				uint32_t flash_status;
+				uint32_t buffer_status;
+			} result[8];
+		} data;
+	} *dma_buffer;
+	dmov_s *cmd;
+	unsigned n;
+	unsigned page = from >> chip->page_shift;
+	uint32_t oob_len = ops->ooblen;
+	uint32_t sectordatasize;
+	uint32_t sectoroobsize;
+	int err, pageerr;
+	dma_addr_t data_dma_addr = 0;
+	dma_addr_t oob_dma_addr = 0;
+	dma_addr_t data_dma_addr_curr = 0;
+	dma_addr_t oob_dma_addr_curr = 0;
+	uint32_t oob_col = 0;
+	unsigned page_count;
+	unsigned pages_read = 0;
+	unsigned start_sector = 0;
+	uint32_t sector_corrected;
+	uint32_t page_corrected;
+	uint32_t total_corrected = 0;
+	uint32_t total_uncorrected = 0;
+	unsigned long uncorrected_noalloc = 0;
+	unsigned long *uncorrected = &uncorrected_noalloc;
+
+	if (from & (mtd->writesize - 1)) {
+		pr_err("%s: unsupported from, 0x%llx\n",
+		       __func__, from);
+		return -EINVAL;
+	}
+	if (ops->mode != MTD_OOB_RAW) {
+		if (ops->datbuf != NULL && (ops->len % mtd->writesize) != 0) {
+			/* when ops->datbuf is NULL, ops->len can be ooblen */
+			pr_err("%s: unsupported ops->len, %d\n",
+			       __func__, ops->len);
+			return -EINVAL;
+		}
+	} else {
+		if (ops->datbuf != NULL &&
+			(ops->len % (mtd->writesize + mtd->oobsize)) != 0) {
+			pr_err("%s: unsupported ops->len,"
+				" %d for MTD_OOB_RAW\n", __func__, ops->len);
+			return -EINVAL;
+		}
+	}
+
+	if (ops->mode != MTD_OOB_RAW && ops->ooblen != 0 && ops->ooboffs != 0) {
+		pr_err("%s: unsupported ops->ooboffs, %d\n",
+		       __func__, ops->ooboffs);
+		return -EINVAL;
+	}
+
+	if (ops->oobbuf && !ops->datbuf && ops->mode == MTD_OOB_AUTO)
+		start_sector = chip->last_sector;
+
+	if (ops->oobbuf && !ops->datbuf) {
+		unsigned tmpoobsz = (ops->mode == MTD_OOB_AUTO) ?
+			mtd->oobavail : mtd->oobsize;
+		page_count = DIV_ROUND_UP(ops->ooblen, tmpoobsz);
+	} else if (ops->mode != MTD_OOB_RAW)
+		page_count = ops->len / mtd->writesize;
+	else
+		page_count = ops->len / (mtd->writesize + mtd->oobsize);
+
+#if 0 /* yaffs reads more oob data than it needs */
+	if (ops->ooblen >= sectoroobsize * 4) {
+		pr_err("%s: unsupported ops->ooblen, %d\n",
+		       __func__, ops->ooblen);
+		return -EINVAL;
+	}
+#endif
+
+#if VERBOSE
+	pr_info("msm_nand_read_oob %llx %p %x %p %x\n",
+		from, ops->datbuf, ops->len, ops->oobbuf, ops->ooblen);
+#endif
+	if (ops->datbuf) {
+		/* memset(ops->datbuf, 0x55, ops->len); */
+		data_dma_addr_curr = data_dma_addr =
+			msm_nand_dma_map(chip->dev, ops->datbuf, ops->len,
+					 DMA_FROM_DEVICE);
+		if (dma_mapping_error(chip->dev, data_dma_addr)) {
+			pr_err("msm_nand_read_oob: failed to get dma addr "
+			       "for %p\n", ops->datbuf);
+			return -EIO;
+		}
+	}
+	if (ops->oobbuf) {
+		memset(ops->oobbuf, 0xff, ops->ooblen);
+		oob_dma_addr_curr = oob_dma_addr =
+			msm_nand_dma_map(chip->dev, ops->oobbuf,
+					 ops->ooblen, DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(chip->dev, oob_dma_addr)) {
+			pr_err("msm_nand_read_oob: failed to get dma addr "
+			       "for %p\n", ops->oobbuf);
+			err = -EIO;
+			goto err_dma_map_oobbuf_failed;
+		}
+	}
+	if (BITS_TO_LONGS(page_count) > 1) {
+		uncorrected = kzalloc(BITS_TO_LONGS(page_count) * sizeof(long),
+				      GFP_NOIO);
+		if (!uncorrected) {
+			err = -ENOMEM;
+			goto err_alloc_uncorrected_failed;
+		}
+	}
+
+	wait_event(chip->wait_queue,
+		   (dma_buffer = msm_nand_get_dma_buffer(
+			    chip, sizeof(*dma_buffer))));
+
+	oob_col = start_sector * 0x210;
+	if (chip->CFG1 & CFG1_WIDE_FLASH)
+		oob_col >>= 1;
+
+	err = 0;
+	while (page_count-- > 0) {
+		cmd = dma_buffer->cmd;
+
+		/* CMD / ADDR0 / ADDR1 / CHIPSEL program values */
+		if (ops->mode != MTD_OOB_RAW) {
+			dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ_ECC;
+			dma_buffer->data.cfg0 =
+				(chip->CFG0 & ~(7U << 6)) |
+				((chip->last_sector - start_sector) << 6);
+			dma_buffer->data.cfg1 = chip->CFG1;
+		} else {
+			dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ;
+			dma_buffer->data.cfg0 =
+				(MSM_NAND_CFG0_RAW & ~(7U << 6)) |
+				(chip->last_sector << 6);
+			dma_buffer->data.cfg1 = MSM_NAND_CFG1_RAW |
+						(chip->CFG1 & CFG1_WIDE_FLASH);
+		}
+
+		dma_buffer->data.addr0 = (page << 16) | oob_col;
+		/* qc example is (page >> 16) && 0xff !? */
+		dma_buffer->data.addr1 = (page >> 16) & 0xff;
+		/* flash0 + undoc bit */
+		dma_buffer->data.chipsel = 0 | 4;
+
+
+		/* GO bit for the EXEC register */
+		dma_buffer->data.exec = 1;
+
+
+		BUILD_BUG_ON(8 != ARRAY_SIZE(dma_buffer->data.result));
+
+		for (n = start_sector; n <= chip->last_sector; n++) {
+			/* flash + buffer status return words */
+			dma_buffer->data.result[n].flash_status = 0xeeeeeeee;
+			dma_buffer->data.result[n].buffer_status = 0xeeeeeeee;
+
+			/* block on cmd ready, then
+			 * write CMD / ADDR0 / ADDR1 / CHIPSEL
+			 * regs in a burst
+			 */
+			cmd->cmd = DST_CRCI_NAND_CMD;
+			cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
+			cmd->dst = MSM_NAND_FLASH_CMD;
+			if (n == start_sector)
+				cmd->len = 16;
+			else
+				cmd->len = 4;
+			cmd++;
+
+			if (n == start_sector) {
+				cmd->cmd = 0;
+				cmd->src = msm_virt_to_dma(chip,
+							&dma_buffer->data.cfg0);
+				cmd->dst = MSM_NAND_DEV0_CFG0;
+				cmd->len = 8;
+				cmd++;
+#if SUPPORT_WRONG_ECC_CONFIG
+				if (chip->saved_ecc_buf_cfg !=
+				    chip->ecc_buf_cfg) {
+					dma_buffer->data.ecccfg =
+						chip->ecc_buf_cfg;
+					cmd->cmd = 0;
+					cmd->src = msm_virt_to_dma(chip,
+						      &dma_buffer->data.ecccfg);
+					cmd->dst = MSM_NAND_EBI2_ECC_BUF_CFG;
+					cmd->len = 4;
+					cmd++;
+				}
+#endif
+			}
+
+			/* kick the execute register */
+			cmd->cmd = 0;
+			cmd->src =
+				msm_virt_to_dma(chip, &dma_buffer->data.exec);
+			cmd->dst = MSM_NAND_EXEC_CMD;
+			cmd->len = 4;
+			cmd++;
+
+			/* block on data ready, then
+			 * read the status register
+			 */
+			cmd->cmd = SRC_CRCI_NAND_DATA;
+			cmd->src = MSM_NAND_FLASH_STATUS;
+			cmd->dst = msm_virt_to_dma(chip,
+						   &dma_buffer->data.result[n]);
+			/* MSM_NAND_FLASH_STATUS + MSM_NAND_BUFFER_STATUS */
+			cmd->len = 8;
+			cmd++;
+
+			/* read data block
+			 * (only valid if status says success)
+			 */
+			if (ops->datbuf) {
+				if (ops->mode != MTD_OOB_RAW)
+					sectordatasize =
+						(n < chip->last_sector) ?
+						516 : chip->last_sectorsz;
+				else
+					sectordatasize = 528;
+
+				cmd->cmd = 0;
+				cmd->src = MSM_NAND_FLASH_BUFFER;
+				cmd->dst = data_dma_addr_curr;
+				data_dma_addr_curr += sectordatasize;
+				cmd->len = sectordatasize;
+				cmd++;
+			}
+
+			if (ops->oobbuf && (n == chip->last_sector ||
+					    ops->mode != MTD_OOB_AUTO)) {
+				cmd->cmd = 0;
+				if (n == chip->last_sector) {
+					cmd->src = MSM_NAND_FLASH_BUFFER +
+						chip->last_sectorsz;
+					sectoroobsize =
+						(chip->last_sector + 1) * 4;
+					if (ops->mode != MTD_OOB_AUTO)
+						sectoroobsize += 10;
+				} else {
+					cmd->src = MSM_NAND_FLASH_BUFFER + 516;
+					sectoroobsize = 10;
+				}
+
+				cmd->dst = oob_dma_addr_curr;
+				if (sectoroobsize < oob_len)
+					cmd->len = sectoroobsize;
+				else
+					cmd->len = oob_len;
+				oob_dma_addr_curr += cmd->len;
+				oob_len -= cmd->len;
+				if (cmd->len > 0)
+					cmd++;
+			}
+		}
+#if SUPPORT_WRONG_ECC_CONFIG
+		if (chip->saved_ecc_buf_cfg != chip->ecc_buf_cfg) {
+			dma_buffer->data.ecccfg_restore =
+				chip->saved_ecc_buf_cfg;
+			cmd->cmd = 0;
+			cmd->src = msm_virt_to_dma(chip,
+					      &dma_buffer->data.ecccfg_restore);
+			cmd->dst = MSM_NAND_EBI2_ECC_BUF_CFG;
+			cmd->len = 4;
+			cmd++;
+		}
+#endif
+
+		BUILD_BUG_ON(8 * 5 + 3 != ARRAY_SIZE(dma_buffer->cmd));
+		BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
+		dma_buffer->cmd[0].cmd |= CMD_OCB;
+		cmd[-1].cmd |= CMD_OCU | CMD_LC;
+
+		dma_buffer->cmdptr =
+			(msm_virt_to_dma(chip, dma_buffer->cmd) >> 3)
+			| CMD_PTR_LP;
+
+		msm_dmov_exec_cmd(
+			chip->dma_channel, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(
+				msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
+
+		/* if any of the writes failed (0x10), or there
+		 * was a protection violation (0x100), we lose
+		 */
+		pageerr = 0;
+		page_corrected = 0;
+		for (n = start_sector; n <= chip->last_sector; n++) {
+			uint32_t buf_stat =
+				dma_buffer->data.result[n].buffer_status;
+			if (buf_stat & BUF_STAT_UNCORRECTABLE) {
+				total_uncorrected++;
+				uncorrected[BIT_WORD(pages_read)] |=
+							BIT_MASK(pages_read);
+				pageerr = -EBADMSG;
+				break;
+			}
+			if (dma_buffer->data.result[n].flash_status & 0x110) {
+				pageerr = -EIO;
+				break;
+			}
+			sector_corrected =buf_stat & BUF_STAT_NUM_ERRS_MASK;
+			page_corrected += sector_corrected;
+			if (sector_corrected > 1)
+				pageerr = -EUCLEAN;
+		}
+		if ((!pageerr && page_corrected) || pageerr == -EUCLEAN) {
+			total_corrected += page_corrected;
+			/* not thread safe */
+			mtd->ecc_stats.corrected += page_corrected;
+		}
+		if (pageerr && (pageerr != -EUCLEAN || err == 0))
+			err = pageerr;
+
+#if VERBOSE
+		pr_info("status: %x %x %x %x %x %x %x %x "
+			"%x %x %x %x %x %x %x %x\n",
+			dma_buffer->data.result[0].flash_status,
+			dma_buffer->data.result[0].buffer_status,
+			dma_buffer->data.result[1].flash_status,
+			dma_buffer->data.result[1].buffer_status,
+			dma_buffer->data.result[2].flash_status,
+			dma_buffer->data.result[2].buffer_status,
+			dma_buffer->data.result[3].flash_status,
+			dma_buffer->data.result[3].buffer_status,
+			dma_buffer->data.result[4].flash_status,
+			dma_buffer->data.result[4].buffer_status,
+			dma_buffer->data.result[5].flash_status,
+			dma_buffer->data.result[5].buffer_status,
+			dma_buffer->data.result[6].flash_status,
+			dma_buffer->data.result[6].buffer_status,
+			dma_buffer->data.result[7].flash_status,
+			dma_buffer->data.result[7].buffer_status);
+#endif
+		if (err && err != -EUCLEAN && err != -EBADMSG)
+			break;
+		pages_read++;
+		page++;
+	}
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+
+err_alloc_uncorrected_failed:
+	if (ops->oobbuf) {
+		dma_unmap_page(chip->dev, oob_dma_addr,
+			       ops->ooblen, DMA_FROM_DEVICE);
+	}
+err_dma_map_oobbuf_failed:
+	if (ops->datbuf) {
+		dma_unmap_page(chip->dev, data_dma_addr,
+			       ops->len, DMA_FROM_DEVICE);
+	}
+
+	if (ops->mode != MTD_OOB_RAW)
+		ops->retlen = mtd->writesize * pages_read;
+	else
+		ops->retlen = (mtd->writesize +  mtd->oobsize) *
+							pages_read;
+	ops->oobretlen = ops->ooblen - oob_len;
+
+	if (err == -EBADMSG && msm_nand_check_empty(mtd, ops, uncorrected))
+		err = 0;
+	else if (total_uncorrected)
+		mtd->ecc_stats.failed += total_uncorrected; /* not threadsafe */
+	if (uncorrected != &uncorrected_noalloc)
+		kfree(uncorrected);
+
+	if (err)
+		pr_err("msm_nand_read_oob %llx %x %x failed %d, corrected %d\n",
+		       from, ops->datbuf ? ops->len : 0, ops->ooblen, err,
+		       total_corrected);
+	return err;
+}
+
+static int
+msm_nand_read(struct mtd_info *mtd, loff_t from, size_t len,
+	      size_t *retlen, u_char *buf)
+{
+	int ret;
+	struct mtd_oob_ops ops;
+
+	/* printk("msm_nand_read %llx %x\n", from, len); */
+
+	ops.mode = MTD_OOB_PLACE;
+	ops.len = len;
+	ops.retlen = 0;
+	ops.ooblen = 0;
+	ops.datbuf = buf;
+	ops.oobbuf = NULL;
+	ret =  msm_nand_read_oob(mtd, from, &ops);
+	*retlen = ops.retlen;
+	return ret;
+}
+
+static int
+msm_nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
+{
+	struct msm_nand_chip *chip = mtd->priv;
+	struct {
+		dmov_s cmd[8 * 6 + 3];
+		unsigned cmdptr;
+		struct {
+			uint32_t cmd;
+			uint32_t addr0;
+			uint32_t addr1;
+			uint32_t chipsel;
+			uint32_t cfg0;
+			uint32_t cfg1;
+			uint32_t exec;
+#if SUPPORT_WRONG_ECC_CONFIG
+			uint32_t ecccfg;
+			uint32_t ecccfg_restore;
+#endif
+			uint32_t flash_status[8];
+			uint32_t zeroes;
+		} data;
+	} *dma_buffer;
+	dmov_s *cmd;
+	unsigned n;
+	unsigned page = to >> chip->page_shift;
+	uint32_t oob_len = ops->ooblen;
+	uint32_t sectordatawritesize;
+	int err;
+	dma_addr_t data_dma_addr = 0;
+	dma_addr_t oob_dma_addr = 0;
+	dma_addr_t data_dma_addr_curr = 0;
+	dma_addr_t oob_dma_addr_curr = 0;
+	unsigned page_count;
+	unsigned pages_written = 0;
+
+	if (to & (mtd->writesize - 1)) {
+		pr_err("%s: unsupported to, 0x%llx\n", __func__, to);
+		return -EINVAL;
+	}
+
+	if (ops->mode != MTD_OOB_RAW) {
+		if (ops->ooblen != 0 && ops->mode != MTD_OOB_AUTO) {
+			pr_err("%s: unsupported ops->mode,%d\n",
+					 __func__, ops->mode);
+			return -EINVAL;
+		}
+		if ((ops->len % mtd->writesize) != 0) {
+			pr_err("%s: unsupported ops->len, %d\n",
+					__func__, ops->len);
+			return -EINVAL;
+		}
+	} else {
+		if ((ops->len % (mtd->writesize + mtd->oobsize)) != 0) {
+			pr_err("%s: unsupported ops->len, "
+				"%d for MTD_OOB_RAW mode\n",
+				 __func__, ops->len);
+			return -EINVAL;
+		}
+	}
+
+	if (ops->datbuf == NULL) {
+		pr_err("%s: unsupported ops->datbuf == NULL\n", __func__);
+		return -EINVAL;
+	}
+#if 0 /* yaffs writes more oob data than it needs */
+	if (ops->ooblen >= sectoroobsize * 4) {
+		pr_err("%s: unsupported ops->ooblen, %d\n",
+		       __func__, ops->ooblen);
+		return -EINVAL;
+	}
+#endif
+	if (ops->mode != MTD_OOB_RAW && ops->ooblen != 0 && ops->ooboffs != 0) {
+		pr_err("%s: unsupported ops->ooboffs, %d\n",
+		       __func__, ops->ooboffs);
+		return -EINVAL;
+	}
+
+	if (ops->datbuf) {
+		data_dma_addr_curr = data_dma_addr =
+			msm_nand_dma_map(chip->dev, ops->datbuf,
+					 ops->len, DMA_TO_DEVICE);
+		if (dma_mapping_error(chip->dev, data_dma_addr)) {
+			pr_err("msm_nand_write_oob: failed to get dma addr "
+			       "for %p\n", ops->datbuf);
+			return -EIO;
+		}
+	}
+	if (ops->oobbuf) {
+		oob_dma_addr_curr = oob_dma_addr =
+			msm_nand_dma_map(chip->dev, ops->oobbuf,
+					 ops->ooblen, DMA_TO_DEVICE);
+		if (dma_mapping_error(chip->dev, oob_dma_addr)) {
+			pr_err("msm_nand_write_oob: failed to get dma addr "
+			       "for %p\n", ops->oobbuf);
+			err = -EIO;
+			goto err_dma_map_oobbuf_failed;
+		}
+	}
+	if (ops->mode != MTD_OOB_RAW)
+		page_count = ops->len / mtd->writesize;
+	else
+		page_count = ops->len / (mtd->writesize + mtd->oobsize);
+
+	wait_event(chip->wait_queue, (dma_buffer =
+			msm_nand_get_dma_buffer(chip, sizeof(*dma_buffer))));
+
+	while (page_count-- > 0) {
+		cmd = dma_buffer->cmd;
+
+		/* CMD / ADDR0 / ADDR1 / CHIPSEL program values */
+		if (ops->mode != MTD_OOB_RAW) {
+			dma_buffer->data.cfg0 = chip->CFG0;
+			dma_buffer->data.cfg1 = chip->CFG1;
+		} else {
+			dma_buffer->data.cfg0 =
+				(MSM_NAND_CFG0_RAW & ~(7U << 6)) |
+				(chip->last_sector << 6);
+			dma_buffer->data.cfg1 = MSM_NAND_CFG1_RAW |
+				(chip->CFG1 & CFG1_WIDE_FLASH);
+		}
+
+		dma_buffer->data.cmd = MSM_NAND_CMD_PRG_PAGE;
+		dma_buffer->data.addr0 = page << 16;
+		dma_buffer->data.addr1 = (page >> 16) & 0xff;
+		dma_buffer->data.chipsel = 0 | 4; /* flash0 + undoc bit */
+		dma_buffer->data.zeroes = 0;
+
+
+			/* GO bit for the EXEC register */
+		dma_buffer->data.exec = 1;
+
+		BUILD_BUG_ON(8 != ARRAY_SIZE(dma_buffer->data.flash_status));
+
+		for (n = 0; n <= chip->last_sector ; n++) {
+			/* status return words */
+			dma_buffer->data.flash_status[n] = 0xeeeeeeee;
+			/* block on cmd ready, then
+			 * write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst
+			 */
+			cmd->cmd = DST_CRCI_NAND_CMD;
+			cmd->src =
+				msm_virt_to_dma(chip, &dma_buffer->data.cmd);
+			cmd->dst = MSM_NAND_FLASH_CMD;
+			if (n == 0)
+				cmd->len = 16;
+			else
+				cmd->len = 4;
+			cmd++;
+
+			if (n == 0) {
+				cmd->cmd = 0;
+				cmd->src = msm_virt_to_dma(chip,
+							&dma_buffer->data.cfg0);
+				cmd->dst = MSM_NAND_DEV0_CFG0;
+				cmd->len = 8;
+				cmd++;
+#if SUPPORT_WRONG_ECC_CONFIG
+				if (chip->saved_ecc_buf_cfg !=
+				    chip->ecc_buf_cfg) {
+					dma_buffer->data.ecccfg =
+						chip->ecc_buf_cfg;
+					cmd->cmd = 0;
+					cmd->src = msm_virt_to_dma(chip,
+						      &dma_buffer->data.ecccfg);
+					cmd->dst = MSM_NAND_EBI2_ECC_BUF_CFG;
+					cmd->len = 4;
+					cmd++;
+				}
+#endif
+			}
+
+				/* write data block */
+			if (ops->mode != MTD_OOB_RAW)
+				sectordatawritesize = (n < chip->last_sector) ?
+					516 : chip->last_sectorsz;
+			else
+				sectordatawritesize = 528;
+
+			cmd->cmd = 0;
+			cmd->src = data_dma_addr_curr;
+			data_dma_addr_curr += sectordatawritesize;
+			cmd->dst = MSM_NAND_FLASH_BUFFER;
+			cmd->len = sectordatawritesize;
+			cmd++;
+
+			if (ops->oobbuf) {
+				if (n == chip->last_sector) {
+					cmd->cmd = 0;
+					cmd->src = oob_dma_addr_curr;
+					cmd->dst = MSM_NAND_FLASH_BUFFER +
+						chip->last_sectorsz;
+					cmd->len = 516 - chip->last_sectorsz;
+					if (oob_len <= cmd->len)
+						cmd->len = oob_len;
+					oob_dma_addr_curr += cmd->len;
+					oob_len -= cmd->len;
+					if (cmd->len > 0)
+						cmd++;
+				}
+				if (ops->mode != MTD_OOB_AUTO) {
+					/* skip ecc bytes in oobbuf */
+					if (oob_len < 10) {
+						oob_dma_addr_curr += 10;
+						oob_len -= 10;
+					} else {
+						oob_dma_addr_curr += oob_len;
+						oob_len = 0;
+					}
+				}
+			}
+
+			/* kick the execute register */
+			cmd->cmd = 0;
+			cmd->src =
+				msm_virt_to_dma(chip, &dma_buffer->data.exec);
+			cmd->dst = MSM_NAND_EXEC_CMD;
+			cmd->len = 4;
+			cmd++;
+
+			/* block on data ready, then
+			 * read the status register
+			 */
+			cmd->cmd = SRC_CRCI_NAND_DATA;
+			cmd->src = MSM_NAND_FLASH_STATUS;
+			cmd->dst = msm_virt_to_dma(chip,
+					     &dma_buffer->data.flash_status[n]);
+			cmd->len = 4;
+			cmd++;
+
+			/* clear the status register in case the OP_ERR is set
+			 * due to the write, to work around a h/w bug */
+			cmd->cmd = 0;
+			cmd->src = msm_virt_to_dma(chip,
+						   &dma_buffer->data.zeroes);
+			cmd->dst = MSM_NAND_FLASH_STATUS;
+			cmd->len = 4;
+			cmd++;
+		}
+#if SUPPORT_WRONG_ECC_CONFIG
+		if (chip->saved_ecc_buf_cfg != chip->ecc_buf_cfg) {
+			dma_buffer->data.ecccfg_restore =
+				chip->saved_ecc_buf_cfg;
+			cmd->cmd = 0;
+			cmd->src = msm_virt_to_dma(chip,
+					      &dma_buffer->data.ecccfg_restore);
+			cmd->dst = MSM_NAND_EBI2_ECC_BUF_CFG;
+			cmd->len = 4;
+			cmd++;
+		}
+#endif
+		dma_buffer->cmd[0].cmd |= CMD_OCB;
+		cmd[-1].cmd |= CMD_OCU | CMD_LC;
+		BUILD_BUG_ON(8 * 6 + 3 != ARRAY_SIZE(dma_buffer->cmd));
+		BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
+		dma_buffer->cmdptr =
+			(msm_virt_to_dma(chip, dma_buffer->cmd) >> 3) |
+			CMD_PTR_LP;
+
+		msm_dmov_exec_cmd(chip->dma_channel,
+			DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(
+				msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
+
+		/* if any of the writes failed (0x10), or there was a
+		 * protection violation (0x100), or the program success
+		 * bit (0x80) is unset, we lose
+		 */
+		err = 0;
+		for (n = 0; n <= chip->last_sector ; n++) {
+			if (dma_buffer->data.flash_status[n] & 0x110) {
+				if (dma_buffer->data.flash_status[n] & 0x10)
+					pr_err("msm_nand: critical write error,"
+					       " 0x%x(%d)\n", page, n);
+				err = -EIO;
+				break;
+			}
+			if (!(dma_buffer->data.flash_status[n] & 0x80)) {
+				err = -EIO;
+				break;
+			}
+		}
+
+#if VERBOSE
+		pr_info("write page %d: status: %x %x %x %x %x %x %x %x\n",
+			page, dma_buffer->data.flash_status[0],
+			dma_buffer->data.flash_status[1],
+			dma_buffer->data.flash_status[2],
+			dma_buffer->data.flash_status[3],
+			dma_buffer->data.flash_status[4],
+			dma_buffer->data.flash_status[5],
+			dma_buffer->data.flash_status[6],
+			dma_buffer->data.flash_status[7]);
+#endif
+		if (err)
+			break;
+		pages_written++;
+		page++;
+	}
+	if (ops->mode != MTD_OOB_RAW)
+		ops->retlen = mtd->writesize * pages_written;
+	else
+		ops->retlen = (mtd->writesize + mtd->oobsize) * pages_written;
+
+	ops->oobretlen = ops->ooblen - oob_len;
+
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+
+	if (ops->oobbuf)
+		dma_unmap_page(chip->dev, oob_dma_addr,
+			       ops->ooblen, DMA_TO_DEVICE);
+err_dma_map_oobbuf_failed:
+	if (ops->datbuf)
+		dma_unmap_page(chip->dev, data_dma_addr,
+			       ops->len, DMA_TO_DEVICE);
+	if (err)
+		pr_err("msm_nand_write_oob %llx %x %x failed %d\n",
+		       to, ops->len, ops->ooblen, err);
+	return err;
+}
+
+static int msm_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
+			  size_t *retlen, const u_char *buf)
+{
+	int ret;
+	struct mtd_oob_ops ops;
+
+	ops.mode = MTD_OOB_PLACE;
+	ops.len = len;
+	ops.retlen = 0;
+	ops.ooblen = 0;
+	ops.datbuf = (uint8_t *)buf;
+	ops.oobbuf = NULL;
+	ret =  msm_nand_write_oob(mtd, to, &ops);
+	*retlen = ops.retlen;
+	return ret;
+}
+
+static int
+msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	int err;
+	struct msm_nand_chip *chip = mtd->priv;
+	struct {
+		dmov_s cmd[5];
+		unsigned cmdptr;
+		unsigned data[9];
+	} *dma_buffer;
+	unsigned page = instr->addr >> chip->page_shift;
+
+	if (instr->addr & (mtd->erasesize - 1)) {
+		pr_err("%s: unsupported erase address, 0x%llx\n",
+		       __func__, instr->addr);
+		return -EINVAL;
+	}
+	if (instr->len != mtd->erasesize) {
+		pr_err("%s: unsupported erase len, %lld\n",
+		       __func__, instr->len);
+		return -EINVAL;
+	}
+
+	wait_event(chip->wait_queue,
+		   (dma_buffer = msm_nand_get_dma_buffer(
+			    chip, sizeof(*dma_buffer))));
+
+	dma_buffer->data[0] = MSM_NAND_CMD_BLOCK_ERASE;
+	dma_buffer->data[1] = page;
+	dma_buffer->data[2] = 0;
+	dma_buffer->data[3] = 0 | 4;
+	dma_buffer->data[4] = 1;
+	dma_buffer->data[5] = 0xeeeeeeee;
+	dma_buffer->data[6] = chip->CFG0 & (~(7 << 6));  /* CW_PER_PAGE = 0 */
+	dma_buffer->data[7] = chip->CFG1;
+	dma_buffer->data[8] = 0;
+	BUILD_BUG_ON(8 != ARRAY_SIZE(dma_buffer->data) - 1);
+
+	dma_buffer->cmd[0].cmd = DST_CRCI_NAND_CMD | CMD_OCB;
+	dma_buffer->cmd[0].src = msm_virt_to_dma(chip, &dma_buffer->data[0]);
+	dma_buffer->cmd[0].dst = MSM_NAND_FLASH_CMD;
+	dma_buffer->cmd[0].len = 16;
+
+	dma_buffer->cmd[1].cmd = 0;
+	dma_buffer->cmd[1].src = msm_virt_to_dma(chip, &dma_buffer->data[6]);
+	dma_buffer->cmd[1].dst = MSM_NAND_DEV0_CFG0;
+	dma_buffer->cmd[1].len = 8;
+
+	dma_buffer->cmd[2].cmd = 0;
+	dma_buffer->cmd[2].src = msm_virt_to_dma(chip, &dma_buffer->data[4]);
+	dma_buffer->cmd[2].dst = MSM_NAND_EXEC_CMD;
+	dma_buffer->cmd[2].len = 4;
+
+	dma_buffer->cmd[3].cmd = SRC_CRCI_NAND_DATA;
+	dma_buffer->cmd[3].src = MSM_NAND_FLASH_STATUS;
+	dma_buffer->cmd[3].dst = msm_virt_to_dma(chip, &dma_buffer->data[5]);
+	dma_buffer->cmd[3].len = 4;
+
+	/* clear the status register in case the OP_ERR is set
+	 * due to the write, to work around a h/w bug */
+	dma_buffer->cmd[4].cmd = CMD_OCU | CMD_LC;
+	dma_buffer->cmd[4].src = msm_virt_to_dma(chip, &dma_buffer->data[8]);
+	dma_buffer->cmd[4].dst = MSM_NAND_FLASH_STATUS;
+	dma_buffer->cmd[4].len = 4;
+
+	BUILD_BUG_ON(4 != ARRAY_SIZE(dma_buffer->cmd) - 1);
+
+	dma_buffer->cmdptr =
+		(msm_virt_to_dma(chip, dma_buffer->cmd) >> 3) | CMD_PTR_LP;
+
+	msm_dmov_exec_cmd(
+		chip->dma_channel, DMOV_CMD_PTR_LIST |
+		DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
+
+	/* we fail if there was an operation error, a mpu error, or the
+	 * erase success bit was not set.
+	 */
+
+	if (dma_buffer->data[5] & 0x110 || !(dma_buffer->data[5] & 0x80)) {
+		if (dma_buffer->data[5] & 0x10)
+			pr_warning("msm_nand: critical erase error, 0x%llx\n",
+				   instr->addr);
+		err = -EIO;
+	} else
+		err = 0;
+
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+	if (err) {
+		pr_err("%s: erase failed, 0x%llx\n", __func__, instr->addr);
+		instr->fail_addr = instr->addr;
+		instr->state = MTD_ERASE_FAILED;
+	} else {
+		instr->state = MTD_ERASE_DONE;
+		instr->fail_addr = 0xffffffff;
+		mtd_erase_callback(instr);
+	}
+	return err;
+}
+
+static int
+msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct msm_nand_chip *chip = mtd->priv;
+	int ret;
+	struct {
+		dmov_s cmd[5];
+		unsigned cmdptr;
+		struct {
+			uint32_t cmd;
+			uint32_t addr0;
+			uint32_t addr1;
+			uint32_t chipsel;
+			uint32_t cfg0;
+			uint32_t cfg1;
+			uint32_t exec;
+			uint32_t ecccfg;
+			struct {
+				uint32_t flash_status;
+				uint32_t buffer_status;
+			} result;
+		} data;
+	} *dma_buffer;
+	dmov_s *cmd;
+	uint8_t *buf;
+	unsigned page = ofs >> chip->page_shift;
+
+	/* Check for invalid offset */
+	if (ofs > mtd->size)
+		return -EINVAL;
+	if (ofs & (mtd->erasesize - 1)) {
+		pr_err("%s: unsupported block address, 0x%x\n",
+			 __func__, (uint32_t)ofs);
+		return -EINVAL;
+	}
+
+	wait_event(chip->wait_queue,
+		(dma_buffer = msm_nand_get_dma_buffer(chip ,
+					 sizeof(*dma_buffer) + 4)));
+	buf = (uint8_t *)dma_buffer + sizeof(*dma_buffer);
+
+	/* Read 4 bytes starting from the bad block marker location
+	 * in the last code word of the page
+	 */
+
+	cmd = dma_buffer->cmd;
+
+	dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ;
+	dma_buffer->data.cfg0 = MSM_NAND_CFG0_RAW & ~(7U << 6);
+	dma_buffer->data.cfg1 = MSM_NAND_CFG1_RAW | (chip->CFG1 & CFG1_WIDE_FLASH);
+
+	if (chip->CFG1 & CFG1_WIDE_FLASH)
+		dma_buffer->data.addr0 = (page << 16) |
+			((528 * chip->last_sector) >> 1);
+	else
+		dma_buffer->data.addr0 = (page << 16) |
+			(528 * chip->last_sector);
+
+	dma_buffer->data.addr1 = (page >> 16) & 0xff;
+	dma_buffer->data.chipsel = 0 | 4;
+
+	dma_buffer->data.exec = 1;
+
+	dma_buffer->data.result.flash_status = 0xeeeeeeee;
+	dma_buffer->data.result.buffer_status = 0xeeeeeeee;
+
+	cmd->cmd = DST_CRCI_NAND_CMD;
+	cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
+	cmd->dst = MSM_NAND_FLASH_CMD;
+	cmd->len = 16;
+	cmd++;
+
+	cmd->cmd = 0;
+	cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cfg0);
+	cmd->dst = MSM_NAND_DEV0_CFG0;
+	cmd->len = 8;
+	cmd++;
+
+	cmd->cmd = 0;
+	cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.exec);
+	cmd->dst = MSM_NAND_EXEC_CMD;
+	cmd->len = 4;
+	cmd++;
+
+	cmd->cmd = SRC_CRCI_NAND_DATA;
+	cmd->src = MSM_NAND_FLASH_STATUS;
+	cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.result);
+	cmd->len = 8;
+	cmd++;
+
+	cmd->cmd = 0;
+	cmd->src = MSM_NAND_FLASH_BUFFER +
+		(mtd->writesize - 528 * chip->last_sector);
+	cmd->dst = msm_virt_to_dma(chip, buf);
+	cmd->len = 4;
+	cmd++;
+
+	BUILD_BUG_ON(5 != ARRAY_SIZE(dma_buffer->cmd));
+	BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
+	dma_buffer->cmd[0].cmd |= CMD_OCB;
+	cmd[-1].cmd |= CMD_OCU | CMD_LC;
+
+	dma_buffer->cmdptr = (msm_virt_to_dma(chip,
+				dma_buffer->cmd) >> 3) | CMD_PTR_LP;
+
+	msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST |
+		DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
+
+	ret = 0;
+	if (dma_buffer->data.result.flash_status & 0x110)
+		ret = -EIO;
+
+	if (!ret) {
+		/* Check for bad block marker byte */
+		if (chip->CFG1 & CFG1_WIDE_FLASH) {
+			if (buf[0] != 0xFF || buf[1] != 0xFF)
+				ret = 1;
+		} else {
+			if (buf[0] != 0xFF)
+				ret = 1;
+		}
+	}
+
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer) + 4);
+	return ret;
+}
+
+
+static int
+msm_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct mtd_oob_ops ops;
+	int ret;
+	uint8_t *buf;
+
+	/* Check for invalid offset */
+	if (ofs > mtd->size)
+		return -EINVAL;
+	if (ofs & (mtd->erasesize - 1)) {
+		pr_err("%s: unsupported block address, 0x%x\n",
+				 __func__, (uint32_t)ofs);
+		return -EINVAL;
+	}
+
+	/*
+	Write all 0s to the first page
+	This will set the BB marker to 0
+	*/
+
+	/* Use the already existing zero page */
+	buf =  page_address(ZERO_PAGE());
+
+	ops.mode = MTD_OOB_RAW;
+	ops.len = mtd->writesize + mtd->oobsize;
+	ops.retlen = 0;
+	ops.ooblen = 0;
+	ops.datbuf = buf;
+	ops.oobbuf = NULL;
+	ret =  msm_nand_write_oob(mtd, ofs, &ops);
+
+	return ret;
+}
+
+/**
+ * msm_nand_suspend - [MTD Interface] Suspend the msm_nand flash
+ * @param mtd		MTD device structure
+ */
+static int msm_nand_suspend(struct mtd_info *mtd)
+{
+	return 0;
+}
+
+/**
+ * msm_nand_resume - [MTD Interface] Resume the msm_nand flash
+ * @param mtd		MTD device structure
+ */
+static void msm_nand_resume(struct mtd_info *mtd)
+{
+}
+
+
+/**
+ * msm_nand_scan - [msm_nand Interface] Scan for the msm_nand device
+ * @param mtd		MTD device structure
+ * @param maxchips	Number of chips to scan for
+ *
+ * This fills out all the not initialized function pointers
+ * with the defaults.
+ * The flash ID is read and the mtd/chip structures are
+ * filled with the appropriate values.
+ */
+int msm_nand_scan(struct mtd_info *mtd, int maxchips)
+{
+	unsigned n;
+	struct msm_nand_chip *chip = mtd->priv;
+	uint32_t flash_id;
+	uint32_t manid;
+	uint32_t devid;
+	uint32_t devcfg;
+	uint32_t busw16;
+	struct nand_flash_dev *flashdev = NULL;
+	struct nand_manufacturers *flashman = NULL;
+
+	if (flash_read_config(chip)) {
+		pr_err("ERRROR: could not save CFG0 & CFG1 state\n");
+		return -ENODEV;
+	}
+	pr_info("msm_nand: NAND_READ_ID = %x\n",
+		flash_rd_reg(chip, MSM_NAND_READ_ID));
+	flash_wr_reg(chip, MSM_NAND_READ_ID, 0x12345678);
+
+	flash_id = flash_read_id(chip);
+	manid = flash_id & 0xff;
+	devid = (flash_id >> 8) & 0xff;
+	devcfg = (flash_id >> 24) & 0xff;
+
+	for (n = 0;  !flashman && nand_manuf_ids[n].id; ++n)
+		if (nand_manuf_ids[n].id == manid)
+			flashman = &nand_manuf_ids[n];
+	for (n = 0; !flashdev && nand_flash_ids[n].id; ++n)
+		if (nand_flash_ids[n].id == devid)
+			flashdev = &nand_flash_ids[n];
+	if (!flashdev || !flashman) {
+		pr_err("ERROR: unknown nand device manuf=%x devid=%x\n",
+		       manid, devid);
+		return -ENOENT;
+	}
+
+	if (!flashdev->pagesize) {
+		mtd->erasesize = (64 * 1024) << ((devcfg >> 4) & 0x3);
+		mtd->writesize = 1024 << (devcfg & 0x3);
+		mtd->oobsize = (8 << ((devcfg >> 2) & 1)) *
+			(mtd->writesize / 512);
+		busw16 = devcfg & (1 << 6) ? CFG1_WIDE_FLASH : 0;
+	} else {
+		mtd->writesize = flashdev->pagesize;
+		mtd->erasesize = flashdev->erasesize;
+		mtd->oobsize = flashdev->pagesize / 32;
+		busw16 = flashdev->options & NAND_BUSWIDTH_16 ?
+			CFG1_WIDE_FLASH : 0;
+	}
+	mtd->size = flashdev->chipsize << 20;
+	pr_info("msm_nand: manuf %s (0x%x) device 0x%x blocksz %x pagesz %x "
+		"size %llx\n", flashman->name, flashman->id, flashdev->id,
+		mtd->erasesize, mtd->writesize, mtd->size);
+
+	if (mtd->writesize == 2048) {
+		chip->page_shift = 11;
+	} else if (mtd->writesize == 4096) {
+		chip->page_shift = 12;
+	} else {
+		pr_err("%s: Unsupported page size (%d)\n", __func__,
+		       mtd->writesize);
+		return -EINVAL;
+	}
+
+	chip->last_sector = (mtd->writesize / 512) - 1;
+	chip->last_sectorsz = mtd->writesize - chip->last_sector * 516;
+
+	if (mtd->oobsize == 64) {
+		mtd->ecclayout = &msm_nand_oob_64;
+	} else if (mtd->oobsize == 128) {
+		mtd->ecclayout = &msm_nand_oob_128;
+	} else {
+		pr_err("%s: Unsupported oob size (%d)\n", __func__,
+		       mtd->oobsize);
+		return -EINVAL;
+	}
+	mtd->oobavail = mtd->ecclayout->oobavail;
+
+	chip->CFG0 = (chip->last_sector << 6) /* codewords per page */
+		|  (516 <<  9)  /* 516 user data bytes */
+		|   (10 << 19)  /* 10 parity bytes */
+		|    (5 << 27)  /* 5 address cycles */
+		|    (1 << 30)  /* Read status before data */
+		|    (1 << 31)  /* Send read cmd */
+		/* 0 spare bytes for 16 bit nand or 1 spare bytes for 8 bit */
+		| ((busw16 & CFG1_WIDE_FLASH) ? (0 << 23) : (1 << 23));
+	chip->CFG1 = (0 <<  0)  /* Enable ecc */
+		|    (7 <<  2)  /* 8 recovery cycles */
+		|    (0 <<  5)  /* Allow CS deassertion */
+		|  ((mtd->writesize - (528 * chip->last_sector) + 1) <<  6)
+		                /* Bad block marker location */
+		|    (0 << 16)  /* Bad block in user data area */
+		|    (2 << 17)  /* 6 cycle tWB/tRB */
+		| (busw16 & CFG1_WIDE_FLASH); /* preserve wide flag */
+
+	pr_info("msm_nand: save CFG0 = %x CFG1 = %x\n", chip->CFG0, chip->CFG1);
+	pr_info("msm_nand: CFG0: cw/page=%d ud_sz=%d ecc_sz=%d spare_sz=%d "
+		"num_addr_cycles=%d\n", (chip->CFG0 >> 6) & 7,
+		(chip->CFG0 >> 9) & 0x3ff, (chip->CFG0 >> 19) & 15,
+		(chip->CFG0 >> 23) & 15, (chip->CFG0 >> 27) & 7);
+
+	n = flash_rd_reg(chip, MSM_NAND_DEV_CMD1);
+	pr_info("msm_nand: DEV_CMD1: %x\n", n);
+
+	n = flash_rd_reg(chip, MSM_NAND_EBI2_ECC_BUF_CFG);
+	pr_info("msm_nand: NAND_EBI2_ECC_BUF_CFG: %x\n", n);
+
+#if SUPPORT_WRONG_ECC_CONFIG
+	chip->ecc_buf_cfg = 0x203;
+	chip->saved_ecc_buf_cfg = n;
+#endif
+
+	/* Fill in remaining MTD driver data */
+	mtd->type = MTD_NANDFLASH;
+	mtd->flags = MTD_CAP_NANDFLASH;
+	/* mtd->ecctype = MTD_ECC_SW; */
+	mtd->erase = msm_nand_erase;
+	mtd->point = NULL;
+	mtd->unpoint = NULL;
+	mtd->read = msm_nand_read;
+	mtd->write = msm_nand_write;
+	mtd->read_oob = msm_nand_read_oob;
+	mtd->write_oob = msm_nand_write_oob;
+	/* mtd->sync = msm_nand_sync; */
+	mtd->lock = NULL;
+	/* mtd->unlock = msm_nand_unlock; */
+	mtd->suspend = msm_nand_suspend;
+	mtd->resume = msm_nand_resume;
+	mtd->block_isbad = msm_nand_block_isbad;
+	mtd->block_markbad = msm_nand_block_markbad;
+	mtd->owner = THIS_MODULE;
+
+	/* Unlock whole block */
+	/* msm_nand_unlock_all(mtd); */
+
+	/* return this->scan_bbt(mtd); */
+	return 0;
+}
+EXPORT_SYMBOL_GPL(msm_nand_scan);
+
+/**
+ * msm_nand_release - [msm_nand Interface] Free resources held by the msm_nand device
+ * @param mtd		MTD device structure
+ */
+void msm_nand_release(struct mtd_info *mtd)
+{
+	/* struct msm_nand_chip *this = mtd->priv; */
+
+#ifdef CONFIG_MTD_PARTITIONS
+	/* Deregister partitions */
+	del_mtd_partitions(mtd);
+#endif
+	/* Deregister the device */
+	del_mtd_device(mtd);
+}
+EXPORT_SYMBOL_GPL(msm_nand_release);
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL,  };
+#endif
+
+struct msm_nand_info {
+	struct mtd_info		mtd;
+	struct mtd_partition	*parts;
+	struct msm_nand_chip	msm_nand;
+};
+
+static int __devinit msm_nand_probe(struct platform_device *pdev)
+{
+	struct msm_nand_info *info;
+	struct flash_platform_data *pdata = pdev->dev.platform_data;
+	int err;
+	int i;
+
+	if (pdev->num_resources != 1) {
+		pr_err("invalid num_resources");
+		return -ENODEV;
+	}
+	if (pdev->resource[0].flags != IORESOURCE_DMA) {
+		pr_err("invalid resource type");
+		return -ENODEV;
+	}
+
+	info = kzalloc(sizeof(struct msm_nand_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->msm_nand.dev = &pdev->dev;
+
+	init_waitqueue_head(&info->msm_nand.wait_queue);
+
+	info->msm_nand.dma_channel = pdev->resource[0].start;
+	/* this currently fails if dev is passed in */
+	info->msm_nand.dma_buffer =
+		dma_alloc_coherent(/*dev*/ NULL, MSM_NAND_DMA_BUFFER_SIZE,
+				   &info->msm_nand.dma_addr, GFP_KERNEL);
+	if (info->msm_nand.dma_buffer == NULL) {
+		err = -ENOMEM;
+		goto out_free_info;
+	}
+
+	pr_info("msm_nand: allocated dma buffer at %p, dma_addr %x\n",
+		info->msm_nand.dma_buffer, info->msm_nand.dma_addr);
+
+	info->mtd.name = dev_name(&pdev->dev);
+	info->mtd.priv = &info->msm_nand;
+	info->mtd.owner = THIS_MODULE;
+
+	if (msm_nand_scan(&info->mtd, 1)) {
+		err = -ENXIO;
+		goto out_free_dma_buffer;
+	}
+
+#ifdef CONFIG_MTD_PARTITIONS
+	err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
+	if (err > 0)
+		add_mtd_partitions(&info->mtd, info->parts, err);
+	else if (err <= 0 && pdata && pdata->parts) {
+		for (i = 0; i < pdata->nr_parts; ++i) {
+			pdata->parts[i].offset *= info->mtd.erasesize;
+			pdata->parts[i].size *= info->mtd.erasesize;
+		}
+		add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+	} else
+#endif
+		err = add_mtd_device(&info->mtd);
+
+	dev_set_drvdata(&pdev->dev, info);
+
+	return 0;
+
+out_free_dma_buffer:
+	dma_free_coherent(/*dev*/ NULL, SZ_4K, info->msm_nand.dma_buffer,
+			  info->msm_nand.dma_addr);
+out_free_info:
+	kfree(info);
+
+	return err;
+}
+
+static int __devexit msm_nand_remove(struct platform_device *pdev)
+{
+	struct msm_nand_info *info = dev_get_drvdata(&pdev->dev);
+
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	if (info) {
+#ifdef CONFIG_MTD_PARTITIONS
+		if (info->parts)
+			del_mtd_partitions(&info->mtd);
+		else
+#endif
+			del_mtd_device(&info->mtd);
+
+		msm_nand_release(&info->mtd);
+		dma_free_coherent(/*dev*/ NULL, SZ_4K,
+				  info->msm_nand.dma_buffer,
+				  info->msm_nand.dma_addr);
+		kfree(info);
+	}
+
+	return 0;
+}
+
+#define DRIVER_NAME "msm_nand"
+
+static struct platform_driver msm_nand_driver = {
+	.probe		= msm_nand_probe,
+	.remove		= __devexit_p(msm_nand_remove),
+	.driver = {
+		.name		= DRIVER_NAME,
+	}
+};
+
+MODULE_ALIAS(DRIVER_NAME);
+
+static int __init msm_nand_init(void)
+{
+	return platform_driver_register(&msm_nand_driver);
+}
+
+static void __exit msm_nand_exit(void)
+{
+	platform_driver_unregister(&msm_nand_driver);
+}
+
+module_init(msm_nand_init);
+module_exit(msm_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("msm_nand flash driver code");
diff --git a/drivers/mtd/devices/msm_nand.h b/drivers/mtd/devices/msm_nand.h
new file mode 100644
index 0000000..18893f1
--- /dev/null
+++ b/drivers/mtd/devices/msm_nand.h
@@ -0,0 +1,71 @@
+/* drivers/mtd/devices/msm_nand.h
+ *
+ * Copyright (C) 2007 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.
+ *
+ */
+
+#ifndef __DRIVERS_MTD_DEVICES_MSM_NAND_H
+#define __DRIVERS_MTD_DEVICES_MSM_NAND_H
+
+#include <mach/msm_iomap.h>
+
+#define MSM_NAND_REG(off)            (MSM_NAND_PHYS + (off))
+
+#define MSM_NAND_FLASH_CMD            MSM_NAND_REG(0x0000)
+#define MSM_NAND_ADDR0                MSM_NAND_REG(0x0004)
+#define MSM_NAND_ADDR1                MSM_NAND_REG(0x0008)
+#define MSM_NAND_FLASH_CHIP_SELECT    MSM_NAND_REG(0x000C)
+#define MSM_NAND_EXEC_CMD             MSM_NAND_REG(0x0010)
+#define MSM_NAND_FLASH_STATUS         MSM_NAND_REG(0x0014)
+#define MSM_NAND_BUFFER_STATUS        MSM_NAND_REG(0x0018)
+#define MSM_NAND_DEV0_CFG0            MSM_NAND_REG(0x0020)
+#define MSM_NAND_DEV0_CFG1            MSM_NAND_REG(0x0024)
+#define MSM_NAND_DEV1_CFG0            MSM_NAND_REG(0x0030)
+#define MSM_NAND_DEV1_CFG1            MSM_NAND_REG(0x0034)
+#define MSM_NAND_READ_ID              MSM_NAND_REG(0x0040)
+#define MSM_NAND_READ_STATUS          MSM_NAND_REG(0x0044)
+#define MSM_NAND_CONFIG_DATA          MSM_NAND_REG(0x0050)
+#define MSM_NAND_CONFIG               MSM_NAND_REG(0x0054)
+#define MSM_NAND_CONFIG_MODE          MSM_NAND_REG(0x0058)
+#define MSM_NAND_CONFIG_STATUS        MSM_NAND_REG(0x0060)
+#define MSM_NAND_MACRO1_REG           MSM_NAND_REG(0x0064)
+#define MSM_NAND_XFR_STEP1            MSM_NAND_REG(0x0070)
+#define MSM_NAND_XFR_STEP2            MSM_NAND_REG(0x0074)
+#define MSM_NAND_XFR_STEP3            MSM_NAND_REG(0x0078)
+#define MSM_NAND_XFR_STEP4            MSM_NAND_REG(0x007C)
+#define MSM_NAND_XFR_STEP5            MSM_NAND_REG(0x0080)
+#define MSM_NAND_XFR_STEP6            MSM_NAND_REG(0x0084)
+#define MSM_NAND_XFR_STEP7            MSM_NAND_REG(0x0088)
+#define MSM_NAND_DEV_CMD0             MSM_NAND_REG(0x00A0)
+#define MSM_NAND_DEV_CMD1             MSM_NAND_REG(0x00A4)
+#define MSM_NAND_DEV_CMD2             MSM_NAND_REG(0x00A8)
+#define MSM_NAND_DEV_CMD_VLD          MSM_NAND_REG(0x00AC)
+#define MSM_NAND_EBI2_MISR_SIG_REG    MSM_NAND_REG(0x00B0)
+#define MSM_NAND_EBI2_ECC_BUF_CFG     MSM_NAND_REG(0x00F0)
+#define MSM_NAND_FLASH_BUFFER         MSM_NAND_REG(0x0100)
+
+/* device commands */
+
+#define MSM_NAND_CMD_SOFT_RESET         0x01
+#define MSM_NAND_CMD_PAGE_READ          0x32
+#define MSM_NAND_CMD_PAGE_READ_ECC      0x33
+#define MSM_NAND_CMD_PAGE_READ_ALL      0x34
+#define MSM_NAND_CMD_SEQ_PAGE_READ      0x15
+#define MSM_NAND_CMD_PRG_PAGE           0x36
+#define MSM_NAND_CMD_PRG_PAGE_ECC       0x37
+#define MSM_NAND_CMD_PRG_PAGE_ALL       0x39
+#define MSM_NAND_CMD_BLOCK_ERASE        0x3A
+#define MSM_NAND_CMD_FETCH_ID           0x0B
+#define MSM_NAND_CMD_STATUS             0x0C
+#define MSM_NAND_CMD_RESET              0x0D
+
+#endif
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 416d7d2..67f927b 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3292,6 +3292,21 @@
 	If you want to log kernel messages over the network, enable this.
 	See <file:Documentation/networking/netconsole.txt> for details.
 
+config MSM_RMNET
+	tristate "MSM RMNET Virtual Network Device"
+	depends on ARCH_MSM
+	default y
+	help
+	  Virtual ethernet interface for MSM RMNET transport.
+
+config MSM_RMNET_DEBUG
+	bool "MSM RMNET debug interface"
+	depends on MSM_RMNET
+	default n
+	help
+	  Debug stats on wakeup counts.
+
+
 config NETCONSOLE_DYNAMIC
 	bool "Dynamic reconfiguration of logging targets"
 	depends on NETCONSOLE && SYSFS
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 79bc9ca..a4fcb6a 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -289,6 +289,8 @@
 obj-$(CONFIG_FS_ENET) += fs_enet/
 
 obj-$(CONFIG_NETXEN_NIC) += netxen/
+
+obj-$(CONFIG_MSM_RMNET) += msm_rmnet.o
 obj-$(CONFIG_NIU) += niu.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_SFC) += sfc/
diff --git a/drivers/net/msm_rmnet.c b/drivers/net/msm_rmnet.c
new file mode 100644
index 0000000..8a8173a
--- /dev/null
+++ b/drivers/net/msm_rmnet.c
@@ -0,0 +1,466 @@
+/* linux/drivers/net/msm_rmnet.c
+ *
+ * Virtual Ethernet Interface for MSM7K Networking
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/wakelock.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#include <mach/msm_smd.h>
+
+/* XXX should come from smd headers */
+#define SMD_PORT_ETHER0 11
+#define POLL_DELAY 1000000 /* 1 second delay interval */
+
+struct rmnet_private
+{
+	smd_channel_t *ch;
+	struct net_device_stats stats;
+	const char *chname;
+	struct wake_lock wake_lock;
+#ifdef CONFIG_MSM_RMNET_DEBUG
+	ktime_t last_packet;
+	short active_countdown; /* Number of times left to check */
+	short restart_count; /* Number of polls seems so far */
+	unsigned long wakeups_xmit;
+	unsigned long wakeups_rcv;
+	unsigned long timeout_us;
+	unsigned long awake_time_ms;
+	struct delayed_work work;
+#endif
+};
+
+static int count_this_packet(void *_hdr, int len)
+{
+	struct ethhdr *hdr = _hdr;
+
+	if (len >= ETH_HLEN && hdr->h_proto == htons(ETH_P_ARP))
+		return 0;
+
+	return 1;
+}
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+static int in_suspend;
+static unsigned long timeout_us;
+static struct workqueue_struct *rmnet_wq;
+
+static void do_check_active(struct work_struct *work)
+{
+	struct rmnet_private *p =
+		container_of(work, struct rmnet_private, work.work);
+
+	/*
+	 * Soft timers do not wake the cpu from suspend.
+	 * If we are in suspend, do_check_active is only called once at the
+	 * timeout time instead of polling at POLL_DELAY interval. Otherwise the
+	 * cpu will sleeps and the timer can fire much much later than POLL_DELAY
+	 * casuing a skew in time calculations.
+	 */
+	if (in_suspend) {
+		/*
+		 * Assume for N packets sent durring this session, they are
+		 * uniformly distributed durring the timeout window.
+		 */
+		int tmp = p->timeout_us * 2 -
+			(p->timeout_us / (p->active_countdown + 1));
+		tmp /= 1000;
+		p->awake_time_ms += tmp;
+
+		p->active_countdown = p->restart_count = 0;
+		return;
+	}
+
+	/*
+	 * Poll if not in suspend, since this gives more accurate tracking of
+	 * rmnet sessions.
+	 */
+	p->restart_count++;
+	if (--p->active_countdown == 0) {
+		p->awake_time_ms += p->restart_count * POLL_DELAY / 1000;
+		p->restart_count = 0;
+	} else {
+		queue_delayed_work(rmnet_wq, &p->work,
+				usecs_to_jiffies(POLL_DELAY));
+	}
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+/*
+ * If early suspend is enabled then we specify two timeout values,
+ * screen on (default), and screen is off.
+ */
+static unsigned long timeout_suspend_us;
+static struct device *rmnet0;
+
+/* Set timeout in us when the screen is off. */
+static ssize_t timeout_suspend_store(struct device *d, struct device_attribute *attr, const char *buf, size_t n)
+{
+	timeout_suspend_us = simple_strtoul(buf, NULL, 10);
+	return n;
+}
+
+static ssize_t timeout_suspend_show(struct device *d,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return sprintf(buf, "%lu\n", (unsigned long) timeout_suspend_us);
+}
+
+static DEVICE_ATTR(timeout_suspend, 0664, timeout_suspend_show, timeout_suspend_store);
+
+static void rmnet_early_suspend(struct early_suspend *handler) {
+	if (rmnet0) {
+		struct rmnet_private *p = netdev_priv(to_net_dev(rmnet0));
+		p->timeout_us = timeout_suspend_us;
+	}
+	in_suspend = 1;
+}
+
+static void rmnet_late_resume(struct early_suspend *handler) {
+	if (rmnet0) {
+		struct rmnet_private *p = netdev_priv(to_net_dev(rmnet0));
+		p->timeout_us = timeout_us;
+	}
+	in_suspend = 0;
+}
+
+static struct early_suspend rmnet_power_suspend = {
+	.suspend = rmnet_early_suspend,
+	.resume = rmnet_late_resume,
+};
+
+static int __init rmnet_late_init(void)
+{
+	register_early_suspend(&rmnet_power_suspend);
+	return 0;
+}
+
+late_initcall(rmnet_late_init);
+#endif
+
+/* Returns 1 if packet caused rmnet to wakeup, 0 otherwise. */
+static int rmnet_cause_wakeup(struct rmnet_private *p) {
+	int ret = 0;
+	ktime_t now;
+	if (p->timeout_us == 0) /* Check if disabled */
+		return 0;
+
+	/* Start timer on a wakeup packet */
+	if (p->active_countdown == 0) {
+		ret = 1;
+		now = ktime_get_real();
+		p->last_packet = now;
+		if (in_suspend)
+			queue_delayed_work(rmnet_wq, &p->work,
+					usecs_to_jiffies(p->timeout_us));
+		else
+			queue_delayed_work(rmnet_wq, &p->work,
+					usecs_to_jiffies(POLL_DELAY));
+	}
+
+	if (in_suspend)
+		p->active_countdown++;
+	else
+		p->active_countdown = p->timeout_us / POLL_DELAY;
+
+	return ret;
+}
+
+static ssize_t wakeups_xmit_show(struct device *d,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct rmnet_private *p = netdev_priv(to_net_dev(d));
+	return sprintf(buf, "%lu\n", p->wakeups_xmit);
+}
+
+DEVICE_ATTR(wakeups_xmit, 0444, wakeups_xmit_show, NULL);
+
+static ssize_t wakeups_rcv_show(struct device *d, struct device_attribute *attr,
+		char *buf)
+{
+	struct rmnet_private *p = netdev_priv(to_net_dev(d));
+	return sprintf(buf, "%lu\n", p->wakeups_rcv);
+}
+
+DEVICE_ATTR(wakeups_rcv, 0444, wakeups_rcv_show, NULL);
+
+/* Set timeout in us. */
+static ssize_t timeout_store(struct device *d, struct device_attribute *attr,
+		const char *buf, size_t n)
+{
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	struct rmnet_private *p = netdev_priv(to_net_dev(d));
+	p->timeout_us = timeout_us = simple_strtoul(buf, NULL, 10);
+#else
+/* If using early suspend/resume hooks do not write the value on store. */
+	timeout_us = simple_strtoul(buf, NULL, 10);
+#endif
+	return n;
+}
+
+static ssize_t timeout_show(struct device *d, struct device_attribute *attr,
+			    char *buf)
+{
+	struct rmnet_private *p = netdev_priv(to_net_dev(d));
+	p = netdev_priv(to_net_dev(d));
+	return sprintf(buf, "%lu\n", timeout_us);
+}
+
+DEVICE_ATTR(timeout, 0664, timeout_show, timeout_store);
+
+/* Show total radio awake time in ms */
+static ssize_t awake_time_show(struct device *d, struct device_attribute *attr,
+				char *buf)
+{
+	struct rmnet_private *p = netdev_priv(to_net_dev(d));
+	return sprintf(buf, "%lu\n", p->awake_time_ms);
+}
+DEVICE_ATTR(awake_time_ms, 0444, awake_time_show, NULL);
+
+#endif
+
+/* Called in soft-irq context */
+static void smd_net_data_handler(unsigned long arg)
+{
+	struct net_device *dev = (struct net_device *) arg;
+	struct rmnet_private *p = netdev_priv(dev);
+	struct sk_buff *skb;
+	void *ptr = 0;
+	int sz;
+
+	for (;;) {
+		sz = smd_cur_packet_size(p->ch);
+		if (sz == 0) break;
+		if (smd_read_avail(p->ch) < sz) break;
+
+		if (sz > 1514) {
+			pr_err("rmnet_recv() discarding %d len\n", sz);
+			ptr = 0;
+		} else {
+			skb = dev_alloc_skb(sz + NET_IP_ALIGN);
+			if (skb == NULL) {
+				pr_err("rmnet_recv() cannot allocate skb\n");
+			} else {
+				skb->dev = dev;
+				skb_reserve(skb, NET_IP_ALIGN);
+				ptr = skb_put(skb, sz);
+				wake_lock_timeout(&p->wake_lock, HZ / 2);
+				if (smd_read(p->ch, ptr, sz) != sz) {
+					pr_err("rmnet_recv() smd lied about avail?!");
+					ptr = 0;
+					dev_kfree_skb_irq(skb);
+				} else {
+					skb->protocol = eth_type_trans(skb, dev);
+					if (count_this_packet(ptr, skb->len)) {
+#ifdef CONFIG_MSM_RMNET_DEBUG
+						p->wakeups_rcv +=
+							rmnet_cause_wakeup(p);
+#endif
+						p->stats.rx_packets++;
+						p->stats.rx_bytes += skb->len;
+					}
+					netif_rx(skb);
+				}
+				continue;
+			}
+		}
+		if (smd_read(p->ch, ptr, sz) != sz)
+			pr_err("rmnet_recv() smd lied about avail?!");
+	}
+}
+
+static DECLARE_TASKLET(smd_net_data_tasklet, smd_net_data_handler, 0);
+
+static void smd_net_notify(void *_dev, unsigned event)
+{
+	if (event != SMD_EVENT_DATA)
+		return;
+
+	smd_net_data_tasklet.data = (unsigned long) _dev;
+
+	tasklet_schedule(&smd_net_data_tasklet);
+}
+
+static int rmnet_open(struct net_device *dev)
+{
+	int r;
+	struct rmnet_private *p = netdev_priv(dev);
+
+	pr_info("rmnet_open()\n");
+	if (!p->ch) {
+		r = smd_open(p->chname, &p->ch, dev, smd_net_notify);
+
+		if (r < 0)
+			return -ENODEV;
+	}
+
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int rmnet_stop(struct net_device *dev)
+{
+	pr_info("rmnet_stop()\n");
+	netif_stop_queue(dev);
+	return 0;
+}
+
+static int rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct rmnet_private *p = netdev_priv(dev);
+	smd_channel_t *ch = p->ch;
+
+	if (smd_write_atomic(ch, skb->data, skb->len) != skb->len) {
+		pr_err("rmnet fifo full, dropping packet\n");
+	} else {
+		if (count_this_packet(skb->data, skb->len)) {
+			p->stats.tx_packets++;
+			p->stats.tx_bytes += skb->len;
+#ifdef CONFIG_MSM_RMNET_DEBUG
+			p->wakeups_xmit += rmnet_cause_wakeup(p);
+#endif
+		}
+	}
+
+	dev_kfree_skb_irq(skb);
+	return 0;
+}
+
+static struct net_device_stats *rmnet_get_stats(struct net_device *dev)
+{
+	struct rmnet_private *p = netdev_priv(dev);
+	return &p->stats;
+}
+
+static void rmnet_set_multicast_list(struct net_device *dev)
+{
+}
+
+static void rmnet_tx_timeout(struct net_device *dev)
+{
+	pr_info("rmnet_tx_timeout()\n");
+}
+
+static struct net_device_ops rmnet_ops = {
+	.ndo_open = rmnet_open,
+	.ndo_stop = rmnet_stop,
+	.ndo_start_xmit = rmnet_xmit,
+	.ndo_get_stats = rmnet_get_stats,
+	.ndo_set_multicast_list = rmnet_set_multicast_list,
+	.ndo_tx_timeout = rmnet_tx_timeout,
+};
+
+static void __init rmnet_setup(struct net_device *dev)
+{
+	dev->netdev_ops = &rmnet_ops;
+
+	dev->watchdog_timeo = 20; /* ??? */
+
+	ether_setup(dev);
+
+	//dev->change_mtu = 0; /* ??? */
+
+	random_ether_addr(dev->dev_addr);
+}
+
+
+static const char *ch_name[3] = {
+	"SMD_DATA5",
+	"SMD_DATA6",
+	"SMD_DATA7",
+};
+
+static int __init rmnet_init(void)
+{
+	int ret;
+	struct device *d;
+	struct net_device *dev;
+	struct rmnet_private *p;
+	unsigned n;
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+	timeout_us = 0;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	timeout_suspend_us = 0;
+#endif
+#endif
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+	rmnet_wq = create_workqueue("rmnet");
+#endif
+
+	for (n = 0; n < 3; n++) {
+		dev = alloc_netdev(sizeof(struct rmnet_private),
+				   "rmnet%d", rmnet_setup);
+
+		if (!dev)
+			return -ENOMEM;
+
+		d = &(dev->dev);
+		p = netdev_priv(dev);
+		p->chname = ch_name[n];
+		wake_lock_init(&p->wake_lock, WAKE_LOCK_SUSPEND, ch_name[n]);
+#ifdef CONFIG_MSM_RMNET_DEBUG
+		p->timeout_us = timeout_us;
+		p->awake_time_ms = p->wakeups_xmit = p->wakeups_rcv = 0;
+		p->active_countdown = p->restart_count = 0;
+		INIT_DELAYED_WORK_DEFERRABLE(&p->work, do_check_active);
+#endif
+
+		ret = register_netdev(dev);
+		if (ret) {
+			free_netdev(dev);
+			return ret;
+		}
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+		if (device_create_file(d, &dev_attr_timeout))
+			continue;
+		if (device_create_file(d, &dev_attr_wakeups_xmit))
+			continue;
+		if (device_create_file(d, &dev_attr_wakeups_rcv))
+			continue;
+		if (device_create_file(d, &dev_attr_awake_time_ms))
+			continue;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+		if (device_create_file(d, &dev_attr_timeout_suspend))
+			continue;
+
+		/* Only care about rmnet0 for suspend/resume tiemout hooks. */
+		if (n == 0)
+			rmnet0 = d;
+#endif
+#endif
+	}
+	return 0;
+}
+
+module_init(rmnet_init);
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 8d2772c..e42d463 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -322,6 +322,20 @@
 #define SMC_outsl(a, r, p, l)	writesl((a) + (r), p, l)
 #define SMC_IRQ_FLAGS		(-1)	/* from resource */
 
+#elif defined(CONFIG_ARCH_MSM)
+
+#define SMC_CAN_USE_8BIT	0
+#define SMC_CAN_USE_16BIT	1
+#define SMC_CAN_USE_32BIT	0
+#define SMC_NOWAIT		1
+
+#define SMC_inw(a, r)		readw((a) + (r))
+#define SMC_outw(v, a, r)	writew(v, (a) + (r))
+#define SMC_insw(a, r, p, l)	readsw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
+
+#define SMC_IRQ_FLAGS		IRQF_TRIGGER_HIGH
+
 #elif defined(CONFIG_MN10300)
 
 /*
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 8e9ba17..dff266b4 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -76,6 +76,12 @@
 	  Say Y here to enable support for the DS2782/DS2786 standalone battery
 	  gas-gauge.
 
+config BATTERY_DS2784
+	tristate "DS2784 battery driver "
+	select W1
+	help
+	  Say Y here to enable support for batteries with ds2784 chip.
+
 config BATTERY_PMU
 	tristate "Apple PMU battery"
 	depends on PPC32 && ADB_PMU
@@ -142,4 +148,10 @@
 	help
 	 Say Y to include support for NXP PCF50633 Main Battery Charger.
 
+config CHARGER_PM8058
+	bool "Qualcomm PM8058 pmic charger driver"
+	depends on PM8058
+	help
+	  Say Y to include support for the pm8058 charge controller
+
 endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 0005080..785ae2a 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -24,6 +24,7 @@
 
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_DS2782)	+= ds2782_battery.o
+obj-$(CONFIG_BATTERY_DS2784)	+= ds2784_battery.o
 obj-$(CONFIG_BATTERY_PMU)	+= pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)	+= olpc_battery.o
 obj-$(CONFIG_BATTERY_TOSA)	+= tosa_battery.o
@@ -34,3 +35,4 @@
 obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
 obj-$(CONFIG_CHARGER_PCF50633)	+= pcf50633-charger.o
+obj-$(CONFIG_CHARGER_PM8058)	+= pm8058-charger.o
diff --git a/drivers/power/ds2784_battery.c b/drivers/power/ds2784_battery.c
new file mode 100755
index 0000000..bc1b4d7
--- /dev/null
+++ b/drivers/power/ds2784_battery.c
@@ -0,0 +1,757 @@
+/* drivers/power/ds2784_battery.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/module.h>
+#include <linux/param.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <linux/android_alarm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/mutex.h>
+#include <linux/ds2784_battery.h>
+
+#include "../w1/w1.h"
+#include "w1_ds2784.h"
+
+extern int is_ac_power_supplied(void);
+
+struct battery_status {
+	int timestamp;
+
+	int voltage_uV;		/* units of uV */
+	int current_uA;		/* units of uA */
+	int current_avg_uA;
+	int charge_uAh;
+
+	u16 temp_C;		/* units of 0.1 C */
+
+	u8 percentage;		/* battery percentage */
+	u8 charge_source;
+	u8 status_reg;
+	u8 battery_full;	/* battery full (don't charge) */
+
+	u8 cooldown;		/* was overtemp */
+	u8 charge_mode;
+} __attribute__((packed));
+
+
+#define SOURCE_NONE	0
+#define SOURCE_USB	1
+#define SOURCE_AC	2
+
+#define CHARGE_OFF	0
+#define CHARGE_SLOW	1
+#define CHARGE_FAST	2
+#define CHARGE_BATT_DISABLE	3 /* disable charging at battery */
+
+#define TEMP_CRITICAL	600 /* no charging at all */
+#define TEMP_HOT	500 /* no fast charge, no charge > 4.1v */
+#define TEMP_WARM	450 /* no fast charge above this */
+
+#define TEMP_HOT_MAX_MV	4100 /* stop charging here when hot */
+#define TEMP_HOT_MIN_MV	3800 /* resume charging here when hot */
+#define CE_DISABLE_MIN_MV 4100
+
+#define BATTERY_LOG_MAX 1024
+#define BATTERY_LOG_MASK (BATTERY_LOG_MAX - 1)
+
+/* When we're awake or running on wall power, sample the battery
+ * gauge every FAST_POLL seconds.  If we're asleep and on battery
+ * power, sample every SLOW_POLL seconds
+ */
+#define FAST_POLL	(1 * 60)
+#define SLOW_POLL	(10 * 60)
+
+static DEFINE_MUTEX(battery_log_lock);
+static struct battery_status battery_log[BATTERY_LOG_MAX];
+static unsigned battery_log_head;
+static unsigned battery_log_tail;
+
+void battery_log_status(struct battery_status *s)
+{
+	unsigned n;
+	mutex_lock(&battery_log_lock);
+	n = battery_log_head;
+	memcpy(battery_log + n, s, sizeof(struct battery_status));
+	n = (n + 1) & BATTERY_LOG_MASK;
+	if (n == battery_log_tail)
+		battery_log_tail = (battery_log_tail + 1) & BATTERY_LOG_MASK;
+	battery_log_head = n;
+	mutex_unlock(&battery_log_lock);
+}
+
+static const char *battery_source[3] = { "none", " usb", "  ac" };
+static const char *battery_mode[4] = { " off", "slow", "fast", "full" };
+
+static int battery_log_print(struct seq_file *sf, void *private)
+{
+	unsigned n;
+	mutex_lock(&battery_log_lock);
+	seq_printf(sf, "timestamp    mV     mA avg mA      uAh   dC   %%   src  mode   reg full\n");
+	for (n = battery_log_tail; n != battery_log_head; n = (n + 1) & BATTERY_LOG_MASK) {
+		struct battery_status *s = battery_log + n;
+		seq_printf(sf, "%9d %5d %6d %6d %8d %4d %3d  %s  %s  0x%02x %d\n",
+			   s->timestamp, s->voltage_uV / 1000,
+			   s->current_uA / 1000, s->current_avg_uA / 1000,
+			   s->charge_uAh, s->temp_C,
+			   s->percentage,
+			   battery_source[s->charge_source],
+			   battery_mode[s->charge_mode],
+			   s->status_reg, s->battery_full);
+	}
+	mutex_unlock(&battery_log_lock);
+	return 0;
+}
+
+
+struct ds2784_device_info {
+	struct device *dev;
+
+	/* DS2784 data, valid after calling ds2784_battery_read_status() */
+	char raw[DS2784_DATA_SIZE];	/* raw DS2784 data */
+
+	struct battery_status status;
+
+	struct power_supply bat;
+	struct workqueue_struct *monitor_wqueue;
+	struct work_struct monitor_work;
+	struct alarm alarm;
+	struct wake_lock work_wake_lock;
+
+	int (*charge)(int on, int fast);
+	struct w1_slave *w1_slave;
+
+	u8 dummy; /* dummy battery flag */
+	u8 last_charge_mode; /* previous charger state */
+	u8 slow_poll;
+
+	ktime_t last_poll;
+	ktime_t last_charge_seen;
+};
+
+#define psy_to_dev_info(x) container_of((x), struct ds2784_device_info, bat)
+
+static struct wake_lock vbus_wake_lock;
+
+#define BATT_RSNSP			(67)	/*Passion battery source 1*/
+
+static enum power_supply_property battery_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	POWER_SUPPLY_PROP_CHARGE_COUNTER,
+};
+
+static int battery_initial;
+
+static int battery_get_property(struct power_supply *psy,
+				    enum power_supply_property psp,
+				    union power_supply_propval *val);
+
+static void battery_ext_power_changed(struct power_supply *psy);
+
+#define to_ds2784_device_info(x) container_of((x), struct ds2784_device_info, \
+					      bat);
+
+static void ds2784_parse_data(u8 *raw, struct battery_status *s)
+{
+	short n;
+
+	/* Get status reg */
+	s->status_reg = raw[DS2784_REG_STS];
+
+	/* Get Level */
+	s->percentage = raw[DS2784_REG_RARC];
+
+	/* Get Voltage: Unit=4.886mV, range is 0V to 4.99V */
+	n = (((raw[DS2784_REG_VOLT_MSB] << 8) |
+	      (raw[DS2784_REG_VOLT_LSB])) >> 5);
+
+	s->voltage_uV = n * 4886;
+
+	/* Get Current: Unit= 1.5625uV x Rsnsp(67)=104.68 */
+	n = ((raw[DS2784_REG_CURR_MSB]) << 8) |
+		raw[DS2784_REG_CURR_LSB];
+	s->current_uA = ((n * 15625) / 10000) * 67;
+
+	n = ((raw[DS2784_REG_AVG_CURR_MSB]) << 8) |
+		raw[DS2784_REG_AVG_CURR_LSB];
+	s->current_avg_uA = ((n * 15625) / 10000) * 67;
+
+	/* Get Temperature:
+	 * 11 bit signed result in Unit=0.125 degree C.
+	 * Convert to integer tenths of degree C.
+	 */
+	n = ((raw[DS2784_REG_TEMP_MSB] << 8) |
+		(raw[DS2784_REG_TEMP_LSB])) >> 5;
+
+	s->temp_C = (n * 10) / 8;
+
+	/* RAAC is in units of 1.6mAh */
+	s->charge_uAh = ((raw[DS2784_REG_RAAC_MSB] << 8) |
+			  raw[DS2784_REG_RAAC_LSB]) * 1600;
+}
+
+static int w1_ds2784_io(struct w1_slave *sl, char *buf, int addr, size_t count, int io)
+{
+	if (!sl)
+		return 0;
+
+	mutex_lock(&sl->master->mutex);
+
+	if (addr > DS2784_DATA_SIZE || addr < 0) {
+		count = 0;
+		goto out;
+	}
+	if (addr + count > DS2784_DATA_SIZE)
+		count = DS2784_DATA_SIZE - addr;
+
+	if (!w1_reset_select_slave(sl)) {
+		if (!io) {
+			w1_write_8(sl->master, W1_DS2784_READ_DATA);
+			w1_write_8(sl->master, addr);
+			count = w1_read_block(sl->master, buf, count);
+		} else {
+			w1_write_8(sl->master, W1_DS2784_WRITE_DATA);
+			w1_write_8(sl->master, addr);
+			w1_write_block(sl->master, buf, count);
+			/* XXX w1_write_block returns void, not n_written */
+		}
+	}
+
+out:
+	mutex_unlock(&sl->master->mutex);
+
+	return count;
+}
+
+static int w1_ds2784_read(struct w1_slave *sl, char *buf, int addr, size_t count)
+{
+	return w1_ds2784_io(sl, buf, addr, count, 0);
+}
+
+static int w1_ds2784_write(struct w1_slave *sl, char *buf, int addr, size_t count)
+{
+	return w1_ds2784_io(sl, buf, addr, count, 1);
+}
+
+static int ds2784_set_cc(struct ds2784_device_info *di, bool enable)
+{
+	int ret;
+
+	if (enable)
+		di->raw[DS2784_REG_PORT] |= 0x02;
+	else
+		di->raw[DS2784_REG_PORT] &= ~0x02;
+	ret = w1_ds2784_write(di->w1_slave, di->raw + DS2784_REG_PORT,
+			      DS2784_REG_PORT, 1);
+	if (ret != 1) {
+		dev_warn(di->dev, "call to w1_ds2784_write failed (0x%p)\n",
+			 di->w1_slave);
+		return 1;
+	}
+	return 0;
+}
+
+static int ds2784_battery_read_status(struct ds2784_device_info *di)
+{
+	int ret, start, count;
+
+	/* The first time we read the entire contents of SRAM/EEPROM,
+	 * but after that we just read the interesting bits that change. */
+	if (di->raw[DS2784_REG_RSNSP] == 0x00) {
+		start = 0;
+		count = DS2784_DATA_SIZE;
+	} else {
+		start = DS2784_REG_PORT;
+		count = DS2784_REG_CURR_LSB - start + 1;
+	}
+
+	ret = w1_ds2784_read(di->w1_slave, di->raw + start, start, count);
+	if (ret != count) {
+		dev_warn(di->dev, "call to w1_ds2784_read failed (0x%p)\n",
+			di->w1_slave);
+		return 1;
+	}
+
+	if (battery_initial == 0) {
+		if (!memcmp(di->raw + 0x20, "DUMMY!", 6)) {
+			unsigned char acr[2];
+
+			di->dummy = 1;
+			pr_info("batt: dummy battery detected\n");
+
+			/* reset ACC register to ~500mAh, since it may have zeroed out */
+			acr[0] = 0x05;
+			acr[1] = 0x06;
+			w1_ds2784_write(di->w1_slave, acr, DS2784_REG_ACCUMULATE_CURR_MSB, 2);
+		}
+		battery_initial = 1;
+	}
+
+	ds2784_parse_data(di->raw, &di->status);
+
+	pr_info("batt: %3d%%, %d mV, %d mA (%d avg), %d.%d C, %d mAh\n",
+		di->status.percentage,
+		di->status.voltage_uV / 1000, di->status.current_uA / 1000,
+		di->status.current_avg_uA / 1000,
+		di->status.temp_C / 10, di->status.temp_C % 10,
+		di->status.charge_uAh / 1000);
+
+	return 0;
+}
+
+static int battery_get_property(struct power_supply *psy,
+				    enum power_supply_property psp,
+				    union power_supply_propval *val)
+{
+	struct ds2784_device_info *di = psy_to_dev_info(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		switch (di->status.charge_source) {
+		case CHARGE_OFF:
+			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+			break;
+		case CHARGE_FAST:
+		case CHARGE_SLOW:
+			if (di->status.battery_full)
+				val->intval = POWER_SUPPLY_STATUS_FULL;
+			else if (di->status.charge_mode == CHARGE_OFF ||
+				 di->status.charge_mode == CHARGE_BATT_DISABLE)
+				val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+			else
+				val->intval = POWER_SUPPLY_STATUS_CHARGING;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+			break;
+		}
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		if (di->status.temp_C >= TEMP_HOT)
+			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		else
+			val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		/* XXX todo */
+		val->intval = 1;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		if (di->dummy)
+			val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+		else
+			val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		if (di->dummy)
+			val->intval = 75;
+		else
+			val->intval = di->status.percentage;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = di->status.voltage_uV;
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = di->status.temp_C;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = di->status.current_uA;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		val->intval = di->status.current_avg_uA;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+		val->intval = di->status.charge_uAh;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ds2784_battery_update_status(struct ds2784_device_info *di)
+{
+	u8 last_level;
+	last_level = di->status.percentage;
+
+	ds2784_battery_read_status(di);
+
+	if ((last_level != di->status.percentage) || (di->status.temp_C > 450))
+		power_supply_changed(&di->bat);
+}
+
+static DEFINE_MUTEX(charge_state_lock);
+
+static bool check_timeout(ktime_t now, ktime_t last, int seconds)
+{
+	ktime_t timeout = ktime_add(last, ktime_set(seconds, 0));
+	return ktime_sub(timeout, now).tv64 < 0;
+}
+
+static int battery_adjust_charge_state(struct ds2784_device_info *di)
+{
+	unsigned source;
+	int rc = 0;
+	int temp, volt;
+	u8 charge_mode;
+	bool charge_timeout = false;
+
+	mutex_lock(&charge_state_lock);
+
+	temp = di->status.temp_C;
+	volt = di->status.voltage_uV / 1000;
+
+	source = di->status.charge_source;
+
+	/* initially our charge mode matches our source:
+	 * NONE:OFF, USB:SLOW, AC:FAST
+	 */
+	charge_mode = source;
+
+	/* shut off charger when full:
+	 * - CHGTF flag is set
+	 */
+	if (di->status.status_reg & 0x80) {
+		di->status.battery_full = 1;
+		charge_mode = CHARGE_BATT_DISABLE;
+	} else
+		di->status.battery_full = 0;
+
+	if (temp >= TEMP_HOT) {
+		if (temp >= TEMP_CRITICAL)
+			charge_mode = CHARGE_BATT_DISABLE;
+
+		/* once we charge to max voltage when hot, disable
+		 * charging until the temp drops or the voltage drops
+		 */
+		if (volt >= TEMP_HOT_MAX_MV)
+			di->status.cooldown = 1;
+	}
+
+	/* when the battery is warm, only charge in slow charge mode */
+	if ((temp >= TEMP_WARM) && (charge_mode == CHARGE_FAST))
+		charge_mode = CHARGE_SLOW;
+
+	if (di->status.cooldown) {
+		if ((temp < TEMP_WARM) || (volt <= TEMP_HOT_MIN_MV))
+			di->status.cooldown = 0;
+		else
+			charge_mode = CHARGE_BATT_DISABLE;
+	}
+
+	if (di->status.current_uA > 1024)
+		di->last_charge_seen = di->last_poll;
+	else if (di->last_charge_mode != CHARGE_OFF &&
+		 check_timeout(di->last_poll, di->last_charge_seen, 60 * 60)) {
+		if (di->last_charge_mode == CHARGE_BATT_DISABLE) {
+			/* The charger is only powering the phone. Toggle the
+			 * enable line periodically to prevent auto shutdown.
+			 */
+			di->last_charge_seen = di->last_poll;
+			pr_info("batt: charging POKE CHARGER\n");
+			di->charge(0, 0);
+			udelay(10);
+			di->charge(1, source == CHARGE_FAST);
+		} else {
+			/* The charger has probably stopped charging. Turn it
+			 * off until the next sample period.
+			 */
+			charge_timeout = true;
+			charge_mode = CHARGE_OFF;
+		}
+	}
+
+	if (source == CHARGE_OFF)
+		charge_mode = CHARGE_OFF;
+
+	/* Don't use CHARGE_BATT_DISABLE unless the voltage is high since the
+	 * voltage drop over the discharge-path diode can cause a shutdown.
+	 */
+	if (charge_mode == CHARGE_BATT_DISABLE && volt < CE_DISABLE_MIN_MV)
+		charge_mode = CHARGE_OFF;
+
+	if (di->last_charge_mode == charge_mode)
+		goto done;
+
+	di->last_charge_mode = charge_mode;
+	di->status.charge_mode = charge_mode;
+
+	switch (charge_mode) {
+	case CHARGE_OFF:
+		di->charge(0, 0);
+		ds2784_set_cc(di, true);
+		if (temp >= TEMP_CRITICAL)
+			pr_info("batt: charging OFF [OVERTEMP]\n");
+		else if (di->status.cooldown)
+			pr_info("batt: charging OFF [COOLDOWN]\n");
+		else if (di->status.battery_full)
+			pr_info("batt: charging OFF [FULL]\n");
+		else if (charge_timeout)
+			pr_info("batt: charging OFF [TIMEOUT]\n");
+		else
+			pr_info("batt: charging OFF\n");
+		break;
+	case CHARGE_BATT_DISABLE:
+		di->last_charge_seen = di->last_poll;
+		ds2784_set_cc(di, false);
+		di->charge(1, source == CHARGE_FAST);
+		if (temp >= TEMP_CRITICAL)
+			pr_info("batt: charging BATTOFF [OVERTEMP]\n");
+		else if (di->status.cooldown)
+			pr_info("batt: charging BATTOFF [COOLDOWN]\n");
+		else if (di->status.battery_full)
+			pr_info("batt: charging BATTOFF [FULL]\n");
+		else
+			pr_info("batt: charging BATTOFF [UNKNOWN]\n");
+		break;
+	case CHARGE_SLOW:
+		di->last_charge_seen = di->last_poll;
+		ds2784_set_cc(di, true);
+		di->charge(1, 0);
+		pr_info("batt: charging SLOW\n");
+		break;
+	case CHARGE_FAST:
+		di->last_charge_seen = di->last_poll;
+		ds2784_set_cc(di, true);
+		di->charge(1, 1);
+		pr_info("batt: charging FAST\n");
+		break;
+	}
+	rc = 1;
+done:
+	mutex_unlock(&charge_state_lock);
+	return rc;
+}
+
+static void ds2784_program_alarm(struct ds2784_device_info *di, int seconds)
+{
+	ktime_t low_interval = ktime_set(seconds - 10, 0);
+	ktime_t slack = ktime_set(20, 0);
+	ktime_t next;
+
+	next = ktime_add(di->last_poll, low_interval);
+
+	alarm_start_range(&di->alarm, next, ktime_add(next, slack));
+}
+
+static void ds2784_battery_work(struct work_struct *work)
+{
+	struct ds2784_device_info *di =
+		container_of(work, struct ds2784_device_info, monitor_work);
+	struct timespec ts;
+	unsigned long flags;
+
+	ds2784_battery_update_status(di);
+
+	di->last_poll = alarm_get_elapsed_realtime();
+
+	if (battery_adjust_charge_state(di))
+		power_supply_changed(&di->bat);
+
+	ts = ktime_to_timespec(di->last_poll);
+	di->status.timestamp = ts.tv_sec;
+	battery_log_status(&di->status);
+
+	/* prevent suspend before starting the alarm */
+	local_irq_save(flags);
+	wake_unlock(&di->work_wake_lock);
+	ds2784_program_alarm(di, FAST_POLL);
+	local_irq_restore(flags);
+}
+
+static void ds2784_battery_alarm(struct alarm *alarm)
+{
+	struct ds2784_device_info *di =
+		container_of(alarm, struct ds2784_device_info, alarm);
+	wake_lock(&di->work_wake_lock);
+	queue_work(di->monitor_wqueue, &di->monitor_work);
+}
+
+static void battery_ext_power_changed(struct power_supply *psy)
+{
+	struct ds2784_device_info *di;
+	int got_power;
+
+	di = psy_to_dev_info(psy);
+	got_power = power_supply_am_i_supplied(psy);
+
+	if (got_power) {
+		if (is_ac_power_supplied())
+			di->status.charge_source = SOURCE_AC;
+		else
+			di->status.charge_source = SOURCE_USB;
+		wake_lock(&vbus_wake_lock);
+	} else {
+		di->status.charge_source = SOURCE_NONE;
+		/* give userspace some time to see the uevent and update
+		 * LED state or whatnot...
+		 */
+		wake_lock_timeout(&vbus_wake_lock, HZ / 2);
+	}
+	battery_adjust_charge_state(di);
+	power_supply_changed(psy);
+}
+
+static int ds2784_battery_probe(struct platform_device *pdev)
+{
+	int rc;
+	struct ds2784_device_info *di;
+	struct ds2784_platform_data *pdata;
+
+	di = kzalloc(sizeof(*di), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, di);
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata || !pdata->charge || !pdata->w1_slave) {
+		pr_err("%s: pdata missing or invalid\n", __func__);
+		rc = -EINVAL;
+		goto fail_register;
+	}
+
+	di->charge = pdata->charge;
+	di->w1_slave = pdata->w1_slave;
+
+	di->dev = &pdev->dev;
+
+	di->bat.name = "battery";
+	di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->bat.properties = battery_properties;
+	di->bat.num_properties = ARRAY_SIZE(battery_properties);
+	di->bat.external_power_changed = battery_ext_power_changed;
+	di->bat.get_property = battery_get_property;
+	di->last_charge_mode = 0xff;
+
+	rc = power_supply_register(&pdev->dev, &di->bat);
+	if (rc)
+		goto fail_register;
+
+	INIT_WORK(&di->monitor_work, ds2784_battery_work);
+	di->monitor_wqueue = create_freezeable_workqueue(dev_name(&pdev->dev));
+
+	/* init to something sane */
+	di->last_poll = alarm_get_elapsed_realtime();
+
+	if (!di->monitor_wqueue) {
+		rc = -ESRCH;
+		goto fail_workqueue;
+	}
+	wake_lock_init(&di->work_wake_lock, WAKE_LOCK_SUSPEND,
+			"ds2784-battery");
+	alarm_init(&di->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+			ds2784_battery_alarm);
+	wake_lock(&di->work_wake_lock);
+	queue_work(di->monitor_wqueue, &di->monitor_work);
+	return 0;
+
+fail_workqueue:
+	power_supply_unregister(&di->bat);
+fail_register:
+	kfree(di);
+	return rc;
+}
+
+static int ds2784_suspend(struct device *dev)
+{
+	struct ds2784_device_info *di = dev_get_drvdata(dev);
+
+	/* If we are on battery, reduce our update rate until
+	 * we next resume.
+	 */
+	if (di->status.charge_source == SOURCE_NONE) {
+		ds2784_program_alarm(di, SLOW_POLL);
+		di->slow_poll = 1;
+	}
+	return 0;
+}
+
+static int ds2784_resume(struct device *dev)
+{
+	struct ds2784_device_info *di = dev_get_drvdata(dev);
+
+	/* We might be on a slow sample cycle.  If we're
+	 * resuming we should resample the battery state
+	 * if it's been over a minute since we last did
+	 * so, and move back to sampling every minute until
+	 * we suspend again.
+	 */
+	if (di->slow_poll) {
+		ds2784_program_alarm(di, FAST_POLL);
+		di->slow_poll = 0;
+	}
+	return 0;
+}
+
+static struct dev_pm_ops ds2784_pm_ops = {
+	.suspend	= ds2784_suspend,
+	.resume		= ds2784_resume,
+};
+
+static struct platform_driver ds2784_battery_driver = {
+	.driver = {
+		.name = "ds2784-battery",
+		.pm = &ds2784_pm_ops,
+	},
+	.probe = ds2784_battery_probe,
+};
+
+static int battery_log_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, battery_log_print, NULL);
+}
+
+static struct file_operations battery_log_fops = {
+	.open = battery_log_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int __init ds2784_battery_init(void)
+{
+	debugfs_create_file("battery_log", 0444, NULL, NULL, &battery_log_fops);
+	wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
+	return platform_driver_register(&ds2784_battery_driver);
+}
+
+module_init(ds2784_battery_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Justin Lin <Justin_lin@htc.com>");
+MODULE_DESCRIPTION("ds2784 battery driver");
diff --git a/drivers/power/pm8058-charger.c b/drivers/power/pm8058-charger.c
new file mode 100644
index 0000000..0642274
--- /dev/null
+++ b/drivers/power/pm8058-charger.c
@@ -0,0 +1,320 @@
+/*
+ * 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/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/pm8058.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+
+struct pm8058_charger {
+	struct device				*pmic_dev;
+	int					chgval_irq;
+	int					fastchg_irq;
+
+	struct power_supply			ac_supply;
+	struct power_supply			usb_supply;
+
+	struct pm8058_charger_platform_data	*pdata;
+
+	spinlock_t				lock;
+	bool					can_charge;
+	bool					is_ac;
+	bool					is_online;
+	bool					vbus_present;
+	int					charge_type;
+	u32					max_current;
+};
+
+static struct pm8058_charger *the_pm8058_charger;
+
+/* TODO: the usb core driver should provide the maximum current draw value to us
+ * for charging */
+
+void pm8058_notify_charger_connected(int status)
+{
+	struct pm8058_charger *charger = the_pm8058_charger;
+	u32 max_current = 0;
+	bool is_ac;
+	bool is_online;
+	bool change = false;
+	unsigned long flags;
+
+	if (!charger)
+		return;
+
+	printk("### %s(%d) ###\n", __func__, status);
+	if (status && !charger->vbus_present)
+		pr_warning("%s: cable status mismatch %d %d\n", __func__,
+			   status, charger->vbus_present);
+
+	switch (status) {
+	case 1:
+		/* usb (pc) charging */
+		max_current = 500;
+		is_ac = false;
+		is_online = true;
+		break;
+	case 2:
+		/* wall charger */
+		max_current = 1500;
+		is_ac = true;
+		is_online = true;
+		break;
+	case 0:
+	default:
+		/* disable charging */
+		max_current = 0;
+		is_ac = false;
+		is_online = false;
+		break;
+	}
+	spin_lock_irqsave(&charger->lock, flags);
+	if (max_current != charger->max_current ||
+	    is_ac != charger->is_ac || is_online != charger->is_online) {
+		charger->max_current = max_current;
+		charger->is_ac = is_ac;
+		charger->is_online = is_online;
+		change = true;
+	}
+	spin_unlock_irqrestore(&charger->lock, flags);
+	/* for now, charge control is done on the modem side, so we have to
+	 * delegate to the board file. Eventually, all charge control will
+	 * be done in this driver */
+	if (change && charger->pdata->charge)
+		charger->pdata->charge(max_current, is_ac);
+
+	power_supply_changed(&charger->ac_supply);
+	power_supply_changed(&charger->usb_supply);
+}
+EXPORT_SYMBOL_GPL(pm8058_notify_charger_connected);
+
+static void check_chgval(struct pm8058_charger *charger)
+{
+	int ret;
+	unsigned long flags;
+
+	ret = pm8058_irq_get_status(charger->pmic_dev, PM8058_CHGVAL_IRQ);
+	if (ret >= 0) {
+		spin_lock_irqsave(&charger->lock, flags);
+		charger->vbus_present = !!ret;
+		spin_unlock_irqrestore(&charger->lock, flags);
+		charger->pdata->vbus_present(ret);
+	} else {
+		pr_err("%s: can't read status!! ignoring event?!\n", __func__);
+	}
+}
+
+static irqreturn_t chgval_irq_handler(int irq, void *dev_id)
+{
+	struct pm8058_charger *charger = dev_id;
+
+	check_chgval(charger);
+	return IRQ_HANDLED;
+}
+
+/* should only get this irq when we are plugged in */
+static irqreturn_t fastchg_irq_handler(int irq, void *dev_id)
+{
+	struct pm8058_charger *charger = dev_id;
+	int ret;
+	bool fast_charging;
+	unsigned long flags;
+
+	ret = pm8058_irq_get_status(charger->pmic_dev, PM8058_FASTCHG_IRQ);
+	if (ret < 0)
+		return IRQ_HANDLED;
+	fast_charging = !!ret;
+
+	spin_lock_irqsave(&charger->lock, flags);
+	if (fast_charging) {
+		if (!charger->vbus_present) {
+			pr_err("%s: charging without vbus?!\n", __func__);
+			goto done;
+		}
+		charger->charge_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
+	} else {
+		/* charging is either stopped (done/overtemp/etc.), or we
+		 * are trickle charging. */
+		/* TODO: detect trickle charging mode */
+		if (charger->is_online)
+			charger->charge_type = POWER_SUPPLY_CHARGE_TYPE_NONE;
+		else
+			charger->charge_type = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+	}
+
+done:
+	spin_unlock_irqrestore(&charger->lock, flags);
+
+	power_supply_changed(&charger->ac_supply);
+	power_supply_changed(&charger->usb_supply);
+	return IRQ_HANDLED;
+}
+
+static int power_get_property(struct power_supply *psy,
+			      enum power_supply_property psp,
+			      union power_supply_propval *val)
+{
+	struct pm8058_charger *charger;
+
+	if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+		charger = container_of(psy, struct pm8058_charger, ac_supply);
+	else
+		charger = container_of(psy, struct pm8058_charger, usb_supply);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+			val->intval = charger->is_online && charger->is_ac;
+		else
+			val->intval = charger->is_online && !charger->is_ac;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		/* for now, fake fast charge all the time if we're on */
+		if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+			val->intval = charger->is_ac ? charger->charge_type :
+				POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+		else
+			val->intval = charger->is_online && !charger->is_ac ?
+				charger->charge_type :
+				POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static enum power_supply_property power_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+};
+
+static int __init pm8058_charger_probe(struct platform_device *pdev)
+{
+	struct pm8058_charger_platform_data *pdata = pdev->dev.platform_data;
+	struct pm8058_charger *charger;
+	int chgval_irq;
+	int fastchg_irq;
+	int ret;
+
+	chgval_irq = platform_get_irq_byname(pdev, "chgval_irq");
+	fastchg_irq = platform_get_irq_byname(pdev, "fastchg_irq");
+
+	if (!pdata || chgval_irq < 0 || fastchg_irq < 0) {
+		pr_err("%s: missing platform data/resources\n", __func__);
+		return -EINVAL;
+	}
+
+	charger = kzalloc(sizeof(struct pm8058_charger), GFP_KERNEL);
+	if (!charger) {
+		pr_err("%s: can't alloc mem for charger struct\n", __func__);
+		return -ENOMEM;
+	}
+
+	charger->pmic_dev = pdev->dev.parent;
+	charger->pdata = pdata;
+	platform_set_drvdata(pdev, charger);
+	spin_lock_init(&charger->lock);
+
+	the_pm8058_charger = charger;
+
+	charger->ac_supply.name = "ac";
+	charger->ac_supply.type = POWER_SUPPLY_TYPE_MAINS;
+	charger->ac_supply.supplied_to = pdata->supplied_to;
+	charger->ac_supply.num_supplicants = pdata->num_supplicants;
+	charger->ac_supply.properties = power_properties;
+	charger->ac_supply.num_properties = ARRAY_SIZE(power_properties);
+	charger->ac_supply.get_property = power_get_property;
+
+	charger->usb_supply.name = "usb";
+	charger->usb_supply.type = POWER_SUPPLY_TYPE_USB;
+	charger->usb_supply.supplied_to = pdata->supplied_to;
+	charger->usb_supply.num_supplicants = pdata->num_supplicants;
+	charger->usb_supply.properties = power_properties;
+	charger->usb_supply.num_properties = ARRAY_SIZE(power_properties);
+	charger->usb_supply.get_property = power_get_property;
+
+	ret = power_supply_register(&pdev->dev, &charger->ac_supply);
+	if (ret)
+		goto err_reg_ac_supply;
+	ret = power_supply_register(&pdev->dev, &charger->usb_supply);
+	if (ret)
+		goto err_reg_usb_supply;
+
+	ret = request_threaded_irq(chgval_irq, NULL, chgval_irq_handler,
+				   IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+				   "pm8058-charger-valid", charger);
+	if (ret) {
+		pr_err("%s: can't request chgval_irq\n", __func__);
+		goto err_req_chgval_irq;
+	}
+	charger->chgval_irq = chgval_irq;
+
+	ret = request_threaded_irq(fastchg_irq, NULL, fastchg_irq_handler,
+				   IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+				   "pm8058-charger-fastchg", charger);
+	if (ret) {
+		pr_err("%s: can't request stuck\n", __func__);
+		goto err_req_fastchg_irq;
+	}
+	charger->fastchg_irq = fastchg_irq;
+	enable_irq_wake(charger->chgval_irq);
+
+	pr_info("%s: driver initialized\n", __func__);
+	check_chgval(charger);
+
+	return 0;
+
+err_req_fastchg_irq:
+	free_irq(chgval_irq, charger);
+err_req_chgval_irq:
+	power_supply_unregister(&charger->usb_supply);
+err_reg_usb_supply:
+	power_supply_unregister(&charger->ac_supply);
+err_reg_ac_supply:
+	platform_set_drvdata(pdev, NULL);
+	the_pm8058_charger = NULL;
+	kfree(charger);
+	return ret;
+}
+
+static struct platform_driver pm8058_charger_driver = {
+	.probe	= pm8058_charger_probe,
+	.driver	= {
+		.name	= "pm8058-charger",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init pm8058_charger_init(void)
+{
+	return platform_driver_register(&pm8058_charger_driver);
+}
+
+module_init(pm8058_charger_init);
+MODULE_DESCRIPTION("PM8058 Charger Driver");
+MODULE_AUTHOR("Dima Zavin <dima@android.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/power/w1_ds2784.h b/drivers/power/w1_ds2784.h
new file mode 100644
index 0000000..6822fc0
--- /dev/null
+++ b/drivers/power/w1_ds2784.h
@@ -0,0 +1,132 @@
+/* drivers/w1/slaves/w1_ds2784.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef __w1_ds2784_h__
+#define __w1_ds2784_h__
+
+
+/* Known commands to the DS2784 chip */
+#define W1_DS2784_SWAP			0xAA
+#define W1_DS2784_READ_DATA		0x69
+#define W1_DS2784_WRITE_DATA		0x6C
+#define W1_DS2784_COPY_DATA		0x48
+#define W1_DS2784_RECALL_DATA		0xB8
+#define W1_DS2784_LOCK			0x6A
+
+/* Number of valid register addresses */
+#define DS2784_DATA_SIZE		0x80
+
+#define DS2784_EEPROM_BLOCK0		0x20
+#define DS2784_ACTIVE_FULL		0x20
+#define DS2784_EEPROM_BLOCK1		0x30
+#define DS2784_RATED_CAPACITY		0x32
+#define DS2784_CURRENT_OFFSET_BIAS	0x33
+#define DS2784_ACTIVE_EMPTY		0x3b
+
+/**
+ * The DS2482 registers - there are 3 registers that are addressed by a read
+ * pointer. The read pointer is set by the last command executed.
+ *
+ * To read the data, issue a register read for any address
+ */
+#define DS2482_CMD_RESET		0xF0	/* No param */
+#define DS2482_CMD_SET_READ_PTR		0xE1	/* Param: DS2482_PTR_CODE_xxx */
+#define DS2482_CMD_CHANNEL_SELECT	0xC3
+#define DS2482_CMD_WRITE_CONFIG		0xD2	/* Param: Config byte */
+#define DS2482_CMD_1WIRE_RESET		0xB4	/* Param: None */
+#define DS2482_CMD_1WIRE_SINGLE_BIT	0x87	/* Param: Bit byte (bit7) */
+#define DS2482_CMD_1WIRE_WRITE_BYTE	0xA5	/* Param: Data byte */
+#define DS2482_CMD_1WIRE_READ_BYTE	0x96	/* Param: None */
+/* Note to read the byte, Set the ReadPtr to Data then read (any addr) */
+#define DS2482_CMD_1WIRE_TRIPLET	0x78	/* Param: Dir byte (bit7) */
+
+/* Values for DS2482_CMD_SET_READ_PTR */
+#define DS2482_PTR_CODE_STATUS		0xF0
+#define DS2482_PTR_CODE_DATA		0xE1
+#define DS2482_PTR_CODE_CHANNEL		0xD2	/* DS2482-800 only */
+#define DS2482_PTR_CODE_CONFIG		0xC3
+
+/*
+DS2784 1-wire slave memory map definitions
+*/
+#define DS2784_REG_PORT			0x00
+#define DS2784_REG_STS			0x01
+#define DS2784_REG_RAAC_MSB		0x02
+#define DS2784_REG_RAAC_LSB		0x03
+#define DS2784_REG_RSAC_MSB		0x04
+#define DS2784_REG_RSAC_LSB		0x05
+#define DS2784_REG_RARC			0x06
+#define DS2784_REG_RSRC			0x07
+#define DS2784_REG_AVG_CURR_MSB		0x08
+#define DS2784_REG_AVG_CURR_LSB		0x09
+#define DS2784_REG_TEMP_MSB		0x0A
+#define DS2784_REG_TEMP_LSB		0x0B
+#define DS2784_REG_VOLT_MSB		0x0C
+#define DS2784_REG_VOLT_LSB		0x0D
+#define DS2784_REG_CURR_MSB		0x0E
+#define DS2784_REG_CURR_LSB		0x0F
+#define DS2784_REG_ACCUMULATE_CURR_MSB	0x10
+#define DS2784_REG_ACCUMULATE_CURR_LSB	0x11
+#define DS2784_REG_ACCUMULATE_CURR_LSB1	0x12
+#define DS2784_REG_ACCUMULATE_CURR_LSB2	0x13
+#define DS2784_REG_AGE_SCALAR		0x14
+#define DS2784_REG_SPECIALL_FEATURE	0x15
+#define DS2784_REG_FULL_MSB		0x16
+#define DS2784_REG_FULL_LSB		0x17
+#define DS2784_REG_ACTIVE_EMPTY_MSB	0x18
+#define DS2784_REG_ACTIVE_EMPTY_LSB	0x19
+#define DS2784_REG_STBY_EMPTY_MSB	0x1A
+#define DS2784_REG_STBY_EMPTY_LSB	0x1B
+#define DS2784_REG_EEPROM		0x1F
+#define DS2784_REG_MFG_GAIN_RSGAIN_MSB	0xB0
+#define DS2784_REG_MFG_GAIN_RSGAIN_LSB	0xB1
+
+#define DS2784_REG_CTRL			0x60
+#define DS2784_REG_ACCUMULATE_BIAS	0x61
+#define DS2784_REG_AGE_CAPA_MSB		0x62
+#define DS2784_REG_AGE_CAPA_LSB		0x63
+#define DS2784_REG_CHARGE_VOLT		0x64
+#define DS2784_REG_MIN_CHARGE_CURR	0x65
+#define DS2784_REG_ACTIVE_EMPTY_VOLT	0x66
+#define DS2784_REG_ACTIVE_EMPTY_CURR	0x67
+#define DS2784_REG_ACTIVE_EMPTY_40	0x68
+#define DS2784_REG_RSNSP		0x69
+#define DS2784_REG_FULL_40_MSB		0x6A
+#define DS2784_REG_FULL_40_LSB		0x6B
+#define DS2784_REG_FULL_SEG_4_SLOPE	0x6C
+#define DS2784_REG_FULL_SEG_3_SLOPE	0x6D
+#define DS2784_REG_FULL_SEG_2_SLOPE	0x6E
+#define DS2784_REG_FULL_SEG_1_SLOPE	0x6F
+#define DS2784_REG_AE_SEG_4_SLOPE	0x70
+#define DS2784_REG_AE_SEG_3_SLOPE	0x71
+#define DS2784_REG_AE_SEG_2_SLOPE	0x72
+#define DS2784_REG_AE_SEG_1_SLOPE	0x73
+#define DS2784_REG_SE_SEG_4_SLOPE	0x74
+#define DS2784_REG_SE_SEG_3_SLOPE	0x75
+#define DS2784_REG_SE_SEG_2_SLOPE	0x76
+#define DS2784_REG_SE_SEG_1_SLOPE	0x77
+#define DS2784_REG_RSGAIN_MSB		0x78
+#define DS2784_REG_RSGAIN_LSB		0x79
+#define DS2784_REG_RSTC			0x7A
+#define DS2784_REG_CURR_OFFSET_BIAS	0x7B
+#define DS2784_REG_TBP34		0x7C
+#define DS2784_REG_TBP23		0x7D
+#define DS2784_REG_TBP12		0x7E
+#define DS2784_REG_PROTECTOR_THRESHOLD	0x7F
+
+#define DS2784_REG_USER_EEPROM_20	0x20
+
+#endif /* !__w1_ds2784__ */
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index f50afc9f..7759790 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -62,6 +62,9 @@
 #define TPS65023_REG_CTRL_LDO2_EN	BIT(2)
 #define TPS65023_REG_CTRL_LDO1_EN	BIT(1)
 
+/* CON_CTRL2 bitfields */
+#define TPS65023_CON_CTRL2_GO		BIT(7)
+
 /* LDO_CTRL bitfields */
 #define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id)	((ldo_id)*4)
 #define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id)	(0xF0 >> ((ldo_id)*4))
@@ -126,11 +129,38 @@
 	struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
 	const struct tps_info *info[TPS65023_NUM_REGULATOR];
 	struct mutex io_lock;
+	unsigned dcdc1_last_uV;
 };
 
+static int tps_65023_read_3bytes(struct tps_pmic *tps, u8 reg)
+{
+	int rv;
+	u8 txbuf[1];
+	u8 rxbuf[3];
+	struct i2c_msg msgs[] = {
+		{
+			.addr = tps->client->addr,
+			.flags = 0,
+			.len = sizeof(txbuf),
+			.buf = txbuf,
+		},
+		{
+			.addr = tps->client->addr,
+			.flags = I2C_M_RD,
+			.len = sizeof(rxbuf),
+			.buf = rxbuf,
+		},
+	};
+	txbuf[0] = reg;
+	rv = i2c_transfer(tps->client->adapter, msgs, 2);
+	if (rv < 0)
+		return rv;
+	return rxbuf[0];
+}
+
 static inline int tps_65023_read(struct tps_pmic *tps, u8 reg)
 {
-	return i2c_smbus_read_byte_data(tps->client, reg);
+	return tps_65023_read_3bytes(tps, reg);
 }
 
 static inline int tps_65023_write(struct tps_pmic *tps, u8 reg, u8 val)
@@ -326,6 +356,9 @@
 	struct tps_pmic *tps = rdev_get_drvdata(dev);
 	int dcdc = rdev_get_id(dev);
 	int vsel;
+	int rv;
+	int uV = 0;
+	int delay;
 
 	if (dcdc != TPS65023_DCDC_1)
 		return -EINVAL;
@@ -339,7 +372,7 @@
 
 	for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
 		int mV = tps->info[dcdc]->table[vsel];
-		int uV = mV * 1000;
+		uV = mV * 1000;
 
 		/* Break at the first in-range value */
 		if (min_uV <= uV && uV <= max_uV)
@@ -349,8 +382,22 @@
 	/* write to the register in case we found a match */
 	if (vsel == tps->info[dcdc]->table_len)
 		return -EINVAL;
+
+	rv = tps_65023_reg_write(tps, TPS65023_REG_DEF_CORE, vsel);
+	if (!rv)
+		rv = tps_65023_reg_write(tps, TPS65023_REG_CON_CTRL2,
+						TPS65023_CON_CTRL2_GO);
+
+	/* Add delay to reach relected voltage (14.4 mV/us default slew rate) */
+	if (tps->dcdc1_last_uV)
+		delay = abs(tps->dcdc1_last_uV - uV);
 	else
-		return tps_65023_reg_write(tps, TPS65023_REG_DEF_CORE, vsel);
+		delay = max(uV - 800000, 1600000 - uV);
+	delay = DIV_ROUND_UP(delay, 14400);
+	udelay(delay);
+	tps->dcdc1_last_uV = rv ? 0 /* Unknown voltage */ : uV;
+
+	return rv;
 }
 
 static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index d6d51e1..dec9e0d 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -655,6 +655,13 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-davinci.
 
+config RTC_DRV_MSM7X00A
+	tristate "MSM7X00A"
+	depends on ARCH_MSM
+	default y
+	help
+	  RTC driver for Qualcomm MSM7K chipsets
+
 config RTC_DRV_OMAP
 	tristate "TI OMAP1"
 	depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 825df62..26d46ee 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -60,6 +60,7 @@
 obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_MC13783)	+= rtc-mc13783.o
 obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o
+obj-$(CONFIG_RTC_DRV_MSM7X00A)	+= rtc-msm7x00a.o
 obj-$(CONFIG_RTC_DRV_MPC5121)	+= rtc-mpc5121.o
 obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
 obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
diff --git a/drivers/rtc/rtc-msm7x00a.c b/drivers/rtc/rtc-msm7x00a.c
new file mode 100644
index 0000000..f14608a
--- /dev/null
+++ b/drivers/rtc/rtc-msm7x00a.c
@@ -0,0 +1,306 @@
+/* drivers/rtc/rtc-msm7x00a.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: San Mehat <san@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/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/rtc.h>
+#include <linux/msm_rpcrouter.h>
+#include <linux/slab.h>
+
+#include <mach/msm_rpcrouter.h>
+
+#define RTC_DEBUG 0
+
+extern void msm_pm_set_max_sleep_time(int64_t sleep_time_ns);
+
+static const char *rpc_versions[] = {
+#if !defined(CONFIG_MSM_LEGACY_7X00A_AMSS)
+	"rs30000048:00040000",
+	"rs30000048:00010000",
+#else
+	"rs30000048:0da5b528",
+#endif
+};
+
+#define TIMEREMOTE_PROCEEDURE_SET_JULIAN	6
+#define TIMEREMOTE_PROCEEDURE_GET_JULIAN	7
+
+struct rpc_time_julian {
+	uint32_t year;
+	uint32_t month;
+	uint32_t day;
+	uint32_t hour;
+	uint32_t minute;
+	uint32_t second;
+	uint32_t day_of_week;
+};
+
+static struct msm_rpc_endpoint *ep;
+static struct rtc_device *rtc;
+static unsigned long rtcalarm_time;
+
+static int
+msmrtc_timeremote_set_time(struct device *dev, struct rtc_time *tm)
+{
+	int rc;
+
+	struct timeremote_set_julian_req {
+		struct rpc_request_hdr hdr;
+		uint32_t opt_arg;
+
+		struct rpc_time_julian time;
+	} req;
+
+	struct timeremote_set_julian_rep {
+		struct rpc_reply_hdr hdr;
+	} rep;
+
+	if (tm->tm_year < 1900)
+		tm->tm_year += 1900;
+
+	if (tm->tm_year < 1970)
+		return -EINVAL;
+
+#if RTC_DEBUG
+	printk(KERN_DEBUG "%s: %.2u/%.2u/%.4u %.2u:%.2u:%.2u (%.2u)\n",
+	       __func__, tm->tm_mon, tm->tm_mday, tm->tm_year,
+	       tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday);
+#endif
+
+	req.opt_arg = cpu_to_be32(1);
+	req.time.year = cpu_to_be32(tm->tm_year);
+	req.time.month = cpu_to_be32(tm->tm_mon + 1);
+	req.time.day = cpu_to_be32(tm->tm_mday);
+	req.time.hour = cpu_to_be32(tm->tm_hour);
+	req.time.minute = cpu_to_be32(tm->tm_min);
+	req.time.second = cpu_to_be32(tm->tm_sec);
+	req.time.day_of_week = cpu_to_be32(tm->tm_wday);
+
+
+	rc = msm_rpc_call_reply(ep, TIMEREMOTE_PROCEEDURE_SET_JULIAN,
+				&req, sizeof(req),
+				&rep, sizeof(rep),
+				5 * HZ);
+	return rc;
+}
+
+static int
+msmrtc_timeremote_read_time(struct device *dev, struct rtc_time *tm)
+{
+	int rc;
+
+	struct timeremote_get_julian_req {
+		struct rpc_request_hdr hdr;
+		uint32_t julian_time_not_null;
+	} req;
+
+	struct timeremote_get_julian_rep {
+		struct rpc_reply_hdr hdr;
+		uint32_t opt_arg;
+		struct rpc_time_julian time;
+	} rep;
+
+	req.julian_time_not_null = cpu_to_be32(1);
+
+	rc = msm_rpc_call_reply(ep, TIMEREMOTE_PROCEEDURE_GET_JULIAN,
+				&req, sizeof(req),
+				&rep, sizeof(rep),
+				5 * HZ);
+	if (rc < 0)
+		return rc;
+
+	if (!be32_to_cpu(rep.opt_arg)) {
+		printk(KERN_ERR "%s: No data from RTC\n", __func__);
+		return -ENODATA;
+	}
+
+	tm->tm_year = be32_to_cpu(rep.time.year);
+	tm->tm_mon = be32_to_cpu(rep.time.month);
+	tm->tm_mday = be32_to_cpu(rep.time.day);
+	tm->tm_hour = be32_to_cpu(rep.time.hour);
+	tm->tm_min = be32_to_cpu(rep.time.minute);
+	tm->tm_sec = be32_to_cpu(rep.time.second);
+	tm->tm_wday = be32_to_cpu(rep.time.day_of_week);
+
+#if RTC_DEBUG
+	printk(KERN_DEBUG "%s: %.2u/%.2u/%.4u %.2u:%.2u:%.2u (%.2u)\n",
+	       __func__, tm->tm_mon, tm->tm_mday, tm->tm_year,
+	       tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday);
+#endif
+
+	tm->tm_year -= 1900;	/* RTC layer expects years to start at 1900 */
+	tm->tm_mon--;		/* RTC layer expects mons to be 0 based */
+
+	if (rtc_valid_tm(tm) < 0) {
+		dev_err(dev, "retrieved date/time is not valid.\n");
+		rtc_time_to_tm(0, tm);
+	}
+
+	return 0;
+}
+
+
+static int
+msmrtc_virtual_alarm_set(struct device *dev, struct rtc_wkalrm *a)
+{
+	unsigned long now = get_seconds();
+
+	if (!a->enabled) {
+		rtcalarm_time = 0;
+		return 0;
+	} else
+		rtc_tm_to_time(&a->time, &rtcalarm_time);
+
+	if (now > rtcalarm_time) {
+		printk(KERN_ERR "%s: Attempt to set alarm in the past\n",
+		       __func__);
+		rtcalarm_time = 0;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct rtc_class_ops msm_rtc_ops = {
+	.read_time	= msmrtc_timeremote_read_time,
+	.set_time	= msmrtc_timeremote_set_time,
+	.set_alarm	= msmrtc_virtual_alarm_set,
+};
+
+static void
+msmrtc_alarmtimer_expired(unsigned long _data)
+{
+#if RTC_DEBUG
+	printk(KERN_DEBUG "%s: Generating alarm event (src %lu)\n",
+	       rtc->name, _data);
+#endif
+	rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+	rtcalarm_time = 0;
+}
+
+static int
+msmrtc_probe(struct platform_device *pdev)
+{
+	struct rpcsvr_platform_device *rdev =
+		container_of(pdev, struct rpcsvr_platform_device, base);
+
+	if (rtc)
+		return -EBUSY;
+
+	ep = msm_rpc_connect(rdev->prog, rdev->vers, 0);
+	if (IS_ERR(ep)) {
+		printk(KERN_ERR "%s: init rpc failed! rc = %ld\n",
+		       __func__, PTR_ERR(ep));
+		return PTR_ERR(ep);
+	}
+
+	rtc = rtc_device_register("msm_rtc",
+				  &pdev->dev,
+				  &msm_rtc_ops,
+				  THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		printk(KERN_ERR "%s: Can't register RTC device (%ld)\n",
+		       pdev->name, PTR_ERR(rtc));
+		return PTR_ERR(rtc);
+	}
+	return 0;
+}
+
+
+static unsigned long msmrtc_get_seconds(void)
+{
+	struct rtc_time tm;
+	unsigned long now;
+
+	msmrtc_timeremote_read_time(NULL, &tm);
+	rtc_tm_to_time(&tm, &now);
+	return now;
+}
+
+static int
+msmrtc_suspend(struct platform_device *dev, pm_message_t state)
+{
+	if (rtcalarm_time) {
+		unsigned long now = msmrtc_get_seconds();
+		int diff = rtcalarm_time - now;
+		if (diff <= 0) {
+			msmrtc_alarmtimer_expired(1);
+			msm_pm_set_max_sleep_time(0);
+			return 0;
+		}
+		msm_pm_set_max_sleep_time((int64_t) ((int64_t) diff * NSEC_PER_SEC));
+	} else
+		msm_pm_set_max_sleep_time(0);
+	return 0;
+}
+
+static int
+msmrtc_resume(struct platform_device *dev)
+{
+	if (rtcalarm_time) {
+		unsigned long now = msmrtc_get_seconds();
+		int diff = rtcalarm_time - now;
+		if (diff <= 0)
+			msmrtc_alarmtimer_expired(2);
+	}
+	return 0;
+}
+
+static int __init msmrtc_init(void)
+{
+	int i;
+	int ret;
+	struct platform_driver *pdrv[ARRAY_SIZE(rpc_versions)];
+
+	rtcalarm_time = 0;
+
+	/* register the devices for all the major versions we support, only
+	 * one should match */
+	for (i = 0; i < ARRAY_SIZE(rpc_versions); i++) {
+		pdrv[i] = kzalloc(sizeof(struct platform_driver), GFP_KERNEL);
+		if (!pdrv[i]) {
+			ret = -ENOMEM;
+			goto err;
+		}
+		pdrv[i]->probe = msmrtc_probe;
+		pdrv[i]->suspend = msmrtc_suspend;
+		pdrv[i]->resume = msmrtc_resume;
+		pdrv[i]->driver.name = rpc_versions[i];
+		pdrv[i]->driver.owner = THIS_MODULE;
+		ret = platform_driver_register(pdrv[i]);
+		if (ret) {
+			kfree(pdrv[i]);
+			goto err;
+		}
+	}
+	return 0;
+
+err:
+	for (--i; i >= 0; i--)
+		platform_driver_unregister(pdrv[i]);
+	return ret;
+}
+
+module_init(msmrtc_init);
+
+MODULE_DESCRIPTION("RTC driver for Qualcomm MSM7x00a chipsets");
+MODULE_AUTHOR("San Mehat <san@android.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 8b23165..ae1684f 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1351,6 +1351,38 @@
 	depends on SERIAL_MSM=y
 	select SERIAL_CORE_CONSOLE
 
+config SERIAL_MSM_CLOCK_CONTROL
+	bool "Allow tty clients to make clock requests to msm uarts."
+	depends on SERIAL_MSM=y
+	default y
+	help
+	 Provides an interface for tty clients to request the msm uart clock
+	 to be turned on or off for power savings.
+
+config SERIAL_MSM_RX_WAKEUP
+	bool "Wakeup the msm uart clock on GPIO activity."
+	depends on SERIAL_MSM_CLOCK_CONTROL
+	default n
+	help
+	 Requires SERIAL_MSM_CLOCK_CONTROL. Wake up the uart while the uart
+	 clock is off, using a wakeup GPIO.
+
+config SERIAL_MSM_HS
+	tristate "MSM UART High Speed: Serial Driver"
+	depends on ARM && ARCH_MSM
+	select SERIAL_CORE
+	default n
+	help
+	  Select this module to enable MSM high speed UART driver.
+
+config SERIAL_BCM_BT_LPM
+	tristate "Broadcom Bluetooth Low Power Mode"
+	depends on ARM && ARCH_MSM
+	select SERIAL_CORE
+	default n
+	help
+	  Select this module for Broadcom Bluetooth low power management.
+
 config SERIAL_NETX
 	tristate "NetX serial port support"
 	depends on ARM && ARCH_NETX
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 208a855..262316e 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -35,6 +35,7 @@
 obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
 obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
 obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
+obj-$(CONFIG_SERIAL_BCM_BT_LPM) += bcm_bt_lpm.o
 obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
 obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
 obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
@@ -74,6 +75,8 @@
 obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
 obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
 obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
+obj-$(CONFIG_MSM_SERIAL_DEBUGGER) += msm_serial_debugger.o
+obj-$(CONFIG_SERIAL_MSM_HS) += msm_serial_hs.o
 obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
diff --git a/drivers/serial/bcm_bt_lpm.c b/drivers/serial/bcm_bt_lpm.c
new file mode 100644
index 0000000..bf5ab33
--- /dev/null
+++ b/drivers/serial/bcm_bt_lpm.c
@@ -0,0 +1,176 @@
+/*
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/hrtimer.h>
+#include <linux/irq.h>
+#include <linux/serial_core.h>
+#include <mach/bcm_bt_lpm.h>
+#include <asm/gpio.h>
+
+/*
+ * Manage WAKE and HOST_WAKE low power mode signals for Broadcom
+ * Bluetooth chipsets.
+ *
+ * This driver needs to be tightly coupled with a uart driver that supports
+ * request_clock_off_locked() and request_clock_on_locked(), to clock off and
+ * on the uart indepdently of Linux suspend/resume.
+ *
+ * The uart driver needs to call bcm_bt_lpm_exit_lpm_locked() every time it
+ * begins TX, to ensure this driver keeps WAKE asserted during TX.
+ *
+ * The callbacks and hijacking of the uart_port struct are not a clean API,
+ * but the Linux tty and serial core layers do not have a better alternative
+ * right now: there is no good way to plumb uart clock control through these
+ * layers. See http://lkml.org/lkml/2008/12/19/213 for more background.
+ */
+
+struct bcm_bt_lpm {
+	unsigned int gpio_wake;
+	unsigned int gpio_host_wake;
+
+	int wake;
+	int host_wake;
+
+	struct hrtimer enter_lpm_timer;
+	ktime_t enter_lpm_delay;
+
+	struct uart_port *uport;
+
+	void (*request_clock_off_locked)(struct uart_port *uport);
+	void (*request_clock_on_locked)(struct uart_port *uport);
+} bt_lpm;
+
+static void set_wake_locked(int wake)
+{
+	if (wake == bt_lpm.wake)
+		return;
+	bt_lpm.wake = wake;
+
+	if (wake || bt_lpm.host_wake)
+		bt_lpm.request_clock_on_locked(bt_lpm.uport);
+	else
+		bt_lpm.request_clock_off_locked(bt_lpm.uport);
+
+	gpio_set_value(bt_lpm.gpio_wake, wake);
+}
+
+static enum hrtimer_restart enter_lpm(struct hrtimer *timer) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&bt_lpm.uport->lock, flags);
+	set_wake_locked(0);
+	spin_unlock_irqrestore(&bt_lpm.uport->lock, flags);
+
+	return HRTIMER_NORESTART;
+}
+
+void bcm_bt_lpm_exit_lpm_locked(struct uart_port *uport) {
+	bt_lpm.uport = uport;
+
+	hrtimer_try_to_cancel(&bt_lpm.enter_lpm_timer);
+
+	set_wake_locked(1);
+
+	hrtimer_start(&bt_lpm.enter_lpm_timer, bt_lpm.enter_lpm_delay,
+			HRTIMER_MODE_REL);
+}
+EXPORT_SYMBOL(bcm_bt_lpm_exit_lpm_locked);
+
+static void update_host_wake_locked(int host_wake)
+{
+	if (host_wake == bt_lpm.host_wake)
+		return;
+	bt_lpm.host_wake = host_wake;
+
+	if (bt_lpm.wake || host_wake)
+		bt_lpm.request_clock_on_locked(bt_lpm.uport);
+	else
+		bt_lpm.request_clock_off_locked(bt_lpm.uport);
+}
+
+static irqreturn_t host_wake_isr(int irq, void *dev)
+{
+	int host_wake;
+	unsigned long flags;
+
+	host_wake = gpio_get_value(bt_lpm.gpio_host_wake);
+	set_irq_type(irq, host_wake ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+
+	if (!bt_lpm.uport) {
+		bt_lpm.host_wake = host_wake;
+		return IRQ_HANDLED;
+	}
+
+	spin_lock_irqsave(&bt_lpm.uport->lock, flags);
+
+	update_host_wake_locked(host_wake);
+
+	spin_unlock_irqrestore(&bt_lpm.uport->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static int bcm_bt_lpm_probe(struct platform_device *pdev)
+{
+	int irq;
+	int ret;
+	struct bcm_bt_lpm_platform_data *pdata = pdev->dev.platform_data;
+
+	if (bt_lpm.request_clock_off_locked != NULL) {
+		printk(KERN_ERR "Cannot register two bcm_bt_lpm drivers\n");
+		return -EINVAL;
+	}
+
+	bt_lpm.gpio_wake = pdata->gpio_wake;
+	bt_lpm.gpio_host_wake = pdata->gpio_host_wake;
+	bt_lpm.request_clock_off_locked = pdata->request_clock_off_locked;
+	bt_lpm.request_clock_on_locked = pdata->request_clock_on_locked;
+
+	hrtimer_init(&bt_lpm.enter_lpm_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	bt_lpm.enter_lpm_delay = ktime_set(1, 0);  /* 1 sec */
+	bt_lpm.enter_lpm_timer.function = enter_lpm;
+
+	gpio_set_value(bt_lpm.gpio_wake, 0);
+	bt_lpm.host_wake = 0;
+
+	irq = gpio_to_irq(bt_lpm.gpio_host_wake);
+	ret = request_irq(irq, host_wake_isr, IRQF_TRIGGER_HIGH,
+			"bt host_wake", NULL);
+	if (ret)
+		return ret;
+	ret = set_irq_wake(irq, 1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct platform_driver bcm_bt_lpm_driver = {
+	.probe = bcm_bt_lpm_probe,
+	.driver = {
+		.name = "bcm_bt_lpm",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init bcm_bt_lpm_init(void)
+{
+	return platform_driver_register(&bcm_bt_lpm_driver);
+}
+
+module_init(bcm_bt_lpm_init);
+MODULE_DESCRIPTION("Broadcom Bluetooth low power mode driver");
+MODULE_AUTHOR("Nick Pelly <npelly@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
index f8c816e..63f3f3e 100644
--- a/drivers/serial/msm_serial.c
+++ b/drivers/serial/msm_serial.c
@@ -34,45 +34,176 @@
 
 #include "msm_serial.h"
 
+#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
+enum msm_clk_states_e {
+	MSM_CLK_PORT_OFF,     /* uart port not in use */
+	MSM_CLK_OFF,          /* clock enabled */
+	MSM_CLK_REQUEST_OFF,  /* disable after TX flushed */
+	MSM_CLK_ON,           /* clock disabled */
+};
+#endif
+
 struct msm_port {
 	struct uart_port	uart;
 	char			name[16];
 	struct clk		*clk;
 	unsigned int		imr;
+#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
+	enum msm_clk_states_e	clk_state;
+	struct hrtimer		clk_off_timer;
+	ktime_t			clk_off_delay;
+#endif
 };
 
 static void msm_stop_tx(struct uart_port *port)
 {
 	struct msm_port *msm_port = UART_TO_MSM(port);
 
+	clk_enable(msm_port->clk);
+
 	msm_port->imr &= ~UART_IMR_TXLEV;
 	msm_write(port, msm_port->imr, UART_IMR);
+
+	clk_disable(msm_port->clk);
 }
 
 static void msm_start_tx(struct uart_port *port)
 {
 	struct msm_port *msm_port = UART_TO_MSM(port);
 
+	clk_enable(msm_port->clk);
+
 	msm_port->imr |= UART_IMR_TXLEV;
 	msm_write(port, msm_port->imr, UART_IMR);
+
+	clk_disable(msm_port->clk);
 }
 
 static void msm_stop_rx(struct uart_port *port)
 {
 	struct msm_port *msm_port = UART_TO_MSM(port);
 
+	clk_enable(msm_port->clk);
+
 	msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
 	msm_write(port, msm_port->imr, UART_IMR);
+
+	clk_disable(msm_port->clk);
 }
 
 static void msm_enable_ms(struct uart_port *port)
 {
 	struct msm_port *msm_port = UART_TO_MSM(port);
 
+	clk_enable(msm_port->clk);
+
 	msm_port->imr |= UART_IMR_DELTA_CTS;
 	msm_write(port, msm_port->imr, UART_IMR);
+
+	clk_disable(msm_port->clk);
 }
 
+#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
+/* turn clock off if TX buffer is empty, otherwise reschedule */
+static enum hrtimer_restart msm_serial_clock_off(struct hrtimer *timer) {
+	struct msm_port *msm_port = container_of(timer, struct msm_port,
+						 clk_off_timer);
+	struct uart_port *port = &msm_port->uart;
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned long flags;
+	int ret = HRTIMER_NORESTART;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (msm_port->clk_state == MSM_CLK_REQUEST_OFF) {
+		if (uart_circ_empty(xmit)) {
+			struct msm_port *msm_port = UART_TO_MSM(port);
+			clk_disable(msm_port->clk);
+			msm_port->clk_state = MSM_CLK_OFF;
+		} else {
+			hrtimer_forward_now(timer, msm_port->clk_off_delay);
+			ret = HRTIMER_RESTART;
+		}
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return HRTIMER_NORESTART;
+}
+
+/* request to turn off uart clock once pending TX is flushed */
+void msm_serial_clock_request_off(struct uart_port *port) {
+	unsigned long flags;
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (msm_port->clk_state == MSM_CLK_ON) {
+		msm_port->clk_state = MSM_CLK_REQUEST_OFF;
+		/* turn off TX later. unfortunately not all msm uart's have a
+		 * TXDONE available, and TXLEV does not wait until completely
+		 * flushed, so a timer is our only option
+		 */
+		hrtimer_start(&msm_port->clk_off_timer,
+			      msm_port->clk_off_delay, HRTIMER_MODE_REL);
+	}
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* request to immediately turn on uart clock.
+ * ignored if there is a pending off request, unless force = 1.
+ */
+void msm_serial_clock_on(struct uart_port *port, int force) {
+	unsigned long flags;
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	switch (msm_port->clk_state) {
+	case MSM_CLK_OFF:
+		clk_enable(msm_port->clk);
+		force = 1;
+	case MSM_CLK_REQUEST_OFF:
+		if (force) {
+			hrtimer_try_to_cancel(&msm_port->clk_off_timer);
+			msm_port->clk_state = MSM_CLK_ON;
+		}
+		break;
+	case MSM_CLK_ON: break;
+	case MSM_CLK_PORT_OFF: break;
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+#endif
+
+#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
+#define WAKE_UP_IND	0x32
+static irqreturn_t msm_rx_irq(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	struct msm_port *msm_port = UART_TO_MSM(port);
+	int inject_wakeup = 0;
+
+	spin_lock(&port->lock);
+
+	if (msm_port->clk_state == MSM_CLK_OFF)
+		inject_wakeup = 1;
+
+	msm_serial_clock_on(port, 0);
+
+	/* we missed an rx while asleep - it must be a wakeup indicator
+	 */
+	if (inject_wakeup) {
+		struct tty_struct *tty = port->state->port.tty;
+		tty_insert_flip_char(tty, WAKE_UP_IND, TTY_NORMAL);
+		tty_flip_buffer_push(tty);
+	}
+
+	spin_unlock(&port->lock);
+	return IRQ_HANDLED;
+}
+#endif
+
 static void handle_rx(struct uart_port *port)
 {
 	struct tty_struct *tty = port->state->port.tty;
@@ -148,6 +279,14 @@
 		sent_tx = 1;
 	}
 
+#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
+	if (sent_tx && msm_port->clk_state == MSM_CLK_REQUEST_OFF)
+		/* new TX - restart the timer */
+		if (hrtimer_try_to_cancel(&msm_port->clk_off_timer) == 1)
+			hrtimer_start(&msm_port->clk_off_timer,
+				msm_port->clk_off_delay, HRTIMER_MODE_REL);
+#endif
+
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(port);
 }
@@ -166,6 +305,7 @@
 	unsigned int misr;
 
 	spin_lock(&port->lock);
+	clk_enable(msm_port->clk);
 	misr = msm_read(port, UART_MISR);
 	msm_write(port, 0, UART_IMR); /* disable interrupt */
 
@@ -177,6 +317,7 @@
 		handle_delta_cts(port);
 
 	msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
+	clk_disable(msm_port->clk);
 	spin_unlock(&port->lock);
 
 	return IRQ_HANDLED;
@@ -184,7 +325,14 @@
 
 static unsigned int msm_tx_empty(struct uart_port *port)
 {
-	return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
+	unsigned int ret;
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	clk_enable(msm_port->clk);
+	ret = (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
+	clk_disable(msm_port->clk);
+
+	return ret;
 }
 
 static unsigned int msm_get_mctrl(struct uart_port *port)
@@ -195,6 +343,9 @@
 static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
 	unsigned int mr;
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	clk_enable(msm_port->clk);
 
 	mr = msm_read(port, UART_MR1);
 
@@ -206,14 +357,22 @@
 		mr |= UART_MR1_RX_RDY_CTL;
 		msm_write(port, mr, UART_MR1);
 	}
+
+	clk_disable(msm_port->clk);
 }
 
 static void msm_break_ctl(struct uart_port *port, int break_ctl)
 {
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	clk_enable(msm_port->clk);
+
 	if (break_ctl)
 		msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
 	else
 		msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
+
+	clk_disable(msm_port->clk);
 }
 
 static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
@@ -307,6 +466,10 @@
 	struct msm_port *msm_port = UART_TO_MSM(port);
 
 	clk_enable(msm_port->clk);
+#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
+	msm_port->clk_state = MSM_CLK_ON;
+#endif
+
 	msm_serial_set_mnd_regs(port);
 }
 
@@ -356,6 +519,17 @@
 			UART_IMR_CURRENT_CTS;
 	msm_write(port, msm_port->imr, UART_IMR);
 
+#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
+	/* Apply the RX GPIO wake irq workaround to the bluetooth uart */
+	if (port->line == 0) {  /* BT is serial device 0 */
+		ret = request_irq(MSM_GPIO_TO_INT(45), msm_rx_irq,
+				  IRQF_TRIGGER_FALLING, "msm_serial0_rx",
+				  port);
+		if (unlikely(ret))
+			return ret;
+	}
+#endif
+
 	return 0;
 }
 
@@ -363,12 +537,27 @@
 {
 	struct msm_port *msm_port = UART_TO_MSM(port);
 
+	clk_enable(msm_port->clk);
+
 	msm_port->imr = 0;
 	msm_write(port, 0, UART_IMR); /* disable interrupts */
 
 	clk_disable(msm_port->clk);
 
 	free_irq(port->irq, port);
+
+#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
+	if (port->line == 0)
+		free_irq(MSM_GPIO_TO_INT(45), port);
+#endif
+
+#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
+	if (msm_port->clk_state != MSM_CLK_OFF)
+		clk_disable(msm_port->clk);
+	msm_port->clk_state = MSM_CLK_PORT_OFF;
+#else
+	clk_disable(msm_port->clk);
+#endif
 }
 
 static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
@@ -376,8 +565,10 @@
 {
 	unsigned long flags;
 	unsigned int baud, mr;
+	struct msm_port *msm_port = UART_TO_MSM(port);
 
 	spin_lock_irqsave(&port->lock, flags);
+	clk_enable(msm_port->clk);
 
 	/* calculate and set baud rate */
 	baud = uart_get_baud_rate(port, termios, old, 300, 115200);
@@ -443,6 +634,7 @@
 
 	uart_update_timeout(port, termios->c_cflag, baud);
 
+	clk_disable(msm_port->clk);
 	spin_unlock_irqrestore(&port->lock, flags);
 }
 
@@ -510,6 +702,7 @@
 static void msm_power(struct uart_port *port, unsigned int state,
 		      unsigned int oldstate)
 {
+#ifndef CONFIG_SERIAL_MSM_CLOCK_CONTROL
 	struct msm_port *msm_port = UART_TO_MSM(port);
 
 	switch (state) {
@@ -522,6 +715,7 @@
 	default:
 		printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
 	}
+#endif
 }
 
 static struct uart_ops msm_uart_pops = {
@@ -602,7 +796,9 @@
 	msm_port = UART_TO_MSM(port);
 
 	spin_lock(&port->lock);
+	clk_enable(msm_port->clk);
 	uart_console_write(port, s, count, msm_console_putchar);
+	clk_disable(msm_port->clk);
 	spin_unlock(&port->lock);
 }
 
@@ -704,6 +900,22 @@
 
 	platform_set_drvdata(pdev, port);
 
+	if (unlikely(set_irq_wake(port->irq, 1)))
+		return -ENXIO;
+
+#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
+	if (port->line == 0)  /* BT is serial device 0 */
+		if (unlikely(set_irq_wake(MSM_GPIO_TO_INT(45), 1)))
+			return -ENXIO;
+#endif
+
+#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
+	msm_port->clk_state = MSM_CLK_PORT_OFF;
+	hrtimer_init(&msm_port->clk_off_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	msm_port->clk_off_timer.function = msm_serial_clock_off;
+	msm_port->clk_off_delay = ktime_set(0, 1000000);  /* 1 ms */
+#endif
+
 	return uart_add_one_port(&msm_uart_driver, port);
 }
 
diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h
index f6ca9ca..059a69e 100644
--- a/drivers/serial/msm_serial.h
+++ b/drivers/serial/msm_serial.h
@@ -114,6 +114,7 @@
 #define UART_MISR	0x0010
 #define UART_ISR	0x0014
 
+#ifndef BUILD_SERIAL_DEBUGGER
 #define UART_TO_MSM(uart_port)	((struct msm_port *) uart_port)
 
 static inline
@@ -169,5 +170,6 @@
 #else
 #define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk
 #endif
+#endif
 
 #endif	/* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/drivers/serial/msm_serial_debugger.c b/drivers/serial/msm_serial_debugger.c
new file mode 100644
index 0000000..f3214d2
--- /dev/null
+++ b/drivers/serial/msm_serial_debugger.c
@@ -0,0 +1,687 @@
+/*
+ * drivers/serial/msm_serial_debuger.c
+ *
+ * Serial Debugger Interface for MSM7K
+ *
+ * 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 <stdarg.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/kernel_debugger.h>
+#include <linux/kernel_stat.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/wakelock.h>
+
+#include <asm/stacktrace.h>
+
+#include <mach/msm_serial_debugger.h>
+#include <mach/system.h>
+#include <mach/fiq.h>
+
+#define BUILD_SERIAL_DEBUGGER
+#include "msm_serial.h"
+
+#include <linux/uaccess.h>
+
+static void sleep_timer_expired(unsigned long);
+
+static unsigned int debug_port_base;
+static int debug_signal_irq;
+static struct clk *debug_clk;
+static bool debug_clk_enabled;
+static bool ignore_next_wakeup_irq;
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER_NO_SLEEP
+static int no_sleep = true;
+#else
+static int no_sleep;
+#endif
+static DEFINE_TIMER(sleep_timer, sleep_timer_expired, 0, 0);
+static int debug_enable;
+static int debugger_enable;
+static struct wake_lock debugger_wake_lock;
+static struct {
+	unsigned int	base;
+	int		irq;
+	struct device	*clk_device;
+	int		signal_irq;
+	int		wakeup_irq;
+} init_data;
+
+module_param(no_sleep, bool, 0644);
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
+static inline void enable_wakeup_irq(unsigned int irq) {}
+static inline void disable_wakeup_irq(unsigned int irq) {}
+#else
+static inline void enable_wakeup_irq(unsigned int irq) {enable_irq(irq);}
+static inline void disable_wakeup_irq(unsigned int irq)
+						{disable_irq_nosync(irq);}
+#endif
+
+
+static inline void msm_write(unsigned int val, unsigned int off)
+{
+	__raw_writel(val, debug_port_base + off);
+}
+
+static inline unsigned int msm_read(unsigned int off)
+{
+	return __raw_readl(debug_port_base + off);
+}
+
+static void debug_port_init(void)
+{
+	/* reset everything */
+	msm_write(UART_CR_CMD_RESET_RX, UART_CR);
+	msm_write(UART_CR_CMD_RESET_TX, UART_CR);
+	msm_write(UART_CR_CMD_RESET_ERR, UART_CR);
+	msm_write(UART_CR_CMD_RESET_BREAK_INT, UART_CR);
+	msm_write(UART_CR_CMD_RESET_CTS, UART_CR);
+	msm_write(UART_CR_CMD_SET_RFR, UART_CR);
+
+	/* setup clock dividers */
+#ifdef CONFIG_ARCH_MSM_SCORPION
+	if (clk_get_rate(debug_clk) == 19200000) {
+		/* clock is TCXO (19.2MHz) */
+		msm_write(0x06, UART_MREG);
+		msm_write(0xF1, UART_NREG);
+		msm_write(0x0F, UART_DREG);
+		msm_write(0x1A, UART_MNDREG);
+	} else
+#endif
+	{
+		/* clock must be TCXO/4 */
+		msm_write(0xC0, UART_MREG);
+		msm_write(0xB2, UART_NREG);
+		msm_write(0x7D, UART_DREG);
+		msm_write(0x1C, UART_MNDREG);
+	}
+
+	msm_write(UART_CSR_115200, UART_CSR);
+
+	/* rx interrupt on every character -- keep it simple */
+	msm_write(0, UART_RFWR);
+
+	/* enable TX and RX */
+	msm_write(0x05, UART_CR);
+
+	/* enable RX interrupt */
+	msm_write(UART_IMR_RXLEV, UART_IMR);
+}
+
+static inline int debug_getc(void)
+{
+	if (msm_read(UART_SR) & UART_SR_RX_READY) {
+		return msm_read(UART_RF);
+	} else {
+		return -1;
+	}
+}
+
+static inline void debug_putc(unsigned int c)
+{
+	while (!(msm_read(UART_SR) & UART_SR_TX_READY)) ;
+	msm_write(c, UART_TF);
+}
+
+static inline void debug_flush(void)
+{
+	while (!(msm_read(UART_SR) & UART_SR_TX_EMPTY)) ;
+}
+
+static void debug_puts(char *s)
+{
+	unsigned c;
+	while ((c = *s++)) {
+		if (c == '\n')
+			debug_putc('\r');
+		debug_putc(c);
+	}
+}
+
+static void debug_prompt(void)
+{
+	debug_puts("debug> ");
+}
+
+int log_buf_copy(char *dest, int idx, int len);
+static void dump_kernel_log(void)
+{
+	char buf[1024];
+	int idx = 0;
+	int ret;
+	int saved_oip;
+
+	/* setting oops_in_progress prevents log_buf_copy()
+	 * from trying to take a spinlock which will make it
+	 * very unhappy in some cases...
+	 */
+	saved_oip = oops_in_progress;
+	oops_in_progress = 1;
+	for (;;) {
+		ret = log_buf_copy(buf, idx, 1023);
+		if (ret <= 0)
+			break;
+		buf[ret] = 0;
+		debug_puts(buf);
+		idx += ret;
+	}
+	oops_in_progress = saved_oip;
+}
+
+static char *mode_name(unsigned cpsr)
+{
+	switch (cpsr & MODE_MASK) {
+	case USR_MODE: return "USR";
+	case FIQ_MODE: return "FIQ";
+	case IRQ_MODE: return "IRQ";
+	case SVC_MODE: return "SVC";
+	case ABT_MODE: return "ABT";
+	case UND_MODE: return "UND";
+	case SYSTEM_MODE: return "SYS";
+	default: return "???";
+	}
+}
+
+#define DEBUG_MAX 64
+static char debug_cmd[DEBUG_MAX];
+static int debug_busy;
+static int debug_abort;
+
+static int debug_printf(void *cookie, const char *fmt, ...)
+{
+	char buf[256];
+	va_list ap;
+
+	va_start(ap, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	va_end(ap);
+
+	debug_puts(buf);
+	return debug_abort;
+}
+
+/* Safe outside fiq context */
+static int debug_printf_nfiq(void *cookie, const char *fmt, ...)
+{
+	char buf[256];
+	va_list ap;
+	unsigned long irq_flags;
+
+	va_start(ap, fmt);
+	vsnprintf(buf, 128, fmt, ap);
+	va_end(ap);
+
+	local_irq_save(irq_flags);
+	debug_puts(buf);
+	debug_flush();
+	local_irq_restore(irq_flags);
+	return debug_abort;
+}
+
+#define dprintf(fmt...) debug_printf(0, fmt)
+
+unsigned int last_irqs[NR_IRQS];
+
+static void dump_regs(unsigned *regs)
+{
+	dprintf(" r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
+		regs[0], regs[1], regs[2], regs[3]);
+	dprintf(" r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
+		regs[4], regs[5], regs[6], regs[7]);
+	dprintf(" r8 %08x  r9 %08x r10 %08x r11 %08x  mode %s\n",
+		regs[8], regs[9], regs[10], regs[11],
+		mode_name(regs[16]));
+	if ((regs[16] & MODE_MASK) == USR_MODE)
+		dprintf(" ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
+			regs[12], regs[13], regs[14], regs[15], regs[16]);
+	else
+		dprintf(" ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x  "
+			"spsr %08x\n", regs[12], regs[13], regs[14], regs[15],
+			regs[16], regs[17]);
+}
+
+struct mode_regs {
+	unsigned long sp_svc;
+	unsigned long lr_svc;
+	unsigned long spsr_svc;
+
+	unsigned long sp_abt;
+	unsigned long lr_abt;
+	unsigned long spsr_abt;
+
+	unsigned long sp_und;
+	unsigned long lr_und;
+	unsigned long spsr_und;
+
+	unsigned long sp_irq;
+	unsigned long lr_irq;
+	unsigned long spsr_irq;
+
+	unsigned long r8_fiq;
+	unsigned long r9_fiq;
+	unsigned long r10_fiq;
+	unsigned long r11_fiq;
+	unsigned long r12_fiq;
+	unsigned long sp_fiq;
+	unsigned long lr_fiq;
+	unsigned long spsr_fiq;
+};
+
+void __naked get_mode_regs(struct mode_regs *regs)
+{
+	asm volatile (
+	"mrs	r1, cpsr\n"
+	"msr	cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n"
+	"stmia	r0!, {r13 - r14}\n"
+	"mrs	r2, spsr\n"
+	"msr	cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n"
+	"stmia	r0!, {r2, r13 - r14}\n"
+	"mrs	r2, spsr\n"
+	"msr	cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n"
+	"stmia	r0!, {r2, r13 - r14}\n"
+	"mrs	r2, spsr\n"
+	"msr	cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
+	"stmia	r0!, {r2, r13 - r14}\n"
+	"mrs	r2, spsr\n"
+	"msr	cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
+	"stmia	r0!, {r2, r8 - r14}\n"
+	"mrs	r2, spsr\n"
+	"stmia	r0!, {r2}\n"
+	"msr	cpsr_c, r1\n"
+	"bx	lr\n");
+}
+
+
+static void dump_allregs(unsigned *regs)
+{
+	struct mode_regs mode_regs;
+	dump_regs(regs);
+	get_mode_regs(&mode_regs);
+	dprintf(" svc: sp %08x  lr %08x  spsr %08x\n",
+		mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc);
+	dprintf(" abt: sp %08x  lr %08x  spsr %08x\n",
+		mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt);
+	dprintf(" und: sp %08x  lr %08x  spsr %08x\n",
+		mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und);
+	dprintf(" irq: sp %08x  lr %08x  spsr %08x\n",
+		mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq);
+	dprintf(" fiq: r8 %08x  r9 %08x  r10 %08x  r11 %08x  r12 %08x\n",
+		mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq,
+		mode_regs.r11_fiq, mode_regs.r12_fiq);
+	dprintf(" fiq: sp %08x  lr %08x  spsr %08x\n",
+		mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq);
+}
+
+static void dump_irqs(void)
+{
+	int n;
+	dprintf("irqnr       total  since-last   status  name\n");
+	for (n = 1; n < NR_IRQS; n++) {
+		struct irqaction *act = irq_desc[n].action;
+		if (!act && !kstat_irqs(n))
+			continue;
+		dprintf("%5d: %10u %11u %8x  %s\n", n,
+			kstat_irqs(n),
+			kstat_irqs(n) - last_irqs[n],
+			irq_desc[n].status,
+			(act && act->name) ? act->name : "???");
+		last_irqs[n] = kstat_irqs(n);
+	}
+}
+
+static int report_trace(struct stackframe *frame, void *d)
+{
+	unsigned int *depth = d;
+
+	if (*depth) {
+		dprintf("  pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
+			frame->pc, frame->pc, frame->lr, frame->lr,
+			frame->sp, frame->fp);
+		(*depth)--;
+		return 0;
+	}
+	dprintf("  ...\n");
+
+	return *depth == 0;
+}
+
+struct frame_tail {
+	struct frame_tail *fp;
+	unsigned long sp;
+	unsigned long lr;
+} __attribute__((packed));
+
+static struct frame_tail *user_backtrace(struct frame_tail *tail)
+{
+	struct frame_tail buftail[2];
+
+	/* Also check accessibility of one struct frame_tail beyond */
+	if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) {
+		dprintf("  invalid frame pointer %p\n", tail);
+		return NULL;
+	}
+	if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) {
+		dprintf("  failed to copy frame pointer %p\n", tail);
+		return NULL;
+	}
+
+	dprintf("  %p\n", buftail[0].lr);
+
+	/* frame pointers should strictly progress back up the stack
+	 * (towards higher addresses) */
+	if (tail >= buftail[0].fp)
+		return NULL;
+
+	return buftail[0].fp-1;
+}
+
+void dump_stacktrace(struct pt_regs * const regs, unsigned int depth, void *ssp)
+{
+	struct frame_tail *tail;
+	struct thread_info *real_thread_info = (struct thread_info *)
+				((unsigned long)ssp & ~(THREAD_SIZE - 1));
+
+	*current_thread_info() = *real_thread_info;
+
+	if (!current)
+		dprintf("current NULL\n");
+	else
+		dprintf("pid: %d  comm: %s\n", current->pid, current->comm);
+	dump_regs((unsigned *)regs);
+
+	if (!user_mode(regs)) {
+		struct stackframe frame;
+		frame.fp = regs->ARM_fp;
+		frame.sp = regs->ARM_sp;
+		frame.lr = regs->ARM_lr;
+		frame.pc = regs->ARM_pc;
+		dprintf("  pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
+			regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr,
+			regs->ARM_sp, regs->ARM_fp);
+		walk_stackframe(&frame, report_trace, &depth);
+		return;
+	}
+
+	tail = ((struct frame_tail *) regs->ARM_fp) - 1;
+	while (depth-- && tail && !((unsigned long) tail & 3))
+		tail = user_backtrace(tail);
+}
+
+static void debug_exec(const char *cmd, unsigned *regs, void *svc_sp)
+{
+	if (!strcmp(cmd, "pc")) {
+		dprintf(" pc %08x cpsr %08x mode %s\n",
+			regs[15], regs[16], mode_name(regs[16]));
+	} else if (!strcmp(cmd, "regs")) {
+		dump_regs(regs);
+	} else if (!strcmp(cmd, "allregs")) {
+		dump_allregs(regs);
+	} else if (!strcmp(cmd, "bt")) {
+		dump_stacktrace((struct pt_regs *)regs, 100, svc_sp);
+	} else if (!strcmp(cmd, "reboot")) {
+		if (msm_hw_reset_hook)
+			msm_hw_reset_hook();
+	} else if (!strcmp(cmd, "irqs")) {
+		dump_irqs();
+	} else if (!strcmp(cmd, "kmsg")) {
+		dump_kernel_log();
+	} else if (!strcmp(cmd, "version")) {
+		dprintf("%s\n", linux_banner);
+	} else if (!strcmp(cmd, "sleep")) {
+		no_sleep = false;
+	} else if (!strcmp(cmd, "nosleep")) {
+		no_sleep = true;
+	} else {
+		if (debug_busy) {
+			dprintf("command processor busy. trying to abort.\n");
+			debug_abort = -1;
+		} else {
+			strcpy(debug_cmd, cmd);
+			debug_busy = 1;
+		}
+		msm_trigger_irq(debug_signal_irq);
+		return;
+	}
+	debug_prompt();
+}
+
+static void sleep_timer_expired(unsigned long data)
+{
+	if (debug_clk_enabled && !no_sleep) {
+		if (debug_enable) {
+			debug_enable = 0;
+			debug_printf_nfiq(NULL,
+					"suspending fiq debugger\n");
+		}
+		ignore_next_wakeup_irq = true;
+		clk_disable(debug_clk);
+		debug_clk_enabled = false;
+		enable_wakeup_irq(init_data.wakeup_irq);
+		set_irq_wake(init_data.wakeup_irq, 1);
+	}
+	wake_unlock(&debugger_wake_lock);
+}
+
+static irqreturn_t wakeup_irq_handler(int irq, void *dev)
+{
+	if (ignore_next_wakeup_irq)
+		ignore_next_wakeup_irq = false;
+	else if (!debug_clk_enabled) {
+		wake_lock(&debugger_wake_lock);
+		clk_enable(debug_clk);
+		debug_clk_enabled = true;
+		set_irq_wake(irq, 0);
+		disable_wakeup_irq(irq);
+		mod_timer(&sleep_timer, jiffies + HZ / 2);
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t debug_irq(int irq, void *dev)
+{
+	if (!no_sleep) {
+		wake_lock(&debugger_wake_lock);
+		mod_timer(&sleep_timer, jiffies + HZ * 5);
+	}
+	if (debug_busy) {
+		struct kdbg_ctxt ctxt;
+
+		ctxt.printf = debug_printf_nfiq;
+		kernel_debugger(&ctxt, debug_cmd);
+		debug_prompt();
+
+		debug_busy = 0;
+	}
+	return IRQ_HANDLED;
+}
+
+static char debug_buf[DEBUG_MAX];
+static int debug_count;
+
+static void debug_fiq(void *data, void *regs, void *svc_sp)
+{
+	int c;
+	static int last_c;
+
+	while ((c = debug_getc()) != -1) {
+		if (!debug_enable) {
+			if ((c == 13) || (c == 10)) {
+				debug_enable = true;
+				debug_count = 0;
+				debug_prompt();
+			}
+		} else if ((c >= ' ') && (c < 127)) {
+			if (debug_count < (DEBUG_MAX - 1)) {
+				debug_buf[debug_count++] = c;
+				debug_putc(c);
+			}
+		} else if ((c == 8) || (c == 127)) {
+			if (debug_count > 0) {
+				debug_count--;
+				debug_putc(8);
+				debug_putc(' ');
+				debug_putc(8);
+			}
+		} else if ((c == 13) || (c == 10)) {
+			if (c == '\r' || (c == '\n' && last_c != '\r')) {
+				debug_putc('\r');
+				debug_putc('\n');
+			}
+			if (debug_count) {
+				debug_buf[debug_count] = 0;
+				debug_count = 0;
+				debug_exec(debug_buf, regs, svc_sp);
+			} else {
+				debug_prompt();
+			}
+		}
+		last_c = c;
+	}
+	debug_flush();
+	if (debug_enable && !no_sleep)
+		msm_trigger_irq(debug_signal_irq); /* poke sleep timer */
+}
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER_CONSOLE)
+static void debug_console_write(struct console *co,
+				const char *s, unsigned int count)
+{
+	unsigned long irq_flags;
+
+	/* disable irq's while TXing outside of FIQ context */
+	local_irq_save(irq_flags);
+	while (count--) {
+		if (*s == '\n')
+			debug_putc('\r');
+		debug_putc(*s++);
+	}
+	debug_flush();
+	local_irq_restore(irq_flags);
+}
+
+static struct console msm_serial_debug_console = {
+	.name = "debug_console",
+	.write = debug_console_write,
+	.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
+};
+#endif
+
+void msm_serial_debug_enable(int enable) {
+	debug_enable = enable;
+}
+
+void msm_serial_debug_init(unsigned int base, int irq,
+			   struct device *clk_device, int signal_irq, int wakeup_irq)
+{
+	int ret;
+	void *port;
+
+	debug_clk = clk_get(clk_device, "uart_clk");
+	if (!debug_clk)
+		return;
+
+	port = ioremap(base, 4096);
+	if (!port)
+		return;
+
+	wake_lock_init(&debugger_wake_lock, WAKE_LOCK_SUSPEND, "serial-debug");
+
+	init_data.base = base;
+	init_data.irq = irq;
+	init_data.clk_device = clk_device;
+	init_data.signal_irq = signal_irq;
+	init_data.wakeup_irq = wakeup_irq;
+	debug_port_base = (unsigned int) port;
+	debug_signal_irq = signal_irq;
+	clk_enable(debug_clk);
+	debug_port_init();
+
+	debug_printf_nfiq(NULL, "<hit enter %sto activate fiq debugger>\n",
+				no_sleep ? "" : "twice ");
+	ignore_next_wakeup_irq = !no_sleep;
+
+	msm_fiq_select(irq);
+	msm_fiq_set_handler(debug_fiq, 0);
+	msm_fiq_enable(irq);
+	clk_disable(debug_clk);
+
+	ret = request_irq(signal_irq, debug_irq,
+			  IRQF_TRIGGER_RISING, "debug", 0);
+	if (ret)
+		printk(KERN_ERR
+		       "serial_debugger: could not install signal_irq");
+
+	ret = set_irq_wake(wakeup_irq, 1);
+	if (ret)
+		pr_err("serial_debugger: could not enable wakeup\n");
+	ret = request_irq(wakeup_irq, wakeup_irq_handler,
+			  IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+			  "debug-wakeup", 0);
+	if (ret)
+		pr_err("serial_debugger: could not install wakeup irq\n");
+	if (no_sleep)
+		wakeup_irq_handler(wakeup_irq, 0);
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER_CONSOLE)
+	register_console(&msm_serial_debug_console);
+	clk_enable(debug_clk);
+#endif
+	debugger_enable = 1;
+}
+static int msm_serial_debug_remove(const char *val, struct kernel_param *kp)
+{
+	int ret;
+	static int pre_stat = 1;
+	ret = param_set_bool(val, kp);
+	if (ret)
+		return ret;
+
+	if (pre_stat == *(int *)kp->arg)
+		return 0;
+
+	pre_stat = *(int *)kp->arg;
+
+	if (*(int *)kp->arg) {
+		msm_serial_debug_init(init_data.base, init_data.irq,
+				init_data.clk_device, init_data.signal_irq,
+				init_data.wakeup_irq);
+		printk(KERN_INFO "enable FIQ serial debugger\n");
+		return 0;
+	}
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER_CONSOLE)
+	unregister_console(&msm_serial_debug_console);
+	clk_disable(debug_clk);
+#endif
+	free_irq(init_data.wakeup_irq, 0);
+	free_irq(init_data.signal_irq, 0);
+	msm_fiq_set_handler(NULL, 0);
+	msm_fiq_disable(init_data.irq);
+	msm_fiq_unselect(init_data.irq);
+	if (debug_clk_enabled)
+		clk_disable(debug_clk);
+	wake_lock_destroy(&debugger_wake_lock);
+	printk(KERN_INFO "disable FIQ serial debugger\n");
+	return 0;
+}
+module_param_call(enable, msm_serial_debug_remove, param_get_bool,
+		&debugger_enable, S_IWUSR | S_IRUGO);
diff --git a/drivers/serial/msm_serial_hs.c b/drivers/serial/msm_serial_hs.c
new file mode 100644
index 0000000..305b8b8
--- /dev/null
+++ b/drivers/serial/msm_serial_hs.c
@@ -0,0 +1,1555 @@
+/* drivers/serial/msm_serial_hs.c
+ *
+ * MSM 7k/8k High speed uart driver
+ *
+ * Copyright (c) 2007-2008 QUALCOMM Incorporated.
+ * Copyright (c) 2008 QUALCOMM USA, INC.
+ * Copyright (c) 2008 Google Inc.
+ * Modified: Nick Pelly <npelly@google.com>
+ *
+ * All source code in this file is licensed under the following license
+ * except where indicated.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+/*
+ * MSM 7k/8k High speed uart driver
+ *
+ * Has optional support for uart power management independent of linux
+ * suspend/resume:
+ *
+ * RX wakeup.
+ * UART wakeup can be triggered by RX activity (using a wakeup GPIO on the
+ * UART RX pin). This should only be used if there is not a wakeup
+ * GPIO on the UART CTS, and the first RX byte is known (for example, with the
+ * Bluetooth Texas Instruments HCILL protocol), since the first RX byte will
+ * always be lost. RTS will be asserted even while the UART is off in this mode
+ * of operation. See msm_serial_hs_platform_data.rx_wakeup_irq.
+ */
+
+#include <linux/module.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <linux/workqueue.h>
+
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <mach/hardware.h>
+#include <mach/dma.h>
+#include <mach/msm_serial_hs.h>
+
+#include "msm_serial_hs_hwreg.h"
+
+enum flush_reason {
+	FLUSH_NONE,
+	FLUSH_DATA_READY,
+	FLUSH_DATA_INVALID,  /* values after this indicate invalid data */
+	FLUSH_IGNORE = FLUSH_DATA_INVALID,
+	FLUSH_STOP,
+	FLUSH_SHUTDOWN,
+};
+
+enum msm_hs_clk_states_e {
+	MSM_HS_CLK_PORT_OFF,     /* port not in use */
+	MSM_HS_CLK_OFF,          /* clock disabled */
+	MSM_HS_CLK_REQUEST_OFF,  /* disable after TX and RX flushed */
+	MSM_HS_CLK_ON,           /* clock enabled */
+};
+
+/* Track the forced RXSTALE flush during clock off sequence.
+ * These states are only valid during MSM_HS_CLK_REQUEST_OFF */
+enum msm_hs_clk_req_off_state_e {
+	CLK_REQ_OFF_START,
+	CLK_REQ_OFF_RXSTALE_ISSUED,
+	CLK_REQ_OFF_FLUSH_ISSUED,
+	CLK_REQ_OFF_RXSTALE_FLUSHED,
+};
+
+struct msm_hs_tx {
+	unsigned int tx_ready_int_en;  /* ok to dma more tx */
+	unsigned int dma_in_flight;    /* tx dma in progress */
+	struct msm_dmov_cmd xfer;
+	dmov_box *command_ptr;
+	u32 *command_ptr_ptr;
+	dma_addr_t mapped_cmd_ptr;
+	dma_addr_t mapped_cmd_ptr_ptr;
+	int tx_count;
+	dma_addr_t dma_base;
+};
+
+struct msm_hs_rx {
+	enum flush_reason flush;
+	struct msm_dmov_cmd xfer;
+	dma_addr_t cmdptr_dmaaddr;
+	dmov_box *command_ptr;
+	u32 *command_ptr_ptr;
+	dma_addr_t mapped_cmd_ptr;
+	wait_queue_head_t wait;
+	dma_addr_t rbuffer;
+	unsigned char *buffer;
+	struct dma_pool *pool;
+	struct wake_lock wake_lock;
+	struct work_struct tty_work;
+};
+
+/* optional RX GPIO IRQ low power wakeup */
+struct msm_hs_rx_wakeup {
+	int irq;  /* < 0 indicates low power wakeup disabled */
+	unsigned char ignore;  /* bool */
+
+	/* bool: inject char into rx tty on wakeup */
+	unsigned char inject_rx;
+	char rx_to_inject;
+};
+
+struct msm_hs_port {
+	struct uart_port uport;
+	unsigned long imr_reg;  /* shadow value of UARTDM_IMR */
+	struct clk *clk;
+	struct msm_hs_tx tx;
+	struct msm_hs_rx rx;
+
+	int dma_tx_channel;
+	int dma_rx_channel;
+	int dma_tx_crci;
+	int dma_rx_crci;
+
+	struct hrtimer clk_off_timer;  /* to poll TXEMT before clock off */
+	ktime_t clk_off_delay;
+	enum msm_hs_clk_states_e clk_state;
+	enum msm_hs_clk_req_off_state_e clk_req_off_state;
+
+	struct msm_hs_rx_wakeup rx_wakeup;
+	/* optional callback to exit low power mode */
+	void (*exit_lpm_cb)(struct uart_port *);
+
+	struct wake_lock dma_wake_lock;  /* held while any DMA active */
+};
+
+#define MSM_UARTDM_BURST_SIZE 16   /* DM burst size (in bytes) */
+#define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE
+#define UARTDM_RX_BUF_SIZE 512
+
+#define UARTDM_NR 2
+
+static struct msm_hs_port q_uart_port[UARTDM_NR];
+static struct platform_driver msm_serial_hs_platform_driver;
+static struct uart_driver msm_hs_driver;
+static struct uart_ops msm_hs_ops;
+static struct workqueue_struct *msm_hs_workqueue;
+
+#define UARTDM_TO_MSM(uart_port) \
+	container_of((uart_port), struct msm_hs_port, uport)
+
+static inline unsigned int use_low_power_rx_wakeup(struct msm_hs_port *msm_uport)
+{
+	return (msm_uport->rx_wakeup.irq >= 0);
+}
+
+static inline unsigned int msm_hs_read(struct uart_port *uport,
+				       unsigned int offset)
+{
+	return ioread32(uport->membase + offset);
+}
+
+static inline void msm_hs_write(struct uart_port *uport, unsigned int offset,
+				 unsigned int value)
+{
+	iowrite32(value, uport->membase + offset);
+}
+
+static void msm_hs_release_port(struct uart_port *port)
+{
+}
+
+static int msm_hs_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static int __devexit msm_hs_remove(struct platform_device *pdev)
+{
+
+	struct msm_hs_port *msm_uport;
+	struct device *dev;
+
+	if (pdev->id < 0 || pdev->id >= UARTDM_NR) {
+		printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id);
+		return -EINVAL;
+	}
+
+	msm_uport = &q_uart_port[pdev->id];
+	dev = msm_uport->uport.dev;
+
+	dma_unmap_single(dev, msm_uport->rx.mapped_cmd_ptr, sizeof(dmov_box),
+			 DMA_TO_DEVICE);
+	dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer,
+		      msm_uport->rx.rbuffer);
+	dma_pool_destroy(msm_uport->rx.pool);
+
+	dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32 *),
+			 DMA_TO_DEVICE);
+	dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32 *),
+			 DMA_TO_DEVICE);
+	dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box),
+			 DMA_TO_DEVICE);
+
+	wake_lock_destroy(&msm_uport->rx.wake_lock);
+	wake_lock_destroy(&msm_uport->dma_wake_lock);
+
+	uart_remove_one_port(&msm_hs_driver, &msm_uport->uport);
+	clk_put(msm_uport->clk);
+
+	/* Free the tx resources */
+	kfree(msm_uport->tx.command_ptr);
+	kfree(msm_uport->tx.command_ptr_ptr);
+
+	/* Free the rx resources */
+	kfree(msm_uport->rx.command_ptr);
+	kfree(msm_uport->rx.command_ptr_ptr);
+
+	iounmap(msm_uport->uport.membase);
+
+	return 0;
+}
+
+static int msm_hs_init_clk_locked(struct uart_port *uport)
+{
+	int ret;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	wake_lock(&msm_uport->dma_wake_lock);
+	ret = clk_enable(msm_uport->clk);
+	if (ret) {
+		printk(KERN_ERR "Error could not turn on UART clk\n");
+		return ret;
+	}
+
+	/* Set up the MREG/NREG/DREG/MNDREG */
+	ret = clk_set_rate(msm_uport->clk, uport->uartclk);
+	if (ret) {
+		printk(KERN_WARNING "Error setting clock rate on UART\n");
+		return ret;
+	}
+
+	msm_uport->clk_state = MSM_HS_CLK_ON;
+	return 0;
+}
+
+/* Enable and Disable clocks  (Used for power management) */
+static void msm_hs_pm(struct uart_port *uport, unsigned int state,
+		      unsigned int oldstate)
+{
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	if (use_low_power_rx_wakeup(msm_uport) || msm_uport->exit_lpm_cb)
+	    return;  /* ignore linux PM states, use msm_hs_request_clock API */
+
+	switch (state) {
+	case 0:
+		clk_enable(msm_uport->clk);
+		break;
+	case 3:
+		clk_disable(msm_uport->clk);
+		break;
+	default:
+		printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
+	}
+}
+
+/*
+ * programs the UARTDM_CSR register with correct bit rates
+ *
+ * Interrupts should be disabled before we are called, as
+ * we modify Set Baud rate
+ * Set receive stale interrupt level, dependant on Bit Rate
+ * Goal is to have around 8 ms before indicate stale.
+ * roundup (((Bit Rate * .008) / 10) + 1
+ */
+static void msm_hs_set_bps_locked(struct uart_port *uport,
+			       unsigned int bps)
+{
+	unsigned long rxstale;
+	unsigned long data;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	switch (bps) {
+	case 300:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0x00);
+		rxstale = 1;
+		break;
+	case 600:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0x11);
+		rxstale = 1;
+		break;
+	case 1200:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0x22);
+		rxstale = 1;
+		break;
+	case 2400:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0x33);
+		rxstale = 1;
+		break;
+	case 4800:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0x44);
+		rxstale = 1;
+		break;
+	case 9600:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0x55);
+		rxstale = 2;
+		break;
+	case 14400:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0x66);
+		rxstale = 3;
+		break;
+	case 19200:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0x77);
+		rxstale = 4;
+		break;
+	case 28800:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0x88);
+		rxstale = 6;
+		break;
+	case 38400:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0x99);
+		rxstale = 8;
+		break;
+	case 57600:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0xaa);
+		rxstale = 16;
+		break;
+	case 76800:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0xbb);
+		rxstale = 16;
+		break;
+	case 115200:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0xcc);
+		rxstale = 31;
+		break;
+	case 230400:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0xee);
+		rxstale = 31;
+		break;
+	case 460800:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0xff);
+		rxstale = 31;
+		break;
+	case 4000000:
+	case 3686400:
+	case 3200000:
+	case 3500000:
+	case 3000000:
+	case 2500000:
+	case 1500000:
+	case 1152000:
+	case 1000000:
+	case 921600:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0xff);
+		rxstale = 31;
+		break;
+	default:
+		msm_hs_write(uport, UARTDM_CSR_ADDR, 0xff);
+		/* default to 9600 */
+		bps = 9600;
+		rxstale = 2;
+		break;
+	}
+	if (bps > 460800) {
+		uport->uartclk = bps * 16;
+	} else {
+		uport->uartclk = 7372800;
+	}
+	if (clk_set_rate(msm_uport->clk, uport->uartclk)) {
+		printk(KERN_WARNING "Error setting clock rate on UART\n");
+		return;
+	}
+
+	data = rxstale & UARTDM_IPR_STALE_LSB_BMSK;
+	data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
+
+	msm_hs_write(uport, UARTDM_IPR_ADDR, data);
+}
+
+/*
+ * termios :  new ktermios
+ * oldtermios:  old ktermios previous setting
+ *
+ * Configure the serial port
+ */
+static void msm_hs_set_termios(struct uart_port *uport,
+				   struct ktermios *termios,
+				   struct ktermios *oldtermios)
+{
+	unsigned int bps;
+	unsigned long data;
+	unsigned long flags;
+	unsigned int c_cflag = termios->c_cflag;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	
+	spin_lock_irqsave(&uport->lock, flags);
+	clk_enable(msm_uport->clk);
+
+	/* 300 is the minimum baud support by the driver  */
+	bps = uart_get_baud_rate(uport, termios, oldtermios, 200, 4000000);
+
+	/* Temporary remapping  200 BAUD to 3.2 mbps */
+	if (bps == 200)
+		bps = 3200000;
+
+	msm_hs_set_bps_locked(uport, bps);
+
+	data = msm_hs_read(uport, UARTDM_MR2_ADDR);
+	data &= ~UARTDM_MR2_PARITY_MODE_BMSK;
+	/* set parity */
+	if (PARENB == (c_cflag & PARENB)) {
+		if (PARODD == (c_cflag & PARODD)) {
+			data |= ODD_PARITY;
+		} else if (CMSPAR == (c_cflag & CMSPAR)) {
+			data |= SPACE_PARITY;
+		} else {
+			data |= EVEN_PARITY;
+		}
+	}
+
+	/* Set bits per char */
+	data &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK;
+
+	switch (c_cflag & CSIZE) {
+	case CS5:
+		data |= FIVE_BPC;
+		break;
+	case CS6:
+		data |= SIX_BPC;
+		break;
+	case CS7:
+		data |= SEVEN_BPC;
+		break;
+	default:
+		data |= EIGHT_BPC;
+		break;
+	}
+	/* stop bits */
+	if (c_cflag & CSTOPB) {
+		data |= STOP_BIT_TWO;
+	} else {
+		/* otherwise 1 stop bit */
+		data |= STOP_BIT_ONE;
+	}
+	data |= UARTDM_MR2_ERROR_MODE_BMSK;
+	/* write parity/bits per char/stop bit configuration */
+	msm_hs_write(uport, UARTDM_MR2_ADDR, data);
+
+	/* Configure HW flow control */
+	data = msm_hs_read(uport, UARTDM_MR1_ADDR);
+
+	data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
+
+	if (c_cflag & CRTSCTS) {
+		data |= UARTDM_MR1_CTS_CTL_BMSK;
+		data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+	}
+
+	msm_hs_write(uport, UARTDM_MR1_ADDR, data);
+
+	uport->ignore_status_mask = termios->c_iflag & INPCK;
+	uport->ignore_status_mask |= termios->c_iflag & IGNPAR;
+	uport->read_status_mask = (termios->c_cflag & CREAD);
+
+	msm_hs_write(uport, UARTDM_IMR_ADDR, 0);
+
+	/* Set Transmit software time out */
+	uart_update_timeout(uport, c_cflag, bps);
+
+	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
+	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
+
+	if (msm_uport->rx.flush == FLUSH_NONE) {
+		wake_lock(&msm_uport->rx.wake_lock);
+		msm_uport->rx.flush = FLUSH_IGNORE;
+		msm_dmov_flush(msm_uport->dma_rx_channel);
+	}
+
+	msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+
+	clk_disable(msm_uport->clk);
+	spin_unlock_irqrestore(&uport->lock, flags);
+}
+
+/*
+ *  Standard API, Transmitter
+ *  Any character in the transmit shift register is sent
+ */
+static unsigned int msm_hs_tx_empty(struct uart_port *uport)
+{
+	unsigned int data;
+	unsigned int ret = 0;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	clk_enable(msm_uport->clk);
+
+	data = msm_hs_read(uport, UARTDM_SR_ADDR);
+	if (data & UARTDM_SR_TXEMT_BMSK)
+		ret = TIOCSER_TEMT;
+
+	clk_disable(msm_uport->clk);
+
+	return ret;
+}
+
+/*
+ *  Standard API, Stop transmitter.
+ *  Any character in the transmit shift register is sent as
+ *  well as the current data mover transfer .
+ */
+static void msm_hs_stop_tx_locked(struct uart_port *uport)
+{
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	msm_uport->tx.tx_ready_int_en = 0;
+}
+
+/*
+ *  Standard API, Stop receiver as soon as possible.
+ *
+ *  Function immediately terminates the operation of the
+ *  channel receiver and any incoming characters are lost. None
+ *  of the receiver status bits are affected by this command and
+ *  characters that are already in the receive FIFO there.
+ */
+static void msm_hs_stop_rx_locked(struct uart_port *uport)
+{
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	unsigned int data;
+
+	clk_enable(msm_uport->clk);
+
+	/* disable dlink */
+	data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+	data &= ~UARTDM_RX_DM_EN_BMSK;
+	msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+
+	/* Disable the receiver */
+	if (msm_uport->rx.flush == FLUSH_NONE) {
+		wake_lock(&msm_uport->rx.wake_lock);
+		msm_dmov_flush(msm_uport->dma_rx_channel);
+	}
+	if (msm_uport->rx.flush != FLUSH_SHUTDOWN)
+		msm_uport->rx.flush = FLUSH_STOP;
+
+	clk_disable(msm_uport->clk);
+}
+
+/*  Transmit the next chunk of data */
+static void msm_hs_submit_tx_locked(struct uart_port *uport)
+{
+	int left;
+	int tx_count;
+	dma_addr_t src_addr;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	struct msm_hs_tx *tx = &msm_uport->tx;
+	struct circ_buf *tx_buf = &msm_uport->uport.state->xmit;
+
+	if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) {
+		msm_hs_stop_tx_locked(uport);
+		return;
+	}
+
+	tx->dma_in_flight = 1;
+
+	tx_count = uart_circ_chars_pending(tx_buf);
+
+	if (UARTDM_TX_BUF_SIZE < tx_count)
+		tx_count = UARTDM_TX_BUF_SIZE;
+
+	left = UART_XMIT_SIZE - tx_buf->tail;
+
+	if (tx_count > left)
+		tx_count = left;
+
+	src_addr = tx->dma_base + tx_buf->tail;
+	dma_sync_single_for_device(uport->dev, src_addr, tx_count,
+				   DMA_TO_DEVICE);
+
+	tx->command_ptr->num_rows = (((tx_count + 15) >> 4) << 16) |
+				     ((tx_count + 15) >> 4);
+	tx->command_ptr->src_row_addr = src_addr;
+
+	dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr,
+				   sizeof(dmov_box), DMA_TO_DEVICE);
+
+	*tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
+
+	dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
+				   sizeof(u32 *), DMA_TO_DEVICE);
+
+	/* Save tx_count to use in Callback */
+	tx->tx_count = tx_count;
+	msm_hs_write(uport, UARTDM_NCF_TX_ADDR, tx_count);
+
+	/* Disable the tx_ready interrupt */
+	msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK;
+	msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+	msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
+}
+
+/* Start to receive the next chunk of data */
+static void msm_hs_start_rx_locked(struct uart_port *uport)
+{
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
+	msm_hs_write(uport, UARTDM_DMRX_ADDR, UARTDM_RX_BUF_SIZE);
+	msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_ENABLE);
+	msm_uport->imr_reg |= UARTDM_ISR_RXLEV_BMSK;
+	msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+
+	msm_uport->rx.flush = FLUSH_NONE;
+	msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel, &msm_uport->rx.xfer);
+
+	/* might have finished RX and be ready to clock off */
+	hrtimer_start(&msm_uport->clk_off_timer, msm_uport->clk_off_delay,
+			HRTIMER_MODE_REL);
+}
+
+/* Enable the transmitter Interrupt */
+static void msm_hs_start_tx_locked(struct uart_port *uport )
+{
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	clk_enable(msm_uport->clk);
+
+	if (msm_uport->exit_lpm_cb)
+		msm_uport->exit_lpm_cb(uport);
+
+	if (msm_uport->tx.tx_ready_int_en == 0) {
+		msm_uport->tx.tx_ready_int_en = 1;
+		msm_hs_submit_tx_locked(uport);
+	}
+
+	clk_disable(msm_uport->clk);
+}
+
+/*
+ *  This routine is called when we are done with a DMA transfer
+ *
+ *  This routine is registered with Data mover when we set
+ *  up a Data Mover transfer. It is called from Data mover ISR
+ *  when the DMA transfer is done.
+ */
+static void msm_hs_dmov_tx_callback(struct msm_dmov_cmd *cmd_ptr,
+					unsigned int result,
+					struct msm_dmov_errdata *err)
+{
+	unsigned long flags;
+	struct msm_hs_port *msm_uport;
+
+	WARN_ON(result != 0x80000002);  /* DMA did not finish properly */
+	msm_uport = container_of(cmd_ptr, struct msm_hs_port, tx.xfer);
+
+	spin_lock_irqsave(&msm_uport->uport.lock, flags);
+	clk_enable(msm_uport->clk);
+
+	msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
+	msm_hs_write(&msm_uport->uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+
+	clk_disable(msm_uport->clk);
+	spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
+}
+
+/*
+ * This routine is called when we are done with a DMA transfer or the
+ * a flush has been sent to the data mover driver.
+ *
+ * This routine is registered with Data mover when we set up a Data Mover
+ *  transfer. It is called from Data mover ISR when the DMA transfer is done.
+ */
+static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
+					unsigned int result,
+					struct msm_dmov_errdata *err)
+{
+	int retval;
+	int rx_count;
+	unsigned long status;
+	unsigned int error_f = 0;
+	unsigned long flags;
+	unsigned int flush;
+	struct tty_struct *tty;
+	struct uart_port *uport;
+	struct msm_hs_port *msm_uport;
+
+	msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer);
+	uport = &msm_uport->uport;
+
+	spin_lock_irqsave(&uport->lock, flags);
+	clk_enable(msm_uport->clk);
+
+	tty = uport->state->port.tty;
+
+	msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
+
+	status = msm_hs_read(uport, UARTDM_SR_ADDR);
+
+	/* overflow is not connect to data in a FIFO */
+	if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) &&
+		     (uport->read_status_mask & CREAD))) {
+		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+		uport->icount.buf_overrun++;
+		error_f = 1;
+	}
+
+	if (!(uport->ignore_status_mask & INPCK))
+		status = status & ~(UARTDM_SR_PAR_FRAME_BMSK);
+
+	if (unlikely(status & UARTDM_SR_PAR_FRAME_BMSK)) {
+		/* Can not tell difference between parity & frame error */
+		uport->icount.parity++;
+		error_f = 1;
+		if (uport->ignore_status_mask & IGNPAR)
+			tty_insert_flip_char(tty, 0, TTY_PARITY);
+	}
+
+	if (error_f)
+		msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS);
+
+	if (msm_uport->clk_req_off_state == CLK_REQ_OFF_FLUSH_ISSUED)
+		msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_FLUSHED;
+
+	flush = msm_uport->rx.flush;
+	if (flush == FLUSH_IGNORE)
+		msm_hs_start_rx_locked(uport);
+	if (flush == FLUSH_STOP)
+		msm_uport->rx.flush = FLUSH_SHUTDOWN;
+	if (flush >= FLUSH_DATA_INVALID)
+		goto out;
+
+	rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR);
+
+	if (0 != (uport->read_status_mask & CREAD)) {
+		retval = tty_insert_flip_string(tty, msm_uport->rx.buffer,
+						rx_count);
+		BUG_ON(retval != rx_count);
+	}
+
+	msm_hs_start_rx_locked(uport);
+
+out:
+	clk_disable(msm_uport->clk);
+	/* release wakelock in 500ms, not immediately, because higher layers
+	 * don't always take wakelocks when they should */
+	wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
+	spin_unlock_irqrestore(&uport->lock, flags);
+
+	if (flush < FLUSH_DATA_INVALID)
+		queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work);
+}
+
+static void msm_hs_tty_flip_buffer_work(struct work_struct *work)
+{
+	struct msm_hs_port *msm_uport =
+			container_of(work, struct msm_hs_port, rx.tty_work);
+	struct tty_struct *tty = msm_uport->uport.state->port.tty;
+
+	tty_flip_buffer_push(tty);
+}
+
+/*
+ *  Standard API, Current states of modem control inputs
+ *
+ * Since CTS can be handled entirely by HARDWARE we always
+ * indicate clear to send and count on the TX FIFO to block when
+ * it fills up.
+ *
+ * - TIOCM_DCD
+ * - TIOCM_CTS
+ * - TIOCM_DSR
+ * - TIOCM_RI
+ *  (Unsupported) DCD and DSR will return them high. RI will return low.
+ */
+static unsigned int msm_hs_get_mctrl_locked(struct uart_port *uport)
+{
+	return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
+}
+
+/*
+ * True enables UART auto RFR, which indicates we are ready for data if the RX
+ * buffer is not full. False disables auto RFR, and deasserts RFR to indicate
+ * we are not ready for data. Must be called with UART clock on.
+ */
+static void set_rfr_locked(struct uart_port *uport, int auto_rfr) {
+	unsigned int data;
+
+	data = msm_hs_read(uport, UARTDM_MR1_ADDR);
+
+	if (auto_rfr) {
+		/* enable auto ready-for-receiving */
+		data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+		msm_hs_write(uport, UARTDM_MR1_ADDR, data);
+	} else {
+		/* disable auto ready-for-receiving */
+		data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
+		msm_hs_write(uport, UARTDM_MR1_ADDR, data);
+		/* RFR is active low, set high */
+		msm_hs_write(uport, UARTDM_CR_ADDR, RFR_HIGH);
+	}
+}
+
+/*
+ *  Standard API, used to set or clear RFR
+ */
+static void msm_hs_set_mctrl_locked(struct uart_port *uport,
+				    unsigned int mctrl)
+{
+	unsigned int auto_rfr;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	clk_enable(msm_uport->clk);
+
+	auto_rfr = TIOCM_RTS & mctrl ? 1 : 0;
+	set_rfr_locked(uport, auto_rfr);
+
+	clk_disable(msm_uport->clk);
+}
+
+/* Standard API, Enable modem status (CTS) interrupt  */
+static void msm_hs_enable_ms_locked(struct uart_port *uport)
+{
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	clk_enable(msm_uport->clk);
+
+	/* Enable DELTA_CTS Interrupt */
+	msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK;
+	msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+
+	clk_disable(msm_uport->clk);
+
+}
+
+/*
+ *  Standard API, Break Signal
+ *
+ * Control the transmission of a break signal. ctl eq 0 => break
+ * signal terminate ctl ne 0 => start break signal
+ */
+static void msm_hs_break_ctl(struct uart_port *uport, int ctl)
+{
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	clk_enable(msm_uport->clk);
+	msm_hs_write(uport, UARTDM_CR_ADDR, ctl ? START_BREAK : STOP_BREAK);
+	clk_disable(msm_uport->clk);
+}
+
+static void msm_hs_config_port(struct uart_port *uport, int cfg_flags)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uport->lock, flags);
+	if (cfg_flags & UART_CONFIG_TYPE) {
+		uport->type = PORT_MSM;
+		msm_hs_request_port(uport);
+	}
+	spin_unlock_irqrestore(&uport->lock, flags);
+}
+
+/*  Handle CTS changes (Called from interrupt handler) */
+static void msm_hs_handle_delta_cts(struct uart_port *uport)
+{
+	unsigned long flags;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	spin_lock_irqsave(&uport->lock, flags);
+	clk_enable(msm_uport->clk);
+
+	/* clear interrupt */
+	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS);
+	uport->icount.cts++;
+
+	clk_disable(msm_uport->clk);
+	spin_unlock_irqrestore(&uport->lock, flags);
+
+	/* clear the IOCTL TIOCMIWAIT if called */
+	wake_up_interruptible(&uport->state->port.delta_msr_wait);
+}
+
+/* check if the TX path is flushed, and if so clock off
+ * returns 0 did not clock off, need to retry (still sending final byte)
+ *        -1 did not clock off, do not retry
+ *         1 if we clocked off
+ */
+static int msm_hs_check_clock_off_locked(struct uart_port *uport)
+{
+	unsigned long sr_status;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	struct circ_buf *tx_buf = &uport->state->xmit;
+
+	/* Cancel if tx tty buffer is not empty, dma is in flight,
+	 * or tx fifo is not empty, or rx fifo is not empty */
+	if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF ||
+	    !uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight ||
+	    (msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) ||
+            !(msm_uport->imr_reg & UARTDM_ISR_RXLEV_BMSK))  {
+		return -1;
+	}
+
+	/* Make sure the uart is finished with the last byte */
+	sr_status = msm_hs_read(uport, UARTDM_SR_ADDR);
+	if (!(sr_status & UARTDM_SR_TXEMT_BMSK))
+		return 0;  /* retry */
+
+	/* Make sure forced RXSTALE flush complete */
+	switch (msm_uport->clk_req_off_state) {
+	case CLK_REQ_OFF_START:
+		msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED;
+		msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT);
+		return 0;  /* RXSTALE flush not complete - retry */
+	case CLK_REQ_OFF_RXSTALE_ISSUED:
+	case CLK_REQ_OFF_FLUSH_ISSUED:
+		return 0;  /* RXSTALE flush not complete - retry */
+	case CLK_REQ_OFF_RXSTALE_FLUSHED:
+		break;  /* continue */
+	}
+
+	if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
+		if (msm_uport->rx.flush == FLUSH_NONE)
+			msm_hs_stop_rx_locked(uport);
+		return 0;  /* come back later to really clock off */
+	}
+
+	/* we really want to clock off */
+	clk_disable(msm_uport->clk);
+	msm_uport->clk_state = MSM_HS_CLK_OFF;
+	wake_unlock(&msm_uport->dma_wake_lock);
+	if (use_low_power_rx_wakeup(msm_uport)) {
+		msm_uport->rx_wakeup.ignore = 1;
+		enable_irq(msm_uport->rx_wakeup.irq);
+	}
+	return 1;
+}
+
+static enum hrtimer_restart msm_hs_clk_off_retry(struct hrtimer *timer) {
+	unsigned long flags;
+	int ret = HRTIMER_NORESTART;
+	struct msm_hs_port *msm_uport = container_of(timer, struct msm_hs_port,
+						     clk_off_timer);
+	struct uart_port *uport = &msm_uport->uport;
+
+	spin_lock_irqsave(&uport->lock, flags);
+
+	if (!msm_hs_check_clock_off_locked(uport)) {
+		hrtimer_forward_now(timer, msm_uport->clk_off_delay);
+		ret = HRTIMER_RESTART;
+	}
+
+	spin_unlock_irqrestore(&uport->lock, flags);
+
+	return ret;
+}
+
+static irqreturn_t msm_hs_isr(int irq, void *dev)
+{
+	unsigned long flags;
+	unsigned long isr_status;
+	struct msm_hs_port *msm_uport = (struct msm_hs_port *)dev;
+	struct uart_port *uport = &msm_uport->uport;
+	struct circ_buf *tx_buf = &uport->state->xmit;
+	struct msm_hs_tx *tx = &msm_uport->tx;
+	struct msm_hs_rx *rx = &msm_uport->rx;
+
+	spin_lock_irqsave(&uport->lock, flags);
+
+	isr_status = msm_hs_read(uport, UARTDM_MISR_ADDR);
+
+	/* Uart RX starting */
+	if (isr_status & UARTDM_ISR_RXLEV_BMSK) {
+		wake_lock(&rx->wake_lock);  /* hold wakelock while rx dma */
+		msm_uport->imr_reg &= ~UARTDM_ISR_RXLEV_BMSK;
+		msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+	}
+	/* Stale rx interrupt */
+	if (isr_status & UARTDM_ISR_RXSTALE_BMSK) {
+		msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
+		msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
+
+		if (msm_uport->clk_req_off_state == CLK_REQ_OFF_RXSTALE_ISSUED)
+			msm_uport->clk_req_off_state =
+					CLK_REQ_OFF_FLUSH_ISSUED;
+		if (rx->flush == FLUSH_NONE) {
+			rx->flush = FLUSH_DATA_READY;
+			msm_dmov_flush(msm_uport->dma_rx_channel);
+		}
+	}
+	/* tx ready interrupt */
+	if (isr_status & UARTDM_ISR_TX_READY_BMSK) {
+		/* Clear  TX Ready */
+		msm_hs_write(uport, UARTDM_CR_ADDR, CLEAR_TX_READY);
+
+		if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
+			msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK;
+			msm_hs_write(uport, UARTDM_IMR_ADDR,
+				     msm_uport->imr_reg);
+		}
+	
+		/* Complete DMA TX transactions and submit new transactions */
+		tx_buf->tail = (tx_buf->tail + tx->tx_count) & ~UART_XMIT_SIZE;
+
+		tx->dma_in_flight = 0;
+
+		uport->icount.tx += tx->tx_count;
+		if (tx->tx_ready_int_en)
+			msm_hs_submit_tx_locked(uport);
+
+		if (uart_circ_chars_pending(tx_buf) < WAKEUP_CHARS)
+			uart_write_wakeup(uport);
+	}
+	if (isr_status & UARTDM_ISR_TXLEV_BMSK) {
+		/* TX FIFO is empty */
+		msm_uport->imr_reg &= ~UARTDM_ISR_TXLEV_BMSK;
+		msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+		if (!msm_hs_check_clock_off_locked(uport))
+			hrtimer_start(&msm_uport->clk_off_timer,
+				      msm_uport->clk_off_delay,
+				      HRTIMER_MODE_REL);
+	}
+
+	/* Change in CTS interrupt */
+	if (isr_status & UARTDM_ISR_DELTA_CTS_BMSK)
+		msm_hs_handle_delta_cts(uport);
+
+	spin_unlock_irqrestore(&uport->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+void msm_hs_request_clock_off_locked(struct uart_port *uport) {
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	if (msm_uport->clk_state == MSM_HS_CLK_ON) {
+		msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF;
+		msm_uport->clk_req_off_state = CLK_REQ_OFF_START;
+		if (!use_low_power_rx_wakeup(msm_uport))
+			set_rfr_locked(uport, 0);
+		msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK;
+		msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+	}
+}
+EXPORT_SYMBOL(msm_hs_request_clock_off_locked);
+
+/* request to turn off uart clock once pending TX is flushed */
+void msm_hs_request_clock_off(struct uart_port *uport) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&uport->lock, flags);
+	msm_hs_request_clock_off_locked(uport);
+	spin_unlock_irqrestore(&uport->lock, flags);
+}
+EXPORT_SYMBOL(msm_hs_request_clock_off);
+
+void msm_hs_request_clock_on_locked(struct uart_port *uport) {
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	unsigned int data;
+
+	switch (msm_uport->clk_state) {
+	case MSM_HS_CLK_OFF:
+		wake_lock(&msm_uport->dma_wake_lock);
+		clk_enable(msm_uport->clk);
+		disable_irq_nosync(msm_uport->rx_wakeup.irq);
+		/* fall-through */
+	case MSM_HS_CLK_REQUEST_OFF:
+		if (msm_uport->rx.flush == FLUSH_STOP ||
+				msm_uport->rx.flush == FLUSH_SHUTDOWN) {
+			msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
+			data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+			data |= UARTDM_RX_DM_EN_BMSK;
+			msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+		}
+		hrtimer_try_to_cancel(&msm_uport->clk_off_timer);
+		if (msm_uport->rx.flush == FLUSH_SHUTDOWN)
+			msm_hs_start_rx_locked(uport);
+		if (!use_low_power_rx_wakeup(msm_uport))
+			set_rfr_locked(uport, 1);
+		if (msm_uport->rx.flush == FLUSH_STOP)
+			msm_uport->rx.flush = FLUSH_IGNORE;
+		msm_uport->clk_state = MSM_HS_CLK_ON;
+		break;
+	case MSM_HS_CLK_ON: break;
+	case MSM_HS_CLK_PORT_OFF: break;
+	}
+}
+EXPORT_SYMBOL(msm_hs_request_clock_on_locked);
+
+void msm_hs_request_clock_on(struct uart_port *uport) {
+	unsigned long flags;
+	spin_lock_irqsave(&uport->lock, flags);
+	msm_hs_request_clock_on_locked(uport);
+	spin_unlock_irqrestore(&uport->lock, flags);
+}
+EXPORT_SYMBOL(msm_hs_request_clock_on);
+
+static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev)
+{
+	unsigned int wakeup = 0;
+	unsigned long flags;
+	struct msm_hs_port *msm_uport = (struct msm_hs_port *)dev;
+	struct uart_port *uport = &msm_uport->uport;
+	struct tty_struct *tty = NULL;
+
+	spin_lock_irqsave(&uport->lock, flags);
+	if (msm_uport->clk_state == MSM_HS_CLK_OFF) {
+		/* ignore the first irq - it is a pending irq that occured
+		 * before enable_irq() */
+		if (msm_uport->rx_wakeup.ignore)
+			msm_uport->rx_wakeup.ignore = 0;
+		else
+			wakeup = 1;
+	}
+
+	if (wakeup) {
+		/* the uart was clocked off during an rx, wake up and
+		 * optionally inject char into tty rx */
+		msm_hs_request_clock_on_locked(uport);
+		if (msm_uport->rx_wakeup.inject_rx) {
+			tty = uport->state->port.tty;
+			tty_insert_flip_char(tty,
+					     msm_uport->rx_wakeup.rx_to_inject,
+					     TTY_NORMAL);
+			queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work);
+		}
+	}
+
+	spin_unlock_irqrestore(&uport->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static const char *msm_hs_type(struct uart_port *port)
+{
+	return ("MSM HS UART");
+}
+
+/* Called when port is opened */
+static int msm_hs_startup(struct uart_port *uport)
+{
+	int ret;
+	int rfr_level;
+	unsigned long flags;
+	unsigned int data;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	struct circ_buf *tx_buf = &uport->state->xmit;
+	struct msm_hs_tx *tx = &msm_uport->tx;
+	struct msm_hs_rx *rx = &msm_uport->rx;
+
+	rfr_level = uport->fifosize;
+	if (rfr_level > 16)
+		rfr_level -= 16;
+
+	tx->dma_base = dma_map_single(uport->dev, tx_buf->buf, UART_XMIT_SIZE,
+				      DMA_TO_DEVICE);
+
+	/* do not let tty layer execute RX in global workqueue, use a
+	 * dedicated workqueue managed by this driver */
+	uport->state->port.tty->low_latency = 1;
+
+	/* turn on uart clk */
+	ret = msm_hs_init_clk_locked(uport);
+	if (unlikely(ret))
+		return ret;
+
+	/* Set auto RFR Level */
+	data = msm_hs_read(uport, UARTDM_MR1_ADDR);
+	data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
+	data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK;
+	data |= (UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2));
+	data |= (UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level);
+	msm_hs_write(uport, UARTDM_MR1_ADDR, data);
+
+	/* Make sure RXSTALE count is non-zero */
+	data = msm_hs_read(uport, UARTDM_IPR_ADDR);
+	if (!data) {
+		data |= 0x1f & UARTDM_IPR_STALE_LSB_BMSK;
+		msm_hs_write(uport, UARTDM_IPR_ADDR, data);
+	}
+
+	/* Enable Data Mover Mode */
+	data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK;
+	msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+
+	/* Reset TX */
+	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
+	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
+	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS);
+	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_BREAK_INT);
+	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
+	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS);
+	msm_hs_write(uport, UARTDM_CR_ADDR, RFR_LOW);
+	/* Turn on Uart Receiver */
+	msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_EN_BMSK);
+
+	/* Turn on Uart Transmitter */
+	msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_EN_BMSK);
+
+	/* Initialize the tx */
+	tx->tx_ready_int_en = 0;
+	tx->dma_in_flight = 0;
+
+	tx->xfer.complete_func = msm_hs_dmov_tx_callback;
+	tx->xfer.execute_func = NULL;
+
+	tx->command_ptr->cmd = CMD_LC |
+	    CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX;
+
+	tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16)
+					   | (MSM_UARTDM_BURST_SIZE);
+
+	tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16);
+
+	tx->command_ptr->dst_row_addr =
+	    msm_uport->uport.mapbase + UARTDM_TF_ADDR;
+
+
+	/* Turn on Uart Receive */
+	rx->xfer.complete_func = msm_hs_dmov_rx_callback;
+	rx->xfer.execute_func = NULL;
+
+	rx->command_ptr->cmd = CMD_LC |
+	    CMD_SRC_CRCI(msm_uport->dma_rx_crci) | CMD_MODE_BOX;
+
+	rx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16)
+					   | (MSM_UARTDM_BURST_SIZE);
+	rx->command_ptr->row_offset =  MSM_UARTDM_BURST_SIZE;
+	rx->command_ptr->src_row_addr = uport->mapbase + UARTDM_RF_ADDR;
+
+
+	msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK;
+	/* Enable reading the current CTS, no harm even if CTS is ignored */
+	msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK;
+
+	msm_hs_write(uport, UARTDM_TFWR_ADDR, 0);  /* TXLEV on empty TX fifo */
+
+
+	ret = request_irq(uport->irq, msm_hs_isr, IRQF_TRIGGER_HIGH,
+			  "msm_hs_uart", msm_uport);
+	if (unlikely(ret))
+		return ret;
+	if (use_low_power_rx_wakeup(msm_uport)) {
+		ret = request_irq(msm_uport->rx_wakeup.irq,
+				  msm_hs_rx_wakeup_isr,
+				  IRQF_TRIGGER_FALLING,
+				  "msm_hs_rx_wakeup", msm_uport);
+		if (unlikely(ret))
+			return ret;
+		disable_irq(msm_uport->rx_wakeup.irq);
+	}
+
+	spin_lock_irqsave(&uport->lock, flags);
+
+	msm_hs_write(uport, UARTDM_RFWR_ADDR, 0);
+	msm_hs_start_rx_locked(uport);
+
+	spin_unlock_irqrestore(&uport->lock, flags);
+
+	return 0;
+}
+
+/* Initialize tx and rx data structures */
+static int uartdm_init_port(struct uart_port *uport)
+{
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	struct msm_hs_tx *tx = &msm_uport->tx;
+	struct msm_hs_rx *rx = &msm_uport->rx;
+
+	/* Allocate the command pointer. Needs to be 64 bit aligned */
+	tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
+
+	tx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA);
+
+	if (!tx->command_ptr || !tx->command_ptr_ptr)
+		return -ENOMEM;
+
+	tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr,
+					    sizeof(dmov_box), DMA_TO_DEVICE);
+	tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
+						tx->command_ptr_ptr,
+						sizeof(u32 *), DMA_TO_DEVICE);
+	tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
+
+	init_waitqueue_head(&rx->wait);
+	wake_lock_init(&rx->wake_lock, WAKE_LOCK_SUSPEND, "msm_serial_hs_rx");
+	wake_lock_init(&msm_uport->dma_wake_lock, WAKE_LOCK_SUSPEND,
+			"msm_serial_hs_dma");
+
+	rx->pool = dma_pool_create("rx_buffer_pool", uport->dev,
+				   UARTDM_RX_BUF_SIZE, 16, 0);
+
+	rx->buffer = dma_pool_alloc(rx->pool, GFP_KERNEL, &rx->rbuffer);
+
+	/* Allocate the command pointer. Needs to be 64 bit aligned */
+	rx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
+
+	rx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA);
+
+	if (!rx->command_ptr || !rx->command_ptr_ptr || !rx->pool ||
+	    !rx->buffer)
+		return -ENOMEM;
+
+	rx->command_ptr->num_rows = ((UARTDM_RX_BUF_SIZE >> 4) << 16) |
+					 (UARTDM_RX_BUF_SIZE >> 4);
+
+	rx->command_ptr->dst_row_addr = rx->rbuffer;
+
+	rx->mapped_cmd_ptr = dma_map_single(uport->dev, rx->command_ptr,
+					    sizeof(dmov_box), DMA_TO_DEVICE);
+
+	*rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr);
+
+	rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr,
+					    sizeof(u32 *), DMA_TO_DEVICE);
+	rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr);
+
+	INIT_WORK(&rx->tty_work, msm_hs_tty_flip_buffer_work);
+
+	return 0;
+}
+
+static int msm_hs_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct uart_port *uport;
+	struct msm_hs_port *msm_uport;
+	struct resource *resource;
+	struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
+
+	if (pdev->id < 0 || pdev->id >= UARTDM_NR) {
+		printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id);
+		return -EINVAL;
+	}
+
+	msm_uport = &q_uart_port[pdev->id];
+	uport = &msm_uport->uport;
+
+	uport->dev = &pdev->dev;
+
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!resource))
+		return -ENXIO;
+	uport->mapbase = resource->start;  /* virtual address */
+
+	uport->membase = ioremap(uport->mapbase, PAGE_SIZE);
+	if (unlikely(!uport->membase))
+		return -ENOMEM;
+
+	uport->irq = platform_get_irq(pdev, 0);
+	if (unlikely(uport->irq < 0))
+		return -ENXIO;
+	if (unlikely(set_irq_wake(uport->irq, 1)))
+		return -ENXIO;
+
+	if (pdata == NULL || pdata->rx_wakeup_irq < 0)
+		msm_uport->rx_wakeup.irq = -1;
+	else {
+		msm_uport->rx_wakeup.irq = pdata->rx_wakeup_irq;
+		msm_uport->rx_wakeup.ignore = 1;
+		msm_uport->rx_wakeup.inject_rx = pdata->inject_rx_on_wakeup;
+		msm_uport->rx_wakeup.rx_to_inject = pdata->rx_to_inject;
+
+		if (unlikely(msm_uport->rx_wakeup.irq < 0))
+			return -ENXIO;
+		if (unlikely(set_irq_wake(msm_uport->rx_wakeup.irq, 1)))
+			return -ENXIO;
+	}
+
+	if (pdata == NULL)
+		msm_uport->exit_lpm_cb = NULL;
+	else
+		msm_uport->exit_lpm_cb = pdata->exit_lpm_cb;
+
+	resource = platform_get_resource_byname(pdev, IORESOURCE_DMA,
+						"uartdm_channels");
+	if (unlikely(!resource))
+		return -ENXIO;
+	msm_uport->dma_tx_channel = resource->start;
+	msm_uport->dma_rx_channel = resource->end;
+	
+	resource = platform_get_resource_byname(pdev, IORESOURCE_DMA,
+						"uartdm_crci");
+	if (unlikely(!resource))
+		return -ENXIO;
+	msm_uport->dma_tx_crci = resource->start;
+	msm_uport->dma_rx_crci = resource->end;
+
+	uport->iotype = UPIO_MEM;
+	uport->fifosize = 64;
+	uport->ops = &msm_hs_ops;
+	uport->flags = UPF_BOOT_AUTOCONF;
+	uport->uartclk = 7372800;
+	msm_uport->imr_reg = 0x0;
+	msm_uport->clk = clk_get(&pdev->dev, "uartdm_clk");
+	if (IS_ERR(msm_uport->clk))
+		return PTR_ERR(msm_uport->clk);
+
+	ret = uartdm_init_port(uport);
+	if (unlikely(ret))
+		return ret;
+
+	/* configure the CR Protection to Enable */
+	msm_hs_write(uport, UARTDM_CR_ADDR, CR_PROTECTION_EN);
+
+	msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
+	hrtimer_init(&msm_uport->clk_off_timer, CLOCK_MONOTONIC,
+		     HRTIMER_MODE_REL);
+	msm_uport->clk_off_timer.function = msm_hs_clk_off_retry;
+	msm_uport->clk_off_delay = ktime_set(0, 1000000);  /* 1ms */
+
+	uport->line = pdev->id;
+	return uart_add_one_port(&msm_hs_driver, uport);
+}
+
+static int __init msm_serial_hs_init(void)
+{
+	int ret;
+	int i;
+
+	/* Init all UARTS as non-configured */
+	for (i = 0; i < UARTDM_NR; i++)
+		q_uart_port[i].uport.type = PORT_UNKNOWN;
+
+	msm_hs_workqueue = create_singlethread_workqueue("msm_serial_hs");
+
+	ret = uart_register_driver(&msm_hs_driver);
+	if (unlikely(ret)) {
+		printk(KERN_ERR "%s failed to load\n", __FUNCTION__);
+		return ret;
+	}
+	ret = platform_driver_register(&msm_serial_hs_platform_driver);
+	if (ret) {
+		printk(KERN_ERR "%s failed to load\n", __FUNCTION__);
+		uart_unregister_driver(&msm_hs_driver);
+		return ret;
+	}
+
+	printk(KERN_INFO "msm_serial_hs module loaded\n");
+	return ret;
+}
+
+/*
+ *  Called by the upper layer when port is closed.
+ *     - Disables the port
+ *     - Unhook the ISR
+ */
+static void msm_hs_shutdown(struct uart_port *uport)
+{
+	unsigned long flags;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	BUG_ON(msm_uport->rx.flush < FLUSH_STOP);
+
+	spin_lock_irqsave(&uport->lock, flags);
+	clk_enable(msm_uport->clk);
+
+	/* Disable the transmitter */
+	msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
+	/* Disable the receiver */
+	msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_DISABLE_BMSK);
+
+	/* Free the interrupt */
+	free_irq(uport->irq, msm_uport);
+	if (use_low_power_rx_wakeup(msm_uport))
+		free_irq(msm_uport->rx_wakeup.irq, msm_uport);
+
+	msm_uport->imr_reg = 0;
+	msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+
+	wait_event(msm_uport->rx.wait, msm_uport->rx.flush == FLUSH_SHUTDOWN);
+
+	clk_disable(msm_uport->clk);  /* to balance local clk_enable() */
+	if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
+		wake_unlock(&msm_uport->dma_wake_lock);
+		clk_disable(msm_uport->clk);  /* to balance clk_state */
+	}
+	msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
+
+	dma_unmap_single(uport->dev, msm_uport->tx.dma_base,
+			 UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+	spin_unlock_irqrestore(&uport->lock, flags);
+
+	if (cancel_work_sync(&msm_uport->rx.tty_work))
+		msm_hs_tty_flip_buffer_work(&msm_uport->rx.tty_work);
+}
+
+static void __exit msm_serial_hs_exit(void)
+{
+	printk(KERN_INFO "msm_serial_hs module removed\n");
+	platform_driver_unregister(&msm_serial_hs_platform_driver);
+	uart_unregister_driver(&msm_hs_driver);
+	destroy_workqueue(msm_hs_workqueue);
+}
+
+static struct platform_driver msm_serial_hs_platform_driver = {
+	.probe = msm_hs_probe,
+	.remove = msm_hs_remove,
+	.driver = {
+		   .name = "msm_serial_hs",
+		   },
+};
+
+static struct uart_driver msm_hs_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "msm_serial_hs",
+	.dev_name = "ttyHS",
+	.nr = UARTDM_NR,
+	.cons = 0,
+};
+
+static struct uart_ops msm_hs_ops = {
+	.tx_empty = msm_hs_tx_empty,
+	.set_mctrl = msm_hs_set_mctrl_locked,
+	.get_mctrl = msm_hs_get_mctrl_locked,
+	.stop_tx = msm_hs_stop_tx_locked,
+	.start_tx = msm_hs_start_tx_locked,
+	.stop_rx = msm_hs_stop_rx_locked,
+	.enable_ms = msm_hs_enable_ms_locked,
+	.break_ctl = msm_hs_break_ctl,
+	.startup = msm_hs_startup,
+	.shutdown = msm_hs_shutdown,
+	.set_termios = msm_hs_set_termios,
+	.pm = msm_hs_pm,
+	.type = msm_hs_type,
+	.config_port = msm_hs_config_port,
+	.release_port = msm_hs_release_port,
+	.request_port = msm_hs_request_port,
+};
+
+module_init(msm_serial_hs_init);
+module_exit(msm_serial_hs_exit);
+MODULE_DESCRIPTION("High Speed UART Driver for the MSM chipset");
+MODULE_VERSION("1.2");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/serial/msm_serial_hs_hwreg.h b/drivers/serial/msm_serial_hs_hwreg.h
new file mode 100644
index 0000000..df59678
--- /dev/null
+++ b/drivers/serial/msm_serial_hs_hwreg.h
@@ -0,0 +1,149 @@
+/* drivers/serial/msm_serial_hs_hwreg.h
+ *
+ * Copyright (c) 2007-2008 QUALCOMM Incorporated.
+ * Copyright (c) 2008 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * except where indicated.
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#ifndef MSM_SERIAL_HS_HWREG_H
+#define MSM_SERIAL_HS_HWREG_H
+
+#define UARTDM_MR1_ADDR 0x0
+#define UARTDM_MR2_ADDR 0x4
+
+/* write only register */
+#define UARTDM_CSR_ADDR 0x8
+
+/* write only register */
+#define UARTDM_TF_ADDR 0x70
+#define UARTDM_TF2_ADDR 0x74
+#define UARTDM_TF3_ADDR 0x78
+#define UARTDM_TF4_ADDR 0x7C
+
+/* write only register */
+#define UARTDM_CR_ADDR 0x10
+/* write only register */
+#define UARTDM_IMR_ADDR 0x14
+
+#define UARTDM_IPR_ADDR 0x18
+#define UARTDM_TFWR_ADDR 0x1c
+#define UARTDM_RFWR_ADDR 0x20
+#define UARTDM_HCR_ADDR 0x24
+#define UARTDM_DMRX_ADDR 0x34
+#define UARTDM_IRDA_ADDR 0x38
+#define UARTDM_DMEN_ADDR 0x3c
+
+/* UART_DM_NO_CHARS_FOR_TX */
+#define UARTDM_NCF_TX_ADDR 0x40
+
+#define UARTDM_BADR_ADDR 0x44
+
+#define UARTDM_SIM_CFG_ADDR 0x80
+
+/* Read Only register */
+#define UARTDM_SR_ADDR 0x8
+
+/* Read Only register */
+#define UARTDM_RF_ADDR  0x70
+#define UARTDM_RF2_ADDR 0x74
+#define UARTDM_RF3_ADDR 0x78
+#define UARTDM_RF4_ADDR 0x7C
+
+/* Read Only register */
+#define UARTDM_MISR_ADDR 0x10
+
+/* Read Only register */
+#define UARTDM_ISR_ADDR 0x14
+#define UARTDM_RX_TOTAL_SNAP_ADDR 0x38
+
+#define UARTDM_RXFS_ADDR 0x50
+
+/* Register field Mask Mapping */
+#define UARTDM_SR_PAR_FRAME_BMSK	BIT(5)
+#define UARTDM_SR_OVERRUN_BMSK		BIT(4)
+#define UARTDM_SR_TXEMT_BMSK		BIT(3)
+#define UARTDM_SR_TXRDY_BMSK		BIT(2)
+#define UARTDM_SR_RXRDY_BMSK		BIT(0)
+
+#define UARTDM_CR_TX_DISABLE_BMSK	BIT(3)
+#define UARTDM_CR_RX_DISABLE_BMSK	BIT(1)
+#define UARTDM_CR_TX_EN_BMSK		BIT(2)
+#define UARTDM_CR_RX_EN_BMSK		BIT(0)
+
+/* UARTDM_CR channel_comman bit value (register field is bits 8:4) */
+#define RESET_RX		0x10
+#define RESET_TX		0x20
+#define RESET_ERROR_STATUS	0x30
+#define RESET_BREAK_INT		0x40
+#define START_BREAK		0x50
+#define STOP_BREAK		0x60
+#define RESET_CTS		0x70
+#define RESET_STALE_INT		0x80
+#define RFR_LOW			0xD0
+#define RFR_HIGH		0xE0
+#define CR_PROTECTION_EN	0x100
+#define STALE_EVENT_ENABLE	0x500
+#define STALE_EVENT_DISABLE	0x600
+#define FORCE_STALE_EVENT	0x400
+#define CLEAR_TX_READY		0x300
+#define RESET_TX_ERROR		0x800
+#define RESET_TX_DONE		0x810
+
+#define UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK 0xffffff00
+#define UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK 0x3f
+#define UARTDM_MR1_CTS_CTL_BMSK 0x40
+#define UARTDM_MR1_RX_RDY_CTL_BMSK 0x80
+
+#define UARTDM_MR2_ERROR_MODE_BMSK 0x40
+#define UARTDM_MR2_BITS_PER_CHAR_BMSK 0x30
+
+/* bits per character configuration */
+#define FIVE_BPC  (0 << 4)
+#define SIX_BPC   (1 << 4)
+#define SEVEN_BPC (2 << 4)
+#define EIGHT_BPC (3 << 4)
+
+#define UARTDM_MR2_STOP_BIT_LEN_BMSK 0xc
+#define STOP_BIT_ONE (1 << 2)
+#define STOP_BIT_TWO (3 << 2)
+
+#define UARTDM_MR2_PARITY_MODE_BMSK 0x3
+
+/* Parity configuration */
+#define NO_PARITY 0x0
+#define EVEN_PARITY 0x1
+#define ODD_PARITY 0x2
+#define SPACE_PARITY 0x3
+
+#define UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK 0xffffff80
+#define UARTDM_IPR_STALE_LSB_BMSK 0x1f
+
+/* These can be used for both ISR and IMR register */
+#define UARTDM_ISR_TX_READY_BMSK	BIT(7)
+#define UARTDM_ISR_CURRENT_CTS_BMSK	BIT(6)
+#define UARTDM_ISR_DELTA_CTS_BMSK	BIT(5)
+#define UARTDM_ISR_RXLEV_BMSK		BIT(4)
+#define UARTDM_ISR_RXSTALE_BMSK		BIT(3)
+#define UARTDM_ISR_RXBREAK_BMSK		BIT(2)
+#define UARTDM_ISR_RXHUNT_BMSK		BIT(1)
+#define UARTDM_ISR_TXLEV_BMSK		BIT(0)
+
+/* Field definitions for UART_DM_DMEN*/
+#define UARTDM_TX_DM_EN_BMSK 0x1
+#define UARTDM_RX_DM_EN_BMSK 0x2
+
+#endif /* MSM_SERIAL_HS_HWREG_H */
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 91c2f4f..9048096 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -243,6 +243,11 @@
 	  The driver can be configured to use any SSP port and additional
 	  documentation can be found a Documentation/spi/pxa2xx.
 
+config SPI_QSD
+	tristate "Qualcomm MSM SPI support"
+	default n
+	depends on ARCH_MSM_SCORPION
+
 config SPI_S3C24XX
 	tristate "Samsung S3C24XX series SPI"
 	depends on ARCH_S3C2410 && EXPERIMENTAL
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e9cbd18..50b4ee3 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -36,6 +36,7 @@
 obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
 obj-$(CONFIG_SPI_MPC8xxx)		+= spi_mpc8xxx.o
 obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
+obj-$(CONFIG_SPI_QSD)			+= spi_qsd.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx_hw.o
 obj-$(CONFIG_SPI_S3C64XX)		+= spi_s3c64xx.o
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
new file mode 100644
index 0000000..1392d29
--- /dev/null
+++ b/drivers/spi/spi_qsd.c
@@ -0,0 +1,1605 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. 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 Code Aurora Forum nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above.  If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL".  Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms.  In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 and only version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * END
+ *
+ * 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.
+ *
+ */
+/*
+ * SPI driver for Qualcomm QSD platforms
+ *
+ */
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <mach/msm_spi.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <mach/dma.h>
+#include <asm/atomic.h>
+
+#define SPI_CONFIG                    0x0000
+#define SPI_IO_CONTROL                0x0004
+#define SPI_IO_MODES                  0x0008
+#define SPI_SW_RESET                  0x000C
+#define SPI_TIME_OUT                  0x0010
+#define SPI_TIME_OUT_CURRENT          0x0014
+#define SPI_MX_OUTPUT_COUNT           0x0018
+#define SPI_MX_OUTPUT_CNT_CURRENT     0x001C
+#define SPI_MX_INPUT_COUNT            0x0020
+#define SPI_MX_INPUT_CNT_CURRENT      0x0024
+#define SPI_MX_READ_COUNT             0x0028
+#define SPI_MX_READ_CNT_CURRENT       0x002C
+#define SPI_OPERATIONAL               0x0030
+#define SPI_ERROR_FLAGS               0x0034
+#define SPI_ERROR_FLAGS_EN            0x0038
+#define SPI_DEASSERT_WAIT             0x003C
+#define SPI_OUTPUT_DEBUG              0x0040
+#define SPI_INPUT_DEBUG               0x0044
+#define SPI_FIFO_WORD_CNT             0x0048
+#define SPI_TEST_CTRL                 0x004C
+#define SPI_OUTPUT_FIFO               0x0100
+#define SPI_INPUT_FIFO                0x0200
+
+/* SPI_CONFIG fields */
+#define SPI_CFG_INPUT_FIRST           0x00000200
+#define SPI_NO_INPUT                  0x00000080
+#define SPI_NO_OUTPUT                 0x00000040
+#define SPI_CFG_LOOPBACK              0x00000100
+#define SPI_CFG_N                     0x0000001F
+
+/* SPI_IO_CONTROL fields */
+#define SPI_IO_C_CLK_IDLE_HIGH        0x00000400
+#define SPI_IO_C_MX_CS_MODE           0x00000100
+#define SPI_IO_C_CS_N_POLARITY        0x000000F0
+#define SPI_IO_C_CS_N_POLARITY_0      0x00000010
+#define SPI_IO_C_CS_SELECT            0x0000000C
+#define SPI_IO_C_TRISTATE_CS          0x00000002
+#define SPI_IO_C_NO_TRI_STATE         0x00000001
+
+/* SPI_IO_MODES fields */
+#define SPI_IO_M_OUTPUT_BIT_SHIFT_EN  0x00004000
+#define SPI_IO_M_PACK_EN              0x00002000
+#define SPI_IO_M_UNPACK_EN            0x00001000
+#define SPI_IO_M_INPUT_MODE           0x00000C00
+#define SPI_IO_M_OUTPUT_MODE          0x00000300
+#define SPI_IO_M_INPUT_FIFO_SIZE      0x000000C0
+#define SPI_IO_M_INPUT_BLOCK_SIZE     0x00000030
+#define SPI_IO_M_OUTPUT_FIFO_SIZE     0x0000000C
+#define SPI_IO_M_OUTPUT_BLOCK_SIZE    0x00000003
+
+/* SPI_OPERATIONAL fields */
+#define SPI_OP_MAX_INPUT_DONE_FLAG    0x00000800
+#define SPI_OP_MAX_OUTPUT_DONE_FLAG   0x00000400
+#define SPI_OP_INPUT_SERVICE_FLAG     0x00000200
+#define SPI_OP_OUTPUT_SERVICE_FLAG    0x00000100
+#define SPI_OP_INPUT_FIFO_FULL        0x00000080
+#define SPI_OP_OUTPUT_FIFO_FULL       0x00000040
+#define SPI_OP_IP_FIFO_NOT_EMPTY      0x00000020
+#define SPI_OP_OP_FIFO_NOT_EMPTY      0x00000010
+#define SPI_OP_STATE_VALID            0x00000004
+#define SPI_OP_STATE                  0x00000003
+#define SPI_OP_STATE_RESET            0x00000000
+#define SPI_OP_STATE_RUN              0x00000001
+#define SPI_OP_STATE_PAUSE            0x00000003
+
+/* SPI_ERROR_FLAGS fields */
+#define SPI_ERR_TIME_OUT_ERR          0x00000040
+#define SPI_ERR_OUTPUT_OVER_RUN_ERR   0x00000020
+#define SPI_ERR_INPUT_UNDER_RUN_ERR   0x00000010
+#define SPI_ERR_OUTPUT_UNDER_RUN_ERR  0x00000008
+#define SPI_ERR_INPUT_OVER_RUN_ERR    0x00000004
+#define SPI_ERR_CLK_OVER_RUN_ERR      0x00000002
+#define SPI_ERR_CLK_UNDER_RUN_ERR     0x00000001
+#define SPI_ERR_MASK                  0x0000007F
+
+/* We don't allow transactions larger than 4K-64 */
+#define SPI_MAX_TRANSFERS             0x000FC0
+#define SPI_MAX_LEN                   (SPI_MAX_TRANSFERS * dd->bytes_per_word)
+#define SPI_MAX_TIMEOUT               0x00010000
+#define SPI_MIN_TRANS_TIME            50
+
+#define SPI_NUM_CHIPSELECTS           4
+#define SPI_QSD_NAME                  "spi_qsd"
+
+/* Data Mover burst size */
+#define DM_BURST_SIZE                 16
+/* Data Mover commands should be aligned to 64 bit(8 bytes) */
+#define DM_BYTE_ALIGN                 8
+
+enum msm_spi_mode {
+	SPI_FIFO_MODE  = 0x0,  /* 00 */
+	SPI_BLOCK_MODE = 0x1,  /* 01 */
+	SPI_DMOV_MODE  = 0x2,  /* 10 */
+	SPI_MODE_NONE  = 0xFF, /* invalid value */
+};
+
+/* Structures for Data Mover */
+struct spi_dmov_cmd {
+	dmov_box box;      /* data aligned to max(dm_burst_size, block_size)
+							   (<= fifo_size) */
+	dmov_s single_pad; /* data unaligned to max(dm_burst_size, block_size)
+			      padded to fit */
+	dma_addr_t cmd_ptr;
+};
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.2");
+MODULE_ALIAS("platform:spi_qsd");
+
+#ifdef CONFIG_DEBUG_FS
+/* Used to create debugfs entries */
+static const struct {
+	const char *name;
+	mode_t mode;
+	int offset;
+} debugfs_spi_regs[] = {
+	{"config",                S_IRUGO | S_IWUSR, SPI_CONFIG},
+	{"io_control",            S_IRUGO | S_IWUSR, SPI_IO_CONTROL},
+	{"io_modes",              S_IRUGO | S_IWUSR, SPI_IO_MODES},
+	{"sw_reset",                        S_IWUSR, SPI_SW_RESET},
+	{"time_out",              S_IRUGO | S_IWUSR, SPI_TIME_OUT},
+	{"time_out_current",      S_IRUGO,           SPI_TIME_OUT_CURRENT},
+	{"mx_output_count",       S_IRUGO | S_IWUSR, SPI_MX_OUTPUT_COUNT},
+	{"mx_output_cnt_current", S_IRUGO,           SPI_MX_OUTPUT_CNT_CURRENT},
+	{"mx_input_count",        S_IRUGO | S_IWUSR, SPI_MX_INPUT_COUNT},
+	{"mx_input_cnt_current",  S_IRUGO,           SPI_MX_INPUT_CNT_CURRENT},
+	{"mx_read_count",         S_IRUGO | S_IWUSR, SPI_MX_READ_COUNT},
+	{"mx_read_cnt_current",   S_IRUGO,           SPI_MX_READ_CNT_CURRENT},
+	{"operational",           S_IRUGO | S_IWUSR, SPI_OPERATIONAL},
+	{"error_flags",           S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS},
+	{"error_flags_en",        S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS_EN},
+	{"deassert_wait",         S_IRUGO | S_IWUSR, SPI_DEASSERT_WAIT},
+	{"output_debug",          S_IRUGO,           SPI_OUTPUT_DEBUG},
+	{"input_debug",           S_IRUGO,           SPI_INPUT_DEBUG},
+	{"fifo_word_cnt",         S_IRUGO,           SPI_FIFO_WORD_CNT},
+	{"test_ctrl",             S_IRUGO | S_IWUSR, SPI_TEST_CTRL},
+	{"output_fifo",                     S_IWUSR, SPI_OUTPUT_FIFO},
+	{"input_fifo" ,           S_IRUSR,           SPI_INPUT_FIFO},
+};
+#endif
+
+struct msm_spi {
+	u8                      *read_buf;
+	const u8                *write_buf;
+	void __iomem		*base;
+	struct device           *dev;
+	spinlock_t               queue_lock;
+	struct list_head         queue;
+	struct workqueue_struct	*workqueue;
+	struct work_struct       work_data;
+	struct spi_message      *cur_msg;
+	struct spi_transfer     *cur_transfer;
+	struct completion        transfer_complete;
+	struct clk              *clk;
+	struct clk              *pclk;
+	int                      max_clock_speed;
+	unsigned long            mem_phys_addr;
+	size_t                   mem_size;
+	u32                      rx_bytes_remaining;
+	u32                      tx_bytes_remaining;
+	u32                      clock_speed;
+	u32                      irq_in;
+	u32                      irq_out;
+	u32                      irq_err;
+	int                      bytes_per_word;
+	bool                     suspended;
+	bool                     transfer_in_progress;
+	/* DMA data */
+	enum msm_spi_mode        mode;
+	bool                     use_dma;
+	int                      tx_dma_chan;
+	int                      tx_dma_crci;
+	int                      rx_dma_chan;
+	int                      rx_dma_crci;
+	/* Data Mover Commands */
+	struct spi_dmov_cmd      *tx_dmov_cmd;
+	struct spi_dmov_cmd      *rx_dmov_cmd;
+	/* Physical address of the tx dmov box command */
+	dma_addr_t               tx_dmov_cmd_dma;
+	dma_addr_t               rx_dmov_cmd_dma;
+	struct msm_dmov_cmd      tx_hdr;
+	struct msm_dmov_cmd      rx_hdr;
+	int                      block_size;
+	int                      burst_size;
+	atomic_t                 rx_irq_called;
+	/* Used to pad messages unaligned to block size */
+	u8                       *tx_padding;
+	dma_addr_t               tx_padding_dma;
+	u8                       *rx_padding;
+	dma_addr_t               rx_padding_dma;
+	u32                      unaligned_len;
+	/* DMA statistics */
+	u32                      stat_dmov_err;
+	u32                      stat_rx;
+	u32                      stat_tx;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dent_spi;
+	struct dentry *debugfs_spi_regs[ARRAY_SIZE(debugfs_spi_regs)];
+#endif
+};
+
+static int input_fifo_size;
+
+static void msm_spi_clock_set(struct msm_spi *dd, int speed)
+{
+	int rc;
+
+	rc = clk_set_rate(dd->clk, speed);
+	if (!rc)
+		dd->clock_speed = speed;
+}
+
+/* Assumption: input_fifo=output_fifo */
+static void __init msm_spi_calculate_fifo_size(struct msm_spi *dd)
+{
+	u32 spi_iom;
+	int block;
+	int mult;
+	int words;
+
+	spi_iom = readl(dd->base + SPI_IO_MODES);
+	block = (spi_iom & SPI_IO_M_INPUT_BLOCK_SIZE) >> 4;
+	mult = (spi_iom & SPI_IO_M_INPUT_FIFO_SIZE) >> 6;
+	switch (block) {
+	case 0:
+		words = 1;
+		break;
+	case 1:
+		words = 4;
+		break;
+	case 2:
+		words = 8;
+		break;
+	default:
+		goto fifo_size_err;
+	}
+	switch (mult) {
+	case 0:
+		input_fifo_size = words * 2;
+		break;
+	case 1:
+		input_fifo_size = words * 4;
+		break;
+	case 2:
+		input_fifo_size = words * 8;
+		break;
+	default:
+		goto fifo_size_err;
+	}
+
+	/* we can't use dma with 8 bytes of fifo since dm burst size is 16 */
+	if (input_fifo_size*sizeof(u32) < DM_BURST_SIZE)
+		dd->use_dma = 0;
+	if (dd->use_dma) {
+		dd->block_size = words*sizeof(u32); /* in bytes */
+		dd->burst_size = max(dd->block_size, DM_BURST_SIZE);
+	}
+
+	return;
+
+fifo_size_err:
+	printk(KERN_WARNING "%s: invalid FIFO size, SPI_IO_MODES=0x%x\n",
+	       __func__, spi_iom);
+	return;
+}
+
+static void msm_spi_read_word_from_fifo(struct msm_spi *dd)
+{
+	u32   data_in;
+	int   i;
+	int   shift;
+
+	data_in = readl(dd->base + SPI_INPUT_FIFO);
+	if (dd->read_buf) {
+		for (i = 0; (i < dd->bytes_per_word) &&
+			     dd->rx_bytes_remaining; i++) {
+			/* The data format depends on bytes_per_word:
+			   4 bytes: 0x12345678
+			   3 bytes: 0x00123456
+			   2 bytes: 0x00001234
+			   1 byte : 0x00000012
+			*/
+			shift = 8 * (dd->bytes_per_word - i - 1);
+			*dd->read_buf++ = (data_in & (0xFF << shift)) >> shift;
+			dd->rx_bytes_remaining--;
+		}
+	} else {
+		if (dd->rx_bytes_remaining >= dd->bytes_per_word)
+			dd->rx_bytes_remaining -= dd->bytes_per_word;
+		else
+			dd->rx_bytes_remaining = 0;
+	}
+}
+
+static void msm_spi_setup_dm_transfer(struct msm_spi *dd)
+{
+	dmov_box *box;
+	int bytes_to_send, num_rows, bytes_sent;
+	u32 num_transfers, timeout;
+
+	atomic_set(&dd->rx_irq_called, 0);
+	bytes_sent = dd->cur_transfer->len - dd->tx_bytes_remaining;
+	/* We'll send in chunks of SPI_MAX_LEN if larger */
+	bytes_to_send = dd->tx_bytes_remaining / SPI_MAX_LEN ?
+			  SPI_MAX_LEN : dd->tx_bytes_remaining;
+	num_transfers = DIV_ROUND_UP(bytes_to_send, dd->bytes_per_word);
+	dd->unaligned_len = bytes_to_send % dd->burst_size;
+	/* We multiply by 8bitsinbyte and multiply by 1.5 for safety */
+	timeout = bytes_to_send * 12 > SPI_MAX_TIMEOUT ?
+			0 : roundup(bytes_to_send * 12, SPI_MIN_TRANS_TIME);
+	num_rows = bytes_to_send / dd->burst_size;
+
+	dd->mode = SPI_DMOV_MODE;
+
+	if (num_rows) {
+		/* src in 16 MSB, dst in 16 LSB */
+		box = &dd->tx_dmov_cmd->box;
+		box->src_row_addr = dd->cur_transfer->tx_dma + bytes_sent;
+		box->src_dst_len = (dd->burst_size << 16) | dd->burst_size;
+		box->num_rows = (num_rows << 16) | num_rows;
+		box->row_offset = (dd->burst_size << 16) | 0;
+
+		box = &dd->rx_dmov_cmd->box;
+		box->dst_row_addr = dd->cur_transfer->rx_dma + bytes_sent;
+		box->src_dst_len = (dd->burst_size << 16) | dd->burst_size;
+		box->num_rows = (num_rows << 16) | num_rows;
+		box->row_offset = (0 << 16) | dd->burst_size;
+
+		dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
+				   DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
+				   offsetof(struct spi_dmov_cmd, box));
+		dd->rx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
+				   DMOV_CMD_ADDR(dd->rx_dmov_cmd_dma +
+				   offsetof(struct spi_dmov_cmd, box));
+	} else {
+		dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
+				   DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
+				   offsetof(struct spi_dmov_cmd, single_pad));
+		dd->rx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
+				   DMOV_CMD_ADDR(dd->rx_dmov_cmd_dma +
+				   offsetof(struct spi_dmov_cmd, single_pad));
+	}
+
+	if (!dd->unaligned_len) {
+		dd->tx_dmov_cmd->box.cmd |= CMD_LC;
+		dd->rx_dmov_cmd->box.cmd |= CMD_LC;
+	} else {
+		dmov_s *tx_cmd = &(dd->tx_dmov_cmd->single_pad);
+		dmov_s *rx_cmd = &(dd->rx_dmov_cmd->single_pad);
+		u32 offset = dd->cur_transfer->len - dd->unaligned_len;
+
+		dd->tx_dmov_cmd->box.cmd &= ~CMD_LC;
+		dd->rx_dmov_cmd->box.cmd &= ~CMD_LC;
+
+		memset(dd->tx_padding, 0, dd->burst_size);
+		memset(dd->rx_padding, 0, dd->burst_size);
+		if (dd->write_buf)
+			memcpy(dd->tx_padding, dd->write_buf + offset,
+			       dd->unaligned_len);
+
+		tx_cmd->src = dd->tx_padding_dma;
+		rx_cmd->dst = dd->rx_padding_dma;
+		tx_cmd->len = rx_cmd->len = dd->burst_size;
+	}
+	/* This also takes care of the padding dummy buf
+	   Since this is set to the correct length, the
+	   dummy bytes won't be actually sent */
+	if (dd->write_buf)
+		writel(num_transfers, dd->base + SPI_MX_OUTPUT_COUNT);
+	if (dd->read_buf)
+		writel(num_transfers, dd->base + SPI_MX_INPUT_COUNT);
+	/* Write timeout */
+	writel(timeout, dd->base + SPI_TIME_OUT);
+}
+
+static void msm_spi_enqueue_dm_commands(struct msm_spi *dd)
+{
+	if (dd->write_buf)
+		msm_dmov_enqueue_cmd(dd->tx_dma_chan, &dd->tx_hdr);
+	if (dd->read_buf)
+		msm_dmov_enqueue_cmd(dd->rx_dma_chan, &dd->rx_hdr);
+}
+
+/* SPI core can send maximum of 4K transfers, because there is HW problem
+   with infinite mode.
+   Therefore, we are sending several chunks of 3K or less (depending on how
+   much is left).
+   Upon completion we send the next chunk, or complete the transfer if
+   everything is finished.
+*/
+static int msm_spi_dm_send_next(struct msm_spi *dd)
+{
+	/* By now we should have sent all the bytes in FIFO mode,
+	 * However to make things right, we'll check anyway.
+	 */
+	if (dd->mode != SPI_DMOV_MODE)
+		return 0;
+
+	/* We need to send more chunks, if we sent max last time */
+	if (dd->tx_bytes_remaining > SPI_MAX_LEN) {
+		dd->tx_bytes_remaining -= SPI_MAX_LEN;
+		writel((readl(dd->base + SPI_OPERATIONAL)
+			& ~SPI_OP_STATE) | SPI_OP_STATE_PAUSE,
+			dd->base + SPI_OPERATIONAL);
+		msm_spi_setup_dm_transfer(dd);
+		msm_spi_enqueue_dm_commands(dd);
+
+		writel((readl(dd->base + SPI_OPERATIONAL)
+			& ~SPI_OP_STATE) | SPI_OP_STATE_RUN,
+			dd->base + SPI_OPERATIONAL);
+		return 1;
+	}
+
+	return 0;
+}
+
+static inline void msm_spi_ack_transfer(struct msm_spi *dd)
+{
+	writel(SPI_OP_MAX_INPUT_DONE_FLAG | SPI_OP_MAX_OUTPUT_DONE_FLAG,
+	       dd->base + SPI_OPERATIONAL);
+	writel(0, dd->base + SPI_TIME_OUT);
+}
+
+static irqreturn_t msm_spi_input_irq(int irq, void *dev_id)
+{
+	struct msm_spi	       *dd = dev_id;
+
+	dd->stat_rx++;
+
+	if (dd->mode == SPI_MODE_NONE)
+		return IRQ_HANDLED;
+
+	if (dd->mode == SPI_DMOV_MODE) {
+		u32 op = readl(dd->base + SPI_OPERATIONAL);
+		if ((!dd->read_buf || op & SPI_OP_MAX_INPUT_DONE_FLAG) &&
+		    (!dd->write_buf || op & SPI_OP_MAX_OUTPUT_DONE_FLAG)) {
+			msm_spi_ack_transfer(dd);
+			if (dd->unaligned_len == 0) {
+				if (atomic_inc_return(&dd->rx_irq_called) == 1)
+					return IRQ_HANDLED;
+			}
+			complete(&dd->transfer_complete);
+			return IRQ_HANDLED;
+		}
+		return IRQ_NONE;
+	}
+
+	/* fifo mode */
+	while ((readl(dd->base + SPI_OPERATIONAL) & SPI_OP_IP_FIFO_NOT_EMPTY) &&
+	       (dd->rx_bytes_remaining > 0)) {
+		msm_spi_read_word_from_fifo(dd);
+	}
+	if (dd->rx_bytes_remaining == 0)
+		complete(&dd->transfer_complete);
+
+	return IRQ_HANDLED;
+}
+
+static void msm_spi_write_word_to_fifo(struct msm_spi *dd)
+{
+	u32    word;
+	u8     byte;
+	int    i;
+
+	word = 0;
+	if (dd->write_buf) {
+		for (i = 0; (i < dd->bytes_per_word) &&
+			     dd->tx_bytes_remaining; i++) {
+			dd->tx_bytes_remaining--;
+			byte = *dd->write_buf++;
+			word |= (byte << (BITS_PER_BYTE * (3 - i)));
+		}
+	} else
+		if (dd->tx_bytes_remaining > dd->bytes_per_word)
+			dd->tx_bytes_remaining -= dd->bytes_per_word;
+		else
+			dd->tx_bytes_remaining = 0;
+	writel(word, dd->base + SPI_OUTPUT_FIFO);
+}
+
+static irqreturn_t msm_spi_output_irq(int irq, void *dev_id)
+{
+	struct msm_spi	       *dd = dev_id;
+	int                     count = 0;
+
+	dd->stat_tx++;
+
+	if (dd->mode == SPI_MODE_NONE)
+		return IRQ_HANDLED;
+
+	if (dd->mode == SPI_DMOV_MODE) {
+		/* TX_ONLY transaction is handled here
+		   This is the only place we send complete at tx and not rx */
+		if (dd->read_buf == NULL && readl(dd->base + SPI_OPERATIONAL) &
+					    SPI_OP_MAX_OUTPUT_DONE_FLAG) {
+			msm_spi_ack_transfer(dd);
+			complete(&dd->transfer_complete);
+			return IRQ_HANDLED;
+		}
+		return IRQ_NONE;
+	}
+
+	/* Output FIFO is empty. Transmit any outstanding write data. */
+	/* There could be one word in input FIFO, so don't send more  */
+	/* than input_fifo_size - 1 more words.                       */
+	while ((dd->tx_bytes_remaining > 0) &&
+	       (count < input_fifo_size - 1) &&
+	       !(readl(dd->base + SPI_OPERATIONAL) & SPI_OP_OUTPUT_FIFO_FULL)) {
+		msm_spi_write_word_to_fifo(dd);
+		count++;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t msm_spi_error_irq(int irq, void *dev_id)
+{
+	struct spi_master	*master = dev_id;
+	struct msm_spi          *dd = spi_master_get_devdata(master);
+	u32                      spi_err;
+
+	spi_err = readl(dd->base + SPI_ERROR_FLAGS);
+	if (spi_err & SPI_ERR_TIME_OUT_ERR) {
+		dev_warn(master->dev.parent, "SPI timeout error\n");
+		msm_dmov_flush(dd->tx_dma_chan);
+		msm_dmov_flush(dd->rx_dma_chan);
+	}
+	if (spi_err & SPI_ERR_OUTPUT_OVER_RUN_ERR)
+		dev_warn(master->dev.parent, "SPI output overrun error\n");
+	if (spi_err & SPI_ERR_INPUT_UNDER_RUN_ERR)
+		dev_warn(master->dev.parent, "SPI input underrun error\n");
+	if (spi_err & SPI_ERR_OUTPUT_UNDER_RUN_ERR)
+		dev_warn(master->dev.parent, "SPI output underrun error\n");
+	if (spi_err & SPI_ERR_INPUT_OVER_RUN_ERR)
+		dev_warn(master->dev.parent, "SPI input overrun error\n");
+	if (spi_err & SPI_ERR_CLK_OVER_RUN_ERR)
+		dev_warn(master->dev.parent, "SPI clock overrun error\n");
+	if (spi_err & SPI_ERR_CLK_UNDER_RUN_ERR)
+		dev_warn(master->dev.parent, "SPI clock underrun error\n");
+	writel(SPI_ERR_MASK, dd->base + SPI_ERROR_FLAGS);
+	return IRQ_HANDLED;
+}
+
+static void msm_spi_unmap_dma_buffers(struct msm_spi *dd)
+{
+	struct device *dev;
+
+	dev = &dd->cur_msg->spi->dev;
+	if (!dd->cur_msg->is_dma_mapped) {
+		if (dd->cur_transfer->rx_buf)
+			dma_unmap_single(dev, dd->cur_transfer->rx_dma,
+					 dd->cur_transfer->len,
+					 DMA_FROM_DEVICE);
+		if (dd->cur_transfer->tx_buf)
+			dma_unmap_single(dev, dd->cur_transfer->tx_dma,
+					 dd->cur_transfer->len,
+					 DMA_TO_DEVICE);
+	}
+	/* If we padded the transfer, we copy it from the padding buf */
+	if (dd->unaligned_len && dd->read_buf) {
+		u32 offset = dd->cur_transfer->len - dd->unaligned_len;
+		memcpy(dd->read_buf + offset, dd->rx_padding,
+		       dd->unaligned_len);
+	}
+}
+
+/**
+ * msm_use_dm - decides whether to use data mover for this
+ * 		transfer
+ * @dd:       device
+ * @tr:       transfer
+ *
+ * Start using DM if:
+ * 1. Transfer is longer than 3*block size.
+ * 2. Buffers should be aligned to cache line.
+ * 3. If Transfer is bigger than max_output_count, we accept only aligned to
+ *    block size transfers.
+ */
+static inline int msm_use_dm(struct msm_spi *dd, struct spi_transfer *tr)
+{
+	u32 cache_line = dma_get_cache_alignment();
+
+	if (!dd->use_dma)
+		return 0;
+
+	if (tr->len < 3*dd->block_size)
+		return 0;
+
+	if (tr->tx_buf) {
+		if (!IS_ALIGNED((size_t)tr->tx_buf, cache_line))
+			return 0;
+	}
+	if (tr->rx_buf) {
+		if (!IS_ALIGNED((size_t)tr->rx_buf, cache_line))
+			return 0;
+	}
+	return 1;
+}
+
+static void msm_spi_process_transfer(struct msm_spi *dd)
+{
+	u8  bpw;
+	u32 spi_config;
+	u32 spi_ioc;
+	u32 spi_iom;
+	u32 spi_ioc_orig;
+	u32 max_speed;
+	u32 chip_select;
+	u32 read_count;
+	u32 timeout;
+
+	if (!dd->cur_transfer->len)
+		return;
+	dd->tx_bytes_remaining = dd->cur_transfer->len;
+	dd->rx_bytes_remaining = dd->cur_transfer->len;
+	dd->read_buf           = dd->cur_transfer->rx_buf;
+	dd->write_buf          = dd->cur_transfer->tx_buf;
+	init_completion(&dd->transfer_complete);
+	if (dd->cur_transfer->bits_per_word)
+		bpw = dd->cur_transfer->bits_per_word;
+	else
+		if (dd->cur_msg->spi->bits_per_word)
+			bpw = dd->cur_msg->spi->bits_per_word;
+		else
+			bpw = 8;
+	dd->bytes_per_word = (bpw + 7) / 8;
+
+	if (dd->cur_transfer->speed_hz)
+		max_speed = dd->cur_transfer->speed_hz;
+	else
+		max_speed = dd->cur_msg->spi->max_speed_hz;
+	if (!dd->clock_speed || max_speed < dd->clock_speed)
+		msm_spi_clock_set(dd, max_speed);
+
+	read_count = DIV_ROUND_UP(dd->cur_transfer->len, dd->bytes_per_word);
+	if (!msm_use_dm(dd, dd->cur_transfer)) {
+		dd->mode = SPI_FIFO_MODE;
+		/* read_count cannot exceed fifo_size, and only one READ COUNT
+		   interrupt is generated per transaction, so for transactions
+		   larger than fifo size READ COUNT must be disabled.
+		   For those transactions we usually move to Data Mover mode.
+		*/
+		if (read_count <= input_fifo_size)
+			writel(read_count, dd->base + SPI_MX_READ_COUNT);
+		else
+			writel(0, dd->base + SPI_MX_READ_COUNT);
+	} else
+		dd->mode = SPI_DMOV_MODE;
+
+	/* Write mode - fifo or data mover*/
+	spi_iom = readl(dd->base + SPI_IO_MODES);
+	spi_iom &= ~(SPI_IO_M_INPUT_MODE | SPI_IO_M_OUTPUT_MODE);
+	spi_iom = (spi_iom | (dd->mode << 10));
+	spi_iom = (spi_iom | (dd->mode << 8));
+	/* Turn on packing for data mover */
+	if (dd->mode == SPI_DMOV_MODE)
+		spi_iom |= SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN;
+	else
+		spi_iom &= ~(SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN);
+	writel(spi_iom, dd->base + SPI_IO_MODES);
+
+	spi_config = readl(dd->base + SPI_CONFIG);
+	if ((bpw - 1) != (spi_config & SPI_CFG_N))
+		spi_config = (spi_config & ~SPI_CFG_N) | (bpw - 1);
+	if (dd->cur_msg->spi->mode & SPI_CPHA)
+		spi_config &= ~SPI_CFG_INPUT_FIRST;
+	else
+		spi_config |= SPI_CFG_INPUT_FIRST;
+	if (dd->cur_msg->spi->mode & SPI_LOOP)
+		spi_config |= SPI_CFG_LOOPBACK;
+	else
+		spi_config &= ~SPI_CFG_LOOPBACK;
+	spi_config &= ~(SPI_NO_INPUT|SPI_NO_OUTPUT);
+	if (dd->mode == SPI_DMOV_MODE) {
+		if (dd->read_buf == NULL)
+			spi_config |= SPI_NO_INPUT;
+		if (dd->write_buf == NULL)
+			spi_config |= SPI_NO_OUTPUT;
+	}
+	writel(spi_config, dd->base + SPI_CONFIG);
+
+	spi_ioc = readl(dd->base + SPI_IO_CONTROL);
+	spi_ioc_orig = spi_ioc;
+	if (dd->cur_msg->spi->mode & SPI_CPOL)
+		spi_ioc |= SPI_IO_C_CLK_IDLE_HIGH;
+	else
+		spi_ioc &= ~SPI_IO_C_CLK_IDLE_HIGH;
+	chip_select = dd->cur_msg->spi->chip_select << 2;
+	if ((spi_ioc & SPI_IO_C_CS_SELECT) != chip_select)
+		spi_ioc = (spi_ioc & ~SPI_IO_C_CS_SELECT) | chip_select;
+	if (!dd->cur_transfer->cs_change)
+		spi_ioc |= SPI_IO_C_MX_CS_MODE;
+	if (spi_ioc != spi_ioc_orig)
+		writel(spi_ioc, dd->base + SPI_IO_CONTROL);
+
+	if (dd->mode == SPI_DMOV_MODE) {
+		msm_spi_setup_dm_transfer(dd);
+		msm_spi_enqueue_dm_commands(dd);
+	}
+	/* The output fifo interrupt handler will handle all writes after
+	   the first. Restricting this to one write avoids contention
+	   issues and race conditions between this thread and the int handler
+	*/
+	else if (dd->mode == SPI_FIFO_MODE)
+		msm_spi_write_word_to_fifo(dd);
+
+	/* Only enter the RUN state after the first word is written into
+	   the output FIFO.  Otherwise, the output FIFO EMPTY interrupt
+	   might fire before the first word is written resulting in a
+	   possible race condition.
+	 */
+	writel((readl(dd->base + SPI_OPERATIONAL)
+		& ~SPI_OP_STATE) | SPI_OP_STATE_RUN,
+	       dd->base + SPI_OPERATIONAL);
+
+	timeout = 100 * msecs_to_jiffies(
+	      DIV_ROUND_UP(dd->cur_transfer->len * 8,
+		 max_speed / MSEC_PER_SEC));
+	do {
+		if (!wait_for_completion_timeout(&dd->transfer_complete,
+						 timeout)) {
+				dev_err(dd->dev, "%s: SPI transaction "
+						 "timeout\n", __func__);
+				dd->cur_msg->status = -EIO;
+				if (dd->mode == SPI_DMOV_MODE) {
+					writel(0, dd->base + SPI_TIME_OUT);
+					msm_dmov_flush(dd->tx_dma_chan);
+					msm_dmov_flush(dd->rx_dma_chan);
+				}
+				break;
+		}
+	} while (msm_spi_dm_send_next(dd));
+
+	if (dd->mode == SPI_DMOV_MODE)
+		msm_spi_unmap_dma_buffers(dd);
+	dd->mode = SPI_MODE_NONE;
+
+	writel(spi_ioc & ~SPI_IO_C_MX_CS_MODE, dd->base + SPI_IO_CONTROL);
+	writel((readl(dd->base + SPI_OPERATIONAL)
+		& ~SPI_OP_STATE) | SPI_OP_STATE_RESET,
+	       dd->base + SPI_OPERATIONAL);
+}
+
+/* workqueue - pull messages from queue & process */
+static void msm_spi_workq(struct work_struct *work)
+{
+	struct msm_spi      *dd =
+		container_of(work, struct msm_spi, work_data);
+	unsigned long        flags;
+	u32                  spi_op;
+	bool                 status_error = 0;
+
+	spi_op = readl(dd->base + SPI_OPERATIONAL);
+	if (spi_op & SPI_OP_STATE_VALID) {
+		spi_op &= ~SPI_OP_STATE;
+		spi_op |= SPI_OP_STATE_RUN;
+	} else {
+		dev_err(dd->dev, "%s: SPI operational state not valid\n",
+			__func__);
+		status_error = 1;
+	}
+
+	dd->transfer_in_progress = 1;
+	spin_lock_irqsave(&dd->queue_lock, flags);
+	while (!list_empty(&dd->queue)) {
+		dd->cur_msg = list_entry(dd->queue.next,
+					 struct spi_message, queue);
+		list_del_init(&dd->cur_msg->queue);
+		spin_unlock_irqrestore(&dd->queue_lock, flags);
+		if (status_error)
+			dd->cur_msg->status = -EIO;
+		else {
+			list_for_each_entry(dd->cur_transfer,
+					    &dd->cur_msg->transfers,
+					    transfer_list) {
+				msm_spi_process_transfer(dd);
+				if (dd->cur_msg->status == -EINPROGRESS)
+					dd->cur_msg->status = 0;
+			}
+		}
+		if (dd->cur_msg->complete)
+			dd->cur_msg->complete(dd->cur_msg->context);
+		spin_lock_irqsave(&dd->queue_lock, flags);
+	}
+	spin_unlock_irqrestore(&dd->queue_lock, flags);
+	dd->transfer_in_progress = 0;
+}
+
+static int msm_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+	struct msm_spi	*dd;
+	unsigned long    flags;
+	struct spi_transfer *tr;
+
+	dd = spi_master_get_devdata(spi->master);
+	if (dd->suspended)
+		return -EBUSY;
+
+	if (list_empty(&msg->transfers) || !msg->complete)
+		return -EINVAL;
+
+	list_for_each_entry(tr, &msg->transfers, transfer_list) {
+		void *tx_buf = (void *)tr->tx_buf;
+		void       *rx_buf = tr->rx_buf;
+		unsigned len = tr->len;
+
+		/* Check message parameters */
+		if (tr->speed_hz > dd->max_clock_speed || (tr->bits_per_word &&
+			 (tr->bits_per_word < 4 || tr->bits_per_word > 32)) ||
+			 (tx_buf == NULL && rx_buf == NULL)) {
+			dev_err(&spi->dev, "Invalid transfer: %d Hz, %d bpw"
+					   "tx=%p, rx=%p\n",
+					    tr->speed_hz, tr->bits_per_word,
+					    tx_buf, rx_buf);
+			goto error;
+		}
+
+		if (!msm_use_dm(dd, tr) || msg->is_dma_mapped)
+			continue;
+
+		/* Do DMA mapping "early" for better error reporting */
+		if (tx_buf != NULL) {
+			tr->tx_dma = dma_map_single(&spi->dev, tx_buf, len,
+						     DMA_TO_DEVICE);
+			if (dma_mapping_error(NULL, tr->tx_dma)) {
+				dev_err(&spi->dev, "dma %cX %d bytes error\n",
+						   'T', len);
+				goto error;
+			}
+		}
+
+		if (rx_buf != NULL) {
+			tr->rx_dma = dma_map_single(&spi->dev, rx_buf, len,
+					DMA_FROM_DEVICE);
+			if (dma_mapping_error(NULL, tr->rx_dma)) {
+				dev_err(&spi->dev, "dma %cX %d bytes error\n",
+						   'R', len);
+				if (tx_buf != NULL)
+					dma_unmap_single(NULL, tr->tx_dma,
+							len, DMA_TO_DEVICE);
+				goto error;
+			}
+		}
+	}
+
+	spin_lock_irqsave(&dd->queue_lock, flags);
+	list_add_tail(&msg->queue, &dd->queue);
+	spin_unlock_irqrestore(&dd->queue_lock, flags);
+	queue_work(dd->workqueue, &dd->work_data);
+	return 0;
+
+error:
+	list_for_each_entry_continue_reverse(tr, &msg->transfers, transfer_list)
+	{
+		if (msm_use_dm(dd, tr) && !msg->is_dma_mapped) {
+			if (tr->rx_buf != NULL)
+				dma_unmap_single(&spi->dev, tr->rx_dma, tr->len,
+						 DMA_TO_DEVICE);
+			if (tr->tx_buf != NULL)
+				dma_unmap_single(&spi->dev, tr->tx_dma, tr->len,
+						  DMA_FROM_DEVICE);
+		}
+	}
+	return -EINVAL;
+}
+
+static int msm_spi_setup(struct spi_device *spi)
+{
+	struct msm_spi	*dd;
+	int              rc = 0;
+	u32              spi_ioc;
+	u32              spi_config;
+	u32              mask;
+
+	if (!spi->bits_per_word)
+		spi->bits_per_word = 8;
+	if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
+		dev_err(&spi->dev, "%s: invalid bits_per_word %d\n",
+			__func__, spi->bits_per_word);
+		rc = -EINVAL;
+	}
+	if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP)) {
+		dev_err(&spi->dev, "%s, unsupported mode bits %x\n",
+			__func__,
+			spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
+							  | SPI_LOOP));
+		rc = -EINVAL;
+	}
+	if (spi->chip_select > SPI_NUM_CHIPSELECTS-1) {
+		dev_err(&spi->dev, "%s, chip select %d exceeds max value %d\n",
+			__func__, spi->chip_select, SPI_NUM_CHIPSELECTS - 1);
+		rc = -EINVAL;
+	}
+
+	if (rc)
+		goto err_setup_exit;
+
+	dd = spi_master_get_devdata(spi->master);
+	spi_ioc = readl(dd->base + SPI_IO_CONTROL);
+	mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
+	if (spi->mode & SPI_CS_HIGH)
+		spi_ioc |= mask;
+	else
+		spi_ioc &= ~mask;
+	if (spi->mode & SPI_CPOL)
+		spi_ioc |= SPI_IO_C_CLK_IDLE_HIGH;
+	else
+		spi_ioc &= ~SPI_IO_C_CLK_IDLE_HIGH;
+	writel(spi_ioc, dd->base + SPI_IO_CONTROL);
+
+	spi_config = readl(dd->base + SPI_CONFIG);
+	if (spi->mode & SPI_LOOP)
+		spi_config |= SPI_CFG_LOOPBACK;
+	else
+		spi_config &= ~SPI_CFG_LOOPBACK;
+	if (spi->mode & SPI_CPHA)
+		spi_config &= ~SPI_CFG_INPUT_FIRST;
+	else
+		spi_config |= SPI_CFG_INPUT_FIRST;
+	writel(spi_config, dd->base + SPI_CONFIG);
+
+err_setup_exit:
+	return rc;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int debugfs_iomem_x32_set(void *data, u64 val)
+{
+	iowrite32(val, data);
+	wmb();
+	return 0;
+}
+
+static int debugfs_iomem_x32_get(void *data, u64 *val)
+{
+	*val = ioread32(data);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
+			debugfs_iomem_x32_set, "0x%08llx\n");
+
+static void spi_debugfs_init(struct msm_spi *dd)
+{
+	dd->dent_spi = debugfs_create_dir(dev_name(dd->dev), NULL);
+	if (dd->dent_spi) {
+		int i;
+		for (i = 0; i < ARRAY_SIZE(debugfs_spi_regs); i++) {
+			dd->debugfs_spi_regs[i] =
+			   debugfs_create_file(
+			       debugfs_spi_regs[i].name,
+			       debugfs_spi_regs[i].mode,
+			       dd->dent_spi,
+			       dd->base + debugfs_spi_regs[i].offset,
+			       &fops_iomem_x32);
+		}
+	}
+}
+
+static void spi_debugfs_exit(struct msm_spi *dd)
+{
+	if (dd->dent_spi) {
+		int i;
+		debugfs_remove_recursive(dd->dent_spi);
+		dd->dent_spi = NULL;
+		for (i = 0; i < ARRAY_SIZE(debugfs_spi_regs); i++)
+			dd->debugfs_spi_regs[i] = NULL;
+	}
+}
+#else
+static void spi_debugfs_init(struct msm_spi *dd) {}
+static void spi_debugfs_exit(struct msm_spi *dd) {}
+#endif
+
+/* ===Device attributes begin=== */
+static ssize_t show_stats(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct msm_spi *dd =  spi_master_get_devdata(master);
+
+	return snprintf(buf, PAGE_SIZE,
+			"Device       %s\n"
+			"use_dma ?    %s\n"
+			"DMA configuration:\n"
+			"tx_ch=%d, rx_ch=%d, tx_crci= %d, rx_crci=%d\n"
+			"--statistics--\n"
+			"Rx isrs  = %d\n"
+			"Tx isrs  = %d\n"
+			"DMA error  = %d\n"
+			"--debug--\n"
+			"NA yet\n",
+			dev_name(dev),
+			dd->use_dma ? "yes" : "no",
+			dd->tx_dma_chan,
+			dd->rx_dma_chan,
+			dd->tx_dma_crci,
+			dd->rx_dma_crci,
+			dd->stat_rx,
+			dd->stat_tx,
+			dd->stat_dmov_err
+			);
+}
+
+/* Reset statistics on write */
+static ssize_t set_stats(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct msm_spi *dd = dev_get_drvdata(dev);
+	dd->stat_rx = 0;
+	dd->stat_tx = 0;
+	dd->stat_dmov_err = 0;
+	return count;
+}
+
+static DEVICE_ATTR(stats, S_IRUGO | S_IWUSR, show_stats, set_stats);
+
+static struct attribute *dev_attrs[] = {
+	&dev_attr_stats.attr,
+	NULL,
+};
+
+static struct attribute_group dev_attr_grp = {
+	.attrs = dev_attrs,
+};
+/* ===Device attributes end=== */
+
+/**
+ * spi_dmov_tx_complete_func - DataMover tx completion callback
+ *
+ * Executed in IRQ context (Data Mover's IRQ) DataMover's
+ * spinlock @msm_dmov_lock held.
+ */
+static void spi_dmov_tx_complete_func(struct msm_dmov_cmd *cmd,
+				      unsigned int result,
+				      struct msm_dmov_errdata *err)
+{
+	struct msm_spi *dd;
+
+	if (!(result & DMOV_RSLT_VALID)) {
+		pr_err("Invalid DMOV result: rc=0x%08x, cmd = %p", result, cmd);
+		return;
+	}
+	/* restore original context */
+	dd = container_of(cmd, struct msm_spi, tx_hdr);
+	if (result & DMOV_RSLT_DONE)
+		dd->stat_tx++;
+	else {
+		/* Error or flush */
+		if (result & DMOV_RSLT_ERROR) {
+			dev_err(dd->dev, "DMA error (0x%08x)\n", result);
+			dd->stat_dmov_err++;
+		}
+		if (result & DMOV_RSLT_FLUSH) {
+			/*
+			 * Flushing normally happens in process of
+			 * removing, when we are waiting for outstanding
+			 * DMA commands to be flushed.
+			 */
+			dev_info(dd->dev,
+				 "DMA channel flushed (0x%08x)\n", result);
+		}
+		if (err)
+			dev_err(dd->dev,
+				"Flush data(%08x %08x %08x %08x %08x %08x)\n",
+				err->flush[0], err->flush[1], err->flush[2],
+				err->flush[3], err->flush[4], err->flush[5]);
+		dd->cur_msg->status = -EIO;
+		writel(0, dd->base + SPI_TIME_OUT);
+		complete(&dd->transfer_complete);
+	}
+}
+
+/**
+ * spi_dmov_rx_complete_func - DataMover rx completion callback
+ *
+ * Executed in IRQ context (Data Mover's IRQ)
+ * DataMover's spinlock @msm_dmov_lock held.
+ */
+static void spi_dmov_rx_complete_func(struct msm_dmov_cmd *cmd,
+				      unsigned int result,
+				      struct msm_dmov_errdata *err)
+{
+	struct msm_spi *dd;
+
+	if (!(result & DMOV_RSLT_VALID)) {
+		pr_err("Invalid DMOV result(rc = 0x%08x, cmd = %p)",
+		       result, cmd);
+		return;
+	}
+	/* restore original context */
+	dd = container_of(cmd, struct msm_spi, rx_hdr);
+	if (result & DMOV_RSLT_DONE) {
+		dd->stat_rx++;
+		if (atomic_inc_return(&dd->rx_irq_called) == 1)
+			return;
+		complete(&dd->transfer_complete);
+	} else {
+		/** Error or flush  */
+		if (result & DMOV_RSLT_ERROR) {
+			dev_err(dd->dev, "DMA error(0x%08x)\n", result);
+			dd->stat_dmov_err++;
+		}
+		if (result & DMOV_RSLT_FLUSH) {
+			dev_info(dd->dev,
+				"DMA channel flushed(0x%08x)\n", result);
+		}
+		if (err)
+			dev_err(dd->dev,
+				"Flush data(%08x %08x %08x %08x %08x %08x)\n",
+				err->flush[0], err->flush[1], err->flush[2],
+				err->flush[3], err->flush[4], err->flush[5]);
+		dd->cur_msg->status = -EIO;
+		writel(0, dd->base + SPI_TIME_OUT);
+		complete(&dd->transfer_complete);
+	}
+}
+
+static inline u32 get_chunk_size(struct msm_spi *dd)
+{
+	u32 cache_line = dma_get_cache_alignment();
+
+	return (roundup(sizeof(struct spi_dmov_cmd), DM_BYTE_ALIGN) +
+			  roundup(dd->burst_size, cache_line))*2;
+}
+
+static void msm_spi_teardown_dma(struct msm_spi *dd)
+{
+	int limit = 0;
+
+	if (!dd->use_dma)
+		return;
+
+	while (dd->mode == SPI_DMOV_MODE && limit++ < 50) {
+		msm_dmov_flush(dd->tx_dma_chan);
+		msm_dmov_flush(dd->rx_dma_chan);
+		msleep(10);
+	}
+
+	dma_free_coherent(NULL, get_chunk_size(dd), dd->tx_dmov_cmd,
+			  dd->tx_dmov_cmd_dma);
+	dd->tx_dmov_cmd = dd->rx_dmov_cmd = NULL;
+	dd->tx_padding = dd->rx_padding = NULL;
+}
+
+static __init int msm_spi_init_dma(struct msm_spi *dd)
+{
+	dmov_box *box;
+	u32 cache_line = dma_get_cache_alignment();
+
+	/* Allocate all as one chunk, since all is smaller than page size */
+
+	/* We send NULL device, since it requires coherent_dma_mask id
+	   device definition, we're okay with using system pool */
+	dd->tx_dmov_cmd = dma_alloc_coherent(NULL, get_chunk_size(dd),
+					     &dd->tx_dmov_cmd_dma, GFP_KERNEL);
+	if (dd->tx_dmov_cmd == NULL)
+		return -ENOMEM;
+
+	/* DMA addresses should be 64 bit aligned aligned */
+	dd->rx_dmov_cmd = (struct spi_dmov_cmd *)
+			  ALIGN((size_t)&dd->tx_dmov_cmd[1], DM_BYTE_ALIGN);
+	dd->rx_dmov_cmd_dma = ALIGN(dd->tx_dmov_cmd_dma +
+			      sizeof(struct spi_dmov_cmd), DM_BYTE_ALIGN);
+
+	/* Buffers should be aligned to cache line */
+	dd->tx_padding = (u8 *)ALIGN((size_t)&dd->rx_dmov_cmd[1], cache_line);
+	dd->tx_padding_dma = ALIGN(dd->rx_dmov_cmd_dma +
+			      sizeof(struct spi_dmov_cmd), cache_line);
+	dd->rx_padding = (u8 *)ALIGN((size_t)(dd->tx_padding + dd->burst_size),
+				     cache_line);
+	dd->rx_padding_dma = ALIGN(dd->tx_padding_dma + dd->burst_size,
+				      cache_line);
+
+	/* Setup DM commands */
+	box = &(dd->rx_dmov_cmd->box);
+	box->cmd = CMD_MODE_BOX | CMD_SRC_CRCI(dd->rx_dma_crci);
+	box->src_row_addr = (uint32_t)dd->mem_phys_addr + SPI_INPUT_FIFO;
+	dd->rx_hdr.cmdptr = DMOV_CMD_PTR_LIST |
+				   DMOV_CMD_ADDR(dd->rx_dmov_cmd_dma +
+				   offsetof(struct spi_dmov_cmd, cmd_ptr));
+	dd->rx_hdr.complete_func = spi_dmov_rx_complete_func;
+
+	box = &(dd->tx_dmov_cmd->box);
+	box->cmd = CMD_MODE_BOX | CMD_DST_CRCI(dd->tx_dma_crci);
+	box->dst_row_addr = (uint32_t)dd->mem_phys_addr + SPI_OUTPUT_FIFO;
+	dd->tx_hdr.cmdptr = DMOV_CMD_PTR_LIST |
+			    DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
+			    offsetof(struct spi_dmov_cmd, cmd_ptr));
+	dd->tx_hdr.complete_func = spi_dmov_tx_complete_func;
+
+	dd->tx_dmov_cmd->single_pad.cmd = CMD_MODE_SINGLE | CMD_LC |
+					  CMD_DST_CRCI(dd->tx_dma_crci);
+	dd->tx_dmov_cmd->single_pad.dst = (uint32_t)dd->mem_phys_addr +
+					   SPI_OUTPUT_FIFO;
+	dd->rx_dmov_cmd->single_pad.cmd = CMD_MODE_SINGLE | CMD_LC |
+					  CMD_SRC_CRCI(dd->rx_dma_crci);
+	dd->rx_dmov_cmd->single_pad.src = (uint32_t)dd->mem_phys_addr +
+					  SPI_INPUT_FIFO;
+
+	/* Clear remaining activities on channel */
+	msm_dmov_flush(dd->tx_dma_chan);
+	msm_dmov_flush(dd->rx_dma_chan);
+
+	return 0;
+}
+
+static int __init msm_spi_probe(struct platform_device *pdev)
+{
+	struct spi_master      *master;
+	struct msm_spi	       *dd;
+	struct resource	       *resource;
+	int			rc = 0;
+	struct clk	       *pclk;
+	struct msm_spi_platform_data *pdata = pdev->dev.platform_data;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(struct msm_spi));
+	if (!master) {
+		rc = -ENOMEM;
+		dev_err(&pdev->dev, "master allocation failed\n");
+		goto err_probe_exit;
+	}
+
+	master->bus_num        = pdev->id;
+	master->num_chipselect = SPI_NUM_CHIPSELECTS;
+	master->setup          = msm_spi_setup;
+	master->transfer       = msm_spi_transfer;
+	platform_set_drvdata(pdev, master);
+	dd = spi_master_get_devdata(master);
+
+	dd->irq_in  = platform_get_irq_byname(pdev, "irq_in");
+	dd->irq_out = platform_get_irq_byname(pdev, "irq_out");
+	dd->irq_err = platform_get_irq_byname(pdev, "irq_err");
+	if ((dd->irq_in < 0) || (dd->irq_out < 0) || (dd->irq_err < 0))
+		goto err_probe_res;
+
+	resource  = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!resource) {
+		rc = -ENXIO;
+		goto err_probe_res;
+	}
+	dd->mem_phys_addr = resource->start;
+	dd->mem_size = (resource->end - resource->start) + 1;
+
+	if (pdata && pdata->dma_config) {
+		rc = pdata->dma_config();
+		if (!rc) {
+			resource  = platform_get_resource_byname(pdev,
+					IORESOURCE_DMA, "spidm_channels");
+			if (resource) {
+				dd->rx_dma_chan = resource->start;
+				dd->tx_dma_chan = resource->end;
+
+				resource  = platform_get_resource_byname(pdev,
+						IORESOURCE_DMA, "spidm_crci");
+				if (!resource) {
+					rc = -ENXIO;
+					goto err_probe_res;
+				}
+				dd->rx_dma_crci = resource->start;
+				dd->tx_dma_crci = resource->end;
+				dd->use_dma = 1;
+			}
+		}
+	}
+
+	if (pdata && pdata->gpio_config) {
+		rc = pdata->gpio_config();
+		if (rc) {
+			dev_err(&pdev->dev, "%s: error configuring GPIOs\n",
+			       __func__);
+			goto err_probe_gpio;
+		}
+	}
+
+	spin_lock_init(&dd->queue_lock);
+	INIT_LIST_HEAD(&dd->queue);
+	INIT_WORK(&dd->work_data, msm_spi_workq);
+	dd->workqueue = create_singlethread_workqueue(
+		dev_name(master->dev.parent));
+	if (!dd->workqueue)
+		goto err_probe_workq;
+
+	if (!request_mem_region(dd->mem_phys_addr, dd->mem_size,
+				SPI_QSD_NAME)) {
+		rc = -ENXIO;
+		goto err_probe_reqmem;
+	}
+
+	dd->base = ioremap(dd->mem_phys_addr, dd->mem_size);
+	if (!dd->base)
+		goto err_probe_ioremap;
+
+	dd->dev = &pdev->dev;
+	dd->clk = clk_get(&pdev->dev, "spi_clk");
+	if (IS_ERR(dd->clk)) {
+		dev_err(&pdev->dev, "%s: unable to get spi_clk\n", __func__);
+		rc = PTR_ERR(dd->clk);
+		goto err_probe_clk_get;
+	}
+	rc = clk_enable(dd->clk);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: unable to enable spi_clk\n",
+			__func__);
+		goto err_probe_clk_enable;
+	}
+	pclk = clk_get(&pdev->dev, "spi_pclk");
+	if (!IS_ERR(pclk)) {
+		dd->pclk = pclk;
+		rc = clk_enable(dd->pclk);
+		if (rc) {
+			dev_err(&pdev->dev, "%s: unable to enable spi_pclk\n",
+				__func__);
+			goto err_probe_pclk_enable;
+		}
+	}
+	if (pdata && pdata->max_clock_speed) {
+		msm_spi_clock_set(dd, pdata->max_clock_speed);
+		dd->max_clock_speed = pdata->max_clock_speed;
+	}
+	msm_spi_calculate_fifo_size(dd);
+	writel(0x1, dd->base + SPI_SW_RESET);
+	if (dd->use_dma) {
+		rc = msm_spi_init_dma(dd);
+		if (rc)
+			goto err_probe_dma;
+	}
+	writel(0x00000000, dd->base + SPI_OPERATIONAL);
+	writel(0x00000000, dd->base + SPI_CONFIG);
+	writel(0x00000000, dd->base + SPI_IO_MODES);
+	writel(SPI_IO_C_NO_TRI_STATE, dd->base + SPI_IO_CONTROL);
+	if (!(readl(dd->base + SPI_OPERATIONAL) & SPI_OP_STATE_VALID)) {
+		dev_err(&pdev->dev, "%s: SPI operational state not valid\n",
+			__func__);
+		rc = -1;
+		goto err_probe_state;
+	}
+	writel(SPI_OP_STATE_RUN, dd->base + SPI_OPERATIONAL);
+
+	dd->suspended = 0;
+	dd->transfer_in_progress = 0;
+	dd->mode = SPI_MODE_NONE;
+
+	rc = request_irq(dd->irq_in, msm_spi_input_irq, IRQF_TRIGGER_RISING,
+			  pdev->name, dd);
+	if (rc)
+		goto err_probe_irq1;
+	rc = request_irq(dd->irq_out, msm_spi_output_irq, IRQF_TRIGGER_RISING,
+			  pdev->name, dd);
+	if (rc)
+		goto err_probe_irq2;
+	rc = request_irq(dd->irq_err, msm_spi_error_irq, IRQF_TRIGGER_RISING,
+			  pdev->name, master);
+	if (rc)
+		goto err_probe_irq3;
+
+	rc = spi_register_master(master);
+	if (rc)
+		goto err_probe_reg_master;
+
+	rc = sysfs_create_group(&(dd->dev->kobj), &dev_attr_grp);
+	if (rc) {
+		dev_err(&pdev->dev, "failed to create dev. attrs : %d\n", rc);
+		goto err_attrs;
+	}
+
+	spi_debugfs_init(dd);
+
+	return 0;
+
+err_attrs:
+err_probe_reg_master:
+	free_irq(dd->irq_err, master);
+err_probe_irq3:
+	free_irq(dd->irq_out, dd);
+err_probe_irq2:
+	free_irq(dd->irq_in, dd);
+err_probe_irq1:
+err_probe_state:
+	msm_spi_teardown_dma(dd);
+err_probe_dma:
+	if (dd->pclk)
+		clk_disable(dd->pclk);
+err_probe_pclk_enable:
+	if (dd->pclk)
+		clk_put(dd->pclk);
+	clk_disable(dd->clk);
+err_probe_clk_enable:
+	clk_put(dd->clk);
+err_probe_clk_get:
+	iounmap(dd->base);
+err_probe_ioremap:
+	release_mem_region(dd->mem_phys_addr, dd->mem_size);
+err_probe_reqmem:
+	destroy_workqueue(dd->workqueue);
+err_probe_workq:
+err_probe_gpio:
+	if (pdata && pdata->gpio_release)
+		pdata->gpio_release();
+err_probe_res:
+	spi_master_put(master);
+err_probe_exit:
+	return rc;
+}
+
+#ifdef CONFIG_PM
+static int msm_spi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct msm_spi    *dd;
+	int                limit = 0;
+
+	if (!master)
+		goto suspend_exit;
+	dd = spi_master_get_devdata(master);
+	if (!dd)
+		goto suspend_exit;
+	dd->suspended = 1;
+	while ((!list_empty(&dd->queue) || dd->transfer_in_progress) &&
+	       limit < 50) {
+		if (dd->mode == SPI_DMOV_MODE) {
+			msm_dmov_flush(dd->tx_dma_chan);
+			msm_dmov_flush(dd->rx_dma_chan);
+		}
+		limit++;
+		msleep(1);
+	}
+
+	disable_irq(dd->irq_in);
+	disable_irq(dd->irq_out);
+	disable_irq(dd->irq_err);
+	clk_disable(dd->clk);
+
+suspend_exit:
+	return 0;
+}
+
+static int msm_spi_resume(struct platform_device *pdev)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct msm_spi    *dd;
+	int rc;
+
+	if (!master)
+		goto resume_exit;
+	dd = spi_master_get_devdata(master);
+	if (!dd)
+		goto resume_exit;
+
+	rc = clk_enable(dd->clk);
+	if (rc) {
+		dev_err(dd->dev, "%s: unable to enable spi_clk\n",
+			__func__);
+		goto resume_exit;
+	}
+
+	enable_irq(dd->irq_in);
+	enable_irq(dd->irq_out);
+	enable_irq(dd->irq_err);
+	dd->suspended = 0;
+resume_exit:
+	return 0;
+}
+#else
+#define msm_spi_suspend NULL
+#define msm_spi_resume NULL
+#endif /* CONFIG_PM */
+
+static int __devexit msm_spi_remove(struct platform_device *pdev)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct msm_spi    *dd = spi_master_get_devdata(master);
+	struct msm_spi_platform_data *pdata = pdev->dev.platform_data;
+
+	spi_debugfs_exit(dd);
+	sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
+
+	free_irq(dd->irq_in, dd);
+	free_irq(dd->irq_out, dd);
+	free_irq(dd->irq_err, master);
+
+	msm_spi_teardown_dma(dd);
+
+	if (pdata && pdata->gpio_release)
+		pdata->gpio_release();
+
+	iounmap(dd->base);
+	release_mem_region(dd->mem_phys_addr, dd->mem_size);
+	clk_disable(dd->clk);
+	clk_put(dd->clk);
+	if (dd->pclk) {
+		clk_disable(dd->pclk);
+		clk_put(dd->pclk);
+	}
+	destroy_workqueue(dd->workqueue);
+	platform_set_drvdata(pdev, 0);
+	spi_unregister_master(master);
+	spi_master_put(master);
+
+	return 0;
+}
+
+static struct platform_driver msm_spi_driver = {
+	.probe          = msm_spi_probe,
+	.driver		= {
+		.name	= "msm_spi",
+		.owner	= THIS_MODULE,
+	},
+	.suspend        = msm_spi_suspend,
+	.resume         = msm_spi_resume,
+	.remove		= __exit_p(msm_spi_remove),
+};
+
+static int __init msm_spi_init(void)
+{
+	return platform_driver_register(&msm_spi_driver);
+}
+module_init(msm_spi_init);
+
+static void __exit msm_spi_exit(void)
+{
+	platform_driver_unregister(&msm_spi_driver);
+}
+module_exit(msm_spi_exit);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 78bb222..7459c30 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -510,6 +510,24 @@
 # LAST -- dummy/emulated controller
 #
 
+config USB_GADGET_MSM_72K
+	boolean "MSM 72K Device Controller"
+	depends on ARCH_MSM
+	select USB_GADGET_SELECTED
+	select USB_GADGET_DUALSPEED
+	help
+	   USB gadget driver for Qualcomm MSM 72K architecture.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "msm72k" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_MSM_72K
+	tristate
+	depends on USB_GADGET_MSM_72K
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 config USB_GADGET_DUMMY_HCD
 	boolean "Dummy HCD (DEVELOPMENT)"
 	depends on USB=y || (USB=m && USB_GADGET=m)
@@ -856,6 +874,12 @@
 	help
 	  Provides adb function for android gadget driver.
 
+config USB_ANDROID_DIAG
+	boolean "USB MSM7K Diag Function"
+	depends on USB_ANDROID
+	help
+	  Qualcomm diagnostics interface support.
+
 config USB_ANDROID_MASS_STORAGE
 	boolean "Android gadget mass storage function"
 	depends on USB_ANDROID && SWITCH
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index d385002..83122fd 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -28,6 +28,7 @@
 obj-$(CONFIG_USB_CI13XXX)	+= ci13xxx_udc.o
 obj-$(CONFIG_USB_S3C_HSOTG)	+= s3c-hsotg.o
 obj-$(CONFIG_USB_LANGWELL)	+= langwell_udc.o
+obj-$(CONFIG_USB_MSM_72K)	+= msm72k_udc.o
 
 #
 # USB gadget drivers
@@ -71,3 +72,6 @@
 obj-$(CONFIG_USB_ANDROID_RNDIS)	+= f_rndis.o u_ether.o
 obj-$(CONFIG_USB_ANDROID_ACCESSORY)	+= f_accessory.o
 
+# MSM specific
+obj-$(CONFIG_USB_ANDROID_DIAG)	+= diag.o
+
diff --git a/drivers/usb/gadget/diag.c b/drivers/usb/gadget/diag.c
new file mode 100644
index 0000000..c100ed4
--- /dev/null
+++ b/drivers/usb/gadget/diag.c
@@ -0,0 +1,935 @@
+/*
+ * Diag Function Device - Route DIAG frames between SMD and USB
+ *
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+
+#include <mach/msm_smd.h>
+
+#include <linux/usb/android_composite.h>
+
+#define NO_HDLC 1
+#define ROUTE_TO_USERSPACE 1
+
+#if 1
+#define TRACE(tag,data,len,decode) do {} while(0)
+#else
+static void TRACE(const char *tag, const void *_data, int len, int decode)
+{
+	const unsigned char *data = _data;
+	int escape = 0;
+
+	printk(KERN_INFO "%s", tag);
+	if (decode) {
+		while (len-- > 0) {
+			unsigned x = *data++;
+			if (x == 0x7e) {
+				printk(" $$");
+				escape = 0;
+				continue;
+			}
+			if (x == 0x7d) {
+				escape = 1;
+				continue;
+			}
+			if (escape) {
+				escape = 0;
+				printk(" %02x", x ^ 0x20);
+			} else {
+				printk(" %02x", x);
+			}
+		}
+	} else {
+		while (len-- > 0) {
+			printk(" %02x", *data++);
+		}
+		printk(" $$");
+	}
+	printk("\n");
+}
+#endif
+
+#define HDLC_MAX 4096
+
+#define TX_REQ_BUF_SZ 8192
+#define RX_REQ_BUF_SZ 8192
+
+/* number of tx/rx requests to allocate */
+#define TX_REQ_NUM 4
+#define RX_REQ_NUM 4
+
+struct diag_context
+{
+	struct usb_function function;
+	struct usb_composite_dev *cdev;
+	struct usb_ep *out;
+	struct usb_ep *in;
+	struct list_head tx_req_idle;
+	struct list_head rx_req_idle;
+	spinlock_t req_lock;
+#if ROUTE_TO_USERSPACE
+	struct mutex user_lock;
+#define ID_TABLE_SZ 10 /* keep this small */
+	struct list_head rx_req_user;
+	wait_queue_head_t read_wq;
+	wait_queue_head_t write_wq;
+	char *user_read_buf;
+	uint32_t user_read_len;
+	char *user_readp;
+	bool opened;
+
+	/* list of registered command ids to be routed to userspace */
+	unsigned char id_table[ID_TABLE_SZ];
+#endif
+	smd_channel_t *ch;
+	int in_busy;
+#ifdef CONFIG_ARCH_QSD8X50
+	smd_channel_t *ch_dsp;
+	int in_busy_dsp;
+#endif
+	int online;
+
+	/* assembly buffer for USB->A9 HDLC frames */
+	unsigned char hdlc_buf[HDLC_MAX];
+	unsigned hdlc_count;
+	unsigned hdlc_escape;
+
+	u64 tx_count; /* to smd */
+	u64 rx_count; /* from smd */
+
+	int function_enable;
+};
+
+static struct usb_interface_descriptor diag_interface_desc = {
+	.bLength                = USB_DT_INTERFACE_SIZE,
+	.bDescriptorType        = USB_DT_INTERFACE,
+	.bInterfaceNumber       = 0,
+	.bNumEndpoints          = 2,
+	.bInterfaceClass        = 0xFF,
+	.bInterfaceSubClass     = 0xFF,
+	.bInterfaceProtocol     = 0xFF,
+};
+
+static struct usb_endpoint_descriptor diag_highspeed_in_desc = {
+	.bLength                = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType        = USB_DT_ENDPOINT,
+	.bEndpointAddress       = USB_DIR_IN,
+	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize         = __constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor diag_highspeed_out_desc = {
+	.bLength                = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType        = USB_DT_ENDPOINT,
+	.bEndpointAddress       = USB_DIR_OUT,
+	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize         = __constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor diag_fullspeed_in_desc = {
+	.bLength                = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType        = USB_DT_ENDPOINT,
+	.bEndpointAddress       = USB_DIR_IN,
+	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor diag_fullspeed_out_desc = {
+	.bLength                = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType        = USB_DT_ENDPOINT,
+	.bEndpointAddress       = USB_DIR_OUT,
+	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *fs_diag_descs[] = {
+	(struct usb_descriptor_header *) &diag_interface_desc,
+	(struct usb_descriptor_header *) &diag_fullspeed_in_desc,
+	(struct usb_descriptor_header *) &diag_fullspeed_out_desc,
+	NULL,
+};
+
+static struct usb_descriptor_header *hs_diag_descs[] = {
+	(struct usb_descriptor_header *) &diag_interface_desc,
+	(struct usb_descriptor_header *) &diag_highspeed_in_desc,
+	(struct usb_descriptor_header *) &diag_highspeed_out_desc,
+	NULL,
+};
+
+static struct diag_context _context;
+
+static inline struct diag_context *func_to_dev(struct usb_function *f)
+{
+	return container_of(f, struct diag_context, function);
+}
+
+static void smd_try_to_send(struct diag_context *ctxt);
+#ifdef CONFIG_ARCH_QSD8X50
+static void dsp_try_to_send(struct diag_context *ctxt);
+#endif
+
+static void diag_queue_out(struct diag_context *ctxt);
+
+/* add a request to the tail of a list */
+static void req_put(struct diag_context *ctxt, struct list_head *head,
+		struct usb_request *req)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctxt->req_lock, flags);
+	list_add_tail(&req->list, head);
+	spin_unlock_irqrestore(&ctxt->req_lock, flags);
+}
+
+/* remove a request from the head of a list */
+static struct usb_request *req_get(struct diag_context *ctxt,
+		struct list_head *head)
+{
+	struct usb_request *req = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctxt->req_lock, flags);
+	if (!list_empty(head)) {
+		req = list_first_entry(head, struct usb_request, list);
+		list_del(&req->list);
+	}
+	spin_unlock_irqrestore(&ctxt->req_lock, flags);
+
+	return req;
+}
+
+static void reqs_free(struct diag_context *ctxt, struct usb_ep *ep,
+			struct list_head *head)
+{
+	struct usb_request *req;
+	while ((req = req_get(ctxt, head))) {
+		kfree(req->buf);
+		usb_ep_free_request(ep, req);
+	}
+}
+
+#if ROUTE_TO_USERSPACE
+#define USB_DIAG_IOC_MAGIC 0xFF
+#define USB_DIAG_FUNC_IOC_REGISTER_SET _IOW(USB_DIAG_IOC_MAGIC, 3, char *)
+
+static long diag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct diag_context *ctxt = &_context;
+	void __user *argp = (void __user *)arg;
+	unsigned long flags;
+	unsigned char temp_id_table[ID_TABLE_SZ];
+
+	if (cmd != USB_DIAG_FUNC_IOC_REGISTER_SET) {
+		pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd));
+		return -EINVAL;
+	}
+
+	if (copy_from_user(temp_id_table, (unsigned char *)argp, ID_TABLE_SZ))
+		return -EFAULT;
+
+	spin_lock_irqsave(&ctxt->req_lock, flags);
+	memcpy(ctxt->id_table, temp_id_table, ID_TABLE_SZ);
+	spin_unlock_irqrestore(&ctxt->req_lock, flags);
+
+	return 0;
+}
+
+static ssize_t diag_read(struct file *fp, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	struct diag_context *ctxt = &_context;
+	struct usb_request *req = 0;
+	int ret = 0;
+
+	mutex_lock(&ctxt->user_lock);
+
+	if (ctxt->user_read_len && ctxt->user_readp) {
+		if (count > ctxt->user_read_len)
+			count = ctxt->user_read_len;
+		if (copy_to_user(buf, ctxt->user_readp, count))
+			ret = -EFAULT;
+		else {
+			ctxt->user_readp += count;
+			ctxt->user_read_len -= count;
+			ret = count;
+		}
+		goto end;
+	}
+
+	mutex_unlock(&ctxt->user_lock);
+	ret = wait_event_interruptible(ctxt->read_wq,
+		(req = req_get(ctxt, &ctxt->rx_req_user)) || !ctxt->online);
+	mutex_lock(&ctxt->user_lock);
+	if (ret < 0) {
+		pr_err("%s: wait_event_interruptible error %d\n",
+			__func__, ret);
+		goto end;
+	}
+	if (!ctxt->online) {
+		pr_err("%s: offline\n", __func__);
+		ret = -EIO;
+		goto end;
+	}
+	if (req) {
+		if (req->actual == 0) {
+			pr_info("%s: no data\n", __func__);
+			goto end;
+		}
+		if (count > req->actual)
+			count = req->actual;
+		if (copy_to_user(buf, req->buf, count)) {
+			ret = -EFAULT;
+			goto end;
+		}
+		req->actual -= count;
+		if (req->actual) {
+			memcpy(ctxt->user_read_buf, req->buf + count, req->actual);
+			ctxt->user_read_len = req->actual;
+			ctxt->user_readp = ctxt->user_read_buf;
+		}
+		ret = count;
+	}
+
+end:
+	if (req)
+		req_put(ctxt, &ctxt->rx_req_idle, req);
+
+	mutex_unlock(&ctxt->user_lock);
+	return ret;
+}
+
+static ssize_t diag_write(struct file *fp, const char __user *buf,
+			size_t count, loff_t *pos)
+{
+	struct diag_context *ctxt = &_context;
+	struct usb_request *req = 0;
+	int ret = 0;
+
+	ret = wait_event_interruptible(ctxt->write_wq,
+		((req = req_get(ctxt, &ctxt->tx_req_idle)) || !ctxt->online));
+
+	mutex_lock(&ctxt->user_lock);
+	if (ret < 0) {
+		pr_err("%s: wait_event_interruptible error %d\n",
+			__func__, ret);
+		goto end;
+	}
+
+	if (!ctxt->online) {
+		pr_err("%s: offline\n", __func__);
+		ret = -EIO;
+		goto end;
+	}
+
+	if (count > TX_REQ_BUF_SZ)
+		count = TX_REQ_BUF_SZ;
+
+	if (req) {
+		if (copy_from_user(req->buf, buf, count)) {
+			ret = -EFAULT;
+			goto end;
+		}
+
+		req->length = count;
+		ret = usb_ep_queue(ctxt->in, req, GFP_ATOMIC);
+		if (ret < 0) {
+			pr_err("%s: usb_ep_queue error %d\n", __func__, ret);
+			goto end;
+		}
+
+		ret = req->length;
+	}
+
+end:
+	if (req)
+		req_put(ctxt, &ctxt->tx_req_idle, req);
+
+	mutex_unlock(&ctxt->user_lock);
+	return ret;
+}
+
+static int diag_open(struct inode *ip, struct file *fp)
+{
+	struct diag_context *ctxt = &_context;
+	int rc = 0;
+
+	mutex_lock(&ctxt->user_lock);
+	if (ctxt->opened) {
+		pr_err("%s: already opened\n", __func__);
+		rc = -EBUSY;
+		goto done;
+	}
+	ctxt->user_read_len = 0;
+	ctxt->user_readp = 0;
+	if (!ctxt->user_read_buf) {
+		ctxt->user_read_buf = kmalloc(RX_REQ_BUF_SZ, GFP_KERNEL);
+		if (!ctxt->user_read_buf) {
+			rc = -ENOMEM;
+			goto done;
+		}
+	}
+	ctxt->opened = true;
+
+done:
+	mutex_unlock(&ctxt->user_lock);
+	return rc;
+}
+
+static int diag_release(struct inode *ip, struct file *fp)
+{
+	struct diag_context *ctxt = &_context;
+
+	mutex_lock(&ctxt->user_lock);
+	ctxt->opened = false;
+	ctxt->user_read_len = 0;
+	ctxt->user_readp = 0;
+	if (ctxt->user_read_buf) {
+		kfree(ctxt->user_read_buf);
+		ctxt->user_read_buf = 0;
+	}
+	mutex_unlock(&ctxt->user_lock);
+
+	return 0;
+}
+
+static struct file_operations diag_fops = {
+	.owner =   THIS_MODULE,
+	.read =    diag_read,
+	.write =   diag_write,
+	.open =    diag_open,
+	.release = diag_release,
+	.unlocked_ioctl = diag_ioctl,
+};
+
+static struct miscdevice diag_device_fops = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "diag",
+	.fops = &diag_fops,
+};
+#endif
+
+static void diag_in_complete(struct usb_ep *ept, struct usb_request *req)
+{
+	struct diag_context *ctxt = req->context;
+#if ROUTE_TO_USERSPACE
+	char c;
+#endif
+
+	ctxt->in_busy = 0;
+	req_put(ctxt, &ctxt->tx_req_idle, req);
+
+#if ROUTE_TO_USERSPACE
+	c = *((char *)req->buf + req->actual - 1);
+	if (c == 0x7e)
+		wake_up(&ctxt->write_wq);
+#endif
+
+	smd_try_to_send(ctxt);
+}
+
+#ifdef CONFIG_ARCH_QSD8X50
+static void diag_dsp_in_complete(struct usb_ep *ept, struct usb_request *req)
+{
+	struct diag_context *ctxt = req->context;
+
+	ctxt->in_busy_dsp = 0;
+	req_put(ctxt, &ctxt->tx_req_idle, req);
+	dsp_try_to_send(ctxt);
+	wake_up(&ctxt->write_wq);
+}
+#endif
+
+static void diag_process_hdlc(struct diag_context *ctxt, void *_data, unsigned len)
+{
+	unsigned char *data = _data;
+	unsigned count = ctxt->hdlc_count;
+	unsigned escape = ctxt->hdlc_escape;
+	unsigned char *hdlc = ctxt->hdlc_buf;
+
+	while (len-- > 0) {
+		unsigned char x = *data++;
+		if (x == 0x7E) { 
+			if (count > 2) {
+				/* we're just ignoring the crc here */
+				TRACE("PC>", hdlc, count - 2, 0);
+				if (ctxt->ch)
+					smd_write(ctxt->ch, hdlc, count - 2);
+			}
+			count = 0;
+			escape = 0;
+		} else if (x == 0x7D) {
+			escape = 1;
+		} else {
+			if (escape) {
+				x = x ^ 0x20;
+				escape = 0;
+			}
+			hdlc[count++] = x;
+
+			/* discard frame if we overflow */
+			if (count == HDLC_MAX)
+				count = 0;
+		}
+	}
+
+	ctxt->hdlc_count = count;
+	ctxt->hdlc_escape = escape;
+}
+
+#if ROUTE_TO_USERSPACE
+static int if_route_to_userspace(struct diag_context *ctxt, unsigned int cmd_id)
+{
+	unsigned long flags;
+	int i;
+
+	if (!ctxt->opened || cmd_id == 0)
+		return 0;
+
+	/* command ids 0xfb..0xff are not used by msm diag; we steal these ids
+	 * for communication between userspace tool and host test tool.
+	 */
+	if (cmd_id >= 0xfb && cmd_id <= 0xff)
+		return 1;
+
+	spin_lock_irqsave(&ctxt->req_lock, flags);
+	for (i = 0; i < ARRAY_SIZE(ctxt->id_table); i++)
+		if (ctxt->id_table[i] == cmd_id) {
+			/* if the command id equals to any of registered ids,
+			 * route to userspace to handle.
+			 */
+			spin_unlock_irqrestore(&ctxt->req_lock, flags);
+			return 1;
+		}
+	spin_unlock_irqrestore(&ctxt->req_lock, flags);
+
+	return 0;
+}
+#endif
+
+static void diag_out_complete(struct usb_ep *ept, struct usb_request *req)
+{
+	struct diag_context *ctxt = req->context;
+
+	if (req->status == 0) {
+#if ROUTE_TO_USERSPACE
+		unsigned int cmd_id = *((unsigned char *)req->buf);
+		if (if_route_to_userspace(ctxt, cmd_id)) {
+			req_put(ctxt, &ctxt->rx_req_user, req);
+			wake_up(&ctxt->read_wq);
+			diag_queue_out(ctxt);
+			return;
+		}
+#endif
+
+#if NO_HDLC
+		TRACE("PC>", req->buf, req->actual, 0);
+		if (ctxt->ch)
+			smd_write(ctxt->ch, req->buf, req->actual);
+#else
+		diag_process_hdlc(ctxt, req->buf, req->actual);
+#endif
+		ctxt->tx_count += req->actual;
+	}
+
+	req_put(ctxt, &ctxt->rx_req_idle, req);
+	diag_queue_out(ctxt);
+}
+
+static void diag_queue_out(struct diag_context *ctxt)
+{
+	struct usb_request *req;
+	int rc;
+
+	req = req_get(ctxt, &ctxt->rx_req_idle);
+	if (!req) {
+		pr_err("%s: rx req queue - out of buffer\n", __func__);
+		return;
+	}
+
+	req->complete = diag_out_complete;
+	req->context = ctxt;
+	req->length = RX_REQ_BUF_SZ;
+
+	rc = usb_ep_queue(ctxt->out, req, GFP_ATOMIC);
+	if (rc < 0) {
+		pr_err("%s: usb_ep_queue failed: %d\n", __func__, rc);
+		req_put(ctxt, &ctxt->rx_req_idle, req);
+	}
+}
+
+static void smd_try_to_send(struct diag_context *ctxt)
+{
+again:
+	if (ctxt->ch && (!ctxt->in_busy)) {
+		int r = smd_read_avail(ctxt->ch);
+
+		if (r > TX_REQ_BUF_SZ) {
+			return;
+		}
+		if (r > 0) {
+			struct usb_request *req;
+			req = req_get(ctxt, &ctxt->tx_req_idle);
+			if (!req) {
+				pr_err("%s: tx req queue is out of buffers\n",
+					__func__);
+				return;
+			}
+			smd_read(ctxt->ch, req->buf, r);
+			ctxt->rx_count += r;
+
+			if (!ctxt->online) {
+//				printk("$$$ discard %d\n", r);
+				req_put(ctxt, &ctxt->tx_req_idle, req);
+				goto again;
+			}
+			req->complete = diag_in_complete;
+			req->context = ctxt;
+			req->length = r;
+
+			TRACE("A9>", req->buf, r, 1);
+			ctxt->in_busy = 1;
+			r = usb_ep_queue(ctxt->in, req, GFP_ATOMIC);
+			if (r < 0) {
+				pr_err("%s: usb_ep_queue failed: %d\n",
+					__func__, r);
+				req_put(ctxt, &ctxt->tx_req_idle, req);
+				ctxt->in_busy = 0;
+			}
+		}
+	}
+}
+
+static void smd_diag_notify(void *priv, unsigned event)
+{
+	struct diag_context *ctxt = priv;
+	smd_try_to_send(ctxt);
+}
+
+#ifdef CONFIG_ARCH_QSD8X50
+static void dsp_try_to_send(struct diag_context *ctxt)
+{
+again:
+	if (ctxt->ch_dsp && (!ctxt->in_busy_dsp)) {
+		int r = smd_read_avail(ctxt->ch_dsp);
+
+		if (r > TX_REQ_BUF_SZ) {
+			return;
+		}
+		if (r > 0) {
+			struct usb_request *req;
+			req = req_get(ctxt, &ctxt->tx_req_idle);
+			if (!req) {
+				pr_err("%s: tx req queue is out of buffers\n",
+					__func__);
+				return;
+			}
+			smd_read(ctxt->ch_dsp, req->buf, r);
+
+			if (!ctxt->online) {
+//				printk("$$$ discard %d\n", r);
+				req_put(ctxt, &ctxt->tx_req_idle, req);
+				goto again;
+			}
+			req->complete = diag_dsp_in_complete;
+			req->context = ctxt;
+			req->length = r;
+
+			TRACE("Q6>", req->buf, r, 1);
+			ctxt->in_busy_dsp = 1;
+			r = usb_ep_queue(ctxt->in, req, GFP_ATOMIC);
+			if (r < 0) {
+				pr_err("%s: usb_ep_queue failed: %d\n",
+					__func__, r);
+				req_put(ctxt, &ctxt->tx_req_idle, req);
+				ctxt->in_busy_dsp = 0;
+			}
+		}
+	}
+}
+
+static void dsp_diag_notify(void *priv, unsigned event)
+{
+	struct diag_context *ctxt = priv;
+	dsp_try_to_send(ctxt);
+}
+#endif
+
+static int __init create_bulk_endpoints(struct diag_context *ctxt,
+				struct usb_endpoint_descriptor *in_desc,
+				struct usb_endpoint_descriptor *out_desc)
+{
+	struct usb_composite_dev *cdev = ctxt->cdev;
+	struct usb_ep *ep;
+	struct usb_request *req;
+	int n;
+
+	ep = usb_ep_autoconfig(cdev->gadget, in_desc);
+	if (!ep) {
+		DBG(cdev, "usb_ep_autoconfig for ep_in failed\n");
+		return -ENODEV;
+	}
+	ctxt->in = ep;
+
+	ep = usb_ep_autoconfig(cdev->gadget, out_desc);
+	if (!ep) {
+		return -ENODEV;
+	}
+	ctxt->out = ep;
+
+	ctxt->tx_count = ctxt->rx_count = 0;
+
+	for (n = 0; n < RX_REQ_NUM; n++) {
+		req = usb_ep_alloc_request(ctxt->out, GFP_KERNEL);
+		if (!req) {
+			DBG(cdev, "%s: usb_ep_alloc_request out of memory\n",
+				__func__);
+			goto rx_fail;
+		}
+		req->buf = kmalloc(RX_REQ_BUF_SZ, GFP_KERNEL);
+		if (!req->buf) {
+			DBG(cdev, "%s: kmalloc out of memory\n", __func__);
+			goto rx_fail;
+		}
+		req->context = ctxt;
+		req->complete = diag_out_complete;
+		req_put(ctxt, &ctxt->rx_req_idle, req);
+	}
+
+	for (n = 0; n < TX_REQ_NUM; n++) {
+		req = usb_ep_alloc_request(ctxt->in, GFP_KERNEL);
+		if (!req) {
+			DBG(cdev, "%s: usb_ep_alloc_request out of memory\n",
+				__func__);
+			goto tx_fail;
+		}
+		req->buf = kmalloc(TX_REQ_BUF_SZ, GFP_KERNEL);
+		if (!req->buf) {
+			DBG(cdev, "%s: kmalloc out of memory\n", __func__);
+			goto tx_fail;
+		}
+		req->context = ctxt;
+		req->complete = diag_in_complete;
+		req_put(ctxt, &ctxt->tx_req_idle, req);
+	}
+
+	return 0;
+
+tx_fail:
+	reqs_free(ctxt, ctxt->in, &ctxt->tx_req_idle);
+rx_fail:
+	reqs_free(ctxt, ctxt->out, &ctxt->rx_req_idle);
+	return -ENOMEM;
+}
+
+static int
+diag_function_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = c->cdev;
+	struct diag_context	*ctxt = func_to_dev(f);
+	int			id;
+	int			ret;
+
+	ctxt->cdev = cdev;
+
+	/* allocate interface ID(s) */
+	id = usb_interface_id(c, f);
+	if (id < 0)
+		return id;
+	diag_interface_desc.bInterfaceNumber = id;
+
+	/* allocate endpoints */
+	ret = create_bulk_endpoints(ctxt, &diag_fullspeed_in_desc,
+			&diag_fullspeed_out_desc);
+	if (ret)
+		return ret;
+
+	/* support high speed hardware */
+	if (gadget_is_dualspeed(c->cdev->gadget)) {
+		diag_highspeed_in_desc.bEndpointAddress =
+			diag_fullspeed_in_desc.bEndpointAddress;
+		diag_highspeed_out_desc.bEndpointAddress =
+			diag_fullspeed_out_desc.bEndpointAddress;
+	}
+
+#if ROUTE_TO_USERSPACE
+	misc_register(&diag_device_fops);
+#endif
+
+	return 0;
+}
+
+static void
+diag_function_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct diag_context	*ctxt = func_to_dev(f);
+	reqs_free(ctxt, ctxt->out, &ctxt->rx_req_idle);
+	reqs_free(ctxt, ctxt->in, &ctxt->tx_req_idle);
+
+#if ROUTE_TO_USERSPACE
+	misc_deregister(&diag_device_fops);
+#endif
+
+	ctxt->tx_count = ctxt->rx_count = 0;
+}
+
+static int diag_function_set_alt(struct usb_function *f,
+		unsigned intf, unsigned alt)
+{
+	struct diag_context	*ctxt = func_to_dev(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+#if ROUTE_TO_USERSPACE
+	struct usb_request *req;
+#endif
+	int ret;
+
+	ret = usb_ep_enable(ctxt->in,
+			ep_choose(cdev->gadget,
+				&diag_highspeed_in_desc,
+				&diag_fullspeed_in_desc));
+	if (ret)
+		return ret;
+	ret = usb_ep_enable(ctxt->out,
+			ep_choose(cdev->gadget,
+				&diag_highspeed_out_desc,
+				&diag_fullspeed_out_desc));
+	if (ret) {
+		usb_ep_disable(ctxt->in);
+		return ret;
+	}
+	ctxt->online = 1;
+
+#if ROUTE_TO_USERSPACE
+	/* recycle unhandled rx reqs to user if any */
+	while ((req = req_get(ctxt, &ctxt->rx_req_user)))
+		req_put(ctxt, &ctxt->rx_req_idle, req);
+#endif
+
+	diag_queue_out(ctxt);
+	smd_try_to_send(ctxt);
+#ifdef CONFIG_ARCH_QSD8X50
+	dsp_try_to_send(ctxt);
+#endif
+
+#if ROUTE_TO_USERSPACE
+	wake_up(&ctxt->read_wq);
+	wake_up(&ctxt->write_wq);
+#endif
+
+	return 0;
+}
+
+static void diag_function_disable(struct usb_function *f)
+{
+	struct diag_context	*ctxt = func_to_dev(f);
+
+	ctxt->online = 0;
+#if ROUTE_TO_USERSPACE
+	wake_up(&ctxt->read_wq);
+	wake_up(&ctxt->write_wq);
+#endif
+	usb_ep_disable(ctxt->in);
+	usb_ep_disable(ctxt->out);
+}
+
+static int diag_set_enabled(const char *val, struct kernel_param *kp)
+{
+	int enabled = simple_strtol(val, NULL, 0);
+	if (_context.cdev)
+		android_enable_function(&_context.function, enabled);
+	_context.function_enable = !!enabled;
+	return 0;
+}
+
+static int diag_get_tx_rx_count(char *buffer, struct kernel_param *kp)
+{
+	struct diag_context *ctxt = &_context;
+
+	return sprintf(buffer, "tx: %llu bytes, rx: %llu bytes",
+	ctxt->tx_count, ctxt->rx_count);
+}
+module_param_call(tx_rx_count, NULL, diag_get_tx_rx_count, NULL, 0444);
+
+static int diag_get_enabled(char *buffer, struct kernel_param *kp)
+{
+	buffer[0] = '0' + !_context.function.disabled;
+	return 1;
+}
+module_param_call(enabled, diag_set_enabled, diag_get_enabled, NULL, 0664);
+
+
+int diag_bind_config(struct usb_configuration *c)
+{
+	struct diag_context *ctxt = &_context;
+	int ret;
+
+	printk(KERN_INFO "diag_bind_config\n");
+
+	ret = smd_open("SMD_DIAG", &ctxt->ch, ctxt, smd_diag_notify);
+	if (ret)
+		return ret;
+
+#ifdef CONFIG_ARCH_QSD8X50
+	ret = smd_open("DSP_DIAG", &ctxt->ch_dsp, ctxt, dsp_diag_notify);
+	if (ret) {
+		pr_err("%s: smd_open failed (DSP_DIAG)\n", __func__);
+		return ret;
+	}
+#endif
+
+	ctxt->cdev = c->cdev;
+	ctxt->function.name = "diag";
+	ctxt->function.descriptors = fs_diag_descs;
+	ctxt->function.hs_descriptors = hs_diag_descs;
+	ctxt->function.bind = diag_function_bind;
+	ctxt->function.unbind = diag_function_unbind;
+	ctxt->function.set_alt = diag_function_set_alt;
+	ctxt->function.disable = diag_function_disable;
+
+	ctxt->function.disabled = !_context.function_enable;
+
+	return usb_add_function(c, &ctxt->function);
+}
+
+static struct android_usb_function diag_function = {
+	.name = "diag",
+	.bind_config = diag_bind_config,
+};
+
+static int __init init(void)
+{
+	struct diag_context *ctxt = &_context;
+
+	printk(KERN_INFO "diag init\n");
+	spin_lock_init(&ctxt->req_lock);
+	INIT_LIST_HEAD(&ctxt->rx_req_idle);
+	INIT_LIST_HEAD(&ctxt->tx_req_idle);
+#if ROUTE_TO_USERSPACE
+	mutex_init(&ctxt->user_lock);
+	INIT_LIST_HEAD(&ctxt->rx_req_user);
+	init_waitqueue_head(&ctxt->read_wq);
+	init_waitqueue_head(&ctxt->write_wq);
+#endif
+
+	android_register_function(&diag_function);
+	return 0;
+}
+module_init(init);
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e511fec..2c7a8e6c 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -126,6 +126,12 @@
 #define gadget_is_ci13xxx(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_MSM_72K
+#define	gadget_is_msm72k(g)	!strcmp("msm72k_udc", (g)->name)
+#else
+#define	gadget_is_msm72k(g)	0
+#endif
+
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
 // ...
@@ -200,6 +206,8 @@
 		return 0x25;
 	else if (gadget_is_s3c_hsotg(gadget))
 		return 0x26;
+	else if (gadget_is_msm72k(gadget))
+		return 0x27;
 	return -ENOENT;
 }
 
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
new file mode 100644
index 0000000..ac1b9ec
--- /dev/null
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -0,0 +1,1937 @@
+/*
+ * Driver for HighSpeed USB Client Controller in MSM7K
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *         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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/board.h>
+#include <mach/msm_hsusb.h>
+#include <linux/device.h>
+#include <mach/msm_hsusb_hw.h>
+
+static const char driver_name[] = "msm72k_udc";
+
+/* #define DEBUG */
+/* #define VERBOSE */
+
+#define MSM_USB_BASE ((unsigned) ui->addr)
+
+#define	DRIVER_DESC		"MSM 72K USB Peripheral Controller"
+
+#define EPT_FLAG_IN        0x0001
+
+#define SETUP_BUF_SIZE      4096
+
+typedef void (*completion_func)(struct usb_ep *ep, struct usb_request *req);
+
+static const char *const ep_name[] = {
+	"ep0out", "ep1out", "ep2out", "ep3out",
+	"ep4out", "ep5out", "ep6out", "ep7out",
+	"ep8out", "ep9out", "ep10out", "ep11out",
+	"ep12out", "ep13out", "ep14out", "ep15out",
+	"ep0in", "ep1in", "ep2in", "ep3in",
+	"ep4in", "ep5in", "ep6in", "ep7in",
+	"ep8in", "ep9in", "ep10in", "ep11in",
+	"ep12in", "ep13in", "ep14in", "ep15in"
+};
+
+/* current state of VBUS */
+static int vbus;
+
+struct msm_request {
+	struct usb_request req;
+
+	/* saved copy of req.complete */
+	completion_func gadget_complete;
+
+	struct usb_info *ui;
+	struct msm_request *next;
+
+	unsigned busy:1;
+	unsigned live:1;
+	unsigned alloced:1;
+
+	dma_addr_t dma;
+	dma_addr_t item_dma;
+
+	struct ept_queue_item *item;
+};
+
+#define to_msm_request(r) container_of(r, struct msm_request, req)
+#define to_msm_endpoint(r) container_of(r, struct msm_endpoint, ep)
+
+struct msm_endpoint {
+	struct usb_ep ep;
+	struct usb_info *ui;
+	struct msm_request *req; /* head of pending requests */
+	struct msm_request *last;
+	unsigned flags;
+
+	/* bit number (0-31) in various status registers
+	** as well as the index into the usb_info's array
+	** of all endpoints
+	*/
+	unsigned char bit;
+	unsigned char num;
+
+	/* pointers to DMA transfer list area */
+	/* these are allocated from the usb_info dma space */
+	struct ept_queue_head *head;
+};
+
+static void usb_do_work(struct work_struct *w);
+
+
+#define USB_STATE_IDLE    0
+#define USB_STATE_ONLINE  1
+#define USB_STATE_OFFLINE 2
+
+#define USB_FLAG_START          0x0001
+#define USB_FLAG_VBUS_ONLINE    0x0002
+#define USB_FLAG_VBUS_OFFLINE   0x0004
+#define USB_FLAG_RESET          0x0008
+
+struct usb_info {
+	/* lock for register/queue/device state changes */
+	spinlock_t lock;
+
+	/* single request used for handling setup transactions */
+	struct usb_request *setup_req;
+
+	struct platform_device *pdev;
+	int irq;
+	void *addr;
+
+	unsigned state;
+	unsigned flags;
+
+	unsigned	online:1;
+	unsigned	running:1;
+
+	struct dma_pool *pool;
+
+	/* dma page to back the queue heads and items */
+	unsigned char *buf;
+	dma_addr_t dma;
+
+	struct ept_queue_head *head;
+
+	/* used for allocation */
+	unsigned next_item;
+	unsigned next_ifc_num;
+
+	/* endpoints are ordered based on their status bits,
+	** so they are OUT0, OUT1, ... OUT15, IN0, IN1, ... IN15
+	*/
+	struct msm_endpoint ept[32];
+
+	int *phy_init_seq;
+	void (*phy_reset)(void);
+	void (*hw_reset)(bool en);
+
+	/* for notification when USB is connected or disconnected */
+	void (*usb_connected)(int);
+
+	struct work_struct work;
+	unsigned phy_status;
+	unsigned phy_fail_count;
+
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+
+#define ep0out ept[0]
+#define ep0in  ept[16]
+
+	struct clk *clk;
+	struct clk *coreclk;
+	struct clk *pclk;
+	struct clk *otgclk;
+	struct clk *ebi1clk;
+
+	unsigned int ep0_dir;
+	u16 test_mode;
+
+	u8 remote_wakeup;
+};
+
+static const struct usb_ep_ops msm72k_ep_ops;
+
+
+static int msm72k_pullup(struct usb_gadget *_gadget, int is_active);
+static int msm72k_set_halt(struct usb_ep *_ep, int value);
+static void flush_endpoint(struct msm_endpoint *ept);
+
+static int usb_ep_get_stall(struct msm_endpoint *ept)
+{
+	unsigned int n;
+	struct usb_info *ui = ept->ui;
+
+	n = readl(USB_ENDPTCTRL(ept->num));
+	if (ept->flags & EPT_FLAG_IN)
+		return (CTRL_TXS & n) ? 1 : 0;
+	else
+		return (CTRL_RXS & n) ? 1 : 0;
+}
+
+static unsigned ulpi_read(struct usb_info *ui, unsigned reg)
+{
+	unsigned timeout = 100000;
+
+	/* initiate read operation */
+	writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ;
+
+	if (timeout == 0) {
+		ERROR("ulpi_read: timeout %08x\n", readl(USB_ULPI_VIEWPORT));
+		return 0xffffffff;
+	}
+	return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
+}
+
+static int ulpi_write(struct usb_info *ui, unsigned val, unsigned reg)
+{
+	unsigned timeout = 10000;
+
+	/* initiate write operation */
+	writel(ULPI_RUN | ULPI_WRITE |
+	       ULPI_ADDR(reg) | ULPI_DATA(val),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	while((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ;
+
+	if (timeout == 0) {
+		printk(KERN_ERR "ulpi_write: timeout\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void ulpi_init(struct usb_info *ui)
+{
+	int *seq = ui->phy_init_seq;
+
+	if (!seq)
+		return;
+
+	while (seq[0] >= 0) {
+//		INFO("ulpi: write 0x%02x to 0x%02x\n", seq[0], seq[1]);
+		ulpi_write(ui, seq[0], seq[1]);
+		seq += 2;
+	}
+}
+
+static void init_endpoints(struct usb_info *ui)
+{
+	unsigned n;
+
+	for (n = 0; n < 32; n++) {
+		struct msm_endpoint *ept = ui->ept + n;
+
+		ept->ui = ui;
+		ept->bit = n;
+		ept->num = n & 15;
+		ept->ep.name = ep_name[n];
+		ept->ep.ops = &msm72k_ep_ops;
+
+		if (ept->bit > 15) {
+			/* IN endpoint */
+			ept->head = ui->head + (ept->num << 1) + 1;
+			ept->flags = EPT_FLAG_IN;
+		} else {
+			/* OUT endpoint */
+			ept->head = ui->head + (ept->num << 1);
+			ept->flags = 0;
+		}
+
+	}
+}
+
+static void config_ept(struct msm_endpoint *ept)
+{
+	unsigned cfg = CONFIG_MAX_PKT(ept->ep.maxpacket) | CONFIG_ZLT;
+
+	if (ept->bit == 0)
+		/* ep0 out needs interrupt-on-setup */
+		cfg |= CONFIG_IOS;
+
+	ept->head->config = cfg;
+	ept->head->next = TERMINATE;
+
+#if 0
+	if (ept->ep.maxpacket)
+		INFO("ept #%d %s max:%d head:%p bit:%d\n",
+		    ept->num, (ept->flags & EPT_FLAG_IN) ? "in" : "out",
+		    ept->ep.maxpacket, ept->head, ept->bit);
+#endif
+}
+
+static void configure_endpoints(struct usb_info *ui)
+{
+	unsigned n;
+
+	for (n = 0; n < 32; n++)
+		config_ept(ui->ept + n);
+}
+
+struct usb_request *usb_ept_alloc_req(struct msm_endpoint *ept,
+			unsigned bufsize, gfp_t gfp_flags)
+{
+	struct usb_info *ui = ept->ui;
+	struct msm_request *req;
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req)
+		goto fail1;
+
+	req->item = dma_pool_alloc(ui->pool, gfp_flags, &req->item_dma);
+	if (!req->item)
+		goto fail2;
+
+	if (bufsize) {
+		req->req.buf = kmalloc(bufsize, gfp_flags);
+		if (!req->req.buf)
+			goto fail3;
+		req->alloced = 1;
+	}
+
+	return &req->req;
+
+fail3:
+	dma_pool_free(ui->pool, req->item, req->item_dma);
+fail2:
+	kfree(req);
+fail1:
+	return 0;
+}
+
+static void usb_ept_enable(struct msm_endpoint *ept, int yes,
+		unsigned char ep_type)
+{
+	struct usb_info *ui = ept->ui;
+	int in = ept->flags & EPT_FLAG_IN;
+	unsigned n;
+
+	n = readl(USB_ENDPTCTRL(ept->num));
+
+	if (in) {
+		n = (n & (~CTRL_TXT_MASK));
+		if (yes) {
+			n |= CTRL_TXE | CTRL_TXR;
+		} else {
+			n &= (~CTRL_TXE);
+		}
+		if (yes) {
+			switch (ep_type) {
+			case USB_ENDPOINT_XFER_BULK:
+				n |= CTRL_TXT_BULK;
+				break;
+			case USB_ENDPOINT_XFER_INT:
+				n |= CTRL_TXT_INT;
+				break;
+			case USB_ENDPOINT_XFER_ISOC:
+				n |= CTRL_TXT_ISOCH;
+				break;
+			default:
+				pr_err("%s: unsupported ep_type %d for %s\n",
+					__func__, ep_type, ept->ep.name);
+				break;
+			}
+		}
+	} else {
+		n = (n & (~CTRL_RXT_MASK));
+		if (yes) {
+			n |= CTRL_RXE | CTRL_RXR;
+		} else {
+			n &= ~(CTRL_RXE);
+		}
+		if (yes) {
+			switch (ep_type) {
+			case USB_ENDPOINT_XFER_BULK:
+				n |= CTRL_RXT_BULK;
+				break;
+			case USB_ENDPOINT_XFER_INT:
+				n |= CTRL_RXT_INT;
+				break;
+			case USB_ENDPOINT_XFER_ISOC:
+				n |= CTRL_RXT_ISOCH;
+				break;
+			default:
+				pr_err("%s: unsupported ep_type %d for %s\n",
+					__func__, ep_type, ept->ep.name);
+				break;
+			}
+		}
+	}
+	writel(n, USB_ENDPTCTRL(ept->num));
+
+#if 0
+	INFO("ept %d %s %s\n",
+	       ept->num, in ? "in" : "out", yes ? "enabled" : "disabled");
+#endif
+}
+
+static void usb_ept_start(struct msm_endpoint *ept)
+{
+	struct usb_info *ui = ept->ui;
+	struct msm_request *req = ept->req;
+
+	BUG_ON(req->live);
+
+	/* link the hw queue head to the request's transaction item */
+	ept->head->next = req->item_dma;
+	ept->head->info = 0;
+
+	/* start the endpoint */
+	writel(1 << ept->bit, USB_ENDPTPRIME);
+
+	/* mark this chain of requests as live */
+	while (req) {
+		req->live = 1;
+		req = req->next;
+	}
+}
+
+int usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req)
+{
+	unsigned long flags;
+	struct msm_request *req = to_msm_request(_req);
+	struct msm_request *last;
+	struct usb_info *ui = ept->ui;
+	struct ept_queue_item *item = req->item;
+	unsigned length = req->req.length;
+
+	if (length > 0x4000)
+		return -EMSGSIZE;
+
+	spin_lock_irqsave(&ui->lock, flags);
+
+	if (req->busy) {
+		req->req.status = -EBUSY;
+		spin_unlock_irqrestore(&ui->lock, flags);
+		INFO("usb_ept_queue_xfer() tried to queue busy request\n");
+		return -EBUSY;
+	}
+
+	if (!ui->online && (ept->num != 0)) {
+		req->req.status = -ESHUTDOWN;
+		spin_unlock_irqrestore(&ui->lock, flags);
+		INFO("usb_ept_queue_xfer() called while offline\n");
+		return -ESHUTDOWN;
+	}
+
+	req->busy = 1;
+	req->live = 0;
+	req->next = 0;
+	req->req.status = -EBUSY;
+
+	req->dma = dma_map_single(NULL, req->req.buf, length,
+				  (ept->flags & EPT_FLAG_IN) ?
+				  DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+	/* prepare the transaction descriptor item for the hardware */
+	item->next = TERMINATE;
+	item->info = INFO_BYTES(length) | INFO_IOC | INFO_ACTIVE;
+	item->page0 = req->dma;
+	item->page1 = (req->dma + 0x1000) & 0xfffff000;
+	item->page2 = (req->dma + 0x2000) & 0xfffff000;
+	item->page3 = (req->dma + 0x3000) & 0xfffff000;
+
+	/* Add the new request to the end of the queue */
+	last = ept->last;
+	if (last) {
+		/* Already requests in the queue. add us to the
+		 * end, but let the completion interrupt actually
+		 * start things going, to avoid hw issues
+		 */
+		last->next = req;
+
+		/* only modify the hw transaction next pointer if
+		 * that request is not live
+		 */
+		if (!last->live)
+			last->item->next = req->item_dma;
+	} else {
+		/* queue was empty -- kick the hardware */
+		ept->req = req;
+		usb_ept_start(ept);
+	}
+	ept->last = req;
+
+	spin_unlock_irqrestore(&ui->lock, flags);
+	return 0;
+}
+
+/* --- endpoint 0 handling --- */
+
+static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct msm_request *r = to_msm_request(req);
+	struct msm_endpoint *ept = to_msm_endpoint(ep);
+	struct usb_info *ui = ept->ui;
+
+	req->complete = r->gadget_complete;
+	r->gadget_complete = NULL;
+	if	(req->complete)
+		req->complete(&ui->ep0in.ep, req);
+}
+
+static void ep0_queue_ack_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(ep);
+	struct msm_request *r = to_msm_request(req);
+	completion_func gadget_complete = r->gadget_complete;
+
+	if (gadget_complete) {
+		r->gadget_complete = NULL;
+		gadget_complete(ep, req);
+	}
+
+	/* queue up the receive of the ACK response from the host */
+	if (req->status == 0) {
+		struct usb_info *ui = ept->ui;
+		req->length = 0;
+		req->complete = ep0_complete;
+		if (ui->ep0_dir == USB_DIR_IN)
+			usb_ept_queue_xfer(&ui->ep0out, req);
+		else
+			usb_ept_queue_xfer(&ui->ep0in, req);
+	} else
+		ep0_complete(ep, req);
+}
+
+static void ep0_setup_ack_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(ep);
+	struct usb_info *ui = ept->ui;
+	unsigned int temp;
+
+	if (!ui->test_mode)
+		return;
+
+	switch (ui->test_mode) {
+	case J_TEST:
+		pr_info("usb electrical test mode: (J)\n");
+		temp = readl(USB_PORTSC) & (~PORTSC_PTC);
+		writel(temp | PORTSC_PTC_J_STATE, USB_PORTSC);
+		break;
+
+	case K_TEST:
+		pr_info("usb electrical test mode: (K)\n");
+		temp = readl(USB_PORTSC) & (~PORTSC_PTC);
+		writel(temp | PORTSC_PTC_K_STATE, USB_PORTSC);
+		break;
+
+	case SE0_NAK_TEST:
+		pr_info("usb electrical test mode: (SE0-NAK)\n");
+		temp = readl(USB_PORTSC) & (~PORTSC_PTC);
+		writel(temp | PORTSC_PTC_SE0_NAK, USB_PORTSC);
+		break;
+
+	case TST_PKT_TEST:
+		pr_info("usb electrical test mode: (TEST_PKT)\n");
+		temp = readl(USB_PORTSC) & (~PORTSC_PTC);
+		writel(temp | PORTSC_PTC_TST_PKT, USB_PORTSC);
+		break;
+	}
+}
+
+static void ep0_setup_ack(struct usb_info *ui)
+{
+	struct usb_request *req = ui->setup_req;
+	req->length = 0;
+	req->complete = ep0_setup_ack_complete;
+	usb_ept_queue_xfer(&ui->ep0in, req);
+}
+
+static void ep0_setup_stall(struct usb_info *ui)
+{
+	writel((1<<16) | (1<<0), USB_ENDPTCTRL(0));
+}
+
+static void ep0_setup_send(struct usb_info *ui, unsigned length)
+{
+	struct usb_request *req = ui->setup_req;
+	struct msm_request *r = to_msm_request(req);
+	struct msm_endpoint *ept = &ui->ep0in;
+
+	req->length = length;
+	req->complete = ep0_queue_ack_complete;
+	r->gadget_complete = NULL;
+	usb_ept_queue_xfer(ept, req);
+}
+
+static void handle_setup(struct usb_info *ui)
+{
+	struct usb_ctrlrequest ctl;
+	struct usb_request *req = ui->setup_req;
+	int ret;
+
+	memcpy(&ctl, ui->ep0out.head->setup_data, sizeof(ctl));
+	writel(EPT_RX(0), USB_ENDPTSETUPSTAT);
+
+	if (ctl.bRequestType & USB_DIR_IN)
+		ui->ep0_dir = USB_DIR_IN;
+	else
+		ui->ep0_dir = USB_DIR_OUT;
+
+	/* any pending ep0 transactions must be canceled */
+	flush_endpoint(&ui->ep0out);
+	flush_endpoint(&ui->ep0in);
+
+#if 0
+	INFO("setup: type=%02x req=%02x val=%04x idx=%04x len=%04x\n",
+	       ctl.bRequestType, ctl.bRequest, ctl.wValue,
+	       ctl.wIndex, ctl.wLength);
+#endif
+
+	if ((ctl.bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) ==
+					(USB_DIR_IN | USB_TYPE_STANDARD)) {
+		if (ctl.bRequest == USB_REQ_GET_STATUS) {
+			if (ctl.wLength != 2)
+				goto stall;
+			switch (ctl.bRequestType & USB_RECIP_MASK) {
+			case USB_RECIP_ENDPOINT:
+			{
+				struct msm_endpoint *ept;
+				unsigned num =
+					ctl.wIndex & USB_ENDPOINT_NUMBER_MASK;
+				u16 temp = 0;
+
+				if (num == 0) {
+					memset(req->buf, 0, 2);
+					break;
+				}
+				if (ctl.wIndex & USB_ENDPOINT_DIR_MASK)
+					num += 16;
+				ept = &ui->ep0out + num;
+				temp = usb_ep_get_stall(ept);
+				temp = temp << USB_ENDPOINT_HALT;
+				memcpy(req->buf, &temp, 2);
+				break;
+			}
+			case USB_RECIP_DEVICE:
+			{
+				u16 temp = 0;
+
+				temp = 1 << USB_DEVICE_SELF_POWERED;
+				temp |= (ui->remote_wakeup <<
+						USB_DEVICE_REMOTE_WAKEUP);
+				memcpy(req->buf, &temp, 2);
+				break;
+			}
+			case USB_RECIP_INTERFACE:
+				memset(req->buf, 0, 2);
+				break;
+			default:
+				goto stall;
+			}
+			ep0_setup_send(ui, 2);
+			return;
+		}
+	}
+	if (ctl.bRequestType ==
+		    (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)) {
+		if ((ctl.bRequest == USB_REQ_CLEAR_FEATURE) ||
+				(ctl.bRequest == USB_REQ_SET_FEATURE)) {
+			if ((ctl.wValue == 0) && (ctl.wLength == 0)) {
+				unsigned num = ctl.wIndex & 0x0f;
+
+				if (num != 0) {
+					struct msm_endpoint *ept;
+
+					if (ctl.wIndex & 0x80)
+						num += 16;
+					ept = &ui->ep0out + num;
+
+					if (ctl.bRequest == USB_REQ_SET_FEATURE)
+						msm72k_set_halt(&ept->ep, 1);
+					else
+						msm72k_set_halt(&ept->ep, 0);
+				}
+				goto ack;
+			}
+		}
+	}
+	if (ctl.bRequestType == (USB_DIR_OUT | USB_TYPE_STANDARD)) {
+		if (ctl.bRequest == USB_REQ_SET_CONFIGURATION) {
+			ui->online = !!ctl.wValue;
+			if (ui->online && ui->usb_connected)
+				ui->usb_connected(1);
+		} else if (ctl.bRequest == USB_REQ_SET_ADDRESS) {
+			/* write address delayed (will take effect
+			** after the next IN txn)
+			*/
+			writel((ctl.wValue << 25) | (1 << 24), USB_DEVICEADDR);
+			goto ack;
+		} else if (ctl.bRequest == USB_REQ_SET_FEATURE) {
+			switch (ctl.wValue) {
+			case USB_DEVICE_TEST_MODE:
+				switch (ctl.wIndex) {
+				case J_TEST:
+				case K_TEST:
+				case SE0_NAK_TEST:
+				case TST_PKT_TEST:
+					ui->test_mode = ctl.wIndex;
+					goto ack;
+				}
+				goto stall;
+			case USB_DEVICE_REMOTE_WAKEUP:
+				ui->remote_wakeup = 1;
+				goto ack;
+			}
+		} else if ((ctl.bRequest == USB_REQ_CLEAR_FEATURE) &&
+				(ctl.wValue == USB_DEVICE_REMOTE_WAKEUP)) {
+			ui->remote_wakeup = 0;
+			goto ack;
+		}
+	}
+
+	/* delegate if we get here */
+	if (ui->driver) {
+		ret = ui->driver->setup(&ui->gadget, &ctl);
+		if (ret >= 0)
+			return;
+	}
+
+stall:
+	/* stall ep0 on error */
+	ep0_setup_stall(ui);
+	return;
+
+ack:
+	ep0_setup_ack(ui);
+}
+
+static void handle_endpoint(struct usb_info *ui, unsigned bit)
+{
+	struct msm_endpoint *ept = ui->ept + bit;
+	struct msm_request *req;
+	unsigned long flags;
+	unsigned info;
+
+#if 0
+	INFO("handle_endpoint() %d %s req=%p(%08x)\n",
+		ept->num, (ept->flags & EPT_FLAG_IN) ? "in" : "out",
+		ept->req, ept->req ? ept->req->item_dma : 0);
+#endif
+
+	/* expire all requests that are no longer active */
+	spin_lock_irqsave(&ui->lock, flags);
+	while ((req = ept->req)) {
+		info = req->item->info;
+
+		/* if we've processed all live requests, time to
+		 * restart the hardware on the next non-live request
+		 */
+		if (!req->live) {
+			usb_ept_start(ept);
+			break;
+		}
+
+		/* if the transaction is still in-flight, stop here */
+		if (info & INFO_ACTIVE)
+			break;
+
+		/* advance ept queue to the next request */
+		ept->req = req->next;
+		if (ept->req == 0)
+			ept->last = 0;
+
+		dma_unmap_single(NULL, req->dma, req->req.length,
+				 (ept->flags & EPT_FLAG_IN) ?
+				 DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+		if (info & (INFO_HALTED | INFO_BUFFER_ERROR | INFO_TXN_ERROR)) {
+			/* XXX pass on more specific error code */
+			req->req.status = -EIO;
+			req->req.actual = 0;
+			INFO("msm72k_udc: ept %d %s error. info=%08x\n",
+			       ept->num,
+			       (ept->flags & EPT_FLAG_IN) ? "in" : "out",
+			       info);
+		} else {
+			req->req.status = 0;
+			req->req.actual =
+				req->req.length - ((info >> 16) & 0x7FFF);
+		}
+		req->busy = 0;
+		req->live = 0;
+
+		if (req->req.complete) {
+			spin_unlock_irqrestore(&ui->lock, flags);
+			req->req.complete(&ept->ep, &req->req);
+			spin_lock_irqsave(&ui->lock, flags);
+		}
+	}
+	spin_unlock_irqrestore(&ui->lock, flags);
+}
+
+#define FLUSH_WAIT_US	5
+#define FLUSH_TIMEOUT	(2 * (USEC_PER_SEC / FLUSH_WAIT_US))
+static void flush_endpoint_hw(struct usb_info *ui, unsigned bits)
+{
+	uint32_t unflushed = 0;
+	uint32_t stat = 0;
+	int cnt = 0;
+
+	/* flush endpoint, canceling transactions
+	** - this can take a "large amount of time" (per databook)
+	** - the flush can fail in some cases, thus we check STAT
+	**   and repeat if we're still operating
+	**   (does the fact that this doesn't use the tripwire matter?!)
+	*/
+	while (cnt < FLUSH_TIMEOUT) {
+		writel(bits, USB_ENDPTFLUSH);
+		while (((unflushed = readl(USB_ENDPTFLUSH)) & bits) &&
+		       cnt < FLUSH_TIMEOUT) {
+			cnt++;
+			udelay(FLUSH_WAIT_US);
+		}
+
+		stat = readl(USB_ENDPTSTAT);
+		if (cnt >= FLUSH_TIMEOUT)
+			goto err;
+		if (!(stat & bits))
+			goto done;
+		cnt++;
+		udelay(FLUSH_WAIT_US);
+	}
+
+err:
+	pr_warning("%s: Could not complete flush! NOT GOOD! "
+		   "stat: %x unflushed: %x bits: %x\n", __func__,
+		   stat, unflushed, bits);
+done:
+	return;
+}
+
+static void flush_endpoint_sw(struct msm_endpoint *ept)
+{
+	struct usb_info *ui = ept->ui;
+	struct msm_request *req;
+	unsigned long flags;
+
+	/* inactive endpoints have nothing to do here */
+	if (ept->ep.maxpacket == 0)
+		return;
+
+	/* put the queue head in a sane state */
+	ept->head->info = 0;
+	ept->head->next = TERMINATE;
+
+	/* cancel any pending requests */
+	spin_lock_irqsave(&ui->lock, flags);
+	req = ept->req;
+	ept->req = 0;
+	ept->last = 0;
+	while (req != 0) {
+		req->busy = 0;
+		req->live = 0;
+		req->req.status = -ECONNRESET;
+		req->req.actual = 0;
+		if (req->req.complete) {
+			spin_unlock_irqrestore(&ui->lock, flags);
+			req->req.complete(&ept->ep, &req->req);
+			spin_lock_irqsave(&ui->lock, flags);
+		}
+		req = req->next;
+	}
+	spin_unlock_irqrestore(&ui->lock, flags);
+}
+
+static void flush_endpoint(struct msm_endpoint *ept)
+{
+	flush_endpoint_hw(ept->ui, (1 << ept->bit));
+	flush_endpoint_sw(ept);
+}
+
+static void flush_all_endpoints(struct usb_info *ui)
+{
+	unsigned n;
+
+	flush_endpoint_hw(ui, 0xffffffff);
+
+	for (n = 0; n < 32; n++)
+		flush_endpoint_sw(ui->ept + n);
+}
+
+
+static irqreturn_t usb_interrupt(int irq, void *data)
+{
+	struct usb_info *ui = data;
+	unsigned n;
+
+	n = readl(USB_USBSTS);
+	writel(n, USB_USBSTS);
+
+	/* somehow we got an IRQ while in the reset sequence: ignore it */
+	if (ui->running == 0)
+		return IRQ_HANDLED;
+
+	if (n & STS_PCI) {
+		switch (readl(USB_PORTSC) & PORTSC_PSPD_MASK) {
+		case PORTSC_PSPD_FS:
+			INFO("msm72k_udc: portchange USB_SPEED_FULL\n");
+			ui->gadget.speed = USB_SPEED_FULL;
+			break;
+		case PORTSC_PSPD_LS:
+			INFO("msm72k_udc: portchange USB_SPEED_LOW\n");
+			ui->gadget.speed = USB_SPEED_LOW;
+			break;
+		case PORTSC_PSPD_HS:
+			INFO("msm72k_udc: portchange USB_SPEED_HIGH\n");
+			ui->gadget.speed = USB_SPEED_HIGH;
+			break;
+		}
+	}
+
+	if (n & STS_URI) {
+		INFO("msm72k_udc: reset\n");
+
+		writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
+		writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
+		writel(0xffffffff, USB_ENDPTFLUSH);
+		writel(0, USB_ENDPTCTRL(1));
+
+		if (ui->online != 0) {
+			/* marking us offline will cause ept queue attempts
+			** to fail
+			*/
+			ui->online = 0;
+
+			flush_all_endpoints(ui);
+
+			/* XXX: we can't seem to detect going offline,
+			 * XXX:  so deconfigure on reset for the time being
+			 */
+			if (ui->driver) {
+				printk(KERN_INFO "usb: notify offline\n");
+				ui->driver->disconnect(&ui->gadget);
+			}
+		}
+	}
+
+	if (n & STS_SLI)
+		INFO("msm72k_udc: suspend\n");
+
+	if (n & STS_UI) {
+		n = readl(USB_ENDPTSETUPSTAT);
+		if (n & EPT_RX(0))
+			handle_setup(ui);
+
+		n = readl(USB_ENDPTCOMPLETE);
+		writel(n, USB_ENDPTCOMPLETE);
+		while (n) {
+			unsigned bit = __ffs(n);
+			handle_endpoint(ui, bit);
+			n = n & (~(1 << bit));
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static void usb_prepare(struct usb_info *ui)
+{
+	spin_lock_init(&ui->lock);
+
+	memset(ui->buf, 0, 4096);
+	ui->head = (void *) (ui->buf + 0);
+
+	/* only important for reset/reinit */
+	memset(ui->ept, 0, sizeof(ui->ept));
+	ui->next_item = 0;
+	ui->next_ifc_num = 0;
+
+	init_endpoints(ui);
+
+	ui->ep0in.ep.maxpacket = 64;
+	ui->ep0out.ep.maxpacket = 64;
+
+	ui->setup_req =
+		usb_ept_alloc_req(&ui->ep0in, SETUP_BUF_SIZE, GFP_KERNEL);
+
+	INIT_WORK(&ui->work, usb_do_work);
+}
+
+static void usb_suspend_phy(struct usb_info *ui)
+{
+#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM7X30)
+	/* clear VBusValid and SessionEnd rising interrupts */
+	ulpi_write(ui, (1 << 1) | (1 << 3), 0x0f);
+	/* clear VBusValid and SessionEnd falling interrupts */
+	ulpi_write(ui, (1 << 1) | (1 << 3), 0x12);
+
+	/* Disable 60MHz CLKOUT in serial or carkit mode */
+	ulpi_write(ui, 0x08, 0x09);
+
+	/* Enable PHY Low Power Suspend - Clock Disable (PLPSCD) */
+	writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
+	mdelay(1);
+#else
+	/* clear VBusValid and SessionEnd rising interrupts */
+	ulpi_write(ui, (1 << 1) | (1 << 3), 0x0f);
+	/* clear VBusValid and SessionEnd falling interrupts */
+	ulpi_write(ui, (1 << 1) | (1 << 3), 0x12);
+	/* disable interface protect circuit to drop current consumption */
+	ulpi_write(ui, (1 << 7), 0x08);
+	/* clear the SuspendM bit -> suspend the PHY */
+	ulpi_write(ui, 1 << 6, 0x06);
+#endif
+}
+
+/* If this function returns < 0, the phy reset failed and we cannot
+ * continue at this point. The only solution is to wait until the next
+ * cable disconnect/reconnect to bring the phy back */
+static int usb_phy_reset(struct usb_info *ui)
+{
+	u32 val;
+	int ret;
+	int retries;
+
+	if (!ui->phy_reset)
+		return 0;
+
+	if (ui->hw_reset)
+		ui->hw_reset(1);
+	ui->phy_reset();
+	if (ui->hw_reset)
+		ui->hw_reset(0);
+
+#if defined(CONFIG_ARCH_QSD8X50)
+	val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
+	writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+	/* XXX: only necessary for pre-45nm internal PHYs. */
+	for (retries = 3; retries > 0; retries--) {
+		ret = ulpi_write(ui, ULPI_FUNC_SUSPENDM, ULPI_FUNC_CTRL_CLR);
+		if (!ret)
+			break;
+		ui->phy_reset();
+	}
+	if (!retries)
+		return -1;
+
+	/* this reset calibrates the phy, if the above write succeeded */
+	ui->phy_reset();
+
+	/* XXX: pre-45nm internal phys have a known issue which can cause them
+	 * to lockup on reset. If ULPI accesses fail, try resetting the phy
+	 * again */
+	for (retries = 3; retries > 0; retries--) {
+		ret = ulpi_read(ui, ULPI_DEBUG_REG);
+		if (ret != 0xffffffff)
+			break;
+		ui->phy_reset();
+	}
+	if (!retries)
+		return -1;
+#endif
+	pr_info("msm_hsusb_phy_reset: success\n");
+	return 0;
+}
+
+static void usb_reset(struct usb_info *ui)
+{
+	unsigned long flags;
+	printk(KERN_INFO "hsusb: reset controller\n");
+
+	spin_lock_irqsave(&ui->lock, flags);
+	ui->running = 0;
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	/* To prevent phantom packets being received by the usb core on
+	 * some devices, put the controller into reset prior to
+	 * resetting the phy. */
+	writel(2, USB_USBCMD);
+	msleep(10);
+
+#if 0
+	/* we should flush and shutdown cleanly if already running */
+	writel(0xffffffff, USB_ENDPTFLUSH);
+	msleep(2);
+#endif
+
+	if (usb_phy_reset(ui) < 0)
+		pr_err("%s: Phy reset failed!\n", __func__);
+
+	msleep(100);
+
+	/* toggle non-driving mode after phy reset to ensure that
+	 * we cause a disconnect event to the host */
+	ulpi_write(ui, 0x18, 0x6);
+	msleep(1);
+	ulpi_write(ui, 0x8, 0x5);
+	msleep(1);
+
+	/* RESET */
+	writel(2, USB_USBCMD);
+	msleep(10);
+
+#ifdef CONFIG_ARCH_MSM7X00A
+	/* INCR4 BURST mode */
+	writel(0x01, USB_SBUSCFG);
+#else
+	/* bursts of unspecified length. */
+	writel(0, USB_AHBBURST);
+	/* Use the AHB transactor */
+	writel(0, USB_AHBMODE);
+#endif
+
+	/* select DEVICE mode */
+	writel(0x12, USB_USBMODE);
+	msleep(1);
+
+	/* select ULPI phy */
+	writel(0x80000000, USB_PORTSC);
+
+	ulpi_init(ui);
+
+	writel(ui->dma, USB_ENDPOINTLISTADDR);
+
+	configure_endpoints(ui);
+
+	/* marking us offline will cause ept queue attempts to fail */
+	ui->online = 0;
+
+	/* terminate any pending transactions */
+	flush_all_endpoints(ui);
+
+	if (ui->driver) {
+		printk(KERN_INFO "usb: notify offline\n");
+		ui->driver->disconnect(&ui->gadget);
+	}
+
+	/* enable interrupts */
+	writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR);
+
+	/* go to RUN mode (D+ pullup enable) */
+	msm72k_pullup(&ui->gadget, 1);
+
+	spin_lock_irqsave(&ui->lock, flags);
+	ui->running = 1;
+	spin_unlock_irqrestore(&ui->lock, flags);
+}
+
+static void usb_start(struct usb_info *ui)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ui->lock, flags);
+	ui->flags |= USB_FLAG_START;
+	schedule_work(&ui->work);
+	spin_unlock_irqrestore(&ui->lock, flags);
+}
+
+static struct usb_info *the_usb_info;
+
+static int usb_free(struct usb_info *ui, int ret)
+{
+	INFO("usb_free(%d)\n", ret);
+
+	if (ui->irq)
+		free_irq(ui->irq, 0);
+	if (ui->pool)
+		dma_pool_destroy(ui->pool);
+	if (ui->dma)
+		dma_free_coherent(&ui->pdev->dev, 4096, ui->buf, ui->dma);
+	if (ui->addr)
+		iounmap(ui->addr);
+	if (ui->clk)
+		clk_put(ui->clk);
+	if (ui->pclk)
+		clk_put(ui->pclk);
+	if (ui->otgclk)
+		clk_put(ui->otgclk);
+	if (ui->coreclk)
+		clk_put(ui->coreclk);
+	if (ui->ebi1clk)
+		clk_put(ui->ebi1clk);
+	kfree(ui);
+	return ret;
+}
+
+static void usb_do_work_check_vbus(struct usb_info *ui)
+{
+	unsigned long iflags;
+
+	spin_lock_irqsave(&ui->lock, iflags);
+	if (vbus) {
+		ui->flags |= USB_FLAG_VBUS_ONLINE;
+	} else {
+		ui->flags |= USB_FLAG_VBUS_OFFLINE;
+	}
+	spin_unlock_irqrestore(&ui->lock, iflags);
+}
+
+static void usb_do_work(struct work_struct *w)
+{
+	struct usb_info *ui = container_of(w, struct usb_info, work);
+	unsigned long iflags;
+	unsigned flags, _vbus;
+
+	for (;;) {
+		spin_lock_irqsave(&ui->lock, iflags);
+		flags = ui->flags;
+		ui->flags = 0;
+		_vbus = vbus;
+		spin_unlock_irqrestore(&ui->lock, iflags);
+
+		/* give up if we have nothing to do */
+		if (flags == 0)
+			break;
+
+		switch (ui->state) {
+		case USB_STATE_IDLE:
+			if (flags & USB_FLAG_START) {
+				pr_info("msm72k_udc: IDLE -> ONLINE\n");
+				clk_set_rate(ui->ebi1clk, 128000000);
+				udelay(10);
+				if (ui->coreclk)
+					clk_enable(ui->coreclk);
+				clk_enable(ui->clk);
+				clk_enable(ui->pclk);
+				if (ui->otgclk)
+					clk_enable(ui->otgclk);
+				usb_reset(ui);
+
+				ui->state = USB_STATE_ONLINE;
+				usb_do_work_check_vbus(ui);
+			}
+			break;
+		case USB_STATE_ONLINE:
+			/* If at any point when we were online, we received
+			 * the signal to go offline, we must honor it
+			 */
+			if (flags & USB_FLAG_VBUS_OFFLINE) {
+				pr_info("msm72k_udc: ONLINE -> OFFLINE\n");
+
+				/* synchronize with irq context */
+				spin_lock_irqsave(&ui->lock, iflags);
+				ui->running = 0;
+				ui->online = 0;
+				msm72k_pullup(&ui->gadget, 0);
+				spin_unlock_irqrestore(&ui->lock, iflags);
+
+				if (ui->usb_connected)
+					ui->usb_connected(0);
+
+				/* terminate any transactions, etc */
+				flush_all_endpoints(ui);
+
+				if (ui->driver) {
+					printk(KERN_INFO "usb: notify offline\n");
+					ui->driver->disconnect(&ui->gadget);
+				}
+
+				usb_phy_reset(ui);
+
+				/* power down phy, clock down usb */
+				spin_lock_irqsave(&ui->lock, iflags);
+				usb_suspend_phy(ui);
+				clk_disable(ui->pclk);
+				clk_disable(ui->clk);
+				if (ui->otgclk)
+					clk_disable(ui->otgclk);
+				if (ui->coreclk)
+					clk_disable(ui->coreclk);
+				clk_set_rate(ui->ebi1clk, 0);
+				spin_unlock_irqrestore(&ui->lock, iflags);
+
+				ui->state = USB_STATE_OFFLINE;
+				usb_do_work_check_vbus(ui);
+				break;
+			}
+			if (flags & USB_FLAG_RESET) {
+				pr_info("msm72k_udc: ONLINE -> RESET\n");
+				usb_reset(ui);
+				pr_info("msm72k_udc: RESET -> ONLINE\n");
+				break;
+			}
+			break;
+		case USB_STATE_OFFLINE:
+			/* If we were signaled to go online and vbus is still
+			 * present when we received the signal, go online.
+			 */
+			if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) {
+				pr_info("msm72k_udc: OFFLINE -> ONLINE\n");
+				clk_set_rate(ui->ebi1clk, 128000000);
+				udelay(10);
+				if (ui->coreclk)
+					clk_enable(ui->coreclk);
+				clk_enable(ui->clk);
+				clk_enable(ui->pclk);
+				if (ui->otgclk)
+					clk_enable(ui->otgclk);
+				usb_reset(ui);
+
+				/* detect shorted D+/D-, indicating AC power */
+				msleep(10);
+				if ((readl(USB_PORTSC) & PORTSC_LS) == PORTSC_LS)
+					if (ui->usb_connected)
+						ui->usb_connected(2);
+
+				ui->state = USB_STATE_ONLINE;
+				usb_do_work_check_vbus(ui);
+			}
+			break;
+		}
+	}
+}
+
+/* FIXME - the callers of this function should use a gadget API instead.
+ * This is called from htc_battery.c and board-halibut.c
+ * WARNING - this can get called before this driver is initialized.
+ */
+void msm_hsusb_set_vbus_state(int online)
+{
+	unsigned long flags = 0;
+	struct usb_info *ui = the_usb_info;
+
+	if (ui)
+		spin_lock_irqsave(&ui->lock, flags);
+	if (vbus != online) {
+		vbus = online;
+		if (ui) {
+			if (online) {
+				ui->flags |= USB_FLAG_VBUS_ONLINE;
+			} else {
+				ui->flags |= USB_FLAG_VBUS_OFFLINE;
+			}
+			schedule_work(&ui->work);
+		}
+	}
+	if (ui)
+		spin_unlock_irqrestore(&ui->lock, flags);
+}
+
+#if defined(CONFIG_DEBUG_FS) && 0
+
+void usb_function_reenumerate(void)
+{
+	struct usb_info *ui = the_usb_info;
+
+	/* disable and re-enable the D+ pullup */
+	msm72k_pullup(&ui->gadget, false);
+	msleep(10);
+	msm72k_pullup(&ui->gadget, true);
+}
+
+static char debug_buffer[PAGE_SIZE];
+
+static ssize_t debug_read_status(struct file *file, char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct usb_info *ui = file->private_data;
+	char *buf = debug_buffer;
+	unsigned long flags;
+	struct msm_endpoint *ept;
+	struct msm_request *req;
+	int n;
+	int i = 0;
+
+	spin_lock_irqsave(&ui->lock, flags);
+
+	i += scnprintf(buf + i, PAGE_SIZE - i,
+		       "regs: setup=%08x prime=%08x stat=%08x done=%08x\n",
+		       readl(USB_ENDPTSETUPSTAT),
+		       readl(USB_ENDPTPRIME),
+		       readl(USB_ENDPTSTAT),
+		       readl(USB_ENDPTCOMPLETE));
+	i += scnprintf(buf + i, PAGE_SIZE - i,
+		       "regs:   cmd=%08x   sts=%08x intr=%08x port=%08x\n\n",
+		       readl(USB_USBCMD),
+		       readl(USB_USBSTS),
+		       readl(USB_USBINTR),
+		       readl(USB_PORTSC));
+
+
+	for (n = 0; n < 32; n++) {
+		ept = ui->ept + n;
+		if (ept->ep.maxpacket == 0)
+			continue;
+
+		i += scnprintf(buf + i, PAGE_SIZE - i,
+			       "ept%d %s cfg=%08x active=%08x next=%08x info=%08x\n",
+			       ept->num, (ept->flags & EPT_FLAG_IN) ? "in " : "out",
+			       ept->head->config, ept->head->active,
+			       ept->head->next, ept->head->info);
+
+		for (req = ept->req; req; req = req->next)
+			i += scnprintf(buf + i, PAGE_SIZE - i,
+				       "  req @%08x next=%08x info=%08x page0=%08x %c %c\n",
+				       req->item_dma, req->item->next,
+				       req->item->info, req->item->page0,
+				       req->busy ? 'B' : ' ',
+				       req->live ? 'L' : ' '
+				);
+	}
+
+	i += scnprintf(buf + i, PAGE_SIZE - i,
+		       "phy failure count: %d\n", ui->phy_fail_count);
+
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return simple_read_from_buffer(ubuf, count, ppos, buf, i);
+}
+
+static ssize_t debug_write_reset(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	struct usb_info *ui = file->private_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ui->lock, flags);
+	ui->flags |= USB_FLAG_RESET;
+	schedule_work(&ui->work);
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return count;
+}
+
+static ssize_t debug_write_cycle(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	usb_function_reenumerate();
+	return count;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+const struct file_operations debug_stat_ops = {
+	.open = debug_open,
+	.read = debug_read_status,
+};
+
+const struct file_operations debug_reset_ops = {
+	.open = debug_open,
+	.write = debug_write_reset,
+};
+
+const struct file_operations debug_cycle_ops = {
+	.open = debug_open,
+	.write = debug_write_cycle,
+};
+
+static void usb_debugfs_init(struct usb_info *ui)
+{
+	struct dentry *dent;
+	dent = debugfs_create_dir("usb", 0);
+	if (IS_ERR(dent))
+		return;
+
+	debugfs_create_file("status", 0444, dent, ui, &debug_stat_ops);
+	debugfs_create_file("reset", 0220, dent, ui, &debug_reset_ops);
+	debugfs_create_file("cycle", 0220, dent, ui, &debug_cycle_ops);
+}
+#else
+static void usb_debugfs_init(struct usb_info *ui) {}
+#endif
+
+static int
+msm72k_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(_ep);
+	unsigned char ep_type =
+			desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+	if (ep_type == USB_ENDPOINT_XFER_BULK)
+		_ep->maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+	else
+		_ep->maxpacket = le16_to_cpu(64);
+	config_ept(ept);
+	usb_ept_enable(ept, 1, ep_type);
+	return 0;
+}
+
+static int msm72k_disable(struct usb_ep *_ep)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(_ep);
+
+	usb_ept_enable(ept, 0, 0);
+	return 0;
+}
+
+static struct usb_request *
+msm72k_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	return usb_ept_alloc_req(to_msm_endpoint(_ep), 0, gfp_flags);
+}
+
+static void
+msm72k_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct msm_request *req = to_msm_request(_req);
+	struct msm_endpoint *ept = to_msm_endpoint(_ep);
+	struct usb_info *ui = ept->ui;
+
+	/* request should not be busy */
+	BUG_ON(req->busy);
+
+	if (req->alloced)
+		kfree(req->req.buf);
+	dma_pool_free(ui->pool, req->item, req->item_dma);
+	kfree(req);
+}
+
+static int
+msm72k_queue(struct usb_ep *_ep, struct usb_request *req, gfp_t gfp_flags)
+{
+	struct msm_endpoint *ep = to_msm_endpoint(_ep);
+	struct usb_info *ui = ep->ui;
+
+	if (ep == &ui->ep0in) {
+		struct msm_request *r = to_msm_request(req);
+		if (!req->length)
+			goto ep_queue_done;
+		else {
+			if (ui->ep0_dir == USB_DIR_OUT) {
+				ep = &ui->ep0out;
+				ep->ep.driver_data = ui->ep0in.ep.driver_data;
+			}
+			/* ep0_queue_ack_complete queue a receive for ACK before
+			** calling req->complete
+			*/
+			r->gadget_complete = req->complete;
+			req->complete = ep0_queue_ack_complete;
+		}
+	}
+ep_queue_done:
+	return usb_ept_queue_xfer(ep, req);
+}
+
+static int msm72k_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct msm_endpoint *ep = to_msm_endpoint(_ep);
+	struct msm_request *req = to_msm_request(_req);
+	struct usb_info *ui = ep->ui;
+
+	struct msm_request *cur, *prev;
+	unsigned long flags;
+
+	if (!_ep || !_req)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ui->lock, flags);
+	cur = ep->req;
+	prev = NULL;
+
+	while (cur != 0) {
+		if (cur == req) {
+			req->busy = 0;
+			req->live = 0;
+			req->req.status = -ECONNRESET;
+			req->req.actual = 0;
+			if (req->req.complete) {
+				spin_unlock_irqrestore(&ui->lock, flags);
+				req->req.complete(&ep->ep, &req->req);
+				spin_lock_irqsave(&ui->lock, flags);
+			}
+			/* remove from linked list */
+			if (prev)
+				prev->next = cur->next;
+			else
+				ep->req = cur->next;
+			if (ep->last == cur)
+				ep->last = prev;
+			/* break from loop */
+			cur = NULL;
+		} else {
+			prev = cur;
+			cur = cur->next;
+		}
+	}
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return 0;
+}
+
+static int
+msm72k_set_halt(struct usb_ep *_ep, int value)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(_ep);
+	struct usb_info *ui = ept->ui;
+	unsigned int in = ept->flags & EPT_FLAG_IN;
+	unsigned int n;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ui->lock, flags);
+	n = readl(USB_ENDPTCTRL(ept->num));
+
+	if (in) {
+		if (value)
+			n |= CTRL_TXS;
+		else {
+			n &= ~CTRL_TXS;
+			n |= CTRL_TXR;
+		}
+	} else {
+		if (value)
+			n |= CTRL_RXS;
+		else {
+			n &= ~CTRL_RXS;
+			n |= CTRL_RXR;
+		}
+	}
+	writel(n, USB_ENDPTCTRL(ept->num));
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return 0;
+}
+
+static int
+msm72k_fifo_status(struct usb_ep *_ep)
+{
+	return -EOPNOTSUPP;
+}
+
+static void
+msm72k_fifo_flush(struct usb_ep *_ep)
+{
+	flush_endpoint(to_msm_endpoint(_ep));
+}
+
+static const struct usb_ep_ops msm72k_ep_ops = {
+	.enable		= msm72k_enable,
+	.disable	= msm72k_disable,
+
+	.alloc_request	= msm72k_alloc_request,
+	.free_request	= msm72k_free_request,
+
+	.queue		= msm72k_queue,
+	.dequeue	= msm72k_dequeue,
+
+	.set_halt	= msm72k_set_halt,
+	.fifo_status	= msm72k_fifo_status,
+	.fifo_flush	= msm72k_fifo_flush,
+};
+
+static int msm72k_get_frame(struct usb_gadget *_gadget)
+{
+	struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
+
+	/* frame number is in bits 13:3 */
+	return (readl(USB_FRINDEX) >> 3) & 0x000007FF;
+}
+
+/* VBUS reporting logically comes from a transceiver */
+static int msm72k_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	msm_hsusb_set_vbus_state(is_active);
+	return 0;
+}
+
+/* drivers may have software control over D+ pullup */
+static int msm72k_pullup(struct usb_gadget *_gadget, int is_active)
+{
+	struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
+
+	u32 cmd = (8 << 16);
+
+	/* disable/enable D+ pullup */
+	if (is_active) {
+		pr_info("msm_hsusb: enable pullup\n");
+		writel(cmd | 1, USB_USBCMD);
+	} else {
+		pr_info("msm_hsusb: disable pullup\n");
+		writel(cmd, USB_USBCMD);
+
+#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM7X30)
+		ulpi_write(ui, 0x48, 0x04);
+#endif
+	}
+
+	return 0;
+}
+
+static int msm72k_wakeup(struct usb_gadget *_gadget)
+{
+	struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
+	unsigned long flags;
+
+	if (!ui->remote_wakeup) {
+		pr_err("%s: remote wakeup not supported\n", __func__);
+		return -ENOTSUPP;
+	}
+
+	if (!ui->online) {
+		pr_err("%s: device is not configured\n", __func__);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&ui->lock, flags);
+	if ((readl(USB_PORTSC) & PORTSC_SUSP) == PORTSC_SUSP) {
+		pr_info("%s: enabling force resume\n", __func__);
+		writel(readl(USB_PORTSC) | PORTSC_FPR, USB_PORTSC);
+	}
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return 0;
+}
+
+static const struct usb_gadget_ops msm72k_ops = {
+	.get_frame	= msm72k_get_frame,
+	.vbus_session	= msm72k_udc_vbus_session,
+	.pullup		= msm72k_pullup,
+	.wakeup		= msm72k_wakeup,
+};
+
+static ssize_t usb_remote_wakeup(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct usb_info *ui = the_usb_info;
+
+	msm72k_wakeup(&ui->gadget);
+
+	return count;
+}
+static DEVICE_ATTR(wakeup, S_IWUSR, 0, usb_remote_wakeup);
+
+static int msm72k_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct usb_info *ui;
+	int irq;
+	int ret;
+
+	INFO("msm72k_probe\n");
+	ui = kzalloc(sizeof(struct usb_info), GFP_KERNEL);
+	if (!ui)
+		return -ENOMEM;
+
+	spin_lock_init(&ui->lock);
+	ui->pdev = pdev;
+
+	if (pdev->dev.platform_data) {
+		struct msm_hsusb_platform_data *pdata = pdev->dev.platform_data;
+		ui->phy_reset = pdata->phy_reset;
+		ui->phy_init_seq = pdata->phy_init_seq;
+		ui->usb_connected = pdata->usb_connected;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res || (irq < 0))
+		return usb_free(ui, -ENODEV);
+
+	ui->addr = ioremap(res->start, 4096);
+	if (!ui->addr)
+		return usb_free(ui, -ENOMEM);
+
+	ui->buf = dma_alloc_coherent(&pdev->dev, 4096, &ui->dma, GFP_KERNEL);
+	if (!ui->buf)
+		return usb_free(ui, -ENOMEM);
+
+	ui->pool = dma_pool_create("msm72k_udc", NULL, 32, 32, 0);
+	if (!ui->pool)
+		return usb_free(ui, -ENOMEM);
+
+	INFO("msm72k_probe() io=%p, irq=%d, dma=%p(%x)\n",
+	       ui->addr, irq, ui->buf, ui->dma);
+
+	ui->clk = clk_get(&pdev->dev, "usb_hs_clk");
+	if (IS_ERR(ui->clk))
+		return usb_free(ui, PTR_ERR(ui->clk));
+
+	ui->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
+	if (IS_ERR(ui->pclk))
+		return usb_free(ui, PTR_ERR(ui->pclk));
+
+	ui->otgclk = clk_get(&pdev->dev, "usb_otg_clk");
+	if (IS_ERR(ui->otgclk))
+		ui->otgclk = NULL;
+
+	ui->coreclk = clk_get(&pdev->dev, "usb_hs_core_clk");
+	if (IS_ERR(ui->coreclk))
+		ui->coreclk = NULL;
+
+	ui->ebi1clk = clk_get(NULL, "ebi1_clk");
+	if (IS_ERR(ui->ebi1clk))
+		return usb_free(ui, PTR_ERR(ui->ebi1clk));
+
+	/* clear interrupts before requesting irq */
+	if (ui->coreclk)
+		clk_enable(ui->coreclk);
+	clk_enable(ui->clk);
+	clk_enable(ui->pclk);
+	if (ui->otgclk)
+		clk_enable(ui->otgclk);
+	writel(0, USB_USBINTR);
+	writel(0, USB_OTGSC);
+	if (ui->coreclk)
+		clk_disable(ui->coreclk);
+	if (ui->otgclk)
+		clk_disable(ui->otgclk);
+	clk_disable(ui->pclk);
+	clk_disable(ui->clk);
+
+	ret = request_irq(irq, usb_interrupt, 0, pdev->name, ui);
+	if (ret)
+		return usb_free(ui, ret);
+	enable_irq_wake(irq);
+	ui->irq = irq;
+
+	ui->gadget.ops = &msm72k_ops;
+	ui->gadget.is_dualspeed = 1;
+	device_initialize(&ui->gadget.dev);
+	dev_set_name(&ui->gadget.dev, "gadget");
+	ui->gadget.dev.parent = &pdev->dev;
+	ui->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+	the_usb_info = ui;
+
+	usb_debugfs_init(ui);
+
+	usb_prepare(ui);
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct usb_info *ui = the_usb_info;
+	int			retval, n;
+
+	if (!driver
+			|| driver->speed < USB_SPEED_FULL
+			|| !driver->bind
+			|| !driver->disconnect
+			|| !driver->setup)
+		return -EINVAL;
+	if (!ui)
+		return -ENODEV;
+	if (ui->driver)
+		return -EBUSY;
+
+	/* first hook up the driver ... */
+	ui->driver = driver;
+	ui->gadget.dev.driver = &driver->driver;
+	ui->gadget.name = driver_name;
+	INIT_LIST_HEAD(&ui->gadget.ep_list);
+	ui->gadget.ep0 = &ui->ep0in.ep;
+	INIT_LIST_HEAD(&ui->gadget.ep0->ep_list);
+	ui->gadget.speed = USB_SPEED_UNKNOWN;
+
+	for (n = 1; n < 16; n++) {
+		struct msm_endpoint *ept = ui->ept + n;
+		list_add_tail(&ept->ep.ep_list, &ui->gadget.ep_list);
+		ept->ep.maxpacket = 512;
+	}
+	for (n = 17; n < 32; n++) {
+		struct msm_endpoint *ept = ui->ept + n;
+		list_add_tail(&ept->ep.ep_list, &ui->gadget.ep_list);
+		ept->ep.maxpacket = 512;
+	}
+
+	retval = device_add(&ui->gadget.dev);
+	if (retval)
+		goto fail;
+
+	retval = driver->bind(&ui->gadget);
+	if (retval) {
+		INFO("bind to driver %s --> error %d\n",
+				driver->driver.name, retval);
+		device_del(&ui->gadget.dev);
+		goto fail;
+	}
+
+	/* create sysfs node for remote wakeup */
+	retval = device_create_file(&ui->gadget.dev, &dev_attr_wakeup);
+	if (retval != 0)
+		INFO("failed to create sysfs entry: (wakeup) error: (%d)\n",
+					retval);
+	INFO("msm72k_udc: registered gadget driver '%s'\n",
+			driver->driver.name);
+	usb_start(ui);
+
+	return 0;
+
+fail:
+	ui->driver = NULL;
+	ui->gadget.dev.driver = NULL;
+	return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct usb_info *dev = the_usb_info;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver || !driver->unbind)
+		return -EINVAL;
+
+	device_remove_file(&dev->gadget.dev, &dev_attr_wakeup);
+	driver->unbind(&dev->gadget);
+	dev->gadget.dev.driver = NULL;
+	dev->driver = NULL;
+
+	device_del(&dev->gadget.dev);
+
+	VDEBUG("unregistered gadget driver '%s'\n", driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+static struct platform_driver usb_driver = {
+	.probe = msm72k_probe,
+	.driver = { .name = "msm_hsusb", },
+};
+
+static int __init init(void)
+{
+	return platform_driver_register(&usb_driver);
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+	platform_driver_unregister(&usb_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Mike Lockwood, Brian Swetland");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3d94a14..20fbb49 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2196,13 +2196,6 @@
 	  Select this option if display contents should be inherited as set by
 	  the bootloader.
 
-config FB_MSM
-	tristate "MSM Framebuffer support"
-	depends on FB && ARCH_MSM
-	select FB_CFB_FILLRECT
-	select FB_CFB_COPYAREA
-	select FB_CFB_IMAGEBLIT
-
 config FB_MX3
 	tristate "MX3 Framebuffer support"
 	depends on FB && MX3_IPU
@@ -2229,6 +2222,8 @@
 	  and could also have been called by other names when coupled with
 	  a bridge adapter.
 
+source "drivers/video/msm/Kconfig"
+
 source "drivers/video/omap/Kconfig"
 source "drivers/video/omap2/Kconfig"
 
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
new file mode 100644
index 0000000..fe5ee26
--- /dev/null
+++ b/drivers/video/msm/Kconfig
@@ -0,0 +1,46 @@
+config FB_MSM
+	tristate
+	depends on FB && ARCH_MSM
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	default y
+
+config FB_MSM_LEGACY_MDP
+	bool
+	depends on FB_MSM && (MSM_MDP31 || MSM_MDP22)
+	default y
+
+config FB_MSM_MDP_PPP
+	bool
+	depends on FB_MSM_LEGACY_MDP
+	default y
+
+config FB_MSM_LCDC
+	bool "Support for integrated LCD controller in qsd8x50"
+	depends on FB_MSM && MSM_MDP31
+	default y
+
+config FB_MSM_MDDI
+	bool "Support for MSM MDDI controllers"
+	depends on FB_MSM
+	default y
+
+config GPU_MSM_KGSL
+	tristate "MSM 3D Graphics driver for Adreno class GPUs"
+	default n
+	depends on FB_MSM && (ARCH_QSD8X50 || ARCH_MSM7X30)
+	select GENERIC_ALLOCATOR
+	select CONFIG_FW_LOADER
+	help
+	  3D graphics driver for QSD8x50 and MSM7x27. Required to
+	  use hardware accelerated OpenGL ES 2.0 and 1.1 on these
+	  chips.
+
+config MSM_KGSL_MMU
+	bool "Turn on MMU for graphics driver "
+	depends on GPU_MSM_KGSL && MMU
+	default n
+	help
+	  If enabled, the GPU driver will allocate memory from vmalloc
+	  and enable the use of GPU MMU, instead of using pmem.
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index 802d6ae..3fcfbd8 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -2,18 +2,33 @@
 # core framebuffer
 #
 obj-y := msm_fb.o
+ifeq ($(CONFIG_FB_MSM_LOGO),y)
+obj-y += logo.o
+endif
 
 # MDP DMA/PPP engine
 #
-obj-y += mdp.o mdp_scale_tables.o mdp_ppp.o
+obj-y += mdp.o
+
+obj-$(CONFIG_MSM_MDP40) += mdp_hw40.o
+
+obj-$(CONFIG_FB_MSM_LEGACY_MDP) += mdp_hw_legacy.o
+
+obj-$(CONFIG_FB_MSM_MDP_PPP) += mdp_ppp.o
+obj-$(CONFIG_MSM_MDP22) += mdp_ppp22.o
+obj-$(CONFIG_MSM_MDP31) += mdp_ppp31.o
 
 # MDDI interface
 #
-obj-y += mddi.o
+obj-$(CONFIG_FB_MSM_MDDI) += mddi.o
 
 # MDDI client/panel drivers
 #
-obj-y += mddi_client_dummy.o
-obj-y += mddi_client_toshiba.o
-obj-y += mddi_client_nt35399.o
+obj-$(CONFIG_FB_MSM_MDDI) += mddi_client_simple.o
+obj-$(CONFIG_FB_MSM_MDDI) += mddi_client_toshiba.o
 
+# MDP LCD controller driver
+obj-$(CONFIG_FB_MSM_LCDC) += mdp_lcdc.o
+
+# Yamato GL driver
+obj-$(CONFIG_GPU_MSM_KGSL) += gpu/kgsl/
diff --git a/drivers/video/msm/gpu/kgsl/Makefile b/drivers/video/msm/gpu/kgsl/Makefile
new file mode 100644
index 0000000..0290b50
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/Makefile
@@ -0,0 +1,11 @@
+msm_kgsl-objs = \
+	kgsl_drawctxt.o \
+	kgsl_cmdstream.o \
+	kgsl.o \
+	kgsl_log.o \
+	kgsl_mmu.o \
+	kgsl_ringbuffer.o \
+	kgsl_sharedmem.o \
+	kgsl_yamato.o
+
+obj-$(CONFIG_GPU_MSM_KGSL) += msm_kgsl.o
diff --git a/drivers/video/msm/gpu/kgsl/kgsl.c b/drivers/video/msm/gpu/kgsl/kgsl.c
new file mode 100644
index 0000000..4dde98e
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl.c
@@ -0,0 +1,1230 @@
+/*
+* Copyright (c) 2008-2009 QUALCOMM USA, INC.
+* 
+* All source code in this file is licensed under the following license
+* 
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+* 
+* This 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.
+* 
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, you can find it at http://www.fsf.org
+*/
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/android_pmem.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+#include <asm/cacheflush.h>
+
+#include <asm/atomic.h>
+
+#include "kgsl.h"
+#include "kgsl_drawctxt.h"
+#include "kgsl_ringbuffer.h"
+#include "kgsl_cmdstream.h"
+#include "kgsl_log.h"
+
+struct kgsl_file_private {
+	struct list_head	list;
+	struct list_head	mem_list;
+	uint32_t		ctxt_id_mask;
+	struct kgsl_pagetable	*pagetable;
+	unsigned long		vmalloc_size;
+};
+
+static void kgsl_put_phys_file(struct file *file);
+
+#ifdef CONFIG_MSM_KGSL_MMU
+static long flush_l1_cache_range(unsigned long addr, int size)
+{
+	struct page *page;
+	pte_t *pte_ptr;
+	unsigned long end;
+
+	for (end = addr; end < (addr + size); end += KGSL_PAGESIZE) {
+		pte_ptr = kgsl_get_pte_from_vaddr(end);
+		if (!pte_ptr)
+			return -EINVAL;
+
+		page = pte_page(pte_val(*pte_ptr));
+		if (!page) {
+			KGSL_DRV_ERR("could not find page for pte\n");
+			pte_unmap(pte_ptr);
+			return -EINVAL;
+		}
+
+		pte_unmap(pte_ptr);
+		flush_dcache_page(page);
+	}
+
+	return 0;
+}
+
+static long flush_l1_cache_all(struct kgsl_file_private *private)
+{
+	int result = 0;
+	struct kgsl_mem_entry *entry = NULL;
+
+	kgsl_yamato_runpending(&kgsl_driver.yamato_device);
+	list_for_each_entry(entry, &private->mem_list, list) {
+		if (KGSL_MEMFLAGS_MEM_REQUIRES_FLUSH & entry->memdesc.priv) {
+			result =
+			    flush_l1_cache_range((unsigned long)entry->
+						 memdesc.hostptr,
+						 entry->memdesc.size);
+			if (result)
+				goto done;
+		}
+	}
+done:
+	return result;
+}
+#else
+static inline long flush_l1_cache_range(unsigned long addr, int size)
+{ return 0; }
+
+static inline long flush_l1_cache_all(struct kgsl_file_private *private)
+{ return 0; }
+#endif
+
+/*this is used for logging, so that we can call the dev_printk
+ functions without export struct kgsl_driver everywhere*/
+struct device *kgsl_driver_getdevnode(void)
+{
+	BUG_ON(kgsl_driver.pdev == NULL);
+	return &kgsl_driver.pdev->dev;
+}
+
+/* the hw and clk enable/disable funcs must be either called from softirq or
+ * with mutex held */
+static void kgsl_clk_enable(void)
+{
+	clk_set_rate(kgsl_driver.ebi1_clk, 128000000);
+	clk_enable(kgsl_driver.imem_clk);
+	if (kgsl_driver.grp_pclk)
+		clk_enable(kgsl_driver.grp_pclk);
+	clk_enable(kgsl_driver.grp_clk);
+}
+
+static void kgsl_clk_disable(void)
+{
+	clk_disable(kgsl_driver.grp_clk);
+	if (kgsl_driver.grp_pclk)
+		clk_disable(kgsl_driver.grp_pclk);
+	clk_disable(kgsl_driver.imem_clk);
+	clk_set_rate(kgsl_driver.ebi1_clk, 0);
+}
+
+static void kgsl_hw_disable(void)
+{
+	kgsl_driver.active = false;
+	disable_irq(kgsl_driver.interrupt_num);
+	kgsl_clk_disable();
+	pr_debug("kgsl: hw disabled\n");
+	wake_unlock(&kgsl_driver.wake_lock);
+}
+
+static void kgsl_hw_enable(void)
+{
+	wake_lock(&kgsl_driver.wake_lock);
+	kgsl_clk_enable();
+	enable_irq(kgsl_driver.interrupt_num);
+	kgsl_driver.active = true;
+	pr_debug("kgsl: hw enabled\n");
+}
+
+static void kgsl_hw_get_locked(void)
+{
+	/* active_cnt is protected by driver mutex */
+	if (kgsl_driver.active_cnt++ == 0) {
+		if (kgsl_driver.active) {
+			del_timer_sync(&kgsl_driver.standby_timer);
+			barrier();
+		}
+		if (!kgsl_driver.active)
+			kgsl_hw_enable();
+	}
+}
+
+static void kgsl_hw_put_locked(bool start_timer)
+{
+	if ((--kgsl_driver.active_cnt == 0) && start_timer) {
+		mod_timer(&kgsl_driver.standby_timer,
+			  jiffies + msecs_to_jiffies(20));
+	}
+}
+
+static void kgsl_do_standby_timer(unsigned long data)
+{
+	if (kgsl_yamato_is_idle(&kgsl_driver.yamato_device))
+		kgsl_hw_disable();
+	else
+		mod_timer(&kgsl_driver.standby_timer,
+			  jiffies + msecs_to_jiffies(10));
+}
+
+/* file operations */
+static int kgsl_first_open_locked(void)
+{
+	int result = 0;
+
+	BUG_ON(kgsl_driver.active);
+	BUG_ON(kgsl_driver.active_cnt);
+
+	kgsl_clk_enable();
+
+	/* init memory apertures */
+	result = kgsl_sharedmem_init(&kgsl_driver.shmem);
+	if (result != 0)
+		goto done;
+
+	/* init devices */
+	result = kgsl_yamato_init(&kgsl_driver.yamato_device,
+					&kgsl_driver.yamato_config);
+	if (result != 0)
+		goto done;
+
+	result = kgsl_yamato_start(&kgsl_driver.yamato_device, 0);
+	if (result != 0)
+		goto done;
+
+done:
+	kgsl_clk_disable();
+	return result;
+}
+
+static int kgsl_last_release_locked(void)
+{
+	BUG_ON(kgsl_driver.active_cnt);
+
+	disable_irq(kgsl_driver.interrupt_num);
+
+	kgsl_yamato_stop(&kgsl_driver.yamato_device);
+
+	/* close devices */
+	kgsl_yamato_close(&kgsl_driver.yamato_device);
+
+	/* shutdown memory apertures */
+	kgsl_sharedmem_close(&kgsl_driver.shmem);
+
+	kgsl_clk_disable();
+	kgsl_driver.active = false;
+	wake_unlock(&kgsl_driver.wake_lock);
+
+	return 0;
+}
+
+static int kgsl_release(struct inode *inodep, struct file *filep)
+{
+	int result = 0;
+	unsigned int i;
+	struct kgsl_mem_entry *entry, *entry_tmp;
+	struct kgsl_file_private *private = NULL;
+
+	mutex_lock(&kgsl_driver.mutex);
+
+	private = filep->private_data;
+	BUG_ON(private == NULL);
+	filep->private_data = NULL;
+	list_del(&private->list);
+
+	kgsl_hw_get_locked();
+
+	for (i = 0; i < KGSL_CONTEXT_MAX; i++)
+		if (private->ctxt_id_mask & (1 << i))
+			kgsl_drawctxt_destroy(&kgsl_driver.yamato_device, i);
+
+	list_for_each_entry_safe(entry, entry_tmp, &private->mem_list, list)
+		kgsl_remove_mem_entry(entry);
+
+	if (private->pagetable != NULL) {
+		kgsl_yamato_cleanup_pt(&kgsl_driver.yamato_device,
+					private->pagetable);
+		kgsl_mmu_destroypagetableobject(private->pagetable);
+		private->pagetable = NULL;
+	}
+
+	kfree(private);
+
+	if (atomic_dec_return(&kgsl_driver.open_count) == 0) {
+		KGSL_DRV_VDBG("last_release\n");
+		kgsl_hw_put_locked(false);
+		result = kgsl_last_release_locked();
+	} else
+		kgsl_hw_put_locked(true);
+
+	mutex_unlock(&kgsl_driver.mutex);
+
+	return result;
+}
+
+static int kgsl_open(struct inode *inodep, struct file *filep)
+{
+	int result = 0;
+	struct kgsl_file_private *private = NULL;
+
+	KGSL_DRV_DBG("file %p pid %d\n", filep, task_pid_nr(current));
+
+
+	if (filep->f_flags & O_EXCL) {
+		KGSL_DRV_ERR("O_EXCL not allowed\n");
+		return -EBUSY;
+	}
+
+	private = kzalloc(sizeof(*private), GFP_KERNEL);
+	if (private == NULL) {
+		KGSL_DRV_ERR("cannot allocate file private data\n");
+		return -ENOMEM;
+	}
+
+	mutex_lock(&kgsl_driver.mutex);
+
+	private->ctxt_id_mask = 0;
+	INIT_LIST_HEAD(&private->mem_list);
+
+	filep->private_data = private;
+
+	list_add(&private->list, &kgsl_driver.client_list);
+
+	if (atomic_inc_return(&kgsl_driver.open_count) == 1) {
+		result = kgsl_first_open_locked();
+		if (result != 0)
+			goto done;
+	}
+
+	kgsl_hw_get_locked();
+
+	/*NOTE: this must happen after first_open */
+	private->pagetable =
+		kgsl_mmu_createpagetableobject(&kgsl_driver.yamato_device.mmu);
+	if (private->pagetable == NULL) {
+		result = -ENOMEM;
+		goto done;
+	}
+	result = kgsl_yamato_setup_pt(&kgsl_driver.yamato_device,
+					private->pagetable);
+	if (result) {
+		kgsl_mmu_destroypagetableobject(private->pagetable);
+		private->pagetable = NULL;
+		goto done;
+	}
+	private->vmalloc_size = 0;
+done:
+	kgsl_hw_put_locked(true);
+	mutex_unlock(&kgsl_driver.mutex);
+	if (result != 0)
+		kgsl_release(inodep, filep);
+	return result;
+}
+
+
+/*call with driver locked */
+static struct kgsl_mem_entry *
+kgsl_sharedmem_find(struct kgsl_file_private *private, unsigned int gpuaddr)
+{
+	struct kgsl_mem_entry *entry = NULL, *result = NULL;
+
+	BUG_ON(private == NULL);
+
+	list_for_each_entry(entry, &private->mem_list, list) {
+		if (entry->memdesc.gpuaddr == gpuaddr) {
+			result = entry;
+			break;
+		}
+	}
+	return result;
+}
+
+/*call with driver locked */
+struct kgsl_mem_entry *
+kgsl_sharedmem_find_region(struct kgsl_file_private *private,
+				unsigned int gpuaddr,
+				size_t size)
+{
+	struct kgsl_mem_entry *entry = NULL, *result = NULL;
+
+	BUG_ON(private == NULL);
+
+	list_for_each_entry(entry, &private->mem_list, list) {
+		if (gpuaddr >= entry->memdesc.gpuaddr &&
+		    ((gpuaddr + size) <=
+			(entry->memdesc.gpuaddr + entry->memdesc.size))) {
+			result = entry;
+			break;
+		}
+	}
+
+	return result;
+}
+
+/*call all ioctl sub functions with driver locked*/
+
+static long kgsl_ioctl_device_getproperty(struct kgsl_file_private *private,
+					 void __user *arg)
+{
+	int result = 0;
+	struct kgsl_device_getproperty param;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+	result = kgsl_yamato_getproperty(&kgsl_driver.yamato_device,
+					 param.type,
+					 param.value, param.sizebytes);
+done:
+	return result;
+}
+
+static long kgsl_ioctl_device_regread(struct kgsl_file_private *private,
+				     void __user *arg)
+{
+	int result = 0;
+	struct kgsl_device_regread param;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+	result = kgsl_yamato_regread(&kgsl_driver.yamato_device,
+				     param.offsetwords, &param.value);
+	if (result != 0)
+		goto done;
+
+	if (copy_to_user(arg, &param, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+done:
+	return result;
+}
+
+
+static long kgsl_ioctl_device_waittimestamp(struct kgsl_file_private *private,
+				     void __user *arg)
+{
+	int result = 0;
+	struct kgsl_device_waittimestamp param;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+
+	/* Don't wait forever, set a max value for now */
+	if (param.timeout == -1)
+		param.timeout = 10 * MSEC_PER_SEC;
+	result = kgsl_yamato_waittimestamp(&kgsl_driver.yamato_device,
+				     param.timestamp,
+				     param.timeout);
+
+	kgsl_yamato_runpending(&kgsl_driver.yamato_device);
+done:
+	return result;
+}
+
+static long kgsl_ioctl_rb_issueibcmds(struct kgsl_file_private *private,
+				     void __user *arg)
+{
+	int result = 0;
+	struct kgsl_ringbuffer_issueibcmds param;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (param.drawctxt_id >= KGSL_CONTEXT_MAX
+		|| (private->ctxt_id_mask & 1 << param.drawctxt_id) == 0) {
+		result = -EINVAL;
+		KGSL_DRV_ERR("invalid drawctxt drawctxt_id %d\n",
+			      param.drawctxt_id);
+		result = -EINVAL;
+		goto done;
+	}
+
+	if (kgsl_sharedmem_find_region(private, param.ibaddr,
+				param.sizedwords*sizeof(uint32_t)) == NULL) {
+		KGSL_DRV_ERR("invalid cmd buffer ibaddr %08x sizedwords %d\n",
+			      param.ibaddr, param.sizedwords);
+		result = -EINVAL;
+		goto done;
+
+	}
+
+	result = kgsl_ringbuffer_issueibcmds(&kgsl_driver.yamato_device,
+					     param.drawctxt_id,
+					     param.ibaddr,
+					     param.sizedwords,
+					     &param.timestamp,
+					     param.flags);
+	if (result != 0)
+		goto done;
+
+	if (copy_to_user(arg, &param, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+done:
+	return result;
+}
+
+static long kgsl_ioctl_cmdstream_readtimestamp(struct kgsl_file_private
+						*private, void __user *arg)
+{
+	int result = 0;
+	struct kgsl_cmdstream_readtimestamp param;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+
+	param.timestamp =
+		kgsl_cmdstream_readtimestamp(&kgsl_driver.yamato_device,
+							param.type);
+	if (result != 0)
+		goto done;
+
+	if (copy_to_user(arg, &param, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+done:
+	return result;
+}
+
+static long kgsl_ioctl_cmdstream_freememontimestamp(struct kgsl_file_private
+						*private, void __user *arg)
+{
+	int result = 0;
+	struct kgsl_cmdstream_freememontimestamp param;
+	struct kgsl_mem_entry *entry = NULL;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+
+	entry = kgsl_sharedmem_find(private, param.gpuaddr);
+	if (entry == NULL) {
+		KGSL_DRV_ERR("invalid gpuaddr %08x\n", param.gpuaddr);
+		result = -EINVAL;
+		goto done;
+	}
+
+	if (entry->memdesc.priv & KGSL_MEMFLAGS_VMALLOC_MEM)
+		entry->memdesc.priv &= ~KGSL_MEMFLAGS_MEM_REQUIRES_FLUSH;
+
+	result = kgsl_cmdstream_freememontimestamp(&kgsl_driver.yamato_device,
+							entry,
+							param.timestamp,
+							param.type);
+
+	kgsl_yamato_runpending(&kgsl_driver.yamato_device);
+
+done:
+	return result;
+}
+
+static long kgsl_ioctl_drawctxt_create(struct kgsl_file_private *private,
+				      void __user *arg)
+{
+	int result = 0;
+	struct kgsl_drawctxt_create param;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+
+	result = kgsl_drawctxt_create(&kgsl_driver.yamato_device,
+					private->pagetable,
+					param.flags,
+					&param.drawctxt_id);
+	if (result != 0)
+		goto done;
+
+	if (copy_to_user(arg, &param, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+
+	private->ctxt_id_mask |= 1 << param.drawctxt_id;
+
+done:
+	return result;
+}
+
+static long kgsl_ioctl_drawctxt_destroy(struct kgsl_file_private *private,
+				       void __user *arg)
+{
+	int result = 0;
+	struct kgsl_drawctxt_destroy param;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (param.drawctxt_id >= KGSL_CONTEXT_MAX
+		|| (private->ctxt_id_mask & 1 << param.drawctxt_id) == 0) {
+		result = -EINVAL;
+		goto done;
+	}
+
+	result = kgsl_drawctxt_destroy(&kgsl_driver.yamato_device,
+					param.drawctxt_id);
+	if (result == 0)
+		private->ctxt_id_mask &= ~(1 << param.drawctxt_id);
+
+done:
+	return result;
+}
+
+void kgsl_remove_mem_entry(struct kgsl_mem_entry *entry)
+{
+	kgsl_mmu_unmap(entry->memdesc.pagetable,
+		       entry->memdesc.gpuaddr & KGSL_PAGEMASK,
+		       entry->memdesc.size);
+	if (KGSL_MEMFLAGS_VMALLOC_MEM & entry->memdesc.priv) {
+		vfree((void *)entry->memdesc.physaddr);
+		entry->priv->vmalloc_size -= entry->memdesc.size;
+	} else
+		kgsl_put_phys_file(entry->pmem_file);
+	list_del(&entry->list);
+
+	if (entry->free_list.prev)
+		list_del(&entry->free_list);
+
+	kfree(entry);
+
+}
+
+static long kgsl_ioctl_sharedmem_free(struct kgsl_file_private *private,
+				     void __user *arg)
+{
+	int result = 0;
+	struct kgsl_sharedmem_free param;
+	struct kgsl_mem_entry *entry = NULL;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+
+	entry = kgsl_sharedmem_find(private, param.gpuaddr);
+	if (entry == NULL) {
+		KGSL_DRV_ERR("invalid gpuaddr %08x\n", param.gpuaddr);
+		result = -EINVAL;
+		goto done;
+	}
+
+	kgsl_remove_mem_entry(entry);
+done:
+	return result;
+}
+
+#ifdef CONFIG_MSM_KGSL_MMU
+static int kgsl_ioctl_sharedmem_from_vmalloc(struct kgsl_file_private *private,
+					     void __user *arg)
+{
+	int result = 0, len;
+	struct kgsl_sharedmem_from_vmalloc param;
+	struct kgsl_mem_entry *entry = NULL;
+	void *vmalloc_area;
+	struct vm_area_struct *vma;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto error;
+	}
+
+	if (!param.hostptr) {
+		KGSL_DRV_ERR
+		    ("Invalid host pointer of malloc passed: param.hostptr "
+		     "%08x\n", param.hostptr);
+		result = -EINVAL;
+		goto error;
+	}
+
+	vma = find_vma(current->mm, param.hostptr);
+	if (!vma) {
+		KGSL_MEM_ERR("Could not find vma for address %x\n",
+			     param.hostptr);
+		result = -EINVAL;
+		goto error;
+	}
+	len = vma->vm_end - vma->vm_start;
+	if (vma->vm_pgoff || !IS_ALIGNED(len, PAGE_SIZE)
+	    || !IS_ALIGNED(vma->vm_start, PAGE_SIZE)) {
+		KGSL_MEM_ERR
+		("kgsl vmalloc mapping must be at offset 0 and page aligned\n");
+		result = -EINVAL;
+		goto error;
+	}
+	if (vma->vm_start != param.hostptr) {
+		KGSL_MEM_ERR
+		    ("vma start address is not equal to mmap address\n");
+		result = -EINVAL;
+		goto error;
+	}
+
+	if ((private->vmalloc_size + len) > KGSL_GRAPHICS_MEMORY_LOW_WATERMARK
+	    && !param.force_no_low_watermark) {
+		result = -ENOMEM;
+		goto error;
+	}
+
+	entry = kzalloc(sizeof(struct kgsl_mem_entry), GFP_KERNEL);
+	if (entry == NULL) {
+		result = -ENOMEM;
+		goto error;
+	}
+
+	/* allocate memory and map it to user space */
+	vmalloc_area = vmalloc_user(len);
+	if (!vmalloc_area) {
+		KGSL_MEM_ERR("vmalloc failed\n");
+		result = -ENOMEM;
+		goto error_free_entry;
+	}
+	if (!kgsl_cache_enable) {
+		/* If we are going to map non-cached, make sure to flush the
+		 * cache to ensure that previously cached data does not
+		 * overwrite this memory */
+		dmac_flush_range(vmalloc_area, vmalloc_area + len);
+		KGSL_MEM_INFO("Caching for memory allocation turned off\n");
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+	} else {
+		KGSL_MEM_INFO("Caching for memory allocation turned on\n");
+	}
+
+	result = remap_vmalloc_range(vma, vmalloc_area, 0);
+	if (result) {
+		KGSL_MEM_ERR("remap_vmalloc_range returned %d\n", result);
+		goto error_free_vmalloc;
+	}
+
+	result =
+	    kgsl_mmu_map(private->pagetable, (unsigned long)vmalloc_area, len,
+			 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV,
+			 &entry->memdesc.gpuaddr, KGSL_MEMFLAGS_ALIGN4K);
+
+	if (result != 0)
+		goto error_free_vmalloc;
+
+	entry->memdesc.pagetable = private->pagetable;
+	entry->memdesc.size = len;
+	entry->memdesc.hostptr = (void *)param.hostptr;
+	entry->memdesc.priv = KGSL_MEMFLAGS_VMALLOC_MEM |
+	    KGSL_MEMFLAGS_MEM_REQUIRES_FLUSH;
+	entry->memdesc.physaddr = (unsigned long)vmalloc_area;
+	entry->priv = private;
+
+	param.gpuaddr = entry->memdesc.gpuaddr;
+
+	if (copy_to_user(arg, &param, sizeof(param))) {
+		result = -EFAULT;
+		goto error_unmap_entry;
+	}
+	private->vmalloc_size += len;
+	list_add(&entry->list, &private->mem_list);
+
+	return 0;
+
+error_unmap_entry:
+	kgsl_mmu_unmap(private->pagetable, entry->memdesc.gpuaddr,
+		       entry->memdesc.size);
+
+error_free_vmalloc:
+	vfree(vmalloc_area);
+
+error_free_entry:
+	kfree(entry);
+
+error:
+	return result;
+}
+#else
+static inline int kgsl_ioctl_sharedmem_from_vmalloc(
+			struct kgsl_file_private *private, void __user *arg)
+{
+	return -ENOSYS;
+}
+#endif
+
+static int kgsl_get_phys_file(int fd, unsigned long *start, unsigned long *len,
+			      struct file **filep)
+{
+	struct file *fbfile;
+	int put_needed;
+	unsigned long vstart = 0;
+	int ret = 0;
+	dev_t rdev;
+	struct fb_info *info;
+
+	*filep = NULL;
+	if (!get_pmem_file(fd, start, &vstart, len, filep))
+		return 0;
+
+	fbfile = fget_light(fd, &put_needed);
+	if (fbfile == NULL)
+		return -1;
+
+	rdev = fbfile->f_dentry->d_inode->i_rdev;
+	info = MAJOR(rdev) == FB_MAJOR ? registered_fb[MINOR(rdev)] : NULL;
+	if (info) {
+		*start = info->fix.smem_start;
+		*len = info->fix.smem_len;
+		ret = 0;
+	} else
+		ret = -1;
+	fput_light(fbfile, put_needed);
+
+	return ret;
+}
+
+static void kgsl_put_phys_file(struct file *file)
+{
+	KGSL_DRV_DBG("put phys file %p\n", file);
+	if (file)
+		put_pmem_file(file);
+}
+
+static int kgsl_ioctl_sharedmem_from_pmem(struct kgsl_file_private *private,
+						void __user *arg)
+{
+	int result = 0;
+	struct kgsl_sharedmem_from_pmem param;
+	struct kgsl_mem_entry *entry = NULL;
+	unsigned long start = 0, len = 0;
+	struct file *pmem_file = NULL;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto error;
+	}
+
+	if (kgsl_get_phys_file(param.pmem_fd, &start, &len, &pmem_file)) {
+		result = -EINVAL;
+		goto error;
+	} else if (param.offset + param.len > len) {
+		KGSL_DRV_ERR("%s: region too large 0x%x + 0x%x >= 0x%lx\n",
+			     __func__, param.offset, param.len, len);
+		result = -EINVAL;
+		goto error_put_pmem;
+	}
+
+	KGSL_MEM_INFO("get phys file %p start 0x%lx len 0x%lx\n",
+		      pmem_file, start, len);
+	KGSL_DRV_DBG("locked phys file %p\n", pmem_file);
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (entry == NULL) {
+		result = -ENOMEM;
+		goto error_put_pmem;
+	}
+
+	entry->pmem_file = pmem_file;
+
+	entry->memdesc.pagetable = private->pagetable;
+
+	/* Any MMU mapped memory must have a length in multiple of PAGESIZE */
+	entry->memdesc.size = ALIGN(param.len, PAGE_SIZE);
+
+	/*we shouldn't need to write here from kernel mode */
+	entry->memdesc.hostptr = NULL;
+
+	/* ensure that MMU mappings are at page boundary */
+	entry->memdesc.physaddr = start + (param.offset & KGSL_PAGEMASK);
+	result = kgsl_mmu_map(private->pagetable, entry->memdesc.physaddr,
+			entry->memdesc.size, GSL_PT_PAGE_RV | GSL_PT_PAGE_WV,
+			&entry->memdesc.gpuaddr,
+			KGSL_MEMFLAGS_ALIGN4K | KGSL_MEMFLAGS_CONPHYS);
+	if (result)
+		goto error_free_entry;
+
+	/* If the offset is not at 4K boundary then add the correct offset
+	 * value to gpuaddr */
+	entry->memdesc.gpuaddr += (param.offset & ~KGSL_PAGEMASK);
+	param.gpuaddr = entry->memdesc.gpuaddr;
+
+	if (copy_to_user(arg, &param, sizeof(param))) {
+		result = -EFAULT;
+		goto error_unmap_entry;
+	}
+	list_add(&entry->list, &private->mem_list);
+	return result;
+
+error_unmap_entry:
+	kgsl_mmu_unmap(entry->memdesc.pagetable,
+		       entry->memdesc.gpuaddr & KGSL_PAGEMASK,
+		       entry->memdesc.size);
+error_free_entry:
+	kfree(entry);
+
+error_put_pmem:
+	kgsl_put_phys_file(pmem_file);
+
+error:
+	return result;
+}
+
+#ifdef CONFIG_MSM_KGSL_MMU
+/*This function flushes a graphics memory allocation from CPU cache
+ *when caching is enabled with MMU*/
+static int kgsl_ioctl_sharedmem_flush_cache(struct kgsl_file_private *private,
+				       void __user *arg)
+{
+	int result = 0;
+	struct kgsl_mem_entry *entry;
+	struct kgsl_sharedmem_free param;
+
+	if (copy_from_user(&param, arg, sizeof(param))) {
+		result = -EFAULT;
+		goto done;
+	}
+
+	entry = kgsl_sharedmem_find(private, param.gpuaddr);
+	if (!entry) {
+		KGSL_DRV_ERR("invalid gpuaddr %08x\n", param.gpuaddr);
+		result = -EINVAL;
+		goto done;
+	}
+	result = flush_l1_cache_range((unsigned long)entry->memdesc.hostptr,
+				      entry->memdesc.size);
+	/* Mark memory as being flushed so we don't flush it again */
+	entry->memdesc.priv &= ~KGSL_MEMFLAGS_MEM_REQUIRES_FLUSH;
+done:
+	return result;
+}
+#else
+static int kgsl_ioctl_sharedmem_flush_cache(struct kgsl_file_private *private,
+					    void __user *arg)
+{
+	return -ENOSYS;
+}
+#endif
+
+
+static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+	int result = 0;
+	struct kgsl_file_private *private = filep->private_data;
+	struct kgsl_drawctxt_set_bin_base_offset binbase;
+
+	BUG_ON(private == NULL);
+
+	KGSL_DRV_VDBG("filep %p cmd 0x%08x arg 0x%08lx\n", filep, cmd, arg);
+
+	mutex_lock(&kgsl_driver.mutex);
+
+	kgsl_hw_get_locked();
+
+	switch (cmd) {
+
+	case IOCTL_KGSL_DEVICE_GETPROPERTY:
+		result =
+		    kgsl_ioctl_device_getproperty(private, (void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_DEVICE_REGREAD:
+		result = kgsl_ioctl_device_regread(private, (void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_DEVICE_WAITTIMESTAMP:
+		result = kgsl_ioctl_device_waittimestamp(private,
+							(void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS:
+		if (kgsl_cache_enable)
+			flush_l1_cache_all(private);
+		result = kgsl_ioctl_rb_issueibcmds(private, (void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_CMDSTREAM_READTIMESTAMP:
+		result =
+		    kgsl_ioctl_cmdstream_readtimestamp(private,
+							(void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP:
+		result =
+		    kgsl_ioctl_cmdstream_freememontimestamp(private,
+						    (void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_DRAWCTXT_CREATE:
+		result = kgsl_ioctl_drawctxt_create(private,
+							(void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_DRAWCTXT_DESTROY:
+		result =
+		    kgsl_ioctl_drawctxt_destroy(private, (void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_SHAREDMEM_FREE:
+		result = kgsl_ioctl_sharedmem_free(private, (void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC:
+		kgsl_yamato_runpending(&kgsl_driver.yamato_device);
+		result = kgsl_ioctl_sharedmem_from_vmalloc(private,
+							   (void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE:
+		if (kgsl_cache_enable)
+			result = kgsl_ioctl_sharedmem_flush_cache(private,
+						       (void __user *)arg);
+		break;
+	case IOCTL_KGSL_SHAREDMEM_FROM_PMEM:
+		kgsl_yamato_runpending(&kgsl_driver.yamato_device);
+		result = kgsl_ioctl_sharedmem_from_pmem(private,
+							(void __user *)arg);
+		break;
+
+	case IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET:
+		if (copy_from_user(&binbase, (void __user *)arg,
+				   sizeof(binbase))) {
+			result = -EFAULT;
+			break;
+		}
+
+		if (private->ctxt_id_mask & (1 << binbase.drawctxt_id)) {
+			result = kgsl_drawctxt_set_bin_base_offset(
+					&kgsl_driver.yamato_device,
+					binbase.drawctxt_id,
+					binbase.offset);
+		} else {
+			result = -EINVAL;
+			KGSL_DRV_ERR("invalid drawctxt drawctxt_id %d\n",
+				     binbase.drawctxt_id);
+		}
+		break;
+
+	default:
+		KGSL_DRV_ERR("invalid ioctl code %08x\n", cmd);
+		result = -EINVAL;
+		break;
+	}
+
+	kgsl_hw_put_locked(true);
+	mutex_unlock(&kgsl_driver.mutex);
+	KGSL_DRV_VDBG("result %d\n", result);
+	return result;
+}
+
+static struct file_operations kgsl_fops = {
+	.owner = THIS_MODULE,
+	.release = kgsl_release,
+	.open = kgsl_open,
+	.unlocked_ioctl = kgsl_ioctl,
+};
+
+
+struct kgsl_driver kgsl_driver = {
+	.misc = {
+		 .name = DRIVER_NAME,
+		 .minor = MISC_DYNAMIC_MINOR,
+		 .fops = &kgsl_fops,
+	 },
+	.open_count = ATOMIC_INIT(0),
+	.mutex = __MUTEX_INITIALIZER(kgsl_driver.mutex),
+};
+
+static void kgsl_driver_cleanup(void)
+{
+
+	wake_lock_destroy(&kgsl_driver.wake_lock);
+
+	if (kgsl_driver.interrupt_num > 0) {
+		if (kgsl_driver.have_irq) {
+			free_irq(kgsl_driver.interrupt_num, NULL);
+			kgsl_driver.have_irq = 0;
+		}
+		kgsl_driver.interrupt_num = 0;
+	}
+
+	if (kgsl_driver.grp_clk) {
+		clk_put(kgsl_driver.grp_clk);
+		kgsl_driver.grp_clk = NULL;
+	}
+
+	if (kgsl_driver.imem_clk != NULL) {
+		clk_put(kgsl_driver.imem_clk);
+		kgsl_driver.imem_clk = NULL;
+	}
+
+	if (kgsl_driver.ebi1_clk != NULL) {
+		clk_put(kgsl_driver.ebi1_clk);
+		kgsl_driver.ebi1_clk = NULL;
+	}
+
+	kgsl_driver.pdev = NULL;
+
+}
+
+
+static int __devinit kgsl_platform_probe(struct platform_device *pdev)
+{
+	int result = 0;
+	struct clk *clk;
+	struct resource *res = NULL;
+
+	kgsl_debug_init();
+
+	INIT_LIST_HEAD(&kgsl_driver.client_list);
+
+	/*acquire clocks */
+	BUG_ON(kgsl_driver.grp_clk != NULL);
+	BUG_ON(kgsl_driver.imem_clk != NULL);
+	BUG_ON(kgsl_driver.ebi1_clk != NULL);
+
+	kgsl_driver.pdev = pdev;
+
+	setup_timer(&kgsl_driver.standby_timer, kgsl_do_standby_timer, 0);
+	wake_lock_init(&kgsl_driver.wake_lock, WAKE_LOCK_SUSPEND, "kgsl");
+
+	clk = clk_get(&pdev->dev, "grp_clk");
+	if (IS_ERR(clk)) {
+		result = PTR_ERR(clk);
+		KGSL_DRV_ERR("clk_get(grp_clk) returned %d\n", result);
+		goto done;
+	}
+	kgsl_driver.grp_clk = clk;
+
+	clk = clk_get(&pdev->dev, "grp_pclk");
+	if (IS_ERR(clk)) {
+		KGSL_DRV_ERR("no grp_pclk, continuing\n");
+		clk = NULL;
+	}
+	kgsl_driver.grp_pclk = clk;
+
+	clk = clk_get(&pdev->dev, "imem_clk");
+	if (IS_ERR(clk)) {
+		result = PTR_ERR(clk);
+		KGSL_DRV_ERR("clk_get(imem_clk) returned %d\n", result);
+		goto done;
+	}
+	kgsl_driver.imem_clk = clk;
+
+	clk = clk_get(&pdev->dev, "ebi1_clk");
+	if (IS_ERR(clk)) {
+		result = PTR_ERR(clk);
+		KGSL_DRV_ERR("clk_get(ebi1_clk) returned %d\n", result);
+		goto done;
+	}
+	kgsl_driver.ebi1_clk = clk;
+
+	/*acquire interrupt */
+	kgsl_driver.interrupt_num = platform_get_irq(pdev, 0);
+	if (kgsl_driver.interrupt_num <= 0) {
+		KGSL_DRV_ERR("platform_get_irq() returned %d\n",
+			       kgsl_driver.interrupt_num);
+		result = -EINVAL;
+		goto done;
+	}
+
+	result = request_irq(kgsl_driver.interrupt_num, kgsl_yamato_isr,
+				IRQF_TRIGGER_HIGH, DRIVER_NAME, NULL);
+	if (result) {
+		KGSL_DRV_ERR("request_irq(%d) returned %d\n",
+			      kgsl_driver.interrupt_num, result);
+		goto done;
+	}
+	kgsl_driver.have_irq = 1;
+	disable_irq(kgsl_driver.interrupt_num);
+
+	result = kgsl_yamato_config(&kgsl_driver.yamato_config, pdev);
+	if (result != 0)
+		goto done;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   "kgsl_phys_memory");
+	if (res == NULL) {
+		result = -EINVAL;
+		goto done;
+	}
+
+	kgsl_driver.shmem.physbase = res->start;
+	kgsl_driver.shmem.size = resource_size(res);
+
+done:
+	if (result)
+		kgsl_driver_cleanup();
+	else
+		result = misc_register(&kgsl_driver.misc);
+
+	return result;
+}
+
+static int kgsl_platform_remove(struct platform_device *pdev)
+{
+
+	kgsl_driver_cleanup();
+	misc_deregister(&kgsl_driver.misc);
+
+	return 0;
+}
+
+static int kgsl_platform_suspend(struct platform_device *pdev,
+				 pm_message_t state)
+{
+	mutex_lock(&kgsl_driver.mutex);
+	if (atomic_read(&kgsl_driver.open_count) > 0) {
+		if (kgsl_driver.active)
+			pr_err("%s: Suspending while active???\n", __func__);
+	}
+	mutex_unlock(&kgsl_driver.mutex);
+	return 0;
+}
+
+static struct platform_driver kgsl_platform_driver = {
+	.probe = kgsl_platform_probe,
+	.remove = __devexit_p(kgsl_platform_remove),
+	.suspend = kgsl_platform_suspend,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DRIVER_NAME
+	}
+};
+
+static int __init kgsl_mod_init(void)
+{
+	return platform_driver_register(&kgsl_platform_driver);
+}
+
+static void __exit kgsl_mod_exit(void)
+{
+	platform_driver_unregister(&kgsl_platform_driver);
+}
+
+module_init(kgsl_mod_init);
+module_exit(kgsl_mod_exit);
+
+MODULE_AUTHOR("QUALCOMM");
+MODULE_DESCRIPTION("3D graphics driver for QSD8x50 and MSM7x27");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:kgsl");
diff --git a/drivers/video/msm/gpu/kgsl/kgsl.h b/drivers/video/msm/gpu/kgsl/kgsl.h
new file mode 100644
index 0000000..e9f0d7c
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl.h
@@ -0,0 +1,84 @@
+/*
+* Copyright (c) 2008-2009 QUALCOMM USA, INC.
+* 
+* All source code in this file is licensed under the following license
+* 
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+* 
+* This 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.
+* 
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, you can find it at http://www.fsf.org
+*/
+#ifndef _GSL_DRIVER_H
+#define _GSL_DRIVER_H
+
+#include <linux/types.h>
+#include <linux/msm_kgsl.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/wakelock.h>
+
+#include <asm/atomic.h>
+
+#include "kgsl_device.h"
+#include "kgsl_sharedmem.h"
+
+#define DRIVER_NAME "kgsl"
+
+struct kgsl_driver {
+	struct miscdevice misc;
+	struct platform_device *pdev;
+	atomic_t open_count;
+	struct mutex mutex;
+
+	int interrupt_num;
+	int have_irq;
+
+	struct clk *grp_clk;
+	struct clk *grp_pclk;
+	struct clk *imem_clk;
+	struct clk *ebi1_clk;
+
+	struct kgsl_devconfig yamato_config;
+
+	uint32_t flags_debug;
+
+	struct kgsl_sharedmem shmem;
+	struct kgsl_device yamato_device;
+
+	struct list_head client_list;
+
+	bool active;
+	int active_cnt;
+	struct timer_list standby_timer;
+
+	struct wake_lock wake_lock;
+};
+
+extern struct kgsl_driver kgsl_driver;
+
+struct kgsl_mem_entry {
+	struct kgsl_memdesc memdesc;
+	struct file *pmem_file;
+	struct list_head list;
+	struct list_head free_list;
+	uint32_t free_timestamp;
+
+	/* back pointer to private structure under whose context this
+	 * allocation is made */
+	struct kgsl_file_private *priv;
+};
+
+void kgsl_remove_mem_entry(struct kgsl_mem_entry *entry);
+
+#endif /* _GSL_DRIVER_H */
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_cmdstream.c b/drivers/video/msm/gpu/kgsl/kgsl_cmdstream.c
new file mode 100644
index 0000000..9b7183c
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_cmdstream.c
@@ -0,0 +1,103 @@
+/*
+* Copyright (c) 2008-2009 QUALCOMM USA, INC.
+* 
+* All source code in this file is licensed under the following license
+* 
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+* 
+* This 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.
+* 
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, you can find it at http://www.fsf.org
+*/
+
+#include "kgsl.h"
+#include "kgsl_device.h"
+#include "kgsl_cmdstream.h"
+#include "kgsl_sharedmem.h"
+
+int kgsl_cmdstream_init(struct kgsl_device *device)
+{
+	return 0;
+}
+
+int kgsl_cmdstream_close(struct kgsl_device *device)
+{
+	return 0;
+}
+
+uint32_t
+kgsl_cmdstream_readtimestamp(struct kgsl_device *device,
+			     enum kgsl_timestamp_type type)
+{
+	uint32_t timestamp = 0;
+
+	KGSL_CMD_VDBG("enter (device_id=%d, type=%d)\n", device->id, type);
+
+	if (type == KGSL_TIMESTAMP_CONSUMED)
+		KGSL_CMDSTREAM_GET_SOP_TIMESTAMP(device,
+						 (unsigned int *)&timestamp);
+	else if (type == KGSL_TIMESTAMP_RETIRED)
+		KGSL_CMDSTREAM_GET_EOP_TIMESTAMP(device,
+						 (unsigned int *)&timestamp);
+
+	KGSL_CMD_VDBG("return %d\n", timestamp);
+
+	return timestamp;
+}
+
+int kgsl_cmdstream_check_timestamp(struct kgsl_device *device,
+				   unsigned int timestamp)
+{
+	unsigned int ts_processed;
+
+	ts_processed = kgsl_cmdstream_readtimestamp(device,
+						    KGSL_TIMESTAMP_RETIRED);
+	return timestamp_cmp(ts_processed, timestamp);
+}
+
+void kgsl_cmdstream_memqueue_drain(struct kgsl_device *device)
+{
+	struct kgsl_mem_entry *entry, *entry_tmp;
+	uint32_t ts_processed;
+	struct kgsl_ringbuffer *rb = &device->ringbuffer;
+
+	/* get current EOP timestamp */
+	ts_processed =
+	    kgsl_cmdstream_readtimestamp(device, KGSL_TIMESTAMP_RETIRED);
+
+	list_for_each_entry_safe(entry, entry_tmp, &rb->memqueue, free_list) {
+		/*NOTE: this assumes that the free list is sorted by
+		 * timestamp, but I'm not yet sure that it is a valid
+		 * assumption
+		 */
+		if (!timestamp_cmp(ts_processed, entry->free_timestamp))
+			break;
+		KGSL_MEM_DBG("ts_processed %d ts_free %d gpuaddr %x)\n",
+			     ts_processed, entry->free_timestamp,
+			     entry->memdesc.gpuaddr);
+		kgsl_remove_mem_entry(entry);
+	}
+}
+
+int
+kgsl_cmdstream_freememontimestamp(struct kgsl_device *device,
+				  struct kgsl_mem_entry *entry,
+				  uint32_t timestamp,
+				  enum kgsl_timestamp_type type)
+{
+	struct kgsl_ringbuffer *rb = &device->ringbuffer;
+	KGSL_MEM_DBG("enter (dev %p gpuaddr %x ts %d)\n",
+		     device, entry->memdesc.gpuaddr, timestamp);
+	(void)type;		/* unref. For now just use EOP timestamp */
+
+	list_add_tail(&entry->free_list, &rb->memqueue);
+	entry->free_timestamp = timestamp;
+
+	return 0;
+}
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_cmdstream.h b/drivers/video/msm/gpu/kgsl/kgsl_cmdstream.h
new file mode 100644
index 0000000..f81ef54
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_cmdstream.h
@@ -0,0 +1,54 @@
+#ifndef __KGSL_CMDSTREAM_H
+#define __KGSL_CMDSTREAM_H
+
+#include <linux/msm_kgsl.h>
+#include "kgsl_device.h"
+#include "kgsl_log.h"
+
+#ifdef KGSL_DEVICE_SHADOW_MEMSTORE_TO_USER
+#define KGSL_CMDSTREAM_USE_MEM_TIMESTAMP
+#endif /* KGSL_DEVICE_SHADOW_MEMSTORE_TO_USER */
+
+#ifdef KGSL_CMDSTREAM_USE_MEM_TIMESTAMP
+#define KGSL_CMDSTREAM_GET_SOP_TIMESTAMP(device, data) 	\
+		kgsl_sharedmem_read(&device->memstore, (data),	\
+				KGSL_DEVICE_MEMSTORE_OFFSET(soptimestamp), 4)
+#else
+#define KGSL_CMDSTREAM_GET_SOP_TIMESTAMP(device, data)	\
+		kgsl_yamato_regread(device, REG_CP_TIMESTAMP, (data))
+#endif /* KGSL_CMDSTREAM_USE_MEM_TIMESTAMP */
+
+#define KGSL_CMDSTREAM_GET_EOP_TIMESTAMP(device, data)	\
+		kgsl_sharedmem_read(&device->memstore, (data),	\
+				KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp), 4)
+
+/* Flags to control command packet settings */
+#define KGSL_CMD_FLAGS_PMODE			0x00000001
+#define KGSL_CMD_FLAGS_NO_TS_CMP		0x00000002
+
+int kgsl_cmdstream_init(struct kgsl_device *device);
+
+int kgsl_cmdstream_close(struct kgsl_device *device);
+
+void kgsl_cmdstream_memqueue_drain(struct kgsl_device *device);
+
+uint32_t
+kgsl_cmdstream_readtimestamp(struct kgsl_device *device,
+			     enum kgsl_timestamp_type type);
+
+int kgsl_cmdstream_check_timestamp(struct kgsl_device *device,
+				   unsigned int timestamp);
+
+int
+kgsl_cmdstream_freememontimestamp(struct kgsl_device *device,
+				  struct kgsl_mem_entry *entry,
+				  uint32_t timestamp,
+				  enum kgsl_timestamp_type type);
+
+static inline bool timestamp_cmp(unsigned int new, unsigned int old)
+{
+	int ts_diff = new - old;
+	return (ts_diff >= 0) || (ts_diff < -20000);
+}
+
+#endif /* __KGSL_CMDSTREAM_H */
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_device.h b/drivers/video/msm/gpu/kgsl/kgsl_device.h
new file mode 100644
index 0000000..dcbf4db
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_device.h
@@ -0,0 +1,141 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#ifndef _KGSL_DEVICE_H
+#define _KGSL_DEVICE_H
+
+#include <asm/atomic.h>
+
+#include <linux/types.h>
+#include <linux/irqreturn.h>
+#include <linux/wait.h>
+#include <linux/msm_kgsl.h>
+
+#include "kgsl_drawctxt.h"
+#include "kgsl_mmu.h"
+#include "kgsl_ringbuffer.h"
+
+#define KGSL_CONTEXT_MAX        8
+
+#define KGSL_TIMEOUT_NONE       0
+#define KGSL_TIMEOUT_DEFAULT    0xFFFFFFFF
+
+#define KGSL_DEV_FLAGS_INITIALIZED0	0x00000001
+#define KGSL_DEV_FLAGS_INITIALIZED	0x00000002
+#define KGSL_DEV_FLAGS_STARTED		0x00000004
+#define KGSL_DEV_FLAGS_ACTIVE		0x00000008
+
+#define KGSL_CHIPID_YAMATODX_REV21  0x20100
+#define KGSL_CHIPID_YAMATODX_REV211 0x20101
+
+/* Private memory flags for use with memdesc->priv feild */
+#define KGSL_MEMFLAGS_MEM_REQUIRES_FLUSH    0x00000001
+#define KGSL_MEMFLAGS_VMALLOC_MEM           0x00000002
+
+#define KGSL_GRAPHICS_MEMORY_LOW_WATERMARK  0x1000000
+#define KGSL_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK)))
+
+struct kgsl_device;
+struct platform_device;
+
+
+struct kgsl_memregion {
+	unsigned char  *mmio_virt_base;
+	unsigned int   mmio_phys_base;
+	uint32_t      gpu_base;
+	unsigned int   sizebytes;
+};
+
+struct kgsl_device {
+
+	unsigned int	  refcnt;
+	uint32_t       flags;
+	enum kgsl_deviceid    id;
+	unsigned int      chip_id;
+	struct kgsl_memregion regspace;
+	struct kgsl_memdesc memstore;
+
+	struct kgsl_mmu 	  mmu;
+	struct kgsl_memregion gmemspace;
+	struct kgsl_ringbuffer ringbuffer;
+	unsigned int      drawctxt_count;
+	struct kgsl_drawctxt *drawctxt_active;
+	struct kgsl_drawctxt drawctxt[KGSL_CONTEXT_MAX];
+
+	wait_queue_head_t ib1_wq;
+};
+
+struct kgsl_devconfig {
+	struct kgsl_memregion regspace;
+
+	unsigned int     mmu_config;
+	uint32_t        mpu_base;
+	int              mpu_range;
+	uint32_t        va_base;
+	unsigned int     va_range;
+
+	struct kgsl_memregion gmemspace;
+};
+
+int kgsl_yamato_start(struct kgsl_device *device, uint32_t flags);
+
+int kgsl_yamato_stop(struct kgsl_device *device);
+
+bool kgsl_yamato_is_idle(struct kgsl_device *device);
+
+int kgsl_yamato_idle(struct kgsl_device *device, unsigned int timeout);
+
+int kgsl_yamato_getproperty(struct kgsl_device *device,
+				enum kgsl_property_type type, void *value,
+				unsigned int sizebytes);
+
+int kgsl_yamato_regread(struct kgsl_device *device, unsigned int offsetwords,
+				unsigned int *value);
+
+int kgsl_yamato_regwrite(struct kgsl_device *device, unsigned int offsetwords,
+				unsigned int value);
+
+int kgsl_yamato_waittimestamp(struct kgsl_device *device,
+				unsigned int timestamp, unsigned int timeout);
+
+
+int kgsl_yamato_init(struct kgsl_device *, struct kgsl_devconfig *);
+
+int kgsl_yamato_close(struct kgsl_device *device);
+
+int kgsl_yamato_runpending(struct kgsl_device *device);
+
+int __init kgsl_yamato_config(struct kgsl_devconfig *,
+				struct platform_device *pdev);
+
+void kgsl_register_dump(struct kgsl_device *device);
+
+int kgsl_yamato_setup_pt(struct kgsl_device *device,
+			 struct kgsl_pagetable *pagetable);
+int kgsl_yamato_cleanup_pt(struct kgsl_device *device,
+			   struct kgsl_pagetable *pagetable);
+#ifdef CONFIG_MSM_KGSL_MMU
+int kgsl_yamato_setstate(struct kgsl_device *device, uint32_t flags);
+#else
+static inline int kgsl_yamato_setstate(struct kgsl_device *device, uint32_t flags)
+{ return 0; }
+#endif
+
+irqreturn_t kgsl_yamato_isr(int irq, void *data);
+
+#endif  /* _KGSL_DEVICE_H */
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_drawctxt.c b/drivers/video/msm/gpu/kgsl/kgsl_drawctxt.c
new file mode 100644
index 0000000..3e5262e
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_drawctxt.c
@@ -0,0 +1,1823 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/msm_kgsl.h>
+
+#include "kgsl_drawctxt.h"
+
+#include "yamato_reg.h"
+#include "kgsl.h"
+#include "kgsl_log.h"
+#include "kgsl_pm4types.h"
+#include "kgsl_cmdstream.h"
+
+/*
+*
+*  Memory Map for Register, Constant & Instruction Shadow, and Command Buffers
+*  (34.5KB)
+*
+*  +---------------------+------------+-------------+---+---------------------+
+*  | ALU Constant Shadow | Reg Shadow | C&V Buffers |Tex| Shader Instr Shadow |
+*  +---------------------+------------+-------------+---+---------------------+
+*    ________________________________/               \____________________
+*   /                                                                     |
+*  +--------------+-----------+------+-----------+------------------------+
+*  | Restore Regs | Save Regs | Quad | Gmem Save | Gmem Restore | unused  |
+*  +--------------+-----------+------+-----------+------------------------+
+*
+* 		 8K - ALU Constant Shadow (8K aligned)
+* 		 4K - H/W Register Shadow (8K aligned)
+* 		 4K - Command and Vertex Buffers
+* 				- Indirect command buffer : Const/Reg restore
+* 					- includes Loop & Bool const shadows
+* 				- Indirect command buffer : Const/Reg save
+* 				- Quad vertices & texture coordinates
+* 				- Indirect command buffer : Gmem save
+* 				- Indirect command buffer : Gmem restore
+* 				- Unused (padding to 8KB boundary)
+* 		<1K - Texture Constant Shadow (768 bytes) (8K aligned)
+*       18K - Shader Instruction Shadow
+*               - 6K vertex (32 byte aligned)
+*               - 6K pixel  (32 byte aligned)
+*               - 6K shared (32 byte aligned)
+*
+*  Note: Reading constants into a shadow, one at a time using REG_TO_MEM, takes
+*  3 DWORDS per DWORD transfered, plus 1 DWORD for the shadow, for a total of
+*  16 bytes per constant.  If the texture constants were transfered this way,
+*  the Command & Vertex Buffers section would extend past the 16K boundary.
+*  By moving the texture constant shadow area to start at 16KB boundary, we
+*  only require approximately 40 bytes more memory, but are able to use the
+*  LOAD_CONSTANT_CONTEXT shadowing feature for the textures, speeding up
+*  context switching.
+*
+*  [Using LOAD_CONSTANT_CONTEXT shadowing feature for the Loop and/or Bool
+*  constants would require an additional 8KB each, for alignment.]
+*
+*/
+
+/* Constants */
+
+#define ALU_CONSTANTS	2048	/* DWORDS */
+#define NUM_REGISTERS	1024	/* DWORDS */
+#ifdef DISABLE_SHADOW_WRITES
+#define CMD_BUFFER_LEN  9216	/* DWORDS */
+#else
+#define CMD_BUFFER_LEN	3072	/* DWORDS */
+#endif
+#define TEX_CONSTANTS		(32*6)	/* DWORDS */
+#define BOOL_CONSTANTS		8	/* DWORDS */
+#define LOOP_CONSTANTS		56	/* DWORDS */
+#define SHADER_INSTRUCT_LOG2	9U	/* 2^n == SHADER_INSTRUCTIONS */
+
+#if defined(PM4_IM_STORE)
+/* 96-bit instructions */
+#define SHADER_INSTRUCT		(1<<SHADER_INSTRUCT_LOG2)
+#else
+#define SHADER_INSTRUCT		0
+#endif
+
+/* LOAD_CONSTANT_CONTEXT shadow size */
+#define LCC_SHADOW_SIZE		0x2000	/* 8KB */
+
+#define ALU_SHADOW_SIZE		LCC_SHADOW_SIZE	/* 8KB */
+#define REG_SHADOW_SIZE		0x1000	/* 4KB */
+#ifdef DISABLE_SHADOW_WRITES
+#define CMD_BUFFER_SIZE     0x9000	/* 36KB */
+#else
+#define CMD_BUFFER_SIZE		0x3000	/* 12KB */
+#endif
+#define TEX_SHADOW_SIZE		(TEX_CONSTANTS*4)	/* 768 bytes */
+#define SHADER_SHADOW_SIZE      (SHADER_INSTRUCT*12)	/* 6KB */
+
+#define REG_OFFSET		LCC_SHADOW_SIZE
+#define CMD_OFFSET		(REG_OFFSET + REG_SHADOW_SIZE)
+#define TEX_OFFSET		(CMD_OFFSET + CMD_BUFFER_SIZE)
+#define	SHADER_OFFSET		((TEX_OFFSET + TEX_SHADOW_SIZE + 32) & ~31)
+
+#define CONTEXT_SIZE		(SHADER_OFFSET + 3 * SHADER_SHADOW_SIZE)
+
+
+
+/* temporary work structure */
+struct tmp_ctx {
+	unsigned int *start;	/* Command & Vertex buffer start */
+	unsigned int *cmd;	/* Next available dword in C&V buffer */
+
+	/* address of buffers, needed when creating IB1 command buffers. */
+	uint32_t bool_shadow;	/* bool constants */
+	uint32_t loop_shadow;	/* loop constants */
+
+#if defined(PM4_IM_STORE)
+	uint32_t shader_shared;	/* shared shader instruction shadow */
+	uint32_t shader_vertex;	/* vertex shader instruction shadow */
+	uint32_t shader_pixel;	/* pixel shader instruction shadow */
+#endif
+
+	/* Addresses in command buffer where separately handled registers
+	 * are saved
+	 */
+	uint32_t reg_values[4];
+	uint32_t chicken_restore;
+
+	uint32_t gmem_base;	/* Base gpu address of GMEM */
+
+};
+
+/* Helper function to calculate IEEE754 single precision float values
+*  without FPU
+*/
+unsigned int uint2float(unsigned int uintval)
+{
+	unsigned int exp = 0;
+	unsigned int frac = 0;
+	unsigned int u = uintval;
+
+	/* Handle zero separately */
+	if (uintval == 0)
+		return 0;
+	/* Find log2 of u */
+	if (u >= 0x10000) {
+		exp += 16;
+		u >>= 16;
+	}
+	if (u >= 0x100) {
+		exp += 8;
+		u >>= 8;
+	}
+	if (u >= 0x10) {
+		exp += 4;
+		u >>= 4;
+	}
+	if (u >= 0x4) {
+		exp += 2;
+		u >>= 2;
+	}
+	if (u >= 0x2) {
+		exp += 1;
+		u >>= 1;
+	}
+
+	/* Calculate fraction */
+	frac = (uintval & (~(1 << exp))) << (23 - exp);
+
+	/* Exp is biased by 127 and shifted 23 bits */
+	exp = (exp + 127) << 23;
+
+	return exp | frac;
+}
+
+/* context save (gmem -> sys) */
+
+/* pre-compiled vertex shader program
+*
+*  attribute vec4  P;
+*  void main(void)
+*  {
+*    gl_Position = P;
+*  }
+*/
+#define GMEM2SYS_VTX_PGM_LEN	0x12
+
+static unsigned int gmem2sys_vtx_pgm[GMEM2SYS_VTX_PGM_LEN] = {
+	0x00011003, 0x00001000, 0xc2000000,
+	0x00001004, 0x00001000, 0xc4000000,
+	0x00001005, 0x00002000, 0x00000000,
+	0x1cb81000, 0x00398a88, 0x00000003,
+	0x140f803e, 0x00000000, 0xe2010100,
+	0x14000000, 0x00000000, 0xe2000000
+};
+
+/* pre-compiled fragment shader program
+*
+*  precision highp float;
+*  uniform   vec4  clear_color;
+*  void main(void)
+*  {
+*     gl_FragColor = clear_color;
+*  }
+*/
+
+#define GMEM2SYS_FRAG_PGM_LEN	0x0c
+
+static unsigned int gmem2sys_frag_pgm[GMEM2SYS_FRAG_PGM_LEN] = {
+	0x00000000, 0x1002c400, 0x10000000,
+	0x00001003, 0x00002000, 0x00000000,
+	0x140f8000, 0x00000000, 0x22000000,
+	0x14000000, 0x00000000, 0xe2000000
+};
+
+/* context restore (sys -> gmem) */
+/* pre-compiled vertex shader program
+*
+*  attribute vec4 position;
+*  attribute vec4 texcoord;
+*  varying   vec4 texcoord0;
+*  void main()
+*  {
+*     gl_Position = position;
+*     texcoord0 = texcoord;
+*  }
+*/
+
+#define SYS2GMEM_VTX_PGM_LEN	0x18
+
+static unsigned int sys2gmem_vtx_pgm[SYS2GMEM_VTX_PGM_LEN] = {
+	0x00052003, 0x00001000, 0xc2000000, 0x00001005,
+	0x00001000, 0xc4000000, 0x00001006, 0x10071000,
+	0x20000000, 0x18981000, 0x0039ba88, 0x00000003,
+	0x12982000, 0x40257b08, 0x00000002, 0x140f803e,
+	0x00000000, 0xe2010100, 0x140f8000, 0x00000000,
+	0xe2020200, 0x14000000, 0x00000000, 0xe2000000
+};
+
+/* pre-compiled fragment shader program
+*
+*  precision mediump   float;
+*  uniform   sampler2D tex0;
+*  varying   vec4      texcoord0;
+*  void main()
+*  {
+*     gl_FragColor = texture2D(tex0, texcoord0.xy);
+*  }
+*/
+
+#define SYS2GMEM_FRAG_PGM_LEN	0x0f
+
+static unsigned int sys2gmem_frag_pgm[SYS2GMEM_FRAG_PGM_LEN] = {
+	0x00011002, 0x00001000, 0xc4000000, 0x00001003,
+	0x10041000, 0x20000000, 0x10000001, 0x1ffff688,
+	0x00000002, 0x140f8000, 0x00000000, 0xe2000000,
+	0x14000000, 0x00000000, 0xe2000000
+};
+
+/* shader texture constants (sysmem -> gmem)  */
+#define SYS2GMEM_TEX_CONST_LEN	6
+
+static unsigned int sys2gmem_tex_const[SYS2GMEM_TEX_CONST_LEN] = {
+	/* Texture, FormatXYZW=Unsigned, ClampXYZ=Wrap/Repeat,
+	 * RFMode=ZeroClamp-1, Dim=1:2d
+	 */
+	0x00000002,		/* Pitch = TBD */
+
+	/* Format=6:8888_WZYX, EndianSwap=0:None, ReqSize=0:256bit, DimHi=0,
+	 * NearestClamp=1:OGL Mode
+	 */
+	0x00000800,		/* Address[31:12] = TBD */
+
+	/* Width, Height, EndianSwap=0:None */
+	0,			/* Width & Height = TBD */
+
+	/* NumFormat=0:RF, DstSelXYZW=XYZW, ExpAdj=0, MagFilt=MinFilt=0:Point,
+	 * Mip=2:BaseMap
+	 */
+	0 << 1 | 1 << 4 | 2 << 7 | 3 << 10 | 2 << 23,
+
+	/* VolMag=VolMin=0:Point, MinMipLvl=0, MaxMipLvl=1, LodBiasH=V=0,
+	 * Dim3d=0
+	 */
+	0,
+
+	/* BorderColor=0:ABGRBlack, ForceBC=0:diable, TriJuice=0, Aniso=0,
+	 * Dim=1:2d, MipPacking=0
+	 */
+	1 << 9			/* Mip Address[31:12] = TBD */
+};
+
+/* quad for copying GMEM to context shadow */
+#define QUAD_LEN				12
+
+static unsigned int gmem_copy_quad[QUAD_LEN] = {
+	0x00000000, 0x00000000, 0x3f800000,
+	0x00000000, 0x00000000, 0x3f800000,
+	0x00000000, 0x00000000, 0x3f800000,
+	0x00000000, 0x00000000, 0x3f800000
+};
+
+#define TEXCOORD_LEN			8
+
+static unsigned int gmem_copy_texcoord[TEXCOORD_LEN] = {
+	0x00000000, 0x3f800000,
+	0x3f800000, 0x3f800000,
+	0x00000000, 0x00000000,
+	0x3f800000, 0x00000000
+};
+
+#define NUM_COLOR_FORMATS   13
+
+static enum SURFACEFORMAT surface_format_table[NUM_COLOR_FORMATS] = {
+	FMT_4_4_4_4,		/* COLORX_4_4_4_4 */
+	FMT_1_5_5_5,		/* COLORX_1_5_5_5 */
+	FMT_5_6_5,		/* COLORX_5_6_5 */
+	FMT_8,			/* COLORX_8 */
+	FMT_8_8,		/* COLORX_8_8 */
+	FMT_8_8_8_8,		/* COLORX_8_8_8_8 */
+	FMT_8_8_8_8,		/* COLORX_S8_8_8_8 */
+	FMT_16_FLOAT,		/* COLORX_16_FLOAT */
+	FMT_16_16_FLOAT,	/* COLORX_16_16_FLOAT */
+	FMT_16_16_16_16_FLOAT,	/* COLORX_16_16_16_16_FLOAT */
+	FMT_32_FLOAT,		/* COLORX_32_FLOAT */
+	FMT_32_32_FLOAT,	/* COLORX_32_32_FLOAT */
+	FMT_32_32_32_32_FLOAT,	/* COLORX_32_32_32_32_FLOAT */
+};
+
+static unsigned int format2bytesperpixel[NUM_COLOR_FORMATS] = {
+	2,			/* COLORX_4_4_4_4 */
+	2,			/* COLORX_1_5_5_5 */
+	2,			/* COLORX_5_6_5 */
+	1,			/* COLORX_8 */
+	2,			/* COLORX_8_8 8*/
+	4,			/* COLORX_8_8_8_8 */
+	4,			/* COLORX_S8_8_8_8 */
+	2,			/* COLORX_16_FLOAT */
+	4,			/* COLORX_16_16_FLOAT */
+	8,			/* COLORX_16_16_16_16_FLOAT */
+	4,			/* COLORX_32_FLOAT */
+	8,			/* COLORX_32_32_FLOAT */
+	16,			/* COLORX_32_32_32_32_FLOAT */
+};
+
+/* shader linkage info */
+#define SHADER_CONST_ADDR	(11 * 6 + 3)
+
+/* gmem command buffer length */
+#define PM4_REG(reg)		((0x4 << 16) | (GSL_HAL_SUBBLOCK_OFFSET(reg)))
+
+/* functions */
+static void config_gmemsize(struct gmem_shadow_t *shadow, int gmem_size)
+{
+	int w = 64, h = 64;	/* 16KB surface, minimum */
+
+	shadow->format = COLORX_8_8_8_8;
+	/* convert from bytes to 32-bit words */
+	gmem_size = (gmem_size + 3) / 4;
+
+	/* find the right surface size, close to a square. */
+	while (w * h < gmem_size)
+		if (w < h)
+			w *= 2;
+		else
+			h *= 2;
+
+	shadow->width = w;
+	shadow->pitch = w;
+	shadow->height = h;
+	shadow->gmem_pitch = shadow->pitch;
+
+	shadow->size = shadow->pitch * shadow->height * 4;
+}
+
+static unsigned int gpuaddr(unsigned int *cmd, struct kgsl_memdesc *memdesc)
+{
+	return memdesc->gpuaddr + ((char *)cmd - (char *)memdesc->hostptr);
+}
+
+static void
+create_ib1(struct kgsl_drawctxt *drawctxt, unsigned int *cmd,
+	   unsigned int *start, unsigned int *end)
+{
+	cmd[0] = PM4_HDR_INDIRECT_BUFFER_PFD;
+	cmd[1] = gpuaddr(start, &drawctxt->gpustate);
+	cmd[2] = end - start;
+}
+
+static unsigned int *program_shader(unsigned int *cmds, int vtxfrag,
+				    unsigned int *shader_pgm, int dwords)
+{
+	/* load the patched vertex shader stream */
+	*cmds++ = pm4_type3_packet(PM4_IM_LOAD_IMMEDIATE, 2 + dwords);
+	/* 0=vertex shader, 1=fragment shader */
+	*cmds++ = vtxfrag;
+	/* instruction start & size (in 32-bit words) */
+	*cmds++ = ((0 << 16) | dwords);
+
+	memcpy(cmds, shader_pgm, dwords << 2);
+	cmds += dwords;
+
+	return cmds;
+}
+
+static unsigned int *reg_to_mem(unsigned int *cmds, uint32_t dst,
+				uint32_t src, int dwords)
+{
+	while (dwords-- > 0) {
+		*cmds++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+		*cmds++ = src++;
+		*cmds++ = dst;
+		dst += 4;
+	}
+
+	return cmds;
+}
+
+#ifdef DISABLE_SHADOW_WRITES
+
+static void build_reg_to_mem_range(unsigned int start, unsigned int end,
+				   unsigned int **cmd,
+				   struct kgsl_drawctxt *drawctxt)
+{
+	unsigned int i = start;
+
+	for (i = start; i <= end; i++) {
+		*(*cmd)++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+		*(*cmd)++ = i | (1 << 30);
+		*(*cmd)++ =
+		    ((drawctxt->gpustate.gpuaddr + REG_OFFSET) & 0xFFFFE000) +
+		    (i - 0x2000) * 4;
+	}
+}
+
+#endif
+
+/* chicken restore */
+static unsigned int *build_chicken_restore_cmds(struct kgsl_drawctxt *drawctxt,
+						struct tmp_ctx *ctx)
+{
+	unsigned int *start = ctx->cmd;
+	unsigned int *cmds = start;
+
+	*cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0;
+
+	*cmds++ = pm4_type0_packet(REG_TP0_CHICKEN, 1);
+	ctx->chicken_restore = gpuaddr(cmds, &drawctxt->gpustate);
+	*cmds++ = 0x00000000;
+
+	/* create indirect buffer command for above command sequence */
+	create_ib1(drawctxt, drawctxt->chicken_restore, start, cmds);
+
+	return cmds;
+}
+
+/* save h/w regs, alu constants, texture contants, etc. ...
+*  requires: bool_shadow_gpuaddr, loop_shadow_gpuaddr
+*/
+static void build_regsave_cmds(struct kgsl_device *device,
+			       struct kgsl_drawctxt *drawctxt,
+			       struct tmp_ctx *ctx)
+{
+	unsigned int *start = ctx->cmd;
+	unsigned int *cmd = start;
+	unsigned int pm_override1;
+
+	kgsl_yamato_regread(device, REG_RBBM_PM_OVERRIDE1, &pm_override1);
+
+	*cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmd++ = 0;
+
+#ifdef DISABLE_SHADOW_WRITES
+	/* Make sure the HW context has the correct register values
+	 * before reading them. */
+	*cmd++ = pm4_type3_packet(PM4_CONTEXT_UPDATE, 1);
+	*cmd++ = 0;
+#endif
+
+	/* Enable clock override for REG_FIFOS_SCLK */
+	*cmd++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE1, 1);
+	*cmd++ = pm_override1 | (1 << 6);
+
+#ifdef DISABLE_SHADOW_WRITES
+	/* Write HW registers into shadow */
+	build_reg_to_mem_range(REG_RB_SURFACE_INFO, REG_RB_DEPTH_INFO, &cmd,
+			       drawctxt);
+	build_reg_to_mem_range(REG_COHER_DEST_BASE_0,
+			       REG_PA_SC_SCREEN_SCISSOR_BR, &cmd, drawctxt);
+	build_reg_to_mem_range(REG_PA_SC_WINDOW_OFFSET,
+			       REG_PA_SC_WINDOW_SCISSOR_BR, &cmd, drawctxt);
+	build_reg_to_mem_range(REG_VGT_MAX_VTX_INDX, REG_RB_FOG_COLOR, &cmd,
+			       drawctxt);
+	build_reg_to_mem_range(REG_RB_STENCILREFMASK_BF,
+			       REG_PA_CL_VPORT_ZOFFSET, &cmd, drawctxt);
+	build_reg_to_mem_range(REG_SQ_PROGRAM_CNTL, REG_SQ_WRAPPING_1, &cmd,
+			       drawctxt);
+	build_reg_to_mem_range(REG_RB_DEPTHCONTROL, REG_RB_MODECONTROL, &cmd,
+			       drawctxt);
+	build_reg_to_mem_range(REG_PA_SU_POINT_SIZE, REG_PA_SC_LINE_STIPPLE,
+			       &cmd, drawctxt);
+	build_reg_to_mem_range(REG_PA_SC_VIZ_QUERY, REG_PA_SC_VIZ_QUERY, &cmd,
+			       drawctxt);
+	build_reg_to_mem_range(REG_PA_SC_LINE_CNTL, REG_SQ_PS_CONST, &cmd,
+			       drawctxt);
+	build_reg_to_mem_range(REG_PA_SC_AA_MASK, REG_PA_SC_AA_MASK, &cmd,
+			       drawctxt);
+	build_reg_to_mem_range(REG_VGT_VERTEX_REUSE_BLOCK_CNTL,
+			       REG_RB_DEPTH_CLEAR, &cmd, drawctxt);
+	build_reg_to_mem_range(REG_RB_SAMPLE_COUNT_CTL, REG_RB_COLOR_DEST_MASK,
+			       &cmd, drawctxt);
+	build_reg_to_mem_range(REG_PA_SU_POLY_OFFSET_FRONT_SCALE,
+			       REG_PA_SU_POLY_OFFSET_BACK_OFFSET, &cmd,
+			       drawctxt);
+
+	/* Copy ALU constants */
+	cmd =
+	    reg_to_mem(cmd, (drawctxt->gpustate.gpuaddr) & 0xFFFFE000,
+		       REG_SQ_CONSTANT_0, ALU_CONSTANTS);
+
+	/* Copy Tex constants */
+	cmd =
+	    reg_to_mem(cmd,
+		       (drawctxt->gpustate.gpuaddr + TEX_OFFSET) & 0xFFFFE000,
+		       REG_SQ_FETCH_0, TEX_CONSTANTS);
+#else
+
+	/* Insert a wait for idle packet before reading the registers.
+	 * This is to fix a hang/reset seen during stress testing.  In this
+	 * hang, CP encountered a timeout reading SQ's boolean constant
+	 * register. There is logic in the HW that blocks reading of this
+	 * register when the SQ block is not idle, which we believe is
+	 * contributing to the hang.*/
+	*cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmd++ = 0;
+	/* H/w registers are already shadowed; just need to disable shadowing
+	 * to prevent corruption.
+	 */
+	*cmd++ = pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, 3);
+	*cmd++ = (drawctxt->gpustate.gpuaddr + REG_OFFSET) & 0xFFFFE000;
+	*cmd++ = 4 << 16;	/* regs, start=0 */
+	*cmd++ = 0x0;		/* count = 0 */
+
+	/* ALU constants are already shadowed; just need to disable shadowing
+	 * to prevent corruption.
+	 */
+	*cmd++ = pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, 3);
+	*cmd++ = drawctxt->gpustate.gpuaddr & 0xFFFFE000;
+	*cmd++ = 0 << 16;	/* ALU, start=0 */
+	*cmd++ = 0x0;		/* count = 0 */
+
+	/* Tex constants are already shadowed; just need to disable shadowing
+	 *  to prevent corruption.
+	 */
+	*cmd++ = pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, 3);
+	*cmd++ = (drawctxt->gpustate.gpuaddr + TEX_OFFSET) & 0xFFFFE000;
+	*cmd++ = 1 << 16;	/* Tex, start=0 */
+	*cmd++ = 0x0;		/* count = 0 */
+#endif
+
+	/* Need to handle some of the registers separately */
+	*cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+	*cmd++ = REG_SQ_GPR_MANAGEMENT;
+	*cmd++ = ctx->reg_values[0];
+
+	*cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+	*cmd++ = REG_TP0_CHICKEN;
+	*cmd++ = ctx->reg_values[1];
+
+	*cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+	*cmd++ = REG_RBBM_PM_OVERRIDE1;
+	*cmd++ = ctx->reg_values[2];
+
+	*cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+	*cmd++ = REG_RBBM_PM_OVERRIDE2;
+	*cmd++ = ctx->reg_values[3];
+
+	/* Copy Boolean constants */
+	cmd = reg_to_mem(cmd, ctx->bool_shadow, REG_SQ_CF_BOOLEANS,
+			 BOOL_CONSTANTS);
+
+	/* Copy Loop constants */
+	cmd = reg_to_mem(cmd, ctx->loop_shadow, REG_SQ_CF_LOOP, LOOP_CONSTANTS);
+
+	/* Restore RBBM_PM_OVERRIDE1 */
+	*cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmd++ = 0;
+	*cmd++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE1, 1);
+	*cmd++ = pm_override1;
+
+	/* create indirect buffer command for above command sequence */
+	create_ib1(drawctxt, drawctxt->reg_save, start, cmd);
+
+	ctx->cmd = cmd;
+}
+
+/*copy colour, depth, & stencil buffers from graphics memory to system memory*/
+static unsigned int *build_gmem2sys_cmds(struct kgsl_device *device,
+					 struct kgsl_drawctxt *drawctxt,
+					 struct tmp_ctx *ctx,
+					 struct gmem_shadow_t *shadow)
+{
+	unsigned int *cmds = shadow->gmem_save_commands;
+	unsigned int *start = cmds;
+	unsigned int pm_override1;
+	/* Calculate the new offset based on the adjusted base */
+	unsigned int bytesperpixel = format2bytesperpixel[shadow->format];
+	unsigned int addr =
+	    (shadow->gmemshadow.gpuaddr + shadow->offset * bytesperpixel);
+	unsigned int offset = (addr - (addr & 0xfffff000)) / bytesperpixel;
+
+	kgsl_yamato_regread(device, REG_RBBM_PM_OVERRIDE1, &pm_override1);
+
+	/* Store TP0_CHICKEN register */
+	*cmds++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+	*cmds++ = REG_TP0_CHICKEN;
+	if (ctx)
+		*cmds++ = ctx->chicken_restore;
+	else
+		cmds++;
+
+	*cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0;
+
+	/* Enable clock override for REG_FIFOS_SCLK */
+	*cmds++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE1, 1);
+	*cmds++ = pm_override1 | (1 << 6);
+
+	/* Set TP0_CHICKEN to zero */
+	*cmds++ = pm4_type0_packet(REG_TP0_CHICKEN, 1);
+	*cmds++ = 0x00000000;
+
+	/* Set PA_SC_AA_CONFIG to 0 */
+	*cmds++ = pm4_type0_packet(REG_PA_SC_AA_CONFIG, 1);
+	*cmds++ = 0x00000000;
+
+	/* program shader */
+
+	/* load shader vtx constants ... 5 dwords */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 4);
+	*cmds++ = (0x1 << 16) | SHADER_CONST_ADDR;
+	*cmds++ = 0;
+	/* valid(?) vtx constant flag & addr */
+	*cmds++ = shadow->quad_vertices.gpuaddr | 0x3;
+	/* limit = 12 dwords */
+	*cmds++ = 0x00000030;
+
+	/* Invalidate L2 cache to make sure vertices are updated */
+	*cmds++ = pm4_type0_packet(REG_TC_CNTL_STATUS, 1);
+	*cmds++ = 0x1;
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 4);
+	*cmds++ = PM4_REG(REG_VGT_MAX_VTX_INDX);
+	*cmds++ = 0x00ffffff;	/* REG_VGT_MAX_VTX_INDX */
+	*cmds++ = 0x0;		/* REG_VGT_MIN_VTX_INDX */
+	*cmds++ = 0x00000000;	/* REG_VGT_INDX_OFFSET */
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_PA_SC_AA_MASK);
+	*cmds++ = 0x0000ffff;	/* REG_PA_SC_AA_MASK */
+
+	/* load the patched vertex shader stream */
+	cmds = program_shader(cmds, 0, gmem2sys_vtx_pgm, GMEM2SYS_VTX_PGM_LEN);
+
+	/* Load the patched fragment shader stream */
+	cmds =
+	    program_shader(cmds, 1, gmem2sys_frag_pgm, GMEM2SYS_FRAG_PGM_LEN);
+
+	/* SQ_PROGRAM_CNTL / SQ_CONTEXT_MISC */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_SQ_PROGRAM_CNTL);
+	*cmds++ = 0x10010001;
+	*cmds++ = 0x00000008;
+
+	/* resolve */
+
+	/* PA_CL_VTE_CNTL */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_PA_CL_VTE_CNTL);
+	/* disable X/Y/Z transforms, X/Y/Z are premultiplied by W */
+	*cmds++ = 0x00000b00;
+
+	/* program surface info */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_RB_SURFACE_INFO);
+	*cmds++ = shadow->gmem_pitch;	/* pitch, MSAA = 1 */
+
+	/* RB_COLOR_INFO Endian=none, Linear, Format=RGBA8888, Swap=0,
+	 *                Base=gmem_base
+	 */
+	/* gmem base assumed 4K aligned. */
+	if (ctx) {
+		BUG_ON(ctx->gmem_base & 0xFFF);
+		*cmds++ =
+		    (shadow->
+		     format << RB_COLOR_INFO__COLOR_FORMAT__SHIFT) | ctx->
+		    gmem_base;
+	} else {
+		unsigned int temp = *cmds;
+		*cmds++ = (temp & ~RB_COLOR_INFO__COLOR_FORMAT_MASK) |
+			(shadow->format << RB_COLOR_INFO__COLOR_FORMAT__SHIFT);
+	}
+
+	/* disable Z */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_RB_DEPTHCONTROL);
+	*cmds++ = 0;
+
+	/* set REG_PA_SU_SC_MODE_CNTL
+	 *              Front_ptype = draw triangles
+	 *              Back_ptype = draw triangles
+	 *              Provoking vertex = last
+	 */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_PA_SU_SC_MODE_CNTL);
+	*cmds++ = 0x00080240;
+
+	/* Use maximum scissor values -- quad vertices already have the
+	 * correct bounds */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_PA_SC_SCREEN_SCISSOR_TL);
+	*cmds++ = (0 << 16) | 0;
+	*cmds++ = (0x1fff << 16) | (0x1fff);
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_PA_SC_WINDOW_SCISSOR_TL);
+	*cmds++ = (unsigned int)((1U << 31) | (0 << 16) | 0);
+	*cmds++ = (0x1fff << 16) | (0x1fff);
+
+	/* load the viewport so that z scale = clear depth and
+	 *  z offset = 0.0f
+	 */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_PA_CL_VPORT_ZSCALE);
+	*cmds++ = 0xbf800000;	/* -1.0f */
+	*cmds++ = 0x0;
+
+	/* load the stencil ref value
+	 * $AAM - do this later
+	 */
+
+	/* load the COPY state */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 6);
+	*cmds++ = PM4_REG(REG_RB_COPY_CONTROL);
+	*cmds++ = 0;		/* RB_COPY_CONTROL */
+	*cmds++ = addr & 0xfffff000;	/* RB_COPY_DEST_BASE */
+	*cmds++ = shadow->pitch >> 5;	/* RB_COPY_DEST_PITCH */
+
+	/* Endian=none, Linear, Format=RGBA8888,Swap=0,!Dither,
+	 *  MaskWrite:R=G=B=A=1
+	 */
+	*cmds++ = 0x0003c008 |
+	    (shadow->format << RB_COPY_DEST_INFO__COPY_DEST_FORMAT__SHIFT);
+	/* Make sure we stay in offsetx field. */
+	BUG_ON(offset & 0xfffff000);
+	*cmds++ = offset;
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_RB_MODECONTROL);
+	*cmds++ = 0x6;		/* EDRAM copy */
+
+	/* queue the draw packet */
+	*cmds++ = pm4_type3_packet(PM4_DRAW_INDX, 2);
+	*cmds++ = 0;		/* viz query info. */
+	/* PrimType=RectList, NumIndices=3, SrcSel=AutoIndex */
+	*cmds++ = 0x00030088;
+
+	/* Restore RBBM_PM_OVERRIDE1 */
+	*cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0;
+	*cmds++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE1, 1);
+	*cmds++ = pm_override1;
+	/* create indirect buffer command for above command sequence */
+	create_ib1(drawctxt, shadow->gmem_save, start, cmds);
+
+	return cmds;
+}
+
+/* context restore */
+
+/*copy colour, depth, & stencil buffers from system memory to graphics memory*/
+static unsigned int *build_sys2gmem_cmds(struct kgsl_device *device,
+					 struct kgsl_drawctxt *drawctxt,
+					 struct tmp_ctx *ctx,
+					 struct gmem_shadow_t *shadow)
+{
+	unsigned int *cmds = shadow->gmem_restore_commands;
+	unsigned int *start = cmds;
+	unsigned int pm_override1;
+
+	kgsl_yamato_regread(device, REG_RBBM_PM_OVERRIDE1, &pm_override1);
+
+	/* Store TP0_CHICKEN register */
+	*cmds++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+	*cmds++ = REG_TP0_CHICKEN;
+	if (ctx)
+		*cmds++ = ctx->chicken_restore;
+	else
+		cmds++;
+
+	*cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0;
+
+	/* Enable clock override for REG_FIFOS_SCLK */
+	*cmds++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE1, 1);
+	*cmds++ = pm_override1 | (1 << 6);
+
+	/* Set TP0_CHICKEN to zero */
+	*cmds++ = pm4_type0_packet(REG_TP0_CHICKEN, 1);
+	*cmds++ = 0x00000000;
+
+	/* Set PA_SC_AA_CONFIG to 0 */
+	*cmds++ = pm4_type0_packet(REG_PA_SC_AA_CONFIG, 1);
+	*cmds++ = 0x00000000;
+	/* shader constants */
+
+	/* vertex buffer constants */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 7);
+
+	*cmds++ = (0x1 << 16) | (9 * 6);
+	/* valid(?) vtx constant flag & addr */
+	*cmds++ = shadow->quad_vertices.gpuaddr | 0x3;
+	/* limit = 12 dwords */
+	*cmds++ = 0x00000030;
+	/* valid(?) vtx constant flag & addr */
+	*cmds++ = shadow->quad_texcoords.gpuaddr | 0x3;
+	/* limit = 8 dwords */
+	*cmds++ = 0x00000020;
+	*cmds++ = 0;
+	*cmds++ = 0;
+
+	/* Invalidate L2 cache to make sure vertices are updated */
+	*cmds++ = pm4_type0_packet(REG_TC_CNTL_STATUS, 1);
+	*cmds++ = 0x1;
+
+	cmds = program_shader(cmds, 0, sys2gmem_vtx_pgm, SYS2GMEM_VTX_PGM_LEN);
+
+	/* Load the patched fragment shader stream */
+	cmds =
+	    program_shader(cmds, 1, sys2gmem_frag_pgm, SYS2GMEM_FRAG_PGM_LEN);
+
+	/* SQ_PROGRAM_CNTL / SQ_CONTEXT_MISC */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_SQ_PROGRAM_CNTL);
+	*cmds++ = 0x10030002;
+	*cmds++ = 0x00000008;
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_PA_SC_AA_MASK);
+	*cmds++ = 0x0000ffff;	/* REG_PA_SC_AA_MASK */
+
+	/* PA_SC_VIZ_QUERY */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_PA_SC_VIZ_QUERY);
+	*cmds++ = 0x0;		/*REG_PA_SC_VIZ_QUERY */
+
+	/* RB_COLORCONTROL */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_RB_COLORCONTROL);
+	*cmds++ = 0x00000c20;
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 4);
+	*cmds++ = PM4_REG(REG_VGT_MAX_VTX_INDX);
+	*cmds++ = 0x00ffffff;	/* mmVGT_MAX_VTX_INDX */
+	*cmds++ = 0x0;		/* mmVGT_MIN_VTX_INDX */
+	*cmds++ = 0x00000000;	/* mmVGT_INDX_OFFSET */
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_VGT_VERTEX_REUSE_BLOCK_CNTL);
+	*cmds++ = 0x00000002;	/* mmVGT_VERTEX_REUSE_BLOCK_CNTL */
+	*cmds++ = 0x00000002;	/* mmVGT_OUT_DEALLOC_CNTL */
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_SQ_INTERPOLATOR_CNTL);
+	//*cmds++ = 0x0000ffff; //mmSQ_INTERPOLATOR_CNTL
+	*cmds++ = 0xffffffff;	//mmSQ_INTERPOLATOR_CNTL
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_PA_SC_AA_CONFIG);
+	*cmds++ = 0x00000000;	/* REG_PA_SC_AA_CONFIG */
+
+	/* set REG_PA_SU_SC_MODE_CNTL
+	 * Front_ptype = draw triangles
+	 * Back_ptype = draw triangles
+	 * Provoking vertex = last
+	 */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_PA_SU_SC_MODE_CNTL);
+	*cmds++ = 0x00080240;
+
+	/* texture constants */
+	*cmds++ =
+	    pm4_type3_packet(PM4_SET_CONSTANT, (SYS2GMEM_TEX_CONST_LEN + 1));
+	*cmds++ = (0x1 << 16) | (0 * 6);
+	memcpy(cmds, sys2gmem_tex_const, SYS2GMEM_TEX_CONST_LEN << 2);
+	cmds[0] |= (shadow->pitch >> 5) << 22;
+	cmds[1] |=
+	    shadow->gmemshadow.gpuaddr | surface_format_table[shadow->format];
+	cmds[2] |=
+	    (shadow->width + shadow->offset_x - 1) | (shadow->height +
+						      shadow->offset_y -
+						      1) << 13;
+	cmds += SYS2GMEM_TEX_CONST_LEN;
+
+	/* program surface info */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_RB_SURFACE_INFO);
+	*cmds++ = shadow->gmem_pitch;	/* pitch, MSAA = 1 */
+
+	/* RB_COLOR_INFO Endian=none, Linear, Format=RGBA8888, Swap=0,
+	 *                Base=gmem_base
+	 */
+	if (ctx)
+		*cmds++ =
+		    (shadow->
+		     format << RB_COLOR_INFO__COLOR_FORMAT__SHIFT) | ctx->
+		    gmem_base;
+	else {
+		unsigned int temp = *cmds;
+		*cmds++ = (temp & ~RB_COLOR_INFO__COLOR_FORMAT_MASK) |
+			(shadow->format << RB_COLOR_INFO__COLOR_FORMAT__SHIFT);
+	}
+
+	/* RB_DEPTHCONTROL */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_RB_DEPTHCONTROL);
+	*cmds++ = 0;		/* disable Z */
+
+	/* Use maximum scissor values -- quad vertices already
+	 * have the correct bounds */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_PA_SC_SCREEN_SCISSOR_TL);
+	*cmds++ = (0 << 16) | 0;
+	*cmds++ = ((0x1fff) << 16) | 0x1fff;
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_PA_SC_WINDOW_SCISSOR_TL);
+	*cmds++ = (unsigned int)((1U << 31) | (0 << 16) | 0);
+	*cmds++ = ((0x1fff) << 16) | 0x1fff;
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_PA_CL_VTE_CNTL);
+	/* disable X/Y/Z transforms, X/Y/Z are premultiplied by W */
+	*cmds++ = 0x00000b00;
+
+	/*load the viewport so that z scale = clear depth and z offset = 0.0f */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_PA_CL_VPORT_ZSCALE);
+	*cmds++ = 0xbf800000;
+	*cmds++ = 0x0;
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_RB_COLOR_MASK);
+	*cmds++ = 0x0000000f;	/* R = G = B = 1:enabled */
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_RB_COLOR_DEST_MASK);
+	*cmds++ = 0xffffffff;
+
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3);
+	*cmds++ = PM4_REG(REG_SQ_WRAPPING_0);
+	*cmds++ = 0x00000000;
+	*cmds++ = 0x00000000;
+
+	/* load the stencil ref value
+	 *  $AAM - do this later
+	 */
+	*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+	*cmds++ = PM4_REG(REG_RB_MODECONTROL);
+	/* draw pixels with color and depth/stencil component */
+	*cmds++ = 0x4;
+
+	/* queue the draw packet */
+	*cmds++ = pm4_type3_packet(PM4_DRAW_INDX, 2);
+	*cmds++ = 0;		/* viz query info. */
+	/* PrimType=RectList, NumIndices=3, SrcSel=AutoIndex */
+	*cmds++ = 0x00030088;
+
+	/* Restore RBBM_PM_OVERRIDE1 */
+	*cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0;
+	*cmds++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE1, 1);
+	*cmds++ = pm_override1;
+
+	/* create indirect buffer command for above command sequence */
+	create_ib1(drawctxt, shadow->gmem_restore, start, cmds);
+
+	return cmds;
+}
+
+/* restore h/w regs, alu constants, texture constants, etc. ... */
+static unsigned *reg_range(unsigned int *cmd, unsigned int start,
+			   unsigned int end)
+{
+	*cmd++ = PM4_REG(start);	/* h/w regs, start addr */
+	*cmd++ = end - start + 1;	/* count */
+	return cmd;
+}
+
+static void build_regrestore_cmds(struct kgsl_device *device,
+				  struct kgsl_drawctxt *drawctxt,
+				  struct tmp_ctx *ctx)
+{
+	unsigned int *start = ctx->cmd;
+	unsigned int *cmd = start;
+	unsigned int pm_override1;
+
+	kgsl_yamato_regread(device, REG_RBBM_PM_OVERRIDE1, &pm_override1);
+
+	*cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmd++ = 0;
+
+	/* Enable clock override for REG_FIFOS_SCLK */
+	*cmd++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE1, 1);
+	*cmd++ = pm_override1 | (1 << 6);
+
+	/* H/W Registers */
+	/* deferred pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, ???); */
+	cmd++;
+#ifdef DISABLE_SHADOW_WRITES
+	/* Force mismatch */
+	*cmd++ = ((drawctxt->gpustate.gpuaddr + REG_OFFSET) & 0xFFFFE000) | 1;
+#else
+	*cmd++ = (drawctxt->gpustate.gpuaddr + REG_OFFSET) & 0xFFFFE000;
+#endif
+
+	cmd = reg_range(cmd, REG_RB_SURFACE_INFO, REG_PA_SC_SCREEN_SCISSOR_BR);
+	cmd = reg_range(cmd, REG_PA_SC_WINDOW_OFFSET,
+			REG_PA_SC_WINDOW_SCISSOR_BR);
+	cmd = reg_range(cmd, REG_VGT_MAX_VTX_INDX, REG_PA_CL_VPORT_ZOFFSET);
+	cmd = reg_range(cmd, REG_SQ_PROGRAM_CNTL, REG_SQ_WRAPPING_1);
+	cmd = reg_range(cmd, REG_RB_DEPTHCONTROL, REG_RB_MODECONTROL);
+	cmd = reg_range(cmd, REG_PA_SU_POINT_SIZE,
+			REG_PA_SC_VIZ_QUERY); /*REG_VGT_ENHANCE */
+	cmd = reg_range(cmd, REG_PA_SC_LINE_CNTL, REG_RB_COLOR_DEST_MASK);
+	cmd = reg_range(cmd, REG_PA_SU_POLY_OFFSET_FRONT_SCALE,
+			REG_PA_SU_POLY_OFFSET_BACK_OFFSET);
+
+	/* Now we know how many register blocks we have, we can compute command
+	 * length
+	 */
+	start[4] =
+	    pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, (cmd - start) - 5);
+	/* Enable shadowing for the entire register block. */
+#ifdef DISABLE_SHADOW_WRITES
+	start[6] |= (0 << 24) | (4 << 16);	/* Disable shadowing. */
+#else
+	start[6] |= (1 << 24) | (4 << 16);
+#endif
+
+	/* Need to handle some of the registers separately */
+	*cmd++ = pm4_type0_packet(REG_SQ_GPR_MANAGEMENT, 1);
+	ctx->reg_values[0] = gpuaddr(cmd, &drawctxt->gpustate);
+	*cmd++ = 0x00040400;
+
+	*cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmd++ = 0;
+	*cmd++ = pm4_type0_packet(REG_TP0_CHICKEN, 1);
+	ctx->reg_values[1] = gpuaddr(cmd, &drawctxt->gpustate);
+	*cmd++ = 0x00000000;
+
+	*cmd++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE1, 1);
+	ctx->reg_values[2] = gpuaddr(cmd, &drawctxt->gpustate);
+	*cmd++ = 0x00000000;
+
+	*cmd++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE2, 1);
+	ctx->reg_values[3] = gpuaddr(cmd, &drawctxt->gpustate);
+	*cmd++ = 0x00000000;
+
+	/* ALU Constants */
+	*cmd++ = pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, 3);
+	*cmd++ = drawctxt->gpustate.gpuaddr & 0xFFFFE000;
+#ifdef DISABLE_SHADOW_WRITES
+	*cmd++ = (0 << 24) | (0 << 16) | 0;	/* Disable shadowing */
+#else
+	*cmd++ = (1 << 24) | (0 << 16) | 0;
+#endif
+	*cmd++ = ALU_CONSTANTS;
+
+	/* Texture Constants */
+	*cmd++ = pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, 3);
+	*cmd++ = (drawctxt->gpustate.gpuaddr + TEX_OFFSET) & 0xFFFFE000;
+#ifdef DISABLE_SHADOW_WRITES
+	/* Disable shadowing */
+	*cmd++ = (0 << 24) | (1 << 16) | 0;
+#else
+	*cmd++ = (1 << 24) | (1 << 16) | 0;
+#endif
+	*cmd++ = TEX_CONSTANTS;
+
+	/* Boolean Constants */
+	*cmd++ = pm4_type3_packet(PM4_SET_CONSTANT, 1 + BOOL_CONSTANTS);
+	*cmd++ = (2 << 16) | 0;
+
+	/* the next BOOL_CONSTANT dwords is the shadow area for
+	 *  boolean constants.
+	 */
+	ctx->bool_shadow = gpuaddr(cmd, &drawctxt->gpustate);
+	cmd += BOOL_CONSTANTS;
+
+	/* Loop Constants */
+	*cmd++ = pm4_type3_packet(PM4_SET_CONSTANT, 1 + LOOP_CONSTANTS);
+	*cmd++ = (3 << 16) | 0;
+
+	/* the next LOOP_CONSTANTS dwords is the shadow area for
+	 * loop constants.
+	 */
+	ctx->loop_shadow = gpuaddr(cmd, &drawctxt->gpustate);
+	cmd += LOOP_CONSTANTS;
+
+	/* Restore RBBM_PM_OVERRIDE1 */
+	*cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmd++ = 0;
+	*cmd++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE1, 1);
+	*cmd++ = pm_override1;
+
+	/* create indirect buffer command for above command sequence */
+	create_ib1(drawctxt, drawctxt->reg_restore, start, cmd);
+
+	ctx->cmd = cmd;
+}
+
+/* quad for saving/restoring gmem */
+static void set_gmem_copy_quad(struct gmem_shadow_t *shadow)
+{
+	/* set vertex buffer values */
+	gmem_copy_quad[1] = uint2float(shadow->height + shadow->gmem_offset_y);
+	gmem_copy_quad[3] = uint2float(shadow->width + shadow->gmem_offset_x);
+	gmem_copy_quad[4] = uint2float(shadow->height + shadow->gmem_offset_y);
+	gmem_copy_quad[9] = uint2float(shadow->width + shadow->gmem_offset_x);
+
+	gmem_copy_quad[0] = uint2float(shadow->gmem_offset_x);
+	gmem_copy_quad[6] = uint2float(shadow->gmem_offset_x);
+	gmem_copy_quad[7] = uint2float(shadow->gmem_offset_y);
+	gmem_copy_quad[10] = uint2float(shadow->gmem_offset_y);
+
+	BUG_ON(shadow->offset_x);
+	BUG_ON(shadow->offset_y);
+
+	memcpy(shadow->quad_vertices.hostptr, gmem_copy_quad, QUAD_LEN << 2);
+
+	memcpy(shadow->quad_texcoords.hostptr, gmem_copy_texcoord,
+	       TEXCOORD_LEN << 2);
+}
+
+/* quad for saving/restoring gmem */
+static void build_quad_vtxbuff(struct kgsl_drawctxt *drawctxt,
+		       struct tmp_ctx *ctx, struct gmem_shadow_t *shadow)
+{
+	unsigned int *cmd = ctx->cmd;
+
+	/* quad vertex buffer location (in GPU space) */
+	shadow->quad_vertices.hostptr = cmd;
+	shadow->quad_vertices.gpuaddr = gpuaddr(cmd, &drawctxt->gpustate);
+
+	cmd += QUAD_LEN;
+
+	/* tex coord buffer location (in GPU space) */
+	shadow->quad_texcoords.hostptr = cmd;
+	shadow->quad_texcoords.gpuaddr = gpuaddr(cmd, &drawctxt->gpustate);
+
+	cmd += TEXCOORD_LEN;
+
+	set_gmem_copy_quad(shadow);
+
+	ctx->cmd = cmd;
+}
+
+static void
+build_shader_save_restore_cmds(struct kgsl_drawctxt *drawctxt,
+			       struct tmp_ctx *ctx)
+{
+	unsigned int *cmd = ctx->cmd;
+	unsigned int *save, *restore, *fixup;
+#if defined(PM4_IM_STORE)
+	unsigned int *startSizeVtx, *startSizePix, *startSizeShared;
+#endif
+	unsigned int *partition1;
+	unsigned int *shaderBases, *partition2;
+
+#if defined(PM4_IM_STORE)
+	/* compute vertex, pixel and shared instruction shadow GPU addresses */
+	ctx->shader_vertex = drawctxt->gpustate.gpuaddr + SHADER_OFFSET;
+	ctx->shader_pixel = ctx->shader_vertex + SHADER_SHADOW_SIZE;
+	ctx->shader_shared = ctx->shader_pixel + SHADER_SHADOW_SIZE;
+#endif
+
+	/* restore shader partitioning and instructions */
+
+	restore = cmd;		/* start address */
+
+	/* Invalidate Vertex & Pixel instruction code address and sizes */
+	*cmd++ = pm4_type3_packet(PM4_INVALIDATE_STATE, 1);
+	*cmd++ = 0x00000300;	/* 0x100 = Vertex, 0x200 = Pixel */
+
+	/* Restore previous shader vertex & pixel instruction bases. */
+	*cmd++ = pm4_type3_packet(PM4_SET_SHADER_BASES, 1);
+	shaderBases = cmd++;	/* TBD #5: shader bases (from fixup) */
+
+	/* write the shader partition information to a scratch register */
+	*cmd++ = pm4_type0_packet(REG_SQ_INST_STORE_MANAGMENT, 1);
+	partition1 = cmd++;	/* TBD #4a: partition info (from save) */
+
+#if defined(PM4_IM_STORE)
+	/* load vertex shader instructions from the shadow. */
+	*cmd++ = pm4_type3_packet(PM4_IM_LOAD, 2);
+	*cmd++ = ctx->shader_vertex + 0x0;	/* 0x0 = Vertex */
+	startSizeVtx = cmd++;	/* TBD #1: start/size (from save) */
+
+	/* load pixel shader instructions from the shadow. */
+	*cmd++ = pm4_type3_packet(PM4_IM_LOAD, 2);
+	*cmd++ = ctx->shader_pixel + 0x1;	/* 0x1 = Pixel */
+	startSizePix = cmd++;	/* TBD #2: start/size (from save) */
+
+	/* load shared shader instructions from the shadow. */
+	*cmd++ = pm4_type3_packet(PM4_IM_LOAD, 2);
+	*cmd++ = ctx->shader_shared + 0x2;	/* 0x2 = Shared */
+	startSizeShared = cmd++;	/* TBD #3: start/size (from save) */
+#endif
+
+	/* create indirect buffer command for above command sequence */
+	create_ib1(drawctxt, drawctxt->shader_restore, restore, cmd);
+
+	/*
+	 *  fixup SET_SHADER_BASES data
+	 *
+	 *  since self-modifying PM4 code is being used here, a seperate
+	 *  command buffer is used for this fixup operation, to ensure the
+	 *  commands are not read by the PM4 engine before the data fields
+	 *  have been written.
+	 */
+
+	fixup = cmd;		/* start address */
+
+	/* write the shader partition information to a scratch register */
+	*cmd++ = pm4_type0_packet(REG_SCRATCH_REG2, 1);
+	partition2 = cmd++;	/* TBD #4b: partition info (from save) */
+
+	/* mask off unused bits, then OR with shader instruction memory size */
+	*cmd++ = pm4_type3_packet(PM4_REG_RMW, 3);
+	*cmd++ = REG_SCRATCH_REG2;
+	/* AND off invalid bits. */
+	*cmd++ = 0x0FFF0FFF;
+	/* OR in instruction memory size */
+	*cmd++ = (unsigned int)((SHADER_INSTRUCT_LOG2 - 5U) << 29);
+
+	/* write the computed value to the SET_SHADER_BASES data field */
+	*cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+	*cmd++ = REG_SCRATCH_REG2;
+	/* TBD #5: shader bases (to restore) */
+	*cmd++ = gpuaddr(shaderBases, &drawctxt->gpustate);
+
+	/* create indirect buffer command for above command sequence */
+	create_ib1(drawctxt, drawctxt->shader_fixup, fixup, cmd);
+
+	/* save shader partitioning and instructions */
+
+	save = cmd;		/* start address */
+
+	*cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmd++ = 0;
+
+	/* fetch the SQ_INST_STORE_MANAGMENT register value,
+	 *  store the value in the data fields of the SET_CONSTANT commands
+	 *  above.
+	 */
+	*cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+	*cmd++ = REG_SQ_INST_STORE_MANAGMENT;
+	/* TBD #4a: partition info (to restore) */
+	*cmd++ = gpuaddr(partition1, &drawctxt->gpustate);
+	*cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2);
+	*cmd++ = REG_SQ_INST_STORE_MANAGMENT;
+	/* TBD #4b: partition info (to fixup) */
+	*cmd++ = gpuaddr(partition2, &drawctxt->gpustate);
+
+#if defined(PM4_IM_STORE)
+
+	/* store the vertex shader instructions */
+	*cmd++ = pm4_type3_packet(PM4_IM_STORE, 2);
+	*cmd++ = ctx->shader_vertex + 0x0;	/* 0x0 = Vertex */
+	/* TBD #1: start/size (to restore) */
+	*cmd++ = gpuaddr(startSizeVtx, &drawctxt->gpustate);
+
+	/* store the pixel shader instructions */
+	*cmd++ = pm4_type3_packet(PM4_IM_STORE, 2);
+	*cmd++ = ctx->shader_pixel + 0x1;	/* 0x1 = Pixel */
+	/* TBD #2: start/size (to restore) */
+	*cmd++ = gpuaddr(startSizePix, &drawctxt->gpustate);
+
+	/* store the shared shader instructions if vertex base is nonzero */
+
+	*cmd++ = pm4_type3_packet(PM4_IM_STORE, 2);
+	*cmd++ = ctx->shader_shared + 0x2;	/* 0x2 = Shared */
+	/* TBD #3: start/size (to restore) */
+	*cmd++ = gpuaddr(startSizeShared, &drawctxt->gpustate);
+
+#endif
+
+	*cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+	*cmd++ = 0;
+
+	/* create indirect buffer command for above command sequence */
+	create_ib1(drawctxt, drawctxt->shader_save, save, cmd);
+
+	ctx->cmd = cmd;
+}
+
+/* create buffers for saving/restoring registers, constants, & GMEM */
+static int
+create_gpustate_shadow(struct kgsl_device *device,
+		       struct kgsl_drawctxt *drawctxt, struct tmp_ctx *ctx)
+{
+	uint32_t flags;
+
+	flags = (KGSL_MEMFLAGS_CONPHYS | KGSL_MEMFLAGS_ALIGN8K);
+
+	/* allocate memory to allow HW to save sub-blocks for efficient context
+	 *  save/restore
+	 */
+	if (kgsl_sharedmem_alloc(flags, CONTEXT_SIZE, &drawctxt->gpustate) != 0)
+		return -ENOMEM;
+	if (kgsl_mmu_map(drawctxt->pagetable, drawctxt->gpustate.physaddr,
+			 drawctxt->gpustate.size,
+			 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV,
+			 &drawctxt->gpustate.gpuaddr,
+			 KGSL_MEMFLAGS_CONPHYS | KGSL_MEMFLAGS_ALIGN8K))
+		return -EINVAL;
+
+	drawctxt->flags |= CTXT_FLAGS_STATE_SHADOW;
+
+	/* Blank out h/w register, constant, and command buffer shadows. */
+	kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0, CONTEXT_SIZE);
+
+	/* set-up command and vertex buffer pointers */
+	ctx->cmd = ctx->start
+	    = (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);
+
+	/* build indirect command buffers to save & restore regs/constants */
+	kgsl_yamato_idle(device, KGSL_TIMEOUT_DEFAULT);
+	build_regrestore_cmds(device, drawctxt, ctx);
+	build_regsave_cmds(device, drawctxt, ctx);
+
+	build_shader_save_restore_cmds(drawctxt, ctx);
+
+	return 0;
+}
+
+/* create buffers for saving/restoring registers, constants, & GMEM */
+static int
+create_gmem_shadow(struct kgsl_device *device, struct kgsl_drawctxt *drawctxt,
+		   struct tmp_ctx *ctx)
+{
+	unsigned int flags = KGSL_MEMFLAGS_CONPHYS | KGSL_MEMFLAGS_ALIGN8K, i;
+
+	config_gmemsize(&drawctxt->context_gmem_shadow,
+			device->gmemspace.sizebytes);
+	ctx->gmem_base = device->gmemspace.gpu_base;
+
+	/* allocate memory for GMEM shadow */
+	if (kgsl_sharedmem_alloc(flags, drawctxt->context_gmem_shadow.size,
+				 &drawctxt->context_gmem_shadow.gmemshadow) !=
+	    0)
+		return -ENOMEM;
+	if (kgsl_mmu_map(drawctxt->pagetable,
+			 drawctxt->context_gmem_shadow.gmemshadow.physaddr,
+			 drawctxt->context_gmem_shadow.gmemshadow.size,
+			 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV,
+			 &drawctxt->context_gmem_shadow.gmemshadow.gpuaddr,
+			 KGSL_MEMFLAGS_CONPHYS | KGSL_MEMFLAGS_ALIGN8K))
+		return -EINVAL;
+
+	/* we've allocated the shadow, when swapped out, GMEM must be saved. */
+	drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW | CTXT_FLAGS_GMEM_SAVE;
+
+	/* blank out gmem shadow. */
+	kgsl_sharedmem_set(&drawctxt->context_gmem_shadow.gmemshadow, 0, 0,
+			   drawctxt->context_gmem_shadow.size);
+
+	/* build quad vertex buffer */
+	build_quad_vtxbuff(drawctxt, ctx, &drawctxt->context_gmem_shadow);
+
+	/* build TP0_CHICKEN register restore command buffer */
+	ctx->cmd = build_chicken_restore_cmds(drawctxt, ctx);
+
+	/* build indirect command buffers to save & restore gmem */
+	/* Idle because we are reading PM override registers */
+	kgsl_yamato_idle(device, KGSL_TIMEOUT_DEFAULT);
+	drawctxt->context_gmem_shadow.gmem_save_commands = ctx->cmd;
+	ctx->cmd =
+	    build_gmem2sys_cmds(device, drawctxt, ctx,
+				&drawctxt->context_gmem_shadow);
+	drawctxt->context_gmem_shadow.gmem_restore_commands = ctx->cmd;
+	ctx->cmd =
+	    build_sys2gmem_cmds(device, drawctxt, ctx,
+				&drawctxt->context_gmem_shadow);
+
+	for (i = 0; i < KGSL_MAX_GMEM_SHADOW_BUFFERS; i++) {
+		build_quad_vtxbuff(drawctxt, ctx,
+				   &drawctxt->user_gmem_shadow[i]);
+
+		drawctxt->user_gmem_shadow[i].gmem_save_commands = ctx->cmd;
+		ctx->cmd =
+		    build_gmem2sys_cmds(device, drawctxt, ctx,
+					&drawctxt->user_gmem_shadow[i]);
+
+		drawctxt->user_gmem_shadow[i].gmem_restore_commands = ctx->cmd;
+		ctx->cmd =
+		    build_sys2gmem_cmds(device, drawctxt, ctx,
+					&drawctxt->user_gmem_shadow[i]);
+	}
+
+	return 0;
+}
+
+/* init draw context */
+
+int kgsl_drawctxt_init(struct kgsl_device *device)
+{
+	return 0;
+}
+
+/* close draw context */
+int kgsl_drawctxt_close(struct kgsl_device *device)
+{
+	return 0;
+}
+
+/* create a new drawing context */
+
+int
+kgsl_drawctxt_create(struct kgsl_device *device,
+		     struct kgsl_pagetable *pagetable,
+		     unsigned int flags, unsigned int *drawctxt_id)
+{
+	struct kgsl_drawctxt *drawctxt;
+	int index;
+	struct tmp_ctx ctx;
+
+	KGSL_CTXT_INFO("pt %p flags %08x\n", pagetable, flags);
+	if (device->drawctxt_count >= KGSL_CONTEXT_MAX)
+		return -EINVAL;
+
+	/* find a free context slot */
+	index = 0;
+	while (index < KGSL_CONTEXT_MAX) {
+		if (device->drawctxt[index].flags == CTXT_FLAGS_NOT_IN_USE)
+			break;
+
+		index++;
+	}
+
+	if (index >= KGSL_CONTEXT_MAX)
+		return -EINVAL;
+
+	drawctxt = &device->drawctxt[index];
+	drawctxt->pagetable = pagetable;
+	drawctxt->flags = CTXT_FLAGS_IN_USE;
+	drawctxt->bin_base_offset = 0;
+
+	device->drawctxt_count++;
+
+	if (create_gpustate_shadow(device, drawctxt, &ctx)
+			!= 0) {
+		kgsl_drawctxt_destroy(device, index);
+		return -EINVAL;
+	}
+
+	/* Save the shader instruction memory on context switching */
+	drawctxt->flags |= CTXT_FLAGS_SHADER_SAVE;
+
+	if (!(flags & KGSL_CONTEXT_NO_GMEM_ALLOC)) {
+		/* create gmem shadow */
+		memset(drawctxt->user_gmem_shadow, 0,
+		       sizeof(struct gmem_shadow_t) *
+				KGSL_MAX_GMEM_SHADOW_BUFFERS);
+
+		if (create_gmem_shadow(device, drawctxt, &ctx)
+				!= 0) {
+			kgsl_drawctxt_destroy(device, index);
+			return -EINVAL;
+		}
+	}
+
+	BUG_ON(ctx.cmd - ctx.start > CMD_BUFFER_LEN);
+
+	*drawctxt_id = index;
+
+	KGSL_CTXT_INFO("return drawctxt_id %d\n", *drawctxt_id);
+	return 0;
+}
+
+/* destroy a drawing context */
+
+int kgsl_drawctxt_destroy(struct kgsl_device *device, unsigned int drawctxt_id)
+{
+	struct kgsl_drawctxt *drawctxt;
+
+	drawctxt = &device->drawctxt[drawctxt_id];
+
+	KGSL_CTXT_INFO("drawctxt_id %d ptr %p\n", drawctxt_id, drawctxt);
+	if (drawctxt->flags != CTXT_FLAGS_NOT_IN_USE) {
+		/* deactivate context */
+		if (device->drawctxt_active == drawctxt) {
+			/* no need to save GMEM or shader, the context is
+			 * being destroyed.
+			 */
+			drawctxt->flags &= ~(CTXT_FLAGS_GMEM_SAVE |
+					     CTXT_FLAGS_SHADER_SAVE |
+					     CTXT_FLAGS_GMEM_SHADOW |
+					     CTXT_FLAGS_STATE_SHADOW);
+
+			kgsl_drawctxt_switch(device, NULL, 0);
+		}
+
+		kgsl_yamato_idle(device, KGSL_TIMEOUT_DEFAULT);
+
+		/* destroy state shadow, if allocated */
+		if (drawctxt->gpustate.gpuaddr != 0) {
+			kgsl_mmu_unmap(drawctxt->pagetable,
+				       drawctxt->gpustate.gpuaddr,
+				       drawctxt->gpustate.size);
+			drawctxt->gpustate.gpuaddr = 0;
+		}
+		if (drawctxt->gpustate.physaddr != 0)
+			kgsl_sharedmem_free(&drawctxt->gpustate);
+
+		/* destroy gmem shadow, if allocated */
+		if (drawctxt->context_gmem_shadow.gmemshadow.gpuaddr != 0) {
+			kgsl_mmu_unmap(drawctxt->pagetable,
+				drawctxt->context_gmem_shadow.gmemshadow.gpuaddr,
+				drawctxt->context_gmem_shadow.gmemshadow.size);
+			drawctxt->context_gmem_shadow.gmemshadow.gpuaddr = 0;
+		}
+
+		if (drawctxt->context_gmem_shadow.gmemshadow.physaddr != 0)
+			kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.
+					    gmemshadow);
+
+		drawctxt->flags = CTXT_FLAGS_NOT_IN_USE;
+
+		BUG_ON(device->drawctxt_count == 0);
+		device->drawctxt_count--;
+	}
+	KGSL_CTXT_INFO("return\n");
+	return 0;
+}
+
+/* Binds a user specified buffer as GMEM shadow area */
+int kgsl_drawctxt_bind_gmem_shadow(struct kgsl_device *device,
+		unsigned int drawctxt_id,
+		const struct kgsl_gmem_desc *gmem_desc,
+		unsigned int shadow_x,
+		unsigned int shadow_y,
+		const struct kgsl_buffer_desc
+		*shadow_buffer, unsigned int buffer_id)
+{
+	struct kgsl_drawctxt *drawctxt;
+
+    /* Shadow struct being modified */
+    struct gmem_shadow_t *shadow;
+	unsigned int i;
+
+	if (device->flags & KGSL_FLAGS_SAFEMODE)
+		/* No need to bind any buffers since safe mode
+		* skips context switch */
+		return 0;
+
+	drawctxt = &device->drawctxt[drawctxt_id];
+
+	shadow = &drawctxt->user_gmem_shadow[buffer_id];
+
+	if (!shadow_buffer->enabled) {
+		/* Disable shadow */
+		KGSL_MEM_ERR("shadow is disabled in bind_gmem\n");
+		shadow->gmemshadow.size = 0;
+	} else {
+		/* Binding to a buffer */
+		unsigned int width, height;
+
+		BUG_ON(gmem_desc->x % 2); /* Needs to be a multiple of 2 */
+		BUG_ON(gmem_desc->y % 2);  /* Needs to be a multiple of 2 */
+		BUG_ON(gmem_desc->width % 2); /* Needs to be a multiple of 2 */
+		/* Needs to be a multiple of 2 */
+		BUG_ON(gmem_desc->height % 2);
+		/* Needs to be a multiple of 32 */
+		BUG_ON(gmem_desc->pitch % 32);
+
+		BUG_ON(shadow_x % 2);  /* Needs to be a multiple of 2 */
+		BUG_ON(shadow_y % 2);  /* Needs to be a multiple of 2 */
+
+		BUG_ON(shadow_buffer->format < COLORX_4_4_4_4);
+		BUG_ON(shadow_buffer->format > COLORX_32_32_32_32_FLOAT);
+		/* Needs to be a multiple of 32 */
+		BUG_ON(shadow_buffer->pitch % 32);
+
+		BUG_ON(buffer_id < 0);
+		BUG_ON(buffer_id > KGSL_MAX_GMEM_SHADOW_BUFFERS);
+
+		width = gmem_desc->width;
+		height = gmem_desc->height;
+
+		shadow->width = width;
+		shadow->format = shadow_buffer->format;
+
+		shadow->height = height;
+		shadow->pitch = shadow_buffer->pitch;
+
+		memset(&shadow->gmemshadow, 0, sizeof(struct kgsl_memdesc));
+		shadow->gmemshadow.hostptr = shadow_buffer->hostptr;
+		shadow->gmemshadow.gpuaddr = shadow_buffer->gpuaddr;
+		shadow->gmemshadow.physaddr = shadow->gmemshadow.gpuaddr;
+		shadow->gmemshadow.size = shadow_buffer->size;
+
+		/* Calculate offset */
+		shadow->offset =
+		    (int)(shadow_buffer->pitch) * ((int)shadow_y -
+						   (int)gmem_desc->y) +
+		    (int)shadow_x - (int)gmem_desc->x;
+
+		shadow->offset_x = shadow_x;
+		shadow->offset_y = shadow_y;
+		shadow->gmem_offset_x = gmem_desc->x;
+		shadow->gmem_offset_y = gmem_desc->y;
+
+		shadow->size = shadow->gmemshadow.size;
+
+		shadow->gmem_pitch = gmem_desc->pitch;
+
+		/* Modify quad vertices */
+		set_gmem_copy_quad(shadow);
+
+		/* Idle because we are reading PM override registers */
+		kgsl_yamato_idle(device, KGSL_TIMEOUT_DEFAULT);
+
+		/* Modify commands */
+		build_gmem2sys_cmds(device, drawctxt, NULL, shadow);
+		build_sys2gmem_cmds(device, drawctxt, NULL, shadow);
+
+		/* Release context GMEM shadow if found */
+		if (drawctxt->context_gmem_shadow.gmemshadow.physaddr != 0) {
+			kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.
+					    gmemshadow);
+			drawctxt->context_gmem_shadow.gmemshadow.physaddr = 0;
+		}
+	}
+
+	/* Enable GMEM shadowing if we have any of the user buffers enabled */
+	drawctxt->flags &= ~CTXT_FLAGS_GMEM_SHADOW;
+	for (i = 0; i < KGSL_MAX_GMEM_SHADOW_BUFFERS; i++) {
+		if (drawctxt->user_gmem_shadow[i].gmemshadow.size > 0)
+			drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW;
+	}
+
+	return 0;
+}
+
+/* set bin base offset */
+int kgsl_drawctxt_set_bin_base_offset(struct kgsl_device *device,
+					unsigned int drawctxt_id,
+					unsigned int offset)
+{
+	struct kgsl_drawctxt *drawctxt;
+
+	drawctxt = &device->drawctxt[drawctxt_id];
+
+	drawctxt->bin_base_offset = offset;
+
+	return 0;
+}
+
+/* switch drawing contexts */
+void
+kgsl_drawctxt_switch(struct kgsl_device *device, struct kgsl_drawctxt *drawctxt,
+			unsigned int flags)
+{
+	struct kgsl_drawctxt *active_ctxt = device->drawctxt_active;
+	unsigned int cmds[2];
+
+	if (drawctxt) {
+		/* Set the flag in context so that the save is done
+		 * when this context is switched out. */
+		if (flags & KGSL_CONTEXT_SAVE_GMEM)
+			drawctxt->flags |= CTXT_FLAGS_GMEM_SAVE;
+		else
+			drawctxt->flags &= ~CTXT_FLAGS_GMEM_SAVE;
+	}
+	/* already current? */
+	if (active_ctxt == drawctxt)
+		return;
+
+	KGSL_CTXT_INFO("from %p to %p flags %d\n",
+			device->drawctxt_active, drawctxt, flags);
+	/* save old context*/
+	if (active_ctxt != NULL) {
+		KGSL_CTXT_INFO("active_ctxt flags %08x\n", active_ctxt->flags);
+		/* save registers and constants. */
+		KGSL_CTXT_DBG("save regs");
+		kgsl_ringbuffer_issuecmds(device, 0, active_ctxt->reg_save, 3);
+
+		if (active_ctxt->flags & CTXT_FLAGS_SHADER_SAVE) {
+			/* save shader partitioning and instructions. */
+			KGSL_CTXT_DBG("save shader");
+			kgsl_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
+						  active_ctxt->shader_save, 3);
+
+			/* fixup shader partitioning parameter for
+			 *  SET_SHADER_BASES.
+			 */
+			KGSL_CTXT_DBG("save shader fixup");
+			kgsl_ringbuffer_issuecmds(device, 0,
+					active_ctxt->shader_fixup, 3);
+
+			active_ctxt->flags |= CTXT_FLAGS_SHADER_RESTORE;
+		}
+
+		if (active_ctxt->flags & CTXT_FLAGS_GMEM_SAVE
+			&& active_ctxt->flags & CTXT_FLAGS_GMEM_SHADOW) {
+			/* save gmem.
+			 * (note: changes shader. shader must already be saved.)
+			 */
+			unsigned int i, numbuffers = 0;
+			KGSL_CTXT_DBG("save gmem");
+			for (i = 0; i < KGSL_MAX_GMEM_SHADOW_BUFFERS; i++) {
+				if (active_ctxt->user_gmem_shadow[i].gmemshadow.
+				    size > 0) {
+					kgsl_ringbuffer_issuecmds(device,
+						KGSL_CMD_FLAGS_PMODE,
+					  active_ctxt->user_gmem_shadow[i].
+						gmem_save, 3);
+
+					/* Restore TP0_CHICKEN */
+					kgsl_ringbuffer_issuecmds(device, 0,
+					  active_ctxt->chicken_restore, 3);
+
+					numbuffers++;
+				}
+			}
+			if (numbuffers == 0) {
+				kgsl_ringbuffer_issuecmds(device,
+				    KGSL_CMD_FLAGS_PMODE,
+				    active_ctxt->context_gmem_shadow.gmem_save,
+				    3);
+
+				/* Restore TP0_CHICKEN */
+				kgsl_ringbuffer_issuecmds(device, 0,
+					 active_ctxt->chicken_restore, 3);
+			}
+
+			active_ctxt->flags |= CTXT_FLAGS_GMEM_RESTORE;
+		}
+	}
+
+	device->drawctxt_active = drawctxt;
+
+	/* restore new context */
+	if (drawctxt != NULL) {
+
+		KGSL_CTXT_INFO("drawctxt flags %08x\n", drawctxt->flags);
+		KGSL_CTXT_DBG("restore pagetable");
+		kgsl_mmu_setstate(device, drawctxt->pagetable);
+
+		/* restore gmem.
+		 *  (note: changes shader. shader must not already be restored.)
+		 */
+		if (drawctxt->flags & CTXT_FLAGS_GMEM_RESTORE) {
+			unsigned int i, numbuffers = 0;
+			KGSL_CTXT_DBG("restore gmem");
+
+			for (i = 0; i < KGSL_MAX_GMEM_SHADOW_BUFFERS; i++) {
+				if (drawctxt->user_gmem_shadow[i].gmemshadow.
+				    size > 0) {
+					kgsl_ringbuffer_issuecmds(device,
+						KGSL_CMD_FLAGS_PMODE,
+					  drawctxt->user_gmem_shadow[i].
+						gmem_restore, 3);
+
+					/* Restore TP0_CHICKEN */
+					kgsl_ringbuffer_issuecmds(device, 0,
+					  drawctxt->chicken_restore, 3);
+					numbuffers++;
+				}
+			}
+			if (numbuffers == 0) {
+				kgsl_ringbuffer_issuecmds(device,
+					KGSL_CMD_FLAGS_PMODE,
+				  drawctxt->context_gmem_shadow.gmem_restore,
+					3);
+
+				/* Restore TP0_CHICKEN */
+				kgsl_ringbuffer_issuecmds(device, 0,
+				  drawctxt->chicken_restore, 3);
+			}
+			drawctxt->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
+		}
+
+		/* restore registers and constants. */
+		KGSL_CTXT_DBG("restore regs");
+		kgsl_ringbuffer_issuecmds(device, 0,
+					  drawctxt->reg_restore, 3);
+
+		/* restore shader instructions & partitioning. */
+		if (drawctxt->flags & CTXT_FLAGS_SHADER_RESTORE)
+			KGSL_CTXT_DBG("restore shader");
+		kgsl_ringbuffer_issuecmds(device, 0,
+					  drawctxt->shader_restore, 3);
+
+		cmds[0] = pm4_type3_packet(PM4_SET_BIN_BASE_OFFSET, 1);
+		cmds[1] = drawctxt->bin_base_offset;
+		kgsl_ringbuffer_issuecmds(device, 0, cmds, 2);
+
+	} else
+		kgsl_mmu_setstate(device, device->mmu.defaultpagetable);
+	KGSL_CTXT_INFO("return\n");
+}
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_drawctxt.h b/drivers/video/msm/gpu/kgsl/kgsl_drawctxt.h
new file mode 100644
index 0000000..3090373
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_drawctxt.h
@@ -0,0 +1,120 @@
+/*
+* (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+* Copyright (c) 2008-2009 QUALCOMM USA, INC.
+* 
+* All source code in this file is licensed under the following license
+* 
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+* 
+* This 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.
+* 
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, you can find it at http://www.fsf.org
+*/
+#ifndef __GSL_DRAWCTXT_H
+#define __GSL_DRAWCTXT_H
+
+/* Flags */
+
+#define CTXT_FLAGS_NOT_IN_USE		0x00000000
+#define CTXT_FLAGS_IN_USE			0x00000001
+
+/* state shadow memory allocated */
+#define CTXT_FLAGS_STATE_SHADOW		0x00000010
+
+/* gmem shadow memory allocated */
+#define CTXT_FLAGS_GMEM_SHADOW		0x00000100
+/* gmem must be copied to shadow */
+#define CTXT_FLAGS_GMEM_SAVE		0x00000200
+/* gmem can be restored from shadow */
+#define CTXT_FLAGS_GMEM_RESTORE		0x00000400
+/* shader must be copied to shadow */
+#define CTXT_FLAGS_SHADER_SAVE		0x00002000
+/* shader can be restored from shadow */
+#define CTXT_FLAGS_SHADER_RESTORE	0x00004000
+
+#include "kgsl_sharedmem.h"
+#include "yamato_reg.h"
+
+#define KGSL_MAX_GMEM_SHADOW_BUFFERS	2
+
+struct kgsl_device;
+
+/*  types */
+
+/* draw context */
+struct gmem_shadow_t {
+	struct kgsl_memdesc gmemshadow;	/* Shadow buffer address */
+
+	/* 256 KB GMEM surface = 4 bytes-per-pixel x 256 pixels/row x
+	* 256 rows. */
+	/* width & height must be a multiples of 32, in case tiled textures
+	 * are used. */
+	enum COLORFORMATX format;
+	unsigned int size;	/* Size of surface used to store GMEM */
+	unsigned int width;	/* Width of surface used to store GMEM */
+	unsigned int height;	/* Height of surface used to store GMEM */
+	unsigned int pitch;	/* Pitch of surface used to store GMEM */
+	int offset;
+	unsigned int offset_x;
+	unsigned int offset_y;
+	unsigned int gmem_offset_x;
+	unsigned int gmem_offset_y;
+	unsigned int gmem_pitch;	/* Pitch value used for GMEM */
+	unsigned int *gmem_save_commands;
+	unsigned int *gmem_restore_commands;
+	unsigned int gmem_save[3];
+	unsigned int gmem_restore[3];
+	struct kgsl_memdesc quad_vertices;
+	struct kgsl_memdesc quad_texcoords;
+};
+
+struct kgsl_drawctxt {
+	uint32_t         flags;
+	struct kgsl_pagetable *pagetable;
+	struct kgsl_memdesc       gpustate;
+	unsigned int        reg_save[3];
+	unsigned int        reg_restore[3];
+	unsigned int        shader_save[3];
+	unsigned int        shader_fixup[3];
+	unsigned int        shader_restore[3];
+	unsigned int		chicken_restore[3];
+	unsigned int 	    bin_base_offset;
+	/* Information of the GMEM shadow that is created in context create */
+	struct gmem_shadow_t context_gmem_shadow;
+	/* User defined GMEM shadow buffers */
+	struct gmem_shadow_t user_gmem_shadow[KGSL_MAX_GMEM_SHADOW_BUFFERS];
+};
+
+
+int kgsl_drawctxt_create(struct kgsl_device *, struct kgsl_pagetable *,
+			  unsigned int flags,
+			  unsigned int *drawctxt_id);
+
+int kgsl_drawctxt_destroy(struct kgsl_device *device, unsigned int drawctxt_id);
+
+int kgsl_drawctxt_init(struct kgsl_device *device);
+
+int kgsl_drawctxt_close(struct kgsl_device *device);
+
+void kgsl_drawctxt_switch(struct kgsl_device *device,
+				struct kgsl_drawctxt *drawctxt,
+				unsigned int flags);
+int kgsl_drawctxt_bind_gmem_shadow(struct kgsl_device *device,
+			unsigned int drawctxt_id,
+			const struct kgsl_gmem_desc *gmem_desc,
+			unsigned int shadow_x,
+			unsigned int shadow_y,
+			const struct kgsl_buffer_desc
+			*shadow_buffer, unsigned int buffer_id);
+
+int kgsl_drawctxt_set_bin_base_offset(struct kgsl_device *device,
+					unsigned int drawctxt_id,
+					unsigned int offset);
+
+#endif  /* __GSL_DRAWCTXT_H */
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_log.c b/drivers/video/msm/gpu/kgsl/kgsl_log.c
new file mode 100644
index 0000000..6308087
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_log.c
@@ -0,0 +1,292 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2008
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#include <linux/debugfs.h>
+#include "kgsl_log.h"
+#include "kgsl_ringbuffer.h"
+#include "kgsl_device.h"
+#include "kgsl.h"
+
+/*default log levels is error for everything*/
+#define KGSL_LOG_LEVEL_DEFAULT 3
+#define KGSL_LOG_LEVEL_MAX     7
+unsigned int kgsl_drv_log = KGSL_LOG_LEVEL_DEFAULT;
+unsigned int kgsl_cmd_log = KGSL_LOG_LEVEL_DEFAULT;
+unsigned int kgsl_ctxt_log = KGSL_LOG_LEVEL_DEFAULT;
+unsigned int kgsl_mem_log = KGSL_LOG_LEVEL_DEFAULT;
+
+unsigned int kgsl_cache_enable;
+
+#ifdef CONFIG_DEBUG_FS
+static int kgsl_log_set(unsigned int *log_val, void *data, u64 val)
+{
+	*log_val = min((unsigned int)val, (unsigned int)KGSL_LOG_LEVEL_MAX);
+	return 0;
+}
+
+static int kgsl_drv_log_set(void *data, u64 val)
+{
+	return kgsl_log_set(&kgsl_drv_log, data, val);
+}
+
+static int kgsl_drv_log_get(void *data, u64 *val)
+{
+	*val = kgsl_drv_log;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(kgsl_drv_log_fops, kgsl_drv_log_get,
+			kgsl_drv_log_set, "%llu\n");
+
+static int kgsl_cmd_log_set(void *data, u64 val)
+{
+	return kgsl_log_set(&kgsl_cmd_log, data, val);
+}
+
+static int kgsl_cmd_log_get(void *data, u64 *val)
+{
+	*val = kgsl_cmd_log;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(kgsl_cmd_log_fops, kgsl_cmd_log_get,
+			kgsl_cmd_log_set, "%llu\n");
+
+static int kgsl_ctxt_log_set(void *data, u64 val)
+{
+	return kgsl_log_set(&kgsl_ctxt_log, data, val);
+}
+
+static int kgsl_ctxt_log_get(void *data, u64 *val)
+{
+	*val = kgsl_ctxt_log;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(kgsl_ctxt_log_fops, kgsl_ctxt_log_get,
+			kgsl_ctxt_log_set, "%llu\n");
+
+static int kgsl_mem_log_set(void *data, u64 val)
+{
+	return kgsl_log_set(&kgsl_mem_log, data, val);
+}
+
+static int kgsl_mem_log_get(void *data, u64 *val)
+{
+	*val = kgsl_mem_log;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(kgsl_mem_log_fops, kgsl_mem_log_get,
+			kgsl_mem_log_set, "%llu\n");
+
+#ifdef DEBUG
+static ssize_t rb_regs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t rb_regs_read(struct file *file, char __user *buf, size_t count,
+				loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct kgsl_device *device = NULL;
+	struct kgsl_ringbuffer *rb = NULL;
+	struct kgsl_rb_debug rb_debug;
+
+	device = &kgsl_driver.yamato_device;
+
+	rb = &device->ringbuffer;
+
+	kgsl_ringbuffer_debug(rb, &rb_debug);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rbbm_status %08x mem_rptr %08x mem_wptr_poll %08x\n",
+			rb_debug.rbbm_status,
+			rb_debug.mem_rptr,
+			rb_debug.mem_wptr_poll);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rb_base %08x rb_cntl %08x rb_rptr_addr %08x"
+			" rb_rptr %08x rb_rptr_wr %08x\n",
+			rb_debug.cp_rb_base,
+			rb_debug.cp_rb_cntl,
+			rb_debug.cp_rb_rptr_addr,
+			rb_debug.cp_rb_rptr,
+			rb_debug.cp_rb_rptr_wr);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rb_wptr %08x rb_wptr_delay %08x rb_wptr_base %08x"
+			" ib1_base %08x ib1_bufsz %08x\n",
+			rb_debug.cp_rb_wptr,
+			rb_debug.cp_rb_wptr_delay,
+			rb_debug.cp_rb_wptr_base,
+			rb_debug.cp_ib1_base,
+			rb_debug.cp_ib1_bufsz);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"ib2_base  %08x ib2_bufsz %08x st_base %08x"
+			" st_bufsz %08x cp_me_cntl %08x cp_me_status %08x\n",
+			rb_debug.cp_ib2_base,
+			rb_debug.cp_ib2_bufsz,
+			rb_debug.cp_st_base,
+			rb_debug.cp_st_bufsz,
+			rb_debug.cp_me_cntl,
+			rb_debug.cp_me_status);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"csq_cp_rb %08x csq_cp_ib1 %08x csq_cp_ib2 %08x\n",
+			rb_debug.cp_csq_rb_stat,
+			rb_debug.cp_csq_ib1_stat,
+			rb_debug.cp_csq_ib2_stat);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"cp_debug %08x cp_stat %08x cp_int_status %08x"
+			" cp_int_cntl %08x\n",
+			rb_debug.cp_debug,
+			rb_debug.cp_stat,
+			rb_debug.cp_int_status,
+			rb_debug.cp_int_cntl);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"sop_timestamp: %0d eop_timestamp: %d\n",
+			rb_debug.sop_timestamp,
+			rb_debug.eop_timestamp);
+	n++;
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static struct file_operations kgsl_rb_regs_fops = {
+	.read = rb_regs_read,
+	.open = rb_regs_open,
+};
+#endif /*DEBUG*/
+
+#ifdef DEBUG
+static ssize_t mmu_regs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t mmu_regs_read(struct file *file, char __user *buf, size_t count,
+				loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct kgsl_device *device = NULL;
+	struct kgsl_mmu *mmu = NULL;
+	struct kgsl_mmu_debug mmu_debug;
+
+	device = &kgsl_driver.yamato_device;
+
+	mmu = &device->mmu;
+
+	kgsl_mmu_debug(mmu, &mmu_debug);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"config %08x mpu_base %08x mpu_end %08x\n",
+			mmu_debug.config,
+			mmu_debug.mpu_base,
+			mmu_debug.mpu_end);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"va_range %08x pt_base %08x\n",
+			mmu_debug.va_range,
+			mmu_debug.pt_base);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"page_fault %08x trans_error %08x axi_error %08x\n",
+			mmu_debug.page_fault,
+			mmu_debug.trans_error,
+			mmu_debug.axi_error);
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"interrupt_mask %08x interrupt_status %08x\n",
+			mmu_debug.interrupt_mask,
+			mmu_debug.interrupt_status);
+
+	n++;
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static struct file_operations kgsl_mmu_regs_fops = {
+	.read = mmu_regs_read,
+	.open = mmu_regs_open,
+};
+#endif /*DEBUG*/
+
+#ifdef CONFIG_MSM_KGSL_MMU
+static int kgsl_cache_enable_set(void *data, u64 val)
+{
+	kgsl_cache_enable = (val != 0);
+	return 0;
+}
+
+static int kgsl_cache_enable_get(void *data, u64 *val)
+{
+	*val = kgsl_cache_enable;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(kgsl_cache_enable_fops, kgsl_cache_enable_get,
+			kgsl_cache_enable_set, "%llu\n");
+#endif
+
+#endif /* CONFIG_DEBUG_FS */
+
+int kgsl_debug_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dent;
+	dent = debugfs_create_dir("kgsl", 0);
+	if (IS_ERR(dent))
+		return 0;
+
+	debugfs_create_file("log_level_cmd", 0644, dent, 0,
+				&kgsl_cmd_log_fops);
+	debugfs_create_file("log_level_ctxt", 0644, dent, 0,
+				&kgsl_ctxt_log_fops);
+	debugfs_create_file("log_level_drv", 0644, dent, 0,
+				&kgsl_drv_log_fops);
+	debugfs_create_file("log_level_mem", 0644, dent, 0,
+				&kgsl_mem_log_fops);
+#ifdef DEBUG
+	debugfs_create_file("rb_regs", 0444, dent, 0,
+				&kgsl_rb_regs_fops);
+#endif
+
+#ifdef DEBUG
+	debugfs_create_file("mmu_regs", 0444, dent, 0,
+				&kgsl_mmu_regs_fops);
+#endif
+
+#ifdef CONFIG_MSM_KGSL_MMU
+	debugfs_create_file("cache_enable", 0644, dent, 0,
+			    &kgsl_cache_enable_fops);
+#endif
+
+#endif /* CONFIG_DEBUG_FS */
+	return 0;
+}
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_log.h b/drivers/video/msm/gpu/kgsl/kgsl_log.h
new file mode 100644
index 0000000..3869ff7
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_log.h
@@ -0,0 +1,105 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2008
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#ifndef _GSL_LOG_H
+#define _GSL_LOG_H
+
+#include <linux/bug.h>
+#include <linux/types.h>
+#include <linux/msm_kgsl.h>
+#include <linux/device.h>
+
+extern unsigned int kgsl_drv_log;
+extern unsigned int kgsl_cmd_log;
+extern unsigned int kgsl_ctxt_log;
+extern unsigned int kgsl_mem_log;
+
+struct device *kgsl_driver_getdevnode(void);
+int kgsl_debug_init(void);
+
+#define KGSL_LOG_VDBG(lvl, fmt, args...) \
+	do { \
+		if ((lvl) >= 7)  \
+			dev_vdbg(kgsl_driver_getdevnode(), "|%s| " fmt, \
+					__func__, ##args);\
+	} while (0)
+
+#define KGSL_LOG_DBG(lvl, fmt, args...) \
+	do { \
+		if ((lvl) >= 7)  \
+			dev_dbg(kgsl_driver_getdevnode(), "|%s| " fmt, \
+					__func__, ##args);\
+	} while (0)
+
+#define KGSL_LOG_INFO(lvl, fmt, args...) \
+	do { \
+		if ((lvl) >= 6)  \
+			dev_info(kgsl_driver_getdevnode(), "|%s| " fmt, \
+					__func__, ##args);\
+	} while (0)
+
+#define KGSL_LOG_WARN(lvl, fmt, args...) \
+	do { \
+		if ((lvl) >= 4)  \
+			dev_warn(kgsl_driver_getdevnode(), "|%s| " fmt, \
+					__func__, ##args);\
+	} while (0)
+
+#define KGSL_LOG_ERR(lvl, fmt, args...) \
+	do { \
+		if ((lvl) >= 3)  \
+			dev_err(kgsl_driver_getdevnode(), "|%s| " fmt, \
+					__func__, ##args);\
+	} while (0)
+
+#define KGSL_LOG_FATAL(lvl, fmt, args...) \
+	do { \
+		if ((lvl) >= 2) \
+			dev_crit(kgsl_driver_getdevnode(), "|%s| " fmt, \
+					__func__, ##args);\
+	} while (0)
+
+#define KGSL_DRV_VDBG(fmt, args...) KGSL_LOG_VDBG(kgsl_drv_log, fmt, ##args)
+#define KGSL_DRV_DBG(fmt, args...)  KGSL_LOG_DBG(kgsl_drv_log, fmt, ##args)
+#define KGSL_DRV_INFO(fmt, args...) KGSL_LOG_INFO(kgsl_drv_log, fmt, ##args)
+#define KGSL_DRV_WARN(fmt, args...) KGSL_LOG_WARN(kgsl_drv_log, fmt, ##args)
+#define KGSL_DRV_ERR(fmt, args...)  KGSL_LOG_ERR(kgsl_drv_log, fmt, ##args)
+#define KGSL_DRV_FATAL(fmt, args...) KGSL_LOG_FATAL(kgsl_drv_log, fmt, ##args)
+
+#define KGSL_CMD_VDBG(fmt, args...) KGSL_LOG_VDBG(kgsl_cmd_log, fmt, ##args)
+#define KGSL_CMD_DBG(fmt, args...)  KGSL_LOG_DBG(kgsl_cmd_log, fmt, ##args)
+#define KGSL_CMD_INFO(fmt, args...) KGSL_LOG_INFO(kgsl_cmd_log, fmt, ##args)
+#define KGSL_CMD_WARN(fmt, args...) KGSL_LOG_WARN(kgsl_cmd_log, fmt, ##args)
+#define KGSL_CMD_ERR(fmt, args...)  KGSL_LOG_ERR(kgsl_cmd_log, fmt, ##args)
+#define KGSL_CMD_FATAL(fmt, args...) KGSL_LOG_FATAL(kgsl_cmd_log, fmt, ##args)
+
+#define KGSL_CTXT_VDBG(fmt, args...) KGSL_LOG_VDBG(kgsl_ctxt_log, fmt, ##args)
+#define KGSL_CTXT_DBG(fmt, args...)  KGSL_LOG_DBG(kgsl_ctxt_log, fmt, ##args)
+#define KGSL_CTXT_INFO(fmt, args...) KGSL_LOG_INFO(kgsl_ctxt_log, fmt, ##args)
+#define KGSL_CTXT_WARN(fmt, args...) KGSL_LOG_WARN(kgsl_ctxt_log, fmt, ##args)
+#define KGSL_CTXT_ERR(fmt, args...)  KGSL_LOG_ERR(kgsl_ctxt_log, fmt, ##args)
+#define KGSL_CTXT_FATAL(fmt, args...) KGSL_LOG_FATAL(kgsl_ctxt_log, fmt, ##args)
+
+#define KGSL_MEM_VDBG(fmt, args...) KGSL_LOG_VDBG(kgsl_mem_log, fmt, ##args)
+#define KGSL_MEM_DBG(fmt, args...)  KGSL_LOG_DBG(kgsl_mem_log, fmt, ##args)
+#define KGSL_MEM_INFO(fmt, args...) KGSL_LOG_INFO(kgsl_mem_log, fmt, ##args)
+#define KGSL_MEM_WARN(fmt, args...) KGSL_LOG_WARN(kgsl_mem_log, fmt, ##args)
+#define KGSL_MEM_ERR(fmt, args...)  KGSL_LOG_ERR(kgsl_mem_log, fmt, ##args)
+#define KGSL_MEM_FATAL(fmt, args...) KGSL_LOG_FATAL(kgsl_mem_log, fmt, ##args)
+
+#endif /* _GSL_LOG_H */
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_mmu.c b/drivers/video/msm/gpu/kgsl/kgsl_mmu.c
new file mode 100644
index 0000000..c32558f
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_mmu.c
@@ -0,0 +1,664 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+
+#include "kgsl_mmu.h"
+#include "kgsl.h"
+#include "kgsl_log.h"
+#include "yamato_reg.h"
+
+struct kgsl_pte_debug {
+	unsigned int read:1;
+	unsigned int write:1;
+	unsigned int dirty:1;
+	unsigned int reserved:9;
+	unsigned int phyaddr:20;
+};
+
+#define GSL_PTE_SIZE	4
+#define GSL_PT_EXTRA_ENTRIES	16
+
+
+#define GSL_PT_PAGE_BITS_MASK	0x00000007
+#define GSL_PT_PAGE_ADDR_MASK	(~(KGSL_PAGESIZE - 1))
+
+#define GSL_MMU_INT_MASK \
+	(MH_INTERRUPT_MASK__AXI_READ_ERROR | \
+	 MH_INTERRUPT_MASK__AXI_WRITE_ERROR)
+
+uint32_t kgsl_pt_entry_get(struct kgsl_pagetable *pt, uint32_t va)
+{
+	return (va - pt->va_base) >> KGSL_PAGESIZE_SHIFT;
+}
+
+uint32_t kgsl_pt_map_get(struct kgsl_pagetable *pt, uint32_t pte)
+{
+	uint32_t *baseptr = (uint32_t *)pt->base.hostptr;
+	return baseptr[pte];
+}
+
+void kgsl_pt_map_set(struct kgsl_pagetable *pt, uint32_t pte, uint32_t val)
+{
+	uint32_t *baseptr = (uint32_t *)pt->base.hostptr;
+	baseptr[pte] = val;
+}
+#define GSL_PT_MAP_DEBUG(pte)	((struct kgsl_pte_debug *) \
+		&gsl_pt_map_get(pagetable, pte))
+
+void kgsl_pt_map_setbits(struct kgsl_pagetable *pt, uint32_t pte, uint32_t bits)
+{
+	uint32_t *baseptr = (uint32_t *)pt->base.hostptr;
+	baseptr[pte] |= bits;
+}
+
+void kgsl_pt_map_setaddr(struct kgsl_pagetable *pt, uint32_t pte,
+					uint32_t pageaddr)
+{
+	uint32_t *baseptr = (uint32_t *)pt->base.hostptr;
+	uint32_t val = baseptr[pte];
+	val &= ~GSL_PT_PAGE_ADDR_MASK;
+	val |= (pageaddr & GSL_PT_PAGE_ADDR_MASK);
+	baseptr[pte] = val;
+}
+
+void kgsl_pt_map_resetall(struct kgsl_pagetable *pt, uint32_t pte)
+{
+	uint32_t *baseptr = (uint32_t *)pt->base.hostptr;
+	baseptr[pte] &= GSL_PT_PAGE_DIRTY;
+}
+
+void kgsl_pt_map_resetbits(struct kgsl_pagetable *pt, uint32_t pte,
+				uint32_t bits)
+{
+	uint32_t *baseptr = (uint32_t *)pt->base.hostptr;
+	baseptr[pte] &= ~(bits & GSL_PT_PAGE_BITS_MASK);
+}
+
+int kgsl_pt_map_isdirty(struct kgsl_pagetable *pt, uint32_t pte)
+{
+	uint32_t *baseptr = (uint32_t *)pt->base.hostptr;
+	return baseptr[pte] & GSL_PT_PAGE_DIRTY;
+}
+
+uint32_t kgsl_pt_map_getaddr(struct kgsl_pagetable *pt, uint32_t pte)
+{
+	uint32_t *baseptr = (uint32_t *)pt->base.hostptr;
+	return baseptr[pte] & GSL_PT_PAGE_ADDR_MASK;
+}
+
+void kgsl_mh_intrcallback(struct kgsl_device *device)
+{
+	unsigned int status = 0;
+	unsigned int reg;
+	unsigned int axi_error;
+	struct kgsl_mmu_debug dbg;
+
+	KGSL_MEM_VDBG("enter (device=%p)\n", device);
+
+	kgsl_yamato_regread(device, REG_MH_INTERRUPT_STATUS, &status);
+
+	if (status & MH_INTERRUPT_MASK__AXI_READ_ERROR) {
+		kgsl_yamato_regread(device, REG_MH_AXI_ERROR, &axi_error);
+		KGSL_MEM_FATAL("axi read error interrupt (%08x)\n", axi_error);
+		kgsl_mmu_debug(&device->mmu, &dbg);
+	} else if (status & MH_INTERRUPT_MASK__AXI_WRITE_ERROR) {
+		kgsl_yamato_regread(device, REG_MH_AXI_ERROR, &axi_error);
+		KGSL_MEM_FATAL("axi write error interrupt (%08x)\n", axi_error);
+		kgsl_mmu_debug(&device->mmu, &dbg);
+	} else if (status & MH_INTERRUPT_MASK__MMU_PAGE_FAULT) {
+		kgsl_yamato_regread(device, REG_MH_MMU_PAGE_FAULT, &reg);
+		KGSL_MEM_FATAL("mmu page fault interrupt: %08x\n", reg);
+		kgsl_mmu_debug(&device->mmu, &dbg);
+	} else {
+		KGSL_MEM_DBG("bad bits in REG_MH_INTERRUPT_STATUS %08x\n",
+			     status);
+	}
+
+	kgsl_yamato_regwrite(device, REG_MH_INTERRUPT_CLEAR, status);
+
+	/*TODO: figure out how to handle errror interupts.
+	* specifically, page faults should probably nuke the client that
+	* caused them, but we don't have enough info to figure that out yet.
+	*/
+
+	KGSL_MEM_VDBG("return\n");
+}
+
+#ifdef DEBUG
+void kgsl_mmu_debug(struct kgsl_mmu *mmu, struct kgsl_mmu_debug *regs)
+{
+	memset(regs, 0, sizeof(struct kgsl_mmu_debug));
+
+	kgsl_yamato_regread(mmu->device, REG_MH_MMU_CONFIG,
+			    &regs->config);
+	kgsl_yamato_regread(mmu->device, REG_MH_MMU_MPU_BASE,
+			    &regs->mpu_base);
+	kgsl_yamato_regread(mmu->device, REG_MH_MMU_MPU_END,
+			    &regs->mpu_end);
+	kgsl_yamato_regread(mmu->device, REG_MH_MMU_VA_RANGE,
+			    &regs->va_range);
+	kgsl_yamato_regread(mmu->device, REG_MH_MMU_PT_BASE,
+			    &regs->pt_base);
+	kgsl_yamato_regread(mmu->device, REG_MH_MMU_PAGE_FAULT,
+			    &regs->page_fault);
+	kgsl_yamato_regread(mmu->device, REG_MH_MMU_TRAN_ERROR,
+			    &regs->trans_error);
+	kgsl_yamato_regread(mmu->device, REG_MH_AXI_ERROR,
+			    &regs->axi_error);
+	kgsl_yamato_regread(mmu->device, REG_MH_INTERRUPT_MASK,
+			    &regs->interrupt_mask);
+	kgsl_yamato_regread(mmu->device, REG_MH_INTERRUPT_STATUS,
+			    &regs->interrupt_status);
+
+	KGSL_MEM_DBG("mmu config %08x mpu_base %08x mpu_end %08x\n",
+		     regs->config, regs->mpu_base, regs->mpu_end);
+	KGSL_MEM_DBG("mmu va_range %08x pt_base %08x \n",
+		     regs->va_range, regs->pt_base);
+	KGSL_MEM_DBG("mmu page_fault %08x tran_err %08x\n",
+		     regs->page_fault, regs->trans_error);
+	KGSL_MEM_DBG("mmu int mask %08x int status %08x\n",
+			regs->interrupt_mask, regs->interrupt_status);
+}
+#endif
+
+struct kgsl_pagetable *kgsl_mmu_createpagetableobject(struct kgsl_mmu *mmu)
+{
+	int status = 0;
+	struct kgsl_pagetable *pagetable = NULL;
+	uint32_t flags;
+
+	KGSL_MEM_VDBG("enter (mmu=%p)\n", mmu);
+
+	pagetable = kzalloc(sizeof(struct kgsl_pagetable), GFP_KERNEL);
+	if (pagetable == NULL) {
+		KGSL_MEM_ERR("Unable to allocate pagetable object.\n");
+		return NULL;
+	}
+
+	pagetable->mmu = mmu;
+	pagetable->va_base = mmu->va_base;
+	pagetable->va_range = mmu->va_range;
+	pagetable->last_superpte = 0;
+	pagetable->max_entries = (mmu->va_range >> KGSL_PAGESIZE_SHIFT)
+				 + GSL_PT_EXTRA_ENTRIES;
+
+	pagetable->pool = gen_pool_create(KGSL_PAGESIZE_SHIFT, -1);
+	if (pagetable->pool == NULL) {
+		KGSL_MEM_ERR("Unable to allocate virtualaddr pool.\n");
+		goto err_gen_pool_create;
+	}
+
+	if (gen_pool_add(pagetable->pool, pagetable->va_base,
+				pagetable->va_range, -1)) {
+		KGSL_MEM_ERR("gen_pool_create failed for pagetable %p\n",
+				pagetable);
+		goto err_gen_pool_add;
+	}
+
+	/* allocate page table memory */
+	flags = (KGSL_MEMFLAGS_ALIGN4K | KGSL_MEMFLAGS_CONPHYS
+		 | KGSL_MEMFLAGS_STRICTREQUEST);
+	status = kgsl_sharedmem_alloc(flags,
+				      pagetable->max_entries * GSL_PTE_SIZE,
+				      &pagetable->base);
+
+	if (status) {
+		KGSL_MEM_ERR("cannot alloc page tables\n");
+		goto err_kgsl_sharedmem_alloc;
+	}
+
+	/* reset page table entries
+	 * -- all pte's are marked as not dirty initially
+	 */
+	kgsl_sharedmem_set(&pagetable->base, 0, 0, pagetable->base.size);
+	pagetable->base.gpuaddr = pagetable->base.physaddr;
+
+	KGSL_MEM_VDBG("return %p\n", pagetable);
+
+	return pagetable;
+
+err_kgsl_sharedmem_alloc:
+err_gen_pool_add:
+	gen_pool_destroy(pagetable->pool);
+err_gen_pool_create:
+	kfree(pagetable);
+	return NULL;
+}
+
+int kgsl_mmu_destroypagetableobject(struct kgsl_pagetable *pagetable)
+{
+	KGSL_MEM_VDBG("enter (pagetable=%p)\n", pagetable);
+
+	if (pagetable) {
+		if (pagetable->base.gpuaddr)
+			kgsl_sharedmem_free(&pagetable->base);
+
+		if (pagetable->pool) {
+			gen_pool_destroy(pagetable->pool);
+			pagetable->pool = NULL;
+		}
+
+		kfree(pagetable);
+
+	}
+	KGSL_MEM_VDBG("return 0x%08x\n", 0);
+
+	return 0;
+}
+
+int kgsl_mmu_setstate(struct kgsl_device *device,
+				struct kgsl_pagetable *pagetable)
+{
+	int status = 0;
+	struct kgsl_mmu *mmu = &device->mmu;
+
+	KGSL_MEM_VDBG("enter (device=%p, pagetable=%p)\n", device, pagetable);
+
+	if (mmu->flags & KGSL_FLAGS_STARTED) {
+		/* page table not current, then setup mmu to use new
+		 *  specified page table
+		 */
+		KGSL_MEM_INFO("from %p to %p\n", mmu->hwpagetable, pagetable);
+		if (mmu->hwpagetable != pagetable) {
+			mmu->hwpagetable = pagetable;
+
+			/* call device specific set page table */
+			status = kgsl_yamato_setstate(mmu->device,
+				KGSL_MMUFLAGS_TLBFLUSH |
+				KGSL_MMUFLAGS_PTUPDATE);
+		}
+	}
+
+	KGSL_MEM_VDBG("return %d\n", status);
+
+	return status;
+}
+
+int kgsl_mmu_init(struct kgsl_device *device)
+{
+	/*
+	 * intialize device mmu
+	 *
+	 * call this with the global lock held
+	 */
+	int status;
+	uint32_t flags;
+	struct kgsl_mmu *mmu = &device->mmu;
+#ifdef _DEBUG
+	struct kgsl_mmu_debug regs;
+#endif /* _DEBUG */
+
+	KGSL_MEM_VDBG("enter (device=%p)\n", device);
+
+	if (mmu->flags & KGSL_FLAGS_INITIALIZED0) {
+		KGSL_MEM_INFO("MMU already initialized.\n");
+		return 0;
+	}
+
+	mmu->device = device;
+
+#ifndef CONFIG_MSM_KGSL_MMU
+	mmu->config = 0x00000000;
+#endif
+
+	/* setup MMU and sub-client behavior */
+	kgsl_yamato_regwrite(device, REG_MH_MMU_CONFIG, mmu->config);
+
+	/* enable axi interrupts */
+	KGSL_MEM_DBG("enabling mmu interrupts mask=0x%08lx\n",
+		     GSL_MMU_INT_MASK);
+	kgsl_yamato_regwrite(device, REG_MH_INTERRUPT_MASK, GSL_MMU_INT_MASK);
+
+	mmu->flags |= KGSL_FLAGS_INITIALIZED0;
+
+	/* MMU not enabled */
+	if ((mmu->config & 0x1) == 0) {
+		KGSL_MEM_VDBG("return %d\n", 0);
+		return 0;
+	}
+
+	/* idle device */
+	kgsl_yamato_idle(device, KGSL_TIMEOUT_DEFAULT);
+
+	/* make sure aligned to pagesize */
+	BUG_ON(mmu->mpu_base & (KGSL_PAGESIZE - 1));
+	BUG_ON((mmu->mpu_base + mmu->mpu_range) & (KGSL_PAGESIZE - 1));
+
+	/* define physical memory range accessible by the core */
+	kgsl_yamato_regwrite(device, REG_MH_MMU_MPU_BASE,
+				mmu->mpu_base);
+	kgsl_yamato_regwrite(device, REG_MH_MMU_MPU_END,
+				mmu->mpu_base + mmu->mpu_range);
+
+	/* enable axi interrupts */
+	KGSL_MEM_DBG("enabling mmu interrupts mask=0x%08lx\n",
+		     GSL_MMU_INT_MASK | MH_INTERRUPT_MASK__MMU_PAGE_FAULT);
+	kgsl_yamato_regwrite(device, REG_MH_INTERRUPT_MASK,
+			GSL_MMU_INT_MASK | MH_INTERRUPT_MASK__MMU_PAGE_FAULT);
+
+	mmu->flags |= KGSL_FLAGS_INITIALIZED;
+
+	/* sub-client MMU lookups require address translation */
+	if ((mmu->config & ~0x1) > 0) {
+		/*make sure virtual address range is a multiple of 64Kb */
+		BUG_ON(mmu->va_range & ((1 << 16) - 1));
+
+		/* allocate memory used for completing r/w operations that
+		 * cannot be mapped by the MMU
+		 */
+		flags = (KGSL_MEMFLAGS_ALIGN4K | KGSL_MEMFLAGS_CONPHYS
+			 | KGSL_MEMFLAGS_STRICTREQUEST);
+		status = kgsl_sharedmem_alloc(flags, 64, &mmu->dummyspace);
+		if (status != 0) {
+			KGSL_MEM_ERR
+			    ("Unable to allocate dummy space memory.\n");
+			kgsl_mmu_close(device);
+			return status;
+		}
+
+		kgsl_sharedmem_set(&mmu->dummyspace, 0, 0,
+				   mmu->dummyspace.size);
+		/* TRAN_ERROR needs a 32 byte (32 byte aligned) chunk of memory
+		 * to complete transactions in case of an MMU fault. Note that
+		 * we'll leave the bottom 32 bytes of the dummyspace for other
+		 * purposes (e.g. use it when dummy read cycles are needed
+		 * for other blocks */
+		kgsl_yamato_regwrite(device,
+				     REG_MH_MMU_TRAN_ERROR,
+				     mmu->dummyspace.physaddr + 32);
+
+		mmu->defaultpagetable = kgsl_mmu_createpagetableobject(mmu);
+		if (!mmu->defaultpagetable) {
+			KGSL_MEM_ERR("Failed to create global page table\n");
+			kgsl_mmu_close(device);
+			return -ENOMEM;
+		}
+		mmu->hwpagetable = mmu->defaultpagetable;
+		kgsl_yamato_regwrite(device, REG_MH_MMU_PT_BASE,
+					mmu->hwpagetable->base.gpuaddr);
+		kgsl_yamato_regwrite(device, REG_MH_MMU_VA_RANGE,
+				(mmu->hwpagetable->va_base |
+				(mmu->hwpagetable->va_range >> 16)));
+		status = kgsl_yamato_setstate(device, KGSL_MMUFLAGS_TLBFLUSH);
+		if (status) {
+			kgsl_mmu_close(device);
+			return status;
+		}
+
+		mmu->flags |= KGSL_FLAGS_STARTED;
+	}
+
+	KGSL_MEM_VDBG("return %d\n", 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_MSM_KGSL_MMU
+pte_t *kgsl_get_pte_from_vaddr(unsigned int vaddr)
+{
+	pgd_t *pgd_ptr = NULL;
+	pmd_t *pmd_ptr = NULL;
+	pte_t *pte_ptr = NULL;
+
+	pgd_ptr = pgd_offset(current->mm, vaddr);
+	if (pgd_none(*pgd) || pgd_bad(*pgd)) {
+		KGSL_MEM_ERR
+		    ("Invalid pgd entry found while trying to convert virtual "
+		     "address to physical\n");
+		return 0;
+	}
+
+	pmd_ptr = pmd_offset(pgd_ptr, vaddr);
+	if (pmd_none(*pmd_ptr) || pmd_bad(*pmd_ptr)) {
+		KGSL_MEM_ERR
+		    ("Invalid pmd entry found while trying to convert virtual "
+		     "address to physical\n");
+		return 0;
+	}
+
+	pte_ptr = pte_offset_map(pmd_ptr, vaddr);
+	if (!pte_ptr) {
+		KGSL_MEM_ERR
+		    ("Unable to map pte entry while trying to convert virtual "
+		     "address to physical\n");
+		return 0;
+	}
+	return pte_ptr;
+}
+
+int kgsl_mmu_map(struct kgsl_pagetable *pagetable,
+				unsigned int address,
+				int range,
+				unsigned int protflags,
+				unsigned int *gpuaddr,
+				unsigned int flags)
+{
+	int numpages;
+	unsigned int pte, superpte, ptefirst, ptelast, physaddr;
+	int flushtlb, alloc_size;
+	struct kgsl_mmu *mmu = NULL;
+	int phys_contiguous = flags & KGSL_MEMFLAGS_CONPHYS;
+	unsigned int align = flags & KGSL_MEMFLAGS_ALIGN_MASK;
+
+	KGSL_MEM_VDBG("enter (pt=%p, physaddr=%08x, range=%08d, gpuaddr=%p)\n",
+		      pagetable, address, range, gpuaddr);
+
+	mmu = pagetable->mmu;
+
+	BUG_ON(mmu == NULL);
+	BUG_ON(protflags & ~(GSL_PT_PAGE_RV | GSL_PT_PAGE_WV));
+	BUG_ON(protflags == 0);
+	BUG_ON(range <= 0);
+
+	/* Only support 4K and 8K alignment for now */
+	if (align != KGSL_MEMFLAGS_ALIGN8K && align != KGSL_MEMFLAGS_ALIGN4K) {
+		KGSL_MEM_ERR("Cannot map memory according to "
+			     "requested flags: %08x\n", flags);
+		return -EINVAL;
+	}
+
+	/* Make sure address being mapped is at 4K boundary */
+	if (!IS_ALIGNED(address, KGSL_PAGESIZE) || range & ~KGSL_PAGEMASK) {
+		KGSL_MEM_ERR("Cannot map address not aligned "
+			     "at page boundary: address: %08x, range: %08x\n",
+			     address, range);
+		return -EINVAL;
+	}
+	alloc_size = range;
+	if (align == KGSL_MEMFLAGS_ALIGN8K)
+		alloc_size += KGSL_PAGESIZE;
+
+	*gpuaddr = gen_pool_alloc(pagetable->pool, alloc_size);
+	if (*gpuaddr == 0) {
+		KGSL_MEM_ERR("gen_pool_alloc failed: %d\n", alloc_size);
+		return -ENOMEM;
+	}
+
+	if (align == KGSL_MEMFLAGS_ALIGN8K) {
+		if (*gpuaddr & ((1 << 13) - 1)) {
+			/* Not 8k aligned, align it */
+			gen_pool_free(pagetable->pool, *gpuaddr, KGSL_PAGESIZE);
+			*gpuaddr = *gpuaddr + KGSL_PAGESIZE;
+		} else
+			gen_pool_free(pagetable->pool, *gpuaddr + range,
+				      KGSL_PAGESIZE);
+	}
+
+	numpages = (range >> KGSL_PAGESIZE_SHIFT);
+
+	ptefirst = kgsl_pt_entry_get(pagetable, *gpuaddr);
+	ptelast = ptefirst + numpages;
+
+	pte = ptefirst;
+	flushtlb = 0;
+
+	superpte = ptefirst & (GSL_PT_SUPER_PTE - 1);
+	for (pte = superpte; pte < ptefirst; pte++) {
+		/* tlb needs to be flushed only when a dirty superPTE
+		   gets backed */
+		if (kgsl_pt_map_isdirty(pagetable, pte)) {
+			flushtlb = 1;
+			break;
+		}
+	}
+
+	for (pte = ptefirst; pte < ptelast; pte++) {
+#ifdef VERBOSE_DEBUG
+		/* check if PTE exists */
+		uint32_t val = kgsl_pt_map_getaddr(pagetable, pte);
+		BUG_ON(val != 0 && val != GSL_PT_PAGE_DIRTY);
+#endif
+		if (kgsl_pt_map_isdirty(pagetable, pte))
+			flushtlb = 1;
+		/* mark pte as in use */
+		if (phys_contiguous)
+			physaddr = address;
+		else {
+			physaddr = vmalloc_to_pfn((void *)address);
+			physaddr <<= PAGE_SHIFT;
+		}
+
+		if (physaddr)
+			kgsl_pt_map_set(pagetable, pte, physaddr | protflags);
+		else {
+			KGSL_MEM_ERR
+			("Unable to find physaddr for vmallloc address: %x\n",
+			     address);
+			kgsl_mmu_unmap(pagetable, *gpuaddr, range);
+			return -EFAULT;
+		}
+		address += KGSL_PAGESIZE;
+	}
+
+	/* set superpte to end of next superpte */
+	superpte = (ptelast + (GSL_PT_SUPER_PTE - 1))
+			& (GSL_PT_SUPER_PTE - 1);
+	for (pte = ptelast; pte < superpte; pte++) {
+		/* tlb needs to be flushed only when a dirty superPTE
+		   gets backed */
+		if (kgsl_pt_map_isdirty(pagetable, pte)) {
+			flushtlb = 1;
+			break;
+		}
+	}
+	KGSL_MEM_INFO("pt %p p %08x g %08x pte f %d l %d n %d f %d\n",
+		      pagetable, address, *gpuaddr, ptefirst, ptelast,
+		      numpages, flushtlb);
+
+	dmb();
+
+	/* Invalidate tlb only if current page table used by GPU is the
+	 * pagetable that we used to allocate */
+	if (pagetable == mmu->hwpagetable)
+		kgsl_yamato_setstate(mmu->device, KGSL_MMUFLAGS_TLBFLUSH);
+
+
+	KGSL_MEM_VDBG("return %d\n", 0);
+
+	return 0;
+}
+
+int
+kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, unsigned int gpuaddr,
+		int range)
+{
+	unsigned int numpages;
+	unsigned int pte, ptefirst, ptelast;
+
+	KGSL_MEM_VDBG("enter (pt=%p, gpuaddr=0x%08x, range=%d)\n",
+			pagetable, gpuaddr, range);
+
+	BUG_ON(range <= 0);
+
+	numpages = (range >> KGSL_PAGESIZE_SHIFT);
+	if (range & (KGSL_PAGESIZE - 1))
+		numpages++;
+
+	ptefirst = kgsl_pt_entry_get(pagetable, gpuaddr);
+	ptelast = ptefirst + numpages;
+
+	KGSL_MEM_INFO("pt %p gpu %08x pte first %d last %d numpages %d\n",
+		      pagetable, gpuaddr, ptefirst, ptelast, numpages);
+
+	for (pte = ptefirst; pte < ptelast; pte++) {
+#ifdef VERBOSE_DEBUG
+		/* check if PTE exists */
+		BUG_ON(!kgsl_pt_map_getaddr(pagetable, pte));
+#endif
+		kgsl_pt_map_set(pagetable, pte, GSL_PT_PAGE_DIRTY);
+	}
+
+	dmb();
+
+	/* Invalidate tlb only if current page table used by GPU is the
+	 * pagetable that we used to allocate */
+	if (pagetable == pagetable->mmu->hwpagetable)
+		kgsl_yamato_setstate(pagetable->mmu->device,
+					KGSL_MMUFLAGS_TLBFLUSH);
+
+	gen_pool_free(pagetable->pool, gpuaddr, range);
+
+	KGSL_MEM_VDBG("return %d\n", 0);
+
+	return 0;
+}
+#endif
+
+int kgsl_mmu_close(struct kgsl_device *device)
+{
+	/*
+	 *  close device mmu
+	 *
+	 *  call this with the global lock held
+	 */
+	struct kgsl_mmu *mmu = &device->mmu;
+#ifdef _DEBUG
+	int i;
+#endif /* _DEBUG */
+
+	KGSL_MEM_VDBG("enter (device=%p)\n", device);
+
+	if (mmu->flags & KGSL_FLAGS_INITIALIZED0) {
+		/* disable mh interrupts */
+		KGSL_MEM_DBG("disabling mmu interrupts\n");
+		kgsl_yamato_regwrite(device, REG_MH_INTERRUPT_MASK, 0);
+
+		/* disable MMU */
+		kgsl_yamato_regwrite(device, REG_MH_MMU_CONFIG, 0x00000000);
+
+		if (mmu->dummyspace.gpuaddr)
+			kgsl_sharedmem_free(&mmu->dummyspace);
+
+		mmu->flags &= ~KGSL_FLAGS_STARTED;
+		mmu->flags &= ~KGSL_FLAGS_INITIALIZED;
+		mmu->flags &= ~KGSL_FLAGS_INITIALIZED0;
+		kgsl_mmu_destroypagetableobject(mmu->defaultpagetable);
+		mmu->defaultpagetable = NULL;
+	}
+
+	KGSL_MEM_VDBG("return %d\n", 0);
+
+	return 0;
+}
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_mmu.h b/drivers/video/msm/gpu/kgsl/kgsl_mmu.h
new file mode 100644
index 0000000..d70f24a
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_mmu.h
@@ -0,0 +1,147 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#ifndef __GSL_MMU_H
+#define __GSL_MMU_H
+#include <linux/types.h>
+#include <linux/msm_kgsl.h>
+#include "kgsl_log.h"
+#include "kgsl_sharedmem.h"
+
+#define GSL_PT_SUPER_PTE 8
+#define GSL_PT_PAGE_WV		0x00000001
+#define GSL_PT_PAGE_RV		0x00000002
+#define GSL_PT_PAGE_DIRTY	0x00000004
+/* MMU Flags */
+#define KGSL_MMUFLAGS_TLBFLUSH         0x10000000
+#define KGSL_MMUFLAGS_PTUPDATE         0x20000000
+
+extern unsigned int kgsl_cache_enable;
+
+struct kgsl_device;
+
+struct kgsl_mmu_debug {
+	unsigned int  config;
+	unsigned int  mpu_base;
+	unsigned int  mpu_end;
+	unsigned int  va_range;
+	unsigned int  pt_base;
+	unsigned int  page_fault;
+	unsigned int  trans_error;
+	unsigned int  axi_error;
+	unsigned int  interrupt_mask;
+	unsigned int  interrupt_status;
+};
+
+struct kgsl_ptstats {
+	int64_t  maps;
+	int64_t  unmaps;
+	int64_t  superpteallocs;
+	int64_t  superptefrees;
+	int64_t  ptswitches;
+	int64_t  tlbflushes[KGSL_DEVICE_MAX];
+};
+
+struct kgsl_pagetable {
+	unsigned int   refcnt;
+	struct kgsl_mmu *mmu;
+	struct kgsl_memdesc  base;
+	uint32_t      va_base;
+	unsigned int   va_range;
+	unsigned int   last_superpte;
+	unsigned int   max_entries;
+	struct gen_pool *pool;
+};
+
+struct kgsl_mmu {
+	unsigned int     refcnt;
+	uint32_t      flags;
+	struct kgsl_device     *device;
+	unsigned int     config;
+	uint32_t        mpu_base;
+	int              mpu_range;
+	uint32_t        va_base;
+	unsigned int     va_range;
+	struct kgsl_memdesc    dummyspace;
+	/* current page table object being used by device mmu */
+	struct kgsl_pagetable  *defaultpagetable;
+	struct kgsl_pagetable  *hwpagetable;
+};
+
+
+static inline int
+kgsl_mmu_isenabled(struct kgsl_mmu *mmu)
+{
+	return ((mmu)->flags & KGSL_FLAGS_STARTED) ? 1 : 0;
+}
+
+
+int kgsl_mmu_init(struct kgsl_device *device);
+
+int kgsl_mmu_close(struct kgsl_device *device);
+
+struct kgsl_pagetable *kgsl_mmu_createpagetableobject(struct kgsl_mmu *mmu);
+
+int kgsl_mmu_destroypagetableobject(struct kgsl_pagetable *pagetable);
+
+int kgsl_mmu_setstate(struct kgsl_device *device,
+			struct kgsl_pagetable *pagetable);
+
+#ifdef CONFIG_MSM_KGSL_MMU
+int kgsl_mmu_map(struct kgsl_pagetable *pagetable,
+		 unsigned int address,
+		 int range,
+		 unsigned int protflags,
+		 unsigned int *gpuaddr,
+		 unsigned int flags);
+
+int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
+					unsigned int gpuaddr, int range);
+
+pte_t *kgsl_get_pte_from_vaddr(unsigned int vaddr);
+#else
+static inline int kgsl_mmu_map(struct kgsl_pagetable *pagetable,
+			       unsigned int address,
+			       int range,
+			       unsigned int protflags,
+			       unsigned int *gpuaddr,
+			       unsigned int flags)
+{
+	*gpuaddr = address;
+	return 0;
+}
+
+static inline int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
+				 unsigned int gpuaddr, int range) { return 0; }
+
+static inline pte_t *kgsl_get_pte_from_vaddr(unsigned int vaddr) {return NULL;}
+#endif
+
+int kgsl_mmu_querystats(struct kgsl_pagetable *pagetable,
+			struct kgsl_ptstats *stats);
+
+void kgsl_mh_intrcallback(struct kgsl_device *device);
+
+#ifdef DEBUG
+void kgsl_mmu_debug(struct kgsl_mmu *, struct kgsl_mmu_debug*);
+#else
+static inline void kgsl_mmu_debug(struct kgsl_mmu *mmu,
+				  struct kgsl_mmu_debug *mmu_debug) { }
+#endif /* DEBUG */
+
+#endif /* __GSL_MMU_H */
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_pm4types.h b/drivers/video/msm/gpu/kgsl/kgsl_pm4types.h
new file mode 100644
index 0000000..bc224b4
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_pm4types.h
@@ -0,0 +1,182 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#ifndef __GSL_PM4TYPES_H
+#define __GSL_PM4TYPES_H
+
+
+#define PM4_PKT_MASK	0xc0000000
+
+#define PM4_TYPE0_PKT	((unsigned int)0 << 30)
+#define PM4_TYPE1_PKT	((unsigned int)1 << 30)
+#define PM4_TYPE2_PKT	((unsigned int)2 << 30)
+#define PM4_TYPE3_PKT	((unsigned int)3 << 30)
+
+
+/* type3 packets */
+/* initialize CP's micro-engine */
+#define PM4_ME_INIT		0x48
+
+/* skip N 32-bit words to get to the next packet */
+#define PM4_NOP			0x10
+
+/* indirect buffer dispatch.  prefetch parser uses this packet type to determine
+*  whether to pre-fetch the IB
+*/
+#define PM4_INDIRECT_BUFFER	0x3f
+
+/* indirect buffer dispatch.  same as IB, but init is pipelined */
+#define PM4_INDIRECT_BUFFER_PFD	0x37
+
+/* wait for the IDLE state of the engine */
+#define PM4_WAIT_FOR_IDLE	0x26
+
+/* wait until a register or memory location is a specific value */
+#define PM4_WAIT_REG_MEM	0x3c
+
+/* wait until a register location is equal to a specific value */
+#define PM4_WAIT_REG_EQ		0x52
+
+/* wait until a register location is >= a specific value */
+#define PM4_WAT_REG_GTE		0x53
+
+/* wait until a read completes */
+#define PM4_WAIT_UNTIL_READ	0x5c
+
+/* wait until all base/size writes from an IB_PFD packet have completed */
+#define PM4_WAIT_IB_PFD_COMPLETE 0x5d
+
+/* register read/modify/write */
+#define PM4_REG_RMW		0x21
+
+/* reads register in chip and writes to memory */
+#define PM4_REG_TO_MEM		0x3e
+
+/* write N 32-bit words to memory */
+#define PM4_MEM_WRITE		0x3d
+
+/* write CP_PROG_COUNTER value to memory */
+#define PM4_MEM_WRITE_CNTR	0x4f
+
+/* conditional execution of a sequence of packets */
+#define PM4_COND_EXEC		0x44
+
+/* conditional write to memory or register */
+#define PM4_COND_WRITE		0x45
+
+/* generate an event that creates a write to memory when completed */
+#define PM4_EVENT_WRITE		0x46
+
+/* generate a VS|PS_done event */
+#define PM4_EVENT_WRITE_SHD	0x58
+
+/* generate a cache flush done event */
+#define PM4_EVENT_WRITE_CFL	0x59
+
+/* generate a z_pass done event */
+#define PM4_EVENT_WRITE_ZPD	0x5b
+
+
+/* initiate fetch of index buffer and draw */
+#define PM4_DRAW_INDX		0x22
+
+/* draw using supplied indices in packet */
+#define PM4_DRAW_INDX_2		0x36
+
+/* initiate fetch of index buffer and binIDs and draw */
+#define PM4_DRAW_INDX_BIN	0x34
+
+/* initiate fetch of bin IDs and draw using supplied indices */
+#define PM4_DRAW_INDX_2_BIN	0x35
+
+
+/* begin/end initiator for viz query extent processing */
+#define PM4_VIZ_QUERY		0x23
+
+/* fetch state sub-blocks and initiate shader code DMAs */
+#define PM4_SET_STATE		0x25
+
+/* load constant into chip and to memory */
+#define PM4_SET_CONSTANT	0x2d
+
+/* load sequencer instruction memory (pointer-based) */
+#define PM4_IM_LOAD		0x27
+
+/* load sequencer instruction memory (code embedded in packet) */
+#define PM4_IM_LOAD_IMMEDIATE	0x2b
+
+/* load constants from a location in memory */
+#define PM4_LOAD_CONSTANT_CONTEXT 0x2e
+
+/* selective invalidation of state pointers */
+#define PM4_INVALIDATE_STATE	0x3b
+
+
+/* dynamically changes shader instruction memory partition */
+#define PM4_SET_SHADER_BASES	0x4A
+
+/* sets the 64-bit BIN_MASK register in the PFP */
+#define PM4_SET_BIN_MASK	0x50
+
+/* sets the 64-bit BIN_SELECT register in the PFP */
+#define PM4_SET_BIN_SELECT	0x51
+
+
+/* updates the current context, if needed */
+#define PM4_CONTEXT_UPDATE	0x5e
+
+/* generate interrupt from the command stream */
+#define PM4_INTERRUPT		0x40
+
+
+/* copy sequencer instruction memory to system memory */
+#define PM4_IM_STORE            0x2c
+
+/* program an offset that will added to the BIN_BASE value of
+ * the 3D_DRAW_INDX_BIN packet */
+#define PM4_SET_BIN_BASE_OFFSET     0x4B
+
+#define PM4_SET_PROTECTED_MODE  0x5f /* sets the register protection mode */
+
+/* packet header building macros */
+#define pm4_type0_packet(regindx, cnt) \
+	(PM4_TYPE0_PKT | (((cnt)-1) << 16) | ((regindx) & 0x7FFF))
+
+#define pm4_type0_packet_for_sameregister(regindx, cnt) \
+	((PM4_TYPE0_PKT | (((cnt)-1) << 16) | ((1 << 15) | \
+		((regindx) & 0x7FFF)))
+
+#define pm4_type1_packet(reg0, reg1) \
+	 (PM4_TYPE1_PKT | ((reg1) << 12) | (reg0))
+
+#define pm4_type3_packet(opcode, cnt) \
+	 (PM4_TYPE3_PKT | (((cnt)-1) << 16) | (((opcode) & 0xFF) << 8))
+
+#define pm4_predicated_type3_packet(opcode, cnt) \
+	 (PM4_TYPE3_PKT | (((cnt)-1) << 16) | (((opcode) & 0xFF) << 8) | 0x1)
+
+#define pm4_nop_packet(cnt) \
+	 (PM4_TYPE3_PKT | (((cnt)-1) << 16) | (PM4_NOP << 8))
+
+
+/* packet headers */
+#define PM4_HDR_ME_INIT	pm4_type3_packet(PM4_ME_INIT, 18)
+#define PM4_HDR_INDIRECT_BUFFER_PFD pm4_type3_packet(PM4_INDIRECT_BUFFER_PFD, 2)
+#define PM4_HDR_INDIRECT_BUFFER	pm4_type3_packet(PM4_INDIRECT_BUFFER, 2)
+
+#endif	/* __GSL_PM4TYPES_H */
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_ringbuffer.c b/drivers/video/msm/gpu/kgsl/kgsl_ringbuffer.c
new file mode 100644
index 0000000..472d10c
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_ringbuffer.c
@@ -0,0 +1,837 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include "kgsl.h"
+#include "kgsl_device.h"
+#include "kgsl_log.h"
+#include "kgsl_pm4types.h"
+#include "kgsl_ringbuffer.h"
+#include "kgsl_cmdstream.h"
+
+#include "yamato_reg.h"
+
+#define GSL_RB_NOP_SIZEDWORDS				2
+/* protected mode error checking below register address 0x800
+*  note: if CP_INTERRUPT packet is used then checking needs
+*  to change to below register address 0x7C8
+*/
+#define GSL_RB_PROTECTED_MODE_CONTROL		0x200001F2
+
+#define GSL_CP_INT_MASK \
+	(CP_INT_CNTL__SW_INT_MASK | \
+	CP_INT_CNTL__T0_PACKET_IN_IB_MASK | \
+	CP_INT_CNTL__OPCODE_ERROR_MASK | \
+	CP_INT_CNTL__PROTECTED_MODE_ERROR_MASK | \
+	CP_INT_CNTL__RESERVED_BIT_ERROR_MASK | \
+	CP_INT_CNTL__IB_ERROR_MASK | \
+	CP_INT_CNTL__IB2_INT_MASK | \
+	CP_INT_CNTL__IB1_INT_MASK | \
+	CP_INT_CNTL__RB_INT_MASK)
+
+#define YAMATO_PFP_FW "yamato_pfp.fw"
+#define YAMATO_PM4_FW "yamato_pm4.fw"
+
+/*  ringbuffer size log2 quadwords equivalent */
+inline unsigned int kgsl_ringbuffer_sizelog2quadwords(unsigned int sizedwords)
+{
+	unsigned int sizelog2quadwords = 0;
+	int i = sizedwords >> 1;
+
+	while (i >>= 1)
+		sizelog2quadwords++;
+
+	return sizelog2quadwords;
+}
+
+
+/* functions */
+void kgsl_cp_intrcallback(struct kgsl_device *device)
+{
+	unsigned int status = 0;
+	struct kgsl_ringbuffer *rb = &device->ringbuffer;
+
+	KGSL_CMD_VDBG("enter (device=%p)\n", device);
+
+	kgsl_yamato_regread(device, REG_CP_INT_STATUS, &status);
+
+	if (status & CP_INT_CNTL__RB_INT_MASK) {
+		/* signal intr completion event */
+		int init_reftimestamp = 0x7fffffff;
+		int enableflag = 0;
+		kgsl_sharedmem_write(&rb->device->memstore,
+			KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable),
+			&enableflag, 4);
+		kgsl_sharedmem_write(&rb->device->memstore,
+			KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts),
+			&init_reftimestamp, 4);
+		KGSL_CMD_WARN("ringbuffer rb interrupt\n");
+	}
+
+	if (status & (CP_INT_CNTL__IB1_INT_MASK | CP_INT_CNTL__RB_INT_MASK)) {
+		KGSL_CMD_WARN("ringbuffer ib1/rb interrupt\n");
+		wake_up_interruptible_all(&device->ib1_wq);
+	}
+	if (status & CP_INT_CNTL__T0_PACKET_IN_IB_MASK) {
+		KGSL_CMD_FATAL("ringbuffer TO packet in IB interrupt\n");
+		kgsl_yamato_regwrite(rb->device, REG_CP_INT_CNTL, 0);
+		kgsl_ringbuffer_dump(rb);
+	}
+	if (status & CP_INT_CNTL__OPCODE_ERROR_MASK) {
+		KGSL_CMD_FATAL("ringbuffer opcode error interrupt\n");
+		kgsl_yamato_regwrite(rb->device, REG_CP_INT_CNTL, 0);
+		kgsl_ringbuffer_dump(rb);
+	}
+	if (status & CP_INT_CNTL__PROTECTED_MODE_ERROR_MASK) {
+		KGSL_CMD_FATAL("ringbuffer protected mode error interrupt\n");
+		kgsl_yamato_regwrite(rb->device, REG_CP_INT_CNTL, 0);
+		kgsl_ringbuffer_dump(rb);
+	}
+	if (status & CP_INT_CNTL__RESERVED_BIT_ERROR_MASK) {
+		KGSL_CMD_FATAL("ringbuffer reserved bit error interrupt\n");
+		kgsl_yamato_regwrite(rb->device, REG_CP_INT_CNTL, 0);
+		kgsl_ringbuffer_dump(rb);
+	}
+	if (status & CP_INT_CNTL__IB_ERROR_MASK) {
+		KGSL_CMD_FATAL("ringbuffer IB error interrupt\n");
+		kgsl_yamato_regwrite(rb->device, REG_CP_INT_CNTL, 0);
+		kgsl_ringbuffer_dump(rb);
+	}
+	if (status & CP_INT_CNTL__SW_INT_MASK)
+		KGSL_CMD_DBG("ringbuffer software interrupt\n");
+
+	if (status & CP_INT_CNTL__IB2_INT_MASK)
+		KGSL_CMD_DBG("ringbuffer ib2 interrupt\n");
+
+	if (status & (~GSL_CP_INT_MASK))
+		KGSL_CMD_DBG("bad bits in REG_CP_INT_STATUS %08x\n", status);
+
+	/* only ack bits we understand */
+	status &= GSL_CP_INT_MASK;
+	kgsl_yamato_regwrite(device, REG_CP_INT_ACK, status);
+
+	KGSL_CMD_VDBG("return\n");
+}
+
+
+void kgsl_ringbuffer_watchdog()
+{
+	struct kgsl_device *device = NULL;
+	struct kgsl_ringbuffer *rb = NULL;
+
+	device = &kgsl_driver.yamato_device;
+
+	BUG_ON(device == NULL);
+
+	rb = &device->ringbuffer;
+
+	KGSL_CMD_VDBG("enter\n");
+
+	if ((rb->flags & KGSL_FLAGS_STARTED) == 0) {
+		KGSL_CMD_VDBG("not started\n");
+		return;
+	}
+
+	GSL_RB_GET_READPTR(rb, &rb->rptr);
+
+	if (rb->rptr == rb->wptr) {
+		/* clear rptr sample for interval n */
+		rb->watchdog.flags &= ~KGSL_FLAGS_ACTIVE;
+		goto done;
+	}
+	/* ringbuffer is currently not empty */
+	/* and a rptr sample was taken during interval n-1 */
+	if (rb->watchdog.flags & KGSL_FLAGS_ACTIVE) {
+		/* and the rptr did not advance between
+		* interval n-1 and n */
+		if (rb->rptr == rb->watchdog.rptr_sample) {
+			/* then the core has hung */
+			KGSL_CMD_FATAL("Watchdog detected core hung.\n");
+			goto done;
+		}
+		/* save rptr sample for interval n */
+		rb->watchdog.flags |= KGSL_FLAGS_ACTIVE;
+		rb->watchdog.rptr_sample = rb->rptr;
+	}
+done:
+	KGSL_CMD_VDBG("return\n");
+}
+
+static void kgsl_ringbuffer_submit(struct kgsl_ringbuffer *rb)
+{
+	BUG_ON(rb->wptr == 0);
+
+	GSL_RB_UPDATE_WPTR_POLLING(rb);
+	/* Drain write buffer and data memory barrier */
+	dsb();
+	dmb();
+
+	/* Memory fence to ensure all data has posted.  On some systems,
+	* like 7x27, the register block is not allocated as strongly ordered
+	* memory.  Adding a memory fence ensures ordering during ringbuffer
+	* submits.*/
+	mb();
+
+	kgsl_yamato_regwrite(rb->device, REG_CP_RB_WPTR, rb->wptr);
+
+	rb->flags |= KGSL_FLAGS_ACTIVE;
+}
+
+static int
+kgsl_ringbuffer_waitspace(struct kgsl_ringbuffer *rb, unsigned int numcmds,
+			  int wptr_ahead)
+{
+	int nopcount;
+	unsigned int freecmds;
+	unsigned int *cmds;
+
+	KGSL_CMD_VDBG("enter (rb=%p, numcmds=%d, wptr_ahead=%d)\n",
+		      rb, numcmds, wptr_ahead);
+
+	/* if wptr ahead, fill the remaining with NOPs */
+	if (wptr_ahead) {
+		/* -1 for header */
+		nopcount = rb->sizedwords - rb->wptr - 1;
+
+		cmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
+		GSL_RB_WRITE(cmds, pm4_nop_packet(nopcount));
+		rb->wptr++;
+
+		kgsl_ringbuffer_submit(rb);
+
+		rb->wptr = 0;
+	}
+
+	/* wait for space in ringbuffer */
+	do {
+		GSL_RB_GET_READPTR(rb, &rb->rptr);
+
+		freecmds = rb->rptr - rb->wptr;
+
+	} while ((freecmds != 0) && (freecmds < numcmds));
+
+	KGSL_CMD_VDBG("return %d\n", 0);
+
+	return 0;
+}
+
+
+static unsigned int *kgsl_ringbuffer_allocspace(struct kgsl_ringbuffer *rb,
+					     unsigned int numcmds)
+{
+	unsigned int	*ptr = NULL;
+	int				status = 0;
+
+	BUG_ON(numcmds >= rb->sizedwords);
+
+	/* check for available space */
+	if (rb->wptr >= rb->rptr) {
+		/* wptr ahead or equal to rptr */
+		/* reserve dwords for nop packet */
+		if ((rb->wptr + numcmds) > (rb->sizedwords -
+				GSL_RB_NOP_SIZEDWORDS))
+			status = kgsl_ringbuffer_waitspace(rb, numcmds, 1);
+	} else {
+		/* wptr behind rptr */
+		if ((rb->wptr + numcmds) >= rb->rptr)
+			status  = kgsl_ringbuffer_waitspace(rb, numcmds, 0);
+		/* check for remaining space */
+		/* reserve dwords for nop packet */
+		if ((rb->wptr + numcmds) > (rb->sizedwords -
+				GSL_RB_NOP_SIZEDWORDS))
+			status = kgsl_ringbuffer_waitspace(rb, numcmds, 1);
+	}
+
+	if (status == 0) {
+		ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
+		rb->wptr += numcmds;
+	}
+
+	return ptr;
+}
+
+static int kgsl_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
+{
+	int status = 0;
+	int i;
+	const struct firmware *fw = NULL;
+	unsigned int *fw_ptr = NULL;
+	size_t fw_word_size = 0;
+
+	status = request_firmware(&fw, YAMATO_PM4_FW,
+					kgsl_driver.misc.this_device);
+	if (status != 0) {
+		KGSL_DRV_ERR("request_firmware failed for %s with error %d\n",
+				YAMATO_PM4_FW, status);
+		goto done;
+	}
+	/*this firmware must come in 3 word chunks. plus 1 word of version*/
+	if ((fw->size % (sizeof(uint32_t)*3)) != 4) {
+		KGSL_DRV_ERR("bad firmware size %d.\n", fw->size);
+		status = -EINVAL;
+		goto done;
+	}
+	fw_ptr = (unsigned int *)fw->data;
+	fw_word_size = fw->size/sizeof(uint32_t);
+	KGSL_DRV_INFO("loading pm4 ucode version: %d\n", fw_ptr[0]);
+
+	kgsl_yamato_regwrite(device, REG_CP_DEBUG, 0x02000000);
+	kgsl_yamato_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
+	for (i = 1; i < fw_word_size; i++)
+		kgsl_yamato_regwrite(device, REG_CP_ME_RAM_DATA, fw_ptr[i]);
+
+done:
+	release_firmware(fw);
+	return status;
+}
+
+static int kgsl_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
+{
+	int status = 0;
+	int i;
+	const struct firmware *fw = NULL;
+	unsigned int *fw_ptr = NULL;
+	size_t fw_word_size = 0;
+
+	status = request_firmware(&fw, YAMATO_PFP_FW,
+				kgsl_driver.misc.this_device);
+	if (status != 0) {
+		KGSL_DRV_ERR("request_firmware for %s failed with error %d\n",
+				YAMATO_PFP_FW, status);
+		return status;
+	}
+	/*this firmware must come in 1 word chunks. */
+	if ((fw->size % sizeof(uint32_t)) != 0) {
+		KGSL_DRV_ERR("bad firmware size %d.\n", fw->size);
+		release_firmware(fw);
+		return -EINVAL;
+	}
+	fw_ptr = (unsigned int *)fw->data;
+	fw_word_size = fw->size/sizeof(uint32_t);
+
+	KGSL_DRV_INFO("loading pfp ucode version: %d\n", fw_ptr[0]);
+
+	kgsl_yamato_regwrite(device, REG_CP_PFP_UCODE_ADDR, 0);
+	for (i = 1; i < fw_word_size; i++)
+		kgsl_yamato_regwrite(device, REG_CP_PFP_UCODE_DATA, fw_ptr[i]);
+
+	release_firmware(fw);
+	return status;
+}
+
+static int kgsl_ringbuffer_start(struct kgsl_ringbuffer *rb)
+{
+	int status;
+	/*cp_rb_cntl_u cp_rb_cntl; */
+	union reg_cp_rb_cntl cp_rb_cntl;
+	unsigned int *cmds, rb_cntl;
+	struct kgsl_device *device = rb->device;
+
+	KGSL_CMD_VDBG("enter (rb=%p)\n", rb);
+
+	if (rb->flags & KGSL_FLAGS_STARTED) {
+		KGSL_CMD_VDBG("return %d\n", 0);
+		return 0;
+	}
+	kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
+				sizeof(struct kgsl_rbmemptrs));
+
+	kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
+				(rb->sizedwords << 2));
+
+	kgsl_yamato_regwrite(device, REG_CP_RB_WPTR_BASE,
+			     (rb->memptrs_desc.gpuaddr
+			      + GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
+
+	/* setup WPTR delay */
+	kgsl_yamato_regwrite(device, REG_CP_RB_WPTR_DELAY, 0 /*0x70000010 */);
+
+	/*setup REG_CP_RB_CNTL */
+	kgsl_yamato_regread(device, REG_CP_RB_CNTL, &rb_cntl);
+	cp_rb_cntl.val = rb_cntl;
+	/* size of ringbuffer */
+	cp_rb_cntl.f.rb_bufsz =
+		kgsl_ringbuffer_sizelog2quadwords(rb->sizedwords);
+	/* quadwords to read before updating mem RPTR */
+	cp_rb_cntl.f.rb_blksz = rb->blksizequadwords;
+	cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN; /* WPTR polling */
+	/* mem RPTR writebacks */
+	cp_rb_cntl.f.rb_no_update =  GSL_RB_CNTL_NO_UPDATE;
+
+	kgsl_yamato_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);
+
+	kgsl_yamato_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);
+
+	kgsl_yamato_regwrite(device, REG_CP_RB_RPTR_ADDR,
+			     rb->memptrs_desc.gpuaddr +
+			     GSL_RB_MEMPTRS_RPTR_OFFSET);
+
+	/* explicitly clear all cp interrupts */
+	kgsl_yamato_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
+
+	/* setup scratch/timestamp */
+	kgsl_yamato_regwrite(device, REG_SCRATCH_ADDR,
+			     device->memstore.gpuaddr +
+			     KGSL_DEVICE_MEMSTORE_OFFSET(soptimestamp));
+
+	kgsl_yamato_regwrite(device, REG_SCRATCH_UMSK,
+			     GSL_RB_MEMPTRS_SCRATCH_MASK);
+
+	/* load the CP ucode */
+
+	status = kgsl_ringbuffer_load_pm4_ucode(device);
+	if (status != 0) {
+		KGSL_DRV_ERR("kgsl_ringbuffer_load_pm4_ucode failed  %d\n",
+				status);
+		return status;
+	}
+
+
+	/* load the prefetch parser ucode */
+	status = kgsl_ringbuffer_load_pfp_ucode(device);
+	if (status != 0) {
+		KGSL_DRV_ERR("kgsl_ringbuffer_load_pm4_ucode failed %d\n",
+				status);
+		return status;
+	}
+
+	kgsl_yamato_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000C0804);
+
+	rb->rptr = 0;
+	rb->wptr = 0;
+
+	rb->timestamp = 0;
+	GSL_RB_INIT_TIMESTAMP(rb);
+
+	INIT_LIST_HEAD(&rb->memqueue);
+
+	/* clear ME_HALT to start micro engine */
+	kgsl_yamato_regwrite(device, REG_CP_ME_CNTL, 0);
+
+	/* ME_INIT */
+	cmds = kgsl_ringbuffer_allocspace(rb, 19);
+
+	GSL_RB_WRITE(cmds, PM4_HDR_ME_INIT);
+	/* All fields present (bits 9:0) */
+	GSL_RB_WRITE(cmds, 0x000003ff);
+	/* Disable/Enable Real-Time Stream processing (present but ignored) */
+	GSL_RB_WRITE(cmds, 0x00000000);
+	/* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
+	GSL_RB_WRITE(cmds, 0x00000000);
+
+	GSL_RB_WRITE(cmds, GSL_HAL_SUBBLOCK_OFFSET(REG_RB_SURFACE_INFO));
+	GSL_RB_WRITE(cmds, GSL_HAL_SUBBLOCK_OFFSET(REG_PA_SC_WINDOW_OFFSET));
+	GSL_RB_WRITE(cmds, GSL_HAL_SUBBLOCK_OFFSET(REG_VGT_MAX_VTX_INDX));
+	GSL_RB_WRITE(cmds, GSL_HAL_SUBBLOCK_OFFSET(REG_SQ_PROGRAM_CNTL));
+	GSL_RB_WRITE(cmds, GSL_HAL_SUBBLOCK_OFFSET(REG_RB_DEPTHCONTROL));
+	GSL_RB_WRITE(cmds, GSL_HAL_SUBBLOCK_OFFSET(REG_PA_SU_POINT_SIZE));
+	GSL_RB_WRITE(cmds, GSL_HAL_SUBBLOCK_OFFSET(REG_PA_SC_LINE_CNTL));
+	GSL_RB_WRITE(cmds,
+	     GSL_HAL_SUBBLOCK_OFFSET(REG_PA_SU_POLY_OFFSET_FRONT_SCALE));
+
+	/* Vertex and Pixel Shader Start Addresses in instructions
+	* (3 DWORDS per instruction) */
+	GSL_RB_WRITE(cmds, 0x80000180);
+	/* Maximum Contexts */
+	GSL_RB_WRITE(cmds, 0x00000001);
+	/* Write Confirm Interval and The CP will wait the
+	* wait_interval * 16 clocks between polling  */
+	GSL_RB_WRITE(cmds, 0x00000000);
+
+	/* NQ and External Memory Swap */
+	GSL_RB_WRITE(cmds, 0x00000000);
+	/* Protected mode error checking */
+	GSL_RB_WRITE(cmds, GSL_RB_PROTECTED_MODE_CONTROL);
+	/* Disable header dumping and Header dump address */
+	GSL_RB_WRITE(cmds, 0x00000000);
+	/* Header dump size */
+	GSL_RB_WRITE(cmds, 0x00000000);
+
+	kgsl_ringbuffer_submit(rb);
+
+	/* idle device to validate ME INIT */
+	status = kgsl_yamato_idle(device, KGSL_TIMEOUT_DEFAULT);
+
+	KGSL_CMD_DBG("enabling CP interrupts: mask %08lx\n", GSL_CP_INT_MASK);
+	kgsl_yamato_regwrite(rb->device, REG_CP_INT_CNTL, GSL_CP_INT_MASK);
+	if (status == 0)
+		rb->flags |= KGSL_FLAGS_STARTED;
+
+	KGSL_CMD_VDBG("return %d\n", status);
+
+	return status;
+}
+
+static int kgsl_ringbuffer_stop(struct kgsl_ringbuffer *rb)
+{
+	KGSL_CMD_VDBG("enter (rb=%p)\n", rb);
+
+	if (rb->flags & KGSL_FLAGS_STARTED) {
+		KGSL_CMD_DBG("disabling CP interrupts: mask %08x\n", 0);
+		kgsl_yamato_regwrite(rb->device, REG_CP_INT_CNTL, 0);
+
+		/* ME_HALT */
+		kgsl_yamato_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
+
+		rb->flags &= ~KGSL_FLAGS_STARTED;
+		kgsl_ringbuffer_dump(rb);
+	}
+
+	KGSL_CMD_VDBG("return %d\n", 0);
+
+	return 0;
+}
+
+int kgsl_ringbuffer_init(struct kgsl_device *device)
+{
+	int status;
+	uint32_t flags;
+	struct kgsl_ringbuffer *rb = &device->ringbuffer;
+
+	KGSL_CMD_VDBG("enter (device=%p)\n", device);
+
+	rb->device = device;
+	rb->sizedwords = (2 << kgsl_cfg_rb_sizelog2quadwords);
+	rb->blksizequadwords = kgsl_cfg_rb_blksizequadwords;
+
+	/* allocate memory for ringbuffer, needs to be double octword aligned
+	* align on page from contiguous physical memory
+	*/
+	flags =
+	    (KGSL_MEMFLAGS_ALIGNPAGE | KGSL_MEMFLAGS_CONPHYS |
+	     KGSL_MEMFLAGS_STRICTREQUEST);
+
+	status = kgsl_sharedmem_alloc(flags, (rb->sizedwords << 2),
+					&rb->buffer_desc);
+
+	if (status != 0) {
+		kgsl_ringbuffer_close(rb);
+		KGSL_CMD_VDBG("return %d\n", status);
+		return status;
+	}
+
+	/* allocate memory for polling and timestamps */
+	/* This really can be at 4 byte alignment boundry but for using MMU
+	 * we need to make it at page boundary */
+	flags = (KGSL_MEMFLAGS_ALIGNPAGE | KGSL_MEMFLAGS_CONPHYS);
+
+	status = kgsl_sharedmem_alloc(flags, sizeof(struct kgsl_rbmemptrs),
+					&rb->memptrs_desc);
+
+	if (status != 0) {
+		kgsl_ringbuffer_close(rb);
+		KGSL_CMD_VDBG("return %d\n", status);
+		return status;
+	}
+
+	/* last allocation of init process is made here so map all
+	 * allocations to MMU */
+	status = kgsl_yamato_setup_pt(device, device->mmu.defaultpagetable);
+	if (status != 0) {
+		kgsl_ringbuffer_close(rb);
+		KGSL_CMD_VDBG("return %d\n", status);
+		return status;
+	}
+
+	/* overlay structure on memptrs memory */
+	rb->memptrs = (struct kgsl_rbmemptrs *) rb->memptrs_desc.hostptr;
+
+	rb->flags |= KGSL_FLAGS_INITIALIZED;
+
+	status = kgsl_ringbuffer_start(rb);
+	if (status != 0) {
+		kgsl_ringbuffer_close(rb);
+		KGSL_CMD_VDBG("return %d\n", status);
+		return status;
+	}
+
+	KGSL_CMD_VDBG("return %d\n", 0);
+	return 0;
+}
+
+int kgsl_ringbuffer_close(struct kgsl_ringbuffer *rb)
+{
+	KGSL_CMD_VDBG("enter (rb=%p)\n", rb);
+
+	kgsl_cmdstream_memqueue_drain(rb->device);
+
+	kgsl_ringbuffer_stop(rb);
+
+	/* this must happen before first sharedmem_free */
+	kgsl_yamato_cleanup_pt(rb->device, rb->device->mmu.defaultpagetable);
+
+	if (rb->buffer_desc.hostptr)
+		kgsl_sharedmem_free(&rb->buffer_desc);
+
+	if (rb->memptrs_desc.hostptr)
+		kgsl_sharedmem_free(&rb->memptrs_desc);
+
+	rb->flags &= ~KGSL_FLAGS_INITIALIZED;
+
+	memset(rb, 0, sizeof(struct kgsl_ringbuffer));
+
+	KGSL_CMD_VDBG("return %d\n", 0);
+	return 0;
+}
+
+static uint32_t
+kgsl_ringbuffer_addcmds(struct kgsl_ringbuffer *rb,
+				int flags, unsigned int *cmds,
+				int sizedwords)
+{
+	unsigned int *ringcmds;
+	unsigned int timestamp;
+	unsigned int total_sizedwords = sizedwords + 6;
+
+	/* reserve space to temporarily turn off protected mode
+	*  error checking if needed
+	*/
+	total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
+	total_sizedwords += !(flags & KGSL_CMD_FLAGS_NO_TS_CMP) ? 9 : 0;
+
+	ringcmds = kgsl_ringbuffer_allocspace(rb, total_sizedwords);
+
+	if (flags & KGSL_CMD_FLAGS_PMODE) {
+		/* disable protected mode error checking */
+		*ringcmds++ = pm4_type3_packet(PM4_SET_PROTECTED_MODE, 1);
+		*ringcmds++ = 0;
+	}
+
+	memcpy(ringcmds, cmds, (sizedwords << 2));
+
+	ringcmds += sizedwords;
+
+	if (flags & KGSL_CMD_FLAGS_PMODE) {
+		/* re-enable protected mode error checking */
+		*ringcmds++ = pm4_type3_packet(PM4_SET_PROTECTED_MODE, 1);
+		*ringcmds++ = 1;
+	}
+
+	rb->timestamp++;
+	timestamp = rb->timestamp;
+
+	/* start-of-pipeline and end-of-pipeline timestamps */
+	*ringcmds++ = pm4_type0_packet(REG_CP_TIMESTAMP, 1);
+	*ringcmds++ = rb->timestamp;
+	*ringcmds++ = pm4_type3_packet(PM4_EVENT_WRITE, 3);
+	*ringcmds++ = CACHE_FLUSH_TS;
+	*ringcmds++ =
+		     (rb->device->memstore.gpuaddr +
+		      KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp));
+	*ringcmds++ = rb->timestamp;
+
+	if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) {
+		/*  Add idle packet so avoid RBBM errors */
+		*ringcmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+		*ringcmds++ = 0x00000000;
+		/* Conditional execution based on memory values */
+		*ringcmds++ = pm4_type3_packet(PM4_COND_EXEC, 4);
+		*ringcmds++ = (rb->device->memstore.gpuaddr +
+			KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable)) >> 2;
+		*ringcmds++ = (rb->device->memstore.gpuaddr +
+			KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts)) >> 2;
+		*ringcmds++ = rb->timestamp;
+		/* # of conditional command DWORDs */
+		*ringcmds++ = 2;
+		*ringcmds++ = pm4_type3_packet(PM4_INTERRUPT, 1);
+		*ringcmds++ = CP_INT_CNTL__RB_INT_MASK;
+	}
+
+	kgsl_ringbuffer_submit(rb);
+
+	GSL_RB_STATS(rb->stats.words_total += sizedwords);
+	GSL_RB_STATS(rb->stats.issues++);
+
+	KGSL_CMD_VDBG("return %d\n", timestamp);
+
+	/* return timestamp of issued coREG_ands */
+	return timestamp;
+}
+
+uint32_t
+kgsl_ringbuffer_issuecmds(struct kgsl_device *device,
+						int flags,
+						unsigned int *cmds,
+						int sizedwords)
+{
+	unsigned int timestamp;
+	struct kgsl_ringbuffer *rb = &device->ringbuffer;
+
+	KGSL_CMD_VDBG("enter (device->id=%d, flags=%d, cmds=%p, "
+		"sizedwords=%d)\n", device->id, flags, cmds, sizedwords);
+
+	timestamp = kgsl_ringbuffer_addcmds(rb, flags, cmds, sizedwords);
+
+	KGSL_CMD_VDBG("return %d\n)", timestamp);
+	return timestamp;
+}
+
+int
+kgsl_ringbuffer_issueibcmds(struct kgsl_device *device,
+				int drawctxt_index,
+				uint32_t ibaddr,
+				int sizedwords,
+				uint32_t *timestamp,
+				unsigned int flags)
+{
+	unsigned int link[3];
+
+	KGSL_CMD_VDBG("enter (device_id=%d, drawctxt_index=%d, ibaddr=0x%08x,"
+			" sizedwords=%d, timestamp=%p)\n",
+			device->id, drawctxt_index, ibaddr,
+			sizedwords, timestamp);
+
+	if (!(device->ringbuffer.flags & KGSL_FLAGS_STARTED)) {
+		KGSL_CMD_VDBG("return %d\n", -EINVAL);
+		return -EINVAL;
+	}
+
+	BUG_ON(ibaddr == 0);
+	BUG_ON(sizedwords == 0);
+
+	link[0] = PM4_HDR_INDIRECT_BUFFER_PFD;
+	link[1] = ibaddr;
+	link[2] = sizedwords;
+
+	kgsl_drawctxt_switch(device, &device->drawctxt[drawctxt_index], flags);
+
+	*timestamp = kgsl_ringbuffer_addcmds(&device->ringbuffer,
+					0, &link[0], 3);
+
+
+	KGSL_CMD_INFO("ctxt %d g %08x sd %d ts %d\n",
+			drawctxt_index, ibaddr, sizedwords, *timestamp);
+
+	KGSL_CMD_VDBG("return %d\n", 0);
+
+	return 0;
+}
+
+
+#ifdef DEBUG
+void kgsl_ringbuffer_debug(struct kgsl_ringbuffer *rb,
+				struct kgsl_rb_debug *rb_debug)
+{
+	memset(rb_debug, 0, sizeof(struct kgsl_rb_debug));
+
+	rb_debug->mem_rptr = rb->memptrs->rptr;
+	rb_debug->mem_wptr_poll = rb->memptrs->wptr_poll;
+	kgsl_yamato_regread(rb->device, REG_CP_RB_BASE,
+			    (unsigned int *)&rb_debug->cp_rb_base);
+	kgsl_yamato_regread(rb->device, REG_CP_RB_CNTL,
+			    (unsigned int *)&rb_debug->cp_rb_cntl);
+	kgsl_yamato_regread(rb->device, REG_CP_RB_RPTR_ADDR,
+			    (unsigned int *)&rb_debug->cp_rb_rptr_addr);
+	kgsl_yamato_regread(rb->device, REG_CP_RB_RPTR,
+			    (unsigned int *)&rb_debug->cp_rb_rptr);
+	kgsl_yamato_regread(rb->device, REG_CP_RB_RPTR_WR,
+			    (unsigned int *)&rb_debug->cp_rb_rptr_wr);
+	kgsl_yamato_regread(rb->device, REG_CP_RB_WPTR,
+			    (unsigned int *)&rb_debug->cp_rb_wptr);
+	kgsl_yamato_regread(rb->device, REG_CP_RB_WPTR_DELAY,
+			    (unsigned int *)&rb_debug->cp_rb_wptr_delay);
+	kgsl_yamato_regread(rb->device, REG_CP_RB_WPTR_BASE,
+			    (unsigned int *)&rb_debug->cp_rb_wptr_base);
+	kgsl_yamato_regread(rb->device, REG_CP_IB1_BASE,
+			    (unsigned int *)&rb_debug->cp_ib1_base);
+	kgsl_yamato_regread(rb->device, REG_CP_IB1_BUFSZ,
+			    (unsigned int *)&rb_debug->cp_ib1_bufsz);
+	kgsl_yamato_regread(rb->device, REG_CP_IB2_BASE,
+			    (unsigned int *)&rb_debug->cp_ib2_base);
+	kgsl_yamato_regread(rb->device, REG_CP_IB2_BUFSZ,
+			    (unsigned int *)&rb_debug->cp_ib2_bufsz);
+	kgsl_yamato_regread(rb->device, REG_CP_ST_BASE,
+			    (unsigned int *)&rb_debug->cp_st_base);
+	kgsl_yamato_regread(rb->device, REG_CP_ST_BUFSZ,
+			    (unsigned int *)&rb_debug->cp_st_bufsz);
+	kgsl_yamato_regread(rb->device, REG_CP_CSQ_RB_STAT,
+			    (unsigned int *)&rb_debug->cp_csq_rb_stat);
+	kgsl_yamato_regread(rb->device, REG_CP_CSQ_IB1_STAT,
+			    (unsigned int *)&rb_debug->cp_csq_ib1_stat);
+	kgsl_yamato_regread(rb->device, REG_CP_CSQ_IB2_STAT,
+			    (unsigned int *)&rb_debug->cp_csq_ib2_stat);
+	kgsl_yamato_regread(rb->device, REG_SCRATCH_UMSK,
+			    (unsigned int *)&rb_debug->scratch_umsk);
+	kgsl_yamato_regread(rb->device, REG_SCRATCH_ADDR,
+			    (unsigned int *)&rb_debug->scratch_addr);
+	kgsl_yamato_regread(rb->device, REG_CP_ME_CNTL,
+			    (unsigned int *)&rb_debug->cp_me_cntl);
+	kgsl_yamato_regread(rb->device, REG_CP_ME_STATUS,
+			    (unsigned int *)&rb_debug->cp_me_status);
+	kgsl_yamato_regread(rb->device, REG_CP_DEBUG,
+			    (unsigned int *)&rb_debug->cp_debug);
+	kgsl_yamato_regread(rb->device, REG_CP_STAT,
+			    (unsigned int *)&rb_debug->cp_stat);
+	kgsl_yamato_regread(rb->device, REG_CP_INT_STATUS,
+			    (unsigned int *)&rb_debug->cp_int_status);
+	kgsl_yamato_regread(rb->device, REG_CP_INT_CNTL,
+			    (unsigned int *)&rb_debug->cp_int_cntl);
+	kgsl_yamato_regread(rb->device, REG_RBBM_STATUS,
+			    (unsigned int *)&rb_debug->rbbm_status);
+	kgsl_yamato_regread(rb->device, REG_RBBM_INT_STATUS,
+			    (unsigned int *)&rb_debug->rbbm_int_status);
+	GSL_RB_GET_SOP_TIMESTAMP(rb, (unsigned int *)&rb_debug->sop_timestamp);
+	GSL_RB_GET_EOP_TIMESTAMP(rb, (unsigned int *)&rb_debug->eop_timestamp);
+
+}
+#endif /*DEBUG*/
+
+#ifdef DEBUG
+void kgsl_ringbuffer_dump(struct kgsl_ringbuffer *rb)
+{
+	struct kgsl_rb_debug rb_debug;
+	kgsl_ringbuffer_debug(rb, &rb_debug);
+
+	KGSL_CMD_DBG("rbbm_status %08x rbbm_int_status %08x"
+			" mem_rptr %08x mem_wptr_poll %08x\n",
+			rb_debug.rbbm_status,
+			rb_debug.rbbm_int_status,
+			rb_debug.mem_rptr, rb_debug.mem_wptr_poll);
+
+	KGSL_CMD_DBG("rb_base %08x rb_cntl %08x rb_rptr_addr %08x rb_rptr %08x"
+			" rb_rptr_wr %08x\n",
+			rb_debug.cp_rb_base, rb_debug.cp_rb_cntl,
+			rb_debug.cp_rb_rptr_addr, rb_debug.cp_rb_rptr,
+			rb_debug.cp_rb_rptr_wr);
+
+	KGSL_CMD_DBG("rb_wptr %08x rb_wptr_delay %08x rb_wptr_base %08x"
+			" ib1_base %08x ib1_bufsz %08x\n",
+			rb_debug.cp_rb_wptr, rb_debug.cp_rb_wptr_delay,
+			rb_debug.cp_rb_wptr_base, rb_debug.cp_ib1_base,
+			rb_debug.cp_ib1_bufsz);
+
+	KGSL_CMD_DBG("ib2_base  %08x ib2_bufsz %08x st_base %08x st_bufsz %08x"
+			" cp_me_cntl %08x cp_me_status %08x\n",
+			rb_debug.cp_ib2_base, rb_debug.cp_ib2_bufsz,
+			rb_debug.cp_st_base, rb_debug.cp_st_bufsz,
+			rb_debug.cp_me_cntl, rb_debug.cp_me_status);
+
+	KGSL_CMD_DBG("cp_debug %08x cp_stat %08x cp_int_status %08x"
+			" cp_int_cntl %08x\n",
+			rb_debug.cp_debug, rb_debug.cp_stat,
+			rb_debug.cp_int_status, rb_debug.cp_int_cntl);
+
+	KGSL_CMD_DBG("sop_timestamp: %d eop_timestamp: %d\n",
+			rb_debug.sop_timestamp, rb_debug.eop_timestamp);
+
+}
+#endif /* DEBUG */
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_ringbuffer.h b/drivers/video/msm/gpu/kgsl/kgsl_ringbuffer.h
new file mode 100644
index 0000000..0d06020
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_ringbuffer.h
@@ -0,0 +1,254 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#ifndef __GSL_RINGBUFFER_H
+#define __GSL_RINGBUFFER_H
+
+#include <linux/types.h>
+#include <linux/msm_kgsl.h>
+#include <linux/mutex.h>
+#include "kgsl_log.h"
+#include "kgsl_sharedmem.h"
+#include "yamato_reg.h"
+
+#define GSL_STATS_RINGBUFFER
+
+#define GSL_RB_USE_MEM_RPTR
+#define GSL_RB_USE_MEM_TIMESTAMP
+#define GSL_DEVICE_SHADOW_MEMSTORE_TO_USER
+
+/* ringbuffer sizes log2quadword */
+#define GSL_RB_SIZE_8	 	0
+#define GSL_RB_SIZE_16		1
+#define GSL_RB_SIZE_32		2
+#define GSL_RB_SIZE_64		3
+#define GSL_RB_SIZE_128		4
+#define GSL_RB_SIZE_256		5
+#define GSL_RB_SIZE_512		6
+#define GSL_RB_SIZE_1K  	7
+#define GSL_RB_SIZE_2K  	8
+#define GSL_RB_SIZE_4K  	9
+#define GSL_RB_SIZE_8K  	10
+#define GSL_RB_SIZE_16K 	11
+#define GSL_RB_SIZE_32K 	12
+#define GSL_RB_SIZE_64K 	13
+#define GSL_RB_SIZE_128K	14
+#define GSL_RB_SIZE_256K	15
+#define GSL_RB_SIZE_512K	16
+#define GSL_RB_SIZE_1M		17
+#define GSL_RB_SIZE_2M		18
+#define GSL_RB_SIZE_4M		19
+
+/* Yamato ringbuffer config*/
+static const unsigned int kgsl_cfg_rb_sizelog2quadwords = GSL_RB_SIZE_32K;
+static const unsigned int kgsl_cfg_rb_blksizequadwords  = GSL_RB_SIZE_16;
+
+/* CP timestamp register */
+#define	REG_CP_TIMESTAMP		 REG_SCRATCH_REG0
+
+
+struct kgsl_device;
+struct kgsl_drawctxt;
+struct kgsl_ringbuffer;
+
+struct kgsl_rb_debug {
+	unsigned int pm4_ucode_rel;
+	unsigned int pfp_ucode_rel;
+	unsigned int mem_wptr_poll;
+	unsigned int mem_rptr;
+	unsigned int cp_rb_base;
+	unsigned int cp_rb_cntl;
+	unsigned int cp_rb_rptr_addr;
+	unsigned int cp_rb_rptr;
+	unsigned int cp_rb_rptr_wr;
+	unsigned int cp_rb_wptr;
+	unsigned int cp_rb_wptr_delay;
+	unsigned int cp_rb_wptr_base;
+	unsigned int cp_ib1_base;
+	unsigned int cp_ib1_bufsz;
+	unsigned int cp_ib2_base;
+	unsigned int cp_ib2_bufsz;
+	unsigned int cp_st_base;
+	unsigned int cp_st_bufsz;
+	unsigned int cp_csq_rb_stat;
+	unsigned int cp_csq_ib1_stat;
+	unsigned int cp_csq_ib2_stat;
+	unsigned int scratch_umsk;
+	unsigned int scratch_addr;
+	unsigned int cp_me_cntl;
+	unsigned int cp_me_status;
+	unsigned int cp_debug;
+	unsigned int cp_stat;
+	unsigned int cp_int_status;
+	unsigned int cp_int_cntl;
+	unsigned int rbbm_status;
+	unsigned int rbbm_int_status;
+	unsigned int sop_timestamp;
+	unsigned int eop_timestamp;
+};
+#ifdef DEBUG
+void kgsl_ringbuffer_debug(struct kgsl_ringbuffer *rb,
+				struct kgsl_rb_debug *rb_debug);
+
+void kgsl_ringbuffer_dump(struct kgsl_ringbuffer *rb);
+#else
+static inline void kgsl_ringbuffer_debug(struct kgsl_ringbuffer *rb,
+					struct kgsl_rb_debug *rb_debug)
+{
+}
+
+static inline void kgsl_ringbuffer_dump(struct kgsl_ringbuffer *rb)
+{
+}
+#endif
+
+struct kgsl_rbwatchdog {
+	uint32_t   flags;
+	unsigned int  rptr_sample;
+};
+
+#define GSL_RB_MEMPTRS_SCRATCH_COUNT	 8
+struct kgsl_rbmemptrs {
+	volatile int  rptr;
+	volatile int  wptr_poll;
+} __attribute__ ((packed));
+
+#define GSL_RB_MEMPTRS_RPTR_OFFSET \
+	(offsetof(struct kgsl_rbmemptrs, rptr))
+
+#define GSL_RB_MEMPTRS_WPTRPOLL_OFFSET \
+	(offsetof(struct kgsl_rbmemptrs, wptr_poll))
+
+struct kgsl_rbstats {
+	int64_t issues;
+	int64_t words_total;
+};
+
+
+struct kgsl_ringbuffer {
+	struct kgsl_device *device;
+	uint32_t flags;
+
+	struct kgsl_memdesc buffer_desc;
+
+	struct kgsl_memdesc memptrs_desc;
+	struct kgsl_rbmemptrs *memptrs;
+
+	/*ringbuffer size */
+	unsigned int sizedwords;
+	unsigned int blksizequadwords;
+
+	unsigned int wptr; /* write pointer offset in dwords from baseaddr */
+	unsigned int rptr; /* read pointer offset in dwords from baseaddr */
+	uint32_t timestamp;
+
+	/* queue of memfrees pending timestamp elapse */
+	struct list_head memqueue;
+
+	struct kgsl_rbwatchdog watchdog;
+
+#ifdef GSL_STATS_RINGBUFFER
+	struct kgsl_rbstats stats;
+#endif /* GSL_STATS_RINGBUFFER */
+
+};
+
+/* dword base address of the GFX decode space */
+#define GSL_HAL_SUBBLOCK_OFFSET(reg) ((unsigned int)((reg) - (0x2000)))
+
+#define GSL_RB_WRITE(ring, data) \
+	do { \
+		mb(); \
+		writel(data, ring); \
+		ring++; \
+	} while (0)
+
+/* timestamp */
+#ifdef GSL_DEVICE_SHADOW_MEMSTORE_TO_USER
+#define GSL_RB_USE_MEM_TIMESTAMP
+#endif /* GSL_DEVICE_SHADOW_MEMSTORE_TO_USER */
+
+#ifdef GSL_RB_USE_MEM_TIMESTAMP
+/* enable timestamp (...scratch0) memory shadowing */
+#define GSL_RB_MEMPTRS_SCRATCH_MASK 0x1
+#define GSL_RB_INIT_TIMESTAMP(rb)
+
+#else
+#define GSL_RB_MEMPTRS_SCRATCH_MASK 0x0
+#define GSL_RB_INIT_TIMESTAMP(rb) \
+		kgsl_yamato_regwrite((rb)->device->id, REG_CP_TIMESTAMP, 0)
+
+#endif /* GSL_RB_USE_MEMTIMESTAMP */
+
+/* mem rptr */
+#ifdef GSL_RB_USE_MEM_RPTR
+#define GSL_RB_CNTL_NO_UPDATE 0x0 /* enable */
+#define GSL_RB_GET_READPTR(rb, data) \
+	do { \
+		*(data) = (rb)->memptrs->rptr; \
+	} while (0)
+#else
+#define GSL_RB_CNTL_NO_UPDATE 0x1 /* disable */
+#define GSL_RB_GET_READPTR(rb, data) \
+	do { \
+		kgsl_yamato_regread((rb)->device->id, REG_CP_RB_RPTR, (data)); \
+	} while (0)
+#endif /* GSL_RB_USE_MEMRPTR */
+
+/* wptr polling */
+#ifdef GSL_RB_USE_WPTR_POLLING
+#define GSL_RB_CNTL_POLL_EN 0x1 /* enable */
+#define GSL_RB_UPDATE_WPTR_POLLING(rb) \
+	do { (rb)->memptrs->wptr_poll = (rb)->wptr; } while (0)
+#else
+#define GSL_RB_CNTL_POLL_EN 0x0 /* disable */
+#define GSL_RB_UPDATE_WPTR_POLLING(rb)
+#endif	/* GSL_RB_USE_WPTR_POLLING */
+
+/* stats */
+#ifdef GSL_STATS_RINGBUFFER
+#define GSL_RB_STATS(x) x
+#else
+#define GSL_RB_STATS(x)
+#endif /* GSL_STATS_RINGBUFFER */
+
+struct kgsl_pmem_entry;
+
+int kgsl_ringbuffer_issueibcmds(struct kgsl_device *, int drawctxt_index,
+				uint32_t ibaddr, int sizedwords,
+				uint32_t *timestamp,
+				unsigned int flags);
+
+int kgsl_ringbuffer_init(struct kgsl_device *device);
+
+int kgsl_ringbuffer_close(struct kgsl_ringbuffer *rb);
+
+uint32_t kgsl_ringbuffer_issuecmds(struct kgsl_device *device,
+					int pmodeoff,
+					unsigned int *cmdaddr,
+					int sizedwords);
+
+int kgsl_ringbuffer_gettimestampshadow(struct kgsl_device *device,
+					unsigned int *sopaddr,
+					unsigned int *eopaddr);
+
+void kgsl_ringbuffer_watchdog(void);
+
+void kgsl_cp_intrcallback(struct kgsl_device *device);
+
+#endif  /* __GSL_RINGBUFFER_H */
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_sharedmem.c b/drivers/video/msm/gpu/kgsl/kgsl_sharedmem.c
new file mode 100644
index 0000000..4a1b421
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_sharedmem.c
@@ -0,0 +1,300 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+
+#include "kgsl_sharedmem.h"
+#include "kgsl_device.h"
+#include "kgsl.h"
+#include "kgsl_log.h"
+
+/*  block alignment shift count */
+static inline unsigned int
+kgsl_memarena_get_order(uint32_t flags)
+{
+	unsigned int alignshift;
+	alignshift = ((flags & KGSL_MEMFLAGS_ALIGN_MASK)
+		      >> KGSL_MEMFLAGS_ALIGN_SHIFT);
+	return alignshift;
+}
+
+/*  block alignment shift count */
+static inline unsigned int
+kgsl_memarena_align(unsigned int address, unsigned int shift)
+{
+	unsigned int alignedbaseaddr = ((address) >> shift) << shift;
+	if (alignedbaseaddr < address)
+		alignedbaseaddr += (1 << shift);
+
+	return alignedbaseaddr;
+}
+
+int
+kgsl_sharedmem_init(struct kgsl_sharedmem *shmem)
+{
+	int result = -EINVAL;
+
+	if (!request_mem_region(shmem->physbase, shmem->size, DRIVER_NAME)) {
+		KGSL_MEM_ERR("request_mem_region failed\n");
+		goto error;
+	}
+
+	shmem->baseptr = ioremap(shmem->physbase, shmem->size);
+	KGSL_MEM_INFO("ioremap(shm) = %p\n", shmem->baseptr);
+
+	if (shmem->baseptr == NULL) {
+		KGSL_MEM_ERR("ioremap failed for address %08x size %d\n",
+				shmem->physbase, shmem->size);
+		result = -ENODEV;
+		goto error_release_mem;
+	}
+
+	shmem->pool = gen_pool_create(KGSL_PAGESIZE_SHIFT, -1);
+	if (shmem->pool == NULL) {
+		KGSL_MEM_ERR("gen_pool_create failed\n");
+		result = -ENOMEM;
+		goto error_iounmap;
+	}
+
+	if (gen_pool_add(shmem->pool, shmem->physbase, shmem->size, -1)) {
+		KGSL_MEM_ERR("gen_pool_create failed\n");
+		result = -ENOMEM;
+		goto error_pool_destroy;
+	}
+	result = 0;
+	KGSL_MEM_INFO("physbase 0x%08x size 0x%08x baseptr 0x%p\n",
+			shmem->physbase, shmem->size, shmem->baseptr);
+	return 0;
+
+error_pool_destroy:
+	gen_pool_destroy(shmem->pool);
+error_iounmap:
+	iounmap(shmem->baseptr);
+	shmem->baseptr = NULL;
+error_release_mem:
+	release_mem_region(shmem->physbase, shmem->size);
+error:
+	return result;
+}
+
+int
+kgsl_sharedmem_close(struct kgsl_sharedmem *shmem)
+{
+	if (shmem->pool) {
+		gen_pool_destroy(shmem->pool);
+		shmem->pool = NULL;
+	}
+
+	if (shmem->baseptr != NULL) {
+		KGSL_MEM_INFO("iounmap(shm) = %p\n", shmem->baseptr);
+		iounmap(shmem->baseptr);
+		shmem->baseptr = NULL;
+		release_mem_region(shmem->physbase, shmem->size);
+	}
+
+	return 0;
+}
+/*
+* get the host mapped address for a hardware device address
+*/
+static void *kgsl_memarena_gethostptr(struct kgsl_sharedmem *shmem,
+					uint32_t physaddr)
+{
+	void *result;
+
+	KGSL_MEM_VDBG("enter (memarena=%p, physaddr=0x%08x)\n",
+			shmem, physaddr);
+
+	BUG_ON(shmem == NULL);
+
+	/* check address range */
+	if (physaddr < shmem->physbase)
+		return NULL;
+
+	if (physaddr >= shmem->physbase + shmem->size)
+		return NULL;
+
+	if (shmem->baseptr == NULL) {
+		KGSL_MEM_VDBG("return: %p\n", NULL);
+		return NULL;
+	}
+
+	result = ((physaddr - shmem->physbase) + shmem->baseptr);
+
+	KGSL_MEM_VDBG("return: %p\n", result);
+
+	return result;
+}
+
+
+int
+kgsl_sharedmem_alloc(uint32_t flags, int size,
+			struct kgsl_memdesc *memdesc)
+{
+	struct kgsl_sharedmem *shmem;
+	int result = -ENOMEM;
+	unsigned int blksize;
+	unsigned int baseaddr;
+	unsigned int alignshift;
+	unsigned int alignedbaseaddr;
+
+	KGSL_MEM_VDBG("enter (flags=0x%08x, size=%d, memdesc=%p)\n",
+					flags, size, memdesc);
+
+	shmem = &kgsl_driver.shmem;
+	BUG_ON(memdesc == NULL);
+	BUG_ON(size <= 0);
+
+	alignshift = kgsl_memarena_get_order(flags);
+
+	size = ALIGN(size, KGSL_PAGESIZE);
+	blksize = size;
+	if (alignshift > KGSL_PAGESIZE_SHIFT)
+		blksize += (1 << alignshift) - KGSL_PAGESIZE;
+
+	baseaddr = gen_pool_alloc(shmem->pool, blksize);
+	if (baseaddr == 0) {
+		KGSL_MEM_ERR("gen_pool_alloc failed\n");
+		result = -ENOMEM;
+		goto done;
+	}
+	result = 0;
+
+	if (alignshift > KGSL_PAGESIZE_SHIFT) {
+		alignedbaseaddr = ALIGN(baseaddr, (1 << alignshift));
+
+		KGSL_MEM_VDBG("ba %x al %x as %d m->as %d bs %x s %x\n",
+				baseaddr, alignedbaseaddr, alignshift,
+				KGSL_PAGESIZE_SHIFT, blksize, size);
+		if (alignedbaseaddr > baseaddr) {
+			KGSL_MEM_VDBG("physaddr %x free before %x size %x\n",
+					alignedbaseaddr,
+					baseaddr, alignedbaseaddr - baseaddr);
+			gen_pool_free(shmem->pool, baseaddr,
+					alignedbaseaddr - baseaddr);
+			blksize -= alignedbaseaddr - baseaddr;
+		}
+		if (blksize > size) {
+			KGSL_MEM_VDBG("physaddr %x free after %x size %x\n",
+					alignedbaseaddr,
+					alignedbaseaddr + size,
+					blksize - size);
+			gen_pool_free(shmem->pool,
+					alignedbaseaddr + size,
+					blksize - size);
+		}
+	} else {
+		alignedbaseaddr = baseaddr;
+	}
+
+	memdesc->physaddr = alignedbaseaddr;
+	memdesc->hostptr = kgsl_memarena_gethostptr(shmem, memdesc->physaddr);
+	memdesc->size = size;
+
+	KGSL_MEM_VDBG("ashift %d m->ashift %d blksize %d base %x abase %x\n",
+			alignshift, KGSL_PAGESIZE_SHIFT, blksize, baseaddr,
+			alignedbaseaddr);
+
+done:
+	if (result)
+		memset(memdesc, 0, sizeof(*memdesc));
+
+
+	KGSL_MEM_VDBG("return: %d\n", result);
+	return result;
+}
+
+void
+kgsl_sharedmem_free(struct kgsl_memdesc *memdesc)
+{
+	struct kgsl_sharedmem  *shmem =  &kgsl_driver.shmem;
+
+	KGSL_MEM_VDBG("enter (shmem=%p, memdesc=%p, physaddr=%08x, size=%d)\n",
+			shmem, memdesc, memdesc->physaddr, memdesc->size);
+
+	BUG_ON(memdesc == NULL);
+	BUG_ON(memdesc->size <= 0);
+	BUG_ON(shmem->physbase > memdesc->physaddr);
+	BUG_ON((shmem->physbase + shmem->size)
+	       < (memdesc->physaddr + memdesc->size));
+
+	gen_pool_free(shmem->pool, memdesc->physaddr, memdesc->size);
+
+	memset(memdesc, 0, sizeof(struct kgsl_memdesc));
+	KGSL_MEM_VDBG("return\n");
+}
+
+int
+kgsl_sharedmem_read(const struct kgsl_memdesc *memdesc, void *dst,
+			unsigned int offsetbytes, unsigned int sizebytes)
+{
+	if (memdesc == NULL || memdesc->hostptr == NULL || dst == NULL) {
+		KGSL_MEM_ERR("bad ptr memdesc %p hostptr %p dst %p\n",
+				memdesc,
+				(memdesc ? memdesc->hostptr : NULL),
+				dst);
+		return -EINVAL;
+	}
+	if (offsetbytes + sizebytes > memdesc->size) {
+		KGSL_MEM_ERR("bad range: offset %d size %d memdesc %d\n",
+				offsetbytes, sizebytes, memdesc->size);
+		return -ERANGE;
+	}
+	memcpy(dst, memdesc->hostptr + offsetbytes, sizebytes);
+	return 0;
+}
+
+int
+kgsl_sharedmem_write(const struct kgsl_memdesc *memdesc,
+			unsigned int offsetbytes,
+			void *value, unsigned int sizebytes)
+{
+	if (memdesc == NULL || memdesc->hostptr == NULL) {
+		KGSL_MEM_ERR("bad ptr memdesc %p hostptr %p\n", memdesc,
+				(memdesc ? memdesc->hostptr : NULL));
+		return -EINVAL;
+	}
+	if (offsetbytes + sizebytes > memdesc->size) {
+		KGSL_MEM_ERR("bad range: offset %d size %d memdesc %d\n",
+				offsetbytes, sizebytes, memdesc->size);
+		return -ERANGE;
+	}
+	memcpy(memdesc->hostptr + offsetbytes, value, sizebytes);
+	return 0;
+}
+
+int
+kgsl_sharedmem_set(const struct kgsl_memdesc *memdesc, unsigned int offsetbytes,
+			unsigned int value, unsigned int sizebytes)
+{
+	if (memdesc == NULL || memdesc->hostptr == NULL) {
+		KGSL_MEM_ERR("bad ptr memdesc %p hostptr %p\n", memdesc,
+				(memdesc ? memdesc->hostptr : NULL));
+		return -EINVAL;
+	}
+	if (offsetbytes + sizebytes > memdesc->size) {
+		KGSL_MEM_ERR("bad range: offset %d size %d memdesc %d\n",
+				offsetbytes, sizebytes, memdesc->size);
+		return -ERANGE;
+	}
+	memset(memdesc->hostptr + offsetbytes, value, sizebytes);
+	return 0;
+}
+
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_sharedmem.h b/drivers/video/msm/gpu/kgsl/kgsl_sharedmem.h
new file mode 100644
index 0000000..eaf8406
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_sharedmem.h
@@ -0,0 +1,111 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#ifndef __GSL_SHAREDMEM_H
+#define __GSL_SHAREDMEM_H
+
+#include <linux/types.h>
+#include <linux/msm_kgsl.h>
+
+#define KGSL_PAGESIZE           0x1000
+#define KGSL_PAGESIZE_SHIFT     12
+#define KGSL_PAGEMASK           (~(KGSL_PAGESIZE - 1))
+
+struct kgsl_pagetable;
+
+struct platform_device;
+struct gen_pool;
+
+/* memory allocation flags */
+#define KGSL_MEMFLAGS_ANY	0x00000000 /*dont care*/
+
+#define KGSL_MEMFLAGS_APERTUREANY 0x00000000
+#define KGSL_MEMFLAGS_EMEM	0x00000000
+#define KGSL_MEMFLAGS_CONPHYS 	0x00001000
+
+#define KGSL_MEMFLAGS_ALIGNANY	0x00000000
+#define KGSL_MEMFLAGS_ALIGN32	0x00000000
+#define KGSL_MEMFLAGS_ALIGN64	0x00060000
+#define KGSL_MEMFLAGS_ALIGN128	0x00070000
+#define KGSL_MEMFLAGS_ALIGN256	0x00080000
+#define KGSL_MEMFLAGS_ALIGN512	0x00090000
+#define KGSL_MEMFLAGS_ALIGN1K	0x000A0000
+#define KGSL_MEMFLAGS_ALIGN2K	0x000B0000
+#define KGSL_MEMFLAGS_ALIGN4K	0x000C0000
+#define KGSL_MEMFLAGS_ALIGN8K	0x000D0000
+#define KGSL_MEMFLAGS_ALIGN16K	0x000E0000
+#define KGSL_MEMFLAGS_ALIGN32K	0x000F0000
+#define KGSL_MEMFLAGS_ALIGN64K	0x00100000
+#define KGSL_MEMFLAGS_ALIGNPAGE	KGSL_MEMFLAGS_ALIGN4K
+
+/* fail the alloc if the flags cannot be honored */
+#define KGSL_MEMFLAGS_STRICTREQUEST 0x80000000
+
+#define KGSL_MEMFLAGS_APERTURE_MASK	0x0000F000
+#define KGSL_MEMFLAGS_ALIGN_MASK 	0x00FF0000
+
+#define KGSL_MEMFLAGS_APERTURE_SHIFT	12
+#define KGSL_MEMFLAGS_ALIGN_SHIFT	16
+
+
+/* shared memory allocation */
+struct kgsl_memdesc {
+	struct kgsl_pagetable *pagetable;
+	void  *hostptr;
+	unsigned int gpuaddr;
+	unsigned int physaddr;
+	unsigned int size;
+	unsigned int priv;
+};
+
+struct kgsl_sharedmem {
+	void *baseptr;
+	unsigned int physbase;
+	unsigned int size;
+	struct gen_pool *pool;
+};
+
+int kgsl_sharedmem_alloc(uint32_t flags, int size,
+			struct kgsl_memdesc *memdesc);
+
+/*TODO: add protection flags */
+int kgsl_sharedmem_import(struct kgsl_pagetable *,
+				uint32_t phys_addr,
+				uint32_t size,
+				struct kgsl_memdesc *memdesc);
+
+
+void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc);
+
+
+int kgsl_sharedmem_read(const struct kgsl_memdesc *memdesc, void *dst,
+			unsigned int offsetbytes, unsigned int sizebytes);
+
+int kgsl_sharedmem_write(const struct kgsl_memdesc *memdesc,
+			unsigned int offsetbytes, void *value,
+			unsigned int sizebytes);
+
+int kgsl_sharedmem_set(const struct kgsl_memdesc *memdesc,
+			unsigned int offsetbytes, unsigned int value,
+			unsigned int sizebytes);
+
+int kgsl_sharedmem_init(struct kgsl_sharedmem *shmem);
+
+int kgsl_sharedmem_close(struct kgsl_sharedmem *shmem);
+
+#endif /* __GSL_SHAREDMEM_H */
diff --git a/drivers/video/msm/gpu/kgsl/kgsl_yamato.c b/drivers/video/msm/gpu/kgsl/kgsl_yamato.c
new file mode 100644
index 0000000..af5a6ff
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/kgsl_yamato.c
@@ -0,0 +1,1004 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include "kgsl.h"
+#include "kgsl_log.h"
+#include "kgsl_pm4types.h"
+#include "kgsl_cmdstream.h"
+
+#include "yamato_reg.h"
+
+#define GSL_RBBM_INT_MASK \
+	 (RBBM_INT_CNTL__RDERR_INT_MASK |  \
+	  RBBM_INT_CNTL__DISPLAY_UPDATE_INT_MASK)
+
+#define GSL_SQ_INT_MASK \
+	(SQ_INT_CNTL__PS_WATCHDOG_MASK | \
+	 SQ_INT_CNTL__VS_WATCHDOG_MASK)
+
+/* Yamato MH arbiter config*/
+#define KGSL_CFG_YAMATO_MHARB \
+	(0x10 \
+		| (0 << MH_ARBITER_CONFIG__SAME_PAGE_GRANULARITY__SHIFT) \
+		| (1 << MH_ARBITER_CONFIG__L1_ARB_ENABLE__SHIFT) \
+		| (1 << MH_ARBITER_CONFIG__L1_ARB_HOLD_ENABLE__SHIFT) \
+		| (0 << MH_ARBITER_CONFIG__L2_ARB_CONTROL__SHIFT) \
+		| (1 << MH_ARBITER_CONFIG__PAGE_SIZE__SHIFT) \
+		| (1 << MH_ARBITER_CONFIG__TC_REORDER_ENABLE__SHIFT) \
+		| (1 << MH_ARBITER_CONFIG__TC_ARB_HOLD_ENABLE__SHIFT) \
+		| (0 << MH_ARBITER_CONFIG__IN_FLIGHT_LIMIT_ENABLE__SHIFT) \
+		| (0x8 << MH_ARBITER_CONFIG__IN_FLIGHT_LIMIT__SHIFT) \
+		| (1 << MH_ARBITER_CONFIG__CP_CLNT_ENABLE__SHIFT) \
+		| (1 << MH_ARBITER_CONFIG__VGT_CLNT_ENABLE__SHIFT) \
+		| (1 << MH_ARBITER_CONFIG__TC_CLNT_ENABLE__SHIFT) \
+		| (1 << MH_ARBITER_CONFIG__RB_CLNT_ENABLE__SHIFT) \
+		| (1 << MH_ARBITER_CONFIG__PA_CLNT_ENABLE__SHIFT))
+
+void kgsl_register_dump(struct kgsl_device *device)
+{
+	unsigned int regValue;
+
+	kgsl_yamato_regread(device, REG_RBBM_STATUS, &regValue);
+	KGSL_CMD_ERR("RBBM_STATUS = %8.8X\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_RB_BASE, &regValue);
+	KGSL_CMD_ERR("CP_RB_BASE = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_RB_CNTL, &regValue);
+	KGSL_CMD_ERR("CP_RB_CNTL = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_RB_RPTR_ADDR, &regValue);
+	KGSL_CMD_ERR("CP_RB_RPTR_ADDR = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_RB_RPTR, &regValue);
+	KGSL_CMD_ERR("CP_RB_RPTR = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_RB_WPTR, &regValue);
+	KGSL_CMD_ERR("CP_RB_WPTR = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_RB_RPTR_WR, &regValue);
+	KGSL_CMD_ERR("CP_RB_RPTR_WR = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_INT_CNTL, &regValue);
+	KGSL_CMD_ERR("CP_INT_CNTL = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_INT_STATUS, &regValue);
+	KGSL_CMD_ERR("CP_INT_STATUS = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_ME_CNTL, &regValue);
+	KGSL_CMD_ERR("CP_ME_CNTL = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_ME_STATUS, &regValue);
+	KGSL_CMD_ERR("CP_ME_STATUS = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_RBBM_PM_OVERRIDE1, &regValue);
+	KGSL_CMD_ERR("RBBM_PM_OVERRIDE1 = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_RBBM_PM_OVERRIDE2, &regValue);
+	KGSL_CMD_ERR("RBBM_PM_OVERRIDE2 = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_RBBM_INT_CNTL, &regValue);
+	KGSL_CMD_ERR("RBBM_INT_CNTL = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_RBBM_INT_STATUS, &regValue);
+	KGSL_CMD_ERR("RBBM_INT_STATUS = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_MASTER_INT_SIGNAL, &regValue);
+	KGSL_CMD_ERR("MASTER_INT_SIGNAL = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_IB1_BASE, &regValue);
+	KGSL_CMD_ERR("CP_IB1_BASE = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_IB1_BUFSZ, &regValue);
+	KGSL_CMD_ERR("CP_IB1_BUFSZ = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_IB2_BASE, &regValue);
+	KGSL_CMD_ERR("CP_IB2_BASE = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_IB2_BUFSZ, &regValue);
+	KGSL_CMD_ERR("CP_IB2_BUFSZ = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_CP_STAT, &regValue);
+	KGSL_CMD_ERR("CP_STAT = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_SCRATCH_REG0, &regValue);
+	KGSL_CMD_ERR("SCRATCH_REG0 = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_COHER_SIZE_PM4, &regValue);
+	KGSL_CMD_ERR("COHER_SIZE_PM4 = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_COHER_BASE_PM4, &regValue);
+	KGSL_CMD_ERR("COHER_BASE_PM4 = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_COHER_STATUS_PM4, &regValue);
+	KGSL_CMD_ERR("COHER_STATUS_PM4 = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_RBBM_READ_ERROR, &regValue);
+	KGSL_CMD_ERR("RBBM_READ_ERROR = %08x\n", regValue);
+	kgsl_yamato_regread(device, REG_MH_AXI_ERROR, &regValue);
+	KGSL_CMD_ERR("MH_AXI_ERROR = %08x\n", regValue);
+}
+
+static int kgsl_yamato_gmeminit(struct kgsl_device *device)
+{
+	union reg_rb_edram_info rb_edram_info;
+	unsigned int gmem_size;
+	unsigned int edram_value = 0;
+
+	/* make sure edram range is aligned to size */
+	BUG_ON(device->gmemspace.gpu_base & (device->gmemspace.sizebytes - 1));
+
+	/* get edram_size value equivalent */
+	gmem_size = (device->gmemspace.sizebytes >> 14);
+	while (gmem_size >>= 1)
+		edram_value++;
+
+	rb_edram_info.val = 0;
+
+	rb_edram_info.f.edram_size = edram_value;
+	rb_edram_info.f.edram_mapping_mode = 0; /* EDRAM_MAP_UPPER */
+	/* must be aligned to size */
+	rb_edram_info.f.edram_range = (device->gmemspace.gpu_base >> 14);
+
+	kgsl_yamato_regwrite(device, REG_RB_EDRAM_INFO, rb_edram_info.val);
+
+	return 0;
+}
+
+static int kgsl_yamato_gmemclose(struct kgsl_device *device)
+{
+	kgsl_yamato_regwrite(device, REG_RB_EDRAM_INFO, 0x00000000);
+
+	return 0;
+}
+
+void kgsl_yamato_rbbm_intrcallback(struct kgsl_device *device)
+{
+	unsigned int status = 0;
+	unsigned int rderr = 0;
+
+	KGSL_DRV_VDBG("enter (device=%p)\n", device);
+
+	kgsl_yamato_regread(device, REG_RBBM_INT_STATUS, &status);
+
+	if (status & RBBM_INT_CNTL__RDERR_INT_MASK) {
+		kgsl_yamato_regread(device, REG_RBBM_READ_ERROR, &rderr);
+		KGSL_DRV_FATAL("rbbm read error interrupt: %08x\n", rderr);
+	} else if (status & RBBM_INT_CNTL__DISPLAY_UPDATE_INT_MASK) {
+		KGSL_DRV_DBG("rbbm display update interrupt\n");
+	} else if (status & RBBM_INT_CNTL__GUI_IDLE_INT_MASK) {
+		KGSL_DRV_DBG("rbbm gui idle interrupt\n");
+	} else {
+		KGSL_CMD_DBG("bad bits in REG_CP_INT_STATUS %08x\n", status);
+	}
+
+	status &= GSL_RBBM_INT_MASK;
+	kgsl_yamato_regwrite(device, REG_RBBM_INT_ACK, status);
+
+	KGSL_DRV_VDBG("return\n");
+}
+
+void kgsl_yamato_sq_intrcallback(struct kgsl_device *device)
+{
+	unsigned int status = 0;
+
+	KGSL_DRV_VDBG("enter (device=%p)\n", device);
+
+	kgsl_yamato_regread(device, REG_SQ_INT_STATUS, &status);
+
+	if (status & SQ_INT_CNTL__PS_WATCHDOG_MASK)
+		KGSL_DRV_DBG("sq ps watchdog interrupt\n");
+	else if (status & SQ_INT_CNTL__VS_WATCHDOG_MASK)
+		KGSL_DRV_DBG("sq vs watchdog interrupt\n");
+	else
+		KGSL_DRV_DBG("bad bits in REG_SQ_INT_STATUS %08x\n", status);
+
+
+	status &= GSL_SQ_INT_MASK;
+	kgsl_yamato_regwrite(device, REG_SQ_INT_ACK, status);
+
+	KGSL_DRV_VDBG("return\n");
+}
+
+irqreturn_t kgsl_yamato_isr(int irq, void *data)
+{
+	irqreturn_t result = IRQ_NONE;
+
+	struct kgsl_device *device = &kgsl_driver.yamato_device;
+	unsigned int status;
+
+	kgsl_yamato_regread(device, REG_MASTER_INT_SIGNAL, &status);
+
+	if (status & MASTER_INT_SIGNAL__MH_INT_STAT) {
+		kgsl_mh_intrcallback(device);
+		result = IRQ_HANDLED;
+	}
+
+	if (status & MASTER_INT_SIGNAL__CP_INT_STAT) {
+		kgsl_cp_intrcallback(device);
+		result = IRQ_HANDLED;
+	}
+
+	if (status & MASTER_INT_SIGNAL__RBBM_INT_STAT) {
+		kgsl_yamato_rbbm_intrcallback(device);
+		result = IRQ_HANDLED;
+	}
+
+	if (status & MASTER_INT_SIGNAL__SQ_INT_STAT) {
+		kgsl_yamato_sq_intrcallback(device);
+		result = IRQ_HANDLED;
+	}
+
+
+	return result;
+}
+
+int kgsl_yamato_cleanup_pt(struct kgsl_device *device,
+			struct kgsl_pagetable *pagetable)
+{
+	kgsl_mmu_unmap(pagetable, device->ringbuffer.buffer_desc.gpuaddr,
+		       device->ringbuffer.buffer_desc.size);
+
+	kgsl_mmu_unmap(pagetable, device->ringbuffer.memptrs_desc.gpuaddr,
+		       device->ringbuffer.memptrs_desc.size);
+
+	kgsl_mmu_unmap(pagetable, device->memstore.gpuaddr,
+		       device->memstore.size);
+
+	kgsl_mmu_unmap(pagetable, device->mmu.dummyspace.gpuaddr,
+			device->mmu.dummyspace.size);
+
+	return 0;
+}
+
+int kgsl_yamato_setup_pt(struct kgsl_device *device,
+			struct kgsl_pagetable *pagetable)
+{
+	int result = 0;
+	unsigned int gpuaddr;
+
+	BUG_ON(device->ringbuffer.buffer_desc.physaddr == 0);
+	BUG_ON(device->ringbuffer.memptrs_desc.physaddr == 0);
+	BUG_ON(device->memstore.physaddr == 0);
+	BUG_ON(device->mmu.dummyspace.physaddr == 0);
+
+	result = kgsl_mmu_map(pagetable,
+			      device->ringbuffer.buffer_desc.physaddr,
+			      device->ringbuffer.buffer_desc.size,
+			      GSL_PT_PAGE_RV, &gpuaddr,
+			      KGSL_MEMFLAGS_CONPHYS | KGSL_MEMFLAGS_ALIGN4K);
+
+	if (result)
+		goto error;
+
+	if (device->ringbuffer.buffer_desc.gpuaddr == 0)
+		device->ringbuffer.buffer_desc.gpuaddr = gpuaddr;
+	BUG_ON(device->ringbuffer.buffer_desc.gpuaddr != gpuaddr);
+
+	result = kgsl_mmu_map(pagetable,
+			      device->ringbuffer.memptrs_desc.physaddr,
+			      device->ringbuffer.memptrs_desc.size,
+			      GSL_PT_PAGE_RV | GSL_PT_PAGE_WV, &gpuaddr,
+			      KGSL_MEMFLAGS_CONPHYS | KGSL_MEMFLAGS_ALIGN4K);
+	if (result)
+		goto unmap_buffer_desc;
+
+	if (device->ringbuffer.memptrs_desc.gpuaddr == 0)
+		device->ringbuffer.memptrs_desc.gpuaddr = gpuaddr;
+	BUG_ON(device->ringbuffer.memptrs_desc.gpuaddr != gpuaddr);
+
+	result = kgsl_mmu_map(pagetable, device->memstore.physaddr,
+			      device->memstore.size,
+			      GSL_PT_PAGE_RV | GSL_PT_PAGE_WV, &gpuaddr,
+			      KGSL_MEMFLAGS_CONPHYS | KGSL_MEMFLAGS_ALIGN4K);
+	if (result)
+		goto unmap_memptrs_desc;
+
+	if (device->memstore.gpuaddr == 0)
+		device->memstore.gpuaddr = gpuaddr;
+	BUG_ON(device->memstore.gpuaddr != gpuaddr);
+
+	result = kgsl_mmu_map(pagetable,
+			device->mmu.dummyspace.physaddr,
+			device->mmu.dummyspace.size,
+			GSL_PT_PAGE_RV | GSL_PT_PAGE_WV, &gpuaddr,
+			KGSL_MEMFLAGS_CONPHYS | KGSL_MEMFLAGS_ALIGN4K);
+
+	if (result)
+		goto unmap_memstore_desc;
+
+	if (device->mmu.dummyspace.gpuaddr == 0)
+		device->mmu.dummyspace.gpuaddr = gpuaddr;
+	BUG_ON(device->mmu.dummyspace.gpuaddr != gpuaddr);
+
+	return result;
+
+unmap_memstore_desc:
+	kgsl_mmu_unmap(pagetable, device->memstore.gpuaddr,
+			device->memstore.size);
+
+unmap_memptrs_desc:
+	kgsl_mmu_unmap(pagetable, device->ringbuffer.memptrs_desc.gpuaddr,
+		       device->ringbuffer.memptrs_desc.size);
+unmap_buffer_desc:
+	kgsl_mmu_unmap(pagetable, device->ringbuffer.buffer_desc.gpuaddr,
+		       device->ringbuffer.buffer_desc.size);
+error:
+	return result;
+
+}
+
+#ifdef CONFIG_MSM_KGSL_MMU
+int kgsl_yamato_setstate(struct kgsl_device *device, uint32_t flags)
+{
+	unsigned int link[32];
+	unsigned int *cmds = &link[0];
+	int sizedwords = 0;
+	unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */
+
+	KGSL_MEM_DBG("device %p ctxt %p pt %p\n",
+			device,
+			device->drawctxt_active,
+			device->mmu.hwpagetable);
+	/* if possible, set via command stream,
+	* otherwise set via direct register writes
+	*/
+	if (device->drawctxt_active) {
+		KGSL_MEM_DBG("cmds\n");
+		if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+			/* wait for graphics pipe to be idle */
+			*cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+			*cmds++ = 0x00000000;
+
+			/* set page table base */
+			*cmds++ = pm4_type0_packet(REG_MH_MMU_PT_BASE, 1);
+			*cmds++ = device->mmu.hwpagetable->base.gpuaddr;
+			sizedwords += 4;
+		}
+
+		if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+			*cmds++ = pm4_type0_packet(REG_MH_MMU_INVALIDATE, 1);
+			*cmds++ = mh_mmu_invalidate;
+			sizedwords += 2;
+		}
+
+		if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+			/* HW workaround: to resolve MMU page fault interrupts
+			* caused by the VGT.It prevents the CP PFP from filling
+			* the VGT DMA request fifo too early,thereby ensuring
+			* that the VGT will not fetch vertex/bin data until
+			* after the page table base register has been updated.
+			*
+			* Two null DRAW_INDX_BIN packets are inserted right
+			* after the page table base update, followed by a
+			* wait for idle. The null packets will fill up the
+			* VGT DMA request fifo and prevent any further
+			* vertex/bin updates from occurring until the wait
+			* has finished. */
+			*cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2);
+			*cmds++ = (0x4 << 16) |
+				(REG_PA_SU_SC_MODE_CNTL - 0x2000);
+			*cmds++ = 0;          /* disable faceness generation */
+			*cmds++ = pm4_type3_packet(PM4_SET_BIN_BASE_OFFSET, 1);
+			*cmds++ = device->mmu.dummyspace.gpuaddr;
+			*cmds++ = pm4_type3_packet(PM4_DRAW_INDX_BIN, 6);
+			*cmds++ = 0;          /* viz query info */
+			*cmds++ = 0x0003C004; /* draw indicator */
+			*cmds++ = 0;          /* bin base */
+			*cmds++ = 3;          /* bin size */
+			*cmds++ = device->mmu.dummyspace.gpuaddr; /* dma base */
+			*cmds++ = 6;          /* dma size */
+			*cmds++ = pm4_type3_packet(PM4_DRAW_INDX_BIN, 6);
+			*cmds++ = 0;          /* viz query info */
+			*cmds++ = 0x0003C004; /* draw indicator */
+			*cmds++ = 0;          /* bin base */
+			*cmds++ = 3;          /* bin size */
+			/* dma base */
+			*cmds++ = device->mmu.dummyspace.gpuaddr;
+			*cmds++ = 6;          /* dma size */
+			*cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1);
+			*cmds++ = 0x00000000;
+			sizedwords += 21;
+		}
+
+		if (flags & (KGSL_MMUFLAGS_PTUPDATE | KGSL_MMUFLAGS_TLBFLUSH)) {
+			*cmds++ = pm4_type3_packet(PM4_INVALIDATE_STATE, 1);
+			*cmds++ = 0x7fff; /* invalidate all base pointers */
+			sizedwords += 2;
+		}
+
+		kgsl_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
+					  &link[0], sizedwords);
+	} else {
+		KGSL_MEM_DBG("regs\n");
+
+		if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+			kgsl_yamato_idle(device, KGSL_TIMEOUT_DEFAULT);
+			kgsl_yamato_regwrite(device, REG_MH_MMU_PT_BASE,
+				     device->mmu.hwpagetable->base.gpuaddr);
+		}
+
+		if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+			kgsl_yamato_regwrite(device, REG_MH_MMU_INVALIDATE,
+					     mh_mmu_invalidate);
+		}
+	}
+
+	return 0;
+}
+#endif
+
+static unsigned int
+kgsl_yamato_getchipid(struct kgsl_device *device)
+{
+	unsigned int chipid;
+	unsigned int coreid, majorid, minorid, patchid, revid;
+
+	/* YDX */
+	kgsl_yamato_regread(device, REG_RBBM_PERIPHID1, &coreid);
+	coreid &= 0xF;
+
+	kgsl_yamato_regread(device, REG_RBBM_PERIPHID2, &majorid);
+	majorid = (majorid >> 4) & 0xF;
+
+	kgsl_yamato_regread(device, REG_RBBM_PATCH_RELEASE, &revid);
+	/* this is a 16bit field, but extremely unlikely it would ever get
+	* this high
+	*/
+	minorid = ((revid >> 0)  & 0xFF);
+
+
+	patchid = ((revid >> 16) & 0xFF);
+
+	chipid  = ((coreid << 24) | (majorid << 16) |
+			(minorid << 8) | (patchid << 0));
+
+	/* Hardware revision 211 (8650) returns the wrong chip ID */
+	if (chipid == KGSL_CHIPID_YAMATODX_REV21)
+		chipid = KGSL_CHIPID_YAMATODX_REV211;
+
+	return chipid;
+}
+
+int kgsl_yamato_init(struct kgsl_device *device, struct kgsl_devconfig *config)
+{
+	int status = -EINVAL;
+	int init_reftimestamp = 0x7fffffff;
+	struct kgsl_memregion *regspace = &device->regspace;
+	unsigned int memflags = KGSL_MEMFLAGS_ALIGNPAGE | KGSL_MEMFLAGS_CONPHYS;
+
+	KGSL_DRV_VDBG("enter (device=%p, config=%p)\n", device, config);
+
+	if (device->flags & KGSL_FLAGS_INITIALIZED) {
+		KGSL_DRV_VDBG("return %d\n", 0);
+		return 0;
+	}
+	memset(device, 0, sizeof(*device));
+
+	init_waitqueue_head(&device->ib1_wq);
+
+	memcpy(regspace, &config->regspace, sizeof(device->regspace));
+	if (regspace->mmio_phys_base == 0 || regspace->sizebytes == 0) {
+		KGSL_DRV_ERR("dev %d invalid regspace\n", device->id);
+		goto error;
+	}
+	if (!request_mem_region(regspace->mmio_phys_base,
+				regspace->sizebytes, DRIVER_NAME)) {
+		KGSL_DRV_ERR("request_mem_region failed for register memory\n");
+		status = -ENODEV;
+		goto error;
+	}
+
+	regspace->mmio_virt_base = ioremap(regspace->mmio_phys_base,
+					   regspace->sizebytes);
+	KGSL_MEM_INFO("ioremap(regs) = %p\n", regspace->mmio_virt_base);
+	if (regspace->mmio_virt_base == NULL) {
+		KGSL_DRV_ERR("ioremap failed for register memory\n");
+		status = -ENODEV;
+		goto error_release_mem;
+	}
+
+	KGSL_DRV_INFO("dev %d regs phys 0x%08x size 0x%08x virt %p\n",
+			device->id, regspace->mmio_phys_base,
+			regspace->sizebytes, regspace->mmio_virt_base);
+
+	memcpy(&device->gmemspace, &config->gmemspace,
+			sizeof(device->gmemspace));
+
+	device->id = KGSL_DEVICE_YAMATO;
+
+	if (config->mmu_config) {
+		device->mmu.config    = config->mmu_config;
+		device->mmu.mpu_base  = config->mpu_base;
+		device->mmu.mpu_range = config->mpu_range;
+		device->mmu.va_base	  = config->va_base;
+		device->mmu.va_range  = config->va_range;
+	}
+
+	device->chip_id = kgsl_yamato_getchipid(device);
+
+	/*We need to make sure all blocks are powered up and clocked before
+	*issuing a soft reset.  The overrides will be turned off (set to 0)
+	*later in kgsl_yamato_start.
+	*/
+	kgsl_yamato_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0xfffffffe);
+	kgsl_yamato_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xffffffff);
+
+	kgsl_yamato_regwrite(device, REG_RBBM_SOFT_RESET, 0xFFFFFFFF);
+	msleep(50);
+	kgsl_yamato_regwrite(device, REG_RBBM_SOFT_RESET, 0x00000000);
+
+	kgsl_yamato_regwrite(device, REG_RBBM_CNTL, 0x00004442);
+
+	kgsl_yamato_regwrite(device, REG_MH_ARBITER_CONFIG,
+				KGSL_CFG_YAMATO_MHARB);
+
+	kgsl_yamato_regwrite(device, REG_SQ_VS_PROGRAM, 0x00000000);
+	kgsl_yamato_regwrite(device, REG_SQ_PS_PROGRAM, 0x00000000);
+
+
+	status = kgsl_mmu_init(device);
+	if (status != 0) {
+		status = -ENODEV;
+		goto error_iounmap;
+	}
+
+	status = kgsl_cmdstream_init(device);
+	if (status != 0) {
+		status = -ENODEV;
+		goto error_close_mmu;
+	}
+
+	status = kgsl_sharedmem_alloc(memflags, sizeof(device->memstore),
+					&device->memstore);
+	if (status != 0)  {
+		status = -ENODEV;
+		goto error_close_cmdstream;
+	}
+	kgsl_sharedmem_set(&device->memstore, 0, 0, device->memstore.size);
+
+	kgsl_sharedmem_write(&device->memstore,
+			     KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts),
+			     &init_reftimestamp, 4);
+
+	kgsl_yamato_regwrite(device, REG_RBBM_DEBUG, 0x00080000);
+	pr_info("msm_kgsl: initilized dev=%d mmu=%s\n", device->id,
+		kgsl_mmu_isenabled(&device->mmu) ? "on" : "off");
+
+	device->flags |= KGSL_FLAGS_INITIALIZED;
+	return 0;
+
+error_close_cmdstream:
+	kgsl_cmdstream_close(device);
+error_close_mmu:
+	kgsl_mmu_close(device);
+error_iounmap:
+	iounmap(regspace->mmio_virt_base);
+	regspace->mmio_virt_base = NULL;
+error_release_mem:
+	release_mem_region(regspace->mmio_phys_base, regspace->sizebytes);
+error:
+	return status;
+}
+
+int kgsl_yamato_close(struct kgsl_device *device)
+{
+	struct kgsl_memregion *regspace = &device->regspace;
+
+	if (device->memstore.hostptr)
+		kgsl_sharedmem_free(&device->memstore);
+
+	kgsl_mmu_close(device);
+
+	kgsl_cmdstream_close(device);
+
+	if (regspace->mmio_virt_base != NULL) {
+		KGSL_MEM_INFO("iounmap(regs) = %p\n", regspace->mmio_virt_base);
+		iounmap(regspace->mmio_virt_base);
+		regspace->mmio_virt_base = NULL;
+		release_mem_region(regspace->mmio_phys_base,
+					regspace->sizebytes);
+	}
+
+	KGSL_DRV_VDBG("return %d\n", 0);
+	device->flags &= ~KGSL_FLAGS_INITIALIZED;
+	return 0;
+}
+
+int kgsl_yamato_start(struct kgsl_device *device, uint32_t flags)
+{
+	int status = -EINVAL;
+
+	KGSL_DRV_VDBG("enter (device=%p)\n", device);
+
+	if (!(device->flags & KGSL_FLAGS_INITIALIZED)) {
+		KGSL_DRV_ERR("Trying to start uninitialized device.\n");
+		return -EINVAL;
+	}
+
+	device->refcnt++;
+
+	if (device->flags & KGSL_FLAGS_STARTED) {
+		KGSL_DRV_VDBG("already started");
+		return 0;
+	}
+
+	kgsl_yamato_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0);
+	kgsl_yamato_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0);
+
+	KGSL_DRV_DBG("enabling RBBM interrupts mask 0x%08lx\n",
+		     GSL_RBBM_INT_MASK);
+	kgsl_yamato_regwrite(device, REG_RBBM_INT_CNTL, GSL_RBBM_INT_MASK);
+
+	/* make sure SQ interrupts are disabled */
+	kgsl_yamato_regwrite(device, REG_SQ_INT_CNTL, 0);
+
+	kgsl_yamato_gmeminit(device);
+
+	status = kgsl_ringbuffer_init(device);
+	if (status != 0) {
+		kgsl_yamato_stop(device);
+		return status;
+	}
+
+	status = kgsl_drawctxt_init(device);
+	if (status != 0) {
+		kgsl_yamato_stop(device);
+		return status;
+	}
+
+	device->flags |= KGSL_FLAGS_STARTED;
+
+	KGSL_DRV_VDBG("return %d\n", status);
+	return status;
+}
+
+int kgsl_yamato_stop(struct kgsl_device *device)
+{
+	if (device->flags & KGSL_FLAGS_STARTED) {
+
+		kgsl_yamato_regwrite(device, REG_RBBM_INT_CNTL, 0);
+
+		kgsl_yamato_regwrite(device, REG_SQ_INT_CNTL, 0);
+
+		kgsl_drawctxt_close(device);
+
+		kgsl_ringbuffer_close(&device->ringbuffer);
+
+		kgsl_yamato_gmemclose(device);
+
+		device->flags &= ~KGSL_FLAGS_STARTED;
+	}
+
+	return 0;
+}
+
+int kgsl_yamato_getproperty(struct kgsl_device *device,
+				enum kgsl_property_type type,
+				void *value,
+				unsigned int sizebytes)
+{
+	int status = -EINVAL;
+
+	switch (type) {
+	case KGSL_PROP_DEVICE_INFO:
+		{
+			struct kgsl_devinfo devinfo;
+
+			if (sizebytes != sizeof(devinfo)) {
+				status = -EINVAL;
+				break;
+			}
+
+			memset(&devinfo, 0, sizeof(devinfo));
+			devinfo.device_id = device->id;
+			devinfo.chip_id = device->chip_id;
+			devinfo.mmu_enabled = kgsl_mmu_isenabled(&device->mmu);
+			devinfo.gmem_hostbaseaddr =
+				(unsigned int)device->gmemspace.mmio_virt_base;
+			devinfo.gmem_gpubaseaddr = device->gmemspace.gpu_base;
+			devinfo.gmem_sizebytes = device->gmemspace.sizebytes;
+
+			if (copy_to_user(value, &devinfo, sizeof(devinfo)) !=
+					0) {
+				status = -EFAULT;
+				break;
+			}
+			status = 0;
+		}
+		break;
+	case KGSL_PROP_DEVICE_SHADOW:
+		{
+			struct kgsl_shadowprop shadowprop;
+
+			if (sizebytes != sizeof(shadowprop)) {
+				status = -EINVAL;
+				break;
+			}
+			memset(&shadowprop, 0, sizeof(shadowprop));
+			if (device->memstore.hostptr) {
+				/*NOTE: with mmu enabled, gpuaddr doesn't mean
+				 * anything to mmap().
+				 */
+				shadowprop.gpuaddr = device->memstore.physaddr;
+				shadowprop.size = device->memstore.size;
+				shadowprop.flags = KGSL_FLAGS_INITIALIZED;
+			}
+			if (copy_to_user(value, &shadowprop,
+				sizeof(shadowprop))) {
+				status = -EFAULT;
+				break;
+			}
+			status = 0;
+		}
+		break;
+	case KGSL_PROP_MMU_ENABLE:
+		{
+#ifdef CONFIG_MSM_KGSL_MMU
+			int mmuProp = 1;
+#else
+			int mmuProp = 0;
+#endif
+			if (sizebytes != sizeof(int)) {
+				status = -EINVAL;
+				break;
+			}
+			if (copy_to_user(value, &mmuProp, sizeof(mmuProp))) {
+				status = -EFAULT;
+				break;
+			}
+			status = 0;
+		}
+		break;
+	case KGSL_PROP_INTERRUPT_WAITS:
+		{
+			int int_waits = 1;
+			if (sizebytes != sizeof(int)) {
+				status = -EINVAL;
+				break;
+			}
+			if (copy_to_user(value, &int_waits, sizeof(int))) {
+				status = -EFAULT;
+				break;
+			}
+			status = 0;
+		}
+		break;
+	default:
+		status = -EINVAL;
+	}
+
+	return status;
+}
+
+/* Note: This is either called from the standby timer, or while holding the
+ * driver mutex.
+ *
+ * The reader may obseve that this function may be called without holding the
+ * driver mutex (in the timer), which can cause the ringbuffer write pointer
+ * to change, when a user submits a command. However, the user must be holding
+ * the driver mutex when doing so, and then must
+ * have canceled the timer. If the timer was executing at the time of
+ * cancellation, the active flag would have been cleared, which the user
+ * ioctl checks for after cancelling the timer.
+ */
+bool kgsl_yamato_is_idle(struct kgsl_device *device)
+{
+	struct kgsl_ringbuffer *rb = &device->ringbuffer;
+	unsigned int rbbm_status;
+
+	BUG_ON(!(rb->flags & KGSL_FLAGS_STARTED));
+
+	GSL_RB_GET_READPTR(rb, &rb->rptr);
+	if (rb->rptr == rb->wptr) {
+		kgsl_yamato_regread(device, REG_RBBM_STATUS, &rbbm_status);
+		if (rbbm_status == 0x110)
+			return true;
+	}
+	return false;
+}
+
+int kgsl_yamato_idle(struct kgsl_device *device, unsigned int timeout)
+{
+	int status = -EINVAL;
+	struct kgsl_ringbuffer *rb = &device->ringbuffer;
+	struct kgsl_mmu_debug mmu_dbg;
+	unsigned int rbbm_status;
+	int idle_count = 0;
+#define IDLE_COUNT_MAX 1000000
+
+	KGSL_DRV_VDBG("enter (device=%p, timeout=%d)\n", device, timeout);
+
+	(void)timeout;
+
+	/* first, wait until the CP has consumed all the commands in
+	 * the ring buffer
+	 */
+	if (rb->flags & KGSL_FLAGS_STARTED) {
+		do {
+			idle_count++;
+			GSL_RB_GET_READPTR(rb, &rb->rptr);
+
+		} while (rb->rptr != rb->wptr && idle_count < IDLE_COUNT_MAX);
+		if (idle_count == IDLE_COUNT_MAX)
+			goto err;
+	}
+	/* now, wait for the GPU to finish its operations */
+	for (idle_count = 0; idle_count < IDLE_COUNT_MAX; idle_count++) {
+		kgsl_yamato_regread(device, REG_RBBM_STATUS, &rbbm_status);
+
+		if (rbbm_status == 0x110) {
+			status = 0;
+			goto done;
+		}
+	}
+
+err:
+	KGSL_DRV_ERR("spun too long waiting for RB to idle\n");
+	kgsl_register_dump(device);
+	kgsl_ringbuffer_dump(rb);
+	kgsl_mmu_debug(&device->mmu, &mmu_dbg);
+	BUG();
+
+done:
+	KGSL_DRV_VDBG("return %d\n", status);
+
+	return status;
+}
+
+int kgsl_yamato_regread(struct kgsl_device *device, unsigned int offsetwords,
+				unsigned int *value)
+{
+	unsigned int *reg;
+
+	if (offsetwords*sizeof(uint32_t) >= device->regspace.sizebytes) {
+		KGSL_DRV_ERR("invalid offset %d\n", offsetwords);
+		return -ERANGE;
+	}
+
+	reg = (unsigned int *)(device->regspace.mmio_virt_base
+				+ (offsetwords << 2));
+	*value = readl(reg);
+
+	return 0;
+}
+
+int kgsl_yamato_regwrite(struct kgsl_device *device, unsigned int offsetwords,
+				unsigned int value)
+{
+	unsigned int *reg;
+
+	if (offsetwords*sizeof(uint32_t) >= device->regspace.sizebytes) {
+		KGSL_DRV_ERR("invalid offset %d\n", offsetwords);
+		return -ERANGE;
+	}
+
+	reg = (unsigned int *)(device->regspace.mmio_virt_base
+				+ (offsetwords << 2));
+	writel(value, reg);
+
+	return 0;
+}
+
+static inline int _wait_timestamp(struct kgsl_device *device,
+				unsigned int timestamp,
+				unsigned int msecs)
+{
+	long status;
+
+	status = wait_event_interruptible_timeout(device->ib1_wq,
+			kgsl_cmdstream_check_timestamp(device, timestamp),
+			msecs_to_jiffies(msecs));
+
+	if (status > 0)
+		status = 0;
+	else if (status == 0) {
+		if (!kgsl_cmdstream_check_timestamp(device, timestamp)) {
+			status = -ETIMEDOUT;
+			kgsl_register_dump(device);
+		}
+	}
+
+	return (int)status;
+}
+
+/* MUST be called with the kgsl_driver.mutex held */
+int kgsl_yamato_waittimestamp(struct kgsl_device *device,
+				unsigned int timestamp,
+				unsigned int msecs)
+{
+	long status = 0;
+	uint32_t ref_ts;
+	int enableflag = 1;
+	unsigned int cmd[2];
+
+	KGSL_DRV_INFO("enter (device=%p,timestamp=%d,timeout=0x%08x)\n",
+			device, timestamp, msecs);
+
+	if (!kgsl_cmdstream_check_timestamp(device, timestamp)) {
+		kgsl_sharedmem_read(&device->memstore, &ref_ts,
+			KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts), 4);
+		if (timestamp_cmp(ref_ts, timestamp)) {
+			kgsl_sharedmem_write(&device->memstore,
+				KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts),
+				&timestamp, 4);
+		}
+
+		cmd[0] = pm4_type3_packet(PM4_INTERRUPT, 1);
+		cmd[1] = CP_INT_CNTL__IB1_INT_MASK;
+		kgsl_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NO_TS_CMP,
+					  cmd, 2);
+		kgsl_sharedmem_write(&device->memstore,
+			KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable),
+			&enableflag, 4);
+
+		mutex_unlock(&kgsl_driver.mutex);
+		status = _wait_timestamp(device, timestamp, msecs);
+		mutex_lock(&kgsl_driver.mutex);
+	}
+
+	KGSL_DRV_INFO("return %ld\n", status);
+	return (int)status;
+}
+
+int kgsl_yamato_runpending(struct kgsl_device *device)
+{
+	if (device->flags & KGSL_FLAGS_INITIALIZED)
+		kgsl_cmdstream_memqueue_drain(device);
+	return 0;
+}
+
+int __init kgsl_yamato_config(struct kgsl_devconfig *devconfig,
+				struct platform_device *pdev)
+{
+	int result = 0;
+	struct resource *res = NULL;
+
+	memset(devconfig, 0, sizeof(*devconfig));
+
+	/*find memory regions */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			"kgsl_reg_memory");
+	if (res == NULL) {
+		KGSL_DRV_ERR("platform_get_resource_byname failed\n");
+		result = -EINVAL;
+		goto done;
+	}
+	KGSL_DRV_DBG("registers at %08x to %08x\n", res->start, res->end);
+	devconfig->regspace.mmio_phys_base = res->start;
+	devconfig->regspace.sizebytes = resource_size(res);
+
+	devconfig->gmemspace.gpu_base = 0;
+	devconfig->gmemspace.sizebytes = SZ_256K;
+
+	/*note: for all of these behavior masks:
+	 *	0 = do not translate
+	 *	1 = translate within va_range, otherwise use physical
+	 *	2 = translate within va_range, otherwise fault
+	 */
+	devconfig->mmu_config = 1 /* mmu enable */
+		    | (2 << MH_MMU_CONFIG__RB_W_CLNT_BEHAVIOR__SHIFT)
+		    | (2 << MH_MMU_CONFIG__CP_W_CLNT_BEHAVIOR__SHIFT)
+		    | (2 << MH_MMU_CONFIG__CP_R0_CLNT_BEHAVIOR__SHIFT)
+		    | (2 << MH_MMU_CONFIG__CP_R1_CLNT_BEHAVIOR__SHIFT)
+		    | (2 << MH_MMU_CONFIG__CP_R2_CLNT_BEHAVIOR__SHIFT)
+		    | (2 << MH_MMU_CONFIG__CP_R3_CLNT_BEHAVIOR__SHIFT)
+		    | (2 << MH_MMU_CONFIG__CP_R4_CLNT_BEHAVIOR__SHIFT)
+		    | (2 << MH_MMU_CONFIG__VGT_R0_CLNT_BEHAVIOR__SHIFT)
+		    | (2 << MH_MMU_CONFIG__VGT_R1_CLNT_BEHAVIOR__SHIFT)
+		    | (2 << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT)
+		    | (2 << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT);
+
+	/*TODO: these should probably be configurable from platform device
+	 * stuff */
+	devconfig->va_base = 0x66000000;
+	devconfig->va_range = SZ_128M;
+
+	/* turn off memory protection unit by setting acceptable physical
+	 * address range to include all pages. Apparrently MPU causing
+	 * problems.
+	 */
+	devconfig->mpu_base = 0x00000000;
+	devconfig->mpu_range = 0xFFFFF000;
+
+	result = 0;
+done:
+	return result;
+}
diff --git a/drivers/video/msm/gpu/kgsl/yamato_reg.h b/drivers/video/msm/gpu/kgsl/yamato_reg.h
new file mode 100644
index 0000000..828b95a
--- /dev/null
+++ b/drivers/video/msm/gpu/kgsl/yamato_reg.h
@@ -0,0 +1,400 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#ifndef _YAMATO_REG_H
+#define _YAMATO_REG_H
+
+enum VGT_EVENT_TYPE {
+ VS_DEALLOC = 0,
+ PS_DEALLOC = 1,
+ VS_DONE_TS = 2,
+ PS_DONE_TS = 3,
+ CACHE_FLUSH_TS = 4,
+ CONTEXT_DONE = 5,
+ CACHE_FLUSH = 6,
+ VIZQUERY_START = 7,
+ VIZQUERY_END = 8,
+ SC_WAIT_WC = 9,
+ RST_PIX_CNT = 13,
+ RST_VTX_CNT = 14,
+ TILE_FLUSH = 15,
+ CACHE_FLUSH_AND_INV_TS_EVENT = 20,
+ ZPASS_DONE = 21,
+ CACHE_FLUSH_AND_INV_EVENT = 22,
+ PERFCOUNTER_START = 23,
+ PERFCOUNTER_STOP = 24,
+ VS_FETCH_DONE = 27,
+ FACENESS_FLUSH = 28,
+};
+
+enum COLORFORMATX {
+ COLORX_4_4_4_4 = 0,
+ COLORX_1_5_5_5 = 1,
+ COLORX_5_6_5 = 2,
+ COLORX_8 = 3,
+ COLORX_8_8 = 4,
+ COLORX_8_8_8_8 = 5,
+ COLORX_S8_8_8_8 = 6,
+ COLORX_16_FLOAT = 7,
+ COLORX_16_16_FLOAT = 8,
+ COLORX_16_16_16_16_FLOAT = 9,
+ COLORX_32_FLOAT = 10,
+ COLORX_32_32_FLOAT = 11,
+ COLORX_32_32_32_32_FLOAT = 12,
+ COLORX_2_3_3 = 13,
+ COLORX_8_8_8 = 14,
+};
+
+enum SURFACEFORMAT {
+    FMT_1_REVERSE                  = 0,
+    FMT_1                          = 1,
+    FMT_8                          = 2,
+    FMT_1_5_5_5                    = 3,
+    FMT_5_6_5                      = 4,
+    FMT_6_5_5                      = 5,
+    FMT_8_8_8_8                    = 6,
+    FMT_2_10_10_10                 = 7,
+    FMT_8_A                        = 8,
+    FMT_8_B                        = 9,
+    FMT_8_8                        = 10,
+    FMT_Cr_Y1_Cb_Y0                = 11,
+    FMT_Y1_Cr_Y0_Cb                = 12,
+    FMT_5_5_5_1                    = 13,
+    FMT_8_8_8_8_A                  = 14,
+    FMT_4_4_4_4                    = 15,
+    FMT_10_11_11                   = 16,
+    FMT_11_11_10                   = 17,
+    FMT_DXT1                       = 18,
+    FMT_DXT2_3                     = 19,
+    FMT_DXT4_5                     = 20,
+    FMT_24_8                       = 22,
+    FMT_24_8_FLOAT                 = 23,
+    FMT_16                         = 24,
+    FMT_16_16                      = 25,
+    FMT_16_16_16_16                = 26,
+    FMT_16_EXPAND                  = 27,
+    FMT_16_16_EXPAND               = 28,
+    FMT_16_16_16_16_EXPAND         = 29,
+    FMT_16_FLOAT                   = 30,
+    FMT_16_16_FLOAT                = 31,
+    FMT_16_16_16_16_FLOAT          = 32,
+    FMT_32                         = 33,
+    FMT_32_32                      = 34,
+    FMT_32_32_32_32                = 35,
+    FMT_32_FLOAT                   = 36,
+    FMT_32_32_FLOAT                = 37,
+    FMT_32_32_32_32_FLOAT          = 38,
+    FMT_32_AS_8                    = 39,
+    FMT_32_AS_8_8                  = 40,
+    FMT_16_MPEG                    = 41,
+    FMT_16_16_MPEG                 = 42,
+    FMT_8_INTERLACED               = 43,
+    FMT_32_AS_8_INTERLACED         = 44,
+    FMT_32_AS_8_8_INTERLACED       = 45,
+    FMT_16_INTERLACED              = 46,
+    FMT_16_MPEG_INTERLACED         = 47,
+    FMT_16_16_MPEG_INTERLACED      = 48,
+    FMT_DXN                        = 49,
+    FMT_8_8_8_8_AS_16_16_16_16     = 50,
+	FMT_DXT1_AS_16_16_16_16        = 51,
+    FMT_DXT2_3_AS_16_16_16_16      = 52,
+    FMT_DXT4_5_AS_16_16_16_16      = 53,
+    FMT_2_10_10_10_AS_16_16_16_16  = 54,
+    FMT_10_11_11_AS_16_16_16_16    = 55,
+    FMT_11_11_10_AS_16_16_16_16    = 56,
+    FMT_32_32_32_FLOAT             = 57,
+    FMT_DXT3A                      = 58,
+    FMT_DXT5A                      = 59,
+    FMT_CTX1                       = 60,
+    FMT_DXT3A_AS_1_1_1_1           = 61
+};
+
+#define RB_EDRAM_INFO_EDRAM_SIZE_SIZE                      4
+#define RB_EDRAM_INFO_EDRAM_MAPPING_MODE_SIZE              2
+#define RB_EDRAM_INFO_UNUSED0_SIZE                         8
+#define RB_EDRAM_INFO_EDRAM_RANGE_SIZE                     18
+
+struct rb_edram_info_t {
+    unsigned int edram_size:RB_EDRAM_INFO_EDRAM_SIZE_SIZE;
+    unsigned int edram_mapping_mode:RB_EDRAM_INFO_EDRAM_MAPPING_MODE_SIZE;
+    unsigned int unused0:RB_EDRAM_INFO_UNUSED0_SIZE;
+    unsigned int edram_range:RB_EDRAM_INFO_EDRAM_RANGE_SIZE;
+};
+
+union reg_rb_edram_info {
+    unsigned int val:32;
+    struct rb_edram_info_t f;
+};
+
+#define CP_RB_CNTL_RB_BUFSZ_SIZE                           6
+#define CP_RB_CNTL_UNUSED0_SIZE                            2
+#define CP_RB_CNTL_RB_BLKSZ_SIZE                           6
+#define CP_RB_CNTL_UNUSED1_SIZE                            2
+#define CP_RB_CNTL_BUF_SWAP_SIZE                           2
+#define CP_RB_CNTL_UNUSED2_SIZE                            2
+#define CP_RB_CNTL_RB_POLL_EN_SIZE                         1
+#define CP_RB_CNTL_UNUSED3_SIZE                            6
+#define CP_RB_CNTL_RB_NO_UPDATE_SIZE                       1
+#define CP_RB_CNTL_UNUSED4_SIZE                            3
+#define CP_RB_CNTL_RB_RPTR_WR_ENA_SIZE                     1
+
+struct cp_rb_cntl_t {
+    unsigned int rb_bufsz:CP_RB_CNTL_RB_BUFSZ_SIZE;
+    unsigned int unused0:CP_RB_CNTL_UNUSED0_SIZE;
+    unsigned int rb_blksz:CP_RB_CNTL_RB_BLKSZ_SIZE;
+    unsigned int unused1:CP_RB_CNTL_UNUSED1_SIZE;
+    unsigned int buf_swap:CP_RB_CNTL_BUF_SWAP_SIZE;
+    unsigned int unused2:CP_RB_CNTL_UNUSED2_SIZE;
+    unsigned int rb_poll_en:CP_RB_CNTL_RB_POLL_EN_SIZE;
+    unsigned int unused3:CP_RB_CNTL_UNUSED3_SIZE;
+    unsigned int rb_no_update:CP_RB_CNTL_RB_NO_UPDATE_SIZE;
+    unsigned int unused4:CP_RB_CNTL_UNUSED4_SIZE;
+    unsigned int rb_rptr_wr_ena:CP_RB_CNTL_RB_RPTR_WR_ENA_SIZE;
+};
+
+union reg_cp_rb_cntl {
+    unsigned int val:32;
+    struct cp_rb_cntl_t f;
+};
+
+#define RB_COLOR_INFO__COLOR_FORMAT_MASK                   0x0000000fL
+#define RB_COPY_DEST_INFO__COPY_DEST_FORMAT__SHIFT         0x00000004
+
+
+#define SQ_INT_CNTL__PS_WATCHDOG_MASK                      0x00000001L
+#define SQ_INT_CNTL__VS_WATCHDOG_MASK                      0x00000002L
+
+#define MH_INTERRUPT_MASK__AXI_READ_ERROR                  0x00000001L
+#define MH_INTERRUPT_MASK__AXI_WRITE_ERROR                 0x00000002L
+#define MH_INTERRUPT_MASK__MMU_PAGE_FAULT                  0x00000004L
+
+#define RBBM_INT_CNTL__RDERR_INT_MASK                      0x00000001L
+#define RBBM_INT_CNTL__DISPLAY_UPDATE_INT_MASK             0x00000002L
+#define RBBM_INT_CNTL__GUI_IDLE_INT_MASK                   0x00080000L
+
+#define RBBM_STATUS__CMDFIFO_AVAIL_MASK                    0x0000001fL
+#define RBBM_STATUS__TC_BUSY_MASK                          0x00000020L
+#define RBBM_STATUS__HIRQ_PENDING_MASK                     0x00000100L
+#define RBBM_STATUS__CPRQ_PENDING_MASK                     0x00000200L
+#define RBBM_STATUS__CFRQ_PENDING_MASK                     0x00000400L
+#define RBBM_STATUS__PFRQ_PENDING_MASK                     0x00000800L
+#define RBBM_STATUS__VGT_BUSY_NO_DMA_MASK                  0x00001000L
+#define RBBM_STATUS__RBBM_WU_BUSY_MASK                     0x00004000L
+#define RBBM_STATUS__CP_NRT_BUSY_MASK                      0x00010000L
+#define RBBM_STATUS__MH_BUSY_MASK                          0x00040000L
+#define RBBM_STATUS__MH_COHERENCY_BUSY_MASK                0x00080000L
+#define RBBM_STATUS__SX_BUSY_MASK                          0x00200000L
+#define RBBM_STATUS__TPC_BUSY_MASK                         0x00400000L
+#define RBBM_STATUS__SC_CNTX_BUSY_MASK                     0x01000000L
+#define RBBM_STATUS__PA_BUSY_MASK                          0x02000000L
+#define RBBM_STATUS__VGT_BUSY_MASK                         0x04000000L
+#define RBBM_STATUS__SQ_CNTX17_BUSY_MASK                   0x08000000L
+#define RBBM_STATUS__SQ_CNTX0_BUSY_MASK                    0x10000000L
+#define RBBM_STATUS__RB_CNTX_BUSY_MASK                     0x40000000L
+#define RBBM_STATUS__GUI_ACTIVE_MASK                       0x80000000L
+
+#define CP_INT_CNTL__SW_INT_MASK                           0x00080000L
+#define CP_INT_CNTL__T0_PACKET_IN_IB_MASK                  0x00800000L
+#define CP_INT_CNTL__OPCODE_ERROR_MASK                     0x01000000L
+#define CP_INT_CNTL__PROTECTED_MODE_ERROR_MASK             0x02000000L
+#define CP_INT_CNTL__RESERVED_BIT_ERROR_MASK               0x04000000L
+#define CP_INT_CNTL__IB_ERROR_MASK                         0x08000000L
+#define CP_INT_CNTL__IB2_INT_MASK                          0x20000000L
+#define CP_INT_CNTL__IB1_INT_MASK                          0x40000000L
+#define CP_INT_CNTL__RB_INT_MASK                           0x80000000L
+
+#define MASTER_INT_SIGNAL__MH_INT_STAT                     0x00000020L
+#define MASTER_INT_SIGNAL__SQ_INT_STAT                     0x04000000L
+#define MASTER_INT_SIGNAL__CP_INT_STAT                     0x40000000L
+#define MASTER_INT_SIGNAL__RBBM_INT_STAT                   0x80000000L
+
+#define RB_EDRAM_INFO__EDRAM_SIZE_MASK                     0x0000000fL
+#define RB_EDRAM_INFO__EDRAM_RANGE_MASK                    0xffffc000L
+
+#define	MH_ARBITER_CONFIG__SAME_PAGE_GRANULARITY__SHIFT    0x00000006
+#define	MH_ARBITER_CONFIG__L1_ARB_ENABLE__SHIFT            0x00000007
+#define	MH_ARBITER_CONFIG__L1_ARB_HOLD_ENABLE__SHIFT       0x00000008
+#define	MH_ARBITER_CONFIG__L2_ARB_CONTROL__SHIFT           0x00000009
+#define	MH_ARBITER_CONFIG__PAGE_SIZE__SHIFT                0x0000000a
+#define	MH_ARBITER_CONFIG__TC_REORDER_ENABLE__SHIFT        0x0000000d
+#define	MH_ARBITER_CONFIG__TC_ARB_HOLD_ENABLE__SHIFT       0x0000000e
+#define	MH_ARBITER_CONFIG__IN_FLIGHT_LIMIT_ENABLE__SHIFT   0x0000000f
+#define	MH_ARBITER_CONFIG__IN_FLIGHT_LIMIT__SHIFT          0x00000010
+#define	MH_ARBITER_CONFIG__CP_CLNT_ENABLE__SHIFT           0x00000016
+#define	MH_ARBITER_CONFIG__VGT_CLNT_ENABLE__SHIFT          0x00000017
+#define	MH_ARBITER_CONFIG__TC_CLNT_ENABLE__SHIFT           0x00000018
+#define	MH_ARBITER_CONFIG__RB_CLNT_ENABLE__SHIFT           0x00000019
+#define	MH_ARBITER_CONFIG__PA_CLNT_ENABLE__SHIFT           0x0000001a
+
+#define	MH_MMU_CONFIG__RB_W_CLNT_BEHAVIOR__SHIFT           0x00000004
+#define	MH_MMU_CONFIG__CP_W_CLNT_BEHAVIOR__SHIFT           0x00000006
+#define	MH_MMU_CONFIG__CP_R0_CLNT_BEHAVIOR__SHIFT          0x00000008
+#define	MH_MMU_CONFIG__CP_R1_CLNT_BEHAVIOR__SHIFT          0x0000000a
+#define	MH_MMU_CONFIG__CP_R2_CLNT_BEHAVIOR__SHIFT          0x0000000c
+#define	MH_MMU_CONFIG__CP_R3_CLNT_BEHAVIOR__SHIFT          0x0000000e
+#define	MH_MMU_CONFIG__CP_R4_CLNT_BEHAVIOR__SHIFT          0x00000010
+#define	MH_MMU_CONFIG__VGT_R0_CLNT_BEHAVIOR__SHIFT         0x00000012
+#define	MH_MMU_CONFIG__VGT_R1_CLNT_BEHAVIOR__SHIFT         0x00000014
+#define	MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT           0x00000016
+#define	MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT           0x00000018
+
+#define	CP_RB_CNTL__RB_BUFSZ__SHIFT                        0x00000000
+#define	CP_RB_CNTL__RB_BLKSZ__SHIFT                        0x00000008
+#define	CP_RB_CNTL__RB_POLL_EN__SHIFT                      0x00000014
+#define	CP_RB_CNTL__RB_NO_UPDATE__SHIFT                    0x0000001b
+
+#define	RB_COLOR_INFO__COLOR_FORMAT__SHIFT                 0x00000000
+#define	RB_EDRAM_INFO__EDRAM_MAPPING_MODE__SHIFT           0x00000004
+#define	RB_EDRAM_INFO__EDRAM_RANGE__SHIFT                  0x0000000e
+
+#define REG_CP_CSQ_IB1_STAT              0x01FE
+#define REG_CP_CSQ_IB2_STAT              0x01FF
+#define REG_CP_CSQ_RB_STAT               0x01FD
+#define REG_CP_DEBUG                     0x01FC
+#define REG_CP_IB1_BASE                  0x0458
+#define REG_CP_IB1_BUFSZ                 0x0459
+#define REG_CP_IB2_BASE                  0x045A
+#define REG_CP_IB2_BUFSZ                 0x045B
+#define REG_CP_INT_ACK                   0x01F4
+#define REG_CP_INT_CNTL                  0x01F2
+#define REG_CP_INT_STATUS                0x01F3
+#define REG_CP_ME_CNTL                   0x01F6
+#define REG_CP_ME_RAM_DATA               0x01FA
+#define REG_CP_ME_RAM_WADDR              0x01F8
+#define REG_CP_ME_STATUS                 0x01F7
+#define REG_CP_PFP_UCODE_ADDR            0x00C0
+#define REG_CP_PFP_UCODE_DATA            0x00C1
+#define REG_CP_QUEUE_THRESHOLDS          0x01D5
+#define REG_CP_RB_BASE                   0x01C0
+#define REG_CP_RB_CNTL                   0x01C1
+#define REG_CP_RB_RPTR                   0x01C4
+#define REG_CP_RB_RPTR_ADDR              0x01C3
+#define REG_CP_RB_RPTR_WR                0x01C7
+#define REG_CP_RB_WPTR                   0x01C5
+#define REG_CP_RB_WPTR_BASE              0x01C8
+#define REG_CP_RB_WPTR_DELAY             0x01C6
+#define REG_CP_STAT                      0x047F
+#define REG_CP_STATE_DEBUG_DATA          0x01ED
+#define REG_CP_STATE_DEBUG_INDEX         0x01EC
+#define REG_CP_ST_BASE                   0x044D
+#define REG_CP_ST_BUFSZ                  0x044E
+
+#define REG_MASTER_INT_SIGNAL            0x03B7
+
+#define REG_MH_ARBITER_CONFIG            0x0A40
+#define REG_MH_INTERRUPT_CLEAR           0x0A44
+#define REG_MH_INTERRUPT_MASK            0x0A42
+#define REG_MH_INTERRUPT_STATUS          0x0A43
+#define REG_MH_MMU_CONFIG                0x0040
+#define REG_MH_MMU_INVALIDATE            0x0045
+#define REG_MH_MMU_MPU_BASE              0x0046
+#define REG_MH_MMU_MPU_END               0x0047
+#define REG_MH_MMU_PAGE_FAULT            0x0043
+#define REG_MH_MMU_PT_BASE               0x0042
+#define REG_MH_MMU_TRAN_ERROR            0x0044
+#define REG_MH_MMU_VA_RANGE              0x0041
+
+#define REG_PA_CL_VPORT_XSCALE           0x210F
+#define REG_PA_CL_VPORT_ZOFFSET          0x2114
+#define REG_PA_CL_VPORT_ZSCALE           0x2113
+#define REG_PA_CL_VTE_CNTL               0x2206
+#define REG_PA_SC_AA_MASK                0x2312
+#define REG_PA_SC_LINE_CNTL              0x2300
+#define REG_PA_SC_SCREEN_SCISSOR_BR      0x200F
+#define REG_PA_SC_SCREEN_SCISSOR_TL      0x200E
+#define REG_PA_SC_VIZ_QUERY              0x2293
+#define REG_PA_SC_VIZ_QUERY_STATUS       0x0C44
+#define REG_PA_SC_WINDOW_OFFSET          0x2080
+#define REG_PA_SC_WINDOW_SCISSOR_BR      0x2082
+#define REG_PA_SC_WINDOW_SCISSOR_TL      0x2081
+#define REG_PA_SU_FACE_DATA              0x0C86
+#define REG_PA_SU_POINT_SIZE             0x2280
+#define REG_PA_SU_POLY_OFFSET_BACK_OFFSET 0x2383
+#define REG_PA_SU_POLY_OFFSET_FRONT_SCALE 0x2380
+#define REG_PA_SU_SC_MODE_CNTL           0x2205
+
+#define REG_RBBM_CNTL                    0x003B
+#define REG_RBBM_INT_ACK                 0x03B6
+#define REG_RBBM_INT_CNTL                0x03B4
+#define REG_RBBM_INT_STATUS              0x03B5
+#define REG_RBBM_PATCH_RELEASE           0x0001
+#define REG_RBBM_PERIPHID1               0x03F9
+#define REG_RBBM_PERIPHID2               0x03FA
+#define REG_RBBM_DEBUG                   0x039B
+#define REG_RBBM_PM_OVERRIDE1            0x039C
+#define REG_RBBM_PM_OVERRIDE2            0x039D
+#define REG_RBBM_READ_ERROR              0x03B3
+#define REG_RBBM_SOFT_RESET              0x003C
+#define REG_RBBM_STATUS                  0x05D0
+
+#define REG_RB_COLORCONTROL              0x2202
+#define REG_RB_COLOR_DEST_MASK           0x2326
+#define REG_RB_COLOR_MASK                0x2104
+#define REG_RB_COPY_CONTROL              0x2318
+#define REG_RB_DEPTHCONTROL              0x2200
+#define REG_RB_EDRAM_INFO                0x0F02
+#define REG_RB_MODECONTROL               0x2208
+#define REG_RB_SURFACE_INFO              0x2000
+
+#define REG_SCRATCH_ADDR                 0x01DD
+#define REG_SCRATCH_REG0                 0x0578
+#define REG_SCRATCH_REG2                 0x057A
+#define REG_SCRATCH_UMSK                 0x01DC
+
+#define REG_SQ_CF_BOOLEANS               0x4900
+#define REG_SQ_CF_LOOP                   0x4908
+#define REG_SQ_GPR_MANAGEMENT            0x0D00
+#define REG_SQ_INST_STORE_MANAGMENT      0x0D02
+#define REG_SQ_INT_ACK                   0x0D36
+#define REG_SQ_INT_CNTL                  0x0D34
+#define REG_SQ_INT_STATUS                0x0D35
+#define REG_SQ_PROGRAM_CNTL              0x2180
+#define REG_SQ_PS_PROGRAM                0x21F6
+#define REG_SQ_VS_PROGRAM                0x21F7
+#define REG_SQ_WRAPPING_0                0x2183
+#define REG_SQ_WRAPPING_1                0x2184
+
+#define REG_VGT_ENHANCE                  0x2294
+#define REG_VGT_INDX_OFFSET              0x2102
+#define REG_VGT_MAX_VTX_INDX             0x2100
+#define REG_VGT_MIN_VTX_INDX             0x2101
+
+#define REG_TP0_CHICKEN					 0x0E1E
+#define REG_TC_CNTL_STATUS             	 0x0E00
+#define REG_PA_SC_AA_CONFIG            	 0x2301
+#define REG_VGT_VERTEX_REUSE_BLOCK_CNTL  0x2316
+#define REG_SQ_INTERPOLATOR_CNTL         0x2182
+#define REG_RB_DEPTH_INFO                0x2002
+#define REG_COHER_DEST_BASE_0            0x2006
+#define REG_PA_SC_SCREEN_SCISSOR_BR      0x200F
+#define REG_RB_FOG_COLOR                 0x2109
+#define REG_RB_STENCILREFMASK_BF         0x210C
+#define REG_PA_SC_LINE_STIPPLE           0x2283
+#define REG_SQ_PS_CONST                  0x2308
+#define REG_VGT_VERTEX_REUSE_BLOCK_CNTL  0x2316
+#define REG_RB_DEPTH_CLEAR               0x231D
+#define REG_RB_SAMPLE_COUNT_CTL          0x2324
+#define REG_SQ_CONSTANT_0                0x4000
+#define REG_SQ_FETCH_0                   0x4800
+
+#define REG_MH_AXI_ERROR		 0xA45
+#define REG_COHER_BASE_PM4		 0xA2A
+#define REG_COHER_STATUS_PM4		 0xA2B
+#define REG_COHER_SIZE_PM4		 0xA29
+
+#endif /* _YAMATO_REG_H */
diff --git a/drivers/video/msm/logo.c b/drivers/video/msm/logo.c
new file mode 100644
index 0000000..7272765
--- /dev/null
+++ b/drivers/video/msm/logo.c
@@ -0,0 +1,98 @@
+/* drivers/video/msm/logo.c
+ *
+ * Show Logo in RLE 565 format
+ *
+ * Copyright (C) 2008 Google 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/module.h>
+#include <linux/types.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/unistd.h>
+#include <linux/syscalls.h>
+
+#include <linux/irq.h>
+#include <asm/system.h>
+
+#define fb_width(fb)	((fb)->var.xres)
+#define fb_height(fb)	((fb)->var.yres)
+#define fb_size(fb)	((fb)->var.xres * (fb)->var.yres * 2)
+
+static void memset16(void *_ptr, unsigned short val, unsigned count)
+{
+	unsigned short *ptr = _ptr;
+	count >>= 1;
+	while (count--)
+		*ptr++ = val;
+}
+
+/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
+int load_565rle_image(char *filename)
+{
+	struct fb_info *info;
+	int fd, err = 0;
+	unsigned count, max;
+	unsigned short *data, *bits, *ptr;
+
+	info = registered_fb[0];
+	if (!info) {
+		printk(KERN_WARNING "%s: Can not access framebuffer\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	fd = sys_open(filename, O_RDONLY, 0);
+	if (fd < 0) {
+		printk(KERN_WARNING "%s: Can not open %s\n",
+			__func__, filename);
+		return -ENOENT;
+	}
+	count = (unsigned)sys_lseek(fd, (off_t)0, 2);
+	if (count == 0) {
+		sys_close(fd);
+		err = -EIO;
+		goto err_logo_close_file;
+	}
+	sys_lseek(fd, (off_t)0, 0);
+	data = kmalloc(count, GFP_KERNEL);
+	if (!data) {
+		printk(KERN_WARNING "%s: Can not alloc data\n", __func__);
+		err = -ENOMEM;
+		goto err_logo_close_file;
+	}
+	if ((unsigned)sys_read(fd, (char *)data, count) != count) {
+		err = -EIO;
+		goto err_logo_free_data;
+	}
+
+	max = fb_width(info) * fb_height(info);
+	ptr = data;
+	bits = (unsigned short *)(info->screen_base);
+	while (count > 3) {
+		unsigned n = ptr[0];
+		if (n > max)
+			break;
+		memset16(bits, ptr[1], n << 1);
+		bits += n;
+		max -= n;
+		ptr += 2;
+		count -= 4;
+	}
+
+err_logo_free_data:
+	kfree(data);
+err_logo_close_file:
+	sys_close(fd);
+	return err;
+}
+EXPORT_SYMBOL(load_565rle_image);
diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c
index c1ff271..927bbc4 100644
--- a/drivers/video/msm/mddi.c
+++ b/drivers/video/msm/mddi.c
@@ -29,6 +29,10 @@
 #include <mach/msm_iomap.h>
 #include <mach/irqs.h>
 #include <mach/board.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/wakelock.h>
+
 #include <mach/msm_fb.h>
 #include "mddi_hw.h"
 
@@ -40,6 +44,8 @@
 #define CMD_GET_CLIENT_CAP     0x0601
 #define CMD_GET_CLIENT_STATUS  0x0602
 
+static uint32_t mddi_debug_flags;
+
 union mddi_rev {
 	unsigned char raw[MDDI_REV_BUFFER_SIZE];
 	struct mddi_rev_packet hdr;
@@ -61,6 +67,8 @@
 	char __iomem *base;
 	int irq;
 	struct clk *clk;
+	struct clk *pclk;
+	unsigned long clk_rate;
 	struct msm_mddi_client_data client_data;
 
 	/* buffer for rev encap packets */
@@ -84,14 +92,21 @@
 	struct mddi_client_caps caps;
 	struct mddi_client_status status;
 
+	struct wake_lock idle_lock;
+	struct wake_lock link_active_idle_lock;
+
 	void (*power_client)(struct msm_mddi_client_data *, int);
 
+	/* used to save/restore pad config during suspend */
+	uint32_t pad_ctrl;
+
 	/* client device published to bind us to the
 	 * appropriate mddi_client driver
 	 */
 	char client_name[20];
 
 	struct platform_device client_pdev;
+	struct resource client_vsync_res;
 };
 
 static void mddi_init_rev_encap(struct mddi_info *mddi);
@@ -103,7 +118,7 @@
 {
 	struct mddi_info *mddi = container_of(cdata, struct mddi_info,
 					      client_data);
-
+	wake_lock(&mddi->link_active_idle_lock);
 	mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD);
 }
 
@@ -127,6 +142,8 @@
 
 	if ((rev->hdr.length <= MDDI_REV_BUFFER_SIZE - 2) &&
 	   (rev->hdr.length >= sizeof(struct mddi_rev_packet) - 2)) {
+		/* printk(KERN_INFO "rev: len=%04x type=%04x\n",
+		 * rev->hdr.length, rev->hdr.type); */
 
 		switch (rev->hdr.type) {
 		case TYPE_CLIENT_CAPS:
@@ -142,6 +159,9 @@
 			wake_up(&mddi->int_wait);
 			break;
 		case TYPE_REGISTER_ACCESS:
+			/* printk(KERN_INFO "rev: reg %x = %x\n",
+			 * rev->reg.register_address,
+			 * rev->reg.register_data_list); */
 			ri = mddi->reg_read;
 			if (ri == 0) {
 				printk(KERN_INFO "rev: got reg %x = %x without "
@@ -203,6 +223,8 @@
 	rev_crc_err_count = mddi_readl(REV_CRC_ERR);
 	if (rev_data_count > 1)
 		printk(KERN_INFO "rev_data_count %d\n", rev_data_count);
+	/* printk(KERN_INFO "rev_data_count %d, INT %x\n", rev_data_count,
+	 * mddi_readl(INT)); */
 
 	if (rev_crc_err_count) {
 		printk(KERN_INFO "rev_crc_err_count %d, INT %x\n",
@@ -222,6 +244,20 @@
 	if (rev_data_count == 0)
 		return;
 
+	if (mddi_debug_flags & 1) {
+		printk(KERN_INFO "INT %x, STAT %x, CURR_REV_PTR %x\n",
+		       mddi_readl(INT), mddi_readl(STAT),
+		       mddi_readl(CURR_REV_PTR));
+		for (i = 0; i < MDDI_REV_BUFFER_SIZE; i++) {
+			if ((i % 16) == 0)
+				printk(KERN_INFO "\n");
+			printk(KERN_INFO " %02x", rev->raw[i]);
+		}
+		printk(KERN_INFO "\n");
+	}
+
+	/* printk(KERN_INFO "rev_data_curr %d + %d\n", mddi->rev_data_curr,
+	 * crev->hdr.length); */
 	prev_offset = mddi->rev_data_curr;
 
 	length = *((uint8_t *)mddi->rev_data + mddi->rev_data_curr);
@@ -247,12 +283,23 @@
 		memcpy(&tmprev.raw[0], mddi->rev_data + prev_offset, rem);
 		memcpy(&tmprev.raw[rem], mddi->rev_data, 2 + length - rem);
 		mddi_handle_rev_data(mddi, &tmprev);
+		if (mddi_debug_flags & 2) {
+			memset(mddi->rev_data + prev_offset, 0xee, rem);
+			memset(mddi->rev_data, 0xee, mddi->rev_data_curr);
+		}
 	} else {
 		mddi_handle_rev_data(mddi, crev);
+		if (mddi_debug_flags & 2)
+			memset(mddi->rev_data + prev_offset, 0xee,
+			       mddi->rev_data_curr - prev_offset);
 	}
 
+	/* if(mddi->rev_data_curr + MDDI_MAX_REV_PKT_SIZE >=
+	 * MDDI_REV_BUFFER_SIZE) { */
 	if (prev_offset < MDDI_REV_BUFFER_SIZE / 2 &&
 	    mddi->rev_data_curr >= MDDI_REV_BUFFER_SIZE / 2) {
+		/* printk(KERN_INFO "passed buffer half full: rev_data_curr
+		 * %d\n", mddi->rev_data_curr); */
 		mddi_writel(mddi->rev_addr, REV_PTR);
 	}
 }
@@ -271,6 +318,9 @@
 
 	mddi_writel(active, INT);
 
+	/* printk(KERN_INFO "%s: isr a=%08x e=%08x s=%08x\n",
+		mddi->name, active, mddi->int_enable, status); */
+
 	/* ignore any interrupts we have disabled */
 	active &= mddi->int_enable;
 
@@ -290,11 +340,13 @@
 	if (active & MDDI_INT_LINK_ACTIVE) {
 		mddi->int_enable &= (~MDDI_INT_LINK_ACTIVE);
 		mddi->int_enable |= MDDI_INT_IN_HIBERNATION;
+		wake_lock(&mddi->link_active_idle_lock);
 	}
 
 	if (active & MDDI_INT_IN_HIBERNATION) {
 		mddi->int_enable &= (~MDDI_INT_IN_HIBERNATION);
 		mddi->int_enable |= MDDI_INT_LINK_ACTIVE;
+		wake_unlock(&mddi->link_active_idle_lock);
 	}
 
 	mddi_writel(mddi->int_enable, INTEN);
@@ -354,7 +406,10 @@
 	mddi_writel(MDDI_HOST_TA2_LEN, TA2_LEN);
 	mddi_writel(0x0096, DRIVE_HI);
 	/* 0x32 normal, 0x50 for Toshiba display */
+
+	/* XXX: should we use 0x32? */
 	mddi_writel(0x0050, DRIVE_LO);
+
 	mddi_writel(0x003C, DISP_WAKE); /* wakeup counter */
 	mddi_writel(MDDI_HOST_REV_RATE_DIV, REV_RATE_DIV);
 
@@ -372,16 +427,26 @@
 		udelay(5);
 	}
 
+	/* XXX: NEED SUPPORT FOR 1.2 */
+
 	/* Recommendation from PAD hw team */
 	mddi_writel(0xa850f, PAD_CTL);
 
+#if defined(CONFIG_MSM_MDP31) || defined(CONFIG_MSM_MDP40)
+	mddi_writel(0x00320000, PAD_IO_CTL);
+	mddi_writel(0x00220020, PAD_CAL);
+#endif
 
 	/* Need an even number for counts */
 	mddi_writel(0x60006, DRIVER_START_CNT);
 
 	mddi_set_auto_hibernate(&mddi->client_data, 0);
 
+#if 1 /* ignore listen */
 	mddi_writel(MDDI_CMD_DISP_IGNORE, CMD);
+#else
+	mddi_writel(MDDI_CMD_DISP_LISTEN, CMD);
+#endif
 	mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
 
 	mddi_init_rev_encap(mddi);
@@ -392,26 +457,39 @@
 {
 	struct mddi_info *mddi = container_of(cdata, struct mddi_info,
 					      client_data);
+	wake_lock(&mddi->idle_lock);
 	/* turn off the client */
 	if (mddi->power_client)
 		mddi->power_client(&mddi->client_data, 0);
 	/* turn off the link */
 	mddi_writel(MDDI_CMD_RESET, CMD);
 	mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
+	/* save pad ctrl and power down the drivers */
+	mddi->pad_ctrl = mddi_readl(PAD_CTL);
+	mddi_writel(0, PAD_CTL);
+	/* release rate request to not hold any high speed plls */
+	clk_set_rate(mddi->clk, 0);
 	/* turn off the clock */
+	if (mddi->pclk)
+		clk_disable(mddi->pclk);
 	clk_disable(mddi->clk);
+	wake_unlock(&mddi->idle_lock);
 }
 
 static void mddi_resume(struct msm_mddi_client_data *cdata)
 {
 	struct mddi_info *mddi = container_of(cdata, struct mddi_info,
 					      client_data);
+	wake_lock(&mddi->idle_lock);
+	clk_enable(mddi->clk);
+	if (mddi->pclk)
+		clk_enable(mddi->pclk);
+	clk_set_rate(mddi->clk, mddi->clk_rate);
+	mddi_writel(mddi->pad_ctrl, PAD_CTL);
 	mddi_set_auto_hibernate(&mddi->client_data, 0);
 	/* turn on the client */
 	if (mddi->power_client)
 		mddi->power_client(&mddi->client_data, 1);
-	/* turn on the clock */
-	clk_enable(mddi->clk);
 	/* set up the local registers */
 	mddi->rev_data_curr = 0;
 	mddi_init_registers(mddi);
@@ -420,6 +498,7 @@
 	mddi_writel(MDDI_CMD_SEND_RTD, CMD);
 	mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
 	mddi_set_auto_hibernate(&mddi->client_data, 1);
+	wake_unlock(&mddi->idle_lock);
 }
 
 static int __init mddi_get_client_caps(struct mddi_info *mddi)
@@ -518,6 +597,7 @@
 					      client_data);
 	struct mddi_llentry *ll;
 	struct mddi_register_access *ra;
+	/* unsigned s; */
 
 	mutex_lock(&mddi->reg_write_lock);
 
@@ -541,9 +621,19 @@
 	ll->next = 0;
 	ll->reserved = 0;
 
+	/* s = mddi_readl(STAT); */
+	/* printk(KERN_INFO "mddi_remote_write(%x, %x), stat = %x\n", val,
+	 * reg, s); */
+
 	mddi_writel(mddi->reg_write_addr, PRI_PTR);
 
+	/* s = mddi_readl(STAT); */
+	/* printk(KERN_INFO "mddi_remote_write(%x, %x) sent, stat = %x\n",
+	 * val, reg, s); */
+
 	mddi_wait_interrupt(mddi, MDDI_INT_PRI_LINK_LIST_DONE);
+	/* printk(KERN_INFO "mddi_remote_write(%x, %x) done, stat = %x\n",
+	 * val, reg, s); */
 	mutex_unlock(&mddi->reg_write_lock);
 }
 
@@ -579,6 +669,7 @@
 	ll->reserved = 0;
 
 	s = mddi_readl(STAT);
+	/* printk(KERN_INFO "mddi_remote_read(%x), stat = %x\n", reg, s); */
 
 	ri.reg = reg;
 	ri.status = -1;
@@ -589,6 +680,14 @@
 		mddi_writel(mddi->reg_read_addr, PRI_PTR);
 
 		mddi_wait_interrupt(mddi, MDDI_INT_PRI_LINK_LIST_DONE);
+		/* s = mddi_readl(STAT); */
+		/* printk(KERN_INFO "mddi_remote_read(%x) sent, stat = %x\n",
+		 * reg, s); */
+
+		/* s = mddi_readl(STAT); */
+		/* while((s & MDDI_STAT_PRI_LINK_LIST_DONE) == 0){ */
+		/*	s = mddi_readl(STAT); */
+		/* } */
 
 		/* Enable Periodic Reverse Encapsulation. */
 		mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 1, CMD);
@@ -607,8 +706,14 @@
 		if (ri.status == 0)
 			break;
 
+		/* printk(KERN_INFO "mddi_remote_read: failed, sent
+		 * MDDI_CMD_SEND_RTD: int %x, stat %x, rtd val %x\n",
+		 * mddi_readl(INT), mddi_readl(STAT), mddi_readl(RTD_VAL)); */
 		mddi_writel(MDDI_CMD_SEND_RTD, CMD);
 		mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD);
+		/* printk(KERN_INFO "mddi_remote_read: failed, sent
+		 * MDDI_CMD_SEND_RTD: int %x, stat %x, rtd val %x\n",
+		 * mddi_readl(INT), mddi_readl(STAT), mddi_readl(RTD_VAL)); */
 		mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
 		printk(KERN_INFO "mddi_remote_read: failed, sent "
 		       "MDDI_CMD_SEND_RTD: int %x, stat %x, rtd val %x "
@@ -618,6 +723,8 @@
 	/* Disable Periodic Reverse Encapsulation. */
 	mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 0, CMD);
 	mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
+	/* printk(KERN_INFO "mddi_remote_read(%x) done, stat = %x,
+	 * return %x\n", reg, s, ri.result); */
 	mddi->reg_read = NULL;
 	mutex_unlock(&mddi->reg_read_lock);
 	return ri.result;
@@ -637,15 +744,26 @@
 		printk(KERN_INFO "mddi: failed to get clock\n");
 		return PTR_ERR(mddi->clk);
 	}
-	ret =  clk_enable(mddi->clk);
-	if (ret)
-		goto fail;
-	ret = clk_set_rate(mddi->clk, clk_rate);
+	mddi->pclk = clk_get(&pdev->dev, "mddi_pclk");
+	if (IS_ERR(mddi->pclk))
+		mddi->pclk = NULL;
+
+	clk_enable(mddi->clk);
+	if (mddi->pclk)
+		clk_enable(mddi->pclk);
+
+	mddi->clk_rate = clk_rate;
+	ret = clk_set_rate(mddi->clk, mddi->clk_rate);
 	if (ret)
 		goto fail;
 	return 0;
 
 fail:
+	if (mddi->pclk) {
+		clk_disable(mddi->pclk);
+		clk_put(mddi->pclk);
+	}
+	clk_disable(mddi->clk);
 	clk_put(mddi->clk);
 	return ret;
 }
@@ -670,7 +788,7 @@
 	return 0;
 }
 
-static int __init mddi_probe(struct platform_device *pdev)
+static int mddi_probe(struct platform_device *pdev)
 {
 	struct msm_mddi_platform_data *pdata = pdev->dev.platform_data;
 	struct mddi_info *mddi = &mddi_info[pdev->id];
@@ -704,6 +822,10 @@
 	spin_lock_init(&mddi->int_lock);
 	init_waitqueue_head(&mddi->int_wait);
 
+	wake_lock_init(&mddi->idle_lock, WAKE_LOCK_IDLE, "mddi_idle_lock");
+	wake_lock_init(&mddi->link_active_idle_lock, WAKE_LOCK_IDLE,
+		       "mddi_link_active_idle_lock");
+
 	ret = mddi_clk_setup(pdev, mddi, pdata->clk_rate);
 	if (ret) {
 		printk(KERN_ERR "mddi: failed to setup clock!\n");
@@ -741,6 +863,8 @@
 		goto error_mddi_version;
 	}
 
+	printk(KERN_INFO "mddi: host core version: 0x%02x\n", mddi->version);
+
 	/* read the capabilities off the client */
 	if (!mddi_get_client_caps(mddi)) {
 		printk(KERN_INFO "mddi: no client found\n");
@@ -753,6 +877,9 @@
 	}
 	mddi_set_auto_hibernate(&mddi->client_data, 1);
 
+	pr_info("%s: got mfr %04x product %04x\n", __func__,
+		mddi->caps.Mfr_Name, mddi->caps.Product_Code);
+
 	if (mddi->caps.Mfr_Name == 0 && mddi->caps.Product_Code == 0)
 		pdata->fixup(&mddi->caps.Mfr_Name, &mddi->caps.Product_Code);
 
@@ -794,6 +921,15 @@
 		goto error_mddi_interface;
 	}
 
+	if (pdata->vsync_irq) {
+		mddi->client_vsync_res.start = pdata->vsync_irq;
+		mddi->client_vsync_res.end = pdata->vsync_irq;
+		mddi->client_vsync_res.flags = IORESOURCE_IRQ;
+		mddi->client_vsync_res.name = "vsync";
+		mddi->client_pdev.resource = &mddi->client_vsync_res;
+		mddi->client_pdev.num_resources = 1;
+	}
+
 	mddi->client_pdev.dev.platform_data = &mddi->client_data;
 	printk(KERN_INFO "mddi: publish: %s\n", mddi->client_name);
 	platform_device_register(&mddi->client_pdev);
@@ -806,6 +942,8 @@
 	dma_free_coherent(NULL, 0x1000, mddi->rev_data, mddi->rev_addr);
 error_rev_data:
 error_clk_setup:
+	wake_lock_destroy(&mddi->idle_lock);
+	wake_lock_destroy(&mddi->link_active_idle_lock);
 error_get_irq_resource:
 	iounmap(mddi->base);
 error_ioremap:
@@ -814,6 +952,37 @@
 	return ret;
 }
 
+#if 0 /* read/write mddi registers from userspace */
+module_param_named(debug, mddi_debug_flags, uint, 0644);
+
+static uint32_t selected_register;
+module_param_named(reg, selected_register, uint, 0644);
+
+static int set_reg(const char *val, struct kernel_param *kp)
+{
+	char *endp;
+	uint32_t l;
+
+	if (!val)
+		return -EINVAL;
+	l = simple_strtoul(val, &endp, 0);
+	if (endp == val || ((uint32_t)l != l))
+		return -EINVAL;
+	mddi_remote_write(kp->arg, l, selected_register);
+	return 0;
+}
+
+static int get_reg(char *buffer, struct kernel_param *kp)
+{
+	int val;
+	val = mddi_remote_read(kp->arg, selected_register);
+	return sprintf(buffer, "%x", val);
+}
+
+module_param_call(pmdh_val, set_reg, get_reg, &mddi_info[0], 0644);
+module_param_call(emdh_val, set_reg, get_reg, &mddi_info[1], 0644);
+
+#endif
 
 static struct platform_driver mddi_driver = {
 	.probe = mddi_probe,
diff --git a/drivers/video/msm/mddi_client_dummy.c b/drivers/video/msm/mddi_client_dummy.c
deleted file mode 100644
index d2a091c..0000000
--- a/drivers/video/msm/mddi_client_dummy.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/* drivers/video/msm_fb/mddi_client_dummy.c
- *
- * Support for "dummy" mddi client devices which require no
- * special initialization code.
- *
- * Copyright (C) 2007 Google 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/slab.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-
-#include <mach/msm_fb.h>
-
-struct panel_info {
-	struct platform_device pdev;
-	struct msm_panel_data panel_data;
-};
-
-static int mddi_dummy_suspend(struct msm_panel_data *panel_data)
-{
-	return 0;
-}
-
-static int mddi_dummy_resume(struct msm_panel_data *panel_data)
-{
-	return 0;
-}
-
-static int mddi_dummy_blank(struct msm_panel_data *panel_data)
-{
-	return 0;
-}
-
-static int mddi_dummy_unblank(struct msm_panel_data *panel_data)
-{
-	return 0;
-}
-
-static int mddi_dummy_probe(struct platform_device *pdev)
-{
-	struct msm_mddi_client_data *client_data = pdev->dev.platform_data;
-	struct panel_info *panel =
-		kzalloc(sizeof(struct panel_info), GFP_KERNEL);
-	int ret;
-	if (!panel)
-		return -ENOMEM;
-	platform_set_drvdata(pdev, panel);
-	panel->panel_data.suspend = mddi_dummy_suspend;
-	panel->panel_data.resume = mddi_dummy_resume;
-	panel->panel_data.blank = mddi_dummy_blank;
-	panel->panel_data.unblank = mddi_dummy_unblank;
-	panel->panel_data.caps = MSMFB_CAP_PARTIAL_UPDATES;
-	panel->pdev.name = "msm_panel";
-	panel->pdev.id = pdev->id;
-	platform_device_add_resources(&panel->pdev,
-				      client_data->fb_resource, 1);
-	panel->panel_data.fb_data = client_data->private_client_data;
-	panel->pdev.dev.platform_data = &panel->panel_data;
-	ret = platform_device_register(&panel->pdev);
-	if (ret) {
-		kfree(panel);
-		return ret;
-	}
-	return 0;
-}
-
-static int mddi_dummy_remove(struct platform_device *pdev)
-{
-	struct panel_info *panel = platform_get_drvdata(pdev);
-	kfree(panel);
-	return 0;
-}
-
-static struct platform_driver mddi_client_dummy = {
-	.probe = mddi_dummy_probe,
-	.remove = mddi_dummy_remove,
-	.driver = { .name = "mddi_c_dummy" },
-};
-
-static int __init mddi_client_dummy_init(void)
-{
-	platform_driver_register(&mddi_client_dummy);
-	return 0;
-}
-
-module_init(mddi_client_dummy_init);
-
diff --git a/drivers/video/msm/mddi_client_nt35399.c b/drivers/video/msm/mddi_client_nt35399.c
deleted file mode 100644
index f239f4a..0000000
--- a/drivers/video/msm/mddi_client_nt35399.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/* drivers/video/msm_fb/mddi_client_nt35399.c
- *
- * Support for Novatek NT35399 MDDI client of Sapphire
- *
- * Copyright (C) 2008 HTC Incorporated
- * Author: Solomon Chiu (solomon_chiu@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/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-#include <mach/msm_fb.h>
-
-static DECLARE_WAIT_QUEUE_HEAD(nt35399_vsync_wait);
-
-struct panel_info {
-	struct msm_mddi_client_data *client_data;
-	struct platform_device pdev;
-	struct msm_panel_data panel_data;
-	struct msmfb_callback *fb_callback;
-	struct work_struct panel_work;
-	struct workqueue_struct *fb_wq;
-	int nt35399_got_int;
-};
-
-static void
-nt35399_request_vsync(struct msm_panel_data *panel_data,
-		      struct msmfb_callback *callback)
-{
-	struct panel_info *panel = container_of(panel_data, struct panel_info,
-						panel_data);
-	struct msm_mddi_client_data *client_data = panel->client_data;
-
-	panel->fb_callback = callback;
-	if (panel->nt35399_got_int) {
-		panel->nt35399_got_int = 0;
-		client_data->activate_link(client_data); /* clears interrupt */
-	}
-}
-
-static void nt35399_wait_vsync(struct msm_panel_data *panel_data)
-{
-	struct panel_info *panel = container_of(panel_data, struct panel_info,
-						panel_data);
-	struct msm_mddi_client_data *client_data = panel->client_data;
-
-	if (panel->nt35399_got_int) {
-		panel->nt35399_got_int = 0;
-		client_data->activate_link(client_data); /* clears interrupt */
-	}
-
-	if (wait_event_timeout(nt35399_vsync_wait, panel->nt35399_got_int,
-				HZ/2) == 0)
-		printk(KERN_ERR "timeout waiting for VSYNC\n");
-
-	panel->nt35399_got_int = 0;
-	/* interrupt clears when screen dma starts */
-}
-
-static int nt35399_suspend(struct msm_panel_data *panel_data)
-{
-	struct panel_info *panel = container_of(panel_data, struct panel_info,
-						panel_data);
-	struct msm_mddi_client_data *client_data = panel->client_data;
-
-	struct msm_mddi_bridge_platform_data *bridge_data =
-		client_data->private_client_data;
-	int ret;
-
-	ret = bridge_data->uninit(bridge_data, client_data);
-	if (ret) {
-		printk(KERN_INFO "mddi nt35399 client: non zero return from "
-			"uninit\n");
-		return ret;
-	}
-	client_data->suspend(client_data);
-	return 0;
-}
-
-static int nt35399_resume(struct msm_panel_data *panel_data)
-{
-	struct panel_info *panel = container_of(panel_data, struct panel_info,
-						panel_data);
-	struct msm_mddi_client_data *client_data = panel->client_data;
-
-	struct msm_mddi_bridge_platform_data *bridge_data =
-		client_data->private_client_data;
-	int ret;
-
-	client_data->resume(client_data);
-	ret = bridge_data->init(bridge_data, client_data);
-	if (ret)
-		return ret;
-	return 0;
-}
-
-static int nt35399_blank(struct msm_panel_data *panel_data)
-{
-	struct panel_info *panel = container_of(panel_data, struct panel_info,
-						panel_data);
-	struct msm_mddi_client_data *client_data = panel->client_data;
-	struct msm_mddi_bridge_platform_data *bridge_data =
-		client_data->private_client_data;
-
-	return bridge_data->blank(bridge_data, client_data);
-}
-
-static int nt35399_unblank(struct msm_panel_data *panel_data)
-{
-	struct panel_info *panel = container_of(panel_data, struct panel_info,
-						panel_data);
-	struct msm_mddi_client_data *client_data = panel->client_data;
-	struct msm_mddi_bridge_platform_data *bridge_data =
-		client_data->private_client_data;
-
-	return bridge_data->unblank(bridge_data, client_data);
-}
-
-irqreturn_t nt35399_vsync_interrupt(int irq, void *data)
-{
-	struct panel_info *panel = data;
-
-	panel->nt35399_got_int = 1;
-
-	if (panel->fb_callback) {
-		panel->fb_callback->func(panel->fb_callback);
-		panel->fb_callback = NULL;
-	}
-
-	wake_up(&nt35399_vsync_wait);
-
-	return IRQ_HANDLED;
-}
-
-static int setup_vsync(struct panel_info *panel, int init)
-{
-	int ret;
-	int gpio = 97;
-	unsigned int irq;
-
-	if (!init) {
-		ret = 0;
-		goto uninit;
-	}
-	ret = gpio_request(gpio, "vsync");
-	if (ret)
-		goto err_request_gpio_failed;
-
-	ret = gpio_direction_input(gpio);
-	if (ret)
-		goto err_gpio_direction_input_failed;
-
-	ret = irq = gpio_to_irq(gpio);
-	if (ret < 0)
-		goto err_get_irq_num_failed;
-
-	ret = request_irq(irq, nt35399_vsync_interrupt, IRQF_TRIGGER_RISING,
-			  "vsync", panel);
-	if (ret)
-		goto err_request_irq_failed;
-
-	printk(KERN_INFO "vsync on gpio %d now %d\n",
-	       gpio, gpio_get_value(gpio));
-	return 0;
-
-uninit:
-	free_irq(gpio_to_irq(gpio), panel->client_data);
-err_request_irq_failed:
-err_get_irq_num_failed:
-err_gpio_direction_input_failed:
-	gpio_free(gpio);
-err_request_gpio_failed:
-	return ret;
-}
-
-static int mddi_nt35399_probe(struct platform_device *pdev)
-{
-	struct msm_mddi_client_data *client_data = pdev->dev.platform_data;
-	struct msm_mddi_bridge_platform_data *bridge_data =
-		client_data->private_client_data;
-
-	int ret;
-
-	struct panel_info *panel = kzalloc(sizeof(struct panel_info),
-					   GFP_KERNEL);
-
-	printk(KERN_DEBUG "%s: enter.\n", __func__);
-
-	if (!panel)
-		return -ENOMEM;
-	platform_set_drvdata(pdev, panel);
-
-	ret = setup_vsync(panel, 1);
-	if (ret) {
-		dev_err(&pdev->dev, "mddi_nt35399_setup_vsync failed\n");
-		return ret;
-	}
-
-	panel->client_data = client_data;
-	panel->panel_data.suspend = nt35399_suspend;
-	panel->panel_data.resume = nt35399_resume;
-	panel->panel_data.wait_vsync = nt35399_wait_vsync;
-	panel->panel_data.request_vsync = nt35399_request_vsync;
-	panel->panel_data.blank = nt35399_blank;
-	panel->panel_data.unblank = nt35399_unblank;
-	panel->panel_data.fb_data = &bridge_data->fb_data;
-	panel->panel_data.caps = 0;
-
-	panel->pdev.name = "msm_panel";
-	panel->pdev.id = pdev->id;
-	panel->pdev.resource = client_data->fb_resource;
-	panel->pdev.num_resources = 1;
-	panel->pdev.dev.platform_data = &panel->panel_data;
-
-	if (bridge_data->init)
-		bridge_data->init(bridge_data, client_data);
-
-	platform_device_register(&panel->pdev);
-
-	return 0;
-}
-
-static int mddi_nt35399_remove(struct platform_device *pdev)
-{
-	struct panel_info *panel = platform_get_drvdata(pdev);
-
-	setup_vsync(panel, 0);
-	kfree(panel);
-	return 0;
-}
-
-static struct platform_driver mddi_client_0bda_8a47 = {
-	.probe = mddi_nt35399_probe,
-	.remove = mddi_nt35399_remove,
-	.driver = { .name = "mddi_c_0bda_8a47" },
-};
-
-static int __init mddi_client_nt35399_init(void)
-{
-	return platform_driver_register(&mddi_client_0bda_8a47);
-}
-
-module_init(mddi_client_nt35399_init);
-
diff --git a/drivers/video/msm/mddi_client_simple.c b/drivers/video/msm/mddi_client_simple.c
new file mode 100644
index 0000000..1613fca
--- /dev/null
+++ b/drivers/video/msm/mddi_client_simple.c
@@ -0,0 +1,236 @@
+/* drivers/video/msm_fb/mddi_client_simple.c
+ *
+ * Support for simple mddi client devices which require no special
+ * initialization code except for what may be provided in the board file.
+ * If the clients do not provide board specific code, this driver's
+ * panel operations are no-ops.
+ *
+ * Copyright (C) 2007-2010, Google 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/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <mach/msm_fb.h>
+
+struct panel_info {
+	struct platform_device		pdev;
+	struct msm_mddi_client_data	*client_data;
+	struct msm_panel_data		panel_data;
+	struct msmfb_callback		*fb_callback;
+	wait_queue_head_t		vsync_wait;
+	int				got_vsync;
+	int				irq;
+};
+
+#define to_panel_info(pd)    container_of((pd), struct panel_info, panel_data)
+
+static void mddi_simple_request_vsync(struct msm_panel_data *panel_data,
+				      struct msmfb_callback *callback)
+{
+	struct panel_info *panel = to_panel_info(panel_data);
+	struct msm_mddi_client_data *client_data = panel->client_data;
+
+	panel->fb_callback = callback;
+	if (panel->got_vsync) {
+		panel->got_vsync = 0;
+		client_data->activate_link(client_data); /* clears interrupt */
+	}
+}
+
+static void mddi_simple_wait_vsync(struct msm_panel_data *panel_data)
+{
+	struct panel_info *panel = to_panel_info(panel_data);
+	struct msm_mddi_client_data *client_data = panel->client_data;
+	int ret;
+
+	if (panel->got_vsync) {
+		panel->got_vsync = 0;
+		client_data->activate_link(client_data); /* clears interrupt */
+	}
+
+	ret = wait_event_timeout(panel->vsync_wait, panel->got_vsync, HZ/2);
+	if (!ret && !panel->got_vsync)
+		pr_err("mddi_client_simple: timeout waiting for vsync\n");
+
+	panel->got_vsync = 0;
+	/* interrupt clears when screen dma starts */
+}
+
+
+static int mddi_simple_suspend(struct msm_panel_data *panel_data)
+{
+	struct panel_info *panel = to_panel_info(panel_data);
+	struct msm_mddi_client_data *client_data = panel->client_data;
+	struct msm_mddi_bridge_platform_data *bridge_data =
+			client_data->private_client_data;
+	int ret;
+
+	if (!bridge_data->uninit)
+		return 0;
+
+	ret = bridge_data->uninit(bridge_data, client_data);
+	if (ret) {
+		pr_info("%s: non zero return from uninit\n", __func__);
+		return ret;
+	}
+	client_data->suspend(client_data);
+	return 0;
+}
+
+static int mddi_simple_resume(struct msm_panel_data *panel_data)
+{
+	struct panel_info *panel = to_panel_info(panel_data);
+	struct msm_mddi_client_data *client_data = panel->client_data;
+	struct msm_mddi_bridge_platform_data *bridge_data =
+			client_data->private_client_data;
+
+	if (!bridge_data->init)
+		return 0;
+
+	client_data->resume(client_data);
+	return bridge_data->init(bridge_data, client_data);
+}
+
+static int mddi_simple_blank(struct msm_panel_data *panel_data)
+{
+	struct panel_info *panel = to_panel_info(panel_data);
+	struct msm_mddi_client_data *client_data = panel->client_data;
+	struct msm_mddi_bridge_platform_data *bridge_data =
+			client_data->private_client_data;
+
+	if (!bridge_data->blank)
+		return 0;
+	return bridge_data->blank(bridge_data, client_data);
+}
+
+static int mddi_simple_unblank(struct msm_panel_data *panel_data)
+{
+	struct panel_info *panel = to_panel_info(panel_data);
+	struct msm_mddi_client_data *client_data = panel->client_data;
+	struct msm_mddi_bridge_platform_data *bridge_data =
+			client_data->private_client_data;
+
+	if (!bridge_data->unblank)
+		return 0;
+	return bridge_data->unblank(bridge_data, client_data);
+}
+
+static irqreturn_t handle_vsync_irq(int irq, void *data)
+{
+	struct panel_info *panel = data;
+
+	panel->got_vsync = 1;
+	if (panel->fb_callback) {
+		panel->fb_callback->func(panel->fb_callback);
+		panel->fb_callback = NULL;
+	}
+
+	wake_up(&panel->vsync_wait);
+	return IRQ_HANDLED;
+}
+
+static int mddi_simple_probe(struct platform_device *pdev)
+{
+	struct msm_mddi_client_data *client_data = pdev->dev.platform_data;
+	struct msm_mddi_bridge_platform_data *bridge_data =
+			client_data->private_client_data;
+	struct panel_info *panel;
+	int ret;
+
+	pr_debug("%s()\n", __func__);
+
+	panel = kzalloc(sizeof(struct panel_info), GFP_KERNEL);
+	if (!panel)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, panel);
+
+	init_waitqueue_head(&panel->vsync_wait);
+
+	panel->irq = platform_get_irq_byname(pdev, "vsync");
+	if (panel->irq >= 0) {
+		ret = request_irq(panel->irq, handle_vsync_irq,
+				  IRQF_TRIGGER_RISING, "mddi_c_simple_vsync",
+				  panel);
+		if (ret) {
+			pr_err("%s: request vsync irq %d failed (%d)\n",
+			       __func__, panel->irq, ret);
+			goto err_req_irq;
+		}
+
+		panel->panel_data.wait_vsync = mddi_simple_wait_vsync;
+		panel->panel_data.request_vsync = mddi_simple_request_vsync;
+	}
+
+	panel->client_data = client_data;
+	panel->panel_data.suspend = mddi_simple_suspend;
+	panel->panel_data.resume = mddi_simple_resume;
+	panel->panel_data.blank = mddi_simple_blank;
+	panel->panel_data.unblank = mddi_simple_unblank;
+	panel->panel_data.caps = bridge_data->panel_caps;
+	panel->panel_data.fb_data = &bridge_data->fb_data;
+
+	panel->pdev.name = "msm_panel";
+	panel->pdev.id = pdev->id;
+	platform_device_add_resources(&panel->pdev,
+				      client_data->fb_resource, 1);
+	panel->pdev.dev.platform_data = &panel->panel_data;
+
+	if (bridge_data->init)
+		bridge_data->init(bridge_data, client_data);
+
+	ret = platform_device_register(&panel->pdev);
+	if (ret) {
+		pr_err("%s: Can't register platform device\n", __func__);
+		goto err_plat_dev_reg;
+	}
+
+	return 0;
+
+err_plat_dev_reg:
+	if (panel->irq >= 0)
+		free_irq(panel->irq, panel);
+err_req_irq:
+	platform_set_drvdata(pdev, NULL);
+	kfree(panel);
+	return ret;
+}
+
+static int mddi_simple_remove(struct platform_device *pdev)
+{
+	struct panel_info *panel = platform_get_drvdata(pdev);
+	kfree(panel);
+	return 0;
+}
+
+static struct platform_driver mddi_client_simple = {
+	.probe	= mddi_simple_probe,
+	.remove	= mddi_simple_remove,
+	.driver	= {
+		.owner	= THIS_MODULE,
+		.name	= "mddi_c_simple"
+	},
+};
+
+static int __init mddi_client_simple_init(void)
+{
+	platform_driver_register(&mddi_client_simple);
+	return 0;
+}
+
+module_init(mddi_client_simple_init);
diff --git a/drivers/video/msm/mddi_client_toshiba.c b/drivers/video/msm/mddi_client_toshiba.c
index f9bc932..21e0ac7 100644
--- a/drivers/video/msm/mddi_client_toshiba.c
+++ b/drivers/video/msm/mddi_client_toshiba.c
@@ -60,6 +60,7 @@
 	struct msm_panel_data panel_data;
 	struct msmfb_callback *toshiba_callback;
 	int toshiba_got_int;
+	int irq;
 };
 
 
@@ -175,47 +176,6 @@
 	return IRQ_HANDLED;
 }
 
-static int setup_vsync(struct panel_info *panel,
-		       int init)
-{
-	int ret;
-	int gpio = 97;
-	unsigned int irq;
-
-	if (!init) {
-		ret = 0;
-		goto uninit;
-	}
-	ret = gpio_request(gpio, "vsync");
-	if (ret)
-		goto err_request_gpio_failed;
-
-	ret = gpio_direction_input(gpio);
-	if (ret)
-		goto err_gpio_direction_input_failed;
-
-	ret = irq = gpio_to_irq(gpio);
-	if (ret < 0)
-		goto err_get_irq_num_failed;
-
-	ret = request_irq(irq, toshiba_vsync_interrupt, IRQF_TRIGGER_RISING,
-			  "vsync", panel);
-	if (ret)
-		goto err_request_irq_failed;
-	printk(KERN_INFO "vsync on gpio %d now %d\n",
-	       gpio, gpio_get_value(gpio));
-	return 0;
-
-uninit:
-	free_irq(gpio_to_irq(gpio), panel);
-err_request_irq_failed:
-err_get_irq_num_failed:
-err_gpio_direction_input_failed:
-	gpio_free(gpio);
-err_request_gpio_failed:
-	return ret;
-}
-
 static int mddi_toshiba_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -232,10 +192,16 @@
 	client_data->remote_write(client_data, GPIOSEL_VWAKEINT, GPIOSEL);
 	client_data->remote_write(client_data, INTMASK_VWAKEOUT, INTMASK);
 
-	ret = setup_vsync(panel, 1);
+	ret = platform_get_irq_byname(pdev, "vsync");
+	if (ret < 0)
+		goto err_plat_get_irq;
+
+	panel->irq = ret;
+	ret = request_irq(panel->irq, toshiba_vsync_interrupt,
+			  IRQF_TRIGGER_RISING, "vsync", panel);
 	if (ret) {
 		dev_err(&pdev->dev, "mddi_bridge_setup_vsync failed\n");
-		return ret;
+		goto err_req_irq;
 	}
 
 	panel->client_data = client_data;
@@ -258,13 +224,19 @@
 	platform_device_register(&panel->pdev);
 
 	return 0;
+
+err_req_irq:
+err_plat_get_irq:
+	kfree(panel);
+	return ret;
 }
 
 static int mddi_toshiba_remove(struct platform_device *pdev)
 {
 	struct panel_info *panel = platform_get_drvdata(pdev);
 
-	setup_vsync(panel, 0);
+	platform_set_drvdata(pdev, NULL);
+	free_irq(panel->irq, panel);
 	kfree(panel);
 	return 0;
 }
diff --git a/drivers/video/msm/mddi_hw.h b/drivers/video/msm/mddi_hw.h
index 45cc01f..47bb449 100644
--- a/drivers/video/msm/mddi_hw.h
+++ b/drivers/video/msm/mddi_hw.h
@@ -53,6 +53,9 @@
 #define MDDI_MF_CNT             0x0084
 #define MDDI_CURR_REV_PTR       0x0088
 #define MDDI_CORE_VER           0x008c
+#define MDDI_FIFO_ALLOC         0x0090
+#define MDDI_PAD_IO_CTL         0x00a0
+#define MDDI_PAD_CAL            0x00a4
 
 #define MDDI_INT_PRI_PTR_READ       0x0001
 #define MDDI_INT_SEC_PTR_READ       0x0002
@@ -125,8 +128,14 @@
 /* MDP sends 256 pixel packets, so lower value hibernates more without
  * significantly increasing latency of waiting for next subframe */
 #define MDDI_HOST_BYTES_PER_SUBFRAME  0x3C00
+
+#if defined(CONFIG_MSM_MDP31) || defined(CONFIG_MSM_MDP40)
+#define MDDI_HOST_TA2_LEN       0x001a
+#define MDDI_HOST_REV_RATE_DIV  0x0004
+#else
 #define MDDI_HOST_TA2_LEN       0x000c
 #define MDDI_HOST_REV_RATE_DIV  0x0002
+#endif
 
 
 struct __attribute__((packed)) mddi_rev_packet {
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 19c01c6..9f32396a 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -22,6 +22,7 @@
 #include <linux/wait.h>
 #include <linux/clk.h>
 #include <linux/file.h>
+#include <linux/android_pmem.h>
 #include <linux/major.h>
 #include <linux/slab.h>
 
@@ -30,50 +31,52 @@
 #include <linux/platform_device.h>
 
 #include "mdp_hw.h"
+#include "mdp_ppp.h"
 
 struct class *mdp_class;
 
 #define MDP_CMD_DEBUG_ACCESS_BASE (0x10000)
 
-static uint16_t mdp_default_ccs[] = {
-	0x254, 0x000, 0x331, 0x254, 0xF38, 0xE61, 0x254, 0x409, 0x000,
-	0x010, 0x080, 0x080
-};
-
-static DECLARE_WAIT_QUEUE_HEAD(mdp_dma2_waitqueue);
-static DECLARE_WAIT_QUEUE_HEAD(mdp_ppp_waitqueue);
-static struct msmfb_callback *dma_callback;
-static struct clk *clk;
 static unsigned int mdp_irq_mask;
-static DEFINE_SPINLOCK(mdp_lock);
-DEFINE_MUTEX(mdp_mutex);
+static struct mdp_info *the_mdp;
 
-static int enable_mdp_irq(struct mdp_info *mdp, uint32_t mask)
+static int locked_enable_mdp_irq(struct mdp_info *mdp, uint32_t mask)
 {
-	unsigned long irq_flags;
-	int ret = 0;
-
 	BUG_ON(!mask);
 
-	spin_lock_irqsave(&mdp_lock, irq_flags);
 	/* if the mask bits are already set return an error, this interrupt
 	 * is already enabled */
 	if (mdp_irq_mask & mask) {
-		printk(KERN_ERR "mdp irq already on already on %x %x\n",
-		       mdp_irq_mask, mask);
-		ret = -1;
+		pr_err("mdp irq already on %x %x\n", mdp_irq_mask, mask);
+		return -1;
 	}
 	/* if the mdp irq is not already enabled enable it */
 	if (!mdp_irq_mask) {
-		if (clk)
-			clk_enable(clk);
+		clk_set_rate(mdp->ebi1_clk, 128000000);
+		clk_enable(mdp->clk);
+		if (mdp->pclk)
+			clk_enable(mdp->pclk);
 		enable_irq(mdp->irq);
 	}
 
+	/* clear out any previous irqs for the requested mask*/
+	mdp_writel(mdp, mask, MDP_INTR_CLEAR);
+
 	/* update the irq mask to reflect the fact that the interrupt is
 	 * enabled */
 	mdp_irq_mask |= mask;
-	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+	mdp_writel(mdp, mdp_irq_mask, MDP_INTR_ENABLE);
+	return 0;
+}
+
+static int enable_mdp_irq(struct mdp_info *mdp, uint32_t mask)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&mdp->lock, flags);
+	ret = locked_enable_mdp_irq(mdp, mask);
+	spin_unlock_irqrestore(&mdp->lock, flags);
 	return ret;
 }
 
@@ -88,23 +91,28 @@
 	/* update the irq mask to reflect the fact that the interrupt is
 	 * disabled */
 	mdp_irq_mask &= ~(mask);
+	mdp_writel(mdp, mdp_irq_mask, MDP_INTR_ENABLE);
+
 	/* if no one is waiting on the interrupt, disable it */
 	if (!mdp_irq_mask) {
-		disable_irq(mdp->irq);
-		if (clk)
-			clk_disable(clk);
+		disable_irq_nosync(mdp->irq);
+		if (mdp->pclk)
+			clk_disable(mdp->pclk);
+		if (mdp->clk)
+			clk_disable(mdp->clk);
+		clk_set_rate(mdp->ebi1_clk, 0);
 	}
 	return 0;
 }
 
-static int disable_mdp_irq(struct mdp_info *mdp, uint32_t mask)
+int disable_mdp_irq(struct mdp_info *mdp, uint32_t mask)
 {
 	unsigned long irq_flags;
 	int ret;
 
-	spin_lock_irqsave(&mdp_lock, irq_flags);
+	spin_lock_irqsave(&mdp->lock, irq_flags);
 	ret = locked_disable_mdp_irq(mdp, mask);
-	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+	spin_unlock_irqrestore(&mdp->lock, irq_flags);
 	return ret;
 }
 
@@ -113,68 +121,109 @@
 	uint32_t status;
 	unsigned long irq_flags;
 	struct mdp_info *mdp = data;
+	int i;
 
-	spin_lock_irqsave(&mdp_lock, irq_flags);
+	spin_lock_irqsave(&mdp->lock, irq_flags);
 
 	status = mdp_readl(mdp, MDP_INTR_STATUS);
 	mdp_writel(mdp, status, MDP_INTR_CLEAR);
 
+//	pr_info("%s: status=%08x (irq_mask=%08x)\n", __func__, status,
+//		mdp_irq_mask);
 	status &= mdp_irq_mask;
-	if (status & DL0_DMA2_TERM_DONE) {
-		if (dma_callback) {
-			dma_callback->func(dma_callback);
-			dma_callback = NULL;
+
+	for (i = 0; i < MSM_MDP_NUM_INTERFACES; ++i) {
+		struct mdp_out_interface *out_if = &mdp->out_if[i];
+		if (status & out_if->dma_mask) {
+			if (out_if->dma_cb) {
+				out_if->dma_cb->func(out_if->dma_cb);
+				out_if->dma_cb = NULL;
+			}
+			wake_up(&out_if->dma_waitqueue);
 		}
-		wake_up(&mdp_dma2_waitqueue);
+		if (status & out_if->irq_mask) {
+			out_if->irq_cb->func(out_if->irq_cb);
+			out_if->irq_cb = NULL;
+		}
 	}
 
-	if (status & DL0_ROI_DONE)
-		wake_up(&mdp_ppp_waitqueue);
+	mdp_ppp_handle_isr(mdp, status);
 
 	if (status)
 		locked_disable_mdp_irq(mdp, status);
 
-	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+	spin_unlock_irqrestore(&mdp->lock, irq_flags);
 	return IRQ_HANDLED;
 }
 
-static uint32_t mdp_check_mask(uint32_t mask)
+static uint32_t mdp_check_mask(struct mdp_info *mdp, uint32_t mask)
 {
 	uint32_t ret;
 	unsigned long irq_flags;
 
-	spin_lock_irqsave(&mdp_lock, irq_flags);
+	spin_lock_irqsave(&mdp->lock, irq_flags);
 	ret = mdp_irq_mask & mask;
-	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+	spin_unlock_irqrestore(&mdp->lock, irq_flags);
 	return ret;
 }
 
-static int mdp_wait(struct mdp_info *mdp, uint32_t mask, wait_queue_head_t *wq)
+int mdp_wait(struct mdp_info *mdp, uint32_t mask, wait_queue_head_t *wq)
 {
 	int ret = 0;
 	unsigned long irq_flags;
 
-	wait_event_timeout(*wq, !mdp_check_mask(mask), HZ);
+//	pr_info("%s: WAITING for 0x%x\n", __func__, mask);
+	wait_event_timeout(*wq, !mdp_check_mask(mdp, mask),
+			   msecs_to_jiffies(1000));
 
-	spin_lock_irqsave(&mdp_lock, irq_flags);
+	spin_lock_irqsave(&mdp->lock, irq_flags);
 	if (mdp_irq_mask & mask) {
+		pr_warning("%s: timeout waiting for mdp to complete 0x%x\n",
+			   __func__, mask);
+		pr_info("GLBL_CLK_ENA: %08X\n",
+			readl(MSM_CLK_CTL_BASE + 0x0000));
+		pr_info("GLBL_CLK_STATE: %08X\n",
+			readl(MSM_CLK_CTL_BASE + 0x0004));
+		pr_info("GLBL_SLEEP_EN: %08X\n",
+			readl(MSM_CLK_CTL_BASE + 0x001C));
+		pr_info("GLBL_CLK_ENA_2: %08X\n",
+			readl(MSM_CLK_CTL_BASE + 0x0220));
+		pr_info("GLBL_CLK_STATE_2: %08X\n",
+			readl(MSM_CLK_CTL_BASE + 0x0224));
+		pr_info("GLBL_CLK_SLEEP_EN_2: %08X\n",
+			readl(MSM_CLK_CTL_BASE + 0x023C));
 		locked_disable_mdp_irq(mdp, mask);
-		printk(KERN_WARNING "timeout waiting for mdp to complete %x\n",
-		       mask);
 		ret = -ETIMEDOUT;
+	} else {
+//		pr_info("%s: SUCCESS waiting for 0x%x\n", __func__, mask);
 	}
-	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+	spin_unlock_irqrestore(&mdp->lock, irq_flags);
 
 	return ret;
 }
 
-void mdp_dma_wait(struct mdp_device *mdp_dev)
+static void mdp_dma_wait(struct mdp_device *mdp_dev, int interface)
 {
 #define MDP_MAX_TIMEOUTS 20
 	static int timeout_count;
 	struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev);
+	unsigned int mask = 0;
+	wait_queue_head_t *wq;
 
-	if (mdp_wait(mdp, DL0_DMA2_TERM_DONE, &mdp_dma2_waitqueue) == -ETIMEDOUT)
+	switch (interface) {
+	case MSM_MDDI_PMDH_INTERFACE:
+	case MSM_MDDI_EMDH_INTERFACE:
+	case MSM_LCDC_INTERFACE:
+		BUG_ON(!mdp->out_if[interface].registered);
+		mask = mdp->out_if[interface].dma_mask;
+		wq = &mdp->out_if[interface].dma_waitqueue;
+		break;
+	default:
+		pr_err("%s: Unknown interface %d\n", __func__, interface);
+		BUG();
+	}
+
+	if (mdp_wait(mdp, mask, wq) == -ETIMEDOUT)
 		timeout_count++;
 	else
 		timeout_count = 0;
@@ -186,180 +235,106 @@
 	}
 }
 
-static int mdp_ppp_wait(struct mdp_info *mdp)
-{
-	return mdp_wait(mdp, DL0_ROI_DONE, &mdp_ppp_waitqueue);
-}
-
-void mdp_dma_to_mddi(struct mdp_info *mdp, uint32_t addr, uint32_t stride,
-		     uint32_t width, uint32_t height, uint32_t x, uint32_t y,
-		     struct msmfb_callback *callback)
-{
-	uint32_t dma2_cfg;
-	uint16_t ld_param = 0; /* 0=PRIM, 1=SECD, 2=EXT */
-
-	if (enable_mdp_irq(mdp, DL0_DMA2_TERM_DONE)) {
-		printk(KERN_ERR "mdp_dma_to_mddi: busy\n");
-		return;
-	}
-
-	dma_callback = callback;
-
-	dma2_cfg = DMA_PACK_TIGHT |
-		DMA_PACK_ALIGN_LSB |
-		DMA_PACK_PATTERN_RGB |
-		DMA_OUT_SEL_AHB |
-		DMA_IBUF_NONCONTIGUOUS;
-
-	dma2_cfg |= DMA_IBUF_FORMAT_RGB565;
-
-	dma2_cfg |= DMA_OUT_SEL_MDDI;
-
-	dma2_cfg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY;
-
-	dma2_cfg |= DMA_DITHER_EN;
-
-	/* setup size, address, and stride */
-	mdp_writel(mdp, (height << 16) | (width),
-		   MDP_CMD_DEBUG_ACCESS_BASE + 0x0184);
-	mdp_writel(mdp, addr, MDP_CMD_DEBUG_ACCESS_BASE + 0x0188);
-	mdp_writel(mdp, stride, MDP_CMD_DEBUG_ACCESS_BASE + 0x018C);
-
-	/* 666 18BPP */
-	dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
-
-	/* set y & x offset and MDDI transaction parameters */
-	mdp_writel(mdp, (y << 16) | (x), MDP_CMD_DEBUG_ACCESS_BASE + 0x0194);
-	mdp_writel(mdp, ld_param, MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0);
-	mdp_writel(mdp, (MDDI_VDO_PACKET_DESC << 16) | MDDI_VDO_PACKET_PRIM,
-		   MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4);
-
-	mdp_writel(mdp, dma2_cfg, MDP_CMD_DEBUG_ACCESS_BASE + 0x0180);
-
-	/* start DMA2 */
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0044);
-}
-
-void mdp_dma(struct mdp_device *mdp_dev, uint32_t addr, uint32_t stride,
+static void mdp_dma(struct mdp_device *mdp_dev, uint32_t addr, uint32_t stride,
 	     uint32_t width, uint32_t height, uint32_t x, uint32_t y,
 	     struct msmfb_callback *callback, int interface)
 {
 	struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev);
+	struct mdp_out_interface *out_if;
+	unsigned long flags;
 
-	if (interface == MSM_MDDI_PMDH_INTERFACE) {
-		mdp_dma_to_mddi(mdp, addr, stride, width, height, x, y,
-				callback);
+	if (interface < 0 || interface > MSM_MDP_NUM_INTERFACES ||
+	    !mdp->out_if[interface].registered) {
+		pr_err("%s: Unknown interface: %d\n", __func__, interface);
+		BUG();
 	}
+	out_if = &mdp->out_if[interface];
+
+	spin_lock_irqsave(&mdp->lock, flags);
+	if (locked_enable_mdp_irq(mdp, out_if->dma_mask)) {
+		pr_err("%s: busy\n", __func__);
+		goto done;
+	}
+
+	out_if->dma_cb = callback;
+	out_if->dma_start(out_if->priv, addr, stride, width, height, x, y);
+done:
+	spin_unlock_irqrestore(&mdp->lock, flags);
 }
 
-int get_img(struct mdp_img *img, struct fb_info *info,
-	    unsigned long *start, unsigned long *len,
-	    struct file **filep)
+void mdp_configure_dma_format(struct mdp_device *mdp_dev)
 {
-	int put_needed, ret = 0;
-	struct file *file;
-	unsigned long vstart;
+	struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev);
+	uint32_t dma_cfg;
 
-	file = fget_light(img->memory_id, &put_needed);
-	if (file == NULL)
-		return -1;
+	if (!mdp->dma_format_dirty)
+		return;
+	dma_cfg = mdp_readl(mdp, MDP_DMA_P_CONFIG);
+	dma_cfg &= ~DMA_IBUF_FORMAT_MASK;
+	dma_cfg &= ~DMA_PACK_PATTERN_MASK;
+	dma_cfg |= (mdp->dma_format | mdp->dma_pack_pattern);
+	mdp_writel(mdp, dma_cfg, MDP_DMA_P_CONFIG);
+	mdp->dma_format_dirty = false;
 
-	if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
-		*start = info->fix.smem_start;
-		*len = info->fix.smem_len;
-	} else
-		ret = -1;
-	fput_light(file, put_needed);
-
-	return ret;
+	return;
 }
 
-void put_img(struct file *src_file, struct file *dst_file)
+int mdp_check_output_format(struct mdp_device *mdp_dev, int bpp)
 {
+	switch (bpp) {
+	case 16:
+	case 24:
+	case 32:
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int mdp_set_output_format(struct mdp_device *mdp_dev, int bpp)
+{
+	struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev);
+	uint32_t format, pack_pattern;
+
+	switch (bpp) {
+	case 16:
+		format = DMA_IBUF_FORMAT_RGB565;
+		pack_pattern = DMA_PACK_PATTERN_RGB;
+		break;
+#ifdef CONFIG_MSM_MDP22
+	case 24:
+	case 32:
+		format = DMA_IBUF_FORMAT_RGB888_OR_ARGB8888;
+		break;
+#else
+	case 24:
+		format = DMA_IBUF_FORMAT_RGB888;
+		pack_pattern = DMA_PACK_PATTERN_BGR;
+		break;
+	case 32:
+		format = DMA_IBUF_FORMAT_XRGB8888;
+		pack_pattern = DMA_PACK_PATTERN_BGR;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+	if (format != mdp->dma_format ||
+	    pack_pattern != mdp->dma_pack_pattern) {
+		mdp->dma_format = format;
+		mdp->dma_pack_pattern = pack_pattern;
+		mdp->dma_format_dirty = true;
+	}
+
+	return 0;
 }
 
 int mdp_blit(struct mdp_device *mdp_dev, struct fb_info *fb,
 	     struct mdp_blit_req *req)
 {
-	int ret;
-	unsigned long src_start = 0, src_len = 0, dst_start = 0, dst_len = 0;
 	struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev);
-	struct file *src_file = 0, *dst_file = 0;
-
-	/* WORKAROUND FOR HARDWARE BUG IN BG TILE FETCH */
-	if (unlikely(req->src_rect.h == 0 ||
-		     req->src_rect.w == 0)) {
-		printk(KERN_ERR "mpd_ppp: src img of zero size!\n");
-		return -EINVAL;
-	}
-	if (unlikely(req->dst_rect.h == 0 ||
-		     req->dst_rect.w == 0))
-		return -EINVAL;
-
-	/* do this first so that if this fails, the caller can always
-	 * safely call put_img */
-	if (unlikely(get_img(&req->src, fb, &src_start, &src_len, &src_file))) {
-		printk(KERN_ERR "mpd_ppp: could not retrieve src image from "
-				"memory\n");
-		return -EINVAL;
-	}
-
-	if (unlikely(get_img(&req->dst, fb, &dst_start, &dst_len, &dst_file))) {
-		printk(KERN_ERR "mpd_ppp: could not retrieve dst image from "
-				"memory\n");
-		return -EINVAL;
-	}
-	mutex_lock(&mdp_mutex);
-
-	/* transp_masking unimplemented */
-	req->transp_mask = MDP_TRANSP_NOP;
-	if (unlikely((req->transp_mask != MDP_TRANSP_NOP ||
-		      req->alpha != MDP_ALPHA_NOP ||
-		      HAS_ALPHA(req->src.format)) &&
-		     (req->flags & MDP_ROT_90 &&
-		      req->dst_rect.w <= 16 && req->dst_rect.h >= 16))) {
-		int i;
-		unsigned int tiles = req->dst_rect.h / 16;
-		unsigned int remainder = req->dst_rect.h % 16;
-		req->src_rect.w = 16*req->src_rect.w / req->dst_rect.h;
-		req->dst_rect.h = 16;
-		for (i = 0; i < tiles; i++) {
-			enable_mdp_irq(mdp, DL0_ROI_DONE);
-			ret = mdp_ppp_blit(mdp, req, src_file, src_start,
-					   src_len, dst_file, dst_start,
-					   dst_len);
-			if (ret)
-				goto err_bad_blit;
-			ret = mdp_ppp_wait(mdp);
-			if (ret)
-				goto err_wait_failed;
-			req->dst_rect.y += 16;
-			req->src_rect.x += req->src_rect.w;
-		}
-		if (!remainder)
-			goto end;
-		req->src_rect.w = remainder*req->src_rect.w / req->dst_rect.h;
-		req->dst_rect.h = remainder;
-	}
-	enable_mdp_irq(mdp, DL0_ROI_DONE);
-	ret = mdp_ppp_blit(mdp, req, src_file, src_start, src_len, dst_file,
-			   dst_start,
-			   dst_len);
-	if (ret)
-		goto err_bad_blit;
-	ret = mdp_ppp_wait(mdp);
-	if (ret)
-		goto err_wait_failed;
-end:
-	put_img(src_file, dst_file);
-	mutex_unlock(&mdp_mutex);
-	return 0;
-err_bad_blit:
-	disable_mdp_irq(mdp, DL0_ROI_DONE);
-err_wait_failed:
-	put_img(src_file, dst_file);
-	mutex_unlock(&mdp_mutex);
-	return ret;
+	return mdp_ppp_blit(mdp, fb, req);
 }
 
 void mdp_set_grp_disp(struct mdp_device *mdp_dev, unsigned disp_id)
@@ -370,6 +345,78 @@
 	mdp_writel(mdp, disp_id, MDP_FULL_BYPASS_WORD43);
 }
 
+/* used by output interface drivers like mddi and lcdc */
+int mdp_out_if_register(struct mdp_device *mdp_dev, int interface,
+			void *private_data, uint32_t dma_mask,
+			mdp_dma_start_func_t dma_start)
+{
+	struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev);
+	unsigned long flags;
+	int ret = 0;
+
+	if (interface < 0 || interface >= MSM_MDP_NUM_INTERFACES) {
+		pr_err("%s: invalid interface (%d)\n", __func__, interface);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&mdp->lock, flags);
+
+	if (mdp->out_if[interface].registered) {
+		pr_err("%s: interface (%d) already registered\n", __func__,
+		       interface);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	init_waitqueue_head(&mdp->out_if[interface].dma_waitqueue);
+	mdp->out_if[interface].registered = 1;
+	mdp->out_if[interface].priv = private_data;
+	mdp->out_if[interface].dma_mask = dma_mask;
+	mdp->out_if[interface].dma_start = dma_start;
+	mdp->out_if[interface].dma_cb = NULL;
+
+done:
+	spin_unlock_irqrestore(&mdp->lock, flags);
+	return ret;
+}
+
+int mdp_out_if_req_irq(struct mdp_device *mdp_dev, int interface,
+		       uint32_t mask, struct msmfb_callback *cb)
+{
+	struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev);
+	unsigned long flags;
+	int ret = 0;
+
+	if (interface < 0 || interface >= MSM_MDP_NUM_INTERFACES) {
+		pr_err("%s: invalid interface (%d)\n", __func__, interface);
+		BUG();
+	} else if (!mdp->out_if[interface].registered) {
+		pr_err("%s: interface (%d) not registered\n", __func__,
+		       interface);
+		BUG();
+	}
+
+	spin_lock_irqsave(&mdp->lock, flags);
+
+	if (mask) {
+		ret = locked_enable_mdp_irq(mdp, mask);
+		if (ret) {
+			pr_err("%s: busy\n", __func__);
+			goto done;
+		}
+		mdp->out_if[interface].irq_mask = mask;
+		mdp->out_if[interface].irq_cb = cb;
+	} else {
+		locked_disable_mdp_irq(mdp, mask);
+		mdp->out_if[interface].irq_mask = 0;
+		mdp->out_if[interface].irq_cb = NULL;
+	}
+
+done:
+	spin_unlock_irqrestore(&mdp->lock, flags);
+	return ret;
+}
+
 int register_mdp_client(struct class_interface *cint)
 {
 	if (!mdp_class) {
@@ -380,14 +427,10 @@
 	return class_interface_register(cint);
 }
 
-#include "mdp_csc_table.h"
-#include "mdp_scale_tables.h"
-
 int mdp_probe(struct platform_device *pdev)
 {
 	struct resource *resource;
 	int ret;
-	int n;
 	struct mdp_info *mdp;
 
 	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -400,6 +443,8 @@
 	if (!mdp)
 		return -ENOMEM;
 
+	spin_lock_init(&mdp->lock);
+
 	mdp->irq = platform_get_irq(pdev, 0);
 	if (mdp->irq < 0) {
 		pr_err("mdp: can not get mdp irq\n");
@@ -419,70 +464,45 @@
 	mdp->mdp_dev.dma_wait = mdp_dma_wait;
 	mdp->mdp_dev.blit = mdp_blit;
 	mdp->mdp_dev.set_grp_disp = mdp_set_grp_disp;
+	mdp->mdp_dev.set_output_format = mdp_set_output_format;
+	mdp->mdp_dev.check_output_format = mdp_check_output_format;
 
-	clk = clk_get(&pdev->dev, "mdp_clk");
-	if (IS_ERR(clk)) {
+	mdp->enable_irq = enable_mdp_irq;
+	mdp->disable_irq = disable_mdp_irq;
+
+	mdp->clk = clk_get(&pdev->dev, "mdp_clk");
+	if (IS_ERR(mdp->clk)) {
 		printk(KERN_INFO "mdp: failed to get mdp clk");
-		return PTR_ERR(clk);
+		ret = PTR_ERR(mdp->clk);
+		goto error_get_mdp_clk;
 	}
 
+	mdp->pclk = clk_get(&pdev->dev, "mdp_pclk");
+	if (IS_ERR(mdp->pclk))
+		mdp->pclk = NULL;
+
+	mdp->ebi1_clk = clk_get(NULL, "ebi1_clk");
+	if (IS_ERR(mdp->ebi1_clk)) {
+		pr_err("mdp: failed to get ebi1 clk\n");
+		ret = PTR_ERR(mdp->ebi1_clk);
+		goto error_get_ebi1_clk;
+	}
+
+
 	ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp);
 	if (ret)
 		goto error_request_irq;
 	disable_irq(mdp->irq);
-	mdp_irq_mask = 0;
 
-	/* debug interface write access */
-	mdp_writel(mdp, 1, 0x60);
-
-	mdp_writel(mdp, MDP_ANY_INTR_MASK, MDP_INTR_ENABLE);
-	mdp_writel(mdp, 1, MDP_EBI2_PORTMAP_MODE);
-
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc);
-
-	for (n = 0; n < ARRAY_SIZE(csc_table); n++)
-		mdp_writel(mdp, csc_table[n].val, csc_table[n].reg);
-
-	/* clear up unused fg/main registers */
-	/* comp.plane 2&3 ystride */
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0120);
-
-	/* unpacked pattern */
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x012c);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0130);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0134);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0158);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x015c);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0160);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0170);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0174);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x017c);
-
-	/* comp.plane 2 & 3 */
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0114);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0118);
-
-	/* clear unused bg registers */
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0);
-	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4);
-
-	for (n = 0; n < ARRAY_SIZE(mdp_upscale_table); n++)
-		mdp_writel(mdp, mdp_upscale_table[n].val,
-		       mdp_upscale_table[n].reg);
-
-	for (n = 0; n < 9; n++)
-		mdp_writel(mdp, mdp_default_ccs[n], 0x40440 + 4 * n);
-	mdp_writel(mdp, mdp_default_ccs[9], 0x40500 + 4 * 0);
-	mdp_writel(mdp, mdp_default_ccs[10], 0x40500 + 4 * 0);
-	mdp_writel(mdp, mdp_default_ccs[11], 0x40500 + 4 * 0);
+	clk_enable(mdp->clk);
+	if (mdp->pclk)
+		clk_enable(mdp->pclk);
+	mdp_hw_init(mdp);
 
 	/* register mdp device */
 	mdp->mdp_dev.dev.parent = &pdev->dev;
 	mdp->mdp_dev.dev.class = mdp_class;
+	dev_set_name(&mdp->mdp_dev.dev, "mdp%d", pdev->id);
 
 	/* if you can remove the platform device you'd have to implement
 	 * this:
@@ -491,14 +511,28 @@
 	ret = device_register(&mdp->mdp_dev.dev);
 	if (ret)
 		goto error_device_register;
+
+	the_mdp = mdp;
+
+	pr_info("%s: initialized\n", __func__);
+
 	return 0;
 
 error_device_register:
+	if (mdp->pclk)
+		clk_disable(mdp->pclk);
+	clk_disable(mdp->clk);
 	free_irq(mdp->irq, mdp);
 error_request_irq:
+	clk_put(mdp->ebi1_clk);
+error_get_ebi1_clk:
+	if (mdp->pclk)
+		clk_put(mdp->pclk);
+	clk_put(mdp->clk);
+error_get_mdp_clk:
 	iounmap(mdp->base);
-error_get_irq:
 error_ioremap:
+error_get_irq:
 	kfree(mdp);
 	return ret;
 }
@@ -508,6 +542,17 @@
 	.driver = {.name = "msm_mdp"},
 };
 
+static int __init mdp_lateinit(void)
+{
+	struct mdp_info *mdp = the_mdp;
+	if (the_mdp) {
+		if (mdp->pclk)
+			clk_disable(mdp->pclk);
+		clk_disable(mdp->clk);
+	}
+	return 0;
+}
+
 static int __init mdp_init(void)
 {
 	mdp_class = class_create(THIS_MODULE, "msm_mdp");
@@ -519,3 +564,4 @@
 }
 
 subsys_initcall(mdp_init);
+late_initcall(mdp_lateinit);
diff --git a/drivers/video/msm/mdp_csc_table.h b/drivers/video/msm/mdp_csc_table.h
index d1cde30..a0f72c0 100644
--- a/drivers/video/msm/mdp_csc_table.h
+++ b/drivers/video/msm/mdp_csc_table.h
@@ -1,4 +1,4 @@
-/* drivers/video/msm_fb/mdp_csc_table.h
+/* drivers/video/msm/mdp_csc_table.h
  *
  * Copyright (C) 2007 QUALCOMM Incorporated
  * Copyright (C) 2007 Google Incorporated
@@ -16,57 +16,116 @@
 static struct {
 	uint32_t reg;
 	uint32_t val;
-} csc_table[] = {
-	{ 0x40400, 0x83 },
-	{ 0x40404, 0x102 },
-	{ 0x40408, 0x32 },
-	{ 0x4040c, 0xffffffb5 },
-	{ 0x40410, 0xffffff6c },
-	{ 0x40414, 0xe1 },
-	{ 0x40418, 0xe1 },
-	{ 0x4041c, 0xffffff45 },
-	{ 0x40420, 0xffffffdc },
-	{ 0x40440, 0x254 },
-	{ 0x40444, 0x0 },
-	{ 0x40448, 0x331 },
-	{ 0x4044c, 0x254 },
-	{ 0x40450, 0xffffff38 },
-	{ 0x40454, 0xfffffe61 },
-	{ 0x40458, 0x254 },
-	{ 0x4045c, 0x409 },
-	{ 0x40460, 0x0 },
-	{ 0x40480, 0x5d },
-	{ 0x40484, 0x13a },
-	{ 0x40488, 0x20 },
-	{ 0x4048c, 0xffffffcd },
-	{ 0x40490, 0xffffff54 },
-	{ 0x40494, 0xe1 },
-	{ 0x40498, 0xe1 },
-	{ 0x4049c, 0xffffff35 },
-	{ 0x404a0, 0xffffffec },
-	{ 0x404c0, 0x254 },
-	{ 0x404c4, 0x0 },
-	{ 0x404c8, 0x396 },
-	{ 0x404cc, 0x254 },
-	{ 0x404d0, 0xffffff94 },
-	{ 0x404d4, 0xfffffef0 },
-	{ 0x404d8, 0x254 },
-	{ 0x404dc, 0x43a },
-	{ 0x404e0, 0x0 },
-	{ 0x40500, 0x10 },
-	{ 0x40504, 0x80 },
-	{ 0x40508, 0x80 },
-	{ 0x40540, 0x10 },
-	{ 0x40544, 0x80 },
-	{ 0x40548, 0x80 },
-	{ 0x40580, 0x10 },
-	{ 0x40584, 0xeb },
-	{ 0x40588, 0x10 },
-	{ 0x4058c, 0xf0 },
-	{ 0x405c0, 0x10 },
-	{ 0x405c4, 0xeb },
-	{ 0x405c8, 0x10 },
-	{ 0x405cc, 0xf0 },
+} csc_matrix_config_table[] = {
+	/* RGB -> YUV primary forward matrix (set1). */
+	{ MDP_CSC_PFMVn(0), 0x83 },
+	{ MDP_CSC_PFMVn(1), 0x102 },
+	{ MDP_CSC_PFMVn(2), 0x32 },
+	{ MDP_CSC_PFMVn(3), 0xffffffb5 },
+	{ MDP_CSC_PFMVn(4), 0xffffff6c },
+	{ MDP_CSC_PFMVn(5), 0xe1 },
+	{ MDP_CSC_PFMVn(6), 0xe1 },
+	{ MDP_CSC_PFMVn(7), 0xffffff45 },
+	{ MDP_CSC_PFMVn(8), 0xffffffdc },
+
+	/* YUV -> RGB primary reverse matrix (set2) */
+	{ MDP_CSC_PRMVn(0), 0x254 },
+	{ MDP_CSC_PRMVn(1), 0x0 },
+	{ MDP_CSC_PRMVn(2), 0x331 },
+	{ MDP_CSC_PRMVn(3), 0x254 },
+	{ MDP_CSC_PRMVn(4), 0xffffff38 },
+	{ MDP_CSC_PRMVn(5), 0xfffffe61 },
+	{ MDP_CSC_PRMVn(6), 0x254 },
+	{ MDP_CSC_PRMVn(7), 0x409 },
+	{ MDP_CSC_PRMVn(8), 0x0 },
+
+#ifndef CONFIG_MSM_MDP31
+	/* For MDP 2.2/3.0 */
+
+	/* primary limit vector */
+	{ MDP_CSC_PLVn(0), 0x10 },
+	{ MDP_CSC_PLVn(1), 0xeb },
+	{ MDP_CSC_PLVn(2), 0x10 },
+	{ MDP_CSC_PLVn(3), 0xf0 },
+
+	/* primary bias vector */
+	{ MDP_CSC_PBVn(0), 0x10 },
+	{ MDP_CSC_PBVn(1), 0x80 },
+	{ MDP_CSC_PBVn(2), 0x80 },
+
+#else /* CONFIG_MSM_MDP31 */
+
+	/* limit vectors configuration */
+	/* rgb -> yuv (set1) pre-limit vector */
+	{ MDP_PPP_CSC_PRE_LV1n(0), 0x10 },
+	{ MDP_PPP_CSC_PRE_LV1n(1), 0xeb },
+	{ MDP_PPP_CSC_PRE_LV1n(2), 0x10 },
+	{ MDP_PPP_CSC_PRE_LV1n(3), 0xf0 },
+	{ MDP_PPP_CSC_PRE_LV1n(4), 0x10 },
+	{ MDP_PPP_CSC_PRE_LV1n(5), 0xf0 },
+
+	/* rgb -> yuv (set1) post-limit vector */
+	{ MDP_PPP_CSC_POST_LV1n(0), 0x0 },
+	{ MDP_PPP_CSC_POST_LV1n(1), 0xff },
+	{ MDP_PPP_CSC_POST_LV1n(2), 0x0 },
+	{ MDP_PPP_CSC_POST_LV1n(3), 0xff },
+	{ MDP_PPP_CSC_POST_LV1n(4), 0x0 },
+	{ MDP_PPP_CSC_POST_LV1n(5), 0xff },
+
+	/* yuv -> rgb (set2) pre-limit vector */
+	{ MDP_PPP_CSC_PRE_LV2n(0), 0x0 },
+	{ MDP_PPP_CSC_PRE_LV2n(1), 0xff },
+	{ MDP_PPP_CSC_PRE_LV2n(2), 0x0 },
+	{ MDP_PPP_CSC_PRE_LV2n(3), 0xff },
+	{ MDP_PPP_CSC_PRE_LV2n(4), 0x0 },
+	{ MDP_PPP_CSC_PRE_LV2n(5), 0xff },
+
+	/* yuv -> rgb (set2) post-limit vector */
+	{ MDP_PPP_CSC_POST_LV2n(0), 0x10 },
+	{ MDP_PPP_CSC_POST_LV2n(1), 0xeb },
+	{ MDP_PPP_CSC_POST_LV2n(2), 0x10 },
+	{ MDP_PPP_CSC_POST_LV2n(3), 0xf0 },
+	{ MDP_PPP_CSC_POST_LV2n(4), 0x10 },
+	{ MDP_PPP_CSC_POST_LV2n(5), 0xf0 },
+
+	/* bias vectors configuration */
+
+	/* XXX: why is set2 used for rgb->yuv, but set1 */
+	/* used for yuv -> rgb??!? Seems to be the reverse of the
+	 * other vectors. */
+
+	/* RGB -> YUV pre-bias vector... */
+	{ MDP_PPP_CSC_PRE_BV2n(0), 0 },
+	{ MDP_PPP_CSC_PRE_BV2n(1), 0 },
+	{ MDP_PPP_CSC_PRE_BV2n(2), 0 },
+
+	/* RGB -> YUV post-bias vector */
+	{ MDP_PPP_CSC_POST_BV2n(0), 0x10 },
+	{ MDP_PPP_CSC_POST_BV2n(1), 0x80 },
+	{ MDP_PPP_CSC_POST_BV2n(2), 0x80 },
+
+	/* YUV -> RGB pre-bias vector... */
+	{ MDP_PPP_CSC_PRE_BV1n(0), 0x1f0 },
+	{ MDP_PPP_CSC_PRE_BV1n(1), 0x180 },
+	{ MDP_PPP_CSC_PRE_BV1n(2), 0x180 },
+
+	/* YUV -> RGB post-bias vector */
+	{ MDP_PPP_CSC_POST_BV1n(0), 0 },
+	{ MDP_PPP_CSC_POST_BV1n(1), 0 },
+	{ MDP_PPP_CSC_POST_BV1n(2), 0 },
+
+	/* luma filter coefficients */
+	{ MDP_PPP_DEINT_COEFFn(0), 0x3e0 },
+	{ MDP_PPP_DEINT_COEFFn(1), 0x360 },
+	{ MDP_PPP_DEINT_COEFFn(2), 0x120 },
+	{ MDP_PPP_DEINT_COEFFn(3), 0x140 },
+#endif
+};
+
+static struct {
+	uint32_t reg;
+	uint32_t val;
+} csc_color_lut[] = {
 	{ 0x40800, 0x0 },
 	{ 0x40804, 0x151515 },
 	{ 0x40808, 0x1d1d1d },
diff --git a/drivers/video/msm/mdp_hw.h b/drivers/video/msm/mdp_hw.h
index 4e3deb4..ba29454 100644
--- a/drivers/video/msm/mdp_hw.h
+++ b/drivers/video/msm/mdp_hw.h
@@ -15,23 +15,70 @@
 #ifndef _MDP_HW_H_
 #define _MDP_HW_H_
 
+#include <linux/platform_device.h>
+#include <linux/wait.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_fb.h>
 
+typedef void (*mdp_dma_start_func_t)(void *private_data, uint32_t addr,
+				     uint32_t stride, uint32_t width,
+				     uint32_t height, uint32_t x, uint32_t y);
+
+struct mdp_out_interface {
+	uint32_t		registered:1;
+	void			*priv;
+
+	/* If the interface client wants to get DMA_DONE events */
+	uint32_t		dma_mask;
+	mdp_dma_start_func_t	dma_start;
+
+	struct msmfb_callback	*dma_cb;
+	wait_queue_head_t	dma_waitqueue;
+
+	/* If the interface client wants to be notified of non-DMA irqs,
+	 * e.g. LCDC/TV-out frame start */
+	uint32_t		irq_mask;
+	struct msmfb_callback	*irq_cb;
+};
+
 struct mdp_info {
+	spinlock_t lock;
 	struct mdp_device mdp_dev;
 	char * __iomem base;
 	int irq;
+	struct clk *clk;
+	struct clk *pclk;
+	struct clk *ebi1_clk;
+	struct mdp_out_interface out_if[MSM_MDP_NUM_INTERFACES];
+	int dma_format;
+	int dma_pack_pattern;
+	bool dma_format_dirty;
+	struct mdp_blit_req *req;
+
+	int (*enable_irq)(struct mdp_info *mdp, uint32_t mask);
+	int (*disable_irq)(struct mdp_info *mdp, uint32_t mask);
 };
+
+void mdp_configure_dma_format(struct mdp_device *mdp_dev);
+
+extern int mdp_out_if_register(struct mdp_device *mdp_dev, int interface,
+			       void *private_data, uint32_t dma_mask,
+			       mdp_dma_start_func_t dma_start);
+
+extern int mdp_out_if_req_irq(struct mdp_device *mdp_dev, int interface,
+			      uint32_t mask, struct msmfb_callback *cb);
+
 struct mdp_blit_req;
 struct mdp_device;
-int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
-		 struct file *src_file, unsigned long src_start,
-		 unsigned long src_len, struct file *dst_file,
-		 unsigned long dst_start, unsigned long dst_len);
+
+int mdp_hw_init(struct mdp_info *mdp);
+
+int mdp_wait(struct mdp_info *mdp, uint32_t mask, wait_queue_head_t *wq);
+
 #define mdp_writel(mdp, value, offset) writel(value, mdp->base + offset)
 #define mdp_readl(mdp, offset) readl(mdp->base + offset)
 
+#if defined(CONFIG_MSM_MDP22)
 #define MDP_SYNC_CONFIG_0                (0x00000)
 #define MDP_SYNC_CONFIG_1                (0x00004)
 #define MDP_SYNC_CONFIG_2                (0x00008)
@@ -40,6 +87,18 @@
 #define MDP_SYNC_STATUS_2                (0x00014)
 #define MDP_SYNC_THRESH_0                (0x00018)
 #define MDP_SYNC_THRESH_1                (0x0001c)
+#endif
+
+#if defined(CONFIG_MSM_MDP40)
+#define MDP_DISP_INTF_SEL                (0x00038)
+#define MDP_MAX_RD_PENDING_CMD_CONFIG    (0x0004c)
+#define MDP_INTR_ENABLE                  (0x00050)
+#define MDP_INTR_STATUS                  (0x00054)
+#define MDP_INTR_CLEAR                   (0x00058)
+#define MDP_EBI2_LCD0                    (0x00060)
+#define MDP_EBI2_LCD1                    (0x00064)
+#define MDP_EBI2_PORTMAP_MODE            (0x00070)
+#else
 #define MDP_INTR_ENABLE                  (0x00020)
 #define MDP_INTR_STATUS                  (0x00024)
 #define MDP_INTR_CLEAR                   (0x00028)
@@ -48,10 +107,20 @@
 #define MDP_DISPLAY_STATUS               (0x00038)
 #define MDP_EBI2_LCD0                    (0x0003c)
 #define MDP_EBI2_LCD1                    (0x00040)
+#define MDP_EBI2_PORTMAP_MODE            (0x0005c)
+#endif
+
+#if defined(CONFIG_MSM_MDP22)
 #define MDP_DISPLAY0_ADDR                (0x00054)
 #define MDP_DISPLAY1_ADDR                (0x00058)
-#define MDP_EBI2_PORTMAP_MODE            (0x0005c)
-#define MDP_MODE                         (0x00060)
+#define MDP_PPP_CMD_MODE                 (0x00060)
+#elif defined(CONFIG_MSM_MDP31)
+#define MDP_DISPLAY0_ADDR                (0x10000)
+#define MDP_DISPLAY1_ADDR                (0x10004)
+#define MDP_PPP_CMD_MODE                 (0x10060)
+#endif
+
+#if defined(CONFIG_MSM_MDP22)
 #define MDP_TV_OUT_STATUS                (0x00064)
 #define MDP_HW_VERSION                   (0x00070)
 #define MDP_SW_RESET                     (0x00074)
@@ -61,6 +130,20 @@
 #define MDP_SECONDARY_VSYNC_OUT_CTRL     (0x00084)
 #define MDP_EXTERNAL_VSYNC_OUT_CTRL      (0x00088)
 #define MDP_VSYNC_CTRL                   (0x0008c)
+#endif
+
+#if defined(CONFIG_MSM_MDP31) || defined(CONFIG_MSM_MDP40)
+#define MDP_MDDI_PARAM_WR_SEL            (0x00090)
+#define MDP_MDDI_PARAM                   (0x00094)
+#define MDP_MDDI_DATA_XFR                (0x00098)
+#endif
+
+#if defined(CONFIG_MSM_MDP40)
+#define MDP_LAYERMIXER_IN_CFG            (0x10100)
+#define MDP_OVERLAYPROC0_CFG             (0x10004)
+#define MDP_OVERLAYPROC1_CFG             (0x18004)
+#endif
+
 #define MDP_CGC_EN                       (0x00100)
 #define MDP_CMD_STATUS                   (0x10008)
 #define MDP_PROFILE_EN                   (0x10010)
@@ -107,6 +190,7 @@
 #define MDP_FULL_BYPASS_WORD35           (0x1018c)
 #define MDP_FULL_BYPASS_WORD37           (0x10194)
 #define MDP_FULL_BYPASS_WORD39           (0x1019c)
+#define MDP_PPP_OUT_XY                   (0x1019c)
 #define MDP_FULL_BYPASS_WORD40           (0x101a0)
 #define MDP_FULL_BYPASS_WORD41           (0x101a4)
 #define MDP_FULL_BYPASS_WORD43           (0x101ac)
@@ -129,11 +213,27 @@
 #define MDP_FULL_BYPASS_WORD61           (0x101f4)
 #define MDP_FULL_BYPASS_WORD62           (0x101f8)
 #define MDP_FULL_BYPASS_WORD63           (0x101fc)
+
+#ifdef CONFIG_MSM_MDP31
+#define MDP_PPP_SRC_XY                   (0x10200)
+#define MDP_PPP_BG_XY                    (0x10204)
+#define MDP_PPP_SRC_IMAGE_SIZE           (0x10208)
+#define MDP_PPP_BG_IMAGE_SIZE            (0x1020c)
+#define MDP_PPP_SCALE_CONFIG             (0x10230)
+#define MDP_PPP_CSC_CONFIG               (0x10240)
+#define MDP_PPP_BLEND_BG_ALPHA_SEL       (0x70010)
+#endif
+
 #define MDP_TFETCH_TEST_MODE             (0x20004)
 #define MDP_TFETCH_STATUS                (0x20008)
 #define MDP_TFETCH_TILE_COUNT            (0x20010)
 #define MDP_TFETCH_FETCH_COUNT           (0x20014)
 #define MDP_TFETCH_CONSTANT_COLOR        (0x20040)
+#define MDP_BGTFETCH_TEST_MODE           (0x28004)
+#define MDP_BGTFETCH_STATUS              (0x28008)
+#define MDP_BGTFETCH_TILE_COUNT          (0x28010)
+#define MDP_BGTFETCH_FETCH_COUNT         (0x28014)
+#define MDP_BGTFETCH_CONSTANT_COLOR      (0x28040)
 #define MDP_CSC_BYPASS                   (0x40004)
 #define MDP_SCALE_COEFF_LSB              (0x5fffc)
 #define MDP_TV_OUT_CTL                   (0xc0000)
@@ -158,55 +258,68 @@
 #define MDP_TEST_MISR_CURR_VAL_DCLK      (0xd020c)
 #define MDP_TEST_CAPTURED_DCLK           (0xd0210)
 #define MDP_TEST_MISR_CAPT_VAL_DCLK      (0xd0214)
-#define MDP_LCDC_CTL                     (0xe0000)
-#define MDP_LCDC_HSYNC_CTL               (0xe0004)
-#define MDP_LCDC_VSYNC_CTL               (0xe0008)
-#define MDP_LCDC_ACTIVE_HCTL             (0xe000c)
-#define MDP_LCDC_ACTIVE_VCTL             (0xe0010)
-#define MDP_LCDC_BORDER_CLR              (0xe0014)
-#define MDP_LCDC_H_BLANK                 (0xe0018)
-#define MDP_LCDC_V_BLANK                 (0xe001c)
-#define MDP_LCDC_UNDERFLOW_CLR           (0xe0020)
-#define MDP_LCDC_HSYNC_SKEW              (0xe0024)
-#define MDP_LCDC_TEST_CTL                (0xe0028)
-#define MDP_LCDC_LINE_IRQ                (0xe002c)
-#define MDP_LCDC_CTL_POLARITY            (0xe0030)
-#define MDP_LCDC_DMA_CONFIG              (0xe1000)
-#define MDP_LCDC_DMA_SIZE                (0xe1004)
-#define MDP_LCDC_DMA_IBUF_ADDR           (0xe1008)
-#define MDP_LCDC_DMA_IBUF_Y_STRIDE       (0xe100c)
 
+#define MDP_DMA_P_CONFIG                 (0x90000)
+#define MDP_DMA_P_SIZE                   (0x90004)
+#define MDP_DMA_P_IBUF_ADDR              (0x90008)
+#define MDP_DMA_P_IBUF_Y_STRIDE          (0x9000c)
+#define MDP_DMA_P_OUT_XY                 (0x90010)
 
-#define MDP_DMA2_TERM 0x1
-#define MDP_DMA3_TERM 0x2
-#define MDP_PPP_TERM 0x3
+#ifdef CONFIG_MSM_MDP40
+#define MDP_DMA_P_START                  (0x0000c)
+#define MDP_DMA_P_FETCH_CFG              (0x91004)
+#define MDP_DMA_P_HIST_INTR_STATUS       (0x95014)
+#define MDP_DMA_P_HIST_INTR_CLEAR        (0x95018)
+#define MDP_DMA_P_HIST_INTR_ENABLE       (0x9501C)
+#else
+#define MDP_DMA_P_START                  (0x00044)
+#define MDP_DMA_P_COLOR_CORRECT_CONFIG   (0x90070)
+#endif
+
+#if defined(CONFIG_MSM_MDP31)
+#define MDP_LCDC_BASE                    (0xe0000)
+#elif defined(CONFIG_MSM_MDP40)
+#define MDP_LCDC_BASE                    (0xc0000)
+#endif
+
+#ifdef MDP_LCDC_BASE
+#define MDP_LCDC_EN                      (MDP_LCDC_BASE + 0x00)
+#define MDP_LCDC_HSYNC_CTL               (MDP_LCDC_BASE + 0x04)
+#define MDP_LCDC_VSYNC_PERIOD            (MDP_LCDC_BASE + 0x08)
+#define MDP_LCDC_VSYNC_PULSE_WIDTH       (MDP_LCDC_BASE + 0x0c)
+#define MDP_LCDC_DISPLAY_HCTL            (MDP_LCDC_BASE + 0x10)
+#define MDP_LCDC_DISPLAY_V_START         (MDP_LCDC_BASE + 0x14)
+#define MDP_LCDC_DISPLAY_V_END           (MDP_LCDC_BASE + 0x18)
+#define MDP_LCDC_ACTIVE_HCTL             (MDP_LCDC_BASE + 0x1c)
+#define MDP_LCDC_ACTIVE_V_START          (MDP_LCDC_BASE + 0x20)
+#define MDP_LCDC_ACTIVE_V_END            (MDP_LCDC_BASE + 0x24)
+#define MDP_LCDC_BORDER_CLR              (MDP_LCDC_BASE + 0x28)
+#define MDP_LCDC_UNDERFLOW_CTL           (MDP_LCDC_BASE + 0x2c)
+#define MDP_LCDC_HSYNC_SKEW              (MDP_LCDC_BASE + 0x30)
+#define MDP_LCDC_TEST_CTL                (MDP_LCDC_BASE + 0x34)
+#define MDP_LCDC_CTL_POLARITY            (MDP_LCDC_BASE + 0x38)
+#endif
+
+#define MDP_PPP_SCALE_STATUS             (0x50000)
+#define MDP_PPP_BLEND_STATUS             (0x70000)
+
+/* MDP_SW_RESET */
+#define MDP_PPP_SW_RESET                (1<<4)
 
 /* MDP_INTR_ENABLE */
-#define DL0_ROI_DONE           (1<<0)
-#define DL1_ROI_DONE           (1<<1)
-#define DL0_DMA2_TERM_DONE     (1<<2)
-#define DL1_DMA2_TERM_DONE     (1<<3)
-#define DL0_PPP_TERM_DONE      (1<<4)
-#define DL1_PPP_TERM_DONE      (1<<5)
-#define TV_OUT_DMA3_DONE       (1<<6)
-#define TV_ENC_UNDERRUN        (1<<7)
-#define DL0_FETCH_DONE         (1<<11)
-#define DL1_FETCH_DONE         (1<<12)
+#define DL0_ROI_DONE			(1<<0)
+#define TV_OUT_DMA3_DONE		(1<<6)
+#define TV_ENC_UNDERRUN			(1<<7)
 
-#define MDP_PPP_BUSY_STATUS (DL0_ROI_DONE| \
-			   DL1_ROI_DONE| \
-			   DL0_PPP_TERM_DONE| \
-			   DL1_PPP_TERM_DONE)
-
-#define MDP_ANY_INTR_MASK (DL0_ROI_DONE| \
-			   DL1_ROI_DONE| \
-			   DL0_DMA2_TERM_DONE| \
-			   DL1_DMA2_TERM_DONE| \
-			   DL0_PPP_TERM_DONE| \
-			   DL1_PPP_TERM_DONE| \
-			   DL0_FETCH_DONE| \
-			   DL1_FETCH_DONE| \
-			   TV_ENC_UNDERRUN)
+#if defined(CONFIG_MSM_MDP40)
+#define MDP_DMA_P_DONE			(1 << 4)
+#elif defined(CONFIG_MSM_MDP22)
+#define MDP_DMA_P_DONE			(1 << 2)
+#elif defined(CONFIG_MSM_MDP31)
+#define MDP_DMA_P_DONE			(1 << 14)
+#define MDP_LCDC_UNDERFLOW		(1 << 16)
+#define MDP_LCDC_FRAME_START		(1 << 15)
+#endif
 
 #define MDP_TOP_LUMA       16
 #define MDP_TOP_CHROMA     0
@@ -316,7 +429,12 @@
 #define PPP_OP_SCALE_X_ON (1<<0)
 #define PPP_OP_SCALE_Y_ON (1<<1)
 
+#ifndef CONFIG_MSM_MDP31
 #define PPP_OP_CONVERT_RGB2YCBCR 0
+#else
+#define PPP_OP_CONVERT_RGB2YCBCR (1<<30)
+#endif
+
 #define PPP_OP_CONVERT_YCBCR2RGB (1<<2)
 #define PPP_OP_CONVERT_ON (1<<3)
 
@@ -372,6 +490,13 @@
 #define PPP_OP_BG_CHROMA_SITE_COSITE 0
 #define PPP_OP_BG_CHROMA_SITE_OFFSITE (1<<27)
 
+#define PPP_BLEND_BG_USE_ALPHA_SEL      (1 << 0)
+#define PPP_BLEND_BG_ALPHA_REVERSE      (1 << 3)
+#define PPP_BLEND_BG_SRCPIXEL_ALPHA     (0 << 1)
+#define PPP_BLEND_BG_DSTPIXEL_ALPHA     (1 << 1)
+#define PPP_BLEND_BG_CONSTANT_ALPHA     (2 << 1)
+#define PPP_BLEND_BG_CONST_ALPHA_VAL(x) ((x) << 24)
+
 /* MDP_PPP_DESTINATION_CONFIG / MDP_FULL_BYPASS_WORD20 */
 #define PPP_DST_C0G_8BIT ((1<<0)|(1<<1))
 #define PPP_DST_C1B_8BIT ((1<<3)|(1<<2))
@@ -449,6 +574,7 @@
 #define PPP_CFG_MDP_XRGB_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
 #define PPP_CFG_MDP_RGBA_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
 #define PPP_CFG_MDP_BGRA_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
+#define PPP_CFG_MDP_RGBX_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
 
 #define PPP_CFG_MDP_Y_CBCR_H2V2(dir)   (PPP_##dir##_C2R_8BIT | \
 					PPP_##dir##_C0G_8BIT | \
@@ -488,12 +614,14 @@
 	MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8)
 #define PPP_PACK_PATTERN_MDP_RGB_888 PPP_PACK_PATTERN_MDP_RGB_565
 #define PPP_PACK_PATTERN_MDP_XRGB_8888 \
-	MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, 8)
+	MDP_GET_PACK_PATTERN(CLR_B, CLR_G, CLR_R, CLR_ALPHA, 8)
 #define PPP_PACK_PATTERN_MDP_ARGB_8888 PPP_PACK_PATTERN_MDP_XRGB_8888
 #define PPP_PACK_PATTERN_MDP_RGBA_8888 \
 	MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, 8)
 #define PPP_PACK_PATTERN_MDP_BGRA_8888 \
 	MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, 8)
+#define PPP_PACK_PATTERN_MDP_RGBX_8888 \
+	MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, 8)
 #define PPP_PACK_PATTERN_MDP_Y_CBCR_H2V1 \
 	MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8)
 #define PPP_PACK_PATTERN_MDP_Y_CBCR_H2V2 PPP_PACK_PATTERN_MDP_Y_CBCR_H2V1
@@ -509,6 +637,7 @@
 #define PPP_CHROMA_SAMP_MDP_ARGB_8888(dir) PPP_OP_##dir##_CHROMA_RGB
 #define PPP_CHROMA_SAMP_MDP_RGBA_8888(dir) PPP_OP_##dir##_CHROMA_RGB
 #define PPP_CHROMA_SAMP_MDP_BGRA_8888(dir) PPP_OP_##dir##_CHROMA_RGB
+#define PPP_CHROMA_SAMP_MDP_RGBX_8888(dir) PPP_OP_##dir##_CHROMA_RGB
 #define PPP_CHROMA_SAMP_MDP_Y_CBCR_H2V1(dir) PPP_OP_##dir##_CHROMA_H2V1
 #define PPP_CHROMA_SAMP_MDP_Y_CBCR_H2V2(dir) PPP_OP_##dir##_CHROMA_420
 #define PPP_CHROMA_SAMP_MDP_Y_CRCB_H2V1(dir) PPP_OP_##dir##_CHROMA_H2V1
@@ -523,6 +652,7 @@
 	[MDP_ARGB_8888] = PPP_##name##_MDP_ARGB_8888,\
 	[MDP_RGBA_8888] = PPP_##name##_MDP_RGBA_8888,\
 	[MDP_BGRA_8888] = PPP_##name##_MDP_BGRA_8888,\
+	[MDP_RGBX_8888] = PPP_##name##_MDP_RGBX_8888,\
 	[MDP_Y_CBCR_H2V1] = PPP_##name##_MDP_Y_CBCR_H2V1,\
 	[MDP_Y_CBCR_H2V2] = PPP_##name##_MDP_Y_CBCR_H2V2,\
 	[MDP_Y_CRCB_H2V1] = PPP_##name##_MDP_Y_CRCB_H2V1,\
@@ -536,6 +666,7 @@
 	[MDP_ARGB_8888] = PPP_##name##_MDP_ARGB_8888(dir),\
 	[MDP_RGBA_8888] = PPP_##name##_MDP_RGBA_8888(dir),\
 	[MDP_BGRA_8888] = PPP_##name##_MDP_BGRA_8888(dir),\
+	[MDP_RGBX_8888] = PPP_##name##_MDP_RGBX_8888(dir),\
 	[MDP_Y_CBCR_H2V1] = PPP_##name##_MDP_Y_CBCR_H2V1(dir),\
 	[MDP_Y_CBCR_H2V2] = PPP_##name##_MDP_Y_CBCR_H2V2(dir),\
 	[MDP_Y_CRCB_H2V1] = PPP_##name##_MDP_Y_CRCB_H2V1(dir),\
@@ -547,7 +678,8 @@
 		       (img == MDP_YCRYCB_H2V1))
 #define IS_RGB(img) ((img == MDP_RGB_565) | (img == MDP_RGB_888) | \
 		     (img == MDP_ARGB_8888) | (img == MDP_RGBA_8888) | \
-		     (img == MDP_XRGB_8888) | (img == MDP_BGRA_8888))
+		     (img == MDP_XRGB_8888) | (img == MDP_BGRA_8888) | \
+		     (img == MDP_RGBX_8888))
 #define HAS_ALPHA(img) ((img == MDP_ARGB_8888) | (img == MDP_RGBA_8888) | \
 			(img == MDP_BGRA_8888))
 
@@ -582,20 +714,71 @@
 #define PPP_ADDR_BG_CFG			MDP_FULL_BYPASS_WORD53
 #define PPP_ADDR_BG_PACK_PATTERN	MDP_FULL_BYPASS_WORD54
 
+/* color conversion matrix configuration registers */
+/* pfmv is mv1, prmv is mv2 */
+#define MDP_CSC_PFMVn(n)		(0x40400 + (4 * (n)))
+#define MDP_CSC_PRMVn(n)		(0x40440 + (4 * (n)))
+
+#ifdef CONFIG_MSM_MDP31
+#define MDP_PPP_CSC_PRE_BV1n(n)		(0x40500 + (4 * (n)))
+#define MDP_PPP_CSC_PRE_BV2n(n)		(0x40540 + (4 * (n)))
+#define MDP_PPP_CSC_POST_BV1n(n)	(0x40580 + (4 * (n)))
+#define MDP_PPP_CSC_POST_BV2n(n)	(0x405c0 + (4 * (n)))
+
+#define MDP_PPP_CSC_PRE_LV1n(n)		(0x40600 + (4 * (n)))
+#define MDP_PPP_CSC_PRE_LV2n(n)		(0x40640 + (4 * (n)))
+#define MDP_PPP_CSC_POST_LV1n(n)	(0x40680 + (4 * (n)))
+#define MDP_PPP_CSC_POST_LV2n(n)	(0x406c0 + (4 * (n)))
+
+#define MDP_PPP_SCALE_COEFF_D0_SET	(0)
+#define MDP_PPP_SCALE_COEFF_D1_SET	(1)
+#define MDP_PPP_SCALE_COEFF_D2_SET	(2)
+#define MDP_PPP_SCALE_COEFF_U1_SET	(3)
+#define MDP_PPP_SCALE_COEFF_LSBn(n)	(0x50400 + (8 * (n)))
+#define MDP_PPP_SCALE_COEFF_MSBn(n)	(0x50404 + (8 * (n)))
+
+#define MDP_PPP_DEINT_COEFFn(n)		(0x30010 + (4 * (n)))
+
+#define MDP_PPP_SCALER_FIR		(0)
+#define MDP_PPP_SCALER_MN		(1)
+
+#else /* !defined(CONFIG_MSM_MDP31) */
+
+#define MDP_CSC_PBVn(n)			(0x40500 + (4 * (n)))
+#define MDP_CSC_SBVn(n)			(0x40540 + (4 * (n)))
+#define MDP_CSC_PLVn(n)			(0x40580 + (4 * (n)))
+#define MDP_CSC_SLVn(n)			(0x405c0 + (4 * (n)))
+
+#endif
+
+
 /* MDP_DMA_CONFIG / MDP_FULL_BYPASS_WORD32 */
-#define DMA_DSTC0G_6BITS (1<<1)
-#define DMA_DSTC1B_6BITS (1<<3)
-#define DMA_DSTC2R_6BITS (1<<5)
 #define DMA_DSTC0G_5BITS (1<<0)
 #define DMA_DSTC1B_5BITS (1<<2)
 #define DMA_DSTC2R_5BITS (1<<4)
 
+#define DMA_DSTC0G_6BITS (2<<0)
+#define DMA_DSTC1B_6BITS (2<<2)
+#define DMA_DSTC2R_6BITS (2<<4)
+
+#define DMA_DSTC0G_8BITS (3<<0)
+#define DMA_DSTC1B_8BITS (3<<2)
+#define DMA_DSTC2R_8BITS (3<<4)
+
+#define DMA_DST_BITS_MASK 0x3F
+
 #define DMA_PACK_TIGHT (1<<6)
 #define DMA_PACK_LOOSE 0
 #define DMA_PACK_ALIGN_LSB 0
 #define DMA_PACK_ALIGN_MSB (1<<7)
+#define DMA_PACK_PATTERN_MASK (0x3f<<8)
 #define DMA_PACK_PATTERN_RGB \
 	(MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 2)<<8)
+#define DMA_PACK_PATTERN_BGR \
+	(MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 2)<<8)
+
+
+#ifdef CONFIG_MSM_MDP22
 
 #define DMA_OUT_SEL_AHB  0
 #define DMA_OUT_SEL_MDDI (1<<14)
@@ -603,16 +786,32 @@
 #define DMA_AHBM_LCD_SEL_SECONDARY (1<<15)
 #define DMA_IBUF_C3ALPHA_EN (1<<16)
 #define DMA_DITHER_EN (1<<17)
-
 #define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY 0
 #define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY (1<<18)
 #define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL (1<<19)
-
 #define DMA_IBUF_FORMAT_RGB565 (1<<20)
 #define DMA_IBUF_FORMAT_RGB888_OR_ARGB8888 0
-
+#define DMA_IBUF_FORMAT_MASK (1 << 20)
 #define DMA_IBUF_NONCONTIGUOUS (1<<21)
 
+#else /* CONFIG_MSM_MDP31 */
+
+#define DMA_OUT_SEL_AHB				(0 << 19)
+#define DMA_OUT_SEL_MDDI			(1 << 19)
+#define DMA_OUT_SEL_LCDC			(2 << 19)
+#define DMA_OUT_SEL_LCDC_MDDI			(3 << 19)
+#define DMA_DITHER_EN				(1 << 24)
+#define DMA_IBUF_FORMAT_RGB888			(0 << 25)
+#define DMA_IBUF_FORMAT_RGB565			(1 << 25)
+#define DMA_IBUF_FORMAT_XRGB8888		(2 << 25)
+#define DMA_IBUF_FORMAT_MASK			(3 << 25)
+#define DMA_IBUF_NONCONTIGUOUS			(0)
+
+#define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY		(0)
+#define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY	(0)
+#define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL	(0)
+#endif
+
 /* MDDI REGISTER ? */
 #define MDDI_VDO_PACKET_DESC  0x5666
 #define MDDI_VDO_PACKET_PRIM  0xC3
diff --git a/drivers/video/msm/mdp_hw40.c b/drivers/video/msm/mdp_hw40.c
new file mode 100644
index 0000000..a642c9b
--- /dev/null
+++ b/drivers/video/msm/mdp_hw40.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Dima Zavin <dima@android.com>
+ *
+ * Based on code from Code Aurora Forum.
+ *
+ * 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/io.h>
+
+#include "mdp_hw.h"
+
+static void mdp_dma_to_mddi(void *priv, uint32_t addr, uint32_t stride,
+			    uint32_t width, uint32_t height, uint32_t x,
+			    uint32_t y)
+{
+	struct mdp_info *mdp = priv;
+	uint32_t dma2_cfg;
+	uint16_t ld_param = 0; /* 0=PRIM, 1=SECD, 2=EXT */
+
+	dma2_cfg = DMA_PACK_TIGHT |
+		DMA_PACK_ALIGN_LSB;
+
+	dma2_cfg |= mdp->dma_format;
+	dma2_cfg |= mdp->dma_pack_pattern;
+	dma2_cfg |= DMA_DITHER_EN;
+
+	/* 666 18BPP */
+	dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
+
+	/* setup size, address, and stride */
+	mdp_writel(mdp, (height << 16) | (width), MDP_DMA_P_SIZE);
+	mdp_writel(mdp, addr, MDP_DMA_P_IBUF_ADDR);
+	mdp_writel(mdp, stride, MDP_DMA_P_IBUF_Y_STRIDE);
+
+	/* set y & x offset and MDDI transaction parameters */
+	mdp_writel(mdp, (y << 16) | (x), MDP_DMA_P_OUT_XY);
+	mdp_writel(mdp, ld_param, MDP_MDDI_PARAM_WR_SEL);
+	mdp_writel(mdp, (MDDI_VDO_PACKET_DESC << 16) | MDDI_VDO_PACKET_PRIM,
+		   MDP_MDDI_PARAM);
+
+	mdp_writel(mdp, 0x1, MDP_MDDI_DATA_XFR);
+	mdp_writel(mdp, dma2_cfg, MDP_DMA_P_CONFIG);
+	mdp_writel(mdp, 0, MDP_DMA_P_START);
+}
+
+int mdp_hw_init(struct mdp_info *mdp)
+{
+	int ret;
+
+	ret = mdp_out_if_register(&mdp->mdp_dev, MSM_MDDI_PMDH_INTERFACE, mdp,
+				  MDP_DMA_P_DONE, mdp_dma_to_mddi);
+	if (ret)
+		return ret;
+
+	mdp_writel(mdp, 0, MDP_INTR_ENABLE);
+	mdp_writel(mdp, 0, MDP_DMA_P_HIST_INTR_ENABLE);
+
+	/* XXX: why set this? QCT says it should be > mdp_pclk,
+	 * but they never set the clkrate of pclk */
+	clk_set_rate(mdp->clk, 122880000); /* 122.88 Mhz */
+	pr_info("%s: mdp_clk=%lu\n", __func__, clk_get_rate(mdp->clk));
+
+	/* TODO: Configure the VG/RGB pipes fetch data */
+
+	/* this should work for any mdp_clk freq. 
+	 * TODO: use different value for mdp_clk freqs >= 90Mhz */
+	mdp_writel(mdp, 0x27, MDP_DMA_P_FETCH_CFG); /* 8 bytes-burst x 8 req */
+
+	mdp_writel(mdp, 0x3, MDP_EBI2_PORTMAP_MODE);
+
+	/* 3 pending requests */
+	mdp_writel(mdp, 0x02222, MDP_MAX_RD_PENDING_CMD_CONFIG);
+
+	/* no overlay processing, sw controls everything */
+	mdp_writel(mdp, 0, MDP_LAYERMIXER_IN_CFG);
+	mdp_writel(mdp, 1 << 3, MDP_OVERLAYPROC0_CFG);
+	mdp_writel(mdp, 1 << 3, MDP_OVERLAYPROC1_CFG);
+
+	/* XXX: HACK! hardcode to do mddi on primary */
+	mdp_writel(mdp, 0x2, MDP_DISP_INTF_SEL);
+	return 0;
+}
+
diff --git a/drivers/video/msm/mdp_hw_legacy.c b/drivers/video/msm/mdp_hw_legacy.c
new file mode 100644
index 0000000..fdde9ff
--- /dev/null
+++ b/drivers/video/msm/mdp_hw_legacy.c
@@ -0,0 +1,156 @@
+/*
+ * 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/io.h>
+
+#include "mdp_hw.h"
+#include "mdp_ppp.h"
+#include "mdp_csc_table.h"
+
+#define MDP_CMD_DEBUG_ACCESS_BASE (0x10000)
+
+#ifdef CONFIG_FB_MSM_MDDI
+static void mdp_dma_to_mddi(void *priv, uint32_t addr, uint32_t stride,
+			    uint32_t width, uint32_t height, uint32_t x,
+			    uint32_t y)
+{
+	struct mdp_info *mdp = priv;
+	uint32_t dma2_cfg;
+	uint16_t ld_param = 0; /* 0=PRIM, 1=SECD, 2=EXT */
+
+	dma2_cfg = DMA_PACK_TIGHT |
+		DMA_PACK_ALIGN_LSB |
+		DMA_OUT_SEL_AHB |
+		DMA_IBUF_NONCONTIGUOUS;
+
+	dma2_cfg |= mdp->dma_format;
+	dma2_cfg |= mdp->dma_pack_pattern;
+
+	dma2_cfg |= DMA_OUT_SEL_MDDI;
+
+	dma2_cfg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY;
+
+	dma2_cfg |= DMA_DITHER_EN;
+
+	/* 666 18BPP */
+	dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
+
+#ifdef CONFIG_MSM_MDP22
+	/* setup size, address, and stride */
+	mdp_writel(mdp, (height << 16) | (width),
+		   MDP_CMD_DEBUG_ACCESS_BASE + 0x0184);
+	mdp_writel(mdp, addr, MDP_CMD_DEBUG_ACCESS_BASE + 0x0188);
+	mdp_writel(mdp, stride, MDP_CMD_DEBUG_ACCESS_BASE + 0x018C);
+
+	/* set y & x offset and MDDI transaction parameters */
+	mdp_writel(mdp, (y << 16) | (x), MDP_CMD_DEBUG_ACCESS_BASE + 0x0194);
+	mdp_writel(mdp, ld_param, MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0);
+	mdp_writel(mdp, (MDDI_VDO_PACKET_DESC << 16) | MDDI_VDO_PACKET_PRIM,
+		   MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4);
+
+	mdp_writel(mdp, dma2_cfg, MDP_CMD_DEBUG_ACCESS_BASE + 0x0180);
+
+	/* start DMA2 */
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0044);
+#else
+	/* setup size, address, and stride */
+	mdp_writel(mdp, (height << 16) | (width), MDP_DMA_P_SIZE);
+	mdp_writel(mdp, addr, MDP_DMA_P_IBUF_ADDR);
+	mdp_writel(mdp, stride, MDP_DMA_P_IBUF_Y_STRIDE);
+
+	/* set y & x offset and MDDI transaction parameters */
+	mdp_writel(mdp, (y << 16) | (x), MDP_DMA_P_OUT_XY);
+	mdp_writel(mdp, ld_param, MDP_MDDI_PARAM_WR_SEL);
+	mdp_writel(mdp, (MDDI_VDO_PACKET_DESC << 16) | MDDI_VDO_PACKET_PRIM,
+		   MDP_MDDI_PARAM);
+
+	mdp_writel(mdp, 0x1, MDP_MDDI_DATA_XFR);
+	mdp_writel(mdp, dma2_cfg, MDP_DMA_P_CONFIG);
+	mdp_writel(mdp, 0, MDP_DMA_P_START);
+#endif
+}
+#endif
+
+int mdp_hw_init(struct mdp_info *mdp)
+{
+	int n;
+
+#ifdef CONFIG_FB_MSM_MDDI
+	n = mdp_out_if_register(&mdp->mdp_dev, MSM_MDDI_PMDH_INTERFACE, mdp,
+				  MDP_DMA_P_DONE, mdp_dma_to_mddi);
+	if (n)
+		return n;
+#endif
+
+	mdp_writel(mdp, 0, MDP_INTR_ENABLE);
+
+	/* debug interface write access */
+	mdp_writel(mdp, 1, 0x60);
+	mdp_writel(mdp, 1, MDP_EBI2_PORTMAP_MODE);
+
+#ifndef CONFIG_MSM_MDP22
+	/* disable lcdc */
+	mdp_writel(mdp, 0, MDP_LCDC_EN);
+	/* enable auto clock gating for all blocks by default */
+	mdp_writel(mdp, 0xffffffff, MDP_CGC_EN);
+	/* reset color/gamma correct parms */
+	mdp_writel(mdp, 0, MDP_DMA_P_COLOR_CORRECT_CONFIG);
+#endif
+
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc);
+	mdp_writel(mdp, 1, 0x60);
+
+	for (n = 0; n < ARRAY_SIZE(csc_color_lut); n++)
+		mdp_writel(mdp, csc_color_lut[n].val, csc_color_lut[n].reg);
+
+	/* clear up unused fg/main registers */
+	/* comp.plane 2&3 ystride */
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0120);
+
+	/* unpacked pattern */
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x012c);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0130);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0134);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0158);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x015c);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0160);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0170);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0174);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x017c);
+
+	/* comp.plane 2 & 3 */
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0114);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0118);
+
+	/* clear unused bg registers */
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0);
+	mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4);
+
+	for (n = 0; n < ARRAY_SIZE(csc_matrix_config_table); n++)
+		mdp_writel(mdp, csc_matrix_config_table[n].val,
+			   csc_matrix_config_table[n].reg);
+
+	mdp_ppp_init_scale(mdp);
+
+#ifndef CONFIG_MSM_MDP31
+	mdp_writel(mdp, 0x04000400, MDP_COMMAND_CONFIG);
+#endif
+
+	return 0;
+}
diff --git a/drivers/video/msm/mdp_lcdc.c b/drivers/video/msm/mdp_lcdc.c
new file mode 100644
index 0000000..a88840aa
--- /dev/null
+++ b/drivers/video/msm/mdp_lcdc.c
@@ -0,0 +1,431 @@
+/* drivers/video/msm/mdp_lcdc.c
+ *
+ * Copyright (c) 2009 Google Inc.
+ * Copyright (c) 2009 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.
+ *
+ * Author: Dima Zavin <dima@android.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+
+#include "mdp_hw.h"
+
+struct mdp_lcdc_info {
+	struct mdp_info			*mdp;
+	struct clk			*mdp_clk;
+	struct clk			*pclk;
+	struct clk			*pad_pclk;
+	struct msm_panel_data		fb_panel_data;
+	struct platform_device		fb_pdev;
+	struct msm_lcdc_platform_data	*pdata;
+	uint32_t fb_start;
+
+	struct msmfb_callback		frame_start_cb;
+	wait_queue_head_t		vsync_waitq;
+	int				got_vsync;
+
+	struct {
+		uint32_t	clk_rate;
+		uint32_t	hsync_ctl;
+		uint32_t	vsync_period;
+		uint32_t	vsync_pulse_width;
+		uint32_t	display_hctl;
+		uint32_t	display_vstart;
+		uint32_t	display_vend;
+		uint32_t	hsync_skew;
+		uint32_t	polarity;
+	} parms;
+};
+
+static struct mdp_device *mdp_dev;
+
+#define panel_to_lcdc(p) container_of((p), struct mdp_lcdc_info, fb_panel_data)
+
+static int lcdc_unblank(struct msm_panel_data *fb_panel)
+{
+	struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel);
+	struct msm_lcdc_panel_ops *panel_ops = lcdc->pdata->panel_ops;
+
+	pr_info("%s: ()\n", __func__);
+	panel_ops->unblank(panel_ops);
+
+	return 0;
+}
+
+static int lcdc_blank(struct msm_panel_data *fb_panel)
+{
+	struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel);
+	struct msm_lcdc_panel_ops *panel_ops = lcdc->pdata->panel_ops;
+
+	pr_info("%s: ()\n", __func__);
+	panel_ops->blank(panel_ops);
+
+	return 0;
+}
+
+static int lcdc_suspend(struct msm_panel_data *fb_panel)
+{
+	struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel);
+
+	pr_info("%s: suspending\n", __func__);
+
+	mdp_writel(lcdc->mdp, 0, MDP_LCDC_EN);
+	clk_disable(lcdc->pad_pclk);
+	clk_disable(lcdc->pclk);
+	clk_disable(lcdc->mdp_clk);
+
+	return 0;
+}
+
+static int lcdc_resume(struct msm_panel_data *fb_panel)
+{
+	struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel);
+
+	pr_info("%s: resuming\n", __func__);
+
+	clk_enable(lcdc->mdp_clk);
+	clk_enable(lcdc->pclk);
+	clk_enable(lcdc->pad_pclk);
+	mdp_writel(lcdc->mdp, 1, MDP_LCDC_EN);
+
+	return 0;
+}
+
+static int lcdc_hw_init(struct mdp_lcdc_info *lcdc)
+{
+	struct msm_panel_data *fb_panel = &lcdc->fb_panel_data;
+	uint32_t dma_cfg;
+
+	clk_enable(lcdc->mdp_clk);
+	clk_enable(lcdc->pclk);
+	clk_enable(lcdc->pad_pclk);
+
+	clk_set_rate(lcdc->pclk, lcdc->parms.clk_rate);
+	clk_set_rate(lcdc->pad_pclk, lcdc->parms.clk_rate);
+
+	/* write the lcdc params */
+	mdp_writel(lcdc->mdp, lcdc->parms.hsync_ctl, MDP_LCDC_HSYNC_CTL);
+	mdp_writel(lcdc->mdp, lcdc->parms.vsync_period, MDP_LCDC_VSYNC_PERIOD);
+	mdp_writel(lcdc->mdp, lcdc->parms.vsync_pulse_width,
+		   MDP_LCDC_VSYNC_PULSE_WIDTH);
+	mdp_writel(lcdc->mdp, lcdc->parms.display_hctl, MDP_LCDC_DISPLAY_HCTL);
+	mdp_writel(lcdc->mdp, lcdc->parms.display_vstart,
+		   MDP_LCDC_DISPLAY_V_START);
+	mdp_writel(lcdc->mdp, lcdc->parms.display_vend, MDP_LCDC_DISPLAY_V_END);
+	mdp_writel(lcdc->mdp, lcdc->parms.hsync_skew, MDP_LCDC_HSYNC_SKEW);
+
+	mdp_writel(lcdc->mdp, 0, MDP_LCDC_BORDER_CLR);
+	mdp_writel(lcdc->mdp, 0xff, MDP_LCDC_UNDERFLOW_CTL);
+	mdp_writel(lcdc->mdp, 0, MDP_LCDC_ACTIVE_HCTL);
+	mdp_writel(lcdc->mdp, 0, MDP_LCDC_ACTIVE_V_START);
+	mdp_writel(lcdc->mdp, 0, MDP_LCDC_ACTIVE_V_END);
+	mdp_writel(lcdc->mdp, lcdc->parms.polarity, MDP_LCDC_CTL_POLARITY);
+
+	/* config the dma_p block that drives the lcdc data */
+	mdp_writel(lcdc->mdp, lcdc->fb_start, MDP_DMA_P_IBUF_ADDR);
+	mdp_writel(lcdc->mdp, (((fb_panel->fb_data->yres & 0x7ff) << 16) |
+			       (fb_panel->fb_data->xres & 0x7ff)),
+		   MDP_DMA_P_SIZE);
+
+	mdp_writel(lcdc->mdp, 0, MDP_DMA_P_OUT_XY);
+
+	dma_cfg = mdp_readl(lcdc->mdp, MDP_DMA_P_CONFIG);
+	dma_cfg |= (DMA_PACK_ALIGN_LSB |
+		   DMA_PACK_PATTERN_RGB |
+		   DMA_DITHER_EN);
+	dma_cfg |= DMA_OUT_SEL_LCDC;
+	dma_cfg &= ~DMA_DST_BITS_MASK;
+
+	if (fb_panel->fb_data->output_format == MSM_MDP_OUT_IF_FMT_RGB666)
+		dma_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
+	else
+		dma_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
+
+	mdp_writel(lcdc->mdp, dma_cfg, MDP_DMA_P_CONFIG);
+
+	/* enable the lcdc timing generation */
+	mdp_writel(lcdc->mdp, 1, MDP_LCDC_EN);
+
+	return 0;
+}
+
+static void lcdc_wait_vsync(struct msm_panel_data *panel)
+{
+	struct mdp_lcdc_info *lcdc = panel_to_lcdc(panel);
+	int ret;
+
+	ret = wait_event_timeout(lcdc->vsync_waitq, lcdc->got_vsync, HZ / 2);
+	if (!ret && !lcdc->got_vsync)
+		pr_err("%s: timeout waiting for VSYNC\n", __func__);
+	lcdc->got_vsync = 0;
+}
+
+static void lcdc_request_vsync(struct msm_panel_data *fb_panel,
+			       struct msmfb_callback *vsync_cb)
+{
+	struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel);
+
+	/* the vsync callback will start the dma */
+	vsync_cb->func(vsync_cb);
+	lcdc->got_vsync = 0;
+	mdp_out_if_req_irq(mdp_dev, MSM_LCDC_INTERFACE, MDP_LCDC_FRAME_START,
+			   &lcdc->frame_start_cb);
+	lcdc_wait_vsync(fb_panel);
+}
+
+static void lcdc_clear_vsync(struct msm_panel_data *fb_panel)
+{
+	struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel);
+	lcdc->got_vsync = 0;
+	mdp_out_if_req_irq(mdp_dev, MSM_LCDC_INTERFACE, 0, NULL);
+}
+
+/* called in irq context with mdp lock held, when mdp gets the
+ * MDP_LCDC_FRAME_START interrupt */
+static void lcdc_frame_start(struct msmfb_callback *cb)
+{
+	struct mdp_lcdc_info *lcdc;
+
+	lcdc = container_of(cb, struct mdp_lcdc_info, frame_start_cb);
+
+	lcdc->got_vsync = 1;
+	wake_up(&lcdc->vsync_waitq);
+}
+
+static void lcdc_dma_start(void *priv, uint32_t addr, uint32_t stride,
+			   uint32_t width, uint32_t height, uint32_t x,
+			   uint32_t y)
+{
+	struct mdp_lcdc_info *lcdc = priv;
+
+	if (lcdc->mdp->dma_format_dirty) {
+		mdp_writel(lcdc->mdp, 0, MDP_LCDC_EN);
+		mdelay(20);
+		mdp_configure_dma_format(mdp_dev);
+		mdp_writel(lcdc->mdp, 1, MDP_LCDC_EN);
+	}
+	mdp_writel(lcdc->mdp, stride, MDP_DMA_P_IBUF_Y_STRIDE);
+	mdp_writel(lcdc->mdp, addr, MDP_DMA_P_IBUF_ADDR);
+}
+
+static void precompute_timing_parms(struct mdp_lcdc_info *lcdc)
+{
+	struct msm_lcdc_timing *timing = lcdc->pdata->timing;
+	struct msm_fb_data *fb_data = lcdc->pdata->fb_data;
+	unsigned int hsync_period;
+	unsigned int hsync_start_x;
+	unsigned int hsync_end_x;
+	unsigned int vsync_period;
+	unsigned int display_vstart;
+	unsigned int display_vend;
+
+	hsync_period = (timing->hsync_back_porch +
+			fb_data->xres + timing->hsync_front_porch);
+	hsync_start_x = timing->hsync_back_porch;
+	hsync_end_x = hsync_start_x + fb_data->xres - 1;
+
+	vsync_period = (timing->vsync_back_porch +
+			fb_data->yres + timing->vsync_front_porch);
+	vsync_period *= hsync_period;
+
+	display_vstart = timing->vsync_back_porch;
+	display_vstart *= hsync_period;
+	display_vstart += timing->hsync_skew;
+
+	display_vend = (timing->vsync_back_porch + fb_data->yres) *
+		hsync_period;
+	display_vend += timing->hsync_skew - 1;
+
+	/* register values we pre-compute at init time from the timing
+	 * information in the panel info */
+	lcdc->parms.hsync_ctl = (((hsync_period & 0xfff) << 16) |
+				 (timing->hsync_pulse_width & 0xfff));
+	lcdc->parms.vsync_period = vsync_period & 0xffffff;
+	lcdc->parms.vsync_pulse_width = (timing->vsync_pulse_width *
+					 hsync_period) & 0xffffff;
+
+	lcdc->parms.display_hctl = (((hsync_end_x & 0xfff) << 16) |
+				    (hsync_start_x & 0xfff));
+	lcdc->parms.display_vstart = display_vstart & 0xffffff;
+	lcdc->parms.display_vend = display_vend & 0xffffff;
+	lcdc->parms.hsync_skew = timing->hsync_skew & 0xfff;
+	lcdc->parms.polarity = ((timing->hsync_act_low << 0) |
+				(timing->vsync_act_low << 1) |
+				(timing->den_act_low << 2));
+	lcdc->parms.clk_rate = timing->clk_rate;
+}
+
+static int mdp_lcdc_probe(struct platform_device *pdev)
+{
+	struct msm_lcdc_platform_data *pdata = pdev->dev.platform_data;
+	struct mdp_lcdc_info *lcdc;
+	int ret = 0;
+
+	if (!pdata) {
+		pr_err("%s: no LCDC platform data found\n", __func__);
+		return -EINVAL;
+	}
+
+	lcdc = kzalloc(sizeof(struct mdp_lcdc_info), GFP_KERNEL);
+	if (!lcdc)
+		return -ENOMEM;
+
+	/* We don't actually own the clocks, the mdp does. */
+	lcdc->mdp_clk = clk_get(mdp_dev->dev.parent, "mdp_clk");
+	if (IS_ERR(lcdc->mdp_clk)) {
+		pr_err("%s: failed to get mdp_clk\n", __func__);
+		ret = PTR_ERR(lcdc->mdp_clk);
+		goto err_get_mdp_clk;
+	}
+
+	lcdc->pclk = clk_get(mdp_dev->dev.parent, "lcdc_pclk_clk");
+	if (IS_ERR(lcdc->pclk)) {
+		pr_err("%s: failed to get lcdc_pclk\n", __func__);
+		ret = PTR_ERR(lcdc->pclk);
+		goto err_get_pclk;
+	}
+
+	lcdc->pad_pclk = clk_get(mdp_dev->dev.parent, "lcdc_pad_pclk_clk");
+	if (IS_ERR(lcdc->pad_pclk)) {
+		pr_err("%s: failed to get lcdc_pad_pclk\n", __func__);
+		ret = PTR_ERR(lcdc->pad_pclk);
+		goto err_get_pad_pclk;
+	}
+
+	init_waitqueue_head(&lcdc->vsync_waitq);
+	lcdc->pdata = pdata;
+	lcdc->frame_start_cb.func = lcdc_frame_start;
+
+	platform_set_drvdata(pdev, lcdc);
+
+	mdp_out_if_register(mdp_dev, MSM_LCDC_INTERFACE, lcdc, MDP_DMA_P_DONE,
+			    lcdc_dma_start);
+
+	precompute_timing_parms(lcdc);
+
+	lcdc->fb_start = pdata->fb_resource->start;
+	lcdc->mdp = container_of(mdp_dev, struct mdp_info, mdp_dev);
+
+	lcdc->fb_panel_data.suspend = lcdc_suspend;
+	lcdc->fb_panel_data.resume = lcdc_resume;
+	lcdc->fb_panel_data.wait_vsync = lcdc_wait_vsync;
+	lcdc->fb_panel_data.request_vsync = lcdc_request_vsync;
+	lcdc->fb_panel_data.clear_vsync = lcdc_clear_vsync;
+	lcdc->fb_panel_data.blank = lcdc_blank;
+	lcdc->fb_panel_data.unblank = lcdc_unblank;
+	lcdc->fb_panel_data.fb_data = pdata->fb_data;
+	lcdc->fb_panel_data.interface_type = MSM_LCDC_INTERFACE;
+
+	ret = lcdc_hw_init(lcdc);
+	if (ret) {
+		pr_err("%s: Cannot initialize the mdp_lcdc\n", __func__);
+		goto err_hw_init;
+	}
+
+	lcdc->fb_pdev.name = "msm_panel";
+	lcdc->fb_pdev.id = pdata->fb_id;
+	lcdc->fb_pdev.resource = pdata->fb_resource;
+	lcdc->fb_pdev.num_resources = 1;
+	lcdc->fb_pdev.dev.platform_data = &lcdc->fb_panel_data;
+
+	if (pdata->panel_ops->init)
+		pdata->panel_ops->init(pdata->panel_ops);
+
+	ret = platform_device_register(&lcdc->fb_pdev);
+	if (ret) {
+		pr_err("%s: Cannot register msm_panel pdev\n", __func__);
+		goto err_plat_dev_reg;
+	}
+
+	pr_info("%s: initialized\n", __func__);
+
+	return 0;
+
+err_plat_dev_reg:
+err_hw_init:
+	platform_set_drvdata(pdev, NULL);
+	clk_put(lcdc->pad_pclk);
+err_get_pad_pclk:
+	clk_put(lcdc->pclk);
+err_get_pclk:
+	clk_put(lcdc->mdp_clk);
+err_get_mdp_clk:
+	kfree(lcdc);
+	return ret;
+}
+
+static int mdp_lcdc_remove(struct platform_device *pdev)
+{
+	struct mdp_lcdc_info *lcdc = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	clk_put(lcdc->pclk);
+	clk_put(lcdc->pad_pclk);
+	kfree(lcdc);
+
+	return 0;
+}
+
+static struct platform_driver mdp_lcdc_driver = {
+	.probe = mdp_lcdc_probe,
+	.remove = mdp_lcdc_remove,
+	.driver = {
+		.name	= "msm_mdp_lcdc",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int mdp_lcdc_add_mdp_device(struct device *dev,
+				   struct class_interface *class_intf)
+{
+	/* might need locking if mulitple mdp devices */
+	if (mdp_dev)
+		return 0;
+	mdp_dev = container_of(dev, struct mdp_device, dev);
+	return platform_driver_register(&mdp_lcdc_driver);
+}
+
+static void mdp_lcdc_remove_mdp_device(struct device *dev,
+				       struct class_interface *class_intf)
+{
+	/* might need locking if mulitple mdp devices */
+	if (dev != &mdp_dev->dev)
+		return;
+	platform_driver_unregister(&mdp_lcdc_driver);
+	mdp_dev = NULL;
+}
+
+static struct class_interface mdp_lcdc_interface = {
+	.add_dev = &mdp_lcdc_add_mdp_device,
+	.remove_dev = &mdp_lcdc_remove_mdp_device,
+};
+
+static int __init mdp_lcdc_init(void)
+{
+	return register_mdp_client(&mdp_lcdc_interface);
+}
+
+module_init(mdp_lcdc_init);
diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c
index 4ff001f..8f56323 100644
--- a/drivers/video/msm/mdp_ppp.c
+++ b/drivers/video/msm/mdp_ppp.c
@@ -15,40 +15,34 @@
 #include <linux/fb.h>
 #include <linux/file.h>
 #include <linux/delay.h>
+#include <linux/major.h>
+#include <linux/msm_hw3d.h>
 #include <linux/msm_mdp.h>
+#include <linux/mutex.h>
+#include <linux/android_pmem.h>
+#include <linux/wait.h>
 #include <mach/msm_fb.h>
 
 #include "mdp_hw.h"
-#include "mdp_scale_tables.h"
+#include "mdp_ppp.h"
 
+#define PPP_DUMP_BLITS 0
+
+#define PPP_DEBUG_MSGS 1
+#if PPP_DEBUG_MSGS
+#define DLOG(fmt,args...) \
+	do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, \
+		    __LINE__, ##args); } \
+	while (0)
+#else
 #define DLOG(x...) do {} while (0)
+#endif
 
-#define MDP_DOWNSCALE_BLUR (MDP_DOWNSCALE_MAX + 1)
-static int downscale_y_table = MDP_DOWNSCALE_MAX;
-static int downscale_x_table = MDP_DOWNSCALE_MAX;
+#define IMG_LEN(rect_h, w, rect_w, bpp) (((rect_h) * w) * bpp)
 
-struct mdp_regs {
-	uint32_t src0;
-	uint32_t src1;
-	uint32_t dst0;
-	uint32_t dst1;
-	uint32_t src_cfg;
-	uint32_t dst_cfg;
-	uint32_t src_pack;
-	uint32_t dst_pack;
-	uint32_t src_rect;
-	uint32_t dst_rect;
-	uint32_t src_ystride;
-	uint32_t dst_ystride;
-	uint32_t op;
-	uint32_t src_bpp;
-	uint32_t dst_bpp;
-	uint32_t edge;
-	uint32_t phasex_init;
-	uint32_t phasey_init;
-	uint32_t phasex_step;
-	uint32_t phasey_step;
-};
+#define Y_TO_CRCB_RATIO(format) \
+	((format == MDP_Y_CBCR_H2V2 || format == MDP_Y_CRCB_H2V2) ?  2 :\
+	 (format == MDP_Y_CBCR_H2V1 || format == MDP_Y_CRCB_H2V1) ?  1 : 1)
 
 static uint32_t pack_pattern[] = {
 	PPP_ARRAY0(PACK_PATTERN)
@@ -62,18 +56,19 @@
 	PPP_ARRAY1(CFG, DST)
 };
 
-static uint32_t bytes_per_pixel[] = {
+static const uint32_t bytes_per_pixel[] = {
 	[MDP_RGB_565] = 2,
-	[MDP_RGB_888] = 3,
 	[MDP_XRGB_8888] = 4,
+	[MDP_Y_CBCR_H2V2] = 1,
 	[MDP_ARGB_8888] = 4,
+	[MDP_RGB_888] = 3,
+	[MDP_Y_CRCB_H2V2] = 1,
+	[MDP_YCRYCB_H2V1] = 2,
+	[MDP_Y_CRCB_H2V1] = 1,
+	[MDP_Y_CBCR_H2V1] = 1,
 	[MDP_RGBA_8888] = 4,
 	[MDP_BGRA_8888] = 4,
-	[MDP_Y_CBCR_H2V1] = 1,
-	[MDP_Y_CBCR_H2V2] = 1,
-	[MDP_Y_CRCB_H2V1] = 1,
-	[MDP_Y_CRCB_H2V2] = 1,
-	[MDP_YCRYCB_H2V1] = 2
+	[MDP_RGBX_8888] = 4,
 };
 
 static uint32_t dst_op_chroma[] = {
@@ -88,26 +83,108 @@
 	PPP_ARRAY1(CHROMA_SAMP, BG)
 };
 
-static void rotate_dst_addr_x(struct mdp_blit_req *req, struct mdp_regs *regs)
+static DECLARE_WAIT_QUEUE_HEAD(mdp_ppp_waitqueue);
+DEFINE_MUTEX(mdp_mutex);
+
+static uint32_t get_luma_offset(struct mdp_img *img,
+				struct mdp_rect *rect, uint32_t bpp)
 {
+#ifndef CONFIG_MSM_MDP31
+	return (rect->x + (rect->y * img->width)) * bpp;
+#else
+	return 0;
+#endif
+}
+
+static uint32_t get_chroma_offset(struct mdp_img *img,
+				  struct mdp_rect *rect, uint32_t bpp)
+{
+#ifndef CONFIG_MSM_MDP31
+	uint32_t compress_v = Y_TO_CRCB_RATIO(img->format);
+	uint32_t compress_h = 2;
+	uint32_t offset = 0;
+
+	if (IS_PSEUDOPLNR(img->format)) {
+		offset = (rect->x / compress_h) * compress_h;
+		offset += rect->y == 0 ? 0 :
+			  ((rect->y + 1) / compress_v) * img->width;
+		offset *= bpp;
+	}
+	return offset;
+#else
+	return 0;
+#endif
+}
+
+static void set_src_region(struct mdp_img *img, struct mdp_rect *rect,
+			   struct ppp_regs *regs)
+{
+	regs->src_rect = (rect->h << 16) | (rect->w & 0x1fff);
+
+#ifdef CONFIG_MSM_MDP31
+	regs->src_xy = (rect->y << 16) | (rect->x & 0x1fff);
+	regs->src_img_sz = (img->height << 16) | (img->width & 0x1fff);
+#endif
+}
+
+static inline void set_dst_region(struct mdp_rect *rect, struct ppp_regs *regs)
+{
+	regs->dst_rect = (rect->h << 16) | (rect->w & 0xfff);
+
+#ifdef CONFIG_MSM_MDP31
+	regs->dst_xy = (rect->y << 16) | (rect->x & 0x1fff);
+#endif
+}
+
+static void set_blend_region(struct mdp_img *img, struct mdp_rect *rect,
+			     struct ppp_regs *regs)
+{
+#ifdef CONFIG_MSM_MDP31
+	uint32_t rect_x = rect->x;
+	uint32_t rect_y = rect->y;
+	uint32_t img_w = img->width;
+	uint32_t img_h = img->height;
+
+	/* HW bug workaround */
+	if (img->format == MDP_YCRYCB_H2V1) {
+		regs->bg0 += (rect_x + (rect_y * img_w)) * regs->bg_bpp;
+		rect_x = 0;
+		rect_y = 0;
+		img_w = rect->w;
+		img_h = rect->h;
+	}
+
+	regs->bg_xy = (rect_y << 16) | (rect_x & 0x1fff);
+	regs->bg_img_sz = (img_h << 16) | (img_w & 0x1fff);
+#endif
+}
+
+static void rotate_dst_addr_x(struct mdp_blit_req *req,
+			      struct ppp_regs *regs)
+{
+#ifndef CONFIG_MSM_MDP31
 	regs->dst0 += (req->dst_rect.w -
 		       min((uint32_t)16, req->dst_rect.w)) * regs->dst_bpp;
 	regs->dst1 += (req->dst_rect.w -
 		       min((uint32_t)16, req->dst_rect.w)) * regs->dst_bpp;
+#endif
 }
 
-static void rotate_dst_addr_y(struct mdp_blit_req *req, struct mdp_regs *regs)
+static void rotate_dst_addr_y(struct mdp_blit_req *req,
+			      struct ppp_regs *regs)
 {
+#ifndef CONFIG_MSM_MDP31
 	regs->dst0 += (req->dst_rect.h -
 		       min((uint32_t)16, req->dst_rect.h)) *
 		       regs->dst_ystride;
 	regs->dst1 += (req->dst_rect.h -
 		       min((uint32_t)16, req->dst_rect.h)) *
 		       regs->dst_ystride;
+#endif
 }
 
 static void blit_rotate(struct mdp_blit_req *req,
-			struct mdp_regs *regs)
+			struct ppp_regs *regs)
 {
 	if (req->flags == MDP_ROT_NOP)
 		return;
@@ -126,16 +203,24 @@
 		regs->op |= PPP_OP_FLIP_LR;
 }
 
-static void blit_convert(struct mdp_blit_req *req, struct mdp_regs *regs)
+static void blit_convert(struct mdp_blit_req *req, struct ppp_regs *regs)
 {
 	if (req->src.format == req->dst.format)
 		return;
 	if (IS_RGB(req->src.format) && IS_YCRCB(req->dst.format)) {
 		regs->op |= PPP_OP_CONVERT_RGB2YCBCR | PPP_OP_CONVERT_ON;
+#ifdef CONFIG_MSM_MDP31
+		/* primary really means set1 */
+		regs->op |= PPP_OP_CONVERT_MATRIX_PRIMARY;
+		regs->csc_cfg = 0x1e;
+#endif
 	} else if (IS_YCRCB(req->src.format) && IS_RGB(req->dst.format)) {
 		regs->op |= PPP_OP_CONVERT_YCBCR2RGB | PPP_OP_CONVERT_ON;
-		if (req->dst.format == MDP_RGB_565)
-			regs->op |= PPP_OP_CONVERT_MATRIX_SECONDARY;
+#ifdef CONFIG_MSM_MDP31
+		/* secondary really means set2 */
+		regs->op |= PPP_OP_CONVERT_MATRIX_SECONDARY;
+		regs->csc_cfg = 0;
+#endif
 	}
 }
 
@@ -165,7 +250,7 @@
 }
 #undef GET_BIT_RANGE
 
-static void blit_blend(struct mdp_blit_req *req, struct mdp_regs *regs)
+static void blit_blend(struct mdp_blit_req *req, struct ppp_regs *regs)
 {
 	/* TRANSP BLEND */
 	if (req->transp_mask != MDP_TRANSP_NOP) {
@@ -190,8 +275,22 @@
 	req->alpha &= 0xff;
 	/* ALPHA BLEND */
 	if (HAS_ALPHA(req->src.format)) {
-		regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
-			PPP_OP_BLEND_SRCPIXEL_ALPHA;
+		regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON;
+		if (req->flags & MDP_BLEND_FG_PREMULT) {
+#ifdef CONFIG_MSM_MDP31
+			/* premultiplied alpha:
+			 * bg_alpha = (1 - fg_alpha)
+			 * fg_alpha = 0xff
+			 */
+			regs->bg_alpha_sel = PPP_BLEND_BG_USE_ALPHA_SEL |
+				PPP_BLEND_BG_ALPHA_REVERSE |
+				PPP_BLEND_BG_SRCPIXEL_ALPHA;
+			regs->op |= PPP_OP_BLEND_CONSTANT_ALPHA;
+			req->alpha = 0xff;
+#endif
+		} else {
+			regs->op |= PPP_OP_BLEND_SRCPIXEL_ALPHA;
+		}
 	} else if (req->alpha < MDP_ALPHA_NOP) {
 		/* just blend by alpha */
 		regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
@@ -200,254 +299,31 @@
 	}
 
 	regs->op |= bg_op_chroma[req->dst.format];
+
+	/* since we always blend src + dst -> dst, copy most of the
+	 * configuration from dest to bg */
+	regs->bg0 = regs->dst0;
+	regs->bg1 = regs->dst1;
+	regs->bg_cfg = src_img_cfg[req->dst.format];
+	regs->bg_bpp = regs->dst_bpp;
+	regs->bg_pack = pack_pattern[req->dst.format];
+	regs->bg_ystride = regs->dst_ystride;
+	set_blend_region(&req->dst, &req->dst_rect, regs);
 }
 
-#define ONE_HALF	(1LL << 32)
-#define ONE		(1LL << 33)
-#define TWO		(2LL << 33)
-#define THREE		(3LL << 33)
-#define FRAC_MASK (ONE - 1)
-#define INT_MASK (~FRAC_MASK)
-
-static int scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t origin,
-			uint32_t *phase_init, uint32_t *phase_step)
+static int blit_scale(struct mdp_info *mdp, struct mdp_blit_req *req,
+		      struct ppp_regs *regs)
 {
-	/* to improve precicsion calculations are done in U31.33 and converted
-	 * to U3.29 at the end */
-	int64_t k1, k2, k3, k4, tmp;
-	uint64_t n, d, os, os_p, od, od_p, oreq;
-	unsigned rpa = 0;
-	int64_t ip64, delta;
+	struct mdp_rect dst_rect;
 
-	if (dim_out % 3 == 0)
-		rpa = !(dim_in % (dim_out / 3));
-
-	n = ((uint64_t)dim_out) << 34;
-	d = dim_in;
-	if (!d)
-		return -1;
-	do_div(n, d);
-	k3 = (n + 1) >> 1;
-	if ((k3 >> 4) < (1LL << 27) || (k3 >> 4) > (1LL << 31)) {
-		DLOG("crap bad scale\n");
-		return -1;
-	}
-	n = ((uint64_t)dim_in) << 34;
-	d = (uint64_t)dim_out;
-	if (!d)
-		return -1;
-	do_div(n, d);
-	k1 = (n + 1) >> 1;
-	k2 = (k1 - ONE) >> 1;
-
-	*phase_init = (int)(k2 >> 4);
-	k4 = (k3 - ONE) >> 1;
-
-	if (rpa) {
-		os = ((uint64_t)origin << 33) - ONE_HALF;
-		tmp = (dim_out * os) + ONE_HALF;
-		if (!dim_in)
-			return -1;
-		do_div(tmp, dim_in);
-		od = tmp - ONE_HALF;
-	} else {
-		os = ((uint64_t)origin << 1) - 1;
-		od = (((k3 * os) >> 1) + k4);
-	}
-
-	od_p = od & INT_MASK;
-	if (od_p != od)
-		od_p += ONE;
-
-	if (rpa) {
-		tmp = (dim_in * od_p) + ONE_HALF;
-		if (!dim_in)
-			return -1;
-		do_div(tmp, dim_in);
-		os_p = tmp - ONE_HALF;
-	} else {
-		os_p = ((k1 * (od_p >> 33)) + k2);
-	}
-
-	oreq = (os_p & INT_MASK) - ONE;
-
-	ip64 = os_p - oreq;
-	delta = ((int64_t)(origin) << 33) - oreq;
-	ip64 -= delta;
-	/* limit to valid range before the left shift */
-	delta = (ip64 & (1LL << 63)) ? 4 : -4;
-	delta <<= 33;
-	while (abs((int)(ip64 >> 33)) > 4)
-		ip64 += delta;
-	*phase_init = (int)(ip64 >> 4);
-	*phase_step = (uint32_t)(k1 >> 4);
-	return 0;
-}
-
-static void load_scale_table(const struct mdp_info *mdp,
-			     struct mdp_table_entry *table, int len)
-{
-	int i;
-	for (i = 0; i < len; i++)
-		mdp_writel(mdp, table[i].val, table[i].reg);
-}
-
-enum {
-IMG_LEFT,
-IMG_RIGHT,
-IMG_TOP,
-IMG_BOTTOM,
-};
-
-static void get_edge_info(uint32_t src, uint32_t src_coord, uint32_t dst,
-			  uint32_t *interp1, uint32_t *interp2,
-			  uint32_t *repeat1, uint32_t *repeat2) {
-	if (src > 3 * dst) {
-		*interp1 = 0;
-		*interp2 = src - 1;
-		*repeat1 = 0;
-		*repeat2 = 0;
-	} else if (src == 3 * dst) {
-		*interp1 = 0;
-		*interp2 = src;
-		*repeat1 = 0;
-		*repeat2 = 1;
-	} else if (src > dst && src < 3 * dst) {
-		*interp1 = -1;
-		*interp2 = src;
-		*repeat1 = 1;
-		*repeat2 = 1;
-	} else if (src == dst) {
-		*interp1 = -1;
-		*interp2 = src + 1;
-		*repeat1 = 1;
-		*repeat2 = 2;
-	} else {
-		*interp1 = -2;
-		*interp2 = src + 1;
-		*repeat1 = 2;
-		*repeat2 = 2;
-	}
-	*interp1 += src_coord;
-	*interp2 += src_coord;
-}
-
-static int get_edge_cond(struct mdp_blit_req *req, struct mdp_regs *regs)
-{
-	int32_t luma_interp[4];
-	int32_t luma_repeat[4];
-	int32_t chroma_interp[4];
-	int32_t chroma_bound[4];
-	int32_t chroma_repeat[4];
-	uint32_t dst_w, dst_h;
-
-	memset(&luma_interp, 0, sizeof(int32_t) * 4);
-	memset(&luma_repeat, 0, sizeof(int32_t) * 4);
-	memset(&chroma_interp, 0, sizeof(int32_t) * 4);
-	memset(&chroma_bound, 0, sizeof(int32_t) * 4);
-	memset(&chroma_repeat, 0, sizeof(int32_t) * 4);
-	regs->edge = 0;
-
+	memcpy(&dst_rect, &req->dst_rect, sizeof(dst_rect));
 	if (req->flags & MDP_ROT_90) {
-		dst_w = req->dst_rect.h;
-		dst_h = req->dst_rect.w;
-	} else {
-		dst_w = req->dst_rect.w;
-		dst_h = req->dst_rect.h;
+		dst_rect.w = req->dst_rect.h;
+		dst_rect.h = req->dst_rect.w;
 	}
 
-	if (regs->op & (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON)) {
-		get_edge_info(req->src_rect.h, req->src_rect.y, dst_h,
-			      &luma_interp[IMG_TOP], &luma_interp[IMG_BOTTOM],
-			      &luma_repeat[IMG_TOP], &luma_repeat[IMG_BOTTOM]);
-		get_edge_info(req->src_rect.w, req->src_rect.x, dst_w,
-			      &luma_interp[IMG_LEFT], &luma_interp[IMG_RIGHT],
-			      &luma_repeat[IMG_LEFT], &luma_repeat[IMG_RIGHT]);
-	} else {
-		luma_interp[IMG_LEFT] = req->src_rect.x;
-		luma_interp[IMG_RIGHT] = req->src_rect.x + req->src_rect.w - 1;
-		luma_interp[IMG_TOP] = req->src_rect.y;
-		luma_interp[IMG_BOTTOM] = req->src_rect.y + req->src_rect.h - 1;
-		luma_repeat[IMG_LEFT] = 0;
-		luma_repeat[IMG_TOP] = 0;
-		luma_repeat[IMG_RIGHT] = 0;
-		luma_repeat[IMG_BOTTOM] = 0;
-	}
-
-	chroma_interp[IMG_LEFT] = luma_interp[IMG_LEFT];
-	chroma_interp[IMG_RIGHT] = luma_interp[IMG_RIGHT];
-	chroma_interp[IMG_TOP] = luma_interp[IMG_TOP];
-	chroma_interp[IMG_BOTTOM] = luma_interp[IMG_BOTTOM];
-
-	chroma_bound[IMG_LEFT] = req->src_rect.x;
-	chroma_bound[IMG_RIGHT] = req->src_rect.x + req->src_rect.w - 1;
-	chroma_bound[IMG_TOP] = req->src_rect.y;
-	chroma_bound[IMG_BOTTOM] = req->src_rect.y + req->src_rect.h - 1;
-
-	if (IS_YCRCB(req->src.format)) {
-		chroma_interp[IMG_LEFT] = chroma_interp[IMG_LEFT] >> 1;
-		chroma_interp[IMG_RIGHT] = (chroma_interp[IMG_RIGHT] + 1) >> 1;
-
-		chroma_bound[IMG_LEFT] = chroma_bound[IMG_LEFT] >> 1;
-		chroma_bound[IMG_RIGHT] = chroma_bound[IMG_RIGHT] >> 1;
-	}
-
-	if (req->src.format == MDP_Y_CBCR_H2V2 ||
-	    req->src.format == MDP_Y_CRCB_H2V2) {
-		chroma_interp[IMG_TOP] = (chroma_interp[IMG_TOP] - 1) >> 1;
-		chroma_interp[IMG_BOTTOM] = (chroma_interp[IMG_BOTTOM] + 1)
-					    >> 1;
-		chroma_bound[IMG_TOP] = (chroma_bound[IMG_TOP] + 1) >> 1;
-		chroma_bound[IMG_BOTTOM] = chroma_bound[IMG_BOTTOM] >> 1;
-	}
-
-	chroma_repeat[IMG_LEFT] = chroma_bound[IMG_LEFT] -
-				  chroma_interp[IMG_LEFT];
-	chroma_repeat[IMG_RIGHT] = chroma_interp[IMG_RIGHT] -
-				  chroma_bound[IMG_RIGHT];
-	chroma_repeat[IMG_TOP] = chroma_bound[IMG_TOP] -
-				  chroma_interp[IMG_TOP];
-	chroma_repeat[IMG_BOTTOM] = chroma_interp[IMG_BOTTOM] -
-				  chroma_bound[IMG_BOTTOM];
-
-	if (chroma_repeat[IMG_LEFT] < 0 || chroma_repeat[IMG_LEFT] > 3 ||
-	    chroma_repeat[IMG_RIGHT] < 0 || chroma_repeat[IMG_RIGHT] > 3 ||
-	    chroma_repeat[IMG_TOP] < 0 || chroma_repeat[IMG_TOP] > 3 ||
-	    chroma_repeat[IMG_BOTTOM] < 0 || chroma_repeat[IMG_BOTTOM] > 3 ||
-	    luma_repeat[IMG_LEFT] < 0 || luma_repeat[IMG_LEFT] > 3 ||
-	    luma_repeat[IMG_RIGHT] < 0 || luma_repeat[IMG_RIGHT] > 3 ||
-	    luma_repeat[IMG_TOP] < 0 || luma_repeat[IMG_TOP] > 3 ||
-	    luma_repeat[IMG_BOTTOM] < 0 || luma_repeat[IMG_BOTTOM] > 3)
-		return -1;
-
-	regs->edge |= (chroma_repeat[IMG_LEFT] & 3) << MDP_LEFT_CHROMA;
-	regs->edge |= (chroma_repeat[IMG_RIGHT] & 3) << MDP_RIGHT_CHROMA;
-	regs->edge |= (chroma_repeat[IMG_TOP] & 3) << MDP_TOP_CHROMA;
-	regs->edge |= (chroma_repeat[IMG_BOTTOM] & 3) << MDP_BOTTOM_CHROMA;
-	regs->edge |= (luma_repeat[IMG_LEFT] & 3) << MDP_LEFT_LUMA;
-	regs->edge |= (luma_repeat[IMG_RIGHT] & 3) << MDP_RIGHT_LUMA;
-	regs->edge |= (luma_repeat[IMG_TOP] & 3) << MDP_TOP_LUMA;
-	regs->edge |= (luma_repeat[IMG_BOTTOM] & 3) << MDP_BOTTOM_LUMA;
-	return 0;
-}
-
-static int blit_scale(const struct mdp_info *mdp, struct mdp_blit_req *req,
-		      struct mdp_regs *regs)
-{
-	uint32_t phase_init_x, phase_init_y, phase_step_x, phase_step_y;
-	uint32_t scale_factor_x, scale_factor_y;
-	uint32_t downscale;
-	uint32_t dst_w, dst_h;
-
-	if (req->flags & MDP_ROT_90) {
-		dst_w = req->dst_rect.h;
-		dst_h = req->dst_rect.w;
-	} else {
-		dst_w = req->dst_rect.w;
-		dst_h = req->dst_rect.h;
-	}
-	if ((req->src_rect.w == dst_w)  && (req->src_rect.h == dst_h) &&
-	    !(req->flags & MDP_BLUR)) {
+	if ((req->src_rect.w == dst_rect.w) && (req->src_rect.h == dst_rect.h)
+	    && !(req->flags & MDP_BLUR)) {
 		regs->phasex_init = 0;
 		regs->phasey_init = 0;
 		regs->phasex_step = 0;
@@ -455,73 +331,30 @@
 		return 0;
 	}
 
-	if (scale_params(req->src_rect.w, dst_w, 1, &phase_init_x,
-			 &phase_step_x) ||
-	    scale_params(req->src_rect.h, dst_h, 1, &phase_init_y,
-			 &phase_step_y))
+	if (mdp_ppp_cfg_scale(mdp, regs, &req->src_rect, &dst_rect,
+				req->src.format, req->dst.format)) {
+		DLOG("crap, bad scale\n");
 		return -1;
-
-	scale_factor_x = (dst_w * 10) / req->src_rect.w;
-	scale_factor_y = (dst_h * 10) / req->src_rect.h;
-
-	if (scale_factor_x > 8)
-		downscale = MDP_DOWNSCALE_PT8TO1;
-	else if (scale_factor_x > 6)
-		downscale = MDP_DOWNSCALE_PT6TOPT8;
-	else if (scale_factor_x > 4)
-		downscale = MDP_DOWNSCALE_PT4TOPT6;
-	else
-		downscale = MDP_DOWNSCALE_PT2TOPT4;
-	if (downscale != downscale_x_table) {
-		load_scale_table(mdp, mdp_downscale_x_table[downscale], 64);
-		downscale_x_table = downscale;
 	}
 
-	if (scale_factor_y > 8)
-		downscale = MDP_DOWNSCALE_PT8TO1;
-	else if (scale_factor_y > 6)
-		downscale = MDP_DOWNSCALE_PT6TOPT8;
-	else if (scale_factor_y > 4)
-		downscale = MDP_DOWNSCALE_PT4TOPT6;
-	else
-		downscale = MDP_DOWNSCALE_PT2TOPT4;
-	if (downscale != downscale_y_table) {
-		load_scale_table(mdp, mdp_downscale_y_table[downscale], 64);
-		downscale_y_table = downscale;
-	}
-
-	regs->phasex_init = phase_init_x;
-	regs->phasey_init = phase_init_y;
-	regs->phasex_step = phase_step_x;
-	regs->phasey_step = phase_step_y;
 	regs->op |= (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
 	return 0;
-
 }
 
-static void blit_blur(const struct mdp_info *mdp, struct mdp_blit_req *req,
-		      struct mdp_regs *regs)
+static void blit_blur(struct mdp_info *mdp, struct mdp_blit_req *req,
+		      struct ppp_regs *regs)
 {
+	int ret;
 	if (!(req->flags & MDP_BLUR))
 		return;
 
-	if (!(downscale_x_table == MDP_DOWNSCALE_BLUR &&
-	      downscale_y_table == MDP_DOWNSCALE_BLUR)) {
-		load_scale_table(mdp, mdp_gaussian_blur_table, 128);
-		downscale_x_table = MDP_DOWNSCALE_BLUR;
-		downscale_y_table = MDP_DOWNSCALE_BLUR;
-	}
+	ret = mdp_ppp_load_blur(mdp);
+	if (ret)
+		return;
 
 	regs->op |= (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
 }
 
-
-#define IMG_LEN(rect_h, w, rect_w, bpp) (((rect_h) * w) * bpp)
-
-#define Y_TO_CRCB_RATIO(format) \
-	((format == MDP_Y_CBCR_H2V2 || format == MDP_Y_CRCB_H2V2) ?  2 :\
-	 (format == MDP_Y_CBCR_H2V1 || format == MDP_Y_CRCB_H2V1) ?  1 : 1)
-
 static void get_len(struct mdp_img *img, struct mdp_rect *rect, uint32_t bpp,
 		    uint32_t *len0, uint32_t *len1)
 {
@@ -534,7 +367,7 @@
 
 static int valid_src_dst(unsigned long src_start, unsigned long src_len,
 			 unsigned long dst_start, unsigned long dst_len,
-			 struct mdp_blit_req *req, struct mdp_regs *regs)
+			 struct mdp_blit_req *req, struct ppp_regs *regs)
 {
 	unsigned long src_min_ok = src_start;
 	unsigned long src_max_ok = src_start + src_len;
@@ -574,83 +407,151 @@
 	return 1;
 }
 
-
-static void flush_imgs(struct mdp_blit_req *req, struct mdp_regs *regs,
+static void flush_imgs(struct mdp_blit_req *req, struct ppp_regs *regs,
 		       struct file *src_file, struct file *dst_file)
 {
+#ifdef CONFIG_ANDROID_PMEM
+	uint32_t src0_len, src1_len, dst0_len, dst1_len;
+
+	/* flush src images to memory before dma to mdp */
+	get_len(&req->src, &req->src_rect, regs->src_bpp, &src0_len,
+		&src1_len);
+	flush_pmem_file(src_file, req->src.offset, src0_len);
+	if (IS_PSEUDOPLNR(req->src.format))
+		flush_pmem_file(src_file, req->src.offset + src0_len,
+				src1_len);
+
+	/* flush dst images */
+	get_len(&req->dst, &req->dst_rect, regs->dst_bpp, &dst0_len,
+		&dst1_len);
+	flush_pmem_file(dst_file, req->dst.offset, dst0_len);
+	if (IS_PSEUDOPLNR(req->dst.format))
+		flush_pmem_file(dst_file, req->dst.offset + dst0_len,
+				dst1_len);
+#endif
 }
 
-static void get_chroma_addr(struct mdp_img *img, struct mdp_rect *rect,
-			    uint32_t base, uint32_t bpp, uint32_t cfg,
-			    uint32_t *addr, uint32_t *ystride)
+static uint32_t get_chroma_base(struct mdp_img *img, uint32_t base,
+				uint32_t bpp)
 {
-	uint32_t compress_v = Y_TO_CRCB_RATIO(img->format);
-	uint32_t compress_h = 2;
-	uint32_t  offset;
+	uint32_t addr = 0;
 
-	if (IS_PSEUDOPLNR(img->format)) {
-		offset = (rect->x / compress_h) * compress_h;
-		offset += rect->y == 0 ? 0 :
-			  ((rect->y + 1) / compress_v) * img->width;
-		*addr = base + (img->width * img->height * bpp);
-		*addr += offset * bpp;
-		*ystride |= *ystride << 16;
-	} else {
-		*addr = 0;
-	}
+	if (IS_PSEUDOPLNR(img->format))
+		addr = base + (img->width * img->height * bpp);
+	return addr;
 }
 
+int mdp_get_bytes_per_pixel(int format)
+{
+	if (format < 0 || format >= MDP_IMGTYPE_LIMIT)
+		return -1;
+	return bytes_per_pixel[format];
+}
+
+#if PPP_DUMP_BLITS
+#define mdp_writel_dbg(mdp, val, reg) do { \
+		pr_info("%s: writing 0x%08x=0x%08x\n", __func__, (reg), (val));\
+		mdp_writel((mdp), (val), (reg)); \
+	} while (0)
+#else
+#define mdp_writel_dbg(mdp, val, reg) mdp_writel((mdp), (val), (reg))
+#endif
+
+
 static int send_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
-		     struct mdp_regs *regs, struct file *src_file,
+		     struct ppp_regs *regs, struct file *src_file,
 		     struct file *dst_file)
 {
-	mdp_writel(mdp, 1, 0x060);
-	mdp_writel(mdp, regs->src_rect, PPP_ADDR_SRC_ROI);
-	mdp_writel(mdp, regs->src0, PPP_ADDR_SRC0);
-	mdp_writel(mdp, regs->src1, PPP_ADDR_SRC1);
-	mdp_writel(mdp, regs->src_ystride, PPP_ADDR_SRC_YSTRIDE);
-	mdp_writel(mdp, regs->src_cfg, PPP_ADDR_SRC_CFG);
-	mdp_writel(mdp, regs->src_pack, PPP_ADDR_SRC_PACK_PATTERN);
+#if 0
+	mdp_writel_dbg(mdp, 1, MDP_PPP_CMD_MODE);
+#endif
+	mdp_writel_dbg(mdp, regs->src_rect, PPP_ADDR_SRC_ROI);
+	mdp_writel_dbg(mdp, regs->src0, PPP_ADDR_SRC0);
+	mdp_writel_dbg(mdp, regs->src1, PPP_ADDR_SRC1);
+	mdp_writel_dbg(mdp, regs->src_ystride, PPP_ADDR_SRC_YSTRIDE);
+	mdp_writel_dbg(mdp, regs->src_cfg, PPP_ADDR_SRC_CFG);
+	mdp_writel_dbg(mdp, regs->src_pack, PPP_ADDR_SRC_PACK_PATTERN);
 
-	mdp_writel(mdp, regs->op, PPP_ADDR_OPERATION);
-	mdp_writel(mdp, regs->phasex_init, PPP_ADDR_PHASEX_INIT);
-	mdp_writel(mdp, regs->phasey_init, PPP_ADDR_PHASEY_INIT);
-	mdp_writel(mdp, regs->phasex_step, PPP_ADDR_PHASEX_STEP);
-	mdp_writel(mdp, regs->phasey_step, PPP_ADDR_PHASEY_STEP);
+	mdp_writel_dbg(mdp, regs->op, PPP_ADDR_OPERATION);
+	mdp_writel_dbg(mdp, regs->phasex_init, PPP_ADDR_PHASEX_INIT);
+	mdp_writel_dbg(mdp, regs->phasey_init, PPP_ADDR_PHASEY_INIT);
+	mdp_writel_dbg(mdp, regs->phasex_step, PPP_ADDR_PHASEX_STEP);
+	mdp_writel_dbg(mdp, regs->phasey_step, PPP_ADDR_PHASEY_STEP);
 
-	mdp_writel(mdp, (req->alpha << 24) | (req->transp_mask & 0xffffff),
+#ifdef CONFIG_MSM_MDP31
+	mdp_writel_dbg(mdp, regs->scale_cfg, MDP_PPP_SCALE_CONFIG);
+	mdp_writel_dbg(mdp, regs->csc_cfg, MDP_PPP_CSC_CONFIG);
+	mdp_writel_dbg(mdp, regs->src_xy, MDP_PPP_SRC_XY);
+	mdp_writel_dbg(mdp, regs->src_img_sz, MDP_PPP_SRC_IMAGE_SIZE);
+	mdp_writel_dbg(mdp, regs->dst_xy, MDP_PPP_OUT_XY);
+#else
+	/* no edge conditions to set for MDP 3.1 */
+	mdp_writel_dbg(mdp, regs->edge, PPP_ADDR_EDGE);
+#endif
+
+	mdp_writel_dbg(mdp, (req->alpha << 24) | (req->transp_mask & 0xffffff),
 	       PPP_ADDR_ALPHA_TRANSP);
 
-	mdp_writel(mdp, regs->dst_cfg, PPP_ADDR_DST_CFG);
-	mdp_writel(mdp, regs->dst_pack, PPP_ADDR_DST_PACK_PATTERN);
-	mdp_writel(mdp, regs->dst_rect, PPP_ADDR_DST_ROI);
-	mdp_writel(mdp, regs->dst0, PPP_ADDR_DST0);
-	mdp_writel(mdp, regs->dst1, PPP_ADDR_DST1);
-	mdp_writel(mdp, regs->dst_ystride, PPP_ADDR_DST_YSTRIDE);
+	mdp_writel_dbg(mdp, regs->dst_cfg, PPP_ADDR_DST_CFG);
+	mdp_writel_dbg(mdp, regs->dst_pack, PPP_ADDR_DST_PACK_PATTERN);
+	mdp_writel_dbg(mdp, regs->dst_rect, PPP_ADDR_DST_ROI);
+	mdp_writel_dbg(mdp, regs->dst0, PPP_ADDR_DST0);
+	mdp_writel_dbg(mdp, regs->dst1, PPP_ADDR_DST1);
+	mdp_writel_dbg(mdp, regs->dst_ystride, PPP_ADDR_DST_YSTRIDE);
 
-	mdp_writel(mdp, regs->edge, PPP_ADDR_EDGE);
 	if (regs->op & PPP_OP_BLEND_ON) {
-		mdp_writel(mdp, regs->dst0, PPP_ADDR_BG0);
-		mdp_writel(mdp, regs->dst1, PPP_ADDR_BG1);
-		mdp_writel(mdp, regs->dst_ystride, PPP_ADDR_BG_YSTRIDE);
-		mdp_writel(mdp, src_img_cfg[req->dst.format], PPP_ADDR_BG_CFG);
-		mdp_writel(mdp, pack_pattern[req->dst.format],
-			   PPP_ADDR_BG_PACK_PATTERN);
+		mdp_writel_dbg(mdp, regs->bg0, PPP_ADDR_BG0);
+		mdp_writel_dbg(mdp, regs->bg1, PPP_ADDR_BG1);
+		mdp_writel_dbg(mdp, regs->bg_ystride, PPP_ADDR_BG_YSTRIDE);
+		mdp_writel_dbg(mdp, regs->bg_cfg, PPP_ADDR_BG_CFG);
+		mdp_writel_dbg(mdp, regs->bg_pack, PPP_ADDR_BG_PACK_PATTERN);
+#ifdef CONFIG_MSM_MDP31
+		mdp_writel_dbg(mdp, regs->bg_xy, MDP_PPP_BG_XY);
+		mdp_writel_dbg(mdp, regs->bg_img_sz, MDP_PPP_BG_IMAGE_SIZE);
+		mdp_writel_dbg(mdp, regs->bg_alpha_sel,
+			       MDP_PPP_BLEND_BG_ALPHA_SEL);
+#endif
 	}
 	flush_imgs(req, regs, src_file, dst_file);
-	mdp_writel(mdp, 0x1000, MDP_DISPLAY0_START);
+	mdp_writel_dbg(mdp, 0x1000, MDP_DISPLAY0_START);
 	return 0;
 }
 
-int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
+#if PPP_DUMP_BLITS
+static void mdp_dump_blit(struct mdp_blit_req *req)
+{
+	pr_info("%s: src: w=%d h=%d f=0x%x offs=0x%x mem_id=%d\n", __func__,
+		req->src.width, req->src.height, req->src.format,
+		req->src.offset, req->src.memory_id);
+	pr_info("%s: dst: w=%d h=%d f=0x%x offs=0x%x mem_id=%d\n", __func__,
+		req->dst.width, req->dst.height, req->dst.format,
+		req->dst.offset, req->dst.memory_id);
+	pr_info("%s: src_rect: x=%d y=%d w=%d h=%d\n", __func__,
+		req->src_rect.x, req->src_rect.y, req->src_rect.w,
+		req->src_rect.h);
+	pr_info("%s: dst_rect: x=%d y=%d w=%d h=%d\n", __func__,
+		req->dst_rect.x, req->dst_rect.y, req->dst_rect.w,
+		req->dst_rect.h);
+	pr_info("%s: alpha=0x%08x\n", __func__, req->alpha);
+	pr_info("%s: transp_max=0x%08x\n", __func__, req->transp_mask);
+	pr_info("%s: flags=%08x\n", __func__, req->flags);
+}
+#endif
+
+static int process_blit(struct mdp_info *mdp, struct mdp_blit_req *req,
 		 struct file *src_file, unsigned long src_start, unsigned long src_len,
 		 struct file *dst_file, unsigned long dst_start, unsigned long dst_len)
 {
-	struct mdp_regs regs = {0};
+	struct ppp_regs regs = {0};
+	uint32_t luma_base;
+
+#if PPP_DUMP_BLITS
+	mdp_dump_blit(req);
+#endif
 
 	if (unlikely(req->src.format >= MDP_IMGTYPE_LIMIT ||
 		     req->dst.format >= MDP_IMGTYPE_LIMIT)) {
-		printk(KERN_ERR "mpd_ppp: img is of wrong format\n");
+		printk(KERN_ERR "mdp_ppp: img is of wrong format\n");
 		return -EINVAL;
 	}
 
@@ -658,7 +559,15 @@
 		     req->src_rect.y > req->src.height ||
 		     req->dst_rect.x > req->dst.width ||
 		     req->dst_rect.y > req->dst.height)) {
-		printk(KERN_ERR "mpd_ppp: img rect is outside of img!\n");
+		printk(KERN_ERR "mdp_ppp: img rect is outside of img!\n");
+		return -EINVAL;
+	}
+
+	if (unlikely(req->src_rect.x + req->src_rect.w > req->src.width ||
+		     req->src_rect.y + req->src_rect.h > req->src.height ||
+		     req->dst_rect.x + req->dst_rect.w > req->dst.width ||
+		     req->dst_rect.y + req->dst_rect.h > req->dst.height)) {
+		printk(KERN_ERR "mdp_ppp: img rect extends outside of img!\n");
 		return -EINVAL;
 	}
 
@@ -666,35 +575,35 @@
 	regs.src_cfg = src_img_cfg[req->src.format];
 	regs.src_cfg |= (req->src_rect.x & 0x1) ? PPP_SRC_BPP_ROI_ODD_X : 0;
 	regs.src_cfg |= (req->src_rect.y & 0x1) ? PPP_SRC_BPP_ROI_ODD_Y : 0;
-	regs.src_rect = (req->src_rect.h << 16) | req->src_rect.w;
 	regs.src_pack = pack_pattern[req->src.format];
 
 	/* set the dest image configuration */
 	regs.dst_cfg = dst_img_cfg[req->dst.format] | PPP_DST_OUT_SEL_AXI;
-	regs.dst_rect = (req->dst_rect.h << 16) | req->dst_rect.w;
 	regs.dst_pack = pack_pattern[req->dst.format];
 
 	/* set src, bpp, start pixel and ystride */
-	regs.src_bpp = bytes_per_pixel[req->src.format];
-	regs.src0 = src_start + req->src.offset;
+	regs.src_bpp = mdp_get_bytes_per_pixel(req->src.format);
+	luma_base = src_start + req->src.offset;
+	regs.src0 = luma_base +
+		get_luma_offset(&req->src, &req->src_rect, regs.src_bpp);
+	regs.src1 = get_chroma_base(&req->src, luma_base, regs.src_bpp);
+	regs.src1 += get_chroma_offset(&req->src, &req->src_rect, regs.src_bpp);
 	regs.src_ystride = req->src.width * regs.src_bpp;
-	get_chroma_addr(&req->src, &req->src_rect, regs.src0, regs.src_bpp,
-			regs.src_cfg, &regs.src1, &regs.src_ystride);
-	regs.src0 += (req->src_rect.x + (req->src_rect.y * req->src.width)) *
-		      regs.src_bpp;
+	set_src_region(&req->src, &req->src_rect, &regs);
 
 	/* set dst, bpp, start pixel and ystride */
-	regs.dst_bpp = bytes_per_pixel[req->dst.format];
-	regs.dst0 = dst_start + req->dst.offset;
+	regs.dst_bpp = mdp_get_bytes_per_pixel(req->dst.format);
+	luma_base = dst_start + req->dst.offset;
+	regs.dst0 = luma_base +
+		get_luma_offset(&req->dst, &req->dst_rect, regs.dst_bpp);
+	regs.dst1 = get_chroma_base(&req->dst, luma_base, regs.dst_bpp);
+	regs.dst1 += get_chroma_offset(&req->dst, &req->dst_rect, regs.dst_bpp);
 	regs.dst_ystride = req->dst.width * regs.dst_bpp;
-	get_chroma_addr(&req->dst, &req->dst_rect, regs.dst0, regs.dst_bpp,
-			regs.dst_cfg, &regs.dst1, &regs.dst_ystride);
-	regs.dst0 += (req->dst_rect.x + (req->dst_rect.y * req->dst.width)) *
-		      regs.dst_bpp;
+	set_dst_region(&req->dst_rect, &regs);
 
 	if (!valid_src_dst(src_start, src_len, dst_start, dst_len, req,
 			   &regs)) {
-		printk(KERN_ERR "mpd_ppp: final src or dst location is "
+		printk(KERN_ERR "mdp_ppp: final src or dst location is "
 			"invalid, are you trying to make an image too large "
 			"or to place it outside the screen?\n");
 		return -EINVAL;
@@ -708,7 +617,7 @@
 		regs.op |= PPP_OP_DITHER_EN;
 	blit_blend(req, &regs);
 	if (blit_scale(mdp, req, &regs)) {
-		printk(KERN_ERR "mpd_ppp: error computing scale for img.\n");
+		printk(KERN_ERR "mdp_ppp: error computing scale for img.\n");
 		return -EINVAL;
 	}
 	blit_blur(mdp, req, &regs);
@@ -722,9 +631,188 @@
 		req->dst_rect.x = req->dst_rect.x & (~0x1);
 		req->dst_rect.w = req->dst_rect.w & (~0x1);
 	}
-	if (get_edge_cond(req, &regs))
+
+	if (mdp_ppp_cfg_edge_cond(req, &regs))
 		return -EINVAL;
 
+	/* for simplicity, always write the chroma stride */
+	regs.src_ystride &= 0x3fff;
+	regs.src_ystride |= regs.src_ystride << 16;
+	regs.dst_ystride &= 0x3fff;
+	regs.dst_ystride |= regs.dst_ystride << 16;
+	regs.bg_ystride &= 0x3fff;
+	regs.bg_ystride |= regs.bg_ystride << 16;
+
+#if PPP_DUMP_BLITS
+	pr_info("%s: sending blit\n", __func__);
+#endif
 	send_blit(mdp, req, &regs, src_file, dst_file);
 	return 0;
 }
+
+#define mdp_dump_register(mdp, reg) \
+	printk(# reg ": %08x\n", mdp_readl((mdp), (reg)))
+
+void mdp_ppp_dump_debug(const struct mdp_info *mdp)
+{
+	mdp_dump_register(mdp, MDP_TFETCH_STATUS);
+	mdp_dump_register(mdp, MDP_TFETCH_TILE_COUNT);
+	mdp_dump_register(mdp, MDP_TFETCH_FETCH_COUNT);
+	mdp_dump_register(mdp, MDP_BGTFETCH_STATUS);
+	mdp_dump_register(mdp, MDP_BGTFETCH_TILE_COUNT);
+	mdp_dump_register(mdp, MDP_BGTFETCH_FETCH_COUNT);
+	mdp_dump_register(mdp, MDP_PPP_SCALE_STATUS);
+	mdp_dump_register(mdp, MDP_PPP_BLEND_STATUS);
+	mdp_dump_register(mdp, MDP_INTR_STATUS);
+	mdp_dump_register(mdp, MDP_INTR_ENABLE);
+}
+
+static int mdp_ppp_wait(struct mdp_info *mdp)
+{
+	int ret;
+
+	ret = mdp_wait(mdp, DL0_ROI_DONE, &mdp_ppp_waitqueue);
+	if (ret)
+		mdp_ppp_dump_debug(mdp);
+	return ret;
+}
+
+static int get_img(struct mdp_img *img, struct fb_info *info,
+		   unsigned long *start, unsigned long *len,
+		   struct file** filep)
+{
+	int put_needed, ret = 0;
+	struct file *file;
+	unsigned long vstart;
+
+	if (!get_pmem_file(img->memory_id, start, &vstart, len, filep))
+		return 0;
+	else if (!get_msm_hw3d_file(img->memory_id, &img->offset, start, len,
+				    filep))
+		return 0;
+
+	file = fget_light(img->memory_id, &put_needed);
+	if (file == NULL)
+		return -1;
+
+	if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
+		*start = info->fix.smem_start;
+		*len = info->fix.smem_len;
+		ret = 0;
+	} else
+		ret = -1;
+	fput_light(file, put_needed);
+
+	return ret;
+}
+
+static void put_img(struct file *file)
+{
+	if (file) {
+		if (is_pmem_file(file))
+			put_pmem_file(file);
+		else if (is_msm_hw3d_file(file))
+			put_msm_hw3d_file(file);
+	}
+}
+
+static void dump_req(struct mdp_blit_req *req,
+	unsigned long src_start, unsigned long src_len,
+	unsigned long dst_start, unsigned long dst_len)
+{
+	pr_err("flags: 0x%x\n",         req->flags);
+	pr_err("src_start:  0x%08lx\n", src_start);
+	pr_err("src_len:    0x%08lx\n", src_len);
+	pr_err("src.offset: 0x%x\n",    req->src.offset);
+	pr_err("src.format: 0x%x\n",    req->src.format);
+	pr_err("src.width:  %d\n",      req->src.width);
+	pr_err("src.height: %d\n",      req->src.height);
+	pr_err("src_rect.x: %d\n",      req->src_rect.x);
+	pr_err("src_rect.y: %d\n",      req->src_rect.y);
+	pr_err("src_rect.w: %d\n",      req->src_rect.w);
+	pr_err("src_rect.h: %d\n",      req->src_rect.h);
+
+	pr_err("dst_start:  0x%08lx\n", dst_start);
+	pr_err("dst_len:    0x%08lx\n", dst_len);
+	pr_err("dst.offset: 0x%x\n",    req->dst.offset);
+	pr_err("dst.format: 0x%x\n",    req->dst.format);
+	pr_err("dst.width:  %d\n",      req->dst.width);
+	pr_err("dst.height: %d\n",      req->dst.height);
+	pr_err("dst_rect.x: %d\n",      req->dst_rect.x);
+	pr_err("dst_rect.y: %d\n",      req->dst_rect.y);
+	pr_err("dst_rect.w: %d\n",      req->dst_rect.w);
+	pr_err("dst_rect.h: %d\n",      req->dst_rect.h);
+}
+
+int mdp_ppp_blit_and_wait(struct mdp_info *mdp, struct mdp_blit_req *req,
+		struct file *src_file, unsigned long src_start, unsigned long src_len,
+		struct file *dst_file, unsigned long dst_start, unsigned long dst_len)
+{
+	int ret;
+	mdp->enable_irq(mdp, DL0_ROI_DONE);
+	ret = process_blit(mdp, req, src_file, src_start, src_len,
+			   dst_file, dst_start, dst_len);
+	if (unlikely(ret)) {
+		mdp->disable_irq(mdp, DL0_ROI_DONE);
+		return ret;
+	}
+	ret = mdp_ppp_wait(mdp);
+	if (unlikely(ret)) {
+		printk(KERN_ERR "%s: failed!\n", __func__);
+		pr_err("original request:\n");
+		dump_req(mdp->req, src_start, src_len, dst_start, dst_len);
+		pr_err("dead request:\n");
+		dump_req(req, src_start, src_len, dst_start, dst_len);
+		BUG();
+		return ret;
+	}
+	return 0;
+}
+
+int mdp_ppp_blit(struct mdp_info *mdp, struct fb_info *fb,
+		 struct mdp_blit_req *req)
+{
+	int ret;
+	unsigned long src_start = 0, src_len = 0, dst_start = 0, dst_len = 0;
+	struct file *src_file = 0, *dst_file = 0;
+
+	ret = mdp_ppp_validate_blit(mdp, req);
+	if (ret)
+		return ret;
+
+	/* do this first so that if this fails, the caller can always
+	 * safely call put_img */
+	if (unlikely(get_img(&req->src, fb, &src_start, &src_len, &src_file))) {
+		printk(KERN_ERR "mdp_ppp: could not retrieve src image from "
+				"memory\n");
+		return -EINVAL;
+	}
+
+	if (unlikely(get_img(&req->dst, fb, &dst_start, &dst_len, &dst_file))) {
+		printk(KERN_ERR "mdp_ppp: could not retrieve dst image from "
+				"memory\n");
+		put_img(src_file);
+		return -EINVAL;
+	}
+	mutex_lock(&mdp_mutex);
+
+	/* transp_masking unimplemented */
+	req->transp_mask = MDP_TRANSP_NOP;
+	mdp->req = req;
+
+	ret = mdp_ppp_do_blit(mdp, req, src_file, src_start, src_len,
+			      dst_file, dst_start, dst_len);
+
+	put_img(src_file);
+	put_img(dst_file);
+	mutex_unlock(&mdp_mutex);
+	return ret;
+}
+
+void mdp_ppp_handle_isr(struct mdp_info *mdp, uint32_t mask)
+{
+	if (mask & DL0_ROI_DONE)
+		wake_up(&mdp_ppp_waitqueue);
+}
+
+
diff --git a/drivers/video/msm/mdp_ppp.h b/drivers/video/msm/mdp_ppp.h
new file mode 100644
index 0000000..03a1506
--- /dev/null
+++ b/drivers/video/msm/mdp_ppp.h
@@ -0,0 +1,118 @@
+/* drivers/video/msm/mdp_ppp.h
+ *
+ * Copyright (C) 2009 Google 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.
+ */
+
+#ifndef _VIDEO_MSM_MDP_PPP_H_
+#define _VIDEO_MSM_MDP_PPP_H_
+
+#include <linux/types.h>
+
+struct ppp_regs {
+	uint32_t src0;
+	uint32_t src1;
+	uint32_t dst0;
+	uint32_t dst1;
+	uint32_t src_cfg;
+	uint32_t dst_cfg;
+	uint32_t src_pack;
+	uint32_t dst_pack;
+	uint32_t src_rect;
+	uint32_t dst_rect;
+	uint32_t src_ystride;
+	uint32_t dst_ystride;
+	uint32_t op;
+	uint32_t src_bpp;
+	uint32_t dst_bpp;
+	uint32_t edge;
+	uint32_t phasex_init;
+	uint32_t phasey_init;
+	uint32_t phasex_step;
+	uint32_t phasey_step;
+
+	uint32_t bg0;
+	uint32_t bg1;
+	uint32_t bg_cfg;
+	uint32_t bg_bpp;
+	uint32_t bg_pack;
+	uint32_t bg_ystride;
+
+#ifdef CONFIG_MSM_MDP31
+	uint32_t src_xy;
+	uint32_t src_img_sz;
+	uint32_t dst_xy;
+	uint32_t bg_xy;
+	uint32_t bg_img_sz;
+	uint32_t bg_alpha_sel;
+
+	uint32_t scale_cfg;
+	uint32_t csc_cfg;
+#endif
+};
+
+struct mdp_info;
+struct mdp_rect;
+struct mdp_blit_req;
+struct fb_info;
+
+#ifdef CONFIG_FB_MSM_MDP_PPP
+int mdp_get_bytes_per_pixel(int format);
+int mdp_ppp_blit(struct mdp_info *mdp, struct fb_info *fb,
+		 struct mdp_blit_req *req);
+void mdp_ppp_handle_isr(struct mdp_info *mdp, uint32_t mask);
+int mdp_ppp_blit_and_wait(struct mdp_info *mdp, struct mdp_blit_req *req,
+			  struct file *src_file, unsigned long src_start,
+			  unsigned long src_len, struct file *dst_file,
+			  unsigned long dst_start, unsigned long dst_len);
+
+/* these must be provided by h/w specific ppp files */
+void mdp_ppp_init_scale(struct mdp_info *mdp);
+int mdp_ppp_cfg_scale(struct mdp_info *mdp, struct ppp_regs *regs,
+		 struct mdp_rect *src_rect, struct mdp_rect *dst_rect,
+		 uint32_t src_format, uint32_t dst_format);
+int mdp_ppp_load_blur(struct mdp_info *mdp);
+int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs);
+int mdp_ppp_validate_blit(struct mdp_info *mdp, struct mdp_blit_req *req);
+int mdp_ppp_do_blit(struct mdp_info *mdp, struct mdp_blit_req *req,
+		    struct file *src_file, unsigned long src_start,
+		    unsigned long src_len, struct file *dst_file,
+		    unsigned long dst_start, unsigned long dst_len);
+
+#else
+
+static inline int mdp_get_bytes_per_pixel(int format) { return -1; }
+static inline int mdp_ppp_blit(struct mdp_info *mdp, struct fb_info *fb,
+			       struct mdp_blit_req *req) { return -EINVAL; }
+static inline void mdp_ppp_handle_isr(struct mdp_info *mdp, uint32_t mask) {}
+static inline int mdp_ppp_blit_and_wait(struct mdp_info *mdp,
+		struct mdp_blit_req *req, struct file *src_file,
+		unsigned long src_start, unsigned long src_len,
+		struct file *dst_file, unsigned long dst_start,
+		unsigned long dst_len) { return 0; }
+
+static inline void mdp_ppp_init_scale(struct mdp_info *mdp) {}
+static inline int mdp_ppp_cfg_scale(struct mdp_info *mdp, struct ppp_regs *regs,
+		 struct mdp_rect *src_rect, struct mdp_rect *dst_rect,
+		 uint32_t src_format, uint32_t dst_format) { return 0; }
+static inline int mdp_ppp_load_blur(struct mdp_info *mdp) { return 0; }
+static inline int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs) { return 0; }
+static inline int mdp_ppp_validate_blit(struct mdp_info *mdp, struct mdp_blit_req *req) { return -EINVAL; }
+static inline int mdp_ppp_do_blit(struct mdp_info *mdp,
+		struct mdp_blit_req *req,
+		struct file *src_file, unsigned long src_start,
+		unsigned long src_len, struct file *dst_file,
+		unsigned long dst_start, unsigned long dst_len) { return 0; }
+
+
+#endif /* CONFIG_FB_MSM_MDP_PPP */
+
+#endif /* _VIDEO_MSM_MDP_PPP_H_ */
diff --git a/drivers/video/msm/mdp_scale_tables.c b/drivers/video/msm/mdp_ppp22.c
similarity index 65%
rename from drivers/video/msm/mdp_scale_tables.c
rename to drivers/video/msm/mdp_ppp22.c
index 604783b..dc4cc27 100644
--- a/drivers/video/msm/mdp_scale_tables.c
+++ b/drivers/video/msm/mdp_ppp22.c
@@ -1,4 +1,4 @@
-/* drivers/video/msm_fb/mdp_scale_tables.c
+/* drivers/video/msm/mdp_ppp22.c
  *
  * Copyright (C) 2007 QUALCOMM Incorporated
  * Copyright (C) 2007 Google Incorporated
@@ -13,10 +13,33 @@
  * GNU General Public License for more details.
  */
 
-#include "mdp_scale_tables.h"
-#include "mdp_hw.h"
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/msm_mdp.h>
 
-struct mdp_table_entry mdp_upscale_table[] = {
+#include "mdp_hw.h"
+#include "mdp_ppp.h"
+
+struct mdp_table_entry {
+	uint32_t reg;
+	uint32_t val;
+};
+
+enum {
+	MDP_DOWNSCALE_PT2TOPT4,
+	MDP_DOWNSCALE_PT4TOPT6,
+	MDP_DOWNSCALE_PT6TOPT8,
+	MDP_DOWNSCALE_PT8TO1,
+	MDP_DOWNSCALE_MAX,
+
+	/* not technically in the downscale table list */
+	MDP_DOWNSCALE_BLUR,
+};
+
+static int downscale_x_table;
+static int downscale_y_table;
+
+static struct mdp_table_entry mdp_upscale_table[] = {
 	{ 0x5fffc, 0x0 },
 	{ 0x50200, 0x7fc00000 },
 	{ 0x5fffc, 0xff80000d },
@@ -764,3 +787,359 @@
 	{ 0x5fffc, 0x20000080 },
 	{ 0x5037c, 0x20000080 },
 };
+
+static void load_table(const struct mdp_info *mdp,
+		       struct mdp_table_entry *table, int len)
+{
+	int i;
+	for (i = 0; i < len; i++)
+		mdp_writel(mdp, table[i].val, table[i].reg);
+}
+
+enum {
+	IMG_LEFT,
+	IMG_RIGHT,
+	IMG_TOP,
+	IMG_BOTTOM,
+};
+
+static void get_edge_info(uint32_t src, uint32_t src_coord, uint32_t dst,
+			  uint32_t *interp1, uint32_t *interp2,
+			  uint32_t *repeat1, uint32_t *repeat2) {
+	if (src > 3 * dst) {
+		*interp1 = 0;
+		*interp2 = src - 1;
+		*repeat1 = 0;
+		*repeat2 = 0;
+	} else if (src == 3 * dst) {
+		*interp1 = 0;
+		*interp2 = src;
+		*repeat1 = 0;
+		*repeat2 = 1;
+	} else if (src > dst && src < 3 * dst) {
+		*interp1 = -1;
+		*interp2 = src;
+		*repeat1 = 1;
+		*repeat2 = 1;
+	} else if (src == dst) {
+		*interp1 = -1;
+		*interp2 = src + 1;
+		*repeat1 = 1;
+		*repeat2 = 2;
+	} else {
+		*interp1 = -2;
+		*interp2 = src + 1;
+		*repeat1 = 2;
+		*repeat2 = 2;
+	}
+	*interp1 += src_coord;
+	*interp2 += src_coord;
+}
+
+int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs)
+{
+	int32_t luma_interp[4];
+	int32_t luma_repeat[4];
+	int32_t chroma_interp[4];
+	int32_t chroma_bound[4];
+	int32_t chroma_repeat[4];
+	uint32_t dst_w, dst_h;
+
+	memset(&luma_interp, 0, sizeof(int32_t) * 4);
+	memset(&luma_repeat, 0, sizeof(int32_t) * 4);
+	memset(&chroma_interp, 0, sizeof(int32_t) * 4);
+	memset(&chroma_bound, 0, sizeof(int32_t) * 4);
+	memset(&chroma_repeat, 0, sizeof(int32_t) * 4);
+	regs->edge = 0;
+
+	if (req->flags & MDP_ROT_90) {
+		dst_w = req->dst_rect.h;
+		dst_h = req->dst_rect.w;
+	} else {
+		dst_w = req->dst_rect.w;
+		dst_h = req->dst_rect.h;
+	}
+
+	if (regs->op & (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON)) {
+		get_edge_info(req->src_rect.h, req->src_rect.y, dst_h,
+			      &luma_interp[IMG_TOP], &luma_interp[IMG_BOTTOM],
+			      &luma_repeat[IMG_TOP], &luma_repeat[IMG_BOTTOM]);
+		get_edge_info(req->src_rect.w, req->src_rect.x, dst_w,
+			      &luma_interp[IMG_LEFT], &luma_interp[IMG_RIGHT],
+			      &luma_repeat[IMG_LEFT], &luma_repeat[IMG_RIGHT]);
+	} else {
+		luma_interp[IMG_LEFT] = req->src_rect.x;
+		luma_interp[IMG_RIGHT] = req->src_rect.x + req->src_rect.w - 1;
+		luma_interp[IMG_TOP] = req->src_rect.y;
+		luma_interp[IMG_BOTTOM] = req->src_rect.y + req->src_rect.h - 1;
+		luma_repeat[IMG_LEFT] = 0;
+		luma_repeat[IMG_TOP] = 0;
+		luma_repeat[IMG_RIGHT] = 0;
+		luma_repeat[IMG_BOTTOM] = 0;
+	}
+
+	chroma_interp[IMG_LEFT] = luma_interp[IMG_LEFT];
+	chroma_interp[IMG_RIGHT] = luma_interp[IMG_RIGHT];
+	chroma_interp[IMG_TOP] = luma_interp[IMG_TOP];
+	chroma_interp[IMG_BOTTOM] = luma_interp[IMG_BOTTOM];
+
+	chroma_bound[IMG_LEFT] = req->src_rect.x;
+	chroma_bound[IMG_RIGHT] = req->src_rect.x + req->src_rect.w - 1;
+	chroma_bound[IMG_TOP] = req->src_rect.y;
+	chroma_bound[IMG_BOTTOM] = req->src_rect.y + req->src_rect.h - 1;
+
+	if (IS_YCRCB(req->src.format)) {
+		chroma_interp[IMG_LEFT] = chroma_interp[IMG_LEFT] >> 1;
+		chroma_interp[IMG_RIGHT] = (chroma_interp[IMG_RIGHT] + 1) >> 1;
+
+		chroma_bound[IMG_LEFT] = chroma_bound[IMG_LEFT] >> 1;
+		chroma_bound[IMG_RIGHT] = chroma_bound[IMG_RIGHT] >> 1;
+	}
+
+	if (req->src.format == MDP_Y_CBCR_H2V2 ||
+	    req->src.format == MDP_Y_CRCB_H2V2) {
+		chroma_interp[IMG_TOP] = (chroma_interp[IMG_TOP] - 1) >> 1;
+		chroma_interp[IMG_BOTTOM] = (chroma_interp[IMG_BOTTOM] + 1)
+					    >> 1;
+		chroma_bound[IMG_TOP] = (chroma_bound[IMG_TOP] + 1) >> 1;
+		chroma_bound[IMG_BOTTOM] = chroma_bound[IMG_BOTTOM] >> 1;
+	}
+
+	chroma_repeat[IMG_LEFT] = chroma_bound[IMG_LEFT] -
+				  chroma_interp[IMG_LEFT];
+	chroma_repeat[IMG_RIGHT] = chroma_interp[IMG_RIGHT] -
+				  chroma_bound[IMG_RIGHT];
+	chroma_repeat[IMG_TOP] = chroma_bound[IMG_TOP] -
+				  chroma_interp[IMG_TOP];
+	chroma_repeat[IMG_BOTTOM] = chroma_interp[IMG_BOTTOM] -
+				  chroma_bound[IMG_BOTTOM];
+
+	if (chroma_repeat[IMG_LEFT] < 0 || chroma_repeat[IMG_LEFT] > 3 ||
+	    chroma_repeat[IMG_RIGHT] < 0 || chroma_repeat[IMG_RIGHT] > 3 ||
+	    chroma_repeat[IMG_TOP] < 0 || chroma_repeat[IMG_TOP] > 3 ||
+	    chroma_repeat[IMG_BOTTOM] < 0 || chroma_repeat[IMG_BOTTOM] > 3 ||
+	    luma_repeat[IMG_LEFT] < 0 || luma_repeat[IMG_LEFT] > 3 ||
+	    luma_repeat[IMG_RIGHT] < 0 || luma_repeat[IMG_RIGHT] > 3 ||
+	    luma_repeat[IMG_TOP] < 0 || luma_repeat[IMG_TOP] > 3 ||
+	    luma_repeat[IMG_BOTTOM] < 0 || luma_repeat[IMG_BOTTOM] > 3)
+		return -1;
+
+	regs->edge |= (chroma_repeat[IMG_LEFT] & 3) << MDP_LEFT_CHROMA;
+	regs->edge |= (chroma_repeat[IMG_RIGHT] & 3) << MDP_RIGHT_CHROMA;
+	regs->edge |= (chroma_repeat[IMG_TOP] & 3) << MDP_TOP_CHROMA;
+	regs->edge |= (chroma_repeat[IMG_BOTTOM] & 3) << MDP_BOTTOM_CHROMA;
+	regs->edge |= (luma_repeat[IMG_LEFT] & 3) << MDP_LEFT_LUMA;
+	regs->edge |= (luma_repeat[IMG_RIGHT] & 3) << MDP_RIGHT_LUMA;
+	regs->edge |= (luma_repeat[IMG_TOP] & 3) << MDP_TOP_LUMA;
+	regs->edge |= (luma_repeat[IMG_BOTTOM] & 3) << MDP_BOTTOM_LUMA;
+	return 0;
+}
+
+#define ONE_HALF	(1LL << 32)
+#define ONE		(1LL << 33)
+#define TWO		(2LL << 33)
+#define THREE		(3LL << 33)
+#define FRAC_MASK (ONE - 1)
+#define INT_MASK (~FRAC_MASK)
+
+static int scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t origin,
+			uint32_t *phase_init, uint32_t *phase_step)
+{
+	/* to improve precicsion calculations are done in U31.33 and converted
+	 * to U3.29 at the end */
+	int64_t k1, k2, k3, k4, tmp;
+	uint64_t n, d, os, os_p, od, od_p, oreq;
+	unsigned rpa = 0;
+	int64_t ip64, delta;
+
+	if (dim_out % 3 == 0)
+		rpa = !(dim_in % (dim_out / 3));
+
+	n = ((uint64_t)dim_out) << 34;
+	d = dim_in;
+	if (!d)
+		return -1;
+	do_div(n, d);
+	k3 = (n + 1) >> 1;
+	if ((k3 >> 4) < (1LL << 27) || (k3 >> 4) > (1LL << 31))
+		return -1;
+
+	n = ((uint64_t)dim_in) << 34;
+	d = (uint64_t)dim_out;
+	if (!d)
+		return -1;
+	do_div(n, d);
+	k1 = (n + 1) >> 1;
+	k2 = (k1 - ONE) >> 1;
+
+	*phase_init = (int)(k2 >> 4);
+	k4 = (k3 - ONE) >> 1;
+
+	if (rpa) {
+		os = ((uint64_t)origin << 33) - ONE_HALF;
+		tmp = (dim_out * os) + ONE_HALF;
+		if (!dim_in)
+			return -1;
+		do_div(tmp, dim_in);
+		od = tmp - ONE_HALF;
+	} else {
+		os = ((uint64_t)origin << 1) - 1;
+		od = (((k3 * os) >> 1) + k4);
+	}
+
+	od_p = od & INT_MASK;
+	if (od_p != od)
+		od_p += ONE;
+
+	if (rpa) {
+		tmp = (dim_in * od_p) + ONE_HALF;
+		if (!dim_in)
+			return -1;
+		do_div(tmp, dim_in);
+		os_p = tmp - ONE_HALF;
+	} else {
+		os_p = ((k1 * (od_p >> 33)) + k2);
+	}
+
+	oreq = (os_p & INT_MASK) - ONE;
+
+	ip64 = os_p - oreq;
+	delta = ((int64_t)(origin) << 33) - oreq;
+	ip64 -= delta;
+	/* limit to valid range before the left shift */
+	delta = (ip64 & (1LL << 63)) ? 4 : -4;
+	delta <<= 33;
+	while (abs((int)(ip64 >> 33)) > 4)
+		ip64 += delta;
+	*phase_init = (int)(ip64 >> 4);
+	*phase_step = (uint32_t)(k1 >> 4);
+	return 0;
+}
+
+int mdp_ppp_cfg_scale(struct mdp_info *mdp, struct ppp_regs *regs,
+		      struct mdp_rect *src_rect, struct mdp_rect *dst_rect,
+		      uint32_t src_format, uint32_t dst_format)
+{
+	int downscale;
+	uint32_t phase_init_x, phase_init_y, phase_step_x, phase_step_y;
+	uint32_t scale_factor_x, scale_factor_y;
+
+	if (scale_params(src_rect->w, dst_rect->w, 1, &phase_init_x,
+			 &phase_step_x) ||
+	    scale_params(src_rect->h, dst_rect->h, 1, &phase_init_y,
+			 &phase_step_y))
+		return -1;
+
+	regs->phasex_init = phase_init_x;
+	regs->phasey_init = phase_init_y;
+	regs->phasex_step = phase_step_x;
+	regs->phasey_step = phase_step_y;
+
+	scale_factor_x = (dst_rect->w * 10) / src_rect->w;
+	scale_factor_y = (dst_rect->h * 10) / src_rect->h;
+
+	if (scale_factor_x > 8)
+		downscale = MDP_DOWNSCALE_PT8TO1;
+	else if (scale_factor_x > 6)
+		downscale = MDP_DOWNSCALE_PT6TOPT8;
+	else if (scale_factor_x > 4)
+		downscale = MDP_DOWNSCALE_PT4TOPT6;
+	else
+		downscale = MDP_DOWNSCALE_PT2TOPT4;
+
+	if (downscale != downscale_x_table) {
+		load_table(mdp, mdp_downscale_x_table[downscale], 64);
+		downscale_x_table = downscale;
+	}
+
+	if (scale_factor_y > 8)
+		downscale = MDP_DOWNSCALE_PT8TO1;
+	else if (scale_factor_y > 6)
+		downscale = MDP_DOWNSCALE_PT6TOPT8;
+	else if (scale_factor_y > 4)
+		downscale = MDP_DOWNSCALE_PT4TOPT6;
+	else
+		downscale = MDP_DOWNSCALE_PT2TOPT4;
+
+	if (downscale != downscale_y_table) {
+		load_table(mdp, mdp_downscale_y_table[downscale], 64);
+		downscale_y_table = downscale;
+	}
+
+	return 0;
+}
+
+
+int mdp_ppp_load_blur(struct mdp_info *mdp)
+{
+	if (!(downscale_x_table == MDP_DOWNSCALE_BLUR &&
+              downscale_y_table == MDP_DOWNSCALE_BLUR)) {
+		load_table(mdp, mdp_gaussian_blur_table, 128);
+		downscale_x_table = MDP_DOWNSCALE_BLUR;
+		downscale_y_table = MDP_DOWNSCALE_BLUR;
+	}
+
+	return 0;
+}
+
+void mdp_ppp_init_scale(struct mdp_info *mdp)
+{
+	downscale_x_table = MDP_DOWNSCALE_MAX;
+	downscale_y_table = MDP_DOWNSCALE_MAX;
+
+	load_table(mdp, mdp_upscale_table, ARRAY_SIZE(mdp_upscale_table));
+}
+
+int mdp_ppp_validate_blit(struct mdp_info *mdp, struct mdp_blit_req *req)
+{
+	/* WORKAROUND FOR HARDWARE BUG IN BG TILE FETCH */
+	if (unlikely(req->src_rect.h == 0 ||
+		     req->src_rect.w == 0)) {
+		pr_info("mdp_ppp: src img of zero size!\n");
+		return -EINVAL;
+	}
+	if (unlikely(req->dst_rect.h == 0 ||
+		     req->dst_rect.w == 0))
+		return -EINVAL;
+
+	return 0;
+}
+
+int mdp_ppp_do_blit(struct mdp_info *mdp, struct mdp_blit_req *req,
+		   struct file *src_file, unsigned long src_start,
+		   unsigned long src_len, struct file *dst_file,
+		   unsigned long dst_start, unsigned long dst_len)
+{
+	int ret;
+
+	if (unlikely((req->transp_mask != MDP_TRANSP_NOP ||
+		      req->alpha != MDP_ALPHA_NOP ||
+		      HAS_ALPHA(req->src.format)) &&
+		     (req->flags & MDP_ROT_90 &&
+		      req->dst_rect.w <= 16 && req->dst_rect.h >= 16))) {
+		int i;
+		unsigned int tiles = req->dst_rect.h / 16;
+		unsigned int remainder = req->dst_rect.h % 16;
+		req->src_rect.w = 16*req->src_rect.w / req->dst_rect.h;
+		req->dst_rect.h = 16;
+		for (i = 0; i < tiles; i++) {
+			ret = mdp_ppp_blit_and_wait(mdp, req,
+						src_file, src_start, src_len,
+						dst_file, dst_start, dst_len);
+			if (ret)
+				goto end;
+			req->dst_rect.y += 16;
+			req->src_rect.x += req->src_rect.w;
+		}
+		if (!remainder)
+			goto end;
+		req->src_rect.w = remainder*req->src_rect.w / req->dst_rect.h;
+		req->dst_rect.h = remainder;
+	}
+
+	ret = mdp_ppp_blit_and_wait(mdp, req,
+				src_file, src_start, src_len,
+				dst_file, dst_start, dst_len);
+end:
+	return ret;
+}
diff --git a/drivers/video/msm/mdp_ppp31.c b/drivers/video/msm/mdp_ppp31.c
new file mode 100644
index 0000000..da4bb02
--- /dev/null
+++ b/drivers/video/msm/mdp_ppp31.c
@@ -0,0 +1,637 @@
+/* drivers/video/msm/mdp_ppp31.c
+ *
+ * Copyright (C) 2009 QUALCOMM Incorporated
+ * Copyright (C) 2009 Google 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/errno.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/msm_mdp.h>
+
+#include "mdp_hw.h"
+#include "mdp_ppp.h"
+
+#define NUM_COEFFS			32
+
+struct mdp_scale_coeffs {
+	uint16_t	c[4][NUM_COEFFS];
+};
+
+struct mdp_scale_tbl_info {
+	uint16_t			offset;
+	uint32_t			set:2;
+	int				use_pr;
+	struct mdp_scale_coeffs		coeffs;
+};
+
+enum {
+	MDP_SCALE_PT2TOPT4,
+	MDP_SCALE_PT4TOPT6,
+	MDP_SCALE_PT6TOPT8,
+	MDP_SCALE_PT8TO8,
+	MDP_SCALE_MAX,
+};
+
+static struct mdp_scale_coeffs mdp_scale_pr_coeffs = {
+	.c = {
+		[0] = {
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+		},
+		[1] = {
+			511, 511, 511, 511, 511, 511, 511, 511,
+			511, 511, 511, 511, 511, 511, 511, 511,
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+		},
+		[2] = {
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+			511, 511, 511, 511, 511, 511, 511, 511,
+			511, 511, 511, 511, 511, 511, 511, 511,
+		},
+		[3] = {
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	},
+};
+
+static struct mdp_scale_tbl_info mdp_scale_tbl[MDP_SCALE_MAX] = {
+	[ MDP_SCALE_PT2TOPT4 ]	= {
+		.offset		= 0,
+		.set		= MDP_PPP_SCALE_COEFF_D0_SET,
+		.use_pr		= -1,
+		.coeffs.c	= {
+			[0] = {
+				131, 131, 130, 129, 128, 127, 127, 126,
+				125, 125, 124, 123, 123, 121, 120, 119,
+				119, 118, 117, 117, 116, 115, 115, 114,
+				113, 112, 111, 110, 109, 109, 108, 107,
+			},
+			[1] = {
+				141, 140, 140, 140, 140, 139, 138, 138,
+				138, 137, 137, 137, 136, 137, 137, 137,
+				136, 136, 136, 135, 135, 135, 134, 134,
+				134, 134, 134, 133, 133, 132, 132, 132,
+			},
+			[2] = {
+				132, 132, 132, 133, 133, 134, 134, 134,
+				134, 134, 135, 135, 135, 136, 136, 136,
+				137, 137, 137, 136, 137, 137, 137, 138,
+				138, 138, 139, 140, 140, 140, 140, 141,
+			},
+			[3] = {
+				107, 108, 109, 109, 110, 111, 112, 113,
+				114, 115, 115, 116, 117, 117, 118, 119,
+				119, 120, 121, 123, 123, 124, 125, 125,
+				126, 127, 127, 128, 129, 130, 131, 131,
+			}
+		},
+	},
+	[ MDP_SCALE_PT4TOPT6 ] = {
+		.offset		= 32,
+		.set		= MDP_PPP_SCALE_COEFF_D1_SET,
+		.use_pr		= -1,
+		.coeffs.c	= {
+			[0] = {
+				136, 132, 128, 123, 119, 115, 111, 107,
+				103, 98, 95, 91, 87, 84, 80, 76,
+				73, 69, 66, 62, 59, 57, 54, 50,
+				47, 44, 41, 39, 36, 33, 32, 29,
+			},
+			[1] = {
+				206, 205, 204, 204, 201, 200, 199, 197,
+				196, 194, 191, 191, 189, 185, 184, 182,
+				180, 178, 176, 173, 170, 168, 165, 162,
+				160, 157, 155, 152, 148, 146, 142, 140,
+			},
+			[2] = {
+				140, 142, 146, 148, 152, 155, 157, 160,
+				162, 165, 168, 170, 173, 176, 178, 180,
+				182, 184, 185, 189, 191, 191, 194, 196,
+				197, 199, 200, 201, 204, 204, 205, 206,
+			},
+			[3] = {
+				29, 32, 33, 36, 39, 41, 44, 47,
+				50, 54, 57, 59, 62, 66, 69, 73,
+				76, 80, 84, 87, 91, 95, 98, 103,
+				107, 111, 115, 119, 123, 128, 132, 136,
+			},
+		},
+	},
+	[ MDP_SCALE_PT6TOPT8 ] = {
+		.offset		= 64,
+		.set		= MDP_PPP_SCALE_COEFF_D2_SET,
+		.use_pr		= -1,
+		.coeffs.c	= {
+			[0] = {
+				104, 96, 89, 82, 75, 68, 61, 55,
+				49, 43, 38, 33, 28, 24, 20, 16,
+				12, 9, 6, 4, 2, 0, -2, -4,
+				-5, -6, -7, -7, -8, -8, -8, -8,
+			},
+			[1] = {
+				303, 303, 302, 300, 298, 296, 293, 289,
+				286, 281, 276, 270, 265, 258, 252, 245,
+				238, 230, 223, 214, 206, 197, 189, 180,
+				172, 163, 154, 145, 137, 128, 120, 112,
+			},
+			[2] = {
+				112, 120, 128, 137, 145, 154, 163, 172,
+				180, 189, 197, 206, 214, 223, 230, 238,
+				245, 252, 258, 265, 270, 276, 281, 286,
+				289, 293, 296, 298, 300, 302, 303, 303,
+			},
+			[3] = {
+				-8, -8, -8, -8, -7, -7, -6, -5,
+				-4, -2, 0, 2, 4, 6, 9, 12,
+				16, 20, 24, 28, 33, 38, 43, 49,
+				55, 61, 68, 75, 82, 89, 96, 104,
+			},
+		},
+	},
+	[ MDP_SCALE_PT8TO8 ] = {
+		.offset		= 96,
+		.set		= MDP_PPP_SCALE_COEFF_U1_SET,
+		.use_pr		= -1,
+		.coeffs.c	= {
+			[0] = {
+				0, -7, -13, -19, -24, -28, -32, -34,
+				-37, -39, -40, -41, -41, -41, -40, -40,
+				-38, -37, -35, -33, -31, -29, -26, -24,
+				-21, -18, -15, -13, -10, -7, -5, -2,
+			},
+			[1] = {
+				511, 507, 501, 494, 485, 475, 463, 450,
+				436, 422, 405, 388, 370, 352, 333, 314,
+				293, 274, 253, 233, 213, 193, 172, 152,
+				133, 113, 95, 77, 60, 43, 28, 13,
+			},
+			[2] = {
+				0, 13, 28, 43, 60, 77, 95, 113,
+				133, 152, 172, 193, 213, 233, 253, 274,
+				294, 314, 333, 352, 370, 388, 405, 422,
+				436, 450, 463, 475, 485, 494, 501, 507,
+			},
+			[3] = {
+				0, -2, -5, -7, -10, -13, -15, -18,
+				-21, -24, -26, -29, -31, -33, -35, -37,
+				-38, -40, -40, -41, -41, -41, -40, -39,
+				-37, -34, -32, -28, -24, -19, -13, -7,
+			},
+		},
+	},
+};
+
+static void load_table(const struct mdp_info *mdp, int scale, int use_pr)
+{
+	int i;
+	uint32_t val;
+	struct mdp_scale_coeffs *coeffs;
+	struct mdp_scale_tbl_info *tbl = &mdp_scale_tbl[scale];
+
+	if (use_pr == tbl->use_pr)
+		return;
+
+	tbl->use_pr = use_pr;
+	if (!use_pr)
+		coeffs = &tbl->coeffs;
+	else
+		coeffs = &mdp_scale_pr_coeffs;
+
+	for (i = 0; i < NUM_COEFFS; ++i) {
+		val = ((coeffs->c[1][i] & 0x3ff) << 16) |
+			(coeffs->c[0][i] & 0x3ff);
+		mdp_writel(mdp, val, MDP_PPP_SCALE_COEFF_LSBn(tbl->offset + i));
+
+		val = ((coeffs->c[3][i] & 0x3ff) << 16) |
+			(coeffs->c[2][i] & 0x3ff);
+		mdp_writel(mdp, val, MDP_PPP_SCALE_COEFF_MSBn(tbl->offset + i));
+	}
+}
+
+#define SCALER_PHASE_BITS		29
+static void scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t scaler,
+			 uint32_t *phase_init, uint32_t *phase_step)
+{
+	uint64_t src = dim_in;
+	uint64_t dst = dim_out;
+	uint64_t numer;
+	uint64_t denom;
+
+	*phase_init = 0;
+
+	if (dst == 1) {
+		/* if destination is 1 pixel wide, the value of phase_step
+		 * is unimportant. */
+		*phase_step = (uint32_t) (src << SCALER_PHASE_BITS);
+		if (scaler == MDP_PPP_SCALER_FIR)
+			*phase_init =
+				(uint32_t) ((src - 1) << SCALER_PHASE_BITS);
+		return;
+	}
+
+	if (scaler == MDP_PPP_SCALER_FIR) {
+		numer = (src - 1) << SCALER_PHASE_BITS;
+		denom = dst - 1;
+		/* we want to round up the result*/
+		numer += denom - 1;
+	} else {
+		numer = src << SCALER_PHASE_BITS;
+		denom = dst;
+	}
+
+	do_div(numer, denom);
+	*phase_step = (uint32_t) numer;
+}
+
+static int scale_idx(int factor)
+{
+	int idx;
+
+	if (factor > 80)
+		idx = MDP_SCALE_PT8TO8;
+	else if (factor > 60)
+		idx = MDP_SCALE_PT6TOPT8;
+	else if (factor > 40)
+		idx = MDP_SCALE_PT4TOPT6;
+	else
+		idx = MDP_SCALE_PT2TOPT4;
+
+	return idx;
+}
+
+int mdp_ppp_cfg_scale(struct mdp_info *mdp, struct ppp_regs *regs,
+		      struct mdp_rect *src_rect, struct mdp_rect *dst_rect,
+		      uint32_t src_format, uint32_t dst_format)
+{
+	uint32_t x_fac;
+	uint32_t y_fac;
+	uint32_t scaler_x = MDP_PPP_SCALER_FIR;
+	uint32_t scaler_y = MDP_PPP_SCALER_FIR;
+	// Don't use pixel repeat mode, it looks bad
+	int use_pr = 0;
+	int x_idx;
+	int y_idx;
+
+	if (unlikely(src_rect->w > 2048 || src_rect->h > 2048))
+		return -ENOTSUPP;
+
+	x_fac = (dst_rect->w * 100) / src_rect->w;
+	y_fac = (dst_rect->h * 100) / src_rect->h;
+
+	/* if down-scaling by a factor smaller than 1/4, use M/N */
+	scaler_x = x_fac <= 25 ? MDP_PPP_SCALER_MN : MDP_PPP_SCALER_FIR;
+	scaler_y = y_fac <= 25 ? MDP_PPP_SCALER_MN : MDP_PPP_SCALER_FIR;
+	scale_params(src_rect->w, dst_rect->w, scaler_x, &regs->phasex_init,
+		     &regs->phasex_step);
+	scale_params(src_rect->h, dst_rect->h, scaler_y, &regs->phasey_init,
+		     &regs->phasey_step);
+
+	x_idx = scale_idx(x_fac);
+	y_idx = scale_idx(y_fac);
+	load_table(mdp, x_idx, use_pr);
+	load_table(mdp, y_idx, use_pr);
+
+	regs->scale_cfg = 0;
+	// Enable SVI when source or destination is YUV
+	if (!IS_RGB(src_format) && !IS_RGB(dst_format))
+		regs->scale_cfg |= (1 << 6);
+	regs->scale_cfg |= (mdp_scale_tbl[x_idx].set << 2) |
+		(mdp_scale_tbl[x_idx].set << 4);
+	regs->scale_cfg |= (scaler_x << 0) | (scaler_y << 1);
+
+	return 0;
+}
+
+int mdp_ppp_load_blur(struct mdp_info *mdp)
+{
+	return -ENOTSUPP;
+}
+
+int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs)
+{
+	return 0;
+}
+
+void mdp_ppp_init_scale(struct mdp_info *mdp)
+{
+	int scale;
+	for (scale = 0; scale < MDP_SCALE_MAX; ++scale)
+		load_table(mdp, scale, 0);
+}
+
+/* Splits a blit into two horizontal stripes.  Used to work around MDP bugs */
+static int blit_split_height(struct mdp_info *mdp, const struct mdp_blit_req *req,
+	struct file *src_file, unsigned long src_start, unsigned long src_len,
+	struct file *dst_file, unsigned long dst_start, unsigned long dst_len)
+{
+	int ret;
+	struct mdp_blit_req splitreq;
+	int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1;
+	int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1;
+
+	splitreq = *req;
+	/* break dest roi at height*/
+	d_x_0 = d_x_1 = req->dst_rect.x;
+	d_w_0 = d_w_1 = req->dst_rect.w;
+	d_y_0 = req->dst_rect.y;
+	if (req->dst_rect.h % 32 == 3)
+		d_h_1 = (req->dst_rect.h - 3) / 2 - 1;
+	else
+		d_h_1 = (req->dst_rect.h - 1) / 2 - 1;
+	d_h_0 = req->dst_rect.h - d_h_1;
+	d_y_1 = d_y_0 + d_h_0;
+	if (req->dst_rect.h == 3) {
+		d_h_1 = 2;
+		d_h_0 = 2;
+		d_y_1 = d_y_0 + 1;
+	}
+	/* break source roi */
+	if (splitreq.flags & MDP_ROT_90) {
+		s_y_0 = s_y_1 = req->src_rect.y;
+		s_h_0 = s_h_1 = req->src_rect.h;
+		s_x_0 = req->src_rect.x;
+		s_w_1 = (req->src_rect.w * d_h_1) / req->dst_rect.h;
+		s_w_0 = req->src_rect.w - s_w_1;
+		s_x_1 = s_x_0 + s_w_0;
+		if (d_h_1 >= 8 * s_w_1) {
+			s_w_1++;
+			s_x_1--;
+		}
+	} else {
+		s_x_0 = s_x_1 = req->src_rect.x;
+		s_w_0 = s_w_1 = req->src_rect.w;
+		s_y_0 = req->src_rect.y;
+		s_h_1 = (req->src_rect.h * d_h_1) / req->dst_rect.h;
+		s_h_0 = req->src_rect.h - s_h_1;
+		s_y_1 = s_y_0 + s_h_0;
+		if (d_h_1 >= 8 * s_h_1) {
+			s_h_1++;
+			s_y_1--;
+		}
+	}
+
+	/* blit first region */
+	if (((splitreq.flags & MDP_ROT_MASK) == MDP_ROT_90) ||
+		((splitreq.flags & MDP_ROT_MASK) == 0x0)) {
+		splitreq.src_rect.h = s_h_0;
+		splitreq.src_rect.y = s_y_0;
+		splitreq.dst_rect.h = d_h_0;
+		splitreq.dst_rect.y = d_y_0;
+		splitreq.src_rect.x = s_x_0;
+		splitreq.src_rect.w = s_w_0;
+		splitreq.dst_rect.x = d_x_0;
+		splitreq.dst_rect.w = d_w_0;
+	} else {
+		splitreq.src_rect.h = s_h_0;
+		splitreq.src_rect.y = s_y_0;
+		splitreq.dst_rect.h = d_h_1;
+		splitreq.dst_rect.y = d_y_1;
+		splitreq.src_rect.x = s_x_0;
+		splitreq.src_rect.w = s_w_0;
+		splitreq.dst_rect.x = d_x_1;
+		splitreq.dst_rect.w = d_w_1;
+	}
+	ret = mdp_ppp_blit_and_wait(mdp, &splitreq,
+		src_file, src_start, src_len,
+		dst_file, dst_start, dst_len);
+	if (ret)
+		return ret;
+
+	/* blit second region */
+	if (((splitreq.flags & MDP_ROT_MASK) == MDP_ROT_90) ||
+		((splitreq.flags & MDP_ROT_MASK) == 0x0)) {
+		splitreq.src_rect.h = s_h_1;
+		splitreq.src_rect.y = s_y_1;
+		splitreq.dst_rect.h = d_h_1;
+		splitreq.dst_rect.y = d_y_1;
+		splitreq.src_rect.x = s_x_1;
+		splitreq.src_rect.w = s_w_1;
+		splitreq.dst_rect.x = d_x_1;
+		splitreq.dst_rect.w = d_w_1;
+	} else {
+		splitreq.src_rect.h = s_h_1;
+		splitreq.src_rect.y = s_y_1;
+		splitreq.dst_rect.h = d_h_0;
+		splitreq.dst_rect.y = d_y_0;
+		splitreq.src_rect.x = s_x_1;
+		splitreq.src_rect.w = s_w_1;
+		splitreq.dst_rect.x = d_x_0;
+		splitreq.dst_rect.w = d_w_0;
+	}
+	ret = mdp_ppp_blit_and_wait(mdp, &splitreq,
+		src_file, src_start, src_len,
+		dst_file, dst_start, dst_len);
+	return ret;
+}
+
+/* Splits a blit into two vertical stripes.  Used to work around MDP bugs */
+static int blit_split_width(struct mdp_info *mdp, const struct mdp_blit_req *req,
+	struct file *src_file, unsigned long src_start, unsigned long src_len,
+	struct file *dst_file, unsigned long dst_start, unsigned long dst_len)
+{
+	int ret;
+	struct mdp_blit_req splitreq;
+	int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1;
+	int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1;
+	splitreq = *req;
+
+	/* break dest roi at width*/
+	d_y_0 = d_y_1 = req->dst_rect.y;
+	d_h_0 = d_h_1 = req->dst_rect.h;
+	d_x_0 = req->dst_rect.x;
+	if (req->dst_rect.w % 32 == 6)
+		d_w_1 = req->dst_rect.w / 2 - 1;
+	else if (req->dst_rect.w % 2 == 0)
+		d_w_1 = req->dst_rect.w / 2;
+	else if (req->dst_rect.w % 32 == 3)
+		d_w_1 = (req->dst_rect.w - 3) / 2 - 1;
+	else
+		d_w_1 = (req->dst_rect.w - 1) / 2 - 1;
+	d_w_0 = req->dst_rect.w - d_w_1;
+	d_x_1 = d_x_0 + d_w_0;
+	if (req->dst_rect.w == 3) {
+		d_w_1 = 2;
+		d_w_0 = 2;
+		d_x_1 = d_x_0 + 1;
+	}
+
+	/* break src roi at height or width*/
+	if (splitreq.flags & MDP_ROT_90) {
+		s_x_0 = s_x_1 = req->src_rect.x;
+		s_w_0 = s_w_1 = req->src_rect.w;
+		s_y_0 = req->src_rect.y;
+		s_h_1 = (req->src_rect.h * d_w_1) / req->dst_rect.w;
+		s_h_0 = req->src_rect.h - s_h_1;
+		s_y_1 = s_y_0 + s_h_0;
+		if (d_w_1 >= 8 * s_h_1) {
+			s_h_1++;
+			s_y_1--;
+		}
+	} else {
+		s_y_0 = s_y_1 = req->src_rect.y;
+		s_h_0 = s_h_1 = req->src_rect.h;
+		s_x_0 = req->src_rect.x;
+		s_w_1 = (req->src_rect.w * d_w_1) / req->dst_rect.w;
+		s_w_0 = req->src_rect.w - s_w_1;
+		s_x_1 = s_x_0 + s_w_0;
+		if (d_w_1 >= 8 * s_w_1) {
+			s_w_1++;
+			s_x_1--;
+		}
+	}
+
+	/* blit first region */
+	if (((splitreq.flags & MDP_ROT_MASK) == MDP_ROT_270) ||
+		((splitreq.flags & MDP_ROT_MASK) == 0x0)) {
+		splitreq.src_rect.h = s_h_0;
+		splitreq.src_rect.y = s_y_0;
+		splitreq.dst_rect.h = d_h_0;
+		splitreq.dst_rect.y = d_y_0;
+		splitreq.src_rect.x = s_x_0;
+		splitreq.src_rect.w = s_w_0;
+		splitreq.dst_rect.x = d_x_0;
+		splitreq.dst_rect.w = d_w_0;
+	} else {
+		splitreq.src_rect.h = s_h_0;
+		splitreq.src_rect.y = s_y_0;
+		splitreq.dst_rect.h = d_h_1;
+		splitreq.dst_rect.y = d_y_1;
+		splitreq.src_rect.x = s_x_0;
+		splitreq.src_rect.w = s_w_0;
+		splitreq.dst_rect.x = d_x_1;
+		splitreq.dst_rect.w = d_w_1;
+	}
+
+	if (unlikely((splitreq.dst_rect.h != 1) &&
+		((splitreq.dst_rect.h % 32 == 3) ||
+		(splitreq.dst_rect.h % 32) == 1)))
+		ret = blit_split_height(mdp, &splitreq,
+			src_file, src_start, src_len,
+			dst_file, dst_start, dst_len);
+	else
+		ret = mdp_ppp_blit_and_wait(mdp, &splitreq,
+			src_file, src_start, src_len,
+			dst_file, dst_start, dst_len);
+	if (ret)
+		return ret;
+
+	/* blit second region */
+	if (((splitreq.flags & MDP_ROT_MASK) == MDP_ROT_270) ||
+		((splitreq.flags & MDP_ROT_MASK) == 0x0)) {
+		splitreq.src_rect.h = s_h_1;
+		splitreq.src_rect.y = s_y_1;
+		splitreq.dst_rect.h = d_h_1;
+		splitreq.dst_rect.y = d_y_1;
+		splitreq.src_rect.x = s_x_1;
+		splitreq.src_rect.w = s_w_1;
+		splitreq.dst_rect.x = d_x_1;
+		splitreq.dst_rect.w = d_w_1;
+	} else {
+		splitreq.src_rect.h = s_h_1;
+		splitreq.src_rect.y = s_y_1;
+		splitreq.dst_rect.h = d_h_0;
+		splitreq.dst_rect.y = d_y_0;
+		splitreq.src_rect.x = s_x_1;
+		splitreq.src_rect.w = s_w_1;
+		splitreq.dst_rect.x = d_x_0;
+		splitreq.dst_rect.w = d_w_0;
+	}
+
+	if (unlikely((splitreq.dst_rect.h != 1) &&
+		((splitreq.dst_rect.h % 32 == 3) ||
+		(splitreq.dst_rect.h % 32) == 1)))
+		ret = blit_split_height(mdp, &splitreq,
+			src_file, src_start, src_len,
+			dst_file, dst_start, dst_len);
+	else
+		ret = mdp_ppp_blit_and_wait(mdp, &splitreq,
+			src_file, src_start, src_len,
+			dst_file, dst_start, dst_len);
+	return ret;
+}
+
+
+int mdp_ppp_validate_blit(struct mdp_info *mdp, struct mdp_blit_req *req)
+{
+	if (req->flags & MDP_ROT_90) {
+		if (unlikely(((req->dst_rect.h == 1) &&
+			((req->src_rect.w != 1) ||
+			(req->dst_rect.w != req->src_rect.h))) ||
+			((req->dst_rect.w == 1) && ((req->src_rect.h != 1) ||
+			(req->dst_rect.h != req->src_rect.w))))) {
+			pr_err("mpd_ppp: error scaling when size is 1!\n");
+			return -EINVAL;
+		}
+	} else {
+		if (unlikely(((req->dst_rect.w == 1) &&
+			((req->src_rect.w != 1) ||
+			(req->dst_rect.h != req->src_rect.h))) ||
+			((req->dst_rect.h == 1) && ((req->src_rect.h != 1) ||
+			(req->dst_rect.h != req->src_rect.h))))) {
+			pr_err("mpd_ppp: error scaling when size is 1!\n");
+			return -EINVAL;
+		}
+	}
+
+	/* WORKAROUND FOR HARDWARE BUG IN BG TILE FETCH */
+	if (unlikely(req->src_rect.h == 0 ||
+		     req->src_rect.w == 0)) {
+		pr_info("mdp_ppp: src img of zero size!\n");
+		return -EINVAL;
+	}
+	if (unlikely(req->dst_rect.h == 0 ||
+		     req->dst_rect.w == 0))
+		return -EINVAL;
+
+	return 0;
+}
+
+int mdp_ppp_do_blit(struct mdp_info *mdp, struct mdp_blit_req *req,
+		    struct file *src_file, unsigned long src_start,
+		    unsigned long src_len, struct file *dst_file,
+		    unsigned long dst_start, unsigned long dst_len)
+{
+	int ret;
+
+	/* Workarounds for MDP 3.1 hardware bugs */
+	if (unlikely((mdp_get_bytes_per_pixel(req->dst.format) == 4) &&
+		(req->dst_rect.w != 1) &&
+		(((req->dst_rect.w % 8) == 6) ||
+		((req->dst_rect.w % 32) == 3) ||
+		((req->dst_rect.w % 32) == 1)))) {
+		ret = blit_split_width(mdp, req,
+				src_file, src_start, src_len,
+				dst_file, dst_start, dst_len);
+		goto end;
+	} else if (unlikely((req->dst_rect.w != 1) && (req->dst_rect.h != 1) &&
+		((req->dst_rect.h % 32) == 3 ||
+		(req->dst_rect.h % 32) == 1))) {
+		ret = blit_split_height(mdp, req,
+			src_file, src_start, src_len,
+			dst_file, dst_start, dst_len);
+		goto end;
+	}
+
+	ret = mdp_ppp_blit_and_wait(mdp, req,
+				src_file, src_start, src_len,
+				dst_file, dst_start, dst_len);
+end:
+	return ret;
+}
diff --git a/drivers/video/msm/mdp_scale_tables.h b/drivers/video/msm/mdp_scale_tables.h
deleted file mode 100644
index 34077b1..0000000
--- a/drivers/video/msm/mdp_scale_tables.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* drivers/video/msm_fb/mdp_scale_tables.h
- *
- * Copyright (C) 2007 QUALCOMM Incorporated
- * Copyright (C) 2007 Google 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.
- */
-#ifndef _MDP_SCALE_TABLES_H_
-#define _MDP_SCALE_TABLES_H_
-
-#include <linux/types.h>
-struct mdp_table_entry {
-	uint32_t reg;
-	uint32_t val;
-};
-
-extern struct mdp_table_entry mdp_upscale_table[64];
-
-enum {
-	MDP_DOWNSCALE_PT2TOPT4,
-	MDP_DOWNSCALE_PT4TOPT6,
-	MDP_DOWNSCALE_PT6TOPT8,
-	MDP_DOWNSCALE_PT8TO1,
-	MDP_DOWNSCALE_MAX,
-};
-
-extern struct mdp_table_entry *mdp_downscale_x_table[MDP_DOWNSCALE_MAX];
-extern struct mdp_table_entry *mdp_downscale_y_table[MDP_DOWNSCALE_MAX];
-extern struct mdp_table_entry mdp_gaussian_blur_table[];
-
-#endif
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index debe593..a21a44a 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -22,6 +22,8 @@
 
 #include <linux/freezer.h>
 #include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <linux/earlysuspend.h>
 #include <linux/msm_mdp.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
@@ -32,6 +34,12 @@
 #include <linux/debugfs.h>
 #include <linux/dma-mapping.h>
 
+#define MSMFB_DEBUG 1
+#ifdef CONFIG_FB_MSM_LOGO
+#define INIT_IMAGE_FILE "/logo.rle"
+extern int load_565rle_image(char *filename);
+#endif
+
 #define PRINT_FPS 0
 #define PRINT_BLIT_TIME 0
 
@@ -53,6 +61,9 @@
 		printk(KERN_INFO "msmfb: "fmt, ##args); \
 } while (0)
 
+#define BITS_PER_PIXEL(info) (info->fb->var.bits_per_pixel)
+#define BYTES_PER_PIXEL(info) (info->fb->var.bits_per_pixel >> 3)
+
 static int msmfb_debug_mask;
 module_param_named(msmfb_debug_mask, msmfb_debug_mask, int,
 		   S_IRUGO | S_IWUSR | S_IWGRP);
@@ -78,6 +89,9 @@
 	} update_info;
 	char *black;
 
+	struct early_suspend earlier_suspend;
+	struct early_suspend early_suspend;
+	struct wake_lock idle_lock;
 	spinlock_t update_lock;
 	struct mutex panel_init_lock;
 	wait_queue_head_t frame_wq;
@@ -105,6 +119,12 @@
 	unsigned long irq_flags;
 	struct msmfb_info *msmfb  = container_of(callback, struct msmfb_info,
 					       dma_callback);
+#if PRINT_FPS
+	int64_t dt;
+	ktime_t now;
+	static int64_t frame_count;
+	static ktime_t last_sec;
+#endif
 
 	spin_lock_irqsave(&msmfb->update_lock, irq_flags);
 	msmfb->frame_done = msmfb->frame_requested;
@@ -113,6 +133,18 @@
 		DLOG(SUSPEND_RESUME, "full update completed\n");
 		queue_work(msmfb->resume_workqueue, &msmfb->resume_work);
 	}
+#if PRINT_FPS
+	now = ktime_get();
+	dt = ktime_to_ns(ktime_sub(now, last_sec));
+	frame_count++;
+	if (dt > NSEC_PER_SEC) {
+		int64_t fps = frame_count * NSEC_PER_SEC * 100;
+		frame_count = 0;
+		last_sec = ktime_get();
+		do_div(fps, dt);
+		DLOG(FPS, "fps * 100: %llu\n", fps);
+	}
+#endif
 	spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
 	wake_up(&msmfb->frame_wq);
 }
@@ -162,9 +194,10 @@
 	}
 	spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
 
-	addr = ((msmfb->xres * (yoffset + y) + x) * 2);
+	addr = ((msmfb->xres * (yoffset + y) + x) * BYTES_PER_PIXEL(msmfb));
 	mdp->dma(mdp, addr + msmfb->fb->fix.smem_start,
-		 msmfb->xres * 2, w, h, x, y, &msmfb->dma_callback,
+		 msmfb->xres * BYTES_PER_PIXEL(msmfb), w, h, x, y,
+		 &msmfb->dma_callback,
 		 panel->interface_type);
 	return 0;
 error:
@@ -181,6 +214,7 @@
 {
 	struct msmfb_info *msmfb = container_of(callback, struct msmfb_info,
 					       vsync_callback);
+	wake_unlock(&msmfb->idle_lock);
 	msmfb_start_dma(msmfb);
 }
 
@@ -201,6 +235,12 @@
 	unsigned long irq_flags;
 	int sleeping;
 	int retry = 1;
+#if PRINT_FPS
+	ktime_t t1, t2;
+	static uint64_t pans;
+	static uint64_t dt;
+	t1 = ktime_get();
+#endif
 
 	DLOG(SHOW_UPDATES, "update %d %d %d %d %d %d\n",
 		left, top, eright, ebottom, yoffset, pan_display);
@@ -220,8 +260,8 @@
 
 	sleeping = msmfb->sleeping;
 	/* on a full update, if the last frame has not completed, wait for it */
-	if (pan_display && (msmfb->frame_requested != msmfb->frame_done ||
-			    sleeping == UPDATING)) {
+	if ((pan_display && msmfb->frame_requested != msmfb->frame_done) ||
+			    sleeping == UPDATING) {
 		int ret;
 		spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
 		ret = wait_event_interruptible_timeout(msmfb->frame_wq,
@@ -231,6 +271,7 @@
 				 msmfb->sleeping == UPDATING)) {
 			if (retry && panel->request_vsync &&
 			    (sleeping == AWAKE)) {
+				wake_lock_timeout(&msmfb->idle_lock, HZ/4);
 				panel->request_vsync(panel,
 					&msmfb->vsync_callback);
 				retry = 0;
@@ -247,6 +288,21 @@
 		goto restart;
 	}
 
+#if PRINT_FPS
+	t2 = ktime_get();
+	if (pan_display) {
+		uint64_t temp = ktime_to_ns(ktime_sub(t2, t1));
+		do_div(temp, 1000);
+		dt += temp;
+		pans++;
+		if (pans > 1000) {
+			do_div(dt, pans);
+			DLOG(FPS, "ave_wait_time: %lld\n", dt);
+			dt = 0;
+			pans = 0;
+		}
+	}
+#endif
 
 	msmfb->frame_requested++;
 	/* if necessary, update the y offset, if this is the
@@ -282,6 +338,7 @@
 	 * for 16 ms (long enough for the dma to panel) and then begin dma */
 	msmfb->vsync_request_time = ktime_get();
 	if (panel->request_vsync && (sleeping == AWAKE)) {
+		wake_lock_timeout(&msmfb->idle_lock, HZ/4);
 		panel->request_vsync(panel, &msmfb->vsync_callback);
 	} else {
 		if (!hrtimer_active(&msmfb->fake_vsync)) {
@@ -308,11 +365,13 @@
 	mutex_lock(&msmfb->panel_init_lock);
 	DLOG(SUSPEND_RESUME, "turning on panel\n");
 	if (msmfb->sleeping == UPDATING) {
+		wake_lock_timeout(&msmfb->idle_lock, HZ);
 		if (panel->unblank(panel)) {
 			printk(KERN_INFO "msmfb: panel unblank failed,"
 			       "not starting drawing\n");
 			goto error;
 		}
+		wake_unlock(&msmfb->idle_lock);
 		spin_lock_irqsave(&msmfb->update_lock, irq_flags);
 		msmfb->sleeping = AWAKE;
 		wake_up(&msmfb->frame_wq);
@@ -322,17 +381,105 @@
 	mutex_unlock(&msmfb->panel_init_lock);
 }
 
+#ifdef CONFIG_HAS_EARLYSUSPEND
+/* turn off the panel */
+static void msmfb_earlier_suspend(struct early_suspend *h)
+{
+	struct msmfb_info *msmfb = container_of(h, struct msmfb_info,
+						earlier_suspend);
+	struct msm_panel_data *panel = msmfb->panel;
+	unsigned long irq_flags;
+
+	mutex_lock(&msmfb->panel_init_lock);
+	msmfb->sleeping = SLEEPING;
+	wake_up(&msmfb->frame_wq);
+	spin_lock_irqsave(&msmfb->update_lock, irq_flags);
+	spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
+	wait_event_timeout(msmfb->frame_wq,
+			   msmfb->frame_requested == msmfb->frame_done, HZ/10);
+
+	mdp->dma(mdp, virt_to_phys(msmfb->black), 0,
+		 msmfb->fb->var.xres, msmfb->fb->var.yres, 0, 0,
+		 NULL, panel->interface_type);
+	mdp->dma_wait(mdp, panel->interface_type);
+
+	/* turn off the panel */
+	panel->blank(panel);
+}
+
+static void msmfb_suspend(struct early_suspend *h)
+{
+	struct msmfb_info *msmfb = container_of(h, struct msmfb_info,
+						early_suspend);
+	struct msm_panel_data *panel = msmfb->panel;
+	/* suspend the panel */
+	panel->suspend(panel);
+	mutex_unlock(&msmfb->panel_init_lock);
+}
+
+static void msmfb_resume(struct early_suspend *h)
+{
+	struct msmfb_info *msmfb = container_of(h, struct msmfb_info,
+						early_suspend);
+	struct msm_panel_data *panel = msmfb->panel;
+	unsigned long irq_flags;
+
+	if (panel->resume(panel)) {
+		printk(KERN_INFO "msmfb: panel resume failed, not resuming "
+		       "fb\n");
+		return;
+	}
+	spin_lock_irqsave(&msmfb->update_lock, irq_flags);
+	msmfb->frame_requested = msmfb->frame_done = msmfb->update_frame = 0;
+	msmfb->sleeping = WAKING;
+	DLOG(SUSPEND_RESUME, "ready, waiting for full update\n");
+	spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
+}
+#endif
 
 static int msmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
+	u32 size;
+
 	if ((var->xres != info->var.xres) ||
 	    (var->yres != info->var.yres) ||
-	    (var->xres_virtual != info->var.xres_virtual) ||
-	    (var->yres_virtual != info->var.yres_virtual) ||
 	    (var->xoffset != info->var.xoffset) ||
-	    (var->bits_per_pixel != info->var.bits_per_pixel) ||
+	    (mdp->check_output_format(mdp, var->bits_per_pixel)) ||
 	    (var->grayscale != info->var.grayscale))
 		 return -EINVAL;
+
+	size = var->xres_virtual * var->yres_virtual *
+		(var->bits_per_pixel >> 3);
+	if (size > info->fix.smem_len)
+		return -EINVAL;
+	return 0;
+}
+
+static int msmfb_set_par(struct fb_info *info)
+{
+	struct fb_var_screeninfo *var = &info->var;
+	struct fb_fix_screeninfo *fix = &info->fix;
+
+	/* we only support RGB ordering for now */
+	if (var->bits_per_pixel == 32 || var->bits_per_pixel == 24) {
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 16;
+		var->blue.length = 8;
+	} else if (var->bits_per_pixel == 16) {
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+	} else
+		return -1;
+	mdp->set_output_format(mdp, var->bits_per_pixel);
+	fix->line_length = var->xres * var->bits_per_pixel / 8;
+
 	return 0;
 }
 
@@ -344,6 +491,13 @@
 	/* "UPDT" */
 	if ((panel->caps & MSMFB_CAP_PARTIAL_UPDATES) &&
 	    (var->reserved[0] == 0x54445055)) {
+#if 0
+		printk(KERN_INFO "pan frame %d-%d, rect %d %d %d %d\n",
+		       msmfb->frame_requested, msmfb->frame_done,
+		       var->reserved[1] & 0xffff,
+		       var->reserved[1] >> 16, var->reserved[2] & 0xffff,
+		       var->reserved[2] >> 16);
+#endif
 		msmfb_pan_update(info, var->reserved[1] & 0xffff,
 				 var->reserved[1] >> 16,
 				 var->reserved[2] & 0xffff,
@@ -407,13 +561,24 @@
 {
 	void __user *argp = (void __user *)arg;
 	int ret;
+#if PRINT_BLIT_TIME
+	ktime_t t1, t2;
+#endif
 
 	switch (cmd) {
 	case MSMFB_GRP_DISP:
 		mdp->set_grp_disp(mdp, arg);
 		break;
 	case MSMFB_BLIT:
+#if PRINT_BLIT_TIME
+		t1 = ktime_get();
+#endif
 		ret = msmfb_blit(p, argp);
+#if PRINT_BLIT_TIME
+		t2 = ktime_get();
+		DLOG(BLIT_TIME, "total %lld\n",
+		       ktime_to_ns(t2) - ktime_to_ns(t1));
+#endif
 		if (ret)
 			return ret;
 		break;
@@ -429,6 +594,7 @@
 	.fb_open = msmfb_open,
 	.fb_release = msmfb_release,
 	.fb_check_var = msmfb_check_var,
+	.fb_set_par = msmfb_set_par,
 	.fb_pan_display = msmfb_pan_display,
 	.fb_fillrect = msmfb_fillrect,
 	.fb_copyarea = msmfb_copyarea,
@@ -439,8 +605,44 @@
 static unsigned PP[16];
 
 
+#if MSMFB_DEBUG
+static ssize_t debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
 
-#define BITS_PER_PIXEL 16
+
+static ssize_t debug_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct msmfb_info *msmfb = (struct msmfb_info *)file->private_data;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&msmfb->update_lock, irq_flags);
+	n = scnprintf(buffer, debug_bufmax, "yoffset %d\n", msmfb->yoffset);
+	n += scnprintf(buffer + n, debug_bufmax, "frame_requested %d\n",
+		       msmfb->frame_requested);
+	n += scnprintf(buffer + n, debug_bufmax, "frame_done %d\n",
+		       msmfb->frame_done);
+	n += scnprintf(buffer + n, debug_bufmax, "sleeping %d\n",
+		       msmfb->sleeping);
+	n += scnprintf(buffer + n, debug_bufmax, "update_frame %d\n",
+		       msmfb->update_frame);
+	spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
+	n++;
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static struct file_operations debug_fops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+#endif
 
 static void setup_fb_info(struct msmfb_info *msmfb)
 {
@@ -457,19 +659,26 @@
 	fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
 	fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
 	fb_info->fix.line_length = msmfb->xres * 2;
-
 	fb_info->var.xres = msmfb->xres;
 	fb_info->var.yres = msmfb->yres;
 	fb_info->var.width = msmfb->panel->fb_data->width;
 	fb_info->var.height = msmfb->panel->fb_data->height;
 	fb_info->var.xres_virtual = msmfb->xres;
 	fb_info->var.yres_virtual = msmfb->yres * 2;
-	fb_info->var.bits_per_pixel = BITS_PER_PIXEL;
+	fb_info->var.bits_per_pixel = 16;
 	fb_info->var.accel_flags = 0;
 
 	fb_info->var.yoffset = 0;
 
 	if (msmfb->panel->caps & MSMFB_CAP_PARTIAL_UPDATES) {
+		/* set the param in the fixed screen, so userspace can't
+		 * change it. This will be used to check for the
+		 * capability. */
+		fb_info->fix.reserved[0] = 0x5444;
+		fb_info->fix.reserved[1] = 0x5055;
+
+		/* This preloads the value so that if userspace doesn't
+		 * change it, it will be a full update */
 		fb_info->var.reserved[0] = 0x54445055;
 		fb_info->var.reserved[1] = 0;
 		fb_info->var.reserved[2] = (uint16_t)msmfb->xres |
@@ -486,6 +695,8 @@
 	fb_info->var.blue.length = 5;
 	fb_info->var.blue.msb_right = 0;
 
+	mdp->set_output_format(mdp, fb_info->var.bits_per_pixel);
+
 	r = fb_alloc_cmap(&fb_info->cmap, 16, 0);
 	fb_info->pseudo_palette = PP;
 
@@ -499,28 +710,30 @@
 	struct fb_info *fb = msmfb->fb;
 	struct resource *resource;
 	unsigned long size = msmfb->xres * msmfb->yres *
-			     (BITS_PER_PIXEL >> 3) * 2;
+		BYTES_PER_PIXEL(msmfb) * 2;
+	unsigned long resource_size;
 	unsigned char *fbram;
 
 	/* board file might have attached a resource describing an fb */
 	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!resource)
 		return -EINVAL;
+	resource_size = resource->end - resource->start + 1;
 
 	/* check the resource is large enough to fit the fb */
-	if (resource->end - resource->start < size) {
-		printk(KERN_ERR "allocated resource is too small for "
+	if (resource_size < size) {
+		printk(KERN_ERR "msmfb: allocated resource is too small for "
 				"fb\n");
 		return -ENOMEM;
 	}
 	fb->fix.smem_start = resource->start;
-	fb->fix.smem_len = resource->end - resource->start;
-	fbram = ioremap(resource->start,
-			resource->end - resource->start);
+	fb->fix.smem_len = resource_size;
+	fbram = ioremap(resource->start, resource_size);
 	if (fbram == 0) {
 		printk(KERN_ERR "msmfb: cannot allocate fbram!\n");
 		return -ENOMEM;
 	}
+
 	fb->screen_base = fbram;
 	return 0;
 }
@@ -569,6 +782,24 @@
 	msmfb->black = kzalloc(msmfb->fb->var.bits_per_pixel*msmfb->xres,
 			       GFP_KERNEL);
 
+	wake_lock_init(&msmfb->idle_lock, WAKE_LOCK_IDLE, "msmfb_idle_lock");
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	msmfb->early_suspend.suspend = msmfb_suspend;
+	msmfb->early_suspend.resume = msmfb_resume;
+	msmfb->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	register_early_suspend(&msmfb->early_suspend);
+
+	msmfb->earlier_suspend.suspend = msmfb_earlier_suspend;
+	msmfb->earlier_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
+	register_early_suspend(&msmfb->earlier_suspend);
+#endif
+
+#if MSMFB_DEBUG
+	debugfs_create_file("msm_fb", S_IFREG | S_IRUGO, NULL,
+			    (void *)fb->par, &debug_fops);
+#endif
+
 	printk(KERN_INFO "msmfb_probe() installing %d x %d panel\n",
 	       msmfb->xres, msmfb->yres);
 
@@ -586,9 +817,21 @@
 
 	msmfb->sleeping = WAKING;
 
+#ifdef CONFIG_FB_MSM_LOGO
+	if (!load_565rle_image(INIT_IMAGE_FILE)) {
+		/* Flip buffer */
+		msmfb->update_info.left = 0;
+		msmfb->update_info.top = 0;
+		msmfb->update_info.eright = info->var.xres;
+		msmfb->update_info.ebottom = info->var.yres;
+		msmfb_pan_update(info, 0, 0, fb->var.xres,
+				 fb->var.yres, 0, 1);
+	}
+#endif
 	return 0;
 
 error_register_framebuffer:
+	wake_lock_destroy(&msmfb->idle_lock);
 	destroy_workqueue(msmfb->resume_workqueue);
 error_create_workqueue:
 	iounmap(fb->screen_base);
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index e5f7441..62a3702 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -84,7 +84,9 @@
 static int ds2482_probe(struct i2c_client *client,
 			const struct i2c_device_id *id);
 static int ds2482_remove(struct i2c_client *client);
-
+static int ds2482_suspend(struct i2c_client *client,
+			  pm_message_t mesg);
+static int ds2482_resume(struct i2c_client *client);
 
 /**
  * Driver data (common to all clients)
@@ -101,6 +103,8 @@
 	},
 	.probe		= ds2482_probe,
 	.remove		= ds2482_remove,
+	.suspend	= ds2482_suspend,
+	.resume		= ds2482_resume,
 	.id_table	= ds2482_id,
 };
 
@@ -130,6 +134,52 @@
 	u8			reg_config;
 };
 
+static int ds2482_write_byte(struct ds2482_data *pdev, u8 cmd)
+{
+	int ret;
+	int retry = 5;
+
+	do {
+		ret = i2c_smbus_write_byte(pdev->client, cmd);
+		if (ret >= 0)
+			break;
+		dev_warn(&pdev->client->dev,
+			 "i2c write %x failed, %d, retries left %d\n",
+			 cmd, ret, retry);
+	} while(retry--);
+	return ret;
+}
+
+static int ds2482_write_byte_data(struct ds2482_data *pdev, u8 cmd, u8 byte)
+{
+	int ret;
+	int retry = 5;
+
+	do {
+		ret = i2c_smbus_write_byte_data(pdev->client, cmd, byte);
+		if (ret >= 0)
+			break;
+		dev_warn(&pdev->client->dev,
+			 "i2c write %x %x failed, %d, retries left %d\n",
+			 cmd, byte, ret, retry);
+	} while(retry--);
+	return ret;
+}
+
+static int ds2482_read_byte(struct ds2482_data *pdev)
+{
+	int ret;
+	int retry = 5;
+
+	do {
+		ret = i2c_smbus_read_byte(pdev->client);
+		if (ret >= 0)
+			break;
+		dev_warn(&pdev->client->dev,
+			 "i2c read failed, %d, retries left %d\n", ret, retry);
+	} while(retry--);
+	return ret;
+}
 
 /**
  * Sets the read pointer.
@@ -140,8 +190,7 @@
 static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
 {
 	if (pdev->read_prt != read_ptr) {
-		if (i2c_smbus_write_byte_data(pdev->client,
-					      DS2482_CMD_SET_READ_PTR,
+		if (ds2482_write_byte_data(pdev, DS2482_CMD_SET_READ_PTR,
 					      read_ptr) < 0)
 			return -1;
 
@@ -160,7 +209,7 @@
  */
 static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
 {
-	if (i2c_smbus_write_byte(pdev->client, cmd) < 0)
+	if (ds2482_write_byte(pdev, cmd) < 0)
 		return -1;
 
 	pdev->read_prt = DS2482_PTR_CODE_STATUS;
@@ -180,7 +229,7 @@
 static inline int ds2482_send_cmd_data(struct ds2482_data *pdev,
 				       u8 cmd, u8 byte)
 {
-	if (i2c_smbus_write_byte_data(pdev->client, cmd, byte) < 0)
+	if (ds2482_write_byte_data(pdev, cmd, byte) < 0)
 		return -1;
 
 	/* all cmds leave in STATUS, except CONFIG */
@@ -231,13 +280,13 @@
  */
 static int ds2482_set_channel(struct ds2482_data *pdev, u8 channel)
 {
-	if (i2c_smbus_write_byte_data(pdev->client, DS2482_CMD_CHANNEL_SELECT,
+	if (ds2482_write_byte_data(pdev, DS2482_CMD_CHANNEL_SELECT,
 				      ds2482_chan_wr[channel]) < 0)
 		return -1;
 
 	pdev->read_prt = DS2482_PTR_CODE_CHANNEL;
 	pdev->channel = -1;
-	if (i2c_smbus_read_byte(pdev->client) == ds2482_chan_rd[channel]) {
+	if (ds2482_read_byte(pdev) == ds2482_chan_rd[channel]) {
 		pdev->channel = channel;
 		return 0;
 	}
@@ -361,7 +410,7 @@
 	ds2482_select_register(pdev, DS2482_PTR_CODE_DATA);
 
 	/* Read the data byte */
-	result = i2c_smbus_read_byte(pdev->client);
+	result = ds2482_read_byte(pdev);
 
 	mutex_unlock(&pdev->access_lock);
 
@@ -408,6 +457,31 @@
 }
 
 
+static int ds2482_suspend(struct i2c_client *client,
+			  pm_message_t mesg)
+{
+	void (*set_slp_n)(int n) =
+		client->dev.platform_data;
+
+	if (set_slp_n)
+		set_slp_n(0);
+
+	return 0;
+}
+
+static int ds2482_resume(struct i2c_client *client)
+{
+	void (*set_slp_n)(int n) =
+		client->dev.platform_data;
+
+	if (set_slp_n) {
+		set_slp_n(1);
+		udelay(100);
+	}
+
+	return 0;
+}
+
 static int ds2482_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
@@ -439,7 +513,7 @@
 	ndelay(525);
 
 	/* Read the status byte - only reset bit and line should be set */
-	temp1 = i2c_smbus_read_byte(client);
+	temp1 = ds2482_read_byte(data);
 	if (temp1 != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) {
 		dev_warn(&client->dev, "DS2482 reset status "
 			 "0x%02X - not a DS2482\n", temp1);
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 3ca1b92..f15ab4b 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -35,6 +35,7 @@
 #define W1_THERM_DS18B20 	0x28
 #define W1_EEPROM_DS2431	0x2D
 #define W1_FAMILY_DS2760	0x30
+#define W1_FAMILY_DS2784	0x32
 
 #define MAXNAMELEN		32
 
diff --git a/include/linux/a1026.h b/include/linux/a1026.h
new file mode 100644
index 0000000..44cdf4d
--- /dev/null
+++ b/include/linux/a1026.h
@@ -0,0 +1,234 @@
+/* include/linux/a1026.h - a1026 voice processor 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_A1026_H
+#define __LINUX_A1026_H
+
+#include <linux/ioctl.h>
+
+#define A1026_MAX_FW_SIZE	(32*1024)
+struct a1026img {
+	unsigned char *buf;
+	unsigned img_size;
+};
+
+enum A1026_PathID {
+	A1026_PATH_SUSPEND,
+	A1026_PATH_INCALL_RECEIVER,
+	A1026_PATH_INCALL_HEADSET,
+	A1026_PATH_INCALL_SPEAKER,
+	A1026_PATH_INCALL_BT,
+	A1026_PATH_VR_NO_NS_RECEIVER,
+	A1026_PATH_VR_NO_NS_HEADSET,
+	A1026_PATH_VR_NO_NS_SPEAKER,
+	A1026_PATH_VR_NO_NS_BT,
+	A1026_PATH_VR_NS_RECEIVER,
+	A1026_PATH_VR_NS_HEADSET,
+	A1026_PATH_VR_NS_SPEAKER,
+	A1026_PATH_VR_NS_BT,
+	A1026_PATH_RECORD_RECEIVER,
+	A1026_PATH_RECORD_HEADSET,
+	A1026_PATH_RECORD_SPEAKER,
+	A1026_PATH_RECORD_BT,
+	A1026_PATH_CAMCORDER,
+	A1026_PATH_INCALL_TTY
+};
+
+/* noise suppression states */
+enum A1026_NS_states {
+	A1026_NS_STATE_AUTO,	/* leave mode as selected by driver  */
+	A1026_NS_STATE_OFF,	/* disable noise suppression */
+	A1026_NS_STATE_CT,	/* force close talk mode */
+	A1026_NS_STATE_FT,	/* force far talk mode */
+	A1026_NS_NUM_STATES
+};
+
+/* indicates if a1026_set_config() performs a full configuration or only
+ * a voice processing algorithm configuration */
+/* IOCTLs for Audience A1026 */
+#define A1026_IOCTL_MAGIC 'u'
+
+#define A1026_BOOTUP_INIT  _IOW(A1026_IOCTL_MAGIC, 0x01, struct a1026img *)
+#define A1026_SET_CONFIG   _IOW(A1026_IOCTL_MAGIC, 0x02, enum A1026_PathID)
+#define A1026_SET_NS_STATE _IOW(A1026_IOCTL_MAGIC, 0x03, enum A1026_NS_states)
+
+/* For Diag */
+#define A1026_SET_MIC_ONOFF	_IOW(A1026_IOCTL_MAGIC, 0x50, unsigned)
+#define A1026_SET_MICSEL_ONOFF	_IOW(A1026_IOCTL_MAGIC, 0x51, unsigned)
+#define A1026_READ_DATA		_IOR(A1026_IOCTL_MAGIC, 0x52, unsigned)
+#define A1026_WRITE_MSG		_IOW(A1026_IOCTL_MAGIC, 0x53, unsigned)
+#define A1026_SYNC_CMD		_IO(A1026_IOCTL_MAGIC, 0x54)
+#define A1026_SET_CMD_FILE	_IOW(A1026_IOCTL_MAGIC, 0x55, unsigned)
+
+#ifdef __KERNEL__
+
+/* A1026 Command codes */
+#define CtrlMode_LAL		0x0001 /* Level Active Low  */
+#define CtrlMode_LAH		0x0002 /* Level Active High */
+#define CtrlMode_FE		0x0003 /* Falling Edge */
+#define CtrlMode_RE		0x0004 /* Rising  Edge */
+#define A100_msg_Sync		0x80000000
+#define A100_msg_Sync_Ack	0x80000000
+
+#define A100_msg_Reset		0x8002
+#define RESET_IMMEDIATE		0x0000
+#define RESET_DELAYED		0x0001
+
+#define A100_msg_BootloadInitiate	0x8003
+#define A100_msg_GetDeviceParm		0x800B
+#define A100_msg_SetDeviceParmID	0x800C
+#define A100_msg_SetDeviceParm		0x800D
+
+/* Get/Set PCM Device Parameter ID List */
+/* PCM-0 */
+#define PCM0WordLength		0x0100
+#define PCM0DelFromFsTx		0x0101
+#define PCM0DelFromFsRx		0x0102
+#define PCM0LatchEdge		0x0103
+#define PCM0Endianness		0x0105
+#define PCM0TristateEnable	0x0107
+
+/* PCM-1 */
+#define PCM1WordLength		0x0200
+#define PCM1DelFromFsTx		0x0201
+#define PCM1DelFromFsRx		0x0202
+#define PCM1LatchEdge		0x0203
+#define PCM1Endianness		0x0205
+#define PCM1TristateEnable	0x0207
+
+/* Possible setting values for PCM I/F */
+#define PCMWordLength_16bit	0x10 /* Default */
+#define PCMWordLength_24bit	0x18
+#define PCMWordLength_32bit	0x20
+#define PCMLatchEdge_Tx_F_Rx_R	0x00 /* Tx/Rx on falling/rising edge */
+#define PCMLatchEdge_Tx_R_Rx_F	0x03 /* Tx/Rx on falling/rising edge */
+#define PCMEndianness_Little	0x00
+#define PCMEndianness_Big	0x01 /* Default */
+#define PCMTristate_Disable	0x00 /* Default */
+#define PCMTristate_Enable	0x01
+
+/* Get/Set ADC Device Parameter ID List */
+/* ADC-0 */
+#define ADC0Gain	0x0300
+#define ADC0Rate	0x0301
+#define ADC0CutoffFreq	0x0302
+
+/* ADC-1 */
+#define ADC1Gain	0x0400
+#define ADC1Rate	0x0401
+#define ADC1CutoffFreq	0x0402
+
+/* Possible setting values for ADC I/F */
+#define ADC_Gain_0db			0x00
+#define ADC_Gain_6db			0x01
+#define ADC_Gain_12db			0x02
+#define ADC_Gain_18db			0x03
+#define ADC_Gain_24db			0x04 /* Default */
+#define ADC_Gain_30db			0x05
+#define ADC_Rate_8kHz			0x00 /* Default */
+#define ADC_Rate_16kHz			0x01
+#define ADC_CutoffFreq_NO_DC_Filter	0x00
+#define ADC_CutoffFreq_59p68Hz		0x01 /* Default */
+#define ADC_CutoffFreq_7p46Hz		0x02
+#define ADC_CutoffFreq_3p73Hz		0x03
+
+/* Set Power State */
+#define A100_msg_Sleep		0x80100001
+
+/* Get/Set Algorithm Parameter command codes list */
+#define A100_msg_GetAlgorithmParm	0x8016
+#define A100_msg_SetAlgorithmParmID	0x8017
+#define A100_msg_SetAlgorithmParm	0x8018
+
+/* Get/Set Algorithm Parameter ID List (Transmit Feature) */
+#define AIS_Global_Supression_Level	0x0000
+#define Mic_Config			0x0002
+#define AEC_Mode			0x0003
+#define AEC_CNG				0x0023
+#define Output_AGC			0x0004
+#define Output_AGC_Target_Level		0x0005
+#define Output_AGC_Noise_Floor		0x0006
+#define Output_AGC_SNR_Improvement	0x0007
+#define Comfort_Noise			0x001A
+#define Comfort_Noise_Level		0x001B
+
+/* Get/Set Algorithm Parameter ID List (Receive Feature) */
+#define Speaker_Volume			0x0012
+#define VEQ_Mode			0x0009
+#define VEQ_Max_FarEnd_Limiter_Level	0x000D
+#define VEQ_Noise_Estimation_Adj	0x0025
+#define Receive_NS			0x000E
+#define Receive_NS_Level		0x000F
+#define SideTone			0x0015
+#define SideTone_Gain			0x0016
+
+/* Audio Path Commands */
+/* Get/Set Transmit Digital Input Gain */
+#define A100_msg_GetTxDigitalInputGain  0x801A
+#define A100_msg_SetTxDigitalInputGain  0x801B
+
+/* Get/Set Receive Digital Input Gain */
+#define A100_msg_GetRcvDigitalInputGain 0x8022
+#define A100_msg_SetRcvDigitalInputGain 0x8023
+
+/* Get/Set Transmit Digital Output Gain */
+#define A100_msg_GetTxDigitalOutputGain 0x801D
+#define A100_msg_SetTxDigitalOutputGain 0x8015
+
+/* Bypass */
+#define A100_msg_Bypass		0x801C /* 0ff = 0x0000; on = 0x0001 (Default) */
+#define A1026_msg_VP_ON		0x801C0001
+#define A1026_msg_VP_OFF	0x801C0000
+
+/* Diagnostic API Commands */
+#define A100_msg_GetMicRMS	0x8013
+#define A100_msg_GetMicPeak	0x8014
+#define DiagPath_Pri_Input_Mic	0x0000
+#define DiagPath_Sec_Input_Mic	0x0001
+#define DiagPath_Output_Mic	0x0002
+#define DiagPath_Far_End_Input	0x0003
+#define DiagPath_Far_End_Output	0x0004
+#define A100_msg_SwapInputCh	0x8019
+#define A100_msg_OutputKnownSig	0x801E
+
+#define A1026_msg_BOOT		0x0001
+#define A1026_msg_BOOT_ACK	0x01
+
+/* general definitions */
+#define TIMEOUT			20 /* ms */
+#define RETRY_CNT		5
+#define POLLING_RETRY_CNT	3
+#define A1026_ERROR_CODE	0xffff
+#define A1026_SLEEP		0
+#define A1026_ACTIVE		1
+#define A1026_CMD_FIFO_DEPTH	64
+#define ERROR			0xffffffff
+
+enum A1026_config_mode {
+	A1026_CONFIG_FULL,
+	A1026_CONFIG_VP
+};
+
+struct a1026_platform_data {
+	uint32_t gpio_a1026_micsel;
+	uint32_t gpio_a1026_wakeup;
+	uint32_t gpio_a1026_reset;
+	uint32_t gpio_a1026_int;
+	uint32_t gpio_a1026_clk;
+};
+
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_A1026_H */
diff --git a/include/linux/akm8973.h b/include/linux/akm8973.h
new file mode 100644
index 0000000..2afa3ba
--- /dev/null
+++ b/include/linux/akm8973.h
@@ -0,0 +1,61 @@
+/*
+ * Definitions for akm8973 compass chip.
+ */
+#ifndef AKM8973_H
+#define AKM8973_H
+
+#include <linux/ioctl.h>
+
+#define AKM8973_I2C_NAME "akm8973"
+
+/* Compass device dependent definition */
+#define AKECS_MODE_MEASURE	0x00	/* Starts measurement. Please use AKECS_MODE_MEASURE_SNG */
+					/* or AKECS_MODE_MEASURE_SEQ instead of this. */
+#define AKECS_MODE_E2P_READ	0x02	/* E2P access mode (read). */
+#define AKECS_MODE_POWERDOWN	0x03	/* Power down mode */
+
+#define RBUFF_SIZE		4	/* Rx buffer size */
+
+/* AK8973 register address */
+#define AKECS_REG_ST			0xC0
+#define AKECS_REG_TMPS			0xC1
+#define AKECS_REG_MS1			0xE0
+
+#define AKMIO				0xA1
+
+/* IOCTLs for AKM library */
+#define ECS_IOCTL_WRITE                 _IOW(AKMIO, 0x01, char[5])
+#define ECS_IOCTL_READ                  _IOWR(AKMIO, 0x02, char[5])
+#define ECS_IOCTL_RESET      	          _IO(AKMIO, 0x03)
+#define ECS_IOCTL_SET_MODE              _IOW(AKMIO, 0x04, short)
+#define ECS_IOCTL_GETDATA               _IOR(AKMIO, 0x05, char[RBUFF_SIZE+1])
+#define ECS_IOCTL_SET_YPR               _IOW(AKMIO, 0x06, short[12])
+#define ECS_IOCTL_GET_OPEN_STATUS       _IOR(AKMIO, 0x07, int)
+#define ECS_IOCTL_GET_CLOSE_STATUS      _IOR(AKMIO, 0x08, int)
+#define ECS_IOCTL_GET_DELAY             _IOR(AKMIO, 0x30, short)
+#define ECS_IOCTL_GET_PROJECT_NAME      _IOR(AKMIO, 0x0D, char[64])
+#define ECS_IOCTL_GET_MATRIX            _IOR(AKMIO, 0x0E, short [4][3][3])
+
+/* IOCTLs for APPs */
+#define ECS_IOCTL_APP_SET_MODE		_IOW(AKMIO, 0x10, short)
+#define ECS_IOCTL_APP_SET_MFLAG		_IOW(AKMIO, 0x11, short)
+#define ECS_IOCTL_APP_GET_MFLAG		_IOW(AKMIO, 0x12, short)
+#define ECS_IOCTL_APP_SET_AFLAG		_IOW(AKMIO, 0x13, short)
+#define ECS_IOCTL_APP_GET_AFLAG		_IOR(AKMIO, 0x14, short)
+#define ECS_IOCTL_APP_SET_TFLAG		_IOR(AKMIO, 0x15, short)
+#define ECS_IOCTL_APP_GET_TFLAG		_IOR(AKMIO, 0x16, short)
+#define ECS_IOCTL_APP_RESET_PEDOMETER   _IO(AKMIO, 0x17)
+#define ECS_IOCTL_APP_SET_DELAY		_IOW(AKMIO, 0x18, short)
+#define ECS_IOCTL_APP_GET_DELAY		ECS_IOCTL_GET_DELAY
+#define ECS_IOCTL_APP_SET_MVFLAG	_IOW(AKMIO, 0x19, short)	/* Set raw magnetic vector flag */
+#define ECS_IOCTL_APP_GET_MVFLAG	_IOR(AKMIO, 0x1A, short)	/* Get raw magnetic vector flag */
+
+struct akm8973_platform_data {
+	short layouts[4][3][3];
+	char project_name[64];
+	int reset;
+	int intr;
+};
+
+#endif
+
diff --git a/include/linux/akm8976.h b/include/linux/akm8976.h
new file mode 100644
index 0000000..8f6a2bb
--- /dev/null
+++ b/include/linux/akm8976.h
@@ -0,0 +1,90 @@
+/*
+ * Definitions for akm8976 compass chip.
+ */
+#ifndef AKM8976_H
+#define AKM8976_H
+
+#include <linux/ioctl.h>
+
+/* Compass device dependent definition */
+#define AKECS_MODE_MEASURE	0x00	/* Starts measurement. Please use AKECS_MODE_MEASURE_SNG */
+					/* or AKECS_MODE_MEASURE_SEQ instead of this. */
+#define AKECS_MODE_PFFD		0x01	/* Start pedometer and free fall detect. */
+#define AKECS_MODE_E2P_READ	0x02	/* E2P access mode (read). */
+#define AKECS_MODE_POWERDOWN	0x03	/* Power down mode */
+
+#define AKECS_MODE_MEASURE_SNG	0x10	/* Starts single measurement */
+#define AKECS_MODE_MEASURE_SEQ	0x11	/* Starts sequential measurement */
+
+/* Default register settings */
+#define CSPEC_AINT		0x01	/* Amplification for acceleration sensor */
+#define CSPEC_SNG_NUM		0x01	/* Single measurement mode */
+#define CSPEC_SEQ_NUM		0x02	/* Sequential measurement mode */
+#define CSPEC_SFRQ_32		0x00	/* Measurement frequency: 32Hz */
+#define CSPEC_SFRQ_64		0x01	/* Measurement frequency: 64Hz */
+#define CSPEC_MCS		0x07	/* Clock frequency */
+#define CSPEC_MKS		0x01	/* Clock type: CMOS level */
+#define CSPEC_INTEN		0x01	/* Interruption pin enable: Enable */
+
+#define RBUFF_SIZE		31	/* Rx buffer size */
+#define MAX_CALI_SIZE	0x1000U	/* calibration buffer size */
+
+/* AK8976A register address */
+#define AKECS_REG_ST			0xC0
+#define AKECS_REG_TMPS			0xC1
+#define AKECS_REG_MS1			0xE0
+#define AKECS_REG_MS2			0xE1
+#define AKECS_REG_MS3			0xE2
+
+#define AKMIO				0xA1
+
+/* IOCTLs for AKM library */
+#define ECS_IOCTL_INIT                  _IO(AKMIO, 0x01)
+#define ECS_IOCTL_WRITE                 _IOW(AKMIO, 0x02, char[5])
+#define ECS_IOCTL_READ                  _IOWR(AKMIO, 0x03, char[5])
+#define ECS_IOCTL_RESET      	          _IO(AKMIO, 0x04)
+#define ECS_IOCTL_INT_STATUS            _IO(AKMIO, 0x05)
+#define ECS_IOCTL_FFD_STATUS            _IO(AKMIO, 0x06)
+#define ECS_IOCTL_SET_MODE              _IOW(AKMIO, 0x07, short)
+#define ECS_IOCTL_GETDATA               _IOR(AKMIO, 0x08, char[RBUFF_SIZE+1])
+#define ECS_IOCTL_GET_NUMFRQ            _IOR(AKMIO, 0x09, char[2])
+#define ECS_IOCTL_SET_PERST             _IO(AKMIO, 0x0A)
+#define ECS_IOCTL_SET_G0RST             _IO(AKMIO, 0x0B)
+#define ECS_IOCTL_SET_YPR               _IOW(AKMIO, 0x0C, short[12])
+#define ECS_IOCTL_GET_OPEN_STATUS       _IOR(AKMIO, 0x0D, int)
+#define ECS_IOCTL_GET_CLOSE_STATUS      _IOR(AKMIO, 0x0E, int)
+#define ECS_IOCTL_GET_CALI_DATA         _IOR(AKMIO, 0x0F, char[MAX_CALI_SIZE])
+#define ECS_IOCTL_GET_DELAY             _IOR(AKMIO, 0x30, short)
+
+/* IOCTLs for APPs */
+#define ECS_IOCTL_APP_SET_MODE		_IOW(AKMIO, 0x10, short)
+#define ECS_IOCTL_APP_SET_MFLAG		_IOW(AKMIO, 0x11, short)
+#define ECS_IOCTL_APP_GET_MFLAG		_IOW(AKMIO, 0x12, short)
+#define ECS_IOCTL_APP_SET_AFLAG		_IOW(AKMIO, 0x13, short)
+#define ECS_IOCTL_APP_GET_AFLAG		_IOR(AKMIO, 0x14, short)
+#define ECS_IOCTL_APP_SET_TFLAG		_IOR(AKMIO, 0x15, short)
+#define ECS_IOCTL_APP_GET_TFLAG		_IOR(AKMIO, 0x16, short)
+#define ECS_IOCTL_APP_RESET_PEDOMETER   _IO(AKMIO, 0x17)
+#define ECS_IOCTL_APP_SET_DELAY		_IOW(AKMIO, 0x18, short)
+#define ECS_IOCTL_APP_GET_DELAY		ECS_IOCTL_GET_DELAY
+#define ECS_IOCTL_APP_SET_MVFLAG	_IOW(AKMIO, 0x19, short)	/* Set raw magnetic vector flag */
+#define ECS_IOCTL_APP_GET_MVFLAG	_IOR(AKMIO, 0x1A, short)	/* Get raw magnetic vector flag */
+
+/* IOCTLs for pedometer */
+#define ECS_IOCTL_SET_STEP_CNT          _IOW(AKMIO, 0x20, short)
+
+/* Default GPIO setting */
+#define ECS_RST		146	/*MISC4, bit2 */
+#define ECS_CLK_ON	155	/*MISC5, bit3 */
+#define ECS_INTR	161	/*INT2, bit1 */
+
+struct akm8976_platform_data {
+	int reset;
+	int clk_on;
+	int intr;
+};
+
+extern char *get_akm_cal_ram(void);
+
+#endif
+
diff --git a/include/linux/bma150.h b/include/linux/bma150.h
new file mode 100644
index 0000000..fe8ef22
--- /dev/null
+++ b/include/linux/bma150.h
@@ -0,0 +1,78 @@
+/*
+ * Definitions for BMA150 G-sensor chip.
+ */
+#ifndef BMA150_H
+#define BMA150_H
+
+#include <linux/ioctl.h>
+
+#define BMA150_I2C_NAME "bma150"
+#define BMA150_G_SENSOR_NAME "bma150"
+
+#define BMAIO				0xA1
+
+/* BMA150 register address */
+#define CHIP_ID_REG			0x00
+#define VERSION_REG			0x01
+#define X_AXIS_LSB_REG		0x02
+#define X_AXIS_MSB_REG		0x03
+#define Y_AXIS_LSB_REG		0x04
+#define Y_AXIS_MSB_REG		0x05
+#define Z_AXIS_LSB_REG		0x06
+#define Z_AXIS_MSB_REG		0x07
+#define TEMP_RD_REG			0x08
+#define SMB150_STATUS_REG	0x09
+#define SMB150_CTRL_REG		0x0a
+#define SMB150_CONF1_REG	0x0b
+#define LG_THRESHOLD_REG	0x0c
+#define LG_DURATION_REG		0x0d
+#define HG_THRESHOLD_REG	0x0e
+#define HG_DURATION_REG		0x0f
+#define MOTION_THRS_REG		0x10
+#define HYSTERESIS_REG		0x11
+#define CUSTOMER1_REG		0x12
+#define CUSTOMER2_REG		0x13
+#define RANGE_BWIDTH_REG	0x14
+#define SMB150_CONF2_REG	0x15
+
+#define OFFS_GAIN_X_REG		0x16
+#define OFFS_GAIN_Y_REG		0x17
+#define OFFS_GAIN_Z_REG		0x18
+#define OFFS_GAIN_T_REG		0x19
+#define OFFSET_X_REG		0x1a
+#define OFFSET_Y_REG		0x1b
+#define OFFSET_Z_REG		0x1c
+#define OFFSET_T_REG		0x1d
+
+
+/* IOCTLs*/
+#define BMA_IOCTL_INIT                  _IO(BMAIO, 0x31)
+#define BMA_IOCTL_WRITE                 _IOW(BMAIO, 0x32, char[5])
+#define BMA_IOCTL_READ                  _IOWR(BMAIO, 0x33, char[5])
+#define BMA_IOCTL_READ_ACCELERATION    _IOWR(BMAIO, 0x34, short[7])
+#define BMA_IOCTL_SET_MODE	  _IOW(BMAIO, 0x35, short)
+#define BMA_IOCTL_GET_INT	  _IOR(BMAIO, 0x36, short)
+
+
+/* range and bandwidth */
+#define BMA_RANGE_2G			0
+#define BMA_RANGE_4G			1
+#define BMA_RANGE_8G			2
+
+#define BMA_BW_25HZ		0
+#define BMA_BW_50HZ		1
+#define BMA_BW_100HZ		2
+#define BMA_BW_190HZ		3
+#define BMA_BW_375HZ		4
+#define BMA_BW_750HZ		5
+#define BMA_BW_1500HZ	6
+
+/* mode settings */
+#define BMA_MODE_NORMAL   	0
+#define BMA_MODE_SLEEP       	1
+
+struct bma150_platform_data {
+	int intr;
+};
+
+#endif
diff --git a/include/linux/capella_cm3602.h b/include/linux/capella_cm3602.h
new file mode 100644
index 0000000..7f1de9b
--- /dev/null
+++ b/include/linux/capella_cm3602.h
@@ -0,0 +1,37 @@
+/* include/linux/capella_cm3602.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Iliyan Malchev <malchev@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.
+ *
+ */
+
+#ifndef __LINUX_CAPELLA_CM3602_H
+#define __LINUX_CAPELLA_CM3602_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define CAPELLA_CM3602_IOCTL_MAGIC 'c'
+#define CAPELLA_CM3602_IOCTL_GET_ENABLED \
+		_IOR(CAPELLA_CM3602_IOCTL_MAGIC, 1, int *)
+#define CAPELLA_CM3602_IOCTL_ENABLE \
+		_IOW(CAPELLA_CM3602_IOCTL_MAGIC, 2, int *)
+
+#ifdef __KERNEL__
+#define CAPELLA_CM3602 "capella_cm3602"
+struct capella_cm3602_platform_data {
+	int (*power)(int); /* power to the chip */
+	int p_out; /* proximity-sensor outpuCAPELLA_CM3602_IOCTL_ENABLE,t */
+};
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/include/linux/cy8c_tmg_ts.h b/include/linux/cy8c_tmg_ts.h
new file mode 100644
index 0000000..f3cf17c
--- /dev/null
+++ b/include/linux/cy8c_tmg_ts.h
@@ -0,0 +1,37 @@
+/* include/linux/cy8c_tmg_ts.c
+ *
+ * Copyright (C) 2007-2008 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 CY8C_I2C_H
+#define CY8C_I2C_H
+
+#include <linux/types.h>
+
+#define CYPRESS_TMG_NAME "cy8c-tmg-ts"
+
+struct cy8c_i2c_platform_data {
+	uint16_t version;
+	int abs_x_min;
+	int abs_x_max;
+	int abs_y_min;
+	int abs_y_max;
+	int abs_pressure_min;
+	int abs_pressure_max;
+	int abs_width_min;
+	int abs_width_max;
+	int (*power)(int on);
+};
+
+#endif
+
diff --git a/include/linux/ds2784_battery.h b/include/linux/ds2784_battery.h
new file mode 100644
index 0000000..7ca10f6
--- /dev/null
+++ b/include/linux/ds2784_battery.h
@@ -0,0 +1,29 @@
+/* include/linux/ds2784_battery.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_DS2784_BATTERY_H
+#define __LINUX_DS2784_BATTERY_H
+
+#ifdef __KERNEL__
+
+struct ds2784_platform_data {
+	int (*charge)(int on, int fast);
+	void *w1_slave;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_DS2784_BATTERY_H */
diff --git a/include/linux/elan_i2c.h b/include/linux/elan_i2c.h
new file mode 100644
index 0000000..41a9936
--- /dev/null
+++ b/include/linux/elan_i2c.h
@@ -0,0 +1,17 @@
+#ifndef ELAN_I2C_H
+#define ELAN_I2C_H
+
+#define ELAN_8232_I2C_NAME "elan-touch"
+
+struct elan_i2c_platform_data {
+	uint16_t version;
+	int abs_x_min;
+	int abs_x_max;
+	int abs_y_min;
+	int abs_y_max;
+	int intr_gpio;
+	int (*power)(int on);
+};
+
+#endif
+
diff --git a/include/linux/lightsensor.h b/include/linux/lightsensor.h
new file mode 100644
index 0000000..501074f
--- /dev/null
+++ b/include/linux/lightsensor.h
@@ -0,0 +1,28 @@
+/* include/linux/lightsensor.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Iliyan Malchev <malchev@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.
+ *
+ */
+
+#ifndef __LINUX_LIGHTSENSOR_H
+#define __LINUX_LIGHTSENSOR_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define LIGHTSENSOR_IOCTL_MAGIC 'l'
+
+#define LIGHTSENSOR_IOCTL_GET_ENABLED _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *)
+#define LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *)
+
+#endif
diff --git a/include/linux/mfd/pm8058.h b/include/linux/mfd/pm8058.h
new file mode 100644
index 0000000..4e0ffdd
--- /dev/null
+++ b/include/linux/mfd/pm8058.h
@@ -0,0 +1,186 @@
+/* include/linux/mfd/pm8058.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_MFD_PM8058_CORE_H
+#define __LINUX_MFD_PM8058_CORE_H
+
+#include <mach/irqs.h>
+
+#define PM8058_NUM_GPIO_IRQS		40
+#define PM8058_NUM_MPP_IRQS		12
+#define PM8058_NUM_KEYPAD_IRQS		2
+#define PM8058_NUM_CHARGER_IRQS		7
+#define PM8058_NUM_IRQS			(PM8058_NUM_GPIO_IRQS + \
+					 PM8058_NUM_MPP_IRQS + \
+					 PM8058_NUM_KEYPAD_IRQS + \
+					 PM8058_NUM_CHARGER_IRQS)
+
+/* be careful if you change this since this is used to map irq <-> gpio */
+#define PM8058_FIRST_GPIO_IRQ		0
+#define PM8058_FIRST_MPP_IRQ		(PM8058_FIRST_GPIO_IRQ + \
+					 PM8058_NUM_GPIO_IRQS)
+#define PM8058_FIRST_KEYPAD_IRQ		(PM8058_FIRST_MPP_IRQ + \
+					 PM8058_NUM_MPP_IRQS)
+#define PM8058_FIRST_CHARGER_IRQ	(PM8058_FIRST_KEYPAD_IRQ + \
+					 PM8058_NUM_KEYPAD_IRQS)
+
+#define PM8058_KEYPAD_IRQ		(PM8058_FIRST_KEYPAD_IRQ + 0)
+#define PM8058_KEYPAD_STUCK_IRQ		(PM8058_FIRST_KEYPAD_IRQ + 1)
+
+#define PM8058_CHGVAL_IRQ		(PM8058_FIRST_CHARGER_IRQ + 0)
+#define PM8058_CHGEND_IRQ		(PM8058_FIRST_CHARGER_IRQ + 1)
+#define PM8058_FASTCHG_IRQ		(PM8058_FIRST_CHARGER_IRQ + 2)
+#define PM8058_CHGFAIL_IRQ		(PM8058_FIRST_CHARGER_IRQ + 5)
+#define PM8058_CHGDONE_IRQ		(PM8058_FIRST_CHARGER_IRQ + 6)
+
+#define PM8058_GPIO_TO_IRQ(base,gpio)	(PM8058_FIRST_GPIO_IRQ + \
+					 (base) + (gpio))
+
+/* these need to match the irq counts/offsets above above */
+#define PM8058_FIRST_GPIO		PM8058_FIRST_GPIO_IRQ
+#define PM8058_NUM_GPIOS		PM8058_NUM_GPIO_IRQS
+#define PM8058_FIRST_MPP		PM8058_FIRST_MPP_IRQ
+#define PM8058_NUM_MPP			PM8058_NUM_MPP_IRQS
+
+#define PM8058_GPIO(base,gpio)		((base) + (gpio) + PM8058_FIRST_GPIO)
+/*#define PM8058_MPP(base,mpp)		((base) + (mpp) + PM8058_FIRST_MPP)*/
+
+struct pm8058_keypad_platform_data {
+	const char		*name;
+	int			num_drv;
+	int			num_sns;
+	/* delay in ms = 1 << scan_delay_shift, 0-7 */
+	int			scan_delay_shift;
+	/* # of 32kHz clock cycles, 1-4 */
+	int			drv_hold_clks;
+	/* in increments of 5ms, max 20ms */
+	int			debounce_ms;
+
+	/* size must be num_drv * num_sns
+	 * index is (drv * num_sns + sns) */
+	const unsigned short	*keymap;
+
+	int			(*init)(struct device *dev);
+};
+
+struct pm8058_charger_platform_data {
+	/* function to call on vbus detect */
+	void			(*vbus_present)(bool present);
+
+	int			(*charge)(u32 max_current, bool is_ac);
+
+	char			**supplied_to;
+	int			num_supplicants;
+};
+
+struct pm8058_platform_data {
+	unsigned int				irq_base;
+	unsigned int				gpio_base;
+	int					(*init)(struct device *dev);
+
+	/* child devices */
+	struct pm8058_keypad_platform_data	*keypad_pdata;
+	struct pm8058_charger_platform_data	*charger_pdata;
+};
+
+#define PM8058_GPIO_VIN_SRC_VPH_PWR	0x0 /* VDD_L6_L7 */
+#define PM8058_GPIO_VIN_SRC_VREG_BB	0x1 /* VDD_L3_L4_L5 */
+#define PM8058_GPIO_VIN_SRC_VREG_S3	0x2 /* VDD_L0_L1_LVS, 1.8V */
+#define PM8058_GPIO_VIN_SRC_VREG_L3	0x3 /* 1.8V or 2.85 */
+#define PM8058_GPIO_VIN_SRC_VREG_L7	0x4 /* 1.8V */
+#define PM8058_GPIO_VIN_SRC_VREG_L6	0x5 /* 3.3V */
+#define PM8058_GPIO_VIN_SRC_VREG_L5	0x6 /* 2.85V */
+#define PM8058_GPIO_VIN_SRC_VREG_L2	0x7 /* 2.6V */
+
+#define PM8058_GPIO_INPUT		0x01
+#define PM8058_GPIO_OUTPUT		0x02
+#define PM8058_GPIO_OUTPUT_HIGH 	0x04
+
+#define PM8058_GPIO_STRENGTH_OFF	0x0
+#define PM8058_GPIO_STRENGTH_HIGH	0x1
+#define PM8058_GPIO_STRENGTH_MED	0x2
+#define PM8058_GPIO_STRENGTH_LOW	0x3
+
+#define	PM8058_GPIO_PULL_UP_30		0x0
+#define	PM8058_GPIO_PULL_UP_1P5		0x1
+#define	PM8058_GPIO_PULL_UP_31P5	0x2
+#define	PM8058_GPIO_PULL_UP_1P5_30	0x3
+#define	PM8058_GPIO_PULL_DOWN		0x4
+#define	PM8058_GPIO_PULL_NONE		0x5
+
+#define PM8058_GPIO_FUNC_NORMAL		0x0
+#define PM8058_GPIO_FUNC_PAIRED		0x1
+#define PM8058_GPIO_FUNC_1		0x2
+#define PM8058_GPIO_FUNC_2		0x3
+
+/* gpio pin flags */
+#define PM8058_GPIO_OPEN_DRAIN		0x10
+#define PM8058_GPIO_HIGH_Z		0x20
+#define PM8058_GPIO_INV_IRQ_POL		0x40
+#define PM8058_GPIO_CONFIGURED		0x80 /* FOR INTERNAL USE ONLY */
+
+struct pm8058_pin_config {
+	u8		vin_src;
+	u8		dir;
+	u8		pull_up;
+	u8		strength;
+	u8		func;
+	u8		flags;
+};
+
+#define PM8058_GPIO_PIN_CONFIG(v,d,p,s,fn,fl) \
+	{ \
+		.vin_src	= (v), \
+		.dir		= (d), \
+		.pull_up	= (p), \
+		.strength	= (s), \
+		.func		= (fn), \
+		.flags		= (fl), \
+	}
+
+#ifdef CONFIG_PM8058
+int pm8058_readb(struct device *dev, u16 addr, u8 *val);
+int pm8058_writeb(struct device *dev, u16 addr, u8 val);
+int pm8058_write_buf(struct device *dev, u16 addr, u8 *buf, int cnt);
+int pm8058_read_buf(struct device *dev, u16 addr, u8 *buf, int cnt);
+int pm8058_gpio_mux_cfg(struct device *dev, unsigned int gpio,
+			struct pm8058_pin_config *cfg);
+int pm8058_gpio_mux(unsigned int gpio, struct pm8058_pin_config *cfg);
+int pm8058_irq_get_status(struct device *dev, unsigned int irq);
+#else
+static inline int pm8058_readb(struct device *dev, u16 addr, u8 *val)
+{ return 0; }
+static inline int pm8058_writeb(struct device *dev, u16 addr, u8 val)
+{ return 0; }
+static inline int pm8058_write_buf(struct device *dev, u16 addr, u8 *buf,
+				   int cnt) { return 0; }
+static inline int pm8058_read_buf(struct device *dev, u16 addr, u8 *buf,
+				  int cnt) { return 0; }
+static inline int pm8058_gpio_mux_cfg(struct device *dev, unsigned int gpio,
+			struct pm8058_pin_config *cfg) { return 0; }
+static inline int pm8058_gpio_mux(unsigned int gpio,
+			struct pm8058_pin_config *cfg) { return 0; }
+static inline int pm8058_irq_get_status(struct device *dev, unsigned int irq)
+{ return 0; }
+#endif
+
+#ifdef CONFIG_CHARGER_PM8058
+void pm8058_notify_charger_connected(int status);
+#else
+static inline void pm8058_notify_charger_connected(int status) {}
+#endif
+
+#endif
diff --git a/include/linux/msm_adsp.h b/include/linux/msm_adsp.h
new file mode 100644
index 0000000..12f219e
--- /dev/null
+++ b/include/linux/msm_adsp.h
@@ -0,0 +1,84 @@
+/* include/linux/msm_adsp.h
+ *
+ * Copyright (c) QUALCOMM Incorporated
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Iliyan Malchev <ibm@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 __LINUX_MSM_ADSP_H
+#define __LINUX_MSM_ADSP_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define ADSP_IOCTL_MAGIC 'q'
+
+/* ADSP_IOCTL_WRITE_COMMAND */
+struct adsp_command_t {
+	uint16_t queue;
+	uint32_t len;		/* bytes */
+	uint8_t *data;
+};
+
+/* ADSP_IOCTL_GET_EVENT */
+struct adsp_event_t {
+	uint16_t type;		/* 1 == event (RPC), 0 == message (adsp) */
+	uint32_t timeout_ms;	/* -1 for infinite, 0 for immediate return */
+	uint16_t msg_id;
+	uint16_t flags;		/* 1 == 16--bit event, 0 == 32-bit event */
+	uint32_t len;		/* size in, number of bytes out */
+	uint8_t *data;
+};
+
+#define ADSP_IOCTL_ENABLE \
+	_IOR(ADSP_IOCTL_MAGIC, 1, unsigned)
+
+#define ADSP_IOCTL_DISABLE \
+	_IOR(ADSP_IOCTL_MAGIC, 2, unsigned)
+
+#define ADSP_IOCTL_DISABLE_ACK \
+	_IOR(ADSP_IOCTL_MAGIC, 3, unsigned)
+
+#define ADSP_IOCTL_WRITE_COMMAND \
+	_IOR(ADSP_IOCTL_MAGIC, 4, struct adsp_command_t *)
+
+#define ADSP_IOCTL_GET_EVENT \
+	_IOWR(ADSP_IOCTL_MAGIC, 5, struct adsp_event_data_t *)
+
+#define ADSP_IOCTL_SET_CLKRATE \
+	_IOR(ADSP_IOCTL_MAGIC, 6, unsigned)
+
+#define ADSP_IOCTL_DISABLE_EVENT_RSP \
+	_IOR(ADSP_IOCTL_MAGIC, 10, unsigned)
+
+struct adsp_pmem_info {
+        int fd;
+        void *vaddr;
+};
+
+#define ADSP_IOCTL_REGISTER_PMEM \
+	_IOW(ADSP_IOCTL_MAGIC, 13, unsigned)
+
+#define ADSP_IOCTL_UNREGISTER_PMEM \
+	_IOW(ADSP_IOCTL_MAGIC, 14, unsigned)
+
+/* Cause any further GET_EVENT ioctls to fail (-ENODEV)
+ * until the device is closed and reopened.  Useful for
+ * terminating event dispatch threads
+ */
+#define ADSP_IOCTL_ABORT_EVENT_READ \
+	_IOW(ADSP_IOCTL_MAGIC, 15, unsigned)
+
+#define ADSP_IOCTL_LINK_TASK \
+	_IOW(ADSP_IOCTL_MAGIC, 16, unsigned)
+
+#endif
diff --git a/include/linux/msm_audio.h b/include/linux/msm_audio.h
new file mode 100644
index 0000000..5875c99
--- /dev/null
+++ b/include/linux/msm_audio.h
@@ -0,0 +1,120 @@
+/* include/linux/msm_audio.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_MSM_AUDIO_H
+#define __LINUX_MSM_AUDIO_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/sizes.h>
+
+/* PCM Audio */
+
+#define AUDIO_IOCTL_MAGIC 'a'
+
+#define AUDIO_START        _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned)
+#define AUDIO_STOP         _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned)
+#define AUDIO_FLUSH        _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned)
+#define AUDIO_GET_CONFIG   _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned)
+#define AUDIO_SET_CONFIG   _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned)
+#define AUDIO_GET_STATS    _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned)
+#define AUDIO_ENABLE_AUDPP _IOW(AUDIO_IOCTL_MAGIC, 6, unsigned)
+#define AUDIO_SET_ADRC     _IOW(AUDIO_IOCTL_MAGIC, 7, unsigned)
+#define AUDIO_SET_EQ       _IOW(AUDIO_IOCTL_MAGIC, 8, unsigned)
+#define AUDIO_SET_RX_IIR   _IOW(AUDIO_IOCTL_MAGIC, 9, unsigned)
+#define AUDIO_SET_VOLUME   _IOW(AUDIO_IOCTL_MAGIC, 10, unsigned)
+#define AUDIO_ENABLE_AUDPRE  _IOW(AUDIO_IOCTL_MAGIC, 11, unsigned)
+#define AUDIO_SET_AGC        _IOW(AUDIO_IOCTL_MAGIC, 12, unsigned)
+#define AUDIO_SET_NS         _IOW(AUDIO_IOCTL_MAGIC, 13, unsigned)
+#define AUDIO_SET_TX_IIR     _IOW(AUDIO_IOCTL_MAGIC, 14, unsigned)
+#define AUDIO_PAUSE	     _IOW(AUDIO_IOCTL_MAGIC, 15, unsigned)
+#define AUDIO_GET_PCM_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 30, unsigned)
+#define AUDIO_SET_PCM_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 31, unsigned)
+#define AUDIO_SWITCH_DEVICE  _IOW(AUDIO_IOCTL_MAGIC, 32, unsigned)
+#define AUDIO_SET_MUTE       _IOW(AUDIO_IOCTL_MAGIC, 33, unsigned)
+#define AUDIO_UPDATE_ACDB    _IOW(AUDIO_IOCTL_MAGIC, 34, unsigned)
+#define AUDIO_START_VOICE    _IOW(AUDIO_IOCTL_MAGIC, 35, unsigned)
+#define AUDIO_STOP_VOICE     _IOW(AUDIO_IOCTL_MAGIC, 36, unsigned)
+#define AUDIO_REINIT_ACDB    _IOW(AUDIO_IOCTL_MAGIC, 39, unsigned)
+
+#define	AUDIO_MAX_COMMON_IOCTL_NUM	100
+
+#define	AUDIO_MAX_COMMON_IOCTL_NUM	100
+
+struct msm_audio_config {
+	uint32_t buffer_size;
+	uint32_t buffer_count;
+	uint32_t channel_count;
+	uint32_t sample_rate;
+	uint32_t type;
+	uint32_t unused[3];
+};
+
+struct msm_audio_stats {
+	uint32_t byte_count;
+	uint32_t sample_count;
+	uint32_t unused[2];
+};
+
+/* Audio routing */
+
+#define SND_IOCTL_MAGIC 's'
+
+#define SND_MUTE_UNMUTED 0
+#define SND_MUTE_MUTED   1
+
+struct msm_snd_device_config {
+	uint32_t device;
+	uint32_t ear_mute;
+	uint32_t mic_mute;
+};
+
+#define SND_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_device_config *)
+
+#define SND_METHOD_VOICE 0
+
+struct msm_snd_volume_config {
+	uint32_t device;
+	uint32_t method;
+	uint32_t volume;
+};
+
+#define SND_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_snd_volume_config *)
+
+/* Returns the number of SND endpoints supported. */
+
+#define SND_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned *)
+
+struct msm_snd_endpoint {
+	int id; /* input and output */
+	char name[64]; /* output only */
+};
+
+/* Takes an index between 0 and one less than the number returned by
+ * SND_GET_NUM_ENDPOINTS, and returns the SND index and name of a
+ * SND endpoint.  On input, the .id field contains the number of the
+ * endpoint, and on exit it contains the SND index, while .name contains
+ * the description of the endpoint.
+ */
+
+#define SND_GET_ENDPOINT _IOWR(SND_IOCTL_MAGIC, 5, struct msm_snd_endpoint *)
+
+struct msm_audio_pcm_config {
+	uint32_t pcm_feedback;	/* 0 - disable > 0 - enable */
+	uint32_t buffer_count;	/* Number of buffers to allocate */
+	uint32_t buffer_size;	/* Size of buffer for capturing of
+				   PCM samples */
+};
+#endif
diff --git a/include/linux/msm_hw3d.h b/include/linux/msm_hw3d.h
new file mode 100644
index 0000000..9178526
--- /dev/null
+++ b/include/linux/msm_hw3d.h
@@ -0,0 +1,61 @@
+/* include/linux/msm_hw3d.h
+ *
+ * Copyright (C) 2007 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.
+ *
+ */
+
+
+#ifndef _MSM_HW3D_H_
+#define _MSM_HW3D_H_
+
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+
+struct hw3d_region;
+
+#define HW3D_IOCTL_MAGIC		'h'
+#define HW3D_WAIT_FOR_REVOKE		_IO(HW3D_IOCTL_MAGIC, 0x80)
+#define HW3D_WAIT_FOR_INTERRUPT		_IO(HW3D_IOCTL_MAGIC, 0x81)
+#define HW3D_GET_REGIONS		\
+			_IOR(HW3D_IOCTL_MAGIC, 0x82, struct hw3d_region *)
+
+#define HW3D_REGION_OFFSET(id)		((((uint32_t)(id)) & 0xf) << 28)
+#define HW3D_REGION_ID(addr)		(((uint32_t)(addr) >> 28) & 0xf)
+#define HW3D_OFFSET_IN_REGION(addr)	((uint32_t)(addr) & ~(0xfUL << 28))
+
+enum {
+	HW3D_EBI		= 0,
+	HW3D_SMI		= 1,
+	HW3D_REGS		= 2,
+
+	HW3D_NUM_REGIONS	= HW3D_REGS + 1,
+};
+
+struct hw3d_region {
+	unsigned long		phys;
+	unsigned long		map_offset;
+	unsigned long		len;
+};
+
+#ifdef CONFIG_MSM_HW3D
+int get_msm_hw3d_file(int fd, uint32_t *offs, unsigned long *pbase,
+		      unsigned long *len, struct file **filp);
+void put_msm_hw3d_file(struct file *file);
+bool is_msm_hw3d_file(struct file *file);
+#else
+int get_msm_hw3d_file(int fd, uint32_t *offs, unsigned long *pbase,
+		      unsigned long *len, struct file **filp) { return -1; }
+void put_msm_hw3d_file(struct file *file) {}
+bool is_msm_hw3d_file(struct file *file) { return false; }
+#endif
+
+#endif /* _MSM_HW3D_H_ */
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
new file mode 100644
index 0000000..28a1e1e8
--- /dev/null
+++ b/include/linux/msm_kgsl.h
@@ -0,0 +1,286 @@
+/*
+ * (C) Copyright Advanced Micro Devices, Inc. 2002, 2007
+ * Copyright (c) 2008-2009 QUALCOMM USA, INC.
+ * 
+ * All source code in this file is licensed under the following license
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ * 
+ * This 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+#ifndef _MSM_KGSL_H
+#define _MSM_KGSL_H
+
+/*context flags */
+#define KGSL_CONTEXT_SAVE_GMEM		1
+#define KGSL_CONTEXT_NO_GMEM_ALLOC	2
+
+/* generic flag values */
+#define KGSL_FLAGS_NORMALMODE  0x00000000
+#define KGSL_FLAGS_SAFEMODE    0x00000001
+#define KGSL_FLAGS_INITIALIZED0 0x00000002
+#define KGSL_FLAGS_INITIALIZED 0x00000004
+#define KGSL_FLAGS_STARTED     0x00000008
+#define KGSL_FLAGS_ACTIVE      0x00000010
+#define KGSL_FLAGS_RESERVED0   0x00000020
+#define KGSL_FLAGS_RESERVED1   0x00000040
+#define KGSL_FLAGS_RESERVED2   0x00000080
+
+/* device id */
+enum kgsl_deviceid {
+	KGSL_DEVICE_ANY		= 0x00000000,
+	KGSL_DEVICE_YAMATO	= 0x00000001,
+	KGSL_DEVICE_G12		= 0x00000002,
+	KGSL_DEVICE_MAX		= 0x00000002
+};
+
+struct kgsl_devinfo {
+
+	unsigned int device_id;
+	/* chip revision id
+	* coreid:8 majorrev:8 minorrev:8 patch:8
+	*/
+	unsigned int chip_id;
+	unsigned int mmu_enabled;
+	unsigned int gmem_gpubaseaddr;
+	/* if gmem_hostbaseaddr is NULL, we would know its not mapped into
+	 * mmio space */
+	unsigned int gmem_hostbaseaddr;
+	unsigned int gmem_sizebytes;
+};
+
+/* this structure defines the region of memory that can be mmap()ed from this
+   driver. The timestamp fields are volatile because they are written by the
+   GPU
+*/
+struct kgsl_devmemstore {
+	volatile unsigned int soptimestamp;
+	unsigned int sbz;
+	volatile unsigned int eoptimestamp;
+	unsigned int sbz2;
+	volatile unsigned int ts_cmp_enable;
+	unsigned int sbz3;
+	volatile unsigned int ref_wait_ts;
+	unsigned int sbz4;
+};
+
+#define KGSL_DEVICE_MEMSTORE_OFFSET(field) \
+	offsetof(struct kgsl_devmemstore, field)
+
+
+/* timestamp id*/
+enum kgsl_timestamp_type {
+	KGSL_TIMESTAMP_CONSUMED = 0x00000001, /* start-of-pipeline timestamp */
+	KGSL_TIMESTAMP_RETIRED  = 0x00000002, /* end-of-pipeline timestamp*/
+	KGSL_TIMESTAMP_MAX      = 0x00000002,
+};
+
+/* property types - used with kgsl_device_getproperty */
+enum kgsl_property_type {
+	KGSL_PROP_DEVICE_INFO     = 0x00000001,
+	KGSL_PROP_DEVICE_SHADOW   = 0x00000002,
+	KGSL_PROP_DEVICE_POWER    = 0x00000003,
+	KGSL_PROP_SHMEM           = 0x00000004,
+	KGSL_PROP_SHMEM_APERTURES = 0x00000005,
+	KGSL_PROP_MMU_ENABLE 	  = 0x00000006,
+	KGSL_PROP_INTERRUPT_WAITS = 0x00000007,
+};
+
+struct kgsl_shadowprop {
+	unsigned int gpuaddr;
+	unsigned int size;
+	unsigned int flags; /* contains KGSL_FLAGS_ values */
+};
+
+/* ioctls */
+#define KGSL_IOC_TYPE 0x09
+
+/* get misc info about the GPU
+   type should be a value from enum kgsl_property_type
+   value points to a structure that varies based on type
+   sizebytes is sizeof() that structure
+   for KGSL_PROP_DEVICE_INFO, use struct kgsl_devinfo
+   this structure contaings hardware versioning info.
+   for KGSL_PROP_DEVICE_SHADOW, use struct kgsl_shadowprop
+   this is used to find mmap() offset and sizes for mapping
+   struct kgsl_memstore into userspace.
+*/
+struct kgsl_device_getproperty {
+	unsigned int type;
+	void  *value;
+	unsigned int sizebytes;
+};
+
+#define IOCTL_KGSL_DEVICE_GETPROPERTY \
+	_IOWR(KGSL_IOC_TYPE, 0x2, struct kgsl_device_getproperty)
+
+
+/* read a GPU register.
+   offsetwords it the 32 bit word offset from the beginning of the
+   GPU register space.
+ */
+struct kgsl_device_regread {
+	unsigned int offsetwords;
+	unsigned int value; /* output param */
+};
+
+#define IOCTL_KGSL_DEVICE_REGREAD \
+	_IOWR(KGSL_IOC_TYPE, 0x3, struct kgsl_device_regread)
+
+
+/* block until the GPU has executed past a given timestamp
+ * timeout is in milliseconds.
+ */
+struct kgsl_device_waittimestamp {
+	unsigned int timestamp;
+	unsigned int timeout;
+};
+
+#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP \
+	_IOW(KGSL_IOC_TYPE, 0x6, struct kgsl_device_waittimestamp)
+
+
+/* issue indirect commands to the GPU.
+ * drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE
+ * ibaddr and sizedwords must specify a subset of a buffer created
+ * with IOCTL_KGSL_SHAREDMEM_FROM_PMEM
+ * flags may be a mask of KGSL_CONTEXT_ values
+ * timestamp is a returned counter value which can be passed to
+ * other ioctls to determine when the commands have been executed by
+ * the GPU.
+ */
+struct kgsl_ringbuffer_issueibcmds {
+	unsigned int drawctxt_id;
+	unsigned int ibaddr;
+	unsigned int sizedwords;
+	unsigned int timestamp; /*output param */
+	unsigned int flags;
+};
+
+#define IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS \
+	_IOWR(KGSL_IOC_TYPE, 0x10, struct kgsl_ringbuffer_issueibcmds)
+
+/* read the most recently executed timestamp value
+ * type should be a value from enum kgsl_timestamp_type
+ */
+struct kgsl_cmdstream_readtimestamp {
+	unsigned int type;
+	unsigned int timestamp; /*output param */
+};
+
+#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP \
+	_IOR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp)
+
+/* free memory when the GPU reaches a given timestamp.
+ * gpuaddr specify a memory region created by a
+ * IOCTL_KGSL_SHAREDMEM_FROM_PMEM call
+ * type should be a value from enum kgsl_timestamp_type
+ */
+struct kgsl_cmdstream_freememontimestamp {
+	unsigned int gpuaddr;
+	unsigned int type;
+	unsigned int timestamp;
+};
+
+#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP \
+	_IOR(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp)
+
+/* create a draw context, which is used to preserve GPU state.
+ * The flags field may contain a mask KGSL_CONTEXT_*  values
+ */
+struct kgsl_drawctxt_create {
+	unsigned int flags;
+	unsigned int drawctxt_id; /*output param */
+};
+
+#define IOCTL_KGSL_DRAWCTXT_CREATE \
+	_IOWR(KGSL_IOC_TYPE, 0x13, struct kgsl_drawctxt_create)
+
+/* destroy a draw context */
+struct kgsl_drawctxt_destroy {
+	unsigned int drawctxt_id;
+};
+
+#define IOCTL_KGSL_DRAWCTXT_DESTROY \
+	_IOW(KGSL_IOC_TYPE, 0x14, struct kgsl_drawctxt_destroy)
+
+/* add a block of pmem or fb into the GPU address space */
+struct kgsl_sharedmem_from_pmem {
+	int pmem_fd;
+	unsigned int gpuaddr;	/*output param */
+	unsigned int len;
+	unsigned int offset;
+};
+
+#define IOCTL_KGSL_SHAREDMEM_FROM_PMEM \
+	_IOWR(KGSL_IOC_TYPE, 0x20, struct kgsl_sharedmem_from_pmem)
+
+/* remove memory from the GPU's address space */
+struct kgsl_sharedmem_free {
+	unsigned int gpuaddr;
+};
+
+#define IOCTL_KGSL_SHAREDMEM_FREE \
+	_IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free)
+
+struct kgsl_gmem_desc {
+	unsigned int x;
+	unsigned int y;
+	unsigned int width;
+	unsigned int height;
+	unsigned int pitch;
+};
+
+struct kgsl_buffer_desc {
+	void 		*hostptr;
+	unsigned int	gpuaddr;
+	int		size;
+	unsigned int	format;
+	unsigned int  	pitch;
+	unsigned int  	enabled;
+};
+
+struct kgsl_bind_gmem_shadow {
+	unsigned int drawctxt_id;
+	struct kgsl_gmem_desc gmem_desc;
+	unsigned int shadow_x;
+	unsigned int shadow_y;
+	struct kgsl_buffer_desc shadow_buffer;
+	unsigned int buffer_id;
+};
+
+#define IOCTL_KGSL_DRAWCTXT_BIND_GMEM_SHADOW \
+    _IOW(KGSL_IOC_TYPE, 0x22, struct kgsl_bind_gmem_shadow)
+
+/* add a block of memory into the GPU address space */
+struct kgsl_sharedmem_from_vmalloc {
+	unsigned int gpuaddr;	/*output param */
+	unsigned int hostptr;
+	/* If set from user space then will attempt to
+	 * allocate even if low watermark is crossed */
+	int force_no_low_watermark;
+};
+
+#define IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC \
+	_IOWR(KGSL_IOC_TYPE, 0x23, struct kgsl_sharedmem_from_vmalloc)
+
+#define IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE \
+	_IOW(KGSL_IOC_TYPE, 0x24, struct kgsl_sharedmem_free)
+
+struct kgsl_drawctxt_set_bin_base_offset {
+	unsigned int drawctxt_id;
+	unsigned int offset;
+};
+
+#define IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET \
+	_IOW(KGSL_IOC_TYPE, 0x25, struct kgsl_drawctxt_set_bin_base_offset)
+
+#endif /* _MSM_KGSL_H */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index d11fe0f..03d8fde 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -32,6 +32,7 @@
 	MDP_Y_CBCR_H2V1,	/* Y and CrCb, pseduo planar w/ Cr is in MSB */
 	MDP_RGBA_8888,		/* ARGB 888 */
 	MDP_BGRA_8888,		/* ABGR 888 */
+	MDP_RGBX_8888,		/* RGBX 888 */
 	MDP_IMGTYPE_LIMIT	/* Non valid image type after this enum */
 };
 
@@ -47,8 +48,10 @@
 #define MDP_ROT_90	0x4
 #define MDP_ROT_180	(MDP_FLIP_UD|MDP_FLIP_LR)
 #define MDP_ROT_270	(MDP_ROT_90|MDP_FLIP_UD|MDP_FLIP_LR)
+#define MDP_ROT_MASK	0x7
 #define MDP_DITHER	0x8
 #define MDP_BLUR	0x10
+#define MDP_BLEND_FG_PREMULT 0x20000
 
 #define MDP_TRANSP_NOP	0xffffffff
 #define MDP_ALPHA_NOP	0xff
diff --git a/include/linux/msm_q6vdec.h b/include/linux/msm_q6vdec.h
new file mode 100644
index 0000000..1dca803
--- /dev/null
+++ b/include/linux/msm_q6vdec.h
@@ -0,0 +1,230 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT 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.
+ *
+ */
+
+#ifndef _MSM_VDEC_H_
+#define _MSM_VDEC_H_
+
+#include <linux/types.h>
+
+#define VDEC_IOCTL_MAGIC 'v'
+
+#define VDEC_IOCTL_INITIALIZE   _IOWR(VDEC_IOCTL_MAGIC, 1, struct vdec_init)
+#define VDEC_IOCTL_SETBUFFERS   _IOW(VDEC_IOCTL_MAGIC, 2, struct vdec_buffer)
+#define VDEC_IOCTL_QUEUE        _IOWR(VDEC_IOCTL_MAGIC, 3, \
+					struct vdec_input_buf)
+#define VDEC_IOCTL_REUSEFRAMEBUFFER  _IOW(VDEC_IOCTL_MAGIC, 4, unsigned int)
+#define VDEC_IOCTL_FLUSH        _IOW(VDEC_IOCTL_MAGIC, 5, unsigned int)
+#define VDEC_IOCTL_EOS          _IO(VDEC_IOCTL_MAGIC, 6)
+#define VDEC_IOCTL_GETMSG       _IOR(VDEC_IOCTL_MAGIC, 7, struct vdec_msg)
+#define VDEC_IOCTL_CLOSE        _IO(VDEC_IOCTL_MAGIC, 8)
+#define VDEC_IOCTL_FREEBUFFERS  _IOW(VDEC_IOCTL_MAGIC, 9, struct vdec_buf_info)
+#define VDEC_IOCTL_GETDECATTRIBUTES   _IOR(VDEC_IOCTL_MAGIC, 10, \
+						struct vdec_dec_attributes)
+
+enum {
+	VDEC_FRAME_DECODE_OK,
+	VDEC_FRAME_DECODE_ERR,
+	VDEC_FATAL_ERR,
+	VDEC_FLUSH_FINISH,
+	VDEC_EOS,
+	VDEC_FRAME_FLUSH,
+	VDEC_STREAM_SWITCH,
+	VDEC_SUSPEND_FINISH,
+	VDEC_BUFFER_CONSUMED
+};
+
+enum {
+	VDEC_FLUSH_INPUT,
+	VDEC_FLUSH_OUTPUT,
+	VDEC_FLUSH_ALL
+};
+
+enum {
+	VDEC_BUFFER_TYPE_INPUT,
+	VDEC_BUFFER_TYPE_OUTPUT,
+	VDEC_BUFFER_TYPE_INTERNAL1,
+	VDEC_BUFFER_TYPE_INTERNAL2,
+};
+
+enum {
+	VDEC_QUEUE_SUCCESS,
+	VDEC_QUEUE_FAILED,
+	VDEC_QUEUE_BADSTATE,
+};
+
+struct vdec_input_buf_info {
+	u32 offset;
+	u32 data;
+	u32 size;
+	int timestamp_lo;
+	int timestamp_hi;
+	int avsync_state;
+	u32 flags;
+};
+
+struct vdec_buf_desc {
+	u32 bufsize;
+	u32 num_min_buffers;
+	u32 num_max_buffers;
+};
+
+struct vdec_buf_req {
+	u32 max_input_queue_size;
+	struct vdec_buf_desc input;
+	struct vdec_buf_desc output;
+	struct vdec_buf_desc dec_req1;
+	struct vdec_buf_desc dec_req2;
+};
+
+struct vdec_region_info {
+	u32 src_id;
+	u32 offset;
+	u32 size;
+};
+
+struct vdec_config {
+	u32 fourcc;		/* video format */
+	u32 width;		/* source width */
+	u32 height;		/* source height */
+	u32 order;		/* render decoder order */
+	u32 notify_enable;	/* enable notify input buffer done event */
+	u32 vc1_rowbase;
+	u32 h264_startcode_detect;
+	u32 h264_nal_len_size;
+	u32 postproc_flag;
+	u32 fruc_enable;
+	u32 reserved;
+};
+
+struct vdec_vc1_panscan_regions {
+	int num;
+	int width[4];
+	int height[4];
+	int xoffset[4];
+	int yoffset[4];
+};
+
+struct vdec_cropping_window {
+	u32 x1;
+	u32 y1;
+	u32 x2;
+	u32 y2;
+};
+
+struct vdec_frame_info {
+	u32 status;		/* video decode status */
+	u32 offset;		/* buffer offset */
+	u32 data1;		/* user data field 1 */
+	u32 data2;		/* user data field 2 */
+	int timestamp_lo;	/* lower 32 bits timestamp, in msec */
+	int timestamp_hi;	/* higher 32 bits timestamp, in msec */
+	int cal_timestamp_lo;	/* lower 32 bits cal timestamp, in msec */
+	int cal_timestamp_hi;	/* higher  32 bits cal timestamp, in msec */
+	u32 dec_width;		/* frame roi width */
+	u32 dec_height;		/* frame roi height */
+	struct vdec_cropping_window cwin;	/* The frame cropping window */
+	u32 picture_type[2];	/* picture coding type */
+	u32 picture_format;	/* picture coding format */
+	u32 vc1_rangeY;		/* luma range mapping */
+	u32 vc1_rangeUV;	/* chroma range mapping */
+	u32 picture_resolution;	/* scaling factor */
+	u32 frame_disp_repeat;	/* how often repeated by disp */
+	u32 repeat_first_field;	/* repeat 1st field after 2nd */
+	u32 top_field_first;	/* top field displayed first */
+	u32 interframe_interp;	/* not for inter-frame interp */
+	struct vdec_vc1_panscan_regions panscan;	/* pan region */
+	u32 concealed_macblk_num;	/* number of concealed macro blk */
+	u32 flags;		/* input flags */
+	u32 performance_stats;	/* performance statistics returned by decoder */
+	u32 data3;		/* user data field 3 */
+};
+
+struct vdec_buf_info {
+	u32 buf_type;
+	struct vdec_region_info region;
+	u32 num_buf;
+	u32 islast;
+};
+
+struct vdec_buffer {
+	u32 pmem_id;
+	struct vdec_buf_info buf;
+};
+
+struct vdec_sequence {
+	u8 *header;
+	u32 len;
+};
+
+struct vdec_config_sps {
+	struct vdec_config cfg;
+	struct vdec_sequence seq;
+};
+
+#define VDEC_MSG_REUSEINPUTBUFFER 	1
+#define VDEC_MSG_FRAMEDONE 		2
+
+struct vdec_msg {
+	u32 id;
+
+	union {
+		/* id = VDEC_MSG_REUSEINPUTBUFFER */
+		u32 buf_id;
+		/* id = VDEC_MSG_FRAMEDONE */
+		struct vdec_frame_info vfr_info;
+	};
+};
+
+struct vdec_init {
+	struct vdec_config_sps sps_cfg;
+	struct vdec_buf_req *buf_req;
+};
+
+struct vdec_input_buf {
+	u32 pmem_id;
+	struct vdec_input_buf_info buffer;
+	struct vdec_queue_status *queue_status;
+};
+
+struct vdec_queue_status {
+	u32 status;
+};
+
+struct vdec_dec_attributes {
+	u32 fourcc;
+	u32 profile;
+	u32 level;
+	u32 dec_pic_width;
+	u32 dec_pic_height;
+	struct vdec_buf_desc input;
+	struct vdec_buf_desc output;
+	struct vdec_buf_desc dec_req1;
+	struct vdec_buf_desc dec_req2;
+};
+
+#endif /* _MSM_VDEC_H_ */
diff --git a/include/linux/msm_q6venc.h b/include/linux/msm_q6venc.h
new file mode 100755
index 0000000..db31332
--- /dev/null
+++ b/include/linux/msm_q6venc.h
@@ -0,0 +1,321 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT 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.
+ *
+ */
+
+#ifndef _MSM_VENC_H_
+#define _MSM_VENC_H_
+
+#include <linux/types.h>
+
+#define VENC_MAX_RECON_BUFFERS 2
+
+#define VENC_FLAG_EOS                   0x00000001
+#define VENC_FLAG_END_OF_FRAME          0x00000010
+#define VENC_FLAG_SYNC_FRAME            0x00000020
+#define VENC_FLAG_EXTRA_DATA            0x00000040
+#define VENC_FLAG_CODEC_CONFIG          0x00000080
+
+enum venc_flush_type {
+	VENC_FLUSH_INPUT,
+	VENC_FLUSH_OUTPUT,
+	VENC_FLUSH_ALL
+};
+
+enum venc_state_type {
+	VENC_STATE_PAUSE = 0x1,
+	VENC_STATE_START = 0x2,
+	VENC_STATE_STOP = 0x4
+};
+
+enum venc_event_type_enum {
+	VENC_EVENT_START_STATUS,
+	VENC_EVENT_STOP_STATUS,
+	VENC_EVENT_SUSPEND_STATUS,
+	VENC_EVENT_RESUME_STATUS,
+	VENC_EVENT_FLUSH_STATUS,
+	VENC_EVENT_RELEASE_INPUT,
+	VENC_EVENT_DELIVER_OUTPUT,
+	VENC_EVENT_UNKNOWN_STATUS
+};
+
+enum venc_status_code {
+	VENC_STATUS_SUCCESS,
+	VENC_STATUS_ERROR,
+	VENC_STATUS_INVALID_STATE,
+	VENC_STATUS_FLUSHING,
+	VENC_STATUS_INVALID_PARAM,
+	VENC_STATUS_CMD_QUEUE_FULL,
+	VENC_STATUS_CRITICAL,
+	VENC_STATUS_INSUFFICIENT_RESOURCES,
+	VENC_STATUS_TIMEOUT
+};
+
+enum venc_msg_code {
+	VENC_MSG_INDICATION,
+	VENC_MSG_INPUT_BUFFER_DONE,
+	VENC_MSG_OUTPUT_BUFFER_DONE,
+	VENC_MSG_NEED_OUTPUT_BUFFER,
+	VENC_MSG_FLUSH,
+	VENC_MSG_START,
+	VENC_MSG_STOP,
+	VENC_MSG_PAUSE,
+	VENC_MSG_RESUME,
+	VENC_MSG_STOP_READING_MSG
+};
+
+enum venc_error_code {
+	VENC_S_SUCCESS,
+	VENC_S_EFAIL,
+	VENC_S_EFATAL,
+	VENC_S_EBADPARAM,
+	VENC_S_EINVALSTATE,
+	VENC_S_ENOSWRES,
+	VENC_S_ENOHWRES,
+	VENC_S_EBUFFREQ,
+	VENC_S_EINVALCMD,
+	VENC_S_ETIMEOUT,
+	VENC_S_ENOREATMPT,
+	VENC_S_ENOPREREQ,
+	VENC_S_ECMDQFULL,
+	VENC_S_ENOTSUPP,
+	VENC_S_ENOTIMPL,
+	VENC_S_ENOTPMEM,
+	VENC_S_EFLUSHED,
+	VENC_S_EINSUFBUF,
+	VENC_S_ESAMESTATE,
+	VENC_S_EINVALTRANS
+};
+
+enum venc_mem_region_enum {
+	VENC_PMEM_EBI1,
+	VENC_PMEM_SMI
+};
+
+struct venc_buf_type {
+	unsigned int region;
+	unsigned int phys;
+	unsigned int size;
+	int offset;
+};
+
+struct venc_qp_range {
+	unsigned int min_qp;
+	unsigned int max_qp;
+};
+
+struct venc_frame_rate {
+	unsigned int frame_rate_num;
+	unsigned int frame_rate_den;
+};
+
+struct venc_slice_info {
+	unsigned int slice_mode;
+	unsigned int units_per_slice;
+};
+
+struct venc_extra_data {
+	unsigned int slice_extra_data_flag;
+	unsigned int slice_client_data1;
+	unsigned int slice_client_data2;
+	unsigned int slice_client_data3;
+	unsigned int none_extra_data_flag;
+	unsigned int none_client_data1;
+	unsigned int none_client_data2;
+	unsigned int none_client_data3;
+};
+
+struct venc_common_config {
+	unsigned int standard;
+	unsigned int input_frame_height;
+	unsigned int input_frame_width;
+	unsigned int output_frame_height;
+	unsigned int output_frame_width;
+	unsigned int rotation_angle;
+	unsigned int intra_period;
+	unsigned int rate_control;
+	struct venc_frame_rate frame_rate;
+	unsigned int bitrate;
+	struct venc_qp_range qp_range;
+	unsigned int iframe_qp;
+	unsigned int pframe_qp;
+	struct venc_slice_info slice_config;
+	struct venc_extra_data extra_data;
+};
+
+struct venc_nonio_buf_config {
+	struct venc_buf_type recon_buf1;
+	struct venc_buf_type recon_buf2;
+	struct venc_buf_type wb_buf;
+	struct venc_buf_type cmd_buf;
+	struct venc_buf_type vlc_buf;
+};
+
+struct venc_mpeg4_config {
+	unsigned int profile;
+	unsigned int level;
+	unsigned int time_resolution;
+	unsigned int ac_prediction;
+	unsigned int hec_interval;
+	unsigned int data_partition;
+	unsigned int short_header;
+	unsigned int rvlc_enable;
+};
+
+struct venc_h263_config {
+	unsigned int profile;
+	unsigned int level;
+};
+
+struct venc_h264_config {
+	unsigned int profile;
+	unsigned int level;
+	unsigned int max_nal;
+	unsigned int idr_period;
+};
+
+struct venc_pmem {
+	int src;
+	int fd;
+	unsigned int offset;
+	void *virt;
+	void *phys;
+	unsigned int size;
+};
+
+struct venc_buffer {
+	unsigned char *ptr_buffer;
+	unsigned int size;
+	unsigned int len;
+	unsigned int offset;
+	long long time_stamp;
+	unsigned int flags;
+	unsigned int client_data;
+};
+
+struct venc_buffers {
+	struct venc_pmem recon_buf[VENC_MAX_RECON_BUFFERS];
+	struct venc_pmem wb_buf;
+	struct venc_pmem cmd_buf;
+	struct venc_pmem vlc_buf;
+};
+
+struct venc_buffer_flush {
+	unsigned int flush_mode;
+};
+
+union venc_msg_data {
+	struct venc_buffer buf;
+	struct venc_buffer_flush flush_ret;
+};
+
+struct venc_msg {
+	unsigned int status_code;
+	unsigned int msg_code;
+	union venc_msg_data msg_data;
+	unsigned int msg_data_size;
+};
+
+union venc_codec_config {
+	struct venc_mpeg4_config mpeg4_params;
+	struct venc_h263_config h263_params;
+	struct venc_h264_config h264_params;
+};
+
+struct venc_q6_config {
+	struct venc_common_config config_params;
+	union venc_codec_config codec_params;
+	struct venc_nonio_buf_config buf_params;
+	void *callback_event;
+};
+
+struct venc_hdr_config {
+	struct venc_common_config config_params;
+	union venc_codec_config codec_params;
+};
+
+struct venc_init_config {
+	struct venc_q6_config q6_config;
+	struct venc_buffers q6_bufs;
+};
+
+struct venc_seq_config {
+	int size;
+	struct venc_pmem buf;
+	struct venc_q6_config q6_config;
+};
+
+#define VENC_IOCTL_MAGIC 'V'
+
+#define VENC_IOCTL_CMD_READ_NEXT_MSG \
+	_IOWR(VENC_IOCTL_MAGIC, 1, struct venc_msg)
+
+#define VENC_IOCTL_CMD_STOP_READ_MSG  _IO(VENC_IOCTL_MAGIC, 2)
+
+#define VENC_IOCTL_SET_INPUT_BUFFER \
+	_IOW(VENC_IOCTL_MAGIC, 3, struct venc_pmem)
+
+#define VENC_IOCTL_SET_OUTPUT_BUFFER \
+	_IOW(VENC_IOCTL_MAGIC, 4, struct venc_pmem)
+
+#define VENC_IOCTL_CMD_START _IOW(VENC_IOCTL_MAGIC, 5, struct venc_init_config)
+
+#define VENC_IOCTL_CMD_ENCODE_FRAME \
+	_IOW(VENC_IOCTL_MAGIC, 6, struct venc_buffer)
+
+#define VENC_IOCTL_CMD_FILL_OUTPUT_BUFFER \
+	_IOW(VENC_IOCTL_MAGIC, 7, struct venc_buffer)
+
+#define VENC_IOCTL_CMD_FLUSH \
+	_IOW(VENC_IOCTL_MAGIC, 8, struct venc_buffer_flush)
+
+#define VENC_IOCTL_CMD_PAUSE _IO(VENC_IOCTL_MAGIC, 9)
+
+#define VENC_IOCTL_CMD_RESUME _IO(VENC_IOCTL_MAGIC, 10)
+
+#define VENC_IOCTL_CMD_STOP _IO(VENC_IOCTL_MAGIC, 11)
+
+#define VENC_IOCTL_SET_INTRA_PERIOD \
+	_IOW(VENC_IOCTL_MAGIC, 12, int)
+
+#define VENC_IOCTL_CMD_REQUEST_IFRAME _IO(VENC_IOCTL_MAGIC, 13)
+
+#define VENC_IOCTL_GET_SEQUENCE_HDR \
+	_IOWR(VENC_IOCTL_MAGIC, 14, struct venc_seq_config)
+
+#define VENC_IOCTL_SET_INTRA_REFRESH \
+	_IOW(VENC_IOCTL_MAGIC, 15, int)
+
+#define VENC_IOCTL_SET_FRAME_RATE \
+	_IOW(VENC_IOCTL_MAGIC, 16, struct venc_frame_rate)
+
+#define VENC_IOCTL_SET_TARGET_BITRATE \
+	_IOW(VENC_IOCTL_MAGIC, 17, int)
+
+#define VENC_IOCTL_SET_QP_RANGE \
+	_IOW(VENC_IOCTL_MAGIC, 18, struct venc_qp_range)
+
+#endif
diff --git a/include/linux/msm_rpcrouter.h b/include/linux/msm_rpcrouter.h
new file mode 100644
index 0000000..62141a0
--- /dev/null
+++ b/include/linux/msm_rpcrouter.h
@@ -0,0 +1,47 @@
+/* include/linux/msm_rpcrouter.h
+ *
+ * Copyright (c) QUALCOMM Incorporated
+ * Copyright (C) 2007 Google, Inc.
+ * Author: San Mehat <san@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 __LINUX_MSM_RPCROUTER_H
+#define __LINUX_MSM_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define RPC_ROUTER_VERSION_V1 0x00010000
+
+struct rpcrouter_ioctl_server_args {
+	uint32_t prog;
+	uint32_t vers;
+};
+
+#define RPC_ROUTER_IOCTL_MAGIC (0xC1)
+
+#define RPC_ROUTER_IOCTL_GET_VERSION \
+	_IOR(RPC_ROUTER_IOCTL_MAGIC, 0, unsigned int)
+
+#define RPC_ROUTER_IOCTL_GET_MTU \
+	_IOR(RPC_ROUTER_IOCTL_MAGIC, 1, unsigned int)
+
+#define RPC_ROUTER_IOCTL_REGISTER_SERVER \
+	_IOWR(RPC_ROUTER_IOCTL_MAGIC, 2, unsigned int)
+
+#define RPC_ROUTER_IOCTL_UNREGISTER_SERVER \
+	_IOWR(RPC_ROUTER_IOCTL_MAGIC, 3, unsigned int)
+
+#define RPC_ROUTER_IOCTL_GET_MINOR_VERSION \
+	_IOW(RPC_ROUTER_IOCTL_MAGIC, 4, unsigned int)
+
+#endif
diff --git a/include/linux/msm_vidc_dec.h b/include/linux/msm_vidc_dec.h
new file mode 100644
index 0000000..5d6233a
--- /dev/null
+++ b/include/linux/msm_vidc_dec.h
@@ -0,0 +1,526 @@
+/* Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+
+#ifndef _MSM_VIDC_DEC_H_
+#define _MSM_VIDC_DEC_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* STATUS CODES */
+/* Base value for status codes */
+#define VDEC_S_BASE	0x40000000
+/* Success */
+#define VDEC_S_SUCCESS	(VDEC_S_BASE)
+/* General failure */
+#define VDEC_S_EFAIL	(VDEC_S_BASE + 1)
+/* Fatal irrecoverable  failure. Need to  tear down session. */
+#define VDEC_S_EFATAL   (VDEC_S_BASE + 2)
+/* Error detected in the passed  parameters */
+#define VDEC_S_EBADPARAM	(VDEC_S_BASE + 3)
+/* Command called in invalid  state. */
+#define VDEC_S_EINVALSTATE	(VDEC_S_BASE + 4)
+ /* Insufficient OS  resources - thread, memory etc. */
+#define VDEC_S_ENOSWRES	(VDEC_S_BASE + 5)
+ /* Insufficient HW resources -  core capacity  maxed  out. */
+#define VDEC_S_ENOHWRES	(VDEC_S_BASE + 6)
+/* Invalid command  called */
+#define VDEC_S_EINVALCMD	(VDEC_S_BASE + 7)
+/* Command timeout. */
+#define VDEC_S_ETIMEOUT	(VDEC_S_BASE + 8)
+/* Pre-requirement is  not met for API. */
+#define VDEC_S_ENOPREREQ	(VDEC_S_BASE + 9)
+/* Command queue is full. */
+#define VDEC_S_ECMDQFULL	(VDEC_S_BASE + 10)
+/* Command is not supported  by this driver */
+#define VDEC_S_ENOTSUPP	(VDEC_S_BASE + 11)
+/* Command is not implemented by thedriver. */
+#define VDEC_S_ENOTIMPL	(VDEC_S_BASE + 12)
+/* Command is not implemented by the driver.  */
+#define VDEC_S_BUSY	(VDEC_S_BASE + 13)
+
+#define VDEC_INTF_VER   	1
+#define VDEC_MSG_BASE	0x0000000
+/* Codes to identify asynchronous message responses and events that driver
+  wants to communicate to the app.*/
+#define VDEC_MSG_INVALID	(VDEC_MSG_BASE + 0)
+#define VDEC_MSG_RESP_INPUT_BUFFER_DONE	(VDEC_MSG_BASE + 1)
+#define VDEC_MSG_RESP_OUTPUT_BUFFER_DONE	(VDEC_MSG_BASE + 2)
+#define VDEC_MSG_RESP_INPUT_FLUSHED	(VDEC_MSG_BASE + 3)
+#define VDEC_MSG_RESP_OUTPUT_FLUSHED	(VDEC_MSG_BASE + 4)
+#define VDEC_MSG_RESP_FLUSH_INPUT_DONE	(VDEC_MSG_BASE + 5)
+#define VDEC_MSG_RESP_FLUSH_OUTPUT_DONE	(VDEC_MSG_BASE + 6)
+#define VDEC_MSG_RESP_START_DONE	(VDEC_MSG_BASE + 7)
+#define VDEC_MSG_RESP_STOP_DONE	(VDEC_MSG_BASE + 8)
+#define VDEC_MSG_RESP_PAUSE_DONE	(VDEC_MSG_BASE + 9)
+#define VDEC_MSG_RESP_RESUME_DONE	(VDEC_MSG_BASE + 10)
+#define VDEC_MSG_RESP_RESOURCE_LOADED	(VDEC_MSG_BASE + 11)
+#define VDEC_EVT_RESOURCES_LOST	(VDEC_MSG_BASE + 12)
+#define VDEC_MSG_EVT_CONFIG_CHANGED	(VDEC_MSG_BASE + 13)
+#define VDEC_MSG_EVT_HW_ERROR	(VDEC_MSG_BASE + 14)
+
+/*Buffer flags bits masks.*/
+#define VDEC_BUFFERFLAG_EOS	0x00000001
+#define VDEC_BUFFERFLAG_DECODEONLY	0x00000004
+#define VDEC_BUFFERFLAG_DATACORRUPT	0x00000008
+#define VDEC_BUFFERFLAG_ENDOFFRAME	0x00000010
+#define VDEC_BUFFERFLAG_SYNCFRAME	0x00000020
+#define VDEC_BUFFERFLAG_EXTRADATA	0x00000040
+#define VDEC_BUFFERFLAG_CODECCONFIG	0x00000080
+
+/*Post processing flags bit masks*/
+#define VDEC_EXTRADATA_QP	0x00000001
+#define VDEC_EXTRADATA_SEI	0x00000002
+#define VDEC_EXTRADATA_VUI	0x00000004
+#define VDEC_EXTRADATA_MB_ERROR_MAP 0x00000008
+
+#define VDEC_CMDBASE	0x800
+#define VDEC_CMD_SET_INTF_VERSION	(VDEC_CMDBASE)
+
+#define VDEC_IOCTL_MAGIC 'v'
+
+struct vdec_ioctl_msg {
+	void __user *in;
+	void __user *out;
+};
+
+/* CMD params: InputParam:enum vdec_codec
+   OutputParam: struct vdec_profile_level*/
+#define VDEC_IOCTL_GET_PROFILE_LEVEL_SUPPORTED \
+	_IOWR(VDEC_IOCTL_MAGIC, 0, struct vdec_ioctl_msg)
+
+/*CMD params:InputParam: NULL
+  OutputParam: uint32_t(bitmask)*/
+#define VDEC_IOCTL_GET_INTERLACE_FORMAT \
+	_IOR(VDEC_IOCTL_MAGIC, 1, struct vdec_ioctl_msg)
+
+/* CMD params: InputParam:  enum vdec_codec
+   OutputParam: struct vdec_profile_level*/
+#define VDEC_IOCTL_GET_CURRENT_PROFILE_LEVEL \
+	_IOWR(VDEC_IOCTL_MAGIC, 2, struct vdec_ioctl_msg)
+
+/*CMD params: SET: InputParam: enum vdec_output_fromat  OutputParam: NULL
+  GET:  InputParam: NULL OutputParam: enum vdec_output_fromat*/
+#define VDEC_IOCTL_SET_OUTPUT_FORMAT \
+	_IOWR(VDEC_IOCTL_MAGIC, 3, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_OUTPUT_FORMAT \
+	_IOWR(VDEC_IOCTL_MAGIC, 4, struct vdec_ioctl_msg)
+
+/*CMD params: SET: InputParam: enum vdec_codec OutputParam: NULL
+  GET: InputParam: NULL OutputParam: enum vdec_codec*/
+#define VDEC_IOCTL_SET_CODEC \
+	_IOW(VDEC_IOCTL_MAGIC, 5, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_CODEC \
+	_IOR(VDEC_IOCTL_MAGIC, 6, struct vdec_ioctl_msg)
+
+/*CMD params: SET: InputParam: struct vdec_picsize outputparam: NULL
+ GET: InputParam: NULL outputparam: struct vdec_picsize*/
+#define VDEC_IOCTL_SET_PICRES \
+	_IOW(VDEC_IOCTL_MAGIC, 7, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_PICRES \
+	_IOR(VDEC_IOCTL_MAGIC, 8, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_EXTRADATA \
+	_IOW(VDEC_IOCTL_MAGIC, 9, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_EXTRADATA \
+	_IOR(VDEC_IOCTL_MAGIC, 10, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_SEQUENCE_HEADER \
+	_IOW(VDEC_IOCTL_MAGIC, 11, struct vdec_ioctl_msg)
+
+/* CMD params: SET: InputParam - vdec_allocatorproperty, OutputParam - NULL
+   GET: InputParam - NULL, OutputParam - vdec_allocatorproperty*/
+#define VDEC_IOCTL_SET_BUFFER_REQ \
+	_IOW(VDEC_IOCTL_MAGIC, 12, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_BUFFER_REQ \
+	_IOR(VDEC_IOCTL_MAGIC, 13, struct vdec_ioctl_msg)
+/* CMD params: InputParam - vdec_buffer, OutputParam - uint8_t** */
+#define VDEC_IOCTL_ALLOCATE_BUFFER \
+	_IOWR(VDEC_IOCTL_MAGIC, 14, struct vdec_ioctl_msg)
+/* CMD params: InputParam - uint8_t *, OutputParam - NULL.*/
+#define VDEC_IOCTL_FREE_BUFFER \
+	_IOW(VDEC_IOCTL_MAGIC, 15, struct vdec_ioctl_msg)
+
+/*CMD params: CMD: InputParam - struct vdec_setbuffer_cmd, OutputParam - NULL*/
+#define VDEC_IOCTL_SET_BUFFER \
+	_IOW(VDEC_IOCTL_MAGIC, 16, struct vdec_ioctl_msg)
+
+/* CMD params: InputParam - struct vdec_fillbuffer_cmd, OutputParam - NULL*/
+#define VDEC_IOCTL_FILL_OUTPUT_BUFFER \
+	_IOW(VDEC_IOCTL_MAGIC, 17, struct vdec_ioctl_msg)
+
+/*CMD params: InputParam - struct vdec_frameinfo , OutputParam - NULL*/
+#define VDEC_IOCTL_DECODE_FRAME \
+	_IOW(VDEC_IOCTL_MAGIC, 18, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_LOAD_RESOURCES _IO(VDEC_IOCTL_MAGIC, 19)
+#define VDEC_IOCTL_CMD_START _IO(VDEC_IOCTL_MAGIC, 20)
+#define VDEC_IOCTL_CMD_STOP _IO(VDEC_IOCTL_MAGIC, 21)
+#define VDEC_IOCTL_CMD_PAUSE _IO(VDEC_IOCTL_MAGIC, 22)
+#define VDEC_IOCTL_CMD_RESUME _IO(VDEC_IOCTL_MAGIC, 23)
+
+/*CMD params: InputParam - enum vdec_bufferflush , OutputParam - NULL */
+#define VDEC_IOCTL_CMD_FLUSH _IOW(VDEC_IOCTL_MAGIC, 24, struct vdec_ioctl_msg)
+
+/* ========================================================
+ * IOCTL for getting asynchronous notification from driver
+ * ========================================================*/
+
+/*IOCTL params: InputParam - NULL, OutputParam - struct vdec_msginfo*/
+#define VDEC_IOCTL_GET_NEXT_MSG \
+	_IOR(VDEC_IOCTL_MAGIC, 25, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_STOP_NEXT_MSG _IO(VDEC_IOCTL_MAGIC, 26)
+
+#define VDEC_IOCTL_GET_NUMBER_INSTANCES \
+	_IOR(VDEC_IOCTL_MAGIC, 27, struct vdec_ioctl_msg)
+
+enum vdec_picture {
+	PICTURE_TYPE_I,
+	PICTURE_TYPE_P,
+	PICTURE_TYPE_B,
+	PICTURE_TYPE_BI,
+	PICTURE_TYPE_SKIP,
+	PICTURE_TYPE_UNKNOWN
+};
+
+enum vdec_buffer {
+	VDEC_BUFFER_TYPE_INPUT,
+	VDEC_BUFFER_TYPE_OUTPUT
+};
+
+struct vdec_allocatorproperty {
+	enum vdec_buffer buffer_type;
+	uint32_t mincount;
+	uint32_t maxcount;
+	uint32_t actualcount;
+	uint32_t buffer_size;
+	uint32_t alignment;
+	uint32_t buf_poolid;
+};
+
+struct vdec_bufferpayload {
+	void __user *addr;
+	size_t sz;
+	int pmem_fd;
+	size_t offset;
+	size_t mmaped_sz;
+};
+
+struct vdec_setbuffer_cmd {
+	enum vdec_buffer buffer_type;
+	struct vdec_bufferpayload buffer;
+};
+
+struct vdec_fillbuffer_cmd {
+	struct vdec_bufferpayload buffer;
+	void *client_data;
+};
+
+enum vdec_bufferflush {
+	VDEC_FLUSH_TYPE_INPUT,
+	VDEC_FLUSH_TYPE_OUTPUT,
+	VDEC_FLUSH_TYPE_ALL
+};
+
+enum vdec_codec {
+	VDEC_CODECTYPE_H264 = 0x1,
+	VDEC_CODECTYPE_H263 = 0x2,
+	VDEC_CODECTYPE_MPEG4 = 0x3,
+	VDEC_CODECTYPE_DIVX_3 = 0x4,
+	VDEC_CODECTYPE_DIVX_4 = 0x5,
+	VDEC_CODECTYPE_DIVX_5 = 0x6,
+	VDEC_CODECTYPE_DIVX_6 = 0x7,
+	VDEC_CODECTYPE_XVID = 0x8,
+	VDEC_CODECTYPE_MPEG1 = 0x9,
+	VDEC_CODECTYPE_MPEG2 = 0xa,
+	VDEC_CODECTYPE_VC1 = 0xb,
+	VDEC_CODECTYPE_VC1_RCV = 0xc
+};
+
+enum vdec_mpeg2_profile {
+	VDEC_MPEG2ProfileSimple = 0x1,
+	VDEC_MPEG2ProfileMain = 0x2,
+	VDEC_MPEG2Profile422 = 0x4,
+	VDEC_MPEG2ProfileSNR = 0x8,
+	VDEC_MPEG2ProfileSpatial = 0x10,
+	VDEC_MPEG2ProfileHigh = 0x20,
+	VDEC_MPEG2ProfileKhronosExtensions = 0x6F000000,
+	VDEC_MPEG2ProfileVendorStartUnused = 0x7F000000,
+	VDEC_MPEG2ProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_mpeg2_level {
+
+	VDEC_MPEG2LevelLL = 0x1,
+	VDEC_MPEG2LevelML = 0x2,
+	VDEC_MPEG2LevelH14 = 0x4,
+	VDEC_MPEG2LevelHL = 0x8,
+	VDEC_MPEG2LevelKhronosExtensions = 0x6F000000,
+	VDEC_MPEG2LevelVendorStartUnused = 0x7F000000,
+	VDEC_MPEG2LevelMax = 0x7FFFFFFF
+};
+
+enum vdec_mpeg4_profile {
+	VDEC_MPEG4ProfileSimple = 0x01,
+	VDEC_MPEG4ProfileSimpleScalable = 0x02,
+	VDEC_MPEG4ProfileCore = 0x04,
+	VDEC_MPEG4ProfileMain = 0x08,
+	VDEC_MPEG4ProfileNbit = 0x10,
+	VDEC_MPEG4ProfileScalableTexture = 0x20,
+	VDEC_MPEG4ProfileSimpleFace = 0x40,
+	VDEC_MPEG4ProfileSimpleFBA = 0x80,
+	VDEC_MPEG4ProfileBasicAnimated = 0x100,
+	VDEC_MPEG4ProfileHybrid = 0x200,
+	VDEC_MPEG4ProfileAdvancedRealTime = 0x400,
+	VDEC_MPEG4ProfileCoreScalable = 0x800,
+	VDEC_MPEG4ProfileAdvancedCoding = 0x1000,
+	VDEC_MPEG4ProfileAdvancedCore = 0x2000,
+	VDEC_MPEG4ProfileAdvancedScalable = 0x4000,
+	VDEC_MPEG4ProfileAdvancedSimple = 0x8000,
+	VDEC_MPEG4ProfileKhronosExtensions = 0x6F000000,
+	VDEC_MPEG4ProfileVendorStartUnused = 0x7F000000,
+	VDEC_MPEG4ProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_mpeg4_level {
+	VDEC_MPEG4Level0 = 0x01,
+	VDEC_MPEG4Level0b = 0x02,
+	VDEC_MPEG4Level1 = 0x04,
+	VDEC_MPEG4Level2 = 0x08,
+	VDEC_MPEG4Level3 = 0x10,
+	VDEC_MPEG4Level4 = 0x20,
+	VDEC_MPEG4Level4a = 0x40,
+	VDEC_MPEG4Level5 = 0x80,
+	VDEC_MPEG4LevelKhronosExtensions = 0x6F000000,
+	VDEC_MPEG4LevelVendorStartUnused = 0x7F000000,
+	VDEC_MPEG4LevelMax = 0x7FFFFFFF
+};
+
+enum vdec_avc_profile {
+	VDEC_AVCProfileBaseline = 0x01,
+	VDEC_AVCProfileMain = 0x02,
+	VDEC_AVCProfileExtended = 0x04,
+	VDEC_AVCProfileHigh = 0x08,
+	VDEC_AVCProfileHigh10 = 0x10,
+	VDEC_AVCProfileHigh422 = 0x20,
+	VDEC_AVCProfileHigh444 = 0x40,
+	VDEC_AVCProfileKhronosExtensions = 0x6F000000,
+	VDEC_AVCProfileVendorStartUnused = 0x7F000000,
+	VDEC_AVCProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_avc_level {
+	VDEC_AVCLevel1 = 0x01,
+	VDEC_AVCLevel1b = 0x02,
+	VDEC_AVCLevel11 = 0x04,
+	VDEC_AVCLevel12 = 0x08,
+	VDEC_AVCLevel13 = 0x10,
+	VDEC_AVCLevel2 = 0x20,
+	VDEC_AVCLevel21 = 0x40,
+	VDEC_AVCLevel22 = 0x80,
+	VDEC_AVCLevel3 = 0x100,
+	VDEC_AVCLevel31 = 0x200,
+	VDEC_AVCLevel32 = 0x400,
+	VDEC_AVCLevel4 = 0x800,
+	VDEC_AVCLevel41 = 0x1000,
+	VDEC_AVCLevel42 = 0x2000,
+	VDEC_AVCLevel5 = 0x4000,
+	VDEC_AVCLevel51 = 0x8000,
+	VDEC_AVCLevelKhronosExtensions = 0x6F000000,
+	VDEC_AVCLevelVendorStartUnused = 0x7F000000,
+	VDEC_AVCLevelMax = 0x7FFFFFFF
+};
+
+enum vdec_divx_profile {
+	VDEC_DIVXProfile_qMobile = 0x01,
+	VDEC_DIVXProfile_Mobile = 0x02,
+	VDEC_DIVXProfile_HD = 0x04,
+	VDEC_DIVXProfile_Handheld = 0x08,
+	VDEC_DIVXProfile_Portable = 0x10,
+	VDEC_DIVXProfile_HomeTheater = 0x20
+};
+
+enum vdec_xvid_profile {
+	VDEC_XVIDProfile_Simple = 0x1,
+	VDEC_XVIDProfile_Advanced_Realtime_Simple = 0x2,
+	VDEC_XVIDProfile_Advanced_Simple = 0x4
+};
+
+enum vdec_xvid_level {
+	VDEC_XVID_LEVEL_S_L0 = 0x1,
+	VDEC_XVID_LEVEL_S_L1 = 0x2,
+	VDEC_XVID_LEVEL_S_L2 = 0x4,
+	VDEC_XVID_LEVEL_S_L3 = 0x8,
+	VDEC_XVID_LEVEL_ARTS_L1 = 0x10,
+	VDEC_XVID_LEVEL_ARTS_L2 = 0x20,
+	VDEC_XVID_LEVEL_ARTS_L3 = 0x40,
+	VDEC_XVID_LEVEL_ARTS_L4 = 0x80,
+	VDEC_XVID_LEVEL_AS_L0 = 0x100,
+	VDEC_XVID_LEVEL_AS_L1 = 0x200,
+	VDEC_XVID_LEVEL_AS_L2 = 0x400,
+	VDEC_XVID_LEVEL_AS_L3 = 0x800,
+	VDEC_XVID_LEVEL_AS_L4 = 0x1000
+};
+
+enum vdec_h263profile {
+	VDEC_H263ProfileBaseline = 0x01,
+	VDEC_H263ProfileH320Coding = 0x02,
+	VDEC_H263ProfileBackwardCompatible = 0x04,
+	VDEC_H263ProfileISWV2 = 0x08,
+	VDEC_H263ProfileISWV3 = 0x10,
+	VDEC_H263ProfileHighCompression = 0x20,
+	VDEC_H263ProfileInternet = 0x40,
+	VDEC_H263ProfileInterlace = 0x80,
+	VDEC_H263ProfileHighLatency = 0x100,
+	VDEC_H263ProfileKhronosExtensions = 0x6F000000,
+	VDEC_H263ProfileVendorStartUnused = 0x7F000000,
+	VDEC_H263ProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_h263level {
+	VDEC_H263Level10 = 0x01,
+	VDEC_H263Level20 = 0x02,
+	VDEC_H263Level30 = 0x04,
+	VDEC_H263Level40 = 0x08,
+	VDEC_H263Level45 = 0x10,
+	VDEC_H263Level50 = 0x20,
+	VDEC_H263Level60 = 0x40,
+	VDEC_H263Level70 = 0x80,
+	VDEC_H263LevelKhronosExtensions = 0x6F000000,
+	VDEC_H263LevelVendorStartUnused = 0x7F000000,
+	VDEC_H263LevelMax = 0x7FFFFFFF
+};
+
+enum vdec_wmv_format {
+	VDEC_WMVFormatUnused = 0x01,
+	VDEC_WMVFormat7 = 0x02,
+	VDEC_WMVFormat8 = 0x04,
+	VDEC_WMVFormat9 = 0x08,
+	VDEC_WMFFormatKhronosExtensions = 0x6F000000,
+	VDEC_WMFFormatVendorStartUnused = 0x7F000000,
+	VDEC_WMVFormatMax = 0x7FFFFFFF
+};
+
+enum vdec_vc1_profile {
+	VDEC_VC1ProfileSimple = 0x1,
+	VDEC_VC1ProfileMain = 0x2,
+	VDEC_VC1ProfileAdvanced = 0x4
+};
+
+enum vdec_vc1_level {
+	VDEC_VC1_LEVEL_S_Low = 0x1,
+	VDEC_VC1_LEVEL_S_Medium = 0x2,
+	VDEC_VC1_LEVEL_M_Low = 0x4,
+	VDEC_VC1_LEVEL_M_Medium = 0x8,
+	VDEC_VC1_LEVEL_M_High = 0x10,
+	VDEC_VC1_LEVEL_A_L0 = 0x20,
+	VDEC_VC1_LEVEL_A_L1 = 0x40,
+	VDEC_VC1_LEVEL_A_L2 = 0x80,
+	VDEC_VC1_LEVEL_A_L3 = 0x100,
+	VDEC_VC1_LEVEL_A_L4 = 0x200
+};
+
+struct vdec_profile_level {
+	uint32_t profiles;
+	uint32_t levels;
+};
+
+enum vdec_interlaced_format {
+	VDEC_InterlaceFrameProgressive = 0x1,
+	VDEC_InterlaceInterleaveFrameTopFieldFirst = 0x2,
+	VDEC_InterlaceInterleaveFrameBottomFieldFirst = 0x4
+};
+
+enum vdec_output_format {
+	VDEC_YUV_FORMAT_NV12 = 0x1,
+	VDEC_YUV_FORMAT_TILE_4x2 = 0x2
+};
+
+struct vdec_picsize {
+	uint32_t frame_width;
+	uint32_t frame_height;
+	uint32_t stride;
+	uint32_t scan_lines;
+};
+
+struct vdec_seqheader {
+	void *addr;
+	size_t sz;
+	int pmem_fd;
+	size_t pmem_offset;
+};
+
+struct vdec_mberror {
+	uint8_t *ptr_errormap;
+	uint32_t err_mapsize;
+};
+
+struct vdec_input_frameinfo {
+	void __user *user_addr;
+	size_t offset;
+	size_t data_len;
+	uint32_t flags;
+	int64_t timestamp;
+	void *client_data;
+	int pmem_fd;
+	size_t pmem_offset;
+};
+
+struct vdec_framesize {
+	uint32_t   left;
+	uint32_t   top;
+	uint32_t   right;
+	uint32_t   bottom;
+};
+
+struct vdec_output_frameinfo {
+	phys_addr_t phys_addr;
+	void __user *user_addr;
+	uint32_t offset;
+	uint32_t len;
+	uint32_t flags;
+	int64_t time_stamp;
+	void *client_data;
+	void *input_frame_clientdata;
+	struct vdec_framesize framesize;
+};
+
+union vdec_msgdata {
+	struct vdec_output_frameinfo output_frame;
+	void *input_frame_clientdata;
+};
+
+struct vdec_msginfo {
+	uint32_t status_code;
+	uint32_t msgcode;
+	union vdec_msgdata msgdata;
+	uint32_t msgdatasize;
+};
+#endif /* end of macro _VDECDECODER_H_ */
diff --git a/include/linux/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
new file mode 100644
index 0000000..f7f398c
--- /dev/null
+++ b/include/linux/msm_vidc_enc.h
@@ -0,0 +1,592 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora Forum, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ *
+ */
+#ifndef _MSM_VIDC_ENC_H_
+#define _MSM_VIDC_ENC_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/** STATUS CODES*/
+/* Base value for status codes */
+#define VEN_S_BASE	0x00000000
+#define VEN_S_SUCCESS	(VEN_S_BASE)/* Success */
+#define VEN_S_EFAIL	(VEN_S_BASE+1)/* General failure */
+#define VEN_S_EFATAL	(VEN_S_BASE+2)/* Fatal irrecoverable failure*/
+#define VEN_S_EBADPARAM	(VEN_S_BASE+3)/* Error passed parameters*/
+/*Command called in invalid state*/
+#define VEN_S_EINVALSTATE	(VEN_S_BASE+4)
+#define VEN_S_ENOSWRES	(VEN_S_BASE+5)/* Insufficient OS resources*/
+#define VEN_S_ENOHWRES	(VEN_S_BASE+6)/*Insufficient HW resources */
+#define VEN_S_EBUFFREQ	(VEN_S_BASE+7)/* Buffer requirements were not met*/
+#define VEN_S_EINVALCMD	(VEN_S_BASE+8)/* Invalid command called */
+#define VEN_S_ETIMEOUT	(VEN_S_BASE+9)/* Command timeout. */
+/*Re-attempt was made when multiple invocation not supported for API.*/
+#define VEN_S_ENOREATMPT	(VEN_S_BASE+10)
+#define VEN_S_ENOPREREQ	(VEN_S_BASE+11)/*Pre-requirement is not met for API*/
+#define VEN_S_ECMDQFULL	(VEN_S_BASE+12)/*Command queue is full*/
+#define VEN_S_ENOTSUPP	(VEN_S_BASE+13)/*Command not supported*/
+#define VEN_S_ENOTIMPL	(VEN_S_BASE+14)/*Command not implemented.*/
+#define VEN_S_ENOTPMEM	(VEN_S_BASE+15)/*Buffer is not from PMEM*/
+#define VEN_S_EFLUSHED	(VEN_S_BASE+16)/*returned buffer was flushed*/
+#define VEN_S_EINSUFBUF	(VEN_S_BASE+17)/*provided buffer size insufficient*/
+#define VEN_S_ESAMESTATE	(VEN_S_BASE+18)
+#define VEN_S_EINVALTRANS	(VEN_S_BASE+19)
+
+#define VEN_INTF_VER			 1
+
+/*Asynchronous messages from driver*/
+#define VEN_MSG_INDICATION	0
+#define VEN_MSG_INPUT_BUFFER_DONE	1
+#define VEN_MSG_OUTPUT_BUFFER_DONE	2
+#define VEN_MSG_NEED_OUTPUT_BUFFER	3
+#define VEN_MSG_FLUSH_INPUT_DONE	4
+#define VEN_MSG_FLUSH_OUPUT_DONE	5
+#define VEN_MSG_START	6
+#define VEN_MSG_STOP	7
+#define VEN_MSG_PAUSE	8
+#define VEN_MSG_RESUME	9
+#define VEN_MSG_STOP_READING_MSG	10
+
+/*Buffer flags bits masks*/
+#define VEN_BUFFLAG_EOS	0x00000001
+#define VEN_BUFFLAG_ENDOFFRAME	0x00000010
+#define VEN_BUFFLAG_SYNCFRAME	0x00000020
+#define VEN_BUFFLAG_EXTRADATA	0x00000040
+#define VEN_BUFFLAG_CODECCONFIG	0x00000080
+
+/*ENCODER CONFIGURATION CONSTANTS*/
+
+/*Encoded video frame types*/
+#define VEN_FRAME_TYPE_I	1/* I frame type */
+#define VEN_FRAME_TYPE_P	2/* P frame type */
+#define VEN_FRAME_TYPE_B	3/* B frame type */
+
+/*Video codec types*/
+#define VEN_CODEC_MPEG4	1/* MPEG4 Codec */
+#define VEN_CODEC_H264	2/* H.264 Codec */
+#define VEN_CODEC_H263	3/* H.263 Codec */
+
+/*Video codec profile types.*/
+#define VEN_PROFILE_MPEG4_SP	1/* 1 - MPEG4 SP profile  */
+#define VEN_PROFILE_MPEG4_ASP	2/* 2 - MPEG4 ASP profile */
+#define VEN_PROFILE_H264_BASELINE	3/* 3 - H264 Baseline profile	*/
+#define VEN_PROFILE_H264_MAIN	4/* 4 - H264 Main profile*/
+#define VEN_PROFILE_H264_HIGH	5/* 5 - H264 High profile*/
+#define VEN_PROFILE_H263_BASELINE	6/* 6 - H263 Baseline profile */
+
+/*Video codec profile level types.*/
+#define VEN_LEVEL_MPEG4_0	0x1/* MPEG4 Level 0	 */
+#define VEN_LEVEL_MPEG4_1	0x2/* MPEG4 Level 1	 */
+#define VEN_LEVEL_MPEG4_2	0x3/* MPEG4 Level 2	 */
+#define VEN_LEVEL_MPEG4_3	0x4/* MPEG4 Level 3	 */
+#define VEN_LEVEL_MPEG4_4	0x5/* MPEG4 Level 4	 */
+#define VEN_LEVEL_MPEG4_5	0x6/* MPEG4 Level 5	 */
+#define VEN_LEVEL_MPEG4_3b	0x7/* MPEG4 Level 3b  */
+#define VEN_LEVEL_MPEG4_6	0x8/* MPEG4 Level 6	 */
+
+#define VEN_LEVEL_H264_1	0x9/* H.264 Level 1	 */
+#define VEN_LEVEL_H264_1b 0xA/* H.264 Level 1b  */
+#define VEN_LEVEL_H264_1p1	0xB/* H.264 Level 1.1 */
+#define VEN_LEVEL_H264_1p2	0xC/* H.264 Level 1.2 */
+#define VEN_LEVEL_H264_1p3	0xD/* H.264 Level 1.3 */
+#define VEN_LEVEL_H264_2	0xE/* H.264 Level 2	 */
+#define VEN_LEVEL_H264_2p1	0xF/* H.264 Level 2.1 */
+#define VEN_LEVEL_H264_2p2	0x10/* H.264 Level 2.2 */
+#define VEN_LEVEL_H264_3	0x11/* H.264 Level 3	 */
+#define VEN_LEVEL_H264_3p1	0x12/* H.264 Level 3.1 */
+
+#define VEN_LEVEL_H263_10	0x13/* H.263 Level 10  */
+#define VEN_LEVEL_H263_20	0x14/* H.263 Level 20  */
+#define VEN_LEVEL_H263_30	0x15/* H.263 Level 30  */
+#define VEN_LEVEL_H263_40	0x16/* H.263 Level 40  */
+#define VEN_LEVEL_H263_45	0x17/* H.263 Level 45  */
+#define VEN_LEVEL_H263_50	0x18/* H.263 Level 50  */
+#define VEN_LEVEL_H263_60	0x19/* H.263 Level 60  */
+#define VEN_LEVEL_H263_70	0x1A/* H.263 Level 70  */
+
+/*Entropy coding model selection for H.264 encoder.*/
+#define VEN_ENTROPY_MODEL_CAVLC	1
+#define VEN_ENTROPY_MODEL_CABAC	2
+/*Cabac model number (0,1,2) for encoder.*/
+#define VEN_CABAC_MODEL_0	1/* CABAC Model 0. */
+#define VEN_CABAC_MODEL_1	2/* CABAC Model 1. */
+#define VEN_CABAC_MODEL_2	3/* CABAC Model 2. */
+
+/*Deblocking filter control type for encoder.*/
+#define VEN_DB_DISABLE	1/* 1 - Disable deblocking filter*/
+#define VEN_DB_ALL_BLKG_BNDRY	2/* 2 - All blocking boundary filtering*/
+#define VEN_DB_SKIP_SLICE_BNDRY	3/* 3 - Filtering except sliceboundary*/
+
+/*Different methods of Multi slice selection.*/
+#define VEN_MSLICE_OFF	1
+#define VEN_MSLICE_CNT_MB	2 /*number of MBscount per slice*/
+#define VEN_MSLICE_CNT_BYTE	3 /*number of bytes count per slice.*/
+#define VEN_MSLICE_GOB	4 /*Multi slice by GOB for H.263 only.*/
+
+/*Different modes for Rate Control.*/
+#define VEN_RC_OFF	1
+#define VEN_RC_VBR_VFR	2
+#define VEN_RC_VBR_CFR	3
+#define VEN_RC_CBR_VFR	4
+
+/*Different modes for flushing buffers*/
+#define VEN_FLUSH_INPUT	1
+#define VEN_FLUSH_OUTPUT	2
+#define VEN_FLUSH_ALL	3
+
+/*Different input formats for YUV data.*/
+#define VEN_INPUTFMT_NV12	1/* NV12 Linear */
+#define VEN_INPUTFMT_NV21	2/* NV21 Linear */
+
+/*Different allowed rotation modes.*/
+#define VEN_ROTATION_0	1/* 0 degrees */
+#define VEN_ROTATION_90	2/* 90 degrees */
+#define VEN_ROTATION_180	3/* 180 degrees */
+#define VEN_ROTATION_270	4/* 270 degrees */
+
+/*IOCTL timeout values*/
+#define VEN_TIMEOUT_INFINITE	0xffffffff
+
+/*Different allowed intra refresh modes.*/
+#define VEN_IR_OFF	1
+#define VEN_IR_CYCLIC	2
+#define VEN_IR_RANDOM	3
+
+/*IOCTL BASE CODES Not to be used directly by the client.*/
+/* Base value for ioctls that are not related to encoder configuration.*/
+#define VEN_IOCTLBASE_NENC	0x800
+/* Base value for encoder configuration ioctls*/
+#define VEN_IOCTLBASE_ENC	0x850
+
+struct venc_ioctl_msg {
+	void __user *in;
+	void __user *out;
+};
+
+/*NON ENCODER CONFIGURATION IOCTLs*/
+
+/*IOCTL params:SET: InputData - unsigned long, OutputData - NULL*/
+#define VEN_IOCTL_SET_INTF_VERSION \
+	_IOW(VEN_IOCTLBASE_NENC, 0, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_timeout, OutputData - venc_msg*/
+#define VEN_IOCTL_CMD_READ_NEXT_MSG \
+	_IOWR(VEN_IOCTLBASE_NENC, 1, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - NULL, OutputData - NULL*/
+#define VEN_IOCTL_CMD_STOP_READ_MSG	_IO(VEN_IOCTLBASE_NENC, 2)
+
+/*IOCTL params:SET: InputData - venc_allocatorproperty, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_allocatorproperty*/
+#define VEN_IOCTL_SET_INPUT_BUFFER_REQ \
+	_IOW(VEN_IOCTLBASE_NENC, 3, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_INPUT_BUFFER_REQ \
+	_IOR(VEN_IOCTLBASE_NENC, 4, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_CMD_ALLOC_INPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 5, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_SET_INPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 6, struct venc_ioctl_msg)
+
+/*IOCTL params: CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_CMD_FREE_INPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 7, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_allocatorproperty, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_allocatorproperty*/
+#define VEN_IOCTL_SET_OUTPUT_BUFFER_REQ \
+	_IOW(VEN_IOCTLBASE_NENC, 8, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_OUTPUT_BUFFER_REQ \
+	_IOR(VEN_IOCTLBASE_NENC, 9, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_CMD_ALLOC_OUTPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 10, struct venc_ioctl_msg)
+
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_SET_OUTPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 11, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL.*/
+#define VEN_IOCTL_CMD_FREE_OUTPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 12, struct venc_ioctl_msg)
+
+
+/* Asynchronous respone message code:* VEN_MSG_START*/
+#define VEN_IOCTL_CMD_START	_IO(VEN_IOCTLBASE_NENC, 13)
+
+
+/*IOCTL params:CMD: InputData - venc_buffer, OutputData - NULL
+ Asynchronous respone message code:VEN_MSG_INPUT_BUFFER_DONE*/
+#define VEN_IOCTL_CMD_ENCODE_FRAME \
+	_IOW(VEN_IOCTLBASE_NENC, 14, struct venc_ioctl_msg)
+
+
+/*IOCTL params:CMD: InputData - venc_buffer, OutputData - NULL
+ Asynchronous response message code:VEN_MSG_OUTPUT_BUFFER_DONE*/
+#define VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 15, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferflush, OutputData - NULL
+ * Asynchronous response message code:VEN_MSG_INPUT_BUFFER_DONE*/
+#define VEN_IOCTL_CMD_FLUSH \
+	_IOW(VEN_IOCTLBASE_NENC, 16, struct venc_ioctl_msg)
+
+
+/*Asynchronous respone message code:VEN_MSG_PAUSE*/
+#define VEN_IOCTL_CMD_PAUSE	_IO(VEN_IOCTLBASE_NENC, 17)
+
+/*Asynchronous respone message code:VEN_MSG_RESUME*/
+#define VEN_IOCTL_CMD_RESUME _IO(VEN_IOCTLBASE_NENC, 18)
+
+/* Asynchronous respone message code:VEN_MSG_STOP*/
+#define VEN_IOCTL_CMD_STOP _IO(VEN_IOCTLBASE_NENC, 19)
+
+
+/*ENCODER PROPERTY CONFIGURATION & CAPABILITY IOCTLs*/
+
+/*IOCTL params:SET: InputData - venc_basecfg, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_basecfg*/
+#define VEN_IOCTL_SET_BASE_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 1, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_BASE_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 2, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+  GET: InputData - NULL, OutputData - venc_switch*/
+#define VEN_IOCTL_SET_LIVE_MODE \
+	_IOW(VEN_IOCTLBASE_ENC, 3, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_LIVE_MODE \
+	_IOR(VEN_IOCTLBASE_ENC, 4, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_profile, OutputData - NULL
+  GET: InputData - NULL, OutputData - venc_profile*/
+#define VEN_IOCTL_SET_CODEC_PROFILE \
+	_IOW(VEN_IOCTLBASE_ENC, 5, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_CODEC_PROFILE \
+	_IOR(VEN_IOCTLBASE_ENC, 6, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - ven_profilelevel, OutputData - NULL
+  GET: InputData - NULL, OutputData - ven_profilelevel*/
+#define VEN_IOCTL_SET_PROFILE_LEVEL \
+	_IOW(VEN_IOCTLBASE_ENC, 7, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_GET_PROFILE_LEVEL \
+	_IOR(VEN_IOCTLBASE_ENC, 8, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_switch*/
+#define VEN_IOCTL_SET_SHORT_HDR \
+	_IOW(VEN_IOCTLBASE_ENC, 9, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_SHORT_HDR \
+	_IOR(VEN_IOCTLBASE_ENC, 10, struct venc_ioctl_msg)
+
+
+/*IOCTL params: SET: InputData - venc_sessionqp, OutputData - NULL
+  GET: InputData - NULL, OutputData - venc_sessionqp*/
+#define VEN_IOCTL_SET_SESSION_QP \
+	_IOW(VEN_IOCTLBASE_ENC, 11, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_SESSION_QP \
+	_IOR(VEN_IOCTLBASE_ENC, 12, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_intraperiod, OutputData - NULL
+  GET: InputData - NULL, OutputData - venc_intraperiod*/
+#define VEN_IOCTL_SET_INTRA_PERIOD \
+	_IOW(VEN_IOCTLBASE_ENC, 13, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_INTRA_PERIOD \
+	_IOR(VEN_IOCTLBASE_ENC, 14, struct venc_ioctl_msg)
+
+
+/* Request an Iframe*/
+#define VEN_IOCTL_CMD_REQUEST_IFRAME _IO(VEN_IOCTLBASE_ENC, 15)
+
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_capability*/
+#define VEN_IOCTL_GET_CAPABILITY \
+	_IOR(VEN_IOCTLBASE_ENC, 16, struct venc_ioctl_msg)
+
+
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_seqheader*/
+#define VEN_IOCTL_GET_SEQUENCE_HDR \
+	_IOR(VEN_IOCTLBASE_ENC, 17, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_entropycfg, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_entropycfg*/
+#define VEN_IOCTL_SET_ENTROPY_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 18, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_ENTROPY_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 19, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_dbcfg, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_dbcfg*/
+#define VEN_IOCTL_SET_DEBLOCKING_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 20, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_DEBLOCKING_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 21, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_intrarefresh, OutputData - NULL
+  GET: InputData - NULL, OutputData - venc_intrarefresh*/
+#define VEN_IOCTL_SET_INTRA_REFRESH \
+	_IOW(VEN_IOCTLBASE_ENC, 22, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_INTRA_REFRESH \
+	_IOR(VEN_IOCTLBASE_ENC, 23, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_multiclicecfg, OutputData - NULL
+  GET: InputData - NULL, OutputData - venc_multiclicecfg*/
+#define VEN_IOCTL_SET_MULTI_SLICE_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 24, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_MULTI_SLICE_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 25, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ratectrlcfg, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_ratectrlcfg*/
+#define VEN_IOCTL_SET_RATE_CTRL_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 26, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_RATE_CTRL_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 27, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_voptimingcfg, OutputData - NULL
+  GET: InputData - NULL, OutputData - venc_voptimingcfg*/
+#define VEN_IOCTL_SET_VOP_TIMING_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 28, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_VOP_TIMING_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 29, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_framerate, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_framerate*/
+#define VEN_IOCTL_SET_FRAME_RATE \
+	_IOW(VEN_IOCTLBASE_ENC, 30, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_FRAME_RATE \
+	_IOR(VEN_IOCTLBASE_ENC, 31, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_targetbitrate, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_targetbitrate*/
+#define VEN_IOCTL_SET_TARGET_BITRATE \
+	_IOW(VEN_IOCTLBASE_ENC, 32, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_TARGET_BITRATE \
+	_IOR(VEN_IOCTLBASE_ENC, 33, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_rotation, OutputData - NULL
+  GET: InputData - NULL, OutputData - venc_rotation*/
+#define VEN_IOCTL_SET_ROTATION \
+	_IOW(VEN_IOCTLBASE_ENC, 34, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_ROTATION \
+	_IOR(VEN_IOCTLBASE_ENC, 35, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_headerextension, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_headerextension*/
+#define VEN_IOCTL_SET_HEC \
+	_IOW(VEN_IOCTLBASE_ENC, 36, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_HEC \
+	_IOR(VEN_IOCTLBASE_ENC, 37, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_switch*/
+#define VEN_IOCTL_SET_DATA_PARTITION \
+	_IOW(VEN_IOCTLBASE_ENC, 38, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_DATA_PARTITION \
+	_IOR(VEN_IOCTLBASE_ENC, 39, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_switch*/
+#define VEN_IOCTL_SET_RVLC \
+	_IOW(VEN_IOCTLBASE_ENC, 40, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_RVLC \
+	_IOR(VEN_IOCTLBASE_ENC, 41, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_switch*/
+#define VEN_IOCTL_SET_AC_PREDICTION \
+	_IOW(VEN_IOCTLBASE_ENC, 42, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_AC_PREDICTION \
+	_IOR(VEN_IOCTLBASE_ENC, 43, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - venc_qprange, OutputData - NULL
+ GET: InputData - NULL, OutputData - venc_qprange*/
+#define VEN_IOCTL_SET_QP_RANGE \
+	_IOW(VEN_IOCTLBASE_ENC, 44, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_QP_RANGE \
+	_IOR(VEN_IOCTLBASE_ENC, 45, struct venc_ioctl_msg)
+
+struct venc_switch {
+	unsigned char status;
+};
+
+struct venc_allocatorproperty {
+	u32 mincount;
+	u32 maxcount;
+	u32 actualcount;
+	u32 datasize;
+	u32 suffixsize;
+	u32 alignment;
+	u32 bufpoolid;
+};
+
+struct venc_bufferpayload {
+	void __user *buffer;
+	size_t sz;
+	int fd;
+	size_t offset;
+	unsigned int maped_size;
+	unsigned long filled_len;
+};
+
+struct venc_buffer {
+	void __user *addr;
+	size_t sz;
+	size_t len;
+	size_t offset;
+	long long timestamp;
+	u32 flags;
+	void *clientdata;
+};
+
+struct venc_basecfg {
+	u32 input_width;
+	u32 input_height;
+	u32 dvs_width;
+	u32 dvs_height;
+	u32 codectype;
+	u32 fps_num;
+	u32 fps_den;
+	u32 targetbitrate;
+	u32 inputformat;
+};
+
+struct venc_profile {
+	unsigned long	profile;
+};
+struct ven_profilelevel {
+	unsigned long	level;
+};
+
+struct venc_sessionqp {
+	unsigned long	iframeqp;
+	unsigned long	pframqp;
+};
+
+struct venc_qprange {
+	u32 maxqp;
+	u32 minqp;
+};
+struct venc_intraperiod {
+	unsigned long	num_pframes;
+};
+struct venc_seqheader {
+	void *buf;
+	size_t buf_sz;
+	size_t hdr_len;
+};
+
+struct venc_capability {
+	unsigned long	codec_types;
+	unsigned long	maxframe_width;
+	unsigned long	maxframe_height;
+	unsigned long	maxtarget_bitrate;
+	unsigned long	maxframe_rate;
+	unsigned long	input_formats;
+	unsigned char	dvs;
+};
+
+struct venc_entropycfg {
+	unsigned longentropysel;
+	unsigned long	cabacmodel;
+};
+
+struct venc_dbcfg {
+	u32 db_mode;
+	u32 slicealpha_offset;
+	u32 slicebeta_offset;
+};
+
+struct venc_intrarefresh {
+	unsigned long	irmode;
+	unsigned long	mbcount;
+};
+
+struct venc_multiclicecfg {
+	unsigned long	mslice_mode;
+	unsigned long	mslice_size;
+};
+
+struct venc_bufferflush {
+	unsigned long	flush_mode;
+};
+
+struct venc_ratectrlcfg {
+	unsigned long	rcmode;
+};
+
+struct	venc_voptimingcfg {
+	u32 voptime_resolution;
+};
+struct venc_framerate {
+	u32 fps_denominator;
+	u32 fps_numerator;
+};
+
+//TODO remove these stupid structs
+struct venc_targetbitrate{
+	u32 target_bitrate;
+};
+
+struct venc_rotation {
+	u32 rotation;
+};
+
+struct venc_timeout {
+	u32 millisec;
+};
+
+struct venc_headerextension {
+	unsigned long header_extension;
+};
+
+struct venc_msg {
+	unsigned long statuscode;
+	unsigned long msgcode;
+	struct venc_buffer buf;
+	size_t msgdata_size;
+};
+#endif /* _MSM_VIDC_ENC_H_ */
diff --git a/include/linux/mt9t013.h b/include/linux/mt9t013.h
new file mode 100644
index 0000000..543923a
--- /dev/null
+++ b/include/linux/mt9t013.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2007-2008 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 CAMERA_MT9T013_H
+#define CAMERA_MT9T013_H
+#include <linux/cdev.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/sizes.h>
+
+/*************************************************************
+*	IOCTL define
+*************************************************************/
+
+#define MT9T013_I2C_IOCTL_MAGIC 'm'
+
+#define MT9T013_I2C_IOCTL_W \
+	        _IOW(MT9T013_I2C_IOCTL_MAGIC, 0, unsigned)
+
+#define MT9T013_I2C_IOCTL_R \
+	        _IOR(MT9T013_I2C_IOCTL_MAGIC, 1, unsigned)
+
+#define MT9T013_I2C_IOCTL_AF_W \
+	        _IOW(MT9T013_I2C_IOCTL_MAGIC, 2, unsigned)
+
+#define MT9T013_I2C_IOCTL_CAMIF_PAD_REG_RESET \
+	_IO(MT9T013_I2C_IOCTL_MAGIC, 3)
+
+#define MT9T013_I2C_IOCTL_CAMIF_PAD_REG_RESET_2 \
+	_IO(MT9T013_I2C_IOCTL_MAGIC, 4)
+
+#define CAMERA_CONFIGURE_GPIOS \
+	_IO(MT9T013_I2C_IOCTL_MAGIC, 7)
+
+#define CAMERA_UNCONFIGURE_GPIOS \
+	_IO(MT9T013_I2C_IOCTL_MAGIC, 8)
+	
+#define CAMERA_LENS_POWER_ON \
+	_IO(MT9T013_I2C_IOCTL_MAGIC, 9)
+	
+#define CAMERA_LENS_POWER_OFF \
+	_IO(MT9T013_I2C_IOCTL_MAGIC, 10)
+
+#define MT9T013_I2C_IOCTL_CAMIF_APPS_RESET \
+	_IO(MT9T013_I2C_IOCTL_MAGIC, 11)
+
+/* Replacement ioctls() for the clkrgm_sec RPCs. */
+
+#define CAMIO_VFE_MDC_CLK 1 /* enable, disable */
+#define CAMIO_MDC_CLK     2 /* enable, disable */
+#define CAMIO_VFE_CLK     3 /* clk_select, freq_prog */
+
+#define MT9T013_I2C_IOCTL_CLK_ENABLE \
+	_IOW(MT9T013_I2C_IOCTL_MAGIC, 12, unsigned)
+
+#define MT9T013_I2C_IOCTL_CLK_DISABLE \
+	_IOW(MT9T013_I2C_IOCTL_MAGIC, 13, unsigned)
+
+#define MT9T013_I2C_IOCTL_CLK_SELECT \
+	_IOW(MT9T013_I2C_IOCTL_MAGIC, 14, unsigned)
+
+#define MT9T013_I2C_IOCTL_CLK_FREQ_PROG \
+	_IOW(MT9T013_I2C_IOCTL_MAGIC, 15, unsigned)
+
+#define CAMSENSOR_REG_INIT		0<<0
+#define CAMSENSOR_REG_UPDATE_PERIODIC 	1<<0
+#define CAMSENSOR_TYPE_PREVIEW          0<<1
+#define CAMSENSOR_TYPE_SNAPSHOT		1<<1
+
+#define MT9T013_I2C_IOCTL_SENSOR_SETTING \
+	_IOW(MT9T013_I2C_IOCTL_MAGIC, 16, uint32_t)
+
+struct mt9t013_reg_struct
+{
+	uint16_t vt_pix_clk_div;            /* 0x0300 */
+	uint16_t vt_sys_clk_div;            /* 0x0302 */
+	uint16_t pre_pll_clk_div;           /* 0x0304 */
+	uint16_t pll_multiplier;            /* 0x0306 */
+	uint16_t op_pix_clk_div;            /* 0x0308 */
+	uint16_t op_sys_clk_div;            /* 0x030A */
+	uint16_t scale_m;                   /* 0x0404 */
+	uint16_t row_speed;                 /* 0x3016 */
+	uint16_t x_addr_start;              /* 0x3004 */
+	uint16_t x_addr_end;                /* 0x3008 */
+	uint16_t y_addr_start;              /* 0x3002 */
+	uint16_t y_addr_end;                /* 0x3006 */
+	uint16_t read_mode;                 /* 0x3040 */
+	uint16_t x_output_size ;            /* 0x034C */
+	uint16_t y_output_size;             /* 0x034E */
+	uint16_t line_length_pck;           /* 0x300C */
+	uint16_t frame_length_lines;        /* 0x300A */
+	uint16_t coarse_integration_time;   /* 0x3012 */
+	uint16_t fine_integration_time;     /* 0x3014 */
+}; 
+
+struct mt9t013_reg_pat {
+	struct mt9t013_reg_struct reg[2];
+};
+
+#define MT9T013_I2C_IOCTL_GET_REGISTERS \
+	_IOR(MT9T013_I2C_IOCTL_MAGIC, 17, struct mt9t013_reg_pat *)
+
+struct mt9t013_exposure_gain {
+	uint16_t gain;
+	uint16_t line;
+	uint32_t mode;
+};
+
+#define MT9T013_I2C_IOCTL_EXPOSURE_GAIN \
+	_IOW(MT9T013_I2C_IOCTL_MAGIC, 18, struct exposure_gain *)
+
+#define MT9T013_I2C_IOCTL_MOVE_FOCUS \
+	_IOW(MT9T013_I2C_IOCTL_MAGIC, 19, uint32_t)
+
+#define MT9T013_I2C_IOCTL_SET_DEFAULT_FOCUS \
+	_IOW(MT9T013_I2C_IOCTL_MAGIC, 20, uint32_t)
+
+#define MT9T013_I2C_IOCTL_POWER_DOWN \
+	_IO(MT9T013_I2C_IOCTL_MAGIC, 21)
+
+struct mt9t013_init {
+	int preview; /* in: 1 for preview, 0 for capture */
+	uint16_t chipid; /* out: chip id */
+};
+
+#define MT9T013_I2C_IOCTL_INIT \
+	_IOWR(MT9T013_I2C_IOCTL_MAGIC, 22, struct mt9t013_init *)
+
+#endif
+
diff --git a/include/linux/tpa2018d1.h b/include/linux/tpa2018d1.h
new file mode 100644
index 0000000..26f608b
--- /dev/null
+++ b/include/linux/tpa2018d1.h
@@ -0,0 +1,36 @@
+/* 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 _LINUX_TPA2018D1_H
+#define _LINUX_TPA2018D1_H
+
+#include <linux/ioctl.h>
+
+enum tpa2018d1_mode {
+	TPA2018_MODE_OFF,
+	TPA2018_MODE_PLAYBACK,
+	TPA2018_MODE_RINGTONE,
+	TPA2018_MODE_VOICE_CALL,
+	TPA2018_NUM_MODES,
+};
+
+#define TPA2018_IOCTL_MAGIC	'a'
+#define TPA2018_SET_CONFIG	_IOW(TPA2018_IOCTL_MAGIC, 1, unsigned)
+#define TPA2018_READ_CONFIG	_IOR(TPA2018_IOCTL_MAGIC, 2, unsigned)
+#define TPA2018_SET_PARAM	_IOW(TPA2018_IOCTL_MAGIC, 3, unsigned)
+#define TPA2018_SET_MODE	_IOW(TPA2018_IOCTL_MAGIC, 4, unsigned)
+
+#endif
+
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
new file mode 100644
index 0000000..c016540
--- /dev/null
+++ b/include/media/msm_camera.h
@@ -0,0 +1,465 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __LINUX_MSM_CAMERA_H
+#define __LINUX_MSM_CAMERA_H
+
+#include <linux/types.h>
+#include <asm/sizes.h>
+#include <linux/ioctl.h>
+
+#define MSM_CAM_IOCTL_MAGIC 'm'
+
+#define MSM_CAM_IOCTL_GET_SENSOR_INFO \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 1, struct msm_camsensor_info *)
+
+#define MSM_CAM_IOCTL_REGISTER_PMEM \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 2, struct msm_pmem_info *)
+
+#define MSM_CAM_IOCTL_UNREGISTER_PMEM \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 3, unsigned)
+
+#define MSM_CAM_IOCTL_CTRL_COMMAND \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 4, struct msm_ctrl_cmd *)
+
+#define MSM_CAM_IOCTL_CONFIG_VFE  \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 5, struct msm_camera_vfe_cfg_cmd *)
+
+#define MSM_CAM_IOCTL_GET_STATS \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 6, struct msm_camera_stats_event_ctrl *)
+
+#define MSM_CAM_IOCTL_GETFRAME \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 7, struct msm_camera_get_frame *)
+
+#define MSM_CAM_IOCTL_ENABLE_VFE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 8, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_CTRL_CMD_DONE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 9, struct camera_cmd *)
+
+#define MSM_CAM_IOCTL_CONFIG_CMD \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 10, struct camera_cmd *)
+
+#define MSM_CAM_IOCTL_DISABLE_VFE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 11, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_PAD_REG_RESET2 \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 12, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_VFE_APPS_RESET \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 13, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 14, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_RELEASE_STATS_BUFFER \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 15, struct msm_stats_buf *)
+
+#define MSM_CAM_IOCTL_AXI_CONFIG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 16, struct msm_camera_vfe_cfg_cmd *)
+
+#define MSM_CAM_IOCTL_GET_PICTURE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 17, struct msm_camera_ctrl_cmd *)
+
+#define MSM_CAM_IOCTL_SET_CROP \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 18, struct crop_info *)
+
+#define MSM_CAM_IOCTL_PP \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 19, uint8_t *)
+
+#define MSM_CAM_IOCTL_PP_DONE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 20, struct msm_snapshot_pp_status *)
+
+#define MSM_CAM_IOCTL_SENSOR_IO_CFG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 21, struct sensor_cfg_data *)
+
+#define MSM_CAMERA_LED_OFF  0
+#define MSM_CAMERA_LED_LOW  1
+#define MSM_CAMERA_LED_HIGH 2
+
+#define MSM_CAM_IOCTL_FLASH_LED_CFG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 22, unsigned *)
+
+#define MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME \
+	_IO(MSM_CAM_IOCTL_MAGIC, 23)
+
+#define MSM_CAM_IOCTL_CTRL_COMMAND_2 \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 24, struct msm_ctrl_cmd *)
+
+#define MSM_CAM_IOCTL_ENABLE_OUTPUT_IND \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 25, uint32_t *)
+
+#define MSM_CAM_IOCTL_AF_CTRL \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 26, struct msm_ctrl_cmt_t *)
+#define MSM_CAM_IOCTL_AF_CTRL_DONE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 27, struct msm_ctrl_cmt_t *)
+
+#define MAX_SENSOR_NUM  3
+#define MAX_SENSOR_NAME 32
+
+#define PP_SNAP		1
+#define PP_RAW_SNAP	(1<<1)
+#define PP_PREV		(1<<2)
+#define PP_MASK		(PP_SNAP|PP_RAW_SNAP|PP_PREV)
+
+#define MSM_CAM_CTRL_CMD_DONE  0
+#define MSM_CAM_SENSOR_VFE_CMD 1
+
+/*****************************************************
+ *  structure
+ *****************************************************/
+
+/* define five type of structures for userspace <==> kernel
+ * space communication:
+ * command 1 - 2 are from userspace ==> kernel
+ * command 3 - 4 are from kernel ==> userspace
+ *
+ * 1. control command: control command(from control thread),
+ *                     control status (from config thread);
+ */
+struct msm_ctrl_cmd {
+	uint16_t type;
+	uint16_t length;
+	void *value;
+	uint16_t status;
+	uint32_t timeout_ms;
+	int resp_fd; /* FIXME: to be used by the kernel, pass-through for now */
+};
+
+struct msm_vfe_evt_msg {
+	unsigned short type; /* 1 == event (RPC), 0 == message (adsp) */
+	unsigned short msg_id;
+	unsigned int len; /* size in, number of bytes out */
+	void *data;
+};
+
+#define MSM_CAM_RESP_CTRL         0
+#define MSM_CAM_RESP_STAT_EVT_MSG 1
+#define MSM_CAM_RESP_V4L2         2
+#define MSM_CAM_RESP_MAX          3
+
+/* this one is used to send ctrl/status up to config thread */
+struct msm_stats_event_ctrl {
+	/* 0 - ctrl_cmd from control thread,
+	 * 1 - stats/event kernel,
+	 * 2 - V4L control or read request */
+	int resptype;
+	int timeout_ms;
+	struct msm_ctrl_cmd ctrl_cmd;
+	/* struct  vfe_event_t  stats_event; */
+	struct msm_vfe_evt_msg stats_event;
+};
+
+/* 2. config command: config command(from config thread); */
+struct msm_camera_cfg_cmd {
+	/* what to config:
+	 * 1 - sensor config, 2 - vfe config */
+	uint16_t cfg_type;
+
+	/* sensor config type */
+	uint16_t cmd_type;
+	uint16_t queue;
+	uint16_t length;
+	void *value;
+};
+
+#define CMD_GENERAL			0
+#define CMD_AXI_CFG_OUT1		1
+#define CMD_AXI_CFG_SNAP_O1_AND_O2	2
+#define CMD_AXI_CFG_OUT2		3
+#define CMD_PICT_T_AXI_CFG		4
+#define CMD_PICT_M_AXI_CFG		5
+#define CMD_RAW_PICT_AXI_CFG		6
+#define CMD_STATS_AXI_CFG		7
+#define CMD_STATS_AF_AXI_CFG		8
+#define CMD_FRAME_BUF_RELEASE		9
+#define CMD_PREV_BUF_CFG		10
+#define CMD_SNAP_BUF_RELEASE		11
+#define CMD_SNAP_BUF_CFG		12
+#define CMD_STATS_DISABLE		13
+#define CMD_STATS_AEC_AWB_ENABLE	14
+#define CMD_STATS_AF_ENABLE		15
+#define CMD_STATS_BUF_RELEASE		16
+#define CMD_STATS_AF_BUF_RELEASE	17
+#define CMD_STATS_ENABLE        18
+#define UPDATE_STATS_INVALID		19
+
+#define CMD_STATS_AEC_ENABLE		20
+#define CMD_STATS_AWB_ENABLE		21
+#define CMD_STATS_AEC_AXI_CFG		22
+#define CMD_STATS_AWB_AXI_CFG		23
+#define CMD_STATS_RS_AXI_CFG		24
+#define CMD_STATS_CS_AXI_CFG		25
+#define CMD_STATS_IHIST_AXI_CFG		26
+#define CMD_STATS_SKIN_AXI_CFG		27
+#define CMD_STATS_AEC_BUF_RELEASE	28
+#define CMD_STATS_AWB_BUF_RELEASE	29
+#define CMD_STATS_RS_BUF_RELEASE	30
+#define CMD_STATS_CS_BUF_RELEASE	31
+#define CMD_STATS_IHIST_BUF_RELEASE	32
+#define CMD_STATS_SKIN_BUF_RELEASE	33
+
+#define CMD_AXI_CFG_SNAP_GEMINI		34
+#define CMD_AXI_CFG_SNAP		35
+#define CMD_AXI_CFG_PREVIEW		36
+#define CMD_AXI_CFG_VIDEO		37
+
+#define CMD_STATS_IHIST_ENABLE 38
+#define CMD_STATS_RS_ENABLE 39
+#define CMD_STATS_CS_ENABLE 40
+#define CMD_AXI_CFG_O1_AND_O2	41 /* output1 and output2 */
+
+/* vfe config command: config command(from config thread)*/
+struct msm_vfe_cfg_cmd {
+	int cmd_type;
+	uint16_t length;
+	void *value;
+};
+
+#define MAX_CAMERA_ENABLE_NAME_LEN 32
+struct camera_enable_cmd {
+	char name[MAX_CAMERA_ENABLE_NAME_LEN];
+};
+
+#define MSM_PMEM_OUTPUT1		0
+#define MSM_PMEM_OUTPUT2		1
+#define MSM_PMEM_OUTPUT1_OUTPUT2	2
+#define MSM_PMEM_THUMBNAIL		3
+#define MSM_PMEM_MAINIMG		4
+#define MSM_PMEM_RAW_MAINIMG		5
+#define MSM_PMEM_AEC_AWB		6
+#define MSM_PMEM_AF			7
+#define MSM_PMEM_AEC			8
+#define MSM_PMEM_AWB			9
+#define MSM_PMEM_RS		    	10
+#define MSM_PMEM_CS	    		11
+#define MSM_PMEM_IHIST			12
+#define MSM_PMEM_SKIN			13
+#define MSM_PMEM_VIDEO			14
+#define MSM_PMEM_PREVIEW		15
+#define MSM_PMEM_MAX			16
+
+#define FRAME_PREVIEW_OUTPUT1		0
+#define FRAME_PREVIEW_OUTPUT2		1
+#define FRAME_SNAPSHOT			2
+#define FRAME_THUMBNAIL		3
+#define FRAME_RAW_SNAPSHOT		4
+#define FRAME_MAX			5
+
+struct msm_pmem_info {
+	int type;
+	int fd;
+	void *vaddr;
+	uint32_t offset;
+	uint32_t len;
+	uint32_t y_off; /* relative to offset */
+	uint32_t cbcr_off; /* relative to offset */
+	uint8_t vfe_can_write;
+};
+
+struct outputCfg {
+	uint32_t height;
+	uint32_t width;
+
+	uint32_t window_height_firstline;
+	uint32_t window_height_lastline;
+};
+
+#define OUTPUT_1	0
+#define OUTPUT_2	1
+#define OUTPUT_1_AND_2	2
+#define CAMIF_TO_AXI_VIA_OUTPUT_2		3
+#define OUTPUT_1_AND_CAMIF_TO_AXI_VIA_OUTPUT_2	4
+#define OUTPUT_2_AND_CAMIF_TO_AXI_VIA_OUTPUT_1	5
+#define OUTPUT_1_AND_3 6
+#define LAST_AXI_OUTPUT_MODE_ENUM = OUTPUT_1_AND_3            7   /* video */
+
+
+#define MSM_FRAME_PREV_1	0
+#define MSM_FRAME_PREV_2	1
+#define MSM_FRAME_ENC		2
+
+#define OUTPUT_TYPE_P		1
+#define OUTPUT_TYPE_T		2
+#define OUTPUT_TYPE_S		3
+#define OUTPUT_TYPE_V		4
+
+struct msm_frame {
+	int path;
+	unsigned long buffer;
+	uint32_t y_off;
+	uint32_t cbcr_off;
+	int fd;
+
+	void *cropinfo;
+	int croplen;
+};
+
+#define STAT_AEAW	0
+#define STAT_AF		1
+#define STAT_AEC	2
+#define STAT_AWB	3
+#define STAT_RS		4
+#define STAT_CS		5
+#define STAT_IHIST	6
+#define STAT_SKIN	7
+#define STAT_MAX	8
+
+struct msm_stats_buf {
+	int type;
+	unsigned long buffer;
+	int fd;
+};
+
+#define MSM_V4L2_VID_CAP_TYPE	0
+#define MSM_V4L2_STREAM_ON	1
+#define MSM_V4L2_STREAM_OFF	2
+#define MSM_V4L2_SNAPSHOT	3
+#define MSM_V4L2_QUERY_CTRL	4
+#define MSM_V4L2_GET_CTRL	5
+#define MSM_V4L2_SET_CTRL	6
+#define MSM_V4L2_QUERY		7
+#define MSM_V4L2_MAX		8
+
+struct crop_info {
+	void *info;
+	int len;
+};
+
+struct msm_postproc {
+	int ftnum;
+	struct msm_frame fthumnail;
+	int fmnum;
+	struct msm_frame fmain;
+};
+
+struct msm_snapshot_pp_status {
+	void *status;
+};
+
+#define CFG_SET_MODE			0
+#define CFG_SET_EFFECT			1
+#define CFG_START			2
+#define CFG_PWR_UP			3
+#define CFG_PWR_DOWN			4
+#define CFG_WRITE_EXPOSURE_GAIN		5
+#define CFG_SET_DEFAULT_FOCUS		6
+#define CFG_MOVE_FOCUS			7
+#define CFG_REGISTER_TO_REAL_GAIN	8
+#define CFG_REAL_TO_REGISTER_GAIN	9
+#define CFG_SET_FPS			10
+#define CFG_SET_PICT_FPS		11
+#define CFG_SET_BRIGHTNESS		12
+#define CFG_SET_CONTRAST		13
+#define CFG_SET_ZOOM			14
+#define CFG_SET_EXPOSURE_MODE		15
+#define CFG_SET_WB			16
+#define CFG_SET_ANTIBANDING		17
+#define CFG_SET_EXP_GAIN		18
+#define CFG_SET_PICT_EXP_GAIN		19
+#define CFG_SET_LENS_SHADING		20
+#define CFG_GET_PICT_FPS		21
+#define CFG_GET_PREV_L_PF		22
+#define CFG_GET_PREV_P_PL		23
+#define CFG_GET_PICT_L_PF		24
+#define CFG_GET_PICT_P_PL		25
+#define CFG_GET_AF_MAX_STEPS		26
+#define CFG_GET_PICT_MAX_EXP_LC		27
+#define CFG_MAX				28
+
+#define MOVE_NEAR	0
+#define MOVE_FAR	1
+
+#define SENSOR_PREVIEW_MODE		0
+#define SENSOR_SNAPSHOT_MODE		1
+#define SENSOR_RAW_SNAPSHOT_MODE	2
+
+#define SENSOR_QTR_SIZE			0
+#define SENSOR_FULL_SIZE		1
+#define SENSOR_INVALID_SIZE		2
+
+#define CAMERA_EFFECT_OFF		0
+#define CAMERA_EFFECT_MONO		1
+#define CAMERA_EFFECT_NEGATIVE		2
+#define CAMERA_EFFECT_SOLARIZE		3
+#define CAMERA_EFFECT_PASTEL		4
+#define CAMERA_EFFECT_MOSAIC		5
+#define CAMERA_EFFECT_RESIZE		6
+#define CAMERA_EFFECT_SEPIA		7
+#define CAMERA_EFFECT_POSTERIZE		8
+#define CAMERA_EFFECT_WHITEBOARD	9
+#define CAMERA_EFFECT_BLACKBOARD	10
+#define CAMERA_EFFECT_AQUA		11
+#define CAMERA_EFFECT_MAX		12
+
+struct sensor_pict_fps {
+	uint16_t prevfps;
+	uint16_t pictfps;
+};
+
+struct exp_gain_cfg {
+	uint16_t gain;
+	uint32_t line;
+};
+
+struct focus_cfg {
+	int32_t steps;
+	int dir;
+};
+
+struct fps_cfg {
+	uint16_t f_mult;
+	uint16_t fps_div;
+	uint32_t pict_fps_div;
+};
+
+struct sensor_cfg_data {
+	int cfgtype;
+	int mode;
+	int rs;
+	uint8_t max_steps;
+
+	union {
+		int8_t effect;
+		uint8_t lens_shading;
+		uint16_t prevl_pf;
+		uint16_t prevp_pl;
+		uint16_t pictl_pf;
+		uint16_t pictp_pl;
+		uint32_t pict_max_exp_lc;
+		uint16_t p_fps;
+		struct sensor_pict_fps gfps;
+		struct exp_gain_cfg exp_gain;
+		struct focus_cfg focus;
+		struct fps_cfg fps;
+	} cfg;
+};
+
+#define GET_NAME			0
+#define GET_PREVIEW_LINE_PER_FRAME	1
+#define GET_PREVIEW_PIXELS_PER_LINE	2
+#define GET_SNAPSHOT_LINE_PER_FRAME	3
+#define GET_SNAPSHOT_PIXELS_PER_LINE	4
+#define GET_SNAPSHOT_FPS		5
+#define GET_SNAPSHOT_MAX_EP_LINE_CNT	6
+
+struct msm_camsensor_info {
+	char name[MAX_SENSOR_NAME];
+	uint8_t flash_enabled;
+};
+#endif /* __LINUX_MSM_CAMERA_H */